agl-service-unicens: robustess measure for tx msg
[apps/agl-service-unicens.git] / ucs2-interface / ucs_lib_interf.c
1 /*------------------------------------------------------------------------------------------------*/
2 /* UNICENS Integration Helper Component                                                           */
3 /* Copyright 2017, Microchip Technology Inc. and its subsidiaries.                                */
4 /*                                                                                                */
5 /* Redistribution and use in source and binary forms, with or without                             */
6 /* modification, are permitted provided that the following conditions are met:                    */
7 /*                                                                                                */
8 /* 1. Redistributions of source code must retain the above copyright notice, this                 */
9 /*    list of conditions and the following disclaimer.                                            */
10 /*                                                                                                */
11 /* 2. Redistributions in binary form must reproduce the above copyright notice,                   */
12 /*    this list of conditions and the following disclaimer in the documentation                   */
13 /*    and/or other materials provided with the distribution.                                      */
14 /*                                                                                                */
15 /* 3. Neither the name of the copyright holder nor the names of its                               */
16 /*    contributors may be used to endorse or promote products derived from                        */
17 /*    this software without specific prior written permission.                                    */
18 /*                                                                                                */
19 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"                    */
20 /* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE                      */
21 /* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE                 */
22 /* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE                   */
23 /* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL                     */
24 /* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR                     */
25 /* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER                     */
26 /* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,                  */
27 /* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE                  */
28 /* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                           */
29 /*------------------------------------------------------------------------------------------------*/
30 #include <assert.h>
31 #include <stdio.h>
32 #include "ucs_interface.h"
33
34 /************************************************************************/
35 /* Private Definitions and variables                                    */
36 /************************************************************************/
37 #define MAGIC (0xA144BEAF)
38
39 /************************************************************************/
40 /* Private Function Prototypes                                          */
41 /************************************************************************/
42 static bool EnqueueCommand(UCSI_Data_t *my, UnicensCmdEntry_t *cmd);
43 static void OnCommandExecuted(UCSI_Data_t *my, UnicensCmd_t cmd);
44 static void RB_Init(RB_t *rb, uint16_t amountOfEntries, uint32_t sizeOfEntry, uint8_t *workingBuffer);
45 static void *RB_GetReadPtr(RB_t *rb);
46 static void RB_PopReadPtr(RB_t *rb);
47 static void *RB_GetWritePtr(RB_t *rb);
48 static void RB_PopWritePtr(RB_t *rb);
49 static uint16_t OnUnicensGetTime(void *user_ptr);
50 static void OnUnicensService( void *user_ptr );
51 static void OnUnicensError( Ucs_Error_t error_code, void *user_ptr );
52 static void OnUnicensAppTimer( uint16_t timeout, void *user_ptr );
53 static void OnUnicensDebugErrorMsg(Msg_MostTel_t *m, void *user_ptr);
54 static void OnLldCtrlStart( Ucs_Lld_Api_t* api_ptr, void *inst_ptr, void *lld_user_ptr );
55 static void OnLldCtrlStop( void *lld_user_ptr );
56 static void OnLldCtrlRxMsgAvailable( void *lld_user_ptr );
57 static void OnLldCtrlTxTransmitC( Ucs_Lld_TxMsg_t *msg_ptr, void *lld_user_ptr );
58 static void OnUnicensRoutingResult(Ucs_Rm_Route_t* route_ptr, Ucs_Rm_RouteInfos_t route_infos, void *user_ptr);
59 static void OnUnicensNetworkStatus(uint16_t change_mask, uint16_t events, Ucs_Network_Availability_t availability,
60     Ucs_Network_AvailInfo_t avail_info, Ucs_Network_AvailTransCause_t avail_trans_cause, uint16_t node_address,
61     uint8_t node_position, uint8_t max_position, uint16_t packet_bw, void *user_ptr);
62 static void OnUnicensDebugXrmResources(Ucs_Xrm_ResourceType_t resource_type,
63     Ucs_Xrm_ResObject_t *resource_ptr, Ucs_Xrm_ResourceInfos_t resource_infos,
64     Ucs_Rm_EndPoint_t *endpoint_inst_ptr, void *user_ptr);
65 static void OnUcsInitResult(Ucs_InitResult_t result, void *user_ptr);
66 static void OnUcsStopResult(Ucs_StdResult_t result, void *user_ptr);
67 static void OnUcsGpioPortCreate(uint16_t node_address, uint16_t gpio_port_handle, Ucs_Gpio_Result_t result, void *user_ptr);
68 static void OnUcsGpioPortWrite(uint16_t node_address, uint16_t gpio_port_handle, uint16_t current_state, uint16_t sticky_state, Ucs_Gpio_Result_t result, void *user_ptr);
69 static void OnUcsMgrReport(Ucs_MgrReport_t code, uint16_t node_address, Ucs_Rm_Node_t *node_ptr, void *user_ptr);
70 static void OnUcsNsRun(Ucs_Rm_Node_t * node_ptr, Ucs_Ns_ResultCode_t result, void *ucs_user_ptr);
71 static void OnUcsAmsRxMsgReceived(void *user_ptr);
72 static void OnUcsGpioTriggerEventStatus(uint16_t node_address, uint16_t gpio_port_handle,
73     uint16_t rising_edges, uint16_t falling_edges, uint16_t levels, void * user_ptr);
74 static void OnUcsI2CWrite(uint16_t node_address, uint16_t i2c_port_handle,
75     uint8_t i2c_slave_address, uint8_t data_len, Ucs_I2c_Result_t result, void *user_ptr);
76 static void OnUcsAmsWrite(Ucs_AmsTx_Msg_t* msg_ptr, Ucs_AmsTx_Result_t result, Ucs_AmsTx_Info_t info, void *user_ptr);
77
78 /************************************************************************/
79 /* Public Function Implementations                                      */
80 /************************************************************************/
81
82 void UCSI_Init(UCSI_Data_t *my, void *pTag)
83 {
84     Ucs_Return_t result;
85     assert(NULL != my);
86     memset(my, 0, sizeof(UCSI_Data_t));
87     my->magic = MAGIC;
88     my->tag = pTag;
89     my->unicens = Ucs_CreateInstance();
90     if (NULL == my->unicens)
91     {
92         UCSI_CB_OnUserMessage(my->tag, true, "Can not instance a new version of UNICENS, "\
93             "increase UCS_NUM_INSTANCES define", 0);
94         assert(false);
95         return;
96     }
97     result = Ucs_SetDefaultConfig(&my->uniInitData);
98     if(UCS_RET_SUCCESS != result)
99     {
100         UCSI_CB_OnUserMessage(my->tag, true, "Can not set default values to UNICENS config (result=0x%X)", 1, result);
101         assert(false);
102         return;
103     }
104     my->uniInitData.user_ptr = my;
105     my->uniInitData.mgr.report_fptr = OnUcsMgrReport;
106
107     my->uniInitData.general.inic_watchdog_enabled = ENABLE_INIC_WATCHDOG;
108     my->uniInitData.general.get_tick_count_fptr = &OnUnicensGetTime;
109     my->uniInitData.general.request_service_fptr = &OnUnicensService;
110     my->uniInitData.general.error_fptr = &OnUnicensError;
111     my->uniInitData.general.set_application_timer_fptr = &OnUnicensAppTimer;
112     my->uniInitData.general.debug_error_msg_fptr = &OnUnicensDebugErrorMsg;
113     my->uniInitData.ams.enabled = ENABLE_AMS_LIB;
114     my->uniInitData.ams.rx.message_received_fptr = &OnUcsAmsRxMsgReceived;
115     my->uniInitData.network.status.notification_mask = 0xC2;
116     my->uniInitData.network.status.cb_fptr = &OnUnicensNetworkStatus;
117
118     my->uniInitData.lld.lld_user_ptr = my;
119     my->uniInitData.lld.start_fptr =  &OnLldCtrlStart;
120     my->uniInitData.lld.stop_fptr = &OnLldCtrlStop;
121     my->uniInitData.lld.rx_available_fptr = &OnLldCtrlRxMsgAvailable;
122     my->uniInitData.lld.tx_transmit_fptr = &OnLldCtrlTxTransmitC;
123
124     my->uniInitData.rm.report_fptr = &OnUnicensRoutingResult;
125     my->uniInitData.rm.debug_resource_status_fptr = &OnUnicensDebugXrmResources;
126
127     my->uniInitData.gpio.trigger_event_status_fptr = &OnUcsGpioTriggerEventStatus;
128
129     RB_Init(&my->rb, CMD_QUEUE_LEN, sizeof(UnicensCmdEntry_t), my->rbBuf);
130 }
131
132 bool UCSI_NewConfig(UCSI_Data_t *my, UcsXmlVal_t *ucsConfig) {
133
134     UnicensCmdEntry_t *e;
135     assert(MAGIC == my->magic);
136     if (my->initialized)
137     {
138         e = (UnicensCmdEntry_t *)RB_GetWritePtr(&my->rb);
139         if (NULL == e) return false;
140         e->cmd = UnicensCmd_Stop;
141         RB_PopWritePtr(&my->rb);
142     }
143     my->uniInitData.mgr.packet_bw = ucsConfig->packetBw;
144     my->uniInitData.mgr.routes_list_ptr = ucsConfig->pRoutes;
145     my->uniInitData.mgr.routes_list_size = ucsConfig->routesSize;
146     my->uniInitData.mgr.nodes_list_ptr = ucsConfig->pNod;
147     my->uniInitData.mgr.nodes_list_size = ucsConfig->nodSize;
148     my->uniInitData.mgr.enabled = true;
149     e = (UnicensCmdEntry_t *)RB_GetWritePtr(&my->rb);
150     if (NULL == e) return false;
151     e->cmd =  UnicensCmd_Init;
152     e->val.Init.init_ptr = &my->uniInitData;
153     RB_PopWritePtr(&my->rb);
154     UCSI_CB_OnServiceRequired(my->tag);
155     return true;
156 }
157
158 bool UCSI_ProcessRxData(UCSI_Data_t *my,
159     const uint8_t *pBuffer, uint16_t len)
160 {
161     Ucs_Lld_RxMsg_t *msg = NULL;
162     assert(MAGIC == my->magic);
163     if (NULL == my->uniLld || NULL == my->uniLldHPtr) return false;
164     msg = my->uniLld->rx_allocate_fptr(my->uniLldHPtr, len);
165     if (NULL == msg)
166     {
167         /*This may happen by definition, OnLldCtrlRxMsgAvailable()
168           will be called, once buffers are available again*/
169         return false;
170     }
171     msg->data_size = len;
172     memcpy(msg->data_ptr, pBuffer, len);
173     my->uniLld->rx_receive_fptr(my->uniLldHPtr, msg);
174     return true;
175 }
176
177 void UCSI_Service(UCSI_Data_t *my)
178 {
179     Ucs_Return_t ret;
180     UnicensCmdEntry_t *e;
181     bool popEntry = true; /*Set to false in specific case, where function will callback asynchrony.*/
182     assert(MAGIC == my->magic);
183     if (NULL != my->unicens && my->triggerService) {
184         my->triggerService = false;
185         Ucs_Service(my->unicens);
186     }
187     if (NULL != my->currentCmd) return;
188     my->currentCmd = e = (UnicensCmdEntry_t *)RB_GetReadPtr(&my->rb);
189     if (NULL == e) return;
190     switch (e->cmd) {
191         case UnicensCmd_Init:
192             if (UCS_RET_SUCCESS == Ucs_Init(my->unicens, e->val.Init.init_ptr, OnUcsInitResult))
193                 popEntry = false;
194             else
195                 UCSI_CB_OnUserMessage(my->tag, true, "Ucs_Init failed", 0);
196             break;
197         case UnicensCmd_Stop:
198             if (UCS_RET_SUCCESS == Ucs_Stop(my->unicens, OnUcsStopResult))
199                 popEntry = false;
200             else
201                 UCSI_CB_OnUserMessage(my->tag, true, "Ucs_Stop failed", 0);
202             break;
203         case UnicensCmd_RmSetRoute:
204             if (UCS_RET_SUCCESS != Ucs_Rm_SetRouteActive(my->unicens, e->val.RmSetRoute.routePtr, e->val.RmSetRoute.isActive))
205                 UCSI_CB_OnUserMessage(my->tag, true, "Ucs_Rm_SetRouteActive failed", 0);
206             break;
207         case UnicensCmd_NsRun:
208             if (UCS_RET_SUCCESS != Ucs_Ns_Run(my->unicens, e->val.NsRun.node_ptr, OnUcsNsRun))
209                 UCSI_CB_OnUserMessage(my->tag, true, "Ucs_Ns_Run failed", 0);
210             break;
211         case UnicensCmd_GpioCreatePort:
212             if (UCS_RET_SUCCESS == Ucs_Gpio_CreatePort(my->unicens, e->val.GpioCreatePort.destination, 0, e->val.GpioCreatePort.debounceTime, OnUcsGpioPortCreate))
213                 popEntry = false;
214             else
215                 UCSI_CB_OnUserMessage(my->tag, true, "Ucs_Gpio_CreatePort failed", 0);
216             break;
217         case UnicensCmd_GpioWritePort:
218             if (UCS_RET_SUCCESS == Ucs_Gpio_WritePort(my->unicens, e->val.GpioWritePort.destination, 0x1D00, e->val.GpioWritePort.mask, e->val.GpioWritePort.data, OnUcsGpioPortWrite))
219                 popEntry = false;
220             else
221                 UCSI_CB_OnUserMessage(my->tag, true, "UnicensCmd_GpioWritePort failed", 0);
222             break;
223         case UnicensCmd_I2CWrite:
224             ret = Ucs_I2c_WritePort(my->unicens, e->val.I2CWrite.destination, 0x0F00,
225                 (e->val.I2CWrite.isBurst ? UCS_I2C_BURST_MODE : UCS_I2C_DEFAULT_MODE), e->val.I2CWrite.blockCount,
226                 e->val.I2CWrite.slaveAddr, e->val.I2CWrite.timeout, e->val.I2CWrite.dataLen, e->val.I2CWrite.data, OnUcsI2CWrite);
227             if (UCS_RET_SUCCESS == ret)
228                 popEntry = false;
229             else {
230                 UCSI_CB_OnUserMessage(my->tag, true, "Ucs_I2c_WritePort failed ret=%d", 1, ret);
231                 assert(e->val.I2CWrite.result_fptr != NULL);
232                 e->val.I2CWrite.result_fptr(NULL /*processing error*/, e->val.I2CWrite.request_ptr);
233             }
234             break;
235         case UnicensCmd_SendAmsMessage:
236         {
237             Ucs_AmsTx_Msg_t *msg;
238             msg = Ucs_AmsTx_AllocMsg(my->unicens, e->val.SendAms.payloadLen);
239             if (NULL == msg)
240             {
241                 /* Try again later */
242                 popEntry = false;
243                 break;
244             }
245             if (0 != e->val.SendAms.payloadLen)
246             {
247                 assert(NULL != msg->data_ptr);
248                 memcpy(msg->data_ptr, e->val.SendAms.pPayload, e->val.SendAms.payloadLen);
249             }
250             msg->custom_info_ptr = NULL;
251             msg->data_size = e->val.SendAms.payloadLen;
252             msg->destination_address = e->val.SendAms.targetAddress;
253             msg->llrbc = 10;
254             msg->msg_id = e->val.SendAms.msgId;
255             if (UCS_RET_SUCCESS == Ucs_AmsTx_SendMsg(my->unicens, msg, OnUcsAmsWrite))
256             {
257                 popEntry = false;
258             }
259             else
260             {
261                 Ucs_AmsTx_FreeUnusedMsg(my->unicens, msg);
262                 UCSI_CB_OnUserMessage(my->tag, true, "Ucs_AmsTx_SendMsg failed", 0);
263             }
264             break;
265         }
266         default:
267             assert(false);
268             break;
269     }
270     if (popEntry)
271     {
272         my->currentCmd = NULL;
273         RB_PopReadPtr(&my->rb);
274     }
275 }
276
277 void UCSI_Timeout(UCSI_Data_t *my)
278 {
279     assert(MAGIC == my->magic);
280     if (NULL == my->unicens) return;
281     Ucs_ReportTimeout(my->unicens);
282 }
283
284 bool UCSI_SendAmsMessage(UCSI_Data_t *my, uint16_t msgId, uint16_t targetAddress, uint8_t *pPayload, uint32_t payloadLen)
285 {
286     UnicensCmdEntry_t entry;
287     assert(MAGIC == my->magic);
288     if (NULL == my) return false;
289     if (payloadLen > UCS_AMS_SIZE_TX_MSG)
290     {
291         UCSI_CB_OnUserMessage(my->tag, true, "SendAms was called with payload length=%d, allowed is=%d", 2, payloadLen, UCS_AMS_SIZE_TX_MSG);
292         return false;
293     }
294     entry.cmd = UnicensCmd_SendAmsMessage;
295     entry.val.SendAms.msgId = msgId;
296     entry.val.SendAms.targetAddress = targetAddress;
297     entry.val.SendAms.payloadLen = payloadLen;
298     memcpy(entry.val.SendAms.pPayload, pPayload, payloadLen);
299     return EnqueueCommand(my, &entry);
300 }
301
302 bool UCSI_GetAmsMessage(UCSI_Data_t *my, uint16_t *pMsgId, uint16_t *pSourceAddress, uint8_t **pPayload, uint32_t *pPayloadLen)
303 {
304     Ucs_AmsRx_Msg_t *msg;
305     assert(MAGIC == my->magic);
306     if (NULL == my->unicens || NULL == pPayload || NULL == pPayloadLen) return false;
307     msg = Ucs_AmsRx_PeekMsg(my->unicens);
308     if (NULL == msg) return false;
309     *pMsgId = msg->msg_id;
310     *pSourceAddress = msg->source_address;
311     *pPayload = msg->data_ptr;
312     *pPayloadLen = msg->data_size;
313     return true;
314 }
315
316 void UCSI_ReleaseAmsMessage(UCSI_Data_t *my)
317 {
318     assert(MAGIC == my->magic);
319     if (NULL == my->unicens) return;
320     Ucs_AmsRx_ReleaseMsg(my->unicens);
321 }
322
323 bool UCSI_SetRouteActive(UCSI_Data_t *my, uint16_t routeId, bool isActive)
324 {
325     uint16_t i;
326     UnicensCmdEntry_t entry;
327     assert(MAGIC == my->magic);
328     if (NULL == my || NULL == my->uniInitData.mgr.routes_list_ptr) return false;
329     for (i = 0; i < my->uniInitData.mgr.routes_list_size; i++)
330     {
331         Ucs_Rm_Route_t *route = &my->uniInitData.mgr.routes_list_ptr[i];
332         if (route->route_id != routeId)
333             continue;
334         entry.cmd = UnicensCmd_RmSetRoute;
335         entry.val.RmSetRoute.routePtr = route;
336         entry.val.RmSetRoute.isActive = isActive;
337         return EnqueueCommand(my, &entry);
338     }
339     return false;
340 }
341
342 bool UCSI_I2CWrite(UCSI_Data_t *my, uint16_t targetAddress, bool isBurst, uint8_t blockCount,
343     uint8_t slaveAddr, uint16_t timeout, uint8_t dataLen, uint8_t *pData,
344     Ucsi_ResultCb_t result_fptr, void *request_ptr)
345 {
346     UnicensCmdEntry_t entry;
347     assert(MAGIC == my->magic);
348     if (NULL == my || NULL == pData || 0 == dataLen) return false;
349     if (dataLen > I2C_WRITE_MAX_LEN) return false;
350     entry.cmd = UnicensCmd_I2CWrite;
351     entry.val.I2CWrite.destination = targetAddress;
352     entry.val.I2CWrite.isBurst = isBurst;
353     entry.val.I2CWrite.blockCount = blockCount;
354     entry.val.I2CWrite.slaveAddr = slaveAddr;
355     entry.val.I2CWrite.timeout = timeout;
356     entry.val.I2CWrite.dataLen = dataLen;
357     entry.val.I2CWrite.result_fptr = result_fptr;
358     entry.val.I2CWrite.request_ptr = request_ptr;
359     memcpy(entry.val.I2CWrite.data, pData, dataLen);
360     return EnqueueCommand(my, &entry);
361 }
362
363 bool UCSI_SetGpioState(UCSI_Data_t *my, uint16_t targetAddress, uint8_t gpioPinId, bool isHighState)
364 {
365     uint16_t mask;
366     UnicensCmdEntry_t entry;
367     assert(MAGIC == my->magic);
368     if (NULL == my) return false;
369     mask = 1 << gpioPinId;
370     entry.cmd = UnicensCmd_GpioWritePort;
371     entry.val.GpioWritePort.destination = targetAddress;
372     entry.val.GpioWritePort.mask = mask;
373     entry.val.GpioWritePort.data = isHighState ? mask : 0;
374     return EnqueueCommand(my, &entry);
375 }
376
377 /************************************************************************/
378 /* Private Functions                                                    */
379 /************************************************************************/
380 static bool EnqueueCommand(UCSI_Data_t *my, UnicensCmdEntry_t *cmd)
381 {
382     UnicensCmdEntry_t *e;
383     if (NULL == my || NULL == cmd)
384     {
385         assert(false);
386         return false;
387     }
388     e = RB_GetWritePtr(&my->rb);
389     if (NULL == e)
390     {
391         UCSI_CB_OnUserMessage(my->tag, true, "Could not enqueue command. Increase CMD_QUEUE_LEN define", 0);
392         return false;
393     }
394     memcpy(e, cmd, sizeof(UnicensCmdEntry_t));
395     RB_PopWritePtr(&my->rb);
396     UCSI_CB_OnServiceRequired(my->tag);
397     return true;
398 }
399
400 static void OnCommandExecuted(UCSI_Data_t *my, UnicensCmd_t cmd)
401 {
402     if (NULL == my)
403     {
404         assert(false);
405         return;
406     }
407     if (NULL == my->currentCmd)
408     {
409         UCSI_CB_OnUserMessage(my->tag, true, "OnUniCommandExecuted was called, but no "\
410             "command is in queue", 0);
411         assert(false);
412         return;
413     }
414     if (my->currentCmd->cmd != cmd)
415     {
416         UCSI_CB_OnUserMessage(my->tag, true, "OnUniCommandExecuted was called with "\
417             "wrong command (Expected=0x%X, Got=0x%X", 2, my->currentCmd->cmd, cmd);
418         assert(false);
419         return;
420     }
421     my->currentCmd = NULL;
422     RB_PopReadPtr(&my->rb);
423 }
424
425 static void RB_Init(RB_t *rb, uint16_t amountOfEntries, uint32_t sizeOfEntry, uint8_t *workingBuffer)
426 {
427     assert(NULL != rb);
428     assert(NULL != workingBuffer);
429     rb->dataQueue = workingBuffer;
430     rb->pRx = rb->dataQueue;
431     rb->pTx = rb->dataQueue;
432     rb->amountOfEntries = amountOfEntries;
433     rb->sizeOfEntry = sizeOfEntry;
434     rb->rxPos = 0;
435     rb->txPos = 0;
436 }
437
438 static void *RB_GetReadPtr(RB_t *rb)
439 {
440     assert(NULL != rb);
441     assert(0 != rb->dataQueue);
442     if (rb->txPos - rb->rxPos > 0)
443     return (void *)rb->pRx;
444     return NULL;
445 }
446
447 static void RB_PopReadPtr(RB_t *rb)
448 {
449     assert(NULL != rb);
450     assert(0 != rb->dataQueue);
451
452     rb->pRx += rb->sizeOfEntry;
453     if (rb->pRx >= rb->dataQueue + ( rb->amountOfEntries * rb->sizeOfEntry))
454     rb->pRx = rb->dataQueue;
455     ++rb->rxPos;
456     assert(rb->txPos >= rb->rxPos);
457 }
458
459 static void *RB_GetWritePtr(RB_t *rb)
460 {
461     assert(NULL != rb);
462     assert(0 != rb->dataQueue);
463     if (rb->txPos - rb->rxPos < rb->amountOfEntries)
464     return (void *)rb->pTx;
465     return NULL;
466 }
467
468 static void RB_PopWritePtr(RB_t *rb)
469 {
470     assert(NULL != rb);
471     assert(0 != rb->dataQueue);
472     rb->pTx += rb->sizeOfEntry;
473     if (rb->pTx >= rb->dataQueue + ( rb->amountOfEntries * rb->sizeOfEntry))
474     rb->pTx = rb->dataQueue;
475     ++rb->txPos;
476     assert(rb->txPos >= rb->rxPos);
477 }
478
479 static uint16_t OnUnicensGetTime(void *user_ptr)
480 {
481     UCSI_Data_t *my = (UCSI_Data_t *)user_ptr;
482     assert(MAGIC == my->magic);
483     return UCSI_CB_OnGetTime(my->tag);
484 }
485
486 static void OnUnicensService( void *user_ptr )
487 {
488     UCSI_Data_t *my = (UCSI_Data_t *)user_ptr;
489     assert(MAGIC == my->magic);
490     my->triggerService = true;
491     UCSI_CB_OnServiceRequired(my->tag);
492 }
493
494 static void OnUnicensError( Ucs_Error_t error_code, void *user_ptr )
495 {
496     UnicensCmdEntry_t e;
497     UCSI_Data_t *my = (UCSI_Data_t *)user_ptr;
498     error_code = error_code;
499     assert(MAGIC == my->magic);
500     UCSI_CB_OnUserMessage(my->tag, true, "UNICENS general error, code=0x%X, restarting", 1, error_code);
501     e.cmd = UnicensCmd_Init;
502     e.val.Init.init_ptr = &my->uniInitData;
503     EnqueueCommand(my, &e);
504 }
505
506 static void OnUnicensAppTimer( uint16_t timeout, void *user_ptr )
507 {
508     UCSI_Data_t *my = (UCSI_Data_t *)user_ptr;
509     assert(MAGIC == my->magic);
510     UCSI_CB_OnSetServiceTimer(my->tag, timeout);
511 }
512
513 static void OnUnicensDebugErrorMsg(Msg_MostTel_t *m, void *user_ptr)
514 {
515     char buffer[100];
516     char val[5];
517     uint8_t i;
518     UCSI_Data_t *my = (UCSI_Data_t *)user_ptr;
519     assert(MAGIC == my->magic);
520     buffer[0] = '\0';
521     for (i = 0; NULL != m->tel.tel_data_ptr && i < m->tel.tel_len; i++)
522     {
523         snprintf(val, sizeof(val), "%02X ", m->tel.tel_data_ptr[i]);
524         strcat(buffer, val);
525     }
526     UCSI_CB_OnUserMessage(my->tag, true, "Received error message, source=%x, %X.%X.%X.%X, [ %s ]",
527         6, m->source_addr, m->id.fblock_id, m->id.instance_id,
528         m->id.function_id, m->id.op_type, buffer);
529 }
530
531 static void OnLldCtrlStart( Ucs_Lld_Api_t* api_ptr, void *inst_ptr, void *lld_user_ptr )
532 {
533     UCSI_Data_t *my = (UCSI_Data_t *)lld_user_ptr;
534     assert(MAGIC == my->magic);
535     my->uniLld = api_ptr;
536     my->uniLldHPtr = inst_ptr;
537 }
538
539 static void OnLldCtrlStop( void *lld_user_ptr )
540 {
541     UCSI_Data_t *my = (UCSI_Data_t *)lld_user_ptr;
542     assert(MAGIC == my->magic);
543     my->uniLld = NULL;
544     my->uniLldHPtr = NULL;
545 }
546
547 static void OnLldCtrlRxMsgAvailable( void *lld_user_ptr )
548 {
549     UCSI_Data_t *my = (UCSI_Data_t *)lld_user_ptr;
550     assert(MAGIC == my->magic);
551     UCSI_CB_OnServiceRequired(my->tag);
552 }
553
554 static void OnLldCtrlTxTransmitC( Ucs_Lld_TxMsg_t *msg_ptr, void *lld_user_ptr )
555 {
556     UCSI_Data_t *my;
557     Ucs_Mem_Buffer_t * buf_ptr;
558     uint8_t buffer[BOARD_PMS_TX_SIZE];
559     uint32_t bufferPos = 0;
560     my = (UCSI_Data_t *)lld_user_ptr;
561     assert(MAGIC == my->magic);
562     if (NULL == msg_ptr || NULL == my || NULL == my->uniLld || NULL == my->uniLldHPtr)
563     {
564         assert(false);
565         return;
566     }
567     for (buf_ptr = msg_ptr->memory_ptr; buf_ptr != NULL; buf_ptr = buf_ptr->next_buffer_ptr)
568     {
569         if (buf_ptr->data_size + bufferPos > sizeof(buffer))
570         {
571             UCSI_CB_OnUserMessage(my->tag, true, "TX buffer is too small, increase " \
572                 "BOARD_PMS_TX_SIZE define (%lu > %lu)", 2, buf_ptr->data_size + bufferPos, sizeof(buffer));
573             my->uniLld->tx_release_fptr(my->uniLldHPtr, msg_ptr);
574             return;
575         }
576         memcpy(&buffer[bufferPos], buf_ptr->data_ptr, buf_ptr->data_size);
577         bufferPos += buf_ptr->data_size;
578     }
579     assert(bufferPos == msg_ptr->memory_ptr->total_size);
580     my->uniLld->tx_release_fptr(my->uniLldHPtr, msg_ptr);
581     UCSI_CB_OnTxRequest(my->tag, buffer, bufferPos);
582 }
583
584 static void OnUnicensRoutingResult(Ucs_Rm_Route_t* route_ptr, Ucs_Rm_RouteInfos_t route_infos, void *user_ptr)
585 {
586     uint16_t conLabel;
587     UCSI_Data_t *my = (UCSI_Data_t *)user_ptr;
588     assert(MAGIC == my->magic);
589     conLabel = Ucs_Rm_GetConnectionLabel(my->unicens, route_ptr);
590     UCSI_CB_OnRouteResult(my->tag, route_ptr->route_id, UCS_RM_ROUTE_INFOS_BUILT == route_infos, conLabel);
591 }
592
593 static void OnUnicensNetworkStatus(uint16_t change_mask, uint16_t events, Ucs_Network_Availability_t availability,
594     Ucs_Network_AvailInfo_t avail_info, Ucs_Network_AvailTransCause_t avail_trans_cause, uint16_t node_address,
595     uint8_t node_position, uint8_t max_position, uint16_t packet_bw, void *user_ptr)
596 {
597     UCSI_Data_t *my = (UCSI_Data_t *)user_ptr;
598     assert(MAGIC == my->magic);
599     UCSI_CB_OnNetworkState(my->tag, UCS_NW_AVAILABLE == availability, packet_bw, max_position);
600 }
601
602 static void OnUnicensDebugXrmResources(Ucs_Xrm_ResourceType_t resource_type,
603     Ucs_Xrm_ResObject_t *resource_ptr, Ucs_Xrm_ResourceInfos_t resource_infos,
604     Ucs_Rm_EndPoint_t *endpoint_inst_ptr, void *user_ptr)
605 {
606     char *msg = NULL;
607     UCSI_Data_t *my;
608     uint16_t adr = 0xFFFF;
609 #ifndef DEBUG_XRM
610     resource_type = resource_type;
611     resource_ptr = resource_ptr;
612     resource_infos = resource_infos;
613     endpoint_inst_ptr = endpoint_inst_ptr;
614     user_ptr = user_ptr;
615 #else
616     endpoint_inst_ptr = endpoint_inst_ptr;
617     my = (UCSI_Data_t *)user_ptr;
618     assert(MAGIC == my->magic);
619     if (NULL == resource_ptr) return;
620     if (endpoint_inst_ptr && endpoint_inst_ptr->node_obj_ptr &&
621             endpoint_inst_ptr->node_obj_ptr->signature_ptr)
622         adr = endpoint_inst_ptr->node_obj_ptr->signature_ptr->node_address;
623     switch (resource_infos)
624     {
625         case UCS_XRM_INFOS_BUILT:
626         msg = (char *)"has been built";
627         break;
628         case UCS_XRM_INFOS_DESTROYED:
629         msg = (char *)"has been destroyed";
630         break;
631         case UCS_XRM_INFOS_ERR_BUILT:
632         msg = (char *)"cannot be built";
633         break;
634         default:
635         msg = (char *)"cannot be destroyed";
636         break;
637     }
638     switch(resource_type)
639     {
640         case UCS_XRM_RC_TYPE_MOST_SOCKET:
641         {
642             Ucs_Xrm_MostSocket_t *ms = (Ucs_Xrm_MostSocket_t *)resource_ptr;
643             assert(ms->resource_type == resource_type);
644             UCSI_CB_OnUserMessage(my->tag, false, "Xrm-Debug (0x%03X): MOST socket %s, handle=%04X, "\
645                 "direction=%d, type=%d, bandwidth=%d", 6, adr, msg, ms->most_port_handle,
646                 ms->direction, ms->data_type, ms->bandwidth);
647             break;
648         }
649         case UCS_XRM_RC_TYPE_MLB_PORT:
650         {
651             Ucs_Xrm_MlbPort_t *m = (Ucs_Xrm_MlbPort_t *)resource_ptr;
652             assert(m->resource_type == resource_type);
653             UCSI_CB_OnUserMessage(my->tag, false, "Xrm-Debug (0x%03X): MLB port %s, index=%d, clock=%d", 4,
654                 adr, msg, m->index, m->clock_config);
655             break;
656         }
657         case UCS_XRM_RC_TYPE_MLB_SOCKET:
658         {
659             Ucs_Xrm_MlbSocket_t *m = (Ucs_Xrm_MlbSocket_t *)resource_ptr;
660             assert(m->resource_type == resource_type);
661             UCSI_CB_OnUserMessage(my->tag, false, "Xrm-Debug (0x%03X): MLB socket %s, direction=%d, type=%d,"\
662                 " bandwidth=%d, channel=%d", 6, adr, msg, m->direction, m->data_type,
663                 m->bandwidth, m->channel_address);
664             break;
665         }
666         case UCS_XRM_RC_TYPE_USB_PORT:
667         {
668             Ucs_Xrm_UsbPort_t *m = (Ucs_Xrm_UsbPort_t *)resource_ptr;
669             assert(m->resource_type == resource_type);
670             UCSI_CB_OnUserMessage(my->tag, false, "Xrm-Debug (0x%03X): USB port %s, in-cnt=%d, out-cnt=%d", 4,
671                 adr, msg, m->streaming_if_ep_in_count, m->streaming_if_ep_out_count);
672             break;
673         }
674         case UCS_XRM_RC_TYPE_USB_SOCKET:
675         {
676             Ucs_Xrm_UsbSocket_t *m = (Ucs_Xrm_UsbSocket_t *)resource_ptr;
677             assert(m->resource_type == resource_type);
678             UCSI_CB_OnUserMessage(my->tag, false, "Xrm-Debug (0x%03X): USB socket %s, direction=%d, type=%d," \
679                 " ep-addr=%02X, frames=%d", 6, adr, msg, m->direction, m->data_type,
680                 m->end_point_addr, m->frames_per_transfer);
681             break;
682         }
683         case UCS_XRM_RC_TYPE_STRM_PORT:
684         {
685             Ucs_Xrm_StrmPort_t *m = (Ucs_Xrm_StrmPort_t *)resource_ptr;
686             assert(m->resource_type == resource_type);
687             UCSI_CB_OnUserMessage(my->tag, false, "Xrm-Debug (0x%03X): I2S port %s, index=%d, clock=%d, "\
688                 "align=%d", 5, adr, msg, m->index, m->clock_config, m->data_alignment);
689             break;
690         }
691         case UCS_XRM_RC_TYPE_STRM_SOCKET:
692         {
693             Ucs_Xrm_StrmSocket_t *m = (Ucs_Xrm_StrmSocket_t *)resource_ptr;
694             assert(m->resource_type == resource_type);
695             UCSI_CB_OnUserMessage(my->tag, false, "Xrm-Debug (0x%03X): I2S socket %s, direction=%d, type=%d"\
696                 ", bandwidth=%d, pin=%d", 6, adr, msg, m->direction, m->data_type,
697                 m->bandwidth, m->stream_pin_id);
698             break;
699         }
700         case UCS_XRM_RC_TYPE_SYNC_CON:
701         {
702             Ucs_Xrm_SyncCon_t *m = (Ucs_Xrm_SyncCon_t *)resource_ptr;
703             assert(m->resource_type == resource_type);
704             UCSI_CB_OnUserMessage(my->tag, false, "Xrm-Debug (0x%03X): Sync connection %s, mute=%d, "\
705                 "offset=%d", 4, adr, msg, m->mute_mode, m->offset);
706             break;
707         }
708         case UCS_XRM_RC_TYPE_COMBINER:
709         {
710             Ucs_Xrm_Combiner_t *m = (Ucs_Xrm_Combiner_t *)resource_ptr;
711             assert(m->resource_type == resource_type);
712             UCSI_CB_OnUserMessage(my->tag, false, "Xrm-Debug (0x%03X): Combiner %s, bytes per frame=%d",
713                 3, adr, msg, m->bytes_per_frame);
714             break;
715         }
716         case UCS_XRM_RC_TYPE_SPLITTER:
717         {
718             Ucs_Xrm_Splitter_t *m = (Ucs_Xrm_Splitter_t *)resource_ptr;
719             assert(m->resource_type == resource_type);
720             UCSI_CB_OnUserMessage(my->tag, false, "Xrm-Debug (0x%03X): Splitter %s, bytes per frame=%d",
721                 3, adr, msg, m->bytes_per_frame);
722             break;
723         }
724         case UCS_XRM_RC_TYPE_AVP_CON:
725         {
726             Ucs_Xrm_AvpCon_t *m = (Ucs_Xrm_AvpCon_t *)resource_ptr;
727             assert(m->resource_type == resource_type);
728             UCSI_CB_OnUserMessage(my->tag, false, "Xrm-Debug (0x%03X): Isoc-AVP connection %s, packetSize=%d",
729                 3, adr, msg, m->isoc_packet_size);
730             break;
731         }
732         default:
733         UCSI_CB_OnUserMessage(my->tag, true, "Xrm-Debug (0x%03X): Unknown type=%d %s", 3 , adr, resource_type, msg);
734     }
735 #endif
736 }
737
738 static void OnUcsInitResult(Ucs_InitResult_t result, void *user_ptr)
739 {
740     UnicensCmdEntry_t e;
741     UCSI_Data_t *my = (UCSI_Data_t *)user_ptr;
742     assert(MAGIC == my->magic);
743     my->initialized = (UCS_INIT_RES_SUCCESS == result);
744     OnCommandExecuted(my, UnicensCmd_Init);
745     if (!my->initialized)
746     {
747         UCSI_CB_OnUserMessage(my->tag, true, "UcsInitResult reported error (0x%X), restarting...", 1, result);
748         e.cmd = UnicensCmd_Init;
749         e.val.Init.init_ptr = &my->uniInitData;
750         EnqueueCommand(my, &e);
751     }
752 }
753
754 static void OnUcsStopResult(Ucs_StdResult_t result, void *user_ptr)
755 {
756     UCSI_Data_t *my = (UCSI_Data_t *)user_ptr;
757     result = result; /*TODO: check error case*/
758     assert(MAGIC == my->magic);
759     my->initialized = false;
760     OnCommandExecuted(my, UnicensCmd_Stop);
761     UCSI_CB_OnStop(my->tag);
762 }
763
764 static void OnUcsGpioPortCreate(uint16_t node_address, uint16_t gpio_port_handle, Ucs_Gpio_Result_t result, void *user_ptr)
765 {
766     UCSI_Data_t *my = (UCSI_Data_t *)user_ptr;
767     assert(MAGIC == my->magic);
768     OnCommandExecuted(my, UnicensCmd_GpioCreatePort);
769 }
770
771 static void OnUcsGpioPortWrite(uint16_t node_address, uint16_t gpio_port_handle, uint16_t current_state, uint16_t sticky_state, Ucs_Gpio_Result_t result, void *user_ptr)
772 {
773     UCSI_Data_t *my = (UCSI_Data_t *)user_ptr;
774     assert(MAGIC == my->magic);
775     OnCommandExecuted(my, UnicensCmd_GpioWritePort);
776 }
777
778 static void OnUcsMgrReport(Ucs_MgrReport_t code, uint16_t node_address, Ucs_Rm_Node_t *node_ptr, void *user_ptr)
779 {
780     UCSI_Data_t *my = (UCSI_Data_t *)user_ptr;
781     assert(MAGIC == my->magic);
782     switch (code)
783     {
784     case UCS_MGR_REP_IGNORED_UNKNOWN:
785         UCSI_CB_OnUserMessage(my->tag, false, "Node=%X: Ignored, because unknown", 1, node_address);
786         break;
787     case UCS_MGR_REP_IGNORED_DUPLICATE:
788         UCSI_CB_OnUserMessage(my->tag, true, "Node=%X: Ignored, because duplicated", 1, node_address);
789         break;
790     case UCS_MGR_REP_AVAILABLE:
791     {
792         UnicensCmdEntry_t e;
793         UCSI_CB_OnUserMessage(my->tag, false, "Node=%X: Available", 1, node_address);
794         /* Execute scripts, if there are any */
795         if (node_ptr && node_ptr->script_list_ptr && node_ptr->script_list_size)
796         {
797             e.cmd = UnicensCmd_NsRun;
798             e.val.NsRun.node_ptr = node_ptr;
799             EnqueueCommand(my, &e);
800         }
801         break;
802     }
803     case UCS_MGR_REP_NOT_AVAILABLE:
804         UCSI_CB_OnUserMessage(my->tag, false, "Node=%X: Not available", 1, node_address);
805         break;
806     default:
807         UCSI_CB_OnUserMessage(my->tag, true, "Node=%X: unknown code", 1, node_address);
808         break;
809     }
810
811     UCSI_CB_OnMgrReport(my->tag, code, node_address, node_ptr);
812 }
813
814 static void OnUcsNsRun(Ucs_Rm_Node_t * node_ptr, Ucs_Ns_ResultCode_t result, void *ucs_user_ptr)
815 {
816     UCSI_Data_t *my;
817 #ifndef DEBUG_XRM
818     node_ptr = node_ptr;
819     result = result;
820     ucs_user_ptr;
821 #else
822     my = (UCSI_Data_t *)ucs_user_ptr;
823     assert(MAGIC == my->magic);
824     UCSI_CB_OnUserMessage(my->tag, false, "OnUcsNsRun (%03X): script executed %s",
825         2, node_ptr->signature_ptr->node_address,
826         (UCS_NS_RES_SUCCESS == result ? "succeeded" : "false"));
827 #endif
828 }
829
830 static void OnUcsAmsRxMsgReceived(void *user_ptr)
831 {
832     UCSI_Data_t *my = (UCSI_Data_t *)user_ptr;
833     assert(MAGIC == my->magic);
834     UCSI_CB_OnAmsMessageReceived(my->tag);
835 }
836
837 static void OnUcsGpioTriggerEventStatus(uint16_t node_address, uint16_t gpio_port_handle,
838     uint16_t rising_edges, uint16_t falling_edges, uint16_t levels, void * user_ptr)
839 {
840     uint8_t i;
841     UCSI_Data_t *my = (UCSI_Data_t *)user_ptr;
842     assert(MAGIC == my->magic);
843     for (i = 0; i < 16; i++)
844     {
845         if (0 != ((rising_edges >> i) & 0x1))
846             UCSI_CB_OnGpioStateChange(my->tag, node_address, i, true);
847         if (0 != ((falling_edges >> i) & 0x1))
848             UCSI_CB_OnGpioStateChange(my->tag, node_address, i, false);
849     }
850 }
851
852 static void OnUcsI2CWrite(uint16_t node_address, uint16_t i2c_port_handle,
853     uint8_t i2c_slave_address, uint8_t data_len, Ucs_I2c_Result_t result, void *user_ptr)
854 {
855     UCSI_Data_t *my = (UCSI_Data_t *)user_ptr;
856     assert(MAGIC == my->magic);
857
858     if ((my->currentCmd->cmd == UnicensCmd_I2CWrite)
859         && (my->currentCmd->val.I2CWrite.result_fptr)) {
860
861         my->currentCmd->val.I2CWrite.result_fptr(&result.code, my->currentCmd->val.I2CWrite.request_ptr);
862     }
863     else {
864         assert(false);
865     }
866
867     OnCommandExecuted(my, UnicensCmd_I2CWrite);
868     if (UCS_I2C_RES_SUCCESS != result.code)
869         UCSI_CB_OnUserMessage(my->tag, true, "Remote I2C Write to node=0x%X failed", 1, node_address);
870 }
871
872 static void OnUcsAmsWrite(Ucs_AmsTx_Msg_t* msg_ptr, Ucs_AmsTx_Result_t result, Ucs_AmsTx_Info_t info, void *user_ptr)
873 {
874     UCSI_Data_t *my = (UCSI_Data_t *)user_ptr;
875     assert(MAGIC == my->magic);
876     OnCommandExecuted(my, UnicensCmd_SendAmsMessage);
877     if (UCS_AMSTX_RES_SUCCESS != result)
878         UCSI_CB_OnUserMessage(my->tag, true, "SendAms failed with result=0x%x, info=0x%X", 2, result, info);
879 }
880
881 /************************************************************************/
882 /* Debug Message output from UNICENS stack:                             */
883 /************************************************************************/
884 #if defined(UCS_TR_ERROR) || defined(UCS_TR_INFO)
885 #include <stdio.h>
886 #define TRACE_BUFFER_SZ 200
887 void App_TraceError(void *ucs_user_ptr, const char module_str[], const char entry_str[], uint16_t vargs_cnt, ...)
888 {
889     va_list argptr;
890     char outbuf[TRACE_BUFFER_SZ];
891     void *tag = NULL;
892     UCSI_Data_t *my = (UCSI_Data_t *)ucs_user_ptr;
893     if (my)
894     {
895         assert(MAGIC == my->magic);
896         tag = my->tag;
897     }
898     va_start(argptr, vargs_cnt);
899     vsnprintf(outbuf, sizeof(outbuf), entry_str, argptr);
900     va_end(argptr);
901     UCSI_CB_OnUserMessage(tag, true, "Error | %s | %s", 2, module_str, outbuf);
902 }
903
904 void App_TraceInfo(void *ucs_user_ptr, const char module_str[], const char entry_str[], uint16_t vargs_cnt, ...)
905 {
906     va_list argptr;
907     char outbuf[TRACE_BUFFER_SZ];
908     void *tag = NULL;
909     UCSI_Data_t *my = (UCSI_Data_t *)ucs_user_ptr;
910     if (my)
911     {
912         assert(MAGIC == my->magic);
913         tag = my->tag;
914     }
915     va_start(argptr, vargs_cnt);
916     vsnprintf(outbuf, sizeof(outbuf), entry_str, argptr);
917     va_end(argptr);
918     UCSI_CB_OnUserMessage(tag, false, "Info | %s | %s", 2, module_str, outbuf);
919 }
920 #endif