diff --git a/src/CAN_FW.h b/src/CAN_FW.h index b83a97b..45bd790 100644 --- a/src/CAN_FW.h +++ b/src/CAN_FW.h @@ -6,12 +6,44 @@ #include "Periodic.h" #include "Can.h" -#define CAN_FW_DESCRIPTION "Test" +enum TPeriodicTasks +{ + PELightButton, // Задача управления триггерной кнопкой. + PeriodicCount, // количество задач +}; // структура с пользовательскими переменными struct TCanFwMem { - CSettings::TSettings Settings; // структура с настройками - должна быть всегда в начале + CSettings::TSettings Settings; // структура с настройками - должна быть всегда в начале + CPeriodic PeriodicTask; + bool ign; // флаг зажигания + bool arm; + bool prearm; // предыдущий статус охраны автомобиля + bool cmf; // флаг "комфорт" + bool mirror; // флаг "сложить зеркала" + + struct{ + bool hazlamp; // состояние аварийки (любой) + bool seized; // Флаг захвата кнопки аварийки + uint8_t step; // Шаги функции Emergency Light Button + TimerMs tmr; // Таймер сбрасывается в момент фронта/спада автомобильной (не нашей!) аварийки + uint8_t cnt; + } ELight; + + struct{ + bool multipkt; + uint8_t mode; + uint8_t pid; + char vin[17]; + } Diag; }; +void Wake_CAN (TCanFwMem * vars); +void ELight_Button2 (TCanFwMem * vars); + +// OBDII +void DiagRcv (TCanFwMem * vars, TCanPkt * pkt, TCanChannel channel); +void DiagReq (TCanFwMem * vars, uint8_t mode, uint8_t pid, TCanChannel channel); + #endif /* CAN_FW_H_ */ diff --git a/src/CAN_Inputs.h b/src/CAN_Inputs.h index 7755ff4..2c36a40 100644 --- a/src/CAN_Inputs.h +++ b/src/CAN_Inputs.h @@ -2,21 +2,186 @@ #include "Can.h" #include "IO.h" #include "Utils.h" - +#include "myfunc/VinReq.h" +#include "myfunc/_MFM3.h" void Init (TCanFwMem * vars) { - CoreFunc->DebugConsole("CAN_FW version: %s\n", (const char*)(gCanFwInfo.TextInfo)); + static const TCanInit can1_init = + { + CCan::CanBaudrate500, + 1, + { + CCan::Filter::List11 (0x010, 0x020), + CCan::Filter::List11 (0x040, 0x0E0), + CCan::Filter::List11 (0x095, 0x100), + CCan::Filter::List11 (0x300, 0x310), + CCan::Filter::List11 (0x334, 0x355), - static const TCanInit can1_init = - { - CCan::CanBaudrate500, - 1, - { - CCan::Filter::List11 (0x660), - CCan::Filter::Mask11 (0x7E0, 0x7F0), // 0x7E0..0x7EF - } - }; - CoreFunc->CanInit (CANch1, &can1_init); + CCan::Filter::List11 (0x380), + CCan::Filter::List11 (0x0C3, 0x210), + } + }; + CoreFunc->CanInit (CANch1, &can1_init); +//--------------------------------------------------------- + static const TCanInit can2_init = + { + CCan::CanBaudrate500, + 1, + { + CCan::Filter::List11 (0x04B, 0x050), + CCan::Filter::List11 (0x111, 0x138), + CCan::Filter::Mask11 (0x7E0, 0x7F0), + } + }; + CoreFunc->CanInit (CANch2, &can2_init); +//--------------------------------------------------------- + vars->PeriodicTask.AddTask (PELightButton, ELight_Button2); +} + +void Can1Received (TCanFwMem * vars, TCanPkt *apPkt) +{ + // int32_t temp; // знаковое! + // int16_t tmp; // знаковое! + uint8_t * buf = apPkt->data; + TCanPkt pkt; + TCanPkt pktm; + + switch (apPkt->id) + { + case 0x010: + CoreFunc->InputState (CIO::iLock, (Rx_D & 0x0C)==0x08); + break; + + case 0x040: + CoreFunc->InputState (CIO::iDoorDrv, (Rx_G & 0xC0)==0x40); + CoreFunc->InputState (CIO::iDoorRL, (Rx_F & 0x0C)==0x04); + + if (vars->cmf) + { + pkt = *apPkt; + pkt.data[4] |= 0x0A; + CoreFunc->CanSend (CANch1, &pkt, 7); + CoreFunc->CanSend (CANch1, &pkt, 17); + vars->cmf = false; + } + break; + + case 0x0E0: + CoreFunc->InputState (CIO::iDoorFP, (Rx_D & 0xC0)==0x40); + CoreFunc->InputState (CIO::iDoorRR, (Rx_B & 0x30)==0x10); + CoreFunc->InputState (CIO::iTrunk, (Rx_F & 0xC0)==0x40); + break; + + case 0x095: + if (Rx_A == 0x52) CoreFunc->Command (CoreCmdTrunkOpened, 0x04); // Br-Hf + break; + + case 0x100: + + if (Rx_B == 0x1F || Rx_B == 0x2F || Rx_B == 0x9F) CoreFunc->Command (CoreCmdArm, 0x04); // Br, HF-L,R + else if (Rx_B == 0x17 || Rx_B == 0x27 || Rx_B == 0x97) CoreFunc->Command (CoreCmdDisarm, 0x04); // Br, HF-L,R +/* + if (vars->mirror) не закрывается и зеркала зависают + { + pktm = *apPkt; + pktm.data[1] == 0x1F; + // попробовать это !!! pktm.data[7] |= 0x08; + for (int i=0; i<30; i++) CoreFunc->CanSend (CANch1, &pktm, 30); + vars->mirror = false; + } + */ + break; + case 0x210: + CoreFunc->DataValue (CanData_CoolantTemp, Rx_C - 10); + break; + + //case 0x270: XC90 + //CoreFunc->DataValue (CanData_FuelLevel, buf[6]*100/256);// + // break; + + case 0x300: + CoreFunc->DataValue (CanData_RPM, (Rx_C << 8 | Rx_D) >> 1); + break; + case 0x310: + CoreFunc->DataValue (CanData_Odometer, ((Rx_A & 0x0F) <<16 | buf[1]<<8 | buf[2]) * 10); + break; + + case 0x334: + CoreFunc->InputState (CIO::iLeftTurnLight, Rx_H & BIT(4)); + CoreFunc->InputState (CIO::iRightTurnLight, Rx_H & BIT(2)); + CoreFunc->InputState (CIO::iEmergency, (Rx_H & 0x14) == 0x14); + break; + case 0x355: + CoreFunc->InputState (CIO::iLauncher, Rx_F & 0x03); + break; + + case 0x000: + // CoreFunc->InputState (CIO::iLamp, Rx_B & BIT(2)); // от XC90 не подходит ID0C3 + // CoreFunc->DataValue (CanData_Speed, (Rx_B << 8 | Rx_C)>>4); + // CoreFunc->DataValue (CanData_FuelLevel, Rx_H); // от XC90 не подходит ID310 + // CoreFunc->DataValue (CanData_FuelConsumption, Rx_C); + break; + } +} +void Can2Received (TCanFwMem * vars, TCanPkt *apPkt) +{ + // int32_t temp; // знаковое! + // int16_t tmp; // знаковое! + uint8_t * buf = apPkt->data; + + switch (apPkt->id) + { + + case 0x04B: + CoreFunc->InputState (CIO::iPark, (Rx_D & 0x0E) == 0x00); + break; + case 0x050: + Rx_C = Rx_C/2; + if (Rx_C > 100) Rx_C = 100; + CoreFunc->DataValue (CanData_Accelerator, Rx_C); + break; + case 0x111: + CoreFunc->InputState (CIO::iIgn, Rx_C & BIT(7)); + break; + case 0x138: + //CoreFunc->InputState (CIO::iHBrake, (Rx_A & 0x0C)==0x04); // ID144 + CoreFunc->DataValue (CanData_BrakeForce,(Rx_E << 8 | Rx_F)/20); + CoreFunc->InputState (CIO::iBrake, Rx_E ); + break; + + case 0x2B0: + //tmp = Rx_D << 8 | Rx_E ; + //CoreFunc->DataValue (CanData_WheelAngle, tmp); + break; + } + +} + +void InputChanged (TCanFwMem * vars, uint32_t aInputNum, bool aSwitchedOn) +{ +// TCanPkt pkt; + + if ((aInputNum == CIO::iIgn) && ! aSwitchedOn) + { + CoreFunc->InputState (CIO::iBrake, false); + CoreFunc->DataValue (CanData_Invalid | CanData_RPM, 0); + } + + if (aInputNum == CIO::iIgn) vars->ign = aSwitchedOn; + + if (aInputNum == CIO::iEmergency) + { + vars->ELight.hazlamp = aSwitchedOn; + + if (!vars->ELight.seized) vars->ELight.tmr.Restart (); // при собственных моргках таймер не перезапускаем + //tt(aSwitchedOn); + } +} + +void GuardEvent (TCanFwMem * vars, TGuardEvents aEvent) +{ + if (aEvent == geARM) vars->arm = true; + if (aEvent == geDISARM) vars->arm = false; } \ No newline at end of file diff --git a/src/CAN_Outputs.h b/src/CAN_Outputs.h index cce6be2..4834095 100644 --- a/src/CAN_Outputs.h +++ b/src/CAN_Outputs.h @@ -3,3 +3,129 @@ #include "IO.h" #include "Utils.h" +void OutputChanged (TCanFwMem * vars, uint32_t aOutputNum, bool aSwitchedOn) +{ + TCanPkt pkt; + + switch (aOutputNum) + { + case CIO::oLights: + if(aSwitchedOn) + { + if (vars->ELight.tmr.Value() > 800 && vars->ELight.step == 0) + { + CoreFunc->RunSequence(SEQ(oEmergency, seqProg8)); // Выход на кнопку аварийки импульс 250 ms + vars->PeriodicTask.SetTimeout (PELightButton, 260); + vars->ELight.step++; + vars->ELight.cnt = 0; + vars->ELight.seized = true; + //tt(0x10); + } + } + break; + + case CIO::oCloseWindows: + if (aSwitchedOn) vars->cmf = true; + break; + + + case CIO::oFoldMirrors: + if (aSwitchedOn) vars->mirror = true; + break; + } +} + +void ELight_Button2(TCanFwMem * vars) // Нажатия на триггерную кнопку аварийки с ожиданием вспышки +{ + switch (vars->ELight.step) + { + case 1: + if (!vars->ELight.hazlamp) + { + if (vars->ELight.cnt < 8) // ожидаем когда лампа загориться + { + vars->PeriodicTask.SetTimeout (PELightButton, 50); // подождем еще + vars->ELight.cnt++; + //tt(0x15); + } + else {vars->ELight.step = 0; /*tt(3);*/} // не удалось зажечь + } + else // если лампа загорелась (~440mS для Monjaro) + { + vars->PeriodicTask.SetTimeout (PELightButton, 150); // пусть погорит хотя бы 150mS + vars->ELight.step++; + //tt(0x20); + } + break; + case 2: // лампа горит уже 150m + CoreFunc->RunSequence(SEQ(oEmergency, seqProg9)); // гасим ее импульсом не менее 150 мс ( 100mS для Monjaro мало) + vars->PeriodicTask.SetTimeout (PELightButton, 160); + vars->ELight.step++; + break; + case 3: + if (!vars->ELight.hazlamp) // ожидаем когда лампа погаснет + { + + vars->ELight.step = 0; + vars->ELight.seized = false; + //tt(0x0F); + } + else vars->PeriodicTask.SetTimeout (PELightButton, 10); + break; + } +} + + +// события arm, disarm, alarm, ... +void Command (TCanFwMem * vars, TCanFwCommands aCmd, uint32_t aCmdParam) +{ + TCanPkt pkt; + uint8_t i; + + switch (aCmd) + { + + case ccLockDoors: + Wake_CAN(vars); + pkt.id = 0x020; + pkt.data_len = 8; + pkt.SetData("\x28\x12\x28\x2B\xAA\x00\x00\x68"); // FL=0x2X RL=0xX2 FR=0x2X RR=0x2X + for (i=0; i<4; i++) CoreFunc->CanSend (CANch1, &pkt, 18); + break; + case ccUnLockDoors: // можно сделать mccPriority + Wake_CAN(vars); + pkt.id = 0x020; + pkt.data_len = 8; + pkt.SetData("\x18\x11\x18\x1B\xAA\x00\x00\x68"); + for (i=0; i<4; i++) CoreFunc->CanSend (CANch1, &pkt, 18); + break; + + case ccSendObdReq: + pkt.id = 0x7DF; + pkt.data_len = 8; + pkt.data[0] = 0x01; + pkt.data[1] = aCmdParam; + CoreFunc->CanSend (CANch2, &pkt, 1); + break; + case ccUpdateVin: // отправить запрос VIN-кода + DiagReq (vars, 0x09, 0x02, CANch2); + break; + + default: break; + } +} + +//============== Пробуждение ================================================== +void Wake_CAN(TCanFwMem * vars) +{ + TCanPkt pkt; +// uint8_t i; + + if (CoreFunc->CanGetRxTimeout (CANch1) < 1000) return; // Если шина не спит то не будим! + + pkt.id = 0x501; + pkt.data_len = 8; + pkt.SetData("\x01\x40\x26\x00\x01"); + CoreFunc->CanSend (CANch1, &pkt, 2); + CoreFunc->CanSend (CANch1, &pkt, 20); +} \ No newline at end of file diff --git a/src/SettingsCANTable.h b/src/SettingsCANTable.h index 6739ada..0097582 100644 --- a/src/SettingsCANTable.h +++ b/src/SettingsCANTable.h @@ -1,10 +1,24 @@ -//===================================================================================== +#define iWireLock iDevice6 +#define iWireUnlock iDevice7 +#define iEmergency iDevice8 +#define oWireLock oDevice6 +#define oWireUnlock oDevice7 +#define oEmergency oDevice8 -// SETTING_RSRV позволяет сделать "дырки" в номерах настроек -// если не определена, значит, она не используется -#ifndef SETTING_RSRV -#define SETTING_RSRV(name) -#endif +/** Новая классификация прошивок ** + + (A) - Обычный обходчик + (B) - Baypass + (С) - Запуск через штатную CAN команду + (E) - Электрический автомобиль + + Правила нумерации версий: + release - меняется только при появлении существенно новой версии приложения. Обратная совместимость может не обеспечиваться. + version - меняется при появлении новых возможостей. + update - меняется при исправлении ошибок в текущей версии. +*/ + + #define CAN_FW_DESCRIPTION "Geely_Atlas2024_[C]" //************************** Динамические параметры ***********************************************// diff --git a/src/myfunc/VinReq.h b/src/myfunc/VinReq.h new file mode 100644 index 0000000..5b96e32 --- /dev/null +++ b/src/myfunc/VinReq.h @@ -0,0 +1,79 @@ +#include "CAN_FW.h" +#include "Can.h" +#include + +void DiagReq (TCanFwMem * vars, uint8_t mode, uint8_t pid, TCanChannel channel) +{ + TCanPkt req; + req.id = 0x7DF; + req.SetData ("\x02\x00\x00"); + req.data_len = 8; + req.data[1] = mode; + req.data[2] = pid; + CoreFunc->CanSend (channel, &req, 0); + + vars->Diag.mode = mode; + vars->Diag.pid = pid; +} + + +void DiagRcv (TCanFwMem * vars, TCanPkt * pkt, TCanChannel channel) +{ + uint8_t * buf = pkt->data; + + // заголовок мультипакета + if (buf[0] == 0x10) + { + uint8_t mode = buf[2] & (~0x40); + uint8_t pid = buf[3]; + + // отправить flow control + if (mode == vars->Diag.mode && + pid == vars->Diag.pid) + { + TCanPkt fc; + fc.id = 0x7E0; + fc.SetData ("\x30\x00\x00"); + fc.data_len = 8; + CoreFunc->CanSend (channel, &fc, 0); + + vars->Diag.multipkt = true; + } + else + { + // сбросить автомат + vars->Diag.mode = vars->Diag.pid = 0; + return; + } + + // заголовок мультипакета с VIN-кодом + if (mode == 9 && pid == 2) + memcpy (vars->Diag.vin, &buf[5], 3); + + } + // тело мультипакета + else + if (((buf[0] & 0xF0) == 0x20) && vars->Diag.multipkt) + { + uint8_t cnt = buf[0] & 0x0F; + + // мультипакет с VIN-кодом + if (vars->Diag.mode == 9 && vars->Diag.pid == 2) + { + if (cnt == 1) + memcpy (&vars->Diag.vin[3], &buf[1], 7); + if (cnt == 2) + { + memcpy (&vars->Diag.vin[10], &buf[1], 7); + + // сообщить в ядро о приёме пакета + CoreFunc->DataValueArr (CanData_VIN, vars->Diag.vin); + + // сбросить автомат + vars->Diag.mode = vars->Diag.pid = 0; + } + } + } + else + vars->Diag.multipkt = false; +} diff --git a/src/myfunc/_MFM3.h b/src/myfunc/_MFM3.h new file mode 100644 index 0000000..7de998c --- /dev/null +++ b/src/myfunc/_MFM3.h @@ -0,0 +1,119 @@ +#include "CAN_FW.h" +#include "Can.h" + +#define Rx_DLC apPkt->data_len +#define Rx_A buf[0] +#define Rx_B buf[1] +#define Rx_C buf[2] +#define Rx_D buf[3] +#define Rx_E buf[4] +#define Rx_F buf[5] +#define Rx_G buf[6] +#define Rx_H buf[7] + +uint16_t bcd (uint16_t hexdata) +{ + uint16_t x; + uint8_t i; + + if ( hexdata > 9999) return 0xFFFF; + + x = hexdata >> (14-3); + hexdata <<= (2+3); + + for (i=0; i<11; i++) + { + if ((x >> 0 & 0x0F) > 4) x+=0x0003; + if ((x >> 4 & 0x0F) > 4) x+=0x0030; + if ((x >> 8 & 0x0F) > 4) x+=0x0300; + if ((x >>12 & 0x0F) > 4) x+=0x3000; + x <<= 1; + if (hexdata & 0x8000) x++; + hexdata <<= 1; + } + return x; +} +#if defined ISiSLAVE +void iSlaveTune (TCanFwMem * vars, bool isStep) +{ + TCanPkt pkt; + uint16_t bcdTime; + + if (isStep) + { + pkt.data[0] = vars->iSlave.prestep; + pkt.data[1] = vars->iSlave.step; + } + else + { + pkt.data[0] = 0xFF; + pkt.data[1] = vars->iSlave.step; + } + + bcdTime = bcd (vars->iSlave.tmrHaz.Value()); + pkt.data[2] = bcdTime >> 8; // время вспышки в двоично-десятичном формате + pkt.data[3] = bcdTime >> 0; + + // pkt.data[2] = (vars->iSlave.tmrHaz.Value()) >> 8; +// pkt.data[3] = vars->iSlave.tmrHaz.Value(); + + pkt.id = 0x7dd; + pkt.data_len = 4; + CoreFunc->CanSend (CANch1, &pkt, 0); +} +void TestSteps (TCanFwMem * vars) +{ + if (vars->iSlave.step != vars->iSlave.prestep) + iSlaveTune (vars, true); + vars->iSlave.prestep = vars->iSlave.step; +} +void TestTimeFlash (TCanFwMem * vars) +{ + if (vars->iSlave.prehazlamp != vars->iSlave.hazlamp) + iSlaveTune (vars, false); +} +# endif +//================================================================= + +void tt (uint8_t t) +{ + TCanPkt pkt; + pkt.id = 0x7dd; + pkt.data_len = 1; + pkt.data[0] = t; + CoreFunc->CanSend (CANch1, &pkt, 0); +} +void tt2 (uint8_t t) +{ + TCanPkt pkt; + pkt.id = 0x7dd; + pkt.data_len = 1; + pkt.data[0] = t; + CoreFunc->CanSend (CANch2, &pkt, 0); +} + +void ttBcd (uint8_t t) +{ + TCanPkt pkt; + uint16_t T; + + T = bcd (t); + pkt.id = 0x7dd; + pkt.data_len = 2; + pkt.data[0] = T >> 8; + pkt.data[1] = T >> 0; + CoreFunc->CanSend (CANch1, &pkt, 0); +} + +void ttuint (uint32_t t) +{ + TCanPkt pkt; + pkt.id = 0x7dd; + pkt.data_len = 4; + pkt.data[0] = t >> 24; + pkt.data[1] = t >> 16; + pkt.data[2] = t >> 8; + pkt.data[3] = t >> 0; + CoreFunc->CanSend (CANch1, &pkt, 0); +} +//================================================================= \ No newline at end of file