109 lines
2.7 KiB
C
109 lines
2.7 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() != SFBUS_SOF_BYTE)
|
|
{
|
|
} // 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 (rs485_recv_c() != SFBUS_EOF_BYTE)
|
|
return -1;
|
|
return frm_length;
|
|
}
|
|
|
|
void sfbus_send_frame(uint16_t address, char *payload, uint8_t length)
|
|
{
|
|
uint8_t framelen = length;
|
|
|
|
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((char)(address & 0xFF)); // target address
|
|
rs485_send_c((char)((address >> SHIFT_1B) & 0xFF));
|
|
|
|
while (framelen > 0)
|
|
{ // send payload
|
|
rs485_send_c(*payload);
|
|
payload++;
|
|
framelen--;
|
|
}
|
|
|
|
rs485_send_c(SFBUS_EOF_BYTE); // send end of frame byte
|
|
}
|