1/*
2 * Copyright (c) 2007-2015 Freescale Semiconductor, Inc.
3 * Copyright 2018-2020 NXP
4 *
5 * License: NXP LA_OPT_NXP_Software_License
6 *
7 * NXP Confidential. This software is owned or controlled by NXP and may
8 * only be used strictly in accordance with the applicable license terms.
9 * By expressly accepting such terms or by downloading, installing,
10 * activating and/or otherwise using the software, you are agreeing that
11 * you have read, and that you agree to comply with and are bound by,
12 * such license terms. If you do not agree to be bound by the applicable
13 * license terms, then you may not retain, install, activate or otherwise
14 * use the software. This code may only be used in a microprocessor,
15 * microcontroller, sensor or digital signal processor ("NXP Product")
16 * supplied directly or indirectly from NXP. See the full NXP Software
17 * License Agreement in license/LA_OPT_NXP_Software_License.pdf
18 *
19 * FreeMASTER Communication Driver - Application Commands handling
20 */
21
22#include "freemaster.h"
23#include "freemaster_private.h"
24#include "freemaster_protocol.h"
25
26#if FMSTR_USE_APPCMD > 0 && FMSTR_DISABLE == 0
27
28/***********************************
29 * local variables
30 ***********************************/
31
32static FMSTR_APPCMD_CODE fmstr_appCmd; /* app.cmd code (to application) */
33static FMSTR_APPCMD_DATA fmstr_appCmdBuff[FMSTR_APPCMD_BUFF_SIZE]; /* app.cmd data buffer */
34static FMSTR_SIZE fmstr_appCmdLen; /* app.cmd data length */
35
36static FMSTR_APPCMD_RESULT fmstr_appCmdResult; /* app.cmd result code (from application) */
37static FMSTR_SIZE8 fmstr_appCmdResultDataLen;
38
39#if FMSTR_MAX_APPCMD_CALLS > 0
40static FMSTR_APPCMD_CODE fmstr_appCmdCallId[FMSTR_MAX_APPCMD_CALLS]; /* registered callback commands */
41static FMSTR_PAPPCMDFUNC fmstr_appCmdCallFunc[FMSTR_MAX_APPCMD_CALLS]; /* registered callback handlers */
42#endif
43
44/***********************************
45 * local functions
46 ***********************************/
47
48static FMSTR_INDEX FMSTR_FindAppCmdCallIndex(FMSTR_APPCMD_CODE appCmdCode);
49
50/******************************************************************************
51 *
52 * @brief Initialize app.cmds interface
53 *
54 ******************************************************************************/
55
56FMSTR_BOOL FMSTR_InitAppCmds(void)
57{
58#if FMSTR_MAX_APPCMD_CALLS > 0
59 FMSTR_INDEX i;
60
61 for (i = 0; i < FMSTR_MAX_APPCMD_CALLS; i++)
62 {
63 fmstr_appCmdCallId[i] = FMSTR_APPCMDRESULT_NOCMD;
64 fmstr_appCmdCallFunc[i] = NULL;
65 }
66#endif
67
68 fmstr_appCmd = (FMSTR_APPCMD_CODE)FMSTR_APPCMDRESULT_NOCMD;
69 fmstr_appCmdResult = (FMSTR_APPCMD_RESULT)FMSTR_APPCMDRESULT_NOCMD;
70
71 return FMSTR_TRUE;
72}
73
74/******************************************************************************
75 *
76 * @brief Handling SANDAPPCMD command
77 *
78 * @param session - transport session
79 * @param msgBuffIO - original command (in) and response buffer (out)
80 *
81 * @return As all command handlers, the return value should be the buffer
82 * pointer where the response output finished (except checksum)
83 *
84 ******************************************************************************/
85
86FMSTR_BPTR FMSTR_StoreAppCmd(FMSTR_SESSION *session, FMSTR_BPTR msgBuffIO, FMSTR_SIZE msgSize, FMSTR_U8 *retStatus)
87{
88 FMSTR_BPTR response = msgBuffIO;
89 FMSTR_SIZE argsLen = msgSize - 1U; /* args len is datalen minus one */
90 FMSTR_U8 code;
91
92 FMSTR_ASSERT(msgBuffIO != NULL);
93 FMSTR_ASSERT(retStatus != NULL);
94
95#if FMSTR_SESSION_COUNT > 1
96 /* Is feature locked by me */
97 if (FMSTR_IsFeatureOwned(session, FMSTR_FEATURE_APPCMD, 0) == FMSTR_FALSE)
98 {
99 *retStatus = FMSTR_STC_SERVBUSY;
100 return response;
101 }
102#endif
103
104 /* the previous command not yet processed */
105 if (fmstr_appCmd != ((FMSTR_APPCMD_CODE)FMSTR_APPCMDRESULT_NOCMD))
106 {
107 *retStatus = FMSTR_STC_SERVBUSY;
108 return response;
109 }
110
111 msgBuffIO = FMSTR_ValueFromBuffer8(&code, msgBuffIO);
112
113 /* does the application command fit to buffer ? */
114 if (argsLen > (FMSTR_SIZE)FMSTR_APPCMD_BUFF_SIZE)
115 {
116 *retStatus = FMSTR_STC_INVBUFF;
117 return response;
118 }
119
120 /* store command data into dedicated buffer */
121 fmstr_appCmd = code;
122 fmstr_appCmdLen = argsLen;
123
124 /* data copy */
125 if (argsLen != 0U)
126 {
127 FMSTR_ADDR appCmdBuffAddr = (FMSTR_ADDR)fmstr_appCmdBuff;
128
129 /*lint -e{534} ignoring return value */
130 msgBuffIO = FMSTR_CopyFromBuffer(appCmdBuffAddr, msgBuffIO, (FMSTR_SIZE8)argsLen);
131 FMSTR_UNUSED(msgBuffIO);
132 }
133
134 /* mark command as "running" (without any response data) */
135 fmstr_appCmdResult = (FMSTR_APPCMD_RESULT)FMSTR_APPCMDRESULT_RUNNING;
136 fmstr_appCmdResultDataLen = 0U;
137
138 /* success */
139 *retStatus = FMSTR_STS_OK;
140 return response;
141}
142
143/******************************************************************************
144 *
145 * @brief Handling GETAPPCMDSTS command
146 *
147 * @param session - transport session
148 * @param msgBuffIO - original command (in) and response buffer (out)
149 *
150 * @return As all command handlers, the return value should be the buffer
151 * pointer where the response output finished (except checksum)
152 *
153 * @note The callback-registered commands are processed at the moment the PC
154 * tries to get the result for the first time. At this moment, we are
155 * sure the PC already got the command delivery packet acknowledged.
156 *
157 ******************************************************************************/
158
159FMSTR_BPTR FMSTR_GetAppCmdStatus(FMSTR_SESSION *session, FMSTR_BPTR msgBuffIO, FMSTR_U8 *retStatus)
160{
161#if FMSTR_MAX_APPCMD_CALLS > 0
162 FMSTR_PAPPCMDFUNC func = NULL;
163 FMSTR_INDEX index;
164
165 FMSTR_ASSERT(msgBuffIO != NULL);
166 FMSTR_ASSERT(retStatus != NULL);
167
168#if FMSTR_SESSION_COUNT > 1
169 /* Is feature locked by me */
170 if (FMSTR_IsFeatureOwned(session, FMSTR_FEATURE_APPCMD, 0) == FMSTR_FALSE)
171 {
172 *retStatus = FMSTR_STC_SERVBUSY;
173 return msgBuffIO;
174 }
175#endif
176
177 /* time to execute the command's callback */
178 if ((index = FMSTR_FindAppCmdCallIndex(fmstr_appCmd)) >= 0)
179 {
180 func = fmstr_appCmdCallFunc[index];
181 }
182
183 /* valid callback function found? */
184 if (func != NULL)
185 {
186 /* do execute callback, return value is app.cmd result code */
187 fmstr_appCmdResult = func(fmstr_appCmd, fmstr_appCmdBuff, fmstr_appCmdLen);
188
189 /* nothing more to do with this command (i.e. command acknowledged) */
190 fmstr_appCmd = FMSTR_APPCMDRESULT_NOCMD;
191 }
192#endif
193
194 /* success */
195 *retStatus = FMSTR_STS_OK;
196 return FMSTR_ValueToBuffer8(msgBuffIO, (FMSTR_U8)fmstr_appCmdResult);
197}
198
199/******************************************************************************
200 *
201 * @brief Handling GETAPPCMDDATA command
202 *
203 * @param session - transport session
204 * @param msgBuffIO - original command (in) and response buffer (out)
205 *
206 * @return As all command handlers, the return value should be the buffer
207 * pointer where the response output finished (except checksum)
208 *
209 ******************************************************************************/
210
211FMSTR_BPTR FMSTR_GetAppCmdRespData(FMSTR_SESSION *session, FMSTR_BPTR msgBuffIO, FMSTR_U8 *retStatus)
212{
213 FMSTR_BPTR response = msgBuffIO;
214 FMSTR_SIZE dataLen;
215 FMSTR_SIZE dataOffset;
216
217 FMSTR_ASSERT(msgBuffIO != NULL);
218 FMSTR_ASSERT(retStatus != NULL);
219
220#if FMSTR_SESSION_COUNT > 1
221 /* Is feature locked by me */
222 if (FMSTR_IsFeatureOwned(session, FMSTR_FEATURE_APPCMD, 0) == FMSTR_FALSE)
223 {
224 *retStatus = FMSTR_STC_SERVBUSY;
225 return response;
226 }
227#endif
228
229 /* the previous command not yet processed */
230 if (fmstr_appCmd != ((FMSTR_APPCMD_CODE)FMSTR_APPCMDRESULT_NOCMD))
231 {
232 *retStatus = FMSTR_STC_SERVBUSY;
233 return response;
234 }
235
236 /* Get the data len from incomming buffer */
237 msgBuffIO = FMSTR_SizeFromBuffer(&dataLen, msgBuffIO);
238
239 /* Get the data offset from incomming buffer */
240 msgBuffIO = FMSTR_SizeFromBuffer(&dataOffset, msgBuffIO);
241
242 /* the response would not fit into comm buffer */
243 if (dataLen > (FMSTR_U16)FMSTR_COMM_BUFFER_SIZE)
244 {
245 *retStatus = FMSTR_STC_RSPBUFFOVF;
246 return response;
247 }
248
249 /* the data would be fetched outside the app.cmd response data */
250 if ((((FMSTR_U16)dataOffset) + dataLen) > (FMSTR_SIZE8)fmstr_appCmdResultDataLen)
251 {
252 *retStatus = FMSTR_STC_INVSIZE;
253 return response;
254 }
255
256 /* copy to buffer */
257 {
258 FMSTR_ADDR appCmdBuffAddr = (FMSTR_ADDR)fmstr_appCmdBuff;
259 response = FMSTR_CopyToBuffer(response, appCmdBuffAddr, (FMSTR_SIZE8)dataLen);
260 }
261
262 /* success */
263 *retStatus = FMSTR_STS_OK | FMSTR_STSF_VARLEN;
264 return response;
265}
266
267/******************************************************************************
268 *
269 * @brief Find index of registered app.cmd callback
270 *
271 * @param appCmdCode - App. command ID
272 *
273 * @return Index of function pointer in our local tables
274 *
275 ******************************************************************************/
276
277static FMSTR_INDEX FMSTR_FindAppCmdCallIndex(FMSTR_APPCMD_CODE appCmdCode)
278{
279#if FMSTR_MAX_APPCMD_CALLS > 0
280 FMSTR_INDEX i;
281
282 for (i = 0; i < FMSTR_MAX_APPCMD_CALLS; i++)
283 {
284 if (fmstr_appCmdCallId[i] == appCmdCode)
285 {
286 return i;
287 }
288 }
289#else
290 /*lint -esym(528, FMSTR_FindAppCmdCallIndex) this function is
291 not referenced when APPCMD_CALLS are not used */
292 FMSTR_UNUSED(appCmdCode);
293#endif
294
295 return -1;
296}
297
298/******************************************************************************
299 *
300 * @brief API: Mark the application command is processed by the application
301 *
302 * @param resultCode - the result code which is returned to a host
303 *
304 ******************************************************************************/
305
306void FMSTR_AppCmdAck(FMSTR_APPCMD_RESULT resultCode)
307{
308 fmstr_appCmdResult = resultCode;
309 fmstr_appCmdResultDataLen = 0U;
310
311 /* waiting for a new command to come */
312 fmstr_appCmd = (FMSTR_APPCMD_CODE)FMSTR_APPCMDRESULT_NOCMD;
313}
314
315/******************************************************************************
316 *
317 * @brief API: Mark the application command is processed by the application
318 *
319 * @param pResultDataAddr - address of data we want to return to the PC
320 * @param resultDataLen - length of return data
321 *
322 ******************************************************************************/
323
324void FMSTR_AppCmdSetResponseData(FMSTR_ADDR resultDataAddr, FMSTR_SIZE resultDataLen)
325{
326 /* any data supplied by user? */
327 if (FMSTR_ADDR_VALID(resultDataAddr) != FMSTR_FALSE)
328 {
329 /* response data length is trimmed if response data would not fit into buffer */
330 fmstr_appCmdResultDataLen = (FMSTR_SIZE8)resultDataLen;
331 if (fmstr_appCmdResultDataLen > (FMSTR_SIZE8)FMSTR_APPCMD_BUFF_SIZE)
332 {
333 fmstr_appCmdResultDataLen = (FMSTR_SIZE8)FMSTR_APPCMD_BUFF_SIZE;
334 }
335
336 if (fmstr_appCmdResultDataLen > 0U)
337 {
338 FMSTR_ADDR appCmdBuffAddr = (FMSTR_ADDR)fmstr_appCmdBuff;
339 FMSTR_MemCpyFrom(appCmdBuffAddr, resultDataAddr, fmstr_appCmdResultDataLen);
340 }
341 }
342 else
343 {
344 /* no data being returned at all (same effect as pure FMSTR_AppCmdAck) */
345 fmstr_appCmdResultDataLen = 0U;
346 }
347}
348
349/******************************************************************************
350 *
351 * @brief API: Fetch the application command code if one is ready for processing
352 *
353 * @return A command code stored in the application cmd buffer.
354 * The return value is FMSTR_APPCMDRESULT_NOCMD if there is no
355 * new command since the last call to FMSTR_AppCmdAck
356 *
357 ******************************************************************************/
358
359FMSTR_APPCMD_CODE FMSTR_GetAppCmd(void)
360{
361#if FMSTR_MAX_APPCMD_CALLS > 0
362 /* the user can never see the callback-registered commands */
363 if (FMSTR_FindAppCmdCallIndex(fmstr_appCmd) >= 0)
364 {
365 return FMSTR_APPCMDRESULT_NOCMD;
366 }
367#endif
368
369 /* otherwise, return the appcomand pending */
370 return fmstr_appCmd;
371}
372
373/******************************************************************************
374 *
375 * @brief API: Get a pointer to application command data
376 *
377 * @param dataLen - A pointer to variable which receives the data length
378 *
379 * @return Pointer to the "application command" data
380 *
381 ******************************************************************************/
382
383FMSTR_APPCMD_PDATA FMSTR_GetAppCmdData(FMSTR_SIZE *dataLen)
384{
385 /* no command, no data */
386 if (fmstr_appCmd == ((FMSTR_APPCMD_CODE)FMSTR_APPCMDRESULT_NOCMD))
387 {
388 return NULL;
389 }
390
391#if FMSTR_MAX_APPCMD_CALLS > 0
392 /* the user never sees the callback-registered commands */
393 if (FMSTR_FindAppCmdCallIndex(fmstr_appCmd) >= 0)
394 {
395 return NULL;
396 }
397#endif
398
399 /* caller want to know the data length */
400 if (dataLen != NULL)
401 {
402 *dataLen = fmstr_appCmdLen;
403 }
404
405 /* data are saved in out buffer */
406 return fmstr_appCmdLen > 0U ? fmstr_appCmdBuff : (FMSTR_APPCMD_PDATA)NULL;
407}
408
409/******************************************************************************
410 *
411 * @brief API: Register or unregister app.cmd callback handler
412 *
413 * @param appCmdCode - App.command ID
414 * @param callbackFunc - Pointer to handler function (NULL to unregister)
415 *
416 * @return Non-zero if successfull, zero if maximum callbacks already set
417 *
418 ******************************************************************************/
419
420FMSTR_BOOL FMSTR_RegisterAppCmdCall(FMSTR_APPCMD_CODE appCmdCode, FMSTR_PAPPCMDFUNC callbackFunc)
421{
422#if FMSTR_MAX_APPCMD_CALLS > 0
423
424 FMSTR_INDEX index;
425
426 /* keep "void" ID as reserved */
427 if (appCmdCode == FMSTR_APPCMDRESULT_NOCMD)
428 {
429 return FMSTR_FALSE;
430 }
431
432 /* get index of app.cmd ID (if already set) */
433 index = FMSTR_FindAppCmdCallIndex(appCmdCode);
434
435 /* when not found, get a free slot (only if registering new callback) */
436 if ((index < 0) && (callbackFunc != NULL))
437 {
438 index = FMSTR_FindAppCmdCallIndex(FMSTR_APPCMDRESULT_NOCMD);
439 }
440
441 /* failed? */
442 if (index < 0)
443 {
444 return FMSTR_FALSE;
445 }
446
447 /* register handler */
448 fmstr_appCmdCallFunc[index] = callbackFunc;
449 fmstr_appCmdCallId[index] = (FMSTR_APPCMD_CODE)(callbackFunc != NULL ? appCmdCode : FMSTR_APPCMDRESULT_NOCMD);
450
451 return FMSTR_TRUE;
452
453#else
454 FMSTR_UNUSED(callbackFunc);
455 FMSTR_UNUSED(appCmdCode);
456
457 /* app.cmd callback not implemented */
458 return FMSTR_FALSE;
459
460#endif
461}
462
463#else /* FMSTR_USE_APPCMD && (!FMSTR_DISABLE) */
464
465/* void Application Command API functions */
466
467void FMSTR_AppCmdAck(FMSTR_APPCMD_RESULT resultCode)
468{
469 FMSTR_UNUSED(resultCode);
470}
471
472void FMSTR_AppCmdSetResponseData(FMSTR_ADDR resultDataAddr, FMSTR_SIZE resultDataLen)
473{
474 FMSTR_UNUSED(resultDataAddr);
475 FMSTR_UNUSED(resultDataLen);
476}
477
478FMSTR_APPCMD_CODE FMSTR_GetAppCmd(void)
479{
480 return (FMSTR_APPCMD_CODE)FMSTR_APPCMDRESULT_NOCMD;
481}
482
483FMSTR_APPCMD_PDATA FMSTR_GetAppCmdData(FMSTR_SIZE *dataLen)
484{
485 FMSTR_UNUSED(dataLen);
486 return NULL;
487}
488
489FMSTR_BOOL FMSTR_RegisterAppCmdCall(FMSTR_APPCMD_CODE appCmdCode, FMSTR_PAPPCMDFUNC callbackFunc)
490{
491 FMSTR_UNUSED(appCmdCode);
492 FMSTR_UNUSED(callbackFunc);
493 return FMSTR_FALSE;
494}
495
496/*lint -efile(766, freemaster_protocol.h) include file is not used in this case */
497
498#endif /* FMSTR_USE_APPCMD && (!FMSTR_DISABLE) */
499