From 0b141290b421874a5a77277937c85c2cec15c951 Mon Sep 17 00:00:00 2001 From: "matthias@arch" Date: Wed, 14 Jun 2023 19:22:11 +0200 Subject: [PATCH] BLE connection works --- teng/address.hpp | 104 --------------------------------- teng/control_bytes.hpp | 7 --- teng/eeprom.hpp | 70 ---------------------- teng/packet.hpp | 23 -------- teng/services.hpp | 17 ++++++ teng/settings.hpp | 6 ++ teng/status.hpp | 37 ++++++++++++ teng/teng.ino | 128 ++++++++++++++++++++++++----------------- 8 files changed, 134 insertions(+), 258 deletions(-) delete mode 100644 teng/address.hpp delete mode 100644 teng/control_bytes.hpp delete mode 100644 teng/eeprom.hpp delete mode 100644 teng/packet.hpp create mode 100644 teng/services.hpp create mode 100644 teng/settings.hpp create mode 100644 teng/status.hpp diff --git a/teng/address.hpp b/teng/address.hpp deleted file mode 100644 index 311d9f3..0000000 --- a/teng/address.hpp +++ /dev/null @@ -1,104 +0,0 @@ -#pragma once - -#include - -class Counter { - public: - const unsigned MAX_NUMBER = 4096; // 12-bit - const int RES = 18; - const int CB = 19; - void reset() { - digitalWrite(CB, HIGH); - digitalWrite(RES, HIGH); - delay(1); - digitalWrite(RES, LOW); - currentValue = 0; - } - /** - * @brief Increment the counter value - * @returns true if overflown to zero - */ - bool increment() { - digitalWrite(CB, LOW); - delay(1); - digitalWrite(CB, HIGH); - currentValue++; - if (currentValue >= MAX_NUMBER) { - currentValue = 0; - return true; - } - return false; - } - unsigned get() { return currentValue; } - private: - unsigned currentValue = 0; -}; - -class AddressState { - public: - AddressState(Counter counter_, int addressPinCount_, const int* addressPins_) - : counter(counter_), addressPinCount(addressPinCount_), addressPins(addressPins_) { - counter.reset(); - } - void set(unsigned targetAddress) { - unsigned targetCounterValue = targetAddress % counter.MAX_NUMBER; - if (counter.get() > targetCounterValue) { - counter.reset(); - - } - for (unsigned i = 0; i < (targetCounterValue - counter.get()); i++) { - counter.increment(); - } - - unsigned pinValues = targetAddress / counter.MAX_NUMBER; - addressPinStateMask = 0; - for (unsigned i = 0; i < addressPinCount; i++) { - unsigned bitSet = pinValues & (1 << i); - if (bitSet > 0) { - digitalWrite(addressPins[i], HIGH); - addressPinStateMask |= (1 << (addressPins[i] - 1)); - } - else { - digitalWrite(addressPins[i], LOW); - - } - } - address = targetAddress; - } - - - void increment() { - if (counter.increment()) { // if overflow - // add 1 to the other pins - for (unsigned i = 0; i < addressPinCount; i++) { - if ((addressPinStateMask & (addressPins[i] - 1)) == 0) { - addressPinStateMask |= (1 << (addressPins[i] - 1)); - digitalWrite(addressPins[i], HIGH); - break; - } - else { - addressPinStateMask ^= (1 << (addressPins[i] - 1)); - digitalWrite(addressPins[i], LOW); - } - } - } - address++; - } - - - unsigned getAddress() { return address; } - unsigned reset() { - counter.reset(); - for (unsigned i = 0; i < addressPinCount; i++) { - digitalWrite(addressPins[i], LOW); - } - } - private: - // if counter is 12 bit and address is 16 bit, this is the value of the top 4 bits - // i-th bit represents i-th pin - unsigned addressPinStateMask = 0; - unsigned address = 0; - Counter counter; - const int* addressPins; - int addressPinCount; -}; diff --git a/teng/control_bytes.hpp b/teng/control_bytes.hpp deleted file mode 100644 index 3f24b85..0000000 --- a/teng/control_bytes.hpp +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - - -const char CTRL_WRITE = 1; -const char CTRL_READ = 2; -const char CTRL_256KB = 11; -const char CTRL_2M = 14; diff --git a/teng/eeprom.hpp b/teng/eeprom.hpp deleted file mode 100644 index 8be1355..0000000 --- a/teng/eeprom.hpp +++ /dev/null @@ -1,70 +0,0 @@ -#pragma once - -#include - -#include "address.hpp" - -class EEPROM { - public: - void setup() { - for (unsigned i = 0; i < addressPinCount; i++) { - pinMode(addressPins[i], OUTPUT); - } - for (unsigned i = 0; i < 8; i++) { - pinMode(dataPins[i], INPUT); - } - pinMode(OEb, OUTPUT); - pinMode(WEb, OUTPUT); - } - - /** - * @brief Read the data pins. - */ - uint8_t readDataPins() { - uint8_t b = 0; - for (unsigned i = 0; i < 8; i++) { - b |= (digitalRead(dataPins[i]) << i); - } - return b; - } - - // set start address in via AddressState - void read(uint8_t* data, unsigned dataSize, AddressState& address) { - unsigned i = 0; - for (unsigned i = 0; i < dataSize; i++) { - digitalWrite(OEb, LOW); - delay(t_OUTPUT_DELAY); - data[i] = readDataPins(); - digitalWrite(OEb, HIGH); - delay(t_OUTPUT_FLOAT); - address.increment(); - } - } - - /* private: */ - int OEb; - int WEb; - int addressPins[6]; - unsigned addressPinCount; - int dataPins[8] = { 2, 3, 4, 5, 6, 7, 8, 9 }; - - // in ms - unsigned t_OUTPUT_DELAY = 1; - unsigned t_MIN_WRITE_PULSE_WIDTH = 1; - unsigned t_OUTPUT_FLOAT = 1; - unsigned t_DATA_HOLD_TIME = 0; -}; - -constexpr EEPROM AT28C256 { - .OEb = 17, - .WEb = 16, - .addressPins = {10, 15, 11}, - .addressPinCount = 3 -}; - -constexpr EEPROM SST39SF02A { - .OEb = 17, - .WEb = 16, - .addressPins = {10, 15, 16, 11, 12, 14}, - .addressPinCount = 6 -}; diff --git a/teng/packet.hpp b/teng/packet.hpp deleted file mode 100644 index 517c4ae..0000000 --- a/teng/packet.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once -#include -#include - -enum PacketType : uint8_t { - MESSAGE, STATUS, COMMAND -}; - -struct Packet { - public: - using size_type = uint16_t; - Packet(PacketType type, size_type size) - : type(type), size(size) { - payload = new uint8_t[size]; - } - ~Packet() { - delete[] payload; - } - uint8_t type; - size_type size; - uint8_t* payload; - -}; diff --git a/teng/services.hpp b/teng/services.hpp new file mode 100644 index 0000000..4fa3333 --- /dev/null +++ b/teng/services.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include + +const char* BASE_UUID = "00000000-9a74-4b30-9361-4a16ec09930f"; + +// Service 1: TENG +const char* TENG_SUUID = "00010000-9a74-4b30-9361-4a16ec09930f"; // Service UUID +const char* TENG_STATUS_CUUID = "00010001-9a74-4b30-9361-4a16ec09930f"; // Characteristic UUID +const char* TENG_COMMAND_CUUID = "00010002-9a74-4b30-9361-4a16ec09930f"; // Characteristic UUID +const char* TENG_READING_CUUID = "00010003-9a74-4b30-9361-4a16ec09930f"; // Characteristic UUID +BLEService tengService(TENG_SUUID); +BLEByteCharacteristic tengStatus(TENG_STATUS_CUUID, BLERead | BLENotify); +BLEByteCharacteristic tengCommand(TENG_COMMAND_CUUID, BLEWrite); +BLEUnsignedShortCharacteristic tengReading(TENG_READING_CUUID, BLERead); + +enum Command : byte { NOOP = 0, MEASURE_BASELINE } diff --git a/teng/settings.hpp b/teng/settings.hpp new file mode 100644 index 0000000..0d05d04 --- /dev/null +++ b/teng/settings.hpp @@ -0,0 +1,6 @@ +#pragma once + +constexpr int LED_RED = 2; +constexpr int LED_YELLOW = 3; +constexpr int LED_GREEN = 4; +constexpr int PIN_TENG = 0; diff --git a/teng/status.hpp b/teng/status.hpp new file mode 100644 index 0000000..527ec5c --- /dev/null +++ b/teng/status.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include +#include "settings.hpp" +#include "services.hpp" + +// needs to be in separate file because sketch preprocessor reorders stuff +enum DeviceStatus : uint8_t { ERROR = 0, BUSY, WAIT_CONNECT, MEASURING_BASELINE, READING }; + +void setStatusLED(DeviceStatus s, bool value) { + switch (s) { + case ERROR: + digitalWrite(LED_RED, value); + break; + case BUSY: + digitalWrite(LED_YELLOW, value); + break; + case WAIT_CONNECT: + digitalWrite(LED_YELLOW, value); + digitalWrite(LED_GREEN, value); + break; + case MEASURING_BASELINE: + digitalWrite(LED_YELLOW, value); + digitalWrite(LED_RED, value); + break; + case READING: + digitalWrite(LED_GREEN, value); + break; + } +} +DeviceStatus deviceStatus = WAIT_CONNECT; +void setStatus(DeviceStatus s) { + setStatusLED(deviceStatus, LOW); + setStatusLED(s, HIGH); + deviceStatus = s; + tengStatus.writeValue(deviceStatus); +} diff --git a/teng/teng.ino b/teng/teng.ino index 6dcccc7..393dcdc 100644 --- a/teng/teng.ino +++ b/teng/teng.ino @@ -1,31 +1,14 @@ /* - * EEPROM PROGRAMMER - * 15-18 Address Pins - * 8 Data Pins - * 2 Control Pins (OEb, WEb) * - * CEb must tied to ground */ #include #include -/* #include "eeprom.hpp" */ -/* #include "address.hpp" */ -/* #include "control_bytes.hpp" */ +#include "settings.hpp" +#include "status.hpp" +#include "services.hpp" -constexpr int LED_RED = 2; -constexpr int LED_YELLOW = 3; -constexpr int LED_GREEN = 4; -constexpr int PIN_TENG = 0; - -/* void maskedWrite(uint32_t mask, uint32_t bits) { */ -/* for (uint32_t i = 0; i < 32; i++) { */ -/* if (mask & (1 << i)) { */ -/* digitalWrite(i, bits & (1 << i)); */ -/* } */ -/* } */ -/* } */ void blinkLED(unsigned n=5, unsigned delay_=200) { for (unsigned i = 0; i < n; i++) { digitalWrite(LED_BUILTIN, HIGH); @@ -36,6 +19,7 @@ void blinkLED(unsigned n=5, unsigned delay_=200) { } + unsigned MAX_DEVIATION = 0; unsigned BASELINE = 0; void measureBaseline(unsigned nMeas, unsigned interval=50) { @@ -58,49 +42,38 @@ void measureBaseline(unsigned nMeas, unsigned interval=50) { } } -void setup() { - /* pinMode(LED_BUILTIN, OUTPUT); */ - /* digitalWrite(LED_BUILTIN, HIGH); */ - /* delay(200); */ +void setup() { + setStatus(DeviceStatus::BUSY); Serial.begin(9600); /* // wait until available */ - while (!Serial); - digitalWrite(LED_BUILTIN, LOW); - delay(200); // empty buffer - while (Serial.read() != -1); + /* while (!Serial); */ - /* digitalWrite(LED_BUILTIN, HIGH); */ - /* delay(5000); */ + blinkLED(2); - /* // reset counter */ - /* blinkLED(); */ - - /* uint8_t payload[] = { 1, 2, 3, 4, 5, 69 }; */ - /* uint8_t type = '#'; */ - /* static_assert(sizeof(payload) == 6); */ - /* uint16_t size = sizeof(payload); */ - /* Serial.write(type); */ - /* Serial.write(lowByte(size)); */ - /* Serial.write(highByte(size));u */ - /* Serial.write(payload, size); */ - - /* delay(5000); */ - blinkLED(4); if (!BLE.begin()) { Serial.println("starting Bluetooth® Low Energy module failed!"); + setStatus(DeviceStatus::ERROR); + while(true); } - BLE.setDeviceName("ArduinoTeng"); + /* BLE.setDeviceName("ArduinoTENG"); */ + BLE.setLocalName("ArduinoTENG"); + + byte data[10] = "\xFF\xFFMQU@TUM"; // 0xFFFF manufacturer id for testing + BLE.setManufacturerData(data, 10); + + tengService.addCharacteristic(tengStatus); + tengService.addCharacteristic(tengCommand); + tengService.addCharacteristic(tengReading); + + BLE.addService(tengService); + BLE.setAdvertisedService(tengService); + + BLE.setConnectable(true); + blinkLED(3); BLE.advertise(); - measureBaseline(100); - digitalWrite(LED_RED, HIGH); - digitalWrite(LED_YELLOW, HIGH); - digitalWrite(LED_GREEN, HIGH); - delay(500); - digitalWrite(LED_RED, LOW); - digitalWrite(LED_YELLOW, LOW); - digitalWrite(LED_GREEN, LOW); + setStatus(DeviceStatus::WAIT_CONNECT); } @@ -109,6 +82,53 @@ void setup() { // the loop function runs over and over again forever void loop() { + blinkLED(3, 100); + // listen for Bluetooth® Low Energy peripherals to connect: + BLEDevice central = BLE.central(); + + // if a central is connected to peripheral: + if (central) { + setStatus(DeviceStatus::READING); + Serial.print("Connected to central: "); + Serial.println(central.address()); + + while (central.connected()) { + if (tengCommand.written()) { + switch (tengCommand.value()) { + case Command::NOOP: + setStatus(DeviceStatus::BUSY); + delay(1000); + break; + case Command::MEASURE_BASELINE: + setStatus(DeviceStatus::MEASURING_BASELINE); + measureBaseline(100); + break; + default: + setStatus(DeviceStatus::ERROR); + delay(1000); + break; + } + setStatus(DeviceStatus::READING); + } + int val = analogRead(PIN_TENG); + tengReading.writeValue(static_cast(val)); + Serial.print(val, DEC); + val -= BASELINE; + if (val < 0) { val = -val; } + Serial.print("/"); + Serial.println(val, DEC); + delay(300); + } + setStatus(DeviceStatus::WAIT_CONNECT); + // when the central disconnects, notify the user + Serial.print("Disconnected from central MAC: "); + Serial.println(central.address()); + } + else { + BLE.advertise(); + } + return; + int led_red = LOW; int led_yellow = LOW; int led_green = LOW; @@ -145,7 +165,7 @@ void loop() { /* if (mem_size = CTRL_2M) { */ /* eeprom = SST39SF02A; */ /* } */ - /* AddressState address(Counter(), eeprom.addressPinCount, eeprom.addressPins); */ + /* AddressStatus address(Counter(), eeprom.addressPinCount, eeprom.addressPins); */ /* const int dataSize = 0x8000; */ /* uint8_t data[dataSize]; */