#define N_SENSORS 12
#define N_TRIG_SENSORS 4
-static int16_t distances[N_SENSORS];
+// static int16_t distances[N_SENSORS];
+
+// hold_regs[0] is unit ID
+#define thresholds (hold_regs+1)
+#define led1_sensors (hold_regs[13])
+#define led2_sensors (hold_regs[14])
+
+#define led_bitmap (hold_regs[MB_N_HOLD_REGS_EEPROM])
+#define distances (hold_regs+MB_N_HOLD_REGS_EEPROM+1)
+#define free_bitmap (hold_regs[MB_N_HOLD_REGS_EEPROM+13])
+#define err_bitmap (hold_regs[MB_N_HOLD_REGS_EEPROM+14])
static void pull_trigger(uint8_t trig)
{
if (state) {
PORTD |= _BV(PD4);
// PORTC |= _BV(PC5);
+ led_bitmap |= 1;
} else {
PORTD &= ~_BV(PD4);
// PORTC &= ~_BV(PC5);
+ led_bitmap &= ~1;
}
} else {
if (state) {
PORTB |= _BV(PB5);
+ led_bitmap |= 2;
} else {
PORTB &= ~_BV(PB5);
+ led_bitmap &= ~2;
}
}
}
+static void eval_bitmaps()
+{
+ uint16_t free_b = 0, err_b = 0, mask;
+ uint8_t i;
+
+ for (i = 0; i < N_SENSORS; i++) {
+ mask = 1 << i;
+
+ if (thresholds[i]) {
+ if (distances[i] == -1 || distances[i] == 0) {
+ err_b |= mask;
+ } else if (distances[i] > thresholds[i]) {
+ free_b |= mask;
+ }
+ }
+ }
+
+ free_bitmap = free_b;
+ err_bitmap = err_b;
+
+ if (led1_sensors) {
+ if (led1_sensors & free_bitmap) {
+ led_set(0, 1);
+ } else {
+ led_set(0, 0);
+ }
+ }
+
+ if (led2_sensors) {
+ if (led2_sensors & free_bitmap) {
+ led_set(1, 1);
+ } else {
+ led_set(1, 0);
+ }
+ }
+}
+
+uint8_t hold_reg_is_valid(uint16_t reg, uint16_t val)
+{
+ if (reg == MB_HOLD_REGS_BASE)
+ return val > 0 && val <= 247;
+
+ return 1;
+}
+
int main()
{
- modbus_init();
+ modbus_init(0);
// output pins
DDRD |= _BV(PD7); // Trig D
sei();
while(1) {
- // do_measurements();
- modbus_poll();
- led_set(0,
- distances[4] > 100 || distances[11] > 100);
+ uint8_t trig;
+ for (trig = 0; trig < N_TRIGGERS; trig++) {
+ uint16_t now;
+ do_measurement(trig);
+ now = TCNT1;
+ while (TCNT1-now < 200)
+ modbus_poll();
+ }
+
+ eval_bitmaps();
+// led_set(0,
+// distances[4] > 100 || distances[11] > 100);
}
}
* All bugs by Jan "Yenya" Kasprzak <kas@fi.muni.cz> :-)
*/
+#include <avr/eeprom.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/atomic.h>
#include <util/delay.h>
+#include "modbus.h"
+
#define BUFSIZE 128 // must be a power of two
// configure the control pin
static volatile bufptr_t rx_bytes, tx_head, tx_tail;
static volatile uint8_t rxbuf[BUFSIZE], txbuf[BUFSIZE];
static volatile uint16_t last_rx;
-static volatile uint8_t unit_id;
+#ifndef mb_unit_id
+static uint8_t mb_unit_id;
+#endif
#define UART_BAUD 9600
#define UBRR_VAL ((F_CPU + 8UL * UART_BAUD) / (16UL*UART_BAUD) - 1)
*/
#define TIMEOUT (28*CLOCK_SPEED/UART_BAUD)
-void modbus_init()
+uint16_t hold_regs[MB_N_HOLD_REGS];
+
+#if MB_N_HOLD_REGS_EEPROM > 0
+static uint16_t hold_regs_ee[MB_N_HOLD_REGS_EEPROM] EEMEM = {
+ 42,
+ 0, 0, 0, 30, 30, 30, 30, 0, 0, 0, 0, 30,
+ (1 << 4) | (1 << 11), // LED 1
+ 0, // LED 2
+};
+
+#endif
+
+void modbus_init(uint8_t unit)
{
rx_bytes = 0;
tx_head = tx_tail = 0;
- unit_id = 42;
+ if (unit)
+ mb_unit_id = unit;
+#if MB_N_HOLD_REGS_EEPROM > 0
+ do {
+ int i;
+ for (i = 0; i < MB_N_HOLD_REGS_EEPROM; i++)
+ hold_regs[i] = eeprom_read_word(&hold_regs_ee[i]);
+ } while (0);
+#endif
ctl_pin_off();
ctl_pin_setup();
return crc;
}
-static void make_exception(uint8_t func, uint8_t code)
+static void make_exception(mb_exception code)
+{
+ txbuf[1] |= 0x80;
+ txbuf[2] = code;
+ tx_head = 3;
+}
+
+#define get_word(ptr, off) (((uint16_t)ptr[off] << 8) | ptr[off+1])
+void put_byte(uint8_t byte)
+{
+ txbuf[tx_head++] = byte;
+}
+
+void put_word(uint16_t word)
{
- txbuf[tx_head++] = unit_id;
- txbuf[tx_head++] = func | 0x80;
- txbuf[tx_head++] = code;
+ txbuf[tx_head++] = word >> 8;
+ txbuf[tx_head++] = word & 0xFF;
+}
+
+static mb_exception read_holding_regs(uint16_t start, uint16_t len)
+{
+ if (len > BUFSIZE/2 - 3)
+ return MB_ILLEGAL_ADDR;
+
+ if (start < MB_HOLD_REGS_BASE
+ || start + len > MB_HOLD_REGS_BASE + MB_N_HOLD_REGS)
+ return MB_ILLEGAL_ADDR;
+
+ put_byte(2*len);
+
+ start -= MB_HOLD_REGS_BASE;
+ while(len--)
+ put_word(hold_regs[start++]);
+
+ return MB_OK;
+}
+
+static mb_exception write_single_reg(uint16_t reg, uint16_t val)
+{
+ if (reg < MB_HOLD_REGS_BASE
+ || reg >= MB_HOLD_REGS_BASE + MB_N_HOLD_REGS)
+ return MB_ILLEGAL_ADDR;
+
+ if (!hold_reg_is_valid(reg, val))
+ return MB_ILLEGAL_VAL;
+
+ reg -= MB_HOLD_REGS_BASE;
+ hold_regs[reg] = val;
+#if MB_N_HOLD_REGS_EEPROM > 0
+ if (reg < MB_N_HOLD_REGS_EEPROM)
+ eeprom_write_word(&hold_regs_ee[reg], val);
+#endif
+ put_word(reg + MB_HOLD_REGS_BASE);
+ put_word(val);
+
+ return MB_OK;
}
void modbus_poll()
{
bufptr_t packet_len;
uint16_t crc;
+ uint8_t rv;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
if (rx_bytes == 0) // nothing received yet
return;
}
- if (rxbuf[0] != unit_id) { // not for myself
+ if (rxbuf[0] != mb_unit_id) { // not for myself
rx_bytes = 0;
return;
}
|| (crc >> 8) != rxbuf[packet_len-1]) // bad crc
goto out;
- tx_head = 0;
+ txbuf[0] = rxbuf[0]; // not mb_unit_id in case it gets changed
+ txbuf[1] = rxbuf[1];
+ tx_head = 2;
+ rv = MB_OK;
switch (rxbuf[1]) { // function
+ case 3:
+ rv = read_holding_regs(get_word(rxbuf, 2), get_word(rxbuf, 4));
+ break;
+ case 6:
+ rv = write_single_reg(get_word(rxbuf, 2), get_word(rxbuf, 4));
+ break;
default:
- make_exception(rxbuf[1], 1); // illegal function
+ make_exception(MB_ILLEGAL_FUNC); // illegal function
}
-
+
+ if (rv)
+ make_exception(rv);
send:
if (tx_head) {
crc = compute_crc(txbuf, tx_head);