OpenCores
URL https://opencores.org/ocsvn/rio/rio/trunk

Subversion Repositories rio

[/] [rio/] [trunk/] [sw/] [stack/] [riostack.c] - Blame information for rev 49

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 20 magro732
/*******************************************************************************
2
 *
3
 * RapidIO IP Library Core
4
 *
5
 * This file is part of the RapidIO IP library project
6
 * http://www.opencores.org/cores/rio/
7
 *
8
 * Description:
9
 * This file contains a software implementation of a RapidIO stack according to
10
 * the 2.2 version, part 6, of the standard. Only short control symbols are
11
 * supported.
12
 *
13
 * Symbols are in four flavors, idle, control, data and error. They are abstract
14
 * and should be serialized by any implementation to be sent on a transmission
15
 * channel. Error symbols are never generated by the stack and are used if the
16
 * symbol decoder encounters an error that the stack should be notified of.
17
 *
18 49 magro732
 * Symbols are inserted into the stack from the lower-half by calling
19
 * RIOSTACK_portAddSymbol() and symbols to transmit are fetched from the stack
20
 * using RIOSTACK_portGetSymbol(). These two functions are the low-level interface
21
 * towards a physical transmission channel.
22
 * The function RIOSTACK_portSetStatus() is used to indicate to the stack that initial
23 20 magro732
 * training of the symbol codec has been completed and that the transmission port
24
 * is ready to accept other symbols than idle. The procedure is to set the port
25
 * status to initialized once idle symbols are successfully received.
26
 *
27 49 magro732
 * On the upper-half interface are the RIOSTACK_setOutboundPacket() function used to
28
 * insert packets into the outbound transmission queue and RIOSTACK_getInboundPacket()
29
 * is used to get packet from the inbound reception queue. The
30
 * RIOSTACK_getInboundQueueLength() function is used to check if any packet is available
31
 * for reading in the inbound reception queue.
32 20 magro732
 *
33
 * -----------------
34
 * |  OS dependent |
35
 * |  (your code)  |
36
 * -----------------
37
 *        |
38
 * -----------------
39
 * |   RioStack    |
40
 * -----------------
41
 *        |
42
 * -----------------
43
 * | Symbol Codec  |
44
 * |  (your code)  |
45
 * -----------------
46
 *        |
47
 * -----------------
48
 * |  Port driver  |
49
 * -----------------
50
 *        |
51
 * -----------------
52
 * | Physical port |
53
 * -----------------
54
 *
55
 * The symbol codec maps a RapidIO symbol to the physical transmission media.
56
 *
57
 * Some typical patterns to handle this stack are:
58
 * Initialization:
59 49 magro732
 *   RIOSTACK_open(...);
60
 *   RIOSTACK_portSetTimeout(...);
61 20 magro732
 *   ...
62
 *   <Symbol transcoder is successfully decoding symbols from the link>
63 49 magro732
 *   RIOSTACK_portSetStatus(1);
64 20 magro732
 *
65
 * Bottom-half traffic handling:
66 49 magro732
 *   RIOSTACK_portSetTime(...);
67 20 magro732
 *   <get symbol from decoder>
68 49 magro732
 *   RIOSTACK_portAddSymbol(...);
69
 *   s = RIOSTACK_portGetSymbol(...);
70 20 magro732
 *   <send symbol to encoder>
71
 *
72
 * Receiving packets:
73 49 magro732
 *   if(RIOSTACK_getInboundQueueLength(...) > 0)
74 20 magro732
 *   {
75 49 magro732
 *     RIOSTACK_getInboundPacket(...);
76
 *     <process the new packet>
77 20 magro732
 *   }
78
 *
79
 * Transmitting packets:
80 49 magro732
 *   <create a new packet>
81
 *   if(RIOSTACK_getOutboundQueueAvailable(...) > 0)
82 20 magro732
 *   {
83 49 magro732
 *     RIOSTACK_setOutboundPacket(...);
84 20 magro732
 *   }
85
 *
86 49 magro732
 * More details about the usage can be found in the module tests in test_riostack.c.
87 20 magro732
 *
88
 * To Do:
89 49 magro732
 * - Optimize the packing of stype0 and stype1 into control symbols.
90 20 magro732
 *
91
 * Author(s):
92
 * - Magnus Rosenius, magro732@opencores.org
93
 *
94
 *******************************************************************************
95
 *
96 49 magro732
 * Copyright (C) 2015 Authors and OPENCORES.ORG
97 20 magro732
 *
98
 * This source file may be used and distributed without
99
 * restriction provided that this copyright statement is not
100
 * removed from the file and that any derivative work contains
101
 * the original copyright notice and the associated disclaimer.
102
 *
103
 * This source file is free software; you can redistribute it
104
 * and/or modify it under the terms of the GNU Lesser General
105
 * Public License as published by the Free Software Foundation;
106
 * either version 2.1 of the License, or (at your option) any
107
 * later version.
108
 *
109
 * This source is distributed in the hope that it will be
110
 * useful, but WITHOUT ANY WARRANTY; without even the implied
111
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
112
 * PURPOSE. See the GNU Lesser General Public License for more
113
 * details.
114
 *
115
 * You should have received a copy of the GNU Lesser General
116
 * Public License along with this source; if not, download it
117
 * from http://www.opencores.org/lgpl.shtml
118
 *
119
 *******************************************************************************/
120
 
121 49 magro732
 
122 20 magro732
/**
123
 * \file riostack.c
124
 */
125
 
126
/*******************************************************************************
127
 * Includes
128
 *******************************************************************************/
129
 
130
#include "riostack.h"
131
 
132
 
133
/*lint -e961 Allow function like macros. */
134
/*lint -e621 Long identifier names allowed to increase readability. */
135
/*lint -w2 */
136
 
137
 
138 49 magro732
/*lint --estring(960,17.4) It is not possible to implement a rio stack without some
139 20 magro732
 * pointer arithmetic */
140
 
141 49 magro732
 
142 20 magro732
/*******************************************************************************
143
 * Local macro definitions
144
 *******************************************************************************/
145
 
146
/* Macro to update 5-bit ackId counters. */
147
#define ACKID_INC(ackId) (((ackId)+1)&0x1f)
148
 
149
/* Macros to get entries from a control symbol. */
150
#define STYPE0_GET(data) ((uint8_t) (((data) >> 21) & 0x00000007u))
151
#define PARAMETER0_GET(data) ((uint8_t) (((data) >> 16) & 0x00000001fu))
152
#define PARAMETER1_GET(data) ((uint8_t) (((data) >> 11) & 0x00000001fu))
153
#define STYPE1_GET(data) ((uint8_t) (((data) >> 8) & 0x00000007u))
154
#define CMD_GET(data) ((uint8_t) (((data) >> 5) & 0x00000007u))
155
#define CRC5_GET(data) ((uint8_t) (((data) >> 0) & 0x0000001fu))
156
 
157
/* Macros to get entries from a packet in a buffer. */
158
#define FTYPE_GET(p) (((p)[0] >> 16) & 0xf)
159
#define DESTID_GET(p) ((p)[0] & 0xffff)
160
#define SRCID_GET(p) (((p)[1] >> 16) & 0xffff)
161
#define TRANSACTION_GET(p) (((p)[1] >> 12) & 0xf)
162
#define MSGLEN_GET(p) TRANSACTION_GET(p)
163
#define SSIZE_GET(p) (((p)[1] >> 8) & 0xf)
164
#define LETTER_GET(p) (((p)[1] >> 6) & 0x3)
165
#define MBOX_GET(p) (((p)[1] >> 4) & 0x3)
166
#define MSGSEG_GET(p) ((p)[1] & 0xf)
167
#define XMBOX_GET(p) MSGSEG_GET(p)
168
#define RDSIZE_GET(p) SSIZE_GET(p)
169
#define WRSIZE_GET(p) SSIZE_GET(p)
170
#define TID_GET(p) ((p)[1] & 0xff)
171
#define HOP_GET(p) (((p)[2] >> 24) & 0xff)
172
#define CONFIG_OFFSET_GET(p) ((p)[2] & 0x00fffffcul)
173
#define INFO_GET(p) (((p)[2] >> 16) & 0xffff)
174
#define ADDRESS_GET(p) ((p)[2] & 0xfffffff8ul)
175
#define WDPTR_GET(p) (((p)[2] >> 2) & 0x1)
176
#define XAMBS_GET(p) ((p)[2] & 0x3)
177
#define DOUBLE_WORD_MSB_GET(p, i) (p)[3+(2*i+0)]
178
#define DOUBLE_WORD_LSB_GET(p, i) (p)[3+(2*i+1)]
179
 
180
/* Transmitter frame states. */
181
#define TX_FRAME_START                  ((uint8_t)0u)
182
#define TX_FRAME_BODY                   ((uint8_t)1u)
183
 
184
/* Control symbol constants. */
185
#define STYPE0_PACKET_ACCEPTED          ((uint8_t)0x00u)
186
#define STYPE0_PACKET_RETRY             ((uint8_t)0x01u)
187
#define STYPE0_PACKET_NOT_ACCEPTED      ((uint8_t)0x02u)
188
#define STYPE0_RESERVED                 ((uint8_t)0x03u)
189
#define STYPE0_STATUS                   ((uint8_t)0x04u)
190
#define STYPE0_VC_STATUS                ((uint8_t)0x05u)
191
#define STYPE0_LINK_RESPONSE            ((uint8_t)0x06u)
192
#define STYPE0_IMPLEMENTATION_DEFINED   ((uint8_t)0x07u)
193
#define STYPE1_START_OF_PACKET          ((uint8_t)0x00u)
194
#define STYPE1_STOMP                    ((uint8_t)0x01u)
195
#define STYPE1_END_OF_PACKET            ((uint8_t)0x02u)
196
#define STYPE1_RESTART_FROM_RETRY       ((uint8_t)0x03u)
197
#define STYPE1_LINK_REQUEST             ((uint8_t)0x04u)
198
#define STYPE1_MULTICAST_EVENT          ((uint8_t)0x05u)
199
#define STYPE1_RESERVED                 ((uint8_t)0x06u)
200
#define STYPE1_NOP                      ((uint8_t)0x07u)
201
 
202
/* Packet ftype constants. */
203
#define FTYPE_REQUEST 0x2
204
#define FTYPE_WRITE 0x5
205
#define FTYPE_MAINTENANCE 0x8
206
#define FTYPE_DOORBELL 0xa
207
#define FTYPE_MESSAGE 0xb
208
#define FTYPE_RESPONSE 0xd
209
 
210
/* Transaction constants. */
211
#define TRANSACTION_MAINT_READ_REQUEST 0
212
#define TRANSACTION_MAINT_WRITE_REQUEST 1
213
#define TRANSACTION_MAINT_READ_RESPONSE 2
214
#define TRANSACTION_MAINT_WRITE_RESPONSE 3
215
#define TRANSACTION_WRITE_NWRITE 4
216
#define TRANSACTION_WRITE_NWRITER 5
217
#define TRANSACTION_REQUEST_NREAD 4
218
#define TRANSACTION_RESPONSE_NO_PAYLOAD 0
219
#define TRANSACTION_RESPONSE_MESSAGE_RESPONSE 1
220
#define TRANSACTION_RESPONSE_WITH_PAYLOAD 8
221
 
222
/* Maintenance transaction lengths. */
223
#define MAINTENANCE_TRANSACTION_READ_REQUEST_SIZE ((uint32_t) 4ul)
224
#define MAINTENANCE_TRANSACTION_WRITE_REQUEST_SIZE ((uint32_t) 6ul)
225
#define MAINTENANCE_TRANSACTION_READ_RESPONSE_SIZE ((uint32_t) 6ul)
226
#define MAINTENANCE_TRANSACTION_WRITE_RESPONSE_SIZE ((uint32_t) 4ul)
227
 
228
/* Constants used to forward different errors to the link partner. */
229
#define PACKET_NOT_ACCEPTED_CAUSE_RESERVED 0u
230
#define PACKET_NOT_ACCEPTED_CAUSE_UNEXPECTED_ACKID 1u
231
#define PACKET_NOT_ACCEPTED_CAUSE_CONTROL_CRC 2u
232
#define PACKET_NOT_ACCEPTED_CAUSE_NON_MAINTENANCE 3u
233
#define PACKET_NOT_ACCEPTED_CAUSE_PACKET_CRC 4u
234
#define PACKET_NOT_ACCEPTED_CAUSE_ILLEGAL_CHARACTER 5u
235
#define PACKET_NOT_ACCEPTED_CAUSE_NO_RESOURCE 6u
236
#define PACKET_NOT_ACCEPTED_CAUSE_DESCRAMBLER 7u
237
#define PACKET_NOT_ACCEPTED_CAUSE_GENERAL 31u
238
 
239
/* Constants used to request link-responses. */
240
#define LINK_REQUEST_RESET_DEVICE 3u
241
#define LINK_REQUEST_INPUT_STATUS 4u
242
 
243
/* Constants used to forward a port status in a link-resonse. */
244
#define LINK_RESPONSE_PORT_STATUS_ERROR 2u
245
#define LINK_RESPONSE_PORT_STATUS_RETRY_STOPPED 4u
246
#define LINK_RESPONSE_PORT_STATUS_ERROR_STOPPED 5u
247
#define LINK_RESPONSE_PORT_STATUS_OK 16u
248
 
249 49 magro732
 
250
 
251 20 magro732
/*******************************************************************************
252
 * Local typedefs
253
 *******************************************************************************/
254
 
255 49 magro732
 
256
 
257 20 magro732
/*******************************************************************************
258
 * Global declarations
259
 *******************************************************************************/
260
 
261 49 magro732
 
262
 
263 20 magro732
/*******************************************************************************
264
 * Local declarations
265
 *******************************************************************************/
266
 
267 49 magro732
 
268
 
269 20 magro732
/*******************************************************************************
270
 * Local function prototypes
271
 *******************************************************************************/
272
 
273
/* Helper functions for protocol events. */
274
static void handleStatus(RioStack_t *stack, const uint8_t ackId, const uint8_t bufferStatus);
275
static void handlePacketAccepted(RioStack_t *stack, const uint8_t ackId, const uint8_t bufferStatus);
276
static void handlePacketRetry(RioStack_t *stack, const uint8_t ackId, const uint8_t bufferStatus);
277
static void handlePacketNotAccepted(RioStack_t *stack, const uint8_t arbitrary, const uint8_t cause);
278
static void handleLinkResponse(RioStack_t *stack, const uint8_t ackId, const uint8_t portStatus);
279
static void handleStartOfPacket(RioStack_t *stack);
280
static void handleEndOfPacket(RioStack_t *stack);
281
static void handleLinkRequest(RioStack_t *stack, uint8_t cmd);
282
static void handleNewPacketStart(RioStack_t *stack);
283
static void handleNewPacketEnd(RioStack_t *stack);
284
 
285
/**
286
 * \brief Create a control symbol.
287
 *
288
 * \param[in] stype0 The stype0 value.
289
 * \param[in] parameter0 The parameter0 value.
290
 * \param[in] parameter1 The parameter1 value.
291
 * \param[in] stype1 The stype1 value.
292
 * \param[in] cmd The cmd value.
293
 * \return The control symbol that were created from the input parameters.
294
 *
295
 * This function creates a control symbol with the specified arguments and
296
 * calculates a CRC-5 checksum according to the standard specification.
297
 */
298 49 magro732
static RioSymbol_t CreateControlSymbol(const uint8_t stype0,
299
                                       const uint8_t parameter0, const uint8_t parameter1,
300
                                       const uint8_t stype1, const uint8_t cmd);
301 20 magro732
 
302
/**
303
 * \brief Function to calculate ITU-CRC5, polynom=0x15.
304
 *
305
 * \param[in] data The data of a control symbol.
306
 * \param[in] crc The crc to initiate the result with.
307
 * \return A new CRC-5 value.
308
 */
309 49 magro732
static uint8_t Crc5(const uint32_t data, const uint8_t crc);
310 20 magro732
 
311
/**
312
 * \brief Create a queue with a specified size and a buffer attached to it.
313
 *
314 49 magro732
 * \param[in] size The number of entries in the queue.
315
 * \param[in] buffer A pointer to the buffer to store the content in.
316 20 magro732
 * \return A queue with the specified size and where new data will be stored
317
 * to the specified buffer.
318
 */
319 49 magro732
static Queue_t QueueCreate(const uint8_t size, uint32_t *buffer);
320 20 magro732
 
321
/**
322
 * \brief Get number of available elements.
323
 *
324
 * \param[in] q The queue to operate on.
325
 * \return The number of free packet buffers in the queue.
326
 */
327 49 magro732
static uint8_t QueueAvailable(const Queue_t q );
328 20 magro732
 
329
/**
330
 * \brief Get if the queue is empty or not.
331
 *
332
 * \param[in] q The queue to operate on.
333
 * \return Non-zero if the queue is empty.
334
 */
335 49 magro732
static int QueueEmpty(const Queue_t q);
336 20 magro732
 
337
/**
338
 * \brief Get the length of a queue.
339
 *
340
 * \param[in] q The queue to operate on.
341
 * \return The number of elements in the queue.
342
 */
343 49 magro732
static uint8_t QueueLength(const Queue_t q);
344 20 magro732
 
345
/**
346
 * \brief Add a new element to the queue.
347
 *
348
 * \param[in] q The queue to operate on.
349
 * \return A queue with one added element.
350
 */
351 49 magro732
static Queue_t QueueEnqueue(Queue_t q);
352 20 magro732
 
353
/**
354
 * \brief Remove an element from the queue.
355
 *
356
 * \param[in] q The queue to operate on.
357
 * \return A queue with on removed element.
358
 */
359 49 magro732
static Queue_t QueueDequeue(Queue_t q);
360 20 magro732
 
361
/**
362
 * \brief Check if the readout window is empty.
363
 *
364
 * \param[in] q The queue to operate on.
365
 * \return If the readout window is empty.
366
 */
367 49 magro732
static int QueueWindowEmpty(const Queue_t q);
368 20 magro732
 
369
/**
370
 * \brief Reset the window to none.
371
 *
372
 * \param[in] q The queue to operate on.
373
 * \return The updated Queue_t structure.
374
 */
375
static Queue_t QueueWindowReset(Queue_t q);
376
 
377
/**
378
 * \brief Increase the window to the next pending element.
379
 *
380
 * \param[in] q The queue to operate on.
381
 * \return The updated Queue_t structure.
382
 */
383
static Queue_t QueueWindowNext(Queue_t q);
384
 
385
/**
386
 * \brief Set actual size of the newest element.
387
 *
388
 * \param[in] q The queue to operate on.
389
 * \param[in] size The size to set the newest content size to.
390
 */
391 49 magro732
static void QueueSetSize(Queue_t q, const uint32_t size);
392 20 magro732
 
393
/**
394
 * \brief Set content at a specified index in the newest element.
395
 *
396
 * \param[in] q The queue to operate on.
397
 * \param[in] index posititon into the element
398
 * \param[in] content The content to set at the specified index in the newest queue element.
399
 */
400 49 magro732
static void QueueSetContent(Queue_t q, const uint32_t index, const uint32_t content);
401 20 magro732
 
402
/**
403
 * \brief Get a pointer to the buffer of the newest element.
404
 *
405
 * \param[in] q The queue to operate on.
406
 * \return A pointer to the content.
407
 */
408 49 magro732
static uint32_t *QueueGetBackBuffer(Queue_t q );
409 20 magro732
 
410
/**
411
 * \brief Get the size of the oldest element.
412
 * \param[in] q The queue to operate on.
413
 * \return The size of the element.
414
 */
415 49 magro732
static uint32_t QueueGetSize(Queue_t q );
416 20 magro732
 
417
/**
418
 * \brief Get the content of the oldest element at specified index.
419
 * \param[in] q The queue to operate on.
420
 * \param[in] index The index into the element to get the content from.
421
 * \return content of element at index position.
422
 */
423 49 magro732
static uint32_t QueueGetFrontContent(Queue_t q, const uint32_t index);
424 20 magro732
 
425
/**
426
 * \brief Get a pointer to the buffer of the oldest element.
427
 *
428
 * \param[in] q The queue to operate on.
429
 * \return A pointer to the content.
430
 */
431 49 magro732
static uint32_t *QueueGetFrontBuffer(Queue_t q );
432 20 magro732
 
433
 
434
 
435
/*******************************************************************************
436
 * Global functions
437
 *******************************************************************************/
438
 
439 49 magro732
void RIOSTACK_open(RioStack_t *stack, void *private,
440
                   const uint32_t rxPacketBufferSize, uint32_t *rxPacketBuffer,
441
                   const uint32_t txPacketBufferSize, uint32_t *txPacketBuffer)
442 20 magro732
{
443
  /* Port time and timeout limit. */
444
  stack->portTime = 0u;
445
  stack->portTimeout = 1000u;
446
 
447
  /* Setup the receiver. */
448
  stack->rxState = RX_STATE_UNINITIALIZED;
449
  stack->rxCounter = 0u;
450
  stack->rxCrc = 0xffffu;
451
  stack->rxStatusReceived = 0u;
452
  stack->rxAckId = 0u;
453
  stack->rxAckIdAcked = 0u;
454
  stack->rxErrorCause = PACKET_NOT_ACCEPTED_CAUSE_RESERVED;
455 49 magro732
  stack->rxQueue = QueueCreate((uint8_t) (rxPacketBufferSize/RIOSTACK_BUFFER_SIZE), rxPacketBuffer);
456 20 magro732
 
457
  /* Setup the transmitter. */
458
  stack->txState = TX_STATE_UNINITIALIZED;
459
  stack->txCounter = 0u;
460
  stack->txStatusCounter = 0u;
461
  stack->txFrameState = TX_FRAME_START;
462
  stack->txAckId = 0u;
463
  stack->txAckIdWindow = 0u;
464 49 magro732
  stack->txQueue = QueueCreate((uint8_t) (txPacketBufferSize/RIOSTACK_BUFFER_SIZE), txPacketBuffer);
465 20 magro732
 
466
  /* Setup status counters for inbound direction. */
467
  stack->statusInboundPacketComplete = 0ul;
468
  stack->statusInboundPacketRetry = 0ul;
469
  stack->statusInboundErrorControlCrc = 0ul;
470
  stack->statusInboundErrorPacketAckId = 0ul;
471
  stack->statusInboundErrorPacketCrc = 0ul;
472
  stack->statusInboundErrorIllegalCharacter = 0ul;
473
  stack->statusInboundErrorGeneral = 0ul;
474
  stack->statusInboundErrorPacketUnsupported = 0ul;
475
 
476
  /* Setup status counters for outbound direction. */
477
  stack->statusOutboundPacketComplete = 0ul;
478 49 magro732
  stack->statusOutboundLinkLatencyMax = 0ul;
479 20 magro732
  stack->statusOutboundPacketRetry = 0ul;
480
  stack->statusOutboundErrorTimeout = 0ul;
481
  stack->statusOutboundErrorPacketAccepted = 0ul;
482
  stack->statusOutboundErrorPacketRetry = 0ul;
483
 
484
  /* Setup status counters for potential problems on the link-partner. */
485
  stack->statusPartnerLinkRequest = 0ul;
486
  stack->statusPartnerErrorControlCrc = 0ul;
487
  stack->statusPartnerErrorPacketAckId = 0ul;
488
  stack->statusPartnerErrorPacketCrc = 0ul;
489
  stack->statusPartnerErrorIllegalCharacter = 0ul;
490
  stack->statusPartnerErrorGeneral = 0ul;
491
 
492
  /* Set pointer to user private data. */
493
  stack->private = private;
494
}
495
 
496
 
497 49 magro732
 
498 20 magro732
/*******************************************************************************************
499 49 magro732
 * Stack status and queue access functions.
500
 * Note that status counters are accessed directly in the stack-structure.
501 20 magro732
 *******************************************************************************************/
502
 
503 49 magro732
int RIOSTACK_getStatus(RioStack_t *stack)
504 20 magro732
{
505 49 magro732
  return !(((stack->rxState == RX_STATE_UNINITIALIZED) || (stack->rxState == RX_STATE_PORT_INITIALIZED)) &&
506
           ((stack->txState == TX_STATE_UNINITIALIZED) || (stack->txState == TX_STATE_PORT_INITIALIZED)));
507
}
508 20 magro732
 
509
 
510
 
511 49 magro732
void RIOSTACK_clearOutboundQueue(RioStack_t *stack)
512
{
513
  while(!QueueEmpty(stack->txQueue))
514 20 magro732
  {
515 49 magro732
    stack->txQueue = QueueDequeue(stack->txQueue);
516 20 magro732
  }
517
}
518
 
519
 
520 49 magro732
 
521
uint8_t RIOSTACK_getOutboundQueueLength(RioStack_t *stack)
522 20 magro732
{
523
  return QueueLength(stack->txQueue);
524
}
525
 
526
 
527
 
528 49 magro732
uint8_t RIOSTACK_getOutboundQueueAvailable(RioStack_t *stack)
529 20 magro732
{
530 49 magro732
  return QueueAvailable(stack->txQueue);
531 20 magro732
}
532
 
533
 
534
 
535 49 magro732
void RIOSTACK_setOutboundPacket(RioStack_t *stack, RioPacket_t *packet)
536 20 magro732
{
537 49 magro732
  uint32_t *src, *dst;
538
  uint32_t size;
539 20 magro732
  uint32_t i;
540
 
541
 
542 49 magro732
  ASSERT((QueueAvailable(stack->txQueue) > 0u),
543
         "Transmission queue packet overflow.");
544 20 magro732
 
545 49 magro732
  src = &packet->payload[0];
546
  dst = QueueGetBackBuffer(stack->txQueue);
547
  size = packet->size;
548 20 magro732
  for(i = 0; i < size; i++)
549
  {
550 49 magro732
    dst[i] = src[i];
551 20 magro732
  }
552
 
553 49 magro732
  QueueSetSize(stack->txQueue, size);
554 20 magro732
  stack->txQueue = QueueEnqueue(stack->txQueue);
555
}
556
 
557
 
558
 
559 49 magro732
void RIOSTACK_clearInboundQueue(RioStack_t *stack)
560 20 magro732
{
561 49 magro732
  while(!QueueEmpty(stack->rxQueue))
562 20 magro732
  {
563 49 magro732
    stack->rxQueue = QueueDequeue(stack->rxQueue);
564 20 magro732
  }
565
}
566
 
567
 
568
 
569 49 magro732
uint8_t RIOSTACK_getInboundQueueLength(RioStack_t *stack)
570 20 magro732
{
571 49 magro732
  return QueueLength(stack->rxQueue);
572 20 magro732
}
573
 
574
 
575
 
576 49 magro732
uint8_t RIOSTACK_getInboundQueueAvailable(RioStack_t *stack)
577 20 magro732
{
578 49 magro732
  return QueueAvailable(stack->rxQueue);
579 20 magro732
}
580
 
581
 
582
 
583 49 magro732
void RIOSTACK_getInboundPacket(RioStack_t *stack, RioPacket_t *packet)
584 20 magro732
{
585 49 magro732
  uint32_t *src, *dst;
586
  uint32_t size;
587
  uint32_t i;
588 20 magro732
 
589
 
590 49 magro732
  ASSERT(!QueueEmpty(stack->rxQueue), "Reading from empty reception queue.");
591 20 magro732
 
592 49 magro732
  src = QueueGetFrontBuffer(stack->rxQueue);
593
  dst = &packet->payload[0];
594
  size = QueueGetSize(stack->rxQueue);
595
  for(i = 0; i < size; i++)
596
  {
597
    dst[i] = src[i];
598
  }
599 20 magro732
 
600 49 magro732
  packet->size = size;
601
  stack->rxQueue = QueueDequeue(stack->rxQueue);
602 20 magro732
}
603
 
604
 
605
 
606
/*******************************************************************************************
607 49 magro732
 * Packet port functions.
608 20 magro732
 *******************************************************************************************/
609
 
610 49 magro732
void RIOSTACK_portSetTime(RioStack_t *stack, const uint32_t time)
611 20 magro732
{
612 49 magro732
  stack->portTime = time;
613 20 magro732
}
614
 
615
 
616
 
617 49 magro732
void RIOSTACK_portSetTimeout(RioStack_t *stack, const uint32_t time)
618 20 magro732
{
619 49 magro732
  stack->portTimeout = time;
620 20 magro732
}
621
 
622
 
623
 
624 49 magro732
void RIOSTACK_portSetStatus(RioStack_t *stack, const uint8_t initialized)
625 20 magro732
{
626
  /* REMARK: Clean the queues here as well??? */
627
  if (initialized)
628
  {
629
    stack->rxState = RX_STATE_PORT_INITIALIZED;
630
    stack->rxCounter = 0u;
631
    stack->rxCrc = 0xffffu;
632
    stack->rxStatusReceived = 0;
633
    stack->rxAckId = 0u;
634
    stack->rxAckIdAcked = 0u;
635
    stack->rxErrorCause = PACKET_NOT_ACCEPTED_CAUSE_RESERVED;
636
 
637
    stack->txState = TX_STATE_PORT_INITIALIZED;
638
    stack->txCounter = 0u;
639
    stack->txStatusCounter = 0u;
640
    stack->txFrameState = TX_FRAME_START;
641
    stack->txAckId = 0u;
642
    stack->txAckIdWindow = 0u;
643
  }
644
  else
645
  {
646
    stack->rxState = RX_STATE_UNINITIALIZED;
647
    stack->txState = TX_STATE_UNINITIALIZED;
648
  }
649
}
650
 
651
 
652
 
653 49 magro732
void RIOSTACK_portAddSymbol(RioStack_t *stack, const RioSymbol_t s)
654 20 magro732
{
655
  uint8_t stype0;
656
  uint8_t parameter0;
657
  uint8_t parameter1;
658
  uint8_t stype1;
659
 
660
 
661
  switch(stack->rxState)
662
  {
663
    case RX_STATE_PORT_INITIALIZED:
664
      /******************************************************************************
665
       * PORT_INITIALIZED
666
       * This state is entered to initialize the link. Only status-control-symbols
667
       * are accepted in this state. When 7 error-free, i.e. with CRC5 correct, status
668
       * control symbols has been received, change state to linkInitialized.
669
       ******************************************************************************/
670
 
671
      /* Check the type of symbol. */
672 49 magro732
      if(s.type == RIOSTACK_SYMBOL_TYPE_CONTROL)
673 20 magro732
      {
674
        /* This is a control symbol. */
675
 
676
        /* Check that the control symbol contains no errors. */
677
        if(Crc5(s.data, 0x1fu) == (s.data & 0x1ful))
678
        {
679
          /* Error-free control symbol. */
680
 
681
          /* Check if the symbol is a status symbol. */
682
          stype0 = STYPE0_GET(s.data);
683
          if(stype0 == STYPE0_STATUS)
684
          {
685
            /* Status symbol received. */
686
 
687
            /* Indicate an error-free status has been received. */
688
            stack->rxStatusReceived = 1;
689
 
690
            /* Check if enough status control symbols has been received. */
691
            if(stack->rxCounter == 7u)
692
            {
693
              /* Enough correct status control symbols has been received without
694
                 errors in between. */
695
 
696
              /* Setup the transmitter with the content of the symbol. */
697
              stack->txAckId = PARAMETER0_GET(s.data);
698
              stack->txAckIdWindow = stack->txAckId;
699
              stack->txBufferStatus = PARAMETER1_GET(s.data);
700
 
701
              /* Set the transmitter in its normal operational mode. */
702
              stack->rxState = RX_STATE_LINK_INITIALIZED;
703
              stack->rxCounter = 0u;
704
            }
705
            else
706
            {
707
              /* Count the number of consequitive error-free status control symbols
708
                 that has been received. */
709
              stack->rxCounter++;
710
            }
711
          }
712
          else
713
          {
714
            /* The received symbol is not a status symbol. */
715
            /* Discard it. */
716
          }
717
        }
718
        else
719
        {
720
          /* CRC error in control symbol. */
721
          /* Restart counting error-free status-control-symbols. */
722
          stack->rxCounter = 0u;
723
        }
724
      }
725
      else
726
      {
727
        /* Not a control symbol. */
728
        /* Discard the symbol. */
729
      }
730
 
731
      break;
732
 
733
    case RX_STATE_LINK_INITIALIZED:
734
      /******************************************************************************
735
       * LINK_INITIALIZED
736
       * The normal state. Accept packets and forward them.
737
       ******************************************************************************/
738
 
739
      /* Check the type of symbol. */
740
      switch(s.type)
741
      {
742 49 magro732
        case RIOSTACK_SYMBOL_TYPE_CONTROL:
743 20 magro732
          /**************************************************************************
744
           * This is a control symbol.
745
           **************************************************************************/
746
 
747
          /* Check if the CRC is correct. */
748
          if(Crc5(s.data, 0x1fu) == (s.data & (uint8_t)0x1ful))
749
          {
750
            /* The CRC is correct. */
751
 
752
            /* Get the content of the control symbol. */
753
            stype0 = STYPE0_GET(s.data);
754
            parameter0 = PARAMETER0_GET(s.data);
755
            parameter1 = PARAMETER1_GET(s.data);
756
            stype1 = STYPE1_GET(s.data);
757
 
758
            /**********************************************************************************
759
             * Check the stype0 part of the symbol.
760
             * Note that errors in this should trigger OUTPUT_ERROR_STOPPED.
761
             **********************************************************************************/
762
            switch(stype0)
763
            {
764
              case STYPE0_STATUS:
765
                /* A status containing the current ackId and the buffer status has been
766
                   received. */
767
                handleStatus(stack, parameter0, parameter1);
768
                break;
769
 
770
              case STYPE0_PACKET_ACCEPTED:
771
                /* A packet has been accepted by the link partner. */
772
                handlePacketAccepted(stack, parameter0, parameter1);
773
                break;
774
 
775
              case STYPE0_PACKET_RETRY:
776
                /* The link partner wants us to initiate a restart of the received ackId. */
777
                handlePacketRetry(stack, parameter0, parameter1);
778
                break;
779
 
780
              case STYPE0_PACKET_NOT_ACCEPTED:
781
                /* The link partner indicates that a packet has been rejected. */
782
                handlePacketNotAccepted(stack, parameter0, parameter1);
783
                break;
784
 
785
              case STYPE0_LINK_RESPONSE:
786
                /* The link partner has sent a response to a link-request. */
787
                handleLinkResponse(stack, parameter0, parameter1);
788
                break;
789
 
790
              case STYPE0_VC_STATUS:
791
              case STYPE0_RESERVED:
792
              case STYPE0_IMPLEMENTATION_DEFINED:
793
              default:
794
                /* Unsupported symbol received. */
795
                /* Discard them. */
796
                break;
797
            }
798
 
799
            /**********************************************************************************
800
             * Check the stype1 part of the symbol.
801
             * Note that errors in this should trigger INPUT_ERROR_STOPPED.
802
             **********************************************************************************/
803
            switch(stype1)
804
            {
805
              case STYPE1_START_OF_PACKET:
806
                /* Start of a new packet. */
807
                handleStartOfPacket(stack);
808
                break;
809
 
810
              case STYPE1_END_OF_PACKET:
811
                /* Ending a packet. */
812
                handleEndOfPacket(stack);
813
                break;
814
 
815
              case STYPE1_STOMP:
816
                /* Cancel the currently received frame. */
817
                stack->rxCounter = 0;
818
                break;
819
 
820
              case STYPE1_RESTART_FROM_RETRY:
821
                /* Cancel the currently received frame when in this state. */
822
                stack->rxCounter = 0;
823
                break;
824
 
825
              case STYPE1_LINK_REQUEST:
826
                /* A link-request has been received. */
827
                handleLinkRequest(stack, CMD_GET(s.data));
828
                break;
829
 
830
              case STYPE1_NOP:
831
                /* No operation symbol. */
832
                /* Discard these. */
833
                break;
834
 
835
              case STYPE1_MULTICAST_EVENT:
836
              case STYPE1_RESERVED:
837
              default:
838
                /* Unsupported symbol received. */
839
                /* Discard them. */
840
                break;
841
            }
842
          }
843
          else
844
          {
845
            /* The control symbol CRC is incorrect. */
846
            /* Corrupted control symbol. Discard the symbol and enter the input-error-stopped state. */
847
            stack->txState = TX_STATE_SEND_PACKET_NOT_ACCEPTED;
848
            stack->rxState = RX_STATE_INPUT_ERROR_STOPPED;
849
            stack->rxErrorCause = PACKET_NOT_ACCEPTED_CAUSE_CONTROL_CRC;
850
            stack->statusInboundErrorControlCrc++;
851
          }
852
          break;
853
 
854 49 magro732
        case RIOSTACK_SYMBOL_TYPE_DATA:
855 20 magro732
          /**************************************************************************
856
           * This is a data symbol.
857
           **************************************************************************/
858
 
859
          /* Check if a packet has been started and that it is not too long. */
860 49 magro732
          if ((stack->rxCounter >= 1u) && (stack->rxCounter <= RIOPACKET_SIZE_MAX))
861 20 magro732
          {
862
            /* A packet has been started. */
863
 
864
            /* Check if the ackId is correct on the first part of the packet. */
865
            if ((stack->rxCounter > 1u) ||
866
                ((stack->rxCounter == 1u) && (((uint8_t)(s.data >> 27)) == stack->rxAckId)))
867
            {
868
              /* The ackId is the expected one. */
869
 
870
              /* Check if this is the first symbol of a packet. */
871
              if (stack->rxCounter == 1u)
872
              {
873
                /* This is the first symbol of the packet. */
874
                /* Start to calculate the CRC of the packet. */
875
                /* Note that the ackId should not be included in the CRC calculation. */
876 49 magro732
                stack->rxCrc = RIOPACKET_Crc32(s.data & (uint32_t)0x03fffffful, 0xffffu);
877 20 magro732
              }
878
              else
879
              {
880
                /* This is not the first symbol. */
881
                /* Continue to calculate the CRC of the packet. */
882 49 magro732
                stack->rxCrc = RIOPACKET_Crc32(s.data, stack->rxCrc);
883 20 magro732
              }
884
 
885
              /* Save the new data in the packet queue and update the reception counter. */
886
              QueueSetContent(stack->rxQueue, (uint32_t)stack->rxCounter - (uint32_t)1ul, s.data);
887
              stack->rxCounter++;
888
            }
889
            else
890
            {
891
              /* The ackId is not correct. */
892
              /* Packet error. Enter input-error-stopped state. */
893
              stack->txState = TX_STATE_SEND_PACKET_NOT_ACCEPTED;
894
              stack->rxState = RX_STATE_INPUT_ERROR_STOPPED;
895
              stack->rxErrorCause = PACKET_NOT_ACCEPTED_CAUSE_UNEXPECTED_ACKID;
896
              stack->statusInboundErrorPacketAckId++;
897
            }
898
          }
899
          else
900
          {
901
            /* No packet has been started or the packet is too long. */
902
            /* Packet error. Enter input-error-stopped state. */
903
            stack->txState = TX_STATE_SEND_PACKET_NOT_ACCEPTED;
904
            stack->rxState = RX_STATE_INPUT_ERROR_STOPPED;
905
            stack->rxErrorCause = PACKET_NOT_ACCEPTED_CAUSE_GENERAL;
906
            stack->statusInboundErrorGeneral++;
907
          }
908
          break;
909
 
910 49 magro732
        case RIOSTACK_SYMBOL_TYPE_ERROR:
911 20 magro732
          /**************************************************************************
912
           * The decoder has received a erronous symbol.
913
           **************************************************************************/
914
 
915
          /* Idle symbol error. Place the receiver in input-error-stopped state. */
916
          stack->txState = TX_STATE_SEND_PACKET_NOT_ACCEPTED;
917
          stack->rxState = RX_STATE_INPUT_ERROR_STOPPED;
918
          stack->rxErrorCause = PACKET_NOT_ACCEPTED_CAUSE_ILLEGAL_CHARACTER;
919
          stack->statusInboundErrorIllegalCharacter++;
920
          break;
921
 
922 49 magro732
        case RIOSTACK_SYMBOL_TYPE_IDLE:
923 20 magro732
        default:
924
          /**************************************************************************
925
           * Idle symbol or unsupported symbol.
926
           **************************************************************************/
927
 
928
          /* Discard these for now. */
929
          break;
930
      }
931
      break;
932
 
933
    case RX_STATE_INPUT_RETRY_STOPPED:
934
      /******************************************************************************
935
       * INPUT_RETRY_STOPPED
936
       * This state is entered when no more buffers was available and a packet was
937
       * received. When in this state, all packets should be discarded until a
938
       * RESTART-FROM-RETRY symbol is received. See section 5.9.1.4 of the standard.
939
       * Note that it is only the input side of the port that are affected, not the
940
       * output side. Packets may still be transmitted and acknowledges should be
941
       * accepted.
942
       ******************************************************************************/
943
 
944
      /* Check the type of symbol. */
945
      switch(s.type)
946
      {
947 49 magro732
        case RIOSTACK_SYMBOL_TYPE_CONTROL:
948 20 magro732
          /* This is a control symbol. */
949
 
950
          /* Check if the CRC is correct. */
951
          if(Crc5(s.data, 0x1fu) == (s.data & (uint8_t)0x1ful))
952
          {
953
            /* The CRC is correct. */
954
 
955
            /* Get the content of the control symbol. */
956
            stype0 = STYPE0_GET(s.data);
957
            parameter0 = PARAMETER0_GET(s.data);
958
            parameter1 = PARAMETER1_GET(s.data);
959
            stype1 = STYPE1_GET(s.data);
960
 
961
            /* Check the stype0 part of the symbol. */
962
            switch(stype0)
963
            {
964
              case STYPE0_STATUS:
965
                /* A status containing the current ackId and the buffer status has been
966
                   received. */
967
                handleStatus(stack, parameter0, parameter1);
968
                break;
969
 
970
              case STYPE0_PACKET_ACCEPTED:
971
                /* A packet has been accepted by the link partner. */
972
                handlePacketAccepted(stack, parameter0, parameter1);
973
                break;
974
 
975
              case STYPE0_PACKET_RETRY:
976
                /* The link partner wants us to initiate a restart of the received ackId. */
977
                handlePacketRetry(stack, parameter0, parameter1);
978
                break;
979
 
980
              case STYPE0_PACKET_NOT_ACCEPTED:
981
                /* The link partner indicates that a packet has been rejected. */
982
                handlePacketNotAccepted(stack, parameter0, parameter1);
983
                break;
984
 
985
              case STYPE0_LINK_RESPONSE:
986
                /* The link partner has sent a response to a link-request. */
987
                handleLinkResponse(stack, parameter0, parameter1);
988
                break;
989
 
990
              case STYPE0_VC_STATUS:
991
              case STYPE0_RESERVED:
992
              case STYPE0_IMPLEMENTATION_DEFINED:
993
              default:
994
                /* Unsupported symbol received. */
995
                /* Discard them. */
996
                break;
997
            }
998
 
999
            /* Check the stype1 part of the symbol. */
1000
            switch(stype1)
1001
            {
1002
              case STYPE1_START_OF_PACKET:
1003
                /* Starting new frames are ignored in this state. */
1004
                break;
1005
 
1006
              case STYPE1_END_OF_PACKET:
1007
                /* Ending new frames are ignored in this state. */
1008
                break;
1009
 
1010
              case STYPE1_STOMP:
1011
                /* Restarting frames are ignored in this state. */
1012
                break;
1013
 
1014
              case STYPE1_RESTART_FROM_RETRY:
1015
                /* The link partner has confirmed our packet-retry-symbol. */
1016
                /* Go back to the normal state and reset the frame reception. */
1017
                stack->rxState = RX_STATE_LINK_INITIALIZED;
1018
                stack->rxCounter = 0u;
1019
                break;
1020
 
1021
              case STYPE1_LINK_REQUEST:
1022
                /* A link-request has been received. */
1023
                handleLinkRequest(stack, CMD_GET(s.data));
1024
                stack->rxState = RX_STATE_LINK_INITIALIZED;
1025
                break;
1026
 
1027
              case STYPE1_NOP:
1028
                /* No operation symbol. */
1029
                /* Discard these. */
1030
                break;
1031
 
1032
              case STYPE1_MULTICAST_EVENT:
1033
              case STYPE1_RESERVED:
1034
              default:
1035
                /* Unsupported symbol received. */
1036
                /* Discard them. */
1037
                break;
1038
            }
1039
          }
1040
          else
1041
          {
1042
            /* The control symbol CRC is incorrect. */
1043
            /* Corrupted control symbol. Discard the symbol and enter the input-error-stopped state. */
1044
            stack->txState = TX_STATE_SEND_PACKET_NOT_ACCEPTED;
1045
            stack->rxState = RX_STATE_INPUT_ERROR_STOPPED;
1046
            stack->rxErrorCause = PACKET_NOT_ACCEPTED_CAUSE_CONTROL_CRC;
1047
            stack->statusInboundErrorControlCrc++;
1048
          }
1049
          break;
1050
 
1051 49 magro732
        case RIOSTACK_SYMBOL_TYPE_ERROR:
1052 20 magro732
          /* Idle symbol error. Place the receiver in input-error-stopped state. */
1053
          stack->txState = TX_STATE_SEND_PACKET_NOT_ACCEPTED;
1054
          stack->rxState = RX_STATE_INPUT_ERROR_STOPPED;
1055
          stack->rxErrorCause = PACKET_NOT_ACCEPTED_CAUSE_ILLEGAL_CHARACTER;
1056
          stack->statusInboundErrorIllegalCharacter++;
1057
          break;
1058
 
1059 49 magro732
        case RIOSTACK_SYMBOL_TYPE_DATA:
1060
        case RIOSTACK_SYMBOL_TYPE_IDLE:
1061 20 magro732
        default:
1062
          /* Data or idle symbol. */
1063
          /* Discard these in this state. */
1064
          break;
1065
      }
1066
      break;
1067
 
1068
    case RX_STATE_INPUT_ERROR_STOPPED:
1069
      /******************************************************************************
1070
       * INPUT_ERROR_STOPPED
1071
       * This state is entered when an error situation has occurred. When in this
1072
       * state, all symbols should be discarded until a link-request-symbols has
1073
       * been received. See section 5.13.2.6 in part 6 of the standard.
1074
       * Note that it is only the input side of the port that are affected, not the
1075
       * output side. Packets may still be transmitted and acknowledges should be
1076
       * accepted.
1077
       ******************************************************************************/
1078
 
1079
      /* Check the type of symbol. */
1080
      switch(s.type)
1081
      {
1082 49 magro732
        case RIOSTACK_SYMBOL_TYPE_CONTROL:
1083 20 magro732
          /* This is a control symbol. */
1084
 
1085
          /* Check if the CRC is correct. */
1086
          if(Crc5(s.data, 0x1fu) == (s.data & (uint8_t)0x1ful))
1087
          {
1088
            /* The CRC is correct. */
1089
 
1090
            /* Get the content of the control symbol. */
1091
            stype0 = STYPE0_GET(s.data);
1092
            parameter0 = PARAMETER0_GET(s.data);
1093
            parameter1 = PARAMETER1_GET(s.data);
1094
            stype1 = STYPE1_GET(s.data);
1095
 
1096
            /* Check the stype0 part of the symbol. */
1097
            switch(stype0)
1098
            {
1099
              case STYPE0_STATUS:
1100
                /* A status containing the current ackId and the buffer status has been
1101
                   received. */
1102
                handleStatus(stack, parameter0, parameter1);
1103
                break;
1104
 
1105
              case STYPE0_PACKET_ACCEPTED:
1106
                /* A packet has been accepted by the link partner. */
1107
                handlePacketAccepted(stack, parameter0, parameter1);
1108
                break;
1109
 
1110
              case STYPE0_PACKET_RETRY:
1111
                /* The link partner wants us to initiate a restart of the received ackId. */
1112
                handlePacketRetry(stack, parameter0, parameter1);
1113
                break;
1114
 
1115
              case STYPE0_PACKET_NOT_ACCEPTED:
1116
                /* The link partner indicates that a packet has been rejected. */
1117
                handlePacketNotAccepted(stack, parameter0, parameter1);
1118
                break;
1119
 
1120
              case STYPE0_LINK_RESPONSE:
1121
                /* The link partner has sent a response to a link-request. */
1122
                handleLinkResponse(stack, parameter0, parameter1);
1123
                break;
1124
 
1125
              case STYPE0_VC_STATUS:
1126
              case STYPE0_RESERVED:
1127
              case STYPE0_IMPLEMENTATION_DEFINED:
1128
              default:
1129
                /* Unsupported symbol received. */
1130
                /* Discard them. */
1131
                break;
1132
            }
1133
 
1134
            /* Check the stype1 part of the symbol. */
1135
            switch(stype1)
1136
            {
1137
              case STYPE1_START_OF_PACKET:
1138
                /* Starting new frames are ignored in this state. */
1139
                break;
1140
 
1141
              case STYPE1_END_OF_PACKET:
1142
                /* Ending new frames are ignored in this state. */
1143
                break;
1144
 
1145
              case STYPE1_STOMP:
1146
                /* Restarting frames are ignored in this state. */
1147
                break;
1148
 
1149
              case STYPE1_RESTART_FROM_RETRY:
1150
                /* Restart-from-retry are ignored in this state.  */
1151
                break;
1152
 
1153
              case STYPE1_LINK_REQUEST:
1154
                /* This is the symbol we have been waiting for. */
1155
                /* Force the transmitter to send a link-response and go back into the normal
1156
                   operational state. */
1157
                /* The transmitter will always send a status as the first symbol after this. */
1158
                handleLinkRequest(stack, CMD_GET(s.data));
1159
                stack->rxState = RX_STATE_LINK_INITIALIZED;
1160
                break;
1161
 
1162
              case STYPE1_NOP:
1163
                /* No operation symbol. */
1164
                /* Discard these. */
1165
                break;
1166
 
1167
              case STYPE1_MULTICAST_EVENT:
1168
              case STYPE1_RESERVED:
1169
              default:
1170
                /* Unsupported symbol received. */
1171
                /* Discard them. */
1172
                break;
1173
            }
1174
          }
1175
          else
1176
          {
1177
            /* The CRC is incorrect. */
1178
            /* Discard these in this state. */
1179
          }
1180
          break;
1181
 
1182 49 magro732
        case RIOSTACK_SYMBOL_TYPE_DATA:
1183
        case RIOSTACK_SYMBOL_TYPE_IDLE:
1184
        case RIOSTACK_SYMBOL_TYPE_ERROR:
1185 20 magro732
        default:
1186
          /* Data, idle or error symbol. */
1187
          /* Discard these in this state. */
1188
          break;
1189
      }
1190
      break;
1191
 
1192
    case RX_STATE_UNINITIALIZED:
1193
    default:
1194
      /******************************************************************************
1195
       * Wait for the port to be initialized.
1196
       ******************************************************************************/
1197
 
1198
      /* Discard all incoming symbols. */
1199
      break;
1200
  }
1201
}
1202
 
1203
 
1204
 
1205 49 magro732
RioSymbol_t RIOSTACK_portGetSymbol(RioStack_t *stack )
1206 20 magro732
{
1207 49 magro732
  RioSymbol_t s;
1208 20 magro732
 
1209
 
1210
  switch(stack->txState)
1211
  {
1212
    case TX_STATE_PORT_INITIALIZED:
1213
      /******************************************************************************
1214
       * PORT_INITIALIZED
1215
       * This state is entered to initialize the link. Send status-control-symbols
1216
       * once in a while until the receiver has received enough error-free status-
1217
       * control-symbols and we have transmitted enough status-control-symbols. Once
1218
       * an error-free status-control-symbol has been received, the statuses are
1219
       * transmitted more frequently to decrease the time for the link to be
1220
       * initialized.
1221
       ******************************************************************************/
1222
 
1223
      /* Check if an idle symbol or a status control symbol should be sent. */
1224
      if(((stack->rxStatusReceived == 0) && (stack->txCounter == 255u)) ||
1225
         ((stack->rxStatusReceived == 1) && (stack->txCounter >= 15u)))
1226
      {
1227
        /* A control symbol should be sent. */
1228
 
1229
        /* Create a new status symbol and reset the transmission counter. */
1230
        stack->txCounter = 0u;
1231
        s = CreateControlSymbol(STYPE0_STATUS, stack->rxAckId, QueueAvailable(stack->rxQueue),
1232
                                STYPE1_NOP, 0u);
1233
 
1234
        /* Check if the receiver has received any error-free status and that we
1235
           have sent at least 15 status control symbols. */
1236
        if((stack->rxStatusReceived == 1) && (stack->txStatusCounter < 15u))
1237
        {
1238
          /* Has not sent enough status control symbols. */
1239
          stack->txStatusCounter++;
1240
        }
1241
        else
1242
        {
1243
          /* Has sent enough status control symbols. */
1244
          /* Dont do anything. */
1245
        }
1246
      }
1247
      else
1248
      {
1249
        /* Idle symbol should be sent. */
1250 49 magro732
        s.type = RIOSTACK_SYMBOL_TYPE_IDLE;
1251 20 magro732
        stack->txCounter++;
1252
      }
1253
 
1254
      /* Check if we are ready to set the transmitter in a link initialized state. */
1255
      if ((stack->rxState == RX_STATE_LINK_INITIALIZED) && (stack->txStatusCounter == 15u))
1256
      {
1257
        /* Ready to go to link initialized. */
1258
        stack->txState = TX_STATE_LINK_INITIALIZED;
1259
        stack->txFrameState = TX_FRAME_START;
1260
        stack->txStatusCounter = 0u;
1261
      }
1262
      else
1263
      {
1264
        /* Not ready to go to link initialized. */
1265
        /* Dont do anything. */
1266
      }
1267
 
1268
      break;
1269
 
1270
    case TX_STATE_LINK_INITIALIZED:
1271
      /******************************************************************************
1272
       * LINK_INITIALIZED
1273
       * The normal state. Accept packets and forward them. Send acknowledges when
1274
       * the receiver has received complete packets.
1275
       ******************************************************************************/
1276
 
1277
      /* Check if the receiver wants to acknowledge a packet. */
1278
      if(stack->rxAckId == stack->rxAckIdAcked)
1279
      {
1280
        /* The receiver does not want to acknowledge a packet. */
1281
 
1282
        /* Check if there are any outstanding packets and if it has timed out. */
1283
        if((stack->txAckId == stack->txAckIdWindow) ||
1284
           ((stack->portTime - stack->txFrameTimeout[stack->txAckId]) < stack->portTimeout))
1285
        {
1286
          /* There are no outstanding packets or there has been no timeout. */
1287
 
1288
          /* Check if a packet is ongoing. */
1289
          if(stack->txFrameState == TX_FRAME_BODY)
1290
          {
1291
            /* A packet transmission is ongoing. */
1292
 
1293
            /* Check if the packet has been completly sent. */
1294 49 magro732
            if(stack->txCounter != QueueGetSize(stack->txQueue))
1295 20 magro732
            {
1296
              /* The packet has not been completly sent. */
1297
 
1298
              /* Create a new data symbol to transmit. */
1299 49 magro732
              s.type = RIOSTACK_SYMBOL_TYPE_DATA;
1300 20 magro732
              s.data = QueueGetFrontContent(stack->txQueue, (uint32_t)stack->txCounter);
1301
 
1302
              /* Check if this is the first symbol in a packet. */
1303
              if (stack->txCounter == 0u)
1304
              {
1305
                /* Place the correct ackId in the right place. */
1306
                s.data |= (uint32_t)stack->txAckIdWindow << 27;
1307
              }
1308
              else
1309
              {
1310
                /* Dont do anything. */
1311
              }
1312
 
1313
              /* Update the transmission counter. */
1314
              stack->txCounter++;
1315
 
1316
              /* A status control symbol was not sent. Update the status counter. */
1317
              stack->txStatusCounter++;
1318
            }
1319
            else
1320
            {
1321
              /* The packet has been sent. */
1322
 
1323
              /* Save the timeout time and update to the next ackId. */
1324
              stack->txFrameTimeout[stack->txAckIdWindow] = stack->portTime;
1325
              stack->txAckIdWindow = ACKID_INC(stack->txAckIdWindow);
1326
              stack->txQueue = QueueWindowNext(stack->txQueue);
1327
 
1328
              /* Check if there are more packets pending to be sent. */
1329
              /* Also check that there are buffer available at the receiver and that not too many
1330
                 packets are outstanding. */
1331
              if(!QueueWindowEmpty(stack->txQueue) && (stack->txBufferStatus > 0) &&
1332
                 (((stack->txAckIdWindow - stack->txAckId) & 0x1f) != 31))
1333
              {
1334
                /* More pending packets. */
1335
                /* Create a control symbol to signal that the new packet has started. */
1336
                s = CreateControlSymbol(STYPE0_STATUS, stack->rxAckId, QueueAvailable(stack->rxQueue),
1337
                                        STYPE1_START_OF_PACKET, 0u);
1338
 
1339
                /* Restart transmission counter. */
1340
                stack->txCounter = 0;
1341
              }
1342
              else
1343
              {
1344
                /* No more pending packets. */
1345
                /* Create a control symbol to signal that the packet has ended. */
1346
                s = CreateControlSymbol(STYPE0_STATUS, stack->rxAckId, QueueAvailable(stack->rxQueue),
1347
                                        STYPE1_END_OF_PACKET, 0u);
1348
 
1349
                /* Go back to wait for a new frame. */
1350
                stack->txFrameState = TX_FRAME_START;
1351
              }
1352
 
1353
              /* A status control symbol has been sent. Reset the status counter. */
1354
              stack->txStatusCounter = 0u;
1355
            }
1356
          }
1357
          else
1358
          {
1359
            /* No packet is being sent. */
1360
 
1361
            /* Check if there are any pending packets to start sending. */
1362
            /* Also check that there are buffer available at the receiver and that not too many
1363
               packets are outstanding. */
1364
            if(!QueueWindowEmpty(stack->txQueue) && (stack->txBufferStatus > 0) &&
1365
               (((stack->txAckIdWindow - stack->txAckId) & 0x1f) != 31))
1366
            {
1367
              /* There is a pending packet to send. */
1368
              /* Send a start-of-packet control symbol to start to send the packet. */
1369
              s = CreateControlSymbol(STYPE0_STATUS, stack->rxAckId, QueueAvailable(stack->rxQueue),
1370
                                      STYPE1_START_OF_PACKET, 0u);
1371
              stack->txFrameState = TX_FRAME_BODY;
1372
              stack->txCounter = 0u;
1373
 
1374
              /* A status control symbol has been sent. Reset the status counter. */
1375
              stack->txStatusCounter = 0u;
1376
            }
1377
            else
1378
            {
1379
              /* There are no pending packets to send. */
1380
 
1381
              /* Check if a status control symbol must be transmitted. */
1382
              if(stack->txStatusCounter < 255u)
1383
              {
1384
                /* Not required to send a status control symbol. */
1385
 
1386
                /* Send an idle-symbol. */
1387 49 magro732
                s.type = RIOSTACK_SYMBOL_TYPE_IDLE;
1388 20 magro732
                stack->txStatusCounter++;
1389
              }
1390
              else
1391
              {
1392
                /* Must send a status control symbol. */
1393
 
1394
                /* Create a status control symbol. */
1395
                s = CreateControlSymbol(STYPE0_STATUS, stack->rxAckId, QueueAvailable(stack->rxQueue),
1396
                                        STYPE1_NOP, 0u);
1397
 
1398
                /* A status control symbol has been sent. Reset the status counter. */
1399
                stack->txStatusCounter = 0u;
1400
              }
1401
            }
1402
          }
1403
        }
1404
        else
1405
        {
1406
          /* There has been a timeout. */
1407
          /* A packet has been sent but no packet-accepted has been received. */
1408
          /* Send link-request-symbol (input-status). */
1409
          s = CreateControlSymbol(STYPE0_STATUS, stack->rxAckId, QueueAvailable(stack->rxQueue),
1410
                                  STYPE1_LINK_REQUEST, LINK_REQUEST_INPUT_STATUS);
1411
 
1412
          /* Save the time when this was transmitted. */
1413
          stack->txFrameTimeout[stack->txAckId] = stack->portTime;
1414
 
1415
          /* Remember that this symbol has been transmitted. */
1416
          stack->txCounter = 1;
1417
 
1418
          /* Go into the output error stopped state. */
1419
          stack->txState = TX_STATE_OUTPUT_ERROR_STOPPED;
1420
          stack->statusOutboundErrorTimeout++;
1421
        }
1422
      }
1423
      else
1424
      {
1425
        /* The receiver wants us to send an acknowledgement. */
1426
        s = CreateControlSymbol(STYPE0_PACKET_ACCEPTED, stack->rxAckIdAcked, QueueAvailable(stack->rxQueue),
1427
                                STYPE1_NOP, 0u);
1428
        stack->rxAckIdAcked = ACKID_INC(stack->rxAckIdAcked);
1429
 
1430
        /* A status control symbol was not sent. Update the status counter. */
1431
        stack->txStatusCounter++;
1432
      }
1433
      break;
1434
 
1435
    case TX_STATE_SEND_PACKET_RETRY:
1436
      /******************************************************************************
1437
       * SEND_PACKET_RETRY
1438
       * This state is set by the receiver to force a packet-retry-symbol to be
1439
       * transmitted.
1440
       ******************************************************************************/
1441
 
1442
      /* Check if the receiver wants to acknowledge a packet. */
1443
      /* This must be done first or we will get an error for a missmatching
1444
         ackId in the link-partner. */
1445
      if(stack->rxAckId == stack->rxAckIdAcked)
1446
      {
1447
        /* No pending acknowledge. */
1448
 
1449
        /* Send a packet-retry symbol to tell the link partner to retry the last frame. */
1450
        s = CreateControlSymbol(STYPE0_PACKET_RETRY, stack->rxAckId, QueueAvailable(stack->rxQueue),
1451
                                STYPE1_NOP, 0u);
1452
 
1453
        /* Proceed with normal transmission. */
1454
        stack->txState = TX_STATE_LINK_INITIALIZED;
1455
 
1456
        /* A status control symbol was not sent. Update the status counter. */
1457
        stack->txStatusCounter++;
1458
      }
1459
      else
1460
      {
1461
 
1462
        /* The receiver wants us to send an acknowledgement. */
1463
        s = CreateControlSymbol(STYPE0_PACKET_ACCEPTED, stack->rxAckIdAcked, QueueAvailable(stack->rxQueue),
1464
                                STYPE1_NOP, 0u);
1465
        stack->rxAckIdAcked = ACKID_INC(stack->rxAckIdAcked);
1466
 
1467
        /* A status control symbol was not sent. Update the status counter. */
1468
        stack->txStatusCounter++;
1469
      }
1470
      break;
1471
 
1472
    case TX_STATE_SEND_PACKET_NOT_ACCEPTED:
1473
      /******************************************************************************
1474
       * SEND_PACKET_NOT_ACCEPTED
1475
       * This state is set by the receiver to force a packet-not-accepted-symbol to be
1476
       * transmitted.
1477
       ******************************************************************************/
1478
 
1479
      /* Send a packet-not-accepted symbol to indicate an error on the link. */
1480
      s = CreateControlSymbol(STYPE0_PACKET_NOT_ACCEPTED, 0, stack->rxErrorCause,
1481
                              STYPE1_NOP, 0u);
1482
 
1483
      /* Proceed with normal transmission. */
1484
      stack->txState = TX_STATE_LINK_INITIALIZED;
1485
 
1486
      /* A status control symbol was not sent. Update the status counter. */
1487
      stack->txStatusCounter++;
1488
      break;
1489
 
1490
    case TX_STATE_SEND_LINK_RESPONSE:
1491
      /******************************************************************************
1492
       * SEND_LINK_RESPONSE
1493
       * This state is set by the receiver to force a link-response-symbol to be
1494
       * transmitted.
1495
       ******************************************************************************/
1496
 
1497
      /* Check the state of the receiver. */
1498
      /* REMARK: If a link-request gives this response and a link-request also makes the receiver
1499
         enter the normal operational state, none of these states except the normal state will ever
1500
         be used... */
1501
      if((stack->rxState == RX_STATE_LINK_INITIALIZED) || (stack->rxState == RX_STATE_PORT_INITIALIZED))
1502
      {
1503
        /* Normal state. */
1504
        s = CreateControlSymbol(STYPE0_LINK_RESPONSE, stack->rxAckId, LINK_RESPONSE_PORT_STATUS_OK,
1505
                                STYPE1_NOP, 0u);
1506
      }
1507
      else if(stack->rxState == RX_STATE_INPUT_RETRY_STOPPED)
1508
      {
1509
        /* Input-retry-stopped state. */
1510
        s = CreateControlSymbol(STYPE0_LINK_RESPONSE, stack->rxAckId, LINK_RESPONSE_PORT_STATUS_RETRY_STOPPED,
1511
                                STYPE1_NOP, 0u);
1512
      }
1513
      else if(stack->rxState == RX_STATE_INPUT_ERROR_STOPPED)
1514
      {
1515
        /* Input-error-stopped state. */
1516
        s = CreateControlSymbol(STYPE0_LINK_RESPONSE, stack->rxAckId, LINK_RESPONSE_PORT_STATUS_ERROR_STOPPED,
1517
                                STYPE1_NOP, 0u);
1518
      }
1519
      else
1520
      {
1521
        /* Not in the defined states. */
1522
        s = CreateControlSymbol(STYPE0_LINK_RESPONSE, stack->rxAckId, LINK_RESPONSE_PORT_STATUS_ERROR,
1523
                                STYPE1_NOP, 0u);
1524
      }
1525
 
1526
      /* Proceed with normal transmission. */
1527
      stack->txState = TX_STATE_LINK_INITIALIZED;
1528
 
1529
      /* Force a status to be transmitted the next time to comply to the input-error-stopped
1530
         state rules. */
1531
      stack->txStatusCounter = 255;
1532
      break;
1533
 
1534
    case TX_STATE_OUTPUT_RETRY_STOPPED:
1535
      /******************************************************************************
1536
       * OUTPUT_RETRY_STOPPED
1537
       * This state is entered when the link-partner has transmitted a
1538
       * packet-retry-symbol. The packet-retry-symbol is acknowledged by sending a
1539
       * restart-from-retry-symbol.
1540
       * This state follows 5.9.1.5 in part 6.
1541
       ******************************************************************************/
1542
 
1543
      /* Send a restart-from-retry symbol to acknowledge. */
1544
      s = CreateControlSymbol(STYPE0_STATUS, stack->rxAckId, QueueAvailable(stack->rxQueue),
1545
                              STYPE1_RESTART_FROM_RETRY, 0u);
1546
 
1547
      /* Restart the current frame and proceed with normal operation. */
1548
      stack->txFrameState = TX_FRAME_START;
1549
      stack->txState = TX_STATE_LINK_INITIALIZED;
1550
      stack->txCounter = 0;
1551
 
1552
      /* Discard all packets that has not received a matching packet-accepted. */
1553
      stack->txAckIdWindow = stack->txAckId;
1554
      stack->txQueue = QueueWindowReset(stack->txQueue);
1555
 
1556
      /* A status control symbol was sent. Reset the status counter. */
1557
      stack->txStatusCounter = 0;
1558
      break;
1559
 
1560
    case TX_STATE_OUTPUT_ERROR_STOPPED:
1561
      /******************************************************************************
1562
       * OUTPUT_ERROR_STOPPED
1563
       * This state is entered when the link partner has encountered any problem
1564
       * which is indicated by sending a packet-not-accepted symbol or if a packet
1565
       * timeout has expired. The error condition is acknowledged by sending a
1566
       * link-request-symbol and then wait for a link-response reply.
1567
       * This state follows 5.13.2.7 in part 6.
1568
       ******************************************************************************/
1569
 
1570
      /* Check if a link-request-symbol has been transmitted. */
1571
      if(stack->txCounter == 0)
1572
      {
1573
        /* A link-request-symbol has not been transmitted. */
1574
 
1575
        /* Send link-request-symbol (input-status). */
1576
        s = CreateControlSymbol(STYPE0_STATUS, stack->rxAckId, QueueAvailable(stack->rxQueue),
1577
                                STYPE1_LINK_REQUEST, LINK_REQUEST_INPUT_STATUS);
1578
 
1579
        /* Save the time when this was transmitted. */
1580
        stack->txFrameTimeout[stack->txAckId] = stack->portTime;
1581
 
1582
        /* Remember that this symbol has been transmitted. */
1583
        stack->txCounter = 1;
1584
      }
1585
      else
1586
      {
1587
        /* A link-request-symbol has been transmitted. */
1588
 
1589
        /* Check if the link partner reply has timed out. */
1590
        if((stack->portTime - stack->txFrameTimeout[stack->txAckId]) < stack->portTimeout)
1591
        {
1592
          /* No timeout. */
1593
 
1594
          /* A link-request-symbol has been transmitted. */
1595
          /* Send only idle-symbols until the link-response is received. */
1596 49 magro732
          s.type = RIOSTACK_SYMBOL_TYPE_IDLE;
1597 20 magro732
        }
1598
        else
1599
        {
1600
          /* Link response timeout. */
1601
 
1602
          /* Check if the link-partner has not responded for too many times. */
1603
          if(stack->txCounter < 5)
1604
          {
1605
            /* Not too many timeouts. */
1606
            /* Retry and send a new link-request. */
1607
 
1608
            /* Send link-request-symbol (input-status). */
1609
            s = CreateControlSymbol(STYPE0_STATUS, stack->rxAckId, QueueAvailable(stack->rxQueue),
1610
                                    STYPE1_LINK_REQUEST, LINK_REQUEST_INPUT_STATUS);
1611
 
1612
            /* Save the time when this was transmitted. */
1613
            stack->txFrameTimeout[stack->txAckId] = stack->portTime;
1614
 
1615
            /* Increment the number of times we have retransmitted the link-request. */
1616
            stack->txCounter++;
1617
          }
1618
          else
1619
          {
1620
            /* The link partner has not answered for too many times. */
1621
            /* Give up and set the state to uninitialized. */
1622
            stack->txState = TX_STATE_UNINITIALIZED;
1623 49 magro732
            s.type = RIOSTACK_SYMBOL_TYPE_IDLE;
1624 20 magro732
            ASSERT0("No link-response received, giving up.");
1625
          }
1626
        }
1627
      }
1628
      break;
1629
 
1630
    case TX_STATE_UNINITIALIZED:
1631
    default:
1632
      /******************************************************************************
1633
       * Wait for the port to be initialized.
1634
       ******************************************************************************/
1635
 
1636
      /* Send only idle symbols. */
1637 49 magro732
      s.type = RIOSTACK_SYMBOL_TYPE_IDLE;
1638 20 magro732
      break;
1639
  }
1640
 
1641
  /* Return the created symbol. */
1642
  return s;
1643
}
1644
 
1645
 
1646
 
1647
/*******************************************************************************
1648 49 magro732
 * Local RapidIO stack helper functions.
1649 20 magro732
 *******************************************************************************/
1650
 
1651
static void handleStatus(RioStack_t *stack, const uint8_t ackId, const uint8_t bufferStatus)
1652
{
1653
  /* Update the buffer status of the link partner. */
1654
  (void) ackId;
1655
  stack->txBufferStatus = bufferStatus;
1656
}
1657
 
1658
 
1659 49 magro732
 
1660 20 magro732
static void handlePacketAccepted(RioStack_t *stack, const uint8_t ackId, const uint8_t bufferStatus)
1661
{
1662 49 magro732
  uint32_t linkLatency;
1663
 
1664
 
1665 20 magro732
  /* Check if an acknowledge is expected and that it is for a transmitted packet. */
1666
  if((stack->txAckId != stack->txAckIdWindow) && (ackId == stack->txAckId))
1667
  {
1668
    /* Acknowledge for a recently transmitted packet received. */
1669 49 magro732
 
1670
    /* Check if the latency of this packet is larger than the largest encountered so far. */
1671
    linkLatency = stack->portTime - stack->txFrameTimeout[ackId];
1672
    if(linkLatency > stack->statusOutboundLinkLatencyMax)
1673
    {
1674
      stack->statusOutboundLinkLatencyMax = linkLatency;
1675
    }
1676
 
1677 20 magro732
    /* Remove the packet from the outbound queue and restart the transmission for
1678
       a new packet. */
1679
    stack->txQueue = QueueDequeue(stack->txQueue);
1680
    stack->txAckId = ACKID_INC(stack->txAckId);
1681
    stack->statusOutboundPacketComplete++;
1682
  }
1683
  else
1684
  {
1685
    /* Acknowledge for an unexpected ackId or not waiting for an acknowledge. */
1686
    /* Link protocol violation. Discard the symbol and enter the output-error-stopped state. */
1687
    stack->txState = TX_STATE_OUTPUT_ERROR_STOPPED;
1688
    stack->txCounter = 0u;
1689
    stack->statusOutboundErrorPacketAccepted++;
1690
  }
1691
 
1692
  /* Update the buffer status of the link partner. */
1693
  stack->txBufferStatus = bufferStatus;
1694
}
1695
 
1696
 
1697 49 magro732
 
1698 20 magro732
static void handlePacketRetry(RioStack_t *stack, const uint8_t ackId, const uint8_t bufferStatus)
1699
{
1700
  /* Check if the retried packet ackId is acceptable. */
1701
  if(ackId == stack->txAckId)
1702
  {
1703
    /* The request for retry is for the current packet. */
1704
    /* Force the transmitter to send a RESTART-FROM-RETRY symbol. */
1705
    stack->txState = TX_STATE_OUTPUT_RETRY_STOPPED;
1706
    stack->statusOutboundPacketRetry++;
1707
  }
1708
  else
1709
  {
1710
    /* Link protocol violation. Discard the symbol and enter the output-error-stopped state. */
1711
    stack->txState = TX_STATE_OUTPUT_ERROR_STOPPED;
1712
    stack->txCounter = 0u;
1713
    stack->statusOutboundErrorPacketRetry++;
1714
  }
1715
 
1716
  /* Update the buffer status of the link partner. */
1717
  stack->txBufferStatus = bufferStatus;
1718
}
1719
 
1720
 
1721 49 magro732
 
1722 20 magro732
static void handlePacketNotAccepted(RioStack_t *stack, const uint8_t arbitrary, const uint8_t cause)
1723
{
1724
  (void) arbitrary;
1725
 
1726
  /* Force the transmitter to enter output-error-stopped state. */
1727
  stack->txState = TX_STATE_OUTPUT_ERROR_STOPPED;
1728
  stack->txCounter = 0u;
1729
 
1730
  /* Record the type of error that caused the packet to not being accepted. */
1731
  switch(cause)
1732
  {
1733
    case PACKET_NOT_ACCEPTED_CAUSE_UNEXPECTED_ACKID:
1734
      stack->statusPartnerErrorPacketAckId++;
1735
      break;
1736
    case PACKET_NOT_ACCEPTED_CAUSE_CONTROL_CRC:
1737
      stack->statusPartnerErrorControlCrc++;
1738
      break;
1739
    case PACKET_NOT_ACCEPTED_CAUSE_PACKET_CRC:
1740
      stack->statusPartnerErrorPacketCrc++;
1741
      break;
1742
    case PACKET_NOT_ACCEPTED_CAUSE_ILLEGAL_CHARACTER:
1743
      stack->statusPartnerErrorIllegalCharacter++;
1744
      break;
1745
    default:
1746
      stack->statusPartnerErrorGeneral++;
1747
      break;
1748
  }
1749
}
1750
 
1751
 
1752 49 magro732
 
1753 20 magro732
static void handleLinkResponse(RioStack_t *stack, const uint8_t ackId, const uint8_t portStatus)
1754
{
1755
  uint8_t window;
1756
  uint8_t windowReceived;
1757
 
1758
 
1759
  (void) portStatus;
1760
 
1761
  /* Check if this symbols is expected. */
1762
  if(stack->txState == TX_STATE_OUTPUT_ERROR_STOPPED)
1763
  {
1764
    /* Calculate the number of packets that has not received an acknowledge on our side and
1765
       on the link-partner side. */
1766
    window = (stack->txAckIdWindow - stack->txAckId) & 0x1f;
1767
    windowReceived = (ackId - stack->txAckId) & 0x1f;
1768
 
1769
    /* Check if the link-partners response is acceptable. */
1770
    if(windowReceived <= window)
1771
    {
1772
      /* A link-response is expected. */
1773
 
1774
      /* Remove entries in the queue that the link-partner has sent acknowledges for that has been lost. */
1775
      while(stack->txAckId != ackId)
1776
      {
1777
        stack->txQueue = QueueDequeue(stack->txQueue);
1778
        stack->txAckId = ACKID_INC(stack->txAckId);
1779
        stack->statusOutboundPacketComplete++;
1780
      }
1781
 
1782
      /* Set the transmission window to the resend packets that has not been received. */
1783
      stack->txQueue = QueueWindowReset(stack->txQueue);
1784
      stack->txAckIdWindow = ackId;
1785
      stack->txFrameState = TX_FRAME_START;
1786
 
1787
      /* Set the transmitter back into normal operation. */
1788
      stack->txState = TX_STATE_LINK_INITIALIZED;
1789
    }
1790
    else
1791
    {
1792
      /* The link-partner response is unacceptable. */
1793
      /* Recovery is not possible. */
1794
      stack->txState = TX_STATE_UNINITIALIZED;
1795
      ASSERT0("Unrecoverable protocol error.");
1796
    }
1797
  }
1798
  else
1799
  {
1800
    /* Not expecting a link-response. */
1801
    /* Just discard this symbol. */
1802
    /* REMARK: Add status counter here??? */
1803
  }
1804
}
1805
 
1806
 
1807 49 magro732
 
1808 20 magro732
static void handleStartOfPacket(RioStack_t *stack)
1809
{
1810
  /* Check if a packet is already started. */
1811
  if(stack->rxCounter != 0u)
1812
  {
1813
    /* Packet has already started. */
1814
    /* This indicates an implicit end-of-packet symbol and signals the previous packet as ready. */
1815
 
1816
    /* Check the packet crc. */
1817
    if(stack->rxCrc == 0x0000u)
1818
    {
1819
      /* The packet has a correct CRC. */
1820
 
1821
      /* Check if the packet is long enough to contain a complete packet. */
1822
      if(stack->rxCounter > 3u)
1823
      {
1824
        /* Packet long enough to process. */
1825
 
1826
        /* Process the newly received packet and start a new one. */
1827
        handleNewPacketEnd(stack);
1828
        handleNewPacketStart(stack);
1829
      }
1830
      else
1831
      {
1832
        /* The packet has a valid CRC but is too short. */
1833
        /* Packet error. Enter input-error-stopped state. */
1834
        stack->txState = TX_STATE_SEND_PACKET_NOT_ACCEPTED;
1835
        stack->rxState = RX_STATE_INPUT_ERROR_STOPPED;
1836
        stack->rxErrorCause = PACKET_NOT_ACCEPTED_CAUSE_GENERAL;
1837
        stack->statusInboundErrorGeneral++;
1838
      }
1839
    }
1840
    else
1841
    {
1842
      /* The packet has an invalid CRC. */
1843
      /* Packet error. Enter input-error-stopped state. */
1844
      stack->txState = TX_STATE_SEND_PACKET_NOT_ACCEPTED;
1845
      stack->rxState = RX_STATE_INPUT_ERROR_STOPPED;
1846
      stack->rxErrorCause = PACKET_NOT_ACCEPTED_CAUSE_PACKET_CRC;
1847
      stack->statusInboundErrorPacketCrc++;
1848
    }
1849
  }
1850
  else
1851
  {
1852
    /* Packet has not already started. */
1853
    handleNewPacketStart(stack);
1854
  }
1855
}
1856
 
1857
 
1858 49 magro732
 
1859 20 magro732
static void handleEndOfPacket(RioStack_t *stack)
1860
{
1861
  /* Check if the CRC is correct. */
1862
  if(stack->rxCrc == 0x0000u)
1863
  {
1864
    /* The packet has a correct CRC. */
1865
 
1866
    /* Check if the packet is long enough to contain a complete packet. */
1867
    if(stack->rxCounter > 3u)
1868
    {
1869
      /* Packet long enough to process. */
1870
 
1871
      /* Process the newly received packet. */
1872
      handleNewPacketEnd(stack);
1873
    }
1874
    else
1875
    {
1876
      /* The packet has a valid CRC but is too short. */
1877
      /* Packet error. Enter input-error-stopped state. */
1878
      stack->txState = TX_STATE_SEND_PACKET_NOT_ACCEPTED;
1879
      stack->rxState = RX_STATE_INPUT_ERROR_STOPPED;
1880
      stack->rxErrorCause = PACKET_NOT_ACCEPTED_CAUSE_GENERAL;
1881
      stack->statusInboundErrorGeneral++;
1882
    }
1883
  }
1884
  else
1885
  {
1886
    /* The packet has an invalid CRC. */
1887
    /* Packet error. Enter input-error-stopped state. */
1888
    stack->txState = TX_STATE_SEND_PACKET_NOT_ACCEPTED;
1889
    stack->rxState = RX_STATE_INPUT_ERROR_STOPPED;
1890
    stack->rxErrorCause = PACKET_NOT_ACCEPTED_CAUSE_PACKET_CRC;
1891
    stack->statusInboundErrorPacketCrc++;
1892
  }
1893
}
1894
 
1895
 
1896 49 magro732
 
1897 20 magro732
static void handleNewPacketStart(RioStack_t *stack)
1898
{
1899
  /* Check if there are buffers available to store the new frame. */
1900
  if (QueueAvailable(stack->rxQueue) > 0u)
1901
  {
1902
    /* There are buffers available to accept the new packet. */
1903
 
1904
    /* Update the reception counter to indicate the frame has started. */
1905
    stack->rxCounter = 1;
1906
  }
1907
  else
1908
  {
1909
    /* There are no buffers available. */
1910
    /* Go to input retry stopped state. */
1911
    stack->statusInboundPacketRetry++;
1912
    stack->txState = TX_STATE_SEND_PACKET_RETRY;
1913
    stack->rxState = RX_STATE_INPUT_RETRY_STOPPED;
1914
  }
1915
}
1916
 
1917
 
1918 49 magro732
 
1919 20 magro732
static void handleNewPacketEnd(RioStack_t *stack)
1920
{
1921
  /* Save the size of the packet. */
1922
  QueueSetSize(stack->rxQueue, (uint32_t)stack->rxCounter - (uint32_t)1ul);
1923
 
1924
  /* Always forward the packet to the top of the stack. */
1925
  stack->rxQueue = QueueEnqueue(stack->rxQueue);
1926 49 magro732
 
1927
  /* Make sure the CRC is reset to an invalid value to avoid a packet
1928
     accidentally being accepted. */
1929
  stack->rxCrc = 0xffff;
1930
 
1931 20 magro732
  /* Reset the reception counter. */
1932
  stack->rxCounter = 0u;
1933
 
1934
  /* Update the ackId for the receiver. */
1935
  stack->rxAckId = ACKID_INC(stack->rxAckId);
1936
 
1937
  /* Update status counter. */
1938
  stack->statusInboundPacketComplete++;
1939
}
1940
 
1941
 
1942 49 magro732
 
1943 20 magro732
static void handleLinkRequest(RioStack_t *stack, uint8_t cmd)
1944
{
1945
  /* Check the command of the link-request. */
1946
  if(cmd == LINK_REQUEST_INPUT_STATUS)
1947
  {
1948
    /* Input-status requested. */
1949
    /* Return input port status. */
1950
 
1951
    /* Force the transmitter to send a link-response-symbol. */
1952
    stack->txState = TX_STATE_SEND_LINK_RESPONSE;
1953
  }
1954
  else if(cmd == LINK_REQUEST_RESET_DEVICE)
1955
  {
1956
    /* Reset-device requested. */
1957
    /* REMARK: Support this??? */
1958
  }
1959
  else
1960
  {
1961
    /* Unrecognized command. */
1962
    /* Dont do anything. */
1963
  }
1964
 
1965
  /* Always cancel an ongoing frame when a link-request has been received. */
1966
  stack->rxCounter = 0;
1967
 
1968
  /* Receiving this indicates the link partner having encountered a potential problem. */
1969
  /* Count the number of times this happens. */
1970
  stack->statusPartnerLinkRequest++;
1971
}
1972
 
1973
 
1974
 
1975 49 magro732
static RioSymbol_t CreateControlSymbol(const uint8_t stype0,
1976
                                       const uint8_t parameter0, const uint8_t parameter1,
1977
                                       const uint8_t stype1, const uint8_t cmd)
1978 20 magro732
{
1979 49 magro732
  RioSymbol_t s;
1980 20 magro732
 
1981 49 magro732
  s.type = RIOSTACK_SYMBOL_TYPE_CONTROL;
1982 20 magro732
 
1983
  s.data = ((uint32_t)stype0 & (uint32_t)0x07ul) << 21;
1984
  s.data |= ((uint32_t)parameter0 & (uint32_t)0x1ful) << 16;
1985
  s.data |= ((uint32_t)parameter1 & (uint32_t)0x1ful) << 11;
1986
  s.data |= ((uint32_t)stype1 & (uint32_t)0x07ul) << 8;
1987
  s.data |= ((uint32_t)cmd & (uint32_t)0x7ul) << 5;
1988
  s.data |= Crc5(s.data, 0x1fu);
1989
 
1990
  return s;
1991
}
1992
 
1993
 
1994 49 magro732
 
1995
static uint8_t Crc5(const uint32_t data, const uint8_t crc)
1996 20 magro732
{
1997
  static const uint8_t crcTable[] = {
1998
    0x00u, 0x15u, 0x1fu, 0x0au, 0x0bu, 0x1eu, 0x14u, 0x01u,
1999
    0x16u, 0x03u, 0x09u, 0x1cu, 0x1du, 0x08u, 0x02u, 0x17u,
2000
    0x19u, 0x0cu, 0x06u, 0x13u, 0x12u, 0x07u, 0x0du, 0x18u,
2001
    0x0fu, 0x1au, 0x10u, 0x05u, 0x04u, 0x11u, 0x1bu, 0x0eu
2002
  };
2003
 
2004
  uint8_t result;
2005
  uint8_t index;
2006
 
2007
  result = crc;
2008
  index  = (uint8_t)((data >> 19) & (uint32_t)0x1ful) ^ result;
2009
  result = crcTable[index];
2010
  index  = (uint8_t)((data >> 14) & (uint32_t)0x1ful) ^ result;
2011
  result = crcTable[index];
2012
  index  = (uint8_t)((data >> 9) & (uint32_t)0x1ful) ^ result;
2013
  result = crcTable[index];
2014
  index  = (uint8_t)((data >> 4) & (uint32_t)0x1eul) ^ result;
2015
  result = crcTable[index];
2016
 
2017
  return result;
2018
}
2019
 
2020
 
2021 49 magro732
/*******************************************************************************************
2022
 * Internal queue functions.
2023
 *******************************************************************************************/
2024 20 magro732
 
2025 49 magro732
static Queue_t QueueCreate(const uint8_t size, uint32_t *buffer)
2026 20 magro732
{
2027
  Queue_t q;
2028
 
2029
  q.size = size;
2030
  q.available = size;
2031
  q.windowSize = 0u;
2032
  q.windowIndex = 0u;
2033
  q.frontIndex = 0u;
2034
  q.backIndex = 0u;
2035
  q.buffer_p = buffer;
2036
 
2037
  return q;
2038
}
2039
 
2040
 
2041 49 magro732
 
2042
static uint8_t QueueAvailable(const Queue_t q)
2043 20 magro732
{
2044
  return q.available;
2045
}
2046
 
2047
 
2048 49 magro732
 
2049
static int QueueEmpty(const Queue_t q)
2050 20 magro732
{
2051 49 magro732
  return (q.available == q.size);
2052 20 magro732
}
2053
 
2054
 
2055 49 magro732
 
2056
static uint8_t QueueLength(const Queue_t q)
2057 20 magro732
{
2058
  return q.size - q.available;
2059
}
2060
 
2061
 
2062 49 magro732
 
2063
static Queue_t QueueEnqueue(Queue_t q)
2064 20 magro732
{
2065
  q.backIndex++;
2066
  if(q.backIndex == q.size)
2067
  {
2068
    q.backIndex = 0;
2069
  }
2070
  q.available--;
2071
  return q;
2072
}
2073
 
2074
 
2075 49 magro732
 
2076
static Queue_t QueueDequeue(Queue_t q)
2077 20 magro732
{
2078
  q.frontIndex++;
2079
  if(q.frontIndex == q.size)
2080
  {
2081
    q.frontIndex = 0;
2082
  }
2083
  q.available++;
2084
  if(q.windowSize == 0)
2085
  {
2086
    q.windowIndex = q.frontIndex;
2087
  }
2088
  else
2089
  {
2090
    q.windowSize--;
2091
  }
2092
  return q;
2093
}
2094
 
2095
 
2096 49 magro732
 
2097
static int QueueWindowEmpty(const Queue_t q)
2098 20 magro732
{
2099 49 magro732
  return ((q.available + q.windowSize) == q.size);
2100 20 magro732
}
2101
 
2102
 
2103 49 magro732
 
2104 20 magro732
static Queue_t QueueWindowReset(Queue_t q)
2105
{
2106
  q.windowIndex = q.frontIndex;
2107
  q.windowSize = 0;
2108
  return q;
2109
}
2110
 
2111
 
2112 49 magro732
 
2113 20 magro732
static Queue_t QueueWindowNext(Queue_t q)
2114
{
2115
  q.windowIndex++;
2116
  if(q.windowIndex == q.size)
2117
  {
2118
    q.windowIndex = 0;
2119
  }
2120
  q.windowSize++;
2121
  return q;
2122
}
2123
 
2124
 
2125
 
2126 49 magro732
static void QueueSetSize(Queue_t q, const uint32_t size)
2127 20 magro732
{
2128 49 magro732
  (q.buffer_p+(RIOSTACK_BUFFER_SIZE*q.backIndex))[0] = size;
2129 20 magro732
}
2130
 
2131
 
2132
 
2133 49 magro732
static void QueueSetContent(Queue_t q, const uint32_t index, const uint32_t content)
2134 20 magro732
{
2135 49 magro732
  (q.buffer_p+(RIOSTACK_BUFFER_SIZE*q.backIndex))[index+1ul] = content;
2136 20 magro732
}
2137
 
2138
 
2139
 
2140 49 magro732
static uint32_t QueueGetSize(Queue_t q)
2141 20 magro732
{
2142 49 magro732
  return (q.buffer_p+(RIOSTACK_BUFFER_SIZE*q.windowIndex))[0];
2143 20 magro732
}
2144
 
2145
 
2146
 
2147 49 magro732
static uint32_t QueueGetFrontContent(const Queue_t q, const uint32_t index)
2148 20 magro732
{
2149 49 magro732
  return (q.buffer_p+(RIOSTACK_BUFFER_SIZE*q.windowIndex))[index+1ul];
2150 20 magro732
}
2151
 
2152
 
2153
 
2154 49 magro732
static uint32_t *QueueGetFrontBuffer(const Queue_t q )
2155 20 magro732
{
2156 49 magro732
  return &((q.buffer_p+(RIOSTACK_BUFFER_SIZE*q.windowIndex))[1]);
2157 20 magro732
}
2158
 
2159
 
2160
 
2161 49 magro732
static uint32_t *QueueGetBackBuffer(const Queue_t q )
2162 20 magro732
{
2163 49 magro732
  return &((q.buffer_p+(RIOSTACK_BUFFER_SIZE*q.backIndex))[1]);
2164 20 magro732
}
2165
 
2166
/*************************** end of file **************************************/

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.