95 lines
2.6 KiB
C
95 lines
2.6 KiB
C
/* Copyright (C) 2025 Dennis Gunia - All Rights Reserved
|
|
* You may use, distribute and modify this code under the
|
|
* terms of the AGPL-3.0 license.
|
|
*
|
|
* https://www.dennisgunia.de
|
|
* https://github.com/dennis9819/splitflap_v1
|
|
*/
|
|
|
|
#include "rs485.h"
|
|
|
|
void rs485_init() {
|
|
// init I/O
|
|
DDRD &= ~(1 << PD0); // BUS_DIR & TX is OUTPUT
|
|
DDRD |= (1 << PD2) | (1 << PD1); // BUS_DIR & TX is OUTPUT
|
|
PORTD &= 0x07; // clear PD0-PD4
|
|
// init UART
|
|
UBRRH = (BAUDRATE >> 8);
|
|
UBRRL = BAUDRATE; // set baud rate
|
|
UCSRB |= (1 << TXEN) | (1 << RXEN); // enable receiver and transmitter
|
|
UCSRC |= (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1); // 8bit data format
|
|
}
|
|
|
|
void dbg(char data) {
|
|
while (!(UCSRA & (1 << UDRE)))
|
|
;
|
|
UDR = data;
|
|
}
|
|
|
|
|
|
|
|
void rs485_send_c(char data) {
|
|
PORTD |= (1 << PD2); // set transciever to transmitt
|
|
while (!(UCSRA & (1 << UDRE)))
|
|
; // wait until buffer is empty
|
|
UCSRA = (1 << TXC); // clear transmit Complete bit
|
|
UDR = 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]);
|
|
}
|
|
}
|
|
|
|
char rs485_recv_c() {
|
|
while (!(UCSRA & (1 << RXC)))
|
|
;
|
|
; // wait while data is being received
|
|
return UDR;
|
|
}
|
|
|
|
// SFBUS Functions
|
|
uint8_t sfbus_recv_frame(uint16_t address, char* payload) {
|
|
while (rs485_recv_c() != '+') {} // 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 << 8);
|
|
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 (rs485_recv_c() != '$') return -1;
|
|
return frm_length;
|
|
}
|
|
|
|
void sfbus_send_frame(uint16_t address, char* payload, uint8_t length) {
|
|
char framelen = length;
|
|
|
|
rs485_send_c(SFBUS_SOF_BYTE); // send startbyte 3 times
|
|
rs485_send_c(0); // send protocol version
|
|
rs485_send_c(framelen + 3); // send lentgh of remaining frame
|
|
|
|
rs485_send_c(address & 0xFF); // target address
|
|
rs485_send_c((address >> 8) & 0xFF);
|
|
|
|
while (framelen > 0) { // send payload
|
|
rs485_send_c(*payload);
|
|
payload++;
|
|
framelen--;
|
|
}
|
|
|
|
rs485_send_c(SFBUS_EOF_BYTE); // send end of frame byte
|
|
}
|