База для Monjaro и Atlas2024
All checks were successful
Push Branch / Build Test (push) Successful in 1m53s

This commit is contained in:
demin
2025-10-22 21:07:41 +03:00
parent 63d038ee63
commit db70af46d4
6 changed files with 555 additions and 20 deletions

View File

@@ -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<PeriodicCount> 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_ */

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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]"
//************************** Динамические параметры ***********************************************//

79
src/myfunc/VinReq.h Normal file
View File

@@ -0,0 +1,79 @@
#include "CAN_FW.h"
#include "Can.h"
#include <string.h>
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;
}

119
src/myfunc/_MFM3.h Normal file
View File

@@ -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);
}
//=================================================================