├── .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 25 | #include 26 | #include "BLESerial.h" 27 | 28 | // define pins (varies per shield/board) 29 | #define BLE_REQ 10 30 | #define BLE_RDY 2 31 | #define BLE_RST 9 32 | 33 | 34 | void forward(); 35 | void loopback(); 36 | void spam(); 37 | 38 | // create ble serial instance, see pinouts above 39 | BLESerial BLESerial(BLE_REQ, BLE_RDY, BLE_RST); 40 | 41 | 42 | void setupBLE() { 43 | // custom services and characteristics can be added as well 44 | BLESerial.setLocalName("UART"); 45 | 46 | Serial.begin(115200); 47 | BLESerial.begin(); 48 | } 49 | 50 | void loopBLE() { 51 | BLESerial.poll(); 52 | 53 | forward(); 54 | // loopback(); 55 | // spam(); 56 | } 57 | 58 | 59 | // forward received from Serial to BLESerial and vice versa 60 | void forward() { 61 | if (BLESerial && Serial) { 62 | int byte; 63 | while ((byte = BLESerial.read()) > 0) Serial.write((char)byte); 64 | while ((byte = Serial.read()) > 0) BLESerial.write((char)byte); 65 | } 66 | } 67 | 68 | // echo all received data back 69 | void loopback() { 70 | if (BLESerial) { 71 | int byte; 72 | while ((byte = BLESerial.read()) > 0) BLESerial.write(byte); 73 | } 74 | } 75 | 76 | // periodically sent time stamps 77 | void spam() { 78 | if (BLESerial) { 79 | BLESerial.print(millis()); 80 | BLESerial.println(" tick-tacks!"); 81 | delay(100); 82 | } 83 | } 84 | 85 | #include 86 | 87 | #include "proto.h" 88 | 89 | //_______________________________________________________________________________________________________________ 90 | // 91 | 92 | //_______________________________________________________________________________________________________________ 93 | // 94 | #define PIN_LED 20 95 | class LedBlinker : public ProtoThread { 96 | uint32_t _pin, _delay; 97 | 98 | public: 99 | LedBlinker(uint32_t pin, uint32_t delay) { 100 | _pin = pin; 101 | _delay = delay; 102 | } 103 | void setup() { 104 | LOG("LedBlinker started."); 105 | pinMode(_pin, OUTPUT); 106 | digitalWrite(_pin, 1); 107 | } 108 | void loop() { 109 | PT_BEGIN(); 110 | while (true) { 111 | timeout(_delay); 112 | digitalWrite(_pin, 0); 113 | PT_YIELD_UNTIL(timeout()); 114 | timeout(_delay); 115 | digitalWrite(_pin, 1); 116 | PT_YIELD_UNTIL(timeout()); 117 | } 118 | PT_END(); 119 | } 120 | void delay(uint32_t d) { _delay = d; } 121 | }; 122 | //_______________________________________________________________________________________________________________ 123 | // 124 | // LedBlinker ledBlinkerRed(LED_RED_PIN,100); 125 | // LedBlinker ledBlinkerGreen(LED_GREEN_PIN,300); 126 | //_______________________________________________________________________________________________________________ 127 | // 128 | class Publisher : public ProtoThread { 129 | String _systemPrefix; 130 | MqttSerial &_mqtt; 131 | LedBlinker &_ledBlinker; 132 | 133 | public: 134 | Publisher(MqttSerial &mqtt, LedBlinker &ledBlinker) 135 | : _mqtt(mqtt), _ledBlinker(ledBlinker){}; 136 | void setup() { 137 | LOG("Publisher started"); 138 | _systemPrefix = "src/" + Sys::hostname + "/system/"; 139 | } 140 | void loop() { 141 | PT_BEGIN(); 142 | while (true) { 143 | if (_mqtt.isConnected()) { 144 | _mqtt.publish(_systemPrefix + "upTime", String(millis())); 145 | _mqtt.publish(_systemPrefix + "build", Sys::build); 146 | _mqtt.publish(_systemPrefix + "cpu", Sys::cpu); 147 | _mqtt.publish(_systemPrefix + "heap", String(freeMemory())); 148 | _ledBlinker.delay(1000); 149 | } else 150 | _ledBlinker.delay(100); 151 | timeout(1000); 152 | PT_YIELD_UNTIL(timeout()); 153 | } 154 | PT_END(); 155 | } 156 | }; 157 | // 158 | //_____________________________________ protothreads running _____ 159 | // 160 | 161 | MqttSerial mqtt(Serial); 162 | MqttSerial mqtt2(BLESerial); 163 | LedBlinker ledBlinkerBlue(PIN_LED, 100); 164 | Publisher publisher(mqtt, ledBlinkerBlue); 165 | 166 | void mqttCallback(String topic, String message) { 167 | Serial.println(" RXD " + topic + "=" + message); 168 | } 169 | 170 | void setup() { 171 | Serial.begin(115200); 172 | LOG("===== Starting ProtoThreads build " __DATE__ " " __TIME__); 173 | Sys::hostname = "nordic"; 174 | Sys::cpu = "nrf51822"; 175 | mqtt.onMqttPublish(mqttCallback); 176 | ProtoThread::setupAll(); 177 | setupBLE(); 178 | } 179 | 180 | void loop() { loopBLE();ProtoThread::loopAll(); } 181 | 182 | -------------------------------------------------------------------------------- /nrf51822-ble/src/proto.cpp: -------------------------------------------------------------------------------- 1 | ../../common/src/proto.cpp -------------------------------------------------------------------------------- /nrf51822-ble/src/proto.h: -------------------------------------------------------------------------------- 1 | ../../common/src/proto.h -------------------------------------------------------------------------------- /nrf51822-ble/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/.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode/.browse.c_cpp.db* 3 | .vscode/c_cpp_properties.json 4 | .vscode/launch.json 5 | .vscode/ipch 6 | -------------------------------------------------------------------------------- /nrf51822/.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/.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 | -------------------------------------------------------------------------------- /nrf51822/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/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/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:waveshare_ble400] 12 | platform = nordicnrf51 13 | board = waveshare_ble400 14 | framework = arduino 15 | upload_protocol=stlink 16 | build_flags= 17 | -DCPU=nrf51822 18 | -DBOARD=nordic 19 | -DPLATFORM=$PIOPLATFORM 20 | -DHOSTNAME=$PIOPLATFORM 21 | -fno-exceptions -fno-rtti 22 | -I../../Common 23 | -Wl,-Map,output.map 24 | -I../../nanoAkka/main 25 | -I../../nanoAkka/components/wifi 26 | -I../../ArduinoJson/src 27 | monitor_port = /dev/ttyUSB0 28 | monitor_speed = 115200 29 | upload_port = /dev/ttyUSB0 -------------------------------------------------------------------------------- /nrf51822/src/MedianFilter.h: -------------------------------------------------------------------------------- 1 | ../../common/src/MedianFilter.h -------------------------------------------------------------------------------- /nrf51822/src/MqttSerial.cpp: -------------------------------------------------------------------------------- 1 | ../../common/src/MqttSerial.cpp -------------------------------------------------------------------------------- /nrf51822/src/NanoAkka.cpp: -------------------------------------------------------------------------------- 1 | ../../common/src/NanoAkka.cpp -------------------------------------------------------------------------------- /nrf51822/src/Sys.cpp: -------------------------------------------------------------------------------- 1 | ../../common/src/Sys.cpp -------------------------------------------------------------------------------- /nrf51822/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 20 15 | #define PIN_BUTTON 17 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("unknown"); 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() { 219 | mainThread.loop(); 220 | if (Serial.available()) { 221 | MqttSerial::onRxd(&mqtt); 222 | } 223 | } 224 | -------------------------------------------------------------------------------- /nrf51822/src/main.cpp-old: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "proto.h" 4 | 5 | //_______________________________________________________________________________________________________________ 6 | // 7 | 8 | //_______________________________________________________________________________________________________________ 9 | // 10 | #define PIN_LED 20 11 | class LedBlinker : public ProtoThread { 12 | uint32_t _pin, _delay; 13 | 14 | public: 15 | LedBlinker(uint32_t pin, uint32_t delay) { 16 | _pin = pin; 17 | _delay = delay; 18 | } 19 | void setup() { 20 | LOG("LedBlinker started."); 21 | pinMode(_pin, OUTPUT); 22 | digitalWrite(_pin, 1); 23 | } 24 | void loop() { 25 | PT_BEGIN(); 26 | while (true) { 27 | timeout(_delay); 28 | digitalWrite(_pin, 0); 29 | PT_YIELD_UNTIL(timeout()); 30 | timeout(_delay); 31 | digitalWrite(_pin, 1); 32 | PT_YIELD_UNTIL(timeout()); 33 | } 34 | PT_END(); 35 | } 36 | void delay(uint32_t d) { _delay = d; } 37 | }; 38 | //_______________________________________________________________________________________________________________ 39 | // 40 | // LedBlinker ledBlinkerRed(LED_RED_PIN,100); 41 | // LedBlinker ledBlinkerGreen(LED_GREEN_PIN,300); 42 | //_______________________________________________________________________________________________________________ 43 | // 44 | class Publisher : public ProtoThread { 45 | String _systemPrefix; 46 | MqttSerial &_mqtt; 47 | LedBlinker &_ledBlinker; 48 | 49 | public: 50 | Publisher(MqttSerial &mqtt, LedBlinker &ledBlinker) 51 | : _mqtt(mqtt), _ledBlinker(ledBlinker){}; 52 | void setup() { 53 | LOG("Publisher started"); 54 | _systemPrefix = "src/" + Sys::hostname + "/system/"; 55 | } 56 | void loop() { 57 | PT_BEGIN(); 58 | while (true) { 59 | if (_mqtt.isConnected()) { 60 | _mqtt.publish(_systemPrefix + "upTime", String(millis())); 61 | _mqtt.publish(_systemPrefix + "build", Sys::build); 62 | _mqtt.publish(_systemPrefix + "cpu", Sys::cpu); 63 | _mqtt.publish(_systemPrefix + "heap", String(freeMemory())); 64 | _ledBlinker.delay(1000); 65 | } else 66 | _ledBlinker.delay(100); 67 | timeout(1000); 68 | PT_YIELD_UNTIL(timeout()); 69 | } 70 | PT_END(); 71 | } 72 | }; 73 | // 74 | //_____________________________________ protothreads running _____ 75 | // 76 | 77 | MqttSerial mqtt(Serial); 78 | LedBlinker ledBlinkerBlue(PIN_LED, 100); 79 | Publisher publisher(mqtt, ledBlinkerBlue); 80 | 81 | void mqttCallback(String topic, String message) { 82 | Serial.println(" RXD " + topic + "=" + message); 83 | } 84 | 85 | void setup() { 86 | Serial.begin(115200); 87 | LOG("===== Starting ProtoThreads build " __DATE__ " " __TIME__); 88 | Sys::hostname = "nordic"; 89 | Sys::cpu = "nrf51822"; 90 | mqtt.onMqttPublish(mqttCallback); 91 | ProtoThread::setupAll(); 92 | } 93 | 94 | void loop() { ProtoThread::loopAll(); } 95 | -------------------------------------------------------------------------------- /nrf51822/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 | -------------------------------------------------------------------------------- /pic32/.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode/.browse.c_cpp.db* 3 | .vscode/c_cpp_properties.json 4 | .vscode/launch.json 5 | .vscode/ipch 6 | -------------------------------------------------------------------------------- /pic32/.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 | -------------------------------------------------------------------------------- /pic32/.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 | -------------------------------------------------------------------------------- /pic32/README.md: -------------------------------------------------------------------------------- 1 | dead end street pic32 compiler doesn't provide c++ atomic, functional,.. 2 | -------------------------------------------------------------------------------- /pic32/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 | -------------------------------------------------------------------------------- /pic32/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 | -------------------------------------------------------------------------------- /pic32/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:chipkit_pi] 12 | platform = microchippic32 13 | board = chipkit_pi 14 | framework = arduino 15 | build_flags= 16 | -DCPU=pic32m250f128 17 | -DBOARD=chipkit_pi 18 | -DPLATFORM=$PIOPLATFORM 19 | -DHOSTNAME=$PIOPLATFORM 20 | -std=c++11 21 | -fno-exceptions -fno-rtti 22 | -I../../Common 23 | -Wl,-Map,output.map 24 | -I../../nanoAkka/main 25 | -I../../nanoAkka/components/wifi 26 | -I../../ArduinoJson/src 27 | monitor_port = /dev/ttyUSB0 28 | monitor_speed = 115200 29 | upload_port = /dev/ttyUSB0 -------------------------------------------------------------------------------- /pic32/src/MqttSerial.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | MqttSerial::MqttSerial(Thread &thr) 4 | : Mqtt(thr), 5 | connected(false), 6 | keepAliveTimer(thr, TIMER_KEEP_ALIVE, 1000, true), 7 | connectTimer(thr, TIMER_CONNECT, 3000, true) { 8 | _rxdString.reserve(256); 9 | } 10 | MqttSerial::~MqttSerial() {} 11 | 12 | void MqttSerial::init() { 13 | INFO("MqttSerial started. "); 14 | txd.clear(); 15 | rxd.clear(); 16 | _hostPrefix = "src/"; 17 | _hostPrefix += Sys::hostname(); 18 | _hostPrefix += "/"; 19 | _loopbackTopic = "dst/"; 20 | _loopbackTopic += Sys::hostname(); 21 | _loopbackTopic += "/system/loopback"; 22 | _loopbackReceived = 0; 23 | 24 | outgoing.async(thread(), [&](const MqttMessage &m) { 25 | if (connected()) { 26 | String topic = _hostPrefix; 27 | topic += m.topic; 28 | publish(topic, m.message); 29 | } 30 | }); 31 | 32 | // Sink &me = *this; 33 | keepAliveTimer >> this; 34 | connectTimer >> this; 35 | 36 | Serial.setTimeout(0); 37 | } 38 | 39 | void MqttSerial::on(const TimerMsg &tm) { 40 | if (tm.id == TIMER_KEEP_ALIVE) { 41 | publish(_loopbackTopic, String("true")); 42 | outgoing.on({"system/alive", "true"}); 43 | } else if (tm.id == TIMER_CONNECT) { 44 | if (Sys::millis() > (_loopbackReceived + 2000)) { 45 | connected = false; 46 | String topic = "dst/"; 47 | topic += Sys::hostname(); 48 | topic += "/#"; 49 | subscribe(topic); 50 | publish(_loopbackTopic, "true"); 51 | } else { 52 | connected = true; 53 | } 54 | } else { 55 | WARN("Invalid Timer Id"); 56 | } 57 | } 58 | 59 | void MqttSerial::request() {} 60 | 61 | void MqttSerial::onRxd(void *me) { 62 | INFO(" RXD "); 63 | MqttSerial *mqttSerial = (MqttSerial *)me; 64 | while (Serial.available()) { 65 | String s; 66 | s = Serial.readString(); 67 | for (uint32_t i = 0; i < s.length(); i++) 68 | mqttSerial->handleSerialByte(s.charAt(i)); 69 | } 70 | } 71 | 72 | void MqttSerial::handleSerialByte(uint8_t b) { 73 | if (b == '\r' || b == '\n') { 74 | if (_rxdString.length() > 0) { 75 | INFO(" RXD : %s ", _rxdString.c_str()); 76 | rxdSerial(_rxdString); 77 | } 78 | _rxdString = ""; 79 | } else { 80 | _rxdString += (char)b; 81 | } 82 | } 83 | 84 | void MqttSerial::rxdSerial(String &rxdString) { 85 | deserializeJson(rxd, rxdString); 86 | JsonArray array = rxd.as(); 87 | if (!array.isNull()) { 88 | if (array[1].as() == _loopbackTopic) { 89 | _loopbackReceived = Sys::millis(); 90 | connected = true; 91 | } else { 92 | String topic = array[1]; 93 | incoming.on({topic.substring(_hostPrefix.length()), array[2]}); 94 | } 95 | } else { 96 | WARN(" parsing JSON array failed "); 97 | } 98 | } 99 | 100 | void MqttSerial::publish(String &topic, String message) { 101 | txd.clear(); 102 | txd.add((int)CMD_PUBLISH); 103 | txd.add(topic); 104 | txd.add(message); 105 | txdSerial(txd); 106 | } 107 | 108 | void MqttSerial::subscribe(String &topic) { 109 | txd.clear(); 110 | txd.add((int)CMD_SUBSCRIBE); 111 | txd.add(topic); 112 | txdSerial(txd); 113 | } 114 | 115 | void MqttSerial::txdSerial(JsonDocument &txd) { 116 | String output = ""; 117 | serializeJson(txd, output); 118 | Serial.println(output.c_str()); 119 | Serial.flush(); 120 | } 121 | -------------------------------------------------------------------------------- /pic32/src/NanoAkka.cpp: -------------------------------------------------------------------------------- 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 %ld 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 | -------------------------------------------------------------------------------- /pic32/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 | -------------------------------------------------------------------------------- /pic32/src/Sys.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | uint64_t Sys::_upTime; 7 | char Sys::_hostname[30] = ""; 8 | uint64_t Sys::_boot_time = 0; 9 | 10 | //_____________________________________________________________ LINUX and CYGWIN 11 | #if defined(__linux__) || defined(__CYGWIN__) || defined ( __APPLE__ ) && !defined(ARDUINO) 12 | #include 13 | #include 14 | 15 | uint64_t Sys::millis() { // time in msec since boot, only increasing 16 | using namespace std::chrono; 17 | milliseconds ms = 18 | duration_cast(system_clock::now().time_since_epoch()); 19 | Sys::_upTime = ms.count();//system_clock::now().time_since_epoch().count() / 1000000; 20 | return _upTime; 21 | } 22 | 23 | void Sys::init() { gethostname(_hostname, sizeof(_hostname) - 1); } 24 | 25 | void Sys::hostname(const char* hostname) { 26 | strncpy(_hostname, hostname, sizeof(_hostname)); 27 | } 28 | 29 | const char* Sys::hostname() { 30 | if (_hostname[0] == 0) 31 | Sys::init(); 32 | return _hostname; 33 | } 34 | 35 | void Sys::delay(uint32_t msec) { 36 | struct timespec ts; 37 | ts.tv_sec = msec / 1000; 38 | ts.tv_nsec = (msec - ts.tv_sec * 1000) * 1000000; 39 | nanosleep(&ts, NULL); 40 | }; 41 | 42 | #endif 43 | 44 | //________________________________________________________ ARDUINO 45 | 46 | #ifdef ARDUINO 47 | 48 | #include 49 | uint64_t Sys::millis() { return ::millis();} 50 | 51 | const char* Sys::cpu() { return S(CPU); } 52 | const char* Sys::board() { return S(BOARD); } 53 | uint64_t Sys::now() { return _boot_time + Sys::millis(); } 54 | uint32_t Sys::getFreeHeap() { return getFreeHeap(); } 55 | 56 | void Sys::hostname(const char* hostname) { 57 | strncpy(_hostname, hostname, sizeof(_hostname)); 58 | } 59 | 60 | const char* Sys::hostname() { return _hostname; } 61 | void Sys::delay(uint32_t delta) { 62 | uint32_t end = Sys::millis() + delta; 63 | while(Sys::millis() < end) 64 | ; 65 | } 66 | #endif 67 | 68 | #ifdef __ESP8266__ 69 | 70 | void Sys::delay(uint32_t delta) { 71 | uint64_t t1 = Sys::millis() + delta; 72 | while (Sys::millis() < t1) 73 | ; 74 | } 75 | 76 | #endif 77 | 78 | #if defined(ESP_OPEN_RTOS) 79 | #include 80 | #include 81 | #include 82 | #include 83 | #include 84 | #include 85 | #include 86 | #include 87 | 88 | const char* Sys::getProcessor() { return "ESP8266"; } 89 | const char* Sys::getBuild() { return __DATE__ " " __TIME__; } 90 | 91 | void Sys::init() { 92 | // uint8_t cpuMhz = sdk_system_get_cpu_frequency(); 93 | } 94 | 95 | uint32_t Sys::getFreeHeap() { return 0; }; 96 | 97 | uint64_t Sys::millis() { 98 | /* 99 | timeval time; 100 | gettimeofday(&time, NULL); 101 | return (time.tv_sec * 1000) + (time.tv_usec / 1000);*/ 102 | return Sys::micros() / 1000; 103 | } 104 | 105 | uint32_t Sys::sec() { return millis() / 1000; } 106 | 107 | uint64_t Sys::micros() { 108 | 109 | static uint32_t lsClock = 0; 110 | static uint32_t msClock = 0; 111 | 112 | vPortEnterCritical(); 113 | uint32_t ccount; 114 | __asm__ __volatile__("esync; rsr %0,ccount" : "=a"(ccount)); 115 | if(ccount < lsClock) { msClock++; } 116 | lsClock = ccount; 117 | portEXIT_CRITICAL(); 118 | 119 | uint64_t micros = msClock; 120 | micros <<= 32; 121 | micros += lsClock; 122 | 123 | return micros / 80; 124 | } 125 | 126 | uint64_t Sys::now() { return _boot_time + Sys::millis(); } 127 | 128 | void Sys::setNow(uint64_t n) { _boot_time = n - Sys::millis(); } 129 | 130 | void Sys::hostname(const char* h) { strncpy(_hostname, h, strlen(h) + 1); } 131 | 132 | void Sys::setHostname(const char* h) { strncpy(_hostname, h, strlen(h) + 1); } 133 | 134 | void Sys::delay(unsigned int delta) { 135 | uint32_t end = Sys::millis() + delta; 136 | while(Sys::millis() < end) 137 | ; 138 | } 139 | 140 | extern "C" uint64_t SysMillis() { return Sys::millis(); } 141 | 142 | /* 143 | * 144 | * ATTENTION : LOGF call Sys::hostname, could invoke another call to 145 | * Sys::hostname with LOGF,.... 146 | * 147 | * 148 | * 149 | */ 150 | 151 | const char* Sys::hostname() { 152 | if(_hostname[0] == 0) { snprintf(_hostname, sizeof(_hostname), "ESP82-%d", sdk_system_get_chip_id() & 0xFFFF); } 153 | return _hostname; 154 | } 155 | const char* Sys::getBoard() { 156 | static char buffer[80]; 157 | snprintf(buffer, sizeof(buffer), " cpu-id : %X , freq : %d Mhz rom-sdk : %s", sdk_system_get_chip_id(), 158 | sdk_system_get_cpu_freq(), sdk_system_get_sdk_version()); 159 | sdk_system_print_meminfo(); 160 | return buffer; 161 | } 162 | 163 | #endif 164 | 165 | #ifdef ESP32_IDF 166 | #include 167 | #include 168 | #include 169 | #include 170 | #include 171 | #include 172 | //#include 173 | 174 | uint32_t Sys::getSerialId() { 175 | union { 176 | uint8_t my_id[6]; 177 | uint32_t lsb; 178 | }; 179 | esp_efuse_mac_get_default(my_id); 180 | // esp_efuse_mac_get_custom(my_id); 181 | // sdk_wifi_get_macaddr(STATION_IF, my_id); 182 | return lsb; 183 | } 184 | 185 | const char* Sys::getProcessor() { return "ESP8266"; } 186 | const char* Sys::getBuild() { return __DATE__ " " __TIME__; } 187 | 188 | uint32_t Sys::getFreeHeap() { return xPortGetFreeHeapSize(); }; 189 | 190 | const char* Sys::hostname() { 191 | if (_hostname[0] == 0) { 192 | union { 193 | uint8_t my_id[6]; 194 | uint32_t word[2]; 195 | }; 196 | esp_efuse_mac_get_default(my_id); 197 | snprintf(_hostname, sizeof(_hostname), "ESP32-%d", 198 | (word[0] ^ word[1]) & 0xFFFF); 199 | } 200 | return _hostname; 201 | } 202 | 203 | void Sys::init() {} 204 | 205 | uint64_t Sys::millis() { return Sys::micros() / 1000; } 206 | 207 | uint32_t Sys::sec() { return millis() / 1000; } 208 | 209 | uint64_t Sys::micros() { 210 | return esp_timer_get_time(); 211 | } 212 | 213 | uint64_t Sys::now() { return _boot_time + Sys::millis(); } 214 | 215 | void Sys::setNow(uint64_t n) { _boot_time = n - Sys::millis(); } 216 | 217 | void Sys::hostname(const char* h) { strncpy(_hostname, h, strlen(h) + 1); } 218 | 219 | void Sys::setHostname(const char* h) { strncpy(_hostname, h, strlen(h) + 1); } 220 | 221 | void Sys::delay(unsigned int delta) { 222 | uint32_t end = Sys::millis() + delta; 223 | while (Sys::millis() < end) { 224 | }; 225 | } 226 | 227 | extern "C" uint64_t SysMillis() { return Sys::millis(); } 228 | #endif // ESP32_IDF 229 | -------------------------------------------------------------------------------- /pic32/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 | -------------------------------------------------------------------------------- /pic32/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 | -------------------------------------------------------------------------------- /simple/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 | 16 | -------------------------------------------------------------------------------- /simple/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void setup() { 4 | Serial.begin(115200); 5 | } 6 | 7 | void loop() { 8 | Serial.println("[1,\"src/myTopic/time\","+String(millis())+"]"); 9 | delay(10); 10 | } -------------------------------------------------------------------------------- /stm32f0discovery/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 | -------------------------------------------------------------------------------- /stm32f0discovery/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:disco_f051r8] 12 | platform = ststm32 13 | board = disco_f051r8 14 | framework = Arduino 15 | upload_protocol = stlink 16 | 17 | -------------------------------------------------------------------------------- /stm32f0discovery/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | 5 | // put your setup code here, to run once: 6 | 7 | while(1) { 8 | // put your main code here, to run repeatedly: 9 | } 10 | } --------------------------------------------------------------------------------