diff --git a/app/demo_quec_at/cmdTest.c b/app/demo_quec_at/cmdTest.c index 10a2d92b0a016bc5b8b452ac653c02dd916f7ff7..815acc553edeac62528b78dea163db5e571e96b1 100644 --- a/app/demo_quec_at/cmdTest.c +++ b/app/demo_quec_at/cmdTest.c @@ -8,64 +8,78 @@ ***************************************************************************/ #include "ql_iotAt.h" #include "qhal_Socket.h" +#include "qhal_atCmd.h" #define APP_AT LL_DBG -typedef struct __appSock -{ - TWLLHead_T head; - pointer_t sockFd; -} appSock_T; -static TWLLHead_T *appSockHead = NULL; -#define APP_AT_SOCKET_PORT 4321 +#define APP_AT_SOCKET_PORT 39999 +#define APP_AT_RECV_MAX 5000 void cmdTestSocketSend(pointer_t sockFd, const quint8_t *data, quint32_t len); typedef struct { char *cmd; - qint32_t (*cb)(QIot_atAction_e action, char *retBuf, quint32_t retMaxLen, quint8_t count, char *arg[]); + void (*cb)(qhal_atcmd_t *cmd); } atCmdTable_t; static atCmdTable_t table[] = { - {"QIOTREG", Ql_iotAtQIOTREG}, - {"QIOTSEND", Ql_iotAtQIOTTransTx}, - {"QIOTRD", Ql_iotAtQIOTTransRx}, - {"QIOTCFG", Ql_iotAtQIOTCFG}, - {"QIOTMODELTD", Ql_iotAtQIOTModelTx}, - {"QIOTMODELRD", Ql_iotAtQIOTModelRx}, - {"QIOTMCUVER", Ql_iotAtQIOTMCUVER}, - {"QIOTUPDATE", Ql_iotAtQIOTUPDATE}, - {"QIOTINFO", Ql_iotAtQIOTINFO}, - {"QIOTOTARD", Ql_iotAtQIOTOTARD}, - {"QIOTSTATE", Ql_iotAtQIOTSTATE}, - {"QIOTLOCCFG", Ql_iotAtQIOTLOCCFG}, - {"QIOTLOCRPT", Ql_iotAtQIOTLOCRPT}, + {"QIOTREG", Qhal_atCmdIotAtQIOTREG}, + {"QIOTSEND", Qhal_atCmdIotAtQIOTTransTx}, + {"QIOTRD", Qhal_atCmdIotAtQIOTTransRx}, + {"QIOTCFG", Qhal_atCmdIotAtQIOTCFG}, + {"QIOTMODELTD", Qhal_atCmdIotAtQIOTModelTx}, + {"QIOTMODELRD", Qhal_atCmdIotAtQIOTModelRx}, + {"QIOTMCUVER", Qhal_atCmdIotAtQIOTMCUVER}, + {"QIOTUPDATE", Qhal_atCmdIotAtQIOTUPDATE}, + {"QIOTINFO", Qhal_atCmdIotAtQIOTINFO}, + {"QIOTOTARD", Qhal_atCmdIotAtQIOTOTARD}, + {"QIOTSTATE", Qhal_atCmdIotAtQIOTSTATE}, + {"QIOTLOCIN", Qhal_atCmdIotAtQIOTLOCIN}, + {"QIOTLOCEXT", Qhal_atCmdIotAtQIOTLOCEXT}, + {"QIOTOTAREQ", Qhal_atCmdIotAtQIOTOTARequest}, + #ifdef QUEC_ENABLE_HTTP_OTA + {"QFOTAUP", Qhal_atCmdIotAtQFOTAUP}, + {"QFOTACFG", Qhal_atCmdIotAtQFOTACFG}, + #endif + #ifdef QUEC_ENABLE_GATEWAY + {"QIOTSUBCONN", Qhal_atCmdIotAtQIOTSUBCONN}, + {"QIOTSUBDISCONN", Qhal_atCmdIotAtQIOTSUBDISCONN}, + {"QIOTSUBRD", Qhal_atCmdIotAtQIOTSUBRD}, + {"QIOTSUBSEND", Qhal_atCmdIotAtQIOTSUBSEND}, + {"QIOTSUBTSLRD", Qhal_atCmdIotAtQIOTSUBTSLRD}, + {"QIOTSUBTSLTD", Qhal_atCmdIotAtQIOTSUBTSLTD}, +// {"QIOTSUBINFO", Qhal_atCmdIotAtQIOTSUBINFO}, + {"QIOTSUBHTB", Qhal_atCmdIotAtQIOTSUBHTB}, + #endif {NULL, NULL}}; + +#define AT_SOCKECT_MASK "AT" /************************************************************************** ** 功能 @brief : AT透传模式 ** 输入 @param : ** 输出 @retval: ***************************************************************************/ -static char *cmdTestPassMode(pointer_t sockFd, int dataLen) +static quint32_t cmdTestPassMode(pointer_t sockFd, int dataLen,char **buf) { int ret; int bufLen = 0; - char *buf = malloc(dataLen); - if(NULL == buf) + qint32_t timeoutSum = 10; + *buf = HAL_MALLOC(dataLen); + if(NULL == *buf) { Quos_logPrintf(APP_AT, LL_ERR, "malloc fail"); - return NULL; + return 0; } do { if(SOCKET_FD_INVALID == sockFd) { - ret = read(STDIN_FILENO, buf+bufLen, dataLen-bufLen); + ret = read(STDIN_FILENO, *buf+bufLen, dataLen-bufLen); } else { - ret = read(sockFd, buf+bufLen, dataLen-bufLen); + ret = read(sockFd, *buf+bufLen, dataLen-bufLen); } if(ret < 0) { @@ -73,29 +87,105 @@ static char *cmdTestPassMode(pointer_t sockFd, int dataLen) break; } bufLen += ret; - if(bufLen == dataLen) + if(bufLen >= dataLen) + { + break; + } + sleep(1); + if(timeoutSum > 0) + { + timeoutSum--; + } + else { - return buf; + return 0; } } while (1); - return NULL; + return bufLen; +} + +/************************************************************************** +** 功能 @brief : AT命令参数提取 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void atCmd_argExtract(char *src, qhal_atcmd_t *cmd) +{ + char *args[QHAL_AT_PARAM_MAX]; + quint32_t argNum = 0; + char *p = src; + do + { + qbool isStr = FALSE; + args[argNum] = p; + if(*p == '"') + { + while ((p = HAL_STRSTR(p+1,"\""))) + { + p++; + if(*p == '\0' || *p == ',') + { + isStr = TRUE; + break; + } + } + } + else + { + p = HAL_STRSTR(p,","); + } + if(p && *p == ',') + { + *p++ = '\0'; + } + if(isStr) + { + cmd->params[argNum].type = QHAL_AT_TYPE_STRING; + cmd->params[argNum].val = (quint8_t *)Quos_stringRemoveMarks(args[argNum]); + cmd->params[argNum].len = HAL_STRLEN(args[argNum]); + } + else + { + if(Quos_strIsUInt(args[argNum], HAL_STRLEN(args[argNum]),NULL) == TRUE) + { + cmd->params[argNum].type = QHAL_AT_TYPE_INT; + cmd->params[argNum].val = (quint8_t *)args[argNum]; + } + else + { + cmd->params[argNum].type = QHAL_AT_TYPE_RAW; + cmd->params[argNum].val = (quint8_t *)args[argNum]; + cmd->params[argNum].len = HAL_STRLEN(args[argNum]); + } + } + argNum++; + }while (argNum < QHAL_AT_PARAM_MAX && p && *p != '\0'); + cmd->param_count = argNum; } + /************************************************************************** ** 功能 @brief : AT命令解析 ** 输入 @param : ** 输出 @retval: ***************************************************************************/ -static void atCmdAnalyze(pointer_t sockFd, char *buf) +static void atCmdAnalyze(pointer_t sockFd, char *buf,int len) { #define AT_HEAD "AT+" - if (0 != strncasecmp(buf, AT_HEAD, HAL_STRLEN(AT_HEAD)) || '\n' != buf[HAL_STRLEN(buf) - 1]) + if (0 != HAL_STRNCASECMP(buf, AT_HEAD, HAL_STRLEN(AT_HEAD))) + { + return; + } + else if('\n' != buf[len - 1]) { + cmdTestSocketSend(sockFd, (const quint8_t *)"ERROR\r\n", HAL_STRLEN("ERROR\r\n")); return; } - buf[HAL_STRLEN(buf) - 1] = 0; - if (buf[HAL_STRLEN(buf) - 1] == '\r') + buf[len - 1] = 0; + len--; + if (buf[len - 1] == '\r') { - buf[HAL_STRLEN(buf) - 1] = 0; + buf[len - 1] = 0; + len--; } buf += HAL_STRLEN(AT_HEAD); quint32_t i = 0; @@ -107,30 +197,21 @@ static void atCmdAnalyze(pointer_t sockFd, char *buf) continue; } buf += HAL_STRLEN(table[i].cmd); - char retBuf[QIOT_AT_BUFFER_MAX] = {0}; - char *words[200]; - quint32_t size = 0; - QIot_atAction_e action = QIOT_AT_ACTION_UNKOWN; + qhal_atcmd_t cmd; + cmd.param_count = 0; + cmd.sockFd = sockFd; + cmd.action = QIOT_AT_ACTION_UNKOWN; if ('=' == buf[0]) { if ('?' == buf[1] && '\0' == buf[2]) { Quos_logPrintf(APP_AT, LL_DBG, "AT test"); - action = QIOT_AT_ACTION_TEST; + cmd.action = QIOT_AT_ACTION_TEST; } else if ('\0' != buf[1]) { - quint32_t i; - size = Quos_stringSplit(buf + 1, words, 200, ",", TRUE); - for (i = 0; i < size; i++) - { - while (' ' == words[i][0]) - { - words[i] = &words[i][1]; - } - Quos_stringRemoveMarks(words[i]); - } - action = QIOT_AT_ACTION_WRITE; + atCmd_argExtract(buf + 1, &cmd); + cmd.action = QIOT_AT_ACTION_WRITE; } else { @@ -140,177 +221,151 @@ static void atCmdAnalyze(pointer_t sockFd, char *buf) else if ('?' == buf[0] && '\0' == buf[1]) { Quos_logPrintf(APP_AT, LL_DBG, "AT read"); - action = QIOT_AT_ACTION_READ; + cmd.action = QIOT_AT_ACTION_READ; } else if ('\0' == buf[0]) { - action = QIOT_AT_ACTION_EXEC; + cmd.action = QIOT_AT_ACTION_EXEC; } - - if (QIOT_AT_ACTION_UNKOWN != action) + if (QIOT_AT_ACTION_UNKOWN != cmd.action) { - qint32_t ret; char *passData = NULL; - if((HAL_STRCMP("QIOTSEND",table[i].cmd) == 0 && 2 == size) || - (HAL_STRCMP("QIOTMODELTD",table[i].cmd) == 0 && (2 == size || 3 == size))) - { - Quos_logPrintf(APP_AT, LL_ERR, "need wait data,len:%d",atoi(words[1])); - cmdTestSocketSend(sockFd, (const quint8_t *)"> ", HAL_STRLEN("> ")); - passData = cmdTestPassMode(sockFd,atoi(words[1])); - if(passData) - { - words[size++] = passData; - } - } - ret = table[i].cb(action, retBuf, sizeof(retBuf), size, words); - if (ret == 0) + uint32_t length = 0; + if (((HAL_STRCMP("QIOTSEND",table[i].cmd) == 0) && 2 == cmd.param_count) || + ((HAL_STRCMP("QIOTMODELTD",table[i].cmd) == 0) && (2 == cmd.param_count ||(3 == cmd.param_count && cmd.params[2].type == QHAL_AT_TYPE_INT)))) { - cmdTestSocketSend(sockFd, (const quint8_t *)"OK\r\n", HAL_STRLEN("OK\r\n")); + length = HAL_ATOI((const char *)cmd.params[1].val); } - else if (ret < 0) +#ifdef QUEC_ENABLE_GATEWAY + else if ((HAL_STRCMP("QIOTSUBTSLTD",table[i].cmd) == 0 && ((4 == cmd.param_count && cmd.params[3].type == QHAL_AT_TYPE_INT) || 3 == cmd.param_count)) || + (HAL_STRCMP("QIOTSUBSEND",table[i].cmd) == 0 && 3 == cmd.param_count)) { - cmdTestSocketSend(sockFd, (const quint8_t *)"ERROR\r\n", HAL_STRLEN("ERROR\r\n")); + length = HAL_ATOI((const char *)cmd.params[2].val); } - else +#endif + if (0 != length) { - cmdTestSocketSend(sockFd, (const quint8_t *)retBuf, ret); - cmdTestSocketSend(sockFd, (const quint8_t *)"\r\n\r\nOK\r\n", HAL_STRLEN("\r\n\r\nOK\r\n")); + Quos_logPrintf(APP_AT, LL_ERR, "need wait data,len:%d",length); + cmdTestSocketSend(sockFd, (const quint8_t *)"> ", HAL_STRLEN("> ")); + quint32_t passDataLen = cmdTestPassMode(sockFd,(int)length,&passData); + if(passDataLen) + { + cmd.params[cmd.param_count].type = QHAL_AT_TYPE_PASS; + cmd.params[cmd.param_count].val = (quint8_t*)passData; + cmd.params[cmd.param_count].len = passDataLen; + cmd.param_count++; + } + else + { + cmdTestSocketSend(sockFd, (const quint8_t *)"ERROR\r\n", HAL_STRLEN("ERROR\r\n")); + if(passData) + { + HAL_FREE(passData); + } + i++; + continue; + } } + table[i].cb(&cmd); if(passData) { - free(passData); + HAL_FREE(passData); } } - i++; - } -} -/************************************************************************** -** 功能 @brief : -** 输入 @param : -** 输出 @retval: -***************************************************************************/ -static void *cmdTestTask(void *arg) -{ - fd_set rset; - UNUSED(arg); - while (1) - { - qint32_t bufLen; - quint8_t buf[1024]; - FD_ZERO(&rset); - FD_SET(STDIN_FILENO, &rset); - int result = select(STDIN_FILENO + 1, &rset, NULL, NULL, NULL); - if (result > 0 && (bufLen = read(STDIN_FILENO, buf, sizeof(buf))) > 0) + else { - buf[bufLen] = 0; - atCmdAnalyze(SOCKET_FD_INVALID, (char *)buf); + cmdTestSocketSend(sockFd, (const quint8_t *)"ERROR\r\n", HAL_STRLEN("ERROR\r\n")); } + i++; } - return NULL; } + /************************************************************************** -** 功能 @brief : +** 功能 @brief : TCP客户端数据发送 ** 输入 @param : ** 输出 @retval: ***************************************************************************/ void cmdTestSocketSend(pointer_t sockFd, const quint8_t *data, quint32_t len) { - TWLLHead_T *temp, *next; + if(NULL == data || 0 == len) + { + return ; + } Quos_logPrintf(APP_AT, LL_DBG, "data[%d]:\n%s", len, data); if (SOCKET_FD_INVALID == sockFd) { - TWLIST_FOR_DATA(appSockHead, temp, next) + void *chlList[100]; + quint32_t count = Quos_socketGetChlFdList(SOCKET_TYPE_TCP_CLI, (void*)AT_SOCKECT_MASK, chlList,sizeof(chlList)/sizeof(chlList[0])); + while (count--) { - appSock_T *listTemp = __GET_STRUCT_BY_ELEMENT(temp, appSock_T, head); - sockFd = listTemp->sockFd; + quint8_t *newData = HAL_MEMDUP(data, len); + if(newData) + { + Quos_socketTxDisorder(chlList[count],NULL,(quint8_t*)newData, len); + } } } - if(data && len) + else { - send(sockFd, data, len, 0); + Quos_socketChlInfoNode_t *node = (Quos_socketChlInfoNode_t *)Quos_socketGetChlFd(sockFd,SOCKET_TYPE_TCP_CLI); + if(node) + { + quint8_t *newData = HAL_MEMDUP(data, len); + if(newData) + { + Quos_socketTxDisorder(node,NULL,(quint8_t*)newData, len); + } + } } } + /************************************************************************** -** 功能 @brief : +** 功能 @brief : TCP客户端数据接收 ** 输入 @param : ** 输出 @retval: ***************************************************************************/ -static void *cmdTestSocketRecvTask(void *arg) +static qbool FUNCTION_ATTR_ROM cmdTestSocketRecv(void *chlFd, const void *peer, quint32_t peerSize, Quos_socketRecvDataNode_t *recvData) { - pointer_t sockFd = (pointer_t)arg; - while (1) + UNUSED(peer); + UNUSED(peerSize); + Quos_socketChlInfoNode_t *chlNode = (Quos_socketChlInfoNode_t *)chlFd; + if(NULL == recvData) { - fd_set rset; - FD_ZERO(&rset); - FD_SET(sockFd, &rset); - int result = select(sockFd + 1, &rset, NULL, NULL, NULL); - if (result < 0) - { - break; - } - else if (result > 0) - { - quint8_t buf[1024]; - qint32_t bufLen = read(sockFd, buf, sizeof(buf)); - if (bufLen > 0) - { - buf[bufLen] = '\0'; - Quos_logPrintf(APP_AT, LL_DBG, "recv:%s", buf); - atCmdAnalyze(sockFd, (char *)buf); - } - else - { - break; - } - } - } - Quos_logPrintf(APP_AT, LL_DBG, "fd[%ld] disconnect", sockFd); - TWLLHead_T *temp, *next; - TWLIST_FOR_DATA(appSockHead, temp, next) - { - appSock_T *listTemp = __GET_STRUCT_BY_ELEMENT(temp, appSock_T, head); - if (listTemp->sockFd == sockFd) - { - Quos_twllHeadDelete(&appSockHead, temp); - free(listTemp); - } + Quos_logPrintf(APP_AT, LL_DBG,"socket disconnect"); + return TRUE; } - return NULL; + Quos_logPrintf(APP_AT, LL_DBG,"recv data:%.*s",recvData->bufLen,recvData->Buf); + atCmdAnalyze(chlNode->sockFd, (char *)recvData->Buf,recvData->bufLen); + return TRUE; } + /************************************************************************** -** 功能 @brief : +** 功能 @brief : 局域网监听新的TCP客户端连接 ** 输入 @param : ** 输出 @retval: ***************************************************************************/ -static void *cmdTestSocketTask(void *arg) +static qbool FUNCTION_ATTR_ROM cmdTestClientListen(void *chlFd, const void *peer, quint32_t peerSize, Quos_socketRecvDataNode_t *recvData) { - quint32_t len; - pointer_t fd = (pointer_t)arg; - Quos_logPrintf(APP_AT, LL_DBG, "fd[%ld]", fd); - - struct sockaddr_in client; - bzero(&client, sizeof(client)); - len = sizeof(client); - - while (1) + UNUSED(chlFd); + UNUSED(peer); + UNUSED(peerSize); + if(NULL == recvData) { - pthread_t pthreadId; - pointer_t appAtFd = accept(fd, (struct sockaddr *)&client, &len); - if (0 != pthread_create(&pthreadId, NULL, (void *)cmdTestSocketRecvTask, (void *)(pointer_t)appAtFd)) - { - close(appAtFd); - break; - } - appSock_T *listNew = (appSock_T *)malloc(sizeof(appSock_T)); - listNew->sockFd = appAtFd; - if (listNew == NULL) - { - break; - } - Quos_twllHeadAdd(&appSockHead, &listNew->head); + return FALSE; } - return NULL; + Quos_socketChlInfoNode_t chlInfo; + HAL_MEMCPY(&chlInfo,recvData->Buf,recvData->bufLen); + Quos_logPrintf(APP_AT, LL_DBG,"new cliend sockFd:"PRINTF_FD,chlInfo.sockFd); + chlInfo.io.send = Qhal_sockWrite; + chlInfo.send.txCnt = 1; + chlInfo.send.timeout = 2000; + chlInfo.recvDataFunc = cmdTestSocketRecv; + chlInfo.io.close = Qhal_sockClose; + chlInfo.param = AT_SOCKECT_MASK; + Quos_socketChannelAdd(NULL,chlInfo); + return TRUE; } + /************************************************************************** ** 功能 @brief : ** 输入 @param : @@ -318,11 +373,17 @@ static void *cmdTestSocketTask(void *arg) ***************************************************************************/ void CmdTestInit(void) { - pthread_t pthreadId; - pthread_t pthreadSocketId; - quint8_t sockType; - pointer_t fd = Qhal_tcpServerInit(&sockType, APP_AT_SOCKET_PORT, 1); - Quos_logPrintf(APP_AT, LL_DBG, "fd[%ld]", fd); - pthread_create(&pthreadSocketId, NULL, (void *)cmdTestSocketTask, (void *)fd); - pthread_create(&pthreadId, NULL, (void *)cmdTestTask, NULL); + Quos_socketChlInfoNode_t chlInfo; + HAL_MEMSET(&chlInfo, 0, sizeof(Quos_socketChlInfoNode_t)); + chlInfo.sockFd = Qhal_tcpServerInit(&chlInfo.type, APP_AT_SOCKET_PORT, 100); + Quos_logPrintf(APP_AT, LL_DBG, "fd:" PRINTF_FD, chlInfo.sockFd); + if (SOCKET_FD_INVALID == chlInfo.sockFd) + { + Quos_logPrintf(APP_AT, LL_ERR, "listening port failed"); + return; + } + chlInfo.send.txCnt = 1; + chlInfo.send.timeout = 2000; + chlInfo.recvDataFunc = cmdTestClientListen; + Quos_socketChannelAdd(NULL, chlInfo); } diff --git a/app/demo_quec_openc/coap/main_coap.c b/app/demo_quec_openc/coap/main_coap.c new file mode 100644 index 0000000000000000000000000000000000000000..8c606d304a39073c8e95ada2b3ba21eca6c80f0d --- /dev/null +++ b/app/demo_quec_openc/coap/main_coap.c @@ -0,0 +1,198 @@ +/************************************************************************* +** 创建人 @author : 吴健超 JCWu +** 版本 @version : V1.0.0 原始版本 +** 日期 @date : +** 功能 @brief : +** 硬件 @hardware:任何ANSI-C平台 +** 其他 @other : +***************************************************************************/ +#include "Ql_iotApi.h" +#include "ql_iotSecure.h" +#include "Qhal_driver.h" +#include "ql_iotDp.h" +void *coapFd = NULL; +quint8_t token19_0_0[8]; + +#define DEV_UUID "868626047808496" +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void CoapSocketRecvNodeCb(void *chlFd, const void *sendData, const void *recvData) +{ + printf("CoapSocketRecvNodeCb recvData:%p\n", recvData); + if (recvData) + { + Coap_Message_t *msg = (Coap_Message_t *)recvData; + printf("code:%s\n", COAP_HEAD_CODE_STRING(msg->head.code)); + } + UNUSED(chlFd); + UNUSED(sendData); +} +/************************************************************************** +** 功能 @brief : coap协议测试 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool CoapAuthRecvHandle(void *chlFd, const Coap_Message_t *coapMsg, Coap_Message_t *retCoapMsg) +{ + UNUSED(chlFd); + UNUSED(coapMsg); + printf("CoapAuthRecvHandle coapMsg:%p\n", coapMsg); + if (COAP_HCODE_DELETE == coapMsg->head.code) + { + printf("CoapRecvNotify:%s\n", COAP_HEAD_CODE_STRING(COAP_HCODE_DELETE)); + Quos_coapHeadSet(retCoapMsg, COAP_HTYPE_ACK, COAP_HCODE_DELETED_202, coapMsg->head.mid, coapMsg->head.tokenLen, coapMsg->token); + return TRUE; + } + else if (COAP_HCODE_PUT == coapMsg->head.code) + { + char *uri = Quos_coapOptionGetPath(coapMsg); + printf("CoapRecvNotify:%s url[%s]\n", COAP_HEAD_CODE_STRING(COAP_HCODE_PUT), uri); + HAL_FREE(uri); + Quos_coapHeadSet(retCoapMsg, COAP_HTYPE_ACK, COAP_HCODE_CHANGED_204, coapMsg->head.mid, coapMsg->head.tokenLen, coapMsg->token); + return TRUE; + } + else if (COAP_HCODE_POST == coapMsg->head.code) + { + printf("CoapRecvNotify:%s\n", COAP_HEAD_CODE_STRING(COAP_HCODE_POST)); + Quos_coapHeadSet(retCoapMsg, COAP_HTYPE_ACK, COAP_HCODE_EMPTY, coapMsg->head.mid, 0, NULL); + Coap_Message_t bsEndMsg; + HAL_MEMSET(&bsEndMsg, 0, sizeof(Coap_Message_t)); + Quos_coapHeadSet(&bsEndMsg, COAP_HTYPE_CON, COAP_HCODE_CHANGED_204, 0, coapMsg->head.tokenLen, coapMsg->token); + Quos_coapMsgSend(chlFd, NULL, &bsEndMsg, CoapSocketRecvNodeCb, FALSE); + return TRUE; + } + return FALSE; +} +/************************************************************************** +** 功能 @brief : coap协议测试 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool CoapConnRecvHandle(void *chlFd, const Coap_Message_t *coapMsg, Coap_Message_t *retCoapMsg) +{ + UNUSED(chlFd); + UNUSED(coapMsg); + printf("CoapConnRecvHandle coapMsg:%p\n", coapMsg); + + if (COAP_HCODE_GET == coapMsg->head.code) + { + char *path = Quos_coapOptionGetPath(coapMsg); + printf("path[%s]\n", path); + if (0 == HAL_STRCMP(path, "/19/0/0")) + { + HAL_MEMCPY(token19_0_0, coapMsg->token, coapMsg->head.tokenLen); + printf("save observe(19/0/0) token\n"); + } + Quos_coapHeadSet(retCoapMsg, COAP_HTYPE_ACK, COAP_HCODE_CONTENT_205, coapMsg->head.mid, coapMsg->head.tokenLen, coapMsg->token); + return TRUE; + } + else if (COAP_HCODE_PUT == coapMsg->head.code) + { + char *path = Quos_coapOptionGetPath(coapMsg); + printf("path[%s]\n", path); + if (0 == HAL_STRCMP(path, "/19/1/0")) + { + printf("recv bus data\n"); + Quos_logHexDumpData(coapMsg->payload.val, coapMsg->payload.len); + Quos_coapHeadSet(retCoapMsg, COAP_HTYPE_ACK, COAP_HCODE_CHANGED_204, coapMsg->head.mid, coapMsg->head.tokenLen, coapMsg->token); + return TRUE; + } + } + return FALSE; +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +extern quint32_t ql_iotDpFormat(quint8_t **buf, quint16_t pId, quint16_t cmd, const quint8_t *payload, quint32_t payloadLen); +void CoapTestDataNotify(void) +{ + static quint16_t id = 0; + char *srcData = "hello world,quecthing"; + + Coap_Message_t msg; + HAL_MEMSET(&msg, 0, sizeof(Coap_Message_t)); + Quos_coapHeadSet(&msg, COAP_HTYPE_NON, COAP_HCODE_CONTENT_205, 0, 8, token19_0_0); + Quos_coapOptionSetNumber(&msg, COAP_OTYPE_OBSERVE, 0); + Quos_coapOptionSetNumber(&msg, COAP_OTYPE_CONTENT_TYPE, COAP_OCTYPE_APP_OCTET_STREAM); + quint8_t *pkg = NULL; + quint32_t pkgLen = ql_iotDpFormat(&pkg, ++id, 0x0024, (quint8_t *)srcData, HAL_STRLEN(srcData)); + if (pkg) + { + Quos_coapPayloadSet(&msg, pkg, pkgLen); + Quos_coapMsgSend(coapFd, NULL, &msg, NULL, FALSE); + } +} +/************************************************************************** +** 功能 @brief : 程序初始化入口 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +int main(void) +{ + /* 初始化quecsdk */ + Ql_iotInit(); + +#if 1 + if (FALSE == Quos_coapInit(&coapFd, "220.180.239.212:8258", CoapAuthRecvHandle)) + { + printf("Quos_coapInit fail\n"); + return -1; + } + + Coap_Message_t coapMsg; + Quos_coapHeadSet(&coapMsg, COAP_HTYPE_CON, COAP_HCODE_POST, 0, 8, NULL); + char *payload = Ql_iotSecureGenCoapAuthPayload("p1145q", "WjJRSEp1c2x1ckU2", DEV_UUID); + Quos_coapPayloadSet(&coapMsg, payload, HAL_STRLEN(payload)); + Quos_coapMsgSend(coapFd, "/bs", &coapMsg, CoapSocketRecvNodeCb, FALSE); +#elif 0 + if (FALSE == Quos_coapInit(&coapFd, "220.180.239.212:8257", CoapConnRecvHandle)) + { + printf("Quos_coapInit fail\n"); + return -1; + } + + char *data = "LZ3oAdAUpizTf0YXID7XWMeYYuNPgqNxByo/ISFiJRQCuV9om2ApZwE4ZLEIfQe7"; + char *ds = Ql_iotSecureDecodeDs("WjJRSEp1c2x1ckU2", (quint8_t *)data, HAL_STRLEN(data)); + printf("ds:%s\n", ds); + char *ep = Ql_iotSecureGenCoapConnEndpoint("p1145q", "WjJRSEp1c2x1ckU2", DEV_UUID, ds); + HAL_FREE(ds); + printf("ep:%s\n", ep); + char *option = HAL_MALLOC(HAL_STRLEN("rd?b=U&lwm2m=1.0<=300000&ep=") + HAL_STRLEN(ep) + 1); + HAL_SPRINTF(option, "%s%s", "rd?b=U&lwm2m=1.0<=300000&ep=", ep); + HAL_FREE(ep); + Coap_Message_t coapMsg; + Quos_coapHeadSet(&coapMsg, COAP_HTYPE_CON, COAP_HCODE_POST, 0, 8, NULL); + Quos_coapOptionSetPath(&coapMsg, option); + Quos_coapPayloadSet(&coapMsg, NULL, 0); + Quos_coapMsgSend(coapFd, NULL, &coapMsg, CoapSocketRecvNodeCb, FALSE); +#else + if (FALSE == Quos_coapInit(&coapFd, "221.229.214.202:5683", CoapConnRecvHandle)) + { + printf("Quos_coapInit fail\n"); + return -1; + } + + char *payload = HAL_MALLOC(56); + HAL_STRCPY(payload, ";rt=\"oma.lwm2m\",,,,,"); + char *option = HAL_MALLOC(HAL_STRLEN("rd?b=U&lwm2m=1.0<=86400&ep=") + HAL_STRLEN(DEV_UUID) + 1); + HAL_SPRINTF(option, "%s%s", "rd?b=U&lwm2m=1.0<=300000&ep=", DEV_UUID); + Coap_Message_t coapMsg; + Quos_coapHeadSet(&coapMsg, COAP_HTYPE_CON, COAP_HCODE_POST, 0, 8, NULL); + Quos_coapOptionSetPath(&coapMsg, option); + Quos_coapPayloadSet(&coapMsg, payload, HAL_STRLEN(payload)); + Quos_coapMsgSend(coapFd, NULL, &coapMsg, CoapSocketRecvNodeCb, FALSE); +#endif + + while (1) + { + QIot_state_e status = Ql_iotGetWorkState(); + printf("work status:%d\r\n", status); + sleep(10); + CoapTestDataNotify(); + } +} diff --git a/app/demo_quec_openc/Ql_iotMain.c b/app/demo_quec_openc/mqtt/Ql_iotMain.c similarity index 68% rename from app/demo_quec_openc/Ql_iotMain.c rename to app/demo_quec_openc/mqtt/Ql_iotMain.c index ee5f82956c050324ae962463dd9b0bcd2f1d8fe6..f553da3d356b8b10ba75a27bfd288ed74215a607 100644 --- a/app/demo_quec_openc/Ql_iotMain.c +++ b/app/demo_quec_openc/mqtt/Ql_iotMain.c @@ -1,313 +1,343 @@ -/************************************************************************* -** 创建人 @author : 吴健超 JCWu -** 版本 @version : V1.0.0 原始版本 -** 日期 @date : -** 功能 @brief : -** 硬件 @hardware:任何ANSI-C平台 -** 其他 @other : -***************************************************************************/ -#include "Ql_iotApi.h" -#include "Qhal_driver.h" -#define QIOT_MQTT_REGISTER_URL "http://iot-south.quectel.com:2883" -#define QIOT_MQTT_PRODUCT_KEY "p1115X" -#define QIOT_MQTT_PRODUCT_SECRET "d2c5Q1FsVWpwT1k3" - -#define QIOT_COAP_BOOTSTRAP_URL "coap://220.180.239.212:8416" -#define QIOT_COAP_PRODUCT_KEY "MXJac1VyQUV1emZj" -#define QIOT_COAP_PRODUCT_SECRET "NlZGU3JUR0pYRGlR" - -#define QIOT_MCU_COMPONENT_NO "MCU" -#define QIOT_MCU_VERSION "1" - -#define LAPP_MAIN LL_DBG - - -/************************************************************************** -** 功能 @brief : -** 输入 @param : -** 输出 @retval: -***************************************************************************/ -void FUNCTION_ATTR_ROM Ql_iotTtlvHandle(const void *ttlvHead) -{ - quint32_t count = Ql_iotTtlvCountGet(ttlvHead); - quint32_t i; - for(i=0;iparm; + *tout = TRUE; +} + +/************************************************************************** +** 功能 @brief : 统计丢包率 阻塞 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void ql_lossrate_task(void) +{ + quint16_t i = 0, j = 0; + quint16_t mode = 1; + quint32_t responseTime; + Systick_T pretime, nextime; + quint64_t averageTime = 0; + qbool timeout = FALSE; + float lossrate = 0.0, averageTime_f = 0.0; + while (i < QLDEMO_NETCHECKTIMES) + { + i++; + Quos_swTimerStart(&QIot_netcheckt, "NET", SWT_ONE_SECOND * 5, 0, ql_iotNetcheckTimeoutCB, &timeout); + Ql_iotCmdBusPassTransSend(mode, (quint8_t *)QLDEMO_NETCHECKSTR, sizeof(QLDEMO_NETCHECKSTR)); + timeout = FALSE; + pretime = Quos_sysTickGet(); + do + { + usleep(1000); + } while ((ql_transSend_flag == TRANSDATA_NONACK) && (!timeout)); + switch (ql_transSend_flag) + { + case TRANSDATA_SUCCEED: + { + j++; + nextime = Quos_sysTickGet(); + responseTime = Quos_sysTickdiff(pretime, nextime, TRUE); + averageTime += responseTime; + break; + } + case TRANSDATA_FAILED: + + case TRANSDATA_NONACK: /* timeout */ + { + HAL_PRINTF("connection failed. check connection\r\n"); + break; + } + default: + + break; + } + Quos_swTimerDelete(QIot_netcheckt); + ql_transSend_flag = TRANSDATA_NONACK; + sleep(1); + } + if (j) + { + averageTime /= j; + } + averageTime_f = averageTime; + averageTime_f /= 1000; + if (i) + { + lossrate = (float)(i - j) / (float)i; + } + else + lossrate = 1.0; + printf("message sended %d times, pkg lossrate is %.3f%%.\r\n", i, lossrate * 100); + printf("average responsetime is %.3f seconds.\r\n", averageTime_f); +} + +/************************************************************************** +** 功能 @brief : 程序初始化入口 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +int FUNCTION_ATTR_ROM main(void) +{ + /* 初始化quecsdk */ + Ql_iotInit(); + /* 注册事件回调函数 */ + Ql_iotConfigSetEventCB(Ql_iotEventCB); + /* 配置产品信息*/ + Ql_iotConfigSetProductinfo(QIOT_MQTT_PRODUCT_KEY, QIOT_MQTT_PRODUCT_SECRET); + /* 配置服务器信息,可选,默认连接MQTT生产环境服务器 */ + Ql_iotConfigSetServer(QIOT_PPROTOCOL_MQTT, QIOT_MQTT_REGISTER_URL); + /* 启动云平台连接 */ + Ql_iotConfigSetConnmode(QIOT_CONNMODE_REQ); + while (1) + { + QIot_state_e status = Ql_iotGetWorkState(); + printf("work status:%d\r\n", status); + ql_lossrate_task(); + sleep(100); + } +} diff --git a/app/demo_quec_python/Ql_iotMain.py.bak b/app/demo_quec_python/Ql_iotMain.py.bak deleted file mode 100644 index 554d6840045234ccaef1efea9c0c26b81f12cbb8..0000000000000000000000000000000000000000 Binary files a/app/demo_quec_python/Ql_iotMain.py.bak and /dev/null differ diff --git a/app/demo_quec_python/Ql_iotMain_Temp.py b/app/demo_quec_python/Ql_iotMain_Temp.py deleted file mode 100644 index df64e0a68a6da309680feb33f6d2e89c202335d0..0000000000000000000000000000000000000000 --- a/app/demo_quec_python/Ql_iotMain_Temp.py +++ /dev/null @@ -1,205 +0,0 @@ -# Copyright 2020 - 2021 quectel -# -*- coding: utf-8 -*- -# @Time : 2021-03-26 -# @Author : evan.li -# @File : Ql_iotMain.py -# @Brief : quecthing -# @revise : -# 2021-05-26 add get_battery_vol - -import quecIot -import misc -import utime as time -import pm -import osTimer -from machine import Pin -from machine import I2C - -DEMO_VERSION = '21053101' - - -data_trans_ready = False -gpio_toggle_flag = False - -def get_battery_vol(): - """ - 鑾峰彇鐢垫睜鐢靛帇锛屽崟浣峬V - """ - return misc.Power.getVbatt() - - -class aht10class(): - i2c_dev = None - i2c_addre = None - - # Initialization command - AHT10_CALIBRATION_CMD = 0xE1 - # Trigger measurement - AHT10_START_MEASURMENT_CMD = 0xAC - # reset - AHT10_RESET_CMD = 0xBA - - def write_data(self, data): - self.i2c_dev.write(self.i2c_addre, - bytearray(0x00), 0, - bytearray(data), len(data)) - pass - - def read_data(self, length): - r_data = [0x00 for i in range(length)] - r_data = bytearray(r_data) - self.i2c_dev.read(self.i2c_addre, - bytearray(0x00), 0, - r_data, length, - 0) - return list(r_data) - - def aht10_init(self, addre=0x38): - self.i2c_dev = I2C(I2C.I2C0, I2C.STANDARD_MODE) # 杩斿洖i2c瀵硅薄 - self.i2c_addre = addre - self.sensor_init() - pass - - def aht10_transformation_temperature(self, data): - r_data = data - #銆鏍规嵁鏁版嵁鎵嬪唽鐨勬弿杩版潵杞寲娓╁害 - humidity = (r_data[0] << 12) | ( - r_data[1] << 4) | ((r_data[2] & 0xF0) >> 4) - humidity = (humidity/(1 << 20)) * 100.0 - print("current humidity is {0}%".format(humidity)) - temperature = ((r_data[2] & 0xf) << 16) | ( - r_data[3] << 8) | r_data[4] - temperature = (temperature * 200.0 / (1 << 20)) - 50 - print("current temperature is {0}掳C".format(temperature)) - return humidity, temperature - - - def sensor_init(self): - # calibration - self.write_data([self.AHT10_CALIBRATION_CMD, 0x08, 0x00]) - time.sleep_ms(300) # at last 300ms - pass - - def ath10_reset(self): - self.write_data([self.AHT10_RESET_CMD]) - time.sleep_ms(20) # at last 20ms - - def trigger_measurement(self): - # Trigger data conversion - self.write_data([self.AHT10_START_MEASURMENT_CMD, 0x33, 0x00]) - time.sleep_ms(200) # at last delay 75ms - # check has success - r_data = self.read_data(6) - # check bit7 - if (r_data[0] >> 7) != 0x0: - print("Conversion has error") - return None - else: - return self.aht10_transformation_temperature(r_data[1:6]) - - -def i2c_aht10_test(): - ath_dev = aht10class() - ath_dev.aht10_init() - - # 娴嬭瘯鍗佹 - for i in range(10): - ath_dev.Trigger_measurement() - time.sleep(1) - - -class Quecthing: - def __init__(self): - """ 鍒濆鍖杚ucsdk """ - quecIot.init() - """ 娉ㄥ唽浜嬩欢鍥炶皟鍑芥暟 """ - quecIot.setEventCB(self.eventCB) - """ 閰嶇疆浜у搧淇℃伅""" - quecIot.setProductinfo("p1116a", "UHg1dTRBRVh3MkVG") - """ 閰嶇疆鏈嶅姟鍣ㄤ俊鎭紝鍙夛紝榛樿杩炴帴MQTT鐢熶骇鐜鏈嶅姟鍣 """ - quecIot.setServer(1,"http://iot-south.quectel.com:2883") - """ 閰嶇疆lifetime锛屽彲閫夛紝MQTT榛樿涓120 """ - quecIot.setLifetime(120) - """ 閰嶇疆澶栭儴MCU鏍囪瘑鍙峰拰鐗堟湰鍙凤紝鍙夛紝濡傛病鏈夊閮∕CU鍒欎笉闇瑕侀厤缃 """ - quecIot.setMcuVersion("MCU1", "1_0_0") - - """ 鍒涘缓瀹氭椂鍣ㄤ换鍔 """ - ostimer = osTimer() - """ 姣忓崄绉掕皟鐢ㄤ竴娆″洖璋冨嚱鏁 """ - ostimer.start(10000, 1, self.mainTask) - - """" 鍒涘缓gpio瀵硅薄 """ - self.gpio1 = Pin(Pin.GPIO1, Pin.OUT, Pin.PULL_DISABLE, 0) - - """ 鍒濆鍖朼ht10 """ - self.ath_dev = aht10class() - self.ath_dev.aht10_init() - - """ 璁剧疆鑷姩浼戠湢妯″紡 """ - pm.autosleep(1) - - """ 鍚姩浜戝钩鍙拌繛鎺 """ - quecIot.setConnmode(1) - - @staticmethod - def eventCB(data): - print("\r\n{},{}\r\n".format(str(data[0]), str(data[1]))) - if len(data) == 3: - print(data[2]) - """ - 娴嬭瘯鍙戦佺墿妯″瀷鏁版嵁 - 鍚戝钩鍙板彂閫佹暟鎹渶瑕佸湪杩斿洖3, 10200涔嬪悗杩涜 - """ - if 1 == data[0] and 10422 == data[1]: - quecIot.setConnmode(0) - exit(0) - elif 3 == data[0] and 10200 == data[1]: - global data_trans_ready - data_trans_ready = True - - - """ 鍙戦乥ool鍨嬫暟鎹""" - quecIot.phymodelReport(1, {2: True}) - """ 鍙戦佹暟鍊 """ - # 鏁存暟 - quecIot.phymodelReport(1, {3: 123}) - # 娴偣鏁 - quecIot.phymodelReport(1, {9: 123.123}) - """ 鍙戦乤rray """ - quecIot.phymodelReport(1, {4: [1, 2, 3]}) - """ 鍙戦佺粨鏋勪綋 """ - quecIot.phymodelReport(1, {6: {8: 1.0, 7: 1.0}}) - - """ 鍙戦佷腑鏂,閫忎紶鏁版嵁鍜岀墿妯″瀷鏁版嵁鏃犳硶鍚屾椂鍦ㄥ钩鍙拌皟璇 """ - - """ - bytes_temp = bytes('涓枃'.encode('utf-8')) - quecIot.passTransSend(1, bytes_temp) - """ - - def mainTask(self, argv): - global data_trans_ready - global gpio_toggle_flag - """ - 涓讳换鍔,涓婃姤鐢垫睜鐢靛帇 - """ - if data_trans_ready: - print('main task') - """ 鑾峰彇鐢靛帇 """ - battery_vol = get_battery_vol() - - temperature = self.ath_dev.trigger_measurement() - """ 鍙戦佺墿妯″瀷鏁版嵁 """ - quecIot.phymodelReport(0, {110 : battery_vol}) - quecIot.phymodelReport(0, {111 : temperature}) - - """ 缈昏浆寮曡剼鐢靛钩 """ - # gpio_toggle_flag = not gpio_toggle_flag - # self.gpio1.write(int(gpio_toggle_flag)) - - - -if __name__ == '__main__': - print('\r\n**********\r\n') - print(DEMO_VERSION) - quecthing = Quecthing() diff --git a/app/demo_quec_python/example1.py b/app/demo_quec_python/example1.py new file mode 100644 index 0000000000000000000000000000000000000000..48ebbe3e0b56e61d86df6624d07fccc0efe55714 --- /dev/null +++ b/app/demo_quec_python/example1.py @@ -0,0 +1,83 @@ +# 璁剧疆GPIO楂樼數骞冲苟璁剧疆瀹氭椂鍣ㄦ寚瀹氭椂闀垮悗鎷変綆GPIO + +import quecIot +from machine import Timer +from machine import Pin + +timer1 = None +TimerCB = None +Gpio_relay = None +remaining_time =0 + +class Quecthing: + + def __init__(self): + global Gpio_relay + global timer1 + global TimerCB + + """ 鍒濆鍖杚ucsdk """ + quecIot.init() + """ 娉ㄥ唽浜嬩欢鍥炶皟鍑芥暟 """ + quecIot.setEventCB(self.eventCB) + """ 閰嶇疆浜у搧淇℃伅""" + quecIot.setProductinfo("p1117y", "OFZCcWt1TjVUeUdn") + """ 鍚姩浜戝钩鍙拌繛鎺 """ + quecIot.setConnmode(1) + timer1 = Timer(Timer.Timer1) + TimerCB = self.timerTask + Gpio_relay = Pin(Pin.GPIO10, Pin.OUT, Pin.PULL_DISABLE, 0) + + @staticmethod + def eventCB(data): + global Gpio_relay + global timer1 + global TimerCB + global remaining_time + + print(str(data[0]) + "," + str(data[1])) + if len(data) == 3: + print(data[2]) + + if 5 == data[0] and 10210 == data[1]: + model = data[2] + print(model.keys()) + model_keys = list(model.keys()) + for cmdId in model_keys: + value = model.get(cmdId); + print("ctrl cmdId:"+str(cmdId)) + print(value) + if 2 == cmdId: + Gpio_relay.write(1) + remaining_time = value + timer1.stop() + timer1.start(period=60 * 1000,mode=Timer.PERIODIC, callback=TimerCB) + + elif 5 == data[0] and 10211 == data[1]: + res_data = dict() + msg = data[2] + pkgId = msg[0] + + for cmdId in msg[1]: + if 1 == cmdId: + res_data[cmdId]=Gpio_relay.read() + elif 2 == cmdId: + res_data[cmdId]=remaining_time + quecIot.phymodelAck(0, pkgId, res_data) + print("read") + print(res_data) + + def timerTask(self, t): + global Gpio_relay + global remaining_time + remaining_time =remaining_time-1 + if 0 == remaining_time: + Gpio_relay.write(0) + res_data = dict() + res_data[1]=Gpio_relay.read() + quecIot.phymodelReport(1,res_data) + print("timeout") + + +if __name__ == '__main__': + Quecthing() diff --git a/app/demo_quec_python/Ql_iotMain.py b/app/demo_quec_python/example2.py similarity index 33% rename from app/demo_quec_python/Ql_iotMain.py rename to app/demo_quec_python/example2.py index 2bc2d9ab04ca1a419e1496d7a81408144e9bdd92..a5e7f365cb7d8f10b8b19b674cfd140ae05f01ae 100644 --- a/app/demo_quec_python/Ql_iotMain.py +++ b/app/demo_quec_python/example2.py @@ -1,145 +1,52 @@ -# Copyright 2020 - 2021 quectel -# -*- coding: utf-8 -*- -# @Time : 2021-03-26 -# @Author : evan.li -# @File : Ql_iotMain.py -# @Brief : quecthing -# @revise : -# 2021-05-26 add get_battery_vol - -import quecIot -import misc -import utime as time -import pm -import osTimer -import uos -from machine import Pin - -DEMO_VERSION = '21060101' - - -data_trans_ready = False -gpio_toggle_flag = False - -def get_battery_vol(): - """ - 鑾峰彇鐢垫睜鐢靛帇锛屽崟浣峬V - """ - return misc.Power.getVbatt() - -""" - 妯$粍OTA鍗囩骇鍜宲ython 鑴氭湰鍗囩骇 -""" -def ota_event(event): - if 7 == event[0] and 10700 == event[1]: - """ 妫鏌ョ粍浠舵爣蹇, 缁勪欢鏍囧織鍦ㄥ钩鍙板垱寤 """ - if "SCRIPT" in event[2]: - quecIot.otaAction(1) - elif "IMEI" in event[2]: - quecIot.otaAction(1) - elif 7 == event[0] and 10701 == event[1]: - pass - elif 7 == event[0] and 10703 == event[1]: - if "SCRIPT" in event[2]: - - uos.rename('usr/demo_quecthing.py', 'usr/demo_quecthing.bk') - uos.rename('usr/qiot_ota.bin', 'usr/demo_quecthing.py') - - """ 璁剧疆鐗堟湰, 涓婃姤鍗囩骇鎴愬姛""" - quecIot.setMcuVersion('SCRIPT', 'v2') - elif "IMEI" in event[2]: - pass - - -class Quecthing: - def __init__(self): - """ 鍒濆鍖杚ucsdk """ - quecIot.init() - """ 娉ㄥ唽浜嬩欢鍥炶皟鍑芥暟 """ - quecIot.setEventCB(self.eventCB) - """ 閰嶇疆浜у搧淇℃伅""" - quecIot.setProductinfo("p1116a", "UHg1dTRBRVh3MkVG") - """ 閰嶇疆鏈嶅姟鍣ㄤ俊鎭紝鍙夛紝榛樿杩炴帴MQTT鐢熶骇鐜鏈嶅姟鍣 """ - quecIot.setServer(1,"http://iot-south.quectel.com:2883") - """ 閰嶇疆lifetime锛屽彲閫夛紝MQTT榛樿涓120 """ - quecIot.setLifetime(120) - """ 閰嶇疆澶栭儴MCU鏍囪瘑鍙峰拰鐗堟湰鍙凤紝鍙夛紝濡傛病鏈夊閮∕CU鍒欎笉闇瑕侀厤缃 """ - quecIot.setMcuVersion("MCU1", "1_0_0") - - """ 鍒涘缓瀹氭椂鍣ㄤ换鍔 """ - ostimer = osTimer() - """ 姣忎竴鐧剧璋冪敤涓娆″洖璋冨嚱鏁 """ - ostimer.start(100000, 1, self.mainTask) - - """" 鍒涘缓gpio瀵硅薄 """ - self.gpio1 = Pin(Pin.GPIO1, Pin.OUT, Pin.PULL_DISABLE, 0) - - - """ 璁剧疆鑷姩浼戠湢妯″紡 """ - pm.autosleep(1) - - """ 鍚姩浜戝钩鍙拌繛鎺 """ - quecIot.setConnmode(1) - - @staticmethod - def eventCB(data): - print("\r\n{},{}\r\n".format(str(data[0]), str(data[1]))) - if len(data) == 3: - print(data[2]) - - ota_event(data) - if 1 == data[0] and 10422 == data[1]: - quecIot.setConnmode(0) - exit(0) - elif 3 == data[0] and 10200 == data[1]: - """ - 娴嬭瘯鍙戦佺墿妯″瀷鏁版嵁 - 鍚戝钩鍙板彂閫佹暟鎹渶瑕佸湪杩斿洖3, 10200涔嬪悗杩涜 - """ - global data_trans_ready - data_trans_ready = True - - - """ 鍙戦乥ool鍨嬫暟鎹""" - quecIot.phymodelReport(1, {2: True}) - """ 鍙戦佹暟鍊 """ - # 鏁存暟 - quecIot.phymodelReport(1, {3: 123}) - # 娴偣鏁 - quecIot.phymodelReport(1, {9: 123.123}) - """ 鍙戦乤rray """ - quecIot.phymodelReport(1, {4: [1, 2, 3]}) - """ 鍙戦佺粨鏋勪綋 """ - quecIot.phymodelReport(1, {6: {8: 1.0, 7: 1.0}}) - - """ 鍙戦佷腑鏂,閫忎紶鏁版嵁鍜岀墿妯″瀷鏁版嵁鏃犳硶鍚屾椂鍦ㄥ钩鍙拌皟璇 """ - - """ - bytes_temp = bytes('涓枃'.encode('utf-8')) - quecIot.passTransSend(1, bytes_temp) - """ - - def mainTask(self, argv): - global data_trans_ready - global gpio_toggle_flag - """ - 涓讳换鍔,涓婃姤鐢垫睜鐢靛帇 - """ - if data_trans_ready: - print('main task') - """ 鑾峰彇鐢靛帇 """ - battery_vol = get_battery_vol() - - """ 鍙戦佺墿妯″瀷鏁版嵁 """ - quecIot.phymodelReport(0, {110 : battery_vol}) - - """ 缈昏浆寮曡剼鐢靛钩 """ - # gpio_toggle_flag = not gpio_toggle_flag - # self.gpio1.write(int(gpio_toggle_flag)) - - - -if __name__ == '__main__': - print('\r\n**********\r\n') - print(DEMO_VERSION) - quecthing = Quecthing() +# -*- coding: utf-8 -*- +# @Time : 2021-03-26 +# @Author : evan.li +# @File : main.py +# @Brief : quecthing +# @revise : +# 2021-05-26 add get_battery_vol + +import quecIot + + +class Quecthing: + def __init__(self): + """ 鍒濆鍖杚ucsdk """ + quecIot.init() + """ 娉ㄥ唽浜嬩欢鍥炶皟鍑芥暟 """ + quecIot.setEventCB(self.eventCB) + """ 閰嶇疆浜у搧淇℃伅""" + quecIot.setProductinfo("p1115X", "d2c5Q1FsVWpwT1k3") + """ 閰嶇疆鏈嶅姟鍣ㄤ俊鎭紝鍙夛紝榛樿杩炴帴MQTT鐢熶骇鐜鏈嶅姟鍣 """ + quecIot.setServer(1,"http://iot-south.quectel.com:2883") + """ 閰嶇疆lifetime锛屽彲閫夛紝MQTT榛樿涓120 """ + quecIot.setLifetime(120) + """ 閰嶇疆澶栭儴MCU鏍囪瘑鍙峰拰鐗堟湰鍙凤紝鍙夛紝濡傛病鏈夊閮∕CU鍒欎笉闇瑕侀厤缃 """ + quecIot.setMcuVersion("MCU1", "1_0_0") + """ 鍚姩浜戝钩鍙拌繛鎺 """ + quecIot.setConnmode(1) + + @staticmethod + def eventCB(data): + print(str(data[0]) + "," + str(data[1]) + "\r\n") + if len(data) == 3: + print(data[2]) + """ + 娴嬭瘯鍙戦佺墿妯″瀷鏁版嵁 + 鍚戝钩鍙板彂閫佹暟鎹渶瑕佸湪杩斿洖3, 10200涔嬪悗杩涜 + """ + if 3 == data[0] and 10200 == data[1]: + """ 鍙戦乥ool鍨嬫暟鎹""" + quecIot.phymodelReport(1, {2: True}) + """ 鍙戦佹暟鍊 """ + # 鏁存暟 + quecIot.phymodelReport(1, {3: 123}) + # 娴偣鏁 + quecIot.phymodelReport(1, {9: 123.123}) + """ 鍙戦乤rray """ + quecIot.phymodelReport(1, {4: [1, 2, 3]}) + """ 鍙戦佺粨鏋勪綋 """ + quecIot.phymodelReport(1, {6: {8: 1.0, 7: 1.0}}) + +if __name__ == '__main__': + Quecthing() diff --git a/app/demo_quec_python/example3.py b/app/demo_quec_python/example3.py new file mode 100644 index 0000000000000000000000000000000000000000..887cb0b645c7ff73dd26745f486326b524b127fb --- /dev/null +++ b/app/demo_quec_python/example3.py @@ -0,0 +1,149 @@ +# -*- coding: utf-8 -*- +# @Time : 2021-03-26 +# @Author : evan.li +# @File : main.py +# @Brief : quecthing +# @revise : +# 2021-05-26 add get_battery_vol + +import quecIot +from machine import Timer + +class Quecthing: + def __init__(self): + """ 鍒濆鍖杚ucsdk """ + quecIot.init() + """ 娉ㄥ唽浜嬩欢鍥炶皟鍑芥暟 """ + quecIot.setEventCB(self.eventCB) + """ 閰嶇疆浜у搧淇℃伅""" + quecIot.setProductinfo("p111HL", "WVF1aHYyMlVXVUl4") + """ 閰嶇疆鏈嶅姟鍣ㄤ俊鎭紝鍙夛紝榛樿杩炴帴MQTT鐢熶骇鐜鏈嶅姟鍣 """ + quecIot.setServer(1,"http://iot-south.quectel.com:2883") + """ 閰嶇疆lifetime锛屽彲閫夛紝MQTT榛樿涓120 """ + quecIot.setLifetime(120) + """ 閰嶇疆澶栭儴MCU鏍囪瘑鍙峰拰鐗堟湰鍙凤紝鍙夛紝濡傛病鏈夊閮∕CU鍒欎笉闇瑕侀厤缃 """ + quecIot.setMcuVersion("MCU1", "1_0_0") + """ 鍚姩浜戝钩鍙拌繛鎺 """ + quecIot.setConnmode(1) + + """ 閰嶇疆瀛愯澶囧洖璋冨嚱鏁 """ + quecIot.subDevSetEventCB(subDevEventCB) + + def subDev_PassTransMode(self): + """ 瀛愯澶囧彂璧疯璇佸埌骞冲彴 """ + quecIot.subDevConn("p111HM", "VzY3dGo2UEF5eDE5", "8EEC4B66AEE8", 0, 120) + """ 瀛愯澶囩櫥闄嗗埌骞冲彴 """ + """ 鑻ュ瓙璁惧宸茶璇佸埌骞冲彴锛屼箣鍚庤皟鐢ㄧ櫥闄嗘帴鍙f椂闇瑕佸皢璁よ瘉寰楀埌鐨刣s淇℃伅鏀惧埌鏂规硶涓紱濡備笅锛 + self.__ds = "1234" + quecIot.subDevConn("p111HM", "VzY3dGo2UEF5eDE5", "8EEC4B66AEE8", self.__ds, 0, 120) + """ + def passTranDev_recvDs(self,ds): + self.__ptDs = ds + print("device id 8EEC4B66AEE8 product key: p111HM, receive ds:"+str(ds)) + + def passTranDev_timerCB(self): + quecIot.subDevHTB("p111HM", "8EEC4B66AEE8") + ptTimer.stop() + ptTimer.start(period=60 * 1000,mode=Timer.PERIODIC, callback=self.passTranDev_timerCB) + + def passTranDev_connSuccess(self): + quecIot.subDevPassTransSend("p111HM", "8EEC4B66AEE8", "123456") + ptTimer = Timer(Timer.ptTimer) + ptTimer.start(period=60 * 1000,mode=Timer.PERIODIC, callback=self.passTranDev_timerCB) + + def passTranDev_timerStop(self): + ptTimer.stop() + + def subDev_TslMode(self): + """ 瀛愯澶囧彂璧疯璇佸埌骞冲彴 """ + quecIot.subDevConn("p111HN", "Vm9pcmR2Mzd4cXB0", "8EEC4B66AEE9", 0, 120) + """ 瀛愯澶囩櫥闄嗗埌骞冲彴 """ + """ 鑻ュ瓙璁惧宸茶璇佸埌骞冲彴锛屼箣鍚庤皟鐢ㄧ櫥闄嗘帴鍙f椂闇瑕佸皢璁よ瘉寰楀埌鐨刣s淇℃伅鏀惧埌鏂规硶涓紱濡備笅锛 + self.__ds = "1234" + quecIot.subDevConn("p111HN", "Vm9pcmR2Mzd4cXB0", "8EEC4B66AEE9", self.__ds, 0, 120) + """ + + def tslDev_recvDs(self,ds): + self.__tslDs = ds + print("device id 8EEC4B66AEE9 product key: p111HN, receive ds:"+str(ds)) + + def tslDev_timerCB(self): + quecIot.subDevHTB("p111HM", "8EEC4B66AEE8") + tslTimer.stop() + tslTimer.start(period=60 * 1000,mode=Timer.PERIODIC, callback=self.tslDev_timerCB) + + def tslDev_timerStop(self): + tslTimer.stop() + + def tslDev_connSuccess(self): + """ 鍙戦乥ool鍨嬫暟鎹""" + quecIot.subDevTslReport("p111HN", "8EEC4B66AEE9", {2: True}) + """ 鍙戦佹暟鍊 """ + # 鏁存暟 + quecIot.subDevTslReport("p111HN", "8EEC4B66AEE9", {3: 123}) + # 娴偣鏁 + quecIot.subDevTslReport("p111HN", "8EEC4B66AEE9", {9: 123.123}) + """ 鍙戦乤rray """ + quecIot.subDevTslReport("p111HN", "8EEC4B66AEE9", {4: [1, 2, 3]}) + """ 鍙戦佺粨鏋勪綋 """ + quecIot.subDevTslReport("p111HN", "8EEC4B66AEE9", {6: {8: 1.0, 7: 1.0}}) + tslTimer = Timer(Timer.tslTimer) + tslTimer.start(period=60 * 1000,mode=Timer.PERIODIC, callback=self.tslDev_timerCB) + + + def subDevEventCB(self,data): + print(data[0]+","+data[1]+","+str(data[2])+","+str(data[3])) + if len(data) == 5: + print(data[4]) + if 1 == data[2] and 10200 == data[3]: + if 5 == len(data): + if "p111HM" == data[0]and "8EEC4B66AEE8" == data[1]: + self.passTranDev_recvDs(data[4]) + elif "p111HN" == data[0] and "8EEC4B66AEE9" == data[1]: + self.tslDev_recvDs(data[4]) + else: + print("register platform error:" + data[3]) + + if 2 == data[2] and 10200 == data[3]: + if "p111HM" == data[0]and "8EEC4B66AEE8" == data[1]: + self.passTranDev_connSuccess() + elif "p111HN" == data[0] and "8EEC4B66AEE9" == data[1]: + self.tslDev_connSuccess() + + if 6 == data[2] and 10200 == data[3]: + if "p111HM" == data[0]and "8EEC4B66AEE8" == data[1]: + self.passTranDev_timerStop() + elif "p111HN" == data[0] and "8EEC4B66AEE9" == data[1]: + self.tslDev_timerStop() + + + @staticmethod + def eventCB(data): + print(str(data[0]) + "," + str(data[1]) + "\r\n") + + if len(data) == 3: + print(data[2]) + """ + 娴嬭瘯鍙戦佺墿妯″瀷鏁版嵁 + 鍚戝钩鍙板彂閫佹暟鎹渶瑕佸湪杩斿洖3, 10200涔嬪悗杩涜 + """ + if 3 == data[0] and 10200 == data[1]: + """ 閫忎紶瀛愯澶 """ + Quecthing.subDev_PassTransMode() + """" 鐗╂ā鍨嬪瓙璁惧 """ + Quecthing.subDev_TslMode() + + """ 鍙戦乥ool鍨嬫暟鎹""" + quecIot.phymodelReport(1, {2: True}) + """ 鍙戦佹暟鍊 """ + # 鏁存暟 + quecIot.phymodelReport(1, {3: 123}) + # 娴偣鏁 + quecIot.phymodelReport(1, {9: 123.123}) + """ 鍙戦乤rray """ + quecIot.phymodelReport(1, {4: [1, 2, 3]}) + """ 鍙戦佺粨鏋勪綋 """ + quecIot.phymodelReport(1, {6: {8: 1.0, 7: 1.0}}) + +if __name__ == '__main__': + Quecthing() diff --git a/cloud/Ql_iotApi.h b/cloud/Ql_iotApi.h index 7adad6747c6e2c3bd9f7d388f7a9c4fc3302a4fb..8211e175f1396e15ae194b1cf7469d5f010e0d77 100644 --- a/cloud/Ql_iotApi.h +++ b/cloud/Ql_iotApi.h @@ -1,7 +1,33 @@ #ifndef __QIOT_API_H__ #define __QIOT_API_H__ +#if 1 #include "Quos_kernel.h" +#else +#include "../driverLayer/Qhal_types.h" +typedef struct cJSON +{ + /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ + struct cJSON *next; + struct cJSON *prev; + /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ + struct cJSON *child; + + /* The type of the item, as above. */ + int type; + + /* The item's string, if type==QUOS_cJSON_String and type == QUOS_cJSON_Raw */ + char *valuestring; + /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ + int valueint; + /* The item's number, if type==QUOS_cJSON_Number */ + double valuedouble; + + /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ + char *string; +} cJSON; + +#endif enum { QIOT_ATEVENT_TYPE_AUTH = 1, @@ -12,10 +38,12 @@ enum QIOT_ATEVENT_TYPE_LOGOUT = 6, QIOT_ATEVENT_TYPE_OTA = 7, QIOT_ATEVENT_TYPE_SERVER = 8, + QIOT_ATEVENT_TYPE_UNAUTH = 9, }; enum { QIOT_AUTH_SUCC = 10200, /* 设备认证成功 */ + QIOT_AUTH_ERR_DMP_INSIDE = 10404, /* DMP内部接口调用失败 */ QIOT_AUTH_ERR_REQDATA = 10420, /* 请求数据错误(连接失败)*/ QIOT_AUTH_ERR_DONE = 10422, /* 设备已认证(连接失败)*/ QIOT_AUTH_ERR_PKPS_INVALID = 10423, /* 没有找到产品信息(连接失败)*/ @@ -26,6 +54,8 @@ enum QIOT_AUTH_ERR_PK_CHANGE = 10430, /* PK发生改变 */ QIOT_AUTH_ERR_DK_ILLEGAL = 10431, /* DK不合法 */ QIOT_AUTH_ERR_PK_VER_NOCOR = 10432, /* PK与认证版本不匹配 */ + QIOT_AUTH_ERR_PSWORD = 10436, /* 登录用户名错误 */ + QIOT_AUTH_ERR_DEVICE_INFO = 10438, /* 没有找到设备信息 */ QIOT_AUTH_ERR_DEVICE_INSIDE = 10450, /* 设备内部错误(连接失败)*/ QIOT_AUTH_ERR_SERVER_NOTFOUND = 10466, /* 引导服务器地址未找到(连接失败)*/ QIOT_AUTH_ERR_FAIL = 10500, /* 设备认证失败(系统发生未知异常)*/ @@ -34,12 +64,18 @@ enum enum { QIOT_CONN_SUCC = 10200, /* 接入成功 */ + QIOT_CONN_ERR_DMP_INSIDE = 10404, /* DMP内部接口调用失败 */ QIOT_CONN_ERR_DS_INVALID = 10430, /* 设备密钥不正确(连接失败)*/ QIOT_CONN_ERR_DEVICE_FORBID = 10431, /* 设备被禁用(连接失败)*/ + QIOT_CONN_ERR_PSWORD = 10436, /* 登录用户名错误 */ + QIOT_CONN_ERR_DS = 10437, /* 设备DS错误 */ + QIOT_CONN_ERR_DEVICE_INFO = 10438, /* 没有找到设备信息 */ QIOT_CONN_ERR_DEVICE_INSIDE = 10450, /* 设备内部错误(连接失败)*/ QIOT_CONN_ERR_VERSION_NOTFOUND = 10471, /* 实现方案版本不支持(连接失败)*/ QIOT_CONN_ERR_PING = 10473, /* 接入心跳异常 */ QIOT_CONN_ERR_NET = 10474, /* 网络异常 */ + QIOT_CONN_ERR_SERVER_CHANGE = 10475, /* 服务器发生改变 */ + QIOT_CONN_ERR_AP = 10476, /* 连接AP异常 */ QIOT_CONN_ERR_UNKNOW = 10500, /* 接入失败(系统发生未知异常)*/ }; enum @@ -55,12 +91,18 @@ enum QIOT_SEND_ERR_PHYMODEL = 10310, /* 物模型数据发送失败 */ QIOT_SEND_SUCC_LOC = 10220, /* 定位数据发送成功 */ QIOT_SEND_ERR_FAIL_LOC = 10320, /* 定位数据发送失败 */ + QIOT_SEND_SUCC_STATE = 10230, /* 状态数据发送成功 */ + QIOT_SEND_ERR_STATE = 10330, /* 状态数据发送失败 */ + QIOT_SEND_SUCC_INFO = 10240, /* 设备信息发送成功 */ + QIOT_SEND_ERR_INFO = 10340, /* 设备信息发送失败 */ }; enum { QIOT_RECV_SUCC_TRANS = 10200, /* 收到透传数据 */ QIOT_RECV_SUCC_PHYMODEL_RECV = 10210, /* 收到物模型下发数据 */ QIOT_RECV_SUCC_PHYMODEL_REQ = 10211, /* 收到物模型请求数据 */ + QIOT_RECV_SUCC_SUB_STATE_REQ = 10220, /* 收到子设备状态请求数据 */ + QIOT_RECV_SUCC_SUB_INFO_REQ = 10230, /* 收到子设备信息请求数据 */ QIOT_RECV_ERR_BUFFER = 10473, /* 接收失败,收到数据但长度超过模组buffer限制,AT非缓存模式下有效*/ QIOT_RECV_ERR_LIMIT = 10428, /* 数据接收失败,设备被限制消息通信,缓存模式下有效 */ }; @@ -77,20 +119,28 @@ enum QIOT_OTA_UPDATING = 10704, /* 包更新中 */ QIOT_OTA_UPDATE_OK = 10705, /* 包更新完成 */ QIOT_OTA_UPDATE_FAIL = 10706, /* 包更新失败 */ + QIOT_OTA_UPDATE_FLAG = 10707, /* 首个设备操作结果广播 */ }; enum { QIOT_SERVER_ERRCODE_RATE_LIMIT = 10428, QIOT_SERVER_ERRCODE_QUANTITY_LIMIT = 10429, }; - +enum +{ + QIOT_SUB_DEV_ERR_No_ASSOCIATION = 10440, /* 子设备与当前网关没有关联关系 */ + QIOT_SUB_DEV_ERR_ALREADY_CONN = 10441, /* 子设备重复登录 */ + QIOT_SUB_DEV_ERR_UNLOGIN = 10442, /* 子设备未登录 */ +}; /* ql_iotDp.h */ typedef enum { QIOT_DPCMD_TYPE_SYS = 0, /* sys类型命令 */ QIOT_DPCMD_TYPE_BUS, /* 业务数据类型命令*/ QIOT_DPCMD_TYPE_OTA, /* OTA类型命令 */ + QIOT_DPCMD_TYPE_LAN, /* LAN类型命令 */ } QIot_dpCmdType_e; + typedef enum { QIOT_DPDATA_TYPE_BOOL = 0, @@ -123,17 +173,26 @@ void *Ql_iotTtlvIdGetStruct(const void *ttlvHead, quint16_t id); qbool Ql_iotTtlvIdAddBool(void **ttlvHead, quint16_t id, qbool value); qbool Ql_iotTtlvIdAddInt(void **ttlvHead, quint16_t id, qint64_t num); qbool Ql_iotTtlvIdAddFloat(void **ttlvHead, quint16_t id, double num); -qbool Ql_iotTtlvIdAddByte(void **ttlvHead, quint16_t id, quint8_t *data, quint32_t len); +qbool Ql_iotTtlvIdAddByte(void **ttlvHead, quint16_t id, const quint8_t *data, quint32_t len); +qbool Ql_iotTtlvIdAddString(void **ttlvHead, quint16_t id, const char *data); qbool Ql_iotTtlvIdAddStruct(void **ttlvHead, quint16_t id, void *vStruct); -#define Ql_iotTtlvIdAddString(ttlvHead, id, data) Ql_iotTtlvIdAddByte(ttlvHead, id, (quint8_t *)data, HAL_STRLEN(data)) +//#define Ql_iotTtlvIdAddString(ttlvHead, id, data) Ql_iotTtlvIdAddByte(ttlvHead, id, (quint8_t *)data, HAL_STRLEN(data)) +void *Ql_iotJson2Ttlv(const cJSON *json); +cJSON *Ql_iotTtlv2Json(const void *ttlvHead); /* ql_iotCmdBus.h */ qbool Ql_iotCmdBusPassTransSend(quint16_t mode, quint8_t *payload, quint32_t len); qbool Ql_iotCmdBusPhymodelReport(quint16_t mode, const void *ttlvHead); qbool Ql_iotCmdBusPhymodelAck(quint16_t mode, quint16_t pkgId, const void *ttlvHead); -qbool Ql_iotCmdBusLocReport(void); + +/* ql_iotCmdLoc.h */ +qbool Ql_iotCmdBusLocReportInside(void *titleTtlv); +qbool Ql_iotCmdBusLocReportOutside(void *nmeaTtlv); +void *Ql_iotLocGetData(const void *titleTtlv); +void *Ql_iotLocGetSupList(void); /* ql_iotCmdOTA.h */ +qbool Ql_iotCmdOtaRequest(quint32_t mode); qbool Ql_iotCmdOtaAction(quint8_t action); quint32_t Ql_iotCmdOtaMcuFWDataRead(quint32_t startAddr, quint8_t data[], quint32_t maxLen); @@ -163,15 +222,25 @@ enum QIOT_DPID_INFO_LAC = 8, /* 位置区代码 */ QIOT_DPID_INFO_PHONE_NUM = 9, /* phone号 */ QIOT_DPID_INFO_SIM_NUM = 10, /* SIM号 */ - QIOT_DPID_INFO_SDK_VER = 11, /* IOT SDK版本号*/ + QIOT_DPID_INFO_SDK_VER = 11, /* quecthingSDK版本号*/ QIOT_DPID_INFO_LOC_SUPLIST = 12, /* 定位功能支持列表 */ + QIOT_DPIO_INFO_DP_VER = 13, /* 数据协议版本 */ + QIOT_DPIO_INFO_CP_VER = 14, /* 通信协议版本号 */ QIOT_DPID_INFO_MAX, }; qbool Ql_iotCmdSysStatusReport(quint16_t ids[], quint32_t size); qbool Ql_iotCmdSysDevInfoReport(quint16_t ids[], quint32_t size); - +void *Ql_iotSysGetDevStatus(quint16_t ids[], quint32_t size); +void *Ql_iotSysGetDevInfo(quint16_t ids[], quint32_t size); +qbool Ql_iotCmdBindcodeReport(quint8_t bindcode[], quint32_t len); /* ql_iotConn.h */ +typedef enum +{ + QIOT_DPAPP_M2M = (1 << 0), + QIOT_DPAPP_SUBDEV = (1 << 1), + QIOT_DPAPP_LANPHONE = (1 << 2), +} QIot_dpAppType_e; /* ql_iotConfig.h */ typedef enum @@ -188,45 +257,65 @@ typedef enum typedef enum { QIOT_STATE_UNINITIALIZE = 0, - QIOT_STATE_INITIALIZED, - QIOT_STATE_AUTHENTICATING, - QIOT_STATE_AUTHENTICATED, - QIOT_STATE_AUTHENTICATE_FAILED, - QIOT_STATE_CONNECTING, - QIOT_STATE_CONNECTED, - QIOT_STATE_CONNECT_FAIL, - QIOT_STATE_SUBSCRIBED, - QIOT_STATE_SUBSCRIBE_FAIL, - QIOT_STATE_DISCONNECTING, - QIOT_STATE_DISCONNECTED, - QIOT_STATE_DISCONNECT_FAIL, + QIOT_STATE_INITIALIZED = 1, + QIOT_STATE_AUTHENTICATING = 2, + QIOT_STATE_AUTHENTICATED = 3, + QIOT_STATE_AUTHENTICATE_FAILED = 4, + QIOT_STATE_CONNECTING = 5, + QIOT_STATE_CONNECTED = 6, + QIOT_STATE_CONNECT_FAIL = 7, + QIOT_STATE_SUBSCRIBED = 8, + QIOT_STATE_SUBSCRIBE_FAIL = 9, + QIOT_STATE_DISCONNECTING = 10, + QIOT_STATE_DISCONNECTED = 11, + QIOT_STATE_DISCONNECT_FAIL = 12, } QIot_state_e; -void Ql_iotInit(void); +qbool Ql_iotInit(void); qbool Ql_iotConfigSetConnmode(QIot_connMode_e mode); QIot_connMode_e Ql_iotConfigGetConnmode(void); -qbool Ql_iotConfigSetPdpContextId(quint8_t contextID); -quint8_t Ql_iotConfigGetPdpContextId(void); +qbool Ql_iotConfigSetProductinfo(const char *pk, const char *ps); +void Ql_iotConfigGetProductinfo(char **pk, char **ps, char **ver); qbool Ql_iotConfigSetServer(QIot_protocolType_t type, const char *server_url); void Ql_iotConfigGetServer(QIot_protocolType_t *type, char **server_url); qbool Ql_iotConfigSetProductinfo(const char *pk, const char *ps); void Ql_iotConfigGetProductinfo(char **pk, char **ps, char **ver); qbool Ql_iotConfigSetLifetime(quint32_t lifetime); quint32_t Ql_iotConfigGetLifetime(void); -qbool Ql_iotConfigAppendAppVersion(const char *appVer); /* 对APP层只有openC方案可用 */ +qbool Ql_iotConfigSetPdpContextId(quint8_t contextID); +quint8_t Ql_iotConfigGetPdpContextId(void); +qbool Ql_iotConfigSetSessionFlag(qbool flag); +qbool Ql_iotConfigGetSessionFlag(void); +qbool Ql_iotConfigSetAppVersion(const char *appVer); /* 对APP层只有openC方案可用 */ char *Ql_iotConfigGetSoftVersion(void); qbool Ql_iotConfigSetMcuVersion(const char *compno, const char *version); quint32_t Ql_iotConfigGetMcuVersion(const char *compno, char **version); void Ql_iotConfigSetEventCB(void (*eventCb)(quint32_t event, qint32_t errcode, const void *value, quint32_t valLen)); QIot_state_e Ql_iotGetWorkState(void); +qbool Ql_iotConfigSetDkDs(const char *dk, const char *ds); +qbool Ql_iotConfigGetDkDs(char **dk, char **ds); -/* ql_iotLocator.h */ -qbool Ql_iotLocatorConfigSet(const void *ttlvHead); -void *Ql_iotLocatorConfigGet(void); -void *Ql_iotLocatorDataGet(const void *titleTtlv); -char *Ql_iotLocatorTtlv2String(const void *ttlv); -qbool Ql_iotLocatoTitleClashCheck(const void *ttlvHead); -qbool Ql_iotLocatoTitleSupportCheck(const void *ttlvHead); - -quint32_t Quos_stringSplit(char *src, char **words, quint32_t maxSize, char *delim, qbool keepEmptyParts); +/* ql_fotaConfig.h */ +#ifdef QUEC_ENABLE_HTTP_OTA +void Ql_iotConfigSetHttpOtaEventCb(void (*eventCb)(quint32_t event, qint32_t errcode, const void *value, quint32_t valLen)); +qbool Ql_iotConfigSetHttpOtaProductInfo(const char *pk, const char *ps); +void Ql_iotConfigGetHttpOtaProductInfo(char **pk, char **ps); +qbool Ql_iotConfigSetHttpOtaTls(qbool tls); +qbool Ql_iotConfigGetHttpOtaTls(void); +qbool Ql_iotConfigSetHttpOtaServer(const char *server_url); +void Ql_iotConfigGetHttpOtaServer(char **server_url); +qbool Ql_iotConfigSetHttpOtaUp(quint8_t battery, quint8_t upmode, const char *url); +void Ql_iotConfigGetHttpOtaUp(quint8_t *battery, quint8_t *upmode, char **url); +#endif +/* ql_iotGwDev.h */ +#ifdef QUEC_ENABLE_GATEWAY +void Ql_iotConfigSetSubDevEventCB(void (*eventCb)(quint32_t event, qint32_t errcode, const char *subPk, const char *subDk, const void *value, quint32_t valLen)); +qbool Ql_iotSubDevConn(const char *subPk, const char *subPs, const char *subDk, const char *subDs, quint8_t sessionType, quint16_t keepalive); +qbool Ql_iotSubDevDisconn(const char *subPk, const char *subDk); +qbool Ql_iotSubDevPassTransSend(const char *subPk, const char *subDk, quint8_t *payload, quint16_t payloadlen); +qbool Ql_iotSubDevTslReport(const char *subPk, const char *subDk, const void *ttlvHead); +qbool Ql_iotSubDevTslAck(const char *subPk, const char *subDk, quint16_t pkgId, const void *ttlvHead); +qbool Ql_iotSubDevDeauth(const char *subPk, const char *subPs, const char *subDk, const char *subDs); +qbool Ql_iotSubDevHTB(const char *subPk, const char *subDk); +#endif #endif \ No newline at end of file diff --git a/cloud/common/ql_iotCmdBus.c b/cloud/common/ql_iotCmdBus.c new file mode 100644 index 0000000000000000000000000000000000000000..368dee738886f45121d49ad0211748f305b7f4cd --- /dev/null +++ b/cloud/common/ql_iotCmdBus.c @@ -0,0 +1,277 @@ +/************************************************************************* +** 创建人 @author : 吴健超 JCWu +** 版本 @version : V1.0.0 原始版本 +** 日期 @date : 2020-12-25 +** 功能 @brief : dmp业务指令,适配DMP2.2.0 +** 硬件 @hardware: +** 其他 @other : +***************************************************************************/ +#include "ql_iotCmdBus.h" +#include "ql_iotCmdSys.h" +#include "ql_iotCmdLoc.h" +#include "ql_iotDp.h" +#include "ql_iotTtlv.h" +#include "ql_iotConfig.h" +#include "Qhal_driver.h" + +Ql_iotCmdBusInfo_t QIot_busInfo; + +/************************************************************************** +** 功能 @brief : 透传数据发送结果 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void FUNCTION_ATTR_ROM ql_iotCmdBusPassTransSendCB(void *chlFd, const void *sendData, const void *recvData) +{ + UNUSED(chlFd); + UNUSED(sendData); + Ql_iotUrcEventCB(QIOT_ATEVENT_TYPE_SEND, recvData ? QIOT_SEND_SUCC_TRANS : QIOT_SEND_ERR_TRANS, NULL, 0); +} +/************************************************************************** +** 功能 @brief : 透传数据发送 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotCmdBusPassTransSend(quint16_t mode, quint8_t *payload, quint32_t len) +{ + if (0 == len) + { + return FALSE; + } + return Ql_iotDpSendCommonReq(QIOT_DPAPP_M2M | QIOT_DPAPP_LANPHONE,NULL, 0, mode, QIOT_DPCMD_PASS_EVENT, payload, len, ql_iotCmdBusPassTransSendCB); +} +/************************************************************************** +** 功能 @brief : 透传数据接收 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Ql_iotCmdBusPassTransRecv(QIot_dpAppType_e app, const char *endPoint, quint16_t pkgId, quint8_t *payload, quint16_t payloadLen) +{ + UNUSED(app); + UNUSED(endPoint); + UNUSED(pkgId); + QIot_buffer_t *recvBuf = HAL_MALLOC(sizeof(QIot_buffer_t) + payloadLen); + if (NULL == recvBuf) + { + Quos_logPrintf(QUEC_BUS, LL_ERR, "mcf recvBuf"); + return; + } + recvBuf->type = QIOT_RECV_SUCC_TRANS; + recvBuf->val.len = payloadLen; + HAL_MEMCPY(recvBuf->val.buf, payload, payloadLen); + if (FALSE == Quos_eventPost(QIOT_ATEVENT_TYPE_RECV, recvBuf)) + { + HAL_FREE(recvBuf); + } +} +/************************************************************************** +** 功能 @brief : 物模型数据发送结果 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void FUNCTION_ATTR_ROM ql_iotCmdBusPhymodelReportCB(void *chlFd, const void *sendData, const void *recvData) +{ + UNUSED(chlFd); + UNUSED(sendData); + Ql_iotUrcEventCB(QIOT_ATEVENT_TYPE_SEND, recvData ? QIOT_SEND_SUCC_PHYMODEL : QIOT_SEND_ERR_PHYMODEL, NULL, 0); +} +/************************************************************************** +** 功能 @brief : 物模型数据上报 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotCmdBusPhymodelReport(quint16_t mode, const void *ttlvHead) +{ + if (NULL == ttlvHead) + { + return FALSE; + } + return Ql_iotDpSendTtlvReq(QIOT_DPAPP_M2M|QIOT_DPAPP_LANPHONE,NULL, 0, mode, QIOT_DPCMD_TSL_EVENT, ttlvHead, ql_iotCmdBusPhymodelReportCB); +} +/************************************************************************** +** 功能 @brief : 物模型数据应答 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotCmdBusPhymodelAck(quint16_t mode, quint16_t pkgId, const void *ttlvHead) +{ + UNUSED(mode); + return Ql_iotDpSendTtlvRsp(QIOT_DPAPP_M2M,NULL, QIOT_DPCMD_TSL_RSP, pkgId, ttlvHead); +} +/************************************************************************** +** 功能 @brief : 物模型数据上报 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotCmdBusPhymodelReportHex(quint16_t mode, quint8_t *buf, quint32_t len) +{ + return Ql_iotDpSendCommonReq(QIOT_DPAPP_M2M|QIOT_DPAPP_LANPHONE, NULL, 0, mode, QIOT_DPCMD_TSL_EVENT, buf, len, ql_iotCmdBusPhymodelReportCB); +} +/************************************************************************** +** 功能 @brief : 物模型数据应答 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotCmdBusPhymodelAckHex(quint16_t mode, quint16_t pkgId, quint8_t *buf, quint32_t len) +{ + UNUSED(mode); + return Ql_iotDpSendCommonRsp(QIOT_DPAPP_M2M,NULL, QIOT_DPCMD_TSL_RSP, pkgId, buf, len); +} +/************************************************************************** +** 功能 @brief : 物模型数据接收 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void Ql_iotCmdBusPhymodelWriteRecv(QIot_dpAppType_e app, const char *endPoint, quint16_t pkgId, quint8_t *payload, quint16_t payloadLen) +{ + UNUSED(app); + UNUSED(endPoint); + void *ttlvHead = Ql_iotTtlvUnformat(payload, payloadLen); + if (NULL == ttlvHead) + { + Ql_iotCmdSysExceReport(app,endPoint, QIOT_SERVER_ERRCODE_UNFORMAT_FAIL, pkgId); + return; + } + Ql_iotTtlvFree(&ttlvHead); + + QIot_buffer_t *recvBuf = NULL; + recvBuf = HAL_MALLOC(sizeof(QIot_buffer_t) + payloadLen); + if (NULL == recvBuf) + { + Quos_logPrintf(QUEC_BUS, LL_ERR, "mcf recvBuf"); + return; + } + HAL_MEMCPY(recvBuf->val.buf, payload, payloadLen); + recvBuf->val.len = payloadLen; + recvBuf->type = QIOT_RECV_SUCC_PHYMODEL_RECV; + if (FALSE == Quos_eventPost(QIOT_ATEVENT_TYPE_RECV, recvBuf)) + { + HAL_FREE(recvBuf); + } +} +/************************************************************************** +** 功能 @brief : 物模型数据请求 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void Ql_iotCmdBusPhymodelReqRecv(QIot_dpAppType_e app, const char *endPoint, quint16_t pkgId, quint8_t *payload, quint16_t payloadLen) +{ + UNUSED(app); + UNUSED(endPoint); + quint16_t *ids = (quint16_t *)HAL_MALLOC(sizeof(quint16_t) * (payloadLen / 2 + 1)); + if (ids) + { + quint32_t idNum; + ids[0] = pkgId; + for (idNum = 0; idNum < payloadLen / 2; idNum++) + { + ids[idNum + 1] = _ARRAY01_U16(payload + idNum * 2); + } + Ql_iotUrcEventCB(QIOT_ATEVENT_TYPE_RECV, QIOT_RECV_SUCC_PHYMODEL_REQ, ids, idNum); + HAL_FREE(ids); + } +} +/************************************************************************** +** 功能 @brief : 业务事件处理 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void ql_iotCmdBusEventNotify(qint32_t event, void *arg) +{ + switch (event) + { + case QIOT_ATEVENT_TYPE_RECV: + { + QIot_buffer_t *recvBuf = (QIot_buffer_t *)arg; + #ifdef QUEC_ENABLE_AT + if (QIot_busInfo.recvIsBuffer) + { + if (QIOT_RECV_SUCC_TRANS == recvBuf->type && Quos_twllHeadGetNodeCount(QIot_busInfo.recvTransData) < QIOT_RECV_NODE_TRANS_MAX) + { + Quos_twllHeadAdd(&QIot_busInfo.recvTransData, &recvBuf->head); + Ql_iotUrcEventCB(QIOT_ATEVENT_TYPE_RECV, QIOT_RECV_SUCC_TRANS, NULL, 0); + } + else if (QIOT_RECV_SUCC_PHYMODEL_RECV == recvBuf->type && Quos_twllHeadGetNodeCount(QIot_busInfo.recvPhymodelData) < QIOT_RECV_NODE_MODEL_MAX) + { + if(QIot_busInfo.dataFormat) + { + void *ttlvHead = Ql_iotTtlvUnformat(recvBuf->val.buf, recvBuf->val.len); + if (NULL == ttlvHead) + { + Quos_logPrintf(QUEC_BUS, LL_ERR, "not ttlv format"); + return; + } + cJSON *root = Ql_iotTtlv2Json(ttlvHead); + Ql_iotTtlvFree(&ttlvHead); + if (NULL == root) + { + Quos_logPrintf(QUEC_BUS, LL_ERR, "ttlv to json error"); + return; + } + char *jsonData = cJSON_PrintUnformatted(root); + int jsonLen = HAL_STRLEN(jsonData); + QIot_buffer_t *jsonBuf = HAL_MALLOC(sizeof(QIot_buffer_t) + jsonLen); + if (NULL == jsonBuf) + { + Quos_logPrintf(QUEC_BUS, LL_ERR, "mcf jsonBuf"); + cJSON_Delete(root); + return; + } + HAL_MEMCPY(jsonBuf->val.buf, jsonData, jsonLen); + jsonBuf->val.len = jsonLen; + jsonBuf->type = QIOT_RECV_SUCC_PHYMODEL_RECV; + cJSON_Delete(root); + HAL_FREE(recvBuf); + Quos_twllHeadAdd(&QIot_busInfo.recvPhymodelData, &jsonBuf->head); + } + else + { + Quos_twllHeadAdd(&QIot_busInfo.recvPhymodelData, &recvBuf->head); + } + Ql_iotUrcEventCB(QIOT_ATEVENT_TYPE_RECV, QIOT_RECV_SUCC_PHYMODEL_RECV, NULL, 0); + } + else + { + HAL_FREE(recvBuf); + Ql_iotUrcEventCB(QIOT_ATEVENT_TYPE_RECV, QIOT_RECV_ERR_LIMIT, NULL, 0); + } + } + else + #endif + { + if (QIOT_RECV_SUCC_TRANS == recvBuf->type) + { + Ql_iotUrcEventCB(QIOT_ATEVENT_TYPE_RECV, QIOT_RECV_SUCC_TRANS, recvBuf->val.buf, recvBuf->val.len); + } + else if (QIOT_RECV_SUCC_PHYMODEL_RECV == recvBuf->type) + { + #ifdef QUEC_ENABLE_AT + Ql_iotUrcEventCB(QIOT_ATEVENT_TYPE_RECV, QIOT_RECV_SUCC_PHYMODEL_RECV, recvBuf->val.buf, recvBuf->val.len); + #else + void *ttlv = Ql_iotTtlvUnformat(recvBuf->val.buf, recvBuf->val.len); + if (ttlv) + { + Ql_iotUrcEventCB(QIOT_ATEVENT_TYPE_RECV, QIOT_RECV_SUCC_PHYMODEL_RECV, ttlv, 0); + Ql_iotTtlvFree(&ttlv); + } + #endif + } + HAL_FREE(recvBuf); + } + break; + } + default: + break; + } +} +/************************************************************************** +** 功能 @brief : 业务任务初始化 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Ql_iotCmdBusInit(void) +{ + HAL_MEMSET(&QIot_busInfo, 0, sizeof(QIot_busInfo)); + qint32_t event[] = {QIOT_ATEVENT_TYPE_RECV}; + Quos_eventCbReg(event, sizeof(event) / sizeof(event[0]), ql_iotCmdBusEventNotify); +} \ No newline at end of file diff --git a/cloud/common/ql_iotCmdBus.h b/cloud/common/ql_iotCmdBus.h new file mode 100644 index 0000000000000000000000000000000000000000..c111107fdebd4890fda6aa29c9a11f6151d82657 --- /dev/null +++ b/cloud/common/ql_iotCmdBus.h @@ -0,0 +1,49 @@ +#ifndef __QIOT_CMDBUS_H__ +#define __QIOT_CMDBUS_H__ +#include "Ql_iotApi.h" + +#define QIOT_RECV_NODE_TRANS_MAX 10 +#define QIOT_RECV_NODE_MODEL_MAX 10 + +#define QIOT_SEND_ERR_STRING(X) \ + ( \ + (X == QIOT_SEND_SUCC_TRANS) ? "SEND_SUCC_TRANS" : (X == QIOT_SEND_SUCC_PHYMODEL) ? "SEND_SUCC_PHYMODEL" \ + : (X == QIOT_SEND_ERR_TRANS) ? "SEND_ERR_TRANS" \ + : (X == QIOT_SEND_ERR_PHYMODEL) ? "SEND_ERR_PHYMODEL" \ + : "Unknown") +#define QIOT_RECV_ERR_STRING(X) \ + ( \ + (X == QIOT_RECV_SUCC_TRANS) ? "RECV_SUCC_TRANS" : (X == QIOT_RECV_SUCC_PHYMODEL_RECV) ? "RECV_SUCC_PHYMODEL_RECV" \ + : (X == QIOT_RECV_SUCC_PHYMODEL_REQ) ? "RECV_SUCC_PHYMODEL_REQ" \ + : (X == QIOT_RECV_ERR_BUFFER) ? "RECV_ERR_BUFFER" \ + : (X == QIOT_RECV_ERR_LIMIT) ? "RECV_ERR_LIMIT" \ + : "Unknown") + +typedef struct +{ + TWLLHead_T head; + int type; + struct + { + quint32_t len; + quint8_t buf[1]; + } val; +} QIot_buffer_t; + +typedef struct +{ + qbool recvIsBuffer; + TWLLHead_T *recvTransData; + TWLLHead_T *recvPhymodelData; + qbool dataFormat; +} Ql_iotCmdBusInfo_t; +extern Ql_iotCmdBusInfo_t QIot_busInfo; +void Ql_iotCmdBusInit(void); + +void Ql_iotCmdBusPassTransRecv(QIot_dpAppType_e app, const char *endPoint, quint16_t pkgId, quint8_t *payload, quint16_t payloadLen); +void Ql_iotCmdBusPhymodelWriteRecv(QIot_dpAppType_e app, const char *endPoint, quint16_t pkgId, quint8_t *payload, quint16_t payloadLen); +void Ql_iotCmdBusPhymodelReqRecv(QIot_dpAppType_e app, const char *endPoint, quint16_t pkgId, quint8_t *payload, quint16_t payloadLen); + +qbool Ql_iotCmdBusPhymodelReportHex(quint16_t mode, quint8_t *buf, quint32_t len); +qbool Ql_iotCmdBusPhymodelAckHex(quint16_t mode, quint16_t pkgId, quint8_t *buf, quint32_t len); +#endif \ No newline at end of file diff --git a/cloud/common/ql_iotCmdLan.c b/cloud/common/ql_iotCmdLan.c new file mode 100644 index 0000000000000000000000000000000000000000..07349aed7e9438b81a59f1b19e0bc291e37f0796 --- /dev/null +++ b/cloud/common/ql_iotCmdLan.c @@ -0,0 +1,85 @@ +/* + * @Author: your name + * @Date: 2021-11-04 19:23:58 + * @LastEditTime: 2021-11-05 11:56:19 + * @LastEditors: Please set LastEditors + * @Description: In User Settings Edit + * @FilePath: \QuecCSDK\cloud\common\ql_iotCmdLan.c + */ +#include "ql_iotCmdLan.h" +#include "ql_iotConfig.h" +#include "ql_iotDp.h" +#include "Qhal_driver.h" + +#ifdef QUEC_ENABLE_LAN + +#ifndef QIOT_LAN_TIMEOUT +#define QIOT_LAN_TIMEOUT 5 * SWT_ONE_SECOND +#endif + +static void *lanChl = NULL; +/************************************************************************** +** 功能 @brief : 设备上报PK、MAC内容 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM ql_iotLanDevDiscover(QIot_dpAppType_e app, const char *endPoint, quint16_t pkgId, quint8_t *payload, quint16_t payloadLen) +{ + UNUSED(payload); + UNUSED(payloadLen); + void *ttlvHead = NULL; + Ql_iotTtlvIdAddString(&ttlvHead, QIOT_DPID_LAN_MAC, QIot_userdata.deviceInfo.deviceKey); + Ql_iotTtlvIdAddString(&ttlvHead, QIOT_DPID_LAN_PK, QIot_userdata.productInfo.productKey); + Ql_iotDpSendTtlvRsp(app, endPoint, QIOT_DPCMD_LAN_DISCOVER_RSP, pkgId, ttlvHead); + Ql_iotTtlvFree(&ttlvHead); +} + + +/************************************************************************** +** 功能 @brief : LAN接收数据 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static qbool FUNCTION_ATTR_ROM ql_iotLanRecvData(void *chlFd, const void *peer, quint32_t peerSize, Quos_socketRecvDataNode_t *recvData) +{ + UNUSED(chlFd); + UNUSED(peer); + UNUSED(peerSize); + /* 在此缺少将peer加入通信总线管理 */ + if (recvData) + { + Ql_iotDpHandle(QIOT_DPAPP_LANPHONE, NULL, recvData->Buf, recvData->bufLen); + } + return TRUE; +} + +/************************************************************************** +** 功能 @brief : LAN初始化 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotCmdLanInit(void) +{ + Quos_socketChlInfoNode_t chlInfo; + HAL_MEMSET(&chlInfo, 0, sizeof(Quos_socketChlInfoNode_t)); + chlInfo.sockFd = Qhal_udpInit(&chlInfo.type, QIOT_LAN_PORT, NULL, 0, NULL); + Quos_logPrintf(QUEC_LAN, LL_DBG, "LANFd:" PRINTF_FD, chlInfo.sockFd); + if (SOCKET_FD_INVALID == chlInfo.sockFd) + { + Quos_logPrintf(QUEC_LAN, LL_ERR, "Listening on LAN port failed"); + return FALSE; + } + chlInfo.io.send = Qhal_sockWrite; + chlInfo.send.txCnt = 1; + chlInfo.send.timeout = QIOT_LAN_TIMEOUT; + chlInfo.recvDataFunc = ql_iotLanRecvData; + chlInfo.io.close = Qhal_sockClose; + lanChl = Quos_socketChannelAdd(NULL, chlInfo); + if (NULL == lanChl) + { + Quos_logPrintf(QUEC_LAN, LL_ERR, "add socket Channel fail"); + return FALSE; + } + return TRUE; +} +#endif diff --git a/cloud/common/ql_iotCmdLan.h b/cloud/common/ql_iotCmdLan.h new file mode 100644 index 0000000000000000000000000000000000000000..54593f9dabf5b8130c00007ac0483c4690b400a3 --- /dev/null +++ b/cloud/common/ql_iotCmdLan.h @@ -0,0 +1,18 @@ +#ifndef __QIOT_LAN_H__ +#define __QIOT_LAN_H__ +#include "Ql_iotApi.h" +#ifdef QUEC_ENABLE_LAN + +#define QIOT_LAN_PORT 40000 + +/* LAN TTLV ID */ +enum +{ + QIOT_DPID_LAN_MAC = 1, /* MAC */ + QIOT_DPID_LAN_PK = 2, /* PK */ +}; + +qbool Ql_iotCmdLanInit(void); +void ql_iotLanDevDiscover(QIot_dpAppType_e app, const char *endPoint, quint16_t pkgId, quint8_t *payload, quint16_t payloadLen); +#endif +#endif diff --git a/cloud/common/ql_iotCmdLoc.c b/cloud/common/ql_iotCmdLoc.c new file mode 100644 index 0000000000000000000000000000000000000000..7102da73ea9c15d1549d4eea288505ee49799def --- /dev/null +++ b/cloud/common/ql_iotCmdLoc.c @@ -0,0 +1,325 @@ +/************************************************************************* +** 创建人 @author : 吴健超 JCWu +** 版本 @version : V1.0.0 原始版本 +** 日期 @date : +** 功能 @brief : +** 硬件 @hardware: +** 其他 @other : +***************************************************************************/ +#include "ql_iotCmdLoc.h" +#include "ql_iotCmdSys.h" +#include "ql_iotConfig.h" +#include "ql_iotDp.h" +#include "ql_iotTtlv.h" +#include "Qhal_driver.h" + +#define QIOT_LOCATOR_SEPARATOR ";" + +/************************************************************************** +** 功能 @brief : 判断组合是否冲突 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotLocatoTitleClashCheck(const void *ttlvHead) +{ + quint32_t titleCnt = 0, titleSum = Ql_iotTtlvCountGet(ttlvHead); + for (titleCnt = 0; titleCnt < titleSum; titleCnt++) + { + char *value = Ql_iotTtlvNodeGetString(Ql_iotTtlvNodeGet(ttlvHead, titleCnt, NULL, NULL)); + if(NULL == value) + { + Quos_logPrintf(QUEC_LOC, LL_ERR, "title is null"); + return FALSE; + } + if (0 == HAL_STRCMP(value, QIOT_LOC_SUPPORT_AUTO) && 1 != titleSum) + { + Quos_logPrintf(QUEC_LOC, LL_ERR, "title[%s] nonuniqueness", value); + return FALSE; + } + else + { + quint32_t cnt1 = 0; + for (cnt1 = 0; cnt1 < titleSum; cnt1++) + { + char *value1 = Ql_iotTtlvNodeGetString(Ql_iotTtlvNodeGet(ttlvHead, cnt1, NULL, NULL)); + if(NULL == value1) + { + Quos_logPrintf(QUEC_LOC, LL_ERR, "title is null"); + return FALSE; + } + if (cnt1 != titleCnt && (HAL_STRSTR(value1, value) || HAL_STRSTR(value, value1))) + { + Quos_logPrintf(QUEC_LOC, LL_ERR, "title[%d][%s] is clash with No[%d][%s]", titleCnt, value, cnt1, value1); + return FALSE; + } + } + } + } + return TRUE; +} +/************************************************************************** +** 功能 @brief : 判断组合是否都支持 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotLocatoTitleSupportCheck(const void *ttlvHead) +{ + char *words[100]; + quint32_t listCnt = Qhal_propertyLocSupList(words, sizeof(words) / sizeof(words[0])); + quint32_t titleCnt = 0, titleSum = Ql_iotTtlvCountGet(ttlvHead); + for (titleCnt = 0; titleCnt < titleSum; titleCnt++) + { + char *title = Ql_iotTtlvNodeGetString(Ql_iotTtlvNodeGet(ttlvHead, titleCnt, NULL, NULL)); + if (NULL == title) + { + Quos_logPrintf(QUEC_LOC, LL_ERR, "title is empty"); + return FALSE; + } + quint32_t count; + for (count = 0; count < listCnt; count++) + { + if (0 == HAL_STRCMP(words[count], title)) + { + break; + } + } + if (count >= listCnt) + { + Quos_logPrintf(QUEC_LOC, LL_ERR, "title[%s] is no support", title); + return FALSE; + } + } + return TRUE; +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +char FUNCTION_ATTR_ROM *Ql_iotLocatorTtlv2String(const void *ttlv) +{ + quint32_t sum = Ql_iotTtlvCountGet(ttlv); + quint32_t cnt; + quint32_t len = 0; + for (cnt = 0; cnt < sum; cnt++) + { + char *locType = Ql_iotTtlvNodeGetString(Ql_iotTtlvNodeGet(ttlv, cnt, NULL, NULL)); + if (locType) + { + len += HAL_STRLEN(locType) + HAL_STRLEN(QIOT_LOCATOR_SEPARATOR); + } + } + char *buf; + if (0 == len || (buf = HAL_MALLOC(len + 1)) == NULL) + { + return NULL; + } + + for (cnt = 0, len = 0; cnt < sum; cnt++) + { + char *locType = Ql_iotTtlvNodeGetString(Ql_iotTtlvNodeGet(ttlv, cnt, NULL, NULL)); + if (locType) + { + len += HAL_SPRINTF(buf + len, "%s%s", locType, QIOT_LOCATOR_SEPARATOR); + } + } + return buf; +} +/************************************************************************** +** 功能 @brief : 计算NMEA语句CRC +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static quint8_t FUNCTION_ATTR_ROM ql_iotLocNmeaCrc(char *str, quint32_t len) +{ + quint8_t crc = 0; + if (NULL == str) + { + return 0; + } + while (len--) + { + crc ^= *str++; + } + return crc; +} +/************************************************************************** +** 功能 @brief : 获取LBS的模拟NMEA语句 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static qbool FUNCTION_ATTR_ROM ql_iotLocatorLbsNmeaRead(void **ttlv) +{ +#define IOT_LBSNMEA_FORMAT "$LBS,%u,%02u,%u,%u,%d,0*" + Qhal_propertyNet_t master, neibh[6]; + quint32_t count = 0; + if (FALSE == Qhal_propertyNetGet(&master, &neibh, sizeof(neibh) / sizeof(neibh[0]), &count) || + count > sizeof(neibh) / sizeof(neibh[0])) + { + return FALSE; + } + + char buf[100]; + quint32_t len = HAL_SPRINTF(buf, IOT_LBSNMEA_FORMAT, master.mcc, master.mnc, master.lac, master.cellid, master.rssi); + len += HAL_SPRINTF(buf + len, "%02d", ql_iotLocNmeaCrc(buf + 1, len - 2)); + buf[len] = 0; + Ql_iotTtlvIdAddString(ttlv, 0, buf); + while (count--) + { + quint32_t len = HAL_SPRINTF(buf, IOT_LBSNMEA_FORMAT, neibh[count].mcc, neibh[count].mnc, neibh[count].lac, neibh[count].cellid, neibh[count].rssi); + len += HAL_SPRINTF(buf + len, "%02d", ql_iotLocNmeaCrc(buf + 1, len - 2)); + buf[len] = 0; + Ql_iotTtlvIdAddString(ttlv, 0, buf); + } + return TRUE; +} + +/************************************************************************** +** 功能 @brief : 根据需求获取定位数据 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM *Ql_iotLocGetData(const void *titleTtlv) +{ + void *locDataTtlv = NULL; + quint32_t titleCnt = 0; + char *locType; + if (FALSE == Ql_iotLocatoTitleClashCheck(titleTtlv) || FALSE == Ql_iotLocatoTitleSupportCheck(titleTtlv)) + { + return NULL; + } + while ((locType = Ql_iotTtlvNodeGetString(Ql_iotTtlvNodeGet(titleTtlv, titleCnt++, NULL, NULL))) != NULL) + { + if (0 == HAL_STRCMP(locType, QIOT_LOC_SUPPORT_AUTO)) + { + if (FALSE == Qhal_propertyGnssRawDataRead(&locDataTtlv, "GGA")) + { + ql_iotLocatorLbsNmeaRead(&locDataTtlv); + } + } + else if (0 == HAL_STRCMP(locType, QIOT_LOC_SUPPORT_LBS)) + { + ql_iotLocatorLbsNmeaRead(&locDataTtlv); + } + else + { + Qhal_propertyGnssRawDataRead(&locDataTtlv, locType); + } + } + return locDataTtlv; +} +/************************************************************************** +** 功能 @brief : 定位数据发送结果 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void FUNCTION_ATTR_ROM ql_iotCmdBusLocReportCB(void *chlFd, const void *sendData, const void *recvData) +{ + UNUSED(chlFd); + UNUSED(sendData); + Ql_iotUrcEventCB(QIOT_ATEVENT_TYPE_SEND, recvData ? QIOT_SEND_SUCC_LOC : QIOT_SEND_ERR_FAIL_LOC, NULL, 0); +} + +/************************************************************************** +** 功能 @brief : 主动上报模组定位数据 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotCmdBusLocReportInside(void *titleTtlv) +{ + qbool ret = FALSE; + void *nmeaTtlv = Ql_iotLocGetData(titleTtlv); + if (NULL == nmeaTtlv) + { + Quos_logPrintf(QUEC_BUS, LL_ERR, "nmeaTtlv is null"); + return FALSE; + } + char *buf = Ql_iotLocatorTtlv2String(nmeaTtlv); + Ql_iotTtlvFree(&nmeaTtlv); + + void *reportTtlv = NULL; + Ql_iotTtlvIdAddString(&reportTtlv, 2, buf); + HAL_FREE(buf); + ret = Ql_iotDpSendTtlvReq(QIOT_DPAPP_M2M,NULL, 0, 1, QIOT_DPCMD_LOC_REPORT, reportTtlv, ql_iotCmdBusLocReportCB); + Ql_iotTtlvFree(&reportTtlv); + return ret; +} +/************************************************************************** +** 功能 @brief : 主动上报外部定位数据 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotCmdBusLocReportOutside(void *nmeaTtlv) +{ + qbool ret = FALSE; + if (NULL == nmeaTtlv) + { + Quos_logPrintf(QUEC_BUS, LL_ERR, "nmeaTtlv is null"); + return FALSE; + } + char *buf = Ql_iotLocatorTtlv2String(nmeaTtlv); + void *reportTtlv = NULL; + Ql_iotTtlvIdAddString(&reportTtlv, 2, buf); + HAL_FREE(buf); + ret = Ql_iotDpSendTtlvReq(QIOT_DPAPP_M2M,NULL, 0, 1, QIOT_DPCMD_LOC_REPORT, reportTtlv, ql_iotCmdBusLocReportCB); + Ql_iotTtlvFree(&reportTtlv); + return ret; +} + +/************************************************************************** +** 功能 @brief : 应答平台查询的实时内置定位数据 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Ql_iotCmdLocDataReqRecv(QIot_dpAppType_e app, const char *endPoint, quint16_t pkgId, quint8_t *payload, quint16_t payloadLen) +{ + void *titleTtlv = NULL; + void *ttlvHead = Ql_iotTtlvUnformat(payload, payloadLen); + char *cfgData = Ql_iotTtlvIdGetString(ttlvHead, 1); + if (cfgData) + { + char *words[100]; + quint32_t count = Quos_stringSplit(cfgData,HAL_STRLEN(cfgData), words, sizeof(words) / sizeof(words[0]), QIOT_LOCATOR_SEPARATOR, FALSE); + quint32_t i; + for (i = 0; i < count; i++) + { + Ql_iotTtlvIdAddString(&titleTtlv, 0, words[i]); + } + } + Ql_iotTtlvFree(&ttlvHead); + if (NULL == titleTtlv || FALSE == Ql_iotLocatoTitleClashCheck(titleTtlv)) + { + Ql_iotTtlvFree(&titleTtlv); + Ql_iotCmdSysExceReport(app,endPoint,QIOT_SERVER_ERRCODE_UNFORMAT_FAIL, pkgId); + } + else + { + void *locDataTtlv = Ql_iotLocGetData(titleTtlv); + Ql_iotTtlvFree(&titleTtlv); + char *buf = Ql_iotLocatorTtlv2String(locDataTtlv); + Ql_iotTtlvFree(&locDataTtlv); + + /* 以下locDataTtlv作用已变 */ + Ql_iotTtlvIdAddString(&locDataTtlv, 2, buf); + HAL_FREE(buf); + Ql_iotDpSendTtlvRsp(app,endPoint, QIOT_DPCMD_LOC_RSP, pkgId, locDataTtlv); + Ql_iotTtlvFree(&locDataTtlv); + } +} +/************************************************************************** +** 功能 @brief : 查询当前模组支持的内置定位至此类型 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM *Ql_iotLocGetSupList(void) +{ + char *words[100]; + quint32_t count = Qhal_propertyLocSupList(words, sizeof(words) / sizeof(words[0])); + quint32_t num; + void *titleTtlv = NULL; + for (num = 0; num < count; num++) + { + Ql_iotTtlvIdAddString(&titleTtlv, 0, words[num]); + } + return titleTtlv; +} \ No newline at end of file diff --git a/cloud/common/ql_iotCmdLoc.h b/cloud/common/ql_iotCmdLoc.h new file mode 100644 index 0000000000000000000000000000000000000000..3a770931b359f78af771e5289b77ef712016b149 --- /dev/null +++ b/cloud/common/ql_iotCmdLoc.h @@ -0,0 +1,9 @@ +#ifndef __QL_IOT_LOCATOR_H__ +#define __QL_IOT_LOCATOR_H__ +#include "Ql_iotApi.h" + +char *Ql_iotLocatorTtlv2String(const void *ttlv); +qbool Ql_iotLocatoTitleClashCheck(const void *ttlvHead); + +void FUNCTION_ATTR_ROM Ql_iotCmdLocDataReqRecv(QIot_dpAppType_e app, const char *endPoint, quint16_t pkgId, quint8_t *payload, quint16_t payloadLen); +#endif \ No newline at end of file diff --git a/cloud/common/ql_iotCmdOTA.c b/cloud/common/ql_iotCmdOTA.c new file mode 100644 index 0000000000000000000000000000000000000000..c146029cb642edbf78e9583d7f1c4e1c095b6221 --- /dev/null +++ b/cloud/common/ql_iotCmdOTA.c @@ -0,0 +1,889 @@ +/************************************************************************* +** 创建人 @author : 吴健超 JCWu +** 版本 @version : V1.0.0 原始版本 +** 日期 @date : 2020-12-25 +** 功能 @brief : dmp OTA,适配DMP2.2.0 +** 硬件 @hardware: +** 其他 @other : +***************************************************************************/ +#include "ql_iotCmdOTA.h" +#include "ql_iotConn.h" +#include "ql_iotDp.h" +#include "ql_iotTtlv.h" +#include "ql_iotConfig.h" +#include "Qhal_driver.h" + +Ql_iotCmdOtaInfo_t QIot_otaInfo; +static void *QIot_otaRuntimer = NULL; +static void *QIot_otaCachetimer = NULL; +static pointer_t QIot_otaFileFd = SOCKET_FD_INVALID; +static QIot_otaStatus_e QIot_otaCacheStatus = QIOT_OTA_STATUS_NOPLAN; +static Quos_socketChlInfoNode_t *sockInfo = NULL; +/************************************************************************** +** 功能 @brief : 升级过程事件上报 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static qbool FUNCTION_ATTR_ROM ql_iotCmdOtaStatusReport(QIot_otaStatus_e code) +{ + qbool ret = FALSE; + void *ttlvHead = NULL; + Quos_logPrintf(QUEC_OTA, LL_DBG, "event:%s", QIOT_OTA_STATUS_STRING(code)); + Ql_iotTtlvIdAddInt(&ttlvHead, QIOT_DPID_OTA_STATUS, code); + Ql_iotTtlvIdAddString(&ttlvHead, QIOT_DPID_OTA_MESSAGE, QIOT_OTA_STATUS_STRING(code)); + Ql_iotTtlvIdAddInt(&ttlvHead, QIOT_DPID_OTA_COMPONENT_TYPE, QIot_otaInfo.componentType); + Ql_iotTtlvIdAddString(&ttlvHead, QIOT_DPID_OTA_COMPONENT_NO, QIot_otaInfo.componentNo); + if(QIOT_OTA_EXTERN_SHA256 == QIot_otaInfo.extraMess && QIOT_OTA_STATUS_SUBMITOTA == code) + { + Ql_iotTtlvIdAddString(&ttlvHead, QIOT_DPID_OTA_DOWN_SIGN,"sha256"); + } + if (QIOT_OTA_STATUS_UPDATESUCCESS == code || QIOT_OTA_STATUS_UPDATEERROR == code) + { + Ql_iotTtlvIdAddString(&ttlvHead, QIOT_DPID_OTA_MODULE_VER, Qhal_softversionGet()); + char *version = NULL; + if (0 != Ql_iotConfigGetMcuVersion(NULL, &version)) + { + Ql_iotTtlvIdAddString(&ttlvHead, QIOT_DPID_OTA_MCU_VER, version); + } + } + //ret = Ql_iotDpSendTtlvOta(QIOT_DPCMD_OTA_EVENT, ttlvHead); + ret = Ql_iotDpSendTtlvReq(QIOT_DPAPP_M2M, NULL, 0, 2, QIOT_DPCMD_OTA_EVENT, ttlvHead, NULL); + Ql_iotTtlvFree(&ttlvHead); + return ret; +} +/************************************************************************** +** 功能 @brief : OTA请求 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotCmdOtaRequest(quint32_t mode) +{ + qbool ret = FALSE; + void *ttlvHead = NULL; + Ql_iotTtlvIdAddString(&ttlvHead, QIOT_DPID_OTA_MODULE_VER, Qhal_softversionGet()); + char *oldVer = NULL; + if (Ql_iotConfigGetMcuVersion(NULL, &oldVer) != 0) + { + Ql_iotTtlvIdAddString(&ttlvHead, QIOT_DPID_OTA_MCU_VER, oldVer); + } + //ret = Ql_iotDpSendTtlvOta(QIOT_DPCMD_OTA_REQUEST, ttlvHead); + ret = Ql_iotDpSendTtlvReq(QIOT_DPAPP_M2M, NULL, 0, 2, QIOT_DPCMD_OTA_REQUEST, ttlvHead, NULL); + Ql_iotTtlvFree(&ttlvHead); + if(ret && mode >= QIOT_OTA_EXTERN_MAX) + { + ret = FALSE; + } + QIot_otaInfo.extraMess = mode; + return ret; +} + +/************************************************************************** +** 功能 @brief : 等待URL超时 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void FUNCTION_ATTR_ROM ql_iotOtaWaitUrlTimeout(void *swtimer) +{ + Quos_logPrintf(QUEC_OTA, LL_ERR, "timeout"); + Quos_swTimerTimeoutSet(swtimer, SWT_SUSPEND); + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)QIOT_OTA_STATUS_UPDATEERROR); +} +/************************************************************************** +** 功能 @brief : HTTP下载超时 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void FUNCTION_ATTR_ROM ql_iotOtaWaitDownloadTimeout(void *swtimer) +{ + Quos_logPrintf(QUEC_OTA, LL_ERR, "timeout"); + Quos_swTimerTimeoutSet(swtimer, SWT_SUSPEND); + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)QIOT_OTA_STATUS_DOWNLOADERROR); +} +/************************************************************************** +** 功能 @brief : 更新超时 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void FUNCTION_ATTR_ROM ql_iotOtaWaitUpdateTimeout(void *swtimer) +{ + Quos_logPrintf(QUEC_OTA, LL_ERR, "timeout"); + Quos_swTimerTimeoutSet(swtimer, SWT_SUSPEND); + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)QIOT_OTA_STATUS_UPDATEERROR); +} +/************************************************************************** +** 功能 @brief : 下载中通知 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void FUNCTION_ATTR_ROM ql_iotOtaDownloading(void *swtimer) +{ + UNUSED(swtimer); + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)QIOT_OTA_STATUS_DOWNLOADING); +} +#if QUEC_ENABLE_QTH_OTA +/************************************************************************** +** 功能 @brief : 进入OTA更新 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void FUNCTION_ATTR_ROM ql_iotOtaUpdate(void *swtimer) +{ + quint32_t delayTime = 0; + delayTime = Qhal_devOtaNotify(QIOT_FILE_OTA, QIot_otaInfo.otaFileInfo.size); + if (delayTime) + { + Quos_swTimerTimeoutSet(swtimer, delayTime); + Quos_swTimerCBSet(swtimer, ql_iotOtaWaitUpdateTimeout); + } + else + { + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)QIOT_OTA_STATUS_UPDATEERROR); + Quos_swTimerTimeoutSet(swtimer, SWT_SUSPEND); + } +} +#endif +/************************************************************************** +** 功能 @brief : OTA文件下载通知 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static qbool FUNCTION_ATTR_ROM ql_iotOtaDownloadCB(qint32_t httpCode, char *retHeader, quint8_t *recvBuf, quint32_t recvLen) +{ + UNUSED(retHeader); + UNUSED(recvBuf); + Quos_logPrintf(QUEC_CONN, LL_DBG, "httpCode:%d recvLen:%u", httpCode, recvLen); + if (200 != httpCode && 206 != httpCode) + { + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)QIOT_OTA_STATUS_DOWNLOADERROR); + return FALSE; + } + if (0 == recvLen) + { + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)QIOT_OTA_STATUS_DOWNLOADING); + } + else + { + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)QIOT_OTA_STATUS_DOWNLOADSUCCESS); + } + return TRUE; +} +/************************************************************************** +** 功能 @brief : 下载文件 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void FUNCTION_ATTR_ROM ql_iotOtaDownload(void) +{ + QIot_otaInfo.currentPiece.size = QIot_otaInfo.otaFileInfo.size - QIot_otaInfo.currentPiece.startAddr < QIot_otaInfo.currentPiece.size ? QIot_otaInfo.otaFileInfo.size - QIot_otaInfo.currentPiece.startAddr : QIot_otaInfo.currentPiece.size; +#ifndef QHAL_DEV_OTA_ENABLE + char rawHeader[100]; + HttpReqData_t reqData; + HAL_MEMSET(&reqData, 0, sizeof(reqData)); + Quos_logPrintf(QUEC_OTA, LL_DBG, "start:%u len:%u", QIot_otaInfo.currentPiece.startAddr, QIot_otaInfo.currentPiece.size); + if (0 != QIot_otaInfo.currentPiece.startAddr || 0 != QIot_otaInfo.currentPiece.size) + { + reqData.rawHeaders = rawHeader; + HAL_SPRINTF(rawHeader, "Accept-Ranges: bytes\r\nRange: bytes=%u-%u\r\n", QIot_otaInfo.currentPiece.startAddr, QIot_otaInfo.currentPiece.startAddr + QIot_otaInfo.currentPiece.size - 1); + } + if (FALSE == Quos_httpGetDownload((void **)(&sockInfo), QIot_otaInfo.otaFileInfo.downloadUrl, ql_iotOtaDownloadCB, &reqData, QIOT_FILE_OTA, 0)) + { + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)QIOT_OTA_STATUS_DOWNLOADERROR); + } +#else + qhal_devOta_e ret = Qhal_devOtaDownload(QIot_otaInfo.otaFileInfo.downloadUrl, QIot_otaInfo.currentPiece.startAddr, QIot_otaInfo.currentPiece.size, QIOT_FILE_OTA, QIot_otaInfo.componentType); + Quos_swTimerTimeoutSet(QIot_otaRuntimer, SWT_SUSPEND); + if (QIOT_COMPTYPE_MCU == QIot_otaInfo.componentType && (QHAL_OTA_UPDATE_SUCC == ret || QHAL_OTA_UPDATE_FAIL == ret)) + { + Quos_logPrintf(QUEC_OTA, LL_ERR, "invalid download result"); + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)QIOT_OTA_STATUS_UPDATEERROR); + return; + } + switch (ret) + { + case QHAL_OTA_DOWN_START: + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)QIOT_OTA_STATUS_DOWNLOADING); + break; + case QHAL_OTA_DOWN_SUCC: + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)QIOT_OTA_STATUS_DOWNLOADSUCCESS); + break; + case QHAL_OTA_DOWN_FAIL: + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)QIOT_OTA_STATUS_DOWNLOADERROR); + break; + case QHAL_OTA_UPDATE_SUCC: + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)QIOT_OTA_STATUS_UPDATESUCCESS); + break; + case QHAL_OTA_UPDATE_FAIL: + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)QIOT_OTA_STATUS_UPDATEERROR); + break; + default: + break; + } +#endif +} + +/************************************************************************** +** 功能 @brief : MCU 版本确认 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Ql_iotCmdOtaMcuVersionModify(const char *compNo, const char *version) +{ + Quos_logPrintf(QUEC_OTA, LL_DBG, "version cur[%s:%s] new[%s:%s] componentType:%d currStatus:%s", compNo, version, QIot_otaInfo.componentNo, QIot_otaInfo.targetVersion, QIot_otaInfo.componentType, QIOT_OTA_STATUS_STRING(QIot_otaInfo.currStatus)); + QIot_otaStatus_e status = QIot_otaInfo.currStatus | QIot_otaCacheStatus; + switch (status) + { + case QIOT_OTA_STATUS_NOPLAN: + case QIOT_OTA_STATUS_REVICEPLAN: + case QIOT_OTA_STATUS_REFUSEDOTA: + case QIOT_OTA_STATUS_UPDATESUCCESS: + case QIOT_OTA_STATUS_UPDATEERROR: + break; + case QIOT_OTA_STATUS_SUBMITOTA: + case QIOT_OTA_STATUS_DOWNLOADSTART: + case QIOT_OTA_STATUS_DOWNLOADING: + case QIOT_OTA_STATUS_DOWNLOADERROR: + case QIOT_OTA_STATUS_DOWNLOADSUCCESS: + case QIOT_OTA_STATUS_UPDATING: + if (QIOT_COMPTYPE_MCU == QIot_otaInfo.componentType && 0 == HAL_STRCMP(compNo, QIot_otaInfo.componentNo)) + { + if (status < QIOT_OTA_STATUS_DOWNLOADSUCCESS && status >= QIOT_OTA_STATUS_DOWNLOADSTART && NULL != sockInfo && Quos_socketCheckChlFd(sockInfo) && TRUE == sockInfo->valid) + { + Qhal_sockClose(sockInfo->sockFd, sockInfo->type); + } + Quos_swTimerTimeoutSet(QIot_otaRuntimer, SWT_SUSPEND); + status = (0 == HAL_STRCMP(version, QIot_otaInfo.targetVersion)) ? QIOT_OTA_STATUS_UPDATESUCCESS : QIOT_OTA_STATUS_UPDATEERROR; + Quos_logPrintf(QUEC_OTA, LL_DBG, "status:%d", status); + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)status); + } + default: + break; + } +} +/************************************************************************** +** 功能 @brief : MCU数据读取 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +quint32_t FUNCTION_ATTR_ROM Ql_iotCmdOtaMcuFWDataRead(quint32_t startAddr, quint8_t data[], quint32_t maxLen) +{ + if (QIOT_OTA_STATUS_DOWNLOADSUCCESS != QIot_otaInfo.currStatus || + startAddr < QIot_otaInfo.currentPiece.startAddr || startAddr >= QIot_otaInfo.currentPiece.startAddr + QIot_otaInfo.currentPiece.size || + 0 == maxLen) + { + Quos_logPrintf(QUEC_OTA, LL_ERR, "currStatus:%s startAddr:%d/%d size:%d", QIOT_OTA_STATUS_STRING(QIot_otaInfo.currStatus), startAddr, QIot_otaInfo.currentPiece.startAddr, QIot_otaInfo.currentPiece.size); + return 0; + } + Quos_swTimerTimeoutSet(QIot_otaRuntimer, QIOT_OTA_WAIT_READ); + if (QIot_otaFileFd == SOCKET_FD_INVALID) + { + QIot_otaFileFd = Qhal_fileOpen(QIOT_FILE_OTA, TRUE); + } + if (SOCKET_FD_INVALID != QIot_otaFileFd) + { + quint32_t offset = startAddr - QIot_otaInfo.currentPiece.startAddr; + maxLen = QIot_otaInfo.currentPiece.size - offset < maxLen ? QIot_otaInfo.currentPiece.size - offset : maxLen; + Quos_logPrintf(QUEC_OTA, LL_DBG, "offset:%d size:%d maxLen:%d", offset, QIot_otaInfo.currentPiece.size, maxLen); + maxLen = Qhal_fileRead(QIot_otaFileFd, offset, data, maxLen); + if (0 == maxLen) + { + Quos_logPrintf(QUEC_OTA, LL_ERR, "file read len=%d", maxLen); + } + + return maxLen; + } + else + { + Quos_logPrintf(QUEC_OTA, LL_ERR, "open file fail fileFd:" PRINTF_LD, QIot_otaFileFd); + } + return 0; +} +/************************************************************************** +** 功能 @brief : 升级确认 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotCmdOtaAction(quint8_t action) +{ + qbool ret = FALSE; + Quos_logPrintf(QUEC_OTA, LL_DBG, "action:%u currStatus:%s", action, QIOT_OTA_STATUS_STRING(QIot_otaInfo.currStatus)); + switch (action) + { + case 0: + /* 模组把状态保存起来 */ + if (QIOT_OTA_STATUS_REVICEPLAN == QIot_otaInfo.currStatus) + { + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)QIOT_OTA_STATUS_REFUSEDOTA); + ret = TRUE; + if (TRUE == QIot_otaInfo.mutilPlansMode) + { + quint32_t flag = 0; + Ql_iotUrcEventCB(QIOT_ATEVENT_TYPE_OTA, QIOT_OTA_UPDATE_FLAG, &flag, sizeof(flag)); + } + } + break; + case 1: + if (QIOT_OTA_STATUS_REVICEPLAN == QIot_otaInfo.currStatus) + { + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)QIOT_OTA_STATUS_SUBMITOTA); + ret = TRUE; + if (TRUE == QIot_otaInfo.mutilPlansMode) + { + quint32_t flag = 0; + Ql_iotUrcEventCB(QIOT_ATEVENT_TYPE_OTA, QIOT_OTA_UPDATE_FLAG, &flag, sizeof(flag)); + } + } + else if (QIOT_OTA_STATUS_SUBMITOTA == QIot_otaInfo.currStatus) + { + ret = TRUE; + } + break; + case 2: + if (QIOT_COMPTYPE_MCU == QIot_otaInfo.componentType && QIot_otaInfo.otaFileInfo.size > 0 && QIOT_OTA_STATUS_DOWNLOADSUCCESS == QIot_otaInfo.currStatus) + { + if (QIot_otaInfo.currentPiece.startAddr + QIot_otaInfo.currentPiece.size < QIot_otaInfo.otaFileInfo.size) + { + QIot_otaInfo.currentPiece.startAddr += QIot_otaInfo.currentPiece.size; + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)QIOT_OTA_STATUS_DOWNLOADSTART); + ret = TRUE; + } + } + break; + case 3: + if (QIOT_COMPTYPE_MCU == QIot_otaInfo.componentType) + { + if (QIOT_OTA_STATUS_DOWNLOADSUCCESS == QIot_otaInfo.currStatus) + { + if (QIot_otaInfo.currentPiece.startAddr + QIot_otaInfo.currentPiece.size >= QIot_otaInfo.otaFileInfo.size) + { + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)QIOT_OTA_STATUS_UPDATING); + ret = TRUE; + } + } + else if (QIOT_OTA_STATUS_UPDATING == QIot_otaInfo.currStatus) + { + ret = TRUE; + } + } + break; + default: + break; + } + return ret; +} +/************************************************************************** +** 功能 @brief : OTA 组件处理 +** 输入 @param : ttlvHead:ttlv链表头 mode:FALSE:首次或单个 TRUE: 多个组件 +** 输出 @retval: +***************************************************************************/ +static qbool FUNCTION_ATTR_ROM ql_iotOtaPlanHandle(void *ttlvHead) +{ + qint64_t componentType = 0; + char *componentNo = Ql_iotTtlvIdGetString(ttlvHead, QIOT_DPID_OTA_COMPONENT_NO); + char *sourceVersion = Ql_iotTtlvIdGetString(ttlvHead, QIOT_DPID_OTA_SOURCE_VER); + char *targetVersion = Ql_iotTtlvIdGetString(ttlvHead, QIOT_DPID_OTA_TARGET_VER); + if (NULL == componentNo || NULL == targetVersion || QIOT_COMPVER_MAXSIZE < HAL_STRLEN(targetVersion) || FALSE == Ql_iotTtlvIdGetInt(ttlvHead, QIOT_DPID_OTA_COMPONENT_TYPE, &componentType)) // || FALSE == Ql_iotTtlvIdGetInt(ttlvHead, QIOT_DPID_OTA_COMPONENT_TYPE, &componentType) + { + Quos_logPrintf(QUEC_OTA, LL_DBG, "info invalid"); + return FALSE; + } + char *tmpBuf = HAL_MALLOC(HAL_STRLEN(componentNo) + HAL_STRLEN(sourceVersion) + HAL_STRLEN(targetVersion) + 4 * 11 + 11 + 1); + if (tmpBuf) + { + qint64_t batteryLimit, minSignalIntensity, useSpace; + int64_t planMode; + HAL_SPRINTF(tmpBuf, "\"%s\",\"%s\",\"%s\",%u,%d,%u", (char *)componentNo, + sourceVersion ? sourceVersion : (char *)"", + (char *)targetVersion, + Ql_iotTtlvIdGetInt(ttlvHead, QIOT_DPID_OTA_BATTERY_LIMIT, &batteryLimit) ? (quint32_t)batteryLimit : 0, + Ql_iotTtlvIdGetInt(ttlvHead, QIOT_DPID_OTA_MIN_SIGNAL, &minSignalIntensity) ? (qint32_t)minSignalIntensity : 0, + Ql_iotTtlvIdGetInt(ttlvHead, QIOT_DPID_OTA_USE_SPACE, &useSpace) ? (quint32_t)useSpace : 0); + + Ql_iotUrcEventCB(QIOT_ATEVENT_TYPE_OTA, QIOT_OTA_TASK_NOTIFY, tmpBuf, HAL_STRLEN(tmpBuf)); + HAL_SNPRINTF(QIot_otaInfo.componentNo, sizeof(QIot_otaInfo.componentNo), "%s", componentNo); + QIot_otaInfo.componentType = componentType; + if (TRUE == Ql_iotTtlvIdGetInt(ttlvHead, QIOT_DPID_OTA_HANDLE_TYPE, &planMode) && QIOT_COMPTYPE_MODULE == componentType) + { + Ql_iotCmdOtaAction(1); + } + HAL_FREE(tmpBuf); + } + return TRUE; +} + +/************************************************************************** +** 功能 @brief : OTA任务下发 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Ql_iotCmdOtaNotify(QIot_dpAppType_e app, const char *endPoint, quint16_t pkgId, quint8_t *payload, quint16_t payloadLen) +{ + UNUSED(app); + UNUSED(endPoint); + UNUSED(pkgId); + Quos_logPrintf(QUEC_OTA, LL_DBG, "recv task"); + if (QIOT_OTA_STATUS_NOPLAN != QIot_otaInfo.currStatus && QIOT_OTA_STATUS_REVICEPLAN != QIot_otaInfo.currStatus) + { + Quos_logPrintf(QUEC_OTA, LL_ERR, "current is %s and no restart", QIOT_OTA_STATUS_STRING(QIot_otaInfo.currStatus)); + return; + } + void *ttlvHead = Ql_iotTtlvUnformat(payload, payloadLen); + void *mutilPlans = Ql_iotTtlvIdGetStruct(ttlvHead, QIOT_DPID_OTA_TASK_INFO); + int count = 0; + if (mutilPlans != NULL) + { + count = Ql_iotTtlvCountGet(mutilPlans); + if (count > 20) + { + Ql_iotTtlvFree(&ttlvHead); + return; + } + int count_i = 0; + QIot_otaInfo.mutilPlansMode = TRUE; + for (count_i = 0; count_i < count; count_i++) + { + void *planStruct = Ql_iotTtlvNodeGet(mutilPlans, count_i, NULL, NULL); + void *childNode = Ql_iotTtlvNodeGetStruct(planStruct); + if (FALSE == ql_iotOtaPlanHandle(childNode)) + continue; + } + } + else + { + QIot_otaInfo.mutilPlansMode = FALSE; + ql_iotOtaPlanHandle(ttlvHead); + } + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)QIOT_OTA_STATUS_REVICEPLAN); + Ql_iotTtlvFree(&ttlvHead); + return; +} +#if QUEC_ENABLE_QTH_OTA==0 +/************************************************************************** +** 功能 @brief : 多固件下发 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static qbool ql_iotCmdOtaFwList(quint8_t *payload, quint32_t len, qbool *isMutilFileInfo) +{ + qint64_t componentType; + void *ttlvHead = Ql_iotTtlvUnformat(payload, len); + + char *componentNo = Ql_iotTtlvIdGetString(ttlvHead, QIOT_DPID_OTA_COMPONENT_NO); + char *targetVersion = Ql_iotTtlvIdGetString(ttlvHead, QIOT_DPID_OTA_TARGET_VER); + if (NULL == componentNo || NULL == targetVersion || FALSE == Ql_iotTtlvIdGetInt(ttlvHead, QIOT_DPID_OTA_COMPONENT_TYPE, &componentType)) + { + goto exit; + } + char *filemd5 = Ql_iotTtlvIdGetString(ttlvHead, QIOT_DPID_OTA_DOWN_MD5); + char *filecrc = Ql_iotTtlvIdGetString(ttlvHead, QIOT_DPID_OTA_DOWN_CRC); + char *filesha256 = Ql_iotTtlvIdGetString(ttlvHead, QIOT_DPID_OTA_DOWN_SHA256); + char *download_url = Ql_iotTtlvIdGetString(ttlvHead, QIOT_DPID_OTA_DOWN_URL); + char *infoArray = Ql_iotTtlvIdGetStruct(ttlvHead, QIOT_DPID_OTA_DOWN_INFO); + if (infoArray != NULL) + { + if (NULL == filemd5 && NULL == filecrc && NULL == filesha256 && NULL == download_url && QIOT_COMPTYPE_MODULE == componentType) + { + quint32_t count = Ql_iotTtlvCountGet(infoArray); + if (count > 5) + { + goto exit; + } + *isMutilFileInfo = TRUE; + QIot_otaFilePublicInfo_t otaInfoArray[QIOT_OTA_FILEINFO_MAX_SIZE]; + HAL_MEMSET(otaInfoArray, 0, sizeof(QIot_otaFilePublicInfo_t) * QIOT_OTA_FILEINFO_MAX_SIZE); + quint32_t array_i = 0; + for (array_i = 0; array_i < count; array_i++) + { + char *info = Ql_iotTtlvNodeGet(infoArray, array_i, NULL, NULL); + void *childNode = Ql_iotTtlvNodeGetStruct(info); + if (info != NULL) + { + int64_t idex = 0; + char *info_url = Ql_iotTtlvIdGetString(childNode, QIOT_DPID_OTA_DOWN_URL); + char *info_filemd5 = Ql_iotTtlvIdGetString(childNode, QIOT_DPID_OTA_DOWN_MD5); + qint64_t info_filesize; + if (NULL == info_url || NULL == info_filemd5 || + FALSE == Ql_iotTtlvIdGetInt(childNode, QIOT_DPID_OTA_DOWN_INFO_IDEX, (int64_t *)&idex) || + FALSE == Ql_iotTtlvIdGetInt(childNode, QIOT_DPID_OTA_DOWN_SIZE, &info_filesize)) + { + Quos_logPrintf(QUEC_OTA, LL_DBG, "info invalid"); + goto exit; + } + otaInfoArray[array_i].idex = idex & 0xFF; + otaInfoArray[array_i].downloadUrl = HAL_MALLOC(HAL_STRLEN(info_url) + 1); + HAL_SNPRINTF(otaInfoArray[array_i].downloadUrl, HAL_STRLEN(info_url) + 1, "%s",info_url); + HAL_SNPRINTF(otaInfoArray[array_i].md5, sizeof(otaInfoArray[array_i].md5), "%s", info_filemd5); + otaInfoArray[array_i].size = info_filesize; + } + else + { + goto exit; + } + } + quint32_t timeout = Qhal_devOtaNotify(otaInfoArray, array_i); + for (array_i = 0; array_i < count; array_i++) + HAL_FREE(otaInfoArray[array_i].downloadUrl); + Quos_swTimerTimeoutSet(QIot_otaRuntimer, timeout); + Quos_swTimerCBSet(QIot_otaRuntimer, ql_iotOtaWaitUpdateTimeout); + } + } + Ql_iotTtlvFree(&ttlvHead); + return TRUE; +exit: + Ql_iotTtlvFree(&ttlvHead); + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)QIOT_OTA_STATUS_UPDATEERROR); + return FALSE; +} +#endif +/************************************************************************** +** 功能 @brief : OTA URL下发 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Ql_iotCmdOtaFwInfo(QIot_dpAppType_e app, const char *endPoint, quint16_t pkgId, quint8_t *payload, quint16_t payloadLen) +{ + UNUSED(app); + UNUSED(endPoint); + UNUSED(pkgId); + Quos_logPrintf(QUEC_OTA, LL_DBG, "recv url"); + if (QIOT_OTA_STATUS_NOPLAN != QIot_otaInfo.currStatus && QIOT_OTA_STATUS_SUBMITOTA != QIot_otaInfo.currStatus) + { + Quos_logPrintf(QUEC_OTA, LL_ERR, "current is %s and no repeat download", QIOT_OTA_STATUS_STRING(QIot_otaInfo.currStatus)); + return; + } + Quos_swTimerTimeoutSet(QIot_otaRuntimer, SWT_SUSPEND); /* 收到URL,关闭等待URL超时定时器 */ + HAL_FREE(QIot_otaInfo.otaFileInfo.downloadUrl); + QIot_otaInfo.otaFileInfo.downloadUrl = NULL; + #if QUEC_ENABLE_QTH_OTA==0 + qbool isMutilFileInfo = FALSE; + ql_iotCmdOtaFwList(payload, payloadLen, &isMutilFileInfo); + if (isMutilFileInfo == TRUE) + { + return; + } + #endif + void *ttlvHead = Ql_iotTtlvUnformat(payload, payloadLen); + qint64_t filesize, componentType; + char *filemd5 = Ql_iotTtlvIdGetString(ttlvHead, QIOT_DPID_OTA_DOWN_MD5); + char *filecrc = Ql_iotTtlvIdGetString(ttlvHead, QIOT_DPID_OTA_DOWN_CRC); + char *filesha256 = NULL; + if (QIOT_OTA_EXTERN_SHA256 == QIot_otaInfo.extraMess) + { + filesha256 = Ql_iotTtlvIdGetString(ttlvHead, QIOT_DPID_OTA_DOWN_SHA256); + } + char *componentNo = Ql_iotTtlvIdGetString(ttlvHead, QIOT_DPID_OTA_COMPONENT_NO); + char *download_url = Ql_iotTtlvIdGetString(ttlvHead, QIOT_DPID_OTA_DOWN_URL); + char *targetVersion = Ql_iotTtlvIdGetString(ttlvHead, QIOT_DPID_OTA_TARGET_VER); + if (NULL == filemd5 || NULL == filecrc || NULL == componentNo || NULL == download_url || NULL == targetVersion || + (QIOT_OTA_EXTERN_SHA256 == QIot_otaInfo.extraMess && NULL == filesha256) || + FALSE == Ql_iotTtlvIdGetInt(ttlvHead, QIOT_DPID_OTA_DOWN_SIZE, &filesize) || + FALSE == Ql_iotTtlvIdGetInt(ttlvHead, QIOT_DPID_OTA_COMPONENT_TYPE, &componentType) || + QIOT_MD5_MAXSIZE != HAL_STRLEN(filemd5) || + QIOT_COMPNO_MAXSIZE < HAL_STRLEN(componentNo) || + QIOT_COMPVER_MAXSIZE < HAL_STRLEN(targetVersion) || + (QIot_otaInfo.otaFileInfo.downloadUrl = HAL_STRDUP((char *)download_url)) == NULL) + { + Quos_logPrintf(QUEC_OTA, LL_DBG, "info invalid"); + Ql_iotTtlvFree(&ttlvHead); + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)QIOT_OTA_STATUS_UPDATEERROR); + return; + } + HAL_SPRINTF(QIot_otaInfo.componentNo, "%s", componentNo); + HAL_SPRINTF(QIot_otaInfo.targetVersion, "%s", targetVersion); + QIot_otaInfo.componentType = (QIot_otaComptype_e)componentType; + QIot_otaInfo.otaFileInfo.size = filesize; + HAL_SPRINTF(QIot_otaInfo.otaFileInfo.md5, "%s", filemd5); + QIot_otaInfo.crc = HAL_STRTOUL(filecrc, NULL, 16); + if (filesha256 != NULL) + { + HAL_SPRINTF(QIot_otaInfo.sha256, "%s", filesha256); + } + Ql_iotTtlvFree(&ttlvHead); + Qhal_propertyDev_t dInfo; + HAL_MEMSET(&dInfo, 0, sizeof(Qhal_propertyDev_t)); + Qhal_propertyDevGet(&dInfo); + if (QIOT_COMPTYPE_MODULE == QIot_otaInfo.componentType && dInfo.flashFree < QIot_otaInfo.otaFileInfo.size) + { + Quos_logPrintf(QUEC_OTA, LL_ERR, "no enough space"); + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)QIOT_OTA_STATUS_UPDATEERROR); + return; + } + + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)QIOT_OTA_STATUS_DOWNLOADSTART); + QIot_otaInfo.currentPiece.startAddr = 0; + QIot_otaInfo.currentPiece.size = dInfo.flashFree > QIot_otaInfo.otaFileInfo.size ? QIot_otaInfo.otaFileInfo.size : dInfo.flashFree; +} +/************************************************************************** +** 功能 @brief : 缓存状态上报 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void FUNCTION_ATTR_ROM ql_iotCmdOtaCacheReport(void *swtimer) +{ + UNUSED(swtimer); + Quos_logPrintf(QUEC_OTA, LL_DBG, "cache status report:%s.", QIOT_OTA_STATUS_STRING(QIot_otaCacheStatus)); + if (QIOT_OTA_STATUS_NOPLAN != QIot_otaCacheStatus) + { + if (TRUE == ql_iotCmdOtaStatusReport(QIot_otaCacheStatus)) + { + QIot_otaCacheStatus = QIOT_OTA_STATUS_NOPLAN; + } + } +} + +/************************************************************************** +** 功能 @brief : OTA事件处理 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void ql_iotCmdOtaEventNotify(qint32_t event, void *arg) +{ + static quint8_t downLoadFailCount = 0; + static qbool downloadStartFlag = TRUE; + switch (event) + { + case QIOT_ATEVENT_TYPE_OTA: + { + QIot_otaStatus_e status = (QIot_otaStatus_e)(pointer_t)arg; + Quos_logPrintf(QUEC_OTA, LL_DBG, "event:%s status:[%d]%s", QIOT_ATEVENT_TYPE_STRING(event), status, QIOT_OTA_STATUS_STRING(status)); + QIot_otaInfo.currStatus = status; + Ql_iotDSKVSave(); + switch (status) + { + case QIOT_OTA_STATUS_NOPLAN: + Quos_swTimerTimeoutSet(QIot_otaRuntimer, SWT_SUSPEND); + HAL_FREE(QIot_otaInfo.otaFileInfo.downloadUrl); + QIot_otaInfo.otaFileInfo.downloadUrl = NULL; + QIot_otaInfo.otaFileInfo.size = 0; + QIot_otaInfo.currentPiece.startAddr = 0; + QIot_otaInfo.currentPiece.size = 0; + Ql_iotDSKVSave(); + if (QIot_otaFileFd != SOCKET_FD_INVALID) + { + Qhal_fileClose(QIot_otaFileFd); + QIot_otaFileFd = SOCKET_FD_INVALID; + } + Qhal_fileErase(QIOT_FILE_OTA); + break; + case QIOT_OTA_STATUS_REVICEPLAN: + Quos_swTimerTimeoutSet(QIot_otaRuntimer, SWT_SUSPEND); + break; + case QIOT_OTA_STATUS_SUBMITOTA: + Quos_swTimerTimeoutSet(QIot_otaRuntimer, QIOT_OTA_WAIT_URL_TIMEOUT); + Quos_swTimerCBSet(QIot_otaRuntimer, ql_iotOtaWaitUrlTimeout); + break; + case QIOT_OTA_STATUS_REFUSEDOTA: + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)QIOT_OTA_STATUS_NOPLAN); + break; + case QIOT_OTA_STATUS_DOWNLOADSTART: + if (downloadStartFlag) + { + if (QIOT_COMPTYPE_MODULE == QIot_otaInfo.componentType) + { + Ql_iotUrcEventCB(QIOT_ATEVENT_TYPE_OTA, QIOT_OTA_START, NULL, 0); + } + else if (QIOT_COMPTYPE_MCU == QIot_otaInfo.componentType) + { + char tmpBuf[QIOT_COMPNO_MAXSIZE + 10 + QIOT_MD5_MAXSIZE + 10 + 7 + QUOS_SHA256_DIGEST_LENGTH * 2 + 1]; + HAL_SPRINTF(tmpBuf, "\"%.*s\",%u,\"%s\",%u", QIOT_COMPNO_MAXSIZE, QIot_otaInfo.componentNo, QIot_otaInfo.otaFileInfo.size, QIot_otaInfo.otaFileInfo.md5, QIot_otaInfo.crc); + if (QIOT_OTA_EXTERN_SHA256 == QIot_otaInfo.extraMess) + { + HAL_SPRINTF(tmpBuf + HAL_STRLEN(tmpBuf), ",\"%s\"", QIot_otaInfo.sha256); + } + Ql_iotUrcEventCB(QIOT_ATEVENT_TYPE_OTA, QIOT_OTA_START, tmpBuf, HAL_STRLEN(tmpBuf)); + } + downloadStartFlag = FALSE; + } + else + { + Ql_iotUrcEventCB(QIOT_ATEVENT_TYPE_OTA, QIOT_OTA_DOWNLOADING, NULL, 0); + } + #if QUEC_ENABLE_QTH_OTA == 0 + if (QIOT_COMPTYPE_MODULE == QIot_otaInfo.componentType) + { + quint32_t timeout = Qhal_devOtaNotify(&(QIot_otaInfo.otaFileInfo), 1); + Quos_swTimerTimeoutSet(QIot_otaRuntimer, timeout); + Quos_swTimerCBSet(QIot_otaRuntimer, ql_iotOtaWaitUpdateTimeout); + } + else + { + #endif + Quos_swTimerTimeoutSet(QIot_otaRuntimer, QIOT_OTA_DOWNLOADING_NOTIFY); + Quos_swTimerCBSet(QIot_otaRuntimer, ql_iotOtaWaitDownloadTimeout); + ql_iotOtaDownload(); + #if QUEC_ENABLE_QTH_OTA == 0 + } + #endif + break; + case QIOT_OTA_STATUS_DOWNLOADING: + Quos_swTimerTimeoutSet(QIot_otaRuntimer, QIOT_OTA_DOWNLOADING_NOTIFY); + Quos_swTimerCBSet(QIot_otaRuntimer, ql_iotOtaDownloading); + Ql_iotUrcEventCB(QIOT_ATEVENT_TYPE_OTA, QIOT_OTA_DOWNLOADING, NULL, 0); + break; + case QIOT_OTA_STATUS_DOWNLOADERROR: + /* 连续下载QIOT_OTA_DOWNLOAD_FAIL_COUNT_MAX次失败则上报更新失败 */ + downLoadFailCount++; + Quos_logPrintf(QUEC_OTA, LL_ERR, "downLoadFailCount:%d", downLoadFailCount); + if (downLoadFailCount > QIOT_OTA_DOWNLOAD_FAIL_COUNT_MAX) + { + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)QIOT_OTA_STATUS_UPDATEERROR); + return; + } + else + { + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)QIOT_OTA_STATUS_NOPLAN); + } + break; + case QIOT_OTA_STATUS_DOWNLOADSUCCESS: + Quos_swTimerTimeoutSet(QIot_otaRuntimer, SWT_SUSPEND); + if (QIOT_COMPTYPE_MODULE == QIot_otaInfo.componentType) + { + char md5String[33]; + if (FALSE == Quos_fileMd5(QIOT_FILE_OTA, QIot_otaInfo.otaFileInfo.size, md5String) || 0 != HAL_STRCMP(QIot_otaInfo.otaFileInfo.md5, md5String)) + { + Quos_logPrintf(QUEC_OTA, LL_ERR, "md5 calc:%s ser:%s", md5String, QIot_otaInfo.otaFileInfo.md5); + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)QIOT_OTA_STATUS_DOWNLOADERROR); + } + else + { + Ql_iotUrcEventCB(QIOT_ATEVENT_TYPE_OTA, QIOT_OTA_DOWNLOADED, NULL, 0); + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)QIOT_OTA_STATUS_UPDATING); + } + } + else if (QIOT_COMPTYPE_MCU == QIot_otaInfo.componentType && QIot_otaInfo.otaFileInfo.size > 0) + { + Quos_swTimerTimeoutSet(QIot_otaRuntimer, QIOT_OTA_WAIT_READ); + Quos_swTimerCBSet(QIot_otaRuntimer, ql_iotOtaWaitUpdateTimeout); + char tmpBuf[QIOT_COMPNO_MAXSIZE + 3 * 10 + 5 + 1]; + HAL_SPRINTF(tmpBuf, "\"%.*s\",%u,%u,%u", QIOT_COMPNO_MAXSIZE, QIot_otaInfo.componentNo, QIot_otaInfo.otaFileInfo.size, QIot_otaInfo.currentPiece.startAddr, QIot_otaInfo.currentPiece.size); + Ql_iotUrcEventCB(QIOT_ATEVENT_TYPE_OTA, QIOT_OTA_DOWNLOADED, tmpBuf, HAL_STRLEN(tmpBuf)); + } + break; + case QIOT_OTA_STATUS_UPDATING: + Quos_swTimerTimeoutSet(QIot_otaRuntimer, SWT_SUSPEND); + if (QIOT_COMPTYPE_MODULE == QIot_otaInfo.componentType) + { + #if QUEC_ENABLE_QTH_OTA + Quos_swTimerTimeoutSet(QIot_otaRuntimer, QIOT_OTA_UPDATE_DELAY); + Quos_swTimerCBSet(QIot_otaRuntimer, ql_iotOtaUpdate); + #endif + } + else if (QIOT_COMPTYPE_MCU == QIot_otaInfo.componentType) + { + Quos_swTimerTimeoutSet(QIot_otaRuntimer, QIOT_OTA_UPDATE_TIMEOUT); + Quos_swTimerCBSet(QIot_otaRuntimer, ql_iotOtaWaitUpdateTimeout); + } + Ql_iotUrcEventCB(QIOT_ATEVENT_TYPE_OTA, QIOT_OTA_UPDATING, NULL, 0); + break; + case QIOT_OTA_STATUS_UPDATESUCCESS: + case QIOT_OTA_STATUS_UPDATEERROR: + Quos_swTimerTimeoutSet(QIot_otaRuntimer, SWT_SUSPEND); + downLoadFailCount = 0; + downloadStartFlag = TRUE; + Ql_iotUrcEventCB(QIOT_ATEVENT_TYPE_OTA, status == QIOT_OTA_STATUS_UPDATESUCCESS ? QIOT_OTA_UPDATE_OK : QIOT_OTA_UPDATE_FAIL, NULL, 0); + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)QIOT_OTA_STATUS_NOPLAN); + break; + default: + return; + } + if (QIOT_OTA_STATUS_NOPLAN != status) + { + if (FALSE == ql_iotCmdOtaStatusReport(status)) + { + Quos_logPrintf(QUEC_OTA, LL_DBG, "report status fail,cache status:%s.", QIOT_OTA_STATUS_STRING(status)); + QIot_otaCacheStatus = status; + } + else + { + Quos_swTimerDelete(QIot_otaCachetimer); + QIot_otaCacheStatus = QIOT_OTA_STATUS_NOPLAN; + } + } + break; + } + case QIOT_ATEVENT_TYPE_SUBCRIBE: + { + switch ((qint32_t)(pointer_t)arg) + { + case QIOT_SUBCRIBE_SUCC: + { + Quos_logPrintf(QUEC_OTA, LL_DBG, "cache status:%s.", QIOT_OTA_STATUS_STRING(QIot_otaCacheStatus)); + if (QIOT_OTA_STATUS_NOPLAN != QIot_otaCacheStatus) + { + Quos_swTimerStart(&QIot_otaCachetimer, "Cache", 0, 1, ql_iotCmdOtaCacheReport, NULL); + } + break; + } + default: + break; + } + break; + } + default: + break; + } +} + +/************************************************************************** +** 功能 @brief : OTA状态恢复 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Ql_iotCmdOtaStatusRecovery(void) +{ + Quos_logPrintf(QUEC_OTA, LL_DBG, "ota status:%s.", QIOT_OTA_STATUS_STRING(QIot_otaInfo.currStatus)); +#ifdef QHAL_DEV_OTA_ENABLE + if (QIOT_OTA_STATUS_DOWNLOADSTART == QIot_otaInfo.currStatus && QIOT_COMPTYPE_MCU == QIot_otaInfo.componentType) + { + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, 0 == HAL_STRCMP(QIot_otaInfo.targetVersion, QIot_userdata.softversion) ? (void *)QIOT_OTA_STATUS_UPDATESUCCESS : (void *)QIOT_OTA_STATUS_UPDATEERROR); + return; + } +#endif + switch (QIot_otaInfo.currStatus) + { + case QIOT_OTA_STATUS_NOPLAN: + break; + case QIOT_OTA_STATUS_SUBMITOTA: + case QIOT_OTA_STATUS_DOWNLOADSTART: + case QIOT_OTA_STATUS_DOWNLOADING: + case QIOT_OTA_STATUS_DOWNLOADSUCCESS: + if (QIOT_COMPTYPE_MODULE == QIot_otaInfo.componentType && 0 == HAL_STRCMP(QIot_otaInfo.targetVersion, QIot_userdata.softversion)) + { + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)QIOT_OTA_STATUS_UPDATESUCCESS); + } + else + { + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)QIOT_OTA_STATUS_DOWNLOADERROR); + } + break; + case QIOT_OTA_STATUS_DOWNLOADERROR: + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)QIOT_OTA_STATUS_DOWNLOADERROR); + break; + case QIOT_OTA_STATUS_UPDATING: + if (QIOT_COMPTYPE_MODULE == QIot_otaInfo.componentType) + { + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, 0 == HAL_STRCMP(QIot_otaInfo.targetVersion, QIot_userdata.softversion) ? (void *)QIOT_OTA_STATUS_UPDATESUCCESS : (void *)QIOT_OTA_STATUS_UPDATEERROR); + } + else if (QIOT_COMPTYPE_MCU == QIot_otaInfo.componentType) + { + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)QIOT_OTA_STATUS_UPDATING); + } + break; + default: + Quos_eventPost(QIOT_ATEVENT_TYPE_OTA, (void *)QIOT_OTA_STATUS_NOPLAN); + break; + } +} + +/************************************************************************** +** 功能 @brief : OTA任务初始化 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Ql_iotCmdOtaInit(void) +{ + HAL_MEMSET(&QIot_otaInfo, 0, sizeof(QIot_otaInfo)); + qint32_t event[] = {QIOT_ATEVENT_TYPE_OTA, QIOT_ATEVENT_TYPE_SUBCRIBE, QIOT_ATEVENT_TYPE_LOGOUT}; + Quos_eventCbReg(event, sizeof(event) / sizeof(event[0]), ql_iotCmdOtaEventNotify); + Quos_swTimerStart(&QIot_otaRuntimer, "OTA", SWT_SUSPEND, 0, NULL, NULL); + Qhal_fileErase(QIOT_FILE_OTA); +} diff --git a/cloud/common/ql_iotCmdOTA.h b/cloud/common/ql_iotCmdOTA.h new file mode 100644 index 0000000000000000000000000000000000000000..13a29da620240c88f14d4989241f6cdb744f1b99 --- /dev/null +++ b/cloud/common/ql_iotCmdOTA.h @@ -0,0 +1,115 @@ +#ifndef __QIOT_CMDOTA_H__ +#define __QIOT_CMDOTA_H__ +#include "Ql_iotApi.h" +#include "Qhal_driver.h" + +#define QIOT_COMPNO_MAXSIZE (32) /* 组件名称最大长度 */ +#define QIOT_COMPVER_MAXSIZE (64) /* 组件版本最大长度 */ +#define QIOT_OTA_WAIT_URL_TIMEOUT (30 * SWT_ONE_SECOND) /* 确认升级等待获取URL超时时间 */ +#define QIOT_OTA_WAIT_READ (60 * SWT_ONE_SECOND) /* SOTA升级模组通知MCU下载完成,MCU超时不读取数据将判为升级失败 */ +#define QIOT_OTA_UPDATE_TIMEOUT (20 * SWT_ONE_MINUTE) +#define QIOT_OTA_DOWNLOADING_NOTIFY (5 * SWT_ONE_SECOND) +#define QIOT_OTA_DOWNLOAD_FAIL_COUNT_MAX 5 /* 最大允许下载失败次数 */ +#define QIOT_OTA_UPDATE_DELAY (5 * SWT_ONE_SECOND) /* 模组下载完成,延缓进入升级,保留几秒完成状态上报 */ +/* OTA升级TTLV ID */ +enum +{ + QIOT_DPID_OTA_DOWN_URL = 1, /* ota升级资源包下载地址 */ + QIOT_DPID_OTA_DOWN_SIZE = 2, /* Ota升级资源包大小 */ + QIOT_DPID_OTA_DOWN_MD5 = 3, /* Ota升级资源包md5值 */ + QIOT_DPID_OTA_COMPONENT_NO = 4, /* 组件标识 */ + QIOT_DPID_OTA_SOURCE_VER = 5, /* 源版本 */ + QIOT_DPID_OTA_TARGET_VER = 6, /* 目标版本 */ + QIOT_DPID_OTA_COMPONENT_TYPE = 7, /* 组件类型 */ + QIOT_DPID_OTA_BATTERY_LIMIT = 8, /* Ota升级最小电量 */ + QIOT_DPID_OTA_USE_SPACE = 9, /* ota升级需要磁盘空间 */ + QIOT_DPID_OTA_MIN_SIGNAL = 10, /* Ota升级最小信号强度 */ + QIOT_DPID_OTA_SUBMIT = 11, /* 是否进行ota升级 */ + QIOT_DPID_OTA_DELAY_TIME = 12, /* Ota升级下次协商时间 */ + QIOT_DPID_OTA_STATUS = 13, /* Ota升级状态 */ + QIOT_DPID_OTA_MESSAGE = 14, /* Ota升级状态信息 */ + QIOT_DPID_OTA_DOWN_CRC = 15, /* Ota升级资源包CRC值 */ + QIOT_DPID_OTA_DOWN_SHA256 = 16, /* Ota升级资源包SHA256值 */ + QIOT_DPID_OTA_DOWN_SIGN = 19, /* 额外需要的文件签名类型 */ + QIOT_DPID_OTA_DOWN_INFO = 20, /* Ota多固件资源信息 */ + QIOT_DPID_OTA_MODULE_VER = 25, /* 模组版本 */ + QIOT_DPID_OTA_MCU_VER = 26, /* MCU版本 */ + QIOT_DPID_OTA_HANDLE_TYPE = 27, /* 升级控制类型 */ + QIOT_DPID_OTA_TASK_INFO = 28, /* Ota多组件升级任务信息 */ + QIOT_DPID_OTA_DOWN_INFO_IDEX = 30, /* Ota多固件资源信息idex */ +}; +typedef enum +{ + QIOT_OTA_STATUS_NOPLAN = 0, /* 空闲 */ + QIOT_OTA_STATUS_REVICEPLAN = 1, /* 收到任务 */ + QIOT_OTA_STATUS_SUBMITOTA = 2, /* 收到确认 */ + QIOT_OTA_STATUS_REFUSEDOTA = 3, /* 收到取消 */ + QIOT_OTA_STATUS_DOWNLOADSTART = 4, /* 下载开始 */ + QIOT_OTA_STATUS_DOWNLOADING = 5, /* 下载中 */ + QIOT_OTA_STATUS_DOWNLOADERROR = 6, /* 下载失败 */ + QIOT_OTA_STATUS_DOWNLOADSUCCESS = 8, /* 下载成功 */ + QIOT_OTA_STATUS_UPDATING = 9, /* 更新中 */ + QIOT_OTA_STATUS_UPDATESUCCESS = 11, /* 更新成功 */ + QIOT_OTA_STATUS_UPDATEERROR = 12, /* 更新失败 */ +} QIot_otaStatus_e; + +#define QIOT_OTA_STATUS_STRING(X) \ + ( \ + (X == QIOT_OTA_STATUS_NOPLAN) ? "NOPLAN" : (X == QIOT_OTA_STATUS_REVICEPLAN) ? "REVICEPLAN" \ + : (X == QIOT_OTA_STATUS_SUBMITOTA) ? "SUBMITOTA" \ + : (X == QIOT_OTA_STATUS_REFUSEDOTA) ? "REFUSEDOTA" \ + : (X == QIOT_OTA_STATUS_DOWNLOADSTART) ? "DOWNLOADSTART" \ + : (X == QIOT_OTA_STATUS_DOWNLOADING) ? "DOWNLOADING" \ + : (X == QIOT_OTA_STATUS_DOWNLOADERROR) ? "DOWNLOADERROR" \ + : (X == QIOT_OTA_STATUS_DOWNLOADSUCCESS) ? "DOWNLOADSUCCESS" \ + : (X == QIOT_OTA_STATUS_UPDATING) ? "UPDATING" \ + : (X == QIOT_OTA_STATUS_UPDATESUCCESS) ? "UPDATESUCCESS" \ + : (X == QIOT_OTA_STATUS_UPDATEERROR) ? "UPDATEERROR" \ + : "Unknown") +#define QIOT_OTA_ERR_STRING(X) \ + ( \ + (X == QIOT_OTA_TASK_NOTIFY) ? "OTA_TASK_NOTIFY" : (X == QIOT_OTA_START) ? "OTA_START" \ + : (X == QIOT_OTA_DOWNLOADING) ? "OTA_DOWNLOADING" \ + : (X == QIOT_OTA_DOWNLOADED) ? "OTA_DOWNLOADED" \ + : (X == QIOT_OTA_UPDATING) ? "OTA_UPDATING" \ + : (X == QIOT_OTA_UPDATE_OK) ? "OTA_UPDATE_OK" \ + : (X == QIOT_OTA_UPDATE_FAIL) ? "OTA_UPDATE_FAIL" \ + : (X == QIOT_OTA_UPDATE_FLAG) ? "QIOT_OTA_UPDATE_FLAG" \ + :"Unknown") +enum +{ + QIOT_OTA_EXTERN_NONE = 0, + QIOT_OTA_EXTERN_SHA256 = 1, + QIOT_OTA_EXTERN_MAX, +}; + +typedef enum +{ + QIOT_COMPTYPE_MODULE = 0, + QIOT_COMPTYPE_MCU, +} QIot_otaComptype_e; + +typedef struct +{ + QIot_otaComptype_e componentType; /* 组件类型 */ + char componentNo[QIOT_COMPNO_MAXSIZE + 1]; /* 组件名称最长32bytes*/ + char targetVersion[QIOT_COMPVER_MAXSIZE + 1]; /* 版本号最长50bytes */ + qbool mutilPlansMode; /* 是否为多组件 */ + QIot_otaStatus_e currStatus; + quint32_t extraMess; + quint32_t crc; + char sha256[QUOS_SHA256_DIGEST_LENGTH * 2 + 1]; + struct + { + quint32_t startAddr; + quint32_t size; + } currentPiece; + QIot_otaFilePublicInfo_t otaFileInfo; +} Ql_iotCmdOtaInfo_t; +extern Ql_iotCmdOtaInfo_t QIot_otaInfo; +void Ql_iotCmdOtaInit(void); +void Ql_iotCmdOtaStatusRecovery(void); +void Ql_iotCmdOtaNotify(QIot_dpAppType_e app, const char *endPoint, quint16_t pkgId, quint8_t *payload, quint16_t payloadLen); +void Ql_iotCmdOtaFwInfo(QIot_dpAppType_e app, const char *endPoint, quint16_t pkgId, quint8_t *payload, quint16_t payloadLen); +void Ql_iotCmdOtaMcuVersionModify(const char *compNo, const char *version); +#endif diff --git a/cloud/common/ql_iotCmdSys.c b/cloud/common/ql_iotCmdSys.c new file mode 100644 index 0000000000000000000000000000000000000000..3571a4e3e8837d2e3a03e5b62aa04b13004532ae --- /dev/null +++ b/cloud/common/ql_iotCmdSys.c @@ -0,0 +1,573 @@ +/************************************************************************* +** 创建人 @author : 吴健超 JCWu +** 版本 @version : V1.0.0 原始版本 +** 日期 @date : +** 功能 @brief : dmp Syc,适配DMP2.2.0 +** 硬件 @hardware: +** 其他 @other : +***************************************************************************/ +#include "ql_iotCmdSys.h" +#include "ql_iotDp.h" +#include "ql_iotTtlv.h" +#include "ql_iotConfig.h" +#include "ql_iotCmdLoc.h" +#include "Qhal_driver.h" +#ifdef QUEC_ENABLE_GATEWAY +#include "ql_iotGwDev.h" +#endif + +enum +{ + QIOT_DEVICE_MANAGE_IP_SET = 0x01, + QIOT_DEVICE_MANAGE_IP_CLEAR = 0x02, + QIOT_DEVICE_MANAGE_REAUTH = 0x04, + QIOT_DEVICE_MANAGE_PKPS_SET = 0x08, + QIOT_DEVICE_MANAGE_PKPS_CLEAR = 0x10, + QIOT_DEVICE_MANAGE_NEW_DS = 0x20, +}; + +/************************************************************************** +** 功能 @brief : 将设备状态赋值ttlv格式,使用完需要Ql_iotTtlvFree()释放资源 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM *Ql_iotSysGetDevStatus(quint16_t ids[], quint32_t size) +{ + void *ttlvHead = NULL; + Qhal_propertyDev_t dInfo; + Qhal_propertyNet_t nInfo; + HAL_MEMSET(&dInfo, 0, sizeof(Qhal_propertyDev_t)); + HAL_MEMSET(&nInfo, 0, sizeof(Qhal_propertyNet_t)); + Qhal_propertyDevGet(&dInfo); + Qhal_propertyNetGet(&nInfo, NULL, 0, NULL); + quint32_t i; + for (i = 0; i < size; i++) + { + switch (ids[i]) + { + case QIOT_DPID_STATUS_BATTERY: + Ql_iotTtlvIdAddInt(&ttlvHead, ids[i], dInfo.cellLevel); + break; + case QIOT_DPID_STATUS_VOLTAGE: + Ql_iotTtlvIdAddFloat(&ttlvHead, ids[i], dInfo.cellVoltage); + break; + case QIOT_DPID_STATUS_SIGNAL: + Ql_iotTtlvIdAddInt(&ttlvHead, ids[i], nInfo.rssi); + break; + case QIOT_DPID_STATUS_FLASHFREE: + Ql_iotTtlvIdAddInt(&ttlvHead, ids[i], dInfo.flashFree); + break; + case QIOT_DPID_STATUS_RSRP: + Ql_iotTtlvIdAddInt(&ttlvHead, ids[i], nInfo.rsrp); + break; + case QIOT_DPID_STATUS_RSRQ: + Ql_iotTtlvIdAddInt(&ttlvHead, ids[i], nInfo.rsrq); + break; + case QIOT_DPID_STATUS_SNR: + Ql_iotTtlvIdAddInt(&ttlvHead, ids[i], nInfo.snr); + break; + default: + break; + } + } + return ttlvHead; +} +/************************************************************************** +** 功能 @brief : 设备状态读取 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Ql_iotCmdSysStatusRecv(QIot_dpAppType_e app, const char *endPoint, quint16_t pkgId, quint8_t *payload, quint16_t payloadLen) +{ + quint16_t ids[QIOT_DPID_STATUS_MAX]; + quint16_t i; + for (i = 0; i < payloadLen - 1 && i / 2 < QIOT_DPID_STATUS_MAX; i += 2) + { + ids[i / 2] = _ARRAY01_U16(&payload[i]); + } + void *ttlvHead = Ql_iotSysGetDevStatus(ids, i / 2); + Ql_iotDpSendTtlvRsp(app, endPoint, QIOT_DPCMD_STATUS_RSP, pkgId, ttlvHead); + Ql_iotTtlvFree(&ttlvHead); +} +/************************************************************************** +** 功能 @brief : 设备状态上报 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotCmdSysStatusReport(quint16_t ids[], quint32_t size) +{ + qbool ret = FALSE; + void *ttlvHead = NULL; + Quos_logPrintf(QUEC_SYS, LL_DBG, "sysStatus report"); + if ((ttlvHead = Ql_iotSysGetDevStatus(ids, size)) != NULL) + { + ret = Ql_iotDpSendTtlvReq(QIOT_DPAPP_M2M, NULL, 0, 1, QIOT_DPCMD_STATUS_EVENT, ttlvHead, NULL); + Ql_iotTtlvFree(&ttlvHead); + } + return ret; +} +/************************************************************************** +** 功能 @brief : 将设备信息赋值ttlv格式,使用完需要Ql_iotTtlvFree()释放资源 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM *Ql_iotSysGetDevInfo(quint16_t ids[], quint32_t size) +{ + void *ttlvHead = NULL; + Qhal_propertyDev_t dInfo; + Qhal_propertyNet_t nInfo; + Qhal_propertySim_t sInfo; + HAL_MEMSET(&dInfo, 0, sizeof(Qhal_propertyDev_t)); + HAL_MEMSET(&nInfo, 0, sizeof(Qhal_propertyNet_t)); + HAL_MEMSET(&sInfo, 0, sizeof(Qhal_propertySim_t)); + Qhal_propertyDevGet(&dInfo); + Qhal_propertyNetGet(&nInfo, NULL, 0, NULL); + Qhal_propertySimGet(&sInfo); + quint32_t i; + for (i = 0; i < size; i++) + { + switch (ids[i]) + { + case QIOT_DPID_INFO_MODEL_TYPE: + Ql_iotTtlvIdAddString(&ttlvHead, ids[i], dInfo.modelType); + break; + case QIOT_DPID_INFO_MODEL_VER: + Ql_iotTtlvIdAddString(&ttlvHead, ids[i], QIot_userdata.softversion); + break; + case QIOT_DPID_INFO_MCU_VER: + Ql_iotTtlvIdAddString(&ttlvHead, ids[i], QIot_userdata.mcuVerList); + break; + case QIOT_DPID_INFO_CELLID: + Ql_iotTtlvIdAddInt(&ttlvHead, ids[i], nInfo.cellid); + break; + case QIOT_DPID_INFO_ICCID: + Ql_iotTtlvIdAddString(&ttlvHead, ids[i], sInfo.iccid); + break; + case QIOT_DPID_INFO_MCC: + Ql_iotTtlvIdAddInt(&ttlvHead, ids[i], nInfo.mcc); + break; + case QIOT_DPID_INFO_MNC: + Ql_iotTtlvIdAddInt(&ttlvHead, ids[i], nInfo.mnc); + break; + case QIOT_DPID_INFO_LAC: + Ql_iotTtlvIdAddInt(&ttlvHead, ids[i], nInfo.lac); + break; + case QIOT_DPID_INFO_PHONE_NUM: + Ql_iotTtlvIdAddString(&ttlvHead, ids[i], sInfo.phoneid); + break; + case QIOT_DPID_INFO_SIM_NUM: + Ql_iotTtlvIdAddString(&ttlvHead, ids[i], sInfo.imsi); + break; + case QIOT_DPID_INFO_SDK_VER: + Ql_iotTtlvIdAddString(&ttlvHead, ids[i], QIOT_SDK_VERSION); + break; + case QIOT_DPID_INFO_LOC_SUPLIST: + { + void *titleTtlv = Ql_iotLocGetSupList(); + char *titleStr = Ql_iotLocatorTtlv2String(titleTtlv); + Ql_iotTtlvFree(&titleTtlv); + Ql_iotTtlvIdAddString(&ttlvHead, QIOT_DPID_INFO_LOC_SUPLIST, titleStr); + HAL_FREE(titleStr); + break; + } + case QIOT_DPIO_INFO_DP_VER: + { + Ql_iotTtlvIdAddString(&ttlvHead, ids[i], QIOT_DATA_PROTOCOL_VER); + break; + } + case QIOT_DPIO_INFO_CP_VER: + { + Ql_iotTtlvIdAddString(&ttlvHead, ids[i], QIOT_COM_PROTOCOL_VER); + break; + } + default: + break; + } + } + return ttlvHead; +} +/************************************************************************** +** 功能 @brief : 设备信息读取 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Ql_iotCmdSysDevInfoRecv(QIot_dpAppType_e app, const char *endPoint, quint16_t pkgId, quint8_t *payload, quint16_t payloadLen) +{ + quint16_t ids[QIOT_DPID_INFO_MAX]; + quint16_t i; + for (i = 0; i < payloadLen - 1 && i / 2 < QIOT_DPID_INFO_MAX; i += 2) + { + ids[i / 2] = _ARRAY01_U16(&payload[i]); + } + void *ttlvHead = Ql_iotSysGetDevInfo(ids, i / 2); + Ql_iotDpSendTtlvRsp(app, endPoint, QIOT_DPCMD_INFO_RSP, pkgId, ttlvHead); + Ql_iotTtlvFree(&ttlvHead); +} +/************************************************************************** +** 功能 @brief : 设备信息上报 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotCmdSysDevInfoReport(quint16_t ids[], quint32_t size) +{ + qbool ret = FALSE; + void *ttlvHead = NULL; + Quos_logPrintf(QUEC_SYS, LL_DBG, "devinfo report"); + if ((ttlvHead = Ql_iotSysGetDevInfo(ids, size)) != NULL) + { + ret = Ql_iotDpSendTtlvReq(QIOT_DPAPP_M2M, NULL, 0, 1, QIOT_DPCMD_INFO_EVENT, ttlvHead, NULL); + Ql_iotTtlvFree(&ttlvHead); + } + return ret; +} +/************************************************************************** +** 功能 @brief : 上报绑定信息,仅在有局域网通信时有效 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotCmdBindcodeReport(quint8_t bindcode[], quint32_t len) +{ + qbool ret = FALSE; + void *ttlvHead = NULL; + Quos_logPrintf(QUEC_SYS, LL_DBG, "bindcode report"); + Ql_iotTtlvIdAddByte(&ttlvHead, QIOT_DPID_DEV_BINDCODE, bindcode, len); + + if (ttlvHead) + { + ret = Ql_iotDpSendTtlvReq(QIOT_DPAPP_M2M, NULL, 0, 1, QIOT_DPCMD_DEV_BINDCODE_WRITE, ttlvHead, NULL); + Ql_iotTtlvFree(&ttlvHead); + } + return ret; +} +/************************************************************************** +** 功能 @brief : 上报错误信息 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Ql_iotCmdSysExceReport(QIot_dpAppType_e app, const char *endPoint, qint32_t errcode, quint16_t pkgId) +{ + void *ttlvHead = NULL; + Quos_logPrintf(QUEC_SYS, LL_WARN, "ecode:%s pkgid:%u", QIOT_SERVER_ERRCODE_STRING(errcode), pkgId); + Ql_iotTtlvIdAddInt(&ttlvHead, QIOT_DPID_EXCE_ERRCODE, errcode); + Ql_iotTtlvIdAddInt(&ttlvHead, QIOT_DPID_EXCE_PKGID, pkgId); + Ql_iotDpSendTtlvReq(app, endPoint, 0, 1, QIOT_DPCMD_EXCE_EVENT, ttlvHead, NULL); + Ql_iotTtlvFree(&ttlvHead); +} + +/************************************************************************** +** 功能 @brief : 设备管理命令处理 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void Ql_iotCmdSysTerManage(QIot_dpAppType_e app, const char *endPoint, quint16_t pkgId, quint8_t *payload, quint16_t payloadLen) +{ + UNUSED(app); + UNUSED(endPoint); + UNUSED(pkgId); + qint32_t errcode = 0; + quint16_t flag = 0; + quint8_t event = 0; + qbool need_save = FALSE; + //Qiot_productType pt = QIot_userdata.productType; + void *ttlvHead = Ql_iotTtlvUnformat(payload, payloadLen); + if (NULL == ttlvHead) + { + return; + } + + /**************************************************设备认证信息提取******************************************************************************/ + char *ds = Ql_iotTtlvIdGetString(ttlvHead, QIOT_DPID_DEV_SECRET); + if (ds && HAL_STRLEN(ds)) + { + HAL_SNPRINTF(QIot_userdata.connectProduct->secret, sizeof(QIot_userdata.connectProduct->secret), "%s", ds); + Ql_iotDSKVSave(); + event = QIOT_ATEVENT_TYPE_AUTH; + errcode = QIOT_AUTH_SUCC; + } + uint8_t *sessionKey = NULL; + quint32_t sessionKeyLen = Ql_iotTtlvIdGetByte(ttlvHead, QIOT_DPID_DEV_SESSIONKEY, &sessionKey); + if (sessionKey && sessionKeyLen) + { + SHA256_ctx_t sha256_ctx; + quint8_t sha256Data[QUOS_SHA256_DIGEST_LENGTH]; + Quos_logHexDump(QUEC_SYS, LL_DUMP, "sessionKey", sessionKey, sessionKeyLen); + HAL_MEMCPY(QIot_userdata.sessionInfo.key, sessionKey, sizeof(QIot_userdata.sessionInfo.key)); + Quos_sha256init(&sha256_ctx); + Quos_sha256update(&sha256_ctx, (const quint8_t *)QIot_userdata.sessionInfo.key, sizeof(QIot_userdata.sessionInfo.key)); + Quos_sha256finish(&sha256_ctx, sha256Data); + HAL_MEMCPY(QIot_userdata.sessionInfo.iv, sha256Data, sizeof(QIot_userdata.sessionInfo.iv)); + QIot_userdata.sessionInfo.usable = TRUE; + } + /*******************************************************设备控制命令提取****************************************************************************/ + void *dnsInfo = Ql_iotTtlvIdGetStruct(ttlvHead, QIOT_DPID_DEV_DNS); + if (dnsInfo) + { + HAL_MEMSET(&QIot_userdata.productInfoCache, 0x00, sizeof(QIot_userdata.productInfoCache)); + + char *domain = Ql_iotTtlvIdGetString(dnsInfo, QIOT_DPID_DEV_DOMAIN); + char *ip = Ql_iotTtlvIdGetString(dnsInfo, QIOT_DPID_DEV_IP); + qint64_t port = 0; + qbool ret = Ql_iotTtlvIdGetInt(dnsInfo, QIOT_DPID_DEV_PORT, &port); + /* 域名 ip 端口号等3个信息需要同时下发,否则认为无效 */ + if (domain && ip && ret) + { + if (HAL_STRLEN(domain) && HAL_STRLEN(ip) && port <= 65535) + { + urlAnalyze_t urlA; + + if (FALSE == Quos_urlAnalyze(QIot_userdata.connectProduct->serverUrl, &urlA)) + { + ret = TRUE; + } + + if (0 == HAL_STRCMP(urlA.hostname, domain) && port == urlA.port) + { + ret = FALSE; + } + if (ret == TRUE) + { + HAL_SNPRINTF(QIot_userdata.productInfoCache.serverUrl, sizeof(QIot_userdata.productInfoCache.serverUrl), "%s:%d", domain, (quint16_t)port); + HAL_SNPRINTF(QIot_userdata.productInfoCache.serverIp, sizeof(QIot_userdata.productInfoCache.serverIp), "%s", ip); + QIot_userdata.connectProduct = &QIot_userdata.productInfoCache; + flag |= QIOT_DEVICE_MANAGE_IP_SET; + event = QIOT_ATEVENT_TYPE_CONN; + errcode = QIOT_CONN_ERR_SERVER_CHANGE; + } + } + /* 下发内容为空,清除云平台下发的服务器信息 */ + else if (0 == HAL_STRLEN(domain) && 0 == HAL_STRLEN(ip) && 0 == port) + { + HAL_MEMSET(QIot_userdata.productInfoCloud.serverUrl, 0x00, sizeof(QIot_userdata.productInfoCloud.serverUrl)); + HAL_MEMSET(QIot_userdata.productInfoCloud.serverIp, 0x00, sizeof(QIot_userdata.productInfoCloud.serverIp)); + //QIot_userdata.connectProduct = &QIot_userdata.productInfo; + flag |= QIOT_DEVICE_MANAGE_IP_CLEAR; + QIot_userdata.connectProduct = &QIot_userdata.productInfoCache; + need_save = TRUE; + } + } + } + char *pk = Ql_iotTtlvIdGetString(ttlvHead, QIOT_DPID_DEV_PK); + char *ps = Ql_iotTtlvIdGetString(ttlvHead, QIOT_DPID_DEV_PS); + if (pk && ps) + { + quint16_t pk_len = HAL_STRLEN(pk); + quint16_t ps_len = HAL_STRLEN(ps); + if (pk_len && ps_len) + { + if (0 != HAL_STRCMP(pk, QIot_userdata.connectProduct->productKey) || 0 != HAL_STRCMP(ps, QIot_userdata.connectProduct->productSecret)) + { + HAL_SNPRINTF(QIot_userdata.productInfoCache.productKey, sizeof(QIot_userdata.productInfoCache.productKey), "%s", pk); + HAL_SNPRINTF(QIot_userdata.productInfoCache.productSecret, sizeof(QIot_userdata.productInfoCache.productSecret), "%s", ps); + flag |= QIOT_DEVICE_MANAGE_PKPS_SET; + event = QIOT_ATEVENT_TYPE_CONN; + errcode = QIOT_CONN_ERR_SERVER_CHANGE; + QIot_userdata.connectProduct = &QIot_userdata.productInfoCache; + } + } + else if (0 == ps_len && 0 == pk_len) + { + /* 清除pk ps */ + HAL_MEMSET(QIot_userdata.productInfoCloud.productKey, 0x00, sizeof(QIot_userdata.productInfoCloud.productKey)); + HAL_MEMSET(QIot_userdata.productInfoCloud.productSecret, 0x00, sizeof(QIot_userdata.productInfoCloud.productSecret)); + flag |= QIOT_DEVICE_MANAGE_PKPS_CLEAR; + QIot_userdata.connectProduct = &QIot_userdata.productInfoCache; + need_save = TRUE; + } + } + + if ((flag & (QIOT_DEVICE_MANAGE_PKPS_SET | QIOT_DEVICE_MANAGE_IP_SET)) == QIOT_DEVICE_MANAGE_PKPS_SET) + { + /* 平台仅设置了pk ps */ + if (HAL_STRLEN(QIot_userdata.productInfoCloud.serverUrl)) + { + HAL_SNPRINTF(QIot_userdata.connectProduct->serverUrl, sizeof(QIot_userdata.connectProduct->serverUrl), "%s", QIot_userdata.productInfoCloud.serverUrl); + HAL_SNPRINTF(QIot_userdata.connectProduct->serverIp, sizeof(QIot_userdata.connectProduct->serverIp), "%s", QIot_userdata.productInfoCloud.serverIp); + } + else + { + HAL_SNPRINTF(QIot_userdata.connectProduct->serverUrl, sizeof(QIot_userdata.connectProduct->serverUrl), "%s", QIot_userdata.productInfo.serverUrl); + HAL_SNPRINTF(QIot_userdata.connectProduct->serverIp, sizeof(QIot_userdata.connectProduct->serverIp), "%s", QIot_userdata.productInfo.serverIp); + } + } + else if ((flag & (QIOT_DEVICE_MANAGE_PKPS_SET | QIOT_DEVICE_MANAGE_IP_SET)) == QIOT_DEVICE_MANAGE_IP_SET) + { + /* 平台仅设置了DNS */ + if (HAL_STRLEN(QIot_userdata.productInfoCloud.productKey)) + { + HAL_SNPRINTF(QIot_userdata.connectProduct->productKey, sizeof(QIot_userdata.connectProduct->productKey), "%s", QIot_userdata.productInfoCloud.productKey); + HAL_SNPRINTF(QIot_userdata.connectProduct->productSecret, sizeof(QIot_userdata.connectProduct->productSecret), "%s", QIot_userdata.productInfoCloud.productSecret); + } + else + { + HAL_SNPRINTF(QIot_userdata.connectProduct->productKey, sizeof(QIot_userdata.connectProduct->productKey), "%s", QIot_userdata.productInfo.productKey); + HAL_SNPRINTF(QIot_userdata.connectProduct->productSecret, sizeof(QIot_userdata.connectProduct->productSecret), "%s", QIot_userdata.productInfo.productSecret); + } + } + else if (flag == (QIOT_DEVICE_MANAGE_PKPS_CLEAR | QIOT_DEVICE_MANAGE_IP_CLEAR)) + { + /* 若平台同时清除DNS与pk ps信息,则需要在此切换连接平台对象为本地 */ + QIot_userdata.connectProduct = &QIot_userdata.productInfo; + event = QIOT_ATEVENT_TYPE_CONN; + errcode = QIOT_CONN_ERR_SERVER_CHANGE; + need_save = TRUE; + } + + qbool reauth_flag = FALSE; + qbool ret = Ql_iotTtlvIdGetBool(ttlvHead, QIOT_DPID_DEV_REAUTH, &reauth_flag); + char *new_ds = Ql_iotTtlvIdGetString(ttlvHead, QIOT_DPID_DEV_NEW_SECRET); + + if (ret && reauth_flag) + { + /* 重新认证标志下发未TRUE, 清除认证信息--若未下发pk ps dns,则清除当前连接对象 */ + flag |= QIOT_DEVICE_MANAGE_REAUTH; + HAL_MEMSET(QIot_userdata.connectProduct->secret, 0x00, sizeof(QIot_userdata.connectProduct->secret)); + event = QIOT_ATEVENT_TYPE_CONN; + errcode = QIOT_CONN_ERR_SERVER_CHANGE; + } + else if (new_ds && HAL_STRLEN(new_ds)) + { + if (0 != HAL_STRCMP(new_ds, QIot_userdata.connectProduct->secret)) + { + /* 新的ds信息保存到即将连接的对象里,--若未下发pk ps dns,则覆盖当前连接中ds信息 */ + HAL_SNPRINTF(QIot_userdata.connectProduct->secret, sizeof(QIot_userdata.connectProduct->secret), "%s", new_ds); + + event = QIOT_ATEVENT_TYPE_CONN; + errcode = QIOT_CONN_ERR_SERVER_CHANGE; + need_save = TRUE; + } + } + else if (0 != (flag & (QIOT_DEVICE_MANAGE_PKPS_SET | QIOT_DEVICE_MANAGE_IP_SET))) + { + /* 若平台下发了pk ps 或dns,且没有下发重新认证标志与新的ds数据,设备需要从其他地方拷贝ds到当前缓存信息对象中 */ + if (HAL_STRLEN(QIot_userdata.productInfoCloud.secret)) + { + HAL_SNPRINTF(QIot_userdata.connectProduct->secret, sizeof(QIot_userdata.connectProduct->secret), "%s", QIot_userdata.productInfoCloud.secret); + } + else + { + HAL_SNPRINTF(QIot_userdata.connectProduct->secret, sizeof(QIot_userdata.connectProduct->secret), "%s", QIot_userdata.productInfo.secret); + } + + event = QIOT_ATEVENT_TYPE_CONN; + errcode = QIOT_CONN_ERR_SERVER_CHANGE; + } + + if (need_save) + { + if (QIot_userdata.connectProduct != &QIot_userdata.productInfoCache) + { + Ql_iotDSKVSave(); + } + } + + if (errcode != 0) + { + if (errcode != QIOT_AUTH_SUCC) + { + Quos_mqttDeinit(QIot_userdata.m2mCtx); + QIot_userdata.m2mCtx = NULL; + } + /* 设置完新的域名后,是直接连接DMP还是重新发起认证 */ + Quos_eventPost(event, (void *)(long)errcode); + } + + Ql_iotTtlvFree(&ttlvHead); +} +/************************************************************************** +** 功能 @brief : 设备管理命令处理 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void Ql_iotCmdSysExceWrite(QIot_dpAppType_e app, const char *endPoint, quint16_t pkgId, quint8_t *payload, quint16_t payloadLen) +{ + UNUSED(app); + UNUSED(endPoint); + UNUSED(pkgId); + void *ttlvHead = Ql_iotTtlvUnformat(payload, payloadLen); + if (NULL == ttlvHead) + { + return; + } + qint64_t errcode = 0, errPkgId = 0; + qbool retErrCode = Ql_iotTtlvIdGetInt(ttlvHead, QIOT_DPID_EXCE_ERRCODE, &errcode); + qbool retErrPkgId = Ql_iotTtlvIdGetInt(ttlvHead, QIOT_DPID_EXCE_PKGID, &errPkgId); + Quos_logPrintf(QUEC_SYS, LL_INFO, "code:[%d]%s pkgid:%u", (int)errcode, retErrCode ? QIOT_SERVER_ERRCODE_STRING(errcode) : "unknown", retErrPkgId ? (int)errPkgId : 0); + if (retErrCode && errcode > 10200) + { + switch (errcode) + { + case QIOT_AUTH_ERR_DONE: + case QIOT_AUTH_ERR_PKPS_INVALID: + case QIOT_AUTH_ERR_PAYLOAD_INVALID: + case QIOT_AUTH_ERR_SIGN_INVALID: + case QIOT_AUTH_ERR_VERSION_INVALID: + case QIOT_AUTH_ERR_HASH_INVALID: + case QIOT_AUTH_ERR_PK_CHANGE: + case QIOT_AUTH_ERR_DK_ILLEGAL: + case QIOT_AUTH_ERR_PK_VER_NOCOR: + Quos_mqttDeinit(QIot_userdata.m2mCtx); + QIot_userdata.m2mCtx = NULL; + Quos_eventPost(QIOT_ATEVENT_TYPE_AUTH, (void *)(pointer_t)errcode); + break; +#ifdef QUEC_ENABLE_GATEWAY + case QIOT_SUB_DEV_ERR_UNLOGIN: + { + char *dk = Ql_iotTtlvIdGetString(ttlvHead, QIOT_DPID_EXCE_DK); + char *pk = Ql_iotTtlvIdGetString(ttlvHead, QIOT_DPID_EXCE_PK); + if (pk && dk) + { + Ql_gatewayDeviceExceWrite(dk, pk, errcode); + } + break; + } +#endif + case QIOT_SERVER_ERRCODE_RATE_LIMIT: + case QIOT_SERVER_ERRCODE_QUANTITY_LIMIT: + default: + Quos_eventPost(QIOT_ATEVENT_TYPE_SERVER, (void *)(pointer_t)errcode); + break; + } + } + Ql_iotTtlvFree(&ttlvHead); +} +/************************************************************************** +** 功能 @brief : sys事件处理 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void ql_iotCmdSysEventNotify(qint32_t event, void *arg) +{ + qint32_t errcode = (qint32_t)(pointer_t)arg; + switch (event) + { + case QIOT_ATEVENT_TYPE_SUBCRIBE: + if (QIOT_SUBCRIBE_SUCC == errcode) + { + quint16_t statusIds[] = {QIOT_DPID_STATUS_BATTERY, + QIOT_DPID_STATUS_VOLTAGE, + QIOT_DPID_STATUS_SIGNAL, + QIOT_DPID_STATUS_FLASHFREE}; + quint16_t infoIds[] = {QIOT_DPID_INFO_MODEL_TYPE, + QIOT_DPID_INFO_MODEL_VER, + QIOT_DPID_INFO_MCU_VER, + QIOT_DPID_INFO_ICCID, + QIOT_DPID_INFO_SDK_VER, + QIOT_DPID_INFO_LOC_SUPLIST, + QIOT_DPIO_INFO_DP_VER, + QIOT_DPIO_INFO_CP_VER}; + Ql_iotCmdSysStatusReport(statusIds, sizeof(statusIds) / sizeof(statusIds[0])); + Ql_iotCmdSysDevInfoReport(infoIds, sizeof(infoIds) / sizeof(infoIds[0])); + } + break; + } +} +/************************************************************************** +** 功能 @brief : Sys任务初始化 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Ql_iotCmdSysInit(void) +{ + qint32_t event[] = {QIOT_ATEVENT_TYPE_SUBCRIBE}; + Quos_eventCbReg(event, sizeof(event) / sizeof(event[0]), ql_iotCmdSysEventNotify); +} \ No newline at end of file diff --git a/cloud/common/ql_iotCmdSys.h b/cloud/common/ql_iotCmdSys.h new file mode 100644 index 0000000000000000000000000000000000000000..db9cd0cd11d431e06fd9592d7315f4c16cd98759 --- /dev/null +++ b/cloud/common/ql_iotCmdSys.h @@ -0,0 +1,53 @@ +#ifndef __QIOT_CMDSYS_H__ +#define __QIOT_CMDSYS_H__ +#include "Ql_iotApi.h" + +enum +{ + QIOT_DPID_EXCE_ERRCODE = 1, /* 异常错误码 */ + QIOT_DPID_EXCE_PKGID = 2, /* 异常包ID */ + QIOT_DPID_EXCE_PK = 3, /* 异常设备pk */ + QIOT_DPID_EXCE_DK = 4, /* 异常设备dk */ +}; + +enum +{ + QIOT_DPID_DEV_DNS = 1, /* DNS信息 */ + QIOT_DPID_DEV_DOMAIN = 2, /* DNS域名 */ + QIOT_DPID_DEV_IP = 3, /* DNS的ip */ + QIOT_DPID_DEV_PORT = 4, /* DNS的端口 */ + QIOT_DPID_DEV_SECRET = 5, /* 设备的秘钥 */ + QIOT_DPID_DEV_SESSIONKEY = 6, /* 会话sessionKey */ + QIOT_DPID_DEV_PK = 7, /* product key */ + QIOT_DPID_DEV_PS = 8, /* product Secret */ + QIOT_DPID_DEV_REAUTH = 9, /* 认证标识 */ + QIOT_DPID_DEV_NEW_SECRET = 10, /* 新的设备密钥 */ + QIOT_DPID_DEV_BINDCODE = 11, /* 设备绑定信息bindcode上报,仅在有局域网通信时有效 */ +}; + +enum +{ + QIOT_SERVER_ERRCODE_PROTOCOL = 1, + QIOT_SERVER_ERRCODE_LEN = 2, + QIOT_SERVER_ERRCODE_CRC = 3, + QIOT_SERVER_ERRCODE_CMD = 4, + QIOT_SERVER_ERRCODE_UNFORMAT_FAIL = 5, +}; + +#define QIOT_SERVER_ERRCODE_STRING(X) \ + ( \ + (X == QIOT_SERVER_ERRCODE_PROTOCOL) ? "EXCE_ERRCODE_PROTOCOL" : (X == QIOT_SERVER_ERRCODE_LEN) ? "EXCE_ERRCODE_LEN" \ + : (X == QIOT_SERVER_ERRCODE_CRC) ? "EXCE_ERRCODE_CRC" \ + : (X == QIOT_SERVER_ERRCODE_CMD) ? "EXCE_ERRCODE_CMD" \ + : (X == QIOT_SERVER_ERRCODE_UNFORMAT_FAIL) ? "EXCE_ERRCODE_UNFORMAT_FAIL" \ + : (X == QIOT_SERVER_ERRCODE_RATE_LIMIT) ? "EXCE_ERRCODE_RATE_LIMIT" \ + : (X == QIOT_SERVER_ERRCODE_QUANTITY_LIMIT) ? "EXCE_ERRCODE_QUANTITY_LIMIT" \ + : "Unknown") + +void Ql_iotCmdSysInit(void); +void Ql_iotCmdSysExceReport(QIot_dpAppType_e app, const char *endPoint, qint32_t errcode, quint16_t pkgId); +void Ql_iotCmdSysStatusRecv(QIot_dpAppType_e app, const char *endPoint, quint16_t pkgId, quint8_t *payload, quint16_t payloadLen); +void Ql_iotCmdSysDevInfoRecv(QIot_dpAppType_e app, const char *endPoint, quint16_t pkgId, quint8_t *payload, quint16_t payloadLen); +void Ql_iotCmdSysTerManage(QIot_dpAppType_e app, const char *endPoint, quint16_t pkgId, quint8_t *payload, quint16_t payloadLen); +void Ql_iotCmdSysExceWrite(QIot_dpAppType_e app, const char *endPoint, quint16_t pkgId, quint8_t *payload, quint16_t payloadLen); +#endif \ No newline at end of file diff --git a/cloud/common/ql_iotConfig.c b/cloud/common/ql_iotConfig.c new file mode 100644 index 0000000000000000000000000000000000000000..86bc77405f16c0b6fe5b1d94973b59d2f5995c82 --- /dev/null +++ b/cloud/common/ql_iotConfig.c @@ -0,0 +1,681 @@ +/************************************************************************* +** 创建人 @author : 吴健超 JCWu +** 版本 @version : V1.0.0 原始版本 +** 日期 @date : +** 功能 @brief : quecthing公共信息 +** 硬件 @hardware:任何ANSI-C平台 +** 其他 @other : +***************************************************************************/ +#include "ql_iotConfig.h" +#include "ql_iotCmdOTA.h" +#include "ql_iotCmdBus.h" +#include "ql_iotCmdSys.h" +#include "ql_iotSecure.h" +#include "ql_iotConn.h" +#include "ql_iotCmdLan.h" +#ifdef QUEC_ENABLE_HTTP_OTA +#include "ql_fotaConfig.h" +#endif +#ifdef QUEC_ENABLE_GATEWAY +#include "ql_iotDMSub.h" +#endif +#include "Qhal_driver.h" + +QIot_userData_t QIot_userdata; + +static const dsKeyValue_t QIotDSKV[] = + { +#ifdef QUEC_ENABLE_AT + {0x00, FALSE, &QIot_userdata.connMode, sizeof(QIot_userdata.connMode)}, + {0x06, FALSE, &QIot_userdata.deviceInfo.contextID, sizeof(QIot_userdata.deviceInfo.contextID)}, + {0x11, FALSE, &QIot_userdata.lifetime, sizeof(QIot_userdata.lifetime)}, + {0x12, TRUE, QIot_userdata.mcuVerList, sizeof(QIot_userdata.mcuVerList)}, + {0x14, FALSE, &QIot_userdata.sessionInfo.flag, sizeof(QIot_userdata.sessionInfo.flag)}, + {0x0F, TRUE, QIot_userdata.deviceInfo.deviceKey, sizeof(QIot_userdata.deviceInfo.deviceKey)}, +#endif + {0x04, TRUE, QIot_userdata.productInfo.productKey, sizeof(QIot_userdata.productInfo.productKey)}, + {0x05, TRUE, QIot_userdata.productInfo.productSecret, sizeof(QIot_userdata.productInfo.productSecret)}, + {0x02, TRUE, QIot_userdata.productInfo.serverUrl, sizeof(QIot_userdata.productInfo.serverUrl)}, + {0x10, TRUE, QIot_userdata.productInfo.secret, sizeof(QIot_userdata.productInfo.secret)}, + + {0x30, TRUE, QIot_otaInfo.componentNo, sizeof(QIot_otaInfo.componentNo)}, + {0x31, TRUE, QIot_otaInfo.targetVersion, sizeof(QIot_otaInfo.targetVersion)}, + {0x32, FALSE, &QIot_otaInfo.componentType, sizeof(QIot_otaInfo.componentType)}, + {0x33, FALSE, &QIot_otaInfo.currStatus, sizeof(QIot_otaInfo.currStatus)}, + {0x34, FALSE, &QIot_otaInfo.extraMess, sizeof(QIot_otaInfo.extraMess)}, +#ifdef QUEC_ENABLE_AT + {0x50, FALSE, &QIot_busInfo.recvIsBuffer, sizeof(QIot_busInfo.recvIsBuffer)}, + {0x51, FALSE, &QIot_busInfo.dataFormat, sizeof(QIot_busInfo.dataFormat)}, +#endif + {0x07, TRUE, QIot_userdata.productInfo.serverIp, sizeof(QIot_userdata.productInfo.serverIp)}, + {0x08, TRUE, QIot_userdata.productInfoCloud.serverUrl, sizeof(QIot_userdata.productInfoCloud.serverUrl)}, + {0x09, TRUE, QIot_userdata.productInfoCloud.serverIp, sizeof(QIot_userdata.productInfoCloud.serverIp)}, + {0x0A, TRUE, QIot_userdata.productInfoCloud.productKey, sizeof(QIot_userdata.productInfoCloud.productKey)}, + {0x0B, TRUE, QIot_userdata.productInfoCloud.productSecret, sizeof(QIot_userdata.productInfoCloud.productSecret)}, + {0x0C, TRUE, QIot_userdata.productInfoCloud.secret, sizeof(QIot_userdata.productInfoCloud.secret)}, +#ifdef QUEC_ENABLE_HTTP_OTA + {0xF0, TRUE, Qota_userdata.productKey, sizeof(Qota_userdata.productKey)}, + {0xF1, TRUE, Qota_userdata.productSecret, sizeof(Qota_userdata.productSecret)}, + {0xF2, TRUE, Qota_userdata.serverUrl, sizeof(Qota_userdata.serverUrl)}, + {0xF3, TRUE, Qota_userdata.uid, sizeof(Qota_userdata.uid)}, + {0xF4, FALSE, &Qota_userdata.tlsMode, sizeof(Qota_userdata.tlsMode)}, + {0xF5, FALSE, &Qota_userdata.status, sizeof(Qota_userdata.status)}, + {0xF6, TRUE, Qota_userdata.targetVersion, sizeof(Qota_userdata.targetVersion)}, + {0xF7, FALSE, &Qota_userdata.tokenOvertime, sizeof(Qota_userdata.tokenOvertime)}, + {0xF8, TRUE, Qota_userdata.token, sizeof(Qota_userdata.token)}, +#endif + {0, FALSE, NULL, 0}}; +/************************************************************************** +** 功能 @brief : Quec IOT初始化,需要在使用IOT服务前调用 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotInit(void) +{ + HAL_MEMSET(&QIot_userdata, 0, sizeof(QIot_userdata)); + Quos_kernelInit(); + if (FALSE == Qhal_beforeMain()) + { + return FALSE; + } + Qhal_propertyDev_t dInfo; + Qhal_propertyDevGet(&dInfo); + Ql_iotConnInit(); + Ql_iotCmdBusInit(); + Ql_iotCmdSysInit(); + Ql_iotCmdOtaInit(); +#ifdef QUEC_ENABLE_LAN + Ql_iotCmdLanInit(); +#endif + char key[QUOS_AES_KEYLEN]; + HAL_MEMSET(key, '1', QUOS_AES_KEYLEN); + HAL_STRCPY(key, Qhal_devUuidGet()); + if (FALSE == Quos_dsKvRead(QIOT_FILE_CONFIG, QIotDSKV, key)) + { + Quos_logPrintf(QUEC_IOT, LL_DBG, "read dskv with aes fail"); + qbool kvret = Quos_dsKvRead(QIOT_FILE_CONFIG, QIotDSKV, NULL); + Quos_logPrintf(QUEC_IOT, LL_DBG, "read dskv without aes %s", _BOOL2STR(kvret)); + } + QIot_userdata.deviceInfo.contextID = dInfo.pdpCxtIdMin; +#ifdef QUEC_ENABLE_AT + if (0 == HAL_STRLEN(QIot_userdata.deviceInfo.deviceKey)) +#endif + { + HAL_SPRINTF(QIot_userdata.deviceInfo.deviceKey, "%s", Qhal_devUuidGet()); + } + if (0 == HAL_STRLEN(QIot_userdata.productInfo.serverUrl)) + { + HAL_SPRINTF(QIot_userdata.productInfo.serverUrl, "%s", QIOT_DMP_SERVERURL_MQTT_DEFAULT); + HAL_SPRINTF(QIot_userdata.productInfo.serverIp, "%s", QIOT_DMP_IP_MQTT_DEFAULT); + } + else if (NULL != HAL_STRSTR(QIot_userdata.productInfo.serverUrl, QIOT_DMP_SERVERURL_HTTP_DEFAULT)) + { + HAL_SPRINTF(QIot_userdata.productInfo.serverUrl, "%s", QIOT_DMP_SERVERURL_MQTT_DEFAULT); + HAL_SPRINTF(QIot_userdata.productInfo.serverIp, "%s", QIOT_DMP_IP_MQTT_DEFAULT); + } + else if (NULL != HAL_STRSTR(QIot_userdata.productInfo.serverUrl, QIOT_DMP_SERVERURL_HTTPS_DEFAULT)) + { + HAL_SPRINTF(QIot_userdata.productInfo.serverUrl, "%s", QIOT_DMP_SERVERURL_MQTTS_DEFAULT); + HAL_SPRINTF(QIot_userdata.productInfo.serverIp, "%s", QIOT_DMP_IP_MQTT_DEFAULT); + } + if (0 == QIot_userdata.lifetime) + { + QIot_userdata.lifetime = 120; + } + /* 若云平台设置过服务器信息,则需要使用云平台设置的信息连接平台,不能切换到本地设置的信息中 */ + if (HAL_STRLEN(QIot_userdata.productInfoCloud.serverUrl)) + { + QIot_userdata.connectProduct = &QIot_userdata.productInfoCloud; + Quos_logPrintf(QUEC_IOT, LL_INFO, "connect server obj cloud"); + } + else + { + Quos_logPrintf(QUEC_IOT, LL_INFO, "connect server obj local"); + QIot_userdata.connectProduct = &QIot_userdata.productInfo; + } + + Ql_iotConfigSetAppVersion(NULL); + Ql_iotCmdOtaStatusRecovery(); + +#ifdef QUEC_ENABLE_HTTP_OTA + Ql_fotaStatusRecovery(); +#endif + QIot_userdata.workState = QIOT_STATE_INITIALIZED; + if (QIOT_CONNMODE_REQ == QIot_userdata.connMode) + { + QIot_userdata.connMode = QIOT_CONNMODE_IDLE; + } + else if (QIOT_CONNMODE_AUTO == QIot_userdata.connMode) + { + Quos_netOpen(); + } + +#ifdef QUEC_ENABLE_GATEWAY + Ql_iotSubDevManagerInit(); + extern void Ql_gatewayDevicePackSubDisconnMsg(const char *pk, const char *dk, quint16_t pkgId); + Ql_iotDMSubDevDeleteAPIregister(QIOT_DEV_SUBDEV_DIRECT, Ql_gatewayDevicePackSubDisconnMsg); +#endif + //xjin.gao 20211206 adaptation//depot10/quecthing/quecthingSDK/2.9.0/ Initialize quecSDK Thread, detect events + Qhal_quecsdk_init(); + + Quos_logPrintf(QUEC_IOT, LL_INFO, "DK \t:%s", QIot_userdata.deviceInfo.deviceKey); + Quos_logPrintf(QUEC_IOT, LL_INFO, "quecthingSDK\t:%s", QIOT_SDK_VERSION); + Quos_logPrintf(QUEC_IOT, LL_INFO, "firmware VER\t:%s", QIot_userdata.softversion); + Quos_logPrintf(QUEC_IOT, LL_INFO, "MCU VER\t:%s", QIot_userdata.mcuVerList); + Quos_logPrintf(QUEC_IOT, LL_INFO, "connmode\t:%s", QIOT_CONN_MODE_STRING(QIot_userdata.connMode)); + Quos_logPrintf(QUEC_IOT, LL_INFO, "contextID\t:%u", QIot_userdata.deviceInfo.contextID); + Quos_logPrintf(QUEC_IOT, LL_INFO, "sertype\t:%s", "MQTT"); + Quos_logPrintf(QUEC_IOT, LL_INFO, "serUrl\t:%s", QIot_userdata.productInfo.serverUrl); + Quos_logPrintf(QUEC_IOT, LL_INFO, "PK \t:%s", QIot_userdata.productInfo.productKey); + /*Quos_logPrintf(QUEC_IOT, LL_DBG, "PS\t:%s", QIot_userdata.productInfo.productSecret);*/ + Quos_logPrintf(QUEC_IOT, LL_INFO, "authVer\t:%s", Ql_iotSecureVerGet()); + /*Quos_logPrintf(QUEC_IOT, LL_INFO, "ds\t:%s", QIot_userdata.deviceInfo.secret);*/ + Quos_logPrintf(QUEC_IOT, LL_INFO, "lifetime\t:%u", QIot_userdata.lifetime); + Quos_logPrintf(QUEC_IOT, LL_INFO, "sessionFlag\t:%d", QIot_userdata.sessionInfo.flag); + Quos_logPrintf(QUEC_IOT, LL_INFO, "buffer mode\t:%s", _BOOL2STR(QIot_busInfo.recvIsBuffer)); + return TRUE; +} +/************************************************************************** +** 功能 @brief : 保存配置信息 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotDSKVSave(void) +{ + char key[QUOS_AES_KEYLEN]; + HAL_MEMSET(key, '1', QUOS_AES_KEYLEN); + HAL_STRCPY(key, Qhal_devUuidGet()); + return Quos_dsKvWrite(QIOT_FILE_CONFIG, QIotDSKV, key); +} +/************************************************************************** +** 功能 @brief : 产品配置-连接模式配置 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotConfigSetConnmode(QIot_connMode_e mode) +{ +#ifndef QUEC_ENABLE_AT + if (QIOT_CONNMODE_AUTO == mode) + { + return FALSE; + } +#endif + /* 判断当前系统服务器地址(url)以及其他配置是否为空 */ + if (QIOT_CONNMODE_IDLE != mode && + (mode > QIOT_CONNMODE_AUTO || + (HAL_STRLEN(QIot_userdata.productInfo.productKey) == 0 || + HAL_STRLEN(QIot_userdata.productInfo.productSecret) == 0 || + HAL_STRLEN(QIot_userdata.productInfo.serverUrl) == 0))) + { + return FALSE; + } + + if (mode != QIot_userdata.connMode) + { + QIot_connMode_e oldStatue = QIot_userdata.connMode; + QIot_userdata.connMode = mode; +#ifdef QUEC_ENABLE_AT + Ql_iotDSKVSave(); +#endif + if (QIOT_CONNMODE_IDLE == mode) + { + QIot_userdata.sessionInfo.usable = FALSE; + QIot_userdata.connFailCnt = 0; + Quos_netClose(); + } + else if(QIOT_CONNMODE_IDLE == oldStatue) + { + Quos_netOpen(); + } + } + return TRUE; +} + +/************************************************************************** +** 功能 @brief : 产品配置-连接模式获取 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +QIot_connMode_e Ql_iotConfigGetConnmode(void) +{ + return QIot_userdata.connMode; +} +/************************************************************************** +** 功能 @brief : 产品配置-PDP contextID配置 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool Ql_iotConfigSetPdpContextId(quint8_t contextID) +{ + Qhal_propertyDev_t dInfo; + + Qhal_propertyDevGet(&dInfo); + if (contextID > dInfo.pdpCxtIdMax || contextID < dInfo.pdpCxtIdMin || QIOT_CONNMODE_IDLE != Ql_iotConfigGetConnmode()) + { + return FALSE; + } + + if (contextID != QIot_userdata.deviceInfo.contextID) + { + QIot_userdata.deviceInfo.contextID = contextID; +#ifdef QUEC_ENABLE_AT + Ql_iotDSKVSave(); +#endif + } + return TRUE; +} +/************************************************************************** +** 功能 @brief : 产品配置-PDP contextID获取 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +quint8_t Ql_iotConfigGetPdpContextId(void) +{ + return QIot_userdata.deviceInfo.contextID; +} +/************************************************************************** +** 功能 @brief : 产品配置-服务器信息配置 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotConfigSetServer(QIot_protocolType_t type, const char *server_url) +{ + qbool needsave = FALSE; + if (QIOT_CONNMODE_IDLE != Ql_iotConfigGetConnmode() || NULL == server_url || 0 == HAL_STRLEN(server_url)) + { + return FALSE; + } + if (QIOT_PPROTOCOL_MQTT != type) + { + return FALSE; + } + if (NULL != HAL_STRSTR(server_url, QIOT_DMP_SERVERURL_HTTP_DEFAULT)) + { + server_url = QIOT_DMP_SERVERURL_MQTT_DEFAULT; + } + else if (NULL != HAL_STRSTR(server_url, QIOT_DMP_SERVERURL_HTTPS_DEFAULT)) + { + server_url = QIOT_DMP_SERVERURL_MQTTS_DEFAULT; + } + if (HAL_STRLEN(server_url) < sizeof(QIot_userdata.productInfo.serverUrl) && 0 != HAL_STRCMP(QIot_userdata.productInfo.serverUrl, server_url)) + { + HAL_SPRINTF(QIot_userdata.productInfo.serverUrl, "%s", server_url); + /* 设置新的域名与当前本地保存域名不一致清除本地域名解析得到IP地址 */ + HAL_MEMSET(QIot_userdata.productInfo.serverIp, 0x00, sizeof(QIot_userdata.productInfo.serverIp)); + needsave = TRUE; + } + if (needsave) + { + HAL_MEMSET(&QIot_userdata.productInfoCache, 0x00, sizeof(Qiot_productInfo_t)); + HAL_MEMSET(&QIot_userdata.productInfoCloud, 0x00, sizeof(Qiot_productInfo_t)); + QIot_userdata.connectProduct = &QIot_userdata.productInfo; + QIot_userdata.productInfo.secret[0] = 0; + Ql_iotDSKVSave(); + } + return TRUE; +} +/************************************************************************** +** 功能 @brief : 产品配置-服务器信息获取 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void Ql_iotConfigGetServer(QIot_protocolType_t *type, char **server_url) +{ + if (type) + { + *type = QIOT_PPROTOCOL_MQTT; + } + if (server_url) + { + if (HAL_STRLEN(QIot_userdata.productInfoCloud.serverUrl)) + { + *server_url = QIot_userdata.productInfoCloud.serverUrl; + } + else + { + *server_url = QIot_userdata.productInfo.serverUrl; + } + } +} +/************************************************************************** +** 功能 @brief : 产品配置-产品信息配置 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotConfigSetProductinfo(const char *pk, const char *ps) +{ + qbool needsave = FALSE; + + if (QIOT_CONNMODE_IDLE != Ql_iotConfigGetConnmode() || pk == NULL || ps == NULL || 0 == HAL_STRLEN(pk) || 0 == HAL_STRLEN(ps)) + { + return FALSE; + } + + if (HAL_STRLEN(pk) < sizeof(QIot_userdata.productInfo.productKey) && 0 != HAL_STRCMP(QIot_userdata.productInfo.productKey, pk)) + { + HAL_SPRINTF(QIot_userdata.productInfo.productKey, "%s", pk); + needsave = TRUE; + } + if (HAL_STRLEN(ps) < sizeof(QIot_userdata.productInfo.productSecret) && 0 != HAL_STRCMP(QIot_userdata.productInfo.productSecret, ps)) + { + HAL_SPRINTF(QIot_userdata.productInfo.productSecret, "%s", ps); + needsave = TRUE; + } + if (needsave) + { + HAL_MEMSET(&QIot_userdata.productInfoCache, 0x00, sizeof(Qiot_productInfo_t)); + HAL_MEMSET(&QIot_userdata.productInfoCloud, 0x00, sizeof(Qiot_productInfo_t)); + QIot_userdata.connectProduct = &QIot_userdata.productInfo; + QIot_userdata.productInfo.secret[0] = 0; + Ql_iotDSKVSave(); + } + return TRUE; +} +/************************************************************************** +** 功能 @brief : 产品配置-产品信息获取 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Ql_iotConfigGetProductinfo(char **pk, char **ps, char **ver) +{ + if (pk) + { + if (HAL_STRLEN(QIot_userdata.productInfoCloud.productKey)) + { + *pk = QIot_userdata.productInfoCloud.productKey; + } + else + { + *pk = QIot_userdata.productInfo.productKey; + } + } + if (ps) + { + if (HAL_STRLEN(QIot_userdata.productInfoCloud.productSecret)) + { + *ps = QIot_userdata.productInfoCloud.productSecret; + } + else + { + *ps = QIot_userdata.productInfo.productSecret; + } + } + if (ver) + *ver = Ql_iotSecureVerGet(); +} +/************************************************************************** +** 功能 @brief : 产品配置-设备生命周期配置 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotConfigSetLifetime(quint32_t lifetime) +{ + if (QIOT_CONNMODE_IDLE != Ql_iotConfigGetConnmode() || lifetime == 0 || lifetime > 65535) + { + return FALSE; + } + + if (QIot_userdata.lifetime != lifetime) + { + QIot_userdata.lifetime = lifetime; +#ifdef QUEC_ENABLE_AT + Ql_iotDSKVSave(); +#endif + } + return TRUE; +} +/************************************************************************** +** 功能 @brief : 产品配置-设备生命周期获取 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +quint32_t FUNCTION_ATTR_ROM Ql_iotConfigGetLifetime(void) +{ + return QIot_userdata.lifetime; +} +/************************************************************************** +** 功能 @brief : 产品配置-sessionKey配置 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool Ql_iotConfigSetSessionFlag(qbool flag) +{ + if (QIOT_CONNMODE_IDLE != Ql_iotConfigGetConnmode()) + { + return FALSE; + } + if (flag != QIot_userdata.sessionInfo.flag) + { + QIot_userdata.sessionInfo.flag = flag; +#ifdef QUEC_ENABLE_AT + Ql_iotDSKVSave(); +#endif + } + return TRUE; +} +/************************************************************************** +** 功能 @brief : 产品配置-sessionKey获取 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool Ql_iotConfigGetSessionFlag(void) +{ + return QIot_userdata.sessionInfo.flag; +} +/************************************************************************** +** 功能 @brief : 增加APP软件版本,在启用quecthing连接之前先配置 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotConfigSetAppVersion(const char *appVer) +{ + HAL_FREE(QIot_userdata.softversion); + if (NULL == appVer) + { + QIot_userdata.softversion = HAL_STRDUP(Qhal_softversionGet()); + } + else + { + quint32_t len = HAL_STRLEN(Qhal_softversionGet()) + HAL_STRLEN(appVer); + QIot_userdata.softversion = HAL_MALLOC(len + 1); + if (QIot_userdata.softversion) + { + HAL_SPRINTF(QIot_userdata.softversion, "%s%s", Qhal_softversionGet(), appVer); + } + } + Quos_logPrintf(QUEC_IOT, LL_INFO, "new soft version:%s", QIot_userdata.softversion); + return NULL == QIot_userdata.softversion ? FALSE : TRUE; +} +/************************************************************************** +** 功能 @brief : 获取版本号 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +char FUNCTION_ATTR_ROM *Ql_iotConfigGetSoftVersion(void) +{ + return QIot_userdata.softversion; +} +/************************************************************************** +** 功能 @brief : 设置MCU版本号 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotConfigSetMcuVersion(const char *compno, const char *version) +{ + qbool ret = FALSE; + if (0 == HAL_STRLEN(compno) || HAL_STRLEN(compno) > QIOT_COMPNO_MAXSIZE || HAL_STRLEN(version) > QIOT_COMPVER_MAXSIZE) + { + return ret; + } + char *oldVersion; + qint32_t oldLen = Quos_keyValueExtract(QIot_userdata.mcuVerList, compno, QIOT_MCUVERSION_STRING_SEP, &oldVersion, QIOT_MCUVERSION_STRING_ENDSTR); + if ((0 >= oldLen && 0 != HAL_STRLEN(version)) || (0 < oldLen && 0 != HAL_STRCMP(oldVersion, version))) + { + ret = Quos_keyValueInsert(QIot_userdata.mcuVerList, sizeof(QIot_userdata.mcuVerList), compno, QIOT_MCUVERSION_STRING_SEP, version, QIOT_MCUVERSION_STRING_ENDSTR); +#ifdef QUEC_ENABLE_AT + Ql_iotDSKVSave(); +#endif + } + else + { + ret = TRUE; + } + + Ql_iotCmdOtaMcuVersionModify(compno, version); + return ret; +} +/************************************************************************** +** 功能 @brief : 获取MCU版本号 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +quint32_t FUNCTION_ATTR_ROM Ql_iotConfigGetMcuVersion(const char *compno, char **version) +{ + if (version) + { + if (NULL == compno) + { + *version = QIot_userdata.mcuVerList; + return HAL_STRLEN(QIot_userdata.mcuVerList); + } + else + { + return Quos_keyValueExtract(QIot_userdata.mcuVerList, compno, QIOT_MCUVERSION_STRING_SEP, version, QIOT_MCUVERSION_STRING_ENDSTR); + } + } + else + { + return 0; + } +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void Ql_iotUrcEventCB(quint32_t event, qint32_t errcode, const void *value, quint32_t valLen) +{ +#ifdef QUEC_ENABLE_AT + extern void Ql_iotAtEventCB(quint32_t event, qint32_t errcode, const void *value, quint32_t valLen); + Ql_iotAtEventCB(event, errcode, value, valLen); +#else + if (QIot_userdata.eventCB) + { + QIot_userdata.eventCB(event, errcode, value, valLen); + } +#endif +} +/************************************************************************** +** 功能 @brief : 注册事件回调函数 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +#ifndef QUEC_ENABLE_AT +void FUNCTION_ATTR_ROM Ql_iotConfigSetEventCB(void (*eventCb)(quint32_t event, qint32_t errcode, const void *value, quint32_t valLen)) +{ + QIot_userdata.eventCB = eventCb; +} +#endif +#ifdef QUEC_ENABLE_GATEWAY +/************************************************************************** +** 功能 @brief : 注册子设备事件回调函数 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Ql_iotConfigSetSubDevEventCB(void (*eventCb)(quint32_t event, qint32_t errcode, const char *subPk, const char *subDk ,const void *value, quint32_t valLen)) +{ + QIot_userdata.SubDevEventCB = eventCb; +} +#endif +/************************************************************************** +** 功能 @brief : 获取当前工作状态 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +QIot_state_e FUNCTION_ATTR_ROM Ql_iotGetWorkState(void) +{ + return QIot_userdata.workState; +} +/************************************************************************** +** 功能 @brief : 设置DK和DS, +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotConfigSetDkDs(const char *dk, const char *ds) +{ + if (QIOT_CONNMODE_IDLE != Ql_iotConfigGetConnmode()) + { + return FALSE; + } + if (HAL_STRLEN(dk) > QIOT_DK_MAXSIZE || HAL_STRLEN(ds) > QIOT_DS_MAXSIZE) + { + Quos_logPrintf(QUEC_IOT, LL_ERR, "dk or ds size over"); + return FALSE; + } + qint32_t len = HAL_STRLEN(dk); + while (len--) + { + if (!(__IS_LETTER(dk[len]) || __IS_DIGIT(dk[len]))) + return FALSE; + } + len = HAL_STRLEN(ds); + while (len--) + { + if (!(__IS_LETTER(ds[len]) || __IS_DIGIT(ds[len]))) + return FALSE; + } + qbool needSave = FALSE; + if (0 == HAL_STRLEN(dk)) /* 若新设DK为空且旧DK也是通过本API设置时,将清空用户配置采用默认DK重新认证 */ + { + if (0 != HAL_STRLEN(ds) || 0 == HAL_STRCMP(QIot_userdata.deviceInfo.deviceKey, Qhal_devUuidGet())) + { + return FALSE; + } + HAL_SPRINTF(QIot_userdata.deviceInfo.deviceKey, "%s", Qhal_devUuidGet()); + HAL_MEMSET(QIot_userdata.productInfo.secret, 0, sizeof(QIot_userdata.productInfo.secret)); + needSave = TRUE; + } + else if (0 == HAL_STRCMP(Qhal_devUuidGet(), dk)) + { + return FALSE; + } + else if (0 != HAL_STRCMP(QIot_userdata.deviceInfo.deviceKey, dk)) + { + HAL_SPRINTF(QIot_userdata.deviceInfo.deviceKey, "%s", dk); + HAL_SPRINTF(QIot_userdata.productInfo.secret, "%s", ds ? ds : ""); + needSave = TRUE; + } + else if ((NULL == ds && HAL_STRLEN(QIot_userdata.productInfo.secret) > 0) || (ds && 0 != HAL_STRCMP(QIot_userdata.productInfo.secret, ds))) + { + HAL_SPRINTF(QIot_userdata.productInfo.secret, "%s", ds ? ds : ""); + needSave = TRUE; + } + + if (needSave) + { + Ql_iotDSKVSave(); + } + return TRUE; +} + +/************************************************************************** +** 功能 @brief : 获取dk和ds,只有dk是外部设置的才允许查询 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotConfigGetDkDs(char **dk, char **ds) +{ + if (0 == HAL_STRCMP(QIot_userdata.deviceInfo.deviceKey, Qhal_devUuidGet())) + { + return FALSE; + } + if (dk) + { + *dk = QIot_userdata.deviceInfo.deviceKey; + } + if (ds) + { + *ds = QIot_userdata.connectProduct->secret; + } + return TRUE; +} diff --git a/cloud/common/ql_iotConfig.h b/cloud/common/ql_iotConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..d8b9890444a8985a656c83acaba220287704c66d --- /dev/null +++ b/cloud/common/ql_iotConfig.h @@ -0,0 +1,94 @@ +#ifndef __QIOT_COMMON_H__ +#define __QIOT_COMMON_H__ +#include "Ql_iotApi.h" + +#define QUEC_BUS LL_DBG +#define QUEC_LAN LL_DBG +#define QUEC_OTA LL_DBG +#define QUEC_SYS LL_DBG +#define QUEC_IOT LL_DBG +#define QUEC_CONN LL_DBG +#define QUEC_DP LL_DBG +#define QUEC_LOC LL_DBG +#define QUEC_SECURE LL_ERR +#define QUEC_AT LL_DBG + +#define QIOT_DATA_PROTOCOL_VER "1.3.0" /* 数据协议版本 */ +#define QIOT_COM_PROTOCOL_VER "3.0.0" /* 通信协议版本 */ +#define QIOT_SDK_VERSION "2.9.0" +#define QIOT_DMP_SERVERURL_MQTT_DEFAULT "iot-south.quectel.com:1883" +#define QIOT_DMP_SERVERURL_MQTTS_DEFAULT "mqtts://iot-south.quectel.com:8883" +#define QIOT_DMP_SERVERURL_HTTP_DEFAULT "iot-south.quectel.com:2883" +#define QIOT_DMP_SERVERURL_HTTPS_DEFAULT "https://iot-south.quectel.com:2884" +#define QIOT_DMP_IP_MQTT_DEFAULT "106.14.246.239" + +#define QIOT_MCUVERSION_STRING_ENDSTR ";" +#define QIOT_MCUVERSION_STRING_SEP ":" +#define QIOT_PK_MAXSIZE (32) +#define QIOT_PS_MAXSIZE (32) +#define QIOT_DK_MAXSIZE (16) +#define QIOT_DS_MAXSIZE (32) +#define QIOT_M2M_CLIENTID_MAXSIZE (2 + QIOT_PK_MAXSIZE + QIOT_DK_MAXSIZE) + +#define QIOT_OTA_FILEINFO_MAX_SIZE (5) +#define QIOT_ATEVENT_TYPE_STRING(X) \ + ( \ + (X == QUOS_SYSTEM_EVENT_NETWORK) ? "QUOS_SYSTEM_EVENT_NETWORK" \ + : (X == QIOT_ATEVENT_TYPE_AUTH) ? "ATEVENT_TYPE_AUTH" \ + : (X == QIOT_ATEVENT_TYPE_CONN) ? "ATEVENT_TYPE_CONN" \ + : (X == QIOT_ATEVENT_TYPE_SUBCRIBE) ? "ATEVENT_TYPE_SUBCRIBE" \ + : (X == QIOT_ATEVENT_TYPE_SEND) ? "ATEVENT_TYPE_SEND" \ + : (X == QIOT_ATEVENT_TYPE_RECV) ? "ATEVENT_TYPE_RECV" \ + : (X == QIOT_ATEVENT_TYPE_LOGOUT) ? "ATEVENT_TYPE_LOGOUT" \ + : (X == QIOT_ATEVENT_TYPE_OTA) ? "ATEVENT_TYPE_OTA" \ + : (X == QIOT_ATEVENT_TYPE_SERVER) ? "ATEVENT_TYPE_SERVER" \ + : "Unknown") + +typedef struct +{ + char serverUrl[QUOS_DNS_HOSTNANE_MAX_LENGHT]; + char productKey[QIOT_PK_MAXSIZE + 1]; + char productSecret[QIOT_PS_MAXSIZE + 1]; + char serverIp[QUOS_IP_ADDR_MAX_LEN]; + char secret[QIOT_DS_MAXSIZE + 1]; /* 2 == encryptType有效 */ +} Qiot_productInfo_t; + +typedef struct +{ + char key[16]; + char iv[16]; + qbool flag; + qbool usable; +} Qiot_sessionInfo_t; +typedef struct +{ + void *m2mCtx; + qbool netIsConn; /* 网络是否可以通信 */ + QIot_state_e workState; /* 工作状态,用于AT指令查询状态 */ + QIot_connMode_e connMode; /* IOT连接模式 */ + quint8_t connFailCnt; + Qiot_productInfo_t *connectProduct; + Qiot_productInfo_t productInfo; + Qiot_productInfo_t productInfoCloud; + Qiot_productInfo_t productInfoCache; + struct + { + quint8_t contextID; + char deviceKey[QIOT_DK_MAXSIZE + 1]; + } deviceInfo; + Qiot_sessionInfo_t sessionInfo; + quint32_t lifetime; + char *softversion; + char mcuVerList[512]; +#ifndef QUEC_ENABLE_AT + void (*eventCB)(quint32_t event, qint32_t errcode, const void *value, quint32_t valLen); +#endif +#ifdef QUEC_ENABLE_GATEWAY + void (*SubDevEventCB)(quint32_t event, qint32_t errcode, const char *subPk, const char * subDk, const void *value, quint32_t valLen); +#endif +} QIot_userData_t; + +extern QIot_userData_t QIot_userdata; +qbool Ql_iotDSKVSave(void); +void Ql_iotUrcEventCB(quint32_t event, qint32_t errcode, const void *value, quint32_t valLen); +#endif \ No newline at end of file diff --git a/cloud/common/ql_iotConn.c b/cloud/common/ql_iotConn.c new file mode 100644 index 0000000000000000000000000000000000000000..74525024a421552c55c1f5827aaa64ef9abc18e5 --- /dev/null +++ b/cloud/common/ql_iotConn.c @@ -0,0 +1,724 @@ +/************************************************************************* +** 创建人 @author : 吴健超 JCWu +** 版本 @version : V1.0.0 原始版本 +** 日期 @date : 2021-01-08 +** 功能 @brief : DMP接入 +** 硬件 @hardware: +** 其他 @other : +***************************************************************************/ +#include "ql_iotConn.h" +#include "ql_iotConfig.h" +#include "ql_iotSecure.h" +#include "ql_iotDp.h" +#include "Qhal_driver.h" +#include "quos_net.h" +#ifdef QUEC_ENABLE_GATEWAY +#include "ql_iotDMSub.h" +#include "ql_iotGwDev.h" +#endif +#include "ql_iotTtlv.h" + +enum +{ + QL_IOT_ERRCODE_LEVEL_FIRST = 0, + QL_IOT_ERRCODE_LEVEL_SECOND, + QL_IOT_ERRCODE_LEVEL_THIRD, + QL_IOT_ERRCODE_LEVEL_FOURTH, + QL_IOT_ERRCODE_LEVEL_FIFTH, + QL_IOT_ERRCODE_LEVEL_MAX, +}; +const quint32_t ql_errTypeTimeout[] = {SWT_ONE_SECOND, SWT_ONE_SECOND * 30, SWT_ONE_MINUTE * 5, SWT_ONE_MINUTE * 10, SWT_SUSPEND}; +typedef struct +{ + quint32_t errcode : 24; + quint32_t errType : 8; +} ql_errcodeType; + +const ql_errcodeType ql_errcodeAuth[] = + { + { + QIOT_AUTH_ERR_UNKNOWN, + QL_IOT_ERRCODE_LEVEL_FIRST, + }, + { + QIOT_AUTH_ERR_DONE, + QL_IOT_ERRCODE_LEVEL_FOURTH, + }, + { + QIOT_AUTH_ERR_PKPS_INVALID, + QL_IOT_ERRCODE_LEVEL_SECOND, + }, + { + QIOT_AUTH_ERR_PAYLOAD_INVALID, + QL_IOT_ERRCODE_LEVEL_SECOND, + }, + { + QIOT_AUTH_ERR_SIGN_INVALID, + QL_IOT_ERRCODE_LEVEL_SECOND, + }, + { + QIOT_AUTH_ERR_VERSION_INVALID, + QL_IOT_ERRCODE_LEVEL_FOURTH, + }, + { + QIOT_AUTH_ERR_HASH_INVALID, + QL_IOT_ERRCODE_LEVEL_SECOND, + }, + { + QIOT_AUTH_ERR_PK_CHANGE, + QL_IOT_ERRCODE_LEVEL_FOURTH, + }, + { + QIOT_AUTH_ERR_DEVICE_INSIDE, + QL_IOT_ERRCODE_LEVEL_FIRST, + }, + { + QIOT_AUTH_ERR_SERVER_NOTFOUND, + QL_IOT_ERRCODE_LEVEL_FIRST, + }, + { + QIOT_AUTH_ERR_FAIL, + QL_IOT_ERRCODE_LEVEL_FIRST, + }, + { + 0xFFFFFF, + 0, + }, +}; + +const ql_errcodeType ql_errcodeConn[] = + { + { + QIOT_CONN_ERR_DS_INVALID, + QL_IOT_ERRCODE_LEVEL_FIFTH, + }, + { + QIOT_CONN_ERR_DEVICE_FORBID, + QL_IOT_ERRCODE_LEVEL_FOURTH, + }, + { + QIOT_CONN_ERR_DEVICE_INSIDE, + QL_IOT_ERRCODE_LEVEL_FIRST, + }, + { + QIOT_CONN_ERR_VERSION_NOTFOUND, + QL_IOT_ERRCODE_LEVEL_FOURTH, + }, + { + QIOT_CONN_ERR_PING, + QL_IOT_ERRCODE_LEVEL_FIRST, + }, + { + QIOT_CONN_ERR_NET, + QL_IOT_ERRCODE_LEVEL_FIRST, + }, + { + QIOT_CONN_ERR_SERVER_CHANGE, + QL_IOT_ERRCODE_LEVEL_FIRST, + }, + { + 0xFFFFFF, + 0, + }, +}; + + +typedef struct +{ + char *topicType; + quint16_t *cmd; +} QIot_connCmdOutType_t; +quint16_t QIot_cmdOutSys[] = {QIOT_DPCMD_STATUS_RSP, QIOT_DPCMD_STATUS_EVENT, QIOT_DPCMD_INFO_RSP, QIOT_DPCMD_INFO_EVENT, QIOT_DPCMD_EXCE_EVENT, + QIOT_DPCMD_SUB_AUTH, QIOT_DPCMD_SUB_AUTH_RSP, QIOT_DPCMD_SUB_LOGIN, QIOT_DPCMD_SUB_LOGIN_RSP, + QIOT_DPCMD_SUB_LOGOUT, QIOT_DPCMD_SUB_LOGOUT_RSP, QIOT_DPCMD_SUB_UNAUTH_EVENT, QIOT_DPCMD_SUB_UNAUTH_EVENT_RSP, + QIOT_DPCMD_SUB_OFFLINE_EVENT, 0}; +quint16_t QIot_cmdOutBus[] = {QIOT_DPCMD_TSL_RSP, QIOT_DPCMD_TSL_EVENT, QIOT_DPCMD_PASS_EVENT, QIOT_DPCMD_LOC_REPORT, QIOT_DPCMD_LOC_RSP, 0}; +quint16_t QIot_cmdOutOta[] = {QIOT_DPCMD_OTA_COMFIRM, QIOT_DPCMD_OTA_EVENT, QIOT_DPCMD_OTA_REQUEST, 0}; +QIot_connCmdOutType_t QIot_connCmdOutType[] = { + {.topicType = "sys", .cmd = QIot_cmdOutSys}, + {.topicType = "bus", .cmd = QIot_cmdOutBus}, + {.topicType = "ota", .cmd = QIot_cmdOutOta}}; + +#define QIOT_SUB_TOPIC_ROOT "q/1/d/" /* 根订阅topic */ +#define QIOT_PUB_TOPIC_ROOT "q/2/d/" /* 根发布topic */ + +static void *QIot_RunTimer = NULL; +static void ql_iotConnStart(void); + +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void ql_iotConnServerInfoCheck(void) +{ + urlAnalyze_t urlA; + if (FALSE == Quos_urlAnalyze(QIot_userdata.connectProduct->serverUrl, &urlA)) + { + Quos_logPrintf(QUEC_CONN, LL_DBG, "get ip from url and ip manage"); + return; + } + /* 若ip发生改变,则需要触发保存,若当前连接服务器信息为缓存区,则不需要进行保存,需要等到连接DMP平台成功以后才可以保存 */ + char ip[QUOS_IP_ADDR_MAX_LEN]; + if (Quos_netHostnameValidIpGet(urlA.hostname, ip) && 0 != HAL_STRCMP(ip, QIot_userdata.connectProduct->serverIp) && QIot_userdata.connectProduct != &QIot_userdata.productInfoCache) + { + HAL_MEMCPY(QIot_userdata.connectProduct->serverIp, ip, QUOS_IP_ADDR_MAX_LEN); + Quos_logPrintf(QUEC_CONN, LL_DBG, "ip is changeed, save new ip:%s", QIot_userdata.connectProduct->serverIp); + Ql_iotDSKVSave(); + } +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void ql_iotConnEventErrcodeDeal(void) +{ + if (QIot_userdata.connectProduct != &QIot_userdata.productInfoCache) + { + return; + } + + /* 切换连接对象 */ + if (QIot_userdata.connFailCnt > 3) + { + if (0 != HAL_STRLEN(QIot_userdata.productInfoCloud.serverUrl)) + { + QIot_userdata.connectProduct = &QIot_userdata.productInfoCloud; + } + else + { + QIot_userdata.connectProduct = &QIot_userdata.productInfo; + } + QIot_userdata.connFailCnt = 0; + } +} +/************************************************************************** +** 功能 @brief : 连接失败,获取设置定时器超时时间 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static quint32_t ql_iotConnTimerTimeoutGet(const ql_errcodeType *errcodeType, qint32_t errcode) +{ + qint32_t timeout = SWT_ONE_SECOND; + quint8_t idx = 0; + + if (errcodeType != NULL) + { + while (errcodeType[idx].errcode != 0xFFFFFF) + { + if (errcodeType[idx].errcode == errcode) + { + if (QL_IOT_ERRCODE_LEVEL_FIFTH == errcodeType[idx].errType) + { + return ql_errTypeTimeout[QL_IOT_ERRCODE_LEVEL_FIFTH]; + } + timeout = ql_errTypeTimeout[errcodeType[idx].errType]; + + break; + } + idx++; + } + } + + /* 若连续失败超过6次,则强制设置连接间隔为30分钟,并重新打开网络 */ + if (++QIot_userdata.connFailCnt > 6) + { + timeout = SWT_ONE_MINUTE * 30; + return timeout; + } + /* 若连接间隔为1秒则需要对连接时间间隔加一个随机时间,随机时间范围是:-500ms~1500ms,防止同一时间过多设备上线 */ + else if (timeout == SWT_ONE_SECOND) + { + qint16_t rand = (Qhal_randomGet() % 2000); + + timeout += rand - 500; + } + /* 连接失败判断当前是否为cache连接对象,若是则需要切换连接对象为cloud或本地 */ + ql_iotConnEventErrcodeDeal(); + + return timeout * QIot_userdata.connFailCnt; +} +/************************************************************************** +** 功能 @brief : 根据命令查找topic类型 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static char *FUNCTION_ATTR_ROM ql_iotConnTopicTypeByCmdGet(quint16_t cmd) +{ + quint32_t i; + for (i = 0; i < sizeof(QIot_connCmdOutType) / sizeof(QIot_connCmdOutType[0]); i++) + { + quint32_t j = 0; + while (QIot_connCmdOutType[i].cmd[j]) + { + if (QIot_connCmdOutType[i].cmd[j++] == cmd) + { + return QIot_connCmdOutType[i].topicType; + } + } + } + return NULL; +} +/************************************************************************** +** 功能 @brief : 接入定时响应 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void FUNCTION_ATTR_ROM ql_iotConnTimeoutCB(void *swtimer) +{ + if (QIot_userdata.connFailCnt > 6) + { + Quos_netOpen(); + QIot_userdata.connFailCnt = 0; + return; + } + Quos_swTimerTimeoutSet(swtimer, SWT_SUSPEND); + ql_iotConnStart(); +} +/************************************************************************** +** 功能 @brief : MQTT事件回调 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void FUNCTION_ATTR_ROM ql_iotConnEventCb(void *chlFd, qint32_t result) +{ + Quos_logPrintf(QUEC_CONN, LL_DBG, "chlFd[%p] result:%s", chlFd, MQTT_ERR_STRING(result)); + switch (result) + { + case QUOS_MQTT_OK_CONNECT: + break; + case QUOS_MQTT_ERR_CONNECT: + Quos_eventPost(QIOT_ATEVENT_TYPE_CONN, (void *)QIOT_CONN_ERR_UNKNOW); + break; + case QUOS_MQTT_ERR_INSIDE: + Quos_eventPost(QIOT_ATEVENT_TYPE_CONN, (void *)QIOT_CONN_ERR_DEVICE_INSIDE); + break; + case QUOS_MQTT_ERR_PING: + Quos_eventPost(QIOT_ATEVENT_TYPE_CONN, (void *)QIOT_CONN_ERR_PING); + break; + case QUOS_MQTT_ERR_NET: + Quos_eventPost(QIOT_ATEVENT_TYPE_CONN, (void *)QIOT_CONN_ERR_NET); + break; + case QUOS_MQTT_UNNACCEPTABLE_PROTOCOL: + Quos_eventPost(QIOT_ATEVENT_TYPE_CONN, (void *)QIOT_CONN_ERR_VERSION_NOTFOUND); + break; + case QUOS_MQTT_CLIENTID_REJECTED: + Quos_eventPost(QIOT_ATEVENT_TYPE_CONN, (void *)QIOT_CONN_ERR_DS_INVALID); + break; + case QUOS_MQTT_SERVER_UNAVAILABLE: + Quos_eventPost(QIOT_ATEVENT_TYPE_CONN, (void *)QIOT_CONN_ERR_DS_INVALID); + break; + case QUOS_MQTT_BAD_USERNAME_OR_PASSWORD: + Quos_eventPost(QIOT_ATEVENT_TYPE_CONN, (void *)QIOT_CONN_ERR_DS_INVALID); + break; + case QUOS_MQTT_NOT_AUTHORIZED: + Quos_eventPost(QIOT_ATEVENT_TYPE_CONN, (void *)QIOT_CONN_ERR_DS_INVALID); + break; + case QUOS_MQTT_OK_SUBSCRIBE: + if (QIOT_STATE_CONNECTING == QIot_userdata.workState) + { + Quos_eventPost(QIOT_ATEVENT_TYPE_CONN, (void *)QIOT_CONN_SUCC); + Quos_eventPost(QIOT_ATEVENT_TYPE_SUBCRIBE, (void *)QIOT_SUBCRIBE_SUCC); + } + break; + case QUOS_MQTT_ERR_SUBSCRI: + Quos_eventPost(QIOT_ATEVENT_TYPE_SUBCRIBE, (void *)QIOT_SUBCRIBE_ERR); + break; + default: + Quos_eventPost(QIOT_ATEVENT_TYPE_CONN, (void *)QIOT_CONN_ERR_UNKNOW); + break; + } +} +/************************************************************************** +** 功能 @brief : MQTT底层接收接口 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void FUNCTION_ATTR_ROM ql_iotConnRecv(MQTTString *topicName, quint8_t *payload, quint32_t payloadlen) +{ + Quos_logPrintf(QUEC_CONN, LL_DBG, "topic:%.*s", topicName->lenstring.len, topicName->lenstring.data); + Quos_logHexDump(QUEC_CONN, LL_DUMP, "recv", payload, payloadlen); +#ifdef QUEC_ENABLE_GATEWAY + QIot_Subdev_t *subdev = NULL; +#endif + char * p; + if((p = HAL_STRSTR(topicName->lenstring.data,QIot_userdata.deviceInfo.deviceKey))) + { + if (Ql_iotConfigGetSessionFlag() && QIot_userdata.sessionInfo.usable) + { + payloadlen = Ql_iotSecureDecryptPayload(payload, payloadlen, QIot_userdata.sessionInfo.key, QIot_userdata.sessionInfo.iv); + Quos_logHexDump(QUEC_CONN, LL_DUMP, "Decrypt data", payload, payloadlen); + } + #if 0 + if (FALSE == Ql_iotDpRawDataPickup(payload, payloadlen, &pkg)) + { + Quos_logPrintf(QUEC_CONN, LL_ERR, "data pickup fail: %.*s", payloadlen, payload); + return; + } + #endif + } +#ifdef QUEC_ENABLE_GATEWAY + else + { + subdev = Ql_iotDMSubDevFindByEndPoint(topicName->lenstring.data); + if (NULL == subdev) + { + Quos_logPrintf(QUEC_CONN, LL_ERR, "subdev not connected: %.*s", topicName->lenstring.len, topicName->lenstring.data); + return; + } + else if (subdev->m2msessionInfo.usable) + { + payloadlen = Ql_iotSecureDecryptPayload(payload, payloadlen, subdev->m2msessionInfo.key, subdev->m2msessionInfo.iv); + Quos_logHexDump(QUEC_CONN, LL_DUMP, "Decrypt data", payload, payloadlen); + } + #if 0 + if (FALSE == Ql_iotDpRawDataPickup(payload, payloadlen, &pkg)) + { + return; + } + #endif + } +#endif + char *cliId = HAL_STRSTR(topicName->lenstring.data, QIOT_SUB_TOPIC_ROOT); + if (NULL == cliId || 0 == payloadlen) + { + return; + } + cliId += HAL_STRLEN(QIOT_SUB_TOPIC_ROOT); + char *words[10]; + quint32_t count = Quos_stringSplit(cliId, topicName->lenstring.len - (cliId - topicName->lenstring.data), words, sizeof(words) / sizeof(words[0]), "/", FALSE); + if (2 == count || 3 == count) + { + topicName->lenstring.len = HAL_SPRINTF(topicName->lenstring.data, "%s", words[0]); + if (3 == count) + { + topicName->lenstring.len += HAL_SPRINTF(topicName->lenstring.data + topicName->lenstring.len, "/%s", words[2]); + } +#ifdef QUEC_ENABLE_GATEWAY + if (NULL == subdev) + Ql_iotDpHandle(QIOT_DPAPP_M2M, topicName->lenstring.data, payload, payloadlen); + else +#endif + Ql_iotDpHandle(QIOT_DPAPP_SUBDEV, topicName->lenstring.data, payload, payloadlen); + } +} +/************************************************************************** +** 功能 @brief : mqtt发送 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotConnSend(const char *endPoint, quint16_t mode, quint16_t cmd, quint16_t srcpkgID, quint16_t pkgId, const quint8_t *payload, quint32_t payloadLen, socketRecvNodeCb_f recvCB) +{ +#ifndef QUEC_ENABLE_GATEWAY + UNUSED(srcpkgID); +#endif + static quint16_t m2mPkgId = 0; + if (NULL == QIot_userdata.m2mCtx || mode > 2) + { + return FALSE; + } + qbool isAck = TRUE; + char *topicType = ql_iotConnTopicTypeByCmdGet(cmd); + if (NULL == topicType) + { + return FALSE; + } + + char clientId[QIOT_M2M_CLIENTID_MAXSIZE + 1]; + HAL_SPRINTF(clientId, "qd%s%s", QIot_userdata.connectProduct->productKey, QIot_userdata.deviceInfo.deviceKey); + if (0 == pkgId) + { + isAck = FALSE; + if(NULL == endPoint || 0 == HAL_STRNCMP(endPoint, clientId, HAL_STRLEN(clientId))) + { + pkgId = Ql_iotDpPkgIdUpdate(&m2mPkgId); + } +#ifdef QUEC_ENABLE_GATEWAY + else + { + QIot_Subdev_t *subdev = Ql_iotDMSubDevFindByEndPoint(endPoint); + if (NULL != subdev) + { + pkgId = Ql_iotDpPkgIdUpdate(&subdev->m2mpkgId); + } + } +#endif + } +#ifdef QUEC_ENABLE_GATEWAY + if (0 != srcpkgID) + { + if (!Ql_iotDMSubDevAddAckmap(endPoint, pkgId, srcpkgID, 0)) + { + return FALSE; + } + } +#endif + char pubTopic[sizeof(QIOT_PUB_TOPIC_ROOT) + QIOT_M2M_CLIENTID_MAXSIZE * 2 + 1 + 3 + 1] = {0}; + char *next = NULL; +#ifdef QUEC_ENABLE_GATEWAY + QIot_Subdev_t *subdev = NULL; +#endif + if (NULL == endPoint) /* local与m2m交互消息 */ + { + HAL_SPRINTF(pubTopic, QIOT_PUB_TOPIC_ROOT "%s/%s", clientId, topicType); + } + else if ((next = HAL_STRSTR(endPoint, "/"))) /* APP消息 */ + { + HAL_SPRINTF(pubTopic, QIOT_PUB_TOPIC_ROOT "%.*s/%s/%s", (int)(next - endPoint), endPoint, topicType, next + 1); + } + else /* 子设备消息 */ + { +#ifdef QUEC_ENABLE_GATEWAY + if (0 == HAL_STRNCMP(topicType, "bus", 3)) + { + subdev = Ql_iotDMSubDevFindByEndPoint(endPoint); + HAL_SPRINTF(pubTopic, QIOT_PUB_TOPIC_ROOT "%s/%s", endPoint, topicType); + } + else + { +#endif + HAL_SPRINTF(pubTopic, QIOT_PUB_TOPIC_ROOT "%s/%s", clientId, topicType); +#ifdef QUEC_ENABLE_GATEWAY + } +#endif + } + + quint8_t *pkg = NULL; + payloadLen = Ql_iotDpFormat(&pkg, pkgId, cmd, payload, payloadLen); + Quos_logPrintf(QUEC_CONN, LL_DBG, "len:%u mode:%d topic:%s", payloadLen, mode, pubTopic); + if (0 == payloadLen) + { + return FALSE; + } + qbool ret = FALSE; +#ifdef QUEC_ENABLE_GATEWAY + if (NULL != subdev && TRUE == subdev->m2msessionInfo.usable) + { + quint8_t *outData = NULL; + payloadLen = Ql_iotSecureEncryptPayload(pkg, payloadLen, &outData, subdev->m2msessionInfo.key, subdev->m2msessionInfo.iv); + HAL_FREE(pkg); + if (outData) + { + ret = Quos_mqttPublish(QIot_userdata.m2mCtx, pubTopic, NULL, mode, outData, payloadLen, recvCB, isAck) < 0 ? FALSE : TRUE; + HAL_FREE(outData); + } + } + else if (NULL == subdev && Ql_iotConfigGetSessionFlag() && QIot_userdata.sessionInfo.usable) /* 主设备使用加密 */ + { + quint8_t *outData = NULL; + payloadLen = Ql_iotSecureEncryptPayload(pkg, payloadLen, &outData, QIot_userdata.sessionInfo.key, QIot_userdata.sessionInfo.iv); + HAL_FREE(pkg); + if (outData) + { + ret = Quos_mqttPublish(QIot_userdata.m2mCtx, pubTopic, NULL, mode, outData, payloadLen, recvCB, isAck) < 0 ? FALSE : TRUE; + HAL_FREE(outData); + } + } +#else + if (Ql_iotConfigGetSessionFlag() && QIot_userdata.sessionInfo.usable) /* 主设备使用加密 */ + { + quint8_t *outData = NULL; + payloadLen = Ql_iotSecureEncryptPayload(pkg, payloadLen, &outData, QIot_userdata.sessionInfo.key, QIot_userdata.sessionInfo.iv); + HAL_FREE(pkg); + if (outData) + { + ret = Quos_mqttPublish(QIot_userdata.m2mCtx, pubTopic, NULL, mode, outData, payloadLen, recvCB, isAck) < 0 ? FALSE : TRUE; + HAL_FREE(outData); + } + } +#endif + else + { + ret = Quos_mqttPublish(QIot_userdata.m2mCtx, pubTopic, NULL, mode, pkg, payloadLen, recvCB, isAck) < 0 ? FALSE : TRUE; + HAL_FREE(pkg); + } + return ret; +} + +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void FUNCTION_ATTR_ROM ql_iotConnStart(void) +{ + urlAnalyze_t urlA; + Quos_logPrintf(QUEC_CONN, LL_DBG, "netIsConn:%s connMode:%s m2mCtx:%p", _BOOL2STR(QIot_userdata.netIsConn), QIOT_CONN_MODE_STRING(QIot_userdata.connMode), QIot_userdata.m2mCtx); + if (TRUE != QIot_userdata.netIsConn || QIOT_CONNMODE_IDLE == QIot_userdata.connMode || NULL != QIot_userdata.m2mCtx) + { + return; + } + if (FALSE == Quos_urlAnalyze(QIot_userdata.connectProduct->serverUrl, &urlA)) + { + Quos_eventPost(QIOT_ATEVENT_TYPE_AUTH, (void *)QIOT_AUTH_ERR_SERVER_NOTFOUND); + } + else if (0 == HAL_STRLEN(QIot_userdata.productInfo.productKey) || 0 == HAL_STRLEN(QIot_userdata.productInfo.productSecret)) + { + Quos_eventPost(QIOT_ATEVENT_TYPE_AUTH, (void *)QIOT_AUTH_ERR_PKPS_INVALID); + } + else + { + Quos_netHostnameSetDefault(urlA.hostname, QIot_userdata.connectProduct->serverIp); + qbool isToAuth = (0 == HAL_STRLEN(QIot_userdata.connectProduct->secret)); + char *password = NULL; + QIot_userdata.sessionInfo.usable = FALSE; + if (isToAuth) + { + password = Ql_iotSecureGenMqttAuthData(QIot_userdata.connectProduct->productKey, QIot_userdata.connectProduct->productSecret, QIot_userdata.deviceInfo.deviceKey); + } + else + { + password = Ql_iotSecureGenMqttConnData(QIot_userdata.connectProduct->productSecret, QIot_userdata.connectProduct->secret); + } + int subQos = 1; + char clientId[QIOT_M2M_CLIENTID_MAXSIZE + 1]; + char subTopicRoot[sizeof(QIOT_SUB_TOPIC_ROOT) + sizeof(clientId) + 3]; + HAL_SPRINTF(clientId, "qd%s%s", QIot_userdata.connectProduct->productKey, QIot_userdata.deviceInfo.deviceKey); + HAL_SPRINTF(subTopicRoot, QIOT_SUB_TOPIC_ROOT "%s/+", clientId); + char *subTopic[1]; + subTopic[0] = subTopicRoot; + qbool ret = Quos_mqttInit(&QIot_userdata.m2mCtx, QIot_userdata.connectProduct->serverUrl, clientId, NULL, password, QIot_userdata.lifetime, 1, subTopic, &subQos, ql_iotConnEventCb, ql_iotConnRecv); + HAL_FREE(password); + if (TRUE == ret) + { + QIot_userdata.workState = isToAuth ? QIOT_STATE_AUTHENTICATING : QIOT_STATE_CONNECTING; + } + else + { + Quos_eventPost(isToAuth ? QIOT_ATEVENT_TYPE_AUTH : QIOT_ATEVENT_TYPE_CONN, (void *)QIOT_CONN_ERR_DEVICE_INSIDE); + } + } +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void FUNCTION_ATTR_ROM ql_iotConnStop(void) +{ + Quos_logPrintf(QUEC_CONN, LL_DBG, "netIsConn:%s connMode:%s m2mCtx:%p", _BOOL2STR(QIot_userdata.netIsConn), QIOT_CONN_MODE_STRING(QIot_userdata.connMode), QIot_userdata.m2mCtx); + if (QIot_userdata.m2mCtx) + { + Quos_mqttDeinit(QIot_userdata.m2mCtx); + QIot_userdata.m2mCtx = NULL; + + if (QIOT_CONNMODE_IDLE == QIot_userdata.connMode && TRUE == QIot_userdata.netIsConn) + { + Quos_eventPost(QIOT_ATEVENT_TYPE_LOGOUT, (void *)QIOT_LOGOUT_SUCC); + QIot_userdata.workState = QIOT_STATE_DISCONNECTED; + } + else if (QIOT_CONNMODE_IDLE != QIot_userdata.connMode && TRUE == QIot_userdata.netIsConn) + { + Quos_eventPost(QIOT_ATEVENT_TYPE_CONN, (void *)QIOT_CONN_ERR_NET); + } + } + Quos_swTimerTimeoutSet(QIot_RunTimer, SWT_SUSPEND); +} + +/************************************************************************** +** 功能 @brief : conn事件处理 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void ql_iotConnEventNotify(qint32_t event, void *arg) +{ + qint32_t errcode = (qint32_t)(pointer_t)arg; + Quos_logPrintf(QUEC_CONN, LL_DBG, "type:%s errcode:%d connMode:%s netIsConn:%s", QIOT_ATEVENT_TYPE_STRING(event), errcode, QIOT_CONN_MODE_STRING(QIot_userdata.connMode), _BOOL2STR(QIot_userdata.netIsConn)); + switch (event) + { + case QIOT_ATEVENT_TYPE_AUTH: + QIot_userdata.workState = QIOT_AUTH_SUCC == errcode ? QIOT_STATE_AUTHENTICATED : QIOT_STATE_AUTHENTICATE_FAILED; + if (QIOT_AUTH_SUCC == errcode) + { + Quos_eventPost(QIOT_ATEVENT_TYPE_CONN, (void *)QIOT_CONN_SUCC); + Quos_eventPost(QIOT_ATEVENT_TYPE_SUBCRIBE, (void *)QIOT_SUBCRIBE_SUCC); + ql_iotConnServerInfoCheck(); + QIot_userdata.connFailCnt = 0; + } + else + { + Quos_swTimerTimeoutSet(QIot_RunTimer, ql_iotConnTimerTimeoutGet(ql_errcodeAuth, errcode)); + } + break; + case QIOT_ATEVENT_TYPE_CONN: + { + QIot_userdata.workState = QIOT_CONN_SUCC == errcode ? QIOT_STATE_CONNECTED : QIOT_STATE_CONNECT_FAIL; + + if (QIOT_CONN_SUCC == errcode) + { + QIot_userdata.connFailCnt = 0; + Quos_swTimerTimeoutSet(QIot_RunTimer, SWT_SUSPEND); + ql_iotConnServerInfoCheck(); + if (QIot_userdata.connectProduct == &QIot_userdata.productInfoCache) + { + /* 若当前连接服务器信息为缓存区,则需要将数据复制到cloud信息区,并执行保存 */ + HAL_MEMCPY(&QIot_userdata.productInfoCloud, QIot_userdata.connectProduct, sizeof(Qiot_productInfo_t)); + Ql_iotDSKVSave(); + } + } + else + { + if (QIOT_CONN_ERR_DS_INVALID == errcode) + { + HAL_MEMSET(QIot_userdata.connectProduct->secret, 0, sizeof(QIot_userdata.connectProduct->secret)); + Ql_iotDSKVSave(); + } +#ifdef QUEC_ENABLE_GATEWAY + Ql_iotDMSubDevBusDisconnNotify(); +#endif + Quos_swTimerTimeoutSet(QIot_RunTimer, ql_iotConnTimerTimeoutGet(ql_errcodeConn, errcode)); + } + break; + } + case QIOT_ATEVENT_TYPE_SUBCRIBE: + switch (errcode) + { + case QIOT_SUBCRIBE_SUCC: + QIot_userdata.workState = QIOT_STATE_SUBSCRIBED; + break; + default: + QIot_userdata.workState = QIOT_STATE_SUBSCRIBE_FAIL; + Quos_swTimerTimeoutSet(QIot_RunTimer, ql_iotConnTimerTimeoutGet(NULL, errcode)); + break; + } + break; + case QIOT_ATEVENT_TYPE_LOGOUT: + break; + case QIOT_ATEVENT_TYPE_SERVER: + break; + case QUOS_SYSTEM_EVENT_NETWORK: + if(QUOS_SEVENT_NET_CONNTIMEOUT == errcode) + { + Quos_eventPost(QIOT_ATEVENT_TYPE_CONN, (void *)QIOT_CONN_ERR_AP); + } + else if(QUOS_SEVENT_NET_CONNECTED == errcode && FALSE == QIot_userdata.netIsConn) + { + QIot_userdata.netIsConn = TRUE; + ql_iotConnStart(); + } + else if(QUOS_SEVENT_NET_DISCONNECT == errcode && TRUE == QIot_userdata.netIsConn) + { + ql_iotConnStop(); + QIot_userdata.netIsConn = FALSE; +#ifdef QUEC_ENABLE_GATEWAY + Ql_iotDMSubDevBusDisconnNotify(); +#endif + } + return; + default: + return; + } + Ql_iotUrcEventCB(event, errcode, NULL, 0); +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Ql_iotConnInit(void) +{ + Quos_swTimerStart(&QIot_RunTimer, "quec run", SWT_SUSPEND, 0, ql_iotConnTimeoutCB, NULL); + qint32_t event[] = {QIOT_ATEVENT_TYPE_AUTH, QIOT_ATEVENT_TYPE_CONN, QIOT_ATEVENT_TYPE_SUBCRIBE, QIOT_ATEVENT_TYPE_LOGOUT, QIOT_ATEVENT_TYPE_SERVER, QUOS_SYSTEM_EVENT_NETWORK}; + Quos_eventCbReg(event, sizeof(event) / sizeof(event[0]), ql_iotConnEventNotify); +} diff --git a/cloud/common/ql_iotConn.h b/cloud/common/ql_iotConn.h new file mode 100644 index 0000000000000000000000000000000000000000..c6dcb45f240827308a4fc31b11084abcfa52374e --- /dev/null +++ b/cloud/common/ql_iotConn.h @@ -0,0 +1,62 @@ +/* + * @Author: your name + * @Date: 2021-11-04 19:23:58 + * @LastEditTime: 2021-11-10 08:52:02 + * @LastEditors: Please set LastEditors + * @Description: In User Settings Edit + * @FilePath: \QuecCSDK\cloud\common\ql_iotConn.h + */ +#ifndef __QIOT_CONN_H__ +#define __QIOT_CONN_H__ +#include "Ql_iotApi.h" + +#define QIOT_CONN_NET_ERRTIME_MAX 6 /* 连续网络异常次数,重启网络 */ +#define QIOT_AUTH_ERR_STRING(X) \ + ( \ + (X == QIOT_AUTH_SUCC) ? "AUTH_SUCC" : (X == QIOT_AUTH_ERR_REQDATA) ? "AUTH_ERR_REQDATA" \ + : (X == QIOT_AUTH_ERR_DONE) ? "AUTH_ERR_DONE" \ + : (X == QIOT_AUTH_ERR_PKPS_INVALID) ? "AUTH_ERR_PKPS_INVALID" \ + : (X == QIOT_AUTH_ERR_PAYLOAD_INVALID) ? "AUTH_ERR_PAYLOAD_INVALID" \ + : (X == QIOT_AUTH_ERR_SIGN_INVALID) ? "AUTH_ERR_SIGN_INVALID" \ + : (X == QIOT_AUTH_ERR_VERSION_INVALID) ? "AUTH_ERR_VERSION_INVALID" \ + : (X == QIOT_AUTH_ERR_HASH_INVALID) ? "AUTH_ERR_HASH_INVALID" \ + : (X == QIOT_AUTH_ERR_PK_CHANGE) ? "AUTH_ERR_PK_CHANGE" \ + : (X == QIOT_AUTH_ERR_DK_ILLEGAL) ? "AUTH_ERR_DK_ILLEGAL" \ + : (X == QIOT_AUTH_ERR_PK_VER_NOCOR) ? "AUTH_ERR_PK_VER_NOCOR" \ + : (X == QIOT_AUTH_ERR_DEVICE_INSIDE) ? "AUTH_ERR_DEVICE_INSIDE" \ + : (X == QIOT_AUTH_ERR_SERVER_NOTFOUND) ? "AUTH_ERR_SERVER_NOTFOUND" \ + : (X == QIOT_AUTH_ERR_FAIL) ? "AUTH_ERR_FAIL" \ + : (X == QIOT_AUTH_ERR_UNKNOWN) ? "AUTH_ERR_UNKNOWN" \ + : "Unknown") + +#define QIOT_CONN_ERR_STRING(X) \ + ( \ + (X == QIOT_CONN_SUCC) ? "CONN_SUCC" : (X == QIOT_CONN_ERR_DS_INVALID) ? "CONN_ERR_DS_INVALID" \ + : (X == QIOT_CONN_ERR_DEVICE_FORBID) ? "CONN_ERR_DEVICE_FORBID" \ + : (X == QIOT_CONN_ERR_DEVICE_INSIDE) ? "CONN_ERR_DEVICE_INSIDE" \ + : (X == QIOT_CONN_ERR_VERSION_NOTFOUND) ? "CONN_ERR_VERSION_NOTFOUND" \ + : (X == QIOT_CONN_ERR_PING) ? "CONN_ERR_PING" \ + : (X == QIOT_CONN_ERR_NET) ? "CONN_ERR_NET" \ + : (X == QIOT_CONN_ERR_SERVER_CHANGE) ? "QIOT_CONN_ERR_SERVER_CHANGE" \ + : (X == QIOT_CONN_ERR_UNKNOW) ? "CONN_ERR_UNKNOW" \ + : "Unknown") + +#define QIOT_SUBCRIBE_ERR_STRING(X) \ + ( \ + (X == QIOT_SUBCRIBE_SUCC) ? "SUBCRIBE_SUCC" : (X == QIOT_SUBCRIBE_ERR) ? "SUBCRIBE_ERR" \ + : "Unknown") + +#define QIOT_LOGOUT_ERR_STRING(X) \ + ( \ + (X == QIOT_LOGOUT_SUCC) ? "LOGOUT_SUCC" : "Unknown") + +#define QIOT_CONN_MODE_STRING(X) \ + ( \ + (X == QIOT_CONNMODE_IDLE) ? "CONNMODE_IDLE" : (X == QIOT_CONNMODE_REQ) ? "CONNMODE_REQ" \ + : (X == QIOT_CONNMODE_AUTO) ? "CONNMODE_AUTO" \ + : "Unknown") +void Ql_iotConnInit(void); +qbool Ql_iotConnSend(const char *endPoint, quint16_t mode, quint16_t cmd, quint16_t srcpkgId, quint16_t pkgId, const quint8_t *payload, quint32_t payloadLen, socketRecvNodeCb_f recvCB); +#ifdef QUEC_ENABLE_GATEWAY +#endif +#endif \ No newline at end of file diff --git a/cloud/common/ql_iotDp.c b/cloud/common/ql_iotDp.c new file mode 100644 index 0000000000000000000000000000000000000000..d309e38f13db829eae0be4755615c17b972c3bf7 --- /dev/null +++ b/cloud/common/ql_iotDp.c @@ -0,0 +1,399 @@ +#include "ql_iotDp.h" +#include "ql_iotTtlv.h" +#include "ql_iotConfig.h" +#include "ql_iotCmdBus.h" +#include "ql_iotCmdOTA.h" +#include "ql_iotCmdSys.h" +#include "ql_iotCmdLan.h" +#include "ql_iotCmdLoc.h" +#include "ql_iotConn.h" +#ifdef QUEC_ENABLE_GATEWAY +#include "ql_iotGwDev.h" +#endif + +/* 协议坐标 */ +#define DP_POS_VER_1 0 +#define DP_POS_VER_2 1 +#define DP_POS_LEN_1 2 +#define DP_POS_LEN_2 3 +#define DP_POS_SUM 4 +#define DP_POS_PID_1 5 +#define DP_POS_PID_2 6 +#define DP_POS_CMD_1 7 +#define DP_POS_CMD_2 8 +#define DP_POS_DATA 9 + +/* 协议版本 */ +#define DP_VER_HEADER 0XAA /* 协议版本固定头部 */ +#define DP_VER_CURRENT 0XAA /* 当前协议版本 */ +#define DP_VER_ESC 0X55 /* 协议版本转义符号 */ + +QIot_cmdTable_t QIot_cmdTableLocal[] = + { + {.cmd = QIOT_DPCMD_TSL_REQ, .cmdHandle = Ql_iotCmdBusPhymodelReqRecv}, /* 物模型状态获取 */ + {.cmd = QIOT_DPCMD_TSL_WRITE, .cmdHandle = Ql_iotCmdBusPhymodelWriteRecv}, /* 物模型数据下发 */ + {.cmd = QIOT_DPCMD_PASS_WRITE, .cmdHandle = Ql_iotCmdBusPassTransRecv}, /* 透传数据下发 */ + {.cmd = QIOT_DPCMD_LOC_REQ, .cmdHandle = Ql_iotCmdLocDataReqRecv}, /* 获取实时定位信息 */ + {.cmd = QIOT_DPCMD_OTA_NOTIFY, .cmdHandle = Ql_iotCmdOtaNotify}, /* OTA升级任务通知 */ + {.cmd = QIOT_DPCMD_OTA_FW_INFO, .cmdHandle = Ql_iotCmdOtaFwInfo}, /* 固件信息下发 */ + {.cmd = QIOT_DPCMD_STATUS_REQ, .cmdHandle = Ql_iotCmdSysStatusRecv}, /* 设备状态获取 */ + {.cmd = QIOT_DPCMD_INFO_REQ, .cmdHandle = Ql_iotCmdSysDevInfoRecv}, /* 模组信息获取 */ + {.cmd = QIOT_DPCMD_EXCE_WRITE, .cmdHandle = Ql_iotCmdSysExceWrite}, /* 平台异常通知到设备 */ + {.cmd = QIOT_DPCMD_DEV_CONFIG_WRITE, .cmdHandle = Ql_iotCmdSysTerManage}, /* 设备配置命令 */ +#ifdef QUEC_ENABLE_GATEWAY + {.cmd = QIOT_DPCMD_SUB_AUTH_RSP, .cmdHandle = Ql_gatewayDeviceSubAuthResponse}, /* 子设备认证--平台回复 */ + {.cmd = QIOT_DPCMD_SUB_LOGIN_RSP, .cmdHandle = Ql_gatewayDeviceSubLoginResponse}, /* 子设备登陆--平台回复 */ + {.cmd = QIOT_DPCMD_SUB_UNAUTH_EVENT_RSP, .cmdHandle = Ql_gatewayDeviceSubUnauthResponse}, /* 子设备注销--平台回复 */ + {.cmd = QIOT_DPCMD_SUB_LOGOUT_RSP, .cmdHandle = Ql_gatewayDeviceSubLogoutResponse}, /* 子设备登出平台响应 */ + {.cmd = QIOT_DPCMD_SUB_OFFLINE_EVENT, .cmdHandle = Ql_gatewayDeviceSubOfflineEvent}, /* 子设备下线事件 */ +#endif +}; +#ifdef QUEC_ENABLE_LAN +QIot_cmdTable_t QIot_cmdTableLan[] = + { + {.cmd = QIOT_DPCMD_LAN_DISCOVER_REQ, .cmdHandle = ql_iotLanDevDiscover}, /* 发现局域网下设备 */ + //{.cmd = QIOT_DPCMD_LAN_AUTH_COND_REQ, .cmdHandle = NULL}, /* 局域网认证前置条件请求 */ + //{.cmd = QIOT_DPCMD_LAN_AUTH_SIGN_REQ, .cmdHandle = NULL}, /* 局域网认证签名请求 */ +}; +#endif +#ifdef QUEC_ENABLE_GATEWAY +QIot_cmdTable_t QIot_cmdTableSubDev[] = + { + {.cmd = QIOT_DPCMD_TSL_REQ, .cmdHandle = Ql_gatewayDeviceSubTslDataRead}, /* 物模型状态获取 */ + {.cmd = QIOT_DPCMD_TSL_WRITE, .cmdHandle = Ql_gatewayDeviceSubTslDataWrite}, /* 物模型数据下发 */ + {.cmd = QIOT_DPCMD_PASS_WRITE, .cmdHandle = Ql_gatewayDeviceSubPassTransData}, /* 透传数据下发 */ + //{.cmd = QIOT_DPCMD_LOC_REQ, .cmdHandle = NULL}, /* 获取实时定位信息 */ + {.cmd = QIOT_DPCMD_STATUS_REQ, .cmdHandle = Ql_gatewayDeviceSubStateRead}, /* 设备状态获取 */ + {.cmd = QIOT_DPCMD_INFO_REQ, .cmdHandle = Ql_gatewayDeviceSubInfoRead}, /* 模组信息获取 */ + + //{.cmd = QIOT_DPCMD_STATUS_EVENT, .cmdHandle = Ql_gatewayDeviceSubStateReport}, /* 子设备状态上报 */ + //{.cmd = QIOT_DPCMD_INFO_EVENT, .cmdHandle = Ql_gatewayDeviceSubInfoReport}, /* 子设备模组信息上报 */ + //{.cmd = QIOT_GATEWAY_SUB_FIND_GATEWAY, .cmdHandle = Ql_gatewayDeviceSubReciveBroadMsg}, /* 子设备广播查找网关 */ + //{.cmd = QIOT_GATEWAY_SUB_CONN_GATEWAY, .cmdHandle = Ql_gatewayDeviceSubConnGatwayMsg}, /* 子设备连接网关 */ + //{.cmd = QIOT_GATEWAY_SUB_AUTH, .cmdHandle = Ql_gatewayDeviceSubAuthMsg}, /* 子设备发起认证 */ + //{.cmd = QIOT_GATEWAY_SUB_LOGIN, .cmdHandle = Ql_gatewayDeviceSubConnMsg}, /* 子设备发起登录平台 */ + //{.cmd = QIOT_GATEWAY_SUB_LOGOUT_EVENT, .cmdHandle = Ql_gatewayDeviceSubDisconnMsg}, /* 子设备发起下线 */ + //{.cmd = QIOT_GATEWAY_SUB_UNAUTH_EVENT, .cmdHandle = Ql_gatewayDeviceSubUnauthMsg}, /* 子设备发起注销 */ + //{.cmd = QIOT_DPCMD_PASS_EVENT, .cmdHandle = Ql_gatewayDeviceSubPassTransReport}, /* 子设备上传透传数据 */ + //{.cmd = QIOT_DPCMD_TSL_EVENT, .cmdHandle = Ql_gatewayDeviceSubPhymodelReport}, /* 子设备上报物模型数据 */ + //{.cmd = QIOT_GATEWAY_SUB_READ_STATE, .cmdHandle = Ql_gatewayDeviceStateQuery}, /* 子设备查询网关状态 */ + +}; +#endif +QIot_dpAppSend_t QIot_dpAppSend[] = + { + {.app = QIOT_DPAPP_M2M, .send = Ql_iotConnSend}, +#ifdef QUEC_ENABLE_GATEWAY +//{.app = QIOT_DPAPP_SUBDEV, .send = Ql_iotConnSubSendUart}, +#endif +}; +/************************************************************************** +** 功能 @brief : 合并数据包,并进行0x55转换 +** 输入 @param : +** 输出 @retval: 输出数据长度 +** 备注 @remark: 这样处理主要是为了减少malloc次数 +***************************************************************************/ +quint32_t FUNCTION_ATTR_ROM Ql_iotDpFormat(quint8_t **buf, quint16_t pId, quint16_t cmd, const quint8_t *payload, quint32_t payloadLen) +{ + quint8_t head[DP_POS_DATA]; + head[DP_POS_VER_1] = DP_VER_HEADER; + head[DP_POS_VER_2] = DP_VER_CURRENT; + _U16_ARRAY01(payloadLen + DP_POS_DATA - DP_POS_SUM, &head[DP_POS_LEN_1]); + _U16_ARRAY01(pId, &head[DP_POS_PID_1]); + _U16_ARRAY01(cmd, &head[DP_POS_CMD_1]); + head[DP_POS_SUM] = (quint8_t)Quos_crcCalculate(0, &head[DP_POS_PID_1], DP_POS_DATA - DP_POS_PID_1); + head[DP_POS_SUM] = (quint8_t)Quos_crcCalculate(head[DP_POS_SUM], payload, payloadLen); + quint32_t escCount = DP_POS_DATA; + quint32_t i; + for (i = DP_POS_VER_2; i < DP_POS_CMD_2; i++) + { + if (DP_VER_HEADER == head[i] && (DP_VER_CURRENT == head[i + 1] || DP_VER_ESC == head[i + 1])) + { + escCount++; + } + } + if (DP_VER_HEADER == head[DP_POS_CMD_2] && (0 == payloadLen || DP_VER_ESC == payload[0])) + { + escCount++; + } + escCount += payloadLen; + if (payloadLen > 0) + { + for (i = 0; i < payloadLen - 1; i++) + { + if (DP_VER_HEADER == payload[i] && (DP_VER_CURRENT == payload[i + 1] || DP_VER_ESC == payload[i + 1])) + { + escCount++; + } + } + if (DP_VER_HEADER == payload[payloadLen - 1]) + { + escCount++; + } + } + + quint8_t *pkgBuf = HAL_MALLOC(escCount); + if (NULL == pkgBuf) + { + return 0; + } + escCount = 0; + pkgBuf[escCount++] = DP_VER_HEADER; + for (i = DP_POS_VER_2; i < DP_POS_CMD_2; i++) + { + pkgBuf[escCount++] = head[i]; + if (DP_VER_HEADER == head[i] && (DP_VER_CURRENT == head[i + 1] || DP_VER_ESC == head[i + 1])) + { + pkgBuf[escCount++] = DP_VER_ESC; + } + } + pkgBuf[escCount++] = head[DP_POS_CMD_2]; + if (DP_VER_HEADER == head[DP_POS_CMD_2] && (0 == payloadLen || DP_VER_ESC == pkgBuf[0])) + { + pkgBuf[escCount++] = DP_VER_ESC; + } + if (payloadLen > 0) + { + for (i = 0; i < payloadLen - 1; i++) + { + pkgBuf[escCount++] = payload[i]; + if (DP_VER_HEADER == payload[i] && (DP_VER_CURRENT == payload[i + 1] || DP_VER_ESC == payload[i + 1])) + { + pkgBuf[escCount++] = DP_VER_ESC; + } + } + pkgBuf[escCount++] = payload[payloadLen - 1]; + if (DP_VER_HEADER == payload[payloadLen - 1]) + { + pkgBuf[escCount++] = DP_VER_ESC; + } + } + *buf = pkgBuf; + Quos_logHexDump(QUEC_DP, LL_DUMP, "send pkg", pkgBuf, escCount); + return escCount; +} +/************************************************************************** +** 功能 @brief : 将DP数据流转成DP结构体 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +QIot_dpPackage_t FUNCTION_ATTR_ROM Ql_iotDpRaw2Package(const quint8_t *buf, quint32_t len) +{ + QIot_dpPackage_t pkg; + pkg.head = _ARRAY01_U16(&buf[DP_POS_VER_1]); + pkg.sum = buf[DP_POS_SUM]; + pkg.pkgId = _ARRAY01_U16(&buf[DP_POS_PID_1]); + pkg.cmd = _ARRAY01_U16(&buf[DP_POS_CMD_1]); + pkg.payloadLen = len - DP_POS_DATA; + if (pkg.payloadLen > 0) + { + pkg.payload = (quint8_t *)&buf[DP_POS_DATA]; + } + else + { + pkg.payload = NULL; + } + + return pkg; +} +/************************************************************************** +** 功能 @brief : 从原始完整数据包中提取协议包,结束后buf内容可能会改变 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotDpRawDataPickup(quint8_t *buf, quint32_t len, QIot_dpPackage_t *pkg) +{ + if (len < DP_POS_DATA || DP_VER_HEADER != buf[0] || DP_VER_CURRENT != buf[1]) + { + return FALSE; + } + quint16_t pkgLen = 0, offset = DP_POS_LEN_1; + quint32_t i; + for (i = offset; i < len; i++) + { + if (DP_VER_HEADER != buf[i - 1] || DP_VER_ESC != buf[i]) + { + buf[offset++] = buf[i]; + } + if (DP_POS_SUM == offset) + { + pkgLen = _ARRAY01_U16(&buf[DP_POS_LEN_1]); + } + else if (pkgLen + DP_POS_SUM == offset) + { + quint16_t pkgId = _ARRAY01_U16(&buf[DP_POS_PID_1]); + if (0x0000 == pkgId || 0xFFFF == pkgId) + { + quint16_t cmd = _ARRAY01_U16(&buf[DP_POS_CMD_1]); + Quos_logPrintf(QUEC_DP, LL_ERR, "pkgid[0x%04X] cmd[0x%04X]", pkgId, cmd); + } + else if ((quint8_t)Quos_crcCalculate(0, buf + DP_POS_PID_1, offset - DP_POS_PID_1) == buf[DP_POS_SUM]) + { + Quos_logHexDump(QUEC_DP, LL_DUMP, "packet", buf, offset); + if (pkg) + { + *pkg = Ql_iotDpRaw2Package(buf, offset); + } + return TRUE; + } + break; + } + } + return FALSE; +} +/************************************************************************** +** 功能 @brief : 检查命令字是否在支持列表 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +QIot_dpCmdHandle_f FUNCTION_ATTR_ROM Ql_iotDpCmdIn(quint16_t cmd, QIot_cmdTable_t table[], quint32_t size) +{ + quint32_t i; + for (i = 0; i < size; i++) + { + if (cmd == table[i].cmd) + { + return table[i].cmdHandle; + } + } + return NULL; +} +/************************************************************************** +** 功能 @brief : 数据接收处理 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Ql_iotDpHandle(QIot_dpAppType_e app, const char *endPoint, quint8_t *payload, quint32_t payloadLen) +{ + Quos_logPrintf(QUEC_DP, LL_DBG, "app:%d ep:%s", app, endPoint); + char clientId[QIOT_M2M_CLIENTID_MAXSIZE + 1]; + HAL_SPRINTF(clientId, "qd%s%s", QIot_userdata.connectProduct->productKey, QIot_userdata.deviceInfo.deviceKey); + QIot_dpCmdHandle_f cmdHandle = NULL; + QIot_dpPackage_t dpPkg; + + if (NULL == payload || FALSE == Ql_iotDpRawDataPickup(payload, payloadLen, &dpPkg)) + { + Quos_logPrintf(QUEC_CONN, LL_ERR, "data pickup fail: %.*s", payloadLen, payload); + return; + } + if (NULL == endPoint || 0 == HAL_STRNCMP(endPoint, clientId, HAL_STRLEN(clientId))) // TODO + { + cmdHandle = Ql_iotDpCmdIn(dpPkg.cmd, QIot_cmdTableLocal, sizeof(QIot_cmdTableLocal) / sizeof(QIot_cmdTableLocal[0])); + } +#ifdef QUEC_ENABLE_LAN + else if (QIOT_DPAPP_LANPHONE == app) + { + cmdHandle = Ql_iotDpCmdIn(dpPkg.cmd, QIot_cmdTableLan, sizeof(QIot_cmdTableLan) / sizeof(QIot_cmdTableLan[0])); + } +#endif +#ifdef QUEC_ENABLE_GATEWAY + else + { + cmdHandle = Ql_iotDpCmdIn(dpPkg.cmd, QIot_cmdTableSubDev, sizeof(QIot_cmdTableSubDev) / sizeof(QIot_cmdTableSubDev[0])); + } +#endif + if (cmdHandle) + { + cmdHandle(app, endPoint, dpPkg.pkgId, dpPkg.payload, dpPkg.payloadLen); + } +} + +/************************************************************************** +** 功能 @brief : 更新pkgid +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +quint16_t FUNCTION_ATTR_ROM Ql_iotDpPkgIdUpdate(quint16_t *pkgId) +{ + (*pkgId)++; + if (0 == (*pkgId) || 0xFFFF == (*pkgId)) + { + *pkgId = 1; + } + return *pkgId; +} + +/************************************************************************** +** 功能 @brief : 发送通用请求数据 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static qbool FUNCTION_ATTR_ROM ql_iotDpSendCommon(QIot_dpAppType_e app, const char *endPoint, quint16_t mode, quint16_t cmd, quint16_t srcPkgId, quint16_t pkgId, const quint8_t *payload, quint32_t payloadLen, socketRecvNodeCb_f recvCB) +{ + UNUSED(srcPkgId); + qbool ret = FALSE; + quint32_t i; + for (i = 0; i < sizeof(QIot_dpAppSend) / sizeof(QIot_dpAppSend[0]); i++) + { + if (app & QIot_dpAppSend[i].app) + { + if ((QIot_dpAppSend[i].send)(endPoint, mode, cmd, srcPkgId, pkgId, payload, payloadLen, recvCB)) + { + ret = TRUE; + } + } + } + return ret; +} +/************************************************************************** +** 功能 @brief : 发送TTLV数据 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static qbool FUNCTION_ATTR_ROM ql_iotDpSendTtlv(QIot_dpAppType_e app, const char *endPoint, quint16_t mode, quint16_t cmd, quint16_t srcPkgId, quint16_t pkgId, const void *ttlvHead, socketRecvNodeCb_f recvCB) +{ + qbool ret = FALSE; + quint32_t len = Ql_iotTtlvFormatLen(ttlvHead); + quint8_t *buf = NULL; + if (len) + { + if ((buf = HAL_MALLOC(len)) == NULL) + { + return FALSE; + } + len = Ql_iotTtlvFormat(ttlvHead, buf); + } + ret = ql_iotDpSendCommon(app, endPoint, mode, cmd, srcPkgId, pkgId, buf, len, recvCB); + if (buf) + { + HAL_FREE(buf); + } + return ret; +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotDpSendCommonReq(QIot_dpAppType_e app, const char *endPoint, quint16_t srcPkgId, quint16_t mode, quint16_t cmd, const quint8_t *payload, quint32_t payloadLen, socketRecvNodeCb_f recvCB) +{ + return ql_iotDpSendCommon(app, endPoint, mode, cmd, srcPkgId, 0, payload, payloadLen, recvCB); +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool Ql_iotDpSendCommonRsp(QIot_dpAppType_e app, const char *endPoint, quint16_t cmd, quint16_t pkgId, const quint8_t *payload, quint32_t payloadLen) +{ + return ql_iotDpSendCommon(app, endPoint, 0, cmd, 0, pkgId, payload, payloadLen, NULL); +} + +/************************************************************************** +** 功能 @brief : 发送TTLV请求数据 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotDpSendTtlvReq(QIot_dpAppType_e app, const char *endPoint, quint16_t srcPkgId, quint16_t mode, quint16_t cmd, const void *ttlvHead, socketRecvNodeCb_f recvCB) +{ + return ql_iotDpSendTtlv(app, endPoint, mode, cmd, srcPkgId, 0, ttlvHead, recvCB); +} +/************************************************************************** +** 功能 @brief : 发送TTLV应答数据 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotDpSendTtlvRsp(QIot_dpAppType_e app, const char *endPoint, quint16_t cmd, quint16_t pkgId, const void *ttlvHead) +{ + return ql_iotDpSendTtlv(app, endPoint, 0, cmd, 0, pkgId, ttlvHead, NULL); +} diff --git a/cloud/common/ql_iotDp.h b/cloud/common/ql_iotDp.h new file mode 100644 index 0000000000000000000000000000000000000000..bc2203c76e42d2ed5268d8f25e79c58a8fc3d0ea --- /dev/null +++ b/cloud/common/ql_iotDp.h @@ -0,0 +1,84 @@ +#ifndef __QUOS_DATA_PACKET_H__ +#define __QUOS_DATA_PACKET_H__ +#include "Ql_iotApi.h" + +enum +{ + QIOT_DPCMD_TSL_REQ = 0X0011, /* 物模型状态获取 */ + QIOT_DPCMD_TSL_RSP = 0X0012, /* 物模型状态上报-回复 */ + QIOT_DPCMD_TSL_WRITE = 0X0013, /* 物模型数据下发 */ + QIOT_DPCMD_TSL_EVENT = 0X0014, /* 物模型数据上报 */ + QIOT_DPCMD_PASS_WRITE = 0X0023, /* 透传数据下发 */ + QIOT_DPCMD_PASS_EVENT = 0X0024, /* 透传数据上发 */ + QIOT_DPCMD_STATUS_REQ = 0X0031, /* 设备状态获取 */ + QIOT_DPCMD_STATUS_RSP = 0X0032, /* 设备状态上报-回复 */ + QIOT_DPCMD_STATUS_EVENT = 0X0034, /* 设备状态上报 */ + QIOT_DPCMD_INFO_REQ = 0X0041, /* 模组信息获取 */ + QIOT_DPCMD_INFO_RSP = 0X0042, /* 模组信息上报-回复 */ + QIOT_DPCMD_INFO_EVENT = 0X0044, /* 模组信息上报 */ + QIOT_DPCMD_EXCE_WRITE = 0X00A3, /* 异常通知 */ + QIOT_DPCMD_EXCE_EVENT = 0X00A4, /* 异常通知 */ + QIOT_DPCMD_DEV_MANAGER_WRITE = 0X00B3, /* 设备管理命令 */ + QIOT_DPCMD_DEV_CONFIG_WRITE = 0X00B4, /* 设备配置命令 */ + QIOT_DPCMD_DEV_BINDCODE_WRITE = 0X00B5, /* 设备上报绑定信息,仅在有局域网通信时有效 */ + QIOT_DPCMD_OTA_NOTIFY = 0X0111, /* OTA升级任务通知 */ + QIOT_DPCMD_OTA_COMFIRM = 0X0112, /* OTA确认-OTA升级任务通知确认是否要升级 */ + QIOT_DPCMD_OTA_FW_INFO = 0X0113, /* 固件信息下发 */ + QIOT_DPCMD_OTA_EVENT = 0X0114, /* OTA过程状态上报 */ + QIOT_DPCMD_OTA_REQUEST = 0X115, /* OTA请求 */ + QIOT_DPCMD_LOC_CFG_WRITE = 0X0121, /* 设置定位信息上报内容,不再支持 */ + QIOT_DPCMD_LOC_REPORT = 0X0122, /* 定位信息上报 */ + QIOT_DPCMD_LOC_REQ = 0X0123, /* 获取实时定位信息 */ + QIOT_DPCMD_LOC_RSP = 0X0124, /* 获取实时定位信息-回复 */ + QIOT_DPCMD_LAN_SEND_ACK = 0X7000, /* 应答局域网通信的请求包,相当于mqtt puback */ + QIOT_DPCMD_LAN_DISCOVER_REQ = 0X7001, /* 发现局域网下设备 */ + QIOT_DPCMD_LAN_DISCOVER_RSP = 0X7002, /* 应答发现局域网下设备 */ + QIOT_DPCMD_LAN_AUTH_COND_REQ = 0X7003, /* 局域网认证前置条件请求 */ + QIOT_DPCMD_LAN_AUTH_COND_RSP = 0X7004, /* 局域网认证前置条件应答 */ + QIOT_DPCMD_LAN_AUTH_SIGN_REQ = 0X7005, /* 局域网认证签名请求 */ + QIOT_DPCMD_LAN_AUTH_SIGN_RSP = 0X7006, /* 局域网认证签名应答 */ + QIOT_DPCMD_SUB_AUTH = 0x00C0, /* 子设备认证指令 */ + QIOT_DPCMD_SUB_AUTH_RSP = 0x00C1, /* 子设备认证回复 */ + QIOT_DPCMD_SUB_LOGIN = 0x00C2, /* 子设备登陆指令 */ + QIOT_DPCMD_SUB_LOGIN_RSP = 0x00C3, /* 子设备登陆返回 */ + QIOT_DPCMD_SUB_LOGOUT = 0x00C4, /* 子设备登出 */ + QIOT_DPCMD_SUB_LOGOUT_RSP = 0x00C5, /* 子设备登出回复 */ + QIOT_DPCMD_SUB_UNAUTH_EVENT = 0x00C6, /* 子设备注销 */ + QIOT_DPCMD_SUB_UNAUTH_EVENT_RSP = 0x00C7, /* 子设备注销返回 */ + QIOT_DPCMD_SUB_OFFLINE_EVENT = 0x00C8, /* 子设备下线通知 */ +}; + +typedef struct +{ + quint16_t head; + quint8_t sum; + quint16_t pkgId; + quint16_t cmd; + quint16_t payloadLen; + quint8_t *payload; +} QIot_dpPackage_t; + +typedef qbool (*QIot_dpAppSend_ftemp)(const char *endPoint, QIot_dpPackage_t dpPkg, socketRecvNodeCb_f recvCB); +typedef qbool (*QIot_dpAppSend_f)(const char *endPoint, quint16_t mode, quint16_t cmd, quint16_t srcpkgId, quint16_t pkgId, const quint8_t *payload, quint32_t payloadLen, socketRecvNodeCb_f recvCB); +typedef struct +{ + QIot_dpAppType_e app; + QIot_dpAppSend_f send; +} QIot_dpAppSend_t; + +typedef void (*QIot_dpCmdHandle_f)(QIot_dpAppType_e app, const char *endPoint, quint16_t pkgId, quint8_t *payload, quint16_t payloadLen); +typedef struct +{ + quint16_t cmd; + QIot_dpCmdHandle_f cmdHandle; +} QIot_cmdTable_t; + +quint32_t Ql_iotDpFormat(quint8_t **buf, quint16_t pId, quint16_t cmd, const quint8_t *payload, quint32_t payloadLen); +quint16_t Ql_iotDpPkgIdUpdate(quint16_t *pkgId); +qbool Ql_iotDpRawDataPickup(quint8_t *buf, quint32_t len, QIot_dpPackage_t *pkg); +void Ql_iotDpHandle(QIot_dpAppType_e app, const char *endPoint, quint8_t *payload, quint32_t payloadLen); +qbool Ql_iotDpSendCommonReq(QIot_dpAppType_e app, const char *endPoint, quint16_t srcPkgId, quint16_t mode, quint16_t cmd, const quint8_t *payload, quint32_t payloadLen, socketRecvNodeCb_f recvCB); +qbool Ql_iotDpSendCommonRsp(QIot_dpAppType_e app, const char *endPoint, quint16_t cmd, quint16_t pkgId, const quint8_t *payload, quint32_t payloadLen); +qbool Ql_iotDpSendTtlvReq(QIot_dpAppType_e app, const char *endPoint, quint16_t srcPkgId, quint16_t mode, quint16_t cmd, const void *ttlvHead, socketRecvNodeCb_f recvCB); +qbool Ql_iotDpSendTtlvRsp(QIot_dpAppType_e app, const char *endPoint, quint16_t cmd, quint16_t pkgId, const void *ttlvHead); +#endif diff --git a/cloud/common/ql_iotSecure.c b/cloud/common/ql_iotSecure.c new file mode 100644 index 0000000000000000000000000000000000000000..217aded557931c78cc983569847b608357247f2a --- /dev/null +++ b/cloud/common/ql_iotSecure.c @@ -0,0 +1,312 @@ +/************************************************************************* +** 鍒涘缓浜 @author : 鍚村仴瓒 JCWu +** 鐗堟湰 @version : V1.0.0 鍘熷鐗堟湰 +** 鏃ユ湡 @date : 2020-12-25 +** 鍔熻兘 @brief : dmp瀹夊叏绠楁硶 +** 纭欢 @hardware锛 +** 鍏朵粬 @other 锛 +***************************************************************************/ +#include "ql_iotSecure.h" +#include "ql_iotConfig.h" +#include "Qhal_driver.h" + +#define QIOT_MQTT_AUTH_VERSION "3" +#define QIOT_COAP_AUTH_VERSION "2" + +/************************************************************************** +** 鍔熻兘 @brief : 鑾峰彇璁よ瘉鍗忚鐗堟湰鍙 +** 杈撳叆 @param : +** 杈撳嚭 @retval: +***************************************************************************/ +char FUNCTION_ATTR_ROM *Ql_iotSecureVerGet(void) +{ + return QIOT_MQTT_AUTH_VERSION; +} +/************************************************************************** +** 鍔熻兘 @brief : 鐢熸垚鎺ュ叆鐨勭鍚 +** 杈撳叆 @param : +** 杈撳嚭 @retval: 杩斿洖鍊奸渶瑕佸閮‵REE鍐呭瓨 +***************************************************************************/ +char FUNCTION_ATTR_ROM *ql_iotSecureGenConnSign(const char *ps, const char *ds, const char *random) +{ + /* 鍒嗛厤鏈澶uffer */ + quint32_t maxLen = HAL_STRLEN(ds) + 1 + HAL_STRLEN(ps) + 1 + HAL_STRLEN(random) + 1; + maxLen = __GET_MAX(maxLen, QUOS_BASE64_DSTDATA_LEN(QUOS_SHA256_DIGEST_LENGTH)); + Quos_logPrintf(QUEC_SECURE, LL_DBG, "keystr maxLen:%d", maxLen); + char *bodyStr = HAL_MALLOC(maxLen); + if (NULL == bodyStr) + { + Quos_logPrintf(QUEC_SECURE, LL_ERR, "mcf bodyStr fail"); + return NULL; + } + /* 绗竴姝ワ細璁惧绛惧悕 SIGN = BASE64(SHA256(DS;PS;RAND)) */ + /* DS;PS;RAND */ + HAL_SPRINTF(bodyStr, "%s;%s;%s", ds, ps, random); + Quos_logPrintf(QUEC_SECURE, LL_DBG, "bodyStr:[%ld]%s", HAL_STRLEN(bodyStr), bodyStr); + + /* SHA256(DS;PS;RAND) */ + SHA256_ctx_t sha256_ctx; + quint8_t sha256Data[QUOS_SHA256_DIGEST_LENGTH]; + Quos_sha256init(&sha256_ctx); + Quos_sha256update(&sha256_ctx, (const quint8_t *)bodyStr, HAL_STRLEN(bodyStr)); + Quos_sha256finish(&sha256_ctx, sha256Data); + Quos_logHexDump(QUEC_SECURE, LL_DBG, "sha256Data", sha256Data, QUOS_SHA256_DIGEST_LENGTH); + + /* BASE64(SHA256(DS;PS;RAND)) */ + Quos_base64Encrypt(sha256Data, QUOS_SHA256_DIGEST_LENGTH, (quint8_t *)bodyStr); + Quos_logPrintf(QUEC_SECURE, LL_DBG, "Sign:[%ld]%s", HAL_STRLEN(bodyStr), bodyStr); + return bodyStr; +} +/************************************************************************** +** 鍔熻兘 @brief : 鐢熸垚璁惧璁よ瘉瀵嗛挜 +** 杈撳叆 @param : +** 杈撳嚭 @retval: +***************************************************************************/ +char FUNCTION_ATTR_ROM *ql_iotSecureGenAuthKey(const char *pk, const char *ps, const char *dk, const char *random) +{ + UNUSED(pk); + quint32_t maxLen = HAL_STRLEN(dk) + 1 + __GET_MAX(HAL_STRLEN(ps), QUOS_BASE64_DSTDATA_LEN(QUOS_SHA256_DIGEST_LENGTH)) + 1 + HAL_STRLEN(random) + 1; + maxLen = __BYTE_TO_ALIGN(maxLen + 1, QUOS_AES_BLOCKLEN); + maxLen = QUOS_BASE64_DSTDATA_LEN(maxLen); + Quos_logPrintf(QUEC_SECURE, LL_DBG, "keystr maxLen:%d", maxLen); + char *bodyStr = HAL_MALLOC(maxLen); + if (NULL == bodyStr) + { + Quos_logPrintf(QUEC_SECURE, LL_ERR, "mcf bodyStr fail"); + return NULL; + } + + /* 绗竴姝ワ細璁惧绛惧悕 SIGN = BASE64(SHA256(DK;PS;RAND)) */ + /* DK;PS;RAND */ + HAL_SPRINTF(bodyStr, "%s;%s;%s", dk, ps, random); + Quos_logPrintf(QUEC_SECURE, LL_DBG, "bodyStr:[%ld]%s", HAL_STRLEN(bodyStr), bodyStr); + /* SHA256(DK;PS;RAND) */ + SHA256_ctx_t sha256_ctx; + quint8_t sha256Data[QUOS_SHA256_DIGEST_LENGTH]; + Quos_sha256init(&sha256_ctx); + Quos_sha256update(&sha256_ctx, (const quint8_t *)bodyStr, HAL_STRLEN(bodyStr)); + Quos_sha256finish(&sha256_ctx, sha256Data); + Quos_logHexDump(QUEC_SECURE, LL_DBG, "sha256Data", sha256Data, QUOS_SHA256_DIGEST_LENGTH); + + HAL_SPRINTF(bodyStr, "%s;%s;", dk, random); + /* BASE64(SHA256(DK;PS;RAND)) */ + Quos_base64Encrypt(sha256Data, QUOS_SHA256_DIGEST_LENGTH, (quint8_t *)bodyStr + HAL_STRLEN(bodyStr)); + Quos_logPrintf(QUEC_SECURE, LL_DBG, "aes srcData:[%ld]%s", HAL_STRLEN(bodyStr), bodyStr); + + /* 绗簩姝ワ紝瀵笵ATA璇锋眰浣撹繘琛孉ES绠楁硶鍔犲瘑鐒跺悗杩涜BASE64缂栫爜 BASE64锛圓ES(PS,DATA璇锋眰浣)锛 */ + /* PS浣跨敤SHA256鍔犲瘑锛岀敓鎴32瀛楄妭鐨勬暟鎹,iv鍋忕Щ閲忎负sha256(ps)鐨勫乏杈16Byte */ + Quos_sha256init(&sha256_ctx); + Quos_sha256update(&sha256_ctx, (const quint8_t *)ps, HAL_STRLEN(ps)); + Quos_sha256finish(&sha256_ctx, sha256Data); + + maxLen = HAL_STRLEN(bodyStr); + AES_ctx_t aes_ctx; + Quos_logHexDump(QUEC_SECURE, LL_DBG, "IV", sha256Data, QUOS_SHA256_DIGEST_LENGTH); + Quos_aesInitCtxIv(&aes_ctx, (const char *)ps, (const char *)sha256Data); + Quos_aesPadding((quint8_t *)bodyStr, (quint8_t *)bodyStr, maxLen); + maxLen = Quos_aesCbcEncrypt(&aes_ctx, bodyStr, __BYTE_TO_ALIGN(maxLen + 1, QUOS_AES_BLOCKLEN)); + Quos_logHexDump(QUEC_SECURE, LL_DBG, "aes dstdata", bodyStr, maxLen); + + /* BASE64锛圓ES(PS,DATA璇锋眰浣)锛 */ + quint32_t offset = QUOS_BASE64_DSTDATA_LEN(maxLen) - maxLen; + HAL_MEMMOVE(bodyStr + offset, bodyStr, maxLen); + Quos_logPrintf(QUEC_SECURE, LL_DBG, "offset:%d", offset); + Quos_base64Encrypt((quint8_t *)bodyStr + offset, maxLen, (quint8_t *)bodyStr); + Quos_logPrintf(QUEC_SECURE, LL_DBG, "bodyStr:[%ld]%s", HAL_STRLEN(bodyStr), bodyStr); + return bodyStr; +} +/************************************************************************** +** 鍔熻兘 @brief : 鐢熸垚MQTT璁惧杩炴帴password +** 杈撳叆 @param : +** 杈撳嚭 @retval: 杩斿洖鍊奸渶瑕佸閮‵REE鍐呭瓨 +***************************************************************************/ +char FUNCTION_ATTR_ROM *Ql_iotSecureGenMqttConnData(const char *ps, const char *ds) +{ + char random[16 + 1]; + HAL_MEMSET(random, 0, sizeof(random)); + Quos_RandomGen((quint8_t *)random, sizeof(random) - 1); + char *sign = ql_iotSecureGenConnSign(ps, ds, random); + if (sign) + { + char *passWord = HAL_MALLOC(1 + 1 + 4 + 1 + HAL_STRLEN(random) + 1 + HAL_STRLEN(sign) + 1); + if (passWord) + { + /* 鎷兼帴passWord */ + HAL_SPRINTF((char *)passWord, "1;%04d;%s;%s", Ql_iotConfigGetSessionFlag(), random, sign); + } + HAL_FREE(sign); + Quos_logPrintf(QUEC_SECURE, LL_DBG, "passWord:%s", passWord); + return passWord; + } + return NULL; +} +/************************************************************************** +** 鍔熻兘 @brief : 鐢熸垚MQTT璁惧璁よ瘉password +** 杈撳叆 @param : +** 杈撳嚭 @retval: 杩斿洖鍊奸渶瑕佸閮‵REE鍐呭瓨 +***************************************************************************/ +char FUNCTION_ATTR_ROM *Ql_iotSecureGenMqttAuthData(const char *pk, const char *ps, const char *dk) +{ + char random[16 + 1]; + HAL_MEMSET(random, 0, sizeof(random)); + Quos_RandomGen((quint8_t *)random, sizeof(random) - 1); + char *bodyStr = ql_iotSecureGenAuthKey(pk, ps, dk, random); + if (bodyStr) + { + char *passWord = HAL_MALLOC(1 + 1 + 4 + 1 + HAL_STRLEN(pk) + 1 + HAL_STRLEN(bodyStr) + 1); + if (passWord) + { + /* 鎷兼帴passWord */ + HAL_SPRINTF((char *)passWord, "0;%04d;%s;%s", Ql_iotConfigGetSessionFlag(), pk, bodyStr); + } + HAL_FREE(bodyStr); + Quos_logPrintf(QUEC_SECURE, LL_DBG, "passWord:[%ld]%s",HAL_STRLEN(passWord), passWord); + return passWord; + } + return NULL; +} +/************************************************************************** +** 鍔熻兘 @brief : 鐢熸垚COAP璁惧杩炴帴password +** 杈撳叆 @param : +** 杈撳嚭 @retval: 杩斿洖鍊奸渶瑕佸閮‵REE鍐呭瓨 +***************************************************************************/ +char FUNCTION_ATTR_ROM *Ql_iotSecureGenCoapConnEndpoint(const char *pk, const char *ps, const char *dk, const char *ds) +{ + char random[16 + 1]; + HAL_MEMSET(random, 0, sizeof(random)); + Quos_RandomGen((quint8_t *)random, sizeof(random) - 1); + char *sign = ql_iotSecureGenConnSign(ps, ds, random); + if (sign) + { + char *passWord = HAL_MALLOC(HAL_STRLEN(pk) + 1 + HAL_STRLEN(dk) + 1 + HAL_STRLEN(random) + 1 + HAL_STRLEN(sign) + 1 + HAL_STRLEN(QIOT_COAP_AUTH_VERSION) + 1); + if (passWord) + { + /* 鎷兼帴passWord */ + HAL_SPRINTF((char *)passWord, "%s;%s;%s;%s;%s", pk, dk, random, sign, QIOT_COAP_AUTH_VERSION); + } + HAL_FREE(sign); + Quos_logPrintf(QUEC_SECURE, LL_DBG, "passWord:%s", passWord); + return passWord; + } + return NULL; +} +/************************************************************************** +** 鍔熻兘 @brief : 鐢熸垚coap璁惧璁よ瘉password +** 杈撳叆 @param : +** 杈撳嚭 @retval: 杩斿洖鍊奸渶瑕佸閮‵REE鍐呭瓨 +***************************************************************************/ +char FUNCTION_ATTR_ROM *Ql_iotSecureGenCoapAuthPayload(const char *pk, const char *ps, const char *dk) +{ + char random[16 + 1]; + HAL_MEMSET(random, 0, sizeof(random)); + Quos_RandomGen((quint8_t *)random, sizeof(random) - 1); + char *bodyStr = ql_iotSecureGenAuthKey(pk, ps, dk, random); + if (bodyStr) + { + char *passWord = HAL_MALLOC(HAL_STRLEN(pk) + 1 + HAL_STRLEN(bodyStr) + 1 + HAL_STRLEN(QIOT_COAP_AUTH_VERSION) + 1); + if (passWord) + { + /* 鎷兼帴passWord */ + HAL_SPRINTF((char *)passWord, "%s;%s;%s", pk, bodyStr, QIOT_COAP_AUTH_VERSION); + } + HAL_FREE(bodyStr); + Quos_logPrintf(QUEC_SECURE, LL_DBG, "passWord:%s", passWord); + return passWord; + } + return NULL; +} +/************************************************************************** +** 鍔熻兘 @brief : ds瑙e瘑鎻愬彇 +** 杈撳叆 @param : +** 杈撳嚭 @retval: 杩斿洖鍊奸渶瑕佸閮‵REE鍐呭瓨 +***************************************************************************/ +char FUNCTION_ATTR_ROM *Ql_iotSecureDecodeDs(const char *ps, const quint8_t *encryData, quint32_t len) +{ + quint8_t *ds = HAL_MALLOC(len + 1); + if (NULL == ds) + { + return NULL; + } + len = Quos_base64Decrypt(encryData, len, ds); + if (len % QUOS_AES_BLOCKLEN != 0) + { + HAL_FREE(ds); + return NULL; + } + quint8_t sha256Data[QUOS_SHA256_DIGEST_LENGTH]; + SHA256_ctx_t sha256_ctx; + Quos_sha256init(&sha256_ctx); + Quos_sha256update(&sha256_ctx, (const quint8_t *)ps, HAL_STRLEN(ps)); + Quos_sha256finish(&sha256_ctx, sha256Data); + + AES_ctx_t aes_ctx; + Quos_aesInitCtxIv(&aes_ctx, (const char *)ps, (const char *)sha256Data); + Quos_aesCbcDecrypt(&aes_ctx, ds, len); + len = Quos_aesPaddingBack(ds, len); + ds[len] = 0; + return (char *)ds; +} +char FUNCTION_ATTR_ROM *Ql_iotSecureDecodeSessionKey(const char *ds, const quint8_t *encryData, quint32_t len) +{ + if (len % QUOS_AES_BLOCKLEN != 0) + { + return NULL; + } + quint8_t *sessionKey = HAL_MALLOC(len + 1); + if (NULL == sessionKey) + { + return NULL; + } + + HAL_MEMCPY(sessionKey, encryData, len); + + quint8_t sha256Data[QUOS_SHA256_DIGEST_LENGTH]; + SHA256_ctx_t sha256_ctx; + Quos_sha256init(&sha256_ctx); + Quos_sha256update(&sha256_ctx, (const quint8_t *)ds, HAL_STRLEN(ds)); + Quos_sha256finish(&sha256_ctx, sha256Data); + AES_ctx_t aes_ctx; + Quos_aesInitCtxIv(&aes_ctx, (const char *)ds, (const char *)sha256Data); + Quos_aesCbcDecrypt(&aes_ctx, sessionKey, len); + len = Quos_aesPaddingBack(sessionKey, len); + sessionKey[len] = 0; + return (char *)sessionKey; +} +/************************************************************************** +** 鍔熻兘 @brief : 涓婅鏁版嵁鍔犲瘑 +** 杈撳叆 @param : +** 杈撳嚭 @retval: +***************************************************************************/ +quint32_t FUNCTION_ATTR_ROM Ql_iotSecureEncryptPayload(quint8_t *data, quint32_t len, uint8_t **outData, const char *key, const char *iv) +{ + /* 涓婁笅琛屾秷鎭殑鏃跺欙紝濡傛灉寮鍚痵essionkey鐨勮瘽锛岄渶瑕佺敤sessionkey浣滀负key鍋歛es鍔犲瘑锛岄偅涔坰essionkey鐨剆ha256宸﹁竟16浣嶅氨鏄痠v鍋忕Щ閲 */ + AES_ctx_t aes_ctx; + Quos_aesInitCtxIv(&aes_ctx, key, iv); + quint32_t encryptLen = __BYTE_TO_ALIGN(len + 1, QUOS_AES_BLOCKLEN); + *outData = HAL_MALLOC(encryptLen); + if (*outData) + { + Quos_aesPadding((quint8_t *)*outData, (quint8_t *)data, len); + Quos_aesCbcEncrypt(&aes_ctx, (void *)*outData, encryptLen); + } + return encryptLen; +} + +/************************************************************************** +** 鍔熻兘 @brief : 涓嬭鏁版嵁瑙e瘑 +** 杈撳叆 @param : +** 杈撳嚭 @retval: +***************************************************************************/ +quint32_t FUNCTION_ATTR_ROM Ql_iotSecureDecryptPayload(quint8_t *data, quint32_t len, const char *key, const char *iv) +{ + if (len % QUOS_AES_BLOCKLEN != 0) + { + return 0; + } + /* 涓婁笅琛屾秷鎭殑鏃跺欙紝濡傛灉寮鍚痵essionkey鐨勮瘽锛岄渶瑕佺敤sessionkey浣滀负key鍋歛es鍔犲瘑锛岄偅涔坰essionkey鐨剆ha256宸﹁竟16浣嶅氨鏄痠v鍋忕Щ閲 */ + AES_ctx_t aes_ctx; + Quos_aesInitCtxIv(&aes_ctx, key, iv); + Quos_aesCbcDecrypt(&aes_ctx, (void *)data, len); + len = Quos_aesPaddingBack(data, len); + return len; +} \ No newline at end of file diff --git a/cloud/common/ql_iotSecure.h b/cloud/common/ql_iotSecure.h new file mode 100644 index 0000000000000000000000000000000000000000..caf8ac88a0c60924cfc378e82e1710c567ed5c66 --- /dev/null +++ b/cloud/common/ql_iotSecure.h @@ -0,0 +1,17 @@ +#ifndef __QIOT_SECURE_H__ +#define __QIOT_SECURE_H__ +#include "Ql_iotApi.h" + +char *Ql_iotSecureVerGet(void); +char *Ql_iotSecureGenMqttConnData(const char *ps, const char *ds); +char *Ql_iotSecureGenMqttAuthData(const char *pk, const char *ps, const char *dk); +char *Ql_iotSecureGenCoapConnEndpoint(const char *pk, const char *ps, const char *dk, const char *ds); +char *Ql_iotSecureGenCoapAuthPayload(const char *pk, const char *ps, const char *dk); +char *Ql_iotSecureDecodeDs(const char *ps, const quint8_t *encryData, quint32_t len); +quint32_t Ql_iotSecureEncryptPayload(quint8_t *data, quint32_t len, uint8_t **outData, const char *key, const char *iv); +quint32_t Ql_iotSecureDecryptPayload(quint8_t *data, quint32_t len, const char *key, const char *iv); +char *ql_iotSecureGenAuthKey(const char *pk, const char *ps, const char *dk, const char *random); +char *ql_iotSecureGenConnSign(const char *ps, const char *ds, const char *random); + +char *Ql_iotSecureDecodeSessionKey(const char *ds, const quint8_t *encryData, quint32_t len); +#endif \ No newline at end of file diff --git a/cloud/common/ql_iotTtlv.c b/cloud/common/ql_iotTtlv.c new file mode 100644 index 0000000000000000000000000000000000000000..59ce5943e366fe43d32ece8cee4cc1436c53d7c0 --- /dev/null +++ b/cloud/common/ql_iotTtlv.c @@ -0,0 +1,962 @@ +/************************************************************************* +** 创建人 @author : 吴健超 JCWu +** 版本 @version : V1.0.0 原始版本 +** 日期 @date : +** 功能 @brief : +** 硬件 @hardware: +** 其他 @other : +***************************************************************************/ +#include "ql_iotTtlv.h" + +#define QUEC_TTLV LL_DBG +/* 数据类型 */ +enum +{ + DP_TTLV_TYPE_BOOL_FALSE = 0, /* 布尔值false */ + DP_TTLV_TYPE_BOOL_TRUE, /* 布尔值true */ + DP_TTLV_TYPE_ENUM_NUM, /* 枚举和数值 */ + DP_TTLV_TYPE_BYTE, /* 二进制数据 */ + DP_TTLV_TYPE_STRUCT, /* 结构体 */ +}; + +typedef struct +{ + TWLLHead_T head; + quint16_t id; + QIot_dpDataType_e type; + union + { + qbool vbool; + double floatNum; + qint64_t intNum; + struct + { + quint8_t *val; + quint16_t len; + } vbytes; + void *vstructHead; + } value; +} QIot_ttlv_t; + +/************************************************************************** +** 功能 @brief : 释放TTLV节点值内存 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void FUNCTION_ATTR_ROM ql_iotTtlvFreeNodeValue(QIot_ttlv_t node) +{ + if (QIOT_DPDATA_TYPE_BYTE == node.type) + { + HAL_FREE(node.value.vbytes.val); + } + else if (QIOT_DPDATA_TYPE_STRUCT == node.type) + { + Ql_iotTtlvFree(&node.value.vstructHead); + } +} +/************************************************************************** +** 功能 @brief : 释放TTLV链表内存 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Ql_iotTtlvFree(void **ttlvHead) +{ + TWLLHead_T *temp, *next; + TWLIST_FOR_DATA((*(TWLLHead_T **)ttlvHead), temp, next) + { + QIot_ttlv_t *node = __GET_STRUCT_BY_ELEMENT(temp, QIot_ttlv_t, head); + Quos_twllHeadDelete((TWLLHead_T **)ttlvHead, &node->head); + ql_iotTtlvFreeNodeValue(*node); + HAL_FREE(node); + } + *ttlvHead = NULL; +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +quint32_t FUNCTION_ATTR_ROM Ql_iotTtlvCountGet(const void *ttlvHead) +{ + return Quos_twllHeadGetNodeCount((TWLLHead_T *)ttlvHead); +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM *Ql_iotTtlvNodeGet(const void *ttlvHead, quint16_t index, quint16_t *id, QIot_dpDataType_e *type) +{ + TWLLHead_T *temp, *next; + TWLIST_FOR_DATA((TWLLHead_T *)ttlvHead, temp, next) + { + if (0 == index) + { + QIot_ttlv_t *node = __GET_STRUCT_BY_ELEMENT(temp, QIot_ttlv_t, head); + if (id) + { + *id = node->id; + } + if (type) + { + *type = node->type; + } + return &node->head; + } + index--; + } + return NULL; +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotTtlvNodeGetBool(const void *ttlvNode, qbool *value) +{ + if (NULL == ttlvNode) + { + return FALSE; + } + QIot_ttlv_t *node = __GET_STRUCT_BY_ELEMENT((TWLLHead_T *)ttlvNode, QIot_ttlv_t, head); + if (value && QIOT_DPDATA_TYPE_BOOL == node->type) + { + *value = node->value.vbool; + return TRUE; + } + return FALSE; +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotTtlvNodeGetInt(const void *ttlvNode, qint64_t *value) +{ + if (NULL == ttlvNode) + { + return FALSE; + } + QIot_ttlv_t *node = __GET_STRUCT_BY_ELEMENT((TWLLHead_T *)ttlvNode, QIot_ttlv_t, head); + if (value && QIOT_DPDATA_TYPE_INT == node->type) + { + *value = (int)node->value.intNum; + return TRUE; + } + return FALSE; +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotTtlvNodeGetFloat(const void *ttlvNode, double *value) +{ + if (NULL == ttlvNode) + { + return FALSE; + } + QIot_ttlv_t *node = __GET_STRUCT_BY_ELEMENT((TWLLHead_T *)ttlvNode, QIot_ttlv_t, head); + if (value && QIOT_DPDATA_TYPE_FLOAT == node->type) + { + *value = node->value.floatNum; + return TRUE; + } + return FALSE; +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +char FUNCTION_ATTR_ROM *Ql_iotTtlvNodeGetString(const void *ttlvNode) +{ + if (NULL == ttlvNode) + { + return NULL; + } + QIot_ttlv_t *node = __GET_STRUCT_BY_ELEMENT((TWLLHead_T *)ttlvNode, QIot_ttlv_t, head); + if (QIOT_DPDATA_TYPE_BYTE == node->type && node->value.vbytes.val && HAL_STRLEN(node->value.vbytes.val)) + { + return (char *)node->value.vbytes.val; + } + return NULL; +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +quint32_t FUNCTION_ATTR_ROM Ql_iotTtlvNodeGetByte(const void *ttlvNode, quint8_t **value) +{ + if (NULL == ttlvNode) + { + return FALSE; + } + QIot_ttlv_t *node = __GET_STRUCT_BY_ELEMENT((TWLLHead_T *)ttlvNode, QIot_ttlv_t, head); + if (value && QIOT_DPDATA_TYPE_BYTE == node->type) + { + *value = node->value.vbytes.val; + return node->value.vbytes.len; + } + return FALSE; +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM *Ql_iotTtlvNodeGetStruct(const void *ttlvNode) +{ + if (NULL == ttlvNode) + { + return NULL; + } + QIot_ttlv_t *node = __GET_STRUCT_BY_ELEMENT((TWLLHead_T *)ttlvNode, QIot_ttlv_t, head); + if (QIOT_DPDATA_TYPE_STRUCT == node->type) + { + return node->value.vstructHead; + } + return NULL; +} +/************************************************************************** +** 功能 @brief : 根据ID查找TTLV节点 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static QIot_ttlv_t FUNCTION_ATTR_ROM *ql_iotTtlvValIdGet(const void *ttlvHead, quint16_t id) +{ + if (0 == id) + { + return NULL; + } + TWLLHead_T *temp, *next; + TWLIST_FOR_DATA((TWLLHead_T *)ttlvHead, temp, next) + { + QIot_ttlv_t *node = __GET_STRUCT_BY_ELEMENT(temp, QIot_ttlv_t, head); + if (id == node->id) + { + return node; + } + } + return NULL; +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotTtlvIdGetBool(const void *ttlvHead, quint16_t id, qbool *value) +{ + QIot_ttlv_t *node = ql_iotTtlvValIdGet(ttlvHead, id); + return node ? Ql_iotTtlvNodeGetBool(&node->head, value) : FALSE; +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotTtlvIdGetInt(const void *ttlvHead, quint16_t id, qint64_t *value) +{ + QIot_ttlv_t *node = ql_iotTtlvValIdGet(ttlvHead, id); + return node ? Ql_iotTtlvNodeGetInt(&node->head, value) : FALSE; +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotTtlvIdGetFloat(const void *ttlvHead, quint16_t id, double *value) +{ + QIot_ttlv_t *node = ql_iotTtlvValIdGet(ttlvHead, id); + return node ? Ql_iotTtlvNodeGetFloat(&node->head, value) : FALSE; +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +char FUNCTION_ATTR_ROM *Ql_iotTtlvIdGetString(const void *ttlvHead, quint16_t id) +{ + QIot_ttlv_t *node = ql_iotTtlvValIdGet(ttlvHead, id); + return node ? Ql_iotTtlvNodeGetString(&node->head) : NULL; +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +quint32_t FUNCTION_ATTR_ROM Ql_iotTtlvIdGetByte(const void *ttlvHead, quint16_t id, quint8_t **value) +{ + QIot_ttlv_t *node = ql_iotTtlvValIdGet(ttlvHead, id); + return node ? Ql_iotTtlvNodeGetByte(&node->head, value) : 0; +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM *Ql_iotTtlvIdGetStruct(const void *ttlvHead, quint16_t id) +{ + QIot_ttlv_t *node = ql_iotTtlvValIdGet(ttlvHead, id); + return node ? Ql_iotTtlvNodeGetStruct(&node->head) : NULL; +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static QIot_ttlv_t FUNCTION_ATTR_ROM *ql_iotTtlvGetNew(void **ttlvHead, quint16_t id, QIot_dpDataType_e type) +{ + QIot_ttlv_t *node = NULL; + if (0 == id || (node = ql_iotTtlvValIdGet(*ttlvHead, id)) == NULL) + { + node = HAL_MALLOC(sizeof(QIot_ttlv_t)); + if (NULL == node) + { + return NULL; + } + HAL_MEMSET(node, 0, sizeof(QIot_ttlv_t)); + node->id = id; + Quos_twllHeadAdd((TWLLHead_T **)ttlvHead, &node->head); + } + ql_iotTtlvFreeNodeValue(*node); + node->type = type; + return node; +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotTtlvIdAddBool(void **ttlvHead, quint16_t id, qbool value) +{ + QIot_ttlv_t *node = ql_iotTtlvGetNew(ttlvHead, id, QIOT_DPDATA_TYPE_BOOL); + if (NULL == node) + { + return FALSE; + } + node->value.vbool = value; + return TRUE; +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotTtlvIdAddInt(void **ttlvHead, quint16_t id, qint64_t value) +{ + QIot_ttlv_t *node = ql_iotTtlvGetNew(ttlvHead, id, QIOT_DPDATA_TYPE_INT); + if (NULL == node) + { + return FALSE; + } + node->value.intNum = value; + return TRUE; +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotTtlvIdAddFloat(void **ttlvHead, quint16_t id, double value) +{ + QIot_ttlv_t *node = ql_iotTtlvGetNew(ttlvHead, id, QIOT_DPDATA_TYPE_FLOAT); + if (NULL == node) + { + return FALSE; + } + node->value.floatNum = value; + return TRUE; +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotTtlvIdAddByte(void **ttlvHead, quint16_t id, const quint8_t *data, quint32_t len) +{ + quint8_t *temp = HAL_MALLOC(len + 1); /* 预留1byte,在字符串类型时存储结束符 */ + if (NULL == temp) + { + return FALSE; + } + QIot_ttlv_t *node = ql_iotTtlvGetNew(ttlvHead, id, QIOT_DPDATA_TYPE_BYTE); + if (NULL == node) + { + return FALSE; + } + HAL_MEMCPY(temp, data, len); + temp[len] = 0; + node->value.vbytes.val = temp; + node->value.vbytes.len = len; + return TRUE; +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool Ql_iotTtlvIdAddString(void **ttlvHead, quint16_t id, const char *data) +{ + return Ql_iotTtlvIdAddByte(ttlvHead, id, (const quint8_t *)data, HAL_STRLEN(data)); +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Ql_iotTtlvIdAddStruct(void **ttlvHead, quint16_t id, void *vStruct) +{ + QIot_ttlv_t *node = ql_iotTtlvGetNew(ttlvHead, id, QIOT_DPDATA_TYPE_STRUCT); + if (NULL == node) + { + return FALSE; + } + node->value.vstructHead = vStruct; + return TRUE; +} +/************************************************************************** +** 功能 @brief : 判断TTLV链表是否是数组结构体 +** 输入 @param : +** 输出 @retval: FALSE:链表错误 +***************************************************************************/ +static qbool FUNCTION_ATTR_ROM ql_iotTtlvIsStructArray(const void *ttlvHead, qbool *isArray) +{ + quint32_t arraySize = 0; + if (isArray) + { + *isArray = FALSE; + } + TWLLHead_T *temp, *next; + TWLIST_FOR_DATA((TWLLHead_T *)ttlvHead, temp, next) + { + QIot_ttlv_t *node = __GET_STRUCT_BY_ELEMENT(temp, QIot_ttlv_t, head); + if (0 == node->id) + { + if (isArray) + { + *isArray = TRUE; + } + arraySize++; + } + else if (arraySize) + { + return FALSE; + } + } + return TRUE; +} +/************************************************************************** +** 功能 @brief : 提取第一个TTLV +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static quint32_t FUNCTION_ATTR_ROM ql_iotTtlvUnformatFirst(const quint8_t *buffer, quint32_t len, QIot_ttlv_t *node) +{ + if (len < 2) + { + return 0; + } + HAL_MEMSET(node, 0, sizeof(QIot_ttlv_t)); + node->id = _ARRAY01_U16(&buffer[0]); + quint8_t ttlvtype = node->id & 0x07; + node->id >>= 3; + switch (ttlvtype) + { + case DP_TTLV_TYPE_BOOL_FALSE: + case DP_TTLV_TYPE_BOOL_TRUE: + { + node->type = QIOT_DPDATA_TYPE_BOOL; + node->value.vbool = DP_TTLV_TYPE_BOOL_TRUE == ttlvtype ? TRUE : FALSE; + return 2; + } + case DP_TTLV_TYPE_ENUM_NUM: + { + if (len < 3) + { + return 0; + } + qbool negative = (buffer[2] >> 7) ? TRUE : FALSE; + quint8_t amp = (buffer[2] >> 3) & 0x0F; + quint8_t tmpLen = ((buffer[2]) & 0x07) + 1; + quint8_t offset; + if (len < (quint32_t)(3 + tmpLen)) + { + return 0; + } + qint64_t value = 0; + for (offset = 0; offset < tmpLen; offset++) + { + value <<= 8; + value |= buffer[offset + 3]; + } + if (negative) + { + value = 0 - value; + } + if (amp) + { + node->type = QIOT_DPDATA_TYPE_FLOAT; + node->value.floatNum = (double)value; + while (amp--) + { + node->value.floatNum /= 10.0; + } + } + else + { + node->type = QIOT_DPDATA_TYPE_INT; + node->value.intNum = value; + } + return 3 + tmpLen; + } + case DP_TTLV_TYPE_BYTE: + { + if (len < 4) + { + return 0; + } + node->type = QIOT_DPDATA_TYPE_BYTE; + node->value.vbytes.len = _ARRAY01_U16(&buffer[2]); + if (len < (quint32_t)(4 + node->value.vbytes.len)) + { + return 0; + } + node->value.vbytes.val = HAL_MALLOC(node->value.vbytes.len + 1); + if (NULL == node->value.vbytes.val) + { + return 0; + } + HAL_MEMCPY(node->value.vbytes.val, &buffer[4], node->value.vbytes.len); + node->value.vbytes.val[node->value.vbytes.len] = 0; + return 4 + node->value.vbytes.len; + } + case DP_TTLV_TYPE_STRUCT: + { + if (len < 4) + { + return 0; + } + quint16_t count = _ARRAY01_U16(&buffer[2]); + quint32_t offset = 4; + node->type = QIOT_DPDATA_TYPE_STRUCT; + while (count--) + { + QIot_ttlv_t *subNode = HAL_MALLOC(sizeof(QIot_ttlv_t)); + if (NULL == subNode) + { + return 0; + } + quint32_t nodeLen = ql_iotTtlvUnformatFirst(&buffer[offset], len - offset, subNode); + if (nodeLen) + { + Quos_twllHeadAdd((TWLLHead_T **)&node->value.vstructHead, &subNode->head); + } + else + { + HAL_FREE(subNode); + Ql_iotTtlvFree(&node->value.vstructHead); + return 0; + } + offset += nodeLen; + } + if (FALSE == ql_iotTtlvIsStructArray(node->value.vstructHead, NULL)) + { + Ql_iotTtlvFree(&node->value.vstructHead); + return 0; + } + return offset; + } + default: + return 0; + } +} +/************************************************************************** +** 功能 @brief : 解压TTLV数据 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM *Ql_iotTtlvUnformat(const quint8_t *buffer, quint32_t len) +{ + void *ttlvHead = NULL; + quint32_t offset; + for (offset = 0; offset < len;) + { + QIot_ttlv_t *node = HAL_MALLOC(sizeof(QIot_ttlv_t)); + if (NULL == node) + { + return NULL; + } + quint32_t nodeLen = ql_iotTtlvUnformatFirst(&buffer[offset], len - offset, node); + if (nodeLen) + { + offset += nodeLen; + Quos_twllHeadAdd((TWLLHead_T **)&ttlvHead, &node->head); + } + else + { + HAL_FREE(node); + Ql_iotTtlvFree((void **)&ttlvHead); + return NULL; + } + } + if (FALSE == ql_iotTtlvIsStructArray(ttlvHead, NULL)) + { + Ql_iotTtlvFree(&ttlvHead); + } + return (void *)ttlvHead; +} +/************************************************************************** +** 功能 @brief : 计算构建TTLV数据包数据长度 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +quint32_t FUNCTION_ATTR_ROM Ql_iotTtlvFormatLen(const void *ttlvHead) +{ + quint32_t pkgLen = 0; + TWLLHead_T *temp, *next; + TWLIST_FOR_DATA((TWLLHead_T *)ttlvHead, temp, next) + { + quint8_t tmpBuf[8]; + QIot_ttlv_t *node = __GET_STRUCT_BY_ELEMENT(temp, QIot_ttlv_t, head); + pkgLen += 2; + switch (node->type) + { + case QIOT_DPDATA_TYPE_BOOL: /*do none*/ + break; + case QIOT_DPDATA_TYPE_INT: + { + pkgLen += 1; + qint64_t value = node->value.intNum; + if (value < 0) + { + value = 0 - value; + } + pkgLen += Quos_intPushArray((quint64_t)value, tmpBuf); + break; + } + case QIOT_DPDATA_TYPE_FLOAT: + { + pkgLen += 1; + double value = node->value.floatNum; + if (value < 0) + { + value = 0 - value; + } + quint8_t amp = 0; + while (0 != (value - (quint64_t)value) && amp < 0x0F) + { + value *= 10.0; + amp++; + } + pkgLen += Quos_intPushArray((quint64_t)value, tmpBuf); + break; + } + case QIOT_DPDATA_TYPE_BYTE: + { + pkgLen += 2 + node->value.vbytes.len; + break; + } + case QIOT_DPDATA_TYPE_STRUCT: + { + pkgLen += 2 + Ql_iotTtlvFormatLen(node->value.vstructHead); + break; + } + } + } + return pkgLen; +} +/************************************************************************** +** 功能 @brief : 构建TTLV数据包数 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +quint32_t FUNCTION_ATTR_ROM Ql_iotTtlvFormat(const void *ttlvHead, quint8_t *retBuf) +{ + quint32_t pkgLen = 0; + TWLLHead_T *temp, *next; + TWLIST_FOR_DATA((TWLLHead_T *)ttlvHead, temp, next) + { + QIot_ttlv_t *node = __GET_STRUCT_BY_ELEMENT(temp, QIot_ttlv_t, head); + _U16_ARRAY01(node->id << 3, &retBuf[pkgLen]); + switch (node->type) + { + case QIOT_DPDATA_TYPE_BOOL: + { + retBuf[pkgLen + 1] |= node->value.vbool ? DP_TTLV_TYPE_BOOL_TRUE : DP_TTLV_TYPE_BOOL_FALSE; + pkgLen += 2; + break; + } + case QIOT_DPDATA_TYPE_INT: + { + qint64_t value = node->value.intNum; + if (value < 0) + { + retBuf[pkgLen + 2] = 1 << 7; + value = 0 - value; + } + else + { + retBuf[pkgLen + 2] = 0; + } + quint8_t tmpLen = Quos_intPushArray((quint64_t)value, &retBuf[pkgLen + 3]); + retBuf[pkgLen + 1] |= DP_TTLV_TYPE_ENUM_NUM; + retBuf[pkgLen + 2] |= (tmpLen - 1); + pkgLen += 3 + tmpLen; + break; + } + case QIOT_DPDATA_TYPE_FLOAT: + { + double value = node->value.floatNum; + if (value < 0) + { + retBuf[pkgLen + 2] = 1 << 7; + value = 0 - value; + } + else + { + retBuf[pkgLen + 2] = 0; + } + + quint8_t amp = 0; + while (0 != (value - (quint64_t)value) && amp < 0x0F) + { + value *= 10.0; + amp++; + } + quint8_t tmpLen = Quos_intPushArray((quint64_t)value, &retBuf[pkgLen + 3]); + retBuf[pkgLen + 1] |= DP_TTLV_TYPE_ENUM_NUM; + retBuf[pkgLen + 2] |= (amp << 3) | (tmpLen - 1); + pkgLen += 3 + tmpLen; + break; + } + case QIOT_DPDATA_TYPE_BYTE: + { + retBuf[pkgLen + 1] |= DP_TTLV_TYPE_BYTE; + _U16_ARRAY01(node->value.vbytes.len, &retBuf[pkgLen + 2]); + HAL_MEMCPY(&retBuf[pkgLen + 4], node->value.vbytes.val, node->value.vbytes.len); + pkgLen += 4 + node->value.vbytes.len; + break; + } + case QIOT_DPDATA_TYPE_STRUCT: + { + quint16_t count = Quos_twllHeadGetNodeCount(node->value.vstructHead); + retBuf[pkgLen + 1] |= DP_TTLV_TYPE_STRUCT; + pkgLen += 2; + _U16_ARRAY01(count, &retBuf[pkgLen]); + pkgLen += 2; + pkgLen += Ql_iotTtlvFormat(node->value.vstructHead, &retBuf[pkgLen]); + break; + } + } + } + return pkgLen; +} + +#define QL_IOTJSON_BYTE_MARK "\\x" +/************************************************************************** +** 功能 @brief : JSON转TTLV +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void FUNCTION_ATTR_ROM ql_iotJson2Ttlv(const cJSON *json, void **ttlvHead) +{ + qbool ret = FALSE; + quint32_t id = 0; + if (json->string && FALSE == Quos_strIsUInt(json->string, HAL_STRLEN(json->string), &id)) + { + return; + } + Quos_logPrintf(QUEC_TTLV,LL_DBG,"string[%s] id[%d] type[%d]",json->string,id,json->type); + switch (json->type) + { + case QUOS_cJSON_False: + ret = Ql_iotTtlvIdAddBool(ttlvHead, id, FALSE); + break; + case QUOS_cJSON_True: + ret = Ql_iotTtlvIdAddBool(ttlvHead, id, TRUE); + break; + case QUOS_cJSON_Number: + ret = Ql_iotTtlvIdAddFloat(ttlvHead, id, json->valuedouble); + break; + case QUOS_cJSON_String: + case QUOS_cJSON_Raw: + { + if (0 == HAL_STRNCMP(json->valuestring, QL_IOTJSON_BYTE_MARK, HAL_STRLEN(QL_IOTJSON_BYTE_MARK))) + { + quint16_t vaildLen = HAL_STRLEN(json->valuestring + 2); + quint8_t *tempBuf = HAL_MALLOC(vaildLen / 2); + if (tempBuf) + { + if (vaildLen / 2 == Quos_str2Hex(json->valuestring + 2, tempBuf)) + { + ret = Ql_iotTtlvIdAddByte(ttlvHead, id, tempBuf, vaildLen / 2); + } + HAL_FREE(tempBuf); + } + } + else if (0 == HAL_STRNCMP(json->valuestring, "\\\\", HAL_STRLEN("\\\\"))) + { + ret = Ql_iotTtlvIdAddString(ttlvHead, id, json->valuestring + 1); + } + else + { + ret = Ql_iotTtlvIdAddString(ttlvHead, id, json->valuestring); + } + } + + break; + case QUOS_cJSON_Array: + case QUOS_cJSON_Object: + { + void *ttlvChild = NULL; + cJSON *child = json->child; + while (child) + { + ql_iotJson2Ttlv(child, &ttlvChild); + if(NULL == ttlvChild) + { + break; + } + child = child->next; + } + if (ttlvChild && ql_iotTtlvIsStructArray(ttlvChild, NULL)) + { + ret = Ql_iotTtlvIdAddStruct(ttlvHead, id, ttlvChild); + } + break; + } + default: + break; + } + if(FALSE == ret) + { + Ql_iotTtlvFree(ttlvHead); + } +} +/************************************************************************** +** 功能 @brief : JSON字符串转TTLV +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM *Ql_iotJson2Ttlv(const cJSON *json) +{ + if(NULL == json) + { + return NULL; + } + void *ttlvHead = NULL; + cJSON *child = json->child; + while (child) + { + ql_iotJson2Ttlv(child, &ttlvHead); + if(NULL == ttlvHead) + { + break; + } + child = child->next; + } + return ttlvHead; +} +/************************************************************************** +** 功能 @brief : TTLV转JSON字符串 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +cJSON FUNCTION_ATTR_ROM *Ql_iotTtlv2Json(const void *ttlvHead) +{ + qbool isArray; + cJSON *jsonRoot = NULL; + if (NULL == ttlvHead || FALSE == ql_iotTtlvIsStructArray(ttlvHead, &isArray)) + { + return NULL; + } + Quos_logPrintf(QUEC_TTLV,LL_DBG,"isArray:%s",_BOOL2STR(isArray)); + TWLLHead_T *temp, *next; + TWLIST_FOR_DATA((TWLLHead_T *)ttlvHead, temp, next) + { + QIot_ttlv_t *node = __GET_STRUCT_BY_ELEMENT(temp, QIot_ttlv_t, head); + char id[10]; + HAL_SPRINTF(id, "%d", node->id); + cJSON *jsonNode = NULL; + switch (node->type) + { + case QIOT_DPDATA_TYPE_BOOL: + jsonNode = cJSON_CreateBool(node->value.vbool); + break; + case QIOT_DPDATA_TYPE_INT: + jsonNode = cJSON_CreateNumber(node->value.intNum); + break; + case QIOT_DPDATA_TYPE_FLOAT: + jsonNode = cJSON_CreateNumber(node->value.floatNum); + break; + case QIOT_DPDATA_TYPE_BYTE: + { + quint16_t i; + for (i = 0; i < node->value.vbytes.len; i++) + { + if (node->value.vbytes.val[i] < 0x20 || node->value.vbytes.val[i] > 0x7E) + { + char *tempBuf = HAL_MALLOC(node->value.vbytes.len * 2 + HAL_STRLEN(QL_IOTJSON_BYTE_MARK) + 1); + if (tempBuf) + { + HAL_SPRINTF(tempBuf, "%s", QL_IOTJSON_BYTE_MARK); + Quos_hex2Str(node->value.vbytes.val, node->value.vbytes.len, tempBuf + HAL_STRLEN(tempBuf), TRUE); + jsonNode = cJSON_CreateString(tempBuf); + HAL_FREE(tempBuf); + break; + } + } + } + if (i >= node->value.vbytes.len) + { + if(0 == HAL_STRNCMP(node->value.vbytes.val, "\\", HAL_STRLEN("\\"))) + { + char *tempBuf = HAL_MALLOC(node->value.vbytes.len+1+1); + if (tempBuf) + { + HAL_SPRINTF(tempBuf, "\\%s", node->value.vbytes.val); + jsonNode = cJSON_CreateString(tempBuf); + HAL_FREE(tempBuf); + break; + } + } + else + { + jsonNode = cJSON_CreateString((const char*)node->value.vbytes.val); + } + } + } + break; + case QIOT_DPDATA_TYPE_STRUCT: + jsonNode = Ql_iotTtlv2Json(node->value.vstructHead); + break; + default: + break; + } + if (NULL == jsonNode) + { + cJSON_Delete(jsonRoot); + jsonRoot = NULL; + break; + } + else if (isArray) + { + if (NULL == jsonRoot) + { + jsonRoot = cJSON_CreateArray(); + } + cJSON_AddItemToArray(jsonRoot, jsonNode); + } + else + { + if (NULL == jsonRoot) + { + jsonRoot = cJSON_CreateObject(); + } + cJSON_AddItemToObject(jsonRoot, id, jsonNode); + } + } + return jsonRoot; +} diff --git a/cloud/common/ql_iotTtlv.h b/cloud/common/ql_iotTtlv.h new file mode 100644 index 0000000000000000000000000000000000000000..d02350cfd3325e019ddcc6b74e938d706a660246 --- /dev/null +++ b/cloud/common/ql_iotTtlv.h @@ -0,0 +1,9 @@ +#ifndef __QL_IOTTTLV_H__ +#define __QL_IOTTTLV_H__ +#include "Ql_iotApi.h" + +void *Ql_iotTtlvUnformat(const quint8_t *buffer, quint32_t len); +quint32_t Ql_iotTtlvFormatLen(const void *ttlvHead); +quint32_t Ql_iotTtlvFormat(const void *ttlvHead, quint8_t *retBuf); + +#endif \ No newline at end of file diff --git a/cloud/python/modquecIot.c b/cloud/python/modquecIot.c new file mode 100644 index 0000000000000000000000000000000000000000..55ae3de101c2420fc4d82fd9cbec329e208b5794 --- /dev/null +++ b/cloud/python/modquecIot.c @@ -0,0 +1,1849 @@ +/************************************************************************* +** @author : +** @version : +** @date : +** @brief : 娉ㄦ剰鏂囦欢浣跨敤 UTF-8 缂栫爜 +** @hardware : +** @other : +***************************************************************************/ +#include "Ql_iotApi.h" +#include "py/obj.h" +#include "py/objlist.h" +#include "py/objtuple.h" +#include "py/objstr.h" +#include "py/runtime.h" +#include "py/mperrno.h" +#include "py/mpz.h" +#include "py/objint.h" +#include "mpconfigport.h" +//#include "helios_os.h" + +extern quint32_t Quos_stringSplit(char *src, quint32_t srcLen, char **words, quint32_t maxSize, const char *delim, qbool keepEmptyParts); +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotCmdBusPassTransSend(mp_obj_t mp_mode, mp_obj_t mp_data) +{ + int mode = mp_obj_get_int(mp_mode); + mp_buffer_info_t data = {0}; + mp_get_buffer_raise(mp_data, &data, MP_BUFFER_READ); + if (FALSE == Ql_iotCmdBusPassTransSend(mode, (quint8_t *)data.buf, data.len)) + { + return mp_obj_new_bool(FALSE); + } + return mp_obj_new_bool(TRUE); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(qpy_Ql_iotCmdBusPassTransSend_obj, qpy_Ql_iotCmdBusPassTransSend); + +//mpz -> 64bit integer for 32bit builds +static qint64_t mpz_to_64bit_int(const mp_obj_int_t *arg, bool is_signed) +{ + //see mpz_as_int_checked + const qint64_t maxCalcThreshold = is_signed ? 140737488355327 : 281474976710655; + + const mpz_t *i = &arg->mpz; + if (!is_signed && i->neg) + { + mp_raise_TypeError(MP_ERROR_TEXT("Source integer must be unsigned")); + } + + short unsigned int *d = i->dig + i->len; + qint64_t val = 0; + + while (d-- > i->dig) + { + if (val > maxCalcThreshold) + { + mp_raise_ValueError(MP_ERROR_TEXT("Value too large for 64bit integer")); + } + val = (val << MPZ_DIG_SIZE) | *d; + } + + if (i->neg) + { + val = -val; + } + return val; +} + +static qint64_t mp_obj_get_lint(mp_const_obj_t arg) +{ + if (arg == mp_const_false) + { + return 0u; + } + else if (arg == mp_const_true) + { + return 1u; + } + else if (MP_OBJ_IS_SMALL_INT(arg)) + { + return MP_OBJ_SMALL_INT_VALUE(arg); + } + else if (MP_OBJ_IS_TYPE(arg, &mp_type_int)) + { + return mpz_to_64bit_int((mp_obj_int_t *)arg, 1); + } + else + { + mp_raise_TypeError(MP_ERROR_TEXT("unsigned integer")); + } + return 0u; +} + +static qbool phy_dict_handle(mp_obj_t mp_data, void **ttlvHead); +static qbool phy_list_handle(mp_obj_t mp_data, void **ttlvHead) +{ + size_t len = 0; + mp_obj_t *items = NULL; + mp_obj_list_get(mp_data, &len, &items); + if (len == 0) + { + return FALSE; + } + for (quint32_t i = 0; i < len; i++) + { + mp_obj_t id = mp_obj_new_int(0); + mp_obj_t value = items[i]; + if (mp_obj_is_bool(value)) + { + Ql_iotTtlvIdAddBool(ttlvHead, mp_obj_get_int(id), value == mp_const_true ? TRUE : FALSE); + } + else if (mp_obj_is_int(value)) + { + Ql_iotTtlvIdAddInt(ttlvHead, mp_obj_get_int(id), mp_obj_get_lint(value)); + } + else if (mp_obj_is_float(value)) + { + Ql_iotTtlvIdAddFloat(ttlvHead, mp_obj_get_int(id), mp_obj_get_float(value)); + } + else if (mp_obj_is_str(value) || mp_obj_is_type(value, &mp_type_bytearray) || mp_obj_is_type(value, &mp_type_bytes)) + { + mp_buffer_info_t data = {0}; + mp_get_buffer_raise(value, &data, MP_BUFFER_READ); + Ql_iotTtlvIdAddByte(ttlvHead, mp_obj_get_int(id), data.buf, data.len); + } + else if (mp_obj_is_type(value, &mp_type_dict)) + { + void *ttlvStructHead = NULL; + phy_dict_handle(value, &ttlvStructHead); + Ql_iotTtlvIdAddStruct(ttlvHead, mp_obj_get_int(id), ttlvStructHead); + } + else if (mp_obj_is_type(value, &mp_type_list) || mp_obj_is_type(value, &mp_type_tuple)) + { + void *ttlvStructHead = NULL; + phy_list_handle(value, &ttlvStructHead); + Ql_iotTtlvIdAddStruct(ttlvHead, mp_obj_get_int(id), ttlvStructHead); + } + else + { + return FALSE; + } + } + return TRUE; +} + +static qbool phy_dict_handle(mp_obj_t mp_data, void **ttlvHead) +{ + quint32_t index = 0; + mp_map_t *map = NULL; + mp_obj_t id = 0; + mp_obj_t value = 0; + if (!mp_obj_is_type(mp_data, &mp_type_dict)) + { + return FALSE; + } + + map = mp_obj_dict_get_map(mp_data); + if (map == NULL) + { + return FALSE; + } + + for (; index < map->alloc; index++) + { + id = map->table[index].key; + value = map->table[index].value; + + if (id == MP_OBJ_NULL) + { + if (index + (quint32_t)1 < map->alloc) + { + continue; + } + else if (index > 0) + { + return TRUE; + } + else + { + return FALSE; + } + } + if (mp_obj_is_bool(value)) + { + Ql_iotTtlvIdAddBool(ttlvHead, mp_obj_get_int(id), value == mp_const_true ? TRUE : FALSE); + } + else if (mp_obj_is_int(value)) + { + Ql_iotTtlvIdAddInt(ttlvHead, mp_obj_get_int(id), mp_obj_get_lint(value)); + } + else if (mp_obj_is_float(value)) + { + Ql_iotTtlvIdAddFloat(ttlvHead, mp_obj_get_int(id), mp_obj_get_float(value)); + } + else if (mp_obj_is_str(value) || mp_obj_is_type(value, &mp_type_bytearray) || mp_obj_is_type(value, &mp_type_bytes)) + { + mp_buffer_info_t data = {0}; + mp_get_buffer_raise(value, &data, MP_BUFFER_READ); + Ql_iotTtlvIdAddByte(ttlvHead, mp_obj_get_int(id), data.buf, data.len); + } + else if (mp_obj_is_type(value, &mp_type_dict)) + { + void *ttlvStructHead = NULL; + phy_dict_handle(value, &ttlvStructHead); + Ql_iotTtlvIdAddStruct(ttlvHead, mp_obj_get_int(id), ttlvStructHead); + } + else if (mp_obj_is_type(value, &mp_type_list) || mp_obj_is_type(value, &mp_type_tuple)) + { + void *ttlvStructHead = NULL; + phy_list_handle(value, &ttlvStructHead); + Ql_iotTtlvIdAddStruct(ttlvHead, mp_obj_get_int(id), ttlvStructHead); + } + else + { + return FALSE; + } + } + return TRUE; +} + +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotCmdBusPhymodelReport(mp_obj_t mp_mode, mp_obj_t mp_data) +{ + int mode = mp_obj_get_int(mp_mode); + mp_obj_t ret = mp_const_true; + void *ttlvHead = NULL; + if (phy_dict_handle(mp_data, &ttlvHead)) + { + if (FALSE == Ql_iotCmdBusPhymodelReport(mode, ttlvHead)) + { + ret = mp_const_false; + } + } + else + { + ret = mp_const_false; + } + Ql_iotTtlvFree(&ttlvHead); + return ret; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(qpy_Ql_iotCmdBusPhymodelReport_obj, qpy_Ql_iotCmdBusPhymodelReport); + +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotCmdBusPhymodelAck(mp_obj_t mp_mode, mp_obj_t mp_pkgid, mp_obj_t mp_data) +{ + int mode = mp_obj_get_int(mp_mode); + int pkgid = mp_obj_get_int(mp_pkgid); + mp_obj_t ret = mp_const_true; + void *ttlvHead = NULL; + if (phy_dict_handle(mp_data, &ttlvHead)) + { + if (FALSE == Ql_iotCmdBusPhymodelAck(mode, (quint16_t)pkgid, ttlvHead)) + { + ret = mp_const_false; + } + } + else + { + ret = mp_const_false; + } + Ql_iotTtlvFree(&ttlvHead); + return ret; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(qpy_Ql_iotCmdBusPhymodelAck_obj, qpy_Ql_iotCmdBusPhymodelAck); + +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotCmdOtaAction(mp_obj_t mp_action) +{ + if (Ql_iotGetWorkState() == 0) + { + return mp_obj_new_bool(FALSE); + } + int action = mp_obj_get_int(mp_action); + if (FALSE == Ql_iotCmdOtaAction(action)) + { + return mp_obj_new_bool(FALSE); + } + return mp_obj_new_bool(TRUE); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_Ql_iotCmdOtaAction_obj, qpy_Ql_iotCmdOtaAction); +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotCmdOtaRequest(mp_obj_t mp_mode) +{ + if (Ql_iotGetWorkState() == 0) + { + return mp_obj_new_bool(FALSE); + } + int mode = mp_obj_get_int(mp_mode); + if (FALSE == Ql_iotCmdOtaRequest(mode)) + { + return mp_obj_new_bool(FALSE); + } + return mp_obj_new_bool(TRUE); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_Ql_iotCmdOtaRequest_obj, qpy_Ql_iotCmdOtaRequest); +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotCmdOtaMcuFWDataRead(mp_obj_t mp_addr, mp_obj_t mp_len) +{ + quint32_t addr = mp_obj_get_int(mp_addr); + quint32_t len = mp_obj_get_int(mp_len); + // 2021-06-18 闄愬埗SOTA璇诲彇闀垮害銆傚洜涓鸿鍙栭暱搴﹁繃闀匡紝浼氬鑷存ā缁刣ump銆傝屼笖璇诲彇瓒呰繃鍥轰欢澶у皬鐨勯暱搴︿篃浼氬厛琛岀敵璇峰唴瀛橈紝瀹规槗dump銆 + if (Ql_iotGetWorkState() == 0 || len == 0 /* || len > Helios_GetAvailableMemorySize() / 3*/) + { + return mp_const_none; + } + void *data = NULL; + quint32_t ret = 0; + + data = malloc(len); + if (data == NULL) + { + mp_raise_OSError(MP_ENOMEM); + return mp_const_none; + } + if ((ret = Ql_iotCmdOtaMcuFWDataRead(addr, (quint8_t *)data, len)) > 0) + { + mp_obj_t retData = mp_obj_new_bytes((const unsigned char *)data, ret); + free(data); + return retData; + } + free(data); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(qpy_Ql_iotCmdOtaMcuFWDataRead_obj, qpy_Ql_iotCmdOtaMcuFWDataRead); +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotCmdSysGetDevStatus(mp_obj_t id_list) +{ + size_t count = 0; + mp_obj_t *items = NULL; + mp_obj_get_array(id_list, &count, &items); + count = count < QIOT_DPID_STATUS_MAX ? count : QIOT_DPID_STATUS_MAX; + mp_obj_t struct_dict = mp_obj_new_dict(count); + quint16_t ids[QIOT_DPID_STATUS_MAX]; + size_t i; + for (i = 0; i < count; i++) + { + ids[i] = mp_obj_get_int(items[i]); + } + void *statusTtlv = Ql_iotSysGetDevStatus(ids, count); + + i = 0; + void *node; + quint16_t id; + QIot_dpDataType_e type; + while ((node = Ql_iotTtlvNodeGet(statusTtlv, i++, &id, &type))) + { + switch (type) + { + case QIOT_DPDATA_TYPE_BOOL: + { + qbool value; + if (Ql_iotTtlvNodeGetBool(node, &value)) + { + mp_obj_dict_store(struct_dict, mp_obj_new_int(id), mp_obj_new_bool(value)); + } + break; + } + case QIOT_DPDATA_TYPE_INT: + { + qint64_t value; + if (Ql_iotTtlvNodeGetInt(node, &value)) + { + mp_obj_dict_store(struct_dict, mp_obj_new_int(id), mp_obj_new_int(value)); + } + break; + } + case QIOT_DPDATA_TYPE_FLOAT: + { + double value; + if (Ql_iotTtlvNodeGetFloat(node, &value)) + { + mp_obj_dict_store(struct_dict, mp_obj_new_int(id), mp_obj_new_float(value)); + } + break; + } + case QIOT_DPDATA_TYPE_BYTE: + { + quint8_t *value; + quint32_t len = Ql_iotTtlvNodeGetByte(node, &value); + if (len) + { + mp_obj_dict_store(struct_dict, mp_obj_new_int(id), mp_obj_new_str((const char *)value, len)); + } + break; + } + case QIOT_DPDATA_TYPE_STRUCT: + break; + } + } + + Ql_iotTtlvFree(&statusTtlv); + return struct_dict; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_Ql_iotCmdSysGetDevStatus_obj, qpy_Ql_iotCmdSysGetDevStatus); +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotCmdSysGetDevInfo(mp_obj_t id_list) +{ + size_t count = 0; + mp_obj_t *items = NULL; + mp_obj_get_array(id_list, &count, &items); + count = count < QIOT_DPID_INFO_MAX ? count : QIOT_DPID_INFO_MAX; + mp_obj_t struct_dict = mp_obj_new_dict(count); + + quint16_t ids[QIOT_DPID_INFO_MAX]; + size_t i; + for (i = 0; i < count; i++) + { + ids[i] = mp_obj_get_int(items[i]); + } + void *statusTtlv = Ql_iotSysGetDevInfo(ids, count); + + i = 0; + void *node; + quint16_t id; + QIot_dpDataType_e type; + while ((node = Ql_iotTtlvNodeGet(statusTtlv, i++, &id, &type))) + { + switch (type) + { + case QIOT_DPDATA_TYPE_BOOL: + { + qbool value; + if (Ql_iotTtlvNodeGetBool(node, &value)) + { + mp_obj_dict_store(struct_dict, mp_obj_new_int(id), mp_obj_new_bool(value)); + } + break; + } + case QIOT_DPDATA_TYPE_INT: + { + qint64_t value; + if (Ql_iotTtlvNodeGetInt(node, &value)) + { + mp_obj_dict_store(struct_dict, mp_obj_new_int(id), mp_obj_new_int(value)); + } + break; + } + case QIOT_DPDATA_TYPE_FLOAT: + { + double value; + if (Ql_iotTtlvNodeGetFloat(node, &value)) + { + mp_obj_dict_store(struct_dict, mp_obj_new_int(id), mp_obj_new_float(value)); + } + break; + } + case QIOT_DPDATA_TYPE_BYTE: + { + quint8_t *value; + quint32_t len = Ql_iotTtlvNodeGetByte(node, &value); + if (len) + { + mp_obj_dict_store(struct_dict, mp_obj_new_int(id), mp_obj_new_str((const char *)value, len)); + } + break; + } + case QIOT_DPDATA_TYPE_STRUCT: + break; + } + } + + Ql_iotTtlvFree(&statusTtlv); + return struct_dict; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_Ql_iotCmdSysGetDevInfo_obj, qpy_Ql_iotCmdSysGetDevInfo); +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotCmdSysStatusReport(mp_obj_t id_list) +{ + qbool ret = FALSE; + size_t count = 0; + mp_obj_t *items = NULL; + quint16_t *ids = NULL; + mp_obj_get_array(id_list, &count, &items); + if (count && (ids = malloc(count * sizeof(sizeof(quint16_t)))) != NULL) + { + size_t i; + for (i = 0; i < count; i++) + { + ids[i] = mp_obj_get_int(items[i]); + } + ret = Ql_iotCmdSysStatusReport(ids, count); + free(ids); + } + return mp_obj_new_bool(ret ? TRUE : FALSE); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_Ql_iotCmdSysStatusReport_obj, qpy_Ql_iotCmdSysStatusReport); +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotCmdSysDevInfoReport(mp_obj_t id_list) +{ + qbool ret = FALSE; + size_t count = 0; + mp_obj_t *items = NULL; + quint16_t *ids = NULL; + mp_obj_get_array(id_list, &count, &items); + if (count && (ids = malloc(count * sizeof(sizeof(quint16_t)))) != NULL) + { + size_t i; + for (i = 0; i < count; i++) + { + ids[i] = mp_obj_get_int(items[i]); + } + ret = Ql_iotCmdSysDevInfoReport(ids, count); + free(ids); + } + return mp_obj_new_bool(ret ? TRUE : FALSE); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_Ql_iotCmdSysDevInfoReport_obj, qpy_Ql_iotCmdSysDevInfoReport); + +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotInit(void) +{ + if (Ql_iotGetWorkState() == 0) + { + if (TRUE == Ql_iotInit()) + { + return mp_const_true; + } + return mp_const_false; + } + else + { + Ql_iotConfigSetConnmode(0); + } + return mp_const_true; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(qpy_Ql_iotInit_obj, qpy_Ql_iotInit); + +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotConfigSetConnmode(mp_obj_t mode) +{ + if (Ql_iotGetWorkState() == 0) + { + return mp_obj_new_bool(FALSE); + } + if (FALSE == Ql_iotConfigSetConnmode(mp_obj_get_int(mode))) + { + return mp_obj_new_bool(FALSE); + } + return mp_obj_new_bool(TRUE); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_Ql_iotConfigSetConnmode_obj, qpy_Ql_iotConfigSetConnmode); + +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotConfigGetConnmode(void) +{ + if (Ql_iotGetWorkState() == 0) + { + return mp_const_none; + } + QIot_connMode_e mode = Ql_iotConfigGetConnmode(); + return mp_obj_new_int(mode); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(qpy_Ql_iotConfigGetConnmode_obj, qpy_Ql_iotConfigGetConnmode); + +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotConfigSetPdpContextId(mp_obj_t context_id) +{ + if (Ql_iotGetWorkState() == 0) + { + return mp_const_false; + } + if (FALSE == Ql_iotConfigSetPdpContextId((quint8_t)mp_obj_get_int(context_id))) + { + return mp_const_false; + } + return mp_const_true; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_Ql_iotConfigSetPdpContextId_obj, qpy_Ql_iotConfigSetPdpContextId); + +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotConfigGetPdpContextId(void) +{ + if (Ql_iotGetWorkState() == 0) + { + return mp_const_none; + } + quint8_t contextid = Ql_iotConfigGetPdpContextId(); + return mp_obj_new_int(contextid); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(qpy_Ql_iotConfigGetPdpContextId_obj, qpy_Ql_iotConfigGetPdpContextId); + +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotConfigSetServer(mp_obj_t type, mp_obj_t server) +{ + if (Ql_iotGetWorkState() == 0) + { + return mp_obj_new_bool(FALSE); + } + mp_buffer_info_t serverinfo = {0}; + mp_get_buffer_raise(server, &serverinfo, MP_BUFFER_READ); + if (FALSE == Ql_iotConfigSetServer(mp_obj_get_int(type), (const char *)serverinfo.buf)) + { + return mp_obj_new_bool(FALSE); + } + return mp_obj_new_bool(TRUE); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(qpy_Ql_iotConfigSetServer_obj, qpy_Ql_iotConfigSetServer); + +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotConfigGetServer(void) +{ + if (Ql_iotGetWorkState() == 0) + { + return mp_const_none; + } + int type = 0; + char *server = NULL; + + Ql_iotConfigGetServer((QIot_protocolType_t *)&type, &server); + mp_obj_t url_info[2] = + { + mp_obj_new_int(type), + mp_obj_new_str(server, strlen(server)), + }; + return mp_obj_new_tuple(2, url_info); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(qpy_Ql_iotConfigGetServer_obj, qpy_Ql_iotConfigGetServer); + +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotConfigSetProductinfo(mp_obj_t product_key, mp_obj_t product_secret) +{ + if (Ql_iotGetWorkState() == 0) + { + return mp_obj_new_bool(FALSE); + } + mp_buffer_info_t keyinfo = {0}; + mp_buffer_info_t secretinfo = {0}; + mp_get_buffer_raise(product_key, &keyinfo, MP_BUFFER_READ); + mp_get_buffer_raise(product_secret, &secretinfo, MP_BUFFER_READ); + if (FALSE == Ql_iotConfigSetProductinfo((const char *)keyinfo.buf, (const char *)secretinfo.buf)) + { + return mp_obj_new_bool(FALSE); + } + return mp_obj_new_bool(TRUE); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(qpy_Ql_iotConfigSetProductinfo_obj, qpy_Ql_iotConfigSetProductinfo); + +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotConfigGetProductinfo(void) +{ + if (Ql_iotGetWorkState() == 0) + { + return mp_const_none; + } + char *product_key = NULL; + char *product_secret = NULL; + char *product_ver = NULL; + + Ql_iotConfigGetProductinfo(&product_key, &product_secret, &product_ver); + mp_obj_t product_info[3] = + { + mp_obj_new_str(product_key, strlen(product_key)), + mp_obj_new_str(product_secret, strlen(product_secret)), + mp_obj_new_str(product_ver, strlen(product_ver))}; + return mp_obj_new_tuple(3, product_info); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(qpy_Ql_iotConfigGetProductinfo_obj, qpy_Ql_iotConfigGetProductinfo); + +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotConfigSetLifetime(mp_obj_t life_time) +{ + if (Ql_iotGetWorkState() == 0) + { + return mp_obj_new_bool(FALSE); + } + int lifetime = mp_obj_get_int(life_time); + if (FALSE == Ql_iotConfigSetLifetime(lifetime)) + { + return mp_obj_new_bool(FALSE); + } + return mp_obj_new_bool(TRUE); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_Ql_iotConfigSetLifetime_obj, qpy_Ql_iotConfigSetLifetime); + +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotConfigGetLifetime(void) +{ + if (Ql_iotGetWorkState() == 0) + { + return mp_const_none; + } + quint32_t lifetime = Ql_iotConfigGetLifetime(); + return mp_obj_new_int_from_uint(lifetime); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(qpy_Ql_iotConfigGetLifetime_obj, qpy_Ql_iotConfigGetLifetime); + +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotConfigSetSessionFlag(mp_obj_t sessionFlag) +{ + if (Ql_iotGetWorkState() == 0 || FALSE == mp_obj_is_bool(sessionFlag)) + { + return mp_obj_new_bool(FALSE); + } + if (FALSE == Ql_iotConfigSetSessionFlag(mp_const_true == sessionFlag ? TRUE : FALSE)) + { + return mp_obj_new_bool(FALSE); + } + return mp_obj_new_bool(TRUE); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_Ql_iotConfigSetSessionFlag_obj, qpy_Ql_iotConfigSetSessionFlag); +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotConfigGetSessionFlag(void) +{ + if (Ql_iotGetWorkState() == 0) + { + return mp_const_none; + } + return mp_obj_new_bool(Ql_iotConfigGetSessionFlag()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(qpy_Ql_iotConfigGetSessionFlag_obj, qpy_Ql_iotConfigGetSessionFlag); +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotConfigGetSoftVersion(void) +{ + if (Ql_iotGetWorkState() == 0) + { + return mp_const_none; + } + char *ver = Ql_iotConfigGetSoftVersion(); + return mp_obj_new_str(ver, strlen(ver)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(qpy_Ql_iotConfigGetSoftVersion_obj, qpy_Ql_iotConfigGetSoftVersion); +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotConfigSetMcuVersion(mp_obj_t mp_compno, mp_obj_t mp_version) +{ + if (Ql_iotGetWorkState() == 0) + { + return mp_obj_new_bool(FALSE); + } + mp_buffer_info_t mcu_compno = {0}; + mp_buffer_info_t mcu_version = {0}; + mp_get_buffer_raise(mp_compno, &mcu_compno, MP_BUFFER_READ); + mp_get_buffer_raise(mp_version, &mcu_version, MP_BUFFER_READ); + if (FALSE == Ql_iotConfigSetMcuVersion((const char *)mcu_compno.buf, (const char *)mcu_version.buf)) + { + return mp_obj_new_bool(FALSE); + } + return mp_obj_new_bool(TRUE); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(qpy_Ql_iotConfigSetMcuVersion_obj, qpy_Ql_iotConfigSetMcuVersion); + +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotConfigGetMcuVersion(void) +{ + if (Ql_iotGetWorkState() == 0) + { + return mp_const_none; + } + char *temp = NULL; + char *oldVer = NULL; + mp_obj_t objList = mp_obj_new_list(0, NULL); + Ql_iotConfigGetMcuVersion(NULL, &oldVer); + temp = malloc(strlen(oldVer) + 1); + if (temp) + { + char *words[100]; + sprintf(temp, "%s", oldVer); + quint32_t count = Quos_stringSplit(temp, strlen(temp), words, sizeof(words) / sizeof(words[0]), ";", FALSE); + while (count--) + { + char *wordsnode[2]; + qint32_t nodeLen = Quos_stringSplit(words[count], strlen(words[count]), wordsnode, sizeof(wordsnode) / sizeof(wordsnode[0]), ":", FALSE); + if (2 == nodeLen) + { + mp_obj_t node[] = + { + mp_obj_new_str(wordsnode[0], strlen(wordsnode[0])), + mp_obj_new_str(wordsnode[1], strlen(wordsnode[1]))}; + mp_obj_list_append(objList, mp_obj_new_tuple(sizeof(node) / sizeof(node[0]), node)); + } + } + free(temp); + } + return objList; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(qpy_Ql_iotConfigGetMcuVersion_obj, qpy_Ql_iotConfigGetMcuVersion); +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotConfigSetDkDs(mp_obj_t dk, mp_obj_t ds) +{ + if (Ql_iotGetWorkState() == 0) + { + return mp_obj_new_bool(FALSE); + } + mp_buffer_info_t dkData = {0}, dsData = {0}; + mp_get_buffer_raise(dk, &dkData, MP_BUFFER_READ); + mp_get_buffer_raise(ds, &dsData, MP_BUFFER_READ); + if (FALSE == Ql_iotConfigSetDkDs((const char *)dkData.buf, (const char *)dsData.buf)) + { + return mp_obj_new_bool(FALSE); + } + return mp_obj_new_bool(TRUE); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(qpy_Ql_iotConfigSetDkDs_obj, qpy_Ql_iotConfigSetDkDs); + +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotConfigGetDkDs(void) +{ + if (Ql_iotGetWorkState() == 0) + { + return mp_const_none; + } + char *dk, *ds; + if (FALSE == Ql_iotConfigGetDkDs(&dk, &ds)) + { + return mp_const_none; + } + mp_obj_t dkds[2] = + { + mp_obj_new_str(dk, strlen(dk)), + mp_obj_new_str(ds, strlen(ds))}; + return mp_obj_new_tuple(2, dkds); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(qpy_Ql_iotConfigGetDkDs_obj, qpy_Ql_iotConfigGetDkDs); +/************************************************************************** +** 鍔熻兘 @brief : +** 杈撳叆 @param : +** 杈撳嚭 @retval: +***************************************************************************/ +static qbool ttlv_dict_handle(const void *ttlv_head, quint32_t count, mp_obj_t node_dict); +static qbool ttlv_array_handle(const void *ttlv_head, quint32_t count, mp_obj_t node_list) +{ + for (quint32_t i = 0; i < count; i++) + { + uint16_t id = 0; + int type = 0; + void *node = Ql_iotTtlvNodeGet(ttlv_head, i, &id, (QIot_dpDataType_e *)&type); + if (node) + { + switch (type) + { + case QIOT_DPDATA_TYPE_BOOL: + { + qbool bool_value; + Ql_iotTtlvNodeGetBool(node, &bool_value); + mp_obj_list_append(node_list, mp_obj_new_bool(bool_value)); + break; + } + case QIOT_DPDATA_TYPE_INT: + { + qint64_t num_value; + Ql_iotTtlvNodeGetInt(node, &num_value); + mp_obj_list_append(node_list, mp_obj_new_int_from_ll((long long)num_value)); + break; + } + case QIOT_DPDATA_TYPE_FLOAT: + { + double num_value; + Ql_iotTtlvNodeGetFloat(node, &num_value); + mp_obj_list_append(node_list, mp_obj_new_float((mp_float_t)num_value)); + break; + } + case QIOT_DPDATA_TYPE_BYTE: + { + quint8_t *value; + quint32_t len = Ql_iotTtlvNodeGetByte(node, &value); + mp_obj_list_append(node_list, mp_obj_new_bytes(value, len)); + break; + } + case QIOT_DPDATA_TYPE_STRUCT: + { + quint32_t struct_count = Ql_iotTtlvCountGet(node); + uint16_t temp_id = 0; + int temp_type = 0; + Ql_iotTtlvNodeGet(Ql_iotTtlvNodeGetStruct(node), 0, &temp_id, (QIot_dpDataType_e *)&temp_type); + if (temp_id == 0) + { + mp_obj_t struct_list = mp_obj_new_list(0, NULL); + ttlv_array_handle(Ql_iotTtlvNodeGetStruct(node), struct_count, struct_list); + mp_obj_list_append(node_list, struct_list); + } + else + { + mp_obj_t struct_dict = mp_obj_new_dict(struct_count); + ttlv_dict_handle(Ql_iotTtlvNodeGetStruct(node), struct_count, struct_dict); + mp_obj_list_append(node_list, struct_dict); + } + break; + } + default: + return FALSE; + break; + } + } + } + return TRUE; +} +static qbool ttlv_dict_handle(const void *ttlv_head, quint32_t count, mp_obj_t node_dict) +{ + for (quint32_t i = 0; i < count; i++) + { + uint16_t id = 0; + int type = 0; + void *node = Ql_iotTtlvNodeGet(ttlv_head, i, &id, (QIot_dpDataType_e *)&type); + if (node) + { + switch (type) + { + case QIOT_DPDATA_TYPE_BOOL: + { + qbool bool_value; + Ql_iotTtlvNodeGetBool(node, &bool_value); + mp_obj_dict_store(node_dict, mp_obj_new_int(id), mp_obj_new_bool(bool_value)); + break; + } + case QIOT_DPDATA_TYPE_INT: + { + qint64_t num_value; + Ql_iotTtlvNodeGetInt(node, &num_value); + mp_obj_dict_store(node_dict, mp_obj_new_int(id), mp_obj_new_int_from_ll((long long)num_value)); + break; + } + case QIOT_DPDATA_TYPE_FLOAT: + { + double num_value; + Ql_iotTtlvNodeGetFloat(node, &num_value); + mp_obj_dict_store(node_dict, mp_obj_new_int(id), mp_obj_new_float((mp_float_t)num_value)); + break; + } + case QIOT_DPDATA_TYPE_BYTE: + { + quint8_t *value; + quint32_t len = Ql_iotTtlvNodeGetByte(node, &value); + mp_obj_dict_store(node_dict, mp_obj_new_int(id), mp_obj_new_bytes(value, len)); + break; + } + case QIOT_DPDATA_TYPE_STRUCT: + { + quint32_t struct_count = Ql_iotTtlvCountGet(Ql_iotTtlvNodeGetStruct(node)); + uint16_t temp_id = 0; + int temp_type = 0; + Ql_iotTtlvNodeGet(Ql_iotTtlvNodeGetStruct(node), 0, &temp_id, (QIot_dpDataType_e *)&temp_type); + if (temp_id == 0) + { + mp_obj_t struct_list = mp_obj_new_list(0, NULL); + ttlv_array_handle(Ql_iotTtlvNodeGetStruct(node), struct_count, struct_list); + mp_obj_dict_store(node_dict, mp_obj_new_int(id), struct_list); + } + else + { + mp_obj_t struct_dict = mp_obj_new_dict(struct_count); + ttlv_dict_handle(Ql_iotTtlvNodeGetStruct(node), struct_count, struct_dict); + mp_obj_dict_store(node_dict, mp_obj_new_int(id), struct_dict); + } + break; + } + default: + return FALSE; + break; + } + } + } + return TRUE; +} + +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +static c_callback_t *Ql_iotUrcEventCB = NULL; +static void ql_iotEventCB(quint32_t event, qint32_t errcode, const void *valueT, quint32_t valLen) +{ + if (NULL == Ql_iotUrcEventCB || (event == 7 && errcode == 10702)) + { + return; + } + if (NULL == valueT) + { + mp_obj_t tuple[] = + { + mp_obj_new_int_from_uint(event), + mp_obj_new_int_from_uint(errcode)}; + mp_sched_schedule_ex(Ql_iotUrcEventCB, mp_obj_new_tuple(2, tuple)); + } + else if (QIOT_ATEVENT_TYPE_RECV == event && QIOT_RECV_SUCC_PHYMODEL_RECV == errcode) + { + quint32_t count = Ql_iotTtlvCountGet(valueT); + mp_obj_t node_dict = mp_obj_new_dict(count); + if (ttlv_dict_handle(valueT, count, node_dict)) + { + mp_obj_t tuple[] = + { + mp_obj_new_int_from_uint(event), + mp_obj_new_int_from_uint(errcode), + node_dict}; + mp_sched_schedule_ex(Ql_iotUrcEventCB, mp_obj_new_tuple(3, tuple)); + } + } + else if (QIOT_ATEVENT_TYPE_RECV == event && QIOT_RECV_SUCC_PHYMODEL_REQ == errcode) + { + quint16_t pkgId = *(quint16_t *)valueT; + quint16_t *ids = (quint16_t *)((quint8_t *)valueT + sizeof(quint16_t)); + mp_obj_t req_list = mp_obj_new_list(0, NULL); + mp_obj_t req_list_temp = mp_obj_new_list(0, NULL); + mp_obj_list_append(req_list, mp_obj_new_int((mp_int_t)pkgId)); + for (quint32_t i = 0; i < valLen; i++) + { + quint16_t modelId = ids[i]; + mp_obj_list_append(req_list_temp, mp_obj_new_int((mp_int_t)modelId)); + } + mp_obj_list_append(req_list, req_list_temp); + mp_obj_t tuple[] = + { + mp_obj_new_int_from_uint(event), + mp_obj_new_int_from_uint(errcode), + req_list}; + mp_sched_schedule_ex(Ql_iotUrcEventCB, mp_obj_new_tuple(3, tuple)); + } + else + { + mp_obj_t tuple[] = + { + mp_obj_new_int_from_uint(event), + mp_obj_new_int_from_uint(errcode), + mp_obj_new_bytes(valueT, valLen)}; + mp_sched_schedule_ex(Ql_iotUrcEventCB, mp_obj_new_tuple(3, tuple)); + } +} +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotConfigSetEventCB(mp_obj_t event_urc_cb) +{ + if (Ql_iotGetWorkState() == 0) + { + return mp_obj_new_bool(FALSE); + } + static c_callback_t cb = {0}; + Ql_iotUrcEventCB = &cb; + mp_sched_schedule_callback_register(Ql_iotUrcEventCB, event_urc_cb); + Ql_iotConfigSetEventCB(ql_iotEventCB); + return mp_obj_new_bool(TRUE); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_Ql_iotConfigSetEventCB_obj, qpy_Ql_iotConfigSetEventCB); +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotGetWorkState(void) +{ + quint32_t state = Ql_iotGetWorkState(); + return mp_obj_new_int_from_uint(state); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(qpy_Ql_iotGetWorkState_obj, qpy_Ql_iotGetWorkState); +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotCmdGetLocSupList(void) +{ + mp_obj_t supList = mp_obj_new_list(0, NULL); + void *titleTtlv = Ql_iotLocGetSupList(); + quint32_t count = Ql_iotTtlvCountGet(titleTtlv); + quint32_t i; + for (i = 0; i < count; i++) + { + char *str = Ql_iotTtlvNodeGetString(Ql_iotTtlvNodeGet(titleTtlv, i, NULL, NULL)); + if (str) + { + mp_obj_list_append(supList, mp_obj_new_str(str, strlen(str))); + } + } + Ql_iotTtlvFree(&titleTtlv); + + return supList; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(qpy_Ql_iotCmdGetLocSupList_obj, qpy_Ql_iotCmdGetLocSupList); +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotCmdGetLocData(mp_obj_t mp_title) +{ + mp_obj_t locDatas = mp_obj_new_list(0, NULL); + if (mp_obj_is_type(mp_title, &mp_type_list) || mp_obj_is_type(mp_title, &mp_type_tuple)) + { + quint32_t i; + size_t len = 0; + void *titleTtlv = NULL; + mp_obj_t *items = NULL; + mp_buffer_info_t itemstr = {0}; + mp_obj_list_get(mp_title, &len, &items); + for (i = 0; i < len; i++) + { + mp_get_buffer_raise(items[i], &itemstr, MP_BUFFER_READ); + Ql_iotTtlvIdAddString(&titleTtlv, 0, itemstr.buf); + } + void *nmeaTtlv = Ql_iotLocGetData(titleTtlv); + Ql_iotTtlvFree(&titleTtlv); + + quint32_t count = Ql_iotTtlvCountGet(nmeaTtlv); + for (i = 0; i < count; i++) + { + char *str = Ql_iotTtlvNodeGetString(Ql_iotTtlvNodeGet(nmeaTtlv, i, NULL, NULL)); + if (str) + { + mp_obj_list_append(locDatas, mp_obj_new_str(str, strlen(str))); + } + } + Ql_iotTtlvFree(&nmeaTtlv); + } + return locDatas; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_Ql_iotCmdGetLocData_obj, qpy_Ql_iotCmdGetLocData); +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotCmdBusLocReportInside(mp_obj_t mp_title) +{ + mp_obj_t ret = mp_const_false; + if (mp_obj_is_type(mp_title, &mp_type_list) || mp_obj_is_type(mp_title, &mp_type_tuple)) + { + quint8_t i; + size_t len = 0; + void *titleTtlv = NULL; + mp_obj_t *items = NULL; + mp_buffer_info_t itemstr = {0}; + mp_obj_list_get(mp_title, &len, &items); + for (i = 0; i < len; i++) + { + mp_get_buffer_raise(items[i], &itemstr, MP_BUFFER_READ); + Ql_iotTtlvIdAddString(&titleTtlv, 0, itemstr.buf); + } + if (Ql_iotCmdBusLocReportInside(titleTtlv)) + { + ret = mp_const_true; + } + Ql_iotTtlvFree(&titleTtlv); + } + else + { + ret = mp_const_false; + } + return ret; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_Ql_iotCmdBusLocReportInside_obj, qpy_Ql_iotCmdBusLocReportInside); + +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotCmdBusLocReportOutside(mp_obj_t mp_nmea) +{ + mp_obj_t ret = mp_const_false; + if (mp_obj_is_type(mp_nmea, &mp_type_list) || mp_obj_is_type(mp_nmea, &mp_type_tuple)) + { + quint8_t i; + size_t len = 0; + void *titleTtlv = NULL; + mp_obj_t *items = NULL; + mp_buffer_info_t itemstr = {0}; + mp_obj_list_get(mp_nmea, &len, &items); + for (i = 0; i < len; i++) + { + mp_get_buffer_raise(items[i], &itemstr, MP_BUFFER_READ); + Ql_iotTtlvIdAddString(&titleTtlv, 0, itemstr.buf); + } + if (Ql_iotCmdBusLocReportOutside(titleTtlv)) + { + ret = mp_const_true; + } + Ql_iotTtlvFree(&titleTtlv); + } + else + { + ret = mp_const_false; + } + return ret; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_Ql_iotCmdBusLocReportOutside_obj, qpy_Ql_iotCmdBusLocReportOutside); +#ifdef QUEC_ENABLE_HTTP_OTA +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotConfigSetHttpOtaProductInfo(mp_obj_t product_key, mp_obj_t product_secret) +{ + if (Ql_iotGetWorkState() == 0) + { + return mp_obj_new_bool(FALSE); + } + mp_buffer_info_t keyinfo = {0}; + mp_buffer_info_t secretinfo = {0}; + mp_get_buffer_raise(product_key, &keyinfo, MP_BUFFER_READ); + mp_get_buffer_raise(product_secret, &secretinfo, MP_BUFFER_READ); + if (FALSE == Ql_iotConfigSetHttpOtaProductInfo((const char *)keyinfo.buf, (const char *)secretinfo.buf)) + { + return mp_obj_new_bool(FALSE); + } + return mp_obj_new_bool(TRUE); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(qpy_Ql_iotConfigSetHttpOtaProductInfo_obj, qpy_Ql_iotConfigSetHttpOtaProductInfo); +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotConfigGetHttpOtaProductInfo(void) +{ + if (Ql_iotGetWorkState() == 0) + { + return mp_const_none; + } + char *product_key = NULL; + char *product_secret = NULL; + + Ql_iotConfigGetHttpOtaProductInfo(&product_key, &product_secret); + mp_obj_t product_info[2] = + { + mp_obj_new_str(product_key, strlen(product_key)), + mp_obj_new_str(product_secret, strlen(product_secret)), + }; + return mp_obj_new_tuple(2, product_info); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(qpy_Ql_iotConfigGetHttpOtaProductInfo_obj, qpy_Ql_iotConfigGetHttpOtaProductInfo); +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotConfigSetHttpOtaTls(mp_obj_t mp_tls) +{ + if (Ql_iotGetWorkState() == 0 || FALSE == mp_obj_is_bool(mp_tls)) + { + return mp_obj_new_bool(FALSE); + } + if (FALSE == Ql_iotConfigSetHttpOtaTls(mp_const_true == mp_tls ? TRUE : FALSE)) + { + return mp_obj_new_bool(FALSE); + } + return mp_obj_new_bool(TRUE); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_Ql_iotConfigSetHttpOtaTls_obj, qpy_Ql_iotConfigSetHttpOtaTls); +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotConfigGetHttpOtaTls(void) +{ + if (Ql_iotGetWorkState() == 0) + { + return mp_const_none; + } + return mp_obj_new_bool(Ql_iotConfigGetHttpOtaTls()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(qpy_Ql_iotConfigGetHttpOtaTls_obj, qpy_Ql_iotConfigGetHttpOtaTls); +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotConfigSetHttpOtaServer(mp_obj_t mp_server) +{ + if (Ql_iotGetWorkState() == 0) + { + return mp_obj_new_bool(FALSE); + } + mp_buffer_info_t serverinfo = {0}; + mp_get_buffer_raise(mp_server, &serverinfo, MP_BUFFER_READ); + if (FALSE == Ql_iotConfigSetHttpOtaServer((const char *)serverinfo.buf)) + { + return mp_obj_new_bool(FALSE); + } + return mp_obj_new_bool(TRUE); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_Ql_iotConfigSetHttpOtaServer_obj, qpy_Ql_iotConfigSetHttpOtaServer); +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotConfigGetHttpOtaServer(void) +{ + if (Ql_iotGetWorkState() == 0) + { + return mp_const_none; + } + char *server = NULL; + + Ql_iotConfigGetHttpOtaServer(&server); + return mp_obj_new_str(server, strlen(server)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(qpy_Ql_iotConfigGetHttpOtaServer_obj, qpy_Ql_iotConfigGetHttpOtaServer); + +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotConfigSetHttpOtaUp(mp_obj_t mp_battery, mp_obj_t mp_upmode, mp_obj_t mp_url) +{ + if (Ql_iotGetWorkState() == 0) + { + return mp_obj_new_bool(FALSE); + } + int battery = mp_obj_get_int(mp_battery); + int upmode = mp_obj_get_int(mp_upmode); + mp_buffer_info_t url = {0}; + mp_get_buffer_raise(mp_url, &url, MP_BUFFER_READ); + if (FALSE == Ql_iotConfigSetHttpOtaUp(battery, upmode, (const char *)url.buf)) + { + return mp_obj_new_bool(FALSE); + } + return mp_obj_new_bool(TRUE); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(qpy_Ql_iotConfigSetHttpOtaUp_obj, qpy_Ql_iotConfigSetHttpOtaUp); +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotConfigGetHttpOtaUp(void) +{ + if (Ql_iotGetWorkState() == 0) + { + return mp_const_none; + } + quint8_t battery, upmode; + char *url = NULL; + + Ql_iotConfigGetHttpOtaUp(&battery, &upmode, &url); + mp_obj_t info[3] = + { + mp_obj_new_int(battery), + mp_obj_new_int(upmode), + mp_obj_new_str(url, strlen(url)), + }; + return mp_obj_new_tuple(3, info); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(qpy_Ql_iotConfigGetHttpOtaUp_obj, qpy_Ql_iotConfigGetHttpOtaUp); + +/************************************************************************** +** 鍔熻兘 @brief : +** 杈撳叆 @param : +** 杈撳嚭 @retval: +***************************************************************************/ +static mp_obj_t Ql_iotUrcHttpOtaEventCB = NULL; +static void ql_iotHttpOTAEventCB(quint32_t event, qint32_t errcode, const void *valueT, quint32_t valLen) +{ + if (NULL == Ql_iotUrcHttpOtaEventCB) + { + return; + } + if (NULL == valueT) + { + mp_obj_t tuple[] = + { + mp_obj_new_int_from_uint(event), + mp_obj_new_int_from_uint(errcode)}; + mp_sched_schedule(Ql_iotUrcHttpOtaEventCB, mp_obj_new_tuple(2, tuple)); + } + else + { + mp_obj_t tuple[] = + { + mp_obj_new_int_from_uint(event), + mp_obj_new_int_from_uint(errcode), + mp_obj_new_bytes(valueT, valLen)}; + mp_sched_schedule(Ql_iotUrcHttpOtaEventCB, mp_obj_new_tuple(3, tuple)); + } +} +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotConfigSetHttpOtaEventCb(mp_obj_t event_urc_cb) +{ + if (Ql_iotGetWorkState() == 0) + { + return mp_obj_new_bool(FALSE); + } + Ql_iotUrcHttpOtaEventCB = event_urc_cb; + Ql_iotConfigSetHttpOtaEventCb(ql_iotHttpOTAEventCB); + return mp_obj_new_bool(TRUE); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_Ql_iotConfigSetHttpOtaEventCb_obj, qpy_Ql_iotConfigSetHttpOtaEventCb); +#endif +#ifdef QUEC_ENABLE_GATEWAY +/************************************************************************** +** @brief : 浣跨敤鍥炶皟鍑芥暟灏嗘暟鎹粍鍖呭苟鎶婃暟鎹彂閫佸埌Python搴旂敤灞 +** @param : +** @retval: +***************************************************************************/ +static mp_obj_t Ql_iotSubDevUrcEventCB = NULL; +static void ql_iotSubDevEventCB(quint32_t event, qint32_t errcode, const char *subPk, const char *subDk, const void *valueT, quint32_t valLen) +{ + if (NULL == Ql_iotSubDevUrcEventCB) + { + return; + } + if (NULL == valueT) + { + mp_obj_t tuple[] = + { + mp_obj_new_bytes((const quint8_t*)subPk, strlen(subDk)), + mp_obj_new_bytes((const quint8_t*)subDk, strlen(subDk)), + mp_obj_new_int_from_uint(event), + mp_obj_new_int_from_uint(errcode)}; + mp_sched_schedule(Ql_iotSubDevUrcEventCB, mp_obj_new_tuple(4, tuple)); + } + else if (QIOT_ATEVENT_TYPE_RECV == event && QIOT_RECV_SUCC_PHYMODEL_RECV == errcode) + { + quint32_t count = Ql_iotTtlvCountGet(valueT); + mp_obj_t node_dict = mp_obj_new_dict(count); + if (ttlv_dict_handle(valueT, count, node_dict)) + { + mp_obj_t tuple[] = + { + mp_obj_new_bytes((const quint8_t*)subPk, strlen(subPk)), + mp_obj_new_bytes((const quint8_t*)subDk, strlen(subDk)), + mp_obj_new_int_from_uint(event), + mp_obj_new_int_from_uint(errcode), + node_dict}; + mp_sched_schedule(Ql_iotSubDevUrcEventCB, mp_obj_new_tuple(5, tuple)); + } + } + else if (QIOT_ATEVENT_TYPE_RECV == event && QIOT_RECV_SUCC_PHYMODEL_REQ == errcode) + { + quint16_t pkgId = *(quint16_t *)valueT; + quint16_t *ids = (quint16_t *)((quint8_t *)valueT + sizeof(quint16_t)); + mp_obj_t req_list = mp_obj_new_list(0, NULL); + mp_obj_t req_list_temp = mp_obj_new_list(0, NULL); + mp_obj_list_append(req_list, mp_obj_new_int((mp_int_t)pkgId)); + for (quint32_t i = 0; i < valLen; i++) + { + quint16_t modelId = ids[i]; + mp_obj_list_append(req_list_temp, mp_obj_new_int((mp_int_t)modelId)); + } + mp_obj_list_append(req_list, req_list_temp); + mp_obj_t tuple[] = + { + mp_obj_new_bytes((const quint8_t*)subPk, strlen(subPk)), + mp_obj_new_bytes((const quint8_t*)subDk, strlen(subDk)), + mp_obj_new_int_from_uint(event), + mp_obj_new_int_from_uint(errcode), + req_list}; + mp_sched_schedule(Ql_iotSubDevUrcEventCB, mp_obj_new_tuple(5, tuple)); + } + else + { + mp_obj_t tuple[] = + { + mp_obj_new_bytes((const quint8_t*)subPk, strlen(subPk)), + mp_obj_new_bytes((const quint8_t*)subDk, strlen(subDk)), + mp_obj_new_int_from_uint(event), + mp_obj_new_int_from_uint(errcode), + mp_obj_new_bytes(valueT, valLen)}; + mp_sched_schedule(Ql_iotSubDevUrcEventCB, mp_obj_new_tuple(5, tuple)); + } +} +/************************************************************************** +** @brief : 娉ㄥ唽瀛愯澶囦簨浠跺洖璋冨嚱鏁 +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotSubDevSetEventCB(mp_obj_t event_sub_dev_urc_cb) +{ + if (Ql_iotGetWorkState() == 0) + { + return mp_obj_new_bool(FALSE); + } + Ql_iotSubDevUrcEventCB = event_sub_dev_urc_cb; + Ql_iotConfigSetSubDevEventCB(ql_iotSubDevEventCB); + return mp_obj_new_bool(TRUE); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(qpy_Ql_iotSubDevSetEventCB_obj, qpy_Ql_iotSubDevSetEventCB); +/************************************************************************** +** @brief : 鍙戣捣瀛愯澶囪繛鎺 +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotSubDevConn(size_t n, const mp_obj_t *mp_data) +{ + if (Ql_iotGetWorkState() == 0 + || !mp_obj_is_str(mp_data[0])|| !mp_obj_is_str(mp_data[1])|| !mp_obj_is_str(mp_data[2])) + { + printf("false...\n"); + return mp_obj_new_bool(FALSE); + } + mp_buffer_info_t pro_keyinfo = {0}; + mp_buffer_info_t pro_secretinfo = {0}; + mp_buffer_info_t dev_keyinfo = {0}; + mp_buffer_info_t dev_secretinfo = {0}; + int session_type_val; + int keepalive_val; + mp_get_buffer_raise(mp_data[0], &pro_keyinfo, MP_BUFFER_READ); + mp_get_buffer_raise(mp_data[1], &pro_secretinfo, MP_BUFFER_READ); + mp_get_buffer_raise(mp_data[2], &dev_keyinfo, MP_BUFFER_READ); + if(5 == n) + { + session_type_val = mp_obj_get_int(mp_data[3]); + keepalive_val = mp_obj_get_int(mp_data[4]); + } + else + { + mp_get_buffer_raise(mp_data[3], &dev_secretinfo, MP_BUFFER_READ); + session_type_val = mp_obj_get_int(mp_data[4]); + keepalive_val = mp_obj_get_int(mp_data[5]); + } + + if (FALSE == Ql_iotSubDevConn((const char *)pro_keyinfo.buf, (const char *)pro_secretinfo.buf, (const char *)dev_keyinfo.buf, (const char *)dev_secretinfo.buf, session_type_val, keepalive_val)) + { + return mp_obj_new_bool(FALSE); + } + return mp_obj_new_bool(TRUE); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(qpy_Ql_iotSubDevConn_obj, 5,6, qpy_Ql_iotSubDevConn); +/************************************************************************** +** @brief : 鍙戣捣瀛愯澶囩櫥鍑 +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotSubDevDisconn(mp_obj_t product_key, mp_obj_t device_key) +{ + if (Ql_iotGetWorkState() == 0) + { + return mp_obj_new_bool(FALSE); + } + mp_buffer_info_t pro_key = {0}; + mp_buffer_info_t dev_key = {0}; + mp_get_buffer_raise(product_key, &pro_key, MP_BUFFER_READ); + mp_get_buffer_raise(device_key, &dev_key, MP_BUFFER_READ); + if (FALSE == Ql_iotSubDevDisconn((const char *)pro_key.buf, (const char *)dev_key.buf)) + { + return mp_obj_new_bool(FALSE); + } + return mp_obj_new_bool(TRUE); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(qpy_Ql_iotSubDevDisconn_obj, qpy_Ql_iotSubDevDisconn); +/************************************************************************** +** @brief : 鍙戣捣瀛愯澶囨敞閿 +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotSubDevDeauth(size_t n, const mp_obj_t *mp_data) +{ + if (Ql_iotGetWorkState() == 0 || + !mp_obj_is_str(mp_data[0])|| !mp_obj_is_str(mp_data[1])|| !mp_obj_is_str(mp_data[2])|| !mp_obj_is_str(mp_data[3])) + { + return mp_obj_new_bool(FALSE); + } + mp_buffer_info_t pro_key = {0}; + mp_buffer_info_t pro_secret = {0}; + mp_buffer_info_t dev_key = {0}; + mp_buffer_info_t dev_secret = {0}; + mp_get_buffer_raise(mp_data[0], &pro_key, MP_BUFFER_READ); + mp_get_buffer_raise(mp_data[1], &pro_secret, MP_BUFFER_READ); + mp_get_buffer_raise(mp_data[2], &dev_key, MP_BUFFER_READ); + mp_get_buffer_raise(mp_data[3], &dev_secret, MP_BUFFER_READ); + if (FALSE == Ql_iotSubDevDeauth((const char *)pro_key.buf, (const char *)pro_secret.buf, (const char *)dev_key.buf, (const char *)dev_secret.buf)) + { + return mp_obj_new_bool(FALSE); + } + return mp_obj_new_bool(TRUE); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(qpy_Ql_iotSubDevDeauth_obj, 4, 4, qpy_Ql_iotSubDevDeauth); +/************************************************************************** +** @brief : 涓婅瀛愯澶囬忎紶鏁版嵁 +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotSubDevPassTransSend(mp_obj_t product_key, mp_obj_t device_key, mp_obj_t mp_data) +{ + mp_buffer_info_t data = {0}; + mp_buffer_info_t pro_key = {0}; + mp_buffer_info_t dev_key = {0}; + mp_get_buffer_raise(product_key, &pro_key, MP_BUFFER_READ); + mp_get_buffer_raise(device_key, &dev_key, MP_BUFFER_READ); + mp_get_buffer_raise(mp_data, &data, MP_BUFFER_READ); + if (FALSE == Ql_iotSubDevPassTransSend((const char *)pro_key.buf, (const char *)dev_key.buf, (quint8_t *)data.buf, data.len)) + { + return mp_obj_new_bool(FALSE); + } + return mp_obj_new_bool(TRUE); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(qpy_Ql_iotSubDevPassTransSend_obj, qpy_Ql_iotSubDevPassTransSend); +/************************************************************************** +** @brief : 涓婅瀛愯澶囩墿妯″瀷鏁版嵁 +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotSubDevTslReport(mp_obj_t product_key, mp_obj_t device_key, mp_obj_t mp_data) +{ + mp_obj_t ret = mp_const_true; + void *ttlvHead = NULL; + if (phy_dict_handle(mp_data, &ttlvHead)) + { + mp_buffer_info_t pro_key = {0}; + mp_buffer_info_t dev_key = {0}; + mp_get_buffer_raise(product_key, &pro_key, MP_BUFFER_READ); + mp_get_buffer_raise(device_key, &dev_key, MP_BUFFER_READ); + if (FALSE == Ql_iotSubDevTslReport((const char *)pro_key.buf, (const char *)dev_key.buf, ttlvHead)) + { + ret = mp_const_false; + } + } + else + { + ret = mp_const_false; + } + Ql_iotTtlvFree(&ttlvHead); + return ret; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(qpy_Ql_iotSubDevTslReport_obj, qpy_Ql_iotSubDevTslReport); +/************************************************************************** +** @brief : 瀛愯澶囧洖澶嶇墿妯″瀷鏌ヨ +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotSubDevTslAck(size_t n, const mp_obj_t *mp_data) +{ + if (!mp_obj_is_str(mp_data[0])|| !mp_obj_is_str(mp_data[1])|| !mp_obj_is_int(mp_data[2])) + { + return mp_obj_new_bool(FALSE); + } + int pkgid = mp_obj_get_int(mp_data[2]); + mp_obj_t ret = mp_const_true; + void *ttlvHead = NULL; + if (phy_dict_handle(mp_data[3], &ttlvHead)) + { + mp_buffer_info_t pro_key = {0}; + mp_buffer_info_t dev_key = {0}; + mp_get_buffer_raise(mp_data[0], &pro_key, MP_BUFFER_READ); + mp_get_buffer_raise(mp_data[1], &dev_key, MP_BUFFER_READ); + if (FALSE == Ql_iotSubDevTslAck((const char *)pro_key.buf, (const char *)dev_key.buf, (quint16_t)pkgid, ttlvHead)) + { + ret = mp_const_false; + } + } + else + { + ret = mp_const_false; + } + Ql_iotTtlvFree(&ttlvHead); + return ret; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(qpy_Ql_iotSubDevTslAck_obj, 4, 4, qpy_Ql_iotSubDevTslAck); +/************************************************************************** +** @brief : 瀛愯澶囧彂閫佸績璺冲寘 +** @param : +** @retval: +***************************************************************************/ +STATIC mp_obj_t qpy_Ql_iotSubDevHTB(mp_obj_t product_key, mp_obj_t device_key) +{ + mp_buffer_info_t pro_key = {0}; + mp_buffer_info_t dev_key = {0}; + mp_get_buffer_raise(product_key, &pro_key, MP_BUFFER_READ); + mp_get_buffer_raise(device_key, &dev_key, MP_BUFFER_READ); + + if (FALSE == Ql_iotSubDevHTB((const char *)pro_key.buf, (const char *)dev_key.buf)) + { + return mp_obj_new_bool(FALSE); + } + return mp_obj_new_bool(TRUE); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(qpy_Ql_iotSubDevHTB_obj, qpy_Ql_iotSubDevHTB); +#endif +/************************************************************************** +** @brief : +** @param : +** @retval: +***************************************************************************/ +STATIC const mp_rom_map_elem_t mp_module_quecIot_globals_table[] = { + {MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_quecIot)}, + {MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&qpy_Ql_iotInit_obj)}, + {MP_ROM_QSTR(MP_QSTR_setConnmode), MP_ROM_PTR(&qpy_Ql_iotConfigSetConnmode_obj)}, + {MP_ROM_QSTR(MP_QSTR_getConnmode), MP_ROM_PTR(&qpy_Ql_iotConfigGetConnmode_obj)}, + {MP_ROM_QSTR(MP_QSTR_setEventCB), MP_ROM_PTR(&qpy_Ql_iotConfigSetEventCB_obj)}, + {MP_ROM_QSTR(MP_QSTR_getWorkState), MP_ROM_PTR(&qpy_Ql_iotGetWorkState_obj)}, + {MP_ROM_QSTR(MP_QSTR_setProductinfo), MP_ROM_PTR(&qpy_Ql_iotConfigSetProductinfo_obj)}, + {MP_ROM_QSTR(MP_QSTR_getProductinfo), MP_ROM_PTR(&qpy_Ql_iotConfigGetProductinfo_obj)}, + {MP_ROM_QSTR(MP_QSTR_setServer), MP_ROM_PTR(&qpy_Ql_iotConfigSetServer_obj)}, + {MP_ROM_QSTR(MP_QSTR_getServer), MP_ROM_PTR(&qpy_Ql_iotConfigGetServer_obj)}, + {MP_ROM_QSTR(MP_QSTR_setLifetime), MP_ROM_PTR(&qpy_Ql_iotConfigSetLifetime_obj)}, + {MP_ROM_QSTR(MP_QSTR_getLifetime), MP_ROM_PTR(&qpy_Ql_iotConfigGetLifetime_obj)}, + {MP_ROM_QSTR(MP_QSTR_setSessionFlag), MP_ROM_PTR(&qpy_Ql_iotConfigSetSessionFlag_obj)}, + {MP_ROM_QSTR(MP_QSTR_getSessionFlag), MP_ROM_PTR(&qpy_Ql_iotConfigGetSessionFlag_obj)}, + {MP_ROM_QSTR(MP_QSTR_setPdpContextId), MP_ROM_PTR(&qpy_Ql_iotConfigSetPdpContextId_obj)}, + {MP_ROM_QSTR(MP_QSTR_getPdpContextId), MP_ROM_PTR(&qpy_Ql_iotConfigGetPdpContextId_obj)}, + {MP_ROM_QSTR(MP_QSTR_getSoftVersion), MP_ROM_PTR(&qpy_Ql_iotConfigGetSoftVersion_obj)}, + {MP_ROM_QSTR(MP_QSTR_setMcuVersion), MP_ROM_PTR(&qpy_Ql_iotConfigSetMcuVersion_obj)}, + {MP_ROM_QSTR(MP_QSTR_getMcuVersion), MP_ROM_PTR(&qpy_Ql_iotConfigGetMcuVersion_obj)}, + {MP_ROM_QSTR(MP_QSTR_setDkDs), MP_ROM_PTR(&qpy_Ql_iotConfigSetDkDs_obj)}, + {MP_ROM_QSTR(MP_QSTR_getDkDs), MP_ROM_PTR(&qpy_Ql_iotConfigGetDkDs_obj)}, + + {MP_ROM_QSTR(MP_QSTR_passTransSend), MP_ROM_PTR(&qpy_Ql_iotCmdBusPassTransSend_obj)}, + {MP_ROM_QSTR(MP_QSTR_phymodelReport), MP_ROM_PTR(&qpy_Ql_iotCmdBusPhymodelReport_obj)}, + {MP_ROM_QSTR(MP_QSTR_phymodelAck), MP_ROM_PTR(&qpy_Ql_iotCmdBusPhymodelAck_obj)}, + {MP_ROM_QSTR(MP_QSTR_getDevStatus), MP_ROM_PTR(&qpy_Ql_iotCmdSysGetDevStatus_obj)}, + {MP_ROM_QSTR(MP_QSTR_getDevInfo), MP_ROM_PTR(&qpy_Ql_iotCmdSysGetDevInfo_obj)}, + {MP_ROM_QSTR(MP_QSTR_statusReport), MP_ROM_PTR(&qpy_Ql_iotCmdSysStatusReport_obj)}, + {MP_ROM_QSTR(MP_QSTR_devInfoReport), MP_ROM_PTR(&qpy_Ql_iotCmdSysDevInfoReport_obj)}, + + {MP_ROM_QSTR(MP_QSTR_getLocSupList), MP_ROM_PTR(&qpy_Ql_iotCmdGetLocSupList_obj)}, + {MP_ROM_QSTR(MP_QSTR_getLocData), MP_ROM_PTR(&qpy_Ql_iotCmdGetLocData_obj)}, + {MP_ROM_QSTR(MP_QSTR_locReportInside), MP_ROM_PTR(&qpy_Ql_iotCmdBusLocReportInside_obj)}, + {MP_ROM_QSTR(MP_QSTR_locReportOutside), MP_ROM_PTR(&qpy_Ql_iotCmdBusLocReportOutside_obj)}, + + {MP_ROM_QSTR(MP_QSTR_otaRequest), MP_ROM_PTR(&qpy_Ql_iotCmdOtaRequest_obj)}, + {MP_ROM_QSTR(MP_QSTR_otaAction), MP_ROM_PTR(&qpy_Ql_iotCmdOtaAction_obj)}, + {MP_ROM_QSTR(MP_QSTR_mcuFWDataRead), MP_ROM_PTR(&qpy_Ql_iotCmdOtaMcuFWDataRead_obj)}, +#ifdef QUEC_ENABLE_HTTP_OTA + {MP_ROM_QSTR(MP_QSTR_setHttpOtaProductInfo), MP_ROM_PTR(&qpy_Ql_iotConfigSetHttpOtaProductInfo_obj)}, + {MP_ROM_QSTR(MP_QSTR_getHttpOtaProductInfo), MP_ROM_PTR(&qpy_Ql_iotConfigGetHttpOtaProductInfo_obj)}, + {MP_ROM_QSTR(MP_QSTR_setHttpOtaTls), MP_ROM_PTR(&qpy_Ql_iotConfigSetHttpOtaTls_obj)}, + {MP_ROM_QSTR(MP_QSTR_getHttpOtaTls), MP_ROM_PTR(&qpy_Ql_iotConfigGetHttpOtaTls_obj)}, + {MP_ROM_QSTR(MP_QSTR_setHttpOtaServer), MP_ROM_PTR(&qpy_Ql_iotConfigSetHttpOtaServer_obj)}, + {MP_ROM_QSTR(MP_QSTR_getHttpOtaServer), MP_ROM_PTR(&qpy_Ql_iotConfigGetHttpOtaServer_obj)}, + {MP_ROM_QSTR(MP_QSTR_setHttpOtaUp), MP_ROM_PTR(&qpy_Ql_iotConfigSetHttpOtaUp_obj)}, + {MP_ROM_QSTR(MP_QSTR_getHttpOtaUp), MP_ROM_PTR(&qpy_Ql_iotConfigGetHttpOtaUp_obj)}, + {MP_ROM_QSTR(MP_QSTR_setHttpOtaEventCb), MP_ROM_PTR(&qpy_Ql_iotConfigSetHttpOtaEventCb_obj)}, +#endif +#ifdef QUEC_ENABLE_GATEWAY + {MP_ROM_QSTR(MP_QSTR_subDevSetEventCB), MP_ROM_PTR(&qpy_Ql_iotSubDevSetEventCB_obj)}, + {MP_ROM_QSTR(MP_QSTR_subDevConn), MP_ROM_PTR(&qpy_Ql_iotSubDevConn_obj)}, + {MP_ROM_QSTR(MP_QSTR_subDevDisconn), MP_ROM_PTR(&qpy_Ql_iotSubDevDisconn_obj)}, + {MP_ROM_QSTR(MP_QSTR_subDevDeauth), MP_ROM_PTR(&qpy_Ql_iotSubDevDeauth_obj)}, + {MP_ROM_QSTR(MP_QSTR_subDevPassTransSend), MP_ROM_PTR(&qpy_Ql_iotSubDevPassTransSend_obj)}, + {MP_ROM_QSTR(MP_QSTR_subDevTslReport), MP_ROM_PTR(&qpy_Ql_iotSubDevTslReport_obj)}, + {MP_ROM_QSTR(MP_QSTR_subDevTslAck), MP_ROM_PTR(&qpy_Ql_iotSubDevTslAck_obj)}, + {MP_ROM_QSTR(MP_QSTR_subDevHTB), MP_ROM_PTR(&qpy_Ql_iotSubDevHTB_obj)}, +#endif +}; +STATIC MP_DEFINE_CONST_DICT(mp_module_quecIot_globals, mp_module_quecIot_globals_table); + +const mp_obj_module_t mp_module_quecIot = { + .base = {&mp_type_module}, + .globals = (mp_obj_dict_t *)&mp_module_quecIot_globals, +}; diff --git a/driverLayer/Qhal_types.h b/driverLayer/Qhal_types.h index 326d4e6b3078496eb97167763a1e7f876ed67262..10b0486a6bb41548b1085a3360d63cd69ce9c658 100644 --- a/driverLayer/Qhal_types.h +++ b/driverLayer/Qhal_types.h @@ -40,6 +40,7 @@ typedef unsigned char qbool; #define FUNCTION_ATTR_RAM +#define QUEC_ENABLE_QTH_OTA 1 #define HAL_MEMCPY(a,b,l) memcpy((quint8_t*)(a),(quint8_t*)(b),l) #define HAL_MEMCMP(a,b,l) memcmp((quint8_t*)(a),(quint8_t*)(b),l) #define HAL_MEMSET(a,b,l) memset((void *)a, (int)b, (size_t)l) diff --git a/driverLayer/qhal_Dev.c b/driverLayer/qhal_Dev.c index 07c2163d7cf388208db3c6310481986ee4e55f3c..dd3ade92f941b2294d814d489f97c9ea4533b545 100644 --- a/driverLayer/qhal_Dev.c +++ b/driverLayer/qhal_Dev.c @@ -49,6 +49,7 @@ static Systick_T RtcTime = {0,0}; HAL_LOCK_DEF(static, lockMallocId) +//HAL_LOCK_DEF(static, lockKernelId) /************************************************************************** ** 功能 @brief : 看门狗喂狗 ** 输入 @param : @@ -343,12 +344,13 @@ void qhal_MainTask(void *argv) Helios_Thread_Delete(Helios_Thread_GetID()); return; } - Ql_iotInit(); + //Ql_iotInit(); + Quos_logPrintf(HAL_DEV, LL_DBG," qhal_MainTask\r\n"); while (1) { quint32_t msg = 1; quint32_t idletime = Quos_kernelTask(); - Quos_logPrintf(HAL_DEV, LL_DBG,"exec:%u\r\n", idletime); + Quos_logPrintf(HAL_DEV, LL_DBG," idletime exec:%u\r\n", idletime); if(idletime) { Helios_MsgQ_Get(msg_quos_task, (void *)&msg, sizeof(quint32_t), idletime); @@ -366,7 +368,7 @@ qbool FUNCTION_ATTR_ROM Qhal_quecsdk_init(void) qhal_main_ref.entry = qhal_MainTask; qhal_main_ref.priority = QHAL_APP_TASK_PRIORITY; qhal_main_ref.stack_size = 1024 * 64; - if(0 >= Helios_Thread_Create(&qhal_main_ref)) + if(0 == Helios_Thread_Create(&qhal_main_ref)) { Helios_Debug_Output("[INIT]Helios_Thread_Create fail"); return FALSE; @@ -381,6 +383,7 @@ qbool FUNCTION_ATTR_ROM Qhal_quecsdk_init(void) qbool FUNCTION_ATTR_ROM Qhal_beforeMain(void) { HAL_LOCK_INIT(lockMallocId); + //HAL_LOCK_INIT(lockKernelId); #if defined (PLAT_Unisoc) Quos_logPrintf(HAL_DEV, LL_DBG,"********** This is PLAT_Unisoc **********"); #elif defined (PLAT_ASR) @@ -390,6 +393,22 @@ qbool FUNCTION_ATTR_ROM Qhal_beforeMain(void) #endif return TRUE; } + +/************************************************************************** +** 鍔熻兘 @brief : 閫鍑轰换鍔℃寕璧锋ā寮 +** 杈撳叆 @param : +** 杈撳嚭 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Qhal_KernelResume(void) +{ + quint32_t msg = 1; + if(msg_quos_task) + { + Helios_MsgQ_Put(msg_quos_task, (void *)&msg, sizeof(quint32_t), HELIOS_NO_WAIT); + } + //HAL_UNLOCK(lockKernelId); +} + /************************************************************************** ** 功能 @brief : 退出低功耗模式 ** 输入 @param : diff --git a/driverLayer/qhal_Dev.h b/driverLayer/qhal_Dev.h index f83a665c5ea7be807116558e0155e0c793bb3402..2a5e46220f8b3846ef25cfe7e9972dd00d24e98b 100644 --- a/driverLayer/qhal_Dev.h +++ b/driverLayer/qhal_Dev.h @@ -12,16 +12,23 @@ typedef enum DEV_RESTART_HW_FAULT, } DevRestartReason_e; +#define QIOT_MD5_MAXSIZE (32) +typedef struct +{ + uint8_t idex; + char md5[QIOT_MD5_MAXSIZE + 1]; + char *downloadUrl; + quint32_t size; +} QIot_otaFilePublicInfo_t; #define DEV_RESTART_REASON_STRING(X) \ ( \ - (X == DEV_RESTART_FACTORY) ? "DEV_RESTART_FACTORY" : \ - (X == DEV_RESTART_SEGMENTFAULT) ? "DEV_RESTART_SEGMENTFAULT" : \ - (X == DEV_RESTART_NORMAL) ? "DEV_RESTART_NORMAL" : \ - (X == DEV_RESTART_OTA) ? "DEV_RESTART_OTA" : \ - (X == DEV_RESTART_WDT) ? "DEV_RESTART_WDT" : \ - (X == DEV_RESTART_NET_EXCP) ? "DEV_RESTART_NET_EXCP" : \ - (X == DEV_RESTART_HW_FAULT) ? "DEV_RESTART_HW_FAULT" : \ - "Unknown") + (X == DEV_RESTART_FACTORY) ? "DEV_RESTART_FACTORY" : (X == DEV_RESTART_SEGMENTFAULT) ? "DEV_RESTART_SEGMENTFAULT" \ + : (X == DEV_RESTART_NORMAL) ? "DEV_RESTART_NORMAL" \ + : (X == DEV_RESTART_OTA) ? "DEV_RESTART_OTA" \ + : (X == DEV_RESTART_WDT) ? "DEV_RESTART_WDT" \ + : (X == DEV_RESTART_NET_EXCP) ? "DEV_RESTART_NET_EXCP" \ + : (X == DEV_RESTART_HW_FAULT) ? "DEV_RESTART_HW_FAULT" \ + : "Unknown") void Qhal_devFeeddog(void); qbool Qhal_rtcInit(void); @@ -33,10 +40,17 @@ void Qhal_devRestart(void); qbool Qhal_beforeMain(void); char *Qhal_devUuidGet(void); quint32_t Qhal_randomGet(void); -#ifdef AT_ENABLE_QUEC +#ifdef QUEC_ENABLE_AT void Qhal_urcReport(const quint8_t *data, quint32_t len); #endif +#if QUEC_ENABLE_QTH_OTA quint32_t Qhal_devOtaNotify(const char *filename, quint32_t fileSize); +#else +quint32_t Qhal_devOtaNotify(QIot_otaFilePublicInfo_t info[], quint32_t size); +#endif +void Qhal_KernelResume(void); void Qhal_netOpen(quint32_t *timeout); void Qhal_netClose(void); -#endif \ No newline at end of file + +qbool FUNCTION_ATTR_ROM Qhal_quecsdk_init(void); +#endif diff --git a/driverLayer/qhal_Socket.c b/driverLayer/qhal_Socket.c index 5f54f0e4cb4c08b54fa9bca3b850925a3f88d727..a2e8647ada02fc59d64fdc50bc206feca7407f40 100644 --- a/driverLayer/qhal_Socket.c +++ b/driverLayer/qhal_Socket.c @@ -190,7 +190,7 @@ static void qhal_SockTcpRecvTask(void *arg) bufLen = read(sockFd, tcp_buf, sizeof(tcp_buf)); if (bufLen > 0) { - Quos_socketIORx(sockFd, SOCKET_TYPE_TCP_CLI, NULL, tcp_buf, bufLen); + Quos_socketIORx(sockFd, SOCKET_TYPE_TCP_CLI, NULL, 0, tcp_buf, bufLen); } else { @@ -199,7 +199,7 @@ static void qhal_SockTcpRecvTask(void *arg) } } Quos_logPrintf(HAL_SOCK, LL_DBG, "sockFd:" PRINTF_FD " len:%d result %d error:%d", sockFd, (int)bufLen, result, (int)errno); - Quos_socketIORx(sockFd, SOCKET_TYPE_TCP_CLI, NULL, NULL, 0); + Quos_socketIORx(sockFd, SOCKET_TYPE_TCP_CLI, NULL, 0, NULL, 0); Helios_Thread_Delete(Helios_Thread_GetID()); } @@ -309,7 +309,7 @@ pointer_t FUNCTION_ATTR_ROM Qhal_tcpClientInit(quint8_t *type, const char *hostn flag = fcntl(sockFd, F_GETFL, 0); //获取文件的flags值。 fcntl(sockFd, F_SETFL, flag | ~O_NONBLOCK); //设置成阻塞模式; lwip_freeaddrinfo(dns); - if(0 >= Helios_Thread_Create(&TcpRecvTask)) + if(0 == Helios_Thread_Create(&TcpRecvTask)) { close(sockFd); return SOCKET_FD_INVALID; @@ -345,7 +345,7 @@ static void qhal_SockTcpTlsRecvTask(void *arg) int len = mbedtls_ssl_read(&sockSslCtx->ssl_ctx, buf, sizeof(buf)); if (len > 0) { - Quos_socketIORx((pointer_t)sockSslCtx, SOCKET_TYPE_TCP_SSL_CLI, NULL, buf, len); + Quos_socketIORx((pointer_t)sockSslCtx, SOCKET_TYPE_TCP_SSL_CLI, NULL, 0, buf, len); } else if (MBEDTLS_ERR_SSL_WANT_READ != len && MBEDTLS_ERR_SSL_WANT_WRITE != len) { @@ -354,7 +354,7 @@ static void qhal_SockTcpTlsRecvTask(void *arg) } Quos_logPrintf(HAL_TCP, LL_INFO,"tcp q"); - Quos_socketIORx((pointer_t)sockSslCtx, SOCKET_TYPE_TCP_SSL_CLI, NULL, NULL, 0); + Quos_socketIORx((pointer_t)sockSslCtx, SOCKET_TYPE_TCP_SSL_CLI, NULL, 0, NULL, 0); HAL_FREE(sockSslCtx); Helios_Thread_Delete(Helios_Thread_GetID()); } @@ -470,7 +470,7 @@ pointer_t FUNCTION_ATTR_ROM Qhal_tcpSslClientInit(quint8_t *type, const char *ho TcpTlsRecvTask.entry = qhal_SockTcpTlsRecvTask; TcpTlsRecvTask.priority = QHAL_APP_TASK_PRIORITY+2; TcpTlsRecvTask.stack_size = 1024*10; - if(0 >= Helios_Thread_Create(&TcpTlsRecvTask)) + if(0 == Helios_Thread_Create(&TcpTlsRecvTask)) { Quos_logPrintf(HAL_TLS, LL_ERR, "pthread fail"); goto exit; @@ -508,3 +508,30 @@ pointer_t FUNCTION_ATTR_ROM Qhal_udpSslInit(quint8_t *type, quint16_t l_port, co UNUSED(r_port); return SOCKET_FD_INVALID; } + +/************************************************************************** +** 锟斤拷锟斤拷 @brief : 锟斤拷锟斤拷URL锟斤拷锟斤拷为IP +** 锟斤拷锟斤拷 @param : hostname: 锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷 + retAddr锟斤拷锟斤拷锟斤拷锟斤拷锟侥碉拷锟绞絀P锟叫憋拷锟斤拷锟斤拷锟絀P锟斤拷锟饺诧拷锟斤拷锟斤拷46 + addrMax锟斤拷锟斤拷锟缴斤拷锟杰碉拷IP锟斤拷锟斤拷 +** 锟斤拷锟 @retval: 锟斤拷锟斤拷锟斤拷实锟斤拷锟杰斤拷锟斤拷锟斤拷IP锟斤拷锟斤拷 +***************************************************************************/ +quint32_t FUNCTION_ATTR_ROM Qhal_dns2IPGet(const char *hostname, quint8_t **retAddr, quint32_t addrMax) +{ + struct hostent *host = NULL; + if (NULL == (host = gethostbyname(hostname))) + { + return 0; + } + quint32_t i; + for (i = 0; i < addrMax; i++) + { + if (NULL == host->h_addr_list[i]) + { + break; + } + HAL_STRCPY(retAddr[i], inet_ntoa(*(struct in_addr *)host->h_addr_list[i])); + } + return i; +} + diff --git a/driverLayer/qhal_Socket.h b/driverLayer/qhal_Socket.h index 775caded3544163100875f67ba734a932deb3066..0533175dc1b0f74b8df490af0ff2a4c712e21a44 100644 --- a/driverLayer/qhal_Socket.h +++ b/driverLayer/qhal_Socket.h @@ -19,4 +19,6 @@ pointer_t Qhal_tcpSslClientInit(quint8_t *type, const char *hostname, quint16_t pointer_t Qhal_udpSslInit(quint8_t *type, quint16_t l_port, const char *hostname, quint16_t r_port); qbool Qhal_sockWrite(pointer_t sockFd, quint8_t type, const void *peer, const quint8_t *buf, quint16_t bufLen, qbool *isSending); void Qhal_sockClose(pointer_t sockFd, quint8_t type); -#endif \ No newline at end of file + +quint32_t FUNCTION_ATTR_ROM Qhal_dns2IPGet(const char *hostname, quint8_t **retAddr, quint32_t addrMax); +#endif diff --git a/driverLayer/qhal_property.c b/driverLayer/qhal_property.c index d8998c27927b1f5e09db00c36f4bb7077240a65f..f2102157d48c4095c57d87f88af3bbcf5b9983a4 100644 --- a/driverLayer/qhal_property.c +++ b/driverLayer/qhal_property.c @@ -217,7 +217,7 @@ quint32_t Qhal_propertyLocSupList(char **words, quint32_t maxSize) { UNUSED(maxSize); quint32_t i = 0; - words[i++] = QIOT_LOC_SUPPORT_NONE; + words[i++] = "NONE"; // words[i++] = QIOT_LOC_SUPPORT_AUTO; words[i++] = QIOT_LOC_SUPPORT_LBS; return i; diff --git a/driverLayer/qhal_property.h b/driverLayer/qhal_property.h index 2650a1dd7e93b1c8fdae150e21ef7a80a0a46034..f2b36d2a12a550dd909e3d7f401d6b74dab28143 100644 --- a/driverLayer/qhal_property.h +++ b/driverLayer/qhal_property.h @@ -6,7 +6,6 @@ extern "C" { #endif -#define QIOT_LOC_SUPPORT_NONE "NONE" #define QIOT_LOC_SUPPORT_AUTO "AUTO" #define QIOT_LOC_SUPPORT_LBS "LBS" typedef struct diff --git a/kernel/Quos_kernel.c b/kernel/Quos_kernel.c new file mode 100644 index 0000000000000000000000000000000000000000..ba345c5bd7a4aee1bfd2d46272ffa63d4fad1ba1 --- /dev/null +++ b/kernel/Quos_kernel.c @@ -0,0 +1,50 @@ +/************************************************************************* +** 创建人 @author : 吴健超 JCWu +** 版本 @version : V1.0.0 原始版本 +** 日期 @date : +** 功能 @brief : +** 硬件 @hardware:任何ANSI-C平台 +** 其他 @other : +***************************************************************************/ +#include "Quos_kernel.h" +#include "Qhal_driver.h" + +static qbool QuosKernelIsResume = FALSE; +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Quos_kernelInit(void) +{ + HAL_LOCK_INIT(lockLogId); + Quos_swTimerInit(); + Quos_sysTickInit(); + Quos_socketInit(); + Quos_signalInit(); +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Quos_kernelResume(void) +{ + Qhal_KernelResume(); + QuosKernelIsResume = TRUE; +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +quint32_t FUNCTION_ATTR_ROM Quos_kernelTask(void) +{ + QuosKernelIsResume = FALSE; + quint32_t swTimerIdle = Quos_swTimerTask(); + qbool sigRet = Quos_signalTask(); + quint32_t sockIdle = Quos_socketTask(); + + swTimerIdle = sigRet ? 0 : (swTimerIdle < sockIdle ? swTimerIdle : sockIdle); + return QuosKernelIsResume ? 0 : swTimerIdle; +} diff --git a/kernel/Quos_kernel.h b/kernel/Quos_kernel.h index 743831de1504e696e4091b4e044ee75d9f135bbb..6d759e371904900392d4e858df9665e2f1ba343d 100644 --- a/kernel/Quos_kernel.h +++ b/kernel/Quos_kernel.h @@ -1,27 +1,28 @@ -#ifndef __QUOS_KERNEL_H__ -#define __QUOS_KERNEL_H__ -#include "quos_log.h" -#include "quos_signal.h" -#include "quos_event.h" -#include "quos_SupportTool.h" -#include "quos_swTimer.h" -#include "quos_sysTick.h" -#include "quos_twll.h" -#include "quos_aes.h" -#include "quos_md5.h" -#include "quos_sha1.h" -#include "quos_sha256.h" -#include "quos_base64.h" -#include "quos_dataStore.h" -#include "quos_socket.h" -#include "quos_http.h" -#include "quos_mqtt.h" -#include "quos_coap.h" -#include "quos_lwm2m.h" -#include "quos_fifo.h" -#include "quos_net.h" -#include "quos_cjson.h" - -void Quos_kernelInit(void); -quint32_t Quos_kernelTask(void); +#ifndef __QUOS_KERNEL_H__ +#define __QUOS_KERNEL_H__ +#include "quos_log.h" +#include "quos_signal.h" +#include "quos_event.h" +#include "quos_SupportTool.h" +#include "quos_swTimer.h" +#include "quos_sysTick.h" +#include "quos_twll.h" +#include "quos_aes.h" +#include "quos_md5.h" +#include "quos_sha1.h" +#include "quos_sha256.h" +#include "quos_base64.h" +#include "quos_dataStore.h" +#include "quos_socket.h" +#include "quos_http.h" +#include "quos_mqtt.h" +#include "quos_coap.h" +#include "quos_lwm2m.h" +#include "quos_fifo.h" +#include "quos_net.h" +#include "quos_cjson.h" + +void Quos_kernelInit(void); +quint32_t Quos_kernelTask(void); +void Quos_kernelResume(void); #endif \ No newline at end of file diff --git a/kernel/quos_SupportTool.c b/kernel/quos_SupportTool.c new file mode 100644 index 0000000000000000000000000000000000000000..1e42bc7459fe06e7f69e8c599c082b6c6ba5ab07 --- /dev/null +++ b/kernel/quos_SupportTool.c @@ -0,0 +1,535 @@ +/************************************************************************* +** 创建人 @author : 吴健超 JCWu +** 版本 @version : V1.0.0 原始版本 +** 日期 @date : +** 功能 @brief : 工具类API和宏定义 +** 硬件 @hardware:任何ANSI-C平台 +** 其他 @other : +***************************************************************************/ +#include "quos_SupportTool.h" +#include "quos_md5.h" +#include "Qhal_driver.h" +/************************************************************************** +** 功能 @brief : 得到value以exp为底的指数. +** 输入 @param : value > 0 exp > 1 +** 输出 @retval: 以exp为底的指数值 +***************************************************************************/ +quint8_t FUNCTION_ATTR_ROM Quos_convertToExp(quint32_t value, quint32_t exp) +{ + quint8_t count = 0; + if (exp <= 1) + { + return 0; + } + + while (value) + { + value = value / exp; + count++; + } + return count - 1; +} + +/************************************************************************** +** 功能 @brief : 将字节流转为字符串 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +quint32_t FUNCTION_ATTR_ROM Quos_hex2Str(quint8_t hex[], quint32_t hexLen, char *retStr, qbool isUpper) +{ + char Hex2strLBuf[] = "0123456789abcdef"; + char Hex2strUBuf[] = "0123456789ABCDEF"; + quint32_t i; + if (isUpper) + { + for (i = 0; i < hexLen; i++) + { + retStr[i << 1] = Hex2strUBuf[hex[i] >> 4]; + retStr[(i << 1) + 1] = Hex2strUBuf[hex[i] & 0x0F]; + } + } + else + { + for (i = 0; i < hexLen; i++) + { + retStr[i << 1] = Hex2strLBuf[hex[i] >> 4]; + retStr[(i << 1) + 1] = Hex2strLBuf[hex[i] & 0x0F]; + } + } + retStr[i << 1] = 0; + return hexLen * 2; +} + +/************************************************************************** +** 功能 @brief : 将字符串转为字节流 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +quint32_t FUNCTION_ATTR_ROM Quos_str2Hex(void *srcStr, quint8_t retHex[]) +{ + quint16_t i; + char *str = (char *)srcStr; + quint16_t strLen = HAL_STRLEN(str); + for (i = 0; i < strLen; i++) + { + if (str[i] >= 'A' && str[i] <= 'F') + { + if (i % 2) + retHex[i >> 1] |= (str[i] - 'A' + 10); + else + retHex[i >> 1] = (str[i] - 'A' + 10) << 4; + } + else if (str[i] >= 'a' && str[i] <= 'f') + { + if (i % 2) + retHex[i >> 1] |= (str[i] - 'a' + 10); + else + retHex[i >> 1] = (str[i] - 'a' + 10) << 4; + } + else if (str[i] >= '0' && str[i] <= '9') + { + if (i % 2) + retHex[i >> 1] |= (str[i] - '0'); + else + retHex[i >> 1] = (str[i] - '0') << 4; + } + else + { + return 0; + } + } + return (i + 1) / 2; +} + +/************************************************************************** +** 功能 @brief : crc计算 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +quint32_t FUNCTION_ATTR_ROM Quos_crcCalculate(quint32_t crc, const void *buf, quint32_t len) +{ + quint8_t *dat = (quint8_t *)buf; + while (len--) + { + crc += *dat++; + } + return crc; +} +/************************************************************************** +** 功能 @brief : KEY-VALUE提取数据 +** 输入 @param : srcStr:key-value键值对源字符串 + keyword关键字,包括key-value分隔符 + dstStr输出buffer + dstLenMax 输出buffer最大长度,value值超出这长度视为无效 + endStr key-value结束分隔符,srcStr为多组kv时,endStr必须为非NULL + eg:Quos_keyValueExtract("qq:1;ww:2;ee:3","ww:",val,30,";")提取key为ww的val是"2" +** 输出 @retval: +***************************************************************************/ +qint32_t FUNCTION_ATTR_ROM Quos_keyValueExtract(char *srcStr, const char *keyword, const char *separator, char **dstStr, const char *endStr) +{ + if (NULL == srcStr || NULL == keyword || NULL == separator || NULL == dstStr) + { + return -1; + } + char *head = (char *)srcStr; + while (NULL != (head = HAL_STRSTR(head, keyword))) + { + if (HAL_STRNCMP(head + HAL_STRLEN(keyword), separator, HAL_STRLEN(separator))) + { + /* do no */ + } + else if (head != srcStr && NULL == endStr) + { + return 0; + } + else if (head == srcStr || ((quint32_t)(head - srcStr) >= (quint32_t)HAL_STRLEN(endStr) && 0 == HAL_STRNCMP(&head[0 - HAL_STRLEN(endStr)], endStr, HAL_STRLEN(endStr)))) + { + break; + } + head++; + } + if (NULL == head) + { + return -1; + } + char *tail = NULL; + head += HAL_STRLEN(keyword) + HAL_STRLEN(separator); + if (endStr) + { + tail = HAL_STRSTR(head, endStr); + } + qint32_t valueLen = tail ? (quint32_t)(tail - head) : HAL_STRLEN(head); + *dstStr = head; + return valueLen; +} +/************************************************************************** +** 功能 @brief : KEY-VALUE增删改 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Quos_keyValueInsert(char *srcStr, quint32_t maxLen, const char *keyword, const char *separator, const char *value, char *endStr) +{ + if (NULL == srcStr || NULL == keyword || 0 == HAL_STRLEN(keyword) || NULL == separator) + { + return FALSE; + } + char *head = srcStr; + + /* 查找keyword是否存在 */ + while (NULL != (head = HAL_STRSTR(head, keyword))) + { + if (0 != HAL_STRNCMP(head + HAL_STRLEN(keyword), separator, HAL_STRLEN(separator))) /* 并非完整keyword,如何在字段中abcd:1查找keyword为abc, 由于匹配到abc后面并非是:,所以匹配错误 */ + { + head++; + } + else if (head != srcStr && NULL == endStr) + { + srcStr[0] = 0; + head = NULL; + break; + } + else if (head == srcStr || ((quint32_t)(head - srcStr) >= (quint32_t)HAL_STRLEN(endStr) && 0 == HAL_STRNCMP(&head[0 - HAL_STRLEN(endStr)], endStr, HAL_STRLEN(endStr)))) + { + qint32_t valueLen = HAL_STRLEN(head); + if (endStr) + { + char *tail = HAL_STRSTR(head + HAL_STRLEN(keyword) + HAL_STRLEN(separator), endStr); + while (tail) + { + tail += HAL_STRLEN(endStr); + valueLen = tail - head; + if (0 == HAL_STRLEN(tail) || 0 != HAL_STRNCMP(tail, endStr, HAL_STRLEN(endStr))) + { + break; + } + } + } + HAL_MEMMOVE(head, head + valueLen, HAL_STRLEN(head + valueLen) + 1); + } + else + { + head++; + } + } + if (endStr && HAL_STRLEN(srcStr) >= HAL_STRLEN(endStr) && 0 == HAL_STRNCMP(srcStr + HAL_STRLEN(srcStr) - HAL_STRLEN(endStr), endStr, HAL_STRLEN(endStr))) + { + srcStr[HAL_STRLEN(srcStr) - HAL_STRLEN(endStr)] = 0; + } + + if (value && HAL_STRLEN(value) > 0) + { + if (HAL_STRLEN(srcStr) + HAL_STRLEN(keyword) + HAL_STRLEN(separator) + HAL_STRLEN(value) + HAL_STRLEN(endStr) >= maxLen) + { + return FALSE; + } + HAL_SPRINTF(srcStr + HAL_STRLEN(srcStr), "%s%s%s%s", (HAL_STRLEN(srcStr) > 0 && endStr) ? endStr : "", keyword, separator, value); + } + return TRUE; +} +/************************************************************************** +** 功能 @brief : 字符串分解 +** 输入 @param : srcStr源字符串,内容将会改变 + words分解字符串指针 + maxSize最大支持分解提取个数 + delim分隔符字符串 +** 输出 @retval: 分解提取的个数 +***************************************************************************/ +quint32_t FUNCTION_ATTR_ROM Quos_stringSplit(char *src, quint32_t srcLen, char **words, quint32_t maxSize, const char *delim, qbool keepEmptyParts) +{ + char *start = src; + quint32_t num = 0; + if (NULL == delim) + { + return 0; + } + quint32_t delimLen = HAL_STRLEN(delim); + while (maxSize > num && src && (quint32_t)(src-start) 1 && '0' == src[0])) + { + return FALSE; + } + if (value) + { + *value = 0; + } + for (i = 0; i < len; i++) + { + if (src[i] < '0' || src[i] > '9') + { + return FALSE; + } + else if (value) + { + *value = (*value) * 10 + src[i] - '0'; + } + } + return TRUE; +} +/************************************************************************** +** 功能 @brief : url解析 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Quos_urlAnalyze(const char *url, urlAnalyze_t *result) +{ + char *tempUrl; + quint8_t i; + HAL_MEMSET(result, 0, sizeof(urlAnalyze_t)); + if (NULL == url || 0 == HAL_STRLEN(url)) + { + return FALSE; + } + if (HAL_STRSTR(url, "s://") || HAL_STRSTR(url, "S://")) + { + result->isSecure = TRUE; + } + else + { + result->isSecure = FALSE; + } + + tempUrl = HAL_STRSTR(url, "://"); + tempUrl = tempUrl ? (tempUrl + HAL_STRLEN("://")) : (char *)url; + + i = 0; + while ('\0' != *tempUrl && ':' != *tempUrl && '/' != *tempUrl && i < QUOS_DNS_HOSTNANE_MAX_LENGHT) + { + result->hostname[i++] = *tempUrl++; + } + if (QUOS_DNS_HOSTNANE_MAX_LENGHT == i || i < 4 || (NULL == HAL_STRCHR(result->hostname, '.') && NULL == HAL_STRCHR(result->hostname, ':'))) + { + return FALSE; + } + result->port = 0; + if (':' == *tempUrl) + { + result->port = HAL_ATOI(tempUrl + 1); + } + tempUrl = HAL_STRSTR(tempUrl, "/"); + result->path = tempUrl ? tempUrl + 1 : NULL; + return TRUE; +} +/************************************************************************** +** 功能 @brief : IP字符串转数值 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +quint32_t FUNCTION_ATTR_ROM Quos_ip2Int(const char *ipStr) +{ + quint32_t ipInt = 0; + quint8_t dots = 0; + quint32_t secValue = 0; + if (NULL == ipStr || *ipStr < '0' || *ipStr > '9') + { + return 0; + } + while (ipStr && *ipStr >= '0' && *ipStr <= '9') + { + secValue = secValue * 10 + (*ipStr++) - '0'; + if (secValue > 255) + { + return 0; + } + if (*ipStr == '.') + { + ipStr++; + dots++; + ipInt = ipInt * 256 + secValue; + secValue = 0; + } + else if (*ipStr == 0 && 3 == dots) + { + return ipInt * 256 + secValue; + } + } + return 0; +} + +/************************************************************************** +** 功能 @brief : strtoul函数重构 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +quint64_t FUNCTION_ATTR_RAM Quos_strtoul(const char *cp, char **endp, quint32_t base) +{ + unsigned long result = 0, value; + if (!base) + { + base = 10; + if (*cp == '0') + { + base = 8; + cp++; + if ((__TO_LOWER(*cp) == 'x') && __IS_XDIGIT(cp[1])) + { + cp++; + base = 16; + } + } + } + else if (base == 16) + { + if (cp[0] == '0' && __TO_LOWER(cp[1]) == 'x') + cp += 2; + } + while (__IS_XDIGIT(*cp) && (value = __IS_DIGIT(*cp) ? *cp - '0' : __TO_LOWER(*cp) - 'a' + 10) < base) + { + result = result * base + value; + cp++; + } + if (endp) + *endp = (char *)cp; + return result; +} +qint64_t FUNCTION_ATTR_RAM Quos_strtol(const char *cp, char **endp, quint32_t base) +{ + if (*cp == '-') + return -Quos_strtoul(cp + 1, endp, base); + return Quos_strtoul(cp, endp, base); +} +/************************************************************************** +** 功能 @brief : 计算文件MD5 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Quos_fileMd5(const char *filename, quint32_t fileLen, char md5[32 + 1]) +{ + md5_state_t md5State; + quint32_t i; + Quos_md5Init(&md5State); + pointer_t fileFd = Qhal_fileOpen(filename, TRUE); + if (SOCKET_FD_INVALID == fileFd) + { + return FALSE; + } + for (i = 0; i < fileLen;) + { + quint8_t tmpBuf[256]; + quint16_t len = i + sizeof(tmpBuf) > fileLen ? fileLen - i : sizeof(tmpBuf); + if (len != Qhal_fileRead(fileFd, i, tmpBuf, len)) + { + Qhal_fileClose(fileFd); + return FALSE; + } + i += len; + Quos_md5Append(&md5State, (const quint8_t *)tmpBuf, len); + Qhal_devFeeddog(); + } + Qhal_fileClose(fileFd); + quint8_t md5Hex[16]; + HAL_MEMSET(md5Hex, 0, sizeof(md5Hex)); + Quos_md5Finish(&md5State, md5Hex); + Quos_hex2Str(md5Hex, sizeof(md5Hex), md5, FALSE); + return TRUE; +} + +/************************************************************************** +** 功能 @brief : 数值压缩push到数组 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +quint32_t FUNCTION_ATTR_ROM Quos_intPushArray(quint64_t intValue, quint8_t *array) +{ + quint32_t i; + quint8_t temp[8]; + _U64_ARRAY01234567(intValue, temp); + for (i = 0; i < sizeof(temp) - 1; i++) + { + if (0 != temp[i]) + { + break; + } + } + HAL_MEMCPY(array, &temp[i], sizeof(temp) - i); + return sizeof(temp) - i; +} +/************************************************************************** + ** 功能 @brief : 字符串若存在双引号则去掉,strVal内容将会改变 + ** 输入 @param : + ** 输出 @retval: + ***************************************************************************/ +char FUNCTION_ATTR_ROM *Quos_stringRemoveMarks(char *strVal) +{ + quint32_t len = HAL_STRLEN(strVal); + if ('"' == strVal[0] && '"' == strVal[len - 1]) + { + quint32_t i; + for (i = 0; i < len - 2; i++) + { + strVal[i] = strVal[i + 1]; + } + strVal[len - 2] = 0; + } + return strVal; +} +/************************************************************************** +** 功能 @brief : 生成随机码,暂定0-9a-zA-Z,后期优化使其适配指定目标 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Quos_RandomGen(quint8_t *random, quint32_t len) +{ + quint32_t i; + for (i = 0; i < len; i++) + { + random[i] = Qhal_randomGet() % (10 + 26 + 26); + if (random[i] < 10) + random[i] += '0'; + else if (random[i] < 10 + 26) + random[i] += 'A' - 10; + else + random[i] += 'a' - 36; + } +} +/************************************************************************** +** 功能 @brief : 浮点数转为无符号整数,并返回小数位数 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +quint8_t FUNCTION_ATTR_ROM Quos_doubleToUInt(double value,quint64_t *IntValue,qbool *negative) +{ + if(value < 0) + { + value = 0 - value; + *negative = TRUE; + } + else + { + *negative = FALSE; + } + char strBuf[22]; + int valueBufLen = HAL_SNPRINTF(strBuf,sizeof(strBuf),"%1.15g",value); + char *decimalPoint = HAL_STRSTR(strBuf,"."); + quint8_t decimals = 0; + if(decimalPoint != NULL) + { + decimals = valueBufLen - (decimalPoint - strBuf) - 1; + HAL_MEMMOVE(decimalPoint,decimalPoint+1,decimals); + strBuf[valueBufLen-1] = '\0'; + } + *IntValue = HAL_STRTOUL(strBuf, NULL, 10); + return decimals; +} diff --git a/kernel/quos_SupportTool.h b/kernel/quos_SupportTool.h index fbe2451795a784a69c91c664c63f834c61802ffe..272f9d0aebea4249217582896091436111d342e6 100644 --- a/kernel/quos_SupportTool.h +++ b/kernel/quos_SupportTool.h @@ -1,137 +1,140 @@ -#ifndef __QUOS_SUPPORTTOOL_H__ -#define __QUOS_SUPPORTTOOL_H__ -#include "quos_config.h" -#ifdef __cplusplus -extern "C" -{ -#endif - - typedef struct - { - char *path; /* path指向url的地址 */ - char hostname[QUOS_DNS_HOSTNANE_MAX_LENGHT]; - qbool isSecure; - quint16_t port; - } urlAnalyze_t; - -#define __ENDIANCHANGE(x) ((sizeof(x) == 2) ? (quint16_t)((x >> 8) | (x << 8)) : ((sizeof(x) == 4) ? (quint32_t)((((x) >> 24) & 0x000000FF) | (((x) >> 8) & 0x0000FF00) | (((x) << 8) & 0x00FF0000) | (((x) << 24) & 0xFF000000)) : (x))) - -/* 字节对齐 */ -#define __BYTE_TO_ALIGN(X, Y) ((X) % (Y) ? ((X) + (Y) - (X) % (Y)) : (X)) - -/*大小写转换 */ -#define __TO_UPPER(X) ((X) & (~0x20)) -#define __TO_LOWER(X) ((X) | 0x20) - -#define __IS_DIGIT(X) ('0' <= (X) && (X) <= '9') -#define __IS_XDIGIT(X) (('0' <= (X) && (X) <= '9') || ('a' <= (X) && (X) <= 'f') || ('A' <= (X) && (X) <= 'F')) - -/*求最大值和最小值 */ -#define __GET_MAX(x, y) (((x) > (y)) ? (x) : (y)) -#define __GET_MIN(x, y) (((x) < (y)) ? (x) : (y)) - -/*得到一个field在结构体(struct)中的偏移量 */ -#define __GET_POS_ELEMENT(type, field) ((pointer_t) & (((type *)0)->field)) -/*得到一个结构体中field所占用的字节数 */ -#define __GET_SIZE_ELEMENT(type, field) sizeof(((type *)0)->field) -/*根据元素地址得到结构体 */ -#define __GET_STRUCT_BY_ELEMENT(ptr, type, field) ((type *)((char *)ptr - __GET_POS_ELEMENT(type, field))) -/*返回一个比X小的最接近的n的倍数 */ -#define __GET_SMALL_N(x, n) ((x) / (n) * (n)) - -/*返回一个比X大的最接近的n的倍数 */ -#define __GET_BIG_N(x, n) (((x) + (n)-1) / (n) * (n)) - -/* 转换宏为字符串 */ -#define _MACRO2STR_1(s) #s -#define _MACRO2STR_2(s) _MACRO2STR_1(s) - -/* 字符串拼接 */ -#define _STRCAT_STR_1(A, B) A##B -#define _STRCAT_STR_2(A, B) _STRCAT_STR_1(A, B) - -#define _BOOL2STR(X) ((X) ? "TRUE" : "FALSE") /* qbool 转字符串 */ -#define _STR2BOOL(X) (0 == HAL_STRCASECMP(X, "TRUE") ? TRUE : FALSE) - -#define _DATA2BOOL(X, Y) (((X >> Y) & 1) ? TRUE : FALSE) - -#define _ARRAY01_U16(ARRAY) (((quint16_t)(((quint8_t *)(ARRAY))[0]) << 8) | \ - ((quint16_t)(((quint8_t *)(ARRAY))[1]) << 0)) - -#define _ARRAY10_U16(ARRAY) (((quint16_t)(((quint8_t *)(ARRAY))[1]) << 8) | \ - ((quint16_t)(((quint8_t *)(ARRAY))[0]) << 0)) - -#define _ARRAY0123_U32(ARRAY) (((quint32_t)(((quint8_t *)(ARRAY))[0]) << 24) | \ - ((quint32_t)(((quint8_t *)(ARRAY))[1]) << 16) | \ - ((quint32_t)(((quint8_t *)(ARRAY))[2]) << 8) | \ - ((quint32_t)(((quint8_t *)(ARRAY))[3]) << 0)) - -#define _ARRAY1032_U32(ARRAY) (((quint32_t)(((quint8_t *)(ARRAY))[1]) << 24) | \ - ((quint32_t)(((quint8_t *)(ARRAY))[0]) << 16) | \ - ((quint32_t)(((quint8_t *)(ARRAY))[3]) << 8) | \ - ((quint32_t)(((quint8_t *)(ARRAY))[2]) << 0)) - -#define _ARRAY3210_U32(ARRAY) (((quint32_t)(((quint8_t *)(ARRAY))[3]) << 24) | \ - ((quint32_t)(((quint8_t *)(ARRAY))[2]) << 16) | \ - ((quint32_t)(((quint8_t *)(ARRAY))[1]) << 8) | \ - ((quint32_t)(((quint8_t *)(ARRAY))[0]) << 0)) - -#define _ARRAY2301_U32(ARRAY) (((quint32_t)(((quint8_t *)(ARRAY))[2]) << 24) | \ - ((quint32_t)(((quint8_t *)(ARRAY))[3]) << 16) | \ - ((quint32_t)(((quint8_t *)(ARRAY))[0]) << 8) | \ - ((quint32_t)(((quint8_t *)(ARRAY))[1]) << 0)) - -#define _ARRAY76543210_U64(ARRAY) (((quint64_t)(((quint8_t *)(ARRAY))[7]) << 56) | \ - ((quint64_t)(((quint8_t *)(ARRAY))[6]) << 48) | \ - ((quint64_t)(((quint8_t *)(ARRAY))[5]) << 40) | \ - ((quint64_t)(((quint8_t *)(ARRAY))[4]) << 32) | \ - ((quint64_t)(((quint8_t *)(ARRAY))[3]) << 24) | \ - ((quint64_t)(((quint8_t *)(ARRAY))[2]) << 16) | \ - ((quint64_t)(((quint8_t *)(ARRAY))[1]) << 8) | \ - ((quint64_t)(((quint8_t *)(ARRAY))[0]) << 0)) - -#define _ARRAY012345678_U64(ARRAY) (((quint64_t)(((quint8_t *)(ARRAY))[0]) << 56) | \ - ((quint64_t)(((quint8_t *)(ARRAY))[1]) << 48) | \ - ((quint64_t)(((quint8_t *)(ARRAY))[2]) << 40) | \ - ((quint64_t)(((quint8_t *)(ARRAY))[3]) << 32) | \ - ((quint64_t)(((quint8_t *)(ARRAY))[4]) << 24) | \ - ((quint64_t)(((quint8_t *)(ARRAY))[4]) << 16) | \ - ((quint64_t)(((quint8_t *)(ARRAY))[6]) << 8) | \ - ((quint64_t)(((quint8_t *)(ARRAY))[7]) << 0)) - -#define _U16_ARRAY01(INT, ARRAY) (((quint8_t *)ARRAY)[0] = ((INT) >> 8) & 0xFF, ((quint8_t *)ARRAY)[1] = (INT)&0xFF) -#define _U16_ARRAY10(INT, ARRAY) (((quint8_t *)ARRAY)[0] = (INT)&0xFF, ((quint8_t *)ARRAY)[1] = ((INT) >> 8) & 0xFF) -#define _U32_ARRAY0123(INT, ARRAY) (((quint8_t *)ARRAY)[0] = ((INT) >> 24) & 0xFF, ((quint8_t *)ARRAY)[1] = ((INT) >> 16) & 0xFF, ((quint8_t *)ARRAY)[2] = ((INT) >> 8) & 0xFF, ((quint8_t *)ARRAY)[3] = (INT)&0xFF) -#define _U32_ARRAY3210(INT, ARRAY) (((quint8_t *)ARRAY)[0] = (INT)&0xFF, ((quint8_t *)ARRAY)[1] = ((INT) >> 8) & 0xFF, ((quint8_t *)ARRAY)[2] = ((INT) >> 16) & 0xFF, ((quint8_t *)ARRAY)[3] = ((INT) >> 24) & 0xFF) -#define _U64_ARRAY01234567(INT, ARRAY) (((quint8_t *)ARRAY)[0] = ((INT) >> 56) & 0xFF, ((quint8_t *)ARRAY)[1] = ((INT) >> 48) & 0xFF, ((quint8_t *)ARRAY)[2] = ((INT) >> 40) & 0xFF, ((quint8_t *)ARRAY)[3] = ((INT) >> 32) & 0xFF, \ - ((quint8_t *)ARRAY)[4] = ((INT) >> 24) & 0xFF, ((quint8_t *)ARRAY)[5] = ((INT) >> 16) & 0xFF, ((quint8_t *)ARRAY)[6] = ((INT) >> 8) & 0xFF, ((quint8_t *)ARRAY)[7] = ((INT) >> 0) & 0xFF) -#define _U64_ARRAY76543210(INT, ARRAY) (((quint8_t*)ARRAY)[0] = (INT)&0xFF,((quint8_t*)ARRAY)[1] = ((INT)>>8)&0xFF,((quint8_t*)ARRAY)[2] = ((INT)>>16)&0xFF,((quint8_t*)ARRAY)[3] = ((INT)>>24)&0xFF, \ - (((quint8_t*)ARRAY)[4] = ((INT)>>32)&0xFF,((quint8_t*)ARRAY)[5] = ((INT)>>40)&0xFF,((quint8_t*)ARRAY)[6] = ((INT)>>48)&0xFF,((quint8_t*)ARRAY)[7] = ((INT)>>56)&0xFF) - -#define IP2STR "%hhu.%hhu.%hhu.%hhu" -#define IP2STR_(IP) (quint8_t)((IP) >> 24), (quint8_t)((IP) >> 16), (quint8_t)((IP) >> 8), (quint8_t)((IP) >> 0) - -#define TIME_SEC2UTC "%08d.%02d.%02d" -#define TIME_SEC2UTC_(SEC) (quint32_t)(SEC / 3600), (quint8_t)(SEC % 3600 / 60), (quint8_t)(SEC % 60) - - quint32_t Quos_hex2Str(quint8_t hex[], quint32_t hexLen, char *retStr, qbool isUpper); - quint32_t Quos_str2Hex(void *srcStr, quint8_t RetHex[]); - quint8_t Quos_convertToExp(quint32_t value, quint32_t exp); - quint32_t Quos_crcCalculate(quint32_t crc, void *buf, quint32_t len); - qint32_t Quos_keyValueExtract(char *srcStr, const char *keyword, const char *separator, char **dstStr, const char *endStr); - qbool Quos_keyValueInsert(char *srcStr, quint32_t maxLen, const char *keyword, const char *separator, const char *value, char *endStr); - quint32_t Quos_stringSplit(char *src, char **words, quint32_t maxSize, char *delim, qbool keepEmptyParts); - qbool Quos_strIsUInt(char *src, quint32_t len, quint32_t *value); - qbool Quos_urlAnalyze(const char *url, urlAnalyze_t *result); - quint32_t Quos_ip2Int(const char *ipStr); - quint64_t Quos_strtoul(const char *cp, char **endp, quint32_t base); - qint64_t Quos_strtol(const char *cp, char **endp, quint32_t base); - qbool Quos_fileMd5(const char *filename, quint32_t fileLen, char md5[]); - quint32_t Quos_intPushArray(quint64_t intValue,quint8_t *array); - char *Quos_stringRemoveMarks(char *strVal); - -#ifdef __cplusplus -} -#endif - -#endif +#ifndef __QUOS_SUPPORTTOOL_H__ +#define __QUOS_SUPPORTTOOL_H__ +#include "quos_config.h" +#ifdef __cplusplus +extern "C" +{ +#endif + + typedef struct + { + char *path; /* path指向url的地址 */ + char hostname[QUOS_DNS_HOSTNANE_MAX_LENGHT]; + qbool isSecure; + quint16_t port; + } urlAnalyze_t; + +#define __ENDIANCHANGE(x) ((sizeof(x) == 2) ? (quint16_t)((x >> 8) | (x << 8)) : ((sizeof(x) == 4) ? (quint32_t)((((x) >> 24) & 0x000000FF) | (((x) >> 8) & 0x0000FF00) | (((x) << 8) & 0x00FF0000) | (((x) << 24) & 0xFF000000)) : (x))) + +/* 字节对齐 */ +#define __BYTE_TO_ALIGN(X, Y) ((X) % (Y) ? ((X) + (Y) - (X) % (Y)) : (X)) + +/*大小写转换 */ +#define __TO_UPPER(X) ((X) & (~0x20)) +#define __TO_LOWER(X) ((X) | 0x20) + +#define __IS_LETTER(X) (('A' <= (X) && (X) <= 'Z') || ('a' <= (X) && (X) <= 'z')) +#define __IS_DIGIT(X) ('0' <= (X) && (X) <= '9') +#define __IS_XDIGIT(X) (('0' <= (X) && (X) <= '9') || ('a' <= (X) && (X) <= 'f') || ('A' <= (X) && (X) <= 'F')) + +/*求最大值和最小值 */ +#define __GET_MAX(x, y) (((x) > (y)) ? (x) : (y)) +#define __GET_MIN(x, y) (((x) < (y)) ? (x) : (y)) + +/*得到一个field在结构体(struct)中的偏移量 */ +#define __GET_POS_ELEMENT(type, field) ((pointer_t) & (((type *)0)->field)) +/*得到一个结构体中field所占用的字节数 */ +#define __GET_SIZE_ELEMENT(type, field) sizeof(((type *)0)->field) +/*根据元素地址得到结构体 */ +#define __GET_STRUCT_BY_ELEMENT(ptr, type, field) ((type *)((char *)ptr - __GET_POS_ELEMENT(type, field))) +/*返回一个比X小的最接近的n的倍数 */ +#define __GET_SMALL_N(x, n) ((x) / (n) * (n)) + +/*返回一个比X大的最接近的n的倍数 */ +#define __GET_BIG_N(x, n) (((x) + (n)-1) / (n) * (n)) + +/* 转换宏为字符串 */ +#define _MACRO2STR_1(s) #s +#define _MACRO2STR_2(s) _MACRO2STR_1(s) + +/* 字符串拼接 */ +#define _STRCAT_STR_1(A, B) A##B +#define _STRCAT_STR_2(A, B) _STRCAT_STR_1(A, B) + +#define _BOOL2STR(X) ((X) ? "TRUE" : "FALSE") /* qbool 转字符串 */ +#define _STR2BOOL(X) (0 == HAL_STRNCASECMP(X, "TRUE", __GET_MAX(HAL_STRLEN(X), HAL_STRLEN("TRUE"))) ? TRUE : FALSE) +#define _STR2PRINT(X) (NULL == X ? "null" : X) +#define _DATA2BOOL(X, Y) (((X >> Y) & 1) ? TRUE : FALSE) + +#define _ARRAY01_U16(ARRAY) (((quint16_t)(((quint8_t *)(ARRAY))[0]) << 8) | \ + ((quint16_t)(((quint8_t *)(ARRAY))[1]) << 0)) + +#define _ARRAY10_U16(ARRAY) (((quint16_t)(((quint8_t *)(ARRAY))[1]) << 8) | \ + ((quint16_t)(((quint8_t *)(ARRAY))[0]) << 0)) + +#define _ARRAY0123_U32(ARRAY) (((quint32_t)(((quint8_t *)(ARRAY))[0]) << 24) | \ + ((quint32_t)(((quint8_t *)(ARRAY))[1]) << 16) | \ + ((quint32_t)(((quint8_t *)(ARRAY))[2]) << 8) | \ + ((quint32_t)(((quint8_t *)(ARRAY))[3]) << 0)) + +#define _ARRAY1032_U32(ARRAY) (((quint32_t)(((quint8_t *)(ARRAY))[1]) << 24) | \ + ((quint32_t)(((quint8_t *)(ARRAY))[0]) << 16) | \ + ((quint32_t)(((quint8_t *)(ARRAY))[3]) << 8) | \ + ((quint32_t)(((quint8_t *)(ARRAY))[2]) << 0)) + +#define _ARRAY3210_U32(ARRAY) (((quint32_t)(((quint8_t *)(ARRAY))[3]) << 24) | \ + ((quint32_t)(((quint8_t *)(ARRAY))[2]) << 16) | \ + ((quint32_t)(((quint8_t *)(ARRAY))[1]) << 8) | \ + ((quint32_t)(((quint8_t *)(ARRAY))[0]) << 0)) + +#define _ARRAY2301_U32(ARRAY) (((quint32_t)(((quint8_t *)(ARRAY))[2]) << 24) | \ + ((quint32_t)(((quint8_t *)(ARRAY))[3]) << 16) | \ + ((quint32_t)(((quint8_t *)(ARRAY))[0]) << 8) | \ + ((quint32_t)(((quint8_t *)(ARRAY))[1]) << 0)) + +#define _ARRAY76543210_U64(ARRAY) (((quint64_t)(((quint8_t *)(ARRAY))[7]) << 56) | \ + ((quint64_t)(((quint8_t *)(ARRAY))[6]) << 48) | \ + ((quint64_t)(((quint8_t *)(ARRAY))[5]) << 40) | \ + ((quint64_t)(((quint8_t *)(ARRAY))[4]) << 32) | \ + ((quint64_t)(((quint8_t *)(ARRAY))[3]) << 24) | \ + ((quint64_t)(((quint8_t *)(ARRAY))[2]) << 16) | \ + ((quint64_t)(((quint8_t *)(ARRAY))[1]) << 8) | \ + ((quint64_t)(((quint8_t *)(ARRAY))[0]) << 0)) + +#define _ARRAY012345678_U64(ARRAY) (((quint64_t)(((quint8_t *)(ARRAY))[0]) << 56) | \ + ((quint64_t)(((quint8_t *)(ARRAY))[1]) << 48) | \ + ((quint64_t)(((quint8_t *)(ARRAY))[2]) << 40) | \ + ((quint64_t)(((quint8_t *)(ARRAY))[3]) << 32) | \ + ((quint64_t)(((quint8_t *)(ARRAY))[4]) << 24) | \ + ((quint64_t)(((quint8_t *)(ARRAY))[4]) << 16) | \ + ((quint64_t)(((quint8_t *)(ARRAY))[6]) << 8) | \ + ((quint64_t)(((quint8_t *)(ARRAY))[7]) << 0)) + +#define _U16_ARRAY01(INT, ARRAY) (((quint8_t *)ARRAY)[0] = ((INT) >> 8) & 0xFF, ((quint8_t *)ARRAY)[1] = (INT)&0xFF) +#define _U16_ARRAY10(INT, ARRAY) (((quint8_t *)ARRAY)[0] = (INT)&0xFF, ((quint8_t *)ARRAY)[1] = ((INT) >> 8) & 0xFF) +#define _U32_ARRAY0123(INT, ARRAY) (((quint8_t *)ARRAY)[0] = ((INT) >> 24) & 0xFF, ((quint8_t *)ARRAY)[1] = ((INT) >> 16) & 0xFF, ((quint8_t *)ARRAY)[2] = ((INT) >> 8) & 0xFF, ((quint8_t *)ARRAY)[3] = (INT)&0xFF) +#define _U32_ARRAY3210(INT, ARRAY) (((quint8_t *)ARRAY)[0] = (INT)&0xFF, ((quint8_t *)ARRAY)[1] = ((INT) >> 8) & 0xFF, ((quint8_t *)ARRAY)[2] = ((INT) >> 16) & 0xFF, ((quint8_t *)ARRAY)[3] = ((INT) >> 24) & 0xFF) +#define _U64_ARRAY01234567(INT, ARRAY) (((quint8_t *)ARRAY)[0] = ((INT) >> 56) & 0xFF, ((quint8_t *)ARRAY)[1] = ((INT) >> 48) & 0xFF, ((quint8_t *)ARRAY)[2] = ((INT) >> 40) & 0xFF, ((quint8_t *)ARRAY)[3] = ((INT) >> 32) & 0xFF, \ + ((quint8_t *)ARRAY)[4] = ((INT) >> 24) & 0xFF, ((quint8_t *)ARRAY)[5] = ((INT) >> 16) & 0xFF, ((quint8_t *)ARRAY)[6] = ((INT) >> 8) & 0xFF, ((quint8_t *)ARRAY)[7] = ((INT) >> 0) & 0xFF) +#define _U64_ARRAY76543210(INT, ARRAY) (((quint8_t*)ARRAY)[0] = (INT)&0xFF,((quint8_t*)ARRAY)[1] = ((INT)>>8)&0xFF,((quint8_t*)ARRAY)[2] = ((INT)>>16)&0xFF,((quint8_t*)ARRAY)[3] = ((INT)>>24)&0xFF, \ + (((quint8_t*)ARRAY)[4] = ((INT)>>32)&0xFF,((quint8_t*)ARRAY)[5] = ((INT)>>40)&0xFF,((quint8_t*)ARRAY)[6] = ((INT)>>48)&0xFF,((quint8_t*)ARRAY)[7] = ((INT)>>56)&0xFF) + +#define IP2STR "%hhu.%hhu.%hhu.%hhu" +#define IP2STR_(IP) (quint8_t)((IP) >> 24), (quint8_t)((IP) >> 16), (quint8_t)((IP) >> 8), (quint8_t)((IP) >> 0) + +#define TIME_SEC2UTC "%08d.%02d.%02d" +#define TIME_SEC2UTC_(SEC) (quint32_t)(SEC / 3600), (quint8_t)(SEC % 3600 / 60), (quint8_t)(SEC % 60) + + quint32_t Quos_hex2Str(quint8_t hex[], quint32_t hexLen, char *retStr, qbool isUpper); + quint32_t Quos_str2Hex(void *srcStr, quint8_t RetHex[]); + quint8_t Quos_convertToExp(quint32_t value, quint32_t exp); + quint32_t Quos_crcCalculate(quint32_t crc, const void *buf, quint32_t len); + qint32_t Quos_keyValueExtract(char *srcStr, const char *keyword, const char *separator, char **dstStr, const char *endStr); + qbool Quos_keyValueInsert(char *srcStr, quint32_t maxLen, const char *keyword, const char *separator, const char *value, char *endStr); + quint32_t Quos_stringSplit(char *src, quint32_t srcLen, char **words, quint32_t maxSize, const char *delim, qbool keepEmptyParts); + qbool Quos_strIsUInt(char *src, quint32_t len, quint32_t *value); + qbool Quos_urlAnalyze(const char *url, urlAnalyze_t *result); + quint32_t Quos_ip2Int(const char *ipStr); + quint64_t Quos_strtoul(const char *cp, char **endp, quint32_t base); + qint64_t Quos_strtol(const char *cp, char **endp, quint32_t base); + qbool Quos_fileMd5(const char *filename, quint32_t fileLen, char md5[]); + quint32_t Quos_intPushArray(quint64_t intValue, quint8_t *array); + char *Quos_stringRemoveMarks(char *strVal); + void Quos_RandomGen(quint8_t *random, quint32_t len); + quint8_t Quos_doubleToUInt(double value, quint64_t *IntValue, qbool *negative); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kernel/quos_aes.c b/kernel/quos_aes.c new file mode 100644 index 0000000000000000000000000000000000000000..ae54d2b7b832b5d615bd97665449b4abea432130 --- /dev/null +++ b/kernel/quos_aes.c @@ -0,0 +1,555 @@ +/* + +This is an implementation of the AES algorithm, specifically ECB, CTR and CBC mode. +Block size can be chosen in aes.h - available choices are QUOS_AES128, QUOS_AES192, QUOS_AES256. + +The implementation is verified against the test vectors in: + National Institute of Standards and Technology Special Publication 800-38A 2001 ED + +NOTE: String length must be evenly divisible by 16byte (str_len % 16 == 0) + You should pad the end of the string with zeros if this is not the case. + For QUOS_AES192/256 the key size is proportionally larger. + +*/ + +/*****************************************************************************/ +/* Includes: */ +/*****************************************************************************/ +#include "quos_aes.h" +#if (SDK_ENABLE_AES == 1) +/*****************************************************************************/ +/* Defines: */ +/*****************************************************************************/ +/* The number of columns comprising a state in AES. This is a constant in AES. Value=4 */ +#define Nb 4 + +#if defined(QUOS_AES256) && (QUOS_AES256 == 1) +#define Nk 8 +#define Nr 14 +#elif defined(QUOS_AES192) && (QUOS_AES192 == 1) +#define Nk 6 +#define Nr 12 +#else +#define Nk 4 /* The number of 32 bit words in a key. */ +#define Nr 10 /* The number of rounds in AES Cipher. */ +#endif + +/*****************************************************************************/ +/* Private variables: */ +/*****************************************************************************/ +/* state - array holding the intermediate results during decryption. */ +typedef quint8_t state_t[4][4]; + +/* The lookup-tables are marked const so they can be placed in read-only storage instead of RAM */ +/* The numbers below can be computed dynamically trading ROM for RAM - */ +/* This can be useful in (embedded) bootloader applications, where ROM is often limited. */ +static const quint8_t sbox[256] = { + /*0 1 2 3 4 5 6 7 8 9 A B C D E F */ + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16}; + +static const quint8_t rsbox[256] = { + 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, + 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, + 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, + 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, + 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, + 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, + 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, + 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, + 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, + 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, + 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, + 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, + 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, + 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, + 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d}; + +/* The round constant word array, Rcon[i], contains the values given by */ +/* x to the power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8) */ +static const quint8_t Rcon[11] = { + 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36}; + +/* + * Jordan Goulder points out in PR #12 (https://github.com/kokke/tiny-AES-C/pull/12), + * that you can remove most of the elements in the Rcon array, because they are unused. + * + * From Wikipedia's article on the Rijndael key schedule @ https://en.wikipedia.org/wiki/Rijndael_key_schedule#Rcon + * + * "Only the first some of these constants are actually used 鈥 up to rcon[10]-for AES-128 (as 11 round keys are needed), + * up to rcon[8] for AES-192, up to rcon[7] for AES-256. rcon[0] is not used in AES algorithm." + */ + +/*****************************************************************************/ +/* Private functions: */ +/*****************************************************************************/ +/* +static quint8_t getSBoxValue(quint8_t num) +{ + return sbox[num]; +} +*/ +#define getSBoxValue(num) (sbox[(num)]) +/* +static quint8_t getSBoxInvert(quint8_t num) +{ + return rsbox[num]; +} +*/ +#define getSBoxInvert(num) (rsbox[(num)]) + +/* This function produces Nb(Nr+1) round keys. The round keys are used in each round to decrypt the states. */ +static void KeyExpansion(quint8_t *RoundKey, const char *Key) +{ + unsigned i, j, k; + quint8_t tempa[4]; /* Used for the column/row operations */ + + /* The first round key is the key itself. */ + for (i = 0; i < Nk; ++i) + { + RoundKey[(i * 4) + 0] = Key[(i * 4) + 0]; + RoundKey[(i * 4) + 1] = Key[(i * 4) + 1]; + RoundKey[(i * 4) + 2] = Key[(i * 4) + 2]; + RoundKey[(i * 4) + 3] = Key[(i * 4) + 3]; + } + + /* All other round keys are found from the previous round keys. */ + for (i = Nk; i < Nb * (Nr + 1); ++i) + { + { + k = (i - 1) * 4; + tempa[0] = RoundKey[k + 0]; + tempa[1] = RoundKey[k + 1]; + tempa[2] = RoundKey[k + 2]; + tempa[3] = RoundKey[k + 3]; + } + + if (i % Nk == 0) + { + /* This function shifts the 4 bytes in a word to the left once. */ + /* [a0,a1,a2,a3] becomes [a1,a2,a3,a0] */ + + /* Function RotWord() */ + { + k = tempa[0]; + tempa[0] = tempa[1]; + tempa[1] = tempa[2]; + tempa[2] = tempa[3]; + tempa[3] = k; + } + + /* SubWord() is a function that takes a four-byte input word and */ + /* applies the S-box to each of the four bytes to produce an output word. */ + + /* Function Subword() */ + { + tempa[0] = getSBoxValue(tempa[0]); + tempa[1] = getSBoxValue(tempa[1]); + tempa[2] = getSBoxValue(tempa[2]); + tempa[3] = getSBoxValue(tempa[3]); + } + + tempa[0] = tempa[0] ^ Rcon[i / Nk]; + } +#if defined(QUOS_AES256) && (QUOS_AES256 == 1) + if (i % Nk == 4) + { + /* Function Subword() */ + { + tempa[0] = getSBoxValue(tempa[0]); + tempa[1] = getSBoxValue(tempa[1]); + tempa[2] = getSBoxValue(tempa[2]); + tempa[3] = getSBoxValue(tempa[3]); + } + } +#endif + j = i * 4; + k = (i - Nk) * 4; + RoundKey[j + 0] = RoundKey[k + 0] ^ tempa[0]; + RoundKey[j + 1] = RoundKey[k + 1] ^ tempa[1]; + RoundKey[j + 2] = RoundKey[k + 2] ^ tempa[2]; + RoundKey[j + 3] = RoundKey[k + 3] ^ tempa[3]; + } +} + +void Quos_aesInitCtx(AES_ctx_t *ctx, const char *key) +{ + KeyExpansion(ctx->RoundKey, key); +} + +void Quos_aesInitCtxIv(AES_ctx_t *ctx, const char *key, const char *iv) +{ + KeyExpansion(ctx->RoundKey, key); + HAL_MEMCPY(ctx->Iv, iv, QUOS_AES_BLOCKLEN); +} +void Quos_aesCtxSetIv(AES_ctx_t *ctx, const char *iv) +{ + HAL_MEMCPY(ctx->Iv, iv, QUOS_AES_BLOCKLEN); +} + +/* This function adds the round key to state. */ +/* The round key is added to the state by an XOR function. */ +static void AddRoundKey(quint8_t round, state_t *state, quint8_t *RoundKey) +{ + quint8_t i, j; + for (i = 0; i < 4; ++i) + { + for (j = 0; j < 4; ++j) + { + (*state)[i][j] ^= RoundKey[(round * Nb * 4) + (i * Nb) + j]; + } + } +} + +/* The SubBytes Function Substitutes the values in the */ +/* state matrix with values in an S-box. */ +static void SubBytes(state_t *state) +{ + quint8_t i, j; + for (i = 0; i < 4; ++i) + { + for (j = 0; j < 4; ++j) + { + (*state)[j][i] = getSBoxValue((*state)[j][i]); + } + } +} + +/* The ShiftRows() function shifts the rows in the state to the left. */ +/* Each row is shifted with different offset. */ +/* Offset = Row number. So the first row is not shifted. */ +static void ShiftRows(state_t *state) +{ + quint8_t temp; + + /* Rotate first row 1 columns to left */ + temp = (*state)[0][1]; + (*state)[0][1] = (*state)[1][1]; + (*state)[1][1] = (*state)[2][1]; + (*state)[2][1] = (*state)[3][1]; + (*state)[3][1] = temp; + + /* Rotate second row 2 columns to left */ + temp = (*state)[0][2]; + (*state)[0][2] = (*state)[2][2]; + (*state)[2][2] = temp; + + temp = (*state)[1][2]; + (*state)[1][2] = (*state)[3][2]; + (*state)[3][2] = temp; + + /* Rotate third row 3 columns to left */ + temp = (*state)[0][3]; + (*state)[0][3] = (*state)[3][3]; + (*state)[3][3] = (*state)[2][3]; + (*state)[2][3] = (*state)[1][3]; + (*state)[1][3] = temp; +} + +static quint8_t xtime(quint8_t x) +{ + return ((x << 1) ^ (((x >> 7) & 1) * 0x1b)); +} + +/* MixColumns function mixes the columns of the state matrix */ +static void MixColumns(state_t *state) +{ + quint8_t i; + quint8_t Tmp, Tm, t; + for (i = 0; i < 4; ++i) + { + t = (*state)[i][0]; + Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3]; + Tm = (*state)[i][0] ^ (*state)[i][1]; + Tm = xtime(Tm); + (*state)[i][0] ^= Tm ^ Tmp; + Tm = (*state)[i][1] ^ (*state)[i][2]; + Tm = xtime(Tm); + (*state)[i][1] ^= Tm ^ Tmp; + Tm = (*state)[i][2] ^ (*state)[i][3]; + Tm = xtime(Tm); + (*state)[i][2] ^= Tm ^ Tmp; + Tm = (*state)[i][3] ^ t; + Tm = xtime(Tm); + (*state)[i][3] ^= Tm ^ Tmp; + } +} + +/* Multiply is used to multiply numbers in the field GF(2^8) */ + +#define Multiply(x, y) \ + (((y & 1) * x) ^ \ + ((y >> 1 & 1) * xtime(x)) ^ \ + ((y >> 2 & 1) * xtime(xtime(x))) ^ \ + ((y >> 3 & 1) * xtime(xtime(xtime(x)))) ^ \ + ((y >> 4 & 1) * xtime(xtime(xtime(xtime(x)))))) + +/* MixColumns function mixes the columns of the state matrix. */ +/* The method used to multiply may be difficult to understand for the inexperienced. */ +/* Please use the references to gain more information. */ +static void InvMixColumns(state_t *state) +{ + int i; + quint8_t a, b, c, d; + for (i = 0; i < 4; ++i) + { + a = (*state)[i][0]; + b = (*state)[i][1]; + c = (*state)[i][2]; + d = (*state)[i][3]; + + (*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09); + (*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d); + (*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b); + (*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e); + } +} + +/* The SubBytes Function Substitutes the values in the */ +/* state matrix with values in an S-box. */ +static void InvSubBytes(state_t *state) +{ + quint8_t i, j; + for (i = 0; i < 4; ++i) + { + for (j = 0; j < 4; ++j) + { + (*state)[j][i] = getSBoxInvert((*state)[j][i]); + } + } +} + +static void InvShiftRows(state_t *state) +{ + quint8_t temp; + + /* Rotate first row 1 columns to right */ + temp = (*state)[3][1]; + (*state)[3][1] = (*state)[2][1]; + (*state)[2][1] = (*state)[1][1]; + (*state)[1][1] = (*state)[0][1]; + (*state)[0][1] = temp; + + /* Rotate second row 2 columns to right */ + temp = (*state)[0][2]; + (*state)[0][2] = (*state)[2][2]; + (*state)[2][2] = temp; + + temp = (*state)[1][2]; + (*state)[1][2] = (*state)[3][2]; + (*state)[3][2] = temp; + + /* Rotate third row 3 columns to right */ + temp = (*state)[0][3]; + (*state)[0][3] = (*state)[1][3]; + (*state)[1][3] = (*state)[2][3]; + (*state)[2][3] = (*state)[3][3]; + (*state)[3][3] = temp; +} + +/* Cipher is the main function that encrypts the PlainText. */ +static void Cipher(state_t *state, quint8_t *RoundKey) +{ + quint8_t round = 0; + + /* Add the First round key to the state before starting the rounds. */ + AddRoundKey(0, state, RoundKey); + + /* There will be Nr rounds. */ + /* The first Nr-1 rounds are identical. */ + /* These Nr-1 rounds are executed in the loop below. */ + for (round = 1; round < Nr; ++round) + { + SubBytes(state); + ShiftRows(state); + MixColumns(state); + AddRoundKey(round, state, RoundKey); + } + + /* The last round is given below. */ + /* The MixColumns function is not here in the last round. */ + SubBytes(state); + ShiftRows(state); + AddRoundKey(Nr, state, RoundKey); +} + +static void InvCipher(state_t *state, quint8_t *RoundKey) +{ + quint8_t round = 0; + + /* Add the First round key to the state before starting the rounds. */ + AddRoundKey(Nr, state, RoundKey); + + /* There will be Nr rounds. */ + /* The first Nr-1 rounds are identical. */ + /* These Nr-1 rounds are executed in the loop below. */ + for (round = (Nr - 1); round > 0; --round) + { + InvShiftRows(state); + InvSubBytes(state); + AddRoundKey(round, state, RoundKey); + InvMixColumns(state); + } + + /* The last round is given below. */ + /* The MixColumns function is not here in the last round. */ + InvShiftRows(state); + InvSubBytes(state); + AddRoundKey(0, state, RoundKey); +} + +/*****************************************************************************/ +/* Public functions: */ +/*****************************************************************************/ + +quint32_t Quos_aesEcbEncrypt(AES_ctx_t *ctx, const quint8_t *buf, quint32_t length) +{ + /* The next function call encrypts the PlainText with the Key using AES algorithm. */ + quint32_t i; + for (i = 0; i < length; i += QUOS_AES_BLOCKLEN) + { + Cipher((state_t *)buf, ctx->RoundKey); + buf += QUOS_AES_BLOCKLEN; + } + return i; +} + +void Quos_aesEcbDecrypt(AES_ctx_t *ctx, const quint8_t *buf, quint32_t length) +{ + /* The next function call decrypts the PlainText with the Key using AES algorithm. */ + quint32_t i; + for (i = 0; i < length; i += QUOS_AES_BLOCKLEN) + { + InvCipher((state_t *)buf, ctx->RoundKey); + buf += QUOS_AES_BLOCKLEN; + } +} + +static void XorWithIv(quint8_t *buf, quint8_t *Iv) +{ + quint8_t i; + for (i = 0; i < QUOS_AES_BLOCKLEN; ++i) /* The block in AES is always 128bit no matter the key size */ + { + buf[i] ^= Iv[i]; + } +} + +quint32_t Quos_aesCbcEncrypt(AES_ctx_t *ctx, void *buf, quint32_t length) +{ + quint32_t i; + quint8_t *data = (quint8_t *)buf; + quint8_t *Iv = ctx->Iv; + for (i = 0; i < length; i += QUOS_AES_BLOCKLEN) + { + XorWithIv(data, Iv); + Cipher((state_t *)data, ctx->RoundKey); + Iv = data; + data += QUOS_AES_BLOCKLEN; + } + /* store Iv in ctx for next call */ + HAL_MEMCPY(ctx->Iv, Iv, QUOS_AES_BLOCKLEN); + return i; +} + +void Quos_aesCbcDecrypt(AES_ctx_t *ctx, void *buf, quint32_t length) +{ + quint16_t i; + quint8_t *data = (quint8_t *)buf; + quint8_t storeNextIv[QUOS_AES_BLOCKLEN]; + for (i = 0; i < length; i += QUOS_AES_BLOCKLEN) + { + HAL_MEMCPY(storeNextIv, data, QUOS_AES_BLOCKLEN); + InvCipher((state_t *)data, ctx->RoundKey); + XorWithIv(data, ctx->Iv); + HAL_MEMCPY(ctx->Iv, storeNextIv, QUOS_AES_BLOCKLEN); + data += QUOS_AES_BLOCKLEN; + } +} + +/* Symmetrical operation: same function for encrypting as for decrypting. Note any IV/nonce should never be reused with the same key */ +void Quos_aesCtrXCrypt(AES_ctx_t *ctx, void *buf, quint32_t length) +{ + quint8_t buffer[QUOS_AES_BLOCKLEN]; + quint8_t *tempBuf = (quint8_t *)buf; + quint16_t i; + int bi; + for (i = 0, bi = QUOS_AES_BLOCKLEN; i < length; ++i, ++bi) + { + if (bi == QUOS_AES_BLOCKLEN) /* we need to regen xor compliment in buffer */ + { + HAL_MEMCPY(buffer, ctx->Iv, QUOS_AES_BLOCKLEN); + Cipher((state_t *)buffer, ctx->RoundKey); + + /* Increment Iv and handle overflow */ + for (bi = (QUOS_AES_BLOCKLEN - 1); bi >= 0; --bi) + { + /* inc will owerflow */ + if (ctx->Iv[bi] == 255) + { + ctx->Iv[bi] = 0; + continue; + } + ctx->Iv[bi] += 1; + break; + } + bi = 0; + } + tempBuf[i] = (tempBuf[i] ^ buffer[bi]); + } +} +/************************************************************************** +** 鍔熻兘 @brief : pcks#7濉厖 +** 杈撳叆 @param : +** 杈撳嚭 @retval: +***************************************************************************/ +void Quos_aesPadding(quint8_t *dest, quint8_t *src, quint32_t srcLen) +{ + quint32_t offset = QUOS_AES_BLOCKLEN - srcLen % QUOS_AES_BLOCKLEN; + HAL_MEMMOVE(dest, src, srcLen); + HAL_MEMSET(dest + srcLen, offset, offset); +} +/************************************************************************** +** 鍔熻兘 @brief : pcks#7鍙嶅~鍏 +** 杈撳叆 @param : +** 杈撳嚭 @retval: +***************************************************************************/ +quint32_t Quos_aesPaddingBack(quint8_t *src, quint32_t srcLen) +{ + quint8_t i = 0; + if (0 == srcLen || (srcLen % QUOS_AES_BLOCKLEN) != 0 || src[srcLen - 1] > QUOS_AES_BLOCKLEN || 0 == src[srcLen - 1]) + { + return srcLen; + } + for (i = 1; i < QUOS_AES_BLOCKLEN; i++) + { + if (src[srcLen - 1 - i] != src[srcLen - i]) + { + break; + } + } + if (i == src[srcLen - 1]) + { + HAL_MEMSET(src + srcLen - i, 0, i); + return srcLen - i; + } + else + { + return srcLen; + } +} +#endif \ No newline at end of file diff --git a/kernel/quos_aes.h b/kernel/quos_aes.h index a9828d2e476259daa80dd162f990c31ea451c40e..27d43e37476e41fd423fa58abb4751b2691c5bf6 100644 --- a/kernel/quos_aes.h +++ b/kernel/quos_aes.h @@ -1,56 +1,56 @@ -#ifndef _AES_H_ -#define _AES_H_ -#include "quos_config.h" - -#if (SDK_ENABLE_AES == 1) -#define QUOS_AES128 1 -/*#define QUOS_AES192 1 */ -/*#define QUOS_AES256 1 */ - -#define QUOS_AES_BLOCKLEN 16 /*Block length in bytes AES is 128b block only */ - -#if defined(QUOS_AES256) && (QUOS_AES256 == 1) -#define QUOS_AES_KEYLEN 32 -#define QUOS_AES_keyExpSize 240 -#elif defined(QUOS_AES192) && (QUOS_AES192 == 1) -#define QUOS_AES_KEYLEN 24 -#define QUOS_AES_keyExpSize 208 -#else -#define QUOS_AES_KEYLEN 16 /* Key length in bytes */ -#define QUOS_AES_keyExpSize 176 -#endif - -typedef struct -{ - quint8_t RoundKey[QUOS_AES_keyExpSize]; - quint8_t Iv[QUOS_AES_BLOCKLEN]; -} AES_ctx_t; - -void Quos_aesInitCtx(AES_ctx_t *ctx, const char *key); -void Quos_aesInitCtxIv(AES_ctx_t *ctx, const char *key, const char *iv); -void Quos_aesCtxSetIv(AES_ctx_t *ctx, const char *iv); - -/* buffer size MUST be mutile of QUOS_AES_BLOCKLEN; */ -/* you need only Quos_aesInitCtx as IV is not used in ECB */ -/* NB: ECB is considered insecure for most uses */ -quint32_t Quos_aesEcbEncrypt(AES_ctx_t *ctx, const quint8_t *buf, quint32_t length); -void Quos_aesEcbDecrypt(AES_ctx_t *ctx, const quint8_t *buf, quint32_t length); - -/* buffer size MUST be mutile of QUOS_AES_BLOCKLEN; */ -/* Suggest https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme */ -/* NOTES: you need to set IV in ctx via Quos_aesInitCtxIv() or Quos_aesCtxSetIv() */ -/* no IV should ever be reused with the same key */ -void Quos_aesCbcEncrypt(AES_ctx_t *ctx, void *buf, quint32_t length); -void Quos_aesCbcDecrypt(AES_ctx_t *ctx, void *buf, quint32_t length); - -/* Same function for encrypting as for decrypting. */ -/* IV is incremented for every block, and used after encryption as XOR-compliment for output */ -/* Suggesting https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme */ -/* NOTES: you need to set IV in ctx with Quos_aesInitCtxIv() or Quos_aesCtxSetIv() */ -/* no IV should ever be reused with the same key */ -void Quos_aesCtrXCrypt(AES_ctx_t *ctx, void *buf, quint32_t length); - -void Quos_aesPadding(quint8_t *dest, quint8_t *src, quint32_t srcLen); -quint32_t Quos_aesPaddingBack(quint8_t *src,quint32_t srcLen); -#endif /*_AES_H_ */ +#ifndef _AES_H_ +#define _AES_H_ +#include "quos_config.h" + +#if (SDK_ENABLE_AES == 1) +#define QUOS_AES128 1 +/*#define QUOS_AES192 1 */ +/*#define QUOS_AES256 1 */ + +#define QUOS_AES_BLOCKLEN 16 /*Block length in bytes AES is 128b block only */ + +#if defined(QUOS_AES256) && (QUOS_AES256 == 1) +#define QUOS_AES_KEYLEN 32 +#define QUOS_AES_keyExpSize 240 +#elif defined(QUOS_AES192) && (QUOS_AES192 == 1) +#define QUOS_AES_KEYLEN 24 +#define QUOS_AES_keyExpSize 208 +#else +#define QUOS_AES_KEYLEN 16 /* Key length in bytes */ +#define QUOS_AES_keyExpSize 176 +#endif + +typedef struct +{ + quint8_t RoundKey[QUOS_AES_keyExpSize]; + quint8_t Iv[QUOS_AES_BLOCKLEN]; +} AES_ctx_t; + +void Quos_aesInitCtx(AES_ctx_t *ctx, const char *key); +void Quos_aesInitCtxIv(AES_ctx_t *ctx, const char *key, const char *iv); +void Quos_aesCtxSetIv(AES_ctx_t *ctx, const char *iv); + +/* buffer size MUST be mutile of QUOS_AES_BLOCKLEN; */ +/* you need only Quos_aesInitCtx as IV is not used in ECB */ +/* NB: ECB is considered insecure for most uses */ +quint32_t Quos_aesEcbEncrypt(AES_ctx_t *ctx, const quint8_t *buf, quint32_t length); +void Quos_aesEcbDecrypt(AES_ctx_t *ctx, const quint8_t *buf, quint32_t length); + +/* buffer size MUST be mutile of QUOS_AES_BLOCKLEN; */ +/* Suggest https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme */ +/* NOTES: you need to set IV in ctx via Quos_aesInitCtxIv() or Quos_aesCtxSetIv() */ +/* no IV should ever be reused with the same key */ +quint32_t Quos_aesCbcEncrypt(AES_ctx_t *ctx, void *buf, quint32_t length); +void Quos_aesCbcDecrypt(AES_ctx_t *ctx, void *buf, quint32_t length); + +/* Same function for encrypting as for decrypting. */ +/* IV is incremented for every block, and used after encryption as XOR-compliment for output */ +/* Suggesting https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme */ +/* NOTES: you need to set IV in ctx with Quos_aesInitCtxIv() or Quos_aesCtxSetIv() */ +/* no IV should ever be reused with the same key */ +void Quos_aesCtrXCrypt(AES_ctx_t *ctx, void *buf, quint32_t length); + +void Quos_aesPadding(quint8_t *dest, quint8_t *src, quint32_t srcLen); +quint32_t Quos_aesPaddingBack(quint8_t *src,quint32_t srcLen); +#endif /*_AES_H_ */ #endif \ No newline at end of file diff --git a/kernel/quos_base64.c b/kernel/quos_base64.c new file mode 100644 index 0000000000000000000000000000000000000000..caa184c26f87fb0c83706e1da55a8d86eaaf16f3 --- /dev/null +++ b/kernel/quos_base64.c @@ -0,0 +1,115 @@ +/************************************************************************* +** 鍒涘缓浜 @author : 鍚村仴瓒 JCWu +** 鐗堟湰 @version : V1.0.0 鍘熷鐗堟湰 +** 鏃ユ湡 @date : +** 鍔熻兘 @brief : base64鍔犺В瀵 +** 纭欢 @hardware锛氫换浣旳NSI-C骞冲彴 +** 鍏朵粬 @other 锛 +***************************************************************************/ +#include "quos_base64.h" +#include "Quos_kernel.h" +#if (SDK_ENABLE_BASE64 == 1) +static char baseCode[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/************************************************************************** +** 鍔熻兘 @brief : base64鍔犲瘑 +** 杈撳叆 @param : dstData:鍔犲瘑鍚庢暟鎹紝闀垮害蹇呴』涓哄師鏁版嵁闀垮害鐨4/3+2 +** 杈撳嚭 @retval: +***************************************************************************/ +quint16_t FUNCTION_ATTR_ROM Quos_base64Encrypt(const quint8_t *srcData, quint16_t srcLen, quint8_t *dstData) +{ + quint16_t i = 0; + Quos_logHexDump(LSDK_ENCRP, LL_DUMP, "base64 encrypt src data", srcData, srcLen); + while (srcLen) + { + dstData[i++] = baseCode[(srcData[0] >> 2) & 0x3F]; + if (srcLen > 2) + { + dstData[i++] = baseCode[((srcData[0] & 0x03) << 4) | (srcData[1] >> 4)]; + dstData[i++] = baseCode[((srcData[1] & 0x0F) << 2) | (srcData[2] >> 6)]; + dstData[i++] = baseCode[srcData[2] & 0x3F]; + srcLen -= 3; + } + else if (1 == srcLen) + { + dstData[i++] = baseCode[(srcData[0] & 3) << 4]; + dstData[i++] = '='; + dstData[i++] = '='; + srcLen = 0; + } + else if (2 == srcLen) + { + dstData[i++] = baseCode[((srcData[0] & 3) << 4) | (srcData[1] >> 4)]; + dstData[i++] = baseCode[(srcData[1] & 0x0F) << 2]; + dstData[i++] = '='; + srcLen = 0; + } + srcData += 3; + } + dstData[i] = 0; + Quos_logPrintf(LSDK_ENCRP, LL_DBG, "base64 encrypt dst data:%s", dstData); + return i; +} +/************************************************************************** +** 鍔熻兘 @brief : base64瑙e瘑 +** 杈撳叆 @param : +** 杈撳嚭 @retval: +***************************************************************************/ +quint16_t FUNCTION_ATTR_ROM Quos_base64Decrypt(const quint8_t *srcData, quint16_t srcLen, quint8_t *dstData) +{ + quint16_t i; + quint16_t dstLen = 0; + Quos_logPrintf(LSDK_ENCRP, LL_DBG, "base64 decrypt src data:%s", srcData); + if (NULL == srcData || NULL == dstData || 0 == srcLen) + { + return 0; + } + for (i = 0; i < srcLen; i += 4) + { + quint8_t k; + quint8_t baseData[4]; + HAL_MEMSET(baseData, 0, sizeof(baseData)); + for (k = 0; k < 64; k++) + { + if (srcData[i] == baseCode[k]) + { + baseData[0] = k; + break; + } + } + for (k = 0; k < 64; k++) + { + if (srcData[i + 1] == baseCode[k]) + { + baseData[1] = k; + break; + } + } + for (k = 0; k < 64; k++) + { + if (srcData[i + 2] == baseCode[k]) + { + baseData[2] = k; + break; + } + } + for (k = 0; k < 64; k++) + { + if (srcData[i + 3] == baseCode[k]) + { + baseData[3] = k; + break; + } + } + dstData[dstLen++] = ((baseData[0] << 2) & 0xFC) | ((baseData[1] >> 4) & 0x03); + if (srcData[i + 2] == '=') + break; + dstData[dstLen++] = ((baseData[1] << 4) & 0xF0) | ((baseData[2] >> 2) & 0x0F); + if (srcData[i + 3] == '=') + break; + dstData[dstLen++] = ((baseData[2] << 6) & 0xF0) | (baseData[3] & 0x3F); + } + Quos_logHexDump(LSDK_ENCRP, LL_DUMP, "base64 decrypt dst data", dstData, dstLen); + return dstLen; +} +#endif \ No newline at end of file diff --git a/kernel/quos_base64.h b/kernel/quos_base64.h index 8ddcd98d564aef7cebd1fafc53f89c632761ce45..0ff9936eb52b5f28f88ddfab5c129ba6e629b782 100644 --- a/kernel/quos_base64.h +++ b/kernel/quos_base64.h @@ -1,10 +1,10 @@ -#ifndef __QUOS_BASE64_H__ -#define __QUOS_BASE64_H__ -#include "quos_config.h" - -#define QUOS_BASE64_DSTDATA_LEN(SRCLEN) (((SRCLEN+2)/3 << 2) + 1) -#if (SDK_ENABLE_BASE64 == 1) -quint16_t Quos_base64Encrypt(quint8_t *srcData, quint16_t srcLen, quint8_t *dstData); -quint16_t Quos_base64Decrypt(quint8_t *srcData, quint16_t srcLen, quint8_t *dstData); -#endif -#endif +#ifndef __QUOS_BASE64_H__ +#define __QUOS_BASE64_H__ +#include "quos_config.h" + +#define QUOS_BASE64_DSTDATA_LEN(SRCLEN) (((SRCLEN+2)/3 << 2) + 1) +#if (SDK_ENABLE_BASE64 == 1) +quint16_t Quos_base64Encrypt(const quint8_t *srcData, quint16_t srcLen, quint8_t *dstData); +quint16_t Quos_base64Decrypt(const quint8_t *srcData, quint16_t srcLen, quint8_t *dstData); +#endif +#endif diff --git a/kernel/quos_cjson.c b/kernel/quos_cjson.c new file mode 100644 index 0000000000000000000000000000000000000000..2e14961361155500ab4af891d056ca5eb396d762 --- /dev/null +++ b/kernel/quos_cjson.c @@ -0,0 +1,2934 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +/* cJSON */ +/* JSON parser in C. */ +/* disable warnings about old C89 functions in MSVC */ +#include "quos_cjson.h" +#if (SDK_ENABLE_JSON ==1 ) +#include "quos_SupportTool.h" +/* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */ +#ifndef isinf +#define isinf(d) (isnan((d - d)) && !isnan(d)) +#endif +#ifndef isnan +#define isnan(d) (d != d) +#endif + +#ifndef NAN +#define NAN 0.0/0.0 +#endif +/* project version */ +#define CJSON_VERSION_MAJOR 1 +#define CJSON_VERSION_MINOR 7 +#define CJSON_VERSION_PATCH 14 + +typedef struct { + const unsigned char *json; + quint32_t position; +} error; +static error global_error = { NULL, 0 }; + +const char * cJSON_GetErrorPtr(void) +{ + return (const char*) (global_error.json + global_error.position); +} + +char * cJSON_GetStringValue(const cJSON * const item) +{ + if (!cJSON_IsString(item)) + { + return NULL; + } + + return item->valuestring; +} + +double cJSON_GetNumberValue(const cJSON * const item) +{ + if (!cJSON_IsNumber(item)) + { + return (double) NAN; + } + + return item->valuedouble; +} + +/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 14) + #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. +#endif + +const char* cJSON_Version(void) +{ + static char version[15]; + HAL_SPRINTF(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); + + return version; +} + +/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */ +static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) +{ + if ((string1 == NULL) || (string2 == NULL)) + { + return 1; + } + + if (string1 == string2) + { + return 0; + } + + for(; __TO_LOWER(*string1) == __TO_LOWER(*string2); (void)string1++, string2++) + { + if (*string1 == '\0') + { + return 0; + } + } + + return __TO_LOWER(*string1) - __TO_LOWER(*string2); +} + +/* HAL_STRLEN of character literals resolved at compile time */ +#define static_strlen(string_literal) (sizeof(string_literal) - sizeof("")) + +/* Internal constructor. */ +static cJSON *cJSON_New_Item(void) +{ + cJSON* node = HAL_MALLOC(sizeof(cJSON)); + if (node) + { + HAL_MEMSET(node, '\0', sizeof(cJSON)); + } + + return node; +} + +/* Delete a cJSON structure. */ +void cJSON_Delete(cJSON *item) +{ + cJSON *next = NULL; + while (item != NULL) + { + next = item->next; + if (!(item->type & QUOS_cJSON_IsReference) && (item->child != NULL)) + { + cJSON_Delete(item->child); + } + if (!(item->type & QUOS_cJSON_IsReference) && (item->valuestring != NULL)) + { + HAL_FREE(item->valuestring); + } + if (!(item->type & QUOS_cJSON_StringIsConst) && (item->string != NULL)) + { + HAL_FREE(item->string); + } + HAL_FREE(item); + item = next; + } +} + +/* get the decimal point character of the current locale */ +static unsigned char get_decimal_point(void) +{ +#ifdef ENABLE_LOCALES + struct lconv *lconv = localeconv(); + return (unsigned char) lconv->decimal_point[0]; +#else + return '.'; +#endif +} + +typedef struct +{ + const unsigned char *content; + quint32_t length; + quint32_t offset; + quint32_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */ +} parse_buffer; + +/* check if the given size is left to read in a given parse buffer (starting with 1) */ +#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length)) +/* check if the buffer can be accessed at the given index (starting with 0) */ +#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length)) +#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index)) +/* get a pointer to the buffer at the position */ +#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset) + +/* Parse the input text to generate a number, and populate the result into item. */ +static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer) +{ + double number = 0; + unsigned char *after_end = NULL; + unsigned char number_c_string[64]; + unsigned char decimal_point = get_decimal_point(); + quint32_t i = 0; + + if ((input_buffer == NULL) || (input_buffer->content == NULL)) + { + return FALSE; + } + + /* copy the number into a temporary buffer and replace '.' with the decimal point + * of the current locale (for strtod) + * This also takes care of '\0' not necessarily being available for marking the end of the input */ + for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) + { + switch (buffer_at_offset(input_buffer)[i]) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '+': + case '-': + case 'e': + case 'E': + number_c_string[i] = buffer_at_offset(input_buffer)[i]; + break; + + case '.': + number_c_string[i] = decimal_point; + break; + + default: + goto loop_end; + } + } +loop_end: + number_c_string[i] = '\0'; + + number = HAL_STRTOD((const char*)number_c_string, (char**)&after_end); + if (number_c_string == after_end) + { + return FALSE; /* parse_error */ + } + + item->valuedouble = number; + + /* use saturation in case of overflow */ + if (number >= INT_MAX) + { + item->valueint = INT_MAX; + } + else if (number <= (double)INT_MIN) + { + item->valueint = INT_MIN; + } + else + { + item->valueint = (int)number; + } + + item->type = QUOS_cJSON_Number; + + input_buffer->offset += (quint32_t)(after_end - number_c_string); + return TRUE; +} + +/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ +double cJSON_SetNumberHelper(cJSON *object, double number) +{ + if (number >= INT_MAX) + { + object->valueint = INT_MAX; + } + else if (number <= (double)INT_MIN) + { + object->valueint = INT_MIN; + } + else + { + object->valueint = (int)number; + } + + return object->valuedouble = number; +} + +char* cJSON_SetValuestring(cJSON *object, const char *valuestring) +{ + char *copy = NULL; + /* if object's type is not QUOS_cJSON_String or is QUOS_cJSON_IsReference, it should not set valuestring */ + if (!(object->type & QUOS_cJSON_String) || (object->type & QUOS_cJSON_IsReference)) + { + return NULL; + } + if (HAL_STRLEN(valuestring) <= HAL_STRLEN(object->valuestring)) + { + HAL_STRCPY(object->valuestring, valuestring); + return object->valuestring; + } + copy = HAL_STRDUP(valuestring); + if (copy == NULL) + { + return NULL; + } + if (object->valuestring != NULL) + { + HAL_FREE(object->valuestring); + } + object->valuestring = copy; + + return copy; +} + +typedef struct +{ + unsigned char *buffer; + quint32_t length; + quint32_t offset; + quint32_t depth; /* current nesting depth (for formatted printing) */ + cJSON_bool noalloc; + cJSON_bool format; /* is this print a formatted print */ +} printbuffer; + +/* realloc printbuffer if necessary to have at least "needed" bytes more */ +static unsigned char* ensure(printbuffer * const p, quint32_t needed) +{ + unsigned char *newbuffer = NULL; + quint32_t newsize = 0; + + if ((p == NULL) || (p->buffer == NULL)) + { + return NULL; + } + + if ((p->length > 0) && (p->offset >= p->length)) + { + /* make sure that offset is valid */ + return NULL; + } + + if (needed > INT_MAX) + { + /* sizes bigger than INT_MAX are currently not supported */ + return NULL; + } + + needed += p->offset + 1; + if (needed <= p->length) + { + return p->buffer + p->offset; + } + + if (p->noalloc) { + return NULL; + } + + /* calculate new buffer size */ + if (needed > (INT_MAX / 2)) + { + /* overflow of int, use INT_MAX if possible */ + if (needed <= INT_MAX) + { + newsize = INT_MAX; + } + else + { + return NULL; + } + } + else + { + newsize = needed * 2; + } + + /* otherwise reallocate manually */ + newbuffer = HAL_MALLOC(newsize); + if (!newbuffer) + { + HAL_FREE(p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + if (newbuffer) + { + HAL_MEMCPY(newbuffer, p->buffer, p->offset + 1); + } + HAL_FREE(p->buffer); + p->length = newsize; + p->buffer = newbuffer; + + return newbuffer + p->offset; +} + +/* calculate the new length of the string in a printbuffer and update the offset */ +static void update_offset(printbuffer * const buffer) +{ + const unsigned char *buffer_pointer = NULL; + if ((buffer == NULL) || (buffer->buffer == NULL)) + { + return; + } + buffer_pointer = buffer->buffer + buffer->offset; + + buffer->offset += HAL_STRLEN((const char*)buffer_pointer); +} + +/* securely comparison of floating-point variables */ +static cJSON_bool compare_double(double a, double b) +{ + double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b); + return (fabs(a - b) <= maxVal * DBL_EPSILON); +} + +/* Render the number nicely from the given item into a string. */ +static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + double d = item->valuedouble; + int length = 0; + quint32_t i = 0; + unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */ + unsigned char decimal_point = get_decimal_point(); + double test = 0.0; + + if (output_buffer == NULL) + { + return FALSE; + } + + /* This checks for NaN and Infinity */ + if (isnan(d) || isinf(d)) + { + length = HAL_SPRINTF((char*)number_buffer, "null"); + } + else + { + /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ + length = HAL_SPRINTF((char*)number_buffer, "%1.15g", d); + + /* Check whether the original double can be recovered */ + if ((HAL_SSCANF((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d)) + { + /* If not, print with 17 decimal places of precision */ + length = HAL_SPRINTF((char*)number_buffer, "%1.17g", d); + } + } + + /* HAL_SPRINTF failed or buffer overrun occurred */ + if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) + { + return FALSE; + } + + /* reserve appropriate space in the output */ + output_pointer = ensure(output_buffer, (quint32_t)length + sizeof("")); + if (output_pointer == NULL) + { + return FALSE; + } + + /* copy the printed number to the output and replace locale + * dependent decimal point with '.' */ + for (i = 0; i < ((quint32_t)length); i++) + { + if (number_buffer[i] == decimal_point) + { + output_pointer[i] = '.'; + continue; + } + + output_pointer[i] = number_buffer[i]; + } + output_pointer[i] = '\0'; + + output_buffer->offset += (quint32_t)length; + + return TRUE; +} + +/* parse 4 digit hexadecimal number */ +static unsigned parse_hex4(const unsigned char * const input) +{ + unsigned int h = 0; + quint32_t i = 0; + + for (i = 0; i < 4; i++) + { + /* parse digit */ + if ((input[i] >= '0') && (input[i] <= '9')) + { + h += (unsigned int) input[i] - '0'; + } + else if ((input[i] >= 'A') && (input[i] <= 'F')) + { + h += (unsigned int) 10 + input[i] - 'A'; + } + else if ((input[i] >= 'a') && (input[i] <= 'f')) + { + h += (unsigned int) 10 + input[i] - 'a'; + } + else /* invalid */ + { + return 0; + } + + if (i < 3) + { + /* shift left to make place for the next nibble */ + h = h << 4; + } + } + + return h; +} + +/* converts a UTF-16 literal to UTF-8 + * A literal can be one or two sequences of the form \uXXXX */ +static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer) +{ + long unsigned int codepoint = 0; + unsigned int first_code = 0; + const unsigned char *first_sequence = input_pointer; + unsigned char utf8_length = 0; + unsigned char utf8_position = 0; + unsigned char sequence_length = 0; + unsigned char first_byte_mark = 0; + + if ((input_end - first_sequence) < 6) + { + /* input ends unexpectedly */ + goto fail; + } + + /* get the first utf16 sequence */ + first_code = parse_hex4(first_sequence + 2); + + /* check that the code is valid */ + if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) + { + goto fail; + } + + /* UTF16 surrogate pair */ + if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) + { + const unsigned char *second_sequence = first_sequence + 6; + unsigned int second_code = 0; + sequence_length = 12; /* \uXXXX\uXXXX */ + + if ((input_end - second_sequence) < 6) + { + /* input ends unexpectedly */ + goto fail; + } + + if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) + { + /* missing second half of the surrogate pair */ + goto fail; + } + + /* get the second utf16 sequence */ + second_code = parse_hex4(second_sequence + 2); + /* check that the code is valid */ + if ((second_code < 0xDC00) || (second_code > 0xDFFF)) + { + /* invalid second half of the surrogate pair */ + goto fail; + } + + + /* calculate the unicode codepoint from the surrogate pair */ + codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF)); + } + else + { + sequence_length = 6; /* \uXXXX */ + codepoint = first_code; + } + + /* encode as UTF-8 + * takes at maximum 4 bytes to encode: + * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ + if (codepoint < 0x80) + { + /* normal ascii, encoding 0xxxxxxx */ + utf8_length = 1; + } + else if (codepoint < 0x800) + { + /* two bytes, encoding 110xxxxx 10xxxxxx */ + utf8_length = 2; + first_byte_mark = 0xC0; /* 11000000 */ + } + else if (codepoint < 0x10000) + { + /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */ + utf8_length = 3; + first_byte_mark = 0xE0; /* 11100000 */ + } + else if (codepoint <= 0x10FFFF) + { + /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ + utf8_length = 4; + first_byte_mark = 0xF0; /* 11110000 */ + } + else + { + /* invalid unicode codepoint */ + goto fail; + } + + /* encode as utf8 */ + for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) + { + /* 10xxxxxx */ + (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF); + codepoint >>= 6; + } + /* encode first byte */ + if (utf8_length > 1) + { + (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF); + } + else + { + (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F); + } + + *output_pointer += utf8_length; + + return sequence_length; + +fail: + return 0; +} + +/* Parse the input text into an unescaped cinput, and populate item. */ +static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer) +{ + const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1; + const unsigned char *input_end = buffer_at_offset(input_buffer) + 1; + unsigned char *output_pointer = NULL; + unsigned char *output = NULL; + + /* not a string */ + if (buffer_at_offset(input_buffer)[0] != '\"') + { + goto fail; + } + + { + /* calculate approximate size of the output (overestimate) */ + quint32_t allocation_length = 0; + quint32_t skipped_bytes = 0; + while (((quint32_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) + { + /* is escape sequence */ + if (input_end[0] == '\\') + { + if ((quint32_t)(input_end + 1 - input_buffer->content) >= input_buffer->length) + { + /* prevent buffer overflow when last input character is a backslash */ + goto fail; + } + skipped_bytes++; + input_end++; + } + input_end++; + } + if (((quint32_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) + { + goto fail; /* string ended unexpectedly */ + } + + /* This is at most how much we need for the output */ + allocation_length = (quint32_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes; + output = HAL_MALLOC(allocation_length + sizeof("")); + if (output == NULL) + { + goto fail; /* allocation failure */ + } + } + + output_pointer = output; + /* loop through the string literal */ + while (input_pointer < input_end) + { + if (*input_pointer != '\\') + { + *output_pointer++ = *input_pointer++; + } + /* escape sequence */ + else + { + unsigned char sequence_length = 2; + if ((input_end - input_pointer) < 1) + { + goto fail; + } + + switch (input_pointer[1]) + { + case 'b': + *output_pointer++ = '\b'; + break; + case 'f': + *output_pointer++ = '\f'; + break; + case 'n': + *output_pointer++ = '\n'; + break; + case 'r': + *output_pointer++ = '\r'; + break; + case 't': + *output_pointer++ = '\t'; + break; + case '\"': + case '\\': + case '/': + *output_pointer++ = input_pointer[1]; + break; + + /* UTF-16 literal */ + case 'u': + sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); + if (sequence_length == 0) + { + /* failed to convert UTF16-literal to UTF-8 */ + goto fail; + } + break; + + default: + goto fail; + } + input_pointer += sequence_length; + } + } + + /* zero terminate the output */ + *output_pointer = '\0'; + + item->type = QUOS_cJSON_String; + item->valuestring = (char*)output; + + input_buffer->offset = (quint32_t) (input_end - input_buffer->content); + input_buffer->offset++; + + return TRUE; + +fail: + if (output != NULL) + { + HAL_FREE(output); + } + + if (input_pointer != NULL) + { + input_buffer->offset = (quint32_t)(input_pointer - input_buffer->content); + } + + return FALSE; +} + +/* Render the cstring provided to an escaped version that can be printed. */ +static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer) +{ + const unsigned char *input_pointer = NULL; + unsigned char *output = NULL; + unsigned char *output_pointer = NULL; + quint32_t output_length = 0; + /* numbers of additional characters needed for escaping */ + quint32_t escape_characters = 0; + + if (output_buffer == NULL) + { + return FALSE; + } + + /* empty string */ + if (input == NULL) + { + output = ensure(output_buffer, sizeof("\"\"")); + if (output == NULL) + { + return FALSE; + } + HAL_STRCPY((char*)output, "\"\""); + + return TRUE; + } + + /* set "flag" to 1 if something needs to be escaped */ + for (input_pointer = input; *input_pointer; input_pointer++) + { + switch (*input_pointer) + { + case '\"': + case '\\': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + /* one character escape sequence */ + escape_characters++; + break; + default: + if (*input_pointer < 32) + { + /* UTF-16 escape sequence uXXXX */ + escape_characters += 5; + } + break; + } + } + output_length = (quint32_t)(input_pointer - input) + escape_characters; + + output = ensure(output_buffer, output_length + sizeof("\"\"")); + if (output == NULL) + { + return FALSE; + } + + /* no characters have to be escaped */ + if (escape_characters == 0) + { + output[0] = '\"'; + HAL_MEMCPY(output + 1, input, output_length); + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return TRUE; + } + + output[0] = '\"'; + output_pointer = output + 1; + /* copy the string */ + for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) + { + if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) + { + /* normal character, copy */ + *output_pointer = *input_pointer; + } + else + { + /* character needs to be escaped */ + *output_pointer++ = '\\'; + switch (*input_pointer) + { + case '\\': + *output_pointer = '\\'; + break; + case '\"': + *output_pointer = '\"'; + break; + case '\b': + *output_pointer = 'b'; + break; + case '\f': + *output_pointer = 'f'; + break; + case '\n': + *output_pointer = 'n'; + break; + case '\r': + *output_pointer = 'r'; + break; + case '\t': + *output_pointer = 't'; + break; + default: + /* escape and print as unicode codepoint */ + HAL_SPRINTF((char*)output_pointer, "u%04x", *input_pointer); + output_pointer += 4; + break; + } + } + } + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return TRUE; +} + +/* Invoke print_string_ptr (which is useful) on an item. */ +static cJSON_bool print_string(const cJSON * const item, printbuffer * const p) +{ + return print_string_ptr((unsigned char*)item->valuestring, p); +} + +/* Predeclare these prototypes. */ +static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer); +static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer); +static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer); + +/* Utility to jump whitespace and cr/lf */ +static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) +{ + if ((buffer == NULL) || (buffer->content == NULL)) + { + return NULL; + } + + if (cannot_access_at_index(buffer, 0)) + { + return buffer; + } + + while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) + { + buffer->offset++; + } + + if (buffer->offset == buffer->length) + { + buffer->offset--; + } + + return buffer; +} + +/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */ +static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) +{ + if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) + { + return NULL; + } + + if (can_access_at_index(buffer, 4) && (HAL_STRNCMP((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) + { + buffer->offset += 3; + } + + return buffer; +} + +cJSON * cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) +{ + quint32_t buffer_length; + + if (NULL == value) + { + return NULL; + } + + /* Adding null character size due to require_null_terminated. */ + buffer_length = HAL_STRLEN(value) + sizeof(""); + + return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end, require_null_terminated); +} + +/* Parse an object - create a new root, and populate. */ +cJSON * cJSON_ParseWithLengthOpts(const char *value, quint32_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated) +{ + parse_buffer buffer = { 0, 0, 0, 0 }; + cJSON *item = NULL; + + /* reset error position */ + global_error.json = NULL; + global_error.position = 0; + + if (value == NULL || 0 == buffer_length) + { + goto fail; + } + + buffer.content = (const unsigned char*)value; + buffer.length = buffer_length; + buffer.offset = 0; + + item = cJSON_New_Item(); + if (item == NULL) /* memory fail */ + { + goto fail; + } + + if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)))) + { + /* parse failure. ep is set. */ + goto fail; + } + + /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ + if (require_null_terminated) + { + buffer_skip_whitespace(&buffer); + if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') + { + goto fail; + } + } + if (return_parse_end) + { + *return_parse_end = (const char*)buffer_at_offset(&buffer); + } + + return item; + +fail: + if (item != NULL) + { + cJSON_Delete(item); + } + + if (value != NULL) + { + error local_error; + local_error.json = (const unsigned char*)value; + local_error.position = 0; + + if (buffer.offset < buffer.length) + { + local_error.position = buffer.offset; + } + else if (buffer.length > 0) + { + local_error.position = buffer.length - 1; + } + + if (return_parse_end != NULL) + { + *return_parse_end = (const char*)local_error.json + local_error.position; + } + + global_error = local_error; + } + + return NULL; +} + +/* Default options for cJSON_Parse */ +cJSON * cJSON_Parse(const char *value) +{ + return cJSON_ParseWithOpts(value, 0, 0); +} + +cJSON * cJSON_ParseWithLength(const char *value, quint32_t buffer_length) +{ + return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0); +} + +#define cjson_min(a, b) (((a) < (b)) ? (a) : (b)) + +static unsigned char *print(const cJSON * const item, cJSON_bool format) +{ + static const quint32_t default_buffer_size = 256; + printbuffer buffer[1]; + unsigned char *printed = NULL; + + HAL_MEMSET(buffer, 0, sizeof(buffer)); + + /* create buffer */ + buffer->buffer = HAL_MALLOC(default_buffer_size); + buffer->length = default_buffer_size; + buffer->format = format; + if (buffer->buffer == NULL) + { + goto fail; + } + + /* print the value */ + if (!print_value(item, buffer)) + { + goto fail; + } + update_offset(buffer); + + printed = HAL_MALLOC(buffer->offset + 1); + if (printed == NULL) + { + goto fail; + } + HAL_MEMCPY(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1)); + printed[buffer->offset] = '\0'; /* just to be sure */ + + /* free the buffer */ + HAL_FREE(buffer->buffer); + + return printed; + +fail: + if (buffer->buffer != NULL) + { + HAL_FREE(buffer->buffer); + } + + if (printed != NULL) + { + HAL_FREE(printed); + } + + return NULL; +} + +/* Render a cJSON item/entity/structure to text. */ +char * cJSON_Print(const cJSON *item) +{ + return (char*)print(item, TRUE); +} + +char * cJSON_PrintUnformatted(const cJSON *item) +{ + return (char*)print(item, FALSE); +} + +char * cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt) +{ + printbuffer p = { 0, 0, 0, 0, 0, 0}; + + if (prebuffer < 0) + { + return NULL; + } + + p.buffer = HAL_MALLOC((quint32_t)prebuffer); + if (!p.buffer) + { + return NULL; + } + + p.length = (quint32_t)prebuffer; + p.offset = 0; + p.noalloc = FALSE; + p.format = fmt; + + if (!print_value(item, &p)) + { + HAL_FREE(p.buffer); + return NULL; + } + + return (char*)p.buffer; +} + +cJSON_bool cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) +{ + printbuffer p = { 0, 0, 0, 0, 0, 0}; + + if ((length < 0) || (buffer == NULL)) + { + return FALSE; + } + + p.buffer = (unsigned char*)buffer; + p.length = (quint32_t)length; + p.offset = 0; + p.noalloc = TRUE; + p.format = format; + + return print_value(item, &p); +} + +/* Parser core - when encountering text, process appropriately. */ +static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer) +{ + if ((input_buffer == NULL) || (input_buffer->content == NULL)) + { + return FALSE; /* no input */ + } + + /* parse the different types of values */ + /* null */ + if (can_read(input_buffer, 4) && (HAL_STRNCASECMP((const char*)buffer_at_offset(input_buffer), "null", 4) == 0)) + { + item->type = QUOS_cJSON_NULL; + input_buffer->offset += 4; + return TRUE; + } + /* FALSE */ + if (can_read(input_buffer, 5) && (HAL_STRNCASECMP((const char*)buffer_at_offset(input_buffer), "false", 5) == 0)) + { + item->type = QUOS_cJSON_False; + input_buffer->offset += 5; + return TRUE; + } + /* TRUE */ + if (can_read(input_buffer, 4) && (HAL_STRNCASECMP((const char*)buffer_at_offset(input_buffer), "true", 4) == 0)) + { + item->type = QUOS_cJSON_True; + item->valueint = 1; + input_buffer->offset += 4; + return TRUE; + } + /* string */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) + { + return parse_string(item, input_buffer); + } + /* number */ + if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) + { + return parse_number(item, input_buffer); + } + /* array */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) + { + return parse_array(item, input_buffer); + } + /* object */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) + { + return parse_object(item, input_buffer); + } + + return FALSE; +} + +/* Render a value to text. */ +static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output = NULL; + + if ((item == NULL) || (output_buffer == NULL)) + { + return FALSE; + } + + switch ((item->type) & 0xFF) + { + case QUOS_cJSON_NULL: + output = ensure(output_buffer, 5); + if (output == NULL) + { + return FALSE; + } + HAL_STRCPY((char*)output, "null"); + return TRUE; + + case QUOS_cJSON_False: + output = ensure(output_buffer, 6); + if (output == NULL) + { + return FALSE; + } + HAL_STRCPY((char*)output, "false"); + return TRUE; + + case QUOS_cJSON_True: + output = ensure(output_buffer, 5); + if (output == NULL) + { + return FALSE; + } + HAL_STRCPY((char*)output, "true"); + return TRUE; + + case QUOS_cJSON_Number: + return print_number(item, output_buffer); + + case QUOS_cJSON_Raw: + { + quint32_t raw_length = 0; + if (item->valuestring == NULL) + { + return FALSE; + } + + raw_length = HAL_STRLEN(item->valuestring) + sizeof(""); + output = ensure(output_buffer, raw_length); + if (output == NULL) + { + return FALSE; + } + HAL_MEMCPY(output, item->valuestring, raw_length); + return TRUE; + } + + case QUOS_cJSON_String: + return print_string(item, output_buffer); + + case QUOS_cJSON_Array: + return print_array(item, output_buffer); + + case QUOS_cJSON_Object: + return print_object(item, output_buffer); + + default: + return FALSE; + } +} + +/* Build an array from input text. */ +static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer) +{ + cJSON *head = NULL; /* head of the linked list */ + cJSON *current_item = NULL; + + if (input_buffer->depth >= QUOS_CJSON_NESTING_LIMIT) + { + return FALSE; /* to deeply nested */ + } + input_buffer->depth++; + + if (buffer_at_offset(input_buffer)[0] != '[') + { + /* not an array */ + goto fail; + } + + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) + { + /* empty array */ + goto success; + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(input_buffer, 0)) + { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + /* loop through the comma separated array elements */ + do + { + /* allocate next item */ + cJSON *new_item = cJSON_New_Item(); + if (new_item == NULL) + { + goto fail; /* allocation failure */ + } + + /* attach next item to list */ + if (head == NULL) + { + /* start the linked list */ + current_item = head = new_item; + } + else + { + /* add to the end and advance */ + current_item->next = new_item; + new_item->prev = current_item; + current_item = new_item; + } + + /* parse next value */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_value(current_item, input_buffer)) + { + goto fail; /* failed to parse value */ + } + buffer_skip_whitespace(input_buffer); + } + while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + + if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') + { + goto fail; /* expected end of array */ + } + +success: + input_buffer->depth--; + + if (head != NULL) { + head->prev = current_item; + } + + item->type = QUOS_cJSON_Array; + item->child = head; + + input_buffer->offset++; + + return TRUE; + +fail: + if (head != NULL) + { + cJSON_Delete(head); + } + + return FALSE; +} + +/* Render an array to text */ +static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + quint32_t length = 0; + cJSON *current_element = item->child; + + if (output_buffer == NULL) + { + return FALSE; + } + + /* Compose the output array. */ + /* opening square bracket */ + output_pointer = ensure(output_buffer, 1); + if (output_pointer == NULL) + { + return FALSE; + } + + *output_pointer = '['; + output_buffer->offset++; + output_buffer->depth++; + + while (current_element != NULL) + { + if (!print_value(current_element, output_buffer)) + { + return FALSE; + } + update_offset(output_buffer); + if (current_element->next) + { + length = (quint32_t) (output_buffer->format ? 2 : 1); + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return FALSE; + } + *output_pointer++ = ','; + if(output_buffer->format) + { + *output_pointer++ = ' '; + } + *output_pointer = '\0'; + output_buffer->offset += length; + } + current_element = current_element->next; + } + + output_pointer = ensure(output_buffer, 2); + if (output_pointer == NULL) + { + return FALSE; + } + *output_pointer++ = ']'; + *output_pointer = '\0'; + output_buffer->depth--; + + return TRUE; +} + +/* Build an object from the text. */ +static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer) +{ + cJSON *head = NULL; /* linked list head */ + cJSON *current_item = NULL; + + if (input_buffer->depth >= QUOS_CJSON_NESTING_LIMIT) + { + return FALSE; /* to deeply nested */ + } + input_buffer->depth++; + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) + { + goto fail; /* not an object */ + } + + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) + { + goto success; /* empty object */ + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(input_buffer, 0)) + { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + /* loop through the comma separated array elements */ + do + { + /* allocate next item */ + cJSON *new_item = cJSON_New_Item(); + if (new_item == NULL) + { + goto fail; /* allocation failure */ + } + + /* attach next item to list */ + if (head == NULL) + { + /* start the linked list */ + current_item = head = new_item; + } + else + { + /* add to the end and advance */ + current_item->next = new_item; + new_item->prev = current_item; + current_item = new_item; + } + + /* parse the name of the child */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_string(current_item, input_buffer)) + { + goto fail; /* failed to parse name */ + } + buffer_skip_whitespace(input_buffer); + + /* swap valuestring and string, because we parsed the name */ + current_item->string = current_item->valuestring; + current_item->valuestring = NULL; + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) + { + goto fail; /* invalid object */ + } + + /* parse the value */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_value(current_item, input_buffer)) + { + goto fail; /* failed to parse value */ + } + buffer_skip_whitespace(input_buffer); + } + while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) + { + goto fail; /* expected end of object */ + } + +success: + input_buffer->depth--; + + if (head != NULL) { + head->prev = current_item; + } + + item->type = QUOS_cJSON_Object; + item->child = head; + + input_buffer->offset++; + return TRUE; + +fail: + if (head != NULL) + { + cJSON_Delete(head); + } + + return FALSE; +} + +/* Render an object to text. */ +static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + quint32_t length = 0; + cJSON *current_item = item->child; + + if (output_buffer == NULL) + { + return FALSE; + } + + /* Compose the output: */ + length = (quint32_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */ + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return FALSE; + } + + *output_pointer++ = '{'; + output_buffer->depth++; + if (output_buffer->format) + { + *output_pointer++ = '\n'; + } + output_buffer->offset += length; + + while (current_item) + { + if (output_buffer->format) + { + quint32_t i; + output_pointer = ensure(output_buffer, output_buffer->depth); + if (output_pointer == NULL) + { + return FALSE; + } + for (i = 0; i < output_buffer->depth; i++) + { + *output_pointer++ = '\t'; + } + output_buffer->offset += output_buffer->depth; + } + + /* print key */ + if (!print_string_ptr((unsigned char*)current_item->string, output_buffer)) + { + return FALSE; + } + update_offset(output_buffer); + + length = (quint32_t) (output_buffer->format ? 2 : 1); + output_pointer = ensure(output_buffer, length); + if (output_pointer == NULL) + { + return FALSE; + } + *output_pointer++ = ':'; + if (output_buffer->format) + { + *output_pointer++ = '\t'; + } + output_buffer->offset += length; + + /* print value */ + if (!print_value(current_item, output_buffer)) + { + return FALSE; + } + update_offset(output_buffer); + + /* print comma if not last */ + length = ((quint32_t)(output_buffer->format ? 1 : 0) + (quint32_t)(current_item->next ? 1 : 0)); + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return FALSE; + } + if (current_item->next) + { + *output_pointer++ = ','; + } + + if (output_buffer->format) + { + *output_pointer++ = '\n'; + } + *output_pointer = '\0'; + output_buffer->offset += length; + + current_item = current_item->next; + } + + output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2); + if (output_pointer == NULL) + { + return FALSE; + } + if (output_buffer->format) + { + quint32_t i; + for (i = 0; i < (output_buffer->depth - 1); i++) + { + *output_pointer++ = '\t'; + } + } + *output_pointer++ = '}'; + *output_pointer = '\0'; + output_buffer->depth--; + + return TRUE; +} + +/* Get Array size/item / object item. */ +int cJSON_GetArraySize(const cJSON *array) +{ + cJSON *child = NULL; + quint32_t size = 0; + + if (array == NULL) + { + return 0; + } + + child = array->child; + + while(child != NULL) + { + size++; + child = child->next; + } + + /* FIXME: Can overflow here. Cannot be fixed without breaking the API */ + + return (int)size; +} + +static cJSON* get_array_item(const cJSON *array, quint32_t index) +{ + cJSON *current_child = NULL; + + if (array == NULL) + { + return NULL; + } + + current_child = array->child; + while ((current_child != NULL) && (index > 0)) + { + index--; + current_child = current_child->next; + } + + return current_child; +} + +cJSON * cJSON_GetArrayItem(const cJSON *array, int index) +{ + if (index < 0) + { + return NULL; + } + + return get_array_item(array, (quint32_t)index); +} + +static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive) +{ + cJSON *current_element = NULL; + + if ((object == NULL) || (name == NULL)) + { + return NULL; + } + + current_element = object->child; + if (case_sensitive) + { + while ((current_element != NULL) && (current_element->string != NULL) && (HAL_STRCMP(name, current_element->string) != 0)) + { + current_element = current_element->next; + } + } + else + { + while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0)) + { + current_element = current_element->next; + } + } + + if ((current_element == NULL) || (current_element->string == NULL)) { + return NULL; + } + + return current_element; +} + +cJSON * cJSON_GetObjectItem(const cJSON * const object, const char * const string) +{ + return get_object_item(object, string, FALSE); +} + +cJSON * cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string) +{ + return get_object_item(object, string, TRUE); +} + +cJSON_bool cJSON_HasObjectItem(const cJSON *object, const char *string) +{ + return cJSON_GetObjectItem(object, string) ? 1 : 0; +} + +/* Utility for array list handling. */ +static void suffix_object(cJSON *prev, cJSON *item) +{ + prev->next = item; + item->prev = prev; +} + +/* Utility for handling references. */ +static cJSON *create_reference(const cJSON *item) +{ + cJSON *reference = NULL; + if (item == NULL) + { + return NULL; + } + + reference = cJSON_New_Item(); + if (reference == NULL) + { + return NULL; + } + + HAL_MEMCPY(reference, item, sizeof(cJSON)); + reference->string = NULL; + reference->type |= QUOS_cJSON_IsReference; + reference->next = reference->prev = NULL; + return reference; +} + +static cJSON_bool add_item_to_array(cJSON *array, cJSON *item) +{ + cJSON *child = NULL; + + if ((item == NULL) || (array == NULL) || (array == item)) + { + return FALSE; + } + + child = array->child; + /* + * To find the last item in array quickly, we use prev in array + */ + if (child == NULL) + { + /* list is empty, start new one */ + array->child = item; + item->prev = item; + item->next = NULL; + } + else + { + /* append to the end */ + if (child->prev) + { + suffix_object(child->prev, item); + array->child->prev = item; + } + } + + return TRUE; +} + +/* Add item to array/object. */ +cJSON_bool cJSON_AddItemToArray(cJSON *array, cJSON *item) +{ + return add_item_to_array(array, item); +} + +#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) + #pragma GCC diagnostic push +#endif +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif +/* helper function to cast away const */ +static void* cast_away_const(const void* string) +{ + return (void*)string; +} +#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) + #pragma GCC diagnostic pop +#endif + + +static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const cJSON_bool constant_key) +{ + char *new_key = NULL; + int new_type = QUOS_cJSON_Invalid; + + if ((object == NULL) || (string == NULL) || (item == NULL) || (object == item)) + { + return FALSE; + } + + if (constant_key) + { + new_key = (char*)cast_away_const(string); + new_type = item->type | QUOS_cJSON_StringIsConst; + } + else + { + new_key = HAL_STRDUP(string); + if (new_key == NULL) + { + return FALSE; + } + + new_type = item->type & ~QUOS_cJSON_StringIsConst; + } + + if (!(item->type & QUOS_cJSON_StringIsConst) && (item->string != NULL)) + { + HAL_FREE(item->string); + } + + item->string = new_key; + item->type = new_type; + + return add_item_to_array(object, item); +} + +cJSON_bool cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) +{ + return add_item_to_object(object, string, item, FALSE); +} + +/* Add an item to an object with constant string as key */ +cJSON_bool cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) +{ + return add_item_to_object(object, string, item, TRUE); +} + +cJSON_bool cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) +{ + if (array == NULL) + { + return FALSE; + } + + return add_item_to_array(array, create_reference(item)); +} + +cJSON_bool cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) +{ + if ((object == NULL) || (string == NULL)) + { + return FALSE; + } + + return add_item_to_object(object, string, create_reference(item), FALSE); +} + +cJSON* cJSON_AddNullToObject(cJSON * const object, const char * const name) +{ + cJSON *null = cJSON_CreateNull(); + if (add_item_to_object(object, name, null, FALSE)) + { + return null; + } + + cJSON_Delete(null); + return NULL; +} + +cJSON* cJSON_AddTrueToObject(cJSON * const object, const char * const name) +{ + cJSON *true_item = cJSON_CreateTrue(); + if (add_item_to_object(object, name, true_item, FALSE)) + { + return true_item; + } + + cJSON_Delete(true_item); + return NULL; +} + +cJSON* cJSON_AddFalseToObject(cJSON * const object, const char * const name) +{ + cJSON *false_item = cJSON_CreateFalse(); + if (add_item_to_object(object, name, false_item, FALSE)) + { + return false_item; + } + + cJSON_Delete(false_item); + return NULL; +} + +cJSON* cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean) +{ + cJSON *bool_item = cJSON_CreateBool(boolean); + if (add_item_to_object(object, name, bool_item, FALSE)) + { + return bool_item; + } + + cJSON_Delete(bool_item); + return NULL; +} + +cJSON* cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number) +{ + cJSON *number_item = cJSON_CreateNumber(number); + if (add_item_to_object(object, name, number_item, FALSE)) + { + return number_item; + } + + cJSON_Delete(number_item); + return NULL; +} + +cJSON* cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string) +{ + cJSON *string_item = cJSON_CreateString(string); + if (add_item_to_object(object, name, string_item, FALSE)) + { + return string_item; + } + + cJSON_Delete(string_item); + return NULL; +} + +cJSON* cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw) +{ + cJSON *raw_item = cJSON_CreateRaw(raw); + if (add_item_to_object(object, name, raw_item, FALSE)) + { + return raw_item; + } + + cJSON_Delete(raw_item); + return NULL; +} + +cJSON* cJSON_AddObjectToObject(cJSON * const object, const char * const name) +{ + cJSON *object_item = cJSON_CreateObject(); + if (add_item_to_object(object, name, object_item, FALSE)) + { + return object_item; + } + + cJSON_Delete(object_item); + return NULL; +} + +cJSON* cJSON_AddArrayToObject(cJSON * const object, const char * const name) +{ + cJSON *array = cJSON_CreateArray(); + if (add_item_to_object(object, name, array, FALSE)) + { + return array; + } + + cJSON_Delete(array); + return NULL; +} + +cJSON * cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item) +{ + if ((parent == NULL) || (item == NULL)) + { + return NULL; + } + + if (item != parent->child) + { + /* not the first element */ + item->prev->next = item->next; + } + if (item->next != NULL) + { + /* not the last element */ + item->next->prev = item->prev; + } + + if (item == parent->child) + { + /* first element */ + parent->child = item->next; + } + else if (item->next == NULL) + { + /* last element */ + parent->child->prev = item->prev; + } + + /* make sure the detached item doesn't point anywhere anymore */ + item->prev = NULL; + item->next = NULL; + + return item; +} + +cJSON * cJSON_DetachItemFromArray(cJSON *array, int which) +{ + if (which < 0) + { + return NULL; + } + + return cJSON_DetachItemViaPointer(array, get_array_item(array, (quint32_t)which)); +} + +void cJSON_DeleteItemFromArray(cJSON *array, int which) +{ + cJSON_Delete(cJSON_DetachItemFromArray(array, which)); +} + +cJSON * cJSON_DetachItemFromObject(cJSON *object, const char *string) +{ + cJSON *to_detach = cJSON_GetObjectItem(object, string); + + return cJSON_DetachItemViaPointer(object, to_detach); +} + +cJSON * cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string) +{ + cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string); + + return cJSON_DetachItemViaPointer(object, to_detach); +} + +void cJSON_DeleteItemFromObject(cJSON *object, const char *string) +{ + cJSON_Delete(cJSON_DetachItemFromObject(object, string)); +} + +void cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string) +{ + cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string)); +} + +/* Replace array/object items with new ones. */ +cJSON_bool cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) +{ + cJSON *after_inserted = NULL; + + if (which < 0) + { + return FALSE; + } + + after_inserted = get_array_item(array, (quint32_t)which); + if (after_inserted == NULL) + { + return add_item_to_array(array, newitem); + } + + newitem->next = after_inserted; + newitem->prev = after_inserted->prev; + after_inserted->prev = newitem; + if (after_inserted == array->child) + { + array->child = newitem; + } + else + { + newitem->prev->next = newitem; + } + return TRUE; +} + +cJSON_bool cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement) +{ + if ((parent == NULL) || (replacement == NULL) || (item == NULL)) + { + return FALSE; + } + + if (replacement == item) + { + return TRUE; + } + + replacement->next = item->next; + replacement->prev = item->prev; + + if (replacement->next != NULL) + { + replacement->next->prev = replacement; + } + if (parent->child == item) + { + if (parent->child->prev == parent->child) + { + replacement->prev = replacement; + } + parent->child = replacement; + } + else + { /* + * To find the last item in array quickly, we use prev in array. + * We can't modify the last item's next pointer where this item was the parent's child + */ + if (replacement->prev != NULL) + { + replacement->prev->next = replacement; + } + if (replacement->next == NULL) + { + parent->child->prev = replacement; + } + } + + item->next = NULL; + item->prev = NULL; + cJSON_Delete(item); + + return TRUE; +} + +cJSON_bool cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) +{ + if (which < 0) + { + return FALSE; + } + + return cJSON_ReplaceItemViaPointer(array, get_array_item(array, (quint32_t)which), newitem); +} + +static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive) +{ + if ((replacement == NULL) || (string == NULL)) + { + return FALSE; + } + + /* replace the name in the replacement */ + if (!(replacement->type & QUOS_cJSON_StringIsConst) && (replacement->string != NULL)) + { + HAL_FREE(replacement->string); + } + replacement->string = HAL_STRDUP(string); + replacement->type &= ~QUOS_cJSON_StringIsConst; + + return cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement); +} + +cJSON_bool cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) +{ + return replace_item_in_object(object, string, newitem, FALSE); +} + +cJSON_bool cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem) +{ + return replace_item_in_object(object, string, newitem, TRUE); +} + +/* Create basic types: */ +cJSON * cJSON_CreateNull(void) +{ + cJSON *item = cJSON_New_Item(); + if(item) + { + item->type = QUOS_cJSON_NULL; + } + + return item; +} + +cJSON * cJSON_CreateTrue(void) +{ + cJSON *item = cJSON_New_Item(); + if(item) + { + item->type = QUOS_cJSON_True; + } + + return item; +} + +cJSON * cJSON_CreateFalse(void) +{ + cJSON *item = cJSON_New_Item(); + if(item) + { + item->type = QUOS_cJSON_False; + } + + return item; +} + +cJSON * cJSON_CreateBool(cJSON_bool boolean) +{ + cJSON *item = cJSON_New_Item(); + if(item) + { + item->type = boolean ? QUOS_cJSON_True : QUOS_cJSON_False; + } + + return item; +} + +cJSON * cJSON_CreateNumber(double num) +{ + cJSON *item = cJSON_New_Item(); + if(item) + { + item->type = QUOS_cJSON_Number; + item->valuedouble = num; + + /* use saturation in case of overflow */ + if (num >= INT_MAX) + { + item->valueint = INT_MAX; + } + else if (num <= (double)INT_MIN) + { + item->valueint = INT_MIN; + } + else + { + item->valueint = (int)num; + } + } + + return item; +} + +cJSON * cJSON_CreateString(const char *string) +{ + cJSON *item = cJSON_New_Item(); + if(item) + { + item->type = QUOS_cJSON_String; + item->valuestring = HAL_STRDUP(string); + if(!item->valuestring) + { + cJSON_Delete(item); + return NULL; + } + } + + return item; +} + +cJSON * cJSON_CreateStringReference(const char *string) +{ + cJSON *item = cJSON_New_Item(); + if (item != NULL) + { + item->type = QUOS_cJSON_String | QUOS_cJSON_IsReference; + item->valuestring = (char*)cast_away_const(string); + } + + return item; +} + +cJSON * cJSON_CreateObjectReference(const cJSON *child) +{ + cJSON *item = cJSON_New_Item(); + if (item != NULL) { + item->type = QUOS_cJSON_Object | QUOS_cJSON_IsReference; + item->child = (cJSON*)cast_away_const(child); + } + + return item; +} + +cJSON * cJSON_CreateArrayReference(const cJSON *child) +{ + cJSON *item = cJSON_New_Item(); + if (item != NULL) { + item->type = QUOS_cJSON_Array | QUOS_cJSON_IsReference; + item->child = (cJSON*)cast_away_const(child); + } + + return item; +} + +cJSON * cJSON_CreateRaw(const char *raw) +{ + cJSON *item = cJSON_New_Item(); + if(item) + { + item->type = QUOS_cJSON_Raw; + item->valuestring = HAL_STRDUP(raw); + if(!item->valuestring) + { + cJSON_Delete(item); + return NULL; + } + } + + return item; +} + +cJSON * cJSON_CreateArray(void) +{ + cJSON *item = cJSON_New_Item(); + if(item) + { + item->type=QUOS_cJSON_Array; + } + + return item; +} + +cJSON * cJSON_CreateObject(void) +{ + cJSON *item = cJSON_New_Item(); + if (item) + { + item->type = QUOS_cJSON_Object; + } + + return item; +} + +/* Create Arrays: */ +cJSON * cJSON_CreateIntArray(const int *numbers, int count) +{ + quint32_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + for(i = 0; a && (i < (quint32_t)count); i++) + { + n = cJSON_CreateNumber(numbers[i]); + if (!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + a->child->prev = n; + + return a; +} + +cJSON * cJSON_CreateFloatArray(const float *numbers, int count) +{ + quint32_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for(i = 0; a && (i < (quint32_t)count); i++) + { + n = cJSON_CreateNumber((double)numbers[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + a->child->prev = n; + + return a; +} + +cJSON * cJSON_CreateDoubleArray(const double *numbers, int count) +{ + quint32_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for(i = 0;a && (i < (quint32_t)count); i++) + { + n = cJSON_CreateNumber(numbers[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + a->child->prev = n; + + return a; +} + +cJSON * cJSON_CreateStringArray(const char *const *strings, int count) +{ + quint32_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (strings == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for (i = 0; a && (i < (quint32_t)count); i++) + { + n = cJSON_CreateString(strings[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p,n); + } + p = n; + } + a->child->prev = n; + + return a; +} + +/* Duplication */ +cJSON * cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) +{ + cJSON *newitem = NULL; + cJSON *child = NULL; + cJSON *next = NULL; + cJSON *newchild = NULL; + + /* Bail on bad ptr */ + if (!item) + { + goto fail; + } + /* Create new item */ + newitem = cJSON_New_Item(); + if (!newitem) + { + goto fail; + } + /* Copy over all vars */ + newitem->type = item->type & (~QUOS_cJSON_IsReference); + newitem->valueint = item->valueint; + newitem->valuedouble = item->valuedouble; + if (item->valuestring) + { + newitem->valuestring = HAL_STRDUP(item->valuestring); + if (!newitem->valuestring) + { + goto fail; + } + } + if (item->string) + { + newitem->string = (item->type&QUOS_cJSON_StringIsConst) ? item->string : HAL_STRDUP(item->string); + if (!newitem->string) + { + goto fail; + } + } + /* If non-recursive, then we're done! */ + if (!recurse) + { + return newitem; + } + /* Walk the ->next chain for the child. */ + child = item->child; + while (child != NULL) + { + newchild = cJSON_Duplicate(child, TRUE); /* Duplicate (with recurse) each item in the ->next chain */ + if (!newchild) + { + goto fail; + } + if (next != NULL) + { + /* If newitem->child already set, then crosswire ->prev and ->next and move on */ + next->next = newchild; + newchild->prev = next; + next = newchild; + } + else + { + /* Set newitem->child and move to it */ + newitem->child = newchild; + next = newchild; + } + child = child->next; + } + if (newitem && newitem->child) + { + newitem->child->prev = newchild; + } + + return newitem; + +fail: + if (newitem != NULL) + { + cJSON_Delete(newitem); + } + + return NULL; +} + +static void skip_oneline_comment(char **input) +{ + *input += static_strlen("//"); + + for (; (*input)[0] != '\0'; ++(*input)) + { + if ((*input)[0] == '\n') { + *input += static_strlen("\n"); + return; + } + } +} + +static void skip_multiline_comment(char **input) +{ + *input += static_strlen("/*"); + + for (; (*input)[0] != '\0'; ++(*input)) + { + if (((*input)[0] == '*') && ((*input)[1] == '/')) + { + *input += static_strlen("*/"); + return; + } + } +} + +static void minify_string(char **input, char **output) { + (*output)[0] = (*input)[0]; + *input += static_strlen("\""); + *output += static_strlen("\""); + + + for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) { + (*output)[0] = (*input)[0]; + + if ((*input)[0] == '\"') { + (*output)[0] = '\"'; + *input += static_strlen("\""); + *output += static_strlen("\""); + return; + } else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) { + (*output)[1] = (*input)[1]; + *input += static_strlen("\""); + *output += static_strlen("\""); + } + } +} + +void cJSON_Minify(char *json) +{ + char *into = json; + + if (json == NULL) + { + return; + } + + while (json[0] != '\0') + { + switch (json[0]) + { + case ' ': + case '\t': + case '\r': + case '\n': + json++; + break; + + case '/': + if (json[1] == '/') + { + skip_oneline_comment(&json); + } + else if (json[1] == '*') + { + skip_multiline_comment(&json); + } else { + json++; + } + break; + + case '\"': + minify_string(&json, (char**)&into); + break; + + default: + into[0] = json[0]; + json++; + into++; + } + } + + /* and null-terminate. */ + *into = '\0'; +} + +cJSON_bool cJSON_IsInvalid(const cJSON * const item) +{ + if (item == NULL) + { + return FALSE; + } + + return (item->type & 0xFF) == QUOS_cJSON_Invalid; +} + +cJSON_bool cJSON_IsFalse(const cJSON * const item) +{ + if (item == NULL) + { + return FALSE; + } + + return (item->type & 0xFF) == QUOS_cJSON_False; +} + +cJSON_bool cJSON_IsTrue(const cJSON * const item) +{ + if (item == NULL) + { + return FALSE; + } + + return (item->type & 0xff) == QUOS_cJSON_True; +} + + +cJSON_bool cJSON_IsBool(const cJSON * const item) +{ + if (item == NULL) + { + return FALSE; + } + + return (item->type & (QUOS_cJSON_True | QUOS_cJSON_False)) != 0; +} +cJSON_bool cJSON_IsNull(const cJSON * const item) +{ + if (item == NULL) + { + return FALSE; + } + + return (item->type & 0xFF) == QUOS_cJSON_NULL; +} + +cJSON_bool cJSON_IsNumber(const cJSON * const item) +{ + if (item == NULL) + { + return FALSE; + } + + return (item->type & 0xFF) == QUOS_cJSON_Number; +} + +cJSON_bool cJSON_IsString(const cJSON * const item) +{ + if (item == NULL) + { + return FALSE; + } + + return (item->type & 0xFF) == QUOS_cJSON_String; +} + +cJSON_bool cJSON_IsArray(const cJSON * const item) +{ + if (item == NULL) + { + return FALSE; + } + + return (item->type & 0xFF) == QUOS_cJSON_Array; +} + +cJSON_bool cJSON_IsObject(const cJSON * const item) +{ + if (item == NULL) + { + return FALSE; + } + + return (item->type & 0xFF) == QUOS_cJSON_Object; +} + +cJSON_bool cJSON_IsRaw(const cJSON * const item) +{ + if (item == NULL) + { + return FALSE; + } + + return (item->type & 0xFF) == QUOS_cJSON_Raw; +} + +cJSON_bool cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive) +{ + if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a)) + { + return FALSE; + } + + /* check if type is valid */ + switch (a->type & 0xFF) + { + case QUOS_cJSON_False: + case QUOS_cJSON_True: + case QUOS_cJSON_NULL: + case QUOS_cJSON_Number: + case QUOS_cJSON_String: + case QUOS_cJSON_Raw: + case QUOS_cJSON_Array: + case QUOS_cJSON_Object: + break; + + default: + return FALSE; + } + + /* identical objects are equal */ + if (a == b) + { + return TRUE; + } + + switch (a->type & 0xFF) + { + /* in these cases and equal type is enough */ + case QUOS_cJSON_False: + case QUOS_cJSON_True: + case QUOS_cJSON_NULL: + return TRUE; + + case QUOS_cJSON_Number: + if (compare_double(a->valuedouble, b->valuedouble)) + { + return TRUE; + } + return FALSE; + + case QUOS_cJSON_String: + case QUOS_cJSON_Raw: + if ((a->valuestring == NULL) || (b->valuestring == NULL)) + { + return FALSE; + } + if (HAL_STRCMP(a->valuestring, b->valuestring) == 0) + { + return TRUE; + } + + return FALSE; + + case QUOS_cJSON_Array: + { + cJSON *a_element = a->child; + cJSON *b_element = b->child; + + for (; (a_element != NULL) && (b_element != NULL);) + { + if (!cJSON_Compare(a_element, b_element, case_sensitive)) + { + return FALSE; + } + + a_element = a_element->next; + b_element = b_element->next; + } + + /* one of the arrays is longer than the other */ + if (a_element != b_element) { + return FALSE; + } + + return TRUE; + } + + case QUOS_cJSON_Object: + { + cJSON *a_element = NULL; + cJSON *b_element = NULL; + QUOS_cJSON_ArrayForEach(a_element, a) + { + /* TODO This has O(n^2) runtime, which is horrible! */ + b_element = get_object_item(b, a_element->string, case_sensitive); + if (b_element == NULL) + { + return FALSE; + } + + if (!cJSON_Compare(a_element, b_element, case_sensitive)) + { + return FALSE; + } + } + + /* doing this twice, once on a and b to prevent TRUE comparison if a subset of b + * TODO: Do this the proper way, this is just a fix for now */ + QUOS_cJSON_ArrayForEach(b_element, b) + { + a_element = get_object_item(a, b_element->string, case_sensitive); + if (a_element == NULL) + { + return FALSE; + } + + if (!cJSON_Compare(b_element, a_element, case_sensitive)) + { + return FALSE; + } + } + + return TRUE; + } + + default: + return FALSE; + } +} + +#endif \ No newline at end of file diff --git a/kernel/quos_cjson.h b/kernel/quos_cjson.h index 7a0a13dc045c47a885f080241280a7d9e98d90b0..c5c896c56579acc1a78895080fcb1112cf3ab3dd 100644 --- a/kernel/quos_cjson.h +++ b/kernel/quos_cjson.h @@ -1,220 +1,214 @@ -/* - Copyright (c) 2009-2017 Dave Gamble and cJSON contributors - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*/ - -#ifndef cJSON__h -#define cJSON__h - -#ifdef __cplusplus -extern "C" -{ -#endif -#include "quos_config.h" -/* cJSON Types: */ -#define QUOS_cJSON_Invalid (0) -#define QUOS_cJSON_False (1 << 0) -#define QUOS_cJSON_True (1 << 1) -#define QUOS_cJSON_NULL (1 << 2) -#define QUOS_cJSON_Number (1 << 3) -#define QUOS_cJSON_String (1 << 4) -#define QUOS_cJSON_Array (1 << 5) -#define QUOS_cJSON_Object (1 << 6) -#define QUOS_cJSON_Raw (1 << 7) /* raw json */ - -#define QUOS_cJSON_IsReference 256 -#define QUOS_cJSON_StringIsConst 512 - -/* The cJSON structure: */ -typedef struct cJSON -{ - /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ - struct cJSON *next; - struct cJSON *prev; - /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ - struct cJSON *child; - - /* The type of the item, as above. */ - int type; - - /* The item's string, if type==QUOS_cJSON_String and type == QUOS_cJSON_Raw */ - char *valuestring; - /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ - int valueint; - /* The item's number, if type==QUOS_cJSON_Number */ - double valuedouble; - - /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ - char *string; -} cJSON; - -typedef qbool cJSON_bool; - -/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them. - * This is to prevent stack overflows. */ -#ifndef QUOS_CJSON_NESTING_LIMIT -#define QUOS_CJSON_NESTING_LIMIT 1000 -#endif - -/* returns the version of cJSON as a string */ -const char* cJSON_Version(void); -/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ -cJSON * cJSON_Parse(const char *value); -cJSON * cJSON_ParseWithLength(const char *value, quint32_t buffer_length); -/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ -/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */ -cJSON * cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); -cJSON * cJSON_ParseWithLengthOpts(const char *value, quint32_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated); - -/* Render a cJSON entity to text for transfer/storage. */ -char * cJSON_Print(const cJSON *item); -/* Render a cJSON entity to text for transfer/storage without any formatting. */ -char * cJSON_PrintUnformatted(const cJSON *item); -/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ -char * cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt); -/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */ -/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */ -cJSON_bool cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); -/* Delete a cJSON entity and all subentities. */ -void cJSON_Delete(cJSON *item); - -/* Returns the number of items in an array (or object). */ -int cJSON_GetArraySize(const cJSON *array); -/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */ -cJSON * cJSON_GetArrayItem(const cJSON *array, int index); -/* Get item "string" from object. Case insensitive. */ -cJSON * cJSON_GetObjectItem(const cJSON * const object, const char * const string); -cJSON * cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string); -cJSON_bool cJSON_HasObjectItem(const cJSON *object, const char *string); -/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ -const char * cJSON_GetErrorPtr(void); - -/* Check item type and return its value */ -char * cJSON_GetStringValue(const cJSON * const item); -double cJSON_GetNumberValue(const cJSON * const item); - -/* These functions check the type of an item */ -cJSON_bool cJSON_IsInvalid(const cJSON * const item); -cJSON_bool cJSON_IsFalse(const cJSON * const item); -cJSON_bool cJSON_IsTrue(const cJSON * const item); -cJSON_bool cJSON_IsBool(const cJSON * const item); -cJSON_bool cJSON_IsNull(const cJSON * const item); -cJSON_bool cJSON_IsNumber(const cJSON * const item); -cJSON_bool cJSON_IsString(const cJSON * const item); -cJSON_bool cJSON_IsArray(const cJSON * const item); -cJSON_bool cJSON_IsObject(const cJSON * const item); -cJSON_bool cJSON_IsRaw(const cJSON * const item); - -/* These calls create a cJSON item of the appropriate type. */ -cJSON * cJSON_CreateNull(void); -cJSON * cJSON_CreateTrue(void); -cJSON * cJSON_CreateFalse(void); -cJSON * cJSON_CreateBool(cJSON_bool boolean); -cJSON * cJSON_CreateNumber(double num); -cJSON * cJSON_CreateString(const char *string); -/* raw json */ -cJSON * cJSON_CreateRaw(const char *raw); -cJSON * cJSON_CreateArray(void); -cJSON * cJSON_CreateObject(void); - -/* Create a string where valuestring references a string so - * it will not be freed by cJSON_Delete */ -cJSON * cJSON_CreateStringReference(const char *string); -/* Create an object/array that only references it's elements so - * they will not be freed by cJSON_Delete */ -cJSON * cJSON_CreateObjectReference(const cJSON *child); -cJSON * cJSON_CreateArrayReference(const cJSON *child); - -/* These utilities create an Array of count items. - * The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/ -cJSON * cJSON_CreateIntArray(const int *numbers, int count); -cJSON * cJSON_CreateFloatArray(const float *numbers, int count); -cJSON * cJSON_CreateDoubleArray(const double *numbers, int count); -cJSON * cJSON_CreateStringArray(const char *const *strings, int count); - -/* Append item to the specified array/object. */ -cJSON_bool cJSON_AddItemToArray(cJSON *array, cJSON *item); -cJSON_bool cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); -/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. - * WARNING: When this function was used, make sure to always check that (item->type & QUOS_cJSON_StringIsConst) is zero before - * writing to `item->string` */ -cJSON_bool cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); -/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ -cJSON_bool cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); -cJSON_bool cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); - -/* Remove/Detach items from Arrays/Objects. */ -cJSON * cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); -cJSON * cJSON_DetachItemFromArray(cJSON *array, int which); -void cJSON_DeleteItemFromArray(cJSON *array, int which); -cJSON * cJSON_DetachItemFromObject(cJSON *object, const char *string); -cJSON * cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string); -void cJSON_DeleteItemFromObject(cJSON *object, const char *string); -void cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string); - -/* Update array items. */ -cJSON_bool cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ -cJSON_bool cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement); -cJSON_bool cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); -cJSON_bool cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); -cJSON_bool cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem); - -/* Duplicate a cJSON item */ -cJSON * cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); -/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will - * need to be released. With recurse!=0, it will duplicate any children connected to the item. - * The item->next and ->prev pointers are always zero on return from Duplicate. */ -/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal. - * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ -cJSON_bool cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); - -/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings. - * The input pointer json cannot point to a read-only address area, such as a string constant, - * but should point to a readable and writable adress area. */ -void cJSON_Minify(char *json); - -/* Helper functions for creating and adding items to an object at the same time. - * They return the added item or NULL on failure. */ -cJSON* cJSON_AddNullToObject(cJSON * const object, const char * const name); -cJSON* cJSON_AddTrueToObject(cJSON * const object, const char * const name); -cJSON* cJSON_AddFalseToObject(cJSON * const object, const char * const name); -cJSON* cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean); -cJSON* cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number); -cJSON* cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string); -cJSON* cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw); -cJSON* cJSON_AddObjectToObject(cJSON * const object, const char * const name); -cJSON* cJSON_AddArrayToObject(cJSON * const object, const char * const name); - -/* When assigning an integer value, it needs to be propagated to valuedouble too. */ -#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) -/* helper for the cJSON_SetNumberValue macro */ -double cJSON_SetNumberHelper(cJSON *object, double number); -#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) -/* Change the valuestring of a QUOS_cJSON_String object, only takes effect when type of object is QUOS_cJSON_String */ -char* cJSON_SetValuestring(cJSON *object, const char *valuestring); - -/* Macro for iterating over an array or object */ -#define QUOS_cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) - -#ifdef __cplusplus -} -#endif - -#endif +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifndef cJSON__h +#define cJSON__h + +#include "quos_config.h" +#if (SDK_ENABLE_JSON ==1 ) +/* cJSON Types: */ +#define QUOS_cJSON_Invalid (0) +#define QUOS_cJSON_False (1 << 0) +#define QUOS_cJSON_True (1 << 1) +#define QUOS_cJSON_NULL (1 << 2) +#define QUOS_cJSON_Number (1 << 3) +#define QUOS_cJSON_String (1 << 4) +#define QUOS_cJSON_Array (1 << 5) +#define QUOS_cJSON_Object (1 << 6) +#define QUOS_cJSON_Raw (1 << 7) /* raw json */ + +#define QUOS_cJSON_IsReference 256 +#define QUOS_cJSON_StringIsConst 512 + +/* The cJSON structure: */ +typedef struct cJSON +{ + /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ + struct cJSON *next; + struct cJSON *prev; + /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ + struct cJSON *child; + + /* The type of the item, as above. */ + int type; + + /* The item's string, if type==QUOS_cJSON_String and type == QUOS_cJSON_Raw */ + char *valuestring; + /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ + int valueint; + /* The item's number, if type==QUOS_cJSON_Number */ + double valuedouble; + + /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ + char *string; +} cJSON; + +typedef qbool cJSON_bool; + +/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them. + * This is to prevent stack overflows. */ +#ifndef QUOS_CJSON_NESTING_LIMIT +#define QUOS_CJSON_NESTING_LIMIT 1000 +#endif + +/* returns the version of cJSON as a string */ +const char* cJSON_Version(void); +/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ +cJSON * cJSON_Parse(const char *value); +cJSON * cJSON_ParseWithLength(const char *value, quint32_t buffer_length); +/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ +/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */ +cJSON * cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); +cJSON * cJSON_ParseWithLengthOpts(const char *value, quint32_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated); + +/* Render a cJSON entity to text for transfer/storage. */ +char * cJSON_Print(const cJSON *item); +/* Render a cJSON entity to text for transfer/storage without any formatting. */ +char * cJSON_PrintUnformatted(const cJSON *item); +/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ +char * cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt); +/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */ +/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */ +cJSON_bool cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); +/* Delete a cJSON entity and all subentities. */ +void cJSON_Delete(cJSON *item); + +/* Returns the number of items in an array (or object). */ +int cJSON_GetArraySize(const cJSON *array); +/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */ +cJSON * cJSON_GetArrayItem(const cJSON *array, int index); +/* Get item "string" from object. Case insensitive. */ +cJSON * cJSON_GetObjectItem(const cJSON * const object, const char * const string); +cJSON * cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string); +cJSON_bool cJSON_HasObjectItem(const cJSON *object, const char *string); +/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ +const char * cJSON_GetErrorPtr(void); + +/* Check item type and return its value */ +char * cJSON_GetStringValue(const cJSON * const item); +double cJSON_GetNumberValue(const cJSON * const item); + +/* These functions check the type of an item */ +cJSON_bool cJSON_IsInvalid(const cJSON * const item); +cJSON_bool cJSON_IsFalse(const cJSON * const item); +cJSON_bool cJSON_IsTrue(const cJSON * const item); +cJSON_bool cJSON_IsBool(const cJSON * const item); +cJSON_bool cJSON_IsNull(const cJSON * const item); +cJSON_bool cJSON_IsNumber(const cJSON * const item); +cJSON_bool cJSON_IsString(const cJSON * const item); +cJSON_bool cJSON_IsArray(const cJSON * const item); +cJSON_bool cJSON_IsObject(const cJSON * const item); +cJSON_bool cJSON_IsRaw(const cJSON * const item); + +/* These calls create a cJSON item of the appropriate type. */ +cJSON * cJSON_CreateNull(void); +cJSON * cJSON_CreateTrue(void); +cJSON * cJSON_CreateFalse(void); +cJSON * cJSON_CreateBool(cJSON_bool boolean); +cJSON * cJSON_CreateNumber(double num); +cJSON * cJSON_CreateString(const char *string); +/* raw json */ +cJSON * cJSON_CreateRaw(const char *raw); +cJSON * cJSON_CreateArray(void); +cJSON * cJSON_CreateObject(void); + +/* Create a string where valuestring references a string so + * it will not be freed by cJSON_Delete */ +cJSON * cJSON_CreateStringReference(const char *string); +/* Create an object/array that only references it's elements so + * they will not be freed by cJSON_Delete */ +cJSON * cJSON_CreateObjectReference(const cJSON *child); +cJSON * cJSON_CreateArrayReference(const cJSON *child); + +/* These utilities create an Array of count items. + * The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/ +cJSON * cJSON_CreateIntArray(const int *numbers, int count); +cJSON * cJSON_CreateFloatArray(const float *numbers, int count); +cJSON * cJSON_CreateDoubleArray(const double *numbers, int count); +cJSON * cJSON_CreateStringArray(const char *const *strings, int count); + +/* Append item to the specified array/object. */ +cJSON_bool cJSON_AddItemToArray(cJSON *array, cJSON *item); +cJSON_bool cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); +/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. + * WARNING: When this function was used, make sure to always check that (item->type & QUOS_cJSON_StringIsConst) is zero before + * writing to `item->string` */ +cJSON_bool cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); +/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ +cJSON_bool cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); +cJSON_bool cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); + +/* Remove/Detach items from Arrays/Objects. */ +cJSON * cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); +cJSON * cJSON_DetachItemFromArray(cJSON *array, int which); +void cJSON_DeleteItemFromArray(cJSON *array, int which); +cJSON * cJSON_DetachItemFromObject(cJSON *object, const char *string); +cJSON * cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string); +void cJSON_DeleteItemFromObject(cJSON *object, const char *string); +void cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string); + +/* Update array items. */ +cJSON_bool cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ +cJSON_bool cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement); +cJSON_bool cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); +cJSON_bool cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); +cJSON_bool cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem); + +/* Duplicate a cJSON item */ +cJSON * cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); +/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will + * need to be released. With recurse!=0, it will duplicate any children connected to the item. + * The item->next and ->prev pointers are always zero on return from Duplicate. */ +/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal. + * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ +cJSON_bool cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); + +/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings. + * The input pointer json cannot point to a read-only address area, such as a string constant, + * but should point to a readable and writable adress area. */ +void cJSON_Minify(char *json); + +/* Helper functions for creating and adding items to an object at the same time. + * They return the added item or NULL on failure. */ +cJSON* cJSON_AddNullToObject(cJSON * const object, const char * const name); +cJSON* cJSON_AddTrueToObject(cJSON * const object, const char * const name); +cJSON* cJSON_AddFalseToObject(cJSON * const object, const char * const name); +cJSON* cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean); +cJSON* cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number); +cJSON* cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string); +cJSON* cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw); +cJSON* cJSON_AddObjectToObject(cJSON * const object, const char * const name); +cJSON* cJSON_AddArrayToObject(cJSON * const object, const char * const name); + +/* When assigning an integer value, it needs to be propagated to valuedouble too. */ +#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) +/* helper for the cJSON_SetNumberValue macro */ +double cJSON_SetNumberHelper(cJSON *object, double number); +#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) +/* Change the valuestring of a QUOS_cJSON_String object, only takes effect when type of object is QUOS_cJSON_String */ +char* cJSON_SetValuestring(cJSON *object, const char *valuestring); + +/* Macro for iterating over an array or object */ +#define QUOS_cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) +#endif + +#endif diff --git a/kernel/quos_coap.c b/kernel/quos_coap.c new file mode 100644 index 0000000000000000000000000000000000000000..94d173b8068c620c7ac1e322353d44219e83fb5b --- /dev/null +++ b/kernel/quos_coap.c @@ -0,0 +1,824 @@ +/************************************************************************* +** 创建人 @author : 吴健超 JCWu +** 版本 @version : V1.0.0 原始版本 +** 日期 @date : +** 功能 @brief : coap通信管理 +** 硬件 @hardware:任何ANSI-C平台 +** 其他 @other : +***************************************************************************/ +#include "quos_coap.h" +#if (SDK_ENABLE_COAP == 1) +#include "Quos_kernel.h" +#include "Qhal_driver.h" + +#ifndef QUOS_COAP_SEND_TIMEOUT +#define QUOS_COAP_SEND_TIMEOUT 5 * SWT_ONE_SECOND +#endif +#ifndef QUOS_COAP_RESEND_TIME +#define QUOS_COAP_RESEND_TIME 3 +#endif +#define QUOS_COAP_VERSION 0x01 + +typedef struct +{ + quint16_t mid; + coapRecvNotify_f notifyCB; + void *peer; +} coapSock_t; +typedef struct +{ + TWLLHead_T head; + coapOptionType_t type; + quint16_t len; + quint8_t val[1]; +} coap_optionNode_t; +/************************************************************************** +** 功能 @brief : coap message 头设置 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Quos_coapHeadSet(Coap_Message_t *coapMsg, coapHeadType_t type, coapHeadCode_t code, quint16_t mid, quint32_t tokenLen, const quint8_t *token) +{ + coapMsg->head.ver = QUOS_COAP_VERSION; + coapMsg->head.type = type; + coapMsg->head.tokenLen = tokenLen > sizeof(coapMsg->token) ? sizeof(coapMsg->token) : tokenLen; + coapMsg->head.code = code; + coapMsg->head.mid = mid; + if (coapMsg->head.tokenLen) + { + if (NULL == token) + { + Systick_T tm = Quos_sysTickGet(); + _U16_ARRAY01(mid, coapMsg->token); + _U32_ARRAY0123(tm.sec, coapMsg->token + 2); + _U16_ARRAY01(tm.ms, coapMsg->token + 6); + } + else + { + HAL_MEMCPY(coapMsg->token, token, coapMsg->head.tokenLen); + } + } +} + +/************************************************************************** +** 功能 @brief : 找出options数组的元素id比参考id大但差值最小的节点 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static coap_optionNode_t FUNCTION_ATTR_ROM *quos_coapOptionIdDeltaMinGet(const TWLLHead_T *optionsHead, const coap_optionNode_t *referNode) +{ + qbool findNext = FALSE; + coap_optionNode_t *option = NULL; + TWLLHead_T *temp, *next; + TWLIST_FOR_DATA((TWLLHead_T *)optionsHead, temp, next) + { + coap_optionNode_t *node = __GET_STRUCT_BY_ELEMENT(temp, coap_optionNode_t, head); + if (NULL == referNode) + { + if (NULL == option) + { + option = node; + } + else if (option->type > node->type) + { + option = node; + } + } + else if (node->type == referNode->type) + { + if (node == referNode) + { + findNext = TRUE; + } + else if (findNext) + { + return node; + } + } + else if (node->type > referNode->type && (NULL == option || node->type < option->type)) + { + option = node; + } + } + return option; +} +/************************************************************************** +** 功能 @brief : coap message option 不透明类型数据添加 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Quos_coapOptionSetOpaque(Coap_Message_t *coapMsg, coapOptionType_t type, const void *val, quint16_t valLen) +{ + coap_optionNode_t *node = HAL_MALLOC(__GET_POS_ELEMENT(coap_optionNode_t, val) + valLen); + if (NULL == node) + { + return FALSE; + } + HAL_MEMSET(node, 0, sizeof(coap_optionNode_t)); + node->type = type; + HAL_MEMCPY(node->val, (quint8_t *)val, valLen); + node->len = valLen; + Quos_twllHeadAdd((TWLLHead_T **)&coapMsg->optionsHead, &node->head); + return TRUE; +} +/************************************************************************** +** 功能 @brief : coap message option 不透明类型数据获取 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Quos_coapOptionGetOpaque(Coap_Message_t *coapMsg, coapOptionType_t type, const void **val, quint16_t *valLen) +{ + TWLLHead_T *temp, *next; + TWLIST_FOR_DATA((TWLLHead_T *)coapMsg->optionsHead, temp, next) + { + coap_optionNode_t *node = __GET_STRUCT_BY_ELEMENT(temp, coap_optionNode_t, head); + if (type == node->type) + { + if (val) + { + *val = node->val; + } + if (valLen) + { + *valLen = node->len; + } + return TRUE; + } + } + return FALSE; +} +/************************************************************************** +** 功能 @brief : coap message option 数值类型数据添加 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Quos_coapOptionSetNumber(Coap_Message_t *coapMsg, coapOptionType_t type, quint32_t number) +{ + quint16_t valLen = 0; + quint32_t temp = number; + do + { + valLen++; + temp >>= 8; + } while (temp > 0); + + coap_optionNode_t *node = HAL_MALLOC(__GET_POS_ELEMENT(coap_optionNode_t, val) + valLen); + if (NULL == node) + { + return FALSE; + } + HAL_MEMSET(node, 0, sizeof(coap_optionNode_t)); + node->type = type; + node->len = valLen; + while (valLen--) + { + node->val[valLen] = number & 0xFF; + number >>= 8; + } + Quos_twllHeadAdd((TWLLHead_T **)&coapMsg->optionsHead, &node->head); + return TRUE; +} +/************************************************************************** +** 功能 @brief : coap message option 数值类型数据获取 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Quos_coapOptionGetNumber(Coap_Message_t *coapMsg, coapOptionType_t type, quint32_t *number) +{ + TWLLHead_T *temp, *next; + TWLIST_FOR_DATA((TWLLHead_T *)coapMsg->optionsHead, temp, next) + { + coap_optionNode_t *node = __GET_STRUCT_BY_ELEMENT(temp, coap_optionNode_t, head); + if (type == node->type) + { + if (number) + { + quint16_t i; + *number = 0; + for (i = 0; i < node->len; i++) + { + *number |= (quint32_t)node->val[i] << (i * 8); + } + } + return TRUE; + } + } + return FALSE; +} +/************************************************************************** +** 功能 @brief : 设置payload +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Quos_coapPayloadSet(Coap_Message_t *coapMsg, const void *val, quint16_t valLen) +{ + coapMsg->payload.val = (void *)val; + coapMsg->payload.len = valLen; +} +/************************************************************************** +** 功能 @brief : PATH 转成option结构体 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Quos_coapOptionSetPath(Coap_Message_t *coapMsg, const char *path) +{ + char *tmpPath = (char *)path; + if (NULL == path) + { + return TRUE; + } + while ('\0' != tmpPath[0] && '?' != tmpPath[0]) + { + if (tmpPath[0] == '/') + tmpPath++; + else + { + quint32_t i = 0; + while ('\0' != tmpPath[i] && tmpPath[i] != '/' && tmpPath[i] != '?') + i++; + if (FALSE == Quos_coapOptionSetOpaque(coapMsg, COAP_OTYPE_URI_PATH, tmpPath, i)) + { + return FALSE; + } + tmpPath += i; + } + } + if ('?' == tmpPath[0]) + tmpPath++; + while ('\0' != tmpPath[0]) + { + if (tmpPath[0] == '&') + tmpPath++; + else + { + quint32_t i = 0; + while (tmpPath[i] != 0 && tmpPath[i] != '&') + i++; + if (FALSE == Quos_coapOptionSetOpaque(coapMsg, COAP_OTYPE_URI_QUERY, tmpPath, i)) + { + return FALSE; + } + tmpPath += i; + } + } + return TRUE; +} +/************************************************************************** +** 功能 @brief : 转成option结构体转成path +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +char FUNCTION_ATTR_ROM *Quos_coapOptionGetPath(const Coap_Message_t *coapMsg) +{ + quint16_t len = 0; + TWLLHead_T *temp, *next; + TWLIST_FOR_DATA((TWLLHead_T *)coapMsg->optionsHead, temp, next) + { + coap_optionNode_t *node = __GET_STRUCT_BY_ELEMENT(temp, coap_optionNode_t, head); + if (COAP_OTYPE_URI_PATH == node->type || COAP_OTYPE_URI_QUERY == node->type) + { + len += node->len + 1; + } + } + char *path = NULL; + if (0 == len || (path = HAL_MALLOC(len + 1)) == NULL) + { + return NULL; + } + len = 0; + TWLIST_FOR_DATA((TWLLHead_T *)coapMsg->optionsHead, temp, next) + { + coap_optionNode_t *node = __GET_STRUCT_BY_ELEMENT(temp, coap_optionNode_t, head); + if (COAP_OTYPE_URI_PATH == node->type) + { + HAL_SPRINTF(path + len, "/%.*s", node->len, node->val); + len += node->len + 1; + } + } + qbool isFirst = TRUE; + TWLIST_FOR_DATA((TWLLHead_T *)coapMsg->optionsHead, temp, next) + { + coap_optionNode_t *node = __GET_STRUCT_BY_ELEMENT(temp, coap_optionNode_t, head); + if (COAP_OTYPE_URI_QUERY == node->type) + { + if (isFirst) + { + HAL_SPRINTF(path + len, "?%.*s", node->len, node->val); + isFirst = FALSE; + } + else + { + HAL_SPRINTF(path + len, "&%.*s", node->len, node->val); + } + len += node->len + 1; + } + } + return path; +} +/************************************************************************** +** 功能 @brief : coap option原型转十六进制流 +** 输入 @param : buffer:非空时将option格式化成16进制到buffer,buffer必须足够大防止溢出 +** 输出 @retval: 返回option格式化成16进制字节长度 +***************************************************************************/ +static quint16_t FUNCTION_ATTR_ROM quos_coapoptionFormat(const coap_optionNode_t *opt, coap_optionNode_t *referNode, quint8_t *buffer) +{ + quint16_t len = 0; + quint16_t delta = opt->type - (referNode ? referNode->type : 0); + if (delta > 268) + { + if (buffer) + { + buffer[0] = 14 << 4; + buffer[1] = (delta - 269) >> 8; + buffer[2] = (delta - 269) & 0xFF; + } + len = 3; + } + else if (delta > 12) + { + if (buffer) + { + buffer[0] = 13 << 4; + buffer[1] = delta - 13; + } + len = 2; + } + else + { + if (buffer) + { + buffer[0] = delta << 4; + } + len = 1; + } + if (opt->len > 268) + { + if (buffer) + { + buffer[0] |= 14; + buffer[len] = (opt->len - 269) >> 8; + buffer[len + 1] = (opt->len - 269) & 0xFF; + } + len += 2; + } + else if (opt->len > 12) + { + if (buffer) + { + buffer[0] |= 13; + buffer[len] = opt->len - 13; + } + len += 1; + } + else + { + if (buffer) + { + buffer[0] |= opt->len; + } + } + if (buffer) + { + HAL_MEMCPY(buffer + len, opt->val, opt->len); + } + len += opt->len; + Quos_logPrintf(LSDK_COAP, LL_DBG, "coap option format len:%u", len); + if (buffer) + { + Quos_logHexDump(LSDK_COAP, LL_DUMP, "option head buf", buffer, len - opt->len); + } + return len; +} +/************************************************************************** +** 功能 @brief : 将十六进制流解析成option结构体 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static quint16_t FUNCTION_ATTR_ROM quos_coapoptionUnformat(const quint8_t *buffer, quint16_t bufLen, coap_optionNode_t **option, coap_optionNode_t *referNode) +{ + if (NULL == buffer || 0 == bufLen) + { + Quos_logPrintf(LSDK_COAP, LL_ERR, "param fail"); + return 0; + } + quint16_t i = 0; + quint16_t delta = (buffer[i] >> 4) & 0x0F; + quint16_t optLen = buffer[i] & 0x0F; + if (15 == delta || 15 == optLen) + { + Quos_logPrintf(LSDK_COAP, LL_ERR, "delta[%u] or optLen[%u] is invalid", delta, optLen); + return 0; + } + i++; + + if (i + (delta > 12 ? (delta - 12) : 0) + (optLen > 12 ? (optLen - 12) : 0) > bufLen) + { + Quos_logPrintf(LSDK_COAP, LL_ERR, "buflen isn't enough for delta and len"); + return 0; + } + if (13 == delta) + { + delta = 13 + buffer[i++]; + } + else if (14 == delta) + { + delta = 269 + buffer[i] * 256 + buffer[i + 1]; + i += 2; + } + if (13 == optLen) + { + optLen = 13 + buffer[i++]; + } + else if (14 == optLen) + { + optLen = 269 + buffer[i] * 256 + buffer[i + 1]; + i += 2; + } + if (i + optLen > bufLen) + { + Quos_logPrintf(LSDK_COAP, LL_ERR, "buflen isn't enough for option value"); + return 0; + } + if (option) + { + *option = HAL_MALLOC(__GET_POS_ELEMENT(coap_optionNode_t, val) + optLen); + if (*option) + { + (*option)->type = delta + (referNode ? referNode->type : 0); + (*option)->len = optLen; + HAL_MEMCPY((*option)->val, &buffer[i], optLen); + } + } + return i + optLen; +} +/************************************************************************** +** 功能 @brief : 释放Coap_Message_t内存 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Quos_coapMessageFree(Coap_Message_t *coapMsg) +{ + while (coapMsg->optionsHead) + { + coap_optionNode_t *node = __GET_STRUCT_BY_ELEMENT(coapMsg->optionsHead, coap_optionNode_t, head); + Quos_twllHeadDelete((TWLLHead_T **)&coapMsg->optionsHead, coapMsg->optionsHead); + HAL_FREE(node); + } + HAL_FREE(coapMsg->payload.val); + HAL_MEMSET(coapMsg, 0, sizeof(Coap_Message_t)); +} +/************************************************************************** +** 功能 @brief : 计算coap数据包长度 +** 输入 @param : coapMsg:coap消息结构体 +** 输出 @retval: +***************************************************************************/ +static quint16_t FUNCTION_ATTR_ROM quos_coapMessageFormat_len(const Coap_Message_t *coapMsg) +{ + quint16_t pkgLen = sizeof(coapMsg->head) + coapMsg->head.tokenLen; + coap_optionNode_t *referNode = NULL; + TWLLHead_T *temp, *next; + TWLIST_FOR_DATA((TWLLHead_T *)coapMsg->optionsHead, temp, next) + { + coap_optionNode_t *node = quos_coapOptionIdDeltaMinGet(coapMsg->optionsHead, referNode); + if (NULL == node) + { + break; + } + pkgLen += quos_coapoptionFormat(node, referNode, NULL); + referNode = node; + } + if (coapMsg->payload.len) + { + pkgLen += 1 + coapMsg->payload.len; + } + Quos_logPrintf(LSDK_COAP, LL_DBG, "coap msg format len:%u", pkgLen); + return pkgLen; +} + +/************************************************************************** +** 功能 @brief : 将coap消息结构体格式化成十六进制字节流 +** 输入 @param : coapMsg:coap消息结构体,buffer:内部分配空间缓存格式化后的字节流 +** 输出 @retval: 格式化后字节流长度 +***************************************************************************/ +static quint16_t FUNCTION_ATTR_ROM quos_coapMessageFormat(const Coap_Message_t *coapMsg, quint8_t **buffer) +{ + quint16_t len = quos_coapMessageFormat_len(coapMsg); + quint8_t *buf = HAL_MALLOC(len); + if (NULL == buf) + { + Quos_logPrintf(LSDK_COAP, LL_ERR, "format malloc fail"); + return 0; + } + *buffer = buf; + len = 0; + + buf[len++] = (coapMsg->head.ver << 6) | (coapMsg->head.type << 4) | coapMsg->head.tokenLen; + buf[len++] = coapMsg->head.code; + buf[len++] = coapMsg->head.mid >> 8; + buf[len++] = coapMsg->head.mid & 0xFF; + + HAL_MEMCPY(buf + len, coapMsg->token, coapMsg->head.tokenLen); + len += coapMsg->head.tokenLen; + + coap_optionNode_t *refNode = NULL; + TWLLHead_T *temp, *next; + TWLIST_FOR_DATA((TWLLHead_T *)coapMsg->optionsHead, temp, next) + { + coap_optionNode_t *node = quos_coapOptionIdDeltaMinGet(coapMsg->optionsHead, refNode); + if (NULL == node) + { + break; + } + len += quos_coapoptionFormat(node, refNode, buf + len); + refNode = node; + } + + if (coapMsg->payload.len) + { + buf[len++] = 0xFF; + HAL_MEMCPY(buf + len, coapMsg->payload.val, coapMsg->payload.len); + len += coapMsg->payload.len; + } + return len; +} + +/************************************************************************** +** 功能 @brief : 检查coap十六进制流是否时有效coap数据 +** 输入 @param : buffer:coap十六进制流 +** 输出 @retval: 返回option有效个数,<0时代表buffer非法coap数据 +***************************************************************************/ +static qbool FUNCTION_ATTR_ROM quos_coapMessageCheck(const quint8_t *buffer, quint16_t len, quint16_t *optSize) +{ + quint16_t i = 4; + if (optSize) + *optSize = 0; + if (NULL == buffer || 0 == len || len < (i + (buffer[0] & 0xF))) + { + Quos_logPrintf(LSDK_COAP, LL_ERR, "param is invalid buffer:%p len:%u tokenLen:%u", buffer, len, buffer[0] & 0xF); + return FALSE; + } + i += buffer[0] & 0xF; + while (1) + { + if (i == len) + { + if (optSize) + { + Quos_logPrintf(LSDK_COAP, LL_DBG, "optsize:%u", *optSize); + } + return TRUE; + } + if (0xFF == buffer[i]) + { + return i + 1 < len ? TRUE : FALSE; + } + quint16_t optlen = quos_coapoptionUnformat(buffer + i, len - i, NULL, NULL); + if (0 == optlen) + { + return FALSE; + } + i += optlen; + if (optSize) + (*optSize) += 1; + } +} +/************************************************************************** +** 功能 @brief : 将十六进制流转成coap结构体 +** 输入 @param : buffer:源数据十六进制流,coap:转换后的coap结构体 +** 输出 @retval: TRUE:成功 FLASE:无效coap数据 +***************************************************************************/ +static qbool FUNCTION_ATTR_ROM quos_coapMessageUnformat(const quint8_t *buffer, quint16_t bufLen, Coap_Message_t *coapMsg) +{ + quint16_t optSize = 0; + Quos_logHexDump(LSDK_COAP, LL_DUMP, "source", (void *)buffer, bufLen); + if (NULL == coapMsg || FALSE == quos_coapMessageCheck(buffer, bufLen, &optSize)) + { + Quos_logPrintf(LSDK_COAP, LL_ERR, "param is invalid"); + return FALSE; + } + quint16_t offset = 1; + HAL_MEMSET(coapMsg, 0, sizeof(Coap_Message_t)); + coapMsg->head.ver = (buffer[0] >> 6) & 0x03; + coapMsg->head.type = (buffer[0] >> 4) & 0x03; + coapMsg->head.tokenLen = (buffer[0] >> 0) & 0x0F; + coapMsg->head.code = buffer[offset++]; + coapMsg->head.mid = ((quint16_t)buffer[offset] << 8) + (quint16_t)buffer[offset + 1]; + offset += 2; + if (bufLen < offset + coapMsg->head.tokenLen) + { + Quos_logPrintf(LSDK_COAP, LL_ERR, "buflen[%u] isn't enough to token[%u+%u]", bufLen, offset, coapMsg->head.tokenLen); + return FALSE; + } + HAL_MEMCPY(coapMsg->token, &buffer[offset], coapMsg->head.tokenLen); + offset += coapMsg->head.tokenLen; + + Quos_logPrintf(LSDK_COAP, LL_DBG, "ver[%u] type[%s] code[%s] mid[%u]", coapMsg->head.ver, COAP_HEAD_TYPE_STRING(coapMsg->head.type), COAP_HEAD_CODE_STRING(coapMsg->head.code), coapMsg->head.mid); + Quos_logHexDump(LSDK_COAP, LL_DUMP, "token", coapMsg->token, coapMsg->head.tokenLen); + + coap_optionNode_t *referNode = NULL; + while (1) + { + quint16_t optLen; + coap_optionNode_t *option; + if (offset == bufLen) + { + return TRUE; + } + else if (0xFF == buffer[offset]) + { + offset++; + if (bufLen > offset) + { + coapMsg->payload.len = bufLen - offset; + coapMsg->payload.val = HAL_MALLOC(coapMsg->payload.len); + if (NULL == coapMsg->payload.val) + { + break; + } + HAL_MEMCPY(coapMsg->payload.val, buffer + offset, coapMsg->payload.len); + return TRUE; + } + else + { + break; + } + } + else if ((optLen = quos_coapoptionUnformat(buffer + offset, bufLen - offset, &option, referNode)) == 0 && NULL == option) + { + break; + } + referNode = option; + offset += optLen; + Quos_twllHeadAdd((TWLLHead_T **)&coapMsg->optionsHead, &option->head); + Quos_logPrintf(LSDK_COAP, LL_DBG, "option type[%s]", COAP_OPTION_TYPE_STRING(option->type)); + Quos_logHexDump(LSDK_COAP, LL_DUMP, "option val", option->val, option->len); + } + Quos_logPrintf(LSDK_COAP, LL_ERR, "unformat fail"); + Quos_coapMessageFree(coapMsg); + return FALSE; +} +/************************************************************************** +** 功能 @brief : coap接收数据处理 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static qbool FUNCTION_ATTR_ROM quos_coapSocketRecv(void *chlFd, const void *peer, quint32_t peerSize, Quos_socketRecvDataNode_t *recvData) +{ + UNUSED(peer); + UNUSED(peerSize); + + Quos_socketChlInfoNode_t *chlNode = (Quos_socketChlInfoNode_t *)chlFd; + coapSock_t *coapSock = (coapSock_t *)chlNode->param; + if (NULL == recvData) + { + coapSock->notifyCB(chlFd, NULL, NULL); + return FALSE; + } + Quos_logHexDump(LSDK_COAP, LL_DUMP, "coap recv", recvData->Buf, recvData->bufLen); + Coap_Message_t coapMsg; + HAL_MEMSET(&coapMsg, 0, sizeof(Coap_Message_t)); + if (FALSE == quos_coapMessageUnformat(recvData->Buf, recvData->bufLen, &coapMsg)) + { + return FALSE; + } + if (COAP_HTYPE_ACK == coapMsg.head.type) + { + Quos_socketTxAck(chlFd, coapSock->peer, coapMsg.head.mid, &coapMsg); + } + else + { + Coap_Message_t retCoapMsg; + HAL_MEMSET(&retCoapMsg, 0, sizeof(Coap_Message_t)); + Quos_coapHeadSet(&retCoapMsg, COAP_HTYPE_ACK, COAP_HCODE_PRECONDITION_FAILED_412, coapMsg.head.mid, coapMsg.head.tokenLen, coapMsg.token); + if (TRUE == coapSock->notifyCB(chlFd, &coapMsg, &retCoapMsg)) + { + Quos_coapMsgSend(chlFd, NULL, &retCoapMsg, NULL, TRUE); + } + } + + Quos_coapMessageFree(&coapMsg); + return TRUE; +} +/************************************************************************** +** 功能 @brief : coap 资源释放 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void FUNCTION_ATTR_ROM quos_coapSocketParamFree(void *param) +{ + coapSock_t *coapSock = (coapSock_t *)param; + HAL_FREE(coapSock->peer); + HAL_FREE(coapSock); +} +/************************************************************************** +** 功能 @brief : coap初始化 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Quos_coapInit(void **chlFdPoint, const char *url, coapRecvNotify_f notifyCb) +{ + urlAnalyze_t urlA; + if (NULL == url) + { + Quos_logPrintf(LSDK_COAP, LL_ERR, "param invalid:url[%p]", url); + return FALSE; + } + if (FALSE == (Quos_urlAnalyze(url, &urlA))) + { + Quos_logPrintf(LSDK_COAP, LL_ERR, "url analyze fail"); + return FALSE; + } + urlA.port = urlA.port ? urlA.port : (urlA.isSecure ? 5684 : 5683); + + coapSock_t *coapSock = HAL_MALLOC(sizeof(coapSock_t)); + if (NULL == coapSock) + { + Quos_logPrintf(LSDK_COAP, LL_ERR, "malloc coapSock fail"); + return FALSE; + } + HAL_MEMSET(coapSock, 0, sizeof(coapSock_t)); + coapSock->notifyCB = notifyCb; + coapSock->mid = 1; + Quos_socketChlInfoNode_t chlInfo; + HAL_MEMSET(&chlInfo, 0, sizeof(Quos_socketChlInfoNode_t)); + if (urlA.isSecure) + { +#if (SDK_ENABLE_TLS == 1) + chlInfo.sockFd = Qhal_udpSslInit(&chlInfo.type, 0, urlA.hostname, urlA.port); +#else + chlInfo.sockFd = SOCKET_FD_INVALID; +#endif + } + else + { + chlInfo.sockFd = Qhal_udpInit(&chlInfo.type, 0, urlA.hostname, urlA.port, &coapSock->peer); + } + if (SOCKET_FD_INVALID == chlInfo.sockFd) + { + Quos_logPrintf(LSDK_COAP, LL_ERR, "coap conneted fail:%s[%u]", urlA.hostname, urlA.port); + return FALSE; + } + + chlInfo.io.send = Qhal_sockWrite; + chlInfo.send.txCnt = QUOS_COAP_RESEND_TIME; + chlInfo.send.timeout = QUOS_COAP_SEND_TIMEOUT; + chlInfo.recvDataFunc = quos_coapSocketRecv; + chlInfo.io.close = Qhal_sockClose; + chlInfo.paramFree = quos_coapSocketParamFree; + chlInfo.param = coapSock; + + void *chlFd = Quos_socketChannelAdd(chlFdPoint, chlInfo); + if (NULL == chlFd) + { + Qhal_sockClose(chlInfo.sockFd, chlInfo.type); + HAL_FREE(coapSock->peer); + HAL_FREE(coapSock); + Quos_logPrintf(LSDK_COAP, LL_ERR, "add socket Channel fail"); + return FALSE; + } + return TRUE; +} +/************************************************************************** +** 功能 @brief : coap message消息发送,回调recvCB()->recvData返回Coap_Message_t + 消息指针 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Quos_coapMsgSend(void *chlFd, const char *path, Coap_Message_t *coapMsg, socketRecvNodeCb_f recvCB, qbool isAck) +{ + if (NULL == chlFd) + { + Quos_coapMessageFree(coapMsg); + Quos_logPrintf(LSDK_COAP, LL_ERR, "param invalid;chlFd[%p]", chlFd); + return FALSE; + } + + Quos_socketChlInfoNode_t *chlNode = (Quos_socketChlInfoNode_t *)chlFd; + coapSock_t *coapSock = (coapSock_t *)chlNode->param; + if (COAP_HTYPE_CON == coapMsg->head.type || COAP_HTYPE_NON == coapMsg->head.type) + { + coapMsg->head.mid = ++coapSock->mid; + } + if (FALSE == Quos_coapOptionSetPath(coapMsg, path)) + { + Quos_coapMessageFree(coapMsg); + Quos_logPrintf(LSDK_COAP, LL_ERR, "path to option fail"); + return FALSE; + } + quint8_t *output = NULL; + quint16_t outLen = quos_coapMessageFormat(coapMsg, &output); + Quos_coapMessageFree(coapMsg); + if (0 == outLen) + { + return FALSE; + } + else if (isAck) + { + return Quos_socketTxDisorder(chlFd, coapSock->peer, output, outLen); + } + else + { + return Quos_socketTx(chlFd, coapSock->peer, 0, 0, NULL, recvCB, coapSock->mid, output, outLen, NULL); + } +} +#endif \ No newline at end of file diff --git a/kernel/quos_coap.h b/kernel/quos_coap.h index 29f3590cfd39683630cc2964c842c573aeaa9ff7..07dfa19ccd144d28a79cef74611ec124f9d544da 100644 --- a/kernel/quos_coap.h +++ b/kernel/quos_coap.h @@ -1,216 +1,212 @@ -#ifndef __QUOS_COAP_H__ -#define __QUOS_COAP_H__ -#include "quos_config.h" -#include "quos_twll.h" -#include "quos_socket.h" -#if (SDK_ENABLE_COAP == 1) - -typedef enum -{ - COAP_HTYPE_CON, /* confirmables */ - COAP_HTYPE_NON, /* non-confirmables */ - COAP_HTYPE_ACK, /* acknowledgements */ - COAP_HTYPE_RST /* reset */ -} coapHeadType_t; -#define COAP_HEAD_TYPE_STRING(X) \ - ( \ - (X == COAP_HTYPE_CON) ? "COAP_HTYPE_CON" : (X == COAP_HTYPE_NON) ? "COAP_HTYPE_NON" \ - : (X == COAP_HTYPE_ACK) ? "COAP_HTYPE_ACK" \ - : (X == COAP_HTYPE_RST) ? "COAP_HTYPE_RST" \ - : "Unknown") -typedef enum -{ -#define COAP_HEAD_CODE(X, Y) (((X) << 5) + Y) - COAP_HCODE_GET = COAP_HEAD_CODE(0, 1), - COAP_HCODE_POST = COAP_HEAD_CODE(0, 2), - COAP_HCODE_PUT = COAP_HEAD_CODE(0, 3), - COAP_HCODE_DELETE = COAP_HEAD_CODE(0, 4), - - COAP_HCODE_CREATED_201 = COAP_HEAD_CODE(2, 1), /* CREATED */ - COAP_HCODE_DELETED_202 = COAP_HEAD_CODE(2, 2), /* DELETED */ - COAP_HCODE_VALID_203 = COAP_HEAD_CODE(2, 3), /* NOT_MODIFIED */ - COAP_HCODE_CHANGED_204 = COAP_HEAD_CODE(2, 4), /* CHANGED */ - COAP_HCODE_CONTENT_205 = COAP_HEAD_CODE(2, 5), /* OK */ - - COAP_HCODE_BAD_REQUEST_400 = COAP_HEAD_CODE(4, 0), /* BAD_REQUEST */ - COAP_HCODE_UNAUTHORIZED_401 = COAP_HEAD_CODE(4, 1), /* UNAUTHORIZED */ - COAP_HCODE_BAD_OPTION_402 = COAP_HEAD_CODE(4, 2), /* BAD_OPTION */ - COAP_HCODE_FORBIDDEN_403 = COAP_HEAD_CODE(4, 3), /* FORBIDDEN */ - COAP_HCODE_NOT_FOUND_404 = COAP_HEAD_CODE(4, 4), /* NOT_FOUND */ - COAP_HCODE_METHOD_NOT_ALLOWED_405 = COAP_HEAD_CODE(4, 5), /* METHOD_NOT_ALLOWED */ - COAP_HCODE_NOT_ACCEPTABLE_406 = COAP_HEAD_CODE(4, 6), /* NOT_ACCEPTABLE */ - COAP_HCODE_PRECONDITION_FAILED_412 = COAP_HEAD_CODE(4, 12), /* BAD_REQUEST */ - COAP_HCODE_REQUEST_ENTITY_TOO_LARGE_413 = COAP_HEAD_CODE(4, 13), /* REQUEST_ENTITY_TOO_LARGE */ - COAP_HCODE_UNSUPPORTED_MEDIA_TYPE_415 = COAP_HEAD_CODE(4, 15), /* UNSUPPORTED_MEDIA_TYPE */ - - COAP_HCODE_INTERNAL_SERVER_ERROR_500 = COAP_HEAD_CODE(5, 0), /* INTERNAL_SERVER_ERROR */ - COAP_HCODE_NOT_IMPLEMENTED_501 = COAP_HEAD_CODE(5, 1), /* NOT_IMPLEMENTED */ - COAP_HCODE_BAD_GATEWAY_502 = COAP_HEAD_CODE(5, 2), /* BAD_GATEWAY */ - COAP_HCODE_SERVICE_UNAVAILABLE_503 = COAP_HEAD_CODE(5, 3), /* SERVICE_UNAVAILABLE */ - COAP_HCODE_GATEWAY_TIMEOUT_504 = COAP_HEAD_CODE(5, 4), /* GATEWAY_TIMEOUT */ - COAP_HCODE_PROXYING_NOT_SUPPORTED_505 = COAP_HEAD_CODE(5, 5), /* PROXYING_NOT_SUPPORTED */ -} coapHeadCode_t; -#define COAP_HEAD_CODE_STRING(X) \ - ( \ - (X == COAP_HCODE_GET) ? "COAP_HCODE_GET" : (X == COAP_HCODE_POST) ? "COAP_HCODE_POST" \ - : (X == COAP_HCODE_PUT) ? "COAP_HCODE_PUT" \ - : (X == COAP_HCODE_DELETE) ? "COAP_HCODE_DELETE" \ - : (X == COAP_HCODE_CREATED_201) ? "COAP_HCODE_CREATED_201" \ - : (X == COAP_HCODE_DELETED_202) ? "COAP_HCODE_DELETED_202" \ - : (X == COAP_HCODE_VALID_203) ? "COAP_HCODE_VALID_203" \ - : (X == COAP_HCODE_CHANGED_204) ? "COAP_HCODE_CHANGED_204" \ - : (X == COAP_HCODE_CONTENT_205) ? "COAP_HCODE_CONTENT_205" \ - : (X == COAP_HCODE_BAD_REQUEST_400) ? "COAP_HCODE_BAD_REQUEST_400" \ - : (X == COAP_HCODE_UNAUTHORIZED_401) ? "COAP_HCODE_UNAUTHORIZED_401" \ - : (X == COAP_HCODE_BAD_OPTION_402) ? "COAP_HCODE_BAD_OPTION_402" \ - : (X == COAP_HCODE_FORBIDDEN_403) ? "COAP_HCODE_FORBIDDEN_403" \ - : (X == COAP_HCODE_NOT_FOUND_404) ? "COAP_HCODE_NOT_FOUND_404" \ - : (X == COAP_HCODE_METHOD_NOT_ALLOWED_405) ? "COAP_HCODE_METHOD_NOT_ALLOWED_405" \ - : (X == COAP_HCODE_NOT_ACCEPTABLE_406) ? "COAP_HCODE_NOT_ACCEPTABLE_406" \ - : (X == COAP_HCODE_PRECONDITION_FAILED_412) ? "COAP_HCODE_PRECONDITION_FAILED_412" \ - : (X == COAP_HCODE_REQUEST_ENTITY_TOO_LARGE_413) ? "COAP_HCODE_REQUEST_ENTITY_TOO_LARGE_413" \ - : (X == COAP_HCODE_UNSUPPORTED_MEDIA_TYPE_415) ? "COAP_HCODE_UNSUPPORTED_MEDIA_TYPE_415" \ - : (X == COAP_HCODE_INTERNAL_SERVER_ERROR_500) ? "COAP_HCODE_INTERNAL_SERVER_ERROR_500" \ - : (X == COAP_HCODE_NOT_IMPLEMENTED_501) ? "COAP_HCODE_NOT_IMPLEMENTED_501" \ - : (X == COAP_HCODE_BAD_GATEWAY_502) ? "COAP_HCODE_BAD_GATEWAY_502" \ - : (X == COAP_HCODE_SERVICE_UNAVAILABLE_503) ? "COAP_HCODE_SERVICE_UNAVAILABLE_503" \ - : (X == COAP_HCODE_GATEWAY_TIMEOUT_504) ? "COAP_HCODE_GATEWAY_TIMEOUT_504" \ - : (X == COAP_HCODE_PROXYING_NOT_SUPPORTED_505) ? "COAP_HCODE_PROXYING_NOT_SUPPORTED_505" \ - : "Unknown") -/* CoAP header options */ -typedef enum -{ - COAP_OTYPE_IF_MATCH = 1, /* 0-8 B */ - COAP_OTYPE_URI_HOST = 3, /* 1-255 B */ - COAP_OTYPE_ETAG = 4, /* 1-8 B */ - COAP_OTYPE_IF_NONE_MATCH = 5, /* 0 B */ - COAP_OTYPE_OBSERVE = 6, /* 0-3 B */ - COAP_OTYPE_URI_PORT = 7, /* 0-2 B */ - COAP_OTYPE_LOCATION_PATH = 8, /* 0-255 B */ - COAP_OTYPE_URI_PATH = 11, /* 0-255 B */ - COAP_OTYPE_CONTENT_TYPE = 12, /* 0-2 B */ - COAP_OTYPE_MAX_AGE = 14, /* 0-4 B */ - COAP_OTYPE_URI_QUERY = 15, /* 0-270 B */ - COAP_OTYPE_ACCEPT = 17, /* 0-2 B */ - COAP_OTYPE_TOKEN = 19, /* 1-8 B */ - COAP_OTYPE_LOCATION_QUERY = 20, /* 1-270 B */ - COAP_OTYPE_BLOCK2 = 23, /* 1-3 B */ - COAP_OTYPE_BLOCK1 = 27, /* 1-3 B */ - COAP_OTYPE_SIZE = 28, /* 0-4 B */ - COAP_OTYPE_PROXY_URI = 35, /* 1-270 B */ -} coapOptionType_t; -#define COAP_OPTION_TYPE_STRING(X) \ - ( \ - (X == COAP_OTYPE_IF_MATCH) ? "OTYPE_IF_MATCH" : (X == COAP_OTYPE_URI_HOST) ? "OTYPE_URI_HOST" \ - : (X == COAP_OTYPE_ETAG) ? "OTYPE_ETAG" \ - : (X == COAP_OTYPE_IF_NONE_MATCH) ? "OTYPE_IF_NONE_MATCH" \ - : (X == COAP_OTYPE_OBSERVE) ? "OTYPE_OBSERVE" \ - : (X == COAP_OTYPE_URI_PORT) ? "OTYPE_URI_PORT" \ - : (X == COAP_OTYPE_LOCATION_PATH) ? "OTYPE_LOCATION_PATH" \ - : (X == COAP_OTYPE_URI_PATH) ? "OTYPE_URI_PATH" \ - : (X == COAP_OTYPE_CONTENT_TYPE) ? "OTYPE_CONTENT_TYPE" \ - : (X == COAP_OTYPE_MAX_AGE) ? "OTYPE_MAX_AGE" \ - : (X == COAP_OTYPE_URI_QUERY) ? "OTYPE_URI_QUERY" \ - : (X == COAP_OTYPE_ACCEPT) ? "OTYPE_ACCEPT" \ - : (X == COAP_OTYPE_TOKEN) ? "OTYPE_TOKEN" \ - : (X == COAP_OTYPE_LOCATION_QUERY) ? "OTYPE_LOCATION_QUERY" \ - : (X == COAP_OTYPE_BLOCK2) ? "OTYPE_BLOCK2" \ - : (X == COAP_OTYPE_BLOCK1) ? "OTYPE_BLOCK1" \ - : (X == COAP_OTYPE_SIZE) ? "OTYPE_SIZE" \ - : (X == COAP_OTYPE_PROXY_URI) ? "OTYPE_PROXY_URI" \ - : "Unknown") - -/* CoAP Content-Types */ -typedef enum -{ - COAP_OCTYPE_TEXT_PLAIN = 0, - COAP_OCTYPE_TEXT_XML = 1, - COAP_OCTYPE_TEXT_CSV = 2, - COAP_OCTYPE_TEXT_HTML = 3, - COAP_OCTYPE_IMAGE_GIF = 21, - COAP_OCTYPE_IMAGE_JPEG = 22, - COAP_OCTYPE_IMAGE_PNG = 23, - COAP_OCTYPE_IMAGE_TIFF = 24, - COAP_OCTYPE_AUDIO_RAW = 25, - COAP_OCTYPE_VIDEO_RAW = 26, - COAP_OCTYPE_APP_LINK_FORMAT = 40, - COAP_OCTYPE_APP_XML = 41, - COAP_OCTYPE_APP_OCTET_STREAM = 42, - COAP_OCTYPE_APP_RDF_XML = 43, - COAP_OCTYPE_APP_SOAP_XML = 44, - COAP_OCTYPE_APP_ATOM_XML = 45, - COAP_OCTYPE_APP_XMPP_XML = 46, - COAP_OCTYPE_APP_EXI = 47, - COAP_OCTYPE_APP_FASTINFOSET = 48, - COAP_OCTYPE_APP_SOAP_FASTINFOSET = 49, - COAP_OCTYPE_APP_JSON = 50, - COAP_OCTYPE_APP_X_OBIX_BINARY = 51, -} coapOptionContentType_t; -#define COAP_OPTION_CONTENT_TYPE_STRING(X) \ - ( \ - (X == COAP_OCTYPE_TEXT_PLAIN) ? "OCTYPE_TEXT_PLAIN" : (X == COAP_OCTYPE_TEXT_XML) ? "OCTYPE_TEXT_XML" \ - : (X == COAP_OCTYPE_TEXT_CSV) ? "OCTYPE_TEXT_CSV" \ - : (X == COAP_OCTYPE_TEXT_HTML) ? "OCTYPE_TEXT_HTML" \ - : (X == COAP_OCTYPE_IMAGE_GIF) ? "OCTYPE_IMAGE_GIF" \ - : (X == COAP_OCTYPE_IMAGE_JPEG) ? "OCTYPE_IMAGE_JPEG" \ - : (X == COAP_OCTYPE_IMAGE_PNG) ? "OCTYPE_IMAGE_PNG" \ - : (X == COAP_OCTYPE_IMAGE_TIFF) ? "OCTYPE_IMAGE_TIFF" \ - : (X == COAP_OCTYPE_AUDIO_RAW) ? "OCTYPE_AUDIO_RAW" \ - : (X == COAP_OCTYPE_VIDEO_RAW) ? "OCTYPE_VIDEO_RAW" \ - : (X == COAP_OCTYPE_APP_LINK_FORMAT) ? "OCTYPE_APP_LINK_FORMAT" \ - : (X == COAP_OCTYPE_APP_XML) ? "OCTYPE_APP_XML" \ - : (X == COAP_OCTYPE_APP_OCTET_STREAM) ? "OCTYPE_APP_OCTET_STREAM" \ - : (X == COAP_OCTYPE_APP_RDF_XML) ? "OCTYPE_APP_RDF_XML" \ - : (X == COAP_OCTYPE_APP_SOAP_XML) ? "OCTYPE_APP_SOAP_XML" \ - : (X == COAP_OCTYPE_APP_ATOM_XML) ? "OCTYPE_APP_ATOM_XML" \ - : (X == COAP_OCTYPE_APP_XMPP_XML) ? "OCTYPE_APP_XMPP_XML" \ - : (X == COAP_OCTYPE_APP_EXI) ? "OCTYPE_APP_EXI" \ - : (X == COAP_OCTYPE_APP_FASTINFOSET) ? "OCTYPE_APP_FASTINFOSET" \ - : (X == COAP_OCTYPE_APP_SOAP_FASTINFOSET) ? "OCTYPE_APP_SOAP_FASTINFOSET" \ - : (X == COAP_OCTYPE_APP_JSON) ? "OCTYPE_APP_JSON" \ - : (X == COAP_OCTYPE_APP_X_OBIX_BINARY) ? "OCTYPE_APP_X_OBIX_BINARY" \ - : "Unknown") - -typedef struct -{ - TWLLHead_T head; - coapOptionType_t type; - quint16_t len; - quint8_t val[1]; -} coap_optionNode_t; - -typedef struct -{ - quint32_t ver : 2; - coapHeadType_t type : 2; - quint32_t tkl : 4; - coapHeadCode_t code : 8; - quint32_t mid : 16; -} coap_MessageHead_t; - -typedef struct -{ - coap_MessageHead_t head; - quint8_t token[8]; - TWLLHead_T *optionsHead; - struct - { - quint16_t len; - quint8_t *val; - } payload; -} Coap_Message_t; - -typedef qbool (*coapRecvNotify_f)(void *chlFd, const Coap_Message_t *coapMsg, Coap_Message_t *retCoapMsg); - -quint16_t Quos_coapMessageFormat(const Coap_Message_t *coapMsg, quint8_t **buffer); -qbool Quos_coapMessageUnformat(const quint8_t *buffer, quint16_t bufLen, Coap_Message_t *coapMsg); -void Quos_coapHeadSet(Coap_Message_t *coapMsg, coapHeadType_t type, coapHeadCode_t code, quint16_t mid, quint32_t tkl, quint8_t *token); -char *Quos_coapOptionGetPath(TWLLHead_T *optionsHead); -qbool Quos_coapOptionFromPath(TWLLHead_T **optionHead, const char *path); -qbool Quos_coapOptionSetOpaque(TWLLHead_T **optionHead, coapOptionType_t type, void *val, quint16_t valLen); -qbool Quos_coapOptionSetNumber(TWLLHead_T **optionHead, coapOptionType_t type, quint32_t number); -void Quos_coapMessageFree(Coap_Message_t *coapMsg); -qbool Quos_coapInit(void **chlFdPoint, const char *url, coapRecvNotify_f notifyCb); -qbool Quos_coapMessageSend(void *chlFd, const char *path, Coap_Message_t *coapMsg, socketRecvNodeCb_f recvCB); -#endif -#endif +#ifndef __QUOS_COAP_H__ +#define __QUOS_COAP_H__ +#include "quos_config.h" +#include "quos_twll.h" +#include "quos_socket.h" +#if (SDK_ENABLE_COAP == 1) + +typedef enum +{ + COAP_HTYPE_CON, /* confirmables */ + COAP_HTYPE_NON, /* non-confirmables */ + COAP_HTYPE_ACK, /* acknowledgements */ + COAP_HTYPE_RST /* reset */ +} coapHeadType_t; +#define COAP_HEAD_TYPE_STRING(X) \ + ( \ + (X == COAP_HTYPE_CON) ? "COAP_HTYPE_CON" : (X == COAP_HTYPE_NON) ? "COAP_HTYPE_NON" \ + : (X == COAP_HTYPE_ACK) ? "COAP_HTYPE_ACK" \ + : (X == COAP_HTYPE_RST) ? "COAP_HTYPE_RST" \ + : "Unknown") +typedef enum +{ +#define COAP_HEAD_CODE(X, Y) (((X) << 5) + Y) + COAP_HCODE_EMPTY = COAP_HEAD_CODE(0, 0), + COAP_HCODE_GET = COAP_HEAD_CODE(0, 1), + COAP_HCODE_POST = COAP_HEAD_CODE(0, 2), + COAP_HCODE_PUT = COAP_HEAD_CODE(0, 3), + COAP_HCODE_DELETE = COAP_HEAD_CODE(0, 4), + + COAP_HCODE_CREATED_201 = COAP_HEAD_CODE(2, 1), /* CREATED */ + COAP_HCODE_DELETED_202 = COAP_HEAD_CODE(2, 2), /* DELETED */ + COAP_HCODE_VALID_203 = COAP_HEAD_CODE(2, 3), /* NOT_MODIFIED */ + COAP_HCODE_CHANGED_204 = COAP_HEAD_CODE(2, 4), /* CHANGED */ + COAP_HCODE_CONTENT_205 = COAP_HEAD_CODE(2, 5), /* OK */ + + COAP_HCODE_BAD_REQUEST_400 = COAP_HEAD_CODE(4, 0), /* BAD_REQUEST */ + COAP_HCODE_UNAUTHORIZED_401 = COAP_HEAD_CODE(4, 1), /* UNAUTHORIZED */ + COAP_HCODE_BAD_OPTION_402 = COAP_HEAD_CODE(4, 2), /* BAD_OPTION */ + COAP_HCODE_FORBIDDEN_403 = COAP_HEAD_CODE(4, 3), /* FORBIDDEN */ + COAP_HCODE_NOT_FOUND_404 = COAP_HEAD_CODE(4, 4), /* NOT_FOUND */ + COAP_HCODE_METHOD_NOT_ALLOWED_405 = COAP_HEAD_CODE(4, 5), /* METHOD_NOT_ALLOWED */ + COAP_HCODE_NOT_ACCEPTABLE_406 = COAP_HEAD_CODE(4, 6), /* NOT_ACCEPTABLE */ + COAP_HCODE_PRECONDITION_FAILED_412 = COAP_HEAD_CODE(4, 12), /* BAD_REQUEST */ + COAP_HCODE_REQUEST_ENTITY_TOO_LARGE_413 = COAP_HEAD_CODE(4, 13), /* REQUEST_ENTITY_TOO_LARGE */ + COAP_HCODE_UNSUPPORTED_MEDIA_TYPE_415 = COAP_HEAD_CODE(4, 15), /* UNSUPPORTED_MEDIA_TYPE */ + + COAP_HCODE_INTERNAL_SERVER_ERROR_500 = COAP_HEAD_CODE(5, 0), /* INTERNAL_SERVER_ERROR */ + COAP_HCODE_NOT_IMPLEMENTED_501 = COAP_HEAD_CODE(5, 1), /* NOT_IMPLEMENTED */ + COAP_HCODE_BAD_GATEWAY_502 = COAP_HEAD_CODE(5, 2), /* BAD_GATEWAY */ + COAP_HCODE_SERVICE_UNAVAILABLE_503 = COAP_HEAD_CODE(5, 3), /* SERVICE_UNAVAILABLE */ + COAP_HCODE_GATEWAY_TIMEOUT_504 = COAP_HEAD_CODE(5, 4), /* GATEWAY_TIMEOUT */ + COAP_HCODE_PROXYING_NOT_SUPPORTED_505 = COAP_HEAD_CODE(5, 5), /* PROXYING_NOT_SUPPORTED */ +} coapHeadCode_t; +#define COAP_HEAD_CODE_STRING(X) \ + ( \ + (X == COAP_HCODE_EMPTY) ? "COAP_HCODE_EMPTY" : (X == COAP_HCODE_GET) ? "COAP_HCODE_GET" \ + : (X == COAP_HCODE_POST) ? "COAP_HCODE_POST" \ + : (X == COAP_HCODE_PUT) ? "COAP_HCODE_PUT" \ + : (X == COAP_HCODE_DELETE) ? "COAP_HCODE_DELETE" \ + : (X == COAP_HCODE_CREATED_201) ? "COAP_HCODE_CREATED_201" \ + : (X == COAP_HCODE_DELETED_202) ? "COAP_HCODE_DELETED_202" \ + : (X == COAP_HCODE_VALID_203) ? "COAP_HCODE_VALID_203" \ + : (X == COAP_HCODE_CHANGED_204) ? "COAP_HCODE_CHANGED_204" \ + : (X == COAP_HCODE_CONTENT_205) ? "COAP_HCODE_CONTENT_205" \ + : (X == COAP_HCODE_BAD_REQUEST_400) ? "COAP_HCODE_BAD_REQUEST_400" \ + : (X == COAP_HCODE_UNAUTHORIZED_401) ? "COAP_HCODE_UNAUTHORIZED_401" \ + : (X == COAP_HCODE_BAD_OPTION_402) ? "COAP_HCODE_BAD_OPTION_402" \ + : (X == COAP_HCODE_FORBIDDEN_403) ? "COAP_HCODE_FORBIDDEN_403" \ + : (X == COAP_HCODE_NOT_FOUND_404) ? "COAP_HCODE_NOT_FOUND_404" \ + : (X == COAP_HCODE_METHOD_NOT_ALLOWED_405) ? "COAP_HCODE_METHOD_NOT_ALLOWED_405" \ + : (X == COAP_HCODE_NOT_ACCEPTABLE_406) ? "COAP_HCODE_NOT_ACCEPTABLE_406" \ + : (X == COAP_HCODE_PRECONDITION_FAILED_412) ? "COAP_HCODE_PRECONDITION_FAILED_412" \ + : (X == COAP_HCODE_REQUEST_ENTITY_TOO_LARGE_413) ? "COAP_HCODE_REQUEST_ENTITY_TOO_LARGE_413" \ + : (X == COAP_HCODE_UNSUPPORTED_MEDIA_TYPE_415) ? "COAP_HCODE_UNSUPPORTED_MEDIA_TYPE_415" \ + : (X == COAP_HCODE_INTERNAL_SERVER_ERROR_500) ? "COAP_HCODE_INTERNAL_SERVER_ERROR_500" \ + : (X == COAP_HCODE_NOT_IMPLEMENTED_501) ? "COAP_HCODE_NOT_IMPLEMENTED_501" \ + : (X == COAP_HCODE_BAD_GATEWAY_502) ? "COAP_HCODE_BAD_GATEWAY_502" \ + : (X == COAP_HCODE_SERVICE_UNAVAILABLE_503) ? "COAP_HCODE_SERVICE_UNAVAILABLE_503" \ + : (X == COAP_HCODE_GATEWAY_TIMEOUT_504) ? "COAP_HCODE_GATEWAY_TIMEOUT_504" \ + : (X == COAP_HCODE_PROXYING_NOT_SUPPORTED_505) ? "COAP_HCODE_PROXYING_NOT_SUPPORTED_505" \ + : "Unknown") +/* CoAP header options */ +typedef enum +{ + COAP_OTYPE_IF_MATCH = 1, /* 0-8 B */ + COAP_OTYPE_URI_HOST = 3, /* 1-255 B */ + COAP_OTYPE_ETAG = 4, /* 1-8 B */ + COAP_OTYPE_IF_NONE_MATCH = 5, /* 0 B */ + COAP_OTYPE_OBSERVE = 6, /* 0-3 B */ + COAP_OTYPE_URI_PORT = 7, /* 0-2 B */ + COAP_OTYPE_LOCATION_PATH = 8, /* 0-255 B */ + COAP_OTYPE_URI_PATH = 11, /* 0-255 B */ + COAP_OTYPE_CONTENT_TYPE = 12, /* 0-2 B */ + COAP_OTYPE_MAX_AGE = 14, /* 0-4 B */ + COAP_OTYPE_URI_QUERY = 15, /* 0-270 B */ + COAP_OTYPE_ACCEPT = 17, /* 0-2 B */ + COAP_OTYPE_TOKEN = 19, /* 1-8 B */ + COAP_OTYPE_LOCATION_QUERY = 20, /* 1-270 B */ + COAP_OTYPE_BLOCK2 = 23, /* 1-3 B */ + COAP_OTYPE_BLOCK1 = 27, /* 1-3 B */ + COAP_OTYPE_SIZE = 28, /* 0-4 B */ + COAP_OTYPE_PROXY_URI = 35, /* 1-270 B */ +} coapOptionType_t; +#define COAP_OPTION_TYPE_STRING(X) \ + ( \ + (X == COAP_OTYPE_IF_MATCH) ? "OTYPE_IF_MATCH" : (X == COAP_OTYPE_URI_HOST) ? "OTYPE_URI_HOST" \ + : (X == COAP_OTYPE_ETAG) ? "OTYPE_ETAG" \ + : (X == COAP_OTYPE_IF_NONE_MATCH) ? "OTYPE_IF_NONE_MATCH" \ + : (X == COAP_OTYPE_OBSERVE) ? "OTYPE_OBSERVE" \ + : (X == COAP_OTYPE_URI_PORT) ? "OTYPE_URI_PORT" \ + : (X == COAP_OTYPE_LOCATION_PATH) ? "OTYPE_LOCATION_PATH" \ + : (X == COAP_OTYPE_URI_PATH) ? "OTYPE_URI_PATH" \ + : (X == COAP_OTYPE_CONTENT_TYPE) ? "OTYPE_CONTENT_TYPE" \ + : (X == COAP_OTYPE_MAX_AGE) ? "OTYPE_MAX_AGE" \ + : (X == COAP_OTYPE_URI_QUERY) ? "OTYPE_URI_QUERY" \ + : (X == COAP_OTYPE_ACCEPT) ? "OTYPE_ACCEPT" \ + : (X == COAP_OTYPE_TOKEN) ? "OTYPE_TOKEN" \ + : (X == COAP_OTYPE_LOCATION_QUERY) ? "OTYPE_LOCATION_QUERY" \ + : (X == COAP_OTYPE_BLOCK2) ? "OTYPE_BLOCK2" \ + : (X == COAP_OTYPE_BLOCK1) ? "OTYPE_BLOCK1" \ + : (X == COAP_OTYPE_SIZE) ? "OTYPE_SIZE" \ + : (X == COAP_OTYPE_PROXY_URI) ? "OTYPE_PROXY_URI" \ + : "Unknown") + +/* CoAP Content-Types */ +typedef enum +{ + COAP_OCTYPE_TEXT_PLAIN = 0, + COAP_OCTYPE_TEXT_XML = 1, + COAP_OCTYPE_TEXT_CSV = 2, + COAP_OCTYPE_TEXT_HTML = 3, + COAP_OCTYPE_IMAGE_GIF = 21, + COAP_OCTYPE_IMAGE_JPEG = 22, + COAP_OCTYPE_IMAGE_PNG = 23, + COAP_OCTYPE_IMAGE_TIFF = 24, + COAP_OCTYPE_AUDIO_RAW = 25, + COAP_OCTYPE_VIDEO_RAW = 26, + COAP_OCTYPE_APP_LINK_FORMAT = 40, + COAP_OCTYPE_APP_XML = 41, + COAP_OCTYPE_APP_OCTET_STREAM = 42, + COAP_OCTYPE_APP_RDF_XML = 43, + COAP_OCTYPE_APP_SOAP_XML = 44, + COAP_OCTYPE_APP_ATOM_XML = 45, + COAP_OCTYPE_APP_XMPP_XML = 46, + COAP_OCTYPE_APP_EXI = 47, + COAP_OCTYPE_APP_FASTINFOSET = 48, + COAP_OCTYPE_APP_SOAP_FASTINFOSET = 49, + COAP_OCTYPE_APP_JSON = 50, + COAP_OCTYPE_APP_X_OBIX_BINARY = 51, +} coapOptionContentType_t; +#define COAP_OPTION_CONTENT_TYPE_STRING(X) \ + ( \ + (X == COAP_OCTYPE_TEXT_PLAIN) ? "OCTYPE_TEXT_PLAIN" : (X == COAP_OCTYPE_TEXT_XML) ? "OCTYPE_TEXT_XML" \ + : (X == COAP_OCTYPE_TEXT_CSV) ? "OCTYPE_TEXT_CSV" \ + : (X == COAP_OCTYPE_TEXT_HTML) ? "OCTYPE_TEXT_HTML" \ + : (X == COAP_OCTYPE_IMAGE_GIF) ? "OCTYPE_IMAGE_GIF" \ + : (X == COAP_OCTYPE_IMAGE_JPEG) ? "OCTYPE_IMAGE_JPEG" \ + : (X == COAP_OCTYPE_IMAGE_PNG) ? "OCTYPE_IMAGE_PNG" \ + : (X == COAP_OCTYPE_IMAGE_TIFF) ? "OCTYPE_IMAGE_TIFF" \ + : (X == COAP_OCTYPE_AUDIO_RAW) ? "OCTYPE_AUDIO_RAW" \ + : (X == COAP_OCTYPE_VIDEO_RAW) ? "OCTYPE_VIDEO_RAW" \ + : (X == COAP_OCTYPE_APP_LINK_FORMAT) ? "OCTYPE_APP_LINK_FORMAT" \ + : (X == COAP_OCTYPE_APP_XML) ? "OCTYPE_APP_XML" \ + : (X == COAP_OCTYPE_APP_OCTET_STREAM) ? "OCTYPE_APP_OCTET_STREAM" \ + : (X == COAP_OCTYPE_APP_RDF_XML) ? "OCTYPE_APP_RDF_XML" \ + : (X == COAP_OCTYPE_APP_SOAP_XML) ? "OCTYPE_APP_SOAP_XML" \ + : (X == COAP_OCTYPE_APP_ATOM_XML) ? "OCTYPE_APP_ATOM_XML" \ + : (X == COAP_OCTYPE_APP_XMPP_XML) ? "OCTYPE_APP_XMPP_XML" \ + : (X == COAP_OCTYPE_APP_EXI) ? "OCTYPE_APP_EXI" \ + : (X == COAP_OCTYPE_APP_FASTINFOSET) ? "OCTYPE_APP_FASTINFOSET" \ + : (X == COAP_OCTYPE_APP_SOAP_FASTINFOSET) ? "OCTYPE_APP_SOAP_FASTINFOSET" \ + : (X == COAP_OCTYPE_APP_JSON) ? "OCTYPE_APP_JSON" \ + : (X == COAP_OCTYPE_APP_X_OBIX_BINARY) ? "OCTYPE_APP_X_OBIX_BINARY" \ + : "Unknown") + +typedef struct +{ + quint32_t ver : 2; + coapHeadType_t type : 2; + quint32_t tokenLen : 4; + coapHeadCode_t code : 8; + quint32_t mid : 16; +} coap_MessageHead_t; + +typedef struct +{ + coap_MessageHead_t head; + quint8_t token[8]; + void *optionsHead; + struct + { + quint16_t len; + void *val; + } payload; +} Coap_Message_t; + +typedef qbool (*coapRecvNotify_f)(void *chlFd, const Coap_Message_t *coapMsg, Coap_Message_t *retCoapMsg); + +void Quos_coapHeadSet(Coap_Message_t *coapMsg, coapHeadType_t type, coapHeadCode_t code, quint16_t mid, quint32_t tokenLen, const quint8_t *token); +char *Quos_coapOptionGetPath(const Coap_Message_t *coapMsg); +qbool Quos_coapOptionSetPath(Coap_Message_t *coapMsg, const char *path); +qbool Quos_coapOptionSetOpaque(Coap_Message_t *coapMsg, coapOptionType_t type, const void *val, quint16_t valLen); +qbool Quos_coapOptionGetOpaque(Coap_Message_t *coapMsg, coapOptionType_t type, const void **val, quint16_t *valLen); +qbool Quos_coapOptionSetNumber(Coap_Message_t *coapMsg, coapOptionType_t type, quint32_t number); +qbool Quos_coapOptionGetNumber(Coap_Message_t *coapMsg, coapOptionType_t type, quint32_t *number); +void Quos_coapPayloadSet(Coap_Message_t *coapMsg, const void *val, quint16_t valLen); +void Quos_coapMessageFree(Coap_Message_t *coapMsg); +qbool Quos_coapInit(void **chlFdPoint, const char *url, coapRecvNotify_f notifyCb); +qbool Quos_coapMsgSend(void *chlFd, const char *path, Coap_Message_t *coapMsg, socketRecvNodeCb_f recvCB, qbool isAck); + +#endif +#endif diff --git a/kernel/quos_config.h b/kernel/quos_config.h index 4982a845ab21e10a20edaa324fcfcd9e4ec45d11..100958d4ff25b104f91c40bb67988f7f00fc54cc 100644 --- a/kernel/quos_config.h +++ b/kernel/quos_config.h @@ -1,52 +1,83 @@ -/* - * @Author: your name - * @Date: 2021-06-21 10:50:46 - * @LastEditTime: 2021-07-07 19:17:00 - * @LastEditors: Please set LastEditors - * @Description: In User Settings Edit - * @FilePath: \quecthing_pythonSDK\components\quecsdk\kernel\quos_config.h - */ -#ifndef __QUOS_CONFIG_H__ -#define __QUOS_CONFIG_H__ -#include "Qhal_types.h" - -#define SOCKET_FD_INVALID ((pointer_t)-1) -#define QUOS_DNS_HOSTNANE_MAX_LENGHT (64) /* DNS规定域名不能超过63字符*/ -#define QUOS_IP_ADDR_MAX_LEN (46) - -enum -{ - QUOS_SYSTEM_EVENT_NETCONNECTED = -1, - QUOS_SYSTEM_EVENT_NETDISCONNECT = -2, -}; -/* SDK 支持功能配置 */ -#define SDK_ENABLE_TLS 1 -#define SDK_ENABLE_HTTP 1 -#define SDK_ENABLE_LWM2M 0 -#define SDK_ENABLE_COAP 0 -#define SDK_ENABLE_MQTT 1 -#define SDK_ENABLE_SHA1 1 -#define SDK_ENABLE_SHA256 1 -#define SDK_ENABLE_MD5 1 -#define SDK_ENABLE_BASE64 1 -#define SDK_ENABLE_AES 1 -#define SDK_ENABLE_EVENT 1 -#define SDK_ENABLE_SIGNAL 1 -#define SDK_ENABLE_TIMER 1 -#define SDK_ENABLE_JSON 1 -#define SDK_ENABLE_DATASAFE 1 -#define SDK_ENABLE_LOGDUMP 0 - -/* LOG模块 PRINTF等级配置 */ -#define LSDK_STORE LL_ERR -#define LSDK_COAP LL_ERR -#define LSDK_ENCRP LL_ERR -#define LSDK_EVENT LL_DBG -#define LSDK_HTTP LL_DBG -#define LSDK_MQTT LL_DBG -#define LSDK_SIG LL_DBG -#define LSDK_SOCK LL_DBG -#define LSDK_TIMER LL_DBG -#define LSDK_LWM2M LL_ERR -#define LSDK_NET LL_ERR -#endif +#ifndef __QUOS_CONFIG_H__ +#define __QUOS_CONFIG_H__ +#include "Qhal_types.h" + +#define SOCKET_FD_INVALID ((pointer_t)-1) +#define QUOS_DNS_HOSTNANE_MAX_LENGHT (64) /* DNS规定域名不能超过63字符*/ +#define QUOS_IP_ADDR_MAX_LEN (46) +enum +{ + QUOS_SYSTEM_EVENT_NETWORK = -1, +}; +enum +{ + QUOS_SEVENT_NET_CONNECTED = 0, + QUOS_SEVENT_NET_DISCONNECT = 1, + QUOS_SEVENT_NET_CONNTIMEOUT = 2, +}; +/* SDK 支持功能配置 */ +#ifndef SDK_ENABLE_TLS +#define SDK_ENABLE_TLS 1 +#endif +#ifndef SDK_ENABLE_HTTP +#define SDK_ENABLE_HTTP 1 +#endif +#ifndef SDK_ENABLE_LWM2M +#define SDK_ENABLE_LWM2M 0 +#endif +#ifndef SDK_ENABLE_COAP +#define SDK_ENABLE_COAP 0 +#endif +#ifndef SDK_ENABLE_MQTT +#define SDK_ENABLE_MQTT 1 +#endif +#ifndef SDK_ENABLE_SHA1 +#define SDK_ENABLE_SHA1 0 +#endif +#ifndef SDK_ENABLE_SHA256 +#define SDK_ENABLE_SHA256 1 +#endif +#ifndef SDK_ENABLE_MD5 +#define SDK_ENABLE_MD5 1 +#endif +#ifndef SDK_ENABLE_BASE64 +#define SDK_ENABLE_BASE64 1 +#endif +#ifndef SDK_ENABLE_AES +#define SDK_ENABLE_AES 1 +#endif +#ifndef SDK_ENABLE_EVENT +#define SDK_ENABLE_EVENT 1 +#endif +#ifndef SDK_ENABLE_FIFO +#define SDK_ENABLE_FIFO 0 +#endif +#ifndef SDK_ENABLE_SIGNAL +#define SDK_ENABLE_SIGNAL 1 +#endif +#ifndef SDK_ENABLE_TIMER +#define SDK_ENABLE_TIMER 1 +#endif +#ifndef SDK_ENABLE_JSON +#define SDK_ENABLE_JSON 1 +#endif +#ifndef SDK_ENABLE_DATASAFE +#define SDK_ENABLE_DATASAFE 1 +#endif +#ifndef SDK_ENABLE_TWLL +#define SDK_ENABLE_TWLL 1 +#endif + +/* LOG模块 PRINTF等级配置 */ +#define LSDK_STORE LL_DBG +#define LSDK_COAP LL_DBG +#define LSDK_ENCRP LL_DBG +#define LSDK_EVENT LL_DBG +#define LSDK_HTTP LL_DBG +#define LSDK_MQTT LL_DBG +#define LSDK_SIG LL_DBG +#define LSDK_SOCK LL_DBG +#define LSDK_TIMER LL_DBG +#define LSDK_LWM2M LL_DBG +#define LSDK_NET LL_DBG +#endif diff --git a/kernel/quos_dataStore.c b/kernel/quos_dataStore.c new file mode 100644 index 0000000000000000000000000000000000000000..e0ff04e575ae4a9074f138cefca2cfad5b6ec12c --- /dev/null +++ b/kernel/quos_dataStore.c @@ -0,0 +1,416 @@ +/************************************************************************* +** 创建人 @author : 吴健超 JCWu +** 版本 @version : V1.0.0 原始版本 +** 日期 @date : +** 功能 @brief : 文件或FLASH安全备份保存 +** 硬件 @hardware:任何ANSI-C平台 +** 其他 @other : +***************************************************************************/ +#include "quos_dataStore.h" +#include "Quos_kernel.h" +#include "Qhal_driver.h" +#if (SDK_ENABLE_DATASAFE == 1) + +#define FILE_DSNAME_BAK_HEAD "_BAK" + +#ifndef QUOS_FILE_NAME_MAXLENGHT +#define QUOS_FILE_NAME_MAXLENGHT 256 /* 文件名最大长度 */ +#endif + +typedef struct +{ + quint32_t index; + quint8_t crc; + quint16_t len; + quint8_t buf[1]; /* 数据开始位置 */ +} SafeFlashHeadData_t; + +/************************************************************************** +** 功能 @brief : 安全写数据 +** 输入 @param : bak + buf:待写入的数据 + bufLen:待写入数据的长度 + aesKey必须是QUOS_AES_KEYLEN字节 +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Quos_dsWrite(const char *filename, const void *buf, quint16_t bufLen, const char *aesKey) +{ + Quos_logPrintf(LSDK_STORE, LL_DBG, "filename[%s] bufLen=%u", filename, bufLen); + Quos_logHexDump(LSDK_STORE, LL_DUMP, "buf", buf, bufLen); + + if (NULL == filename || buf == NULL || 0 == bufLen) + { + return FALSE; + } + char *fileNew = (char *)filename; + char filenameBak[QUOS_FILE_NAME_MAXLENGHT + sizeof(FILE_DSNAME_BAK_HEAD)]; + HAL_SPRINTF(filenameBak, "%s", filename); + char *point = filenameBak + HAL_STRLEN(filenameBak); + while (point != filenameBak && '.' != *point) + { + point--; + } + if (point == filenameBak) + { + HAL_SPRINTF(filenameBak + HAL_STRLEN(filenameBak), "%s", FILE_DSNAME_BAK_HEAD); + } + else + { + HAL_MEMMOVE(point + HAL_STRLEN(FILE_DSNAME_BAK_HEAD), point, HAL_STRLEN(FILE_DSNAME_BAK_HEAD) + 1); + HAL_MEMCPY(point, FILE_DSNAME_BAK_HEAD, HAL_STRLEN(FILE_DSNAME_BAK_HEAD)); + } + + SafeFlashHeadData_t sfHD[2]; + HAL_MEMSET(sfHD, 0, sizeof(sfHD)); + pointer_t fileFd = Qhal_fileOpen(filename, TRUE); + pointer_t fileBakFd = Qhal_fileOpen(filenameBak, TRUE); + if (SOCKET_FD_INVALID != fileFd) + { + Qhal_fileRead(fileFd, 0, &sfHD[0], __GET_POS_ELEMENT(SafeFlashHeadData_t, buf)); + } + if (SOCKET_FD_INVALID != fileBakFd) + { + Qhal_fileRead(fileBakFd, 0, &sfHD[1], __GET_POS_ELEMENT(SafeFlashHeadData_t, buf)); + } + + Quos_logPrintf(LSDK_STORE, LL_DBG, "filename[%s] Index:%u len:%u crc:0x%02X", filename, sfHD[0].index, sfHD[0].len, sfHD[0].crc); + Quos_logPrintf(LSDK_STORE, LL_DBG, "filenameBak[%s] Index:%u len:%u crc:0x%02X", filenameBak, sfHD[1].index, sfHD[1].len, sfHD[1].crc); + + if (0xFFFFFFFF == sfHD[0].index || 0xFFFF == sfHD[0].len) + { + HAL_MEMSET(&sfHD[0], 0, sizeof(sfHD[0])); + } + if (0xFFFFFFFF == sfHD[1].index || 0xFFFF == sfHD[1].len) + { + HAL_MEMSET(&sfHD[1], 0, sizeof(sfHD[1])); + } + + quint32_t maxLen = sfHD[0].len > sfHD[1].len ? sfHD[0].len : sfHD[1].len; + maxLen = maxLen > (quint32_t)__BYTE_TO_ALIGN(bufLen + 1, QUOS_AES_BLOCKLEN) ? maxLen : (quint32_t)__BYTE_TO_ALIGN(bufLen + 1, QUOS_AES_BLOCKLEN); + SafeFlashHeadData_t *newSfHD = (SafeFlashHeadData_t *)HAL_MALLOC(__GET_POS_ELEMENT(SafeFlashHeadData_t, buf) + maxLen); + if (newSfHD) + { + if (sfHD[0].index <= sfHD[1].index) + { + if (sfHD[1].len == 0 || + sfHD[1].len != Qhal_fileRead(fileBakFd, __GET_POS_ELEMENT(SafeFlashHeadData_t, buf), newSfHD->buf, sfHD[1].len) || + sfHD[1].crc != (quint8_t)Quos_crcCalculate(0, newSfHD->buf, sfHD[1].len)) + { + Quos_logPrintf(LSDK_STORE, LL_ERR, "newest data in flash1 is invaild"); + newSfHD->index = sfHD[0].index + 1; + fileNew = filenameBak; + } + else + { + newSfHD->index = sfHD[1].index + 1; + } + } + else + { + if (sfHD[0].len == 0 || + sfHD[0].len != Qhal_fileRead(fileFd, __GET_POS_ELEMENT(SafeFlashHeadData_t, buf), newSfHD->buf, sfHD[0].len) || + sfHD[0].crc != (quint8_t)Quos_crcCalculate(0, newSfHD->buf, sfHD[0].len)) + { + Quos_logPrintf(LSDK_STORE, LL_ERR, "newest data in flash0 is invaild"); + newSfHD->index = sfHD[1].index + 1; + } + else + { + newSfHD->index = sfHD[0].index + 1; + fileNew = filenameBak; + } + } + } + /*else + { + Quos_logPrintf(LSDK_STORE, LL_WARN, "malloc sfHD fail so cancel crc old data"); + newSfHD = (SafeFlashHeadData_t *)HAL_MALLOC(__GET_POS_ELEMENT(SafeFlashHeadData_t, buf) + __BYTE_TO_ALIGN(bufLen,QUOS_AES_BLOCKLEN)); + if (NULL == newSfHD) + { + Quos_logPrintf(LSDK_STORE, LL_ERR, "mcf sfHD"); + return FALSE; + } + if (sfHD[0].index <= sfHD[1].index) + { + newSfHD->index = sfHD[1].index + 1; + } + else + { + newSfHD->index = sfHD[0].index + 1; + fileNew = filenameBak; + } + }*/ + if (SOCKET_FD_INVALID != fileFd) + { + Qhal_fileClose(fileFd); + } + if (SOCKET_FD_INVALID != fileBakFd) + { + Qhal_fileClose(fileBakFd); + } + if (NULL == newSfHD) + { + return FALSE; + } + + HAL_MEMCPY(newSfHD->buf, buf, bufLen); + newSfHD->len = bufLen; + if (aesKey) + { + AES_ctx_t aes_ctx; + Quos_aesInitCtx(&aes_ctx, aesKey); + Quos_aesPadding(newSfHD->buf, newSfHD->buf, newSfHD->len); + newSfHD->len = Quos_aesEcbEncrypt(&aes_ctx, (const quint8_t *)newSfHD->buf, __BYTE_TO_ALIGN(newSfHD->len + 1, QUOS_AES_BLOCKLEN)); + } + + newSfHD->crc = (quint8_t)Quos_crcCalculate(0, newSfHD->buf, newSfHD->len); + Quos_logPrintf(LSDK_STORE, LL_DBG, "fileNew[%s] Index:%u len:%u crc:0x%02X", fileNew, newSfHD->index, newSfHD->len, newSfHD->crc); + Qhal_fileErase(fileNew); + + qbool ret = FALSE; + fileFd = Qhal_fileOpen(fileNew, FALSE); + if (SOCKET_FD_INVALID != fileFd) + { + ret = Qhal_fileWrite(fileFd, 0, newSfHD, __GET_POS_ELEMENT(SafeFlashHeadData_t, buf) + newSfHD->len); + Qhal_fileClose(fileFd); + } + else + { + Quos_logPrintf(LSDK_STORE, LL_ERR, "fileNew[%s] open fail", fileNew); + } + + HAL_FREE(newSfHD); + return ret; +} +/************************************************************************** +** 功能 @brief : 安全读数据 +** 输入 @param : addr:保存数据的起始地址 + buf:待读取的数据缓冲区 + bufLen:待读取数据的长度 + aesKey必须是QUOS_AES_KEYLEN字节 +** 输出 @retval: +***************************************************************************/ +quint32_t FUNCTION_ATTR_ROM Quos_dsRead(const char *filename, void **buf, const char *aesKey) +{ + quint32_t ret = 0; + Quos_logPrintf(LSDK_STORE, LL_DBG, "filename[%s]", filename); + *buf = NULL; + if (NULL == filename) + { + return 0; + } + char filenameBak[QUOS_FILE_NAME_MAXLENGHT + sizeof(FILE_DSNAME_BAK_HEAD)]; + HAL_SPRINTF(filenameBak, "%s", filename); + char *point = filenameBak + HAL_STRLEN(filenameBak); + while (point != filenameBak && '.' != *point) + { + point--; + } + if (point == filenameBak) + { + HAL_SPRINTF(filenameBak + HAL_STRLEN(filenameBak), "%s", FILE_DSNAME_BAK_HEAD); + } + else + { + HAL_MEMMOVE(point + HAL_STRLEN(FILE_DSNAME_BAK_HEAD), point, HAL_STRLEN(FILE_DSNAME_BAK_HEAD) + 1); + HAL_MEMCPY(point, FILE_DSNAME_BAK_HEAD, HAL_STRLEN(FILE_DSNAME_BAK_HEAD)); + } + + SafeFlashHeadData_t sfHD[2]; + HAL_MEMSET(sfHD, 0, sizeof(sfHD)); + pointer_t fileFd = Qhal_fileOpen(filename, TRUE); + pointer_t fileBakFd = Qhal_fileOpen(filenameBak, TRUE); + if (SOCKET_FD_INVALID != fileFd) + { + Qhal_fileRead(fileFd, 0, &sfHD[0], __GET_POS_ELEMENT(SafeFlashHeadData_t, buf)); + } + if (SOCKET_FD_INVALID != fileBakFd) + { + Qhal_fileRead(fileBakFd, 0, &sfHD[1], __GET_POS_ELEMENT(SafeFlashHeadData_t, buf)); + } + Quos_logPrintf(LSDK_STORE, LL_DBG, "filename[%s] Index:%u len:%u crc:0x%02X", filename, sfHD[0].index, sfHD[0].len, sfHD[0].crc); + Quos_logPrintf(LSDK_STORE, LL_DBG, "filenameBak[%s] Index:%u len:%u crc:0x%02X", filenameBak, sfHD[1].index, sfHD[1].len, sfHD[1].crc); + + if (0xFFFFFFFF == sfHD[0].index) + { + HAL_MEMSET(&sfHD[0], 0, sizeof(sfHD[0])); + } + if (0xFFFFFFFF == sfHD[1].index) + { + HAL_MEMSET(&sfHD[1], 0, sizeof(sfHD[1])); + } + if ((0 == sfHD[0].len && 0 == sfHD[1].len) || (*buf = HAL_MALLOC(sfHD[0].len > sfHD[1].len ? sfHD[0].len : sfHD[1].len)) == NULL) + { + Quos_logPrintf(LSDK_STORE, LL_ERR, "mcf buf %u:%u", sfHD[0].len, sfHD[1].len); + } + else if (sfHD[0].index > sfHD[1].index) + { + if (sfHD[0].len != 0 && + sfHD[0].len == Qhal_fileRead(fileFd, __GET_POS_ELEMENT(SafeFlashHeadData_t, buf), *buf, sfHD[0].len) && + sfHD[0].crc == (quint8_t)Quos_crcCalculate(0, *buf, sfHD[0].len)) + { + ret = sfHD[0].len; + Quos_logPrintf(LSDK_STORE, LL_DBG, "index[0] data is newest"); + } + else if (sfHD[1].len != 0 && + sfHD[1].len == Qhal_fileRead(fileBakFd, __GET_POS_ELEMENT(SafeFlashHeadData_t, buf), *buf, sfHD[1].len) && + sfHD[1].crc == (quint8_t)Quos_crcCalculate(0, *buf, sfHD[1].len)) + { + ret = sfHD[1].len; + Quos_logPrintf(LSDK_STORE, LL_DBG, "index[1] data is newest because index[0] data was abnormal"); + } + } + else + { + if (sfHD[1].len != 0 && + sfHD[1].len == Qhal_fileRead(fileBakFd, __GET_POS_ELEMENT(SafeFlashHeadData_t, buf), *buf, sfHD[1].len) && + sfHD[1].crc == (quint8_t)Quos_crcCalculate(0, *buf, sfHD[1].len)) + { + ret = sfHD[1].len; + Quos_logPrintf(LSDK_STORE, LL_DBG, "index[1] data is newest"); + } + else if (sfHD[0].len != 0 && + sfHD[0].len == Qhal_fileRead(fileFd, __GET_POS_ELEMENT(SafeFlashHeadData_t, buf), *buf, sfHD[0].len) && + sfHD[0].crc == (quint8_t)Quos_crcCalculate(0, *buf, sfHD[0].len)) + { + ret = sfHD[0].len; + Quos_logPrintf(LSDK_STORE, LL_DBG, "index[0] data is newest because index[1] data was abnormal"); + } + } + if (SOCKET_FD_INVALID != fileFd) + { + Qhal_fileClose(fileFd); + } + if (SOCKET_FD_INVALID != fileBakFd) + { + Qhal_fileClose(fileBakFd); + } + if (ret == 0 && NULL != *buf) + { + HAL_FREE(*buf); + *buf = NULL; + } + if (aesKey) + { + AES_ctx_t aes_ctx; + Quos_aesInitCtx(&aes_ctx, aesKey); + Quos_aesEcbDecrypt(&aes_ctx, *buf, ret); + ret = Quos_aesPaddingBack(*buf, ret); + } + return ret; +} +#endif + +typedef struct +{ +#define DATA_STORE_INFO_HEAD 0x56473830 + quint32_t head; + quint8_t dat[1]; /* StoragerDataNode_t的元素组合 */ +} dsKeyValueInfo_t; +/************************************************************************** +** 功能 @brief : 从Flash读取KEY-VALUE类数据 +** 输入 @param : aesKey必须是QUOS_AES_KEYLEN字节 +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Quos_dsKvRead(const char *filename, const dsKeyValue_t keyValueNode[], const char *aesKey) +{ + dsKeyValueInfo_t *dataInfo = NULL; + + quint32_t len = Quos_dsRead(filename, (void **)&dataInfo, aesKey); + if (NULL == dataInfo || dataInfo->head != DATA_STORE_INFO_HEAD || len <= sizeof(dataInfo->head)) + { + HAL_FREE(dataInfo); + Quos_logPrintf(LSDK_STORE, LL_ERR, "read store data fail"); + return FALSE; + } + len -= sizeof(dataInfo->head); + quint16_t i; + for (i = 0; i < len; i += 3) + { + quint16_t j = 0; + while (keyValueNode[j].dat) + { + if (dataInfo->dat[i] == keyValueNode[j].id) + { + quint16_t nodeLen = _ARRAY01_U16(&dataInfo->dat[i + 1]); + HAL_MEMSET(keyValueNode[j].dat, 0, keyValueNode[j].maxLen); + if (nodeLen > 0 && nodeLen <= keyValueNode[j].maxLen) + { + HAL_MEMCPY(keyValueNode[j].dat, &dataInfo->dat[i + 3], nodeLen); + Quos_logPrintf(LSDK_STORE, LL_DBG, "id[0x%02X] %.*s", keyValueNode[j].id, nodeLen, (char *)keyValueNode[j].dat); + Quos_logHexDump(LSDK_STORE, LL_DUMP, "", keyValueNode[j].dat, nodeLen); + } + + i += nodeLen; + break; + } + j++; + } + } + HAL_FREE(dataInfo); + return TRUE; +} +/************************************************************************** +** 功能 @brief : 写入存储类数据到Flash +** 输入 @param : aesKey必须是QUOS_AES_KEYLEN字节 +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Quos_dsKvWrite(const char *filename, const dsKeyValue_t keyValueNode[], const char *aesKey) +{ + dsKeyValueInfo_t *dataInfo; + quint16_t datLen = 0; + quint8_t nodeCount = 0; + while (keyValueNode[nodeCount].dat) + { + if (keyValueNode[nodeCount].isString) + { + datLen += 3 + HAL_STRLEN(keyValueNode[nodeCount].dat); + } + else + { + datLen += 3 + keyValueNode[nodeCount].maxLen; + } + nodeCount++; + } + Quos_logPrintf(LSDK_STORE, LL_ERR, "nodeCount[%u] datLen[%u]", nodeCount, datLen); + dataInfo = (dsKeyValueInfo_t *)HAL_MALLOC(__GET_POS_ELEMENT(dsKeyValueInfo_t, dat) + datLen); + if (NULL == dataInfo) + { + Quos_logPrintf(LSDK_STORE, LL_ERR, "mcf dataInfo"); + return FALSE; + } + dataInfo->head = DATA_STORE_INFO_HEAD; + nodeCount = 0; + datLen = 0; + while (keyValueNode[nodeCount].dat) + { + quint16_t nodeLen; + if (keyValueNode[nodeCount].isString) + { + nodeLen = HAL_STRLEN(keyValueNode[nodeCount].dat); + } + else + { + nodeLen = keyValueNode[nodeCount].maxLen; + } + + dataInfo->dat[datLen++] = keyValueNode[nodeCount].id; + _U16_ARRAY01(nodeLen, &dataInfo->dat[datLen]); + datLen += 2; + if (nodeLen > 0) + { + HAL_MEMCPY(&dataInfo->dat[datLen], keyValueNode[nodeCount].dat, nodeLen); + } + datLen += nodeLen; + Quos_logPrintf(LSDK_STORE, LL_ERR, "id[0x%02X]", keyValueNode[nodeCount].id); + Quos_logHexDump(LSDK_STORE, LL_DUMP, "", keyValueNode[nodeCount].dat, nodeLen); + nodeCount++; + } + if (FALSE == Quos_dsWrite(filename, dataInfo, __GET_POS_ELEMENT(dsKeyValueInfo_t, dat) + datLen, aesKey)) + { + HAL_FREE(dataInfo); + return FALSE; + } + HAL_FREE(dataInfo); + return TRUE; +} diff --git a/kernel/quos_dataStore.h b/kernel/quos_dataStore.h index 22399b06918c97fe1b12cc55371a3516bb264f2f..4e9566c9da02275c466a19e903703a98d5768cff 100644 --- a/kernel/quos_dataStore.h +++ b/kernel/quos_dataStore.h @@ -1,18 +1,18 @@ -#ifndef __QUOS_DATA_STORE_H__ -#define __QUOS_DATA_STORE_H__ -#include "quos_config.h" - -#if (SDK_ENABLE_DATASAFE == 1) -qbool Quos_dsWrite(const char *filename,void *buf,quint16_t bufLen); -quint32_t Quos_dsRead(const char *filename, void **buf); -#endif -typedef struct -{ - quint8_t id; - qbool isString; - void *dat; - quint16_t maxLen; -}dsKeyValue_t; -qbool Quos_dsKvRead(const char *filename,const dsKeyValue_t keyValueNode[]); -qbool Quos_dsKvWrite(const char *filename,const dsKeyValue_t keyValueNode[]); +#ifndef __QUOS_DATA_STORE_H__ +#define __QUOS_DATA_STORE_H__ +#include "quos_config.h" + +#if (SDK_ENABLE_DATASAFE == 1) +qbool Quos_dsWrite(const char *filename, const void *buf, quint16_t bufLen, const char *aesKey); +quint32_t Quos_dsRead(const char *filename, void **buf, const char *aesKey); +#endif +typedef struct +{ + quint8_t id; + qbool isString; + void *dat; + quint16_t maxLen; +} dsKeyValue_t; +qbool Quos_dsKvRead(const char *filename, const dsKeyValue_t keyValueNode[], const char *aesKey); +qbool Quos_dsKvWrite(const char *filename, const dsKeyValue_t keyValueNode[], const char *aesKey); #endif \ No newline at end of file diff --git a/kernel/quos_event.c b/kernel/quos_event.c new file mode 100644 index 0000000000000000000000000000000000000000..ed4bd2f41b18cdf7e9f26f586357e4b015ac8bbf --- /dev/null +++ b/kernel/quos_event.c @@ -0,0 +1,121 @@ +/************************************************************************* +** 源码未经检录,使用需谨慎 +** 创建人 @author : 吴健超 JCWu +** 版本 @version : V1.0.0 原始版本 +** 日期 @date : +** 功能 @brief : 事件分发管理 +** 硬件 @hardware:任何ANSI-C平台 +** 其他 @other : +***************************************************************************/ +#include "quos_event.h" +#include "Quos_kernel.h" +#if (SDK_ENABLE_EVENT == 1) +typedef struct +{ + qint32_t event; + void *arg; +}EventArg_t; + +typedef struct +{ + TWLLHead_T head; + qint32_t eventId; + quint32_t cbArraySize; + EventCB_f *cbArray; +} EventNode_t; +static TWLLHead_T *EventList = NULL; + +/************************************************************************** +** 功能 @brief : 事件注册 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Quos_eventCbReg(const qint32_t eventArray[], quint32_t eventCnt, EventCB_f eventCb) +{ + quint32_t i; + for (i = 0; i < eventCnt; i++) + { + EventNode_t *newNode = NULL; + TWLLHead_T *temp, *next; + TWLIST_FOR_DATA(EventList, temp, next) + { + EventNode_t *node = __GET_STRUCT_BY_ELEMENT(temp, EventNode_t, head); + if (node->eventId == eventArray[i]) + { + newNode = node; + break; + } + } + if (NULL == newNode) + { + newNode = HAL_MALLOC(sizeof(EventNode_t)); + if (NULL == newNode) + { + continue; + } + HAL_MEMSET(newNode, 0, sizeof(EventNode_t)); + Quos_twllHeadAdd(&EventList, &newNode->head); + newNode->eventId = eventArray[i]; + } + + quint32_t cbId; + for (cbId = 0; cbId < newNode->cbArraySize; cbId++) + { + if (newNode->cbArray[cbId] == eventCb) + { + break; + } + } + if (cbId == newNode->cbArraySize) + { + EventCB_f *newCbArray = HAL_MALLOC(sizeof(EventCB_f) * (newNode->cbArraySize + 1)); + if (newCbArray) + { + HAL_MEMCPY(newCbArray, newNode->cbArray, newNode->cbArraySize * sizeof(EventCB_f)); + newCbArray[newNode->cbArraySize++] = eventCb; + HAL_FREE(newNode->cbArray); + newNode->cbArray = newCbArray; + Quos_logPrintf(LSDK_EVENT, LL_DBG, "add event[%d] Cb[%p] ok", newNode->eventId, eventCb); + } + } + } +} +/************************************************************************** +** 功能 @brief : 事件分发处理 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void FUNCTION_ATTR_ROM quos_eventHandle(const void *arg, quint32_t argLen) +{ + UNUSED(argLen); + EventArg_t *eventArg = (EventArg_t*)arg; + Quos_logPrintf(LSDK_EVENT, LL_DBG, "event:%d", eventArg->event); + TWLLHead_T *temp, *next; + TWLIST_FOR_DATA(EventList, temp, next) + { + EventNode_t *node = __GET_STRUCT_BY_ELEMENT(temp, EventNode_t, head); + if (eventArg->event == node->eventId) + { + quint32_t i; + for ( i= 0; i < node->cbArraySize; i++) + { + node->cbArray[i](eventArg->event,eventArg->arg); + } + break; + } + } +} +/************************************************************************** +** 功能 @brief : 事件post +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Quos_eventPost(qint32_t event,void *arg) +{ + EventArg_t eventArg; + eventArg.event = event; + eventArg.arg = arg; + Quos_logPrintf(LSDK_EVENT, LL_DBG, "event:%d", event); + return Quos_signalSet(&eventArg, sizeof(eventArg), quos_eventHandle); +} +#endif \ No newline at end of file diff --git a/kernel/quos_fifo.c b/kernel/quos_fifo.c new file mode 100644 index 0000000000000000000000000000000000000000..5a7c4528dbe578e3635272c470c02d7cb215d664 --- /dev/null +++ b/kernel/quos_fifo.c @@ -0,0 +1,235 @@ +锘/************************************************************************* +** 鍒涘缓浜 @author : 鍚村仴瓒 +** 鐗堟湰 @version : V 1.0.0 鍘熷鐗堟湰 +** 鏃ユ湡 @date : 2021.1.10 +** 鍔熻兘 @brief : 瀹炵幇FIFO鐜殑璇诲啓涓庢仮澶嶆寚瀹氶暱搴 +** 纭欢 @hardware锛氫换浣旳NSI-C骞冲彴 +** 鍏朵粬 @other 锛 +***************************************************************************/ +#include "quos_fifo.h" + +#if (SDK_ENABLE_FIFO ==1) +/************************************************************************** +** 鍔熻兘 @brief : 鍒濆鍖朏IFO鐜殑澶у皬锛屽繀椤诲湪浣跨敤FIFO鐜箣鍓嶈皟鐢 +** 杈撳叆 @param : buf锛歠ifo缂撳啿鍖烘寚閽堬紝size锛欶IFO鐜殑澶у皬 +** 杈撳嚭 @retval: +***************************************************************************/ +FifoDat_T FUNCTION_ATTR_ROM Quos_fifoInit(quint8_t *buf, quint32_t size) +{ + FifoDat_T fifo; + fifo.head = 0; + fifo.tail = 0; + fifo.bufSize = size; + fifo.fifoBuf = buf; + return fifo; +} +/************************************************************************** +** 鍔熻兘 @brief : 璁$畻FIFO鐜腑宸茬敤绌洪棿澶у皬 +** 杈撳叆 @param : +** 杈撳嚭 @retval: +***************************************************************************/ +quint32_t FUNCTION_ATTR_RAM Quos_fifoUsedLen(FifoDat_T *fifo) +{ + quint32_t head = fifo->head; + quint32_t tail = fifo->tail; + if (NULL == fifo) + { + return 0; + } + return (head <= tail) ? (tail - head) : (fifo->bufSize - head + tail); +} +/************************************************************************** +** 鍔熻兘 @brief : 璁$畻FIFO鐜腑鍓╀綑绌洪棿澶у皬 +** 杈撳叆 @param : +** 杈撳嚭 @retval: +***************************************************************************/ +quint32_t FUNCTION_ATTR_RAM Quos_fifoFreeLen(FifoDat_T *fifo) +{ + quint32_t head = fifo->head; + quint32_t tail = fifo->tail; + if (NULL == fifo) + { + return 0; + } + return (head > tail) ? (head - tail) : (fifo->bufSize - tail + head); +} + +/************************************************************************** +** 鍔熻兘 @brief : 娓呯┖缂撳啿鍖 +** 杈撳叆 @param : +** 杈撳嚭 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Quos_fifoClear(FifoDat_T *fifo) +{ + fifo->head = fifo->tail; +} +/************************************************************************** +** 鍔熻兘 @brief : 鍒犻櫎缂撳啿鍖 +** 杈撳叆 @param : +** 杈撳嚭 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Quos_fifoDelete(FifoDat_T *fifo) +{ + fifo->head = 0; + fifo->tail = 0; + fifo->bufSize = 0; + fifo->fifoBuf = NULL; +} +/************************************************************************** +** 鍔熻兘 @brief : 鍚戞寚瀹欶IFO鐜腑鍐欏叆鎸囧畾闀垮害鏁版嵁锛岃嫢FIFO鐜湭鐢ㄧ┖闂翠笉瓒筹紝鍒欏啓婊′负姝 +** 杈撳叆 @param : +** 杈撳嚭 @retval: 杩斿洖鎴愬姛鍐欏叆鐨勯暱搴 +***************************************************************************/ +quint32_t FUNCTION_ATTR_RAM Quos_fifoWrite(FifoDat_T *fifo, void *buf, quint32_t len) +{ + quint32_t i, freeLen; + quint8_t *data = (quint8_t *)buf; + if (fifo == NULL || fifo->fifoBuf == NULL) + { + return 0; + } + freeLen = Quos_fifoFreeLen(fifo); /* fifo鐜腑鏈敤澶у皬 */ + len = (freeLen > len) ? len : freeLen; + for (i = 0; i < len; i++) + { + fifo->fifoBuf[fifo->tail++] = *data++; + if (fifo->tail == fifo->bufSize) + fifo->tail = 0; + } + return len; +} +/************************************************************************** +** 鍔熻兘 @brief : 璇诲彇浠嶧IFO鐜殑澶撮儴鍋忕Щoffset鐨勪竴涓暟鎹,璇诲彇鍚庝笉浼氬垹闄ゅご閮 +** 杈撳叆 @param : offset:鍋忕Щ閲 +** 杈撳嚭 @retval: 杩斿洖鎴愬姛涓庡惁 +***************************************************************************/ +qint8_t FUNCTION_ATTR_RAM Quos_fifoCheckOffset(FifoDat_T *fifo, void *buf, quint32_t offset) +{ + quint32_t index; + quint8_t *data = (quint8_t *)buf; + if (fifo == NULL || fifo->fifoBuf == NULL || buf == NULL) + { + return -1; + } + if (Quos_fifoUsedLen(fifo) <= offset) /* fifo鐜腑鏈夋晥闀垮害涓嶈冻 */ + return -1; + + if (fifo->bufSize - fifo->head > offset) + { + index = fifo->head + offset; + } + else + { + index = offset - (fifo->bufSize - fifo->head); + } + *data = fifo->fifoBuf[index]; + return 0; +} +/************************************************************************** +** 鍔熻兘 @brief : 璇诲彇浠嶧IFO鐜殑澶撮儴鍋忕Щoffset寮濮嬬殑len涓暟鎹,涓嶄細浼氬垹闄よ鍙栧悗鐨勬暟鎹 +** 杈撳叆 @param : offset:鍋忕Щ閲 +** 杈撳嚭 @retval: 杩斿洖鎴愬姛涓庡惁 +***************************************************************************/ +quint32_t FUNCTION_ATTR_RAM Quos_fifoReadByte_noDel(FifoDat_T *fifo, void *buf, quint32_t offset, quint32_t len) +{ + quint32_t index; + quint32_t usedLen = Quos_fifoUsedLen(fifo); + quint8_t *data = (quint8_t *)buf; + if (fifo == NULL || fifo->fifoBuf == NULL || buf == NULL || 0 == usedLen || 0 == len) + { + return 0; + } + len = usedLen < len ? usedLen : len; + for (index = 0; index < len; index++) + { + if (fifo->bufSize - fifo->head > offset + index) + { + data[index] = fifo->fifoBuf[fifo->head + offset + index]; + } + else + { + data[index] = fifo->fifoBuf[offset + index - (fifo->bufSize - fifo->head)]; + } + } + return len; +} +/************************************************************************** +** 鍔熻兘 @brief : 璇诲彇浠嶧IFO鐜殑澶撮儴len涓暟鎹,浼氬垹闄よ鍙栧悗鐨勬暟鎹 +** 杈撳叆 @param : +** 杈撳嚭 @retval: 杩斿洖鎴愬姛涓庡惁 +***************************************************************************/ +quint32_t FUNCTION_ATTR_RAM Quos_fifoReadByte_del(FifoDat_T *fifo, void *buf, quint32_t len) +{ + quint32_t index; + quint32_t usedLen = Quos_fifoUsedLen(fifo); + quint8_t *data = (quint8_t *)buf; + if (fifo == NULL || fifo->fifoBuf == NULL || buf == NULL || 0 == usedLen || 0 == len) + { + return 0; + } + len = usedLen < len ? usedLen : len; + for (index = 0; index < len; index++) + { + data[index] = fifo->fifoBuf[fifo->head++]; + if (fifo->head == fifo->bufSize) + fifo->head = 0; + } + return len; +} +/************************************************************************** +** 鍔熻兘 @brief : 鍒犻櫎FIFO棣栭儴鐨凬涓暟鎹 +** 杈撳叆 @param : +** 杈撳嚭 @retval: NULL +***************************************************************************/ +void FUNCTION_ATTR_RAM Quos_fifoDeleteNByte(FifoDat_T *fifo, quint32_t len) +{ + if (fifo == NULL || fifo->fifoBuf == NULL) + { + return; + } + if (Quos_fifoUsedLen(fifo) < len) + { + fifo->head = fifo->tail; + } + else + { + fifo->head = (fifo->bufSize - fifo->head > len) ? (fifo->head + len) : (len - (fifo->bufSize - fifo->head)); + } +} +/************************************************************************** +** 鍔熻兘 @brief : 姣旇緝瀛楄妭娴 +** 杈撳叆 @param : +** 杈撳嚭 @retval: NULL +***************************************************************************/ +qint32_t FUNCTION_ATTR_RAM Quos_fifoStrstr(FifoDat_T *fifo, quint32_t offset, void *buf, quint32_t bufLen) +{ + quint8_t *data = (quint8_t *)buf; + if (fifo == NULL || fifo->fifoBuf == NULL || buf == NULL) + { + return -1; + } + quint32_t usedLen = Quos_fifoUsedLen(fifo); + quint32_t start = 0; + quint32_t index; + for (index = offset; index < usedLen; index++) + { + if (((fifo->bufSize - fifo->head > index) && (data[start] == fifo->fifoBuf[fifo->head + index])) || + ((fifo->bufSize - fifo->head <= index) && (data[start] == fifo->fifoBuf[index - (fifo->bufSize - fifo->head)]))) + { + start++; + if (start == bufLen) + { + return index + 1 - bufLen; + } + } + else + { + start = 0; + index = offset; + offset++; + } + } + return -1; +} + +#endif \ No newline at end of file diff --git a/kernel/quos_fifo.h b/kernel/quos_fifo.h index ac38ea957165d06fa7803133eb67b7d0951c9515..d84175d35742b81e72ee1b30756bcb96d51a603f 100644 --- a/kernel/quos_fifo.h +++ b/kernel/quos_fifo.h @@ -1,33 +1,27 @@ -#ifndef __FIFO_H__ -#define __FIFO_H__ - -#include "quos_config.h" - -#ifdef __cplusplus -extern "C" -{ -#endif - - typedef struct - { - quint32_t head; - quint32_t tail; - quint32_t bufSize; - quint8_t *fifoBuf; - } FifoDat_T; - FifoDat_T Quos_fifoInit(quint8_t *buf, quint32_t size); - quint32_t Quos_fifoUsedLen(FifoDat_T *fifo); - quint32_t Quos_fifoFreeLen(FifoDat_T *fifo); - void Quos_fifoClear(FifoDat_T *fifo); - void Quos_fifoDelete(FifoDat_T *fifo); - quint32_t Quos_fifoWrite(FifoDat_T *fifo, void *buf, quint32_t len); - qint8_t Quos_fifoCheckOffset(FifoDat_T *fifo, void *buf, quint32_t offset); - quint32_t Quos_fifoReadByte_noDel(FifoDat_T *fifo, void *buf, quint32_t offset, quint32_t len); - quint32_t Quos_fifoReadByte_del(FifoDat_T *fifo, void *buf, quint32_t len); - void Quos_fifoDeleteNByte(FifoDat_T *fifo, quint32_t len); - qint32_t Quos_fifoStrstr(FifoDat_T *fifo, quint32_t offset, void *buf, quint32_t bufLen); -#ifdef __cplusplus -} -#endif - -#endif +#ifndef __FIFO_H__ +#define __FIFO_H__ + +#include "quos_config.h" +#if (SDK_ENABLE_FIFO == 1) + +typedef struct +{ + quint32_t head; + quint32_t tail; + quint32_t bufSize; + quint8_t *fifoBuf; +} FifoDat_T; +FifoDat_T Quos_fifoInit(quint8_t *buf, quint32_t size); +quint32_t Quos_fifoUsedLen(FifoDat_T *fifo); +quint32_t Quos_fifoFreeLen(FifoDat_T *fifo); +void Quos_fifoClear(FifoDat_T *fifo); +void Quos_fifoDelete(FifoDat_T *fifo); +quint32_t Quos_fifoWrite(FifoDat_T *fifo, void *buf, quint32_t len); +qint8_t Quos_fifoCheckOffset(FifoDat_T *fifo, void *buf, quint32_t offset); +quint32_t Quos_fifoReadByte_noDel(FifoDat_T *fifo, void *buf, quint32_t offset, quint32_t len); +quint32_t Quos_fifoReadByte_del(FifoDat_T *fifo, void *buf, quint32_t len); +void Quos_fifoDeleteNByte(FifoDat_T *fifo, quint32_t len); +qint32_t Quos_fifoStrstr(FifoDat_T *fifo, quint32_t offset, void *buf, quint32_t bufLen); + +#endif +#endif diff --git a/kernel/quos_http.c b/kernel/quos_http.c new file mode 100644 index 0000000000000000000000000000000000000000..f372cbcdf031bedd467b10fa12c3bb00ef7d467a --- /dev/null +++ b/kernel/quos_http.c @@ -0,0 +1,650 @@ +/************************************************************************* +** 创建人 @author : 吴健超 JCWu +** 版本 @version : V1.0.0 原始版本 +** 日期 @date : +** 功能 @brief : Http通信管理 +** 硬件 @hardware:任何ANSI-C平台 +** 其他 @other : +***************************************************************************/ +#include "quos_http.h" +#if (SDK_ENABLE_HTTP == 1) +#include "Quos_kernel.h" +#include "Qhal_driver.h" +#ifndef QUOS_HTTP_TIMEOUT +#define QUOS_HTTP_TIMEOUT 10 * SWT_ONE_SECOND +#endif +#ifndef QUOS_HTTP_FILE_PIECE +#define QUOS_HTTP_FILE_PIECE 1024 +#endif +#define HTTP_DEFAULT_HEADER "%s /%s HTTP/1.1\r\nHost:%s:%d\r\n%s" + +enum +{ + HTTP_BODY_TYPE_INVALID = -3, + HTTP_BODY_TYPE_NOMASK = -2, + HTTP_BODY_TYPE_CHUNKED = -1, + HTTP_BODY_TYPE_CONTENTLENGHT, +}; +typedef struct +{ + httpEventCB_f eventCB; + char *sendFilename; + char *recvFilename; + qint32_t httpCode; + qint32_t bodyType; + char *retHeader; + quint32_t bodyLen; + quint32_t bodyOffset; + quint32_t chunkedBlockLen; + pointer_t fileFd; +} HttpSocket_t; + +/************************************************************************** +** 功能 @brief : http socket connet结果 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static qbool FUNCTION_ATTR_ROM quos_httpSockConnctCB(void *chlFd, qbool result) +{ + Quos_logPrintf(LSDK_HTTP, LL_DBG, "chlFd[%p] result:%s", chlFd, _BOOL2STR(result)); + if (result == FALSE && NULL != chlFd) + { + Quos_socketChlInfoNode_t *chlNode = (Quos_socketChlInfoNode_t *)chlFd; + ((HttpSocket_t *)(chlNode->param))->eventCB(QUOS_HTTP_CODE_ERR_NET, NULL, NULL, 0); + } + return TRUE; +} +/************************************************************************** +** 功能 @brief : HTTP send CB +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void FUNCTION_ATTR_ROM quos_httpSendCB(void *chlFd, const void *sendData, const void *recvData) +{ + UNUSED(sendData); + if (NULL == recvData) + { + Quos_socketChlInfoNode_t *chlNode = (Quos_socketChlInfoNode_t *)chlFd; + HttpSocket_t *httpSocket = (HttpSocket_t *)chlNode->param; + httpSocket->eventCB(QUOS_HTTP_CODE_ERR_NET, NULL, NULL, 0); + Quos_socketChannelDel((void *)chlNode); + } +} +/************************************************************************** +** 功能 @brief : HTTP 使用TCP发送 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static qbool FUNCTION_ATTR_ROM quos_httpSendResult(void *chlFd, const void *sendData, qbool result) +{ + Quos_logPrintf(LSDK_HTTP, LL_DBG, "chlFd[%p] result:%s", chlFd, _BOOL2STR(result)); + Quos_socketChlInfoNode_t *chlNode = (Quos_socketChlInfoNode_t *)chlFd; + Quos_socketSendDataNode_t *sendNode = (Quos_socketSendDataNode_t *)sendData; + HttpSocket_t *httpSocket = (HttpSocket_t *)chlNode->param; + if (TRUE == result) + { + if (SOCKET_FD_INVALID == httpSocket->fileFd) + { + httpSocket->fileFd = Qhal_fileOpen(httpSocket->sendFilename, TRUE); + if (SOCKET_FD_INVALID == httpSocket->fileFd) + { + Quos_socketChannelDel((void *)chlNode); + return FALSE; + } + } + if (httpSocket->bodyLen > httpSocket->bodyOffset) + { + quint32_t len = httpSocket->bodyLen - httpSocket->bodyOffset; + len = len > QUOS_HTTP_FILE_PIECE ? QUOS_HTTP_FILE_PIECE : len; + quint8_t *buf = HAL_MALLOC(len); + if (NULL == buf) + { + Quos_logPrintf(LSDK_HTTP, LL_ERR, "mcf buf to file piece len:%u", len); + } + else if (Qhal_fileRead(httpSocket->fileFd, httpSocket->bodyOffset, buf, len) != len) + { + HAL_FREE(buf); + Quos_logPrintf(LSDK_HTTP, LL_ERR, "read file piece len fail"); + } + else if (FALSE == Quos_socketTx(chlFd, NULL, sendNode->sendCnt, sendNode->sendTimeout, (socketsendNodeCb_f)sendNode->sendCB, (socketRecvNodeCb_f)sendNode->recvCB, sendNode->pkgId, buf, len, NULL)) + { + Quos_logPrintf(LSDK_HTTP, LL_ERR, "add file piece to socket sendlist fail"); + } + else + { + httpSocket->bodyOffset += len; + Quos_logPrintf(LSDK_HTTP, LL_DBG, "sendFile:%u/%u", httpSocket->bodyOffset, httpSocket->bodyLen); + return TRUE; + } + } + else + { + Qhal_fileClose(httpSocket->fileFd); + httpSocket->fileFd = SOCKET_FD_INVALID; + quint8_t *buf = HAL_MALLOC(sizeof(QUOS_HTTP_MULTIPART_NODE_END)); + if (NULL == buf) + { + Quos_logPrintf(LSDK_HTTP, LL_ERR, "mcf buf to multipart end mask"); + return FALSE; + } + HAL_SPRINTF((char *)buf, "%s", QUOS_HTTP_MULTIPART_NODE_END); + if (FALSE == Quos_socketTx(chlFd, NULL, sendNode->sendCnt, sendNode->sendTimeout, NULL, (socketRecvNodeCb_f)sendNode->recvCB, sendNode->pkgId, buf, HAL_STRLEN(buf), NULL)) + { + Quos_logPrintf(LSDK_HTTP, LL_ERR, "add multipart end mask to socket sendlist fail"); + } + else + { + Quos_logPrintf(LSDK_HTTP, LL_INFO, "send multipart end mask"); + return TRUE; + } + } + } + Quos_socketChannelDel(chlFd); + return FALSE; +} +/************************************************************************** +** 功能 @brief : http接收数据 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static qbool FUNCTION_ATTR_ROM quos_httpRecvData(void *chlFd, const void *peer, quint32_t peerSize, Quos_socketRecvDataNode_t *recvData) +{ + UNUSED(peer); + UNUSED(peerSize); + Quos_socketChlInfoNode_t *chlNode = (Quos_socketChlInfoNode_t *)chlFd; + HttpSocket_t *httpSocket = (HttpSocket_t *)chlNode->param; + /* socket被对端断开,返回bufLen=0 */ + if (NULL == recvData) + { + /* 如果body类型不指定且不用保存为文件,则以socket断开作为接收完成标识 */ + Quos_logPrintf(LSDK_HTTP, LL_ERR, "recv buf len= 0"); + if (NULL == httpSocket->recvFilename && HTTP_BODY_TYPE_NOMASK == httpSocket->bodyType && httpSocket->bodyLen > 0) + { + httpSocket->eventCB(httpSocket->httpCode, httpSocket->retHeader, chlNode->unformTemp.buf, httpSocket->bodyLen); + } + + /* 如果在下载文件过程网络断开,则通知应用层网络异常和已接收到的字节数,方便应用层做断点续传 */ + else if (NULL != httpSocket->recvFilename && HTTP_BODY_TYPE_INVALID != httpSocket->bodyType && httpSocket->bodyLen > 0) + { + httpSocket->eventCB(QUOS_HTTP_CODE_ERR_NET, httpSocket->retHeader, (quint8_t *)httpSocket->recvFilename, httpSocket->bodyLen); + } + else + { + httpSocket->eventCB(QUOS_HTTP_CODE_ERR_NET, httpSocket->retHeader, NULL, 0); + } + if (SOCKET_FD_INVALID != httpSocket->fileFd) + { + Qhal_fileClose(httpSocket->fileFd); + httpSocket->fileFd = SOCKET_FD_INVALID; + } + return FALSE; + } + Quos_logHexDump(LSDK_HTTP, LL_DUMP, "RECV", recvData->Buf, recvData->bufLen); + /* 先将接收数据放入缓冲区内 */ + if (recvData->bufLen + chlNode->unformTemp.offset + 1 > chlNode->unformTemp.bufLen) + { + quint8_t *tempBuf = HAL_MALLOC(recvData->bufLen + chlNode->unformTemp.offset + 1); + if (NULL == tempBuf) + { + httpEventCB_f cb = httpSocket->eventCB; + Quos_socketChannelDel(chlFd); + cb(QUOS_HTTP_CODE_ERR_RAM, NULL, NULL, 0); + return FALSE; + } + HAL_MEMCPY(tempBuf, chlNode->unformTemp.buf, chlNode->unformTemp.offset); + HAL_FREE(chlNode->unformTemp.buf); + chlNode->unformTemp.buf = tempBuf; + chlNode->unformTemp.bufLen = recvData->bufLen + chlNode->unformTemp.offset + 1; + } + HAL_MEMCPY(chlNode->unformTemp.buf + chlNode->unformTemp.offset, recvData->Buf, recvData->bufLen); + chlNode->unformTemp.offset += recvData->bufLen; + chlNode->unformTemp.buf[chlNode->unformTemp.offset] = 0; + + /* 处理HTTP 返回HEADER */ + if (HTTP_BODY_TYPE_INVALID == httpSocket->bodyType) + { + char *headSplit = HAL_STRSTR(chlNode->unformTemp.buf, "\r\n\r\n"); + if (NULL == headSplit) + { + Quos_logPrintf(LSDK_HTTP, LL_DBG, "http head find invalid"); + return FALSE; + } + headSplit+=2; + HAL_MEMSET(headSplit, 0, HAL_STRLEN("\r\n")); + + if (0 != HAL_STRNCMP(chlNode->unformTemp.buf, "HTTP/1.1 ", HAL_STRLEN("HTTP/1.1 "))) + { + httpEventCB_f cb = httpSocket->eventCB; + char *retHeader = httpSocket->retHeader; + httpSocket->retHeader = NULL; + Quos_socketChannelDel(chlFd); + cb(QUOS_HTTP_CODE_ERR_DATA, retHeader, NULL, 0); + HAL_FREE(retHeader); + return FALSE; + } + + httpSocket->bodyLen = 0; + httpSocket->chunkedBlockLen = 0; + httpSocket->httpCode = HAL_ATOI((char *)chlNode->unformTemp.buf + HAL_STRLEN("HTTP/1.1 ")); + + /* 查找body格式类型 */ + char *pdata; + if ((pdata = HAL_STRSTR(chlNode->unformTemp.buf, "Content-Length: ")) != NULL) + { + httpSocket->bodyType = (qint32_t)HAL_ATOI(pdata + HAL_STRLEN("Content-Length: ")); + } + else if ((pdata = HAL_STRSTR(chlNode->unformTemp.buf, "Transfer-Encoding: chunked\r\n")) != NULL) + { + httpSocket->bodyType = HTTP_BODY_TYPE_CHUNKED; + } + else + { + httpSocket->bodyType = HTTP_BODY_TYPE_NOMASK; + } + + /*if ((pdata = HAL_STRSTR(chlNode->unformTemp.buf, "Content-Range: bytes ")) != NULL) + { + httpSocket->bodyOffset = HAL_ATOI(pdata + HAL_STRLEN("Content-Range: bytes ")); + }*/ + /* 把http 返回header返回给应用层 */ + quint32_t headerLen = headSplit - (char *)chlNode->unformTemp.buf; + Quos_logPrintf(LSDK_HTTP, LL_DBG, "find http head ok,code:%d bodyType:%d bodyOffset:%u header len:%u", httpSocket->httpCode, httpSocket->bodyType, httpSocket->bodyOffset, headerLen); + Quos_logPrintf(LSDK_HTTP, LL_DBG, "%s", chlNode->unformTemp.buf); + httpSocket->retHeader = HAL_MALLOC(headerLen + 1); + if (NULL == httpSocket->retHeader) + { + Quos_socketChannelDel(chlFd); + return TRUE; + } + /* 删掉缓冲区中header内容 */ + HAL_MEMCPY(httpSocket->retHeader, chlNode->unformTemp.buf, headerLen); + httpSocket->retHeader[headerLen] = 0; + chlNode->unformTemp.offset -= headerLen + HAL_STRLEN("\r\n"); + HAL_MEMMOVE(chlNode->unformTemp.buf, headSplit + HAL_STRLEN("\r\n"), chlNode->unformTemp.offset); + chlNode->unformTemp.buf[chlNode->unformTemp.offset] = 0; + if (NULL != httpSocket->recvFilename) + { + if (FALSE == httpSocket->eventCB(httpSocket->httpCode, httpSocket->retHeader, (quint8_t *)httpSocket->recvFilename, httpSocket->bodyLen)) + { + Quos_socketChannelDel(chlFd); + return TRUE; + } + else if ((httpSocket->fileFd = Qhal_fileOpen(httpSocket->recvFilename, FALSE)) == SOCKET_FD_INVALID) + { + Quos_socketChannelDel(chlFd); + return TRUE; + } + } + } + + if (HTTP_BODY_TYPE_NOMASK == httpSocket->bodyType) + { + if (NULL != httpSocket->recvFilename) + { + Qhal_fileWrite(httpSocket->fileFd, httpSocket->bodyOffset + httpSocket->bodyLen, chlNode->unformTemp.buf, chlNode->unformTemp.offset); + httpSocket->bodyLen += chlNode->unformTemp.offset; + chlNode->unformTemp.offset = 0; + } + else + { + httpSocket->bodyLen = chlNode->unformTemp.offset; + } + } + else if (HTTP_BODY_TYPE_CHUNKED == httpSocket->bodyType) + { + if (NULL != httpSocket->recvFilename) + { + char *temp = (char *)chlNode->unformTemp.buf; + while (1) + { + if (httpSocket->chunkedBlockLen == 0) + { + if (temp[0] == '\r') + temp++; + if (temp[0] == '\n') + temp++; + if (HAL_STRSTR(temp, "\r\n") == NULL) + { + Quos_logPrintf(LSDK_HTTP, LL_DBG, "no found block len head"); + break; + } + httpSocket->chunkedBlockLen = HAL_STRTOUL(temp, NULL, 16); + Quos_logPrintf(LSDK_HTTP, LL_DBG, "chunkedBlockLen:%u", httpSocket->chunkedBlockLen); + if (0 == httpSocket->chunkedBlockLen) + { + HttpSocket_t temp; + temp.eventCB = httpSocket->eventCB; + temp.httpCode = httpSocket->httpCode; + temp.retHeader = httpSocket->retHeader; + temp.recvFilename = httpSocket->recvFilename; + temp.bodyLen = httpSocket->bodyLen; + httpSocket->retHeader = NULL; + httpSocket->recvFilename = NULL; + if (SOCKET_FD_INVALID != httpSocket->fileFd) + { + Qhal_fileClose(httpSocket->fileFd); + httpSocket->fileFd = SOCKET_FD_INVALID; + } + Quos_socketChannelDel(chlFd); + temp.eventCB(temp.httpCode, temp.retHeader, (quint8_t *)temp.recvFilename, temp.bodyLen); + HAL_FREE(temp.retHeader); + HAL_FREE(temp.recvFilename); + return TRUE; + } + temp = HAL_STRSTR(temp, "\r\n") + HAL_STRLEN("\r\n"); + } + + quint32_t validLen = chlNode->unformTemp.offset - (temp - (char *)chlNode->unformTemp.buf) > httpSocket->chunkedBlockLen ? httpSocket->chunkedBlockLen : chlNode->unformTemp.offset - (temp - (char *)chlNode->unformTemp.buf); + if (validLen == 0) + { + break; + } + Qhal_fileWrite(httpSocket->fileFd, httpSocket->bodyOffset + httpSocket->bodyLen, temp, validLen); + httpSocket->bodyLen += validLen; + httpSocket->chunkedBlockLen -= validLen; + temp += validLen; + } + if (temp != (char *)chlNode->unformTemp.buf) + { + chlNode->unformTemp.offset = chlNode->unformTemp.offset - (temp - (char *)chlNode->unformTemp.buf); + HAL_MEMMOVE(chlNode->unformTemp.buf, temp, chlNode->unformTemp.offset); + chlNode->unformTemp.buf[chlNode->unformTemp.offset] = 0; + } + return FALSE; + } + else + { + Quos_logPrintf(LSDK_HTTP, LL_DBG, "body:%u\n%s ", chlNode->unformTemp.offset, chlNode->unformTemp.buf); + if (HAL_STRSTR(chlNode->unformTemp.buf, "\r\n0\r\n\r\n")) + { + quint32_t pieceLen; + char *temp = (char *)chlNode->unformTemp.buf; + + while ((pieceLen = HAL_STRTOUL(temp, NULL, 16)) > 0) + { + Quos_logPrintf(LSDK_HTTP, LL_DBG, "pieceLen:%u bodyLen=%u", pieceLen, httpSocket->bodyLen); + temp = HAL_STRSTR(temp, "\r\n") + HAL_STRLEN("\r\n"); + HAL_MEMMOVE(chlNode->unformTemp.buf + httpSocket->bodyLen, temp, pieceLen); + httpSocket->bodyLen += pieceLen; + chlNode->unformTemp.buf[httpSocket->bodyLen] = 0; + temp += pieceLen + HAL_STRLEN("\r\n"); + } + + httpSocket->eventCB(httpSocket->httpCode, httpSocket->retHeader, chlNode->unformTemp.buf, httpSocket->bodyLen); + Quos_socketChannelDel(chlFd); + return TRUE; + } + } + } + else if (HTTP_BODY_TYPE_CONTENTLENGHT <= httpSocket->bodyType) + { + if (NULL != httpSocket->recvFilename) + { + Qhal_fileWrite(httpSocket->fileFd, httpSocket->bodyOffset + httpSocket->bodyLen, chlNode->unformTemp.buf, chlNode->unformTemp.offset); + httpSocket->bodyLen += chlNode->unformTemp.offset; + Quos_logPrintf(LSDK_HTTP, LL_DBG, "recv piece:%u len:%u", chlNode->unformTemp.offset, httpSocket->bodyLen); + chlNode->unformTemp.offset = 0; + if (httpSocket->bodyLen >= (quint32_t)httpSocket->bodyType) + { + if (SOCKET_FD_INVALID != httpSocket->fileFd) + { + Qhal_fileClose(httpSocket->fileFd); + httpSocket->fileFd = SOCKET_FD_INVALID; + } + httpSocket->eventCB(httpSocket->httpCode, httpSocket->retHeader, (quint8_t *)httpSocket->recvFilename, httpSocket->bodyLen); + Quos_socketChannelDel(chlFd); + return TRUE; + } + } + else + { + httpSocket->bodyLen = chlNode->unformTemp.offset; + if (httpSocket->bodyLen >= (quint32_t)httpSocket->bodyType) + { + httpSocket->eventCB(httpSocket->httpCode, httpSocket->retHeader, chlNode->unformTemp.buf, httpSocket->bodyLen); + Quos_socketChannelDel(chlFd); + return TRUE; + } + } + } + return TRUE; +} +/************************************************************************** +** 功能 @brief : HTTP参数资源释放 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void FUNCTION_ATTR_ROM quos_httpParamFree(void *param) +{ + HttpSocket_t *httpSock = (HttpSocket_t *)param; + if (SOCKET_FD_INVALID != httpSock->fileFd) + { + Qhal_fileClose(httpSock->fileFd); + httpSock->fileFd = SOCKET_FD_INVALID; + } + HAL_FREE(httpSock->sendFilename); + HAL_FREE(httpSock->recvFilename); + HAL_FREE(httpSock->retHeader); + HAL_FREE(httpSock); +} +/************************************************************************** +** 功能 @brief : http request +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Quos_httpRequest(void **httpFd, const char *opt, const char *url, httpEventCB_f eventCB, const HttpReqData_t *reqData, const HttpReqFile_t *reqFile) +{ + urlAnalyze_t urlA; + if (NULL == opt || NULL == url || NULL == eventCB || (NULL != reqData && 0 != reqData->payloadLen && NULL == reqData->payload)) + { + Quos_logPrintf(LSDK_HTTP, LL_ERR, "opt[%s] url[%p] eventCB[%p] payload[%u:%p]", opt, url, eventCB, reqData->payloadLen, reqData->payload); + return FALSE; + } + if (FALSE == (Quos_urlAnalyze(url, &urlA))) + { + Quos_logPrintf(LSDK_HTTP, LL_ERR, "url invliad"); + return FALSE; + } + urlA.port = urlA.port ? urlA.port : (urlA.isSecure ? 443 : 80); + + HttpSocket_t *httpSock = HAL_MALLOC(sizeof(HttpSocket_t)); + if (NULL == httpSock) + { + Quos_logPrintf(LSDK_HTTP, LL_ERR, "mcf httpSock"); + return FALSE; + } + HAL_MEMSET(httpSock, 0, sizeof(HttpSocket_t)); + httpSock->fileFd = SOCKET_FD_INVALID; + httpSock->eventCB = eventCB; + httpSock->bodyType = HTTP_BODY_TYPE_INVALID; + if (reqFile) + { + httpSock->bodyOffset = reqFile->offset; + httpSock->bodyLen = reqFile->size; + if (reqFile->txName) + { + httpSock->sendFilename = HAL_STRDUP(reqFile->txName); + if (NULL == httpSock->sendFilename) + { + Quos_logPrintf(LSDK_HTTP, LL_ERR, "mcf sendFilename"); + HAL_FREE(httpSock); + return FALSE; + } + } + if (reqFile->rxName) + { + httpSock->recvFilename = HAL_STRDUP(reqFile->rxName); + if (NULL == httpSock->recvFilename) + { + Quos_logPrintf(LSDK_HTTP, LL_ERR, "mcf recvFilename"); + HAL_FREE(httpSock->sendFilename); + HAL_FREE(httpSock); + return FALSE; + } + } + } + + quint16_t len = sizeof(HTTP_DEFAULT_HEADER) + HAL_STRLEN(opt) + HAL_STRLEN(urlA.path) + HAL_STRLEN(urlA.hostname) + 5; + if (reqData) + { + len += HAL_STRLEN(reqData->rawHeaders) + reqData->payloadLen; + } + + if (NULL == reqFile && NULL != reqData && 0 != reqData->payloadLen) + { + len += sizeof(QUOS_HTTP_HEAD_CONTENT_LENGHT) + 5; + } + len += HAL_STRLEN("\r\n"); + quint8_t *buf = HAL_MALLOC(len); + if (NULL == buf) + { + HAL_FREE(httpSock->sendFilename); + HAL_FREE(httpSock->recvFilename); + HAL_FREE(httpSock); + Quos_logPrintf(LSDK_HTTP, LL_ERR, "mcf tcpPayload,len:%u", len); + return FALSE; + } + len = HAL_SPRINTF((char *)buf, HTTP_DEFAULT_HEADER, opt, (urlA.path ? urlA.path : ""), urlA.hostname, urlA.port, ((reqData && reqData->rawHeaders) ? reqData->rawHeaders : "")); + if (NULL == reqFile && NULL != reqData && 0 != reqData->payloadLen) + { + len += HAL_SPRINTF((char *)buf + len, QUOS_HTTP_HEAD_CONTENT_LENGHT, reqData->payloadLen); + } + len += HAL_SPRINTF((char *)buf + len, "\r\n"); + Quos_logPrintf(LSDK_HTTP, LL_DBG, "%s", buf); + if (reqData && 0 != reqData->payloadLen) + { + HAL_MEMCPY(buf + len, reqData->payload, reqData->payloadLen); + len += reqData->payloadLen; + } + + Quos_socketChlInfoNode_t chlInfo; + HAL_MEMSET(&chlInfo, 0, sizeof(Quos_socketChlInfoNode_t)); + if (urlA.isSecure) + { +#if (SDK_ENABLE_TLS == 1) + chlInfo.sockFd = Qhal_tcpSslClientInit(&chlInfo.type, urlA.hostname, urlA.port, &chlInfo.conn.timeout); +#else + chlInfo.sockFd = SOCKET_FD_INVALID; +#endif + } + else + { + chlInfo.sockFd = Qhal_tcpClientInit(&chlInfo.type, urlA.hostname, urlA.port, &chlInfo.conn.timeout); + } + if (chlInfo.conn.timeout) + { + chlInfo.conn.notify = quos_httpSockConnctCB; + } + + if (SOCKET_FD_INVALID == chlInfo.sockFd) + { + HAL_FREE(httpSock->sendFilename); + HAL_FREE(httpSock->recvFilename); + HAL_FREE(httpSock->retHeader); + HAL_FREE(httpSock); + Quos_logPrintf(LSDK_HTTP, LL_ERR, "conn fail:%s[%u]", urlA.hostname, urlA.port); + return FALSE; + } + + chlInfo.io.send = Qhal_sockWrite; + chlInfo.send.txCnt = 1; + chlInfo.send.timeout = QUOS_HTTP_TIMEOUT; + chlInfo.recvDataFunc = quos_httpRecvData; + chlInfo.io.close = Qhal_sockClose; + chlInfo.paramFree = quos_httpParamFree; + chlInfo.param = httpSock; + + void *chlFd = Quos_socketChannelAdd(httpFd, chlInfo); + if (NULL == chlFd) + { + Quos_logPrintf(LSDK_HTTP, LL_ERR, "add socket Channel fail"); + Qhal_sockClose(chlInfo.sockFd, chlInfo.type); + HAL_FREE(httpSock->sendFilename); + HAL_FREE(httpSock->recvFilename); + HAL_FREE(httpSock->retHeader); + HAL_FREE(httpSock); + return FALSE; + } + + if (FALSE == Quos_socketTx(chlFd, NULL, 0, 0, ((NULL == reqFile || FALSE == reqFile->isPostForm) ? NULL : quos_httpSendResult), quos_httpSendCB, 0, buf, len, NULL)) + { + Quos_socketChannelDel(chlFd); + return FALSE; + } + Quos_logPrintf(LSDK_HTTP, LL_DBG, "http socket create ok"); + return TRUE; +} +/************************************************************************** +** 功能 @brief : http get下载文件 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Quos_httpGetDownload(void **httpFd, const char *url, httpEventCB_f eventCB, const HttpReqData_t *reqData, const char *filename, quint32_t offset) +{ + HttpReqFile_t reqFile; + HAL_MEMSET(&reqFile, 0, sizeof(HttpReqFile_t)); + reqFile.rxName = (char *)filename; + reqFile.offset = offset; + return Quos_httpRequest(httpFd, "GET", url, eventCB, reqData, &reqFile); +} +/************************************************************************** +** 功能 @brief : http post表单 +** 输入 @param : reqData.rawHeaders:除了Content-Type和Content-Length外其他自定义的header + reqData.payload:表单的表头数据 + reqData.payloadLen:表单的表头数据长度 +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Quos_httpPostForm(void **httpFd, const char *url, httpEventCB_f eventCB, const HttpReqData_t *reqData, const char *filename, quint32_t fileSize) +{ + HttpReqFile_t reqFile; + HAL_MEMSET(&reqFile, 0, sizeof(HttpReqFile_t)); + HttpReqData_t newReqData = *reqData; + reqFile.txName = (char *)filename; + reqFile.size = fileSize; + reqFile.isPostForm = TRUE; + + quint32_t rawHeaderLen = HAL_STRLEN(reqData->rawHeaders); + rawHeaderLen += sizeof(QUOS_HTTP_CONTENT_TYPE_KEY) + HAL_STRLEN(QUOS_HTTP_CONTENT_TYPE_VALUE_MULTIPART); + rawHeaderLen += sizeof(QUOS_HTTP_HEAD_CONTENT_LENGHT) + 5; + newReqData.rawHeaders = HAL_MALLOC(rawHeaderLen); + if (NULL == newReqData.rawHeaders) + { + return FALSE; + } + HAL_SPRINTF(newReqData.rawHeaders, "%s" QUOS_HTTP_CONTENT_TYPE_KEY QUOS_HTTP_CONTENT_TYPE_VALUE_MULTIPART QUOS_HTTP_HEAD_CONTENT_LENGHT, reqData->rawHeaders, reqData->payloadLen + fileSize + (quint32_t)HAL_STRLEN(QUOS_HTTP_MULTIPART_NODE_END)); + qbool ret = Quos_httpRequest(httpFd, "POST", url, eventCB, &newReqData, &reqFile); + HAL_FREE(newReqData.rawHeaders); + return ret; +} +/************************************************************************** +** 功能 @brief : 获取当前文件下载/上传进度 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Quos_httpFileRate(void *httpFd, quint32_t *bodyLen, qint32_t *bodyType, char **retHeader) +{ + qbool ret = FALSE; + if(Quos_socketGetSockFdType(httpFd, NULL, NULL)) + { + Quos_socketChlInfoNode_t *sockNode = (Quos_socketChlInfoNode_t*)httpFd; + if(sockNode->param) + { + HttpSocket_t *httpSock = (HttpSocket_t *)sockNode->param; + if(bodyLen) + { + *bodyLen = httpSock->bodyLen; + } + if(bodyType) + { + *bodyType = httpSock->bodyType; + } + if(retHeader) + { + *retHeader = httpSock->retHeader; + } + ret = TRUE; + } + } + return ret; +} +#endif \ No newline at end of file diff --git a/kernel/quos_http.h b/kernel/quos_http.h index 8102423e90c95247ac228974605a699db5793687..51ad9f8b5340037d0069f7cd6d8dcfb8c11f9343 100644 --- a/kernel/quos_http.h +++ b/kernel/quos_http.h @@ -1,56 +1,56 @@ -#ifndef __QUOS_HTTP_H__ -#define __QUOS_HTTP_H__ -#include "quos_config.h" -#if (SDK_ENABLE_HTTP==1) -#define QUOS_HTTP_MULTIPART_BOUNDARY "450d2e46-73fc11eaad264b91df3ae910" -#define QUOS_HTTP_MULTIPART_NODE_START "--" QUOS_HTTP_MULTIPART_BOUNDARY "\r\n" -#define QUOS_HTTP_MULTIPART_NODE_END "\r\n--" QUOS_HTTP_MULTIPART_BOUNDARY "--\r\n" - -#define QUOS_HTTP_HEAD_CONTENT_LENGHT "Content-Length: %u\r\n" - -#define QUOS_HTTP_CONTENT_TYPE_KEY "Content-Type: " -#define QUOS_HTTP_CONTENT_TYPE_VALUE_JSON "application/json\r\n" -#define QUOS_HTTP_CONTENT_TYPE_VALUE_MULTIPART "multipart/form-data; boundary=" QUOS_HTTP_MULTIPART_BOUNDARY "\r\n" -#define QUOS_HTTP_CONTENT_TYPE_VALUE_OCTET_STREAM "application/octet-stream\r\n" - -#define QUOS_HTTP_CONTENT_DISPOSITION_KEY "Content-Disposition: " - -enum -{ - QUOS_HTTP_CODE_ERR_DATA = -255, - QUOS_HTTP_CODE_ERR_RAM, - QUOS_HTTP_CODE_ERR_NET, -}; - -typedef struct -{ - char *rawHeaders; /* 每项以"\r\n"结束 */ - char *payload; - quint16_t payloadLen; -} HttpReqData_t; - -typedef struct -{ - char *txName; - char *rxName; - quint32_t size; - quint32_t offset; - qbool isPostForm; -} HttpReqFile_t; - -/* 在非下载文件时,只有完成整个HTTP才CB一次 - 在下载文件时,下载提取到header数据时先CB一次,recvLen=0, - 根据CB返回结果判断是否继续,为TRUE时则继续下载文件, - HTTP结束后再CB一次,此时recvLen为下载到的文件大小 */ -typedef qbool (*httpEventCB_f)(qint32_t httpCode, char *retHeader, quint8_t *recvBuf, quint32_t recvLen); - -qbool Quos_httpRequest(const char *opt, const char *url, httpEventCB_f eventCB, const HttpReqData_t *reqData, const HttpReqFile_t *reqFile); -qbool Quos_httpGetDownload(const char *url, httpEventCB_f eventCB, const HttpReqData_t *reqData, const char *filename, quint32_t offset); -qbool Quos_httpPostForm(const char *url, httpEventCB_f eventCB, const HttpReqData_t *reqData, const char *filename, quint32_t fileSize); - -#define Quos_httpGet(URL, EVENTCB, REQDATA) Quos_httpRequest("GET", URL, EVENTCB, REQDATA, NULL) -#define Quos_httpPost(URL, EVENTCB, REQDATA) Quos_httpRequest("POST", URL, EVENTCB, REQDATA, NULL) -#define Quos_httpPut(URL, EVENTCB, REQDATA) Quos_httpRequest("PUT", URL, EVENTCB, REQDATA, NULL) -#define Quos_httpDelete(URL, EVENTCB, REQDATA) Quos_httpRequest("DELETE", URL, EVENTCB, REQDATA, NULL) -#endif -#endif +#ifndef __QUOS_HTTP_H__ +#define __QUOS_HTTP_H__ +#include "quos_config.h" +#if (SDK_ENABLE_HTTP == 1) +#define QUOS_HTTP_MULTIPART_BOUNDARY "450d2e46-73fc11eaad264b91df3ae910" +#define QUOS_HTTP_MULTIPART_NODE_START "--" QUOS_HTTP_MULTIPART_BOUNDARY "\r\n" +#define QUOS_HTTP_MULTIPART_NODE_END "\r\n--" QUOS_HTTP_MULTIPART_BOUNDARY "--\r\n" + +#define QUOS_HTTP_HEAD_CONTENT_LENGHT "Content-Length: %u\r\n" + +#define QUOS_HTTP_CONTENT_TYPE_KEY "Content-Type: " +#define QUOS_HTTP_CONTENT_TYPE_VALUE_JSON "application/json\r\n" +#define QUOS_HTTP_CONTENT_TYPE_VALUE_MULTIPART "multipart/form-data; boundary=" QUOS_HTTP_MULTIPART_BOUNDARY "\r\n" +#define QUOS_HTTP_CONTENT_TYPE_VALUE_OCTET_STREAM "application/octet-stream\r\n" + +#define QUOS_HTTP_CONTENT_DISPOSITION_KEY "Content-Disposition: " + +enum +{ + QUOS_HTTP_CODE_ERR_DATA = -255, + QUOS_HTTP_CODE_ERR_RAM, + QUOS_HTTP_CODE_ERR_NET, +}; + +typedef struct +{ + char *rawHeaders; /* 每项以"\r\n"结束 */ + char *payload; + quint16_t payloadLen; +} HttpReqData_t; + +typedef struct +{ + char *txName; + char *rxName; + quint32_t size; + quint32_t offset; + qbool isPostForm; +} HttpReqFile_t; + +/* 在非下载文件时,只有完成整个HTTP才CB一次 + 在下载文件时,下载提取到header数据时先CB一次,recvLen=0, + 根据CB返回结果判断是否继续,为TRUE时则继续下载文件, + HTTP结束后再CB一次,此时recvLen为下载到的文件大小 */ +typedef qbool (*httpEventCB_f)(qint32_t httpCode, char *retHeader, quint8_t *recvBuf, quint32_t recvLen); + +qbool Quos_httpRequest(void **httpFd, const char *opt, const char *url, httpEventCB_f eventCB, const HttpReqData_t *reqData, const HttpReqFile_t *reqFile); +qbool Quos_httpGetDownload(void **httpFd, const char *url, httpEventCB_f eventCB, const HttpReqData_t *reqData, const char *filename, quint32_t offset); +qbool Quos_httpPostForm(void **httpFd, const char *url, httpEventCB_f eventCB, const HttpReqData_t *reqData, const char *filename, quint32_t fileSize); + +#define Quos_httpGet(URL, EVENTCB, REQDATA) Quos_httpRequest(NULL, "GET", URL, EVENTCB, REQDATA, NULL) +#define Quos_httpPost(URL, EVENTCB, REQDATA) Quos_httpRequest(NULL, "POST", URL, EVENTCB, REQDATA, NULL) +#define Quos_httpPut(URL, EVENTCB, REQDATA) Quos_httpRequest(NULL, "PUT", URL, EVENTCB, REQDATA, NULL) +#define Quos_httpDelete(URL, EVENTCB, REQDATA) Quos_httpRequest(NULL, "DELETE", URL, EVENTCB, REQDATA, NULL) +#endif +#endif diff --git a/kernel/quos_log.c b/kernel/quos_log.c new file mode 100644 index 0000000000000000000000000000000000000000..8e76751a16d3ebc22532ebfffae11575a93400e8 --- /dev/null +++ b/kernel/quos_log.c @@ -0,0 +1,29 @@ +/************************************************************************* +** 创建人 @author : 吴健超 JCWu +** 版本 @version : V1.0.0 原始版本 +** 日期 @date : +** 功能 @brief : 统一日志打印API +** 硬件 @hardware:任何ANSI-C平台 +** 其他 @other : +***************************************************************************/ +#include "quos_log.h" +HAL_LOCK_DEF(,lockLogId) + +/************************************************************************** +** 功能 @brief : HEXDUMP数据 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_RAM Quos_logHexDumpData(const void *dat, quint16_t len) +{ + quint16_t i; + for (i = 0; i < len; i++) + { + if (i % 20 == 0) + { + HAL_PRINTF("\r\n"); + } + HAL_PRINTF("%02X ", ((quint8_t *)dat)[i]); + } + HAL_PRINTF("\r\n"); +} diff --git a/kernel/quos_log.h b/kernel/quos_log.h index 3e4e9e58ed3eecd8d45a8d5befb86ac0c5e31dd7..2ad079880d1adbda699d16875e57c941a2d285c5 100644 --- a/kernel/quos_log.h +++ b/kernel/quos_log.h @@ -1,49 +1,53 @@ -#ifndef __QUOS_LOG_H__ -#define __QUOS_LOG_H__ -#include "quos_config.h" - -#ifdef __cplusplus -extern "C" -{ -#endif - -#define LL_OFF (0X07) /* 关闭所有日志 */ -#define LL_FAIL (0X06) /* 将导致程序退出的错误及其以上 */ -#define LL_ERR (0X05) /* 发生错误但不会导致程序退出及其以上 */ -#define LL_WARN (0X04) /* 警告级别错误及其以上 */ -#define LL_INFO (0X03) /* 粗粒度级别log及其以上 */ -#define LL_DBG (0X02) /* 所有log */ -#define LL_DUMP (0X01) /* dump数据,仅用于Quos_logHexDump打印 */ - -#ifndef QUOS_LOGL -#define QUOS_LOGL LL_DBG -#endif - -#define Quos_logPrintf(TYPE, LEVEL, format, ...) \ - if (LEVEL >= TYPE && LEVEL >= QUOS_LOGL) \ - { \ - HAL_LOCK(lockLogId); \ - HAL_PRINTF("%s<%s\t> %s[%d] " format "\r\n", Qhal_logHeadString(), #TYPE, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ - HAL_UNLOCK(lockLogId); \ - } - -#if (SDK_ENABLE_LOGDUMP ==1 ) -#define Quos_logHexDump(TYPE, LEVEL, HEAD, DAT, DATLEN) \ - if (LEVEL >= TYPE && LEVEL >= QUOS_LOGL) \ - { \ - HAL_LOCK(lockLogId); \ - HAL_PRINTF("%s<%s\t> %s[%d] %s\r\n", Qhal_logHeadString(), #TYPE, __FUNCTION__, __LINE__, HEAD); \ - HAL_PRINTF("*************************** %04d **************************", (quint16_t)(DATLEN)); \ - Quos_logHexDumpData(DAT, DATLEN); \ - HAL_UNLOCK(lockLogId); \ - } - void Quos_logHexDumpData(void *dat, quint16_t len); -#else - #define Quos_logHexDump(TYPE, LEVEL, HEAD, DAT, DATLEN) -#endif - HAL_LOCK_DEF(extern, lockLogId) - extern char *Qhal_logHeadString(void); -#ifdef __cplusplus -} -#endif +#ifndef __QUOS_LOG_H__ +#define __QUOS_LOG_H__ +#include "quos_config.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define LL_OFF (0X07) /* 关闭所有日志 */ +#define LL_FAIL (0X06) /* 将导致程序退出的错误及其以上 */ +#define LL_ERR (0X05) /* 发生错误但不会导致程序退出及其以上 */ +#define LL_WARN (0X04) /* 警告级别错误及其以上 */ +#define LL_INFO (0X03) /* 粗粒度级别log及其以上 */ +#define LL_DBG (0X02) /* 所有log */ +#define LL_DUMP (0X01) /* dump数据,仅用于Quos_logHexDump打印 */ + +#ifndef QUOS_LOGL +#define QUOS_LOGL LL_ERR +#endif + +#define Quos_logPrintf(TYPE, LEVEL, format, ...) \ + do \ + { \ + if (LEVEL >= TYPE && LEVEL >= QUOS_LOGL) \ + { \ + HAL_LOCK(lockLogId); \ + HAL_PRINTF("%s<%-12s> %s[%d] " format "\r\n", Qhal_logHeadString(), #TYPE, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ + HAL_UNLOCK(lockLogId); \ + } \ + } while (0) + +#define Quos_logHexDump(TYPE, LEVEL, HEAD, DAT, DATLEN) \ + do \ + { \ + if (LEVEL >= TYPE && LEVEL >= QUOS_LOGL) \ + { \ + HAL_LOCK(lockLogId); \ + HAL_PRINTF("%s<%-12s> %s[%d] %s\r\n", Qhal_logHeadString(), #TYPE, __FUNCTION__, __LINE__, HEAD); \ + HAL_PRINTF("*************************** %04d **************************", (quint16_t)(DATLEN)); \ + Quos_logHexDumpData(DAT, DATLEN); \ + HAL_UNLOCK(lockLogId); \ + } \ + } while (0) + + void Quos_logHexDumpData(const void *dat, quint16_t len); + + HAL_LOCK_DEF(extern, lockLogId) + extern char *Qhal_logHeadString(void); +#ifdef __cplusplus +} +#endif #endif \ No newline at end of file diff --git a/kernel/quos_lwm2m.c b/kernel/quos_lwm2m.c new file mode 100644 index 0000000000000000000000000000000000000000..15c1a8c1d336ed385180269b64b4674a017b0cf8 --- /dev/null +++ b/kernel/quos_lwm2m.c @@ -0,0 +1,182 @@ +/************************************************************************* +** 创建人 @author : 吴健超 JCWu +** 版本 @version : V1.0.0 原始版本 +** 日期 @date : +** 功能 @brief : lwm2m bootstrap +** 硬件 @hardware:任何ANSI-C平台 +** 其他 @other : +***************************************************************************/ +#include "quos_lwm2m.h" +#if (SDK_ENABLE_LWM2M == 1) +#include "internals.h" +#include "Qhal_driver.h" +extern char *get_server_uri(lwm2m_object_t *objectP, quint16_t secObjInstID); + +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void FUNCTION_ATTR_ROM quos_lwm2mStepTimeCB(void *swTimer) +{ + lwm2m_context_t *ctx = (lwm2m_context_t *)swTimer->parm; + lwm2mUsedata_t *userdata = (lwm2mUsedata_t *)ctx->userData; + time_t stepPeriod = userdata->stepPeriod; + int stepRet = lwm2m_step(ctx, &stepPeriod); + Quos_logPrintf(LSDK_LWM2M, LL_DBG, "lwm2m step period:" PRINTF_FD " stepRet:0x%02X state:%s", stepPeriod, stepRet, STR_STATE(ctx->state)); + if (0 != stepRet && ctx->state == STATE_BOOTSTRAPPING) + { + /* 需要在此重新初始化资源 */ + ctx->state = STATE_INITIAL; + stepPeriod = 10; + } + Quos_swTimerTimeoutSet(swTimer, stepPeriod * SWT_ONE_SECOND); +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM *quos_lwm2mInit(char *name, lwm2m_object_t *objects[], quint16_t count, lwm2mUsedata_t *userdata) +{ + if (NULL == userdata) + { + Quos_logPrintf(LSDK_LWM2M, LL_ERR, "userdata param invalid"); + return NULL; + } + lwm2m_context_t *ctx = lwm2m_init(userdata); + if (NULL == ctx) + { + Quos_logPrintf(LSDK_LWM2M, LL_ERR, "init fail"); + HAL_FREE(userdata); + return NULL; + } + if (FALSE == Quos_swTimerStart(&ctx->stepTimer, "lwm2m step", 1, 0, quos_lwm2mStepTimeCB, ctx)) + { + Quos_logPrintf(LSDK_LWM2M, LL_ERR, "step timer start fail"); + HAL_FREE(userdata); + HAL_FREE(ctx); + return NULL; + } + if (COAP_NO_ERROR != lwm2m_configure(ctx, name, NULL, NULL, count, objects)) + { + Quos_logPrintf(LSDK_LWM2M, LL_ERR, "config fail"); + Quos_swTimerDelete(ctx->stepTimer); + HAL_FREE(userdata); + HAL_FREE(ctx); + return NULL; + } + Quos_logPrintf(LSDK_LWM2M, LL_DBG, "lwm2m init ok"); + return (void *)ctx; +} + +/************************************************************************** +** 功能 @brief : coap接收数据处理 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static qbool FUNCTION_ATTR_ROM quos_lwm2mSocketRecv(void *chlFd, const void *peer, quint32_t peerSize, Quos_socketRecvDataNode_t *recvData) +{ + UNUSED(peer); + UNUSED(peerSize); + Quos_logPrintf(LSDK_LWM2M, LL_DBG, "lwm2m recv chlFd[%p]", chlFd); + + Quos_socketChlInfoNode_t *chlNode = (Quos_socketChlInfoNode_t *)chlFd; + lwm2m_context_t *ctx = (lwm2m_context_t *)chlNode->param; + if (NULL == recvData) + { + ctx->state = STATE_INITIAL; + Quos_swTimerTimeoutSet(ctx->stepTimer, 0); + return FALSE; + } + Quos_logHexDump(LSDK_LWM2M, LL_DUMP, "lwm2m recv", recvData->Buf, recvData->bufLen); + lwm2m_handle_packet(ctx, recvData->Buf, recvData->bufLen, chlFd); + Quos_swTimerTimeoutSet(ctx->stepTimer, 0); + return TRUE; +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM *lwm2m_connect_server(void **fd, quint16_t secObjInstID, void *context) +{ + lwm2m_context_t *ctx = (lwm2m_context_t *)context; + lwm2m_object_t *targetP = (lwm2m_object_t *)LWM2M_LIST_FIND(ctx->objectList, LWM2M_SECURITY_OBJECT_ID); + if (NULL == targetP) + { + Quos_logPrintf(LSDK_LWM2M, LL_ERR, "not found security obj"); + return NULL; + } + char *url = get_server_uri(targetP, secObjInstID); + if (NULL == url) + { + Quos_logPrintf(LSDK_LWM2M, LL_ERR, "server url is empty"); + return NULL; + } + Quos_logPrintf(LSDK_LWM2M, LL_DBG, "url:%s", url); + urlAnalyze_t urlA; + if (FALSE == Quos_urlAnalyze(url, &urlA)) + { + Quos_logPrintf(LSDK_LWM2M, LL_ERR, "url[%s] analyze fail", url); + return NULL; + } + urlA.port = urlA.port ? urlA.port : (urlA.isSecure ? 5684 : 5683); + Quos_socketChlInfoNode_t chlInfo; + HAL_MEMSET(&chlInfo, 0, sizeof(Quos_socketChlInfoNode_t)); + if (urlA.isSecure) + { +#if (SDK_ENABLE_TLS == 1) + chlInfo.sockFd = Qhal_udpSslInit(&chlInfo.type, 0, urlA.hostname, urlA.port); +#else + chlInfo.sockFd = SOCKET_FD_INVALID; +#endif + } + else + { + chlInfo.sockFd = Qhal_udpInit(&chlInfo.type, 0, urlA.hostname, urlA.port, NULL); + } + if (SOCKET_FD_INVALID == chlInfo.sockFd) + { + Quos_logPrintf(LSDK_LWM2M, LL_ERR, "coap conn fail:%s[%u]", urlA.hostname, urlA.port); + return FALSE; + } + + chlInfo.io.send = Qhal_sockWrite; + chlInfo.send.txCnt = COAP_MAX_RETRANSMIT; + chlInfo.send.timeout = COAP_RESPONSE_TIMEOUT * SWT_ONE_SECOND; + chlInfo.recvDataFunc = quos_lwm2mSocketRecv; + chlInfo.io.close = Qhal_sockClose; + chlInfo.param = context; + void *chlFd = Quos_socketChannelAdd(fd, chlInfo); + Quos_logPrintf(LSDK_LWM2M, LL_INFO, "lwm2m chlFd[%p]", chlFd); + if(NULL == chlFd) + { + Qhal_sockClose(chlInfo.sockFd,chlInfo.type); + } + return chlFd; +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM lwm2m_close_connection(void *sessionH, void *context) +{ + Quos_logPrintf(LSDK_LWM2M, LL_INFO, "lwm2m close sessionH[%p] context[%p]", sessionH, context); + Quos_socketChannelDel(sessionH); +} + +/************************************************************************** +** 功能 @brief : bootstrap payload +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +quint16_t FUNCTION_ATTR_ROM get_bootstrap_payload(lwm2m_context_t *context, quint8_t **valP) +{ + lwm2mUsedata_t *userdata = (lwm2mUsedata_t *)context->userData; + *valP = userdata->bs.payload.val; + return userdata->bs.payload.len; +} + +#endif \ No newline at end of file diff --git a/kernel/quos_md5.c b/kernel/quos_md5.c new file mode 100644 index 0000000000000000000000000000000000000000..bb255a0ddecd4bbb39d6a38039be40bfa26aba11 --- /dev/null +++ b/kernel/quos_md5.c @@ -0,0 +1,274 @@ +/************************************************************************* +** 创建人 @author : 吴健超 JCWu +** 版本 @version : V1.0.0 原始版本 +** 日期 @date : +** 功能 @brief : MD5算法 +** 硬件 @hardware:任何ANSI-C平台 +** 其他 @other : +***************************************************************************/ +#include "quos_md5.h" +#if (SDK_ENABLE_MD5 == 1) +#define T1 0xd76aa478 +#define T2 0xe8c7b756 +#define T3 0x242070db +#define T4 0xc1bdceee +#define T5 0xf57c0faf +#define T6 0x4787c62a +#define T7 0xa8304613 +#define T8 0xfd469501 +#define T9 0x698098d8 +#define T10 0x8b44f7af +#define T11 0xffff5bb1 +#define T12 0x895cd7be +#define T13 0x6b901122 +#define T14 0xfd987193 +#define T15 0xa679438e +#define T16 0x49b40821 +#define T17 0xf61e2562 +#define T18 0xc040b340 +#define T19 0x265e5a51 +#define T20 0xe9b6c7aa +#define T21 0xd62f105d +#define T22 0x02441453 +#define T23 0xd8a1e681 +#define T24 0xe7d3fbc8 +#define T25 0x21e1cde6 +#define T26 0xc33707d6 +#define T27 0xf4d50d87 +#define T28 0x455a14ed +#define T29 0xa9e3e905 +#define T30 0xfcefa3f8 +#define T31 0x676f02d9 +#define T32 0x8d2a4c8a +#define T33 0xfffa3942 +#define T34 0x8771f681 +#define T35 0x6d9d6122 +#define T36 0xfde5380c +#define T37 0xa4beea44 +#define T38 0x4bdecfa9 +#define T39 0xf6bb4b60 +#define T40 0xbebfbc70 +#define T41 0x289b7ec6 +#define T42 0xeaa127fa +#define T43 0xd4ef3085 +#define T44 0x04881d05 +#define T45 0xd9d4d039 +#define T46 0xe6db99e5 +#define T47 0x1fa27cf8 +#define T48 0xc4ac5665 +#define T49 0xf4292244 +#define T50 0x432aff97 +#define T51 0xab9423a7 +#define T52 0xfc93a039 +#define T53 0x655b59c3 +#define T54 0x8f0ccc92 +#define T55 0xffeff47d +#define T56 0x85845dd1 +#define T57 0x6fa87e4f +#define T58 0xfe2ce6e0 +#define T59 0xa3014314 +#define T60 0x4e0811a1 +#define T61 0xf7537e82 +#define T62 0xbd3af235 +#define T63 0x2ad7d2bb +#define T64 0xeb86d391 + +static void md5_process(md5_state_t *pms, const quint8_t data[64]) +{ + quint32_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2], d = pms->abcd[3]; + quint32_t t; + + quint32_t xbuf[16]; + const quint32_t *X; + static const int w = 1; + + if (*((const quint8_t *)&w)) + { + if (!((data - (const quint8_t *)0) & 3)) + { + X = (const quint32_t *)data; + } + else + { + HAL_MEMCPY(xbuf, data, 64); + X = xbuf; + } + } + else + { + const quint8_t *xp = data; + int i; + X = xbuf; + for (i = 0; i < 16; ++i, xp += 4) + { + xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); + } + } + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) +#define FF(a, b, c, d, k, s, Ti) \ + t = a + ((b & c) | (~b & d)) + X[k] + Ti; \ + a = ROTATE_LEFT(t, s) + b +#define GG(a, b, c, d, k, s, Ti) \ + t = a + ((b & d) | (c & ~d)) + X[k] + Ti; \ + a = ROTATE_LEFT(t, s) + b +#define HH(a, b, c, d, k, s, Ti) \ + t = a + ((b) ^ (c) ^ (d)) + X[k] + Ti; \ + a = ROTATE_LEFT(t, s) + b +#define II(a, b, c, d, k, s, Ti) \ + t = a + ((c) ^ ((b) | ~(d))) + X[k] + Ti; \ + a = ROTATE_LEFT(t, s) + b + + FF(a, b, c, d, 0, 7, T1); + FF(d, a, b, c, 1, 12, T2); + FF(c, d, a, b, 2, 17, T3); + FF(b, c, d, a, 3, 22, T4); + FF(a, b, c, d, 4, 7, T5); + FF(d, a, b, c, 5, 12, T6); + FF(c, d, a, b, 6, 17, T7); + FF(b, c, d, a, 7, 22, T8); + FF(a, b, c, d, 8, 7, T9); + FF(d, a, b, c, 9, 12, T10); + FF(c, d, a, b, 10, 17, T11); + FF(b, c, d, a, 11, 22, T12); + FF(a, b, c, d, 12, 7, T13); + FF(d, a, b, c, 13, 12, T14); + FF(c, d, a, b, 14, 17, T15); + FF(b, c, d, a, 15, 22, T16); + + GG(a, b, c, d, 1, 5, T17); + GG(d, a, b, c, 6, 9, T18); + GG(c, d, a, b, 11, 14, T19); + GG(b, c, d, a, 0, 20, T20); + GG(a, b, c, d, 5, 5, T21); + GG(d, a, b, c, 10, 9, T22); + GG(c, d, a, b, 15, 14, T23); + GG(b, c, d, a, 4, 20, T24); + GG(a, b, c, d, 9, 5, T25); + GG(d, a, b, c, 14, 9, T26); + GG(c, d, a, b, 3, 14, T27); + GG(b, c, d, a, 8, 20, T28); + GG(a, b, c, d, 13, 5, T29); + GG(d, a, b, c, 2, 9, T30); + GG(c, d, a, b, 7, 14, T31); + GG(b, c, d, a, 12, 20, T32); + + HH(a, b, c, d, 5, 4, T33); + HH(d, a, b, c, 8, 11, T34); + HH(c, d, a, b, 11, 16, T35); + HH(b, c, d, a, 14, 23, T36); + HH(a, b, c, d, 1, 4, T37); + HH(d, a, b, c, 4, 11, T38); + HH(c, d, a, b, 7, 16, T39); + HH(b, c, d, a, 10, 23, T40); + HH(a, b, c, d, 13, 4, T41); + HH(d, a, b, c, 0, 11, T42); + HH(c, d, a, b, 3, 16, T43); + HH(b, c, d, a, 6, 23, T44); + HH(a, b, c, d, 9, 4, T45); + HH(d, a, b, c, 12, 11, T46); + HH(c, d, a, b, 15, 16, T47); + HH(b, c, d, a, 2, 23, T48); + + II(a, b, c, d, 0, 6, T49); + II(d, a, b, c, 7, 10, T50); + II(c, d, a, b, 14, 15, T51); + II(b, c, d, a, 5, 21, T52); + II(a, b, c, d, 12, 6, T53); + II(d, a, b, c, 3, 10, T54); + II(c, d, a, b, 10, 15, T55); + II(b, c, d, a, 1, 21, T56); + II(a, b, c, d, 8, 6, T57); + II(d, a, b, c, 15, 10, T58); + II(c, d, a, b, 6, 15, T59); + II(b, c, d, a, 13, 21, T60); + II(a, b, c, d, 4, 6, T61); + II(d, a, b, c, 11, 10, T62); + II(c, d, a, b, 2, 15, T63); + II(b, c, d, a, 9, 21, T64); + + /* Then perform the following additions. (That is increment each + of the four registers by the value it had before this block + was started.) */ + pms->abcd[0] += a; + pms->abcd[1] += b; + pms->abcd[2] += c; + pms->abcd[3] += d; +} + +void Quos_md5Init(md5_state_t *pms) +{ + pms->count[0] = pms->count[1] = 0; + pms->abcd[0] = 0x67452301; + pms->abcd[1] = 0xefcdab89; + pms->abcd[2] = 0x98badcfe; + pms->abcd[3] = 0x10325476; +} + +void Quos_md5Append(md5_state_t *pms, const quint8_t *data, quint32_t nbytes) +{ + const quint8_t *p = data; + int left = nbytes; + int offset = (pms->count[0] >> 3) & 63; + quint32_t nbits = (quint32_t)(nbytes << 3); + + if (nbytes <= 0) + return; + + /* Update the message length. */ + pms->count[1] += nbytes >> 29; + pms->count[0] += nbits; + if (pms->count[0] < nbits) + pms->count[1]++; + + /* Process an initial partial block. */ + if (offset) + { + int copy; + if (offset + nbytes > 64) + { + copy = 64 - offset; + } + else + { + copy = nbytes; + } + + HAL_MEMCPY(pms->buf + offset, p, copy); + if (offset + copy < 64) + return; + p += copy; + left -= copy; + md5_process(pms, pms->buf); + } + + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) + md5_process(pms, p); + + /* Process a final partial block. */ + if (left) + HAL_MEMCPY(pms->buf, p, left); +} + +void Quos_md5Finish(md5_state_t *pms, quint8_t digest[16]) +{ + static const quint8_t pad[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + quint8_t data[8]; + int i; + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (quint8_t)(pms->count[i >> 2] >> ((i & 3) << 3)); + /* Pad to 56 bytes mod 64. */ + Quos_md5Append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); + /* Append the length. */ + Quos_md5Append(pms, data, 8); + for (i = 0; i < 16; ++i) + digest[i] = (quint8_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); +} +#endif \ No newline at end of file diff --git a/kernel/quos_mqtt.c b/kernel/quos_mqtt.c new file mode 100644 index 0000000000000000000000000000000000000000..299256ed51e56f6a82ba8d37bf66e23c967a8a4b --- /dev/null +++ b/kernel/quos_mqtt.c @@ -0,0 +1,602 @@ +/************************************************************************* +** 创建人 @author : 吴健超 JCWu +** 版本 @version : V1.0.0 原始版本 +** 日期 @date : +** 功能 @brief : MQTT通信管理 +** 硬件 @hardware:任何ANSI-C平台 +** 其他 @other : +***************************************************************************/ +#include "quos_mqtt.h" +#if (SDK_ENABLE_MQTT == 1) +#include "Quos_kernel.h" +#include "Qhal_driver.h" +#ifndef QUOS_MQTT_RESEND_TIME +#define QUOS_MQTT_RESEND_TIME 3 +#endif +#ifndef QUOS_MQTT_SEND_TIMEOUT +#define QUOS_MQTT_SEND_TIMEOUT 2 * SWT_ONE_SECOND +#endif +#ifndef QUOS_MQTT_CONNECT_TIMEOUT +#define QUOS_MQTT_CONNECT_TIMEOUT 5 * SWT_ONE_SECOND +#endif +#ifndef QUOS_MQTT_PING_TIMEOUT +#define QUOS_MQTT_PING_TIMEOUT 5 * SWT_ONE_SECOND +#endif +typedef struct +{ + void *pingTimer; + quint32_t keepAlive; + MqttEventCb_f eventCB; + MqttpublishRecv_f pubRecv; + quint16_t pkgId; + quint16_t qos2RecvId; +} mqttSock_t; + +static void quos_mqttPing(void *swTimer); +/************************************************************************** +** 功能 @brief : MQTT协议通信数据包解析 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static qbool FUNCTION_ATTR_ROM quos_mqttUnform(const quint8_t *buf, quint32_t bufLen, quint32_t *offset, Quos_socketTempData_t *unformTemp) +{ + if (unformTemp->bufLen == 0) + { + unformTemp->buf = (quint8_t *)HAL_MALLOC(5); + if (NULL == unformTemp->buf) + { + Quos_logPrintf(LSDK_MQTT, LL_ERR, "mcf"); + *offset = bufLen; + return FALSE; + } + unformTemp->offset = 0; + unformTemp->bufLen = 5; + } + + int pkgLen = 0; + quint32_t i; + for (i = 1; i < unformTemp->offset; i++) + { + if ((unformTemp->buf[i] & 0x80) == 0x00) + { + MQTTPacket_decodeBuf(unformTemp->buf + 1, &pkgLen); + pkgLen = MQTTPacket_len(pkgLen); + } + } + for (*offset = 0; *offset < bufLen; (*offset)++) + { + if (unformTemp->offset == 0) + { + quint8_t type = buf[*offset] >> 4; + quint8_t flag = buf[*offset] & 0x0F; + + if ((0 == flag && (CONNECT == type || CONNACK == type || PUBACK == type || PUBREC == type || PUBCOMP == type || SUBACK == type || UNSUBACK == type || PINGREQ == type || PINGRESP == type || DISCONNECT == type)) || + (1 == flag && (PUBREL == type || SUBSCRIBE == type || UNSUBSCRIBE == type)) || + PUBLISH == type) + { + unformTemp->buf[unformTemp->offset++] = buf[*offset]; + Quos_logPrintf(LSDK_MQTT, LL_DBG, "mqtt head type:%X flag:%X", type, flag); + } + } + else if (0 == pkgLen) + { + unformTemp->buf[unformTemp->offset++] = buf[*offset]; + if ((buf[*offset] & 0x80) == 0x00) + { + MQTTPacket_decodeBuf(unformTemp->buf + 1, &pkgLen); + pkgLen = MQTTPacket_len(pkgLen); + if (pkgLen > (int)unformTemp->bufLen) + { + quint8_t *newBuf = (quint8_t *)HAL_MALLOC(pkgLen); + if (newBuf) + { + HAL_MEMCPY(newBuf, unformTemp->buf, unformTemp->offset); + HAL_FREE(unformTemp->buf); + unformTemp->buf = newBuf; + unformTemp->bufLen = pkgLen; + } + else + { + unformTemp->offset = 0; + *offset = bufLen; + return FALSE; + } + } + else if (pkgLen == 2) + { + Quos_logPrintf(LSDK_MQTT, LL_DBG, "mqtt ok head[0x%02X] len[%u]", unformTemp->buf[0], unformTemp->offset); + (*offset)++; + return TRUE; + } + } + else if (unformTemp->offset >= 5) + { + unformTemp->offset = 0; + pkgLen = 0; + } + } + else + { + unformTemp->buf[unformTemp->offset++] = buf[*offset]; + if (unformTemp->offset >= (quint32_t)pkgLen) + { + Quos_logPrintf(LSDK_MQTT, LL_DBG, "mqtt ok head[0x%02X] len[%u]", unformTemp->buf[0], unformTemp->offset); + (*offset)++; + return TRUE; + } + } + } + + return FALSE; +} +/************************************************************************** +** 功能 @brief : m2m publish send ack +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void quos_mqttPublishRecvAck(void *chlFd, const void *sendData, const void *recvData) +{ + UNUSED(chlFd); + UNUSED(sendData); + if (recvData) + { + Quos_logPrintf(LSDK_MQTT, LL_DBG, "publish success"); + } + else + { + Quos_logPrintf(LSDK_MQTT, LL_DBG, "publish fail"); + } +} +/************************************************************************** +** 功能 @brief : m2m publish send +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qint32_t FUNCTION_ATTR_ROM Quos_mqttPublish(const void *chlFd, char *topicString, const void *param, qint32_t qos, void *buf, quint16_t bufLen, socketRecvNodeCb_f recvCB, qbool isAck) +{ + if (NULL == chlFd || NULL == topicString || NULL == buf || 0 == bufLen) + { + Quos_logPrintf(LSDK_MQTT, LL_ERR, "chlFd[%p] topicString:%s buf:%p bufLen:%u", chlFd, topicString, buf, bufLen); + return -1; + } + Quos_socketChlInfoNode_t *chlNode = (Quos_socketChlInfoNode_t *)chlFd; + if (NULL == chlNode->param) + { + Quos_logPrintf(LSDK_MQTT, LL_ERR, "mqttSock invalid"); + return -1; + } + mqttSock_t *mqttSock = (mqttSock_t *)chlNode->param; + MQTTString topic; + HAL_MEMSET(&topic, 0, sizeof(topic)); + topic.cstring = topicString; + quint16_t len = MQTTPacket_len(MQTTSerialize_publishLength(qos, topic, bufLen)); + quint8_t *pubBuf = HAL_MALLOC(len); + if (NULL == pubBuf) + { + Quos_logPrintf(LSDK_MQTT, LL_ERR, "mcf pubBuf"); + return -1; + } + len = MQTTSerialize_publish(pubBuf, len, 0, (int)qos, 0, 0 == qos ? 0 : ((++mqttSock->pkgId) == 0 ? (++mqttSock->pkgId) : mqttSock->pkgId), topic, buf, bufLen); + if (isAck) + { + return Quos_socketTxDisorder(chlFd, NULL, pubBuf, len) ? mqttSock->pkgId : -1; + } + else if (0 == qos) + { + return Quos_socketTx(chlFd, NULL, 0, 0, NULL, NULL, 0, pubBuf, len, param) ? mqttSock->pkgId : -1; + } + else + { + return Quos_socketTx(chlFd, NULL, 0, 0, NULL, recvCB ? recvCB : quos_mqttPublishRecvAck, mqttSock->pkgId, pubBuf, len, param) ? mqttSock->pkgId : -1; + } +} + +/************************************************************************** +** 功能 @brief : 解析publish包 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Quos_mqttPublishReslover(quint8_t *srcData, quint32_t srcLen, MQTTString *topicName, quint8_t **payload, int *payloadlen) +{ + int qos; + quint8_t dup = 0; + quint16_t packetid = 0; + quint8_t retained; + if (MQTTDeserialize_publish(&dup, &qos, &retained, &packetid, topicName, payload, payloadlen, srcData, srcLen)) + { + return TRUE; + } + else + { + return FALSE; + } +} +/************************************************************************** +** 功能 @brief : mqtt接收数据处理 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static qbool FUNCTION_ATTR_ROM quos_mqttRecv(void *chlFd, const void *peer, quint32_t peerSize, Quos_socketRecvDataNode_t *recvData) +{ + UNUSED(peer); + UNUSED(peerSize); + Quos_socketChlInfoNode_t *chlNode = (Quos_socketChlInfoNode_t *)chlFd; + mqttSock_t *mqttSock = (mqttSock_t *)chlNode->param; + if (NULL == recvData) + { + Quos_swTimerDelete(mqttSock->pingTimer); + mqttSock->eventCB(chlFd, QUOS_MQTT_ERR_NET); + return FALSE; + } + Quos_logHexDump(LSDK_MQTT, LL_DUMP, "m2m recv", recvData->Buf, recvData->bufLen); + + switch (recvData->Buf[0] >> 4) + { + case PUBLISH: + { + int qos; + quint8_t dup = 0; + quint16_t packetid = 0; + quint8_t retained; + MQTTString topicName; + quint8_t *payload; + int payloadlen; + if (MQTTDeserialize_publish(&dup, &qos, &retained, &packetid, &topicName, &payload, &payloadlen, recvData->Buf, recvData->bufLen)) + { + Quos_logPrintf(LSDK_MQTT, LL_DBG, "dup[%u] qos[%d] retained[%u] packetid[%u] topicName[%.*s] payload[%p] payloadlen[%d]", dup, qos, retained, packetid, topicName.lenstring.len, topicName.lenstring.data, payload, payloadlen); + if (0 == qos) + { + mqttSock->pubRecv(&topicName, payload, (quint32_t)payloadlen); + } + else if (1 == qos) + { + mqttSock->pubRecv(&topicName, payload, payloadlen); + quint16_t len = 4; + quint8_t *buf = HAL_MALLOC(len); + if (buf) + { + MQTTSerialize_ack(buf, len, PUBACK, 0, packetid); + Quos_socketTxDisorder(chlFd, NULL, buf, len); + } + } + else if (2 == qos) + { + if (mqttSock->qos2RecvId != packetid) + { + mqttSock->qos2RecvId = packetid; + mqttSock->pubRecv(&topicName, payload, payloadlen); + } + quint16_t len = 4; + quint8_t *buf = HAL_MALLOC(len); + if (buf) + { + MQTTSerialize_ack(buf, len, PUBREC, dup, packetid); + Quos_socketTxDisorder(chlFd, NULL, buf, len); + } + } + } + break; + } + case CONNACK: + { + Quos_socketTxAck(chlFd, NULL, 0, recvData); + break; + } + case PINGRESP: + Quos_swTimerTimeoutSet(mqttSock->pingTimer, mqttSock->keepAlive - (QUOS_MQTT_RESEND_TIME + 1) * QUOS_MQTT_PING_TIMEOUT); + Quos_swTimerRepeatSet(mqttSock->pingTimer, QUOS_MQTT_RESEND_TIME); + Quos_logPrintf(LSDK_MQTT, LL_INFO, "PINGRESP"); + break; + case SUBACK: + case PUBCOMP: + case PUBACK: + case UNSUBACK: + { + quint8_t type = 0, dup = 0; + quint16_t packetid = 0; + MQTTDeserialize_ack(&type, &dup, &packetid, recvData->Buf, recvData->bufLen); + Quos_socketTxAck(chlFd, NULL, packetid, recvData); + break; + } + case PUBREC: + { + quint16_t len = 4; + quint8_t *buf = HAL_MALLOC(len); + if (buf) + { + quint8_t type = 0, dup = 0; + quint16_t packetid = 0; + MQTTDeserialize_ack(&type, &dup, &packetid, recvData->Buf, recvData->bufLen); + MQTTSerialize_ack(buf, len, PUBREL, dup, packetid); + Quos_socketTxDisorder(chlFd, NULL, buf, len); + } + break; + } + case PUBREL: + { + quint16_t len = 4; + quint8_t *buf = HAL_MALLOC(len); + if (buf) + { + quint8_t type = 0, dup = 0; + quint16_t packetid = 0; + MQTTDeserialize_ack(&type, &dup, &packetid, recvData->Buf, recvData->bufLen); + MQTTSerialize_pubcomp(buf, len, packetid); + Quos_socketTxDisorder(chlFd, NULL, buf, len); + } + break; + } + default: + break; + } + return TRUE; +} +/************************************************************************** +** 功能 @brief : mqtt断开 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void FUNCTION_ATTR_ROM quos_mqttParamFree(void *param) +{ + mqttSock_t *mqttSock = (mqttSock_t *)param; + Quos_swTimerDelete(mqttSock->pingTimer); + HAL_FREE(mqttSock); +} +/************************************************************************** +** 功能 @brief : Mqtt connect应答结果 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void FUNCTION_ATTR_ROM quos_mqttConnectAck(void *chlFd, const void *sendData, const void *recvDataIn) +{ + UNUSED(sendData); + Quos_socketRecvDataNode_t *recvData = (Quos_socketRecvDataNode_t *)recvDataIn; + quint8_t sessionPresent, connack_rc = 0; + Quos_socketChlInfoNode_t *chlNode = (Quos_socketChlInfoNode_t *)chlFd; + mqttSock_t *mqttSock = (mqttSock_t *)chlNode->param; + if (NULL == recvData) + { + mqttSock->eventCB(chlFd, QUOS_MQTT_ERR_NET); + Quos_socketChannelDel((void *)chlNode); + } + else if (1 != MQTTDeserialize_connack(&sessionPresent, &connack_rc, (quint8_t *)recvData->Buf, recvData->bufLen)) + { + mqttSock->eventCB(chlFd, QUOS_MQTT_ERR_CONNECT); + Quos_socketChannelDel(chlFd); + } + else if (QUOS_MQTT_CONNECTION_ACCEPTED != connack_rc) + { + mqttSock->eventCB(chlFd, (qint32_t)connack_rc); + Quos_socketChannelDel(chlFd); + } + else if (FALSE == Quos_swTimerStart(&mqttSock->pingTimer, "MQTT ping", (mqttSock->keepAlive - (QUOS_MQTT_RESEND_TIME + 1) * QUOS_MQTT_PING_TIMEOUT) / 2, QUOS_MQTT_RESEND_TIME, quos_mqttPing, chlFd)) + { + mqttSock->eventCB(chlFd, QUOS_MQTT_ERR_INSIDE); + Quos_socketChannelDel(chlFd); + } + else + { + mqttSock->eventCB(chlFd, QUOS_MQTT_OK_CONNECT); + } +} +/************************************************************************** +** 功能 @brief : Mqtt connect&subscribe&ping应答结果 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void FUNCTION_ATTR_ROM quos_mqttSubcribeAck(void *chlFd, const void *sendData, const void *recvDataIn) +{ + Quos_socketRecvDataNode_t *recvData = (Quos_socketRecvDataNode_t *)recvDataIn; + quint16_t packetid; + int count, grantedQoSs[100]; + Quos_socketChlInfoNode_t *chlNode = (Quos_socketChlInfoNode_t *)chlFd; + mqttSock_t *mqttSock = (mqttSock_t *)chlNode->param; + UNUSED(sendData); + if (NULL == recvData || + 1 != MQTTDeserialize_suback(&packetid, sizeof(grantedQoSs) / sizeof(grantedQoSs[0]), &count, grantedQoSs, recvData->Buf, recvData->bufLen)) + { + Quos_swTimerDelete(mqttSock->pingTimer); + mqttSock->eventCB(chlFd, QUOS_MQTT_ERR_SUBSCRI); + Quos_socketChannelDel(NULL == recvData ? (void *)chlNode : chlFd); + } + else + { + mqttSock->eventCB(chlFd, QUOS_MQTT_OK_SUBSCRIBE); + } +} +/************************************************************************** +** 功能 @brief : MQTT 心跳 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void FUNCTION_ATTR_ROM quos_mqttPing(void *swTimer) +{ + Quos_socketChlInfoNode_t *chlNode = (Quos_socketChlInfoNode_t *)Quos_swTimerParmGet(swTimer); + if (0 == Quos_swTimerRepeatGet(swTimer) && Quos_socketCheckChlFd(chlNode) ) + { + mqttSock_t *mqttSock = (mqttSock_t *)chlNode->param; + mqttSock->eventCB(chlNode, QUOS_MQTT_ERR_PING); + Quos_socketChannelDel((void *)chlNode); + return; + } + quint16_t len = 2; + quint8_t *buf = HAL_MALLOC(len); + Quos_swTimerTimeoutSet(swTimer, QUOS_MQTT_PING_TIMEOUT); + if (NULL == buf) + { + return; + } + Quos_logPrintf(LSDK_MQTT, LL_INFO, "ping"); + MQTTSerialize_pingreq(buf, len); + Quos_socketTxDisorder(chlNode, NULL, buf, len); +} +/************************************************************************** +** 功能 @brief : Mqtt socket connet结果 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static qbool FUNCTION_ATTR_ROM quos_mqttSockConnctCB(void *chlFd, qbool result) +{ + Quos_logPrintf(LSDK_MQTT, LL_DBG, "chlFd[%p] result:%s", chlFd, _BOOL2STR(result)); + if (result == FALSE && NULL != chlFd) + { + Quos_socketChlInfoNode_t *chlNode = (Quos_socketChlInfoNode_t *)chlFd; + ((mqttSock_t *)(chlNode->param))->eventCB(chlFd, QUOS_MQTT_ERR_NET); + } + return TRUE; +} + +/************************************************************************** +** 功能 @brief : Mqtt服务初始化 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Quos_mqttInit(void **chlFdPoint, + const char *url, + const char *clientID, + const char *username, + const char *password, + quint16_t keepAlive, + quint8_t topicCount, + char *topicString[], + const int *requestedQoSs, + MqttEventCb_f eventCB, + MqttpublishRecv_f pubRecv) +{ + urlAnalyze_t urlA; + if (NULL == url || NULL == clientID || NULL == password || (0 != topicCount && (NULL == topicString || NULL == requestedQoSs)) || NULL == eventCB || NULL == pubRecv) + { + Quos_logPrintf(LSDK_MQTT, LL_ERR, "url[%p] clientID[%s] username[%s] password[%s] topicCount[%u] topic[%p] requestedQoSs[%p] eventCB[%p] pubRecv[%p]", + url, clientID, username, password, topicCount, topicString, requestedQoSs, eventCB, pubRecv); + return FALSE; + } + if (FALSE == (Quos_urlAnalyze(url, &urlA))) + { + Quos_logPrintf(LSDK_MQTT, LL_ERR, "url analyze fail"); + return FALSE; + } + urlA.port = urlA.port ? urlA.port : (urlA.isSecure ? 8883 : 1883); + + mqttSock_t *mqttSock = HAL_MALLOC(sizeof(mqttSock_t)); + if (NULL == mqttSock) + { + Quos_logPrintf(LSDK_MQTT, LL_ERR, "mcf mqttSock"); + return FALSE; + } + HAL_MEMSET(mqttSock, 0, sizeof(mqttSock_t)); + + Quos_socketChlInfoNode_t chlInfo; + HAL_MEMSET(&chlInfo, 0, sizeof(Quos_socketChlInfoNode_t)); + if (urlA.isSecure) + { +#if (SDK_ENABLE_TLS == 1) + chlInfo.sockFd = Qhal_tcpSslClientInit(&chlInfo.type, urlA.hostname, urlA.port, &chlInfo.conn.timeout); +#else + chlInfo.sockFd = SOCKET_FD_INVALID; +#endif + } + else + { + chlInfo.sockFd = Qhal_tcpClientInit(&chlInfo.type, urlA.hostname, urlA.port, &chlInfo.conn.timeout); + } + if (chlInfo.conn.timeout) + { + chlInfo.conn.notify = quos_mqttSockConnctCB; + } + if (SOCKET_FD_INVALID == chlInfo.sockFd) + { + Quos_logPrintf(LSDK_MQTT, LL_ERR, "mqtt conn fail:%s[%u]", urlA.hostname, urlA.port); + HAL_FREE(mqttSock); + return FALSE; + } + + chlInfo.io.send = Qhal_sockWrite; + chlInfo.send.txCnt = QUOS_MQTT_RESEND_TIME; + chlInfo.send.timeout = QUOS_MQTT_SEND_TIMEOUT; + chlInfo.recvDataFunc = quos_mqttRecv; + chlInfo.unformFunc = quos_mqttUnform; + chlInfo.io.close = Qhal_sockClose; + chlInfo.paramFree = quos_mqttParamFree; + chlInfo.param = mqttSock; + + if (keepAlive <= (QUOS_MQTT_RESEND_TIME + 1) * QUOS_MQTT_PING_TIMEOUT / SWT_ONE_SECOND) + { + keepAlive = (QUOS_MQTT_RESEND_TIME + 1) * QUOS_MQTT_PING_TIMEOUT / SWT_ONE_SECOND + 1; + } + mqttSock->keepAlive = (quint32_t)keepAlive * SWT_ONE_SECOND; + mqttSock->eventCB = eventCB; + mqttSock->pubRecv = pubRecv; + + void *chlFd = Quos_socketChannelAdd(chlFdPoint, chlInfo); + if (NULL == chlFd) + { + Qhal_sockClose(chlInfo.sockFd, chlInfo.type); + HAL_FREE(mqttSock); + Quos_logPrintf(LSDK_MQTT, LL_ERR, "add socket Channel fail"); + return FALSE; + } + + MQTTPacket_connectData mqttConnData = MQTTPacket_connectData_initializer; + mqttConnData.keepAliveInterval = keepAlive; + mqttConnData.clientID.cstring = (char *)clientID; + mqttConnData.username.cstring = (char *)username; + mqttConnData.password.cstring = (char *)password; + + quint16_t len = MQTTPacket_len(MQTTSerialize_connectLength(&mqttConnData)); + quint8_t *pkg = HAL_MALLOC(len); + if (NULL == pkg) + { + Quos_socketChannelDel(chlFd); + return FALSE; + } + len = MQTTSerialize_connect(pkg, len, &mqttConnData); + if (FALSE == Quos_socketTx(chlFd, NULL, 0, QUOS_MQTT_CONNECT_TIMEOUT, NULL, quos_mqttConnectAck, 0, pkg, len, NULL)) + { + Quos_socketChannelDel(chlFd); + return FALSE; + } + if (topicCount > 0) + { + MQTTString *topic = HAL_MALLOC(sizeof(MQTTString) * topicCount); + if (NULL == topic) + { + Quos_socketChannelDel(chlFd); + return FALSE; + } + HAL_MEMSET(topic, 0, sizeof(MQTTString) * topicCount); + quint8_t i; + for (i = 0; i < topicCount; i++) + { + topic[i].cstring = topicString[i]; + } + + len = MQTTPacket_len(MQTTSerialize_subscribeLength(topicCount, topic)); + pkg = HAL_MALLOC(len); + if (NULL == pkg) + { + HAL_FREE(topic); + Quos_socketChannelDel(chlFd); + return FALSE; + } + len = MQTTSerialize_subscribe(pkg, len, 0, ++mqttSock->pkgId, topicCount, topic, (int *)requestedQoSs); + HAL_FREE(topic); + if (FALSE == Quos_socketTx(chlFd, NULL, 0, QUOS_MQTT_CONNECT_TIMEOUT, NULL, quos_mqttSubcribeAck, mqttSock->pkgId, pkg, len, NULL)) + { + Quos_logPrintf(LSDK_MQTT, LL_ERR, "mcf subscribe pkg"); + Quos_socketChannelDel(chlFd); + return FALSE; + } + } + Quos_logPrintf(LSDK_MQTT, LL_DBG, "mqtt init ok"); + return TRUE; +} +/************************************************************************** +** 功能 @brief : 关闭MQTT服务 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Quos_mqttDeinit(void *chlFd) +{ + Quos_socketChannelDel(chlFd); +} +#endif \ No newline at end of file diff --git a/kernel/quos_mqtt.h b/kernel/quos_mqtt.h index 9a08d120890efc46982d6637f53fcca07bb5defe..b7146374d5c964cc537475c7d2319e523cbaf4ad 100644 --- a/kernel/quos_mqtt.h +++ b/kernel/quos_mqtt.h @@ -1,51 +1,52 @@ -#ifndef __QUOS_MQTT_H__ -#define __QUOS_MQTT_H__ -#include "quos_config.h" -#if (SDK_ENABLE_MQTT == 1) -#include "quos_socket.h" -#include "MQTTPacket.h" - -enum -{ - QUOS_MQTT_ERR_INSIDE = -5, - QUOS_MQTT_ERR_NET = -4, - QUOS_MQTT_ERR_PING = -3, - QUOS_MQTT_ERR_SUBSCRI = -2, - QUOS_MQTT_ERR_CONNECT = -1, - QUOS_MQTT_OK_CONNECT = 0, - QUOS_MQTT_OK_SUBSCRIBE = 100, -}; - -#define MQTT_ERR_STRING(X) \ - ( \ - (X == QUOS_MQTT_ERR_PING) ? "QUOS_MQTT_ERR_PING" : (X == QUOS_MQTT_ERR_SUBSCRI) ? "MQTT_ERR_SUBSCRI" \ - : (X == QUOS_MQTT_ERR_CONNECT) ? "MQTT_ERR_CONNECT" \ - : (X == QUOS_MQTT_ERR_NET) ? "MQTT_ERR_NET" \ - : (X == QUOS_MQTT_OK_CONNECT) ? "MQTT_OK_CONNECT" \ - : (X == QUOS_MQTT_OK_SUBSCRIBE) ? "MQTT_OK_SUBSCRIBE" \ - : (X == QUOS_MQTT_UNNACCEPTABLE_PROTOCOL) ? "MQTT_UNNACCEPTABLE_PROTOCOL" \ - : (X == QUOS_MQTT_CLIENTID_REJECTED) ? "MQTT_CLIENTID_REJECTED" \ - : (X == QUOS_MQTT_SERVER_UNAVAILABLE) ? "MQTT_SERVER_UNAVAILABLE" \ - : (X == QUOS_MQTT_BAD_USERNAME_OR_PASSWORD) ? "MQTT_BAD_USERNAME_OR_PASSWORD" \ - : (X == QUOS_MQTT_NOT_AUTHORIZED) ? "MQTT_NOT_AUTHORIZED" \ - : "Unknown") - -typedef void (*MqttEventCb_f)(void *chlFd, qint32_t event); -typedef void (*MqttpublishRecv_f)(MQTTString *topicName, quint8_t *payload, quint32_t payloadlen); - -qbool Quos_mqttInit(void **chlFdPoint, - const char *url, - const char *clientID, - const char *username, - const char *password, - quint16_t keepAlive, - quint8_t topicCount, - MQTTString *topic, - const int *requestedQoSs, - MqttEventCb_f eventCB, - MqttpublishRecv_f pubRecv); -void Quos_mqttDeinit(void *chlFd); -qint32_t Quos_mqttPublishSend(const void *chlFd, char *topicString, const void *param, qint32_t qos, void *buf, quint16_t bufLen, socketRecvNodeCb_f recvCB); -qbool Quos_mqttPublishReslover(quint8_t *srcData, quint32_t srcLen, MQTTString *topicName, quint8_t **payload, int *payloadlen); -#endif +#ifndef __QUOS_MQTT_H__ +#define __QUOS_MQTT_H__ +#include "quos_config.h" +#if (SDK_ENABLE_MQTT == 1) +#include "quos_socket.h" +#include "MQTTPacket.h" + +enum +{ + QUOS_MQTT_ERR_INSIDE = -5, + QUOS_MQTT_ERR_NET = -4, + QUOS_MQTT_ERR_PING = -3, + QUOS_MQTT_ERR_SUBSCRI = -2, + QUOS_MQTT_ERR_CONNECT = -1, + QUOS_MQTT_OK_CONNECT = 0, + QUOS_MQTT_OK_SUBSCRIBE = 100, +}; + +#define MQTT_ERR_STRING(X) \ + ( \ + (X == QUOS_MQTT_ERR_PING) ? "QUOS_MQTT_ERR_PING" : (X == QUOS_MQTT_ERR_SUBSCRI) ? "MQTT_ERR_SUBSCRI" \ + : (X == QUOS_MQTT_ERR_CONNECT) ? "MQTT_ERR_CONNECT" \ + : (X == QUOS_MQTT_ERR_NET) ? "MQTT_ERR_NET" \ + : (X == QUOS_MQTT_OK_CONNECT) ? "MQTT_OK_CONNECT" \ + : (X == QUOS_MQTT_OK_SUBSCRIBE) ? "MQTT_OK_SUBSCRIBE" \ + : (X == QUOS_MQTT_UNNACCEPTABLE_PROTOCOL) ? "MQTT_UNNACCEPTABLE_PROTOCOL" \ + : (X == QUOS_MQTT_CLIENTID_REJECTED) ? "MQTT_CLIENTID_REJECTED" \ + : (X == QUOS_MQTT_SERVER_UNAVAILABLE) ? "MQTT_SERVER_UNAVAILABLE" \ + : (X == QUOS_MQTT_BAD_USERNAME_OR_PASSWORD) ? "MQTT_BAD_USERNAME_OR_PASSWORD" \ + : (X == QUOS_MQTT_NOT_AUTHORIZED) ? "MQTT_NOT_AUTHORIZED" \ + : "Unknown") + +typedef void (*MqttEventCb_f)(void *chlFd, qint32_t event); +typedef void (*MqttpublishRecv_f)(MQTTString *topicName, quint8_t *payload, quint32_t payloadlen); + +qbool Quos_mqttInit(void **chlFdPoint, + const char *url, + const char *clientID, + const char *username, + const char *password, + quint16_t keepAlive, + quint8_t topicCount, + char *topicString[], + const int *requestedQoSs, + MqttEventCb_f eventCB, + MqttpublishRecv_f pubRecv); +void Quos_mqttDeinit(void *chlFd); + +qint32_t Quos_mqttPublish(const void *chlFd, char *topicString, const void *param, qint32_t qos, void *buf, quint16_t bufLen, socketRecvNodeCb_f recvCB, qbool isAck); +qbool Quos_mqttPublishReslover(quint8_t *srcData, quint32_t srcLen, MQTTString *topicName, quint8_t **payload, int *payloadlen); +#endif #endif \ No newline at end of file diff --git a/kernel/quos_net.c b/kernel/quos_net.c new file mode 100644 index 0000000000000000000000000000000000000000..05bced8a09b9e3b5b51ad7f609beb1218a1e924b --- /dev/null +++ b/kernel/quos_net.c @@ -0,0 +1,315 @@ +/************************************************************************* +** 创建人 @author : 吴健超 JCWu +** 版本 @version : V1.0.0 原始版本 +** 日期 @date : 2021-02-09 +** 功能 @brief : 网络管理 +** 硬件 @hardware: +** 其他 @other : +***************************************************************************/ +#include "quos_net.h" +#include "quos_swTimer.h" +#include "quos_event.h" +#include "quos_log.h" +#include "quos_SupportTool.h" +#include "quos_twll.h" +#include "Qhal_driver.h" + +typedef struct +{ + TWLLHead_T head; + char hostname[QUOS_DNS_HOSTNANE_MAX_LENGHT]; + quint8_t defaultIp[QUOS_IP_ADDR_MAX_LEN]; + quint8_t ip[DNS_IP_FROM_HOSTNAME_MAX_NUM][QUOS_IP_ADDR_MAX_LEN]; + qint8_t ip_num; +} Quos_netHostInfo_t; + +static TWLLHead_T *HostInfoHead = NULL; +static void *NetRetryTimer = NULL; +static qbool NetIsConnected = FALSE; +/************************************************************************** +** 功能 @brief : 尝试启动硬件网络连接 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void FUNCTION_ATTR_ROM quos_netRetry(void *swtimer) +{ + quint32_t timeout = 30 * SWT_ONE_SECOND; + Qhal_netOpen(&timeout); + Quos_logPrintf(LSDK_NET, LL_DBG, "net open wait:%dms", timeout); + if (NetIsConnected) + { + /* 在Qhal_netOpen函数执行过程中,网络已连接成功事件可能已经通过函数Quos_netIOStatusNotify已经将NetIsConnected设置为TRUE了,故此处需要判断NetIsConnected是否被置为TRUE */ + } + else if (0 == timeout) + { + if (Quos_eventPost(QUOS_SYSTEM_EVENT_NETWORK, (void *)QUOS_SEVENT_NET_CONNECTED)) + { + Quos_swTimerTimeoutSet(swtimer, SWT_SUSPEND); + NetIsConnected = TRUE; + Quos_logPrintf(LSDK_NET, LL_DBG, "post EVENT_NETCONNECTED ok"); + } + else + { + Quos_logPrintf(LSDK_NET, LL_ERR, "post EVENT_NETCONNECTED fail"); + } + } + else + { + if(0 != Quos_swTimerTimeoutGet(swtimer)) + { + Quos_eventPost(QUOS_SYSTEM_EVENT_NETWORK, (void *)QUOS_SEVENT_NET_CONNTIMEOUT); + } + Quos_swTimerTimeoutSet(swtimer, timeout); + } +} +/************************************************************************** +** 功能 @brief : 打开网络服务 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Quos_netOpen(void) +{ + Quos_logPrintf(LSDK_NET, LL_DBG, "NetRetryTimer:%p", NetRetryTimer); + if (NULL == NetRetryTimer || SWT_SUSPEND == Quos_swTimerTimeoutGet(NetRetryTimer)) + { + if (NetIsConnected && Quos_eventPost(QUOS_SYSTEM_EVENT_NETWORK, (void *)QUOS_SEVENT_NET_DISCONNECT)) + { + NetIsConnected = FALSE; + } + Quos_swTimerStart(&NetRetryTimer, "net", 0, 0, quos_netRetry, NULL); + } +} +/************************************************************************** +** 功能 @brief : 关闭网络服务 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Quos_netClose(void) +{ + if (NetRetryTimer && SWT_SUSPEND == Quos_swTimerTimeoutGet(NetRetryTimer)) + { + if (Quos_eventPost(QUOS_SYSTEM_EVENT_NETWORK, (void *)QUOS_SEVENT_NET_DISCONNECT)) + { + Quos_logPrintf(LSDK_NET, LL_DBG, "post EVENT_NETDISCONNECT ok"); + NetIsConnected = FALSE; + Quos_swTimerDelete(NetRetryTimer); + Qhal_netClose(); + } + else + { + Quos_logPrintf(LSDK_NET, LL_ERR, "post EVENT_NETDISCONNECT fail"); + } + } + else + { + Quos_swTimerDelete(NetRetryTimer); + } +} +/************************************************************************** +** 功能 @brief : 网络状态变化通知 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Quos_netIOStatusNotify(qbool isConn) +{ + Quos_logPrintf(LSDK_NET, LL_DBG, "isConn:%s", _BOOL2STR(isConn)); + if (NULL == NetRetryTimer) + { + return; + } + else if (SWT_SUSPEND == Quos_swTimerTimeoutGet(NetRetryTimer) && FALSE == isConn) + { + if (Quos_eventPost(QUOS_SYSTEM_EVENT_NETWORK, (void *)QUOS_SEVENT_NET_DISCONNECT)) + { + NetIsConnected = FALSE; + Quos_logPrintf(LSDK_NET, LL_INFO, "post EVENT_NETDISCONNECT ok"); + } + else + { + Quos_logPrintf(LSDK_NET, LL_ERR, "post EVENT_NETDISCONNECT fail"); + } + Quos_swTimerTimeoutSet(NetRetryTimer, 0); + } + else if (SWT_SUSPEND != Quos_swTimerTimeoutGet(NetRetryTimer) && TRUE == isConn) + { + if (Quos_eventPost(QUOS_SYSTEM_EVENT_NETWORK, (void *)QUOS_SEVENT_NET_CONNECTED)) + { + Quos_logPrintf(LSDK_NET, LL_DBG, "post EVENT_NETCONNECTED ok"); + NetIsConnected = TRUE; + Quos_swTimerTimeoutSet(NetRetryTimer, SWT_SUSPEND); + } + else + { + Quos_logPrintf(LSDK_NET, LL_ERR, "post EVENT_NETCONNECTED fail"); + } + } +} +/************************************************************************** +** 功能 @brief :根据hostname查找当前节点 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static Quos_netHostInfo_t *quos_hostnameNodeFind(const char *hostname) +{ + TWLLHead_T *temp, *next; + TWLIST_FOR_DATA(HostInfoHead, temp, next) + { + Quos_netHostInfo_t *node = __GET_STRUCT_BY_ELEMENT(temp, Quos_netHostInfo_t, head); + if (0 == HAL_STRCMP(node->hostname, hostname)) + { + Quos_logPrintf(LSDK_NET, LL_DBG, "[%s] node ok", hostname); + return node; + } + } + Quos_logPrintf(LSDK_NET, LL_ERR, "no [%s] node", hostname); + return NULL; +} +/************************************************************************** +** 功能 @brief : 删除域名相关信息管理节点 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void Quos_netHostnameDelete(const char *hostname) +{ + Quos_netHostInfo_t *node = quos_hostnameNodeFind(hostname); + if (node) + { + Quos_twllHeadDelete(&HostInfoHead, &node->head); + HAL_FREE(node); + Quos_logPrintf(LSDK_NET, LL_DBG, "[%s] node ok", hostname); + } +} +/************************************************************************** +** 功能 @brief : 增加域名相关信息 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +Quos_netHostInfo_t *Quos_hostnameNodeAdd(const char *hostname) +{ + Quos_netHostInfo_t *node = quos_hostnameNodeFind(hostname); + if (NULL == node && (node = HAL_MALLOC(sizeof(Quos_netHostInfo_t))) != NULL) + { + HAL_MEMSET(node, 0, sizeof(Quos_netHostInfo_t)); + Quos_twllHeadAdd(&HostInfoHead, &node->head); + HAL_SNPRINTF(node->hostname, sizeof(node->hostname), "%s", hostname); + Quos_logPrintf(LSDK_NET, LL_DBG, "[%s] node ok", hostname); + } + + return node; +} +/************************************************************************** +** 功能 @brief :添加域名信息管理节点 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void Quos_netHostnameSetDefault(const char *hostname, const char *ip) +{ + Quos_netHostInfo_t *node = Quos_hostnameNodeAdd(hostname); + if (node) + { + if (ip && HAL_STRLEN(ip)) + { + HAL_MEMCPY(node->defaultIp, ip, QUOS_IP_ADDR_MAX_LEN); + } + else + { + HAL_MEMSET(node->defaultIp, 0, QUOS_IP_ADDR_MAX_LEN); + } + Quos_logPrintf(LSDK_NET, LL_DBG, "[%s][%s] ok", hostname, ip); + } +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void Quos_netHostnameDnsEnable(const char *hostname) +{ + Quos_netHostInfo_t *node = Quos_hostnameNodeAdd(hostname); + if (node) + { + node->ip_num = HAL_STRLEN(node->defaultIp) ? -1 : 0; + Quos_logPrintf(LSDK_NET, LL_DBG, "[%s] %d ok", hostname, node->ip_num); + } + else + { + Quos_logPrintf(LSDK_NET, LL_ERR, "[%s] enable fail", hostname); + } +} + +/************************************************************************** +** 功能 @brief : 根据DNS获取ip值 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +quint8_t *Quos_netGetIpFromHostname(const char *hostname) +{ + Quos_netHostInfo_t *node = quos_hostnameNodeFind(hostname); + if (NULL == node || node->ip_num >= DNS_IP_FROM_HOSTNAME_MAX_NUM) + { + Quos_logPrintf(LSDK_NET, LL_ERR, "[%s] vaild", hostname); + return NULL; + } +#if 0 + //xjin.gao 20211206 adaptation//depot10/quecthing/quecthingSDK/2.9.0/ node->ip_num Adapt to the "char", Will not be -1 + if (-1 == node->ip_num) + { + node->ip_num = 0; + Quos_logPrintf(LSDK_NET, LL_DBG, "[%s] default ip[%s]", hostname, node->defaultIp); + return HAL_STRLEN(node->defaultIp) ? node->defaultIp : NULL; + } + else +#endif + if (0 == node->ip_num) + { + /* 使用域名进行DNS解析 */ + quint8_t *ipPtr[DNS_IP_FROM_HOSTNAME_MAX_NUM]; + for (/*NULL*/; node->ip_num < DNS_IP_FROM_HOSTNAME_MAX_NUM; node->ip_num++) + { + ipPtr[(quint8_t)node->ip_num] = node->ip[(quint8_t)node->ip_num]; + } + node->ip_num = (quint8_t)Qhal_dns2IPGet(hostname, ipPtr, node->ip_num); + Quos_logPrintf(LSDK_NET, LL_DBG, "[%s] do dns[%d]", hostname, node->ip_num); + while (node->ip_num--) + { + //xjin.gao 20211206 adaptation//depot10/quecthing/quecthingSDK/2.9.0/ node->ip_num Adapt to the "char", do not print this log + //Quos_logPrintf(LSDK_NET, LL_DBG, "[%s] [%d][%s]", hostname, node->ip_num, node->ip[node->ip_num]); + } + node->ip_num = 0; + } + return HAL_STRLEN(node->ip[(quint8_t)node->ip_num]) ? node->ip[(quint8_t)node->ip_num++] : NULL; +} +/************************************************************************** +** 功能 @brief : 底层连接成功后告知当前域名对应的有效ip序号 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void Quos_netHostnameValidIpNumSet(const char *hostname) +{ + Quos_netHostInfo_t *node = quos_hostnameNodeFind(hostname); + if (node && node->ip_num > 0) + { + HAL_MEMCPY(node->defaultIp, node->ip[(quint8_t)node->ip_num - 1], QUOS_IP_ADDR_MAX_LEN); + Quos_logPrintf(LSDK_NET, LL_DBG, "[%s] set [%d][%s] to default", hostname, node->ip_num - 1, node->defaultIp); + } +} +/************************************************************************** +** 功能 @brief : 根据域名获取有效ip +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool Quos_netHostnameValidIpGet(const char *hostname, char *ip) +{ + Quos_netHostInfo_t *node = quos_hostnameNodeFind(hostname); + + /* 没有找到域名对应的节点,或者当前域名没有发生过解析ip或IP没有变化,故不需要进行替换和保存 */ + if (NULL == node || 0 == HAL_STRLEN(node->defaultIp)) + { + return FALSE; + } + if (ip) + { + HAL_MEMCPY((quint8_t *)ip, node->defaultIp, QUOS_IP_ADDR_MAX_LEN); + } + return TRUE; +} diff --git a/kernel/quos_net.h b/kernel/quos_net.h index 97a91917ccef748a8c8a9a7c7bb32dd39ff54628..bb0997f1674ca33b1ba4e0c6f57e2bdc3ae6560a 100644 --- a/kernel/quos_net.h +++ b/kernel/quos_net.h @@ -1,7 +1,16 @@ -#ifndef __QUOS_NET_H__ -#define __QUOS_NET_H__ -#include "quos_config.h" -void Quos_netOpen(void); -void Quos_netClose(void); -void Quos_netIOStatusNotify(qbool result); +#ifndef __QUOS_NET_H__ +#define __QUOS_NET_H__ +#include "quos_config.h" +void Quos_netOpen(void); +void Quos_netClose(void); +void Quos_netIOStatusNotify(qbool result); + +#define DNS_IP_FROM_HOSTNAME_MAX_NUM (3) /* 从DNS中获取ip个数 */ + +void Quos_netHostnameSetDefault(const char *hostname, const char *ip); +quint8_t *Quos_netGetIpFromHostname(const char *hostname); +void Quos_netHostnameValidIpNumSet(const char *hostname); +qbool Quos_netHostnameValidIpGet(const char *hostname, char *ip); +void Quos_netHostnameDnsEnable(const char *hostname); +void Quos_netHostnameDelete(const char *hostname); #endif \ No newline at end of file diff --git a/kernel/quos_sha1.c b/kernel/quos_sha1.c new file mode 100644 index 0000000000000000000000000000000000000000..83048d691f88fd21654c975033fb8018fbb60a42 --- /dev/null +++ b/kernel/quos_sha1.c @@ -0,0 +1,216 @@ +#include "quos_sha1.h" +#include "Quos_kernel.h" + +#if (SDK_ENABLE_SHA1 == 1) +static const quint32_t K[] = { + 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6}; + +static const quint8_t sha1_padding[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +#define S(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) + +#define R(t) \ + (temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ W[(t - 14) & 0x0F] ^ W[t & 0x0F], (W[t & 0x0F] = S(temp, 1))) + +#define P(a, b, c, d, e, x, K) \ + do \ + { \ + e += S(a, 5) + F(b, c, d) + K + x; \ + b = S(b, 30); \ + } while (0) + +static void quos_sha1process(SHA1_ctx_t *ctx, const quint8_t data[64]) +{ + quint32_t temp, W[16]; + quint32_t A[5]; + quint32_t i; + for (i = 0; i < 5; i++) + { + A[i] = ctx->state[i]; + } + for (i = 0; i < 16; i++) + { + W[i] = _ARRAY0123_U32(data + 4 * i); + } + +#define F(x, y, z) (z ^ (x & (y ^ z))) + + for (i = 0; i < 16; i++) + { + P(A[0], A[1], A[2], A[3], A[4], W[i], K[i / 20]); + temp = A[4]; + A[4] = A[3]; + A[3] = A[2]; + A[2] = A[1]; + A[1] = A[0]; + A[0] = temp; + } + for (i = 16; i < 20; i++) + { + P(A[0], A[1], A[2], A[3], A[4], R(i), K[i / 20]); + temp = A[4]; + A[4] = A[3]; + A[3] = A[2]; + A[2] = A[1]; + A[1] = A[0]; + A[0] = temp; + } +#undef F + +#define F(x, y, z) (x ^ y ^ z) + + for (i = 20; i < 40; i++) + { + P(A[0], A[1], A[2], A[3], A[4], R(i), K[i / 20]); + temp = A[4]; + A[4] = A[3]; + A[3] = A[2]; + A[2] = A[1]; + A[1] = A[0]; + A[0] = temp; + } + +#undef F + +#define F(x, y, z) ((x & y) | (z & (x | y))) + + for (i = 40; i < 60; i++) + { + P(A[0], A[1], A[2], A[3], A[4], R(i), K[i / 20]); + temp = A[4]; + A[4] = A[3]; + A[3] = A[2]; + A[2] = A[1]; + A[1] = A[0]; + A[0] = temp; + } + +#undef F + +#define F(x, y, z) (x ^ y ^ z) + for (i = 60; i < 80; i++) + { + P(A[0], A[1], A[2], A[3], A[4], R(i), K[i / 20]); + temp = A[4]; + A[4] = A[3]; + A[3] = A[2]; + A[2] = A[1]; + A[1] = A[0]; + A[0] = temp; + } +#undef F + for (i = 0; i < 5; i++) + { + ctx->state[i] += A[i]; + } +} + +void Quos_sha1init(SHA1_ctx_t *ctx) +{ + HAL_MEMSET(ctx, 0, sizeof(SHA1_ctx_t)); + ctx->total[0] = 0; + ctx->total[1] = 0; + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; +} +void Quos_sha1update(SHA1_ctx_t *ctx, const quint8_t *input, quint32_t ilen) +{ + quint32_t fill; + quint32_t left; + + if (ilen == 0) + { + return; + } + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (quint32_t)ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if (ctx->total[0] < (quint32_t)ilen) + { + ctx->total[1]++; + } + + if (left && ilen >= fill) + { + HAL_MEMCPY((void *)(ctx->buffer + left), input, fill); + quos_sha1process(ctx, ctx->buffer); + input += fill; + ilen -= fill; + left = 0; + } + + while (ilen >= 64) + { + quos_sha1process(ctx, input); + input += 64; + ilen -= 64; + } + + if (ilen > 0) + { + HAL_MEMCPY((void *)(ctx->buffer + left), input, ilen); + } +} +void Quos_sha1key(SHA1_ctx_t *ctx, quint8_t *key, quint8_t key_len) +{ + + quint8_t k_ipad[QUOS_SHA1_KEY_IOPAD_SIZE]; + key_len = key_len > QUOS_SHA1_KEY_IOPAD_SIZE ? QUOS_SHA1_KEY_IOPAD_SIZE : key_len; + HAL_MEMSET(ctx->k_opad, 0, sizeof(ctx->k_opad)); + HAL_MEMCPY(ctx->k_opad, key, key_len); + HAL_MEMSET(k_ipad, 0, sizeof(k_ipad)); + HAL_MEMCPY(k_ipad, key, key_len); + quint8_t i = 0; + for (i = 0; i < QUOS_SHA1_KEY_IOPAD_SIZE; i++) + { + k_ipad[i] ^= 0x36; + ctx->k_opad[i] ^= 0x5c; + } + ctx->isHmac = TRUE; + Quos_sha1update(ctx, k_ipad, QUOS_SHA1_KEY_IOPAD_SIZE); +} +void Quos_sha1finish(SHA1_ctx_t *ctx, quint8_t output[QUOS_SHA1_DIGEST_LENGTH]) +{ + quint32_t last, padn; + quint32_t high, low; + quint8_t msglen[8]; + + high = (ctx->total[0] >> 29) | (ctx->total[1] << 3); + low = (ctx->total[0] << 3); + + _U32_ARRAY0123(high, msglen); + _U32_ARRAY0123(low, msglen + 4); + + last = ctx->total[0] & 0x3F; + padn = (last < 56) ? (56 - last) : (120 - last); + + Quos_sha1update(ctx, sha1_padding, padn); + Quos_sha1update(ctx, msglen, 8); + + _U32_ARRAY0123(ctx->state[0], output); + _U32_ARRAY0123(ctx->state[1], output + 4); + _U32_ARRAY0123(ctx->state[2], output + 8); + _U32_ARRAY0123(ctx->state[3], output + 12); + _U32_ARRAY0123(ctx->state[4], output + 16); + if (ctx->isHmac) + { + SHA1_ctx_t context; + Quos_sha1init(&context); /* init context for 2nd pass */ + Quos_sha1update(&context, ctx->k_opad, QUOS_SHA1_KEY_IOPAD_SIZE); /* start with outer pad */ + Quos_sha1update(&context, output, QUOS_SHA1_DIGEST_LENGTH); /* then results of 1st hash */ + Quos_sha1finish(&context, output); /* finish up 2nd pass */ + } +} + +#endif \ No newline at end of file diff --git a/kernel/quos_sha256.c b/kernel/quos_sha256.c new file mode 100644 index 0000000000000000000000000000000000000000..d9f9414ce842a3c3d7d95d1b3f37e095a8f4849a --- /dev/null +++ b/kernel/quos_sha256.c @@ -0,0 +1,258 @@ +#include "quos_sha256.h" +#include "Quos_kernel.h" +#if (SDK_ENABLE_SHA256 == 1) + +static const quint32_t K[] = { + 0x428A2F98, + 0x71374491, + 0xB5C0FBCF, + 0xE9B5DBA5, + 0x3956C25B, + 0x59F111F1, + 0x923F82A4, + 0xAB1C5ED5, + 0xD807AA98, + 0x12835B01, + 0x243185BE, + 0x550C7DC3, + 0x72BE5D74, + 0x80DEB1FE, + 0x9BDC06A7, + 0xC19BF174, + 0xE49B69C1, + 0xEFBE4786, + 0x0FC19DC6, + 0x240CA1CC, + 0x2DE92C6F, + 0x4A7484AA, + 0x5CB0A9DC, + 0x76F988DA, + 0x983E5152, + 0xA831C66D, + 0xB00327C8, + 0xBF597FC7, + 0xC6E00BF3, + 0xD5A79147, + 0x06CA6351, + 0x14292967, + 0x27B70A85, + 0x2E1B2138, + 0x4D2C6DFC, + 0x53380D13, + 0x650A7354, + 0x766A0ABB, + 0x81C2C92E, + 0x92722C85, + 0xA2BFE8A1, + 0xA81A664B, + 0xC24B8B70, + 0xC76C51A3, + 0xD192E819, + 0xD6990624, + 0xF40E3585, + 0x106AA070, + 0x19A4C116, + 0x1E376C08, + 0x2748774C, + 0x34B0BCB5, + 0x391C0CB3, + 0x4ED8AA4A, + 0x5B9CCA4F, + 0x682E6FF3, + 0x748F82EE, + 0x78A5636F, + 0x84C87814, + 0x8CC70208, + 0x90BEFFFA, + 0xA4506CEB, + 0xBEF9A3F7, + 0xC67178F2, +}; + +static const quint8_t sha256_padding[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +#define SHR(x, n) ((x & 0xFFFFFFFF) >> n) +#define ROTR(x, n) (SHR(x, n) | (x << (32 - n))) + +#define S0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3)) +#define S1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10)) + +#define S2(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) +#define S3(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) + +#define F0(x, y, z) ((x & y) | (z & (x | y))) +#define F1(x, y, z) (z ^ (x & (y ^ z))) + +#define R(t) W[t] = S1(W[t - 2]) + W[t - 7] + S0(W[t - 15]) + W[t - 16] + +#define P(a, b, c, d, e, f, g, h, x, K) \ + do \ + { \ + quint32_t temp = h + S3(e) + F1(e, f, g) + K + x; \ + d += temp; \ + h = temp + S2(a) + F0(a, b, c); \ + } while (0) + +static void quos_sha256process(SHA256_ctx_t *ctx, const quint8_t data[64]) +{ + quint32_t temp, W[64]; + quint32_t A[8]; + quint32_t i; + + for (i = 0; i < 8; i++) + { + A[i] = ctx->state[i]; + } + + for (i = 0; i < 64; i++) + { + if (i < 16) + { + W[i] = _ARRAY0123_U32(data + 4 * i); + } + else + { + R(i); + } + + P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i], K[i]); + + temp = A[7]; + A[7] = A[6]; + A[6] = A[5]; + A[5] = A[4]; + A[4] = A[3]; + A[3] = A[2]; + A[2] = A[1]; + A[1] = A[0]; + A[0] = temp; + } + for (i = 0; i < 8; i++) + { + ctx->state[i] += A[i]; + } +} + +void Quos_sha256init(SHA256_ctx_t *ctx) +{ + HAL_MEMSET(ctx, 0, sizeof(SHA256_ctx_t)); + ctx->total[0] = 0; + ctx->total[1] = 0; + ctx->state[0] = 0x6A09E667; + ctx->state[1] = 0xBB67AE85; + ctx->state[2] = 0x3C6EF372; + ctx->state[3] = 0xA54FF53A; + ctx->state[4] = 0x510E527F; + ctx->state[5] = 0x9B05688C; + ctx->state[6] = 0x1F83D9AB; + ctx->state[7] = 0x5BE0CD19; + ctx->is224 = FALSE; +} + +void Quos_sha256update(SHA256_ctx_t *ctx, const quint8_t *input, quint32_t ilen) +{ + quint32_t fill; + quint32_t left; + + if (ilen == 0) + { + return; + } + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (quint32_t)ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if (ctx->total[0] < (quint32_t)ilen) + { + ctx->total[1]++; + } + + if (left && ilen >= fill) + { + HAL_MEMCPY((void *)(ctx->buffer + left), input, fill); + quos_sha256process(ctx, ctx->buffer); + input += fill; + ilen -= fill; + left = 0; + } + + while (ilen >= 64) + { + quos_sha256process(ctx, input); + input += 64; + ilen -= 64; + } + + if (ilen > 0) + { + HAL_MEMCPY((void *)(ctx->buffer + left), input, ilen); + } +} + +void Quos_sha256key(SHA256_ctx_t *ctx, quint8_t *key, quint8_t key_len) +{ + quint8_t k_ipad[QUOS_SHA256_KEY_IOPAD_SIZE]; + key_len = key_len > QUOS_SHA256_KEY_IOPAD_SIZE ? QUOS_SHA256_KEY_IOPAD_SIZE : key_len; + HAL_MEMSET(ctx->k_opad, 0, sizeof(ctx->k_opad)); + HAL_MEMCPY(ctx->k_opad, key, key_len); + HAL_MEMSET(k_ipad, 0, sizeof(k_ipad)); + HAL_MEMCPY(k_ipad, key, key_len); + quint8_t i = 0; + for (i = 0; i < QUOS_SHA256_KEY_IOPAD_SIZE; i++) + { + k_ipad[i] ^= 0x36; + ctx->k_opad[i] ^= 0x5c; + } + ctx->isHmac = TRUE; + Quos_sha256update(ctx, k_ipad, QUOS_SHA256_KEY_IOPAD_SIZE); +} + +void Quos_sha256finish(SHA256_ctx_t *ctx, quint8_t output[QUOS_SHA256_DIGEST_LENGTH]) +{ + quint32_t last, padn; + quint32_t high, low; + quint8_t msglen[8]; + + high = (ctx->total[0] >> 29) | (ctx->total[1] << 3); + low = (ctx->total[0] << 3); + + _U32_ARRAY0123(high, msglen); + _U32_ARRAY0123(low, msglen + 4); + + last = ctx->total[0] & 0x3F; + padn = (last < 56) ? (56 - last) : (120 - last); + + Quos_sha256update(ctx, sha256_padding, padn); + Quos_sha256update(ctx, msglen, 8); + + _U32_ARRAY0123(ctx->state[0], output); + _U32_ARRAY0123(ctx->state[1], output + 4); + _U32_ARRAY0123(ctx->state[2], output + 8); + _U32_ARRAY0123(ctx->state[3], output + 12); + _U32_ARRAY0123(ctx->state[4], output + 16); + _U32_ARRAY0123(ctx->state[5], output + 20); + _U32_ARRAY0123(ctx->state[6], output + 24); + + if (FALSE == ctx->is224) + { + _U32_ARRAY0123(ctx->state[7], output + 28); + } + + if (ctx->isHmac) + { + SHA256_ctx_t context; + Quos_sha256init(&context); /* init context for 2nd pass */ + Quos_sha256update(&context, ctx->k_opad, QUOS_SHA256_KEY_IOPAD_SIZE); /* start with outer pad */ + Quos_sha256update(&context, output, QUOS_SHA256_DIGEST_LENGTH); /* then results of 1st hash */ + Quos_sha256finish(&context, output); /* finish up 2nd pass */ + } +} + +#endif \ No newline at end of file diff --git a/kernel/quos_signal.c b/kernel/quos_signal.c new file mode 100644 index 0000000000000000000000000000000000000000..a23ce00b29ec195ffc0d217b18d6e75b837c3a65 --- /dev/null +++ b/kernel/quos_signal.c @@ -0,0 +1,83 @@ +/************************************************************************* +** 源码未经检录,使用需谨慎 +** 创建人 @author : 吴健超 JCWu +** 版本 @version : V1.0.0 原始版本 +** 日期 @date : +** 功能 @brief : 信号量管理 +** 硬件 @hardware:任何ANSI-C平台 +** 其他 @other : +***************************************************************************/ +#include "quos_signal.h" +#include "Quos_kernel.h" + +#if (SDK_ENABLE_SIGNAL == 1) +typedef struct +{ + TWLLHead_T head; + SignalCB_f eventCB; + quint32_t argLen; + quint8_t arg[1]; +} SignalInfoNode_t; + +static TWLLHead_T *SignalList = NULL; +HAL_LOCK_DEF(static,lockId) + +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Quos_signalInit(void) +{ + HAL_LOCK_INIT(lockId); +} +/************************************************************************** +** 功能 @brief : 发起信号 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Quos_signalSet(void *arg, quint32_t len, SignalCB_f eventCB) +{ + if (NULL == eventCB) + { + return FALSE; + } + SignalInfoNode_t *node = HAL_MALLOC(__GET_POS_ELEMENT(SignalInfoNode_t, arg) + len); + if (NULL == node) + { + Quos_logPrintf(LSDK_SIG, LL_ERR, "signal node malloc fail"); + return FALSE; + } + node->eventCB = eventCB; + HAL_MEMCPY(node->arg, arg, len); + node->argLen = len; + HAL_LOCK(lockId); + Quos_twllHeadAdd(&SignalList, &node->head); + HAL_UNLOCK(lockId); + Quos_kernelResume(); + return TRUE; +} +/************************************************************************** +** 功能 @brief : 处理信号 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_RAM Quos_signalTask(void) +{ + if (NULL == SignalList) + { + Quos_logPrintf(LSDK_SIG, LL_DBG,"is empty"); + return FALSE; + } + HAL_LOCK(lockId); + SignalInfoNode_t *node = __GET_STRUCT_BY_ELEMENT(SignalList, SignalInfoNode_t, head); + Quos_twllHeadDelete(&SignalList, SignalList); + HAL_UNLOCK(lockId); + Quos_logHexDump(LSDK_SIG, LL_DUMP, "signal get", node->arg, node->argLen); + Quos_logPrintf(LSDK_SIG, LL_DBG, "exec cb[%p]",node->eventCB); + node->eventCB(node->arg, node->argLen); + Quos_logPrintf(LSDK_SIG, LL_DBG, "exec cb[%p] finish",node->eventCB); + HAL_FREE(node); + return TRUE; +} +#endif \ No newline at end of file diff --git a/kernel/quos_socket.c b/kernel/quos_socket.c new file mode 100644 index 0000000000000000000000000000000000000000..ae7fa9957aa8254ce7f67a75deda5b8c46274e2e --- /dev/null +++ b/kernel/quos_socket.c @@ -0,0 +1,792 @@ +/************************************************************************* +** 创建人 @author : 吴健超 JCWu +** 版本 @version : V1.0.0 原始版本 +** 日期 @date : +** 功能 @brief : 通信socket管理 +** 硬件 @hardware:任何ANSI-C平台 +** 其他 @other : +***************************************************************************/ +#include "quos_socket.h" +#include "Quos_kernel.h" +static TWLLHead_T *chlInfoListHead = NULL; +HAL_LOCK_DEF(static, lockId) +#ifndef SOCKET_SENDDATA_BYTESIZE_MAX +#define SOCKET_SENDDATA_BYTESIZE_MAX (50 * 1024) +#endif +static void *quos_socketGetChlFd(pointer_t sockFd, quint8_t type); +static qbool quos_socketCheckChlFd(const void *chlFd); +static quint32_t quos_socketSendDataByteSize(void *chlFd); +static qbool quos_socketChannelDel(void *chlFd); +/************************************************************************** +** 功能 @brief : socket通道初始化 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Quos_socketInit(void) +{ + HAL_LOCK_INIT(lockId); +} + +/************************************************************************** +** 功能 @brief : socket connect成功处理 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Quos_socketIOConnResult(pointer_t sockFd, quint8_t type, qbool result) +{ + HAL_LOCK(lockId); + Quos_socketChlInfoNode_t *node = (Quos_socketChlInfoNode_t *)quos_socketGetChlFd(sockFd, type); + if (node && node->valid) + { + Quos_swTimerDelete(node->conn.timer); + if (node->conn.notify) + { + HAL_UNLOCK(lockId); + node->conn.notify((void *)node, result); + HAL_LOCK(lockId); + } + if (FALSE == result) + { + quos_socketChannelDel((void *)node); + } + Quos_kernelResume(); + } + HAL_UNLOCK(lockId); +} +/************************************************************************** +** 功能 @brief : socket connect超时处理,超时删除掉channel +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void FUNCTION_ATTR_ROM quos_socketConnTimeout(void *swTimer) +{ + HAL_LOCK(lockId); + Quos_socketChlInfoNode_t *chlNode = (Quos_socketChlInfoNode_t *)Quos_swTimerParmGet(swTimer); + Quos_logPrintf(LSDK_SOCK, LL_ERR, "chlNode[%p] conn timeout", chlNode); + if (FALSE == quos_socketCheckChlFd(chlNode)) + { + HAL_UNLOCK(lockId); + return; + } + if (chlNode->valid) + { + if (chlNode->conn.notify) + { + HAL_UNLOCK(lockId); + chlNode->conn.notify((void *)chlNode, FALSE); + HAL_LOCK(lockId); + } + quos_socketChannelDel((void *)chlNode); + Quos_kernelResume(); + Quos_logPrintf(LSDK_SOCK, LL_INFO, "del sockChlInfo"); + } + HAL_UNLOCK(lockId); +} +/************************************************************************** +** 功能 @brief : socket通道增加 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM *Quos_socketChannelAdd(void **chlFdPoint, Quos_socketChlInfoNode_t chlInfo) +{ + Quos_logPrintf(LSDK_SOCK, LL_INFO, "sockFd[" PRINTF_FD "] type[%u] sendCnt[%u] sendTimeout[%u] io.send[%p] recvDataFunc[%p] unformFunc[%p] param:%p", + chlInfo.sockFd, chlInfo.type, chlInfo.send.txCnt, chlInfo.send.timeout, chlInfo.io.send, chlInfo.recvDataFunc, chlInfo.unformFunc, chlInfo.param); + + if (SOCKET_FD_INVALID == chlInfo.sockFd || 0 == chlInfo.send.txCnt || 0 == chlInfo.send.timeout) + { + Quos_logPrintf(LSDK_SOCK, LL_ERR, "arg is invalid sockFd:" PRINTF_FD " sendCnt:%u sendTimeout:%u cb:%p timeout:%u", + chlInfo.sockFd, chlInfo.send.txCnt, chlInfo.send.timeout, chlInfo.conn.notify, chlInfo.conn.timeout); + return NULL; + } + HAL_LOCK(lockId); + Quos_socketChlInfoNode_t *node = (Quos_socketChlInfoNode_t *)quos_socketGetChlFd(chlInfo.sockFd, chlInfo.type); + if (node) + { + Quos_logPrintf(LSDK_SOCK, LL_WARN, "find invalid fd in socket channel list"); + quos_socketChannelDel((void *)node); + Quos_kernelResume(); + } + HAL_UNLOCK(lockId); + + Quos_socketChlInfoNode_t *newChlInfo = HAL_MALLOC(sizeof(Quos_socketChlInfoNode_t)); + if (NULL == newChlInfo) + { + Quos_logPrintf(LSDK_SOCK, LL_ERR, "MALLOC newChlInfo fail"); + return NULL; + } + HAL_MEMCPY(newChlInfo, &chlInfo, sizeof(Quos_socketChlInfoNode_t)); + if (newChlInfo->conn.timeout) + { + if (FALSE == Quos_swTimerStart(&newChlInfo->conn.timer, "socket connect", newChlInfo->conn.timeout, 1, quos_socketConnTimeout, (void *)newChlInfo)) + { + Quos_logPrintf(LSDK_SOCK, LL_ERR, "conntime start fail"); + HAL_FREE(newChlInfo); + return NULL; + } + } + if (chlFdPoint) + { + *chlFdPoint = newChlInfo; + } + newChlInfo->self = chlFdPoint; + newChlInfo->valid = TRUE; + HAL_LOCK(lockId); + Quos_twllHeadAdd(&chlInfoListHead, &newChlInfo->head); + Quos_logPrintf(LSDK_SOCK, LL_INFO, "ok, node count:%u", Quos_twllHeadGetNodeCount(chlInfoListHead)); + HAL_UNLOCK(lockId); + Quos_kernelResume(); + return (void *)newChlInfo; +} +/************************************************************************** +** 功能 @brief : socket通道删除 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static qbool FUNCTION_ATTR_ROM quos_socketChannelDel(void *chlFd) +{ + Quos_logPrintf(LSDK_SOCK, LL_INFO, "chlFd[%p]", chlFd); + if (quos_socketCheckChlFd(chlFd)) + { + Quos_socketChlInfoNode_t *chlNode = (Quos_socketChlInfoNode_t *)chlFd; + if (chlNode->valid) + { + chlNode->valid = FALSE; + if (chlNode->self) + { + *chlNode->self = NULL; + chlNode->self = NULL; + } + Quos_swTimerDelete(chlNode->conn.timer); + Quos_kernelResume(); + return TRUE; + } + Quos_logPrintf(LSDK_SOCK, LL_DBG, "del chl and send node ok"); + } + return FALSE; +} +qbool FUNCTION_ATTR_ROM Quos_socketChannelDel(void *chlFd) +{ + HAL_LOCK(lockId); + qbool ret = quos_socketChannelDel(chlFd); + HAL_UNLOCK(lockId); + return ret; +} +/************************************************************************** +** 功能 @brief : socket通信 TASK +** 输入 @param : +** 输出 @retval: FALSE:任何通道无数据发送 +***************************************************************************/ +quint32_t FUNCTION_ATTR_ROM Quos_socketTask(void) +{ + quint32_t idleTime = SWT_SUSPEND; + HAL_LOCK(lockId); + TWLLHead_T *chlTemp, *chlNext; + TWLIST_FOR_DATA(chlInfoListHead, chlTemp, chlNext) + { + Quos_socketChlInfoNode_t *chlNode = __GET_STRUCT_BY_ELEMENT(chlTemp, Quos_socketChlInfoNode_t, head); + qint32_t interval = Quos_sysTickdiff(Quos_sysTickGet(), chlNode->send.beginTime, TRUE); + if (interval < 0) + { + interval = 0; + chlNode->send.beginTime = Quos_sysTickGet(); + } + if (FALSE == chlNode->valid) /*socket通道已被删除,则在此FREE内存*/ + { + Quos_logPrintf(LSDK_SOCK, LL_DBG, "chlNode[%p] memory free", chlNode); + Quos_twllHeadDelete(&chlInfoListHead, &chlNode->head); + if (chlNode->unformTemp.buf) + { + HAL_FREE(chlNode->unformTemp.buf); + } + TWLLHead_T *sendTemp, *sendNext; + TWLIST_FOR_DATA(chlNode->send.disorderList, sendTemp, sendNext) + { + Quos_socketSendDataNode_t *sendNode = __GET_STRUCT_BY_ELEMENT(sendTemp, Quos_socketSendDataNode_t, head); + Quos_twllHeadDelete(&chlNode->send.disorderList, &sendNode->head); + HAL_FREE(sendNode->Buf); + HAL_FREE(sendNode); + } + TWLIST_FOR_DATA(chlNode->send.orderList, sendTemp, sendNext) + { + Quos_socketSendDataNode_t *sendNode = __GET_STRUCT_BY_ELEMENT(sendTemp, Quos_socketSendDataNode_t, head); + Quos_twllHeadDelete(&chlNode->send.orderList, &sendNode->head); + HAL_FREE(sendNode->Buf); + HAL_FREE(sendNode); + } + if (chlNode->io.close) + { + (chlNode->io.close)(chlNode->sockFd, chlNode->type); + } + if (chlNode->paramFree && chlNode->param) + { + chlNode->paramFree(chlNode->param); + } + HAL_FREE(chlNode); + } + else if (chlNode->conn.timer) /* socket connecting中 */ + { + /* do no */ + } + else if ((quint32_t)interval < chlNode->send.sendInterVal) /*处在限速中 */ + { + Quos_logPrintf(LSDK_SOCK, LL_DBG, "send rate limited:%d/%u", interval, chlNode->send.sendInterVal); + if (idleTime > chlNode->send.sendInterVal - interval) + { + idleTime = chlNode->send.sendInterVal - interval; + } + } + else if (0 == chlNode->send.waitIoSendAck && (chlNode->send.disorderList || FALSE == chlNode->send.waitPkgAck)) + { + qbool iosendRet = TRUE; + qbool isSending = FALSE; + if (chlNode->send.disorderList) + { + Quos_socketSendDataNode_t *sendNode = __GET_STRUCT_BY_ELEMENT(chlNode->send.disorderList, Quos_socketSendDataNode_t, head); + iosendRet = (chlNode->io.send)(chlNode->sockFd, chlNode->type, sendNode->peer, sendNode->Buf, sendNode->bufLen, &isSending); + Quos_logPrintf(LSDK_SOCK, LL_DBG, "disorderList send,sendNode:%p iosendRet:%s isSending:%s", sendNode, _BOOL2STR(iosendRet), _BOOL2STR(isSending)); + chlNode->send.beginTime = Quos_sysTickGet(); + if (iosendRet) + { + if (FALSE == isSending) + { + Quos_twllHeadDelete(&chlNode->send.disorderList, chlNode->send.disorderList); + HAL_FREE(sendNode->Buf); + HAL_FREE(sendNode); + idleTime = 0; + } + else + { + chlNode->send.waitIoSendAck = 1; + if (idleTime > sendNode->sendTimeout) + { + idleTime = sendNode->sendTimeout; + } + } + } + else + { + idleTime = 0; + } + } + else if (chlNode->send.orderList && FALSE == chlNode->send.waitPkgAck) + { + Quos_socketSendDataNode_t *sendNode = __GET_STRUCT_BY_ELEMENT(chlNode->send.orderList, Quos_socketSendDataNode_t, head); + iosendRet = (chlNode->io.send)(chlNode->sockFd, chlNode->type, sendNode->peer, sendNode->Buf, sendNode->bufLen, &isSending); + Quos_logPrintf(LSDK_SOCK, LL_DBG, "orderList send,sendNode:%p iosendRet:%s isSending:%s", sendNode, _BOOL2STR(iosendRet), _BOOL2STR(isSending)); + chlNode->send.beginTime = Quos_sysTickGet(); + if (TRUE == iosendRet) + { + Quos_logPrintf(LSDK_SOCK, LL_DBG, "chlFd[%p] sendNode[%p] io send ok,isSending[%s] sendCnt:%u", chlNode, sendNode, _BOOL2STR(isSending), sendNode->sendCnt); + if (FALSE == isSending && sendNode->sendCB) + { + HAL_UNLOCK(lockId); + qbool sendCbRet = sendNode->sendCB((void *)chlNode, sendNode, TRUE); + HAL_LOCK(lockId); + if (sendCbRet) + { + if (sendNode == __GET_STRUCT_BY_ELEMENT(chlNode->send.orderList, Quos_socketSendDataNode_t, head)) + { + Quos_twllHeadDelete(&chlNode->send.orderList, chlNode->send.orderList); + HAL_FREE(sendNode->Buf); + HAL_FREE(sendNode); + } + continue; + } + } + + if (FALSE == isSending && 0 == sendNode->sendCnt) + { + Quos_twllHeadDelete(&chlNode->send.orderList, chlNode->send.orderList); + HAL_FREE(sendNode->Buf); + HAL_FREE(sendNode); + idleTime = 0; + } + else + { + if (TRUE == isSending) + { + chlNode->send.waitIoSendAck = 2; + Quos_logPrintf(LSDK_SOCK, LL_DBG, "chlFd[%p] sendNode[%p] need wait sendcb", chlNode, sendNode); + } + if (0 != sendNode->sendCnt) + { + chlNode->send.waitPkgAck = TRUE; + Quos_logPrintf(LSDK_SOCK, LL_DBG, "chlFd[%p] sendNode[%p] need wait pkg ack", chlNode, sendNode); + } + if (idleTime > sendNode->sendTimeout) + { + idleTime = sendNode->sendTimeout; + } + } + } + else + { + idleTime = 0; + } + } + if (FALSE == iosendRet) + { + Quos_logPrintf(LSDK_SOCK, LL_ERR, "chlFd[%p] io send fail", chlNode); + HAL_UNLOCK(lockId); + chlNode->recvDataFunc((void *)chlNode, NULL, 0, NULL); + HAL_LOCK(lockId); + quos_socketChannelDel((void *)chlNode); + } + } + else if (1 == chlNode->send.waitIoSendAck) + { + Quos_socketSendDataNode_t *sendNode = __GET_STRUCT_BY_ELEMENT(chlNode->send.disorderList, Quos_socketSendDataNode_t, head); + if (interval > (qint32_t)sendNode->sendTimeout) + { + Quos_twllHeadDelete(&chlNode->send.disorderList, chlNode->send.disorderList); + HAL_FREE(sendNode->Buf); + HAL_FREE(sendNode); + chlNode->send.waitIoSendAck = 0; + idleTime = 0; + } + } + else if (2 == chlNode->send.waitIoSendAck || TRUE == chlNode->send.waitPkgAck) + { + Quos_socketSendDataNode_t *sendNode = __GET_STRUCT_BY_ELEMENT(chlNode->send.orderList, Quos_socketSendDataNode_t, head); + qint32_t recvInter = Quos_sysTickdiff(Quos_sysTickGet(), chlNode->send.recvTime, TRUE); + if (interval > (qint32_t)sendNode->sendTimeout && recvInter >= (qint32_t)chlNode->send.timeout / 2) + { + chlNode->send.waitIoSendAck = 0; + chlNode->send.waitPkgAck = FALSE; + if (sendNode->sendCnt > 0) + { + sendNode->sendCnt--; + } + if (0 == sendNode->sendCnt) + { + if (sendNode->recvCB) + { + HAL_UNLOCK(lockId); + sendNode->recvCB((void *)chlNode, sendNode, NULL); + HAL_LOCK(lockId); + } + if (sendNode == __GET_STRUCT_BY_ELEMENT(chlNode->send.orderList, Quos_socketSendDataNode_t, head)) + { + Quos_twllHeadDelete(&chlNode->send.orderList, chlNode->send.orderList); + HAL_FREE(sendNode->Buf); + HAL_FREE(sendNode); + } + } + idleTime = 0; + } + else if ((quint32_t)interval < sendNode->sendTimeout) + { + idleTime = sendNode->sendTimeout - interval; + } + else + { + idleTime = chlNode->send.timeout / 2 - recvInter; + } + } + } + HAL_UNLOCK(lockId); + return idleTime; +} +/************************************************************************** +** 功能 @brief : socket添加发送数据到有序发送链表 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Quos_socketTx(const void *chlFd, void *peer, quint8_t sendCnt, quint32_t sendTimeout, socketsendNodeCb_f sendCB, socketRecvNodeCb_f recvCB, + quint32_t pkgId, quint8_t *buf, quint16_t bufLen, const void *param) +{ + qbool ret = FALSE; + Quos_logPrintf(LSDK_SOCK, LL_DBG, "chlFd[%p] sendCnt[%u] sendTimeout[%u] sendCB[%p] recvCB[%p] pkgId[%u] bufLen[%u]", chlFd, sendCnt, sendTimeout, sendCB, recvCB, pkgId, bufLen); + Quos_logHexDump(LSDK_SOCK, LL_DUMP, "send", buf, bufLen); + HAL_LOCK(lockId); + if (quos_socketSendDataByteSize(NULL) < SOCKET_SENDDATA_BYTESIZE_MAX && quos_socketCheckChlFd(chlFd)) + { + Quos_socketChlInfoNode_t *chlNode = (Quos_socketChlInfoNode_t *)chlFd; + Quos_socketSendDataNode_t *sendNode; + if (chlNode->valid && chlNode->io.send && (sendNode = HAL_MALLOC(sizeof(Quos_socketSendDataNode_t))) != NULL) + { + HAL_MEMSET(sendNode, 0, sizeof(Quos_socketSendDataNode_t)); + Quos_twllHeadAdd(&chlNode->send.orderList, &sendNode->head); + Quos_logPrintf(LSDK_SOCK, LL_DBG, "chlFd[%p] add sendNode[%p]", chlNode, sendNode); + sendNode->param = (void *)param; + + sendNode->sendCnt = (recvCB) ? ((sendCnt == 0) ? chlNode->send.txCnt : sendCnt) : 0; + sendNode->sendTimeout = sendTimeout ? sendTimeout : chlNode->send.timeout; + sendNode->sendCB = sendCB; + sendNode->recvCB = recvCB; + sendNode->pkgId = pkgId; + sendNode->peer = peer; + sendNode->Buf = buf; + sendNode->bufLen = bufLen; + Quos_kernelResume(); + ret = TRUE; + } + } + if (FALSE == ret && buf) + { + HAL_FREE(buf); + } + HAL_UNLOCK(lockId); + return ret; +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Quos_socketTxDisorder(const void *chlFd, void *peer, quint8_t *buf, quint16_t bufLen) +{ + qbool ret = FALSE; + HAL_LOCK(lockId); + Quos_logPrintf(LSDK_SOCK, LL_DBG, "chlFd[%p] bufLen[%u]", chlFd, bufLen); + Quos_logHexDump(LSDK_SOCK, LL_DUMP, "send", buf, bufLen); + if (quos_socketSendDataByteSize(NULL) < SOCKET_SENDDATA_BYTESIZE_MAX && quos_socketCheckChlFd(chlFd)) + { + Quos_socketChlInfoNode_t *chlNode = (Quos_socketChlInfoNode_t *)chlFd; + Quos_socketSendDataNode_t *sendNode; + if (chlNode->valid && chlNode->io.send && (sendNode = HAL_MALLOC(sizeof(Quos_socketSendDataNode_t))) != NULL) + { + HAL_MEMSET(sendNode, 0, sizeof(Quos_socketSendDataNode_t)); + Quos_twllHeadAdd(&chlNode->send.disorderList, &sendNode->head); + Quos_logPrintf(LSDK_SOCK, LL_DBG, "chlFd[%p] add sendNode[%p]", chlNode, sendNode); + sendNode->sendTimeout = chlNode->send.timeout; + sendNode->peer = peer; + sendNode->Buf = buf; + sendNode->bufLen = bufLen; + Quos_kernelResume(); + ret = TRUE; + } + } + if (FALSE == ret && buf) + { + HAL_FREE(buf); + } + HAL_UNLOCK(lockId); + return ret; +} +/************************************************************************** +** 功能 @brief : socket发送数据出去完成回调 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Quos_socketIOTxCb(pointer_t sockFd, quint8_t type) +{ + HAL_LOCK(lockId); + Quos_socketChlInfoNode_t *chlNode = (Quos_socketChlInfoNode_t *)quos_socketGetChlFd(sockFd, type); + if (chlNode && chlNode->valid) + { + if (1 == chlNode->send.waitIoSendAck && chlNode->send.disorderList) + { + Quos_socketSendDataNode_t *sendNode = __GET_STRUCT_BY_ELEMENT(chlNode->send.disorderList, Quos_socketSendDataNode_t, head); + Quos_twllHeadDelete(&chlNode->send.disorderList, chlNode->send.disorderList); + HAL_FREE(sendNode->Buf); + HAL_FREE(sendNode); + chlNode->send.waitIoSendAck = 0; + } + else if (2 == chlNode->send.waitIoSendAck && chlNode->send.orderList) + { + Quos_socketSendDataNode_t *sendNode = __GET_STRUCT_BY_ELEMENT(chlNode->send.orderList, Quos_socketSendDataNode_t, head); + qbool sendCbRet = FALSE; + if (sendNode->sendCB) + { + HAL_UNLOCK(lockId); + sendCbRet = sendNode->sendCB((void *)chlNode, sendNode, TRUE); + HAL_LOCK(lockId); + } + if (quos_socketCheckChlFd(chlNode)) + { + if ((sendCbRet || FALSE == chlNode->send.waitPkgAck) && sendNode == __GET_STRUCT_BY_ELEMENT(chlNode->send.orderList, Quos_socketSendDataNode_t, head)) + { + Quos_twllHeadDelete(&chlNode->send.orderList, chlNode->send.orderList); + HAL_FREE(sendNode->Buf); + HAL_FREE(sendNode); + } + chlNode->send.waitIoSendAck = 0; + } + } + else + { + chlNode->send.waitIoSendAck = 0; + } + Quos_kernelResume(); + } + HAL_UNLOCK(lockId); +} +/************************************************************************** +** 功能 @brief : socket通信数据收到发送应答 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Quos_socketTxAck(void *chlFd, const void *peer, quint32_t pkgId, const void *recvData) +{ + Quos_logPrintf(LSDK_SOCK, LL_DBG, "recv chlFd[%p] pkgId[%u]", chlFd, pkgId); + qbool ret = FALSE; + HAL_LOCK(lockId); + if (quos_socketCheckChlFd(chlFd)) + { + Quos_socketChlInfoNode_t *chlNode = (Quos_socketChlInfoNode_t *)chlFd; + if (chlNode->valid && chlNode->send.orderList && TRUE == chlNode->send.waitPkgAck) + { + Quos_socketSendDataNode_t *sendNode = __GET_STRUCT_BY_ELEMENT(chlNode->send.orderList, Quos_socketSendDataNode_t, head); + if (sendNode->pkgId == pkgId && sendNode->peer == peer) + { + Quos_logPrintf(LSDK_SOCK, LL_DBG, "pkgId is match send's"); + chlNode->send.waitIoSendAck = 0; + chlNode->send.waitPkgAck = FALSE; + Quos_twllHeadDelete(&chlNode->send.orderList, chlNode->send.orderList); + HAL_UNLOCK(lockId); + sendNode->recvCB((void *)chlNode, sendNode, recvData); + HAL_LOCK(lockId); + if (quos_socketCheckChlFd(chlNode)) + { + HAL_FREE(sendNode->Buf); + HAL_FREE(sendNode); + } + Quos_kernelResume(); + ret = TRUE; + } + } + } + HAL_UNLOCK(lockId); + return ret; +} +/************************************************************************** +** 功能 @brief : socket添加接收数据到接收链表 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Quos_socketIORx(pointer_t sockFd, quint8_t type, const void *peer, quint32_t peerSize, quint8_t *buf, quint32_t bufLen) +{ + HAL_LOCK(lockId); + Quos_logPrintf(LSDK_SOCK, LL_DBG, "sockFd[" PRINTF_FD "] bufLen[%u]", sockFd, bufLen); + Quos_logHexDump(LSDK_SOCK, LL_DUMP, "recv", buf, bufLen); + Quos_socketChlInfoNode_t *chlNode = (Quos_socketChlInfoNode_t *)quos_socketGetChlFd(sockFd, type); + if (chlNode && chlNode->valid) + { + chlNode->send.recvTime = Quos_sysTickGet(); + if (chlNode->recvDataFunc) + { + Quos_socketRecvDataNode_t newNode; + HAL_MEMSET(&newNode, 0, sizeof(Quos_socketRecvDataNode_t)); + if (0 == bufLen) + { + chlNode->io.close = NULL; /* no close repeat */ + HAL_UNLOCK(lockId); + chlNode->recvDataFunc((void *)chlNode, peer, peerSize, NULL); + HAL_LOCK(lockId); + quos_socketChannelDel((void *)chlNode); + Quos_kernelResume(); + } + else if (chlNode->unformFunc) + { + Quos_logPrintf(LSDK_SOCK, LL_DBG, "need to unform before"); + quint32_t dealLen = 0; + while (dealLen < bufLen && quos_socketCheckChlFd(chlNode)) + { + quint32_t offset = 0; + if (FALSE == chlNode->unformFunc(buf + dealLen, bufLen - dealLen, &offset, &chlNode->unformTemp)) + { + Quos_logPrintf(LSDK_SOCK, LL_DBG, "unform fail"); + } + else + { + Quos_logHexDump(LSDK_SOCK, LL_DUMP, "unform ok", chlNode->unformTemp.buf, chlNode->unformTemp.offset); + newNode.bufLen = chlNode->unformTemp.offset; + newNode.Buf = chlNode->unformTemp.buf; + chlNode->unformTemp.offset = 0; + HAL_UNLOCK(lockId); + chlNode->recvDataFunc((void *)chlNode, peer, peerSize, &newNode); + HAL_LOCK(lockId); + } + dealLen += offset; + } + } + else + { + Quos_logPrintf(LSDK_SOCK, LL_DBG, "recvDataFunc direct"); + newNode.bufLen = bufLen; + newNode.Buf = buf; + HAL_UNLOCK(lockId); + chlNode->recvDataFunc((void *)chlNode, peer, peerSize, &newNode); + HAL_LOCK(lockId); + } + } + } + HAL_UNLOCK(lockId); +} + +/************************************************************************** +** 功能 @brief : 获取socket类型 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Quos_socketGetSockFdType(void *chlFd, pointer_t *sockFd, quint8_t *type) +{ + qbool ret = FALSE; + HAL_LOCK(lockId); + if (quos_socketCheckChlFd(chlFd)) + { + Quos_socketChlInfoNode_t *chlNode = (Quos_socketChlInfoNode_t *)chlFd; + if (chlNode->valid) + { + if (sockFd) + { + *sockFd = chlNode->sockFd; + } + if (type) + { + *type = chlNode->type; + } + ret = TRUE; + } + } + HAL_UNLOCK(lockId); + return ret; +} +/************************************************************************** +** 功能 @brief : 获取指定节点 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void FUNCTION_ATTR_ROM *quos_socketGetChlFd(pointer_t sockFd, quint8_t type) +{ + TWLLHead_T *temp, *next; + TWLIST_FOR_DATA(chlInfoListHead, temp, next) + { + Quos_socketChlInfoNode_t *chlNode = __GET_STRUCT_BY_ELEMENT(temp, Quos_socketChlInfoNode_t, head); + if (chlNode->sockFd == sockFd && chlNode->type == type) + { + Quos_logPrintf(LSDK_SOCK, LL_DBG, "find chlFd[%p] ok", chlNode); + return chlNode; + } + } + return NULL; +} +void FUNCTION_ATTR_ROM *Quos_socketGetChlFd(pointer_t sockFd, quint8_t type) +{ + HAL_LOCK(lockId); + void *node = quos_socketGetChlFd(sockFd, type); + HAL_UNLOCK(lockId); + return node; +} +/************************************************************************** +** 功能 @brief : 获取指定类型和参数指针匹配的chlFd列表 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +quint32_t Quos_socketGetChlFdList(quint8_t type, const void *param, void *chlFd[], quint32_t maxSize) +{ + quint32_t count = 0; + HAL_LOCK(lockId); + TWLLHead_T *temp, *next; + TWLIST_FOR_DATA(chlInfoListHead, temp, next) + { + Quos_socketChlInfoNode_t *chlNode = __GET_STRUCT_BY_ELEMENT(temp, Quos_socketChlInfoNode_t, head); + if (chlNode->type == type && chlNode->param == param) + { + chlFd[count++] = chlNode; + if(count == maxSize) + { + break; + } + } + } + HAL_UNLOCK(lockId); + return count; +} +/************************************************************************** +** 功能 @brief : 判断chlFd是否存在 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static qbool FUNCTION_ATTR_ROM quos_socketCheckChlFd(const void *chlFd) +{ + qbool ret = FALSE; + TWLLHead_T *temp, *next; + TWLIST_FOR_DATA(chlInfoListHead, temp, next) + { + Quos_socketChlInfoNode_t *chlNode = __GET_STRUCT_BY_ELEMENT(temp, Quos_socketChlInfoNode_t, head); + if (chlNode == (const Quos_socketChlInfoNode_t *)chlFd) + { + ret = TRUE; + break; + } + } + Quos_logPrintf(LSDK_SOCK, LL_DBG, "find chlFd[%p] %s", chlFd, _BOOL2STR(ret)); + return ret; +} +qbool FUNCTION_ATTR_ROM Quos_socketCheckChlFd(const void *chlFd) +{ + HAL_LOCK(lockId); + qbool ret = quos_socketCheckChlFd(chlFd); + HAL_UNLOCK(lockId); + return ret; +} +/************************************************************************** +** 功能 @brief : socket通道链表获取 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +TWLLHead_T FUNCTION_ATTR_ROM *Quos_socketGetChlHead(void) +{ + return chlInfoListHead; +} +/************************************************************************** +** 功能 @brief : 变更socket接收处理回调函数 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Quos_socketInfoModity(void *chlFd, quint8_t sendCnt, quint32_t sendTimeout, socketRecvNotify_f recvDataFunc) +{ + HAL_LOCK(lockId); + qbool ret = quos_socketCheckChlFd(chlFd); + if (ret) + { + Quos_socketChlInfoNode_t *chlNode = (Quos_socketChlInfoNode_t *)chlFd; + chlNode->send.txCnt = sendCnt ? sendCnt : chlNode->send.txCnt; + chlNode->send.timeout = sendTimeout ? sendTimeout : chlNode->send.timeout; + chlNode->recvDataFunc = recvDataFunc ? recvDataFunc : chlNode->recvDataFunc; + Quos_kernelResume(); + } + HAL_UNLOCK(lockId); + return ret; +} +/************************************************************************** +** 功能 @brief : +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static quint32_t FUNCTION_ATTR_ROM quos_socketSendDataByteSize(void *chlFd) +{ + quint32_t byteSize = 0; + TWLLHead_T *temp, *next; + TWLIST_FOR_DATA(chlInfoListHead, temp, next) + { + Quos_socketChlInfoNode_t *chlNode = __GET_STRUCT_BY_ELEMENT(temp, Quos_socketChlInfoNode_t, head); + if (NULL == chlFd || chlNode == (Quos_socketChlInfoNode_t *)chlFd) + { + TWLLHead_T *sendTemp, *sendNext; + quint32_t nodeByteSize = 0; + TWLIST_FOR_DATA(chlNode->send.orderList, sendTemp, sendNext) + { + Quos_socketSendDataNode_t *sendNode = __GET_STRUCT_BY_ELEMENT(sendTemp, Quos_socketSendDataNode_t, head); + nodeByteSize += sendNode->bufLen; + } + TWLIST_FOR_DATA(chlNode->send.disorderList, sendTemp, sendNext) + { + Quos_socketSendDataNode_t *sendNode = __GET_STRUCT_BY_ELEMENT(sendTemp, Quos_socketSendDataNode_t, head); + nodeByteSize += sendNode->bufLen; + } + byteSize += nodeByteSize; + //Quos_logPrintf(LSDK_SOCK, LL_DBG, "chlFd[%p] byteSize=%u/%u", chlNode, nodeByteSize, byteSize); + } + } + return byteSize; +} +quint32_t FUNCTION_ATTR_ROM Quos_socketSendDataByteSize(void *chlFd) +{ + HAL_LOCK(lockId); + quint32_t size = quos_socketSendDataByteSize(chlFd); + HAL_UNLOCK(lockId); + return size; +} diff --git a/kernel/quos_socket.h b/kernel/quos_socket.h index 42b3497d7ab4dab8c3798e51e4eb4ac4c1623344..2cf512550c638ee570fc4cbfd297e382dbf8d875 100644 --- a/kernel/quos_socket.h +++ b/kernel/quos_socket.h @@ -1,95 +1,97 @@ -#ifndef __QUOS_SOCKET_H__ -#define __QUOS_SOCKET_H__ -#include "quos_config.h" -#include "quos_twll.h" -#include "quos_swTimer.h" -typedef struct -{ - quint16_t bufLen; - quint8_t *Buf; - void *peer; -} Quos_socketRecvDataNode_t; /* 接收包节点 */ - -typedef struct -{ - TWLLHead_T head; - quint8_t sendCnt; - quint32_t sendTimeout; - qbool (*sendCB)(void *chlFd, const void *sendData, qbool result); - void (*recvCB)(void *chlFd, const void *sendData, const Quos_socketRecvDataNode_t *recvData); /* 等待接收超时或成功 */ - void *param; - quint32_t pkgId; - quint16_t bufLen; - quint8_t *Buf; -} Quos_socketSendDataNode_t; /* 发送包节点 */ -typedef qbool (*socketsendNodeCb_f)(void *chlFd, const void *sendData, qbool result); -typedef void (*socketRecvNodeCb_f)(void *chlFd, const void *sendData, const Quos_socketRecvDataNode_t *recvData); - -typedef struct -{ - quint8_t *buf; - quint32_t offset; - quint32_t bufLen; -} Quos_socketTempData_t; - -typedef qbool (*socketUnform_f)(quint8_t *buf, quint32_t bufLen, quint32_t *offset, Quos_socketTempData_t *unformTemp); -typedef qbool (*socketRecvNotify_f)(void *chlFd, Quos_socketRecvDataNode_t *recvData); -typedef qbool (*socketConnNotify_f)(void *chlFd, qbool result); -typedef qbool (*socketSendIO_f)(pointer_t sockFd, quint8_t type, const void *peer, const quint8_t *buf, quint16_t bufLen, qbool *isSending); -typedef void (*socketCloseIO_f)(pointer_t sockFd, quint8_t type); -typedef void (*socketParamFree_f)(void *param); -typedef struct -{ - TWLLHead_T head; - pointer_t sockFd; - quint8_t type; - qbool valid; - void *param; - void **self; - socketRecvNotify_f recvDataFunc; - socketUnform_f unformFunc; - Quos_socketTempData_t unformTemp; - socketParamFree_f paramFree; - struct - { - socketSendIO_f send; - socketCloseIO_f close; - void *peer; - } io; /* 此IO类CB里面不允许调用Quos_socket类API,否则会引起死锁 */ - struct - { - socketConnNotify_f notify; - quint32_t timeout; - SWTimer_T *timer; - } conn; - struct - { - quint8_t txCnt; - quint32_t timeout; - quint32_t sendInterVal; /* 数据发送最小间隔,用于限速 */ - Systick_T beginTime; - Systick_T recvTime; - quint8_t waitIoSendAck; - qbool waitPkgAck; - TWLLHead_T *orderList; /* 有序发送列表 */ - TWLLHead_T *disorderList; /* 无序发送列表,必须是无需等待应答数据;有数据会优先于有序发送列表,即使有序发送列表还在发送中,由于不对此类型限制数量,尽量避免使用此类型 */ - } send; -} Quos_socketChlInfoNode_t; - -void Quos_socketInit(void); -void *Quos_socketChannelAdd(void **chlFdPoint, Quos_socketChlInfoNode_t chlInfo); -qbool Quos_socketChannelDel(void *chlFd); -void Quos_socketIOConnResult(pointer_t sockFd, quint8_t type, qbool result); -void Quos_socketIORx(pointer_t sockFd, quint8_t type, const void *peer, quint8_t *Buf, quint32_t bufLen); -void Quos_socketIOTxCb(pointer_t sockFd, quint8_t type); -qbool Quos_socketTx(const void *chlFd, quint8_t sendCnt, quint32_t sendTimeout, socketsendNodeCb_f sendCB, socketRecvNodeCb_f recvCB, - quint32_t pkgId, quint8_t *buf, quint16_t bufLen, const void *param); -qbool Quos_socketTxDisorder(const void *chlFd, quint8_t *buf, quint16_t bufLen); -qbool Quos_socketTxAck(void *chlFd, quint32_t pkgId, const void *recvData); -qbool Quos_socketGetSockFdType(void *chlFd, pointer_t *sockFd, quint8_t *type); -void *Quos_socketGetChlFd(pointer_t sockFd, quint8_t type); -TWLLHead_T *Quos_socketGetChlHead(void); -qbool Quos_socketInfoModity(void *chlFd, quint8_t sendCnt, quint32_t sendTimeout, socketRecvNotify_f recvDataFunc); -quint32_t Quos_socketSendDataByteSize(void *chlFd); -quint32_t Quos_socketTask(void); -#endif +#ifndef __QUOS_SOCKET_H__ +#define __QUOS_SOCKET_H__ +#include "quos_config.h" +#include "quos_twll.h" +#include "quos_swTimer.h" +typedef struct +{ + quint16_t bufLen; + quint8_t *Buf; +} Quos_socketRecvDataNode_t; /* 接收包节点 */ + +typedef qbool (*socketsendNodeCb_f)(void *chlFd, const void *sendData, qbool result); +typedef void (*socketRecvNodeCb_f)(void *chlFd, const void *sendData, const void *recvData); +typedef struct +{ + TWLLHead_T head; + quint8_t sendCnt; + quint16_t bufLen; + quint32_t sendTimeout; + quint32_t pkgId; + quint8_t *Buf; + void *param; + void *peer; + socketsendNodeCb_f sendCB; + socketRecvNodeCb_f recvCB; /* 等待接收超时或成功 */ +} Quos_socketSendDataNode_t; /* 发送包节点 */ + +typedef struct +{ + quint8_t temp; + quint8_t *buf; + quint32_t offset; + quint32_t bufLen; +} Quos_socketTempData_t; + +typedef qbool (*socketUnform_f)(const quint8_t *buf, quint32_t bufLen, quint32_t *offset, Quos_socketTempData_t *unformTemp); +typedef qbool (*socketRecvNotify_f)(void *chlFd, const void *peer, quint32_t peerSize, Quos_socketRecvDataNode_t *recvData); +typedef qbool (*socketConnNotify_f)(void *chlFd, qbool result); +typedef qbool (*socketSendIO_f)(pointer_t sockFd, quint8_t type, const void *peer, const quint8_t *buf, quint16_t bufLen, qbool *isSending); +typedef void (*socketCloseIO_f)(pointer_t sockFd, quint8_t type); +typedef void (*socketParamFree_f)(void *param); +typedef struct +{ + TWLLHead_T head; + pointer_t sockFd; + quint8_t type; + qbool valid; + void *param; + void **self; + socketRecvNotify_f recvDataFunc; + socketUnform_f unformFunc; /* 此回调API内不允许调用Quos_socket类API,否则会引起死锁 */ + Quos_socketTempData_t unformTemp; + socketParamFree_f paramFree; + struct + { + socketSendIO_f send; + socketCloseIO_f close; + } io; /* 此IO类CB里面不允许调用Quos_socket类API,否则会引起死锁 */ + struct + { + socketConnNotify_f notify; + quint32_t timeout; + void *timer; + } conn; + struct + { + quint8_t txCnt; + quint8_t waitIoSendAck; + qbool waitPkgAck; + quint32_t timeout; + quint32_t sendInterVal; /* 数据发送最小间隔,用于限速 */ + Systick_T beginTime; + Systick_T recvTime; + TWLLHead_T *orderList; /* 有序发送列表 */ + TWLLHead_T *disorderList; /* 无序发送列表,必须是无需等待应答数据;有数据会优先于有序发送列表,即使有序发送列表还在发送中 */ + } send; +} Quos_socketChlInfoNode_t; + +void Quos_socketInit(void); +void *Quos_socketChannelAdd(void **chlFdPoint, Quos_socketChlInfoNode_t chlInfo); +qbool Quos_socketChannelDel(void *chlFd); +void Quos_socketIOConnResult(pointer_t sockFd, quint8_t type, qbool result); +void Quos_socketIORx(pointer_t sockFd, quint8_t type, const void *peer, quint32_t peerSize, quint8_t *Buf, quint32_t bufLen); +void Quos_socketIOTxCb(pointer_t sockFd, quint8_t type); +qbool Quos_socketTx(const void *chlFd, void *peer, quint8_t sendCnt, quint32_t sendTimeout, socketsendNodeCb_f sendCB, socketRecvNodeCb_f recvCB, + quint32_t pkgId, quint8_t *buf, quint16_t bufLen, const void *param); +qbool Quos_socketTxDisorder(const void *chlFd, void *peer, quint8_t *buf, quint16_t bufLen); +qbool Quos_socketTxAck(void *chlFd, const void *peer, quint32_t pkgId, const void *recvData); +qbool Quos_socketGetSockFdType(void *chlFd, pointer_t *sockFd, quint8_t *type); +void *Quos_socketGetChlFd(pointer_t sockFd, quint8_t type); +quint32_t Quos_socketGetChlFdList(quint8_t type, const void *param, void *chlFd[], quint32_t maxSize); +qbool Quos_socketCheckChlFd(const void *chlFd); +TWLLHead_T *Quos_socketGetChlHead(void); +qbool Quos_socketInfoModity(void *chlFd, quint8_t sendCnt, quint32_t sendTimeout, socketRecvNotify_f recvDataFunc); +quint32_t Quos_socketSendDataByteSize(void *chlFd); +quint32_t Quos_socketTask(void); +#endif diff --git a/kernel/quos_swTimer.c b/kernel/quos_swTimer.c new file mode 100644 index 0000000000000000000000000000000000000000..550b725309142ba07c3eb1f2b9e24ada0c1c7517 --- /dev/null +++ b/kernel/quos_swTimer.c @@ -0,0 +1,351 @@ +/************************************************************************* +** 创建人 @author : 吴健超 JCWu +** 版本 @version : V1.0.0 原始版本 +** 日期 @date : +** 功能 @brief : 软件定时器 +** 硬件 @hardware:任何ANSI-C平台 +** 其他 @other : +***************************************************************************/ +#include "quos_swTimer.h" +#include "Quos_kernel.h" + +#if (SDK_ENABLE_TIMER == 1) + +typedef struct +{ + TWLLHead_T head; + char *name; + Systick_T endTime; + quint32_t timeout; /* 定时时长,单位ms */ + quint32_t repeat; /* 重复次数 */ + void *parm; + void **self; + void (*timeoutCb)(void *swTimer); +} SWTimer_T; + +#define SWT_FOREVER ((quint32_t)-1) +static TWLLHead_T *SWTimerHead = NULL; +HAL_LOCK_DEF(static, lockId) +/************************************************************************** +** 功能 @brief : 打印定时器 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static void FUNCTION_ATTR_ROM quos_swTimerPrintf(void) +{ + Systick_T now = Quos_sysTickGet(); + TWLLHead_T *temp, *next; + Quos_logPrintf(LSDK_TIMER, LL_INFO, "**list pointer*********endTime*****timeout**repeat*******timerCB***********param****name******(" TIME_SEC2UTC ":%03d)***", TIME_SEC2UTC_(now.sec), now.ms); + TWLIST_FOR_DATA(SWTimerHead, temp, next) + { + SWTimer_T *timer = __GET_STRUCT_BY_ELEMENT(temp, SWTimer_T, head); + Quos_logPrintf(LSDK_TIMER, LL_INFO, "%-16p " TIME_SEC2UTC ":%03d %8d %6d %16p %16p %s", timer, TIME_SEC2UTC_(timer->endTime.sec), timer->endTime.ms, timer->timeout, timer->repeat, timer->timeoutCb, timer->parm, timer->name); + } +} +/************************************************************************** +** 功能 @brief : 初始化定时器 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Quos_swTimerInit(void) +{ + HAL_LOCK_INIT(lockId); +} +/************************************************************************** +** 功能 @brief : 启动一个定时器 +** 输入 @param : timeout 定时时长;repeat 定时次数,0为不断重复 +timeoutCb 定时时间到的回调处理函数,此函数需尽量简短, +timeoverCb 定是次数结束调用,为NULL时则无需通知 +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Quos_swTimerStart(void **swTimerP, char *name, quint32_t timeout, quint32_t repeat, const SWTimerCB timeoutCb, void *parm) +{ + SWTimer_T **swTimer = (SWTimer_T **)swTimerP; + Quos_logPrintf(LSDK_TIMER, LL_INFO, "swTimer[%p] *swTimer[%p] name[%s] timeout[%u] repeat[%u] timeoutCb[%p] parm[%p]", swTimer, *swTimer, name, timeout, repeat, timeoutCb, parm); + + if (NULL == timeoutCb && SWT_SUSPEND != timeout) + { + Quos_logPrintf(LSDK_TIMER, LL_ERR, "parm invaild"); + return FALSE; + } + + SWTimer_T *listNew = NULL; + HAL_LOCK(lockId); + if (swTimer && *swTimer) + { + TWLLHead_T *temp, *next; + TWLIST_FOR_DATA(SWTimerHead, temp, next) + { + SWTimer_T *timer = __GET_STRUCT_BY_ELEMENT(temp, SWTimer_T, head); + if (timer == *swTimer) + { + Quos_logPrintf(LSDK_TIMER, LL_DBG, "swTimer has in list"); + Quos_twllHeadDelete(&SWTimerHead, temp); + listNew = timer; + break; + } + } + } + if (NULL == listNew) + { + listNew = (SWTimer_T *)HAL_MALLOC(sizeof(SWTimer_T)); + if (NULL == listNew) + { + Quos_logPrintf(LSDK_TIMER, LL_ERR, "mcf newTimer"); + if (swTimer) + { + *swTimer = NULL; + } + HAL_UNLOCK(lockId); + return FALSE; + } + HAL_MEMSET(listNew, 0, sizeof(sizeof(SWTimer_T))); + listNew->self = (void **)swTimer; + if (swTimer) + { + *swTimer = (void *)listNew; + } + } + + listNew->name = name; + listNew->endTime = Quos_sysTickAddMs(Quos_sysTickGet(), timeout); + listNew->timeout = timeout; + listNew->repeat = (repeat == 0) ? SWT_FOREVER : repeat; + listNew->parm = parm; + listNew->timeoutCb = timeoutCb; + Quos_twllHeadAdd(&SWTimerHead, &listNew->head); + Quos_kernelResume(); + quos_swTimerPrintf(); + HAL_UNLOCK(lockId); + return TRUE; +} +/************************************************************************** +** 功能 @brief : 删除指定编号定时器 +** 输入 @param : 定时器编号 +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Quos_swTimerDelete(void *swTimerP) +{ + SWTimer_T *swTimer = (SWTimer_T *)swTimerP; + Quos_logPrintf(LSDK_TIMER, LL_INFO, "swTimer[%p]:%s", swTimer, (swTimer && swTimer->name) ? swTimer->name : ""); + TWLLHead_T *temp, *next; + HAL_LOCK(lockId); + TWLIST_FOR_DATA(SWTimerHead, temp, next) + { + SWTimer_T *timer = __GET_STRUCT_BY_ELEMENT(temp, SWTimer_T, head); + if (timer == swTimer) + { + Quos_logPrintf(LSDK_TIMER, LL_DBG, "timer is del repeat[%u]", timer->repeat); + if (timer->self) + { + *timer->self = NULL; + timer->self = NULL; + } + Quos_twllHeadDelete(&SWTimerHead, temp); + HAL_FREE(timer); + Quos_kernelResume(); + quos_swTimerPrintf(); + break; + } + } + HAL_UNLOCK(lockId); +} + +/************************************************************************** +** 功能 @brief : 变更定时器超时时间 +** 输入 @param : timeout:超时时间 +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Quos_swTimerTimeoutSet(void *swTimerP, quint32_t timeout) +{ + SWTimer_T *swTimer = (SWTimer_T *)swTimerP; + Quos_logPrintf(LSDK_TIMER, LL_DBG, "timeout:%u", timeout); + TWLLHead_T *temp, *next; + HAL_LOCK(lockId); + TWLIST_FOR_DATA(SWTimerHead, temp, next) + { + SWTimer_T *timer = __GET_STRUCT_BY_ELEMENT(temp, SWTimer_T, head); + if (timer == swTimer) + { + timer->timeout = timeout; + timer->endTime = Quos_sysTickAddMs(Quos_sysTickGet(), timer->timeout); + Quos_kernelResume(); + break; + } + } + HAL_UNLOCK(lockId); +} +/************************************************************************** +** 功能 @brief : 获取定时器超时时间 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +quint32_t FUNCTION_ATTR_ROM Quos_swTimerTimeoutGet(void *swTimerP) +{ + quint32_t timeout = SWT_SUSPEND; + SWTimer_T *swTimer = (SWTimer_T *)swTimerP; + TWLLHead_T *temp, *next; + HAL_LOCK(lockId); + TWLIST_FOR_DATA(SWTimerHead, temp, next) + { + SWTimer_T *timer = __GET_STRUCT_BY_ELEMENT(temp, SWTimer_T, head); + if (timer == swTimer) + { + timeout = timer->timeout; + break; + } + } + HAL_UNLOCK(lockId); + return timeout; +} +/************************************************************************** +** 功能 @brief : 变更定时器重复次数 +** 输入 @param : repeat:0为永久 +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Quos_swTimerRepeatSet(void *swTimerP, quint32_t repeat) +{ + SWTimer_T *swTimer = (SWTimer_T *)swTimerP; + Quos_logPrintf(LSDK_TIMER, LL_DBG, "repeat:%u", repeat); + TWLLHead_T *temp, *next; + HAL_LOCK(lockId); + TWLIST_FOR_DATA(SWTimerHead, temp, next) + { + SWTimer_T *timer = __GET_STRUCT_BY_ELEMENT(temp, SWTimer_T, head); + if (timer == swTimer) + { + timer->repeat = (repeat == 0) ? SWT_FOREVER : repeat; + Quos_kernelResume(); + break; + } + } + HAL_UNLOCK(lockId); +} +/************************************************************************** +** 功能 @brief : 获取定时器重复次数 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +quint32_t FUNCTION_ATTR_ROM Quos_swTimerRepeatGet(void *swTimerP) +{ + quint32_t repeat = 0; + SWTimer_T *swTimer = (SWTimer_T *)swTimerP; + TWLLHead_T *temp, *next; + HAL_LOCK(lockId); + TWLIST_FOR_DATA(SWTimerHead, temp, next) + { + SWTimer_T *timer = __GET_STRUCT_BY_ELEMENT(temp, SWTimer_T, head); + if (timer == swTimer) + { + repeat = timer->repeat; + break; + } + } + HAL_UNLOCK(lockId); + return repeat; +} +/************************************************************************** +** 功能 @brief : 获取定时器外参 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM *Quos_swTimerParmGet(void *swTimerP) +{ + void *param = NULL; + SWTimer_T *swTimer = (SWTimer_T *)swTimerP; + TWLLHead_T *temp, *next; + HAL_LOCK(lockId); + TWLIST_FOR_DATA(SWTimerHead, temp, next) + { + SWTimer_T *timer = __GET_STRUCT_BY_ELEMENT(temp, SWTimer_T, head); + if (timer == swTimer) + { + param = timer->parm; + } + } + HAL_UNLOCK(lockId); + return param; +} +/************************************************************************** +** 功能 @brief : 变更定时器回调函数 +** 输入 @param : repeat:0为永久 +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Quos_swTimerCBSet(void *swTimerP, const SWTimerCB timeoutCb) +{ + SWTimer_T *swTimer = (SWTimer_T *)swTimerP; + Quos_logPrintf(LSDK_TIMER, LL_DBG, "timeoutCb:%p", timeoutCb); + TWLLHead_T *temp, *next; + HAL_LOCK(lockId); + TWLIST_FOR_DATA(SWTimerHead, temp, next) + { + SWTimer_T *timer = __GET_STRUCT_BY_ELEMENT(temp, SWTimer_T, head); + if (timer == swTimer) + { + timer->timeoutCb = timeoutCb; + break; + } + } + HAL_UNLOCK(lockId); +} +/************************************************************************** +** 功能 @brief : 检查定时器时间是否已到 +** 输入 @param : +** 输出 @retval: 距离下次响应时长,-1:无定时器 +***************************************************************************/ +quint32_t FUNCTION_ATTR_RAM Quos_swTimerTask(void) +{ + SWTimer_T *listMinTime = NULL; + TWLLHead_T *temp, *next; + HAL_LOCK(lockId); + + TWLIST_FOR_DATA(SWTimerHead, temp, next) + { + SWTimer_T *timer = __GET_STRUCT_BY_ELEMENT(temp, SWTimer_T, head); + if(0 == timer->repeat) + { + if(timer->self) + { + *timer->self = NULL; + timer->self = NULL; + } + Quos_twllHeadDelete(&SWTimerHead, temp); + HAL_FREE(timer); + quos_swTimerPrintf(); + } + else if (SWT_SUSPEND == timer->timeout) /* timeout为-1时为无效定时器 */ + { + // DO NOT + } + else if (NULL == listMinTime || Quos_sysTickdiff(timer->endTime, listMinTime->endTime, TRUE) < 0) + { + listMinTime = timer; + } + } + if(NULL == listMinTime) + { + HAL_UNLOCK(lockId); + Quos_logPrintf(LSDK_TIMER, LL_DBG, "suspend"); + return SWT_SUSPEND; + } + + qint32_t interval = Quos_sysTickdiff(listMinTime->endTime, Quos_sysTickGet(), TRUE); + if(interval > 0) + { + HAL_UNLOCK(lockId); + Quos_logPrintf(LSDK_TIMER, LL_DBG, "interval:%d", interval); + return interval; + } + Quos_logPrintf(LSDK_TIMER, LL_INFO, "%s:%p timeout:%u repeat:%u", listMinTime->name, listMinTime, listMinTime->timeout, listMinTime->repeat); + if (listMinTime->repeat != SWT_FOREVER) + { + listMinTime->repeat--; + } + listMinTime->endTime = Quos_sysTickAddMs(Quos_sysTickGet(), listMinTime->timeout); + HAL_UNLOCK(lockId); + Quos_logPrintf(LSDK_TIMER, LL_DBG, "exec cb[%s]",listMinTime->name); + listMinTime->timeoutCb((void *)listMinTime); + Quos_logPrintf(LSDK_TIMER, LL_DBG, "exec cb[%s] finish",listMinTime->name); + return 0; +} +#endif diff --git a/kernel/quos_swTimer.h b/kernel/quos_swTimer.h index 39decc7fbbc2b353bf5c812efcccefc674aca2bb..e2e36f307fcc38a988801e1ad9337489e90091f7 100644 --- a/kernel/quos_swTimer.h +++ b/kernel/quos_swTimer.h @@ -1,37 +1,29 @@ -#ifndef __QUOS_SWTIMER_H__ -#define __QUOS_SWTIMER_H__ -#include "quos_config.h" -#include "quos_twll.h" -#include "quos_sysTick.h" - -#if (SDK_ENABLE_TIMER == 1) - -#define SWT_SUSPEND ((quint32_t)-1) -#define SWT_ONE_MSEC (1) -#define SWT_ONE_SECOND (1000 * SWT_ONE_MSEC) -#define SWT_ONE_MINUTE (60 * SWT_ONE_SECOND) -#define SWT_ONE_HOUR (60 * SWT_ONE_MINUTE) -#define SWT_ONE_DAY (24 * SWT_ONE_HOUR) - -typedef struct __SWTimer -{ - TWLLHead_T head; - char *name; - Systick_T endTime; - quint32_t timeout; /* 定时时长,单位ms */ - quint32_t repeat; /* 重复次数 */ - void *parm; - void **self; - void (*timeoutCb)(struct __SWTimer *swTimer); -} SWTimer_T; - -typedef void (*SWTimerCB)(SWTimer_T *swTimer); -qbool Quos_swTimerStart(SWTimer_T **swTimer, char *name, quint32_t timeout, quint32_t repeat, const SWTimerCB timeoutCb, void *parm); -void Quos_swTimerDelete(SWTimer_T *SWTimer); -void Quos_swTimerTimeoutSet(SWTimer_T *swTimer, quint32_t timeout); -void Quos_swTimerRepeatSet(SWTimer_T *swTimer, quint32_t repeat); -void Quos_swTimerCBSet(SWTimer_T *swTimer, const SWTimerCB timeoutCb); -quint32_t Quos_swTimerTask(void); - -#endif +#ifndef __QUOS_SWTIMER_H__ +#define __QUOS_SWTIMER_H__ +#include "quos_config.h" +#include "quos_twll.h" +#include "quos_sysTick.h" + +#if (SDK_ENABLE_TIMER == 1) + +#define SWT_SUSPEND ((quint32_t)-1) +#define SWT_ONE_MSEC (1) +#define SWT_ONE_SECOND (1000 * SWT_ONE_MSEC) +#define SWT_ONE_MINUTE (60 * SWT_ONE_SECOND) +#define SWT_ONE_HOUR (60 * SWT_ONE_MINUTE) +#define SWT_ONE_DAY (24 * SWT_ONE_HOUR) + +typedef void (*SWTimerCB)(void *swTimerP); +void Quos_swTimerInit(void); +qbool Quos_swTimerStart(void **swTimerP, char *name, quint32_t timeout, quint32_t repeat, const SWTimerCB timeoutCb, void *parm); +void Quos_swTimerDelete(void *SWTimerP); +void Quos_swTimerTimeoutSet(void *swTimerP, quint32_t timeout); +quint32_t Quos_swTimerTimeoutGet(void *swTimerP); +void Quos_swTimerRepeatSet(void *swTimerP, quint32_t repeat); +quint32_t Quos_swTimerRepeatGet(void *swTimerP); +void *Quos_swTimerParmGet(void *swTimerP); +void Quos_swTimerCBSet(void *swTimerP, const SWTimerCB timeoutCb); +quint32_t Quos_swTimerTask(void); + +#endif #endif \ No newline at end of file diff --git a/kernel/quos_sysTick.c b/kernel/quos_sysTick.c new file mode 100644 index 0000000000000000000000000000000000000000..f5eaef88528d5f484692ee4251f89a833b8aa8f3 --- /dev/null +++ b/kernel/quos_sysTick.c @@ -0,0 +1,255 @@ +/************************************************************************* +** 创建人 @author : 吴健超 JCWu +** 版本 @version : V1.0.0 原始版本 +** 日期 @date : +** 功能 @brief : 系统时钟 +** 硬件 @hardware:任何ANSI-C平台 +** 其他 @other : +***************************************************************************/ +#include "quos_sysTick.h" +#include "Quos_kernel.h" +#include "Qhal_driver.h" +static qint32_t Timezone = 8 * 3600; +HAL_LOCK_DEF(static, lockId) +static Systick_T SysTickStart = {0, 0}; +/************************************************************************** +** 功能 @brief : 初始化系统时间 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Quos_sysTickInit(void) +{ + Qhal_rtcInit(); + HAL_LOCK_INIT(lockId); + Qhal_rtcGet(&SysTickStart.sec, &SysTickStart.ms); +} +/************************************************************************** +** 功能 @brief : 纠正系统时间 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Quos_sysTickRectify(Systick_T sysTickNew) +{ + HAL_LOCK(lockId); + Systick_T systickNow; + Qhal_rtcGet(&systickNow.sec, &systickNow.ms); + + qint32_t diffVal = Quos_sysTickdiff(sysTickNew, systickNow, TRUE); + if (diffVal < 0) + { + diffVal = 0 - diffVal; + SysTickStart.sec -= diffVal / 1000; + diffVal %= 1000; + if (SysTickStart.ms < (quint32_t)diffVal) + { + SysTickStart.sec--; + SysTickStart.ms += 1000 - diffVal; + } + else + { + SysTickStart.ms -= diffVal; + } + } + else + { + SysTickStart.ms += diffVal %= 1000; + SysTickStart.sec += diffVal / 1000; + if (SysTickStart.ms >= 1000) + { + SysTickStart.sec += SysTickStart.ms / 1000; + SysTickStart.ms %= SysTickStart.ms; + } + } + HAL_UNLOCK(lockId); +} +/************************************************************************** +** 功能 @brief : 获取当前系统运行时间 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +Systick_T FUNCTION_ATTR_ROM Quos_sysTickGet(void) +{ + HAL_LOCK(lockId); + Systick_T SysTickNow; + Qhal_rtcGet(&SysTickNow.sec, &SysTickNow.ms); + SysTickNow.sec -= SysTickStart.sec; + if (SysTickNow.ms < SysTickStart.ms) + { + SysTickNow.sec--; + SysTickNow.ms += 1000; + } + SysTickNow.ms -= SysTickStart.ms; + HAL_UNLOCK(lockId); + return SysTickNow; +} +/************************************************************************** +** 功能 @brief : 获取当前系统运行时间ms +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +quint32_t FUNCTION_ATTR_ROM Quos_sysTickGetMs(void) +{ + Systick_T now = Quos_sysTickGet(); + return (quint32_t)(now.sec * 1000 + now.ms); +} +/************************************************************************** +** 功能 @brief : 获取当前系统运行时间s +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +quint32_t FUNCTION_ATTR_ROM Quos_sysTickGetS(void) +{ + return Quos_sysTickGet().sec; +} + +/************************************************************************** +** 功能 @brief : 计算tick加上ms后时间 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +Systick_T FUNCTION_ATTR_ROM Quos_sysTickAddMs(Systick_T tick, quint32_t ms) +{ + tick.sec += ms / 1000; + tick.ms += ms % 1000; + tick.sec += tick.ms / 1000; + tick.ms = tick.ms % 1000; + return tick; +} + +/************************************************************************** +** 功能 @brief : 比较时间大小 +** 输入 @param : isMs:差值单位TRUE:毫秒,FALSE:秒 +** 输出 @retval: 返回时间差值 +***************************************************************************/ +qint32_t FUNCTION_ATTR_ROM Quos_sysTickdiff(Systick_T time1, Systick_T time2, qbool isMs) +{ + qint32_t interval; + if (time1.sec > time2.sec || (time1.sec == time2.sec && time1.ms >= time2.ms)) + { + if (time1.ms < time2.ms) + { + time1.sec--; + time1.ms += 1000; + } + interval = time1.sec - time2.sec; + if (isMs) + interval = interval * 1000 + (time1.ms - time2.ms); + } + else + { + if (time2.ms < time1.ms) + { + time2.sec--; + time2.ms += 1000; + } + interval = time1.sec - time2.sec; + if (isMs) + interval = interval * 1000 - (time2.ms - time1.ms); + } + return interval; +} +/************************************************************************** +** 功能 @brief : 设置时区 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Quos_timezoneSet(qint32_t tz) +{ + Timezone = tz; +} +/************************************************************************** +** 功能 @brief : 获取时区 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +qint32_t Quos_timezoneGet(void) +{ + return Timezone; +} +/************************************************************************** +** 功能 @brief : 时间戳转成年月日时分秒 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static const quint8_t Days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; +Quos_tm_t FUNCTION_ATTR_RAM Quos_localtime(quint32_t time) +{ + Quos_tm_t tm; + quint32_t Pass4year; + quint32_t hours_per_year; + time += Timezone; + tm.tm_sec = time % 60; /*取秒时间 */ + time /= 60; + tm.tm_min = time % 60; /*取分钟时间 */ + time /= 60; + Pass4year = time / (1461L * 24L); /*取过去多少个四年,每四年有 1461*24 小时 */ + tm.tm_year = (Pass4year << 2) + 1970; /*计算年份 */ + time %= 1461L * 24L; /*四年中剩下的小时数 */ + /*校正闰年影响的年份,计算一年中剩下的小时数 */ + for (;;) + { + hours_per_year = 365 * 24; /*一年的小时数 */ + if ((tm.tm_year & 3) == 0) + hours_per_year += 24; /*判断闰年,一年则多24小时,即一天 */ + if (time < hours_per_year) + break; + tm.tm_year++; + time -= hours_per_year; + } + + tm.tm_hour = time % 24; /*小时数 */ + time /= 24; /*一年中剩下的天数 */ + time++; /*假定为闰年 */ + /*校正闰年的误差,计算月份,日期 */ + if ((tm.tm_year & 3) == 0) + { + if (time > 60) + time--; + else if (time == 60) + { + tm.tm_mon = 1; + tm.tm_mday = 29; + return tm; + } + } + /*计算月日 */ + for (tm.tm_mon = 0; Days[tm.tm_mon] < time; tm.tm_mon++) + { + time -= Days[tm.tm_mon]; + } + tm.tm_mon += 1; + tm.tm_mday = time; + return tm; +} +/************************************************************************** +** 功能 @brief : 年月日时分秒转成时间戳 +** 输入 @param : +** 输出 @retval: +***************************************************************************/ +static quint32_t mon_yday[2][12] = + { + {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}, + {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}, +}; + +static qbool isleap(quint32_t year) +{ + return (year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0); +} + +quint32_t FUNCTION_ATTR_RAM Quos_mktime(Quos_tm_t tm) +{ + /* 以平年时间计算的秒数 */ + quint32_t result = (tm.tm_year - 1970) * 365 * 24 * 3600 + + (mon_yday[isleap(tm.tm_year) ? 1 : 0][tm.tm_mon - 1] + tm.tm_mday - 1) * 24 * 3600 + + tm.tm_hour * 3600 + tm.tm_min * 60 + tm.tm_sec; + /* 加上闰年的秒数 */ + quint32_t i; + for (i = 1970; i < tm.tm_year; i++) + { + if (isleap(i)) + result += 24 * 3600; + } + + return result - Timezone; +} \ No newline at end of file diff --git a/kernel/quos_twll.c b/kernel/quos_twll.c new file mode 100644 index 0000000000000000000000000000000000000000..1a16c602f3c96008d8bd85298d3707f27aa69a15 --- /dev/null +++ b/kernel/quos_twll.c @@ -0,0 +1,183 @@ +/************************************************************************* +** 源码未经检录,使用需谨慎 +** 创建人 @author : 吴健超 JCWu +** 版本 @version : V1.0.0 原始版本 +** 日期 @date : +** 功能 @brief : 实现双向非循环向链表操作 +** 硬件 @hardware:任何ANSI-C平台 +** 其他 @other : +***************************************************************************/ +#include "quos_twll.h" +#if (SDK_ENABLE_TWLL ==1) +#include "Quos_kernel.h" + +/************************************************************************** +** 功能 @brief : 向链表尾部增加节点 +** 输入 @param : list 链表的首节点地址 node 新链表节点 +** 输出 @retval: 增加的节点指针 +***************************************************************************/ +void FUNCTION_ATTR_ROM Quos_twllHeadAdd(TWLLHead_T **list, TWLLHead_T *node) +{ + TWLLHead_T *tempNode; + for (tempNode = *list; NULL != tempNode; tempNode = tempNode->next) + { + if (tempNode == node) + { + return; + } + } + node->next = NULL; + if (*list == NULL) + { + *list = node; + } + else + { + node->prev = (*list)->prev; + (*list)->prev->next = node; + } + (*list)->prev = node; +} +/************************************************************************** +** 功能 @brief : 向链表头部增加节点 +** 输入 @param : list 链表的首节点地址 node 新链表节点 +** 输出 @retval: 增加的节点指针 +***************************************************************************/ +void FUNCTION_ATTR_ROM Quos_twllHeadAddFirst(TWLLHead_T **list, TWLLHead_T *node) +{ + node->next = *list; + if(NULL == *list) + { + node->prev = node; + } + else + { + node->prev = (*list)->prev; + (*list)->prev = node; + } + *list = node; +} +/************************************************************************** +** 功能 @brief : 删除指定节点 +** 输入 @param : list 链表的首节点地址 node 待删除链表节点 +** 输出 @retval: +***************************************************************************/ +void FUNCTION_ATTR_ROM Quos_twllHeadDelete(TWLLHead_T **list, TWLLHead_T *node) +{ + TWLLHead_T *tempNode; + for (tempNode = *list; NULL != tempNode; tempNode = tempNode->next) + { + if (tempNode == node) + { + if (node == *list) + { + if (node->next) + { + node->next->prev = (*list)->prev; + } + *list = node->next; + } + else if (node->next) + { + node->next->prev = node->prev; + node->prev->next = node->next; + } + else + { + (*list)->prev = node->prev; + node->prev->next = NULL; + } + node->prev = NULL; + node->next = NULL; + return; + } + } +} +/************************************************************************** +** 功能 @brief : 在指定节点前面插入节点 +** 输入 @param : list 链表的首节点地址 referNode参考节点 node 新链表节点 +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Quos_twllHeadInsertFront(TWLLHead_T **list, TWLLHead_T *referNode, TWLLHead_T *node) +{ + Quos_twllHeadDelete(list, node); + TWLLHead_T *tempNode; + for (tempNode = *list; NULL != tempNode; tempNode = tempNode->next) + { + if (tempNode == referNode) + { + node->next = referNode; + node->prev = referNode->prev; + + if (referNode == *list) + { + *list = node; + } + else + { + referNode->prev->next = node; + } + referNode->prev = node; + return TRUE; + } + } + return FALSE; +} +/************************************************************************** +** 功能 @brief : 在指定节点后面插入节点 +** 输入 @param : list 链表的首节点地址 referNode参考节点 node 新链表节点 +** 输出 @retval: +***************************************************************************/ +qbool FUNCTION_ATTR_ROM Quos_twllHeadInsertBehind(TWLLHead_T **list, TWLLHead_T *referNode, TWLLHead_T *node) +{ + Quos_twllHeadDelete(list, node); + TWLLHead_T *tempNode; + for (tempNode = *list; NULL != tempNode; tempNode = tempNode->next) + { + if (tempNode == referNode) + { + node->next = referNode->next; + node->prev = referNode; + if (referNode->next) + { + referNode->next->prev = node; + } + referNode->next = node; + return TRUE; + } + } + return FALSE; +} +/************************************************************************** +** 功能 @brief : 查找链表第N个节点 +** 输入 @param : list 链表的首节点地址,nodeId 节点编号第一个节点是0 +** 输出 @retval: +***************************************************************************/ +TWLLHead_T FUNCTION_ATTR_ROM *Quos_twllHeadFineNodeByNodeId(TWLLHead_T *list, quint32_t nodeId) +{ + TWLLHead_T *tempNode = list; + while (tempNode && nodeId) + { + nodeId--; + tempNode = tempNode->next; + } + return tempNode; +} +/************************************************************************** +** 功能 @brief : 获取指定链表节点数 +** 输入 @param : list 链表的首节点地址 +** 输出 @retval: +***************************************************************************/ +quint32_t FUNCTION_ATTR_ROM Quos_twllHeadGetNodeCount(TWLLHead_T *list) +{ + quint16_t nodeCnt = 0; + TWLLHead_T *tempNode = list; + while (tempNode) + { + nodeCnt++; + tempNode = tempNode->next; + } + return nodeCnt; +} + +#endif \ No newline at end of file diff --git a/kernel/quos_twll.h b/kernel/quos_twll.h index 1378acac5efa323b98109bfa096c991ffe190730..95e581f477d88a37ea06fa4c622275c5687060a7 100644 --- a/kernel/quos_twll.h +++ b/kernel/quos_twll.h @@ -1,32 +1,28 @@ -#ifndef __QUOS_TWLL_H__ -#define __QUOS_TWLL_H__ -#include "quos_config.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct __TWLLHead -{ - struct __TWLLHead *prev; - struct __TWLLHead *next; -}TWLLHead_T; -/* 对节点轮询 */ -#define TWLIST_FOR_DATA(LISTHEAD,LISTTEMP,NEXTLIST) \ - for((LISTTEMP) = (LISTHEAD),(NEXTLIST) = (LISTHEAD)?(LISTHEAD)->next:NULL; \ - NULL != (LISTTEMP); \ - (LISTTEMP) = (NEXTLIST),(NEXTLIST) = (NEXTLIST)?(NEXTLIST)->next:NULL) - -void Quos_twllHeadAdd(TWLLHead_T **twList,TWLLHead_T *twNode); -void Quos_twllHeadAddFirst(TWLLHead_T **list, TWLLHead_T *node); -void Quos_twllHeadDelete(TWLLHead_T **twList,TWLLHead_T *twNode); -qbool Quos_twllHeadInsertFront(TWLLHead_T **list, TWLLHead_T *referNode, TWLLHead_T *node); -qbool Quos_twllHeadInsertBehind(TWLLHead_T **list, TWLLHead_T *referNode, TWLLHead_T *node); -TWLLHead_T *Quos_twllHeadFineNodeByDataCmp(TWLLHead_T *list,void* dat,quint16_t offset,quint16_t len); -TWLLHead_T *Quos_twllHeadFineNodeByNodeId(TWLLHead_T *list, quint32_t nodeId); -quint32_t Quos_twllHeadGetNodeCount(TWLLHead_T *list); -#ifdef __cplusplus -} -#endif - -#endif +#ifndef __QUOS_TWLL_H__ +#define __QUOS_TWLL_H__ +#include "quos_config.h" + +#if (SDK_ENABLE_TWLL ==1) + +typedef struct __TWLLHead +{ + struct __TWLLHead *prev; + struct __TWLLHead *next; +}TWLLHead_T; +/* 对节点轮询 */ +#define TWLIST_FOR_DATA(LISTHEAD,LISTTEMP,NEXTLIST) \ + for((LISTTEMP) = (LISTHEAD),(NEXTLIST) = (LISTHEAD)?(LISTHEAD)->next:NULL; \ + NULL != (LISTTEMP); \ + (LISTTEMP) = (NEXTLIST),(NEXTLIST) = (NEXTLIST)?(NEXTLIST)->next:NULL) + +void Quos_twllHeadAdd(TWLLHead_T **twList,TWLLHead_T *twNode); +void Quos_twllHeadAddFirst(TWLLHead_T **list, TWLLHead_T *node); +void Quos_twllHeadDelete(TWLLHead_T **twList,TWLLHead_T *twNode); +qbool Quos_twllHeadInsertFront(TWLLHead_T **list, TWLLHead_T *referNode, TWLLHead_T *node); +qbool Quos_twllHeadInsertBehind(TWLLHead_T **list, TWLLHead_T *referNode, TWLLHead_T *node); +TWLLHead_T *Quos_twllHeadFineNodeByNodeId(TWLLHead_T *list, quint32_t nodeId); +quint32_t Quos_twllHeadGetNodeCount(TWLLHead_T *list); + +#endif + +#endif diff --git a/platform/ASR_lib/lib/libquecsdk_in.a b/platform/ASR_lib/lib/libquecsdk_in.a deleted file mode 100644 index 4bb5608607a05bfa2ee9c8a436aa11fafbd80e71..0000000000000000000000000000000000000000 Binary files a/platform/ASR_lib/lib/libquecsdk_in.a and /dev/null differ diff --git a/platform/Unisoc_lib/lib/libquecsdk_in.a b/platform/Unisoc_lib/lib/libquecsdk_in.a deleted file mode 100644 index 7ec860f9fa607ac1fc8cd8a358b0d92332aca140..0000000000000000000000000000000000000000 Binary files a/platform/Unisoc_lib/lib/libquecsdk_in.a and /dev/null differ diff --git a/quecsdk.mk b/quecsdk.mk index 3aaecd988afd8c1988634611da06e072425afae2..98e92b62a047b74224b329e46cc90c3ae764d847 100644 --- a/quecsdk.mk +++ b/quecsdk.mk @@ -8,17 +8,6 @@ NAME := QUECSDK $(NAME)_DEFINE := CLOUD_ENABLE_QUEC_MQTT ENABLE_QUEC_PYTHON -#缂栬瘧骞冲彴涓篈SR -ifeq ($(strip $(PLAT)),ASR) -$(NAME)_ARCHIVES := platform/ASR_lib/lib/libquecsdk_in.a -else -#缂栬瘧骞冲彴涓哄睍閿 -ifeq ($(strip $(PLAT)),Unisoc) -$(NAME)_ARCHIVES := platform/Unisoc_lib/lib/libquecsdk_in.a -else -$(error current platform does not support quecIot) -endif -endif $(NAME)_SRCS += \ driverLayer/qhal_Dev.c \ @@ -35,13 +24,48 @@ $(NAME)_SRCS += \ thirdLib/mqtt/MQTTSubscribeClient.c \ thirdLib/mqtt/MQTTSubscribeServer.c \ thirdLib/mqtt/MQTTUnsubscribeClient.c \ - thirdLib/mqtt/MQTTUnsubscribeServer.c + thirdLib/mqtt/MQTTUnsubscribeServer.c \ + cloud/common/ql_iotCmdBus.c \ + cloud/common/ql_iotCmdLan.c \ + cloud/common/ql_iotCmdLoc.c \ + cloud/common/ql_iotCmdOTA.c \ + cloud/common/ql_iotCmdSys.c \ + cloud/common/ql_iotConfig.c \ + cloud/common/ql_iotConn.c \ + cloud/common/ql_iotDp.c \ + cloud/common/ql_iotConn.c \ + cloud/common/ql_iotSecure.c \ + cloud/common/ql_iotTtlv.c \ + kernel/quos_aes.c \ + kernel/quos_base64.c \ + kernel/quos_cjson.c \ + kernel/quos_coap.c \ + kernel/quos_dataStore.c \ + kernel/quos_event.c \ + kernel/quos_fifo.c \ + kernel/quos_http.c \ + kernel/Quos_kernel.c \ + kernel/quos_log.c \ + kernel/quos_lwm2m.c \ + kernel/quos_md5.c \ + kernel/quos_mqtt.c \ + kernel/quos_net.c \ + kernel/quos_sha1.c \ + kernel/quos_sha256.c \ + kernel/quos_signal.c \ + kernel/quos_socket.c \ + kernel/quos_SupportTool.c \ + kernel/quos_swTimer.c \ + kernel/quos_sysTick.c \ + kernel/quos_twll.c \ + GLOBAL_INCS += \ driverLayer \ thirdLib/mqtt \ thirdLib/cJSON \ cloud \ + cloud/common \ kernel #endif