/* 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 }