#include "clock.h"
#include "modbus.h"
-#define BUFSIZE 128 // maximum request size
+#define BUFSIZE 180 // maximum request size
// configure the control pin
#define ctl_pin_setup() do { DDRD |= _BV(PD2); } while (0)
#endif
static volatile bufptr_t buf_len, tx_ptr;
-static volatile uint8_t buffer[BUFSIZE], transmitting;;
+static volatile uint8_t buffer[BUFSIZE], transmitting;
static volatile uint16_t last_rx;
#ifndef mb_unit_id
static uint8_t mb_unit_id;
return MB_OK;
}
-void modbus_poll()
+uint8_t modbus_poll()
{
bufptr_t packet_len;
uint16_t crc;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
if (transmitting)
- return;
-
- if (buf_len == 0) // nothing received yet
- return;
+ return 0;
if (get_clock() - last_rx < REQ_TIMEOUT) // still receiving
- return;
-
- if (buf_len < 4) { // too short
- buf_len = 0;
- return;
- }
+ return 0;
- if (buffer[0] != mb_unit_id) { // not for myself
+ if (buf_len < 4) { // too short (or not for us)
buf_len = 0;
- return;
+ return 0;
}
transmitting = 1; // disable further reads
transmitting = 0;
buf_len = 0;
}
- return;
+ return 1;
}
packet_len -= 2; // strip the CRC
switch (buffer[1]) { // function
case 3:
- if (packet_len == 5)
+ if (packet_len == 6)
rv = read_holding_regs(
get_word(buffer, 2),
get_word(buffer, 4)
);
break;
case 6:
- if (packet_len == 5)
+ if (packet_len == 6)
rv = write_single_reg(
get_word(buffer, 2),
get_word(buffer, 4)
tx_ptr = 0;
ctl_pin_on();
UCSR0B |= _BV(UDRIE0);
+
+ return 1;
}
ISR(USART_RX_vect)
{
uint8_t rx_byte = UDR0;
+ clock_t now = get_clock();
+
+ if (transmitting) // how did we get here? discard it
+ goto out;
- if (transmitting) // discard it
- return;
+ if (buf_len && buffer[0] != mb_unit_id) // not for us
+ goto out;
- buffer[buf_len] = rx_byte;
+ if (buf_len == BUFSIZE) { // overrun - discard the packet
+ buffer[0] = 0xFF;
+ buf_len = 1;
+ goto out;
+ }
- if (buf_len + 1 < BUFSIZE) // ignore overruns
- buf_len++;
+ if (now - last_rx >= REQ_TIMEOUT) { // new packet; start over
+ buf_len = 0;
+ }
- last_rx = get_clock();
+ // TODO: we can probably calculate the CRC here as well
+ buffer[buf_len++] = rx_byte;
+out:
+ last_rx = now;
}
ISR(USART_TX_vect)
ISR(USART_UDRE_vect)
{
- if (tx_ptr+1 >= buf_len) {
+ if (tx_ptr >= buf_len) {
+ UCSR0A |= _BV(TXC0); // clear the pending TXC flag
UCSR0B |= _BV(TXCIE0); // enable xmit complete irq
UCSR0B &= ~_BV(UDRIE0); // disable ourselves
} else {