Initial commit

This commit is contained in:
2025-10-22 20:40:25 +03:00
commit 63d038ee63
57 changed files with 104378 additions and 0 deletions

288
libs/Can.h Normal file
View File

@@ -0,0 +1,288 @@
/*
* Can.h
*
* Created on: 01 июня 2015 г.
* Author: esaulenko
*/
#ifndef DRIVERS_CAN_CAN_H_
#define DRIVERS_CAN_CAN_H_
#include <stdint.h>
#include "CommonTypes.h"
#ifndef CAN_FIRMWARE
#include "SysTimer.h"
#include "Buffer.h"
#include "scmRTOS.h"
#endif
struct TCanPkt
{
uint32_t id;
uint8_t data[8];
uint8_t data_len;
TCanPkt() { }
TCanPkt (uint32_t pkt_id):
id(pkt_id) { }
// принимает строку, заполняет данные пакета. Неуказанные данные заполняются нулями
template <int N>
inline void SetData (const char (&data_str)[N])
{
int data_size = (N <= 8) ? (N - 1) : 8;
for (int i = 0; i < data_size; i++)
data[i] = data_str[i];
for (int i = data_size; i < 8; i++)
data[i] = 0x00;
}
inline void SetData (uint8_t A)
{ data_len = 1;
data[0] = A; data[1] = 0; data[2] = 0; data[3] = 0;
data[4] = 0; data[5] = 0; data[6] = 0; data[7] = 0;
}
inline void SetData (uint8_t A, uint8_t B)
{ data_len = 2;
data[0] = A; data[1] = B; data[2] = 0; data[3] = 0;
data[4] = 0; data[5] = 0; data[6] = 0; data[7] = 0;
}
inline void SetData (uint8_t A, uint8_t B, uint8_t C)
{ data_len = 3;
data[0] = A; data[1] = B; data[2] = C; data[3] = 0;
data[4] = 0; data[5] = 0; data[6] = 0; data[7] = 0;
}
inline void SetData (uint8_t A, uint8_t B, uint8_t C, uint8_t D)
{ data_len = 4;
data[0] = A; data[1] = B; data[2] = C; data[3] = D;
data[4] = 0; data[5] = 0; data[6] = 0; data[7] = 0;
}
inline void SetData (uint8_t A, uint8_t B, uint8_t C, uint8_t D, uint8_t E)
{ data_len = 5;
data[0] = A; data[1] = B; data[2] = C; data[3] = D;
data[4] = E; data[5] = 0; data[6] = 0; data[7] = 0;
}
inline void SetData (uint8_t A, uint8_t B, uint8_t C, uint8_t D, uint8_t E, uint8_t F)
{ data_len = 6;
data[0] = A; data[1] = B; data[2] = C; data[3] = D;
data[4] = E; data[5] = F; data[6] = 0; data[7] = 0;
}
inline void SetData (uint8_t A, uint8_t B, uint8_t C, uint8_t D, uint8_t E, uint8_t F, uint8_t G)
{ data_len = 7;
data[0] = A; data[1] = B; data[2] = C; data[3] = D;
data[4] = E; data[5] = F; data[6] = G; data[7] = 0;
}
inline void SetData (uint8_t A, uint8_t B, uint8_t C, uint8_t D, uint8_t E, uint8_t F, uint8_t G, uint8_t H)
{ data_len = 8;
data[0] = A; data[1] = B; data[2] = C; data[3] = D;
data[4] = E; data[5] = F; data[6] = G; data[7] = H;
}
};
struct TCanInit
{
uint32_t baudrate; // "сырое" значение регистра BTR, см. TCanBaudrate
uint8_t mode; // в наст. момент не используется. TODO Должно быть RO / RW
uint64_t filters[27]; // массив со значениями для пар регистров; заполняется Filters::xxx
};
class CCan
{
public:
enum TCanState : uint8_t
{
CanActive,
CanRxOnly, // внешний драйвер выключен
CanSleep, // внешний драйвер выключен, модуль в спящем режиме
CanInitError = 0xFE,
CanBusOff = 0xFF,
};
/* TIME QUANTUM FREQUENCY:
Ftq = Ntq * Fbaud
where 8 <= Ntq <= 25, and Ntq - is integer!
BAUD RATE PRESCALER:
BRP = (Fcan/Ftq)–1
INDIVIDUAL BIT TIME SEGMENTS:
(Bit Time) = (Sync Segment) + (Time Segment 1) + (Time Segment 2)
where
(Sync Segment) = 1*Tq (constant)
(Time Segment 2) ~= 30% of Nominal Bit Time = Ntq/3
(Time Segment 2) > 1*Tq
(Time Segment 1) > 3*Tq
(Time Segment 1) > (Time Segment 2)
(Time Segment 1) <= (Time Segment 2)+8
(Synchronous Jump Width) <= (Time Segment 2)
Table of Parameters:
--------+-----------------------------------------------------+
BRP@Fcan| Ntq |
9MHz |25|24|23|22|21|20|19|18|17|16|15|14|13|12|11|10| 9| 8|
--------+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
500.000 | | | | | | | | 0| | | | | | | | | 1| |
250.000 | | | | | | | | 1| | | | | | 2| | | 3| |
125.000 | | 2| | | | | | 3| | | | | | 5| | | 7| 8|
100.000 | | | | | | | | 4| | | 5| | | | | 8| 9| |
83.333 | | | | | | | | 5| | | | | | 8| | |11| |
50.000 | | | | | | 8| | 9| | |11| | |14| |17|19| |
33.333 | | | | | | | |14| | |17| | | | |26|29| |
20.000 |17| | | | | | |24| | |29| | | | |44|49| |
15.000 |23|24| | | |29| | | | |39| | |49| |59| |74|
10.000 |35| | | | |44| |49| | |59| | |74| |89|99| |
--------+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
*/
#define CAN_BTR(BRP,TSEG1,TSEG2,SJW) (((((((SJW)&0x03)<<4)|((TSEG2)&0x07))<<4)|((TSEG1)&0x0F))<<16)|((BRP)&0x3FF)
// значения регистра BTR
enum TCanBaudrate {
CanBaudrate500 = CAN_BTR(0,10,5,3),
CanBaudrate250 = CAN_BTR(1,10,5,3),
// CanBaudrate125 = CAN_BTR(2,14,7,3),
CanBaudrate125 = CAN_BTR(3,10,5,3),
CanBaudrate100 = CAN_BTR(4,10,5,3),
CanBaudrate83 = CAN_BTR(5,10,5,3),
// CanBaudrate50 = CAN_BTR(8,11,6,3),
CanBaudrate50 = CAN_BTR(9,10,5,3),
CanBaudrate33 = CAN_BTR(14,10,5,3),
CanBaudrate20 = CAN_BTR(17,15,7,3),
// CanBaudrate20 = CAN_BTR(24,10,5,3),
CanBaudrate15 = CAN_BTR(23,15,7,3),
// CanBaudrate15 = CAN_BTR(24,14,7,3),
// CanBaudrate15 = CAN_BTR(29,11,6,3),
CanBaudrate10 = CAN_BTR(35,15,7,3),
// CanBaudrate10 = CAN_BTR(44,11,6,3),
// CanBaudrate10 = CAN_BTR(49,10,5,3),
};
#ifndef CAN_FIRMWARE
CCan ();
uint32_t Init (TCanChannel aCh, const TCanInit * apInit);
uint32_t Send (TCanChannel aCh, TCanPkt * apPkt, uint32_t aTimeout);
void ReceivedIsr (TCanChannel aCh, TCanPkt * apPkt);
uint32_t ProcessQueue ();
uint32_t GetRcv (TCanChannel aCh, TCanPkt * apPkt);
uint32_t GetRcvTimeout (TCanChannel aCh)
{ return _rx_tmr[aCh].Value(); }
#endif // CAN_FIRMWARE
// объявление фильтров при инициализации
struct Filter {
// добавить пару идентификаторов для точного соответствия
static constexpr uint64_t List11 (uint16_t id1, uint16_t id2)
{
return ((uint64_t) (IdStd (id1) | 0x01) << 32) |
(uint64_t) (IdStd (id2) | 0x01);
}
static constexpr uint64_t List29 (uint32_t id1, uint32_t id2)
{
return ((uint64_t) (IdExt (id1) | 0x01) << 32) |
(uint64_t) (IdExt (id2) | 0x01);
}
// добавить один идентификатор
static constexpr uint64_t List11 (uint16_t id1)
{
return ((uint64_t) (IdStd (id1) | 0x01) << 32) |
(uint64_t) (IdStd (id1) | 0x01);
}
static constexpr uint64_t List29 (uint32_t id1)
{
return ((uint64_t) (IdExt (id1) | 0x01) << 32) |
(uint64_t) (IdExt (id1) | 0x01);
}
// добавить один идентификатор с маской
static constexpr uint64_t Mask11 (uint16_t id, uint16_t mask)
{
return ((uint64_t) (IdStd (id)) << 32) |
(uint64_t) (IdStd (mask) | 0x01);
}
static constexpr uint64_t Mask29 (uint32_t id, uint32_t mask)
{
return ((uint64_t) (IdExt (id)) << 32) |
(uint64_t) (IdExt (mask) | 0x01);
}
private:
// формирование ID для фильтров
static constexpr uint32_t IdStd (uint16_t id)
{ return (id & 0x7FFul) << 21; }
static constexpr uint32_t IdExt (uint32_t id)
{ return ((id & 0x1FFFFFFFul) << 3) | 0x04; }
};
#ifndef CAN_FIRMWARE
private:
uint8_t sleep_en;
bool IsSleepEn (TCanChannel aCh)
{ return sleep_en & aCh; }
// очередь пакетов на отправку - тот же TCanPkt, но с таймером
struct TCanPktTxInt: public TCanPkt {
uint32_t timeout;
TimerMs tmr;
};
typedef CircularBuffer<TCanPkt, 16> TRxBuf;
typedef CircularBuffer<TCanPktTxInt, 32> TTxBuf;
TRxBuf _rx_buf[2];
TTxBuf _tx_buf[2];
uint32_t TxByTimeout (TCanChannel aCh);
bool IsTxQueueEmpty (TCanChannel aCh);
TCanState _state[2];
// Send() и обработка очереди вызываются из разных потоков, нужна защита
OS::TMutex can_mutex;
// сбрасывается по приёму любого пакета
TimerMs _rx_tmr[2];
#endif // CAN_FIRMWARE
};
extern CCan gCan;
#endif /* DRIVERS_CAN_CAN_H_ */