81 lines
2.0 KiB
C
81 lines
2.0 KiB
C
#include <stdio.h>
|
|
|
|
#include "ch32v003fun.h"
|
|
#include "modbus.h"
|
|
#include "rs485.h"
|
|
#include "shift_reg.h"
|
|
#include "simple_eeprom.h"
|
|
#include "state_manager.h"
|
|
#include "systick.h"
|
|
|
|
#define SLAVE_ADDRESS 0x01
|
|
#define MAX_MODBUS_FRAME 16
|
|
#define NUM_REGISTERS 1
|
|
#define FRAME_TIMEOUT_MS 4 // 3.5 char times at 9600 baud (~1.042ms per char)
|
|
|
|
static uint16_t holding_registers[NUM_REGISTERS];
|
|
|
|
static void handle_modbus_frame(uint8_t* rx_buffer, uint16_t rx_count) {
|
|
uint8_t response[MAX_MODBUS_FRAME];
|
|
uint16_t response_len;
|
|
uint8_t result;
|
|
|
|
result = modbus_process_message(rx_buffer, rx_count, SLAVE_ADDRESS,
|
|
holding_registers, NUM_REGISTERS);
|
|
|
|
if (result == MODBUS_ERROR_NONE) {
|
|
shift_reg_write(holding_registers[0]);
|
|
save_state(holding_registers[0]);
|
|
|
|
response_len = modbus_create_response(response, SLAVE_ADDRESS,
|
|
MODBUS_FC_WRITE_SINGLE_REGISTER, 0,
|
|
holding_registers[0]);
|
|
} else {
|
|
response_len = modbus_create_error_response(
|
|
response, SLAVE_ADDRESS, MODBUS_FC_WRITE_SINGLE_REGISTER, result);
|
|
}
|
|
|
|
rs485_send(response, response_len);
|
|
}
|
|
|
|
int main(void) {
|
|
uint8_t rx_buffer[MAX_MODBUS_FRAME];
|
|
uint16_t rx_count = 0;
|
|
uint32_t last_byte_time = 0;
|
|
|
|
SystemInit();
|
|
systick_init();
|
|
shift_reg_init();
|
|
rs485_init(UART_BRR);
|
|
|
|
// restore last saved state
|
|
holding_registers[0] = load_state();
|
|
shift_reg_write(holding_registers[0]);
|
|
|
|
while (1) {
|
|
if (!rs485_available()) {
|
|
continue;
|
|
}
|
|
|
|
uint32_t current_time = millis();
|
|
|
|
// check for frame timeout
|
|
if (rx_count > 0 && (current_time - last_byte_time) > FRAME_TIMEOUT_MS) {
|
|
rx_count = 0;
|
|
}
|
|
|
|
rx_buffer[rx_count++] = rs485_read();
|
|
last_byte_time = current_time;
|
|
|
|
// process complete frame
|
|
if (rx_count >= 8) {
|
|
handle_modbus_frame(rx_buffer, rx_count);
|
|
rx_count = 0;
|
|
}
|
|
|
|
// buffer overflow protection
|
|
if (rx_count >= MAX_MODBUS_FRAME) {
|
|
rx_count = 0;
|
|
}
|
|
}
|
|
} |