diff --git a/README.md b/README.md index bf79717..58d8ab8 100644 --- a/README.md +++ b/README.md @@ -10,10 +10,14 @@ The purpose of this library is to use the phyphox app (see www.phyphox.org) to p - Arduino Uno R4 Wifi (see note below) - senseBox MCU with NINA-B31 module - ESP 32 +- STM32 (e.g. STM32WB55) Note: The Arduino Nano 33 IoT and the Arduino uno R4 are somewhat unusual. You will need to install the ArduinoBLE library to use it and you will need to call "PhyphoxBLE::poll()" periodically for it to work. Note: When using the NINA-B31 module you must call PhyphoxBLE::poll() periodically (in loop() ) or the library will not work. + The same applies to STM32 + +Note: to use STM32 BLE, you need the STM32duinoBLE library, and (at least for the STM32WBx5) the appropriate BLE stack (see Copro binaries) ## Concept of phyphox @@ -29,6 +33,7 @@ Alternatively, you can download this repository here as a zip file from github a You will may also need to install an BLE library specific to your board: - ArduinoBLE for the Arduino Nano 33 IoT +- STM32duinoBLE for an STM32 ## Usage diff --git a/src/experiment.cpp b/src/experiment.cpp index 90ca7e1..3e2885a 100644 --- a/src/experiment.cpp +++ b/src/experiment.cpp @@ -154,7 +154,7 @@ void PhyphoxBleExperiment::getFirstBytes(char *buffArray, const char *DEVICENAME strcat(buffArray, DEVICENAME); if(MTU!=20){ - char add[0]; + char add[10]; sprintf(add, "\" mtu=\"%i", MTU); strcat(buffArray, add); } diff --git a/src/phyphoxBLE_NRF52.h b/src/phyphoxBLE_NRF52.h index 4167272..e6c8167 100644 --- a/src/phyphoxBLE_NRF52.h +++ b/src/phyphoxBLE_NRF52.h @@ -1,6 +1,8 @@ #ifndef PHYPHOXBLE_NRF52_H #define PHYPHOXBLE_NRF52_H -#define NDEBUG +#if !defined(NDEBUG) && defined(ARDUINO_ARCH_MBED) + #define NDEBUG +#endif #include #include diff --git a/src/phyphoxBLE_STM32.cpp b/src/phyphoxBLE_STM32.cpp new file mode 100644 index 0000000..fb8c955 --- /dev/null +++ b/src/phyphoxBLE_STM32.cpp @@ -0,0 +1,389 @@ +#if defined(ARDUINO_ARCH_STM32) + +#include "phyphoxBLE_STM32.h" +#include "Arduino.h" +#include + +#if defined(ARDUINO_STEVAL_MKBOXPRO) + /* STEVAL-MKBOXPRO */ + SPIClass SpiHCI(PA7, PA6, PA5); + HCISpiTransportClass HCISpiTransport(SpiHCI, BLUENRG_LP, PA2, PB11, PD4, 1000000, SPI_MODE3); + #if !defined(FAKE_BLELOCALDEVICE) + BLELocalDevice BLEObj(&HCISpiTransport); + BLELocalDevice& BLE = BLEObj; + #endif +#elif defined(ARDUINO_STEVAL_MKSBOX1V1) + /* STEVAL-MKSBOX1V1 */ + SPIClass SpiHCI(PC3, PD3, PD1); + HCISpiTransportClass HCISpiTransport(SpiHCI, SPBTLE_1S, PD0, PD4, PA8, 1000000, SPI_MODE1); + #if !defined(FAKE_BLELOCALDEVICE) + BLELocalDevice BLEObj(&HCISpiTransport); + BLELocalDevice& BLE = BLEObj; + #endif +#elif defined(ARDUINO_B_L475E_IOT01A) || defined(ARDUINO_B_L4S5I_IOT01A) + /* B-L475E-IOT01A1 or B_L4S5I_IOT01A */ + SPIClass SpiHCI(PC12, PC11, PC10); + HCISpiTransportClass HCISpiTransport(SpiHCI, SPBTLE_RF, PD13, PE6, PA8, 8000000, SPI_MODE0); + #if !defined(FAKE_BLELOCALDEVICE) + BLELocalDevice BLEObj(&HCISpiTransport); + BLELocalDevice& BLE = BLEObj; + #endif +#elif defined(ARDUINO_NUCLEO_WB15CC) || defined(ARDUINO_P_NUCLEO_WB55RG) ||\ + defined(ARDUINO_STM32WB5MM_DK) || defined(ARDUINO_P_NUCLEO_WB55_USB_DONGLE) + HCISharedMemTransportClass HCISharedMemTransport; + #if !defined(FAKE_BLELOCALDEVICE) + BLELocalDevice BLEObj(&HCISharedMemTransport); + BLELocalDevice& BLE = BLEObj; + #endif +#else + /* Shield IDB05A2 with SPI clock on D3 */ + SPIClass SpiHCI(D11, D12, D3); + HCISpiTransportClass HCISpiTransport(SpiHCI, BLUENRG_M0, A1, A0, D7, 8000000, SPI_MODE0); + #if !defined(FAKE_BLELOCALDEVICE) + BLELocalDevice BLEObj(&HCISpiTransport); + BLELocalDevice& BLE = BLEObj; + #endif + /* Shield IDB05A2 with SPI clock on D13 */ + // #define SpiHCI SPI + // HCISpiTransportClass HCISpiTransport(SpiHCI, BLUENRG_M0, A1, A0, D7, 8000000, SPI_MODE0); + // #if !defined(FAKE_BLELOCALDEVICE) + // BLELocalDevice BLEObj(&HCISpiTransport); + // BLELocalDevice& BLE = BLEObj; + // #endif + /* Shield IDB05A1 with SPI clock on D3 */ + // SPIClass SpiHCI(D11, D12, D3); + // HCISpiTransportClass HCISpiTransport(SpiHCI, SPBTLE_RF, A1, A0, D7, 8000000, SPI_MODE0); + // #if !defined(FAKE_BLELOCALDEVICE) + // BLELocalDevice BLEObj(&HCISpiTransport); + // BLELocalDevice& BLE = BLEObj; + // #endif + /* Shield IDB05A1 with SPI clock on D13 */ + // #define SpiHCI SPI + // HCISpiTransportClass HCISpiTransport(SpiHCI, SPBTLE_RF, A1, A0, D7, 8000000, SPI_MODE0); + // #if !defined(FAKE_BLELOCALDEVICE) + // BLELocalDevice BLEObj(&HCISpiTransport); + // BLELocalDevice& BLE = BLEObj; + // #endif + /* Shield BNRG2A1 with SPI clock on D3 */ + // SPIClass SpiHCI(D11, D12, D3); + // HCISpiTransportClass HCISpiTransport(SpiHCI, BLUENRG_M2SP, A1, A0, D7, 1000000, SPI_MODE1); + // #if !defined(FAKE_BLELOCALDEVICE) + // BLELocalDevice BLEObj(&HCISpiTransport); + // BLELocalDevice& BLE = BLEObj; + // #endif + /* Shield BNRG2A1 with SPI clock on D13 */ + // #define SpiHCI SPI + // HCISpiTransportClass HCISpiTransport(SpiHCI, BLUENRG_M2SP, A1, A0, D7, 1000000, SPI_MODE1); + // #if !defined(FAKE_BLELOCALDEVICE) + // BLELocalDevice BLEObj(&HCISpiTransport); + // BLELocalDevice& BLE = BLEObj; + // #endif +#endif + +BLEService PhyphoxBLE::phyphoxExperimentService{phyphoxBleExperimentServiceUUID}; // create service +BLECharacteristic PhyphoxBLE::experimentCharacteristic{phyphoxBleExperimentCharacteristicUUID, BLERead | BLEWrite| BLENotify, 20, false}; +BLECharacteristic PhyphoxBLE::controlCharacteristic{phyphoxBleExperimentControlCharacteristicUUID, BLERead | BLEWrite| BLENotify, 20, false}; +BLECharacteristic PhyphoxBLE::eventCharacteristic{phyphoxBleEventCharacteristicUUID, BLERead | BLEWrite| BLENotify, 20, false}; + +BLEService PhyphoxBLE::phyphoxDataService{phyphoxBleDataServiceUUID}; // create service +BLECharacteristic PhyphoxBLE::dataCharacteristic{phyphoxBleDataCharacteristicUUID, BLERead | BLEWrite | BLENotify, 20, false}; +BLECharacteristic PhyphoxBLE::configCharacteristic{phyphoxBleConfigCharacteristicUUID, BLERead | BLEWrite| BLENotify, 20, false}; + +uint16_t PhyphoxBLE::minConInterval = 6; //7.5ms +uint16_t PhyphoxBLE::maxConInterval = 24; //30ms +uint16_t PhyphoxBLE::slaveLatency = 0; +uint16_t PhyphoxBLE::timeout = 50; + +uint16_t PhyphoxBLE::MTU = 20; +uint16_t PhyphoxBleExperiment::MTU = 20; + +int64_t PhyphoxBLE::experimentTime = 0; +int64_t PhyphoxBLE::systemTime = 0; +uint8_t PhyphoxBLE::eventType = 0; + +uint8_t* PhyphoxBLE::data = nullptr; //this pointer points to the data the user wants to write in the characteristic +uint8_t* PhyphoxBLE::p_exp = nullptr; //this pointer will point to the byte array which holds an experiment + +size_t PhyphoxBLE::expLen = 0; //try o avoid this maybe use std::array or std::vector +const int maxExperimentSize = 6000; +uint8_t storage[maxExperimentSize]; +uint8_t PhyphoxBLE::eventData[17]={0}; +//uint8_t eventData[17]; +char *PhyphoxBLE::EXPARRAY=(char*)storage; + +void(*PhyphoxBLE::configHandler)() = nullptr; +void(*PhyphoxBLE::experimentEventHandler)() = nullptr; + +void PhyphoxBLE::start(const char* DEVICE_NAME, uint8_t* exp_pointer, size_t len){ + p_exp = exp_pointer; + expLen = len; + start(DEVICE_NAME); +} + +void PhyphoxBLE::start(uint8_t* exp_pointer, size_t len){ + p_exp = exp_pointer; + expLen = len; + start(); +} + +void PhyphoxBLE::start(const char* DEVICE_NAME) +{ + deviceName = DEVICE_NAME; + + controlCharacteristic.setEventHandler(BLEWritten, controlCharacteristicWritten); + eventCharacteristic.setEventHandler(BLEWritten, eventCharacteristicWritten); + configCharacteristic.setEventHandler(BLEWritten, configCharacteristicWritten); + + if(p_exp == nullptr){ + + PhyphoxBleExperiment defaultExperiment; + + //View + PhyphoxBleExperiment::View firstView; + + //Graph + PhyphoxBleExperiment::Graph firstGraph; //Create graph which will plot random numbers over time + firstGraph.setChannel(0,1); + + firstView.addElement(firstGraph); + defaultExperiment.addView(firstView); + + addExperiment(defaultExperiment); + } + + + if(!BLE.begin()) { Serial.println("failed to BLE.begin()!"); } + BLE.setLocalName(DEVICE_NAME); + BLE.setAdvertisedService(phyphoxExperimentService); + //BLE.setAdvertisedService(phyphoxDataService); + + // add the characteristics to the service + phyphoxExperimentService.addCharacteristic(experimentCharacteristic); + phyphoxExperimentService.addCharacteristic(controlCharacteristic); + phyphoxExperimentService.addCharacteristic(eventCharacteristic); + phyphoxDataService.addCharacteristic(configCharacteristic); + phyphoxDataService.addCharacteristic(dataCharacteristic); + + // add the service + BLE.addService(phyphoxExperimentService); + BLE.addService(phyphoxDataService); + + // set connection parameter + BLE.setConnectionInterval(minConInterval, maxConInterval); + + // start advertising + BLE.advertise(); + +} + +void PhyphoxBLE::start() { + PhyphoxBLE::start("phyphox-Arduino"); +} + +void PhyphoxBLE::poll() +{ + BLE.poll(); +} + +void PhyphoxBLE::poll(int timeout) +{ + BLE.poll(timeout); +} + +void PhyphoxBLE::read(uint8_t *arrayPointer, unsigned int arraySize) +{ + configCharacteristic.readValue(arrayPointer, arraySize); +} + +void PhyphoxBLE::read(float& f) +{ + uint8_t readDATA[4]; + configCharacteristic.readValue(readDATA, 4); + memcpy(&f,&readDATA[0],4); +} + +void PhyphoxBLE::read(float& f1, float& f2) +{ + uint8_t readDATA[8]; + configCharacteristic.readValue(readDATA, 8); + memcpy(&f1,readDATA,4); + memcpy(&f2,readDATA+4,4); +} +void PhyphoxBLE::read(float& f1, float& f2, float& f3) +{ + uint8_t readDATA[12]; + configCharacteristic.readValue(readDATA, 12); + memcpy(&f1,readDATA,4); + memcpy(&f2,readDATA+4,4); + memcpy(&f3,readDATA+8,4); +} +void PhyphoxBLE::read(float& f1, float& f2, float& f3, float& f4) +{ + uint8_t readDATA[16]; + configCharacteristic.readValue(readDATA, 16); + memcpy(&f1,readDATA,4); + memcpy(&f2,readDATA+4,4); + memcpy(&f3,readDATA+8,4); + memcpy(&f4,readDATA+12,4); +} +void PhyphoxBLE::read(float& f1, float& f2, float& f3, float& f4, float& f5) +{ + uint8_t readDATA[20]; + configCharacteristic.readValue(readDATA, 20); + memcpy(&f1,readDATA,4); + memcpy(&f2,readDATA+4,4); + memcpy(&f3,readDATA+8,4); + memcpy(&f4,readDATA+12,4); + memcpy(&f5,readDATA+16,4); +} + +void PhyphoxBLE::addExperiment(PhyphoxBleExperiment& exp) +{ + memset(EXPARRAY,0,maxExperimentSize); + + exp.getFirstBytes(EXPARRAY, deviceName); + + + for(uint8_t i=0;i(&value); + dataCharacteristic.writeValue(data,4); +} + + +void PhyphoxBLE::write(float& f1, float& f2) +{ + float array[2] = {f1, f2}; + data = reinterpret_cast(array); + dataCharacteristic.writeValue(data,8); +} + +void PhyphoxBLE::write(float& f1, float& f2, float& f3) +{ + float array[3] = {f1, f2, f3}; + data = reinterpret_cast(array); + dataCharacteristic.writeValue(data,12); +} + +void PhyphoxBLE::write(float& f1, float& f2, float& f3 , float& f4) +{ + float array[4] = {f1, f2, f3, f4}; + data = reinterpret_cast(array); + dataCharacteristic.writeValue(data,16); +} + +void PhyphoxBLE::write(float& f1, float& f2, float& f3 , float& f4, float& f5) +{ + float array[5] = {f1, f2, f3, f4, f5}; + data = reinterpret_cast(array); + dataCharacteristic.writeValue(data,20); +} + +void PhyphoxBLE::controlCharacteristicWritten(BLEDevice central, BLECharacteristic characteristic) { + byte value = 0; + characteristic.readValue(value); + if (value & 0x01) { + //sendexperiment + transferExperiment(); + } else { + //experiment transfered + } + +} + +void PhyphoxBLE::transferExperiment(){ + + BLE.stopAdvertise(); + + uint8_t* exp = p_exp; + size_t exp_len = expLen; + + uint8_t header[20] = {0}; //20 byte as standard package size for ble transfer + const char phyphox[] = "phyphox"; + uint32_t table[256]; + phyphoxBleCrc32::generate_table(table); + uint32_t checksum = phyphoxBleCrc32::update(table, 0, exp, exp_len); + size_t arrayLength = exp_len; + uint8_t experimentSizeArray[4] = {0}; + experimentSizeArray[0]= (arrayLength >> 24); + experimentSizeArray[1]= (arrayLength >> 16); + experimentSizeArray[2]= (arrayLength >> 8); + experimentSizeArray[3]= arrayLength; + + uint8_t checksumArray[4] = {0}; + checksumArray[0]= (checksum >> 24) & 0xFF; + checksumArray[1]= (checksum >> 16) & 0xFF; + checksumArray[2]= (checksum >> 8) & 0xFF; + checksumArray[3]= checksum & 0xFF; + + memcpy(&header[0],&phyphox[0],7); + memcpy(&header[0]+7,&experimentSizeArray[0],4); + memcpy(&header[0]+7+4,&checksumArray[0],4); + experimentCharacteristic.writeValue(header,sizeof(header)); + + for(size_t i = 0; i < exp_len/20; ++i){ + memcpy(&header[0],&exp[0]+i*20,20); + experimentCharacteristic.writeValue(header,sizeof(header)); + delay(5); + } + +if(exp_len%20 != 0){ + const size_t rest = exp_len%20; + uint8_t slice[rest]; + memcpy(&slice[0],&exp[0]+exp_len-rest,rest); + experimentCharacteristic.writeValue(slice,sizeof(slice)); + + delay(5); +} + + BLE.advertise(); +} + +void PhyphoxBLE::configCharacteristicWritten(BLEDevice central, BLECharacteristic characteristic){ + if(configHandler!=nullptr){ + (*configHandler)(); + } +} + +void PhyphoxBLE::eventCharacteristicWritten(BLEDevice central, BLECharacteristic characteristic){ + + uint8_t read_buffer[17]; + eventCharacteristic.readValue(read_buffer, 17); + + + memcpy(&eventData[0],read_buffer,17); + int64_t et,st; + memcpy(&et,&eventData[0]+1,8); + memcpy(&st,&eventData[0]+1+8,8); + PhyphoxBLE::eventType = eventData[0]; + PhyphoxBLE::systemTime = swap_int64(st); + PhyphoxBLE::experimentTime = swap_int64(et); + + if(experimentEventHandler!=nullptr){ + (*experimentEventHandler)(); + } +} + +void PhyphoxBLE::printXML(HardwareSerial* printer){ + printer->println(""); + for(int i =0; iprint(CHAR); + } + printer->println(""); +} +#endif diff --git a/src/phyphoxBLE_STM32.h b/src/phyphoxBLE_STM32.h new file mode 100644 index 0000000..94a95e9 --- /dev/null +++ b/src/phyphoxBLE_STM32.h @@ -0,0 +1,84 @@ +#ifndef PHYPHOXBLE_STM32_H +#define PHYPHOXBLE_STM32_H +#if !defined(NDEBUG) && defined(ARDUINO_ARCH_STM32) + #define NDEBUG +#endif + +#include + +#include +#include "phyphoxBleExperiment.h" + +class PhyphoxBLE +{ + private: + + static uint8_t data_package[20]; + + static void controlCharacteristicWritten(BLEDevice, BLECharacteristic); + static void eventCharacteristicWritten(BLEDevice, BLECharacteristic); + static void configCharacteristicWritten(BLEDevice, BLECharacteristic); + + static BLEService phyphoxExperimentService; + static BLECharacteristic experimentCharacteristic; + static BLECharacteristic controlCharacteristic; + static BLECharacteristic eventCharacteristic; + + static BLEService phyphoxDataService; + static BLECharacteristic dataCharacteristic; + static BLECharacteristic configCharacteristic; + + + static uint8_t* data; //this pointer points to the data the user wants to write in the characteristic + static uint8_t* p_exp; //this pointer will point to the byte array which holds an experiment + + static size_t expLen; //try o avoid this maybe use std::array or std::vector + static char *EXPARRAY; + + public: + + static void start(const char* DEVICE_NAME, uint8_t* p, size_t n = 0); + static void start(const char* DEVICE_NAME); + static void start(uint8_t* p, size_t n = 0); + static void start(); + + static void addExperiment(PhyphoxBleExperiment&); + static void transferExperiment(); + static void write(float&); + static void write(float&, float&); + static void write(float&, float&, float&); + static void write(float&, float&, float&, float&); + static void write(float&, float&, float&, float&, float&); + + static void read(uint8_t*, unsigned int); + static void read(float&); + static void read(float&, float&); + static void read(float&, float&, float&); + static void read(float&, float&, float&, float&); + static void read(float&, float&, float&, float&, float&); + + + static void poll(); + static void poll(int timeout); + + static void(*configHandler)(); + static void(*experimentEventHandler)(); + + static uint16_t minConInterval; + static uint16_t maxConInterval; + static uint16_t slaveLatency; + static uint16_t timeout; + static uint16_t MTU; + + static int64_t experimentTime; + static int64_t systemTime; + static uint8_t eventType; + + static uint8_t eventData[17]; + + static void printXML(HardwareSerial*); + +}; + + +#endif diff --git a/src/phyphoxBle.h b/src/phyphoxBle.h index 3578aba..909287a 100644 --- a/src/phyphoxBle.h +++ b/src/phyphoxBle.h @@ -56,6 +56,8 @@ static const char *deviceName = "phyphox-Arduino"; #elif defined(ARDUINO_SAMD_NANO_33_IOT) || defined(ARDUINO_UNOR4_WIFI) #include #include "phyphoxBLE_NanoIOT.h" +#elif defined(ARDUINO_ARCH_STM32) + #include "phyphoxBLE_STM32.h" #else #error "Unsupported board selected!" #endif