diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000000..0dc70545a0 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,92 @@ +name: Continuous Integration (CI) + +on: + push: + + pull_request: + branches: [ develop ] + +jobs: + build: + strategy: + fail-fast: false + matrix: + arch: [Esp8266, Host, Esp32, Rp2040] + variant: [""] + os: [ubuntu-latest, windows-latest] + include: + - arch: Esp32 + variant: esp32s2 + os: ubuntu-latest + - arch: Esp32 + variant: esp32s2 + os: windows-latest + - arch: Esp32 + variant: esp32c3 + os: ubuntu-latest + - arch: Esp32 + variant: esp32c3 + os: windows-latest + exclude: + - os: windows-latest + arch: Host + + continue-on-error: ${{ matrix.arch == 'Host' && matrix.os == 'windows-latest' }} + + concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-${{ toJson(matrix) }} + cancel-in-progress: true + + runs-on: ${{ matrix.os }} + + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Setup SMING_HOME for Ubuntu + if: ${{ matrix.os == 'ubuntu-latest' }} + run: | + echo "CI_BUILD_DIR=$GITHUB_WORKSPACE" >> $GITHUB_ENV + echo "SMING_HOME=$GITHUB_WORKSPACE/Sming" >> $GITHUB_ENV + - name: Setup SMING_HOME for Windows + if: ${{ matrix.os == 'windows-latest' }} + run: | + echo ("CI_BUILD_DIR=" + $env:GITHUB_WORKSPACE) >> $env:GITHUB_ENV + $env:SMING_HOME = Join-Path $env:GITHUB_WORKSPACE "Sming" + echo ("SMING_HOME=" + $env:SMING_HOME) >> $env:GITHUB_ENV + - name: Install Sming Framework on Ubuntu + if: ${{ matrix.os == 'ubuntu-latest' }} + env: + SMING_ARCH: ${{matrix.arch}} + SMING_SOC: ${{matrix.variant}} + run: | + ./Tools/install.sh $(echo "$SMING_ARCH" | tr '[:upper:]' '[:lower:]') + - name: Install Sming Framework on Windows + if: ${{ matrix.os == 'windows-latest' }} + env: + SMING_ARCH: ${{matrix.arch}} + SMING_SOC: ${{matrix.variant}} + run: | + Tools/ci/setenv.ps1 + Tools/install.cmd "$env:SMING_ARCH".ToLower() + - name: Install Ninja + uses: seanmiddleditch/gha-setup-ninja@master + - name: Build and Test for ${{matrix.arch}} on Ubuntu + env: + SMING_ARCH: ${{matrix.arch}} + SMING_SOC: ${{matrix.variant}} + CLANG_FORMAT: clang-format-8 + if: ${{ matrix.os == 'ubuntu-latest' }} + run: | + source $SMING_HOME/../Tools/export.sh + $CLANG_FORMAT --version + ./Tools/ci/build.sh + - name: Build and Test for ${{matrix.arch}} on Windows + env: + SMING_ARCH: ${{matrix.arch}} + SMING_SOC: ${{matrix.variant}} + if: ${{ matrix.os == 'windows-latest' }} + run: | + $env:PYTHON_PATH=$(python -c "import sys, os.path; print(os.path.dirname(sys.executable))") + Tools/ci/setenv.ps1 + Tools/ci/build.cmd + diff --git a/.github/workflows/coverity-scan.yml b/.github/workflows/coverity-scan.yml new file mode 100644 index 0000000000..1d65dd2aaf --- /dev/null +++ b/.github/workflows/coverity-scan.yml @@ -0,0 +1,73 @@ +name: Coverity Scan + +on: + # Push to master MUST be evaluated + # Pushing to develop only on condition + push: + branches: [ master, develop ] + # Pull requests to master MUST be evaluated + pull_request: + branches: [ master ] + # Run the workflow once a month + schedule: + - cron: '30 1 1 * *' + +jobs: + scan: +# concurrency: +# group: ${{ github.head_ref || github.run_id }} +# cancel-in-progress: true + + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Check if we are allowed to scan + env: + BRANCH: ${{github.ref_name}} + run: | + CHECK_SCA=0 + if [[ "$BRANCH" == "master" ]]; then + CHECK_SCA=1; + elif [[ $BRANCH == "develop" ]]; then + if [[ "$GITHUB_EVENT_NAME" == "schedule" ]]; then + CHECK_SCA=1; + elif [[ "$GITHUB_EVENT_NAME" == "push" ]]; then + COMMIT_MSG=$(git log --format=%B -n 1) + if [[ "$COMMIT_MSG" == *"[scan:coverity]"* ]]; then + CHECK_SCA=1; + fi + fi + fi + + echo "CHECK_SCA=$CHECK_SCA" >> $GITHUB_ENV + - name: Setup SMING_HOME for Ubuntu + if: ${{ env.CHECK_SCA == 1 }} + run: | + echo "CI_BUILD_DIR=$GITHUB_WORKSPACE" >> $GITHUB_ENV + echo "SMING_HOME=$GITHUB_WORKSPACE/Sming" >> $GITHUB_ENV + echo "SMING_ARCH=Host" >> $GITHUB_ENV + - name: Install Sming Framework on Ubuntu + if: ${{ env.CHECK_SCA == 1 }} + run: | + ./Tools/install.sh $(echo "$SMING_ARCH" | tr '[:upper:]' '[:lower:]') + - name: Install Ninja + if: ${{ env.CHECK_SCA == 1 }} + uses: seanmiddleditch/gha-setup-ninja@master + - name: Run Coverity Scan + if: ${{ env.CHECK_SCA == 1 }} + env: + COVERITY_SCAN_TOKEN: ${{secrets.COVERITY_SCAN_TOKEN}} + run: | + source $SMING_HOME/../Tools/export.sh + export MAKE_PARALLEL="make -j$(nproc)" + export COVERITY_SCAN_BUILD_COMMAND_PREPEND="cd $SMING_HOME" + cat > /tmp/secrets.sh + $SMING_HOME/Arch/Host/Tools/ci/coverity-scan.sh + - name: Archive scan log + if: ${{ env.CHECK_SCA == 1 }} + uses: actions/upload-artifact@v3 + with: + name: coverity-scan-report + path: Sming/cov-int/scm_log.txt diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000000..0d4abe542a --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,42 @@ +name: Release + +on: + workflow_dispatch: + push: + tags: + - '[0-9]+.[0-9]+.[0-9]+' + +# TODO: check if the tag is pointing to the tip of the master branch + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: trstringer/manual-approval@v1 + if: ${{ github.ref_type == 'tag' }} + with: + secret: ${{ github.TOKEN }} + approvers: slaff + - name: Install xmlstarlet + if: ${{ github.ref_type == 'tag' }} + run: sudo apt-get install -y xmlstarlet + - name: Build docs + if: ${{ github.ref_type == 'tag' }} + run: | + Tools/install.sh doc + make -C docs html + zip -r sming-docs.zip docs/build/html + - name: Release New Version + if: ${{ github.ref_type == 'tag' }} + env: + SMING_ARCH: Host + RELEASE_TOKEN: ${{secrets.RELEASE_TOKEN}} + CI_REPO_NAME: ${{github.repository}} + CHOCO_TOKEN: ${{secrets.CHOKO_TOKEN}} + run: | + export CI_BUILD_DIR="$GITHUB_WORKSPACE" + export SMING_HOME="$GITHUB_WORKSPACE/Sming" + make -C $SMING_HOME submodules + cat > /tmp/secrets.sh + Tools/ci/deploy.sh ${{github.ref_name}} \ No newline at end of file diff --git a/.github/workflows/pull-request.yml b/.github/workflows/spelling-check.yml similarity index 89% rename from .github/workflows/pull-request.yml rename to .github/workflows/spelling-check.yml index 2ab7d91ddf..0edeb0080e 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/spelling-check.yml @@ -1,10 +1,9 @@ -# Run whenever a PR is generated or updated. - -name: Pull Request Checks +name: Spelling Check on: pull_request: - + branches: [ develop ] + jobs: code-spell: diff --git a/.gitmodules b/.gitmodules index f2d502425f..7607e1ac02 100644 --- a/.gitmodules +++ b/.gitmodules @@ -57,6 +57,10 @@ path = Sming/Components/libyuarel url = https://github.com/jacketizer/libyuarel.git ignore = dirty +[submodule "lwip"] + path = Sming/Components/lwip/lwip + url = https://github.com/lwip-tcpip/lwip + ignore = dirty [submodule "mqtt-codec"] path = Sming/Components/mqtt-codec url = https://github.com/slaff/mqtt-codec.git @@ -126,10 +130,6 @@ # `Host` Components # -[submodule "Host.lwip"] - path = Sming/Arch/Host/Components/lwip/lwip - url = https://github.com/lwip-tcpip/lwip - ignore = dirty [submodule "seriallib"] path = Sming/Arch/Host/Components/SerialLib/seriallib url = https://github.com/imabot2/serialib.git @@ -157,6 +157,22 @@ path = Sming/Libraries/Adafruit_BusIO url = https://github.com/adafruit/Adafruit_BusIO ignore = dirty +[submodule "Libraries.Adafruit_GFX"] + path = Sming/Libraries/Adafruit_GFX + url = https://github.com/adafruit/Adafruit-GFX-Library + ignore = dirty +[submodule "Libraries.Adafruit_ILI9341"] + path = Sming/Libraries/Adafruit_ILI9341 + url = https://github.com/adafruit/Adafruit_ILI9341 + ignore = dirty +[submodule "Libraries.Adafruit_NeoPixel"] + path = Sming/Libraries/Adafruit_NeoPixel + url = https://github.com/adafruit/Adafruit_NeoPixel + ignore = dirty +[submodule "Libraries.Adafruit_PCD8544"] + path = Sming/Libraries/Adafruit_PCD8544 + url = https://github.com/adafruit/Adafruit-PCD8544-Nokia-5110-LCD-library + ignore = dirty [submodule "Libraries.Adafruit_Sensor"] path = Sming/Libraries/Adafruit_Sensor url = https://github.com/adafruit/Adafruit_Sensor @@ -173,6 +189,10 @@ path = Sming/Libraries/Adafruit_VL53L0X url = https://github.com/adafruit/Adafruit_VL53L0X.git ignore = dirty +[submodule "Libraries.AnimatedGIF"] + path = Sming/Libraries/AnimatedGIF/AnimatedGIF + url = https://github.com/bitbank2/AnimatedGIF.git + ignore = dirty [submodule "Libraries.ArduinoFFT"] path = Sming/Libraries/ArduinoFFT url = https://github.com/kosme/arduinoFFT.git @@ -229,6 +249,10 @@ path = Sming/Libraries/jerryscript url = https://github.com/slaff/Sming-jerryscript.git ignore = dirty +[submodule "Libraries.IOControl"] + path = Sming/Libraries/IOControl + url = https://github.com/mikee47/IOControl + ignore = dirty [submodule "Libraries.IR"] path = Sming/Libraries/IR url = https://github.com/markszabo/IRremoteESP8266.git diff --git a/README.md b/README.md index 83ab9aee4e..c659b0941d 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Sming is [open source](LICENSE), modular and supports [multiple architectures](h [![Backers](https://opencollective.com/Sming/backers/badge.svg)](#financial-contributions) [![Sponsors](https://opencollective.com/Sming/sponsors/badge.svg)](#financial-contributions) [![Download](https://img.shields.io/badge/download-~1.7M-orange.svg)](https://github.com/SmingHub/Sming/releases/latest) -[![Build](https://travis-ci.org/SmingHub/Sming.svg?branch=develop)](https://travis-ci.org/SmingHub/Sming) +[![Build](https://github.com/SmingHub/Sming/actions/workflows/ci.yml/badge.svg)](https://github.com/SmingHub/Sming/actions/workflows/ci.yml) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/23ff16f8d550440787125b0d25ba7ada)](https://www.codacy.com/gh/SmingHub/Sming/dashboard?utm_source=github.com&utm_medium=referral&utm_content=SmingHub/Sming&utm_campaign=Badge_Grade) [![Coverity Badge](https://img.shields.io/coverity/scan/12007.svg)](https://scan.coverity.com/projects/sminghub-sming) @@ -29,7 +29,7 @@ You can also try Sming without installing anything locally. We have an [interact The purpose of Sming is to simplify the creation of embedded applications. The documentation will help you get started in no time. -- [**Documentation for version 4.5.0**](https://sming.readthedocs.io/en/stable) - current stable version. +- [**Documentation for version 4.6.0**](https://sming.readthedocs.io/en/stable) - current stable version. - [Documentation for version 4.2.x](https://sming.readthedocs.io/en/4.2.2) - Long Term Support (LTS) version. - [Documentation for latest](https://sming.readthedocs.io/en/latest) - development version. @@ -37,7 +37,7 @@ The purpose of Sming is to simplify the creation of embedded applications. The d ### Stable -- [Sming V4.5.0](https://github.com/SmingHub/Sming/releases/tag/4.5.0) - great new features, performance and stability improvements. +- [Sming V4.6.0](https://github.com/SmingHub/Sming/releases/tag/4.6.0) - great new features, performance and stability improvements. ### Long Term Support (LTS) diff --git a/Sming/Arch/Esp32/Components/driver/include/driver/hw_timer.h b/Sming/Arch/Esp32/Components/driver/include/driver/hw_timer.h index be15811eb3..49de03e797 100644 --- a/Sming/Arch/Esp32/Components/driver/include/driver/hw_timer.h +++ b/Sming/Arch/Esp32/Components/driver/include/driver/hw_timer.h @@ -12,7 +12,17 @@ #include #include -#include +#include + +#ifdef CONFIG_ESP_TIMER_IMPL_TG0_LAC +#include +#else +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif #define HW_TIMER_BASE_CLK APB_CLK_FREQ @@ -117,17 +127,34 @@ uint32_t hw_timer1_read(void); * *************************************/ -constexpr uint32_t HW_TIMER2_CLK = 1000000; - -extern "C" int64_t esp_timer_get_time(void); +#if CONFIG_ESP_TIMER_IMPL_TG0_LAC +#define HW_TIMER2_CLK 2000000U +#define HW_TIMER2_INDEX 0 +#elif defined(CONFIG_IDF_TARGET_ESP32S2) +#define HW_TIMER2_CLK 80000000U +#define HW_TIMER2_INDEX +#elif defined(CONFIG_IDF_TARGET_ESP32C3) +#define HW_TIMER2_CLK 16000000U +#define HW_TIMER2_INDEX 0 +#elif defined(CONFIG_IDF_TARGET_ESP32S3) +#define HW_TIMER2_CLK 16000000U +#define HW_TIMER2_INDEX 0 +#else +_Static_assert(false, "ESP32 Unsupported timer"); +#endif /** * @brief Read current timer2 value * @retval uint32_t */ -__forceinline uint32_t hw_timer2_read(void) +__forceinline static uint32_t hw_timer2_read(void) { - return esp_timer_get_time(); +#if CONFIG_ESP_TIMER_IMPL_TG0_LAC + return REG_READ(TIMG_LACTLO_REG(HW_TIMER2_INDEX)); +#else + systimer_ll_counter_snapshot(HW_TIMER2_INDEX); + return systimer_ll_get_counter_value_low(HW_TIMER2_INDEX); +#endif } #define NOW() hw_timer2_read() @@ -139,3 +166,7 @@ __forceinline uint32_t hw_timer2_read(void) void hw_timer_init(void); /** @} */ + +#ifdef __cplusplus +} +#endif diff --git a/Sming/Arch/Esp32/Components/driver/uart.cpp b/Sming/Arch/Esp32/Components/driver/uart.cpp index 78a14e48c2..6808f46636 100644 --- a/Sming/Arch/Esp32/Components/driver/uart.cpp +++ b/Sming/Arch/Esp32/Components/driver/uart.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include namespace @@ -151,36 +152,6 @@ smg_uart_t* get_physical(smg_uart_t* uart) return uart; } -bool realloc_buffer(SerialBuffer*& buffer, size_t new_size) -{ - if(buffer != nullptr) { - if(new_size == 0) { - smg_uart_disable_interrupts(); - delete buffer; - buffer = nullptr; - smg_uart_restore_interrupts(); - return true; - } - - return buffer->resize(new_size) == new_size; - } - - if(new_size == 0) { - return true; - } - - // Avoid allocating in SPIRAM - auto mem = heap_caps_malloc(sizeof(SerialBuffer), MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL); - auto new_buf = new(mem) SerialBuffer; - if(new_buf != nullptr && new_buf->resize(new_size) == new_size) { - buffer = new_buf; - return true; - } - - delete new_buf; - return false; -} - /** @brief UART interrupt service routine * @note both UARTS share the same ISR, although UART1 only supports transmit */ @@ -315,51 +286,6 @@ void smg_uart_set_callback(smg_uart_t* uart, smg_uart_callback_t callback, void* } } -size_t smg_uart_resize_rx_buffer(smg_uart_t* uart, size_t new_size) -{ - if(smg_uart_rx_enabled(uart)) { - realloc_buffer(uart->rx_buffer, new_size); - } - return smg_uart_rx_buffer_size(uart); -} - -size_t smg_uart_rx_buffer_size(smg_uart_t* uart) -{ - return uart != nullptr && uart->rx_buffer != nullptr ? uart->rx_buffer->getSize() : 0; -} - -size_t smg_uart_resize_tx_buffer(smg_uart_t* uart, size_t new_size) -{ - if(smg_uart_tx_enabled(uart)) { - realloc_buffer(uart->tx_buffer, new_size); - } - return smg_uart_tx_buffer_size(uart); -} - -size_t smg_uart_tx_buffer_size(smg_uart_t* uart) -{ - return uart != nullptr && uart->tx_buffer != nullptr ? uart->tx_buffer->getSize() : 0; -} - -int smg_uart_peek_char(smg_uart_t* uart) -{ - return uart != nullptr && uart->rx_buffer ? uart->rx_buffer->peekChar() : -1; -} - -int smg_uart_rx_find(smg_uart_t* uart, char c) -{ - if(uart == nullptr || uart->rx_buffer == nullptr) { - return -1; - } - - return uart->rx_buffer->find(c); -} - -int smg_uart_peek_last_char(smg_uart_t* uart) -{ - return uart != nullptr && uart->rx_buffer != nullptr ? uart->rx_buffer->peekLastChar() : -1; -} - size_t smg_uart_read(smg_uart_t* uart, void* buffer, size_t size) { if(!smg_uart_rx_enabled(uart) || buffer == nullptr || size == 0) { @@ -425,7 +351,7 @@ void smg_uart_start_isr(smg_uart_t* uart) dev->conf1.val = 0; if(smg_uart_rx_enabled(uart)) { - uart_ll_set_rxfifo_full_thr(dev, 120); + uart_ll_set_rxfifo_full_thr(dev, RX_FIFO_FULL_THRESHOLD); uart_ll_set_rx_tout(dev, 10); /* @@ -686,7 +612,7 @@ smg_uart_t* smg_uart_init_ex(const smg_uart_config_t& cfg) auto txBufferSize = cfg.tx_size; if(smg_uart_rx_enabled(uart)) { - if(!realloc_buffer(uart->rx_buffer, rxBufferSize)) { + if(!smg_uart_realloc_buffer(uart->rx_buffer, rxBufferSize)) { delete uart; return nullptr; } @@ -696,7 +622,7 @@ smg_uart_t* smg_uart_init_ex(const smg_uart_config_t& cfg) } if(smg_uart_tx_enabled(uart)) { - if(!realloc_buffer(uart->tx_buffer, txBufferSize)) { + if(!smg_uart_realloc_buffer(uart->tx_buffer, txBufferSize)) { delete uart->rx_buffer; delete uart; return nullptr; @@ -729,7 +655,7 @@ smg_uart_t* smg_uart_init_ex(const smg_uart_config_t& cfg) uart_ll_set_tx_idle_num(dev, 0); // Bottom 8 bits identical to esp8266 - dev->conf0.val = (dev->conf0.val & 0xFFFFFF00) | cfg.config; + dev->conf0.val = (dev->conf0.val & 0xFFFFFF00) | cfg.format; smg_uart_set_baudrate(uart, cfg.baudrate); smg_uart_flush(uart); @@ -764,19 +690,44 @@ void smg_uart_uninit(smg_uart_t* uart) delete uart; } -smg_uart_t* smg_uart_init(uint8_t uart_nr, uint32_t baudrate, uint32_t config, smg_uart_mode_t mode, uint8_t tx_pin, - size_t rx_size, size_t tx_size) +void smg_uart_set_format(smg_uart_t* uart, smg_uart_format_t format) { - smg_uart_config_t cfg = {.uart_nr = uart_nr, - .tx_pin = tx_pin, - .rx_pin = UART_PIN_DEFAULT, - .mode = mode, - .options = _BV(UART_OPT_TXWAIT), - .baudrate = baudrate, - .config = config, - .rx_size = rx_size, - .tx_size = tx_size}; - return smg_uart_init_ex(cfg); + uart = get_physical(uart); + if(uart == nullptr) { + return; + } + smg_uart_config_format_t fmt{.val = format}; + auto dev = getDevice(uart->uart_nr); + uart_ll_set_data_bit_num(dev, uart_word_length_t(fmt.bits)); + uart_ll_set_parity(dev, uart_parity_t(fmt.parity)); + uart_ll_set_stop_bits(dev, uart_stop_bits_t(fmt.stop_bits)); +} + +bool smg_uart_intr_config(smg_uart_t* uart, const smg_uart_intr_config_t* config) +{ + uart = get_physical(uart); + if(uart == nullptr || config == nullptr) { + return false; + } + + auto dev = getDevice(uart->uart_nr); + if(smg_uart_rx_enabled(uart)) { + uint8_t full_threshold; + if(uart->rx_buffer == nullptr) { + // Setting this to 0 results in lockup as the interrupt never clears + full_threshold = TRange(1, UART_RXFIFO_FULL_THRHD).clip(config->rxfifo_full_thresh); + } else { + full_threshold = RX_FIFO_FULL_THRESHOLD; + } + uart_ll_set_rxfifo_full_thr(dev, full_threshold); + uart_ll_set_rx_tout(dev, TRange(0, UART_RX_TOUT_THRHD).clip(config->rx_timeout_thresh)); + } + + if(smg_uart_tx_enabled(uart)) { + uart_ll_set_txfifo_empty_thr(dev, TRange(0, UART_TXFIFO_EMPTY_THRHD).clip(config->txfifo_empty_intr_thresh)); + } + + return true; } void smg_uart_swap(smg_uart_t* uart, int tx_pin) diff --git a/Sming/Arch/Esp32/Components/esp32/component.mk b/Sming/Arch/Esp32/Components/esp32/component.mk index b60596d355..affffe905e 100644 --- a/Sming/Arch/Esp32/Components/esp32/component.mk +++ b/Sming/Arch/Esp32/Components/esp32/component.mk @@ -43,6 +43,7 @@ SDK_INCDIRS := \ esp_rom/include/$(ESP_VARIANT) \ esp_rom/include \ $(ESP_VARIANT)/include \ + esp_ringbuf/include \ esp_timer/include \ soc/include \ soc/$(ESP_VARIANT)/include \ @@ -101,6 +102,7 @@ SDK_COMPONENTS := \ esp_ipc \ esp_pm \ esp_rom \ + esp_ringbuf \ esp_system \ esp_timer \ espcoredump \ diff --git a/Sming/Arch/Esp32/Components/esp32/src/startup.cpp b/Sming/Arch/Esp32/Components/esp32/src/startup.cpp index 8c8bf99b7b..48a89348c3 100644 --- a/Sming/Arch/Esp32/Components/esp32/src/startup.cpp +++ b/Sming/Arch/Esp32/Components/esp32/src/startup.cpp @@ -19,55 +19,21 @@ #include #include -#ifndef DISABLE_NETWORK -#include -#ifndef DISABLE_WIFI -#include -#include -#endif -#endif - extern void init(); extern esp_event_loop_handle_t sming_create_event_loop(); +extern void esp_network_initialise(); namespace { -#ifndef DISABLE_WIFI -esp_event_handler_t wifiEventHandler; - -/* - * Initialise NVS which IDF WiFi uses to store configuration parameters. - */ -void esp_init_nvs() -{ - esp_err_t ret = nvs_flash_init(); - if(ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { - ESP_ERROR_CHECK(nvs_flash_erase()); - ret = nvs_flash_init(); - } - ESP_ERROR_CHECK(ret); -} - -/* - * Initialise default WiFi stack - */ -void esp_init_wifi() -{ - esp_netif_init(); - if(wifiEventHandler != nullptr) { - ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, wifiEventHandler, nullptr)); - ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, wifiEventHandler, nullptr)); - } - wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); - ESP_ERROR_CHECK(esp_wifi_init(&cfg)); -} -#endif - void main(void*) { - assert(esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, true) == ESP_OK); - assert(esp_task_wdt_add(NULL) == ESP_OK); - assert(esp_task_wdt_status(NULL) == ESP_OK); + auto err = esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, true); + (void)err; + assert(err == ESP_OK); + err = esp_task_wdt_add(nullptr); + assert(err == ESP_OK); + err = esp_task_wdt_status(nullptr); + assert(err == ESP_OK); hw_timer_init(); @@ -77,8 +43,7 @@ void main(void*) auto loop = sming_create_event_loop(); #ifndef DISABLE_WIFI - esp_init_nvs(); - esp_init_wifi(); + esp_network_initialise(); #endif System.initialize(); @@ -94,18 +59,6 @@ void main(void*) } // namespace -/* - * Called from WiFi event implementation constructor. - * Cannot register directly as event queue hasn't been created yet. - * NOTE: May only be called once. - */ -void wifi_set_event_handler_cb(esp_event_handler_t eventHandler) -{ -#ifndef DISABLE_WIFI - wifiEventHandler = eventHandler; -#endif -} - extern void sming_create_task(TaskFunction_t); extern "C" void app_main(void) diff --git a/Sming/Arch/Esp32/Components/libc/src/replacements.c b/Sming/Arch/Esp32/Components/libc/src/replacements.c index 768f09ee11..0cef65db14 100644 --- a/Sming/Arch/Esp32/Components/libc/src/replacements.c +++ b/Sming/Arch/Esp32/Components/libc/src/replacements.c @@ -26,7 +26,7 @@ ssize_t WRAP(_read_r)(struct _reent* r, int fd, void* dst, size_t size) return -1; } -size_t WRAP(putc)(char c) +size_t WRAP(putchar)(char c) { return m_putc(c); } diff --git a/Sming/Arch/Esp32/Core/SPI.cpp b/Sming/Arch/Esp32/Core/SPI.cpp deleted file mode 100644 index f6d8316b03..0000000000 --- a/Sming/Arch/Esp32/Core/SPI.cpp +++ /dev/null @@ -1,451 +0,0 @@ -/**** - * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. - * Created 2015 by Skurydin Alexey - * http://github.com/SmingHub/Sming - * All files of the Sming Core are provided under the LGPL v3 license. - * - * SPI.cpp - * - * Created on: Mar 2, 2016 - * Author: harry-boe - * - * Some code is derived from: - * David Ogilvy (MetalPhreak) - * - ****/ - -#include "SPI.h" -#include -#undef FLAG_ATTR -#define FLAG_ATTR(TYPE) -#define typeof decltype -#include -#include -#include -#include - -// define the static singleton -SPIClass SPI; - -using SpiDevice = volatile spi_dev_t; - -namespace -{ -const SpiPins defaultPins[] = { - {6, 7, 8, SPI_PIN_DEFAULT}, - {14, 12, 13, SPI_PIN_DEFAULT}, - {18, 19, 23, SPI_PIN_DEFAULT}, -}; - -// Used internally to calculate optimum SPI speed -struct SpiPreDiv { - unsigned freq; - unsigned prescale; - unsigned divisor; -}; - -/** - * @brief Wait until SPI has finished any current transaction - */ -__forceinline void spi_wait(SpiDevice& dev) -{ - while(dev.cmd.usr) { - // - } -} - -/** - * @brief Initiate an SPI user transaction - */ -__forceinline void spi_send(SpiDevice& dev, unsigned num_bits) -{ - spi_ll_set_mosi_bitlen(&dev, num_bits); - spi_ll_set_miso_bitlen(&dev, num_bits); - dev.cmd.usr = true; -} - -/** - * @brief Configure SPI mode parameters for clock edge and clock polarity. - * @param device - * @param mode - * - * Mode Clock Polarity (CPOL) Clock Phase (CPHA) - * SPI_MODE0 0 0 - * SPI_MODE1 0 1 - * SPI_MODE2 1 0 - * SPI_MODE3 1 1 - */ -void spi_mode(SpiDevice& dev, uint8_t mode) -{ - spi_ll_master_set_mode(&dev, mode); - -#ifdef SPI_DEBUG - debug_i("[SPI] spi_mode(mode %x) cpha %X, cpol %X)", mode, mode & 0x0F, mode & 0xF0); -#endif -} - -/** - * @brief Setup the byte order for shifting data out of buffer - * @param MSBFIRST 1 - * Data is sent out starting with Bit31 and down to Bit0 - * LSBFIRST 0 - * Data is sent out starting with the lowest BYTE, from MSB to LSB - * 0xABCDEFGH would be sent as 0xGHEFCDAB - */ -void spi_byte_order(SpiDevice& dev, uint8_t byte_order) -{ -#ifdef SPI_DEBUG - debug_i("[SPI] spi_byte_order(byte_order %u)", byte_order); -#endif - -// No HAL definition for this -#if SOC_ESP32 || SOC_ESP32S2 - dev.user.rd_byte_order = (byte_order == MSBFIRST); - dev.user.wr_byte_order = (byte_order == MSBFIRST); -#else -// No definition in datasheet for esp32-c3, perhaps it's just missing? -#warning "SPI byte order unsupported" -#endif -} - -/** - * @brief Calculate the closest prescale value for a given frequency and clock-divider - * @param apbFreq APB CPU frequency, in Hz - * @param freq target SPI bus frequency, in Hz - * @param div divisor value to use - * @retval SpiPreDiv contains resulting frequency, prescaler and divisor values - */ -SpiPreDiv calculateSpeed(unsigned apbFreq, unsigned freq, unsigned div) -{ - SpiPreDiv prediv; - unsigned pre = apbFreq / (freq * div); - if(pre == 0) { - pre = 1; - } - unsigned n = pre * div; - while(true) { - prediv.freq = apbFreq / n; - if(prediv.freq <= freq) { - break; - } - ++pre; - n += div; - } - prediv.prescale = pre; - prediv.divisor = div; - -#ifdef SPI_DEBUG - debug_i("[SPI] calculateSpeed(freq %u, pre %u, div %u)", freq, pre, div); -#endif - - return prediv; -} - -/** @brief Check speed settings and perform any pre-calculation required - * @param speed IN: requested bus frequency, OUT: Modified settings with prescale values - * @note - * The algorithm is testing with clock dividers 2,3 and 5 to find the best pre-divider - * The resulting clock frequency is not 100% accurate but delivers result within 5% - * - * It is guaranteed that the frequency will not exceed the given target - */ -void checkSpeed(SPISpeed& speed, unsigned apbFreq) -{ - SpiPreDiv prediv; - - // If we're not running at max then need to determine appropriate prescale values - if(speed.frequency >= apbFreq) { - // Use maximum speed - prediv.freq = apbFreq; - prediv.prescale = 0; - prediv.divisor = 0; - speed.regVal = SPI_CLK_EQU_SYSCLK; - } else { - prediv = calculateSpeed(apbFreq, speed.frequency, 2); - if(prediv.freq != speed.frequency) { - // Use whichever divisor gives the highest frequency - SpiPreDiv pd3 = calculateSpeed(apbFreq, speed.frequency, 3); - SpiPreDiv pd5 = calculateSpeed(apbFreq, speed.frequency, 5); - if(pd3.freq > prediv.freq || pd5.freq > prediv.freq) { - prediv = (pd3.freq > pd5.freq) ? pd3 : pd5; - } - } - - // We have prescale and divisor values, now get regVal so we don't need to do this every time prepare() is called - decltype(spi_dev_t::clock) reg{{ - .clkcnt_l = 0, - .clkcnt_h = prediv.divisor / 2, - .clkcnt_n = prediv.divisor - 1, - .clkdiv_pre = prediv.prescale - 1, - }}; - speed.regVal = reg.val; - } - - debug_i("[SPI] APB freq = %u, pre = %u, div = %u, target freq = %u, actual = %u", apbFreq, prediv.prescale, - prediv.divisor, speed.frequency, prediv.freq); -} - -uint32_t getApbFrequency() -{ - constexpr uint32_t DIV_MHZ{1000000}; - rtc_cpu_freq_config_t conf; - rtc_clk_cpu_freq_get_config(&conf); - return (conf.freq_mhz >= 80) ? (80 * DIV_MHZ) : ((conf.source_freq_mhz * DIV_MHZ) / conf.div); -} - -void spi_set_clock(SpiDevice& dev, SPISpeed& speed) -{ - // Clock register value is never 0, so indicates it hasn't been calculated - if(speed.regVal == 0) { - checkSpeed(speed, getApbFrequency()); - } else { -#ifdef SPI_DEBUG - debug_i("[SPI] spi_set_clock(%u)", speed.frequency); -#endif - } - - dev.clock.val = speed.regVal; -} - -const spi_signal_conn_t& getBusInfo(SpiBus busId) -{ - return spi_periph_signal[unsigned(busId) - 1]; -} - -SpiDevice& getDevice(SpiBus busId) -{ - return *getBusInfo(busId).hw; -} - -struct BusState { - bool assigned : 1; -}; - -BusState busState[SOC_SPI_PERIPH_NUM]; - -BusState& getBusState(SpiBus busId) -{ - return busState[unsigned(busId) - 1]; -} - -} // namespace - -bool SPIClass::setup(SpiBus busId, SpiPins pins) -{ - if(busId < SpiBus::MIN || busId > SpiBus::MAX) { - debug_e("[SPI] Invalid bus"); - return false; - } - - if(getBusState(busId).assigned) { - debug_e("[SPI] Bus #%u already assigned", busId); - return false; - } - - this->busId = busId; - this->pins = pins; - return true; -} - -bool SPIClass::begin() -{ - if(busId < SpiBus::MIN || busId > SpiBus::MAX) { - debug_e("[SPI] Invalid bus"); - return false; - } - - auto& state = getBusState(busId); - if(state.assigned) { - debug_e("[SPI] Bus #%u already assigned", busId); - return false; - } - - auto& bus = getBusInfo(busId); - periph_ll_enable_clk_clear_rst(bus.module); - - auto& dev = getDevice(busId); - - // Initialise bus - spi_ll_master_init(&dev); - spi_ll_clear_int_stat(&dev); - - // - spi_ll_enable_mosi(&dev, true); - spi_ll_enable_miso(&dev, true); - spi_ll_set_half_duplex(&dev, false); - - spi_ll_set_dummy(&dev, 0); - spi_ll_set_command_bitlen(&dev, 0); - spi_ll_set_addr_bitlen(&dev, 0); - - // Not using any auto. chip selects - spi_ll_master_select_cs(&dev, -1); - - auto& defPins = defaultPins[unsigned(busId) - 1]; - - // Clock pin - if(pins.sck == SPI_PIN_DEFAULT) { - pins.sck = defPins.sck; - } - pinMode(pins.sck, OUTPUT); - gpio_matrix_out(pins.sck, bus.spiclk_out, false, false); - - // MISO - if(pins.miso == SPI_PIN_DEFAULT) { - pins.miso = defPins.miso; - } - pinMode(pins.miso, INPUT); - gpio_matrix_in(pins.miso, bus.spiq_in, false); - - // MOSI - if(pins.mosi == SPI_PIN_DEFAULT) { - pins.mosi = defPins.mosi; - } - pinMode(pins.mosi, OUTPUT); - gpio_matrix_out(pins.mosi, bus.spid_out, false, false); - - debug_i("[SPI] SCK = %u, MISO = %u, MOSI = %u", pins.sck, pins.miso, pins.mosi); - - // Clock - - // TODO: Framework needs to consider how to manage system clock changes - // addApbChangeCallback(this, [](void* arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb) { - // auto cls = static_cast(arg); - // auto& dev = cls->bus.dev; - // if(ev_type == APB_BEFORE_CHANGE) { - // while(dev.cmd.usr) { - // // - // } - // } else { - // setClock(cls->speed, new_apb); - // } - // }); - - checkSpeed(SPIDefaultSettings.speed, getApbFrequency()); - prepare(SPIDefaultSettings); - - state.assigned = true; - return true; -} - -void SPIClass::end() -{ - if(busId < SpiBus::MIN || busId > SpiBus::MAX) { - return; - } - - auto& state = getBusState(busId); - if(!state.assigned) { - return; - } - - auto& info = getBusInfo(busId); - periph_ll_disable_clk_set_rst(info.module); - - state.assigned = false; -} - -uint32_t SPIClass::transfer32(uint32_t data, uint8_t bits) -{ - auto& dev = getDevice(busId); - - spi_wait(dev); - - // copy data to W0 -#if SOC_ESP32 || SOC_ESP32S2 - if(dev.user.wr_byte_order) { - dev.data_buf[0] = data << (32 - bits); - } else -#endif - { - dev.data_buf[0] = data; - } - - spi_send(dev, bits); - spi_wait(dev); - - auto res = dev.data_buf[0]; -#if SOC_ESP32 || SOC_ESP32S2 - if(dev.user.rd_byte_order) { - res >>= (32 - bits); - } -#endif - return res; -} - -uint8_t SPIClass::read8() -{ - auto& dev = getDevice(busId); - - spi_wait(dev); - - dev.data_buf[0] = 0x00; - - spi_send(dev, 8); - spi_wait(dev); - - auto res = dev.data_buf[0]; -#if SOC_ESP32 || SOC_ESP32S2 - if(dev.user.rd_byte_order) { - res >>= 24; - } -#endif - return res; -} - -void SPIClass::transfer(uint8_t* buffer, size_t numberBytes) -{ - constexpr size_t BLOCKSIZE{64}; // the max length of the ESP SPI_W0 registers - - auto& dev = getDevice(busId); - - unsigned bufIndx = 0; - - unsigned blocks = ((numberBytes - 1) / BLOCKSIZE) + 1; -#ifdef SPI_DEBUG - unsigned total = blocks; -#endif - - // loop number of blocks - while(blocks--) { - // get full BLOCKSIZE or number of remaining bytes - auto bufLength = std::min(numberBytes - bufIndx, BLOCKSIZE); - -#ifdef SPI_DEBUG - debug_i("[SPI] Write/Read Block %u total %u bytes", total - blocks, bufLength); -#endif - - spi_wait(dev); - - // copy the registers starting from last index position - if(IS_ALIGNED(buffer)) { - memcpy((void*)dev.data_buf, &buffer[bufIndx], ALIGNUP4(bufLength)); - } else { - uint32_t wordBuffer[BLOCKSIZE / 4]; - memcpy(wordBuffer, &buffer[bufIndx], bufLength); - memcpy((void*)dev.data_buf, wordBuffer, ALIGNUP4(bufLength)); - } - - spi_send(dev, bufLength * 8); - spi_wait(dev); - - // copy the registers starting from last index position - memcpy(&buffer[bufIndx], (void*)dev.data_buf, bufLength); - - bufIndx += bufLength; - } -} - -void SPIClass::prepare(SPISettings& settings) -{ -#ifdef SPI_DEBUG - debug_i("[SPI] prepare()"); - settings.print("settings"); -#endif - - auto& dev = getDevice(busId); - - spi_set_clock(dev, settings.speed); - spi_byte_order(dev, settings.byteOrder); - spi_mode(dev, settings.dataMode); -} diff --git a/Sming/Arch/Esp32/Core/SPI.h b/Sming/Arch/Esp32/Core/SPI.h deleted file mode 100644 index 1ef1f3cd22..0000000000 --- a/Sming/Arch/Esp32/Core/SPI.h +++ /dev/null @@ -1,108 +0,0 @@ -/**** - * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. - * Created 2015 by Skurydin Alexey - * http://github.com/SmingHub/Sming - * All files of the Sming Core are provided under the LGPL v3 license. - * - * SPI.h - * - * Based on Arduino-esp32 code - * - * https://github.com/espressif/arduino-esp32/blob/master/libraries/SPI/src/SPI.h - * https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-spi.h - */ - -/** @defgroup hw_spi SPI Hardware support - * @brief Provides hardware SPI support - */ - -#pragma once - -#include "SPIBase.h" -#include "SPISettings.h" -#include - -//#define SPI_DEBUG 1 - -// for compatibility when porting from Arduino -#define SPI_HAS_TRANSACTION 0 - -static constexpr uint8_t SPI_PIN_DEFAULT{0xff}; - -/** - * @brief Hardware SPI object - * @addtogroup hw_spi - * @{ - */ - -/** - * @brief Identifies bus selection - */ -enum class SpiBus { - INVALID = 0, - MIN = 1, - SPI1 = 1, - FSPI = 1, // Attached to the flash (can use the same data lines but different SS) - SPI2 = 2, - HSPI = 2, // Normally mapped to pins 12 - 15, but can be matrixed to any pins -#if SOC_SPI_PERIPH_NUM > 2 - SPI3 = 3, - VSPI = 3, // Normally attached to pins 5, 18, 19 and 23, but can be matrixed to any pins -#endif - MAX = SOC_SPI_PERIPH_NUM, -#ifdef SOC_ESP32C3 - DEFAULT = SPI1, -#else - DEFAULT = VSPI, -#endif -}; - -/** - * @brief SPI pin connections - */ -struct SpiPins { - uint8_t sck{SPI_PIN_DEFAULT}; - uint8_t miso{SPI_PIN_DEFAULT}; - uint8_t mosi{SPI_PIN_DEFAULT}; - uint8_t ss{SPI_PIN_DEFAULT}; -}; - -class SPIClass : public SPIBase -{ -public: - SPIClass(const SPIClass&) = delete; - SPIClass& operator=(const SPIClass&) = delete; - - SPIClass(SpiBus id = SpiBus::DEFAULT) : busId(id) - { - } - - SPIClass(SpiBus id, SpiPins pins) : busId(id), pins(pins) - { - } - - /** - * @brief Alternative to defining bus and pin set in constructor. - * Use this method to change global `SPI` instance setup. - * - * IMPORTANT: Must be called *before* begin(). - */ - bool setup(SpiBus id, SpiPins pins); - - bool begin() override; - void end() override; - uint8_t read8() override; - uint32_t transfer32(uint32_t val, uint8_t bits = 32) override; - - using SPIBase::transfer; - void transfer(uint8_t* buffer, size_t numberBytes) override; - -protected: - void prepare(SPISettings& settings) override; - - SpiBus busId; - SpiPins pins; -}; - -/** @brief Global instance of SPI class */ -extern SPIClass SPI; diff --git a/Sming/Arch/Esp32/Platform/Clocks.h b/Sming/Arch/Esp32/Platform/Clocks.h index fcf72ef9e8..43b4ea854b 100644 --- a/Sming/Arch/Esp32/Platform/Clocks.h +++ b/Sming/Arch/Esp32/Platform/Clocks.h @@ -16,9 +16,8 @@ /** * @brief Clock implementation for os_timer API - * @see See IDF components/esp_common/src/ets_timer_legacy.c */ -struct OsTimerClock : public NanoTime::Clock { +struct OsTimerClock : public NanoTime::Clock { static constexpr const char* typeName() { return "OsTimerClock"; @@ -26,7 +25,7 @@ struct OsTimerClock : public NanoTime::Clock; using CpuCycleClockNormal = CpuCycleClock; diff --git a/Sming/Arch/Esp32/build.mk b/Sming/Arch/Esp32/build.mk index aeb1bc7a8b..2524b411cd 100644 --- a/Sming/Arch/Esp32/build.mk +++ b/Sming/Arch/Esp32/build.mk @@ -140,6 +140,7 @@ CPPFLAGS += \ -MP \ $(EXTRA_CPPFLAGS) \ -DARCH_ESP32 \ + -DESP32 \ -D__ESP32_EX__ \ -D__ets__ \ -D_GNU_SOURCE \ diff --git a/Sming/Arch/Esp8266/Components/driver/include/driver/hw_timer.h b/Sming/Arch/Esp8266/Components/driver/include/driver/hw_timer.h index a8214a1373..069f8dafc1 100644 --- a/Sming/Arch/Esp8266/Components/driver/include/driver/hw_timer.h +++ b/Sming/Arch/Esp8266/Components/driver/include/driver/hw_timer.h @@ -84,8 +84,8 @@ void IRAM_ATTR hw_timer1_attach_interrupt(hw_timer_source_type_t source_type, hw */ inline void IRAM_ATTR hw_timer1_enable(hw_timer_clkdiv_t div, hw_timer_intr_type_t intr_type, bool auto_load) { - constexpr uint32_t FRC1_ENABLE_TIMER = BIT7; - constexpr uint32_t FRC1_AUTO_LOAD = BIT6; +#define FRC1_ENABLE_TIMER BIT7 +#define FRC1_AUTO_LOAD BIT6 uint32_t ctrl = (div & 0x0C) | (intr_type & 0x01) | FRC1_ENABLE_TIMER; if(auto_load) { @@ -143,12 +143,12 @@ __forceinline uint32_t hw_timer1_read(void) *************************************/ #ifdef USE_US_TIMER -constexpr uint32_t HW_TIMER2_CLKDIV = TIMER_CLKDIV_16; +#define HW_TIMER2_CLKDIV TIMER_CLKDIV_16 #else -constexpr uint32_t HW_TIMER2_CLKDIV = TIMER_CLKDIV_256; +#define HW_TIMER2_CLKDIV TIMER_CLKDIV_256 #endif -constexpr uint32_t HW_TIMER2_CLK = HW_TIMER_BASE_CLK >> HW_TIMER2_CLKDIV; +#define HW_TIMER2_CLK (HW_TIMER_BASE_CLK >> HW_TIMER2_CLKDIV) /** * @brief Read current timer2 value diff --git a/Sming/Arch/Esp8266/Components/driver/uart.cpp b/Sming/Arch/Esp8266/Components/driver/uart.cpp index eb1277a444..37e2e151ee 100644 --- a/Sming/Arch/Esp8266/Components/driver/uart.cpp +++ b/Sming/Arch/Esp8266/Components/driver/uart.cpp @@ -49,6 +49,7 @@ #include #include #include +#include /* * Parameters relating to RX FIFO and buffer thresholds @@ -143,34 +144,6 @@ smg_uart_t* get_physical(smg_uart_t* uart) return uart; } -bool realloc_buffer(SerialBuffer*& buffer, size_t new_size) -{ - if(buffer != nullptr) { - if(new_size == 0) { - smg_uart_disable_interrupts(); - delete buffer; - buffer = nullptr; - smg_uart_restore_interrupts(); - return true; - } - - return buffer->resize(new_size) == new_size; - } - - if(new_size == 0) { - return true; - } - - auto new_buf = new SerialBuffer; - if(new_buf != nullptr && new_buf->resize(new_size) == new_size) { - buffer = new_buf; - return true; - } - - delete new_buf; - return false; -} - /** * @brief service interrupts for a UART * @param uart_nr identifies which UART to check @@ -379,51 +352,6 @@ void smg_uart_set_callback(smg_uart_t* uart, smg_uart_callback_t callback, void* } } -size_t smg_uart_resize_rx_buffer(smg_uart_t* uart, size_t new_size) -{ - if(smg_uart_rx_enabled(uart)) { - realloc_buffer(uart->rx_buffer, new_size); - } - return smg_uart_rx_buffer_size(uart); -} - -size_t smg_uart_rx_buffer_size(smg_uart_t* uart) -{ - return uart != nullptr && uart->rx_buffer != nullptr ? uart->rx_buffer->getSize() : 0; -} - -size_t smg_uart_resize_tx_buffer(smg_uart_t* uart, size_t new_size) -{ - if(smg_uart_tx_enabled(uart)) { - realloc_buffer(uart->tx_buffer, new_size); - } - return smg_uart_tx_buffer_size(uart); -} - -size_t smg_uart_tx_buffer_size(smg_uart_t* uart) -{ - return uart != nullptr && uart->tx_buffer != nullptr ? uart->tx_buffer->getSize() : 0; -} - -int smg_uart_peek_char(smg_uart_t* uart) -{ - return uart != nullptr && uart->rx_buffer ? uart->rx_buffer->peekChar() : -1; -} - -int smg_uart_rx_find(smg_uart_t* uart, char c) -{ - if(uart == nullptr || uart->rx_buffer == nullptr) { - return -1; - } - - return uart->rx_buffer->find(c); -} - -int smg_uart_peek_last_char(smg_uart_t* uart) -{ - return uart != nullptr && uart->rx_buffer != nullptr ? uart->rx_buffer->peekLastChar() : -1; -} - size_t smg_uart_read(smg_uart_t* uart, void* buffer, size_t size) { if(!smg_uart_rx_enabled(uart) || buffer == nullptr || size == 0) { @@ -487,7 +415,7 @@ void smg_uart_start_isr(smg_uart_t* uart) uint32_t intena = 0; if(smg_uart_rx_enabled(uart)) { - conf1 = (120 << UART_RXFIFO_FULL_THRHD_S) | (0x02 << UART_RX_TOUT_THRHD_S) | UART_RX_TOUT_EN; + conf1 = (RX_FIFO_FULL_THRESHOLD << UART_RXFIFO_FULL_THRHD_S) | (0x02 << UART_RX_TOUT_THRHD_S) | UART_RX_TOUT_EN; /* * There is little benefit in generating interrupts on errors, instead these @@ -750,12 +678,12 @@ smg_uart_t* smg_uart_init_ex(const smg_uart_config_t& cfg) txBufferSize += UART_TX_FIFO_SIZE; } - if(smg_uart_rx_enabled(uart) && !realloc_buffer(uart->rx_buffer, rxBufferSize)) { + if(smg_uart_rx_enabled(uart) && !smg_uart_realloc_buffer(uart->rx_buffer, rxBufferSize)) { delete uart; return nullptr; } - if(smg_uart_tx_enabled(uart) && !realloc_buffer(uart->tx_buffer, txBufferSize)) { + if(smg_uart_tx_enabled(uart) && !smg_uart_realloc_buffer(uart->tx_buffer, txBufferSize)) { delete uart->rx_buffer; delete uart; return nullptr; @@ -780,7 +708,7 @@ smg_uart_t* smg_uart_init_ex(const smg_uart_config_t& cfg) CLEAR_PERI_REG_MASK(UART_SWAP_REG, UART_SWAP0); - WRITE_PERI_REG(UART_CONF0(UART0), cfg.config); + WRITE_PERI_REG(UART_CONF0(UART0), cfg.format); break; case UART1: @@ -792,7 +720,7 @@ smg_uart_t* smg_uart_init_ex(const smg_uart_config_t& cfg) uart->mode = UART_TX_ONLY; // Transmit buffer optional - if(!realloc_buffer(uart->tx_buffer, txBufferSize)) { + if(!smg_uart_realloc_buffer(uart->tx_buffer, txBufferSize)) { delete uart; return nullptr; } @@ -801,7 +729,7 @@ smg_uart_t* smg_uart_init_ex(const smg_uart_config_t& cfg) smg_uart_detach(cfg.uart_nr); uart->tx_pin = 2; uart1_pin_select(uart->tx_pin); - WRITE_PERI_REG(UART_CONF0(UART1), cfg.config); + WRITE_PERI_REG(UART_CONF0(UART1), cfg.format); break; default: @@ -849,21 +777,42 @@ void smg_uart_uninit(smg_uart_t* uart) delete uart; } -smg_uart_t* smg_uart_init(uint8_t uart_nr, uint32_t baudrate, uint32_t config, smg_uart_mode_t mode, uint8_t tx_pin, - size_t rx_size, size_t tx_size) -{ - smg_uart_config_t cfg = { - .uart_nr = uart_nr, - .tx_pin = tx_pin, - .rx_pin = UART_PIN_DEFAULT, - .mode = mode, - .options = _BV(UART_OPT_TXWAIT), - .baudrate = baudrate, - .config = config, - .rx_size = rx_size, - .tx_size = tx_size, - }; - return smg_uart_init_ex(cfg); +void smg_uart_set_format(smg_uart_t* uart, smg_uart_format_t format) +{ + uart = get_physical(uart); + if(uart != nullptr) { + SET_PERI_REG_BITS(UART_CONF0(uart->uart_nr), 0xff, format, 0); + } +} + +bool smg_uart_intr_config(smg_uart_t* uart, const smg_uart_intr_config_t* config) +{ + uart = get_physical(uart); + if(uart == nullptr || config == nullptr) { + return false; + } + + uint32_t conf1{0}; + if(smg_uart_rx_enabled(uart)) { + if(uart->rx_buffer == nullptr) { + // Setting this to 0 results in lockup as the interrupt never clears + uint8_t rxfifo_full_thresh = TRange(1, UART_RXFIFO_FULL_THRHD).clip(config->rxfifo_full_thresh); + conf1 |= rxfifo_full_thresh << UART_RXFIFO_FULL_THRHD_S; + } else { + conf1 |= RX_FIFO_FULL_THRESHOLD << UART_RXFIFO_FULL_THRHD_S; + } + uint8_t rx_timeout_thresh = TRange(0, UART_RX_TOUT_THRHD).clip(config->rx_timeout_thresh); + conf1 |= rx_timeout_thresh << UART_RX_TOUT_THRHD_S; + conf1 |= UART_RX_TOUT_EN; + } + + if(smg_uart_tx_enabled(uart)) { + uint8_t txfifo_empty_intr_thresh = TRange(0, UART_TXFIFO_EMPTY_THRHD).clip(config->txfifo_empty_intr_thresh); + conf1 |= txfifo_empty_intr_thresh << UART_TXFIFO_EMPTY_THRHD_S; + } + + WRITE_PERI_REG(UART_CONF1(uart->uart_nr), conf1); + return true; } void smg_uart_swap(smg_uart_t* uart, int tx_pin) diff --git a/Sming/Arch/Esp8266/Components/esp-open-lwip/component.mk b/Sming/Arch/Esp8266/Components/esp-open-lwip/component.mk index 13ba166b61..e99342f5b8 100644 --- a/Sming/Arch/Esp8266/Components/esp-open-lwip/component.mk +++ b/Sming/Arch/Esp8266/Components/esp-open-lwip/component.mk @@ -53,7 +53,8 @@ COMPONENT_SRCFILES := \ lwip/core/ipv4/ip_frag.c \ lwip/netif/etharp.c \ \ - lwip/app/dhcpserver.c + lwip/app/dhcpserver.c \ + lwip/app/ping.c ifeq ($(ENABLE_ESPCONN),1) COMPONENT_SRCFILES += \ diff --git a/Sming/Arch/Esp8266/Components/gdbstub/gdbuart.cpp b/Sming/Arch/Esp8266/Components/gdbstub/gdbuart.cpp index b7f483cbe0..e54fce80f3 100644 --- a/Sming/Arch/Esp8266/Components/gdbstub/gdbuart.cpp +++ b/Sming/Arch/Esp8266/Components/gdbstub/gdbuart.cpp @@ -382,7 +382,7 @@ bool ATTR_GDBINIT gdb_uart_init() .mode = UART_FULL, .options = _BV(UART_OPT_TXWAIT) | _BV(UART_OPT_CALLBACK_RAW), .baudrate = SERIAL_BAUD_RATE, - .config = UART_8N1, + .format = UART_8N1, .rx_size = 0, .tx_size = 0, }; diff --git a/Sming/Arch/Esp8266/Core/SPI.cpp b/Sming/Arch/Esp8266/Core/SPI.cpp deleted file mode 100644 index a566605f3f..0000000000 --- a/Sming/Arch/Esp8266/Core/SPI.cpp +++ /dev/null @@ -1,345 +0,0 @@ -/**** - * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. - * Created 2015 by Skurydin Alexey - * http://github.com/SmingHub/Sming - * All files of the Sming Core are provided under the LGPL v3 license. - * - * SPI.cpp - * - * Created on: Mar 2, 2016 - * Author: harry-boe - * - * Some code is derived from: - * David Ogilvy (MetalPhreak) - * - ****/ - -#include "SPI.h" -#include -#include "espinc/eagle_soc.h" -#include "espinc/spi_register.h" - -// define the static singleton -SPIClass SPI; - -namespace -{ -// Used internally to calculate optimum SPI speed -struct SpiPreDiv { - unsigned freq; - unsigned prescale; - unsigned divisor; -}; - -/** - * @brief Wait until HSPI has finished any current transaction - */ -__forceinline void spi_wait() -{ - while(READ_PERI_REG(SPI_CMD(SPI_NO)) & SPI_USR) { - // - } -} - -/** - * @brief Initiate an HSPI user transaction - */ -__forceinline void spi_send() -{ - SET_PERI_REG_MASK(SPI_CMD(SPI_NO), SPI_USR); -} - -/** - * @brief Configure SPI mode parameters for clock edge and clock polarity. - * - * Private method used by SPISetings - * - * @param SPI_MODE0 .. SPI_MODE4 - * - * Mode Clock Polarity (CPOL) Clock Phase (CPHA) - * SPI_MODE0 0 0 - * SPI_MODE1 0 1 - * SPI_MODE2 1 0 - * SPI_MODE3 1 1 - */ -void spi_mode(uint8_t mode) -{ - uint8_t spi_cpha = mode & 0x0F; - uint8_t spi_cpol = mode & 0xF0; - -#ifdef SPI_DEBUG - debugf("SPIClass::spi_mode(mode %x) spi_cpha %X,spi_cpol %X)", mode, spi_cpha, spi_cpol); -#endif - - if(spi_cpha == spi_cpol) { - CLEAR_PERI_REG_MASK(SPI_USER(SPI_NO), SPI_CK_OUT_EDGE); - } else { - SET_PERI_REG_MASK(SPI_USER(SPI_NO), SPI_CK_OUT_EDGE); - } - - if(spi_cpol) { - SET_PERI_REG_MASK(SPI_PIN(SPI_NO), SPI_IDLE_EDGE); - } else { - CLEAR_PERI_REG_MASK(SPI_PIN(SPI_NO), SPI_IDLE_EDGE); - } -} - -/** - * @brief Setup the byte order for shifting data out of buffer - * - * Private method used by SPISetings - * - * @param MSBFIRST 1 - * Data is sent out starting with Bit31 and down to Bit0 - * LSBFIRST 0 - * Data is sent out starting with the lowest BYTE, from MSB to LSB - * 0xABCDEFGH would be sent as 0xGHEFCDAB - */ -void spi_byte_order(uint8_t byte_order) -{ -#ifdef SPI_DEBUG - debugf("SPIClass::spi_byte_order(byte_order %u)", byte_order); -#endif - - if(byte_order) { - SET_PERI_REG_MASK(SPI_USER(SPI_NO), SPI_WR_BYTE_ORDER); - SET_PERI_REG_MASK(SPI_USER(SPI_NO), SPI_RD_BYTE_ORDER); - } else { - CLEAR_PERI_REG_MASK(SPI_USER(SPI_NO), SPI_WR_BYTE_ORDER); - CLEAR_PERI_REG_MASK(SPI_USER(SPI_NO), SPI_RD_BYTE_ORDER); - } -} - -/** - * @brief Calculate the closest prescale value for a given frequency and clock-divider - * @param cpuFreq current CPU frequency, in Hz - * @param freq target SPI bus frequency, in Hz - * @param div divisor value to use - * @retval SpiPreDiv contains resulting frequency, prescaler and divisor values - */ -SpiPreDiv calculateSpeed(unsigned cpuFreq, unsigned freq, unsigned div) -{ - SpiPreDiv prediv; - unsigned pre = cpuFreq / (freq * div); - if(pre == 0) { - pre = 1; - } - unsigned n = pre * div; - while(true) { - prediv.freq = cpuFreq / n; - if(prediv.freq <= freq) { - break; - } - ++pre; - n += div; - } - prediv.prescale = pre; - prediv.divisor = div; - -#ifdef SPI_DEBUG - debugf("SPI calculateSpeed(uint freq %u, uint pre %u, uint div %u)", f, pre, div); -#endif - - return prediv; -} - -/** @brief Check speed settings and perform any pre-calculation required - * @param speed IN: requested bus frequency, OUT: Modified settings with prescale values - * @note - * The algorithm is testing with clock dividers 2,3 and 5 to find the best pre-divider - * The resulting clock frequency is not 100% accurate but delivers result within 5% - * - * It is guaranteed that the frequency will not exceed the given target - * - * Make sure that the ESP clock frequency is set before initializing the SPI bus. - * Changes on the ESP clock are not recognised once initialized - */ -void checkSpeed(SPISpeed& speed) -{ - unsigned cpuFreq = system_get_cpu_freq() * 1000000UL; -#ifdef SPI_DEBUG - debugf("SPIClass::calculateSpeed() -> current cpu frequency %u", cpuFreq); -#endif - - SpiPreDiv prediv; - - // If we're not running at max then need to determine appropriate prescale values - if(speed.frequency >= cpuFreq) { - // Use maximum speed - prediv.freq = cpuFreq; - prediv.divisor = 0; - speed.regVal = SPI_CLK_EQU_SYSCLK; - } else { - prediv = calculateSpeed(cpuFreq, speed.frequency, 2); - if(prediv.freq != speed.frequency) { - // Use whichever divisor gives the highest frequency - SpiPreDiv pd3 = calculateSpeed(cpuFreq, speed.frequency, 3); - SpiPreDiv pd5 = calculateSpeed(cpuFreq, speed.frequency, 5); - if(pd3.freq > prediv.freq || pd5.freq > prediv.freq) { - prediv = (pd3.freq > pd5.freq) ? pd3 : pd5; - } - } - - // We have prescale and divisor values, now get regVal so we don't need to do this every time prepare() is called - speed.regVal = (((prediv.prescale - 1) & SPI_CLKDIV_PRE) << SPI_CLKDIV_PRE_S) | - (((prediv.divisor - 1) & SPI_CLKCNT_N) << SPI_CLKCNT_N_S) | - (((prediv.divisor >> 1) & SPI_CLKCNT_H) << SPI_CLKCNT_H_S) | - ((0 & SPI_CLKCNT_L) << SPI_CLKCNT_L_S); - } - - //#ifdef SPI_DEBUG - debug_e("-> Using clock divider %u -> target freq %u -> result %u", prediv.divisor, speed.frequency, prediv.freq); - //#endif - - speed.frequency = prediv.freq; -} - -void spi_set_clock(SPISpeed& speed) -{ - // Clock register value is never 0, so indicates it hasn't been calculated - if(speed.regVal == 0) { - checkSpeed(speed); - } else { -#ifdef SPI_DEBUG - unsigned prescale = (speed.regVal >> SPI_CLKDIV_PRE_S) + 1; - unsigned divisor = (speed.regVal >> SPI_CLKCNT_N_S) + 1; - debugf("spi_set_clock(prescaler %u, divisor %u) for target %u", prescale, divisor, speed.frequency); -#endif - } - - WRITE_PERI_REG(SPI_CLOCK(SPI_NO), speed.regVal); -} - -} // namespace - -bool SPIClass::begin() -{ - CLEAR_PERI_REG_MASK(PERIPHS_IO_MUX, BIT9); - - PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2); // HSPIQ MISO == GPIO12 - PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2); // HSPID MOSI == GPIO13 - PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2); // CLK == GPIO14 - - checkSpeed(SPIDefaultSettings.speed); - prepare(SPIDefaultSettings); - - return true; -} - -uint32_t SPIClass::transfer32(uint32_t data, uint8_t bits) -{ - uint32_t regvalue = READ_PERI_REG(SPI_USER(SPI_NO)) & (SPI_WR_BYTE_ORDER | SPI_RD_BYTE_ORDER | SPI_CK_OUT_EDGE); - - spi_wait(); - - regvalue |= SPI_USR_MOSI | SPI_DOUTDIN | SPI_CK_I_EDGE; - WRITE_PERI_REG(SPI_USER(SPI_NO), regvalue); - - WRITE_PERI_REG(SPI_USER1(SPI_NO), (((bits - 1) & SPI_USR_MOSI_BITLEN) << SPI_USR_MOSI_BITLEN_S) | - (((bits - 1) & SPI_USR_MISO_BITLEN) << SPI_USR_MISO_BITLEN_S)); - - // copy data to W0 - if(READ_PERI_REG(SPI_USER(SPI_NO)) & SPI_WR_BYTE_ORDER) { - WRITE_PERI_REG(SPI_W0(SPI_NO), data << (32 - bits)); - } else { - WRITE_PERI_REG(SPI_W0(SPI_NO), data); - } - - spi_send(); - spi_wait(); - - auto res = READ_PERI_REG(SPI_W0(SPI_NO)); - if(READ_PERI_REG(SPI_USER(SPI_NO)) & SPI_RD_BYTE_ORDER) { - res >>= (32 - bits); - } - - return res; -} - -uint8_t SPIClass::read8() -{ - spi_wait(); - - WRITE_PERI_REG(SPI_W0(SPI_NO), 0x00); - - spi_send(); - spi_wait(); - - auto res = READ_PERI_REG(SPI_W0(SPI_NO)); - if(READ_PERI_REG(SPI_USER(SPI_NO)) & SPI_RD_BYTE_ORDER) { - res >>= 24; - } - - return res; -} - -void SPIClass::transfer(uint8_t* buffer, size_t numberBytes) -{ -#define BLOCKSIZE 64U // the max length of the ESP SPI_W0 registers - - unsigned bufIndx = 0; - - unsigned blocks = ((numberBytes - 1) / BLOCKSIZE) + 1; -#ifdef SPI_DEBUG - unsigned total = blocks; -#endif - - // loop number of blocks - while(blocks--) { - // get full BLOCKSIZE or number of remaining bytes - auto bufLength = std::min(numberBytes - bufIndx, BLOCKSIZE); - -#ifdef SPI_DEBUG - debugf("Write/Read Block %u total %u bytes", total - blocks, bufLength); -#endif - - // compute the number of bits to clock - auto num_bits = bufLength * 8; - - uint32_t regvalue = READ_PERI_REG(SPI_USER(SPI_NO)) & (SPI_WR_BYTE_ORDER | SPI_RD_BYTE_ORDER | SPI_CK_OUT_EDGE); - - spi_wait(); - - regvalue |= SPI_USR_MOSI | SPI_DOUTDIN | SPI_CK_I_EDGE; - WRITE_PERI_REG(SPI_USER(SPI_NO), regvalue); - - // setup bit length - WRITE_PERI_REG(SPI_USER1(SPI_NO), (((num_bits - 1) & SPI_USR_MOSI_BITLEN) << SPI_USR_MOSI_BITLEN_S) | - (((num_bits - 1) & SPI_USR_MISO_BITLEN) << SPI_USR_MISO_BITLEN_S)); - - // copy the registers starting from last index position - if(IS_ALIGNED(buffer)) { - memcpy((void*)SPI_W0(SPI_NO), &buffer[bufIndx], ALIGNUP4(bufLength)); - } else { - uint32_t wordBuffer[BLOCKSIZE / 4]; - memcpy(wordBuffer, &buffer[bufIndx], bufLength); - memcpy((void*)SPI_W0(SPI_NO), wordBuffer, ALIGNUP4(bufLength)); - } - - spi_send(); - spi_wait(); - - // copy the registers starting from last index position - memcpy(&buffer[bufIndx], (void*)SPI_W0(SPI_NO), bufLength); - - // increment bufIndex - bufIndx += bufLength; - } -} - -void SPIClass::prepare(SPISettings& settings) -{ -#ifdef SPI_DEBUG - debugf("SPIClass::prepare(SPISettings)"); - settings.print("settings"); -#endif - - // setup clock - spi_set_clock(settings.speed); - - // set byte order - spi_byte_order(settings.byteOrder); - - // set spi mode - spi_mode(settings.dataMode); -} diff --git a/Sming/Arch/Esp8266/Core/SPI.h b/Sming/Arch/Esp8266/Core/SPI.h deleted file mode 100644 index e6ad930196..0000000000 --- a/Sming/Arch/Esp8266/Core/SPI.h +++ /dev/null @@ -1,63 +0,0 @@ -/**** - * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. - * Created 2015 by Skurydin Alexey - * http://github.com/SmingHub/Sming - * All files of the Sming Core are provided under the LGPL v3 license. - * - * SPI.h - * - * Created on: Mar 2, 2016 - * Author: harry-boe - * - */ - -/** @defgroup hw_spi SPI Hardware support - * @brief Provides hardware SPI support - */ - -#pragma once - -#include "SPIBase.h" -#include "SPISettings.h" - -//#define SPI_DEBUG 1 - -// for compatibility when porting from Arduino -#define SPI_HAS_TRANSACTION 0 - -#define SPI_NO 1 - -/** - * @brief Hardware SPI object - * @addtogroup hw_spi - * @{ - */ - -class SPIClass : public SPIBase -{ -public: - SPIClass() - { - } - - SPIClass(const SPIClass&) = delete; - SPIClass& operator=(const SPIClass&) = delete; - - bool begin() override; - - void end() override - { - } - - uint8_t read8() override; - uint32_t transfer32(uint32_t val, uint8_t bits = 32) override; - - using SPIBase::transfer; - void transfer(uint8_t* buffer, size_t numberBytes) override; - -protected: - void prepare(SPISettings& settings) override; -}; - -/** @brief Global instance of SPI class */ -extern SPIClass SPI; diff --git a/Sming/Arch/Esp8266/Core/SPISoft.cpp b/Sming/Arch/Esp8266/Core/SPISoft.cpp deleted file mode 100644 index 77b0efca32..0000000000 --- a/Sming/Arch/Esp8266/Core/SPISoft.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* -Author: (github.com/)ADiea -Project: Sming for ESP8266 - https://github.com/anakod/Sming -License: MIT -Date: 15.07.2015 -Descr: Implement software SPI. To improve speed, GPIO16 is not supported(see Digital.cpp) -*/ -#include "SPISoft.h" -#include - -#define SPEED 0 /* You gain ~0.7 kBps (more for larger data chunks)*/ -#define SIZE 1 /* You gain ~ 400B from the total 32K of cache RAM */ -#define SPEED_VS_SIZE SIZE /* Your choice here, I choose SIZE */ - -#define GP_IN(pin) ((GPIO_REG_READ(GPIO_IN_ADDRESS) >> (pin)) & 1) -#define GP_OUT(pin, val) \ - GPIO_REG_WRITE(((((val) != LOW) ? GPIO_OUT_W1TS_ADDRESS : GPIO_OUT_W1TC_ADDRESS)), ((uint16_t)1 << (pin))) -#define SCK_PULSE \ - GP_OUT(mCLK, HIGH); \ - fastDelay(m_delay); \ - GP_OUT(mCLK, LOW); \ - fastDelay(m_delay); - -static inline void IRAM_ATTR fastDelay(unsigned d) -{ - while(d) - --d; -} - -bool SPISoft::begin() -{ - if(16 == mMISO || 16 == mMOSI || 16 == mCLK) { - /*To be able to use fast/simple GPIO read/write GPIO16 is not supported*/ - debugf("SPISoft: GPIO 16 not supported\n"); - return false; - } - - pinMode(mCLK, OUTPUT); - digitalWrite(mCLK, LOW); - - pinMode(mMISO, INPUT); - digitalWrite(mMISO, HIGH); - - pinMode(mMOSI, OUTPUT); - return true; -} - -void SPISoft::transfer(uint8_t* buffer, uint32_t size) -{ - do { - uint8_t d = *buffer; - - GP_OUT(mMOSI, d & 0x80); /* bit7 */ - uint8_t r = GP_IN(mMISO); //bit 7 - SCK_PULSE - GP_OUT(mMOSI, d & 0x40); /* bit6 */ - r = r << 1 | GP_IN(mMISO); //bit 6 - SCK_PULSE - GP_OUT(mMOSI, d & 0x20); /* bit5 */ - r = r << 1 | GP_IN(mMISO); //bit 5 - SCK_PULSE - GP_OUT(mMOSI, d & 0x10); /* bit4 */ - r = r << 1 | GP_IN(mMISO); //bit 4 - SCK_PULSE - GP_OUT(mMOSI, d & 0x08); /* bit3 */ - r = r << 1 | GP_IN(mMISO); //bit 3 - SCK_PULSE - GP_OUT(mMOSI, d & 0x04); /* bit2 */ - r = r << 1 | GP_IN(mMISO); //bit 2 - SCK_PULSE - GP_OUT(mMOSI, d & 0x02); /* bit1 */ - r = r << 1 | GP_IN(mMISO); //bit 1 - SCK_PULSE - GP_OUT(mMOSI, d & 0x01); /* bit0 */ - r = r << 1 | GP_IN(mMISO); //bit 0 - SCK_PULSE - - *buffer++ = r; - } while(--size); -} diff --git a/Sming/Arch/Host/Components/SerialLib/README.rst b/Sming/Arch/Host/Components/SerialLib/README.rst new file mode 100644 index 0000000000..71f26d109c --- /dev/null +++ b/Sming/Arch/Host/Components/SerialLib/README.rst @@ -0,0 +1,6 @@ +Serialib +======== + +Serialib is a simple C++ library for serial communication. The library has been designed to work under Linux and Windows. + +More details on [Lulu's blog](https://lucidar.me/en/serialib/cross-plateform-rs232-serial-library/) diff --git a/Sming/Arch/Host/Components/driver/component.mk b/Sming/Arch/Host/Components/driver/component.mk index 334ca3db26..2e19ed401d 100644 --- a/Sming/Arch/Host/Components/driver/component.mk +++ b/Sming/Arch/Host/Components/driver/component.mk @@ -23,7 +23,7 @@ ENABLE_HOST_UARTID ?= # Options to add when running emulator CACHE_VARS += HOST_UART_OPTIONS HOST_UART_OPTIONS ?= $(addprefix --uart=,$(ENABLE_HOST_UARTID)) -CLI_TARGET_OPTIONS += $(HOST_UART_OPTIONS) +override CLI_TARGET_OPTIONS += $(HOST_UART_OPTIONS) # $1 -> Uart ID define RunHostTerminal diff --git a/Sming/Arch/Host/Components/driver/hw_timer.cpp b/Sming/Arch/Host/Components/driver/hw_timer.cpp index c5d045355f..e0d8f2c28c 100644 --- a/Sming/Arch/Host/Components/driver/hw_timer.cpp +++ b/Sming/Arch/Host/Components/driver/hw_timer.cpp @@ -12,12 +12,12 @@ #include #include -#include -#include +#include #include #include #include #include +#include /* Timer 1 */ @@ -158,13 +158,7 @@ void* CTimerThread::thread_routine() */ const unsigned SCHED_MIN = 1500; if(interval > SCHED_MIN) { - timeval tv; - gettimeofday(&tv, nullptr); - tv.tv_usec += interval - SCHED_MIN; - timespec to; - to.tv_sec = tv.tv_sec + tv.tv_usec / 1000000; - to.tv_nsec = (tv.tv_usec % 1000000) * 1000; - if(sem.timedwait(&to)) { + if(sem.timedwait(interval - SCHED_MIN)) { continue; // state changed } if(errno != ETIMEDOUT) { @@ -207,41 +201,49 @@ void* CTimerThread::thread_routine() return nullptr; } -static CTimerThread timer1("Timer1"); +static std::unique_ptr timer1; + +void hw_timer_init(void) +{ + timer1.reset(new CTimerThread("Timer1")); +} void hw_timer_cleanup() { - timer1.terminate(); + if(timer1) { + timer1->terminate(); + timer1.reset(); + } } void hw_timer1_attach_interrupt(hw_timer_source_type_t source_type, hw_timer_callback_t callback, void* arg) { - timer1.attach_interrupt(source_type, callback, arg); + timer1->attach_interrupt(source_type, callback, arg); } void hw_timer1_enable(hw_timer_clkdiv_t div, hw_timer_intr_type_t intr_type, bool auto_load) { - timer1.enable(div, intr_type, auto_load); + timer1->enable(div, intr_type, auto_load); } void hw_timer1_write(uint32_t ticks) { - timer1.write(ticks); + timer1->write(ticks); } void hw_timer1_disable() { - timer1.stop(); + timer1->stop(); } void hw_timer1_detach_interrupt() { - timer1.detach_interrupt(); + timer1->detach_interrupt(); } uint32_t hw_timer1_read() { - return timer1.read(); + return timer1->read(); } uint32_t hw_timer2_read() diff --git a/Sming/Arch/Host/Components/driver/include/driver/hw_timer.h b/Sming/Arch/Host/Components/driver/include/driver/hw_timer.h index 1eb2de5282..314f625416 100644 --- a/Sming/Arch/Host/Components/driver/include/driver/hw_timer.h +++ b/Sming/Arch/Host/Components/driver/include/driver/hw_timer.h @@ -14,14 +14,14 @@ #include #include -#define APB_CLK_FREQ 80000000U - -#define HW_TIMER_BASE_CLK APB_CLK_FREQ - #ifdef __cplusplus extern "C" { #endif +#define APB_CLK_FREQ 80000000U + +#define HW_TIMER_BASE_CLK APB_CLK_FREQ + /************************************* * * FRC1 timer @@ -67,9 +67,9 @@ uint32_t hw_timer1_read(void); *************************************/ #ifdef USE_US_TIMER -constexpr uint32_t HW_TIMER2_CLK = HW_TIMER_BASE_CLK / 16; +#define HW_TIMER2_CLK (HW_TIMER_BASE_CLK / 16) #else -constexpr uint32_t HW_TIMER2_CLK = HW_TIMER_BASE_CLK / 256; +#define HW_TIMER2_CLK (HW_TIMER_BASE_CLK / 256) #endif uint32_t hw_timer2_read(void); @@ -79,9 +79,7 @@ inline uint32_t NOW() return hw_timer2_read(); } -inline void hw_timer_init(void) -{ -} +void hw_timer_init(void); void hw_timer_cleanup(); diff --git a/Sming/Arch/Host/Components/driver/include/driver/os_timer.h b/Sming/Arch/Host/Components/driver/include/driver/os_timer.h index e63933a3df..4502fc2e23 100644 --- a/Sming/Arch/Host/Components/driver/include/driver/os_timer.h +++ b/Sming/Arch/Host/Components/driver/include/driver/os_timer.h @@ -60,8 +60,11 @@ static inline uint64_t os_timer_expire(const os_timer_t* ptimer) void os_timer_done(os_timer_t* ptimer); -// Hook function to service timers -void host_service_timers(); +/** + * @brief Hook function to service timers + * @retval int Milliseconds until next timer due, -1 if none + */ +int host_service_timers(); #ifdef __cplusplus } diff --git a/Sming/Arch/Host/Components/driver/os_timer.cpp b/Sming/Arch/Host/Components/driver/os_timer.cpp index 5eddbb2900..ec80e5237d 100644 --- a/Sming/Arch/Host/Components/driver/os_timer.cpp +++ b/Sming/Arch/Host/Components/driver/os_timer.cpp @@ -4,10 +4,13 @@ #include #include -static os_timer_t* timer_list; -static CMutex mutex; +namespace +{ +os_timer_t* timer_list; +CMutex mutex; -static void timer_insert(uint32_t expire, os_timer_t* ptimer) +// Called with mutex locked +void timer_insert(uint32_t expire, os_timer_t* ptimer) { os_timer_t* t_prev = nullptr; auto t = timer_list; @@ -27,6 +30,8 @@ static void timer_insert(uint32_t expire, os_timer_t* ptimer) ptimer->timer_expire = expire; } +} // namespace + void os_timer_arm_ticks(os_timer_t* ptimer, uint32_t ticks, bool repeat_flag) { assert(ptimer != nullptr); @@ -37,6 +42,11 @@ void os_timer_arm_ticks(os_timer_t* ptimer, uint32_t ticks, bool repeat_flag) mutex.lock(); timer_insert(hw_timer2_read() + ticks, ptimer); mutex.unlock(); + + // Kick main thread (which services timers) if we're due next + if(timer_list == ptimer) { + host_thread_kick(); + } } void os_timer_arm(struct os_timer_t* ptimer, uint32_t time, bool repeat_flag) @@ -57,6 +67,10 @@ void os_timer_disarm(struct os_timer_t* ptimer) { assert(ptimer != nullptr); + if(int(ptimer->timer_next) == -1) { + return; + } + mutex.lock(); if(timer_list != nullptr) { // Remove timer from list @@ -91,39 +105,35 @@ void os_timer_done(struct os_timer_t* ptimer) os_timer_disarm(ptimer); } -// Called with mutex locked -static os_timer_t* find_expired_timer() +int host_service_timers() { if(timer_list == nullptr) { - return nullptr; + return -1; } auto ticks_now = hw_timer2_read(); auto t = timer_list; - if(int(t->timer_expire - ticks_now) > 0) { - // No timers due - return nullptr; + int ticks = t->timer_expire - ticks_now; + if(ticks > 0) { + // Return milliseconds until timer due + using R = std::ratio<1000, HW_TIMER2_CLK>; + return muldiv(unsigned(ticks)); } - // Found an expired timer, so remove from queue + mutex.lock(); + // Pop timer from queue timer_list = t->timer_next; t->timer_next = reinterpret_cast(-1); - // Repeating timer? if(t->timer_period != 0) { timer_insert(t->timer_expire + t->timer_period, t); } - - return t; -} - -void host_service_timers() -{ - mutex.lock(); - auto t = find_expired_timer(); mutex.unlock(); - if(t != nullptr && t->timer_func != nullptr) { + if(t->timer_func != nullptr) { t->timer_func(t->timer_arg); } + + // Call again soon as poss. + return 0; } diff --git a/Sming/Arch/Host/Components/driver/uart.cpp b/Sming/Arch/Host/Components/driver/uart.cpp index bde5e7dfdd..55a635f93f 100644 --- a/Sming/Arch/Host/Components/driver/uart.cpp +++ b/Sming/Arch/Host/Components/driver/uart.cpp @@ -78,34 +78,6 @@ __forceinline bool smg_uart_isr_enabled(uint8_t nr) return bitRead(isrMask, nr); } -bool realloc_buffer(SerialBuffer*& buffer, size_t new_size) -{ - if(buffer != nullptr) { - if(new_size == 0) { - (void)smg_uart_disable_interrupts(); - delete buffer; - buffer = nullptr; - smg_uart_restore_interrupts(); - return true; - } - - return buffer->resize(new_size) == new_size; - } - - if(new_size == 0) { - return true; - } - - auto new_buf = new SerialBuffer; - if(new_buf != nullptr && new_buf->resize(new_size) == new_size) { - buffer = new_buf; - return true; - } - - delete new_buf; - return false; -} - } // namespace smg_uart_t* smg_uart_get_uart(uint8_t uart_nr) @@ -141,51 +113,6 @@ void smg_uart_set_callback(smg_uart_t* uart, smg_uart_callback_t callback, void* } } -size_t smg_uart_resize_rx_buffer(smg_uart_t* uart, size_t new_size) -{ - if(smg_uart_rx_enabled(uart)) { - realloc_buffer(uart->rx_buffer, new_size); - } - return smg_uart_rx_buffer_size(uart); -} - -size_t smg_uart_rx_buffer_size(smg_uart_t* uart) -{ - return uart != nullptr && uart->rx_buffer != nullptr ? uart->rx_buffer->getSize() : 0; -} - -size_t smg_uart_resize_tx_buffer(smg_uart_t* uart, size_t new_size) -{ - if(smg_uart_tx_enabled(uart)) { - realloc_buffer(uart->tx_buffer, new_size); - } - return smg_uart_tx_buffer_size(uart); -} - -size_t smg_uart_tx_buffer_size(smg_uart_t* uart) -{ - return uart != nullptr && uart->tx_buffer != nullptr ? uart->tx_buffer->getSize() : 0; -} - -int smg_uart_peek_char(smg_uart_t* uart) -{ - return uart != nullptr && uart->rx_buffer ? uart->rx_buffer->peekChar() : -1; -} - -int smg_uart_rx_find(smg_uart_t* uart, char c) -{ - if(uart == nullptr || uart->rx_buffer == nullptr) { - return -1; - } - - return uart->rx_buffer->find(c); -} - -int smg_uart_peek_last_char(smg_uart_t* uart) -{ - return uart != nullptr && uart->rx_buffer != nullptr ? uart->rx_buffer->peekLastChar() : -1; -} - size_t smg_uart_read(smg_uart_t* uart, void* buffer, size_t size) { if(!smg_uart_rx_enabled(uart) || buffer == nullptr || size == 0) { @@ -357,6 +284,10 @@ smg_uart_t* smg_uart_init_ex(const smg_uart_config_t& cfg) return nullptr; } + if(cfg.uart_nr >= UART_COUNT) { + return nullptr; + } + auto uart = new smg_uart_t; if(uart == nullptr) { return nullptr; @@ -377,54 +308,22 @@ smg_uart_t* smg_uart_init_ex(const smg_uart_config_t& cfg) rxBufferSize += UART_RX_FIFO_SIZE; txBufferSize += UART_TX_FIFO_SIZE; - switch(cfg.uart_nr) { - case UART0: - case UART2: - if(smg_uart_rx_enabled(uart) && !realloc_buffer(uart->rx_buffer, rxBufferSize)) { - delete uart; - return nullptr; - } - - if(smg_uart_tx_enabled(uart) && !realloc_buffer(uart->tx_buffer, txBufferSize)) { - delete uart->rx_buffer; - delete uart; - return nullptr; - } - - if(cfg.uart_nr == UART2) { - break; - } - - // OK, buffers allocated so setup hardware - smg_uart_detach(cfg.uart_nr); - - break; - - case UART1: - // Note: uart_interrupt_handler does not support RX on UART 1 - if(uart->mode == UART_RX_ONLY) { - delete uart; - return nullptr; - } - uart->mode = UART_TX_ONLY; - - // Transmit buffer optional - if(!realloc_buffer(uart->tx_buffer, txBufferSize)) { - delete uart; - return nullptr; - } - - // Setup hardware - smg_uart_detach(cfg.uart_nr); - break; + if(smg_uart_rx_enabled(uart) && !smg_uart_realloc_buffer(uart->rx_buffer, rxBufferSize)) { + delete uart; + return nullptr; + } - default: - // big fail! + if(smg_uart_tx_enabled(uart) && !smg_uart_realloc_buffer(uart->tx_buffer, txBufferSize)) { + delete uart->rx_buffer; delete uart; return nullptr; } + // OK, buffers allocated so setup hardware + smg_uart_detach(cfg.uart_nr); + smg_uart_set_baudrate(uart, cfg.baudrate); + smg_uart_set_format(uart, cfg.format); smg_uart_flush(uart); uartInstances[cfg.uart_nr] = uart; smg_uart_start_isr(uart); @@ -453,21 +352,19 @@ void smg_uart_uninit(smg_uart_t* uart) delete uart; } -smg_uart_t* smg_uart_init(uint8_t uart_nr, uint32_t baudrate, uint32_t config, smg_uart_mode_t mode, uint8_t tx_pin, - size_t rx_size, size_t tx_size) +void smg_uart_set_format(smg_uart_t* uart, smg_uart_format_t format) { - smg_uart_config_t cfg = { - .uart_nr = uart_nr, - .tx_pin = tx_pin, - .rx_pin = UART_PIN_DEFAULT, - .mode = mode, - .options = _BV(UART_OPT_TXWAIT), - .baudrate = baudrate, - .config = config, - .rx_size = rx_size, - .tx_size = tx_size, - }; - return smg_uart_init_ex(cfg); + // Not implemented + (void)uart; + (void)format; +} + +bool smg_uart_intr_config(smg_uart_t* uart, const smg_uart_intr_config_t* config) +{ + // Not implemented + (void)uart; + (void)config; + return false; } void smg_uart_swap(smg_uart_t* uart, int tx_pin) diff --git a/Sming/Arch/Host/Components/driver/uart.rst b/Sming/Arch/Host/Components/driver/uart.rst index 8e8a6e19c8..ea635a9846 100644 --- a/Sming/Arch/Host/Components/driver/uart.rst +++ b/Sming/Arch/Host/Components/driver/uart.rst @@ -9,8 +9,7 @@ Introduction Implements a UART driver to connect via TCP socket, allowing terminal emulation using telnet, or directly to local host serial device (e.g. /dev/ttyUSB0, COM4, etc.) -By default, output to UART0 is sent to the console and keyboard input is written to the UART0 receive queue. -If emulation is enabled on any ports then this behaviour is disabled. +If not otherwise reassigned, UART0 output is sent to the console and keyboard input is written to the UART0 receive queue. Build variables @@ -101,3 +100,7 @@ For Windows, substitute the appropriate device name, e.g. ``COM4`` instead of `` .. note:: If necessary, add ``ENABLE_HOST_UARTID=`` to prevent telnet windows from being created. + +Console I/O may be assigned to a different port like this:: + + make run HOST_UART_OPTIONS="--uart=1 --device=console" diff --git a/Sming/Arch/Host/Components/driver/uart_server.cpp b/Sming/Arch/Host/Components/driver/uart_server.cpp index 552216b298..aadc360bd1 100644 --- a/Sming/Arch/Host/Components/driver/uart_server.cpp +++ b/Sming/Arch/Host/Components/driver/uart_server.cpp @@ -31,12 +31,11 @@ namespace { unsigned portBase{10000}; std::unique_ptr servers[UART_COUNT]; -} // namespace class KeyboardThread : public CThread { public: - KeyboardThread() : CThread("keyboard", 0) + KeyboardThread() : CThread("keyboard", 1) { } @@ -65,7 +64,7 @@ void* KeyboardThread::thread_routine() while(!done) { int c = getkey(); if(c == KEY_NONE) { - sched_yield(); + msleep(50); continue; } @@ -93,9 +92,9 @@ void* KeyboardThread::thread_routine() return nullptr; } -static KeyboardThread* keyboardThread; +KeyboardThread* keyboardThread; -static void destroyKeyboardThread() +void destroyKeyboardThread() { if(keyboardThread == nullptr) { return; @@ -106,7 +105,7 @@ static void destroyKeyboardThread() keyboardThread = nullptr; } -static void onUart0Notify(smg_uart_t* uart, smg_uart_notify_code_t code) +void uartConsoleNotify(smg_uart_t* uart, smg_uart_notify_code_t code) { switch(code) { case UART_NOTIFY_AFTER_WRITE: { @@ -135,6 +134,8 @@ static void onUart0Notify(smg_uart_t* uart, smg_uart_notify_code_t code) } } +} // namespace + void startup(const Config& config) { if(config.portBase != 0) { @@ -143,31 +144,43 @@ void startup(const Config& config) auto notify = [](smg_uart_t* uart, smg_uart_notify_code_t code) { auto& server = servers[uart->uart_nr]; - if(server) { + if(server != nullptr) { server->onNotify(uart, code); } else if(code == UART_NOTIFY_AFTER_WRITE) { uart->tx_buffer->clear(); } }; + bool consoleAssigned{false}; for(unsigned i = 0; i < UART_COUNT; ++i) { smg_uart_set_notify(i, notify); if(!bitRead(config.enableMask, i)) { continue; } + auto devname = config.deviceNames[i]; + if(devname != nullptr && strcmp(devname, "console") == 0) { + if(consoleAssigned) { + host_debug_e("Console may not be assigned to multiple ports"); + exit(1); + } + smg_uart_set_notify(i, uartConsoleNotify); + consoleAssigned = true; + continue; + } + auto& server = servers[i]; - if(config.deviceNames[i] == nullptr) { + if(devname == nullptr) { server.reset(new CUartPort(i)); } else { - server.reset(new CUartDevice(i, config.deviceNames[i], config.baud[i])); + server.reset(new CUartDevice(i, devname, config.baud[i])); } server->execute(); } - // If no ports have been enabled then redirect port 0 output to host console - if(config.enableMask == 0) { + // Redirect port 0 to console if not otherwise enabled + if(!bitRead(config.enableMask, 0) && !consoleAssigned) { // Redirect the main serial port to console output - smg_uart_set_notify(UART0, onUart0Notify); + smg_uart_set_notify(UART0, uartConsoleNotify); } } @@ -351,7 +364,7 @@ void* CUartPort::thread_routine() host_debug_i("Uart #%u socket open", uart_nr); while(socket->active()) { - if(txsem.timedwait(IDLE_SLEEP_MS)) { + if(txsem.timedwait(IDLE_SLEEP_MS * 1000)) { if(serviceWrite() < 0) { break; } @@ -435,7 +448,7 @@ int CUartDevice::writeBytes(const void* data, size_t size) void* CUartDevice::thread_routine() { while(!done) { - if(txsem.timedwait(IDLE_SLEEP_MS)) { + if(txsem.timedwait(IDLE_SLEEP_MS * 1000)) { if(uart != nullptr && !device) { device.reset(new SerialDevice); char res = device->openDevice(deviceName, uart->baud_rate); diff --git a/Sming/Arch/Host/Components/esp_hal/clk.c b/Sming/Arch/Host/Components/esp_hal/clk.c index 74729ee259..8eedfb078f 100644 --- a/Sming/Arch/Host/Components/esp_hal/clk.c +++ b/Sming/Arch/Host/Components/esp_hal/clk.c @@ -3,15 +3,42 @@ // The current CPU frequency in MHz (ticks per us) static uint8_t cpu_frequency = SYS_CPU_80MHZ; +static uint64_t base_nanos; +static uint32_t base_ccount; + +/* + * Ensure values returned increase monotonically. + */ +static uint32_t get_ccount(uint64_t nanos) +{ + uint32_t ccount; + if(base_nanos == 0) { + base_nanos = nanos; + base_ccount = nanos / cpu_frequency; + ccount = base_ccount; + } else { + ccount = base_ccount + cpu_frequency * ((nanos - base_nanos) / 1000); + } + + return ccount; +} bool system_update_cpu_freq(uint8 freq) { - if(freq == SYS_CPU_80MHZ || freq == SYS_CPU_160MHZ) { - cpu_frequency = freq; + if(freq == cpu_frequency) { return true; - } else { + } + + if(freq != SYS_CPU_80MHZ && freq != SYS_CPU_160MHZ) { return false; } + + uint64_t nanos = os_get_nanoseconds(); + base_ccount = get_ccount(nanos); + base_nanos = nanos; + cpu_frequency = freq; + + return true; } uint8_t ets_get_cpu_frequency(void) @@ -24,19 +51,7 @@ uint8 system_get_cpu_freq(void) return ets_get_cpu_frequency(); } -/* - * The 'correct' conversion is actually: - * - * `os_get_nanoseconds() / (1000UL * cpu_frequency)` - * - * However, in use this just ends up returning 0 all the time which is - * not particularly useful. - * - * On my dev. system a straight nanosecond count gives quite useful - * values when evaluating code paths. Try :sample:`Basic_Delegates`. - * - */ uint32_t esp_get_ccount() { - return os_get_nanoseconds(); + return get_ccount(os_get_nanoseconds()); } diff --git a/Sming/Arch/Host/Components/esp_hal/tasks.cpp b/Sming/Arch/Host/Components/esp_hal/tasks.cpp index 064fe7e860..437d9a6b08 100644 --- a/Sming/Arch/Host/Components/esp_hal/tasks.cpp +++ b/Sming/Arch/Host/Components/esp_hal/tasks.cpp @@ -3,6 +3,8 @@ #include #include +namespace +{ class TaskQueue { public: @@ -40,7 +42,7 @@ class TaskQueue } private: - CMutex mutex; + static CMutex mutex; os_task_t callback; os_event_t* events; uint8_t read; @@ -48,10 +50,13 @@ class TaskQueue uint8_t length; }; -static TaskQueue* task_queues[USER_TASK_PRIO_MAX + 1]; +CMutex TaskQueue::mutex; +TaskQueue* task_queues[USER_TASK_PRIO_MAX + 1]; const uint8_t HOST_TASK_PRIO = USER_TASK_PRIO_MAX; +} // namespace + bool system_os_task(os_task_t callback, uint8_t prio, os_event_t* events, uint8_t qlen) { if(prio >= USER_TASK_PRIO_MAX) { @@ -80,7 +85,12 @@ bool system_os_post(uint8_t prio, os_signal_t sig, os_param_t par) return false; } - return task_queues[prio]->post(sig, par); + if(!task_queues[prio]->post(sig, par)) { + return false; + } + + host_thread_kick(); + return true; } void host_init_tasks() diff --git a/Sming/Arch/Host/Components/esp_wifi/component.mk b/Sming/Arch/Host/Components/esp_wifi/component.mk index bb59c69494..1fd2c3aeb5 100644 --- a/Sming/Arch/Host/Components/esp_wifi/component.mk +++ b/Sming/Arch/Host/Components/esp_wifi/component.mk @@ -5,7 +5,7 @@ COMPONENT_DEPENDS := lwip # Options to add for configuring host network behaviour CACHE_VARS += HOST_NETWORK_OPTIONS HOST_NETWORK_OPTIONS ?= -CLI_TARGET_OPTIONS += $(HOST_NETWORK_OPTIONS) +override CLI_TARGET_OPTIONS += $(HOST_NETWORK_OPTIONS) App-build: esp-wifi-check diff --git a/Sming/Arch/Host/Components/gdbstub/gdbcmds b/Sming/Arch/Host/Components/gdbstub/gdbcmds index ce3dfcdbb9..9b184ee836 100644 --- a/Sming/Arch/Host/Components/gdbstub/gdbcmds +++ b/Sming/Arch/Host/Components/gdbstub/gdbcmds @@ -1,4 +1,5 @@ -handle SIGUSR1 nostop noprint +# Used for interrupt emulation +handle SIG34 SIG35 nostop noprint # Enable this if you want to log all traffic between GDB and the stub #set remotelogfile gdb_rsp_logfile.txt diff --git a/Sming/Arch/Host/Components/hostlib/.cs b/Sming/Arch/Host/Components/hostlib/.cs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Sming/Arch/Host/Components/hostlib/README.rst b/Sming/Arch/Host/Components/hostlib/README.rst index 93f296b454..673def58fe 100644 --- a/Sming/Arch/Host/Components/hostlib/README.rst +++ b/Sming/Arch/Host/Components/hostlib/README.rst @@ -33,20 +33,16 @@ Ideally we'd use SCHED_FIFO to disable time-slicing and more closely resemble ho on a single-core CPU. However, this mode isn't supported in Windows, and Linux requires privileged access and can potentially crash the system. Best avoided, I think. -All ESP code runs at a specific interrupt level, where 0 represents regular code. When an interrupt +All ESP code runs at a specific interrupt level, where 0 represents regular code. +Interrupts are triggered from a separate thread (a CThread instance) which calls :cpp:func:` +When an interrupt occurs, the level is raised according to the priority of that interrupt. Until that code has finished, only interrupts of a higher priority will preempt it. -The ``set_interrupt_level`` function is used to ensure that threads running at different interrupt -levels do not pre-empty each other, as this would introduce problems that do not exist on real hardware. -The main thread is also suspended during interrupt execution. - - -.. envvar:: LWIP_SERVICE_INTERVAL - - Default: 2ms - - LWIP stack is serviced via polling, this determines the interval. +Thread 'interrupt' code is sandwiched between calls to `interrupt_begin()` and `interrupt_end()`, +which blocks interrupts from other threads at the same or lower level. +The threads aren't suspended but will block if they call `interrupt_begin()`. +However, the main thread (level 0) is halted to reflect normal interrupt behaviour. .. envvar:: HOST_PARAMETERS diff --git a/Sming/Arch/Host/Components/hostlib/component.mk b/Sming/Arch/Host/Components/hostlib/component.mk index 36956894c0..4f6ce7af50 100644 --- a/Sming/Arch/Host/Components/hostlib/component.mk +++ b/Sming/Arch/Host/Components/hostlib/component.mk @@ -2,6 +2,8 @@ EXTRA_LIBS := pthread ifeq ($(UNAME),Windows) EXTRA_LIBS += wsock32 +else + EXTRA_LIBS += rt endif COMPONENT_DEPENDS := \ @@ -21,10 +23,5 @@ COMPONENT_INCDIRS := include COMPONENT_SRCDIRS := . COMPONENT_DOXYGEN_INPUT := include/hostlib -# LWIP service interval (milliseconds) -COMPONENT_RELINK_VARS += LWIP_SERVICE_INTERVAL -LWIP_SERVICE_INTERVAL ?= 2 -COMPONENT_CXXFLAGS += -DLWIP_SERVICE_INTERVAL=$(LWIP_SERVICE_INTERVAL) - # Optional command line parameters passed to host application CACHE_VARS += HOST_PARAMETERS diff --git a/Sming/Arch/Host/Components/hostlib/hostapi.h b/Sming/Arch/Host/Components/hostlib/hostapi.h index fd36d917cc..f9fceb5086 100644 --- a/Sming/Arch/Host/Components/hostlib/hostapi.h +++ b/Sming/Arch/Host/Components/hostlib/hostapi.h @@ -19,7 +19,7 @@ #pragma once -#include "hostmsg.h" +#include "include/hostlib/hostmsg.h" #ifdef __cplusplus extern "C" { diff --git a/Sming/Arch/Host/Components/hostlib/hostlib.c b/Sming/Arch/Host/Components/hostlib/hostlib.c index 95c8fa90bb..93d6d00941 100644 --- a/Sming/Arch/Host/Components/hostlib/hostlib.c +++ b/Sming/Arch/Host/Components/hostlib/hostlib.c @@ -31,7 +31,7 @@ int msleep(unsigned ms) size_t getHostAppDir(char* path, size_t bufSize) { - if(path == NULL ||bufSize == 0) { + if(path == NULL || bufSize == 0) { return 0; } diff --git a/Sming/Arch/Host/Components/hostlib/hostmsg.c b/Sming/Arch/Host/Components/hostlib/hostmsg.c index c4be9a91c4..0c561b0fd4 100644 --- a/Sming/Arch/Host/Components/hostlib/hostmsg.c +++ b/Sming/Arch/Host/Components/hostlib/hostmsg.c @@ -18,9 +18,10 @@ ****/ #include +#include #include #include -#include "hostmsg.h" +#include "include/hostlib/hostmsg.h" int host_debug_level = 2; @@ -72,10 +73,10 @@ void host_printfp(const char* fmt, const char* pretty_function, ...) size_t host_nputs(const char* str, size_t length) { - return fwrite(str, 1, length, stderr); + return write(STDERR_FILENO, str, length); } void host_puts(const char* str) { - fputs(str, stderr); + host_nputs(str, strlen(str)); } diff --git a/Sming/Arch/Host/Components/hostlib/include/hostlib/emu.h b/Sming/Arch/Host/Components/hostlib/include/hostlib/emu.h index 5ebda3bce8..24a09ecf4e 100644 --- a/Sming/Arch/Host/Components/hostlib/include/hostlib/emu.h +++ b/Sming/Arch/Host/Components/hostlib/include/hostlib/emu.h @@ -16,8 +16,9 @@ extern "C" { /** * @brief Executing this function will run once the main emulator loop. + * @retval int Milliseconds until next due timer, -1 if none */ -void host_main_loop(); +int host_main_loop(); #ifdef __cplusplus } diff --git a/Sming/Arch/Host/Components/hostlib/hostmsg.h b/Sming/Arch/Host/Components/hostlib/include/hostlib/hostmsg.h similarity index 100% rename from Sming/Arch/Host/Components/hostlib/hostmsg.h rename to Sming/Arch/Host/Components/hostlib/include/hostlib/hostmsg.h diff --git a/Sming/Arch/Host/Components/hostlib/options.cpp b/Sming/Arch/Host/Components/hostlib/options.cpp index bc40b88e12..91beab8a9e 100644 --- a/Sming/Arch/Host/Components/hostlib/options.cpp +++ b/Sming/Arch/Host/Components/hostlib/options.cpp @@ -18,7 +18,7 @@ ****/ #include "options.h" -#include "hostmsg.h" +#include "include/hostlib/hostmsg.h" #include #include #include diff --git a/Sming/Arch/Host/Components/hostlib/options.h b/Sming/Arch/Host/Components/hostlib/options.h index 45e7603d4e..73ef80d6d0 100644 --- a/Sming/Arch/Host/Components/hostlib/options.h +++ b/Sming/Arch/Host/Components/hostlib/options.h @@ -31,8 +31,10 @@ XX(help, no_argument, "Show help", nullptr, nullptr, nullptr) \ XX(uart, required_argument, "Enable UART server", "PORT", "Which UART number to enable", \ "e.g. --uart=0 --uart=1 enable servers for UART0, UART1\0") \ - XX(device, required_argument, "Set device for uart", "DEVICE", "Optionally map uart to device", \ - "e.g. --uart=0 --device=/dev/ttyUSB0\0") \ + XX(device, required_argument, "Set device for uart", "DEVICE", \ + "Optionally map uart to device. Use `console` to change printf target.", \ + "e.g. --uart=0 --device=/dev/ttyUSB0\0" \ + " --uart=1 --device=console\0") \ XX(baud, required_argument, "Set baud rate for UART", "BAUD", "Requires --device argument", \ "e.g. --uart=0 --device=/dev/ttyUSB0 --baud=115200\0") \ XX(portbase, required_argument, "Specify base port number for UART socket servers", "PORT", "IP port number", \ @@ -56,7 +58,8 @@ "Useful for running samples in CI\0") \ XX(nonet, no_argument, "Skip network initialisation", nullptr, nullptr, nullptr) \ XX(debug, required_argument, "Set debug verbosity", "LEVEL", "Maximum debug message level to print", \ - "0 = errors only, 1 = +warnings, 2 = +info\0") + "0 = errors only, 1 = +warnings, 2 = +info\0") \ + XX(cpulimit, required_argument, "Set CPU limit", "COUNT", "0 = no limit", nullptr) enum option_tag_t { #define XX(tag, has_arg, desc, argname, arghelp, examples) opt_##tag, diff --git a/Sming/Arch/Host/Components/hostlib/sockets.cpp b/Sming/Arch/Host/Components/hostlib/sockets.cpp index 5be1025302..4dcc740289 100644 --- a/Sming/Arch/Host/Components/hostlib/sockets.cpp +++ b/Sming/Arch/Host/Components/hostlib/sockets.cpp @@ -18,7 +18,7 @@ ****/ #include "sockets.h" -#include "hostmsg.h" +#include "include/hostlib/hostmsg.h" #include #ifndef __WIN32 diff --git a/Sming/Arch/Host/Components/hostlib/startup.cpp b/Sming/Arch/Host/Components/hostlib/startup.cpp index b36e89f342..8bb37fe968 100644 --- a/Sming/Arch/Host/Components/hostlib/startup.cpp +++ b/Sming/Arch/Host/Components/hostlib/startup.cpp @@ -24,10 +24,12 @@ #include "threads.h" #include "except.h" #include "options.h" +#include #include #include #include #include +#include #include #include #include "include/hostlib/init.h" @@ -35,23 +37,18 @@ #include "include/hostlib/hostlib.h" #include "include/hostlib/CommandLine.h" #include - #include -#include #ifndef DISABLE_NETWORK #include -extern void host_wifi_lwip_init_complete(); -static bool lwip_initialised; #endif +namespace +{ static int exitCode; static bool done; -static OneShotElapseTimer lwipServiceTimer; - -extern void host_init_bootloader(); -static void cleanup() +void cleanup() { hw_timer_cleanup(); host_flashmem_cleanup(); @@ -63,12 +60,15 @@ static void cleanup() host_debug_i("Goodbye!"); } +} // namespace + void host_exit(int code) { static unsigned exit_count; host_debug_i("returning %d", code); exitCode = code; + host_thread_kick(); done = true; if(exit_count++) { @@ -113,58 +113,36 @@ static void pause(int secs) } } -void host_main_loop() +/* + * When there is no work being done we should wait efficiently. + * Tasks and timers can be set from an interrupt (i.e. hardware thread), + * so they can kick a semaphore to wake us up. + */ +int host_main_loop() { - host_service_tasks(); - host_service_timers(); -#ifndef DISABLE_NETWORK - if(lwip_initialised && lwipServiceTimer.expired()) { - host_lwip_service(); - lwipServiceTimer.start(); - } -#endif system_soft_wdt_feed(); + host_service_tasks(); + return host_service_timers(); } int main(int argc, char* argv[]) { trap_exceptions(); - static struct { - int pause; - int exitpause; - bool initonly; + struct Config { + int pause{-1}; + int exitpause{-1}; int loopcount; - bool enable_network; + uint8_t cpulimit; + bool initonly; + bool enable_network{true}; UartServer::Config uart; FlashmemConfig flash; #ifndef DISABLE_NETWORK struct lwip_param lwip; -#endif - } config = { - .pause = -1, - .exitpause = -1, - .initonly = false, - .enable_network = true, - .uart = - { - .enableMask = 0, - .portBase = 0, - }, - .flash = - { - .filename = nullptr, - .createSize = 0, - - }, -#ifndef DISABLE_NETWORK - .lwip = - { - .ifname = nullptr, - .ipaddr = nullptr, - }, #endif }; + static Config config{}; int uart_num{-1}; option_tag_t opt; @@ -257,6 +235,10 @@ int main(int argc, char* argv[]) host_debug_level = atoi(arg); break; + case opt_cpulimit: + config.cpulimit = atoi(arg); + break; + case opt_none: break; } @@ -280,7 +262,7 @@ int main(int argc, char* argv[]) } else { Storage::initialize(); - CThread::startup(); + CThread::startup(config.cpulimit); hw_timer_init(); @@ -291,10 +273,7 @@ int main(int argc, char* argv[]) #ifndef DISABLE_NETWORK if(config.enable_network) { - lwip_initialised = host_lwip_init(&config.lwip); - if(lwip_initialised) { - host_wifi_lwip_init_complete(); - } + host_lwip_init(config.lwip); } else { host_debug_i("Network initialisation skipped as requested"); } @@ -309,19 +288,17 @@ int main(int argc, char* argv[]) host_init(); -#ifndef DISABLE_NETWORK - lwipServiceTimer.reset(); -#endif while(!done) { - host_main_loop(); - if(config.loopcount == 0) { - continue; - } - --config.loopcount; - if(config.loopcount == 0) { - host_debug_i("Reached requested loop count limit: exiting"); - break; + int due = host_main_loop(); + if(config.loopcount != 0) { + --config.loopcount; + if(config.loopcount == 0) { + host_debug_i("Reached requested loop count limit: exiting"); + break; + } } + + host_thread_wait(due); } host_debug_i(">> Normal Exit <<\n"); diff --git a/Sming/Arch/Host/Components/hostlib/threads.cpp b/Sming/Arch/Host/Components/hostlib/threads.cpp index b93160adfb..83aa68ca08 100644 --- a/Sming/Arch/Host/Components/hostlib/threads.cpp +++ b/Sming/Arch/Host/Components/hostlib/threads.cpp @@ -18,72 +18,243 @@ ****/ #include "threads.h" +#include +#include #include +#include -CMutex CThread::interrupt; +unsigned CThread::interrupt_mask; + +namespace +{ +pthread_t mainThread; +CBasicMutex* interrupt; +pthread_cond_t interruptCond = PTHREAD_COND_INITIALIZER; #ifdef __WIN32 -static HANDLE mainThread; +/* + * pthread-win32 implements semaphores with a mutex. + * If it's locked when the main thread is suspended, calling sem_post() from another thread results in deadlock. + * Use a native Windows semaphore to avoid this issue. + */ +HANDLE host_thread_semaphore; #else -static pthread_t mainThread; -static CSemaphore mainThreadSemaphore; +CSemaphore host_thread_semaphore; +volatile bool mainThreadSignalled; +timer_t signalTimer; +int pauseSignal; +int resumeSignal; -static void signal_handler(int sig) +void signal_handler(int sig) { - if(sig == SIGUSR1) { - mainThreadSemaphore.wait(); + if(sig == pauseSignal) { + mainThreadSignalled = true; + /* + * A resumeSignal here results in deadlock as we're waiting for a signal which will never arrive. + * Possibly useful async-safe functions: + * + * - sem_post() + * - alarm(secs) Delivers SIGALRM after a delay. + * - timer_settime() as for alarm() but with smaller interval + * + */ + struct timespec ts = {0, long(0.1e9)}; + struct itimerspec its = {ts, ts}; + timer_settime(signalTimer, 0, &its, nullptr); + while(mainThreadSignalled) { + pause(); + } + its = {}; + timer_settime(signalTimer, 0, &its, nullptr); + } else if(sig == resumeSignal) { + mainThreadSignalled = false; + } else if(sig == SIGALRM) { + } else { + assert(false); } } #endif -void CThread::startup() +bool isMainThread() __attribute__((unused)); +bool isMainThread() { + return pthread_equal(pthread_self(), mainThread); +} + +void suspend_main_thread() +{ + assert(!isMainThread()); + #ifdef __WIN32 - mainThread = OpenThread(THREAD_ALL_ACCESS, FALSE, GetCurrentThreadId()); + SuspendThread(pthread_getw32threadhandle_np(mainThread)); #else - mainThread = pthread_self(); - signal(SIGUSR1, signal_handler); + + assert(!mainThreadSignalled); + int err = pthread_kill(mainThread, pauseSignal); + (void)err; + assert(err == 0); + while(!mainThreadSignalled) { + sched_yield(); + } #endif } -static void suspend_main_thread(bool suspend) +void resume_main_thread() { + assert(!isMainThread()); + #ifdef __WIN32 - if(suspend) { - SuspendThread(mainThread); - } else { - ResumeThread(mainThread); - } + ResumeThread(pthread_getw32threadhandle_np(mainThread)); #else - if(suspend) { - pthread_kill(mainThread, SIGUSR1); - } else { - mainThreadSemaphore.post(); + assert(mainThreadSignalled); + int err = pthread_kill(mainThread, resumeSignal); + (void)err; + assert(err == 0); + while(mainThreadSignalled) { + sched_yield(); } #endif } -void CThread::set_interrupt_level(unsigned new_level) +} // namespace + +void CMutex::lock() { - if(new_level > 0) { - interrupt.lock(); - suspend_main_thread(true); - } else { - suspend_main_thread(false); - interrupt.unlock(); + interrupt->lock(); + CBasicMutex::lock(); +} + +void CMutex::unlock() +{ + CBasicMutex::unlock(); + interrupt->unlock(); +} + +bool CSemaphore::timedwait(unsigned us) +{ + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + uint64_t ns = ts.tv_nsec + uint64_t(us) * 1000; + ts.tv_sec += ns / 1000000000; + ts.tv_nsec = ns % 1000000000; + return timedwait(&ts); +} + +void CThread::startup(unsigned cpulimit) +{ + if(cpulimit != 0) { + cpu_set_t set; + CPU_ZERO(&set); + for(unsigned i = 0; i < cpulimit; ++i) { + CPU_SET(i, &set); + } + if(sched_setaffinity(getpid(), sizeof(set), &set) == 0) { + host_debug_i("Using max. %u CPUs", cpulimit); + } else { + host_debug_e("ERROR! Failed to set CPU affinity"); + } } + + mainThread = pthread_self(); + interrupt = new CBasicMutex; + +#ifdef __WIN32 + host_thread_semaphore = CreateSemaphore(nullptr, 0, 1024, nullptr); +#else + pauseSignal = SIGRTMIN + 0; + resumeSignal = SIGRTMIN + 1; + signal(pauseSignal, signal_handler); + signal(resumeSignal, signal_handler); + signal(SIGALRM, signal_handler); + timer_create(CLOCK_MONOTONIC, nullptr, &signalTimer); +#endif +} + +CThread::CThread(const char* name, unsigned interrupt_level) : name(name), interrupt_level(interrupt_level) +{ + assert(interrupt_level > 0); +} + +CThread::~CThread() +{ + HOST_THREAD_DEBUG("Thread '%s' destroyed", name); } void CThread::interrupt_lock() { - interrupt.lock(); + assert(interrupt_mask == 0); + interrupt->lock(); } void CThread::interrupt_unlock() { - interrupt.unlock(); + assert(interrupt_mask == 0); + interrupt->unlock(); +} + +void CThread::interrupt_begin() +{ + assert(isCurrent()); + + // Block until all equal or higher interrupt levels are done + interrupt->lock(); + while(interrupt_level <= interrupt_mask) { + interrupt->wait(interruptCond); + } + assert(interrupt_level > interrupt_mask); + + if(interrupt_mask == 0) { + suspend_main_thread(); + } + + previous_mask = interrupt_mask; + interrupt_mask = interrupt_level; + + interrupt->unlock(); + pthread_cond_signal(&interruptCond); +} + +void CThread::interrupt_end() +{ + assert(isCurrent()); + + interrupt->lock(); + + interrupt_mask = previous_mask; + + if(interrupt_mask == 0) { + resume_main_thread(); + } + + interrupt->unlock(); +} + +void host_thread_wait(int ms) +{ + constexpr int SCHED_WAIT{2}; + if(ms >= 0 && ms <= SCHED_WAIT) { + return; + } +#ifdef __WIN32 + WaitForSingleObject(host_thread_semaphore, (ms < 0) ? INFINITE : ms - SCHED_WAIT); +#else + if(ms < 0) { + host_thread_semaphore.wait(); + } else if(ms > SCHED_WAIT) { + host_thread_semaphore.timedwait((ms - SCHED_WAIT) * 1000); + } +#endif +} + +void host_thread_kick() +{ +#ifdef __WIN32 + ReleaseSemaphore(host_thread_semaphore, 1, nullptr); +#else + host_thread_semaphore.post(); +#endif } diff --git a/Sming/Arch/Host/Components/hostlib/threads.h b/Sming/Arch/Host/Components/hostlib/threads.h index 9409c5fe6a..b97e708f65 100644 --- a/Sming/Arch/Host/Components/hostlib/threads.h +++ b/Sming/Arch/Host/Components/hostlib/threads.h @@ -20,9 +20,10 @@ #pragma once #include "include/hostlib/hostlib.h" -#include "hostmsg.h" +#include #include #include +#include #if defined(DEBUG_VERBOSE_LEVEL) && (DEBUG_VERBOSE_LEVEL == 3) #define HOST_THREAD_DEBUG(fmt, ...) host_printf(fmt "\n", ##__VA_ARGS__) @@ -30,158 +31,220 @@ #define HOST_THREAD_DEBUG(fmt, ...) #endif -class CMutex; - -class CThread +/** + * @brief Wrapper for posix thread mutex + * + * Note: Don't use this in application code, use `CMutex` as it guards against interrupt deadlocks. + */ +class CBasicMutex { public: - static void startup(); - - // Sets interrupt level for current thread - static void set_interrupt_level(unsigned new_level); - - CThread(const char* name, unsigned interrupt_level) : name(name), interrupt_level(interrupt_level) + ~CBasicMutex() { + pthread_mutex_destroy(&m_priv); } - virtual ~CThread() + void lock() { - HOST_THREAD_DEBUG("Thread '%s' destroyed", name); + pthread_mutex_lock(&m_priv); } - bool execute() + bool tryLock() { - return pthread_create(&m_thread, NULL, thread_start, this) == 0; + return pthread_mutex_trylock(&m_priv) == 0; } - bool detach() + void unlock() { - return pthread_detach(m_thread) == 0; + pthread_mutex_unlock(&m_priv); } - bool cancel() + int wait(pthread_cond_t& cond) { - return pthread_cancel(m_thread) == 0; + return pthread_cond_wait(&cond, &m_priv); } - void join() - { - pthread_join(m_thread, nullptr); - HOST_THREAD_DEBUG("Thread '%s' complete", name); - } +private: + /* + * This behaviour allows threads to lock the mutex multiple times whilst + * blocking other threads. Avoids risk of deadlocks and simplifies code. + */ + pthread_mutex_t m_priv = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; +}; - bool isCurrent() const +/** + * @brief Wrapper for posix thread mutex with interrupt deadlock protection + * + * To simulate interrupts the main thread is suspended, but if this happens whilst it owns + * a mutex then interrupt code can deadlock the application. + * + * This object uses an additional mutex shared with CThread to guard against this. + */ +class CMutex : public CBasicMutex +{ +public: + void lock(); + void unlock(); +}; + +/** + * @brief Wrapper for posix semaphore + */ +class CSemaphore +{ +public: + CSemaphore() { - return pthread_equal(pthread_self(), m_thread) != 0; + sem_init(&m_sem, 0, 0); } - /* - * Called at the start of any code which affects framework variables. - * Will block if any another thread is running in interrupt context. - * - * @todo Only block if another thread is running at the same or higher level - * i.e. high-priority interrupts can pre-empty lower-priority ones. - */ - void interrupt_begin() + ~CSemaphore() { - set_interrupt_level(interrupt_level); + sem_destroy(&m_sem); } - /* - * Allows other waiting threads to resume. - */ - void interrupt_end() + bool post() { - set_interrupt_level(0); + return sem_post(&m_sem) == 0; } - static void interrupt_lock(); - static void interrupt_unlock(); - -protected: - virtual void* thread_routine() = 0; - -private: - static void* thread_start(void* param) + bool wait() { - auto thread = static_cast(param); - HOST_THREAD_DEBUG("Thread '%s' running", thread->name); - return thread->thread_routine(); + return sem_wait(&m_sem) == 0; } -private: - pthread_t m_thread = {0}; - const char* name; // Helps to identify purpose for debugging - unsigned interrupt_level; // Interrupt level associated with this thread - static CMutex interrupt; -}; - -class CMutex -{ -public: - ~CMutex() + bool trywait() { - pthread_mutex_destroy(&m_priv); + return sem_trywait(&m_sem) == 0; } - void lock() + bool timedwait(const struct timespec* abs_timeout) { - pthread_mutex_lock(&m_priv); + return sem_timedwait(&m_sem, abs_timeout) == 0; } - void unlock() + + bool timedwait(unsigned us); + + int value() const { - pthread_mutex_unlock(&m_priv); + int n{0}; + sem_getvalue(const_cast(&m_sem), &n); + return n; } private: - /* - * This behaviour allows threads to lock the mutex multiple times whilst - * blocking other threads. Avoids risk of deadlocks and simplifies code. - */ - pthread_mutex_t m_priv = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; + sem_t m_sem; }; -class CSemaphore +/** + * @brief Class to manage separate execution thread for simulating hardware and interrupts. + */ +class CThread { public: - CSemaphore() + static void startup(unsigned cpulimit = 0); + + /** + * @brief Construct a new CThread object + * @param name Name of thread (for debugging) + * @param interrupt_level Must be > 0. Higher values can interrupt threads of lower levels. + */ + CThread(const char* name, unsigned interrupt_level); + + virtual ~CThread(); + + bool execute() { - sem_init(&m_sem, 0, 0); + return pthread_create(&m_thread, NULL, thread_start, this) == 0; } - ~CSemaphore() + bool detach() { - sem_destroy(&m_sem); + return pthread_detach(m_thread) == 0; } - bool post() + bool cancel() { - return sem_post(&m_sem) == 0; + return pthread_cancel(m_thread) == 0; } - bool wait() + void join() { - return sem_wait(&m_sem) == 0; + pthread_join(m_thread, nullptr); + HOST_THREAD_DEBUG("Thread '%s' complete", name); } - bool trywait() + /** + * @brief Determine if running in the context of this thread + */ + bool isCurrent() const { - return sem_trywait(&m_sem) == 0; + return pthread_equal(pthread_self(), m_thread) != 0; } - bool timedwait(const struct timespec* abs_timeout) + /** + * @brief A thread calls this method before issuing an 'interrupt'. + * + * Will block if any another thread is running interrupt code at the same or higher level. + * i.e. high-priority interrupts can pre-empty lower-priority ones. + */ + void interrupt_begin(); + + /** + * @brief Signals end of interrupt code and allows other waiting threads to issue interrupts + */ + void interrupt_end(); + + /** + * @brief Prevent all interrupts + */ + static void interrupt_lock(); + + /** + * @brief Resume interrupts + */ + static void interrupt_unlock(); + + bool operator==(pthread_t other) const { - return sem_timedwait(&m_sem, abs_timeout) == 0; + return pthread_equal(other, m_thread); } - bool timedwait(unsigned ms) + /** + * @brief Get name of the currently executing thread + */ + static const char* getCurrentName(); + +protected: + /** + * @brief Inherited classes must implement this method + */ + virtual void* thread_routine() = 0; + +private: + static void* thread_start(void* param) { - timespec to; - to.tv_sec = ms / 1000; - to.tv_nsec = (ms % 1000) * 1000000; - return timedwait(&to); + auto thread = static_cast(param); + HOST_THREAD_DEBUG("Thread '%s' running", thread->name); + return thread->thread_routine(); } private: - sem_t m_sem; + pthread_t m_thread = {0}; + const char* name; ///< Helps to identify purpose for debugging + unsigned interrupt_level; ///< Interrupt level associated with this thread + unsigned previous_mask{0}; ///< Used to restore previous interrupt mask when interrupt ends + static unsigned interrupt_mask; ///< Current interrupt level }; + +/* + * Called from main loop + * @param ms Time in milliseconds until next schedule timer event, + * negative if no timers have been scheduled. + */ +void host_thread_wait(int ms); + +/* + * Cancels wait, e.g. when new event is posted to queue + */ +void host_thread_kick(); diff --git a/Sming/Arch/Host/Components/lwip/Linux/host_lwip.c b/Sming/Arch/Host/Components/lwip/Linux/host_lwip.c deleted file mode 100644 index 9c84f4fe9a..0000000000 --- a/Sming/Arch/Host/Components/lwip/Linux/host_lwip.c +++ /dev/null @@ -1,180 +0,0 @@ -/** - * host_lwip.cpp - * - * Copyright 2019 mikee47 - * - * This file is part of the Sming Framework Project - * - * This library is free software: you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation, version 3 or later. - * - * 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with SHEM. - * If not, see . - * - ****/ - -#include "../host_lwip.h" -#include "../../hostlib/hostmsg.h" - -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -struct net_config { - char ifname[32]; - ip4_addr_t ipaddr; - ip4_addr_t netmask; - ip4_addr_t gw; -}; - -static struct netif netif; - -static void getMacAddress(const char* ifname, uint8_t hwaddr[6]) -{ - if(ifname == NULL) { - return; - } - - struct ifreq ifr = {0}; - ifr.ifr_addr.sa_family = AF_INET; - strncpy(ifr.ifr_name, ifname, IFNAMSIZ); - ifr.ifr_name[IFNAMSIZ - 1] = '\0'; - - int fd = socket(AF_INET, SOCK_DGRAM, 0); - int res = ioctl(fd, SIOCGIFHWADDR, &ifr); - close(fd); - - if(res == 0) { - memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, 6); - } else { - memset(hwaddr, 0, 6); - } -} - -/** - * @brief Fetch address and network mask for an interface - * @param ifname NULL to get first compatible interface - */ -static bool getifaddr(const char* ifname, struct net_config* netcfg) -{ - struct ifaddrs* list; - if(getifaddrs(&list) < 0) { - host_debug_e("getifaddrs: %s", strerror(errno)); - return false; - } - - bool res = false; - - for(struct ifaddrs* ifa = list; ifa != NULL; ifa = ifa->ifa_next) { - if(ifa->ifa_addr == NULL) { - continue; - } - if(ifa->ifa_addr->sa_family != AF_INET) { - continue; - } - - if(ifname == NULL) { - if(memcmp(ifa->ifa_name, "tap", 3) != 0) { - continue; - } - } else if(strcmp(ifa->ifa_name, ifname) != 0) { - continue; - } - - strcpy(netcfg->ifname, ifa->ifa_name); - netcfg->gw.addr = ((struct sockaddr_in*)ifa->ifa_addr)->sin_addr.s_addr; - netcfg->netmask.addr = ((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr.s_addr; - - res = true; - break; - } - - freeifaddrs(list); - return res; -} - -bool host_lwip_init(const struct lwip_param* param) -{ - host_debug_i("%s", "Initialising LWIP"); - - struct net_config netcfg = {0}; - - if(!getifaddr(param->ifname, &netcfg)) { - if(param->ifname == NULL) { - host_debug_e("%s", "No compatible interface found"); - } else { - host_debug_e("Interface '%s' not found", param->ifname); - } - return false; - } - - if(param->gateway != NULL && ip4addr_aton(param->gateway, &netcfg.gw) != 1) { - host_debug_e("Failed to parse provided Gateway address '%s'", param->gateway); - return false; - } - - if(param->netmask != NULL && ip4addr_aton(param->netmask, &netcfg.netmask) != 1) { - host_debug_e("Failed to parse provided Network Mask '%s'", param->netmask); - return false; - } - - if(param->ipaddr == NULL) { - // Choose a default IP address - IP4_ADDR(&netcfg.ipaddr, (uint32_t)ip4_addr1(&netcfg.gw), (uint32_t)ip4_addr2(&netcfg.gw), - (uint32_t)ip4_addr3(&netcfg.gw), 10U); - } else if(ip4addr_aton(param->ipaddr, &netcfg.ipaddr) != 1) { - host_debug_e("Failed to parse provided IP address '%s'", param->ipaddr); - return false; - } - - char ip_str[IP4ADDR_STRLEN_MAX]; - ip4addr_ntoa_r(&netcfg.ipaddr, ip_str, sizeof(ip_str)); - char nm_str[IP4ADDR_STRLEN_MAX]; - ip4addr_ntoa_r(&netcfg.netmask, nm_str, sizeof(nm_str)); - char gw_str[IP4ADDR_STRLEN_MAX]; - ip4addr_ntoa_r(&netcfg.gw, gw_str, sizeof(gw_str)); - host_debug_i("Using interface '%s', gateway = %s, netmask = %s; using ip = %s", netcfg.ifname, gw_str, nm_str, - ip_str); - - setenv("PRECONFIGURED_TAPIF", netcfg.ifname, true); - - lwip_init(); - - netif_add(&netif, &netcfg.ipaddr, &netcfg.netmask, &netcfg.gw, NULL, tapif_init, ethernet_input); - - getMacAddress(netcfg.ifname, netif.hwaddr); - host_debug_i("MAC: %02x:%02x:%02x:%02x:%02x:%02x", netif.hwaddr[0], netif.hwaddr[1], netif.hwaddr[2], - netif.hwaddr[3], netif.hwaddr[4], netif.hwaddr[5]); - - netif_set_default(&netif); - - return true; -} - -void host_lwip_service(void) -{ - /* poll netif, pass packet to lwIP */ - tapif_select(&netif); - netif_poll(&netif); - sys_check_timeouts(); -} - -void host_lwip_shutdown(void) -{ -} diff --git a/Sming/Arch/Host/Components/lwip/Windows/.gitignore b/Sming/Arch/Host/Components/lwip/Windows/.gitignore deleted file mode 100644 index 667fe0a3ad..0000000000 --- a/Sming/Arch/Host/Components/lwip/Windows/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -src -tmp diff --git a/Sming/Arch/Host/Components/lwip/component.mk b/Sming/Arch/Host/Components/lwip/component.mk deleted file mode 100644 index a92eaaa254..0000000000 --- a/Sming/Arch/Host/Components/lwip/component.mk +++ /dev/null @@ -1,39 +0,0 @@ -# Uses cmake to build -CUSTOM_BUILD := 1 - -# => LWIP -ifndef MAKE_CLEAN -ifndef ENABLE_CUSTOM_LWIP -ENABLE_CUSTOM_LWIP := 2 -else ifneq ($(ENABLE_CUSTOM_LWIP), 2) -$(error Host only supports LWIP version 2) -endif -endif - -COMPONENT_SUBMODULES := lwip -COMPONENT_INCDIRS := . lwip/src/include -COMPONENT_VARS += ENABLE_LWIPDEBUG -ENABLE_LWIPDEBUG ?= 0 -ifeq ($(ENABLE_LWIPDEBUG), 1) - CMAKE_OPTIONS := -DCMAKE_BUILD_TYPE=Debug -else - CMAKE_OPTIONS := -DCMAKE_BUILD_TYPE=Release -endif - -ifeq ($(SMING_RELEASE),1) - CMAKE_OPTIONS += -DLWIP_NOASSERT=1 -endif - -ifeq ($(UNAME),Windows) - COMPONENT_INCDIRS += lwip/contrib/ports/win32/include - CMAKE_OPTIONS += -G "MSYS Makefiles" -else - COMPONENT_INCDIRS += lwip/contrib/ports/unix/port/include -endif - -CMAKE_OPTIONS += -DLWIP_LIBNAME=$(COMPONENT_VARIANT) -CMAKE_OPTIONS += -DCMAKE_C_COMPILER=$(CC) - -$(COMPONENT_RULE)$(COMPONENT_LIBPATH): - $(Q) $(CMAKE) -DUSER_LIBDIR=$(COMPONENT_LIBDIR) $(CMAKE_OPTIONS) $(COMPONENT_PATH)/$(UNAME) - $(Q) $(MAKE) diff --git a/Sming/Arch/Host/Components/lwip/lwip b/Sming/Arch/Host/Components/lwip/lwip deleted file mode 160000 index dae8eb8d6e..0000000000 --- a/Sming/Arch/Host/Components/lwip/lwip +++ /dev/null @@ -1 +0,0 @@ -Subproject commit dae8eb8d6e210ecf9b75ec9539ba243f1ef096da diff --git a/Sming/Arch/Host/Components/vflash/component.mk b/Sming/Arch/Host/Components/vflash/component.mk index 65f9df027a..d70bebe643 100644 --- a/Sming/Arch/Host/Components/vflash/component.mk +++ b/Sming/Arch/Host/Components/vflash/component.mk @@ -13,7 +13,7 @@ SPI_SIZE = $(STORAGE_DEVICE_spiFlash_SIZE) # Options to add when running emulator CACHE_VARS += HOST_FLASH_OPTIONS HOST_FLASH_OPTIONS ?= --flashfile=$(FLASH_BIN) --flashsize=$(SPI_SIZE) -CLI_TARGET_OPTIONS += $(HOST_FLASH_OPTIONS) +override CLI_TARGET_OPTIONS += $(HOST_FLASH_OPTIONS) # Virtual flasher tool VFLASH := $(PYTHON) $(COMPONENT_PATH)/vflash.py $(FLASH_BIN) $(STORAGE_DEVICE_spiFlash_SIZE_BYTES) diff --git a/Sming/Arch/Host/Core/SPI.cpp b/Sming/Arch/Host/Core/SPI.cpp deleted file mode 100644 index 104f2b2821..0000000000 --- a/Sming/Arch/Host/Core/SPI.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "SPI.h" - -SPIClass SPI; - -bool SPIClass::begin() -{ - return false; -} - -void SPIClass::transfer(uint8_t* buffer, size_t numberBytes) -{ -} - -void SPIClass::prepare(SPISettings& settings) -{ -} diff --git a/Sming/Arch/Host/Core/SPI.h b/Sming/Arch/Host/Core/SPI.h deleted file mode 100644 index 3097d03df8..0000000000 --- a/Sming/Arch/Host/Core/SPI.h +++ /dev/null @@ -1,55 +0,0 @@ -/**** - * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. - * Created 2015 by Skurydin Alexey - * http://github.com/SmingHub/Sming - * All files of the Sming Core are provided under the LGPL v3 license. - * - * SPI.h - */ - -/** @defgroup hw_spi SPI Hardware support - * @brief Provides hardware SPI support - */ - -#pragma once - -#include "SPIBase.h" -#include "SPISettings.h" - -//#define SPI_DEBUG 1 - -// for compatibility when porting from Arduino -#define SPI_HAS_TRANSACTION 0 - -/** - * @brief Hardware SPI object - * @addtogroup hw_spi - * @{ - */ - -class SPIClass : public SPIBase -{ -public: - SPIClass() - { - } - - SPIClass(const SPIClass&) = delete; - SPIClass& operator=(const SPIClass&) = delete; - - bool begin() override; - - void end() override - { - } - - using SPIBase::beginTransaction; - using SPIBase::transfer; - void transfer(uint8_t* buffer, size_t numberBytes) override; - -protected: - void prepare(SPISettings& settings) override; -}; - -/** @brief Global instance of SPI class */ -extern SPIClass SPI; diff --git a/Sming/Arch/Host/Platform/RTC.cpp b/Sming/Arch/Host/Platform/RTC.cpp index bfe723b1f3..6d93b702be 100644 --- a/Sming/Arch/Host/Platform/RTC.cpp +++ b/Sming/Arch/Host/Platform/RTC.cpp @@ -14,6 +14,11 @@ RtcClass RTC; +namespace +{ +int timeDiff; // Difference between set time and system time +} + RtcClass::RtcClass() { } @@ -30,7 +35,7 @@ uint32_t RtcClass::getRtcSeconds() { struct timeval tv; gettimeofday(&tv, nullptr); - return tv.tv_sec; + return tv.tv_sec + timeDiff; } bool RtcClass::setRtcNanoseconds(uint64_t nanoseconds) @@ -40,5 +45,7 @@ bool RtcClass::setRtcNanoseconds(uint64_t nanoseconds) bool RtcClass::setRtcSeconds(uint32_t seconds) { - return false; + timeDiff = 0; + timeDiff = seconds - getRtcSeconds(); + return true; } diff --git a/Sming/Arch/Host/README.rst b/Sming/Arch/Host/README.rst index 9326a585eb..d4fc206122 100644 --- a/Sming/Arch/Host/README.rst +++ b/Sming/Arch/Host/README.rst @@ -33,8 +33,6 @@ Building Build the framework and application as usual, specifying :envvar:`SMING_ARCH` =Host. For example:: - cd $SMING_HOME - make SMING_ARCH=Host cd $SMING_HOME/../samples/Basic_Serial make SMING_ARCH=Host @@ -48,6 +46,18 @@ used to pass the appropriate options to the command line. To find out what options are in force, use ``make list-config``. +Configuration +------------- + +.. envvar:: CLI_TARGET_OPTIONS + + Use this to add any custom options to the emulator command line. e.g.: + + make run CLI_TARGET_OPTIONS=--help + make run CLI_TARGET_OPTIONS="--debug=0 --cpulimit=2" + + Note: These settings are not 'sticky' + Components ---------- diff --git a/Sming/Arch/Rp2040/Components/driver/include/driver/hw_timer.h b/Sming/Arch/Rp2040/Components/driver/include/driver/hw_timer.h index 2d2270ec9e..f8cc61272b 100644 --- a/Sming/Arch/Rp2040/Components/driver/include/driver/hw_timer.h +++ b/Sming/Arch/Rp2040/Components/driver/include/driver/hw_timer.h @@ -13,6 +13,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + #define HW_TIMER_BASE_CLK 1000000U /** @@ -44,7 +48,7 @@ __forceinline uint32_t IRAM_ATTR hw_timer_ticks() /** * @brief Maximum timer interval in ticks */ -#define MAX_HW_TIMER1_INTERVAL 0x7fffffff +#define MAX_HW_TIMER1_INTERVAL 0x7fffffffU /** * @brief Minimum hardware interval in microseconds @@ -81,7 +85,7 @@ struct hw_timer_private_t { void* timer1_arg; }; -extern hw_timer_private_t hw_timer_private; +extern struct hw_timer_private_t hw_timer_private; /** * @brief Attach an interrupt for the timer @@ -142,7 +146,7 @@ __forceinline uint32_t hw_timer1_read() * *************************************/ -constexpr uint32_t HW_TIMER2_CLK = HW_TIMER_BASE_CLK; +#define HW_TIMER2_CLK HW_TIMER_BASE_CLK /** * @brief Read current timer2 value @@ -154,3 +158,7 @@ __forceinline uint32_t hw_timer2_read() } /** @} */ + +#ifdef __cplusplus +} +#endif diff --git a/Sming/Arch/Rp2040/Components/driver/uart.cpp b/Sming/Arch/Rp2040/Components/driver/uart.cpp index 03e99c0bdf..ecb8a3e076 100644 --- a/Sming/Arch/Rp2040/Components/driver/uart.cpp +++ b/Sming/Arch/Rp2040/Components/driver/uart.cpp @@ -95,32 +95,6 @@ __forceinline void uart_enable_isr(uint8_t nr) irq_set_enabled(UART0_IRQ + nr, true); } -bool realloc_buffer(SerialBuffer*& buffer, size_t new_size) -{ - if(buffer != nullptr) { - if(new_size == 0) { - delete buffer; - buffer = nullptr; - return true; - } - - return buffer->resize(new_size) == new_size; - } - - if(new_size == 0) { - return true; - } - - auto new_buf = new SerialBuffer; - if(new_buf != nullptr && new_buf->resize(new_size) == new_size) { - buffer = new_buf; - return true; - } - - delete new_buf; - return false; -} - void IRAM_ATTR handleInterrupt(smg_uart_t* uart, uart_dev_t* dev) { auto mis = dev->mis; @@ -281,55 +255,6 @@ void smg_uart_set_callback(smg_uart_t* uart, smg_uart_callback_t callback, void* } } -size_t smg_uart_resize_rx_buffer(smg_uart_t* uart, size_t new_size) -{ - if(smg_uart_rx_enabled(uart)) { - uart_disable_isr(uart->uart_nr); - realloc_buffer(uart->rx_buffer, new_size); - uart_enable_isr(uart->uart_nr); - } - return smg_uart_rx_buffer_size(uart); -} - -size_t smg_uart_rx_buffer_size(smg_uart_t* uart) -{ - return uart != nullptr && uart->rx_buffer != nullptr ? uart->rx_buffer->getSize() : 0; -} - -size_t smg_uart_resize_tx_buffer(smg_uart_t* uart, size_t new_size) -{ - if(smg_uart_tx_enabled(uart)) { - uart_disable_isr(uart->uart_nr); - realloc_buffer(uart->tx_buffer, new_size); - uart_enable_isr(uart->uart_nr); - } - return smg_uart_tx_buffer_size(uart); -} - -size_t smg_uart_tx_buffer_size(smg_uart_t* uart) -{ - return uart != nullptr && uart->tx_buffer != nullptr ? uart->tx_buffer->getSize() : 0; -} - -int smg_uart_peek_char(smg_uart_t* uart) -{ - return uart != nullptr && uart->rx_buffer ? uart->rx_buffer->peekChar() : -1; -} - -int smg_uart_rx_find(smg_uart_t* uart, char c) -{ - if(uart == nullptr || uart->rx_buffer == nullptr) { - return -1; - } - - return uart->rx_buffer->find(c); -} - -int smg_uart_peek_last_char(smg_uart_t* uart) -{ - return uart != nullptr && uart->rx_buffer != nullptr ? uart->rx_buffer->peekLastChar() : -1; -} - size_t smg_uart_read(smg_uart_t* uart, void* buffer, size_t size) { if(!smg_uart_rx_enabled(uart) || buffer == nullptr || size == 0) { @@ -659,7 +584,7 @@ smg_uart_t* smg_uart_init_ex(const smg_uart_config_t& cfg) auto txBufferSize = cfg.tx_size; if(smg_uart_rx_enabled(uart)) { - if(!realloc_buffer(uart->rx_buffer, rxBufferSize)) { + if(!smg_uart_realloc_buffer(uart->rx_buffer, rxBufferSize)) { delete uart; return nullptr; } @@ -669,7 +594,7 @@ smg_uart_t* smg_uart_init_ex(const smg_uart_config_t& cfg) } if(smg_uart_tx_enabled(uart)) { - if(!realloc_buffer(uart->tx_buffer, txBufferSize)) { + if(!smg_uart_realloc_buffer(uart->tx_buffer, txBufferSize)) { delete uart->rx_buffer; delete uart; return nullptr; @@ -687,19 +612,9 @@ smg_uart_t* smg_uart_init_ex(const smg_uart_config_t& cfg) smg_uart_detach(cfg.uart_nr); smg_uart_set_baudrate(uart, cfg.baudrate); - auto dev = getDevice(cfg.uart_nr); + smg_uart_set_format(uart, cfg.format); - // Setup line control register - smg_uart_config_format_t fmt; - fmt.val = cfg.config; - uint32_t lcr{0}; - lcr |= fmt.bits << UART_UARTLCR_H_WLEN_LSB; // data bits - if(fmt.stop_bits != UART_NB_STOP_BIT_1) { // stop bits - lcr |= UART_UARTLCR_H_STP2_BITS; - } - lcr |= fmt.parity << UART_UARTLCR_H_PEN_LSB; // parity - lcr |= UART_UARTLCR_H_FEN_BITS; // Enable FIFOs - dev->lcr_h = lcr; + auto dev = getDevice(cfg.uart_nr); // Enable the UART if(uart->mode == UART_TX_ONLY) { @@ -747,19 +662,32 @@ void smg_uart_uninit(smg_uart_t* uart) delete uart; } -smg_uart_t* smg_uart_init(uint8_t uart_nr, uint32_t baudrate, uint32_t config, smg_uart_mode_t mode, uint8_t tx_pin, - size_t rx_size, size_t tx_size) +void smg_uart_set_format(smg_uart_t* uart, smg_uart_format_t format) +{ + if(uart == nullptr) { + return; + } + + auto dev = getDevice(uart->uart_nr); + + // Setup line control register + smg_uart_config_format_t fmt{.val = format}; + uint32_t lcr{0}; + lcr |= fmt.bits << UART_UARTLCR_H_WLEN_LSB; // data bits + if(fmt.stop_bits != UART_NB_STOP_BIT_1) { // stop bits + lcr |= UART_UARTLCR_H_STP2_BITS; + } + lcr |= fmt.parity << UART_UARTLCR_H_PEN_LSB; // parity + lcr |= UART_UARTLCR_H_FEN_BITS; // Enable FIFOs + dev->lcr_h = lcr; +} + +bool smg_uart_intr_config(smg_uart_t* uart, const smg_uart_intr_config_t* config) { - smg_uart_config_t cfg = {.uart_nr = uart_nr, - .tx_pin = tx_pin, - .rx_pin = UART_PIN_DEFAULT, - .mode = mode, - .options = _BV(UART_OPT_TXWAIT), - .baudrate = baudrate, - .config = config, - .rx_size = rx_size, - .tx_size = tx_size}; - return smg_uart_init_ex(cfg); + // Not supported + (void)uart; + (void)config; + return false; } void smg_uart_swap(smg_uart_t* uart, int tx_pin) diff --git a/Sming/Arch/Rp2040/Components/rp2040/component.mk b/Sming/Arch/Rp2040/Components/rp2040/component.mk index cca3b2e132..fc87b4cd6a 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/component.mk +++ b/Sming/Arch/Rp2040/Components/rp2040/component.mk @@ -38,6 +38,7 @@ SDK_INTERFACES := \ common/pico_bit_ops \ common/pico_divider \ common/pico_sync \ + common/pico_time \ common/pico_util \ rp2040/hardware_regs \ rp2040/hardware_structs \ @@ -52,10 +53,12 @@ SDK_INTERFACES := \ rp2_common/hardware_exception \ rp2_common/hardware_flash \ rp2_common/hardware_irq \ + rp2_common/hardware_pio \ rp2_common/hardware_resets \ rp2_common/hardware_rosc \ rp2_common/hardware_rtc \ rp2_common/hardware_pll \ + rp2_common/hardware_spi \ rp2_common/hardware_vreg \ rp2_common/hardware_watchdog \ rp2_common/hardware_xosc \ @@ -89,11 +92,6 @@ EXTRA_LIBS += \ pico \ m -ifdef NINJA -NINJA := $(call FixPath,$(NINJA)) -else -NINJA := ninja -endif RP2040_CMAKE_OPTIONS := \ -G Ninja \ -DCMAKE_MAKE_PROGRAM=$(NINJA) diff --git a/Sming/Arch/Rp2040/Components/rp2040/pico-sdk b/Sming/Arch/Rp2040/Components/rp2040/pico-sdk index bfcbefafc5..0f67a6c00c 160000 --- a/Sming/Arch/Rp2040/Components/rp2040/pico-sdk +++ b/Sming/Arch/Rp2040/Components/rp2040/pico-sdk @@ -1 +1 @@ -Subproject commit bfcbefafc5d2a210551a4d9d80b4303d4ae0adf7 +Subproject commit 0f67a6c00c05e60c34fe1f35a835a133d3e12872 diff --git a/Sming/Arch/Rp2040/Components/rp2040/pico-sdk.patch b/Sming/Arch/Rp2040/Components/rp2040/pico-sdk.patch index 405be571b1..dcc9f8dde5 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/pico-sdk.patch +++ b/Sming/Arch/Rp2040/Components/rp2040/pico-sdk.patch @@ -1,8 +1,8 @@ diff --git a/src/rp2_common/pico_platform/include/pico/platform.h b/src/rp2_common/pico_platform/include/pico/platform.h -index c008b95..bf5a690 100644 +index 596b0db..0fb309f 100644 --- a/src/rp2_common/pico_platform/include/pico/platform.h +++ b/src/rp2_common/pico_platform/include/pico/platform.h -@@ -146,7 +146,7 @@ static inline void tight_loop_contents(void) {} +@@ -357,7 +357,7 @@ static __force_inline void tight_loop_contents(void) {} * \return a * b */ __force_inline static int32_t __mul_instruction(int32_t a, int32_t b) { diff --git a/Sming/Arch/Rp2040/Components/rp2040/src/clk.c b/Sming/Arch/Rp2040/Components/rp2040/src/clk.c index d53a5dc366..6abc297851 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/src/clk.c +++ b/Sming/Arch/Rp2040/Components/rp2040/src/clk.c @@ -17,12 +17,12 @@ static void IRAM_ATTR systick_overflow_isr() uint32_t IRAM_ATTR esp_get_ccount() { - extern volatile uint32_t systick_overflow; uint32_t ovf = systick_overflow; if(ovf != systick_overflow) { ovf = systick_overflow; } - return systick_hw->cvr | (ovf << 24); + // CVR is a down-counter + return ((1 + ovf) << 24) - systick_hw->cvr; } /*! \brief Check if a given system clock frequency is valid/attainable diff --git a/Sming/Arch/Rp2040/Components/spi_flash/flashmem.cpp b/Sming/Arch/Rp2040/Components/spi_flash/flashmem.cpp index 641d1fde4d..54d7f4a599 100644 --- a/Sming/Arch/Rp2040/Components/spi_flash/flashmem.cpp +++ b/Sming/Arch/Rp2040/Components/spi_flash/flashmem.cpp @@ -139,7 +139,7 @@ uint32_t readAligned(void* to, uint32_t fromaddr, uint32_t size) * Use the auxiliary bus slave for the DMA<-FIFO accesses, to avoid stalling * the DMA against general XIP traffic. */ - constexpr unsigned dma_chan{0}; + auto dma_chan = dma_claim_unused_channel(true); dma_channel_config cfg = dma_channel_get_default_config(dma_chan); channel_config_set_transfer_data_size(&cfg, dmaTransferSize); channel_config_set_read_increment(&cfg, false); @@ -153,6 +153,7 @@ uint32_t readAligned(void* to, uint32_t fromaddr, uint32_t size) ); dma_channel_wait_for_finish_blocking(dma_chan); + dma_channel_unclaim(dma_chan); return size; } diff --git a/Sming/Arch/Rp2040/Core/SPI.cpp.todo b/Sming/Arch/Rp2040/Core/SPI.cpp.todo deleted file mode 100644 index a566605f3f..0000000000 --- a/Sming/Arch/Rp2040/Core/SPI.cpp.todo +++ /dev/null @@ -1,345 +0,0 @@ -/**** - * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. - * Created 2015 by Skurydin Alexey - * http://github.com/SmingHub/Sming - * All files of the Sming Core are provided under the LGPL v3 license. - * - * SPI.cpp - * - * Created on: Mar 2, 2016 - * Author: harry-boe - * - * Some code is derived from: - * David Ogilvy (MetalPhreak) - * - ****/ - -#include "SPI.h" -#include -#include "espinc/eagle_soc.h" -#include "espinc/spi_register.h" - -// define the static singleton -SPIClass SPI; - -namespace -{ -// Used internally to calculate optimum SPI speed -struct SpiPreDiv { - unsigned freq; - unsigned prescale; - unsigned divisor; -}; - -/** - * @brief Wait until HSPI has finished any current transaction - */ -__forceinline void spi_wait() -{ - while(READ_PERI_REG(SPI_CMD(SPI_NO)) & SPI_USR) { - // - } -} - -/** - * @brief Initiate an HSPI user transaction - */ -__forceinline void spi_send() -{ - SET_PERI_REG_MASK(SPI_CMD(SPI_NO), SPI_USR); -} - -/** - * @brief Configure SPI mode parameters for clock edge and clock polarity. - * - * Private method used by SPISetings - * - * @param SPI_MODE0 .. SPI_MODE4 - * - * Mode Clock Polarity (CPOL) Clock Phase (CPHA) - * SPI_MODE0 0 0 - * SPI_MODE1 0 1 - * SPI_MODE2 1 0 - * SPI_MODE3 1 1 - */ -void spi_mode(uint8_t mode) -{ - uint8_t spi_cpha = mode & 0x0F; - uint8_t spi_cpol = mode & 0xF0; - -#ifdef SPI_DEBUG - debugf("SPIClass::spi_mode(mode %x) spi_cpha %X,spi_cpol %X)", mode, spi_cpha, spi_cpol); -#endif - - if(spi_cpha == spi_cpol) { - CLEAR_PERI_REG_MASK(SPI_USER(SPI_NO), SPI_CK_OUT_EDGE); - } else { - SET_PERI_REG_MASK(SPI_USER(SPI_NO), SPI_CK_OUT_EDGE); - } - - if(spi_cpol) { - SET_PERI_REG_MASK(SPI_PIN(SPI_NO), SPI_IDLE_EDGE); - } else { - CLEAR_PERI_REG_MASK(SPI_PIN(SPI_NO), SPI_IDLE_EDGE); - } -} - -/** - * @brief Setup the byte order for shifting data out of buffer - * - * Private method used by SPISetings - * - * @param MSBFIRST 1 - * Data is sent out starting with Bit31 and down to Bit0 - * LSBFIRST 0 - * Data is sent out starting with the lowest BYTE, from MSB to LSB - * 0xABCDEFGH would be sent as 0xGHEFCDAB - */ -void spi_byte_order(uint8_t byte_order) -{ -#ifdef SPI_DEBUG - debugf("SPIClass::spi_byte_order(byte_order %u)", byte_order); -#endif - - if(byte_order) { - SET_PERI_REG_MASK(SPI_USER(SPI_NO), SPI_WR_BYTE_ORDER); - SET_PERI_REG_MASK(SPI_USER(SPI_NO), SPI_RD_BYTE_ORDER); - } else { - CLEAR_PERI_REG_MASK(SPI_USER(SPI_NO), SPI_WR_BYTE_ORDER); - CLEAR_PERI_REG_MASK(SPI_USER(SPI_NO), SPI_RD_BYTE_ORDER); - } -} - -/** - * @brief Calculate the closest prescale value for a given frequency and clock-divider - * @param cpuFreq current CPU frequency, in Hz - * @param freq target SPI bus frequency, in Hz - * @param div divisor value to use - * @retval SpiPreDiv contains resulting frequency, prescaler and divisor values - */ -SpiPreDiv calculateSpeed(unsigned cpuFreq, unsigned freq, unsigned div) -{ - SpiPreDiv prediv; - unsigned pre = cpuFreq / (freq * div); - if(pre == 0) { - pre = 1; - } - unsigned n = pre * div; - while(true) { - prediv.freq = cpuFreq / n; - if(prediv.freq <= freq) { - break; - } - ++pre; - n += div; - } - prediv.prescale = pre; - prediv.divisor = div; - -#ifdef SPI_DEBUG - debugf("SPI calculateSpeed(uint freq %u, uint pre %u, uint div %u)", f, pre, div); -#endif - - return prediv; -} - -/** @brief Check speed settings and perform any pre-calculation required - * @param speed IN: requested bus frequency, OUT: Modified settings with prescale values - * @note - * The algorithm is testing with clock dividers 2,3 and 5 to find the best pre-divider - * The resulting clock frequency is not 100% accurate but delivers result within 5% - * - * It is guaranteed that the frequency will not exceed the given target - * - * Make sure that the ESP clock frequency is set before initializing the SPI bus. - * Changes on the ESP clock are not recognised once initialized - */ -void checkSpeed(SPISpeed& speed) -{ - unsigned cpuFreq = system_get_cpu_freq() * 1000000UL; -#ifdef SPI_DEBUG - debugf("SPIClass::calculateSpeed() -> current cpu frequency %u", cpuFreq); -#endif - - SpiPreDiv prediv; - - // If we're not running at max then need to determine appropriate prescale values - if(speed.frequency >= cpuFreq) { - // Use maximum speed - prediv.freq = cpuFreq; - prediv.divisor = 0; - speed.regVal = SPI_CLK_EQU_SYSCLK; - } else { - prediv = calculateSpeed(cpuFreq, speed.frequency, 2); - if(prediv.freq != speed.frequency) { - // Use whichever divisor gives the highest frequency - SpiPreDiv pd3 = calculateSpeed(cpuFreq, speed.frequency, 3); - SpiPreDiv pd5 = calculateSpeed(cpuFreq, speed.frequency, 5); - if(pd3.freq > prediv.freq || pd5.freq > prediv.freq) { - prediv = (pd3.freq > pd5.freq) ? pd3 : pd5; - } - } - - // We have prescale and divisor values, now get regVal so we don't need to do this every time prepare() is called - speed.regVal = (((prediv.prescale - 1) & SPI_CLKDIV_PRE) << SPI_CLKDIV_PRE_S) | - (((prediv.divisor - 1) & SPI_CLKCNT_N) << SPI_CLKCNT_N_S) | - (((prediv.divisor >> 1) & SPI_CLKCNT_H) << SPI_CLKCNT_H_S) | - ((0 & SPI_CLKCNT_L) << SPI_CLKCNT_L_S); - } - - //#ifdef SPI_DEBUG - debug_e("-> Using clock divider %u -> target freq %u -> result %u", prediv.divisor, speed.frequency, prediv.freq); - //#endif - - speed.frequency = prediv.freq; -} - -void spi_set_clock(SPISpeed& speed) -{ - // Clock register value is never 0, so indicates it hasn't been calculated - if(speed.regVal == 0) { - checkSpeed(speed); - } else { -#ifdef SPI_DEBUG - unsigned prescale = (speed.regVal >> SPI_CLKDIV_PRE_S) + 1; - unsigned divisor = (speed.regVal >> SPI_CLKCNT_N_S) + 1; - debugf("spi_set_clock(prescaler %u, divisor %u) for target %u", prescale, divisor, speed.frequency); -#endif - } - - WRITE_PERI_REG(SPI_CLOCK(SPI_NO), speed.regVal); -} - -} // namespace - -bool SPIClass::begin() -{ - CLEAR_PERI_REG_MASK(PERIPHS_IO_MUX, BIT9); - - PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2); // HSPIQ MISO == GPIO12 - PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2); // HSPID MOSI == GPIO13 - PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2); // CLK == GPIO14 - - checkSpeed(SPIDefaultSettings.speed); - prepare(SPIDefaultSettings); - - return true; -} - -uint32_t SPIClass::transfer32(uint32_t data, uint8_t bits) -{ - uint32_t regvalue = READ_PERI_REG(SPI_USER(SPI_NO)) & (SPI_WR_BYTE_ORDER | SPI_RD_BYTE_ORDER | SPI_CK_OUT_EDGE); - - spi_wait(); - - regvalue |= SPI_USR_MOSI | SPI_DOUTDIN | SPI_CK_I_EDGE; - WRITE_PERI_REG(SPI_USER(SPI_NO), regvalue); - - WRITE_PERI_REG(SPI_USER1(SPI_NO), (((bits - 1) & SPI_USR_MOSI_BITLEN) << SPI_USR_MOSI_BITLEN_S) | - (((bits - 1) & SPI_USR_MISO_BITLEN) << SPI_USR_MISO_BITLEN_S)); - - // copy data to W0 - if(READ_PERI_REG(SPI_USER(SPI_NO)) & SPI_WR_BYTE_ORDER) { - WRITE_PERI_REG(SPI_W0(SPI_NO), data << (32 - bits)); - } else { - WRITE_PERI_REG(SPI_W0(SPI_NO), data); - } - - spi_send(); - spi_wait(); - - auto res = READ_PERI_REG(SPI_W0(SPI_NO)); - if(READ_PERI_REG(SPI_USER(SPI_NO)) & SPI_RD_BYTE_ORDER) { - res >>= (32 - bits); - } - - return res; -} - -uint8_t SPIClass::read8() -{ - spi_wait(); - - WRITE_PERI_REG(SPI_W0(SPI_NO), 0x00); - - spi_send(); - spi_wait(); - - auto res = READ_PERI_REG(SPI_W0(SPI_NO)); - if(READ_PERI_REG(SPI_USER(SPI_NO)) & SPI_RD_BYTE_ORDER) { - res >>= 24; - } - - return res; -} - -void SPIClass::transfer(uint8_t* buffer, size_t numberBytes) -{ -#define BLOCKSIZE 64U // the max length of the ESP SPI_W0 registers - - unsigned bufIndx = 0; - - unsigned blocks = ((numberBytes - 1) / BLOCKSIZE) + 1; -#ifdef SPI_DEBUG - unsigned total = blocks; -#endif - - // loop number of blocks - while(blocks--) { - // get full BLOCKSIZE or number of remaining bytes - auto bufLength = std::min(numberBytes - bufIndx, BLOCKSIZE); - -#ifdef SPI_DEBUG - debugf("Write/Read Block %u total %u bytes", total - blocks, bufLength); -#endif - - // compute the number of bits to clock - auto num_bits = bufLength * 8; - - uint32_t regvalue = READ_PERI_REG(SPI_USER(SPI_NO)) & (SPI_WR_BYTE_ORDER | SPI_RD_BYTE_ORDER | SPI_CK_OUT_EDGE); - - spi_wait(); - - regvalue |= SPI_USR_MOSI | SPI_DOUTDIN | SPI_CK_I_EDGE; - WRITE_PERI_REG(SPI_USER(SPI_NO), regvalue); - - // setup bit length - WRITE_PERI_REG(SPI_USER1(SPI_NO), (((num_bits - 1) & SPI_USR_MOSI_BITLEN) << SPI_USR_MOSI_BITLEN_S) | - (((num_bits - 1) & SPI_USR_MISO_BITLEN) << SPI_USR_MISO_BITLEN_S)); - - // copy the registers starting from last index position - if(IS_ALIGNED(buffer)) { - memcpy((void*)SPI_W0(SPI_NO), &buffer[bufIndx], ALIGNUP4(bufLength)); - } else { - uint32_t wordBuffer[BLOCKSIZE / 4]; - memcpy(wordBuffer, &buffer[bufIndx], bufLength); - memcpy((void*)SPI_W0(SPI_NO), wordBuffer, ALIGNUP4(bufLength)); - } - - spi_send(); - spi_wait(); - - // copy the registers starting from last index position - memcpy(&buffer[bufIndx], (void*)SPI_W0(SPI_NO), bufLength); - - // increment bufIndex - bufIndx += bufLength; - } -} - -void SPIClass::prepare(SPISettings& settings) -{ -#ifdef SPI_DEBUG - debugf("SPIClass::prepare(SPISettings)"); - settings.print("settings"); -#endif - - // setup clock - spi_set_clock(settings.speed); - - // set byte order - spi_byte_order(settings.byteOrder); - - // set spi mode - spi_mode(settings.dataMode); -} diff --git a/Sming/Arch/Rp2040/Core/SPI.h b/Sming/Arch/Rp2040/Core/SPI.h deleted file mode 100644 index e6ad930196..0000000000 --- a/Sming/Arch/Rp2040/Core/SPI.h +++ /dev/null @@ -1,63 +0,0 @@ -/**** - * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. - * Created 2015 by Skurydin Alexey - * http://github.com/SmingHub/Sming - * All files of the Sming Core are provided under the LGPL v3 license. - * - * SPI.h - * - * Created on: Mar 2, 2016 - * Author: harry-boe - * - */ - -/** @defgroup hw_spi SPI Hardware support - * @brief Provides hardware SPI support - */ - -#pragma once - -#include "SPIBase.h" -#include "SPISettings.h" - -//#define SPI_DEBUG 1 - -// for compatibility when porting from Arduino -#define SPI_HAS_TRANSACTION 0 - -#define SPI_NO 1 - -/** - * @brief Hardware SPI object - * @addtogroup hw_spi - * @{ - */ - -class SPIClass : public SPIBase -{ -public: - SPIClass() - { - } - - SPIClass(const SPIClass&) = delete; - SPIClass& operator=(const SPIClass&) = delete; - - bool begin() override; - - void end() override - { - } - - uint8_t read8() override; - uint32_t transfer32(uint32_t val, uint8_t bits = 32) override; - - using SPIBase::transfer; - void transfer(uint8_t* buffer, size_t numberBytes) override; - -protected: - void prepare(SPISettings& settings) override; -}; - -/** @brief Global instance of SPI class */ -extern SPIClass SPI; diff --git a/Sming/Arch/Rp2040/README.rst b/Sming/Arch/Rp2040/README.rst index 8bda1debd7..40eda7363b 100644 --- a/Sming/Arch/Rp2040/README.rst +++ b/Sming/Arch/Rp2040/README.rst @@ -35,15 +35,24 @@ Tested and working: Exception information not yet implemented. - System functions :cpp:func:`system_get_chip_id`, :cpp:func:`system_get_sdk_version`. - Partitions and file systems (except SD cards and FAT) +- SPIClass tested with Radio_nRF24L01 sample only -The following items are yet to be implemented: +In progress: + +Networking + A skeleton WiFi/lwip2 support framework is provided sufficient to build samples with Networking enabled, + but it is currently non-functional. + The goal is to allow use of networking adapters such as Ethernet over SPI, similar to how ESP32. + USB offers the possibility of CDMA networking for mobile applications. + +Yet to be implemented: USB Best to write a separate ``Sming-USB`` library (based on TinyUSB) to support the RP2040, ESP32-S2 & ESP32-S3 variants. Needs some thought about good integration into the framework. Arduino-Pico overrides ``HardwareSerial`` to support serial devices, we can do something similar. -SPI - Nice for messing around with displays. +HardwareSPI + To support DMA, etc. Analogue I/O Has 4 channels + temperature. PWM @@ -57,10 +66,6 @@ Low-power modes Deep sleep / suspend / power-saving Dual-core support RP2040 is a dual-core processor! -Networking - Applications must currently be built with :envvar:`DISABLE_NETWORK` =1. - RP2040 doesn't have WiFi but a network stack via ethernet adapter would be useful. - USB offers the possibility of CDMA networking for mobile applications. PIO (Programmable I/O) A killer feature for the RP2040. Uses range from simple glue logic to I2S, etc. diff --git a/Sming/Arch/Rp2040/Tools/ci/build.run.cmd b/Sming/Arch/Rp2040/Tools/ci/build.run.cmd index c2fa057237..68138c5a00 100644 --- a/Sming/Arch/Rp2040/Tools/ci/build.run.cmd +++ b/Sming/Arch/Rp2040/Tools/ci/build.run.cmd @@ -1,6 +1,6 @@ REM Rp2040 build.run.cmd -set RP2040_PROJECTS=Basic_Blink Basic_Serial Basic_Storage +set RP2040_PROJECTS=Basic_Blink Basic_Serial Basic_Storage HttpServer_ConfigNetwork %MAKE_PARALLEL% %RP2040_PROJECTS% DEBUG_VERBOSE_LEVEL=3 || goto :error diff --git a/Sming/Arch/Rp2040/Tools/ci/build.run.sh b/Sming/Arch/Rp2040/Tools/ci/build.run.sh index 6838fa42d1..7c95543143 100644 --- a/Sming/Arch/Rp2040/Tools/ci/build.run.sh +++ b/Sming/Arch/Rp2040/Tools/ci/build.run.sh @@ -3,3 +3,5 @@ # Rp2040 build.run.sh $MAKE_PARALLEL samples DEBUG_VERBOSE_LEVEL=3 STRICT=1 + +$MAKE_PARALLEL component-samples STRICT=1 diff --git a/Sming/Arch/Rp2040/build.mk b/Sming/Arch/Rp2040/build.mk index 29d774c29e..77cb67856f 100644 --- a/Sming/Arch/Rp2040/build.mk +++ b/Sming/Arch/Rp2040/build.mk @@ -6,6 +6,7 @@ CPPFLAGS += \ -DARCH_RP2040 \ + -DARDUINO_ARCH_RP2040 \ -march=armv6-m \ -mcpu=cortex-m0plus \ -mthumb diff --git a/Sming/Components/FlashString b/Sming/Components/FlashString index b99a4c516b..9daf0d5b3b 160000 --- a/Sming/Components/FlashString +++ b/Sming/Components/FlashString @@ -1 +1 @@ -Subproject commit b99a4c516b8c7c1c0f38985c50db12ed11b177cb +Subproject commit 9daf0d5b3bcba93ba7a2d749638e8d0fdbe016ed diff --git a/Sming/Components/Hosted-Lib/Kconfig b/Sming/Components/Hosted-Lib/Kconfig new file mode 100644 index 0000000000..eaae7785e0 --- /dev/null +++ b/Sming/Components/Hosted-Lib/Kconfig @@ -0,0 +1,12 @@ +menu "Hosted-Lib" + depends on !ENABLE_HOSTED + + config ENABLE_HOSTED_DIGITAL + bool "Proxy Digital.h commands" + default y + + config ENABLE_HOSTED_WIRE + bool "Proxy Wire.h commands" + default y + +endmenu diff --git a/Sming/Components/Hosted-Lib/component.mk b/Sming/Components/Hosted-Lib/component.mk index 4bc530aa9f..8bc49e3816 100644 --- a/Sming/Components/Hosted-Lib/component.mk +++ b/Sming/Components/Hosted-Lib/component.mk @@ -1,3 +1,12 @@ COMPONENT_SOC := host COMPONENT_SRCDIRS := $(COMPONENT_PATH)/src -COMPONENT_DEPENDS := Hosted \ No newline at end of file +COMPONENT_DEPENDS := Hosted + + +COMPONENT_VARS += ENABLE_HOSTED_DIGITAL +ENABLE_HOSTED_DIGITAL ?= 1 +COMPONENT_CPPFLAGS += -DENABLE_HOSTED_DIGITAL=$(ENABLE_HOSTED_DIGITAL) + +COMPONENT_VARS += ENABLE_HOSTED_WIRE +ENABLE_HOSTED_WIRE ?= 1 +COMPONENT_CPPFLAGS += -DENABLE_HOSTED_WIRE=$(ENABLE_HOSTED_WIRE) diff --git a/Sming/Components/Hosted-Lib/src/Digital.cpp b/Sming/Components/Hosted-Lib/src/Digital.cpp index 1462f33811..b6fd746323 100644 --- a/Sming/Components/Hosted-Lib/src/Digital.cpp +++ b/Sming/Components/Hosted-Lib/src/Digital.cpp @@ -11,6 +11,8 @@ * ****/ +#if ENABLE_HOSTED_DIGITAL + #include #include @@ -37,3 +39,5 @@ unsigned long pulseIn(uint16_t pin, uint8_t state, unsigned long timeout) hostedClient->send(__func__, pin, state, timeout); return hostedClient->wait(); } + +#endif /* ENABLE_HOSTED_DIGITAL */ diff --git a/Sming/Components/Hosted-Lib/src/Wire.cpp b/Sming/Components/Hosted-Lib/src/Wire.cpp new file mode 100644 index 0000000000..7320f613fb --- /dev/null +++ b/Sming/Components/Hosted-Lib/src/Wire.cpp @@ -0,0 +1,152 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * Wire.cpp + * + * @author 2022 Slavey Karadzhov + * + * + ****/ + +#if ENABLE_HOSTED_WIRE + +#include +#include +#include + +extern Hosted::Client* hostedClient; + +void TwoWire::begin(uint8_t sda, uint8_t scl) +{ + hostedClient->send(__PRETTY_FUNCTION__, sda, scl); +} + +void TwoWire::pins(uint8_t sda, uint8_t scl) +{ + hostedClient->send(__PRETTY_FUNCTION__, sda, scl); +} + +void TwoWire::begin() +{ + hostedClient->send(__PRETTY_FUNCTION__); +} + +void TwoWire::end() +{ + hostedClient->send(__PRETTY_FUNCTION__); +} + +TwoWire::Status TwoWire::status() +{ + hostedClient->send(__PRETTY_FUNCTION__); + return hostedClient->wait(); +} + +void TwoWire::setClock(uint32_t freq) +{ + hostedClient->send(__PRETTY_FUNCTION__, freq); +} + +void TwoWire::setClockStretchLimit(uint32_t limit) +{ + hostedClient->send(__PRETTY_FUNCTION__, limit); +} + +uint8_t TwoWire::requestFrom(uint8_t address, uint8_t size, bool sendStop) +{ + hostedClient->send(__PRETTY_FUNCTION__, address, size, sendStop); + return hostedClient->wait(); +} + +void TwoWire::beginTransmission(uint8_t address) +{ + hostedClient->send(__PRETTY_FUNCTION__, address); +} + +TwoWire::Error TwoWire::endTransmission(bool sendStop) +{ + hostedClient->send(__PRETTY_FUNCTION__, sendStop); + return hostedClient->wait(); +} + +size_t TwoWire::write(uint8_t data) +{ + hostedClient->send(__PRETTY_FUNCTION__, data); + return hostedClient->wait(); +} + +size_t TwoWire::write(const uint8_t* data, size_t quantity) +{ + hostedClient->send(__PRETTY_FUNCTION__, data, quantity); + return hostedClient->wait(); +} + +int TwoWire::available() +{ + hostedClient->send(__PRETTY_FUNCTION__); + return hostedClient->wait(); +} + +int TwoWire::read() +{ + hostedClient->send(__PRETTY_FUNCTION__); + return hostedClient->wait(); +} + +int TwoWire::peek() +{ + hostedClient->send(__PRETTY_FUNCTION__); + return hostedClient->wait(); +} + +void TwoWire::flush() +{ + hostedClient->send(__PRETTY_FUNCTION__); +} + +void TwoWire::onReceiveService(uint8_t* inBytes, int numBytes) +{ + // don't bother if user hasn't registered a callback + // if(!userReceiveCallback){ + // return; + // } + // // don't bother if rx buffer is in use by a master requestFrom() op + // // i know this drops data, but it allows for slight stupidity + // // meaning, they may not have read all the master requestFrom() data yet + // if(rxBufferIndex < rxBufferLength){ + // return; + // } + // // copy twi rx buffer into local read buffer + // // this enables new reads to happen in parallel + // for(uint8_t i = 0; i < numBytes; ++i){ + // rxBuffer[i] = inBytes[i]; + // } + // // set rx iterator vars + // rxBufferIndex = 0; + // rxBufferLength = numBytes; + // // alert user program + // user_onReceive(numBytes); +} + +void TwoWire::onRequestService() +{ + // // don't bother if user hasn't registered a callback + // if(!userRequestCallback){ + // return; + // } + // // reset tx buffer iterator vars + // // !!! this will kill any pending pre-master sendTo() activity + // txBufferIndex = 0; + // txBufferLength = 0; + // // alert user program + // user_onRequest(); +} + +#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_TWOWIRE) +TwoWire Wire; +#endif + +#endif /* ENABLE_HOSTED_WIRE */ diff --git a/Sming/Components/Hosted/component.mk b/Sming/Components/Hosted/component.mk index 3d8103475f..4d19f5a640 100644 --- a/Sming/Components/Hosted/component.mk +++ b/Sming/Components/Hosted/component.mk @@ -13,6 +13,11 @@ ifneq ($(ENABLE_HOSTED),) COMPONENT_SRCDIRS += init/$(ENABLE_HOSTED) EXTRA_LDFLAGS := $(call Wrap,host_init) COMPONENT_DEPENDS += SerialLib + ifeq ($(ENABLE_HOSTED),tcp) + COMPONENT_DEPENDS += Network + DISABLE_NETWORK := 0 + DISABLE_WIFI := 0 + endif endif COMPONENT_RELINK_VARS += HOSTED_SERVER_IP diff --git a/Sming/Components/Hosted/include/Hosted/Client.h b/Sming/Components/Hosted/include/Hosted/Client.h index 80f3e97dbb..ece7a59054 100644 --- a/Sming/Components/Hosted/include/Hosted/Client.h +++ b/Sming/Components/Hosted/include/Hosted/Client.h @@ -24,6 +24,7 @@ #include #include #include +#include "Util.h" using namespace simpleRPC; @@ -36,22 +37,35 @@ class Client public: using RemoteCommands = HashMap; - Client(Stream& stream) : stream(stream) + Client(Stream& stream, char methodEndsWith = ':') : stream(stream), methodEndsWith(methodEndsWith) { } /** * @brief Method to send commands to the remote server * @param functionName + * Either the name or the name with the signature. + * Example: "digitalWrite" - will try to call the default digitalWrite function on the server + * + * If the command is overloaded, one command name with two or more different signatures + * then the name has to be containing the full function signature. + * Example: "void digitalWrite(uint16_t, uint8_t)". + * The name with the signature MUST be the same as the one produced from + * __PRETTY_FUNCTION__ -> https://gcc.gnu.org/onlinedocs/gcc/Function-Names.html + * * @param variable arguments * - * @retval true on success + * @retval true on success, false if the command is not available */ - template bool send(const char* functionName, Args... args) + template bool send(const String& functionName, Args... args) { - uint8_t functionId = getFunctionId(functionName); + int functionId = getFunctionId(functionName); + if(functionId == COMMAND_NOT_FOUND) { + return false; + } - rpcPrint(stream, functionId, args...); + rpcPrint(stream, uint8_t(functionId), args...); + stream.flush(); return true; } @@ -79,12 +93,17 @@ class Client * @param name command name to query * @retval -1 if not found. Otherwise the id of the function */ - int getFunctionId(const char* name) + int getFunctionId(String name) { if(fetchCommands) { getRemoteCommands(); } + if(name.indexOf('(') != -1 && name.indexOf(')') != -1) { + // most probably we have a name with a signature + name = convertFQN(name); + } + int id = commands.indexOf(name); if(id < 0) { return COMMAND_NOT_FOUND; @@ -107,6 +126,7 @@ class Client ParserSettings settings; settings.startMethods = ParserSettings::SimpleMethod(&Client::startMethods, this); settings.startMethod = ParserSettings::SimpleMethod(&Client::startMethod, this); + settings.methodSignature = ParserSettings::CharMethod(&Client::methodSignature, this); settings.methodName = ParserSettings::CharMethod(&Client::methodName, this); settings.endMethod = ParserSettings::SimpleMethod(&Client::endMethod, this); settings.endMethods = ParserSettings::SimpleMethod(&Client::endMethods, this); @@ -121,7 +141,7 @@ class Client continue; } - ParserResult result = parse(settings, buffer, length); + ParserResult result = parse(settings, buffer, length, methodEndsWith); if(result == ParserResult::finished) { break; } @@ -132,6 +152,12 @@ class Client } } while(true); + host_debug_i("Available commands:"); + + for(size_t i = 0; i < commands.count(); i++) { + host_debug_i("\t%s => %d", commands.keyAt(i).c_str(), commands.valueAt(i)); + } + host_debug_i("Connected. Starting application"); return true; @@ -142,7 +168,9 @@ class Client bool fetchCommands{true}; RemoteCommands commands; uint8_t methodPosition = 0; - String parsedCommand; + String name; + String signature; + char methodEndsWith; void startMethods() { @@ -152,17 +180,26 @@ class Client void startMethod() { - parsedCommand = ""; + name = ""; + signature = ""; + } + + void methodSignature(char ch) + { + signature += ch; } void methodName(char ch) { - parsedCommand += ch; + name += ch; } void endMethod() { - commands[parsedCommand] = methodPosition++; + if(!commands.contains(name) || signature == ":") { + commands[name] = methodPosition; + } + commands[name + "(" + signature + ")"] = methodPosition++; } void endMethods() diff --git a/Sming/Components/Hosted/include/Hosted/Transport/TcpClientStream.h b/Sming/Components/Hosted/include/Hosted/Transport/TcpClientStream.h index 9dcc79ece6..1d43fcc872 100644 --- a/Sming/Components/Hosted/include/Hosted/Transport/TcpClientStream.h +++ b/Sming/Components/Hosted/include/Hosted/Transport/TcpClientStream.h @@ -23,7 +23,8 @@ namespace Transport class TcpClientStream : public Stream { public: - TcpClientStream(TcpClient& client, size_t cbufferSize = 1024) : cBuffer(cbufferSize), client(client) + TcpClientStream(TcpClient& client, size_t cbufferSize = 1024, size_t threshold = 400) + : cBuffer(cbufferSize), client(client), pendingBytes(0), threshold(threshold) { client.setReceiveDelegate(TcpClientDataDelegate(&TcpClientStream::store, this)); } @@ -47,6 +48,11 @@ class TcpClientStream : public Stream size_t write(const uint8_t* buffer, size_t size) override { if(client.send(reinterpret_cast(buffer), size)) { + pendingBytes += size; + if(pendingBytes > threshold) { + pendingBytes = 0; + client.commit(); + } return size; } @@ -81,6 +87,8 @@ class TcpClientStream : public Stream private: CircularBuffer cBuffer; TcpClient& client; + size_t pendingBytes; + size_t threshold; bool store(TcpClient& client, char* data, int size) { diff --git a/Sming/Components/Hosted/include/Hosted/Util.h b/Sming/Components/Hosted/include/Hosted/Util.h new file mode 100644 index 0000000000..54e7299cf4 --- /dev/null +++ b/Sming/Components/Hosted/include/Hosted/Util.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +namespace Hosted +{ +/** + * Convert C type to format character + * See: https://docs.python.org/3.5/library/struct.html#format-strings + */ +char convertType(const String& type); + +/** + * Converts a name as given from __PRETTY_FUNCTION__ to internal format. + * Examples: + * void a::sub(int) -> a::sub(: i) + * void TwoWire::pins(uint8_t,uint8_t) -> TwoWire::pins(: B B) + * uint8_t digitalRead(uint16_t) -> digitalRead(B: H) + * @param name source name + * @retval converted name + */ +String convertFQN(const String& name); + +} // namespace Hosted diff --git a/Sming/Components/Hosted/init/serial/InitClient.cpp b/Sming/Components/Hosted/init/serial/InitClient.cpp index 3b4c980548..f1ecbed542 100644 --- a/Sming/Components/Hosted/init/serial/InitClient.cpp +++ b/Sming/Components/Hosted/init/serial/InitClient.cpp @@ -42,7 +42,7 @@ void __wrap_host_init() msleep(50); } - hostedClient = new Hosted::Client(hostedSerial); + hostedClient = new Hosted::Client(hostedSerial, '>'); hostedClient->getRemoteCommands(); init(); } diff --git a/Sming/Components/Hosted/init/tcp/InitClient.cpp b/Sming/Components/Hosted/init/tcp/InitClient.cpp index 04a71dc3c1..3e4dce3bc7 100644 --- a/Sming/Components/Hosted/init/tcp/InitClient.cpp +++ b/Sming/Components/Hosted/init/tcp/InitClient.cpp @@ -57,7 +57,7 @@ static void ready(IpAddress ip, IpAddress mask, IpAddress gateway) tcpClient->connect(remoteIp, 4031); stream = new Hosted::Transport::TcpClientStream(*tcpClient); - hostedClient = new Hosted::Client(*stream); + hostedClient = new Hosted::Client(*stream, '>'); hostedClient->getRemoteCommands(); init(); } diff --git a/Sming/Components/Hosted/samples/serial/app/application.cpp b/Sming/Components/Hosted/samples/serial/app/application.cpp index 8faed12e44..5f5c0288d4 100644 --- a/Sming/Components/Hosted/samples/serial/app/application.cpp +++ b/Sming/Components/Hosted/samples/serial/app/application.cpp @@ -4,6 +4,7 @@ #include #include #include +#include using namespace Hosted::Transport; @@ -18,18 +19,34 @@ void init() // clang-format off interface(stream, /* - * Below we are exporting the following remote commands: - * - pinMode - * - digitalRead - * - digitalWrite - * - pulseIn - * You can add more commands here. For every command you should specify command and text description in the format below. + * List of exported commands. More commands can be added. + * For every command one should specify command and text description in the format below. * For more information read the SimpleRPC interface API: https://simplerpc.readthedocs.io/en/latest/api/interface.html */ - pinMode, F("pinMode: Sets mode of digital pin. @pin: Pin number, @mode: Mode type."), - digitalRead, F("digitalRead: Read digital pin. @pin: Pin number. @return: Pin value."), - digitalWrite, F("digitalWrite: Write to a digital pin. @pin: Pin number. @value: Pin value."), - pulseIn, F("pulseIn: Measure duration of pulse on pin. @pin: Pin number. @state: State of pulse to measure. @timeout: Maximum duration of pulse. @return: Pulse duration in microseconds)") + pinMode, F("pinMode> Sets mode of digital pin. @pin: Pin number, @mode: Mode type."), + digitalRead, F("digitalRead> Read digital pin. @pin: Pin number. @return: Pin value."), + digitalWrite, F("digitalWrite> Write to a digital pin. @pin: Pin number. @value: Pin value."), + pulseIn, F("pulseIn> Measure duration of pulse on pin. @pin: Pin number. @state: State of pulse to measure. @timeout: Maximum duration of pulse. @return: Pulse duration in microseconds)"), + // void TwoWire::begin(uint8_t sda, uint8_t scl) + pack(&Wire, (void(TwoWire::*)(uint8_t,uint8_t))&TwoWire::begin), F("TwoWire::begin> Starts two-wire communication. @sda: Data pin. @scl: Clock pin."), + // void TwoWire::begin() + pack(&Wire, (void(TwoWire::*)(void))&TwoWire::begin), F("TwoWire::begin> Starts two-wire communication."), + pack(&Wire, &TwoWire::pins), F("TwoWire::pins> Starts two-wire communication. @sda: Data pin. @scl: Clock pin."), + pack(&Wire, &TwoWire::status), F("TwoWire::status> Get status."), + pack(&Wire, &TwoWire::end), F("TwoWire::end> Ends two-wire communication."), + pack(&Wire, &TwoWire::setClock), F("TwoWire::setClock> Sets clock frequency. @freq: clock frequency."), + pack(&Wire, &TwoWire::setClockStretchLimit), F("TwoWire::setClockStretchLimit> Sts clock stretch limit. @limit: stretch limit."), + pack(&Wire, &TwoWire::requestFrom), F("TwoWire::requestFrom> Request from. @address: Address. @size: Size. @sendStop flag. @return: uint8_t."), + pack(&Wire, &TwoWire::beginTransmission), F("TwoWire::beginTransmission> Begin transmission. @address: Address."), + pack(&Wire, &TwoWire::endTransmission), F("TwoWire::endTransmission> End transmission. @sendStop: flag. @return: error code"), + // size_t TwoWire::write(uint8_t data) + pack(&Wire, (size_t(TwoWire::*)(uint8_t))&TwoWire::write), F("TwoWire::write> Write byte. @data: byte. @return: written bytes"), + // size_t TwoWire::write(const uint8_t* data, size_t quantity) + pack(&Wire, (size_t(TwoWire::*)(const uint8_t*, size_t))&TwoWire::write), F("TwoWire::write> Write bytes. @data: data pointer. @quantity: data size. @return: written bytes"), + pack(&Wire, &TwoWire::available), F("TwoWire::available> Available bytes. @return: count"), + pack(&Wire, &TwoWire::read), F("TwoWire::read> Read a byte. @return: byte"), + pack(&Wire, &TwoWire::peek), F("TwoWire::peek> Peek. @return: byte without advancing the internal pointer."), + pack(&Wire, &TwoWire::flush), F("TwoWire::flush> Flush.") ); // clang-format on diff --git a/Sming/Components/Hosted/samples/serial/component.mk b/Sming/Components/Hosted/samples/serial/component.mk index 75ad616820..92762f12bc 100644 --- a/Sming/Components/Hosted/samples/serial/component.mk +++ b/Sming/Components/Hosted/samples/serial/component.mk @@ -6,4 +6,4 @@ ENABLE_HOSTED := DISABLE_NETWORK := 1 ENABLE_HOST_UARTID := 0 -HOST_NETWORK_OPTIONS := --pause \ No newline at end of file +HOST_NETWORK_OPTIONS := --pause diff --git a/Sming/Components/Hosted/samples/tcp/app/application.cpp b/Sming/Components/Hosted/samples/tcp/app/application.cpp index bfcc930d51..54ceb15e6e 100644 --- a/Sming/Components/Hosted/samples/tcp/app/application.cpp +++ b/Sming/Components/Hosted/samples/tcp/app/application.cpp @@ -48,10 +48,10 @@ void connectOk(IpAddress ip, IpAddress mask, IpAddress gateway) * You can add more commands here. For every command you should specify command and text description in the format below. * For more information read the SimpleRPC interface API: https://simplerpc.readthedocs.io/en/latest/api/interface.html */ - pinMode, F("pinMode: Sets mode of digital pin. @pin: Pin number, @mode: Mode type."), - digitalRead, F("digitalRead: Read digital pin. @pin: Pin number. @return: Pin value."), - digitalWrite, F("digitalWrite: Write to a digital pin. @pin: Pin number. @value: Pin value."), - pulseIn, F("pulseIn: Measure duration of pulse on pin. @pin: Pin number. @state: State of pulse to measure. @timeout: Maximum duration of pulse. @return: Pulse duration in microseconds)") + pinMode, F("pinMode> Sets mode of digital pin. @pin: Pin number, @mode: Mode type."), + digitalRead, F("digitalRead> Read digital pin. @pin: Pin number. @return: Pin value."), + digitalWrite, F("digitalWrite> Write to a digital pin. @pin: Pin number. @value: Pin value."), + pulseIn, F("pulseIn> Measure duration of pulse on pin. @pin: Pin number. @state: State of pulse to measure. @timeout: Maximum duration of pulse. @return: Pulse duration in microseconds)") ); // clang-format on diff --git a/Sming/Components/Hosted/src/Util.cpp b/Sming/Components/Hosted/src/Util.cpp new file mode 100644 index 0000000000..dde76ac755 --- /dev/null +++ b/Sming/Components/Hosted/src/Util.cpp @@ -0,0 +1,86 @@ + +#include "../include/Hosted/Util.h" +#include + +namespace Hosted +{ +/** + * Convert C type to format character + * See: https://docs.python.org/3.5/library/struct.html#format-strings + */ +char convertType(const String& type) +{ + if(type == "int") { + return 'i'; + } + + if(type == "uint8_t") { + return 'B'; + } + + if(type == "uint16_t") { + return 'H'; + } + + if(type == "bool") { + return '?'; + } + + if(type == "char") { + return 'c'; + } + + if(type == "float") { + return 'f'; + } + + // TODO: ... add all types... + if(type != "void") { + debug_w("Unknown type: %s", type); + } + + // void and unknown + return '\0'; +} + +/** + * Converts a name as given from __PRETTY_FUNCTION__ to internal format. + * Examples: + * void a::sub(int) -> a::sub(: i) + * void TwoWire::pins(uint8_t,uint8_t) -> TwoWire::pins(: B B) + * uint8_t digitalRead(uint16_t) -> digitalRead(B: H) + * @param name source name + * @retval converted name + */ +String convertFQN(const String& name) +{ + String converted; + int spacePos = name.indexOf(' '); + String returnType = name.substring(0, spacePos); + int openBracePosition = name.indexOf('('); + int closeBracePosition = name.indexOf(')'); + Vector params; + String arguments = name.substring(openBracePosition + 1, closeBracePosition); + size_t paramsCount = splitString(arguments, ',', params); + + converted = name.substring(spacePos + 1, openBracePosition) + '('; // name + char returnTypeChar = convertType(returnType); + if(returnTypeChar) { + converted += returnTypeChar; + } + + converted += ':'; + for(size_t i = 0; i < paramsCount; i++) { + params[i].trim(); + if(params[i].length() == 0) { + continue; + } + converted += ' '; + converted += convertType(params[i]); + } + converted += ')'; + + return converted; +} + +} // namespace Hosted diff --git a/Sming/Components/IFS b/Sming/Components/IFS index ea8765a968..9dbc293071 160000 --- a/Sming/Components/IFS +++ b/Sming/Components/IFS @@ -1 +1 @@ -Subproject commit ea8765a968a3e4a9d4bbf1eb240754c1f06c3131 +Subproject commit 9dbc29307169c426ab5c9e6eab1b8cf0dcedfa4a diff --git a/Sming/Components/Network/Arch/Esp32/Platform/AccessPointImpl.cpp b/Sming/Components/Network/Arch/Esp32/Platform/AccessPointImpl.cpp index 24f858e6b6..0ee9de2684 100644 --- a/Sming/Components/Network/Arch/Esp32/Platform/AccessPointImpl.cpp +++ b/Sming/Components/Network/Arch/Esp32/Platform/AccessPointImpl.cpp @@ -10,12 +10,14 @@ #include "AccessPointImpl.h" #include "StationListImpl.h" -#include -#include -#include -static AccessPointImpl accessPoint; -AccessPointClass& WifiAccessPoint = accessPoint; +AccessPointClass& WifiAccessPoint{SmingInternal::Network::accessPoint}; + +namespace SmingInternal +{ +namespace Network +{ +AccessPointImpl accessPoint; void AccessPointImpl::enable(bool enabled, bool save) { @@ -193,3 +195,6 @@ std::unique_ptr AccessPointImpl::getStations() const void AccessPointImpl::onSystemReady() { } + +} // namespace Network +} // namespace SmingInternal diff --git a/Sming/Components/Network/Arch/Esp32/Platform/AccessPointImpl.h b/Sming/Components/Network/Arch/Esp32/Platform/AccessPointImpl.h index 4d6cc073ef..7135dbe47a 100644 --- a/Sming/Components/Network/Arch/Esp32/Platform/AccessPointImpl.h +++ b/Sming/Components/Network/Arch/Esp32/Platform/AccessPointImpl.h @@ -12,9 +12,14 @@ #include #include +#include struct esp_netif_obj; +namespace SmingInternal +{ +namespace Network +{ class AccessPointImpl : public AccessPointClass, protected ISystemReadyHandler { public: @@ -38,9 +43,19 @@ class AccessPointImpl : public AccessPointClass, protected ISystemReadyHandler String getPassword() const override; std::unique_ptr getStations() const override; + // Called from WifiEventsImpl + void eventHandler(esp_event_base_t base, int32_t id, void* data) + { + } + protected: void onSystemReady() override; private: esp_netif_obj* apNetworkInterface{nullptr}; }; + +extern AccessPointImpl accessPoint; + +} // namespace Network +} // namespace SmingInternal diff --git a/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.cpp b/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.cpp index afc79494bc..744b595e12 100644 --- a/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.cpp +++ b/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.cpp @@ -9,15 +9,25 @@ ****/ #include "StationImpl.h" -#include "WifiEventsImpl.h" - -#include -#include -#include +#include #ifdef ENABLE_WPS #include +#endif + +// Use same NVS namespace as other WiFi settings +#define NVS_NAMESPACE "nvs.net80211" +#define NVS_STA_AUTOCONNECT "sta.autoconnect" + +StationClass& WifiStation{SmingInternal::Network::station}; +namespace SmingInternal +{ +namespace Network +{ +StationImpl station; + +#ifdef ENABLE_WPS /* * Information only required during WPS negotiation */ @@ -30,11 +40,26 @@ struct StationImpl::WpsConfig { uint8_t credIndex; bool ignoreDisconnects; }; - #endif -static StationImpl station; -StationClass& WifiStation = station; +void setAutoConnect(bool enable) +{ + nvs_handle_t handle; + ESP_ERROR_CHECK(nvs_open(NVS_NAMESPACE, NVS_READWRITE, &handle)); + nvs_set_u8(handle, NVS_STA_AUTOCONNECT, enable); + nvs_close(handle); +} + +bool getAutoConnect() +{ + uint8_t enable{false}; + nvs_handle_t handle; + if(nvs_open(NVS_NAMESPACE, NVS_READONLY, &handle) == ESP_OK) { + nvs_get_u8(handle, NVS_STA_AUTOCONNECT, &enable); + nvs_close(handle); + } + return enable; +} class BssInfoImpl : public BssInfo { @@ -50,12 +75,53 @@ class BssInfoImpl : public BssInfo } }; +void StationImpl::eventHandler(esp_event_base_t base, int32_t id, void* data) +{ + if(base == WIFI_EVENT) { + bool allowAutoConnect{true}; +#ifdef ENABLE_WPS + if(wpsConfig != nullptr) { + wpsEventHandler(id, data); + allowAutoConnect = false; + } +#endif +#ifdef ENABLE_SMART_CONFIG + if(smartConfigEventInfo) { + allowAutoConnect = false; + } +#endif + switch(id) { + case WIFI_EVENT_STA_START: + if(allowAutoConnect && getAutoConnect()) { + connectionStatus = eSCS_Connecting; + esp_wifi_connect(); + } + break; + case WIFI_EVENT_STA_DISCONNECTED: { + connectionStatus = eSCS_ConnectionFailed; + break; + } + default:; + } + } else if(base == IP_EVENT) { + switch(id) { + case IP_EVENT_STA_GOT_IP: + connectionStatus = eSCS_GotIP; + break; + case IP_EVENT_STA_LOST_IP: + connectionStatus = eSCS_Connecting; + break; + default:; + } + } +} + void StationImpl::enable(bool enabled, bool save) { wifi_mode_t mode; ESP_ERROR_CHECK(esp_wifi_get_mode(&mode)); if(enabled) { - if(stationNetworkInterface == nullptr) { + if(!stationNetworkInterface) { stationNetworkInterface = esp_netif_create_default_wifi_sta(); } switch(mode) { @@ -89,6 +155,7 @@ void StationImpl::enable(bool enabled, bool save) } ESP_ERROR_CHECK(esp_wifi_set_storage(save ? WIFI_STORAGE_FLASH : WIFI_STORAGE_RAM)); ESP_ERROR_CHECK(esp_wifi_set_mode(mode)); + ESP_ERROR_CHECK(esp_wifi_start()); } bool StationImpl::isEnabled() const @@ -114,6 +181,10 @@ bool StationImpl::config(const String& ssid, const String& password, bool autoCo enable(true, save); + if(save) { + setAutoConnect(autoConnectOnStartup); + } + ESP_ERROR_CHECK(esp_wifi_set_storage(save ? WIFI_STORAGE_FLASH : WIFI_STORAGE_RAM)); ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &config)); @@ -123,7 +194,7 @@ bool StationImpl::config(const String& ssid, const String& password, bool autoCo bool StationImpl::connect() { disconnect(); - return esp_wifi_start() == ESP_OK; + return esp_wifi_connect() == ESP_OK; } bool StationImpl::disconnect() @@ -290,7 +361,7 @@ String StationImpl::getPassword() const StationConnectionStatus StationImpl::getConnectionStatus() const { - return WifiEventsImpl::stationConnectionStatus; + return connectionStatus; } bool StationImpl::startScan(ScanCompletedDelegate scanCompleted) @@ -352,123 +423,116 @@ void StationImpl::onSystemReady() #ifdef ENABLE_SMART_CONFIG -void StationImpl::internalSmartConfig(sc_status status, void* pdata) +void StationImpl::internalSmartConfig(smartconfig_event_t event_id, void* pdata) { - if(smartConfigEventInfo == nullptr) { - debug_e("smartconfig eventInfo is NULL"); + if(!smartConfigEventInfo) { + debug_e("[SC] ERROR! eventInfo null"); return; } auto& evt = *smartConfigEventInfo; - switch(status) { - case SC_STATUS_WAIT: - debugf("SC_STATUS_WAIT\n"); + SmartConfigEvent event; + switch(event_id) { + case SC_EVENT_SCAN_DONE: + debugf("[SC] SCAN_DONE"); + event = SCE_FindChannel; break; - case SC_STATUS_FIND_CHANNEL: - debugf("SC_STATUS_FIND_CHANNEL\n"); + case SC_EVENT_FOUND_CHANNEL: + debugf("[SC] FOUND_CHANNEL"); + event = SCE_GettingSsid; break; - case SC_STATUS_GETTING_SSID_PSWD: - debugf("SC_STATUS_GETTING_SSID_PSWD\n"); - assert(pdata != nullptr); - smartConfigEventInfo->type = SmartConfigType(*static_cast(pdata)); + case SC_EVENT_SEND_ACK_DONE: + debugf("[SC] SEND_ACK_DONE"); + event = SCE_LinkOver; break; - case SC_STATUS_LINK: { - debugf("SC_STATUS_LINK\n"); - auto cfg = static_cast(pdata); + case SC_EVENT_GOT_SSID_PSWD: { + debugf("[SC] GOT_SSID_PSWD"); + auto cfg = static_cast(pdata); assert(cfg != nullptr); + if(cfg == nullptr) { + return; + } evt.ssid = reinterpret_cast(cfg->ssid); evt.password = reinterpret_cast(cfg->password); - evt.bssidSet = (cfg->bssid_set != 0); + evt.bssidSet = cfg->bssid_set; evt.bssid = cfg->bssid; + evt.type = SmartConfigType(cfg->type); + event = SCE_Link; break; } - case SC_STATUS_LINK_OVER: - debugf("SC_STATUS_LINK_OVER\n"); - break; + default: + debugf("[SC] UNKNOWN %u", event_id); + return; } - bool processInternal = true; - if(smartConfigCallback) { - processInternal = smartConfigCallback(SmartConfigEvent(status), evt); + if(smartConfigCallback && !smartConfigCallback(event, evt)) { + return; } - if(processInternal) { - switch(status) { - case SC_STATUS_WAIT: - break; - case SC_STATUS_FIND_CHANNEL: - break; - case SC_STATUS_GETTING_SSID_PSWD: - break; - case SC_STATUS_LINK: - config(evt.ssid, evt.password, true, true); - connect(); - break; - case SC_STATUS_LINK_OVER: - smartConfigStop(); - break; - } + switch(event_id) { + case SC_EVENT_GOT_SSID_PSWD: + config(evt.ssid, evt.password, true, true); + connect(); + break; + case SC_EVENT_SEND_ACK_DONE: + smartConfigStop(); + break; + default:; } } +void StationImpl::smartConfigEventHandler(void* arg, esp_event_base_t base, int32_t id, void* data) +{ + auto self = static_cast(arg); + return self->internalSmartConfig(smartconfig_event_t(id), data); +} + bool StationImpl::smartConfigStart(SmartConfigType sctype, SmartConfigDelegate callback) { - if(smartConfigEventInfo != nullptr) { + if(smartConfigEventInfo) { return false; // Already in progress } - if(!smartconfig_set_type(sc_type(sctype))) { + if(esp_smartconfig_set_type(smartconfig_type_t(sctype)) != ESP_OK) { debug_e("smartconfig_set_type(%u) failed", sctype); return false; } - smartConfigEventInfo = new SmartConfigEventInfo; - if(smartConfigEventInfo == nullptr) { + smartConfigEventInfo.reset(new SmartConfigEventInfo{}); + if(!smartConfigEventInfo) { return false; } - // Bug in SDK Version 3 where a debug statement attempts to read from flash and throws a memory exception - // This is a workaround - auto os_print = system_get_os_print(); - if(os_print) { - system_set_os_print(false); - } - smartConfigCallback = callback; - if(!smartconfig_start([](sc_status status, void* pdata) { station.internalSmartConfig(status, pdata); })) { - debug_e("smartconfig_start() failed"); + ESP_ERROR_CHECK(esp_event_handler_register(SC_EVENT, ESP_EVENT_ANY_ID, smartConfigEventHandler, this)); + + smartconfig_start_config_t cfg = SMARTCONFIG_START_CONFIG_DEFAULT(); + if(esp_smartconfig_start(&cfg) != ESP_OK) { + debug_e("esp_smartconfig_start() failed"); + esp_event_handler_unregister(SC_EVENT, ESP_EVENT_ANY_ID, smartConfigEventHandler); smartConfigCallback = nullptr; - delete smartConfigEventInfo; - smartConfigEventInfo = nullptr; + smartConfigEventInfo.reset(); return false; } - if(os_print) { - system_set_os_print(true); - } - return true; } void StationImpl::smartConfigStop() { - smartconfig_stop(); + esp_event_handler_unregister(SC_EVENT, ESP_EVENT_ANY_ID, smartConfigEventHandler); + esp_smartconfig_stop(); smartConfigCallback = nullptr; - delete smartConfigEventInfo; - smartConfigEventInfo = nullptr; + smartConfigEventInfo.reset(); } #endif // ENABLE_SMART_CONFIG #ifdef ENABLE_WPS -void StationImpl::wpsEventHandler(esp_event_base_t event_base, int32_t event_id, void* event_data) +void StationImpl::wpsEventHandler(int32_t event_id, void* event_data) { - if(wpsConfig == nullptr) { - return; - } - switch(event_id) { case WIFI_EVENT_STA_DISCONNECTED: debug_w("WIFI_EVENT_STA_DISCONNECTED"); @@ -574,8 +638,6 @@ bool StationImpl::wpsConfigStart(WPSConfigDelegate callback) debug_d("[WPS] wpsConfigStart()"); - ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, staticWpsEventHandler, this)); - enable(true, false); connect(); @@ -595,9 +657,11 @@ bool StationImpl::wpsCallback(WpsStatus status) void StationImpl::wpsConfigStop() { ESP_ERROR_CHECK(esp_wifi_wps_disable()); - ESP_ERROR_CHECK(esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, staticWpsEventHandler)); delete wpsConfig; wpsConfig = nullptr; } #endif // ENABLE_WPS + +}; // namespace Network +}; // namespace SmingInternal diff --git a/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.h b/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.h index 6aa477391a..1a1842d206 100644 --- a/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.h +++ b/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.h @@ -4,7 +4,7 @@ * http://github.com/SmingHub/Sming * All files of the Sming Core are provided under the LGPL v3 license. * - * StationImpl.h - Esp8266 WiFi Station + * StationImpl.h - Esp32 WiFi Station * ****/ @@ -16,10 +16,15 @@ #ifdef ENABLE_SMART_CONFIG #include +#include #endif struct esp_netif_obj; +namespace SmingInternal +{ +namespace Network +{ class StationImpl : public StationClass, protected ISystemReadyHandler { public: @@ -61,26 +66,26 @@ class StationImpl : public StationClass, protected ISystemReadyHandler void wpsConfigStop() override; #endif + // Called from WifiEventsImpl + void eventHandler(esp_event_base_t base, int32_t id, void* data); + protected: void onSystemReady() override; private: static void staticScanCompleted(wifi_event_sta_scan_done_t* event, uint8_t status); #ifdef ENABLE_WPS - static void staticWpsEventHandler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) - { - auto self = static_cast(arg); - self->wpsEventHandler(event_base, event_id, event_data); - } - void wpsEventHandler(esp_event_base_t event_base, int32_t event_id, void* event_data); + void wpsEventHandler(int32_t event_id, void* event_data); bool wpsCallback(WpsStatus status); bool wpsConfigure(uint8_t credIndex); #endif #ifdef ENABLE_SMART_CONFIG - void internalSmartConfig(sc_status status, void* pdata); + void internalSmartConfig(smartconfig_event_t event, void* pdata); + static void smartConfigEventHandler(void* arg, esp_event_base_t base, int32_t id, void* data); #endif private: + StationConnectionStatus connectionStatus{eSCS_Idle}; bool runScan{false}; #ifdef ENABLE_WPS struct WpsConfig; @@ -91,3 +96,8 @@ class StationImpl : public StationClass, protected ISystemReadyHandler #endif esp_netif_obj* stationNetworkInterface{nullptr}; }; + +extern StationImpl station; + +}; // namespace Network +}; // namespace SmingInternal diff --git a/Sming/Components/Network/Arch/Esp32/Platform/WifiEventsImpl.cpp b/Sming/Components/Network/Arch/Esp32/Platform/WifiEventsImpl.cpp index dcadfad2b9..d6ff95efbe 100644 --- a/Sming/Components/Network/Arch/Esp32/Platform/WifiEventsImpl.cpp +++ b/Sming/Components/Network/Arch/Esp32/Platform/WifiEventsImpl.cpp @@ -5,22 +5,19 @@ * All files of the Sming Core are provided under the LGPL v3 license. * * WifiEventsImpl.cpp - * - * Created on: 19 февр. 2016 г. - * Author: shurik */ #include "WifiEventsImpl.h" -#include -#include -#include +#include "StationImpl.h" #include -static WifiEventsImpl events; -WifiEventsClass& WifiEvents = events; +WifiEventsClass& WifiEvents{SmingInternal::Network::events}; -StationConnectionStatus WifiEventsImpl::stationConnectionStatus = eSCS_Idle; -extern void wifi_set_event_handler_cb(esp_event_handler_t eventHandler); +namespace SmingInternal +{ +namespace Network +{ +WifiEventsImpl events; ip_addr_t ip(esp_ip4_addr_t ip) { @@ -28,23 +25,11 @@ ip_addr_t ip(esp_ip4_addr_t ip) return r; } -WifiEventsImpl::WifiEventsImpl() -{ - auto eventHandler = [](void* arg, esp_event_base_t base, int32_t id, void* data) -> void { - events.WifiEventHandler(arg, base, id, data); - }; - wifi_set_event_handler_cb(eventHandler); -} - -void WifiEventsImpl::WifiEventHandler(void* arg, esp_event_base_t base, int32_t id, void* data) +void WifiEventsImpl::eventHandler(esp_event_base_t base, int32_t id, void* data) { - debugf("event %s|%d\n", base, id); - if(base == WIFI_EVENT) { switch(id) { case WIFI_EVENT_STA_START: - stationConnectionStatus = eSCS_Connecting; - esp_wifi_connect(); break; case WIFI_EVENT_STA_CONNECTED: { wifi_event_sta_connected_t* event = reinterpret_cast(data); @@ -56,7 +41,6 @@ void WifiEventsImpl::WifiEventHandler(void* arg, esp_event_base_t base, int32_t break; } case WIFI_EVENT_STA_DISCONNECTED: { - stationConnectionStatus = eSCS_ConnectionFailed; wifi_event_sta_disconnected_t* event = reinterpret_cast(data); debugf("disconnect from ssid %s, reason %d\n", event->ssid, event->reason); if(onSTADisconnect) { @@ -117,7 +101,6 @@ void WifiEventsImpl::WifiEventHandler(void* arg, esp_event_base_t base, int32_t } else if(base == IP_EVENT) { switch(id) { case IP_EVENT_STA_GOT_IP: { - stationConnectionStatus = eSCS_GotIP; ip_event_got_ip_t* event = reinterpret_cast(data); debugf("ip:" IPSTR ",mask:" IPSTR ",gw:" IPSTR "\n", IP2STR(&event->ip_info.ip), IP2STR(&event->ip_info.netmask), IP2STR(&event->ip_info.gw)); @@ -139,3 +122,6 @@ void WifiEventsImpl::WifiEventHandler(void* arg, esp_event_base_t base, int32_t } // switch id } } + +} // namespace Network +} // namespace SmingInternal diff --git a/Sming/Components/Network/Arch/Esp32/Platform/WifiEventsImpl.h b/Sming/Components/Network/Arch/Esp32/Platform/WifiEventsImpl.h index a420cc1ea1..99886ae9f9 100644 --- a/Sming/Components/Network/Arch/Esp32/Platform/WifiEventsImpl.h +++ b/Sming/Components/Network/Arch/Esp32/Platform/WifiEventsImpl.h @@ -4,7 +4,7 @@ * http://github.com/SmingHub/Sming * All files of the Sming Core are provided under the LGPL v3 license. * - * WifiEventsImpl.h - Esp8266 WiFi events + * WifiEventsImpl.h - Esp32 WiFi events * ****/ @@ -14,14 +14,16 @@ #include #include +namespace SmingInternal +{ +namespace Network +{ class WifiEventsImpl : public WifiEventsClass { public: - static StationConnectionStatus stationConnectionStatus; - -public: - WifiEventsImpl(); - -private: - void WifiEventHandler(void* arg, esp_event_base_t base, int32_t id, void* data); + void eventHandler(esp_event_base_t base, int32_t id, void* data); }; + +extern WifiEventsImpl events; +} // namespace Network +} // namespace SmingInternal diff --git a/Sming/Components/Network/Arch/Esp32/Platform/init.cpp b/Sming/Components/Network/Arch/Esp32/Platform/init.cpp new file mode 100644 index 0000000000..2b90f0d22f --- /dev/null +++ b/Sming/Components/Network/Arch/Esp32/Platform/init.cpp @@ -0,0 +1,44 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * init.cpp + */ + +#include "StationImpl.h" +#include "AccessPointImpl.h" +#include "WifiEventsImpl.h" +#include +#include + +// Called from startup +void esp_network_initialise() +{ + /* + * Initialise NVS which IDF WiFi uses to store configuration parameters. + */ + esp_err_t ret = nvs_flash_init(); + if(ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + /* + * Initialise default WiFi stack + */ + esp_netif_init(); + auto eventHandler = [](void* arg, esp_event_base_t base, int32_t id, void* data) -> void { + using namespace SmingInternal::Network; + debugf("event %s|%d\n", base, id); + station.eventHandler(base, id, data); + accessPoint.eventHandler(base, id, data); + events.eventHandler(base, id, data); + }; + ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, eventHandler, nullptr)); + ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, eventHandler, nullptr)); + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); +} diff --git a/Sming/Components/Network/Arch/Host/Platform/StationImpl.cpp b/Sming/Components/Network/Arch/Host/Platform/StationImpl.cpp index bda2418983..f2e6fc7e11 100644 --- a/Sming/Components/Network/Arch/Host/Platform/StationImpl.cpp +++ b/Sming/Components/Network/Arch/Host/Platform/StationImpl.cpp @@ -12,6 +12,7 @@ #include "WifiEventsImpl.h" #include #include +#include StationImpl station; StationClass& WifiStation = station; @@ -57,12 +58,6 @@ static StationImpl::ApInfo apInfoList[] = { }, }; -// Called directly from startup code -void host_wifi_lwip_init_complete(void) -{ - station.initialise(netif_default); -} - static int getRandomRssi() { return int(os_random() % 50) - 90; @@ -83,6 +78,7 @@ class BssInfoImpl : public BssInfo StationImpl::StationImpl() : currentAp(&apInfoList[0]), savedAp(&apInfoList[0]) { + host_lwip_on_init_complete([]() { station.initialise(netif_default); }); } void StationImpl::initialise(netif* nif) diff --git a/Sming/Components/Network/Arch/Rp2040/Platform/AccessPointImpl.cpp b/Sming/Components/Network/Arch/Rp2040/Platform/AccessPointImpl.cpp new file mode 100644 index 0000000000..32a3b7eca3 --- /dev/null +++ b/Sming/Components/Network/Arch/Rp2040/Platform/AccessPointImpl.cpp @@ -0,0 +1,84 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * AccessPointImpl.cpp + * + ****/ + +#include "AccessPointImpl.h" +#include "StationListImpl.h" + +static AccessPointImpl accessPoint; +AccessPointClass& WifiAccessPoint = accessPoint; + +void AccessPointImpl::enable(bool enabled, bool save) +{ +} + +bool AccessPointImpl::isEnabled() const +{ + return false; +} + +bool AccessPointImpl::config(const String& ssid, String password, WifiAuthMode mode, bool hidden, int channel, + int beaconInterval) +{ + return false; +} + +IpAddress AccessPointImpl::getIP() const +{ + return IpAddress{}; +} + +IpAddress AccessPointImpl::getNetworkBroadcast() const +{ + return IpAddress{}; +} + +IpAddress AccessPointImpl::getNetworkMask() const +{ + return IpAddress{}; +} + +IpAddress AccessPointImpl::getNetworkGateway() const +{ + return IpAddress{}; +} + +bool AccessPointImpl::setIP(IpAddress address) +{ + return false; +} + +MacAddress AccessPointImpl::getMacAddress() const +{ + return MacAddress{}; +} + +bool AccessPointImpl::setMacAddress(const MacAddress& addr) const +{ + return false; +} + +String AccessPointImpl::getSSID() const +{ + return nullptr; +} + +String AccessPointImpl::getPassword() const +{ + return nullptr; +} + +std::unique_ptr AccessPointImpl::getStations() const +{ + return std::unique_ptr(new StationListImpl); +} + +void AccessPointImpl::onSystemReady() +{ +} diff --git a/Sming/Components/Network/Arch/Rp2040/Platform/AccessPointImpl.h b/Sming/Components/Network/Arch/Rp2040/Platform/AccessPointImpl.h new file mode 100644 index 0000000000..9ad1964628 --- /dev/null +++ b/Sming/Components/Network/Arch/Rp2040/Platform/AccessPointImpl.h @@ -0,0 +1,41 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * AccessPointImpl.h - Esp8266 WiFi Access Point + * + ****/ + +#pragma once + +#include +#include + +class AccessPointImpl : public AccessPointClass, protected ISystemReadyHandler +{ +public: + AccessPointImpl() + { + System.onReady(this); + } + + void enable(bool enabled, bool save) override; + bool isEnabled() const override; + bool config(const String& ssid, String password, WifiAuthMode mode, bool hidden, int channel, + int beaconInterval) override; + IpAddress getIP() const override; + bool setIP(IpAddress address) override; + MacAddress getMacAddress() const override; + bool setMacAddress(const MacAddress& addr) const override; + IpAddress getNetworkMask() const override; + IpAddress getNetworkGateway() const override; + IpAddress getNetworkBroadcast() const override; + String getSSID() const override; + String getPassword() const override; + std::unique_ptr getStations() const override; + +protected: + void onSystemReady() override; +}; diff --git a/Sming/Components/Network/Arch/Rp2040/Platform/StationImpl.cpp b/Sming/Components/Network/Arch/Rp2040/Platform/StationImpl.cpp new file mode 100644 index 0000000000..5cf95b2b24 --- /dev/null +++ b/Sming/Components/Network/Arch/Rp2040/Platform/StationImpl.cpp @@ -0,0 +1,161 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * StationImpl.cpp + * + ****/ + +#include "StationImpl.h" +#include "WifiEventsImpl.h" + +static StationImpl station; +StationClass& WifiStation = station; + +void StationImpl::enable(bool enabled, bool save) +{ +} + +bool StationImpl::isEnabled() const +{ + return false; +} + +bool StationImpl::config(const String& ssid, const String& password, bool autoConnectOnStartup, bool save) +{ + return false; +} + +bool StationImpl::connect() +{ + return false; +} + +bool StationImpl::disconnect() +{ + return false; +} + +bool StationImpl::isEnabledDHCP() const +{ + return false; +} + +void StationImpl::enableDHCP(bool enable) +{ +} + +void StationImpl::setHostname(const String& hostname) +{ +} + +String StationImpl::getHostname() const +{ + return nullptr; +} + +IpAddress StationImpl::getIP() const +{ + return IpAddress{}; +} + +MacAddress StationImpl::getMacAddress() const +{ + return MacAddress{}; +} + +bool StationImpl::setMacAddress(const MacAddress& addr) const +{ + return false; +} + +IpAddress StationImpl::getNetworkBroadcast() const +{ + return IpAddress{}; +} + +IpAddress StationImpl::getNetworkMask() const +{ + return IpAddress{}; +} + +IpAddress StationImpl::getNetworkGateway() const +{ + return IpAddress{}; +} + +bool StationImpl::setIP(IpAddress address, IpAddress netmask, IpAddress gateway) +{ + return false; +} + +String StationImpl::getSSID() const +{ + return nullptr; +} + +int8_t StationImpl::getRssi() const +{ + return 0; +} + +uint8_t StationImpl::getChannel() const +{ + return 0; +} + +String StationImpl::getPassword() const +{ + return nullptr; +} + +StationConnectionStatus StationImpl::getConnectionStatus() const +{ + return eSCS_Idle; +} + +bool StationImpl::startScan(ScanCompletedDelegate scanCompleted) +{ + return false; +} + +void StationImpl::onSystemReady() +{ +} + +#ifdef ENABLE_SMART_CONFIG + +void StationImpl::internalSmartConfig(sc_status status, void* pdata) +{ +} + +bool StationImpl::smartConfigStart(SmartConfigType sctype, SmartConfigDelegate callback) +{ + return false; +} + +void StationImpl::smartConfigStop() +{ +} + +#endif // ENABLE_SMART_CONFIG + +#ifdef ENABLE_WPS + +bool StationImpl::wpsConfigure(uint8_t credIndex) +{ + return false; +} + +bool StationImpl::wpsConfigStart(WPSConfigDelegate callback) +{ + return false; +} + +void StationImpl::wpsConfigStop() +{ +} + +#endif // ENABLE_WPS diff --git a/Sming/Components/Network/Arch/Rp2040/Platform/StationImpl.h b/Sming/Components/Network/Arch/Rp2040/Platform/StationImpl.h new file mode 100644 index 0000000000..43d189e865 --- /dev/null +++ b/Sming/Components/Network/Arch/Rp2040/Platform/StationImpl.h @@ -0,0 +1,59 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * StationImpl.h - Esp8266 WiFi Station + * + ****/ + +#pragma once + +#include +#include + +class StationImpl : public StationClass, protected ISystemReadyHandler +{ +public: + StationImpl() + { + System.onReady(this); + } + + void enable(bool enabled, bool save) override; + bool isEnabled() const override; + bool config(const String& ssid, const String& password, bool autoConnectOnStartup, bool save) override; + bool connect() override; + bool disconnect() override; + StationConnectionStatus getConnectionStatus() const override; + bool isEnabledDHCP() const override; + void enableDHCP(bool enable) override; + void setHostname(const String& hostname) override; + String getHostname() const override; + IpAddress getIP() const override; + MacAddress getMacAddress() const override; + bool setMacAddress(const MacAddress& addr) const override; + IpAddress getNetworkMask() const override; + IpAddress getNetworkGateway() const override; + IpAddress getNetworkBroadcast() const override; + bool setIP(IpAddress address, IpAddress netmask, IpAddress gateway) override; + String getSSID() const override; + String getPassword() const override; + int8_t getRssi() const override; + uint8_t getChannel() const override; + bool startScan(ScanCompletedDelegate scanCompleted) override; + +#ifdef ENABLE_SMART_CONFIG + bool smartConfigStart(SmartConfigType sctype, SmartConfigDelegate callback) override; + void smartConfigStop() override; +#endif + +#ifdef ENABLE_WPS + bool wpsConfigStart(WPSConfigDelegate callback) override; + void wpsConfigStop() override; +#endif + +protected: + void onSystemReady() override; +}; diff --git a/Sming/Components/Network/Arch/Rp2040/Platform/StationListImpl.h b/Sming/Components/Network/Arch/Rp2040/Platform/StationListImpl.h new file mode 100644 index 0000000000..7ff39dc230 --- /dev/null +++ b/Sming/Components/Network/Arch/Rp2040/Platform/StationListImpl.h @@ -0,0 +1,46 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * StationListImpl.h + * + ****/ + +#pragma once + +#include + +class StationListImpl : public StationList +{ +public: + StationListImpl() + { + add(new Info{}); + } + +private: + class Info : public StationInfo + { + public: + Info() + { + } + + MacAddress mac() const override + { + return MacAddress{}; + } + + int8_t rssi() const override + { + return 0; + } + + IpAddress ip() const override + { + return IpAddress{}; + } + }; +}; diff --git a/Sming/Components/Network/Arch/Rp2040/Platform/WifiEventsImpl.cpp b/Sming/Components/Network/Arch/Rp2040/Platform/WifiEventsImpl.cpp new file mode 100644 index 0000000000..cfe7636320 --- /dev/null +++ b/Sming/Components/Network/Arch/Rp2040/Platform/WifiEventsImpl.cpp @@ -0,0 +1,21 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * WifiEventsImpl.cpp + * + * Created on: 19 февр. 2016 г. + * Author: shurik + */ + +#include "WifiEventsImpl.h" +#include + +static WifiEventsImpl events; +WifiEventsClass& WifiEvents = events; + +WifiEventsImpl::WifiEventsImpl() +{ +} diff --git a/Sming/Components/Network/Arch/Rp2040/Platform/WifiEventsImpl.h b/Sming/Components/Network/Arch/Rp2040/Platform/WifiEventsImpl.h new file mode 100644 index 0000000000..2d13fa756d --- /dev/null +++ b/Sming/Components/Network/Arch/Rp2040/Platform/WifiEventsImpl.h @@ -0,0 +1,23 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * WifiEventsImpl.h - Esp8266 WiFi events + * + ****/ + +#pragma once + +#include +#include + +class WifiEventsImpl : public WifiEventsClass +{ +public: + static StationConnectionStatus stationConnectionStatus; + +public: + WifiEventsImpl(); +}; diff --git a/Sming/Components/Network/component.mk b/Sming/Components/Network/component.mk index c6eec0041e..893ea752f2 100644 --- a/Sming/Components/Network/component.mk +++ b/Sming/Components/Network/component.mk @@ -1,5 +1,3 @@ -COMPONENT_SOC := esp* host - COMPONENT_SRCDIRS := \ src \ $(call ListAllSubDirs,$(COMPONENT_PATH)/src) \ @@ -71,4 +69,9 @@ COMPONENT_DEPENDS += \ esp_wifi \ lwip +else ifeq ($(SMING_ARCH),Rp2040) + +COMPONENT_DEPENDS += \ + lwip + endif diff --git a/Sming/Components/Network/src/Network/NetUtils.h b/Sming/Components/Network/src/Network/NetUtils.h index 46e5192dc0..770592f002 100644 --- a/Sming/Components/Network/src/Network/NetUtils.h +++ b/Sming/Components/Network/src/Network/NetUtils.h @@ -10,10 +10,12 @@ #pragma once -#ifdef ARCH_ESP8266 -#include "lwip/tcp_impl.h" -#else +#include + +#if LWIP_VERSION_MAJOR == 2 #include "lwip/priv/tcp_priv.h" +#else +#include "lwip/tcp_impl.h" #endif struct pbuf; diff --git a/Sming/Components/Network/src/Platform/Station.h b/Sming/Components/Network/src/Platform/Station.h index aa64fba07f..32b9c37d70 100644 --- a/Sming/Components/Network/src/Platform/Station.h +++ b/Sming/Components/Network/src/Platform/Station.h @@ -43,6 +43,7 @@ enum SmartConfigType { SCT_EspTouch, ///< ESP Touch SCT_AirKiss, ///< Air Kiss SCT_EspTouch_AirKiss, ///< ESP Touch and Air Kiss + SCT_EspTouch_V2, ///< ESP Touch version 2 }; /// Smart configuration event diff --git a/Sming/Components/Storage/src/Debug.cpp b/Sming/Components/Storage/src/Debug.cpp new file mode 100644 index 0000000000..37d261ecea --- /dev/null +++ b/Sming/Components/Storage/src/Debug.cpp @@ -0,0 +1,69 @@ +#include "include/Storage/Debug.h" +#include "include/Storage.h" +#include "include/Storage/SpiFlash.h" + +namespace Storage +{ +namespace Debug +{ +void printPartition(Print& out, Partition part, bool includeDevice) +{ + out.print(part.name()); + if(includeDevice) { + out.print(" on "); + out.print(part.getDeviceName()); + } + out.print(" ("); + out.print(part.typeString()); + out.print(_F(" @ 0x")); + out.print(part.address(), HEX); + out.print(_F(", size 0x")); + out.print(part.size(), HEX); + out.println(")"); +} + +void listPartitions(Print& out) +{ + out.println(); + out.println(_F("Registered partitions:")); + for(auto it = Storage::findPartition(); it; ++it) { + out.print("- "); + printPartition(out, *it); + } + out.println(); +} + +void listDevices(Print& out, bool fullPartitionInfo) +{ + out.println(); + out.println(_F("Registered storage devices:")); + for(auto& dev : Storage::getDevices()) { + out.print(" name = '"); + out.print(dev.getName()); + out.print(_F("', type = ")); + out.print(toString(dev.getType())); + out.print(_F(", size = 0x")); + out.print(dev.getSize(), HEX); + out.print(_F(", partitions:")); + if(dev.partitions().count() == 0) { + out.println(_F(" None.")); + continue; + } + + out.println(); + for(auto part : dev.partitions()) { + if(fullPartitionInfo) { + out.print(" "); + printPartition(out, part, false); + } else { + out.print(" "); + out.print(part.name()); + } + } + out.println(); + } + out.println(); +} + +} // namespace Debug +} // namespace Storage diff --git a/Sming/Components/Storage/src/PartitionStream.cpp b/Sming/Components/Storage/src/PartitionStream.cpp index d89f43df1f..beec49dd7d 100644 --- a/Sming/Components/Storage/src/PartitionStream.cpp +++ b/Sming/Components/Storage/src/PartitionStream.cpp @@ -9,6 +9,7 @@ ****/ #include "include/Storage/PartitionStream.h" +#include namespace Storage { @@ -46,15 +47,29 @@ int PartitionStream::seekFrom(int offset, SeekOrigin origin) size_t PartitionStream::write(const uint8_t* data, size_t length) { auto len = std::min(size_t(size - writePos), length); - if(len != 0) { - if(!partition.write(startOffset + writePos, data, len)) { - len = 0; - } else { - writePos += len; + if(len == 0) { + return 0; + } + + if(blockErase) { + auto endPos = writePos + len; + if(endPos > erasePos) { + size_t blockSize = partition.getBlockSize(); + size_t eraseLen = endPos - erasePos + blockSize - 1; + eraseLen -= eraseLen % blockSize; + debug_d("[PS] erase(0x%08x, 0x%08x", startOffset + erasePos, eraseLen); + if(!partition.erase_range(startOffset + erasePos, eraseLen)) { + return 0; + } + erasePos += eraseLen; } } - // Return amount actually written + if(!partition.write(startOffset + writePos, data, len)) { + return 0; + } + + writePos += len; return len; } diff --git a/Sming/Components/Storage/src/include/Storage/Debug.h b/Sming/Components/Storage/src/include/Storage/Debug.h new file mode 100644 index 0000000000..74c99c3b57 --- /dev/null +++ b/Sming/Components/Storage/src/include/Storage/Debug.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include "Partition.h" + +namespace Storage +{ +namespace Debug +{ +void printPartition(Print& out, Partition part, bool includeDevice = true); +void listPartitions(Print& out); +void listDevices(Print& out, bool fullPartitionInfo = true); + +} // namespace Debug +} // namespace Storage diff --git a/Sming/Components/Storage/src/include/Storage/PartitionStream.h b/Sming/Components/Storage/src/include/Storage/PartitionStream.h index 93debaeaff..09d19570f8 100644 --- a/Sming/Components/Storage/src/include/Storage/PartitionStream.h +++ b/Sming/Components/Storage/src/include/Storage/PartitionStream.h @@ -25,12 +25,29 @@ namespace Storage class PartitionStream : public ReadWriteStream { public: - PartitionStream(Partition partition, uint32_t offset, size_t size) - : partition(partition), startOffset(offset), size(size) + /** + * @brief Access part of a partition using a stream + * @param partition + * @param offset Limit access to this starting offset + * @param size Limit access to this number of bytes from starting offset + * @param blockErase Set to true to erase blocks before writing + * + * If blockErase is false then region must be pre-erased before writing. + */ + PartitionStream(Partition partition, uint32_t offset, size_t size, bool blockErase = false) + : partition(partition), startOffset(offset), size(size), blockErase(blockErase) { } - PartitionStream(Partition partition) : partition(partition), startOffset(0), size(partition.size()) + /** + * @brief Access entire partition using stream + * @param partition + * @param blockErase Set to true to erase blocks before writing + * + * If blockErase is false then partition must be pre-erased before writing. + */ + PartitionStream(Partition partition, bool blockErase = false) + : partition(partition), startOffset{0}, size(partition.size()), blockErase(blockErase) { } @@ -56,6 +73,8 @@ class PartitionStream : public ReadWriteStream size_t size; uint32_t writePos{0}; uint32_t readPos{0}; + uint32_t erasePos{0}; + bool blockErase; }; } // namespace Storage diff --git a/Sming/Components/arch_driver/src/include/driver/uart.h b/Sming/Components/arch_driver/src/include/driver/uart.h index e568bc606f..f7ed88c90e 100644 --- a/Sming/Components/arch_driver/src/include/driver/uart.h +++ b/Sming/Components/arch_driver/src/include/driver/uart.h @@ -104,9 +104,9 @@ static inline constexpr uint8_t SMG_UART_FORMAT(smg_uart_bits_t databits, smg_ua } /** - * @brief Structure for easier decomposing of `config` value + * @brief Structure for easier decomposing of `format` value * - * Used by drivers to read config values + * Used by drivers to read format values */ union smg_uart_config_format_t { struct { @@ -254,20 +254,46 @@ struct smg_uart_config_t { uint8_t rx_pin; smg_uart_mode_t mode; ///< Whether to enable receive, transmit or both uart_options_t options; - uint32_t baudrate; ///< Requested baudrate; actual baudrate may differ - uint32_t config; ///< UART CONF0 register bits + uint32_t baudrate; ///< Requested baudrate; actual baudrate may differ + smg_uart_format_t format; ///< UART CONF0 register bits size_t rx_size; size_t tx_size; }; // @deprecated Use `smg_uart_init_ex()` instead -smg_uart_t* smg_uart_init(uint8_t uart_nr, uint32_t baudrate, uint32_t config, smg_uart_mode_t mode, uint8_t tx_pin, - size_t rx_size, size_t tx_size = 0); +smg_uart_t* smg_uart_init(uint8_t uart_nr, uint32_t baudrate, smg_uart_format_t format, smg_uart_mode_t mode, + uint8_t tx_pin, size_t rx_size, size_t tx_size = 0); smg_uart_t* smg_uart_init_ex(const smg_uart_config_t& cfg); void smg_uart_uninit(smg_uart_t* uart); +/** + * @brief Set the UART data format + * @param uart + * @param format UART CONF0 register bits + */ +void smg_uart_set_format(smg_uart_t* uart, smg_uart_format_t format); + +/** + * @brief UART interrupt configuration parameters for smg_uart_intr_config function + * + * Threshold values are expressed in character times + */ +typedef struct { + uint8_t rx_timeout_thresh; + uint8_t txfifo_empty_intr_thresh; + uint8_t rxfifo_full_thresh; ///< Ignored if additional buffers are allocated +} smg_uart_intr_config_t; + +/** + * @brief Configure interrupt thresholds + * @param uart + * @param config + * @retval bool true on success, false on error (bad parameter or unsupported) + */ +bool smg_uart_intr_config(smg_uart_t* uart, const smg_uart_intr_config_t* config); + __forceinline int smg_uart_get_nr(smg_uart_t* uart) { return uart ? uart->uart_nr : -1; @@ -488,6 +514,9 @@ void smg_uart_restore_interrupts(); /** @} */ +// Internal routine +bool smg_uart_realloc_buffer(SerialBuffer*& buffer, size_t new_size); + #if defined(__cplusplus) } // extern "C" #endif diff --git a/Sming/Components/arch_driver/src/uart.cpp b/Sming/Components/arch_driver/src/uart.cpp new file mode 100644 index 0000000000..456776090b --- /dev/null +++ b/Sming/Components/arch_driver/src/uart.cpp @@ -0,0 +1,102 @@ +#include "include/driver/uart.h" +#include "include/driver/SerialBuffer.h" +#include +#include + +bool smg_uart_realloc_buffer(SerialBuffer*& buffer, size_t new_size) +{ + if(buffer != nullptr) { + size_t res = 0; + smg_uart_disable_interrupts(); + if(new_size == 0) { + delete buffer; + buffer = nullptr; + } else { + res = buffer->resize(new_size); + } + smg_uart_restore_interrupts(); + + return res == new_size; + } + + if(new_size == 0) { + return true; + } + +#ifdef ARCH_ESP32 + // Avoid allocating in SPIRAM + auto mem = heap_caps_malloc(sizeof(SerialBuffer), MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL); + auto new_buf = new(mem) SerialBuffer; +#else + auto new_buf = new SerialBuffer; +#endif + if(new_buf != nullptr && new_buf->resize(new_size) == new_size) { + buffer = new_buf; + return true; + } + + delete new_buf; + return false; +} + +smg_uart_t* smg_uart_init(uint8_t uart_nr, uint32_t baudrate, smg_uart_format_t format, smg_uart_mode_t mode, + uint8_t tx_pin, size_t rx_size, size_t tx_size) +{ + smg_uart_config_t cfg = { + .uart_nr = uart_nr, + .tx_pin = tx_pin, + .rx_pin = UART_PIN_DEFAULT, + .mode = mode, + .options = _BV(UART_OPT_TXWAIT), + .baudrate = baudrate, + .format = format, + .rx_size = rx_size, + .tx_size = tx_size, + }; + return smg_uart_init_ex(cfg); +} + +size_t smg_uart_resize_rx_buffer(smg_uart_t* uart, size_t new_size) +{ + if(smg_uart_rx_enabled(uart)) { + smg_uart_realloc_buffer(uart->rx_buffer, new_size); + } + return smg_uart_rx_buffer_size(uart); +} + +size_t smg_uart_rx_buffer_size(smg_uart_t* uart) +{ + return uart != nullptr && uart->rx_buffer != nullptr ? uart->rx_buffer->getSize() : 0; +} + +size_t smg_uart_resize_tx_buffer(smg_uart_t* uart, size_t new_size) +{ + if(smg_uart_tx_enabled(uart)) { + smg_uart_realloc_buffer(uart->tx_buffer, new_size); + } + return smg_uart_tx_buffer_size(uart); +} + +size_t smg_uart_tx_buffer_size(smg_uart_t* uart) +{ + return uart != nullptr && uart->tx_buffer != nullptr ? uart->tx_buffer->getSize() : 0; +} + +int smg_uart_peek_char(smg_uart_t* uart) +{ + return uart != nullptr && uart->rx_buffer ? uart->rx_buffer->peekChar() : -1; +} + +int smg_uart_rx_find(smg_uart_t* uart, char c) +{ + if(uart == nullptr || uart->rx_buffer == nullptr) { + return -1; + } + + return uart->rx_buffer->find(c); +} + +int smg_uart_peek_last_char(smg_uart_t* uart) +{ + return uart != nullptr && uart->rx_buffer != nullptr ? uart->rx_buffer->peekLastChar() : -1; +} diff --git a/Sming/Components/crypto/include/Crypto/HashContext.h b/Sming/Components/crypto/include/Crypto/HashContext.h index 6192c7b59c..512d6cf477 100644 --- a/Sming/Components/crypto/include/Crypto/HashContext.h +++ b/Sming/Components/crypto/include/Crypto/HashContext.h @@ -103,7 +103,7 @@ template class HashContext */ Hash getHash() { - Hash hash; + Hash hash{}; engine.final(hash.data()); return hash; } diff --git a/Sming/Arch/Host/Components/lwip/.patches/lwip.patch b/Sming/Components/lwip/.patches/lwip.patch similarity index 79% rename from Sming/Arch/Host/Components/lwip/.patches/lwip.patch rename to Sming/Components/lwip/.patches/lwip.patch index 282244d0f1..2bcf655f45 100644 --- a/Sming/Arch/Host/Components/lwip/.patches/lwip.patch +++ b/Sming/Components/lwip/.patches/lwip.patch @@ -1,5 +1,5 @@ diff --git a/contrib/ports/unix/port/sys_arch.c b/contrib/ports/unix/port/sys_arch.c -index 1b61f205..620133d9 100644 +index 9f7c8d3a..440469c6 100644 --- a/contrib/ports/unix/port/sys_arch.c +++ b/contrib/ports/unix/port/sys_arch.c @@ -71,10 +71,12 @@ @@ -16,7 +16,7 @@ index 1b61f205..620133d9 100644 } static void -@@ -752,15 +754,3 @@ sys_arch_unprotect(sys_prot_t pval) +@@ -757,15 +759,3 @@ sys_arch_unprotect(sys_prot_t pval) } #endif /* SYS_LIGHTWEIGHT_PROT */ @@ -32,6 +32,7 @@ index 1b61f205..620133d9 100644 - return select(1, &fds, NULL, NULL, &tv); -} -#endif /* !NO_SYS */ + diff --git a/contrib/ports/CMakeCommon.cmake b/contrib/ports/CMakeCommon.cmake index fccf0f31..0a6378c4 100644 --- a/contrib/ports/CMakeCommon.cmake @@ -63,7 +64,7 @@ index fccf0f31..0a6378c4 100644 if(LWIP_USE_SANITIZERS) list(APPEND LWIP_COMPILER_FLAGS_GNU_CLANG diff --git a/contrib/ports/win32/sys_arch.c b/contrib/ports/win32/sys_arch.c -index 84c1bcaf..f23dfa67 100644 +index 61897e9d..e2eb7053 100644 --- a/contrib/ports/win32/sys_arch.c +++ b/contrib/ports/win32/sys_arch.c @@ -38,6 +38,7 @@ @@ -74,7 +75,7 @@ index 84c1bcaf..f23dfa67 100644 #ifdef _MSC_VER #pragma warning (pop) #endif -@@ -732,28 +733,6 @@ sys_arch_netconn_sem_free(void) +@@ -742,28 +743,6 @@ sys_arch_netconn_sem_free(void) #endif /* !NO_SYS */ @@ -105,7 +106,7 @@ index 84c1bcaf..f23dfa67 100644 /* This is an example implementation for LWIP_PLATFORM_DIAG: diff --git a/contrib/ports/win32/pcapif.c b/contrib/ports/win32/pcapif.c -index 36356ca5..895f2a2d 100644 +index 3066abd0..62097fee 100644 --- a/contrib/ports/win32/pcapif.c +++ b/contrib/ports/win32/pcapif.c @@ -40,16 +40,7 @@ @@ -125,7 +126,7 @@ index 36356ca5..895f2a2d 100644 #include "lwip/opt.h" -@@ -477,7 +468,6 @@ pcap_reopen_adapter(struct pcapif_private *pa) +@@ -490,7 +481,6 @@ pcap_reopen_adapter(struct pcapif_private *pa) static struct pcapif_private* pcapif_init_adapter(int adapter_num, void *arg) { @@ -133,7 +134,7 @@ index 36356ca5..895f2a2d 100644 int number_of_adapters; struct pcapif_private *pa; char errbuf[PCAP_ERRBUF_SIZE+1]; -@@ -539,6 +529,7 @@ pcapif_init_adapter(int adapter_num, void *arg) +@@ -552,6 +542,7 @@ pcapif_init_adapter(int adapter_num, void *arg) } #ifndef PCAPIF_LIB_QUIET @@ -141,3 +142,17 @@ index 36356ca5..895f2a2d 100644 /* Scan the list printing every entry */ for (d = alldevs, i = 0; d != NULL; d = d->next, i++) { char *desc = d->description; + +diff --git a/contrib/ports/win32/pcapif_helper.c b/contrib/ports/win32/pcapif_helper.c +index bc6ca8d8..82e26d27 100644 +--- a/contrib/ports/win32/pcapif_helper.c ++++ b/contrib/ports/win32/pcapif_helper.c +@@ -102,7 +102,7 @@ pcapifh_alloc_readonly_copy(void *data, size_t len) + lwip_win32_platform_diag("VirtualProtect failed: %d\n", GetLastError()); + while(1); + } +- printf("pcapifh_alloc_readonly_copy(%d): 0x%08x\n", len, ret); ++ printf("pcapifh_alloc_readonly_copy(%d): %p\n", len, ret); + return ret; + } + diff --git a/Sming/Arch/Host/Components/lwip/.patches/lwip/README.rst b/Sming/Components/lwip/.patches/lwip/README.rst similarity index 100% rename from Sming/Arch/Host/Components/lwip/.patches/lwip/README.rst rename to Sming/Components/lwip/.patches/lwip/README.rst diff --git a/Sming/Arch/Host/Components/lwip/.patches/lwip/README.txt b/Sming/Components/lwip/.patches/lwip/README.txt similarity index 100% rename from Sming/Arch/Host/Components/lwip/.patches/lwip/README.txt rename to Sming/Components/lwip/.patches/lwip/README.txt diff --git a/Sming/Arch/Host/Components/lwip/README.rst b/Sming/Components/lwip/README.rst similarity index 100% rename from Sming/Arch/Host/Components/lwip/README.rst rename to Sming/Components/lwip/README.rst diff --git a/Sming/Components/lwip/component.mk b/Sming/Components/lwip/component.mk new file mode 100644 index 0000000000..c6d48d82a8 --- /dev/null +++ b/Sming/Components/lwip/component.mk @@ -0,0 +1,51 @@ +export CC + +# => LWIP +ifndef MAKE_CLEAN +ifndef ENABLE_CUSTOM_LWIP +ENABLE_CUSTOM_LWIP := 2 +else ifneq ($(ENABLE_CUSTOM_LWIP), 2) +$(error This library requires ENABLE_CUSTOM_LWIP=2) +endif +endif + +COMPONENT_SUBMODULES := lwip + +COMPONENT_INCDIRS := \ + . \ + src/Arch/$(SMING_ARCH)/include \ + lwip/src/include + +COMPONENT_SRCDIRS := \ + src \ + src/Arch/$(SMING_ARCH) + +COMPONENT_VARS += ENABLE_LWIPDEBUG +ENABLE_LWIPDEBUG ?= 0 +LWIP_LIBNAME := clwip + +LWIP_CMAKE_OPTIONS := \ + -G Ninja \ + -DLWIP_LIBNAME=$(LWIP_LIBNAME) \ + -DLWIP_DIR=$(COMPONENT_PATH)/lwip \ + -DCMAKE_MAKE_PROGRAM="$(NINJA)" + +ifeq ($(ENABLE_LWIPDEBUG), 1) +LWIP_CMAKE_OPTIONS += -DCMAKE_BUILD_TYPE=Debug +else +LWIP_CMAKE_OPTIONS += -DCMAKE_BUILD_TYPE=Release +endif +ifeq ($(SMING_RELEASE),1) + LWIP_CMAKE_OPTIONS += -DLWIP_NOASSERT=1 +endif + +LWIP_TARGET := $(COMPONENT_LIBDIR)/lib$(LWIP_LIBNAME).a +COMPONENT_TARGETS += $(LWIP_TARGET) +EXTRA_LIBS := $(LWIP_LIBNAME) + +LWIP_ARCH_SRCDIR := $(COMPONENT_PATH)/src/Arch/$(SMING_ARCH) +include $(LWIP_ARCH_SRCDIR)/arch.mk + +$(COMPONENT_RULE)$(LWIP_TARGET): + $(Q) $(CMAKE) -DUSER_LIBDIR=$(COMPONENT_LIBDIR) $(LWIP_CMAKE_OPTIONS) $(LWIP_ARCH_SRCDIR) + $(Q) $(NINJA) diff --git a/Sming/Components/lwip/lwip b/Sming/Components/lwip/lwip new file mode 160000 index 0000000000..e8741da9d2 --- /dev/null +++ b/Sming/Components/lwip/lwip @@ -0,0 +1 @@ +Subproject commit e8741da9d2086c0fad6703536e1c6133b8f88512 diff --git a/Sming/Arch/Host/Components/lwip/lwipopts.h b/Sming/Components/lwip/lwipopts.h similarity index 100% rename from Sming/Arch/Host/Components/lwip/lwipopts.h rename to Sming/Components/lwip/lwipopts.h diff --git a/Sming/Components/lwip/src/.cs b/Sming/Components/lwip/src/.cs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Sming/Arch/Host/Components/lwip/Linux/CMakeLists.txt b/Sming/Components/lwip/src/Arch/Host/Linux/CMakeLists.txt similarity index 88% rename from Sming/Arch/Host/Components/lwip/Linux/CMakeLists.txt rename to Sming/Components/lwip/src/Arch/Host/Linux/CMakeLists.txt index 98f0637927..19ba30ac35 100644 --- a/Sming/Arch/Host/Components/lwip/Linux/CMakeLists.txt +++ b/Sming/Components/lwip/src/Arch/Host/Linux/CMakeLists.txt @@ -11,7 +11,6 @@ if (NOT CMAKE_SYSTEM_NAME STREQUAL "Linux" AND NOT CMAKE_SYSTEM_NAME STREQUAL "G endif() set (CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DLWIP_DEBUG") -set(LWIP_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../lwip) include(${LWIP_DIR}/contrib/ports/CMakeCommon.cmake) set (LWIP_INCLUDE_DIRS @@ -25,7 +24,6 @@ include(${LWIP_CONTRIB_DIR}/ports/unix/Filelists.cmake) include(${LWIP_DIR}/src/Filelists.cmake) add_library(lwip - host_lwip.c ${LWIP_DIR}/src/api/err.c ${lwipcore_SRCS} ${lwipcore4_SRCS} @@ -36,7 +34,7 @@ add_library(lwip ) set_target_properties(lwip - PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${USER_LIBDIR} PREFIX "clib-" OUTPUT_NAME "${LWIP_LIBNAME}" + PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${USER_LIBDIR} OUTPUT_NAME "${LWIP_LIBNAME}" ) target_compile_options(lwip PRIVATE ${LWIP_COMPILER_FLAGS} -m32) diff --git a/Sming/Components/lwip/src/Arch/Host/Linux/lwip_arch.cpp b/Sming/Components/lwip/src/Arch/Host/Linux/lwip_arch.cpp new file mode 100644 index 0000000000..c8ae59f16c --- /dev/null +++ b/Sming/Components/lwip/src/Arch/Host/Linux/lwip_arch.cpp @@ -0,0 +1,140 @@ +/** + * lwip_arch.cpp + * + * Copyright 2019 mikee47 + * + * This file is part of the Sming Framework Project + * + * This library is free software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, version 3 or later. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this library. + * If not, see . + * + ****/ +#include "../lwip_arch.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +extern "C" { +#include +} + +namespace +{ +struct netif net_if; + +void getMacAddress(const char* ifname, uint8_t hwaddr[6]) +{ + if(ifname == nullptr) { + return; + } + + struct ifreq ifr = {0}; + ifr.ifr_addr.sa_family = AF_INET; + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + ifr.ifr_name[IFNAMSIZ - 1] = '\0'; + + int fd = socket(AF_INET, SOCK_DGRAM, 0); + int res = ioctl(fd, SIOCGIFHWADDR, &ifr); + close(fd); + + if(res == 0) { + memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, 6); + } else { + memset(hwaddr, 0, 6); + } +} + +/** + * @brief Fetch address and network mask for an interface + * @param ifname nullptr to get first compatible interface + */ +bool getifaddr(struct lwip_net_config& netcfg) +{ + struct ifaddrs* list; + if(getifaddrs(&list) < 0) { + host_debug_e("getifaddrs: %s", strerror(errno)); + return false; + } + + bool res{false}; + + for(auto ifa = list; ifa != nullptr; ifa = ifa->ifa_next) { + if(ifa->ifa_addr == nullptr) { + continue; + } + if(ifa->ifa_addr->sa_family != AF_INET) { + continue; + } + + if(*netcfg.ifname == '\0') { + if(memcmp(ifa->ifa_name, "tap", 3) != 0) { + continue; + } + } else if(strcmp(ifa->ifa_name, netcfg.ifname) != 0) { + continue; + } + + strncpy(netcfg.ifname, ifa->ifa_name, sizeof(netcfg.ifname) - 1); + netcfg.gw.addr = ((struct sockaddr_in*)ifa->ifa_addr)->sin_addr.s_addr; + netcfg.netmask.addr = ((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr.s_addr; + + res = true; + break; + } + + freeifaddrs(list); + return res; +} + +} // namespace + +struct netif* lwip_arch_init(struct lwip_net_config& netcfg) +{ + if(!getifaddr(netcfg)) { + if(netcfg.ifname[0] == '\0') { + host_debug_e("%s", "No compatible interface found"); + } else { + host_debug_e("Interface '%s' not found", netcfg.ifname); + } + return nullptr; + } + + if(ip_addr_isany(&netcfg.ipaddr)) { + // Choose a default IP address + IP4_ADDR(&netcfg.ipaddr, (uint32_t)ip4_addr1(&netcfg.gw), (uint32_t)ip4_addr2(&netcfg.gw), + (uint32_t)ip4_addr3(&netcfg.gw), 10U); + } + + setenv("PRECONFIGURED_TAPIF", netcfg.ifname, true); + lwip_init(); + netif_add(&net_if, &netcfg.ipaddr, &netcfg.netmask, &netcfg.gw, nullptr, tapif_init, ethernet_input); + getMacAddress(netcfg.ifname, net_if.hwaddr); + + return &net_if; +} + +bool lwip_arch_service() +{ + /* poll netif, pass packet to lwIP */ + int res = tapif_select(&net_if); + netif_poll(&net_if); + sys_check_timeouts(); + + return res > 0; +} + +void lwip_arch_shutdown() +{ +} diff --git a/Sming/Components/lwip/src/Arch/Host/Windows/.gitignore b/Sming/Components/lwip/src/Arch/Host/Windows/.gitignore new file mode 100644 index 0000000000..e0287f15c4 --- /dev/null +++ b/Sming/Components/lwip/src/Arch/Host/Windows/.gitignore @@ -0,0 +1 @@ +npcap/ diff --git a/Sming/Arch/Host/Components/lwip/Windows/CMakeLists.txt b/Sming/Components/lwip/src/Arch/Host/Windows/CMakeLists.txt similarity index 65% rename from Sming/Arch/Host/Components/lwip/Windows/CMakeLists.txt rename to Sming/Components/lwip/src/Arch/Host/Windows/CMakeLists.txt index 0a9cfd1226..d3d8e7f8d2 100644 --- a/Sming/Arch/Host/Components/lwip/Windows/CMakeLists.txt +++ b/Sming/Components/lwip/src/Arch/Host/Windows/CMakeLists.txt @@ -6,37 +6,21 @@ set (BUILD_SHARED_LIBS OFF) set (CMAKE_C_STANDARD 11) set (CMAKE_C_STANDARD_REQUIRED ON) -include (ExternalProject) - -set (PCAP_SRC npcap-sdk-1.05.zip) -set (PCAP_DIR src/npcap) -ExternalProject_Add(npcap - PREFIX ${CMAKE_CURRENT_SOURCE_DIR} - URL https://nmap.org/npcap/dist/${PCAP_SRC} - URL_HASH MD5=9af87ce508bee6a347be72b3e9adf777 - PATCH_COMMAND patch -p1 -i ../../npcap.patch - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" -) - set (CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DLWIP_DEBUG") -set(LWIP_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../lwip) include(${LWIP_DIR}/contrib/ports/CMakeCommon.cmake) set (LWIP_INCLUDE_DIRS "${LWIP_DIR}/.." "${LWIP_DIR}/src/include" "${LWIP_CONTRIB_DIR}/ports/win32/include" - "${PCAP_DIR}/Include" + "${NPCAP_SRCDIR}/Include" "${CMAKE_CURRENT_SOURCE_DIR}/" ) include(${LWIP_DIR}/src/Filelists.cmake) add_library(lwip - host_lwip.c npcap.c ${LWIP_CONTRIB_DIR}/ports/win32/sys_arch.c ${LWIP_CONTRIB_DIR}/ports/win32/pcapif.c @@ -48,10 +32,8 @@ add_library(lwip ${lwipnetif_SRCS} ) -add_dependencies(lwip npcap) - set_target_properties(lwip - PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${USER_LIBDIR} PREFIX "clib-" OUTPUT_NAME "${LWIP_LIBNAME}" + PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${USER_LIBDIR} OUTPUT_NAME "${LWIP_LIBNAME}" ) target_compile_options(lwip PRIVATE ${LWIP_COMPILER_FLAGS} -m32 -Wno-strict-aliasing) diff --git a/Sming/Arch/Host/Components/lwip/Windows/host_lwip.c b/Sming/Components/lwip/src/Arch/Host/Windows/lwip_arch.cpp similarity index 50% rename from Sming/Arch/Host/Components/lwip/Windows/host_lwip.c rename to Sming/Components/lwip/src/Arch/Host/Windows/lwip_arch.cpp index 4c9751d1df..f38a8d43bb 100644 --- a/Sming/Arch/Host/Components/lwip/Windows/host_lwip.c +++ b/Sming/Components/lwip/src/Arch/Host/Windows/lwip_arch.cpp @@ -1,5 +1,5 @@ /** - * host_lwip.cpp + * lwip_arch.cpp * * Copyright 2019 mikee47 * @@ -12,44 +12,36 @@ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along with SHEM. + * You should have received a copy of the GNU General Public License along with this library. * If not, see . * ****/ -#include "../host_lwip.h" -#include "../../hostlib/hostmsg.h" +#define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS +#include "../lwip_arch.h" #include "lwipcfg.h" #include <../pcapif.h> #include "npcap.h" #include #include -#include -#include #include #include #include -struct net_config { - char ifname[128]; - unsigned ifindex; - ip4_addr_t ipaddr; - ip4_addr_t netmask; - ip4_addr_t gw; -}; - -static struct netif netif; +namespace +{ +struct netif net_if; /* * Find an IP4 address in a list of addresses */ -static bool find_ip4_addr(struct pcap_addr* pca, ip4_addr_t* addr, ip4_addr_t* mask) +bool find_ip4_addr(struct pcap_addr* pca, ip4_addr_t* addr, ip4_addr_t* mask) { #define IP4(saddr) ((ip4_addr_t*)&(((struct sockaddr_in*)saddr)->sin_addr)) - for(; pca != NULL; pca = pca->next) { - if(pca->addr == NULL || pca->addr->sa_family != AF_INET) { + for(; pca != nullptr; pca = pca->next) { + if(pca->addr == nullptr || pca->addr->sa_family != AF_INET) { continue; } addr->addr = ((struct sockaddr_in*)pca->addr)->sin_addr.s_addr; @@ -68,19 +60,8 @@ static bool find_ip4_addr(struct pcap_addr* pca, ip4_addr_t* addr, ip4_addr_t* m * ? list adapters * */ -static bool find_adapter(const struct lwip_param* param, struct net_config* netcfg) +bool find_adapter(struct lwip_net_config& netcfg) { - int ifindex = -1; - - if(param->ifname != NULL) { - // Check for valid numeric argument, interpreted as the adapter number - char* tail; - ifindex = strtol(param->ifname, &tail, 0); - if(*tail != '\0') { - ifindex = -1; // Not a valid number - } - } - pcap_if_t* alldevs; char errbuf[PCAP_ERRBUF_SIZE + 1]; if(pcap_findalldevs(&alldevs, errbuf) < 0) { @@ -88,16 +69,29 @@ static bool find_adapter(const struct lwip_param* param, struct net_config* netc return false; } - if(param->ifname != NULL && param->ifname[0] == '?') { + int ifindex = -1; + switch(netcfg.ifname[0]) { + case '?': printf("Available adapters:\n"); + break; + case '\0': + break; + default: + // Check for valid numeric argument, interpreted as the adapter number + char* tail; + ifindex = strtol(netcfg.ifname, &tail, 0); + if(*tail != '\0') { + ifindex = -1; // Not a valid number + } } - bool res = false; + bool res{false}; pcap_if_t* d = alldevs; - int idx = 0; - for(; d != NULL; d = d->next, idx++) { - if(param->ifname == NULL) { + int idx{0}; + for(; d != nullptr; d = d->next, idx++) { + switch(netcfg.ifname[0]) { + case '\0': { // @todo autodetect ip4_addr_t addr; ip4_addr_t mask; @@ -107,25 +101,28 @@ static bool find_adapter(const struct lwip_param* param, struct net_config* netc } // If an IP address was requested, use that in our search for an appropriate adapter - if(!ip4_addr_isany_val(netcfg->ipaddr) && !ip4_addr_netcmp(&netcfg->ipaddr, &addr, &mask)) { + if(!ip4_addr_isany_val(netcfg.ipaddr) && !ip4_addr_netcmp(&netcfg.ipaddr, &addr, &mask)) { // Skip, address doesn't comply continue; } - netcfg->ifindex = idx; - strncpy(netcfg->ifname, d->description, sizeof(netcfg->ifname)); - netcfg->ifname[sizeof(netcfg->ifname) - 1] = '\0'; - netcfg->netmask.addr = mask.addr; + netcfg.ifindex = idx; + strncpy(netcfg.ifname, d->description, sizeof(netcfg.ifname)); + netcfg.ifname[sizeof(netcfg.ifname) - 1] = '\0'; + netcfg.netmask.addr = mask.addr; res = true; break; } - } else if(param->ifname[0] == '?') { + break; + } + + case '?': { const char* guid_ptr = strchr(d->name, '{'); - if(guid_ptr == NULL) { + if(guid_ptr == nullptr) { guid_ptr = d->name; } printf("- %d: %s", idx, guid_ptr); - if(d->description != NULL) { + if(d->description != nullptr) { printf(" - %s", d->description); } printf("\n"); @@ -139,13 +136,20 @@ static bool find_adapter(const struct lwip_param* param, struct net_config* netc strcat(s, ip4addr_ntoa(&mask)); printf(" %s\n", s); } - } else if(idx == ifindex || (ifindex < 0 && strstr(d->name, param->ifname) != NULL)) { - netcfg->ifindex = idx; - strncpy(netcfg->ifname, d->description, sizeof(netcfg->ifname)); - netcfg->ifname[sizeof(netcfg->ifname) - 1] = '\0'; - if(ip4_addr_isany_val(netcfg->netmask)) { + break; + } + + default: + if(idx != ifindex && strstr(d->name, netcfg.ifname) == nullptr) { + // Interface match not found + break; + } + + netcfg.ifindex = idx; + strncpy(netcfg.ifname, d->description, sizeof(netcfg.ifname) - 1); + if(ip4_addr_isany_val(netcfg.netmask)) { ip4_addr_t addr; - find_ip4_addr(d->addresses, &addr, &netcfg->netmask); + find_ip4_addr(d->addresses, &addr, &netcfg.netmask); } res = true; break; @@ -154,74 +158,48 @@ static bool find_adapter(const struct lwip_param* param, struct net_config* netc pcap_freealldevs(alldevs); - if(param->ifname != NULL && param->ifname[0] == '?') { + if(netcfg.ifname[0] == '?') { + // Terminate application once interfaces have been listed exit(1); } return res; } -bool host_lwip_init(const struct lwip_param* param) -{ - host_debug_i("%s", "Initialising LWIP"); +} // namespace +struct netif* lwip_arch_init(struct lwip_net_config& netcfg) +{ if(!npcap_init()) { - return false; - } - - struct net_config netcfg = {0}; - - if(param->ipaddr != NULL && ip4addr_aton(param->ipaddr, &netcfg.ipaddr) != 1) { - host_debug_e("Failed to parse IP address '%s'", param->ipaddr); - return false; - } - - if(param->netmask != NULL && ip4addr_aton(param->netmask, &netcfg.netmask) != 1) { - host_debug_e("Failed to parse Network Mask '%s'", param->netmask); - return false; - } - - if(param->gateway != NULL && ip4addr_aton(param->gateway, &netcfg.gw) != 1) { - host_debug_e("Failed to parse Gateway address '%s'", param->gateway); - return false; + return nullptr; } - if(!find_adapter(param, &netcfg)) { - return false; + if(!find_adapter(netcfg)) { + return nullptr; } - char ip_str[IP4ADDR_STRLEN_MAX]; - ip4addr_ntoa_r(&netcfg.ipaddr, ip_str, sizeof(ip_str)); - char nm_str[IP4ADDR_STRLEN_MAX]; - ip4addr_ntoa_r(&netcfg.netmask, nm_str, sizeof(nm_str)); - char gw_str[IP4ADDR_STRLEN_MAX]; - ip4addr_ntoa_r(&netcfg.gw, gw_str, sizeof(gw_str)); - host_debug_i("gateway = %s, netmask = %s; using ip = %s", gw_str, nm_str, ip_str); - // Even though we're running as NO_SYS, stuff like crypt needs initialising sys_init(); lwip_init(); void* state = (void*)(netcfg.ifindex + 1); // See pcapif_low_level_init() - netif_add(&netif, &netcfg.ipaddr, &netcfg.netmask, &netcfg.gw, state, pcapif_init, ethernet_input); - netif_set_default(&netif); - - host_debug_i("MAC: %02x:%02x:%02x:%02x:%02x:%02x", netif.hwaddr[0], netif.hwaddr[1], netif.hwaddr[2], - netif.hwaddr[3], netif.hwaddr[4], netif.hwaddr[5]); + netif_add(&net_if, &netcfg.ipaddr, &netcfg.netmask, &netcfg.gw, state, pcapif_init, ethernet_input); - return true; + return &net_if; } -void host_lwip_service(void) +bool lwip_arch_service() { /* check for packets and link status*/ - pcapif_poll(&netif); - netif_poll(&netif); + pcapif_poll(&net_if); + netif_poll(&net_if); sys_check_timeouts(); + + return true; } -void host_lwip_shutdown(void) +void lwip_arch_shutdown() { /* release the pcap library... */ - pcapif_shutdown(&netif); + pcapif_shutdown(&net_if); } diff --git a/Sming/Arch/Host/Components/lwip/Windows/lwipcfg.h b/Sming/Components/lwip/src/Arch/Host/Windows/lwipcfg.h similarity index 100% rename from Sming/Arch/Host/Components/lwip/Windows/lwipcfg.h rename to Sming/Components/lwip/src/Arch/Host/Windows/lwipcfg.h diff --git a/Sming/Arch/Host/Components/lwip/Windows/npcap.c b/Sming/Components/lwip/src/Arch/Host/Windows/npcap.c similarity index 99% rename from Sming/Arch/Host/Components/lwip/Windows/npcap.c rename to Sming/Components/lwip/src/Arch/Host/Windows/npcap.c index fefbcf12b1..fab8b3389b 100644 --- a/Sming/Arch/Host/Components/lwip/Windows/npcap.c +++ b/Sming/Components/lwip/src/Arch/Host/Windows/npcap.c @@ -12,7 +12,7 @@ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along with SHEM. + * You should have received a copy of the GNU General Public License along with this library. * If not, see . * ****/ diff --git a/Sming/Arch/Host/Components/lwip/Windows/npcap.h b/Sming/Components/lwip/src/Arch/Host/Windows/npcap.h similarity index 89% rename from Sming/Arch/Host/Components/lwip/Windows/npcap.h rename to Sming/Components/lwip/src/Arch/Host/Windows/npcap.h index 0d6c3b6a74..bdc1be8852 100644 --- a/Sming/Arch/Host/Components/lwip/Windows/npcap.h +++ b/Sming/Components/lwip/src/Arch/Host/Windows/npcap.h @@ -12,7 +12,7 @@ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along with SHEM. + * You should have received a copy of the GNU General Public License along with this library. * If not, see . * ****/ @@ -21,9 +21,17 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + /* * Load NPCAP library (actually called wpdand bind required functions * * If */ bool npcap_init(void); + +#ifdef __cplusplus +} +#endif diff --git a/Sming/Arch/Host/Components/lwip/Windows/npcap.patch b/Sming/Components/lwip/src/Arch/Host/Windows/npcap.patch similarity index 100% rename from Sming/Arch/Host/Components/lwip/Windows/npcap.patch rename to Sming/Components/lwip/src/Arch/Host/Windows/npcap.patch diff --git a/Sming/Arch/Host/Components/lwip/Windows/ntddndis.h b/Sming/Components/lwip/src/Arch/Host/Windows/ntddndis.h similarity index 100% rename from Sming/Arch/Host/Components/lwip/Windows/ntddndis.h rename to Sming/Components/lwip/src/Arch/Host/Windows/ntddndis.h diff --git a/Sming/Components/lwip/src/Arch/Host/arch.mk b/Sming/Components/lwip/src/Arch/Host/arch.mk new file mode 100644 index 0000000000..5f0080a0a4 --- /dev/null +++ b/Sming/Components/lwip/src/Arch/Host/arch.mk @@ -0,0 +1,35 @@ +# +# Host lwip +# + +ifeq ($(UNAME),Windows) + + LWIP_ARCH_SRCDIR := $(LWIP_ARCH_SRCDIR)/Windows + NPCAP_SRCDIR := $(LWIP_ARCH_SRCDIR)/npcap + LWIP_CMAKE_OPTIONS += -DNPCAP_SRCDIR=$(NPCAP_SRCDIR) + COMPONENT_INCDIRS += \ + lwip/contrib/ports/win32/include \ + $(NPCAP_SRCDIR)/Include + COMPONENT_PREREQUISITES += $(NPCAP_SRCDIR)/.ok + PCAP_SRC := npcap-sdk-1.05.zip + +$(NPCAP_SRCDIR)/.ok: + @echo Fetching npcap... + $(Q) \ + rm -rf $(@D) && \ + mkdir -p $(@D) && \ + cd $(@D) && \ + powershell -Command "Set-Variable ProgressPreference SilentlyContinue; \ + Invoke-WebRequest https://nmap.org/npcap/dist/$(PCAP_SRC) -OutFile $(PCAP_SRC); \ + Expand-Archive $(PCAP_SRC) ." && \ + $(call ApplyPatch,$(LWIP_ARCH_SRCDIR)/npcap.patch) && \ + touch $@ + +else + + COMPONENT_INCDIRS += lwip/contrib/ports/unix/port/include + LWIP_ARCH_SRCDIR := $(LWIP_ARCH_SRCDIR)/Linux + +endif + +COMPONENT_SRCDIRS += $(LWIP_ARCH_SRCDIR) diff --git a/Sming/Components/lwip/src/Arch/Host/host_lwip.cpp b/Sming/Components/lwip/src/Arch/Host/host_lwip.cpp new file mode 100644 index 0000000000..b8c48e051a --- /dev/null +++ b/Sming/Components/lwip/src/Arch/Host/host_lwip.cpp @@ -0,0 +1,102 @@ +/** + * common.cpp + * + * Copyright 2022 mikee47 + * + * This file is part of the Sming Framework Project + * + * This library is free software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, version 3 or later. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this library. + * If not, see . + * + ****/ + +#include "lwip_arch.h" +#include "lwip/netif.h" +#include + +namespace +{ +SimpleTimer lwipServiceTimer; +host_lwip_init_callback_t init_callback; + +// Service stack more freqently when busy to ensure decent throughput +constexpr unsigned activeInterval{2}; +constexpr unsigned inactiveInterval{100}; + +} // namespace + +bool host_lwip_init(const struct lwip_param& param) +{ + host_debug_i("%s", "Initialising LWIP"); + + lwip_net_config config{}; + if(param.ifname != nullptr) { + strncpy(config.ifname, param.ifname, sizeof(config.ifname) - 1); + } + + if(param.netmask != nullptr && ip4addr_aton(param.netmask, &config.netmask) != 1) { + host_debug_e("Failed to parse Network Mask '%s'", param.netmask); + return false; + } + + if(param.gateway != nullptr && ip4addr_aton(param.gateway, &config.gw) != 1) { + host_debug_e("Failed to parse Gateway address '%s'", param.gateway); + return false; + } + + if(param.ipaddr != nullptr && ip4addr_aton(param.ipaddr, &config.ipaddr) != 1) { + host_debug_e("Failed to parse IP address '%s'", param.ipaddr); + return false; + } + + auto nif = lwip_arch_init(config); + if(nif == nullptr) { + return false; + } + netif_set_default(nif); + +#if DEBUG_VERBOSE_LEVEL >= INFO + char ip_str[IP4ADDR_STRLEN_MAX]; + ip4addr_ntoa_r(&config.ipaddr, ip_str, sizeof(ip_str)); + char nm_str[IP4ADDR_STRLEN_MAX]; + ip4addr_ntoa_r(&config.netmask, nm_str, sizeof(nm_str)); + char gw_str[IP4ADDR_STRLEN_MAX]; + ip4addr_ntoa_r(&config.gw, gw_str, sizeof(gw_str)); + host_debug_i("Using interface '%s', gateway %s, netmask %s, ip %s", config.ifname, gw_str, nm_str, ip_str); + + assert(nif != nullptr); + host_debug_i("MAC: %02x:%02x:%02x:%02x:%02x:%02x", nif->hwaddr[0], nif->hwaddr[1], nif->hwaddr[2], nif->hwaddr[3], + nif->hwaddr[4], nif->hwaddr[5]); +#endif + + if(init_callback != nullptr) { + init_callback(); + } + + lwipServiceTimer.initializeMs(activeInterval, []() { + bool active = lwip_arch_service(); + lwipServiceTimer.setIntervalMs(active ? activeInterval : inactiveInterval); + lwipServiceTimer.startOnce(); + }); + lwipServiceTimer.startOnce(); + + return true; +} + +void host_lwip_shutdown() +{ + lwipServiceTimer.stop(); + lwip_arch_shutdown(); +} + +void host_lwip_on_init_complete(host_lwip_init_callback_t callback) +{ + init_callback = callback; +} diff --git a/Sming/Arch/Host/Components/lwip/host_lwip.h b/Sming/Components/lwip/src/Arch/Host/include/host_lwip.h similarity index 74% rename from Sming/Arch/Host/Components/lwip/host_lwip.h rename to Sming/Components/lwip/src/Arch/Host/include/host_lwip.h index 94942fb181..6e3c48dcc9 100644 --- a/Sming/Arch/Host/Components/lwip/host_lwip.h +++ b/Sming/Components/lwip/src/Arch/Host/include/host_lwip.h @@ -12,19 +12,15 @@ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along with SHEM. + * You should have received a copy of the GNU General Public License along with this library. * If not, see . * ****/ #pragma once -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif +#include +#include struct lwip_param { const char* ifname; ///< Name of interface to use @@ -33,10 +29,14 @@ struct lwip_param { const char* netmask; ///< Network mask }; -bool host_lwip_init(const struct lwip_param* param); -void host_lwip_service(void); -void host_lwip_shutdown(void); +/* + * Called by startup code + */ +bool host_lwip_init(const struct lwip_param& param); +void host_lwip_shutdown(); -#ifdef __cplusplus -} -#endif +/* + * Called from Network library + */ +using host_lwip_init_callback_t = void (*)(); +void host_lwip_on_init_complete(host_lwip_init_callback_t callback); diff --git a/Sming/Components/lwip/src/Arch/Host/lwip_arch.h b/Sming/Components/lwip/src/Arch/Host/lwip_arch.h new file mode 100644 index 0000000000..b3a9ba06f4 --- /dev/null +++ b/Sming/Components/lwip/src/Arch/Host/lwip_arch.h @@ -0,0 +1,50 @@ +/** + * host_lwip.h - Sming Host LWIP network support + * + * Copyright 2019 mikee47 + * + * This file is part of the Sming Framework Project + * + * This library is free software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, version 3 or later. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this library. + * If not, see . + * + ****/ + +#pragma once + +#include "include/host_lwip.h" +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct lwip_net_config { + char ifname[128]; + unsigned ifindex; + ip4_addr_t ipaddr; + ip4_addr_t netmask; + ip4_addr_t gw; +}; + +struct netif* lwip_arch_init(struct lwip_net_config& config); +void lwip_arch_shutdown(); + +/* + * Poll the LWIP stack. + * Return true if data was processed, false otherwise. + */ +bool lwip_arch_service(); + +#ifdef __cplusplus +} +#endif diff --git a/Sming/Components/lwip/src/Arch/Rp2040/CMakeLists.txt b/Sming/Components/lwip/src/Arch/Rp2040/CMakeLists.txt new file mode 100644 index 0000000000..f8b25ad0fd --- /dev/null +++ b/Sming/Components/lwip/src/Arch/Rp2040/CMakeLists.txt @@ -0,0 +1,38 @@ +cmake_minimum_required(VERSION 3.12) + +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_BUILD_TYPE RelWithDebInfo) + +set(DCMAKE_C_COMPILER $ENV{CC}) +set(CMAKE_C_COMPILER_FORCED TRUE) + +project(lwip C) + +set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DLWIP_DEBUG") +include(${LWIP_DIR}/contrib/ports/CMakeCommon.cmake) + +set (LWIP_INCLUDE_DIRS + "${CMAKE_CURRENT_SOURCE_DIR}/include" + "${LWIP_DIR}/.." + "${LWIP_DIR}/src/include" + "${CMAKE_CURRENT_SOURCE_DIR}/" +) + +include(${LWIP_DIR}/src/Filelists.cmake) + +add_library(lwip + sys.c + ${LWIP_DIR}/src/api/err.c + ${lwipcore_SRCS} + ${lwipcore4_SRCS} + ${lwipcore6_SRCS} + ${lwipnetif_SRCS} +) + +set_target_properties(lwip + PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${USER_LIBDIR} OUTPUT_NAME "${LWIP_LIBNAME}" +) + +target_compile_definitions(lwip PRIVATE ${LWIP_DEFINITIONS} ${LWIP_MBEDTLS_DEFINITIONS}) +target_include_directories(lwip PRIVATE ${LWIP_INCLUDE_DIRS} ${LWIP_MBEDTLS_INCLUDE_DIRS}) diff --git a/Sming/Components/lwip/src/Arch/Rp2040/arch.mk b/Sming/Components/lwip/src/Arch/Rp2040/arch.mk new file mode 100644 index 0000000000..7ce92fc25e --- /dev/null +++ b/Sming/Components/lwip/src/Arch/Rp2040/arch.mk @@ -0,0 +1,3 @@ +# +# Rp2040 lwip +# diff --git a/Sming/Components/lwip/src/Arch/Rp2040/include/arch/cc.h b/Sming/Components/lwip/src/Arch/Rp2040/include/arch/cc.h new file mode 100644 index 0000000000..55b39cc36f --- /dev/null +++ b/Sming/Components/lwip/src/Arch/Rp2040/include/arch/cc.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __CC_H__ +#define __CC_H__ + +#include + +typedef int sys_prot_t; + +/* define compiler specific symbols */ +#if defined(__ICCARM__) + +#define PACK_STRUCT_BEGIN +#define PACK_STRUCT_STRUCT +#define PACK_STRUCT_END +#define PACK_STRUCT_FIELD(x) x +#define PACK_STRUCT_USE_INCLUDES + +#elif defined(__CC_ARM) + +#define PACK_STRUCT_BEGIN __packed +#define PACK_STRUCT_STRUCT +#define PACK_STRUCT_END +#define PACK_STRUCT_FIELD(x) x + +#elif defined(__GNUC__) + +#define PACK_STRUCT_BEGIN +#define PACK_STRUCT_STRUCT __attribute__((__packed__)) +#define PACK_STRUCT_END +#define PACK_STRUCT_FIELD(x) x + +#elif defined(__TASKING__) + +#define PACK_STRUCT_BEGIN +#define PACK_STRUCT_STRUCT +#define PACK_STRUCT_END +#define PACK_STRUCT_FIELD(x) x + +#endif + +#define LWIP_PLATFORM_ASSERT(x) \ + do { \ + if(!(x)) \ + while(1) \ + ; \ + } while(0) + +#ifdef __cplusplus +extern "C" { +#endif + +// Sming +uint32_t os_random(void); +#define LWIP_RAND() os_random() + +#ifdef __cplusplus +} +#endif + +#endif /* __CC_H__ */ diff --git a/Sming/Components/lwip/src/Arch/Rp2040/sys.c b/Sming/Components/lwip/src/Arch/Rp2040/sys.c new file mode 100644 index 0000000000..2b69358e9e --- /dev/null +++ b/Sming/Components/lwip/src/Arch/Rp2040/sys.c @@ -0,0 +1,19 @@ +#include + +/* lwip has provision for using a mutex, when applicable */ +sys_prot_t sys_arch_protect(void) +{ + return 0; +} + +void sys_arch_unprotect(sys_prot_t pval) +{ + (void)pval; +} + +/* lwip needs a millisecond time source */ +uint32_t sys_now(void) +{ + extern uint32_t millis(void); + return millis(); +} diff --git a/Sming/Components/rboot/include/host_rboot.h b/Sming/Components/rboot/include/host_rboot.h new file mode 100644 index 0000000000..48b44744d9 --- /dev/null +++ b/Sming/Components/rboot/include/host_rboot.h @@ -0,0 +1,13 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * host_rboot.h + * + ****/ + +#pragma once + +void host_init_bootloader(); diff --git a/Sming/Components/simpleRPC/include/simpleRPC/parser.h b/Sming/Components/simpleRPC/include/simpleRPC/parser.h index a1ce2e336e..d797cbc51f 100644 --- a/Sming/Components/simpleRPC/include/simpleRPC/parser.h +++ b/Sming/Components/simpleRPC/include/simpleRPC/parser.h @@ -39,6 +39,7 @@ enum class ParserState { type_end, start_methods, extract_method_start, + extract_method_signature, extract_method_name, extract_method, extract_method_end, @@ -52,12 +53,13 @@ struct ParserSettings { SimpleMethod startMethods; SimpleMethod startMethod; + CharMethod methodSignature; CharMethod methodName; SimpleMethod endMethod; SimpleMethod endMethods; ParserState state = ParserState::ready; }; -ParserResult parse(ParserSettings& settings, const char* buffer, size_t length); +ParserResult parse(ParserSettings& settings, const char* buffer, size_t length, char nameEndsWith = ':'); } // namespace simpleRPC diff --git a/Sming/Components/simpleRPC/simpleRPC b/Sming/Components/simpleRPC/simpleRPC index d76e9fa54e..609e739742 160000 --- a/Sming/Components/simpleRPC/simpleRPC +++ b/Sming/Components/simpleRPC/simpleRPC @@ -1 +1 @@ -Subproject commit d76e9fa54ef816519693322c832af8bb9f186fd7 +Subproject commit 609e7397428a973e83a97b2d5cf75c4321b8d26f diff --git a/Sming/Components/simpleRPC/simpleRPC.patch b/Sming/Components/simpleRPC/simpleRPC.patch index 5657d6fc78..f19e3c2aa3 100644 --- a/Sming/Components/simpleRPC/simpleRPC.patch +++ b/Sming/Components/simpleRPC/simpleRPC.patch @@ -1,8 +1,20 @@ +diff --git a/src/defs.h b/src/defs.h +index c5b9ccf..9b2367d 100644 +--- a/src/defs.h ++++ b/src/defs.h +@@ -1,6 +1,6 @@ + #pragma once + +-#include ++#include + + #define _PROTOCOL "simpleRPC" + #define _VERSION "\3\0\0" diff --git a/src/read.tcc b/src/read.tcc -index 2e5810f..513d691 100644 +index b32699e..3f03cde 100644 --- a/src/read.tcc +++ b/src/read.tcc -@@ -3,7 +3,6 @@ +@@ -2,7 +2,6 @@ #include "defs.h" #include "tuple.tcc" @@ -10,40 +22,11 @@ index 2e5810f..513d691 100644 //! \defgroup read -diff --git a/src/signature.tcc b/src/signature.tcc -index 00f5eb1..f3a675d 100644 ---- a/src/signature.tcc -+++ b/src/signature.tcc -@@ -25,7 +25,7 @@ void _parameterTypes(Stream& io, void (*f_)(H, Tail...)) { - * `rpcTypeOf()` to encode its type. The first parameter type `H` is removed - * from function pointer `*f_` in the recursive call. - */ -- H data; -+ H data{}; - - rpcPrint(io, ' '); - rpcTypeOf(io, data); -@@ -49,13 +49,13 @@ void _parameterTypes(Stream& io, void (*f_)(H&, Tail...)) { - */ - template - void signature(Stream& io, R (*f)(FArgs...)) { -- /* -+ /* - * A dummy function pointer is prepared, referred to as `f_` in the template - * functions above, which will be used to isolate parameter types. The return - * type of this function pointer is removed to avoid unneeded template - * expansion. - */ -- R data; -+ R data{}; - - rpcTypeOf(io, data); - rpcPrint(io, ':'); diff --git a/src/types.tcc b/src/types.tcc -index 651fb38..8a7cfa5 100644 +index b0de8d9..aca5f07 100644 --- a/src/types.tcc +++ b/src/types.tcc -@@ -3,7 +3,6 @@ +@@ -2,7 +2,6 @@ #include "print.tcc" #include "tuple.tcc" @@ -52,10 +35,10 @@ index 651fb38..8a7cfa5 100644 //! \defgroup types diff --git a/src/write.tcc b/src/write.tcc -index d51cdd1..abf1e7b 100644 +index 1f018c4..727f81f 100644 --- a/src/write.tcc +++ b/src/write.tcc -@@ -3,7 +3,6 @@ +@@ -2,7 +2,6 @@ #include "print.tcc" #include "tuple.tcc" @@ -63,16 +46,3 @@ index d51cdd1..abf1e7b 100644 //! \defgroup write -diff --git a/src/defs.h b/src/defs.h -index 8d2ec2a..93edaf5 100644 ---- a/src/defs.h -+++ b/src/defs.h -@@ -1,7 +1,7 @@ - #ifndef SIMPLE_RPC_DEFS_H_ - #define SIMPLE_RPC_DEFS_H_ - --#include -+#include - - #define _PROTOCOL "simpleRPC" - #define _VERSION "\3\0\0" diff --git a/Sming/Components/simpleRPC/src/parser.cpp b/Sming/Components/simpleRPC/src/parser.cpp index 7be4f8183c..adfce7d5a4 100644 --- a/Sming/Components/simpleRPC/src/parser.cpp +++ b/Sming/Components/simpleRPC/src/parser.cpp @@ -33,7 +33,7 @@ namespace simpleRPC state = NEW_STATE; \ } -ParserResult parse(ParserSettings& settings, const char* buffer, size_t length) +ParserResult parse(ParserSettings& settings, const char* buffer, size_t length, char nameEndsWith) { auto& state = settings.state; /* @@ -141,15 +141,25 @@ ParserResult parse(ParserSettings& settings, const char* buffer, size_t length) goto REENTER; } - SKIP_UNTIL(';', ParserState::extract_method_name); - if(settings.startMethod) { settings.startMethod(); } + state = ParserState::extract_method_signature; + /* fall-through */ + } + case ParserState::extract_method_signature: { + if(ch == ';') { + state = ParserState::extract_method_name; + break; + } + + if(settings.methodSignature) { + settings.methodSignature(ch); + } break; } case ParserState::extract_method_name: { - if(ch == ':') { + if(ch == nameEndsWith) { state = ParserState::extract_method_end; break; } diff --git a/Sming/Components/ssl/src/Session.cpp b/Sming/Components/ssl/src/Session.cpp index 6f0143a5de..aed3f1d1a4 100644 --- a/Sming/Components/ssl/src/Session.cpp +++ b/Sming/Components/ssl/src/Session.cpp @@ -13,6 +13,7 @@ #include #include #include +#include namespace Ssl { @@ -111,9 +112,9 @@ void Session::beginHandshake() debug_d("SSL: handshake start"); #ifndef SSL_SLOW_CONNECT curFreq = System.getCpuFrequency(); - if(curFreq != eCF_160MHz) { + if(curFreq != CpuCycleClockFast::cpuFrequency()) { debug_d("SSL: Switching to 160 MHz"); - System.setCpuFrequency(eCF_160MHz); // For shorter waiting time, more power consumption. + System.setCpuFrequency(CpuCycleClockFast::cpuFrequency()); // For shorter waiting time, more power consumption. } #endif } diff --git a/Sming/Core/Data/CStringArray.cpp b/Sming/Core/Data/CStringArray.cpp index 525fdddde2..8321fbeb01 100644 --- a/Sming/Core/Data/CStringArray.cpp +++ b/Sming/Core/Data/CStringArray.cpp @@ -81,6 +81,65 @@ const char* CStringArray::getValue(unsigned index) const return nullptr; } +bool CStringArray::pushFront(const char* str) +{ + if(str == nullptr) { + // Nothing to insert + return true; + } + + auto str_len = strlen(str) + 1; + auto len = length(); + if(!setLength(len + str_len)) { + return false; + } + char* ptr = String::begin(); + memmove(ptr + str_len, ptr, str_len); + memcpy(ptr, str, str_len); + if(stringCount != 0) { + ++stringCount; + } + return true; +} + +String CStringArray::popFront() +{ + if(length() == 0) { + return nullptr; + } + auto p = c_str(); + auto len = strlen(p); + String s(p, len); + remove(0, len + 1); + if(stringCount != 0) { + --stringCount; + } + return s; +} + +const char* CStringArray::back() const +{ + size_t len = length(); + if(len == 0) { + return nullptr; + } + return cbuffer() + lastIndexOf('\0', len - 2) + 1; +} + +String CStringArray::popBack() +{ + auto backPtr = back(); + if(backPtr == nullptr) { + return nullptr; + } + String s = backPtr; + setLength(backPtr - cbuffer()); + if(stringCount != 0) { + --stringCount; + } + return s; +} + // Called when a string array is constructed or assigned void CStringArray::init() { diff --git a/Sming/Core/Data/CStringArray.h b/Sming/Core/Data/CStringArray.h index 0234b3befd..5bcf331862 100644 --- a/Sming/Core/Data/CStringArray.h +++ b/Sming/Core/Data/CStringArray.h @@ -191,6 +191,48 @@ class CStringArray : private String return getValue(index); } + /** + * @brief Get first value in array, null if empty + */ + const char* front() const + { + return cbuffer(); + } + + /** + * @brief Insert item at start of array + * @param str Item to insert + * @retval bool false on memory error + */ + bool pushFront(const char* str); + + /** + * @brief Pop first item from array (at index 0) + * @retval String null if array is empty + */ + String popFront(); + + /** + * @brief Get last item in array, null if empty + */ + const char* back() const; + + /** + * @brief Add item to end of array + * @param str Item to add + * @retval bool false on memory error + */ + bool pushBack(const char* str) + { + return add(str); + } + + /** + * @brief Pop last item from array + * @retval String null if array is empty + */ + String popBack(); + /** @brief Empty the array */ void clear() @@ -215,13 +257,13 @@ class CStringArray : private String Iterator(const Iterator&) = default; Iterator(const CStringArray* array, uint16_t offset, uint16_t index) - : array_(array), offset_(offset), index_(index) + : mArray(array), mOffset(offset), mIndex(index) { } operator bool() const { - return array_ != nullptr && offset_ < array_->length(); + return mArray != nullptr && mOffset < mArray->length(); } bool equals(const char* rhs) const @@ -238,7 +280,7 @@ class CStringArray : private String bool operator==(const Iterator& rhs) const { - return array_ == rhs.array_ && offset_ == rhs.offset_; + return mArray == rhs.mArray && mOffset == rhs.mOffset; } bool operator!=(const Iterator& rhs) const @@ -278,11 +320,11 @@ class CStringArray : private String const char* str() const { - if(array_ == nullptr) { + if(mArray == nullptr) { return ""; } - return array_->c_str() + offset_; + return mArray->c_str() + mOffset; } const char* operator*() const @@ -292,12 +334,12 @@ class CStringArray : private String uint16_t index() const { - return index_; + return mIndex; } uint16_t offset() const { - return offset_; + return mOffset; } Iterator& operator++() @@ -316,17 +358,17 @@ class CStringArray : private String void next() { if(*this) { - offset_ += strlen(str()) + 1; - ++index_; + mOffset += strlen(str()) + 1; + ++mIndex; } } using const_iterator = Iterator; private: - const CStringArray* array_ = nullptr; - uint16_t offset_ = 0; - uint16_t index_ = 0; + const CStringArray* mArray = nullptr; + uint16_t mOffset = 0; + uint16_t mIndex = 0; }; Iterator begin() const diff --git a/Sming/Core/Data/Format/Json.cpp b/Sming/Core/Data/Format/Json.cpp index 01404fbaca..3cfaa73aaf 100644 --- a/Sming/Core/Data/Format/Json.cpp +++ b/Sming/Core/Data/Format/Json.cpp @@ -4,7 +4,7 @@ * http://github.com/SmingHub/Sming * All files of the Sming Core are provided under the LGPL v3 license. * - * JsonDirectoryTemplate.h + * Json.cpp * * @author mikee47 Nov 2020 * diff --git a/Sming/Core/Data/Range.h b/Sming/Core/Data/Range.h index 2a07c238b2..56fed9ee55 100644 --- a/Sming/Core/Data/Range.h +++ b/Sming/Core/Data/Range.h @@ -13,6 +13,8 @@ /** * @brief Manage a range of numbers between specified limits + * + * Values in the range meet the criteria (min <= value <= max) */ template struct TRange { T min{}; @@ -75,11 +77,25 @@ template struct TRange { { } + /** + * @brief Determine if range contains a value + */ bool contains(T value) { return (value >= min) && (value <= max); } + /** + * @brief Clip values to within the range + */ + T clip(T value) + { + return (value < min) ? min : (value > max) ? max : value; + } + + /** + * @brief Return a random value within the range + */ T random() const { auto value = os_random(); diff --git a/Sming/Core/Data/Stream/DataSourceStream.cpp b/Sming/Core/Data/Stream/DataSourceStream.cpp index 4a7e0e41bd..bbab048c30 100644 --- a/Sming/Core/Data/Stream/DataSourceStream.cpp +++ b/Sming/Core/Data/Stream/DataSourceStream.cpp @@ -45,7 +45,7 @@ String IDataSourceStream::readString(size_t maxLen) size_t remain = maxLen; while(remain != 0) { char buffer[256]; - size_t len = readBytes(buffer, remain); + size_t len = readBytes(buffer, std::min(sizeof(buffer), remain)); if(len == 0) { break; } diff --git a/Sming/Core/Data/Stream/FileStream.h b/Sming/Core/Data/Stream/FileStream.h index 1e03feeef3..013ebf7de0 100644 --- a/Sming/Core/Data/Stream/FileStream.h +++ b/Sming/Core/Data/Stream/FileStream.h @@ -33,10 +33,5 @@ class FileStream : public IFS::FileStream open(fileName, openFlags); } - FileStream(DirHandle dir, const String& name, FileOpenFlags openFlags = File::ReadOnly) : FileStream() - { - open(dir, name, openFlags); - } - using IFS::FileStream::attach; }; diff --git a/Sming/Core/Data/Stream/IFS/FileStream.cpp b/Sming/Core/Data/Stream/IFS/FileStream.cpp index 66eac3245e..a046ad3ef3 100644 --- a/Sming/Core/Data/Stream/IFS/FileStream.cpp +++ b/Sming/Core/Data/Stream/IFS/FileStream.cpp @@ -39,7 +39,7 @@ bool FileStream::open(const String& fileName, OpenFlags openFlags) FileHandle file = fs->open(fileName, openFlags); if(!check(file)) { - debug_w("File '%s' open error: %s", fileName.c_str(), fs->getErrorString(file).c_str()); + debug_d("File '%s' open error: %s", fileName.c_str(), fs->getErrorString(file).c_str()); return false; } diff --git a/Sming/Core/Data/Stream/IFS/FileStream.h b/Sming/Core/Data/Stream/IFS/FileStream.h index 567c24e118..faffccab92 100644 --- a/Sming/Core/Data/Stream/IFS/FileStream.h +++ b/Sming/Core/Data/Stream/IFS/FileStream.h @@ -43,15 +43,6 @@ class FileStream : public FsBase, public ReadWriteStream */ bool open(const String& fileName, IFS::OpenFlags openFlags = OpenFlag::Read); - /** @brief Open a file and attach this stream object to it - * @param dir Location of file - * @param fileName Name of file - * @param openFlags - * @retval bool true on success, false on error - * @note call getLastError() to determine cause of failure - */ - bool open(DirHandle dir, const String& name, OpenFlags openFlags = OpenFlag::Read); - /** @brief Close file */ void close(); diff --git a/Sming/Core/Data/Stream/LimitedMemoryStream.cpp b/Sming/Core/Data/Stream/LimitedMemoryStream.cpp index 4f598d2f92..89112e547f 100644 --- a/Sming/Core/Data/Stream/LimitedMemoryStream.cpp +++ b/Sming/Core/Data/Stream/LimitedMemoryStream.cpp @@ -82,7 +82,9 @@ bool LimitedMemoryStream::moveString(String& s) sizeOk = false; } - assert(s.setBuffer({buffer, capacity, size - 1})); + bool res = s.setBuffer({buffer, capacity, size - 1}); + (void)res; + assert(res); owned = false; buffer = nullptr; diff --git a/Sming/Core/Data/Stream/MemoryDataStream.cpp b/Sming/Core/Data/Stream/MemoryDataStream.cpp index 8d38750901..154cb5c748 100644 --- a/Sming/Core/Data/Stream/MemoryDataStream.cpp +++ b/Sming/Core/Data/Stream/MemoryDataStream.cpp @@ -103,7 +103,9 @@ bool MemoryDataStream::moveString(String& s) bool sizeOk = ensureCapacity(size + 1); // If we couldn't reallocate for the NUL terminator, drop the last character - assert(s.setBuffer({buffer, capacity, sizeOk ? size : size - 1})); + bool res = s.setBuffer({buffer, capacity, sizeOk ? size : size - 1}); + (void)res; + assert(res); buffer = nullptr; readPos = 0; diff --git a/Sming/Core/FileSystem.h b/Sming/Core/FileSystem.h index 8c968d5701..179d875837 100644 --- a/Sming/Core/FileSystem.h +++ b/Sming/Core/FileSystem.h @@ -119,6 +119,17 @@ bool fwfs_mount(); */ bool fwfs_mount(Storage::Partition partition); +/** + * @brief Mount a backup archive + * @param filename Path to archive file + * @retval IFS::FileSystem* Mounted filesystem. Caller must delete when finished. + */ +inline IFS::FileSystem* fileMountArchive(const String& filename) +{ + auto fs = getFileSystem(); + return fs ? IFS::mountArchive(*fs, filename) : nullptr; +} + /** @brief Open file by path * @param path Full path to file * @param flags Mode to open file @@ -548,4 +559,24 @@ inline int fileSetTime(FileHandle file, time_t mtime) return fileSystem->settime(file, mtime); } +/** @brief Create a directory + * @param path Path to directory + * @retval int Error code + */ +template int createDirectory(const T& path) +{ + CHECK_FS(mkdir); + return fileSystem->mkdir(path); +} + +/** @brief Create a directory and all required parent directories + * @param path Path to directory + * @retval int Error code + */ +template int createDirectories(const T& path) +{ + CHECK_FS(mkdir); + return fileSystem->makedirs(path); +} + /** @} */ diff --git a/Sming/Core/HardwareSerial.cpp b/Sming/Core/HardwareSerial.cpp index f50900652a..de7079eadd 100644 --- a/Sming/Core/HardwareSerial.cpp +++ b/Sming/Core/HardwareSerial.cpp @@ -28,7 +28,7 @@ HardwareSerial::~HardwareSerial() #endif } -void HardwareSerial::begin(uint32_t baud, SerialConfig config, SerialMode mode, uint8_t txPin, uint8_t rxPin) +void HardwareSerial::begin(uint32_t baud, SerialFormat format, SerialMode mode, uint8_t txPin, uint8_t rxPin) { end(); @@ -42,7 +42,7 @@ void HardwareSerial::begin(uint32_t baud, SerialConfig config, SerialMode mode, .mode = smg_uart_mode_t(mode), .options = options, .baudrate = baud, - .config = uint32_t(config), + .format = smg_uart_format_t(format), .rx_size = rxSize, .tx_size = txSize, }; diff --git a/Sming/Core/HardwareSerial.h b/Sming/Core/HardwareSerial.h index a76a5dc22e..ea996aa1a0 100644 --- a/Sming/Core/HardwareSerial.h +++ b/Sming/Core/HardwareSerial.h @@ -58,13 +58,13 @@ class CommandExecutor; XX(5E2) XX(6E2) XX(7E2) XX(8E2) XX(5O1) XX(6O1) XX(7O1) XX(8O1) XX(5O2) XX(6O2) XX(7O2) XX(8O2) // clang-format on -enum class SerialConfig { -#define XX(x) Cfg##x = UART_##x, +enum class SerialFormat { +#define XX(x) Fmt##x = UART_##x, SERIAL_CONFIG_MAP(XX) #undef XX }; -#define XX(x) static constexpr SerialConfig SERIAL_##x{SerialConfig::Cfg##x}; +#define XX(x) static constexpr SerialFormat SERIAL_##x{SerialFormat::Fmt##x}; SERIAL_CONFIG_MAP(XX) #undef XX @@ -140,39 +140,39 @@ class HardwareSerial : public ReadWriteStream /** * @brief Initialise and set its configuration. * @param baud Baud rate to use - * @param config can be 5, 6, 7, 8 data bits, odd (O), + * @param format can be 5, 6, 7, 8 data bits, odd (O), * even (E), and no (N) parity, and 1 or 2 stop bits. * To set the desired mode, call Serial.begin(baudrate, SERIAL_8N1), * Serial.begin(baudrate, SERIAL_6E2), etc. */ - void begin(uint32_t baud, SerialConfig config) + void begin(uint32_t baud, SerialFormat format) { - begin(baud, config, SERIAL_FULL, SERIAL_PIN_DEFAULT); + begin(baud, format, SERIAL_FULL, SERIAL_PIN_DEFAULT); } /** * @brief Initialise, set its configuration and mode. * @param baud Baud rate to use - * @param config can be 5, 6, 7, 8 data bits, odd (O), + * @param format can be 5, 6, 7, 8 data bits, odd (O), * even (E), and no (N) parity, and 1 or 2 stop bits. * To set the desired mode, call Serial.begin(baudrate, SERIAL_8N1), * Serial.begin(baudrate, SERIAL_6E2), etc. * @param mode specifies if the UART supports receiving (RX), transmitting (TX) or both (FULL) operations */ - void begin(uint32_t baud, SerialConfig config, SerialMode mode) + void begin(uint32_t baud, SerialFormat format, SerialMode mode) { - begin(baud, config, mode, 1); + begin(baud, format, mode, 1); } /** * @brief Initialise, set its configuration and mode. * @param baud Baud rate to use - * @param config + * @param format * @param mode * @param txPin Can specify alternate pin for TX * @param rxPin */ - void begin(uint32_t baud, SerialConfig config, SerialMode mode, uint8_t txPin, uint8_t rxPin = SERIAL_PIN_DEFAULT); + void begin(uint32_t baud, SerialFormat format, SerialMode mode, uint8_t txPin, uint8_t rxPin = SERIAL_PIN_DEFAULT); /** * @brief De-inits the current UART if it is already used diff --git a/Sming/Core/SPISoft.h b/Sming/Core/SPISoft.h deleted file mode 100644 index 2e7468d5b6..0000000000 --- a/Sming/Core/SPISoft.h +++ /dev/null @@ -1,45 +0,0 @@ -/* -Author: ADiea -Project: Sming for ESP8266 -License: MIT -Date: 15.07.2015 -Descr: Implement software SPI for HW configs other than hardware SPI pins(GPIO 12,13,14) -*/ -#pragma once - -#include "SPIBase.h" -#include "SPISettings.h" - -class SPISoft : public SPIBase -{ -public: - SPISoft(uint16_t miso, uint16_t mosi, uint16_t sck, uint8_t delay) - : mMISO(miso), mMOSI(mosi), mCLK(sck), m_delay(delay) - { - } - - bool begin() override; - - void end() override - { - } - - void transfer(uint8_t* buffer, size_t size) override; - - /** - * @brief Set microsecond delay for the SCK signal. Impacts SPI speed - */ - void setDelay(uint8_t dly) - { - m_delay = dly; - } - -protected: - void prepare(SPISettings& settings) override - { - } - -private: - uint16_t mMISO, mMOSI, mCLK; - uint8_t m_delay; -}; diff --git a/Sming/Core/SmingVersion.h b/Sming/Core/SmingVersion.h index 11a8c06c8b..ffbf7ba418 100644 --- a/Sming/Core/SmingVersion.h +++ b/Sming/Core/SmingVersion.h @@ -6,7 +6,7 @@ */ #define SMING_MAJOR_VERSION 4 -#define SMING_MINOR_VERSION 5 +#define SMING_MINOR_VERSION 6 #define SMING_PATCH_VERSION 0 #define SMING_PRE_RELEASE "" diff --git a/Sming/Libraries/.patches/Adafruit_BME280_Library/README.md b/Sming/Libraries/.patches/Adafruit_BME280_Library/README.md index 5ebaad0976..205198e819 100644 --- a/Sming/Libraries/.patches/Adafruit_BME280_Library/README.md +++ b/Sming/Libraries/.patches/Adafruit_BME280_Library/README.md @@ -1,6 +1,6 @@ # Adafruit BME280 Library -[![Build Status](https://github.com/adafruit/Adafruit_BME280_Library/workflows/Arduino%20Library%20CI/badge.svg)](https://github.com/adafruit/Adafruit_BME280_Library/actions)[![Documentation](https://github.com/adafruit/ci-arduino/blob/master/assets/doxygen_badge.svg)](http://adafruit.github.io/Adafruit_BME280_Library/html/index.html) +[![Build Status](https://github.com/adafruit/Adafruit_BME280_Library/workflows/Arduino%20Library%20CI/badge.svg)](https://github.com/adafruit/Adafruit_BME280_Library/actions) diff --git a/Sming/Libraries/.patches/Adafruit_GFX.patch b/Sming/Libraries/.patches/Adafruit_GFX.patch new file mode 100644 index 0000000000..04d95e8163 --- /dev/null +++ b/Sming/Libraries/.patches/Adafruit_GFX.patch @@ -0,0 +1,268 @@ +diff --git a/Adafruit_SPITFT.cpp b/Adafruit_SPITFT.cpp +index b78d5ce..d2d02b1 100644 +--- a/Adafruit_SPITFT.cpp ++++ b/Adafruit_SPITFT.cpp +@@ -35,6 +35,10 @@ + + #include "Adafruit_SPITFT.h" + ++#ifdef ARCH_RP2040 ++#include ++#endif ++ + #if defined(__AVR__) + #if defined(__AVR_XMEGA__) // only tested with __AVR_ATmega4809__ + #define AVR_WRITESPI(x) \ +@@ -234,23 +238,13 @@ Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, int8_t cs, int8_t dc, + need to call subclass' begin() function, which in turn calls + this library's initSPI() function to initialize pins. + */ +-#if defined(ESP8266) // See notes below +-Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, int8_t cs, int8_t dc, +- int8_t rst) +- : Adafruit_GFX(w, h), connection(TFT_HARD_SPI), _rst(rst), _cs(cs), +- _dc(dc) { +- hwspi._spi = &SPI; +-} +-#else // !ESP8266 + Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, int8_t cs, int8_t dc, + int8_t rst) + : Adafruit_SPITFT(w, h, &SPI, cs, dc, rst) { + // This just invokes the hardware SPI constructor below, + // passing the default SPI device (&SPI). + } +-#endif // end !ESP8266 + +-#if !defined(ESP8266) + // ESP8266 compiler freaks out at this constructor -- it can't disambiguate + // beteween the SPIClass pointer (argument #3) and a regular integer. + // Solution here it to just not offer this variant on the ESP8266. You can +@@ -278,7 +272,7 @@ Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, int8_t cs, int8_t dc, + GPIO manually. Do this BEFORE calling the display-specific + begin or init function. Unfortunate but unavoidable. + */ +-Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, SPIClass *spiClass, ++Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, SPIBase *spiClass, + int8_t cs, int8_t dc, int8_t rst) + : Adafruit_GFX(w, h), connection(TFT_HARD_SPI), _rst(rst), _cs(cs), + _dc(dc) { +@@ -341,7 +335,6 @@ Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, SPIClass *spiClass, + #endif // end !HAS_PORT_SET_CLR + #endif // end USE_FAST_PINIO + } +-#endif // end !ESP8266 + + /*! + @brief Adafruit_SPITFT constructor for parallel display connection. +@@ -1000,154 +993,11 @@ void Adafruit_SPITFT::writePixels(uint16_t *colors, uint32_t len, bool block, + + // avoid paramater-not-used complaints + (void)block; +- (void)bigEndian; +- +-#if defined(ESP32) +- if (connection == TFT_HARD_SPI) { +- if (!bigEndian) { +- hwspi._spi->writePixels(colors, len * 2); // Inbuilt endian-swap +- } else { +- hwspi._spi->writeBytes((uint8_t *)colors, len * 2); // Issue bytes direct +- } +- return; +- } +-#elif defined(ARDUINO_NRF52_ADAFRUIT) && \ +- defined(NRF52840_XXAA) // Adafruit nRF52 use SPIM3 DMA at 32Mhz +- if (!bigEndian) { +- swapBytes(colors, len); // convert little-to-big endian for display +- } +- hwspi._spi->transfer(colors, NULL, 2 * len); // NULL RX to avoid overwrite +- if (!bigEndian) { +- swapBytes(colors, len); // big-to-little endian to restore pixel buffer +- } +- +- return; +-#elif defined(ARDUINO_ARCH_RP2040) +- spi_inst_t *pi_spi = hwspi._spi == &SPI ? spi0 : spi1; + + if (!bigEndian) { +- // switch to 16-bit writes +- hw_write_masked(&spi_get_hw(pi_spi)->cr0, 15 << SPI_SSPCR0_DSS_LSB, +- SPI_SSPCR0_DSS_BITS); +- spi_write16_blocking(pi_spi, colors, len); +- // switch back to 8-bit +- hw_write_masked(&spi_get_hw(pi_spi)->cr0, 7 << SPI_SSPCR0_DSS_LSB, +- SPI_SSPCR0_DSS_BITS); +- } else { +- spi_write_blocking(pi_spi, (uint8_t *)colors, len * 2); +- } +- return; +-#elif defined(USE_SPI_DMA) && \ +- (defined(__SAMD51__) || defined(ARDUINO_SAMD_ZERO)) +- if ((connection == TFT_HARD_SPI) || (connection == TFT_PARALLEL)) { +- int maxSpan = maxFillLen / 2; // One scanline max +- uint8_t pixelBufIdx = 0; // Active pixel buffer number +-#if defined(__SAMD51__) +- if (connection == TFT_PARALLEL) { +- // Switch WR pin to PWM or CCL +- pinPeripheral(tft8._wr, wrPeripheral); +- } +-#endif // end __SAMD51__ +- if (!bigEndian) { // Normal little-endian situation... +- while (len) { +- int count = (len < maxSpan) ? len : maxSpan; +- +- // Because TFT and SAMD endianisms are different, must swap +- // bytes from the 'colors' array passed into a DMA working +- // buffer. This can take place while the prior DMA transfer +- // is in progress, hence the need for two pixelBufs. +- swapBytes(colors, count, pixelBuf[pixelBufIdx]); +- colors += count; +- +- // The transfers themselves are relatively small, so we don't +- // need a long descriptor list. We just alternate between the +- // first two, sharing pixelBufIdx for that purpose. +- descriptor[pixelBufIdx].SRCADDR.reg = +- (uint32_t)pixelBuf[pixelBufIdx] + count * 2; +- descriptor[pixelBufIdx].BTCTRL.bit.SRCINC = 1; +- descriptor[pixelBufIdx].BTCNT.reg = count * 2; +- descriptor[pixelBufIdx].DESCADDR.reg = 0; +- +- while (dma_busy) +- ; // Wait for prior line to finish +- +- // Move new descriptor into place... +- memcpy(dptr, &descriptor[pixelBufIdx], sizeof(DmacDescriptor)); +- dma_busy = true; +- dma.startJob(); // Trigger SPI DMA transfer +- if (connection == TFT_PARALLEL) +- dma.trigger(); +- pixelBufIdx = 1 - pixelBufIdx; // Swap DMA pixel buffers +- +- len -= count; +- } +- } else { // bigEndian == true +- // With big-endian pixel data, this can be handled as a single +- // DMA transfer using chained descriptors. Even full screen, this +- // needs only a relatively short descriptor list, each +- // transferring a max of 32,767 (not 32,768) pixels. The list +- // was allocated large enough to accommodate a full screen's +- // worth of data, so this won't run past the end of the list. +- int d, numDescriptors = (len + 32766) / 32767; +- for (d = 0; d < numDescriptors; d++) { +- int count = (len < 32767) ? len : 32767; +- descriptor[d].SRCADDR.reg = (uint32_t)colors + count * 2; +- descriptor[d].BTCTRL.bit.SRCINC = 1; +- descriptor[d].BTCNT.reg = count * 2; +- descriptor[d].DESCADDR.reg = (uint32_t)&descriptor[d + 1]; +- len -= count; +- colors += count; +- } +- descriptor[d - 1].DESCADDR.reg = 0; +- +- while (dma_busy) +- ; // Wait for prior transfer (if any) to finish +- +- // Move first descriptor into place and start transfer... +- memcpy(dptr, &descriptor[0], sizeof(DmacDescriptor)); +- dma_busy = true; +- dma.startJob(); // Trigger SPI DMA transfer +- if (connection == TFT_PARALLEL) +- dma.trigger(); +- } // end bigEndian +- +- lastFillColor = 0x0000; // pixelBuf has been sullied +- lastFillLen = 0; +- if (block) { +- while (dma_busy) +- ; // Wait for last line to complete +-#if defined(__SAMD51__) || defined(ARDUINO_SAMD_ZERO) +- if (connection == TFT_HARD_SPI) { +- // See SAMD51/21 note in writeColor() +- hwspi._spi->setDataMode(hwspi._mode); +- } else { +- pinPeripheral(tft8._wr, PIO_OUTPUT); // Switch WR back to GPIO +- } +-#endif // end __SAMD51__ || ARDUINO_SAMD_ZERO +- } +- return; +- } +-#endif // end USE_SPI_DMA +- +- // All other cases (bitbang SPI or non-DMA hard SPI or parallel), +- // use a loop with the normal 16-bit data write function: +- +- if (!bigEndian) { +- while (len--) { +- SPI_WRITE16(*colors++); +- } +- } else { +- // Well this is awkward. SPI_WRITE16() was designed for little-endian +- // hosts and big-endian displays as that's nearly always the typical +- // case. If the bigEndian flag was set, data is already in display's +- // order...so each pixel needs byte-swapping before being issued. +- // Rather than having a separate big-endian SPI_WRITE16 (adding more +- // bloat), it's preferred if calling function is smart and only uses +- // bigEndian where DMA is supported. But we gotta handle this... +- while (len--) { +- SPI_WRITE16(__builtin_bswap16(*colors++)); +- } ++ swapBytes(colors, len); + } ++ hwspi._spi->transfer(reinterpret_cast(colors), len * 2); + } + + /*! + +diff --git a/Adafruit_SPITFT.h b/Adafruit_SPITFT.h +index 7f5d80f..9725e13 100644 +--- a/Adafruit_SPITFT.h ++++ b/Adafruit_SPITFT.h +@@ -138,13 +138,11 @@ public: + Adafruit_SPITFT(uint16_t w, uint16_t h, int8_t cs, int8_t dc, + int8_t rst = -1); + +-#if !defined(ESP8266) // See notes in .cpp + // Hardware SPI constructor using an arbitrary SPI peripheral: expects + // width & height (rotation 0), SPIClass pointer, 2 signal pins (cs, dc) + // and optional reset pin. cs is required but can be -1 if unused. +- Adafruit_SPITFT(uint16_t w, uint16_t h, SPIClass *spiClass, int8_t cs, ++ Adafruit_SPITFT(uint16_t w, uint16_t h, SPIBase *spiClass, int8_t cs, + int8_t dc, int8_t rst = -1); +-#endif // end !ESP8266 + + // Parallel constructor: expects width & height (rotation 0), flag + // indicating whether 16-bit (true) or 8-bit (false) interface, 3 signal +@@ -403,7 +401,7 @@ protected: + union { + #endif + struct { // Values specific to HARDWARE SPI: +- SPIClass *_spi; ///< SPI class pointer ++ SPIBase *_spi; ///< SPI class pointer + #if defined(SPI_HAS_TRANSACTION) + SPISettings settings; ///< SPI transaction settings + #else + +diff --git a/glcdfont.c b/glcdfont.c +index 535da3a..e6bcafd 100644 +--- a/glcdfont.c ++++ b/glcdfont.c +@@ -13,7 +13,7 @@ + // PROGMEM is defefind for T4 to place data in specific memory section + #undef PROGMEM + #define PROGMEM +-#else ++#elif !defined(PROGMEM) + #define PROGMEM + #endif + +diff --git a/README.md b/README.md +index 6f36460..50b2fe0 100644 +--- a/README.md ++++ b/README.md +@@ -1,4 +1,6 @@ +-# Adafruit GFX Library ![Build Status](https://github.com/adafruit/Adafruit-GFX-Library/workflows/Arduino%20Library%20CI/badge.svg) ++# Adafruit GFX Library ++ ++![Build Status](https://github.com/adafruit/Adafruit-GFX-Library/workflows/Arduino%20Library%20CI/badge.svg) + + This is the core graphics library for all our displays, providing a common set of graphics primitives (points, lines, circles, etc.). It needs to be paired with a hardware-specific library for each display device we carry (to handle the lower-level functions). + diff --git a/Sming/Libraries/Adafruit_GFX/BMPDraw.h b/Sming/Libraries/.patches/Adafruit_GFX/BMPDraw.h similarity index 77% rename from Sming/Libraries/Adafruit_GFX/BMPDraw.h rename to Sming/Libraries/.patches/Adafruit_GFX/BMPDraw.h index 4ceb3e0401..8d65f642a8 100644 --- a/Sming/Libraries/Adafruit_GFX/BMPDraw.h +++ b/Sming/Libraries/.patches/Adafruit_GFX/BMPDraw.h @@ -45,15 +45,15 @@ as well as Adafruit raw 1.8" TFT display * * unsigned width() * unsigned height() + * startWrite() + * endWrite() * setAddrWindow(x1, y1, x2, y2) - * pushColor(uint16_t rgb565) + * writePixels(uint16_t rgb565) * * Return types and parameters don't need to be exact. * Note that this would probably be more efficient using a virtual base class... */ -#define BUFFPIXEL 20 - template bool bmpDraw(Adafruit_TFT& tft, String fileName, uint8_t x, uint8_t y) { if((x >= tft.width()) || (y >= tft.height())) { @@ -64,8 +64,8 @@ template bool bmpDraw(Adafruit_TFT& tft, String fileName, u uint32_t startTime = millis(); - file_t handle = fileOpen(fileName.c_str(), File::ReadOnly); - if(handle < 0) { + File file; + if(!file.open(fileName)) { debug_e("File wasn't found: %s", fileName.c_str()); return false; } @@ -74,23 +74,18 @@ template bool bmpDraw(Adafruit_TFT& tft, String fileName, u // BMP data is stored little-endian, esp8266 is little-endian too. // May need to reverse subscript order if porting elsewhere. - auto read16 = [handle]() -> uint16_t { + auto read16 = [&file]() -> uint16_t { char bytes[2]; - fileRead(handle, bytes, 2); + file.read(bytes, 2); return (bytes[1] << 8) + bytes[0]; }; - auto read32 = [handle]() -> uint32_t { + auto read32 = [&file]() -> uint32_t { char bytes[4]; - fileRead(handle, bytes, 4); + file.read(bytes, 4); return (bytes[3] << 24) + (bytes[2] << 16) + (bytes[1] << 8) + bytes[0]; }; - // Convert rgb values into RGB565 format - auto color565 = [](uint8_t r, uint8_t g, uint8_t b) -> uint16_t { - return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3); - }; - // Parse BMP header bool goodBmp = false; // Set to true on valid header parse while(true) { @@ -145,11 +140,44 @@ template bool bmpDraw(Adafruit_TFT& tft, String fileName, u } // Set TFT address window to clipped image bounds - tft.setAddrWindow(x, y, x + w - 1, y + h - 1); + tft.startWrite(); + tft.setAddrWindow(x, y, w, h); + + constexpr size_t BUFFPIXEL{20}; + struct Buffer { + union { + uint8_t rgb[BUFFPIXEL][3]; // pixel buffer (R+G+B per pixel) + uint16_t colors[BUFFPIXEL]; // Resulting colours + }; + uint8_t index{0}; + + // Convert rgb values into RGB565 format + static uint16_t color565(uint8_t r, uint8_t g, uint8_t b) + { + return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3); + } + + bool convertPixel() + { + uint16_t color = color565(rgb[index][2], rgb[index][1], rgb[index][0]); + colors[index] = __builtin_bswap16(color); + ++index; + return index == BUFFPIXEL; + } + }; + Buffer buf; + bool reload{true}; + + auto flushPixels = [&]() { + if(buf.index == 0) { + return; + } + tft.writePixels(buf.colors, buf.index, true, true); + buf.index = 0; + }; - uint8_t sdbuffer[3 * BUFFPIXEL]; // pixel buffer (R+G+B per pixel) - uint8_t buffidx = sizeof(sdbuffer); // Current position in sdbuffer - for(int row = 0; row < h; row++) { // For each scanline... + uint32_t filePos = file.tell(); + for(int row = 0; row < h; row++) { // For each scanline... /* * Seek to start of scan line. It might seem inefficient to be doing this on * every line, but this method covers a lot of gritty details like cropping @@ -164,29 +192,27 @@ template bool bmpDraw(Adafruit_TFT& tft, String fileName, u // Bitmap is stored top-to-bottom pos = bmpImageoffset + row * rowSize; } - if(fileTell(handle) != int(pos)) { - fileSeek(handle, pos, SeekOrigin::Start); - buffidx = sizeof(sdbuffer); // Force buffer reload + if(filePos != pos) { + filePos = file.seek(pos, SeekOrigin::Start); + reload = true; } - for(int col = 0; col < w; col++) { // For each pixel... + for(int col = 0; col < w; ++col) { // Time to read more pixel data? - if(buffidx >= sizeof(sdbuffer)) { // Indeed - fileRead(handle, sdbuffer, sizeof(sdbuffer)); - buffidx = 0; // Set index to beginning + if(reload) { + flushPixels(); + filePos += file.read(buf.rgb, sizeof(buf.rgb)); + reload = false; } + reload = buf.convertPixel(); + } + } + flushPixels(); + tft.endWrite(); - // Convert pixel from BMP to TFT format, push to display - uint8_t b = sdbuffer[buffidx++]; - uint8_t g = sdbuffer[buffidx++]; - uint8_t r = sdbuffer[buffidx++]; - tft.pushColor(color565(r, g, b)); - } // end pixel - } // end scanline debug_i("Loaded in %d ms", millis() - startTime); break; } - fileClose(handle); if(!goodBmp) { debug_e("BMP format not recognized."); } diff --git a/Sming/Libraries/.patches/Adafruit_GFX/component.mk b/Sming/Libraries/.patches/Adafruit_GFX/component.mk new file mode 100644 index 0000000000..1e8018bfc8 --- /dev/null +++ b/Sming/Libraries/.patches/Adafruit_GFX/component.mk @@ -0,0 +1,2 @@ +COMPONENT_DEPENDS := Adafruit_BusIO +COMPONENT_INCDIRS := . diff --git a/Sming/Libraries/.patches/Adafruit_ILI9341.patch b/Sming/Libraries/.patches/Adafruit_ILI9341.patch new file mode 100644 index 0000000000..aa9338743d --- /dev/null +++ b/Sming/Libraries/.patches/Adafruit_ILI9341.patch @@ -0,0 +1,49 @@ +diff --git a/Adafruit_ILI9341.cpp b/Adafruit_ILI9341.cpp +old mode 100755 +new mode 100644 +index c962765..91aedbc +--- a/Adafruit_ILI9341.cpp ++++ b/Adafruit_ILI9341.cpp +@@ -121,7 +121,7 @@ Adafruit_ILI9341::Adafruit_ILI9341(int8_t cs, int8_t dc, int8_t rst) + @param rst Reset pin # (optional, pass -1 if unused). + */ + /**************************************************************************/ +-Adafruit_ILI9341::Adafruit_ILI9341(SPIClass *spiClass, int8_t dc, int8_t cs, ++Adafruit_ILI9341::Adafruit_ILI9341(SPIBase *spiClass, int8_t dc, int8_t cs, + int8_t rst) + : Adafruit_SPITFT(ILI9341_TFTWIDTH, ILI9341_TFTHEIGHT, spiClass, cs, dc, + rst) {} + +diff --git a/Adafruit_ILI9341.h b/Adafruit_ILI9341.h +old mode 100755 +new mode 100644 +index 2d64ec7..573331b +--- a/Adafruit_ILI9341.h ++++ b/Adafruit_ILI9341.h +@@ -134,11 +134,12 @@ work with ILI9340) + + class Adafruit_ILI9341 : public Adafruit_SPITFT { + public: ++ Adafruit_ILI9341(): Adafruit_ILI9341(TFT_CS_PIN, TFT_DC_PIN, TFT_RESET_PIN) { } + Adafruit_ILI9341(int8_t _CS, int8_t _DC, int8_t _MOSI, int8_t _SCLK, + int8_t _RST = -1, int8_t _MISO = -1); + Adafruit_ILI9341(int8_t _CS, int8_t _DC, int8_t _RST = -1); + #if !defined(ESP8266) +- Adafruit_ILI9341(SPIClass *spiClass, int8_t dc, int8_t cs = -1, ++ Adafruit_ILI9341(SPIBase *spiClass, int8_t dc, int8_t cs = -1, + int8_t rst = -1); + #endif // end !ESP8266 + Adafruit_ILI9341(tftBusWidth busWidth, int8_t d0, int8_t wr, int8_t dc, + +diff --git a/README.md b/README.md +index 2f62bcd..740a120 100644 +--- a/README.md ++++ b/README.md +@@ -1,4 +1,6 @@ +-# Adafruit ILI9341 Arduino Library [![Build Status](https://github.com/adafruit/Adafruit_ILI9341/workflows/Arduino%20Library%20CI/badge.svg)](https://github.com/adafruit/Adafruit_ILI9341/actions)[![Documentation](https://github.com/adafruit/ci-arduino/blob/master/assets/doxygen_badge.svg)](http://adafruit.github.io/Adafruit_ILI9341/html/index.html) ++# Adafruit ILI9341 Arduino Library ++ ++[![Build Status](https://github.com/adafruit/Adafruit_ILI9341/workflows/Arduino%20Library%20CI/badge.svg)](https://github.com/adafruit/Adafruit_ILI9341/actions) + + This is a library for the Adafruit ILI9341 display products + diff --git a/Sming/Libraries/.patches/Adafruit_ILI9341/component.mk b/Sming/Libraries/.patches/Adafruit_ILI9341/component.mk new file mode 100644 index 0000000000..f2af12da7a --- /dev/null +++ b/Sming/Libraries/.patches/Adafruit_ILI9341/component.mk @@ -0,0 +1,20 @@ +COMPONENT_DEPENDS := Adafruit_GFX + +CONFIG_VARS += TFT_CS_PIN TFT_DC_PIN TFT_RESET_PIN + +ifeq ($(SMING_ARCH),Esp32) +TFT_CS_PIN ?= 18 +TFT_DC_PIN ?= 19 +TFT_RESET_PIN ?= 21 +else +TFT_CS_PIN ?= 15 +TFT_DC_PIN ?= 5 +TFT_RESET_PIN ?= 4 +endif + +GLOBAL_CFLAGS += -DTFT_CS_PIN=$(TFT_CS_PIN) -DTFT_DC_PIN=$(TFT_DC_PIN) + +# Reset pin is optional +ifdef TFT_RESET_PIN +GLOBAL_CFLAGS += -DTFT_RESET_PIN=$(TFT_RESET_PIN) +endif diff --git a/Sming/Libraries/.patches/Adafruit_NeoPixel.patch b/Sming/Libraries/.patches/Adafruit_NeoPixel.patch new file mode 100644 index 0000000000..f97f89ce02 --- /dev/null +++ b/Sming/Libraries/.patches/Adafruit_NeoPixel.patch @@ -0,0 +1,107 @@ +diff --git a/esp8266.c b/esp8266.cpp +similarity index 100% +rename from esp8266.c +rename to esp8266.cpp + +diff --git a/esp.c b/esp.cpp +similarity index 96% +rename from esp.c +rename to esp.cpp +index c480a20..8077839 100644 +--- a/esp.c ++++ b/esp.cpp +@@ -94,7 +94,7 @@ void espShow(uint8_t pin, uint8_t *pixels, uint32_t numBytes, boolean is800KHz) + for (size_t i = 0; i < ADAFRUIT_RMT_CHANNEL_MAX; i++) { + if (!rmt_reserved_channels[i]) { + rmt_reserved_channels[i] = true; +- channel = i; ++ channel = rmt_channel_t(i); + break; + } + } +@@ -104,14 +104,14 @@ void espShow(uint8_t pin, uint8_t *pixels, uint32_t numBytes, boolean is800KHz) + } + + #if defined(HAS_ESP_IDF_4) +- rmt_config_t config = RMT_DEFAULT_CONFIG_TX(pin, channel); ++ rmt_config_t config = RMT_DEFAULT_CONFIG_TX(gpio_num_t(pin), channel); + config.clk_div = 2; + #else + // Match default TX config from ESP-IDF version 3.4 + rmt_config_t config = { + .rmt_mode = RMT_MODE_TX, + .channel = channel, +- .gpio_num = pin, ++ .gpio_num = gpio_num_t(pin), + .clk_div = 2, + .mem_block_num = 1, + .tx_config = { +@@ -172,7 +172,7 @@ void espShow(uint8_t pin, uint8_t *pixels, uint32_t numBytes, boolean is800KHz) + rmt_driver_uninstall(config.channel); + rmt_reserved_channels[channel] = false; + +- gpio_set_direction(pin, GPIO_MODE_OUTPUT); ++ gpio_set_direction(gpio_num_t(pin), GPIO_MODE_OUTPUT); + } + + #endif + +diff --git a/Adafruit_NeoPixel.cpp b/Adafruit_NeoPixel.cpp +index 44d9ca3..14870ec 100644 +--- a/Adafruit_NeoPixel.cpp ++++ b/Adafruit_NeoPixel.cpp +@@ -227,14 +227,8 @@ void Adafruit_NeoPixel::rp2040Show(uint8_t pin, uint8_t *pixels, uint32_t numBy + + #endif + +-#if defined(ESP8266) +-// ESP8266 show() is external to enforce ICACHE_RAM_ATTR execution +-extern "C" IRAM_ATTR void espShow(uint16_t pin, uint8_t *pixels, +- uint32_t numBytes, uint8_t type); +-#elif defined(ESP32) +-extern "C" void espShow(uint16_t pin, uint8_t *pixels, uint32_t numBytes, +- uint8_t type); +-#endif // ESP8266 ++extern void espShow(uint8_t pin, uint8_t *pixels, uint32_t numBytes, ++ boolean type); + + #if defined(K210) + #define KENDRYTE_K210 1 + +diff --git a/README.md b/README.md +index eff1337..ad50db0 100644 +--- a/README.md ++++ b/README.md +@@ -1,4 +1,6 @@ +-# Adafruit NeoPixel Library [![Build Status](https://github.com/adafruit/Adafruit_NeoPixel/workflows/Arduino%20Library%20CI/badge.svg)](https://github.com/adafruit/Adafruit_NeoPixel/actions)[![Documentation](https://github.com/adafruit/ci-arduino/blob/master/assets/doxygen_badge.svg)](http://adafruit.github.io/Adafruit_NeoPixel/html/index.html) ++# Adafruit NeoPixel Library ++ ++[![Build Status](https://github.com/adafruit/Adafruit_NeoPixel/workflows/Arduino%20Library%20CI/badge.svg)](https://github.com/adafruit/Adafruit_NeoPixel/actions) + + Arduino library for controlling single-wire-based LED pixels and strip such as the [Adafruit 60 LED/meter Digital LED strip][strip], the [Adafruit FLORA RGB Smart Pixel][flora], the [Adafruit Breadboard-friendly RGB Smart Pixel][pixel], the [Adafruit NeoPixel Stick][stick], and the [Adafruit NeoPixel Shield][shield]. + +@@ -14,24 +16,6 @@ Compatibility notes: Port A is not supported on any AVR processors at this time + + --- + +-## Installation +- +-### First Method +- +-![image](https://user-images.githubusercontent.com/36513474/68967967-3e37f480-0803-11ea-91d9-601848c306ee.png) +- +-1. In the Arduino IDE, navigate to Sketch > Include Library > Manage Libraries +-1. Then the Library Manager will open and you will find a list of libraries that are already installed or ready for installation. +-1. Then search for Neopixel strip using the search bar. +-1. Click on the text area and then select the specific version and install it. +- +-### Second Method +- +-1. Navigate to the [Releases page](https://github.com/adafruit/Adafruit_NeoPixel/releases). +-1. Download the latest release. +-1. Extract the zip file +-1. In the Arduino IDE, navigate to Sketch > Include Library > Add .ZIP Library +- + ## Features + + - ### Simple to use diff --git a/Sming/Libraries/.patches/Adafruit_NeoPixel/component.mk b/Sming/Libraries/.patches/Adafruit_NeoPixel/component.mk new file mode 100644 index 0000000000..f534f71c7a --- /dev/null +++ b/Sming/Libraries/.patches/Adafruit_NeoPixel/component.mk @@ -0,0 +1 @@ +COMPONENT_SOC := $(filter-out host,$(AVAILABLE_SOCS)) diff --git a/Sming/Libraries/.patches/Adafruit_PCD8544.patch b/Sming/Libraries/.patches/Adafruit_PCD8544.patch new file mode 100644 index 0000000000..ebfadc435e --- /dev/null +++ b/Sming/Libraries/.patches/Adafruit_PCD8544.patch @@ -0,0 +1,12 @@ +diff --git a/README.md b/README.md +index 85d6290..cb535ec 100644 +--- a/README.md ++++ b/README.md +@@ -1,4 +1,6 @@ +-# Adafruit PCD8544 Nokia 5110 LCD Library [![Build Status](https://github.com/adafruit/Adafruit-PCD8544-Nokia-5110-LCD-library/workflows/Arduino%20Library%20CI/badge.svg)](https://github.com/adafruit/Adafruit-PCD8544-Nokia-5110-LCD-library/actions)[![Documentation](https://github.com/adafruit/ci-arduino/blob/master/assets/doxygen_badge.svg)](http://adafruit.github.io/Adafruit-PCD8544-Nokia-5110-LCD-library/html/index.html) ++# Adafruit PCD8544 Nokia 5110 LCD Library ++ ++[![Build Status](https://github.com/adafruit/Adafruit-PCD8544-Nokia-5110-LCD-library/workflows/Arduino%20Library%20CI/badge.svg)](https://github.com/adafruit/Adafruit-PCD8544-Nokia-5110-LCD-library/actions) + + This is a library for our Monochrome Nokia 5110 LCD Displays + diff --git a/Sming/Libraries/.patches/Adafruit_PCD8544/component.mk b/Sming/Libraries/.patches/Adafruit_PCD8544/component.mk new file mode 100644 index 0000000000..c8075d5ebb --- /dev/null +++ b/Sming/Libraries/.patches/Adafruit_PCD8544/component.mk @@ -0,0 +1,2 @@ +COMPONENT_DEPENDS := Adafruit_GFX +COMPONENT_SOC := $(filter-out host,$(AVAILABLE_SOCS)) diff --git a/Sming/Libraries/.patches/Adafruit_SSD1306.patch b/Sming/Libraries/.patches/Adafruit_SSD1306.patch index c3077b4efa..fc7da6d9a7 100644 --- a/Sming/Libraries/.patches/Adafruit_SSD1306.patch +++ b/Sming/Libraries/.patches/Adafruit_SSD1306.patch @@ -1,291 +1,12 @@ -diff --git a/Adafruit_SSD1306.cpp b/Adafruit_SSD1306.cpp -index 570a335..750b750 100644 ---- a/Adafruit_SSD1306.cpp -+++ b/Adafruit_SSD1306.cpp -@@ -32,12 +32,38 @@ All text above, and the splash screen below must be included in any redistributi - - #include - #include --#include "Adafruit_GFX.h" - #include "Adafruit_SSD1306.h" - - // the memory buffer for the LCD - - static uint8_t buffer[SSD1306_LCDHEIGHT * SSD1306_LCDWIDTH / 8] = { -+ -+#if (SSD1306_LCDWIDTH == 64 && SSD1306_LCDHEIGHT == 48) -+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, -+0xE0, 0xF0, 0xF8, 0xFC, 0xFC, 0xFE, 0xFF, 0xFC, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, -+0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF0, 0xF0, 0xE0, 0xE0, 0xC0, 0x80, 0xC0, 0xFC, 0xFF, 0xFF, -+0xFF, 0xFF, 0x7F, 0x3F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF, -+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xC7, 0xC7, 0x87, 0x8F, 0x9F, 0x9F, 0xFF, 0xFF, -+0xFF, 0xC1, 0xC0, 0xE0, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFC, 0xFC, 0xFC, 0xFE, 0xFE, -+0xFE, 0xFC, 0xFC, 0xF8, 0xF8, 0xF0, 0xE0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, -+0xE0, 0xF1, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x1F, 0x0F, 0x0F, 0x87, 0xE7, 0xFF, 0xFF, -+0xFF, 0x1F, 0x1F, 0x3F, 0xF9, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, -+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x0F, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFE, 0xFF, 0xFF, -+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x7E, 0x3F, 0x3F, 0x0F, 0x1F, 0xFF, 0xFF, -+0xFF, 0xFC, 0xF0, 0xE0, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xF0, 0x01, 0x01, 0x01, 0x01, -+0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, -+0x03, 0x03, 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, -+0x0F, 0x1F, 0x3F, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x1F, 0x03, 0x00, 0x00, 0x00, -+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -+#else - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -@@ -71,7 +97,7 @@ static uint8_t buffer[SSD1306_LCDHEIGHT * SSD1306_LCDWIDTH / 8] = { - 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x03, 0x01, 0x00, 0x00, 0x00, 0x03, - 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, --#if (SSD1306_LCDHEIGHT == 64) -+#if (SSD1306_LCDWIDTH == 128 && SSD1306_LCDHEIGHT == 64) - 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x1F, 0x0F, - 0x87, 0xC7, 0xF7, 0xFF, 0xFF, 0x1F, 0x1F, 0x3D, 0xFC, 0xF8, 0xF8, 0xF8, 0xF8, 0x7C, 0x7D, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x0F, 0x07, 0x00, 0x30, 0x30, 0x00, 0x00, -@@ -106,6 +132,7 @@ static uint8_t buffer[SSD1306_LCDHEIGHT * SSD1306_LCDWIDTH / 8] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - #endif - #endif -+#endif - }; - - #define ssd1306_swap(a, b) { int16_t t = a; a = b; b = t; } -@@ -252,7 +279,7 @@ void Adafruit_SSD1306::begin(uint8_t vccstate, uint8_t i2caddr, bool reset) { - ssd1306_command(SSD1306_SETCONTRAST); // 0x81 - ssd1306_command(0x8F); - --#elif defined SSD1306_128_64 -+#elif defined SSD1306_128_64 || defined SH1106_128_64 - ssd1306_command(SSD1306_SETCOMPINS); // 0xDA - ssd1306_command(0x12); - ssd1306_command(SSD1306_SETCONTRAST); // 0x81 -@@ -270,6 +297,15 @@ void Adafruit_SSD1306::begin(uint8_t vccstate, uint8_t i2caddr, bool reset) { - else - { ssd1306_command(0xAF); } - -+#elif defined SSD1306_64_48 -+ ssd1306_command(SSD1306_SETCOMPINS); // 0xDA -+ ssd1306_command(0x12); -+ ssd1306_command(SSD1306_SETCONTRAST); // 0x81 -+ if (vccstate == SSD1306_EXTERNALVCC) -+ { ssd1306_command(0x9F); } -+ else -+ { ssd1306_command(0xCF); } -+ - #endif - - ssd1306_command(SSD1306_SETPRECHARGE); // 0xd9 -@@ -417,21 +453,52 @@ void Adafruit_SSD1306::dim(boolean dim) { - } - - void Adafruit_SSD1306::display(void) { -+#if defined SH1106_128_64 -+ for (int index = 0; index < 8; index++) { -+ ssd1306_command(SH1106_SETSTARTPAGE + index); -+ /* for some reason display is shifted by 2 columns -+ * on 1.3" displays from ebay -+ */ -+ ssd1306_command(SSD1306_SETLOWCOLUMN + 2); // low column start address -+ ssd1306_command(SSD1306_SETHIGHCOLUMN); // high column start address -+ -+ for (int pixel = 0; pixel < SSD1306_LCDWIDTH; pixel++) { -+ Wire.beginTransmission(_i2caddr); -+ WIRE_WRITE(0x40); -+ // input buffer doesn't accept all bytes at once -+ for (uint8_t x=0; x<16; x++) { -+ WIRE_WRITE(buffer[index * SSD1306_LCDWIDTH + pixel]); -+ ++pixel; -+ } -+ --pixel; -+ Wire.endTransmission(); -+ } -+ } -+#else - ssd1306_command(SSD1306_COLUMNADDR); -+ #if SSD1306_LCDWIDTH == 64 && SSD1306_LCDHEIGHT == 48 -+ ssd1306_command(32); -+ ssd1306_command(32 + SSD1306_LCDWIDTH - 1); -+ #else - ssd1306_command(0); // Column start address (0 = reset) - ssd1306_command(SSD1306_LCDWIDTH-1); // Column end address (127 = reset) -+#endif - - ssd1306_command(SSD1306_PAGEADDR); - ssd1306_command(0); // Page start address (0 = reset) -- #if SSD1306_LCDHEIGHT == 64 -+ ssd1306_command((SSD1306_LCDHEIGHT / 8) - 1); // Page end address -+ /* -+ #if SSD1306_LCDWIDTH == 128 && SSD1306_LCDHEIGHT == 64 - ssd1306_command(7); // Page end address -- #endif -- #if SSD1306_LCDHEIGHT == 32 -+ #elif SSD1306_LCDWIDTH == 64 && SSD1306_LCDHEIGHT == 48 -+ ssd1306_command(5); // Page end address -+ #elif SSD1306_LCDWIDTH == 128 && SSD1306_LCDHEIGHT == 32 - ssd1306_command(3); // Page end address -- #endif -- #if SSD1306_LCDHEIGHT == 16 -+ #elif SSD1306_LCDWIDTH == 96 && SSD1306_LCDHEIGHT == 16 -+ - ssd1306_command(1); // Page end address - #endif -+*/ - - if (sid != -1) - { -@@ -482,6 +549,7 @@ void Adafruit_SSD1306::display(void) { - TWBR = twbrbackup; - #endif - } -+#endif /* defined SH1106_128_64 */ - } - - // clear everything -@@ -564,13 +632,13 @@ void Adafruit_SSD1306::drawFastHLineInternal(int16_t x, int16_t y, int16_t w, ui - if(w <= 0) { return; } - - // set up the pointer for movement through the buffer -- register uint8_t *pBuf = buffer; -+ uint8_t *pBuf = buffer; - // adjust the buffer pointer for the current row - pBuf += ((y/8) * SSD1306_LCDWIDTH); - // and offset x columns in - pBuf += x; - -- register uint8_t mask = 1 << (y&7); -+ uint8_t mask = 1 << (y&7); - - switch (color) - { -@@ -638,27 +706,27 @@ void Adafruit_SSD1306::drawFastVLineInternal(int16_t x, int16_t __y, int16_t __h - } - - // this display doesn't need ints for coordinates, use local byte registers for faster juggling -- register uint8_t y = __y; -- register uint8_t h = __h; -+ uint8_t y = __y; -+ uint8_t h = __h; - - - // set up the pointer for fast movement through the buffer -- register uint8_t *pBuf = buffer; -+ uint8_t *pBuf = buffer; - // adjust the buffer pointer for the current row - pBuf += ((y/8) * SSD1306_LCDWIDTH); - // and offset x columns in - pBuf += x; - - // do the first partial byte, if necessary - this requires some masking -- register uint8_t mod = (y&7); -+ uint8_t mod = (y&7); - if(mod) { - // mask off the high n bits we want to set - mod = 8-mod; - - // note - lookup table results in a nearly 10% performance improvement in fill* functions -- // register uint8_t mask = ~(0xFF >> (mod)); -+ // uint8_t mask = ~(0xFF >> (mod)); - static uint8_t premask[8] = {0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE }; -- register uint8_t mask = premask[mod]; -+ uint8_t mask = premask[mod]; - - // adjust the mask if we're not going to reach the end of this byte - if( h < mod) { -@@ -696,7 +764,7 @@ void Adafruit_SSD1306::drawFastVLineInternal(int16_t x, int16_t __y, int16_t __h - } - else { - // store a local value to work with -- register uint8_t val = (color == WHITE) ? 255 : 0; -+ uint8_t val = (color == WHITE) ? 255 : 0; - - do { - // write our value in -@@ -715,10 +783,10 @@ void Adafruit_SSD1306::drawFastVLineInternal(int16_t x, int16_t __y, int16_t __h - if(h) { - mod = h & 7; - // this time we want to mask the low bits of the byte, vs the high bits we did above -- // register uint8_t mask = (1 << mod) - 1; -+ // uint8_t mask = (1 << mod) - 1; - // note - lookup table results in a nearly 10% performance improvement in fill* functions - static uint8_t postmask[8] = {0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F }; -- register uint8_t mask = postmask[mod]; -+ uint8_t mask = postmask[mod]; - switch (color) - { - case WHITE: *pBuf |= mask; break; -diff --git a/Adafruit_SSD1306.h b/Adafruit_SSD1306.h -index 1162f87..28d783f 100644 ---- a/Adafruit_SSD1306.h -+++ b/Adafruit_SSD1306.h -@@ -46,7 +46,7 @@ All text above, and the splash screen must be included in any redistribution - #endif - - #include --#include -+#include - - #define BLACK 0 - #define WHITE 1 -@@ -69,20 +69,29 @@ All text above, and the splash screen must be included in any redistribution - - SSD1306_96_16 - -+ SH1106_128_64 - 1.3" OLED display version -+ - -----------------------------------------------------------------------*/ --// #define SSD1306_128_64 -- #define SSD1306_128_32 --// #define SSD1306_96_16 -+// #define SH1106_128_64 -+ #define SSD1306_128_64 -+// #define SSD1306_128_32 -+// #define SSD1306_96_16 -+// #define SSD1306_64_48 - /*=========================================================================*/ - -+#if defined SSD1306_128_64 && defined SH1106_128_64 -+ #error "Select either SH1106 or SSD1306 display type in SSD1306.h" -+#endif -+ +diff --git a/README.md b/README.md +index 6dc7e1d..ea3caf9 100644 +--- a/README.md ++++ b/README.md +@@ -1,4 +1,6 @@ +-# Adafruit_SSD1306 [![Build Status](https://github.com/adafruit/Adafruit_SSD1306/workflows/Arduino%20Library%20CI/badge.svg)](https://github.com/adafruit/Adafruit_SSD1306/actions)[![Documentation](https://github.com/adafruit/ci-arduino/blob/master/assets/doxygen_badge.svg)](http://adafruit.github.io/Adafruit_SSD1306/html/index.html) ++# Adafruit_SSD1306 + - #if defined SSD1306_128_64 && defined SSD1306_128_32 - #error "Only one SSD1306 display can be specified at once in SSD1306.h" - #endif --#if !defined SSD1306_128_64 && !defined SSD1306_128_32 && !defined SSD1306_96_16 -+#if !defined SSD1306_128_64 && !defined SSD1306_128_32 && !defined SSD1306_96_16 && !defined SSD1306_64_48 && !defined SH1106_128_64 - #error "At least one SSD1306 display must be specified in SSD1306.h" - #endif ++[![Build Status](https://github.com/adafruit/Adafruit_SSD1306/workflows/Arduino%20Library%20CI/badge.svg)](https://github.com/adafruit/Adafruit_SSD1306/actions)[![Documentation](https://github.com/adafruit/ci-arduino/blob/master/assets/doxygen_badge.svg)](http://adafruit.github.io/Adafruit_SSD1306/html/index.html) --#if defined SSD1306_128_64 -+#if defined SSD1306_128_64 || defined SH1106_128_64 - #define SSD1306_LCDWIDTH 128 - #define SSD1306_LCDHEIGHT 64 - #endif -@@ -93,6 +102,9 @@ All text above, and the splash screen must be included in any redistribution - #if defined SSD1306_96_16 - #define SSD1306_LCDWIDTH 96 - #define SSD1306_LCDHEIGHT 16 -+#elif defined SSD1306_64_48 -+ #define SSD1306_LCDWIDTH 64 -+ #define SSD1306_LCDHEIGHT 48 - #endif + This is a library for our Monochrome OLEDs based on SSD1306 drivers - #define SSD1306_SETCONTRAST 0x81 -@@ -132,6 +144,8 @@ All text above, and the splash screen must be included in any redistribution - #define SSD1306_EXTERNALVCC 0x1 - #define SSD1306_SWITCHCAPVCC 0x2 - -+#define SH1106_SETSTARTPAGE 0xB0 -+ - // Scrolling #defines - #define SSD1306_ACTIVATE_SCROLL 0x2F - #define SSD1306_DEACTIVATE_SCROLL 0x2E diff --git a/Sming/Libraries/.patches/Adafruit_SSD1306/README.md b/Sming/Libraries/.patches/Adafruit_SSD1306/README.md deleted file mode 100644 index 3d9f2bcee2..0000000000 --- a/Sming/Libraries/.patches/Adafruit_SSD1306/README.md +++ /dev/null @@ -1,60 +0,0 @@ -# Adafruit SSD1306 Display - -## Introduction - -This is a library for our Monochrome OLEDs based on SSD1306 drivers - - Pick one up today in the adafruit shop! - ------> http://www.adafruit.com/category/63_98 - -These displays use SPI to communicate, 4 or 5 pins are required to -interface - -Adafruit invests time and resources providing this open source code, -please support Adafruit and open-source hardware by purchasing -products from Adafruit! - -Written by Limor Fried/Ladyada for Adafruit Industries. -Scrolling code contributed by Michael Gregg -BSD license, check license.txt for more information -All text above must be included in any redistribution - -To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder Adafruit_SSD1306. Check that the Adafruit_SSD1306 folder contains Adafruit_SSD1306.cpp and Adafruit_SSD1306.h - -Place the Adafruit_SSD1306 library folder your /libraries/ folder. You may need to create the libraries subfolder if its your first library. Restart the IDE. - -You will also have to download the Adafruit GFX Graphics core which does all the circles, text, rectangles, etc. You can get it from -https://github.com/adafruit/Adafruit-GFX-Library -and download/install that library as well - - - -## Compatibility - -MCU | Tested Works | Doesn't Work | Not Tested | Notes ------------------- | :----------: | :----------: | :---------: | ----- -Atmega328 @ 16MHz | X | | | -Atmega328 @ 12MHz | X | | | -Atmega32u4 @ 16MHz | X | | | -Atmega32u4 @ 8MHz | X | | | -ESP8266 | X | | | change OLED_RESET to different pin if using default I2C pins D4/D5. -Atmega2560 @ 16MHz | X | | | -ATSAM3X8E | X | | | -ATSAM21D | X | | | -ATtiny85 @ 16MHz | | X | | -ATtiny85 @ 8MHz | | X | | -Intel Curie @ 32MHz | | | X | -STM32F2 | | | X | - - * ATmega328 @ 16MHz : Arduino UNO, Adafruit Pro Trinket 5V, Adafruit Metro 328, Adafruit Metro Mini - * ATmega328 @ 12MHz : Adafruit Pro Trinket 3V - * ATmega32u4 @ 16MHz : Arduino Leonardo, Arduino Micro, Arduino Yun, Teensy 2.0 - * ATmega32u4 @ 8MHz : Adafruit Flora, Bluefruit Micro - * ESP8266 : Adafruit Huzzah - * ATmega2560 @ 16MHz : Arduino Mega - * ATSAM3X8E : Arduino Due - * ATSAM21D : Arduino Zero, M0 Pro - * ATtiny85 @ 16MHz : Adafruit Trinket 5V - * ATtiny85 @ 8MHz : Adafruit Gemma, Arduino Gemma, Adafruit Trinket 3V - - diff --git a/Sming/Libraries/.patches/Adafruit_SSD1306/component.mk b/Sming/Libraries/.patches/Adafruit_SSD1306/component.mk index f1713fa80a..c0f10a2685 100644 --- a/Sming/Libraries/.patches/Adafruit_SSD1306/component.mk +++ b/Sming/Libraries/.patches/Adafruit_SSD1306/component.mk @@ -1,2 +1,8 @@ -COMPONENT_SOC := esp8266 +COMPONENT_SOC := * COMPONENT_DEPENDS := Adafruit_GFX +COMPONENT_INCDIRS := . + +ifeq ($(SMING_ARCH),Host) + # pretend to be ESP8266 build + COMPONENT_CPPFLAGS += -DESP8266 +endif diff --git a/Sming/Libraries/.patches/Adafruit_ST7735.patch b/Sming/Libraries/.patches/Adafruit_ST7735.patch index 70a6963881..fe774a4c70 100644 --- a/Sming/Libraries/.patches/Adafruit_ST7735.patch +++ b/Sming/Libraries/.patches/Adafruit_ST7735.patch @@ -1,13 +1,13 @@ -diff --git a/Adafruit_ST7735.h b/Adafruit_ST7735.h -index b1e85fd..b10d01c 100755 ---- a/Adafruit_ST7735.h -+++ b/Adafruit_ST7735.h -@@ -26,7 +26,7 @@ as well as Adafruit raw 1.8" TFT display +diff --git a/README.txt b/README.md +similarity index 98% +rename from README.txt +rename to README.md +index 7689d77..fc1dca5 100644 +--- a/README.txt ++++ b/README.md +@@ -1,3 +1,5 @@ ++# Adafruit ST7735 Display ++ + This is a library for several Adafruit displays based on ST77* drivers. - #include "Arduino.h" - #include "Print.h" --#include -+#include - - #if defined(__AVR__) || defined(CORE_TEENSY) - #include + Works with the Adafruit 1.8" TFT Breakout w/SD card diff --git a/Sming/Libraries/.patches/Adafruit_ST7735/README.md b/Sming/Libraries/.patches/Adafruit_ST7735/README.md deleted file mode 100644 index 89fabb3ca8..0000000000 --- a/Sming/Libraries/.patches/Adafruit_ST7735/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# Adafruit ST7735 Display - -This is a library for the Adafruit 1.8" SPI display. -This library works with the Adafruit 1.8" TFT Breakout w/SD card - ----> http://www.adafruit.com/products/358 -The 1.8" TFT shield - ----> https://www.adafruit.com/product/802 -The 1.44" TFT breakout - ----> https://www.adafruit.com/product/2088 -as well as Adafruit raw 1.8" TFT display - ----> http://www.adafruit.com/products/618 - - -Check out the links above for our tutorials and wiring diagrams. -These displays use SPI to communicate, 4 or 5 pins are required -to interface (RST is optional). -Adafruit invests time and resources providing this open source code, -please support Adafruit and open-source hardware by purchasing -products from Adafruit! - -Written by Limor Fried/Ladyada for Adafruit Industries. -MIT license, all text above must be included in any redistribution - -To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder Adafruit_ST7735. Check that the Adafruit_ST7735 folder contains Adafruit_ST7735.cpp and Adafruit_ST7735. - -Place the Adafruit_ST7735 library folder your /libraries/ folder. You may need to create the libraries subfolder if its your first library. Restart the IDE - -Also requires the Adafruit_GFX library for Arduino. diff --git a/Sming/Libraries/Adafruit_GFX b/Sming/Libraries/Adafruit_GFX new file mode 160000 index 0000000000..223f914d0e --- /dev/null +++ b/Sming/Libraries/Adafruit_GFX @@ -0,0 +1 @@ +Subproject commit 223f914d0e092cc24723182a2e3273e61c4b22ea diff --git a/Sming/Libraries/Adafruit_GFX/Adafruit_GFX.cpp b/Sming/Libraries/Adafruit_GFX/Adafruit_GFX.cpp deleted file mode 100644 index 300386f8a1..0000000000 --- a/Sming/Libraries/Adafruit_GFX/Adafruit_GFX.cpp +++ /dev/null @@ -1,518 +0,0 @@ -/* -This is the core graphics library for all our displays, providing a common -set of graphics primitives (points, lines, circles, etc.). It needs to be -paired with a hardware-specific library for each display device we carry -(to handle the lower-level functions). - -Adafruit invests time and resources providing this open source code, please -support Adafruit & open-source hardware by purchasing products from Adafruit! - -Copyright (c) 2013 Adafruit Industries. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -- Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. -- Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "Adafruit_GFX.h" - -#include - -#include "glcdfont.c" - -Adafruit_GFX::Adafruit_GFX(int16_t w, int16_t h): - WIDTH(w), HEIGHT(h) -{ - _width = WIDTH; - _height = HEIGHT; - rotation = 0; - cursor_y = cursor_x = 0; - textsize = 1; - textcolor = textbgcolor = 0xFFFF; - wrap = true; -} - -// Draw a circle outline -void Adafruit_GFX::drawCircle(int16_t x0, int16_t y0, int16_t r, - uint16_t color) { - int16_t f = 1 - r; - int16_t ddF_x = 1; - int16_t ddF_y = -2 * r; - int16_t x = 0; - int16_t y = r; - - drawPixel(x0 , y0+r, color); - drawPixel(x0 , y0-r, color); - drawPixel(x0+r, y0 , color); - drawPixel(x0-r, y0 , color); - - while (x= 0) { - y--; - ddF_y += 2; - f += ddF_y; - } - x++; - ddF_x += 2; - f += ddF_x; - - drawPixel(x0 + x, y0 + y, color); - drawPixel(x0 - x, y0 + y, color); - drawPixel(x0 + x, y0 - y, color); - drawPixel(x0 - x, y0 - y, color); - drawPixel(x0 + y, y0 + x, color); - drawPixel(x0 - y, y0 + x, color); - drawPixel(x0 + y, y0 - x, color); - drawPixel(x0 - y, y0 - x, color); - } -} - -void Adafruit_GFX::drawCircleHelper( int16_t x0, int16_t y0, - int16_t r, uint8_t cornername, uint16_t color) { - int16_t f = 1 - r; - int16_t ddF_x = 1; - int16_t ddF_y = -2 * r; - int16_t x = 0; - int16_t y = r; - - while (x= 0) { - y--; - ddF_y += 2; - f += ddF_y; - } - x++; - ddF_x += 2; - f += ddF_x; - if (cornername & 0x4) { - drawPixel(x0 + x, y0 + y, color); - drawPixel(x0 + y, y0 + x, color); - } - if (cornername & 0x2) { - drawPixel(x0 + x, y0 - y, color); - drawPixel(x0 + y, y0 - x, color); - } - if (cornername & 0x8) { - drawPixel(x0 - y, y0 + x, color); - drawPixel(x0 - x, y0 + y, color); - } - if (cornername & 0x1) { - drawPixel(x0 - y, y0 - x, color); - drawPixel(x0 - x, y0 - y, color); - } - } -} - -void Adafruit_GFX::fillCircle(int16_t x0, int16_t y0, int16_t r, - uint16_t color) { - drawFastVLine(x0, y0-r, 2*r+1, color); - fillCircleHelper(x0, y0, r, 3, 0, color); -} - -// Used to do circles and roundrects -void Adafruit_GFX::fillCircleHelper(int16_t x0, int16_t y0, int16_t r, - uint8_t cornername, int16_t delta, uint16_t color) { - - int16_t f = 1 - r; - int16_t ddF_x = 1; - int16_t ddF_y = -2 * r; - int16_t x = 0; - int16_t y = r; - - while (x= 0) { - y--; - ddF_y += 2; - f += ddF_y; - } - x++; - ddF_x += 2; - f += ddF_x; - - if (cornername & 0x1) { - drawFastVLine(x0+x, y0-y, 2*y+1+delta, color); - drawFastVLine(x0+y, y0-x, 2*x+1+delta, color); - } - if (cornername & 0x2) { - drawFastVLine(x0-x, y0-y, 2*y+1+delta, color); - drawFastVLine(x0-y, y0-x, 2*x+1+delta, color); - } - } -} - -// Bresenham's algorithm - thx wikipedia -void Adafruit_GFX::drawLine(int16_t x0, int16_t y0, - int16_t x1, int16_t y1, - uint16_t color) { - int16_t steep = abs(y1 - y0) > abs(x1 - x0); - if (steep) { - swap(x0, y0); - swap(x1, y1); - } - - if (x0 > x1) { - swap(x0, x1); - swap(y0, y1); - } - - int16_t dx, dy; - dx = x1 - x0; - dy = abs(y1 - y0); - - int16_t err = dx / 2; - int16_t ystep; - - if (y0 < y1) { - ystep = 1; - } else { - ystep = -1; - } - - for (; x0<=x1; x0++) { - if (steep) { - drawPixel(y0, x0, color); - } else { - drawPixel(x0, y0, color); - } - err -= dy; - if (err < 0) { - y0 += ystep; - err += dx; - } - } -} - -// Draw a rectangle -void Adafruit_GFX::drawRect(int16_t x, int16_t y, - int16_t w, int16_t h, - uint16_t color) { - drawFastHLine(x, y, w, color); - drawFastHLine(x, y+h-1, w, color); - drawFastVLine(x, y, h, color); - drawFastVLine(x+w-1, y, h, color); -} - -void Adafruit_GFX::drawFastVLine(int16_t x, int16_t y, - int16_t h, uint16_t color) { - // Update in subclasses if desired! - drawLine(x, y, x, y+h-1, color); -} - -void Adafruit_GFX::drawFastHLine(int16_t x, int16_t y, - int16_t w, uint16_t color) { - // Update in subclasses if desired! - drawLine(x, y, x+w-1, y, color); -} - -void Adafruit_GFX::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, - uint16_t color) { - // Update in subclasses if desired! - for (int16_t i=x; i= y1 >= y0) - if (y0 > y1) { - swap(y0, y1); swap(x0, x1); - } - if (y1 > y2) { - swap(y2, y1); swap(x2, x1); - } - if (y0 > y1) { - swap(y0, y1); swap(x0, x1); - } - - if(y0 == y2) { // Handle awkward all-on-same-line case as its own thing - a = b = x0; - if(x1 < a) a = x1; - else if(x1 > b) b = x1; - if(x2 < a) a = x2; - else if(x2 > b) b = x2; - drawFastHLine(a, y0, b-a+1, color); - return; - } - - int16_t - dx01 = x1 - x0, - dy01 = y1 - y0, - dx02 = x2 - x0, - dy02 = y2 - y0, - dx12 = x2 - x1, - dy12 = y2 - y1; - int32_t - sa = 0, - sb = 0; - - // For upper part of triangle, find scanline crossings for segments - // 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1 - // is included here (and second loop will be skipped, avoiding a /0 - // error there), otherwise scanline y1 is skipped here and handled - // in the second loop...which also avoids a /0 error here if y0=y1 - // (flat-topped triangle). - if(y1 == y2) last = y1; // Include y1 scanline - else last = y1-1; // Skip it - - for(y=y0; y<=last; y++) { - a = x0 + sa / dy01; - b = x0 + sb / dy02; - sa += dx01; - sb += dx02; - /* longhand: - a = x0 + (x1 - x0) * (y - y0) / (y1 - y0); - b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); - */ - if(a > b) swap(a,b); - drawFastHLine(a, y, b-a+1, color); - } - - // For lower part of triangle, find scanline crossings for segments - // 0-2 and 1-2. This loop is skipped if y1=y2. - sa = dx12 * (y - y1); - sb = dx02 * (y - y0); - for(; y<=y2; y++) { - a = x1 + sa / dy12; - b = x0 + sb / dy02; - sa += dx12; - sb += dx02; - /* longhand: - a = x1 + (x2 - x1) * (y - y1) / (y2 - y1); - b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); - */ - if(a > b) swap(a,b); - drawFastHLine(a, y, b-a+1, color); - } -} - -void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, - const uint8_t *bitmap, int16_t w, int16_t h, - uint16_t color) { - - int16_t i, j, byteWidth = (w + 7) / 8; - - for(j=0; j> (i & 7))) { - drawPixel(x+i, y+j, color); - } - } - } -} - -// Draw a 1-bit color bitmap at the specified x, y position from the -// provided bitmap buffer (must be PROGMEM memory) using color as the -// foreground color and bg as the background color. -void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, - const uint8_t *bitmap, int16_t w, int16_t h, - uint16_t color, uint16_t bg) { - - int16_t i, j, byteWidth = (w + 7) / 8; - - for(j=0; j> (i & 7))) { - drawPixel(x+i, y+j, color); - } - else { - drawPixel(x+i, y+j, bg); - } - } - } -} - -//Draw XBitMap Files (*.xbm), exported from GIMP, -//Usage: Export from GIMP to *.xbm, rename *.xbm to *.c and open in editor. -//C Array can be directly used with this function -void Adafruit_GFX::drawXBitmap(int16_t x, int16_t y, - const uint8_t *bitmap, int16_t w, int16_t h, - uint16_t color) { - - int16_t i, j, byteWidth = (w + 7) / 8; - - for(j=0; j= 100 -size_t Adafruit_GFX::write(uint8_t c) { -#else -void Adafruit_GFX::write(uint8_t c) { -#endif - if (c == '\n') { - cursor_y += textsize*8; - cursor_x = 0; - } else if (c == '\r') { - // skip em - } else { - drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize); - cursor_x += textsize*6; - if (wrap && (cursor_x > (_width - textsize*6))) { - cursor_y += textsize*8; - cursor_x = 0; - } - } -#if ARDUINO >= 100 - return 1; -#endif -} - -// Draw a character -void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c, - uint16_t color, uint16_t bg, uint8_t size) { - - if((x >= _width) || // Clip right - (y >= _height) || // Clip bottom - ((x + 6 * size - 1) < 0) || // Clip left - ((y + 8 * size - 1) < 0)) // Clip top - return; - - for (int8_t i=0; i<6; i++ ) { - uint8_t line; - if (i == 5) - line = 0x0; - else - line = pgm_read_byte(font+(c*5)+i); - for (int8_t j = 0; j<8; j++) { - if (line & 0x1) { - if (size == 1) // default size - drawPixel(x+i, y+j, color); - else { // big size - fillRect(x+(i*size), y+(j*size), size, size, color); - } - } else if (bg != color) { - if (size == 1) // default size - drawPixel(x+i, y+j, bg); - else { // big size - fillRect(x+i*size, y+j*size, size, size, bg); - } - } - line >>= 1; - } - } -} - -void Adafruit_GFX::setCursor(int16_t x, int16_t y) { - cursor_x = x; - cursor_y = y; -} - -void Adafruit_GFX::setTextSize(uint8_t s) { - textsize = (s > 0) ? s : 1; -} - -void Adafruit_GFX::setTextColor(uint16_t c) { - // For 'transparent' background, we'll set the bg - // to the same as fg instead of using a flag - textcolor = textbgcolor = c; -} - -void Adafruit_GFX::setTextColor(uint16_t c, uint16_t b) { - textcolor = c; - textbgcolor = b; -} - -void Adafruit_GFX::setTextWrap(boolean w) { - wrap = w; -} - -uint8_t Adafruit_GFX::getRotation(void) const { - return rotation; -} - -void Adafruit_GFX::setRotation(uint8_t x) { - rotation = (x & 3); - switch(rotation) { - case 0: - case 2: - _width = WIDTH; - _height = HEIGHT; - break; - case 1: - case 3: - _width = HEIGHT; - _height = WIDTH; - break; - } -} - -// Return the size of the display (per current rotation) -int16_t Adafruit_GFX::width(void) const { - return _width; -} - -int16_t Adafruit_GFX::height(void) const { - return _height; -} - -void Adafruit_GFX::invertDisplay(boolean i) { - // Do nothing, must be subclassed if supported -} - diff --git a/Sming/Libraries/Adafruit_GFX/Adafruit_GFX.h b/Sming/Libraries/Adafruit_GFX/Adafruit_GFX.h deleted file mode 100644 index 049bff06de..0000000000 --- a/Sming/Libraries/Adafruit_GFX/Adafruit_GFX.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef _ADAFRUIT_GFX_H -#define _ADAFRUIT_GFX_H - -#include -#include - -class Adafruit_GFX : public Print { - - public: - - Adafruit_GFX(int16_t w, int16_t h); // Constructor - - // This MUST be defined by the subclass: - virtual void drawPixel(int16_t x, int16_t y, uint16_t color) = 0; - - // These MAY be overridden by the subclass to provide device-specific - // optimized code. Otherwise 'generic' versions are used. - virtual void - drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color), - drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color), - drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color), - drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color), - fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color), - fillScreen(uint16_t color), - invertDisplay(boolean i); - - // These exist only with Adafruit_GFX (no subclass overrides) - void - drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color), - drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, - uint16_t color), - fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color), - fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, - int16_t delta, uint16_t color), - drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, - int16_t x2, int16_t y2, uint16_t color), - fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, - int16_t x2, int16_t y2, uint16_t color), - drawRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, - int16_t radius, uint16_t color), - fillRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, - int16_t radius, uint16_t color), - drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, - int16_t w, int16_t h, uint16_t color), - drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, - int16_t w, int16_t h, uint16_t color, uint16_t bg), - drawXBitmap(int16_t x, int16_t y, const uint8_t *bitmap, - int16_t w, int16_t h, uint16_t color), - drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, - uint16_t bg, uint8_t size), - setCursor(int16_t x, int16_t y), - setTextColor(uint16_t c), - setTextColor(uint16_t c, uint16_t bg), - setTextSize(uint8_t s), - setTextWrap(boolean w), - setRotation(uint8_t r); - - virtual size_t write(uint8_t); - - int16_t height(void) const; - int16_t width(void) const; - - uint8_t getRotation(void) const; - - protected: - const int16_t - WIDTH, HEIGHT; // This is the 'raw' display w/h - never changes - int16_t - _width, _height, // Display w/h as modified by current rotation - cursor_x, cursor_y; - uint16_t - textcolor, textbgcolor; - uint8_t - textsize, - rotation; - boolean - wrap; // If set, 'wrap' text at right edge of display -}; - -#endif // _ADAFRUIT_GFX_H diff --git a/Sming/Libraries/Adafruit_GFX/README.md b/Sming/Libraries/Adafruit_GFX/README.md deleted file mode 100644 index 065a38d305..0000000000 --- a/Sming/Libraries/Adafruit_GFX/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# Adafruit GFX - -This is the core graphics library for all our displays, providing a common set of graphics primitives (points, lines, circles, etc.). It needs to be paired with a hardware-specific library for each display device we carry (to handle the lower-level functions). - -Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit! - -Written by Limor Fried/Ladyada for Adafruit Industries. -BSD license, check license.txt for more information. -All text above must be included in any redistribution. - -To download, click the DOWNLOAD ZIP button, uncompress and rename the uncompressed folder Adafruit_GFX. Confirm that the Adafruit_GFX folder contains Adafruit_GFX.cpp and Adafruit_GFX.h - -Place the Adafruit_GFX library folder your /Libraries/ folder. You may need to create the Libraries subfolder if its your first library. Restart the IDE. - -## Useful Resources - -- Image2Code - This is a handy Java GUI utility to convert a BMP file into the array code necessary to display the image with the drawBitmap function. Check out the code at ehubin's GitHub repository: - https://github.com/ehubin/Adafruit-GFX-Library/tree/master/Img2Code - -- drawXBitmap function - You can use the GIMP photo editor to save a .xbm file and use the array saved in the file to draw a bitmap with the drawXBitmap function. See the pull request here for more details: - https://github.com/adafruit/Adafruit-GFX-Library/pull/31 diff --git a/Sming/Libraries/Adafruit_GFX/glcdfont.c b/Sming/Libraries/Adafruit_GFX/glcdfont.c deleted file mode 100644 index d0a160fd19..0000000000 --- a/Sming/Libraries/Adafruit_GFX/glcdfont.c +++ /dev/null @@ -1,265 +0,0 @@ -#ifndef FONT5X7_H -#define FONT5X7_H - -#include - -// Standard ASCII 5x7 font - -static const unsigned char font[] PROGMEM = { - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3E, 0x5B, 0x4F, 0x5B, 0x3E, - 0x3E, 0x6B, 0x4F, 0x6B, 0x3E, - 0x1C, 0x3E, 0x7C, 0x3E, 0x1C, - 0x18, 0x3C, 0x7E, 0x3C, 0x18, - 0x1C, 0x57, 0x7D, 0x57, 0x1C, - 0x1C, 0x5E, 0x7F, 0x5E, 0x1C, - 0x00, 0x18, 0x3C, 0x18, 0x00, - 0xFF, 0xE7, 0xC3, 0xE7, 0xFF, - 0x00, 0x18, 0x24, 0x18, 0x00, - 0xFF, 0xE7, 0xDB, 0xE7, 0xFF, - 0x30, 0x48, 0x3A, 0x06, 0x0E, - 0x26, 0x29, 0x79, 0x29, 0x26, - 0x40, 0x7F, 0x05, 0x05, 0x07, - 0x40, 0x7F, 0x05, 0x25, 0x3F, - 0x5A, 0x3C, 0xE7, 0x3C, 0x5A, - 0x7F, 0x3E, 0x1C, 0x1C, 0x08, - 0x08, 0x1C, 0x1C, 0x3E, 0x7F, - 0x14, 0x22, 0x7F, 0x22, 0x14, - 0x5F, 0x5F, 0x00, 0x5F, 0x5F, - 0x06, 0x09, 0x7F, 0x01, 0x7F, - 0x00, 0x66, 0x89, 0x95, 0x6A, - 0x60, 0x60, 0x60, 0x60, 0x60, - 0x94, 0xA2, 0xFF, 0xA2, 0x94, - 0x08, 0x04, 0x7E, 0x04, 0x08, - 0x10, 0x20, 0x7E, 0x20, 0x10, - 0x08, 0x08, 0x2A, 0x1C, 0x08, - 0x08, 0x1C, 0x2A, 0x08, 0x08, - 0x1E, 0x10, 0x10, 0x10, 0x10, - 0x0C, 0x1E, 0x0C, 0x1E, 0x0C, - 0x30, 0x38, 0x3E, 0x38, 0x30, - 0x06, 0x0E, 0x3E, 0x0E, 0x06, - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x5F, 0x00, 0x00, - 0x00, 0x07, 0x00, 0x07, 0x00, - 0x14, 0x7F, 0x14, 0x7F, 0x14, - 0x24, 0x2A, 0x7F, 0x2A, 0x12, - 0x23, 0x13, 0x08, 0x64, 0x62, - 0x36, 0x49, 0x56, 0x20, 0x50, - 0x00, 0x08, 0x07, 0x03, 0x00, - 0x00, 0x1C, 0x22, 0x41, 0x00, - 0x00, 0x41, 0x22, 0x1C, 0x00, - 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, - 0x08, 0x08, 0x3E, 0x08, 0x08, - 0x00, 0x80, 0x70, 0x30, 0x00, - 0x08, 0x08, 0x08, 0x08, 0x08, - 0x00, 0x00, 0x60, 0x60, 0x00, - 0x20, 0x10, 0x08, 0x04, 0x02, - 0x3E, 0x51, 0x49, 0x45, 0x3E, - 0x00, 0x42, 0x7F, 0x40, 0x00, - 0x72, 0x49, 0x49, 0x49, 0x46, - 0x21, 0x41, 0x49, 0x4D, 0x33, - 0x18, 0x14, 0x12, 0x7F, 0x10, - 0x27, 0x45, 0x45, 0x45, 0x39, - 0x3C, 0x4A, 0x49, 0x49, 0x31, - 0x41, 0x21, 0x11, 0x09, 0x07, - 0x36, 0x49, 0x49, 0x49, 0x36, - 0x46, 0x49, 0x49, 0x29, 0x1E, - 0x00, 0x00, 0x14, 0x00, 0x00, - 0x00, 0x40, 0x34, 0x00, 0x00, - 0x00, 0x08, 0x14, 0x22, 0x41, - 0x14, 0x14, 0x14, 0x14, 0x14, - 0x00, 0x41, 0x22, 0x14, 0x08, - 0x02, 0x01, 0x59, 0x09, 0x06, - 0x3E, 0x41, 0x5D, 0x59, 0x4E, - 0x7C, 0x12, 0x11, 0x12, 0x7C, - 0x7F, 0x49, 0x49, 0x49, 0x36, - 0x3E, 0x41, 0x41, 0x41, 0x22, - 0x7F, 0x41, 0x41, 0x41, 0x3E, - 0x7F, 0x49, 0x49, 0x49, 0x41, - 0x7F, 0x09, 0x09, 0x09, 0x01, - 0x3E, 0x41, 0x41, 0x51, 0x73, - 0x7F, 0x08, 0x08, 0x08, 0x7F, - 0x00, 0x41, 0x7F, 0x41, 0x00, - 0x20, 0x40, 0x41, 0x3F, 0x01, - 0x7F, 0x08, 0x14, 0x22, 0x41, - 0x7F, 0x40, 0x40, 0x40, 0x40, - 0x7F, 0x02, 0x1C, 0x02, 0x7F, - 0x7F, 0x04, 0x08, 0x10, 0x7F, - 0x3E, 0x41, 0x41, 0x41, 0x3E, - 0x7F, 0x09, 0x09, 0x09, 0x06, - 0x3E, 0x41, 0x51, 0x21, 0x5E, - 0x7F, 0x09, 0x19, 0x29, 0x46, - 0x26, 0x49, 0x49, 0x49, 0x32, - 0x03, 0x01, 0x7F, 0x01, 0x03, - 0x3F, 0x40, 0x40, 0x40, 0x3F, - 0x1F, 0x20, 0x40, 0x20, 0x1F, - 0x3F, 0x40, 0x38, 0x40, 0x3F, - 0x63, 0x14, 0x08, 0x14, 0x63, - 0x03, 0x04, 0x78, 0x04, 0x03, - 0x61, 0x59, 0x49, 0x4D, 0x43, - 0x00, 0x7F, 0x41, 0x41, 0x41, - 0x02, 0x04, 0x08, 0x10, 0x20, - 0x00, 0x41, 0x41, 0x41, 0x7F, - 0x04, 0x02, 0x01, 0x02, 0x04, - 0x40, 0x40, 0x40, 0x40, 0x40, - 0x00, 0x03, 0x07, 0x08, 0x00, - 0x20, 0x54, 0x54, 0x78, 0x40, - 0x7F, 0x28, 0x44, 0x44, 0x38, - 0x38, 0x44, 0x44, 0x44, 0x28, - 0x38, 0x44, 0x44, 0x28, 0x7F, - 0x38, 0x54, 0x54, 0x54, 0x18, - 0x00, 0x08, 0x7E, 0x09, 0x02, - 0x18, 0xA4, 0xA4, 0x9C, 0x78, - 0x7F, 0x08, 0x04, 0x04, 0x78, - 0x00, 0x44, 0x7D, 0x40, 0x00, - 0x20, 0x40, 0x40, 0x3D, 0x00, - 0x7F, 0x10, 0x28, 0x44, 0x00, - 0x00, 0x41, 0x7F, 0x40, 0x00, - 0x7C, 0x04, 0x78, 0x04, 0x78, - 0x7C, 0x08, 0x04, 0x04, 0x78, - 0x38, 0x44, 0x44, 0x44, 0x38, - 0xFC, 0x18, 0x24, 0x24, 0x18, - 0x18, 0x24, 0x24, 0x18, 0xFC, - 0x7C, 0x08, 0x04, 0x04, 0x08, - 0x48, 0x54, 0x54, 0x54, 0x24, - 0x04, 0x04, 0x3F, 0x44, 0x24, - 0x3C, 0x40, 0x40, 0x20, 0x7C, - 0x1C, 0x20, 0x40, 0x20, 0x1C, - 0x3C, 0x40, 0x30, 0x40, 0x3C, - 0x44, 0x28, 0x10, 0x28, 0x44, - 0x4C, 0x90, 0x90, 0x90, 0x7C, - 0x44, 0x64, 0x54, 0x4C, 0x44, - 0x00, 0x08, 0x36, 0x41, 0x00, - 0x00, 0x00, 0x77, 0x00, 0x00, - 0x00, 0x41, 0x36, 0x08, 0x00, - 0x02, 0x01, 0x02, 0x04, 0x02, - 0x3C, 0x26, 0x23, 0x26, 0x3C, - 0x1E, 0xA1, 0xA1, 0x61, 0x12, - 0x3A, 0x40, 0x40, 0x20, 0x7A, - 0x38, 0x54, 0x54, 0x55, 0x59, - 0x21, 0x55, 0x55, 0x79, 0x41, - 0x22, 0x54, 0x54, 0x78, 0x42, // a-umlaut - 0x21, 0x55, 0x54, 0x78, 0x40, - 0x20, 0x54, 0x55, 0x79, 0x40, - 0x0C, 0x1E, 0x52, 0x72, 0x12, - 0x39, 0x55, 0x55, 0x55, 0x59, - 0x39, 0x54, 0x54, 0x54, 0x59, - 0x39, 0x55, 0x54, 0x54, 0x58, - 0x00, 0x00, 0x45, 0x7C, 0x41, - 0x00, 0x02, 0x45, 0x7D, 0x42, - 0x00, 0x01, 0x45, 0x7C, 0x40, - 0x7D, 0x12, 0x11, 0x12, 0x7D, // A-umlaut - 0xF0, 0x28, 0x25, 0x28, 0xF0, - 0x7C, 0x54, 0x55, 0x45, 0x00, - 0x20, 0x54, 0x54, 0x7C, 0x54, - 0x7C, 0x0A, 0x09, 0x7F, 0x49, - 0x32, 0x49, 0x49, 0x49, 0x32, - 0x3A, 0x44, 0x44, 0x44, 0x3A, // o-umlaut - 0x32, 0x4A, 0x48, 0x48, 0x30, - 0x3A, 0x41, 0x41, 0x21, 0x7A, - 0x3A, 0x42, 0x40, 0x20, 0x78, - 0x00, 0x9D, 0xA0, 0xA0, 0x7D, - 0x3D, 0x42, 0x42, 0x42, 0x3D, // O-umlaut - 0x3D, 0x40, 0x40, 0x40, 0x3D, - 0x3C, 0x24, 0xFF, 0x24, 0x24, - 0x48, 0x7E, 0x49, 0x43, 0x66, - 0x2B, 0x2F, 0xFC, 0x2F, 0x2B, - 0xFF, 0x09, 0x29, 0xF6, 0x20, - 0xC0, 0x88, 0x7E, 0x09, 0x03, - 0x20, 0x54, 0x54, 0x79, 0x41, - 0x00, 0x00, 0x44, 0x7D, 0x41, - 0x30, 0x48, 0x48, 0x4A, 0x32, - 0x38, 0x40, 0x40, 0x22, 0x7A, - 0x00, 0x7A, 0x0A, 0x0A, 0x72, - 0x7D, 0x0D, 0x19, 0x31, 0x7D, - 0x26, 0x29, 0x29, 0x2F, 0x28, - 0x26, 0x29, 0x29, 0x29, 0x26, - 0x30, 0x48, 0x4D, 0x40, 0x20, - 0x38, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x38, - 0x2F, 0x10, 0xC8, 0xAC, 0xBA, - 0x2F, 0x10, 0x28, 0x34, 0xFA, - 0x00, 0x00, 0x7B, 0x00, 0x00, - 0x08, 0x14, 0x2A, 0x14, 0x22, - 0x22, 0x14, 0x2A, 0x14, 0x08, - 0xAA, 0x00, 0x55, 0x00, 0xAA, - 0xAA, 0x55, 0xAA, 0x55, 0xAA, - 0x00, 0x00, 0x00, 0xFF, 0x00, - 0x10, 0x10, 0x10, 0xFF, 0x00, - 0x14, 0x14, 0x14, 0xFF, 0x00, - 0x10, 0x10, 0xFF, 0x00, 0xFF, - 0x10, 0x10, 0xF0, 0x10, 0xF0, - 0x14, 0x14, 0x14, 0xFC, 0x00, - 0x14, 0x14, 0xF7, 0x00, 0xFF, - 0x00, 0x00, 0xFF, 0x00, 0xFF, - 0x14, 0x14, 0xF4, 0x04, 0xFC, - 0x14, 0x14, 0x17, 0x10, 0x1F, - 0x10, 0x10, 0x1F, 0x10, 0x1F, - 0x14, 0x14, 0x14, 0x1F, 0x00, - 0x10, 0x10, 0x10, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x1F, 0x10, - 0x10, 0x10, 0x10, 0x1F, 0x10, - 0x10, 0x10, 0x10, 0xF0, 0x10, - 0x00, 0x00, 0x00, 0xFF, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0xFF, 0x10, - 0x00, 0x00, 0x00, 0xFF, 0x14, - 0x00, 0x00, 0xFF, 0x00, 0xFF, - 0x00, 0x00, 0x1F, 0x10, 0x17, - 0x00, 0x00, 0xFC, 0x04, 0xF4, - 0x14, 0x14, 0x17, 0x10, 0x17, - 0x14, 0x14, 0xF4, 0x04, 0xF4, - 0x00, 0x00, 0xFF, 0x00, 0xF7, - 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0xF7, 0x00, 0xF7, - 0x14, 0x14, 0x14, 0x17, 0x14, - 0x10, 0x10, 0x1F, 0x10, 0x1F, - 0x14, 0x14, 0x14, 0xF4, 0x14, - 0x10, 0x10, 0xF0, 0x10, 0xF0, - 0x00, 0x00, 0x1F, 0x10, 0x1F, - 0x00, 0x00, 0x00, 0x1F, 0x14, - 0x00, 0x00, 0x00, 0xFC, 0x14, - 0x00, 0x00, 0xF0, 0x10, 0xF0, - 0x10, 0x10, 0xFF, 0x10, 0xFF, - 0x14, 0x14, 0x14, 0xFF, 0x14, - 0x10, 0x10, 0x10, 0x1F, 0x00, - 0x00, 0x00, 0x00, 0xF0, 0x10, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, - 0x38, 0x44, 0x44, 0x38, 0x44, - 0xFC, 0x4A, 0x4A, 0x4A, 0x34, // sharp-s or beta - 0x7E, 0x02, 0x02, 0x06, 0x06, - 0x02, 0x7E, 0x02, 0x7E, 0x02, - 0x63, 0x55, 0x49, 0x41, 0x63, - 0x38, 0x44, 0x44, 0x3C, 0x04, - 0x40, 0x7E, 0x20, 0x1E, 0x20, - 0x06, 0x02, 0x7E, 0x02, 0x02, - 0x99, 0xA5, 0xE7, 0xA5, 0x99, - 0x1C, 0x2A, 0x49, 0x2A, 0x1C, - 0x4C, 0x72, 0x01, 0x72, 0x4C, - 0x30, 0x4A, 0x4D, 0x4D, 0x30, - 0x30, 0x48, 0x78, 0x48, 0x30, - 0xBC, 0x62, 0x5A, 0x46, 0x3D, - 0x3E, 0x49, 0x49, 0x49, 0x00, - 0x7E, 0x01, 0x01, 0x01, 0x7E, - 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, - 0x44, 0x44, 0x5F, 0x44, 0x44, - 0x40, 0x51, 0x4A, 0x44, 0x40, - 0x40, 0x44, 0x4A, 0x51, 0x40, - 0x00, 0x00, 0xFF, 0x01, 0x03, - 0xE0, 0x80, 0xFF, 0x00, 0x00, - 0x08, 0x08, 0x6B, 0x6B, 0x08, - 0x36, 0x12, 0x36, 0x24, 0x36, - 0x06, 0x0F, 0x09, 0x0F, 0x06, - 0x00, 0x00, 0x18, 0x18, 0x00, - 0x00, 0x00, 0x10, 0x10, 0x00, - 0x30, 0x40, 0xFF, 0x01, 0x01, - 0x00, 0x1F, 0x01, 0x01, 0x1E, - 0x00, 0x19, 0x1D, 0x17, 0x12, - 0x00, 0x3C, 0x3C, 0x3C, 0x3C, - 0x00, 0x00, 0x00, 0x00, 0x00 -}; -#endif // FONT5X7_H diff --git a/Sming/Libraries/Adafruit_GFX/license.txt b/Sming/Libraries/Adafruit_GFX/license.txt deleted file mode 100644 index 7492e93a13..0000000000 --- a/Sming/Libraries/Adafruit_GFX/license.txt +++ /dev/null @@ -1,24 +0,0 @@ -Software License Agreement (BSD License) - -Copyright (c) 2012 Adafruit Industries. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -- Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. -- Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. diff --git a/Sming/Libraries/Adafruit_ILI9341 b/Sming/Libraries/Adafruit_ILI9341 new file mode 160000 index 0000000000..172411ce7c --- /dev/null +++ b/Sming/Libraries/Adafruit_ILI9341 @@ -0,0 +1 @@ +Subproject commit 172411ce7cf85449731ea7a6ad9d5b5986e8b923 diff --git a/Sming/Libraries/Adafruit_ILI9341/Adafruit_ILI9341.cpp b/Sming/Libraries/Adafruit_ILI9341/Adafruit_ILI9341.cpp deleted file mode 100644 index 4fdde584dd..0000000000 --- a/Sming/Libraries/Adafruit_ILI9341/Adafruit_ILI9341.cpp +++ /dev/null @@ -1,328 +0,0 @@ -/*************************************************** - This is our library for the Adafruit ILI9341 Breakout and Shield - ----> http://www.adafruit.com/products/1651 - - Check out the links above for our tutorials and wiring diagrams - These displays use SPI to communicate, 4 or 5 pins are required to - interface (RST is optional) - Adafruit invests time and resources providing this open source code, - please support Adafruit and open-source hardware by purchasing - products from Adafruit! - - Written by Limor Fried/Ladyada for Adafruit Industries. - MIT license, all text above must be included in any redistribution - ****************************************************/ -/******************************** - * ported for Sming by M.Bozkurt. - * alonewolf07@gmail.com - ********************************/ - -#include "Adafruit_ILI9341.h" - -#define SWAPBYTES(i) ((i>>8) | (i<<8)) - -#define TFT_CS_ACTIVE digitalWrite(TFT_CS_PIN, false) -#define TFT_CS_DEACTIVE digitalWrite(TFT_CS_PIN, true) -#define TFT_CS_INIT pinMode(TFT_CS_PIN, OUTPUT); TFT_CS_DEACTIVE - -#define TFT_DC_DATA digitalWrite(TFT_DC_PIN, true) -#define TFT_DC_COMMAND digitalWrite(TFT_DC_PIN, false) -#define TFT_DC_INIT pinMode(TFT_DC_PIN, OUTPUT); TFT_DC_DATA - -// Reset line is optional - must be tied high if not used -#ifdef TFT_RESET_PIN -#define TFT_RST_ACTIVE digitalWrite(TFT_RESET_PIN, false) -#define TFT_RST_DEACTIVE digitalWrite(TFT_RESET_PIN, true) -#define TFT_RST_INIT pinMode(TFT_RESET_PIN, OUTPUT); TFT_RST_DEACTIVE -#else -#define TFT_RST_ACTIVE -#define TFT_RST_DEACTIVE -#define TFT_RST_INIT -#endif - - -// Constructor when using software SPI. All output pins are configurable. -Adafruit_ILI9341::Adafruit_ILI9341() : Adafruit_GFX(ILI9341_TFTWIDTH, ILI9341_TFTHEIGHT) { - tabcolor = 0; -} - -void Adafruit_ILI9341::transmitCmdData(uint8_t cmd, uint8_t *data, uint8_t numDataByte) -{ - TFT_DC_COMMAND; - TFT_CS_ACTIVE; - SPI.transfer(cmd); - TFT_CS_DEACTIVE; - - TFT_DC_DATA; - TFT_CS_ACTIVE; - SPI.transfer(data, numDataByte); - TFT_CS_DEACTIVE; -} - -void Adafruit_ILI9341::transmitData(uint16_t data) -{ - TFT_CS_ACTIVE; - SPI.transfer((uint8_t*)&data, 2); - TFT_CS_DEACTIVE; -} - -void Adafruit_ILI9341::transmitCmdData(uint8_t cmd, uint32_t data) -{ - TFT_DC_COMMAND; - - TFT_CS_ACTIVE; - SPI.transfer(cmd); - TFT_CS_DEACTIVE; - - TFT_DC_DATA; - TFT_CS_ACTIVE; - SPI.transfer32(data); - TFT_CS_DEACTIVE; -} - -void Adafruit_ILI9341::transmitData(uint16_t data, int32_t repeats) -{ - TFT_CS_ACTIVE; - while(repeats--) { - SPI.transfer16(data); - } - TFT_CS_DEACTIVE; -} - -void Adafruit_ILI9341::transmitCmd(uint8_t cmd) -{ - TFT_DC_COMMAND; - TFT_CS_ACTIVE; - SPI.transfer(cmd); - TFT_CS_DEACTIVE; - TFT_DC_DATA; -} - -#define DELAY 0x80 - -//Set communication using HW SPI Port -void Adafruit_ILI9341::begin(void) { - SPI.SPIDefaultSettings = SPISettings(20000000, LSBFIRST, SPI_MODE0); - SPI.begin(); - TFT_DC_INIT; - TFT_RST_INIT; - TFT_CS_INIT; - - TFT_RST_ACTIVE; - delayMicroseconds(10000); - TFT_RST_DEACTIVE; - delayMicroseconds(1000); - - uint8_t data[15] = {0}; - - data[0] = 0x39; - data[1] = 0x2C; - data[2] = 0x00; - data[3] = 0x34; - data[4] = 0x02; - transmitCmdData(0xCB, data, 5); - - data[0] = 0x00; - data[1] = 0XC1; - data[2] = 0X30; - transmitCmdData(0xCF, data, 3); - - data[0] = 0x85; - data[1] = 0x00; - data[2] = 0x78; - transmitCmdData(0xE8, data, 3); - - data[0] = 0x00; - data[1] = 0x00; - transmitCmdData(0xEA, data, 2); - - data[0] = 0x64; - data[1] = 0x03; - data[2] = 0X12; - data[3] = 0X81; - transmitCmdData(0xED, data, 4); - - data[0] = 0x20; - transmitCmdData(0xF7, data, 1); - - data[0] = 0x23; //VRH[5:0] - transmitCmdData(0xC0, data, 1); //Power control - - data[0] = 0x10; //SAP[2:0];BT[3:0] - transmitCmdData(0xC1, data, 1); //Power control - - data[0] = 0x3e; //Contrast - data[1] = 0x28; - transmitCmdData(0xC5, data, 2); //VCM control - - data[0] = 0x86; //-- - transmitCmdData(0xC7, data, 1); //VCM control2 - - data[0] = 0x48; //C8 - - //This command works with ili9341 - //transmitCmdData(0x36, data, 1); // Memory Access Control - - //This commands works with ili9341-9340-9340c - transmitCmdData(0x40, data, 1); - transmitCmdData(0x08, data, 1); - - data[0] = 0x55; - transmitCmdData(0x3A, data, 1); - - data[0] = 0x00; - data[1] = 0x18; - transmitCmdData(0xB1, data, 2); - - data[0] = 0x08; - data[1] = 0x82; - data[2] = 0x27; - transmitCmdData(0xB6, data, 3); // Display Function Control - - data[0] = 0x00; - transmitCmdData(0xF2, data, 1); // 3Gamma Function Disable - - data[0] = 0x01; - transmitCmdData(0x26, data, 1); //Gamma curve selected - - data[0] = 0x0F; - data[1] = 0x31; - data[2] = 0x2B; - data[3] = 0x0C; - data[4] = 0x0E; - data[5] = 0x08; - data[6] = 0x4E; - data[7] = 0xF1; - data[8] = 0x37; - data[9] = 0x07; - data[10] = 0x10; - data[11] = 0x03; - data[12] = 0x0E; - data[13] = 0x09; - data[14] = 0x00; - transmitCmdData(0xE0, data, 15); //Set Gamma - - data[0] = 0x00; - data[1] = 0x0E; - data[2] = 0x14; - data[3] = 0x03; - data[4] = 0x11; - data[5] = 0x07; - data[6] = 0x31; - data[7] = 0xC1; - data[8] = 0x48; - data[9] = 0x08; - data[10] = 0x0F; - data[11] = 0x0C; - data[12] = 0x31; - data[13] = 0x36; - data[14] = 0x0F; - transmitCmdData(0xE1, data, 15); //Set Gamma - - transmitCmd(0x11); //Exit Sleep - delayMicroseconds(120000); - - transmitCmd(0x29); //Display on - transmitCmd(0x2c); -} - -void Adafruit_ILI9341::drawPixel(int16_t x, int16_t y, uint16_t color) { - - if((x < 0) ||(x >= _width) || (y < 0) || (y >= _height)) return; - setAddrWindow(x,y,x+1,y+1); - transmitData(SWAPBYTES(color)); -} - -void Adafruit_ILI9341::pushColor(uint16_t color) { - transmitData(SWAPBYTES(color)); -} - - -void Adafruit_ILI9341::drawFastVLine(int16_t x, int16_t y, int16_t h, - uint16_t color) { - - // Rudimentary clipping - if((x >= _width) || (y >= _height)) return; - - if((y+h-1) >= _height) - h = _height-y; - - setAddrWindow(x, y, x, y+h-1); - transmitData(SWAPBYTES(color), h); -} - -void Adafruit_ILI9341::drawFastHLine(int16_t x, int16_t y, int16_t w, - uint16_t color) { - - // Rudimentary clipping - if((x >= _width) || (y >= _height)) return; - if((x+w-1) >= _width) w = _width-x; - setAddrWindow(x, y, x+w-1, y); - transmitData(SWAPBYTES(color), w); -} - -void Adafruit_ILI9341::fillScreen(uint16_t color) { - fillRect(0, 0, _width, _height, color); -} - -// fill a rectangle -void Adafruit_ILI9341::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, - uint16_t color) { - - // rudimentary clipping (drawChar w/big text requires this) - if((x >= _width) || (y >= _height)) return; - if((x + w - 1) >= _width) w = _width - x; - if((y + h - 1) >= _height) h = _height - y; - - setAddrWindow(x, y, x+w-1, y+h-1); - transmitData(SWAPBYTES(color), h*w); -} - - - -// Pass 8-bit (each) R,G,B, get back 16-bit packed color -uint16_t Adafruit_ILI9341::color565(uint8_t r, uint8_t g, uint8_t b) { - return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3); -} - -#define MADCTL_MY 0x80 -#define MADCTL_MX 0x40 -#define MADCTL_MV 0x20 -#define MADCTL_ML 0x10 -#define MADCTL_RGB 0x00 -#define MADCTL_BGR 0x08 -#define MADCTL_MH 0x04 - -void Adafruit_ILI9341::setRotation(uint8_t m) { - - uint8_t data; - rotation = m % 4; // can't be higher than 3 - switch (rotation) { - case 0: - data = MADCTL_MX | MADCTL_BGR; - _width = ILI9341_TFTWIDTH; - _height = ILI9341_TFTHEIGHT; - break; - case 1: - data = MADCTL_MV | MADCTL_BGR; - _width = ILI9341_TFTHEIGHT; - _height = ILI9341_TFTWIDTH; - break; - case 2: - data = MADCTL_MY | MADCTL_BGR; - _width = ILI9341_TFTWIDTH; - _height = ILI9341_TFTHEIGHT; - break; - case 3: - data = MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_BGR; - _width = ILI9341_TFTHEIGHT; - _height = ILI9341_TFTWIDTH; - break; - } - transmitCmdData(ILI9341_MADCTL, &data, 1); -} - - -void Adafruit_ILI9341::invertDisplay(bool i) { - transmitCmd(i ? ILI9341_INVON : ILI9341_INVOFF); -} diff --git a/Sming/Libraries/Adafruit_ILI9341/Adafruit_ILI9341.h b/Sming/Libraries/Adafruit_ILI9341/Adafruit_ILI9341.h deleted file mode 100644 index cb41c2a2f8..0000000000 --- a/Sming/Libraries/Adafruit_ILI9341/Adafruit_ILI9341.h +++ /dev/null @@ -1,141 +0,0 @@ -/*************************************************** - This is our library for the Adafruit ILI9341 Breakout and Shield - ----> http://www.adafruit.com/products/1651 - - Check out the links above for our tutorials and wiring diagrams - These displays use SPI to communicate, 4 or 5 pins are required to - interface (RST is optional) - Adafruit invests time and resources providing this open source code, - please support Adafruit and open-source hardware by purchasing - products from Adafruit! - - Written by Limor Fried/Ladyada for Adafruit Industries. - MIT license, all text above must be included in any redistribution - ****************************************************/ -/******************************** - * ported for Sming by M.Bozkurt. - * alonewolf07@gmail.com - ********************************/ - -#ifndef _ADAFRUIT_ILI9341H_ -#define _ADAFRUIT_ILI9341H_ - -#include -#include - -#define ILI9341_TFTWIDTH 240 -#define ILI9341_TFTHEIGHT 320 - -#define ILI9341_NOP 0x00 -#define ILI9341_SWRESET 0x01 -#define ILI9341_RDDID 0x04 -#define ILI9341_RDDST 0x09 - -#define ILI9341_SLPIN 0x10 -#define ILI9341_SLPOUT 0x11 -#define ILI9341_PTLON 0x12 -#define ILI9341_NORON 0x13 - -#define ILI9341_RDMODE 0x0A -#define ILI9341_RDMADCTL 0x0B -#define ILI9341_RDPIXFMT 0x0C -#define ILI9341_RDIMGFMT 0x0A -#define ILI9341_RDSELFDIAG 0x0F - -#define ILI9341_INVOFF 0x20 -#define ILI9341_INVON 0x21 -#define ILI9341_GAMMASET 0x26 -#define ILI9341_DISPOFF 0x28 -#define ILI9341_DISPON 0x29 - -#define ILI9341_CASET 0x2A -#define ILI9341_PASET 0x2B -#define ILI9341_RAMWR 0x2C -#define ILI9341_RAMRD 0x2E - -#define ILI9341_PTLAR 0x30 -#define ILI9341_MADCTL 0x36 -#define ILI9341_PIXFMT 0x3A - -#define ILI9341_FRMCTR1 0xB1 -#define ILI9341_FRMCTR2 0xB2 -#define ILI9341_FRMCTR3 0xB3 -#define ILI9341_INVCTR 0xB4 -#define ILI9341_DFUNCTR 0xB6 - -#define ILI9341_PWCTR1 0xC0 -#define ILI9341_PWCTR2 0xC1 -#define ILI9341_PWCTR3 0xC2 -#define ILI9341_PWCTR4 0xC3 -#define ILI9341_PWCTR5 0xC4 -#define ILI9341_VMCTR1 0xC5 -#define ILI9341_VMCTR2 0xC7 - -#define ILI9341_RDID1 0xDA -#define ILI9341_RDID2 0xDB -#define ILI9341_RDID3 0xDC -#define ILI9341_RDID4 0xDD - -#define ILI9341_GMCTRP1 0xE0 -#define ILI9341_GMCTRN1 0xE1 -/* -#define ILI9341_PWCTR6 0xFC - -*/ - -// Color definitions -#define ILI9341_BLACK 0x0000 /* 0, 0, 0 */ -#define ILI9341_NAVY 0x000F /* 0, 0, 128 */ -#define ILI9341_DARKGREEN 0x03E0 /* 0, 128, 0 */ -#define ILI9341_DARKCYAN 0x03EF /* 0, 128, 128 */ -#define ILI9341_MAROON 0x7800 /* 128, 0, 0 */ -#define ILI9341_PURPLE 0x780F /* 128, 0, 128 */ -#define ILI9341_OLIVE 0x7BE0 /* 128, 128, 0 */ -#define ILI9341_LIGHTGREY 0xC618 /* 192, 192, 192 */ -#define ILI9341_DARKGREY 0x7BEF /* 128, 128, 128 */ -#define ILI9341_BLUE 0x001F /* 0, 0, 255 */ -#define ILI9341_GREEN 0x07E0 /* 0, 255, 0 */ -#define ILI9341_CYAN 0x07FF /* 0, 255, 255 */ -#define ILI9341_RED 0xF800 /* 255, 0, 0 */ -#define ILI9341_MAGENTA 0xF81F /* 255, 0, 255 */ -#define ILI9341_YELLOW 0xFFE0 /* 255, 255, 0 */ -#define ILI9341_WHITE 0xFFFF /* 255, 255, 255 */ -#define ILI9341_ORANGE 0xFD20 /* 255, 165, 0 */ -#define ILI9341_GREENYELLOW 0xAFE5 /* 173, 255, 47 */ -#define ILI9341_PINK 0xF81F - -#define MAKEWORD(b1, b2, b3, b4) (uint32_t(b1) | ((b2) << 8) | ((b3) << 16) | ((b4) << 24)) - - -class Adafruit_ILI9341 : public Adafruit_GFX { - -private: - uint8_t tabcolor; - void transmitCmdData(uint8_t cmd, uint8_t *data, uint8_t numDataByte); - void transmitData(uint16_t data); - void transmitCmdData(uint8_t cmd, uint32_t data); - void transmitData(uint16_t data, int32_t repeats); - void transmitCmd(uint8_t cmd); - -public: - Adafruit_ILI9341(); - - void begin(void), - fillScreen(uint16_t color), - pushColor(uint16_t color), - drawPixel(int16_t x, int16_t y, uint16_t color), - drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color), - drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color), - fillRect(int16_t x, int16_t y, int16_t w, int16_t h, - uint16_t color), - setRotation(uint8_t r), - invertDisplay(bool i); - inline void setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) - { transmitCmdData(ILI9341_CASET, MAKEWORD(x0 >> 8, x0 & 0xFF, x1 >> 8, x1 & 0xFF)); - transmitCmdData(ILI9341_PASET, MAKEWORD(y0 >> 8, y0 & 0xFF, y1 >> 8, y1 & 0xFF)); - transmitCmd(ILI9341_RAMWR); // write to RAM - } - uint16_t color565(uint8_t r, uint8_t g, uint8_t b); -}; - -#endif diff --git a/Sming/Libraries/Adafruit_ILI9341/README.rst b/Sming/Libraries/Adafruit_ILI9341/README.rst deleted file mode 100644 index d4c476230e..0000000000 --- a/Sming/Libraries/Adafruit_ILI9341/README.rst +++ /dev/null @@ -1,35 +0,0 @@ -Adafruit ILI9341 Display -======================== - -This is a Sming port of the library for the Adafruit ILI9341 display products. - -This library works with the Adafruit 2.8" Touch Shield V2 (SPI) -http://www.adafruit.com/products/1651 - -Check out the links above for our tutorials and wiring diagrams. -These displays use SPI to communicate, 4 or 5 pins are required -to interface (RST is optional). - -Adafruit invests time and resources providing this open source code, -please support Adafruit and open-source hardware by purchasing -products from Adafruit! - -Written by Limor Fried/Ladyada for Adafruit Industries. -MIT license, all text above must be included in any redistribution - - -Configuration variables ------------------------ - - -.. envvar:: TFT_CS_PIN - - Pin to use for SPI CS (Chip Select). Active low. - -.. envvar:: TFT_DC_PIN - - Pin for controlling DC (Data / Command) line - -.. envvar:: TFT_RESET_PIN - - Pin for resetting the display. Optional. diff --git a/Sming/Libraries/Adafruit_ILI9341/component.mk b/Sming/Libraries/Adafruit_ILI9341/component.mk deleted file mode 100644 index 91e2591dae..0000000000 --- a/Sming/Libraries/Adafruit_ILI9341/component.mk +++ /dev/null @@ -1,22 +0,0 @@ -COMPONENT_DEPENDS := Adafruit_GFX - -COMPONENT_RELINK_VARS := TFT_CS_PIN TFT_DC_PIN TFT_RESET_PIN - -ifeq ($(SMING_ARCH),Esp8266) -TFT_CS_PIN ?= 15 -TFT_DC_PIN ?= 5 -TFT_RESET_PIN ?= 4 -else ifeq ($(SMING_ARCH),Esp32) -TFT_CS_PIN ?= 18 -TFT_DC_PIN ?= 19 -TFT_RESET_PIN ?= 21 -else ifndef MAKE_DOCS -$(warning Arch unsupported) -endif - -COMPONENT_CXXFLAGS += -DTFT_CS_PIN=$(TFT_CS_PIN) -DTFT_DC_PIN=$(TFT_DC_PIN) - -# Reset pin is optional -ifdef TFT_RESET_PIN -COMPONENT_CXXFLAGS += -DTFT_RESET_PIN=$(TFT_RESET_PIN) -endif diff --git a/Sming/Libraries/Adafruit_ILI9341/examples/breakouttouchpaint/breakouttouchpaint.ino b/Sming/Libraries/Adafruit_ILI9341/examples/breakouttouchpaint/breakouttouchpaint.ino deleted file mode 100644 index 298bcad6b3..0000000000 --- a/Sming/Libraries/Adafruit_ILI9341/examples/breakouttouchpaint/breakouttouchpaint.ino +++ /dev/null @@ -1,145 +0,0 @@ -/*************************************************** - This is our touchscreen painting example for the Adafruit ILI9341 Breakout - ----> http://www.adafruit.com/products/1770 - - Check out the links above for our tutorials and wiring diagrams - These displays use SPI to communicate, 4 or 5 pins are required to - interface (RST is optional) - Adafruit invests time and resources providing this open source code, - please support Adafruit and open-source hardware by purchasing - products from Adafruit! - - Written by Limor Fried/Ladyada for Adafruit Industries. - MIT license, all text above must be included in any redistribution - ****************************************************/ - -/** NOT FOR USE WITH THE TOUCH SHIELD, ONLY FOR THE BREAKOUT! **/ - -#include // Core graphics library -#include -#include -#include "TouchScreen.h" - -// These are the four touchscreen analog pins -#define YP A2 // must be an analog pin, use "An" notation! -#define XM A3 // must be an analog pin, use "An" notation! -#define YM 5 // can be a digital pin -#define XP 4 // can be a digital pin - -// This is calibration data for the raw touch data to the screen coordinates -#define TS_MINX 150 -#define TS_MINY 120 -#define TS_MAXX 920 -#define TS_MAXY 940 - -#define MINPRESSURE 10 -#define MAXPRESSURE 1000 - -// The display uses hardware SPI, plus #9 & #10 -#define TFT_CS 10 -#define TFT_DC 9 -Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); - -// For better pressure precision, we need to know the resistance -// between X+ and X- Use any multimeter to read it -// For the one we're using, its 300 ohms across the X plate -TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300); - -// Size of the color selection boxes and the paintbrush size -#define BOXSIZE 40 -#define PENRADIUS 3 -int oldcolor, currentcolor; - -void setup(void) { - // while (!Serial); // used for leonardo debugging - - Serial.begin(9600); - Serial.println(F("Touch Paint!")); - - tft.begin(); - tft.fillScreen(ILI9341_BLACK); - - // make the color selection boxes - tft.fillRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_RED); - tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_YELLOW); - tft.fillRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_GREEN); - tft.fillRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_CYAN); - tft.fillRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_BLUE); - tft.fillRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_MAGENTA); - - // select the current color 'red' - tft.drawRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); - currentcolor = ILI9341_RED; -} - - -void loop() -{ - // Retrieve a point - TSPoint p = ts.getPoint(); - - /* - Serial.print("X = "); Serial.print(p.x); - Serial.print("\tY = "); Serial.print(p.y); - Serial.print("\tPressure = "); Serial.println(p.z); - */ - - // we have some minimum pressure we consider 'valid' - // pressure of 0 means no pressing! - if (p.z < MINPRESSURE || p.z > MAXPRESSURE) { - return; - } - - // Scale from ~0->1000 to tft.width using the calibration #'s - p.x = map(p.x, TS_MINX, TS_MAXX, 0, tft.width()); - p.y = map(p.y, TS_MINY, TS_MAXY, 0, tft.height()); - - /* - Serial.print("("); Serial.print(p.x); - Serial.print(", "); Serial.print(p.y); - Serial.println(")"); - */ - - - if (p.y < BOXSIZE) { - oldcolor = currentcolor; - - if (p.x < BOXSIZE) { - currentcolor = ILI9341_RED; - tft.drawRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); - } else if (p.x < BOXSIZE*2) { - currentcolor = ILI9341_YELLOW; - tft.drawRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); - } else if (p.x < BOXSIZE*3) { - currentcolor = ILI9341_GREEN; - tft.drawRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); - } else if (p.x < BOXSIZE*4) { - currentcolor = ILI9341_CYAN; - tft.drawRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); - } else if (p.x < BOXSIZE*5) { - currentcolor = ILI9341_BLUE; - tft.drawRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); - } else if (p.x < BOXSIZE*6) { - currentcolor = ILI9341_MAGENTA; - tft.drawRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); - } - - if (oldcolor != currentcolor) { - if (oldcolor == ILI9341_RED) - tft.fillRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_RED); - if (oldcolor == ILI9341_YELLOW) - tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_YELLOW); - if (oldcolor == ILI9341_GREEN) - tft.fillRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_GREEN); - if (oldcolor == ILI9341_CYAN) - tft.fillRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_CYAN); - if (oldcolor == ILI9341_BLUE) - tft.fillRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_BLUE); - if (oldcolor == ILI9341_MAGENTA) - tft.fillRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_MAGENTA); - } - } - if (((p.y-PENRADIUS) > BOXSIZE) && ((p.y+PENRADIUS) < tft.height())) { - tft.fillCircle(p.x, p.y, PENRADIUS, currentcolor); - } -} diff --git a/Sming/Libraries/Adafruit_ILI9341/examples/graphicstest/graphicstest.ino b/Sming/Libraries/Adafruit_ILI9341/examples/graphicstest/graphicstest.ino deleted file mode 100644 index 07ec02fb49..0000000000 --- a/Sming/Libraries/Adafruit_ILI9341/examples/graphicstest/graphicstest.ino +++ /dev/null @@ -1,349 +0,0 @@ -/*************************************************** - This is our GFX example for the Adafruit ILI9341 Breakout and Shield - ----> http://www.adafruit.com/products/1651 - - Check out the links above for our tutorials and wiring diagrams - These displays use SPI to communicate, 4 or 5 pins are required to - interface (RST is optional) - Adafruit invests time and resources providing this open source code, - please support Adafruit and open-source hardware by purchasing - products from Adafruit! - - Written by Limor Fried/Ladyada for Adafruit Industries. - MIT license, all text above must be included in any redistribution - ****************************************************/ - - -#include "SPI.h" -#include "Adafruit_GFX.h" -#include "Adafruit_ILI9341.h" - -// For the Adafruit shield, these are the default. -#define TFT_DC 9 -#define TFT_CS 10 - -// Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC -Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); -// If using the breakout, change pins as desired -//Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO); - -void setup() { - Serial.begin(9600); - Serial.println("ILI9341 Test!"); - - tft.begin(); - - // read diagnostics (optional but can help debug problems) - uint8_t x = tft.readcommand8(ILI9341_RDMODE); - Serial.print("Display Power Mode: 0x"); Serial.println(x, HEX); - x = tft.readcommand8(ILI9341_RDMADCTL); - Serial.print("MADCTL Mode: 0x"); Serial.println(x, HEX); - x = tft.readcommand8(ILI9341_RDPIXFMT); - Serial.print("Pixel Format: 0x"); Serial.println(x, HEX); - x = tft.readcommand8(ILI9341_RDIMGFMT); - Serial.print("Image Format: 0x"); Serial.println(x, HEX); - x = tft.readcommand8(ILI9341_RDSELFDIAG); - Serial.print("Self Diagnostic: 0x"); Serial.println(x, HEX); - - Serial.println(F("Benchmark Time (microseconds)")); - - Serial.print(F("Screen fill ")); - Serial.println(testFillScreen()); - delay(500); - - Serial.print(F("Text ")); - Serial.println(testText()); - delay(3000); - - Serial.print(F("Lines ")); - Serial.println(testLines(ILI9341_CYAN)); - delay(500); - - Serial.print(F("Horiz/Vert Lines ")); - Serial.println(testFastLines(ILI9341_RED, ILI9341_BLUE)); - delay(500); - - Serial.print(F("Rectangles (outline) ")); - Serial.println(testRects(ILI9341_GREEN)); - delay(500); - - Serial.print(F("Rectangles (filled) ")); - Serial.println(testFilledRects(ILI9341_YELLOW, ILI9341_MAGENTA)); - delay(500); - - Serial.print(F("Circles (filled) ")); - Serial.println(testFilledCircles(10, ILI9341_MAGENTA)); - - Serial.print(F("Circles (outline) ")); - Serial.println(testCircles(10, ILI9341_WHITE)); - delay(500); - - Serial.print(F("Triangles (outline) ")); - Serial.println(testTriangles()); - delay(500); - - Serial.print(F("Triangles (filled) ")); - Serial.println(testFilledTriangles()); - delay(500); - - Serial.print(F("Rounded rects (outline) ")); - Serial.println(testRoundRects()); - delay(500); - - Serial.print(F("Rounded rects (filled) ")); - Serial.println(testFilledRoundRects()); - delay(500); - - Serial.println(F("Done!")); - -} - - -void loop(void) { - for(uint8_t rotation=0; rotation<4; rotation++) { - tft.setRotation(rotation); - testText(); - delay(1000); - } -} - -unsigned long testFillScreen() { - unsigned long start = micros(); - tft.fillScreen(ILI9341_BLACK); - tft.fillScreen(ILI9341_RED); - tft.fillScreen(ILI9341_GREEN); - tft.fillScreen(ILI9341_BLUE); - tft.fillScreen(ILI9341_BLACK); - return micros() - start; -} - -unsigned long testText() { - tft.fillScreen(ILI9341_BLACK); - unsigned long start = micros(); - tft.setCursor(0, 0); - tft.setTextColor(ILI9341_WHITE); tft.setTextSize(1); - tft.println("Hello World!"); - tft.setTextColor(ILI9341_YELLOW); tft.setTextSize(2); - tft.println(1234.56); - tft.setTextColor(ILI9341_RED); tft.setTextSize(3); - tft.println(0xDEADBEEF, HEX); - tft.println(); - tft.setTextColor(ILI9341_GREEN); - tft.setTextSize(5); - tft.println("Groop"); - tft.setTextSize(2); - tft.println("I implore thee,"); - tft.setTextSize(1); - tft.println("my foonting turlingdromes."); - tft.println("And hooptiously drangle me"); - tft.println("with crinkly bindlewurdles,"); - tft.println("Or I will rend thee"); - tft.println("in the gobberwarts"); - tft.println("with my blurglecruncheon,"); - tft.println("see if I don't!"); - return micros() - start; -} - -unsigned long testLines(uint16_t color) { - unsigned long start, t; - int x1, y1, x2, y2, - w = tft.width(), - h = tft.height(); - - tft.fillScreen(ILI9341_BLACK); - - x1 = y1 = 0; - y2 = h - 1; - start = micros(); - for(x2=0; x20; i-=6) { - i2 = i / 2; - start = micros(); - tft.fillRect(cx-i2, cy-i2, i, i, color1); - t += micros() - start; - // Outlines are not included in timing results - tft.drawRect(cx-i2, cy-i2, i, i, color2); - } - - return t; -} - -unsigned long testFilledCircles(uint8_t radius, uint16_t color) { - unsigned long start; - int x, y, w = tft.width(), h = tft.height(), r2 = radius * 2; - - tft.fillScreen(ILI9341_BLACK); - start = micros(); - for(x=radius; x10; i-=5) { - start = micros(); - tft.fillTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i, - tft.color565(0, i, i)); - t += micros() - start; - tft.drawTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i, - tft.color565(i, i, 0)); - } - - return t; -} - -unsigned long testRoundRects() { - unsigned long start; - int w, i, i2, - cx = tft.width() / 2 - 1, - cy = tft.height() / 2 - 1; - - tft.fillScreen(ILI9341_BLACK); - w = min(tft.width(), tft.height()); - start = micros(); - for(i=0; i20; i-=6) { - i2 = i / 2; - tft.fillRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(0, i, 0)); - } - - return micros() - start; -} \ No newline at end of file diff --git a/Sming/Libraries/Adafruit_ILI9341/examples/onoffbutton/onoffbutton.ino b/Sming/Libraries/Adafruit_ILI9341/examples/onoffbutton/onoffbutton.ino deleted file mode 100644 index 3365d3385d..0000000000 --- a/Sming/Libraries/Adafruit_ILI9341/examples/onoffbutton/onoffbutton.ino +++ /dev/null @@ -1,125 +0,0 @@ -//This example implements a simple sliding On/Off button. The example -// demonstrates drawing and touch operations. -// -//Thanks to Adafruit forums member Asteroid for the original sketch! -// -#include -#include -#include -#include -#include - -// This is calibration data for the raw touch data to the screen coordinates -#define TS_MINX 150 -#define TS_MINY 130 -#define TS_MAXX 3800 -#define TS_MAXY 4000 - -#define STMPE_CS 8 -Adafruit_STMPE610 ts = Adafruit_STMPE610(STMPE_CS); -#define TFT_CS 10 -#define TFT_DC 9 -Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); - -boolean RecordOn = false; - -#define FRAME_X 210 -#define FRAME_Y 180 -#define FRAME_W 100 -#define FRAME_H 50 - -#define REDBUTTON_X FRAME_X -#define REDBUTTON_Y FRAME_Y -#define REDBUTTON_W (FRAME_W/2) -#define REDBUTTON_H FRAME_H - -#define GREENBUTTON_X (REDBUTTON_X + REDBUTTON_W) -#define GREENBUTTON_Y FRAME_Y -#define GREENBUTTON_W (FRAME_W/2) -#define GREENBUTTON_H FRAME_H - -void drawFrame() -{ - tft.drawRect(FRAME_X, FRAME_Y, FRAME_W, FRAME_H, ILI9341_BLACK); -} - -void redBtn() -{ - tft.fillRect(REDBUTTON_X, REDBUTTON_Y, REDBUTTON_W, REDBUTTON_H, ILI9341_RED); - tft.fillRect(GREENBUTTON_X, GREENBUTTON_Y, GREENBUTTON_W, GREENBUTTON_H, ILI9341_BLUE); - drawFrame(); - tft.setCursor(GREENBUTTON_X + 6 , GREENBUTTON_Y + (GREENBUTTON_H/2)); - tft.setTextColor(ILI9341_WHITE); - tft.setTextSize(2); - tft.println("ON"); - RecordOn = false; -} - -void greenBtn() -{ - tft.fillRect(GREENBUTTON_X, GREENBUTTON_Y, GREENBUTTON_W, GREENBUTTON_H, ILI9341_GREEN); - tft.fillRect(REDBUTTON_X, REDBUTTON_Y, REDBUTTON_W, REDBUTTON_H, ILI9341_BLUE); - drawFrame(); - tft.setCursor(REDBUTTON_X + 6 , REDBUTTON_Y + (REDBUTTON_H/2)); - tft.setTextColor(ILI9341_WHITE); - tft.setTextSize(2); - tft.println("OFF"); - RecordOn = true; -} - -void setup(void) -{ - Serial.begin(9600); - tft.begin(); - if (!ts.begin()) { - Serial.println("Unable to start touchscreen."); - } - else { - Serial.println("Touchscreen started."); - } - - tft.fillScreen(ILI9341_BLUE); - // origin = left,top landscape (USB left upper) - tft.setRotation(1); - redBtn(); -} - -void loop() -{ - // See if there's any touch data for us - if (!ts.bufferEmpty()) - { - // Retrieve a point - TS_Point p = ts.getPoint(); - // Scale using the calibration #'s - // and rotate coordinate system - p.x = map(p.x, TS_MINY, TS_MAXY, 0, tft.height()); - p.y = map(p.y, TS_MINX, TS_MAXX, 0, tft.width()); - int y = tft.height() - p.x; - int x = p.y; - - if (RecordOn) - { - if((x > REDBUTTON_X) && (x < (REDBUTTON_X + REDBUTTON_W))) { - if ((y > REDBUTTON_Y) && (y <= (REDBUTTON_Y + REDBUTTON_H))) { - Serial.println("Red btn hit"); - redBtn(); - } - } - } - else //Record is off (RecordOn == false) - { - if((x > GREENBUTTON_X) && (x < (GREENBUTTON_X + GREENBUTTON_W))) { - if ((y > GREENBUTTON_Y) && (y <= (GREENBUTTON_Y + GREENBUTTON_H))) { - Serial.println("Green btn hit"); - greenBtn(); - } - } - } - - Serial.println(RecordOn); - } -} - - - diff --git a/Sming/Libraries/Adafruit_ILI9341/examples/onoffbutton_breakout/onoffbutton_breakout.ino b/Sming/Libraries/Adafruit_ILI9341/examples/onoffbutton_breakout/onoffbutton_breakout.ino deleted file mode 100644 index aa8cb9992f..0000000000 --- a/Sming/Libraries/Adafruit_ILI9341/examples/onoffbutton_breakout/onoffbutton_breakout.ino +++ /dev/null @@ -1,133 +0,0 @@ -//This example implements a simple sliding On/Off button. The example -// demonstrates drawing and touch operations. -// -//Thanks to Adafruit forums member Asteroid for the original sketch! -// -#include -#include -#include -#include -#include - -//Touchscreen X+ X- Y+ Y- pins -#define YP A3 // must be an analog pin, use "An" notation! -#define XM A2 // must be an analog pin, use "An" notation! -#define YM 5 // can be a digital pin -#define XP 4 // can be a digital pin - -// This is calibration data for the raw touch data to the screen coordinates -#define TS_MINX 150 -#define TS_MINY 120 -#define TS_MAXX 920 -#define TS_MAXY 940 - -#define MINPRESSURE 10 -#define MAXPRESSURE 1000 - -// For better pressure precision, we need to know the resistance -// between X+ and X- Use any multimeter to read it -// For the one we're using, its 300 ohms across the X plate -TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300); - - -#define TFT_CS 10 -#define TFT_DC 9 -Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); - -boolean RecordOn = false; - -#define FRAME_X 210 -#define FRAME_Y 180 -#define FRAME_W 100 -#define FRAME_H 50 - -#define REDBUTTON_X FRAME_X -#define REDBUTTON_Y FRAME_Y -#define REDBUTTON_W (FRAME_W/2) -#define REDBUTTON_H FRAME_H - -#define GREENBUTTON_X (REDBUTTON_X + REDBUTTON_W) -#define GREENBUTTON_Y FRAME_Y -#define GREENBUTTON_W (FRAME_W/2) -#define GREENBUTTON_H FRAME_H - -void drawFrame() -{ - tft.drawRect(FRAME_X, FRAME_Y, FRAME_W, FRAME_H, ILI9341_BLACK); -} - -void redBtn() -{ - tft.fillRect(REDBUTTON_X, REDBUTTON_Y, REDBUTTON_W, REDBUTTON_H, ILI9341_RED); - tft.fillRect(GREENBUTTON_X, GREENBUTTON_Y, GREENBUTTON_W, GREENBUTTON_H, ILI9341_BLUE); - drawFrame(); - tft.setCursor(GREENBUTTON_X + 6 , GREENBUTTON_Y + (GREENBUTTON_H/2)); - tft.setTextColor(ILI9341_WHITE); - tft.setTextSize(2); - tft.println("ON"); - RecordOn = false; -} - -void greenBtn() -{ - tft.fillRect(GREENBUTTON_X, GREENBUTTON_Y, GREENBUTTON_W, GREENBUTTON_H, ILI9341_GREEN); - tft.fillRect(REDBUTTON_X, REDBUTTON_Y, REDBUTTON_W, REDBUTTON_H, ILI9341_BLUE); - drawFrame(); - tft.setCursor(REDBUTTON_X + 6 , REDBUTTON_Y + (REDBUTTON_H/2)); - tft.setTextColor(ILI9341_WHITE); - tft.setTextSize(2); - tft.println("OFF"); - RecordOn = true; -} - -void setup(void) -{ - Serial.begin(9600); - tft.begin(); - - tft.fillScreen(ILI9341_BLUE); - // origin = left,top landscape (USB left upper) - tft.setRotation(1); - redBtn(); -} - -void loop() -{ - // Retrieve a point - TSPoint p = ts.getPoint(); - - // See if there's any touch data for us - if (p.z > MINPRESSURE && p.z < MAXPRESSURE) - { - // Scale using the calibration #'s - // and rotate coordinate system - p.x = map(p.x, TS_MINY, TS_MAXY, 0, tft.height()); - p.y = map(p.y, TS_MINX, TS_MAXX, 0, tft.width()); - int y = tft.height() - p.x; - int x = p.y; - - if (RecordOn) - { - if((x > REDBUTTON_X) && (x < (REDBUTTON_X + REDBUTTON_W))) { - if ((y > REDBUTTON_Y) && (y <= (REDBUTTON_Y + REDBUTTON_H))) { - Serial.println("Red btn hit"); - redBtn(); - } - } - } - else //Record is off (RecordOn == false) - { - if((x > GREENBUTTON_X) && (x < (GREENBUTTON_X + GREENBUTTON_W))) { - if ((y > GREENBUTTON_Y) && (y <= (GREENBUTTON_Y + GREENBUTTON_H))) { - Serial.println("Green btn hit"); - greenBtn(); - } - } - } - - Serial.println(RecordOn); - } -} - - - diff --git a/Sming/Libraries/Adafruit_ILI9341/examples/spitftbitmap/spitftbitmap.ino b/Sming/Libraries/Adafruit_ILI9341/examples/spitftbitmap/spitftbitmap.ino deleted file mode 100644 index f87d6f7e75..0000000000 --- a/Sming/Libraries/Adafruit_ILI9341/examples/spitftbitmap/spitftbitmap.ino +++ /dev/null @@ -1,189 +0,0 @@ -/*************************************************** - This is our Bitmap drawing example for the Adafruit ILI9341 Breakout and Shield - ----> http://www.adafruit.com/products/1651 - - Check out the links above for our tutorials and wiring diagrams - These displays use SPI to communicate, 4 or 5 pins are required to - interface (RST is optional) - Adafruit invests time and resources providing this open source code, - please support Adafruit and open-source hardware by purchasing - products from Adafruit! - - Written by Limor Fried/Ladyada for Adafruit Industries. - MIT license, all text above must be included in any redistribution - ****************************************************/ - - -#include // Core graphics library -#include "Adafruit_ILI9341.h" // Hardware-specific library -#include -#include - -// TFT display and SD card will share the hardware SPI interface. -// Hardware SPI pins are specific to the Arduino board type and -// cannot be remapped to alternate pins. For Arduino Uno, -// Duemilanove, etc., pin 11 = MOSI, pin 12 = MISO, pin 13 = SCK. - -#define TFT_DC 9 -#define TFT_CS 10 -Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); - -#define SD_CS 4 - -void setup(void) { - Serial.begin(9600); - - tft.begin(); - tft.fillScreen(ILI9341_BLUE); - - Serial.print("Initializing SD card..."); - if (!SD.begin(SD_CS)) { - Serial.println("failed!"); - } - Serial.println("OK!"); - - bmpDraw("purple.bmp", 0, 0); -} - -void loop() { -} - -// This function opens a Windows Bitmap (BMP) file and -// displays it at the given coordinates. It's sped up -// by reading many pixels worth of data at a time -// (rather than pixel by pixel). Increasing the buffer -// size takes more of the Arduino's precious RAM but -// makes loading a little faster. 20 pixels seems a -// good balance. - -#define BUFFPIXEL 20 - -void bmpDraw(char *filename, uint8_t x, uint16_t y) { - - File bmpFile; - int bmpWidth, bmpHeight; // W+H in pixels - uint8_t bmpDepth; // Bit depth (currently must be 24) - uint32_t bmpImageoffset; // Start of image data in file - uint32_t rowSize; // Not always = bmpWidth; may have padding - uint8_t sdbuffer[3*BUFFPIXEL]; // pixel buffer (R+G+B per pixel) - uint8_t buffidx = sizeof(sdbuffer); // Current position in sdbuffer - boolean goodBmp = false; // Set to true on valid header parse - boolean flip = true; // BMP is stored bottom-to-top - int w, h, row, col; - uint8_t r, g, b; - uint32_t pos = 0, startTime = millis(); - - if((x >= tft.width()) || (y >= tft.height())) return; - - Serial.println(); - Serial.print(F("Loading image '")); - Serial.print(filename); - Serial.println('\''); - - // Open requested file on SD card - if ((bmpFile = SD.open(filename)) == NULL) { - Serial.print(F("File not found")); - return; - } - - // Parse BMP header - if(read16(bmpFile) == 0x4D42) { // BMP signature - Serial.print(F("File size: ")); Serial.println(read32(bmpFile)); - (void)read32(bmpFile); // Read & ignore creator bytes - bmpImageoffset = read32(bmpFile); // Start of image data - Serial.print(F("Image Offset: ")); Serial.println(bmpImageoffset, DEC); - // Read DIB header - Serial.print(F("Header size: ")); Serial.println(read32(bmpFile)); - bmpWidth = read32(bmpFile); - bmpHeight = read32(bmpFile); - if(read16(bmpFile) == 1) { // # planes -- must be '1' - bmpDepth = read16(bmpFile); // bits per pixel - Serial.print(F("Bit Depth: ")); Serial.println(bmpDepth); - if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed - - goodBmp = true; // Supported BMP format -- proceed! - Serial.print(F("Image size: ")); - Serial.print(bmpWidth); - Serial.print('x'); - Serial.println(bmpHeight); - - // BMP rows are padded (if needed) to 4-byte boundary - rowSize = (bmpWidth * 3 + 3) & ~3; - - // If bmpHeight is negative, image is in top-down order. - // This is not canon but has been observed in the wild. - if(bmpHeight < 0) { - bmpHeight = -bmpHeight; - flip = false; - } - - // Crop area to be loaded - w = bmpWidth; - h = bmpHeight; - if((x+w-1) >= tft.width()) w = tft.width() - x; - if((y+h-1) >= tft.height()) h = tft.height() - y; - - // Set TFT address window to clipped image bounds - tft.setAddrWindow(x, y, x+w-1, y+h-1); - - for (row=0; row= sizeof(sdbuffer)) { // Indeed - bmpFile.read(sdbuffer, sizeof(sdbuffer)); - buffidx = 0; // Set index to beginning - } - - // Convert pixel from BMP to TFT format, push to display - b = sdbuffer[buffidx++]; - g = sdbuffer[buffidx++]; - r = sdbuffer[buffidx++]; - tft.pushColor(tft.color565(r,g,b)); - } // end pixel - } // end scanline - Serial.print(F("Loaded in ")); - Serial.print(millis() - startTime); - Serial.println(" ms"); - } // end goodBmp - } - } - - bmpFile.close(); - if(!goodBmp) Serial.println(F("BMP format not recognized.")); -} - -// These read 16- and 32-bit types from the SD card file. -// BMP data is stored little-endian, Arduino is little-endian too. -// May need to reverse subscript order if porting elsewhere. - -uint16_t read16(File &f) { - uint16_t result; - ((uint8_t *)&result)[0] = f.read(); // LSB - ((uint8_t *)&result)[1] = f.read(); // MSB - return result; -} - -uint32_t read32(File &f) { - uint32_t result; - ((uint8_t *)&result)[0] = f.read(); // LSB - ((uint8_t *)&result)[1] = f.read(); - ((uint8_t *)&result)[2] = f.read(); - ((uint8_t *)&result)[3] = f.read(); // MSB - return result; -} diff --git a/Sming/Libraries/Adafruit_ILI9341/examples/touchpaint/touchpaint.ino b/Sming/Libraries/Adafruit_ILI9341/examples/touchpaint/touchpaint.ino deleted file mode 100644 index 227abdc84d..0000000000 --- a/Sming/Libraries/Adafruit_ILI9341/examples/touchpaint/touchpaint.ino +++ /dev/null @@ -1,146 +0,0 @@ -/*************************************************** - This is our touchscreen painting example for the Adafruit ILI9341 Shield - ----> http://www.adafruit.com/products/1651 - - Check out the links above for our tutorials and wiring diagrams - These displays use SPI to communicate, 4 or 5 pins are required to - interface (RST is optional) - Adafruit invests time and resources providing this open source code, - please support Adafruit and open-source hardware by purchasing - products from Adafruit! - - Written by Limor Fried/Ladyada for Adafruit Industries. - MIT license, all text above must be included in any redistribution - ****************************************************/ - - -#include // Core graphics library -#include -#include // this is needed even tho we aren't using it -#include -#include - -// This is calibration data for the raw touch data to the screen coordinates -#define TS_MINX 150 -#define TS_MINY 130 -#define TS_MAXX 3800 -#define TS_MAXY 4000 - -// The STMPE610 uses hardware SPI on the shield, and #8 -#define STMPE_CS 8 -Adafruit_STMPE610 ts = Adafruit_STMPE610(STMPE_CS); - -// The display also uses hardware SPI, plus #9 & #10 -#define TFT_CS 10 -#define TFT_DC 9 -Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); - -// Size of the color selection boxes and the paintbrush size -#define BOXSIZE 40 -#define PENRADIUS 3 -int oldcolor, currentcolor; - -void setup(void) { - // while (!Serial); // used for leonardo debugging - - Serial.begin(9600); - Serial.println(F("Touch Paint!")); - - tft.begin(); - - if (!ts.begin()) { - Serial.println("Couldn't start touchscreen controller"); - while (1); - } - Serial.println("Touchscreen started"); - - tft.fillScreen(ILI9341_BLACK); - - // make the color selection boxes - tft.fillRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_RED); - tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_YELLOW); - tft.fillRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_GREEN); - tft.fillRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_CYAN); - tft.fillRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_BLUE); - tft.fillRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_MAGENTA); - - // select the current color 'red' - tft.drawRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); - currentcolor = ILI9341_RED; -} - - -void loop() -{ - // See if there's any touch data for us - if (ts.bufferEmpty()) { - return; - } - /* - // You can also wait for a touch - if (! ts.touched()) { - return; - } - */ - - // Retrieve a point - TS_Point p = ts.getPoint(); - - /* - Serial.print("X = "); Serial.print(p.x); - Serial.print("\tY = "); Serial.print(p.y); - Serial.print("\tPressure = "); Serial.println(p.z); - */ - - // Scale from ~0->4000 to tft.width using the calibration #'s - p.x = map(p.x, TS_MINX, TS_MAXX, 0, tft.width()); - p.y = map(p.y, TS_MINY, TS_MAXY, 0, tft.height()); - - /* - Serial.print("("); Serial.print(p.x); - Serial.print(", "); Serial.print(p.y); - Serial.println(")"); - */ - - if (p.y < BOXSIZE) { - oldcolor = currentcolor; - - if (p.x < BOXSIZE) { - currentcolor = ILI9341_RED; - tft.drawRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); - } else if (p.x < BOXSIZE*2) { - currentcolor = ILI9341_YELLOW; - tft.drawRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); - } else if (p.x < BOXSIZE*3) { - currentcolor = ILI9341_GREEN; - tft.drawRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); - } else if (p.x < BOXSIZE*4) { - currentcolor = ILI9341_CYAN; - tft.drawRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); - } else if (p.x < BOXSIZE*5) { - currentcolor = ILI9341_BLUE; - tft.drawRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); - } else if (p.x < BOXSIZE*6) { - currentcolor = ILI9341_MAGENTA; - tft.drawRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); - } - - if (oldcolor != currentcolor) { - if (oldcolor == ILI9341_RED) - tft.fillRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_RED); - if (oldcolor == ILI9341_YELLOW) - tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_YELLOW); - if (oldcolor == ILI9341_GREEN) - tft.fillRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_GREEN); - if (oldcolor == ILI9341_CYAN) - tft.fillRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_CYAN); - if (oldcolor == ILI9341_BLUE) - tft.fillRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_BLUE); - if (oldcolor == ILI9341_MAGENTA) - tft.fillRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_MAGENTA); - } - } - if (((p.y-PENRADIUS) > BOXSIZE) && ((p.y+PENRADIUS) < tft.height())) { - tft.fillCircle(p.x, p.y, PENRADIUS, currentcolor); - } -} diff --git a/Sming/Libraries/Adafruit_ILI9341/library.properties b/Sming/Libraries/Adafruit_ILI9341/library.properties deleted file mode 100644 index aa621a9429..0000000000 --- a/Sming/Libraries/Adafruit_ILI9341/library.properties +++ /dev/null @@ -1,9 +0,0 @@ -name=Adafruit ILI9341 -version=1.0.0 -author=Adafruit -maintainer=Adafruit -sentence=Library for Adafruit ILI9341 displays -paragraph=Library for Adafruit ILI9341 displays -category=Display -url=https://github.com/adafruit/Adafruit_ILI9341 -architectures=* diff --git a/Sming/Libraries/Adafruit_NeoPixel b/Sming/Libraries/Adafruit_NeoPixel new file mode 160000 index 0000000000..7f3ebe002a --- /dev/null +++ b/Sming/Libraries/Adafruit_NeoPixel @@ -0,0 +1 @@ +Subproject commit 7f3ebe002a270ebf5298200c411085bba6ad131d diff --git a/Sming/Libraries/Adafruit_NeoPixel/Adafruit_NeoPixel.cpp b/Sming/Libraries/Adafruit_NeoPixel/Adafruit_NeoPixel.cpp deleted file mode 100644 index 751bff1425..0000000000 --- a/Sming/Libraries/Adafruit_NeoPixel/Adafruit_NeoPixel.cpp +++ /dev/null @@ -1,284 +0,0 @@ -/*------------------------------------------------------------------------- - Arduino library to control a wide variety of WS2811- and WS2812-based RGB - LED devices such as Adafruit FLORA RGB Smart Pixels and NeoPixel strips. - Currently handles 400 and 800 KHz bitstreams on 8, 12 and 16 MHz ATmega - MCUs, with LEDs wired for RGB or GRB color order. 8 MHz MCUs provide - output on PORTB and PORTD, while 16 MHz chips can handle most output pins - (possible exception with upper PORT registers on the Arduino Mega). - - Written by Phil Burgess / Paint Your Dragon for Adafruit Industries, - contributions by PJRC and other members of the open source community. - - Adafruit invests time and resources providing this open source code, - please support Adafruit and open-source hardware by purchasing products - from Adafruit! - - ------------------------------------------------------------------------- - This file is part of the Adafruit NeoPixel library. - - NeoPixel 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 3 of - the License, or (at your option) any later version. - - NeoPixel 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 NeoPixel. If not, see - . - -------------------------------------------------------------------------*/ -/*------------------------------------------------------------------------- - This library edited and adapted for Sming project - * by alonewolfx2 - * alonewolf07@gmail.com - */ -#include "Adafruit_NeoPixel.h" -#include - -Adafruit_NeoPixel::Adafruit_NeoPixel(uint16_t n, uint8_t p, uint8_t t) : numLEDs(n), numBytes(n * 3), pin(p), - brightness(0), pixels(NULL), type(t), endTime(0) -{ - if((pixels = (uint8_t *)malloc(numBytes))) { - memset(pixels, 0, numBytes); - } - if(t & NEO_GRB) { // GRB vs RGB; might add others if needed - rOffset = 1; - gOffset = 0; - bOffset = 2; - } else if (t & NEO_BRG) { - rOffset = 1; - gOffset = 2; - bOffset = 0; - } else { - rOffset = 0; - gOffset = 1; - bOffset = 2; - } - -} - -Adafruit_NeoPixel::~Adafruit_NeoPixel() { - if(pixels) free(pixels); - pinMode(pin, INPUT); -} - -void Adafruit_NeoPixel::begin(void) { - pinMode(pin, OUTPUT); - digitalWrite(pin, LOW); -} -static uint32_t _getCycleCount(void) __attribute__((always_inline)); -static inline uint32_t _getCycleCount(void) { - uint32_t ccount; - __asm__ __volatile__("rsr %0,ccount":"=a" (ccount)); - return ccount; -} -void IRAM_ATTR Adafruit_NeoPixel::show(void) { - - if(!pixels) return; - - // Data latch = 50+ microsecond pause in the output stream. Rather than - // put a delay at the end of the function, the ending time is noted and - // the function will simply hold off (if needed) on issuing the - // subsequent round of data until the latch time has elapsed. This - // allows the mainline code to start generating the next frame of data - // rather than stalling for the latch. - while(!canShow()); - // endTime is a private member (rather than global var) so that multiple - // instances on different pins can be quickly issued in succession (each - // instance doesn't delay the next). - - // In order to make this code runtime-configurable to work with any pin, - // SBI/CBI instructions are eschewed in favor of full PORT writes via the - // OUT or ST instructions. It relies on two facts: that peripheral - // functions (such as PWM) take precedence on output pins, so our PORT- - // wide writes won't interfere, and that interrupts are globally disabled - // while data is being issued to the LEDs, so no other code will be - // accessing the PORT. The code takes an initial 'snapshot' of the PORT - // state, computes 'pin high' and 'pin low' values, and writes these back - // to the PORT register as needed. - - noInterrupts(); // Need 100% focus on instruction timing - - boolean is800KHz=true; - - #define CYCLES_800_T0H (F_CPU / 2500000) // 0.4us - #define CYCLES_800_T1H (F_CPU / 1250000) // 0.8us - #define CYCLES_800 (F_CPU / 800000) // 1.25us per bit - #define CYCLES_400_T0H (F_CPU / 2000000) // 0.5uS - #define CYCLES_400_T1H (F_CPU / 833333) // 1.2us - #define CYCLES_400 (F_CPU / 400000) // 2.5us per bit - - uint8_t *p, *end, pix, mask; - uint32_t t, time0, time1, period, c, startTime, pinMask; - - pinMask = _BV(pin); - p = pixels; - end = p + numBytes; - pix = *p++; - mask = 0x80; - startTime = 0; - - #ifdef NEO_KHZ400 - if(is800KHz) { - #endif - time0 = CYCLES_800_T0H; - time1 = CYCLES_800_T1H; - period = CYCLES_800; - #ifdef NEO_KHZ400 - } else { // 400 KHz bitstream - time0 = CYCLES_400_T0H; - time1 = CYCLES_400_T1H; - period = CYCLES_400; - } - #endif - - for(t = time0;; t = time0) { - if(pix & mask) t = time1; // Bit high duration - while(((c = _getCycleCount()) - startTime) < period); // Wait for bit start - GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinMask); // Set high - startTime = c; // Save start time - while(((c = _getCycleCount()) - startTime) < t); // Wait high duration - GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinMask); // Set low - if(!(mask >>= 1)) { // Next bit/byte - if(p >= end) break; - pix = *p++; - mask = 0x80; - } - } - while((_getCycleCount() - startTime) < period); // Wait for last bit - interrupts(); - - endTime = micros(); // Save EOD time for latch on next call -} - -// Set the output pin number -void Adafruit_NeoPixel::setPin(uint8_t p) { - pinMode(pin, INPUT); - pin = p; - pinMode(p, OUTPUT); - digitalWrite(p, LOW); - -} - -// Set pixel color from separate R,G,B components: -void Adafruit_NeoPixel::setPixelColor( - uint16_t n, uint8_t r, uint8_t g, uint8_t b) { - if(n < numLEDs) { - if(brightness) { // See notes in setBrightness() - r = (r * brightness) >> 8; - g = (g * brightness) >> 8; - b = (b * brightness) >> 8; - } - uint8_t *p = &pixels[n * 3]; - p[rOffset] = r; - p[gOffset] = g; - p[bOffset] = b; - } -} - -// Set pixel color from 'packed' 32-bit RGB color: -void Adafruit_NeoPixel::setPixelColor(uint16_t n, uint32_t c) { - if(n < numLEDs) { - uint8_t - r = (uint8_t)(c >> 16), - g = (uint8_t)(c >> 8), - b = (uint8_t)c; - if(brightness) { // See notes in setBrightness() - r = (r * brightness) >> 8; - g = (g * brightness) >> 8; - b = (b * brightness) >> 8; - } - uint8_t *p = &pixels[n * 3]; - p[rOffset] = r; - p[gOffset] = g; - p[bOffset] = b; - } -} - -// Convert separate R,G,B into packed 32-bit RGB color. -// Packed format is always RGB, regardless of LED strand color order. -uint32_t Adafruit_NeoPixel::Color(uint8_t r, uint8_t g, uint8_t b) { - return ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; -} - -// Query color from previously-set pixel (returns packed 32-bit RGB value) -uint32_t Adafruit_NeoPixel::getPixelColor(uint16_t n) const { - if(n >= numLEDs) { - // Out of bounds, return no color. - return 0; - } - uint8_t *p = &pixels[n * 3]; - uint32_t c = ((uint32_t)p[rOffset] << 16) | - ((uint32_t)p[gOffset] << 8) | - (uint32_t)p[bOffset]; - // Adjust this back up to the true color, as setting a pixel color will - // scale it back down again. - if(brightness) { // See notes in setBrightness() - //Cast the color to a byte array - uint8_t * c_ptr =reinterpret_cast(&c); - c_ptr[0] = (c_ptr[0] << 8)/brightness; - c_ptr[1] = (c_ptr[1] << 8)/brightness; - c_ptr[2] = (c_ptr[2] << 8)/brightness; - } - return c; // Pixel # is out of bounds -} - -// Returns pointer to pixels[] array. Pixel data is stored in device- -// native format and is not translated here. Application will need to be -// aware whether pixels are RGB vs. GRB and handle colors appropriately. -uint8_t *Adafruit_NeoPixel::getPixels(void) const { - return pixels; -} - -uint16_t Adafruit_NeoPixel::numPixels(void) const { - return numLEDs; -} - -// Adjust output brightness; 0=darkest (off), 255=brightest. This does -// NOT immediately affect what's currently displayed on the LEDs. The -// next call to show() will refresh the LEDs at this level. However, -// this process is potentially "lossy," especially when increasing -// brightness. The tight timing in the WS2811/WS2812 code means there -// aren't enough free cycles to perform this scaling on the fly as data -// is issued. So we make a pass through the existing color data in RAM -// and scale it (subsequent graphics commands also work at this -// brightness level). If there's a significant step up in brightness, -// the limited number of steps (quantization) in the old data will be -// quite visible in the re-scaled version. For a non-destructive -// change, you'll need to re-render the full strip data. C'est la vie. -void Adafruit_NeoPixel::setBrightness(uint8_t b) { - // Stored brightness value is different than what's passed. - // This simplifies the actual scaling math later, allowing a fast - // 8x8-bit multiply and taking the MSB. 'brightness' is a uint8_t, - // adding 1 here may (intentionally) roll over...so 0 = max brightness - // (color values are interpreted literally; no scaling), 1 = min - // brightness (off), 255 = just below max brightness. - uint8_t newBrightness = b + 1; - if(newBrightness != brightness) { // Compare against prior value - // Brightness has changed -- re-scale existing data in RAM - uint8_t c, - *ptr = pixels, - oldBrightness = brightness - 1; // De-wrap old brightness value - uint16_t scale; - if(oldBrightness == 0) scale = 0; // Avoid /0 - else if(b == 255) scale = 65535 / oldBrightness; - else scale = (((uint16_t)newBrightness << 8) - 1) / oldBrightness; - for(uint16_t i=0; i> 8; - } - brightness = newBrightness; - } -} - -//Return the brightness value -uint8_t Adafruit_NeoPixel::getBrightness(void) const { - return brightness - 1; -} - -void Adafruit_NeoPixel::clear() { - memset(pixels, 0, numBytes); -} diff --git a/Sming/Libraries/Adafruit_NeoPixel/Adafruit_NeoPixel.h b/Sming/Libraries/Adafruit_NeoPixel/Adafruit_NeoPixel.h deleted file mode 100644 index a19cd71b1f..0000000000 --- a/Sming/Libraries/Adafruit_NeoPixel/Adafruit_NeoPixel.h +++ /dev/null @@ -1,90 +0,0 @@ -/*-------------------------------------------------------------------- - This file is part of the Adafruit NeoPixel library. - - NeoPixel 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 3 of - the License, or (at your option) any later version. - - NeoPixel 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 NeoPixel. If not, see - . - --------------------------------------------------------------------*/ -/*------------------------------------------------------------------------- - This library edited and adapted for Sming project - * by alonewolfx2 - * alonewolf07@gmail.com - */ -#ifndef ADAFRUIT_NEOPIXEL_H -#define ADAFRUIT_NEOPIXEL_H - -#if ARDUINO >= 100 - #include "Arduino.h" - #define WIRE_WRITE Wire.write -#else - #include "WProgram.h" - #define WIRE_WRITE Wire.send -#endif - - -// 'type' flags for LED pixels (third parameter to constructor): -#define NEO_RGB 0x00 // Wired for RGB data order -#define NEO_GRB 0x01 // Wired for GRB data order -#define NEO_BRG 0x04 - -#define NEO_COLMASK 0x01 -#define NEO_KHZ800 0x02 // 800 KHz datastream -#define NEO_SPDMASK 0x02 - -class Adafruit_NeoPixel { - - public: - - // Constructor: number of LEDs, pin number, LED type - Adafruit_NeoPixel(uint16_t n, uint8_t p=6, uint8_t t=NEO_GRB + NEO_KHZ800); - ~Adafruit_NeoPixel(); - - void - begin(void), - show(void), - setPin(uint8_t p), - setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b), - setPixelColor(uint16_t n, uint32_t c), - setBrightness(uint8_t), - clear(); - uint8_t - *getPixels(void) const, - getBrightness(void) const; - uint16_t - numPixels(void) const; - static uint32_t - Color(uint8_t r, uint8_t g, uint8_t b); - uint32_t - getPixelColor(uint16_t n) const; - inline bool - canShow(void) { return (micros() - endTime) >= 50L; } - - private: - - const uint16_t - numLEDs, // Number of RGB LEDs in strip - numBytes; // Size of 'pixels' buffer below - uint8_t - pin, // Output pin number - brightness, - *pixels, // Holds LED color values (3 bytes each) - rOffset, // Index of red byte within each 3-byte pixel - gOffset, // Index of green byte - bOffset; // Index of blue byte - const uint8_t - type; // Pixel flags (400 vs 800 KHz, RGB vs GRB color) - uint32_t - endTime; // Latch timing reference -}; - -#endif // ADAFRUIT_NEOPIXEL_H diff --git a/Sming/Libraries/Adafruit_NeoPixel/COPYING b/Sming/Libraries/Adafruit_NeoPixel/COPYING deleted file mode 100644 index 7dcf8e8ae4..0000000000 --- a/Sming/Libraries/Adafruit_NeoPixel/COPYING +++ /dev/null @@ -1,794 +0,0 @@ - - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - - -LGPL ADDENDUM: - - - - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. diff --git a/Sming/Libraries/Adafruit_NeoPixel/README.md b/Sming/Libraries/Adafruit_NeoPixel/README.md deleted file mode 100644 index fbeff35504..0000000000 --- a/Sming/Libraries/Adafruit_NeoPixel/README.md +++ /dev/null @@ -1,50 +0,0 @@ -# Adafruit NeoPixel Library -[![Build Status](https://travis-ci.org/adafruit/Adafruit_NeoPixel.svg?branch=master)](https://travis-ci.org/adafruit/Adafruit_NeoPixel) - -*This library edited and adapted for Sming project by alonewolfx2 alonewolf07@gmail.com* - -Arduino library for controlling single-wire-based LED pixels and strip such as the [Adafruit 60 LED/meter Digital LED strip][strip], the [Adafruit FLORA RGB Smart Pixel][flora], the [Adafruit Breadboard-friendly RGB Smart Pixel][pixel], the [Adafruit NeoPixel Stick][stick], and the [Adafruit NeoPixel Shield][shield]. - -After downloading, rename folder to 'Adafruit_NeoPixel' and install in Arduino Libraries folder. Restart Arduino IDE, then open File->Sketchbook->Library->Adafruit_NeoPixel->strandtest sketch. - -Compatibility notes: Port A is not supported on any AVR processors at this time - -[flora]: http://adafruit.com/products/1060 -[strip]: http://adafruit.com/products/1138 -[pixel]: http://adafruit.com/products/1312 -[stick]: http://adafruit.com/products/1426 -[shield]: http://adafruit.com/products/1430 - ---- - -## Supported chipsets - -We have included code for the following chips - *sometimes these break for exciting reasons that we can't control* in which case please open an issue! - - * AVR ATmega and ATtiny (any 8-bit) - 8 MHz, 12 MHz and 16 MHz - * Teensy 3.x and LC - * Arduino Due - * Arduino 101 - * ATSAMD21 (Arduino Zero/M0 and other SAMD21 boards) @ 48 MHz - * ATSAMD51 @ 120 MHz - * Adafruit STM32 Feather @ 120 MHz - * ESP8266 any speed - * ESP32 any speed - * Nordic nRF52 (Adafruit Feather nRF52), nRF51 (micro:bit) - -Check forks for other architectures not listed here! - ---- - -### Roadmap - -The PRIME DIRECTIVE is to maintain backward compatibility with existing Arduino sketches -- many are hosted elsewhere and don't track changes here, some are in print and can never be changed! - -Please don't reformat code for the sake of reformatting code. The resulting large "visual diff" makes it impossible to untangle actual bug fixes from merely rearranged lines. (Exception for first item in wishlist below.) - -Things I'd Like To Do But There's No Official Timeline So Please Don't Count On Any Of This Ever Being Canonical: - - * For the show() function (with all the delicate pixel timing stuff), break out each architecture into separate source files rather than the current unmaintainable tangle of #ifdef statements! - * Please don't use updateLength() or updateType() in new code. They should not have been implemented this way (use the C++ 'new' operator with the regular constructor instead) and are only sticking around because of the Prime Directive. setPin() is OK for now though, it's a trick we can use to 'recycle' pixel memory across multiple strips. - * In the M0 and M4 code, use the hardware systick counter for bit timing rather than hand-tweaked NOPs (a temporary kludge at the time because I wasn't reading systick correctly). (As of 1.4.2, systick is used on M4 devices and it appears to be overclock-compatible. Not for M0 yet, which is why this item is still here.) - * As currently written, brightness scaling is still a "destructive" operation -- pixel values are altered in RAM and the original value as set can't be accurately read back, only approximated, which has been confusing and frustrating to users. It was done this way at the time because NeoPixel timing is strict, AVR microcontrollers (all we had at the time) are limited, and assembly language is hard. All the 32-bit architectures should have no problem handling nondestructive brightness scaling -- calculating each byte immediately before it's sent out the wire, maintaining the original set value in RAM -- the work just hasn't been done. There's a fair chance even the AVR code could manage it with some intense focus. (The DotStar library achieves nondestructive brightness scaling because it doesn't have to manage data timing so carefully...every architecture, even ATtiny, just takes whatever cycles it needs for the multiply/shift operations.) diff --git a/Sming/Libraries/Adafruit_NeoPixel/component.mk b/Sming/Libraries/Adafruit_NeoPixel/component.mk deleted file mode 100644 index e243360e9c..0000000000 --- a/Sming/Libraries/Adafruit_NeoPixel/component.mk +++ /dev/null @@ -1 +0,0 @@ -COMPONENT_SOC := esp8266 diff --git a/Sming/Libraries/Adafruit_NeoPixel/keywords.txt b/Sming/Libraries/Adafruit_NeoPixel/keywords.txt deleted file mode 100644 index 76f9446dfa..0000000000 --- a/Sming/Libraries/Adafruit_NeoPixel/keywords.txt +++ /dev/null @@ -1,29 +0,0 @@ -####################################### -# Syntax Coloring Map For Adafruit_NeoPixel -####################################### -# Class -####################################### - -Adafruit_NeoPixel KEYWORD1 - -####################################### -# Methods and Functions -####################################### - -setPixelColor KEYWORD2 -setPin KEYWORD2 -setBrightness KEYWORD2 -numPixels KEYWORD2 -getPixelColor KEYWORD2 -Color KEYWORD2 - -####################################### -# Constants -####################################### - -NEO_GRB LITERAL1 -NEO_COLMASK LITERAL1 -NEO_KHZ800 LITERAL1 -NEO_SPDMASK LITERAL1 -NEO_RGB LITERAL1 -NEO_KHZ400 LITERAL1 diff --git a/Sming/Libraries/Adafruit_NeoPixel/library.properties b/Sming/Libraries/Adafruit_NeoPixel/library.properties deleted file mode 100644 index be53f8f538..0000000000 --- a/Sming/Libraries/Adafruit_NeoPixel/library.properties +++ /dev/null @@ -1,9 +0,0 @@ -name=Adafruit NeoPixel -version=1.0.3 -author=Adafruit -maintainer=Adafruit -sentence=Arduino library for controlling single-wire-based LED pixels and strip. -paragraph=Arduino library for controlling single-wire-based LED pixels and strip. -category=Display -url=https://github.com/adafruit/Adafruit_NeoPixel -architectures=* diff --git a/Sming/Libraries/Adafruit_PCD8544 b/Sming/Libraries/Adafruit_PCD8544 new file mode 160000 index 0000000000..6414a48a40 --- /dev/null +++ b/Sming/Libraries/Adafruit_PCD8544 @@ -0,0 +1 @@ +Subproject commit 6414a48a40aafb740a2d0d4205a84f623073815a diff --git a/Sming/Libraries/Adafruit_PCD8544/Adafruit_PCD8544.cpp b/Sming/Libraries/Adafruit_PCD8544/Adafruit_PCD8544.cpp deleted file mode 100644 index 6f6710bbd9..0000000000 --- a/Sming/Libraries/Adafruit_PCD8544/Adafruit_PCD8544.cpp +++ /dev/null @@ -1,346 +0,0 @@ -/********************************************************************* -This is a library for our Monochrome Nokia 5110 LCD Displays - - Pick one up today in the adafruit shop! - ------> http://www.adafruit.com/products/338 - -These displays use SPI to communicate, 4 or 5 pins are required to -interface - -Adafruit invests time and resources providing this open source code, -please support Adafruit and open-source hardware by purchasing -products from Adafruit! - -Written by Limor Fried/Ladyada for Adafruit Industries. -BSD license, check license.txt for more information -All text above, and the splash screen below must be included in any redistribution -*********************************************************************/ - -//#include -//#include -//#if defined(ARDUINO) && ARDUINO >= 100 -// #include "Arduino.h" -//#else -// #include "WProgram.h" -//#endif - -//#ifdef __AVR__ - // #include -//#endif - -//#ifndef _BV -// #define _BV(x) (1 << (x)) -//#endif - - -#include "Adafruit_PCD8544.h" - -#include - -#include - - -// the memory buffer for the LCD -uint8_t pcd8544_buffer[LCDWIDTH * LCDHEIGHT / 8] = { - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xe0,0xe0,0xe0,0xc0,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x80,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x80,0xc0,0xe0,0xe0,0xe0,0xe0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x1f,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x1e,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xc0,0xc0,0xc0,0xe0,0xe0,0xe0,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x1f,0x1f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x1f,0x3f,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xf0,0xe0,0xe0,0xe0,0xc0,0xc0,0xc0,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x7f,0x7f,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe1,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xe1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x7f,0x7f,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x83,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x1e,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xcf,0x83,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x1f,0x3f,0x7f,0xff,0xff,0xff,0x7f,0x7f,0x3f,0x3f,0x1f,0x3f,0x3f,0x3f,0x0f,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x0f,0x3f,0x3f,0x3f,0x1f,0x3f,0x3f,0x7f,0xff,0xff,0xff,0xff,0x3f,0x3f,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - -}; - - -// reduces how much is refreshed, which speeds it up! -// originally derived from Steve Evans/JCW's mod but cleaned up and -// optimized -//#define enablePartialUpdate - -#ifdef enablePartialUpdate -static uint8_t xUpdateMin, xUpdateMax, yUpdateMin, yUpdateMax; -#endif - - - -static void updateBoundingBox(uint8_t xmin, uint8_t ymin, uint8_t xmax, uint8_t ymax) { -#ifdef enablePartialUpdate - if (xmin < xUpdateMin) xUpdateMin = xmin; - if (xmax > xUpdateMax) xUpdateMax = xmax; - if (ymin < yUpdateMin) yUpdateMin = ymin; - if (ymax > yUpdateMax) yUpdateMax = ymax; -#endif -} - -Adafruit_PCD8544::Adafruit_PCD8544(int8_t SCLK, int8_t DIN, int8_t DC, - int8_t CS, int8_t RST) : Adafruit_GFX(LCDWIDTH, LCDHEIGHT) { - _din = DIN; - _sclk = SCLK; - _dc = DC; - _rst = RST; - _cs = CS; -} - -Adafruit_PCD8544::Adafruit_PCD8544(int8_t SCLK, int8_t DIN, int8_t DC, - int8_t RST) : Adafruit_GFX(LCDWIDTH, LCDHEIGHT) { - _din = DIN; - _sclk = SCLK; - _dc = DC; - _rst = RST; - _cs = -1; -} - -Adafruit_PCD8544::Adafruit_PCD8544(int8_t DC, int8_t CS, int8_t RST): - Adafruit_GFX(LCDWIDTH, LCDHEIGHT) { - // -1 for din and sclk specify using hardware SPI - _din = -1; - _sclk = -1; - _dc = DC; - _rst = RST; - _cs = CS; -} - - -// the most basic function, set a single pixel -void Adafruit_PCD8544::drawPixel(int16_t x, int16_t y, uint16_t color) { - if ((x < 0) || (x >= _width) || (y < 0) || (y >= _height)) - return; - - int16_t t; - switch(rotation){ - case 1: - t = x; - x = y; - y = LCDHEIGHT - 1 - t; - break; - case 2: - x = LCDWIDTH - 1 - x; - y = LCDHEIGHT - 1 - y; - break; - case 3: - t = x; - x = LCDWIDTH - 1 - y; - y = t; - break; - } - - if ((x < 0) || (x >= LCDWIDTH) || (y < 0) || (y >= LCDHEIGHT)) - return; - - // x is which column - if (color) - pcd8544_buffer[x+ (y/8)*LCDWIDTH] |= _BV(y%8); - else - pcd8544_buffer[x+ (y/8)*LCDWIDTH] &= ~_BV(y%8); - - updateBoundingBox(x,y,x,y); -} - - -// the most basic function, get a single pixel -uint8_t Adafruit_PCD8544::getPixel(int8_t x, int8_t y) { - if ((x < 0) || (x >= LCDWIDTH) || (y < 0) || (y >= LCDHEIGHT)) - return 0; - - return (pcd8544_buffer[x+ (y/8)*LCDWIDTH] >> (y%8)) & 0x1; -} - - -void Adafruit_PCD8544::begin(uint8_t contrast, uint8_t bias) { - /* - if (isHardwareSPI()) { - // Setup hardware SPI. - SPI.begin(); - SPI.setClockDivider(PCD8544_SPI_CLOCK_DIV); - SPI.setDataMode(SPI_MODE0); - SPI.setBitOrder(MSBFIRST); - } - else { -*/ - // Setup software SPI. - - // Set software SPI specific pin outputs. - pinMode(_din, OUTPUT); - pinMode(_sclk, OUTPUT); - - // Set software SPI ports and masks. - clkport = portOutputRegister(digitalPinToPort(_sclk)); - clkpinmask = digitalPinToBitMask(_sclk); - mosiport = portOutputRegister(digitalPinToPort(_din)); - mosipinmask = digitalPinToBitMask(_din); -// } - - // Set common pin outputs. - pinMode(_dc, OUTPUT); - if (_rst > 0) - pinMode(_rst, OUTPUT); - if (_cs > 0) - pinMode(_cs, OUTPUT); - - // toggle RST low to reset - if (_rst > 0) { - digitalWrite(_rst, LOW); - delay(500); - digitalWrite(_rst, HIGH); - } - - // get into the EXTENDED mode! - command(PCD8544_FUNCTIONSET | PCD8544_EXTENDEDINSTRUCTION ); - - // LCD bias select (4 is optimal?) - command(PCD8544_SETBIAS | bias); - - // set VOP - if (contrast > 0x4f) - contrast = 0x4f; - - command( PCD8544_SETVOP | contrast); // Experimentally determined - - - // normal mode - command(PCD8544_FUNCTIONSET); - - // Set display to Normal - command(PCD8544_DISPLAYCONTROL | PCD8544_DISPLAYNORMAL); - - // initial display line - // set page address - // set column address - // write display data - - // set up a bounding box for screen updates - - updateBoundingBox(0, 0, LCDWIDTH-1, LCDHEIGHT-1); - // Push out pcd8544_buffer to the Display (will show the AFI logo) - display(); -} - - -inline void Adafruit_PCD8544::spiWrite(uint8_t d) { - if (isHardwareSPI()) { - // Hardware SPI write. - SPI.transfer(d); - } - else { - // Software SPI write with bit banging. - for(uint8_t bit = 0x80; bit; bit >>= 1) { - *clkport &= ~clkpinmask; - if(d & bit) *mosiport |= mosipinmask; - else *mosiport &= ~mosipinmask; - *clkport |= clkpinmask; - } - } -} - -bool Adafruit_PCD8544::isHardwareSPI() { - return (_din == -1 && _sclk == -1); -} - -void Adafruit_PCD8544::command(uint8_t c) { - digitalWrite(_dc, LOW); - if (_cs > 0) - digitalWrite(_cs, LOW); - shiftOut(_din, _sclk, MSBFIRST, c); - if (_cs > 0) - digitalWrite(_cs, HIGH); -} - -void Adafruit_PCD8544::data(uint8_t c) { - digitalWrite(_dc, HIGH); - if (_cs > 0) - digitalWrite(_cs, LOW); - shiftOut(_din, _sclk, MSBFIRST, c); - if (_cs > 0) - digitalWrite(_cs, HIGH); -} - -void Adafruit_PCD8544::setContrast(uint8_t val) { - if (val > 0x7f) { - val = 0x7f; - } - command(PCD8544_FUNCTIONSET | PCD8544_EXTENDEDINSTRUCTION ); - command( PCD8544_SETVOP | val); - command(PCD8544_FUNCTIONSET); - - } - - - -void Adafruit_PCD8544::display(void) { - uint8_t col, maxcol, p; - - for(p = 0; p < 6; p++) { -#ifdef enablePartialUpdate - // check if this page is part of update - if ( yUpdateMin >= ((p+1)*8) ) { - continue; // nope, skip it! - } - if (yUpdateMax < p*8) { - break; - } -#endif - - command(PCD8544_SETYADDR | p); - - -#ifdef enablePartialUpdate - col = xUpdateMin; - maxcol = xUpdateMax; -#else - // start at the beginning of the row - col = 0; - maxcol = LCDWIDTH-1; -#endif - - command(PCD8544_SETXADDR | col); - - digitalWrite(_dc, HIGH); - if (_cs > 0) - digitalWrite(_cs, LOW); - for(; col <= maxcol; col++) { - shiftOut(_din, _sclk, MSBFIRST,pcd8544_buffer[(LCDWIDTH*p)+col]); - //spiWrite(); - } - if (_cs > 0) - digitalWrite(_cs, HIGH); - - } - - command(PCD8544_SETYADDR ); // no idea why this is necessary but it is to finish the last byte? -#ifdef enablePartialUpdate - xUpdateMin = LCDWIDTH - 1; - xUpdateMax = 0; - yUpdateMin = LCDHEIGHT-1; - yUpdateMax = 0; -#endif - -} - -// clear everything -void Adafruit_PCD8544::clearDisplay(void) { - memset(pcd8544_buffer, 0, LCDWIDTH*LCDHEIGHT/8); - updateBoundingBox(0, 0, LCDWIDTH-1, LCDHEIGHT-1); - cursor_y = cursor_x = 0; -} - -/* -// this doesn't touch the buffer, just clears the display RAM - might be handy -void Adafruit_PCD8544::clearDisplay(void) { - - uint8_t p, c; - - for(p = 0; p < 8; p++) { - - st7565_command(CMD_SET_PAGE | p); - for(c = 0; c < 129; c++) { - //uart_putw_dec(c); - //uart_putchar(' '); - st7565_command(CMD_SET_COLUMN_LOWER | (c & 0xf)); - st7565_command(CMD_SET_COLUMN_UPPER | ((c >> 4) & 0xf)); - st7565_data(0x0); - } - } - -} - -*/ diff --git a/Sming/Libraries/Adafruit_PCD8544/Adafruit_PCD8544.h b/Sming/Libraries/Adafruit_PCD8544/Adafruit_PCD8544.h deleted file mode 100644 index da3ebab045..0000000000 --- a/Sming/Libraries/Adafruit_PCD8544/Adafruit_PCD8544.h +++ /dev/null @@ -1,100 +0,0 @@ -/********************************************************************* -This is a library for our Monochrome Nokia 5110 LCD Displays - - Pick one up today in the adafruit shop! - ------> http://www.adafruit.com/products/338 - -These displays use SPI to communicate, 4 or 5 pins are required to -interface - -Adafruit invests time and resources providing this open source code, -please support Adafruit and open-source hardware by purchasing -products from Adafruit! - -Written by Limor Fried/Ladyada for Adafruit Industries. -BSD license, check license.txt for more information -All text above, and the splash screen must be included in any redistribution -*********************************************************************/ - - -#if ARDUINO >= 100 - #include "Arduino.h" - #define WIRE_WRITE Wire.write -#else - #include "WProgram.h" - #define WIRE_WRITE Wire.send -#endif - -#include -#include - -#ifdef __SAM3X8E__ - typedef volatile RwReg PortReg; - typedef uint32_t PortMask; -#else - typedef volatile GPIO_REG_TYPE PortReg; - typedef GPIO_REG_TYPE PortMask; -#endif - -#define BLACK 1 -#define WHITE 0 - -#define LCDWIDTH 84 -#define LCDHEIGHT 48 - -#define PCD8544_POWERDOWN 0x04 -#define PCD8544_ENTRYMODE 0x02 -#define PCD8544_EXTENDEDINSTRUCTION 0x21 - -#define PCD8544_DISPLAYBLANK 0x0 -#define PCD8544_DISPLAYNORMAL 0x0C -#define PCD8544_DISPLAYALLON 0x1 -#define PCD8544_DISPLAYINVERTED 0x0d - -// H = 0 -#define PCD8544_FUNCTIONSET 0x20 -#define PCD8544_DISPLAYCONTROL 0x08 -#define PCD8544_SETYADDR 0x40 -#define PCD8544_SETXADDR 0x80 - -// H = 1 -#define PCD8544_SETTEMP 0x04 -#define PCD8544_SETBIAS 0x14 -#define PCD8544_SETVOP 0xBf - -// Default to max SPI clock speed for PCD8544 of 4 mhz (16mhz / 4) for normal Arduinos. -// This can be modified to change the clock speed if necessary (like for supporting other hardware). - -#define PCD8544_SPI_CLOCK_DIV SPI_CLOCK_DIV4 - - -class Adafruit_PCD8544 : public Adafruit_GFX { - public: - // Software SPI with explicit CS pin. - Adafruit_PCD8544(int8_t SCLK, int8_t DIN, int8_t DC, int8_t CS, int8_t RST); - // Software SPI with CS tied to ground. Saves a pin but other pins can't be shared with other hardware. - Adafruit_PCD8544(int8_t SCLK, int8_t DIN, int8_t DC, int8_t RST); - // Hardware SPI based on hardware controlled SCK (SCLK) and MOSI (DIN) pins. CS is still controlled by any IO pin. - // NOTE: MISO and SS will be set as an input and output respectively, so be careful sharing those pins! - Adafruit_PCD8544(int8_t DC, int8_t CS, int8_t RST); - - void begin(uint8_t contrast = 40, uint8_t bias = 0x04); - - void command(uint8_t c); - void data(uint8_t c); - - void setContrast(uint8_t val); - void clearDisplay(void); - void display(); - - void drawPixel(int16_t x, int16_t y, uint16_t color); - uint8_t getPixel(int8_t x, int8_t y); - - private: - int8_t _din, _sclk, _dc, _rst, _cs; - volatile PortReg *mosiport, *clkport; - PortMask mosipinmask, clkpinmask; - - void spiWrite(uint8_t c); - bool isHardwareSPI(); -}; diff --git a/Sming/Libraries/Adafruit_PCD8544/README.md b/Sming/Libraries/Adafruit_PCD8544/README.md deleted file mode 100644 index 80055d2592..0000000000 --- a/Sming/Libraries/Adafruit_PCD8544/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# Adafruit PCD8544 Display - -This is a library for our Monochrome Nokia 5110 LCD Displays - - Pick one up today in the adafruit shop! - ------> http://www.adafruit.com/products/338 - -These displays use SPI to communicate, 4 or 5 pins are required to -interface - -Adafruit invests time and resources providing this open source code, -please support Adafruit and open-source hardware by purchasing -products from Adafruit! - -Written by Limor Fried/Ladyada for Adafruit Industries. -BSD license, check license.txt for more information -All text above must be included in any redistribution - -To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder Adafruit_PCD8544. Check that the Adafruit_PCD8544 folder contains Adafruit_PCD8544.cpp and Adafruit_PCD8544.h - -Place the Adafruit_PCD8544 library folder your /libraries/ folder. You may need to create the libraries subfolder if its your first library. Restart the IDE. - -You will also have to download the Adafruit GFX Graphics core which does all the circles, text, rectangles, etc. You can get it from -https://github.com/adafruit/Adafruit-GFX-Library -and download/install that library as well \ No newline at end of file diff --git a/Sming/Libraries/Adafruit_PCD8544/component.mk b/Sming/Libraries/Adafruit_PCD8544/component.mk deleted file mode 100644 index f2997c2408..0000000000 --- a/Sming/Libraries/Adafruit_PCD8544/component.mk +++ /dev/null @@ -1 +0,0 @@ -COMPONENT_DEPENDS := Adafruit_GFX diff --git a/Sming/Libraries/Adafruit_PCD8544/examples/pcdtest/pcdtest.ino b/Sming/Libraries/Adafruit_PCD8544/examples/pcdtest/pcdtest.ino deleted file mode 100644 index f47ad60ead..0000000000 --- a/Sming/Libraries/Adafruit_PCD8544/examples/pcdtest/pcdtest.ino +++ /dev/null @@ -1,350 +0,0 @@ -/********************************************************************* -This is an example sketch for our Monochrome Nokia 5110 LCD Displays - - Pick one up today in the adafruit shop! - ------> http://www.adafruit.com/products/338 - -These displays use SPI to communicate, 4 or 5 pins are required to -interface - -Adafruit invests time and resources providing this open source code, -please support Adafruit and open-source hardware by purchasing -products from Adafruit! - -Written by Limor Fried/Ladyada for Adafruit Industries. -BSD license, check license.txt for more information -All text above, and the splash screen must be included in any redistribution -*********************************************************************/ - -#include -#include -#include - -// Software SPI (slower updates, more flexible pin options): -// pin 7 - Serial clock out (SCLK) -// pin 6 - Serial data out (DIN) -// pin 5 - Data/Command select (D/C) -// pin 4 - LCD chip select (CS) -// pin 3 - LCD reset (RST) -Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 5, 4, 3); - -// Hardware SPI (faster, but must use certain hardware pins): -// SCK is LCD serial clock (SCLK) - this is pin 13 on Arduino Uno -// MOSI is LCD DIN - this is pin 11 on an Arduino Uno -// pin 5 - Data/Command select (D/C) -// pin 4 - LCD chip select (CS) -// pin 3 - LCD reset (RST) -// Adafruit_PCD8544 display = Adafruit_PCD8544(5, 4, 3); -// Note with hardware SPI MISO and SS pins aren't used but will still be read -// and written to during SPI transfer. Be careful sharing these pins! - -#define NUMFLAKES 10 -#define XPOS 0 -#define YPOS 1 -#define DELTAY 2 - - -#define LOGO16_GLCD_HEIGHT 16 -#define LOGO16_GLCD_WIDTH 16 - -static const unsigned char PROGMEM logo16_glcd_bmp[] = -{ B00000000, B11000000, - B00000001, B11000000, - B00000001, B11000000, - B00000011, B11100000, - B11110011, B11100000, - B11111110, B11111000, - B01111110, B11111111, - B00110011, B10011111, - B00011111, B11111100, - B00001101, B01110000, - B00011011, B10100000, - B00111111, B11100000, - B00111111, B11110000, - B01111100, B11110000, - B01110000, B01110000, - B00000000, B00110000 }; - -void setup() { - Serial.begin(9600); - - display.begin(); - // init done - - // you can change the contrast around to adapt the display - // for the best viewing! - display.setContrast(50); - - display.display(); // show splashscreen - delay(2000); - display.clearDisplay(); // clears the screen and buffer - - // draw a single pixel - display.drawPixel(10, 10, BLACK); - display.display(); - delay(2000); - display.clearDisplay(); - - // draw many lines - testdrawline(); - display.display(); - delay(2000); - display.clearDisplay(); - - // draw rectangles - testdrawrect(); - display.display(); - delay(2000); - display.clearDisplay(); - - // draw multiple rectangles - testfillrect(); - display.display(); - delay(2000); - display.clearDisplay(); - - // draw multiple circles - testdrawcircle(); - display.display(); - delay(2000); - display.clearDisplay(); - - // draw a circle, 10 pixel radius - display.fillCircle(display.width()/2, display.height()/2, 10, BLACK); - display.display(); - delay(2000); - display.clearDisplay(); - - testdrawroundrect(); - delay(2000); - display.clearDisplay(); - - testfillroundrect(); - delay(2000); - display.clearDisplay(); - - testdrawtriangle(); - delay(2000); - display.clearDisplay(); - - testfilltriangle(); - delay(2000); - display.clearDisplay(); - - // draw the first ~12 characters in the font - testdrawchar(); - display.display(); - delay(2000); - display.clearDisplay(); - - // text display tests - display.setTextSize(1); - display.setTextColor(BLACK); - display.setCursor(0,0); - display.println("Hello, world!"); - display.setTextColor(WHITE, BLACK); // 'inverted' text - display.println(3.141592); - display.setTextSize(2); - display.setTextColor(BLACK); - display.print("0x"); display.println(0xDEADBEEF, HEX); - display.display(); - delay(2000); - - // rotation example - display.clearDisplay(); - display.setRotation(1); // rotate 90 degrees counter clockwise, can also use values of 2 and 3 to go further. - display.setTextSize(1); - display.setTextColor(BLACK); - display.setCursor(0,0); - display.println("Rotation"); - display.setTextSize(2); - display.println("Example!"); - display.display(); - delay(2000); - - // revert back to no rotation - display.setRotation(0); - - // miniature bitmap display - display.clearDisplay(); - display.drawBitmap(30, 16, logo16_glcd_bmp, 16, 16, 1); - display.display(); - - // invert the display - display.invertDisplay(true); - delay(1000); - display.invertDisplay(false); - delay(1000); - - // draw a bitmap icon and 'animate' movement - testdrawbitmap(logo16_glcd_bmp, LOGO16_GLCD_WIDTH, LOGO16_GLCD_HEIGHT); -} - - -void loop() { - -} - - -void testdrawbitmap(const uint8_t *bitmap, uint8_t w, uint8_t h) { - uint8_t icons[NUMFLAKES][3]; - randomSeed(666); // whatever seed - - // initialize - for (uint8_t f=0; f< NUMFLAKES; f++) { - icons[f][XPOS] = random(display.width()); - icons[f][YPOS] = 0; - icons[f][DELTAY] = random(5) + 1; - - Serial.print("x: "); - Serial.print(icons[f][XPOS], DEC); - Serial.print(" y: "); - Serial.print(icons[f][YPOS], DEC); - Serial.print(" dy: "); - Serial.println(icons[f][DELTAY], DEC); - } - - while (1) { - // draw each icon - for (uint8_t f=0; f< NUMFLAKES; f++) { - display.drawBitmap(icons[f][XPOS], icons[f][YPOS], logo16_glcd_bmp, w, h, BLACK); - } - display.display(); - delay(200); - - // then erase it + move it - for (uint8_t f=0; f< NUMFLAKES; f++) { - display.drawBitmap(icons[f][XPOS], icons[f][YPOS], logo16_glcd_bmp, w, h, WHITE); - // move it - icons[f][YPOS] += icons[f][DELTAY]; - // if its gone, reinit - if (icons[f][YPOS] > display.height()) { - icons[f][XPOS] = random(display.width()); - icons[f][YPOS] = 0; - icons[f][DELTAY] = random(5) + 1; - } - } - } -} - - -void testdrawchar(void) { - display.setTextSize(1); - display.setTextColor(BLACK); - display.setCursor(0,0); - - for (uint8_t i=0; i < 168; i++) { - if (i == '\n') continue; - display.write(i); - //if ((i > 0) && (i % 14 == 0)) - //display.println(); - } - display.display(); -} - -void testdrawcircle(void) { - for (int16_t i=0; i0; i-=5) { - display.fillTriangle(display.width()/2, display.height()/2-i, - display.width()/2-i, display.height()/2+i, - display.width()/2+i, display.height()/2+i, color); - if (color == WHITE) color = BLACK; - else color = WHITE; - display.display(); - } -} - -void testdrawroundrect(void) { - for (int16_t i=0; i=0; i-=4) { - display.drawLine(0, display.height()-1, display.width()-1, i, BLACK); - display.display(); - } - delay(250); - - display.clearDisplay(); - for (int16_t i=display.width()-1; i>=0; i-=4) { - display.drawLine(display.width()-1, display.height()-1, i, 0, BLACK); - display.display(); - } - for (int16_t i=display.height()-1; i>=0; i-=4) { - display.drawLine(display.width()-1, display.height()-1, 0, i, BLACK); - display.display(); - } - delay(250); - - display.clearDisplay(); - for (int16_t i=0; i -sentence=Arduino driver for PC8544, most commonly found in small Nokia 5110's -paragraph=Arduino driver for PC8544, most commonly found in small Nokia 5110's -category=Display -url=https://github.com/adafruit/Adafruit-PCD8544-Nokia-5110-LCD-library -architectures=* diff --git a/Sming/Libraries/Adafruit_PCD8544/license.txt b/Sming/Libraries/Adafruit_PCD8544/license.txt deleted file mode 100644 index f6a0f22b82..0000000000 --- a/Sming/Libraries/Adafruit_PCD8544/license.txt +++ /dev/null @@ -1,26 +0,0 @@ -Software License Agreement (BSD License) - -Copyright (c) 2012, Adafruit Industries -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: -1. Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. -3. Neither the name of the copyright holders nor the -names of its contributors may be used to endorse or promote products -derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Sming/Libraries/Adafruit_SSD1306 b/Sming/Libraries/Adafruit_SSD1306 index ddfec78fa1..d6db01d87f 160000 --- a/Sming/Libraries/Adafruit_SSD1306 +++ b/Sming/Libraries/Adafruit_SSD1306 @@ -1 +1 @@ -Subproject commit ddfec78fa15f0ff8dfc8a76524077ba6bb5fc6f3 +Subproject commit d6db01d87fe5cff5649993f1c6c3064db6a09ec7 diff --git a/Sming/Libraries/Adafruit_ST7735 b/Sming/Libraries/Adafruit_ST7735 index 591fa4165d..84a5b431af 160000 --- a/Sming/Libraries/Adafruit_ST7735 +++ b/Sming/Libraries/Adafruit_ST7735 @@ -1 +1 @@ -Subproject commit 591fa4165d95c33ba13bfad2f09758852fe1282a +Subproject commit 84a5b431af92bd52f27ea19cd8ead6ad06de9fb3 diff --git a/Sming/Libraries/AnimatedGIF/AnimatedGIF b/Sming/Libraries/AnimatedGIF/AnimatedGIF new file mode 160000 index 0000000000..73f4a4091d --- /dev/null +++ b/Sming/Libraries/AnimatedGIF/AnimatedGIF @@ -0,0 +1 @@ +Subproject commit 73f4a4091d580cf180d01fb9c598fe0e55067ca0 diff --git a/Sming/Libraries/AnimatedGIF/README.rst b/Sming/Libraries/AnimatedGIF/README.rst new file mode 100644 index 0000000000..cf386681e7 --- /dev/null +++ b/Sming/Libraries/AnimatedGIF/README.rst @@ -0,0 +1,50 @@ +AnimatedGIF +=========== + +.. highlight:: c++ + +Introduction +------------ + +AnimatedGIF is an optimized library for playing animated GIFs on embedded devices. + +Features +-------- + +- Supports any MCU with at least 24K of RAM (Cortex-M0+ is the simplest I've tested). +- Optimized for speed; the main limitation will be how fast you can copy the pixels to the display. You can use SPI+DMA to help. +- GIF image data can come from memory (FLASH/RAM), SDCard or any media you provide. +- GIF files can be any length, (e.g. hundreds of megabytes) +- Simple C++ class and callback design allows you to easily add GIF support to any application. +- The C code doing the heavy lifting is completely portable and has no external dependencies. +- Does not use dynamic memory (malloc/free/new/delete), so it's easy to build it for a minimal bare metal system. + + +Using +----- + +1. Add ``COMPONENT_DEPENDS += AnimatedGIF`` to your application componenent.mk file. +2. Add these lines to your application:: + + #include + + namespace + { + AnimatedGifTask* task; + + // ... + + } // namespace + + void init() + { + // ... + + initDisplay(); + tft.setOrientation(Graphics::Orientation::deg270); + + auto surface = tft.createSurface(); + assert(surface != nullptr); + task = new AnimatedGifTask(*surface, gifData); + task->resume(); + } diff --git a/Sming/Libraries/AnimatedGIF/component.mk b/Sming/Libraries/AnimatedGIF/component.mk new file mode 100644 index 0000000000..d414a3106d --- /dev/null +++ b/Sming/Libraries/AnimatedGIF/component.mk @@ -0,0 +1,6 @@ +COMPONENT_SUBMODULES := AnimatedGIF + +COMPONENT_DEPENDS := Graphics + +COMPONENT_SRCDIRS := src $(COMPONENT_SUBMODULES)/src +COMPONENT_INCDIRS := $(COMPONENT_SRCDIRS) diff --git a/Sming/Libraries/AnimatedGIF/samples/Basic_AnimatedGIF/Makefile b/Sming/Libraries/AnimatedGIF/samples/Basic_AnimatedGIF/Makefile new file mode 100644 index 0000000000..ff51b6c3a7 --- /dev/null +++ b/Sming/Libraries/AnimatedGIF/samples/Basic_AnimatedGIF/Makefile @@ -0,0 +1,9 @@ +##################################################################### +#### Please don't change this file. Use component.mk instead #### +##################################################################### + +ifndef SMING_HOME +$(error SMING_HOME is not set: please configure it as an environment variable) +endif + +include $(SMING_HOME)/project.mk diff --git a/Sming/Libraries/AnimatedGIF/samples/Basic_AnimatedGIF/README.rst b/Sming/Libraries/AnimatedGIF/samples/Basic_AnimatedGIF/README.rst new file mode 100644 index 0000000000..cc5015a9b8 --- /dev/null +++ b/Sming/Libraries/AnimatedGIF/samples/Basic_AnimatedGIF/README.rst @@ -0,0 +1,12 @@ +Basic AnimatedGIF +================= + +Sample demonstating the usage of the optimized :library:`AnimatedGIF` library +together with :library:`Graphics` library. + +You should be able to see the following animated image: + +.. image:: files/frog.gif + :height: 235px + +Image source: `Animated Images Dot Org `__. \ No newline at end of file diff --git a/Sming/Libraries/AnimatedGIF/samples/Basic_AnimatedGIF/app/.cs b/Sming/Libraries/AnimatedGIF/samples/Basic_AnimatedGIF/app/.cs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Sming/Libraries/AnimatedGIF/samples/Basic_AnimatedGIF/app/application.cpp b/Sming/Libraries/AnimatedGIF/samples/Basic_AnimatedGIF/app/application.cpp new file mode 100644 index 0000000000..baa14325ae --- /dev/null +++ b/Sming/Libraries/AnimatedGIF/samples/Basic_AnimatedGIF/app/application.cpp @@ -0,0 +1,25 @@ +#include +#include +#include + +namespace +{ +AnimatedGifTask* task; + +IMPORT_FSTR(gifData, PROJECT_DIR "/files/frog.gif") + +} // namespace + +void init() +{ + Serial.begin(SERIAL_BAUD_RATE); + Serial.systemDebugOutput(true); + + initDisplay(); + tft.setOrientation(Graphics::Orientation::deg270); + + auto surface = tft.createSurface(); + assert(surface != nullptr); + task = new AnimatedGifTask(*surface, gifData); + task->resume(); +} diff --git a/Sming/Libraries/AnimatedGIF/samples/Basic_AnimatedGIF/component.mk b/Sming/Libraries/AnimatedGIF/samples/Basic_AnimatedGIF/component.mk new file mode 100644 index 0000000000..234d9bef96 --- /dev/null +++ b/Sming/Libraries/AnimatedGIF/samples/Basic_AnimatedGIF/component.mk @@ -0,0 +1,6 @@ +## If project doesn't require networking, saves RAM and build time +DISABLE_NETWORK := 1 +COMPONENT_DEPENDS := AnimatedGIF + +COMPONENT_DOCFILES := files/frog.gif + diff --git a/Sming/Libraries/AnimatedGIF/samples/Basic_AnimatedGIF/files/frog.gif b/Sming/Libraries/AnimatedGIF/samples/Basic_AnimatedGIF/files/frog.gif new file mode 100644 index 0000000000..cad08a4ab4 Binary files /dev/null and b/Sming/Libraries/AnimatedGIF/samples/Basic_AnimatedGIF/files/frog.gif differ diff --git a/Sming/Libraries/AnimatedGIF/src/.cs b/Sming/Libraries/AnimatedGIF/src/.cs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Sming/Libraries/AnimatedGIF/src/AnimatedGifTask.cpp b/Sming/Libraries/AnimatedGIF/src/AnimatedGifTask.cpp new file mode 100644 index 0000000000..36b63e4179 --- /dev/null +++ b/Sming/Libraries/AnimatedGIF/src/AnimatedGifTask.cpp @@ -0,0 +1,138 @@ +/**** + * AnimatedGifTask.cpp + * + * This library is free software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, version 3 or later. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this library. + * If not, see . + * + * @author: Feb 2022 - Slavey Karadzhov + * + ****/ + +#include "AnimatedGifTask.h" + +void draw(GIFDRAW* pDraw) +{ + auto surface = static_cast(pDraw->pUser); + if(surface == nullptr) { + return; + } + + const auto& tftSize = surface->getSize(); + const int DISPLAY_WIDTH = tftSize.w; + const int DISPLAY_HEIGHT = tftSize.h; + + auto pixelFormat = surface->getPixelFormat(); + auto bytesPerPixel = Graphics::getBytesPerPixel(pixelFormat); + + uint16_t usTemp[DISPLAY_WIDTH]; + Graphics::SharedBuffer buffer(bytesPerPixel * DISPLAY_WIDTH); + + int iWidth = pDraw->iWidth; + if(iWidth + pDraw->iX > DISPLAY_WIDTH) { + iWidth = DISPLAY_WIDTH - pDraw->iX; + } + const uint16_t* usPalette = pDraw->pPalette; + int y = pDraw->iY + pDraw->y; // current line + if(y >= DISPLAY_HEIGHT || pDraw->iX >= DISPLAY_WIDTH || iWidth < 1) { + return; + } + + auto s = pDraw->pPixels; + if(pDraw->ucDisposalMethod == 2) // restore to background color + { + for(int x = 0; x < iWidth; x++) { + if(s[x] == pDraw->ucTransparent) { + s[x] = pDraw->ucBackground; + } + } + pDraw->ucHasTransparency = 0; + } + + // Apply the new pixels to the main image + if(pDraw->ucHasTransparency) // if transparency used + { + uint8_t ucTransparent = pDraw->ucTransparent; + uint8_t* pEnd = s + iWidth; + int x = 0; + int iCount = 0; // count non-transparent pixels + while(x < iWidth) { + uint8_t c = ucTransparent - 1; + uint16_t* d = usTemp; + while(c != ucTransparent && s < pEnd) { + c = *s++; + if(c == ucTransparent) { + // done, stop: back up to treat it like transparent + s--; + } else { + // opaque + *d++ = __builtin_bswap16(usPalette[c]); + iCount++; + } + } // while looking for opaque pixels + if(iCount != 0) // any opaque pixels? + { + Graphics::convert(usTemp, Graphics::PixelFormat::RGB565, buffer.get(), pixelFormat, iCount); + Graphics::Rect r(pDraw->iX + x, y, iCount, 1); + surface->reset(); + surface->setAddrWindow(r); + surface->writeDataBuffer(buffer, 0, iCount * bytesPerPixel); + surface->present(); + x += iCount; + iCount = 0; + } + // no, look for a run of transparent pixels + c = ucTransparent; + while(c == ucTransparent && s < pEnd) { + c = *s++; + if(c == ucTransparent) { + iCount++; + } else { + s--; + } + } + if(iCount != 0) { + // skip these + x += iCount; + iCount = 0; + } + } + } else { + // No transparency + s = pDraw->pPixels; + // Translate the 8-bit pixels through the RGB565 palette (already byte reversed) + for(int x = 0; x < iWidth; x++) { + usTemp[x] = __builtin_bswap16(usPalette[*s++]); + } + Graphics::convert(usTemp, Graphics::PixelFormat::RGB565, buffer.get(), surface->getPixelFormat(), iWidth); + Graphics::Rect r(pDraw->iX, y, iWidth, 1); + surface->reset(); + surface->setAddrWindow(r); + surface->writeDataBuffer(buffer, 0, iWidth * bytesPerPixel); + surface->present(); + } +} + +AnimatedGifTask::AnimatedGifTask(Graphics::Surface& surface, const void* data, size_t length, bool inFlash) + : surface(surface) +{ + auto ptr = static_cast(const_cast(data)); + if(inFlash) { + gif.openFLASH(ptr, length, draw); + } else { + gif.open(ptr, length, draw); + } +} + +void AnimatedGifTask::loop() +{ + gif.playFrame(true, nullptr, &surface); + // To slow frames down or reduce load... + // sleep(100); +} diff --git a/Sming/Libraries/AnimatedGIF/src/AnimatedGifTask.h b/Sming/Libraries/AnimatedGIF/src/AnimatedGifTask.h new file mode 100644 index 0000000000..218ed72ea7 --- /dev/null +++ b/Sming/Libraries/AnimatedGIF/src/AnimatedGifTask.h @@ -0,0 +1,45 @@ +/**** + * AnimatedGifTask.h + * + * This library is free software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, version 3 or later. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this library. + * If not, see . + * + * @author: Feb 2022 - Slavey Karadzhov + * + ****/ + +#pragma once + +#include +#include +#include + +class AnimatedGifTask : public Task +{ +public: + AnimatedGifTask(Graphics::Surface& surface, const void* data, size_t length, bool inFlash); + + AnimatedGifTask(Graphics::Surface& surface, const FSTR::ObjectBase& data) + : AnimatedGifTask(surface, data.data(), data.length(), true) + { + } + + ~AnimatedGifTask() + { + gif.close(); + } + +protected: + void loop() override; + +private: + AnimatedGIF gif; + Graphics::Surface& surface; +}; diff --git a/Sming/Libraries/AtClient/README.rst b/Sming/Libraries/AtClient/README.rst new file mode 100644 index 0000000000..1b37edde1b --- /dev/null +++ b/Sming/Libraries/AtClient/README.rst @@ -0,0 +1,41 @@ +At Client +========= + +.. highlight:: c++ + +Introduction +------------ + +AT commands were initially instructions used to control a modem. AT is the abbreviation of ATtention. +Every command line starts with "AT" or "at". +If interested a good background article is `Hayes Command Set `__. + +Nowadays also other devices allow communication via AT commands as for example GSM/GPRS modems, GPS trackers, web cameras and more. + +This library simplifies the communication with such devices. + +Usage +----- + +1. Add ``COMPONENT_DEPENDS += AtClient`` to your application componenent.mk file. +2. Add these lines to your application:: + + #include + + namespace + { + AtClient* atClient; + + // ... + + } // namespace + + void init() + { + Serial.begin(SERIAL_BAUD_RATE); + Serial.systemDebugOutput(true); + + atClient = new AtClient(Serial); + atClient->send("ATE0\r"); + // ... + } \ No newline at end of file diff --git a/Sming/Libraries/AtClient/component.mk b/Sming/Libraries/AtClient/component.mk new file mode 100644 index 0000000000..8d771139b9 --- /dev/null +++ b/Sming/Libraries/AtClient/component.mk @@ -0,0 +1,2 @@ +COMPONENT_SRCDIRS := src +COMPONENT_INCDIRS := $(COMPONENT_SRCDIRS) \ No newline at end of file diff --git a/Sming/Libraries/AtClient/samples/Webcam/Makefile b/Sming/Libraries/AtClient/samples/Webcam/Makefile new file mode 100644 index 0000000000..ff51b6c3a7 --- /dev/null +++ b/Sming/Libraries/AtClient/samples/Webcam/Makefile @@ -0,0 +1,9 @@ +##################################################################### +#### Please don't change this file. Use component.mk instead #### +##################################################################### + +ifndef SMING_HOME +$(error SMING_HOME is not set: please configure it as an environment variable) +endif + +include $(SMING_HOME)/project.mk diff --git a/Sming/Libraries/AtClient/samples/Webcam/README.rst b/Sming/Libraries/AtClient/samples/Webcam/README.rst new file mode 100644 index 0000000000..49dd397f07 --- /dev/null +++ b/Sming/Libraries/AtClient/samples/Webcam/README.rst @@ -0,0 +1,7 @@ +Webcam +====== + +Sample demonstrating communication with a web camera via AT commands using :library:`AtClient` library. +The complete set of commands for the sample web camera are in the docs/ directory. + +More about the web camera module and commands can be found `here `__. \ No newline at end of file diff --git a/Sming/Libraries/AtClient/samples/Webcam/app/.cs b/Sming/Libraries/AtClient/samples/Webcam/app/.cs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Sming/Libraries/AtClient/samples/Webcam/app/application.cpp b/Sming/Libraries/AtClient/samples/Webcam/app/application.cpp new file mode 100644 index 0000000000..8bbeefe1da --- /dev/null +++ b/Sming/Libraries/AtClient/samples/Webcam/app/application.cpp @@ -0,0 +1,56 @@ +#include +#include + +AtClient* atClient; + +namespace +{ +int pictureSize; + +bool processSize(AtClient& atClient, String& reply) +{ + /* + * ================ + AT+CAMCAP capture picture + Set Command: + Capture and store a Picture local and returns bytes of captured picture + AT+CAMCAP + +CAMCAP: + OK + on error: + +CME ERROR: + * ================ + */ + if(reply.indexOf("+CME ERROR") == 0) { + debug_e("Unable to capture image"); + return false; + } + + // Read the size of the captured image + String length = reply.substring(8); + pictureSize = atoi(length.c_str()); + + debug_d("Picture size: %d", pictureSize); + + return true; +} + +} // namespace + +void init() +{ + Serial.begin(SERIAL_BAUD_RATE); + Serial.systemDebugOutput(true); + Serial.swap(); //swap to GPIO13 and GPIO15 + + atClient = new AtClient(Serial); + + // The commands below will be queued and executed + // in the same order as defined below. + // One command needs to finish successfully in order for the next one to start. + atClient->send("ATE0\r"); + atClient->send("AT+CAMSTOP\r"); + + atClient->send("AT+CAMSTART=1\r"); + atClient->send("AT+CAMCAP\r", processSize); +} diff --git a/Sming/Libraries/AtClient/samples/Webcam/component.mk b/Sming/Libraries/AtClient/samples/Webcam/component.mk new file mode 100644 index 0000000000..23b6d42689 --- /dev/null +++ b/Sming/Libraries/AtClient/samples/Webcam/component.mk @@ -0,0 +1,3 @@ +## If project doesn't require networking, saves RAM and build time +DISABLE_NETWORK := 1 +COMPONENT_DEPENDS := AtClient diff --git a/Sming/Libraries/AtClient/samples/Webcam/docs/A6-a7-a6c-at-v102.pdf b/Sming/Libraries/AtClient/samples/Webcam/docs/A6-a7-a6c-at-v102.pdf new file mode 100644 index 0000000000..c59c767db9 Binary files /dev/null and b/Sming/Libraries/AtClient/samples/Webcam/docs/A6-a7-a6c-at-v102.pdf differ diff --git a/Sming/Libraries/AtClient/src/.cs b/Sming/Libraries/AtClient/src/.cs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Sming/Core/AtClient.cpp b/Sming/Libraries/AtClient/src/AtClient.cpp similarity index 67% rename from Sming/Core/AtClient.cpp rename to Sming/Libraries/AtClient/src/AtClient.cpp index 8a278d4805..fa4a45056a 100644 --- a/Sming/Core/AtClient.cpp +++ b/Sming/Libraries/AtClient/src/AtClient.cpp @@ -12,15 +12,13 @@ ****/ #include "AtClient.h" -#include "Clock.h" -#ifndef debugf -#define debugf(fmt, ...) -#endif +#include +#include -AtClient::AtClient(HardwareSerial* stream) : stream(stream) +AtClient::AtClient(HardwareSerial& stream) : stream(stream) { - this->stream->onDataReceived(StreamDataReceivedDelegate(&AtClient::processor, this)); + stream.onDataReceived(StreamDataReceivedDelegate(&AtClient::processor, this)); } void AtClient::processor(Stream& source, char arrivedChar, uint16_t availableCharsCount) @@ -29,7 +27,7 @@ void AtClient::processor(Stream& source, char arrivedChar, uint16_t availableCha return; } - if(state == eAtError) { + if(state == State::Error) { // discard input at error state return; } @@ -46,17 +44,17 @@ void AtClient::processor(Stream& source, char arrivedChar, uint16_t availableCha } commandTimer.stop(); - debugf("Processing: %d ms, %s", millis(), currentCommand.text.substring(0, 20).c_str()); + debug_d("Processing: %d ms, %s", millis(), currentCommand.text.substring(0, 20).c_str()); char response[availableCharsCount]; for(int i = 0; i < availableCharsCount; i++) { - response[i] = stream->read(); + response[i] = stream.read(); if(response[i] == '\r' || response[i] == '\n') { response[i] = '\0'; } } - debugf("Got response: %s", response); + debug_d("Got response: %s", response); String reply(response); if(reply.indexOf(AT_REPLY_OK) + reply.indexOf(currentCommand.response2) == -2) { @@ -67,7 +65,7 @@ void AtClient::processor(Stream& source, char arrivedChar, uint16_t availableCha } if(currentCommand.breakOnError) { - state = eAtError; + state = State::Error; return; } } @@ -83,7 +81,7 @@ void AtClient::processor(Stream& source, char arrivedChar, uint16_t availableCha void AtClient::send(const String& text, const String& altResponse, uint32_t timeoutMs, unsigned retries) { - AtCommand atCommand; + Command atCommand; atCommand.text = text; atCommand.response2 = altResponse; atCommand.timeout = timeoutMs; @@ -92,9 +90,9 @@ void AtClient::send(const String& text, const String& altResponse, uint32_t time send(atCommand); } -void AtClient::send(const String& text, AtReceiveCallback onReceive, uint32_t timeoutMs, unsigned retries) +void AtClient::send(const String& text, ReceiveCallback onReceive, uint32_t timeoutMs, unsigned retries) { - AtCommand atCommand; + Command atCommand; atCommand.text = text; atCommand.onReceive = onReceive; atCommand.timeout = timeoutMs; @@ -103,9 +101,9 @@ void AtClient::send(const String& text, AtReceiveCallback onReceive, uint32_t ti send(atCommand); } -void AtClient::send(const String& text, AtCompleteCallback onComplete, uint32_t timeoutMs, unsigned retries) +void AtClient::send(const String& text, CompleteCallback onComplete, uint32_t timeoutMs, unsigned retries) { - AtCommand atCommand; + Command atCommand; atCommand.text = text; atCommand.onComplete = onComplete; atCommand.timeout = timeoutMs; @@ -116,7 +114,7 @@ void AtClient::send(const String& text, AtCompleteCallback onComplete, uint32_t // Low Level Communication Functions -void AtClient::send(AtCommand command) +void AtClient::send(Command command) { if(currentCommand.text.length()) { queue.enqueue(command); @@ -126,21 +124,21 @@ void AtClient::send(AtCommand command) sendDirect(command); } -void AtClient::sendDirect(AtCommand command) +void AtClient::sendDirect(Command command) { - state = eAtRunning; + state = State::Running; commandTimer.stop(); currentCommand = command; - stream->print(command.text); - debugf("Sent: timeout: %d, current %d ms, name: %s", currentCommand.timeout, millis(), - command.text.substring(0, 20).c_str()); + stream.print(command.text); + debug_d("Sent: timeout: %d, current %d ms, name: %s", currentCommand.timeout, millis(), + command.text.substring(0, 20).c_str()); commandTimer.initializeMs(currentCommand.timeout, TimerDelegate(&AtClient::ticker, this)).startOnce(); } // Low Level Queue Functions void AtClient::resend() { - state = eAtOK; + state = State::OK; if(currentCommand.text.length()) { sendDirect(currentCommand); return; @@ -151,12 +149,12 @@ void AtClient::resend() void AtClient::next() { - if(state == eAtError) { - debugf("We are at error state! No next"); + if(state == State::Error) { + debug_e("We are at error state! No next"); return; } - state = eAtOK; + state = State::OK; currentCommand.text = ""; if(queue.count() > 0) { send(queue.dequeue()); @@ -165,22 +163,22 @@ void AtClient::next() void AtClient::ticker() { - debugf("Ticker =================> "); + debug_d("Ticker =================> "); if(!currentCommand.text.length()) { commandTimer.stop(); - debugf("Error: Timeout without command?!"); + debug_e("Error: Timeout without command?!"); return; } currentCommand.retries--; - debugf("Retries: %d", currentCommand.retries); + debug_d("Retries: %d", currentCommand.retries); if(currentCommand.retries > 0) { commandTimer.restart(); sendDirect(currentCommand); return; } - state = eAtError; + state = State::Error; - debugf("Timeout: %d ms, %s", millis(), currentCommand.text.c_str()); + debug_d("Timeout: %d ms, %s", millis(), currentCommand.text.c_str()); } diff --git a/Sming/Core/AtClient.h b/Sming/Libraries/AtClient/src/AtClient.h similarity index 58% rename from Sming/Core/AtClient.h rename to Sming/Libraries/AtClient/src/AtClient.h index b423798fca..b00656149c 100644 --- a/Sming/Core/AtClient.h +++ b/Sming/Libraries/AtClient/src/AtClient.h @@ -15,52 +15,50 @@ #pragma once -#include "HardwareSerial.h" -#include "FIFO.h" -#include "Timer.h" +#include +#include +#include #define AT_REPLY_OK "OK" #ifndef AT_TIMEOUT #define AT_TIMEOUT 2000 #endif -class AtClient; - -/** - * @brief If the callback returns true then this means that we have - * finished successfully processing the command - */ -using AtReceiveCallback = Delegate; - -/** - * @brief If the callback returns true then this means that we have - * finished successfully processing the command - */ -using AtCompleteCallback = Delegate; - -struct AtCommand { - String text; ///< the actual AT command - String response2; ///< alternative successful response - unsigned timeout; ///< timeout in milliseconds - unsigned retries; ///< number of retries before giving up - bool breakOnError = true; ///< stop executing next command if that one has failed - AtReceiveCallback onReceive; ///< if set you can process manually all incoming data in a callback - AtCompleteCallback onComplete; ///< if set then you can process the complete response manually -}; - -enum AtState { - eAtOK = 0, - eAtRunning, - eAtError, -}; - /** * @brief Class that facilitates the communication with an AT device. */ class AtClient { public: - AtClient(HardwareSerial* stream); + /** + * @brief If the callback returns true then this means that we have + * finished successfully processing the command + */ + using ReceiveCallback = Delegate; + + /** + * @brief If the callback returns true then this means that we have + * finished successfully processing the command + */ + using CompleteCallback = Delegate; + + struct Command { + String text; ///< the actual AT command + String response2; ///< alternative successful response + unsigned timeout; ///< timeout in milliseconds + unsigned retries; ///< number of retries before giving up + bool breakOnError = true; ///< stop executing next command if that one has failed + ReceiveCallback onReceive; ///< if set you can process manually all incoming data in a callback + CompleteCallback onComplete; ///< if set then you can process the complete response manually + }; + + enum class State { + OK = 0, + Running, + Error, + }; + + AtClient(HardwareSerial& stream); virtual ~AtClient() { @@ -83,7 +81,7 @@ class AtClient * @param timeoutMs Time in milliseconds to wait for response * @param retries Retries on error */ - void send(const String& text, AtReceiveCallback onReceive, uint32_t timeoutMs = AT_TIMEOUT, unsigned retries = 0); + void send(const String& text, ReceiveCallback onReceive, uint32_t timeoutMs = AT_TIMEOUT, unsigned retries = 0); /** * @brief Sends AT command @@ -92,7 +90,7 @@ class AtClient * @param timeoutMs Time in milliseconds to wait for response * @param retries Retries on error */ - void send(const String& text, AtCompleteCallback onComplete, uint32_t timeoutMs = AT_TIMEOUT, unsigned retries = 0); + void send(const String& text, CompleteCallback onComplete, uint32_t timeoutMs = AT_TIMEOUT, unsigned retries = 0); // Low Level Functions @@ -102,19 +100,19 @@ class AtClient * and manually set your AtCommand arguments. * @param command */ - void send(AtCommand command); + void send(Command command); /** * @brief Executes directly (does not queue it) a command * @param command */ - void sendDirect(AtCommand command); + void sendDirect(Command command); /** * @brief Returns the current state * @retval AtState */ - AtState getState() + State getState() { return state; } @@ -130,7 +128,7 @@ class AtClient */ void next(); - AtCommand currentCommand; ///< The current command + Command currentCommand; ///< The current command protected: /** @@ -139,10 +137,10 @@ class AtClient virtual void processor(Stream& source, char arrivedChar, uint16_t availableCharsCount); private: - FIFO queue; ///< Queue for the commands to be executed - HardwareSerial* stream = nullptr; ///< The main communication stream - Timer commandTimer; ///< timer used for commands with timeout - AtState state = eAtOK; + FIFO queue; ///< Queue for the commands to be executed + HardwareSerial& stream; ///< The main communication stream + Timer commandTimer; ///< timer used for commands with timeout + State state = State::OK; /** * @brief Timeout checker method @@ -151,7 +149,7 @@ class AtClient }; /** - * @code AtClient camera(&Serial); + * @code AtClient camera(Serial); * camera("ATE0\r"); * camera("AT+CAMSTOP\r"); * diff --git a/Sming/Libraries/Graphics b/Sming/Libraries/Graphics index 98da456e43..999ebaeb17 160000 --- a/Sming/Libraries/Graphics +++ b/Sming/Libraries/Graphics @@ -1 +1 @@ -Subproject commit 98da456e4338153d779bca64b6ac7d56ee9b80c4 +Subproject commit 999ebaeb177e14a2a592fb1fd70bcfe421c2019f diff --git a/Sming/Libraries/HardwareSPI b/Sming/Libraries/HardwareSPI index ae5efe4d99..09b9327dba 160000 --- a/Sming/Libraries/HardwareSPI +++ b/Sming/Libraries/HardwareSPI @@ -1 +1 @@ -Subproject commit ae5efe4d990340654baa399dba0c9e54203ec5eb +Subproject commit 09b9327dba3dc40ca276b0c3612e1e48602cab4a diff --git a/Sming/Libraries/IOControl b/Sming/Libraries/IOControl new file mode 160000 index 0000000000..48a5f8ef43 --- /dev/null +++ b/Sming/Libraries/IOControl @@ -0,0 +1 @@ +Subproject commit 48a5f8ef43ce20452090ad79893f0b0735607828 diff --git a/Sming/Libraries/LittleFS b/Sming/Libraries/LittleFS index 7e3ffdc7df..804705b99f 160000 --- a/Sming/Libraries/LittleFS +++ b/Sming/Libraries/LittleFS @@ -1 +1 @@ -Subproject commit 7e3ffdc7dffca6c2139bf090bac50e0aa8ce399d +Subproject commit 804705b99f95e5297fa193ad3c5aff12f32f1ec0 diff --git a/Sming/Libraries/MultipartParser/samples/Conditional_Upload/component.mk b/Sming/Libraries/MultipartParser/samples/Conditional_Upload/component.mk index aafe73766e..04d1bd4842 100644 --- a/Sming/Libraries/MultipartParser/samples/Conditional_Upload/component.mk +++ b/Sming/Libraries/MultipartParser/samples/Conditional_Upload/component.mk @@ -1,4 +1,4 @@ -HWCONFIG := spiffs +HWCONFIG := spiffs-2m SPIFF_FILES = web/ ARDUINO_LIBRARIES := MultipartParser diff --git a/Sming/Libraries/Ota/component.mk b/Sming/Libraries/Ota/component.mk index d5939e6287..964bde20cb 100644 --- a/Sming/Libraries/Ota/component.mk +++ b/Sming/Libraries/Ota/component.mk @@ -1,3 +1,5 @@ +COMPONENT_SOC = esp* host + COMPONENT_ARCH := $(SMING_ARCH) ifeq ($(COMPONENT_ARCH),Host) COMPONENT_ARCH := Esp8266 diff --git a/Sming/Libraries/OtaUpgradeMqtt/samples/Upgrade/component.mk b/Sming/Libraries/OtaUpgradeMqtt/samples/Upgrade/component.mk index 7b087c1768..b396b06b89 100644 --- a/Sming/Libraries/OtaUpgradeMqtt/samples/Upgrade/component.mk +++ b/Sming/Libraries/OtaUpgradeMqtt/samples/Upgrade/component.mk @@ -1,4 +1,5 @@ ## User configurable settings +COMPONENT_SOC = esp* host ## [Application id and version] ## # Application id diff --git a/Sming/Libraries/SDCard/SDCard.cpp b/Sming/Libraries/SDCard/SDCard.cpp index 05f0d3952b..804a709f8c 100644 --- a/Sming/Libraries/SDCard/SDCard.cpp +++ b/Sming/Libraries/SDCard/SDCard.cpp @@ -61,7 +61,6 @@ bool SDCard_begin(uint8_t slaveSelect, uint32_t freqLimit) auto& settings = SDCardSPI->SPIDefaultSettings; - settings.byteOrder = LSBFIRST; settings.dataMode = SPI_MODE0; spiInitFreq = 1000000U; @@ -347,7 +346,7 @@ DSTATUS disk_initialize(BYTE drv /* Physical drive nmuber (0) */ return RES_NOTRDY; } - SPISettings initSettings(spiInitFreq, LSBFIRST, SPI_MODE0); + SPISettings initSettings(spiInitFreq, MSBFIRST, SPI_MODE0); SDCardSPI->beginTransaction(initSettings); dly_us(10000); diff --git a/Sming/Libraries/SPI/Kconfig b/Sming/Libraries/SPI/Kconfig new file mode 100644 index 0000000000..c67cb3a671 --- /dev/null +++ b/Sming/Libraries/SPI/Kconfig @@ -0,0 +1,18 @@ +menu "SPI Library" + config SPISOFT_DELAY_VARIABLE + bool "Variable clock delay" + default N + + config SPISOFT_DELAY_FIXED + int "Fixed clock delay" + default 0 + range 0 12 + depends on !SPISOFT_DELAY_VARIABLE + help + Inserts one CPU 'nop' instruction after every SCK transition + + config ENABLE_SPI_DEBUG + bool "Enable SPI debug output" + default N + +endmenu diff --git a/Sming/Libraries/SPI/README.rst b/Sming/Libraries/SPI/README.rst new file mode 100644 index 0000000000..d671c1a09a --- /dev/null +++ b/Sming/Libraries/SPI/README.rst @@ -0,0 +1,33 @@ +SPI Library +=========== + +Provides support for both hardware and software-base SPI master devices. + +.. toctree:: + :glob: + + * + + +Build variables +--------------- + +.. envvar:: ENABLE_SPI_DEBUG + + default: 0 (disabled) + + Enable to print additional debug messages. + + +API Documentation +----------------- + +.. doxygengroup:: base_spi + :content-only: + :members: + + +.. doxygengroup:: hw_spi + :content-only: + :members: + diff --git a/Sming/Libraries/SPI/component.mk b/Sming/Libraries/SPI/component.mk new file mode 100644 index 0000000000..a4d8ef30bf --- /dev/null +++ b/Sming/Libraries/SPI/component.mk @@ -0,0 +1,26 @@ +COMPONENT_SRCDIRS := \ + src \ + src/Arch/$(SMING_ARCH) + +COMPONENT_INCDIRS := $(COMPONENT_SRCDIRS) + +COMPONENT_DOXYGEN_INPUT := src + +# +COMPONENT_RELINK_VARS += SPISOFT_DELAY_FIXED +SPISOFT_DELAY_FIXED ?= 0 +COMPONENT_CPPFLAGS := -DSPISOFT_DELAY_FIXED=$(SPISOFT_DELAY_FIXED) + +# +COMPONENT_RELINK_VARS += SPISOFT_DELAY_VARIABLE +SPISOFT_DELAY_VARIABLE ?= 0 +ifeq ($(SPISOFT_DELAY_VARIABLE),1) +COMPONENT_CPPFLAGS := -DSPISOFT_DELAY_VARIABLE=1 +endif + +# +COMPONENT_VARS += ENABLE_SPI_DEBUG +ENABLE_SPI_DEBUG ?= 0 +ifeq ($(ENABLE_SPI_DEBUG),1) +GLOBAL_CFLAGS += -DSPI_DEBUG=1 +endif diff --git a/Sming/Libraries/SPI/spisoft-160.png b/Sming/Libraries/SPI/spisoft-160.png new file mode 100644 index 0000000000..5cc19ac73b Binary files /dev/null and b/Sming/Libraries/SPI/spisoft-160.png differ diff --git a/Sming/Libraries/SPI/spisoft-80.png b/Sming/Libraries/SPI/spisoft-80.png new file mode 100644 index 0000000000..420246f4e8 Binary files /dev/null and b/Sming/Libraries/SPI/spisoft-80.png differ diff --git a/Sming/Libraries/SPI/spisoft.ods b/Sming/Libraries/SPI/spisoft.ods new file mode 100644 index 0000000000..fe4b02bf7b Binary files /dev/null and b/Sming/Libraries/SPI/spisoft.ods differ diff --git a/Sming/Libraries/SPI/spisoft.rst b/Sming/Libraries/SPI/spisoft.rst new file mode 100644 index 0000000000..fbcc2edc78 --- /dev/null +++ b/Sming/Libraries/SPI/spisoft.rst @@ -0,0 +1,146 @@ +Software SPI +=========== + +Software SPI is likely to be of use only for ESP8266, but is enabled for all architectures. + +The ESP8266 can manage a minimum of about 70ns between bit edges, with a maximum of +about 1.8 MBit/s at normal CPU clock frequency or 2.5 MHz if CPU clock set to fast. + + +Build variables +--------------- + +.. envvar:: SPISOFT_DELAY_VARIABLE + + default: 0 (disabled) + + This setting must be enabled in order to use :cpp:func:`SPISoft::setDelay`. + The base clock speed (i.e. delay=0) is reduced to about 1.4 MBit/s (2.1 MBit/s for fast CPU). + + The appropriate delay factor can be provided in the :cpp:class:`SPISoft` constructor, + or by calling :cpp:func:`SPISoft::setDelay`. + + With the ESP8266, then the appropriate delay factor is calculated automatically from + the speed passed in :cpp:class:`SPISettings`. + This will override any previously set delay factor. + Use a speed of 0 to use the manually configured delay value. + + +.. envvar:: SPISOFT_DELAY_FIXED + + default: 0 (disabled) + maximum: 10 + + Adds the requested number of 'NOP' CPU instructions to every clock transition. + + Has less impact than enabling variable delays. + + Use variable delays if 10 is insufficient. + + Will be ignored if variable delays are enabled. + + +Performance +----------- + +The following information has been obtained by measurement. +The test application was built using: + +.. code-block:: bash + + make SPISOFT_CALIBRATE=1 SPISOFT_DELAY_VARIABLE=1 CPU_FAST=0 + +then flashed to an ESP-12F. An oscilliscope was hooked up to the SCK output +and the maximum frequency at each delay setting noted. +(Not too awkward, just note down the frequency each time the figure changes.) + +Entering these into the `spisoft.ods` spreadsheet allows the values to be charted and +co-efficients calculated. + +Curiously values from 8 upward form a straight line so we can calculate those. +Smaller values are non-linear so a small lookup table is used. + +Repeat for `CPU_FAST=1`. + +Note that these figures are concerned with *maximum* (i.e. burst) frequencies +at each delay setting, since that is what devices are sensitive to. + + +80 MHz CPU +~~~~~~~~~~ + +.. image:: spisoft-80.png + +======= ========== ======= +. Frequency (kHz) +------- ------------------- +Delay Variable Fixed +======= ========== ======= +0 1357 2288 +1 1315 1869 +2 1215 1824 +3 1129 1780 +4 1055 1744 +5 990 1709 +6 932 1639 +7 881 1575 +8 819 1511 +9 743 1462 +10 680 1408 +11 626 1338 +12 578 1294 +20 367 +30 251 +40 192 +50 155 +60 129 +70 112 +80 98 +90 87 +100 79 +======= ========== ======= + + +160 MHz CPU +~~~~~~~~~~~ + +.. image:: spisoft-160.png + +======= ========== ======= +. Frequency (kHz) +------- ------------------- +Delay Variable Fixed +======= ========== ======= +0 2133 2857 +1 2126 2510 +2 2106 2500 +3 1958 2439 +4 1861 2429 +5 1745 2372 +6 1668 2353 +7 1573 2294 +8 1482 2283 +9 1357 2242 +10 1250 2222 +11 1160 2174 +12 1081 2165 +20 702 +30 488 +40 374 +50 303 +60 255 +70 220 +80 193 +90 172 +100 156 +======= ========== ======= + + + +API Documentation +----------------- + +.. doxygengroup:: soft_spi + :content-only: + :members: + diff --git a/Sming/Libraries/SPI/src/Arch/Esp32/SPI.cpp b/Sming/Libraries/SPI/src/Arch/Esp32/SPI.cpp new file mode 100644 index 0000000000..3317529ca7 --- /dev/null +++ b/Sming/Libraries/SPI/src/Arch/Esp32/SPI.cpp @@ -0,0 +1,395 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * SPI.cpp + * + * Created on: Mar 2, 2016 + * Author: harry-boe + * + * Some code is derived from: + * David Ogilvy (MetalPhreak) + * + ****/ + +#include "SPI.h" +#include +#undef FLAG_ATTR +#define FLAG_ATTR(TYPE) +#define typeof decltype +#include +#include +#include +#include +#include + +// Use SPI hardware byte ordering so we don't need to do it in software +#if defined(SOC_ESP32) || defined(SOC_ESP32S2) +#define BYTE_ORDER_SUPPORTED 1 +#define SPI_BYTESWAP(n) (n) +#else +#define BYTE_ORDER_SUPPORTED 0 +#define SPI_BYTESWAP(n) __builtin_bswap32(n) +#endif + +#define GET_DEVICE(err) \ + if(!busAssigned[busId]) { \ + debug_e("[SPI] Not Ready"); \ + return err; \ + } \ + SpiDevice dev{busId}; + +SPIClass SPI; + +namespace +{ +constexpr size_t SPI_FIFO_SIZE{64}; + +const SpiPins defaultPins[]{ + {.sck = SPI_IOMUX_PIN_NUM_CLK, .miso = SPI_IOMUX_PIN_NUM_MISO, .mosi = SPI_IOMUX_PIN_NUM_MOSI}, + {.sck = SPI2_IOMUX_PIN_NUM_CLK, .miso = SPI2_IOMUX_PIN_NUM_MISO, .mosi = SPI2_IOMUX_PIN_NUM_MOSI}, +#ifdef SPI3_IOMUX_PIN_NUM_CLK + {.sck = SPI3_IOMUX_PIN_NUM_CLK, .miso = SPI3_IOMUX_PIN_NUM_MISO, .mosi = SPI3_IOMUX_PIN_NUM_MOSI}, +#else + {.sck = SPI_PIN_DEFAULT, .miso = SPI_PIN_DEFAULT, .mosi = SPI_PIN_DEFAULT}, +#endif +}; + +struct SpiDevice { + const spi_signal_conn_t& info; + + explicit SpiDevice(SpiBus busId) : info(spi_periph_signal[unsigned(busId) - 1]) + { + } + + void init() + { + periph_ll_enable_clk_clear_rst(info.module); + + // Initialise bus + spi_ll_master_init(info.hw); + spi_ll_disable_int(info.hw); + spi_ll_set_mosi_delay(info.hw, 0, 0); + + // Configure full duplex - bi-directdional transfer in MOSI phase + spi_ll_set_half_duplex(info.hw, false); + spi_ll_enable_mosi(info.hw, true); + spi_ll_enable_miso(info.hw, true); + + // We only use data phase, disable the others + spi_ll_set_dummy(info.hw, 0); + spi_ll_set_command_bitlen(info.hw, 0); + spi_ll_set_addr_bitlen(info.hw, 0); + + // Not using any auto. chip selects + spi_ll_master_select_cs(info.hw, -1); + } + + void deinit() + { + periph_ll_disable_clk_set_rst(info.module); + } + + void set_clock(SPISpeed& speed); + + /** + * @brief Wait until SPI has finished any current transaction + */ + void wait() + { + while(info.hw->cmd.usr) { + // + } + } + + /** + * @brief Initiate an SPI user transaction + */ + void send(unsigned num_bits) + { + spi_ll_set_mosi_bitlen(info.hw, num_bits); + spi_ll_set_miso_bitlen(info.hw, num_bits); + spi_ll_master_user_start(info.hw); + } + + void set_mode(SpiMode mode) + { +#ifdef SPI_DEBUG + debugf("[SPI] set_mode(mode %x) cpha %X, cpol %X)", mode, mode & 0x0F, mode & 0xF0); +#endif + spi_ll_master_set_mode(info.hw, SPISettings::getModeNum(mode)); + } + + void set_bit_order(uint8_t bit_order) + { +#ifdef SPI_DEBUG + debugf("[SPI] set_bit_order(bit_order %u)", bit_order); +#endif + decltype(info.hw->ctrl) ctrl; + ctrl.val = info.hw->ctrl.val; + ctrl.rd_bit_order = (bit_order != MSBFIRST); + ctrl.wr_bit_order = (bit_order != MSBFIRST); + info.hw->ctrl.val = ctrl.val; + } + +#if BYTE_ORDER_SUPPORTED + void set_byte_order(uint8_t byte_order) + { + decltype(info.hw->user) user; + user.val = info.hw->user.val; + user.rd_byte_order = (byte_order == MSBFIRST); + user.wr_byte_order = (byte_order == MSBFIRST); + info.hw->user.val = user.val; + } +#endif + + uint32_t read() + { + return info.hw->data_buf[0]; + } + + void write(uint32_t value) + { + info.hw->data_buf[0] = value; + } + + void read(void* buffer, size_t length) + { + if(IS_ALIGNED(buffer) && IS_ALIGNED(length)) { + memcpy(buffer, (void*)info.hw->data_buf, length); + } else { + uint32_t wordBuffer[SPI_FIFO_SIZE]; + memcpy(wordBuffer, (void*)info.hw->data_buf, ALIGNUP4(length)); + memcpy(buffer, wordBuffer, length); + } + } + + void write(const void* buffer, size_t length) + { + if(IS_ALIGNED(buffer)) { + memcpy((void*)info.hw->data_buf, buffer, ALIGNUP4(length)); + } else { + uint32_t wordBuffer[SPI_FIFO_SIZE]; + memcpy(wordBuffer, buffer, length); + memcpy((void*)info.hw->data_buf, wordBuffer, ALIGNUP4(length)); + } + } +}; + +/** @brief Check speed settings and perform any pre-calculation required + * @param speed IN: requested bus frequency, OUT: Modified settings with prescale values + */ +void checkSpeed(SPISpeed& speed) +{ + constexpr int duty_cycle{127}; + spi_ll_clock_val_t clock_reg; + unsigned actual_freq = spi_ll_master_cal_clock(SPI_LL_PERIPH_CLK_FREQ, speed.frequency, duty_cycle, &clock_reg); + speed.regVal = clock_reg; + +#ifdef SPI_DEBUG + debugf("[SPI] target freq = %u, actual = %u", speed.frequency, actual_freq); +#else + (void)actual_freq; +#endif +} + +void SpiDevice::set_clock(SPISpeed& speed) +{ + // Clock register value is never 0, so indicates it hasn't been calculated + if(speed.regVal == 0) { + checkSpeed(speed); + } else { +#ifdef SPI_DEBUG + debugf("[SPI] spi_set_clock(%u)", speed.frequency); +#endif + } + + spi_ll_master_set_clock_by_reg(info.hw, &speed.regVal); +} + +BitSet busAssigned; + +} // namespace + +SPIClass::SPIClass() : SPIBase(defaultPins[unsigned(SpiBus::DEFAULT) - 1]) +{ +} + +bool SPIClass::setup(SpiBus busId, SpiPins pins) +{ + if(busId < SpiBus::MIN || busId > SpiBus::MAX) { + debug_e("[SPI] Invalid bus"); + return false; + } + + if(busAssigned[busId]) { + debug_e("[SPI] Bus #%u already assigned", busId); + return false; + } + + this->busId = busId; + mPins = pins; + return true; +} + +bool SPIClass::begin() +{ + if(busId < SpiBus::MIN || busId > SpiBus::MAX) { + debug_e("[SPI] Invalid bus"); + return false; + } + + if(busAssigned[busId]) { + debug_e("[SPI] Bus #%u already assigned", busId); + return false; + } + + assignDefaultPins(defaultPins[unsigned(busId) - 1]); + + bool pinsOk = true; + if(!GPIO_IS_VALID_OUTPUT_GPIO(pins.sck)) { + debug_e("[SPI] SCK invalid %u", pins.sck); + pinsOk = false; + } + if(!GPIO_IS_VALID_GPIO(pins.mosi)) { + debug_e("[SPI] SCK invalid %u", pins.mosi); + pinsOk = false; + } + if(!GPIO_IS_VALID_GPIO(pins.miso)) { + debug_e("[SPI] MISO invalid %u", pins.miso); + pinsOk = false; + } + if(!pinsOk) { + return false; + } + + busAssigned += busId; + + SpiDevice dev(busId); + dev.init(); + + bool useIomux = (pins.sck == dev.info.spiclk_iomux_pin && pins.miso == dev.info.spiq_iomux_pin && + pins.mosi == dev.info.spid_iomux_pin); + if(useIomux) { + // Use IO Mux + gpio_iomux_in(pins.sck, dev.info.spiclk_in); + gpio_iomux_out(pins.sck, dev.info.func, false); + + gpio_iomux_in(pins.miso, dev.info.spiq_in); + gpio_iomux_out(pins.miso, dev.info.func, false); + + gpio_iomux_in(pins.mosi, dev.info.spid_in); + gpio_iomux_out(pins.mosi, dev.info.func, false); + } else { + // Use GPIO Mux + pinMode(pins.sck, OUTPUT); + gpio_matrix_out(pins.sck, dev.info.spiclk_out, false, false); + + pinMode(pins.miso, INPUT); + gpio_matrix_in(pins.miso, dev.info.spiq_in, false); + + pinMode(pins.mosi, OUTPUT); + gpio_matrix_out(pins.mosi, dev.info.spid_out, false, false); + } + + debug_i("[SPI] Bus #%u using %sIO MUX: SCK %u, MISO %u, MOSI %u", busId, useIomux ? "" : "GP", pins.sck, pins.miso, + pins.mosi); + + checkSpeed(SPIDefaultSettings.speed); + prepare(SPIDefaultSettings); + + return true; +} + +void SPIClass::end() +{ + GET_DEVICE(); + + dev.deinit(); + busAssigned -= busId; +} + +uint32_t SPIClass::transfer32(uint32_t data, uint8_t bits) +{ + GET_DEVICE(0); + + if(!lsbFirst) { + data = SPI_BYTESWAP(data << (32 - bits)); + } + dev.write(data); + dev.send(bits); + dev.wait(); + + data = dev.read(); + if(!lsbFirst) { + data = SPI_BYTESWAP(data) >> (32 - bits); + } + return data; +} + +uint8_t SPIClass::read8() +{ + GET_DEVICE(0); + + dev.write(0xff); + dev.send(8); + dev.wait(); + + return dev.read(); +} + +void SPIClass::transfer(uint8_t* buffer, size_t numberBytes) +{ + GET_DEVICE(); + + // Always transfer LS byte first to match system byte order +#if BYTE_ORDER_SUPPORTED + if(!lsbFirst) { + dev.set_byte_order(LSBFIRST); + } +#endif + + for(unsigned i = 0; i < numberBytes; i += SPI_FIFO_SIZE) { + auto blockLen = std::min(numberBytes - i, SPI_FIFO_SIZE); + + dev.write(&buffer[i], blockLen); + dev.send(blockLen * 8); + dev.wait(); + dev.read(&buffer[i], blockLen); + } + +#if BYTE_ORDER_SUPPORTED + if(!lsbFirst) { + dev.set_byte_order(MSBFIRST); + } +#endif +} + +void SPIClass::prepare(SPISettings& settings) +{ +#ifdef SPI_DEBUG + debugf("[SPI] prepare()"); + settings.print("settings"); +#endif + + GET_DEVICE(); + + dev.set_mode(settings.dataMode); + dev.set_clock(settings.speed); + + // Set both bit and byte order to optimise transfer32() performance + dev.set_bit_order(settings.bitOrder); + lsbFirst = (settings.bitOrder != MSBFIRST); +#if BYTE_ORDER_SUPPORTED + dev.set_byte_order(settings.bitOrder); +#endif +} + +bool SPIClass::loopback(bool enable) +{ + GET_DEVICE(false); + gpio_matrix_in(enable ? pins.mosi : pins.miso, dev.info.spiq_in, false); + return true; +} diff --git a/Sming/Libraries/SPI/src/Arch/Esp32/spi_arch.h b/Sming/Libraries/SPI/src/Arch/Esp32/spi_arch.h new file mode 100644 index 0000000000..6f209ff361 --- /dev/null +++ b/Sming/Libraries/SPI/src/Arch/Esp32/spi_arch.h @@ -0,0 +1,36 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * spi_arch.h - Esp32 + * + * Based on Arduino-esp32 code + * + * https://github.com/espressif/arduino-esp32/blob/master/libraries/SPI/src/SPI.h + * https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-spi.h + */ + +#pragma once + +#include + +/** + * @brief Identifies bus selection + * @ingroup hw_spi + */ +enum class SpiBus { + INVALID = 0, + MIN = 1, + SPI1 = 1, + FSPI = 1, // Attached to the flash (can use the same data lines but different SS) + SPI2 = 2, + HSPI = 2, // Normally mapped to pins 12 - 15, but can be matrixed to any pins +#if SOC_SPI_PERIPH_NUM > 2 + SPI3 = 3, + VSPI = 3, // Normally attached to pins 5, 18, 19 and 23, but can be matrixed to any pins +#endif + MAX = SOC_SPI_PERIPH_NUM, + DEFAULT = SPI2, +}; diff --git a/Sming/Libraries/SPI/src/Arch/Esp32/spisoft_arch.h b/Sming/Libraries/SPI/src/Arch/Esp32/spisoft_arch.h new file mode 100644 index 0000000000..e44856071a --- /dev/null +++ b/Sming/Libraries/SPI/src/Arch/Esp32/spisoft_arch.h @@ -0,0 +1,28 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * softspi_arch.h - Esp32 + * + */ + +#pragma once + +#include +#include +#include + +#define GP_IN(pin) GP_FAST_READ(pin, GPIO_IN_REG) +#define GP_OUT(pin, val) GP_FAST_WRITE(pin, val, GPIO_OUT_W1TC_REG, GPIO_OUT_W1TS_REG) + +namespace spisoft +{ +constexpr SpiPins defaultPins{ + .sck = SPI2_IOMUX_PIN_NUM_CLK, + .miso = SPI2_IOMUX_PIN_NUM_MISO, + .mosi = SPI2_IOMUX_PIN_NUM_MOSI, +}; + +} diff --git a/Sming/Libraries/SPI/src/Arch/Esp8266/SPI.cpp b/Sming/Libraries/SPI/src/Arch/Esp8266/SPI.cpp new file mode 100644 index 0000000000..36c723d488 --- /dev/null +++ b/Sming/Libraries/SPI/src/Arch/Esp8266/SPI.cpp @@ -0,0 +1,377 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * SPI.cpp + * + * Created on: Mar 2, 2016 + * Author: harry-boe + * + * Some code is derived from: + * David Ogilvy (MetalPhreak) + * + ****/ + +#include "SPI.h" +#include +#include "espinc/eagle_soc.h" +#include "espinc/spi_register.h" +#include "espinc/spi_struct.h" + +// ESP8266 SPI hardware supports byte ordering so we don't need to do it in software +#define BYTE_ORDER_SUPPORTED 1 +#define SPI_BYTESWAP(n) (n) + +#define GET_DEVICE(err) \ + if(!busAssigned) { \ + debug_e("[SPI] Not Ready"); \ + return err; \ + } \ + SpiDevice dev; + +SPIClass SPI; + +namespace +{ +constexpr SpiPins defaultPins{ + .sck = 14, + .miso = 12, + .mosi = 13, +}; +constexpr size_t SPI_FIFO_SIZE{64}; + +bool busAssigned; + +// Used internally to calculate optimum SPI speed +struct SpiPreDiv { + unsigned freq; + unsigned prescale; + unsigned divisor; +}; + +struct SpiDevice { + volatile spi_dev_t* hw; + + SpiDevice() : hw(&SPI1) + { + } + + void init() + { + hw->user.val = 0; + hw->user.usr_mosi = true; + hw->user.duplex = true; + hw->user.ck_i_edge = true; + } + + void set_clock(SPISpeed& speed); + + /** + * @brief Wait until SPI has finished any current transaction + */ + void wait() + { + while(hw->cmd.usr) { + // + } + } + + /** + * @brief Initiate an SPI user transaction + */ + void send(unsigned num_bits) + { + hw->user1.usr_mosi_bitlen = num_bits - 1; + hw->cmd.usr = true; + } + + void set_mode(SpiMode mode) + { + uint8_t mode_num = SPISettings::getModeNum(mode); + bool spi_cpha = (mode_num & 0x01) != 0; + bool spi_cpol = (mode_num & 0x02) != 0; + +#ifdef SPI_DEBUG + debugf("[SPI] spi_mode(mode %x) spi_cpha %X, spi_cpol %X)", mode, spi_cpha, spi_cpol); +#endif + + hw->user.ck_out_edge = (spi_cpha != spi_cpol); + hw->pin.ck_idle_edge = spi_cpol; + } + + void set_bit_order(uint8_t bit_order) + { +#ifdef SPI_DEBUG + debugf("[SPI] set_bit_order(bit_order %u)", bit_order); +#endif + decltype(hw->ctrl) ctrl; + ctrl.val = hw->ctrl.val; + ctrl.rd_bit_order = (bit_order != MSBFIRST); + ctrl.wr_bit_order = (bit_order != MSBFIRST); + hw->ctrl.val = ctrl.val; + } + +#if BYTE_ORDER_SUPPORTED + void set_byte_order(uint8_t byte_order) + { + decltype(hw->user) user; + user.val = hw->user.val; + user.rd_byte_order = (byte_order == MSBFIRST); + user.wr_byte_order = (byte_order == MSBFIRST); + hw->user.val = user.val; + } +#endif + + uint32_t read() + { + return hw->data_buf[0]; + } + + void write(uint32_t value) + { + hw->data_buf[0] = value; + } + + void read(void* buffer, size_t length) + { + if(IS_ALIGNED(buffer) && IS_ALIGNED(length)) { + memcpy(buffer, (void*)hw->data_buf, length); + } else { + uint32_t wordBuffer[SPI_FIFO_SIZE]; + memcpy(wordBuffer, (void*)hw->data_buf, ALIGNUP4(length)); + memcpy(buffer, wordBuffer, length); + } + } + + void write(const void* buffer, size_t length) + { + if(IS_ALIGNED(buffer)) { + memcpy((void*)hw->data_buf, buffer, ALIGNUP4(length)); + } else { + uint32_t wordBuffer[SPI_FIFO_SIZE]; + memcpy(wordBuffer, buffer, length); + memcpy((void*)hw->data_buf, wordBuffer, ALIGNUP4(length)); + } + } +}; + +/** + * @brief Calculate the closest prescale value for a given frequency and clock-divider + * @param freq target SPI bus frequency, in Hz + * @param div divisor value to use + * @retval SpiPreDiv contains resulting frequency, prescaler and divisor values + */ +SpiPreDiv calculateSpeed(unsigned freq, unsigned div) +{ + SpiPreDiv prediv; + unsigned pre = APB_CLK_FREQ / (freq * div); + if(pre == 0) { + pre = 1; + } + unsigned n = pre * div; + while(true) { + prediv.freq = APB_CLK_FREQ / n; + if(prediv.freq <= freq) { + break; + } + ++pre; + n += div; + } + prediv.prescale = pre; + prediv.divisor = div; + +#ifdef SPI_DEBUG + debugf("[SPI] calculateSpeed(freq %u, pre %u, div %u)", freq, pre, div); +#endif + + return prediv; +} + +/** @brief Check speed settings and perform any pre-calculation required + * @param speed IN: requested bus frequency, OUT: Modified settings with prescale values + * @note + * The algorithm is testing with clock dividers 2,3 and 5 to find the best pre-divider + * The resulting clock frequency is not 100% accurate but delivers result within 5% + * + * It is guaranteed that the frequency will not exceed the given target + */ +void checkSpeed(SPISpeed& speed) +{ + SpiPreDiv prediv; + + // If we're not running at max then need to determine appropriate prescale values + if(speed.frequency >= APB_CLK_FREQ) { + // Use maximum speed + prediv.freq = APB_CLK_FREQ; +#ifdef SPI_DEBUG + prediv.divisor = 0; +#endif + speed.regVal = SPI_CLK_EQU_SYSCLK; + } else { + prediv = calculateSpeed(speed.frequency, 2); + if(prediv.freq != speed.frequency) { + // Use whichever divisor gives the highest frequency + SpiPreDiv pd3 = calculateSpeed(speed.frequency, 3); + SpiPreDiv pd5 = calculateSpeed(speed.frequency, 5); + if(pd3.freq > prediv.freq || pd5.freq > prediv.freq) { + prediv = (pd3.freq > pd5.freq) ? pd3 : pd5; + } + } + + // We have prescale and divisor values, now get regVal so we don't need to do this every time prepare() is called + decltype(spi_dev_t::clock) clk{{ + .clkcnt_l = prediv.divisor - 1, + .clkcnt_h = (prediv.divisor / 2) - 1, + .clkcnt_n = prediv.divisor - 1, + .clkdiv_pre = prediv.prescale - 1, + }}; + speed.regVal = clk.val; + } + +#ifdef SPI_DEBUG + debugf("[SPI] Using clock divider %u -> target freq %u -> result %u", prediv.divisor, speed.frequency, prediv.freq); +#endif + + speed.frequency = prediv.freq; +} + +void SpiDevice::set_clock(SPISpeed& speed) +{ + // Clock register value is never 0, so indicates it hasn't been calculated + if(speed.regVal == 0) { + checkSpeed(speed); + } else { +#ifdef SPI_DEBUG + unsigned prescale = (speed.regVal >> SPI_CLKDIV_PRE_S) + 1; + unsigned divisor = (speed.regVal >> SPI_CLKCNT_N_S) + 1; + debugf("[SPI] set_clock(prescaler %u, divisor %u) for target %u", prescale, divisor, speed.frequency); +#endif + } + + hw->clock.val = speed.regVal; +} + +} // namespace + +SPIClass::SPIClass() : SPIBase(defaultPins) +{ +} + +bool SPIClass::setup(SpiBus id, SpiPins pins) +{ + return (id == SpiBus::DEFAULT) && pins == defaultPins; +} + +bool SPIClass::begin() +{ + if(busAssigned) { + debug_e("[SPI] Bus already assigned"); + return false; + } + + busAssigned = true; + + SpiDevice dev; + dev.init(); + + CLEAR_PERI_REG_MASK(PERIPHS_IO_MUX, BIT9); + + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2); // HSPIQ MISO == GPIO12 + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2); // HSPID MOSI == GPIO13 + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2); // CLK == GPIO14 + + prepare(SPIDefaultSettings); + + return true; +} + +void SPIClass::end() +{ + GET_DEVICE(); + + busAssigned = false; +} + +uint32_t SPIClass::transfer32(uint32_t data, uint8_t bits) +{ + GET_DEVICE(0); + + if(!lsbFirst) { + data = SPI_BYTESWAP(data << (32 - bits)); + } + dev.write(data); + dev.send(bits); + dev.wait(); + + data = dev.read(); + if(!lsbFirst) { + data = SPI_BYTESWAP(data) >> (32 - bits); + } + return data; +} + +uint8_t SPIClass::read8() +{ + GET_DEVICE(0); + + dev.write(0xff); + dev.send(8); + dev.wait(); + + return dev.read(); +} + +void SPIClass::transfer(uint8_t* buffer, size_t numberBytes) +{ + GET_DEVICE(); + + // Always transfer LS byte first to match system byte order +#if BYTE_ORDER_SUPPORTED + if(!lsbFirst) { + dev.set_byte_order(LSBFIRST); + } +#endif + + for(unsigned i = 0; i < numberBytes; i += SPI_FIFO_SIZE) { + auto blockLen = std::min(numberBytes - i, SPI_FIFO_SIZE); + + dev.write(&buffer[i], blockLen); + dev.send(blockLen * 8); + dev.wait(); + dev.read(&buffer[i], blockLen); + } + +#if BYTE_ORDER_SUPPORTED + if(!lsbFirst) { + dev.set_byte_order(MSBFIRST); + } +#endif +} + +void SPIClass::prepare(SPISettings& settings) +{ +#ifdef SPI_DEBUG + debugf("[SPI] prepare()"); + settings.print("settings"); +#endif + + GET_DEVICE(); + + dev.set_mode(settings.dataMode); + dev.set_clock(settings.speed); + + // Set both bit and byte order to optimise transfer32() performance + dev.set_bit_order(settings.bitOrder); + lsbFirst = (settings.bitOrder != MSBFIRST); +#if BYTE_ORDER_SUPPORTED + dev.set_byte_order(settings.bitOrder); +#endif +} + +bool SPIClass::loopback(bool enable) +{ + (void)enable; + return false; +} diff --git a/Sming/Libraries/SPI/src/Arch/Esp8266/spi_arch.h b/Sming/Libraries/SPI/src/Arch/Esp8266/spi_arch.h new file mode 100644 index 0000000000..4d646ac952 --- /dev/null +++ b/Sming/Libraries/SPI/src/Arch/Esp8266/spi_arch.h @@ -0,0 +1,25 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * spi_arch.h - Esp8266 + * + */ + +#pragma once + +/** + * @brief Identifies bus selection + * + * @todo Add support for overlapped I/O using SPI0 pins. + * Devices can be represented as SPI2, SPI3 and SPI4 as there are three CS available. + */ +enum class SpiBus { + INVALID = 0, + MIN = 1, + SPI1 = 1, + MAX = 1, + DEFAULT = SPI1, +}; diff --git a/Sming/Libraries/SPI/src/Arch/Esp8266/spisoft_arch.cpp b/Sming/Libraries/SPI/src/Arch/Esp8266/spisoft_arch.cpp new file mode 100644 index 0000000000..7e7acd3577 --- /dev/null +++ b/Sming/Libraries/SPI/src/Arch/Esp8266/spisoft_arch.cpp @@ -0,0 +1,110 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * spisoft_arch.cpp + * + ****/ + +#include +#include +#include + +#if defined(SPISOFT_DELAY_VARIABLE) + +namespace +{ +/* + * Matching small delay values to frequency reuires a lookup table as the relationship is non-linear. + * Given values are clock period in ns, found by measurement. + * + * Two tables are required depending on currently selected CPU frequency. + */ + +DEFINE_FSTR_ARRAY(table80, uint16_t, 737, 760, 823, 886, 948, 1011, 1073, 1135) +DEFINE_FSTR_ARRAY(table160, uint16_t, 469, 470, 475, 511, 537, 573, 600, 636) + +/* + * Longer delay values are calculated, these are linearly proportional to period. + */ + +struct CoEfficient { + int16_t m; + int16_t c; +}; + +constexpr int M{16}; // Scalar to store values to one DP + +constexpr CoEfficient coefficients[2]{ + {int16_t(124.9 * M), 224}, + {int16_t(62.5 * M), 175}, +}; + +} // namespace + +uint8_t checkSpeed(SPISpeed& speed) +{ + constexpr int maxDelay{255}; + + union SpeedConfig { + uint32_t val; + struct { + uint8_t cpuFreq; + uint8_t delay; + }; + }; + + SpeedConfig cfg{speed.regVal}; + + // A change in CPU frequency or requested frequency will fail this check + auto cpuFreq = system_get_cpu_freq(); + if(cfg.cpuFreq == cpuFreq) { + // Already calculated, done + return cfg.delay; + } + + constexpr int NS = 1000000000; + + auto periodRequired = NS / speed.frequency; + const FSTR::Array& table = (cpuFreq <= 80) ? table80 : table160; + int delay = table.length() - 1; + uint16_t period = table[delay]; + if(period == periodRequired) { + // OK, entry matches + } else if(period > periodRequired) { + // Value is in table, match highest frequency not exceeding requested value + for(uint8_t i = 0; i < table.length(); ++i) { + period = table[i]; + if(period >= periodRequired) { + delay = i; + break; + } + } + } else { + // Calculate the delay, and resulting clock frequency + auto coeff = coefficients[(cpuFreq <= 80) ? 0 : 1]; + if(periodRequired == 0) { + delay = maxDelay; + } else { + delay = M * (periodRequired - coeff.c) / coeff.m; + delay = std::min(delay, maxDelay); + } +#ifdef SPI_DEBUG + period = (coeff.m * delay / M) + coeff.c; +#endif + } + + cfg.cpuFreq = cpuFreq; + cfg.delay = delay; + speed.regVal = cfg.val; + +#ifdef SPI_DEBUG + debugf("[SSPI] Using delay %u -> target freq %u -> result %u", delay, speed.frequency, NS / period); +#endif + + return cfg.delay; +} + +#endif diff --git a/Sming/Libraries/SPI/src/Arch/Esp8266/spisoft_arch.h b/Sming/Libraries/SPI/src/Arch/Esp8266/spisoft_arch.h new file mode 100644 index 0000000000..a416ccae67 --- /dev/null +++ b/Sming/Libraries/SPI/src/Arch/Esp8266/spisoft_arch.h @@ -0,0 +1,32 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * softspi_arch.h - Esp8266 + * + */ + +#pragma once + +#include + +#define GP_IN(pin) GP_FAST_READ(pin, PERIPHS_GPIO_BASEADDR + GPIO_IN_ADDRESS) +#define GP_OUT(pin, val) \ + GP_FAST_WRITE(pin, val, PERIPHS_GPIO_BASEADDR + GPIO_OUT_W1TC_ADDRESS, \ + PERIPHS_GPIO_BASEADDR + GPIO_OUT_W1TS_ADDRESS) + +namespace spisoft +{ +constexpr SpiPins defaultPins{ + .sck = 14, + .miso = 12, + .mosi = 13, +}; + +#ifdef SPISOFT_DELAY_VARIABLE +uint8_t checkSpeed(SPISpeed& speed); +#endif + +} // namespace spisoft diff --git a/Sming/Libraries/SPI/src/Arch/Host/SPI.cpp b/Sming/Libraries/SPI/src/Arch/Host/SPI.cpp new file mode 100644 index 0000000000..a1e942f8d6 --- /dev/null +++ b/Sming/Libraries/SPI/src/Arch/Host/SPI.cpp @@ -0,0 +1,268 @@ +#include "SPI.h" +#include +#include +#include +#include + +#define SPI_FIFO_DEPTH 8 + +#define GET_DEVICE(err) \ + if(!busAssigned[busId]) { \ + debug_e("[SPI] Not Ready"); \ + return err; \ + } \ + auto& dev = getDevice(busId); + +SPIClass SPI; + +namespace +{ +class SpiDevice +{ +public: + void init() + { + } + + void deinit() + { + } + + uint16_t configure(uint8_t data_bits, uint8_t mode, uint16_t clk) + { + return data_bits | mode | clk; + } + + void set_data_bits(uint16_t cr0val, uint8_t data_bits) + { + bits = data_bits; + } + + bool can_read() const + { + return true; + } + + bool can_write() const + { + return true; + } + + uint16_t read() + { + auto c = fifo.dequeue(); + if(ioCallback) { + ioCallback(c, bits, true); + } + return c; + } + + void write(uint16_t c) + { + c &= BIT(bits) - 1; + if(ioCallback) { + ioCallback(c, bits, false); + } + fifo.enqueue(c); + } + + uint16_t read_blocking() + { + return read(); + } + + void write_blocking(uint16_t c) + { + write(c); + } + + SPIClass::IoCallback ioCallback; + +private: + FIFO fifo; + uint8_t bits{0}; +}; + +SpiDevice devices[SOC_SPI_PERIPH_NUM]; + +SpiDevice& getDevice(SpiBus busId) +{ + return devices[unsigned(busId) - 1]; +} + +BitSet busAssigned; + +uint8_t reverseBits(uint8_t n) +{ + static constexpr uint8_t rev_nybble[16]{ + 0b0000, 0b1000, 0b0100, 0b1100, 0b0010, 0b1010, 0b0110, 0b1110, + 0b0001, 0b1001, 0b0101, 0b1101, 0b0011, 0b1011, 0b0111, 0b1111, + }; + return (rev_nybble[n & 0x0f] << 4) | rev_nybble[n >> 4]; +} + +uint16_t reverseBits(uint16_t n) +{ + return (reverseBits(uint8_t(n)) << 8) | reverseBits(uint8_t(n >> 8)); +} + +void reverseBits(uint8_t* buffer, size_t length) +{ + while(length--) { + *buffer = reverseBits(*buffer); + ++buffer; + } +} + +} // namespace + +SPIClass::SPIClass() : SPIBase({1, 2, 3}) +{ +} + +bool SPIClass::setup(SpiBus busId, SpiPins pins) +{ + if(busId < SpiBus::MIN || busId > SpiBus::MAX) { + debug_e("[SPI] Invalid bus"); + return false; + } + + if(busAssigned[busId]) { + debug_e("[SPI] Bus #%u already assigned", busId); + return false; + } + + this->busId = busId; + mPins = pins; + return true; +} + +bool SPIClass::begin() +{ + if(busAssigned[busId]) { + debug_e("[SPI] Bus #%u already assigned", busId); + return false; + } + + busAssigned += busId; + + auto& dev = getDevice(busId); + dev.init(); + + prepare(SPIDefaultSettings); + return true; +} + +void SPIClass::end() +{ + GET_DEVICE(); + dev.deinit(); + busAssigned -= busId; +} + +void SPIClass::setDebugIoCallback(IoCallback callback) +{ + GET_DEVICE(); + dev.ioCallback = callback; +} + +uint32_t SPIClass::transfer32(uint32_t data, uint8_t bits) +{ + if(bits < 4) { + debug_e("[SPI] Minimum 4 bit transfers"); + return 0; + } + + GET_DEVICE(0); + + auto writeRead = [&](uint16_t data, uint8_t bits) -> uint16_t { + dev.set_data_bits(cr0val, bits); + if(lsbFirst) { + data = reverseBits(data); + data >>= 16 - bits; + } + dev.write(data); + data = dev.read_blocking(); + if(lsbFirst) { + data <<= 16 - bits; + data = reverseBits(data); + } + return data; + }; + + /* + * 0-3: Not supported + * 4-16: One transfer + * 17-24: Two transfers, first is 8 bits + * 25-32: Two transfers, first is 16 bits + */ + uint32_t res; + if(bits <= 16) { + res = writeRead(data, bits); + } else { + uint8_t n = (bits <= 24) ? 8 : 16; + if(lsbFirst) { + res = writeRead(data, n); + res |= writeRead(data >> n, bits - n) << n; + } else { + res = writeRead(data >> n, bits - n) << n; + res |= writeRead(data, n); + } + } + + return res; +} + +uint8_t SPIClass::read8() +{ + return transfer32(0xff, 8); +} + +void SPIClass::transfer(uint8_t* buffer, size_t numberBytes) +{ + GET_DEVICE(); + + if(lsbFirst) { + reverseBits(buffer, numberBytes); + } + + size_t rx_remaining = numberBytes; + size_t tx_remaining = numberBytes; + const uint8_t* src = buffer; + uint8_t* dst = buffer; + + dev.set_data_bits(cr0val, 8); + while(rx_remaining + tx_remaining != 0) { + /* + * Never have more transfers in flight than will fit into the RX FIFO, + * or FIFO will overflow if this code is heavily interrupted. + */ + while(tx_remaining != 0 && rx_remaining < tx_remaining + SPI_FIFO_DEPTH && dev.can_write()) { + dev.write(*src++); + --tx_remaining; + } + if(rx_remaining != 0 && dev.can_read()) { + *dst++ = dev.read(); + --rx_remaining; + } + } + + if(lsbFirst) { + reverseBits(buffer, numberBytes); + } +} + +void SPIClass::prepare(SPISettings& settings) +{ + GET_DEVICE(); + + cr0val = dev.configure(8, settings.dataMode, 0); + + lsbFirst = (settings.bitOrder == LSBFIRST); +} + +bool SPIClass::loopback(bool enable) +{ + (void)enable; + return true; +} diff --git a/Sming/Libraries/SPI/src/Arch/Host/spi_arch.h b/Sming/Libraries/SPI/src/Arch/Host/spi_arch.h new file mode 100644 index 0000000000..65a1c07bce --- /dev/null +++ b/Sming/Libraries/SPI/src/Arch/Host/spi_arch.h @@ -0,0 +1,25 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * spi_arch.h - Host + */ + +#pragma once + +static constexpr uint8_t SOC_SPI_PERIPH_NUM{3}; + +/** + * @brief Identifies bus selection + */ +enum class SpiBus { + INVALID = 0, + MIN = 1, + SPI1 = 1, + SPI2 = 2, + SPI3 = 3, + MAX = SOC_SPI_PERIPH_NUM, + DEFAULT = SPI1, +}; diff --git a/Sming/Libraries/SPI/src/Arch/Host/spisoft_arch.h b/Sming/Libraries/SPI/src/Arch/Host/spisoft_arch.h new file mode 100644 index 0000000000..1ff1193ddb --- /dev/null +++ b/Sming/Libraries/SPI/src/Arch/Host/spisoft_arch.h @@ -0,0 +1,24 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * softspi_arch.h - Host + * + */ + +#pragma once + +#define GP_IN(pin) digitalRead(pin) +#define GP_OUT(pin, val) digitalWrite(pin, (val)&1) + +namespace spisoft +{ +constexpr SpiPins defaultPins{ + .sck = 14, + .miso = 12, + .mosi = 13, +}; + +} // namespace spisoft diff --git a/Sming/Libraries/SPI/src/Arch/Rp2040/SPI.cpp b/Sming/Libraries/SPI/src/Arch/Rp2040/SPI.cpp new file mode 100644 index 0000000000..2e3f173c2d --- /dev/null +++ b/Sming/Libraries/SPI/src/Arch/Rp2040/SPI.cpp @@ -0,0 +1,417 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * SPI.cpp + * + ****/ + +#include "SPI.h" +#include +#include +#include +#include +#include +#include +#include + +#define SPI_FIFO_DEPTH 8 + +#define GET_DEVICE(err) \ + if(!busAssigned[busId]) { \ + debug_e("[SPI] Not Ready"); \ + return err; \ + } \ + auto& dev = getDevice(busId); + +SPIClass SPI; + +namespace +{ +const SpiPins defaultPins[SOC_SPI_PERIPH_NUM] = { + {.sck = PICO_DEFAULT_SPI_SCK_PIN, .miso = PICO_DEFAULT_SPI_RX_PIN, .mosi = PICO_DEFAULT_SPI_TX_PIN}, + {.sck = 10, .miso = 12, .mosi = 11}, +}; + +// +union ClockReg { + struct { + uint8_t prescale; + uint8_t postdiv; + }; + uint16_t val; +}; + +// Used internally to calculate optimum SPI speed +struct SpiPreDiv { + SpiPreDiv(unsigned freq, uint8_t prescale, uint8_t postdiv) : freq(freq), reg{prescale, postdiv} + { + } + + unsigned freq; + ClockReg reg; +}; + +struct SpiDevice { + spi_hw_t* const hw; + + void reset() + { + reset_block(hw == spi0_hw ? RESETS_RESET_SPI0_BITS : RESETS_RESET_SPI1_BITS); + } + + void unreset() + { + unreset_block_wait(hw == spi0_hw ? RESETS_RESET_SPI0_BITS : RESETS_RESET_SPI1_BITS); + } + + void init() + { + reset(); + hw->cr1 = 0; + unreset(); + + // Enable the SPI + hw->cr1 = SPI_SSPCR1_SSE_BITS; + } + + void deinit() + { + hw->cr1 = 0; + hw->dmacr = 0; + reset(); + } + + union SSPCR0 { + struct { + uint32_t dss : 4; ///< Data Size Select + uint32_t frf : 2; ///< Frame Format + uint32_t spo : 1; ///< SSPCLKOUT polarity + uint32_t sph : 1; ///< SSPCLKOUT phase + uint32_t scr : 8; ///< Serial clock rate + }; + uint32_t val; + }; + + enum FrameFormat { + FRAME_FORMAT_MOTOROLA = 0, + FRAME_FORMAT_TI = 1, + FRAME_FORMAT_MICROWIRE = 2, + FRAME_FORMAT_UNDEFINED = 3, + }; + + uint16_t configure(uint8_t data_bits, uint8_t mode, ClockReg clk) + { + hw->cpsr = clk.prescale; + SSPCR0 cr0{{ + .dss = uint8_t(data_bits - 1), + .frf = FRAME_FORMAT_MOTOROLA, + .spo = (mode & 0xF0) ? 1U : 0U, + .sph = (mode & 0x0F) ? 1U : 0U, + .scr = uint8_t(clk.postdiv - 1), + }}; + hw->cr0 = cr0.val; + return cr0.val; + } + + void loopback(bool enable) + { + hw_write_masked(&hw->cr1, enable << SPI_SSPCR1_LBM_LSB, SPI_SSPCR1_LBM_BITS); + } + + void set_data_bits(uint16_t cr0val, uint8_t data_bits) + { + SSPCR0 cr0{.val = cr0val}; + cr0.dss = data_bits - 1; + hw->cr0 = cr0.val; + } + + bool is_busy() const + { + return hw->sr & SPI_SSPSR_BSY_BITS; + } + + bool can_read() const + { + return hw->sr & SPI_SSPSR_RNE_BITS; + } + + bool can_write() const + { + return hw->sr & SPI_SSPSR_TNF_BITS; + } + + uint16_t read() + { + return hw->dr; + } + + void write(uint16_t c) + { + hw->dr = c; + } + + uint16_t read_blocking() + { + while(!can_read()) { + } + return read(); + } + + void write_blocking(uint16_t c) + { + while(!can_write()) { + } + write(c); + } +}; + +SpiDevice devices[SOC_SPI_PERIPH_NUM] = { + {spi0_hw}, + {spi1_hw}, +}; + +SpiDevice& getDevice(SpiBus busId) +{ + return devices[unsigned(busId) - 1]; +} + +BitSet busAssigned; + +// Cortex M0+ doesn't support the rbit instruction +// __forceinline uint32_t reverseBits(uint32_t value) +// { +// uint32_t result; +// __asm__("rbit %0, %1" : "=r"(result) : "r"(value)); +// return result; +// } + +uint8_t reverseBits(uint8_t n) +{ + static constexpr uint8_t rev_nybble[16]{ + 0b0000, 0b1000, 0b0100, 0b1100, 0b0010, 0b1010, 0b0110, 0b1110, + 0b0001, 0b1001, 0b0101, 0b1101, 0b0011, 0b1011, 0b0111, 0b1111, + }; + return (rev_nybble[n & 0x0f] << 4) | rev_nybble[n >> 4]; +} + +uint16_t reverseBits(uint16_t n) +{ + return (reverseBits(uint8_t(n)) << 8) | reverseBits(uint8_t(n >> 8)); +} + +void reverseBits(uint8_t* buffer, size_t length) +{ + while(length--) { + *buffer = reverseBits(*buffer); + ++buffer; + } +} + +SpiPreDiv calculateSpeed(unsigned baudrate) +{ + auto freq_in = clock_get_hz(clk_peri); + if(baudrate > freq_in) { + return SpiPreDiv(freq_in, 2, 1); + } + + /* + * Find smallest prescale value which puts output frequency in range of post-divide. + * Prescale is an even number from 2 to 254 inclusive. + */ + unsigned prescale; + for(prescale = 2; prescale <= 254; prescale += 2) { + if(freq_in < (prescale + 2) * 256 * (uint64_t)baudrate) + break; + } + if(prescale > 254) { + // Frequency too low + prescale = 254; + } + + /* + * Find largest post-divide which makes output <= baudrate. + * Post-divide is an integer in the range 1 to 256 inclusive. + */ + unsigned postdiv; + for(postdiv = 256; postdiv > 1; --postdiv) { + if(freq_in / (prescale * (postdiv - 1)) > baudrate) + break; + } + + // Return actual frequency and corresponding settings + return SpiPreDiv(freq_in / (prescale * postdiv), prescale, postdiv); +} + +} // namespace + +SPIClass::SPIClass() : SPIBase(defaultPins[unsigned(SpiBus::DEFAULT) - 1]) +{ +} + +bool SPIClass::setup(SpiBus busId, SpiPins pins) +{ + if(busId < SpiBus::MIN || busId > SpiBus::MAX) { + debug_e("[SPI] Invalid bus"); + return false; + } + + if(busAssigned[busId]) { + debug_e("[SPI] Bus #%u already assigned", busId); + return false; + } + + this->busId = busId; + mPins = pins; + return true; +} + +bool SPIClass::begin() +{ + if(busAssigned[busId]) { + debug_e("[SPI] Bus #%u already assigned", busId); + return false; + } + + busAssigned += busId; + + auto& dev = getDevice(busId); + dev.init(); + + assignDefaultPins(defaultPins[unsigned(busId) - 1]); + + gpio_set_function(pins.sck, GPIO_FUNC_SPI); + gpio_set_function(pins.miso, GPIO_FUNC_SPI); + gpio_set_function(pins.mosi, GPIO_FUNC_SPI); + gpio_pull_up(pins.miso); + + prepare(SPIDefaultSettings); + return true; +} + +void SPIClass::end() +{ + GET_DEVICE(); + dev.deinit(); + busAssigned -= busId; +} + +uint32_t SPIClass::transfer32(uint32_t data, uint8_t bits) +{ + if(bits < 4) { + debug_e("[SPI] Minimum 4 bit transfers"); + return 0; + } + + GET_DEVICE(0); + + auto writeRead = [&](uint16_t data, uint8_t bits) -> uint16_t { + dev.set_data_bits(cr0val, bits); + if(lsbFirst) { + data = reverseBits(data); + data >>= 16 - bits; + } + dev.write(data); + data = dev.read_blocking(); + if(lsbFirst) { + data <<= 16 - bits; + data = reverseBits(data); + } + return data; + }; + + /* + * 0-3: Not supported + * 4-16: One transfer + * 17-24: Two transfers, first is 8 bits + * 25-32: Two transfers, first is 16 bits + */ + uint32_t res; + if(bits <= 16) { + res = writeRead(data, bits); + } else { + uint8_t n = (bits <= 24) ? 8 : 16; + if(lsbFirst) { + res = writeRead(data, n); + res |= writeRead(data >> n, bits - n) << n; + } else { + res = writeRead(data >> n, bits - n) << n; + res |= writeRead(data, n); + } + } + + return res; +} + +uint8_t SPIClass::read8() +{ + return transfer32(0xff, 8); +} + +void SPIClass::transfer(uint8_t* buffer, size_t numberBytes) +{ + GET_DEVICE(); + + if(lsbFirst) { + reverseBits(buffer, numberBytes); + } + + size_t rx_remaining = numberBytes; + size_t tx_remaining = numberBytes; + const uint8_t* src = buffer; + uint8_t* dst = buffer; + + dev.set_data_bits(cr0val, 8); + while(rx_remaining + tx_remaining != 0) { + /* + * Never have more transfers in flight than will fit into the RX FIFO, + * or FIFO will overflow if this code is heavily interrupted. + */ + while(tx_remaining != 0 && rx_remaining < tx_remaining + SPI_FIFO_DEPTH && dev.can_write()) { + dev.write(*src++); + --tx_remaining; + } + if(rx_remaining != 0 && dev.can_read()) { + *dst++ = dev.read(); + --rx_remaining; + } + } + + if(lsbFirst) { + reverseBits(buffer, numberBytes); + } +} + +void SPIClass::prepare(SPISettings& settings) +{ + GET_DEVICE(); + +#ifdef SPI_DEBUG + debug_i("[SPI] prepare()"); + settings.print("settings"); +#endif + + // Clock register value is never 0, so indicates it hasn't been calculated + auto& speed = settings.speed; + if(speed.regVal == 0) { + auto prediv = calculateSpeed(speed.frequency); + speed.regVal = prediv.reg.val; + debug_i("[SPI] pre = %u, div = %u, target freq = %u, actual = %u", prediv.reg.prescale, prediv.reg.postdiv, + speed.frequency, prediv.freq); + } + ClockReg clk; + clk.val = settings.speed.regVal; + + cr0val = dev.configure(8, settings.dataMode, clk); + + lsbFirst = (settings.bitOrder == LSBFIRST); +} + +bool SPIClass::loopback(bool enable) +{ + GET_DEVICE(false); + dev.loopback(enable); + return true; +} diff --git a/Sming/Libraries/SPI/src/Arch/Rp2040/spi_arch.h b/Sming/Libraries/SPI/src/Arch/Rp2040/spi_arch.h new file mode 100644 index 0000000000..3015059060 --- /dev/null +++ b/Sming/Libraries/SPI/src/Arch/Rp2040/spi_arch.h @@ -0,0 +1,25 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * spi_arch.h - Rp2040 + * + */ + +#pragma once + +static constexpr uint8_t SOC_SPI_PERIPH_NUM{2}; + +/** + * @brief Identifies bus selection + */ +enum class SpiBus { + INVALID = 0, + MIN = 1, + SPI1 = 1, + SPI2 = 2, + MAX = SOC_SPI_PERIPH_NUM, + DEFAULT = SPI1, +}; diff --git a/Sming/Libraries/SPI/src/Arch/Rp2040/spisoft_arch.h b/Sming/Libraries/SPI/src/Arch/Rp2040/spisoft_arch.h new file mode 100644 index 0000000000..fca4567880 --- /dev/null +++ b/Sming/Libraries/SPI/src/Arch/Rp2040/spisoft_arch.h @@ -0,0 +1,29 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * softspi_arch.h - Rp2040 + * + */ + +#pragma once + +#include +#include + +#define GP_IN(pin) GP_FAST_READ(pin, SIO_BASE + SIO_GPIO_IN_OFFSET) +#define GP_OUT(pin, val) GP_FAST_WRITE(pin, val, SIO_BASE + SIO_GPIO_OUT_CLR_OFFSET, SIO_BASE + SIO_GPIO_OUT_SET_OFFSET) + +#define SPISOFT_ARCH_DELAY_FIXED 1 + +namespace spisoft +{ +constexpr SpiPins defaultPins{ + .sck = PICO_DEFAULT_SPI_SCK_PIN, + .miso = PICO_DEFAULT_SPI_RX_PIN, + .mosi = PICO_DEFAULT_SPI_TX_PIN, +}; + +} // namespace spisoft diff --git a/Sming/Libraries/SPI/src/SPI.h b/Sming/Libraries/SPI/src/SPI.h new file mode 100644 index 0000000000..580daa59c4 --- /dev/null +++ b/Sming/Libraries/SPI/src/SPI.h @@ -0,0 +1,94 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * SPI.h + * + * Created on: Mar 2, 2016 + * Author: harry-boe + * + */ + +#pragma once + +#include "SPIBase.h" +#include "SPISettings.h" +#include + +/** + * @defgroup hw_spi SPI Hardware support + * @brief Provides hardware SPI support + * @{ + */ + +/** + * @brief Hardware SPI class + */ +class SPIClass : public SPIBase +{ +public: + SPIClass(); + SPIClass(const SPIClass&) = delete; + SPIClass& operator=(const SPIClass&) = delete; + + /** + * @brief Alternative to defining bus and pin set in constructor. + * Use this method to change global `SPI` instance setup. + * + * IMPORTANT: Must be called *before* begin(). + */ + bool setup(SpiBus id, SpiPins pins = {}); + + bool setup(SpiPins pins) + { + return setup(SpiBus::DEFAULT, pins); + } + + bool begin() override; + void end() override; + + uint8_t read8() override; + uint32_t transfer32(uint32_t val, uint8_t bits = 32) override; + + using SPIBase::transfer; + void transfer(uint8_t* buffer, size_t numberBytes) override; + + bool loopback(bool enable) override; + +#ifdef ARCH_HOST + /** + * @brief Used for testing purposes only + * @param c Value being read/written + * @param bits Size of value in bits + * @param read true for incoming value, false for outgoing + */ + using IoCallback = void (*)(uint16_t c, uint8_t bits, bool read); + + /** + * @brief Used for testing purposes only + * Must be called *after* begin(). + * + * Used to verify serialisation/de-searialisation bit ordering + */ + void setDebugIoCallback(IoCallback callback); +#endif + +protected: + void prepare(SPISettings& settings) override; + +private: +#ifndef ARCH_ESP8266 + SpiBus busId{SpiBus::DEFAULT}; +#endif +#if defined(ARCH_RP2040) || defined(ARCH_HOST) + uint16_t cr0val{0}; +#endif + bool lsbFirst{false}; +}; + +/** @brief Global instance of SPI class */ +extern SPIClass SPI; + +/** @} */ diff --git a/Sming/Core/SPIBase.h b/Sming/Libraries/SPI/src/SPIBase.h similarity index 57% rename from Sming/Core/SPIBase.h rename to Sming/Libraries/SPI/src/SPIBase.h index 2943176aa8..894dab5274 100644 --- a/Sming/Core/SPIBase.h +++ b/Sming/Libraries/SPI/src/SPIBase.h @@ -14,7 +14,10 @@ #pragma once #include "SPISettings.h" -#include +#include + +// for compatibility when porting from Arduino +#define SPI_HAS_TRANSACTION 1 /** * @defgroup base_spi SPI support classes @@ -22,18 +25,41 @@ * @{ */ +/** + * @brief SPI driver uses default pin assignment + */ +static constexpr uint8_t SPI_PIN_DEFAULT{0xff}; + +/** + * @brief SPI pin connections + */ +struct SpiPins { + uint8_t sck{SPI_PIN_DEFAULT}; + uint8_t miso{SPI_PIN_DEFAULT}; + uint8_t mosi{SPI_PIN_DEFAULT}; + + bool operator==(const SpiPins& other) const + { + return sck == other.sck && miso == other.miso && mosi == other.mosi; + } +}; + /* * @brief Base class/interface for SPI implementations */ class SPIBase { public: + SPIBase(const SpiPins& pins) : mPins(pins) + { + } + virtual ~SPIBase() { } /** - * @brief Initialize the SPI bus by setting SCK, MOSI, and SS to outputs, pulling SCK and MOSI low, and SS high. + * @brief Initialize the SPI bus by setting SCK and MOSI to outputs, pulling SCK and MOSI low. */ virtual bool begin() = 0; @@ -63,17 +89,33 @@ class SPIBase { } - /** @brief Read one byte from SPI without setting up registers - * @param none - * @retval byte received + void write(uint8_t data) + { + transfer(data); + } + + void write16(uint16_t data) + { + transfer16(data); + } + + void write32(uint32_t data) + { + transfer32(data); + } + + /** + * @brief Read one byte from SPI without setting up registers + * @param none + * @retval byte received * - * used for performance tuning when doing continuous reads - * this method does not reset the registers , so make sure - * that a regular transfer(data) call was performed + * Used for performance tuning when doing continuous reads + * this method does not reset the registers, so make sure + * that a regular transfer(data) call was performed * - * Note: this method is not found on the Arduino API + * Note: this method is not found on the Arduino API * - * USE WITH CARE !! + * USE WITH CARE !! * */ virtual uint8_t read8() @@ -94,7 +136,7 @@ class SPIBase */ /** - * @brief Send/receive one bytes of data + * @brief Send/receive one byte of data * @param val The byte to send * @retval uint8_t The received byte */ @@ -106,7 +148,10 @@ class SPIBase /** * @brief Send/receive one 16-bit word of data * @param val The word to send - * @retval uint8_t The received word + * @retval uint16_t The received word + * + * Word is transferred either MSB first (bit 15) or LSB first (bit 0) + * depending on the currently applied bitOrder setting. */ uint16_t transfer16(uint16_t val) { @@ -116,13 +161,10 @@ class SPIBase /** * @brief Send/receive a word of variable size * @param val Word to send - * @param bits Number of bits to send - * - * SPI transfer is based on a simultaneous send and receive: - * the received data is returned in receivedVal (or receivedVal16). + * @param bits Size of word * - * receivedVal = SPI.transfer(val) : single byte - * receivedVal16 = SPI.transfer16(val16) : single short + * Word is transferred either MSB first (bits-1) or LSB first (bit 0) + * depending on the currently applied bitOrder setting. */ virtual uint32_t transfer32(uint32_t val, uint8_t bits = 32) { @@ -139,20 +181,47 @@ class SPIBase /** @} */ + /** + * @brief For testing, tie MISO <-> MOSI internally + * + * Note: Not included in std Arduino lib + */ + virtual bool loopback(bool enable) = 0; + /** * @brief Default settings used by the SPI bus * until reset by beginTransaction(SPISettings) * - * Note: not included in std Arduino lib + * Note: Not included in std Arduino lib */ SPISettings SPIDefaultSettings; + const SpiPins& pins{mPins}; + protected: /** * @brief Prepare/configure with settings * @param settings include frequency, byte order and SPI mode */ virtual void prepare(SPISettings& settings) = 0; + + /** + * @brief Assign any default pins + */ + void assignDefaultPins(const SpiPins& defPins) + { + if(pins.sck == SPI_PIN_DEFAULT) { + mPins.sck = defPins.sck; + } + if(pins.miso == SPI_PIN_DEFAULT) { + mPins.miso = defPins.miso; + } + if(pins.mosi == SPI_PIN_DEFAULT) { + mPins.mosi = defPins.mosi; + } + } + + SpiPins mPins; }; /** @} */ diff --git a/Sming/Core/SPISettings.h b/Sming/Libraries/SPI/src/SPISettings.h similarity index 59% rename from Sming/Core/SPISettings.h rename to Sming/Libraries/SPI/src/SPISettings.h index 1e4d60b8a9..b7f3dc8016 100644 --- a/Sming/Core/SPISettings.h +++ b/Sming/Libraries/SPI/src/SPISettings.h @@ -13,7 +13,8 @@ #pragma once -#include "Digital.h" +#include +#include #ifdef SPI_DEBUG #include #endif @@ -28,10 +29,12 @@ // SPI_MODE2 1 0 // SPI_MODE3 1 1 -#define SPI_MODE0 0x00 -#define SPI_MODE1 0x0F -#define SPI_MODE2 0xF0 -#define SPI_MODE3 0xFF +enum SpiMode : uint8_t { + SPI_MODE0 = 0x00, + SPI_MODE1 = 0x0F, + SPI_MODE2 = 0xF0, + SPI_MODE3 = 0xFF, +}; const uint32_t SPI_SPEED_DEFAULT = 4000000UL; @@ -40,12 +43,11 @@ const uint32_t SPI_SPEED_DEFAULT = 4000000UL; * between bus devices */ struct SPISpeed { - uint32_t frequency; - uint32_t regVal; ///< Cached clock register value + uint32_t frequency{0}; + uint32_t regVal{0}; ///< Cached clock register value - SPISpeed(uint32_t freq = SPI_SPEED_DEFAULT) + SPISpeed(uint32_t freq = SPI_SPEED_DEFAULT) : frequency(freq) { - setFrequency(freq); } SPISpeed& operator=(uint32_t freq) @@ -61,8 +63,10 @@ struct SPISpeed { void setFrequency(uint32_t freq) { - frequency = freq; - regVal = 0; + if(freq != frequency) { + frequency = freq; + regVal = 0; + } } }; @@ -83,47 +87,58 @@ class SPISettings * * @param speed: The maximum speed of communication. For a SPI chip rated up to sys clock speed. * For 20 MHz, use 20000000. - * @param byteOrder: MSBFIRST or LSBFIRST + * @param bitOrder: MSBFIRST or LSBFIRST + * Determines how bits within each byte are sent on the wire. + * Data is always sent LSB first (matches system endianness) * @param dataMode : SPI_MODE0, SPI_MODE1, SPI_MODE2, or SPI_MODE3 * - * byteOrder's are: - * - * MSBFIRST Data is sent out starting with Bit31 and down to Bit0 - * LSBFIRST Data is sent out starting with the lowest BYTE, from MSB to LSB. - * 0xABCDEFGH would be sent as 0xGHEFCDAB - * - * Data modes are: - * * Mode Clock Polarity (CPOL) Clock Phase (CPHA) * SPI_MODE0 0 0 * SPI_MODE1 0 1 * SPI_MODE2 1 0 * SPI_MODE3 1 1 */ - SPISettings(uint32_t speed, uint8_t byteOrder, uint8_t dataMode) - : speed(speed), byteOrder(byteOrder), dataMode(dataMode) + SPISettings(uint32_t speed, uint8_t bitOrder, SpiMode dataMode) + : speed(speed), bitOrder(bitOrder), dataMode(dataMode) { #ifdef SPI_DEBUG - debugf("SPISettings(int %i, uint8 %u, uint8 %u)", speed, byteOrder, dataMode); + debugf("SPISettings(int %i, uint8 %u, uint8 %u)", speed, bitOrder, dataMode); #endif } + /* + * Arduino libraries use non-typed dataMode + */ + SPISettings(uint32_t speed, uint8_t bitOrder, uint8_t dataMode) + : speed(speed), bitOrder(bitOrder), dataMode(SpiMode(dataMode)) + { + } + // overload operator to check whether the settings are equal bool operator==(const SPISettings& other) const { - return (speed == other.speed) && (byteOrder == other.byteOrder) && (dataMode == other.dataMode); + return (speed == other.speed) && (bitOrder == other.bitOrder) && (dataMode == other.dataMode); } void print(const char* s) { #ifdef SPI_DEBUG - debugf("-> %s -> SPISettings(%u, %u, %u)", s, speed.frequency, byteOrder, dataMode); + debugf("-> %s -> SPISettings(%u, %u, %u)", s, speed.frequency, bitOrder, dataMode); #endif } + /** + * @brief Get number 0-3 corresponding to an SpiMode setting + * @param mode Can be SpiMode or a number 0-3 + */ + static uint8_t getModeNum(SpiMode mode) + { + return (mode <= 3) ? mode : ((mode & 0x10) >> 3) | (mode & 0x01); + } + SPISpeed speed; - uint8_t byteOrder{MSBFIRST}; - uint8_t dataMode{SPI_MODE0}; + uint8_t bitOrder{MSBFIRST}; + SpiMode dataMode{SPI_MODE0}; }; /** @} */ diff --git a/Sming/Libraries/SPI/src/SPISoft.cpp b/Sming/Libraries/SPI/src/SPISoft.cpp new file mode 100644 index 0000000000..d20e3925f2 --- /dev/null +++ b/Sming/Libraries/SPI/src/SPISoft.cpp @@ -0,0 +1,256 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * SPISoft.cpp + * + * Author: (github.com/)ADiea + * Project: Sming for ESP8266 - https://github.com/anakod/Sming + * License: MIT + * Date: 15.07.2015 + * Descr: Implement software SPI. To improve speed, GPIO16 is not supported(see Digital.cpp) + * + * @author mikee47 January 2022 + * + ****/ + +#include "SPISoft.h" +#include +#include + +#ifndef SPISOFT_ARCH_DELAY_FIXED +#define SPISOFT_ARCH_DELAY_FIXED 0 +#endif + +#define FUNC_OPT __attribute__((optimize(3))) + +namespace spisoft +{ +#define SCK_SETUP() GP_OUT(pins.sck, ~cksample) +#define SCK_SAMPLE() GP_OUT(pins.sck, cksample) +#define SCK_IDLE() GP_OUT(pins.sck, cpol) +#define MOSI_WRITE(d) GP_OUT(pins.mosi, d) +#define MISO_READ() GP_IN(pins.miso) + +// Enabling variable delays disables fixed delays +#ifdef SPISOFT_DELAY_VARIABLE +#undef SPISOFT_DELAY_FIXED +#define SPISOFT_DELAY_FIXED 0 +#endif + +static_assert(SPISOFT_DELAY_FIXED >= 0 && SPISOFT_DELAY_FIXED <= 20, "SPISOFT_DELAY_FIXED invalid"); + +template __forceinline void fixedDelay() +{ + __asm__ volatile("nop" :::); + fixedDelay(); +} + +template <> void fixedDelay<0>() +{ +} + +__forceinline void fastDelay(int d) +{ + fixedDelay(); +#ifdef SPISOFT_DELAY_VARIABLE + while(d-- > 0) { + __asm__ volatile("nop" :::); + } +#else + (void)d; +#endif +} + +} // namespace spisoft + +using namespace spisoft; + +SPISoft::SPISoft() : SPIBase(spisoft::defaultPins) +{ +} + +SPISoft::SPISoft(uint8_t delay) : SPIBase(spisoft::defaultPins), m_delay(delay) +{ +} + +bool SPISoft::begin() +{ + assignDefaultPins(defaultPins); + +#ifdef ARCH_ESP8266 + if(16 == pins.miso || 16 == pins.mosi || 16 == pins.sck) { + /*To be able to use fast/simple GPIO read/write GPIO16 is not supported*/ + debug_e("[SPISoft] GPIO 16 not supported\n"); + return false; + } +#elif defined(ARCH_ESP32) + if(pins.sck >= 32 || pins.miso >= 32 || pins.mosi >= 32) { + debug_e("[SPISoft] Only bank 0 pins supported"); + return false; + } +#endif + + pinMode(pins.sck, OUTPUT); + + pinMode(pins.miso, INPUT); + digitalWrite(pins.miso, HIGH); + + pinMode(pins.mosi, OUTPUT); + + prepare(SPIDefaultSettings); + + return true; +} + +// Write/read a bit in LSB-first order +#define CLOCK_LSB(bit, shift) \ + SCK_SETUP(); \ + MOSI_WRITE(word >> bit); \ + fastDelay(m_delay); \ + res >>= 1; \ + SCK_SAMPLE(); \ + res |= MISO_READ() << shift; \ + fastDelay(m_delay - 7); + +#define CLOCK_LSB8(bit) CLOCK_LSB(bit, 7) + +uint8_t FUNC_OPT SPISoft::transferByteLSB(uint8_t word) +{ + uint8_t res{0}; + CLOCK_LSB8(0) + CLOCK_LSB8(1) + CLOCK_LSB8(2) + CLOCK_LSB8(3) + CLOCK_LSB8(4) + CLOCK_LSB8(5) + CLOCK_LSB8(6) + CLOCK_LSB8(7) + return res; +} + +uint32_t FUNC_OPT SPISoft::transferWordLSB(uint32_t word, uint8_t bits) +{ + uint32_t res{0}; + + switch(bits / 8) { + case 4: + res = transferByteLSB(word) << 24; + word >>= 8; + case 3: + res = (res >> 8) | transferByteLSB(word) << 24; + word >>= 8; + case 2: + res = (res >> 8) | transferByteLSB(word) << 24; + word >>= 8; + case 1: + res = (res >> 8) | transferByteLSB(word) << 24; + word >>= 8; + } + + for(uint8_t bit = 0; bit < (bits % 8); ++bit) { + CLOCK_LSB(bit, 31); + } + + res >>= 32 - bits; + return res; +} + +// Write/read a bit in MSB-first order +#define CLOCK_MSB32(bit) \ + SCK_SETUP(); \ + MOSI_WRITE(word >> bit); \ + fastDelay(m_delay); \ + res <<= 1; \ + SCK_SAMPLE(); \ + res |= MISO_READ(); \ + fastDelay(m_delay - 7); + +uint8_t FUNC_OPT SPISoft::transferByteMSB(uint8_t word) +{ + uint8_t res{0}; + CLOCK_MSB32(7) + CLOCK_MSB32(6) + CLOCK_MSB32(5) + CLOCK_MSB32(4) + CLOCK_MSB32(3) + CLOCK_MSB32(2) + CLOCK_MSB32(1) + CLOCK_MSB32(0) + return res; +} + +uint32_t FUNC_OPT SPISoft::transferWordMSB(uint32_t word, uint8_t bits) +{ + uint32_t res{0}; + uint8_t bit = bits; + while((bit & 7) != 0) { + --bit; + CLOCK_MSB32(bit); + } + + switch(bit / 8) { + case 4: + res = transferByteMSB(word >> 24); + case 3: + res = (res << 8) | transferByteMSB(word >> 16); + case 2: + res = (res << 8) | transferByteMSB(word >> 8); + case 1: + res = (res << 8) | transferByteMSB(word); + } + + return res; +} + +uint32_t SPISoft::transfer32(uint32_t val, uint8_t bits) +{ + if(lsbFirst) { + val = transferWordLSB(val, bits); + } else { + val = transferWordMSB(val, bits); + } + + return val; +} + +void SPISoft::transfer(uint8_t* buffer, size_t size) +{ + if(lsbFirst) { + while(size-- != 0) { + *buffer = transferByteLSB(*buffer); + ++buffer; + } + } else { + while(size-- != 0) { + *buffer = transferByteMSB(*buffer); + ++buffer; + } + } +} + +void SPISoft::prepare(SPISettings& settings) +{ + dataMode = settings.dataMode; + auto mode_num = SPISettings::getModeNum(dataMode); + cpol = (mode_num & 0x02) >> 1; + uint8_t cpha = mode_num & 0x01; + cksample = (cpol == cpha); + + lsbFirst = (settings.bitOrder != MSBFIRST); + SCK_SETUP(); + +#if defined(SPISOFT_DELAY_VARIABLE) && defined(ARCH_ESP8266) + // If user doesn't specify speed then don't override + if(settings.speed.frequency != 0) { + m_delay = checkSpeed(settings.speed); + } +#endif +} + +void SPISoft::endTransaction() +{ + SCK_IDLE(); +} diff --git a/Sming/Libraries/SPI/src/SPISoft.h b/Sming/Libraries/SPI/src/SPISoft.h new file mode 100644 index 0000000000..b428c7623c --- /dev/null +++ b/Sming/Libraries/SPI/src/SPISoft.h @@ -0,0 +1,124 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * SPISoft.h + * + * Author: ADiea + * Project: Sming for ESP8266 + * License: MIT + * Date: 15.07.2015 + * Descr: Implement software SPI for HW configs other than hardware SPI pins(GPIO 12,13,14) + * + * @author mikee47 January 2022 + * + * Rewritten to implement bit ordering, modes, delays and transactions. + * + ****/ + +#pragma once + +#include "SPIBase.h" + +/** + * @defgroup soft_spi SPI software implementation + */ + +/** + * @brief Software-based SPI master + * + * Intended for ESP8266 due to limited I/O but will work on any architecture. + * + * @ingroup soft_spi + */ +class SPISoft : public SPIBase +{ +public: + /** + * @name Constructors + * @{ + */ + + /** + * @brief Default constructor uses same pins as hardware SPI + */ + SPISoft(); + + /** + * @brief Specify pins to use plus optional delay + * + * Delay is ignored if code is not compiled with SPISOFT_DELAY < 0. + */ + SPISoft(uint8_t miso, uint8_t mosi, uint8_t sck, uint8_t delay = 0) : SPISoft({sck, miso, mosi}, delay) + { + } + + /** + * @brief Specify pins plus optional delay + */ + SPISoft(const SpiPins& pins, uint8_t delay = 0) : SPIBase(pins), m_delay(delay) + { + } + + /** + * @brief Use default pins but provide a delay + */ + SPISoft(uint8_t delay); + + /** @} */ + + bool setup(SpiPins pins) + { + this->mPins = pins; + return true; + } + + bool begin() override; + + void end() override + { + } + + void endTransaction() override; + + using SPIBase::transfer; + uint32_t transfer32(uint32_t val, uint8_t bits = 32) override; + void transfer(uint8_t* buffer, size_t size) override; + + /** + * @brief Set delay factor for the SCK signal. Impacts SPI speed. + * + * Requires code to be compiled with SPISOFT_DELAY < 0. + * + * ESP8266 only: The delay will be automatically calculated for a requested + * clock speed when `begin()` or `beginTransaction()` are called. + * To use only the manually programmed delay, set the clock speed to zero. + */ + void setDelay(uint8_t delay) + { + m_delay = delay; + } + + bool loopback(bool enable) override + { + (void)enable; + return false; + } + +protected: + void prepare(SPISettings& settings) override; + +private: + uint8_t transferByteLSB(uint8_t word); + uint8_t transferByteMSB(uint8_t word); + uint32_t transferWordLSB(uint32_t word, uint8_t bits); + uint32_t transferWordMSB(uint32_t word, uint8_t bits); + + uint8_t m_delay{0}; + SpiMode dataMode{SPI_MODE0}; + uint8_t cpol{0}; + uint8_t cksample{0}; + bool lsbFirst{false}; +}; diff --git a/Sming/Libraries/SPI/src/fast_io.h b/Sming/Libraries/SPI/src/fast_io.h new file mode 100644 index 0000000000..d294eb12e2 --- /dev/null +++ b/Sming/Libraries/SPI/src/fast_io.h @@ -0,0 +1,55 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * fast_io.h + * + * @author mikee47 January 2022 + * + * Support macros to perform GPIO as fast as possible by avoiding conditionals and accessing memory-mapped registers directly. + * + ****/ + +#pragma once + +#include + +/** + * @brief Return value if flag is clear, otherwise 0 + * @param flag Only bit 0 is checked + * @param value if flag is clear + */ +#define GP_IF0(flag, value) ((value) & (((flag)&1) - 1)) + +/** + * @brief Return value if flag is set, otherwise 0 + * @param flag Only bit 0 is checked + * @param value if flag is set + */ +#define GP_IF1(flag, value) ((value) & ~(((flag)&1) - 1)) + +/** + * @brief Choose one of two values depending on whether \a flag is 0 or 1 + * @param flag Only bit 0 is checked + * @param value0 if flag is clear + * @param value1 if flag is set + */ +#define GP_SELECT(flag, value0, value1) (((value0) & (((flag)&1) - 1)) | ((value1) & ~(((flag)&1) - 1))) + +/** + * @brief Read a GPIO into bit 0 + * @param pin Pin number to read + * @param reg GPIO address for INPUT + * @retval uint32_t Either 0 or 1 + */ +#define GP_FAST_READ(pin, reg) ((*(const volatile uint32_t*)(reg) >> ((pin)&31)) & 1) + +/** + * @brief Set or clear a GPIO line + * @param pin Number of GPIO pin to write + * @param regclr Absolute register address used to CLEAR a GPIO to 0 + * @param regset Absolute register address used to SET a GPIO to 1 + */ +#define GP_FAST_WRITE(pin, val, regclr, regset) (*(volatile uint32_t*)GP_SELECT(val, regclr, regset) = BIT(pin)) diff --git a/Sming/Libraries/SPI/test/Kconfig b/Sming/Libraries/SPI/test/Kconfig new file mode 100644 index 0000000000..4c30b8132f --- /dev/null +++ b/Sming/Libraries/SPI/test/Kconfig @@ -0,0 +1,19 @@ +menu "SPI Library Tests" + config SPISOFT_ENABLE + bool "Test software SPI" + default Y + help + De-select to test hardware SPI + + config SPISOFT_CALIBRATE + bool "Run software SPI calbration sequence" + default N + depends on SPISOFT_ENABLE + help + Set increasing delay values so resulting clock frequency may be noted + + config CPU_FAST + bool "Use fast CPU clock" + default N + +endmenu diff --git a/Sming/Libraries/SPI/test/Makefile b/Sming/Libraries/SPI/test/Makefile new file mode 100644 index 0000000000..14dab6ca07 --- /dev/null +++ b/Sming/Libraries/SPI/test/Makefile @@ -0,0 +1,10 @@ +##################################################################### +#### Please don't change this file. Use component.mk instead #### +##################################################################### + +ifndef SMING_HOME +$(error SMING_HOME is not set. Please configure it as an environment variable) +endif + +# Include application Makefile +include $(SMING_HOME)/project.mk diff --git a/Sming/Libraries/SPI/test/app/.cs b/Sming/Libraries/SPI/test/app/.cs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Sming/Libraries/SPI/test/app/SPI.cpp b/Sming/Libraries/SPI/test/app/SPI.cpp new file mode 100644 index 0000000000..31377d3fd3 --- /dev/null +++ b/Sming/Libraries/SPI/test/app/SPI.cpp @@ -0,0 +1,383 @@ +#include +#include +#include + +namespace +{ +void printBin(const char* tag, uint32_t value) +{ + char buf[40]; + ultoa_wp(value, buf, 2, 32, '0'); + m_puts(tag); + m_putc(' '); + m_nputs(buf, 8); + m_putc(' '); + m_nputs(buf + 8, 8); + m_putc(' '); + m_nputs(buf + 16, 8); + m_putc(' '); + m_nputs(buf + 24, 8); + m_puts("\r\n"); +} + +#ifdef ARCH_HOST +void ioCallback(uint16_t c, uint8_t bits, bool read) +{ + char buf[40]; + ultoa_wp(c, buf, 2, 32, '0'); + m_puts(read ? "<< " : ">> "); + m_nputs(buf + 32 - bits, bits); + m_puts("\r\n"); +} +#endif + +#if SPISOFT_ENABLE +SPISoft spi(0); +#else +SPIBase& spi = SPI; +#endif + +#if CPU_FAST +using CycleTimer = CpuCycleTimerFast; +#else +using CycleTimer = CpuCycleTimer; +#endif + +} // namespace + +class SpiTest : public TestGroup +{ +public: + SpiTest() : TestGroup(F("SPI")), cycleTimes(F("Transaction Time")) + { + debug_i("Testing %sware SPI", SPISOFT_ENABLE ? "Soft" : "Hard"); + } + + void execute() override + { + System.setCpuFrequency(CycleTimer::cpuFrequency()); + + // spi.setup(SpiBus::SPI3); + REQUIRE(spi.begin()); + + debug_w("Connected SCK %u, MISO %u, MOSI %u", spi.pins.sck, spi.pins.miso, spi.pins.mosi); + +#ifdef ARCH_HOST + setDigitalHooks(nullptr); + loopbackTests(); +#else + settings.speed = 150e3; + spi.beginTransaction(settings); + settings.speed = 2e6; + spi.beginTransaction(settings); + settings.speed = 1e6; + spi.beginTransaction(settings); + settings.speed = 800e3; + spi.beginTransaction(settings); + settings.speed = 10000; + spi.beginTransaction(settings); + settings.speed = 30000; + spi.beginTransaction(settings); + settings.speed = 50000; + spi.beginTransaction(settings); + settings.speed = 1; + spi.beginTransaction(settings); + +#if SPISOFT_ENABLE && SPISOFT_CALIBRATE + testSoftwareDelays(); +#else + testBitPatterns(); +#endif +#endif + } + +#if SPISOFT_ENABLE && SPISOFT_CALIBRATE + void testSoftwareDelays() + { + TEST_CASE("Software SPI delay") + { + debug_w("Connect scope and measure"); + settings.speed = 0; + constexpr unsigned duration{5}; + constexpr unsigned loopInterval{250}; + loopCount = 0; + delay = -1; + timer.initializeMs([this]() { + if(loopCount-- == 0) { + Serial.println(); + + if(delay >= 100) { + timer.stop(); + testBitPatterns(); + return; + } + + if(delay >= 20) { + delay += 10; + } else if(delay < 12) { + ++delay; + } else { + delay = 20; + } + Serial.print("delay = "); + Serial.print(delay); + spi.setDelay(delay); + loopCount = duration * 1000 / loopInterval; + } + + spi.beginTransaction(settings); + uint8_t data[]{0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55}; + spi.transfer(data, sizeof(data)); + spi.endTransaction(); + + m_putc('.'); + }); + timer.start(); + return pending(); + } + } +#endif + + void testBitPatterns() + { + TEST_CASE("Bit Patterns") + { + debug_w("Connect scope and observe bit pattern"); + clearStats(); + constexpr unsigned duration{10}; + constexpr unsigned loopInterval{250}; + loopCount = duration * 1000 / loopInterval; + timer.initializeMs([this]() { bitPatterns(); }); + timer.start(); + return pending(); + } + } + + /* + * 6 transactions: + * + * - MODE0 MSBFIRST 0xAA00AA00 0x12345678 0x12 0x34 0x56 0x78 0x9A + * Viewed MSB first: 00 AA 00 AA 12 34 56 78 12 34 56 78 9A + * Viewed LSB first: 00 55 00 55 48 2C 6A 1E 48 2C 6A 1E 59 + * - MODE0 LSBFIRST 0xAA00AA00 0x12345678 0x12 0x34 0x56 0x78 0x9A + * Viewed MSB first: 55 00 55 00 1E 6A 2C 48 48 2C 6A 1E 59 + * Viewed LSB first: AA 00 AA 00 78 56 34 12 12 34 56 78 9A + * - MODE0 MSBFIRST 0xAA (13 bits) + * Clock idles LOW, latch on RISING edge + * - MODE1 MSBFIRST 0xAA (13 bits) + * Clock idles LOW, latch on FALLING edge + * - MODE2 MSBFIRST 0xAA (13 bits) + * Clock idles HIGH, latch on FALLINGg edge + * - MODE3 MSBFIRST 0xAA (13 bits) + * Clock idles HIGH, latch on RISING edge + */ + void bitPatterns() + { + settings.speed = 100000; + settings.dataMode = SPI_MODE0; + for(uint8_t bitOrder : {MSBFIRST, LSBFIRST}) { + settings.bitOrder = bitOrder; + beginTrans(); + spi.transfer32(0x00AA00AA); + spi.transfer32(0x12345678); + uint8_t data[]{0x12, 0x34, 0x56, 0x78, 0x9A}; + spi.transfer(data, ARRAY_SIZE(data)); + endTrans(13 * 8); + delayMicroseconds(100); + } + + delayMicroseconds(200); + for(auto dataMode : {SPI_MODE0, SPI_MODE1, SPI_MODE2, SPI_MODE3}) { + settings.bitOrder = MSBFIRST; + settings.dataMode = dataMode; + beginTrans(); + spi.transfer32(0xAA, 13); + endTrans(13); + delayMicroseconds(100); + } + + // Leave bus in mode 0 + settings.dataMode = SPI_MODE0; + spi.beginTransaction(settings); + spi.endTransaction(); + + m_putc('.'); + + if(loopCount-- != 0) { + return; + } + + timer.stop(); + m_puts("\r\n"); + printStats(); + + loopbackTests(); + + System.setCpuFrequency(CpuCycleClockNormal::cpuFrequency()); + spi.end(); + complete(); + } + + void loopbackTests() + { + if(!spi.loopback(true)) { + debug_w("WARNING: SPI loopback not supported. Manual connection required."); + debug_w("Connect MISO (GPIO%u) <-> MOSI (GPIO%u)", spi.pins.miso, spi.pins.mosi); + allowFailure = true; + } + + settings.speed = 8000000; + settings.dataMode = SPI_MODE0; + + TEST_CASE("32-bit values") + { +#ifdef ARCH_HOST + SPI.setDebugIoCallback(ioCallback); +#endif + clearStats(); + + /* + * Note: Single-bit transfers fail on esp32c3, and RP2040 doesn't + * support less than 4 bits. So start at 4. + */ + for(auto bitOrder : {MSBFIRST, LSBFIRST}) { + settings.bitOrder = bitOrder; + for(auto bits : {4, 7, 8, 9, 15, 16, 17, 19, 23, 24, 25, 29, 30, 31}) { + send(0, bits); + send(0xffffffff, bits); + send(0xaaaaaaaa, bits); + send(0x55555555, bits); + send(0x12345678, bits); + send(~0x12345678, bits); + } + } +#ifdef ARCH_HOST + SPI.setDebugIoCallback(nullptr); +#endif + + printStats(); + } + + TEST_CASE("Byte sequences") + { + clearStats(); + + DEFINE_FSTR_LOCAL(seq1, "This is a longer sequence but no more than 64 bytes"); + for(auto bitOrder : {MSBFIRST, LSBFIRST}) { + settings.bitOrder = bitOrder; + for(unsigned offset = 0; offset < 4; ++offset) { + // Small packet, fits in FIFO + send(seq1, offset); + + // Packet larger than FIFO + String seq2 = seq1; + seq2 += seq2; + seq2 += seq2; + seq2 += seq2; + seq2 += seq2; + send(seq2, offset); + } + } + + printStats(); + } + } + + void send(uint32_t outValue, uint8_t bits) + { + outValue &= BIT(bits) - 1; + Serial.print("TX 0x"); + Serial.print(outValue, HEX); + Serial.print(", "); + Serial.print(bits); + Serial.print(" bits, "); + Serial.print(settings.bitOrder == MSBFIRST ? 'M' : 'L'); + Serial.println("SB first"); + printBin(">", outValue); + + beginTrans(); + spi.beginTransaction(settings); + uint32_t inValue = spi.transfer32(outValue, bits); + endTrans(bits); + + if(inValue != outValue) { + printBin("<", inValue); + Serial.print("RX 0x"); + Serial.println(inValue, HEX); + if(allowFailure) { + fail(__PRETTY_FUNCTION__); + return; + } + } + + REQUIRE(inValue == outValue); + } + + void send(const String& outData, unsigned startOffset) + { + String inData = outData; + auto bufptr = reinterpret_cast(inData.begin() + startOffset); + auto length = inData.length() - startOffset; + + debug_i("TX %u bytes, startOffset %u, %cSB first", length, startOffset, + settings.bitOrder == MSBFIRST ? 'M' : 'L'); + + beginTrans(); + spi.transfer(bufptr, length); + endTrans(length * 8); + + auto outptr = outData.c_str() + startOffset; + if(memcmp(outptr, bufptr, length) != 0) { + length = std::min(length, 64U); + m_printHex(">", outptr, length); + m_printHex("<", bufptr, length); + if(allowFailure) { + fail(__PRETTY_FUNCTION__); + } else { + TEST_ASSERT(false); + } + } + } + +private: + void clearStats() + { + cycleTimes.clear(); + totalBitCount = 0; + } + + __forceinline void beginTrans() + { + cycleTimes.start(); + spi.beginTransaction(settings); + } + + __forceinline void endTrans(size_t bitCount) + { + spi.endTransaction(); + cycleTimes.update(); + totalBitCount += bitCount; + } + + void printStats() + { + Serial.println(cycleTimes); + unsigned kbps = 1e6 * totalBitCount / cycleTimes.getTotalTime(); + Serial.print("Average bitrate: "); + Serial.print(kbps); + Serial.println(" kbit/s"); + } + + Timer timer; + MinMaxTimes cycleTimes; + size_t totalBitCount{0}; + SPISettings settings; + unsigned loopCount{0}; + int delay{0}; + bool allowFailure{false}; +}; + +void REGISTER_TEST(SPI) +{ + registerGroup(); +} diff --git a/Sming/Libraries/SPI/test/app/application.cpp b/Sming/Libraries/SPI/test/app/application.cpp new file mode 100644 index 0000000000..88ac40e1e8 --- /dev/null +++ b/Sming/Libraries/SPI/test/app/application.cpp @@ -0,0 +1,32 @@ +#include + +#define TEST_GROUP_INTERVAL 500 +#define RESTART_DELAY 10000 + +extern void REGISTER_TEST(SPI); + +namespace +{ +void testsComplete() +{ +#ifdef ARCH_HOST + System.restart(); +#else + SmingTest::runner.execute(testsComplete, RESTART_DELAY); +#endif +} + +} // namespace + +void init() +{ + Serial.setTxBufferSize(1024); + Serial.begin(SERIAL_BAUD_RATE); + Serial.systemDebugOutput(true); + + debug_e("SPI test application"); + + REGISTER_TEST(SPI); + SmingTest::runner.setGroupIntervalMs(TEST_GROUP_INTERVAL); + System.onReady([]() { SmingTest::runner.execute(testsComplete); }); +} diff --git a/Sming/Libraries/SPI/test/component.mk b/Sming/Libraries/SPI/test/component.mk new file mode 100644 index 0000000000..b8c5e6f45e --- /dev/null +++ b/Sming/Libraries/SPI/test/component.mk @@ -0,0 +1,26 @@ +ARDUINO_LIBRARIES := \ + SmingTest \ + SPI + +# +HOST_NETWORK_OPTIONS := --nonet +DISABLE_NETWORK := 1 +DEBUG_VERBOSE_LEVEL := 2 + +# +COMPONENT_VARS += SPISOFT_ENABLE +SPISOFT_ENABLE ?= 0 +COMPONENT_CPPFLAGS += -DSPISOFT_ENABLE=$(SPISOFT_ENABLE) + +# +COMPONENT_VARS += SPISOFT_CALIBRATE +SPISOFT_CALIBRATE ?= 0 +COMPONENT_CPPFLAGS += -DSPISOFT_CALIBRATE=$(SPISOFT_CALIBRATE) + +# +COMPONENT_VARS += CPU_FAST +CPU_FAST ?= 0 +COMPONENT_CPPFLAGS += -DCPU_FAST=$(CPU_FAST) + +.PHONY: execute +execute: flash run diff --git a/Sming/Libraries/jerryscript b/Sming/Libraries/jerryscript index 91dee9e149..ac5f4ed3cf 160000 --- a/Sming/Libraries/jerryscript +++ b/Sming/Libraries/jerryscript @@ -1 +1 @@ -Subproject commit 91dee9e1490375f0a0bf583805d38937c96db1bd +Subproject commit ac5f4ed3cf68b4f5877db890fa02929a128498c3 diff --git a/Sming/Libraries/jerryscript.no-recursive b/Sming/Libraries/jerryscript.no-recursive new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Sming/Makefile b/Sming/Makefile index 9f241f7ced..b42993d4a1 100644 --- a/Sming/Makefile +++ b/Sming/Makefile @@ -61,7 +61,7 @@ submodules: $(ALL_SUBMODULES:=/.submodule) ##Fetch all third-party submodules (b # Build a list of available Components COMPONENT_SEARCH_DIRS += $(ARCH_COMPONENTS) Components Libraries -ALL_COMPONENT_DIRS := $(sort $(foreach d,$(COMPONENT_SEARCH_DIRS),$(call ListSubDirs,$d))) +ALL_COMPONENT_DIRS := $(sort $(call ListSubDirs,$(COMPONENT_SEARCH_DIRS))) # Generates a rule to fetch all submodules for a Component # $1 Component name @@ -116,8 +116,9 @@ SAMPLE_NAMES = $(notdir $(SAMPLE_PATHS)) samples: $(SAMPLES_BUILT) ##Build all sample applications # Build any samples which haven't yet been marked -$(SAMPLES_BUILT): - @printf "\n\n** Building $(notdir $(call dirx,$@)) **\n\n" +%.built: + @printf "\n\n** Building $(@D) **\n\n" + $(Q) $(MAKE) --no-print-directory -C $(@D) submodules $(Q) $(MAKE) --no-print-directory -C $(@D) PIP_ARGS=-q python-requirements sample $(Q) touch $@ @@ -143,10 +144,6 @@ COMPONENT_SAMPLES_BUILT = $(addsuffix $(BUILT_SUFFIX),$(COMPONENT_SAMPLE_PATHS)) .PHONY: build-component-samples build-component-samples: $(COMPONENT_SAMPLES_BUILT) -$(COMPONENT_SAMPLES_BUILT): - @printf "\n\n** Building $(@D) **\n\n" - $(Q) $(MAKE) --no-print-directory -C $(@D) PIP_ARGS=-q python-requirements sample - $(Q) touch $@ # This file is generated on failure during test phase export TEST_FAILURE_FILE := $(SMING_HOME)/.test-failure @@ -218,7 +215,7 @@ CS_SEARCH_DIRS ?= $(call ListAllSubDirs,$(CS_ROOT_DIRS)) # Resultant set of directories whose contents to apply coding style to CS_DIRS ?= $(patsubst %/.cs,%,$(wildcard $(foreach d,$(CS_SEARCH_DIRS),$d/.cs))) # Files to apply coding style to -CS_FILES = $(if $(CS_DIRS),$(call rwildcard,$(CS_DIRS:=/*),%.cpp %.hpp %.h %.c),) +CS_FILES = $(if $(CS_DIRS),$(sort $(call rwildcard,$(CS_DIRS:=/*),%.cpp %.hpp %.h %.c))) .PHONY: cs cs: ##Apply coding style to all core files diff --git a/Sming/Platform/Clocks.h b/Sming/Platform/Clocks.h index 3e7ad28f8b..c0cf401503 100644 --- a/Sming/Platform/Clocks.h +++ b/Sming/Platform/Clocks.h @@ -91,11 +91,6 @@ struct CpuCycleClock return esp_get_ccount(); } - static constexpr bool isFast() - { - return cpuFreq == eCF_160MHz; - } - static constexpr CpuFrequency cpuFrequency() { return cpuFreq; diff --git a/Sming/Wiring/MacAddress.cpp b/Sming/Wiring/MacAddress.cpp index 3022bc93d3..6d0b697769 100644 --- a/Sming/Wiring/MacAddress.cpp +++ b/Sming/Wiring/MacAddress.cpp @@ -23,13 +23,30 @@ #include "MacAddress.h" #include -uint8_t MacAddress::operator[](unsigned index) const +MacAddress::MacAddress(const String& s) { - if(index >= sizeof(octets)) { - abort(); + // Maximum length with 2 hex digits per octet plus optional separator + bool sep; + if(s.length() == 12) { + sep = false; + } else if(s.length() == 17) { + sep = true; + } else { + return; } - - return octets[index]; + auto str = s.c_str(); + Octets res{}; + for(unsigned i = 0; i < 6; ++i) { + if(sep && i != 5 && strchr(_F(":-.,/ "), str[2]) == nullptr) { + return; + } + if(!isxdigit(str[0]) || !isxdigit(str[1])) { + return; + } + res[i] = (unhex(str[0]) << 4) | unhex(str[1]); + str += 2 + unsigned(sep); + } + memcpy(octets, res, sizeof(res)); } uint8_t& MacAddress::operator[](unsigned index) diff --git a/Sming/Wiring/MacAddress.h b/Sming/Wiring/MacAddress.h index 050e3ee475..c8405348c8 100644 --- a/Sming/Wiring/MacAddress.h +++ b/Sming/Wiring/MacAddress.h @@ -53,6 +53,13 @@ class MacAddress : public Printable setOctets(octets); } + /** + * @brief Create a MAC address from valid string. + * e.g. 01:02:03:04:05:06 + * Separators are optional. + */ + MacAddress(const String& s); + /** * @brief Get the octets of the MAC address. */ @@ -72,14 +79,17 @@ class MacAddress : public Printable /** * @brief Get the octet at the given index in the MAC address. * @param index The index. - * @return The octet at the given index. + * @retval const uint8_t& Read-only reference to the octet at the given index. */ - uint8_t operator[](unsigned index) const; + const uint8_t& operator[](unsigned index) const + { + return const_cast(this)->operator[](index); + } /** * @brief Get a reference to the octet at the given index in the MAC address. * @param index The index. - * @return A reference to the octet at the given index. + * @retval uint8_t& A writeable reference to the octet at the given index. */ uint8_t& operator[](unsigned index); diff --git a/Sming/Wiring/WHashMap.h b/Sming/Wiring/WHashMap.h index 9eeb9bc6b4..790e530356 100644 --- a/Sming/Wiring/WHashMap.h +++ b/Sming/Wiring/WHashMap.h @@ -70,6 +70,26 @@ template class HashMap return *this; } + Value& operator*() + { + return v; + } + + const Value& operator*() const + { + return v; + } + + Value* operator->() + { + return &v; + } + + const Value* operator->() const + { + return &v; + } + private: const K& k; Value& v; diff --git a/Sming/Wiring/WString.cpp b/Sming/Wiring/WString.cpp index 4975d78efb..f7fa4ad78b 100644 --- a/Sming/Wiring/WString.cpp +++ b/Sming/Wiring/WString.cpp @@ -909,7 +909,7 @@ void String::remove(size_t index, size_t count) } char* writeTo = buffer() + index; len -= count; - memcpy(writeTo, writeTo + count, len - index); + memmove(writeTo, writeTo + count, len - index); setlen(len); } diff --git a/Sming/build.mk b/Sming/build.mk index fcd0e0555a..14b1c0be99 100644 --- a/Sming/build.mk +++ b/Sming/build.mk @@ -10,8 +10,8 @@ SMING_HOME := $(patsubst %/,%,$(call FixPath,$(SMING_HOME))) DEBUG_VARS += SMING_ARCH SMING_SOC ifeq (,$(SMING_ARCH)) ifeq (,$(SMING_SOC)) - SMING_ARCH := Esp8266 - SMING_SOC := esp8266 + override SMING_ARCH := Esp8266 + override SMING_SOC := esp8266 else override SMING_ARCH := $(notdir $(call dirx,$(filter %/$(SMING_SOC)-soc.json,$(SOC_CONFIG_FILES)))) ifeq (,$(SMING_ARCH)) @@ -19,7 +19,7 @@ ifeq (,$(SMING_ARCH)) endif endif else ifeq (,$(filter $(SMING_SOC),$(ARCH_$(SMING_ARCH)_SOC))) - SMING_SOC := $(firstword $(ARCH_$(SMING_ARCH)_SOC)) + override SMING_SOC := $(firstword $(ARCH_$(SMING_ARCH)_SOC)) endif ifeq (,$(wildcard $(SMING_HOME)/Arch/$(SMING_ARCH)/build.mk)) @@ -39,11 +39,18 @@ DEBUG_VARS += \ CXX \ AR \ LD \ + NINJA \ NM \ OBJCOPY \ OBJDUMP \ GDB +ifdef NINJA +NINJA := $(call FixPath,$(NINJA)) +else +NINJA := ninja +endif + DEBUG_VARS += SMING_RELEASE ifeq ($(SMING_RELEASE),1) BUILD_TYPE := release @@ -274,9 +281,12 @@ endef # $1 -> List of files define ClangFormat $(if $(V),$(info Applying coding style to $(words $1) files ...)) - @for FILE in $1; do \ - $(CLANG_FORMAT) -i -style=file $$FILE; \ - done + $(call ClangFormatBatch,$1) +endef + +define ClangFormatBatch + @$(CLANG_FORMAT) -i -style=file $(wordlist 1,20,$1) + $(if $(word 21,$1),$(call ClangFormatBatch,$(wordlist 21,1000000,$1))) endef define ListSubmodules diff --git a/Sming/component.mk b/Sming/component.mk index 32d727928d..16059d289e 100644 --- a/Sming/component.mk +++ b/Sming/component.mk @@ -17,6 +17,7 @@ COMPONENT_DEPENDS := \ FlashString \ Spiffs \ IFS \ + SPI \ terminal COMPONENT_DOXYGEN_PREDEFINED := \ diff --git a/Sming/project.mk b/Sming/project.mk index 120568a03d..cb5ce2ade6 100644 --- a/Sming/project.mk +++ b/Sming/project.mk @@ -227,7 +227,7 @@ endif # PROJECT_SOC endef # ParseComponent # Build a list of all available Components -ALL_COMPONENT_DIRS = $(foreach d,$(ALL_SEARCH_DIRS),$(call ListSubDirs,$d)) +ALL_COMPONENT_DIRS = $(call ListSubDirs,$(ALL_SEARCH_DIRS)) # Lookup Component directory from a name # $1 -> Component name diff --git a/Sming/util.mk b/Sming/util.mk index 53d64bcf26..fa70e23c8c 100644 --- a/Sming/util.mk +++ b/Sming/util.mk @@ -9,7 +9,7 @@ ifeq ($(OS),Windows_NT) # Powershell does weird things to this variable, revert to default override MAKE := make -FixPath = $(subst //,/,$(subst \,/,/$(subst :,,$1))) +FixPath = $(if $(findstring :,$1),$(subst //,/,$(subst \,/,/$(subst :,,$1))),$(abspath $1)) else FixPath = $1 endif @@ -46,7 +46,7 @@ endef # Results are sorted and without trailing path separator # $1 -> Root paths define ListSubDirs -$(foreach d,$(dir $(wildcard $1/*/.)),$(d:/=)) +$(foreach d,$(dir $(wildcard $(addsuffix /*/.,$1))),$(d:/=)) endef # Check that $2 is a valid sub-directory of $1. Return empty string if not. diff --git a/Tools/ci/build.cmd b/Tools/ci/build.cmd index 5124c44373..4efca9ff24 100644 --- a/Tools/ci/build.cmd +++ b/Tools/ci/build.cmd @@ -9,9 +9,6 @@ if "%BUILD_DOCS%"=="true" ( goto :EOF ) -subst z: %CI_BUILD_DIR% -set SMING_HOME=z:\Sming - cd /d %SMING_HOME% call Arch\%SMING_ARCH%\Tools\ci\build.setup.cmd || goto :error @@ -33,8 +30,8 @@ cd /d %SMING_PROJECTS_DIR%/samples/Basic_Blink make help make list-config -REM HostTests should build and run on all architectures -%MAKE_PARALLEL% -C "%SMING_PROJECTS_DIR%/tests/HostTests" +REM HostTests must build for all architectures +%MAKE_PARALLEL% -C "%SMING_PROJECTS_DIR%/tests/HostTests" || goto :error REM Start Arch-specific tests cd /d %SMING_HOME% diff --git a/Tools/ci/library/Makefile b/Tools/ci/library/Makefile index 01c044601b..c93a0e195f 100644 --- a/Tools/ci/library/Makefile +++ b/Tools/ci/library/Makefile @@ -36,6 +36,7 @@ apps: $(APP_NAMES) .PHONY: $(APP_NAMES) $(APP_NAMES): @printf "\n\n** Building $@ for $(SMING_SOC) **\n\n" + $(Q) $(MAKE) --no-print-directory -C $@ submodules $(Q) $(MAKE) --no-print-directory -C $@ PIP_ARGS=-q python-requirements sample .PHONY: run-test diff --git a/Tools/ci/library/appveyor.txt b/Tools/ci/library/appveyor.txt index c9f3ec79e3..47561c9f9f 100644 --- a/Tools/ci/library/appveyor.txt +++ b/Tools/ci/library/appveyor.txt @@ -26,17 +26,17 @@ install: - ps: | Start-Process -FilePath git -ArgumentList "clone $env:SMING_REPO -b $env:SMING_BRANCH --depth 1 sming" -Wait -NoNewWindow $env:COMPONENT_SEARCH_DIRS = (resolve-path "$pwd/..").path - sming/Tools/ci/setenv.ps1 - make -C "$env:SMING_HOME" "fetch-$env:APPVEYOR_PROJECT_SLUG" + $env:CI_MAKEFILE = (resolve-path "$pwd/sming/Tools/ci/library/Makefile").path + . sming/Tools/ci/setenv.ps1 - cmd: | - if "%APPVEYOR_BUILD_WORKER_CLOUD%"=="" sming\Tools\ci\install.cmd %SMING_ARCH% %INSTALL_OPTS% + if "%APPVEYOR_BUILD_WORKER_CLOUD%"=="" sming\Tools\ci\install.cmd %SMING_ARCH% - sh: | if [ -z "$APPVEYOR_BUILD_WORKER_CLOUD" ]; then - . sming/Tools/ci/install.sh ${SMING_ARCH,,} $INSTALL_OPTS + . sming/Tools/ci/install.sh ${SMING_ARCH,,} fi build_script: - - sh: make -j$(nproc) -f $SMING_HOME/../Tools/ci/library/Makefile - - cmd: make -j%NUMBER_OF_PROCESSORS% -f %SMING_HOME%/../Tools/ci/library/Makefile + - sh: make -j$(nproc) -f $CI_MAKEFILE + - cmd: make -j%NUMBER_OF_PROCESSORS% -f %CI_MAKEFILE% diff --git a/Tools/ci/setenv.ps1 b/Tools/ci/setenv.ps1 index 9113108898..a2c69a3925 100644 --- a/Tools/ci/setenv.ps1 +++ b/Tools/ci/setenv.ps1 @@ -26,9 +26,16 @@ if (Test-Path "$env:PICO_TOOLCHAIN_PATH" ) { if ($IsWindows) { $env:PATH = "C:\MinGW\msys\1.0\bin;C:\MinGW\bin;$env:PATH" - $env:PATH = "C:\Python39;C:\Python39\Scripts;$env:PATH" - $env:PYTHON = "C:\Python39\python" - $env:ESP32_PYTHON_PATH = "C:\Python39" + if ($null -eq $env:PYTHON_PATH) { + $env:PYTHON_PATH = "C:\Python39-x64" + if ( -not (Test-Path "$env:PYTHON_PATH") ) { + $env:PYTHON_PATH = "C:\Python39" + } + } + + $env:PATH = "$env:PYTHON_PATH;$env:PYTHON_PATH\Scripts;$env:PATH" + $env:PYTHON = "$env:PYTHON_PATH\python" + $env:ESP32_PYTHON_PATH = "$env:PYTHON_PATH" $env:PATH = "$env:PROGRAMFILES\CMake\bin;$env:PATH" diff --git a/Tools/ci/testnotify.sh b/Tools/ci/testnotify.sh new file mode 100755 index 0000000000..c681e46964 --- /dev/null +++ b/Tools/ci/testnotify.sh @@ -0,0 +1,47 @@ +#!/bin/bash +# +# Send test notification to CI framework +# +# Don't call directly; use makefile functions in `util.mk` +# + +set -e + +testname="$1" +status="$2" + +testfile=/tmp/$MODULE.test +mkdir -p "$(dirname "$testfile")" +curNanos=$(date +%s%N) +if [ -f "$testfile" ]; then + prevNanos=$(<"$testfile") + elapsedMillis=$(( (curNanos - prevNanos) / 1000000 )) +fi + +case "$status" in + "start") + cmd=AddTest + status=Running + elapsedMillis=0 + ;; + "success") + cmd=UpdateTest + status=Passed + ;; + "fail") + cmd=UpdateTest + status=Failed + ;; + *) + echo "Invalid status: $status" + exit 1 + ;; +esac + +if [ -n "$APPVEYOR" ]; then + appveyor $cmd "$testname" -Framework Sming -Filename "$MODULE" -Outcome $status -Duration $elapsedMillis +else + echo "TestNotify: $cmd $testname -Framework Sming -Filename $MODULE -Outcome $status -Duration $elapsedMillis" +fi + +echo "$curNanos" > "$testfile" diff --git a/Tools/ci/util.mk b/Tools/ci/util.mk new file mode 100644 index 0000000000..b19337edb8 --- /dev/null +++ b/Tools/ci/util.mk @@ -0,0 +1,24 @@ +# +# CI utilities +# + +include $(SMING_HOME)/util.mk + +SMING_HOME := $(patsubst %/,%,$(call FixPath,$(SMING_HOME))) +CI_TOOLS_DIR := $(abspath $(SMING_HOME)/../Tools/ci) + +$(info CI_TOOLS_DIR = $(CI_TOOLS_DIR)) + +ifndef MODULE +MODULE := $(patsubst $(SMING_HOME)/%,%,$(shell pwd)) +endif + +export MODULE + +# Send CI test framework notification +# $1 -> Name of test +# $2 -> Status (start, success, fail) +# $MODULE -> Test module name +define TestNotify + $(CI_TOOLS_DIR)/testnotify.sh $1 $2 +endef diff --git a/Tools/install.sh b/Tools/install.sh index e45be81e65..26f1c72939 100755 --- a/Tools/install.sh +++ b/Tools/install.sh @@ -114,6 +114,7 @@ else curl \ git \ make \ + ninja-build \ unzip \ g++ \ g++-multilib \ @@ -137,6 +138,7 @@ else glibc-devel.i686 \ libstdc++.i686 \ make \ + ninja-build \ python3 \ python3-pip \ sed \ diff --git a/appveyor.yml b/appveyor.yml index 972d188321..fb4c571ef5 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,5 +1,4 @@ image: -- Ubuntu2004 - Visual Studio 2019 environment: @@ -9,21 +8,6 @@ environment: matrix: - SMING_ARCH: Host - - SMING_ARCH: Esp8266 - - - SMING_ARCH: Esp32 - SMING_SOC: esp32 - - - SMING_ARCH: Esp32 - SMING_SOC: esp32s2 - - - SMING_ARCH: Esp32 - SMING_SOC: esp32c3 - - - SMING_ARCH: Rp2040 - - - BUILD_DOCS: true - install: - ps: | # Set up environment variables for all environments and build types diff --git a/docs/Makefile b/docs/Makefile index c8b8165c34..e6eed83edb 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -108,7 +108,7 @@ COMPONENT_ROOT_DIRS := \ $(SMINGDIR)/samples # All directories where a README file should/must exist, and where a component.mk file could exist -COMPONENT_DIRS := $(SMING_HOME) $(foreach d,$(COMPONENT_ROOT_DIRS),$(call ListSubDirs,$d)) +COMPONENT_DIRS := $(SMING_HOME) $(call ListSubDirs,$(COMPONENT_ROOT_DIRS)) COMPONENT_SAMPLES := $(wildcard $(addsuffix /samples/*/component.mk,$(COMPONENT_DIRS))) COMPONENT_DIRS += $(COMPONENT_SAMPLES:/component.mk=) @@ -163,6 +163,7 @@ COMPONENT_RULE := __no_build__ COMPONENT_NAME := $1 COMPONENT_PATH := $2 COMPONENT_VARS := +COMPONENT_RELINK_VARS := CONFIG_VARS := RELINK_VARS := CACHE_VARS := @@ -189,7 +190,7 @@ DOXYGEN_INPUT += $$(addprefix $2/,$$(COMPONENT_DOXYGEN_INPUT)) DOXYGEN_INCLUDE_PATH += $$(addprefix $2/,$$(COMPONENT_DOXYGEN_INCLUDE)) DOXYGEN_PREDEFINED += $$(COMPONENT_DOXYGEN_PREDEFINED) # -COMPONENT_ENVVARS := $$(sort $$(COMPONENT_VARS) $$(CONFIG_VARS) $$(RELINK_VARS) $$(CACHE_VARS) $$(DEBUG_VARS)) +COMPONENT_ENVVARS := $$(sort $$(COMPONENT_VARS) $$(COMPONENT_RELINK_VARS) $$(CONFIG_VARS) $$(RELINK_VARS) $$(CACHE_VARS) $$(DEBUG_VARS)) CMP_$2_ENVVARS := $$(COMPONENT_ENVVARS) $$(foreach c,$$(COMPONENT_DEPENDS) $$(ARDUINO_LIBRARIES),$$(eval CMP_$$c_XREF += $2)) diff --git a/docs/requirements.txt b/docs/requirements.txt index bcfe112050..4ee83e6283 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -8,6 +8,6 @@ breathe==4.31.0 sphinxcontrib-wavedrom sphinx-copybutton sphinxcontrib-seqdiag==2.0.0 -jinja2==2.11.3 +jinja2>=3.0.3 setuptools>=57.5.0 funcparserlib==1.0.0a0 diff --git a/docs/source/framework/core/data/cstringarray.rst b/docs/source/framework/core/data/cstringarray.rst index 78a7dfe746..a53f04abdb 100644 --- a/docs/source/framework/core/data/cstringarray.rst +++ b/docs/source/framework/core/data/cstringarray.rst @@ -132,6 +132,29 @@ For more complex operations:: } +Pushing and popping +------------------- + +CStringArray can be used as a simple FIFO or stack using push/pop methods. +Behaviour is similar to STL deque, except pop methods also return a value. + +STACK:: + + CStringArray csa; + csa.pushBack("first value"); + csa.pushBack("second value"); + String popStack = csa.popBack(); // "second value" + +FIFO:: + + CStringArray csa; + csa.pushBack("first value"); + csa.pushBack("second value"); + String deque = csa.popFront(); // "first value" + +Note that popping values does not perform any memory de-allocation. + + Comparison with Vector ------------------------------ diff --git a/docs/source/upgrading/4.5-4.6.rst b/docs/source/upgrading/4.5-4.6.rst new file mode 100644 index 0000000000..ca543b06e6 --- /dev/null +++ b/docs/source/upgrading/4.5-4.6.rst @@ -0,0 +1,19 @@ +From v4.5 to v4.6 +================= + +.. highlight:: c++ + +SPI Byte/Bit ordering +--------------------- + +The :cpp:class:`SPISettings` class has been revised to be consistent with Arduino ESP8266, ESP32, RP2040, etc. +which provide a **bitOrder** setting but not ``byteOrder``. + +Bytes are now always sent LSB first, which corresponds with the system endianness. +Bit order simply indicates how the bits within each byte are sent on the wire. +This is predominantly MSB first, the default. + +The :cpp:class:`SPISoft` class has been upgraded to support bit ordering, transactions +and includes automatic delay calculation for the ESP8266. + +See :issue:`1428`. diff --git a/docs/source/upgrading/index.rst b/docs/source/upgrading/index.rst index 5dde9f953d..915fe4dc28 100644 --- a/docs/source/upgrading/index.rst +++ b/docs/source/upgrading/index.rst @@ -7,6 +7,7 @@ For newer versions we have dedicated pages. .. toctree:: :maxdepth: 1 + 4.5-4.6 4.4-4.5 4.3-4.4 4.2-4.3 diff --git a/samples/Arducam/app/application.cpp b/samples/Arducam/app/application.cpp index 673e08ae19..0a7163bbb2 100644 --- a/samples/Arducam/app/application.cpp +++ b/samples/Arducam/app/application.cpp @@ -11,7 +11,6 @@ #include #include #include -#include // If you want, you can define WiFi settings globally in Eclipse Environment Variables #ifndef WIFI_SSID diff --git a/samples/Arducam/component.mk b/samples/Arducam/component.mk index a1e75ed048..76533c24f2 100644 --- a/samples/Arducam/component.mk +++ b/samples/Arducam/component.mk @@ -1,4 +1,3 @@ -COMPONENT_SOC := esp* ARDUINO_LIBRARIES := ArduCAM -HWCONFIG = spiffs +HWCONFIG = spiffs-2m SPIFF_FILES = web/build diff --git a/samples/Basic_APA102/app/application.cpp b/samples/Basic_APA102/app/application.cpp index 463401b5f3..606c1e75e7 100644 --- a/samples/Basic_APA102/app/application.cpp +++ b/samples/Basic_APA102/app/application.cpp @@ -21,16 +21,13 @@ #define NUM_LED 60 // number of LEDs on strip -#define SPI_SCLK 14 -#define SPI_MOSI 13 -#define SPI_MISO 12 #define SPI_CS 2 Timer procTimer; // in this demo, the same ports for HW and SW SPI are used #ifdef _USE_SOFTSPI -SPISoft sSPI(SPI_MISO, SPI_MOSI, SPI_SCLK, 200); +SPISoft sSPI(1); APA102 LED(NUM_LED, sSPI); // APA102 constructor for software SPI, call with number of LEDs #else APA102 LED(NUM_LED); // APA102 constructor, call with number of LEDs @@ -122,11 +119,6 @@ void init() Serial.begin(SERIAL_BAUD_RATE); Serial.systemDebugOutput(true); -#ifndef DISABLE_WIFI - WifiAccessPoint.enable(false); - WifiStation.enable(false); -#endif - /* configure SPI */ LED.begin(); // default 4MHz clk, CS on PIN_2 //LED.begin(SPI_1MHZ); diff --git a/samples/Basic_APA102/component.mk b/samples/Basic_APA102/component.mk index 6fc9a3b0be..ddf51eff08 100644 --- a/samples/Basic_APA102/component.mk +++ b/samples/Basic_APA102/component.mk @@ -1,2 +1,4 @@ -COMPONENT_SOC := esp* ARDUINO_LIBRARIES := APA102 + +SPISOFT_DELAY := -1 +DISABLE_NETWORK := 1 diff --git a/samples/Basic_AWS/component.mk b/samples/Basic_AWS/component.mk index 75d34a5e87..6e25c28d7d 100644 --- a/samples/Basic_AWS/component.mk +++ b/samples/Basic_AWS/component.mk @@ -1,4 +1,3 @@ -COMPONENT_SOC := esp* host ENABLE_SSL := 1 MQTT_NO_COMPAT := 1 ENABLE_CUSTOM_HEAP := 1 diff --git a/samples/Basic_Delegates/app/speed.cpp b/samples/Basic_Delegates/app/speed.cpp index 208f8e9c59..3250f2d1e8 100644 --- a/samples/Basic_Delegates/app/speed.cpp +++ b/samples/Basic_Delegates/app/speed.cpp @@ -3,7 +3,6 @@ */ #include -#include #include "callbacks.h" #ifdef ARCH_HOST diff --git a/samples/Basic_IFS/basic_ifs_Rp2040.hw b/samples/Basic_IFS/basic_ifs_Rp2040.hw new file mode 100644 index 0000000000..b6090a2e16 --- /dev/null +++ b/samples/Basic_IFS/basic_ifs_Rp2040.hw @@ -0,0 +1,25 @@ +{ + "name": "Rp2040 config", + "arch": "Rp2040", + "base_config": "basic_ifs", + "options": [ + "2m" + ], + "partitions": { + "rom0": { + "size": "480K" + }, + "lfs1": { + "size": "932K", + "address": "0x00078000" + }, + "spiffs0": { + "address": "0x00161000", + "size": "376K" + }, + "fwfs1": { + "address": "0x001bf000", + "size": "256K" + } + } +} \ No newline at end of file diff --git a/samples/Basic_IFS/component.mk b/samples/Basic_IFS/component.mk index ffe779282a..feec6c667e 100644 --- a/samples/Basic_IFS/component.mk +++ b/samples/Basic_IFS/component.mk @@ -1,4 +1,3 @@ -COMPONENT_SOC := esp* host COMPONENT_DEPENDS := LittleFS # Empty SPIFFS partition please diff --git a/samples/Basic_IFS/fsimage.fwfs b/samples/Basic_IFS/fsimage.fwfs index 8e63a810cd..40051d1e23 100644 --- a/samples/Basic_IFS/fsimage.fwfs +++ b/samples/Basic_IFS/fsimage.fwfs @@ -9,9 +9,7 @@ "test.jsonc": "basic_ifs.hw", "readme.md": "${SMING_HOME}/Components/IFS/README.rst", "sming.png": "${SMING_HOME}/../docs/api-logo.png", - "Data": "${SMING_HOME}/Core/Data", - "framework": "${SMING_HOME}/../docs/source/framework", - "Sming": "${SMING_HOME}/Core" + "Data": "${SMING_HOME}/Core/Data" }, // Directories to mount other object stores "mountpoints": { diff --git a/samples/Basic_NFC/app/application.cpp b/samples/Basic_NFC/app/application.cpp index fb2473f90c..9d532ec4bd 100644 --- a/samples/Basic_NFC/app/application.cpp +++ b/samples/Basic_NFC/app/application.cpp @@ -5,7 +5,7 @@ Timer procTimer; static Timer nfcScanTimer; int helloCounter = 0; -void ICACHE_FLASH_ATTR scanNfc(byte scanner); +void scanNfc(byte scanner); #define SS_PIN 4 // D2 @@ -22,7 +22,7 @@ void sayHello() } } //--------------------------------- -static void ICACHE_FLASH_ATTR dump_byte_array(byte* buffer, byte bufferSize) +static void dump_byte_array(byte* buffer, byte bufferSize) { String hexOut; for(byte i = 0; i < bufferSize; i++) { @@ -31,7 +31,7 @@ static void ICACHE_FLASH_ATTR dump_byte_array(byte* buffer, byte bufferSize) debugf("%s", hexOut.c_str()); } //--------------------------------- -void ICACHE_FLASH_ATTR scanNfc(byte scanner) +void scanNfc(byte scanner) { if(!mfrc522.PICC_IsNewCardPresent()) { debugf("Scanning nfc Scanner:%d \r\n", scanner); diff --git a/samples/Basic_NFC/component.mk b/samples/Basic_NFC/component.mk index d428c401d4..daa48a38fe 100644 --- a/samples/Basic_NFC/component.mk +++ b/samples/Basic_NFC/component.mk @@ -1,3 +1,2 @@ -COMPONENT_SOC := esp* ARDUINO_LIBRARIES := MFRC522 DISABLE_NETWORK := 1 diff --git a/samples/Basic_ProgMem/app/TestProgmem.cpp b/samples/Basic_ProgMem/app/TestProgmem.cpp index 90999f58eb..f922abf4b2 100644 --- a/samples/Basic_ProgMem/app/TestProgmem.cpp +++ b/samples/Basic_ProgMem/app/TestProgmem.cpp @@ -5,9 +5,8 @@ */ #include "TestProgmem.h" -#include "FlashData.h" -#include "Print.h" #include +#include "FlashData.h" #include #include #include diff --git a/samples/Basic_ProgMem/include/TestProgmem.h b/samples/Basic_ProgMem/include/TestProgmem.h index a6890097b4..b62bcace89 100644 --- a/samples/Basic_ProgMem/include/TestProgmem.h +++ b/samples/Basic_ProgMem/include/TestProgmem.h @@ -4,11 +4,8 @@ * @author: 19 Sep 2018 - mikee47 */ -#ifndef __TEST_PROGMEM_H_ -#define __TEST_PROGMEM_H_ +#pragma once -#include "Print.h" +#include void testProgmem(Print& out); - -#endif /* __TEST_PROGMEM_H_ */ diff --git a/samples/Basic_Servo/app/application.cpp b/samples/Basic_Servo/app/application.cpp index a918117b14..f77be8c461 100644 --- a/samples/Basic_Servo/app/application.cpp +++ b/samples/Basic_Servo/app/application.cpp @@ -117,7 +117,7 @@ void init() Serial.setTxBufferSize(1024); Serial.println("Init Basic Servo Sample"); - System.setCpuFrequency(eCF_80MHz); + System.setCpuFrequency(CpuCycleClockNormal::cpuFrequency()); #ifdef ARCH_HOST setDigitalHooks(nullptr); diff --git a/samples/Basic_SmartConfig/app/application.cpp b/samples/Basic_SmartConfig/app/application.cpp index 0e6697d369..62a6057986 100644 --- a/samples/Basic_SmartConfig/app/application.cpp +++ b/samples/Basic_SmartConfig/app/application.cpp @@ -27,11 +27,18 @@ bool smartConfigCallback(SmartConfigEvent event, const SmartConfigEventInfo& inf return false; } +void gotIP(IpAddress ip, IpAddress netmask, IpAddress gateway) +{ + Serial.print("Connected: "); + Serial.println(ip); +} + void init() { Serial.begin(SERIAL_BAUD_RATE); // 115200 by default Serial.systemDebugOutput(true); // Debug output to serial + WifiEvents.onStationGotIP(gotIP); WifiAccessPoint.enable(false); WifiStation.enable(true); // automatic (acts as the sample callback above) diff --git a/samples/Basic_SmartConfig/component.mk b/samples/Basic_SmartConfig/component.mk index 7d1cc32f5b..5e3a891d2d 100644 --- a/samples/Basic_SmartConfig/component.mk +++ b/samples/Basic_SmartConfig/component.mk @@ -1,2 +1,2 @@ -COMPONENT_SOC := esp8266 +COMPONENT_SOC := esp* ENABLE_SMART_CONFIG = 1 diff --git a/samples/Basic_Ssl/app/application.cpp b/samples/Basic_Ssl/app/application.cpp index c91d7fec68..90c9174828 100644 --- a/samples/Basic_Ssl/app/application.cpp +++ b/samples/Basic_Ssl/app/application.cpp @@ -1,6 +1,5 @@ #include #include -#include #ifdef ENABLE_MALLOC_COUNT #include diff --git a/samples/Basic_Ssl/component.mk b/samples/Basic_Ssl/component.mk index f37a7e4a1a..b994d8280f 100644 --- a/samples/Basic_Ssl/component.mk +++ b/samples/Basic_Ssl/component.mk @@ -1,5 +1,3 @@ -COMPONENT_SOC := esp* host - # ifeq ($(ENABLE_MALLOC_COUNT),1) COMPONENT_DEPENDS += malloc_count diff --git a/samples/Basic_Storage/app/application.cpp b/samples/Basic_Storage/app/application.cpp index 37ed842b1a..a1ba039d47 100644 --- a/samples/Basic_Storage/app/application.cpp +++ b/samples/Basic_Storage/app/application.cpp @@ -1,28 +1,10 @@ #include #include #include -#include +#include IMPORT_FSTR(FS_app, PROJECT_DIR "/app/application.cpp") -void listDevices() -{ - Serial.println(); - Serial.println(_F("Registered storage devices:")); - for(auto& dev : Storage::getDevices()) { - Serial.print(" name = '"); - Serial.print(dev.getName()); - Serial.print(_F("', type = ")); - Serial.print(toString(dev.getType())); - Serial.print(_F(", size = 0x")); - Serial.print(dev.getSize(), HEX); - Serial.print(_F(", ID = 0x")); - Serial.print(dev.getId(), HEX); - Serial.println(); - } - Serial.println(); -} - void listSpiffsPartitions() { Serial.println(_F("** Enumerate registered SPIFFS partitions")); @@ -83,7 +65,7 @@ void init() Serial.begin(SERIAL_BAUD_RATE); Serial.systemDebugOutput(true); - listDevices(); + Storage::Debug::listDevices(Serial); listSpiffsPartitions(); diff --git a/samples/Basic_Tasks/app/application.cpp b/samples/Basic_Tasks/app/application.cpp index 4fc5b8396a..a049457c6b 100644 --- a/samples/Basic_Tasks/app/application.cpp +++ b/samples/Basic_Tasks/app/application.cpp @@ -111,7 +111,7 @@ void init() Serial.begin(SERIAL_BAUD_RATE); Serial.systemDebugOutput(true); - // System.setCpuFrequency(eCF_160MHz); + // System.setCpuFrequency(CpuCycleClockFast::cpuFrequency()); Serial.print(_F("Available heap: ")); Serial.println(system_get_free_heap_size()); diff --git a/samples/Basic_WebSkeletonApp/app/application.cpp b/samples/Basic_WebSkeletonApp/app/application.cpp index 72112247aa..dcdbc84d42 100644 --- a/samples/Basic_WebSkeletonApp/app/application.cpp +++ b/samples/Basic_WebSkeletonApp/app/application.cpp @@ -42,8 +42,8 @@ void init() spiffs_mount(); // Mount file system, in order to work with files #endif - //SET higher CPU freq & disable wifi sleep - // system_update_cpu_freq(SYS_CPU_160MHZ); + // Set higher CPU freq & disable wifi sleep + // System.setCpuFrequency(CpuCycleClockFast::cpuFrequency()); wifi_set_sleep_type(NONE_SLEEP_T); activeConfig = loadConfig(); diff --git a/samples/Basic_WebSkeletonApp/component.mk b/samples/Basic_WebSkeletonApp/component.mk index 248c71219b..1fd7647f2f 100644 --- a/samples/Basic_WebSkeletonApp/component.mk +++ b/samples/Basic_WebSkeletonApp/component.mk @@ -1,6 +1,6 @@ COMPONENT_SOC := esp* ARDUINO_LIBRARIES := ArduinoJson6 -HWCONFIG := spiffs +HWCONFIG := spiffs-2m # Use to store files in a FlashString map object instead of SPIFFS CONFIG_VARS += ENABLE_FLASHSTRING_MAP diff --git a/samples/Basic_WebSkeletonApp_LTS/app/application.cpp b/samples/Basic_WebSkeletonApp_LTS/app/application.cpp index 7c7d00e2b8..2d3d341db2 100644 --- a/samples/Basic_WebSkeletonApp_LTS/app/application.cpp +++ b/samples/Basic_WebSkeletonApp_LTS/app/application.cpp @@ -14,8 +14,8 @@ void init() Serial.systemDebugOutput(false); Serial.commandProcessing(false); - //SET higher CPU freq & disable wifi sleep - system_update_cpu_freq(SYS_CPU_160MHZ); + // Set higher CPU freq & disable wifi sleep + System.setCpuFrequency(CpuCycleClockFast::cpuFrequency()); wifi_set_sleep_type(NONE_SLEEP_T); ActiveConfig = loadConfig(); diff --git a/samples/Basic_WiFi/component.mk b/samples/Basic_WiFi/component.mk deleted file mode 100644 index 996e1b20f1..0000000000 --- a/samples/Basic_WiFi/component.mk +++ /dev/null @@ -1 +0,0 @@ -COMPONENT_SOC := esp* host diff --git a/samples/CanBus/component.mk b/samples/CanBus/component.mk index 469fa2ae38..668373c3fc 100644 --- a/samples/CanBus/component.mk +++ b/samples/CanBus/component.mk @@ -1,2 +1 @@ -COMPONENT_SOC := esp* ARDUINO_LIBRARIES := MCP_CAN_lib diff --git a/samples/CommandProcessing_Debug/component.mk b/samples/CommandProcessing_Debug/component.mk index 8090a5763c..372d718852 100644 --- a/samples/CommandProcessing_Debug/component.mk +++ b/samples/CommandProcessing_Debug/component.mk @@ -1,2 +1 @@ -COMPONENT_SOC := esp* host -HWCONFIG := spiffs +HWCONFIG := spiffs-2m diff --git a/samples/DS3232RTC_NTP_Setter/component.mk b/samples/DS3232RTC_NTP_Setter/component.mk index e9017a1d47..9f593e41f9 100644 --- a/samples/DS3232RTC_NTP_Setter/component.mk +++ b/samples/DS3232RTC_NTP_Setter/component.mk @@ -1,2 +1 @@ -COMPONENT_SOC := esp* host ARDUINO_LIBRARIES := DS3232RTC diff --git a/samples/DnsCaptivePortal/component.mk b/samples/DnsCaptivePortal/component.mk deleted file mode 100644 index 996e1b20f1..0000000000 --- a/samples/DnsCaptivePortal/component.mk +++ /dev/null @@ -1 +0,0 @@ -COMPONENT_SOC := esp* host diff --git a/samples/Echo_Ssl/component.mk b/samples/Echo_Ssl/component.mk index b304dbdbe3..ae82bad52a 100644 --- a/samples/Echo_Ssl/component.mk +++ b/samples/Echo_Ssl/component.mk @@ -1,2 +1 @@ -COMPONENT_SOC := esp* host ENABLE_SSL = 1 diff --git a/samples/FtpServer_Files/component.mk b/samples/FtpServer_Files/component.mk index 3328bd6994..a7f4382ef0 100644 --- a/samples/FtpServer_Files/component.mk +++ b/samples/FtpServer_Files/component.mk @@ -1,5 +1,3 @@ -COMPONENT_SOC := esp* host - ifeq ($(SMING_ARCH),Esp32) HWCONFIG := ftpserver-esp32 else diff --git a/samples/HttpClient/component.mk b/samples/HttpClient/component.mk index 7cf6292fc2..c5d62bde55 100644 --- a/samples/HttpClient/component.mk +++ b/samples/HttpClient/component.mk @@ -1,5 +1,4 @@ -COMPONENT_SOC := esp* host -HWCONFIG = spiffs +HWCONFIG = spiffs-2m ## Prefer BearSSL as it can handle more gracefully big SSL packets. ENABLE_SSL ?= Bearssl diff --git a/samples/HttpClient_Instapush/component.mk b/samples/HttpClient_Instapush/component.mk index 18dde4ba83..6fad8b7821 100644 --- a/samples/HttpClient_Instapush/component.mk +++ b/samples/HttpClient_Instapush/component.mk @@ -1,2 +1 @@ -COMPONENT_SOC := esp* host ARDUINO_LIBRARIES := ArduinoJson6 diff --git a/samples/HttpClient_ThingSpeak/component.mk b/samples/HttpClient_ThingSpeak/component.mk deleted file mode 100644 index 996e1b20f1..0000000000 --- a/samples/HttpClient_ThingSpeak/component.mk +++ /dev/null @@ -1 +0,0 @@ -COMPONENT_SOC := esp* host diff --git a/samples/HttpServer_AJAX/app/application.cpp b/samples/HttpServer_AJAX/app/application.cpp index 732a00d2d2..afdf4866c4 100644 --- a/samples/HttpServer_AJAX/app/application.cpp +++ b/samples/HttpServer_AJAX/app/application.cpp @@ -60,7 +60,7 @@ void onAjaxInput(HttpRequest& request, HttpResponse& response) void onAjaxFrequency(HttpRequest& request, HttpResponse& response) { int freq = request.getQueryParameter("value").toInt(); - System.setCpuFrequency((CpuFrequency)freq); + System.setCpuFrequency(CpuFrequency(freq)); JsonObjectStream* stream = new JsonObjectStream(); JsonObject json = stream->getRoot(); diff --git a/samples/HttpServer_AJAX/component.mk b/samples/HttpServer_AJAX/component.mk index 48a65977fd..54bf56dc7b 100644 --- a/samples/HttpServer_AJAX/component.mk +++ b/samples/HttpServer_AJAX/component.mk @@ -1,4 +1,3 @@ -COMPONENT_SOC := esp* host -HWCONFIG := spiffs +HWCONFIG := spiffs-2m SPIFF_FILES = web/build ARDUINO_LIBRARIES := ArduinoJson6 diff --git a/samples/HttpServer_Bootstrap/app/application.cpp b/samples/HttpServer_Bootstrap/app/application.cpp index 0d21f0beed..a5a520e760 100644 --- a/samples/HttpServer_Bootstrap/app/application.cpp +++ b/samples/HttpServer_Bootstrap/app/application.cpp @@ -103,8 +103,8 @@ void init() // Run our method when station was connected to AP WifiEvents.onStationGotIP(gotIP); - //Change CPU freq. to 160MHZ - System.setCpuFrequency(eCF_160MHz); + // Max. out CPU frequency + System.setCpuFrequency(CpuCycleClockFast::cpuFrequency()); Serial.print("New CPU frequency is:"); - Serial.println((int)System.getCpuFrequency()); + Serial.println(int(System.getCpuFrequency())); } diff --git a/samples/HttpServer_Bootstrap/component.mk b/samples/HttpServer_Bootstrap/component.mk index a962a87528..9204b27acd 100644 --- a/samples/HttpServer_Bootstrap/component.mk +++ b/samples/HttpServer_Bootstrap/component.mk @@ -1,3 +1,2 @@ -COMPONENT_SOC := esp* host -HWCONFIG := spiffs +HWCONFIG := spiffs-2m SPIFF_FILES := diff --git a/samples/HttpServer_ConfigNetwork/component.mk b/samples/HttpServer_ConfigNetwork/component.mk index 330da01820..520c21f8c0 100644 --- a/samples/HttpServer_ConfigNetwork/component.mk +++ b/samples/HttpServer_ConfigNetwork/component.mk @@ -1,5 +1,4 @@ -COMPONENT_SOC := esp* host -HWCONFIG := spiffs +HWCONFIG := spiffs-2m SPIFF_FILES = web/build ARDUINO_LIBRARIES := ArduinoJson6 diff --git a/samples/HttpServer_FirmwareUpload/component.mk b/samples/HttpServer_FirmwareUpload/component.mk index 1ade710396..5bba481389 100644 --- a/samples/HttpServer_FirmwareUpload/component.mk +++ b/samples/HttpServer_FirmwareUpload/component.mk @@ -1,4 +1,3 @@ -COMPONENT_SOC := esp* host HWCONFIG := spiffs SPIFF_FILES = web/ ARDUINO_LIBRARIES := MultipartParser OtaUpgrade diff --git a/samples/HttpServer_Plugins/component.mk b/samples/HttpServer_Plugins/component.mk deleted file mode 100644 index 2e97043e61..0000000000 --- a/samples/HttpServer_Plugins/component.mk +++ /dev/null @@ -1,2 +0,0 @@ -COMPONENT_SOC := esp* host -HWCONFIG := standard diff --git a/samples/HttpServer_WebSockets/component.mk b/samples/HttpServer_WebSockets/component.mk index 8090a5763c..372d718852 100644 --- a/samples/HttpServer_WebSockets/component.mk +++ b/samples/HttpServer_WebSockets/component.mk @@ -1,2 +1 @@ -COMPONENT_SOC := esp* host -HWCONFIG := spiffs +HWCONFIG := spiffs-2m diff --git a/samples/LED_YeelightBulb/component.mk b/samples/LED_YeelightBulb/component.mk index bcb0cc54fe..68b70f2b6b 100644 --- a/samples/LED_YeelightBulb/component.mk +++ b/samples/LED_YeelightBulb/component.mk @@ -1,2 +1 @@ -COMPONENT_SOC := esp* ARDUINO_LIBRARIES := Yeelight diff --git a/samples/MeteoControl/component.mk b/samples/MeteoControl/component.mk index ce01f3d394..045387d781 100644 --- a/samples/MeteoControl/component.mk +++ b/samples/MeteoControl/component.mk @@ -1,4 +1,3 @@ -COMPONENT_SOC := esp* host ARDUINO_LIBRARIES := LiquidCrystal DHTesp ArduinoJson6 -HWCONFIG := spiffs +HWCONFIG := spiffs-2m SPIFF_FILES = web diff --git a/samples/MeteoControl_mqtt/component.mk b/samples/MeteoControl_mqtt/component.mk index 3c83b86cfe..5b00021804 100644 --- a/samples/MeteoControl_mqtt/component.mk +++ b/samples/MeteoControl_mqtt/component.mk @@ -1,2 +1 @@ -COMPONENT_SOC := esp* host ARDUINO_LIBRARIES := BMP180 SI7021 diff --git a/samples/MqttClient_Hello/component.mk b/samples/MqttClient_Hello/component.mk index cb1ff93301..1df6dd6e74 100644 --- a/samples/MqttClient_Hello/component.mk +++ b/samples/MqttClient_Hello/component.mk @@ -1,6 +1,3 @@ -COMPONENT_SOC := esp* host -HWCONFIG := standard-4m - ifdef MQTT_URL USER_CFLAGS += -DMQTT_URL=\"$(MQTT_URL)\" endif diff --git a/samples/Network_Ping/Makefile b/samples/Network_Ping/Makefile new file mode 100644 index 0000000000..ff51b6c3a7 --- /dev/null +++ b/samples/Network_Ping/Makefile @@ -0,0 +1,9 @@ +##################################################################### +#### Please don't change this file. Use component.mk instead #### +##################################################################### + +ifndef SMING_HOME +$(error SMING_HOME is not set: please configure it as an environment variable) +endif + +include $(SMING_HOME)/project.mk diff --git a/samples/Network_Ping/README.rst b/samples/Network_Ping/README.rst new file mode 100644 index 0000000000..db2f004dd8 --- /dev/null +++ b/samples/Network_Ping/README.rst @@ -0,0 +1,4 @@ +Network Ping +============ + +Sample demonstrating the usage of a network ping to check for connectivity issues. diff --git a/samples/Network_Ping/app/application.cpp b/samples/Network_Ping/app/application.cpp new file mode 100644 index 0000000000..1d86662d11 --- /dev/null +++ b/samples/Network_Ping/app/application.cpp @@ -0,0 +1,98 @@ +#include +extern "C" { +#include +} + +// If you want, you can define WiFi settings globally in Eclipse Environment Variables +#ifndef WIFI_SSID +#define WIFI_SSID "PleaseEnterSSID" // Put your SSID and Password here +#define WIFI_PWD "PleaseEnterPass" +#endif + +namespace +{ +ping_option pingOptions; +uint8_t failedAttempts; +constexpr uint8_t PING_COUNT = 3; +constexpr uint8_t MAX_FAILED_ATTEMTPS = 5; +constexpr uint8_t PING_INTERVAL_SECONDS = 10; +constexpr uint8_t RESTART_DELAY_SECONDS = 2; + +Timer procTimer; + +void ping(uint32 ip); + +void pingTask() +{ + ping(IpAddress("8.8.8.8")); // ping Google DNS servers +} + +void onSent(void* arg, void* pdata) +{ + ping_resp* response = reinterpret_cast(pdata); + + if(response == nullptr) { + debug_e("Invalid onSent call"); + return; + } + + Serial.printf("Ping sent. Total failed attempts: %d.\n", failedAttempts); + if(failedAttempts / response->total_count > MAX_FAILED_ATTEMTPS) { + debug_d("Scheduling system restart in %d seconds.", RESTART_DELAY_SECONDS); + // schedule restart + System.restart(RESTART_DELAY_SECONDS * 1000); + return; + } + + debug_d("Scheduling another ping in %d seconds", PING_INTERVAL_SECONDS); + procTimer.initializeMs(PING_INTERVAL_SECONDS * 1000, pingTask).startOnce(); +} + +void onReceived(void* arg, void* pdata) +{ + ping_resp* response = reinterpret_cast(pdata); + if(response == nullptr) { + debug_e("Invalid onReceived call"); + return; + } + + Serial.printf("Ping received. Sequence: %d, Success: %d, Elapsed time: %d", response->seqno, + response->ping_err == 0, response->total_time); + Serial.println(); + + if(response->ping_err) { + failedAttempts++; + } else { + failedAttempts = 0; + } +} + +void ping(uint32_t ip) +{ + debug_d("Ping IP: %s", IpAddress(ip).toString().c_str()); + pingOptions.ip = ip; + pingOptions.count = PING_COUNT; + pingOptions.recv_function = onReceived; + pingOptions.sent_function = onSent; + ping_start(&pingOptions); +} + +void connectOk(IpAddress ip, IpAddress mask, IpAddress gateway) +{ + debug_d("Scheduling initial ping in 1 second."); + procTimer.initializeMs(1000, pingTask).startOnce(); +} + +} // namespace + +void init() +{ + Serial.begin(SERIAL_BAUD_RATE); + Serial.systemDebugOutput(true); + + // Setup the WIFI connection + WifiStation.enable(true); + WifiStation.config(WIFI_SSID, WIFI_PWD); + + WifiEvents.onStationGotIP(connectOk); +} diff --git a/samples/Network_Ping/component.mk b/samples/Network_Ping/component.mk new file mode 100644 index 0000000000..16ad0adfd3 --- /dev/null +++ b/samples/Network_Ping/component.mk @@ -0,0 +1,2 @@ +COMPONENT_DEPENDS := Network +COMPONENT_SOC := esp8266 diff --git a/samples/PortExpander_MCP23S17/app/application.cpp b/samples/PortExpander_MCP23S17/app/application.cpp index 7de5674543..d607c9cd8e 100644 --- a/samples/PortExpander_MCP23S17/app/application.cpp +++ b/samples/PortExpander_MCP23S17/app/application.cpp @@ -18,8 +18,8 @@ void init() Serial.systemDebugOutput(false); // Allow debug output to serial Serial.println("<-= Sming start =->"); - //SET higher CPU freq & disable wifi sleep - system_update_cpu_freq(SYS_CPU_160MHZ); + // Set higher CPU freq & disable wifi sleep + System.setCpuFrequency(CpuCycleClockFast::cpuFrequency()); #ifndef DISABLE_WIFI wifi_set_sleep_type(NONE_SLEEP_T); diff --git a/samples/Radio_nRF24L01/app/application.cpp b/samples/Radio_nRF24L01/app/application.cpp index 8823fbf9dc..bfaa62ef8e 100644 --- a/samples/Radio_nRF24L01/app/application.cpp +++ b/samples/Radio_nRF24L01/app/application.cpp @@ -1,5 +1,4 @@ #include -#include #include #include @@ -16,12 +15,12 @@ * CSN GPIO5 (changeable) * GND GND */ -#ifdef ARCH_ESP8266 -constexpr uint8_t RF24_CE_PIN{4}; -constexpr uint8_t RF24_CSN_PIN{5}; -#else +#ifdef ARCH_ESP32 constexpr uint8_t RF24_CE_PIN{19}; constexpr uint8_t RF24_CSN_PIN{21}; +#else +constexpr uint8_t RF24_CE_PIN{4}; +constexpr uint8_t RF24_CSN_PIN{5}; #endif RF24 radio(RF24_CE_PIN, RF24_CSN_PIN); diff --git a/samples/Radio_nRF24L01/component.mk b/samples/Radio_nRF24L01/component.mk index 0d123ac87d..0ab96e0560 100644 --- a/samples/Radio_nRF24L01/component.mk +++ b/samples/Radio_nRF24L01/component.mk @@ -1,3 +1,2 @@ -COMPONENT_SOC := esp* ARDUINO_LIBRARIES := RF24 DISABLE_NETWORK := 1 diff --git a/samples/SDCard/app/application.cpp b/samples/SDCard/app/application.cpp index 7246e4fa0e..2cdebb9222 100644 --- a/samples/SDCard/app/application.cpp +++ b/samples/SDCard/app/application.cpp @@ -7,7 +7,6 @@ Descr: SDCard/FAT file usage and write benchmark. */ #include #include -#include /*(!) Warning on some hardware versions (ESP07, maybe ESP12) * pins GPIO4 and GPIO5 are swapped !*/ @@ -17,13 +16,11 @@ Descr: SDCard/FAT file usage and write benchmark. #define PIN_CARD_CK 14 /* Serial Clock */ // Chip selects independent of SPI controller in use -#ifdef ARCH_ESP8266 -// Cannot use GPIO15 as this affects boot mode -#define PIN_CARD_SS 5 /* Slave Select */ -#elif defined(ARCH_ESP32) +#ifdef ARCH_ESP32 #define PIN_CARD_SS 21 #else -static_assert(false, "Unsupported arch.") +// Esp8266 cannot use GPIO15 as this affects boot mode +#define PIN_CARD_SS 5 #endif /* Sets the max frequency of SPI (init is done at a lower speed than the main communication) */ diff --git a/samples/SDCard/component.mk b/samples/SDCard/component.mk index b5a80cdda0..dbb34d5811 100644 --- a/samples/SDCard/component.mk +++ b/samples/SDCard/component.mk @@ -1,3 +1,2 @@ -COMPONENT_SOC := esp* ARDUINO_LIBRARIES := SDCard DISABLE_NETWORK := 1 diff --git a/samples/ScreenLCD_5110/component.mk b/samples/ScreenLCD_5110/component.mk index ffe0e64f7e..67c6b5b9fb 100644 --- a/samples/ScreenLCD_5110/component.mk +++ b/samples/ScreenLCD_5110/component.mk @@ -1,3 +1,2 @@ -COMPONENT_SOC := esp8266 ARDUINO_LIBRARIES := Adafruit_PCD8544 DISABLE_NETWORK := 1 diff --git a/samples/ScreenOLED_SSD1306/app/application.cpp b/samples/ScreenOLED_SSD1306/app/application.cpp index c962f4838a..0322e588b6 100644 --- a/samples/ScreenOLED_SSD1306/app/application.cpp +++ b/samples/ScreenOLED_SSD1306/app/application.cpp @@ -1,5 +1,5 @@ #include -#include +#include /* * Hardware SPI mode: @@ -68,7 +68,7 @@ void init() // by default, we'll generate the high voltage from the 3.3v line internally! (neat!) // initialize with the I2C addr 0x3c (for the 128x64) // bool:reset set to TRUE or FALSE depending on your display - display.begin(SSD1306_SWITCHCAPVCC, SSD1306_I2C_ADDRESS, false); + display.begin(SSD1306_SWITCHCAPVCC, 0x3c, false); display.display(); DemoTimer.initializeMs(2000, Demo1).start(); } diff --git a/samples/ScreenTFT_ILI9340-ILI9341/app/application.cpp b/samples/ScreenTFT_ILI9340-ILI9341/app/application.cpp index 0f8478c408..699b51755e 100644 --- a/samples/ScreenTFT_ILI9340-ILI9341/app/application.cpp +++ b/samples/ScreenTFT_ILI9340-ILI9341/app/application.cpp @@ -8,16 +8,7 @@ #define WIFI_PWD "PleaseEnterPass" #endif -/* -Pinout: -MISO GPIO12 -MOSI GPIO13 -CLK GPIO14 -CS GPIO15 -DC GPIO5 -RST GPIO4 -*/ - +// See library for pinout Adafruit_ILI9341 tft; Timer guiTimer; @@ -37,7 +28,7 @@ int satir = 6; String lists[] = {"a", "b", "c", "d", "e", "f"}; -void basicBPM() +void basicBMP() { tft.fillScreen(ILI9341_BLACK); // Clear display tft.setRotation(tft.getRotation() + 1); // Inc rotation 90 degrees @@ -70,7 +61,7 @@ void basicGui() } p1 = 50; r++; - guiTimer.initializeMs(1000, basicBPM).start(false); + guiTimer.initializeMs<1000>(basicBMP).start(false); } void init() @@ -110,6 +101,6 @@ void init() tft.println("M.Bozkurt"); delay(2000); tft.fillScreen(0); - guiTimer.initializeMs(1000, basicGui).start(false); + guiTimer.initializeMs<1000>(basicGui).start(false); //runTest(); } diff --git a/samples/ScreenTFT_ILI9340-ILI9341/component.mk b/samples/ScreenTFT_ILI9340-ILI9341/component.mk index c707c73488..dd4e525197 100644 --- a/samples/ScreenTFT_ILI9340-ILI9341/component.mk +++ b/samples/ScreenTFT_ILI9340-ILI9341/component.mk @@ -1,4 +1,3 @@ -COMPONENT_SOC := esp* -HWCONFIG := spiffs +HWCONFIG := spiffs-2m ARDUINO_LIBRARIES := Adafruit_ILI9341 DISABLE_NETWORK := 1 diff --git a/samples/ScreenTFT_ST7735/component.mk b/samples/ScreenTFT_ST7735/component.mk index 9dc2b653a6..17c7646fff 100644 --- a/samples/ScreenTFT_ST7735/component.mk +++ b/samples/ScreenTFT_ST7735/component.mk @@ -1,4 +1,4 @@ COMPONENT_SOC := esp* -HWCONFIG := spiffs +HWCONFIG := spiffs-2m ARDUINO_LIBRARIES := Adafruit_ST7735 DISABLE_NETWORK := 1 diff --git a/samples/SmtpClient/component.mk b/samples/SmtpClient/component.mk index a2dcaeebda..7f43d35855 100644 --- a/samples/SmtpClient/component.mk +++ b/samples/SmtpClient/component.mk @@ -1,3 +1,2 @@ -COMPONENT_SOC := esp* host -HWCONFIG := spiffs +HWCONFIG := spiffs-2m ENABLE_SSL ?= 1 diff --git a/samples/SystemClock_NTP/component.mk b/samples/SystemClock_NTP/component.mk index e1c336e04d..2d668a76f1 100644 --- a/samples/SystemClock_NTP/component.mk +++ b/samples/SystemClock_NTP/component.mk @@ -1,4 +1,3 @@ -COMPONENT_SOC := esp* host ARDUINO_LIBRARIES = \ Timezone \ SolarCalculator diff --git a/samples/TcpClient_NarodMon/component.mk b/samples/TcpClient_NarodMon/component.mk deleted file mode 100644 index 996e1b20f1..0000000000 --- a/samples/TcpClient_NarodMon/component.mk +++ /dev/null @@ -1 +0,0 @@ -COMPONENT_SOC := esp* host diff --git a/samples/Telnet_Server/component.mk b/samples/Telnet_Server/component.mk deleted file mode 100644 index 996e1b20f1..0000000000 --- a/samples/Telnet_Server/component.mk +++ /dev/null @@ -1 +0,0 @@ -COMPONENT_SOC := esp* host diff --git a/samples/UdpServer_Echo/component.mk b/samples/UdpServer_Echo/component.mk deleted file mode 100644 index 996e1b20f1..0000000000 --- a/samples/UdpServer_Echo/component.mk +++ /dev/null @@ -1 +0,0 @@ -COMPONENT_SOC := esp* host diff --git a/samples/UdpServer_mDNS/app/application.cpp b/samples/UdpServer_mDNS/app/application.cpp index 141a8391b3..48b282604f 100644 --- a/samples/UdpServer_mDNS/app/application.cpp +++ b/samples/UdpServer_mDNS/app/application.cpp @@ -1,7 +1,6 @@ #include #include #include -#include // If you want, you can define WiFi settings globally in Eclipse Environment Variables #ifndef WIFI_SSID diff --git a/samples/UdpServer_mDNS/component.mk b/samples/UdpServer_mDNS/component.mk index 5d9e79ee5e..fb69aa5341 100644 --- a/samples/UdpServer_mDNS/component.mk +++ b/samples/UdpServer_mDNS/component.mk @@ -1,4 +1,3 @@ -COMPONENT_SOC := esp* host -HWCONFIG := spiffs +HWCONFIG := spiffs-2m SPIFF_FILES := COMPONENT_DEPENDS += MDNS diff --git a/samples/WebcamServer/component.mk b/samples/WebcamServer/component.mk index b42229fefe..927c3db9f6 100644 --- a/samples/WebcamServer/component.mk +++ b/samples/WebcamServer/component.mk @@ -1,4 +1,3 @@ -COMPONENT_SOC := esp* host ARDUINO_LIBRARIES := WebCam -HWCONFIG := spiffs +HWCONFIG := spiffs-2m SPIFF_FILES = web/build diff --git a/samples/Websocket_Client/component.mk b/samples/Websocket_Client/component.mk index 1ca12e2921..27468497da 100644 --- a/samples/Websocket_Client/component.mk +++ b/samples/Websocket_Client/component.mk @@ -1,5 +1,2 @@ -COMPONENT_SOC := esp* host -HWCONFIG := standard-4m - # Uncomment the option below if you want SSL support #ENABLE_SSL=1 diff --git a/tests/HostTests/app/application.cpp b/tests/HostTests/app/application.cpp index e1668b2b3c..c64e750aff 100644 --- a/tests/HostTests/app/application.cpp +++ b/tests/HostTests/app/application.cpp @@ -54,6 +54,7 @@ void init() debug_e("WELCOME to SMING! Host Tests application running."); spiffs_mount(); + fileSystemFormat(); registerTests(); diff --git a/tests/HostTests/component.mk b/tests/HostTests/component.mk index 741d7ea035..3368f1f11e 100644 --- a/tests/HostTests/component.mk +++ b/tests/HostTests/component.mk @@ -1,6 +1,8 @@ ifeq ($(SMING_ARCH),Rp2040) HWCONFIG = host-tests-1m DISABLE_NETWORK := 1 +else ifeq ($(SMING_ARCH),Esp32) +HWCONFIG = host-tests-esp32 else HWCONFIG = host-tests endif diff --git a/tests/HostTests/host-tests-esp32.hw b/tests/HostTests/host-tests-esp32.hw new file mode 100644 index 0000000000..d8b9c308fa --- /dev/null +++ b/tests/HostTests/host-tests-esp32.hw @@ -0,0 +1,9 @@ +{ + "name": "Host Tests for Esp32", + "base_config": "host-tests", + "partitions": { + "factory": { + "size": "1M" + } + } +} diff --git a/tests/HostTests/modules/CStringArray.cpp b/tests/HostTests/modules/CStringArray.cpp index f07450df0d..efb7b5e3e1 100644 --- a/tests/HostTests/modules/CStringArray.cpp +++ b/tests/HostTests/modules/CStringArray.cpp @@ -180,6 +180,39 @@ class CStringArrayTest : public TestGroup std::swap(it1, it2); } } + + TEST_CASE("push front") + { + CStringArray csa; + REQUIRE(csa.front() == nullptr); + REQUIRE(csa.pushFront("abc")); + REQUIRE_EQ(String(csa.front()), "abc"); + REQUIRE(csa.pushFront("def")); + REQUIRE_EQ(String(csa.front()), "def"); + REQUIRE_EQ(csa.count(), 2); + REQUIRE_EQ(csa.popFront(), "def"); + REQUIRE_EQ(csa.count(), 1); + REQUIRE_EQ(csa.popFront(), "abc"); + REQUIRE_EQ(csa.count(), 0); + REQUIRE(!csa.popFront()); + } + + TEST_CASE("push back") + { + CStringArray csa; + REQUIRE(csa.back() == nullptr); + REQUIRE(csa.pushBack("abc")); + REQUIRE(csa.pushBack("def")); + REQUIRE_EQ(csa.count(), 2); + REQUIRE_EQ(String(csa.back()), "def"); + REQUIRE_EQ(csa.popBack(), "def"); + REQUIRE_EQ(String(csa.back()), "abc"); + REQUIRE_EQ(csa.count(), 1); + REQUIRE_EQ(csa.popBack(), "abc"); + REQUIRE_EQ(csa.count(), 0); + REQUIRE(csa.back() == nullptr); + REQUIRE(!csa.popBack()); + } } }; diff --git a/tests/HostTests/modules/Clocks.cpp b/tests/HostTests/modules/Clocks.cpp index 331fe55415..41dc8a5f3f 100644 --- a/tests/HostTests/modules/Clocks.cpp +++ b/tests/HostTests/modules/Clocks.cpp @@ -6,6 +6,7 @@ #include #include +#include template class ClockTestTemplate : public TestGroup { @@ -37,8 +38,8 @@ template class ClockTestTemplate : public TestG TEST_CASE("vs. system time") { constexpr uint32_t duration{2000000}; - auto startTicks = Clock::ticks(); auto startTime = system_get_time(); + auto startTicks = Clock::ticks(); uint32_t time; while((time = system_get_time()) < startTime + duration) { // @@ -48,7 +49,12 @@ template class ClockTestTemplate : public TestG debug_w("System time elapsed: %u", time - startTime); debug_w("%s ticks: %u", Clock::typeName(), endTicks - startTicks); debug_w("Ratio: x %f", float(endTicks - startTicks) / (time - startTime)); - debug_w("Apparent time: %u", uint32_t(Micros::ticksToTime(endTicks - startTicks))); + uint32_t us = Micros::ticksToTime(endTicks - startTicks); + debug_w("Apparent time: %u", us); + // Up-timers may report 0 if inactive + if(endTicks != 0 || startTicks != 0) { + REQUIRE(abs(int(us - duration)) < 500); // Allow some latitude + } } } @@ -238,6 +244,20 @@ template class ClockTestTemplate : public TestG CpuCycleTimes calcCycles; }; +template +class Timer1ClockTestTemplate : public ClockTestTemplate, uint32_t> +{ +public: + void execute() override + { + // Configure the hardware to match selected clock divider + Timer1Api timer; + timer.arm(false); + + ClockTestTemplate, uint32_t>::execute(); + } +}; + template class CpuClockTestTemplate : public ClockTestTemplate { public: @@ -246,9 +266,11 @@ template class CpuClockTestTemplate : public Cl void execute() override { uint32_t curFreq = system_get_cpu_freq(); - System.setCpuFrequency(Clock::cpuFrequency()); + if(!System.setCpuFrequency(Clock::cpuFrequency())) { + debug_e("Failed to set CPU frequency, skipping test"); + return; + } - // delay(100); debug_i("CPU freq: %u -> %u MHz", curFreq, system_get_cpu_freq()); ClockTestTemplate::execute(); System.setCpuFrequency(CpuCycleClockNormal::cpuFrequency()); @@ -472,8 +494,8 @@ void REGISTER_TEST(Clocks) registerGroup(); - registerGroup, uint32_t>>(); - registerGroup, uint32_t>>(); + registerGroup>(); + registerGroup>(); registerGroup>(); diff --git a/tests/HostTests/modules/Network/Arch/Host/Hosted.cpp b/tests/HostTests/modules/Network/Arch/Host/Hosted.cpp index c77f9b54cb..fa01c930e9 100644 --- a/tests/HostTests/modules/Network/Arch/Host/Hosted.cpp +++ b/tests/HostTests/modules/Network/Arch/Host/Hosted.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -14,6 +15,31 @@ static uint32_t plusCommand(uint8_t a, uint16_t b) return a + b; }; +class TheWire +{ +public: + void begin() + { + called++; + } + + uint8_t begin(uint8_t a, uint8_t b) + { + called += (a + b); + return called; + } + + uint8_t getCalled() + { + return called; + } + +private: + uint8_t called{0}; +}; + +TheWire theWire; + class HostedTest : public TestGroup { public: @@ -74,16 +100,18 @@ class HostedTest : public TestGroup // clang-format off interface(stream, /* - * Below we are exporting the following remote commands: - * - pinMode - * - digitalRead - * - digitalWrite * You can add more commands here. For every command you should specify command and text description in the format below. * For more information read the SimpleRPC interface API: https://simplerpc.readthedocs.io/en/latest/api/interface.html */ - pinMode, "pinMode: Sets mode of digital pin. @pin: Pin number, @mode: Mode type.", - digitalRead, "digitalRead: Read digital pin. @pin: Pin number. @return: Pin value.", - plusCommand, "plusCommand: Sum two numbers. @a: number one. @b: number two." + pinMode, "pinMode> Sets mode of digital pin. @pin: Pin number, @mode: Mode type.", + digitalRead, "digitalRead> Read digital pin. @pin: Pin number. @return: Pin value.", + plusCommand, "plusCommand> Sum two numbers. @a: number one. @b: number two.", + /* class methods */ + // uint8_t TwoWire::begin(uint8_t sda, uint8_t scl) + pack(&theWire, (uint8_t(TheWire::*)(uint8_t,uint8_t))&TheWire::begin), "TheWire::begin> Starts two-wire communication. @sda: Data pin. @scl: Clock pin.", + // void TheWire::begin() + pack(&theWire, (void(TheWire::*)())&TheWire::begin), "TheWire::begin> Starts two-wire communication.", + pack(&theWire, (uint8_t(TheWire::*)())&TheWire::getCalled), "TheWire::getCalled> Gets times called. @return: Result." ); // clang-format on @@ -95,12 +123,13 @@ class HostedTest : public TestGroup client.connect(WifiStation.getIP(), 4031); Hosted::Transport::TcpClientStream stream(client, 1024); - Hosted::Client hostedClient(stream); + Hosted::Client hostedClient(stream, '>'); TEST_CASE("Client::getRemoteCommands()") { REQUIRE(hostedClient.getRemoteCommands() == true); REQUIRE(hostedClient.getFunctionId("plusCommand") == 2); + REQUIRE(hostedClient.getFunctionId("uint8_t TheWire::begin(uint8_t, uint8_t)") == 3); } TEST_CASE("Client::send and wait()") @@ -112,6 +141,15 @@ class HostedTest : public TestGroup debug_i("PlusCommand Roundtrip Time: %s", timer.elapsedTime().toString().c_str()); } + + TEST_CASE("Client::send and check class method") + { + REQUIRE(hostedClient.send("uint8_t TheWire::begin(uint8_t, uint8_t)", uint8_t(3), uint8_t(3)) == true); + REQUIRE(hostedClient.wait() == 6); + + REQUIRE(hostedClient.send("uint8_t TheWire::getCalled()") == true); + REQUIRE(hostedClient.wait() == 6); + } } private: diff --git a/tests/HostTests/modules/Storage.cpp b/tests/HostTests/modules/Storage.cpp index 238af5076b..06cd99c4cd 100644 --- a/tests/HostTests/modules/Storage.cpp +++ b/tests/HostTests/modules/Storage.cpp @@ -1,5 +1,6 @@ #include #include +#include class TestDevice : public Storage::Device { @@ -64,23 +65,8 @@ class PartitionTest : public TestGroup { for(auto it = Storage::findPartition(); it; ++it) { auto part = *it; - - Serial.println(); - Serial.print(_F("Device '")); - Serial.print(part.getDeviceName()); - Serial.print(_F("', partition '")); - Serial.print(part.name()); - Serial.print(_F("', type ")); - Serial.print(int(part.type())); - Serial.print('/'); - Serial.print(int(part.subType())); - Serial.print(" ("); - Serial.print(part.longTypeString()); - Serial.print(_F("), address 0x")); - Serial.print(part.address(), HEX); - Serial.print(_F(", size 0x")); - Serial.print(part.size(), HEX); - Serial.println(); + Serial.print("* "); + Storage::Debug::printPartition(Serial, part); testRead(part, 0xE0, 0x20, true); testRead(part, 10, 20, true); diff --git a/tests/HostTests/modules/Stream.cpp b/tests/HostTests/modules/Stream.cpp index 65782a1030..0f52776c96 100644 --- a/tests/HostTests/modules/Stream.cpp +++ b/tests/HostTests/modules/Stream.cpp @@ -83,6 +83,13 @@ class StreamTest : public TestGroup REQUIRE(strlen(s.c_str()) == s.length()); } + TEST_CASE("readString (PR #2468)") + { + FSTR::Stream stream(FS_abstract); + String s = stream.readString(0x10000); + REQUIRE(s == FS_abstract); + } + #ifndef DISABLE_NETWORK TEST_CASE("ChunkedStream / StreamTransformer") diff --git a/tests/HostTests/modules/Timers.cpp b/tests/HostTests/modules/Timers.cpp index d25220ed45..6f9c4e943b 100644 --- a/tests/HostTests/modules/Timers.cpp +++ b/tests/HostTests/modules/Timers.cpp @@ -82,7 +82,10 @@ class CallbackTimerTest : public TestGroup } auto mem = MallocCount::getCurrent(); - String s = statusTimer; + String s; + s += system_get_time(); + s += " "; + s += statusTimer; s += " fired, timercount = "; s += activeTimerCount; s += ", mem = "; diff --git a/tests/HostTests/modules/Wiring.cpp b/tests/HostTests/modules/Wiring.cpp index 6d7904698c..c66e3cfa50 100644 --- a/tests/HostTests/modules/Wiring.cpp +++ b/tests/HostTests/modules/Wiring.cpp @@ -2,6 +2,7 @@ #include #include +#include class WiringTest : public TestGroup { @@ -14,7 +15,7 @@ class WiringTest : public TestGroup { Serial.print(e.key()); Serial.print(" = "); - Serial.println(e.value()); + Serial.println(*e); } template void print(const Map& map) const @@ -37,9 +38,16 @@ class WiringTest : public TestGroup print(map); for(auto e : map) { - e.value() += ": gobbed"; + String s = *e; + e->length(); } + for(auto e : map) { + *e += ": gobbed"; + } + + REQUIRE_EQ(map["b"], "value(b): gobbed"); + print(map); } @@ -63,6 +71,21 @@ class WiringTest : public TestGroup Serial.println(e); } } + + TEST_CASE("MacAddress") + { + const uint8_t refOctets[]{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc}; + const MacAddress ref{refOctets}; + REQUIRE(memcmp(&ref[0], refOctets, 6) == 0); + REQUIRE(MacAddress("123456789abc") == ref); + REQUIRE(MacAddress("12:34:56:78:9A:bc") == ref); + REQUIRE(MacAddress("12.34:56:78:9a:Bc") == ref); + REQUIRE(MacAddress("12 34 56 78 9a bC") == ref); + REQUIRE(MacAddress("ffffffffffff") == MacAddress({0xff, 0xff, 0xff, 0xff, 0xff, 0xff})); + REQUIRE(!MacAddress("123456789abc.")); + REQUIRE(!MacAddress("")); + REQUIRE(!MacAddress("fffffffgfffff")); + } } };