From e4343ed10541444bc16b6fed4f27039df366c278 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Thu, 13 May 2021 13:25:54 -0700 Subject: [PATCH 01/12] libraries/EpoxyMockDigitalWriteFast: Fix compiler warnings for unused parameters --- libraries/EpoxyMockDigitalWriteFast/digitalWriteFast.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/EpoxyMockDigitalWriteFast/digitalWriteFast.h b/libraries/EpoxyMockDigitalWriteFast/digitalWriteFast.h index eb49110..1def813 100644 --- a/libraries/EpoxyMockDigitalWriteFast/digitalWriteFast.h +++ b/libraries/EpoxyMockDigitalWriteFast/digitalWriteFast.h @@ -14,10 +14,10 @@ #include // uint8_t -inline void digitalWriteFast(uint8_t pin, uint8_t value) {} +inline void digitalWriteFast(uint8_t /*pin*/, uint8_t /*value*/) {} -inline void pinModeFast(uint8_t pin, uint8_t value) {} +inline void pinModeFast(uint8_t /*pin*/, uint8_t /*value*/) {} -inline uint8_t digitalReadFast(uint8_t pin) { return 0; } +inline uint8_t digitalReadFast(uint8_t /*pin*/) { return 0; } #endif From d66ecfe25eb3950fe9277cef72e815df4aa50581 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Thu, 29 Apr 2021 06:07:37 -0700 Subject: [PATCH 02/12] .gitignore: Update comment to matching renaming of EpoxyProm{Avr,Esp} to EpoxyEeprom{Avr,Esp} --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index ff28393..2dedd4d 100644 --- a/.gitignore +++ b/.gitignore @@ -34,5 +34,5 @@ # Root directory of EpoxyFS epoxyfsdata -# Root file of EpoxyPromAvr and EpoxyPromEsp +# Root file of EpoxyEeromAvr and EpoxyEeromEsp epoxyeepromdata From 5797bd546fabc7ec4c9329c20effd51b271e1c09 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Tue, 18 May 2021 12:15:23 -0700 Subject: [PATCH 03/12] EpoxyMockDigitalWriteFast/README.md: Fix typos --- libraries/EpoxyMockDigitalWriteFast/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/EpoxyMockDigitalWriteFast/README.md b/libraries/EpoxyMockDigitalWriteFast/README.md index bbf39a9..0835ef7 100644 --- a/libraries/EpoxyMockDigitalWriteFast/README.md +++ b/libraries/EpoxyMockDigitalWriteFast/README.md @@ -45,11 +45,11 @@ To fix that problem, change the code to look like this: ... ``` -Then add `EpoxyDigitalWriteFastMock` to the `ARDUINO_LIBS` in the EpoxyDuino +Then add `EpoxyMockDigitalWriteFast` to the `ARDUINO_LIBS` in the EpoxyDuino `Makefile`: ```make APP_NAME := MyApp -ARDUINO_LIBS := EpoxyDigitalWriteFastMock ... +ARDUINO_LIBS := EpoxyMockDigitalWriteFast ... include ../../../../EpoxyDuino.mk ``` From 5b7517605740c8a2fbf88ba088f1d7c37d652ed9 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Tue, 18 May 2021 12:17:00 -0700 Subject: [PATCH 04/12] EpoxyMockTimerOne: Add mock library for TimerOne (https://github.com/PaulStoffregen/TimerOne) --- CHANGELOG.md | 2 + libraries/EpoxyMockTimerOne/README.md | 40 +++++++++++++ libraries/EpoxyMockTimerOne/TimerOne.cpp | 10 ++++ libraries/EpoxyMockTimerOne/TimerOne.h | 73 ++++++++++++++++++++++++ 4 files changed, 125 insertions(+) create mode 100644 libraries/EpoxyMockTimerOne/README.md create mode 100644 libraries/EpoxyMockTimerOne/TimerOne.cpp create mode 100644 libraries/EpoxyMockTimerOne/TimerOne.h diff --git a/CHANGELOG.md b/CHANGELOG.md index 8aea0a8..4bf7c98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # Changelog * Unreleased + * Add `EpoxyMockTimerOne` mock library for `TimerOne` + (https://github.com/PaulStoffregen/TimerOne). * 0.7 (2021-04-28) * Add `libraries/EpoxyMockDigitalWriteFast`, a simple mock library for `digitalWriteFast` (https://github.com/NicksonYap/digitalWriteFast) to diff --git a/libraries/EpoxyMockTimerOne/README.md b/libraries/EpoxyMockTimerOne/README.md new file mode 100644 index 0000000..e179a7e --- /dev/null +++ b/libraries/EpoxyMockTimerOne/README.md @@ -0,0 +1,40 @@ +# EpocyMockTimerOne Library + +A mock implementation of the `TimerOne` library +(https://github.com/PaulStoffregen/TimerOne) to allow code written against +that library to compile under EpoxyDuino. + +Since TimerThree (https://github.com/PaulStoffregen/TimerThree) has the exact +same API, we can use this mock for TimerThree for mocking purposes as well. + +## Usage + +Code written against `TimerOne` should compile without change with this mock +library. All methods are stubbed out with empty function bodies. + +```C++ +#include +#include +... + +void doSomething() { + ... +} + +void setup() { + Timer1.initialize(100); // do something every 100 micros + Timer1.attachInterrupt(doSomething); + ... +} + +void loop() { +} +``` + +Then add `EpoxyMockTimerOne` to the `ARDUINO_LIBS` in the EpoxyDuino `Makefile`: + +```make +APP_NAME := MyApp +ARDUINO_LIBS := EpocyMockTimerOne ... +include ../../../../EpoxyDuino.mk +``` diff --git a/libraries/EpoxyMockTimerOne/TimerOne.cpp b/libraries/EpoxyMockTimerOne/TimerOne.cpp new file mode 100644 index 0000000..7127b4f --- /dev/null +++ b/libraries/EpoxyMockTimerOne/TimerOne.cpp @@ -0,0 +1,10 @@ +/* + * MIT License + * Copyright (c) 2021 Brian T. Park + */ + +#include "TimerOne.h" + +void (*TimerOne::isrCallback)() = TimerOne::isrDefaultUnused; + +TimerOne Timer1; diff --git a/libraries/EpoxyMockTimerOne/TimerOne.h b/libraries/EpoxyMockTimerOne/TimerOne.h new file mode 100644 index 0000000..e99cf14 --- /dev/null +++ b/libraries/EpoxyMockTimerOne/TimerOne.h @@ -0,0 +1,73 @@ +/* + * MIT License + * Copyright (c) 2021 Brian T. Park + */ + +/** + * @file Simple mock implementation of the TimerOne library + * (https://github.com/PaulStoffregen/TimerOne) to allow code written against + * that library to compile under EpoxyDuino. + */ + +#ifndef EPOXY_MOCK_TIMER_ONE_H +#define EPOXY_MOCK_TIMER_ONE_H + +#include // uint8_t + +/** + * Mock implementation of the TimerOne class from the TimerOne library + * (https://github.com/PaulStoffregen/TimerOne). Since TimerThree + * (https://github.com/PaulStoffregen/TimerThree) has the exact same API, this + * class can be substituted for TimerThree for mocking purposes. + */ +class TimerOne { + public: + //------------------------------------------------------------------------- + // Configuration + //------------------------------------------------------------------------- + + void initialize(unsigned long microseconds=1000000) { + setPeriod(microseconds); + } + + void setPeriod(unsigned long /*microseconds*/) {} + + //------------------------------------------------------------------------- + // Run Control + //------------------------------------------------------------------------- + + void start() {} + void stop() {} + void restart() {} + void resume() {} + + //------------------------------------------------------------------------- + // PWM outputs + //------------------------------------------------------------------------- + + void setPwmDuty(char /*pin*/, unsigned int /*duty*/) {} + void pwm(char /*pin*/, unsigned int /*duty*/) {} + void pwm(char /*pin*/, unsigned int /*duty*/, + unsigned long /*microseconds*/) {} + void disablePwm(char /*pin*/) {} + + //------------------------------------------------------------------------- + // Interrupt Function + //------------------------------------------------------------------------- + + void attachInterrupt(void (*isr)()) { isrCallback = isr; } + + void attachInterrupt(void (*isr)(), unsigned long microseconds) { + if (microseconds > 0) setPeriod(microseconds); + attachInterrupt(isr); + } + + void detachInterrupt() {} + + static void (*isrCallback)(); // this is a static variable, not a function + static void isrDefaultUnused() {} +}; + +extern TimerOne Timer1; + +#endif From 32086b48812b1977b9f93f988c6b1113cd3d5178 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Wed, 16 Jun 2021 06:42:29 -0700 Subject: [PATCH 05/12] README.md: Fix typos; add EpoxyMockTimerOne --- README.md | 55 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 26df306..7d13427 100644 --- a/README.md +++ b/README.md @@ -25,11 +25,13 @@ if the sketch is `SampleTest/SampleTest.ino`, then the makefile should be `SampleTest/Makefile`. The sketch is compiled with just a `make` command. It produces an executable with a `.out` extension, for example, `SampleTest.out`. -Most hardware dependent functions are stubbed out (defined but don't do -anything) to allow the Arduino programs to compile. This may be sufficient for a -CI pipeline. For actual application development, I have started to build -a set of libraries within EpoxyDuino which emulate the versions that run the -actual hardware: +The `Serial` port object sends the output to the `STDOUT` and reads from the +`STDIN` of the Unix host environment. Most other hardware dependent +features (e.g. I2C, SPI, GPIO) are stubbed out (defined but don't do anything) +to allow the Arduino programs to compile. This may be sufficient for a CI +pipeline. For actual application development, I have started to build a set of +libraries within EpoxyDuino which emulate the versions that run the actual +hardware: * EpoxyFS: emulation of the ESP8266 LittleFS or ESP32 LITTLEFS * EpoxyEepromAvr: emulation of AVR-flavored `EEPROM` @@ -176,8 +178,10 @@ Arduino controller. If the Arduino program depends on additional Arduino libraries, they must be specified in the `Makefile` using the `ARDUINO_LIBS` parameter. For example, -this includes the [AUnit](https://github.com/bxparks/AUnit) library if it is at -the same level as EpoxyDuino: +the following includes the [AUnit](https://github.com/bxparks/AUnit), +[AceButton](https://github.com/bxparks/AceButton), and +[AceTime](https://github.com/bxparks/AceTime) libraries if they are installed at +the same directory level as EpoxyDuino: ``` APP_NAME := SampleTest @@ -185,11 +189,11 @@ ARDUINO_LIBS := AUnit AceButton AceTime include ../../EpoxyDuino/EpoxyDuino.mk ``` -The libraries are referred to by their base directory name (e.g. `AceButton`, -or `AceTime`) not the full path. By default, the `EpoxyDuino.mk` file will look +The libraries are referred to using their base directory name (e.g. `AceButton`, +or `AceTime`) not their full path. By default, the `EpoxyDuino.mk` file will look for these additional libraries at the following locations: -* `EPOXY_DUINO_DIR/..` - in other words, siblings to the `EpoxyDuino` install +* `EPOXY_DUINO_DIR/../` - in other words, siblings to the `EpoxyDuino` install directory (this assumes that EpoxyDuino was installed in the Arduino `libraries` directory as recommended above) * `EPOXY_DUINO_DIR/libraries/` - additional libraries provided by the EpoxyDuino @@ -428,6 +432,9 @@ $ CXX=clang++ make the `make` command, which causes `make` to set its internal `CXX` variable, which causes `EpoxyDuino.mk` to use `clang++` over the default `g++`.) +The `clang++` compiler will sometimes catch a different set of programming +errors. + ### Generated Source Code @@ -459,7 +466,7 @@ bar.cpp: bar.h generate_bar.sh The `*.o` files in `OJBS` are passed to the linker when the `app.out` binary file is created. -The `GENERATED` is not absolutely required, since the default rules already know +The `GENERATED` is not strictly required, since the default rules already know how to compile the `*.o` files from the `*.cpp` or `*.c` files. The primary effect of `GENERATED` currently is to cause the generated files to be removed when `make clean` is called. @@ -471,7 +478,7 @@ The `make clean` rule is predefined to remove all of the intermediate `*.o` files and `GENERATED` files that the `EpoxyDuino.mk` file knows about. Sometimes, we want to do additional clean up. For example, the EEPROM emulation libraries ([EpoxyEepromAvr](libraries/EpoxyEepromAvr) or -(EpoxyEepromEsp)[libraries/EpoxyEepromEsp]) will create a file in the current +[EpoxyEepromEsp](libraries/EpoxyEepromEsp)) will create a file in the current directory named `epoxyeepromdata` which stores the content of the emulated `EEPROM`. To remove such extra files, we can create a new `Makefile` target that performs the clean up, and add the name of the target to `MORE_CLEAN`. @@ -495,7 +502,7 @@ more_clean: This is very advanced. The Arduino ecosystem supports different hardware processors, architectures, and platforms. The software environment for a -specific hardware environment is called a Core. The environment provided by +specific hardware environment is called a "Core". The environment provided by EpoxyDuino resembles the AVR Core most closely because a lot of the API emulation code was borrowed from the AVR Core. However, EpoxyDuino does not provide an exact emulation of the AVR Core. In fact, I consider EpoxyDuino to be @@ -627,11 +634,11 @@ categorize these libraries in a sensible way in the context of EpoxyDuino, but here is my current attempt: * **Inherently Compatible Libraries**: - * Mostly algorithmic or have limited dependency on low-level Arduino API - (e.g. `millis()`, `micros()`, `delay()`, `F()`). + * Libraries that are mostly algorithmic often have limited dependency on + low-level Arduino API (e.g. `millis()`, `micros()`, `delay()`, `F()`). * If these have been written to be cross-platform across different Arduino hardware, then these should also automatically work under EpoxyDuino - without much (or any) modifications. + with little or no modifications. * **Emulation Libraries**. * Libraries for EpoxyDuino written specifically to emulate the functionality of an Arduino library, for example, using the filesystem or @@ -672,8 +679,7 @@ platforms. These libraries are designed partially or fully emulate the functionality a particular Arduino library in the Unix-like desktop environment using -EpoxyDuino. I have provide provide 3 such libraries within the EpoxyDuino -project: +EpoxyDuino. I have provided 3 such libraries within the EpoxyDuino project: * [libraries/EpoxyFS](libraries/EpoxyFS) * An implementation of a file system compatible with @@ -717,10 +723,13 @@ intended. This limitation may be sufficient for Continous Integration purposes. is included automatically by the `` file in EpoxyDuino. * It follows the same pattern as `Wire`, the header file provides only mock functions of the actual `SPI` library. -* [libaries/EpoxyMockDigitalWriteFast](libraries/EpoxyMockDigitalWriteFast) - * A simple mock for the `digitalWriteFast` library - (https://github.com/NicksonYap/digitalWriteFast) to allow code written +* [EpoxyMockDigitalWriteFast](libraries/EpoxyMockDigitalWriteFast) + * A simple mock of one of the `digitalWriteFast` libraries (e.g. + https://github.com/NicksonYap/digitalWriteFast) to allow code written against it to compile under EpoxyDuino. +* [EpoxyMockTimerOne](libraries/EpoxyMockTimerOne) + * A simple mock of the TimerOne (https://github.com/PaulStoffregen/TimerOne) + library. * EspMock (https://github.com/hsaturn/EspMock) * This is a separate project that provides various mocks for functions and libraries included with the ESP8266 and the ESP32 processors. @@ -784,10 +793,6 @@ $ ./SampleTest.out < /dev/null | less # works ## Feedback and Support -If you find this library useful, consider starring this project on GitHub. The -stars will let me prioritize the more popular libraries over the less popular -ones. - If you have any questions, comments and other support questions about how to use this library, please use the [GitHub Discussions](https://github.com/bxparks/EpoxyDuino/discussions) From 3361f773d7e8a3bb9af3fac3b52f350f30f6a480 Mon Sep 17 00:00:00 2001 From: Ben Wolsieffer Date: Tue, 13 Jul 2021 16:06:35 -0400 Subject: [PATCH 06/12] Add PlatformIO library.json Since the headers are now in a subdirectory, a library.json file is necessary to allow PlatformIO to find them. --- library.json | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 library.json diff --git a/library.json b/library.json new file mode 100644 index 0000000..60f34ca --- /dev/null +++ b/library.json @@ -0,0 +1,25 @@ +{ + "name": "EpoxyDuino", + "version": "0.7.0", + "description": "Compile and run Arduino programs natively on Linux, MacOS and FreeBSD.", + "keywords": [ + "unit-test", + "mock", + "arduino", + "native" + ], + "repository": { + "type": "git", + "url": "https://github.com/bxparks/EpoxyDuino.git" + }, + "authors": { + "name": "Brian Park" + }, + "license": "MIT", + "platforms": [ + "native" + ], + "build": { + "includeDir": "cores/epoxy" + } +} From 3cc5af175b6483659884e197060266877cc2a363 Mon Sep 17 00:00:00 2001 From: Ben Wolsieffer Date: Tue, 13 Jul 2021 15:51:49 -0400 Subject: [PATCH 07/12] Move stdin processing to yield() Before this patch, stdin is only read between calls to loop(). This causes problems when a program waits for serial input while calling yield() in a loop. Moving the stdin handling code to yield() fixes this problem and more closely matches real hardware behavior. Also, this patch checks the return value from read(), which fixes a compiler warning and allows null bytes to be read correctly. --- cores/epoxy/Arduino.cpp | 7 ++++++- cores/epoxy/main.cpp | 5 +---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/cores/epoxy/Arduino.cpp b/cores/epoxy/Arduino.cpp index c236c0b..db59a96 100644 --- a/cores/epoxy/Arduino.cpp +++ b/cores/epoxy/Arduino.cpp @@ -13,7 +13,7 @@ */ #include -#include // usleep() +#include // read(), STDIN_FILENO, usleep() #include // clock_gettime() #include "Arduino.h" @@ -22,6 +22,11 @@ // ----------------------------------------------------------------------- void yield() { + char c = '\0'; + if (read(STDIN_FILENO, &c, 1) == 1) { + Serial.insertChar(c); + } + usleep(1000); // prevents program from consuming 100% CPU } diff --git a/cores/epoxy/main.cpp b/cores/epoxy/main.cpp index db64a45..87b97e9 100644 --- a/cores/epoxy/main.cpp +++ b/cores/epoxy/main.cpp @@ -22,7 +22,7 @@ #include // SIGINT #include // exit() #include // perror() -#include // read() +#include // isatty(), STDIN_FILENO #include #include @@ -113,9 +113,6 @@ int unixhostduino_main(int /*argc*/, char** /*argv*/) { setup(); while (true) { - char c = '\0'; - read(STDIN_FILENO, &c, 1); - if (c) Serial.insertChar(c); loop(); yield(); } From a085771f09affd9cb0daff1bb14581b4e79957fe Mon Sep 17 00:00:00 2001 From: Brian Park Date: Thu, 15 Jul 2021 15:49:50 -0700 Subject: [PATCH 08/12] README.md: Add documentation for library.json, tagging it unsupported officially, see #31 --- CHANGELOG.md | 8 ++++++++ README.md | 10 ++++++++++ 2 files changed, 18 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4bf7c98..8291890 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,14 @@ * Unreleased * Add `EpoxyMockTimerOne` mock library for `TimerOne` (https://github.com/PaulStoffregen/TimerOne). + * Add `library.json` to support + [PlaformIO in Native + mode](https://docs.platformio.org/en/latest/platforms/native.html). (See + [PR #31](https://github.com/bxparks/EpoxyDuino/pull/31) by + https://github.com/lopsided98). + * Move code that pumps the `Serial` object from `unixhostduino_main()` + to `yield()`. Fix bug to allow correct handling of `NUL` byte in the + serial stream. (See [PR #32] by https://github.com/lopsided98). * 0.7 (2021-04-28) * Add `libraries/EpoxyMockDigitalWriteFast`, a simple mock library for `digitalWriteFast` (https://github.com/NicksonYap/digitalWriteFast) to diff --git a/README.md b/README.md index 7d13427..a66afc6 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,7 @@ for more details. * [Generated Source Code](#GeneratedSourceCode) * [Additional Clean Up](#AdditionalCleanUp) * [Alternate Arduino Core](#AlternateArduinoCore) + * [PlatformIO](#PlatformIO) * [Supported Arduino Features](#SupportedArduinoFeatures) * [Arduino Functions](#ArduinoFunctions) * [Serial Port Emulation](#SerialPortEmulation) @@ -529,6 +530,15 @@ EpoxyDuino provides the ability substitute a different Arduino API Core through * If not overridden by the provided Makefile, this is set to `$(EPOXY_DUINO_DIR)/cores/$(EPOXY_CORE)`. + +### PlatformIO + +The `library.json` file supports [PlaformIO in Native +mode](https://docs.platformio.org/en/latest/platforms/native.html). It was added +in [Issue #31](https://github.com/bxparks/EpoxyDuino/pull/31) (thanks +https://github.com/lopsided98). However, this functionality is *unsupported*. If +it becomes broken in the future, please send me a PR to fix it. + ## Supported Arduino Features From 50e83dd9c8023b7535529485a4238cbcbccaa400 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Thu, 5 Aug 2021 15:53:41 -0700 Subject: [PATCH 09/12] Repurpose 'EPOXY_CORE' make variable to specify the EPOXY_CORE_AVR or EPOXY_CORE_ESP8266 macro; merge ExpMock/cores/esp2866 into EpoxyDuino/cores/epoxy --- CHANGELOG.md | 8 + EpoxyDuino.mk | 75 ++++---- README.md | 63 ++++--- cores/epoxy/Arduino.cpp | 2 +- cores/epoxy/Arduino.h | 216 ++++++++++++++++------ cores/epoxy/ArduinoEsp8266.h | 280 +++++++++++++++++++++++++++++ cores/epoxy/Client.h | 58 ++++++ cores/epoxy/Esp.cpp | 7 + cores/epoxy/Esp.h | 53 ++++++ cores/epoxy/WMath.cpp | 38 ++-- cores/epoxy/pins_arduino_avr.h | 54 ++++++ cores/epoxy/pins_arduino_esp8266.h | 69 +++++++ 12 files changed, 799 insertions(+), 124 deletions(-) create mode 100644 cores/epoxy/ArduinoEsp8266.h create mode 100644 cores/epoxy/Client.h create mode 100644 cores/epoxy/Esp.cpp create mode 100644 cores/epoxy/Esp.h create mode 100644 cores/epoxy/pins_arduino_avr.h create mode 100644 cores/epoxy/pins_arduino_esp8266.h diff --git a/CHANGELOG.md b/CHANGELOG.md index 8291890..72132a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,14 @@ * Move code that pumps the `Serial` object from `unixhostduino_main()` to `yield()`. Fix bug to allow correct handling of `NUL` byte in the serial stream. (See [PR #32] by https://github.com/lopsided98). + * Repurpose the `EPOXY_CORE` make variable to be the name of the macro that + defines the target architecture. Currently, the valid options are: + * `EPOXY_CORE_AVR` (default) + * `EPOXY_CORE_ESP8266` + * Merge ESP8266-specific changes from + https://github.com/hsaturn/EspMock/cores/esp8266 into + EpoxyDuino/cores/epoxy, guarded by `EPOXY_CORE_ESP8266` macro. + * Add `map()`, `makeWord()` functions to `WMath.cpp`. * 0.7 (2021-04-28) * Add `libraries/EpoxyMockDigitalWriteFast`, a simple mock library for `digitalWriteFast` (https://github.com/NicksonYap/digitalWriteFast) to diff --git a/EpoxyDuino.mk b/EpoxyDuino.mk index 60d1a08..95b6a8b 100644 --- a/EpoxyDuino.mk +++ b/EpoxyDuino.mk @@ -10,28 +10,38 @@ # # The 2 required parameters are: # -# * APP_NAME: base name of the Arduino sketch file, -# e.g. 'Blink' not 'Blink.ino' -# * ARDUINO_LIBS: list of dependent Arduino libraries in sibling directories -# to EpoxyDuino (e.g. AUnit). The EpoxyDuino directory is -# automatically included. +# * APP_NAME +# * Base name of the Arduino sketch file, e.g. 'Blink' not 'Blink.ino' +# * ARDUINO_LIBS +# * List of dependent Arduino libraries in sibling directories to +# EpoxyDuino (e.g. AUnit). +# * The EpoxyDuino directory is automatically included. # # Optional parameters are: # -# * ARDUINO_LIB_DIRS: List of additional locations of Arduino libs, for -# example, $(arduino_ide_dir)/libraries, -# $(arduino_ide_dir)/hardware/arduino/avr/libraries, -# $(arduino_ide_dir)/portable/packages/arduino/hardware/avr/1.8.2/libraries. -# (The $(arduino_ide_dir) is an example temporary variable containing the -# install location of the Arduino IDE. It is not used by EpoxyDuino.mk.) -# * OBJS: Additional object (*.o) files needed by the binary -# * GENERATED: A list of files which are generated by a script, and therefore -# can be deleted by 'make clean' -# * MORE_CLEAN: Optional user-supplied make-target that performs -# additional cleanup (i.e. removing generated files or directories). -# * EPOXY_CORE: Select an alternate Arduino Core. Default 'epoxy'. -# * EPOXY_CORE_PATH: Select the alternate Core given by this full path. -# Default: $(EPOXY_DUINO_DIR)/cores/$(EPOXY_CORE). +# * ARDUINO_LIB_DIRS +# * List of additional locations of Arduino libs +# * For example, $(arduino_ide_dir)/libraries, +# $(arduino_ide_dir)/hardware/arduino/avr/libraries, +# $(arduino_ide_dir)/portable/packages/arduino/hardware/avr/1.8.2/libraries. +# * (The $(arduino_ide_dir) is an example temporary variable containing +# the install location of the Arduino IDE. It is not used by +# EpoxyDuino.mk.) +# * OBJS +# * Additional object (*.o) files needed by the binary +# * GENERATED +# * A list of files which are generated by a script, and therefore can be +# deleted by 'make clean' +# * MORE_CLEAN +# * Optional user-supplied make-target that performs additional cleanup +# (i.e. removing generated files or directories). +# * EPOXY_CORE +# * The C macro to select a specific core. Valid options are: +# * EPOXY_CORE_AVR (default) +# * EPOXY_CORE_ESP8266 +# * EPOXY_CORE_PATH +# * Select the alternate Core given by this full path. +# * Default: $(EPOXY_DUINO_DIR)/cores/epoxy # # Type 'make -n' to verify. # @@ -54,24 +64,13 @@ EPOXY_DUINO_PARENT_DIR := $(abspath $(EPOXY_DUINO_DIR)/..) # directory. ARDUINO_LIB_DIRS ?= -# Define the module that contains and other core API files. By -# default, the "epoxy" core is used which is based on the AVR core, with some -# extensions. The file lives in $(EPOXY_DUINO_DIR/cores/epoxy. -# -# Currently, only "epoxy" Core has been implemented. If additional predefined -# cores become supported in EpoxyDuino in $(EPOXY_DUINO_DIR)/cores/, then -# end-user can override EPOXY_CORE with another predefined core. For example, -# if I decide to implement a version of the Core that tries to emulate the -# ESP8266 and create the implementation files under -# $(EPOXY_DUINO_DIR)/cores/esp8266, then this variable could be set to -# "esp8266". -EPOXY_CORE ?= epoxy - -# This variable provides a big hammer that can override the Arduino Core -# supplied by EpoxyDuino with an externally provided Core that compatible with -# EpoxyDuino (e.g. EPOXY_CORE_PATH = -# $(EPOXY_DUINO_DIR)/../EspMock/cores/esp8266). -EPOXY_CORE_PATH ?= $(EPOXY_DUINO_DIR)/cores/$(EPOXY_CORE) +# C macro to select a specific core. Valid options are: +# EPOXY_CORE_AVR (default), EPOXY_CORE_ESP8266. +EPOXY_CORE ?= EPOXY_CORE_AVR + +# Define the directory where the and other core API files are +# located. The default is $(EPOXY_DUINO_DIR)/cores/epoxy. +EPOXY_CORE_PATH ?= $(EPOXY_DUINO_DIR)/cores/epoxy # Find the directory paths of the libraries listed in ARDUINO_LIBS by looking # under directory given by EPOXY_DUINO_LIB_DIR, the directory given by @@ -135,7 +134,7 @@ CPPFLAGS ?= # instead of Arduino.h so that files like 'compat.h' can determine the # compile-time environment without having to include . # Also define UNIX_HOST_DUINO for backwards compatibility. -CPPFLAGS += -D UNIX_HOST_DUINO -D EPOXY_DUINO +CPPFLAGS += -D UNIX_HOST_DUINO -D EPOXY_DUINO -D $(EPOXY_CORE) # Add the header files for the Core files. CPPFLAGS += -I$(EPOXY_CORE_PATH) # Add the header files for libraries. Old Arduino libraries place the header diff --git a/README.md b/README.md index a66afc6..7cc9a39 100644 --- a/README.md +++ b/README.md @@ -503,32 +503,55 @@ more_clean: This is very advanced. The Arduino ecosystem supports different hardware processors, architectures, and platforms. The software environment for a -specific hardware environment is called a "Core". The environment provided by -EpoxyDuino resembles the AVR Core most closely because a lot of the API -emulation code was borrowed from the AVR Core. However, EpoxyDuino does not -provide an exact emulation of the AVR Core. In fact, I consider EpoxyDuino to be -its own unique version of the Arduino API. +specific hardware environment is called a "Core". By default, the environment +provided by EpoxyDuino resembles the AVR Core most closely because a lot of the +API emulation code was borrowed from the AVR Core. There may be situations where an Arduino program is specifically meant to run -under a hardware platform other than an AVR processor. If we want to use -EpoxyDuino to compile that program under Linux/MacOS/FreeBSD, we must provide a -different Arduino Core API. For example, if your program is meant to run on an -ESP8266 or ESP32 using its WiFi network capabilities, you may need special APIs -to compile that program under EpoxyDuino. - -EpoxyDuino provides the ability substitute a different Arduino API Core through -2 Makefile variables: +under a hardware platform other than an AVR processor, for example, the ESP8266 +Core. EpoxyDuino provides the ability substitute a different Arduino API Core +through 2 Makefile variables: * `EPOXY_CORE` - * Use the core defined in the subdirectory under - `$(EPOXY_DUINO_DIR)/cores/`. - * By default, this variable defined to be `epoxy`, so - the core files are searched under `$(EPOXY_DUINO_DIR)/cores/epoxy/`. - * Currently `epoxy` is the only Core provided by the EpoxyDuino package. + * This Makefile variable defines the C-preprocessor macro which will be + defined through the `-D` flag through `-D $(EPOXY_CORE)`. + +There are currently 2 valid options for this Makefile variable: + +* `EPOXY_CORE_AVR` (default) + * Causes `Arduino.h` to emulate the Arduino AVR core. +* `EPOXY_CORE_ESP8266` + * Causes `Arduino.h` to emulate the ESP8266 Core. + +For example, setting the following in the `Makefile`: + +``` +EPOXY_CORE := EPOXY_CORE_ESP8266 +``` + +causes the `make` command to pass the `-D EPOXY_CORE_ESP8266` flag to the +compiler, which will activate any code that is guarded by: + +```C++ +#if defined(EPOXY_CORE_ESP8266) + ... +#endif +``` + +If the `EPOXY_CORE` make variable is insufficient (because the appropriate +changes have not been incorporated into `$(EPOXY_DUINO_DIR)/cores/epoxy/`, then +there is an even bigger hammer with the following make variable: + * `EPOXY_CORE_PATH` * Defines the full-path to the Arduino Core API files. - * If not overridden by the provided Makefile, this is set to - `$(EPOXY_DUINO_DIR)/cores/$(EPOXY_CORE)`. + +By default, this is set to `$(EPOXY_DUINO_DIR)/cores/epoxy`. You can create your +own set of Arduino API files in a directory of your choosing, and set this +make variable to point to these custom files: + +``` +EPOXY_CORE_PATH := {my_own_directory}/cores/mycore +``` ### PlatformIO diff --git a/cores/epoxy/Arduino.cpp b/cores/epoxy/Arduino.cpp index db59a96..26027de 100644 --- a/cores/epoxy/Arduino.cpp +++ b/cores/epoxy/Arduino.cpp @@ -63,7 +63,7 @@ void delayMicroseconds(unsigned int us) { } unsigned long pulseIn( - uint8_t /*pin*/, uint8_t /*state*/,unsigned long /*timeout*/) { + uint8_t /*pin*/, uint8_t /*state*/, unsigned long /*timeout*/) { return 0; } diff --git a/cores/epoxy/Arduino.h b/cores/epoxy/Arduino.h index 366faaa..4fc47a7 100644 --- a/cores/epoxy/Arduino.h +++ b/cores/epoxy/Arduino.h @@ -9,7 +9,15 @@ #ifndef EPOXY_DUINO_EPOXY_ARDUINO_H #define EPOXY_DUINO_EPOXY_ARDUINO_H +#include +#include +#include +#include +#include #include + +#include "WString.h" +#include "WCharacter.h" #include "Print.h" #include "StdioSerial.h" @@ -21,10 +29,27 @@ #define HIGH 0x1 #define LOW 0x0 -// Used by pinMode() -#define INPUT 0x0 -#define OUTPUT 0x1 -#define INPUT_PULLUP 0x2 +// Used by pinMode() and other GPIO functions. +#if defined(EPOXY_CORE_AVR) + #define INPUT 0x0 + #define OUTPUT 0x1 + #define INPUT_PULLUP 0x2 +#endif +#if defined(EPOXY_CORE_ESP8266) + #define INPUT 0x00 + #define INPUT_PULLUP 0x02 + #define INPUT_PULLDOWN_16 0x04 // PULLDOWN only possible for pin16 + #define OUTPUT 0x01 + #define OUTPUT_OPEN_DRAIN 0x03 + #define WAKEUP_PULLUP 0x05 + #define WAKEUP_PULLDOWN 0x07 + #define SPECIAL 0xF8 //uart0rx/tx uart1tx and hspi + #define FUNCTION_0 0x08 + #define FUNCTION_1 0x18 + #define FUNCTION_2 0x28 + #define FUNCTION_3 0x38 + #define FUNCTION_4 0x48 +#endif // Various math constants. #define PI 3.1415926535897932384626433832795 @@ -40,63 +65,107 @@ #define LSBFIRST 0 #define MSBFIRST 1 -#define CHANGE 1 -#define FALLING 2 -#define RISING 3 - -// Arbitrarily define the pin for the LED_BUILTIN -#define LED_BUILTIN 1 - -// Define a bunch of digital and analog pins -#define D0 0 -#define D1 1 -#define D2 2 -#define D3 3 -#define D4 4 -#define D5 5 -#define D6 6 -#define D7 7 -#define D8 8 -#define D9 9 -#define D10 10 -#define D11 11 -#define D12 12 -#define D13 13 -#define D14 14 -#define D15 15 -#define D16 16 -#define D17 17 -#define D18 18 -#define D19 19 - -#define A0 0 -#define A1 1 -#define A2 2 -#define A3 3 -#define A4 4 -#define A5 5 -#define A6 6 -#define A7 7 -#define A8 8 -#define A9 9 - -// Define pins used by I2C and SPI. -static const uint8_t SS = 1; -static const uint8_t MOSI = 2; -static const uint8_t MISO = 3; -static const uint8_t SCK = 4; -static const uint8_t SDA = 5; -static const uint8_t SCL = 6; +// Interrupt Modes +#if defined(EPOXY_CORE_AVR) + #define CHANGE 1 + #define FALLING 2 + #define RISING 3 +#endif +#if defined(EPOXY_CORE_ESP8266) + #define RISING 0x01 + #define FALLING 0x02 + #define CHANGE 0x03 + #define ONLOW 0x04 + #define ONHIGH 0x05 + #define ONLOW_WE 0x0C + #define ONHIGH_WE 0x0D +#endif + +#define DEFAULT 1 +#define EXTERNAL 0 + +// Timer stuff on ESP8266 +#if defined(EPOXY_CORE_ESP8266) + #define TIM_DIV1 0 //80MHz (80 ticks/us - 104857.588 us max) + #define TIM_DIV16 1 //5MHz (5 ticks/us - 1677721.4 us max) + #define TIM_DIV265 3 //312.5Khz (1 tick = 3.2us - 26843542.4 us max) + + //timer int_types + #define TIM_EDGE 0 + #define TIM_LEVEL 1 + + //timer reload values + #define TIM_SINGLE 0 //on interrupt routine you need to write a new value to start the timer again + #define TIM_LOOP 1 //on interrupt the counter will start with the same value again + + #define timer1_read() (T1V) + #define timer1_enabled() ((T1C & (1 << TCTE)) != 0) + #define timer1_interrupted() ((T1C & (1 << TCIS)) != 0) + + typedef void(*timercallback)(void); + + void timer1_isr_init(void); + void timer1_enable(uint8_t divider, uint8_t int_type, uint8_t reload); + void timer1_disable(void); + void timer1_attachInterrupt(timercallback userFunc); + void timer1_detachInterrupt(void); + void timer1_write(uint32_t ticks); //maximum ticks 8388607 + + // timer0 is a special CPU timer that has very high resolution but with + // limited control. + // it uses CCOUNT (ESP.GetCycleCount()) as the non-resetable timer counter + // it does not support divide, type, or reload flags + // it is auto-disabled when the compare value matches CCOUNT + // it is auto-enabled when the compare value changes + #define timer0_interrupted() (ETS_INTR_PENDING() & (_BV(ETS_COMPARE0_INUM))) + #define timer0_read() ((__extension__({uint32_t count;__asm__ __volatile__("esync; rsr %0,ccompare0":"=a" (count));count;}))) + #define timer0_write(count) __asm__ __volatile__("wsr %0,ccompare0; esync"::"a" (count) : "memory") + + void timer0_isr_init(void); + void timer0_attachInterrupt(timercallback userFunc); + void timer0_detachInterrupt(void); +#endif + +#if defined(EPOXY_CORE_AVR) + #define NOT_A_PIN 0 + #define NOT_A_PORT 0 +#endif +#if defined(EPOXY_CORE_ESP8266) + #define NOT_A_PIN -1 + #define NOT_A_PORT -1 +#endif +#define NOT_AN_INTERRUPT -1 +#define NOT_ON_TIMER 0 // Stub implementations #define interrupts() #define noInterrupts() +#define bit(b) (1UL << (b)) +#if defined(EPOXY_CORE_ESP8266) + #define _BV(b) (1UL << (b)) +#endif + +#define lowByte(w) ((uint8_t) ((w) & 0xff)) +#define highByte(w) ((uint8_t) ((w) >> 8)) + extern "C" { typedef bool boolean; typedef uint8_t byte; -typedef unsigned int word; +typedef uint16_t word; + +#if defined(EPOXY_CORE_ESP8266) + void ets_intr_lock(); + void ets_intr_unlock(); + + void preinit(void); + void init(void); + void initVariant(void); + + void optimistic_yield(uint32_t interval_us); + void esp_yield(void); +#endif void yield(); @@ -104,7 +173,13 @@ void pinMode(uint8_t pin, uint8_t mode); void digitalWrite(uint8_t pin, uint8_t val); int digitalRead(uint8_t pin); int analogRead(uint8_t pin); +void analogReference(uint8_t mode); void analogWrite(uint8_t pin, int val); +#if defined(EPOXY_CORE_ESP8266) + void analogWriteFreq(uint32_t freq); + void analogWriteResolution(int res); + void analogWriteRange(uint32_t range); +#endif unsigned long millis(); unsigned long micros(); @@ -116,6 +191,12 @@ unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout); void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val); uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder); +void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode); +void detachInterrupt(uint8_t interruptNum); +#if defined(EPOXY_CORE_ESP8266) + void attachInterruptArg(uint8_t pin, void (*)(void*), void* arg, int mode); +#endif + /** Provided in the client code's *.ino file. */ void setup(); @@ -134,5 +215,36 @@ int main(int argc, char** argv); long random(long); long random(long, long); void randomSeed(unsigned long); +long map(long, long, long, long, long); +uint16_t makeWord(uint16_t w); +uint16_t makeWord(byte h, byte l); +#if defined(EPOXY_CORE_ESP8266) + long secureRandom(long); + long secureRandom(long, long); +#endif + +#if defined(EPOXY_CORE_ESP8266) + void setTZ(const char* tz); + + void configTime(int timezone, int daylightOffset_sec, const char* server1, + const char* server2 = nullptr, const char* server3 = nullptr); + + void configTime(const char* tz, const char* server1, + const char* server2 = nullptr, const char* server3 = nullptr); + + // esp32 api compatibility + inline void configTzTime(const char* tz, const char* server1, + const char* server2 = nullptr, const char* server3 = nullptr) + { + configTime(tz, server1, server2, server3); + } +#endif + +#if defined(EPOXY_CORE_ESP8266) + #include "pins_arduino_esp8266.h" +#endif +#if defined(EPOXY_CORE_AVR) + #include "pins_arduino_avr.h" +#endif #endif diff --git a/cores/epoxy/ArduinoEsp8266.h b/cores/epoxy/ArduinoEsp8266.h new file mode 100644 index 0000000..0e7cf3f --- /dev/null +++ b/cores/epoxy/ArduinoEsp8266.h @@ -0,0 +1,280 @@ +/* + Arduino.h - Main include file for the Arduino SDK + Copyright (c) 2005-2013 Arduino Team. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define HIGH 0x1 +#define LOW 0x0 + +// GPIO FUNCTIONS +#define INPUT 0x00 +#define INPUT_PULLUP 0x02 +#define INPUT_PULLDOWN_16 0x04 // PULLDOWN only possible for pin16 +#define OUTPUT 0x01 +#define OUTPUT_OPEN_DRAIN 0x03 +#define WAKEUP_PULLUP 0x05 +#define WAKEUP_PULLDOWN 0x07 +#define SPECIAL 0xF8 //defaults to the usable BUSes uart0rx/tx uart1tx and hspi +#define FUNCTION_0 0x08 +#define FUNCTION_1 0x18 +#define FUNCTION_2 0x28 +#define FUNCTION_3 0x38 +#define FUNCTION_4 0x48 + +// Various math constants. +#define PI 3.1415926535897932384626433832795 +#define HALF_PI 1.5707963267948966192313216916398 +#define TWO_PI 6.283185307179586476925286766559 +#define DEG_TO_RAD 0.017453292519943295769236907684886 +#define RAD_TO_DEG 57.295779513082320876798154814105 +#define EULER 2.718281828459045235360287471352 + +#define SERIAL 0x0 +#define DISPLAY 0x1 + +#define LSBFIRST 0 +#define MSBFIRST 1 + +// Interrupt Modes +#define RISING 0x01 +#define FALLING 0x02 +#define CHANGE 0x03 +#define ONLOW 0x04 +#define ONHIGH 0x05 +#define ONLOW_WE 0x0C +#define ONHIGH_WE 0x0D + +#define DEFAULT 1 +#define EXTERNAL 0 + +//timer dividers +enum TIM_DIV_ENUM { + TIM_DIV1 = 0, //80MHz (80 ticks/us - 104857.588 us max) + TIM_DIV16 = 1, //5MHz (5 ticks/us - 1677721.4 us max) + TIM_DIV256 = 3 //312.5Khz (1 tick = 3.2us - 26843542.4 us max) +}; + + +//timer int_types +#define TIM_EDGE 0 +#define TIM_LEVEL 1 +//timer reload values +#define TIM_SINGLE 0 //on interrupt routine you need to write a new value to start the timer again +#define TIM_LOOP 1 //on interrupt the counter will start with the same value again + +#define timer1_read() (T1V) +#define timer1_enabled() ((T1C & (1 << TCTE)) != 0) +#define timer1_interrupted() ((T1C & (1 << TCIS)) != 0) + +typedef void(*timercallback)(void); + +void timer1_isr_init(void); +void timer1_enable(uint8_t divider, uint8_t int_type, uint8_t reload); +void timer1_disable(void); +void timer1_attachInterrupt(timercallback userFunc); +void timer1_detachInterrupt(void); +void timer1_write(uint32_t ticks); //maximum ticks 8388607 + +// timer0 is a special CPU timer that has very high resolution but with +// limited control. +// it uses CCOUNT (ESP.GetCycleCount()) as the non-resetable timer counter +// it does not support divide, type, or reload flags +// it is auto-disabled when the compare value matches CCOUNT +// it is auto-enabled when the compare value changes +#define timer0_interrupted() (ETS_INTR_PENDING() & (_BV(ETS_COMPARE0_INUM))) +#define timer0_read() ((__extension__({uint32_t count;__asm__ __volatile__("esync; rsr %0,ccompare0":"=a" (count));count;}))) +#define timer0_write(count) __asm__ __volatile__("wsr %0,ccompare0; esync"::"a" (count) : "memory") + +void timer0_isr_init(void); +void timer0_attachInterrupt(timercallback userFunc); +void timer0_detachInterrupt(void); + +#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt))) +#define radians(deg) ((deg)*DEG_TO_RAD) +#define degrees(rad) ((rad)*RAD_TO_DEG) +#define sq(x) ((x)*(x)) + +#define interrupts() +#define noInterrupts() + +// #define clockCyclesPerMicrosecond() ( F_CPU / 1000000L ) +#define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() ) +#define microsecondsToClockCycles(a) ( (a) * clockCyclesPerMicrosecond() ) + +#define lowByte(w) ((uint8_t) ((w) & 0xff)) +#define highByte(w) ((uint8_t) ((w) >> 8)) + +#define bitRead(value, bit) (((value) >> (bit)) & 0x01) +#define bitSet(value, bit) ((value) |= (1UL << (bit))) +#define bitClear(value, bit) ((value) &= ~(1UL << (bit))) +#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit)) + +// avr-libc defines _NOP() since 1.6.2 +#ifndef _NOP +#define _NOP() do { __asm__ volatile ("nop"); } while (0) +#endif + +#define bit(b) (1UL << (b)) +#define _BV(b) (1UL << (b)) + +typedef uint16_t word; +typedef bool boolean; +typedef uint8_t byte; + +void ets_intr_lock(); +void ets_intr_unlock(); + +void init(void); +void initVariant(void); + +void pinMode(uint8_t pin, uint8_t mode); +void digitalWrite(uint8_t pin, uint8_t val); +int digitalRead(uint8_t pin); +int analogRead(uint8_t pin); +void analogReference(uint8_t mode); +void analogWrite(uint8_t pin, int val); +void analogWriteMode(uint8_t pin, int val, bool openDrain); +void analogWriteFreq(uint32_t freq); +void analogWriteResolution(int res); +void analogWriteRange(uint32_t range); + +unsigned long millis(); +unsigned long micros(); +void delay(unsigned long ms); +void delayMicroseconds(unsigned int us); +unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout); +unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout); + +void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val); +uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder); + +void attachInterrupt(uint8_t pin, void (*)(void), int mode); +void detachInterrupt(uint8_t pin); +void attachInterruptArg(uint8_t pin, void (*)(void*), void* arg, int mode); + +void preinit(void); +void setup(void); +void loop(void); + +void yield(void); + +void optimistic_yield(uint32_t interval_us); + +#define _PORT_GPIO16 1 +#define digitalPinToPort(pin) (((pin)==16)?(_PORT_GPIO16):(0)) +#define digitalPinToBitMask(pin) (((pin)==16)?(1):(1UL << (pin))) +#define digitalPinToTimer(pin) (0) +#define portOutputRegister(port) (((port)==_PORT_GPIO16)?((volatile uint32_t*) &GP16O):((volatile uint32_t*) &GPO)) +#define portInputRegister(port) (((port)==_PORT_GPIO16)?((volatile uint32_t*) &GP16I):((volatile uint32_t*) &GPI)) +#define portModeRegister(port) (((port)==_PORT_GPIO16)?((volatile uint32_t*) &GP16E):((volatile uint32_t*) &GPE)) + +#define NOT_A_PIN -1 +#define NOT_A_PORT -1 +#define NOT_AN_INTERRUPT -1 +#define NOT_ON_TIMER 0 + +#ifdef __cplusplus +} // extern "C" +#endif + +// undefine stdlib's definitions when encountered, provide abs that supports floating point for C code +#ifndef __cplusplus +#undef abs +#define abs(x) ({ __typeof__(x) _x = (x); _x > 0 ? _x : -_x; }) +#undef round +#define round(x) ({ __typeof__(x) _x = (x); _x >= 0 ? (long)(_x + 0.5) : (long)(_x - 0.5); }) +#endif // ifndef __cplusplus + +// from this point onward, we need to configure the c++ environment +#ifdef __cplusplus + +#include +#include +#include + +using std::min; +using std::max; +using std::round; +using std::isinf; +using std::isnan; + +// Use float-compatible stl abs() and round(), we don't use Arduino macros to avoid issues with the C++ libraries +using std::abs; +using std::round; + +#define _min(a,b) ({ decltype(a) _a = (a); decltype(b) _b = (b); _a < _b? _a : _b; }) +#define _max(a,b) ({ decltype(a) _a = (a); decltype(b) _b = (b); _a > _b? _a : _b; }) + +uint16_t makeWord(uint16_t w); +uint16_t makeWord(byte h, byte l); + +#define word(...) makeWord(__VA_ARGS__) + +unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L); +unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L); + +void tone(uint8_t _pin, unsigned int frequency, unsigned long duration = 0); +void tone(uint8_t _pin, int frequency, unsigned long duration = 0); +void tone(uint8_t _pin, double frequency, unsigned long duration = 0); +void noTone(uint8_t _pin); + +// WMath prototypes +long random(long); +long random(long, long); +void randomSeed(unsigned long); +long secureRandom(long); +long secureRandom(long, long); +long map(long, long, long, long, long); + +void setTZ(const char* tz); + +void configTime(int timezone, int daylightOffset_sec, const char* server1, + const char* server2 = nullptr, const char* server3 = nullptr); + +void configTime(const char* tz, const char* server1, + const char* server2 = nullptr, const char* server3 = nullptr); + +// esp32 api compatibility +inline void configTzTime(const char* tz, const char* server1, + const char* server2 = nullptr, const char* server3 = nullptr) +{ + configTime(tz, server1, server2, server3); +} + +// Everything we expect to be implicitly loaded for the sketch +#include + +#include "WCharacter.h" +#include "WString.h" + +#include "StdioSerial.h" +#include "Esp.h" + +#endif // __cplusplus + +#include "pins_arduino.h" + diff --git a/cores/epoxy/Client.h b/cores/epoxy/Client.h new file mode 100644 index 0000000..23b741a --- /dev/null +++ b/cores/epoxy/Client.h @@ -0,0 +1,58 @@ +/* + Borrowed from esp8266/hardware/esp8266/2.7.4/cores/esp8266/Client.h. + + Client.h - Base class that provides Client + Copyright (c) 2011 Adrian McEwen. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef EPOXY_DUINO_CLIENT_H +#define EPOXY_DUINO_CLIENT_H + +#if defined(EPOXY_CORE_ESP8266) + +#include "Print.h" +#include "Stream.h" +#include "IPAddress.h" + +class Client: public Stream { + + public: + virtual int connect(IPAddress ip, uint16_t port) = 0; + virtual int connect(const char *host, uint16_t port) = 0; + virtual size_t write(uint8_t) override = 0; + virtual size_t write(const uint8_t *buf, size_t size) override = 0; + virtual int available() override = 0; + virtual int read() override = 0; + /* virtual int read(uint8_t *buf, size_t size) override = 0; */ + virtual int peek() override = 0; + virtual void flush() override = 0; + virtual void stop() = 0; + virtual uint8_t connected() = 0; + virtual operator bool() = 0; + protected: + /* does not compile + uint8_t* rawIPAddress(IPAddress& addr) { + return addr.raw_address(); + } + const uint8_t* rawIPAddress(const IPAddress& addr) { + return addr.raw_address(); + } + */ +}; + +#endif +#endif diff --git a/cores/epoxy/Esp.cpp b/cores/epoxy/Esp.cpp new file mode 100644 index 0000000..c1e75ba --- /dev/null +++ b/cores/epoxy/Esp.cpp @@ -0,0 +1,7 @@ +#if defined(EPOXY_CORE_ESP8266) + +#include "Esp.h" + +EspClass ESP; + +#endif diff --git a/cores/epoxy/Esp.h b/cores/epoxy/Esp.h new file mode 100644 index 0000000..38630cc --- /dev/null +++ b/cores/epoxy/Esp.h @@ -0,0 +1,53 @@ +#ifndef EPOXY_DUINO_ESP_H +#define EPOXY_DUINO_ESP_H + +#if defined(EPOXY_CORE_ESP8266) + +#include +#include +#include + +class _FLOAT +{ + public: + int digits; + float val; +}; + +class EspClass +{ + public: + EspClass() { + gettimeofday(&start, NULL); + } + + void reset() {}; + + // Very ugly approximation, this is freeStack + unsigned long getFreeHeap() { + int i; + static int* h=40000+&i; + return h-&i; + } + + uint32_t getCpuFreqMHZ() { return 80; } + + uint32_t getCycleCount() { + struct timeval now; + gettimeofday(&now, NULL); + return getCpuFreqMHZ() + * ((now.tv_sec-start.tv_sec)*1000000+(now.tv_usec-start.tv_usec)); + } + + private: + struct timeval start; +}; + +class Serial_ : public Stream +{ +}; + +extern EspClass ESP; + +#endif +#endif diff --git a/cores/epoxy/WMath.cpp b/cores/epoxy/WMath.cpp index ea13bdc..c7fc4ee 100644 --- a/cores/epoxy/WMath.cpp +++ b/cores/epoxy/WMath.cpp @@ -27,23 +27,35 @@ extern "C" { } void randomSeed(unsigned long seed) { - if(seed != 0) { - srand(seed); - } + if (seed != 0) { + srand(seed); + } } long random(long howbig) { - if(howbig == 0) { - return 0; - } - uint32_t val = rand(); - return val % howbig; + if (howbig == 0) { + return 0; + } + uint32_t val = rand(); + return val % howbig; } long random(long howsmall, long howbig) { - if(howsmall >= howbig) { - return howsmall; - } - long diff = howbig - howsmall; - return random(diff) + howsmall; + if (howsmall >= howbig) { + return howsmall; + } + long diff = howbig - howsmall; + return random(diff) + howsmall; +} + +long map(long x, long in_min, long in_max, long out_min, long out_max) { + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; +} + +uint16_t makeWord(unsigned int w) { + return w; +} + +uint16_t makeWord(unsigned char h, unsigned char l) { + return (h << 8) | l; } diff --git a/cores/epoxy/pins_arduino_avr.h b/cores/epoxy/pins_arduino_avr.h new file mode 100644 index 0000000..484d023 --- /dev/null +++ b/cores/epoxy/pins_arduino_avr.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2019 Brian T. Park + * MIT License + */ + +#ifndef EPOXY_DUINO_PINS_ARDUINO_AVR_H +#define EPOXY_DUINO_PINS_ARDUINO_AVR_H + +// Arbitrarily define the pin for the LED_BUILTIN +#define LED_BUILTIN 1 + +// Define a bunch of digital pins. +#define D0 0 +#define D1 1 +#define D2 2 +#define D3 3 +#define D4 4 +#define D5 5 +#define D6 6 +#define D7 7 +#define D8 8 +#define D9 9 +#define D10 10 +#define D11 11 +#define D12 12 +#define D13 13 +#define D14 14 +#define D15 15 +#define D16 16 +#define D17 17 +#define D18 18 +#define D19 19 + +// Define some arbitary analog pins. +#define A0 0 +#define A1 1 +#define A2 2 +#define A3 3 +#define A4 4 +#define A5 5 +#define A6 6 +#define A7 7 +#define A8 8 +#define A9 9 + +// Define some arbitrary pins used by I2C and SPI. +static const uint8_t SS = 1; +static const uint8_t MOSI = 2; +static const uint8_t MISO = 3; +static const uint8_t SCK = 4; +static const uint8_t SDA = 5; +static const uint8_t SCL = 6; + +#endif diff --git a/cores/epoxy/pins_arduino_esp8266.h b/cores/epoxy/pins_arduino_esp8266.h new file mode 100644 index 0000000..ca88a3e --- /dev/null +++ b/cores/epoxy/pins_arduino_esp8266.h @@ -0,0 +1,69 @@ +/* + Taken from esp8266/hardware/esp8266/2.7.4/variants/d1/pins_arduino.h. + + pins_arduino.h - Pin definition functions for Arduino + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2007 David A. Mellis + Modified for ESP8266 platform by Ivan Grokhotkov, 2014-2015. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + $Id: wiring.h 249 2007-02-03 16:52:51Z mellis $ +*/ + +#ifndef EPOXY_DUINO_PINS_ARDUINO_ESP8266_H +#define EPOXY_DUINO_PINS_ARDUINO_ESP8266_H + +#define PIN_WIRE_SDA (4) +#define PIN_WIRE_SCL (5) + +static const uint8_t SDA = PIN_WIRE_SDA; +static const uint8_t SCL = PIN_WIRE_SCL; + +//new ESP-12E GPIO2 +#define LED_BUILTIN 2 + +static const uint8_t D0 = 3; +static const uint8_t D1 = 1; +static const uint8_t D2 = 16; +static const uint8_t D3 = 5; +static const uint8_t D4 = 4; +static const uint8_t D5 = 14; +static const uint8_t D6 = 12; +static const uint8_t D7 = 13; +static const uint8_t D8 = 0; +static const uint8_t D9 = 2; +static const uint8_t D10 = 15; +static const uint8_t D11 = 13; +static const uint8_t D12 = 12; +static const uint8_t D13 = 14; +static const uint8_t D14 = 4; +static const uint8_t D15 = 5; + +// Define some arbitary analog pins. +static const uint8_t A0 = 0; +static const uint8_t A1 = 1; +static const uint8_t A2 = 2; +static const uint8_t A3 = 3; +static const uint8_t A4 = 4; +static const uint8_t A5 = 5; +static const uint8_t A6 = 6; +static const uint8_t A7 = 7; +static const uint8_t A8 = 8; +static const uint8_t A9 = 9; + +#endif From d249cc8dccfdf7b7583fe2f91a75107e166d59b5 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Fri, 6 Aug 2021 16:19:17 -0700 Subject: [PATCH 10/12] pgmspace.h: Add macro for snprintf_P(), fixes #33 --- cores/epoxy/pgmspace.h | 1 + 1 file changed, 1 insertion(+) diff --git a/cores/epoxy/pgmspace.h b/cores/epoxy/pgmspace.h index 7dc881d..c7635ba 100644 --- a/cores/epoxy/pgmspace.h +++ b/cores/epoxy/pgmspace.h @@ -37,6 +37,7 @@ #define strchr_P strchr #define strrchr_P strrchr #define memcpy_P memcpy +#define snprintf_P snprintf #define vsnprintf_P vsnprintf #endif From 5b4386dc13247daf7fb25411c37f9ff5ec1b472c Mon Sep 17 00:00:00 2001 From: Brian Park Date: Sun, 8 Aug 2021 14:50:13 -0700 Subject: [PATCH 11/12] Bump version to 0.8 --- CHANGELOG.md | 11 +++++++---- README.md | 2 +- cores/epoxy/Arduino.h | 14 +++++++++----- library.json | 2 +- 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 72132a2..27c3688 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog * Unreleased +* 0.8 (2021-08-08) * Add `EpoxyMockTimerOne` mock library for `TimerOne` (https://github.com/PaulStoffregen/TimerOne). * Add `library.json` to support @@ -11,10 +12,12 @@ * Move code that pumps the `Serial` object from `unixhostduino_main()` to `yield()`. Fix bug to allow correct handling of `NUL` byte in the serial stream. (See [PR #32] by https://github.com/lopsided98). - * Repurpose the `EPOXY_CORE` make variable to be the name of the macro that - defines the target architecture. Currently, the valid options are: - * `EPOXY_CORE_AVR` (default) - * `EPOXY_CORE_ESP8266` + * **Breaking** Repurpose the `EPOXY_CORE` make variable to be the name of + the macro that defines the target architecture so that `Arduino.h` brings + in definitions which target specific Arduino platforms: + * The valid options are: + * `EPOXY_CORE_AVR` (default) + * `EPOXY_CORE_ESP8266` * Merge ESP8266-specific changes from https://github.com/hsaturn/EspMock/cores/esp8266 into EpoxyDuino/cores/epoxy, guarded by `EPOXY_CORE_ESP8266` macro. diff --git a/README.md b/README.md index 7cc9a39..861518b 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ The disadvantages are: environments (e.g. 16-bit `int` versus 32-bit `int`, or 32-bit `long` versus 64-bit `long`). -**Version**: 0.7 (2021-04-28) +**Version**: 0.8 (2021-08-08) **Changelog**: See [CHANGELOG.md](CHANGELOG.md) diff --git a/cores/epoxy/Arduino.h b/cores/epoxy/Arduino.h index 4fc47a7..e2f1d66 100644 --- a/cores/epoxy/Arduino.h +++ b/cores/epoxy/Arduino.h @@ -2,13 +2,21 @@ * Copyright (c) 2019 Brian T. Park * MIT License * - * Parts derived from the Arduino SDK + * Parts derived from the AVR Arduino SDK version 1.8.3 + * (https://github.com/arduino/ArduinoCore-avr). * Copyright (c) 2005-2013 Arduino Team + * + * Parts derived from the ESP8266 Arduino SDK version 2.7.4 + * (https://github.com/esp8266/Arduino). */ #ifndef EPOXY_DUINO_EPOXY_ARDUINO_H #define EPOXY_DUINO_EPOXY_ARDUINO_H +// xx.yy.zz => xxyyzz (without leading 0) +#define EPOXY_DUINO_VERSION 800 +#define EPOXY_DUINO_VERSION_STRING "0.8.0" + #include #include #include @@ -21,10 +29,6 @@ #include "Print.h" #include "StdioSerial.h" -// xx.yy.zz => xxyyzz (without leading 0) -#define EPOXY_DUINO_VERSION 700 -#define EPOXY_DUINO_VERSION_STRING "0.7.0" - // Used by digitalRead() and digitalWrite() #define HIGH 0x1 #define LOW 0x0 diff --git a/library.json b/library.json index 60f34ca..0468721 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "EpoxyDuino", - "version": "0.7.0", + "version": "0.8.0", "description": "Compile and run Arduino programs natively on Linux, MacOS and FreeBSD.", "keywords": [ "unit-test", From 9f6078b7e9810395db83f146c3134c7805cd6085 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Sun, 8 Aug 2021 14:52:33 -0700 Subject: [PATCH 12/12] README.md: Fix missing ')' --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 861518b..b13107f 100644 --- a/README.md +++ b/README.md @@ -538,8 +538,8 @@ compiler, which will activate any code that is guarded by: #endif ``` -If the `EPOXY_CORE` make variable is insufficient (because the appropriate -changes have not been incorporated into `$(EPOXY_DUINO_DIR)/cores/epoxy/`, then +If the `EPOXY_CORE` make variable is insufficient (e.g. because the appropriate +changes have not been incorporated into `$(EPOXY_DUINO_DIR)/cores/epoxy/`), then there is an even bigger hammer with the following make variable: * `EPOXY_CORE_PATH`