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