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 | |
32 | static FMSTR_APPCMD_CODE fmstr_appCmd; /* app.cmd code (to application) */ |
33 | static FMSTR_APPCMD_DATA fmstr_appCmdBuff[FMSTR_APPCMD_BUFF_SIZE]; /* app.cmd data buffer */ |
34 | static FMSTR_SIZE fmstr_appCmdLen; /* app.cmd data length */ |
35 | |
36 | static FMSTR_APPCMD_RESULT fmstr_appCmdResult; /* app.cmd result code (from application) */ |
37 | static FMSTR_SIZE8 fmstr_appCmdResultDataLen; |
38 | |
39 | #if FMSTR_MAX_APPCMD_CALLS > 0 |
40 | static FMSTR_APPCMD_CODE fmstr_appCmdCallId[FMSTR_MAX_APPCMD_CALLS]; /* registered callback commands */ |
41 | static FMSTR_PAPPCMDFUNC fmstr_appCmdCallFunc[FMSTR_MAX_APPCMD_CALLS]; /* registered callback handlers */ |
42 | #endif |
43 | |
44 | /*********************************** |
45 | * local functions |
46 | ***********************************/ |
47 | |
48 | static FMSTR_INDEX FMSTR_FindAppCmdCallIndex(FMSTR_APPCMD_CODE appCmdCode); |
49 | |
50 | /****************************************************************************** |
51 | * |
52 | * @brief Initialize app.cmds interface |
53 | * |
54 | ******************************************************************************/ |
55 | |
56 | FMSTR_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 | |
86 | FMSTR_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 | |
159 | FMSTR_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 | |
211 | FMSTR_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 | |
277 | static 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 | |
306 | void 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 | |
324 | void 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 | |
359 | FMSTR_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 | |
383 | FMSTR_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 | |
420 | FMSTR_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 | |
467 | void FMSTR_AppCmdAck(FMSTR_APPCMD_RESULT resultCode) |
468 | { |
469 | FMSTR_UNUSED(resultCode); |
470 | } |
471 | |
472 | void FMSTR_AppCmdSetResponseData(FMSTR_ADDR resultDataAddr, FMSTR_SIZE resultDataLen) |
473 | { |
474 | FMSTR_UNUSED(resultDataAddr); |
475 | FMSTR_UNUSED(resultDataLen); |
476 | } |
477 | |
478 | FMSTR_APPCMD_CODE FMSTR_GetAppCmd(void) |
479 | { |
480 | return (FMSTR_APPCMD_CODE)FMSTR_APPCMDRESULT_NOCMD; |
481 | } |
482 | |
483 | FMSTR_APPCMD_PDATA FMSTR_GetAppCmdData(FMSTR_SIZE *dataLen) |
484 | { |
485 | FMSTR_UNUSED(dataLen); |
486 | return NULL; |
487 | } |
488 | |
489 | FMSTR_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 | |