add protocol version2
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -42,6 +42,7 @@ uint8_t getSts();
|
||||
uint16_t getVoltage();
|
||||
void mctrl_power(uint8_t state);
|
||||
|
||||
uint16_t timer_ticks;
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user