]> begriffs open source - cmsis-driver-validation/blob - Tools/SPI_Server/Source/SPI_Server.c
Minor update to SPI driver validation documentation and SPI_Server
[cmsis-driver-validation] / Tools / SPI_Server / Source / SPI_Server.c
1 /*
2  * Copyright (c) 2020-2021 Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Licensed under the Apache License, Version 2.0 (the License); you may
7  * not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an AS IS BASIS, WITHOUT
14  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * -----------------------------------------------------------------------------
19  *
20  * Project:     SPI Server
21  * Title:       SPI Server application
22  *
23  * -----------------------------------------------------------------------------
24  */
25
26
27 #include <stdint.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <stdio.h>
31
32 #include "SPI_Server_Config.h"
33 #include "SPI_Server.h"
34
35 #include "cmsis_os2.h"
36 #include "cmsis_compiler.h"
37 #include "cmsis_vio.h"
38
39 #include "Driver_SPI.h"                 // ::CMSIS Driver:SPI
40
41 #ifndef  SPI_SERVER_DEBUG
42 #define  SPI_SERVER_DEBUG       0
43 #endif
44
45 // Fixed SPI Server settings (not available through SPI_Server_Config.h)
46 #define  SPI_SERVER_SS_MODE     2       // Slave Select Hardware monitored
47 #define  SPI_SERVER_FORMAT      0       // Clock Polarity 0 / Clock Phase 0
48 #define  SPI_SERVER_DATA_BITS   8       // 8 data bits
49 #define  SPI_SERVER_BIT_ORDER   0       // MSB to LSB bit order
50
51 #define  SPI_EVENTS_MASK       (ARM_SPI_EVENT_TRANSFER_COMPLETE | \
52                                 ARM_SPI_EVENT_DATA_LOST         | \
53                                 ARM_SPI_EVENT_MODE_FAULT)
54
55 #define  DATA_BITS_TO_BYTES(data_bits)      (((data_bits) > 16) ? (4U) : (((data_bits) > 8) ? (2U) : (1U)))
56 #define  BYTES_TO_ITEMS(bytes,data_bits)    ((bytes + DATA_BITS_TO_BYTES(data_bits) - 1U) / DATA_BITS_TO_BYTES(data_bits))
57
58 /* Access to Driver_SPI# */
59 #define  SPI_Driver_Aux(n)      Driver_SPI##n
60 #define  SPI_Driver_Name(n)     SPI_Driver_Aux(n)
61 extern   ARM_DRIVER_SPI         SPI_Driver_Name(SPI_SERVER_DRV_NUM);
62 #define  drvSPI               (&SPI_Driver_Name(SPI_SERVER_DRV_NUM))
63
64 typedef struct {                // SPI Interface settings structure
65   uint32_t mode;
66   uint32_t format;
67   uint32_t bit_num;
68   uint32_t bit_order;
69   uint32_t ss_mode;
70   uint32_t bus_speed;
71 } SPI_COM_CONFIG_t;
72
73 // Structure containing command string and pointer to command handling function
74 typedef struct {
75   const char     *command;
76         int32_t (*Command_Func) (const char *command);
77 } SPI_CMD_DESC_t;
78
79 // Local functions
80
81 // Main thread (reception and execution of command)
82 __NO_RETURN \
83 static void     SPI_Server_Thread    (void *argument);
84
85 // SPI Interface communication functions
86 static void     SPI_Com_Event        (uint32_t event);
87 static int32_t  SPI_Com_Initialize   (void);
88 static int32_t  SPI_Com_Uninitialize (void);
89 static int32_t  SPI_Com_PowerOn      (void);
90 static int32_t  SPI_Com_PowerOff     (void);
91 static int32_t  SPI_Com_Configure    (const SPI_COM_CONFIG_t *config);
92 static uint32_t SPI_Com_SS           (uint32_t active);
93 static int32_t  SPI_Com_Receive      (                      void *data_in, uint32_t num, uint32_t timeout);
94 static int32_t  SPI_Com_Send         (const void *data_out,                uint32_t num, uint32_t timeout);
95 static int32_t  SPI_Com_Transfer     (const void *data_out, void *data_in, uint32_t num, uint32_t timeout);
96 static int32_t  SPI_Com_Abort        (void);
97 static uint32_t SPI_Com_GetCnt       (void);
98
99 // Command handling functions
100 static int32_t  SPI_Cmd_GetVer       (const char *cmd);
101 static int32_t  SPI_Cmd_GetCap       (const char *cmd);
102 static int32_t  SPI_Cmd_SetBuf       (const char *cmd);
103 static int32_t  SPI_Cmd_GetBuf       (const char *cmd);
104 static int32_t  SPI_Cmd_SetCom       (const char *cmd);
105 static int32_t  SPI_Cmd_Xfer         (const char *cmd);
106 static int32_t  SPI_Cmd_GetCnt       (const char *cmd);
107
108 // Local variables
109
110 // Command specification (command string, command handling function)
111 static const SPI_CMD_DESC_t spi_cmd_desc[] = {
112  { "GET VER" , SPI_Cmd_GetVer },
113  { "GET CAP" , SPI_Cmd_GetCap },
114  { "SET BUF" , SPI_Cmd_SetBuf },
115  { "GET BUF" , SPI_Cmd_GetBuf },
116  { "SET COM" , SPI_Cmd_SetCom },
117  { "XFER"    , SPI_Cmd_Xfer   },
118  { "GET CNT" , SPI_Cmd_GetCnt }
119 };
120
121 static       osThreadId_t       spi_server_thread_id   =   NULL;
122 static       osThreadAttr_t     thread_attr = {
123   .name       = "SPI_Server_Thread",
124   .stack_size = 512U
125 };
126
127 static       uint8_t            spi_server_state       =   SPI_SERVER_STATE_RECEPTION;
128 static       uint32_t           spi_cmd_timeout        =   SPI_SERVER_CMD_TIMEOUT;
129 static       uint32_t           spi_xfer_timeout       =   SPI_SERVER_CMD_TIMEOUT;
130 static       uint32_t           spi_xfer_cnt           =   0U;
131 static       uint32_t           spi_xfer_buf_size      =   SPI_SERVER_BUF_SIZE;
132 static const SPI_COM_CONFIG_t   spi_com_config_default = { ARM_SPI_MODE_SLAVE, 
133                                                          ((SPI_SERVER_FORMAT    << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk), 
134                                                          ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos)    & ARM_SPI_DATA_BITS_Msk), 
135                                                          ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos)    & ARM_SPI_BIT_ORDER_Msk), 
136                                                            ARM_SPI_SS_SLAVE_HW,
137                                                            0U   // Bus speed for Slave mode is unused
138                                                          };
139 static const SPI_COM_CONFIG_t   spi_com_config_inactive= { ARM_SPI_MODE_INACTIVE, 0U, 0U, 0U, 0U, 0U };
140 static       SPI_COM_CONFIG_t   spi_com_config_xfer;
141 static       uint8_t            spi_bytes_per_item        = 1U;
142 static       uint8_t            spi_cmd_buf_rx[32]        __ALIGNED(4);
143 static       uint8_t            spi_cmd_buf_tx[32]        __ALIGNED(4);
144 static       uint8_t           *ptr_spi_xfer_buf_rx       = NULL;
145 static       uint8_t           *ptr_spi_xfer_buf_tx       = NULL;
146 static       void              *ptr_spi_xfer_buf_rx_alloc = NULL;
147 static       void              *ptr_spi_xfer_buf_tx_alloc = NULL;
148
149 // Global functions
150
151 /**
152   \fn            int32_t SPI_Server_Start (void)
153   \brief         Initialize, power up, configure SPI interface and start SPI Server thread.
154   \return        execution status
155                    - EXIT_SUCCESS: Operation successful
156                    - EXIT_FAILURE: Operation failed
157 */
158 int32_t SPI_Server_Start (void) {
159   int32_t ret;
160
161   vioInit();
162   (void)vioPrint(vioLevelHeading, "SPI Server v%s", SPI_SERVER_VER);
163
164   // Initialize local variables
165   spi_server_state   = SPI_SERVER_STATE_RECEPTION;
166   spi_cmd_timeout    = SPI_SERVER_CMD_TIMEOUT;
167   spi_xfer_timeout   = SPI_SERVER_CMD_TIMEOUT;
168   spi_xfer_cnt       = 0U;
169   spi_xfer_buf_size  = SPI_SERVER_BUF_SIZE;
170   spi_bytes_per_item = DATA_BITS_TO_BYTES(SPI_SERVER_DATA_BITS);
171   memset(spi_cmd_buf_rx,  0, sizeof(spi_cmd_buf_rx));
172   memset(spi_cmd_buf_tx,  0, sizeof(spi_cmd_buf_tx));
173   memcpy(&spi_com_config_xfer, &spi_com_config_default, sizeof(SPI_COM_CONFIG_t));
174
175   // Allocate buffers for data transmission and reception
176   // (maximum size is incremented by 4 bytes to ensure that buffer can be aligned to 4 bytes)
177
178   ptr_spi_xfer_buf_rx_alloc = malloc(SPI_SERVER_BUF_SIZE + 4U);
179   if (((uint32_t)ptr_spi_xfer_buf_rx_alloc & 3U) != 0U) {
180     // If allocated memory is not 4 byte aligned, use next 4 byte aligned address for ptr_tx_buf
181     ptr_spi_xfer_buf_rx = (uint8_t *)((((uint32_t)ptr_spi_xfer_buf_rx_alloc) + 3U) & (~3U));
182   } else {
183     // If allocated memory is 4 byte aligned, use it directly
184     ptr_spi_xfer_buf_rx = (uint8_t *)ptr_spi_xfer_buf_rx_alloc;
185   }
186   ptr_spi_xfer_buf_tx_alloc = malloc(SPI_SERVER_BUF_SIZE + 4U);
187   if (((uint32_t)ptr_spi_xfer_buf_tx_alloc & 3U) != 0U) {
188     // If allocated memory is not 4 byte aligned, use next 4 byte aligned address for ptr_tx_buf
189     ptr_spi_xfer_buf_tx = (uint8_t *)((((uint32_t)ptr_spi_xfer_buf_tx_alloc) + 3U) & (~3U));
190   } else {
191     // If allocated memory is 4 byte aligned, use it directly
192     ptr_spi_xfer_buf_tx = (uint8_t *)ptr_spi_xfer_buf_tx_alloc;
193   }
194
195   if ((ptr_spi_xfer_buf_rx != NULL) || (ptr_spi_xfer_buf_tx != NULL)) {
196     memset(ptr_spi_xfer_buf_rx, 0, SPI_SERVER_BUF_SIZE);
197     memset(ptr_spi_xfer_buf_rx, 0, SPI_SERVER_BUF_SIZE);
198     ret = EXIT_SUCCESS;
199   } else {
200     ret = EXIT_FAILURE;
201   }
202
203   if (ret == EXIT_SUCCESS) {
204     ret = SPI_Com_Initialize();
205   }
206
207   if (ret == EXIT_SUCCESS) {
208     ret = SPI_Com_PowerOn();
209   }
210
211   if (ret == EXIT_SUCCESS) {
212     ret = SPI_Com_Configure(&spi_com_config_default);
213   }
214
215   if ((ret == EXIT_SUCCESS) && (spi_server_thread_id == NULL)) {
216     // Create SPI_Server_Thread thread
217     spi_server_thread_id = osThreadNew(SPI_Server_Thread, NULL, &thread_attr);
218     if (spi_server_thread_id == NULL) {
219       ret = EXIT_FAILURE;
220     }
221   }
222
223   if (ret != EXIT_SUCCESS) {
224     vioPrint(vioLevelError, "Server Start failed!");
225   }
226
227   return ret;
228 }
229
230 /**
231   \fn            int32_t SPI_Server_Stop (void)
232   \brief         Terminate SPI Server thread, power down and uninitialize SPI interface.
233   \return        execution status
234                    - EXIT_SUCCESS: Operation successful
235                    - EXIT_FAILURE: Operation failed
236 */
237 int32_t SPI_Server_Stop (void) {
238    int32_t ret;
239   uint32_t i;
240
241   ret = EXIT_FAILURE;
242
243   if (spi_server_thread_id != NULL) {
244     spi_server_state = SPI_SERVER_STATE_TERMINATE;
245     for (i = 0U; i < 10U; i++) {
246       if (osThreadGetState(spi_server_thread_id) == osThreadTerminated) {
247         spi_server_thread_id = NULL;
248         ret = EXIT_SUCCESS;
249         break;
250       }
251       (void)osDelay(100U);
252     }
253   }
254
255   if (ret == EXIT_SUCCESS) {
256     ret = SPI_Com_PowerOff();
257   }
258
259   if (ret == EXIT_SUCCESS) {
260     ret = SPI_Com_Uninitialize();
261   }
262
263   if (ptr_spi_xfer_buf_rx_alloc != NULL) {
264     free(ptr_spi_xfer_buf_rx_alloc);
265     ptr_spi_xfer_buf_rx       = NULL;
266     ptr_spi_xfer_buf_rx_alloc = NULL;
267   }
268   if (ptr_spi_xfer_buf_tx_alloc != NULL) {
269     free(ptr_spi_xfer_buf_tx_alloc);
270     ptr_spi_xfer_buf_tx       = NULL;
271     ptr_spi_xfer_buf_tx_alloc = NULL;
272   }
273
274   if (ret != EXIT_SUCCESS) {
275     vioPrint(vioLevelError, "Server Stop failed! ");
276   }
277
278   return ret;
279 }
280
281
282 // Local functions
283
284 /**
285   \fn            static void SPI_Server_Thread (void *argument)
286   \brief         SPI Server thread function.
287   \detail        This is a thread function that waits to receive a command from SPI Client 
288                  (Driver Validation suite), and after command is received it is executed 
289                  and the process starts again by waiting to receive next command.
290   \param[in]     argument       Not used
291   \return        none
292 */
293 static void SPI_Server_Thread (void *argument) {
294   uint8_t i;
295
296   (void)argument;
297
298   for (;;) {
299     switch (spi_server_state) {
300
301       case SPI_SERVER_STATE_RECEPTION:  // Receive a command
302         if (SPI_Com_Receive(spi_cmd_buf_rx, BYTES_TO_ITEMS(sizeof(spi_cmd_buf_rx),SPI_SERVER_DATA_BITS), osWaitForever) == EXIT_SUCCESS) {
303           spi_server_state = SPI_SERVER_STATE_EXECUTION;
304         }
305         // If 32 byte command was not received restart the reception of 32 byte command
306         break;
307
308       case SPI_SERVER_STATE_EXECUTION:  // Execute a command
309         // Find the command and call handling function
310         for (i = 0U; i < (sizeof(spi_cmd_desc) / sizeof(SPI_CMD_DESC_t)); i++) {
311           if (memcmp(spi_cmd_buf_rx, spi_cmd_desc[i].command, strlen(spi_cmd_desc[i].command)) == 0) {
312             (void)spi_cmd_desc[i].Command_Func((const char *)spi_cmd_buf_rx);
313             break;
314           }
315         }
316         vioPrint(vioLevelMessage, "%.20s                    ", spi_cmd_buf_rx);
317         spi_server_state = SPI_SERVER_STATE_RECEPTION;
318         break;
319
320       case SPI_SERVER_STATE_TERMINATE:  // Self-terminate the thread
321       default:                          // Should never happen, processed as terminate request
322         vioPrint(vioLevelError, "Server stopped!     ");
323         (void)SPI_Com_Abort();
324         (void)osThreadTerminate(osThreadGetId());
325         break;
326     }
327   }
328 }
329
330 /**
331   \fn            static void SPI_Com_Event (uint32_t event)
332   \brief         SPI communication event callback (called from SPI driver from IRQ context).
333   \detail        This function dispatches event (flag) to SPI Server thread.
334   \param[in]     event       SPI event
335                    - ARM_SPI_EVENT_TRANSFER_COMPLETE: Data Transfer completed
336                    - ARM_SPI_EVENT_DATA_LOST:         Data lost: Receive overflow / Transmit underflow
337                    - ARM_SPI_EVENT_MODE_FAULT:        Master Mode Fault (SS deactivated when Master)
338   \return        none
339 */
340 static void SPI_Com_Event (uint32_t event) {
341
342   if (spi_server_thread_id != NULL) {
343     (void)osThreadFlagsSet(spi_server_thread_id, event);
344   }
345 }
346
347 /**
348   \fn            static int32_t SPI_Com_Initialize (void)
349   \brief         Initialize SPI interface.
350   \return        execution status
351                    - EXIT_SUCCESS: Operation successful
352                    - EXIT_FAILURE: Operation failed
353 */
354 static int32_t SPI_Com_Initialize (void) {
355   int32_t ret;
356
357   ret = EXIT_FAILURE;
358
359   if (drvSPI->Initialize(SPI_Com_Event) == ARM_DRIVER_OK) {
360     ret = EXIT_SUCCESS;
361   }
362
363   return ret;
364 }
365
366 /**
367   \fn            static int32_t SPI_Com_Uninitialize (void)
368   \brief         Uninitialize SPI interface.
369   \return        execution status
370                    - EXIT_SUCCESS: Operation successful
371                    - EXIT_FAILURE: Operation failed
372 */
373 static int32_t SPI_Com_Uninitialize (void) {
374   int32_t ret;
375
376   ret = EXIT_FAILURE;
377
378   if (drvSPI->Uninitialize() == ARM_DRIVER_OK) {
379     ret = EXIT_SUCCESS;
380   }
381
382   return ret;
383 }
384
385 /**
386   \fn            static int32_t SPI_Com_PowerOn (void)
387   \brief         Power-up SPI interface.
388   \return        execution status
389                    - EXIT_SUCCESS: Operation successful
390                    - EXIT_FAILURE: Operation failed
391 */
392 static int32_t SPI_Com_PowerOn (void) {
393   int32_t ret;
394
395   ret = EXIT_FAILURE;
396
397   if (drvSPI->PowerControl(ARM_POWER_FULL) == ARM_DRIVER_OK) {
398     ret = EXIT_SUCCESS;
399   }
400
401   return ret;
402 }
403
404 /**
405   \fn            static int32_t SPI_Com_PowerOff (void)
406   \brief         Power-down SPI interface.
407   \return        execution status
408                    - EXIT_SUCCESS: Operation successful
409                    - EXIT_FAILURE: Operation failed
410 */
411 static int32_t SPI_Com_PowerOff (void) {
412   int32_t ret;
413
414   ret = EXIT_FAILURE;
415
416   if (drvSPI->PowerControl(ARM_POWER_OFF) == ARM_DRIVER_OK) {
417     ret = EXIT_SUCCESS;
418   }
419
420   return ret;
421 }
422
423 /**
424   \fn            static int32_t SPI_Com_Configure (const SPI_COM_CONFIG_t *config)
425   \brief         Configure SPI interface.
426   \param[in]     config      Pointer to structure containing SPI interface configuration settings
427   \return        execution status
428                    - EXIT_SUCCESS: Operation successful
429                    - EXIT_FAILURE: Operation failed
430 */
431 static int32_t SPI_Com_Configure (const SPI_COM_CONFIG_t *config) {
432   int32_t ret;
433
434   ret = EXIT_FAILURE;
435
436   if (drvSPI->Control(config->mode      |
437                       config->format    |
438                       config->bit_num   |
439                       config->bit_order |
440                       config->ss_mode   ,
441                       config->bus_speed ) == ARM_DRIVER_OK) {
442     spi_bytes_per_item = DATA_BITS_TO_BYTES((config->bit_num & ARM_SPI_DATA_BITS_Msk) >> ARM_SPI_DATA_BITS_Pos);
443     ret = EXIT_SUCCESS;
444   }
445
446   return ret;
447 }
448
449 /**
450   \fn            static uint32_t SPI_Com_SS (void)
451   \brief         Drive Slave Select line with Control function.
452   \return        number of data items transferred
453 */
454 static uint32_t SPI_Com_SS (uint32_t active) {
455    int32_t ret;
456   uint32_t arg;
457
458   ret = EXIT_FAILURE;
459
460   if (active != 0U) {
461     arg = ARM_SPI_SS_ACTIVE;
462   } else {
463     arg = ARM_SPI_SS_INACTIVE;
464   }
465
466   if (drvSPI->Control(ARM_SPI_CONTROL_SS, arg) == ARM_DRIVER_OK) {
467     ret = EXIT_SUCCESS;
468   }
469
470   return ret;
471 }
472
473 /**
474   \fn            static int32_t SPI_Com_Receive (void *data_in, uint32_t num, uint32_t timeout)
475   \brief         Receive data (command) over SPI interface.
476   \param[out]    data_in     Pointer to memory where data will be received
477   \param[in]     num         Number of data items to be received
478   \param[in]     timeout     Timeout for reception (in ms)
479   \return        execution status
480                    - EXIT_SUCCESS: Operation successful
481                    - EXIT_FAILURE: Operation failed
482 */
483 static int32_t SPI_Com_Receive (void *data_in, uint32_t num, uint32_t timeout) {
484    int32_t ret;
485   uint32_t flags, tmo, time, cnt;
486
487   ret = EXIT_FAILURE;
488
489   if (spi_server_thread_id != NULL) {
490     memset(data_in, (int32_t)'?', spi_bytes_per_item * num);
491     vioSetSignal (vioLED0, vioLEDon);
492     cnt  = 0;
493     time = timeout;
494     if (drvSPI->Receive(data_in, num) == ARM_DRIVER_OK) {
495       while (time != 0U) {
496         if (time > 100U) {
497           tmo = 100U;
498         } else {
499           tmo = time;
500         }
501         flags = osThreadFlagsWait(SPI_EVENTS_MASK, osFlagsWaitAny, tmo);
502         if (flags == osFlagsErrorTimeout) {     // If timeout
503           if (time != osWaitForever) {
504             time -= tmo;
505           }
506           if (drvSPI->GetDataCount() != 0U) {
507             while (cnt != drvSPI->GetDataCount()) {   // While count is changing
508               cnt = drvSPI->GetDataCount();
509               flags = osThreadFlagsWait(SPI_EVENTS_MASK, osFlagsWaitAny, 10U);
510               if (flags == osFlagsErrorTimeout) {     // If timeout
511                 if (time != osWaitForever) {
512                   if (time > tmo) {
513                     time -= tmo;
514                   } else {
515                     time = 0U;
516                     break;
517                   }
518                 }
519               } else if ((flags & (0x80000000U | ARM_SPI_EVENT_TRANSFER_COMPLETE)) == ARM_SPI_EVENT_TRANSFER_COMPLETE) {
520                 // If completed event was signaled
521                 ret = EXIT_SUCCESS;
522                 break;
523               } else {
524                 // In all other cases exit with failed status
525                 break;
526               }
527             }
528             if (cnt != 0U) {
529               // If something was received but not of expected size then terminate the reception
530               break;
531             }
532           }
533         } else if ((flags & (0x80000000U | ARM_SPI_EVENT_TRANSFER_COMPLETE)) == ARM_SPI_EVENT_TRANSFER_COMPLETE) {
534           // If completed event was signaled
535           ret = EXIT_SUCCESS;
536           break;
537         } else {
538           // In all other cases exit with failed status
539           break;
540         }
541       }
542       if (ret != EXIT_SUCCESS) {
543         // If receive was activated but failed to receive expected data then abort the transfer
544         (void)drvSPI->Control(ARM_SPI_ABORT_TRANSFER, 0U);
545       }
546       vioSetSignal (vioLED0, vioLEDoff);
547     }
548   }
549
550   return ret;
551 }
552
553 /**
554   \fn            static int32_t SPI_Com_Send (const void *data_out, uint32_t num, uint32_t timeout)
555   \brief         Send data (response) over SPI interface.
556   \param[out]    data_out       Pointer to memory containing data to be sent
557   \param[in]     num            Number of data items to be sent
558   \param[in]     timeout        Timeout for send (in ms)
559   \return        execution status
560                    - EXIT_SUCCESS: Operation successful
561                    - EXIT_FAILURE: Operation failed
562 */
563 static int32_t SPI_Com_Send (const void *data_out, uint32_t num, uint32_t timeout) {
564   uint32_t flags;
565    int32_t ret;
566
567   ret = EXIT_FAILURE;
568
569   if (spi_server_thread_id != NULL) {
570     vioSetSignal (vioLED1, vioLEDon);
571     if (drvSPI->Send(data_out, num) == ARM_DRIVER_OK) {
572       flags = osThreadFlagsWait(SPI_EVENTS_MASK, osFlagsWaitAny, timeout);
573       if ((flags & (0x80000000U | ARM_SPI_EVENT_TRANSFER_COMPLETE)) == ARM_SPI_EVENT_TRANSFER_COMPLETE) {
574         // If completed event was signaled
575         ret = EXIT_SUCCESS;
576       }
577       if (ret != EXIT_SUCCESS) {
578         // If send was activated but failed to send all of the expected data then abort the transfer
579         (void)drvSPI->Control(ARM_SPI_ABORT_TRANSFER, 0U);
580       }
581       vioSetSignal (vioLED1, vioLEDoff);
582     }
583   }
584
585   return ret;
586 }
587
588 /**
589   \fn            static int32_t SPI_Com_Transfer (const void *data_out, void *data_in, uint32_t num, uint32_t timeout)
590   \brief         Transfer (send/receive) data over SPI interface.
591   \param[in]     data_out       Pointer to memory containing data to be sent
592   \param[out]    data_in        Pointer to memory where data will be received
593   \param[in]     num            Number of data items to be transferred
594   \param[in]     timeout        Timeout for transfer (in ms)
595   \return        execution status
596                    - EXIT_SUCCESS: Operation successful
597                    - EXIT_FAILURE: Operation failed
598 */
599 static int32_t SPI_Com_Transfer (const void *data_out, void *data_in, uint32_t num, uint32_t timeout) {
600   uint32_t flags;
601    int32_t ret;
602
603   ret = EXIT_FAILURE;
604
605   if (spi_server_thread_id != NULL) {
606     vioSetSignal (vioLED2, vioLEDon);
607     if (drvSPI->Transfer(data_out, data_in, num) == ARM_DRIVER_OK) {
608       flags = osThreadFlagsWait(SPI_EVENTS_MASK, osFlagsWaitAny, timeout);
609       spi_xfer_cnt = drvSPI->GetDataCount();
610       if ((flags & (0x80000000U | ARM_SPI_EVENT_TRANSFER_COMPLETE)) == ARM_SPI_EVENT_TRANSFER_COMPLETE) {
611         // If completed event was signaled
612         ret = EXIT_SUCCESS;
613       } else {
614         // If error or timeout
615         (void)drvSPI->Control(ARM_SPI_ABORT_TRANSFER, 0U);
616       }
617       vioSetSignal (vioLED2, vioLEDoff);
618     }
619   }
620
621   return ret;
622 }
623
624 /**
625   \fn            static int32_t SPI_Com_Abort (void)
626   \brief         Abort current transfer on SPI interface.
627   \return        execution status
628                    - EXIT_SUCCESS: Operation successful
629                    - EXIT_FAILURE: Operation failed
630 */
631 static int32_t SPI_Com_Abort (void) {
632   int32_t ret;
633
634   ret = EXIT_FAILURE;
635
636   if (drvSPI->Control(ARM_SPI_ABORT_TRANSFER, 0U) == ARM_DRIVER_OK) {
637     ret = EXIT_SUCCESS;
638   }
639
640   return ret;
641 }
642
643 /**
644   \fn            static uint32_t SPI_Com_GetCnt (void)
645   \brief         Get number of data items transferred over SPI interface in last transfer.
646   \return        number of data items transferred
647 */
648 static uint32_t SPI_Com_GetCnt (void) {
649   return spi_xfer_cnt;
650 }
651
652
653 // Command handling functions
654
655 /**
656   \fn            static int32_t SPI_Cmd_GetVer (const char *cmd)
657   \brief         Handle command "GET VER".
658   \detail        Return SPI Server version over SPI interface (16 bytes).
659   \param[in]     cmd            Pointer to null-terminated command string
660   \return        execution status
661                    - EXIT_SUCCESS: Operation successful
662                    - EXIT_FAILURE: Operation failed
663 */
664 static int32_t SPI_Cmd_GetVer (const char *cmd) {
665
666   (void)cmd;
667
668   memset(spi_cmd_buf_tx, 0, 16);
669   memcpy(spi_cmd_buf_tx, SPI_SERVER_VER, sizeof(SPI_SERVER_VER));
670
671   return (SPI_Com_Send(spi_cmd_buf_tx, BYTES_TO_ITEMS(16U, SPI_SERVER_DATA_BITS), spi_cmd_timeout));
672 }
673
674 /**
675   \fn            static int32_t SPI_Cmd_GetCap (const char *cmd)
676   \brief         Handle command "GET CAP".
677   \detail        Return SPI Server capabilities over SPI interface (32 bytes).
678   \param[in]     cmd            Pointer to null-terminated command string
679   \return        execution status
680                    - EXIT_SUCCESS: Operation successful
681                    - EXIT_FAILURE: Operation failed
682 */
683 static int32_t SPI_Cmd_GetCap (const char *cmd) {
684   int32_t  ret;
685   uint32_t mode_mask, format_mask, data_bits_mask, bit_order_mask, bus_speed_min, bus_speed_max;
686   uint32_t bs;
687   uint8_t  i;
688
689   (void)cmd;
690
691   ret = EXIT_FAILURE;
692
693   // Determine supported minimum bus speed
694   // Find minimum speed setting at which Control function succeeds
695   bs = 1000U;
696   do {
697     if (drvSPI->Control(ARM_SPI_MODE_MASTER                                                           | 
698                       ((SPI_SERVER_FORMAT    << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) | 
699                       ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos)    & ARM_SPI_DATA_BITS_Msk)    | 
700                       ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos)    & ARM_SPI_BIT_ORDER_Msk)    | 
701                         ARM_SPI_SS_MASTER_HW_OUTPUT                                                   , 
702                         bs     ) == ARM_DRIVER_OK) {
703       break;
704     }
705     if (drvSPI->Control(ARM_SPI_MODE_MASTER                                                           | 
706                       ((SPI_SERVER_FORMAT    << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) | 
707                       ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos)    & ARM_SPI_DATA_BITS_Msk)    | 
708                       ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos)    & ARM_SPI_BIT_ORDER_Msk)    | 
709                         ARM_SPI_SS_MASTER_HW_OUTPUT                                                   , 
710                         bs * 2U) == ARM_DRIVER_OK) {
711       bs *= 2U;
712       break;
713     }
714     if (drvSPI->Control(ARM_SPI_MODE_MASTER                                                           | 
715                       ((SPI_SERVER_FORMAT    << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) | 
716                       ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos)    & ARM_SPI_DATA_BITS_Msk)    | 
717                       ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos)    & ARM_SPI_BIT_ORDER_Msk)    | 
718                         ARM_SPI_SS_MASTER_HW_OUTPUT                                                   , 
719                         bs * 5U) == ARM_DRIVER_OK) {
720       bs *= 5U;
721       break;
722     }
723     if (drvSPI->Control(ARM_SPI_MODE_MASTER                                                           | 
724                       ((SPI_SERVER_FORMAT    << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) | 
725                       ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos)    & ARM_SPI_DATA_BITS_Msk)    | 
726                       ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos)    & ARM_SPI_BIT_ORDER_Msk)    | 
727                         ARM_SPI_SS_MASTER_HW_OUTPUT                                                   , 
728                         bs * 10U) == ARM_DRIVER_OK) {
729       bs *= 10U;
730       break;
731     }
732     bs *= 10U;
733   } while (bs < 1000000U);
734   bus_speed_min = bs;
735
736   // Determine supported maximum bus speed
737   // Find maximum speed setting at which Control function succeeds
738   bs = 100000000U;
739   do {
740     if (drvSPI->Control(ARM_SPI_MODE_MASTER                                                           | 
741                       ((SPI_SERVER_FORMAT    << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) | 
742                       ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos)    & ARM_SPI_DATA_BITS_Msk)    | 
743                       ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos)    & ARM_SPI_BIT_ORDER_Msk)    | 
744                         ARM_SPI_SS_MASTER_HW_OUTPUT                                                   , 
745                         bs     ) == ARM_DRIVER_OK) {
746       break;
747     }
748     if (drvSPI->Control(ARM_SPI_MODE_MASTER                                                           | 
749                       ((SPI_SERVER_FORMAT    << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) | 
750                       ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos)    & ARM_SPI_DATA_BITS_Msk)    | 
751                       ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos)    & ARM_SPI_BIT_ORDER_Msk)    | 
752                         ARM_SPI_SS_MASTER_HW_OUTPUT                                                   , 
753                         bs / 2U) == ARM_DRIVER_OK) {
754       bs /= 2U;
755       break;
756     }
757     if (drvSPI->Control(ARM_SPI_MODE_MASTER                                                           | 
758                       ((SPI_SERVER_FORMAT    << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) | 
759                       ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos)    & ARM_SPI_DATA_BITS_Msk)    | 
760                       ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos)    & ARM_SPI_BIT_ORDER_Msk)    | 
761                         ARM_SPI_SS_MASTER_HW_OUTPUT                                                   , 
762                         bs / 5U) == ARM_DRIVER_OK) {
763       bs /= 5U;
764       break;
765     }
766     if (drvSPI->Control(ARM_SPI_MODE_MASTER                                                           | 
767                       ((SPI_SERVER_FORMAT    << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) | 
768                       ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos)    & ARM_SPI_DATA_BITS_Msk)    | 
769                       ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos)    & ARM_SPI_BIT_ORDER_Msk)    | 
770                         ARM_SPI_SS_MASTER_HW_OUTPUT                                                   , 
771                         bs / 10U) == ARM_DRIVER_OK) {
772       bs /= 10U;
773       break;
774     }
775     bs /= 10U;
776   } while (bs > 1000000U);
777   bus_speed_max = bs;
778
779   // Determine supported modes
780   mode_mask = 0U;
781   if (drvSPI->Control(ARM_SPI_MODE_MASTER                                                           | 
782                     ((SPI_SERVER_FORMAT    << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) | 
783                     ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos)    & ARM_SPI_DATA_BITS_Msk)    | 
784                     ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos)    & ARM_SPI_BIT_ORDER_Msk)    | 
785                       ARM_SPI_SS_MASTER_HW_OUTPUT                                                   , 
786                       bus_speed_min ) == ARM_DRIVER_OK) {
787     mode_mask |= 1U;
788   }
789
790   if (drvSPI->Control(ARM_SPI_MODE_SLAVE                                                            | 
791                     ((SPI_SERVER_FORMAT    << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) | 
792                     ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos)    & ARM_SPI_DATA_BITS_Msk)    | 
793                     ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos)    & ARM_SPI_BIT_ORDER_Msk)    | 
794                       ARM_SPI_SS_SLAVE_HW                                                           , 
795                       0U ) == ARM_DRIVER_OK) {
796     mode_mask |= 1U << 1;
797   }
798
799   // Determine supported clock / frame format
800   format_mask = 0U;
801   if (drvSPI->Control(ARM_SPI_MODE_SLAVE                                                            | 
802                       ARM_SPI_CPOL0_CPHA0                                                           | 
803                     ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos)    & ARM_SPI_DATA_BITS_Msk)    | 
804                     ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos)    & ARM_SPI_BIT_ORDER_Msk)    | 
805                       ARM_SPI_SS_SLAVE_HW                                                           , 
806                       0U ) == ARM_DRIVER_OK) {
807     format_mask |= 1U;
808   }
809   if (drvSPI->Control(ARM_SPI_MODE_SLAVE                                                            | 
810                       ARM_SPI_CPOL0_CPHA1                                                           | 
811                     ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos)    & ARM_SPI_DATA_BITS_Msk)    | 
812                     ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos)    & ARM_SPI_BIT_ORDER_Msk)    | 
813                       ARM_SPI_SS_SLAVE_HW                                                           , 
814                       0U ) == ARM_DRIVER_OK) {
815     format_mask |= 1U << 1;
816   }
817   if (drvSPI->Control(ARM_SPI_MODE_SLAVE                                                            | 
818                       ARM_SPI_CPOL1_CPHA0                                                           | 
819                     ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos)    & ARM_SPI_DATA_BITS_Msk)    | 
820                     ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos)    & ARM_SPI_BIT_ORDER_Msk)    | 
821                       ARM_SPI_SS_SLAVE_HW                                                           , 
822                       0U ) == ARM_DRIVER_OK) {
823     format_mask |= 1U << 2;
824   }
825   if (drvSPI->Control(ARM_SPI_MODE_SLAVE                                                            | 
826                       ARM_SPI_CPOL1_CPHA1                                                           | 
827                     ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos)    & ARM_SPI_DATA_BITS_Msk)    | 
828                     ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos)    & ARM_SPI_BIT_ORDER_Msk)    | 
829                       ARM_SPI_SS_SLAVE_HW                                                           , 
830                       0U ) == ARM_DRIVER_OK) {
831     format_mask |= 1U << 3;
832   }
833   if (drvSPI->Control(ARM_SPI_MODE_SLAVE                                                            | 
834                       ARM_SPI_TI_SSI                                                                | 
835                     ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos)    & ARM_SPI_DATA_BITS_Msk)    | 
836                     ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos)    & ARM_SPI_BIT_ORDER_Msk)    | 
837                       ARM_SPI_SS_SLAVE_HW                                                           , 
838                       0U ) == ARM_DRIVER_OK) {
839     format_mask |= 1U << 4;
840   }
841   if (drvSPI->Control(ARM_SPI_MODE_SLAVE                                                            | 
842                       ARM_SPI_MICROWIRE                                                             | 
843                     ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos)    & ARM_SPI_DATA_BITS_Msk)    | 
844                     ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos)    & ARM_SPI_BIT_ORDER_Msk)    | 
845                       ARM_SPI_SS_SLAVE_HW                                                           , 
846                       0U ) == ARM_DRIVER_OK) {
847     format_mask |= 1U << 5;
848   }
849
850   // Determine supported data bits
851   data_bits_mask = 0U;
852   for (i = 1U; i <= 32U; i++) {
853     if (drvSPI->Control(ARM_SPI_MODE_SLAVE                                                            | 
854                       ((SPI_SERVER_FORMAT    << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) | 
855                       ((i                    << ARM_SPI_DATA_BITS_Pos)    & ARM_SPI_DATA_BITS_Msk)    | 
856                       ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos)    & ARM_SPI_BIT_ORDER_Msk)    | 
857                         ARM_SPI_SS_SLAVE_HW                                                           , 
858                         0U ) == ARM_DRIVER_OK) {
859       data_bits_mask |= 1UL << (i - 1U);
860     }
861   }
862
863   // Determine bit order
864   bit_order_mask = 0U;
865   if (drvSPI->Control(ARM_SPI_MODE_SLAVE                                                            | 
866                     ((SPI_SERVER_FORMAT    << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) | 
867                     ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos)    & ARM_SPI_DATA_BITS_Msk)    | 
868                       ARM_SPI_MSB_LSB                                                               | 
869                       ARM_SPI_SS_SLAVE_HW                                                           , 
870                       0U ) == ARM_DRIVER_OK) {
871     bit_order_mask |= 1U;
872   }
873   if (drvSPI->Control(ARM_SPI_MODE_SLAVE                                                            | 
874                     ((SPI_SERVER_FORMAT    << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) | 
875                     ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos)    & ARM_SPI_DATA_BITS_Msk)    | 
876                       ARM_SPI_LSB_MSB                                                               | 
877                       ARM_SPI_SS_SLAVE_HW                                                           , 
878                       0U ) == ARM_DRIVER_OK) {
879     bit_order_mask |= 1U << 1;
880   }
881
882   // Revert communication settings to default because they were changed during auto-detection of capabilities
883   (void)SPI_Com_Configure(&spi_com_config_default);
884
885   memset(spi_cmd_buf_tx, 0, 32);
886   if (snprintf((char *)spi_cmd_buf_tx, 32, "%02X,%02X,%08X,%02X,%i,%i", 
887                 mode_mask, 
888                 format_mask, 
889                 data_bits_mask, 
890                 bit_order_mask, 
891                (bus_speed_min / 1000U), 
892                (bus_speed_max / 1000U)) <= 32) {
893     ret = SPI_Com_Send(spi_cmd_buf_tx, BYTES_TO_ITEMS(32U, SPI_SERVER_DATA_BITS), spi_cmd_timeout);
894   }
895
896   return ret;
897 }
898
899 /**
900   \fn            static int32_t SPI_Cmd_SetBuf (const char *cmd)
901   \brief         Handle command "SET BUF RX/TX,len[,pattern]".
902   \detail        Initialize content of the buffer in the following way:
903                   - fill whole buffer with 'pattern' value if it is specified, and 'len' is 0
904                   - fill whole buffer with 0 if 'pattern' is not provided and 'len' is 0
905                   - load 'len' bytes from start of the buffer with content 
906                     received in IN data phase
907   \param[in]     cmd            Pointer to null-terminated command string
908   \return        execution status
909                    - EXIT_SUCCESS: Operation successful
910                    - EXIT_FAILURE: Operation failed
911 */
912 static int32_t SPI_Cmd_SetBuf (const char *cmd) {
913   const char     *ptr_str;
914         uint8_t  *ptr_buf;
915         uint32_t  val, len;
916         uint8_t   pattern;
917          int32_t  ret;
918
919   ret     = EXIT_SUCCESS;
920   ptr_str = NULL;
921   ptr_buf = NULL;
922   val     = 0U;
923   len     = 0U;
924   pattern = 0U;
925
926   // Parse 'RX' or 'TX' selection
927   if        (strstr(cmd, "RX") != NULL) {
928     ptr_buf = ptr_spi_xfer_buf_rx;
929   } else if (strstr(cmd, "TX") != NULL) {
930     ptr_buf = ptr_spi_xfer_buf_tx;
931   } else {
932     ret = EXIT_FAILURE;
933   }
934
935   if (ret == EXIT_SUCCESS) {
936     // Parse 'len'
937     ptr_str = strstr(cmd, ",");         // Find ','
938     if (ptr_str != NULL) {              // If ',' was found
939       ptr_str++;                        // Skip ','
940       while (*ptr_str == ' ') {         // Skip whitespaces after ','
941         ptr_str++;
942       }
943       if (sscanf(ptr_str, "%u", &val) == 1) {
944         if (val <= spi_xfer_buf_size) {
945           len = val;
946         } else {
947           ret = EXIT_FAILURE;
948         }
949       } else {
950         ret = EXIT_FAILURE;
951       }
952     } else {
953       ret = EXIT_FAILURE;
954     }
955   }
956
957   if ((ret == EXIT_SUCCESS) && (ptr_str != NULL)) {
958     // Parse optional 'pattern'
959     ptr_str = strstr(ptr_str, ",");     // Find ','
960     if (ptr_str != NULL) {              // If ',' was found
961       ptr_str++;                        // Skip ','
962       while (*ptr_str == ' ') {         // Skip whitespaces after ','
963         ptr_str++;
964       }
965       if (sscanf(ptr_str, "%x", &val) == 1) {
966         pattern = (uint8_t)val;
967       } else {
968         ret = EXIT_FAILURE;
969       }
970     }
971   }
972
973   if ((ret == EXIT_SUCCESS) && (ptr_buf != NULL)) {
974     // Fill the whole buffer with 'pattern', if 'pattern' was not specified 
975     // in the command then the whole buffer will be filled with 0
976     memset(ptr_buf, (int32_t)pattern, spi_xfer_buf_size);
977   }
978
979   if ((ret == EXIT_SUCCESS) && (ptr_buf != NULL) && (len != 0U)) {
980     // Load 'len' bytes from start of buffer with content received in IN data phase
981     ret = SPI_Com_Receive(ptr_buf, BYTES_TO_ITEMS(len, SPI_SERVER_DATA_BITS), spi_cmd_timeout);
982   }
983
984   return ret;
985 }
986
987 /**
988   \fn            static int32_t SPI_Cmd_GetBuf (const char *cmd)
989   \brief         Handle command "GET BUF RX/TX,len".
990   \detail        Send content of buffer over SPI interface.
991   \param[in]     cmd            Pointer to null-terminated command string
992   \return        execution status
993                    - EXIT_SUCCESS: Operation successful
994                    - EXIT_FAILURE: Operation failed
995 */
996 static int32_t SPI_Cmd_GetBuf (const char *cmd) {
997   const char     *ptr_str;
998   const uint8_t  *ptr_buf;
999         uint32_t  val, len;
1000          int32_t  ret;
1001
1002   ret      = EXIT_SUCCESS;
1003   ptr_str  = NULL;
1004   ptr_buf  = NULL;
1005   val      = 0U;
1006   len      = 0U;
1007
1008   // Parse 'RX' or 'TX' selection
1009   if        (strstr(cmd, "RX") != NULL) {
1010     ptr_buf = ptr_spi_xfer_buf_rx;
1011   } else if (strstr(cmd, "TX") != NULL) {
1012     ptr_buf = ptr_spi_xfer_buf_tx;
1013   } else {
1014     ret = EXIT_FAILURE;
1015   }
1016
1017   if (ret == EXIT_SUCCESS) {
1018     // Parse 'len'
1019     ptr_str = strstr(cmd, ",");         // Find ','
1020     if (ptr_str != NULL) {              // If ',' was found
1021       ptr_str++;                        // Skip ','
1022       while (*ptr_str == ' ') {         // Skip whitespaces after ','
1023         ptr_str++;
1024       }
1025       if (sscanf(ptr_str, "%u", &val) == 1) {
1026         if ((val > 0U) && (val <= spi_xfer_buf_size)) {
1027           len = val;
1028         } else {
1029           ret = EXIT_FAILURE;
1030         }
1031       } else {
1032         ret = EXIT_FAILURE;
1033       }
1034     } else {
1035       ret = EXIT_FAILURE;
1036     }
1037   }
1038
1039   if ((ret == EXIT_SUCCESS) && (ptr_buf != NULL) && (len != 0U)) {
1040     ret = SPI_Com_Send(ptr_buf, BYTES_TO_ITEMS(len, SPI_SERVER_DATA_BITS), spi_cmd_timeout);
1041   }
1042
1043   return ret;
1044 }
1045
1046 /**
1047   \fn            static int32_t SPI_Cmd_SetCom (const char *cmd)
1048   \brief         Handle command "SET COM mode,format,bit_num,bit_order,ss_mode,bus_speed".
1049   \detail        Set communication configuration settings used for transfers (XFER commands).
1050   \param[in]     cmd            Pointer to null-terminated command string
1051   \return        execution status
1052                    - EXIT_SUCCESS: Operation successful
1053                    - EXIT_FAILURE: Operation failed
1054 */
1055 static int32_t SPI_Cmd_SetCom (const char *cmd) {
1056   const char    *ptr_str;
1057         uint32_t val;
1058          int32_t ret;
1059
1060   ret = EXIT_SUCCESS;
1061   val = 0U;
1062
1063   ptr_str = &cmd[7];                    // Skip "SET COM"
1064   while (*ptr_str == ' ') {             // Skip whitespaces
1065     ptr_str++;
1066   }
1067
1068   // Parse 'mode'
1069   if (sscanf(ptr_str, "%u", &val) == 1) {
1070     switch (val) {
1071       case 0U:                          // Master mode
1072         spi_com_config_xfer.mode = ARM_SPI_MODE_MASTER;
1073         break;
1074       case 1U:                          // Slave mode
1075         spi_com_config_xfer.mode = ARM_SPI_MODE_SLAVE;
1076         break;
1077       default:
1078         ret = EXIT_FAILURE;
1079         break;
1080     }
1081   } else {
1082     ret = EXIT_FAILURE;
1083   }
1084
1085   if ((ret == EXIT_SUCCESS) && (ptr_str != NULL)) {
1086     // Parse 'format' (clock polarity/phase or frame format)
1087     ptr_str = strstr(ptr_str, ",");     // Find ','
1088     if (ptr_str != NULL) {              // If ',' was found
1089       ptr_str++;                        // Skip ','
1090       while (*ptr_str == ' ') {         // Skip whitespaces after ','
1091         ptr_str++;
1092       }
1093       if (sscanf(ptr_str, "%u", &val) == 1) {
1094         switch (val) {
1095           case 0:                       // Clock polarity 0, clock phase 0
1096             spi_com_config_xfer.format = ARM_SPI_CPOL0_CPHA0;
1097             break;
1098           case 1:                       // Clock polarity 0, clock phase 1
1099             spi_com_config_xfer.format = ARM_SPI_CPOL0_CPHA1;
1100             break;
1101           case 2:                       // Clock polarity 1, clock phase 0
1102             spi_com_config_xfer.format = ARM_SPI_CPOL1_CPHA0;
1103             break;
1104           case 3:                       // Clock polarity 1, clock phase 1
1105             spi_com_config_xfer.format = ARM_SPI_CPOL1_CPHA1;
1106             break;
1107           case 4:                       // Texas Instruments Frame Format
1108             spi_com_config_xfer.format = ARM_SPI_TI_SSI;
1109             break;
1110           case 5:                       // National Microwire Frame Format
1111             spi_com_config_xfer.format = ARM_SPI_MICROWIRE;
1112             break;
1113           default:
1114             ret = EXIT_FAILURE;
1115             break;
1116         }
1117       } else {
1118         ret = EXIT_FAILURE;
1119       }
1120     }
1121   }
1122
1123   if ((ret == EXIT_SUCCESS) && (ptr_str != NULL)) {
1124     // Parse 'bit_num'
1125     ptr_str = strstr(ptr_str, ",");     // Find ','
1126     if (ptr_str != NULL) {              // If ',' was found
1127       ptr_str++;                        // Skip ','
1128       while (*ptr_str == ' ') {         // Skip whitespaces after ','
1129         ptr_str++;
1130       }
1131       if (sscanf(ptr_str, "%u", &val) == 1) {
1132         if ((val > 0U) && (val <= 32U)) {
1133           spi_com_config_xfer.bit_num = ARM_SPI_DATA_BITS(val);
1134         } else {
1135           ret = EXIT_FAILURE;
1136         }
1137       } else {
1138         ret = EXIT_FAILURE;
1139       }
1140     }
1141   }
1142
1143   if ((ret == EXIT_SUCCESS) && (ptr_str != NULL)) {
1144     // Parse 'bit_order'
1145     ptr_str = strstr(ptr_str, ",");     // Find ','
1146     if (ptr_str != NULL) {              // If ',' was found
1147       ptr_str++;                        // Skip ','
1148       while (*ptr_str == ' ') {         // Skip whitespaces after ','
1149         ptr_str++;
1150       }
1151       if (sscanf(ptr_str, "%u", &val) == 1) {
1152         if (val == 0U) {
1153           spi_com_config_xfer.bit_order = ARM_SPI_MSB_LSB;
1154         } else if (val == 1U) {
1155           spi_com_config_xfer.bit_order = ARM_SPI_LSB_MSB;
1156         } else {
1157           ret = EXIT_FAILURE;
1158         }
1159       } else {
1160         ret = EXIT_FAILURE;
1161       }
1162     }
1163   }
1164
1165   if ((ret == EXIT_SUCCESS) && (ptr_str != NULL)) {
1166     // Parse 'ss_mode'
1167     ptr_str = strstr(ptr_str, ",");     // Find ','
1168     if (ptr_str != NULL) {              // If ',' was found
1169       ptr_str++;                        // Skip ','
1170       while (*ptr_str == ' ') {         // Skip whitespaces after ','
1171         ptr_str++;
1172       }
1173       if (sscanf(ptr_str, "%u", &val) == 1) {
1174         if (spi_com_config_xfer.mode == ARM_SPI_MODE_MASTER) {
1175           // Slave Select modes for Master mode
1176           switch (val) {
1177             case 0:
1178               spi_com_config_xfer.ss_mode = ARM_SPI_SS_MASTER_UNUSED;
1179               break;
1180             case 1:
1181               spi_com_config_xfer.ss_mode = ARM_SPI_SS_MASTER_HW_OUTPUT;
1182               break;
1183             default:
1184               ret = EXIT_FAILURE;
1185               break;
1186           }
1187         } else {
1188           // Slave Select modes for Slave mode
1189           switch (val) {
1190             case 0:
1191               spi_com_config_xfer.ss_mode = ARM_SPI_SS_SLAVE_SW;
1192               break;
1193             case 1:
1194               spi_com_config_xfer.ss_mode = ARM_SPI_SS_SLAVE_HW;
1195               break;
1196             default:
1197               ret = EXIT_FAILURE;
1198               break;
1199           }
1200         }
1201       } else {
1202         ret = EXIT_FAILURE;
1203       }
1204     }
1205   }
1206
1207   if ((ret == EXIT_SUCCESS) && (ptr_str != NULL)) {
1208     // Parse 'bus_speed'
1209     ptr_str = strstr(ptr_str, ",");     // Find ','
1210     if (ptr_str != NULL) {              // If ',' was found
1211       ptr_str++;                        // Skip ','
1212       while (*ptr_str == ' ') {         // Skip whitespaces after ','
1213         ptr_str++;
1214       }
1215       if (sscanf(ptr_str, "%u", &val) == 1) {
1216         spi_com_config_xfer.bus_speed = val;
1217       } else {
1218         ret = EXIT_FAILURE;
1219       }
1220     }
1221   }
1222
1223   return ret;
1224 }
1225
1226 /**
1227   \fn            static int32_t SPI_Cmd_Xfer (const char *cmd)
1228   \brief         Handle command "XFER num[,delay_c][,delay_t][,timeout]".
1229   \detail        Send data from SPI TX buffer and receive data to SPI RX buffer 
1230                  (buffers must be set with "SET BUF" command before this command).
1231                  Control function is delayed by optional parameter 'delay_c' in milliseconds.
1232                  Transfer function is delayed by optional parameter 'delay_t' in milliseconds, 
1233                  starting after delay specified with 'delay_c' parameter.
1234   \param[in]     cmd            Pointer to null-terminated command string
1235   \return        execution status
1236                    - EXIT_SUCCESS: Operation successful
1237                    - EXIT_FAILURE: Operation failed
1238 */
1239 static int32_t SPI_Cmd_Xfer (const char *cmd) {
1240   const char    *ptr_str;
1241         uint32_t val, num, delay_c, delay_t, start_tick, curr_tick;
1242          int32_t ret;
1243
1244   ret             = EXIT_SUCCESS;
1245   val             = 0U;
1246   num             = 0U;
1247   delay_c         = 0U;
1248   delay_t         = 0U;
1249
1250   ptr_str = &cmd[4];                    // Skip "XFER"
1251   while (*ptr_str == ' ') {             // Skip whitespaces
1252     ptr_str++;
1253   }
1254
1255   // Parse 'num'
1256   if (sscanf(ptr_str, "%u", &val) == 1) {
1257     if ((val > 0U) && (val <= spi_xfer_buf_size)) {
1258       num = val;
1259     } else {
1260       ret = EXIT_FAILURE;
1261     }
1262   } else {
1263     ret = EXIT_FAILURE;
1264   }
1265
1266   if ((ret == EXIT_SUCCESS) && (ptr_str != NULL)) {
1267     // Parse optional 'delay_c'
1268     ptr_str = strstr(ptr_str, ",");     // Find ','
1269     if (ptr_str != NULL) {              // If ',' was found
1270       ptr_str++;                        // Skip ','
1271       while (*ptr_str == ' ') {         // Skip whitespaces after ','
1272         ptr_str++;
1273       }
1274       if (sscanf(ptr_str, "%u", &val) == 1) {
1275         if (val != osWaitForever) {
1276           delay_c = val;
1277         } else {
1278           ret = EXIT_FAILURE;
1279         }
1280       } else {
1281         ret = EXIT_FAILURE;
1282       }
1283     }
1284   }
1285
1286   if ((ret == EXIT_SUCCESS) && (ptr_str != NULL)) {
1287     // Parse optional 'delay_t'
1288     ptr_str = strstr(ptr_str, ",");     // Find ','
1289     if (ptr_str != NULL) {              // If ',' was found
1290       ptr_str++;                        // Skip ','
1291       while (*ptr_str == ' ') {         // Skip whitespaces after ','
1292         ptr_str++;
1293       }
1294       if (sscanf(ptr_str, "%u", &val) == 1) {
1295         if (val != osWaitForever) {
1296           delay_t = val;
1297         } else {
1298           ret = EXIT_FAILURE;
1299         }
1300       } else {
1301         ret = EXIT_FAILURE;
1302       }
1303     }
1304   }
1305
1306   if ((ret == EXIT_SUCCESS) && (ptr_str != NULL)) {
1307     // Parse optional 'timeout'
1308     ptr_str = strstr(ptr_str, ",");     // Find ','
1309     if (ptr_str != NULL) {              // If ',' was found
1310       ptr_str++;                        // Skip ','
1311       while (*ptr_str == ' ') {         // Skip whitespaces after ','
1312         ptr_str++;
1313       }
1314       if (sscanf(ptr_str, "%u", &val) == 1) {
1315         if (val != osWaitForever) {
1316           spi_xfer_timeout = val;
1317         } else {
1318           ret = EXIT_FAILURE;
1319         }
1320       } else {
1321         ret = EXIT_FAILURE;
1322       }
1323     }
1324   }
1325
1326   start_tick = osKernelGetTickCount();
1327
1328   if (ret == EXIT_SUCCESS) {
1329     // Deactivate SPI
1330     ret = SPI_Com_Configure(&spi_com_config_inactive);
1331   }
1332
1333   if ((ret == EXIT_SUCCESS) && (delay_c != 0U)) {
1334     // Delay before Control function is called
1335     (void)osDelay(delay_c);
1336   }
1337
1338   if (ret == EXIT_SUCCESS) {
1339     // Configure communication settings before transfer
1340     ret = SPI_Com_Configure(&spi_com_config_xfer);
1341   }
1342
1343   if ((ret == EXIT_SUCCESS) && (delay_t != 0U)) {
1344     // Delay before Transfer function is called
1345     (void)osDelay(delay_t);
1346   }
1347
1348   if ((ret == EXIT_SUCCESS) && 
1349       (spi_com_config_xfer.mode    == ARM_SPI_MODE_SLAVE) && 
1350       (spi_com_config_xfer.ss_mode == ARM_SPI_SS_SLAVE_SW)) {
1351     // Only for Slave transfer with Slave Select unused, 
1352     // use Software Slave Select and drive it to active state
1353     ret = SPI_Com_SS(1U);
1354   }
1355
1356   if (ret == EXIT_SUCCESS) {
1357     // Transfer data
1358     ret = SPI_Com_Transfer(ptr_spi_xfer_buf_tx, ptr_spi_xfer_buf_rx, num, spi_xfer_timeout);
1359   }
1360
1361   if ((ret == EXIT_SUCCESS) && 
1362       (spi_com_config_xfer.mode    == ARM_SPI_MODE_SLAVE) && 
1363       (spi_com_config_xfer.ss_mode == ARM_SPI_SS_SLAVE_SW)) {
1364     // Only for Slave transfer with Slave Select unused, 
1365     // use Software Slave Select and drive it to inactive state
1366     ret = SPI_Com_SS(0U);
1367   }
1368
1369   // Deactivate SPI
1370   (void)SPI_Com_Configure(&spi_com_config_inactive);
1371
1372   // Wait until timeout expires
1373   curr_tick = osKernelGetTickCount();
1374   if ((curr_tick - start_tick) < spi_xfer_timeout) {
1375     (void)osDelay(spi_xfer_timeout - (curr_tick - start_tick));
1376   }
1377
1378   // Wait additional 10 ms to insure that Client has deactivated
1379   (void)osDelay(10U);
1380
1381   // Revert communication settings to default
1382   (void)SPI_Com_Configure(&spi_com_config_default);
1383
1384   return ret;
1385 }
1386
1387 /**
1388   \fn            static int32_t SPI_Cmd_GetCnt (const char *cmd)
1389   \brief         Handle command "GET CNT".
1390   \detail        Return number of items transferred (sent/received) in last transfer 
1391                  (requested by last XFER command).
1392   \param[in]     cmd            Pointer to null-terminated command string
1393   \return        execution status
1394                    - EXIT_SUCCESS: Operation successful
1395                    - EXIT_FAILURE: Operation failed
1396 */
1397 static int32_t SPI_Cmd_GetCnt (const char *cmd) {
1398   int32_t ret;
1399
1400   (void)cmd;
1401
1402   ret = EXIT_FAILURE;
1403
1404   memset(spi_cmd_buf_tx, 0, 16);
1405   if (snprintf((char *)spi_cmd_buf_tx, 16, "%u", SPI_Com_GetCnt()) < 16) {
1406     ret = SPI_Com_Send(spi_cmd_buf_tx, BYTES_TO_ITEMS(16U, SPI_SERVER_DATA_BITS), spi_cmd_timeout);
1407   }
1408
1409   return ret;
1410 }