matemat/feedback/firmware/main.c

129 lines
2.6 KiB
C
Raw Normal View History

2021-01-17 15:37:57 +01:00
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <can.h>
2021-01-19 19:30:35 +01:00
#include <messages.h>
2021-01-17 15:37:57 +01:00
static bool report_change = false;
static uint16_t saved_status;
2021-02-08 16:14:56 +01:00
static uint16_t status_hysteresis[2];
2021-01-17 15:37:57 +01:00
static void init() {
// Set PB as input, pull-up off
DDRB = 0;
// Set PC0/4/6 as input, pull-up off
DDRC &= ~(_BV(DDC0) | _BV(DDC4) | _BV(DDC6));
// Initialize CAN interface
can_init(BITRATE_125_KBPS);
// Regular receive/transmit mode
can_set_mode(NORMAL_MODE);
// Filter for messages addressed to us (RTR on)
can_filter_t us = {
.id = CAN_HOSTID_FEEDBACK,
.mask = CAN_HOSTID_MASK,
2021-01-17 15:37:57 +01:00
.flags = {
.rtr = 1,
.extended = 0,
},
};
can_set_filter(0, &us);
// Filter for public messages (RTR off)
can_filter_t pub = {
.id = CAN_HOSTID_BROADCAST,
.mask = CAN_HOSTID_MASK,
.flags = {
.rtr = 0,
.extended = 0,
},
};
can_set_filter(1, &pub);
2021-01-17 15:37:57 +01:00
// Enable interrupts to start reception
sei();
}
static uint16_t get_status() {
2021-01-17 15:37:57 +01:00
// Get GPIO state
// PB -> invert -> Dend..Hend, Dempty..Fempty
uint8_t statusl = ~PINB;
// PC0,6,4 -> invert -> Gempty, Hempty, Reset
uint8_t pinc = ~PINC;
uint8_t gempty = (pinc & _BV(0)) ? _BV(0) : 0;
uint8_t hempty = (pinc & _BV(6)) ? _BV(1) : 0;
uint8_t swres = (pinc & _BV(4)) ? _BV(2) : 0;
uint8_t statush = gempty | hempty | swres;
return ((uint16_t) statush << 8) | ((uint16_t) statusl);
}
2021-02-08 16:14:56 +01:00
static uint16_t graded_status() {
uint16_t status = get_status();
2021-02-08 16:50:57 +01:00
// report a one bit if the majority of the last states had a one
uint16_t graded =
(status_hysteresis[0] & status_hysteresis[1]) |
(status_hysteresis[1] & status) |
(status_hysteresis[0] & status);
2021-02-08 16:14:56 +01:00
status_hysteresis[0] = status_hysteresis[1];
status_hysteresis[1] = status;
return graded;
}
static void send_status(uint16_t status) {
2021-01-17 15:37:57 +01:00
if (can_check_free_buffer()) {
can_t msg = {
.id = CAN_MSG_FEEDBACK_STATUS,
2021-01-17 15:37:57 +01:00
.flags = {
.rtr = 0,
},
.length = 2,
.data = { (uint8_t) (status >> 8), status & 0xff, },
2021-01-17 15:37:57 +01:00
};
can_send_message(&msg);
}
}
static void loop() {
// Check for status changes
2021-02-08 16:14:56 +01:00
uint16_t new_status = graded_status();
2021-01-19 19:40:07 +01:00
if (new_status != saved_status) {
if (report_change) {
send_status(new_status);
}
saved_status = new_status;
}
2021-01-19 19:40:07 +01:00
2021-01-17 15:37:57 +01:00
// Check for new messages
if (can_check_message()) {
can_t msg = { 0 };
uint8_t status = can_get_message(&msg);
if (status != 0) {
switch (msg.id) {
case CAN_MSG_FEEDBACK_STATUS:
2021-02-08 16:14:56 +01:00
send_status(new_status);
2021-01-18 20:25:36 +01:00
break;
case CAN_MSG_AUTO_STATUS:
if (msg.length == 1) {
report_change = msg.data[0] ? true : false;
}
break;
2021-01-17 15:37:57 +01:00
}
}
}
2021-02-08 16:14:56 +01:00
2021-02-08 16:50:57 +01:00
_delay_ms(200);
2021-01-17 15:37:57 +01:00
}
int main() {
init();
while (1) {
loop();
}
}