add protocol version2

This commit is contained in:
Dennis Gunia
2025-10-08 23:42:32 +02:00
parent 2fe870a68d
commit 0e03de54b4
18 changed files with 214 additions and 199 deletions

View File

@@ -6,50 +6,50 @@
* https://github.com/dennis9819/splitflap_v1
*/
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/iom8.h>
#include <avr/wdt.h>
#include <stdlib.h>
#include <string.h>
#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/iom8.h>
// I/O Pin definition
#define BUX_RX PD0 // RX Pin (to buffer)
#define BUX_TX PD1 // TX Pin (to buffer)
#define BUX_DIR PD2 // Buffer direction pin
#define SENSOR_HOME PD3 // Home sensor pin
#define BUX_RX PD0 // RX Pin (to buffer)
#define BUX_TX PD1 // TX Pin (to buffer)
#define BUX_DIR PD2 // Buffer direction pin
#define SENSOR_HOME PD3 // Home sensor pin
#define MOTOR_A PC0 // Motor phase A driver
#define MOTOR_B PC1 // Motor phase B driver
#define MOTOR_C PC2 // Motor phase C driver
#define MOTOR_D PC3 // Motor phase D driver
#define MOTOR_A PC0 // Motor phase A driver
#define MOTOR_B PC1 // Motor phase B driver
#define MOTOR_C PC2 // Motor phase C driver
#define MOTOR_D PC3 // Motor phase D driver
// EEPROM Addresses
#define CONF_CONST_OKAY (uint8_t)0xAA
#define CONF_CONST_OKAY (uint8_t)0xAA
#define CONF_ADDR_OKAY 0x0004
#define CONF_ADDR_ADDR 0x0000
#define CONF_ADDR_OFFSET 0x0002
// Protocol definitions
#define PROTO_MAXPKGLEN 64 // maximum size of package in bytes
#define PROTO_MAXPKGLEN 64 // maximum size of package in bytes
// Command Bytes
#define CMDB_SETVAL (uint8_t)0x10 // Set display value
#define CMDB_SETVALR (uint8_t)0x11 // Set display value and do a full rotation
#define CMDB_EEPROMR (uint8_t)0xF0 // Read EEPROM
#define CMDB_EEPROMW (uint8_t)0xF1 // Write EEPROM
#define CMDB_GSTS (uint8_t)0xF8 // Get status
#define CMDB_PING (uint8_t)0xFE // Ping
#define CMDB_RESET (uint8_t)0x30 // Reset device
#define CMDB_PWRON (uint8_t)0x21 // Power motor on
#define CMDB_RPWROFF (uint8_t)0x20 // Poer motor off
#define CMDB_SETVAL (uint8_t)0x10 // Set display value
#define CMDB_SETVALR (uint8_t)0x11 // Set display value and do a full rotation
#define CMDB_EEPROMR (uint8_t)0xF0 // Read EEPROM
#define CMDB_EEPROMW (uint8_t)0xF1 // Write EEPROM
#define CMDB_GSTS (uint8_t)0xF8 // Get status
#define CMDB_PING (uint8_t)0xFE // Ping
#define CMDB_RESET (uint8_t)0x30 // Reset device
#define CMDB_PWRON (uint8_t)0x21 // Power motor on
#define CMDB_RPWROFF (uint8_t)0x20 // Poer motor off
// Command Responses
#define CMDR_ERR_INVALID 0xEE // Invalid command
#define CMDR_ACK 0xAA // Acknowledge
#define CMDR_PING 0xFF // Ping response
#define CMDR_ERR_INVALID 0xEE // Invalid command
#define CMDR_ACK 0xAA // Acknowledge
#define CMDR_PING 0xFF // Ping response
// Utility definitions
#define SHIFT_0B 0

View File

@@ -61,7 +61,8 @@ void initialSetup()
void readCommand()
{
char *payload = malloc(PROTO_MAXPKGLEN);
uint8_t payload_len = sfbus_recv_frame(address, payload);
uint8_t payload_len = sfbus_recv_frame_v2(address, payload);
payload += 2; // skip address bytes
if (payload_len > 0)
{
// read command byte
@@ -90,7 +91,7 @@ void readCommand()
*(msg + i) = (char)eeprom_read_c(i - 1);
}
_delay_ms(2);
sfbus_send_frame(0xFFFF, msg, bytes + 1);
sfbus_send_frame_v2(0xFFFF, msg, bytes + 1);
free(msg);
}
else if (opcode == CMDB_EEPROMW)
@@ -111,7 +112,7 @@ void readCommand()
*(msg + i) = (char)eeprom_read_c(i - 1);
}
_delay_ms(2);
sfbus_send_frame(0xFFFF, msg, bytes + 1);
sfbus_send_frame_v2(0xFFFF, msg, bytes + 1);
free(msg);
// now use new addr
uint8_t addrL = eeprom_read_c(CONF_ADDR_ADDR);
@@ -131,14 +132,14 @@ void readCommand()
*(msg + 4) = (char)((counter >> SHIFT_2B) & 0xFF);
*(msg + 3) = (char)((counter >> SHIFT_3B) & 0xFF);
_delay_ms(2);
sfbus_send_frame(0xFFFF, msg, 7);
sfbus_send_frame_v2(0xFFFF, msg, 7);
free(msg);
}
else if (opcode == CMDB_PING)
{
char msg = (char)CMDR_PING;
_delay_ms(2);
sfbus_send_frame(0xFFFF, &msg, 1);
sfbus_send_frame_v2(0xFFFF, &msg, 1);
}
else if (opcode == CMDB_RPWROFF)
{
@@ -163,7 +164,7 @@ void readCommand()
// invalid opcode
char msg = CMDR_ERR_INVALID;
_delay_ms(2);
sfbus_send_frame(0xFFFF, &msg, 1);
sfbus_send_frame_v2(0xFFFF, &msg, 1);
}
}
free(payload);

View File

@@ -45,6 +45,7 @@ uint8_t sts_flag_busy = 0; // device is busy
uint16_t currentVoltage = 0; // current ADC reading
uint8_t currentFaultReadings = 0; // ticks with faulty readings (too many will
// trip pwrdwn and sts_flag_fuse)
uint16_t timer_ticks = 0;
int STEPS_OFFSET = 0;
// initialize motor controller
@@ -109,6 +110,7 @@ void readVoltage()
// MAIN service routine. Called by timer 1
ISR(TIMER1_COMPA_vect)
{
timer_ticks ++;
readVoltage(); // read and check voltage
if (sts_flag_pwrdwn == 1 || sts_flag_failsafe == 1)
{
@@ -239,7 +241,7 @@ uint8_t getSts()
status |= sts_flag_fuse << 2; // bit 2: fuse blown
status |= sts_flag_pwrdwn << 4; // bit 4: device powered down
status |= sts_flag_failsafe << 5; // bit 5: failsafe active
status |= sts_flag_busy << 6; // bit 6: failsafe active
status |= sts_flag_busy << 6; // bit 6: device busy
if ((PIND & (1 << PD3)) == 0)
{
status |= (1 << 3);

View File

@@ -42,6 +42,7 @@ uint8_t getSts();
uint16_t getVoltage();
void mctrl_power(uint8_t state);
uint16_t timer_ticks;
#ifdef __cplusplus
}
#endif // __cplusplus

View File

@@ -6,6 +6,7 @@
* https://github.com/dennis9819/splitflap_v1
*/
#include "mctrl.h"
#include "rs485.h"
void rs485_init()
@@ -21,14 +22,7 @@ void rs485_init()
UCSRC |= (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1); // 8bit data format
}
void dbg(char data)
{
while (!(UCSRA & (1 << UDRE)))
;
UDR = data;
}
// send byte over rs485
void rs485_send_c(char data)
{
PORTD |= (1 << PD2); // set transciever to transmitt
@@ -39,17 +33,10 @@ void rs485_send_c(char data)
while (!(UCSRA & (1 << TXC)))
{
}; // wait until transmitt complete
PORTD &= ~(1 << PD2); // set transciever to transmitt
}
void rs485_send_str(char *data)
{
for (unsigned int i = 0; i < sizeof(data); i++)
{
rs485_send_c(data[i]);
}
PORTD &= ~(1 << PD2); // set transciever back to receive
}
// receive without timeout
char rs485_recv_c()
{
while (!(UCSRA & (1 << RXC)))
@@ -57,42 +44,69 @@ char rs485_recv_c()
return UDR;
}
// SFBUS Functions
uint8_t sfbus_recv_frame(uint16_t address, char *payload)
// receive with timeout
int rs485_recv_c_rxout(uint8_t timeout, char *data)
{
while (rs485_recv_c() != SFBUS_SOF_BYTE)
timer_ticks = 0;
while (!(UCSRA & (1 << RXC)))
{
} // Wwait for start byte
uint8_t frm_version = rs485_recv_c();
if (frm_version != 0)
return 0;
uint8_t frm_length = rs485_recv_c();
uint8_t frm_addrL = rs485_recv_c();
uint8_t frm_addrH = rs485_recv_c();
uint16_t frm_addr = frm_addrL | (frm_addrH << SHIFT_1B);
if (frm_addr != address)
return 0;
char *_payload = payload;
for (uint8_t i = 0; i < (frm_length - 3); i++)
{
*_payload = rs485_recv_c();
_payload++;
if (timer_ticks > timeout)
{
return 0;
}
}
if (rs485_recv_c() != SFBUS_EOF_BYTE)
return -1;
return frm_length;
*data = UDR;
return 1;
}
void sfbus_send_frame(uint16_t address, char *payload, uint8_t length)
// SFBUS Functions
// receive paket with crc checking and timeout
uint8_t sfbus_recv_frame_v2(uint16_t address, char *payload)
{
const uint8_t RX_TIMEOUT = 2;
while (rs485_recv_c() != SFBUS_SOF_BYTE)
{
} // Wait for start byte
uint8_t frm_version, frm_length;
if (rs485_recv_c_rxout(RX_TIMEOUT, (char *)&frm_version) == 0) // read header: version
return -1;
if (rs485_recv_c_rxout(RX_TIMEOUT, (char *)&frm_length) == 0) // read header: payload length
return -1;
// ALWAYS!!! receive full packet to avoid sync error
for (int i = 0; i < frm_length; i++)
{
if (rs485_recv_c_rxout(RX_TIMEOUT, payload + i) == 0)
{
return -1;
}
}
// check protocol version
if (frm_version != 0x01)
{
return -1; // abort on incompatible version
}
// if version matches, read address and checksum
uint16_t recv_addr = (*(payload + 0) & 0xFF) | ((*(payload + 1) & 0xFF) << SHIFT_1B);
uint16_t checksum = (*(payload + (frm_length - 2)) & 0xFF) | ((*(payload + (frm_length - 1)) & 0xFF) << SHIFT_1B);
// calculate checksum of received payload
uint16_t checksum_calc = calc_CRC16(payload + 2, frm_length - 4);
// return length on valid address and crc, return 0 to ignore
return (checksum == checksum_calc && address == recv_addr) ? frm_length : 0;
}
// send paket with crc
void sfbus_send_frame_v2(uint16_t address, char *payload, uint8_t length)
{
uint8_t framelen = length;
// claculate crc value
uint16_t crc = calc_CRC16(payload, framelen);
rs485_send_c(SFBUS_SOF_BYTE); // send startbyte 3 times
rs485_send_c(0); // send protocol version
rs485_send_c((char)(framelen + 3)); // send lentgh of remaining frame
rs485_send_c(SFBUS_SOF_BYTE); // send startbyte
rs485_send_c(1); // send protocol version
rs485_send_c((char)(framelen + 4)); // send lentgh of remaining frame
rs485_send_c((char)(address & 0xFF)); // target address
rs485_send_c((char)((address >> SHIFT_1B) & 0xFF));
@@ -104,5 +118,32 @@ void sfbus_send_frame(uint16_t address, char *payload, uint8_t length)
framelen--;
}
rs485_send_c(SFBUS_EOF_BYTE); // send end of frame byte
rs485_send_c((char)(crc & 0xFF)); // send crc
rs485_send_c((char)((crc >> SHIFT_1B) & 0xFF));
}
// calculate crc checksum
uint16_t calc_CRC16(char *buffer, uint8_t len)
{
uint16_t crc16 = 0xFFFF;
for (uint8_t pos = 0; pos < len; pos++)
{
char byte_value = *(buffer); // read byte after byte from buffer
buffer++;
crc16 ^= byte_value; // XOR byte into least sig. byte of crc
for (int i = 8; i != 0; i--)
{ // Loop over each bit
if ((crc16 & 0x0001) != 0)
{ // If the LSB is set
crc16 >>= 1; // Shift right and XOR 0xA001
crc16 ^= 0xA001;
}
else
{ // Else LSB is not set
crc16 >>= 1; // Just shift right
}
}
}
return crc16;
}

View File

@@ -9,24 +9,29 @@
#pragma once
//#define F_CPU 16000000UL
#define UART_BAUD 19200 // RS485 baud rate
#define BAUDRATE ((F_CPU) / (UART_BAUD * 16UL) - 1) // set baud rate value for UBRR
//#define UART_BAUD 19200 // RS485 baud rate
#define UART_BAUD 57600 // RS485 baud rate
#define BAUDRATE ((F_CPU) / (UART_BAUD * 16UL) - 1) // set baud rate value for UBRR
#define SFBUS_SOF_BYTE '+' // Byte marks start of frame
#define SFBUS_EOF_BYTE '$' // Byte marks end of frame
#define SFBUS_SOF_BYTE '+' // Byte marks start of frame
#define SFBUS_EOF_BYTE '$' // Byte marks end of frame
#ifdef __cplusplus
extern "C" {
extern "C"
{
#endif // __cplusplus
void dbg(char data);
void rs485_init(void);
void rs485_send_c(char data);
void rs485_send_str(char* data);
char rs485_recv_c(void);
void rs485_init(void);
void rs485_send_c(char data);
char rs485_recv_c(void);
int rs485_recv_c_rxout(uint8_t timeout, char *data);
uint8_t sfbus_recv_frame(uint16_t address, char* payload);
void sfbus_send_frame(uint16_t address, char* payload, uint8_t length);
uint8_t sfbus_recv_frame_v2(uint16_t address, char *payload);
void sfbus_send_frame_v2(uint16_t address, char *payload, uint8_t length);
uint16_t calc_CRC16(char *buffer, uint8_t len);
// auxilary var for uart timeout
extern uint16_t timer_ticks;
#ifdef __cplusplus
}