// // Created by cfif on 04.10.2022. // #include #include #include #include #include "SerialPort.h" #include "string.h" #include "fs_base_func.h" #include #include "ModemReceiveFunc.h" #include "ModemSendFunc.h" #include "ModemSend.h" #define LOGGER env->logger #define LOG_SIGN "GONEC" /* uint16_t crc16(uint8_t *data, size_t data_len) { // uint16_t xor_in = 0x0000; uint16_t xor_out = 0xFFFF; uint16_t poly = 0x1021; uint16_t reg = 0xFFFF; //xor_in; for (size_t octet_idx = 0; octet_idx < data_len; octet_idx++) { uint8_t octet = data[octet_idx]; for (uint8_t bit_idx = 0; bit_idx < 8; bit_idx++) { uint16_t topbit = reg & 0x8000; if (octet & (0x80 >> bit_idx)) { topbit &= 0x8000; } reg <<= 1; reg |= (octet >> (7 - bit_idx)) & 0x1; if (topbit) { reg ^= poly; } } reg &= 0xFFFF; } return reg ^ xor_out; } void TracertSensor_Init(tTracertSensor *env, tSerialPortIO *io, tDeviceStorageIni *store ) { env->io = io; env->store = store; env->sensorAccess = osMutexNew(NULL); AtCmdInit( &env->tracertAt, io, env->mem.modemTx, sizeof(env->mem.modemTx), env->mem.modemRx, sizeof(env->mem.modemRx), 2000, 2000 ); //Инициализируем поток InitThreadAtrStatic(&env->thread.attr, "TracertSensor", env->thread.controlBlock, env->thread.stack, osPriorityNormal); env->thread.id = 0; } void getSensorAbExt(tTracertSensor *env, uint8_t *sensorA, uint8_t *sensorB, uint8_t *sensorExt1, uint8_t *sensorExt2, uint8_t *sensorExt3, uint8_t *sensorExt4) { if (osMutexAcquire(env->sensorAccess, 1000) == osOK) { memcpy(sensorA, env->sensorA, 2); memcpy(sensorB, env->sensorB, 2); memcpy(sensorExt1, env->sensorExt1, 4); memcpy(sensorExt2, env->sensorExt2, 4); memcpy(sensorExt3, env->sensorExt3, 4); memcpy(sensorExt4, env->sensorExt4, 4); osMutexRelease(env->sensorAccess); } } static _Noreturn void TracertSensor_Thread(tTracertSensor *env) { AtCmdPrepare(&env->tracertAt); AtCmdRxClear(&env->tracertAt); uint8_t dataAFX[32]; uint8_t dataAF[32]; for (;;) { while (AtCmdReceiveNextLine(&env->tracertAt, 1000) == AT_OK) { if (AtCmdRxBeginWithStatic(&env->tracertAt, "AFX")) { iAsciiStringParseHexBytes(dataAFX, &env->tracertAt.rxBuffer.data[3], env->tracertAt.rxBuffer.len - 3); uint16_t crc16calc = crc16(dataAFX, 16); uint16_t crc = ((uint16_t *) &dataAFX)[8]; if (osMutexAcquire(env->sensorAccess, 1000) == osOK) { memcpy(env->sensorExt1, &dataAFX[0], 4); memcpy(env->sensorExt2, &dataAFX[4], 4); memcpy(env->sensorExt3, &dataAFX[8], 4); memcpy(env->sensorExt4, &dataAFX[12], 4); osMutexRelease(env->sensorAccess); } AtCmdRxClear(&env->tracertAt); } else if (AtCmdRxBeginWithStatic(&env->tracertAt, "AF")) { iAsciiStringParseHexBytes(dataAF, &env->tracertAt.rxBuffer.data[2], env->tracertAt.rxBuffer.len - 2); if (osMutexAcquire(env->sensorAccess, 1000) == osOK) { env->sensorA[0] = dataAF[1]; env->sensorA[1] = dataAF[2]; env->sensorB[0] = dataAF[4]; env->sensorB[1] = dataAF[8]; osMutexRelease(env->sensorAccess); } AtCmdRxClear(&env->tracertAt); } AtCmdRxClear(&env->tracertAt); } } } */ void TracertMain_Init( tTracertMain *env, tGnss *gnss, tDeviceStorageIni *store, tExternal *external, tFs *fs, tTaskAdc *taskAdc, tRtcIO *rtcIo, tModemMain *modemMain, osMutexId_t accessTracert ) { env->store = store; env->gnss = gnss; env->stepPoint = 0; env->taskAdc = taskAdc; env->external = external; env->fs = fs; env->rtcIO = rtcIo; env->isModemDelAccess = true; env->modemMain = modemMain; env->accessTracert = accessTracert; env->isSpeedCurse = false; /* const uint8_t data[] = {'A', 'F', 'X', 0xe1, 0x98, 0x76, 0x54, 0xe2, 0xab, 0xcd, 0xef, 0xe3, 0x44, 0x55, 0x66, 0xe4, 0x99, 0x88, 0x77}; uint16_t crc16calc = crc16(&data[3], 16); uint8_t buf[16] = { 0x38, 0x7a, 0x76, 0x0e, 0x43, 0x76, 0x4e, 0x2d, 0x65, 0xd5, 0xe0, 0x14, 0x80, 0x00, 0x00, 0x00 }; uint32_t buf[4] = {0x387a760e, 0x43764e2d, 0x65d5e014, 0x80000000}; uint32_t buf[4] = { 0x3e74e77b, 0x43be6582, 0x61e711d0, 0x80000000 }; tStructTracertPoint *structTracertPoint = (tStructTracertPoint *) buf; */ //Инициализируем поток InitThreadAtrStatic(&env->thread.attr, "Tracert", env->thread.controlBlock, env->thread.stack, osPriorityNormal); env->thread.id = 0; } // Создание и запись в файл bool createFileTracert(tTracertMain *env) { FIL file; FRESULT fr; char real_filename[MAX_LEN_PATH_FS]; ++env->store->nvm.maxId_OutBox; if (env->store->nvm.maxId_OutBox > 32767) env->store->nvm.maxId_OutBox = 1; DeviceStorageCounterIni_Dump(env->store); // Запись заголовка в файл char buf[9]; char BufFileWrite[512]; BufFileWrite[0] = '\0'; strcat(BufFileWrite, "&from="); utoa(env->store->nvm.Settings_General.ATnum_v, &BufFileWrite[strlen(BufFileWrite)], 10); strcat(BufFileWrite, "&to="); utoa(env->store->nvm.Settings_Tracert.TrATsrv_v, buf, 10); strcat(BufFileWrite, buf); strcat(BufFileWrite, "&chSv=1"); strcat(BufFileWrite, "&mnum="); utoa(env->store->nvm.maxId_OutBox, buf, 10); strcat(BufFileWrite, buf); strcat(BufFileWrite, "&urgency=0"); strcat(BufFileWrite, "&type=1"); strcat(BufFileWrite, "&sos=0"); strcat(BufFileWrite, "&kvs=0"); strcat(BufFileWrite, "&subj=file&msg="); createFileNameForId(real_filename, "", env->store->nvm.maxId_OutBox, "DAT"); strcat(BufFileWrite, real_filename); createFileNameForId(real_filename, (char *) dir_tracert, env->store->nvm.maxId_OutBox, "OTM"); fr = f_open_i(env->fs, &file, (TCHAR *) real_filename, FA_WRITE | FA_CREATE_ALWAYS); if (fr) return false; UINT bytes_written; fr = f_write_i(env->fs, &file, BufFileWrite, strlen(BufFileWrite), &bytes_written); fr = f_close_i(env->fs, &file); createFileNameForId(real_filename, (char *) dir_tracert, env->store->nvm.maxId_OutBox, "DAT"); fr = f_open_i(env->fs, &file, (TCHAR *) real_filename, FA_WRITE | FA_CREATE_ALWAYS); if (fr) return false; fr = f_write_i(env->fs, &file, env->bufTracert, env->posInBlock, &bytes_written); fr = f_close_i(env->fs, &file); return true; } // Удаление самого старого файла void getDelOldTracert(tTracertMain *env) { FRESULT fr; DIR dj; FILINFO fno; FILINFO fnoInf; FRESULT frInf; char strId[MAX_LEN_PATH_FS]; strId[0] = '\0'; uint32_t minNum = 0xFFFFFFFF; fr = f_findfirst_i(env->fs, &dj, &fno, dir_tracert, "*.OTM"); char path_Old_fileName[MAX_LEN_PATH_FS]; path_Old_fileName[0] = '\0'; while (fr == FR_OK && fno.fname[0]) { // Полный путь с именем файла до файла исходящего сообщения REP char path_tracert_fileName[MAX_LEN_PATH_FS]; path_tracert_fileName[0] = '\0'; strcat(path_tracert_fileName, dir_tracert); strcat(path_tracert_fileName, fno.fname); uint32_t Num = atoi(&fno.fname[0]); // Самый старый файл frInf = f_stat(path_tracert_fileName, &fnoInf); if (frInf == FR_OK) { if (Num < minNum) { minNum = Num; path_Old_fileName[0] = '\0'; strcat(path_Old_fileName, path_tracert_fileName); } } fr = f_findnext_i(env->fs, &dj, &fno); } fr = f_closedir_i(env->fs, &dj); fr = f_unlink_i(env->fs, path_Old_fileName); } static uint32_t reverse32(uint32_t x) { x = (x & 0x00FF00FF) << 8 | (x & 0xFF00FF00) >> 8; x = (x & 0x0000FFFF) << 16 | (x & 0xFFFF0000) >> 16; return x; } static uint32_t toFrOfMin(double d) { if (d < 1) d += 1; double orig = d; uint32_t kf = 1; uint32_t test = (uint32_t) d; uint32_t count = 0; while (test != d) { ++count; d *= 10; test = (uint32_t) d; kf *= 10; if (count >= 5) break; } uint32_t result = kf * (orig - (uint32_t) orig); return result; } uint16_t minShare(double frMin) { return (uint16_t) (frMin * 10000); /* uint16_t LIM = 0b1111111111111; if (frMin < 0.1) { return 0; } uint32_t val = 0; uint32_t mux = 1; do { mux *= 10; val = frMin * mux; if (val == 0) { return val; } if ((val > LIM)) { mux /= 10; break; } } while (1); val = frMin * mux; while (val && ((val % 10) == 0)) { val /= 10; } return val; */ } void cConvertFrDegTracer(double frDeg, uint8_t latLonFlag, uint8_t *data) { uint8_t direction = frDeg > 0 ? 0 : 1; int8_t fullDeg = (int8_t) (frDeg); double frMin = (frDeg - fullDeg) * 60.0; int8_t fullMin = (int8_t) frMin; //int16_t frOfMin = (int16_t) ((frMin - fullMin) * 8192); uint8_t absFullDeg = (uint8_t) abs((int) fullDeg); uint8_t absFullMin = abs(fullMin); if (frMin < 0) frMin *= -1; uint16_t absFrOfMin = minShare(frMin - (uint16_t) frMin); //uint16_t absFrOfMin = abs(frOfMin); /* uint32_t result = (0b01 << 30) | ((latLonFlag & 0b1) << 29) | ((direction) << 28) | ((absFullDeg) << 20) | ((absFullMin & 0b111111) << 14) | ((absFrOfMin & 0b11111111111111)) << 0; */ tStructTracertCoord *structTracertCoord = (tStructTracertCoord *) data; structTracertCoord->absFrOfMin = absFrOfMin; // 14: Доли минут после точки structTracertCoord->absFullMin = absFullMin; // 6: Минуты structTracertCoord->absFullDeg = absFullDeg; // 8: Градусы structTracertCoord->direction = direction; // Полушарие structTracertCoord->latLonFlag = latLonFlag; // Признак широты structTracertCoord->data_static = 1; // 01 - Резерв } //int8_t temp2; static _Noreturn void TracertMain_Thread(tTracertMain *env) { /* uint8_t dataPK[] = {0x5d, 0x6a, 0xad, 0xe5, 0x43, 0x4b, 0x24, 0x29, 0x62, 0x96, 0xa1, 0xdc, 0x88, 0x10, 0x00, 0x00, 0x91, 0xa0, 0x10, 0x00}; uint8_t dataPK2[] = {0x5d, 0x6c, 0xb6, 0xa0, 0x43, 0x4b, 0x23, 0x40, 0x62, 0x96, 0x9f, 0xb6, 0x88, 0x11, 0x54, 0x00, 0x91, 0xa4, 0x28, 0x00}; tStructTracertPoint *test = (tStructTracertPoint *) &dataPK2[0]; */ /* uint8_t dataPK[] = {0x5d, 0x42, 0xF5, 0x85, 0x53, 0xbd, 0xc3, 0xe7, 0x71, 0xe3, 0x80, 0x00, 0x88, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00}; tStructTracertPoint *test = (tStructTracertPoint *) &dataPK[0]; */ uint32_t maxBuf = env->store->nvm.Settings_Tracert.MaxBuf_v; env->isModemCreateAccess = true; for (;;) { // Ждать ГНСС if (env->store->nvm.Settings_Tracert.TransferCoordSettings_v == 0) { if (env->modemMain->location.isOneValidGnss) { SystemDelayMs(100); continue; } } // Ждать только времени с ГНСС или ПК // if ((env->modemMain->location.isOneDateTime) || (env->modemMain->location.isOneValidGnss)) { if (env->modemMain->location.isOneDateTime) { SystemDelayMs(100); continue; } if (env->store->nvm.Settings_Tracert.PeSvCoor_v > 0) { if (env->store->nvm.Settings_Tracert.mTracer_v > 0) { env->isModemDelAccess = true; } } // Трассировка не работает (удаление файлов из отправки) if ((env->store->nvm.Settings_Tracert.PeSvCoor_v == 0) || (env->store->nvm.Settings_Tracert.mTracer_v == 0)) { if (env->isModemDelAccess) { // Удаление всех файлов трассировки // delDirFileFs(env->fs, (char *) dir_tracert); env->isModemCreateAccess = true; env->isModemDelAccess = false; env->modemMain->stateRequest.stateReqDelExtT = StateReqExtForDel; } env->stepPoint = 0; SystemDelayMs(100); continue; } // Включение трассировки, после выключения if (env->isModemCreateAccess) { delRepout(env->modemMain, TYPE_FILE_TRACERT, true, false); env->isModemCreateAccess = false; env->modemMain->stateRequest.stateReqCreateExtT = StateReqExtForCreate; // SystemDelayMs(100); } // начало --------------------------- Заголовок ----------------------------------------------------------------------- if (env->stepPoint == 0) { env->isSpeedCurse = false; // Передача курса и скорости if (env->store->nvm.Settings_Tracert.trSendSpeed_v) { env->isSpeedCurse = true; } // Передача доп. данных env->isDataAddition = false; if (env->store->nvm.Settings_Tracert.TransmissionModeData == 1) { env->isDataAddition = true; } uint8_t headerTracert[16] = {0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x74, 0x6e, 0x64, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00}; tStructTracertHeader *structTracertHeader = (tStructTracertHeader *) headerTracert; structTracertHeader->len = 16; if (env->isSpeedCurse) { structTracertHeader->len = 20; } if (env->isDataAddition) { structTracertHeader->len = 32; } structTracertHeader->nAt[0] = env->store->nvm.Settings_General.ATnum_v; structTracertHeader->nAt[1] = env->store->nvm.Settings_General.ATnum_v >> 8; structTracertHeader->nAt[2] = env->store->nvm.Settings_General.ATnum_v >> 16; env->posInBlock = sizeof(tStructTracertHeader); memcpy(env->bufTracert, headerTracert, sizeof(tStructTracertHeader)); } // конец --------------------------- Заголовок ----------------------------------------------------------------------- // начало -------------------------- Дата/Время----------------------------------------------------------------------- struct tm time; //env->rtcIO->getTM(&env->rtcIO, &time); time_t timestamp; env->rtcIO->get(&env->rtcIO, ×tamp); localtime_r(×tamp, &time); /* uint32_t dateTime2 = (((time.tm_year - 100) & 0b111111) << 26) | ((time.tm_mon & 0b1111) << 22) | ((time.tm_mday & 0b11111) << 17) | ((time.tm_hour & 0b11111) << 12) | ((time.tm_min & 0b111111) << 6) | ((time.tm_sec & 0b111111) << 0); */ uint8_t dateTime[4] = {0, 0, 0, 0}; tStructTracertDateTime *structTracertDateTime = (tStructTracertDateTime *) &dateTime[0]; structTracertDateTime->sec = time.tm_sec; // Секунды structTracertDateTime->min = time.tm_min; // Минуты structTracertDateTime->hour = time.tm_hour; // Часы structTracertDateTime->day = time.tm_mday; // День structTracertDateTime->mouth = time.tm_mon + 1; // Месяц structTracertDateTime->year = time.tm_year - 100; // Год memcpy(&env->bufTracert[env->posInBlock], &dateTime[0], 4); env->posInBlock += 4; tTracertNavData location; // конец -------------------------- Дата/Время----------------------------------------------------------------------- // начало ------------------------ Широта/Долгота-------------------------------------------------------------------- uint8_t latitude[4] = {0, 0, 0, 0}; uint8_t longitude[4] = {0, 0, 0, 0}; // Координаты с ГНСС не были получены никогда if (env->modemMain->location.isOneValidGnss) { cConvertFrDegTracer(env->modemMain->location.latitude, 0, &latitude[0]); cConvertFrDegTracer(env->modemMain->location.longitude, 1, &longitude[0]); location.speed = 0; location.curse = 0; // char bufText[128]; // bufText[0] = '\0'; // strcat(bufText, "Координаты (по умолчанию) "); // char buf[12]; // utoa((uint32_t) env->modemMain->location.latitude, buf, 10); // strcat(bufText, buf); // strcat(bufText, ", "); // utoa((uint32_t) env->modemMain->location.longitude, buf, 10); // strcat(bufText, buf); // LoggerInfo(LOGGER, LOG_SIGN, bufText, strlen(bufText)); } else { Gnss_GetNavDataTracert(env->gnss, &location); cConvertFrDegTracer(location.gnss_latitude, 0, &latitude[0]); cConvertFrDegTracer(location.gnss_longitude, 1, &longitude[0]); // char bufText[128]; // bufText[0] = '\0'; // strcat(bufText, "Координаты (с ГНСС) "); // char buf[12]; // utoa((uint32_t) location.gnss_latitude, buf, 10); // strcat(bufText, buf); // strcat(bufText, ", "); // utoa((uint32_t) location.gnss_longitude, buf, 10); // strcat(bufText, buf); // LoggerInfo(LOGGER, LOG_SIGN, bufText, strlen(bufText)); } memcpy(&env->bufTracert[env->posInBlock], &latitude[0], 4); env->posInBlock += 4; memcpy(&env->bufTracert[env->posInBlock], &longitude[0], 4); env->posInBlock += 4; // конец ------------------------ Широта/Долгота-------------------------------------------------------------------- uint16_t sensorA; uint16_t sensorB; uint8_t sensorExt[16]; getSensorAbExt(env->external, &sensorA, &sensorB, sensorExt); // начало ---------------------------Датчики------------------------------------------------------------------------ /* uint32_t IG = 0; // Зажигание uint32_t AL = 0; // Тревога uint32_t D1 = 0; // Датчик вскрытия uint32_t D2 = 0; // uint32_t D3 = 0; // uint32_t EC = 0; // Признак слова курса if (env->isSpeedCurse) { EC = 1; // Признак слова курса } uint32_t SensorABPoint2 = (8 << 28) | ((EC & 0b1) << 27) | ((D3 & 0b1) << 24) | ((D2 & 0b1) << 23) | ((D1 & 0b1) << 22) | ((AL & 0b1) << 21) | ((IG & 0b1) << 20) | ((sensorB & 0b1111111111) << 10) | ((sensorA & 0b1111111111) << 0); */ uint8_t SensorABPoint[4] = {0, 0, 0, 0}; tStructTracertSensorAB *structTracertSensorAB = (tStructTracertSensorAB *) &SensorABPoint[0]; structTracertSensorAB->sensor_A = sensorA; // structTracertSensorAB->sensor_B = sensorB; // structTracertSensorAB->IG = 0; // Зажигание structTracertSensorAB->AL = 0; // Тревога structTracertSensorAB->D1 = 0; // Датчик вскрытия structTracertSensorAB->D2 = 0; // structTracertSensorAB->D3 = 0; // structTracertSensorAB->reserver2 = 0; structTracertSensorAB->EC = 0; // Признак слова курса if (env->isSpeedCurse) { structTracertSensorAB->EC = 1; // Признак слова курса } structTracertSensorAB->id_static = 8; // 1000 // Передача напряжения if (env->store->nvm.Settings_Tracert.SensorAD0volt_v) { uint32_t vcc = getVcc(env->taskAdc) / 1000; structTracertSensorAB->sensor_A = vcc; } memcpy(&env->bufTracert[env->posInBlock], &SensorABPoint[0], 4); env->posInBlock += 4; // конец ---------------------------Датчики---------------------------------------------------------------------- // начало --------------------------Курс и скорость------------------------------------------------------------- if (env->isSpeedCurse) { /* uint32_t SpeedCursePoint2 = (9 << 28) | ((location.temperature & 0b11111111) << 19) | ((location.curse & 0b111111111) << 10) | ((location.speed & 0b1111111111) << 0); */ uint8_t SpeedCursePoint[4] = {0, 0, 0, 0}; tStructTracertSpeedCursePoint *structTracertSpeedCursePoint = (tStructTracertSpeedCursePoint *) &SpeedCursePoint[0]; structTracertSpeedCursePoint->speed = location.speed; structTracertSpeedCursePoint->curse = location.curse; uint8_t temp; if (env->modemMain->temp < 0) { temp = (env->modemMain->temp * -1); temp |= 0x80; } else { temp = env->modemMain->temp; } structTracertSpeedCursePoint->temperature = temp; structTracertSpeedCursePoint->reserved = 0; structTracertSpeedCursePoint->id_static = 9; // 1001 memcpy(&env->bufTracert[env->posInBlock], &SpeedCursePoint[0], 4); env->posInBlock += 4; } // конец --------------------------Курс и скорость------------------------------------------------------------- // начало ---------------------------Доп данные------------------------------------------------------------------ if (env->isDataAddition) { if (env->isSpeedCurse) { memcpy(&env->bufTracert[env->posInBlock], &sensorExt[4], 12); env->posInBlock += 12; } else { memcpy(&env->bufTracert[env->posInBlock], &sensorExt[0], 16); env->posInBlock += 16; } } // конец ---------------------------Доп данные------------------------------------------------------------------- volatile tStructTracertPoint *structTracertPoint = (tStructTracertPoint *) &env->bufTracert[16]; ++env->stepPoint; if ((env->stepPoint >= env->store->nvm.Settings_Tracert.minPtoSe_v) || ((env->stepPoint >= 38))) { env->stepPoint = 0; env->rtcIO->get(&env->rtcIO, ×tamp); while (env->modemMain->isEnableTracerTimeStamp >= (uint32_t) timestamp) { env->rtcIO->get(&env->rtcIO, ×tamp); SystemDelayMs(1000); } if (osMutexAcquire(env->accessTracert, 2000) == osOK) { createFileTracert(env); // Количество файлов в tracert uint32_t count = getCountFiles(env->modemMain, (char *) dir_tracert); while (count > env->store->nvm.Settings_Tracert.MaxFiles_v) { // Удаление самого старого файла tracert delFilesOld(env->modemMain, (char *) dir_tracert); // Количество файлов в tracert count = getCountFiles(env->modemMain, (char *) dir_tracert); } env->rtcIO->get(&env->rtcIO, &env->modemMain->eventWebState.EVENT_TRACERT); // Чтобы не запрашивать лишний раз модем. Если в трассировке уже есть максимум файлов для отправки. if (getCountTracertInRepoutCute(env->fs, env->store->nvm.Settings_Tracert.MaxBuf_v) < env->store->nvm.Settings_Tracert.MaxBuf_v) env->modemMain->stateRequest.stateReqCreateExtT = StateReqExtForCreate; osMutexRelease(env->accessTracert); } } for (uint32_t i = 0; i < env->store->nvm.Settings_Tracert.PeSvCoor_v; ++i) { if ((env->store->nvm.Settings_Tracert.PeSvCoor_v == 0) || (env->store->nvm.Settings_Tracert.mTracer_v == 0)) { break; } if (maxBuf != env->store->nvm.Settings_Tracert.MaxBuf_v) { maxBuf = env->store->nvm.Settings_Tracert.MaxBuf_v; delRepout(env->modemMain, TYPE_FILE_TRACERT, true, false); env->modemMain->stateRequest.stateReqCreateExtT = StateReqExtForCreate; } SystemDelayMs(1000); } } } void TracertMain_StartThread(tTracertMain *env) { if (!env->thread.id) { env->thread.id = osThreadNew((osThreadFunc_t) (TracertMain_Thread), (void *) (env), &env->thread.attr); } else { osThreadResume(env->thread.id); } } /* void TracertSensor_StartThread(tTracertSensor *env) { if (!env->thread.id) { env->thread.id = osThreadNew((osThreadFunc_t) (TracertSensor_Thread), (void *) (env), &env->thread.attr); } else { osThreadResume(env->thread.id); } } */