software/arduino/ubus: ubus code dump
This commit is contained in:
2
software/arduino/ubus/.gitignore
vendored
Normal file
2
software/arduino/ubus/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
.pioenvs
|
||||
.piolibdeps
|
||||
224
software/arduino/ubus/lib/UBus/UBus.cpp
Normal file
224
software/arduino/ubus/lib/UBus/UBus.cpp
Normal file
@@ -0,0 +1,224 @@
|
||||
#include "UBus.h"
|
||||
|
||||
#include <PN532_HSU.h>
|
||||
#include <PN532.h>
|
||||
|
||||
PN532_HSU pn532hsu(Serial1);
|
||||
PN532 nfc(pn532hsu);
|
||||
|
||||
#include <FastLED.h>
|
||||
#define NUM_LEDS 10
|
||||
#define DATA_PIN 12
|
||||
CRGB leds[NUM_LEDS];
|
||||
|
||||
void UBus::begin() {
|
||||
RS485Class::begin(115200);
|
||||
|
||||
Serial.print("UBus starting up on address ");
|
||||
Serial.println(addr);
|
||||
|
||||
if (addr >= 0x80) {
|
||||
Serial.println("**** This device is unprovisioned! Disabling responder. ****");
|
||||
}
|
||||
|
||||
// Peripherals
|
||||
FastLED.addLeds<WS2811, DATA_PIN, RGB>(leds, NUM_LEDS);
|
||||
FastLED.show();
|
||||
|
||||
// PN532 UART needs a pullup
|
||||
pinMode(11, INPUT_PULLUP);
|
||||
pinMode(12, INPUT_PULLUP);
|
||||
|
||||
nfc.begin();
|
||||
uint32_t versiondata = nfc.getFirmwareVersion();
|
||||
|
||||
// Got ok data, print it out!
|
||||
Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
|
||||
Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
|
||||
Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
|
||||
|
||||
nfc.setPassiveActivationRetries(0xFF);
|
||||
nfc.SAMConfig();
|
||||
// Blink on bootup
|
||||
identify_ts = 1;
|
||||
|
||||
receive();
|
||||
}
|
||||
|
||||
void UBus::poll() {
|
||||
if (identify_ts != 0) {
|
||||
if (identify_ts + 200 > millis()) {
|
||||
digitalWrite(13, false);
|
||||
} else {
|
||||
identify_ts = 0;
|
||||
digitalWrite(13, true);
|
||||
}
|
||||
}
|
||||
|
||||
while(available() > 0) parse(read());
|
||||
|
||||
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
|
||||
uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
|
||||
|
||||
// Wait for an ISO14443A type cards (Mifare, etc.). When one is found
|
||||
// 'uid' will be populated with the UID, and uidLength will indicate
|
||||
// if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
|
||||
bool success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, &uid[0], &uidLength);
|
||||
|
||||
if (success) {
|
||||
for (uint8_t i=0; i < uidLength; i++)
|
||||
{
|
||||
Serial.print(uid[i], HEX);
|
||||
Serial.print(" ");
|
||||
}
|
||||
Serial.println("");
|
||||
}
|
||||
}
|
||||
|
||||
// Encodes a single byte and writes it into am output buffer
|
||||
void UBus::sendByte(uint8_t b) {
|
||||
if (b == HDLC_START || b == HDLC_ESC) {
|
||||
write(HDLC_ESC);
|
||||
write(b ^ 0x20);
|
||||
} else {
|
||||
write(b);
|
||||
}
|
||||
}
|
||||
|
||||
// Builds and sends a response message
|
||||
void UBus::send(uint8_t msg_type, uint8_t* buf, size_t size) {
|
||||
beginTransmission();
|
||||
uint16_t crc = CRC16_CCITT_INIT_VAL;
|
||||
write(HDLC_START);
|
||||
|
||||
sendByte(addr | 0x80); crc = _crc_ccitt_update(crc, addr | 0x80);
|
||||
sendByte(msg_type); crc = _crc_ccitt_update(crc, msg_type);
|
||||
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
sendByte(buf[i]); crc = _crc_ccitt_update(crc, buf[i]);
|
||||
}
|
||||
|
||||
sendByte(crc & 0xff);
|
||||
sendByte(crc >> 8);
|
||||
write(HDLC_START);
|
||||
endTransmission();
|
||||
}
|
||||
|
||||
// Handle message residing currently in the buffer
|
||||
void UBus::handleRequest() {
|
||||
uint8_t target = buffer[0];
|
||||
uint8_t msg_type = buffer[1];
|
||||
|
||||
uint8_t* payload = buffer + 2;
|
||||
uint8_t payload_len = buf_pos - 4;
|
||||
uint8_t resp[16];
|
||||
|
||||
// Serial.println(msg_type);
|
||||
|
||||
switch (msg_type) {
|
||||
case SYS_StatusPoll:
|
||||
resp[0] = 0x00;
|
||||
sendResponse(msg_type, resp, 1);
|
||||
break;
|
||||
|
||||
case SYS_Identify:
|
||||
identify_ts = millis();
|
||||
sendResponse(msg_type, resp, 0);
|
||||
break;
|
||||
|
||||
case SYS_SupportedCommands:
|
||||
resp[0] = 0x00;
|
||||
resp[1] = 0x01;
|
||||
resp[2] = 0x02;
|
||||
|
||||
sendResponse(msg_type, resp, 3);
|
||||
// SYS_StatusPoll, SYS_Identify, SYS_SupportedCommands,
|
||||
// ...
|
||||
break;
|
||||
|
||||
case GPIO_Write:
|
||||
for (uint8_t i = 0; i < payload_len / 2; i++) {
|
||||
pinMode(payload[2 * i], OUTPUT);
|
||||
digitalWrite(payload[2 * i], payload[2 * i + 1]);
|
||||
}
|
||||
|
||||
resp[0] = 0x00;
|
||||
sendResponse(msg_type, resp, 1);
|
||||
break;
|
||||
|
||||
case GPIO_Read:
|
||||
for (uint8_t i = 0; i < payload_len; i++) {
|
||||
pinMode(payload[i], INPUT_PULLUP);
|
||||
resp[i] = digitalRead(payload[i]);
|
||||
}
|
||||
sendResponse(msg_type, resp, payload_len);
|
||||
break;
|
||||
|
||||
case GPIO_WS2812:
|
||||
// TODO memcpy?
|
||||
for (uint8_t i = 0; i < payload_len / 3; i++) {
|
||||
leds[i].r = payload[3*i];
|
||||
leds[i].g = payload[3*i + 1];
|
||||
leds[i].b = payload[3*i + 2];
|
||||
}
|
||||
FastLED.show();
|
||||
sendResponse(msg_type, {}, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Sends a response while also handling delayed response in case of broadcast
|
||||
// messages
|
||||
void UBus::sendResponse(uint8_t msg_type, uint8_t buf[], size_t size) {
|
||||
if (buffer[0] == 0xff) {
|
||||
uint32_t _broadcast_timeslot = 20;
|
||||
uint32_t offset = 0; // millis() - _hdlc_start;
|
||||
if (_broadcast_timeslot * addr > offset) {
|
||||
delay(_broadcast_timeslot * addr - offset); // (millis() - _hdlc_start));
|
||||
send(msg_type, buf, size);
|
||||
}
|
||||
} else {
|
||||
send(msg_type, buf, size);
|
||||
}
|
||||
}
|
||||
|
||||
void UBus::parse(uint8_t c) {
|
||||
if (c == HDLC_ESC) {
|
||||
escape = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (c == HDLC_START) {
|
||||
escape = false;
|
||||
// Serial.println(millis() - _hdlc_start);
|
||||
// 1 byte address, 1 byte msg_type, 2 bytes checksum
|
||||
if (buf_pos >= 4) {
|
||||
if (checksum == 0) {
|
||||
// frame finish - verified
|
||||
// digitalWrite(13, !digitalRead(13));
|
||||
if ((buffer[0] == 0xff || buffer[0] == addr) && addr != 0xff) {
|
||||
handleRequest();
|
||||
}
|
||||
} else {
|
||||
Serial.println("Invalid frame: ");
|
||||
for (int i = 0; i < buf_pos; i++) { Serial.print(buffer[i], HEX); Serial.print(" "); }
|
||||
Serial.println(checksum);
|
||||
// frame invalid
|
||||
}
|
||||
}
|
||||
|
||||
buf_pos = 0;
|
||||
checksum = CRC16_CCITT_INIT_VAL;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (buf_pos < HDLC_BUF_SIZE) {
|
||||
// Serial.println(c);
|
||||
buffer[buf_pos] = escape ? c ^ 0x20 : c;
|
||||
checksum = _crc_ccitt_update(checksum, buffer[buf_pos]);
|
||||
buf_pos += 1;
|
||||
}
|
||||
|
||||
escape = false;
|
||||
}
|
||||
50
software/arduino/ubus/lib/UBus/UBus.h
Normal file
50
software/arduino/ubus/lib/UBus/UBus.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#ifndef UBUS_H
|
||||
#define UBUS_H
|
||||
|
||||
#include <ArduinoRS485.h>
|
||||
#include <util/crc16.h>
|
||||
|
||||
extern unsigned long _hdlc_start;
|
||||
|
||||
#define HDLC_START 0x7E
|
||||
#define HDLC_ESC 0x7D
|
||||
#define HDLC_BUF_SIZE 32
|
||||
#define CRC16_CCITT_INIT_VAL 0xFFFF
|
||||
|
||||
class UBus: public RS485Class {
|
||||
public:
|
||||
enum MessageType : uint8_t {
|
||||
SYS_StatusPoll = 0x00,
|
||||
SYS_Identify = 0x01,
|
||||
SYS_SupportedCommands = 0x02,
|
||||
|
||||
GPIO_Write = 0x10,
|
||||
GPIO_Read = 0x11,
|
||||
GPIO_WS2812 = 0x12,
|
||||
|
||||
PERI_NFC = 0x20,
|
||||
};
|
||||
|
||||
uint8_t addr = 0;
|
||||
uint32_t identify_ts = 0;
|
||||
|
||||
bool escape = false;
|
||||
|
||||
uint8_t buf_pos = 0;
|
||||
uint8_t buffer[HDLC_BUF_SIZE];
|
||||
uint16_t checksum = CRC16_CCITT_INIT_VAL;
|
||||
|
||||
UBus(): RS485Class(Serial, 1, 3, 2) { }
|
||||
|
||||
void begin();
|
||||
|
||||
void sendByte(uint8_t b);
|
||||
void send(uint8_t msg_type, uint8_t* buf, size_t size);
|
||||
void sendResponse(uint8_t msg_type, uint8_t* buf, size_t size);
|
||||
|
||||
void handleRequest();
|
||||
|
||||
void poll();
|
||||
void parse(uint8_t c);
|
||||
};
|
||||
#endif
|
||||
25
software/arduino/ubus/platformio.ini
Normal file
25
software/arduino/ubus/platformio.ini
Normal file
@@ -0,0 +1,25 @@
|
||||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env:uno]
|
||||
platform = atmelavr
|
||||
board = atmega328pb
|
||||
build_flags = -D SERIAL_PORT_HARDWARE=Serial
|
||||
framework = arduino
|
||||
upload_flags = -F
|
||||
monitor_port = /dev/serial/by-id/usb-FTDI_TTL232R_FTF48YOZ-if00-port0
|
||||
upload_port = /dev/serial/by-id/usb-FTDI_TTL232R_FTF48YOZ-if00-port0
|
||||
targets = upload, monitor
|
||||
monitor_speed = 115200
|
||||
lib_deps =
|
||||
Wire
|
||||
arduino-libraries/ArduinoRS485@^1.0.0
|
||||
fastled/FastLED@^3.4.0
|
||||
https://github.com/yoshitake-hamano/PN532
|
||||
42
software/arduino/ubus/src/main.ino
Normal file
42
software/arduino/ubus/src/main.ino
Normal file
@@ -0,0 +1,42 @@
|
||||
#include <EEPROM.h>
|
||||
#include <UBus.h>
|
||||
|
||||
const int RS485_RE = 2;
|
||||
const int RS485_DE = 3;
|
||||
|
||||
UBus bus;
|
||||
|
||||
void provision() {
|
||||
long start_ts = millis();
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println("This device is unprovisioned!");
|
||||
|
||||
while (start_ts + 10000 > millis()) {
|
||||
Serial.print("Address: ");
|
||||
long addr = Serial.parseInt(SKIP_WHITESPACE);
|
||||
if (addr < 0x01 || addr > 0x80) {
|
||||
Serial.println("Invalid address...");
|
||||
continue;
|
||||
}
|
||||
|
||||
EEPROM.write(0x00, addr);
|
||||
bus.addr = addr;
|
||||
Serial.println("Finished.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
pinMode(13, OUTPUT);
|
||||
bus.addr = EEPROM.read(0);
|
||||
|
||||
if (bus.addr == 0xff) {
|
||||
provision();
|
||||
}
|
||||
bus.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
bus.poll();
|
||||
}
|
||||
Reference in New Issue
Block a user