├── .stackedit-trash
└── README.md
├── README.md
├── common
├── Button.cpp
├── Button.h
├── LedBlinker.cpp
├── LedBlinker.h
└── common
├── doc
├── bluepill.jpg
├── esp32.jpg
├── esp8266.jpeg
├── maple.jpeg
├── maple.jpg
├── mqtt-spy.png
├── nrf51822.jpeg
├── stellaris.jpeg
└── ucs.jpg
├── esp32-bluetooth
├── .gitignore
├── .travis.yml
├── .vscode
│ └── extensions.json
├── include
│ └── README
├── lib
│ └── README
├── platformio.ini
├── src
│ ├── README.MD
│ ├── arduino
│ ├── common
│ └── main.cpp
└── test
│ └── README
├── esp32
├── .gitignore
├── .travis.yml
├── .vscode
│ └── extensions.json
├── include
│ └── README
├── lib
│ └── README
├── platformio.ini
├── src
│ ├── arduino
│ ├── common
│ └── main.cpp
└── test
│ └── README
├── esp8266
├── .gitignore
├── .travis.yml
├── .vscode
│ └── extensions.json
├── include
│ └── README
├── lib
│ └── README
├── output.map
├── platformio.ini
├── src
│ ├── arduino
│ ├── common
│ └── main.cpp
└── test
│ └── README
├── lm4f120-cm3
├── .gitignore
├── .travis.yml
├── .vscode
│ └── extensions.json
├── flash.ld
├── include
│ └── README
├── lib
│ └── README
├── platformio.ini
├── src
│ ├── Hardware.h
│ ├── MedianFilter.h
│ ├── Serial.h
│ ├── Streams.cpp
│ ├── Streams.h
│ ├── app_main.cpp
│ └── main.cpp
└── test
│ └── README
├── lm4f120
├── .gitignore
├── .travis.yml
├── .vscode
│ └── extensions.json
├── ACM_minicom.log
├── README.MD
├── include
│ └── README
├── lib
│ └── README
├── output.map
├── platformio.ini
├── src
│ ├── arduino
│ ├── common
│ ├── main.cpp
│ ├── printf.c
│ └── printf.h
└── test
│ └── README
├── maple
├── .gitignore
├── .travis.yml
├── .vscode
│ └── extensions.json
├── include
│ └── README
├── lib
│ └── README
├── platformio.ini
├── src
│ ├── MqttSerial.cpp
│ ├── NanoAkka.cpp
│ ├── NanoAkka.cpp-old
│ ├── Sys.cpp
│ └── main.cpp
└── test
│ └── README
├── nrf51822-ble
├── .gitignore
├── .travis.yml
├── .vscode
│ └── extensions.json
├── include
│ └── README
├── lib
│ └── README
├── platformio.ini
├── src
│ ├── BLESerial.cpp
│ ├── BLESerial.h
│ ├── main.cpp
│ ├── proto.cpp
│ └── proto.h
└── test
│ └── README
├── nrf51822
├── .gitignore
├── .travis.yml
├── .vscode
│ └── extensions.json
├── include
│ └── README
├── lib
│ └── README
├── platformio.ini
├── src
│ ├── MedianFilter.h
│ ├── MqttSerial.cpp
│ ├── NanoAkka.cpp
│ ├── Sys.cpp
│ ├── main.cpp
│ └── main.cpp-old
└── test
│ └── README
├── pic32
├── .gitignore
├── .travis.yml
├── .vscode
│ └── extensions.json
├── README.md
├── include
│ └── README
├── lib
│ └── README
├── platformio.ini
├── src
│ ├── MqttSerial.cpp
│ ├── NanoAkka.cpp
│ ├── NanoAkka.cpp-old
│ ├── Sys.cpp
│ └── main.cpp
└── test
│ └── README
├── simple
├── platformio.ini
└── src
│ └── main.cpp
└── stm32f0discovery
├── include
└── README
├── platformio.ini
└── src
└── main.cpp
/.stackedit-trash/README.md:
--------------------------------------------------------------------------------
1 | # Arduino code mqtt over serial
2 |
3 | - Framework = Arduino
4 | - IDE = Visual Code + PlatformIO
5 |
6 | ### LM4F120 Launchpad
7 |
8 |
9 | The Launchpad board only needs one USB connector as the LM4F120 used as programmer exposes an ICDI port and a CDC serial port.
10 |
11 | ### maple mini LeafLabs
12 | This is a maple leaflabs board, programmed through a STLINKV2 clone. Parameters need to be changed in platformio.ini if the maple board is used with the inbuild bootloader.
13 | The USB connection will present itself as an USB CDC device :
14 | ```
15 | Bus 001 Device 021: ID 0483:5740 STMicroelectronics STM32F407
16 | ```
17 |
18 |
19 | ### nrf51822
20 |
21 |
22 | ### ESP32
23 |
24 |
25 | ### ESP8266
26 |
27 |
28 | ### MQTT SPY screenshot
29 |
30 |
31 |
32 | ### Test setup
33 |
34 | 5 different devices and 1 serial2mqtt handling all communication.
35 |
36 |
37 |
38 | Top to bottom :
39 | - nrf51822 on a nrf51822 evaluation kit board with stlink clone
40 | - esp32 - flashing a stm32 maple
41 | - esp8266
42 | - Stellaris Launchpas lm4f120h5qr
43 | - maple - stm32f103 with stlink clone
44 |
45 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Arduino code mqtt over serial
2 |
3 | ## Synopsis
4 | This code enables Arduino based microcontrollers to use a serial port communication to send MQTT publish information to topics and subscribe to MQTT topics.
5 | This requires to have serial2mqtt (Linux X86 or ARM -Raspberry Pi ) run on the host side.
6 | Only QOS level 0 used.
7 | ### Conventions used in the code
8 |
9 | - MQTT Publish happens on **src/device/object/property**
10 | - MQTT Subscribe happens on **dst/device/#**
11 | - The **device** part is also the internal hostname. It can be configured via the options (-DHOSTNAME ) in platformio.ini.
12 | ```c++
13 | ValueFlow x;
14 | x.pass(true);
15 | x == mqtt.topic("object1/x")
16 | x=1; // will publish the value on MQTT
17 | ```
18 |
19 | Publishing topic=dst/device/object1/x , message=123 will result that x becomes 123 in the Arduino.
20 |
21 | Most basic type are supported : string, bool, float, integer types as it uses ArduinoJson variants.
22 | Complex JSON object types need to be composed by the application itself.
23 | See also : https://github.com/vortex314/nanoAkka/blob/master/README.md
24 |
25 |
26 | ## Build it
27 | - Framework = Arduino
28 | - IDE = Visual Code + PlatformIO
29 |
30 | ```Shell
31 | git clone https://github.com/bblanchon/ArduinoJson
32 | git clone https://github.com/vortex314/mqtt2serial.git
33 | git clone https://github.com/vortex314/limero.git
34 |
35 | git clone https://github.com/vortex314/serial2mqtt.git
36 | cd mqtt2serial
37 | ```
38 | - use visual code with platformio extension to open any of the projects within mqtt2serial
39 | - compile and download to controller, check out the ports used in the platformio.ini. Could differ on your system
40 | ## Run it
41 | - check if the serial port is sending out JSON arrays to subscribe and do loopback tests. Use minicom or the in-build terminal of platformio
42 | - then activate serial2mqtt , adapt the serial2mqtt.json file for the correct ports. Don't forget to close the connection from the previous step.
43 | ```
44 | cd ../serial2mqtt
45 | cd build
46 | unzip serial2mqtt.x86_64.zip # for Linux 64bit
47 | cd ..
48 | # check serial2mqtt.json for the correct settings
49 | build/Debug/serial2mqtt
50 | ```
51 | Have fun.
52 | ## Implementation details
53 | - The Arduino sends out continously every x seconds a loopback message on which it also subscribes : *dst/device/system/loopback:true*
54 | - This enables to detect if the there is an E2E connection with the broker.
55 | - If no response is received it will send out also repetitively the subscribe command to *dst/device/#*
56 | - As long as there is no loopback and subscribe established, it will not publish any further topics.
57 | - The LED of the board is used to indicate this connection status, it blinks slow if there is connection to MQTT, it blinks fast when the connection is not established or gone.
58 | ### LM4F120 Launchpad
59 |
60 |
61 | The Launchpad board only needs one USB connector as the LM4F120 used as programmer exposes an ICDI port and a CDC serial port.
62 |
63 | ### maple mini LeafLabs
64 | This is a maple leaflabs board, programmed through a STLINKV2 clone. Parameters need to be changed in platformio.ini if the maple board is used with the inbuild bootloader.
65 | The USB connection will present itself as an USB CDC device :
66 | ```
67 | Bus 001 Device 021: ID 0483:5740 STMicroelectronics STM32F407
68 | ```
69 |
70 |
71 | ### nrf51822
72 |
73 |
74 | ### ESP32
75 |
76 |
77 | ### ESP8266
78 |
79 |
80 | ### MQTT SPY screenshot
81 |
82 |
83 |
84 | ### Test setup
85 |
86 | 5 different devices and 1 serial2mqtt handling all communication.
87 |
88 |
89 |
90 | Top to bottom :
91 | - nrf51822 on a nrf51822 evaluation kit board with stlink clone
92 | - esp32 - flashing a stm32 maple
93 | - esp8266
94 | - Stellaris Launchpas lm4f120h5qr
95 | - maple - stm32f103 with stlink clone
96 |
97 | ### Folder structure
98 | - simple : most Basic Arduino example. Just a serial println publishing a topic.
99 | - subscribe ( TBC ) : subscribe to a topic and handle messages.
100 | - Serial Mqtt full example , it has more features :
101 | * it will detect a failing connection
102 | * it sends out a loopback message to itself, to check the E2E connectivity with MQTT
103 | * it automatically resubscribes to his own destination based on hostname
104 | * it stops all publishes until a connection is reliably present
105 | * it's reactive stream driven based on [nanoAkka](https://github.com/vortex314/nanoAkka/blob/master/README.md)
106 | * it should work on any Arduino having a serial or USB CDC connection. Anyway on those in my possession
107 |
108 |
--------------------------------------------------------------------------------
/common/Button.cpp:
--------------------------------------------------------------------------------
1 | //_______________________________________________________________________________________________________________
2 | //
3 | #include
4 |
5 | Button *Button::_button = 0;
6 |
7 | Button::Button(Thread &thr, uint32_t pin) : Actor(thr), ValueFlow(), _pin(pin)
8 | {
9 | _button = this;
10 | };
11 |
12 | void Button::newValue(bool b)
13 | {
14 | if (b != _lastState)
15 | {
16 | _lastState = b;
17 | on(b);
18 | }
19 | }
20 |
21 | void IRAM_ATTR Button::isrButton()
22 | {
23 | if (_button)
24 | _button->newValue(digitalRead(_button->_pin) == 0);
25 | }
26 | void Button::init()
27 | {
28 | pinMode(_pin, INPUT_PULLUP);
29 | attachInterrupt(_pin, isrButton, CHANGE);
30 | };
31 |
--------------------------------------------------------------------------------
/common/Button.h:
--------------------------------------------------------------------------------
1 | //_______________________________________________________________________________________________________________
2 | //
3 | #ifndef _BUTTON_H_
4 | #define _BUTTON_H_
5 | #include
6 | #ifndef IRAM_ATTR
7 | #define IRAM_ATTR
8 | #endif
9 | class Button : public Actor, public ValueFlow
10 | {
11 | uint32_t _pin;
12 | bool _pinOldValue;
13 | static Button *_button;
14 | static Button *_button2;
15 | bool _lastState = false;
16 |
17 | public:
18 | Button(Thread &thr, uint32_t pin) ;
19 | void newValue(bool b);
20 | static void IRAM_ATTR isrButton();
21 | void init();
22 | };
23 | #endif
24 |
--------------------------------------------------------------------------------
/common/LedBlinker.cpp:
--------------------------------------------------------------------------------
1 | //_______________________________________________________________________________________________________________
2 | //
3 | #include
4 |
5 | LedBlinker::LedBlinker(Thread& thr,uint32_t pin, uint32_t delay)
6 | : Actor(thr),_pin(pin),blinkTimer(thr,delay,true),timerHandler(3,"timerHandler"),blinkSlow(3,"blinkSlow") {
7 |
8 | blinkTimer >> ([&](const TimerMsg tm) {
9 | digitalWrite(_pin, _on);
10 | _on = _on ? 0 : 1 ;
11 | });
12 |
13 | _pin = pin;
14 | blinkSlow.async(thread(),[&](bool flag) {
15 | if ( flag ) blinkTimer.interval(500);
16 | else blinkTimer.interval(100);
17 | });
18 | }
19 | void LedBlinker::init() {
20 | pinMode(_pin, OUTPUT);
21 | digitalWrite(_pin, 1);
22 | }
23 |
24 | void LedBlinker::delay(uint32_t d) {
25 | blinkTimer.interval(d);
26 | }
--------------------------------------------------------------------------------
/common/LedBlinker.h:
--------------------------------------------------------------------------------
1 | #ifndef _LED_BLINKER_H_
2 | #define _LED_BLINKER_H_
3 | #include
4 | #include
5 |
6 | class LedBlinker : public Actor {
7 | uint32_t _pin;
8 | int _on=0;
9 |
10 | public:
11 | static const int BLINK_TIMER_ID=1;
12 | TimerSource blinkTimer;
13 | Sink timerHandler;
14 | Sink blinkSlow;
15 | LedBlinker(Thread& thr,uint32_t pin, uint32_t delay);
16 | void init();
17 | void delay(uint32_t d);
18 | void onNext(const TimerMsg&);
19 | };
20 |
21 | #endif
--------------------------------------------------------------------------------
/common/common:
--------------------------------------------------------------------------------
1 | ../../common
--------------------------------------------------------------------------------
/doc/bluepill.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vortex314/mqtt2serial/c8de67dc2e9acc4176740068525c86f98ba87b2f/doc/bluepill.jpg
--------------------------------------------------------------------------------
/doc/esp32.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vortex314/mqtt2serial/c8de67dc2e9acc4176740068525c86f98ba87b2f/doc/esp32.jpg
--------------------------------------------------------------------------------
/doc/esp8266.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vortex314/mqtt2serial/c8de67dc2e9acc4176740068525c86f98ba87b2f/doc/esp8266.jpeg
--------------------------------------------------------------------------------
/doc/maple.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vortex314/mqtt2serial/c8de67dc2e9acc4176740068525c86f98ba87b2f/doc/maple.jpeg
--------------------------------------------------------------------------------
/doc/maple.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vortex314/mqtt2serial/c8de67dc2e9acc4176740068525c86f98ba87b2f/doc/maple.jpg
--------------------------------------------------------------------------------
/doc/mqtt-spy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vortex314/mqtt2serial/c8de67dc2e9acc4176740068525c86f98ba87b2f/doc/mqtt-spy.png
--------------------------------------------------------------------------------
/doc/nrf51822.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vortex314/mqtt2serial/c8de67dc2e9acc4176740068525c86f98ba87b2f/doc/nrf51822.jpeg
--------------------------------------------------------------------------------
/doc/stellaris.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vortex314/mqtt2serial/c8de67dc2e9acc4176740068525c86f98ba87b2f/doc/stellaris.jpeg
--------------------------------------------------------------------------------
/doc/ucs.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vortex314/mqtt2serial/c8de67dc2e9acc4176740068525c86f98ba87b2f/doc/ucs.jpg
--------------------------------------------------------------------------------
/esp32-bluetooth/.gitignore:
--------------------------------------------------------------------------------
1 | .pio
2 | .vscode/.browse.c_cpp.db*
3 | .vscode/c_cpp_properties.json
4 | .vscode/launch.json
5 | .vscode/ipch
6 |
--------------------------------------------------------------------------------
/esp32-bluetooth/.travis.yml:
--------------------------------------------------------------------------------
1 | # Continuous Integration (CI) is the practice, in software
2 | # engineering, of merging all developer working copies with a shared mainline
3 | # several times a day < https://docs.platformio.org/page/ci/index.html >
4 | #
5 | # Documentation:
6 | #
7 | # * Travis CI Embedded Builds with PlatformIO
8 | # < https://docs.travis-ci.com/user/integration/platformio/ >
9 | #
10 | # * PlatformIO integration with Travis CI
11 | # < https://docs.platformio.org/page/ci/travis.html >
12 | #
13 | # * User Guide for `platformio ci` command
14 | # < https://docs.platformio.org/page/userguide/cmd_ci.html >
15 | #
16 | #
17 | # Please choose one of the following templates (proposed below) and uncomment
18 | # it (remove "# " before each line) or use own configuration according to the
19 | # Travis CI documentation (see above).
20 | #
21 |
22 |
23 | #
24 | # Template #1: General project. Test it using existing `platformio.ini`.
25 | #
26 |
27 | # language: python
28 | # python:
29 | # - "2.7"
30 | #
31 | # sudo: false
32 | # cache:
33 | # directories:
34 | # - "~/.platformio"
35 | #
36 | # install:
37 | # - pip install -U platformio
38 | # - platformio update
39 | #
40 | # script:
41 | # - platformio run
42 |
43 |
44 | #
45 | # Template #2: The project is intended to be used as a library with examples.
46 | #
47 |
48 | # language: python
49 | # python:
50 | # - "2.7"
51 | #
52 | # sudo: false
53 | # cache:
54 | # directories:
55 | # - "~/.platformio"
56 | #
57 | # env:
58 | # - PLATFORMIO_CI_SRC=path/to/test/file.c
59 | # - PLATFORMIO_CI_SRC=examples/file.ino
60 | # - PLATFORMIO_CI_SRC=path/to/test/directory
61 | #
62 | # install:
63 | # - pip install -U platformio
64 | # - platformio update
65 | #
66 | # script:
67 | # - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N
68 |
--------------------------------------------------------------------------------
/esp32-bluetooth/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // See http://go.microsoft.com/fwlink/?LinkId=827846
3 | // for the documentation about the extensions.json format
4 | "recommendations": [
5 | "platformio.platformio-ide"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/esp32-bluetooth/include/README:
--------------------------------------------------------------------------------
1 |
2 | This directory is intended for project header files.
3 |
4 | A header file is a file containing C declarations and macro definitions
5 | to be shared between several project source files. You request the use of a
6 | header file in your project source file (C, C++, etc) located in `src` folder
7 | by including it, with the C preprocessing directive `#include'.
8 |
9 | ```src/main.c
10 |
11 | #include "header.h"
12 |
13 | int main (void)
14 | {
15 | ...
16 | }
17 | ```
18 |
19 | Including a header file produces the same results as copying the header file
20 | into each source file that needs it. Such copying would be time-consuming
21 | and error-prone. With a header file, the related declarations appear
22 | in only one place. If they need to be changed, they can be changed in one
23 | place, and programs that include the header file will automatically use the
24 | new version when next recompiled. The header file eliminates the labor of
25 | finding and changing all the copies as well as the risk that a failure to
26 | find one copy will result in inconsistencies within a program.
27 |
28 | In C, the usual convention is to give header files names that end with `.h'.
29 | It is most portable to use only letters, digits, dashes, and underscores in
30 | header file names, and at most one dot.
31 |
32 | Read more about using header files in official GCC documentation:
33 |
34 | * Include Syntax
35 | * Include Operation
36 | * Once-Only Headers
37 | * Computed Includes
38 |
39 | https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
40 |
--------------------------------------------------------------------------------
/esp32-bluetooth/lib/README:
--------------------------------------------------------------------------------
1 |
2 | This directory is intended for project specific (private) libraries.
3 | PlatformIO will compile them to static libraries and link into executable file.
4 |
5 | The source code of each library should be placed in a an own separate directory
6 | ("lib/your_library_name/[here are source files]").
7 |
8 | For example, see a structure of the following two libraries `Foo` and `Bar`:
9 |
10 | |--lib
11 | | |
12 | | |--Bar
13 | | | |--docs
14 | | | |--examples
15 | | | |--src
16 | | | |- Bar.c
17 | | | |- Bar.h
18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
19 | | |
20 | | |--Foo
21 | | | |- Foo.c
22 | | | |- Foo.h
23 | | |
24 | | |- README --> THIS FILE
25 | |
26 | |- platformio.ini
27 | |--src
28 | |- main.c
29 |
30 | and a contents of `src/main.c`:
31 | ```
32 | #include
33 | #include
34 |
35 | int main (void)
36 | {
37 | ...
38 | }
39 |
40 | ```
41 |
42 | PlatformIO Library Dependency Finder will find automatically dependent
43 | libraries scanning project source files.
44 |
45 | More information about PlatformIO Library Dependency Finder
46 | - https://docs.platformio.org/page/librarymanager/ldf.html
47 |
--------------------------------------------------------------------------------
/esp32-bluetooth/platformio.ini:
--------------------------------------------------------------------------------
1 | ;PlatformIO Project Configuration File
2 | ;
3 | ; Build options: build flags, source filter
4 | ; Upload options: custom upload port, speed and extra flags
5 | ; Library options: dependencies, extra library storages
6 | ; Advanced options: extra scripting
7 | ;
8 | ; Please visit documentation for the other options and examples
9 | ; https://docs.platformio.org/page/projectconf.html
10 |
11 | [env:esp32doit-devkit-v1]
12 | platform = espressif32
13 | board = esp32doit-devkit-v1
14 | framework = arduino
15 | build_flags =
16 | -I../common
17 | -I../../limero/inc
18 | -I../../limero/arduino
19 | -I../../ArduinoJson/src
20 | -std=c++11
21 | -DCPU=esp32
22 | -DBOARD=esp32doit-devkit-v1
23 | -DPLATFORM=$PIOPLATFORM
24 | -DHOSTNAME=bluetooth
25 | monitor_port = /dev/ttyUSB0
26 | monitor_speed = 115200
27 | upload_port = /dev/ttyUSB0
28 | upload_speed=921600
29 |
--------------------------------------------------------------------------------
/esp32-bluetooth/src/README.MD:
--------------------------------------------------------------------------------
1 | # Bluetooth serial
2 | A small attempt at using Bluetooth as serial comm port for MQTT
3 | ## Linux serial port over bluetooth
4 | https://medium.com/@18218004/devlog-6-bluetooth-and-esp32-ba076a8e207d
5 | ## serial2mqtt over bluetooth
6 | Config file.
7 | ```
8 | {
9 | "mqtt": {
10 | "connection": "tcp://limero.ddns.net:1883"
11 | },
12 | "serial": {
13 | "baudrate": 115200,
14 | "ports": [
15 | "/dev/rfcomm0"
16 | ],
17 | "protocol": "jsonArray"
18 | },
19 | "log": {
20 | "protocol": true,
21 | "debug": true,
22 | "useColors": true,
23 | "mqtt": false,
24 | "program": false,
25 | "level": "I",
26 | "file": "log.serial2mqtt.",
27 | "console": true
28 | }
29 | }
30 | ```
--------------------------------------------------------------------------------
/esp32-bluetooth/src/arduino:
--------------------------------------------------------------------------------
1 | ../../../limero/arduino/
--------------------------------------------------------------------------------
/esp32-bluetooth/src/common:
--------------------------------------------------------------------------------
1 | ../../common
--------------------------------------------------------------------------------
/esp32-bluetooth/src/main.cpp:
--------------------------------------------------------------------------------
1 | //This example code is in the Public Domain (or CC0 licensed, at your option.)
2 | //By Evandro Copercini - 2018
3 | //
4 | //This example creates a bridge between Serial and Classical Bluetooth (SPP)
5 | //and also demonstrate that SerialBT have the same functionalities of a normal Serial
6 |
7 | #include "BluetoothSerial.h"
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | #define PIN_LED 2
16 | #define PIN_BUTTON 0
17 |
18 | #if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
19 | #error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
20 | #endif
21 |
22 | BluetoothSerial SerialBT;
23 |
24 | void loopBT()
25 | {
26 | if (Serial.available())
27 | {
28 | SerialBT.write(Serial.read());
29 | }
30 | if (SerialBT.available())
31 | {
32 | Serial.write(SerialBT.read());
33 | }
34 | delay(20);
35 | }
36 |
37 | Thread mainThread("main");
38 | LedBlinker ledBlinkerBlue(mainThread, PIN_LED, 100);
39 | Button button1(mainThread, PIN_BUTTON);
40 | Poller poller(mainThread);
41 | MqttSerial mqtt(mainThread, SerialBT);
42 | Log logger(1024);
43 |
44 | LambdaSource systemHeap([]() { return ESP.getFreeHeap(); });
45 | LambdaSource systemUptime([]() { return Sys::millis(); });
46 | LambdaSource systemHostname([]() { return Sys::hostname(); });
47 | LambdaSource systemBoard([]() { return Sys::board(); });
48 | LambdaSource systemCpu([]() { return Sys::cpu(); });
49 | ValueSource systemBuild = __DATE__ " " __TIME__;
50 |
51 | void serialBTEvent()
52 | {
53 | INFO("-");
54 | MqttSerial::onRxd(&mqtt);
55 | }
56 |
57 | uint8_t macPc[] = {0x00, 0x15, 0x83, 0x47, 0x43, 0x5F};
58 | uint8_t macMe[] = {0x30, 0xae, 0xa4, 0x1d, 0x81, 0x06}; // 30:AE:A4:1D:81:06
59 |
60 | void setup()
61 | {
62 | Serial.begin(115200);
63 | SerialBT.begin("ESP32-BT"); //Bluetooth device nam
64 | SerialBT.connect(macPc);
65 | Serial.println("\r\n===== Starting build " __DATE__ " " __TIME__);
66 |
67 | Sys::hostname(S(HOSTNAME));
68 |
69 | button1.init();
70 | ledBlinkerBlue.init();
71 | mqtt.init();
72 |
73 | mqtt.connected >> ledBlinkerBlue.blinkSlow;
74 | mqtt.connected >> poller.connected;
75 | mqtt.connected >> mqtt.toTopic("mqtt/connected");
76 |
77 | poller >> systemHeap >> mqtt.toTopic("system/heap");
78 | poller >> systemUptime >> mqtt.toTopic("system/upTime");
79 | poller >> systemBuild >> mqtt.toTopic("system/build");
80 | poller >> systemHostname >> mqtt.toTopic("system/hostname");
81 | poller >> systemBoard >> mqtt.toTopic("system/board");
82 | poller >> systemCpu >> mqtt.toTopic("system/cpu");
83 | poller >> button1 >> mqtt.toTopic("button/button1");
84 | }
85 |
86 | void loop()
87 | {
88 | mainThread.loop();
89 | if (SerialBT.available())
90 | {
91 | MqttSerial::onRxd(&mqtt);
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/esp32-bluetooth/test/README:
--------------------------------------------------------------------------------
1 |
2 | This directory is intended for PIO Unit Testing and project tests.
3 |
4 | Unit Testing is a software testing method by which individual units of
5 | source code, sets of one or more MCU program modules together with associated
6 | control data, usage procedures, and operating procedures, are tested to
7 | determine whether they are fit for use. Unit testing finds problems early
8 | in the development cycle.
9 |
10 | More information about PIO Unit Testing:
11 | - https://docs.platformio.org/page/plus/unit-testing.html
12 |
--------------------------------------------------------------------------------
/esp32/.gitignore:
--------------------------------------------------------------------------------
1 | .pio
2 | .vscode/.browse.c_cpp.db*
3 | .vscode/c_cpp_properties.json
4 | .vscode/launch.json
5 | .vscode/ipch
6 |
--------------------------------------------------------------------------------
/esp32/.travis.yml:
--------------------------------------------------------------------------------
1 | # Continuous Integration (CI) is the practice, in software
2 | # engineering, of merging all developer working copies with a shared mainline
3 | # several times a day < https://docs.platformio.org/page/ci/index.html >
4 | #
5 | # Documentation:
6 | #
7 | # * Travis CI Embedded Builds with PlatformIO
8 | # < https://docs.travis-ci.com/user/integration/platformio/ >
9 | #
10 | # * PlatformIO integration with Travis CI
11 | # < https://docs.platformio.org/page/ci/travis.html >
12 | #
13 | # * User Guide for `platformio ci` command
14 | # < https://docs.platformio.org/page/userguide/cmd_ci.html >
15 | #
16 | #
17 | # Please choose one of the following templates (proposed below) and uncomment
18 | # it (remove "# " before each line) or use own configuration according to the
19 | # Travis CI documentation (see above).
20 | #
21 |
22 |
23 | #
24 | # Template #1: General project. Test it using existing `platformio.ini`.
25 | #
26 |
27 | # language: python
28 | # python:
29 | # - "2.7"
30 | #
31 | # sudo: false
32 | # cache:
33 | # directories:
34 | # - "~/.platformio"
35 | #
36 | # install:
37 | # - pip install -U platformio
38 | # - platformio update
39 | #
40 | # script:
41 | # - platformio run
42 |
43 |
44 | #
45 | # Template #2: The project is intended to be used as a library with examples.
46 | #
47 |
48 | # language: python
49 | # python:
50 | # - "2.7"
51 | #
52 | # sudo: false
53 | # cache:
54 | # directories:
55 | # - "~/.platformio"
56 | #
57 | # env:
58 | # - PLATFORMIO_CI_SRC=path/to/test/file.c
59 | # - PLATFORMIO_CI_SRC=examples/file.ino
60 | # - PLATFORMIO_CI_SRC=path/to/test/directory
61 | #
62 | # install:
63 | # - pip install -U platformio
64 | # - platformio update
65 | #
66 | # script:
67 | # - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N
68 |
--------------------------------------------------------------------------------
/esp32/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // See http://go.microsoft.com/fwlink/?LinkId=827846
3 | // for the documentation about the extensions.json format
4 | "recommendations": [
5 | "platformio.platformio-ide"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/esp32/include/README:
--------------------------------------------------------------------------------
1 |
2 | This directory is intended for project header files.
3 |
4 | A header file is a file containing C declarations and macro definitions
5 | to be shared between several project source files. You request the use of a
6 | header file in your project source file (C, C++, etc) located in `src` folder
7 | by including it, with the C preprocessing directive `#include'.
8 |
9 | ```src/main.c
10 |
11 | #include "header.h"
12 |
13 | int main (void)
14 | {
15 | ...
16 | }
17 | ```
18 |
19 | Including a header file produces the same results as copying the header file
20 | into each source file that needs it. Such copying would be time-consuming
21 | and error-prone. With a header file, the related declarations appear
22 | in only one place. If they need to be changed, they can be changed in one
23 | place, and programs that include the header file will automatically use the
24 | new version when next recompiled. The header file eliminates the labor of
25 | finding and changing all the copies as well as the risk that a failure to
26 | find one copy will result in inconsistencies within a program.
27 |
28 | In C, the usual convention is to give header files names that end with `.h'.
29 | It is most portable to use only letters, digits, dashes, and underscores in
30 | header file names, and at most one dot.
31 |
32 | Read more about using header files in official GCC documentation:
33 |
34 | * Include Syntax
35 | * Include Operation
36 | * Once-Only Headers
37 | * Computed Includes
38 |
39 | https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
40 |
--------------------------------------------------------------------------------
/esp32/lib/README:
--------------------------------------------------------------------------------
1 |
2 | This directory is intended for project specific (private) libraries.
3 | PlatformIO will compile them to static libraries and link into executable file.
4 |
5 | The source code of each library should be placed in a an own separate directory
6 | ("lib/your_library_name/[here are source files]").
7 |
8 | For example, see a structure of the following two libraries `Foo` and `Bar`:
9 |
10 | |--lib
11 | | |
12 | | |--Bar
13 | | | |--docs
14 | | | |--examples
15 | | | |--src
16 | | | |- Bar.c
17 | | | |- Bar.h
18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
19 | | |
20 | | |--Foo
21 | | | |- Foo.c
22 | | | |- Foo.h
23 | | |
24 | | |- README --> THIS FILE
25 | |
26 | |- platformio.ini
27 | |--src
28 | |- main.c
29 |
30 | and a contents of `src/main.c`:
31 | ```
32 | #include
33 | #include
34 |
35 | int main (void)
36 | {
37 | ...
38 | }
39 |
40 | ```
41 |
42 | PlatformIO Library Dependency Finder will find automatically dependent
43 | libraries scanning project source files.
44 |
45 | More information about PlatformIO Library Dependency Finder
46 | - https://docs.platformio.org/page/librarymanager/ldf.html
47 |
--------------------------------------------------------------------------------
/esp32/platformio.ini:
--------------------------------------------------------------------------------
1 | ;PlatformIO Project Configuration File
2 | ;
3 | ; Build options: build flags, source filter
4 | ; Upload options: custom upload port, speed and extra flags
5 | ; Library options: dependencies, extra library storages
6 | ; Advanced options: extra scripting
7 | ;
8 | ; Please visit documentation for the other options and examples
9 | ; https://docs.platformio.org/page/projectconf.html
10 |
11 | [env:esp32doit-devkit-v1]
12 | platform = espressif32
13 | board = esp32doit-devkit-v1
14 | framework = arduino
15 | build_flags =
16 | -I../common
17 | -I../../limero/inc
18 | -I../../limero/arduino
19 | -I../../ArduinoJson/src
20 | -std=c++11
21 | -DCPU=esp32
22 | -DBOARD=esp32doit-devkit-v1
23 | -DPLATFORM=$PIOPLATFORM
24 | -DHOSTNAME=$PIOPLATFORM
25 | monitor_port = /dev/ttyUSB0
26 | monitor_speed = 115200
27 | upload_port = /dev/ttyUSB0
28 | upload_speed=921600
--------------------------------------------------------------------------------
/esp32/src/arduino:
--------------------------------------------------------------------------------
1 | ../../../limero/arduino/
--------------------------------------------------------------------------------
/esp32/src/common:
--------------------------------------------------------------------------------
1 | ../../common
--------------------------------------------------------------------------------
/esp32/src/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include
6 | #define PIN_LED 2
7 | #define PIN_BUTTON 0
8 | #include
9 | #include
10 | #include
11 |
12 | Thread mainThread("main");
13 | LedBlinker ledBlinkerBlue(mainThread, PIN_LED, 100);
14 | Button button1(mainThread, PIN_BUTTON);
15 | Poller poller(mainThread);
16 | MqttSerial mqtt(mainThread,Serial);
17 | Log logger(1024);
18 |
19 | LambdaSource systemHeap([]() { return ESP.getFreeHeap(); });
20 | LambdaSource systemUptime([]() { return Sys::millis(); });
21 | LambdaSource systemHostname([]() { return Sys::hostname(); });
22 | LambdaSource systemBoard([]() { return Sys::board(); });
23 | LambdaSource systemCpu([]() { return Sys::cpu(); });
24 | ValueSource systemBuild = __DATE__ " " __TIME__;
25 |
26 | void serialEvent() {
27 | INFO("-");
28 | MqttSerial::onRxd(&mqtt);
29 | }
30 |
31 | void setup() {
32 | Serial.begin(115200);
33 | Serial.println("\r\n===== Starting build " __DATE__ " " __TIME__);
34 |
35 | Sys::hostname(S(HOSTNAME));
36 |
37 | button1.init();
38 | ledBlinkerBlue.init();
39 | mqtt.init();
40 |
41 | mqtt.connected >> ledBlinkerBlue.blinkSlow;
42 | mqtt.connected >> poller.connected;
43 | mqtt.connected >> mqtt.toTopic("mqtt/connected");
44 |
45 | poller >> systemHeap >> mqtt.toTopic("system/heap");
46 | poller >> systemUptime >> mqtt.toTopic("system/upTime");
47 | poller >> systemBuild >> mqtt.toTopic("system/build");
48 | poller >> systemHostname >> mqtt.toTopic("system/hostname");
49 | poller >> systemBoard >> mqtt.toTopic("system/board");
50 | poller >> systemCpu >> mqtt.toTopic("system/cpu");
51 | poller >> button1 >> mqtt.toTopic("button/button1");
52 |
53 | }
54 |
55 | void loop() {
56 | mainThread.loop();
57 | if (Serial.available()) {
58 | MqttSerial::onRxd(&mqtt);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/esp32/test/README:
--------------------------------------------------------------------------------
1 |
2 | This directory is intended for PIO Unit Testing and project tests.
3 |
4 | Unit Testing is a software testing method by which individual units of
5 | source code, sets of one or more MCU program modules together with associated
6 | control data, usage procedures, and operating procedures, are tested to
7 | determine whether they are fit for use. Unit testing finds problems early
8 | in the development cycle.
9 |
10 | More information about PIO Unit Testing:
11 | - https://docs.platformio.org/page/plus/unit-testing.html
12 |
--------------------------------------------------------------------------------
/esp8266/.gitignore:
--------------------------------------------------------------------------------
1 | .pio
2 | .vscode/.browse.c_cpp.db*
3 | .vscode/c_cpp_properties.json
4 | .vscode/launch.json
5 | .vscode/ipch
6 |
--------------------------------------------------------------------------------
/esp8266/.travis.yml:
--------------------------------------------------------------------------------
1 | # Continuous Integration (CI) is the practice, in software
2 | # engineering, of merging all developer working copies with a shared mainline
3 | # several times a day < https://docs.platformio.org/page/ci/index.html >
4 | #
5 | # Documentation:
6 | #
7 | # * Travis CI Embedded Builds with PlatformIO
8 | # < https://docs.travis-ci.com/user/integration/platformio/ >
9 | #
10 | # * PlatformIO integration with Travis CI
11 | # < https://docs.platformio.org/page/ci/travis.html >
12 | #
13 | # * User Guide for `platformio ci` command
14 | # < https://docs.platformio.org/page/userguide/cmd_ci.html >
15 | #
16 | #
17 | # Please choose one of the following templates (proposed below) and uncomment
18 | # it (remove "# " before each line) or use own configuration according to the
19 | # Travis CI documentation (see above).
20 | #
21 |
22 |
23 | #
24 | # Template #1: General project. Test it using existing `platformio.ini`.
25 | #
26 |
27 | # language: python
28 | # python:
29 | # - "2.7"
30 | #
31 | # sudo: false
32 | # cache:
33 | # directories:
34 | # - "~/.platformio"
35 | #
36 | # install:
37 | # - pip install -U platformio
38 | # - platformio update
39 | #
40 | # script:
41 | # - platformio run
42 |
43 |
44 | #
45 | # Template #2: The project is intended to be used as a library with examples.
46 | #
47 |
48 | # language: python
49 | # python:
50 | # - "2.7"
51 | #
52 | # sudo: false
53 | # cache:
54 | # directories:
55 | # - "~/.platformio"
56 | #
57 | # env:
58 | # - PLATFORMIO_CI_SRC=path/to/test/file.c
59 | # - PLATFORMIO_CI_SRC=examples/file.ino
60 | # - PLATFORMIO_CI_SRC=path/to/test/directory
61 | #
62 | # install:
63 | # - pip install -U platformio
64 | # - platformio update
65 | #
66 | # script:
67 | # - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N
68 |
--------------------------------------------------------------------------------
/esp8266/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // See http://go.microsoft.com/fwlink/?LinkId=827846
3 | // for the documentation about the extensions.json format
4 | "recommendations": [
5 | "platformio.platformio-ide"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/esp8266/include/README:
--------------------------------------------------------------------------------
1 |
2 | This directory is intended for project header files.
3 |
4 | A header file is a file containing C declarations and macro definitions
5 | to be shared between several project source files. You request the use of a
6 | header file in your project source file (C, C++, etc) located in `src` folder
7 | by including it, with the C preprocessing directive `#include'.
8 |
9 | ```src/main.c
10 |
11 | #include "header.h"
12 |
13 | int main (void)
14 | {
15 | ...
16 | }
17 | ```
18 |
19 | Including a header file produces the same results as copying the header file
20 | into each source file that needs it. Such copying would be time-consuming
21 | and error-prone. With a header file, the related declarations appear
22 | in only one place. If they need to be changed, they can be changed in one
23 | place, and programs that include the header file will automatically use the
24 | new version when next recompiled. The header file eliminates the labor of
25 | finding and changing all the copies as well as the risk that a failure to
26 | find one copy will result in inconsistencies within a program.
27 |
28 | In C, the usual convention is to give header files names that end with `.h'.
29 | It is most portable to use only letters, digits, dashes, and underscores in
30 | header file names, and at most one dot.
31 |
32 | Read more about using header files in official GCC documentation:
33 |
34 | * Include Syntax
35 | * Include Operation
36 | * Once-Only Headers
37 | * Computed Includes
38 |
39 | https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
40 |
--------------------------------------------------------------------------------
/esp8266/lib/README:
--------------------------------------------------------------------------------
1 |
2 | This directory is intended for project specific (private) libraries.
3 | PlatformIO will compile them to static libraries and link into executable file.
4 |
5 | The source code of each library should be placed in a an own separate directory
6 | ("lib/your_library_name/[here are source files]").
7 |
8 | For example, see a structure of the following two libraries `Foo` and `Bar`:
9 |
10 | |--lib
11 | | |
12 | | |--Bar
13 | | | |--docs
14 | | | |--examples
15 | | | |--src
16 | | | |- Bar.c
17 | | | |- Bar.h
18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
19 | | |
20 | | |--Foo
21 | | | |- Foo.c
22 | | | |- Foo.h
23 | | |
24 | | |- README --> THIS FILE
25 | |
26 | |- platformio.ini
27 | |--src
28 | |- main.c
29 |
30 | and a contents of `src/main.c`:
31 | ```
32 | #include
33 | #include
34 |
35 | int main (void)
36 | {
37 | ...
38 | }
39 |
40 | ```
41 |
42 | PlatformIO Library Dependency Finder will find automatically dependent
43 | libraries scanning project source files.
44 |
45 | More information about PlatformIO Library Dependency Finder
46 | - https://docs.platformio.org/page/librarymanager/ldf.html
47 |
--------------------------------------------------------------------------------
/esp8266/platformio.ini:
--------------------------------------------------------------------------------
1 | ;PlatformIO Project Configuration File
2 | ;
3 | ; Build options: build flags, source filter
4 | ; Upload options: custom upload port, speed and extra flags
5 | ; Library options: dependencies, extra library storages
6 | ; Advanced options: extra scripting
7 | ;
8 | ; Please visit documentation for the other options and examples
9 | ; https://docs.platformio.org/page/projectconf.html
10 |
11 | [env:nodemcuv2]
12 | platform = espressif8266
13 | board = nodemcuv2
14 | framework = arduino
15 | upload_speed=921600
16 | upload_port=/dev/ttyUSB0
17 | monitor_port = /dev/ttyUSB0
18 | monitor_speed = 115200
19 | build_flags =
20 | -I../common
21 | -I../../limero/inc
22 | -I../../limero/arduino
23 | -I../../ArduinoJson/src
24 | -std=c++11
25 | -DCPU=esp8266
26 | -DBOARD=nodemcuv2
27 | -DPLATFORM=$PIOPLATFORM
28 | -DHOSTNAME=esp8266
29 | lib_extra_dirs =
30 | ../../limero/arduino/
31 |
32 |
--------------------------------------------------------------------------------
/esp8266/src/arduino:
--------------------------------------------------------------------------------
1 | ../../../limero/arduino/
--------------------------------------------------------------------------------
/esp8266/src/common:
--------------------------------------------------------------------------------
1 | ../../common
--------------------------------------------------------------------------------
/esp8266/src/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include
6 | #define PIN_LED 2
7 | #define PIN_BUTTON 0
8 | #include
9 | #include
10 | #include
11 |
12 | Thread mainThread("main");
13 | LedBlinker ledBlinkerBlue(mainThread, PIN_LED, 100);
14 | Button button1(mainThread, PIN_BUTTON);
15 | Poller poller(mainThread);
16 | MqttSerial mqtt(mainThread,Serial);
17 | Log logger(1024);
18 |
19 | LambdaSource systemHeap([]() { return ESP.getFreeHeap(); });
20 | LambdaSource systemUptime([]() { return Sys::millis(); });
21 | LambdaSource systemHostname([]() { return Sys::hostname(); });
22 | LambdaSource systemBoard([]() { return Sys::board(); });
23 | LambdaSource systemCpu([]() { return Sys::cpu(); });
24 | ValueSource systemBuild = __DATE__ " " __TIME__;
25 |
26 | void serialEvent() {
27 | INFO("-");
28 | MqttSerial::onRxd(&mqtt);
29 | }
30 |
31 | void setup() {
32 | Serial.begin(115200);
33 | Serial.println("\r\n===== Starting build " __DATE__ " " __TIME__);
34 |
35 | Sys::hostname(S(HOSTNAME));
36 |
37 | button1.init();
38 | ledBlinkerBlue.init();
39 | mqtt.init();
40 |
41 | mqtt.connected >> ledBlinkerBlue.blinkSlow;
42 | mqtt.connected >> poller.connected;
43 | mqtt.connected >> mqtt.toTopic("mqtt/connected");
44 |
45 | poller >> systemHeap >> mqtt.toTopic("system/heap");
46 | poller >> systemUptime >> mqtt.toTopic("system/upTime");
47 | poller >> systemBuild >> mqtt.toTopic("system/build");
48 | poller >> systemHostname >> mqtt.toTopic("system/hostname");
49 | poller >> systemBoard >> mqtt.toTopic("system/board");
50 | poller >> systemCpu >> mqtt.toTopic("system/cpu");
51 | poller >> button1 >> mqtt.toTopic("button/button1");
52 |
53 | }
54 |
55 | void loop() {
56 | mainThread.loop();
57 | if (Serial.available()) {
58 | MqttSerial::onRxd(&mqtt);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/esp8266/test/README:
--------------------------------------------------------------------------------
1 |
2 | This directory is intended for PIO Unit Testing and project tests.
3 |
4 | Unit Testing is a software testing method by which individual units of
5 | source code, sets of one or more MCU program modules together with associated
6 | control data, usage procedures, and operating procedures, are tested to
7 | determine whether they are fit for use. Unit testing finds problems early
8 | in the development cycle.
9 |
10 | More information about PIO Unit Testing:
11 | - https://docs.platformio.org/page/plus/unit-testing.html
12 |
--------------------------------------------------------------------------------
/lm4f120-cm3/.gitignore:
--------------------------------------------------------------------------------
1 | .pio
2 | .vscode/.browse.c_cpp.db*
3 | .vscode/c_cpp_properties.json
4 | .vscode/launch.json
5 | .vscode/ipch
6 |
--------------------------------------------------------------------------------
/lm4f120-cm3/.travis.yml:
--------------------------------------------------------------------------------
1 | # Continuous Integration (CI) is the practice, in software
2 | # engineering, of merging all developer working copies with a shared mainline
3 | # several times a day < https://docs.platformio.org/page/ci/index.html >
4 | #
5 | # Documentation:
6 | #
7 | # * Travis CI Embedded Builds with PlatformIO
8 | # < https://docs.travis-ci.com/user/integration/platformio/ >
9 | #
10 | # * PlatformIO integration with Travis CI
11 | # < https://docs.platformio.org/page/ci/travis.html >
12 | #
13 | # * User Guide for `platformio ci` command
14 | # < https://docs.platformio.org/page/userguide/cmd_ci.html >
15 | #
16 | #
17 | # Please choose one of the following templates (proposed below) and uncomment
18 | # it (remove "# " before each line) or use own configuration according to the
19 | # Travis CI documentation (see above).
20 | #
21 |
22 |
23 | #
24 | # Template #1: General project. Test it using existing `platformio.ini`.
25 | #
26 |
27 | # language: python
28 | # python:
29 | # - "2.7"
30 | #
31 | # sudo: false
32 | # cache:
33 | # directories:
34 | # - "~/.platformio"
35 | #
36 | # install:
37 | # - pip install -U platformio
38 | # - platformio update
39 | #
40 | # script:
41 | # - platformio run
42 |
43 |
44 | #
45 | # Template #2: The project is intended to be used as a library with examples.
46 | #
47 |
48 | # language: python
49 | # python:
50 | # - "2.7"
51 | #
52 | # sudo: false
53 | # cache:
54 | # directories:
55 | # - "~/.platformio"
56 | #
57 | # env:
58 | # - PLATFORMIO_CI_SRC=path/to/test/file.c
59 | # - PLATFORMIO_CI_SRC=examples/file.ino
60 | # - PLATFORMIO_CI_SRC=path/to/test/directory
61 | #
62 | # install:
63 | # - pip install -U platformio
64 | # - platformio update
65 | #
66 | # script:
67 | # - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N
68 |
--------------------------------------------------------------------------------
/lm4f120-cm3/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // See http://go.microsoft.com/fwlink/?LinkId=827846
3 | // for the documentation about the extensions.json format
4 | "recommendations": [
5 | "platformio.platformio-ide"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/lm4f120-cm3/flash.ld:
--------------------------------------------------------------------------------
1 | /*
2 | * libmaple linker script for "Flash" builds.
3 | *
4 | * A Flash build puts .text (and .rodata) in Flash, and
5 | * .data/.bss/heap (of course) in SRAM, but offsets the sections by
6 | * enough space to store the Maple bootloader, which lives in low
7 | * Flash and uses low memory.
8 | */
9 |
10 | /*
11 | * This pulls in the appropriate MEMORY declaration from the right
12 | * subdirectory of stm32/mem/ (the environment must call ld with the
13 | * right include directory flags to make this happen). Boards can also
14 | * use this file to use any of libmaple's memory-related hooks (like
15 | * where the heap should live).
16 | */
17 | /*INCLUDE "C:\Temp\Platformio Projects\bluepill\src\mem-flash.inc"
18 | */
19 | /* Provide memory region aliases for common.inc */
20 | REGION_ALIAS("REGION_TEXT", rom);
21 | REGION_ALIAS("REGION_DATA", ram);
22 | REGION_ALIAS("REGION_BSS", ram);
23 | REGION_ALIAS("REGION_RODATA", rom);
24 |
25 | /* Let common.inc handle the real work. */
26 | INCLUDE common.inc
27 | MEMORY
28 | {
29 | rom (rx) : ORIGIN = 0x00000000, LENGTH = 256K
30 | ram (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
31 | }
--------------------------------------------------------------------------------
/lm4f120-cm3/include/README:
--------------------------------------------------------------------------------
1 |
2 | This directory is intended for project header files.
3 |
4 | A header file is a file containing C declarations and macro definitions
5 | to be shared between several project source files. You request the use of a
6 | header file in your project source file (C, C++, etc) located in `src` folder
7 | by including it, with the C preprocessing directive `#include'.
8 |
9 | ```src/main.c
10 |
11 | #include "header.h"
12 |
13 | int main (void)
14 | {
15 | ...
16 | }
17 | ```
18 |
19 | Including a header file produces the same results as copying the header file
20 | into each source file that needs it. Such copying would be time-consuming
21 | and error-prone. With a header file, the related declarations appear
22 | in only one place. If they need to be changed, they can be changed in one
23 | place, and programs that include the header file will automatically use the
24 | new version when next recompiled. The header file eliminates the labor of
25 | finding and changing all the copies as well as the risk that a failure to
26 | find one copy will result in inconsistencies within a program.
27 |
28 | In C, the usual convention is to give header files names that end with `.h'.
29 | It is most portable to use only letters, digits, dashes, and underscores in
30 | header file names, and at most one dot.
31 |
32 | Read more about using header files in official GCC documentation:
33 |
34 | * Include Syntax
35 | * Include Operation
36 | * Once-Only Headers
37 | * Computed Includes
38 |
39 | https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
40 |
--------------------------------------------------------------------------------
/lm4f120-cm3/lib/README:
--------------------------------------------------------------------------------
1 |
2 | This directory is intended for project specific (private) libraries.
3 | PlatformIO will compile them to static libraries and link into executable file.
4 |
5 | The source code of each library should be placed in a an own separate directory
6 | ("lib/your_library_name/[here are source files]").
7 |
8 | For example, see a structure of the following two libraries `Foo` and `Bar`:
9 |
10 | |--lib
11 | | |
12 | | |--Bar
13 | | | |--docs
14 | | | |--examples
15 | | | |--src
16 | | | |- Bar.c
17 | | | |- Bar.h
18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
19 | | |
20 | | |--Foo
21 | | | |- Foo.c
22 | | | |- Foo.h
23 | | |
24 | | |- README --> THIS FILE
25 | |
26 | |- platformio.ini
27 | |--src
28 | |- main.c
29 |
30 | and a contents of `src/main.c`:
31 | ```
32 | #include
33 | #include
34 |
35 | int main (void)
36 | {
37 | ...
38 | }
39 |
40 | ```
41 |
42 | PlatformIO Library Dependency Finder will find automatically dependent
43 | libraries scanning project source files.
44 |
45 | More information about PlatformIO Library Dependency Finder
46 | - https://docs.platformio.org/page/librarymanager/ldf.html
47 |
--------------------------------------------------------------------------------
/lm4f120-cm3/platformio.ini:
--------------------------------------------------------------------------------
1 | ;PlatformIO Project Configuration File
2 | ;
3 | ; Build options: build flags, source filter
4 | ; Upload options: custom upload port, speed and extra flags
5 | ; Library options: dependencies, extra library storages
6 | ; Advanced options: extra scripting
7 | ;
8 | ; Please visit documentation for the other options and examples
9 | ; https://docs.platformio.org/page/projectconf.html
10 |
11 | [env:lplm4f120h5qr]
12 | platform = titiva
13 | board = lplm4f120h5qr
14 | framework = libopencm3
15 | lib_deps=
16 | ArduinoJson
17 | build_flags =
18 | -I../../ArduinoJson/src
19 | -I ../../Common
20 | -fno-exceptions -fno-rtti
21 | -llibstdc++
22 | -llibc
23 | ; -std=c++11
24 | -DLM4F_OPENCM3
25 | ; -Wl,-T${platformio.src_dir}/../flash.ld,-v
26 |
27 |
--------------------------------------------------------------------------------
/lm4f120-cm3/src/Hardware.h:
--------------------------------------------------------------------------------
1 | #ifndef HARDWARE_H
2 | #define HARDWARE_H
3 | #include
4 | #include
5 |
6 | class Bytes;
7 |
8 | typedef void (*FunctionPointer)(void*);
9 |
10 | typedef uint32_t Erc;
11 | typedef uint32_t PhysicalPin;
12 | typedef enum {
13 | LP_TXD = 0,
14 | LP_RXD,
15 | LP_SCL,
16 | LP_SDA,
17 | LP_MISO,
18 | LP_MOSI,
19 | LP_SCK,
20 | LP_CS
21 | } LogicalPin;
22 |
23 | class Driver {
24 | public:
25 | virtual Erc init() = 0;
26 | virtual Erc deInit() = 0;
27 | };
28 |
29 | class UART : public Driver {
30 | public:
31 | static UART& create(uint32_t module,PhysicalPin txd, PhysicalPin rxd);
32 | virtual Erc mode(const char*)=0;
33 | virtual Erc init() = 0;
34 | virtual Erc deInit() = 0;
35 | virtual Erc setClock(uint32_t clock) = 0;
36 |
37 | virtual Erc write(const uint8_t* data, uint32_t length) = 0;
38 | virtual Erc write(uint8_t b) = 0;
39 | virtual Erc read(Bytes& bytes) = 0;
40 | virtual uint8_t read() = 0;
41 | virtual void onRxd(FunctionPointer, void*) = 0;
42 | virtual void onTxd(FunctionPointer, void*) = 0;
43 | virtual uint32_t hasSpace() = 0;
44 | virtual uint32_t hasData() = 0;
45 | };
46 |
47 | //===================================================== GPIO DigitalIn ========
48 |
49 | class DigitalIn : public Driver {
50 | public:
51 | typedef enum { DIN_NONE, DIN_RAISE, DIN_FALL, DIN_CHANGE } PinChange;
52 |
53 | typedef enum { DIN_PULL_UP = 1, DIN_PULL_DOWN = 2 } Mode;
54 | static DigitalIn& create(PhysicalPin pin);
55 | virtual int read() = 0;
56 | virtual Erc init() = 0;
57 | virtual Erc deInit() = 0;
58 | virtual Erc onChange(PinChange pinChange, FunctionPointer fp,
59 | void* object) = 0;
60 | virtual Erc setMode(Mode m) = 0;
61 | virtual PhysicalPin getPin() = 0;
62 | };
63 | //===================================================== GPIO DigitalOut
64 | class DigitalOut : public Driver {
65 | public:
66 | static DigitalOut& create(PhysicalPin pin);
67 | virtual Erc init() = 0;
68 | virtual Erc deInit() = 0;
69 | virtual Erc write(int) = 0;
70 | virtual PhysicalPin getPin() = 0;
71 | };
72 | //===================================================== I2C ===
73 |
74 | #define I2C_WRITE_BIT
75 | #define I2C_READ_BIT 0
76 |
77 | class I2C : public Driver {
78 | public:
79 | static I2C& create(PhysicalPin scl, PhysicalPin sda);
80 | virtual Erc init() = 0;
81 | virtual Erc deInit() = 0;
82 | virtual Erc setClock(uint32_t) = 0;
83 | virtual Erc setSlaveAddress(uint8_t address) = 0;
84 | virtual Erc write(uint8_t* data, uint32_t size) = 0;
85 | virtual Erc write(uint8_t data) = 0;
86 | virtual Erc read(uint8_t* data, uint32_t size) = 0;
87 | };
88 |
89 | class Spi : public Driver {
90 | public:
91 | public:
92 | typedef enum {
93 | SPI_MODE_PHASE0_POL0 = 0,
94 | SPI_MODE_PHASE1_POL0 = 1,
95 | SPI_MODE_PHASE0_POL1 = 2,
96 | SPI_MODE_PHASE1_POL1 = 3
97 | } SpiMode;
98 | typedef enum {
99 | SPI_CLOCK_125K = 125000,
100 | SPI_CLOCK_250K = 250000,
101 | SPI_CLOCK_500K = 500000,
102 | SPI_CLOCK_1M = 1000000,
103 | SPI_CLOCK_2M = 2000000,
104 | SPI_CLOCK_4M = 4000000,
105 | SPI_CLOCK_8M = 8000000,
106 | SPI_CLOCK_10M = 10000000,
107 | SPI_CLOCK_20M = 20000000
108 | } SpiClock;
109 |
110 | static Spi& create(PhysicalPin miso, PhysicalPin mosi, PhysicalPin sck,
111 | PhysicalPin cs);
112 | virtual ~Spi();
113 | virtual Erc init() = 0;
114 | virtual Erc deInit() = 0;
115 | virtual Erc exchange(Bytes& in, Bytes& out) = 0;
116 | virtual Erc onExchange(FunctionPointer, void*) = 0;
117 | virtual Erc setClock(uint32_t) = 0;
118 | virtual Erc setMode(SpiMode) = 0;
119 | virtual Erc setLsbFirst(bool) = 0;
120 | virtual Erc setHwSelect(bool) = 0;
121 | };
122 |
123 | class ADC {
124 |
125 | public:
126 | static ADC& create(PhysicalPin pin);
127 |
128 | virtual Erc init() = 0;
129 | virtual int getValue() = 0;
130 | };
131 |
132 | class Connector {
133 | uint32_t _pinsUsed;
134 | uint32_t _connectorIdx;
135 | uint32_t _physicalPins[8];
136 | UART* _uart;
137 | Spi* _spi;
138 | I2C* _i2c;
139 | ADC* _adc;
140 |
141 | private:
142 | void lockPin(LogicalPin);
143 | bool isUsedPin(LogicalPin lp) { return _pinsUsed & lp; }
144 | void freePin(LogicalPin);
145 |
146 | public:
147 | uint32_t toPin(uint32_t logicalPin);
148 | static const char* uextPin(uint32_t logicalPin);
149 | Connector(uint32_t idx);
150 | UART& getUART();
151 | Spi& getSPI();
152 | I2C& getI2C();
153 | DigitalIn& getDigitalIn(LogicalPin);
154 | DigitalOut& getDigitalOut(LogicalPin);
155 | ADC& getADC(LogicalPin);
156 | uint32_t index() {return _connectorIdx;};
157 | // PWM& getPWM();
158 | };
159 |
160 | #endif
161 |
--------------------------------------------------------------------------------
/lm4f120-cm3/src/MedianFilter.h:
--------------------------------------------------------------------------------
1 | #ifndef MedianFilter_h
2 | #define MedianFilter_h
3 |
4 | template
5 | class MedianFilter
6 | {
7 | public:
8 |
9 | /* Constructor
10 | */
11 | MedianFilter()
12 | : m_idx(0), m_med(0), m_cnt(0)
13 | {
14 | }
15 |
16 | /* addSample(s): adds the sample S to the window and computes the median
17 | * if enough samples have been gathered
18 | */
19 | void addSample(T s)
20 | {
21 | m_buf[m_idx] = s;
22 | m_idx = (m_idx + 1) % S;
23 | m_cnt += (m_cnt < S) ? 1 : 0;
24 | if(m_cnt == S) {
25 | p_calcMedian();
26 | }
27 | }
28 |
29 | /* isReady(): returns true if at least the required number of samples
30 | * have been gathered, false otherwise
31 | */
32 | bool isReady()
33 | {
34 | return m_cnt == S;
35 | }
36 |
37 | /* getMedian(): returns the median computed when the last sample was
38 | * added. Does not return anything meaningful if not enough samples
39 | * have been gathered; check isReady() first.
40 | */
41 | T getMedian()
42 | {
43 | return m_med;
44 | }
45 |
46 |
47 | private:
48 |
49 | int m_idx, m_med,m_cnt;
50 | T m_buf[S], m_tmp[S];
51 |
52 | /* p_calcMedian(): helper to calculate the median. Copies
53 | * the buffer into the temp area, then calls Hoare's in-place
54 | * selection algorithm to obtain the median.
55 | */
56 | void p_calcMedian()
57 | {
58 | for(int i = 0; i < S; i++) {
59 | m_tmp[i] = m_buf[i];
60 | }
61 | m_med = p_select(0, S - 1, S / 2);
62 | }
63 |
64 | /* p_partition(l, r, p): partition function, like from quicksort.
65 | * l and r are the left and right bounds of the array (m_tmp),
66 | * respectively, and p is the pivot index.
67 | */
68 | int p_partition(int l, int r, int p)
69 | {
70 | T tmp;
71 | T pv = m_tmp[p];
72 | m_tmp[p] = m_tmp[r];
73 | m_tmp[r] = pv;
74 | int s = l;
75 | for(int i = l; i < r; i++) {
76 | if(m_tmp[i] < pv) {
77 | tmp = m_tmp[s];
78 | m_tmp[s] = m_tmp[i];
79 | m_tmp[i] = tmp;
80 | s++;
81 | }
82 | }
83 | tmp = m_tmp[s];
84 | m_tmp[s] = m_tmp[r];
85 | m_tmp[r] = tmp;
86 | return s;
87 | }
88 |
89 | /* p_select(l, r, k): Hoare's quickselect. l and r are the
90 | * array bounds, and k conveys that we want to return
91 | * the k-th value
92 | */
93 | T p_select(int l, int r, int k)
94 | {
95 | if(l == r) {
96 | return m_tmp[l];
97 | }
98 | int p = (l + r) / 2;
99 | p = p_partition(l, r, p);
100 | if(p == k) {
101 | return m_tmp[k];
102 | } else if(k < p) {
103 | return p_select(l, p - 1, k);
104 | } else {
105 | return p_select(p + 1, r, k);
106 | }
107 | }
108 |
109 | };
110 |
111 | #endif
112 |
--------------------------------------------------------------------------------
/lm4f120-cm3/src/Serial.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vortex314/mqtt2serial/c8de67dc2e9acc4176740068525c86f98ba87b2f/lm4f120-cm3/src/Serial.h
--------------------------------------------------------------------------------
/lm4f120-cm3/src/Streams.cpp:
--------------------------------------------------------------------------------
1 | #include "Streams.h"
2 | /*
3 | namespace std {
4 | void __throw_length_error(char const *) {
5 | WARN("__throw_length_error");
6 | while (1)
7 | ;
8 | }
9 | void __throw_bad_alloc() {
10 | WARN("__throw_bad_alloc");
11 | while (1)
12 | ;
13 | }
14 | void __throw_bad_function_call() {
15 | WARN("__throw_bad_function_call");
16 | while (1)
17 | ;
18 | }
19 | } // namespace std
20 | */
21 |
--------------------------------------------------------------------------------
/lm4f120-cm3/src/Streams.h:
--------------------------------------------------------------------------------
1 | #ifndef STREAMS_H
2 | #define STREAMS_H
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | //______________________________________________________________________________
11 | //
12 | template class Observer {
13 | public:
14 | virtual void onNext(T) = 0;
15 | };
16 | template class Sink : public Observer {};
17 | //______________________________________________________________________________
18 | //
19 | // DD : used vector of void pointers and not vector of pointers to template
20 | // class, to avoid explosion of vector implementations
21 | class Requestable {
22 | public:
23 | virtual void
24 | request() = 0; //{ WARN(" I am abstract Requestable. Don't call me."); };
25 | };
26 | // not sure these extra inheritance are useful
27 | template class Source : public Requestable {
28 | std::vector _observers;
29 |
30 | protected:
31 | uint32_t size() { return _observers.size(); }
32 | Observer *operator[](uint32_t idx) {
33 | return static_cast *>(_observers[idx]);
34 | }
35 |
36 | public:
37 | void subscribe(Observer &observer) {
38 | _observers.push_back((void *)&observer);
39 | }
40 |
41 | void emit(T t) {
42 | for (void *pv : _observers) {
43 | Observer *pObserver = static_cast *>(pv);
44 | pObserver->onNext(t);
45 | }
46 | }
47 | };
48 |
49 | // A flow can be both Sink and Source. Most of the time it will be in the middle
50 | // of a stream
51 | //______________________________________________________________________________________
52 | //
53 | template
54 | class Flow : public Sink, public Source {
55 | public:
56 | Flow(){};
57 | Flow(Sink &a, Source &b) : Sink(a), Source(b){};
58 | };
59 | //_________________________________________ CompositeFlow
60 | //_____________________________________________
61 | //
62 | template class CompositeFlow : public Flow {
63 | Sink &_in;
64 | Source &_out;
65 |
66 | public:
67 | CompositeFlow(Sink &a, Source &b) : _in(a), _out(b){};
68 | void request() { _out.request(); };
69 | void onNext(IN in) { _in.onNext(in); }
70 | };
71 | //______________________________________________________________________________________
72 | //
73 | template
74 | Flow &operator>>(Flow &flow1, Flow &flow2) {
75 | flow1.subscribe(flow2);
76 | return *new CompositeFlow(flow1, flow2);
77 | };
78 |
79 | template
80 | Sink &operator>>(Flow &flow, Sink &sink) {
81 | flow.subscribe(sink);
82 | return flow;
83 | };
84 |
85 | template
86 | Source &operator>>(Source &source, Flow &flow) {
87 | source.subscribe(flow);
88 | return flow;
89 | };
90 |
91 | template void operator>>(Source &source, Sink &sink) {
92 | source.subscribe(sink);
93 | };
94 |
95 | //______________________________________________________________________________
96 | //
97 | //______________________________________________________________________________
98 | //
99 |
100 | template class ValueFlow : public Flow {
101 | T _value;
102 | bool _emitOnChange = false;
103 |
104 | public:
105 | ValueFlow() {}
106 | ValueFlow(T x) { _value = x; };
107 | void request() { this->emit(_value); }
108 | void onNext(T value) {
109 | if (_emitOnChange && (_value != value)) {
110 | this->emit(value);
111 | }
112 | _value = value;
113 | }
114 | void emitOnChange(bool b) { _emitOnChange = b; };
115 | inline void operator=(T value) { onNext(value); };
116 | inline T operator()() { return _value; }
117 | };
118 | //______________________________________________________________________________
119 | //
120 | template class LambdaSink : public Sink {
121 | std::function _handler;
122 |
123 | public:
124 | LambdaSink(){};
125 | LambdaSink(std::function handler) : _handler(handler){};
126 | void handler(std::function handler) { _handler = handler; };
127 | void onNext(T event) { _handler(event); };
128 | };
129 | //______________________________________________________________________________
130 | //
131 | template class LambdaFlow : public Flow {
132 | std::function _handler;
133 |
134 | public:
135 | LambdaFlow(){};
136 | LambdaFlow(std::function handler) : _handler(handler){};
137 | void handler(std::function handler) { _handler = handler; };
138 | void onNext(IN event) { _handler(event); };
139 | };
140 | //______________________________________________________________________________
141 | //
142 | template class Filter : public Flow {
143 | T _value;
144 |
145 | public:
146 | Filter(T value) { _value = value; }
147 | void onNext(T in) {
148 | if (in == _value)
149 | this->emit(in);
150 | }
151 | };
152 |
153 | #include
154 |
155 | template class Median : public Flow {
156 | MedianFilter _mf;
157 |
158 | public:
159 | Median(){};
160 | void onNext(T value) {
161 | _mf.addSample(value);
162 | if (_mf.isReady()) {
163 | this->emit(_mf.getMedian());
164 | }
165 | };
166 | void request() { WARN(" not made for polling "); }
167 | };
168 |
169 | template class Router : public Flow {
170 | uint32_t _idx;
171 |
172 | public:
173 | void onNext(T t) {
174 | _idx++;
175 | if (_idx > this->size())
176 | _idx = 0;
177 | (*this)[_idx]->onNext(t);
178 | }
179 | };
180 | //______________________________________________________________________________
181 | //
182 | #ifdef FREERTOS
183 | #include "freertos/task.h"
184 | #include
185 | #include
186 |
187 | template class AsyncFlow : public Flow {
188 | std::deque _buffer;
189 | uint32_t _queueDepth;
190 | SemaphoreHandle_t xSemaphore = NULL;
191 |
192 | public:
193 | AsyncFlow(uint32_t size) : _queueDepth(size) {
194 | xSemaphore = xSemaphoreCreateBinary();
195 | xSemaphoreGive(xSemaphore);
196 | }
197 | void onNext(T event) {
198 | if (xSemaphoreTake(xSemaphore, (TickType_t)10) == pdTRUE) {
199 | if (_buffer.size() >= _queueDepth) {
200 | _buffer.pop_front();
201 | // WARN(" buffer overflow in
202 | // BufferedSink
203 | //");
204 | }
205 | _buffer.push_back(event);
206 | xSemaphoreGive(xSemaphore);
207 | return;
208 | } else {
209 | WARN(" timeout on async buffer ! ");
210 | }
211 | }
212 | void onNextFromIsr(T event) {
213 | BaseType_t higherPriorityTaskWoken;
214 | if (xSemaphoreTakeFromISR(xSemaphore, &higherPriorityTaskWoken) == pdTRUE) {
215 | if (_buffer.size() >= _queueDepth) {
216 | _buffer.pop_front();
217 | // WARN(" buffer overflow in
218 | // BufferedSink
219 | //");
220 | }
221 | _buffer.push_back(event);
222 | xSemaphoreGive(xSemaphore);
223 | return;
224 | } else {
225 | // WARN(" timeout on async buffer ! "); // no log from ISR
226 | }
227 | }
228 |
229 | void request() {
230 | if (xSemaphoreTake(xSemaphore, (TickType_t)10) == pdTRUE) {
231 | T t;
232 | bool hasData = false;
233 | if (_buffer.size()) {
234 | t = _buffer.front();
235 | _buffer.pop_front();
236 | hasData = true;
237 | }
238 | xSemaphoreGive(xSemaphore);
239 | if (hasData)
240 | this->emit(t);
241 | return;
242 | } else {
243 | WARN(" timeout on async buffer ! ");
244 | }
245 | }
246 | };
247 | #else
248 | #define STM32F1
249 | #include
250 |
251 | template class AsyncFlow : public Flow {
252 | std::deque _buffer;
253 | uint32_t _queueDepth;
254 | Sema& _sema;
255 |
256 | public:
257 | AsyncFlow(uint32_t size) : _queueDepth(size), _sema(Sema::create()) {}
258 | void onNext(T event) {
259 | _sema.wait();
260 | if (_buffer.size() >= _queueDepth) {
261 | _buffer.pop_front();
262 | // WARN(" buffer overflow in
263 | // BufferedSink ");
264 | }
265 | _buffer.push_back(event);
266 | _sema.release();
267 | return;
268 | }
269 | void onNextFromIsr(T event) {
270 | _sema.wait();
271 | if (_buffer.size() >= _queueDepth) {
272 | _buffer.pop_front();
273 | // WARN(" buffer overflow in
274 | // BufferedSink ");
275 | }
276 | _buffer.push_back(event);
277 | _sema.release();
278 | return;
279 | }
280 |
281 | void request() {
282 | _sema.wait();
283 | T t;
284 | bool hasData = false;
285 | if (_buffer.size()) {
286 | t = _buffer.front();
287 | _buffer.pop_front();
288 | hasData = true;
289 | }
290 | if (hasData)
291 | this->emit(t);
292 | _sema.release();
293 | }
294 | };
295 | #endif
296 |
297 | template class AsyncValueFlow : Flow {
298 | T _value;
299 |
300 | public:
301 | void onNext(T value) { _value = value; }
302 | void request() { this->emit(_value); }
303 | };
304 |
305 | class AtomicSource : public Source {
306 | std::atomic _atom;
307 |
308 | public:
309 | void inc() { _atom++; }
310 | void request() {
311 | if (_atom > 0) {
312 | emit(_atom);
313 | _atom--;
314 | }
315 | }
316 | };
317 |
318 | class TimerMsg {
319 | public:
320 | uint32_t id;
321 | };
322 |
323 | class TimerSource : public Source {
324 | uint32_t _interval;
325 | bool _repeat;
326 | uint64_t _expireTime;
327 | uint32_t _id;
328 |
329 | public:
330 | TimerSource(int id, uint32_t interval, bool repeat) {
331 | _id = id;
332 | _interval = interval;
333 | _repeat = repeat;
334 | _expireTime = Sys::millis() + _interval;
335 | }
336 | void interval(uint32_t i) { _interval = i; }
337 | void request() {
338 | if (Sys::millis() > _expireTime) {
339 | _expireTime = Sys::millis() + _interval;
340 | this->emit({_id});
341 | }
342 | }
343 | };
344 |
345 | #endif
346 |
--------------------------------------------------------------------------------
/lm4f120-cm3/src/app_main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | class UART_TIVA : public UART
16 | {
17 | FunctionPointer _onRxd;
18 | FunctionPointer _onTxd;
19 | void *_onRxdVoid = 0;
20 | void *_onTxdVoid = 0;
21 | uint32_t clock = 9600;
22 | uint32_t _pinTxd;
23 | uint32_t _pinRxd;
24 | uint32_t _baudrate;
25 | std::deque _rxdBuf;
26 | std::deque _txdBuf;
27 |
28 | uint32_t _driver;
29 | uint32_t _dataBits = 8;
30 | uart_parity _parity;
31 | uint32_t _stopBits;
32 | uint32_t _module = 0;
33 |
34 | public:
35 | static UART &create(uint32_t module) { return *new UART_TIVA(module); };
36 |
37 | UART_TIVA(uint32_t module) { _module = module; }
38 |
39 | Erc mode(const char *m)
40 | {
41 | if (m[0] == '8')
42 | _dataBits = 8;
43 | else if (m[0] == '7')
44 | _dataBits = 7;
45 | else if (m[0] == '6')
46 | _dataBits = 6;
47 | else if (m[0] == '5')
48 | _dataBits = 5;
49 | else
50 | return EINVAL;
51 | if (m[1] == 'E')
52 | _parity = UART_PARITY_EVEN;
53 | else if (m[1] == 'O')
54 | _parity = UART_PARITY_ODD;
55 | else if (m[1] == 'N')
56 | _parity = UART_PARITY_NONE;
57 | else
58 | return EINVAL;
59 | if (m[2] == '1')
60 | _stopBits = 1;
61 | else if (m[2] == '2')
62 | _stopBits = 2;
63 | else
64 | return EINVAL;
65 | return E_OK;
66 | }
67 | Erc init()
68 | {
69 | periph_clock_enable(RCC_GPIOA);
70 | /* Mux PA0 and PA1 to UART0 (alternate function 1) */
71 | gpio_set_af(GPIOA, 1, GPIO0 | GPIO1);
72 | /* Enable the UART clock */
73 | periph_clock_enable(RCC_UART0);
74 | /* We need a brief delay before we can access UART config registers */
75 | __asm__("nop");
76 | /* Disable the UART while we mess with its setings */
77 | uart_disable(UART0);
78 | /* Configure the UART clock source as precision internal oscillator */
79 | uart_clock_from_piosc(UART0);
80 | uart_set_baudrate(UART0, _baudrate);
81 | uart_set_databits(UART0, _dataBits);
82 | uart_set_parity(UART0, _parity);
83 | uart_set_stopbits(UART0, _stopBits);
84 | /* Now that we're done messing with the settings, enable the UART */
85 | uart_enable(UART0);
86 | return E_OK;
87 | }
88 | Erc deInit(){return E_OK;};
89 | Erc setClock(uint32_t clock) { _baudrate = clock; return E_OK;};
90 |
91 | Erc write(const uint8_t *data, uint32_t length)
92 | {
93 | for (uint32_t idx = 0; idx < length; idx++)
94 | write(*(data + idx));
95 | return E_OK;
96 | };
97 | Erc write(uint8_t b)
98 | {
99 | _txdBuf.push_back(b);
100 | return E_OK;
101 | };
102 | Erc read(Bytes &bytes)
103 | {
104 | while (_rxdBuf.size())
105 | {
106 | auto b = _rxdBuf.front();
107 | _rxdBuf.pop_front();
108 | bytes.write(b);
109 | }
110 | return E_OK;
111 | };
112 | uint8_t read()
113 | {
114 | auto b = _rxdBuf.front();
115 | _rxdBuf.pop_front();
116 | return b;
117 | };
118 | void onRxd(FunctionPointer fp, void *context)
119 | {
120 | _onRxd = fp;
121 | _onRxdVoid = context;
122 | };
123 | void onTxd(FunctionPointer fp, void *context)
124 | {
125 | _onTxd = fp;
126 | _onTxdVoid = context;
127 | };
128 | uint32_t hasSpace() { return 5; };
129 | uint32_t hasData() { return _rxdBuf.size(); };
130 | };
131 |
132 | class Serial : public AsyncFlow
133 | {
134 | };
135 |
136 | void app_main()
137 | {
138 | UART &uart0 = UART_TIVA::create(0);
139 | std::string hw = "Hello World";
140 | uart0.write('A');
141 | }
--------------------------------------------------------------------------------
/lm4f120-cm3/src/main.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include
10 | #include
11 |
12 | /* This is how the RGB LED is connected on the stellaris launchpad */
13 | #define RGB_PORT GPIOF
14 | enum {
15 | LED_R = GPIO1,
16 | LED_G = GPIO3,
17 | LED_B = GPIO2,
18 | };
19 |
20 | /* This is how the user switches are connected to GPIOF */
21 | enum {
22 | USR_SW1 = GPIO4,
23 | USR_SW2 = GPIO0,
24 | };
25 |
26 | /* The divisors we loop through when the user presses SW2 */
27 | enum {
28 | PLL_DIV_80MHZ = 5,
29 | PLL_DIV_57MHZ = 7,
30 | PLL_DIV_40MHZ = 10,
31 | PLL_DIV_20MHZ = 20,
32 | PLL_DIV_16MHZ = 25,
33 | };
34 |
35 | static const uint8_t plldiv[] = {
36 | PLL_DIV_80MHZ,
37 | PLL_DIV_57MHZ,
38 | PLL_DIV_40MHZ,
39 | PLL_DIV_20MHZ,
40 | PLL_DIV_16MHZ,
41 | 0
42 | };
43 | /* The PLL divisor we are currently on */
44 | static size_t ipll = 0;
45 | /* Are we bypassing the PLL, or not? */
46 | static bool bypass = false;
47 |
48 | /*
49 | * Clock setup:
50 | * Take the main crystal oscillator at 16MHz, run it through the PLL, and divide
51 | * the 400MHz PLL clock to get a system clock of 80MHz.
52 | */
53 | static void clock_setup(void)
54 | {
55 | rcc_sysclk_config(OSCSRC_MOSC, XTAL_16M, PLL_DIV_80MHZ);
56 | }
57 |
58 | /*
59 | * GPIO setup:
60 | * Enable the pins driving the RGB LED as outputs.
61 | */
62 | static void gpio_setup(void)
63 | {
64 | /*
65 | * Configure GPIOF
66 | * This port is used to control the RGB LED
67 | */
68 | periph_clock_enable(RCC_GPIOF);
69 | const uint32_t outpins = (LED_R | LED_G | LED_B);
70 |
71 | gpio_mode_setup(RGB_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, outpins);
72 | gpio_set_output_config(RGB_PORT, GPIO_OTYPE_PP, GPIO_DRIVE_2MA, outpins);
73 |
74 | /*
75 | * Now take care of our buttons
76 | */
77 | const uint32_t btnpins = USR_SW1 | USR_SW2;
78 |
79 | /*
80 | * PF0 is a locked by default. We need to unlock it before we can
81 | * re-purpose it as a GPIO pin.
82 | */
83 | gpio_unlock_commit(GPIOF, USR_SW2);
84 | /* Configure pins as inputs, with pull-up. */
85 | gpio_mode_setup(GPIOF, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, btnpins);
86 | }
87 |
88 | /*
89 | * IRQ setup:
90 | * Trigger an interrupt whenever a button is depressed.
91 | */
92 | static void irq_setup(void)
93 | {
94 | const uint32_t btnpins = USR_SW1 | USR_SW2;
95 | /* Trigger interrupt on rising-edge (when button is depressed) */
96 | gpio_configure_trigger(GPIOF, GPIO_TRIG_EDGE_RISE, btnpins);
97 | /* Finally, Enable interrupt */
98 | gpio_enable_interrupts(GPIOF, btnpins);
99 | /* Enable the interrupt in the NVIC as well */
100 | nvic_enable_irq(NVIC_GPIOF_IRQ);
101 | }
102 |
103 | #define FLASH_DELAY 800000
104 | static void delay(void)
105 | {
106 | int i;
107 | for (i = 0; i < FLASH_DELAY; i++) /* Wait a bit. */
108 | __asm__("nop");
109 | }
110 |
111 | static void uart_setup(void)
112 | {
113 | /* Enable GPIOA in run mode. */
114 | periph_clock_enable(RCC_GPIOA);
115 | /* Mux PA0 and PA1 to UART0 (alternate function 1) */
116 | gpio_set_af(GPIOA, 1, GPIO0 | GPIO1);
117 |
118 | /* Enable the UART clock */
119 | periph_clock_enable(RCC_UART0);
120 | /* We need a brief delay before we can access UART config registers */
121 | __asm__("nop");
122 | /* Disable the UART while we mess with its setings */
123 | uart_disable(UART0);
124 | /* Configure the UART clock source as precision internal oscillator */
125 | uart_clock_from_piosc(UART0);
126 | /* Set communication parameters */
127 | uart_set_baudrate(UART0, 115200);
128 | uart_set_databits(UART0, 8);
129 | uart_set_parity(UART0, UART_PARITY_NONE);
130 | uart_set_stopbits(UART0, 1);
131 | /* Now that we're done messing with the settings, enable the UART */
132 | uart_enable(UART0);
133 | }
134 |
135 | static void uart_irq_setup(void)
136 | {
137 | /* Gimme and RX interrupt */
138 | uart_enable_rx_interrupt(UART0);
139 | /* Make sure the interrupt is routed through the NVIC */
140 | nvic_enable_irq(NVIC_UART0_IRQ);
141 | }
142 |
143 | /*
144 | * uart0_isr is declared as a weak function. When we override it here, the
145 | * libopencm3 build system takes care that it becomes our UART0 ISR.
146 | */
147 | void uart0_isr(void)
148 | {
149 | uint8_t rx;
150 | uint32_t irq_clear = 0;
151 |
152 | if (uart_is_interrupt_source(UART0, UART_INT_RX)) {
153 | rx = uart_recv(UART0);
154 | uart_send(UART0, rx);
155 | irq_clear |= UART_INT_RX;
156 | }
157 |
158 | uart_clear_interrupt_flag(UART0, (uart_interrupt_flag)irq_clear);
159 | }
160 |
161 | extern void app_main();
162 |
163 | int main(void)
164 | {
165 | gpio_enable_ahb_aperture();
166 | clock_setup();
167 | gpio_setup();
168 | irq_setup();
169 | uart_setup();
170 | uart_irq_setup();
171 |
172 | for(int i=0;i<100;i++) uart_send_blocking(UART0,'H');
173 | app_main();
174 |
175 | /* Blink each color of the RGB LED in order. */
176 | while (1) {
177 | /*
178 | * Flash the Red diode
179 | */
180 | gpio_set(RGB_PORT, LED_R);
181 | delay(); /* Wait a bit. */
182 | gpio_clear(RGB_PORT, LED_R);
183 | delay(); /* Wait a bit. */
184 |
185 | /*
186 | * Flash the Green diode
187 | */
188 | gpio_set(RGB_PORT, LED_G);
189 | delay(); /* Wait a bit. */
190 | gpio_clear(RGB_PORT, LED_G);
191 | delay(); /* Wait a bit. */
192 |
193 | /*
194 | * Flash the Blue diode
195 | */
196 | gpio_set(RGB_PORT, LED_B);
197 | delay(); /* Wait a bit. */
198 | gpio_clear(RGB_PORT, LED_B);
199 | delay(); /* Wait a bit. */
200 | }
201 |
202 | return 0;
203 | }
204 |
205 | void gpiof_isr(void)
206 | {
207 | if (gpio_is_interrupt_source(GPIOF, USR_SW1)) {
208 | /* SW1 was just depressed */
209 | bypass = !bypass;
210 | if (bypass) {
211 | rcc_pll_bypass_enable();
212 | /*
213 | * The divisor is still applied to the raw clock.
214 | * Disable the divisor, or we'll divide the raw clock.
215 | */
216 | SYSCTL_RCC &= ~SYSCTL_RCC_USESYSDIV;
217 | }
218 | else
219 | {
220 | rcc_change_pll_divisor(plldiv[ipll]);
221 | }
222 | /* Clear interrupt source */
223 | gpio_clear_interrupt_flag(GPIOF, USR_SW1);
224 | }
225 |
226 | if (gpio_is_interrupt_source(GPIOF, USR_SW2)) {
227 | /* SW2 was just depressed */
228 | if (!bypass) {
229 | if (plldiv[++ipll] == 0)
230 | ipll = 0;
231 | rcc_change_pll_divisor(plldiv[ipll]);
232 | }
233 | /* Clear interrupt source */
234 | gpio_clear_interrupt_flag(GPIOF, USR_SW2);
235 | }
236 | }
--------------------------------------------------------------------------------
/lm4f120-cm3/test/README:
--------------------------------------------------------------------------------
1 |
2 | This directory is intended for PIO Unit Testing and project tests.
3 |
4 | Unit Testing is a software testing method by which individual units of
5 | source code, sets of one or more MCU program modules together with associated
6 | control data, usage procedures, and operating procedures, are tested to
7 | determine whether they are fit for use. Unit testing finds problems early
8 | in the development cycle.
9 |
10 | More information about PIO Unit Testing:
11 | - https://docs.platformio.org/page/plus/unit-testing.html
12 |
--------------------------------------------------------------------------------
/lm4f120/.gitignore:
--------------------------------------------------------------------------------
1 | .pio
2 | .vscode/.browse.c_cpp.db*
3 | .vscode/c_cpp_properties.json
4 | .vscode/launch.json
5 | .vscode/ipch
6 |
--------------------------------------------------------------------------------
/lm4f120/.travis.yml:
--------------------------------------------------------------------------------
1 | # Continuous Integration (CI) is the practice, in software
2 | # engineering, of merging all developer working copies with a shared mainline
3 | # several times a day < https://docs.platformio.org/page/ci/index.html >
4 | #
5 | # Documentation:
6 | #
7 | # * Travis CI Embedded Builds with PlatformIO
8 | # < https://docs.travis-ci.com/user/integration/platformio/ >
9 | #
10 | # * PlatformIO integration with Travis CI
11 | # < https://docs.platformio.org/page/ci/travis.html >
12 | #
13 | # * User Guide for `platformio ci` command
14 | # < https://docs.platformio.org/page/userguide/cmd_ci.html >
15 | #
16 | #
17 | # Please choose one of the following templates (proposed below) and uncomment
18 | # it (remove "# " before each line) or use own configuration according to the
19 | # Travis CI documentation (see above).
20 | #
21 |
22 |
23 | #
24 | # Template #1: General project. Test it using existing `platformio.ini`.
25 | #
26 |
27 | # language: python
28 | # python:
29 | # - "2.7"
30 | #
31 | # sudo: false
32 | # cache:
33 | # directories:
34 | # - "~/.platformio"
35 | #
36 | # install:
37 | # - pip install -U platformio
38 | # - platformio update
39 | #
40 | # script:
41 | # - platformio run
42 |
43 |
44 | #
45 | # Template #2: The project is intended to be used as a library with examples.
46 | #
47 |
48 | # language: python
49 | # python:
50 | # - "2.7"
51 | #
52 | # sudo: false
53 | # cache:
54 | # directories:
55 | # - "~/.platformio"
56 | #
57 | # env:
58 | # - PLATFORMIO_CI_SRC=path/to/test/file.c
59 | # - PLATFORMIO_CI_SRC=examples/file.ino
60 | # - PLATFORMIO_CI_SRC=path/to/test/directory
61 | #
62 | # install:
63 | # - pip install -U platformio
64 | # - platformio update
65 | #
66 | # script:
67 | # - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N
68 |
--------------------------------------------------------------------------------
/lm4f120/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // See http://go.microsoft.com/fwlink/?LinkId=827846
3 | // for the documentation about the extensions.json format
4 | "recommendations": [
5 | "platformio.platformio-ide"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/lm4f120/ACM_minicom.log:
--------------------------------------------------------------------------------
1 | Y
2 | W 001271 | /home/lieven:234 | BUSY
3 | W 001274 | /home/lieven:234 | BUSY
4 | W 001277 | /home/lieven:234 | BUSY
5 | W 001280 | /homI 020742 | src/main.cpp:176 | handled 50000 messages in 1470 msec = 34 msg/msec
6 | [1,"dst/titiva/system/loopback","true"]
7 | [0,"dst/titiva/#"]
8 | [1,"dst/titiva/system/loopback","true"]
9 | [1,"dst/titiva/system/loopback","true"]
10 | I 022228 | src/main.cpp:176 | handled 50000 messages in 1480 msec = 33 msg/msec
11 | [1,"dst/titiva/system/loopback","true"]
12 |
13 | ===== Starting build Mar 29 2020 20:30:46
14 | I 000002 | src/MqttSeri:011 | MqttSerial started.
15 | sizeof(int) : 4
16 | I 000009 | src/main.cpp:176 | handled 50000 messages in 9 msec = 5555 msg/msec
17 | I 000500 | src/main.cpp:258 | board : StellarisLaunchPad
18 | [1,"dst/titiva/system/loopback","true"]
19 | I 001300 | src/main.cpp:258 | board : StellarisLaunchPad
20 | I 001493 | src/main.cpp:176 | handled 50000 messages in 1477 msec = 33 msg/msec
21 | [1,"dst/titiva/system/loopback","true"]
22 | I 002100 | src/main.cpp:258 | board : StellarisLaunchPad
23 | I 002900 | src/main.cpp:258 | board : StellarisLaunchPad
24 | I 002978 | src/main.cpp:176 | handled 50000 messages in 1479 msec = 33 msg/msec
25 | [1,"dst/titiva/system/loopback","true"]
26 | [0,"dst/titiva/#"]
27 | [1,"dst/titiva/system/loopback","true"]
28 | [1,"dst/titiva/system/loopback","true"]
29 | I 004462 | src/main.cpp:176 | handled 50000 messages in 1479 msec = 33 msg/msec
30 |
31 | ===== Starting build Mar 29 2020 20:30:46
32 | I 000002 | src/MqttSeri:011 | MqttSerial started.
33 | sizeof(int) : 4
34 | I 000009 | src/main.cpp:176 | handled 50000 messages in 9 msec = 5555 msg/msec
35 | I 000500 | src/main.cpp:258 | board : StellarisLaunchPad
36 | [1,"dst/titiva/system/loopback","true"]
37 | I 001300 | src/main.cpp:258 | board : StellarisLaunchPad
38 | I 001493 | src/main.cpp:176 | handled 50000 messages in 1477 msec = 33 msg/msec
39 | [1,"dst/titiva/system/loopback","true"]
40 | I 002100 | src/main.cpp:258 | board : StellarisLaunchPad
41 | I 002900 | src/main.cpp:258 | board : StellarisLaunchPad
42 | I 002978 | src/main.cpp:176 | handled 50000 messages in 1479 msec = 33 msg/msec
43 | [1,"dst/titiva/system/loopback","true"]
44 | [0,"dst/titiva/#"]
45 | [1,"dst/titiva/system/loopback","true"]
46 | [1,"dst/titiva/system/loopback","true"]
47 | I 004462 | src/main.cpp:176 | handled 50000 messages in 1479 msec = 33 msg/msec
48 | [1,"dst/titiva/system/loopback","true"]
49 | I 005938 | src/main.cpp:176 | handled 50000 messages in 1470 msec = 34 msg/msec
50 | [1,"dst/titiva/system/loopback","true"]
51 | [0,"dst/titiva/#"]
52 | [1,"dst/titiva/system/loopback","true"]
53 | [1,"dst/titiva/system/loopback","true"]
54 | I 007422 | src/main.cpp:176 | handled 50000 messages in 1478 msec = 33 msg/msec
55 | [1,"dst/titiva/system/loopback","true"]
56 | I 008898 | src/main.cpp:176 | handled 50000 messages in 1470 msec = 34 msg/msec
57 | [1,"dst/titiva/system/loopback","true"]
58 | [0,"dst/titiva/#"]
59 | [1,"dst/titiva/system/loopback","true"]
60 | [1,"dst/titiva/system/loopback","true"]
61 | I 010382 | src/main.cpp:176 | handled 50000 messages in 1478 msec = 33 msg/msec
62 | [1,"dst/titiva/system/loopback","true"]
63 | I 011858 | src/main.cpp:176 | handled 50000 messages in 1470 msec = 34 msg/msec
64 | [1,"dst/titiva/system/loopback","true"]
65 | [0,"dst/titiva/#"]
66 | [1,"dst/titiva/system/loopback","true"]
67 | [1,"dst/titiva/system/loopback","true"]
68 | I 013342 | src/main.cpp:176 | handled 50000 messages in 1478 msec = 33 msg/msec
69 | [1,"dst/titiva/system/loopback","true"]
70 | I 014818 | src/main.cpp:176 | handled 50000 messages in 1470 msec = 34 msg/msec
71 | [1,"dst/titiva/system/loopback","true"]
72 | [0,"dst/titiva/#"]
73 | [1,"dst/titiva/system/loopback","true"]
74 | [1,"dst/titiva/system/loopback","true"]
75 | I 016303 | src/main.cpp:176 | handled 50000 messages in 1479 msec = 33 msg/msec
76 | [1,"dst/titiva/system/loopback","true"]
77 | I 017780 | src/main.cpp:176 | handled 50000 messages in 1471 msec = 33 msg/msec
78 | [1,"dst/titiva/system/loopback","true"]
79 | [0,"dst/titiva/#"]
80 | [1,"dst/titiva/system/loopback","true"]
81 | [1,"dst/titiva/system/loopback","true"]
82 | I 019266 | src/main.cpp:176 | handled 50000 messages in 1480 msec = 33 msg/msec
83 | [1,"dst/titiva/system/loopback","true"]
84 | I 020742 | src/main.cpp:176 | handled 50000 messages in 1470 msec = 34 msg/msec
85 | [1,"dst/titiva/system/loopback","true"]
86 | [0,"dst/titiva/#"]
87 | [1,"dst/titiva/system/loopback","true"]
88 | [1,"dst/titiva/system/loopback","true"]
89 | I 022228 | src/main.cpp:176 | handled 50000 messages in 1480 msec = 33 msg/msec
90 | [1,"dst/titiva/system/loopback","true"]
91 | I 023705 | src/main.cpp:176 | handled 50000 messages in 1471 msec = 33 msg/msec
92 | [1,"dst/titiva/system/loopback","true"]
93 | [0,"dst/titiva/#"]
94 | [1,"dst/titiva/system/loopback","true"]
95 | [1,"dst/titiva/system/loopback","true"]
96 | I 025191 | src/main.cpp:176 | handled 50000 messages in 1480 msec = 33 msg/msec
97 | [1,"dst/titiva/system/loopback","true"]
98 | I 026667 | src/main.cpp:176 | handled 50000 messages in 1470 msec = 34 msg/msec
99 | [1,"dst/titiva/system/loopback","true"]
100 | [0,"dst/titiva/#"]
101 | [1,"dst/titiva/system/loopback","true"]
102 | [1,"dst/titiva/system/loopback","true"]
103 | I 028153 | src/main.cpp:176 | handled 50000 messages in 1480 msec = 33 msg/msec
104 | [1,"dst/titiva/system/loopback","true"]
105 | I 029630 | src/main.cpp:176 | handled 50000 messages in 1471 msec = 33 msg/msec
106 | [1,"dst/titiva/system/loopback","true"]
107 | [0,"dst/titiva/#"]
108 | [1,"dst/titiva/system/loopback","true"]
109 | [1,"dst/titiva/system/loopback","true"]
110 | I 031116 | src/main.cpp:176 | handled 50000 messages in 1480 msec = 33 msg/msec
111 | [1,"dst/titiva/system/loopback","true"]
112 | I 032593 | src/main.cpp:176 | handled 50000 messages in 1471 msec = 33 msg/msec
113 | [1,"dst/titiva/system/loopback","true"]
114 | [0,"dst/titiva/#"]
115 | [1,"dst/titiva/system/loopback","true"]
116 | [1,"dst/titiva/system/loopback","true"]
117 | I 034078 | src/main.cpp:176 | handled 50000 messages in 1480 msec = 33 msg/msec
118 | [1,"dst/titiva/system/loopback","true"]
119 | I 035555 | src/main.cpp:176 | handled 50000 messages in 1471 msec = 33 msg/msec
120 | [1,"dst/titiva/system/loopback","true"]
121 | [0,"dst/titiva/#"]
122 | [1,"dst/titiva/system/loopback","true"]
123 | [1,"dst/titiva/system/loopback","true"]
124 | I 037041 | src/main.cpp:176 | handled 50000 messages in 1480 msec = 33 msg/msec
125 | [1,"dst/titiva/system/loopback","true"]
126 | I 038518 | src/main.cpp:176 | handled 50000 messages in 1471 msec = 33 msg/msec
127 | [1,"dst/titiva/system/loopback","true"]
128 | [0,"dst/titiva/#"]
129 | [1,"dst/titiva/system/loopback","true"]
130 | [1,"dst/titiva/system/loopback","true"]
131 | I 040004 | src/main.cpp:176 | handled 50000 messages in 1480 msec = 33 msg/msec
132 | [1,"dst/titiva/system/loopback","true"]
133 | I 041480 | src/main.cpp:176 | handled 50000 messages in 1471 msec = 33 msg/msec
134 | [1,"dst/titiva/system/loopback","true"]
135 | [0,"dst/titiva/#"]
136 | [1,"dst/titiva/system/loopback","true"]
137 | I 042962 | src/main.cpp:176 | handled 50000 messages in 1476 msec = 33 msg/msec
138 | [1,"dst/titiva/system/loopback","true"]
139 | [1,"dst/titiva/system/loopback","true"]
140 | I 044443 | src/main.cpp:176 | handled 50000 messages in 1475 msec = 33 msg/msec
141 | [1,"dst/titiva/system/loopback","true"]
142 | [0,"dst/titiva/#"]
143 | [1,"dst/titiva/system/loopback","true"]
144 | I 045925 | src/main.cpp:176 | handled 50000 messages in 1476 msec = 33 msg/msec
145 | [1,"dst/titiva/system/loopback","true"]
146 | [1,"dst/titiva/system/loopback","true"]
147 | I 047405 | src/main.cpp:176 | handled 50000 messages in 1474 msec = 33 msg/msec
148 | [1,"dst/titiva/system/loopback","true"]
149 | [0,"dst/titiva/#"]
150 | [1,"dst/titiva/system/loopback","true"]
151 | I 048888 | src/main.cpp:176 | handled 50000 messages in 1477 msec = 33 msg/msec
152 | [1,"dst/titiva/system/loopback","true"]
153 | [1,"dst/titiva/system/loopback","true"]
154 | I 050368 | src/main.cpp:176 | handled 50000 messages in 1475 msec = 33 msg/msec
155 | [1,"dst/titiva/system/loopback","true"]
156 | [0,"dst/titiva/#"]
157 | [1,"dst/titiva/system/loopback","true"]
158 | I 051850 | src/main.cpp:176 | handled 50000 messages in 1476 msec = 33 msg/msec
159 | [1,"dst/titiva/system/loopback","true"]
160 | [1,"dst/titiva/system/loopback","true"]
161 | I 053330 | src/main.cpp:176 | handled 50000 messages in 1474 msec = 33 msg/msec
162 | [1,"dst/titiva/system/loopback","true"]
163 | [0,"dst/titiva/#"]
164 | [1,"dst/titiva/system/loopback","true"]
165 | I 054813 | src/main.cpp:176 | handled 50000 messages in 1477 msec = 33 msg/msec
166 | [1,"dst/titiva/system/loopback","true"]
167 | [1,"dst/titiva/system/loopback","true"]
168 | I 056293 | src/main.cpp:176 | handled 50000 messages in 1474 msec = 33 msg/msec
169 | [1,"dst/titiva/system/loopback","true"]
170 | [0,"dst/titiva/#"]
171 | [1,"dst/titiva/system/loopback","true"]
172 | I 057775 | src/main.cpp:176 | handled 50000 messages in 1476 msec = 33 msg/msec
173 | [1,"dst/titiva/system/loopback","true"]
174 | [1,"dst/titiva/system/loopback","true"]
175 | I 059256 | src/main.cpp:176 | handled 50000 messages in 1475 msec = 33 msg/msec
176 | [1,"dst/titiva/system/loopback","true"]
177 | [0,"dst/titiva/#"]
178 | [1,"dst/titiva/system/loopback","true"]
179 | I 060738 | src/main.cpp:176 | handled 50000 messages in 1477 msec = 33 msg/msec
180 | [1,"dst/titiva/system/loopback","true"]
181 | [1,"dst/titiva/system/loopback","true"]
182 | I 062218 | src/main.cpp:176 | handled 50000 messages in 1474 msec = 33 msg/msec
183 | [1,"dst/titiva/system/loopback","true"]
184 | [0,"dst/titiva/#"]
185 | [1,"dst/titiva/system/loopback","true"]
186 | I 063700 | src/main.cpp:176 | handled 50000 messages in 1476 msec = 33 msg/msec
187 | [1,"dst/titiva/system/loopback","true"]
188 | [1,"dst/titiva/system/loopback","true"]
189 |
--------------------------------------------------------------------------------
/lm4f120/README.MD:
--------------------------------------------------------------------------------
1 | # LM4F120
2 | needed some tweeking in include files for sleep() function
3 | not stdc++11
4 | needed to include printf.h
5 | # Recommended
6 | curl -fsSL https://raw.githubusercontent.com/platformio/platformio-core/master/scripts/99-platformio-udev.rules | sudo tee /etc/udev/rules.d/99-platformio-udev.rules
7 |
8 | # OR, manually download and copy this file to destination folder
9 | sudo cp 99-platformio-udev.rules /etc/udev/rules.d/99-platformio-udev.rules
10 | sudo service udev restart
11 |
12 | https://docs.platformio.org/en/latest/faq.html#platformio-udev-rules
--------------------------------------------------------------------------------
/lm4f120/include/README:
--------------------------------------------------------------------------------
1 |
2 | This directory is intended for project header files.
3 |
4 | A header file is a file containing C declarations and macro definitions
5 | to be shared between several project source files. You request the use of a
6 | header file in your project source file (C, C++, etc) located in `src` folder
7 | by including it, with the C preprocessing directive `#include'.
8 |
9 | ```src/main.c
10 |
11 | #include "header.h"
12 |
13 | int main (void)
14 | {
15 | ...
16 | }
17 | ```
18 |
19 | Including a header file produces the same results as copying the header file
20 | into each source file that needs it. Such copying would be time-consuming
21 | and error-prone. With a header file, the related declarations appear
22 | in only one place. If they need to be changed, they can be changed in one
23 | place, and programs that include the header file will automatically use the
24 | new version when next recompiled. The header file eliminates the labor of
25 | finding and changing all the copies as well as the risk that a failure to
26 | find one copy will result in inconsistencies within a program.
27 |
28 | In C, the usual convention is to give header files names that end with `.h'.
29 | It is most portable to use only letters, digits, dashes, and underscores in
30 | header file names, and at most one dot.
31 |
32 | Read more about using header files in official GCC documentation:
33 |
34 | * Include Syntax
35 | * Include Operation
36 | * Once-Only Headers
37 | * Computed Includes
38 |
39 | https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
40 |
--------------------------------------------------------------------------------
/lm4f120/lib/README:
--------------------------------------------------------------------------------
1 |
2 | This directory is intended for project specific (private) libraries.
3 | PlatformIO will compile them to static libraries and link into executable file.
4 |
5 | The source code of each library should be placed in a an own separate directory
6 | ("lib/your_library_name/[here are source files]").
7 |
8 | For example, see a structure of the following two libraries `Foo` and `Bar`:
9 |
10 | |--lib
11 | | |
12 | | |--Bar
13 | | | |--docs
14 | | | |--examples
15 | | | |--src
16 | | | |- Bar.c
17 | | | |- Bar.h
18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
19 | | |
20 | | |--Foo
21 | | | |- Foo.c
22 | | | |- Foo.h
23 | | |
24 | | |- README --> THIS FILE
25 | |
26 | |- platformio.ini
27 | |--src
28 | |- main.c
29 |
30 | and a contents of `src/main.c`:
31 | ```
32 | #include
33 | #include
34 |
35 | int main (void)
36 | {
37 | ...
38 | }
39 |
40 | ```
41 |
42 | PlatformIO Library Dependency Finder will find automatically dependent
43 | libraries scanning project source files.
44 |
45 | More information about PlatformIO Library Dependency Finder
46 | - https://docs.platformio.org/page/librarymanager/ldf.html
47 |
--------------------------------------------------------------------------------
/lm4f120/platformio.ini:
--------------------------------------------------------------------------------
1 | ;PlatformIO Project Configuration File
2 | ;
3 | ; Build options: build flags, source filter
4 | ; Upload options: custom upload port, speed and extra flags
5 | ; Library options: dependencies, extra library storages
6 | ; Advanced options: extra scripting
7 | ;
8 | ; Please visit documentation for the other options and examples
9 | ; https://docs.platformio.org/page/projectconf.html
10 |
11 | [env:lplm4f120h5qr]
12 | platform = titiva
13 | board = lplm4f120h5qr
14 | framework = arduino
15 | build_flags=
16 | -DCPU=lm4f120h5qr
17 | -DBOARD=StellarisLaunchPad
18 | -DPLATFORM=$PIOPLATFORM
19 | -I../common
20 | -I../../limero/inc
21 | -I../../limero/arduino
22 | -I../../ArduinoJson/src
23 | -llibstdc++
24 | -fno-rtti -fno-exceptions
25 | -Wl,--gc-sections
26 | -Os
27 | -DHOSTNAME=lm4f120
28 | monitor_port = /dev/ttyACM0
29 | monitor_speed = 115200
30 | upload_port = /dev/ttyACM0
31 |
32 |
--------------------------------------------------------------------------------
/lm4f120/src/arduino:
--------------------------------------------------------------------------------
1 | ../../../limero/arduino/
--------------------------------------------------------------------------------
/lm4f120/src/common:
--------------------------------------------------------------------------------
1 | ../../common
--------------------------------------------------------------------------------
/lm4f120/src/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include
6 | #define PIN_LED PF_3
7 | #define PIN_BUTTON PF_4
8 | #include
9 | #include
10 |
11 | extern "C" void _exit() {}
12 |
13 | Thread mainThread("main");
14 | LedBlinker ledBlinkerBlue(mainThread, PIN_LED, 100);
15 | Button button1(mainThread, PIN_BUTTON);
16 | Poller poller(mainThread);
17 | MqttSerial mqtt(mainThread, Serial);
18 | Log logger(1024);
19 |
20 | LambdaSource systemUptime([]() { return Sys::millis(); });
21 | LambdaSource systemHostname([]() { return Sys::hostname(); });
22 | LambdaSource systemBoard([]() { return Sys::board(); });
23 | LambdaSource systemCpu([]() { return Sys::cpu(); });
24 | ValueSource systemBuild = __DATE__ " " __TIME__;
25 |
26 | void serialEvent()
27 | {
28 | INFO("-");
29 | MqttSerial::onRxd(&mqtt);
30 | }
31 |
32 | void setup()
33 | {
34 | Serial.begin(115200);
35 | Serial.println("\r\n===== Starting build " __DATE__ " " __TIME__);
36 |
37 | Sys::hostname(S(HOSTNAME));
38 |
39 | button1.init();
40 | ledBlinkerBlue.init();
41 | mqtt.init();
42 |
43 | mqtt.connected >> ledBlinkerBlue.blinkSlow;
44 | mqtt.connected >> poller.connected;
45 | mqtt.connected >> mqtt.toTopic("mqtt/connected");
46 |
47 | poller >> systemUptime >> mqtt.toTopic("system/upTime");
48 | poller >> systemBuild >> mqtt.toTopic("system/build");
49 | poller >> systemHostname >> mqtt.toTopic("system/hostname");
50 | poller >> systemBoard >> mqtt.toTopic("system/board");
51 | poller >> systemCpu >> mqtt.toTopic("system/cpu");
52 | poller >> button1 >> mqtt.toTopic("button/button1");
53 | }
54 |
55 | void loop()
56 | {
57 | mainThread.loop();
58 | if (Serial.available())
59 | {
60 | MqttSerial::onRxd(&mqtt);
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/lm4f120/src/printf.c:
--------------------------------------------------------------------------------
1 | ///////////////////////////////////////////////////////////////////////////////
2 | // \author (c) Marco Paland (info@paland.com)
3 | // 2014-2019, PALANDesign Hannover, Germany
4 | //
5 | // \license The MIT License (MIT)
6 | //
7 | // Permission is hereby granted, free of charge, to any person obtaining a copy
8 | // of this software and associated documentation files (the "Software"), to deal
9 | // in the Software without restriction, including without limitation the rights
10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the Software is
12 | // furnished to do so, subject to the following conditions:
13 | //
14 | // The above copyright notice and this permission notice shall be included in
15 | // all copies or substantial portions of the Software.
16 | //
17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | // THE SOFTWARE.
24 | //
25 | // \brief Tiny printf, sprintf and (v)snprintf implementation, optimized for speed on
26 | // embedded systems with a very limited resources. These routines are thread
27 | // safe and reentrant!
28 | // Use this instead of the bloated standard/newlib printf cause these use
29 | // malloc for printf (and may not be thread safe).
30 | //
31 | ///////////////////////////////////////////////////////////////////////////////
32 |
33 | #include
34 | #include
35 |
36 | #include "printf.h"
37 |
38 |
39 | // define this globally (e.g. gcc -DPRINTF_INCLUDE_CONFIG_H ...) to include the
40 | // printf_config.h header file
41 | // default: undefined
42 | #ifdef PRINTF_INCLUDE_CONFIG_H
43 | #include "printf_config.h"
44 | #endif
45 |
46 |
47 | // 'ntoa' conversion buffer size, this must be big enough to hold one converted
48 | // numeric number including padded zeros (dynamically created on stack)
49 | // default: 32 byte
50 | #ifndef PRINTF_NTOA_BUFFER_SIZE
51 | #define PRINTF_NTOA_BUFFER_SIZE 32U
52 | #endif
53 |
54 | // 'ftoa' conversion buffer size, this must be big enough to hold one converted
55 | // float number including padded zeros (dynamically created on stack)
56 | // default: 32 byte
57 | #ifndef PRINTF_FTOA_BUFFER_SIZE
58 | #define PRINTF_FTOA_BUFFER_SIZE 32U
59 | #endif
60 |
61 | // support for the floating point type (%f)
62 | // default: activated
63 | #ifndef PRINTF_DISABLE_SUPPORT_FLOAT
64 | #define PRINTF_SUPPORT_FLOAT
65 | #endif
66 |
67 | // support for exponential floating point notation (%e/%g)
68 | // default: activated
69 | #ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL
70 | #define PRINTF_SUPPORT_EXPONENTIAL
71 | #endif
72 |
73 | // define the default floating point precision
74 | // default: 6 digits
75 | #ifndef PRINTF_DEFAULT_FLOAT_PRECISION
76 | #define PRINTF_DEFAULT_FLOAT_PRECISION 6U
77 | #endif
78 |
79 | // define the largest float suitable to print with %f
80 | // default: 1e9
81 | #ifndef PRINTF_MAX_FLOAT
82 | #define PRINTF_MAX_FLOAT 1e9
83 | #endif
84 |
85 | // support for the long long types (%llu or %p)
86 | // default: activated
87 | #ifndef PRINTF_DISABLE_SUPPORT_LONG_LONG
88 | #define PRINTF_SUPPORT_LONG_LONG
89 | #endif
90 |
91 | // support for the ptrdiff_t type (%t)
92 | // ptrdiff_t is normally defined in as long or long long type
93 | // default: activated
94 | #ifndef PRINTF_DISABLE_SUPPORT_PTRDIFF_T
95 | #define PRINTF_SUPPORT_PTRDIFF_T
96 | #endif
97 |
98 | ///////////////////////////////////////////////////////////////////////////////
99 |
100 | // internal flag definitions
101 | #define FLAGS_ZEROPAD (1U << 0U)
102 | #define FLAGS_LEFT (1U << 1U)
103 | #define FLAGS_PLUS (1U << 2U)
104 | #define FLAGS_SPACE (1U << 3U)
105 | #define FLAGS_HASH (1U << 4U)
106 | #define FLAGS_UPPERCASE (1U << 5U)
107 | #define FLAGS_CHAR (1U << 6U)
108 | #define FLAGS_SHORT (1U << 7U)
109 | #define FLAGS_LONG (1U << 8U)
110 | #define FLAGS_LONG_LONG (1U << 9U)
111 | #define FLAGS_PRECISION (1U << 10U)
112 | #define FLAGS_ADAPT_EXP (1U << 11U)
113 |
114 |
115 | // import float.h for DBL_MAX
116 | #if defined(PRINTF_SUPPORT_FLOAT)
117 | #include
118 | #endif
119 |
120 |
121 | // output function type
122 | typedef void (*out_fct_type)(char character, void* buffer, size_t idx, size_t maxlen);
123 |
124 |
125 | // wrapper (used as buffer) for output function type
126 | typedef struct {
127 | void (*fct)(char character, void* arg);
128 | void* arg;
129 | } out_fct_wrap_type;
130 |
131 |
132 | // internal buffer output
133 | static inline void _out_buffer(char character, void* buffer, size_t idx, size_t maxlen)
134 | {
135 | if (idx < maxlen) {
136 | ((char*)buffer)[idx] = character;
137 | }
138 | }
139 |
140 |
141 | // internal null output
142 | static inline void _out_null(char character, void* buffer, size_t idx, size_t maxlen)
143 | {
144 | (void)character; (void)buffer; (void)idx; (void)maxlen;
145 | }
146 |
147 |
148 | // internal _putchar wrapper
149 | static inline void _out_char(char character, void* buffer, size_t idx, size_t maxlen)
150 | {
151 | (void)buffer; (void)idx; (void)maxlen;
152 | if (character) {
153 | _putchar(character);
154 | }
155 | }
156 |
157 |
158 | // internal output function wrapper
159 | static inline void _out_fct(char character, void* buffer, size_t idx, size_t maxlen)
160 | {
161 | (void)idx; (void)maxlen;
162 | if (character) {
163 | // buffer is the output fct pointer
164 | ((out_fct_wrap_type*)buffer)->fct(character, ((out_fct_wrap_type*)buffer)->arg);
165 | }
166 | }
167 |
168 |
169 | // internal secure strlen
170 | // \return The length of the string (excluding the terminating 0) limited by 'maxsize'
171 | static inline unsigned int _strnlen_s(const char* str, size_t maxsize)
172 | {
173 | const char* s;
174 | for (s = str; *s && maxsize--; ++s);
175 | return (unsigned int)(s - str);
176 | }
177 |
178 |
179 | // internal test if char is a digit (0-9)
180 | // \return true if char is a digit
181 | static inline bool _is_digit(char ch)
182 | {
183 | return (ch >= '0') && (ch <= '9');
184 | }
185 |
186 |
187 | // internal ASCII string to unsigned int conversion
188 | static unsigned int _atoi(const char** str)
189 | {
190 | unsigned int i = 0U;
191 | while (_is_digit(**str)) {
192 | i = i * 10U + (unsigned int)(*((*str)++) - '0');
193 | }
194 | return i;
195 | }
196 |
197 |
198 | // output the specified string in reverse, taking care of any zero-padding
199 | static size_t _out_rev(out_fct_type out, char* buffer, size_t idx, size_t maxlen, const char* buf, size_t len, unsigned int width, unsigned int flags)
200 | {
201 | const size_t start_idx = idx;
202 |
203 | // pad spaces up to given width
204 | if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) {
205 | for (size_t i = len; i < width; i++) {
206 | out(' ', buffer, idx++, maxlen);
207 | }
208 | }
209 |
210 | // reverse string
211 | while (len) {
212 | out(buf[--len], buffer, idx++, maxlen);
213 | }
214 |
215 | // append pad spaces up to given width
216 | if (flags & FLAGS_LEFT) {
217 | while (idx - start_idx < width) {
218 | out(' ', buffer, idx++, maxlen);
219 | }
220 | }
221 |
222 | return idx;
223 | }
224 |
225 |
226 | // internal itoa format
227 | static size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen, char* buf, size_t len, bool negative, unsigned int base, unsigned int prec, unsigned int width, unsigned int flags)
228 | {
229 | // pad leading zeros
230 | if (!(flags & FLAGS_LEFT)) {
231 | if (width && (flags & FLAGS_ZEROPAD) && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
232 | width--;
233 | }
234 | while ((len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
235 | buf[len++] = '0';
236 | }
237 | while ((flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
238 | buf[len++] = '0';
239 | }
240 | }
241 |
242 | // handle hash
243 | if (flags & FLAGS_HASH) {
244 | if (!(flags & FLAGS_PRECISION) && len && ((len == prec) || (len == width))) {
245 | len--;
246 | if (len && (base == 16U)) {
247 | len--;
248 | }
249 | }
250 | if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
251 | buf[len++] = 'x';
252 | }
253 | else if ((base == 16U) && (flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
254 | buf[len++] = 'X';
255 | }
256 | else if ((base == 2U) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
257 | buf[len++] = 'b';
258 | }
259 | if (len < PRINTF_NTOA_BUFFER_SIZE) {
260 | buf[len++] = '0';
261 | }
262 | }
263 |
264 | if (len < PRINTF_NTOA_BUFFER_SIZE) {
265 | if (negative) {
266 | buf[len++] = '-';
267 | }
268 | else if (flags & FLAGS_PLUS) {
269 | buf[len++] = '+'; // ignore the space if the '+' exists
270 | }
271 | else if (flags & FLAGS_SPACE) {
272 | buf[len++] = ' ';
273 | }
274 | }
275 |
276 | return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags);
277 | }
278 |
279 |
280 | // internal itoa for 'long' type
281 | static size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, unsigned long base, unsigned int prec, unsigned int width, unsigned int flags)
282 | {
283 | char buf[PRINTF_NTOA_BUFFER_SIZE];
284 | size_t len = 0U;
285 |
286 | // no hash for 0 values
287 | if (!value) {
288 | flags &= ~FLAGS_HASH;
289 | }
290 |
291 | // write if precision != 0 and value is != 0
292 | if (!(flags & FLAGS_PRECISION) || value) {
293 | do {
294 | const char digit = (char)(value % base);
295 | buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
296 | value /= base;
297 | } while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
298 | }
299 |
300 | return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags);
301 | }
302 |
303 |
304 | // internal itoa for 'long long' type
305 | #if defined(PRINTF_SUPPORT_LONG_LONG)
306 | static size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long long value, bool negative, unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags)
307 | {
308 | char buf[PRINTF_NTOA_BUFFER_SIZE];
309 | size_t len = 0U;
310 |
311 | // no hash for 0 values
312 | if (!value) {
313 | flags &= ~FLAGS_HASH;
314 | }
315 |
316 | // write if precision != 0 and value is != 0
317 | if (!(flags & FLAGS_PRECISION) || value) {
318 | do {
319 | const char digit = (char)(value % base);
320 | buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
321 | value /= base;
322 | } while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
323 | }
324 |
325 | return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags);
326 | }
327 | #endif // PRINTF_SUPPORT_LONG_LONG
328 |
329 |
330 | #if defined(PRINTF_SUPPORT_FLOAT)
331 |
332 | #if defined(PRINTF_SUPPORT_EXPONENTIAL)
333 | // forward declaration so that _ftoa can switch to exp notation for values > PRINTF_MAX_FLOAT
334 | static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags);
335 | #endif
336 |
337 |
338 | // internal ftoa for fixed decimal floating point
339 | static size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags)
340 | {
341 | char buf[PRINTF_FTOA_BUFFER_SIZE];
342 | size_t len = 0U;
343 | double diff = 0.0;
344 |
345 | // powers of 10
346 | static const double pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
347 |
348 | // test for special values
349 | if (value != value)
350 | return _out_rev(out, buffer, idx, maxlen, "nan", 3, width, flags);
351 | if (value < -DBL_MAX)
352 | return _out_rev(out, buffer, idx, maxlen, "fni-", 4, width, flags);
353 | if (value > DBL_MAX)
354 | return _out_rev(out, buffer, idx, maxlen, (flags & FLAGS_PLUS) ? "fni+" : "fni", (flags & FLAGS_PLUS) ? 4U : 3U, width, flags);
355 |
356 | // test for very large values
357 | // standard printf behavior is to print EVERY whole number digit -- which could be 100s of characters overflowing your buffers == bad
358 | if ((value > PRINTF_MAX_FLOAT) || (value < -PRINTF_MAX_FLOAT)) {
359 | #if defined(PRINTF_SUPPORT_EXPONENTIAL)
360 | return _etoa(out, buffer, idx, maxlen, value, prec, width, flags);
361 | #else
362 | return 0U;
363 | #endif
364 | }
365 |
366 | // test for negative
367 | bool negative = false;
368 | if (value < 0) {
369 | negative = true;
370 | value = 0 - value;
371 | }
372 |
373 | // set default precision, if not set explicitly
374 | if (!(flags & FLAGS_PRECISION)) {
375 | prec = PRINTF_DEFAULT_FLOAT_PRECISION;
376 | }
377 | // limit precision to 9, cause a prec >= 10 can lead to overflow errors
378 | while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) {
379 | buf[len++] = '0';
380 | prec--;
381 | }
382 |
383 | int whole = (int)value;
384 | double tmp = (value - whole) * pow10[prec];
385 | unsigned long frac = (unsigned long)tmp;
386 | diff = tmp - frac;
387 |
388 | if (diff > 0.5) {
389 | ++frac;
390 | // handle rollover, e.g. case 0.99 with prec 1 is 1.0
391 | if (frac >= pow10[prec]) {
392 | frac = 0;
393 | ++whole;
394 | }
395 | }
396 | else if (diff < 0.5) {
397 | }
398 | else if ((frac == 0U) || (frac & 1U)) {
399 | // if halfway, round up if odd OR if last digit is 0
400 | ++frac;
401 | }
402 |
403 | if (prec == 0U) {
404 | diff = value - (double)whole;
405 | if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) {
406 | // exactly 0.5 and ODD, then round up
407 | // 1.5 -> 2, but 2.5 -> 2
408 | ++whole;
409 | }
410 | }
411 | else {
412 | unsigned int count = prec;
413 | // now do fractional part, as an unsigned number
414 | while (len < PRINTF_FTOA_BUFFER_SIZE) {
415 | --count;
416 | buf[len++] = (char)(48U + (frac % 10U));
417 | if (!(frac /= 10U)) {
418 | break;
419 | }
420 | }
421 | // add extra 0s
422 | while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) {
423 | buf[len++] = '0';
424 | }
425 | if (len < PRINTF_FTOA_BUFFER_SIZE) {
426 | // add decimal
427 | buf[len++] = '.';
428 | }
429 | }
430 |
431 | // do whole part, number is reversed
432 | while (len < PRINTF_FTOA_BUFFER_SIZE) {
433 | buf[len++] = (char)(48 + (whole % 10));
434 | if (!(whole /= 10)) {
435 | break;
436 | }
437 | }
438 |
439 | // pad leading zeros
440 | if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) {
441 | if (width && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
442 | width--;
443 | }
444 | while ((len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) {
445 | buf[len++] = '0';
446 | }
447 | }
448 |
449 | if (len < PRINTF_FTOA_BUFFER_SIZE) {
450 | if (negative) {
451 | buf[len++] = '-';
452 | }
453 | else if (flags & FLAGS_PLUS) {
454 | buf[len++] = '+'; // ignore the space if the '+' exists
455 | }
456 | else if (flags & FLAGS_SPACE) {
457 | buf[len++] = ' ';
458 | }
459 | }
460 |
461 | return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags);
462 | }
463 |
464 |
465 | #if defined(PRINTF_SUPPORT_EXPONENTIAL)
466 | // internal ftoa variant for exponential floating-point type, contributed by Martijn Jasperse
467 | static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags)
468 | {
469 | // check for NaN and special values
470 | if ((value != value) || (value > DBL_MAX) || (value < -DBL_MAX)) {
471 | return _ftoa(out, buffer, idx, maxlen, value, prec, width, flags);
472 | }
473 |
474 | // determine the sign
475 | const bool negative = value < 0;
476 | if (negative) {
477 | value = -value;
478 | }
479 |
480 | // default precision
481 | if (!(flags & FLAGS_PRECISION)) {
482 | prec = PRINTF_DEFAULT_FLOAT_PRECISION;
483 | }
484 |
485 | // determine the decimal exponent
486 | // based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c)
487 | union {
488 | uint64_t U;
489 | double F;
490 | } conv;
491 |
492 | conv.F = value;
493 | int exp2 = (int)((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2
494 | conv.U = (conv.U & ((1ULL << 52U) - 1U)) | (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2)
495 | // now approximate log10 from the log2 integer part and an expansion of ln around 1.5
496 | int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168);
497 | // now we want to compute 10^expval but we want to be sure it won't overflow
498 | exp2 = (int)(expval * 3.321928094887362 + 0.5);
499 | const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453;
500 | const double z2 = z * z;
501 | conv.U = (uint64_t)(exp2 + 1023) << 52U;
502 | // compute exp(z) using continued fractions, see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex
503 | conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14)))));
504 | // correct for rounding errors
505 | if (value < conv.F) {
506 | expval--;
507 | conv.F /= 10;
508 | }
509 |
510 | // the exponent format is "%+03d" and largest value is "307", so set aside 4-5 characters
511 | unsigned int minwidth = ((expval < 100) && (expval > -100)) ? 4U : 5U;
512 |
513 | // in "%g" mode, "prec" is the number of *significant figures* not decimals
514 | if (flags & FLAGS_ADAPT_EXP) {
515 | // do we want to fall-back to "%f" mode?
516 | if ((value >= 1e-4) && (value < 1e6)) {
517 | if ((int)prec > expval) {
518 | prec = (unsigned)((int)prec - expval - 1);
519 | }
520 | else {
521 | prec = 0;
522 | }
523 | flags |= FLAGS_PRECISION; // make sure _ftoa respects precision
524 | // no characters in exponent
525 | minwidth = 0U;
526 | expval = 0;
527 | }
528 | else {
529 | // we use one sigfig for the whole part
530 | if ((prec > 0) && (flags & FLAGS_PRECISION)) {
531 | --prec;
532 | }
533 | }
534 | }
535 |
536 | // will everything fit?
537 | unsigned int fwidth = width;
538 | if (width > minwidth) {
539 | // we didn't fall-back so subtract the characters required for the exponent
540 | fwidth -= minwidth;
541 | } else {
542 | // not enough characters, so go back to default sizing
543 | fwidth = 0U;
544 | }
545 | if ((flags & FLAGS_LEFT) && minwidth) {
546 | // if we're padding on the right, DON'T pad the floating part
547 | fwidth = 0U;
548 | }
549 |
550 | // rescale the float value
551 | if (expval) {
552 | value /= conv.F;
553 | }
554 |
555 | // output the floating part
556 | const size_t start_idx = idx;
557 | idx = _ftoa(out, buffer, idx, maxlen, negative ? -value : value, prec, fwidth, flags & ~FLAGS_ADAPT_EXP);
558 |
559 | // output the exponent part
560 | if (minwidth) {
561 | // output the exponential symbol
562 | out((flags & FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen);
563 | // output the exponent value
564 | idx = _ntoa_long(out, buffer, idx, maxlen, (expval < 0) ? -expval : expval, expval < 0, 10, 0, minwidth-1, FLAGS_ZEROPAD | FLAGS_PLUS);
565 | // might need to right-pad spaces
566 | if (flags & FLAGS_LEFT) {
567 | while (idx - start_idx < width) out(' ', buffer, idx++, maxlen);
568 | }
569 | }
570 | return idx;
571 | }
572 | #endif // PRINTF_SUPPORT_EXPONENTIAL
573 | #endif // PRINTF_SUPPORT_FLOAT
574 |
575 |
576 | // internal vsnprintf
577 | static int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, va_list va)
578 | {
579 | unsigned int flags, width, precision, n;
580 | size_t idx = 0U;
581 |
582 | if (!buffer) {
583 | // use null output function
584 | out = _out_null;
585 | }
586 |
587 | while (*format)
588 | {
589 | // format specifier? %[flags][width][.precision][length]
590 | if (*format != '%') {
591 | // no
592 | out(*format, buffer, idx++, maxlen);
593 | format++;
594 | continue;
595 | }
596 | else {
597 | // yes, evaluate it
598 | format++;
599 | }
600 |
601 | // evaluate flags
602 | flags = 0U;
603 | do {
604 | switch (*format) {
605 | case '0': flags |= FLAGS_ZEROPAD; format++; n = 1U; break;
606 | case '-': flags |= FLAGS_LEFT; format++; n = 1U; break;
607 | case '+': flags |= FLAGS_PLUS; format++; n = 1U; break;
608 | case ' ': flags |= FLAGS_SPACE; format++; n = 1U; break;
609 | case '#': flags |= FLAGS_HASH; format++; n = 1U; break;
610 | default : n = 0U; break;
611 | }
612 | } while (n);
613 |
614 | // evaluate width field
615 | width = 0U;
616 | if (_is_digit(*format)) {
617 | width = _atoi(&format);
618 | }
619 | else if (*format == '*') {
620 | const int w = va_arg(va, int);
621 | if (w < 0) {
622 | flags |= FLAGS_LEFT; // reverse padding
623 | width = (unsigned int)-w;
624 | }
625 | else {
626 | width = (unsigned int)w;
627 | }
628 | format++;
629 | }
630 |
631 | // evaluate precision field
632 | precision = 0U;
633 | if (*format == '.') {
634 | flags |= FLAGS_PRECISION;
635 | format++;
636 | if (_is_digit(*format)) {
637 | precision = _atoi(&format);
638 | }
639 | else if (*format == '*') {
640 | const int prec = (int)va_arg(va, int);
641 | precision = prec > 0 ? (unsigned int)prec : 0U;
642 | format++;
643 | }
644 | }
645 |
646 | // evaluate length field
647 | switch (*format) {
648 | case 'l' :
649 | flags |= FLAGS_LONG;
650 | format++;
651 | if (*format == 'l') {
652 | flags |= FLAGS_LONG_LONG;
653 | format++;
654 | }
655 | break;
656 | case 'h' :
657 | flags |= FLAGS_SHORT;
658 | format++;
659 | if (*format == 'h') {
660 | flags |= FLAGS_CHAR;
661 | format++;
662 | }
663 | break;
664 | #if defined(PRINTF_SUPPORT_PTRDIFF_T)
665 | case 't' :
666 | flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
667 | format++;
668 | break;
669 | #endif
670 | case 'j' :
671 | flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
672 | format++;
673 | break;
674 | case 'z' :
675 | flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
676 | format++;
677 | break;
678 | default :
679 | break;
680 | }
681 |
682 | // evaluate specifier
683 | switch (*format) {
684 | case 'd' :
685 | case 'i' :
686 | case 'u' :
687 | case 'x' :
688 | case 'X' :
689 | case 'o' :
690 | case 'b' : {
691 | // set the base
692 | unsigned int base;
693 | if (*format == 'x' || *format == 'X') {
694 | base = 16U;
695 | }
696 | else if (*format == 'o') {
697 | base = 8U;
698 | }
699 | else if (*format == 'b') {
700 | base = 2U;
701 | }
702 | else {
703 | base = 10U;
704 | flags &= ~FLAGS_HASH; // no hash for dec format
705 | }
706 | // uppercase
707 | if (*format == 'X') {
708 | flags |= FLAGS_UPPERCASE;
709 | }
710 |
711 | // no plus or space flag for u, x, X, o, b
712 | if ((*format != 'i') && (*format != 'd')) {
713 | flags &= ~(FLAGS_PLUS | FLAGS_SPACE);
714 | }
715 |
716 | // ignore '0' flag when precision is given
717 | if (flags & FLAGS_PRECISION) {
718 | flags &= ~FLAGS_ZEROPAD;
719 | }
720 |
721 | // convert the integer
722 | if ((*format == 'i') || (*format == 'd')) {
723 | // signed
724 | if (flags & FLAGS_LONG_LONG) {
725 | #if defined(PRINTF_SUPPORT_LONG_LONG)
726 | const long long value = va_arg(va, long long);
727 | idx = _ntoa_long_long(out, buffer, idx, maxlen, (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
728 | #endif
729 | }
730 | else if (flags & FLAGS_LONG) {
731 | const long value = va_arg(va, long);
732 | idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
733 | }
734 | else {
735 | const int value = (flags & FLAGS_CHAR) ? (char)va_arg(va, int) : (flags & FLAGS_SHORT) ? (short int)va_arg(va, int) : va_arg(va, int);
736 | idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
737 | }
738 | }
739 | else {
740 | // unsigned
741 | if (flags & FLAGS_LONG_LONG) {
742 | #if defined(PRINTF_SUPPORT_LONG_LONG)
743 | idx = _ntoa_long_long(out, buffer, idx, maxlen, va_arg(va, unsigned long long), false, base, precision, width, flags);
744 | #endif
745 | }
746 | else if (flags & FLAGS_LONG) {
747 | idx = _ntoa_long(out, buffer, idx, maxlen, va_arg(va, unsigned long), false, base, precision, width, flags);
748 | }
749 | else {
750 | const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va_arg(va, unsigned int) : (flags & FLAGS_SHORT) ? (unsigned short int)va_arg(va, unsigned int) : va_arg(va, unsigned int);
751 | idx = _ntoa_long(out, buffer, idx, maxlen, value, false, base, precision, width, flags);
752 | }
753 | }
754 | format++;
755 | break;
756 | }
757 | #if defined(PRINTF_SUPPORT_FLOAT)
758 | case 'f' :
759 | case 'F' :
760 | if (*format == 'F') flags |= FLAGS_UPPERCASE;
761 | idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags);
762 | format++;
763 | break;
764 | #if defined(PRINTF_SUPPORT_EXPONENTIAL)
765 | case 'e':
766 | case 'E':
767 | case 'g':
768 | case 'G':
769 | if ((*format == 'g')||(*format == 'G')) flags |= FLAGS_ADAPT_EXP;
770 | if ((*format == 'E')||(*format == 'G')) flags |= FLAGS_UPPERCASE;
771 | idx = _etoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags);
772 | format++;
773 | break;
774 | #endif // PRINTF_SUPPORT_EXPONENTIAL
775 | #endif // PRINTF_SUPPORT_FLOAT
776 | case 'c' : {
777 | unsigned int l = 1U;
778 | // pre padding
779 | if (!(flags & FLAGS_LEFT)) {
780 | while (l++ < width) {
781 | out(' ', buffer, idx++, maxlen);
782 | }
783 | }
784 | // char output
785 | out((char)va_arg(va, int), buffer, idx++, maxlen);
786 | // post padding
787 | if (flags & FLAGS_LEFT) {
788 | while (l++ < width) {
789 | out(' ', buffer, idx++, maxlen);
790 | }
791 | }
792 | format++;
793 | break;
794 | }
795 |
796 | case 's' : {
797 | const char* p = va_arg(va, char*);
798 | unsigned int l = _strnlen_s(p, precision ? precision : (size_t)-1);
799 | // pre padding
800 | if (flags & FLAGS_PRECISION) {
801 | l = (l < precision ? l : precision);
802 | }
803 | if (!(flags & FLAGS_LEFT)) {
804 | while (l++ < width) {
805 | out(' ', buffer, idx++, maxlen);
806 | }
807 | }
808 | // string output
809 | while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) {
810 | out(*(p++), buffer, idx++, maxlen);
811 | }
812 | // post padding
813 | if (flags & FLAGS_LEFT) {
814 | while (l++ < width) {
815 | out(' ', buffer, idx++, maxlen);
816 | }
817 | }
818 | format++;
819 | break;
820 | }
821 |
822 | case 'p' : {
823 | width = sizeof(void*) * 2U;
824 | flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE;
825 | #if defined(PRINTF_SUPPORT_LONG_LONG)
826 | const bool is_ll = sizeof(uintptr_t) == sizeof(long long);
827 | if (is_ll) {
828 | idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void*), false, 16U, precision, width, flags);
829 | }
830 | else {
831 | #endif
832 | idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void*)), false, 16U, precision, width, flags);
833 | #if defined(PRINTF_SUPPORT_LONG_LONG)
834 | }
835 | #endif
836 | format++;
837 | break;
838 | }
839 |
840 | case '%' :
841 | out('%', buffer, idx++, maxlen);
842 | format++;
843 | break;
844 |
845 | default :
846 | out(*format, buffer, idx++, maxlen);
847 | format++;
848 | break;
849 | }
850 | }
851 |
852 | // termination
853 | out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen);
854 |
855 | // return written chars without terminating \0
856 | return (int)idx;
857 | }
858 |
859 |
860 | ///////////////////////////////////////////////////////////////////////////////
861 |
862 | int printf_(const char* format, ...)
863 | {
864 | va_list va;
865 | va_start(va, format);
866 | char buffer[1];
867 | const int ret = _vsnprintf(_out_char, buffer, (size_t)-1, format, va);
868 | va_end(va);
869 | return ret;
870 | }
871 |
872 |
873 | int sprintf_(char* buffer, const char* format, ...)
874 | {
875 | va_list va;
876 | va_start(va, format);
877 | const int ret = _vsnprintf(_out_buffer, buffer, (size_t)-1, format, va);
878 | va_end(va);
879 | return ret;
880 | }
881 |
882 |
883 | int snprintf_(char* buffer, size_t count, const char* format, ...)
884 | {
885 | va_list va;
886 | va_start(va, format);
887 | const int ret = _vsnprintf(_out_buffer, buffer, count, format, va);
888 | va_end(va);
889 | return ret;
890 | }
891 |
892 |
893 | int vprintf_(const char* format, va_list va)
894 | {
895 | char buffer[1];
896 | return _vsnprintf(_out_char, buffer, (size_t)-1, format, va);
897 | }
898 |
899 |
900 | int vsnprintf_(char* buffer, size_t count, const char* format, va_list va)
901 | {
902 | return _vsnprintf(_out_buffer, buffer, count, format, va);
903 | }
904 |
905 |
906 | int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...)
907 | {
908 | va_list va;
909 | va_start(va, format);
910 | const out_fct_wrap_type out_fct_wrap = { out, arg };
911 | const int ret = _vsnprintf(_out_fct, (char*)(uintptr_t)&out_fct_wrap, (size_t)-1, format, va);
912 | va_end(va);
913 | return ret;
914 | }
--------------------------------------------------------------------------------
/lm4f120/src/printf.h:
--------------------------------------------------------------------------------
1 | ///////////////////////////////////////////////////////////////////////////////
2 | // \author (c) Marco Paland (info@paland.com)
3 | // 2014-2019, PALANDesign Hannover, Germany
4 | //
5 | // \license The MIT License (MIT)
6 | //
7 | // Permission is hereby granted, free of charge, to any person obtaining a copy
8 | // of this software and associated documentation files (the "Software"), to deal
9 | // in the Software without restriction, including without limitation the rights
10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the Software is
12 | // furnished to do so, subject to the following conditions:
13 | //
14 | // The above copyright notice and this permission notice shall be included in
15 | // all copies or substantial portions of the Software.
16 | //
17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | // THE SOFTWARE.
24 | //
25 | // \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on
26 | // embedded systems with a very limited resources.
27 | // Use this instead of bloated standard/newlib printf.
28 | // These routines are thread safe and reentrant.
29 | //
30 | ///////////////////////////////////////////////////////////////////////////////
31 |
32 | #ifndef _PRINTF_H_
33 | #define _PRINTF_H_
34 |
35 | #include
36 | #include
37 |
38 |
39 | #ifdef __cplusplus
40 | extern "C" {
41 | #endif
42 |
43 |
44 | /**
45 | * Output a character to a custom device like UART, used by the printf() function
46 | * This function is declared here only. You have to write your custom implementation somewhere
47 | * \param character Character to output
48 | */
49 | void _putchar(char character);
50 |
51 |
52 | /**
53 | * Tiny printf implementation
54 | * You have to implement _putchar if you use printf()
55 | * To avoid conflicts with the regular printf() API it is overridden by macro defines
56 | * and internal underscore-appended functions like printf_() are used
57 | * \param format A string that specifies the format of the output
58 | * \return The number of characters that are written into the array, not counting the terminating null character
59 | */
60 | //#define printf printf_
61 | int printf_(const char* format, ...);
62 |
63 |
64 | /**
65 | * Tiny sprintf implementation
66 | * Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING (V)SNPRINTF INSTEAD!
67 | * \param buffer A pointer to the buffer where to store the formatted string. MUST be big enough to store the output!
68 | * \param format A string that specifies the format of the output
69 | * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character
70 | */
71 | #define sprintf sprintf_
72 | int sprintf_(char* buffer, const char* format, ...);
73 |
74 |
75 | /**
76 | * Tiny snprintf/vsnprintf implementation
77 | * \param buffer A pointer to the buffer where to store the formatted string
78 | * \param count The maximum number of characters to store in the buffer, including a terminating null character
79 | * \param format A string that specifies the format of the output
80 | * \param va A value identifying a variable arguments list
81 | * \return The number of characters that COULD have been written into the buffer, not counting the terminating
82 | * null character. A value equal or larger than count indicates truncation. Only when the returned value
83 | * is non-negative and less than count, the string has been completely written.
84 | */
85 | #define snprintf snprintf_
86 | #define vsnprintf vsnprintf_
87 | int snprintf_(char* buffer, size_t count, const char* format, ...);
88 | int vsnprintf_(char* buffer, size_t count, const char* format, va_list va);
89 |
90 |
91 | /**
92 | * Tiny vprintf implementation
93 | * \param format A string that specifies the format of the output
94 | * \param va A value identifying a variable arguments list
95 | * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character
96 | */
97 | #define vprintf vprintf_
98 | int vprintf_(const char* format, va_list va);
99 |
100 |
101 | /**
102 | * printf with output function
103 | * You may use this as dynamic alternative to printf() with its fixed _putchar() output
104 | * \param out An output function which takes one character and an argument pointer
105 | * \param arg An argument pointer for user data passed to output function
106 | * \param format A string that specifies the format of the output
107 | * \return The number of characters that are sent to the output function, not counting the terminating null character
108 | */
109 | int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...);
110 |
111 |
112 | #ifdef __cplusplus
113 | }
114 | #endif
115 |
116 |
117 | #endif // _PRINTF_H_
--------------------------------------------------------------------------------
/lm4f120/test/README:
--------------------------------------------------------------------------------
1 |
2 | This directory is intended for PIO Unit Testing and project tests.
3 |
4 | Unit Testing is a software testing method by which individual units of
5 | source code, sets of one or more MCU program modules together with associated
6 | control data, usage procedures, and operating procedures, are tested to
7 | determine whether they are fit for use. Unit testing finds problems early
8 | in the development cycle.
9 |
10 | More information about PIO Unit Testing:
11 | - https://docs.platformio.org/page/plus/unit-testing.html
12 |
--------------------------------------------------------------------------------
/maple/.gitignore:
--------------------------------------------------------------------------------
1 | .pio
2 | .vscode/.browse.c_cpp.db*
3 | .vscode/c_cpp_properties.json
4 | .vscode/launch.json
5 | .vscode/ipch
6 |
--------------------------------------------------------------------------------
/maple/.travis.yml:
--------------------------------------------------------------------------------
1 | # Continuous Integration (CI) is the practice, in software
2 | # engineering, of merging all developer working copies with a shared mainline
3 | # several times a day < https://docs.platformio.org/page/ci/index.html >
4 | #
5 | # Documentation:
6 | #
7 | # * Travis CI Embedded Builds with PlatformIO
8 | # < https://docs.travis-ci.com/user/integration/platformio/ >
9 | #
10 | # * PlatformIO integration with Travis CI
11 | # < https://docs.platformio.org/page/ci/travis.html >
12 | #
13 | # * User Guide for `platformio ci` command
14 | # < https://docs.platformio.org/page/userguide/cmd_ci.html >
15 | #
16 | #
17 | # Please choose one of the following templates (proposed below) and uncomment
18 | # it (remove "# " before each line) or use own configuration according to the
19 | # Travis CI documentation (see above).
20 | #
21 |
22 |
23 | #
24 | # Template #1: General project. Test it using existing `platformio.ini`.
25 | #
26 |
27 | # language: python
28 | # python:
29 | # - "2.7"
30 | #
31 | # sudo: false
32 | # cache:
33 | # directories:
34 | # - "~/.platformio"
35 | #
36 | # install:
37 | # - pip install -U platformio
38 | # - platformio update
39 | #
40 | # script:
41 | # - platformio run
42 |
43 |
44 | #
45 | # Template #2: The project is intended to be used as a library with examples.
46 | #
47 |
48 | # language: python
49 | # python:
50 | # - "2.7"
51 | #
52 | # sudo: false
53 | # cache:
54 | # directories:
55 | # - "~/.platformio"
56 | #
57 | # env:
58 | # - PLATFORMIO_CI_SRC=path/to/test/file.c
59 | # - PLATFORMIO_CI_SRC=examples/file.ino
60 | # - PLATFORMIO_CI_SRC=path/to/test/directory
61 | #
62 | # install:
63 | # - pip install -U platformio
64 | # - platformio update
65 | #
66 | # script:
67 | # - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N
68 |
--------------------------------------------------------------------------------
/maple/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // See http://go.microsoft.com/fwlink/?LinkId=827846
3 | // for the documentation about the extensions.json format
4 | "recommendations": [
5 | "platformio.platformio-ide"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/maple/include/README:
--------------------------------------------------------------------------------
1 |
2 | This directory is intended for project header files.
3 |
4 | A header file is a file containing C declarations and macro definitions
5 | to be shared between several project source files. You request the use of a
6 | header file in your project source file (C, C++, etc) located in `src` folder
7 | by including it, with the C preprocessing directive `#include'.
8 |
9 | ```src/main.c
10 |
11 | #include "header.h"
12 |
13 | int main (void)
14 | {
15 | ...
16 | }
17 | ```
18 |
19 | Including a header file produces the same results as copying the header file
20 | into each source file that needs it. Such copying would be time-consuming
21 | and error-prone. With a header file, the related declarations appear
22 | in only one place. If they need to be changed, they can be changed in one
23 | place, and programs that include the header file will automatically use the
24 | new version when next recompiled. The header file eliminates the labor of
25 | finding and changing all the copies as well as the risk that a failure to
26 | find one copy will result in inconsistencies within a program.
27 |
28 | In C, the usual convention is to give header files names that end with `.h'.
29 | It is most portable to use only letters, digits, dashes, and underscores in
30 | header file names, and at most one dot.
31 |
32 | Read more about using header files in official GCC documentation:
33 |
34 | * Include Syntax
35 | * Include Operation
36 | * Once-Only Headers
37 | * Computed Includes
38 |
39 | https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
40 |
--------------------------------------------------------------------------------
/maple/lib/README:
--------------------------------------------------------------------------------
1 |
2 | This directory is intended for project specific (private) libraries.
3 | PlatformIO will compile them to static libraries and link into executable file.
4 |
5 | The source code of each library should be placed in a an own separate directory
6 | ("lib/your_library_name/[here are source files]").
7 |
8 | For example, see a structure of the following two libraries `Foo` and `Bar`:
9 |
10 | |--lib
11 | | |
12 | | |--Bar
13 | | | |--docs
14 | | | |--examples
15 | | | |--src
16 | | | |- Bar.c
17 | | | |- Bar.h
18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
19 | | |
20 | | |--Foo
21 | | | |- Foo.c
22 | | | |- Foo.h
23 | | |
24 | | |- README --> THIS FILE
25 | |
26 | |- platformio.ini
27 | |--src
28 | |- main.c
29 |
30 | and a contents of `src/main.c`:
31 | ```
32 | #include
33 | #include
34 |
35 | int main (void)
36 | {
37 | ...
38 | }
39 |
40 | ```
41 |
42 | PlatformIO Library Dependency Finder will find automatically dependent
43 | libraries scanning project source files.
44 |
45 | More information about PlatformIO Library Dependency Finder
46 | - https://docs.platformio.org/page/librarymanager/ldf.html
47 |
--------------------------------------------------------------------------------
/maple/platformio.ini:
--------------------------------------------------------------------------------
1 | ;PlatformIO Project Configuration File
2 | ;
3 | ; Build options: build flags, source filter
4 | ; Upload options: custom upload port, speed and extra flags
5 | ; Library options: dependencies, extra library storages
6 | ; Advanced options: extra scripting
7 | ;
8 | ; Please visit documentation for the other options and examples
9 | ; https://docs.platformio.org/page/projectconf.html
10 |
11 |
12 | [env:maple]
13 | platform = ststm32
14 | board = maple_mini_origin
15 | framework = arduino
16 | upload_protocol=stlink
17 | build_flags =
18 | -D USBD_USE_CDC
19 | -D PIO_FRAMEWORK_ARDUINO_ENABLE_CDC
20 | -D PIO_FRAMEWORK_ARDUINO_USB_FULLMODE
21 | -D USBCON
22 | -D USBD_VID=0x0483
23 | -D USB_MANUFACTURER="ST"
24 | -D USB_PRODUCT="\"MAPLE\""
25 | -D HAL_PCD_MODULE_ENABLED
26 | -I../../Common
27 | -Wl,-Map,output.map
28 | -I../../nanoAkka/main
29 | -I../../nanoAkka/components/wifi
30 | -I../../ArduinoJson/src
31 | -DCPU=stm32f103
32 | -DBOARD=maple
33 | -DPLATFORM=$PIOPLATFORM
34 | -DHOSTNAME=$PIOPLATFORM
35 |
36 |
--------------------------------------------------------------------------------
/maple/src/MqttSerial.cpp:
--------------------------------------------------------------------------------
1 | ../../common/src/MqttSerial.cpp
--------------------------------------------------------------------------------
/maple/src/NanoAkka.cpp:
--------------------------------------------------------------------------------
1 | ../../common/src/NanoAkka.cpp
--------------------------------------------------------------------------------
/maple/src/NanoAkka.cpp-old:
--------------------------------------------------------------------------------
1 | #include "NanoAkka.h"
2 |
3 | NanoStats stats;
4 | /*
5 | _____ _ _
6 | |_ _| |__ _ __ ___ __ _ __| |
7 | | | | '_ \| '__/ _ \/ _` |/ _` |
8 | | | | | | | | | __/ (_| | (_| |
9 | |_| |_| |_|_| \___|\__,_|\__,_|
10 | */
11 | int Thread::_id = 0;
12 |
13 | void Thread::createQueue() {}
14 |
15 | void Thread::start() {}
16 |
17 | int Thread::enqueue(Invoker *invoker) {
18 | // INFO("Thread '%s' >>> '%s'",_name.c_str(),symbols(invoker));
19 | _workQueue.push(invoker);
20 | return 0;
21 | };
22 |
23 | void Thread::run() {
24 | INFO("Thread '%s' started ", _name.c_str());
25 | while (true) loop();
26 | }
27 |
28 | void Thread::loop() {
29 | uint64_t now = Sys::millis();
30 | uint64_t expTime = now + 5000;
31 | TimerSource *expiredTimer = 0;
32 | // find next expired timer if any within 5 sec
33 | for (auto timer : _timers) {
34 | if (timer->expireTime() < expTime) {
35 | expTime = timer->expireTime();
36 | expiredTimer = timer;
37 | }
38 | }
39 | int32_t waitTime =
40 | (expTime - now); // ESP_OPEN_RTOS seems to double sleep time ?
41 |
42 | // INFO(" waitTime : %d ",waitTime);
43 |
44 | if (waitTime > 0) {
45 | Invoker *prq;
46 | if (_workQueue.pop(prq) == 0) {
47 | uint64_t start = Sys::millis();
48 | prq->invoke();
49 | uint32_t delta = Sys::millis() - start;
50 | if (delta > 20)
51 | WARN("Invoker [%X] slow %lu msec invoker on thread '%s'.",
52 | (unsigned int)prq, delta, _name.c_str());
53 | }
54 | } else {
55 | if (expiredTimer) {
56 | if (-waitTime > 100)
57 | INFO("Timer[%X] already expired by %u msec on thread '%s'.",
58 | (unsigned int)expiredTimer, -waitTime, _name.c_str());
59 | uint64_t start = Sys::millis();
60 | expiredTimer->request();
61 | uint32_t deltaExec = Sys::millis() - start;
62 | if (deltaExec > 20)
63 | WARN("Timer [%X] request slow %lu msec on thread '%s'",
64 | (unsigned int)expiredTimer, deltaExec, _name.c_str());
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/maple/src/Sys.cpp:
--------------------------------------------------------------------------------
1 | ../../common/src/Sys.cpp
--------------------------------------------------------------------------------
/maple/src/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include
6 | //#include
7 | namespace std {
8 | void __throw_bad_function_call() {
9 | WARN("invalid function called");
10 | while (1)
11 | ;
12 | }
13 | } // namespace std
14 | #define PIN_LED PB1
15 | #define PIN_BUTTON PB8
16 |
17 | //_______________________________________________________________________________________________________________
18 | //
19 | #ifdef __arm__
20 | // should use uinstd.h to define sbrk but Due causes a conflict
21 | extern "C" char *sbrk(int incr);
22 | #else // __ARM__
23 | extern char *__brkval;
24 | #endif // __arm__
25 |
26 | int freeMemory() {
27 | char top;
28 | #ifdef __arm__
29 | return &top - reinterpret_cast(sbrk(0));
30 | #elif defined(CORE_TEENSY) || (ARDUINO > 103 && ARDUINO != 151)
31 | return &top - __brkval;
32 | #else // __arm__
33 | return __brkval ? &top - __brkval : &top - __malloc_heap_start;
34 | #endif // __arm__
35 | }
36 | //_______________________________________________________________________________________________________________
37 | //
38 |
39 | class LedBlinker : public Actor, public Sink {
40 | uint32_t _pin;
41 | bool _on;
42 |
43 | public:
44 | Sink blinkSlow;
45 | TimerSource blinkTimer;
46 |
47 | LedBlinker(Thread &thr, uint32_t pin, uint32_t delay);
48 | void init() {
49 | pinMode(_pin, OUTPUT);
50 | digitalWrite(_pin, 1);
51 | blinkTimer >> *this;
52 | };
53 | void delay(uint32_t d) { blinkTimer.interval(d); };
54 | void on(const TimerMsg &) {
55 | digitalWrite(_pin, _on);
56 | _on = !_on;
57 | };
58 | };
59 |
60 | LedBlinker::LedBlinker(Thread &thr, uint32_t pin, uint32_t delay)
61 | : Actor(thr), blinkTimer(thr, 1, delay, true) {
62 | _pin = pin;
63 | blinkTimer.interval(delay);
64 | blinkSlow.sync([&](bool flag) {
65 | if (flag)
66 | blinkTimer.interval(500);
67 | else
68 | blinkTimer.interval(100);
69 | });
70 | }
71 |
72 | //_______________________________________________________________________________________________________________
73 | //
74 | class Button : public Actor, public ValueFlow {
75 | uint32_t _pin;
76 | bool _pinOldValue;
77 | static Button *_button;
78 | static Button *_button2;
79 | bool _lastState = false;
80 |
81 | public:
82 | Button(Thread &thr, uint32_t pin) : Actor(thr), ValueFlow(), _pin(pin) {
83 | _button = this;
84 | };
85 |
86 | void newValue(bool b) {
87 | if (b != _lastState) {
88 | _lastState = b;
89 | on(b);
90 | }
91 | }
92 |
93 | static void isrButton() {
94 | if (_button) _button->newValue(digitalRead(_button->_pin) == 0);
95 | }
96 | void init() {
97 | pinMode(_pin, INPUT_PULLUP);
98 | attachInterrupt(_pin, isrButton, CHANGE);
99 | };
100 | };
101 |
102 | Button *Button::_button = 0;
103 | //______________________________________________________________________
104 | //
105 | class Pinger : public Actor {
106 | int _counter = 0;
107 |
108 | public:
109 | ValueSource out;
110 | Sink in;
111 | Pinger(Thread &thr) : Actor(thr) {
112 | in.async(thread(), [&](const int &i) { out = _counter++; });
113 | }
114 | void start() { out = _counter++; }
115 | };
116 | #define DELTA 50000
117 | class Echo : public Actor {
118 | uint64_t _startTime;
119 |
120 | public:
121 | ValueSource msgPerMsec = 0;
122 | ValueSource out;
123 | Sink in;
124 | Echo(Thread &thr) : Actor(thr) {
125 | in.async(thread(), [&](const int &i) {
126 | // INFO("");
127 | if (i % DELTA == 0) {
128 | uint64_t endTime = Sys::millis();
129 | uint32_t delta = endTime - _startTime;
130 | msgPerMsec = DELTA / delta;
131 | INFO(" handled %d messages in %lu msec = %d msg/msec ", DELTA, delta,
132 | msgPerMsec());
133 | _startTime = Sys::millis();
134 | }
135 | out = i;
136 | });
137 | }
138 | };
139 |
140 | class Poller : public Actor, public Sink {
141 | TimerSource _pollInterval;
142 | std::vector _publishers;
143 | uint32_t _idx = 0;
144 | bool _connected;
145 |
146 | public:
147 | Sink connected;
148 | Poller(Thread &thr) : Actor(thr), _pollInterval(thr, 1, 100, true) {
149 | _pollInterval >> this;
150 | connected.async(thread(), [&](const bool &b) { _connected = b; });
151 | async(thread(), [&](const TimerMsg tm) {
152 | if (_publishers.size() && _connected)
153 | _publishers[_idx++ % _publishers.size()]->request();
154 | });
155 | };
156 | void setInterval(uint32_t t) { _pollInterval.interval(t); }
157 | Poller &operator()(Requestable &rq) {
158 | _publishers.push_back(&rq);
159 | return *this;
160 | }
161 | };
162 | //_______________________________________________________________________________________________________________
163 | //
164 | //__________________________________________
165 |
166 | // MqttSerial mqtt(mainThread,Serial);
167 | Thread mainThread("main");
168 | LedBlinker ledBlinkerBlue(mainThread, PIN_LED, 100);
169 | Button button1(mainThread, PIN_BUTTON);
170 | Poller poller(mainThread);
171 | MqttSerial mqtt(mainThread);
172 | Pinger pinger(mainThread);
173 | Echo echo(mainThread);
174 |
175 | LambdaSource systemHeap([]() { return freeMemory(); });
176 | LambdaSource systemUptime([]() { return Sys::millis(); });
177 | LambdaSource systemHostname([]() { return Sys::hostname(); });
178 | LambdaSource systemBoard([]() { return Sys::board(); });
179 | LambdaSource systemCpu([]() { return Sys::cpu(); });
180 | ValueSource systemBuild = __DATE__ " " __TIME__;
181 | void serialEvent() { MqttSerial::onRxd(&mqtt); }
182 | void setup() {
183 | Serial.begin(115200);
184 | Serial.println("\r\n===== Starting build " __DATE__ " " __TIME__);
185 | #ifndef HOSTNAME
186 | Sys::hostname("lm4f120");
187 | #else
188 | Sys::hostname(S(HOSTNAME));
189 | #endif
190 | button1.init();
191 | ledBlinkerBlue.init();
192 | mqtt.init();
193 |
194 | mqtt.connected >> ledBlinkerBlue.blinkSlow;
195 | mqtt.connected >> poller.connected;
196 | mqtt.connected >> mqtt.toTopic("mqtt/connected");
197 |
198 | systemHeap >> mqtt.toTopic("system/heap");
199 | systemUptime >> mqtt.toTopic("system/upTime");
200 | systemBuild >> mqtt.toTopic("system/build");
201 | systemHostname >> mqtt.toTopic("system/hostname");
202 | systemBoard >> mqtt.toTopic("system/board");
203 | systemCpu >> mqtt.toTopic("system/cpu");
204 |
205 | systemBoard >> ([](const char *board) { INFO("board : %s ", board); });
206 | poller.connected.on(true);
207 | poller(systemHostname)(systemHeap)(systemBuild)(systemUptime)(systemBoard)(
208 | systemCpu);
209 |
210 | button1 >> mqtt.toTopic("button/button1");
211 | poller(button1);
212 | pinger.out >> echo.in; // the wiring
213 | echo.out >> pinger.in;
214 | pinger.start();
215 | Serial.println(" sizeof(int) : " + String(sizeof(int)));
216 | }
217 |
218 | void loop() { mainThread.loop(); }
219 |
--------------------------------------------------------------------------------
/maple/test/README:
--------------------------------------------------------------------------------
1 |
2 | This directory is intended for PIO Unit Testing and project tests.
3 |
4 | Unit Testing is a software testing method by which individual units of
5 | source code, sets of one or more MCU program modules together with associated
6 | control data, usage procedures, and operating procedures, are tested to
7 | determine whether they are fit for use. Unit testing finds problems early
8 | in the development cycle.
9 |
10 | More information about PIO Unit Testing:
11 | - https://docs.platformio.org/page/plus/unit-testing.html
12 |
--------------------------------------------------------------------------------
/nrf51822-ble/.gitignore:
--------------------------------------------------------------------------------
1 | .pio
2 | .vscode/.browse.c_cpp.db*
3 | .vscode/c_cpp_properties.json
4 | .vscode/launch.json
5 | .vscode/ipch
6 |
--------------------------------------------------------------------------------
/nrf51822-ble/.travis.yml:
--------------------------------------------------------------------------------
1 | # Continuous Integration (CI) is the practice, in software
2 | # engineering, of merging all developer working copies with a shared mainline
3 | # several times a day < https://docs.platformio.org/page/ci/index.html >
4 | #
5 | # Documentation:
6 | #
7 | # * Travis CI Embedded Builds with PlatformIO
8 | # < https://docs.travis-ci.com/user/integration/platformio/ >
9 | #
10 | # * PlatformIO integration with Travis CI
11 | # < https://docs.platformio.org/page/ci/travis.html >
12 | #
13 | # * User Guide for `platformio ci` command
14 | # < https://docs.platformio.org/page/userguide/cmd_ci.html >
15 | #
16 | #
17 | # Please choose one of the following templates (proposed below) and uncomment
18 | # it (remove "# " before each line) or use own configuration according to the
19 | # Travis CI documentation (see above).
20 | #
21 |
22 |
23 | #
24 | # Template #1: General project. Test it using existing `platformio.ini`.
25 | #
26 |
27 | # language: python
28 | # python:
29 | # - "2.7"
30 | #
31 | # sudo: false
32 | # cache:
33 | # directories:
34 | # - "~/.platformio"
35 | #
36 | # install:
37 | # - pip install -U platformio
38 | # - platformio update
39 | #
40 | # script:
41 | # - platformio run
42 |
43 |
44 | #
45 | # Template #2: The project is intended to be used as a library with examples.
46 | #
47 |
48 | # language: python
49 | # python:
50 | # - "2.7"
51 | #
52 | # sudo: false
53 | # cache:
54 | # directories:
55 | # - "~/.platformio"
56 | #
57 | # env:
58 | # - PLATFORMIO_CI_SRC=path/to/test/file.c
59 | # - PLATFORMIO_CI_SRC=examples/file.ino
60 | # - PLATFORMIO_CI_SRC=path/to/test/directory
61 | #
62 | # install:
63 | # - pip install -U platformio
64 | # - platformio update
65 | #
66 | # script:
67 | # - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N
68 |
--------------------------------------------------------------------------------
/nrf51822-ble/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // See http://go.microsoft.com/fwlink/?LinkId=827846
3 | // for the documentation about the extensions.json format
4 | "recommendations": [
5 | "platformio.platformio-ide"
6 | ]
7 | }
--------------------------------------------------------------------------------
/nrf51822-ble/include/README:
--------------------------------------------------------------------------------
1 |
2 | This directory is intended for project header files.
3 |
4 | A header file is a file containing C declarations and macro definitions
5 | to be shared between several project source files. You request the use of a
6 | header file in your project source file (C, C++, etc) located in `src` folder
7 | by including it, with the C preprocessing directive `#include'.
8 |
9 | ```src/main.c
10 |
11 | #include "header.h"
12 |
13 | int main (void)
14 | {
15 | ...
16 | }
17 | ```
18 |
19 | Including a header file produces the same results as copying the header file
20 | into each source file that needs it. Such copying would be time-consuming
21 | and error-prone. With a header file, the related declarations appear
22 | in only one place. If they need to be changed, they can be changed in one
23 | place, and programs that include the header file will automatically use the
24 | new version when next recompiled. The header file eliminates the labor of
25 | finding and changing all the copies as well as the risk that a failure to
26 | find one copy will result in inconsistencies within a program.
27 |
28 | In C, the usual convention is to give header files names that end with `.h'.
29 | It is most portable to use only letters, digits, dashes, and underscores in
30 | header file names, and at most one dot.
31 |
32 | Read more about using header files in official GCC documentation:
33 |
34 | * Include Syntax
35 | * Include Operation
36 | * Once-Only Headers
37 | * Computed Includes
38 |
39 | https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
40 |
--------------------------------------------------------------------------------
/nrf51822-ble/lib/README:
--------------------------------------------------------------------------------
1 |
2 | This directory is intended for project specific (private) libraries.
3 | PlatformIO will compile them to static libraries and link into executable file.
4 |
5 | The source code of each library should be placed in a an own separate directory
6 | ("lib/your_library_name/[here are source files]").
7 |
8 | For example, see a structure of the following two libraries `Foo` and `Bar`:
9 |
10 | |--lib
11 | | |
12 | | |--Bar
13 | | | |--docs
14 | | | |--examples
15 | | | |--src
16 | | | |- Bar.c
17 | | | |- Bar.h
18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
19 | | |
20 | | |--Foo
21 | | | |- Foo.c
22 | | | |- Foo.h
23 | | |
24 | | |- README --> THIS FILE
25 | |
26 | |- platformio.ini
27 | |--src
28 | |- main.c
29 |
30 | and a contents of `src/main.c`:
31 | ```
32 | #include
33 | #include
34 |
35 | int main (void)
36 | {
37 | ...
38 | }
39 |
40 | ```
41 |
42 | PlatformIO Library Dependency Finder will find automatically dependent
43 | libraries scanning project source files.
44 |
45 | More information about PlatformIO Library Dependency Finder
46 | - https://docs.platformio.org/page/librarymanager/ldf.html
47 |
--------------------------------------------------------------------------------
/nrf51822-ble/platformio.ini:
--------------------------------------------------------------------------------
1 | ;PlatformIO Project Configuration File
2 | ;
3 | ; Build options: build flags, source filter
4 | ; Upload options: custom upload port, speed and extra flags
5 | ; Library options: dependencies, extra library storages
6 | ; Advanced options: extra scripting
7 | ;
8 | ; Please visit documentation for the other options and examples
9 | ; https://docs.platformio.org/page/projectconf.html
10 |
11 | [env:ble400]
12 | platform = nordicnrf51
13 | board = waveshare_ble400
14 | framework = arduino
15 | ;-> use S110 softdevice
16 | build_flags = -DS130, -DNRF51_S130, -g3, -Og, -DNRF_51822_DEBUG -DBLE_SERIAL_DEBUG_XX
17 | build_unflags = -Os, -O1, -O2, -O3, -g1
18 | lib_deps = BLEPeripheral
19 | monitor_speed = 115200
20 | upload_protocol=stlink
--------------------------------------------------------------------------------
/nrf51822-ble/src/BLESerial.cpp:
--------------------------------------------------------------------------------
1 | #include "BLESerial.h"
2 |
3 | // #define BLE_SERIAL_DEBUG
4 |
5 | BLESerial* BLESerial::_instance = NULL;
6 |
7 | BLESerial::BLESerial(unsigned char req, unsigned char rdy, unsigned char rst) :
8 | BLEPeripheral(req, rdy, rst)
9 | {
10 | this->_txCount = 0;
11 | this->_rxHead = this->_rxTail = 0;
12 | this->_flushed = 0;
13 | BLESerial::_instance = this;
14 |
15 | addAttribute(this->_uartService);
16 | addAttribute(this->_uartNameDescriptor);
17 | setAdvertisedServiceUuid(this->_uartService.uuid());
18 | addAttribute(this->_rxCharacteristic);
19 | addAttribute(this->_rxNameDescriptor);
20 | this->_rxCharacteristic.setEventHandler(BLEWritten, BLESerial::_received);
21 | addAttribute(this->_txCharacteristic);
22 | addAttribute(this->_txNameDescriptor);
23 | }
24 |
25 | void BLESerial::begin(...) {
26 | BLEPeripheral::begin();
27 | #ifdef BLE_SERIAL_DEBUG
28 | Serial.println(F("BLESerial::begin()"));
29 | #endif
30 | }
31 |
32 | void BLESerial::poll() {
33 | if (millis() < this->_flushed + 100) {
34 | BLEPeripheral::poll();
35 | } else {
36 | flush();
37 | }
38 | }
39 |
40 | void BLESerial::end() {
41 | this->_rxCharacteristic.setEventHandler(BLEWritten, NULL);
42 | this->_rxHead = this->_rxTail = 0;
43 | flush();
44 | BLEPeripheral::disconnect();
45 | }
46 |
47 | int BLESerial::available(void) {
48 | BLEPeripheral::poll();
49 | int retval = (this->_rxHead - this->_rxTail + sizeof(this->_rxBuffer)) % sizeof(this->_rxBuffer);
50 | #ifdef BLE_SERIAL_DEBUG
51 | if(retval){Serial.print(F("BLESerial::available() = "));
52 | Serial.println(retval);}
53 | #endif
54 | return retval;
55 | }
56 |
57 | int BLESerial::peek(void) {
58 | BLEPeripheral::poll();
59 | if (this->_rxTail == this->_rxHead) return -1;
60 | uint8_t byte = this->_rxBuffer[this->_rxTail];
61 | #ifdef BLE_SERIAL_DEBUG
62 | Serial.print(F("BLESerial::peek() = "));
63 | Serial.print((char) byte);
64 | Serial.print(F(" 0x"));
65 | Serial.println(byte, HEX);
66 | #endif
67 | return byte;
68 | }
69 |
70 | int BLESerial::read(void) {
71 | BLEPeripheral::poll();
72 | if (this->_rxTail == this->_rxHead) return -1;
73 | this->_rxTail = (this->_rxTail + 1) % sizeof(this->_rxBuffer);
74 | uint8_t byte = this->_rxBuffer[this->_rxTail];
75 | #ifdef BLE_SERIAL_DEBUG
76 | Serial.print(F("BLESerial::read() = "));
77 | Serial.print((char) byte);
78 | Serial.print(F(" 0x"));
79 | Serial.println(byte, HEX);
80 | #endif
81 | return byte;
82 | }
83 |
84 | void BLESerial::flush(void) {
85 | if (this->_txCount == 0) return;
86 | this->_txCharacteristic.setValue(this->_txBuffer, this->_txCount);
87 | this->_flushed = millis();
88 | this->_txCount = 0;
89 | BLEPeripheral::poll();
90 | #ifdef BLE_SERIAL_DEBUG
91 | Serial.println(F("BLESerial::flush()"));
92 | #endif
93 | }
94 |
95 | size_t BLESerial::write(uint8_t byte) {
96 | BLEPeripheral::poll();
97 | if (this->_txCharacteristic.subscribed() == false) return 0;
98 | this->_txBuffer[this->_txCount++] = byte;
99 | if (this->_txCount == sizeof(this->_txBuffer)) flush();
100 | #ifdef BLE_SERIAL_DEBUG
101 | Serial.print(F("BLESerial::write("));
102 | Serial.print((char) byte);
103 | Serial.print(F(" 0x"));
104 | Serial.print(byte, HEX);
105 | Serial.println(F(") = 1"));
106 | #endif
107 | return 1;
108 | }
109 |
110 | BLESerial::operator bool() {
111 | bool retval = BLEPeripheral::connected();
112 | #ifdef BLE_SERIAL_DEBUG
113 | if(retval){
114 | Serial.print(F("BLESerial::operator bool() = "));
115 | Serial.println(retval);}
116 | #endif
117 | return retval;
118 | }
119 |
120 | void BLESerial::_received(const uint8_t* data, size_t size) {
121 | for (int i = 0; i < size; i++) {
122 | this->_rxHead = (this->_rxHead + 1) % sizeof(this->_rxBuffer);
123 | this->_rxBuffer[this->_rxHead] = data[i];
124 | }
125 | #ifdef BLE_SERIAL_DEBUG
126 | Serial.print(F("BLESerial::received("));
127 | for (int i = 0; i < size; i++) Serial.print((char) data[i]);
128 | Serial.println(F(")"));
129 | #endif
130 | }
131 |
132 | void BLESerial::_received(BLECentral& /*central*/, BLECharacteristic& rxCharacteristic) {
133 | BLESerial::_instance->_received(rxCharacteristic.value(), rxCharacteristic.valueLength());
134 | }
135 |
136 |
--------------------------------------------------------------------------------
/nrf51822-ble/src/BLESerial.h:
--------------------------------------------------------------------------------
1 | #ifndef _BLE_SERIAL_H_
2 | #define _BLE_SERIAL_H_
3 |
4 | #include
5 | #include
6 |
7 | class BLESerial : public BLEPeripheral, public Stream
8 | {
9 | public:
10 | BLESerial(unsigned char req, unsigned char rdy, unsigned char rst);
11 |
12 | void begin(...);
13 | void poll();
14 | void end();
15 |
16 | virtual int available(void);
17 | virtual int peek(void);
18 | virtual int read(void);
19 | virtual void flush(void);
20 | virtual size_t write(uint8_t byte);
21 | using Print::write;
22 | virtual operator bool();
23 |
24 | private:
25 | unsigned long _flushed;
26 | static BLESerial* _instance;
27 |
28 | size_t _rxHead;
29 | size_t _rxTail;
30 | size_t _rxCount() const;
31 | uint8_t _rxBuffer[BLE_ATTRIBUTE_MAX_VALUE_LENGTH];
32 | size_t _txCount;
33 | uint8_t _txBuffer[BLE_ATTRIBUTE_MAX_VALUE_LENGTH];
34 |
35 | BLEService _uartService = BLEService("6E400001-B5A3-F393-E0A9-E50E24DCCA9E");
36 | BLEDescriptor _uartNameDescriptor = BLEDescriptor("2901", "UART");
37 | BLECharacteristic _rxCharacteristic = BLECharacteristic("6E400002-B5A3-F393-E0A9-E50E24DCCA9E", BLEWriteWithoutResponse, BLE_ATTRIBUTE_MAX_VALUE_LENGTH);
38 | BLEDescriptor _rxNameDescriptor = BLEDescriptor("2901", "RX - Receive Data (Write)");
39 | BLECharacteristic _txCharacteristic = BLECharacteristic("6E400003-B5A3-F393-E0A9-E50E24DCCA9E", BLENotify, BLE_ATTRIBUTE_MAX_VALUE_LENGTH);
40 | BLEDescriptor _txNameDescriptor = BLEDescriptor("2901", "TX - Transfer Data (Notify)");
41 |
42 | void _received(const uint8_t* data, size_t size);
43 | static void _received(BLECentral& /*central*/, BLECharacteristic& rxCharacteristic);
44 | };
45 |
46 | #endif
47 |
--------------------------------------------------------------------------------
/nrf51822-ble/src/main.cpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) Sandeep Mistry. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | // Import libraries (BLEPeripheral depends on SPI)
5 | #include
6 | // Copyright (c) Sandeep Mistry. All rights reserved.
7 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
8 |
9 | /*
10 | * Serial Port over BLE
11 | * Create UART service compatible with Nordic's *nRF Toolbox* and Adafruit's *Bluefruit LE* iOS/Android apps.
12 | *
13 | * BLESerial class implements same protocols as Arduino's built-in Serial class and can be used as it's wireless
14 | * replacement. Data transfers are routed through a BLE service with TX and RX characteristics. To make the
15 | * service discoverable all UUIDs are NUS (Nordic UART Service) compatible.
16 | *
17 | * Please note that TX and RX characteristics use Notify and WriteWithoutResponse, so there's no guarantee
18 | * that the data will make it to the other end. However, under normal circumstances and reasonable signal
19 | * strengths everything works well.
20 | */
21 |
22 |
23 | // Import libraries (BLEPeripheral depends on SPI)
24 | #include