diff --git a/.github/workflows/check-arduino.yml b/.github/workflows/check-arduino.yml index 291351b..a5715d3 100644 --- a/.github/workflows/check-arduino.yml +++ b/.github/workflows/check-arduino.yml @@ -23,6 +23,6 @@ jobs: with: compliance: specification # Change this to "update" once the library is added to the index. - library-manager: submit + library-manager: update # Always use this setting for official repositories. Remove for 3rd party projects. official: true diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1d74e21 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.vscode/ diff --git a/README.md b/README.md index ca585ae..3a997da 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ Although you are free to directly manipulate I/O requests and responses (e.g. [T ## :zap: Caveats -This library is currently in **BETA** phase. This means that neither the API nor the usage patterns are set in stone and are likely to change. We are publishing this library in the full knowledge that we can't foresee every possible use-case and edge-case. Therefore we would like to treat this library, while it's in beta phase, as an experiment and ask for your input for shaping this library. Please help us by providing feedback in the [issues section](https://github.com/bcmi-labs/Arduino_Threads/issues) or participating in our [discussions](https://github.com/arduino/language/discussions). +This library is currently in **BETA** phase. This means that neither the API nor the usage patterns are set in stone and are likely to change. We are publishing this library in the full knowledge that we can't foresee every possible use-case and edge-case. Therefore we would like to treat this library, while it's in beta phase, as an experiment and ask for your input for shaping this library. Please help us by providing feedback in the [issues section](https://github.com/arduino-libraries/Arduino_Threads/issues) or participating in our [discussions](https://github.com/arduino-libraries/Arduino_Threads/discussions). ## :mag_right: Resources diff --git a/docs/README.md b/docs/README.md index 7511394..0b070ae 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,7 +2,7 @@ `Arduino_Threads/docs` ====================== -The Arduino threading APIs brings multi-threading to the world of Arduino. If you're new to the concept of threads we suggest you have first a look at the [Threading Basics](01-threading-basics.md) document. +The Arduino threading APIs brings multi-threading to the world of Arduino. If you're new to the concept of threads we suggest you have first a look at the [Threading Basics](threading-basics.md) document. The following Arduino architectures and boards are currently supported: * `mbed_portenta`: [Portenta H7](https://store.arduino.cc/products/portenta-h7) @@ -10,24 +10,29 @@ The following Arduino architectures and boards are currently supported: * `mbed_edge`: [Edge Control](https://store.arduino.cc/products/arduino-edge-control) * `mbed_nicla`: [Nicla Sense ME](https://store.arduino.cc/products/nicla-sense-me), [Nicla Vision](http://store.arduino.cc/products/nicla-vision) +### Tooling -Threading with the above mentioned Arduino cores can be achieved by leveraging the [Arduino_Threads](https://github.com/bcmi-labs/Arduino_Threads) library in combination with the [Arduino Command Line Interface](https://github.com/facchinm/arduino-cli/commits/arduino_threads_rebased) (arduino-cli). +Threading with the above mentioned Arduino cores can be achieved by leveraging the [Arduino_Threads](https://github.com/bcmi-labs/Arduino_Threads) library in combination with the [Arduino Command Line Interface](https://github.com/facchinm/arduino-cli/commits/arduino_threads_rebased) (arduino-cli). -Download a preliminary, pre-built `arduino-cli` binary for your operating system that supports threading: -* [MacOS_64Bit](https://downloads.arduino.cc/tools/arduino-cli/inot_support/arduino-cli_git-snapshot_macOS_64bit.tar.gz) -* [Linux_32Bit](https://downloads.arduino.cc/tools/arduino-cli/inot_support/arduino-cli_git-snapshot_Linux_32bit.tar.gz) -* [Linux_64Bit](https://downloads.arduino.cc/tools/arduino-cli/inot_support/arduino-cli_git-snapshot_Linux_64bit.tar.gz) -* [Linux_ARMv6](https://downloads.arduino.cc/tools/arduino-cli/inot_support/arduino-cli_git-snapshot_Linux_ARMv6.tar.gz) -* [Linux_ARMv7](https://downloads.arduino.cc/tools/arduino-cli/inot_support/arduino-cli_git-snapshot_Linux_ARMv7.tar.gz) -* [Windows_32Bit](https://downloads.arduino.cc/tools/arduino-cli/inot_support/arduino-cli_git-snapshot_Windows_32bit.zip) -* [Windows_64Bit](https://downloads.arduino.cc/tools/arduino-cli/inot_support/arduino-cli_git-snapshot_Windows_64bit.zip) +For those who are unsure how to use the Arduino CLI in combination with multi-threading take a look a condensed [getting started guide](cli-getting-started.md). There's also the comprehensive [arduino-cli documentation](https://arduino.github.io/arduino-cli/getting-started) to consider. + +Download a preliminary, pre-built `arduino-cli` binary (experimental) or patched `Arduino IDE` (very experimental) for your operating system that supports threading: +| Platform | Download CLI | Download IDE | +|:-:|:-:|:-:| +| MacOS_64Bit | [`arduino-cli`](https://downloads.arduino.cc/tools/arduino-cli/inot_support/arduino-cli_git-snapshot_macOS_64bit.tar.gz) | [`Arduino IDE`](https://downloads.arduino.cc/ide_staging/arduino_threads/arduino-PR-ae92bd4498e867b07581d1d4191be14b9ef0f69a-BUILD-65-macosx.zip) | +| Linux_32Bit | [`arduino-cli`](https://downloads.arduino.cc/tools/arduino-cli/inot_support/arduino-cli_git-snapshot_Linux_32bit.tar.gz) | [`Arduino IDE`](https://downloads.arduino.cc/ide_staging/arduino_threads/arduino-PR-ae92bd4498e867b07581d1d4191be14b9ef0f69a-BUILD-65-linux32.tar.xz) | +| Linux_64Bit | [`arduino-cli`](https://downloads.arduino.cc/tools/arduino-cli/inot_support/arduino-cli_git-snapshot_Linux_64bit.tar.gz) | [`Arduino IDE`](https://downloads.arduino.cc/ide_staging/arduino_threads/arduino-PR-ae92bd4498e867b07581d1d4191be14b9ef0f69a-BUILD-65-linux64.tar.xz) | +| Linux_ARMv6 | [`arduino-cli`](https://downloads.arduino.cc/tools/arduino-cli/inot_support/arduino-cli_git-snapshot_Linux_ARMv6.tar.gz) | | +| Linux_ARMv7 | [`arduino-cli`](https://downloads.arduino.cc/tools/arduino-cli/inot_support/arduino-cli_git-snapshot_Linux_ARMv7.tar.gz) | [`Arduino IDE`](https://downloads.arduino.cc/ide_staging/arduino_threads/arduino-PR-ae92bd4498e867b07581d1d4191be14b9ef0f69a-BUILD-65-linuxarm.tar.xz) | +| Windows_32Bit | [`arduino-cli`](https://downloads.arduino.cc/tools/arduino-cli/inot_support/arduino-cli_git-snapshot_Windows_32bit.zip) | | +| Windows_64Bit | [`arduino-cli`](https://downloads.arduino.cc/tools/arduino-cli/inot_support/arduino-cli_git-snapshot_Windows_64bit.zip) | [`Arduino IDE`](https://downloads.arduino.cc/ide_staging/arduino_threads/arduino-PR-ae92bd4498e867b07581d1d4191be14b9ef0f69a-BUILD-65-windows.zip) | ### Table of Contents In the following documents you will find more information about the topics covered by this library. -1. [Threading Basics](01-threading-basics.md) -2. [Data exchange between threads](02-data-exchange.md) -3. [Threadsafe `Serial`](03-threadsafe-serial.md) -4. [Threadsafe `Wire`](04-threadsafe-wire.md) -5. [Threadsafe `SPI`](05-threadsafe-spi.md) +1. [Threading Basics](threading-basics.md) +2. [Data exchange between threads](data-exchange.md) +3. [Threadsafe `Serial`](threadsafe-serial.md) +4. [Threadsafe `Wire`](threadsafe-wire.md) +5. [Threadsafe `SPI`](threadsafe-spi.md) diff --git a/docs/assets/boardlist.png b/docs/assets/boardlist.png new file mode 100644 index 0000000..4de06c0 Binary files /dev/null and b/docs/assets/boardlist.png differ diff --git a/docs/assets/compiled.png b/docs/assets/compiled.png new file mode 100644 index 0000000..08ecf37 Binary files /dev/null and b/docs/assets/compiled.png differ diff --git a/docs/assets/pathupdate.png b/docs/assets/pathupdate.png new file mode 100644 index 0000000..55a39f4 Binary files /dev/null and b/docs/assets/pathupdate.png differ diff --git a/docs/assets/uploaded.png b/docs/assets/uploaded.png new file mode 100644 index 0000000..cfdf8e2 Binary files /dev/null and b/docs/assets/uploaded.png differ diff --git a/docs/cli-getting-started.md b/docs/cli-getting-started.md new file mode 100644 index 0000000..29b89a4 --- /dev/null +++ b/docs/cli-getting-started.md @@ -0,0 +1,110 @@ + + +How to get started with the `Arduino CLI` and `Arduino_Threads` +=============================================================== +## Introduction +For now, you need to use the Arduino CLI to upload sketches made with the `Arduino_Threads` library. It can be intimidating at first, but once you get the hang of it, it is not that different from working in the IDE. + +This document will help you get started, showing you how to find all the information you need to get off the ground without needing to go in depth and learn everything there is to know about the CLI. + +## Installing +To use the `Arduino_Threads` library, a special version of the Arduino CLI needs to be downloaded and installed. Installing the Arduino CLI is really just as simple as downloading it and extracting the files from the .zip archive, once it is on your computer it is installed. However, to keep your workflow tidy and organized, we recommend moving it to a directory with a short path. If you have been using the Arduino IDE, most likely the files are stored in your `Documents` folder, so let's put the CLI files in the same place. + +Make a new folder in your `Documents` folder, and name it `CLI`, extract the files from the .zip archive to this folder. + +## Navigating With the Command Prompt and Launching the Arduino CLI +Since the Arduino CLI is a command line tool, it is not a program that you can launch by double clicking on the `.exe` file. Instead, we need to start it from the command prompt. Using the command prompt can be thought of like using the file explorer, you are in a folder, can move around to other folders, create new files, delete files, etc. The difference is that you do all of these things with commands instead of buttons. + +Unlike the file explorer where you click the folder you want to go to, navigating in the command prompt is done by first writing the command letting the program know that we want to move somewhere new, then telling it where we want to go. + +When you open up a command prompt window, you should be started in the root directory of your user profile, you can see in what folder you are by looking at the path text right where you enter your commands. Because you're started at the root of your user profile, the path should say `C:\Users\` + +Inside of this root folder there are other folders, if you want to go into the `Documents` folder, instead of clicking on it like you would do in the file explorer, you write the command: +``` +cd Documents +``` +and press enter. Notice how, after executing this command, the path updates to include the folder name of the folder you just went inside of. This part is super important, and it is also where many make small mistakes that keep anything from working the way it should, but if you pay close attention to what folder you are inside of, you can avoid these mistakes. + +![Path update](./assets/pathupdate.png) + +If you want to go back one step, to the folder you came from, you write this command: + +``` +cd .. +``` +But we don't need to do that now, we want to be inside of the `CLI` folder, that is inside of the `Documents` folder. + +Navigate to it with the command: +``` +cd Documents/CLI +``` + +Once inside of `CLI`, you're ready to launch the Arduino CLI. Launching it this way, ensures that you are launching the special version of the CLI that can handle the `Arduino_Threads` library. Execute this command: +``` +start arduino-cli.exe +``` + +If it seems like nothing happened - great! Then it probably worked. If you got an error, such as a message saying the file could not be found, a few things to check are: + +- That you are in the right path, if you've copied the setup suggested in this guide, the directory you want to be in should have the path `C:\Users\\Documents\CLI` +- That the arduino-cli.exe file is inside of this folder +- That there aren't any small spelling-errors + +Once you believe that you have successfully started the Arduino CLI, confirm by executing the command +``` +arduino-cli +``` +If you get a list of all the available commands, everything is as it should, and you can move on to the next step. + +## Finding Information About your Board +To compile sketches and to upload to your Arduino board, you need to know some information about the board you have connected. In this step we're going to find all the information we need. Connect your Arduino board to your computer, and execute the command: +``` +arduino-cli board list +``` +If your board was found, you will get a bunch of information about it. The information we're interested in is the `FQBN`, and the port. `FQBN` stands for "Fully Qualified Board Name", and is how the computer refers to the board. The port is like an address for the board. + +![Board list](./assets/boardlist.png) + +If you are, like we are, using an Arduino Nano 33 BLE Sense, the `FQBN` will be `arduino:mbed_nano:nano33ble`. We need to specify every time we are compiling and uploading sketches that they are to be compiled for this board, just like we do in the IDE. + +## Installing Cores +If you have already used your Arduino board with the IDE, you can skip this step entirely. Otherwise, there are some files you may need to install to be able to use the board. But don't worry, it's just one command. The Arduino Nano 33 BLE Sense uses the `arduino:mbed_nano` core, which is another piece of information that we got from the board list command we executed, so we need to install that before using the board. + +If you are unsure whether or not you have the core installed, go through with this step. If it is already installed, it won't do any harm to do it again. + +To install the core, execute this command: +``` +arduino-cli core install arduino:mbed_nano +``` +If you are using a board with another core, replace `arduino:mbed_nano` in the command with whatever core you got from the board list. + +## Make a Sketch +Now it is time to either make a new sketch, or to place a sketch that you have already made or want to test in the `CLI` folder. + +If you want to make a new sketch, use the command: +``` +arduino-cli sketch new MySketch +``` +and a new folder will be created inside of the `CLI` folder, this new folder is named `MySketch` and contains a file named `MySketch.ino`. This .ino file can be opened, and edited in your text-editor of choice. Once you are happy with the sketch, move on to the next step. + +If you already have a sketch that you want to upload, find it and move it into the `CLI` folder. Be sure to move the folder containing the `.ino` file and any extra files included in the sketch, and not the `.ino` file on its own. + +## Compile and Upload + +The final steps to do are to compile and to upload the sketch. We'll do this with two separate commands. To compile, we need to pass the FQBN in the command to specify what board we want to compile it for, and we need to tell it what sketch we want to compile. We'll compile the sketch we created earlier to be uploaded to an Arduino Nano 33 BLE Sense. We can do this with the command: +``` +arduino-cli compile --fqbn arduino:mbed_nano:nano33ble MySketch +``` +Once you execute this command, it's going to start compiling unless something went wrong. If it looks like nothing is happening - Great! That probably means that everything is going as it should. Depending on the core, compiling might take a few minutes. Be patient, it may seem like it's taking too long, but give it time. Eventually, you'll get a statement about the memory use, libraries included, and platform used. + +![Compiled sketch statement](./assets/compiled.png) + +Now that the sketch is compiled, let's upload it! For this, we need to specify the FQBN again, as well as the port the board is connected to, so it's uploaded to the right place. To find the port, go back to the board list we got earlier, ours is connected to port `COM14`, but replace this part of the command with whatever port your list says. Now execute the command: +``` +arduino-cli upload -p COM14 --fqbn arduino:mbed_nano:nano33ble MySketch +``` +If everything went as it should, the sketch is now uploading to the board, and once that is done, you've successfully used the Arduino CLI to upload a sketch to your board. + +![Uploaded sketch](./assets/uploaded.png) + +Now that you know how to do this, it might be a good opportunity to take the deep dive in the DIY-spirit, experiment with different workflows and interfaces for the terminal to tailor your Arduino experience to your liking. \ No newline at end of file diff --git a/docs/02-data-exchange.md b/docs/data-exchange.md similarity index 100% rename from docs/02-data-exchange.md rename to docs/data-exchange.md diff --git a/docs/01-threading-basics.md b/docs/threading-basics.md similarity index 100% rename from docs/01-threading-basics.md rename to docs/threading-basics.md diff --git a/docs/03-threadsafe-serial.md b/docs/threadsafe-serial.md similarity index 100% rename from docs/03-threadsafe-serial.md rename to docs/threadsafe-serial.md diff --git a/docs/05-threadsafe-spi.md b/docs/threadsafe-spi.md similarity index 95% rename from docs/05-threadsafe-spi.md rename to docs/threadsafe-spi.md index 079cc04..4d0cd2b 100644 --- a/docs/05-threadsafe-spi.md +++ b/docs/threadsafe-spi.md @@ -3,7 +3,7 @@ Thread-safe `SPI` =============== ## Introduction -`SPI` communication shares the same problems that [have been outlined](04-threadsafe-wire.md) for using `Wire` in a multithreaded environment. This is due to the fact that every `SPI` transaction consists of multiple function calls, i.e. +`SPI` communication shares the same problems that [have been outlined](threadsafe-wire.md) for using `Wire` in a multithreaded environment. This is due to the fact that every `SPI` transaction consists of multiple function calls, i.e. ```C++ digitalWrite(cs, LOW); diff --git a/docs/04-threadsafe-wire.md b/docs/threadsafe-wire.md similarity index 100% rename from docs/04-threadsafe-wire.md rename to docs/threadsafe-wire.md diff --git a/examples/Breaks_1/Breaks_1.ino b/examples/Breaks_1/Breaks_1.ino deleted file mode 100644 index fbb7922..0000000 --- a/examples/Breaks_1/Breaks_1.ino +++ /dev/null @@ -1,11 +0,0 @@ -#include - -void setup() -{ - Thread.start(); -} - -void loop() -{ - -} \ No newline at end of file diff --git a/examples/Breaks_1/Thread.inot b/examples/Breaks_1/Thread.inot deleted file mode 100644 index 0c86dce..0000000 --- a/examples/Breaks_1/Thread.inot +++ /dev/null @@ -1,23 +0,0 @@ -/* This fails to compile because it doesn't look like a - * declaration and a definition but rather like an attempt - * to overload myFunc with the same signature (again) - * resulting in a compile error. - */ - -int myFunc(int const a, int const b); - -void setup() -{ - -} - -void loop() -{ - static int c = 0; - c += myFunc(0,c); -} - -int myFunc(int const a, int const b) -{ - return (a + b); -} \ No newline at end of file diff --git a/examples/Breaks_2/Breaks_2.ino b/examples/Breaks_2/Breaks_2.ino deleted file mode 100644 index fbb7922..0000000 --- a/examples/Breaks_2/Breaks_2.ino +++ /dev/null @@ -1,11 +0,0 @@ -#include - -void setup() -{ - Thread.start(); -} - -void loop() -{ - -} \ No newline at end of file diff --git a/examples/Breaks_2/SharedVariables.h b/examples/Breaks_2/SharedVariables.h deleted file mode 100644 index e69de29..0000000 diff --git a/examples/Breaks_2/Thread.inot b/examples/Breaks_2/Thread.inot deleted file mode 100644 index 0eff097..0000000 --- a/examples/Breaks_2/Thread.inot +++ /dev/null @@ -1,21 +0,0 @@ -/* This fails to compile because myEventHandler has the - * function signature of 'void Thread::myEventHandler(void)' - * and is a member function of 'class Thread' while - * attachInterrupt expects a function with the signature - * 'void myEventHandler(void)' - */ - -void myEventHandler() -{ - /* Do something. */ -} - -void setup() -{ - attachInterrupt(digitalPinToInterrupt(2), myEventHandler, CHANGE); -} - -void loop() -{ - -} diff --git a/examples/Breaks_3/Breaks_3.ino b/examples/Breaks_3/Breaks_3.ino deleted file mode 100644 index fbb7922..0000000 --- a/examples/Breaks_3/Breaks_3.ino +++ /dev/null @@ -1,11 +0,0 @@ -#include - -void setup() -{ - Thread.start(); -} - -void loop() -{ - -} \ No newline at end of file diff --git a/examples/Breaks_3/SharedVariables.h b/examples/Breaks_3/SharedVariables.h deleted file mode 100644 index e69de29..0000000 diff --git a/examples/Breaks_3/Thread.inot b/examples/Breaks_3/Thread.inot deleted file mode 100644 index 6b2b2b4..0000000 --- a/examples/Breaks_3/Thread.inot +++ /dev/null @@ -1,15 +0,0 @@ -/* This fails to compile because in-class-initialisation of - * a static member variable is forbidden. - */ - -static int my_global_variable = 0; - -void setup() -{ - -} - -void loop() -{ - -} diff --git a/examples/Breaks_4/Breaks_4.ino b/examples/Breaks_4/Breaks_4.ino deleted file mode 100644 index fbb7922..0000000 --- a/examples/Breaks_4/Breaks_4.ino +++ /dev/null @@ -1,11 +0,0 @@ -#include - -void setup() -{ - Thread.start(); -} - -void loop() -{ - -} \ No newline at end of file diff --git a/examples/Breaks_4/SharedVariables.h b/examples/Breaks_4/SharedVariables.h deleted file mode 100644 index e69de29..0000000 diff --git a/examples/Breaks_4/Thread.inot b/examples/Breaks_4/Thread.inot deleted file mode 100644 index 2588a25..0000000 --- a/examples/Breaks_4/Thread.inot +++ /dev/null @@ -1,47 +0,0 @@ -/* Breaks for all kind of stuff ... - */ - -/************************************************************************************** - * CONSTANTS - **************************************************************************************/ - -static byte constexpr LSM6DSOX_ADDRESS = 0x6A; -static byte constexpr LSM6DSOX_WHO_AM_I_REG = 0x0F; - -/************************************************************************************** - * GLOBAL VARIABLES - **************************************************************************************/ - -BusDevice lsm6dsox(Wire, LSM6DSOX_ADDRESS); - -/************************************************************************************** - * FUNCTIONS - **************************************************************************************/ - -byte lsm6dsox_read_reg(byte reg_addr) -{ - byte read_buf = 0; - lsm6dsox.wire().writeThenRead(®_addr, 1, &read_buf, 1); - return read_buf; -} - -/************************************************************************************** - * SETUP/LOOP - **************************************************************************************/ - -void setup() -{ - Serial.begin(9600); -} - -void loop() -{ - /* Sleep between 5 and 500 ms */ - rtos::ThisThread::sleep_for(rtos::Kernel::Clock::duration_u32(random(5,500))); - /* Try to read some data from the LSM6DSOX. */ - byte const who_am_i = lsm6dsox_read_reg(LSM6DSOX_WHO_AM_I_REG); - /* Print thread id and chip id value to serial. */ - char msg[64] = {0}; - snprintf(msg, sizeof(msg), "%s: LSM6DSOX[WHO_AM_I] = 0x%X", rtos::ThisThread::get_name(), who_am_i); - Serial.println(msg); -} diff --git a/examples/Breaks_5/Breaks_5.ino b/examples/Breaks_5/Breaks_5.ino deleted file mode 100644 index fbb7922..0000000 --- a/examples/Breaks_5/Breaks_5.ino +++ /dev/null @@ -1,11 +0,0 @@ -#include - -void setup() -{ - Thread.start(); -} - -void loop() -{ - -} \ No newline at end of file diff --git a/examples/Breaks_5/SharedVariables.h b/examples/Breaks_5/SharedVariables.h deleted file mode 100644 index e69de29..0000000 diff --git a/examples/Breaks_5/Thread.inot b/examples/Breaks_5/Thread.inot deleted file mode 100644 index c430b03..0000000 --- a/examples/Breaks_5/Thread.inot +++ /dev/null @@ -1,19 +0,0 @@ -/* This fails to compile because myEventHandler is declared - * after setup/loop and currently there's not automatic prototype - * generation as done for the ino file. - */ - -void setup() -{ - attachInterrupt(digitalPinToInterrupt(2), myEventHandler, CHANGE); -} - -void loop() -{ - -} - -void myEventHandler() -{ - /* Do something. */ -} diff --git a/examples/Breaks_6/Breaks_6.ino b/examples/Breaks_6/Breaks_6.ino deleted file mode 100644 index 86b3bfa..0000000 --- a/examples/Breaks_6/Breaks_6.ino +++ /dev/null @@ -1,15 +0,0 @@ -/* This example is in fact expected to break, since we try - * to access a thread-private variable. - */ - -#include - -void setup() -{ - Thread.start(); -} - -void loop() -{ - int const my_var = var; -} diff --git a/examples/Breaks_6/SharedVariables.h b/examples/Breaks_6/SharedVariables.h deleted file mode 100644 index e69de29..0000000 diff --git a/examples/Breaks_6/Thread.inot b/examples/Breaks_6/Thread.inot deleted file mode 100644 index b31007b..0000000 --- a/examples/Breaks_6/Thread.inot +++ /dev/null @@ -1,11 +0,0 @@ -void setup() -{ - -} - -void loop() -{ - -} - -int var = 0; diff --git a/examples/Threading_Basics/Source_Sink_Counter/Source_Sink_Counter.ino b/examples/Threading_Basics/Source_Sink_Counter/Source_Sink_Counter.ino index f237bb2..7f528a1 100644 --- a/examples/Threading_Basics/Source_Sink_Counter/Source_Sink_Counter.ino +++ b/examples/Threading_Basics/Source_Sink_Counter/Source_Sink_Counter.ino @@ -5,7 +5,7 @@ void setup() { - Producer.counter.connectTo(Consumer.counter); + CONNECT(Producer, counter, Consumer, counter); Producer.start(); Consumer.start(); } diff --git a/examples/Threading_Basics/Source_Sink_LED/Source_Sink_LED.ino b/examples/Threading_Basics/Source_Sink_LED/Source_Sink_LED.ino index c0e94be..d781476 100644 --- a/examples/Threading_Basics/Source_Sink_LED/Source_Sink_LED.ino +++ b/examples/Threading_Basics/Source_Sink_LED/Source_Sink_LED.ino @@ -5,7 +5,7 @@ void setup() { - Source_Thread.led.connectTo(Sink_Thread.led); + CONNECT(Source_Thread, led, Sink_Thread, led); Sink_Thread.start(); Source_Thread.start(); } diff --git a/examples/Threading_Basics/Thermostat/AirConditionerControl.inot b/examples/Threading_Basics/Thermostat/AirConditionerControl.inot new file mode 100644 index 0000000..59dc16e --- /dev/null +++ b/examples/Threading_Basics/Thermostat/AirConditionerControl.inot @@ -0,0 +1,53 @@ +/* Define a data sink named 'temperature' of type 'float'. */ +SINK(temperature, float, 10); + +void setup() +{ + Serial.begin(9600); + while (!Serial) { } +} + +bool is_ac_on = false; + +void loop() +{ + float current_temperature_deg = temperature.pop(); + + /* Check if the temperature reported by the thermostat is above + * or below 26.0 °C. If the temperature is above 26.0 °C, turn + * on the AC. + */ + bool turn_ac_on = false, + turn_ac_off = false; + + if (current_temperature_deg > 26.0f) + turn_ac_on = true; + else + turn_ac_off = true; + + /* Only perform a simulated turning on of + * the air conditioner if the heating is + * air conditioner is currently turned off. + */ + if (is_ac_on && turn_ac_off) + { + is_ac_on = false; + + Serial.block(); + Serial.print("AC OFF ("); + Serial.print(current_temperature_deg); + Serial.println(" °C)"); + Serial.unblock(); + } + + if (!is_ac_on && turn_ac_on) + { + is_ac_on = true; + + Serial.block(); + Serial.print("AC ON ("); + Serial.print(current_temperature_deg); + Serial.println(" °C)"); + Serial.unblock(); + } +} diff --git a/examples/Threading_Basics/Thermostat/HeatingControl.inot b/examples/Threading_Basics/Thermostat/HeatingControl.inot new file mode 100644 index 0000000..5fcaf82 --- /dev/null +++ b/examples/Threading_Basics/Thermostat/HeatingControl.inot @@ -0,0 +1,53 @@ +/* Define a data sink named 'temperature' of type 'float'. */ +SINK(temperature, float, 10); + +void setup() +{ + Serial.begin(9600); + while (!Serial) { } +} + +bool is_heating_on = false; + +void loop() +{ + float current_temperature_deg = temperature.pop(); + + /* Check if the temperature reported by the thermostat is above + * or below 22.0 °C. If the temperature is below 22.0 °C, turn + * on the heating. + */ + bool turn_heating_on = false, + turn_heating_off = false; + + if (current_temperature_deg < 22.0f) + turn_heating_on = true; + else + turn_heating_off = true; + + /* Only perform a simulated turning on of + * the heating if the heating is currently + * turned off. + */ + if (is_heating_on && turn_heating_off) + { + is_heating_on = false; + + Serial.block(); + Serial.print("Heating OFF ("); + Serial.print(current_temperature_deg); + Serial.println(" °C)"); + Serial.unblock(); + } + + if (!is_heating_on && turn_heating_on) + { + is_heating_on = true; + + Serial.block(); + Serial.print("Heating ON ("); + Serial.print(current_temperature_deg); + Serial.println(" °C)"); + Serial.unblock(); + } +} diff --git a/examples/Breaks_1/SharedVariables.h b/examples/Threading_Basics/Thermostat/SharedVariables.h similarity index 100% rename from examples/Breaks_1/SharedVariables.h rename to examples/Threading_Basics/Thermostat/SharedVariables.h diff --git a/examples/Threading_Basics/Thermostat/TemperatureSensor.inot b/examples/Threading_Basics/Thermostat/TemperatureSensor.inot new file mode 100644 index 0000000..d763ca4 --- /dev/null +++ b/examples/Threading_Basics/Thermostat/TemperatureSensor.inot @@ -0,0 +1,19 @@ +/* Define a data source named 'temperature' of type 'float'. */ +SOURCE(temperature, float); + +void setup() +{ + +} + +void loop() +{ + /* Read temperature - since this is just a simulation + * so we take a random value between 15 and 30 °C. + */ + float const temperature_deg = (rand() % 16) + 15; + /* Store in temperature source variable. */ + temperature.push(temperature_deg); + /* Do only one temperature sensore measurement per second. */ + delay(5000); +} diff --git a/examples/Threading_Basics/Thermostat/TemperatureSensorReporter.inot b/examples/Threading_Basics/Thermostat/TemperatureSensorReporter.inot new file mode 100644 index 0000000..c6ceb10 --- /dev/null +++ b/examples/Threading_Basics/Thermostat/TemperatureSensorReporter.inot @@ -0,0 +1,19 @@ +/* Define a data sink named 'temperature' of type 'float'. */ +SINK(temperature, float); + +void setup() +{ + Serial.begin(9600); + while (!Serial) { } +} + +void loop() +{ + float const current_temperature_deg = temperature.pop(); + + Serial.block(); + Serial.print("Temperature = "); + Serial.print(current_temperature_deg); + Serial.println(" °C"); + Serial.unblock(); +} diff --git a/examples/Threading_Basics/Thermostat/Thermostat.ino b/examples/Threading_Basics/Thermostat/Thermostat.ino new file mode 100644 index 0000000..f033e07 --- /dev/null +++ b/examples/Threading_Basics/Thermostat/Thermostat.ino @@ -0,0 +1,37 @@ +/* This example emulates a thermostat system which consists of + * a single temperature sensore and multiple heating devices + * or air-conditioners. The temperature sensor provides periodic + * temperature sensor measurements and acts as a temperature source. + * This temperature is consumed by various TemperatureControl_ threads + * which perform the act of actual room temperature control. + * + * Note: While there is only a single temperature "source" there are + * multiple temperature "sinks". The source/sink paradigm is constructed + * in such a way, that each sink is guaranteed to see every value provided + * by a source. This is something that can not be modeled using the shared + * variable abstraction. + */ + +void setup() +{ + /* Connect the temperature sensor thread providing temperature readings + * with the various temperature control unit threads. + */ + CONNECT(TemperatureSensor, temperature, HeatingControl, temperature); + CONNECT(TemperatureSensor, temperature, AirConditionerControl, temperature); + CONNECT(TemperatureSensor, temperature, TemperatureSensorReporter, temperature); + + /* Start the individual threads for sensing the temperature + * and controlling heating/air-conditioning based on the sensed + * temperature on a per-room basis. + */ + TemperatureSensor.start(); + HeatingControl.start(); + AirConditionerControl.start(); + TemperatureSensorReporter.start(); +} + +void loop() +{ + +} diff --git a/library.properties b/library.properties index f2079e1..617da6e 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Arduino_Threads -version=0.2.0 +version=0.3.0 author=Arduino maintainer=Arduino sentence=Easy multi-threading for your Mbed OS-based Arduino. diff --git a/src/Arduino_Threads.h b/src/Arduino_Threads.h index 6a233ed..5078dfd 100644 --- a/src/Arduino_Threads.h +++ b/src/Arduino_Threads.h @@ -41,9 +41,7 @@ **************************************************************************************/ #define SOURCE(name, type) \ -public: \ - Source name; \ -private: +Source name; /* We need to call the SinkBlocking(size_t const size) * non-default constructor using size as parameter. @@ -61,14 +59,10 @@ public: \ */ #define SINK_2_ARG(name, type) \ -public: \ - SinkBlocking name{1}; \ -private: +SinkBlocking name{1} #define SINK_3_ARG(name, type, size) \ -public: \ - SinkBlocking name{size}; \ -private: +SinkBlocking name{size} /* Black C macro magic enabling "macro overloading" * with same name macro, but multiple arguments. @@ -78,10 +72,10 @@ public: \ #define SINK(...) GET_SINK_MACRO(__VA_ARGS__, SINK_3_ARG, SINK_2_ARG)(__VA_ARGS__) #define SINK_NON_BLOCKING(name, type) \ -public: \ - SinkNonBlocking name{}; \ -private: +SinkNonBlocking name{} +#define CONNECT(source_thread, source_name, sink_thread, sink_name) \ +source_thread##Private::source_name.connectTo(sink_thread##Private::sink_name) #define SHARED_2_ARG(name, type) \ Shared name; @@ -135,13 +129,28 @@ class Arduino_Threads void threadFunc(); }; -#define THD_ENTER(tabname) class ARDUINO_THREADS_CONCAT(tabname, Class) : public Arduino_Threads { \ -public: \ - ARDUINO_THREADS_CONCAT(tabname, Class)() { _tabname = ARDUINO_THREADS_TO_STRING(tabname); } \ -private: \ +#define THD_SETUP(ns) ns::setup() +#define THD_LOOP(ns) ns::loop() + +#define THD_ENTER(tabname) \ +namespace ARDUINO_THREADS_CONCAT(tabname,Private)\ +{\ + void setup();\ + void loop();\ +}\ +class ARDUINO_THREADS_CONCAT(tabname, Class) : public Arduino_Threads\ +{\ +public:\ + ARDUINO_THREADS_CONCAT(tabname, Class)() { _tabname = ARDUINO_THREADS_TO_STRING(tabname); }\ +protected:\ + virtual void setup() override { THD_SETUP(ARDUINO_THREADS_CONCAT(tabname,Private)); }\ + virtual void loop() override { THD_LOOP(ARDUINO_THREADS_CONCAT(tabname,Private)); }\ +};\ +namespace ARDUINO_THREADS_CONCAT(tabname,Private)\ +{ -#define THD_DONE(tabname) \ -}; \ +#define THD_DONE(tabname)\ +};\ ARDUINO_THREADS_CONCAT(tabname,Class) tabname; #endif /* ARDUINO_THREADS_H_ */