feat(set-protocol): добавь порт F407 для DevBoard_V1
This commit is contained in:
22
c/set-protocol/ports/stm32f407-devboard-v1/README.md
Normal file
22
c/set-protocol/ports/stm32f407-devboard-v1/README.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# STM32F407 + CAN485 DevBoard_V1
|
||||
|
||||
Порт даёт SETGUI доступ к существующим Modbus-регистрам STM32F407 через
|
||||
классический CAN. ПК подключён к USB-UART платы CAN485 DevBoard_V1, команда
|
||||
`T,E` платы отправляет ProtoCAN-кадр, а этот порт отвечает тем же типом кадра.
|
||||
При маршруте `Q3` плата одновременно ретранслирует поток по RS-485.
|
||||
|
||||
Порт не настраивает GPIO, bitrate, фильтры и не запускает CAN: это остаётся за
|
||||
CubeMX-проектом. Необработанные кадры передаются callback-у приложения, поэтому
|
||||
загрузчик ProtoCAN и регистровый сервис могут делить FIFO0.
|
||||
|
||||
Слой приложения предоставляет callback-и чтения и записи. Нулевой DLC означает
|
||||
чтение; данные в кадре `HOLDING`/`COIL` — запись. За кадр передаются до четырёх
|
||||
16-битных регистров или до шестнадцати coils.
|
||||
|
||||
```c
|
||||
static set_devboard_v1_stm32f407_t gui_can;
|
||||
set_devboard_v1_stm32f407_init(&gui_can, &hcan, 7, 3,
|
||||
app_read_register, app_write_register, NULL,
|
||||
app_handle_boot_frame, NULL);
|
||||
for (;;) set_devboard_v1_stm32f407_poll(&gui_can);
|
||||
```
|
||||
@@ -0,0 +1,80 @@
|
||||
#include "set_devboard_v1_stm32f407.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static bool transmit(set_devboard_v1_stm32f407_t *port,
|
||||
const pcan_frame_t *frame)
|
||||
{
|
||||
CAN_TxHeaderTypeDef header;
|
||||
uint32_t mailbox = 0U;
|
||||
uint8_t data[8] = {0U};
|
||||
|
||||
memset(&header, 0, sizeof(header));
|
||||
header.ExtId = frame->id & 0x1FFFFFFFUL;
|
||||
header.IDE = CAN_ID_EXT;
|
||||
header.RTR = ((frame->flags & PCAN_FLAG_RTR) != 0U) ?
|
||||
CAN_RTR_REMOTE : CAN_RTR_DATA;
|
||||
header.DLC = frame->dlc;
|
||||
header.TransmitGlobalTime = DISABLE;
|
||||
memcpy(data, frame->data, frame->dlc);
|
||||
if (HAL_CAN_AddTxMessage(port->can, &header, data, &mailbox) != HAL_OK) {
|
||||
port->tx_errors++;
|
||||
return false;
|
||||
}
|
||||
port->tx_frames++;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool set_devboard_v1_stm32f407_init(
|
||||
set_devboard_v1_stm32f407_t *port, CAN_HandleTypeDef *can,
|
||||
uint8_t device_type, uint8_t device_id,
|
||||
pcan_modbus_read_fn read, pcan_modbus_write_fn write, void *register_user,
|
||||
set_devboard_v1_unhandled_fn unhandled, void *unhandled_user)
|
||||
{
|
||||
if ((port == NULL) || (can == NULL)) {
|
||||
return false;
|
||||
}
|
||||
memset(port, 0, sizeof(*port));
|
||||
port->can = can;
|
||||
port->unhandled = unhandled;
|
||||
port->unhandled_user = unhandled_user;
|
||||
return pcan_modbus_server_init(&port->server, device_type, device_id,
|
||||
read, write, register_user);
|
||||
}
|
||||
|
||||
size_t set_devboard_v1_stm32f407_poll(set_devboard_v1_stm32f407_t *port)
|
||||
{
|
||||
size_t handled = 0U;
|
||||
if ((port == NULL) || (port->can == NULL)) {
|
||||
return 0U;
|
||||
}
|
||||
while (HAL_CAN_GetRxFifoFillLevel(port->can, CAN_RX_FIFO0) != 0U) {
|
||||
CAN_RxHeaderTypeDef header;
|
||||
uint8_t data[8] = {0U};
|
||||
pcan_frame_t request = {0};
|
||||
pcan_frame_t response;
|
||||
pcan_modbus_result_t result;
|
||||
|
||||
if (HAL_CAN_GetRxMessage(port->can, CAN_RX_FIFO0, &header, data) != HAL_OK) {
|
||||
break;
|
||||
}
|
||||
port->rx_frames++;
|
||||
request.id = (header.IDE == CAN_ID_EXT) ? header.ExtId : header.StdId;
|
||||
request.flags = (header.IDE == CAN_ID_EXT) ? PCAN_FLAG_IDE : 0U;
|
||||
if (header.RTR == CAN_RTR_REMOTE) {
|
||||
request.flags |= PCAN_FLAG_RTR;
|
||||
}
|
||||
request.dlc = (header.DLC > 8U) ? 8U : (uint8_t)header.DLC;
|
||||
memcpy(request.data, data, request.dlc);
|
||||
|
||||
result = pcan_modbus_server_handle(&port->server, &request, &response);
|
||||
if (result == PCAN_MODBUS_RESPONSE) {
|
||||
(void)transmit(port, &response);
|
||||
handled++;
|
||||
} else if ((result == PCAN_MODBUS_NOT_FOR_US) &&
|
||||
(port->unhandled != NULL)) {
|
||||
port->unhandled(port->unhandled_user, &header, data);
|
||||
}
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/** STM32F407 bxCAN port for SETGUI through CAN485 DevBoard_V1. */
|
||||
#ifndef SET_DEVBOARD_V1_STM32F407_H
|
||||
#define SET_DEVBOARD_V1_STM32F407_H
|
||||
|
||||
#include "stm32f4xx_hal.h"
|
||||
#include "pcan_modbus_server.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void (*set_devboard_v1_unhandled_fn)(void *user,
|
||||
const CAN_RxHeaderTypeDef *header,
|
||||
const uint8_t data[8]);
|
||||
|
||||
typedef struct {
|
||||
CAN_HandleTypeDef *can;
|
||||
pcan_modbus_server_t server;
|
||||
set_devboard_v1_unhandled_fn unhandled;
|
||||
void *unhandled_user;
|
||||
uint32_t rx_frames;
|
||||
uint32_t tx_frames;
|
||||
uint32_t tx_errors;
|
||||
} set_devboard_v1_stm32f407_t;
|
||||
|
||||
bool set_devboard_v1_stm32f407_init(
|
||||
set_devboard_v1_stm32f407_t *port, CAN_HandleTypeDef *can,
|
||||
uint8_t device_type, uint8_t device_id,
|
||||
pcan_modbus_read_fn read, pcan_modbus_write_fn write, void *register_user,
|
||||
set_devboard_v1_unhandled_fn unhandled, void *unhandled_user);
|
||||
|
||||
size_t set_devboard_v1_stm32f407_poll(set_devboard_v1_stm32f407_t *port);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user