├── .gitignore
├── src
├── copyToMem.h
├── copyToMem.cpp
├── error.cpp
├── element.cpp
├── defines.h
├── exportdata.cpp
├── boards
│ ├── NINAB31serial.h
│ ├── phyphoxBLE_NINAB31.h
│ ├── phyphoxBLE_NanoIOT.h
│ ├── phyphoxBLE_STM32.h
│ ├── phyphoxBLE_ESP32.h
│ ├── phyphoxBLE_NRF52.h
│ ├── NINAB31serial.cpp
│ ├── phyphoxBLE_NINAB31.cpp
│ ├── phyphoxBLE_NanoIOT.cpp
│ ├── phyphoxBLE_STM32.cpp
│ ├── phyphoxBLE_NRF52.cpp
│ └── phyphoxBLE_ESP32.cpp
├── exportSet.cpp
├── view.cpp
├── infoField.cpp
├── separator.cpp
├── edit.cpp
├── value.cpp
├── subgraph.cpp
├── sensor.cpp
├── errorhandler.cpp
├── phyphoxBle.h
├── graph.cpp
├── phyphoxBleExperiment.h
└── experiment.cpp
├── examples
├── randomNumbers
│ └── randomNumbers.ino
├── getSystemAndEventTime
│ └── getSystemAndEventTime.ino
├── connectionParameter
│ └── connectionParameter.ino
├── readoutADC
│ └── readoutADC.ino
├── getDataFromSmartphone
│ └── getDataFromSmartphone.ino
├── getSensorDataFromSmartphone
│ └── getSensorDataFromSmartphone.ino
├── rangefinder
│ └── rangefinder.ino
├── multigraph
│ └── multigraph.ino
├── CreateExperiment
│ └── CreateExperiment.ino
└── CO2kit
│ └── CO2kit.ino
├── library.properties
├── COPYING.LESSER
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .vscode/*
--------------------------------------------------------------------------------
/src/copyToMem.h:
--------------------------------------------------------------------------------
1 | #include "phyphoxBleExperiment.h"
2 |
3 | void copyToMem(char **target, const char *data);
--------------------------------------------------------------------------------
/src/copyToMem.cpp:
--------------------------------------------------------------------------------
1 | #include "copyToMem.h"
2 |
3 | void copyToMem(char **target, const char *data) {
4 | // if (*target != NULL) {
5 | // free(*target); // Causes crashes
6 | // }
7 | *target = (char*) malloc(sizeof(char) * (strlen(data)+1));
8 | strcpy(*target, data);
9 | }
--------------------------------------------------------------------------------
/src/error.cpp:
--------------------------------------------------------------------------------
1 | #include "phyphoxBleExperiment.h"
2 | #include "copyToMem.h"
3 |
4 | void PhyphoxBleExperiment::Error::getBytes(char *buffArray) {
5 | strcat(buffArray,"\t\t\n");
8 | strcat(buffArray,"\t\t\n");
9 | }
10 |
--------------------------------------------------------------------------------
/src/element.cpp:
--------------------------------------------------------------------------------
1 | #include "phyphoxBleExperiment.h"
2 | #include "copyToMem.h"
3 |
4 | void PhyphoxBleExperiment::Element::setLabel(const char *l){
5 | ERROR = ERROR.MESSAGE == NULL ? err_checkLength(l, 41, "setLabel") : ERROR;
6 | copyToMem(&LABEL, (std::string(l)).c_str());
7 | }
8 |
9 | // void PhyphoxBleExperiment::Element::setLabel(const char *l){
10 | // copyToMem(&LABEL, (" label=\"" + std::string(l) + "\"").c_str());
11 | // }
12 |
--------------------------------------------------------------------------------
/src/defines.h:
--------------------------------------------------------------------------------
1 | // Experiment constants
2 | #define phyphoxBleNViews 15
3 | #define phyphoxBleNSensors 5
4 | #define phyphoxBleNElements 20
5 | #define phyphoxBleNExportSets 10
6 | #define phyphoxBleNChannel 10
7 |
8 | // Graph style options
9 | #define STYLE_LINES "lines"
10 | #define STYLE_DOTS "dots"
11 | #define STYLE_VBARS "vbars"
12 | #define STYLE_HBARS "hbars"
13 | #define STYLE_MAP "map"
14 |
15 | // Graph layout options
16 | #define LAYOUT_AUTO "auto"
17 | #define LAYOUT_EXTEND "extend"
18 | #define LAYOUT_FIXED "fixed"
--------------------------------------------------------------------------------
/examples/randomNumbers/randomNumbers.ino:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | void setup() {
4 | PhyphoxBLE::start("phyphox device"); //Start the BLE server
5 | }
6 |
7 | void loop() {
8 | float randomNumber = random(0,100); //Generate random number in the range 0 to 100
9 | PhyphoxBLE::write(randomNumber); //Send value to phyphox
10 | delay(50); //Shortly pause before repeating
11 | PhyphoxBLE::poll(); //IMPORTANT: In contrast to other devices, poll() needs to be called periodically on the 33 IoT
12 | }
13 |
--------------------------------------------------------------------------------
/library.properties:
--------------------------------------------------------------------------------
1 | name=phyphox BLE
2 | version=1.2.6
3 | author=RWTH Aachen University
4 | maintainer=Dominik Dorsel
5 | sentence=Use the app phyphox to visualize your sensor data on your phone or tablet!
6 | paragraph=The purpose of this library is to use the open source phyphox app (see https://phyphox.org) to plot sensor data on your phone. phyphox is much more than only 'plotting your data'. You can also perform data analysis with it or access your phones sensors to use in your Arduino project.
7 | category=Other
8 | url=https://phyphox.org/arduino
9 | architectures=mbed,esp32,samd,mbed_nano,renesas_uno
10 | includes=phyphoxBle.h
11 |
--------------------------------------------------------------------------------
/src/exportdata.cpp:
--------------------------------------------------------------------------------
1 | #include "phyphoxBleExperiment.h"
2 | #include "copyToMem.h"
3 |
4 | void PhyphoxBleExperiment::ExportData::setDatachannel(int d){
5 | char tmp[20];
6 | sprintf(tmp, "CH%d", d);
7 | copyToMem(&BUFFER, tmp);
8 | }
9 |
10 | void PhyphoxBleExperiment::ExportData::setXMLAttribute(const char *xml){
11 | copyToMem(&XMLAttribute, (" " + std::string(xml)).c_str());
12 | }
13 |
14 | void PhyphoxBleExperiment::ExportData::setLabel(const char *l)
15 | {
16 | copyToMem(&LABEL, (std::string(l)).c_str());
17 | }
18 |
19 | void PhyphoxBleExperiment::ExportData::getBytes(char *buffArray)
20 | {
21 | strcat(buffArray,"\t\t");
25 | if (!BUFFER) {strcat(buffArray,"CH1");} else {strcat(buffArray,BUFFER);}
26 | strcat(buffArray, "\n");
27 |
28 | }
--------------------------------------------------------------------------------
/src/boards/NINAB31serial.h:
--------------------------------------------------------------------------------
1 | #ifndef NINAB31SERIAL_H
2 | #define NINAB31SERIAL_H
3 |
4 | #include
5 |
6 |
7 | class NINAB31Serial
8 | {
9 |
10 | private:
11 |
12 | static String m_input;
13 | static bool checkUnsolicited();
14 | static bool connected;
15 |
16 | public:
17 | static bool configModule();
18 | static bool begin();
19 | static bool setLocalName(String name);
20 | static bool writeValue(int characteristic, String value);
21 | static bool writeValue(int characteristic, uint8_t* value, int len);
22 | static bool setConnectionInterval(int minInterval, int maxInterval);
23 |
24 | static int parseResponse(String msg, uint32_t timeout);
25 | static bool checkResponse(String msg, uint32_t timeout);
26 | static bool poll();
27 | static String checkCharWritten(int handle);
28 | static void flushInput();
29 | static bool advertise();
30 | static bool stopAdvertise();
31 |
32 | };
33 |
34 | #endif
35 |
--------------------------------------------------------------------------------
/src/exportSet.cpp:
--------------------------------------------------------------------------------
1 | #include "phyphoxBleExperiment.h"
2 | #include "copyToMem.h"
3 |
4 | void PhyphoxBleExperiment::ExportSet::addElement(Element& e)
5 | {
6 | for(int i=0; i\n");
30 |
31 | //loop over elements
32 | for(int i=0; igetBytes(buffArray);
35 | }
36 | }
37 | strcat(buffArray,"\t\n");
38 |
39 |
40 |
41 | }
42 |
43 |
44 |
--------------------------------------------------------------------------------
/examples/getSystemAndEventTime/getSystemAndEventTime.ino:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | void setup() {
4 | Serial.begin(115200);
5 | PhyphoxBLE::start();
6 | PhyphoxBLE::experimentEventHandler = &newExperimentEvent; // declare which function should be called after receiving an experiment event
7 | PhyphoxBLE::printXML(&Serial);
8 | }
9 |
10 | void loop() {
11 | float randomNumber = random(0,100); //Generate random number in the range 0 to 100
12 | PhyphoxBLE::write(randomNumber); //Send value to phyphox
13 | delay(100);
14 | PhyphoxBLE::poll(); //Only required for the Arduino Nano 33 IoT, but it does no harm for other boards.
15 |
16 | }
17 |
18 | //declare function which is called after phyphox wrote to the event characteristic
19 | void newExperimentEvent(){
20 | Serial.println("New experiment event received:");
21 | Serial.print("Event type: ");
22 | Serial.print(PhyphoxBLE::eventType);
23 | Serial.println(" (0 = Paused, 1 = Started, 2 = Clear, 255 = SYNC)");
24 | Serial.print("Experiment time [ms]: ");
25 | Serial.println(PhyphoxBLE::experimentTime);
26 | Serial.print("Unix system time [ms]: ");
27 | Serial.println(PhyphoxBLE::systemTime);
28 | }
29 |
--------------------------------------------------------------------------------
/src/view.cpp:
--------------------------------------------------------------------------------
1 | #include "phyphoxBleExperiment.h"
2 | #include "copyToMem.h"
3 |
4 | void PhyphoxBleExperiment::View::addElement(Element& e)
5 | {
6 | for(int i=0; i\n");
29 | }
30 |
31 | if(ELEMENTS[elem]!=nullptr){
32 | if(ELEMENTS[elem]->ERROR.MESSAGE == NULL) {
33 | ELEMENTS[elem]->getBytes(buffArray);
34 | }
35 | }
36 |
37 | if(elem == phyphoxBleNElements-1) {
38 | strcat(buffArray,"\t\n");
39 | }
40 |
41 |
42 |
43 | }
44 |
45 |
46 |
--------------------------------------------------------------------------------
/src/infoField.cpp:
--------------------------------------------------------------------------------
1 | #include "phyphoxBleExperiment.h"
2 | #include "copyToMem.h"
3 |
4 | void PhyphoxBleExperiment::InfoField::setInfo(const char *i)
5 | {
6 | ERROR = ERROR.MESSAGE == NULL ? err_checkLength(i, 191, "setInfo") : ERROR;
7 | copyToMem(&INFO, (std::string(i)).c_str());
8 | }
9 |
10 | void PhyphoxBleExperiment::InfoField::setColor(const char *c)
11 | {
12 | ERROR = ERROR.MESSAGE == NULL ? err_checkHex(c, "setColor") : ERROR;
13 | copyToMem(&COLOR, (" color=\"" + std::string(c) + "\"").c_str());
14 | }
15 |
16 | void PhyphoxBleExperiment::InfoField::setXMLAttribute(const char *xml){
17 | ERROR = ERROR.MESSAGE == NULL ? err_checkLength(xml, 98, "setXMLAttribute") : ERROR;
18 | copyToMem(&XMLAttribute, (" " + std::string(xml)).c_str());
19 | }
20 |
21 | void PhyphoxBleExperiment::InfoField::getBytes(char *buffArray)
22 | {
23 |
24 | strcat(buffArray,"\t\t\n");
35 | strcat(buffArray,"\t\t\n");
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/separator.cpp:
--------------------------------------------------------------------------------
1 | #include "phyphoxBleExperiment.h"
2 | #include "copyToMem.h"
3 |
4 | void PhyphoxBleExperiment::Separator::setHeight(float h)
5 | {
6 | ERROR = ERROR.MESSAGE == NULL ? err_checkUpper((int) h, 10, "setHeight") : ERROR;
7 | char tmp[20];
8 | sprintf(tmp, " height=\"%.2f\"", h);
9 | copyToMem(&HEIGHT, tmp);
10 | }
11 |
12 | void PhyphoxBleExperiment::Separator::setColor(const char *c)
13 | {
14 | ERROR = ERROR.MESSAGE == NULL ? err_checkHex(c, "setColor") : ERROR;
15 | copyToMem(&COLOR, (std::string(c)).c_str());
16 | }
17 |
18 | void PhyphoxBleExperiment::Separator::setXMLAttribute(const char * xml) {
19 | ERROR = ERROR.MESSAGE == NULL ? err_checkLength(xml, 98, "setXMLAttribute") : ERROR;
20 | copyToMem(&XMLAttribute, (" " + std::string(xml)).c_str());
21 | }
22 |
23 | void PhyphoxBleExperiment::Separator::getBytes(char *buffArray)
24 | {
25 | strcat(buffArray,"\t\t\n");
34 | strcat(buffArray, "\t\t\n");
35 | }
36 |
--------------------------------------------------------------------------------
/examples/connectionParameter/connectionParameter.ino:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | void setup() {
4 | /*
5 | Minimum interval between two connection events allowed for a connection.
6 | It shall be less than or equal to maxConnectionInterval. This value, in units of 1.25ms, is included in the range [0x0006 : 0x0C80].
7 | */
8 | PhyphoxBLE::minConInterval = 6; //6 = 7.5ms
9 |
10 | /*Maximum interval between two connection events allowed for a connection.
11 | It shall be greater than or equal to minConnectionInterval. This value is in unit of 1.25ms and is in the range [0x0006 : 0x0C80].
12 | */
13 | PhyphoxBLE::maxConInterval = 24; //10 = 12.5ms
14 |
15 | /*
16 | Number of connection events the slave can drop if it has nothing to communicate to the master.
17 | This value shall be in the range [0x0000 : 0x01F3].
18 | */
19 | PhyphoxBLE::slaveLatency = 0; //
20 | /*
21 | Link supervision timeout for the connection.
22 | Time after which the connection is considered lost if the device didn't receive a packet from its peer.
23 | This value is in the range [0x000A : 0x0C80] and is in unit of 10 ms.
24 | */
25 | PhyphoxBLE::timeout = 50; //50 = 500ms
26 |
27 |
28 | PhyphoxBLE::start(); //Start the BLE server
29 | }
30 |
31 | void loop() {
32 | float randomNumber = random(0,100); //Generate random number in the range 0 to 100
33 | PhyphoxBLE::write(randomNumber); //Send value to phyphox
34 | delay(20); //Shortly pause before repeating
35 | }
--------------------------------------------------------------------------------
/examples/readoutADC/readoutADC.ino:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | int ADC_GPIO = 25; // ESP32
4 | //int ADC_GPIO = A0; // Arduino Nano 33 BLE
5 |
6 | void setup() {
7 |
8 |
9 | // put your setup code here, to run once:
10 | Serial.begin(115200);
11 | PhyphoxBLE::start("Voltmeter");
12 |
13 | PhyphoxBleExperiment Voltmeter;
14 |
15 | Voltmeter.setTitle("Voltmeter");
16 | Voltmeter.setCategory("Arduino Experiments");
17 | Voltmeter.setDescription("This experiment will plot the measured voltage over time.");
18 |
19 | //View
20 | PhyphoxBleExperiment::View firstView;
21 | firstView.setLabel("Rawdata"); //Create a "view"
22 |
23 | //Graph
24 | PhyphoxBleExperiment::Graph firstGraph; //Create graph which will plot random numbers over time
25 | firstGraph.setLabel("Voltmeter");
26 | firstGraph.setUnitX("s");
27 | firstGraph.setUnitY("V");
28 | firstGraph.setLabelX("time");
29 | firstGraph.setLabelY("Voltage");
30 |
31 | /* Assign Channels, so which data is plotted on x or y axis
32 | first parameter represents x-axis, second y-axis
33 | Channel 0 means a timestamp is created after the BLE package arrives in phyphox
34 | Channel 1 to N corresponding to the N-parameter which is written in server.write()
35 | */
36 |
37 | firstGraph.setChannel(0, 1);
38 |
39 | firstView.addElement(firstGraph); //attach graph to view
40 | Voltmeter.addView(firstView); //Attach view to experiment
41 | PhyphoxBLE::addExperiment(Voltmeter); //Attach experiment to server
42 |
43 |
44 |
45 | }
46 |
47 | void loop() {
48 | // put your main code here, to run repeatedly:
49 |
50 | float voltage = 3.3 * analogRead(ADC_GPIO)/4095;
51 | delay(1);
52 |
53 | PhyphoxBLE::write(voltage);
54 |
55 | Serial.print("Voltage = ");
56 | Serial.println(voltage);
57 |
58 | delay(20);
59 | }
--------------------------------------------------------------------------------
/examples/getDataFromSmartphone/getDataFromSmartphone.ino:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | /* In this example we can change the blink interval of our mikrocontroller via phyphox
4 | */
5 |
6 | void receivedData();
7 |
8 | long lastTimestamp = 0;
9 | float blinkInterval = 100;
10 | bool led = true;
11 |
12 | void setup()
13 | {
14 | Serial.begin(115200);
15 | PhyphoxBLE::start();
16 | PhyphoxBLE::configHandler=&receivedData;
17 | pinMode(LED_BUILTIN, OUTPUT);
18 |
19 | //Experiment
20 | PhyphoxBleExperiment getDataFromSmartphone;
21 | getDataFromSmartphone.setTitle("Set Blink Interval");
22 | getDataFromSmartphone.setCategory("Arduino Experiments");
23 | getDataFromSmartphone.setDescription("User can set Blink Interval of Mikrocontroller LED");
24 |
25 | //View
26 | PhyphoxBleExperiment::View firstView;
27 | firstView.setLabel("FirstView"); //Create a "view"
28 |
29 | //Edit
30 | PhyphoxBleExperiment::Edit Interval;
31 | Interval.setLabel("Interval");
32 | Interval.setUnit("ms");
33 | Interval.setSigned(false);
34 | Interval.setDecimal(false);
35 | Interval.setChannel(1);
36 |
37 | firstView.addElement(Interval);
38 | getDataFromSmartphone.addView(firstView); //attach view to experiment
39 | PhyphoxBLE::addExperiment(getDataFromSmartphone); //attach experiment to server
40 | }
41 |
42 |
43 | void loop()
44 | {
45 | PhyphoxBLE::poll(); //Only required for the Arduino Nano 33 IoT, but it does no harm for other boards.
46 |
47 | if(millis()-lastTimestamp>blinkInterval){
48 | lastTimestamp = millis();
49 | led=!led;
50 | digitalWrite(LED_BUILTIN, led);
51 | }
52 | }
53 |
54 | void receivedData(){
55 | float receivedInterval;
56 | PhyphoxBLE::read(receivedInterval);
57 | if(receivedInterval>0){
58 | blinkInterval =receivedInterval;
59 | }
60 | Serial.println(blinkInterval);
61 | }
--------------------------------------------------------------------------------
/examples/getSensorDataFromSmartphone/getSensorDataFromSmartphone.ino:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | void setup() {
4 | Serial.begin(115200);
5 |
6 | PhyphoxBLE::start();
7 | PhyphoxBLE::configHandler=&receivedData;
8 |
9 | PhyphoxBleExperiment getDataFromSmartphonesensor;
10 | getDataFromSmartphonesensor.setTitle("Get Accelerometer Data");
11 | getDataFromSmartphonesensor.setCategory("Arduino Experiments");
12 | getDataFromSmartphonesensor.setDescription("Send smartphone accelerometer data to an arduino/esp32");
13 |
14 | PhyphoxBleExperiment::View firstView;
15 | firstView.setLabel("FirstView"); //Create a "view"
16 |
17 | PhyphoxBleExperiment::InfoField infoText;
18 | infoText.setInfo("Acc data is sent to smartphone");
19 | firstView.addElement(infoText);
20 |
21 | PhyphoxBleExperiment::Sensor smartphoneAcc; // add new sensor
22 |
23 | // Set type of sensor:
24 | // SENSOR_ACCELEROMETER
25 | // SENSOR_ACCELEROMETER_WITHOUT_G
26 | // SENSOR_GYROSCOPE
27 | // SENSOR_MAGNETOMETER
28 | // SENSOR_PRESSURE
29 | smartphoneAcc.setType(SENSOR_ACCELEROMETER);
30 | smartphoneAcc.setAverage(true);
31 | smartphoneAcc.setRate(80);
32 |
33 | // map sensor channel to incoming data channels
34 | smartphoneAcc.mapChannel("x",1);
35 | smartphoneAcc.mapChannel("y",2);
36 | smartphoneAcc.mapChannel("z",3);
37 |
38 | getDataFromSmartphonesensor.addView(firstView);
39 | getDataFromSmartphonesensor.addSensor(smartphoneAcc);
40 |
41 | PhyphoxBLE::addExperiment(getDataFromSmartphonesensor);
42 | PhyphoxBLE::printXML(&Serial); //print the generated xml file into the serial monitor
43 | }
44 |
45 | void loop() {
46 | delay(100);
47 | PhyphoxBLE::poll(); //Only required for the Arduino Nano 33 IoT, but it does no harm for other boards.
48 | }
49 |
50 | void receivedData(){
51 | Serial.println("data:");
52 | float x,y,z;
53 | PhyphoxBLE::read(x,y,z);
54 | Serial.print("x: ");
55 | Serial.print(x);
56 |
57 | Serial.print(" y: ");
58 | Serial.print(y);
59 |
60 | Serial.print(" z: ");
61 | Serial.println(z);
62 | }
--------------------------------------------------------------------------------
/src/edit.cpp:
--------------------------------------------------------------------------------
1 | #include "phyphoxBleExperiment.h"
2 | #include "copyToMem.h"
3 |
4 | void PhyphoxBleExperiment::Edit::setUnit(const char *u)
5 | {
6 | ERROR = ERROR.MESSAGE == NULL ? err_checkLength(u, 12, "setUnit") : ERROR;
7 | copyToMem(&UNIT, (std::string(u)).c_str());
8 | }
9 |
10 | void PhyphoxBleExperiment::Edit::setSigned(bool s)
11 | {
12 | if(s) copyToMem(&SIGNED, "true");
13 | else copyToMem(&SIGNED, "false");
14 | }
15 |
16 | void PhyphoxBleExperiment::Edit::setDecimal(bool d)
17 | {
18 | if(d) copyToMem(&DECIMAL, "true");
19 | else copyToMem(&DECIMAL, "false");
20 | }
21 |
22 | void PhyphoxBleExperiment::Edit::setXMLAttribute(const char *xml){
23 | ERROR = ERROR.MESSAGE == NULL ? err_checkLength(xml, 98, "setXMLAttribute") : ERROR;
24 | copyToMem(&XMLAttribute, (" " + std::string(xml)).c_str());
25 | }
26 |
27 | void PhyphoxBleExperiment::Edit::setChannel(int b){
28 | ERROR = ERROR.MESSAGE == NULL ? err_checkUpper(b, 5, "setChannel") : ERROR;
29 | char tmp[20];
30 | sprintf(tmp, "CB%i", b);
31 | copyToMem(&BUFFER, tmp);
32 | }
33 |
34 | void PhyphoxBleExperiment::Edit::getBytes(char *buffArray)
35 | {
36 | strcat(buffArray,"\t\t\n");
63 | strcat(buffArray,"\t\t\n");
66 | strcat(buffArray, "\t\t\n");
67 | }
68 |
--------------------------------------------------------------------------------
/src/value.cpp:
--------------------------------------------------------------------------------
1 | #include "phyphoxBleExperiment.h"
2 | #include "copyToMem.h"
3 |
4 | void PhyphoxBleExperiment::Value::setColor(const char *c)
5 | {
6 | ERROR = ERROR.MESSAGE == NULL ? err_checkHex(c, "setColor") : ERROR;
7 | copyToMem(&COLOR, (std::string(c)).c_str());
8 | }
9 |
10 | void PhyphoxBleExperiment::Value::setPrecision(int p)
11 | {
12 | ERROR = ERROR.MESSAGE == NULL ? err_checkUpper(p, 999, "setPrecision") : ERROR;
13 | char tmp[20];
14 | sprintf(tmp,"%i", p);
15 | copyToMem(&PRECISION, tmp);
16 | }
17 |
18 | void PhyphoxBleExperiment::Value::setUnit(const char* u)
19 | {
20 | ERROR = ERROR.MESSAGE == NULL ? err_checkLength(u, 12, "setUnit") : ERROR;
21 | copyToMem(&UNIT, (std::string(u)).c_str());
22 | }
23 |
24 | void PhyphoxBleExperiment::Value::setChannel(int c)
25 | {
26 | ERROR = ERROR.MESSAGE == NULL ? err_checkUpper(c, numberOfChannels, "setChannel") : ERROR;
27 | char tmp[20];
28 | sprintf(tmp, "CH%i", c);
29 | copyToMem(&INPUTVALUE, tmp);
30 | }
31 |
32 | void PhyphoxBleExperiment::Value::setXMLAttribute(const char *xml){
33 | ERROR = ERROR.MESSAGE == NULL ? err_checkLength(xml, 98, "setXMLAttribute") : ERROR;
34 | copyToMem(&XMLAttribute, (" " + std::string(xml)).c_str());
35 | }
36 |
37 | void PhyphoxBleExperiment::Value::getBytes(char *buffArray)
38 | {
39 |
40 | strcat(buffArray,"\t\t\n");
66 |
67 | strcat(buffArray, "\t\t\t");
68 | if (!INPUTVALUE) {strcat(buffArray,"CH3");} else {strcat(buffArray,INPUTVALUE);}
69 | strcat(buffArray, "\n\t\t\n");
70 | }
71 |
--------------------------------------------------------------------------------
/examples/rangefinder/rangefinder.ino:
--------------------------------------------------------------------------------
1 | #include //Phyphox BLE library
2 |
3 | #include //Required for the VL53L0X rangefinder
4 | #include //Required for the VL53L0X rangefinder
5 | VL53L0X sensor; //Instance of the rangefinder sensor
6 |
7 | void setup() {
8 | PhyphoxBLE::start("Rangefinder");
9 |
10 | //Experiment
11 | PhyphoxBleExperiment experiment;
12 |
13 | experiment.setTitle("Rangefinder");
14 | experiment.setCategory("Arduino Experiments");
15 | experiment.setDescription("Plot the distance from a time-of-flight sensor over time.");
16 |
17 | //View
18 | PhyphoxBleExperiment::View view;
19 |
20 | //Graph
21 | PhyphoxBleExperiment::Graph graph;
22 | graph.setLabel("Distance over time");
23 | graph.setUnitX("s");
24 | graph.setUnitY("mm");
25 | graph.setLabelX("time");
26 | graph.setLabelY("distance");
27 |
28 | //In contrast to other examples, we will not generate the timestamp on the phone.
29 | //For experiments with a high data rate, we can achieve a better temporal
30 | //accuracy if we generate the timestamp on the Arduino and send it in pairs with the
31 | //measured values.
32 | graph.setChannel(1,2);
33 |
34 | view.addElement(graph); //Attach graph to view
35 | experiment.addView(view); //Attach view to experiment
36 | PhyphoxBLE::addExperiment(experiment); //Attach experiment to server
37 |
38 | //Start the rangefinder
39 | Wire.begin();
40 | while (!sensor.init())
41 | delay(100);
42 | sensor.setTimeout(500);
43 | sensor.startContinuous();
44 | }
45 |
46 |
47 | void loop() {
48 | float t = 0.001 * (float)millis(); //Time in seconds
49 | float distance = sensor.readRangeContinuousMillimeters(); //Distance in millimeters
50 |
51 | if (distance == 8190) //This is an error state if no distance could be determined. Zero looks better in this case.
52 | distance = 0;
53 |
54 | PhyphoxBLE::write(t, distance); //Send data to phyphox
55 |
56 | PhyphoxBLE::poll(); //Only required for the Arduino Nano 33 IoT, but it does no harm for other boards.
57 | }
58 |
--------------------------------------------------------------------------------
/src/subgraph.cpp:
--------------------------------------------------------------------------------
1 | #include "phyphoxBleExperiment.h"
2 | #include "copyToMem.h"
3 |
4 | void PhyphoxBleExperiment::Graph::Subgraph::getBytes(char *buffArray)
5 | {
6 | //strcat(buffArray, "\n");
7 | strcat(buffArray, "\n\t\t\t");
24 | if (!INPUTX) {strcat(buffArray,"CH0");} else {strcat(buffArray,INPUTX);}
25 | strcat(buffArray, "\n\t\t\t");
26 | if (!INPUTY) {strcat(buffArray,"CH1");} else {strcat(buffArray,INPUTY);}
27 | strcat(buffArray, "");
28 | }
29 |
30 | void PhyphoxBleExperiment::Graph::Subgraph::setColor(const char *c){
31 | ERROR = ERROR.MESSAGE == NULL ? err_checkHex(c, "setColor") : ERROR;
32 | copyToMem(&COLOR, (std::string(c)).c_str());
33 | }
34 |
35 | void PhyphoxBleExperiment::Graph::Subgraph::setLinewidth(float w){
36 | ERROR = ERROR.MESSAGE == NULL ? err_checkUpper(w, 10, "setLinewidth") : ERROR;
37 | char tmp[10];
38 | sprintf(tmp, "%.2f", w);
39 | copyToMem(&WIDTH, tmp);
40 | }
41 | /**
42 | * @param s STYLE_DOTS
43 | */
44 | void PhyphoxBleExperiment::Graph::Subgraph::setStyle(const char *s){
45 | Error styleError = err_checkStyle(s, "setStyle");
46 | ERROR = ERROR.MESSAGE == NULL ? styleError : ERROR;
47 | if(styleError.MESSAGE == NULL){
48 | copyToMem(&STYLE, ("" + std::string(s)).c_str());
49 | }
50 | }
51 |
52 | void PhyphoxBleExperiment::Graph::Subgraph::setChannel(int x, int y)
53 | {
54 | ERROR = ERROR.MESSAGE == NULL ? err_checkUpper(x, numberOfChannels, "setChannel") : ERROR;
55 | ERROR = ERROR.MESSAGE == NULL ? err_checkUpper(y, numberOfChannels, "setChannel") : ERROR;
56 |
57 | char tmpX[20];
58 | sprintf(tmpX, "CH%i", x);
59 | copyToMem(&INPUTX, tmpX);
60 | char tmpY[20];
61 | sprintf(tmpY, "CH%i", y);
62 | copyToMem(&INPUTY, tmpY);
63 | }
--------------------------------------------------------------------------------
/src/boards/phyphoxBLE_NINAB31.h:
--------------------------------------------------------------------------------
1 | #ifndef PHYPHOXBLE_NINAB31_H
2 | #define PHYPHOXBLE_NINAB31_H
3 |
4 | #include
5 | #include "phyphoxBleExperiment.h"
6 | #include "NINAB31serial.h"
7 |
8 | class PhyphoxBLE
9 | {
10 | private:
11 |
12 | static uint8_t data_package[20];
13 |
14 | static NINAB31Serial port;
15 |
16 | static void controlCharacteristicWritten();
17 | static void configCharacteristicWritten();
18 |
19 | static int h_phyphoxExperimentService;
20 | static int h_experimentCharacteristic;
21 | static int h_controlCharacteristic;
22 |
23 | static int h_phyphoxDataService;
24 | static int h_dataCharacteristic;
25 | static int h_configCharacteristic;
26 | static bool exploaded;
27 |
28 | static uint8_t* data; //this pointer points to the data the user wants to write in the characteristic
29 | static uint8_t* p_exp; //this pointer will point to the byte array which holds an experiment
30 |
31 | static size_t expLen; //try o avoid this maybe use std::array or std::vector
32 | static uint8_t EXPARRAY[4000];// block some storage
33 |
34 | static uint8_t controlCharValue[21];
35 | static uint8_t configCharValue[21];
36 |
37 | public:
38 |
39 | static void start(const char* DEVICE_NAME, uint8_t* p, size_t n = 0);
40 | static void start(const char* DEVICE_NAME);
41 | static void start(uint8_t* p, size_t n = 0);
42 | static void start();
43 |
44 | static void addExperiment(PhyphoxBleExperiment&);
45 | static void transferExperiment();
46 | static void write(float&);
47 | static void write(float&, float&);
48 | static void write(float&, float&, float&);
49 | static void write(float&, float&, float&, float&);
50 | static void write(float&, float&, float&, float&, float&);
51 |
52 | static void read(uint8_t*, unsigned int);
53 | static void read(float&);
54 |
55 |
56 |
57 | static void poll();
58 | static void poll(int timeout);
59 |
60 | static void(*configHandler)();
61 | static uint16_t minConInterval;
62 | static uint16_t maxConInterval;
63 | static uint16_t slaveLatency;
64 | static uint16_t timeout;
65 | static uint16_t MTU;
66 |
67 | };
68 |
69 |
70 | #endif
71 |
--------------------------------------------------------------------------------
/src/boards/phyphoxBLE_NanoIOT.h:
--------------------------------------------------------------------------------
1 | #ifndef PHYPHOXBLE_NANOIOT_H
2 | #define PHYPHOXBLE_NANOIOT_H
3 |
4 | #include
5 | #include "phyphoxBleExperiment.h"
6 |
7 | class PhyphoxBLE
8 | {
9 | private:
10 |
11 | static uint8_t data_package[20];
12 |
13 | static void controlCharacteristicWritten(BLEDevice, BLECharacteristic);
14 | static void eventCharacteristicWritten(BLEDevice, BLECharacteristic);
15 | static void configCharacteristicWritten(BLEDevice, BLECharacteristic);
16 |
17 | static BLEService phyphoxExperimentService;
18 | static BLECharacteristic experimentCharacteristic;
19 | static BLECharacteristic controlCharacteristic;
20 | static BLECharacteristic eventCharacteristic;
21 |
22 | static BLEService phyphoxDataService;
23 | static BLECharacteristic dataCharacteristic;
24 | static BLECharacteristic configCharacteristic;
25 |
26 |
27 | static uint8_t* data; //this pointer points to the data the user wants to write in the characteristic
28 | static uint8_t* p_exp; //this pointer will point to the byte array which holds an experiment
29 |
30 | static size_t expLen; //try o avoid this maybe use std::array or std::vector
31 | static char *EXPARRAY;
32 |
33 | public:
34 |
35 | static void start(const char* DEVICE_NAME, uint8_t* p, size_t n = 0);
36 | static void start(const char* DEVICE_NAME);
37 | static void start(uint8_t* p, size_t n = 0);
38 | static void start();
39 |
40 | static void addExperiment(PhyphoxBleExperiment&);
41 | static void transferExperiment();
42 | static void write(float&);
43 | static void write(float&, float&);
44 | static void write(float&, float&, float&);
45 | static void write(float&, float&, float&, float&);
46 | static void write(float&, float&, float&, float&, float&);
47 |
48 | static void read(uint8_t*, unsigned int);
49 | static void read(float&);
50 | static void read(float&, float&);
51 | static void read(float&, float&, float&);
52 | static void read(float&, float&, float&, float&);
53 | static void read(float&, float&, float&, float&, float&);
54 |
55 |
56 | static void poll();
57 | static void poll(int timeout);
58 |
59 | static void(*configHandler)();
60 | static void(*experimentEventHandler)();
61 |
62 | static uint16_t minConInterval;
63 | static uint16_t maxConInterval;
64 | static uint16_t slaveLatency;
65 | static uint16_t timeout;
66 | static uint16_t MTU;
67 |
68 | static int64_t experimentTime;
69 | static int64_t systemTime;
70 | static uint8_t eventType;
71 |
72 | static uint8_t eventData[17];
73 |
74 | static void printXML(HardwareSerial*);
75 |
76 | };
77 |
78 |
79 | #endif
80 |
--------------------------------------------------------------------------------
/src/sensor.cpp:
--------------------------------------------------------------------------------
1 | #include "phyphoxBleExperiment.h"
2 | #include "copyToMem.h"
3 | #include
4 |
5 | void PhyphoxBleExperiment::Sensor::setType(const char *t)
6 | {
7 | ERROR = ERROR.MESSAGE == NULL ? err_checkSensor(t, "setType") : ERROR;
8 | copyToMem(&TYPE, (std::string(t)).c_str());
9 | }
10 |
11 | void PhyphoxBleExperiment::Sensor::mapChannel(const char *comp, int ch)
12 | {
13 | for(int i=0;i<5;i++){
14 | if (COMPONENT[i]==NULL)
15 | {
16 | ERROR = ERROR.MESSAGE == NULL ? err_checkComponent(comp, "routeData") : ERROR;
17 | ERROR = ERROR.MESSAGE == NULL ? err_checkUpper(ch,5, "routeData") : ERROR;
18 | copyToMem(&COMPONENT[i], (std::string(comp)).c_str());
19 | std::ostringstream s;
20 | s << ch;
21 | std::string temp = s.str();
22 | copyToMem(&CHANNEL[i], ("CB"+temp).c_str());
23 | break;
24 | }
25 | }
26 | }
27 | void PhyphoxBleExperiment::Sensor::setAverage(bool b)
28 | {
29 | if(b){
30 | copyToMem(&AVERAGE, "true");
31 | }else{
32 | copyToMem(&AVERAGE, "false");
33 | }
34 | }
35 |
36 | void PhyphoxBleExperiment::Sensor::setRate(int r){
37 | ERROR = ERROR.MESSAGE == NULL ? err_checkUpper(r,100, "setRate") : ERROR;
38 | std::ostringstream s;
39 | s << r;
40 | std::string temp = s.str();
41 | copyToMem(&RATE, (" rate=\""+temp+"\"").c_str());
42 | }
43 |
44 | void PhyphoxBleExperiment::Sensor::setXMLAttribute(const char *xml){
45 | ERROR = ERROR.MESSAGE == NULL ? err_checkLength(xml, 98, "setXMLAttribute") : ERROR;
46 | copyToMem(&XMLAttribute, (" " + std::string(xml)).c_str());
47 | }
48 |
49 | void PhyphoxBleExperiment::Sensor::getBytes(char *buffArray)
50 | {
51 | if(ERROR.MESSAGE == NULL){
52 | strcat(buffArray,"\t\n");
65 | //route components
66 | for (int i = 0; i < 5; i++){
67 | if(CHANNEL[i]!=NULL && COMPONENT[i]!=NULL){
68 | strcat(buffArray,"\t\t\n");
75 | }
76 | }
77 | strcat(buffArray,"\t\n");
78 | }
79 |
80 | }
--------------------------------------------------------------------------------
/src/errorhandler.cpp:
--------------------------------------------------------------------------------
1 | #include "phyphoxBleExperiment.h"
2 | #include "copyToMem.h"
3 |
4 |
5 | PhyphoxBleExperiment::Error PhyphoxBleExperiment::Errorhandler::err_checkLength(const char *input, int maxLength, const char *origin) {
6 | Error ret;
7 | if(strlen(input) > maxLength) {
8 | copyToMem(&ret.MESSAGE, ("ERR_01, in " + std::string(origin) + "(). \n").c_str());
9 | }
10 | return ret;
11 | }
12 |
13 | PhyphoxBleExperiment::Error PhyphoxBleExperiment::Errorhandler::err_checkUpper(int input, int upperValue, const char *origin) {
14 | Error ret;
15 | if(input > upperValue) {
16 | copyToMem(&ret.MESSAGE, ("ERR_02, in " + std::string(origin) + "(). \n").c_str());
17 | }
18 | return ret;
19 | }
20 |
21 | PhyphoxBleExperiment::Error PhyphoxBleExperiment::Errorhandler::err_checkHex(const char* input, const char *origin){
22 | Error ret;
23 | if(strlen(input) != 6) {
24 | copyToMem(&ret.MESSAGE, ("ERR_03, in " + std::string(origin) + "(). \n").c_str());
25 | };
26 | for(int i=0; i<=5; i++) {
27 | if(!((input[i] <='f' && input[i] >='a') || (input[i] <='F' && input[i] >='A') || (input[i] <='9' && input[i] >='0'))) {
28 | copyToMem(&ret.MESSAGE, ("ERR_03, in " + std::string(origin) + "(). \n").c_str());
29 | }
30 | }
31 | return ret;
32 | }
33 |
34 | PhyphoxBleExperiment::Error PhyphoxBleExperiment::Errorhandler::err_checkStyle(const char *input, const char *origin) {
35 | Error ret;
36 | if(strcmp(input,"lines")!=0 && strcmp(input,"dots")!=0 && strcmp(input,"vbars")!=0 && strcmp(input,"hbars")!=0 && strcmp(input,"map")!=0) {
37 | copyToMem(&ret.MESSAGE, ("ERR_04, in " + std::string(origin) + "(). \n").c_str());
38 | }
39 | return ret;
40 | }
41 |
42 | PhyphoxBleExperiment::Error PhyphoxBleExperiment::Errorhandler::err_checkLayout(const char *input, const char *origin) {
43 | Error ret;
44 | copyToMem(&ret.MESSAGE, ("ERR_05, in " + std::string(origin) + "(). \n").c_str());
45 | return ret;
46 | }
47 |
48 | PhyphoxBleExperiment::Error PhyphoxBleExperiment::Errorhandler::err_checkSensor(const char *input, const char *origin) {
49 | Error ret;
50 | if(strcmp(input,"accelerometer")!=0 && strcmp(input,"linear_acceleration")!=0 && strcmp(input,"gyroscope")!=0 && strcmp(input,"light")!=0 && strcmp(input,"magnetic_field")!=0 && strcmp(input,"pressure")!=0 && strcmp(input,"temperature")!=0) {
51 | copyToMem(&ret.MESSAGE, ("ERR_04, in " + std::string(origin) + "(). \n").c_str());
52 | }
53 | return ret;
54 | }
55 |
56 | PhyphoxBleExperiment::Error PhyphoxBleExperiment::Errorhandler::err_checkComponent(const char *input, const char *origin) {
57 | Error ret;
58 | if(strcmp(input,"x")!=0 && strcmp(input,"y")!=0 && strcmp(input,"z")!=0 && strcmp(input,"abs")!=0 && strcmp(input,"accuracy")!=0 && strcmp(input,"t")!=0) {
59 | copyToMem(&ret.MESSAGE, ("ERR_04, in " + std::string(origin) + "(). \n").c_str());
60 | }
61 | return ret;
62 | }
--------------------------------------------------------------------------------
/src/boards/phyphoxBLE_STM32.h:
--------------------------------------------------------------------------------
1 | #ifndef PHYPHOXBLE_STM32_H
2 | #define PHYPHOXBLE_STM32_H
3 | #if !defined(NDEBUG) && defined(ARDUINO_ARCH_STM32)
4 | #define NDEBUG
5 | #endif
6 |
7 | #include
8 |
9 | #include
10 | #include "phyphoxBleExperiment.h"
11 |
12 | class PhyphoxBLE
13 | {
14 | private:
15 |
16 | static uint8_t data_package[20];
17 |
18 | static void controlCharacteristicWritten(BLEDevice, BLECharacteristic);
19 | static void eventCharacteristicWritten(BLEDevice, BLECharacteristic);
20 | static void configCharacteristicWritten(BLEDevice, BLECharacteristic);
21 |
22 | static BLEService phyphoxExperimentService;
23 | static BLECharacteristic experimentCharacteristic;
24 | static BLECharacteristic controlCharacteristic;
25 | static BLECharacteristic eventCharacteristic;
26 |
27 | static BLEService phyphoxDataService;
28 | static BLECharacteristic dataCharacteristic;
29 | static BLECharacteristic configCharacteristic;
30 |
31 |
32 | static uint8_t* data; //this pointer points to the data the user wants to write in the characteristic
33 | static uint8_t* p_exp; //this pointer will point to the byte array which holds an experiment
34 |
35 | static size_t expLen; //try o avoid this maybe use std::array or std::vector
36 | static char *EXPARRAY;
37 |
38 | public:
39 |
40 | static void start(const char* DEVICE_NAME, uint8_t* p, size_t n = 0);
41 | static void start(const char* DEVICE_NAME);
42 | static void start(uint8_t* p, size_t n = 0);
43 | static void start();
44 |
45 | static void addExperiment(PhyphoxBleExperiment&);
46 | static void transferExperiment();
47 | static void write(float&);
48 | static void write(float&, float&);
49 | static void write(float&, float&, float&);
50 | static void write(float&, float&, float&, float&);
51 | static void write(float&, float&, float&, float&, float&);
52 |
53 | static void read(uint8_t*, unsigned int);
54 | static void read(float&);
55 | static void read(float&, float&);
56 | static void read(float&, float&, float&);
57 | static void read(float&, float&, float&, float&);
58 | static void read(float&, float&, float&, float&, float&);
59 |
60 |
61 | static void poll();
62 | static void poll(int timeout);
63 |
64 | static void(*configHandler)();
65 | static void(*experimentEventHandler)();
66 |
67 | static uint16_t minConInterval;
68 | static uint16_t maxConInterval;
69 | static uint16_t slaveLatency;
70 | static uint16_t timeout;
71 | static uint16_t MTU;
72 |
73 | static int64_t experimentTime;
74 | static int64_t systemTime;
75 | static uint8_t eventType;
76 |
77 | static uint8_t eventData[17];
78 |
79 | static void printXML(HardwareSerial*);
80 |
81 | };
82 |
83 |
84 | #endif
85 |
--------------------------------------------------------------------------------
/examples/multigraph/multigraph.ino:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #define PI 3.1415926535897932384626433832795
4 | float periodTime = 2.0;//in s
5 |
6 | void setup() {
7 | Serial.begin(115200);
8 | PhyphoxBLE::start();
9 |
10 | PhyphoxBleExperiment MultiGraph;
11 |
12 | MultiGraph.setTitle("Multi Graph Example");
13 | MultiGraph.setCategory("Arduino Experiments");
14 | MultiGraph.setDescription("ArduinoBLE Example");
15 |
16 | PhyphoxBleExperiment::View firstView;
17 | firstView.setLabel("FirstView"); //Create a "view"
18 |
19 | //Multiple graphs in one plot can be realised by two different methods.
20 | // OPTION 1 is do create a graph as usual and add additional datastreams the following way
21 | PhyphoxBleExperiment::Graph myFirstGraph;
22 | myFirstGraph.setLabel("Trigonometric functions");
23 | myFirstGraph.setLabelX("time");
24 | myFirstGraph.setUnitX("s");
25 | myFirstGraph.setLabelY("sin(t), cos(t)");
26 |
27 | myFirstGraph.setChannel(1,2);
28 | myFirstGraph.setStyle(STYLE_DOTS);//"lines" are used if you dont set a style
29 | myFirstGraph.setColor("ffffff");
30 | myFirstGraph.setLinewidth(2);//if you dont select a linewidth, a width of 1 is used by default
31 |
32 | PhyphoxBleExperiment::Graph::Subgraph additionalData;
33 | additionalData.setChannel(1,3);
34 | additionalData.setStyle(STYLE_LINES);
35 | additionalData.setColor("ff00ff");
36 | additionalData.setLinewidth(1);
37 |
38 | myFirstGraph.addSubgraph(additionalData);
39 |
40 | //OPTION 2: you can also skip editing the graph object and just add datastreams
41 | PhyphoxBleExperiment::Graph mySecondGraph;
42 | mySecondGraph.setLabel("Trigonometric functions");
43 | mySecondGraph.setLabelX("time");
44 | mySecondGraph.setUnitX("s");
45 | mySecondGraph.setLabelY("sin(t), cos(t)");
46 |
47 | PhyphoxBleExperiment::Graph::Subgraph firstData;
48 | firstData.setChannel(1,2);
49 | firstData.setColor("ffffff");
50 | firstData.setStyle(STYLE_DOTS);
51 | firstData.setLinewidth(2);
52 |
53 | mySecondGraph.addSubgraph(firstData);
54 |
55 | PhyphoxBleExperiment::Graph::Subgraph secondData;
56 | secondData.setChannel(1,3);
57 | secondData.setColor("ff00ff");
58 | secondData.setLinewidth(1);//if you dont select a linewidth, a width of 1 is used by default
59 | secondData.setStyle(STYLE_LINES); //"lines" are used if you dont set a style
60 |
61 |
62 | mySecondGraph.addSubgraph(secondData);
63 |
64 | firstView.addElement(myFirstGraph);
65 | firstView.addElement(mySecondGraph);
66 |
67 | MultiGraph.addView(firstView);
68 |
69 | PhyphoxBLE::addExperiment(MultiGraph);
70 |
71 | PhyphoxBLE::printXML(&Serial);
72 | }
73 |
74 | void loop() {
75 |
76 | float currentTime = millis()/1000.0;
77 | float sinus = generateSin(currentTime);
78 | float cosinus = generateSin(currentTime+0.25*periodTime);
79 | PhyphoxBLE::write(currentTime,sinus,cosinus);
80 | delay(100);
81 | PhyphoxBLE::poll(); //Only required for the Arduino Nano 33 IoT, but it does no harm for other boards.
82 | }
83 |
84 | float generateSin(float x){
85 | return 1.0 * sin(x*2.0*PI/periodTime);
86 | }
--------------------------------------------------------------------------------
/src/phyphoxBle.h:
--------------------------------------------------------------------------------
1 | #ifndef PHYPHOXBLE
2 | #define PHYPHOXBLE
3 |
4 | #include "Arduino.h"
5 |
6 | static const char *phyphoxBleExperimentServiceUUID = "cddf0001-30f7-4671-8b43-5e40ba53514a";
7 | static const char *phyphoxBleExperimentCharacteristicUUID = "cddf0002-30f7-4671-8b43-5e40ba53514a";
8 | static const char *phyphoxBleExperimentControlCharacteristicUUID = "cddf0003-30f7-4671-8b43-5e40ba53514a";
9 | static const char *phyphoxBleEventCharacteristicUUID = "cddf0004-30f7-4671-8b43-5e40ba53514a";
10 |
11 | static const char *phyphoxBleDataServiceUUID = "cddf1001-30f7-4671-8b43-5e40ba53514a";
12 | static const char *phyphoxBleDataCharacteristicUUID = "cddf1002-30f7-4671-8b43-5e40ba53514a";
13 | static const char *phyphoxBleConfigCharacteristicUUID = "cddf1003-30f7-4671-8b43-5e40ba53514a";
14 |
15 | static const char *deviceName = "phyphox-Arduino";
16 |
17 | #define SENSOR_ACCELEROMETER "accelerometer"
18 | #define SENSOR_ACCELEROMETER_WITHOUT_G "linear_acceleration"
19 | #define SENSOR_GYROSCOPE "gyroscope"
20 | #define SENSOR_MAGNETOMETER "magnetometer"
21 | #define SENSOR_PRESSURE "pressure"
22 | #define SENSOR_TEMPERATURE "temperature"
23 | #define SENSOR_LIGHT "light"
24 | #define SENSOR_HUMIDITY "humidity"
25 | #define SENSOR_PROXIMITY "proximity"
26 |
27 | #define STYLE_DOTS "dots"
28 | #define STYLE_LINES "lines"
29 | #define STYLE_VBARS "vbars"
30 | #define STYLE_HBARS "hbars"
31 | #define STYLE_MAP "map"
32 |
33 | #define COLOR_RED "fe005d"
34 | #define COLOR_BLUE "39a2ff"
35 | #define COLOR_GREEN "2bfb4c"
36 | #define COLOR_ORANGE "ff7e22"
37 | #define COLOR_WHITE "ffffff"
38 | #define COLOR_YELLOW "edf668"
39 | #define COLOR_MAGENTA "eb46f4"
40 |
41 | #define LAYOUT_AUTO "auto"
42 | #define LAYOUT_EXTEND "extend"
43 | #define LAYOUT_FIXED "fixed"
44 |
45 | #ifndef CONFIGSIZE
46 | #define CONFIGSIZE 20
47 | #endif
48 | #if defined(ARDUINO_SAMD_MKR1000) || defined(ARDUINO_SENSEBOX_MCU_ESP32S2)
49 | #include "boards/phyphoxBLE_NINAB31.h"
50 | #elif defined(ARDUINO_ARCH_MBED)
51 | #include "boards/phyphoxBLE_NRF52.h"
52 | #elif defined(ESP32) && !defined(ARDUINO_SENSEBOX_MCU_ESP32S2)
53 | #include "boards/phyphoxBLE_ESP32.h"
54 | #elif defined(ARDUINO_SAMD_NANO_33_IOT) || defined(ARDUINO_UNOR4_WIFI) || defined(ARDUINO_SAMD_MKRWIFI1010)
55 | #include
56 | #include "boards/phyphoxBLE_NanoIOT.h"
57 | #elif defined(ARDUINO_ARCH_STM32)
58 | #include "boards/phyphoxBLE_STM32.h"
59 | #else
60 | #error "Unsupported board selected!"
61 | #endif
62 |
63 | #include "Arduino.h"
64 |
65 | struct phyphoxBleCrc32
66 | {
67 | static void generate_table(uint32_t(&table)[256])
68 | {
69 | uint32_t polynomial = 0xEDB88320;
70 | for (uint32_t i = 0; i < 256; i++)
71 | {
72 | uint32_t c = i;
73 | for (size_t j = 0; j < 8; j++)
74 | {
75 | if (c & 1) {
76 | c = polynomial ^ (c >> 1);
77 | }
78 | else {
79 | c >>= 1;
80 | }
81 | }
82 | table[i] = c;
83 | }
84 | }
85 |
86 | static uint32_t update(uint32_t (&table)[256], uint32_t initial, const uint8_t* buf, size_t len)
87 | {
88 | uint32_t c = initial ^ 0xFFFFFFFF;
89 | const uint8_t* u = static_cast(buf);
90 | for (size_t i = 0; i < len; ++i)
91 | {
92 | c = table[(c ^ u[i]) & 0xFF] ^ (c >> 8);
93 | }
94 | return c ^ 0xFFFFFFFF;
95 | }
96 | };
97 |
98 | static int64_t swap_int64( int64_t val ){
99 | val = ((val << 8) & 0xFF00FF00FF00FF00ULL ) | ((val >> 8) & 0x00FF00FF00FF00FFULL );
100 | val = ((val << 16) & 0xFFFF0000FFFF0000ULL ) | ((val >> 16) & 0x0000FFFF0000FFFFULL );
101 | return (val << 32) | ((val >> 32) & 0xFFFFFFFFULL);
102 | }
103 |
104 | #endif
105 |
--------------------------------------------------------------------------------
/src/boards/phyphoxBLE_ESP32.h:
--------------------------------------------------------------------------------
1 | #ifdef ESP32
2 | #ifndef PHYPHOXBLE_ESP32_H
3 | #define PHYPHOXBLE_ESP32_H
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include "phyphoxBleExperiment.h"
12 |
13 | using std::copy;
14 |
15 |
16 | class PhyphoxBLE
17 | {
18 | private:
19 |
20 | static uint8_t data_package[20];
21 |
22 | static BLEServer *myServer;
23 | static BLEService *phyphoxDataService;
24 | static BLEService *phyphoxExperimentService;
25 | static BLEDescriptor *myExperimentDescriptor;
26 | static BLEDescriptor *myDataDescriptor;
27 | static BLEDescriptor *myEventDescriptor;
28 | static BLEDescriptor *myConfigDescriptor;
29 | static BLECharacteristic *dataCharacteristic;
30 | static BLECharacteristic *experimentCharacteristic;
31 | static BLECharacteristic *eventCharacteristic;
32 | static BLECharacteristic *configCharacteristic;
33 | static BLEAdvertising *myAdvertising;
34 |
35 | // void when_connected();
36 | // virtual void onDisconnectionComplete();
37 |
38 | static uint8_t* data; //this pointer points to the data the user wants to write in the characteristic
39 | static uint8_t* p_exp; //this pointer will point to the byte array which holds an experiment
40 | static TaskHandle_t TaskTransfer;
41 |
42 | static char *EXPARRAY;
43 |
44 | static size_t expLen; //try o avoid this maybe use std::array or std::vector
45 |
46 | public:
47 |
48 | static void disconnected();
49 | static void start(const char* DEVICE_NAME, uint8_t* p, size_t n = 0);
50 | static void start(const char* DEVICE_NAME);
51 | static void start(uint8_t* p, size_t n = 0);
52 | static void start();
53 |
54 | static void when_subscription_received();
55 | static void addExperiment(PhyphoxBleExperiment&);
56 |
57 | static void poll();
58 | static void poll(int timeout);
59 |
60 | static void write(float&);
61 | static void write(float&, float&);
62 | static void write(float&, float&, float&);
63 | static void write(float&, float&, float&, float&);
64 | static void write(float&, float&, float&, float&, float&);
65 | static void write(uint8_t *, unsigned int );
66 | static void write(float *,unsigned int);
67 |
68 |
69 | static void read(uint8_t*, unsigned int);
70 | static void read(float&);
71 | static void read(float&, float&);
72 | static void read(float&, float&, float&);
73 | static void read(float&, float&, float&, float&);
74 | static void read(float&, float&, float&, float&, float&);
75 | static void configHandlerDebug();
76 | static void (*configHandler)();
77 |
78 | static void eventCharacteristicHandler();
79 | static void (*experimentEventHandler)();
80 |
81 | static void printXML(HardwareSerial*);
82 |
83 | static void setMTU(uint16_t);
84 | static uint16_t MTU;
85 |
86 | static void startTask();
87 | static void staticStartTask(void*);
88 |
89 | static HardwareSerial* printer; //for debug purpose
90 | static void begin(HardwareSerial*); //for debug purpose
91 |
92 | static uint16_t minConInterval;
93 | static uint16_t maxConInterval;
94 | static uint16_t slaveLatency;
95 | static uint16_t timeout;
96 | static uint16_t currentConnections;
97 | static bool isSubscribed;
98 |
99 | static uint8_t eventData[17];
100 | static int64_t experimentTime;
101 | static int64_t systemTime;
102 | static uint8_t eventType;
103 | };
104 |
105 |
106 | #endif
107 | #endif
108 |
--------------------------------------------------------------------------------
/src/boards/phyphoxBLE_NRF52.h:
--------------------------------------------------------------------------------
1 | #ifndef PHYPHOXBLE_NRF52_H
2 | #define PHYPHOXBLE_NRF52_H
3 | #if !defined(NDEBUG) && defined(ARDUINO_ARCH_MBED)
4 | #define NDEBUG
5 | #endif
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 |
19 | #include "phyphoxBleExperiment.h"
20 |
21 | #ifndef NDEBUG
22 | using arduino::HardwareSerial;
23 | #endif
24 | using events::EventQueue;
25 | using rtos::Thread;
26 | using mbed::callback;
27 | using std::copy;
28 |
29 | #ifndef DATASIZE
30 | #define DATASIZE 20
31 | #endif
32 |
33 | class PhyphoxBleEventHandler : public ble::Gap::EventHandler {
34 | public:
35 |
36 | virtual void onDisconnectionComplete(const ble::DisconnectionCompleteEvent&);
37 | virtual void onConnectionComplete(const ble::ConnectionCompleteEvent&);
38 | PhyphoxBleEventHandler(BLE& ble):
39 | ble(ble) {
40 | }
41 |
42 | private:
43 | BLE& ble;
44 | };
45 |
46 | class PhyphoxBLE
47 | {
48 |
49 | private:
50 |
51 | static PhyphoxBleEventHandler eventHandler;
52 |
53 |
54 | static const UUID phyphoxExperimentServiceUUID;
55 | static const UUID phyphoxDataServiceUUID;
56 |
57 | static const UUID experimentCharacteristicUUID;
58 | static const UUID dataCharacteristicUUID;
59 | static const UUID configCharacteristicUUID;
60 | static const UUID eventCharacteristicUUID;
61 |
62 | static char name[50];
63 |
64 | static uint8_t data_package[20];
65 | static uint8_t eventData[17];
66 | static uint8_t config_package[CONFIGSIZE];
67 |
68 | /*BLE stuff*/
69 | static BLE& ble;
70 | static ReadWriteArrayGattCharacteristic dataCharacteristic; //Note: Use { } instead of () google most vexing parse
71 | static uint8_t readValue[DATASIZE];
72 | static ReadWriteArrayGattCharacteristic eventCharacteristic;
73 | static ReadWriteArrayGattCharacteristic configCharacteristic;
74 | static ReadOnlyArrayGattCharacteristic experimentCharacteristic;
75 |
76 | static Thread bleEventThread;
77 | static Thread transferExpThread;
78 | static EventQueue queue;
79 | /*end BLE stuff*/
80 | static EventQueue transferQueue;
81 |
82 |
83 | //helper function to initialize BLE server and for connection poperties
84 | static void bleInitComplete(BLE::InitializationCompleteCallbackContext*);
85 | static void when_subscription_received(GattAttribute::Handle_t);
86 | static void configReceived(const GattWriteCallbackParams *params);
87 | static void eventReceived(const GattWriteCallbackParams *params);
88 |
89 | //helper functon that runs in the thread ble_server
90 | //static void waitForEvent();
91 | static void transferExp();
92 | static GattCharacteristic* phyphoxCharacteristics[];
93 | static GattService phyphoxService;
94 |
95 | static GattCharacteristic* phyphoxDataCharacteristics[];
96 | static GattService phyphoxDataService;
97 |
98 | static void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context);
99 |
100 | #ifndef NDEBUG
101 | static inline HardwareSerial* printer; //for debug purpose
102 | #endif
103 | static uint8_t* data; //this pointer points to the data the user wants to write in the characteristic
104 | static uint8_t* config;
105 | static uint8_t* event;
106 | static uint8_t* p_exp; //this pointer will point to the byte array which holds an experiment
107 |
108 |
109 | public:
110 |
111 | static char EXPARRAY[4096];// block some storage
112 | static size_t expLen; //try o avoid this maybe use std::array or std::vector
113 |
114 | static inline uint16_t minConInterval = 6; //7.5ms
115 | static inline uint16_t maxConInterval = 24; //30ms
116 | static inline uint16_t slaveLatency = 0;
117 | static inline uint16_t timeout = 50;
118 | static inline uint16_t MTU = 20;
119 | static inline uint16_t currentConnections = 0;
120 |
121 | static void (*configHandler)();
122 | static void (*experimentEventHandler)();
123 |
124 | static void printXML(HardwareSerial*);
125 |
126 | static void poll();
127 | static void poll(int timeout);
128 |
129 | static void start(const char* DEVICE_NAME, uint8_t* p, size_t n = 0);
130 | static void start(const char* DEVICE_NAME);
131 | static void start(uint8_t* p, size_t n = 0);
132 | static void start();
133 |
134 | static void write(uint8_t*, unsigned int);
135 | static void write(float&);
136 | static void write(float&, float&, float&, float&, float&);
137 | static void write(float&, float&, float&, float&);
138 | static void write(float&, float&, float&);
139 | static void write(float&, float&);
140 | static void read(uint8_t*, unsigned int);
141 | static void read(float&);
142 | static void read(float&, float&);
143 | static void read(float&, float&, float&);
144 | static void read(float&, float&, float&, float&);
145 | static void read(float&, float&, float&, float&, float&);
146 |
147 | static void addExperiment(PhyphoxBleExperiment&);
148 |
149 | static int64_t experimentTime;
150 | static int64_t systemTime;
151 | static uint8_t eventType;
152 |
153 | #ifndef NDEBUG
154 | static void begin(HardwareSerial*); //for debug purpose
155 | static void output(const char*); //for debug purpose
156 | static void output(const uint32_t);
157 | #endif
158 | };
159 |
160 | #endif
161 |
--------------------------------------------------------------------------------
/examples/CreateExperiment/CreateExperiment.ino:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | void setup()
4 | {
5 | Serial.begin(115200);
6 | PhyphoxBLE::start("create experiment");
7 |
8 | //Experiment
9 | PhyphoxBleExperiment plotRandomValues; //generate experiment on Arduino which plot random values
10 |
11 |
12 | plotRandomValues.setTitle("Create Experiment");
13 | plotRandomValues.setCategory("Arduino Experiments");
14 | plotRandomValues.setDescription("Random numbers are generated on Arduino and visualized with phyphox afterwards");
15 |
16 | //View
17 | PhyphoxBleExperiment::View firstView;
18 | firstView.setLabel("FirstView"); //Create a "view"
19 | PhyphoxBleExperiment::View secondView;
20 | secondView.setLabel("SecondView"); //Create a "view"
21 |
22 | //Graph
23 | PhyphoxBleExperiment::Graph firstGraph; //Create graph which will plot random numbers over time
24 | firstGraph.setMinY(0, LAYOUT_FIXED);
25 | firstGraph.setMaxY(100, LAYOUT_FIXED);
26 | firstGraph.setLabel("Random number over time");
27 | firstGraph.setUnitX("s");
28 | firstGraph.setUnitY("");
29 | firstGraph.setLabelX("time");
30 | firstGraph.setLabelY("random number");
31 | firstGraph.setXPrecision(1); //The amount of digits shown after the decimal point
32 | firstGraph.setYPrecision(1);
33 |
34 | /* Assign Channels, so which data is plotted on x or y axis
35 | first parameter represents x-axis, second y-axis
36 | Channel 0 means a timestamp is created after the BLE package arrives in phyphox
37 | Channel 1 to N corresponding to the N-parameter which is written in server.write()
38 | */
39 |
40 | firstGraph.setChannel(0, 1);
41 |
42 | //Second Graph
43 |
44 | PhyphoxBleExperiment::Graph secondGraph; //Create graph which will plot random numbers over time
45 | secondGraph.setLabel("Random number squared over random number");
46 | secondGraph.setUnitX("");
47 | secondGraph.setUnitY("");
48 | secondGraph.setLabelX("random number");
49 | secondGraph.setLabelY("squared");
50 | secondGraph.setStyle(STYLE_DOTS);
51 | secondGraph.setColor("2E728E"); //Sets Color of line
52 |
53 | /* Assign Channels, so which data is plotted on x or y axis
54 | first parameter represents x-axis, second y-axis
55 | Channel 0 means a timestamp is created after the BLE package arrives in phyphox
56 | Channel 1 to N corresponding to the N-parameter which is written in server.write()
57 | */
58 |
59 | secondGraph.setChannel(1, 2);
60 |
61 |
62 | //Info
63 | PhyphoxBleExperiment::InfoField myInfo; //Creates an info-box.
64 | myInfo.setInfo("This is an Info field!");
65 | myInfo.setColor("890128"); //Sets font color. Uses a 6 digit hexadecimal value in "quotation marks".
66 | myInfo.setXMLAttribute("size=\"1.2\"");
67 |
68 | //Separator
69 | PhyphoxBleExperiment::Separator mySeparator; //Creates a line to separate elements.
70 | mySeparator.setHeight(0.3); //Sets height of the separator.
71 | mySeparator.setColor("404040"); //Sets color of the separator. Uses a 6 digit hexadecimal value in "quotation marks".
72 |
73 | //Value
74 | PhyphoxBleExperiment::Value myValue; //Creates a value-box.
75 | myValue.setLabel("Number"); //Sets the label
76 | myValue.setPrecision(2); //The amount of digits shown after the decimal point.
77 | myValue.setUnit("unit"); //The physical unit associated with the displayed value.
78 | myValue.setColor("FFFFFF"); //Sets font color. Uses a 6 digit hexadecimal value in "quotation marks".
79 | myValue.setChannel(0);
80 | myValue.setXMLAttribute("size=\"2\"");
81 |
82 | //Export
83 | PhyphoxBleExperiment::ExportSet mySet; //Provides exporting the data to excel etc.
84 | mySet.setLabel("mySet");
85 | PhyphoxBleExperiment::ExportData myData1;
86 | myData1.setLabel("myData1");
87 | myData1.setDatachannel(1);
88 |
89 | PhyphoxBleExperiment::ExportData myData2;
90 | myData2.setLabel("myData2");
91 | myData2.setDatachannel(2);
92 |
93 | //attach to experiment
94 |
95 | firstView.addElement(firstGraph); //attach graph to view
96 | firstView.addElement(secondGraph); //attach second graph to view
97 | secondView.addElement(myInfo); //attach info to view
98 | secondView.addElement(mySeparator); //attach separator to view
99 | secondView.addElement(myValue); //attach value to view
100 |
101 | plotRandomValues.addView(firstView); //attach view to experiment
102 | plotRandomValues.addView(secondView);
103 | mySet.addElement(myData1); //attach data to exportSet
104 | mySet.addElement(myData2); //attach data to exportSet
105 | plotRandomValues.addExportSet(mySet); //attach exportSet to experiment
106 | PhyphoxBLE::addExperiment(plotRandomValues); //attach experiment to server
107 | }
108 |
109 |
110 | void loop()
111 | {
112 | float randomValue = random(0, 100); //create random number between 0 - 100
113 | float randomValue2 = randomValue * randomValue;
114 |
115 | /* The random number is written into Channel 1
116 | Up to 5 Channels can written at the same time with server.write(randomDistance, valueChannel2, valueChannel3.. )
117 | */
118 | PhyphoxBLE::write(randomValue, randomValue2);
119 | delay(50);
120 |
121 | PhyphoxBLE::poll(); //Only required for the Arduino Nano 33 IoT, but it does no harm for other boards.
122 | }
--------------------------------------------------------------------------------
/src/boards/NINAB31serial.cpp:
--------------------------------------------------------------------------------
1 | #if defined(ARDUINO_SAMD_MKR1000) || defined(ARDUINO_SENSEBOX_MCU_ESP32S2)
2 | #include "NINAB31serial.h"
3 |
4 | #if defined(ARDUINO_SAMD_MKR1000)
5 | #define SerialBLE Serial3
6 | #elif defined(ARDUINO_SENSEBOX_MCU_ESP32S2)
7 | #define SerialBLE Serial1
8 | #endif
9 |
10 |
11 | String NINAB31Serial::m_input="";
12 | bool NINAB31Serial::connected=false;
13 |
14 | bool NINAB31Serial::configModule(){
15 | SerialBLE.print("AT+UMRS=115200,2,8,1,1\r"); //115200, no flow control, 8 data bits, 1 stop bit, no parity
16 | SerialBLE.print("AT&W0\r"); //write configuration to nonvolatile memory
17 | SerialBLE.print("AT+CPWROFF\r"); //restart module into new configuration
18 | SerialBLE.flush();
19 | delay(2000); //wait for module to come up
20 | /*digitalWrite(22,HIGH); //hardware power cycle - avoid if possible
21 | delay(500);
22 | digitalWrite(22,LOW);
23 | delay(1000);
24 | */
25 | return checkResponse("ATE0",500); //send command (echo off) and check if module is responding correctly
26 | }
27 |
28 | bool NINAB31Serial::begin(){
29 | SerialBLE.begin(115200);
30 | delay(500);
31 | checkResponse("AT",500); //throwaway command in case buffer gets reinitialized because SerialBLE.begin was already called
32 | for(int i=0;i<3;i++){ //try to send a command, in case it fails configure device and restart it
33 | if(checkResponse("ATE0",500)){
34 | return true;
35 | }else{
36 | if(configModule()){
37 | return true;
38 | }
39 | }
40 | }
41 | return false;
42 | }
43 |
44 | bool NINAB31Serial::setLocalName(String name){
45 | if(name.length()>29){
46 | return false;
47 | }
48 | return checkResponse(String("AT+UBTLN=\"")+name+"\"", 1000);
49 | }
50 |
51 | bool NINAB31Serial::advertise(){
52 | return checkResponse(String("AT+UBTDM=3"), 1000);
53 | }
54 |
55 | bool NINAB31Serial::stopAdvertise(){
56 | return checkResponse(String("AT+UBTDM=1"), 1000);
57 | }
58 |
59 |
60 | bool NINAB31Serial::setConnectionInterval(int minInterval, int maxInterval){
61 | if(minInterval<32 || minInterval >16384 || maxInterval<32 || maxInterval >16384 || maxInterval40){
72 | return false;
73 | }
74 | return checkResponse(String("AT+UBTGSN=0,")+characteristic+","+value, 1000);
75 | }
76 |
77 | bool NINAB31Serial::writeValue(int characteristic, uint8_t* value, int len){
78 | if(!connected){
79 | return false;
80 | }
81 | if(len>20){
82 | return false;
83 | }
84 | auto msg=String("AT+UBTGSN=0,")+characteristic+",";
85 | for(int i=0;i>4,HEX);
87 | msg+=String((value[i]&0xf),HEX);
88 | }
89 | return checkResponse(msg, 1000);
90 | }
91 |
92 |
93 |
94 | int NINAB31Serial::parseResponse(String cmd, uint32_t timeout){
95 | while(SerialBLE.available()){
96 | (SerialBLE.read());
97 | }
98 | SerialBLE.print(cmd);
99 | SerialBLE.write('\r');
100 | SerialBLE.flush();
101 | String input="";
102 | auto starttime=millis();
103 | while(millis()-starttime seccommapos){
182 | int rhandle=m_input.substring(commapos+1,seccommapos).toInt();
183 | if(rhandle==handle){
184 | return m_input.substring(seccommapos+1,thirdcommapos);
185 | }
186 | }
187 |
188 | }else{
189 | //Serial.println(m_input);
190 | }
191 | return "";
192 |
193 | }
194 |
195 | void NINAB31Serial::flushInput(){
196 | m_input="";
197 | }
198 |
199 | #endif
200 |
201 |
202 |
--------------------------------------------------------------------------------
/COPYING.LESSER:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
166 |
--------------------------------------------------------------------------------
/src/graph.cpp:
--------------------------------------------------------------------------------
1 | #include "phyphoxBleExperiment.h"
2 | #include "copyToMem.h"
3 | #include
4 |
5 | void PhyphoxBleExperiment::Graph::setUnitX(const char *ux){
6 | ERROR = ERROR.MESSAGE == NULL ? err_checkLength(ux, 5, "setUnitX") : ERROR;
7 | copyToMem(&UNITX, (std::string(ux)).c_str());
8 | }
9 |
10 | void PhyphoxBleExperiment::Graph::setUnitY(const char *uy){
11 | ERROR = ERROR.MESSAGE == NULL ? err_checkLength(uy, 5, "setUnitY") : ERROR;
12 | copyToMem(&UNITY, (std::string(uy)).c_str());
13 | }
14 |
15 | void PhyphoxBleExperiment::Graph::setLabelX(const char *lx){
16 | ERROR = ERROR.MESSAGE == NULL ? err_checkLength(lx, 20, "setLabelX") : ERROR;
17 | copyToMem(&LABELX, (std::string(lx)).c_str());
18 | }
19 |
20 | void PhyphoxBleExperiment::Graph::setLabelY(const char *ly){
21 | ERROR = ERROR.MESSAGE == NULL ? err_checkLength(ly, 20, "setLabelY") : ERROR;
22 | copyToMem(&LABELY, (std::string(ly)).c_str());
23 | }
24 |
25 |
26 | void PhyphoxBleExperiment::Graph::setColor(const char *c){
27 | FIRSTSUBGRAPH.setColor(c);
28 | }
29 |
30 | void PhyphoxBleExperiment::Graph::setLinewidth(float w){
31 | FIRSTSUBGRAPH.setLinewidth(w);
32 | }
33 |
34 | void PhyphoxBleExperiment::Graph::setXPrecision(int px){
35 | ERROR = ERROR.MESSAGE == NULL ? err_checkUpper(px, 9999, "setXPrecision") : ERROR;
36 | char tmp[20];
37 | sprintf(tmp, "%i", px);
38 | copyToMem(&XPRECISION, tmp);
39 | }
40 |
41 | void PhyphoxBleExperiment::Graph::setYPrecision(int py){
42 | ERROR = ERROR.MESSAGE == NULL ? err_checkUpper(py, 9999, "setYPrecision") : ERROR;
43 | char tmp[20];
44 | sprintf(tmp, "%i", py);
45 | copyToMem(&YPRECISION, tmp);
46 | }
47 |
48 | void PhyphoxBleExperiment::Graph::setTimeOnX(bool b){
49 | char tmp[10];
50 | if(b){
51 | sprintf(tmp, "true");
52 | }else{
53 | sprintf(tmp, "false");
54 | }
55 | copyToMem(&TIMEONX, tmp);
56 | }
57 |
58 | void PhyphoxBleExperiment::Graph::setTimeOnY(bool b){
59 | char tmp[10];
60 | if(b){
61 | sprintf(tmp, "true");
62 | }else{
63 | sprintf(tmp, "false");
64 | }
65 | copyToMem(&TIMEONY, tmp);
66 | }
67 |
68 | void PhyphoxBleExperiment::Graph::setSystemTime(bool b){
69 | char tmp[10];
70 | if(b){
71 | sprintf(tmp, "true");
72 | }else{
73 | sprintf(tmp, "false");
74 | }
75 | copyToMem(&SYSTEMTIME, tmp);
76 | }
77 |
78 | void PhyphoxBleExperiment::Graph::setChannel(int x, int y)
79 | {
80 | ERROR = ERROR.MESSAGE == NULL ? err_checkUpper(x, numberOfChannels, "setChannel") : ERROR;
81 | ERROR = ERROR.MESSAGE == NULL ? err_checkUpper(y, numberOfChannels, "setChannel") : ERROR;
82 |
83 | char tmpX[20];
84 | sprintf(tmpX, "CH%i", x);
85 | copyToMem(&FIRSTSUBGRAPH.INPUTX, tmpX);
86 | char tmpY[20];
87 | sprintf(tmpY, "CH%i", y);
88 | copyToMem(&FIRSTSUBGRAPH.INPUTY, tmpY);
89 | SUBGRAPHS[0]=&FIRSTSUBGRAPH;
90 | }
91 | void PhyphoxBleExperiment::Graph::addSubgraph(Subgraph& sg){
92 | for (int i = 0; i < phyphoxBleNChannel; i++){
93 | if(SUBGRAPHS[i]==nullptr){
94 | SUBGRAPHS[i] = &sg;
95 | if(ERROR.MESSAGE==NULL){
96 | ERROR = sg.ERROR;
97 | }
98 | break;
99 | }
100 | }
101 | }
102 |
103 | void PhyphoxBleExperiment::Graph::setStyle(const char *s){
104 | FIRSTSUBGRAPH.setStyle(s);
105 | }
106 |
107 | void PhyphoxBleExperiment::Graph::setMinX(float value, const char * layout) {
108 | /**
109 | * Sets the min x value for the co-system.
110 | *
111 | * @param value The min x value.
112 | * @param layout Choose between auto, extend and fixed.
113 | */
114 | std::string layoutString;
115 | layoutString.assign(layout);
116 | std::ostringstream valueStringStream;
117 | valueStringStream << value;
118 | if(strcmp(layout, LAYOUT_AUTO) == 0 || strcmp(layout, LAYOUT_EXTEND) == 0 || strcmp(layout, LAYOUT_FIXED) == 0) {
119 | copyToMem(&MINX, (" scaleMinX=\"" + layoutString + "\"" + " minX=\"" + valueStringStream.str() + "\"").c_str());
120 | } else {
121 | ERROR = ERROR.MESSAGE == NULL ? err_checkLayout(layout, "setMinX") : ERROR;
122 | }
123 | }
124 |
125 | void PhyphoxBleExperiment::Graph::setMaxX(float value, const char * layout) {
126 | /**
127 | * Sets the min x value for the co-system.
128 | *
129 | * @param value The max x value.
130 | * @param layout Choose between auto, extend and fixed.
131 | */
132 | std::string layoutString;
133 | layoutString.assign(layout);
134 | std::ostringstream valueStringStream;
135 | valueStringStream << value;
136 | if(strcmp(layout, "auto") == 0 || strcmp(layout, "extend") == 0 || strcmp(layout, "fixed") == 0) {
137 | copyToMem(&MAXX, (" scaleMaxX=\"" + layoutString + "\"" + " maxX=\"" + valueStringStream.str() + "\"").c_str());
138 | } else {
139 | ERROR = ERROR.MESSAGE == NULL ? err_checkLayout(layout, "setMaxX") : ERROR;
140 | }
141 | }
142 |
143 | void PhyphoxBleExperiment::Graph::setMinY(float value, const char * layout) {
144 | /**
145 | * Sets the min x value for the co-system.
146 | *
147 | * @param value The min y value.
148 | * @param layout Choose between auto, extend and fixed.
149 | */
150 | std::string layoutString;
151 | layoutString.assign(layout);
152 | std::ostringstream valueStringStream;
153 | valueStringStream << value;
154 | if(strcmp(layout, "auto") == 0 || strcmp(layout, "extend") == 0 || strcmp(layout, "fixed") == 0) {
155 | copyToMem(&MINY, (" scaleMinY=\"" + layoutString + "\"" + " minY=\"" + valueStringStream.str() + "\"").c_str());
156 | } else {
157 | ERROR = ERROR.MESSAGE == NULL ? err_checkLayout(layout, "setMinY") : ERROR;
158 | }
159 | }
160 | void PhyphoxBleExperiment::Graph::setMaxY(float value, const char * layout) {
161 | /**
162 | * Sets the min x value for the co-system.
163 | *
164 | * @param value The max y value.
165 | * @param layout Choose between auto, extend and fixed.
166 | */
167 | std::string layoutString;
168 | layoutString.assign(layout);
169 | std::ostringstream valueStringStream;
170 | valueStringStream << value;
171 | if(strcmp(layout, "auto") == 0 || strcmp(layout, "extend") == 0 || strcmp(layout, "fixed") == 0) {
172 | copyToMem(&MAXY, (" scaleMaxY=\"" + layoutString + "\"" + " maxY=\"" + valueStringStream.str() + "\"").c_str());
173 | } else {
174 | ERROR = ERROR.MESSAGE == NULL ? err_checkLayout(layout, "setMaxY") : ERROR;
175 | }
176 | }
177 |
178 | void PhyphoxBleExperiment::Graph::setXMLAttribute(const char *xml){
179 | ERROR = ERROR.MESSAGE == NULL ? err_checkLength(xml, 98, "setXMLAttribute") : ERROR;
180 | copyToMem(&XMLAttribute, (" " + std::string(xml)).c_str());
181 | }
182 |
183 | void PhyphoxBleExperiment::Graph::getBytes(char *buffArray)
184 | {
185 | strcat(buffArray,"\t\t");
251 |
252 | for(int i=0;igetBytes(buffArray);
255 | }
256 | }
257 |
258 | strcat(buffArray, "\n\t\t\n");
259 |
260 | }
--------------------------------------------------------------------------------
/src/phyphoxBleExperiment.h:
--------------------------------------------------------------------------------
1 | #ifndef PHYPHOX_BLE_EXPERIMENT
2 | #define PHYPHOX_BLE_EXPERIMENT
3 |
4 | #include
5 | #include "copyToMem.h"
6 | #include "defines.h"
7 | #include
8 |
9 | class PhyphoxBleExperiment {
10 |
11 | public:
12 |
13 | PhyphoxBleExperiment() = default;
14 | PhyphoxBleExperiment(const PhyphoxBleExperiment&) = delete;
15 | PhyphoxBleExperiment &operator=(const PhyphoxBleExperiment &) = delete;
16 | ~PhyphoxBleExperiment() = default;
17 |
18 | static uint16_t MTU;
19 |
20 | class Error {
21 | public:
22 | char* MESSAGE = NULL;
23 | void getBytes(char *);
24 | };
25 |
26 |
27 | class Errorhandler {
28 | public:
29 | virtual Error err_checkLength(const char *, int, const char *);
30 | virtual Error err_checkUpper(int, int, const char *);
31 | virtual Error err_checkHex(const char *, const char *);
32 | virtual Error err_checkStyle(const char *, const char *);
33 | virtual Error err_checkLayout(const char *, const char *);
34 | virtual Error err_checkComponent(const char *, const char *);
35 | virtual Error err_checkSensor(const char *, const char *);
36 | };
37 |
38 | class Element : public Errorhandler {
39 | public:
40 | Element() = default;
41 | Element(const Element &) = delete;
42 | Element &operator=(const Element &) = delete;
43 | ~Element() = default;
44 |
45 | int typeID = 0;
46 |
47 | char* LABEL = NULL;
48 |
49 | Error ERROR;
50 |
51 | virtual void setLabel(const char *);
52 | virtual void getBytes(char *)=0;
53 |
54 | private:
55 | };
56 |
57 |
58 |
59 | class Graph : public Element
60 | {
61 | public:
62 |
63 | class Subgraph : public Errorhandler
64 | {
65 | public:
66 | Subgraph() = default;
67 | Subgraph(const Subgraph &) = delete;
68 | Subgraph &operator=(const Subgraph &) = delete;
69 | ~Subgraph() = default;
70 |
71 | char* INPUTX = NULL;
72 | char* INPUTY = NULL;
73 | char* COLOR = NULL;
74 | char* WIDTH = NULL;
75 | char* STYLE = NULL;
76 | bool isActive = false;
77 |
78 | void setColor(const char *);
79 | void setStyle(const char *);
80 | void setLinewidth(float w);
81 | void setChannel(int, int);
82 | void getBytes(char *);
83 |
84 | Error ERROR;
85 | private:
86 | };
87 |
88 | Graph() = default;
89 | Graph(const Graph &) = delete;
90 | Graph &operator=(const Graph &) = delete;
91 | ~Graph() = default;
92 |
93 | char* UNITX = NULL;
94 | char* UNITY = NULL;
95 | char* LABELX = NULL;
96 | char* LABELY = NULL;
97 | char* XPRECISION = NULL;
98 | char* YPRECISION = NULL;
99 | char* MINX = NULL;
100 | char* MAXX = NULL;
101 | char* MINY = NULL;
102 | char* MAXY = NULL;
103 |
104 | char* TIMEONX = NULL;
105 | char* TIMEONY = NULL;
106 |
107 | char* SYSTEMTIME = NULL;
108 |
109 | char* INPUTX = NULL;
110 | char* INPUTY = NULL;
111 |
112 | Subgraph *SUBGRAPHS[phyphoxBleNChannel]={nullptr};
113 | Subgraph FIRSTSUBGRAPH;
114 |
115 | char* XMLAttribute = NULL;
116 |
117 | void setUnitX(const char *);
118 | void setUnitY(const char *);
119 | void setLabelX(const char *);
120 | void setLabelY(const char *);
121 | void setXPrecision(int);
122 | void setYPrecision(int);
123 | void setTimeOnX(bool);
124 | void setTimeOnY(bool);
125 | void setSystemTime(bool);
126 |
127 | void setChannel(int, int);
128 | void addSubgraph(Subgraph &);
129 | void addChannel(int, int, const char*);
130 | void setStyle(const char *);
131 | void setColor(const char *);
132 | void setLinewidth(float w);
133 | void setMinX(float, const char *);
134 | void setMaxX(float, const char *);
135 | void setMinY(float, const char *);
136 | void setMaxY(float, const char *);
137 | void setXMLAttribute(const char *);
138 |
139 | void phyphoxTimestamp();
140 | void getBytes(char *);
141 |
142 | private:
143 | };
144 |
145 | class View
146 | {
147 | public:
148 | View() = default;
149 | View(const View &) = delete;
150 | View &operator=(const View &) = delete;
151 | ~View() = default;
152 |
153 | void setLabel(const char *);
154 | void getBytes(char *, uint8_t);
155 | void addElement(Element &);
156 | void setXMLAttribute(const char *);
157 |
158 | char* LABEL = NULL;
159 | char* XMLAttribute = NULL;
160 |
161 | Element *ELEMENTS[phyphoxBleNElements] = {nullptr};
162 |
163 | private:
164 | };
165 |
166 | class ExportData : public Element
167 | {
168 | public:
169 | ExportData(){};
170 | ExportData(const ExportData &) = delete;
171 | ExportData &operator=(const ExportData &) = delete;
172 | ~ExportData() = default;
173 |
174 | char* BUFFER = NULL;
175 | char* LABEL = NULL;
176 | char* XMLAttribute = NULL;
177 | void setDatachannel(int);
178 | void setXMLAttribute(const char *);
179 | void setLabel(const char *);
180 | void getBytes(char *);
181 |
182 | private:
183 | };
184 |
185 | class ExportSet
186 | {
187 | public:
188 | ExportSet(){};
189 | ExportSet(const ExportSet &) = delete;
190 | ExportSet &operator=(const ExportSet &) = delete;
191 | ~ExportSet() = default;
192 |
193 | void setLabel(const char *);
194 | void getBytes(char *);
195 | void addElement(Element &);
196 | void setXMLAttribute(const char *);
197 |
198 | char* LABEL = NULL;
199 | char* XMLAttribute = NULL;
200 | Element *ELEMENTS[phyphoxBleNExportSets] = {nullptr};
201 |
202 | private:
203 | };
204 |
205 | class Sensor : public Errorhandler
206 | {
207 | public:
208 | Sensor(){};
209 | Sensor(const Sensor &) = delete;
210 | Sensor &operator=(const Sensor &) = delete;
211 | ~Sensor() = default;
212 |
213 | void setType(const char *);
214 | void setComponent(const char *);
215 | void setAverage(bool);
216 | void setRate(int);
217 | void mapChannel(const char *, int);
218 | void setXMLAttribute(const char *);
219 | void getBytes(char *);
220 |
221 | char* TYPE = NULL;
222 | char* CHANNEL[5] = {NULL};
223 | char* COMPONENT[5] = {NULL};
224 | char* RATE = NULL;
225 | char* AVERAGE = NULL;
226 | char* XMLAttribute = NULL;
227 |
228 | Error ERROR;
229 |
230 | private:
231 | };
232 |
233 | class InfoField : public Element
234 | {
235 | public:
236 | InfoField(){};
237 | InfoField(const InfoField &) = delete;
238 | InfoField &operator=(const InfoField &) = delete;
239 | ~InfoField() = default;
240 |
241 | void setInfo(const char *);
242 | void setColor(const char *);
243 | void setXMLAttribute(const char *);
244 | void getBytes(char *);
245 |
246 | char* INFO = NULL;
247 | char* COLOR = NULL;
248 | char* XMLAttribute = NULL;
249 |
250 | private:
251 | };
252 |
253 | class Separator : public Element
254 | {
255 | public:
256 | Separator(){};
257 | Separator(const Separator &) = delete;
258 | Separator &operator=(const Separator &) = delete;
259 | ~Separator() = default;
260 |
261 | void setHeight(float);
262 | void setColor(const char *);
263 | void setXMLAttribute(const char *);
264 | void getBytes(char *);
265 |
266 | char* COLOR = NULL;
267 | char* HEIGHT = NULL;
268 | char* XMLAttribute = NULL;
269 |
270 | private:
271 | };
272 |
273 | class Value : public Element
274 | {
275 | public:
276 | Value(){};
277 | Value(const Value &) = delete;
278 | Value &operator=(const Value &) = delete;
279 | ~Value() = default;
280 |
281 | void setPrecision(int);
282 | void setUnit(const char *);
283 | void setColor(const char *);
284 | void getBytes(char *);
285 | void setChannel(int);
286 | void setXMLAttribute(const char *);
287 |
288 | char* PRECISION = NULL;
289 | char* UNIT = NULL;
290 | char* COLOR = NULL;
291 | char* INPUTVALUE = NULL;
292 | char* XMLAttribute = NULL;
293 |
294 | private:
295 | };
296 |
297 | class Edit : public Element
298 | {
299 | public:
300 | Edit(){};
301 | Edit(const Edit &) = delete;
302 | Edit &operator=(const Edit &) = delete;
303 | ~Edit() = default;
304 |
305 | void setUnit(const char *);
306 | void setSigned(bool);
307 | void setDecimal(bool);
308 | void setXMLAttribute(const char *);
309 | void setChannel(int);
310 | void getBytes(char *);
311 |
312 | char* UNIT = NULL;
313 | char* SIGNED = NULL;
314 | char* DECIMAL = NULL;
315 | char* XMLAttribute = NULL;
316 | char* BUFFER = NULL;
317 |
318 | private:
319 | };
320 |
321 | void setTitle(const char *);
322 | void setCategory(const char *);
323 | void setDescription(const char *);
324 | void setColor(const char *);
325 | void setRepeating(const int);
326 | // void setConfig(const char *);
327 | void setSubscribeOnStart(bool);
328 |
329 | void getBytes(char *);
330 | void getFirstBytes(char *, const char *);
331 | void getViewBytes(char *, uint8_t, uint8_t);
332 | void getLastBytes(char *);
333 | void addView(View &);
334 | void addSensor(Sensor &);
335 | void addExportSet(ExportSet &);
336 |
337 | char* TITLE = NULL;
338 | char* CATEGORY = NULL;
339 | char* DESCRIPTION = NULL;
340 | char* COLOR = NULL;
341 | // char* CONFIG = NULL;
342 | char* SUBSCRIBEONSTART = NULL;
343 |
344 | View *VIEWS[phyphoxBleNViews] = {nullptr};
345 | Sensor *SENSORS[phyphoxBleNSensors] = {nullptr};
346 | ExportSet *EXPORTSETS[phyphoxBleNExportSets] = {nullptr};
347 |
348 | static int numberOfChannels;
349 | int repeating = 0;
350 |
351 |
352 | };
353 |
354 | #endif
355 |
--------------------------------------------------------------------------------
/src/boards/phyphoxBLE_NINAB31.cpp:
--------------------------------------------------------------------------------
1 | #if defined(ARDUINO_SAMD_MKR1000) || defined(ARDUINO_SENSEBOX_MCU_ESP32S2)
2 |
3 | #include "phyphoxBle.h"
4 | #include "NINAB31serial.h"
5 | #include "Arduino.h"
6 | #include
7 | /*
8 | BLEService PhyphoxBLE::phyphoxExperimentService{phyphoxBleExperimentServiceUUID}; // create service
9 | BLECharacteristic PhyphoxBLE::experimentCharacteristic{phyphoxBleExperimentCharacteristicUUID, BLERead | BLEWrite| BLENotify, 20, false};
10 | BLECharacteristic PhyphoxBLE::controlCharacteristic{phyphoxBleExperimentControlCharacteristicUUID, BLERead | BLEWrite| BLENotify, 20, false};
11 |
12 | BLEService PhyphoxBLE::phyphoxDataService{phyphoxBleDataServiceUUID}; // create service
13 | BLECharacteristic PhyphoxBLE::dataCharacteristic{phyphoxBleDataCharacteristicUUID, BLERead | BLEWrite | BLENotify, 20, false};
14 | BLECharacteristic PhyphoxBLE::configCharacteristic{phyphoxBleConfigCharacteristicUUID, BLERead | BLEWrite| BLENotify, 20, false};
15 | */
16 | uint16_t PhyphoxBLE::minConInterval = 12; //7.5ms
17 | uint16_t PhyphoxBLE::maxConInterval = 48; //30ms
18 | uint16_t PhyphoxBLE::slaveLatency = 0;
19 | uint16_t PhyphoxBLE::timeout = 50;
20 |
21 | uint16_t PhyphoxBLE::MTU = 20;
22 | uint16_t PhyphoxBleExperiment::MTU = 20;
23 |
24 | int PhyphoxBLE::h_phyphoxExperimentService=0;
25 | int PhyphoxBLE::h_experimentCharacteristic=0;
26 | int PhyphoxBLE::h_controlCharacteristic=0;
27 |
28 | int PhyphoxBLE::h_phyphoxDataService=0;
29 | int PhyphoxBLE::h_dataCharacteristic=0;
30 | int PhyphoxBLE::h_configCharacteristic=0;
31 |
32 | bool PhyphoxBLE::exploaded=false;
33 |
34 | uint8_t* PhyphoxBLE::data = nullptr; //this pointer points to the data the user wants to write in the characteristic
35 | uint8_t* PhyphoxBLE::p_exp = nullptr; //this pointer will point to the byte array which holds an experiment
36 |
37 | size_t PhyphoxBLE::expLen = 0; //try o avoid this maybe use std::array or std::vector
38 | uint8_t PhyphoxBLE::EXPARRAY[4000] = {0};// block some storage
39 |
40 | uint8_t PhyphoxBLE::controlCharValue[21]={0};
41 | uint8_t PhyphoxBLE::configCharValue[21]={0};
42 |
43 |
44 |
45 | void(*PhyphoxBLE::configHandler)() = nullptr;
46 |
47 | void PhyphoxBLE::start(const char* DEVICE_NAME, uint8_t* exp_pointer, size_t len){
48 | p_exp = exp_pointer;
49 | expLen = len;
50 | start(DEVICE_NAME);
51 | }
52 |
53 | void PhyphoxBLE::start(uint8_t* exp_pointer, size_t len){
54 | p_exp = exp_pointer;
55 | expLen = len;
56 | start();
57 | }
58 |
59 | void PhyphoxBLE::start(const char* DEVICE_NAME)
60 | {
61 | port.begin();
62 | port.stopAdvertise();
63 |
64 | port.checkResponse("AT+UBTAD=020A0605121800280011074A5153BA405E438B7146F7300100DFCD",1000);
65 | h_phyphoxExperimentService=port.parseResponse("AT+UBTGSER=CDDF000130F746718B435E40BA53514A",1000);
66 | h_controlCharacteristic=port.parseResponse("AT+UBTGCHA=CDDF000330F746718B435E40BA53514A,1a,1,1",1000);
67 | h_experimentCharacteristic=port.parseResponse("AT+UBTGCHA=CDDF000230F746718B435E40BA53514A,1a,1,1",1000);
68 |
69 | h_phyphoxDataService=port.parseResponse("AT+UBTGSER=CDDF100130F746718B435E40BA53514A",1000);
70 | h_dataCharacteristic=port.parseResponse("AT+UBTGCHA=CDDF100230F746718B435E40BA53514A,1a,1,1",1000);
71 | h_configCharacteristic=port.parseResponse("AT+UBTGCHA=CDDF100330F746718B435E40BA53514A,1a,1,1",1000);
72 |
73 |
74 |
75 | if(p_exp == nullptr){
76 |
77 | PhyphoxBleExperiment defaultExperiment;
78 |
79 | //View
80 | PhyphoxBleExperiment::View firstView;
81 |
82 | //Graph
83 | PhyphoxBleExperiment::Graph firstGraph; //Create graph which will plot random numbers over time
84 | firstGraph.setChannel(0,1);
85 |
86 | firstView.addElement(firstGraph);
87 | defaultExperiment.addView(firstView);
88 |
89 | addExperiment(defaultExperiment);
90 | }
91 |
92 |
93 |
94 |
95 | // set connection parameter
96 | port.setConnectionInterval(minConInterval, maxConInterval);
97 | port.checkResponse("AT+UBTAD=020A0605121800280011074A5153BA405E438B7146F7300100DFCD",1000);
98 | port.advertise();
99 | port.setLocalName(DEVICE_NAME);
100 |
101 | }
102 |
103 | void PhyphoxBLE::start() {
104 | PhyphoxBLE::start("phyphox-senseBox");
105 | }
106 |
107 |
108 | void PhyphoxBLE::poll(int timeout)
109 | {
110 | auto starttime=millis();
111 | while(millis()-starttime(&value);
163 | port.writeValue(h_dataCharacteristic,data,4);
164 | }
165 |
166 |
167 | void PhyphoxBLE::write(float& f1, float& f2)
168 | {
169 | if(!exploaded){
170 | return;
171 | }
172 | float array[2] = {f1, f2};
173 | data = reinterpret_cast(array);
174 | port.writeValue(h_dataCharacteristic,data,8);
175 | }
176 |
177 | void PhyphoxBLE::write(float& f1, float& f2, float& f3)
178 | {
179 | if(!exploaded){
180 | return;
181 | }
182 | float array[3] = {f1, f2, f3};
183 | data = reinterpret_cast(array);
184 | port.writeValue(h_dataCharacteristic,data,12);
185 | }
186 |
187 | void PhyphoxBLE::write(float& f1, float& f2, float& f3 , float& f4)
188 | {
189 | if(!exploaded){
190 | return;
191 | }
192 | float array[4] = {f1, f2, f3, f4};
193 | data = reinterpret_cast(array);
194 | port.writeValue(h_dataCharacteristic,data,16);
195 | }
196 |
197 | void PhyphoxBLE::write(float& f1, float& f2, float& f3 , float& f4, float& f5)
198 | {
199 | if(!exploaded){
200 | return;
201 | }
202 | float array[5] = {f1, f2, f3, f4, f5};
203 | data = reinterpret_cast(array);
204 | port.writeValue(h_dataCharacteristic,data,20);
205 | }
206 |
207 |
208 | bool parseValue(uint8_t* target, String s){
209 | String hextable="0123456789ABCDEF";
210 | if(s.length() && s.length()<41){
211 | s.toUpperCase();
212 | for(int i=0;i> 24);
268 | experimentSizeArray[1]= (arrayLength >> 16);
269 | experimentSizeArray[2]= (arrayLength >> 8);
270 | experimentSizeArray[3]= arrayLength;
271 |
272 | uint8_t checksumArray[4] = {0};
273 | checksumArray[0]= (checksum >> 24) & 0xFF;
274 | checksumArray[1]= (checksum >> 16) & 0xFF;
275 | checksumArray[2]= (checksum >> 8) & 0xFF;
276 | checksumArray[3]= checksum & 0xFF;
277 |
278 | memcpy(&header[0],&phyphox[0],7);
279 | memcpy(&header[0]+7,&experimentSizeArray[0],4);
280 | memcpy(&header[0]+7+4,&checksumArray[0],4);
281 | port.writeValue(h_experimentCharacteristic,header,sizeof(header));
282 |
283 | for(size_t i = 0; i < exp_len/20; ++i){
284 | memcpy(&header[0],&exp[0]+i*20,20);
285 | port.writeValue(h_experimentCharacteristic,header,sizeof(header));
286 | delay(5);
287 | }
288 |
289 | if(exp_len%20 != 0){
290 | const size_t rest = exp_len%20;
291 | uint8_t slice[rest];
292 | memcpy(&slice[0],&exp[0]+exp_len-rest,rest);
293 | port.writeValue(h_experimentCharacteristic,slice,sizeof(slice));
294 | }
295 | exploaded=true;
296 |
297 | port.advertise();
298 | }
299 |
300 | void PhyphoxBLE::configCharacteristicWritten(){
301 | if(configHandler!=nullptr){
302 | (*configHandler)();
303 | }
304 | }
305 | #endif
306 |
--------------------------------------------------------------------------------
/src/boards/phyphoxBLE_NanoIOT.cpp:
--------------------------------------------------------------------------------
1 | #if defined(ARDUINO_SAMD_NANO_33_IOT) || defined(ARDUINO_UNOR4_WIFI) || defined(ARDUINO_SAMD_MKRWIFI1010)
2 |
3 | #include "phyphoxBLE_NanoIOT.h"
4 | #include "Arduino.h"
5 | #include
6 |
7 | BLEService PhyphoxBLE::phyphoxExperimentService{phyphoxBleExperimentServiceUUID}; // create service
8 | BLECharacteristic PhyphoxBLE::experimentCharacteristic{phyphoxBleExperimentCharacteristicUUID, BLERead | BLEWrite| BLENotify, 20, false};
9 | BLECharacteristic PhyphoxBLE::controlCharacteristic{phyphoxBleExperimentControlCharacteristicUUID, BLERead | BLEWrite| BLENotify, 20, false};
10 | BLECharacteristic PhyphoxBLE::eventCharacteristic{phyphoxBleEventCharacteristicUUID, BLERead | BLEWrite| BLENotify, 20, false};
11 |
12 | BLEService PhyphoxBLE::phyphoxDataService{phyphoxBleDataServiceUUID}; // create service
13 | BLECharacteristic PhyphoxBLE::dataCharacteristic{phyphoxBleDataCharacteristicUUID, BLERead | BLEWrite | BLENotify, 20, false};
14 | BLECharacteristic PhyphoxBLE::configCharacteristic{phyphoxBleConfigCharacteristicUUID, BLERead | BLEWrite| BLENotify, 20, false};
15 |
16 | uint16_t PhyphoxBLE::minConInterval = 6; //7.5ms
17 | uint16_t PhyphoxBLE::maxConInterval = 24; //30ms
18 | uint16_t PhyphoxBLE::slaveLatency = 0;
19 | uint16_t PhyphoxBLE::timeout = 50;
20 |
21 | uint16_t PhyphoxBLE::MTU = 20;
22 | uint16_t PhyphoxBleExperiment::MTU = 20;
23 |
24 | int64_t PhyphoxBLE::experimentTime = NULL;
25 | int64_t PhyphoxBLE::systemTime = NULL;
26 | uint8_t PhyphoxBLE::eventType = NULL;
27 |
28 | uint8_t* PhyphoxBLE::data = nullptr; //this pointer points to the data the user wants to write in the characteristic
29 | uint8_t* PhyphoxBLE::p_exp = nullptr; //this pointer will point to the byte array which holds an experiment
30 |
31 | size_t PhyphoxBLE::expLen = 0; //try o avoid this maybe use std::array or std::vector
32 | const int maxExperimentSize = 6000;
33 | uint8_t storage[maxExperimentSize];
34 | uint8_t PhyphoxBLE::eventData[17]={0};
35 | //uint8_t eventData[17];
36 | char *PhyphoxBLE::EXPARRAY=(char*)storage;
37 |
38 | void(*PhyphoxBLE::configHandler)() = nullptr;
39 | void(*PhyphoxBLE::experimentEventHandler)() = nullptr;
40 |
41 | void PhyphoxBLE::start(const char* DEVICE_NAME, uint8_t* exp_pointer, size_t len){
42 | p_exp = exp_pointer;
43 | expLen = len;
44 | start(DEVICE_NAME);
45 | }
46 |
47 | void PhyphoxBLE::start(uint8_t* exp_pointer, size_t len){
48 | p_exp = exp_pointer;
49 | expLen = len;
50 | start();
51 | }
52 |
53 | void PhyphoxBLE::start(const char* DEVICE_NAME)
54 | {
55 | deviceName = DEVICE_NAME;
56 |
57 | controlCharacteristic.setEventHandler(BLEWritten, controlCharacteristicWritten);
58 | eventCharacteristic.setEventHandler(BLEWritten, eventCharacteristicWritten);
59 | configCharacteristic.setEventHandler(BLEWritten, configCharacteristicWritten);
60 |
61 | if(p_exp == nullptr){
62 |
63 | PhyphoxBleExperiment defaultExperiment;
64 |
65 | //View
66 | PhyphoxBleExperiment::View firstView;
67 |
68 | //Graph
69 | PhyphoxBleExperiment::Graph firstGraph; //Create graph which will plot random numbers over time
70 | firstGraph.setChannel(0,1);
71 |
72 | firstView.addElement(firstGraph);
73 | defaultExperiment.addView(firstView);
74 |
75 | addExperiment(defaultExperiment);
76 | }
77 |
78 |
79 | BLE.begin();
80 | BLE.setLocalName(DEVICE_NAME);
81 | BLE.setAdvertisedService(phyphoxExperimentService);
82 | //BLE.setAdvertisedService(phyphoxDataService);
83 |
84 | // add the characteristics to the service
85 | phyphoxExperimentService.addCharacteristic(experimentCharacteristic);
86 | phyphoxExperimentService.addCharacteristic(controlCharacteristic);
87 | phyphoxExperimentService.addCharacteristic(eventCharacteristic);
88 | phyphoxDataService.addCharacteristic(configCharacteristic);
89 | phyphoxDataService.addCharacteristic(dataCharacteristic);
90 |
91 | // add the service
92 | BLE.addService(phyphoxExperimentService);
93 | BLE.addService(phyphoxDataService);
94 |
95 | // set connection parameter
96 | BLE.setConnectionInterval(minConInterval, maxConInterval);
97 |
98 | // start advertising
99 | BLE.advertise();
100 |
101 | }
102 |
103 | void PhyphoxBLE::start() {
104 | PhyphoxBLE::start("phyphox-Arduino");
105 | }
106 |
107 | void PhyphoxBLE::poll()
108 | {
109 | BLE.poll();
110 | }
111 |
112 | void PhyphoxBLE::poll(int timeout)
113 | {
114 | BLE.poll(timeout);
115 | }
116 |
117 | void PhyphoxBLE::read(uint8_t *arrayPointer, unsigned int arraySize)
118 | {
119 | configCharacteristic.readValue(arrayPointer, arraySize);
120 | }
121 |
122 | void PhyphoxBLE::read(float& f)
123 | {
124 | uint8_t readDATA[4];
125 | configCharacteristic.readValue(readDATA, 4);
126 | memcpy(&f,&readDATA[0],4);
127 | }
128 |
129 | void PhyphoxBLE::read(float& f1, float& f2)
130 | {
131 | uint8_t readDATA[8];
132 | configCharacteristic.readValue(readDATA, 8);
133 | memcpy(&f1,readDATA,4);
134 | memcpy(&f2,readDATA+4,4);
135 | }
136 | void PhyphoxBLE::read(float& f1, float& f2, float& f3)
137 | {
138 | uint8_t readDATA[12];
139 | configCharacteristic.readValue(readDATA, 12);
140 | memcpy(&f1,readDATA,4);
141 | memcpy(&f2,readDATA+4,4);
142 | memcpy(&f3,readDATA+8,4);
143 | }
144 | void PhyphoxBLE::read(float& f1, float& f2, float& f3, float& f4)
145 | {
146 | uint8_t readDATA[16];
147 | configCharacteristic.readValue(readDATA, 16);
148 | memcpy(&f1,readDATA,4);
149 | memcpy(&f2,readDATA+4,4);
150 | memcpy(&f3,readDATA+8,4);
151 | memcpy(&f4,readDATA+12,4);
152 | }
153 | void PhyphoxBLE::read(float& f1, float& f2, float& f3, float& f4, float& f5)
154 | {
155 | uint8_t readDATA[20];
156 | configCharacteristic.readValue(readDATA, 20);
157 | memcpy(&f1,readDATA,4);
158 | memcpy(&f2,readDATA+4,4);
159 | memcpy(&f3,readDATA+8,4);
160 | memcpy(&f4,readDATA+12,4);
161 | memcpy(&f5,readDATA+16,4);
162 | }
163 |
164 | void PhyphoxBLE::addExperiment(PhyphoxBleExperiment& exp)
165 | {
166 | memset(EXPARRAY,0,maxExperimentSize);
167 |
168 | exp.getFirstBytes(EXPARRAY, deviceName);
169 |
170 |
171 | for(uint8_t i=0;i(&value);
188 | dataCharacteristic.writeValue(data,4);
189 | }
190 |
191 |
192 | void PhyphoxBLE::write(float& f1, float& f2)
193 | {
194 | float array[2] = {f1, f2};
195 | data = reinterpret_cast(array);
196 | dataCharacteristic.writeValue(data,8);
197 | }
198 |
199 | void PhyphoxBLE::write(float& f1, float& f2, float& f3)
200 | {
201 | float array[3] = {f1, f2, f3};
202 | data = reinterpret_cast(array);
203 | dataCharacteristic.writeValue(data,12);
204 | }
205 |
206 | void PhyphoxBLE::write(float& f1, float& f2, float& f3 , float& f4)
207 | {
208 | float array[4] = {f1, f2, f3, f4};
209 | data = reinterpret_cast(array);
210 | dataCharacteristic.writeValue(data,16);
211 | }
212 |
213 | void PhyphoxBLE::write(float& f1, float& f2, float& f3 , float& f4, float& f5)
214 | {
215 | float array[5] = {f1, f2, f3, f4, f5};
216 | data = reinterpret_cast(array);
217 | dataCharacteristic.writeValue(data,20);
218 | }
219 |
220 | void PhyphoxBLE::controlCharacteristicWritten(BLEDevice central, BLECharacteristic characteristic) {
221 | byte value = 0;
222 | characteristic.readValue(value);
223 | if (value & 0x01) {
224 | //sendexperiment
225 | transferExperiment();
226 | } else {
227 | //experiment transfered
228 | }
229 |
230 | }
231 |
232 | void PhyphoxBLE::transferExperiment(){
233 |
234 | BLE.stopAdvertise();
235 |
236 | uint8_t* exp = p_exp;
237 | size_t exp_len = expLen;
238 |
239 | uint8_t header[20] = {0}; //20 byte as standard package size for ble transfer
240 | const char phyphox[] = "phyphox";
241 | uint32_t table[256];
242 | phyphoxBleCrc32::generate_table(table);
243 | uint32_t checksum = phyphoxBleCrc32::update(table, 0, exp, exp_len);
244 | size_t arrayLength = exp_len;
245 | uint8_t experimentSizeArray[4] = {0};
246 | experimentSizeArray[0]= (arrayLength >> 24);
247 | experimentSizeArray[1]= (arrayLength >> 16);
248 | experimentSizeArray[2]= (arrayLength >> 8);
249 | experimentSizeArray[3]= arrayLength;
250 |
251 | uint8_t checksumArray[4] = {0};
252 | checksumArray[0]= (checksum >> 24) & 0xFF;
253 | checksumArray[1]= (checksum >> 16) & 0xFF;
254 | checksumArray[2]= (checksum >> 8) & 0xFF;
255 | checksumArray[3]= checksum & 0xFF;
256 |
257 | memcpy(&header[0],&phyphox[0],7);
258 | memcpy(&header[0]+7,&experimentSizeArray[0],4);
259 | memcpy(&header[0]+7+4,&checksumArray[0],4);
260 | experimentCharacteristic.writeValue(header,sizeof(header));
261 |
262 | for(size_t i = 0; i < exp_len/20; ++i){
263 | memcpy(&header[0],&exp[0]+i*20,20);
264 | experimentCharacteristic.writeValue(header,sizeof(header));
265 | delay(5);
266 | }
267 |
268 | if(exp_len%20 != 0){
269 | const size_t rest = exp_len%20;
270 | uint8_t slice[rest];
271 | memcpy(&slice[0],&exp[0]+exp_len-rest,rest);
272 | experimentCharacteristic.writeValue(slice,sizeof(slice));
273 |
274 | delay(5);
275 | }
276 |
277 | BLE.advertise();
278 | }
279 |
280 | void PhyphoxBLE::configCharacteristicWritten(BLEDevice central, BLECharacteristic characteristic){
281 | if(configHandler!=nullptr){
282 | (*configHandler)();
283 | }
284 | }
285 |
286 | void PhyphoxBLE::eventCharacteristicWritten(BLEDevice central, BLECharacteristic characteristic){
287 |
288 | uint8_t read_buffer[17];
289 | eventCharacteristic.readValue(read_buffer, 17);
290 |
291 |
292 | memcpy(&eventData[0],read_buffer,17);
293 | int64_t et,st;
294 | memcpy(&et,&eventData[0]+1,8);
295 | memcpy(&st,&eventData[0]+1+8,8);
296 | PhyphoxBLE::eventType = eventData[0];
297 | PhyphoxBLE::systemTime = swap_int64(st);
298 | PhyphoxBLE::experimentTime = swap_int64(et);
299 |
300 | if(experimentEventHandler!=nullptr){
301 | (*experimentEventHandler)();
302 | }
303 | }
304 |
305 | void PhyphoxBLE::printXML(HardwareSerial* printer){
306 | printer->println("");
307 | for(int i =0; iprint(CHAR);
310 | }
311 | printer->println("");
312 | }
313 | #endif
314 |
--------------------------------------------------------------------------------
/src/experiment.cpp:
--------------------------------------------------------------------------------
1 | #include "phyphoxBleExperiment.h"
2 | #include "copyToMem.h"
3 | #include "phyphoxBle.h"
4 |
5 | int PhyphoxBleExperiment::numberOfChannels = 5;
6 |
7 |
8 | void PhyphoxBleExperiment::addView(View& v)
9 | {
10 | for(int i=0; isetLabel("SENSOR RAW DATA");
29 | VIEWS[phyphoxBleNViews-1] = RawDataSmartoneSensor;
30 | InfoField* SensorType = new InfoField();
31 | SensorType->INFO = s.TYPE;
32 | for (int j = 0; j < phyphoxBleNElements; j++){
33 | if(VIEWS[phyphoxBleNViews-1]->ELEMENTS[j]==nullptr){
34 | VIEWS[phyphoxBleNViews-1]->ELEMENTS[j] = SensorType;
35 | break;
36 | }
37 | }
38 |
39 | }
40 |
41 | for(int mappedCH = 0; mappedCH<5; mappedCH++){
42 | if( s.CHANNEL[mappedCH]!=nullptr){
43 | for (int j = 0; j < phyphoxBleNElements; j++){
44 | if(VIEWS[phyphoxBleNViews-1]->ELEMENTS[j]==nullptr){
45 | PhyphoxBleExperiment::Value* newValueField = new Value();
46 | newValueField->INPUTVALUE = s.CHANNEL[mappedCH];
47 | newValueField->LABEL = s.COMPONENT[mappedCH];
48 | VIEWS[phyphoxBleNViews-1]->ELEMENTS[j]=newValueField;
49 | break;
50 | }
51 | }
52 | }
53 | }
54 |
55 | break;
56 | }
57 | }
58 | }
59 |
60 | void PhyphoxBleExperiment::setTitle(const char *t){
61 | copyToMem(&TITLE, t);
62 | }
63 |
64 | void PhyphoxBleExperiment::setCategory(const char *c){
65 | copyToMem(&CATEGORY, c);
66 | }
67 |
68 | void PhyphoxBleExperiment::setDescription(const char *d){
69 | copyToMem(&DESCRIPTION, d);
70 | }
71 |
72 | void PhyphoxBleExperiment::setColor(const char *c){
73 | copyToMem(&COLOR, (std::string(c)).c_str());
74 | }
75 |
76 | void PhyphoxBleExperiment::setRepeating(const int r){
77 | PhyphoxBleExperiment::repeating = r;
78 | }
79 | void PhyphoxBleExperiment::setSubscribeOnStart(bool b) {
80 | if(b) copyToMem(&SUBSCRIBEONSTART, "true");
81 | else copyToMem(&SUBSCRIBEONSTART, "false");
82 | }
83 |
84 | // void PhyphoxBleExperiment::setConfig(const char *c){
85 | // copyToMem(&CONFIG, c);
86 | // }
87 |
88 | void PhyphoxBleExperiment::addExportSet(ExportSet& e)
89 | {
90 | for(int i=0; i\n");
105 | //build title
106 | strcat(buffArray,"");
107 | if (!TITLE) {strcat(buffArray,"Arduino-Experiment");} else {strcat(buffArray,TITLE);}
108 | strcat(buffArray,"\n");
109 |
110 | //build category
111 | strcat(buffArray, "");
112 | if (!CATEGORY) {strcat(buffArray,"Arduino Experiments");} else {strcat(buffArray,CATEGORY);}
113 | strcat(buffArray, "\n");
114 |
115 | //build color
116 | /*
117 | if (!COLOR){
118 | strcat(buffArray, "");
119 | strcat(buffArray,COLOR);
120 | strcat(buffArray, "\n");
121 | }
122 | */
123 |
124 | //build description
125 | strcat(buffArray, "");
126 | if (!DESCRIPTION) {
127 | strcat(buffArray,"An experiment created with the phyphox BLE library for Arduino-compatible micro controllers.");
128 | }else {
129 | strcat(buffArray,DESCRIPTION);
130 | }
131 | strcat(buffArray, "\n");
132 |
133 | //build container
134 | strcat(buffArray, "\n");
135 | strcat(buffArray, "\tCH0\n");
136 | strcat(buffArray, "\tCB1\n");
137 | strcat(buffArray, "\tCB2\n");
138 | strcat(buffArray, "\tCB3\n");
139 | strcat(buffArray, "\tCB4\n");
140 | strcat(buffArray, "\tCB5\n");
141 |
142 | for(int i=0; iCH");
144 | char add[20];
145 | sprintf(add, "%i", i+1);
146 | strcat(buffArray, add);
147 | strcat(buffArray, "\n");
148 | }
149 | strcat(buffArray, "\n");
150 |
151 | //build input
152 | strcat(buffArray, "\n");
153 | strcat(buffArray, "\t\n\t\t");
164 |
165 |
166 |
167 |
168 | //build config
169 | //strcat(buffArray,"\t\t");
170 | // if (!CONFIG) {strcat(buffArray,"000000");} else {strcat(buffArray,CONFIG);}
171 | //strcat(buffArray,"\n\t\t");
172 |
173 |
174 | if(repeating <= 0){
175 | for(int i=1; i<=numberOfChannels;i++){
176 | strcat(buffArray, "\t\t\n");
182 | }
183 | }else{
184 | for(int i=1; i<=numberOfChannels;i++){
185 | strcat(buffArray, "\n\t\t");
191 | }
192 | }
193 |
194 | strcat(buffArray,"");
195 |
196 | strcat(buffArray, "\n\t\n");
197 | //build sensor input
198 |
199 | for (int i = 0; i < phyphoxBleNSensors; i++)
200 | {
201 | if(SENSORS[i] != nullptr){
202 | //strcat(buffArray, "\n\t\tCB1");
203 | SENSORS[i]->getBytes(buffArray);
204 | }
205 | }
206 | strcat(buffArray, "\n");
207 |
208 |
209 | //build output
210 | strcat(buffArray, "\n");
231 |
232 | //build analysis
233 | strcat(buffArray, "\n");
234 |
235 | //build views
236 | strcat(buffArray, "\n");
237 |
238 | //errorhandling
239 | for(int i=0;iELEMENTS[j]!=nullptr){
243 | if(VIEWS[i]->ELEMENTS[j]->ERROR.MESSAGE != NULL) {
244 | if(errors == 0) {
245 | strcat(buffArray, "\t \n");
246 | }
247 | VIEWS[i]->ELEMENTS[j]->ERROR.getBytes(buffArray);
248 | errors++;
249 | }
250 | }
251 | }
252 | }
253 | }
254 |
255 | for(int i=0; iERROR.MESSAGE !=NULL){
257 | if(errors == 0){
258 | strcat(buffArray, "\t \n");
259 | }
260 | SENSORS[i]->ERROR.getBytes(buffArray);
261 | errors++;
262 | }
263 | }
264 |
265 | if(errors>0) {
266 | strcat(buffArray,"\t\t\n");
267 | //strcat(buffArray,"\" color=\"ff0000\">\n");
268 | strcat(buffArray,"\t\t\n");
269 | strcat(buffArray,"\t\t\n");
270 | //strcat(buffArray,"\" color=\"ff0000\">\n");
271 | strcat(buffArray,"\t\t\n");
272 | strcat(buffArray,"\t\n");
273 | }
274 | }
275 |
276 | void PhyphoxBleExperiment::getViewBytes(char *buffArray, uint8_t view, uint8_t element){
277 |
278 | if(VIEWS[view]!=nullptr && viewgetBytes(buffArray,element);
280 | }
281 |
282 | }
283 |
284 | void PhyphoxBleExperiment::getLastBytes(char *buffArray){
285 | bool noExports = true;
286 |
287 | strcat(buffArray,"\n");
288 |
289 | //build export
290 | strcat(buffArray, "\n");
291 | for(int i=0;igetBytes(buffArray);
294 | noExports = false;
295 | }
296 | }
297 | if(noExports) {
298 | strcat(buffArray,"\t\n");
299 |
300 | for(int i=0;iCH%i", i,i);
304 | strcat(buffArray, add);
305 | strcat(buffArray,"\n");
306 | }
307 | strcat(buffArray,"\t\n");
308 | }
309 | strcat(buffArray, "\n");
310 |
311 | //close
312 | strcat(buffArray, "");
313 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # phyphox Arduino BLE
2 | Use phyphox to plot sensor data from your Microcontroller.
3 |
4 | The purpose of this library is to use the phyphox app (see www.phyphox.org) to plot sensor data on your phone with the open source app phyphox. In the other direction you can also use this library to access sensor data from your phone to use in your [Arduino](https://www.arduino.cc/) or ESP32 project.
5 |
6 | ## Supported boards
7 | - Arduino Nano 33 Ble
8 | - Arduino Nano Sense
9 | - Arduino Nano 33 IoT (see note below)
10 | - Arduino Uno R4 Wifi (see note below)
11 | - Arduino MKR WiFi 1010
12 | - senseBox MCU with NINA-B31 module
13 | - ESP 32
14 | - STM32 (e.g. STM32WB55)
15 |
16 | 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.
17 |
18 | Note: When using the NINA-B31 module you must call PhyphoxBLE::poll() periodically (in loop() ) or the library will not work.
19 | The same applies to STM32
20 |
21 | Note: to use STM32 BLE, you need the STM32duinoBLE library, and (at least for the STM32WBx5) the appropriate BLE stack (see Copro binaries)
22 |
23 | ## Concept of phyphox
24 |
25 | Phyphox is an open source app that has been developed at the RWTH Aachen University. It is available on Android and iOS and primarily aims at making the phone's sensors available for physics experiments. However, the app is based on a very flexible file format that defines data sources, visualizations (i.e. values and graphs) and data analysis (from simple formulas to Fourier transforms). This file format also allows to define Bluetooth Low Energy devices to exchange data from and to.
26 |
27 | This library generates an experiment configuration in this file format and allows phyphox to conenct to your microcontroller. It directly transfers the configuration (including graph configurations, axis labels, etc.) to phyphox and provides function to submit data to be plotted in phyphox or receive sensor data.
28 |
29 | ## Installation
30 |
31 | You should be able to find this library in the library search of your Arduino IDE. There you should usually find the latest release from here, which has been tagged with a version number.
32 |
33 | Alternatively, you can download this repository here as a zip file from github and install it with via the Arduino IDE's menu using the "Add ZIP library" entry. We recommend using the Arduino library manager, but directly installing a version from here might be relevant to try a specific branch or new feature.
34 |
35 | You will may also need to install an BLE library specific to your board:
36 | - ArduinoBLE for the Arduino Nano 33 IoT
37 | - STM32duinoBLE for an STM32
38 |
39 | ## Usage
40 |
41 | The easiest way to learn how to use this library is by looking at the examples in the `examples` folder. In most cases, you can simply connect to your Arduino running this library by scanning for Bluetooth devices via the "+"-button on the main screen of phyphox.
42 |
43 | ### randomNumbers.ino
44 |
45 | This is our minimal example. It submits random numbers to phyphox. All you need to do to submit a value to phyphox is including this library, starting the server (i.e. in `setup()`) and writing your data to the server.
46 |
47 | ```arduino
48 | #include
49 |
50 | void setup() {
51 | PhyphoxBLE::start(); //Start the BLE server
52 | }
53 |
54 | void loop() {
55 | //uncomment next line if using senseBox MCU or Arduino Nano 33 IoT
56 | //PhyphoxBLE::poll();
57 | float randomNumber = random(0,100); //Generate random number in the range 0 to 100
58 | PhyphoxBLE::write(randomNumber); //Send value to phyphox
59 | delay(50); //Shortly pause before repeating
60 | }
61 | ```
62 |
63 | ### CreateExperiment.ino
64 |
65 | This example shows how you can set a title, category and description as well as how to define graphs and setting axis labels and units. You can define one or multiple views (shown as tabs in phyphox), each of which can hold one or more graphs.
66 |
67 | For each graph you need to call `setChannel(x, y)` with x and y being an index of your data set. This index corresponds to the order of the values that you transfer in a call to `server.write` while the index `0` is special and corresponds to the timestamp at which phyphox receives the value. At the moment `server.write` supports up to five values.
68 |
69 | For example, let's assume you have the float values `foo` and `bar`. You can then call server.write(foo, bar) to send a set with both values. If you call `setChannel(0,1)`, your graph would plot `foo` on the y axis over time on the x axis. If you call `setChannel(2,1)`, your graph would plot `foo` on the y axis and `bar` on the x axis.
70 |
71 | Here are some useful methods to create your own experiment:
72 |
73 | | Target | Method | Explanation |
74 | | ---------- | ------------------------ | ----------------------------------------------------------------- |
75 | | Experiment | setTitle(char*) | Sets a title for the experiment |
76 | | Experiment | setCategory(char*) | Sets a category for the experiment |
77 | | Experiment | setDescription(char*) | Sets a description for the experiment |
78 | | Experiment | addView(View&) | Adds a view to the corresponding experiment |
79 | | Experiment | addExportSet(ExportSet&) | Adds an exportSet to the corresponding experiment |
80 | | Experiment | addSensor(Sensor&) | Data from smarpthone sensor can will be received (see getSensorDataFromSmartphone example)|
81 | | View | addElement(Element&) | Adds an element to the corresponding view |
82 | | View | setLabel(char*) | Sets a label for the view |
83 | | Graph | setLabel(char*) | Sets a label for the graph |
84 | | Graph | setUnitX(char*) | Sets the unit for x (similar with y) |
85 | | Graph | setLabelX(char*) | Sets a label for x (similar with y) |
86 | | Graph | setXPrecision(int) | Sets the amount of digits after the decimal point (similar with y)|
87 | | Graph | setChannel(int, int) | As explained above (1-5) |
88 | | Graph | addSubgraph(Subgraph) | Adds an additional subgraph (see example "multigraph") |
89 | | Graph | setStyle(char*) | Sets the style (use defines: STYLE_LINES, STYLE_DOTS). |
90 | | Graph | setColor(char*) | Sets the line color of the graph (use a 6 digit hexadecimal code) |
91 | | Graph | setMinX(int, const char *)| Sets the min x value of the co-system and a layout (auto, extend and fixed) |
92 | | Graph | setMaxX(int, const char *)| Sets the max x value of the co-system and a layout (auto, extend and fixed) |
93 | | Graph | setMinY(int, const char *)| Sets the min y value of the co-system and a layout (auto, extend and fixed) |
94 | | Graph | setMaxY(int, const char *)| Sets the max y value of the co-system and a layout (auto, extend and fixed) |
95 | | Graph | setLineWidth(float) | Sets the line width |
96 | | Separator | setHeight(float) | Creates a line to separate parts of the experiment |
97 | | Separator | setColor(char*) | Sets the color of the line (use a 6 digit hexadecimal code) |
98 | | Info | setInfo(char*) | Sets the infotext |
99 | | Info | setColor(char*) | Sets the font color (use a 6 digit hexadecimal code) |
100 | | Value | setLabel(char*) | Sets a label for the displayed value |
101 | | Value | setPrecision(int) | Sets the amount of digits after the decimal point |
102 | | Value | setUnit(char*) | Sets a unit for the displayed value |
103 | | Value | setColor(char*) | Sets the font color (use a 6 digit hexadecimal code) |
104 | | Value | setChannel(int) | As explained above, just with one parameter (1-5) |
105 | | Edit | setLabel(char*) | Sets label for the editfield |
106 | | Edit | setUnit(char*) | Sets unit |
107 | | Edit | setSigned(bool) | true = signed values allowed |
108 | | Edit | setDecimal(bool) | true = decimal values allowed |
109 | | Edit | setChannel(int) | As explained above, just with one parameter (1-5) |
110 | | ExportSet | setLabel(char*) | Sets a label for the exportSet (Used to export to Excel, etc.) |
111 | | ExportData | setLabel(char*) | Sets a label for the exportData |
112 | | ExportData | setDatachannel(int) | Defines which channel should be exported for this dataset (1-5) |
113 | | Everything | setXMLAttribute(char*) | Custom property e.g. setXMLAttribute("lineWidth=\"3\"") |
114 |
115 |
116 | #### Style and Layout oprtions for setStyle and setMax/setMin
117 | STYLE_LINES, STYLE_DOTS, STYLE_VBARS, STYLE_HBARS, STYLE_MAP
118 |
119 | LAYOUT_AUTO, LAYOUT_EXTEND, LAYOUT_FIXED
120 |
121 | #### Error messages
122 |
123 | If for some reason the app shows you an error in form of "ERROR FOUND: ERR_X", with different values for X, this could be the reason:
124 | * ERR_01: The input was too long.
125 | * ERR_02: The value exceeds the upper limit.
126 | * ERR_03: The input was not a 6-digit hexadecimal code.
127 | * ERR_04: The input does not match with a valid value.
128 | * ERR_05: The layout must be auto, extend or fixed.
129 |
130 | If you realize that the microcontroller is continiously rebooting, you maybe added too many elements.
131 |
132 | ### getDataFromSmartphone.ino
133 |
134 | The phyphox file format is much more powerful than what is offered by this library's interface. In the example `getDataFromSmartphone.ino` you can see how a phyphox-file can be used to set up a sensor on the phone and retrieve its data on the Arduino. In contrast to other examples, the phyphox-file is not generated by the library but instead loaded in phyphox with a QR code. You can also convert your manually created phyphox file into a header file and provide it to this library so it is submitted via Bluetooth.
135 |
136 | As the phyphox file format is extremely complex and powerful, please refer to the [phyphox wiki](https://phyphox.org/wiki/index.php/Phyphox_file_format) to learn about it and feel free to contact us if you are stuck or think that a specific aspect of the file format should be easily accessible through our Arduino library.
137 |
138 | ### Further documentation
139 |
140 | For now, this library is rather lightweight. Feel free to browse the `.h` files to learn about the functions that are already available.
141 |
142 | ## Missing features
143 |
144 | In the future we would like to see...
145 | - Some memory optimization
146 | - Compression for the transfer of the phyphox experiment generated on the Arduino
147 | - Option to request a larger mtu size
148 | - Addition graph settings
149 | - Proper documentation
150 |
151 | If you can help with this, we are happy to receive a pull request. You can contact us via contact@phyphox.org if you plan on a large addition to this library and want to make sure that it does not collide with anything we are already working on.
152 |
153 | ## Credits
154 |
155 | This library has been developed by the phyphox team at the RWTH Aachen University. In particular, the foundations and basic concept was created by Alexander Krampe as part of his Master thesis. The library has been further improved and is now maintained by Dominik Dorsel, our PhD student who also supervised Alexander's thesis. The library was also further optimized and extended with new features by Marcel Hagedorn and Edward Leier.
156 |
157 | ## Licence
158 |
159 | This library is released under the GNU Lesser General Public Licence v3.0 (or newer).
160 |
161 | ## Contact
162 |
163 | Contact us any time at contact@phyphox.org and learn more about phyphox on https://phyphox.org.
164 |
165 |
--------------------------------------------------------------------------------
/src/boards/phyphoxBLE_STM32.cpp:
--------------------------------------------------------------------------------
1 | #if defined(ARDUINO_ARCH_STM32)
2 |
3 | #include "phyphoxBLE_STM32.h"
4 | #include "Arduino.h"
5 | #include
6 |
7 | #if defined(ARDUINO_STEVAL_MKBOXPRO)
8 | /* STEVAL-MKBOXPRO */
9 | SPIClass SpiHCI(PA7, PA6, PA5);
10 | HCISpiTransportClass HCISpiTransport(SpiHCI, BLUENRG_LP, PA2, PB11, PD4, 1000000, SPI_MODE3);
11 | #if !defined(FAKE_BLELOCALDEVICE)
12 | BLELocalDevice BLEObj(&HCISpiTransport);
13 | BLELocalDevice& BLE = BLEObj;
14 | #endif
15 | #elif defined(ARDUINO_STEVAL_MKSBOX1V1)
16 | /* STEVAL-MKSBOX1V1 */
17 | SPIClass SpiHCI(PC3, PD3, PD1);
18 | HCISpiTransportClass HCISpiTransport(SpiHCI, SPBTLE_1S, PD0, PD4, PA8, 1000000, SPI_MODE1);
19 | #if !defined(FAKE_BLELOCALDEVICE)
20 | BLELocalDevice BLEObj(&HCISpiTransport);
21 | BLELocalDevice& BLE = BLEObj;
22 | #endif
23 | #elif defined(ARDUINO_B_L475E_IOT01A) || defined(ARDUINO_B_L4S5I_IOT01A)
24 | /* B-L475E-IOT01A1 or B_L4S5I_IOT01A */
25 | SPIClass SpiHCI(PC12, PC11, PC10);
26 | HCISpiTransportClass HCISpiTransport(SpiHCI, SPBTLE_RF, PD13, PE6, PA8, 8000000, SPI_MODE0);
27 | #if !defined(FAKE_BLELOCALDEVICE)
28 | BLELocalDevice BLEObj(&HCISpiTransport);
29 | BLELocalDevice& BLE = BLEObj;
30 | #endif
31 | #elif defined(ARDUINO_NUCLEO_WB15CC) || defined(ARDUINO_P_NUCLEO_WB55RG) ||\
32 | defined(ARDUINO_STM32WB5MM_DK) || defined(ARDUINO_P_NUCLEO_WB55_USB_DONGLE)
33 | HCISharedMemTransportClass HCISharedMemTransport;
34 | #if !defined(FAKE_BLELOCALDEVICE)
35 | BLELocalDevice BLEObj(&HCISharedMemTransport);
36 | BLELocalDevice& BLE = BLEObj;
37 | #endif
38 | #else
39 | /* Shield IDB05A2 with SPI clock on D3 */
40 | SPIClass SpiHCI(D11, D12, D3);
41 | HCISpiTransportClass HCISpiTransport(SpiHCI, BLUENRG_M0, A1, A0, D7, 8000000, SPI_MODE0);
42 | #if !defined(FAKE_BLELOCALDEVICE)
43 | BLELocalDevice BLEObj(&HCISpiTransport);
44 | BLELocalDevice& BLE = BLEObj;
45 | #endif
46 | /* Shield IDB05A2 with SPI clock on D13 */
47 | // #define SpiHCI SPI
48 | // HCISpiTransportClass HCISpiTransport(SpiHCI, BLUENRG_M0, A1, A0, D7, 8000000, SPI_MODE0);
49 | // #if !defined(FAKE_BLELOCALDEVICE)
50 | // BLELocalDevice BLEObj(&HCISpiTransport);
51 | // BLELocalDevice& BLE = BLEObj;
52 | // #endif
53 | /* Shield IDB05A1 with SPI clock on D3 */
54 | // SPIClass SpiHCI(D11, D12, D3);
55 | // HCISpiTransportClass HCISpiTransport(SpiHCI, SPBTLE_RF, A1, A0, D7, 8000000, SPI_MODE0);
56 | // #if !defined(FAKE_BLELOCALDEVICE)
57 | // BLELocalDevice BLEObj(&HCISpiTransport);
58 | // BLELocalDevice& BLE = BLEObj;
59 | // #endif
60 | /* Shield IDB05A1 with SPI clock on D13 */
61 | // #define SpiHCI SPI
62 | // HCISpiTransportClass HCISpiTransport(SpiHCI, SPBTLE_RF, A1, A0, D7, 8000000, SPI_MODE0);
63 | // #if !defined(FAKE_BLELOCALDEVICE)
64 | // BLELocalDevice BLEObj(&HCISpiTransport);
65 | // BLELocalDevice& BLE = BLEObj;
66 | // #endif
67 | /* Shield BNRG2A1 with SPI clock on D3 */
68 | // SPIClass SpiHCI(D11, D12, D3);
69 | // HCISpiTransportClass HCISpiTransport(SpiHCI, BLUENRG_M2SP, A1, A0, D7, 1000000, SPI_MODE1);
70 | // #if !defined(FAKE_BLELOCALDEVICE)
71 | // BLELocalDevice BLEObj(&HCISpiTransport);
72 | // BLELocalDevice& BLE = BLEObj;
73 | // #endif
74 | /* Shield BNRG2A1 with SPI clock on D13 */
75 | // #define SpiHCI SPI
76 | // HCISpiTransportClass HCISpiTransport(SpiHCI, BLUENRG_M2SP, A1, A0, D7, 1000000, SPI_MODE1);
77 | // #if !defined(FAKE_BLELOCALDEVICE)
78 | // BLELocalDevice BLEObj(&HCISpiTransport);
79 | // BLELocalDevice& BLE = BLEObj;
80 | // #endif
81 | #endif
82 |
83 | BLEService PhyphoxBLE::phyphoxExperimentService{phyphoxBleExperimentServiceUUID}; // create service
84 | BLECharacteristic PhyphoxBLE::experimentCharacteristic{phyphoxBleExperimentCharacteristicUUID, BLERead | BLEWrite| BLENotify, 20, false};
85 | BLECharacteristic PhyphoxBLE::controlCharacteristic{phyphoxBleExperimentControlCharacteristicUUID, BLERead | BLEWrite| BLENotify, 20, false};
86 | BLECharacteristic PhyphoxBLE::eventCharacteristic{phyphoxBleEventCharacteristicUUID, BLERead | BLEWrite| BLENotify, 20, false};
87 |
88 | BLEService PhyphoxBLE::phyphoxDataService{phyphoxBleDataServiceUUID}; // create service
89 | BLECharacteristic PhyphoxBLE::dataCharacteristic{phyphoxBleDataCharacteristicUUID, BLERead | BLEWrite | BLENotify, 20, false};
90 | BLECharacteristic PhyphoxBLE::configCharacteristic{phyphoxBleConfigCharacteristicUUID, BLERead | BLEWrite| BLENotify, 20, false};
91 |
92 | uint16_t PhyphoxBLE::minConInterval = 6; //7.5ms
93 | uint16_t PhyphoxBLE::maxConInterval = 24; //30ms
94 | uint16_t PhyphoxBLE::slaveLatency = 0;
95 | uint16_t PhyphoxBLE::timeout = 50;
96 |
97 | uint16_t PhyphoxBLE::MTU = 20;
98 | uint16_t PhyphoxBleExperiment::MTU = 20;
99 |
100 | int64_t PhyphoxBLE::experimentTime = 0;
101 | int64_t PhyphoxBLE::systemTime = 0;
102 | uint8_t PhyphoxBLE::eventType = 0;
103 |
104 | uint8_t* PhyphoxBLE::data = nullptr; //this pointer points to the data the user wants to write in the characteristic
105 | uint8_t* PhyphoxBLE::p_exp = nullptr; //this pointer will point to the byte array which holds an experiment
106 |
107 | size_t PhyphoxBLE::expLen = 0; //try o avoid this maybe use std::array or std::vector
108 | const int maxExperimentSize = 6000;
109 | uint8_t storage[maxExperimentSize];
110 | uint8_t PhyphoxBLE::eventData[17]={0};
111 | //uint8_t eventData[17];
112 | char *PhyphoxBLE::EXPARRAY=(char*)storage;
113 |
114 | void(*PhyphoxBLE::configHandler)() = nullptr;
115 | void(*PhyphoxBLE::experimentEventHandler)() = nullptr;
116 |
117 | void PhyphoxBLE::start(const char* DEVICE_NAME, uint8_t* exp_pointer, size_t len){
118 | p_exp = exp_pointer;
119 | expLen = len;
120 | start(DEVICE_NAME);
121 | }
122 |
123 | void PhyphoxBLE::start(uint8_t* exp_pointer, size_t len){
124 | p_exp = exp_pointer;
125 | expLen = len;
126 | start();
127 | }
128 |
129 | void PhyphoxBLE::start(const char* DEVICE_NAME)
130 | {
131 | deviceName = DEVICE_NAME;
132 |
133 | controlCharacteristic.setEventHandler(BLEWritten, controlCharacteristicWritten);
134 | eventCharacteristic.setEventHandler(BLEWritten, eventCharacteristicWritten);
135 | configCharacteristic.setEventHandler(BLEWritten, configCharacteristicWritten);
136 |
137 | if(p_exp == nullptr){
138 |
139 | PhyphoxBleExperiment defaultExperiment;
140 |
141 | //View
142 | PhyphoxBleExperiment::View firstView;
143 |
144 | //Graph
145 | PhyphoxBleExperiment::Graph firstGraph; //Create graph which will plot random numbers over time
146 | firstGraph.setChannel(0,1);
147 |
148 | firstView.addElement(firstGraph);
149 | defaultExperiment.addView(firstView);
150 |
151 | addExperiment(defaultExperiment);
152 | }
153 |
154 |
155 | if(!BLE.begin()) { Serial.println("failed to BLE.begin()!"); }
156 | BLE.setLocalName(DEVICE_NAME);
157 | BLE.setAdvertisedService(phyphoxExperimentService);
158 | //BLE.setAdvertisedService(phyphoxDataService);
159 |
160 | // add the characteristics to the service
161 | phyphoxExperimentService.addCharacteristic(experimentCharacteristic);
162 | phyphoxExperimentService.addCharacteristic(controlCharacteristic);
163 | phyphoxExperimentService.addCharacteristic(eventCharacteristic);
164 | phyphoxDataService.addCharacteristic(configCharacteristic);
165 | phyphoxDataService.addCharacteristic(dataCharacteristic);
166 |
167 | // add the service
168 | BLE.addService(phyphoxExperimentService);
169 | BLE.addService(phyphoxDataService);
170 |
171 | // set connection parameter
172 | BLE.setConnectionInterval(minConInterval, maxConInterval);
173 |
174 | // start advertising
175 | BLE.advertise();
176 |
177 | }
178 |
179 | void PhyphoxBLE::start() {
180 | PhyphoxBLE::start("phyphox-Arduino");
181 | }
182 |
183 | void PhyphoxBLE::poll()
184 | {
185 | BLE.poll();
186 | }
187 |
188 | void PhyphoxBLE::poll(int timeout)
189 | {
190 | BLE.poll(timeout);
191 | }
192 |
193 | void PhyphoxBLE::read(uint8_t *arrayPointer, unsigned int arraySize)
194 | {
195 | configCharacteristic.readValue(arrayPointer, arraySize);
196 | }
197 |
198 | void PhyphoxBLE::read(float& f)
199 | {
200 | uint8_t readDATA[4];
201 | configCharacteristic.readValue(readDATA, 4);
202 | memcpy(&f,&readDATA[0],4);
203 | }
204 |
205 | void PhyphoxBLE::read(float& f1, float& f2)
206 | {
207 | uint8_t readDATA[8];
208 | configCharacteristic.readValue(readDATA, 8);
209 | memcpy(&f1,readDATA,4);
210 | memcpy(&f2,readDATA+4,4);
211 | }
212 | void PhyphoxBLE::read(float& f1, float& f2, float& f3)
213 | {
214 | uint8_t readDATA[12];
215 | configCharacteristic.readValue(readDATA, 12);
216 | memcpy(&f1,readDATA,4);
217 | memcpy(&f2,readDATA+4,4);
218 | memcpy(&f3,readDATA+8,4);
219 | }
220 | void PhyphoxBLE::read(float& f1, float& f2, float& f3, float& f4)
221 | {
222 | uint8_t readDATA[16];
223 | configCharacteristic.readValue(readDATA, 16);
224 | memcpy(&f1,readDATA,4);
225 | memcpy(&f2,readDATA+4,4);
226 | memcpy(&f3,readDATA+8,4);
227 | memcpy(&f4,readDATA+12,4);
228 | }
229 | void PhyphoxBLE::read(float& f1, float& f2, float& f3, float& f4, float& f5)
230 | {
231 | uint8_t readDATA[20];
232 | configCharacteristic.readValue(readDATA, 20);
233 | memcpy(&f1,readDATA,4);
234 | memcpy(&f2,readDATA+4,4);
235 | memcpy(&f3,readDATA+8,4);
236 | memcpy(&f4,readDATA+12,4);
237 | memcpy(&f5,readDATA+16,4);
238 | }
239 |
240 | void PhyphoxBLE::addExperiment(PhyphoxBleExperiment& exp)
241 | {
242 | memset(EXPARRAY,0,maxExperimentSize);
243 |
244 | exp.getFirstBytes(EXPARRAY, deviceName);
245 |
246 |
247 | for(uint8_t i=0;i(&value);
264 | dataCharacteristic.writeValue(data,4);
265 | }
266 |
267 |
268 | void PhyphoxBLE::write(float& f1, float& f2)
269 | {
270 | float array[2] = {f1, f2};
271 | data = reinterpret_cast(array);
272 | dataCharacteristic.writeValue(data,8);
273 | }
274 |
275 | void PhyphoxBLE::write(float& f1, float& f2, float& f3)
276 | {
277 | float array[3] = {f1, f2, f3};
278 | data = reinterpret_cast(array);
279 | dataCharacteristic.writeValue(data,12);
280 | }
281 |
282 | void PhyphoxBLE::write(float& f1, float& f2, float& f3 , float& f4)
283 | {
284 | float array[4] = {f1, f2, f3, f4};
285 | data = reinterpret_cast(array);
286 | dataCharacteristic.writeValue(data,16);
287 | }
288 |
289 | void PhyphoxBLE::write(float& f1, float& f2, float& f3 , float& f4, float& f5)
290 | {
291 | float array[5] = {f1, f2, f3, f4, f5};
292 | data = reinterpret_cast(array);
293 | dataCharacteristic.writeValue(data,20);
294 | }
295 |
296 | void PhyphoxBLE::controlCharacteristicWritten(BLEDevice central, BLECharacteristic characteristic) {
297 | byte value = 0;
298 | characteristic.readValue(value);
299 | if (value & 0x01) {
300 | //sendexperiment
301 | transferExperiment();
302 | } else {
303 | //experiment transfered
304 | }
305 |
306 | }
307 |
308 | void PhyphoxBLE::transferExperiment(){
309 |
310 | BLE.stopAdvertise();
311 |
312 | uint8_t* exp = p_exp;
313 | size_t exp_len = expLen;
314 |
315 | uint8_t header[20] = {0}; //20 byte as standard package size for ble transfer
316 | const char phyphox[] = "phyphox";
317 | uint32_t table[256];
318 | phyphoxBleCrc32::generate_table(table);
319 | uint32_t checksum = phyphoxBleCrc32::update(table, 0, exp, exp_len);
320 | size_t arrayLength = exp_len;
321 | uint8_t experimentSizeArray[4] = {0};
322 | experimentSizeArray[0]= (arrayLength >> 24);
323 | experimentSizeArray[1]= (arrayLength >> 16);
324 | experimentSizeArray[2]= (arrayLength >> 8);
325 | experimentSizeArray[3]= arrayLength;
326 |
327 | uint8_t checksumArray[4] = {0};
328 | checksumArray[0]= (checksum >> 24) & 0xFF;
329 | checksumArray[1]= (checksum >> 16) & 0xFF;
330 | checksumArray[2]= (checksum >> 8) & 0xFF;
331 | checksumArray[3]= checksum & 0xFF;
332 |
333 | memcpy(&header[0],&phyphox[0],7);
334 | memcpy(&header[0]+7,&experimentSizeArray[0],4);
335 | memcpy(&header[0]+7+4,&checksumArray[0],4);
336 | experimentCharacteristic.writeValue(header,sizeof(header));
337 |
338 | for(size_t i = 0; i < exp_len/20; ++i){
339 | memcpy(&header[0],&exp[0]+i*20,20);
340 | experimentCharacteristic.writeValue(header,sizeof(header));
341 | delay(5);
342 | }
343 |
344 | if(exp_len%20 != 0){
345 | const size_t rest = exp_len%20;
346 | uint8_t slice[rest];
347 | memcpy(&slice[0],&exp[0]+exp_len-rest,rest);
348 | experimentCharacteristic.writeValue(slice,sizeof(slice));
349 |
350 | delay(5);
351 | }
352 |
353 | BLE.advertise();
354 | }
355 |
356 | void PhyphoxBLE::configCharacteristicWritten(BLEDevice central, BLECharacteristic characteristic){
357 | if(configHandler!=nullptr){
358 | (*configHandler)();
359 | }
360 | }
361 |
362 | void PhyphoxBLE::eventCharacteristicWritten(BLEDevice central, BLECharacteristic characteristic){
363 |
364 | uint8_t read_buffer[17];
365 | eventCharacteristic.readValue(read_buffer, 17);
366 |
367 |
368 | memcpy(&eventData[0],read_buffer,17);
369 | int64_t et,st;
370 | memcpy(&et,&eventData[0]+1,8);
371 | memcpy(&st,&eventData[0]+1+8,8);
372 | PhyphoxBLE::eventType = eventData[0];
373 | PhyphoxBLE::systemTime = swap_int64(st);
374 | PhyphoxBLE::experimentTime = swap_int64(et);
375 |
376 | if(experimentEventHandler!=nullptr){
377 | (*experimentEventHandler)();
378 | }
379 | }
380 |
381 | void PhyphoxBLE::printXML(HardwareSerial* printer){
382 | printer->println("");
383 | for(int i =0; iprint(CHAR);
386 | }
387 | printer->println("");
388 | }
389 | #endif
390 |
--------------------------------------------------------------------------------
/src/boards/phyphoxBLE_NRF52.cpp:
--------------------------------------------------------------------------------
1 | #if defined(ARDUINO_ARCH_MBED)
2 | #include "phyphoxBLE_NRF52.h"
3 |
4 | const UUID PhyphoxBLE::phyphoxExperimentServiceUUID = UUID(phyphoxBleExperimentServiceUUID);
5 | const UUID PhyphoxBLE::experimentCharacteristicUUID = UUID(phyphoxBleExperimentCharacteristicUUID);
6 |
7 | const UUID PhyphoxBLE::phyphoxDataServiceUUID = UUID(phyphoxBleDataServiceUUID);
8 | const UUID PhyphoxBLE::dataCharacteristicUUID = UUID(phyphoxBleDataCharacteristicUUID);
9 | const UUID PhyphoxBLE::configCharacteristicUUID = UUID(phyphoxBleConfigCharacteristicUUID);
10 | const UUID PhyphoxBLE::eventCharacteristicUUID = UUID(phyphoxBleEventCharacteristicUUID);
11 |
12 | uint16_t PhyphoxBleExperiment::MTU = 20;
13 |
14 | char PhyphoxBLE::name[50] = "";
15 |
16 | Thread PhyphoxBLE::bleEventThread;
17 | Thread PhyphoxBLE::transferExpThread;
18 |
19 | uint8_t PhyphoxBLE::data_package[20] = {0};
20 | uint8_t PhyphoxBLE::config_package[CONFIGSIZE] = {0};
21 | uint8_t PhyphoxBLE::eventData[17] = {0};
22 | int64_t PhyphoxBLE::experimentTime = NULL;
23 | int64_t PhyphoxBLE::systemTime = NULL;
24 | uint8_t PhyphoxBLE::eventType = NULL;
25 |
26 | /*BLE stuff*/
27 | BLE& bleInstance = BLE::Instance(BLE::DEFAULT_INSTANCE);
28 | BLE& PhyphoxBLE::ble = bleInstance;
29 |
30 | uint8_t PhyphoxBLE::readValue[DATASIZE] = {0};
31 |
32 | ReadWriteArrayGattCharacteristic PhyphoxBLE::dataCharacteristic{PhyphoxBLE::dataCharacteristicUUID, PhyphoxBLE::data_package, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY}; //Note: Use { } instead of () google most vexing parse
33 | ReadWriteArrayGattCharacteristic PhyphoxBLE::configCharacteristic{PhyphoxBLE::configCharacteristicUUID, PhyphoxBLE::config_package, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY};
34 | ReadWriteArrayGattCharacteristic PhyphoxBLE::eventCharacteristic{PhyphoxBLE::eventCharacteristicUUID, PhyphoxBLE::eventData, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY};
35 |
36 | //Experiment Transfer
37 | ReadOnlyArrayGattCharacteristic PhyphoxBLE::experimentCharacteristic{PhyphoxBLE::experimentCharacteristicUUID, PhyphoxBLE::readValue, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY};
38 |
39 | EventQueue PhyphoxBLE::queue{32 * EVENTS_EVENT_SIZE};
40 | /*end BLE stuff*/
41 | EventQueue PhyphoxBLE::transferQueue{32 * EVENTS_EVENT_SIZE};
42 |
43 | PhyphoxBleEventHandler PhyphoxBLE::eventHandler(bleInstance);
44 |
45 | GattCharacteristic* PhyphoxBLE::phyphoxCharacteristics[2] = {&PhyphoxBLE::experimentCharacteristic,&PhyphoxBLE::eventCharacteristic};
46 | GattService PhyphoxBLE::phyphoxService{PhyphoxBLE::phyphoxExperimentServiceUUID, PhyphoxBLE::phyphoxCharacteristics, sizeof(PhyphoxBLE::phyphoxCharacteristics) / sizeof(GattCharacteristic *)};
47 |
48 | GattCharacteristic* PhyphoxBLE::phyphoxDataCharacteristics[2] = {&PhyphoxBLE::dataCharacteristic, &PhyphoxBLE::configCharacteristic};
49 | GattService PhyphoxBLE::phyphoxDataService{PhyphoxBLE::phyphoxDataServiceUUID, PhyphoxBLE::phyphoxDataCharacteristics, sizeof(PhyphoxBLE::phyphoxDataCharacteristics) / sizeof(GattCharacteristic *)};
50 |
51 | uint8_t* PhyphoxBLE::data = nullptr; //this pointer points to the data the user wants to write in the characteristic
52 | uint8_t* PhyphoxBLE::config =nullptr;
53 | uint8_t* PhyphoxBLE::event =nullptr;
54 | uint8_t* PhyphoxBLE::p_exp = nullptr; //this pointer will point to the byte array which holds an experiment
55 |
56 | char PhyphoxBLE::EXPARRAY[4096] = {0};// block some storage
57 | size_t PhyphoxBLE::expLen = 0; //try o avoid this maybe use std::array or std::vector
58 |
59 | void (*PhyphoxBLE::configHandler)() = nullptr;
60 | void (*PhyphoxBLE::experimentEventHandler)() = nullptr;
61 |
62 | void PhyphoxBleEventHandler::onDisconnectionComplete(const ble::DisconnectionCompleteEvent &event)
63 | {
64 | //#ifndef NDEBUG
65 | //if(printer)
66 | // printer -> println("Disconnection");
67 | //#endif
68 | ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE);
69 | PhyphoxBLE::currentConnections= PhyphoxBLE::currentConnections -1;
70 | }
71 |
72 | void PhyphoxBleEventHandler::onConnectionComplete(const ble::ConnectionCompleteEvent &event)
73 | {
74 | //#ifndef NDEBUG
75 | //if(printer)
76 | // printer -> println("Connection with device");
77 | //#endif
78 |
79 | PhyphoxBLE::currentConnections+=1;
80 |
81 |
82 | ble.gap().updateConnectionParameters(event.getConnectionHandle(),
83 | ble::conn_interval_t(PhyphoxBLE::minConInterval),
84 | ble::conn_interval_t(PhyphoxBLE::maxConInterval),
85 | ble::slave_latency_t (PhyphoxBLE::slaveLatency),
86 | ble::supervision_timeout_t(PhyphoxBLE::timeout));
87 |
88 | }
89 |
90 | #ifndef NDEBUG
91 | void PhyphoxBLE::begin(HardwareSerial* hwPrint)
92 | {
93 | printer = hwPrint;
94 | if(printer)
95 | printer->begin(9600);
96 | }
97 |
98 | void PhyphoxBLE::output(const char* s)
99 | {
100 | if(printer)
101 | printer->println(s);
102 | }
103 |
104 | void PhyphoxBLE::output(const uint32_t num)
105 | {
106 | if(printer)
107 | printer -> println(num);
108 | }
109 |
110 | #endif
111 |
112 | void PhyphoxBLE::printXML(HardwareSerial* printer){
113 | printer->println("");
114 | for(int i =0; iprint(CHAR);
117 | }
118 | printer->println("");
119 | }
120 |
121 |
122 |
123 | void PhyphoxBLE::when_subscription_received(GattAttribute::Handle_t handle)
124 | {
125 | #ifndef NDEBUG
126 | output("Received a subscription");
127 | #endif
128 | bool sub_dChar = false;
129 | ble.gattServer().areUpdatesEnabled(experimentCharacteristic, &sub_dChar);
130 |
131 | if(sub_dChar)
132 | {
133 | transferQueue.call(transferExp);
134 | sub_dChar = false;
135 | }
136 | //after experiment has been transfered start advertising again
137 | ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE);
138 |
139 | }
140 | void PhyphoxBLE::configReceived(const GattWriteCallbackParams *params)
141 | {
142 | if(params->handle == configCharacteristic.getValueHandle()){
143 | if(configHandler != nullptr){
144 | transferQueue.call( configHandler );
145 | }
146 | }else if (params->handle == eventCharacteristic.getValueHandle())
147 | {
148 | uint16_t eventSize = 17;
149 | ble.gattServer().read(eventCharacteristic.getValueHandle(), eventData, &eventSize);
150 | int64_t et,st;
151 | memcpy(&et,&eventData[0]+1,8);
152 | memcpy(&st,&eventData[0]+1+8,8);
153 | PhyphoxBLE::eventType = eventData[0];
154 | PhyphoxBLE::systemTime = swap_int64(st);
155 | PhyphoxBLE::experimentTime = swap_int64(et);
156 | if(experimentEventHandler != nullptr){
157 | transferQueue.call( experimentEventHandler );
158 | }
159 |
160 | }
161 |
162 | }
163 |
164 | void PhyphoxBLE::transferExp()
165 | {
166 | BLE &ble = PhyphoxBLE::ble;
167 | uint8_t* exp = PhyphoxBLE::p_exp;
168 | size_t exp_len = PhyphoxBLE::expLen;
169 |
170 | #ifndef NDEBUG
171 | PhyphoxBLE::output("In transfer exp");
172 | #endif
173 |
174 | uint8_t header[20] = {0}; //20 byte as standard package size for ble transfer
175 | const char phyphox[] = "phyphox-Arduino";
176 | uint32_t table[256];
177 | phyphoxBleCrc32::generate_table(table);
178 | uint32_t checksum = phyphoxBleCrc32::update(table, 0, exp, exp_len);
179 | #ifndef NDEBUG
180 | PhyphoxBLE::output("checksum: ");
181 | PhyphoxBLE::output(checksum);
182 | #endif
183 | size_t arrayLength = exp_len;
184 | uint8_t experimentSizeArray[4] = {0};
185 | experimentSizeArray[0]= (arrayLength >> 24);
186 | experimentSizeArray[1]= (arrayLength >> 16);
187 | experimentSizeArray[2]= (arrayLength >> 8);
188 | experimentSizeArray[3]= arrayLength;
189 |
190 | uint8_t checksumArray[4] = {0};
191 | checksumArray[0]= (checksum >> 24) & 0xFF;
192 | checksumArray[1]= (checksum >> 16) & 0xFF;
193 | checksumArray[2]= (checksum >> 8) & 0xFF;
194 | checksumArray[3]= checksum & 0xFF;
195 |
196 | copy(phyphox, phyphox+7, header);
197 | copy(experimentSizeArray, experimentSizeArray+ 4, header + 7);
198 | copy(checksumArray, checksumArray + 4, header +11);
199 |
200 | ble.gattServer().write(PhyphoxBLE::experimentCharacteristic.getValueHandle(), header, sizeof(header));
201 | wait_us(30000);
202 |
203 | for(size_t i = 0; i < exp_len/20; ++i)
204 | {
205 | copy(exp+i*20, exp+i*20+20, header);
206 | ble.gattServer().write(PhyphoxBLE::experimentCharacteristic.getValueHandle(), header, sizeof(header));
207 | wait_us(30000);
208 | }
209 |
210 | if(exp_len%20 != 0)
211 | {
212 | const size_t rest = exp_len%20;
213 | uint8_t slice[rest];
214 | copy(exp + exp_len - rest, exp + exp_len, slice);
215 | ble.gattServer().write(PhyphoxBLE::experimentCharacteristic.getValueHandle(), slice, sizeof(slice));
216 | wait_us(30000);
217 | }
218 | }
219 |
220 | void PhyphoxBLE::bleInitComplete(BLE::InitializationCompleteCallbackContext* params)
221 | {
222 |
223 | ble.gattServer().onUpdatesEnabled(PhyphoxBLE::when_subscription_received);
224 | ble.gattServer().onDataWritten(PhyphoxBLE::configReceived);
225 |
226 | ble.gap().setEventHandler(&PhyphoxBLE::eventHandler);
227 |
228 | uint8_t _adv_buffer[ble::LEGACY_ADVERTISING_MAX_SIZE];
229 | ble::AdvertisingDataBuilder adv_data_builder(_adv_buffer);
230 | //adv_data_builder.setConnectionIntervalPreference(ble::conn_interval_t(minConInterval) ,ble::conn_interval_t(maxConInterval) );
231 | ble::AdvertisingParameters adv_parameters(ble::advertising_type_t::CONNECTABLE_UNDIRECTED, ble::adv_interval_t(ble::millisecond_t(100)));
232 | adv_data_builder.setFlags();
233 | adv_data_builder.setLocalServiceList(mbed::make_Span(&phyphoxExperimentServiceUUID, 1));
234 |
235 | #ifndef NDEBUG
236 | if(error == BLE_ERROR_BUFFER_OVERFLOW){
237 | output("BLE_ERROR_BUFFER_OVERFLOW");
238 | }else if(error == BLE_ERROR_NONE){
239 | output("BLE_ERROR_NONE");
240 | }else if(error == BLE_ERROR_INVALID_PARAM){
241 | output("BLE_ERROR_INVALID_PARAM");
242 | }
243 | #endif
244 |
245 | ble.gap().setAdvertisingParameters(ble::LEGACY_ADVERTISING_HANDLE, adv_parameters);
246 | ble.gap().setAdvertisingPayload(ble::LEGACY_ADVERTISING_HANDLE,adv_data_builder.getAdvertisingData());
247 | adv_data_builder.clear();
248 | adv_data_builder.setName(name);
249 | ble.gap().setAdvertisingScanResponse(ble::LEGACY_ADVERTISING_HANDLE,adv_data_builder.getAdvertisingData());
250 | ble.gattServer().addService(phyphoxService);
251 | ble.gattServer().addService(phyphoxDataService);
252 |
253 | ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE);
254 | #ifndef NDEBUG
255 | output("in init");
256 | #endif
257 | }
258 |
259 | void PhyphoxBLE::start(const char* DEVICE_NAME, uint8_t* exp_pointer, size_t len)
260 | {
261 | /**
262 | * \brief start the server and begin advertising
263 | * This methods starts the server by. By specifying
264 | * exp_pointer and len you can send your own phyphox
265 | * experiment to your smartphone. Otherwise a default
266 | * experiment will be sent.
267 | * \param exp_pointer a pointer to an experiment
268 | * \param len the len of the experiment
269 | */
270 | #ifndef NDEBUG
271 | output("In start");
272 | #endif
273 |
274 | strncpy(name, DEVICE_NAME, 49);
275 | name[50] = '\0';
276 |
277 | if(exp_pointer != nullptr){
278 | p_exp = exp_pointer;
279 | expLen = len;
280 | }else if(p_exp==nullptr){
281 |
282 | PhyphoxBleExperiment defaultExperiment;
283 |
284 | //View
285 | PhyphoxBleExperiment::View firstView;
286 |
287 | //Graph
288 | PhyphoxBleExperiment::Graph firstGraph; //Create graph which will plot random numbers over time
289 | firstGraph.setChannel(0,1);
290 |
291 | firstView.addElement(firstGraph);
292 | defaultExperiment.addView(firstView);
293 |
294 | addExperiment(defaultExperiment);
295 |
296 | }
297 |
298 | bleEventThread.start(callback(&queue, &EventQueue::dispatch_forever));
299 | transferExpThread.start(callback(&transferQueue, &EventQueue::dispatch_forever));
300 | ble.onEventsToProcess(PhyphoxBLE::schedule_ble_events);
301 | ble.init(PhyphoxBLE::bleInitComplete);
302 | }
303 |
304 | void PhyphoxBLE::start(uint8_t* exp_pointer, size_t len) {
305 | start("phyphox-Arduino", exp_pointer, len);
306 | }
307 |
308 | void PhyphoxBLE::start(const char* DEVICE_NAME) {
309 | start(DEVICE_NAME, nullptr, 0);
310 | deviceName = DEVICE_NAME;
311 | }
312 |
313 | void PhyphoxBLE::start() {
314 | start("phyphox-Arduino", nullptr, 0);
315 | }
316 |
317 | void PhyphoxBLE::poll() {
318 | }
319 |
320 | void PhyphoxBLE::poll(int timeout) {
321 | }
322 |
323 | void PhyphoxBLE::write(float& value)
324 | {
325 | /**
326 | * \brief Write a single float into characteristic
327 | * The float is parsed to uint8_t*
328 | * because the gattServer write method
329 | * expects a pointer to uint8_t
330 | * \param f1 represent a float most likeley sensor data
331 | */
332 | data = reinterpret_cast(&value);
333 | ble.gattServer().write(dataCharacteristic.getValueHandle(), data, 4);
334 | }
335 |
336 |
337 | ///todo: public getter for gatt server
338 |
339 |
340 | void PhyphoxBLE::write(float& f1, float& f2)
341 | {
342 | /**
343 | * \brief Write 2 floats into characteristic
344 | * The floats are parsed to uint8_t*
345 | * because the gattServer write method e
346 | * expects a pointer to uint8_t
347 | * \param f1 and f2 represent two floats most likeley sensor data
348 | */
349 |
350 | float array[2] = {f1, f2};
351 | data = reinterpret_cast(array);
352 | ble.gattServer().write(dataCharacteristic.getValueHandle(), data, 8);
353 | }
354 |
355 | void PhyphoxBLE::write(float& f1, float& f2, float& f3)
356 | {
357 | /**
358 | * \brief Write 3 floats into characteristic
359 | * The floats are parsed to uint8_t*
360 | * because the gattServer write method
361 | * expects a pointer to uint8_t
362 | * \param param f1 and f2 and f3 represents three floats most likeley sensor data
363 | */
364 | float array[3] = {f1, f2, f3};
365 | data = reinterpret_cast(array);
366 | ble.gattServer().write(dataCharacteristic.getValueHandle(), data, 12);
367 | }
368 |
369 | void PhyphoxBLE::write(float& f1, float& f2, float& f3, float& f4)
370 | {
371 | /**
372 | * \brief Write 4 floats into characteristic
373 | * The floats are parsed to uint8_t*
374 | * because the gattServer write method
375 | * expects a pointer to uint8_t
376 | * \param param f1 and f2 and f3 and f4 represents four floats most likeley sensor data
377 | */
378 | float array[4] = {f1, f2, f3, f4};
379 | data = reinterpret_cast(array);
380 | ble.gattServer().write(dataCharacteristic.getValueHandle(), data, 16);
381 | }
382 | void PhyphoxBLE::write(float& f1, float& f2, float& f3, float& f4, float& f5)
383 | {
384 | /**
385 | * \brief Write 5 floats into characteristic
386 | * The floats are parsed to uint8_t*
387 | * because the gattServer write method
388 | * expects a pointer to uint8_t
389 | * \param param f1 and f2 and f3 and f4 and f5 represents five floats most likeley sensor data
390 | */
391 | float array[5] = {f1, f2, f3, f4, f5};
392 | data = reinterpret_cast(array);
393 | ble.gattServer().write(dataCharacteristic.getValueHandle(), data, 20);
394 | }
395 | void PhyphoxBLE::write(uint8_t *arrayPointer, unsigned int arraySize)
396 | {
397 | ble.gattServer().write(dataCharacteristic.getValueHandle(), arrayPointer, arraySize);
398 | }
399 |
400 |
401 | void PhyphoxBLE::read(float& f1)
402 | {
403 | uint16_t configSize = 4;
404 | uint8_t myConfig[4];
405 | ble.gattServer().read(configCharacteristic.getValueHandle(), myConfig, &configSize);
406 | memcpy(&f1,&myConfig[0], 4);
407 | }
408 | void PhyphoxBLE::read(float& f1, float& f2)
409 | {
410 | uint16_t configSize = 8;
411 | uint8_t myConfig[8];
412 | ble.gattServer().read(configCharacteristic.getValueHandle(), myConfig, &configSize);
413 | memcpy(&f1,&myConfig[0],4);
414 | memcpy(&f2,&myConfig[0]+4,4);
415 | }
416 | void PhyphoxBLE::read(float& f1, float& f2, float& f3)
417 | {
418 | uint16_t configSize = 12;
419 | uint8_t myConfig[12];
420 | ble.gattServer().read(configCharacteristic.getValueHandle(), myConfig, &configSize);
421 | memcpy(&f1,&myConfig[0],4);
422 | memcpy(&f2,&myConfig[0]+4,4);
423 | memcpy(&f3,&myConfig[0]+8,4);
424 | }
425 | void PhyphoxBLE::read(float& f1, float& f2, float& f3, float& f4)
426 | {
427 | uint16_t configSize = 16;
428 | uint8_t myConfig[16];
429 | ble.gattServer().read(configCharacteristic.getValueHandle(), myConfig, &configSize);
430 | memcpy(&f1,&myConfig[0],4);
431 | memcpy(&f2,&myConfig[0]+4,4);
432 | memcpy(&f3,&myConfig[0]+8,4);
433 | memcpy(&f4,&myConfig[0]+12,4);
434 | }
435 | void PhyphoxBLE::read(float& f1, float& f2, float& f3, float& f4, float& f5)
436 | {
437 | uint16_t configSize = 20;
438 | uint8_t myConfig[20];
439 | ble.gattServer().read(configCharacteristic.getValueHandle(), myConfig, &configSize);
440 | memcpy(&f1,&myConfig[0],4);
441 | memcpy(&f2,&myConfig[0]+4,4);
442 | memcpy(&f3,&myConfig[0]+8,4);
443 | memcpy(&f4,&myConfig[0]+12,4);
444 | memcpy(&f5,&myConfig[0]+16,4);
445 | }
446 |
447 | void PhyphoxBLE::read(uint8_t *arrayPointer, unsigned int arraySize)
448 | {
449 | uint16_t myArraySize = arraySize;
450 | ble.gattServer().read(configCharacteristic.getValueHandle(), arrayPointer, &myArraySize);
451 | }
452 |
453 |
454 | void PhyphoxBLE::addExperiment(PhyphoxBleExperiment& exp)
455 | {
456 | for (int i = 0; i < 4096; i++){
457 | PhyphoxBLE::EXPARRAY[i]=0;
458 | }
459 | exp.getFirstBytes(EXPARRAY, deviceName);
460 | for(uint8_t i=0;i(&context->ble, &BLE::processEvents));
473 | }
474 |
475 | #endif
476 |
477 |
478 |
--------------------------------------------------------------------------------
/src/boards/phyphoxBLE_ESP32.cpp:
--------------------------------------------------------------------------------
1 | #if defined(ESP32) && !defined(ARDUINO_SENSEBOX_MCU_ESP32S2)
2 | #include "phyphoxBLE_ESP32.h"
3 | #include "Arduino.h"
4 | #include
5 | #include "esp_system.h"
6 | //#define DEBUG
7 | //init statics
8 | uint8_t PhyphoxBLE::data_package[20] = {0};
9 | void (*PhyphoxBLE::configHandler)() = nullptr;
10 | void (*PhyphoxBLE::experimentEventHandler)() = nullptr;
11 | uint8_t storage[16000];
12 | //uint8_t *storage = (uint8_t*) malloc(8000 * sizeof(char));
13 | char *PhyphoxBLE::EXPARRAY=(char*)storage;
14 | uint8_t* PhyphoxBLE::p_exp = nullptr;
15 | size_t PhyphoxBLE::expLen = 0;
16 | HardwareSerial* PhyphoxBLE::printer =nullptr;
17 |
18 | BLEServer *PhyphoxBLE::myServer;
19 | BLEService *PhyphoxBLE::phyphoxExperimentService;
20 | BLEService *PhyphoxBLE::phyphoxDataService;
21 | BLEDescriptor *PhyphoxBLE::myExperimentDescriptor;
22 | BLEDescriptor *PhyphoxBLE::myDataDescriptor;
23 | BLEDescriptor *PhyphoxBLE::myEventDescriptor;
24 | BLEDescriptor *PhyphoxBLE::myConfigDescriptor;
25 | BLECharacteristic *PhyphoxBLE::dataCharacteristic;
26 | BLECharacteristic *PhyphoxBLE::eventCharacteristic;
27 | BLECharacteristic *PhyphoxBLE::experimentCharacteristic;
28 | BLECharacteristic *PhyphoxBLE::configCharacteristic;
29 | BLEAdvertising *PhyphoxBLE::myAdvertising;
30 | TaskHandle_t PhyphoxBLE::TaskTransfer;
31 | uint8_t* PhyphoxBLE::data;
32 |
33 | uint16_t PhyphoxBLE::minConInterval = 6; //7.5ms
34 | uint16_t PhyphoxBLE::maxConInterval = 24; //30ms
35 | uint16_t PhyphoxBLE::slaveLatency = 0;
36 | uint16_t PhyphoxBLE::timeout = 50;
37 | uint16_t PhyphoxBLE::currentConnections=0;
38 | bool PhyphoxBLE::isSubscribed=false;
39 |
40 | uint8_t PhyphoxBLE::eventData[17]={0};
41 | int64_t PhyphoxBLE::experimentTime = NULL;
42 | int64_t PhyphoxBLE::systemTime = NULL;
43 | uint8_t PhyphoxBLE::eventType = NULL;
44 | uint16_t PhyphoxBLE::MTU = 20;
45 | uint16_t PhyphoxBleExperiment::MTU = 20;
46 |
47 | #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
48 | class MyExpCallback: public BLECharacteristicCallbacks {
49 | private:
50 | HardwareSerial* printer;
51 |
52 | public:
53 | MyExpCallback(HardwareSerial* hwPrint) {
54 | printer = hwPrint;
55 | }
56 | private:
57 |
58 | void onSubscribe(BLECharacteristic *pCharacteristic, ble_gap_conn_desc *desc, uint16_t subValue) override {
59 | #ifdef DEBUG
60 | if(printer){
61 | printer->println("onSubscribe (exp)");
62 | }
63 | #endif
64 |
65 | if (subValue) {
66 | // start when_subscription_received() on cpu 1
67 | PhyphoxBLE::startTask();
68 | }
69 | };
70 | };
71 | #else
72 | class MyExpDescCallback: public BLEDescriptorCallbacks {
73 | private:
74 | HardwareSerial* printer;
75 |
76 | public:
77 | MyExpDescCallback(HardwareSerial* hwPrint) {
78 | printer = hwPrint;
79 | }
80 | private:
81 |
82 | void onWrite(BLEDescriptor* pDescriptor) override {
83 | #ifdef DEBUG
84 | if(printer){
85 | printer->println("descriptor write (exp)");
86 | }
87 | #endif
88 | uint8_t* rxValue = pDescriptor->getValue();
89 |
90 | if(pDescriptor->getLength() > 0){
91 | if (rxValue[0] == 1) {
92 | // start when_subscription_received() on cpu 1
93 | PhyphoxBLE::startTask();
94 | }
95 | }
96 | };
97 | };
98 | #endif
99 |
100 | #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
101 | class MyDataCallback: public BLECharacteristicCallbacks {
102 | private:
103 | HardwareSerial* printer;
104 |
105 | public:
106 | MyDataCallback(HardwareSerial* hwPrint) {
107 | printer = hwPrint;
108 | }
109 |
110 | private:
111 |
112 | void onSubscribe(BLECharacteristic *pCharacteristic, ble_gap_conn_desc *desc, uint16_t subValue) override {
113 | #ifdef DEBUG
114 | if(printer){
115 | printer->println("onSubscribe (data)");
116 | }
117 | #endif
118 |
119 | if(subValue > 0){
120 | PhyphoxBLE::isSubscribed=true;
121 | }
122 | };
123 | };
124 | #else
125 | class MyDataDescCallback: public BLEDescriptorCallbacks {
126 | private:
127 | HardwareSerial* printer;
128 |
129 | public:
130 | MyDataDescCallback(HardwareSerial* hwPrint) {
131 | printer = hwPrint;
132 | }
133 |
134 | private:
135 |
136 | void onWrite(BLEDescriptor* pDescriptor) override {
137 | #ifdef DEBUG
138 | if(printer){
139 | printer->println("descriptor write (data)");
140 | }
141 | #endif
142 | uint8_t* rxValue = pDescriptor->getValue();
143 |
144 | if(pDescriptor->getLength() > 0){
145 | PhyphoxBLE::isSubscribed=true;
146 | }
147 | };
148 | };
149 | #endif
150 |
151 | class MyEventCallback: public BLECharacteristicCallbacks {
152 | private:
153 | HardwareSerial* printer;
154 |
155 | public:
156 | MyEventCallback(HardwareSerial* hwPrint) {
157 | printer = hwPrint;
158 | }
159 | private:
160 |
161 | void onWrite(BLECharacteristic *pCharacteristic) override {
162 | #ifdef DEBUG
163 | if(printer){
164 | printer->println("characteristic write (event)");
165 | }
166 | #endif
167 | PhyphoxBLE::eventCharacteristicHandler();
168 | };
169 | };
170 |
171 | class MyCharCallback: public BLECharacteristicCallbacks {
172 | private:
173 | HardwareSerial* printer;
174 |
175 | public:
176 | MyCharCallback(HardwareSerial* hwPrint) {
177 | printer = hwPrint;
178 | }
179 | private:
180 | PhyphoxBLE* myServerPointer;
181 | void onWrite(BLECharacteristic *pCharacteristic) override {
182 | #ifdef DEBUG
183 | if(printer){
184 | printer->println("characteristic write (config)");
185 | }
186 | #endif
187 | PhyphoxBLE::configHandlerDebug();
188 | }
189 | };
190 |
191 | class MyServerCallbacks: public BLEServerCallbacks {
192 |
193 | private:
194 | HardwareSerial* printer;
195 |
196 | public:
197 | MyServerCallbacks(HardwareSerial* hwPrint) {
198 | printer = hwPrint;
199 | }
200 |
201 | #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
202 | void onConnect(BLEServer *pServer, ble_gap_conn_desc *desc) override {
203 | #ifdef DEBUG
204 | if(printer){
205 | printer->println("onConnect (NimBLE)");
206 | }
207 | #endif
208 | pServer->updateConnParams(desc->conn_handle, PhyphoxBLE::minConInterval, PhyphoxBLE::maxConInterval, PhyphoxBLE::slaveLatency, PhyphoxBLE::timeout);
209 | PhyphoxBLE::currentConnections+=1;
210 | };
211 | #else
212 | void onConnect(BLEServer* pServer, esp_ble_gatts_cb_param_t *param) override {
213 | #ifdef DEBUG
214 | if(printer){
215 | printer->println("onConnect (legacy)");
216 | }
217 | #endif
218 | pServer->updateConnParams(param->connect.remote_bda,PhyphoxBLE::minConInterval,PhyphoxBLE::maxConInterval,PhyphoxBLE::slaveLatency,PhyphoxBLE::timeout);
219 | PhyphoxBLE::currentConnections+=1;
220 | };
221 | #endif
222 |
223 | void onDisconnect(BLEServer* pServer) override {
224 | PhyphoxBLE::disconnected();
225 | PhyphoxBLE::currentConnections-=1;
226 | }
227 |
228 |
229 | };
230 |
231 | void PhyphoxBLE::configHandlerDebug(){
232 | if(configHandler!=nullptr){
233 | (*configHandler)();
234 | }
235 | }
236 |
237 | void PhyphoxBLE::eventCharacteristicHandler(){
238 | uint8_t* data = eventCharacteristic->getData();
239 | memcpy(&eventData[0],data,17);
240 | int64_t et,st;
241 | memcpy(&et,data+1,8);
242 | memcpy(&st,data+1+8,8);
243 | PhyphoxBLE::eventType = eventData[0];
244 | PhyphoxBLE::systemTime = swap_int64(st);
245 | PhyphoxBLE::experimentTime = swap_int64(et);
246 | if(experimentEventHandler!=nullptr){
247 | (*experimentEventHandler)();
248 | }
249 | }
250 |
251 | void PhyphoxBLE::setMTU(uint16_t mtuSize) {
252 | BLEDevice::setMTU(mtuSize+3); //user mtu size + 3 for overhead
253 |
254 | PhyphoxBLE::MTU = mtuSize;
255 | PhyphoxBleExperiment::MTU = mtuSize;
256 | }
257 |
258 | void PhyphoxBLE::start(const char* DEVICE_NAME, uint8_t* exp_pointer, size_t len){
259 | p_exp = exp_pointer;
260 | expLen = len;
261 | start(DEVICE_NAME);
262 | }
263 |
264 | void PhyphoxBLE::start(uint8_t* exp_pointer, size_t len){
265 | p_exp = exp_pointer;
266 | expLen = len;
267 | start();
268 | }
269 |
270 | void PhyphoxBLE::start(const char * DEVICE_NAME)
271 | {
272 | deviceName = DEVICE_NAME;
273 | #ifdef DEBUG
274 | if(printer){
275 | printer->println("starting server");
276 | }
277 | #endif
278 | if(p_exp == nullptr){
279 | PhyphoxBleExperiment defaultExperiment;
280 |
281 | //View
282 | PhyphoxBleExperiment::View firstView;
283 |
284 | //Graph
285 | PhyphoxBleExperiment::Graph firstGraph; //Create graph which will plot random numbers over time
286 | firstGraph.setChannel(0,1);
287 |
288 | //Value
289 | PhyphoxBleExperiment::Value valueField;
290 | valueField.setChannel(1);
291 |
292 | firstView.addElement(firstGraph);
293 | firstView.addElement(valueField);
294 | defaultExperiment.addView(firstView);
295 |
296 | addExperiment(defaultExperiment);
297 | }
298 |
299 | BLEDevice::init(DEVICE_NAME);
300 | myServer = BLEDevice::createServer();
301 | myServer->setCallbacks(new MyServerCallbacks(printer));
302 | phyphoxExperimentService = myServer->createService(phyphoxBleExperimentServiceUUID);
303 |
304 | experimentCharacteristic = phyphoxExperimentService->createCharacteristic(
305 | phyphoxBleExperimentCharacteristicUUID,
306 | BLECharacteristic::PROPERTY_READ |
307 | BLECharacteristic::PROPERTY_WRITE |
308 | BLECharacteristic::PROPERTY_NOTIFY
309 | );
310 | eventCharacteristic = phyphoxExperimentService->createCharacteristic(
311 | phyphoxBleEventCharacteristicUUID,
312 | BLECharacteristic::PROPERTY_WRITE
313 | );
314 |
315 | phyphoxDataService = myServer->createService(phyphoxBleDataServiceUUID);
316 |
317 | dataCharacteristic = phyphoxDataService->createCharacteristic(
318 | phyphoxBleDataCharacteristicUUID,
319 | BLECharacteristic::PROPERTY_READ |
320 | BLECharacteristic::PROPERTY_WRITE |
321 | BLECharacteristic::PROPERTY_NOTIFY
322 |
323 | );
324 |
325 | configCharacteristic = phyphoxDataService->createCharacteristic(
326 | phyphoxBleConfigCharacteristicUUID,
327 | BLECharacteristic::PROPERTY_READ |
328 | BLECharacteristic::PROPERTY_WRITE |
329 | BLECharacteristic::PROPERTY_NOTIFY
330 | );
331 |
332 | myExperimentDescriptor = new BLE2902();
333 | myDataDescriptor = new BLE2902();
334 | myEventDescriptor = new BLE2902();
335 | myConfigDescriptor = new BLE2902();
336 |
337 | #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
338 | experimentCharacteristic->setCallbacks(new MyExpCallback(printer));
339 | dataCharacteristic->setCallbacks(new MyDataCallback(printer));
340 | #else
341 | myExperimentDescriptor->setCallbacks(new MyExpDescCallback(printer));
342 | myDataDescriptor->setCallbacks(new MyDataDescCallback(printer));
343 | #endif
344 | eventCharacteristic->setCallbacks(new MyEventCallback(printer));
345 | configCharacteristic->setCallbacks(new MyCharCallback(printer));
346 |
347 | dataCharacteristic->addDescriptor(myDataDescriptor);
348 | experimentCharacteristic->addDescriptor(myExperimentDescriptor);
349 | eventCharacteristic->addDescriptor(myEventDescriptor);
350 | configCharacteristic->addDescriptor(myConfigDescriptor);
351 |
352 |
353 | phyphoxExperimentService->start();
354 | phyphoxDataService->start();
355 | myAdvertising = BLEDevice::getAdvertising();
356 | myAdvertising->addServiceUUID(phyphoxExperimentService->getUUID());
357 | BLEDevice::startAdvertising();
358 |
359 | }
360 |
361 | void PhyphoxBLE::start() {
362 | PhyphoxBLE::start("phyphox-Arduino");
363 | }
364 |
365 | void PhyphoxBLE::poll() {
366 | }
367 |
368 | void PhyphoxBLE::poll(int timeout) {
369 | }
370 |
371 | //thank you stackoverflow =)
372 | void PhyphoxBLE::staticStartTask(void* _this){
373 | PhyphoxBLE::when_subscription_received();
374 | delay(1);
375 | }
376 |
377 | void PhyphoxBLE::startTask()
378 | {
379 | xTaskCreatePinnedToCore(staticStartTask, "TaskTransfer",10000, NULL,1, &TaskTransfer, tskNO_AFFINITY);
380 | delay(1);
381 | }
382 |
383 | void PhyphoxBLE::write(float& value)
384 | {
385 | /**
386 | * \brief Write a single float into characteristic
387 | * The float is parsed to uint8_t*
388 | * because the gattServer write method
389 | * expects a pointer to uint8_t
390 | * \param f1 represent a float most likeley sensor data
391 | */
392 | data = reinterpret_cast(&value);
393 | dataCharacteristic->setValue(data,4);
394 | dataCharacteristic->notify();
395 | }
396 |
397 | void PhyphoxBLE::write(float& f1, float& f2)
398 | {
399 | float array[2] = {f1, f2};
400 | data = reinterpret_cast(array);
401 | dataCharacteristic->setValue(data,8);
402 | dataCharacteristic->notify();
403 | }
404 | void PhyphoxBLE::write(float& f1, float& f2, float& f3)
405 | {
406 | float array[3] = {f1, f2, f3};
407 | data = reinterpret_cast(array);
408 | dataCharacteristic->setValue(data,12);
409 | dataCharacteristic->notify();
410 | }
411 | void PhyphoxBLE::write(float& f1, float& f2, float& f3, float& f4)
412 | {
413 | float array[4] = {f1, f2, f3, f4};
414 | data = reinterpret_cast(array);
415 | dataCharacteristic->setValue(data,16);
416 | dataCharacteristic->notify();
417 | }
418 | void PhyphoxBLE::write(float& f1, float& f2, float& f3, float& f4, float& f5)
419 | {
420 | float array[5] = {f1, f2, f3, f4, f5};
421 | data = reinterpret_cast(array);
422 | dataCharacteristic->setValue(data,20);
423 | dataCharacteristic->notify();
424 | }
425 | void PhyphoxBLE::write(uint8_t *arrayPointer, unsigned int arraySize)
426 | {
427 | dataCharacteristic->setValue(arrayPointer,arraySize);
428 | dataCharacteristic->notify();
429 | }
430 | void PhyphoxBLE::write(float *arrayPointer, unsigned int arrayLength)
431 | {
432 | uint8_t dataBuffer[arrayLength*4];
433 | memcpy(&dataBuffer[0], &arrayPointer[0],arrayLength*4);
434 | dataCharacteristic->setValue(&dataBuffer[0],arrayLength*4);
435 | dataCharacteristic->notify();
436 | }
437 |
438 |
439 | void PhyphoxBLE::read(uint8_t *arrayPointer, unsigned int arraySize)
440 | {
441 | uint8_t* data = configCharacteristic->getData();
442 | memcpy(arrayPointer,data,arraySize);
443 | }
444 |
445 | void PhyphoxBLE::read(float& f)
446 | {
447 | uint8_t* data = configCharacteristic->getData();
448 | memcpy(&f,data,4);
449 | }
450 | void PhyphoxBLE::read(float& f1, float& f2)
451 | {
452 | uint8_t* data = configCharacteristic->getData();
453 | memcpy(&f1,data,4);
454 | memcpy(&f2,data+4,4);
455 | }
456 | void PhyphoxBLE::read(float& f1, float& f2, float& f3)
457 | {
458 | uint8_t* data = configCharacteristic->getData();
459 | memcpy(&f1,data,4);
460 | memcpy(&f2,data+4,4);
461 | memcpy(&f3,data+8,4);
462 | }
463 | void PhyphoxBLE::read(float& f1, float& f2, float& f3, float& f4)
464 | {
465 | uint8_t* data = configCharacteristic->getData();
466 | memcpy(&f1,data,4);
467 | memcpy(&f2,data+4,4);
468 | memcpy(&f3,data+8,4);
469 | memcpy(&f4,data+12,4);
470 | }
471 | void PhyphoxBLE::read(float& f1, float& f2, float& f3, float& f4, float& f5)
472 | {
473 | uint8_t* data = configCharacteristic->getData();
474 | memcpy(&f1,data,4);
475 | memcpy(&f2,data+4,4);
476 | memcpy(&f3,data+8,4);
477 | memcpy(&f4,data+12,4);
478 | memcpy(&f5,data+16,4);
479 | }
480 |
481 |
482 | void PhyphoxBLE::when_subscription_received()
483 | {
484 |
485 | myAdvertising->stop();
486 |
487 | uint8_t* exp = p_exp;
488 | size_t exp_len = expLen;
489 |
490 | uint8_t header[20] = {0}; //20 byte as standard package size for ble transfer
491 | const char phyphox[] = "phyphox";
492 | uint32_t table[256];
493 | phyphoxBleCrc32::generate_table(table);
494 | uint32_t checksum = phyphoxBleCrc32::update(table, 0, exp, exp_len);
495 | size_t arrayLength = exp_len;
496 | uint8_t experimentSizeArray[4] = {0};
497 | experimentSizeArray[0]= (arrayLength >> 24);
498 | experimentSizeArray[1]= (arrayLength >> 16);
499 | experimentSizeArray[2]= (arrayLength >> 8);
500 | experimentSizeArray[3]= arrayLength;
501 |
502 | uint8_t checksumArray[4] = {0};
503 | checksumArray[0]= (checksum >> 24) & 0xFF;
504 | checksumArray[1]= (checksum >> 16) & 0xFF;
505 | checksumArray[2]= (checksum >> 8) & 0xFF;
506 | checksumArray[3]= checksum & 0xFF;
507 |
508 | copy(phyphox, phyphox+7, header);
509 | copy(experimentSizeArray, experimentSizeArray+ 4, header + 7);
510 | copy(checksumArray, checksumArray + 4, header +11);
511 | experimentCharacteristic->setValue(header,sizeof(header));
512 | experimentCharacteristic->notify();
513 |
514 | for(size_t i = 0; i < exp_len/20; ++i){
515 | copy(exp+i*20, exp+i*20+20, header);
516 | experimentCharacteristic->setValue(header,sizeof(header));
517 | experimentCharacteristic->notify();
518 | delay(10);// mh does not work anymore with 1ms delay?!
519 | }
520 |
521 | if(exp_len%20 != 0){
522 | const size_t rest = exp_len%20;
523 | uint8_t slice[rest];
524 | copy(exp + exp_len - rest, exp + exp_len, slice);
525 | experimentCharacteristic->setValue(slice,sizeof(slice));
526 | experimentCharacteristic->notify();
527 | delay(1);
528 | }
529 |
530 |
531 | myAdvertising->start();
532 |
533 |
534 | vTaskDelete( NULL );
535 |
536 | }
537 | void PhyphoxBLE::addExperiment(PhyphoxBleExperiment& exp)
538 | {
539 | for (int i = 0; i < 16000; i++)
540 | {
541 | storage[i]=0;
542 | }
543 |
544 | exp.getFirstBytes(EXPARRAY, deviceName);
545 | for(uint8_t i=0;i println("device disconnected");
559 | }
560 | #endif
561 | myAdvertising->start();
562 | }
563 |
564 |
565 | void PhyphoxBLE::begin(HardwareSerial* hwPrint)
566 | {
567 | #ifdef DEBUG
568 | printer = hwPrint;
569 | if(printer)
570 | printer->begin(115200);
571 | #endif
572 | }
573 |
574 | void PhyphoxBLE::printXML(HardwareSerial* printer){
575 | printer->println("");
576 | for(int i =0; iprint(CHAR);
579 | }
580 | printer->println("");
581 | }
582 |
583 | #endif
584 |
--------------------------------------------------------------------------------
/examples/CO2kit/CO2kit.ino:
--------------------------------------------------------------------------------
1 | /*
2 | Dies ist eine aktualisierte Version des Arduino Codes für das phyphox CO2 Monitor Kit
3 |
4 | Um Ihren CO2-Monitor zu aktualisieren, löschen Sie in der phyphox App die Experimente "CO2-Sensor" und "CO₂-Sensor Maintenance"
5 | und folgen Sie dem Software-Teil der Aufbauanleitung.
6 | https://phyphox.org/wp-content/uploads/2021/03/CO2-Monitor-Rev_1_1.pdf
7 |
8 |
9 | This is an updated version of the Arduino Code for the phyphox CO2 Monitor Kit
10 |
11 | To update your CO2 Monitor delete in the phyphox app the experiements "CO2-Sensor" and "CO₂-Sensor Maintenance"
12 | and follow the software part of the assembly instructions
13 | https://phyphox.org/wp-content/uploads/2021/03/CO2-Monitor-Rev_1_1.pdf
14 | */
15 |
16 |
17 | #include
18 | #include "SparkFun_SCD30_Arduino_Library.h"
19 | #include
20 | #include
21 |
22 | //LED Update Thresholds
23 | //Can be set as desired
24 | float topThreshold = 1000;
25 | float bottomThreshold = 600;
26 |
27 |
28 | bool FORMATFLASH = true;
29 |
30 | SCD30 airSensor;
31 | File fsUploadFile; // a File variable to temporarily store the received file
32 |
33 | int maxDatasets = 7200; //store data every 12s over 24h -> maxDatasets = 24*60*60/12 = 7200
34 | int transferedDatasets = 11; //mtu size = 176 -> 4*4*11 = 176
35 |
36 | const int measuredDataLength = 4;
37 | float measuredData[measuredDataLength]; //co2,temperature,humidity,seconds since uptime, number of dataset
38 |
39 | float averageMeasuredData[measuredDataLength];
40 | int averageOver = 6; //6*2s rate = store data every 12s
41 | int averageCounter = 0;
42 | int oldDataTransmissionOffset = -1;
43 | int lineNumber = 0;
44 |
45 | void receivedConfig();
46 | long timeStampBlue = -3; //used to timestamp the moment of connection
47 | int currentConnections = 0;
48 | //Pinout
49 | int pinGreen = 26;
50 | int pinRed = 33;
51 | int pinBlue = 25;
52 | bool RED = 1;
53 | bool GREEN = 0;
54 | bool BLUE = 1;
55 | int readyPin = 5;
56 |
57 |
58 | uint8_t versionID = 3;
59 | uint8_t currentOffset;
60 | uint8_t statusCO2calibration = 0;
61 | /*
62 | The following byte array contains the complete phyphox experiment.
63 | The phyphox experiment (xml-file) where the byte array is generated from can be found in the github repository https://github.com/Dorsel89/phyphox-hardware (CO2-Monitor Kit folder).
64 | */
65 | uint8_t CO2Monitor[2877] = {80, 75, 3, 4, 20, 0, 0, 0, 8, 0, 129, 91, 97, 84, 18, 124, 19, 223, 161, 10, 0, 0, 113, 58, 0, 0, 11, 0, 0, 0, 99, 111, 50, 46, 112, 104, 121, 112, 104, 111, 120, 213, 91, 221, 146, 219, 182, 21, 190, 222, 206, 244, 29, 80, 206, 120, 98, 79, 35, 81, 210, 202, 187, 30, 143, 86, 157, 141, 29, 39, 158, 38, 217, 142, 215, 205, 79, 61, 30, 15, 68, 130, 75, 100, 33, 128, 5, 193, 213, 202, 147, 43, 191, 72, 111, 114, 223, 62, 64, 175, 226, 55, 201, 147, 244, 0, 32, 41, 146, 162, 36, 80, 145, 215, 169, 60, 182, 68, 242, 156, 131, 239, 252, 226, 0, 132, 39, 73, 188, 76, 98, 113, 139, 110, 136, 76, 169, 224, 103, 222, 176, 63, 28, 120, 211, 63, 254, 1, 193, 103, 162, 168, 98, 100, 250, 228, 226, 215, 119, 239, 122, 95, 11, 78, 149, 144, 19, 223, 222, 204, 41, 2, 172, 200, 149, 144, 203, 156, 232, 146, 240, 84, 211, 148, 183, 11, 50, 193, 132, 156, 142, 142, 207, 207, 199, 167, 19, 223, 94, 229, 143, 66, 146, 6, 146, 38, 10, 70, 159, 190, 140, 105, 138, 200, 109, 66, 36, 157, 19, 174, 208, 13, 77, 51, 204, 232, 91, 146, 34, 21, 19, 148, 26, 233, 40, 196, 10, 35, 17, 153, 91, 5, 126, 51, 124, 78, 208, 71, 207, 128, 106, 46, 36, 65, 148, 71, 66, 206, 177, 22, 254, 169, 150, 70, 149, 225, 202, 169, 169, 34, 90, 78, 46, 163, 47, 228, 85, 31, 189, 140, 137, 36, 134, 8, 39, 9, 163, 129, 225, 69, 32, 5, 100, 133, 2, 190, 48, 213, 178, 141, 45, 40, 191, 66, 22, 48, 195, 148, 147, 176, 143, 126, 16, 25, 10, 48, 71, 152, 165, 2, 69, 192, 97, 97, 84, 84, 162, 33, 193, 41, 90, 80, 21, 3, 158, 144, 8, 163, 153, 36, 253, 137, 95, 53, 68, 110, 27, 26, 216, 177, 65, 131, 51, 47, 85, 122, 64, 207, 90, 122, 226, 211, 160, 164, 179, 190, 146, 152, 167, 204, 192, 77, 55, 220, 71, 76, 4, 152, 145, 51, 143, 112, 175, 66, 210, 116, 53, 154, 183, 185, 186, 248, 56, 186, 188, 248, 124, 8, 255, 182, 217, 202, 140, 229, 87, 148, 221, 101, 131, 144, 108, 179, 65, 239, 235, 15, 101, 131, 167, 148, 164, 160, 239, 231, 43, 43, 164, 138, 48, 166, 80, 72, 9, 178, 130, 192, 0, 132, 35, 96, 106, 168, 127, 89, 216, 7, 66, 252, 59, 2, 209, 11, 161, 245, 124, 21, 225, 132, 155, 144, 131, 175, 75, 16, 133, 179, 168, 100, 211, 129, 126, 35, 120, 25, 233, 232, 169, 144, 10, 130, 80, 134, 102, 212, 115, 190, 32, 60, 204, 32, 154, 223, 102, 18, 189, 192, 217, 156, 101, 145, 122, 255, 223, 25, 145, 11, 28, 196, 250, 1, 145, 215, 236, 253, 207, 82, 245, 209, 121, 246, 254, 95, 68, 134, 100, 94, 29, 44, 52, 242, 114, 72, 21, 213, 158, 135, 4, 40, 230, 144, 118, 223, 154, 96, 223, 232, 58, 99, 38, 27, 225, 8, 18, 235, 138, 114, 204, 206, 188, 23, 224, 163, 207, 8, 35, 89, 16, 43, 64, 145, 166, 10, 48, 92, 147, 137, 111, 41, 29, 248, 225, 14, 185, 129, 44, 103, 161, 9, 43, 111, 250, 5, 73, 19, 66, 3, 200, 57, 176, 201, 83, 99, 104, 172, 77, 24, 18, 201, 157, 229, 190, 36, 115, 80, 17, 171, 76, 2, 192, 213, 133, 51, 255, 151, 217, 156, 134, 84, 45, 189, 233, 87, 96, 232, 200, 232, 71, 175, 174, 193, 126, 206, 34, 212, 111, 132, 16, 31, 0, 2, 248, 216, 155, 254, 163, 11, 203, 83, 227, 3, 99, 118, 103, 158, 111, 41, 89, 120, 211, 115, 158, 130, 215, 220, 71, 122, 146, 73, 105, 147, 11, 204, 146, 62, 6, 1, 215, 42, 131, 60, 35, 18, 93, 218, 91, 200, 89, 22, 23, 101, 0, 33, 73, 2, 66, 111, 72, 232, 77, 191, 17, 65, 140, 192, 96, 188, 136, 35, 112, 66, 132, 249, 85, 7, 213, 214, 164, 62, 134, 18, 199, 72, 160, 16, 134, 236, 98, 144, 77, 104, 70, 152, 88, 180, 134, 109, 57, 220, 99, 180, 120, 255, 115, 204, 8, 202, 184, 185, 79, 57, 84, 5, 224, 189, 193, 140, 65, 25, 72, 157, 225, 92, 198, 98, 97, 241, 68, 82, 204, 97, 232, 72, 228, 115, 33, 88, 81, 170, 162, 38, 87, 10, 184, 158, 23, 193, 58, 115, 75, 135, 185, 13, 135, 8, 234, 148, 198, 14, 57, 165, 27, 139, 43, 131, 146, 112, 139, 251, 177, 51, 156, 33, 138, 69, 38, 189, 233, 16, 60, 150, 65, 169, 113, 102, 28, 25, 198, 212, 155, 142, 114, 78, 119, 143, 140, 11, 214, 113, 103, 214, 81, 201, 59, 234, 206, 92, 134, 171, 113, 63, 212, 198, 74, 196, 66, 201, 77, 23, 56, 102, 238, 150, 19, 156, 45, 17, 131, 128, 202, 139, 222, 55, 153, 180, 151, 221, 50, 239, 5, 209, 115, 38, 176, 173, 138, 69, 121, 107, 239, 170, 33, 9, 235, 107, 129, 125, 35, 172, 111, 5, 245, 221, 13, 133, 229, 12, 102, 178, 144, 138, 91, 170, 167, 240, 191, 138, 152, 233, 112, 19, 81, 100, 239, 57, 75, 130, 153, 80, 137, 116, 201, 33, 164, 211, 90, 91, 226, 77, 255, 86, 121, 84, 157, 207, 90, 100, 183, 245, 28, 19, 191, 165, 25, 155, 48, 202, 175, 17, 195, 51, 98, 198, 46, 91, 78, 232, 134, 71, 30, 138, 233, 85, 204, 224, 47, 244, 121, 17, 102, 41, 40, 22, 43, 149, 164, 143, 125, 127, 177, 88, 244, 27, 228, 254, 196, 215, 194, 218, 5, 111, 82, 106, 199, 16, 75, 145, 169, 108, 70, 250, 129, 152, 251, 11, 172, 130, 248, 47, 55, 103, 151, 217, 143, 163, 243, 31, 111, 191, 188, 24, 95, 215, 70, 204, 199, 213, 177, 213, 11, 4, 87, 186, 249, 149, 181, 166, 179, 188, 11, 77, 246, 91, 104, 182, 96, 73, 17, 136, 55, 148, 79, 252, 242, 201, 14, 114, 61, 191, 117, 98, 128, 144, 234, 54, 0, 152, 101, 141, 97, 11, 203, 208, 168, 192, 197, 194, 113, 136, 97, 174, 67, 39, 14, 173, 196, 26, 195, 78, 187, 234, 113, 58, 90, 182, 27, 139, 134, 213, 141, 195, 88, 119, 157, 101, 151, 42, 85, 234, 237, 180, 157, 21, 232, 134, 189, 78, 189, 155, 62, 164, 81, 212, 109, 132, 64, 64, 197, 15, 84, 71, 87, 135, 52, 133, 197, 230, 178, 155, 157, 186, 115, 105, 135, 119, 102, 50, 62, 111, 229, 218, 26, 244, 176, 176, 166, 170, 20, 240, 150, 72, 225, 158, 47, 73, 162, 121, 186, 210, 175, 143, 225, 8, 144, 95, 176, 176, 206, 120, 116, 180, 149, 161, 232, 235, 116, 223, 187, 215, 136, 50, 95, 193, 124, 150, 41, 37, 92, 171, 219, 67, 111, 58, 91, 42, 114, 46, 101, 155, 251, 38, 126, 123, 225, 158, 80, 158, 100, 170, 42, 119, 198, 50, 162, 132, 80, 49, 162, 225, 153, 247, 228, 2, 230, 41, 142, 231, 36, 255, 9, 93, 95, 72, 116, 115, 172, 104, 148, 239, 147, 120, 8, 22, 33, 86, 131, 52, 155, 233, 117, 222, 140, 92, 240, 75, 221, 60, 22, 147, 14, 154, 171, 12, 8, 78, 79, 214, 86, 223, 48, 1, 193, 248, 40, 136, 177, 60, 243, 130, 48, 140, 134, 131, 193, 168, 119, 60, 136, 78, 123, 227, 147, 211, 97, 239, 209, 108, 124, 220, 123, 72, 198, 131, 25, 126, 120, 252, 112, 56, 198, 30, 2, 29, 202, 141, 171, 136, 9, 172, 142, 71, 95, 81, 5, 235, 245, 207, 121, 72, 161, 27, 133, 142, 53, 74, 9, 140, 125, 12, 200, 72, 66, 176, 210, 45, 0, 12, 127, 82, 206, 71, 118, 212, 187, 196, 114, 186, 142, 197, 36, 233, 199, 65, 51, 28, 174, 195, 209, 217, 95, 67, 115, 116, 116, 244, 97, 65, 60, 92, 7, 81, 206, 207, 85, 20, 213, 190, 171, 140, 206, 50, 174, 171, 1, 60, 41, 217, 182, 132, 115, 211, 208, 148, 175, 169, 120, 236, 174, 98, 153, 115, 181, 244, 171, 130, 218, 4, 188, 134, 117, 130, 161, 61, 93, 234, 238, 45, 101, 132, 36, 80, 6, 250, 144, 109, 130, 255, 61, 37, 242, 185, 22, 86, 164, 82, 189, 138, 252, 169, 215, 123, 227, 242, 233, 245, 166, 117, 174, 159, 86, 6, 184, 36, 10, 105, 187, 35, 93, 33, 171, 150, 249, 105, 141, 235, 151, 127, 31, 234, 143, 17, 93, 23, 142, 104, 132, 138, 66, 173, 119, 88, 7, 159, 162, 5, 172, 66, 48, 172, 59, 160, 220, 160, 37, 192, 12, 9, 172, 48, 231, 122, 215, 213, 130, 21, 220, 172, 77, 111, 17, 190, 165, 41, 172, 42, 136, 250, 36, 69, 89, 106, 151, 175, 90, 22, 44, 97, 231, 137, 94, 194, 98, 190, 68, 156, 228, 11, 221, 68, 80, 88, 117, 97, 189, 81, 171, 155, 94, 164, 55, 136, 133, 225, 177, 62, 41, 214, 188, 90, 130, 222, 247, 13, 51, 70, 250, 168, 9, 217, 60, 109, 207, 218, 114, 138, 90, 143, 71, 191, 96, 171, 220, 3, 197, 25, 73, 211, 51, 79, 201, 12, 138, 37, 249, 103, 134, 89, 126, 177, 33, 88, 25, 193, 178, 140, 136, 194, 104, 235, 97, 87, 97, 81, 203, 4, 106, 244, 13, 102, 90, 232, 96, 43, 105, 93, 122, 161, 74, 43, 131, 213, 175, 149, 195, 34, 106, 49, 0, 141, 254, 143, 180, 47, 11, 146, 187, 250, 157, 148, 63, 64, 2, 151, 251, 157, 51, 211, 46, 124, 164, 4, 198, 73, 66, 120, 232, 96, 253, 225, 161, 28, 245, 17, 73, 115, 191, 99, 8, 90, 248, 89, 171, 252, 149, 137, 107, 226, 151, 70, 169, 135, 123, 215, 16, 111, 246, 131, 135, 212, 20, 154, 16, 181, 244, 144, 191, 69, 69, 73, 210, 140, 41, 175, 0, 101, 97, 183, 169, 188, 57, 204, 75, 67, 28, 202, 226, 77, 147, 236, 52, 251, 1, 18, 237, 220, 136, 93, 77, 35, 191, 191, 68, 171, 135, 77, 32, 58, 86, 174, 98, 171, 99, 167, 49, 221, 49, 148, 77, 174, 59, 138, 213, 6, 202, 1, 113, 20, 221, 173, 59, 12, 205, 113, 48, 20, 54, 103, 246, 112, 200, 33, 135, 223, 211, 23, 135, 132, 176, 151, 27, 14, 9, 96, 207, 249, 252, 195, 23, 152, 75, 33, 109, 75, 26, 18, 6, 93, 46, 10, 51, 123, 16, 129, 164, 232, 142, 11, 76, 42, 164, 115, 107, 212, 161, 147, 10, 68, 7, 98, 27, 119, 206, 228, 38, 72, 28, 60, 90, 137, 129, 70, 100, 239, 100, 10, 68, 103, 22, 77, 223, 153, 105, 181, 235, 218, 50, 173, 230, 174, 217, 103, 98, 29, 109, 53, 80, 101, 59, 179, 101, 216, 182, 112, 215, 196, 68, 191, 189, 162, 16, 163, 174, 225, 242, 198, 106, 214, 45, 247, 54, 194, 106, 66, 168, 60, 147, 250, 237, 163, 125, 153, 234, 138, 77, 75, 115, 110, 173, 76, 35, 2, 11, 209, 93, 237, 236, 218, 252, 218, 49, 176, 43, 33, 212, 37, 25, 186, 178, 184, 249, 102, 155, 55, 170, 100, 129, 216, 65, 176, 59, 39, 26, 101, 127, 19, 152, 214, 176, 168, 251, 254, 112, 21, 26, 62, 95, 16, 174, 79, 92, 216, 157, 1, 179, 233, 96, 110, 223, 117, 133, 214, 135, 127, 50, 134, 81, 254, 125, 230, 221, 127, 53, 124, 243, 186, 247, 106, 244, 250, 207, 175, 142, 95, 63, 112, 94, 54, 111, 240, 246, 222, 171, 236, 205, 219, 0, 187, 162, 170, 124, 47, 210, 226, 207, 92, 203, 195, 249, 242, 153, 137, 13, 115, 140, 193, 190, 121, 39, 161, 117, 168, 137, 156, 59, 246, 101, 61, 90, 127, 167, 179, 104, 27, 117, 205, 109, 174, 92, 171, 186, 105, 223, 170, 108, 139, 139, 234, 139, 175, 157, 229, 196, 145, 180, 246, 138, 107, 103, 121, 217, 66, 218, 94, 102, 38, 126, 177, 141, 155, 147, 78, 110, 40, 89, 20, 23, 229, 141, 226, 189, 189, 61, 24, 213, 24, 255, 74, 226, 36, 46, 40, 26, 7, 31, 16, 163, 156, 124, 71, 67, 21, 159, 121, 35, 189, 15, 205, 4, 152, 86, 159, 176, 29, 159, 122, 150, 231, 251, 252, 136, 150, 189, 250, 65, 111, 121, 255, 250, 238, 157, 135, 50, 78, 21, 60, 75, 73, 96, 127, 195, 147, 36, 153, 123, 38, 240, 47, 248, 247, 197, 238, 91, 186, 76, 193, 156, 47, 233, 156, 180, 239, 79, 160, 149, 99, 117, 249, 59, 243, 110, 155, 175, 0, 205, 195, 93, 92, 203, 250, 123, 205, 214, 48, 240, 141, 37, 154, 119, 205, 252, 187, 201, 60, 229, 171, 180, 4, 194, 146, 218, 13, 122, 176, 83, 26, 80, 221, 37, 68, 52, 40, 227, 48, 51, 239, 218, 140, 5, 54, 98, 45, 215, 195, 237, 240, 12, 146, 230, 221, 148, 36, 24, 102, 8, 40, 45, 49, 177, 199, 46, 134, 45, 155, 43, 53, 31, 87, 207, 21, 22, 46, 141, 162, 32, 28, 226, 77, 46, 173, 30, 3, 108, 115, 236, 47, 255, 121, 242, 17, 29, 171, 209, 253, 118, 215, 214, 172, 210, 213, 175, 218, 0, 27, 145, 86, 54, 24, 62, 172, 99, 215, 79, 82, 149, 25, 59, 56, 61, 126, 118, 190, 201, 189, 171, 195, 82, 109, 206, 189, 247, 17, 93, 91, 43, 159, 251, 122, 182, 197, 44, 93, 253, 123, 111, 179, 138, 171, 125, 27, 119, 231, 54, 104, 242, 125, 244, 18, 238, 218, 113, 226, 58, 125, 199, 141, 110, 67, 158, 207, 39, 27, 119, 49, 93, 228, 247, 30, 157, 140, 7, 131, 221, 131, 216, 153, 182, 178, 127, 113, 116, 180, 55, 220, 234, 193, 134, 246, 233, 211, 183, 214, 107, 145, 82, 157, 60, 245, 44, 88, 33, 105, 251, 85, 155, 41, 237, 113, 96, 215, 148, 212, 26, 214, 66, 110, 237, 92, 112, 213, 12, 13, 181, 236, 189, 156, 96, 142, 19, 4, 237, 138, 62, 149, 129, 230, 248, 214, 156, 206, 104, 59, 24, 60, 241, 129, 114, 141, 105, 152, 51, 13, 189, 169, 235, 161, 223, 138, 160, 85, 172, 234, 11, 183, 250, 179, 162, 202, 43, 141, 48, 109, 138, 87, 50, 13, 250, 219, 217, 26, 194, 27, 116, 250, 127, 214, 20, 54, 61, 192, 185, 97, 132, 25, 189, 2, 59, 73, 61, 166, 231, 79, 183, 230, 97, 243, 120, 171, 91, 146, 116, 207, 143, 214, 104, 174, 157, 66, 64, 235, 224, 138, 83, 203, 142, 153, 123, 124, 50, 56, 16, 176, 173, 168, 202, 35, 209, 142, 176, 78, 71, 119, 2, 107, 220, 17, 214, 112, 60, 190, 27, 115, 117, 5, 182, 95, 1, 118, 1, 182, 37, 33, 55, 23, 183, 202, 41, 242, 90, 125, 179, 227, 239, 172, 107, 245, 4, 107, 175, 104, 38, 114, 115, 22, 251, 123, 106, 67, 127, 3, 249, 233, 104, 69, 110, 126, 79, 243, 152, 220, 64, 111, 92, 93, 48, 216, 139, 233, 184, 202, 113, 100, 50, 17, 254, 49, 102, 90, 49, 62, 58, 169, 48, 218, 139, 233, 104, 92, 229, 172, 213, 212, 82, 204, 134, 73, 201, 94, 148, 171, 56, 40, 98, 118, 231, 181, 226, 32, 149, 31, 139, 107, 171, 70, 230, 148, 116, 254, 92, 247, 101, 232, 62, 160, 124, 208, 236, 186, 52, 209, 22, 198, 39, 23, 35, 116, 31, 86, 40, 15, 234, 107, 165, 29, 92, 149, 190, 25, 221, 135, 62, 248, 65, 179, 33, 223, 193, 191, 214, 157, 161, 251, 247, 30, 52, 58, 191, 134, 136, 137, 15, 214, 40, 13, 87, 218, 106, 226, 231, 39, 216, 167, 255, 3, 80, 75, 1, 2, 31, 0, 20, 0, 0, 0, 8, 0, 129, 91, 97, 84, 18, 124, 19, 223, 161, 10, 0, 0, 113, 58, 0, 0, 11, 0, 36, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 99, 111, 50, 46, 112, 104, 121, 112, 104, 111, 120, 10, 0, 32, 0, 0, 0, 0, 0, 1, 0, 24, 0, 218, 42, 214, 7, 87, 45, 216, 1, 151, 133, 123, 7, 88, 45, 216, 1, 3, 16, 118, 7, 88, 45, 216, 1, 80, 75, 5, 6, 0, 0, 0, 0, 1, 0, 1, 0, 93, 0, 0, 0, 202, 10, 0, 0, 0, 0};
66 |
67 | void setup() {
68 |
69 | //Start the SPIFFS and list all contents
70 | Serial.println("init spiffs");
71 | initStorage();
72 | delay(50);
73 |
74 | //Start the BLE server
75 | PhyphoxBLE::start("CO2 Monitor", &CO2Monitor[0], sizeof(CO2Monitor));
76 | PhyphoxBLE::configHandler = &receivedConfig;
77 | PhyphoxBLE::setMTU(176);
78 |
79 | Serial.begin(115200);
80 |
81 | pinMode(readyPin, INPUT);
82 | //initialize rgb-led
83 | pinMode(pinGreen, OUTPUT);
84 | pinMode(pinRed, OUTPUT);
85 | pinMode(pinBlue, OUTPUT);
86 | digitalWrite(pinGreen, GREEN);
87 | digitalWrite(pinRed, RED);
88 | digitalWrite(pinBlue, BLUE);
89 |
90 | //initialize the air Sensor
91 | Wire.begin();
92 | if (airSensor.begin(Wire, false) == false)
93 | {
94 | Serial.println("Air sensor not detected. Please check wiring. Freezing...");
95 | while (1);
96 | }
97 |
98 | delay(200);
99 |
100 | Serial.print("Temperature offset: ");
101 | Serial.println(airSensor.getTemperatureOffset());
102 | currentOffset = airSensor.getTemperatureOffset() * 10;
103 | }
104 |
105 | void loop() {
106 | if (digitalRead(readyPin))
107 | {
108 | //read data
109 | measuredData[0] = airSensor.getCO2();
110 | measuredData[1] = airSensor.getTemperature();
111 | measuredData[2] = airSensor.getHumidity();
112 | measuredData[3] = millis() / 1000;
113 |
114 | //print data
115 | echoDataset("Measured", measuredData);
116 |
117 | uint8_t Data[20] = {0};
118 | Data[0] = currentOffset;
119 | Data[1] = statusCO2calibration;
120 | Data[2] = versionID;
121 | memcpy(&Data[3], &measuredData[0], 16);
122 |
123 | //Send data to phyphox
124 | PhyphoxBLE::write(&Data[0], 20);
125 |
126 | //calculate average Data over [averageOver] periods
127 | if (averageCounter == averageOver) {
128 | storeMeasuredData(averageMeasuredData);
129 | averageMeasuredData[0] = 0;
130 | averageMeasuredData[1] = 0;
131 | averageMeasuredData[2] = 0;
132 | averageMeasuredData[3] = 0;
133 | averageCounter = 0;
134 | }
135 | if (averageCounter < averageOver) {
136 | averageMeasuredData[0] += measuredData[0] / averageOver;
137 | averageMeasuredData[1] += measuredData[1] / averageOver;
138 | averageMeasuredData[2] += measuredData[2] / averageOver;
139 | averageMeasuredData[3] += measuredData[3] / averageOver;
140 | averageCounter += 1;
141 | }
142 |
143 | updateLED(measuredData[0]);
144 | delay(10);
145 | }
146 |
147 | //Data transfer loop
148 | if (oldDataTransmissionOffset >= 0) {
149 | if (transferOldData(oldDataTransmissionOffset))
150 | oldDataTransmissionOffset++;
151 | else {
152 | oldDataTransmissionOffset = -1;
153 | Serial.println("Transfer of old date completed.");
154 | }
155 | delay(10);
156 | }
157 | }
158 |
159 | //Print one dataset
160 | void echoDataset(String note, float * data) {
161 | Serial.print(note);
162 | Serial.print(" => CO2: ");
163 | Serial.print(data[0]);
164 | Serial.print(", Temperature: ");
165 | Serial.print(data[1]);
166 | Serial.print(", Humidity: ");
167 | Serial.print(data[2]);
168 | Serial.print(", Timestamp: ");
169 | Serial.println(data[3]);
170 | }
171 |
172 | // Start the SPIFFS and list all contents
173 | void initStorage() {
174 | if (!SPIFFS.begin(true)) {
175 | Serial.println("An Error has occurred while mounting SPIFFS");
176 | return;
177 | }
178 |
179 | if (FORMATFLASH) {
180 | bool formatted = SPIFFS.format();
181 | if ( formatted ) {
182 | Serial.println("SPIFFS formatted successfully");
183 | } else {
184 | Serial.println("Error formatting");
185 | }
186 | }
187 |
188 | int totalBytes = SPIFFS.totalBytes();
189 | int usedBytes = SPIFFS.usedBytes();
190 | Serial.print("total Bytes ");
191 | Serial.println(totalBytes);
192 | Serial.print("total Bytes ");
193 | Serial.println(usedBytes);
194 |
195 | File file = SPIFFS.open("/set.txt", FILE_WRITE);
196 | file.close();
197 | delay(1);
198 | }
199 |
200 | //Interpretation of received data
201 | void receivedConfig() {
202 | /*
203 | phyphox experiment may send an Array with 5 Bytes
204 | byte information
205 | 0 bool transfer Data
206 | 1 calibrate: 1=CO2 2=temperature
207 | 2 bool setColorBlue
208 | */
209 | //read data
210 | uint8_t readArray[6] = {0};
211 | PhyphoxBLE::read(&readArray[0], 6);
212 |
213 | //DATA TRANSFER
214 | if (readArray[0] == 1) {
215 | Serial.println("Resending of old data requested.");
216 | oldDataTransmissionOffset = 0;
217 | }
218 |
219 | //CO2 CALIBRATION
220 | if (readArray[1] == 1) {
221 | Serial.print("Calibration with fresh air ");
222 | airSensor.setAutoSelfCalibration(false);
223 | Serial.println(airSensor.setForcedRecalibrationFactor(400));
224 | statusCO2calibration = 1;
225 | }
226 |
227 | //TEMPERATURE CALIBRATION
228 | if (readArray[1] == 2) {
229 | Serial.print("Current Offset: ");
230 | Serial.print(airSensor.getTemperatureOffset());
231 | Serial.println(" °C");
232 | delay(50);
233 | currentOffset = readArray[5] / 10.0;
234 | if (currentOffset >= 0) {
235 | airSensor.setTemperatureOffset(currentOffset);
236 | }
237 | Serial.print("New Offset: ");
238 | Serial.print(currentOffset);
239 | Serial.println(" °C");
240 | delay(50);
241 | Serial.print("Restarting ESP32..");
242 | delay(1000);
243 | ESP.restart();
244 | }
245 |
246 | }
247 |
248 | //Transfer [transferedDatasets] datasets at position [offset]
249 | bool transferOldData(int offset) {
250 | int i_buffer = transferedDatasets;
251 | char buffer[4 * measuredDataLength * transferedDatasets];
252 |
253 | File file = SPIFFS.open("/set.txt", "r");
254 |
255 | //Check if enough datasets are available
256 | for (int i = 0; i < transferedDatasets; i++) {
257 | file.seek(offset * 4 * measuredDataLength * transferedDatasets + i * 4 * measuredDataLength, SeekSet);
258 | if (!file.available() && i == 0) {
259 | //No datasets available
260 | file.close();
261 | return false;
262 | }
263 | else if (!file.available()) {
264 | //Update number of datsets for transfer
265 | i_buffer = i;
266 | break;
267 | }
268 | }
269 |
270 | //Read and send the available amount of datasets
271 | file.seek(offset * 4 * measuredDataLength * transferedDatasets, SeekSet);
272 | int l = file.readBytes(buffer, 4 * measuredDataLength * i_buffer);
273 | file.close();
274 | uint8_t bufferArray[4 * measuredDataLength * i_buffer + 3];
275 | memcpy(&bufferArray[3], &buffer[0], 4 * measuredDataLength * i_buffer);
276 | PhyphoxBLE::write(bufferArray, 4 * measuredDataLength * i_buffer); //Send value to phyphox
277 |
278 | //All datasets are read -> return false
279 | if (i_buffer != transferedDatasets) {
280 | return false;
281 | } else {
282 | return true;
283 | }
284 | }
285 |
286 | //store one dataset in the ESP32 file system
287 | void storeMeasuredData(float dataArray[4]) {
288 | byte byteArray[4 * measuredDataLength];
289 | memcpy(&byteArray[0], &dataArray[0], 4 * measuredDataLength);
290 | File file = SPIFFS.open("/set.txt", "r+");
291 | file.seek(lineNumber * 4 * measuredDataLength, SeekSet);
292 | file.write(byteArray, 4 * measuredDataLength);
293 | file.close();
294 |
295 | //circular data storage
296 | if (lineNumber < (maxDatasets - 1)) {
297 | lineNumber += 1;
298 | } else {
299 | lineNumber = 0;
300 | }
301 | }
302 |
303 |
304 | //Update LED according to thresholds and current CO2 Value or changed connection count
305 | void updateLED(float co2value) {
306 | //update LED to blue if a device (dis)connects
307 | if (PhyphoxBLE::currentConnections != currentConnections) {
308 | BLUE = false;
309 | digitalWrite(pinBlue, BLUE);
310 | timeStampBlue = millis()/1000;
311 | currentConnections = PhyphoxBLE::currentConnections;
312 | Serial.print("Connection Count: ");
313 | Serial.print(currentConnections);
314 | Serial.print(" @ ");
315 | Serial.println(timeStampBlue);
316 | }
317 | if(millis()/1000 > timeStampBlue+0.3){
318 | BLUE = true;
319 | digitalWrite(pinBlue, BLUE);
320 | }
321 |
322 | if (co2value > topThreshold && RED == true) {
323 | Serial.println("Update to red");
324 | GREEN = true;
325 | RED = false;
326 | BLUE = true;
327 | digitalWrite(pinGreen, GREEN);
328 | digitalWrite(pinRed, RED);
329 | digitalWrite(pinBlue, BLUE);
330 | }
331 | if (co2value < bottomThreshold && GREEN == true) {
332 | Serial.println("Update to green");
333 | GREEN = false;
334 | RED = true;
335 | BLUE = true;
336 | digitalWrite(pinGreen, GREEN);
337 | digitalWrite(pinRed, RED);
338 | digitalWrite(pinBlue, BLUE);
339 |
340 | }
341 |
342 | }
343 |
--------------------------------------------------------------------------------