216 lines
5.0 KiB
C++
216 lines
5.0 KiB
C++
#define DEVICE_ID 0x00
|
|
#define KEEPALIVE_INTERVAL_MSEC 5000UL
|
|
|
|
#define DRIVER_ENABLE 4
|
|
#define RECEIVER_nENABLE 2
|
|
|
|
#define SWITCH0 A3
|
|
#define SWITCH1 A2
|
|
#define SWITCH2 A1
|
|
#define SWITCH3 A0
|
|
#define SWITCH4 13
|
|
#define SWITCH5 12
|
|
|
|
#define OUT0 3
|
|
#define OUT1 5
|
|
#define OUT2 6
|
|
#define OUT3 9
|
|
#define OUT4 11
|
|
#define OUT5 10
|
|
|
|
static uint8_t pattern_buf[6] = {0,0,0,0,0};
|
|
static const uint8_t target_pattern[6] = {4, 2, 3, 5, 1, 0};
|
|
static const uint8_t input_pins[] = {SWITCH0, SWITCH1 ,SWITCH2, SWITCH3, SWITCH4, SWITCH5};
|
|
static const uint8_t output_pins[] = {OUT0, OUT1, OUT2, OUT3, OUT4, OUT5};
|
|
static int8_t last_input = -1, input_count = 0;
|
|
|
|
typedef enum packet_type_t {
|
|
PACKET_KEEPALIVE = 0,
|
|
PACKET_INPUT, /* Discrete input button / switch event */
|
|
PACKET_OUTPUT, /* Notify room controller that we triggered output */
|
|
PACKET_SOLVED,
|
|
PACKET_FAILED,
|
|
PACKET_LOG
|
|
} __attribute__((__packed__)) packet_type_t;
|
|
|
|
typedef struct pheader_t {
|
|
packet_type_t p_type;
|
|
uint8_t id;
|
|
} __attribute__((__packed__)) pheader_t;
|
|
|
|
void eia485_send(uint8_t *packet, size_t len) {
|
|
driver_enable();
|
|
Serial.write(packet, len);
|
|
Serial.flush();
|
|
driver_disable();
|
|
}
|
|
|
|
uint16_t calc_crc(uint8_t *msg,int n)
|
|
{
|
|
uint16_t x = 0;
|
|
|
|
while(n--) {
|
|
x = crc_xmodem_update(x, (uint16_t)*msg++);
|
|
}
|
|
|
|
return(x);
|
|
}
|
|
|
|
uint16_t crc_xmodem_update (uint16_t crc, uint8_t data)
|
|
{
|
|
int i;
|
|
|
|
crc = crc ^ ((uint16_t)data << 8);
|
|
for (i=0; i<8; i++) {
|
|
if (crc & 0x8000)
|
|
crc = (crc << 1) ^ 0x1021; //(polynomial = 0x1021)
|
|
else
|
|
crc <<= 1;
|
|
}
|
|
return crc;
|
|
}
|
|
|
|
void send_packet(packet_type_t type, uint8_t* data, uint8_t len) {
|
|
uint8_t packet_len = len+sizeof(pheader_t)+3;
|
|
uint8_t buf[packet_len];
|
|
buf[0] = type;
|
|
buf[1] = DEVICE_ID;
|
|
memcpy(buf+2, data, len);
|
|
uint16_t crc = calc_crc(buf, packet_len - 3);
|
|
buf[packet_len - 3] = crc >> 8;
|
|
buf[packet_len - 2] = crc & 0xff;
|
|
buf[packet_len - 1] = 0xC0;
|
|
eia485_send(buf, packet_len);
|
|
}
|
|
|
|
void driver_init(void) {
|
|
/* Serial and serial support pin setup */
|
|
driver_disable();
|
|
pinMode(DRIVER_ENABLE, OUTPUT);
|
|
pinMode(RECEIVER_nENABLE, OUTPUT);
|
|
}
|
|
|
|
inline void driver_enable(void) {
|
|
digitalWrite(DRIVER_ENABLE, HIGH);
|
|
digitalWrite(RECEIVER_nENABLE, LOW);
|
|
}
|
|
|
|
inline void driver_disable(void) {
|
|
digitalWrite(DRIVER_ENABLE, LOW);
|
|
digitalWrite(RECEIVER_nENABLE, HIGH);
|
|
}
|
|
|
|
void setup() {
|
|
pinMode(SWITCH0, INPUT_PULLUP);
|
|
pinMode(SWITCH1, INPUT_PULLUP);
|
|
pinMode(SWITCH2, INPUT_PULLUP);
|
|
pinMode(SWITCH3, INPUT_PULLUP);
|
|
pinMode(SWITCH4, INPUT_PULLUP);
|
|
pinMode(SWITCH5, INPUT_PULLUP);
|
|
|
|
pinMode(OUT0, OUTPUT);
|
|
pinMode(OUT1, OUTPUT);
|
|
pinMode(OUT2, OUTPUT);
|
|
pinMode(OUT3, OUTPUT);
|
|
pinMode(OUT4, OUTPUT);
|
|
pinMode(OUT5, OUTPUT);
|
|
set_all(false);
|
|
|
|
|
|
/* Serial and serial support pin setup */
|
|
driver_init();
|
|
Serial.begin(1000000);
|
|
|
|
set_all(true);
|
|
delay(1000);
|
|
set_all(false);
|
|
randomSeed(analogRead(A4));
|
|
delay(random(500));
|
|
send_packet(PACKET_LOG, (uint8_t*) "Alive", 6);
|
|
}
|
|
|
|
void loop() {
|
|
if (!(millis() % KEEPALIVE_INTERVAL_MSEC)) {
|
|
/* Send keepalive every */
|
|
send_packet(PACKET_KEEPALIVE, NULL, 0);
|
|
delay(2);
|
|
}
|
|
for (uint8_t i = 0; i < sizeof(input_pins); i++) {
|
|
/* Button i pressed */
|
|
if (digitalRead(input_pins[i]) == LOW) {
|
|
if (last_input == i) {
|
|
/* Primitive debounce */
|
|
continue;
|
|
}
|
|
/* Blink to acknowledge entry */
|
|
digitalWrite(output_pins[i], !digitalRead(output_pins[i]));
|
|
delay(100);
|
|
digitalWrite(output_pins[i], !digitalRead(output_pins[i]));
|
|
|
|
last_input = i;
|
|
pattern_buf[input_count] = i;
|
|
input_count += 1;
|
|
|
|
/* Illumated buttons in correct positions */
|
|
if (target_pattern[input_count-1] == i) {
|
|
digitalWrite(output_pins[i], HIGH);
|
|
}
|
|
|
|
/* After six entries, see if the correct code has been entered */
|
|
if (input_count == 6) {
|
|
if (!memcmp(pattern_buf, target_pattern, sizeof(target_pattern))) {
|
|
win();
|
|
} else {
|
|
send_packet(PACKET_FAILED, NULL, 0);
|
|
delay(1000);
|
|
nope();
|
|
set_all(false);
|
|
input_count = 0;
|
|
last_input = -1;
|
|
}
|
|
}
|
|
uint8_t buf[2];
|
|
buf[0] = i;
|
|
buf[1] = LOW;
|
|
send_packet(PACKET_INPUT, buf, 2);
|
|
}
|
|
}
|
|
delay(1);
|
|
}
|
|
|
|
void set_all(bool val) {
|
|
for (uint8_t i = 0; i < 6; i++) {
|
|
digitalWrite(output_pins[i], val);
|
|
}
|
|
}
|
|
|
|
void win(void) {
|
|
while(true) {
|
|
set_all(true);
|
|
delay(1000);
|
|
set_all(false);
|
|
delay(1000);
|
|
send_packet(PACKET_SOLVED, NULL, 0);
|
|
}
|
|
}
|
|
|
|
void nope(void) {
|
|
for (uint8_t i = 0; i < 3; i++) {
|
|
digitalWrite(OUT0, HIGH);
|
|
digitalWrite(OUT2, HIGH);
|
|
digitalWrite(OUT4, HIGH);
|
|
digitalWrite(OUT1, LOW);
|
|
digitalWrite(OUT3, LOW);
|
|
digitalWrite(OUT5, LOW);
|
|
delay(500);
|
|
digitalWrite(OUT0, LOW);
|
|
digitalWrite(OUT2, LOW);
|
|
digitalWrite(OUT4, LOW);
|
|
digitalWrite(OUT1, HIGH);
|
|
digitalWrite(OUT3, HIGH);
|
|
digitalWrite(OUT5, HIGH);
|
|
delay(500);
|
|
}
|
|
}
|
|
|