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