/* Copyright (C) 2018 RDA Technologies Limited and/or its affiliates("RDA"). * All rights reserved. * * This software is supplied "AS IS" without any warranties. * RDA assumes no responsibility or liability for the use of the software, * conveys no license or title under any patent, copyright, or mask work * right to the product. RDA reserves the right to make changes in the * software without notification. RDA also make no representation or * warranty that such application will be suitable for the specified use * without further testing or modification. */ #ifndef _AT_ENGINE_H_ #define _AT_ENGINE_H_ #include #include #include #include "osi_api.h" #include "osi_event_hub.h" #include "osi_generic_list.h" #include "osi_pipe.h" #include "atr_config.h" #include "at_cfg.h" #include "quec_proj_config.h" #include "drv_uart.h" #include "drv_serial.h" #include "quec_sio_adapter.h" #include "quec_dispatch.h" #ifdef __cplusplus extern "C" { #endif //21220122 kevin.wang move it to quec_sio_adapter.h #ifndef CONFIG_QUEC_PROJECT_FEATURE_ATC_PARSE /** * @brief forward declaration of uart driver */ struct drvUart; /** * @brief opaque data structure of AT engine */ typedef struct atEngine atEngine_t; /** * @brief data structure of AT device */ typedef struct atDevice atDevice_t; #endif /** * @brief opaque data structure of AT dispatch */ #ifndef CONFIG_QUEC_PROJECT_FEATURE_ATC_PARSE typedef struct atDispatch atDispatch_t; #else typedef struct ql_dispatch atDispatch_t; #define atCmdEngine ql_dispatch #define atDataEngine ql_dispatch #endif /** * @brief opaque data structure of AT command mode engine */ typedef struct atCmdEngine atCmdEngine_t; /** * @brief opaque data structure of AT data mode engine */ typedef struct atDataEngine atDataEngine_t; /** * @brief opaque data structure of AT mux mode engine */ typedef struct atCmuxEngine atCmuxEngine_t; /** * @brief data structure of AT command */ #ifndef CONFIG_QUEC_PROJECT_FEATURE_ATC_PARSE typedef struct atCommand atCommand_t; #else #include "quec_at_param.h" typedef struct ql_at_cmd atCommand_t; #endif //21220122 kevin.wang move it to quec_sio_adapter.h #ifndef CONFIG_QUEC_PROJECT_FEATURE_ATC_PARSE /** * @ brief AT device character framing format * * Refer to V.250 +ICF. The enum value *matches* format parameter in +ICF * command. */ typedef enum atDeviceFormat { AT_DEVICE_FORMAT_AUTO_DETECT, ///< auto detect AT_DEVICE_FORMAT_8N2, ///< 8 Data; 2 Stop AT_DEVICE_FORMAT_811, ///< 8 Data; 1 Parity; 1 Stop AT_DEVICE_FORMAT_8N1, ///< 8 Data; 1 Stop AT_DEVICE_FORMAT_7N2, ///< 7 Data; 2 Stop AT_DEVICE_FORMAT_711, ///< 7 Data; 1 Parity; 1 Stop AT_DEVICE_FORMAT_7N1 ///< 7 Data; 1 Stop } atDeviceFormat_t; /** * @ brief AT device character framing parity * * Refer to V.250 +ICF. The enum value *matches* format parameter in +ICF * command. */ typedef enum atDeviceParity { AT_DEVICE_PARITY_ODD, ///< Odd AT_DEVICE_PARITY_EVEN, ///< Even AT_DEVICE_PARITY_MARK, ///< Mark AT_DEVICE_PARITY_SPACE ///< Space } atDeviceParity_t; /** * @ brief AT device receive flow control * * Refer to V.250 +IFC. The enum value *matches* format parameter in +IFC * command. Not supported options are not listed. */ typedef enum atDeviceRXFC { AT_DEVICE_RXFC_NONE, ///< None AT_DEVICE_RXFC_HW = 2 ///< Circuit 133 (Ready for Receiving) } atDeviceRXFC_t; /** * @ brief AT device transfer flow control * * Refer to V.250 +IFC. The enum value *matches* format parameter in +IFC * command. Not supported options are not listed. */ typedef enum atDeviceTXFC { AT_DEVICE_TXFC_NONE, ///< None AT_DEVICE_TXFC_HW = 2 ///< Circuit 106 (Clear to Send/Ready for Sending) } atDeviceTXFC_t; /** * @brief AT device attribute * (TODO!! maybe need to distinguish device type, * below all for UART like device) * @baud_max Maximum value of baudrate * @baud_min Minimum value of baudrate * @format_support Boolean type array mark whether this device support * the format refer to \p atDeviceFormat or not. * @parity_support Boolean type array mark whether this device support * the parity refer to \p atDeviceParity or not. */ typedef struct { uint32_t baud_max; uint32_t baud_min; bool format_support[7]; bool parity_support[4]; } atDeviceAttr_t; /** * @brief AT device data structure */ struct atDevice { /** delete function */ void (*destroy)(atDevice_t *th); /** open function */ bool (*open)(atDevice_t *th); /** close function */ void (*close)(atDevice_t *th); /** write function */ int (*write)(atDevice_t *th, const void *data, size_t size); /** read function */ int (*read)(atDevice_t *th, void *data, size_t size); /** get read available bytes function */ int (*read_avail)(atDevice_t *th); /** get write available space function */ int (*write_avail)(atDevice_t *th); /** set baudrate function */ void (*set_baud)(atDevice_t *th, size_t baud); /** set format function */ void (*set_format)(atDevice_t *th, atDeviceFormat_t format, atDeviceParity_t parity); /** set flow control */ bool (*set_flow_ctrl)(atDevice_t *th, atDeviceRXFC_t rxfc, atDeviceTXFC_t txfc); /** set auto sleep timeout */ void (*set_auto_sleep)(atDevice_t *th, int timeout); /** check if the device is ready*/ bool isReady; /** get device attributes */ const atDeviceAttr_t *(*get_attribute)(atDevice_t *th); /** the dispatch */ atDispatch_t *recv; }; /** * @brief CMUX configuration */ typedef struct { uint8_t transparency; ///< 0: basic, 1: advanced uint8_t subset; ///< 0: UIH, 1: UI, 2: I uint8_t port_speed; ///< transmission rate int max_frame_size; ///< maximum frame size uint8_t ack_timer; ///< acknowledgement timer in units of ten milliseconds uint8_t max_retrans_count; ///< maximum number of re-transmissions uint8_t resp_timer; ///< response timer for the multiplexer control channel in units of ten milliseconds uint8_t wakeup_resp_timer; ///< wake up response timer in seconds uint8_t window_size; ///< window size, for Advanced option with Error-Recovery Mode } atCmuxConfig_t; /** * @brief enum type of command mode engine prompt finish mode * * In prompt mode, BACKSPACE will be chcked. When BACKSPACE is input * in the middle, the previous character will be removed from the * buffer. */ typedef enum atCmdPromptEndMode { AT_PROMPT_END_CTRL_Z, ///< ended with CTRL-Z AT_PROMPT_END_ESC, ///< ended with ESCAPE AT_PROMPT_END_OVERFLOW ///< provided buffer overflow } atCmdPromptEndMode_t; /** * @brief UART AT device configuration */ typedef struct { uint32_t name; ///< uart name, such as DRV_NAME_UART1 size_t baud; ///< baud rate atDeviceFormat_t format; ///< character framing format atDeviceParity_t parity; ///< character framing parity bool rts_enable; ///< hw flow control, rts enable bool cts_enable; ///< hw flow control, cts enable } atDeviceUartConfig_t; /** * @brief virtual AT device configuration */ typedef struct { uint32_t name; ///< device name, only used in trace osiPipe_t *rx_pipe; ///< AT RX pipe osiPipe_t *tx_pipe; ///< AT TX pipe } atDeviceVirtConfig_t; #ifdef CONFIG_QUEC_PROJECT_FEATURE_UART typedef struct { atDevice_t ops; // API drvUart_t *drv; atDeviceUartConfig_t config; // UART configuration osiWork_t *work; uint32_t pending_event; atDeviceAttr_t attr; } atDeviceUart_t; typedef struct { atDevice_t ops; // API uint32_t name; drvSerial_t *serial; } atDeviceUsrl_t; #endif #endif /* end CONFIG_QUEC_PROJECT_FEATURE_ATC_PARSE */ /** * @brief callback function type after prompt mode is finished * * @param ctx provided callback context * @param end_mode prompt end mode, refer to \p atCmdPromptEndMode_t * @param size received data size */ typedef void (*atCmdPromptCB_t)(void *ctx, atCmdPromptEndMode_t end_mode, size_t size); /** * @brief callback function type in command bypass mode * * @param ctx provided callback context * @param data received data pointer * @param size received data size * @return * - consumed bytes, it can be less than \p size * - 0 if nothing consumed */ typedef int (*atCmdBypassCB_t)(void *ctx, const void *data, size_t size); /** * @brief callback function type in data bypass mode * * @param ctx provided callback context * @param data received data pointer * @param size received data size * @return * - consumed bytes, it can be less than \p size * - 0 if nothing consumed */ typedef int (*atDataBypassCB_t)(void *ctx, const void *data, size_t size); /** * @brief set AT device dispatch * * @param th AT device pointer, must be valid * @param recv AT dispatch pointer, must be valid */ static inline void atDeviceSetDispatch(atDevice_t *th, atDispatch_t *recv) { th->recv = recv; } /** * @brief get AT device dispatch * * @param th AT device pointer, must be valid * @return AT dispatch pointer */ static inline atDispatch_t *atDeviceGetDispatch(atDevice_t *th) { return th->recv; } #ifndef CONFIG_QUEC_PROJECT_FEATURE_ATC_PARSE /** * @brief create UART AT device * * After create, the device is in *close* state. \p atDeviceOpen * should be called before access the device. * * @param cfg UART AT device configuration, must be valid * this /p cfg can be change by the function, * invalid items will be corrected to bestfit * @return * - UART AT device pointer * - NULL if out of memory */ atDevice_t *atDeviceUartCreate(atDeviceUartConfig_t *cfg); /** * @brief create UART AT device * * Comparing to \p atDeviceUartCreate, the parameter is an already created * UART device. * * @param drv UART AT device driver, must be valid * @return * - UART AT device pointer * - NULL if out of memory, or invalid parmameter */ atDevice_t *atDeviceUartCreateWithDevice(struct drvUart *drv); /** * @brief create serial AT device * * This used to create USB CDC/ACM AT device. * * @param name serial device name, such as DRV_NAME_USRL_COM0 * @return * - serial AT device pointer * - NULL if out of memory */ atDevice_t *atDeviceUserialCreate(uint32_t name); /** * @brief create diag at device * * This used to create diag AT device * * @return * - NULL fail * - other the at device */ atDevice_t *atDeviceDiagCreate(); /** * @brief create virtual AT device * * @param cfg virtual AT device configuration, must be valid * @return * - AT device pointer * - NULL if out of memory */ atDevice_t *atDeviceVirtCreate(const atDeviceVirtConfig_t *cfg); /** * @brief delete the AT device * * When \p th is NULL, nothing will be done. * * @param th AT device to be deleted */ void atDeviceDelete(atDevice_t *th); /** * @brief open the AT device for read and write * * @param th AT device, must be valid * @return * - true on success */ bool atDeviceOpen(atDevice_t *th); /** * @brief close the AT device * * @param th AT device, must be valid */ void atDeviceClose(atDevice_t *th); /** * @brief write data to AT device * * AT device will try to write all data. When the output buffer is * full, it will wait. * * Usually, AT device will define a *reasonable* timeout. At timeout, * the written size may be less than specified size. * * When \p size is 0, nothing will be done. * * @param th AT device, must be valid * @param data data pointer to be written, must be valid if \p size * is not zero * @param size data size * @return * - written byte count * - -1 if parameter is invalid, or device error */ int atDeviceWrite(atDevice_t *th, const void *data, size_t size); /** * @brief read data from AT device * * It will just read from the device receive buffer. When the buffer * is empty, return 0. Even the receive buffer is not empty, the return * size may be less than the specified size. * * When \p size is 0, nothing will be done. * * @param th AT device, must be valid * @param data mempry pointer for read, must be valid if \p size * is not zero * @param size memory size * @return * - read byte count * - -1 if parameter is invalid, or device error */ int atDeviceRead(atDevice_t *th, void *data, size_t size); /** * @brief AT device read available bytes * * @param th AT device, must be valid * @return * - (-1) Parameter error * - OTHERS (>=0) Available size in byte */ int atDeviceReadAvail(atDevice_t *th); /** * @brief AT device write available space * * @param th AT device, must be valid * @return * - (-1) Parameter error * - OTHERS (>=0) Available size in byte */ int atDeviceWriteAvail(atDevice_t *th); /** * @brief set AT device baudrate * * @param th AT device, must be valid * @param baud baud rate */ void atDeviceSetBaudrate(atDevice_t *th, size_t baud); /** * @brief set AT device charactor format * * @param th AT device, must be valid * @param format refer to \p atDeviceFormat_t * @param parity refer to \p atDeviceParity_t */ void atDeviceSetFormat(atDevice_t *th, atDeviceFormat_t format, atDeviceParity_t parity); /** * @brief set AT device flow control * * @param th AT device, must be valid * @param rxfc flow control of RX * @param txfc flow control of TX * @return * - true on success * - false on failed */ bool atDeviceSetFlowCtrl(atDevice_t *th, atDeviceRXFC_t rxfc, atDeviceTXFC_t txfc); /** * @brief set AT device auto sleep * * Refer to \p drvUartSetAutoSleep * * @param th AT device, must be valid * @param timeout auto sleep wait time after transfer done. It can be * 0 but not recommended. Negative value to disable * auto sleep feature. */ void atDeviceSetAutoSleep(atDevice_t *th, int timeout); /** * @brief get AT device attribute * * @param th AT device, must be valid * @return the attribute of this device */ const atDeviceAttr_t *atDeviceAttribute(atDevice_t *th); #endif /* end CONFIG_QUEC_PROJECT_FEATURE_ATC_PARSE */ /** * @brief create a dispatch of device * * @param device AT device pointer, must be valid * @return the created dispatch pointer */ atDispatch_t *atDispatchCreate(atDevice_t *device); /** * @brief create dispatch for device or cmux DLC * * When \p device is not NULL, the dispatch is for device. When * \p cmuxParent is not NULL, the dispatch is for cmux DLC. It is * invalid that both of \p device and \p cmuxParent are not NULL, * or both of \p device and \p cmuxParent are NULL. * * @param device AT device * @param cmuxParent parent cmux mode engine * @param dlci when create dispatch for cmux DLC, it is the * DLC number * @return * - the created dispatch * - NULL if out of memory */ atDispatch_t *atDispatchDlcCreate(atDevice_t *device, atCmuxEngine_t *cmuxParent, int dlci); /** * @brief delete a dispatch * * When \p th is NULL, nothing will be done. * * When engines of the dispatch is busy, the dispatch won't be deleted * immediately. Rather, it will be deleted after engines is non-busy. * When the dispatch is in delete pending mode, engine output will be * disabled. * * @param th the dispatch pointer, must be valid */ void atDispatchDelete(atDispatch_t *th); /** * @brief read data from AT device * * Usually, it is called (directly or through thread callback) when there * are input data in AT device. * * @param th the dispatch pointer, must be valid */ void atDispatchRead(atDispatch_t *th); /** * @brief send event to AT thread itself to consume more data * * AT thread is working in non-blocking asynchronous mode. When downstream * is ready, it is needed to notify upstream to consume more data. Event * is used to avoid too many levels of function calls. * * @param th the dispatch pointer, must be valid */ void atDispatchReadLater(atDispatch_t *th); /** * @brief notify dispatch that device is broken * * This can be called outside AT thread. * * @param th the dispatch pointer, must be valid */ void atDispatchDeviceBroken(atDispatch_t *th); /** * @brief get AT device of the dispatch * * When the dispatch is binded to CMUX DLC, the device of the parent * CMUX engine will be returned. * * @param th the dispatch pointer, must be valid * @return the AT device pointer */ atDevice_t *atDispatchGetDevice(atDispatch_t *th); /** * @brief get the command mode engine the dispatch * * Command mode engine of dispatch will be always created. This will * return the command mode engine, no matter which dispatch mode is. * * @param th the dispatch pointer, must be valid * @return the command mode engine */ atCmdEngine_t *atDispatchGetCmdEngine(atDispatch_t *th); /** * @brief get the data mode engine the dispatch * * Data mode engine of dispatch will be created when dispatch is changed * to data mode. So, the returned pointer may be NULL if not in data mode. * * @param th the dispatch pointer, must be valid * @return the data mode engine */ atDataEngine_t *atDispatchGetDataEngine(atDispatch_t *th); /** * @brief get the paremt cmux mode engine * * When the dispatch is not created for cmux DLC, it will return NULL. * * @param th the dispatch pointer, must be valid * @return the parent cmux mode engine */ atCmuxEngine_t *atDispatchGetParentCmuxEngine(atDispatch_t *th); /** * @brief check whether in command mode * * @param th the dispatch pointer, must be valid * @return * - true if in command mode * - false if not in command mode */ bool atDispatchIsCmdMode(atDispatch_t *th); /** * @brief check whether in data mode * * @param th the dispatch pointer, must be valid * @return * - true if in data mode * - false if not in data mode */ bool atDispatchIsDataMode(atDispatch_t *th); /** * @brief check whether dispatch is in cmux mode * * @param th the dispatch pointer, must be valid * @return * - true if the dispatch is in cmux mode * - false if the dispatch is not in cmux mode */ bool atDispatchIsCmuxMode(atDispatch_t *th); #ifdef CONFIG_QUEC_PROJECT_FEATURE extern int atDispatchGetDlci(atDispatch_t *th); #endif /** * @brief set dispatch to command mode * * @param th the dispatch pointer, must be valid */ void atDispatchSetCmdMode(atDispatch_t *th); /** * @brief set dispatch to data mode * * @param th the dispatch pointer, must be valid */ void atDispatchSetDataMode(atDispatch_t *th); /** * @brief finish data mode and set dispatch to command mode * * @param th the dispatch pointer, must be valid */ void atDispatchEndDataMode(atDispatch_t *th); /** * @brief finish data PPP mode and set dispatch to command mode * * Comparing to \p atDispatchEndDataMode, the dispatch will still checking * whether incoming data are valid PPP packets. Only when the incoming * data are invalid PPP packets, or configured timeout reaches, dispatch * will start to push data to command line engine. * * @param th the dispatch pointer, must be valid */ void atDispatchEndDataPppMode(atDispatch_t *th); /** * @brief dispatch end cmux mode * * It must be called in CMUX mode. * * @param th the dispatch pointer, must be valid */ void atDispatchEndCmuxMode(atDispatch_t *th); /** * @brief check whether dispatch in data escape mode * * @param th the dispatch pointer, must be valid */ bool atDispatchInDataEscape(atDispatch_t *th); /** * @brief set dispatch to cmux mode, with specified configuration * * @param th the dispatch pointer, must be valid * @param cfg cmux configuration */ void atDispatchSetCmuxMode(atDispatch_t *th, const atCmuxConfig_t *cfg); /** * @brief get the global AT dispatch list * * @return the global AT dispatch list head */ osiSlistHead_t *atDispatchGetList(void); /** * @brief end cmux mode for all dispatches in cmux mode * * It will check all dispatches, and end cmux mode forcedly if the dispatch * is in cmux mode. * * @return the count of dispatches in cmux mode */ unsigned atDispatchEndCmuxModeAll(void); /** * @brief check whether it is a valid dispatch pointer * * @param p the dispatch pointer to be checked * @return * - true if \p p is valid dispatch pointer * - false if \p p is not valid dispatch pointer */ bool atDispatchIsValid(atDispatch_t *p); /** * @brief dispatch write data * * When the dispatch is for device, \p data will be written to device. * Otherwise, \p data will be written the corresponding DLC. * * @param th the dispatch pointer, must be valid * @param data data to be written, can't be NULL is size is not 0 * @param size data size */ void atDispatchWrite(atDispatch_t *th, const uint8_t *data, unsigned size); /** * @brief push data to dispatch * * Usually it is called by cmux engine, to push data to dispatch for * DLC. At push, all data will be consumed or cached in dispatch. * * @param th the dispatch pointer, must be valid * @param data data to be pushed to dispatch, can't be NULL is size is not 0 * @param size data size */ void atDispatchPushData(atDispatch_t *th, const void *data, size_t size); /** * @brief create AT command mode engine * * @param dispatch parent dispatch of the command mode engine * @return * - command mode engine pointer * - NULL if out of memory */ atCmdEngine_t *atCmdEngineCreate(atDispatch_t *dispatch); /** * @brief delete AT command mode engine * * @param th command mode engine, must be valid */ void atCmdEngineDelete(atCmdEngine_t *th); /** * @brief push data to command engine * * It will be called by dispatch. When dispatch received data, either in * read mode or push mode, dispatch will push the data to engine. * * @param th cmux mode engine, must be valid * @param data data to be pushed, can't be NULL if \p size is not 0. * @param size data size * @return * - consumed data size * - -1 if command engine is busy */ int atCmdPushData(atCmdEngine_t *th, const void *data, size_t size); /** * @brief write data to AT command mode engine * * When the parent dispatch is not in command mode, nothing will be done. * * It will wait all data are written (maybe in buffer of AT device). * * Though the data should be printable characters in typical cases, * non-printable characters are permitted. It can be used to output * binary data if needed. * * @param th command mode engine, must be valid * @param data data pointer to be write, can't be NULL is size is not 0 * @param size data size */ void atCmdWrite(atCmdEngine_t *th, const void *data, size_t size); /** * @brief set command mode engine to command line mode * * Command line mode is the mode to receive AT commands. * * @param th command mode engine, must be valid */ void atCmdSetLineMode(atCmdEngine_t *th); /** * @brief set command mode engine to command line mode * * Prompt mode is the mode defined in \p CMGS and \p CMGW. * * Though the main purpose of this mode is for \p CMGS and \p CMGW, it * can be used in other command handling, if the behavior is the same. * * In prompt mode, the input won't come to command line buffer, rather * the input will be written to the provided buffer. * * @param th command mode engine, must be valid * @param cb callback after the prompt input is finished * @param cb_ctx callback context * @param buff buffer pointer for input data, can't be NULL * @param buff_size buffer size * @return * - true on success * - false on invalid parameter, the mode isn't changed */ bool atCmdSetPromptMode(atCmdEngine_t *th, atCmdPromptCB_t cb, void *cb_ctx, void *buff, size_t buff_size); /** * @brief set command mode engine to bypass mode * * In bypass mode, the input will be passed as parameter of callback. Also, * the input won't be echoed no matter the setting of *ATE*. * * After bypass mode input is finished, \p atCmdSetLineMode should be called * explicitly. * * Typical usage is to receive binary data. * * @param th command mode engine, must be valid * @param cb callback when there are input data * @param cb_ctx callback context * @return * - true on success * - false on invalid parameter */ bool atCmdSetBypassMode(atCmdEngine_t *th, atCmdBypassCB_t cb, void *cb_ctx); /** * @brief notify AT device baudrate is changed by AT command * * AT device flow control change commands: +IPR * * @param th command mode engine, must be valid */ void atCmdDeviceSetBaudNeeded(atCmdEngine_t *th); /** * @brief notify AT device format is changed by AT command * * When AT device format is changed, the new setting can't be applied to * AT device immediately. Rather, AT device format should be changed after * the command line is finished. This is for AT command handler to notify * that AT device format change. * * AT device format change commands: * - +IPR * - +ICF * * @param th command mode engine, must be valid */ void atCmdDeviceSetFormatNeeded(atCmdEngine_t *th); /** * @brief notify AT device flow control is changed by AT command * * AT device flow control change commands: +IFC * * @param th command mode engine, must be valid */ void atCmdDeviceSetIfcNeeded(atCmdEngine_t *th); #ifndef CONFIG_QUEC_PROJECT_FEATURE_ATC_PARSE /** * @brief ignore remain commands in the command line * * @param th command mode engine, must be valid */ void atCmdClearRemains(atCmdEngine_t *th); #endif /** * @brief handle one command finish * * @param engine command mode engine, must be valid * @param ok whether the command is success or fail */ void atCmdFinalHandle(atCmdEngine_t *engine, bool ok); /** * @brief notify one command in command line is finished * * One command line may contain multiple AT commands. After each command * handling is finished, this should be called. And command mode engine * will schedule to handle the next command, if available. * * @param th command mode engine, must be valid */ void atCmdCommandFinished(atCmdEngine_t *th); /** * @brief AT command timeout handler function type * * @param cmd current AT command in handling */ typedef void (*atCommandTimeoutHandler_t)(atCommand_t *cmd); /** * @brief set command timeout handler * * Set AT command handler timeout handler. At timeout, \p handler will be * called. * * It is not needed to unregister the timeout handler manually. At * \p atCmdFinalHandle, the timeout handler will be cleared automatically. * * When \p handler is NULL, the previously registered timeout handler will * be cleared, through it is not needed in typical cases. * * This *must* be called in AT command handler. * * Usually, the timeout handler shall do the command clean up, and response * a final result code. For example: * * \code{.cpp} * static void _timeout(atCommand_t *cmd) * { * // clean up ... * atCmdRespCmdError(cmd->engine, cme_error_code); * } * * void AT_COMMAND_HANDLE(atCommand_t *cmd) * { * // ...... * atCmdSetTimeoutHandler(cmd->engine, ms, _timeout); * } * \endcode * * When the AT command will switch channel to data or CMUX mode, the timeout * handler may be called when the channel is not in command mode. Usually, it * is not wanted. And it is suggested not to set timeout handler if the * command will switch mode. * * @param th command mode engine, must be valid * @param timeout timeout in milliseconds * @param handler timeout handler * @return * - true on success * - false if there are no AT command in handling */ bool atCmdSetTimeoutHandler(atCmdEngine_t *th, uint32_t timeout, atCommandTimeoutHandler_t handler); /** * @brief AT command abort handler function type * * @param cmd current AT command in handling */ typedef void (*atCommandAbortHandler_t)(atCommand_t *cmd); /** * @brief set command handler abort handler * * By default, when an AT command is in handling, further input will be * hold. Only after the current AT command finished, further input will * be parsed. * * When a valid \p handler is registered, \p handler will be called on * *any* input character. Usually, final result code shall be responsed * in \p handler to abort the current command handling. * * When command engine is not in command line mode (such as prompt mode), * abort handler won't be called in further input. * * It is not needed to unregister the abort handler manually. At * \p atCmdFinalHandle, the abort handler will be cleared automatically. * * When \p handler is NULL, the previously registered abort handler will * be cleared. * * Usually, the timeout handler shall do the command clean up, and response * a final result code. For example: * * \code{.cpp} * static void _aborted(atCommand_t *cmd) * { * // clean up ... * atCmdRespCmdError(cmd->engine, cme_error_code); * } * * void AT_COMMAND_HANDLE(atCommand_t *cmd) * { * // ...... * atCmdSetAbortHandler(cmd->engine, _aborted); * } * \endcode * * @param th command mode engine, must be valid * @param handler abort handler * @return * - true on success * - false if there are no command in handling */ bool atCmdSetAbortHandler(atCmdEngine_t *th, atCommandAbortHandler_t handler); /** * @brief check whether in command line mode * * @param th command mode engine, must be valid * @return * - true if in command line mode * - false if not in command line mode */ bool atCmdIsLineMode(atCmdEngine_t *th); /** * @brief check whether in prompt mode * * @param th command mode engine, must be valid * @return * - true if in prompt mode * - false if not in prompt mode */ bool atCmdIsPromptMode(atCmdEngine_t *th); /** * @brief check whether in bypass mode * * @param th command mode engine, must be valid * @return * - true if in bypass mode * - false if not in bypass mode */ bool atCmdIsBypassMode(atCmdEngine_t *th); /** * @brief get this or parent dispatch in cmux mode * * When the channel is in cmux mode, return the dispatch of current channel. * When the channel is a sub-channel of cmux mode, return the dispatch of * parent channel, which is in cmux mode. Otherwise, return NULL. * * @param th command mode engine, must be valid * @return * - dispatch of current or parent channel, which is in cmux mode * - NULL if neither current nor parent channel is in cmux mode */ atDispatch_t *atCmdGetDispatchInCmux(atCmdEngine_t *th); /** * @brief set the binded SIM * * @param th command mode engine, must be valid * @param sim SIM number */ void atCmdSetSim(atCmdEngine_t *th, uint8_t sim); /** * @brief get the binded SIM * * @param th command mode engine, must be valid * @return the binded SIM number */ uint8_t atCmdGetSim(atCmdEngine_t *th); /** * @brief get the parent dispatch * * @param th command mode engine, must be valid * @return the parent dispatch */ atDispatch_t *atCmdGetDispatch(atCmdEngine_t *th); /** * @brief get the pointer of per channel settings * * It returns the per channel settings, and it can be modified * directly. * * @param th command mode engine, must be valid * @return per channel settings pointer */ atChannelSetting_t *atCmdChannelSetting(atCmdEngine_t *th); /** * @brief check whether it is the first infomation text * * Depends on AT channel setting, there are extra characters for * the first information text. * * @param th command mode engine, must be valid * @return * - true if it is the first information text, that is there * are no information text is output before. * - false if not */ bool atCmdIsFirstInfoText(atCmdEngine_t *th); /** * @brief set the first infomation text flag * * @param th command mode engine, must be valid * @param is_first the first information text flag */ void atCmdSetFirstInfoText(atCmdEngine_t *th, bool is_first); /** * @brief check whether the command list is empty * * A command line will contain multiple AT commands. This will check * whether the command list is empty. * * @param th command mode engine, must be valid * @return * - true if the command list is empty * - false if not */ bool atCmdListIsEmpty(atCmdEngine_t *th); /** * @brief get the channel index * * Channel index is an internal index for each channel. Application * shouldn't assume the meaning of the channel index. Also, there are * no API to find channel by index. * * @param th command mode engine, must be valid * @return the internal channel index */ uint8_t atCmdChannelIndex(atCmdEngine_t *th); #ifndef CONFIG_QUEC_PROJECT_FEATURE_ATC_PARSE /** * @brief increase reference for command engine * * In case that the command engine is needed for certain asynchronous * handling, this should be called to indicate that the command engine * shouldn't be deleted. After the asynchronous handling is done, * \p atCmdDeceaseRef should be called to indicate the command engine * is no longer needed. * * @param th command mode engine, must be valid */ void atCmdIncreaseRef(atCmdEngine_t *th); /** * @brief decrease reference for command engine * * @param th command mode engine, must be valid */ void atCmdDeceaseRef(atCmdEngine_t *th); #endif /** * @brief set comman engine urc enable or disable * * When disabled, all urc will be ignored for the specified command engine. * This is a non-standard feature. By default, urc is enabled. * * @param th command mode engine, must be valid * @param enable true for enable urc, false for disable */ void atCmdSetUrcEnable(atCmdEngine_t *th, bool enable); /** * @brief whether urc is enabled for command engine * * @param th command mode engine, must be valid * @return * - true if urc is enabled for the command engine * - flase if urc is disabled */ bool atCmdIsUrcEnabled(atCmdEngine_t *th); /** * @brief set comman engine urc enable or disable * * When disabled, all urc will be ignored for the specified command engine. * This is a non-standard feature. By default, urc is enabled. * * @param th command mode engine, must be valid * @param enable true for enable urc, false for disable */ void atCmdSetUrcEnable(atCmdEngine_t *th, bool enable); /** * @brief whether urc is enabled for command engine * * @param th command mode engine, must be valid * @return * - true if urc is enabled for the command engine * - flase if urc is disabled */ bool atCmdIsUrcEnabled(atCmdEngine_t *th); /** * @brief indicate start of URC output * * URC output may be buffered, and it may be needed to drop oldest URC * at buffer full. This indicates the start of URC output, to keep record * of starting position of each URC in buffer. * * @param th command mode engine, must be valid */ void atCmdUrcStart(atCmdEngine_t *th); /** * @brief indicate end of URC output * * @param th command mode engine, must be valid */ void atCmdUrcStop(atCmdEngine_t *th); /** * @brief write URC data to AT command mode engine * * The URC data will be buffered, and output at \p atCmdUrcFlush. * * @param th command mode engine, must be valid * @param data data pointer to be write, can't be NULL is size is not 0 * @param size data size */ void atCmdUrcWrite(atCmdEngine_t *th, const void *data, size_t size); /** * @brief clear (discard) all buffered URC data * * @param th command mode engine, must be valid */ void atCmdUrcClear(atCmdEngine_t *th); /** * @brief flush (output) all buffered URC data * * @param th command mode engine, must be valid */ void atCmdUrcFlush(atCmdEngine_t *th); /** * @brief call async function in worker thread * * \p call will be executed in AT command channel worker thread. So, don't * call AT response APIs in \p call. * * @param th command mode engine, must be valid * @param call async call function * @param ctx async call context */ void atCmdWorkerCall(atCmdEngine_t *th, osiCallback_t call, void *ctx); /** * @brief create AT data mode engine * * @param dispatch parent dispatch of the data mode engine * @return * - data mode engine pointer * - NULL if out of memory */ atDataEngine_t *atDataEngineCreate(atDispatch_t *dispatch); /** * @brief delete AT data mode engine * * @param th data mode engine, must be valid */ void atDataEngineDelete(atDataEngine_t *th); /** * @brief push data to data engine * * It will be called by dispatch. When dispatch received data, dispatch * will push the data to engine. * * @param th data mode engine, must be valid * @param data data to be pushed, can't be NULL if \p size is not 0. * @param size data size * @return * - consumed data size * - -1 if data engine is busy */ int atDataPushData(atDataEngine_t *th, const void *data, size_t size); /** * @brief write data to data mode engine * * When the parent dispatch is not in data mode, nothing will be done. * * It will wait all data are written (maybe in buffer of AT device). * * @param th data mode engine, must be valid * @param data data pointer to be write, can't be NULL is size is not 0 * @param size data size */ void atDataWrite(atDataEngine_t *th, const void *data, size_t size); /** * @brief set data mode engine to PPP mode * * @param th data mode engine, must be valid * @param ppp the PPP context pointer */ void atDataSetPPPMode(atDataEngine_t *th, void *ppp); /* @brief Exit data mode engine to PPP mode * * @param th data mode engine, must be valid */ void atDataExitPPPMode(atDataEngine_t *th); /** * @brief set data mode engine to bypass mode * * @param th data mode engine, must be valid * @param cb callback when there are input data * @param cb_ctx callback context * @return * - true on success * - false on invalid parameter */ void atDataSetBypassMode(atDataEngine_t *th, atDataBypassCB_t cb, void *cb_ctx); /** * @brief check whether in PPP mode * * @param th data mode engine, must be valid * @return * - true if in PPP mode * - false if not in PPP mode */ bool atDataIsPPPMode(atDataEngine_t *th); /** * @brief check whether in bypass mode * * @param th data mode engine, must be valid * @return * - true if in bypass mode * - false if not in bypass mode */ bool atDataIsBypassMode(atDataEngine_t *th); /** * @brief get the parent dispatch * * @param th data mode engine, must be valid * @return the parent dispatch */ atDispatch_t *atDataGetDispatch(atDataEngine_t *th); /** * @brief get the PPP context * * @param th data mode engine, must be valid * @return the PPP context pointer */ void *atDataEngineGetPppSession(atDataEngine_t *th); /** * @brief clear the pppsession pointer * * @param th data mode engine, must be valid * */ void atDataClearPPPSession(atDataEngine_t *th); /** * @brief create AT cmux mode engine * * @param dispatch parent dispatch of the cmux mode engine * @param cfg cmux configuration * @return * - cmux mode engine pointer * - NULL if out of memory */ atCmuxEngine_t *atCmuxEngineCreate(atDispatch_t *dispatch, const atCmuxConfig_t *cfg); /** * @brief delete AT cmux mode engine * * @param th cmux mode engine, must be valid */ void atCmuxEngineDelete(atCmuxEngine_t *th); /** * @brief push data to cmux engine * * It will be called by dispatch. When dispatch received data, dispatch * will push the data to engine. * * @param th cmux mode engine, must be valid * @param data data to be pushed, can't be NULL if \p size is not 0. * @param size data size * @return * - consumed data size * - -1 if cmux engine is busy */ int atCmuxPushData(atCmuxEngine_t *th, const void *data, size_t size); /** * @brief write data to specified DLC of AT cmux mode engine * * It will wait all data are written (maybe in buffer of AT device). * The data will be sent in UIH packet. * * @param th cmux mode engine, must be valid * @param data data pointer to be write, can't be NULL is size is not 0 * @param size data size * @param dlci DLC number */ void atCmuxDlcWrite(atCmuxEngine_t *th, const void *data, size_t size, int dlci); /** * @brief get the cmux mode engine current configuration * * @param th cmux mode engine, must be valid * @return the cmux mode engine current configuration */ atCmuxConfig_t atCmuxGetConfig(atCmuxEngine_t *th); /** * @brief get max frame size of AT cmux mode engine * * @param th cmux mode engine, must be valid * @return * - max frame size */ int atCmuxMaxFrameSize(atCmuxEngine_t *th); /** * @brief get device of AT cmux mode engine * * @param th cmux mode engine, must be valid * @return * - cmux configuration */ atDevice_t *atCmuxGetDevice(atCmuxEngine_t *th); /** * @brief get the parent dispatch * * @param th cmux mode engine, must be valid * @return the parent dispatch */ atDispatch_t *atCmuxGetDispatch(atCmuxEngine_t *th); /** * @brief Send CTRL msg MSC * * @param th cmux mode engine, must be valid * @param cr 1:ctrl command, 0:ctrl response * @param dlci virtual circuit path * @param v24 v.24 control signal * @param br default 0 */ void atCmuxSendCtrlMSC(atCmuxEngine_t *th, uint8_t cr, uint8_t dlci, uint8_t v24, uint8_t br); /** * @brief callback function for async AT command * * For async command, the callback shall be registered though \a cfwRequestUTI * to wait CFW event with specified UTI, or through \a atSetPendingIdCmd * to wait speficied event ID. When the matching event is arrived, this * callback will be called (and the registration will be removed automatically). */ typedef void (*atCommandAsyncCB_t)(atCommand_t *cmd, const osiEvent_t *event); /** * @brief register an ID pending command * * When the event with specified ID arrived, the callback will be called. * * @param cmd the AT command context * @param id event ID * @param handler the callback to be called * @return * - true if success * - false on error. Refer to \a osiEventDispatchRegister */ bool atSetPendingIdCmd(atCommand_t *cmd, uint32_t id, atCommandAsyncCB_t handler); /** * @brief init at device as an alarm owner */ void atAlarmInit(); /** * @brief schedule a callback running in AT thread * * It is just \p osiThreadCallback with AT thread as parameter. * * @param cb callback to be executed * @param ctx callback context */ void atEngineCallback(osiCallback_t cb, void *ctx); /** * @brief find the channel in data mode * * Now only one channel can be set in data mode (that is, PPP). This will * find the data mode channel if exists. When there are no channel in data * mode it will return NULL. * * @return * - the channel in data mode if exists * - NULL if no channels are in data mode */ atDispatch_t *atFindDataChannel(void); /** * @brief AT dispatch mode switch cause */ typedef enum atModeSwitchCause { /** * @brief start data mode */ AT_MODE_SWITCH_DATA_START, /** * @brief end data mode */ AT_MODE_SWITCH_DATA_END, /** * @brief end data PPP mode * * Refer to \p atDispatchEndDataPppMode. */ AT_MODE_SWITCH_DATA_PPP_END, /** * @brief escape from data mode to command line mode * * The data engine will be kept, and push data to command line engine. * Typical usage is to process command temporally. */ AT_MODE_SWITCH_DATA_ESCAPE, /** * @brief resume data mode from escaped command line mode */ AT_MODE_SWITCH_DATA_RESUME, } atModeSwitchCause_t; void atEngineSchedule(osiCallback_t cb, void *cb_ctx); void atEngineModeSwitch(atModeSwitchCause_t cause, atDispatch_t *d); void atEngineSetDeviceAutoSleep(bool enabled); void atMemFreeLater(void *ptr); void atMemUndoFreeLater(void *ptr); void atEngineEarlyInit(void); void atEngineStart(void); osiThread_t *atEngineGetThreadId(void); bool atEventRegister(uint32_t id, osiEventHandler_t handler); bool atEventsRegister(uint32_t id, ...); void AT_SetAsyncTimerMux(atCmdEngine_t *cmd, uint32_t timeout); bool atCmdEngineIsValid(atCmdEngine_t *cmd); /** * @brief whether there are commands running in any channel * * When channel is not in command mode, the *hold* command won't be regarded * as running command. For example, when a channel enters data mode by ATD * command, the ATD is not regards as running command even it is not finished. * * Usually, it can be use a hint for not blocking at engine. * * @return * -true if there are commands running in any channel * -false if not */ bool atEngineIsCmdRunning(void); /** * @brief AT dispatch ModeSwitch handler function * * @param cmd current ATdispatch pointer * @param cause ModeSwitch cause */ typedef void (*atDispatchModeSwitchHandler_t)(atDispatch_t *th, atModeSwitchCause_t cause); /** * @brief set ModeSwitch handler * * Set AT ModeSwitch handler. At ModeSwitch, \p handler will be * called. * * When \p handler is NULL, the previously registered ModeSwitch handler will * be cleared, through it is not needed in typical cases. * * This *must* be called in AT command handler. * * * @param th the dispatch pointer, must be valid * @param handler ModeSwitch handler */ void atDispatchSetModeSwitchHandler(atDispatch_t *th, atDispatchModeSwitchHandler_t handler); /** * @brief invoke ModeSwitch handler * * Invoke AT ModeSwitch handler. Call handler. * * * @param th the dispatch pointer, must be valid * @param cause ModeSwitch cause */ void atDispatchInvokeModeSwitchHandle(atDispatch_t *th, atModeSwitchCause_t cause); /** * @brief default ppp ModeSwitch handler * * @param th the dispatch pointer, must be valid * @param cause ModeSwitch cause */ void pppAtModeSwitchHandler(atDispatch_t *th, atModeSwitchCause_t cause); /** * @brief create usb serial AT channel * * @param name the usb serial name * @return * - succeed create the channel or fail */ bool atEngineCreateUSerialChannel(uint32_t name); /** * @brief create uart AT channel * * @param name the UART name * @return * - succeed create the channel or fail */ bool atEngineCreateUartChannel(uint32_t name); /** * @brief get AT device ready status * * @param th AT device pointer, must be valid * @return * - ture device ready or fail not ready */ bool atDispatchGetDeviceReadyStatus(atDispatch_t *th); /** * @brief set AT device ready status * * @param th AT device pointer, must be valid * @param bReady Whether device is ready; * @return * NONE */ void atDispatchSetDeviceReadyStatus(atDispatch_t *th, bool bReady); /** * @brief User customize the baud rate * * @param th AT device pointer, must be valid * @return * NONE */ void atCmdDeviceEnableUsrBaud(atCmdEngine_t *th); /** * @brief User customize the icf config * * @param th AT device pointer, must be valid * @return * NONE */ void atCmdDeviceSetUsrFormatNeeded(atCmdEngine_t *th); #ifdef __cplusplus } #endif #endif