26 typedef struct SrpStats_
30 uint32_t rx_cache_full;
38 static SrpStats _stats;
48 #define _TCD(NAME, FMT, ...) \
49 logDebug("dbg: " STR(NAME) ": " FMT, __VA_ARGS__)
51 #define _TCM(NAME, FMT, ...) \
52 logDebug("dbg: " STR(NAME), 0)
55 #define _TCD(NAME, FMT, ...)
56 #define _TCM(NAME, MSG)
62 static int _srpSchdPeriodicId;
67 #define _SRP_RESEND_SPREAD 64
71 #define _SRP_RESEND_TIMEOUT ( ( SRP_RESEND_TIMEOUT * CLOCKS_PER_SEC ) / 1000 )
73 #define _SRP_RESEND_TIMEOUT SRP_RESEND_TIMEOUT
80 #define _SRP_CACHE_MAX_AGE \
81 ( ( _SRP_RESEND_TIMEOUT + ( _SRP_RESEND_TIMEOUT / 2 ) * \
82 ( SRP_RESEND_MAX - 1 ) ) * SRP_RESEND_MAX )
84 #if (_SRP_CACHE_MAX_AGE > 0x7FFF)
85 #error "Timeout too big"
99 #define _SRP_TXF_CNT_MASK 0x3F
100 #define _SRP_TXF_CNT_SHIFT 0
101 #define _SRP_TXF_CONFIRMED BIT(6)
103 #define _SRP_TX_CNT_GET( F ) ( ( ( F ) & _SRP_TXF_CNT_MASK ) >> _SRP_TXF_CNT_SHIFT )
104 #define _SRP_TX_CNT_SET( C ) ( ( ( C ) << _SRP_TXF_CNT_SHIFT ) & _SRP_TXF_CNT_MASK )
121 static uint8_t _srpTxId;
125 #define _SRP_RXF_USED BIT(0)
126 #define _SRP_RXF_SEND_CFM BIT(1)
127 #define _SRP_RXF_NEED_CFM ( _SRP_RXF_USED | _SRP_RXF_SEND_CFM )
139 static SrpRxEntry *
const _srpRxCacheFirst = &_srpRxCache[0];
143 static inline uint16_t srpTimeOutNew(uint16_t to)
145 return ( clock() + to ) & 0xFFFF;
148 static inline bool srpTimeOut(uint16_t to)
150 return CGE(clock() & 0xFFFF, to, 16);
157 puts(
"---- SRP TX Queue ----");
161 printf(
"Commit content: %d of %d\n", _srpTxQueue.used, _srpTxQueue.size);
162 printf(
"Commit record : %d of %d\n", _srpTxRecQueue.length, _srpTxRecQueue.descr->capacity);
165 SrpTxRec * txRec = (SrpTxRec *)
qFirst(&_srpTxRecQueue);
167 while (txRec != NULL) {
168 printf(
"- %d: flags=%02x id=%d timeout=%d\n", t, txRec->flags, txRec->msgId, txRec->timeout);
169 txRec = (SrpTxRec *)
qNext(&_srpTxRecQueue, txRec);
174 puts(
"---- SRP RX Cache ----");
180 for (curEntry = _srpRxCacheFirst; curEntry <= _srpRxCacheLast; ++curEntry)
182 if (curEntry->flags & _SRP_RXF_USED) {
184 printf(
"- %d: flags=%02x id=%d timeout=%d\n",
185 t, curEntry->flags, curEntry->msgId, curEntry->timeout);
192 printf(
"RX-msg: %d, RX-dups: %d, RX-cache-full: %d\n", _stats.rx, _stats.rx_dup, _stats.rx_cache_full);
193 printf(
"RX-cfm: %d, RX-err-fmt: %d, RX-drop-ack: %d\n", _stats.rx_cfm, _stats.rx_err_fmt, _stats.rx_drop_ack);
194 printf(
"TX: %d, TX-err: %d\n", _stats.tx, _stats.tx_err);
200 static bool srpRxNew(
SockAddr * addr, uint8_t msgId)
217 if (curEntry->flags & _SRP_RXF_USED) {
218 if (
sockAddrEq(&(curEntry->addr), addr) && curEntry->msgId == msgId) {
219 curEntry->flags |= _SRP_RXF_SEND_CFM;
223 _TCD(srpRxNew,
"Received message wit rmsgID=%d before, ignore", msgId);
228 if (srpTimeOut(curEntry->timeout))
234 #ifdef SRP_STRICT_RX_CACHE
240 if (curEntry->flags == 0) {
242 bestEntry = curEntry;
250 if (bestEntry == NULL)
253 if (!(curEntry->flags & _SRP_RXF_SEND_CFM))
256 bestEntry = curEntry;
259 }
else if (bestEntry->flags != 0) {
263 if (curEntry->flags == 0) {
265 bestEntry = curEntry;
268 }
else if (bestEntry->flags != 0 &&
CLE(curEntry->timeout, bestEntry->timeout, 16)) {
271 bestEntry = curEntry;
277 curEntry = ( curEntry == _srpRxCacheLast ) ? _srpRxCacheFirst : curEntry + 1;
278 }
while (curEntry != firstEntry);
283 if (bestEntry == NULL)
286 logWarn(
"No free entries, could not accept message with rmsgID %d", msgId);
287 _stats.rx_cache_full += 1;
292 _TCD(srpRxNew,
"New entry to RX cache, old rmsgID = %d, new rmsgID = %d",
293 bestEntry->msgId, msgId);
294 bestEntry->flags = _SRP_RXF_SEND_CFM | _SRP_RXF_USED;
295 bestEntry->addr = *addr;
296 bestEntry->msgId = msgId;
297 bestEntry->timeout = srpTimeOutNew(_SRP_CACHE_MAX_AGE);
307 static bool srpAckFor(
SockAddr * addr, uint8_t * cfmPtr)
310 while (entry <= _srpRxCacheLast)
312 if ( ( entry->flags & _SRP_RXF_NEED_CFM ) == _SRP_RXF_NEED_CFM &&
316 *cfmPtr = entry->msgId;
318 _TCD(srpRxNew,
"Send confirm for rmsgId=%d", entry->msgId);
320 entry->flags &= ~_SRP_RXF_SEND_CFM;
338 static bool srpUdpTransmit(
SockAddr * addr,
int len,
bool dontack)
354 _srpSwap.hdr.flags = 0;
358 while (srpAckFor(addr, &(_srpSwap.hdr.ackId[ackCnt])))
365 if (ackCnt == 0 && len == 0)
return false;
367 _TCD(srpUdpTransmit,
"Transmitting: addr=0x%08x len=%d", addr->
ip, len);
371 _srpSwap.content[len] =
'\0';
384 void srpTxCfm(
SockAddr * sender, uint8_t msgId)
387 SrpTxRec * txRec =
qFirst(&_srpTxRecQueue);
389 while (txRec != NULL)
391 if (txRec->msgId == msgId &&
sockAddrEq(sender, &(txRec->addr)))
393 _TCD(srpTxCfm,
"Message lmsgID=%d confirmed!", txRec->msgId);
394 txRec->flags |= _SRP_TXF_CONFIRMED;
398 txRec =
qNext(&_srpTxRecQueue, txRec);
423 for (i = 0; i < cfm; ++i) {
424 srpTxCfm(rxAddr, msgPtr->hdr.ackId[i]);
429 _stats.rx_drop_ack++;
434 if (srpRxNew(rxAddr, msgPtr->hdr.msgId)) {
453 _TCD(
srpTx,
"Packet size: %d", len);
454 _TCD(
srpTx,
"TX Free: %d, used = %d, read = %d, write = %d",
vqFree(&_srpTxQueue),
455 _srpTxQueue.used, _srpTxQueue.read, _srpTxQueue.write);
458 logWarn(
"TX queue full, cannot create message");
461 if (
qFull(&_srpTxRecQueue)) {
463 logWarn(
"TX record queue full, cannot create message");
469 memcpy(_srpSwap.content, message, len);
470 _srpSwap.hdr.msgId = _srpTxId ++;
472 _TCD(srpProcessTx,
"Transmitting lmsgId=%d", _srpSwap.hdr.msgId);
474 srpUdpTransmit(txAddr, len,
false);
477 const SrpTxRec qRec =
480 .timeout = srpTimeOutNew( _SRP_RESEND_TIMEOUT + ( rand() % _SRP_RESEND_SPREAD ) ),
481 .flags = _SRP_TX_CNT_SET( 0 ),
482 .msgId = _srpSwap.hdr.msgId
485 qQueue(&_srpTxRecQueue, (uint8_t *)&qRec);
492 static bool srpProcessTx()
496 SrpTxRec * txRecPtr =
qFirst(&_srpTxRecQueue);
499 while (txRecPtr != NULL)
502 if (! ( txRecPtr->flags & _SRP_TXF_CONFIRMED ) )
505 if (!srpTimeOut(txRecPtr->timeout)) {
515 _srpLost(&(txRecPtr->addr), txRecPtr->msgId);
517 logWarn(
"Lost packet: SockAddr=0x%08x msgId=%d",
518 txRecPtr->addr.ip, txRecPtr->msgId);
526 txRecPtr =
qFirst(&_srpTxRecQueue);
530 if (txRecPtr == NULL )
534 return srpUdpTransmit(&addr, 0,
false);
541 uint16_t len =
sizeof(_srpSwap);
546 vqDeQueue(&_srpTxQueue, &len, (uint8_t *)&_srpSwap);
547 _TCD(srpProcessTx,
"Retransmitting lmsgId=%d", txRec.msgId);
549 srpUdpTransmit(&(txRec.addr), len -
sizeof(
SrpHeader),
false);
553 int cnt = _SRP_TX_CNT_GET( txRec.flags );
557 txRec.flags = ( txRec.flags & ~_SRP_TXF_CNT_MASK ) |
558 _SRP_TX_CNT_SET( cnt );
564 txRec.timeout = srpTimeOutNew( ( _SRP_RESEND_TIMEOUT * cnt )
565 + ( rand() % _SRP_RESEND_SPREAD ) );
569 qQueue(&_srpTxRecQueue, (uint8_t *)&txRec);
570 vqQueue(&_srpTxQueue, len, (uint8_t *)&_srpSwap);
588 _TCD(
srpTx,
"Packet size: %d", len);
592 logError(
"Invalid TX length! %d", len);
598 memcpy(_srpSwap.content, message, len);
599 _srpSwap.hdr.msgId = _srpTxId ++;
601 _TCD(srpProcessTx,
"Transmitting noack lmsgId=%d", _srpSwap.hdr.msgId);
604 srpUdpTransmit(txAddr, len,
true);
608 static bool srpProcessTx()
611 return srpUdpTransmit(&addr, 0,
true);
618 static void srpProcessRx()
622 for (curEntry = _srpRxCacheFirst; curEntry <= _srpRxCacheLast; ++curEntry)
624 if (curEntry->flags & _SRP_RXF_USED)
626 if (srpTimeOut(curEntry->timeout)) {
627 _TCD(srpProcessRx,
"Freeing RX cache entry for rmsgId=%d", curEntry->msgId);
638 bool r = srpProcessTx();
652 assert ( _SRP_CACHE_MAX_AGE < (1 << 14));
654 _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.
#define logError(MSG,...)
Format a log message with fatal level.
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).