503 lines
15 KiB
C
503 lines
15 KiB
C
//
|
||
// Created by cfif on 04.10.2022.
|
||
//
|
||
|
||
#include <stddef.h>
|
||
#include <SystemDelayInterface.h>
|
||
#include <External.h>
|
||
#include <CmsisRtosThreadUtils.h>
|
||
#include "SerialPort.h"
|
||
#include "string.h"
|
||
#include "fs_base_func.h"
|
||
#include <stdlib.h>
|
||
#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);
|
||
}
|
||
} |