aboutsummaryrefslogtreecommitdiffstats
path: root/nrf52
diff options
context:
space:
mode:
Diffstat (limited to 'nrf52')
-rw-r--r--nrf52/Makefile22
-rw-r--r--nrf52/Makefile.feather-5283210
-rw-r--r--nrf52/Makefile.feather-5284010
-rw-r--r--nrf52/i2c_ring_buffer.cpp24
-rw-r--r--nrf52/i2c_ring_buffer.h21
-rw-r--r--nrf52/log.h17
-rw-r--r--nrf52/nrf52.ino94
-rw-r--r--nrf52/state_machine.cpp79
-rw-r--r--nrf52/state_machine.h28
9 files changed, 305 insertions, 0 deletions
diff --git a/nrf52/Makefile b/nrf52/Makefile
new file mode 100644
index 0000000..fdb47ee
--- /dev/null
+++ b/nrf52/Makefile
@@ -0,0 +1,22 @@
+include ../Makefile.common
+#include Makefile.feather-52840
+include Makefile.feather-52832
+
+SERIALPORT = $(shell ../find-serial-port $(USBVID) $(USBPID) || echo 'cant-find-serial-port')
+
+APP = nrf52
+
+all: $(BUILDDIR)/$(APP).ino.zip
+
+flash: $(BUILDDIR)/$(APP).ino.zip $(SERIALPORT)
+ adafruit-nrfutil dfu serial --package $(BUILDDIR)/$(APP).ino.zip -p $(SERIALPORT) -b 115200 -sb -t 1200
+
+console:
+ screen $(SERIALPORT) 115200
+
+# Deps
+nrf52.ino: i2c_ring_buffer.cpp state_machine.cpp log.h ../common/i2c_message.h
+
+i2c_ring_buffer.cpp: i2c_ring_buffer.h
+
+state_machine.cpp: state_machine.h
diff --git a/nrf52/Makefile.feather-52832 b/nrf52/Makefile.feather-52832
new file mode 100644
index 0000000..c2dff2b
--- /dev/null
+++ b/nrf52/Makefile.feather-52832
@@ -0,0 +1,10 @@
+# -*- mode: Makefile -*-
+
+VENDOR = adafruit
+PLATFORM = nrf52
+BOARD = feather52832
+
+EXTRAPREFS = -prefs "build.sd_flags=-DS132" -prefs "build.sd_name=s132" -prefs "build.sd_version=6.1.1" -prefs "build.sd_fwid=0x00B7"
+
+USBVID = 10c4
+USBPID = ea60
diff --git a/nrf52/Makefile.feather-52840 b/nrf52/Makefile.feather-52840
new file mode 100644
index 0000000..81d7245
--- /dev/null
+++ b/nrf52/Makefile.feather-52840
@@ -0,0 +1,10 @@
+# -*- mode: Makefile -*-
+
+VENDOR = adafruit
+PLATFORM = nrf52
+BOARD = feather52840
+
+EXTRAPREFS = -prefs "build.sd_name=s140" -prefs "build.sd_version=6.1.1" -prefs "build.sd_fwid=0x00B6"
+
+USBVID = 239a
+USBPID = '0029|8029'
diff --git a/nrf52/i2c_ring_buffer.cpp b/nrf52/i2c_ring_buffer.cpp
new file mode 100644
index 0000000..0f215f2
--- /dev/null
+++ b/nrf52/i2c_ring_buffer.cpp
@@ -0,0 +1,24 @@
+#include "i2c_ring_buffer.h"
+
+#include <SimplyAtomic.h>
+
+I2CRingBuffer::I2CRingBuffer(): head(0), tail(0) {}
+
+bool I2CRingBuffer::read(uint8_t *v) {
+ ATOMIC() {
+ if (this->head == this->tail) {
+ return false;
+ }
+
+ *v = this->buf[this->head];
+ this->head = (this->head + 1) % RINGBUFLEN;
+ return true;
+ }
+}
+
+void I2CRingBuffer::write(uint8_t v) {
+ ATOMIC() {
+ this->buf[this->tail] = v;
+ this->tail = (this->tail + 1) % RINGBUFLEN;
+ }
+}
diff --git a/nrf52/i2c_ring_buffer.h b/nrf52/i2c_ring_buffer.h
new file mode 100644
index 0000000..a274798
--- /dev/null
+++ b/nrf52/i2c_ring_buffer.h
@@ -0,0 +1,21 @@
+#ifndef I2C_RING_BUFFER_H
+#define I2C_RING_BUFFER_H
+
+#include <stdint.h>
+
+#define RINGBUFLEN 256
+
+class I2CRingBuffer {
+public:
+ I2CRingBuffer();
+
+ bool read(uint8_t *);
+ void write(uint8_t);
+
+private:
+ volatile uint8_t buf[RINGBUFLEN];
+ volatile uint8_t head;
+ volatile uint8_t tail;
+};
+
+#endif
diff --git a/nrf52/log.h b/nrf52/log.h
new file mode 100644
index 0000000..b78fec0
--- /dev/null
+++ b/nrf52/log.h
@@ -0,0 +1,17 @@
+#ifndef LOG_H
+#define LOG_H
+
+#define DEBUG 0
+#if DEBUG
+#define dbgPrint(...) Serial.print(__VA_ARGS__)
+#define dbgPrintf(...) Serial.printf(__VA_ARGS__)
+#define dbgPrintln(...) Serial.println(__VA_ARGS__)
+#define dbgWrite(...) Serial.write(__VA_ARGS__)
+#else
+#define dbgPrint(...)
+#define dbgPrintf(...)
+#define dbgPrintln(...)
+#define dbgWrite(...)
+#endif
+
+#endif
diff --git a/nrf52/nrf52.ino b/nrf52/nrf52.ino
new file mode 100644
index 0000000..1b4ac3c
--- /dev/null
+++ b/nrf52/nrf52.ino
@@ -0,0 +1,94 @@
+// -*- mode: c++ -*-
+#include "i2c_message.h"
+#include "i2c_ring_buffer.h"
+#include "log.h"
+#include "state_machine.h"
+
+#include <bluefruit.h>
+#include <Wire.h>
+
+BLEDis bledis;
+BLEHidAdafruit blehid;
+
+I2CRingBuffer rb;
+StateMachine fsm(&blehid);
+
+void setup() {
+ pinMode(LED_BUILTIN, OUTPUT);
+ digitalWrite(LED_BUILTIN, HIGH);
+
+ pinMode(PIN_WIRE_SDA, INPUT_PULLUP);
+ pinMode(PIN_WIRE_SCL, INPUT_PULLUP);
+
+ Serial.begin(115200);
+ Serial.println("usb2btle booting.");
+
+ Wire.begin(BTLE_WIREADDR);
+ Wire.onReceive(wireDataReceived);
+
+ Bluefruit.begin();
+ Bluefruit.setTxPower(4);
+ Bluefruit.setName("usb2btle");
+
+ // Configure and Start Device Information Service
+ bledis.setManufacturer("Kublai Khansulting");
+ bledis.setModel("devel-nrf52832-trinketm0");
+ bledis.begin();
+
+ /* Start BLE HID
+ * Note: Apple requires BLE device must have min connection interval >= 20m
+ * ( The smaller the connection interval the faster we could send data).
+ * However for HID and MIDI device, Apple could accept min connection interval
+ * up to 11.25 ms. Therefore BLEHidAdafruit::begin() will try to set the min and max
+ * connection interval to 11.25 ms and 15 ms respectively for best performance.
+ */
+ blehid.begin();
+ blehid.setKeyboardLedCallback(setKeyboardLED);
+
+ startAdv();
+
+ digitalWrite(LED_BUILTIN, LOW);
+}
+
+void startAdv(void)
+{
+ Serial.println("Advertising HID.");
+
+ Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
+ Bluefruit.Advertising.addTxPower();
+ Bluefruit.Advertising.addAppearance(BLE_APPEARANCE_HID_KEYBOARD);
+ Bluefruit.Advertising.addService(blehid);
+ Bluefruit.Advertising.addName();
+ Bluefruit.Advertising.restartOnDisconnect(true);
+ Bluefruit.Advertising.setInterval(32, 244);
+ Bluefruit.Advertising.setFastTimeout(30);
+ Bluefruit.Advertising.start(0);
+}
+
+void loop() {
+ waitForEvent();
+
+ uint8_t v;
+ while (rb.read(&v)) {
+ dbgPrintf("got byte on rb: %02x\r\n", v);
+ fsm.byteReceived(v);
+ }
+}
+
+void wireDataReceived(int numBytes) {
+ dbgPrintf("wireDataReceived: %u\r\n", numBytes);
+ for (int i = 0; i < numBytes; i++) {
+ rb.write(Wire.read());
+ }
+}
+
+void setKeyboardLED(uint16_t conn_handle, uint8_t led_bitmap) {
+ (void) conn_handle;
+
+ // light up Red Led if any bits is set
+ if (led_bitmap) {
+ ledOn(LED_RED);
+ } else {
+ ledOff(LED_RED);
+ }
+}
diff --git a/nrf52/state_machine.cpp b/nrf52/state_machine.cpp
new file mode 100644
index 0000000..15e38b9
--- /dev/null
+++ b/nrf52/state_machine.cpp
@@ -0,0 +1,79 @@
+#include "state_machine.h"
+
+#include "i2c_message.h"
+#include "log.h"
+
+#include <Arduino.h>
+
+StateMachine::StateMachine(BLEHidAdafruit *blehid): currentState(WAIT_FOR_TYPE), blehid(blehid) {}
+
+void StateMachine::byteReceived(uint8_t inByte) {
+ dbgPrint("inByte=");
+ dbgPrintln(inByte);
+
+ switch (this->currentState) {
+ case WAIT_FOR_TYPE:
+ switch (inByte) {
+ case KBD:
+ digitalWrite(LED_BUILTIN, HIGH);
+ this->msgType = KBD;
+ break;
+
+ case DBG:
+ dbgPrint("T-M0: ");
+ this->msgType = DBG;
+ break;
+
+ default:
+ this->msgType = INVALID;
+ Serial.printf("Invalid message type: %ud.\r\n", inByte);
+ }
+
+ this->currentState = WAIT_FOR_LEN;
+ break;
+
+ case WAIT_FOR_LEN:
+ dbgPrintf("msg len: %u\r\n", inByte);
+ this->msgLen = inByte;
+ this->msgCount = 0;
+
+ if (this->msgLen == 0) {
+ this->currentState = WAIT_FOR_TYPE;
+ } else {
+ this->currentState = WAIT_FOR_DATA;
+ }
+ break;
+
+ case WAIT_FOR_DATA:
+ dbgPrintf("data: %02x\r\n", inByte);
+ switch (this->msgType) {
+ case KBD:
+ this->message[this->msgCount++ % sizeof(this->message)] = inByte;
+ break;
+
+ case DBG:
+ dbgPrint(inByte);
+ break;
+ }
+
+ if (this->msgCount == this->msgLen) {
+ switch (this->msgType) {
+ case KBD:
+ dbgPrintln("sending kbd report");
+ this->blehid->keyboardReport(this->message[0], &this->message[2]);
+ digitalWrite(LED_BUILTIN, LOW);
+ break;
+
+ case DBG:
+ dbgPrintln();
+ break;
+ }
+ this->currentState = WAIT_FOR_TYPE;
+ }
+ break;
+
+ default:
+ Serial.printf("Invalid message state: %ud.\r\n", this->currentState);
+ break;
+ }
+}
diff --git a/nrf52/state_machine.h b/nrf52/state_machine.h
new file mode 100644
index 0000000..d972926
--- /dev/null
+++ b/nrf52/state_machine.h
@@ -0,0 +1,28 @@
+#ifndef STATE_MACHINE_H
+#define STATE_MACHINE_H
+
+#include "i2c_message.h"
+
+#include <bluefruit.h>
+
+#include <stdint.h>
+
+#define MAX_MSG_LEN 32
+
+enum state_t {WAIT_FOR_TYPE, WAIT_FOR_LEN, WAIT_FOR_DATA};
+
+class StateMachine {
+public:
+ StateMachine(BLEHidAdafruit *);
+ void byteReceived(uint8_t);
+
+private:
+ state_t currentState;
+ uint8_t message[MAX_MSG_LEN];
+ uint8_t msgLen, msgCount;
+ i2c_message_t msgType;
+
+ BLEHidAdafruit *blehid;
+};
+
+#endif