работа canemu вынесена в отдельную функцию

доработана терминалка
+гитигнор сгенереных файлов
This commit is contained in:
2025-08-05 12:29:33 +03:00
parent 8d3704b539
commit e1491ceb8f
78 changed files with 342 additions and 6592 deletions

View File

@@ -1,8 +1,12 @@
#include "canEmu.h"
#include "stm32f1xx_hal.h"
#include "rs_message.h"
volatile uint32_t CANEMU_BIT_TICKS = 0;
CANEmu_HandleTypeDef hcanemu;
int flag_manual = 0;
int transmit_prev = 0;
static void delay_us(uint32_t us) {
uint32_t ticks = us * CANEMU_TIM_US_TICKS;
@@ -44,25 +48,83 @@ void wait_exact_ticks(uint16_t target_ticks) {
void CANEmu_SendFrame(CANEmu_HandleTypeDef *canemu) {
if (canemu->bitrate_bps == 0) return;
if (canemu->bitrate_bps == 0) return;
form_CAN_bitstream_full(&canemu->header, canemu->data, canemu->errors);
form_CAN_bitstream_full(&canemu->header, canemu->data, canemu->errors);
CANEMU_BIT_TICKS = (CANEMU_TIM_CLOCK_HZ + canemu->bitrate_bps / 2) / canemu->bitrate_bps;
CANEMU_BIT_TICKS = (CANEMU_TIM_CLOCK_HZ + canemu->bitrate_bps / 2) / canemu->bitrate_bps;
uint16_t current = tim_get(CANEMU_TIM);
uint16_t next_edge = current;
uint16_t current = tim_get(CANEMU_TIM);
uint16_t next_edge = current;
for (uint32_t i = 0; i < can_bits_len; i++) {
if (can_bits[i])
can_tx_set_1();
else
can_tx_set_0();
__disable_irq();
for (uint32_t i = 0; i < can_bits_len; i++) {
if (can_bits[i])
can_tx_set_1();
else
can_tx_set_0();
next_edge += (uint16_t)CANEMU_BIT_TICKS; // автоматически обрежется до 16 бит
wait_exact_ticks(next_edge);
}
next_edge += (uint16_t)CANEMU_BIT_TICKS; // автоматически обрежется до 16 бит
wait_exact_ticks(next_edge);
}
can_tx_set_1(); // Завершаем линию
can_tx_set_1(); // Завершаем линию
__enable_irq();
}
void CANEmu_Working(CANEmu_HandleTypeDef *canemu)
{
if(flag_manual == 0)
{
canemu->start_poll = MB_DATA.Coils.START_POLLING;
canemu->transmit = MB_DATA.Coils.START_SINGLE_FRAME;
canemu->period_ms = MB_DATA.HoldRegs.CAN_PERIOD;
if(canemu->period_ms < CAN_MIN_PERIOD)
{
canemu->period_ms = CAN_MIN_PERIOD;
}
// can message
canemu->header.IDE = MB_DATA.Coils.HEADER_IDE;
canemu->header.RTR = MB_DATA.Coils.HEADER_RTR;
canemu->bitrate_bps = (uint32_t)MB_DATA.HoldRegs.CAN_BITRATE_KBPS*1000;
canemu->header.ExtId = ((uint32_t)MB_DATA.HoldRegs.CAN_ID_HI << 16) | MB_DATA.HoldRegs.CAN_ID_LO;
canemu->header.StdId = canemu->header.ExtId;
canemu->header.DLC = (uint8_t)MB_DATA.HoldRegs.CAN_DLC & 0xF;
canemu->data[0] = (uint8_t)MB_DATA.HoldRegs.CAN_DATA_0;
canemu->data[1] = (uint8_t)MB_DATA.HoldRegs.CAN_DATA_1;
canemu->data[2] = (uint8_t)MB_DATA.HoldRegs.CAN_DATA_2;
canemu->data[3] = (uint8_t)MB_DATA.HoldRegs.CAN_DATA_3;
canemu->data[4] = (uint8_t)MB_DATA.HoldRegs.CAN_DATA_4;
canemu->data[5] = (uint8_t)MB_DATA.HoldRegs.CAN_DATA_5;
canemu->data[6] = (uint8_t)MB_DATA.HoldRegs.CAN_DATA_6;
canemu->data[7] = (uint8_t)MB_DATA.HoldRegs.CAN_DATA_7;
// errors
canemu->errors.FF_SRS = MB_DATA.Coils.FLIP_SRS;
canemu->errors.FF_IDE = MB_DATA.Coils.FLIP_IDE;
canemu->errors.FF_RTR = MB_DATA.Coils.FLIP_RTR;
canemu->errors.FF_R1 = MB_DATA.Coils.FLIP_R1;
canemu->errors.FF_R0 = MB_DATA.Coils.FLIP_R0;
canemu->errors.MSGID = MB_DATA.Coils.FLIP_MSGID_BIT;
canemu->errors.DATA = MB_DATA.Coils.FLIP_DATA_BIT;
canemu->errors.CRC_ERR = MB_DATA.Coils.FLIP_CRC_BIT;
canemu->errors.STUFF_BITS = MB_DATA.Coils.DISABLE_STUFF_BITS;
}
if(canemu->start_poll)
{
canemu->transmit = 0;
HAL_Delay(canemu->period_ms);
CANEmu_SendFrame(&hcanemu);
}
else if((canemu->transmit == 1) && (transmit_prev == 0))
{
CANEmu_SendFrame(&hcanemu);
}
transmit_prev = canemu->transmit;
}

View File

@@ -10,7 +10,7 @@
#define CANEMU_TIM TIM2
#define CANEMU_TIM_US_TICKS 72 // Для 1 мкс при 72 МГц
#define CANEMU_TIM_CLOCK_HZ 72000000UL // частота таймера
#define CAN_MIN_PERIOD 20
// === Макросы управления GPIO ===
#define can_tx_set_1() (CANEMU_TX_GPIO_PORT->BSRR = (1U << CANEMU_TX_GPIO_PIN))
@@ -33,9 +33,11 @@ typedef struct
uint32_t period_ms;
CAN_ErrorFlags_t errors;
}CANEmu_HandleTypeDef;
extern CANEmu_HandleTypeDef hcanemu;
void CANEmu_Init(CANEmu_HandleTypeDef *hcanemu, uint32_t bitrate);
void CANEmu_Working(CANEmu_HandleTypeDef *hcanemu);
void CANEmu_SendFrame(CANEmu_HandleTypeDef *hcanemu);

View File

@@ -10,6 +10,8 @@ uint32_t can_bits_len = 0;
uint32_t err_indices[MAX_ERR_BITS];
uint8_t err_indices_count = 0;
#define FLIP_RAW_BITS
void append_bit(uint8_t *buf, uint32_t *len, uint8_t bit) {
if (*len < MAX_BITS) {
buf[(*len)++] = bit;
@@ -60,137 +62,156 @@ void apply_bit_stuffing_with_error(const uint8_t *src, uint32_t src_len, uint8_t
}
}
// Вспомогательная функция для инверсии бита в raw_bits
// Вспомогательная функция для инверсии бита
void flip_bit(uint32_t bit_index) {
if (bit_index < raw_len) {
can_bits[bit_index] = !can_bits[bit_index];
}
}
// Вспомогательная функция для инверсии бита в raw_bits
void flip_raw_bit(uint32_t bit_index) {
if (bit_index < raw_len) {
raw_bits[bit_index] = !raw_bits[bit_index];
}
}
void form_CAN_bitstream_full(const CAN_TxHeaderTypeDef *header, const uint8_t *data, CAN_ErrorFlags_t errors) {
raw_len = 0;
err_indices_count = 0;
raw_len = 0;
err_indices_count = 0;
uint32_t data_idx = 0xFF;
uint32_t srr_idx = 0xFF;
uint32_t id_start = 0xFF;
uint32_t id2_start = 0xFF;
uint32_t rtr_idx = 0xFF;
uint32_t ide_idx = 0xFF;
uint32_t r1_idx = 0xFF;
uint32_t r0_idx = 0xFF;
// 1. SOF (start of frame)
append_bit(raw_bits, &raw_len, 0); // dominant
// 1. SOF (start of frame)
append_bit(raw_bits, &raw_len, 0); // dominant
// Запоминаем индексы для ошибок
uint32_t idx_start = raw_len; // начало Arbitration + Control
// Запоминаем индексы для ошибок
uint32_t idx_start = raw_len; // начало Arbitration + Control
if (header->IDE == 0) {
// --- Standard Frame (11-bit ID) ---
// ID[10:0]
append_bits(raw_bits, &raw_len, header->StdId & 0x7FF, 11);
id_start = raw_len - 11; // начало ID
if (header->IDE == 0) {
// --- Standard Frame (11-bit ID) ---
// ID[10:0]
append_bits(raw_bits, &raw_len, header->StdId & 0x7FF, 11);
uint32_t id_start = raw_len - 11; // начало ID
// RTR
append_bit(raw_bits, &raw_len, header->RTR);
rtr_idx = raw_len - 1;
// RTR
append_bit(raw_bits, &raw_len, header->RTR);
uint32_t rtr_idx = raw_len - 1;
// IDE = 0
append_bit(raw_bits, &raw_len, 0);
ide_idx = raw_len - 1;
// IDE = 0
append_bit(raw_bits, &raw_len, 0);
uint32_t ide_idx = raw_len - 1;
// r0
append_bit(raw_bits, &raw_len, 0);
r0_idx = raw_len - 1;
// r0
append_bit(raw_bits, &raw_len, 0);
uint32_t r0_idx = raw_len - 1;
// Ошибки FF_RTR, FF_IDE, FF_R0
if (errors.FF_RTR) flip_bit(rtr_idx);
if (errors.FF_IDE) flip_bit(ide_idx);
if (errors.FF_R0) flip_bit(r0_idx);
} else {
// --- Extended Frame (29-bit ID) ---
uint32_t ext_id = header->ExtId & 0x1FFFFFFF;
append_bits(raw_bits, &raw_len, (ext_id >> 18) & 0x7FF, 11); // ID[28:18]
id_start = raw_len - 11;
// MSGID_ERR — переворачиваем 1-й бит ID (MSB ID[10]) для примера
if (errors.MSGID) flip_bit(id_start);
// SRR
append_bit(raw_bits, &raw_len, 1);
srr_idx = raw_len - 1;
} else {
// --- Extended Frame (29-bit ID) ---
uint32_t ext_id = header->ExtId & 0x1FFFFFFF;
append_bits(raw_bits, &raw_len, (ext_id >> 18) & 0x7FF, 11); // ID[28:18]
uint32_t id1_start = raw_len - 11;
// IDE = 1
append_bit(raw_bits, &raw_len, 1);
ide_idx = raw_len - 1;
// SRR
append_bit(raw_bits, &raw_len, 1);
uint32_t srr_idx = raw_len - 1;
append_bits(raw_bits, &raw_len, (ext_id >> 0) & 0x3FFFF, 18); // ID[17:0]
id2_start = raw_len - 18;
// IDE = 1
append_bit(raw_bits, &raw_len, 1);
uint32_t ide_idx = raw_len - 1;
// RTR
append_bit(raw_bits, &raw_len, header->RTR);
rtr_idx = raw_len - 1;
append_bits(raw_bits, &raw_len, (ext_id >> 0) & 0x3FFFF, 18); // ID[17:0]
uint32_t id2_start = raw_len - 18;
// r1
append_bit(raw_bits, &raw_len, 0);
r1_idx = raw_len - 1;
// RTR
append_bit(raw_bits, &raw_len, header->RTR);
uint32_t rtr_idx = raw_len - 1;
// r0
append_bit(raw_bits, &raw_len, 0);
r0_idx = raw_len - 1;
}
// r1
append_bit(raw_bits, &raw_len, 0);
uint32_t r1_idx = raw_len - 1;
// 3. DLC
append_bits(raw_bits, &raw_len, header->DLC & 0xF, 4);
// r0
append_bit(raw_bits, &raw_len, 0);
uint32_t r0_idx = raw_len - 1;
// 4. Data field (если не RTR)
if (!header->RTR) {
uint8_t dlc = header->DLC & 0xF;
data_idx = raw_len;
for (uint8_t i = 0; i < dlc && i < 8; i++) {
uint8_t byte_val = data[i];
// Time-stamp override on last 2 bytes
if (header->TransmitGlobalTime == ENABLE && i >= 6) {
append_bits(raw_bits, &raw_len, 0x00, 8); // Will be replaced by timestamp elsewhere
} else {
append_bits(raw_bits, &raw_len, byte_val, 8);
}
}
}
// Ошибки FF_SRS_ERR — это SRR бит в extended frame
if (errors.FF_SRS) flip_bit(srr_idx);
if (errors.FF_IDE) flip_bit(ide_idx);
if (errors.FF_RTR) flip_bit(rtr_idx);
if (errors.FF_R1) flip_bit(r1_idx);
if (errors.FF_R0) flip_bit(r0_idx);
// 5. CRC
uint16_t crc = compute_crc15(raw_bits, raw_len);
uint32_t crc_start = raw_len;
append_bits(raw_bits, &raw_len, crc, 15);
// MSGID_ERR — переворачиваем 1-й бит ID (для примера бит ID[28])
if (errors.MSGID) flip_bit(id1_start);
if (errors.CRC_ERR) {
flip_bit(crc_start); // инвертируем 1-й бит CRC для примера
}
}
// 6. CRC Delimiter (recessive)
append_bit(raw_bits, &raw_len, 1);
// 3. DLC
append_bits(raw_bits, &raw_len, header->DLC & 0xF, 4);
#ifdef FLIP_RAW_BITS
// Ошибки
if (errors.FF_SRS) flip_raw_bit(srr_idx);
if (errors.FF_IDE) flip_raw_bit(ide_idx);
if (errors.FF_RTR) flip_raw_bit(rtr_idx);
if (errors.FF_R1) flip_raw_bit(r1_idx);
if (errors.FF_R0) flip_raw_bit(r0_idx);
if (errors.DATA) flip_raw_bit(data_idx);
// MSGID_ERR — переворачиваем 1-й бит ID (MSB ID[10]) для примера
if (errors.MSGID) flip_raw_bit(id_start);
#endif
// 10. Apply bit stuffing, пропускаем вставку stuff bits если ошибка ERR_STUFF_BITS
apply_bit_stuffing_with_error(raw_bits, raw_len, can_bits, &can_bits_len, errors.STUFF_BITS);
// 7. ACK Slot (dominant)
append_bit(can_bits, &can_bits_len, 1);
// 4. Data field (если не RTR)
if (!header->RTR) {
uint8_t dlc = header->DLC & 0xF;
for (uint8_t i = 0; i < dlc && i < 8; i++) {
uint32_t byte_start = raw_len;
uint8_t byte_val = data[i];
// Time-stamp override on last 2 bytes
if (header->TransmitGlobalTime == ENABLE && i >= 6) {
append_bits(raw_bits, &raw_len, 0x00, 8); // Will be replaced by timestamp elsewhere
} else {
append_bits(raw_bits, &raw_len, byte_val, 8);
}
// 8. ACK Delimiter (recessive)
append_bit(can_bits, &can_bits_len, 1);
// Если ошибка DATA_ERR, инвертируем 1-й бит первого байта данных для примера
if ((errors.DATA) && i == 0) {
flip_bit(byte_start);
}
}
}
// 5. CRC
uint16_t crc = compute_crc15(raw_bits, raw_len);
uint32_t crc_start = raw_len;
append_bits(raw_bits, &raw_len, crc, 15);
if (errors.CRC_ERR) {
flip_bit(crc_start); // инвертируем 1-й бит CRC для примера
}
// 6. CRC Delimiter (recessive)
append_bit(raw_bits, &raw_len, 1);
// 10. Apply bit stuffing, пропускаем вставку stuff bits если ошибка ERR_STUFF_BITS
apply_bit_stuffing_with_error(raw_bits, raw_len, can_bits, &can_bits_len, errors.STUFF_BITS);
// 7. ACK Slot (dominant)
append_bit(raw_bits, &raw_len, 1);
// 8. ACK Delimiter (recessive)
append_bit(raw_bits, &raw_len, 1);
// 9. End of Frame (7 recessive bits)
for (int i = 0; i < 7; i++) {
append_bit(raw_bits, &raw_len, 1);
}
// 9. End of Frame (7 recessive bits)
for (int i = 0; i < 7; i++) {
append_bit(can_bits, &can_bits_len, 1);
}
// Ошибки
#ifndef FLIP_RAW_BITS
if (errors.FF_SRS) flip_bit(srr_idx);
if (errors.FF_IDE) flip_bit(ide_idx);
if (errors.FF_RTR) flip_bit(rtr_idx);
if (errors.FF_R1) flip_bit(r1_idx);
if (errors.FF_R0) flip_bit(r0_idx);
if (errors.DATA) flip_bit(data_idx);
// MSGID_ERR — переворачиваем 1-й бит ID (MSB ID[10]) для примера
if (errors.MSGID) flip_bit(id_start);
#endif
}

View File

@@ -57,8 +57,6 @@ void SystemClock_Config(void);
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
CANEmu_HandleTypeDef hcanemu;
int flag_manual = 0;
/* USER CODE END 0 */
/**
@@ -102,56 +100,9 @@ int main(void)
/* Infinite loop */
/* USER CODE BEGIN WHILE */
int transmit_prev = hcanemu.transmit;
while (1)
{
if(flag_manual == 0)
{
hcanemu.start_poll = MB_DATA.Coils.START_POLLING;
hcanemu.transmit = MB_DATA.Coils.START_SINGLE_FRAME;
hcanemu.period_ms = MB_DATA.HoldRegs.CAN_PERIOD;
// can message
hcanemu.header.IDE = MB_DATA.Coils.HEADER_IDE;
hcanemu.header.RTR = MB_DATA.Coils.HEADER_RTR;
hcanemu.bitrate_bps = (uint32_t)MB_DATA.HoldRegs.CAN_BITRATE_KBPS*1000;
hcanemu.header.ExtId = ((uint32_t)MB_DATA.HoldRegs.CAN_ID_HI << 16) || MB_DATA.HoldRegs.CAN_ID_LO;
hcanemu.header.StdId = hcanemu.header.ExtId;
hcanemu.header.DLC = (uint8_t)MB_DATA.HoldRegs.CAN_DLC & 0xF;
hcanemu.data[0] = (uint8_t)MB_DATA.HoldRegs.CAN_DATA_0;
hcanemu.data[1] = (uint8_t)MB_DATA.HoldRegs.CAN_DATA_1;
hcanemu.data[2] = (uint8_t)MB_DATA.HoldRegs.CAN_DATA_2;
hcanemu.data[3] = (uint8_t)MB_DATA.HoldRegs.CAN_DATA_3;
hcanemu.data[4] = (uint8_t)MB_DATA.HoldRegs.CAN_DATA_4;
hcanemu.data[5] = (uint8_t)MB_DATA.HoldRegs.CAN_DATA_5;
hcanemu.data[6] = (uint8_t)MB_DATA.HoldRegs.CAN_DATA_6;
hcanemu.data[7] = (uint8_t)MB_DATA.HoldRegs.CAN_DATA_7;
// errors
hcanemu.errors.FF_SRS = MB_DATA.Coils.FLIP_SRS;
hcanemu.errors.FF_IDE = MB_DATA.Coils.FLIP_IDE;
hcanemu.errors.FF_RTR = MB_DATA.Coils.FLIP_RTR;
hcanemu.errors.FF_R1 = MB_DATA.Coils.FLIP_R1;
hcanemu.errors.FF_R0 = MB_DATA.Coils.FLIP_R0;
hcanemu.errors.MSGID = MB_DATA.Coils.FLIP_MSGID_BIT;
hcanemu.errors.DATA = MB_DATA.Coils.FLIP_DATA_BIT;
hcanemu.errors.CRC_ERR = MB_DATA.Coils.FLIP_CRC_BIT;
hcanemu.errors.STUFF_BITS = MB_DATA.Coils.DISABLE_STUFF_BITS;
}
if(hcanemu.start_poll)
{
hcanemu.transmit = 0;
HAL_Delay(hcanemu.period_ms);
CANEmu_SendFrame(&hcanemu);
}
else if((hcanemu.transmit == 1) && (transmit_prev == 0))
{
CANEmu_SendFrame(&hcanemu);
}
transmit_prev = hcanemu.transmit;
CANEmu_Working(&hcanemu);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */

View File

@@ -39,7 +39,7 @@ void MX_USART1_UART_Init(void)
/* USER CODE END USART1_Init 1 */
huart1.Instance = USART1;
huart1.Init.BaudRate = 256000;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;