// // Created by cfif on 04.10.2022. // #include #include #include #include #include "SerialPort.h" #include "string.h" #include "fs_base_func.h" #include #include "httpd_post.h" #include "httpd_get.h" #include "httpd_base_func.h" #include "json_func.h" #include "crc16_tracer.h" #define LOGGER env->logger #define LOG_SIGN "GONEC" extern char bufAnswerGetGlobal[LEN_BUF_SMALL_ANSWER_HTTP]; void External_Init(tExternal *env, tSerialPortIO *io, tDeviceStorageIni *store, tFs *fs, tRtcIO *rtcIo, tModemMain *modemMain ) { env->io = io; env->store = store; env->fs = fs; env->rtcIo = rtcIo; env->modemMain = modemMain; env->count = 0; env->countPack = 0; env->stepTimeSecond = 0; memset(env->sensorExt, 0, sizeof(env->sensorExt)); env->sensorA = 0; env->sensorB = 0; env->sensorAccess = osMutexNew(NULL); env->bufAnswer = bufAnswerGetGlobal; AtCmdInit( &env->externalAt, io, env->mem.modemTx, sizeof(env->mem.modemTx), env->mem.modemRx, sizeof(env->mem.modemRx), 5000, 5000 ); //Инициализируем поток InitThreadAtrStatic(&env->thread.attr, "External", env->thread.controlBlock, env->thread.stack, osPriorityNormal); env->thread.id = 0; } void ReInitExternalProtocol(tExternal *env) { env->count = 0; env->countPack = 0; env->stepTimeSecond = 0; memset(env->sensorExt, 0, sizeof(env->sensorExt)); env->sensorA = 0; env->sensorB = 0; } bool SendFileToUART(tFs *fs, char *fileName, tAtCmd *At) { FIL fsrc; // File objects BYTE buffer[512]; // File copy buffer FRESULT fr; // FatFs function common result code UINT br; // File read/write count fr = f_open_i(fs, &fsrc, fileName, FA_READ); if (fr) return false; for (;;) { f_read_i(fs, &fsrc, buffer, sizeof(buffer), &br); if (br == 0) break; AtCmdTxClear(At); AtCmdSend(At, buffer, br); } f_close_i(fs, &fsrc); return true; } void ExternalProtocol(tExternal *env) { char *params = NULL; char uri[100]; char uri2[100]; while (AtCmdReceiveNextLine(&env->externalAt, 1000) == AT_OK) { if (osMutexAcquire(httpSettings.accessHTTP, TIME_MUTEX_HTTP_ACCESS) == osOK) { if (env->externalAt.rxBuffer.len > sizeof(uri)) { uint32_t err = Post_PARAM_ERR; env->left = json_generate_err_answer(env->bufAnswer, LEN_BUF_SMALL_ANSWER_HTTP, err); AtCmdTxClear(&env->externalAt); AtCmdSend(&env->externalAt, env->bufAnswer, env->left); osMutexRelease(httpSettings.accessHTTP); return; } uri[0] = '/'; memcpy(&uri[1], &env->externalAt.rxBuffer.data[2], env->externalAt.rxBuffer.len - 2); if (uri[env->externalAt.rxBuffer.len - 2] == '\r') uri[env->externalAt.rxBuffer.len - 2] = '\0'; if (uri[env->externalAt.rxBuffer.len - 2] == '\n') uri[env->externalAt.rxBuffer.len - 2] = '\0'; if (uri[env->externalAt.rxBuffer.len - 3] == '\r') uri[env->externalAt.rxBuffer.len - 3] = '\0'; if (uri[env->externalAt.rxBuffer.len - 3] == '\n') uri[env->externalAt.rxBuffer.len - 3] = '\0'; int pos = -1; int len = -1; char filename[MAX_LEN_PATH_FS]; filename[0] = '\0'; memcpy(uri2, uri, sizeof(uri)); char *params2 = NULL; params2 = (char *) strchr(uri2, '?'); if (params2 != NULL) { *params2 = '\0'; params2++; } env->params_post_uri.paramcount = extract_uri_ex_parameters(params2, env->params_post_uri.params_names, env->params_post_uri.params_vals, MAX_POST_GET_PARAMETERS); if (strcmp(env->params_post_uri.params_names[0], "wrfile") == 0) { for (int i = 0; i < env->params_post_uri.paramcount; ++i) { if (strcmp(env->params_post_uri.params_names[i], "pos") == 0) pos = atoi(env->params_post_uri.params_vals[i]); if (strcmp(env->params_post_uri.params_names[i], "len") == 0) len = atoi(env->params_post_uri.params_vals[i]); if (strcmp(env->params_post_uri.params_names[i], "wrfile") == 0) extract_utf8_parameters(env->params_post_uri.params_vals[i], filename, sizeof(filename)); } if ((pos == -1) || (len == -1) || (strlen(filename) == 0) || (len > 1024)) { } else { AtCmdPrepare(&env->externalAt); AtCmdTxClear(&env->externalAt); AtCmdTxAddStatic(&env->externalAt, ">"); AtCmdTxSendLn(&env->externalAt); AtCmdRxClear(&env->externalAt); uint16_t size = AtCmdRxReadRAW(&env->externalAt, (uint8_t *) env->bufAnswer, len, 5000); if (len != size) { uint32_t err = Post_PARAM_ERR; env->left = json_generate_err_answer(env->bufAnswer, LEN_BUF_SMALL_ANSWER_HTTP, err); AtCmdTxClear(&env->externalAt); AtCmdSend(&env->externalAt, env->bufAnswer, env->left); osMutexRelease(httpSettings.accessHTTP); return; } } } params = (char *) strchr(uri, '?'); if (params != NULL) { *params = '\0'; params++; } idPostResult_t resultGet = httpd_get_begin(&httpSettings, httpSettings.auth, uri, params, &env->isContentFile, env->fileNameContent, env->bufAnswer, &env->left); if (env->isContentFile) { SendFileToUART(env->fs, env->fileNameContent, &env->externalAt); } else { if (env->left > 0) { AtCmdTxClear(&env->externalAt); AtCmdSend(&env->externalAt, env->bufAnswer, env->left); } } osMutexRelease(httpSettings.accessHTTP); } } } AtCommandResult getDataAmsRadar(tExternal *env, int count) { AtCmdPrepare(&env->externalAt); AtCmdTxClear(&env->externalAt); AtCmdTxAddStatic(&env->externalAt, "DATA=?"); AtCmdTxSendLn(&env->externalAt); #ifdef DEBUG_EXT_MODEM if (count == 0) { LoggerInfoStatic(LOGGER, LOG_SIGN, "Отправка команды на АМС: DATA=?"); } else { char bufText[128]; bufText[0] = '\0'; strcat(bufText, "Отправка команды на АМС (попытка №"); char buf[12]; utoa(count, buf, 10); strcat(bufText, buf); strcat(bufText, "): DATA=?"); LoggerInfo(LOGGER, LOG_SIGN, bufText, strlen(bufText)); } #endif uint32_t timeout = 5000; uint32_t endMs = SystemGetMs() + timeout; uint32_t leftMs = timeout; while ((AtCmdReceiveNextLine(&env->externalAt, leftMs) == AT_OK) && (SystemGetMs() < endMs)) { leftMs = endMs - SystemGetMs(); if (env->externalAt.rxBuffer.len > 240) { LoggerInfoStatic(LOGGER, LOG_SIGN, "Превышен размер данных. Игнорирование полученных данных данных от АМС."); //LoggerInfo(LOGGER, LOG_SIGN, env->externalAt.rxBuffer.data, env->externalAt.rxBuffer.len); return AT_ERROR; } else { bool isStart = false; bool isHead = false; for (size_t i = 0; i < env->externalAt.rxBuffer.len; ++i) { if (env->externalAt.rxBuffer.data[i] == '$') { isStart = true; isHead = true; } if (isStart) { if (isHead) { isHead = false; time_t timestamp; env->rtcIo->get(&env->rtcIo, ×tamp); char buf[12]; utoa((uint32_t) timestamp, buf, 10); for (size_t j = 0; j < strlen(buf); ++j) { env->bufAnswer[env->count] = buf[j]; ++env->count; } env->bufAnswer[env->count] = ':'; ++env->count; } env->bufAnswer[env->count] = env->externalAt.rxBuffer.data[i]; ++env->count; } if (env->externalAt.rxBuffer.data[i] == '\n') { break; } } if (isStart) { #ifdef DEBUG_EXT_MODEM LoggerInfoStatic(LOGGER, LOG_SIGN, "Получены данные от АМС."); //LoggerInfo(LOGGER, LOG_SIGN, env->externalAt.rxBuffer.data, env->externalAt.rxBuffer.len); #endif ++env->countPack; } if ((env->countPack >= env->store->nvm.Settings_AmsRadar.AmsRadarNumPack) || (env->countPack >= 5)) { //sendAmsRadar(env->modemMain, env->bufAnswer, env->count); sendExtProtokolPack(env->modemMain, TYPE_FILE_AMS_RADAR, env->bufAnswer, env->count); env->countPack = 0; env->count = 0; return AT_OK; } } } return AT_ERROR; } void AmsRadarProtocol(tExternal *env) { SystemDelayMs(1000); ++env->stepTimeSecond; if (env->stepTimeSecond >= env->store->nvm.Settings_AmsRadar.AmsRadarReqTime * 60) { env->stepTimeSecond = 0; for (int i = 0; i <= 3; ++i) { if (getDataAmsRadar(env, i) == AT_OK) { break; } } } } AtCommandResult getDataLoraWan(tExternal *env) { AtCmdPrepare(&env->externalAt); uint32_t timeout = 1000; uint32_t endMs = SystemGetMs() + timeout; uint32_t leftMs = timeout; while ((AtCmdReceiveNextLine(&env->externalAt, leftMs) == AT_OK) && (SystemGetMs() < endMs)) { leftMs = endMs - SystemGetMs(); if (AtCmdRxBeginWithStatic(&env->externalAt, "JSON up: ")) { env->count = env->externalAt.rxBuffer.len; memcpy(env->bufAnswer, env->externalAt.rxBuffer.data, env->externalAt.rxBuffer.len); sendExtProtokolPack(env->modemMain, TYPE_FILE_LORA_WAN, env->bufAnswer, env->count); AtCmdRxClear(&env->externalAt); return AT_OK; } else { AtCmdProcessUnresolvedLine(&env->externalAt); AtCmdRxClear(&env->externalAt); continue; } } return AT_ERROR; } void LoraWanProtocol(tExternal *env) { // SystemDelayMs(1000); getDataLoraWan(env); } uint16_t getCrcTracer(char *hexCrc) { uint8_t dataCrc[4]; iAsciiStringParseHexBytes(dataCrc, hexCrc, 4); return dataCrc[1] | (dataCrc[0] << 8); } void getSensorAbExt(tExternal *env, uint16_t *sensorA, uint16_t *sensorB, uint8_t *sensorExt) { if (osMutexAcquire(env->sensorAccess, 1000) == osOK) { *sensorA = env->sensorA; *sensorB = env->sensorB; memcpy(sensorExt, env->sensorExt, 16); osMutexRelease(env->sensorAccess); } } void TracerProtocol(tExternal *env) { AtCmdPrepare(&env->externalAt); AtCmdRxClear(&env->externalAt); uint8_t dataAFX[32]; uint8_t dataAF[32]; while (AtCmdReceiveNextLine(&env->externalAt, 1000) == AT_OK) { if (AtCmdRxBeginWithStatic(&env->externalAt, "AFX")) { --env->externalAt.rxBuffer.len; volatile uint16_t crc16 = getCrcTracer( &env->externalAt.rxBuffer.data[env->externalAt.rxBuffer.len - lenHexCRC]); volatile uint16_t crc16calc = CRC16soft((unsigned char *) env->externalAt.rxBuffer.data, env->externalAt.rxBuffer.len - lenHexCRC); memset(dataAFX, 0, sizeof(dataAFX)); if (crc16 == crc16calc) { iAsciiStringParseHexBytes(dataAFX, &env->externalAt.rxBuffer.data[3], env->externalAt.rxBuffer.len - lenHexCRC - 3); if (osMutexAcquire(env->sensorAccess, 1000) == osOK) { for (int i = 0; i < 16; ++i) { env->sensorExt[i] = dataAFX[15 - i]; } osMutexRelease(env->sensorAccess); } } AtCmdRxClear(&env->externalAt); } else if (AtCmdRxBeginWithStatic(&env->externalAt, "AF")) { --env->externalAt.rxBuffer.len; volatile uint16_t crc16 = getCrcTracer( &env->externalAt.rxBuffer.data[env->externalAt.rxBuffer.len - lenHexCRC]); volatile uint16_t crc16calc = CRC16soft((unsigned char *) env->externalAt.rxBuffer.data, env->externalAt.rxBuffer.len - lenHexCRC); memset(dataAF, 0, sizeof(dataAF)); if (crc16 == crc16calc) { iAsciiStringParseHexBytes(dataAF, &env->externalAt.rxBuffer.data[2], env->externalAt.rxBuffer.len - lenHexCRC - 2); if (osMutexAcquire(env->sensorAccess, 1000) == osOK) { env->sensorA = dataAF[2] | (8 << dataAF[1]); env->sensorB = dataAF[5] | (8 << dataAF[4]); osMutexRelease(env->sensorAccess); } } AtCmdRxClear(&env->externalAt); } AtCmdRxClear(&env->externalAt); } } static _Noreturn void External_Thread(tExternal *env) { AtCmdPrepare(&env->externalAt); AtCmdRxClear(&env->externalAt); for (;;) { if (env->store->runtime.Settings_RS485_Bluetooth.PortAssign == PROTOCOL_EXTERNAL) { ExternalProtocol(env); } else if (env->store->runtime.Settings_RS485_Bluetooth.PortAssign == PROTOKOL_AMS_RADAR) { if (env->modemMain->location.isOneDateTime) { SystemDelayMs(1000); continue; } AmsRadarProtocol(env); } else if (env->store->runtime.Settings_RS485_Bluetooth.PortAssign == PROTOKOL_LORA_WAN) { if (env->modemMain->location.isOneDateTime) { SystemDelayMs(1000); continue; } LoraWanProtocol(env); } else if (env->store->runtime.Settings_RS485_Bluetooth.PortAssign == PROTOKOL_TELEMETRY) { TracerProtocol(env); } else { SystemDelayMs(1000); } } } void External_StartThread(tExternal *env) { if (!env->thread.id) { env->thread.id = osThreadNew((osThreadFunc_t) (External_Thread), (void *) (env), &env->thread.attr); } else { osThreadResume(env->thread.id); } }