GONEC_ARTERY_External/Src/External.c

503 lines
15 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// 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, &timestamp);
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);
}
}