34 #define _TCD(NAME, FMT, ...) \
35 logDebug("dbg: " STR(NAME) ": " FMT, __VA_ARGS__)
37 #define _TCM(NAME, FMT, ...) \
38 logDebug("dbg: " STR(NAME), 0)
41 #define _TCD(NAME, FMT, ...)
42 #define _TCM(NAME, MSG)
48 static int _srpSchdPeriodicId;
53 #define _SRP_RESEND_SPREAD 64
57 #define _SRP_RESEND_TIMEOUT ( ( SRP_RESEND_TIMEOUT * CLOCKS_PER_SEC ) / 1000 )
59 #define _SRP_RESEND_TIMEOUT SRP_RESEND_TIMEOUT
66 #define _SRP_CACHE_MAX_AGE \
67 ( ( _SRP_RESEND_TIMEOUT + ( _SRP_RESEND_TIMEOUT / 2 ) * \
68 ( SRP_RESEND_MAX - 1 ) ) * SRP_RESEND_MAX )
70 #if (_SRP_CACHE_MAX_AGE > 0x7FFF)
71 #error "Timeout too big"
85 #define _SRP_TXF_CNT_MASK 0x3F
86 #define _SRP_TXF_CNT_SHIFT 0
87 #define _SRP_TXF_CONFIRMED BIT(6)
89 #define _SRP_TX_CNT_GET( F ) ( ( ( F ) & _SRP_TXF_CNT_MASK ) >> _SRP_TXF_CNT_SHIFT )
90 #define _SRP_TX_CNT_SET( C ) ( ( ( C ) << _SRP_TXF_CNT_SHIFT ) & _SRP_TXF_CNT_MASK )
107 static uint8_t _srpTxId;
111 #define _SRP_RXF_USED BIT(0)
112 #define _SRP_RXF_SEND_CFM BIT(1)
113 #define _SRP_RXF_NEED_CFM ( _SRP_RXF_USED | _SRP_RXF_SEND_CFM )
125 static SrpRxEntry *
const _srpRxCacheFirst = &_srpRxCache[0];
129 static inline uint16_t srpTimeOutNew(uint16_t to)
131 return ( clock() + to ) & 0xFFFF;
134 static inline bool srpTimeOut(uint16_t to)
136 return CGE(clock() & 0xFFFF, to, 16);
143 puts(
"---- SRP TX Queue ----");
147 printf(
"Commit content: %d of %d\n", _srpTxQueue.used, _srpTxQueue.size);
148 printf(
"Commit record : %d of %d\n", _srpTxRecQueue.length, _srpTxRecQueue.descr->capacity);
151 SrpTxRec * txRec = (SrpTxRec *)
qFirst(&_srpTxRecQueue);
153 while (txRec != NULL) {
154 printf(
"- %d: flags=%02x id=%d timeout=%d\n", t, txRec->flags, txRec->msgId, txRec->timeout);
155 txRec = (SrpTxRec *)
qNext(&_srpTxRecQueue, txRec);
160 puts(
"---- SRP RX Cache ----");
166 for (curEntry = _srpRxCacheFirst; curEntry <= _srpRxCacheLast; ++curEntry)
168 if (curEntry->flags & _SRP_RXF_USED) {
170 printf(
"- %d: flags=%02x id=%d timeout=%d\n",
171 t, curEntry->flags, curEntry->msgId, curEntry->timeout);
183 static bool srpRxNew(
SockAddr * addr, uint8_t msgId)
200 if (curEntry->flags & _SRP_RXF_USED) {
201 if (
sockAddrEq(&(curEntry->addr), addr) && curEntry->msgId == msgId) {
202 curEntry->flags |= _SRP_RXF_SEND_CFM;
206 _TCD(srpRxNew,
"Received message wit rmsgID=%d before, ignore", msgId);
210 if (srpTimeOut(curEntry->timeout))
216 #ifdef SRP_STRICT_RX_CACHE
222 if (curEntry->flags == 0) {
224 bestEntry = curEntry;
232 if (bestEntry == NULL)
235 if (!(curEntry->flags & _SRP_RXF_SEND_CFM))
238 bestEntry = curEntry;
241 }
else if (bestEntry->flags != 0) {
245 if (curEntry->flags == 0) {
247 bestEntry = curEntry;
250 }
else if (bestEntry->flags != 0 &&
CLE(curEntry->timeout, bestEntry->timeout, 16)) {
253 bestEntry = curEntry;
259 curEntry = ( curEntry == _srpRxCacheLast ) ? _srpRxCacheFirst : curEntry + 1;
260 }
while (curEntry != firstEntry);
265 if (bestEntry == NULL)
268 logWarn(
"No free entries, could not accept message with rmsgID %d", msgId);
273 _TCD(srpRxNew,
"New entry to RX cache, old rmsgID = %d, new rmsgID = %d",
274 bestEntry->msgId, msgId);
275 bestEntry->flags = _SRP_RXF_SEND_CFM | _SRP_RXF_USED;
276 bestEntry->addr = *addr;
277 bestEntry->msgId = msgId;
278 bestEntry->timeout = srpTimeOutNew(_SRP_CACHE_MAX_AGE);
287 static bool srpAckFor(
SockAddr * addr, uint8_t * cfmPtr)
290 while (entry <= _srpRxCacheLast)
292 if ( ( entry->flags & _SRP_RXF_NEED_CFM ) == _SRP_RXF_NEED_CFM &&
296 *cfmPtr = entry->msgId;
298 _TCD(srpRxNew,
"Send confirm for rmsgId=%d", entry->msgId);
300 entry->flags &= ~_SRP_RXF_SEND_CFM;
317 static bool srpUdpTransmit(
SockAddr * addr,
int len,
bool dontack)
333 _srpSwap.hdr.flags = 0;
337 while (srpAckFor(addr, &(_srpSwap.hdr.ackId[ackCnt])))
344 if (ackCnt == 0 && len == 0)
return false;
346 _TCD(srpUdpTransmit,
"Transmitting: addr=0x%08x len=%d", addr->
ip, len);
350 _srpSwap.content[len] =
'\0';
363 void srpTxCfm(
SockAddr * sender, uint8_t msgId)
366 SrpTxRec * txRec =
qFirst(&_srpTxRecQueue);
368 while (txRec != NULL)
370 if (txRec->msgId == msgId &&
sockAddrEq(sender, &(txRec->addr)))
372 _TCD(srpTxCfm,
"Message lmsgID=%d confirmed!", txRec->msgId);
373 txRec->flags |= _SRP_TXF_CONFIRMED;
377 txRec =
qNext(&_srpTxRecQueue, txRec);
395 for (i = 0; i < cfm; ++i) {
396 srpTxCfm(rxAddr, msgPtr->hdr.ackId[i]);
401 if (srpRxNew(rxAddr, msgPtr->hdr.msgId)) {
420 _TCD(
srpTx,
"Packet size: %d", len);
421 _TCD(
srpTx,
"TX Free: %d, used = %d, read = %d, write = %d",
vqFree(&_srpTxQueue),
422 _srpTxQueue.used, _srpTxQueue.read, _srpTxQueue.write);
425 logWarn(
"TX queue full, cannot create message");
428 if (
qFull(&_srpTxRecQueue)) {
430 logWarn(
"TX record queue full, cannot create message");
436 memcpy(_srpSwap.content, message, len);
437 _srpSwap.hdr.msgId = _srpTxId ++;
439 _TCD(srpProcessTx,
"Transmitting lmsgId=%d", _srpSwap.hdr.msgId);
441 srpUdpTransmit(txAddr, len,
false);
444 const SrpTxRec qRec =
447 .timeout = srpTimeOutNew( _SRP_RESEND_TIMEOUT + ( rand() % _SRP_RESEND_SPREAD ) ),
448 .flags = _SRP_TX_CNT_SET( 0 ),
449 .msgId = _srpSwap.hdr.msgId
452 qQueue(&_srpTxRecQueue, (uint8_t *)&qRec);
459 static bool srpProcessTx()
463 SrpTxRec * txRecPtr =
qFirst(&_srpTxRecQueue);
466 while (txRecPtr != NULL)
469 if (! ( txRecPtr->flags & _SRP_TXF_CONFIRMED ) )
472 if (!srpTimeOut(txRecPtr->timeout)) {
482 _srpLost(&(txRecPtr->addr), txRecPtr->msgId);
484 logWarn(
"Lost packet: SockAddr=0x%08x msgId=%d",
485 txRecPtr->addr.ip, txRecPtr->msgId);
493 txRecPtr =
qFirst(&_srpTxRecQueue);
497 if (txRecPtr == NULL )
501 return srpUdpTransmit(&addr, 0,
false);
508 uint16_t len =
sizeof(_srpSwap);
513 vqDeQueue(&_srpTxQueue, &len, (uint8_t *)&_srpSwap);
514 _TCD(srpProcessTx,
"Retransmitting lmsgId=%d", txRec.msgId);
516 srpUdpTransmit(&(txRec.addr), len -
sizeof(
SrpHeader),
false);
520 int cnt = _SRP_TX_CNT_GET( txRec.flags );
524 txRec.flags = ( txRec.flags & ~_SRP_TXF_CNT_MASK ) |
525 _SRP_TX_CNT_SET( cnt );
531 txRec.timeout = srpTimeOutNew( ( _SRP_RESEND_TIMEOUT * cnt )
532 + ( rand() % _SRP_RESEND_SPREAD ) );
536 qQueue(&_srpTxRecQueue, (uint8_t *)&txRec);
537 vqQueue(&_srpTxQueue, len, (uint8_t *)&_srpSwap);
555 _TCD(
srpTx,
"Packet size: %d", len);
558 memcpy(_srpSwap.content, message, len);
559 _srpSwap.hdr.msgId = _srpTxId ++;
561 _TCD(srpProcessTx,
"Transmitting noack lmsgId=%d", _srpSwap.hdr.msgId);
564 srpUdpTransmit(txAddr, len,
true);
568 static bool srpProcessTx()
571 return srpUdpTransmit(&addr, 0,
true);
578 static void srpProcessRx()
582 for (curEntry = _srpRxCacheFirst; curEntry <= _srpRxCacheLast; ++curEntry)
584 if (curEntry->flags & _SRP_RXF_USED)
586 if (srpTimeOut(curEntry->timeout)) {
587 _TCD(srpProcessRx,
"Freeing RX cache entry for rmsgId=%d", curEntry->msgId);
598 bool r = srpProcessTx();
612 assert ( _SRP_CACHE_MAX_AGE < (1 << 14));
614 _srpTxId = rand() & 0xFF;
#define SRP_TX_QUEUE_SIZE
Transmit queue buffer size.
A variable length queue implementation.
bool vqDeQueue(VarQueue *const vq, uint16_t *length, uint8_t *buffer)
DeQueues an element from the queue.
static bool qFull(Queue *q)
Returns whether or not the queue is full.
static void * qNext(Queue *q, void *ptr)
Peek at the next element in the queue.
void schdRunPeriodic(int taskId, int interval)
Schedule a task to run periodically.
bool vqQueue(VarQueue *const vq, uint16_t length, uint8_t *buffer)
Queues an element on the queue.
bool srpTx(SockAddr *txAddr, uint8_t *message, int len)
Invoked by application for sending an SRP packet.
#define SRP_RESEND_MAX
Max number of resends.
void _srpUdpTx(SockAddr *txAddr, uint8_t *udpPayload, int len)
Transmit UDP packet.
#define SRP_RESEND_TIMEOUT
Resend time-out in ms.
bool schdRegister(SchdTaskF task, bool priority, int *taskId)
Register a task with the scheduler.
void _srpLost(SockAddr *addr, uint8_t msgId)
Stub, invoked when an SRP message is lost.
SRP or Simple Retransmission Protocol is a protocol which retransmits packets if they have not been c...
Simple task scheduler for tasks.
void srpDumpStatus()
Outputs SRP status information.
#define STR(EXPR)
Stringyfies an expression.
Queue is created in statically allocated memory.
#define logWarn(MSG,...)
Format a log message with warning level.
void srpProcess()
Should be called periodically to process any pending requests.
void srpUdpRx(SockAddr *rxAddr, uint8_t *udpPayload, int len)
Invoked by UDP stack for receiving a SRP packet.
static bool sockAddrEq(SockAddr *addr1, SockAddr *addr2)
Checks if two socket addresses are equal.
Combination of IP address and port.
#define VQ_INIT(NAME, SIZE)
Initializes the variable length queue.
static void * qFirst(Queue *q)
Peek at the first element in the queue.
#define SRP_FLG_MSG
Contains message.
static bool qDeQueue(Queue *q, void *data)
Dequeue an element from the front of the queue.
#define SRP_TX_MAX_QUEUE
Allow up to 32 items on the TX queue.
#define CLE(A, B, BITS)
Cyclic comparison function Less Or Equal To.
#define SRP_MAX_ACKS
Maximum number of acknowledges.
#define SRP_FLG_DONTACK
No ack required.
static bool qQueue(Queue *q, void *data)
Queue data to the end of the queue.
uint16_t vqFree(VarQueue *const vq)
Returns the number of bytes free for the next element.
#define LOG_DEF(NAME,...)
Define a logger for a module.
#define SRP_FLG_ACK_SHIFT
Shift for the number of acks.
#define Q_INIT(NAME, ENTRY_SIZE, CAPACITY)
Convenience Macro, defines and inits queue.
#define SRP_FLG_ACK_MASK
Mask for the number of acks.
#define CGE(A, B, BITS)
Cyclic comparison function Greater Of Equal To.
#define SRP_MAX_PAYLOAD
maximum size of the payload of a SRP message.
#define SRP_RX_MAX_CACHE
Max receive confirms.
Implements a generic logger facility.
void _srpRx(SockAddr *rxAddr, uint8_t *message, int len)
Process a received SRP packet.
void * qDeQueueIP(Queue *q)
Dequeue an element from the front of the queue in place.
void srpInit()
Initializes the SRP protocol engine.
bool vqRemove(VarQueue *const vq)
Removes the first element from the queue (not the last).