Compare commits
@@ -20,7 +20,7 @@ jobs:
|
||||
- name: Run codespell
|
||||
uses: codespell-project/actions-codespell@master
|
||||
with:
|
||||
skip: ./ArduinoCore-API,./libraries/ESP8266SdFat,./libraries/Adafruit_TinyUSB_Arduino,./libraries/LittleFS/lib,./tools/pyserial,./pico-sdk,./.github,./docs/i2s.rst,./cores/rp2040/api,./libraries/FreeRTOS,./tools/libbearssl/bearssl,./include,./libraries/WiFi/examples/BearSSL_Server,./ota/uzlib
|
||||
skip: ./ArduinoCore-API,./libraries/ESP8266SdFat,./libraries/Adafruit_TinyUSB_Arduino,./libraries/LittleFS/lib,./tools/pyserial,./pico-sdk,./.github,./docs/i2s.rst,./cores/rp2040/api,./libraries/FreeRTOS,./tools/libbearssl/bearssl,./include,./libraries/WiFi/examples/BearSSL_Server,./ota/uzlib,./libraries/http-parser/lib,./libraries/WebServer/examples/HelloServerBearSSL/HelloServerBearSSL.ino,./libraries/HTTPUpdateServer/examples/SecureBearSSLUpdater/SecureBearSSLUpdater.ino
|
||||
ignore_words_list: ser,dout
|
||||
|
||||
# Consistent style
|
||||
|
||||
+2
-1
@@ -3,4 +3,5 @@ system
|
||||
tools/dist
|
||||
docs/_build
|
||||
ota/build
|
||||
tools/libpico/build
|
||||
tools/libpico/build
|
||||
platform.local.txt
|
||||
|
||||
@@ -34,3 +34,6 @@
|
||||
[submodule "ota/uzlib"]
|
||||
path = ota/uzlib
|
||||
url = https://github.com/pfalcon/uzlib.git
|
||||
[submodule "libraries/http_parser/lib/http-parser"]
|
||||
path = libraries/http-parser/lib/http-parser
|
||||
url = https://github.com/nodejs/http-parser.git
|
||||
|
||||
+1
-1
Submodule ArduinoCore-API updated: ff01bb620e...d955d75747
@@ -25,6 +25,7 @@ See https://arduino-pico.readthedocs.io/en/latest/ along with the examples for m
|
||||
* DeRuiLab FlyBoard2040 Core
|
||||
* DFRobot Beetle RP2040
|
||||
* ElectronicCats Hunter Cat NFC
|
||||
* ExtremeElectronics RC2040
|
||||
* Invector Labs Challenger RP2040 WiFi
|
||||
* Invector Labs Challenger RP2040 WiFi/BLE
|
||||
* Invector Labs Challenger NB RP2040 WiFi
|
||||
@@ -147,6 +148,8 @@ The installed tools include a version of OpenOCD (in the pqt-openocd directory)
|
||||
* Adafruit TinyUSB Arduino (USB mouse, keyboard, flash drive, generic HID, CDC Serial, MIDI, WebUSB, others)
|
||||
* Generic Arduino USB Serial, Keyboard, and Mouse emulation
|
||||
* WiFi (Pico W)
|
||||
* HTTP client and server (WebServer)
|
||||
* SSL/TLS/HTTPS
|
||||
* Over-the-Air (OTA) upgrades
|
||||
* Filesystems (LittleFS and SD/SDFS)
|
||||
* Multicore support (setup1() and loop1())
|
||||
@@ -170,6 +173,7 @@ Here are some links to coverage and additional tutorials for using `arduino-pico
|
||||
* Pre-release Adafruit QT Py RP2040 - https://www.youtube.com/watch?v=sfC1msqXX0I
|
||||
* Adafruit Feather RP2040 running LCD + TMP117 - https://www.youtube.com/watch?v=fKDeqZiIwHg
|
||||
* Demonstration of Servos and I2C in Korean - https://cafe.naver.com/arduinoshield/1201
|
||||
* Home Assistant Pico W integration starter project using Arduino - https://github.com/daniloc/PicoW_HomeAssistant_Starter
|
||||
|
||||
# Contributing
|
||||
If you want to contribute or have bugfixes, drop me a note at <earlephilhower@yahoo.com> or open an issue/PR here.
|
||||
@@ -187,7 +191,10 @@ If you want to contribute or have bugfixes, drop me a note at <earlephilhower@ya
|
||||
* [lwIP](https://savannah.nongnu.org/projects/lwip/) is (c) the Swedish Institute of Computer Science and licenced under the BSD license.
|
||||
* [BearSSL](https://bearssl.org) library written by Thomas Pornin, is distributed under the [MIT License](https://bearssl.org/#legal-details).
|
||||
* [UZLib](https://github.com/pfalcon/uzlib) is copyright (c) 2003 Joergen Ibsen and distributed under the zlib license.
|
||||
* [LEAmDMS](https://github.com/LaborEtArs/ESP8266mDNS) is copyright multiple authors and distributed under the MIT license.
|
||||
* [LEAmDNS](https://github.com/LaborEtArs/ESP8266mDNS) is copyright multiple authors and distributed under the MIT license.
|
||||
* [http-parser](https://github.com/nodejs/http-parser) is copyright Joyent, Inc. and other Node contributors.
|
||||
* WebServer code modified from the [ESP32 WebServer](https://github.com/espressif/arduino-esp32/tree/master/libraries/WebServer) and is copyright (c) 2015 Ivan Grokhotkov and others
|
||||
|
||||
|
||||
-Earle F. Philhower, III
|
||||
earlephilhower@yahoo.com
|
||||
|
||||
+2457
-1
File diff suppressed because it is too large
Load Diff
@@ -90,6 +90,15 @@ extern bool __isFreeRTOS;
|
||||
#define HAVE_HWSERIAL1
|
||||
#define HAVE_HWSERIAL2
|
||||
|
||||
// PSTR/etc.
|
||||
#ifndef FPSTR
|
||||
#define FPSTR (const char *)
|
||||
#endif
|
||||
|
||||
#ifndef PGM_VOID_P
|
||||
#define PGM_VOID_P void *
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#ifdef USE_TINYUSB
|
||||
|
||||
@@ -24,26 +24,39 @@
|
||||
#pragma once
|
||||
|
||||
#include "pico/mutex.h"
|
||||
#include "_freertos.h"
|
||||
|
||||
class CoreMutex {
|
||||
public:
|
||||
CoreMutex(mutex_t *mutex) {
|
||||
uint32_t owner;
|
||||
CoreMutex(mutex_t *mutex, bool debugEnable = true) {
|
||||
_mutex = mutex;
|
||||
_acquired = false;
|
||||
if (!mutex_try_enter(_mutex, &owner)) {
|
||||
if (owner == get_core_num()) { // Deadlock!
|
||||
DEBUGCORE("CoreMutex - Deadlock detected!\n");
|
||||
return;
|
||||
if (__isFreeRTOS) {
|
||||
auto m = __get_freertos_mutex_for_ptr(mutex);
|
||||
__freertos_mutex_take(m);
|
||||
} else {
|
||||
uint32_t owner;
|
||||
if (!mutex_try_enter(_mutex, &owner)) {
|
||||
if (owner == get_core_num()) { // Deadlock!
|
||||
if (debugEnable) {
|
||||
DEBUGCORE("CoreMutex - Deadlock detected!\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
mutex_enter_blocking(_mutex);
|
||||
}
|
||||
mutex_enter_blocking(_mutex);
|
||||
}
|
||||
_acquired = true;
|
||||
}
|
||||
|
||||
~CoreMutex() {
|
||||
if (_acquired) {
|
||||
mutex_exit(_mutex);
|
||||
if (__isFreeRTOS) {
|
||||
auto m = __get_freertos_mutex_for_ptr(_mutex);
|
||||
__freertos_mutex_give(m);
|
||||
} else {
|
||||
mutex_exit(_mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -240,7 +240,7 @@ protected:
|
||||
}
|
||||
time_t (*_timeCallback)(void) = nullptr;
|
||||
static time_t _defaultTimeCB(void) {
|
||||
return time(NULL);
|
||||
return time(nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -129,10 +129,10 @@ struct TimeUnit {
|
||||
}
|
||||
};
|
||||
|
||||
using TimeMillis = TimeUnit< TimeSourceMillis, 1000 >;
|
||||
using TimeFastMillis = TimeUnit< TimeSourceCycles, 1000 >;
|
||||
using TimeFastMicros = TimeUnit< TimeSourceCycles, 1000000 >;
|
||||
using TimeFastNanos = TimeUnit< TimeSourceCycles, 1000000000 >;
|
||||
using TimeMillis = TimeUnit < TimeSourceMillis, 1'000 >;
|
||||
using TimeFastMillis = TimeUnit < TimeSourceCycles, 1'000 >;
|
||||
using TimeFastMicros = TimeUnit < TimeSourceCycles, 1'000'000 >;
|
||||
using TimeFastNanos = TimeUnit < TimeSourceCycles, 1'000'000'000 >;
|
||||
|
||||
} //TimePolicy
|
||||
|
||||
|
||||
@@ -32,20 +32,10 @@
|
||||
#include "ccount.pio.h"
|
||||
#include <malloc.h>
|
||||
|
||||
#include "_freertos.h"
|
||||
|
||||
extern "C" volatile bool __otherCoreIdled;
|
||||
|
||||
// Halt the FreeRTOS PendSV task switching magic
|
||||
extern "C" int __holdUpPendSV;
|
||||
|
||||
// FreeRTOS weak functions, to be overridden when we really are running FreeRTOS
|
||||
extern "C" {
|
||||
extern void vTaskSuspendAll() __attribute__((weak));
|
||||
extern int32_t xTaskResumeAll() __attribute__((weak));
|
||||
typedef struct tskTaskControlBlock * TaskHandle_t;
|
||||
extern void vTaskPreemptionDisable(TaskHandle_t p) __attribute__((weak));
|
||||
extern void vTaskPreemptionEnable(TaskHandle_t p) __attribute__((weak));
|
||||
}
|
||||
|
||||
class _MFIFO {
|
||||
public:
|
||||
_MFIFO() { /* noop */ };
|
||||
@@ -248,7 +238,7 @@ public:
|
||||
// Convert from microseconds to PIO clock cycles
|
||||
static int usToPIOCycles(int us) {
|
||||
// Parenthesis needed to guarantee order of operations to avoid 32bit overflow
|
||||
return (us * (clock_get_hz(clk_sys) / 1000000));
|
||||
return (us * (clock_get_hz(clk_sys) / 1'000'000));
|
||||
}
|
||||
|
||||
// Get current clock frequency
|
||||
@@ -324,6 +314,14 @@ public:
|
||||
reboot();
|
||||
}
|
||||
|
||||
void wdt_begin(uint32_t delay_ms) {
|
||||
watchdog_enable(delay_ms, 1);
|
||||
}
|
||||
|
||||
void wdt_reset() {
|
||||
watchdog_update();
|
||||
}
|
||||
|
||||
const char *getChipID() {
|
||||
static char id[PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1] = { 0 };
|
||||
if (!id[0]) {
|
||||
|
||||
@@ -71,8 +71,6 @@ static int __usb_task_irq;
|
||||
|
||||
#define EPNUM_HID 0x83
|
||||
|
||||
#define EPNUM_MIDI 0x01
|
||||
|
||||
|
||||
const uint8_t *tud_descriptor_device_cb(void) {
|
||||
static tusb_desc_device_t usbd_desc_device = {
|
||||
@@ -91,7 +89,7 @@ const uint8_t *tud_descriptor_device_cb(void) {
|
||||
.iSerialNumber = USBD_STR_SERIAL,
|
||||
.bNumConfigurations = 1
|
||||
};
|
||||
if (__USBInstallSerial && !__USBInstallKeyboard && !__USBInstallMouse && !__USBInstallJoystick && !__USBInstallMIDI) {
|
||||
if (__USBInstallSerial && !__USBInstallKeyboard && !__USBInstallMouse && !__USBInstallJoystick) {
|
||||
// Can use as-is, this is the default USB case
|
||||
return (const uint8_t *)&usbd_desc_device;
|
||||
}
|
||||
@@ -105,9 +103,6 @@ const uint8_t *tud_descriptor_device_cb(void) {
|
||||
if (__USBInstallJoystick) {
|
||||
usbd_desc_device.idProduct |= 0x0100;
|
||||
}
|
||||
if (__USBInstallMIDI) {
|
||||
usbd_desc_device.idProduct |= 0x2000;
|
||||
}
|
||||
// Set the device class to 0 to indicate multiple device classes
|
||||
usbd_desc_device.bDeviceClass = 0;
|
||||
usbd_desc_device.bDeviceSubClass = 0;
|
||||
@@ -228,7 +223,7 @@ void __SetupUSBDescriptor() {
|
||||
if (!usbd_desc_cfg) {
|
||||
bool hasHID = __USBInstallKeyboard || __USBInstallMouse || __USBInstallJoystick;
|
||||
|
||||
uint8_t interface_count = (__USBInstallSerial ? 2 : 0) + (hasHID ? 1 : 0) + (__USBInstallMIDI ? 2 : 0);
|
||||
uint8_t interface_count = (__USBInstallSerial ? 2 : 0) + (hasHID ? 1 : 0);
|
||||
|
||||
uint8_t cdc_desc[TUD_CDC_DESC_LEN] = {
|
||||
// Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval
|
||||
@@ -243,13 +238,7 @@ void __SetupUSBDescriptor() {
|
||||
TUD_HID_DESCRIPTOR(hid_itf, 0, HID_ITF_PROTOCOL_NONE, hid_report_len, EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 10)
|
||||
};
|
||||
|
||||
uint8_t midi_itf = hid_itf + (hasHID ? 1 : 0);
|
||||
uint8_t midi_desc[TUD_MIDI_DESC_LEN] = {
|
||||
// Interface number, string index, EP Out & EP In address, EP size
|
||||
TUD_MIDI_DESCRIPTOR(midi_itf, 0, EPNUM_MIDI, 0x80 | EPNUM_MIDI, 64)
|
||||
};
|
||||
|
||||
int usbd_desc_len = TUD_CONFIG_DESC_LEN + (__USBInstallSerial ? sizeof(cdc_desc) : 0) + (hasHID ? sizeof(hid_desc) : 0) + (__USBInstallMIDI ? sizeof(midi_desc) : 0);
|
||||
int usbd_desc_len = TUD_CONFIG_DESC_LEN + (__USBInstallSerial ? sizeof(cdc_desc) : 0) + (hasHID ? sizeof(hid_desc) : 0);
|
||||
|
||||
uint8_t tud_cfg_desc[TUD_CONFIG_DESC_LEN] = {
|
||||
// Config number, interface count, string index, total length, attribute, power in mA
|
||||
@@ -271,9 +260,6 @@ void __SetupUSBDescriptor() {
|
||||
memcpy(ptr, hid_desc, sizeof(hid_desc));
|
||||
ptr += sizeof(hid_desc);
|
||||
}
|
||||
if (__USBInstallMIDI) {
|
||||
memcpy(ptr, midi_desc, sizeof(midi_desc));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -303,7 +289,7 @@ const uint16_t *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
|
||||
len = 1;
|
||||
} else {
|
||||
if (index >= sizeof(usbd_desc_str) / sizeof(usbd_desc_str[0])) {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
const char *str = usbd_desc_str[index];
|
||||
for (len = 0; len < DESC_STR_MAX - 1 && str[len]; ++len) {
|
||||
@@ -322,7 +308,7 @@ static void usb_irq() {
|
||||
// if the mutex is already owned, then we are in user code
|
||||
// in this file which will do a tud_task itself, so we'll just do nothing
|
||||
// until the next tick; we won't starve
|
||||
if (mutex_try_enter(&__usb_mutex, NULL)) {
|
||||
if (mutex_try_enter(&__usb_mutex, nullptr)) {
|
||||
tud_task();
|
||||
mutex_exit(&__usb_mutex);
|
||||
}
|
||||
@@ -352,7 +338,7 @@ void __USBStart() {
|
||||
irq_set_exclusive_handler(__usb_task_irq, usb_irq);
|
||||
irq_set_enabled(__usb_task_irq, true);
|
||||
|
||||
add_alarm_in_us(USB_TASK_INTERVAL, timer_task, NULL, true);
|
||||
add_alarm_in_us(USB_TASK_INTERVAL, timer_task, nullptr, true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ extern void __USBInstallSerial() __attribute__((weak));
|
||||
extern void __USBInstallKeyboard() __attribute__((weak));
|
||||
extern void __USBInstallJoystick() __attribute__((weak));
|
||||
extern void __USBInstallMouse() __attribute__((weak));
|
||||
extern void __USBInstallMIDI() __attribute__((weak));
|
||||
|
||||
// Big, global USB mutex, shared with all USB devices to make sure we don't
|
||||
// have multiple cores updating the TUSB state in parallel
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#define ARDUINO_PICO_MAJOR 2
|
||||
#define ARDUINO_PICO_MINOR 4
|
||||
#define ARDUINO_PICO_REVISION 1
|
||||
#define ARDUINO_PICO_VERSION_STR "2.4.1"
|
||||
#define ARDUINO_PICO_MINOR 5
|
||||
#define ARDUINO_PICO_REVISION 4
|
||||
#define ARDUINO_PICO_VERSION_STR "2.5.4"
|
||||
|
||||
@@ -370,3 +370,8 @@ size_t SerialPIO::write(uint8_t c) {
|
||||
SerialPIO::operator bool() {
|
||||
return _running;
|
||||
}
|
||||
|
||||
#ifdef ARDUINO_NANO_RP2040_CONNECT
|
||||
// NINA updates
|
||||
SerialPIO Serial3(SERIAL3_TX, SERIAL3_RX);
|
||||
#endif
|
||||
|
||||
@@ -80,3 +80,8 @@ protected:
|
||||
uint32_t _reader;
|
||||
uint8_t *_queue;
|
||||
};
|
||||
|
||||
#ifdef ARDUINO_NANO_RP2040_CONNECT
|
||||
// NINA updates
|
||||
extern SerialPIO Serial3;
|
||||
#endif
|
||||
|
||||
@@ -171,12 +171,16 @@ void SerialUART::begin(unsigned long baud, uint16_t config) {
|
||||
break;
|
||||
}
|
||||
uart_set_format(_uart, bits, stop, parity);
|
||||
_fcnTx = gpio_get_function(_tx);
|
||||
_fcnRx = gpio_get_function(_rx);
|
||||
gpio_set_function(_tx, GPIO_FUNC_UART);
|
||||
gpio_set_function(_rx, GPIO_FUNC_UART);
|
||||
if (_rts != UART_PIN_NOT_DEFINED) {
|
||||
_fcnRts = gpio_get_function(_rts);
|
||||
gpio_set_function(_rts, GPIO_FUNC_UART);
|
||||
}
|
||||
if (_cts != UART_PIN_NOT_DEFINED) {
|
||||
_fcnCts = gpio_get_function(_cts);
|
||||
gpio_set_function(_cts, GPIO_FUNC_UART);
|
||||
}
|
||||
uart_set_hw_flow(_uart, _rts != UART_PIN_NOT_DEFINED, _cts != UART_PIN_NOT_DEFINED);
|
||||
@@ -211,6 +215,7 @@ void SerialUART::end() {
|
||||
irq_set_enabled(UART1_IRQ, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Paranoia - ensure nobody else is using anything here at the same time
|
||||
mutex_enter_blocking(&_mutex);
|
||||
mutex_enter_blocking(&_fifoMutex);
|
||||
@@ -219,6 +224,16 @@ void SerialUART::end() {
|
||||
// Reset the mutexes once all is off/cleaned up
|
||||
mutex_exit(&_fifoMutex);
|
||||
mutex_exit(&_mutex);
|
||||
|
||||
// Restore pin functions
|
||||
gpio_set_function(_tx, _fcnTx);
|
||||
gpio_set_function(_rx, _fcnRx);
|
||||
if (_rts != UART_PIN_NOT_DEFINED) {
|
||||
gpio_set_function(_rts, _fcnRts);
|
||||
}
|
||||
if (_cts != UART_PIN_NOT_DEFINED) {
|
||||
gpio_set_function(_cts, _fcnCts);
|
||||
}
|
||||
}
|
||||
|
||||
void SerialUART::_pumpFIFO() {
|
||||
|
||||
@@ -71,6 +71,7 @@ private:
|
||||
uart_inst_t *_uart;
|
||||
pin_size_t _tx, _rx;
|
||||
pin_size_t _rts, _cts;
|
||||
enum gpio_function _fcnTx, _fcnRx, _fcnRts, _fcnCts;
|
||||
int _baud;
|
||||
mutex_t _mutex;
|
||||
bool _polling = false;
|
||||
|
||||
@@ -64,52 +64,57 @@ void SerialUSB::end() {
|
||||
}
|
||||
|
||||
int SerialUSB::peek() {
|
||||
CoreMutex m(&__usb_mutex);
|
||||
CoreMutex m(&__usb_mutex, false);
|
||||
if (!_running || !m) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t c;
|
||||
tud_task();
|
||||
return tud_cdc_peek(&c) ? (int) c : -1;
|
||||
}
|
||||
|
||||
int SerialUSB::read() {
|
||||
CoreMutex m(&__usb_mutex);
|
||||
CoreMutex m(&__usb_mutex, false);
|
||||
if (!_running || !m) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tud_cdc_connected() && tud_cdc_available()) {
|
||||
tud_task();
|
||||
if (tud_cdc_available()) {
|
||||
return tud_cdc_read_char();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int SerialUSB::available() {
|
||||
CoreMutex m(&__usb_mutex);
|
||||
CoreMutex m(&__usb_mutex, false);
|
||||
if (!_running || !m) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
tud_task();
|
||||
return tud_cdc_available();
|
||||
}
|
||||
|
||||
int SerialUSB::availableForWrite() {
|
||||
CoreMutex m(&__usb_mutex);
|
||||
CoreMutex m(&__usb_mutex, false);
|
||||
if (!_running || !m) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
tud_task();
|
||||
return tud_cdc_write_available();
|
||||
}
|
||||
|
||||
void SerialUSB::flush() {
|
||||
CoreMutex m(&__usb_mutex);
|
||||
CoreMutex m(&__usb_mutex, false);
|
||||
if (!_running || !m) {
|
||||
return;
|
||||
}
|
||||
|
||||
tud_cdc_write_flush();
|
||||
tud_task();
|
||||
}
|
||||
|
||||
size_t SerialUSB::write(uint8_t c) {
|
||||
@@ -117,7 +122,7 @@ size_t SerialUSB::write(uint8_t c) {
|
||||
}
|
||||
|
||||
size_t SerialUSB::write(const uint8_t *buf, size_t length) {
|
||||
CoreMutex m(&__usb_mutex);
|
||||
CoreMutex m(&__usb_mutex, false);
|
||||
if (!_running || !m) {
|
||||
return 0;
|
||||
}
|
||||
@@ -142,7 +147,7 @@ size_t SerialUSB::write(const uint8_t *buf, size_t length) {
|
||||
tud_task();
|
||||
tud_cdc_write_flush();
|
||||
if (!tud_cdc_connected() ||
|
||||
(!tud_cdc_write_available() && time_us_64() > last_avail_time + 1000000 /* 1 second */)) {
|
||||
(!tud_cdc_write_available() && time_us_64() > last_avail_time + 1'000'000 /* 1 second */)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -151,11 +156,12 @@ size_t SerialUSB::write(const uint8_t *buf, size_t length) {
|
||||
// reset our timeout
|
||||
last_avail_time = 0;
|
||||
}
|
||||
tud_task();
|
||||
return written;
|
||||
}
|
||||
|
||||
SerialUSB::operator bool() {
|
||||
CoreMutex m(&__usb_mutex);
|
||||
CoreMutex m(&__usb_mutex, false);
|
||||
if (!_running || !m) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ void tone(uint8_t pin, unsigned int frequency, unsigned long duration) {
|
||||
return; // Weird deadlock case
|
||||
}
|
||||
|
||||
int us = 1000000 / frequency / 2;
|
||||
int us = 1'000'000 / frequency / 2;
|
||||
if (us < 5) {
|
||||
us = 5;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
_freertos.cpp - Internal core definitions for FreeRTOS
|
||||
|
||||
Copyright (c) 2022 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "_freertos.h"
|
||||
#include "pico/mutex.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct {
|
||||
mutex_t *src;
|
||||
SemaphoreHandle_t dst;
|
||||
} FMMap;
|
||||
|
||||
static FMMap *_map = nullptr;
|
||||
extern "C" SemaphoreHandle_t __get_freertos_mutex_for_ptr(mutex_t *m) {
|
||||
if (!_map) {
|
||||
_map = (FMMap *)calloc(sizeof(FMMap), 16);
|
||||
}
|
||||
// Pre-existing map
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (m == _map[i].src) {
|
||||
return _map[i].dst;
|
||||
}
|
||||
}
|
||||
// Make a new mutex
|
||||
auto fm = __freertos_mutex_create();
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (_map[i].src == nullptr) {
|
||||
_map[i].src = m;
|
||||
_map[i].dst = fm;
|
||||
return fm;
|
||||
}
|
||||
}
|
||||
return nullptr; // Need to make space for more mutex maps!
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
_freertos.h - Internal core definitions for FreeRTOS
|
||||
|
||||
Copyright (c) 2022 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "pico/mutex.h"
|
||||
|
||||
// Cannot include refs to FreeRTOS's actual semaphore calls because they
|
||||
// are implemented as macros, so we have a wrapper in our variant hook
|
||||
// to handle it.
|
||||
|
||||
extern bool __isFreeRTOS;
|
||||
|
||||
// FreeRTOS has been set up
|
||||
extern volatile bool __freeRTOSinitted;
|
||||
|
||||
extern "C" {
|
||||
#ifndef INC_FREERTOS_H
|
||||
struct QueueDefinition; /* Using old naming convention so as not to break kernel aware debuggers. */
|
||||
typedef struct QueueDefinition * QueueHandle_t;
|
||||
typedef QueueHandle_t SemaphoreHandle_t;
|
||||
#endif
|
||||
|
||||
extern SemaphoreHandle_t __freertos_mutex_create() __attribute__((weak));
|
||||
extern SemaphoreHandle_t _freertos_recursive_mutex_create() __attribute__((weak));
|
||||
|
||||
extern void __freertos_mutex_take(SemaphoreHandle_t mtx) __attribute__((weak));
|
||||
extern int __freertos_mutex_try_take(SemaphoreHandle_t mtx) __attribute__((weak));
|
||||
extern void __freertos_mutex_give(SemaphoreHandle_t mtx) __attribute__((weak));
|
||||
|
||||
extern void __freertos_recursive_mutex_take(SemaphoreHandle_t mtx) __attribute__((weak));
|
||||
extern int __freertos_recursive_mutex_try_take(SemaphoreHandle_t mtx) __attribute__((weak));
|
||||
extern void __freertos_recursive_mutex_give(SemaphoreHandle_t mtx) __attribute__((weak));
|
||||
|
||||
#ifndef INC_FREERTOS_H
|
||||
extern void vTaskSuspendAll() __attribute__((weak));
|
||||
extern int32_t xTaskResumeAll() __attribute__((weak));
|
||||
|
||||
typedef struct tskTaskControlBlock * TaskHandle_t;
|
||||
extern void vTaskPreemptionDisable(TaskHandle_t p) __attribute__((weak));
|
||||
extern void vTaskPreemptionEnable(TaskHandle_t p) __attribute__((weak));
|
||||
#endif
|
||||
|
||||
extern SemaphoreHandle_t __get_freertos_mutex_for_ptr(mutex_t *m);
|
||||
}
|
||||
|
||||
// Halt the FreeRTOS PendSV task switching magic
|
||||
extern "C" int __holdUpPendSV;
|
||||
@@ -1,57 +1,2 @@
|
||||
/*
|
||||
Arduino API main include
|
||||
Copyright (c) 2016 Arduino LLC. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef ARDUINO_API_H
|
||||
#define ARDUINO_API_H
|
||||
|
||||
// version 1.2.0
|
||||
#define ARDUINO_API_VERSION 10200
|
||||
|
||||
#include "Binary.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include "Interrupts.h"
|
||||
#include "IPAddress.h"
|
||||
#include "Print.h"
|
||||
#include "Printable.h"
|
||||
#include "PluggableUSB.h"
|
||||
#include "Server.h"
|
||||
#include "String.h"
|
||||
#include "Stream.h"
|
||||
#include "Udp.h"
|
||||
#include "USBAPI.h"
|
||||
#include "WCharacter.h"
|
||||
#endif
|
||||
|
||||
/* Standard C library includes */
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
// Misc Arduino core functions
|
||||
#include "Common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
// Compatibility layer for older code
|
||||
#include "Compat.h"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#pragma once
|
||||
#include "../../../ArduinoCore-API/api/ArduinoAPI.h"
|
||||
|
||||
+2
-552
@@ -1,552 +1,2 @@
|
||||
/*
|
||||
binary.h - Definitions for binary constants
|
||||
Deprecated -- use 0b binary literals instead
|
||||
Copyright (c) 2006 David A. Mellis. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef Binary_h
|
||||
#define Binary_h
|
||||
|
||||
/* If supported, 0b binary literals are preferable to these constants.
|
||||
* In that case, warn the user about these being deprecated (if possible). */
|
||||
#if __cplusplus >= 201402L
|
||||
/* C++14 introduces binary literals; C++11 introduces [[deprecated()]] */
|
||||
#define DEPRECATED(x) [[deprecated("use " #x " instead")]]
|
||||
#elif __GNUC__ >= 6
|
||||
/* GCC 4.3 supports binary literals; GCC 6 supports __deprecated__ on enums*/
|
||||
#define DEPRECATED(x) __attribute__ ((__deprecated__ ("use " #x " instead")))
|
||||
#else
|
||||
/* binary literals not supported, or "deprecated" warning not displayable */
|
||||
#define DEPRECATED(x)
|
||||
#endif
|
||||
|
||||
enum {
|
||||
B0 DEPRECATED(0b0 ) = 0,
|
||||
B00 DEPRECATED(0b00 ) = 0,
|
||||
B000 DEPRECATED(0b000 ) = 0,
|
||||
B0000 DEPRECATED(0b0000 ) = 0,
|
||||
B00000 DEPRECATED(0b00000 ) = 0,
|
||||
B000000 DEPRECATED(0b000000 ) = 0,
|
||||
B0000000 DEPRECATED(0b0000000 ) = 0,
|
||||
B00000000 DEPRECATED(0b00000000) = 0,
|
||||
B1 DEPRECATED(0b1 ) = 1,
|
||||
B01 DEPRECATED(0b01 ) = 1,
|
||||
B001 DEPRECATED(0b001 ) = 1,
|
||||
B0001 DEPRECATED(0b0001 ) = 1,
|
||||
B00001 DEPRECATED(0b00001 ) = 1,
|
||||
B000001 DEPRECATED(0b000001 ) = 1,
|
||||
B0000001 DEPRECATED(0b0000001 ) = 1,
|
||||
B00000001 DEPRECATED(0b00000001) = 1,
|
||||
B10 DEPRECATED(0b10 ) = 2,
|
||||
B010 DEPRECATED(0b010 ) = 2,
|
||||
B0010 DEPRECATED(0b0010 ) = 2,
|
||||
B00010 DEPRECATED(0b00010 ) = 2,
|
||||
B000010 DEPRECATED(0b000010 ) = 2,
|
||||
B0000010 DEPRECATED(0b0000010 ) = 2,
|
||||
B00000010 DEPRECATED(0b00000010) = 2,
|
||||
B11 DEPRECATED(0b11 ) = 3,
|
||||
B011 DEPRECATED(0b011 ) = 3,
|
||||
B0011 DEPRECATED(0b0011 ) = 3,
|
||||
B00011 DEPRECATED(0b00011 ) = 3,
|
||||
B000011 DEPRECATED(0b000011 ) = 3,
|
||||
B0000011 DEPRECATED(0b0000011 ) = 3,
|
||||
B00000011 DEPRECATED(0b00000011) = 3,
|
||||
B100 DEPRECATED(0b100 ) = 4,
|
||||
B0100 DEPRECATED(0b0100 ) = 4,
|
||||
B00100 DEPRECATED(0b00100 ) = 4,
|
||||
B000100 DEPRECATED(0b000100 ) = 4,
|
||||
B0000100 DEPRECATED(0b0000100 ) = 4,
|
||||
B00000100 DEPRECATED(0b00000100) = 4,
|
||||
B101 DEPRECATED(0b101 ) = 5,
|
||||
B0101 DEPRECATED(0b0101 ) = 5,
|
||||
B00101 DEPRECATED(0b00101 ) = 5,
|
||||
B000101 DEPRECATED(0b000101 ) = 5,
|
||||
B0000101 DEPRECATED(0b0000101 ) = 5,
|
||||
B00000101 DEPRECATED(0b00000101) = 5,
|
||||
B110 DEPRECATED(0b110 ) = 6,
|
||||
B0110 DEPRECATED(0b0110 ) = 6,
|
||||
B00110 DEPRECATED(0b00110 ) = 6,
|
||||
B000110 DEPRECATED(0b000110 ) = 6,
|
||||
B0000110 DEPRECATED(0b0000110 ) = 6,
|
||||
B00000110 DEPRECATED(0b00000110) = 6,
|
||||
B111 DEPRECATED(0b111 ) = 7,
|
||||
B0111 DEPRECATED(0b0111 ) = 7,
|
||||
B00111 DEPRECATED(0b00111 ) = 7,
|
||||
B000111 DEPRECATED(0b000111 ) = 7,
|
||||
B0000111 DEPRECATED(0b0000111 ) = 7,
|
||||
B00000111 DEPRECATED(0b00000111) = 7,
|
||||
B1000 DEPRECATED(0b1000 ) = 8,
|
||||
B01000 DEPRECATED(0b01000 ) = 8,
|
||||
B001000 DEPRECATED(0b001000 ) = 8,
|
||||
B0001000 DEPRECATED(0b0001000 ) = 8,
|
||||
B00001000 DEPRECATED(0b00001000) = 8,
|
||||
B1001 DEPRECATED(0b1001 ) = 9,
|
||||
B01001 DEPRECATED(0b01001 ) = 9,
|
||||
B001001 DEPRECATED(0b001001 ) = 9,
|
||||
B0001001 DEPRECATED(0b0001001 ) = 9,
|
||||
B00001001 DEPRECATED(0b00001001) = 9,
|
||||
B1010 DEPRECATED(0b1010 ) = 10,
|
||||
B01010 DEPRECATED(0b01010 ) = 10,
|
||||
B001010 DEPRECATED(0b001010 ) = 10,
|
||||
B0001010 DEPRECATED(0b0001010 ) = 10,
|
||||
B00001010 DEPRECATED(0b00001010) = 10,
|
||||
B1011 DEPRECATED(0b1011 ) = 11,
|
||||
B01011 DEPRECATED(0b01011 ) = 11,
|
||||
B001011 DEPRECATED(0b001011 ) = 11,
|
||||
B0001011 DEPRECATED(0b0001011 ) = 11,
|
||||
B00001011 DEPRECATED(0b00001011) = 11,
|
||||
B1100 DEPRECATED(0b1100 ) = 12,
|
||||
B01100 DEPRECATED(0b01100 ) = 12,
|
||||
B001100 DEPRECATED(0b001100 ) = 12,
|
||||
B0001100 DEPRECATED(0b0001100 ) = 12,
|
||||
B00001100 DEPRECATED(0b00001100) = 12,
|
||||
B1101 DEPRECATED(0b1101 ) = 13,
|
||||
B01101 DEPRECATED(0b01101 ) = 13,
|
||||
B001101 DEPRECATED(0b001101 ) = 13,
|
||||
B0001101 DEPRECATED(0b0001101 ) = 13,
|
||||
B00001101 DEPRECATED(0b00001101) = 13,
|
||||
B1110 DEPRECATED(0b1110 ) = 14,
|
||||
B01110 DEPRECATED(0b01110 ) = 14,
|
||||
B001110 DEPRECATED(0b001110 ) = 14,
|
||||
B0001110 DEPRECATED(0b0001110 ) = 14,
|
||||
B00001110 DEPRECATED(0b00001110) = 14,
|
||||
B1111 DEPRECATED(0b1111 ) = 15,
|
||||
B01111 DEPRECATED(0b01111 ) = 15,
|
||||
B001111 DEPRECATED(0b001111 ) = 15,
|
||||
B0001111 DEPRECATED(0b0001111 ) = 15,
|
||||
B00001111 DEPRECATED(0b00001111) = 15,
|
||||
B10000 DEPRECATED(0b10000 ) = 16,
|
||||
B010000 DEPRECATED(0b010000 ) = 16,
|
||||
B0010000 DEPRECATED(0b0010000 ) = 16,
|
||||
B00010000 DEPRECATED(0b00010000) = 16,
|
||||
B10001 DEPRECATED(0b10001 ) = 17,
|
||||
B010001 DEPRECATED(0b010001 ) = 17,
|
||||
B0010001 DEPRECATED(0b0010001 ) = 17,
|
||||
B00010001 DEPRECATED(0b00010001) = 17,
|
||||
B10010 DEPRECATED(0b10010 ) = 18,
|
||||
B010010 DEPRECATED(0b010010 ) = 18,
|
||||
B0010010 DEPRECATED(0b0010010 ) = 18,
|
||||
B00010010 DEPRECATED(0b00010010) = 18,
|
||||
B10011 DEPRECATED(0b10011 ) = 19,
|
||||
B010011 DEPRECATED(0b010011 ) = 19,
|
||||
B0010011 DEPRECATED(0b0010011 ) = 19,
|
||||
B00010011 DEPRECATED(0b00010011) = 19,
|
||||
B10100 DEPRECATED(0b10100 ) = 20,
|
||||
B010100 DEPRECATED(0b010100 ) = 20,
|
||||
B0010100 DEPRECATED(0b0010100 ) = 20,
|
||||
B00010100 DEPRECATED(0b00010100) = 20,
|
||||
B10101 DEPRECATED(0b10101 ) = 21,
|
||||
B010101 DEPRECATED(0b010101 ) = 21,
|
||||
B0010101 DEPRECATED(0b0010101 ) = 21,
|
||||
B00010101 DEPRECATED(0b00010101) = 21,
|
||||
B10110 DEPRECATED(0b10110 ) = 22,
|
||||
B010110 DEPRECATED(0b010110 ) = 22,
|
||||
B0010110 DEPRECATED(0b0010110 ) = 22,
|
||||
B00010110 DEPRECATED(0b00010110) = 22,
|
||||
B10111 DEPRECATED(0b10111 ) = 23,
|
||||
B010111 DEPRECATED(0b010111 ) = 23,
|
||||
B0010111 DEPRECATED(0b0010111 ) = 23,
|
||||
B00010111 DEPRECATED(0b00010111) = 23,
|
||||
B11000 DEPRECATED(0b11000 ) = 24,
|
||||
B011000 DEPRECATED(0b011000 ) = 24,
|
||||
B0011000 DEPRECATED(0b0011000 ) = 24,
|
||||
B00011000 DEPRECATED(0b00011000) = 24,
|
||||
B11001 DEPRECATED(0b11001 ) = 25,
|
||||
B011001 DEPRECATED(0b011001 ) = 25,
|
||||
B0011001 DEPRECATED(0b0011001 ) = 25,
|
||||
B00011001 DEPRECATED(0b00011001) = 25,
|
||||
B11010 DEPRECATED(0b11010 ) = 26,
|
||||
B011010 DEPRECATED(0b011010 ) = 26,
|
||||
B0011010 DEPRECATED(0b0011010 ) = 26,
|
||||
B00011010 DEPRECATED(0b00011010) = 26,
|
||||
B11011 DEPRECATED(0b11011 ) = 27,
|
||||
B011011 DEPRECATED(0b011011 ) = 27,
|
||||
B0011011 DEPRECATED(0b0011011 ) = 27,
|
||||
B00011011 DEPRECATED(0b00011011) = 27,
|
||||
B11100 DEPRECATED(0b11100 ) = 28,
|
||||
B011100 DEPRECATED(0b011100 ) = 28,
|
||||
B0011100 DEPRECATED(0b0011100 ) = 28,
|
||||
B00011100 DEPRECATED(0b00011100) = 28,
|
||||
B11101 DEPRECATED(0b11101 ) = 29,
|
||||
B011101 DEPRECATED(0b011101 ) = 29,
|
||||
B0011101 DEPRECATED(0b0011101 ) = 29,
|
||||
B00011101 DEPRECATED(0b00011101) = 29,
|
||||
B11110 DEPRECATED(0b11110 ) = 30,
|
||||
B011110 DEPRECATED(0b011110 ) = 30,
|
||||
B0011110 DEPRECATED(0b0011110 ) = 30,
|
||||
B00011110 DEPRECATED(0b00011110) = 30,
|
||||
B11111 DEPRECATED(0b11111 ) = 31,
|
||||
B011111 DEPRECATED(0b011111 ) = 31,
|
||||
B0011111 DEPRECATED(0b0011111 ) = 31,
|
||||
B00011111 DEPRECATED(0b00011111) = 31,
|
||||
B100000 DEPRECATED(0b100000 ) = 32,
|
||||
B0100000 DEPRECATED(0b0100000 ) = 32,
|
||||
B00100000 DEPRECATED(0b00100000) = 32,
|
||||
B100001 DEPRECATED(0b100001 ) = 33,
|
||||
B0100001 DEPRECATED(0b0100001 ) = 33,
|
||||
B00100001 DEPRECATED(0b00100001) = 33,
|
||||
B100010 DEPRECATED(0b100010 ) = 34,
|
||||
B0100010 DEPRECATED(0b0100010 ) = 34,
|
||||
B00100010 DEPRECATED(0b00100010) = 34,
|
||||
B100011 DEPRECATED(0b100011 ) = 35,
|
||||
B0100011 DEPRECATED(0b0100011 ) = 35,
|
||||
B00100011 DEPRECATED(0b00100011) = 35,
|
||||
B100100 DEPRECATED(0b100100 ) = 36,
|
||||
B0100100 DEPRECATED(0b0100100 ) = 36,
|
||||
B00100100 DEPRECATED(0b00100100) = 36,
|
||||
B100101 DEPRECATED(0b100101 ) = 37,
|
||||
B0100101 DEPRECATED(0b0100101 ) = 37,
|
||||
B00100101 DEPRECATED(0b00100101) = 37,
|
||||
B100110 DEPRECATED(0b100110 ) = 38,
|
||||
B0100110 DEPRECATED(0b0100110 ) = 38,
|
||||
B00100110 DEPRECATED(0b00100110) = 38,
|
||||
B100111 DEPRECATED(0b100111 ) = 39,
|
||||
B0100111 DEPRECATED(0b0100111 ) = 39,
|
||||
B00100111 DEPRECATED(0b00100111) = 39,
|
||||
B101000 DEPRECATED(0b101000 ) = 40,
|
||||
B0101000 DEPRECATED(0b0101000 ) = 40,
|
||||
B00101000 DEPRECATED(0b00101000) = 40,
|
||||
B101001 DEPRECATED(0b101001 ) = 41,
|
||||
B0101001 DEPRECATED(0b0101001 ) = 41,
|
||||
B00101001 DEPRECATED(0b00101001) = 41,
|
||||
B101010 DEPRECATED(0b101010 ) = 42,
|
||||
B0101010 DEPRECATED(0b0101010 ) = 42,
|
||||
B00101010 DEPRECATED(0b00101010) = 42,
|
||||
B101011 DEPRECATED(0b101011 ) = 43,
|
||||
B0101011 DEPRECATED(0b0101011 ) = 43,
|
||||
B00101011 DEPRECATED(0b00101011) = 43,
|
||||
B101100 DEPRECATED(0b101100 ) = 44,
|
||||
B0101100 DEPRECATED(0b0101100 ) = 44,
|
||||
B00101100 DEPRECATED(0b00101100) = 44,
|
||||
B101101 DEPRECATED(0b101101 ) = 45,
|
||||
B0101101 DEPRECATED(0b0101101 ) = 45,
|
||||
B00101101 DEPRECATED(0b00101101) = 45,
|
||||
B101110 DEPRECATED(0b101110 ) = 46,
|
||||
B0101110 DEPRECATED(0b0101110 ) = 46,
|
||||
B00101110 DEPRECATED(0b00101110) = 46,
|
||||
B101111 DEPRECATED(0b101111 ) = 47,
|
||||
B0101111 DEPRECATED(0b0101111 ) = 47,
|
||||
B00101111 DEPRECATED(0b00101111) = 47,
|
||||
B110000 DEPRECATED(0b110000 ) = 48,
|
||||
B0110000 DEPRECATED(0b0110000 ) = 48,
|
||||
B00110000 DEPRECATED(0b00110000) = 48,
|
||||
B110001 DEPRECATED(0b110001 ) = 49,
|
||||
B0110001 DEPRECATED(0b0110001 ) = 49,
|
||||
B00110001 DEPRECATED(0b00110001) = 49,
|
||||
B110010 DEPRECATED(0b110010 ) = 50,
|
||||
B0110010 DEPRECATED(0b0110010 ) = 50,
|
||||
B00110010 DEPRECATED(0b00110010) = 50,
|
||||
B110011 DEPRECATED(0b110011 ) = 51,
|
||||
B0110011 DEPRECATED(0b0110011 ) = 51,
|
||||
B00110011 DEPRECATED(0b00110011) = 51,
|
||||
B110100 DEPRECATED(0b110100 ) = 52,
|
||||
B0110100 DEPRECATED(0b0110100 ) = 52,
|
||||
B00110100 DEPRECATED(0b00110100) = 52,
|
||||
B110101 DEPRECATED(0b110101 ) = 53,
|
||||
B0110101 DEPRECATED(0b0110101 ) = 53,
|
||||
B00110101 DEPRECATED(0b00110101) = 53,
|
||||
B110110 DEPRECATED(0b110110 ) = 54,
|
||||
B0110110 DEPRECATED(0b0110110 ) = 54,
|
||||
B00110110 DEPRECATED(0b00110110) = 54,
|
||||
B110111 DEPRECATED(0b110111 ) = 55,
|
||||
B0110111 DEPRECATED(0b0110111 ) = 55,
|
||||
B00110111 DEPRECATED(0b00110111) = 55,
|
||||
B111000 DEPRECATED(0b111000 ) = 56,
|
||||
B0111000 DEPRECATED(0b0111000 ) = 56,
|
||||
B00111000 DEPRECATED(0b00111000) = 56,
|
||||
B111001 DEPRECATED(0b111001 ) = 57,
|
||||
B0111001 DEPRECATED(0b0111001 ) = 57,
|
||||
B00111001 DEPRECATED(0b00111001) = 57,
|
||||
B111010 DEPRECATED(0b111010 ) = 58,
|
||||
B0111010 DEPRECATED(0b0111010 ) = 58,
|
||||
B00111010 DEPRECATED(0b00111010) = 58,
|
||||
B111011 DEPRECATED(0b111011 ) = 59,
|
||||
B0111011 DEPRECATED(0b0111011 ) = 59,
|
||||
B00111011 DEPRECATED(0b00111011) = 59,
|
||||
B111100 DEPRECATED(0b111100 ) = 60,
|
||||
B0111100 DEPRECATED(0b0111100 ) = 60,
|
||||
B00111100 DEPRECATED(0b00111100) = 60,
|
||||
B111101 DEPRECATED(0b111101 ) = 61,
|
||||
B0111101 DEPRECATED(0b0111101 ) = 61,
|
||||
B00111101 DEPRECATED(0b00111101) = 61,
|
||||
B111110 DEPRECATED(0b111110 ) = 62,
|
||||
B0111110 DEPRECATED(0b0111110 ) = 62,
|
||||
B00111110 DEPRECATED(0b00111110) = 62,
|
||||
B111111 DEPRECATED(0b111111 ) = 63,
|
||||
B0111111 DEPRECATED(0b0111111 ) = 63,
|
||||
B00111111 DEPRECATED(0b00111111) = 63,
|
||||
B1000000 DEPRECATED(0b1000000 ) = 64,
|
||||
B01000000 DEPRECATED(0b01000000) = 64,
|
||||
B1000001 DEPRECATED(0b1000001 ) = 65,
|
||||
B01000001 DEPRECATED(0b01000001) = 65,
|
||||
B1000010 DEPRECATED(0b1000010 ) = 66,
|
||||
B01000010 DEPRECATED(0b01000010) = 66,
|
||||
B1000011 DEPRECATED(0b1000011 ) = 67,
|
||||
B01000011 DEPRECATED(0b01000011) = 67,
|
||||
B1000100 DEPRECATED(0b1000100 ) = 68,
|
||||
B01000100 DEPRECATED(0b01000100) = 68,
|
||||
B1000101 DEPRECATED(0b1000101 ) = 69,
|
||||
B01000101 DEPRECATED(0b01000101) = 69,
|
||||
B1000110 DEPRECATED(0b1000110 ) = 70,
|
||||
B01000110 DEPRECATED(0b01000110) = 70,
|
||||
B1000111 DEPRECATED(0b1000111 ) = 71,
|
||||
B01000111 DEPRECATED(0b01000111) = 71,
|
||||
B1001000 DEPRECATED(0b1001000 ) = 72,
|
||||
B01001000 DEPRECATED(0b01001000) = 72,
|
||||
B1001001 DEPRECATED(0b1001001 ) = 73,
|
||||
B01001001 DEPRECATED(0b01001001) = 73,
|
||||
B1001010 DEPRECATED(0b1001010 ) = 74,
|
||||
B01001010 DEPRECATED(0b01001010) = 74,
|
||||
B1001011 DEPRECATED(0b1001011 ) = 75,
|
||||
B01001011 DEPRECATED(0b01001011) = 75,
|
||||
B1001100 DEPRECATED(0b1001100 ) = 76,
|
||||
B01001100 DEPRECATED(0b01001100) = 76,
|
||||
B1001101 DEPRECATED(0b1001101 ) = 77,
|
||||
B01001101 DEPRECATED(0b01001101) = 77,
|
||||
B1001110 DEPRECATED(0b1001110 ) = 78,
|
||||
B01001110 DEPRECATED(0b01001110) = 78,
|
||||
B1001111 DEPRECATED(0b1001111 ) = 79,
|
||||
B01001111 DEPRECATED(0b01001111) = 79,
|
||||
B1010000 DEPRECATED(0b1010000 ) = 80,
|
||||
B01010000 DEPRECATED(0b01010000) = 80,
|
||||
B1010001 DEPRECATED(0b1010001 ) = 81,
|
||||
B01010001 DEPRECATED(0b01010001) = 81,
|
||||
B1010010 DEPRECATED(0b1010010 ) = 82,
|
||||
B01010010 DEPRECATED(0b01010010) = 82,
|
||||
B1010011 DEPRECATED(0b1010011 ) = 83,
|
||||
B01010011 DEPRECATED(0b01010011) = 83,
|
||||
B1010100 DEPRECATED(0b1010100 ) = 84,
|
||||
B01010100 DEPRECATED(0b01010100) = 84,
|
||||
B1010101 DEPRECATED(0b1010101 ) = 85,
|
||||
B01010101 DEPRECATED(0b01010101) = 85,
|
||||
B1010110 DEPRECATED(0b1010110 ) = 86,
|
||||
B01010110 DEPRECATED(0b01010110) = 86,
|
||||
B1010111 DEPRECATED(0b1010111 ) = 87,
|
||||
B01010111 DEPRECATED(0b01010111) = 87,
|
||||
B1011000 DEPRECATED(0b1011000 ) = 88,
|
||||
B01011000 DEPRECATED(0b01011000) = 88,
|
||||
B1011001 DEPRECATED(0b1011001 ) = 89,
|
||||
B01011001 DEPRECATED(0b01011001) = 89,
|
||||
B1011010 DEPRECATED(0b1011010 ) = 90,
|
||||
B01011010 DEPRECATED(0b01011010) = 90,
|
||||
B1011011 DEPRECATED(0b1011011 ) = 91,
|
||||
B01011011 DEPRECATED(0b01011011) = 91,
|
||||
B1011100 DEPRECATED(0b1011100 ) = 92,
|
||||
B01011100 DEPRECATED(0b01011100) = 92,
|
||||
B1011101 DEPRECATED(0b1011101 ) = 93,
|
||||
B01011101 DEPRECATED(0b01011101) = 93,
|
||||
B1011110 DEPRECATED(0b1011110 ) = 94,
|
||||
B01011110 DEPRECATED(0b01011110) = 94,
|
||||
B1011111 DEPRECATED(0b1011111 ) = 95,
|
||||
B01011111 DEPRECATED(0b01011111) = 95,
|
||||
B1100000 DEPRECATED(0b1100000 ) = 96,
|
||||
B01100000 DEPRECATED(0b01100000) = 96,
|
||||
B1100001 DEPRECATED(0b1100001 ) = 97,
|
||||
B01100001 DEPRECATED(0b01100001) = 97,
|
||||
B1100010 DEPRECATED(0b1100010 ) = 98,
|
||||
B01100010 DEPRECATED(0b01100010) = 98,
|
||||
B1100011 DEPRECATED(0b1100011 ) = 99,
|
||||
B01100011 DEPRECATED(0b01100011) = 99,
|
||||
B1100100 DEPRECATED(0b1100100 ) = 100,
|
||||
B01100100 DEPRECATED(0b01100100) = 100,
|
||||
B1100101 DEPRECATED(0b1100101 ) = 101,
|
||||
B01100101 DEPRECATED(0b01100101) = 101,
|
||||
B1100110 DEPRECATED(0b1100110 ) = 102,
|
||||
B01100110 DEPRECATED(0b01100110) = 102,
|
||||
B1100111 DEPRECATED(0b1100111 ) = 103,
|
||||
B01100111 DEPRECATED(0b01100111) = 103,
|
||||
B1101000 DEPRECATED(0b1101000 ) = 104,
|
||||
B01101000 DEPRECATED(0b01101000) = 104,
|
||||
B1101001 DEPRECATED(0b1101001 ) = 105,
|
||||
B01101001 DEPRECATED(0b01101001) = 105,
|
||||
B1101010 DEPRECATED(0b1101010 ) = 106,
|
||||
B01101010 DEPRECATED(0b01101010) = 106,
|
||||
B1101011 DEPRECATED(0b1101011 ) = 107,
|
||||
B01101011 DEPRECATED(0b01101011) = 107,
|
||||
B1101100 DEPRECATED(0b1101100 ) = 108,
|
||||
B01101100 DEPRECATED(0b01101100) = 108,
|
||||
B1101101 DEPRECATED(0b1101101 ) = 109,
|
||||
B01101101 DEPRECATED(0b01101101) = 109,
|
||||
B1101110 DEPRECATED(0b1101110 ) = 110,
|
||||
B01101110 DEPRECATED(0b01101110) = 110,
|
||||
B1101111 DEPRECATED(0b1101111 ) = 111,
|
||||
B01101111 DEPRECATED(0b01101111) = 111,
|
||||
B1110000 DEPRECATED(0b1110000 ) = 112,
|
||||
B01110000 DEPRECATED(0b01110000) = 112,
|
||||
B1110001 DEPRECATED(0b1110001 ) = 113,
|
||||
B01110001 DEPRECATED(0b01110001) = 113,
|
||||
B1110010 DEPRECATED(0b1110010 ) = 114,
|
||||
B01110010 DEPRECATED(0b01110010) = 114,
|
||||
B1110011 DEPRECATED(0b1110011 ) = 115,
|
||||
B01110011 DEPRECATED(0b01110011) = 115,
|
||||
B1110100 DEPRECATED(0b1110100 ) = 116,
|
||||
B01110100 DEPRECATED(0b01110100) = 116,
|
||||
B1110101 DEPRECATED(0b1110101 ) = 117,
|
||||
B01110101 DEPRECATED(0b01110101) = 117,
|
||||
B1110110 DEPRECATED(0b1110110 ) = 118,
|
||||
B01110110 DEPRECATED(0b01110110) = 118,
|
||||
B1110111 DEPRECATED(0b1110111 ) = 119,
|
||||
B01110111 DEPRECATED(0b01110111) = 119,
|
||||
B1111000 DEPRECATED(0b1111000 ) = 120,
|
||||
B01111000 DEPRECATED(0b01111000) = 120,
|
||||
B1111001 DEPRECATED(0b1111001 ) = 121,
|
||||
B01111001 DEPRECATED(0b01111001) = 121,
|
||||
B1111010 DEPRECATED(0b1111010 ) = 122,
|
||||
B01111010 DEPRECATED(0b01111010) = 122,
|
||||
B1111011 DEPRECATED(0b1111011 ) = 123,
|
||||
B01111011 DEPRECATED(0b01111011) = 123,
|
||||
B1111100 DEPRECATED(0b1111100 ) = 124,
|
||||
B01111100 DEPRECATED(0b01111100) = 124,
|
||||
B1111101 DEPRECATED(0b1111101 ) = 125,
|
||||
B01111101 DEPRECATED(0b01111101) = 125,
|
||||
B1111110 DEPRECATED(0b1111110 ) = 126,
|
||||
B01111110 DEPRECATED(0b01111110) = 126,
|
||||
B1111111 DEPRECATED(0b1111111 ) = 127,
|
||||
B01111111 DEPRECATED(0b01111111) = 127,
|
||||
B10000000 DEPRECATED(0b10000000) = 128,
|
||||
B10000001 DEPRECATED(0b10000001) = 129,
|
||||
B10000010 DEPRECATED(0b10000010) = 130,
|
||||
B10000011 DEPRECATED(0b10000011) = 131,
|
||||
B10000100 DEPRECATED(0b10000100) = 132,
|
||||
B10000101 DEPRECATED(0b10000101) = 133,
|
||||
B10000110 DEPRECATED(0b10000110) = 134,
|
||||
B10000111 DEPRECATED(0b10000111) = 135,
|
||||
B10001000 DEPRECATED(0b10001000) = 136,
|
||||
B10001001 DEPRECATED(0b10001001) = 137,
|
||||
B10001010 DEPRECATED(0b10001010) = 138,
|
||||
B10001011 DEPRECATED(0b10001011) = 139,
|
||||
B10001100 DEPRECATED(0b10001100) = 140,
|
||||
B10001101 DEPRECATED(0b10001101) = 141,
|
||||
B10001110 DEPRECATED(0b10001110) = 142,
|
||||
B10001111 DEPRECATED(0b10001111) = 143,
|
||||
B10010000 DEPRECATED(0b10010000) = 144,
|
||||
B10010001 DEPRECATED(0b10010001) = 145,
|
||||
B10010010 DEPRECATED(0b10010010) = 146,
|
||||
B10010011 DEPRECATED(0b10010011) = 147,
|
||||
B10010100 DEPRECATED(0b10010100) = 148,
|
||||
B10010101 DEPRECATED(0b10010101) = 149,
|
||||
B10010110 DEPRECATED(0b10010110) = 150,
|
||||
B10010111 DEPRECATED(0b10010111) = 151,
|
||||
B10011000 DEPRECATED(0b10011000) = 152,
|
||||
B10011001 DEPRECATED(0b10011001) = 153,
|
||||
B10011010 DEPRECATED(0b10011010) = 154,
|
||||
B10011011 DEPRECATED(0b10011011) = 155,
|
||||
B10011100 DEPRECATED(0b10011100) = 156,
|
||||
B10011101 DEPRECATED(0b10011101) = 157,
|
||||
B10011110 DEPRECATED(0b10011110) = 158,
|
||||
B10011111 DEPRECATED(0b10011111) = 159,
|
||||
B10100000 DEPRECATED(0b10100000) = 160,
|
||||
B10100001 DEPRECATED(0b10100001) = 161,
|
||||
B10100010 DEPRECATED(0b10100010) = 162,
|
||||
B10100011 DEPRECATED(0b10100011) = 163,
|
||||
B10100100 DEPRECATED(0b10100100) = 164,
|
||||
B10100101 DEPRECATED(0b10100101) = 165,
|
||||
B10100110 DEPRECATED(0b10100110) = 166,
|
||||
B10100111 DEPRECATED(0b10100111) = 167,
|
||||
B10101000 DEPRECATED(0b10101000) = 168,
|
||||
B10101001 DEPRECATED(0b10101001) = 169,
|
||||
B10101010 DEPRECATED(0b10101010) = 170,
|
||||
B10101011 DEPRECATED(0b10101011) = 171,
|
||||
B10101100 DEPRECATED(0b10101100) = 172,
|
||||
B10101101 DEPRECATED(0b10101101) = 173,
|
||||
B10101110 DEPRECATED(0b10101110) = 174,
|
||||
B10101111 DEPRECATED(0b10101111) = 175,
|
||||
B10110000 DEPRECATED(0b10110000) = 176,
|
||||
B10110001 DEPRECATED(0b10110001) = 177,
|
||||
B10110010 DEPRECATED(0b10110010) = 178,
|
||||
B10110011 DEPRECATED(0b10110011) = 179,
|
||||
B10110100 DEPRECATED(0b10110100) = 180,
|
||||
B10110101 DEPRECATED(0b10110101) = 181,
|
||||
B10110110 DEPRECATED(0b10110110) = 182,
|
||||
B10110111 DEPRECATED(0b10110111) = 183,
|
||||
B10111000 DEPRECATED(0b10111000) = 184,
|
||||
B10111001 DEPRECATED(0b10111001) = 185,
|
||||
B10111010 DEPRECATED(0b10111010) = 186,
|
||||
B10111011 DEPRECATED(0b10111011) = 187,
|
||||
B10111100 DEPRECATED(0b10111100) = 188,
|
||||
B10111101 DEPRECATED(0b10111101) = 189,
|
||||
B10111110 DEPRECATED(0b10111110) = 190,
|
||||
B10111111 DEPRECATED(0b10111111) = 191,
|
||||
B11000000 DEPRECATED(0b11000000) = 192,
|
||||
B11000001 DEPRECATED(0b11000001) = 193,
|
||||
B11000010 DEPRECATED(0b11000010) = 194,
|
||||
B11000011 DEPRECATED(0b11000011) = 195,
|
||||
B11000100 DEPRECATED(0b11000100) = 196,
|
||||
B11000101 DEPRECATED(0b11000101) = 197,
|
||||
B11000110 DEPRECATED(0b11000110) = 198,
|
||||
B11000111 DEPRECATED(0b11000111) = 199,
|
||||
B11001000 DEPRECATED(0b11001000) = 200,
|
||||
B11001001 DEPRECATED(0b11001001) = 201,
|
||||
B11001010 DEPRECATED(0b11001010) = 202,
|
||||
B11001011 DEPRECATED(0b11001011) = 203,
|
||||
B11001100 DEPRECATED(0b11001100) = 204,
|
||||
B11001101 DEPRECATED(0b11001101) = 205,
|
||||
B11001110 DEPRECATED(0b11001110) = 206,
|
||||
B11001111 DEPRECATED(0b11001111) = 207,
|
||||
B11010000 DEPRECATED(0b11010000) = 208,
|
||||
B11010001 DEPRECATED(0b11010001) = 209,
|
||||
B11010010 DEPRECATED(0b11010010) = 210,
|
||||
B11010011 DEPRECATED(0b11010011) = 211,
|
||||
B11010100 DEPRECATED(0b11010100) = 212,
|
||||
B11010101 DEPRECATED(0b11010101) = 213,
|
||||
B11010110 DEPRECATED(0b11010110) = 214,
|
||||
B11010111 DEPRECATED(0b11010111) = 215,
|
||||
B11011000 DEPRECATED(0b11011000) = 216,
|
||||
B11011001 DEPRECATED(0b11011001) = 217,
|
||||
B11011010 DEPRECATED(0b11011010) = 218,
|
||||
B11011011 DEPRECATED(0b11011011) = 219,
|
||||
B11011100 DEPRECATED(0b11011100) = 220,
|
||||
B11011101 DEPRECATED(0b11011101) = 221,
|
||||
B11011110 DEPRECATED(0b11011110) = 222,
|
||||
B11011111 DEPRECATED(0b11011111) = 223,
|
||||
B11100000 DEPRECATED(0b11100000) = 224,
|
||||
B11100001 DEPRECATED(0b11100001) = 225,
|
||||
B11100010 DEPRECATED(0b11100010) = 226,
|
||||
B11100011 DEPRECATED(0b11100011) = 227,
|
||||
B11100100 DEPRECATED(0b11100100) = 228,
|
||||
B11100101 DEPRECATED(0b11100101) = 229,
|
||||
B11100110 DEPRECATED(0b11100110) = 230,
|
||||
B11100111 DEPRECATED(0b11100111) = 231,
|
||||
B11101000 DEPRECATED(0b11101000) = 232,
|
||||
B11101001 DEPRECATED(0b11101001) = 233,
|
||||
B11101010 DEPRECATED(0b11101010) = 234,
|
||||
B11101011 DEPRECATED(0b11101011) = 235,
|
||||
B11101100 DEPRECATED(0b11101100) = 236,
|
||||
B11101101 DEPRECATED(0b11101101) = 237,
|
||||
B11101110 DEPRECATED(0b11101110) = 238,
|
||||
B11101111 DEPRECATED(0b11101111) = 239,
|
||||
B11110000 DEPRECATED(0b11110000) = 240,
|
||||
B11110001 DEPRECATED(0b11110001) = 241,
|
||||
B11110010 DEPRECATED(0b11110010) = 242,
|
||||
B11110011 DEPRECATED(0b11110011) = 243,
|
||||
B11110100 DEPRECATED(0b11110100) = 244,
|
||||
B11110101 DEPRECATED(0b11110101) = 245,
|
||||
B11110110 DEPRECATED(0b11110110) = 246,
|
||||
B11110111 DEPRECATED(0b11110111) = 247,
|
||||
B11111000 DEPRECATED(0b11111000) = 248,
|
||||
B11111001 DEPRECATED(0b11111001) = 249,
|
||||
B11111010 DEPRECATED(0b11111010) = 250,
|
||||
B11111011 DEPRECATED(0b11111011) = 251,
|
||||
B11111100 DEPRECATED(0b11111100) = 252,
|
||||
B11111101 DEPRECATED(0b11111101) = 253,
|
||||
B11111110 DEPRECATED(0b11111110) = 254,
|
||||
B11111111 DEPRECATED(0b11111111) = 255
|
||||
};
|
||||
|
||||
#undef DEPRECATED
|
||||
|
||||
#endif
|
||||
#pragma once
|
||||
#include "../../../ArduinoCore-API/api/Binary.h"
|
||||
|
||||
@@ -1,46 +1,2 @@
|
||||
/*
|
||||
Client.h - Base class that provides Client
|
||||
Copyright (c) 2011 Adrian McEwen. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Stream.h"
|
||||
#include "IPAddress.h"
|
||||
|
||||
namespace arduino {
|
||||
|
||||
class Client : public Stream {
|
||||
|
||||
public:
|
||||
virtual int connect(IPAddress ip, uint16_t port) =0;
|
||||
virtual int connect(const char *host, uint16_t port) =0;
|
||||
virtual size_t write(uint8_t) =0;
|
||||
virtual size_t write(const uint8_t *buf, size_t size) =0;
|
||||
virtual int available() = 0;
|
||||
virtual int read() = 0;
|
||||
virtual int read(uint8_t *buf, size_t size) = 0;
|
||||
virtual int peek() = 0;
|
||||
virtual void flush() = 0;
|
||||
virtual void stop() = 0;
|
||||
virtual uint8_t connected() = 0;
|
||||
virtual operator bool() = 0;
|
||||
protected:
|
||||
uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); };
|
||||
};
|
||||
|
||||
}
|
||||
#include "../../../ArduinoCore-API/api/Client.h"
|
||||
|
||||
@@ -1,10 +1 @@
|
||||
#include "Common.h"
|
||||
|
||||
/* C++ prototypes */
|
||||
long map(long x, long in_min, long in_max, long out_min, long out_max)
|
||||
{
|
||||
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||
}
|
||||
|
||||
uint16_t makeWord(uint16_t w) { return w; }
|
||||
uint16_t makeWord(uint8_t h, uint8_t l) { return (h << 8) | l; }
|
||||
#include "../../../ArduinoCore-API/api/Common.cpp"
|
||||
|
||||
+1
-172
@@ -1,173 +1,2 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"{
|
||||
#endif
|
||||
|
||||
void yield(void);
|
||||
|
||||
typedef enum {
|
||||
LOW = 0,
|
||||
HIGH = 1,
|
||||
CHANGE = 2,
|
||||
FALLING = 3,
|
||||
RISING = 4,
|
||||
} PinStatus;
|
||||
|
||||
typedef enum {
|
||||
INPUT = 0x0,
|
||||
OUTPUT = 0x1,
|
||||
INPUT_PULLUP = 0x2,
|
||||
INPUT_PULLDOWN = 0x3,
|
||||
OUTPUT_2MA = 0x4,
|
||||
OUTPUT_4MA = 0x5,
|
||||
OUTPUT_8MA = 0x6,
|
||||
OUTPUT_12MA = 0x7,
|
||||
} PinMode;
|
||||
|
||||
typedef enum {
|
||||
LSBFIRST = 0,
|
||||
MSBFIRST = 1,
|
||||
} BitOrder;
|
||||
|
||||
#define PI 3.1415926535897932384626433832795
|
||||
#define HALF_PI 1.5707963267948966192313216916398
|
||||
#define TWO_PI 6.283185307179586476925286766559
|
||||
#define DEG_TO_RAD 0.017453292519943295769236907684886
|
||||
#define RAD_TO_DEG 57.295779513082320876798154814105
|
||||
#define EULER 2.718281828459045235360287471352
|
||||
|
||||
#define SERIAL 0x0
|
||||
#define DISPLAY 0x1
|
||||
|
||||
#ifndef constrain
|
||||
#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
|
||||
#endif
|
||||
|
||||
#ifndef radians
|
||||
#define radians(deg) ((deg)*DEG_TO_RAD)
|
||||
#endif
|
||||
|
||||
#ifndef degrees
|
||||
#define degrees(rad) ((rad)*RAD_TO_DEG)
|
||||
#endif
|
||||
|
||||
#ifndef sq
|
||||
#define sq(x) ((x)*(x))
|
||||
#endif
|
||||
|
||||
typedef void (*voidFuncPtr)(void);
|
||||
typedef void (*voidFuncPtrParam)(void*);
|
||||
|
||||
// interrupts() / noInterrupts() must be defined by the core
|
||||
|
||||
#define lowByte(w) ((uint8_t) ((w) & 0xff))
|
||||
#define highByte(w) ((uint8_t) ((w) >> 8))
|
||||
|
||||
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
|
||||
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
|
||||
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
|
||||
#define bitToggle(value, bit) ((value) ^= (1UL << (bit)))
|
||||
#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
|
||||
|
||||
#ifndef bit
|
||||
#define bit(b) (1UL << (b))
|
||||
#endif
|
||||
|
||||
/* TODO: request for removal */
|
||||
typedef bool boolean;
|
||||
typedef uint8_t byte;
|
||||
typedef uint16_t word;
|
||||
|
||||
void init(void);
|
||||
void initVariant(void);
|
||||
|
||||
#ifndef HOST
|
||||
int atexit(void (*func)()) __attribute__((weak));
|
||||
#endif
|
||||
int main() __attribute__((weak));
|
||||
|
||||
#ifdef EXTENDED_PIN_MODE
|
||||
// Platforms who wnat to declare more than 256 pins need to define EXTENDED_PIN_MODE globally
|
||||
typedef uint32_t pin_size_t;
|
||||
#else
|
||||
typedef uint8_t pin_size_t;
|
||||
#endif
|
||||
|
||||
void pinMode(pin_size_t pinNumber, PinMode pinMode);
|
||||
void digitalWrite(pin_size_t pinNumber, PinStatus status);
|
||||
PinStatus digitalRead(pin_size_t pinNumber);
|
||||
int analogRead(pin_size_t pinNumber);
|
||||
void analogReference(uint8_t mode);
|
||||
void analogWrite(pin_size_t pinNumber, int value);
|
||||
|
||||
unsigned long millis(void);
|
||||
unsigned long micros(void);
|
||||
void delay(unsigned long);
|
||||
void delayMicroseconds(unsigned int us);
|
||||
unsigned long pulseIn(pin_size_t pin, uint8_t state, unsigned long timeout);
|
||||
unsigned long pulseInLong(pin_size_t pin, uint8_t state, unsigned long timeout);
|
||||
|
||||
void shiftOut(pin_size_t dataPin, pin_size_t clockPin, BitOrder bitOrder, uint8_t val);
|
||||
uint8_t shiftIn(pin_size_t dataPin, pin_size_t clockPin, BitOrder bitOrder);
|
||||
|
||||
void attachInterrupt(pin_size_t interruptNumber, voidFuncPtr callback, PinStatus mode);
|
||||
void attachInterruptParam(pin_size_t interruptNumber, voidFuncPtrParam callback, PinStatus mode, void* param);
|
||||
void detachInterrupt(pin_size_t interruptNumber);
|
||||
|
||||
void setup(void);
|
||||
void loop(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
template<class T, class L>
|
||||
auto min(const T& a, const L& b) -> decltype((b < a) ? b : a)
|
||||
{
|
||||
return (b < a) ? b : a;
|
||||
}
|
||||
|
||||
template<class T, class L>
|
||||
auto max(const T& a, const L& b) -> decltype((b < a) ? b : a)
|
||||
{
|
||||
return (a < b) ? b : a;
|
||||
}
|
||||
#else
|
||||
#ifndef min
|
||||
#define min(a,b) \
|
||||
({ __typeof__ (a) _a = (a); \
|
||||
__typeof__ (b) _b = (b); \
|
||||
_a < _b ? _a : _b; })
|
||||
#endif
|
||||
#ifndef max
|
||||
#define max(a,b) \
|
||||
({ __typeof__ (a) _a = (a); \
|
||||
__typeof__ (b) _b = (b); \
|
||||
_a > _b ? _a : _b; })
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
/* C++ prototypes */
|
||||
uint16_t makeWord(uint16_t w);
|
||||
uint16_t makeWord(byte h, byte l);
|
||||
|
||||
#define word(...) makeWord(__VA_ARGS__)
|
||||
|
||||
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L);
|
||||
unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L);
|
||||
|
||||
void tone(uint8_t _pin, unsigned int frequency, unsigned long duration = 0);
|
||||
void noTone(uint8_t _pin);
|
||||
|
||||
// WMath prototypes
|
||||
long random(long);
|
||||
long random(long, long);
|
||||
void randomSeed(unsigned long);
|
||||
long map(long, long, long, long, long);
|
||||
|
||||
#endif // __cplusplus
|
||||
#include "../../../ArduinoCore-API/api/Common.h"
|
||||
|
||||
@@ -1,16 +1,2 @@
|
||||
#ifndef __COMPAT_H__
|
||||
#define __COMPAT_H__
|
||||
|
||||
namespace arduino {
|
||||
|
||||
inline void pinMode(pin_size_t pinNumber, int mode) {
|
||||
pinMode(pinNumber, (PinMode)mode);
|
||||
};
|
||||
|
||||
inline void digitalWrite(pin_size_t pinNumber, int status) {
|
||||
digitalWrite(pinNumber, (PinStatus)status);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#pragma once
|
||||
#include "../../../ArduinoCore-API/api/Compat.h"
|
||||
|
||||
@@ -1,47 +1,2 @@
|
||||
/*
|
||||
Copyright (c) 2016 Arduino LLC. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "Stream.h"
|
||||
|
||||
namespace arduino {
|
||||
|
||||
class HardwareI2C : public Stream
|
||||
{
|
||||
public:
|
||||
virtual void begin() = 0;
|
||||
virtual void begin(uint8_t address) = 0;
|
||||
virtual void end() = 0;
|
||||
|
||||
virtual void setClock(uint32_t freq) = 0;
|
||||
|
||||
virtual void beginTransmission(uint8_t address) = 0;
|
||||
virtual uint8_t endTransmission(bool stopBit) = 0;
|
||||
virtual uint8_t endTransmission(void) = 0;
|
||||
|
||||
virtual size_t requestFrom(uint8_t address, size_t len, bool stopBit) = 0;
|
||||
virtual size_t requestFrom(uint8_t address, size_t len) = 0;
|
||||
|
||||
virtual void onReceive(void(*)(int)) = 0;
|
||||
virtual void onRequest(void(*)(void)) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#include "../../../ArduinoCore-API/api/HardwareI2C.h"
|
||||
|
||||
@@ -1,130 +1,2 @@
|
||||
/*
|
||||
Copyright (c) 2018 Arduino LLC. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Common.h"
|
||||
#include <inttypes.h>
|
||||
#include "Stream.h"
|
||||
|
||||
#define SPI_HAS_TRANSACTION
|
||||
|
||||
namespace arduino {
|
||||
|
||||
typedef enum {
|
||||
SPI_MODE0 = 0,
|
||||
SPI_MODE1 = 1,
|
||||
SPI_MODE2 = 2,
|
||||
SPI_MODE3 = 3,
|
||||
} SPIMode;
|
||||
|
||||
|
||||
class SPISettings {
|
||||
public:
|
||||
SPISettings(uint32_t clock, BitOrder bitOrder, SPIMode dataMode) {
|
||||
if (__builtin_constant_p(clock)) {
|
||||
init_AlwaysInline(clock, bitOrder, dataMode);
|
||||
} else {
|
||||
init_MightInline(clock, bitOrder, dataMode);
|
||||
}
|
||||
}
|
||||
|
||||
SPISettings(uint32_t clock, BitOrder bitOrder, int dataMode) {
|
||||
if (__builtin_constant_p(clock)) {
|
||||
init_AlwaysInline(clock, bitOrder, (SPIMode)dataMode);
|
||||
} else {
|
||||
init_MightInline(clock, bitOrder, (SPIMode)dataMode);
|
||||
}
|
||||
}
|
||||
|
||||
// Default speed set to 4MHz, SPI mode set to MODE 0 and Bit order set to MSB first.
|
||||
SPISettings() { init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0); }
|
||||
|
||||
bool operator==(const SPISettings& rhs) const
|
||||
{
|
||||
if ((this->clockFreq == rhs.clockFreq) &&
|
||||
(this->bitOrder == rhs.bitOrder) &&
|
||||
(this->dataMode == rhs.dataMode)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator!=(const SPISettings& rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
uint32_t getClockFreq() const {
|
||||
return clockFreq;
|
||||
}
|
||||
SPIMode getDataMode() const {
|
||||
return dataMode;
|
||||
}
|
||||
BitOrder getBitOrder() const {
|
||||
return (bitOrder);
|
||||
}
|
||||
|
||||
private:
|
||||
void init_MightInline(uint32_t clock, BitOrder bitOrder, SPIMode dataMode) {
|
||||
init_AlwaysInline(clock, bitOrder, dataMode);
|
||||
}
|
||||
|
||||
// Core developer MUST use an helper function in beginTransaction() to use this data
|
||||
void init_AlwaysInline(uint32_t clock, BitOrder bitOrder, SPIMode dataMode) __attribute__((__always_inline__)) {
|
||||
this->clockFreq = clock;
|
||||
this->dataMode = dataMode;
|
||||
this->bitOrder = bitOrder;
|
||||
}
|
||||
|
||||
uint32_t clockFreq;
|
||||
SPIMode dataMode;
|
||||
BitOrder bitOrder;
|
||||
|
||||
friend class HardwareSPI;
|
||||
};
|
||||
|
||||
const SPISettings DEFAULT_SPI_SETTINGS = SPISettings();
|
||||
|
||||
class HardwareSPI
|
||||
{
|
||||
public:
|
||||
virtual ~HardwareSPI() { }
|
||||
|
||||
virtual uint8_t transfer(uint8_t data) = 0;
|
||||
virtual uint16_t transfer16(uint16_t data) = 0;
|
||||
virtual void transfer(void *buf, size_t count) = 0;
|
||||
|
||||
// Transaction Functions
|
||||
virtual void usingInterrupt(int interruptNumber) = 0;
|
||||
virtual void notUsingInterrupt(int interruptNumber) = 0;
|
||||
virtual void beginTransaction(SPISettings settings) = 0;
|
||||
virtual void endTransaction(void) = 0;
|
||||
|
||||
// SPI Configuration methods
|
||||
virtual void attachInterrupt() = 0;
|
||||
virtual void detachInterrupt() = 0;
|
||||
|
||||
virtual void begin() = 0;
|
||||
virtual void end() = 0;
|
||||
};
|
||||
|
||||
// Alias SPIClass to HardwareSPI since it's already the defacto standard for SPI classe name
|
||||
typedef HardwareSPI SPIClass;
|
||||
|
||||
}
|
||||
#include "../../../ArduinoCore-API/api/HardwareSPI.h"
|
||||
|
||||
@@ -1,105 +1,2 @@
|
||||
/*
|
||||
Copyright (c) 2016 Arduino LLC. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "Stream.h"
|
||||
|
||||
namespace arduino {
|
||||
|
||||
// XXX: Those constants should be defined as const int / enums?
|
||||
// XXX: shall we use namespaces too?
|
||||
#define SERIAL_PARITY_EVEN (0x1ul)
|
||||
#define SERIAL_PARITY_ODD (0x2ul)
|
||||
#define SERIAL_PARITY_NONE (0x3ul)
|
||||
#define SERIAL_PARITY_MARK (0x4ul)
|
||||
#define SERIAL_PARITY_SPACE (0x5ul)
|
||||
#define SERIAL_PARITY_MASK (0xFul)
|
||||
|
||||
#define SERIAL_STOP_BIT_1 (0x10ul)
|
||||
#define SERIAL_STOP_BIT_1_5 (0x20ul)
|
||||
#define SERIAL_STOP_BIT_2 (0x30ul)
|
||||
#define SERIAL_STOP_BIT_MASK (0xF0ul)
|
||||
|
||||
#define SERIAL_DATA_5 (0x100ul)
|
||||
#define SERIAL_DATA_6 (0x200ul)
|
||||
#define SERIAL_DATA_7 (0x300ul)
|
||||
#define SERIAL_DATA_8 (0x400ul)
|
||||
#define SERIAL_DATA_MASK (0xF00ul)
|
||||
|
||||
#define SERIAL_5N1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_NONE | SERIAL_DATA_5)
|
||||
#define SERIAL_6N1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_NONE | SERIAL_DATA_6)
|
||||
#define SERIAL_7N1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_NONE | SERIAL_DATA_7)
|
||||
#define SERIAL_8N1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_NONE | SERIAL_DATA_8)
|
||||
#define SERIAL_5N2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_NONE | SERIAL_DATA_5)
|
||||
#define SERIAL_6N2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_NONE | SERIAL_DATA_6)
|
||||
#define SERIAL_7N2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_NONE | SERIAL_DATA_7)
|
||||
#define SERIAL_8N2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_NONE | SERIAL_DATA_8)
|
||||
#define SERIAL_5E1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_EVEN | SERIAL_DATA_5)
|
||||
#define SERIAL_6E1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_EVEN | SERIAL_DATA_6)
|
||||
#define SERIAL_7E1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_EVEN | SERIAL_DATA_7)
|
||||
#define SERIAL_8E1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_EVEN | SERIAL_DATA_8)
|
||||
#define SERIAL_5E2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_EVEN | SERIAL_DATA_5)
|
||||
#define SERIAL_6E2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_EVEN | SERIAL_DATA_6)
|
||||
#define SERIAL_7E2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_EVEN | SERIAL_DATA_7)
|
||||
#define SERIAL_8E2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_EVEN | SERIAL_DATA_8)
|
||||
#define SERIAL_5O1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_ODD | SERIAL_DATA_5)
|
||||
#define SERIAL_6O1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_ODD | SERIAL_DATA_6)
|
||||
#define SERIAL_7O1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_ODD | SERIAL_DATA_7)
|
||||
#define SERIAL_8O1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_ODD | SERIAL_DATA_8)
|
||||
#define SERIAL_5O2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_ODD | SERIAL_DATA_5)
|
||||
#define SERIAL_6O2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_ODD | SERIAL_DATA_6)
|
||||
#define SERIAL_7O2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_ODD | SERIAL_DATA_7)
|
||||
#define SERIAL_8O2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_ODD | SERIAL_DATA_8)
|
||||
#define SERIAL_5M1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_MARK | SERIAL_DATA_5)
|
||||
#define SERIAL_6M1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_MARK | SERIAL_DATA_6)
|
||||
#define SERIAL_7M1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_MARK | SERIAL_DATA_7)
|
||||
#define SERIAL_8M1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_MARK | SERIAL_DATA_8)
|
||||
#define SERIAL_5M2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_MARK | SERIAL_DATA_5)
|
||||
#define SERIAL_6M2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_MARK | SERIAL_DATA_6)
|
||||
#define SERIAL_7M2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_MARK | SERIAL_DATA_7)
|
||||
#define SERIAL_8M2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_MARK | SERIAL_DATA_8)
|
||||
#define SERIAL_5S1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_SPACE | SERIAL_DATA_5)
|
||||
#define SERIAL_6S1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_SPACE | SERIAL_DATA_6)
|
||||
#define SERIAL_7S1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_SPACE | SERIAL_DATA_7)
|
||||
#define SERIAL_8S1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_SPACE | SERIAL_DATA_8)
|
||||
#define SERIAL_5S2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_SPACE | SERIAL_DATA_5)
|
||||
#define SERIAL_6S2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_SPACE | SERIAL_DATA_6)
|
||||
#define SERIAL_7S2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_SPACE | SERIAL_DATA_7)
|
||||
#define SERIAL_8S2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_SPACE | SERIAL_DATA_8)
|
||||
|
||||
class HardwareSerial : public Stream
|
||||
{
|
||||
public:
|
||||
virtual void begin(unsigned long) = 0;
|
||||
virtual void begin(unsigned long baudrate, uint16_t config) = 0;
|
||||
virtual void end() = 0;
|
||||
virtual int available(void) = 0;
|
||||
virtual int peek(void) = 0;
|
||||
virtual int read(void) = 0;
|
||||
virtual void flush(void) = 0;
|
||||
virtual size_t write(uint8_t) = 0;
|
||||
using Print::write; // pull in write(str) and write(buf, size) from Print
|
||||
virtual operator bool() = 0;
|
||||
};
|
||||
|
||||
// XXX: Are we keeping the serialEvent API?
|
||||
extern void serialEventRun(void) __attribute__((weak));
|
||||
|
||||
}
|
||||
#include "../../../ArduinoCore-API/api/HardwareSerial.h"
|
||||
|
||||
@@ -1,248 +1 @@
|
||||
/*
|
||||
IPAddress.cpp - Base class that provides IPAddress
|
||||
Copyright (c) 2011 Adrian McEwen. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <IPAddress.h>
|
||||
#include <Print.h>
|
||||
|
||||
IPAddress::IPAddress(const IPAddress& from)
|
||||
{
|
||||
ip_addr_copy(_ip, from._ip);
|
||||
}
|
||||
|
||||
IPAddress::IPAddress() {
|
||||
_ip = *IP_ANY_TYPE; // lwIP's v4-or-v6 generic address
|
||||
}
|
||||
|
||||
bool IPAddress::isSet () const {
|
||||
return !ip_addr_isany(&_ip) && ((*this) != IPADDR_NONE);
|
||||
}
|
||||
|
||||
IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) {
|
||||
setV4();
|
||||
(*this)[0] = first_octet;
|
||||
(*this)[1] = second_octet;
|
||||
(*this)[2] = third_octet;
|
||||
(*this)[3] = fourth_octet;
|
||||
}
|
||||
|
||||
void IPAddress::ctor32(uint32_t address) {
|
||||
setV4();
|
||||
v4() = address;
|
||||
}
|
||||
|
||||
IPAddress::IPAddress(const uint8_t *address) {
|
||||
setV4();
|
||||
(*this)[0] = address[0];
|
||||
(*this)[1] = address[1];
|
||||
(*this)[2] = address[2];
|
||||
(*this)[3] = address[3];
|
||||
}
|
||||
|
||||
bool IPAddress::fromString(const char *address) {
|
||||
if (!fromString4(address)) {
|
||||
#if LWIP_IPV6
|
||||
return fromString6(address);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IPAddress::fromString4(const char *address) {
|
||||
// TODO: (IPv4) add support for "a", "a.b", "a.b.c" formats
|
||||
|
||||
uint16_t acc = 0; // Accumulator
|
||||
uint8_t dots = 0;
|
||||
|
||||
while (*address)
|
||||
{
|
||||
char c = *address++;
|
||||
if (c >= '0' && c <= '9')
|
||||
{
|
||||
acc = acc * 10 + (c - '0');
|
||||
if (acc > 255) {
|
||||
// Value out of [0..255] range
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (c == '.')
|
||||
{
|
||||
if (dots == 3) {
|
||||
// Too much dots (there must be 3 dots)
|
||||
return false;
|
||||
}
|
||||
(*this)[dots++] = acc;
|
||||
acc = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Invalid char
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (dots != 3) {
|
||||
// Too few dots (there must be 3 dots)
|
||||
return false;
|
||||
}
|
||||
(*this)[3] = acc;
|
||||
|
||||
setV4();
|
||||
return true;
|
||||
}
|
||||
|
||||
IPAddress& IPAddress::operator=(const uint8_t *address) {
|
||||
setV4();
|
||||
v4() = *reinterpret_cast<const uint32_t*>(address);
|
||||
return *this;
|
||||
}
|
||||
|
||||
IPAddress& IPAddress::operator=(uint32_t address) {
|
||||
setV4();
|
||||
v4() = address;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool IPAddress::operator==(const uint8_t* addr) const {
|
||||
return isV4() && v4() == *reinterpret_cast<const uint32_t*>(addr);
|
||||
}
|
||||
|
||||
size_t IPAddress::printTo(Print& p) const {
|
||||
String s = toString();
|
||||
return p.print(s);
|
||||
}
|
||||
|
||||
String IPAddress::toString() const
|
||||
{
|
||||
String s;
|
||||
|
||||
if (!isSet())
|
||||
return "(IP unset)";
|
||||
|
||||
#if LWIP_IPV6
|
||||
if (isV6()) {
|
||||
int count0 = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
uint16_t bit = PP_NTOHS(raw6()[i]);
|
||||
if (bit || count0 < 0) {
|
||||
char buff[64];
|
||||
snprintf(buff, 64, "%x", bit);
|
||||
buff[63] = 0;
|
||||
s += buff;
|
||||
if (count0 > 0)
|
||||
// no more hiding 0
|
||||
count0 = -8;
|
||||
} else
|
||||
count0++;
|
||||
if ((i != 7 && count0 < 2) || count0 == 7)
|
||||
s += ':';
|
||||
}
|
||||
return s;
|
||||
}
|
||||
#endif
|
||||
|
||||
for(int i = 0; i < 4; i++) {
|
||||
char buff[16];
|
||||
snprintf(buff, 16, "%d", (*this)[i]);
|
||||
buff[15] = 0;
|
||||
s += buff;
|
||||
if (i != 3)
|
||||
s += '.';
|
||||
}
|
||||
return s;
|
||||
|
||||
}
|
||||
|
||||
bool IPAddress::isValid(const String& arg) {
|
||||
return IPAddress().fromString(arg);
|
||||
}
|
||||
|
||||
bool IPAddress::isValid(const char* arg) {
|
||||
return IPAddress().fromString(arg);
|
||||
}
|
||||
|
||||
namespace arduino {
|
||||
const IPAddress INADDR_ANY; // generic "0.0.0.0" for IPv4 & IPv6
|
||||
const IPAddress INADDR_NONE(255,255,255,255);
|
||||
};
|
||||
|
||||
void IPAddress::clear() {
|
||||
(*this) = INADDR_ANY;
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
|
||||
#if LWIP_IPV6
|
||||
|
||||
bool IPAddress::fromString6(const char *address) {
|
||||
// TODO: test test test
|
||||
|
||||
uint32_t acc = 0; // Accumulator
|
||||
int dots = 0, doubledots = -1;
|
||||
|
||||
while (*address)
|
||||
{
|
||||
char c = tolower(*address++);
|
||||
if (isalnum(c)) {
|
||||
if (c >= 'a')
|
||||
c -= 'a' - '0' - 10;
|
||||
acc = acc * 16 + (c - '0');
|
||||
if (acc > 0xffff)
|
||||
// Value out of range
|
||||
return false;
|
||||
}
|
||||
else if (c == ':') {
|
||||
if (*address == ':') {
|
||||
if (doubledots >= 0)
|
||||
// :: allowed once
|
||||
return false;
|
||||
// remember location
|
||||
doubledots = dots + !!acc;
|
||||
address++;
|
||||
}
|
||||
if (dots == 7)
|
||||
// too many separators
|
||||
return false;
|
||||
raw6()[dots++] = PP_HTONS(acc);
|
||||
acc = 0;
|
||||
}
|
||||
else
|
||||
// Invalid char
|
||||
return false;
|
||||
}
|
||||
|
||||
if (doubledots == -1 && dots != 7)
|
||||
// Too few separators
|
||||
return false;
|
||||
raw6()[dots++] = PP_HTONS(acc);
|
||||
|
||||
if (doubledots != -1) {
|
||||
for (int i = dots - doubledots - 1; i >= 0; i--)
|
||||
raw6()[8 - dots + doubledots + i] = raw6()[doubledots + i];
|
||||
for (int i = doubledots; i < 8 - dots + doubledots; i++)
|
||||
raw6()[i] = 0;
|
||||
}
|
||||
|
||||
setV6();
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
#include "../../../ArduinoCore-API/api/IPAddress.cpp"
|
||||
|
||||
@@ -1,236 +1,2 @@
|
||||
/*
|
||||
IPAddress.h - Base class that provides IPAddress
|
||||
Copyright (c) 2011 Adrian McEwen. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <api/String.h>
|
||||
#include <Printable.h>
|
||||
|
||||
#include <lwip/init.h>
|
||||
#include <lwip/ip_addr.h>
|
||||
#include <lwip/ip4_addr.h>
|
||||
|
||||
|
||||
// forward declarations of global name space friend classes
|
||||
class EthernetClass;
|
||||
class DhcpClass;
|
||||
class DNSClient;
|
||||
|
||||
|
||||
namespace arduino {
|
||||
|
||||
// to display a netif id with printf:
|
||||
#define NETIFID_STR "%c%c%u"
|
||||
#define NETIFID_VAL(netif) \
|
||||
((netif)? (netif)->name[0]: '-'), \
|
||||
((netif)? (netif)->name[1]: '-'), \
|
||||
((netif)? netif_get_index(netif): 42)
|
||||
|
||||
// A class to make it easier to handle and pass around IP addresses
|
||||
// IPv6 update:
|
||||
// IPAddress is now a decorator class for lwIP's ip_addr_t
|
||||
// fully backward compatible with legacy IPv4-only Arduino's
|
||||
// with unchanged footprint when IPv6 is disabled
|
||||
|
||||
class IPAddress: public Printable {
|
||||
private:
|
||||
#if !LWIP_IPV6
|
||||
// Ugly hack to allow Arduino Ethernet library to twiddle internal bits.
|
||||
// This can only work in IPv4-only mode, of course.
|
||||
union {
|
||||
ip_addr_t _ip;
|
||||
struct {
|
||||
uint8_t bytes[4];
|
||||
} _address;
|
||||
};
|
||||
static_assert(sizeof(_ip) == sizeof(_address), "IP_ADDR_T size != _ADDRESS size");
|
||||
#else
|
||||
ip_addr_t _ip;
|
||||
#endif
|
||||
|
||||
// Access the raw byte array containing the address. Because this returns a pointer
|
||||
// to the internal structure rather than a copy of the address this function should only
|
||||
// be used when you know that the usage of the returned uint8_t* will be transient and not
|
||||
// stored.
|
||||
uint8_t* raw_address() {
|
||||
return reinterpret_cast<uint8_t*>(&v4());
|
||||
}
|
||||
const uint8_t* raw_address() const {
|
||||
return reinterpret_cast<const uint8_t*>(&v4());
|
||||
}
|
||||
|
||||
void ctor32 (uint32_t);
|
||||
|
||||
public:
|
||||
// Constructors
|
||||
IPAddress();
|
||||
IPAddress(const IPAddress& from);
|
||||
IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet);
|
||||
IPAddress(uint32_t address) { ctor32(address); }
|
||||
// IPAddress(unsigned long address) { ctor32(address); }
|
||||
IPAddress(int address) { ctor32(address); }
|
||||
IPAddress(const uint8_t *address);
|
||||
|
||||
bool fromString(const char *address);
|
||||
bool fromString(const String &address) { return fromString(address.c_str()); }
|
||||
|
||||
// Overloaded cast operator to allow IPAddress objects to be used where a pointer
|
||||
// to a four-byte uint8_t array is expected
|
||||
operator uint32_t() const { return isV4()? v4(): (uint32_t)0; }
|
||||
operator uint32_t() { return isV4()? v4(): (uint32_t)0; }
|
||||
|
||||
bool isSet () const;
|
||||
operator bool () const { return isSet(); } // <-
|
||||
operator bool () { return isSet(); } // <- both are needed
|
||||
|
||||
// generic IPv4 wrapper to uint32-view like arduino loves to see it
|
||||
const uint32_t& v4() const { return ip_2_ip4(&_ip)->addr; } // for raw_address(const)
|
||||
uint32_t& v4() { return ip_2_ip4(&_ip)->addr; }
|
||||
|
||||
bool operator==(const IPAddress& addr) const {
|
||||
return ip_addr_cmp(&_ip, &addr._ip);
|
||||
}
|
||||
bool operator!=(const IPAddress& addr) const {
|
||||
return !ip_addr_cmp(&_ip, &addr._ip);
|
||||
}
|
||||
bool operator==(uint32_t addr) const {
|
||||
return isV4() && v4() == addr;
|
||||
}
|
||||
// bool operator==(unsigned long addr) const {
|
||||
// return isV4() && v4() == (uint32_t)addr;
|
||||
// }
|
||||
bool operator!=(uint32_t addr) const {
|
||||
return !(isV4() && v4() == addr);
|
||||
}
|
||||
// bool operator!=(unsigned long addr) const {
|
||||
// return isV4() && v4() != (uint32_t)addr;
|
||||
// }
|
||||
bool operator==(const uint8_t* addr) const;
|
||||
|
||||
int operator>>(int n) const {
|
||||
return isV4()? v4() >> n: 0;
|
||||
}
|
||||
|
||||
// Overloaded index operator to allow getting and setting individual octets of the address
|
||||
uint8_t operator[](int index) const {
|
||||
return isV4()? *(raw_address() + index): 0;
|
||||
}
|
||||
uint8_t& operator[](int index) {
|
||||
setV4();
|
||||
return *(raw_address() + index);
|
||||
}
|
||||
|
||||
// Overloaded copy operators to allow initialisation of IPAddress objects from other types
|
||||
IPAddress& operator=(const uint8_t *address);
|
||||
IPAddress& operator=(uint32_t address);
|
||||
IPAddress& operator=(const IPAddress&) = default;
|
||||
|
||||
virtual size_t printTo(Print& p) const;
|
||||
String toString() const;
|
||||
|
||||
void clear();
|
||||
|
||||
/*
|
||||
check if input string(arg) is a valid IPV4 address or not.
|
||||
return true on valid.
|
||||
return false on invalid.
|
||||
*/
|
||||
static bool isValid(const String& arg);
|
||||
static bool isValid(const char* arg);
|
||||
|
||||
friend class WiFiClass;
|
||||
friend class EthernetClass;
|
||||
friend class UDP;
|
||||
friend class Client;
|
||||
friend class Server;
|
||||
friend class DhcpClass;
|
||||
friend class DNSClient;
|
||||
|
||||
friend ::EthernetClass;
|
||||
friend ::DhcpClass;
|
||||
friend ::DNSClient;
|
||||
|
||||
/*
|
||||
lwIP address compatibility
|
||||
*/
|
||||
//IPAddress(const ipv4_addr& fw_addr) { setV4(); v4() = fw_addr.addr; }
|
||||
//IPAddress(const ipv4_addr* fw_addr) { setV4(); v4() = fw_addr->addr; }
|
||||
|
||||
//IPAddress& operator=(const ipv4_addr& fw_addr) { setV4(); v4() = fw_addr.addr; return *this; }
|
||||
//IPAddress& operator=(const ipv4_addr* fw_addr) { setV4(); v4() = fw_addr->addr; return *this; }
|
||||
|
||||
operator ip_addr_t () const { return _ip; }
|
||||
operator const ip_addr_t*() const { return &_ip; }
|
||||
operator ip_addr_t*() { return &_ip; }
|
||||
|
||||
bool isV4() const { return IP_IS_V4_VAL(_ip); }
|
||||
void setV4() { IP_SET_TYPE_VAL(_ip, IPADDR_TYPE_V4); }
|
||||
|
||||
bool isLocal () const { return ip_addr_islinklocal(&_ip); }
|
||||
|
||||
|
||||
IPAddress(const ip_addr_t& lwip_addr) { ip_addr_copy(_ip, lwip_addr); }
|
||||
IPAddress(const ip_addr_t* lwip_addr) { ip_addr_copy(_ip, *lwip_addr); }
|
||||
|
||||
IPAddress& operator=(const ip_addr_t& lwip_addr) { ip_addr_copy(_ip, lwip_addr); return *this; }
|
||||
IPAddress& operator=(const ip_addr_t* lwip_addr) { ip_addr_copy(_ip, *lwip_addr); return *this; }
|
||||
|
||||
#if LWIP_IPV6
|
||||
uint16_t* raw6()
|
||||
{
|
||||
setV6();
|
||||
return reinterpret_cast<uint16_t*>(ip_2_ip6(&_ip));
|
||||
}
|
||||
|
||||
const uint16_t* raw6() const
|
||||
{
|
||||
return isV6()? reinterpret_cast<const uint16_t*>(ip_2_ip6(&_ip)): nullptr;
|
||||
}
|
||||
|
||||
// when not IPv6, ip_addr_t == ip4_addr_t so this one would be ambiguous
|
||||
// required otherwise
|
||||
operator const ip4_addr_t*() const { return isV4()? ip_2_ip4(&_ip): nullptr; }
|
||||
|
||||
bool isV6() const { return IP_IS_V6_VAL(_ip); }
|
||||
void setV6() { IP_SET_TYPE_VAL(_ip, IPADDR_TYPE_V6); }
|
||||
|
||||
protected:
|
||||
bool fromString6(const char *address);
|
||||
|
||||
#else
|
||||
|
||||
// allow portable code when IPv6 is not enabled
|
||||
|
||||
uint16_t* raw6() { return nullptr; }
|
||||
const uint16_t* raw6() const { return nullptr; }
|
||||
bool isV6() const { return false; }
|
||||
void setV6() { }
|
||||
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool fromString4(const char *address);
|
||||
|
||||
};
|
||||
|
||||
extern const IPAddress INADDR_ANY;
|
||||
extern const IPAddress INADDR_NONE;
|
||||
|
||||
}
|
||||
#include "../../../ArduinoCore-API/api/IPAddress.h"
|
||||
|
||||
@@ -1,44 +1,2 @@
|
||||
#ifndef W_INTERRUPTS_CPP
|
||||
#define W_INTERRUPTS_CPP
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "Common.h"
|
||||
|
||||
namespace arduino {
|
||||
|
||||
template <typename T>
|
||||
using voidTemplateFuncPtrParam = void (*)(T param);
|
||||
|
||||
template<typename T> struct __container__ {
|
||||
void* param;
|
||||
voidTemplateFuncPtrParam<T> function;
|
||||
};
|
||||
|
||||
// C++ only overloaded version of attachInterrupt function
|
||||
template<typename T> void attachInterrupt(pin_size_t interruptNum, voidTemplateFuncPtrParam<T> userFunc, PinStatus mode, T& param) {
|
||||
|
||||
struct __container__<T> *cont = new __container__<T>();
|
||||
cont->param = ¶m;
|
||||
cont->function = userFunc;
|
||||
|
||||
// TODO: check lambda scope
|
||||
// TODO: add structure to delete(__container__) when detachInterrupt() is called
|
||||
auto f = [](void* a) -> void
|
||||
{
|
||||
T param = *(T*)((struct __container__<T>*)a)->param;
|
||||
(((struct __container__<T>*)a)->function)(param);
|
||||
};
|
||||
|
||||
attachInterruptParam(interruptNum, f, mode, cont);
|
||||
}
|
||||
|
||||
template<typename T> void attachInterrupt(pin_size_t interruptNum, voidTemplateFuncPtrParam<T*> userFunc, PinStatus mode, T* param) {
|
||||
attachInterruptParam(interruptNum, (voidFuncPtrParam)userFunc, mode, (void*)param);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#pragma once
|
||||
#include "../../../ArduinoCore-API/api/Interrupts.h"
|
||||
|
||||
@@ -1,101 +1 @@
|
||||
/*
|
||||
PluggableUSB.cpp
|
||||
Copyright (c) 2015 Arduino LLC
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "USBAPI.h"
|
||||
#include "PluggableUSB.h"
|
||||
|
||||
using namespace arduino;
|
||||
|
||||
int PluggableUSB_::getInterface(uint8_t* interfaceCount)
|
||||
{
|
||||
int sent = 0;
|
||||
PluggableUSBModule* node;
|
||||
for (node = rootNode; node; node = node->next) {
|
||||
int res = node->getInterface(interfaceCount);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
sent += res;
|
||||
}
|
||||
return sent;
|
||||
}
|
||||
|
||||
int PluggableUSB_::getDescriptor(USBSetup& setup)
|
||||
{
|
||||
PluggableUSBModule* node;
|
||||
for (node = rootNode; node; node = node->next) {
|
||||
int ret = node->getDescriptor(setup);
|
||||
// ret!=0 -> request has been processed
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PluggableUSB_::getShortName(char *iSerialNum)
|
||||
{
|
||||
PluggableUSBModule* node;
|
||||
for (node = rootNode; node; node = node->next) {
|
||||
iSerialNum += node->getShortName(iSerialNum);
|
||||
}
|
||||
*iSerialNum = 0;
|
||||
}
|
||||
|
||||
bool PluggableUSB_::setup(USBSetup& setup)
|
||||
{
|
||||
PluggableUSBModule* node;
|
||||
for (node = rootNode; node; node = node->next) {
|
||||
if (node->setup(setup)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PluggableUSB_::plug(PluggableUSBModule *node)
|
||||
{
|
||||
if ((lastEp + node->numEndpoints) > totalEP) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!rootNode) {
|
||||
rootNode = node;
|
||||
} else {
|
||||
PluggableUSBModule *current = rootNode;
|
||||
while (current->next) {
|
||||
current = current->next;
|
||||
}
|
||||
current->next = node;
|
||||
}
|
||||
|
||||
node->pluggedInterface = lastIf;
|
||||
node->pluggedEndpoint = lastEp;
|
||||
lastIf += node->numInterfaces;
|
||||
for (uint8_t i = 0; i < node->numEndpoints; i++) {
|
||||
*(unsigned int*)(epBuffer(lastEp)) = node->endpointType[i];
|
||||
lastEp++;
|
||||
}
|
||||
return true;
|
||||
// restart USB layer???
|
||||
}
|
||||
|
||||
PluggableUSB_& PluggableUSB()
|
||||
{
|
||||
static PluggableUSB_ obj;
|
||||
return obj;
|
||||
}
|
||||
#include "../../../ArduinoCore-API/api/PluggableUSB.cpp"
|
||||
|
||||
@@ -1,78 +1,2 @@
|
||||
/*
|
||||
PluggableUSB.h
|
||||
Copyright (c) 2015 Arduino LLC
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef PUSB_h
|
||||
#define PUSB_h
|
||||
|
||||
#include "USBAPI.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
namespace arduino {
|
||||
|
||||
class PluggableUSBModule {
|
||||
public:
|
||||
PluggableUSBModule(uint8_t numEps, uint8_t numIfs, unsigned int *epType) :
|
||||
numEndpoints(numEps), numInterfaces(numIfs), endpointType(epType)
|
||||
{ }
|
||||
|
||||
protected:
|
||||
virtual bool setup(USBSetup& setup) = 0;
|
||||
virtual int getInterface(uint8_t* interfaceCount) = 0;
|
||||
virtual int getDescriptor(USBSetup& setup) = 0;
|
||||
virtual uint8_t getShortName(char *name) { name[0] = 'A'+pluggedInterface; return 1; }
|
||||
|
||||
uint8_t pluggedInterface;
|
||||
uint8_t pluggedEndpoint;
|
||||
|
||||
const uint8_t numEndpoints;
|
||||
const uint8_t numInterfaces;
|
||||
const unsigned int *endpointType;
|
||||
|
||||
PluggableUSBModule *next = NULL;
|
||||
|
||||
friend class PluggableUSB_;
|
||||
};
|
||||
|
||||
class PluggableUSB_ {
|
||||
public:
|
||||
PluggableUSB_();
|
||||
bool plug(PluggableUSBModule *node);
|
||||
int getInterface(uint8_t* interfaceCount);
|
||||
int getDescriptor(USBSetup& setup);
|
||||
bool setup(USBSetup& setup);
|
||||
void getShortName(char *iSerialNum);
|
||||
|
||||
private:
|
||||
uint8_t lastIf;
|
||||
uint8_t lastEp;
|
||||
PluggableUSBModule* rootNode;
|
||||
uint8_t totalEP;
|
||||
};
|
||||
}
|
||||
|
||||
// core need to define
|
||||
void* epBuffer(unsigned int n); // -> returns a pointer to the Nth element of the EP buffer structure
|
||||
|
||||
// Replacement for global singleton.
|
||||
// This function prevents static-initialization-order-fiasco
|
||||
// https://isocpp.org/wiki/faq/ctors#static-init-order-on-first-use
|
||||
arduino::PluggableUSB_& PluggableUSB();
|
||||
|
||||
#endif
|
||||
#pragma once
|
||||
#include "../../../ArduinoCore-API/api/PluggableUSB.h"
|
||||
|
||||
+1
-429
@@ -1,429 +1 @@
|
||||
/*
|
||||
Copyright (c) 2014 Arduino. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "Print.h"
|
||||
|
||||
using namespace arduino;
|
||||
|
||||
// Public Methods //////////////////////////////////////////////////////////////
|
||||
|
||||
/* default implementation: may be overridden */
|
||||
size_t Print::write(const uint8_t *buffer, size_t size)
|
||||
{
|
||||
size_t n = 0;
|
||||
while (size--) {
|
||||
if (write(*buffer++)) n++;
|
||||
else break;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::print(const __FlashStringHelper *ifsh)
|
||||
{
|
||||
#if defined(__AVR__)
|
||||
PGM_P p = reinterpret_cast<PGM_P>(ifsh);
|
||||
size_t n = 0;
|
||||
while (1) {
|
||||
unsigned char c = pgm_read_byte(p++);
|
||||
if (c == 0) break;
|
||||
if (write(c)) n++;
|
||||
else break;
|
||||
}
|
||||
return n;
|
||||
#else
|
||||
return print(reinterpret_cast<const char *>(ifsh));
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t Print::print(const String &s)
|
||||
{
|
||||
return write(s.c_str(), s.length());
|
||||
}
|
||||
|
||||
size_t Print::print(const char str[])
|
||||
{
|
||||
return write(str);
|
||||
}
|
||||
|
||||
size_t Print::print(char c)
|
||||
{
|
||||
return write(c);
|
||||
}
|
||||
|
||||
size_t Print::print(unsigned char b, int base)
|
||||
{
|
||||
return print((unsigned long) b, base);
|
||||
}
|
||||
|
||||
size_t Print::print(int n, int base)
|
||||
{
|
||||
return print((long) n, base);
|
||||
}
|
||||
|
||||
size_t Print::print(unsigned int n, int base)
|
||||
{
|
||||
return print((unsigned long) n, base);
|
||||
}
|
||||
|
||||
size_t Print::print(long n, int base)
|
||||
{
|
||||
if (base == 0) {
|
||||
return write(n);
|
||||
} else if (base == 10) {
|
||||
if (n < 0) {
|
||||
int t = print('-');
|
||||
n = -n;
|
||||
return printNumber(n, 10) + t;
|
||||
}
|
||||
return printNumber(n, 10);
|
||||
} else {
|
||||
return printNumber(n, base);
|
||||
}
|
||||
}
|
||||
|
||||
size_t Print::print(unsigned long n, int base)
|
||||
{
|
||||
if (base == 0) return write(n);
|
||||
else return printNumber(n, base);
|
||||
}
|
||||
|
||||
size_t Print::print(long long n, int base)
|
||||
{
|
||||
if (base == 0) {
|
||||
return write(n);
|
||||
} else if (base == 10) {
|
||||
if (n < 0) {
|
||||
int t = print('-');
|
||||
n = -n;
|
||||
return printULLNumber(n, 10) + t;
|
||||
}
|
||||
return printULLNumber(n, 10);
|
||||
} else {
|
||||
return printULLNumber(n, base);
|
||||
}
|
||||
}
|
||||
|
||||
size_t Print::print(unsigned long long n, int base)
|
||||
{
|
||||
if (base == 0) return write(n);
|
||||
else return printULLNumber(n, base);
|
||||
}
|
||||
|
||||
size_t Print::print(double n, int digits)
|
||||
{
|
||||
return printFloat(n, digits);
|
||||
}
|
||||
|
||||
size_t Print::println(const __FlashStringHelper *ifsh)
|
||||
{
|
||||
size_t n = print(ifsh);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::print(const Printable& x)
|
||||
{
|
||||
return x.printTo(*this);
|
||||
}
|
||||
|
||||
size_t Print::println(void)
|
||||
{
|
||||
return write("\r\n");
|
||||
}
|
||||
|
||||
size_t Print::println(const String &s)
|
||||
{
|
||||
size_t n = print(s);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(const char c[])
|
||||
{
|
||||
size_t n = print(c);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(char c)
|
||||
{
|
||||
size_t n = print(c);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(unsigned char b, int base)
|
||||
{
|
||||
size_t n = print(b, base);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(int num, int base)
|
||||
{
|
||||
size_t n = print(num, base);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(unsigned int num, int base)
|
||||
{
|
||||
size_t n = print(num, base);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(long num, int base)
|
||||
{
|
||||
size_t n = print(num, base);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(unsigned long num, int base)
|
||||
{
|
||||
size_t n = print(num, base);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(long long num, int base)
|
||||
{
|
||||
size_t n = print(num, base);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(unsigned long long num, int base)
|
||||
{
|
||||
size_t n = print(num, base);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(double num, int digits)
|
||||
{
|
||||
size_t n = print(num, digits);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(const Printable& x)
|
||||
{
|
||||
size_t n = print(x);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::printf(const char *format, ...) {
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
char temp[64];
|
||||
char* buffer = temp;
|
||||
size_t len = vsnprintf(temp, sizeof(temp), format, arg);
|
||||
va_end(arg);
|
||||
if (len > sizeof(temp) - 1) {
|
||||
buffer = new char[len + 1];
|
||||
if (!buffer) {
|
||||
return 0;
|
||||
}
|
||||
va_start(arg, format);
|
||||
vsnprintf(buffer, len + 1, format, arg);
|
||||
va_end(arg);
|
||||
}
|
||||
len = write((const uint8_t*) buffer, len);
|
||||
if (buffer != temp) {
|
||||
delete[] buffer;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
// TODO - must be better way than cut-n-paste!
|
||||
size_t Print::printf_P(const char *format, ...) {
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
char temp[64];
|
||||
char* buffer = temp;
|
||||
size_t len = vsnprintf(temp, sizeof(temp), format, arg);
|
||||
va_end(arg);
|
||||
if (len > sizeof(temp) - 1) {
|
||||
buffer = new char[len + 1];
|
||||
if (!buffer) {
|
||||
return 0;
|
||||
}
|
||||
va_start(arg, format);
|
||||
vsnprintf(buffer, len + 1, format, arg);
|
||||
va_end(arg);
|
||||
}
|
||||
len = write((const uint8_t*) buffer, len);
|
||||
if (buffer != temp) {
|
||||
delete[] buffer;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
// Private Methods /////////////////////////////////////////////////////////////
|
||||
|
||||
size_t Print::printNumber(unsigned long n, uint8_t base)
|
||||
{
|
||||
char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte.
|
||||
char *str = &buf[sizeof(buf) - 1];
|
||||
|
||||
*str = '\0';
|
||||
|
||||
// prevent crash if called with base == 1
|
||||
if (base < 2) base = 10;
|
||||
|
||||
do {
|
||||
char c = n % base;
|
||||
n /= base;
|
||||
|
||||
*--str = c < 10 ? c + '0' : c + 'A' - 10;
|
||||
} while(n);
|
||||
|
||||
return write(str);
|
||||
}
|
||||
|
||||
// REFERENCE IMPLEMENTATION FOR ULL
|
||||
// size_t Print::printULLNumber(unsigned long long n, uint8_t base)
|
||||
// {
|
||||
// // if limited to base 10 and 16 the bufsize can be smaller
|
||||
// char buf[65];
|
||||
// char *str = &buf[64];
|
||||
|
||||
// *str = '\0';
|
||||
|
||||
// // prevent crash if called with base == 1
|
||||
// if (base < 2) base = 10;
|
||||
|
||||
// do {
|
||||
// unsigned long long t = n / base;
|
||||
// char c = n - t * base; // faster than c = n%base;
|
||||
// n = t;
|
||||
// *--str = c < 10 ? c + '0' : c + 'A' - 10;
|
||||
// } while(n);
|
||||
|
||||
// return write(str);
|
||||
// }
|
||||
|
||||
// FAST IMPLEMENTATION FOR ULL
|
||||
size_t Print::printULLNumber(unsigned long long n64, uint8_t base)
|
||||
{
|
||||
// if limited to base 10 and 16 the bufsize can be 20
|
||||
char buf[64];
|
||||
uint8_t i = 0;
|
||||
uint8_t innerLoops = 0;
|
||||
|
||||
// prevent crash if called with base == 1
|
||||
if (base < 2) base = 10;
|
||||
|
||||
// process chunks that fit in "16 bit math".
|
||||
uint16_t top = 0xFFFF / base;
|
||||
uint16_t th16 = 1;
|
||||
while (th16 < top)
|
||||
{
|
||||
th16 *= base;
|
||||
innerLoops++;
|
||||
}
|
||||
|
||||
while (n64 > th16)
|
||||
{
|
||||
// 64 bit math part
|
||||
uint64_t q = n64 / th16;
|
||||
uint16_t r = n64 - q*th16;
|
||||
n64 = q;
|
||||
|
||||
// 16 bit math loop to do remainder. (note buffer is filled reverse)
|
||||
for (uint8_t j=0; j < innerLoops; j++)
|
||||
{
|
||||
uint16_t qq = r/base;
|
||||
buf[i++] = r - qq*base;
|
||||
r = qq;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t n16 = n64;
|
||||
while (n16 > 0)
|
||||
{
|
||||
uint16_t qq = n16/base;
|
||||
buf[i++] = n16 - qq*base;
|
||||
n16 = qq;
|
||||
}
|
||||
|
||||
size_t bytes = i;
|
||||
for (; i > 0; i--)
|
||||
write((char) (buf[i - 1] < 10 ?
|
||||
'0' + buf[i - 1] :
|
||||
'A' + buf[i - 1] - 10));
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
size_t Print::printFloat(double number, int digits)
|
||||
{
|
||||
if (digits < 0)
|
||||
digits = 2;
|
||||
|
||||
size_t n = 0;
|
||||
|
||||
if (isnan(number)) return print("nan");
|
||||
if (isinf(number)) return print("inf");
|
||||
if (number > 4294967040.0) return print ("ovf"); // constant determined empirically
|
||||
if (number <-4294967040.0) return print ("ovf"); // constant determined empirically
|
||||
|
||||
// Handle negative numbers
|
||||
if (number < 0.0)
|
||||
{
|
||||
n += print('-');
|
||||
number = -number;
|
||||
}
|
||||
|
||||
// Round correctly so that print(1.999, 2) prints as "2.00"
|
||||
double rounding = 0.5;
|
||||
for (uint8_t i=0; i<digits; ++i)
|
||||
rounding /= 10.0;
|
||||
|
||||
number += rounding;
|
||||
|
||||
// Extract the integer part of the number and print it
|
||||
unsigned long int_part = (unsigned long)number;
|
||||
double remainder = number - (double)int_part;
|
||||
n += print(int_part);
|
||||
|
||||
// Print the decimal point, but only if there are digits beyond
|
||||
if (digits > 0) {
|
||||
n += print(".");
|
||||
}
|
||||
|
||||
// Extract digits from the remainder one at a time
|
||||
while (digits-- > 0)
|
||||
{
|
||||
remainder *= 10.0;
|
||||
unsigned int toPrint = (unsigned int)remainder;
|
||||
n += print(toPrint);
|
||||
remainder -= toPrint;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
#include "../../../ArduinoCore-API/api/Print.cpp"
|
||||
|
||||
@@ -1,100 +1,2 @@
|
||||
/*
|
||||
Copyright (c) 2016 Arduino LLC. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h> // for size_t
|
||||
|
||||
#include "String.h"
|
||||
#include "Printable.h"
|
||||
|
||||
#define DEC 10
|
||||
#define HEX 16
|
||||
#define OCT 8
|
||||
#define BIN 2
|
||||
|
||||
namespace arduino {
|
||||
|
||||
class Print
|
||||
{
|
||||
private:
|
||||
int write_error;
|
||||
size_t printNumber(unsigned long, uint8_t);
|
||||
size_t printULLNumber(unsigned long long, uint8_t);
|
||||
size_t printFloat(double, int);
|
||||
protected:
|
||||
void setWriteError(int err = 1) { write_error = err; }
|
||||
public:
|
||||
Print() : write_error(0) {}
|
||||
|
||||
int getWriteError() { return write_error; }
|
||||
void clearWriteError() { setWriteError(0); }
|
||||
|
||||
virtual size_t write(uint8_t) = 0;
|
||||
size_t write(const char *str) {
|
||||
if (str == NULL) return 0;
|
||||
return write((const uint8_t *)str, strlen(str));
|
||||
}
|
||||
virtual size_t write(const uint8_t *buffer, size_t size);
|
||||
size_t write(const char *buffer, size_t size) {
|
||||
return write((const uint8_t *)buffer, size);
|
||||
}
|
||||
|
||||
// default to zero, meaning "a single write may block"
|
||||
// should be overriden by subclasses with buffering
|
||||
virtual int availableForWrite() { return 0; }
|
||||
|
||||
size_t print(const __FlashStringHelper *);
|
||||
size_t print(const String &);
|
||||
size_t print(const char[]);
|
||||
size_t print(char);
|
||||
size_t print(unsigned char, int = DEC);
|
||||
size_t print(int, int = DEC);
|
||||
size_t print(unsigned int, int = DEC);
|
||||
size_t print(long, int = DEC);
|
||||
size_t print(unsigned long, int = DEC);
|
||||
size_t print(long long, int = DEC);
|
||||
size_t print(unsigned long long, int = DEC);
|
||||
size_t print(double, int = 2);
|
||||
size_t print(const Printable&);
|
||||
|
||||
size_t println(const __FlashStringHelper *);
|
||||
size_t println(const String &s);
|
||||
size_t println(const char[]);
|
||||
size_t println(char);
|
||||
size_t println(unsigned char, int = DEC);
|
||||
size_t println(int, int = DEC);
|
||||
size_t println(unsigned int, int = DEC);
|
||||
size_t println(long, int = DEC);
|
||||
size_t println(unsigned long, int = DEC);
|
||||
size_t println(long long, int = DEC);
|
||||
size_t println(unsigned long long, int = DEC);
|
||||
size_t println(double, int = 2);
|
||||
size_t println(const Printable&);
|
||||
size_t println(void);
|
||||
|
||||
// EFP3 - Add printf() to make life so much easier...
|
||||
size_t printf(const char *format, ...);
|
||||
size_t printf_P(const char *format, ...);
|
||||
|
||||
virtual void flush() { /* Empty implementation for backward compatibility */ }
|
||||
};
|
||||
|
||||
}
|
||||
using namespace arduino;
|
||||
#include "../../../ArduinoCore-API/api/Print.h"
|
||||
|
||||
@@ -1,39 +1,2 @@
|
||||
/*
|
||||
Copyright (c) 2016 Arduino LLC. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace arduino {
|
||||
|
||||
class Print;
|
||||
|
||||
/** The Printable class provides a way for new classes to allow themselves to be printed.
|
||||
By deriving from Printable and implementing the printTo method, it will then be possible
|
||||
for users to print out instances of this class by passing them into the usual
|
||||
Print::print and Print::println methods.
|
||||
*/
|
||||
|
||||
class Printable
|
||||
{
|
||||
public:
|
||||
virtual size_t printTo(Print& p) const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
#include "../../../ArduinoCore-API/api/Printable.h"
|
||||
|
||||
@@ -1,141 +1 @@
|
||||
/*
|
||||
Copyright (c) 2014 Arduino. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#ifndef _RING_BUFFER_
|
||||
#define _RING_BUFFER_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace arduino {
|
||||
|
||||
// Define constants and variables for buffering incoming serial data. We're
|
||||
// using a ring buffer (I think), in which head is the index of the location
|
||||
// to which to write the next incoming character and tail is the index of the
|
||||
// location from which to read.
|
||||
#define SERIAL_BUFFER_SIZE 64
|
||||
|
||||
template <int N>
|
||||
class RingBufferN
|
||||
{
|
||||
public:
|
||||
uint8_t _aucBuffer[N] ;
|
||||
volatile int _iHead ;
|
||||
volatile int _iTail ;
|
||||
volatile int _numElems;
|
||||
|
||||
public:
|
||||
RingBufferN( void ) ;
|
||||
void store_char( uint8_t c ) ;
|
||||
void clear();
|
||||
int read_char();
|
||||
int available();
|
||||
int availableForStore();
|
||||
int peek();
|
||||
bool isFull();
|
||||
|
||||
private:
|
||||
int nextIndex(int index);
|
||||
inline bool isEmpty() const { return (_numElems == 0); }
|
||||
};
|
||||
|
||||
typedef RingBufferN<SERIAL_BUFFER_SIZE> RingBuffer;
|
||||
|
||||
|
||||
template <int N>
|
||||
RingBufferN<N>::RingBufferN( void )
|
||||
{
|
||||
memset( _aucBuffer, 0, N ) ;
|
||||
clear();
|
||||
}
|
||||
|
||||
template <int N>
|
||||
void RingBufferN<N>::store_char( uint8_t c )
|
||||
{
|
||||
// if we should be storing the received character into the location
|
||||
// just before the tail (meaning that the head would advance to the
|
||||
// current location of the tail), we're about to overflow the buffer
|
||||
// and so we don't write the character or advance the head.
|
||||
if (!isFull())
|
||||
{
|
||||
_aucBuffer[_iHead] = c ;
|
||||
_iHead = nextIndex(_iHead);
|
||||
_numElems++;
|
||||
}
|
||||
}
|
||||
|
||||
template <int N>
|
||||
void RingBufferN<N>::clear()
|
||||
{
|
||||
_iHead = 0;
|
||||
_iTail = 0;
|
||||
_numElems = 0;
|
||||
}
|
||||
|
||||
template <int N>
|
||||
int RingBufferN<N>::read_char()
|
||||
{
|
||||
if (isEmpty())
|
||||
return -1;
|
||||
|
||||
uint8_t value = _aucBuffer[_iTail];
|
||||
_iTail = nextIndex(_iTail);
|
||||
_numElems--;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
template <int N>
|
||||
int RingBufferN<N>::available()
|
||||
{
|
||||
return _numElems;
|
||||
}
|
||||
|
||||
template <int N>
|
||||
int RingBufferN<N>::availableForStore()
|
||||
{
|
||||
return (N - _numElems);
|
||||
}
|
||||
|
||||
template <int N>
|
||||
int RingBufferN<N>::peek()
|
||||
{
|
||||
if (isEmpty())
|
||||
return -1;
|
||||
|
||||
return _aucBuffer[_iTail];
|
||||
}
|
||||
|
||||
template <int N>
|
||||
int RingBufferN<N>::nextIndex(int index)
|
||||
{
|
||||
return (uint32_t)(index + 1) % N;
|
||||
}
|
||||
|
||||
template <int N>
|
||||
bool RingBufferN<N>::isFull()
|
||||
{
|
||||
return (_numElems == N);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif /* _RING_BUFFER_ */
|
||||
#endif /* __cplusplus */
|
||||
#include "../../../ArduinoCore-API/api/RingBuffer.h"
|
||||
|
||||
@@ -1,31 +1,2 @@
|
||||
/*
|
||||
Server.h - Base class that provides Server
|
||||
Copyright (c) 2011 Adrian McEwen. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Print.h"
|
||||
|
||||
namespace arduino {
|
||||
|
||||
class Server : public Print {
|
||||
public:
|
||||
virtual void begin() = 0;
|
||||
};
|
||||
|
||||
}
|
||||
#include "../../../ArduinoCore-API/api/Server.h"
|
||||
|
||||
+1
-321
@@ -1,321 +1 @@
|
||||
/*
|
||||
Stream.cpp - adds parsing methods to Stream class
|
||||
Copyright (c) 2008 David A. Mellis. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Created July 2011
|
||||
parsing functions based on TextFinder library by Michael Margolis
|
||||
|
||||
findMulti/findUntil routines written by Jim Leonard/Xuth
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "Stream.h"
|
||||
|
||||
#define PARSE_TIMEOUT 1000 // default number of milli-seconds to wait
|
||||
|
||||
using namespace arduino;
|
||||
|
||||
// private method to read stream with timeout
|
||||
int Stream::timedRead()
|
||||
{
|
||||
int c;
|
||||
_startMillis = millis();
|
||||
do {
|
||||
c = read();
|
||||
if (c >= 0) return c;
|
||||
} while(millis() - _startMillis < _timeout);
|
||||
return -1; // -1 indicates timeout
|
||||
}
|
||||
|
||||
// private method to peek stream with timeout
|
||||
int Stream::timedPeek()
|
||||
{
|
||||
int c;
|
||||
_startMillis = millis();
|
||||
do {
|
||||
c = peek();
|
||||
if (c >= 0) return c;
|
||||
} while(millis() - _startMillis < _timeout);
|
||||
return -1; // -1 indicates timeout
|
||||
}
|
||||
|
||||
// returns peek of the next digit in the stream or -1 if timeout
|
||||
// discards non-numeric characters
|
||||
int Stream::peekNextDigit(LookaheadMode lookahead, bool detectDecimal)
|
||||
{
|
||||
int c;
|
||||
while (1) {
|
||||
c = timedPeek();
|
||||
|
||||
if( c < 0 ||
|
||||
c == '-' ||
|
||||
(c >= '0' && c <= '9') ||
|
||||
(detectDecimal && c == '.')) return c;
|
||||
|
||||
switch( lookahead ){
|
||||
case SKIP_NONE: return -1; // Fail code.
|
||||
case SKIP_WHITESPACE:
|
||||
switch( c ){
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
case '\n': break;
|
||||
default: return -1; // Fail code.
|
||||
}
|
||||
case SKIP_ALL:
|
||||
break;
|
||||
}
|
||||
read(); // discard non-numeric
|
||||
}
|
||||
}
|
||||
|
||||
// Public Methods
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
void Stream::setTimeout(unsigned long timeout) // sets the maximum number of milliseconds to wait
|
||||
{
|
||||
_timeout = timeout;
|
||||
}
|
||||
|
||||
// find returns true if the target string is found
|
||||
bool Stream::find(const char *target)
|
||||
{
|
||||
return findUntil(target, strlen(target), NULL, 0);
|
||||
}
|
||||
|
||||
// reads data from the stream until the target string of given length is found
|
||||
// returns true if target string is found, false if timed out
|
||||
bool Stream::find(const char *target, size_t length)
|
||||
{
|
||||
return findUntil(target, length, NULL, 0);
|
||||
}
|
||||
|
||||
// as find but search ends if the terminator string is found
|
||||
bool Stream::findUntil(const char *target, const char *terminator)
|
||||
{
|
||||
return findUntil(target, strlen(target), terminator, strlen(terminator));
|
||||
}
|
||||
|
||||
// reads data from the stream until the target string of the given length is found
|
||||
// search terminated if the terminator string is found
|
||||
// returns true if target string is found, false if terminated or timed out
|
||||
bool Stream::findUntil(const char *target, size_t targetLen, const char *terminator, size_t termLen)
|
||||
{
|
||||
if (terminator == NULL) {
|
||||
MultiTarget t[1] = {{target, targetLen, 0}};
|
||||
return findMulti(t, 1) == 0;
|
||||
} else {
|
||||
MultiTarget t[2] = {{target, targetLen, 0}, {terminator, termLen, 0}};
|
||||
return findMulti(t, 2) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
// returns the first valid (long) integer value from the current position.
|
||||
// lookahead determines how parseInt looks ahead in the stream.
|
||||
// See LookaheadMode enumeration at the top of the file.
|
||||
// Lookahead is terminated by the first character that is not a valid part of an integer.
|
||||
// Once parsing commences, 'ignore' will be skipped in the stream.
|
||||
long Stream::parseInt(LookaheadMode lookahead, char ignore)
|
||||
{
|
||||
bool isNegative = false;
|
||||
long value = 0;
|
||||
int c;
|
||||
|
||||
c = peekNextDigit(lookahead, false);
|
||||
// ignore non numeric leading characters
|
||||
if(c < 0)
|
||||
return 0; // zero returned if timeout
|
||||
|
||||
do{
|
||||
if((char)c == ignore)
|
||||
; // ignore this character
|
||||
else if(c == '-')
|
||||
isNegative = true;
|
||||
else if(c >= '0' && c <= '9') // is c a digit?
|
||||
value = value * 10 + c - '0';
|
||||
read(); // consume the character we got with peek
|
||||
c = timedPeek();
|
||||
}
|
||||
while( (c >= '0' && c <= '9') || (char)c == ignore );
|
||||
|
||||
if(isNegative)
|
||||
value = -value;
|
||||
return value;
|
||||
}
|
||||
|
||||
// as parseInt but returns a floating point value
|
||||
float Stream::parseFloat(LookaheadMode lookahead, char ignore)
|
||||
{
|
||||
bool isNegative = false;
|
||||
bool isFraction = false;
|
||||
double value = 0.0;
|
||||
int c;
|
||||
double fraction = 1.0;
|
||||
|
||||
c = peekNextDigit(lookahead, true);
|
||||
// ignore non numeric leading characters
|
||||
if(c < 0)
|
||||
return 0; // zero returned if timeout
|
||||
|
||||
do{
|
||||
if((char)c == ignore)
|
||||
; // ignore
|
||||
else if(c == '-')
|
||||
isNegative = true;
|
||||
else if (c == '.')
|
||||
isFraction = true;
|
||||
else if(c >= '0' && c <= '9') { // is c a digit?
|
||||
if(isFraction) {
|
||||
fraction *= 0.1;
|
||||
value = value + fraction * (c - '0');
|
||||
} else {
|
||||
value = value * 10 + c - '0';
|
||||
}
|
||||
}
|
||||
read(); // consume the character we got with peek
|
||||
c = timedPeek();
|
||||
}
|
||||
while( (c >= '0' && c <= '9') || (c == '.' && !isFraction) || (char)c == ignore );
|
||||
|
||||
if(isNegative)
|
||||
value = -value;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
// read characters from stream into buffer
|
||||
// terminates if length characters have been read, or timeout (see setTimeout)
|
||||
// returns the number of characters placed in the buffer
|
||||
// the buffer is NOT null terminated.
|
||||
//
|
||||
size_t Stream::readBytes(char *buffer, size_t length)
|
||||
{
|
||||
size_t count = 0;
|
||||
while (count < length) {
|
||||
int c = timedRead();
|
||||
if (c < 0) break;
|
||||
*buffer++ = (char)c;
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
// as readBytes with terminator character
|
||||
// terminates if length characters have been read, timeout, or if the terminator character detected
|
||||
// returns the number of characters placed in the buffer (0 means no valid data found)
|
||||
|
||||
size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length)
|
||||
{
|
||||
size_t index = 0;
|
||||
while (index < length) {
|
||||
int c = timedRead();
|
||||
if (c < 0 || (char)c == terminator) break;
|
||||
*buffer++ = (char)c;
|
||||
index++;
|
||||
}
|
||||
return index; // return number of characters, not including null terminator
|
||||
}
|
||||
|
||||
String Stream::readString()
|
||||
{
|
||||
String ret;
|
||||
int c = timedRead();
|
||||
while (c >= 0)
|
||||
{
|
||||
ret += (char)c;
|
||||
c = timedRead();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
String Stream::readStringUntil(char terminator)
|
||||
{
|
||||
String ret;
|
||||
int c = timedRead();
|
||||
while (c >= 0 && (char)c != terminator)
|
||||
{
|
||||
ret += (char)c;
|
||||
c = timedRead();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Stream::findMulti( struct Stream::MultiTarget *targets, int tCount) {
|
||||
// any zero length target string automatically matches and would make
|
||||
// a mess of the rest of the algorithm.
|
||||
for (struct MultiTarget *t = targets; t < targets+tCount; ++t) {
|
||||
if (t->len <= 0)
|
||||
return t - targets;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
int c = timedRead();
|
||||
if (c < 0)
|
||||
return -1;
|
||||
|
||||
for (struct MultiTarget *t = targets; t < targets+tCount; ++t) {
|
||||
// the simple case is if we match, deal with that first.
|
||||
if ((char)c == t->str[t->index]) {
|
||||
if (++t->index == t->len)
|
||||
return t - targets;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
// if not we need to walk back and see if we could have matched further
|
||||
// down the stream (ie '1112' doesn't match the first position in '11112'
|
||||
// but it will match the second position so we can't just reset the current
|
||||
// index to 0 when we find a mismatch.
|
||||
if (t->index == 0)
|
||||
continue;
|
||||
|
||||
int origIndex = t->index;
|
||||
do {
|
||||
--t->index;
|
||||
// first check if current char works against the new current index
|
||||
if ((char)c != t->str[t->index])
|
||||
continue;
|
||||
|
||||
// if it's the only char then we're good, nothing more to check
|
||||
if (t->index == 0) {
|
||||
t->index++;
|
||||
break;
|
||||
}
|
||||
|
||||
// otherwise we need to check the rest of the found string
|
||||
int diff = origIndex - t->index;
|
||||
size_t i;
|
||||
for (i = 0; i < t->index; ++i) {
|
||||
if (t->str[i] != t->str[i + diff])
|
||||
break;
|
||||
}
|
||||
|
||||
// if we successfully got through the previous loop then our current
|
||||
// index is good.
|
||||
if (i == t->index) {
|
||||
t->index++;
|
||||
break;
|
||||
}
|
||||
|
||||
// otherwise we just try the next index
|
||||
} while (t->index);
|
||||
}
|
||||
}
|
||||
// unreachable
|
||||
return -1;
|
||||
}
|
||||
#include "../../../ArduinoCore-API/api/Stream.cpp"
|
||||
|
||||
+1
-130
@@ -1,131 +1,2 @@
|
||||
/*
|
||||
Stream.h - base class for character-based streams.
|
||||
Copyright (c) 2010 David A. Mellis. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
parsing functions based on TextFinder library by Michael Margolis
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "Print.h"
|
||||
|
||||
// compatability macros for testing
|
||||
/*
|
||||
#define getInt() parseInt()
|
||||
#define getInt(ignore) parseInt(ignore)
|
||||
#define getFloat() parseFloat()
|
||||
#define getFloat(ignore) parseFloat(ignore)
|
||||
#define getString( pre_string, post_string, buffer, length)
|
||||
readBytesBetween( pre_string, terminator, buffer, length)
|
||||
*/
|
||||
|
||||
namespace arduino {
|
||||
|
||||
// This enumeration provides the lookahead options for parseInt(), parseFloat()
|
||||
// The rules set out here are used until either the first valid character is found
|
||||
// or a time out occurs due to lack of input.
|
||||
enum LookaheadMode{
|
||||
SKIP_ALL, // All invalid characters are ignored.
|
||||
SKIP_NONE, // Nothing is skipped, and the stream is not touched unless the first waiting character is valid.
|
||||
SKIP_WHITESPACE // Only tabs, spaces, line feeds & carriage returns are skipped.
|
||||
};
|
||||
|
||||
#define NO_IGNORE_CHAR '\x01' // a char not found in a valid ASCII numeric field
|
||||
|
||||
class Stream : public Print
|
||||
{
|
||||
protected:
|
||||
unsigned long _timeout; // number of milliseconds to wait for the next char before aborting timed read
|
||||
unsigned long _startMillis; // used for timeout measurement
|
||||
int timedRead(); // private method to read stream with timeout
|
||||
int timedPeek(); // private method to peek stream with timeout
|
||||
int peekNextDigit(LookaheadMode lookahead, bool detectDecimal); // returns the next numeric digit in the stream or -1 if timeout
|
||||
|
||||
public:
|
||||
virtual int available() = 0;
|
||||
virtual int read() = 0;
|
||||
virtual int peek() = 0;
|
||||
|
||||
Stream() {_timeout=1000;}
|
||||
|
||||
// parsing methods
|
||||
|
||||
void setTimeout(unsigned long timeout); // sets maximum milliseconds to wait for stream data, default is 1 second
|
||||
unsigned long getTimeout(void) { return _timeout; }
|
||||
|
||||
bool find(const char *target); // reads data from the stream until the target string is found
|
||||
bool find(const uint8_t *target) { return find ((const char *)target); }
|
||||
// returns true if target string is found, false if timed out (see setTimeout)
|
||||
|
||||
bool find(const char *target, size_t length); // reads data from the stream until the target string of given length is found
|
||||
bool find(const uint8_t *target, size_t length) { return find ((const char *)target, length); }
|
||||
// returns true if target string is found, false if timed out
|
||||
|
||||
bool find(char target) { return find (&target, 1); }
|
||||
|
||||
bool findUntil(const char *target, const char *terminator); // as find but search ends if the terminator string is found
|
||||
bool findUntil(const uint8_t *target, const char *terminator) { return findUntil((const char *)target, terminator); }
|
||||
|
||||
bool findUntil(const char *target, size_t targetLen, const char *terminate, size_t termLen); // as above but search ends if the terminate string is found
|
||||
bool findUntil(const uint8_t *target, size_t targetLen, const char *terminate, size_t termLen) {return findUntil((const char *)target, targetLen, terminate, termLen); }
|
||||
|
||||
long parseInt(LookaheadMode lookahead = SKIP_ALL, char ignore = NO_IGNORE_CHAR);
|
||||
// returns the first valid (long) integer value from the current position.
|
||||
// lookahead determines how parseInt looks ahead in the stream.
|
||||
// See LookaheadMode enumeration at the top of the file.
|
||||
// Lookahead is terminated by the first character that is not a valid part of an integer.
|
||||
// Once parsing commences, 'ignore' will be skipped in the stream.
|
||||
|
||||
float parseFloat(LookaheadMode lookahead = SKIP_ALL, char ignore = NO_IGNORE_CHAR);
|
||||
// float version of parseInt
|
||||
|
||||
size_t readBytes( char *buffer, size_t length); // read chars from stream into buffer
|
||||
size_t readBytes( uint8_t *buffer, size_t length) { return readBytes((char *)buffer, length); }
|
||||
// terminates if length characters have been read or timeout (see setTimeout)
|
||||
// returns the number of characters placed in the buffer (0 means no valid data found)
|
||||
|
||||
size_t readBytesUntil( char terminator, char *buffer, size_t length); // as readBytes with terminator character
|
||||
size_t readBytesUntil( char terminator, uint8_t *buffer, size_t length) { return readBytesUntil(terminator, (char *)buffer, length); }
|
||||
// terminates if length characters have been read, timeout, or if the terminator character detected
|
||||
// returns the number of characters placed in the buffer (0 means no valid data found)
|
||||
|
||||
// Arduino String functions to be added here
|
||||
String readString();
|
||||
String readStringUntil(char terminator);
|
||||
|
||||
protected:
|
||||
long parseInt(char ignore) { return parseInt(SKIP_ALL, ignore); }
|
||||
float parseFloat(char ignore) { return parseFloat(SKIP_ALL, ignore); }
|
||||
// These overload exists for compatibility with any class that has derived
|
||||
// Stream and used parseFloat/Int with a custom ignore character. To keep
|
||||
// the public API simple, these overload remains protected.
|
||||
|
||||
struct MultiTarget {
|
||||
const char *str; // string you're searching for
|
||||
size_t len; // length of string you're searching for
|
||||
size_t index; // index used by the search routine.
|
||||
};
|
||||
|
||||
// This allows you to search for an arbitrary number of strings.
|
||||
// Returns index of the target that is found first or -1 if timeout occurs.
|
||||
int findMulti(struct MultiTarget *targets, int tCount);
|
||||
};
|
||||
|
||||
#undef NO_IGNORE_CHAR
|
||||
|
||||
}
|
||||
#include "../../../ArduinoCore-API/api/Stream.h"
|
||||
|
||||
+1
-768
@@ -1,768 +1 @@
|
||||
/*
|
||||
String library for Wiring & Arduino
|
||||
...mostly rewritten by Paul Stoffregen...
|
||||
Copyright (c) 2009-10 Hernando Barragan. All rights reserved.
|
||||
Copyright 2011, Paul Stoffregen, paul@pjrc.com
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "String.h"
|
||||
#include "Common.h"
|
||||
#include "itoa.h"
|
||||
#include "deprecated-avr-comp/avr/dtostrf.h"
|
||||
|
||||
#include <float.h>
|
||||
|
||||
namespace arduino {
|
||||
|
||||
/*********************************************/
|
||||
/* Static Member Initialisation */
|
||||
/*********************************************/
|
||||
|
||||
size_t const String::FLT_MAX_DECIMAL_PLACES;
|
||||
size_t const String::DBL_MAX_DECIMAL_PLACES;
|
||||
|
||||
/*********************************************/
|
||||
/* Constructors */
|
||||
/*********************************************/
|
||||
|
||||
String::String(const char *cstr)
|
||||
{
|
||||
init();
|
||||
if (cstr) copy(cstr, strlen(cstr));
|
||||
}
|
||||
|
||||
String::String(const char *cstr, unsigned int length)
|
||||
{
|
||||
init();
|
||||
if (cstr) copy(cstr, length);
|
||||
}
|
||||
|
||||
String::String(const String &value)
|
||||
{
|
||||
init();
|
||||
*this = value;
|
||||
}
|
||||
|
||||
String::String(const __FlashStringHelper *pstr)
|
||||
{
|
||||
init();
|
||||
*this = pstr;
|
||||
}
|
||||
|
||||
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
String::String(String &&rval)
|
||||
{
|
||||
init();
|
||||
move(rval);
|
||||
}
|
||||
String::String(StringSumHelper &&rval)
|
||||
{
|
||||
init();
|
||||
move(rval);
|
||||
}
|
||||
#endif
|
||||
|
||||
String::String(char c)
|
||||
{
|
||||
init();
|
||||
char buf[2];
|
||||
buf[0] = c;
|
||||
buf[1] = 0;
|
||||
*this = buf;
|
||||
}
|
||||
|
||||
String::String(unsigned char value, unsigned char base)
|
||||
{
|
||||
init();
|
||||
char buf[1 + 8 * sizeof(unsigned char)];
|
||||
utoa(value, buf, base);
|
||||
*this = buf;
|
||||
}
|
||||
|
||||
String::String(int value, unsigned char base)
|
||||
{
|
||||
init();
|
||||
char buf[2 + 8 * sizeof(int)];
|
||||
itoa(value, buf, base);
|
||||
*this = buf;
|
||||
}
|
||||
|
||||
String::String(unsigned int value, unsigned char base)
|
||||
{
|
||||
init();
|
||||
char buf[1 + 8 * sizeof(unsigned int)];
|
||||
utoa(value, buf, base);
|
||||
*this = buf;
|
||||
}
|
||||
|
||||
String::String(long value, unsigned char base)
|
||||
{
|
||||
init();
|
||||
char buf[2 + 8 * sizeof(long)];
|
||||
ltoa(value, buf, base);
|
||||
*this = buf;
|
||||
}
|
||||
|
||||
String::String(unsigned long value, unsigned char base)
|
||||
{
|
||||
init();
|
||||
char buf[1 + 8 * sizeof(unsigned long)];
|
||||
ultoa(value, buf, base);
|
||||
*this = buf;
|
||||
}
|
||||
|
||||
String::String(float value, unsigned char decimalPlaces)
|
||||
{
|
||||
static size_t const FLOAT_BUF_SIZE = FLT_MAX_10_EXP + FLT_MAX_DECIMAL_PLACES + 1 /* '-' */ + 1 /* '.' */ + 1 /* '\0' */;
|
||||
init();
|
||||
char buf[FLOAT_BUF_SIZE];
|
||||
decimalPlaces = min(decimalPlaces, FLT_MAX_DECIMAL_PLACES);
|
||||
*this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf);
|
||||
}
|
||||
|
||||
String::String(double value, unsigned char decimalPlaces)
|
||||
{
|
||||
static size_t const DOUBLE_BUF_SIZE = DBL_MAX_10_EXP + DBL_MAX_DECIMAL_PLACES + 1 /* '-' */ + 1 /* '.' */ + 1 /* '\0' */;
|
||||
init();
|
||||
char buf[DOUBLE_BUF_SIZE];
|
||||
decimalPlaces = min(decimalPlaces, DBL_MAX_DECIMAL_PLACES);
|
||||
*this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf);
|
||||
}
|
||||
|
||||
String::~String()
|
||||
{
|
||||
if (buffer) free(buffer);
|
||||
}
|
||||
|
||||
/*********************************************/
|
||||
/* Memory Management */
|
||||
/*********************************************/
|
||||
|
||||
inline void String::init(void)
|
||||
{
|
||||
buffer = NULL;
|
||||
capacity = 0;
|
||||
len = 0;
|
||||
}
|
||||
|
||||
void String::invalidate(void)
|
||||
{
|
||||
if (buffer) free(buffer);
|
||||
buffer = NULL;
|
||||
capacity = len = 0;
|
||||
}
|
||||
|
||||
unsigned char String::reserve(unsigned int size)
|
||||
{
|
||||
if (buffer && capacity >= size) return 1;
|
||||
if (changeBuffer(size)) {
|
||||
if (len == 0) buffer[0] = 0;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned char String::changeBuffer(unsigned int maxStrLen)
|
||||
{
|
||||
char *newbuffer = (char *)realloc(buffer, maxStrLen + 1);
|
||||
if (newbuffer) {
|
||||
buffer = newbuffer;
|
||||
capacity = maxStrLen;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************/
|
||||
/* Copy and Move */
|
||||
/*********************************************/
|
||||
|
||||
String & String::copy(const char *cstr, unsigned int length)
|
||||
{
|
||||
if (!reserve(length)) {
|
||||
invalidate();
|
||||
return *this;
|
||||
}
|
||||
len = length;
|
||||
memcpy(buffer, cstr, length);
|
||||
buffer[len] = '\0';
|
||||
return *this;
|
||||
}
|
||||
|
||||
String & String::copy(const __FlashStringHelper *pstr, unsigned int length)
|
||||
{
|
||||
if (!reserve(length)) {
|
||||
invalidate();
|
||||
return *this;
|
||||
}
|
||||
len = length;
|
||||
strcpy_P(buffer, (PGM_P)pstr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
void String::move(String &rhs)
|
||||
{
|
||||
if (buffer) {
|
||||
if (rhs && capacity >= rhs.len) {
|
||||
memcpy(buffer, rhs.buffer, rhs.len);
|
||||
len = rhs.len;
|
||||
buffer[len] = '\0';
|
||||
rhs.len = 0;
|
||||
return;
|
||||
} else {
|
||||
free(buffer);
|
||||
}
|
||||
}
|
||||
buffer = rhs.buffer;
|
||||
capacity = rhs.capacity;
|
||||
len = rhs.len;
|
||||
rhs.buffer = NULL;
|
||||
rhs.capacity = 0;
|
||||
rhs.len = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
String & String::operator = (const String &rhs)
|
||||
{
|
||||
if (this == &rhs) return *this;
|
||||
|
||||
if (rhs.buffer) copy(rhs.buffer, rhs.len);
|
||||
else invalidate();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
String & String::operator = (String &&rval)
|
||||
{
|
||||
if (this != &rval) move(rval);
|
||||
return *this;
|
||||
}
|
||||
|
||||
String & String::operator = (StringSumHelper &&rval)
|
||||
{
|
||||
if (this != &rval) move(rval);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
String & String::operator = (const char *cstr)
|
||||
{
|
||||
if (cstr) copy(cstr, strlen(cstr));
|
||||
else invalidate();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
String & String::operator = (const __FlashStringHelper *pstr)
|
||||
{
|
||||
if (pstr) copy(pstr, strlen_P((PGM_P)pstr));
|
||||
else invalidate();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*********************************************/
|
||||
/* concat */
|
||||
/*********************************************/
|
||||
|
||||
unsigned char String::concat(const String &s)
|
||||
{
|
||||
return concat(s.buffer, s.len);
|
||||
}
|
||||
|
||||
unsigned char String::concat(const char *cstr, unsigned int length)
|
||||
{
|
||||
unsigned int newlen = len + length;
|
||||
if (!cstr) return 0;
|
||||
if (length == 0) return 1;
|
||||
if (!reserve(newlen)) return 0;
|
||||
memcpy(buffer + len, cstr, length);
|
||||
len = newlen;
|
||||
buffer[len] = '\0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned char String::concat(const char *cstr)
|
||||
{
|
||||
if (!cstr) return 0;
|
||||
return concat(cstr, strlen(cstr));
|
||||
}
|
||||
|
||||
unsigned char String::concat(char c)
|
||||
{
|
||||
return concat(&c, 1);
|
||||
}
|
||||
|
||||
unsigned char String::concat(unsigned char num)
|
||||
{
|
||||
char buf[1 + 3 * sizeof(unsigned char)];
|
||||
itoa(num, buf, 10);
|
||||
return concat(buf);
|
||||
}
|
||||
|
||||
unsigned char String::concat(int num)
|
||||
{
|
||||
char buf[2 + 3 * sizeof(int)];
|
||||
itoa(num, buf, 10);
|
||||
return concat(buf);
|
||||
}
|
||||
|
||||
unsigned char String::concat(unsigned int num)
|
||||
{
|
||||
char buf[1 + 3 * sizeof(unsigned int)];
|
||||
utoa(num, buf, 10);
|
||||
return concat(buf);
|
||||
}
|
||||
|
||||
unsigned char String::concat(long num)
|
||||
{
|
||||
char buf[2 + 3 * sizeof(long)];
|
||||
ltoa(num, buf, 10);
|
||||
return concat(buf);
|
||||
}
|
||||
|
||||
unsigned char String::concat(unsigned long num)
|
||||
{
|
||||
char buf[1 + 3 * sizeof(unsigned long)];
|
||||
ultoa(num, buf, 10);
|
||||
return concat(buf);
|
||||
}
|
||||
|
||||
unsigned char String::concat(float num)
|
||||
{
|
||||
char buf[20];
|
||||
char* string = dtostrf(num, 4, 2, buf);
|
||||
return concat(string);
|
||||
}
|
||||
|
||||
unsigned char String::concat(double num)
|
||||
{
|
||||
char buf[20];
|
||||
char* string = dtostrf(num, 4, 2, buf);
|
||||
return concat(string);
|
||||
}
|
||||
|
||||
unsigned char String::concat(const __FlashStringHelper * str)
|
||||
{
|
||||
if (!str) return 0;
|
||||
int length = strlen_P((const char *) str);
|
||||
if (length == 0) return 1;
|
||||
unsigned int newlen = len + length;
|
||||
if (!reserve(newlen)) return 0;
|
||||
strcpy_P(buffer + len, (const char *) str);
|
||||
len = newlen;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*********************************************/
|
||||
/* Concatenate */
|
||||
/*********************************************/
|
||||
|
||||
StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs)
|
||||
{
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
if (!a.concat(rhs.buffer, rhs.len)) a.invalidate();
|
||||
return a;
|
||||
}
|
||||
|
||||
StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr)
|
||||
{
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
if (!cstr || !a.concat(cstr)) a.invalidate();
|
||||
return a;
|
||||
}
|
||||
|
||||
StringSumHelper & operator + (const StringSumHelper &lhs, char c)
|
||||
{
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
if (!a.concat(c)) a.invalidate();
|
||||
return a;
|
||||
}
|
||||
|
||||
StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char num)
|
||||
{
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
if (!a.concat(num)) a.invalidate();
|
||||
return a;
|
||||
}
|
||||
|
||||
StringSumHelper & operator + (const StringSumHelper &lhs, int num)
|
||||
{
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
if (!a.concat(num)) a.invalidate();
|
||||
return a;
|
||||
}
|
||||
|
||||
StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num)
|
||||
{
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
if (!a.concat(num)) a.invalidate();
|
||||
return a;
|
||||
}
|
||||
|
||||
StringSumHelper & operator + (const StringSumHelper &lhs, long num)
|
||||
{
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
if (!a.concat(num)) a.invalidate();
|
||||
return a;
|
||||
}
|
||||
|
||||
StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num)
|
||||
{
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
if (!a.concat(num)) a.invalidate();
|
||||
return a;
|
||||
}
|
||||
|
||||
StringSumHelper & operator + (const StringSumHelper &lhs, float num)
|
||||
{
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
if (!a.concat(num)) a.invalidate();
|
||||
return a;
|
||||
}
|
||||
|
||||
StringSumHelper & operator + (const StringSumHelper &lhs, double num)
|
||||
{
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
if (!a.concat(num)) a.invalidate();
|
||||
return a;
|
||||
}
|
||||
|
||||
StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *rhs)
|
||||
{
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
if (!a.concat(rhs)) a.invalidate();
|
||||
return a;
|
||||
}
|
||||
|
||||
/*********************************************/
|
||||
/* Comparison */
|
||||
/*********************************************/
|
||||
|
||||
int String::compareTo(const String &s) const
|
||||
{
|
||||
if (!buffer || !s.buffer) {
|
||||
if (s.buffer && s.len > 0) return 0 - *(unsigned char *)s.buffer;
|
||||
if (buffer && len > 0) return *(unsigned char *)buffer;
|
||||
return 0;
|
||||
}
|
||||
return strcmp(buffer, s.buffer);
|
||||
}
|
||||
|
||||
int String::compareTo(const char *cstr) const
|
||||
{
|
||||
if (!buffer || !cstr) {
|
||||
if (cstr && *cstr) return 0 - *(unsigned char *)cstr;
|
||||
if (buffer && len > 0) return *(unsigned char *)buffer;
|
||||
return 0;
|
||||
}
|
||||
return strcmp(buffer, cstr);
|
||||
}
|
||||
|
||||
unsigned char String::equals(const String &s2) const
|
||||
{
|
||||
return (len == s2.len && compareTo(s2) == 0);
|
||||
}
|
||||
|
||||
unsigned char String::equals(const char *cstr) const
|
||||
{
|
||||
if (len == 0) return (cstr == NULL || *cstr == 0);
|
||||
if (cstr == NULL) return buffer[0] == 0;
|
||||
return strcmp(buffer, cstr) == 0;
|
||||
}
|
||||
|
||||
unsigned char String::equalsIgnoreCase( const String &s2 ) const
|
||||
{
|
||||
if (this == &s2) return 1;
|
||||
if (len != s2.len) return 0;
|
||||
if (len == 0) return 1;
|
||||
const char *p1 = buffer;
|
||||
const char *p2 = s2.buffer;
|
||||
while (*p1) {
|
||||
if (tolower(*p1++) != tolower(*p2++)) return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned char String::startsWith( const String &s2 ) const
|
||||
{
|
||||
if (len < s2.len) return 0;
|
||||
return startsWith(s2, 0);
|
||||
}
|
||||
|
||||
unsigned char String::startsWith( const String &s2, unsigned int offset ) const
|
||||
{
|
||||
if (offset > len - s2.len || !buffer || !s2.buffer) return 0;
|
||||
return strncmp( &buffer[offset], s2.buffer, s2.len ) == 0;
|
||||
}
|
||||
|
||||
unsigned char String::endsWith( const String &s2 ) const
|
||||
{
|
||||
if ( len < s2.len || !buffer || !s2.buffer) return 0;
|
||||
return strcmp(&buffer[len - s2.len], s2.buffer) == 0;
|
||||
}
|
||||
|
||||
/*********************************************/
|
||||
/* Character Access */
|
||||
/*********************************************/
|
||||
|
||||
char String::charAt(unsigned int loc) const
|
||||
{
|
||||
return operator[](loc);
|
||||
}
|
||||
|
||||
void String::setCharAt(unsigned int loc, char c)
|
||||
{
|
||||
if (loc < len) buffer[loc] = c;
|
||||
}
|
||||
|
||||
char & String::operator[](unsigned int index)
|
||||
{
|
||||
static char dummy_writable_char;
|
||||
if (index >= len || !buffer) {
|
||||
dummy_writable_char = 0;
|
||||
return dummy_writable_char;
|
||||
}
|
||||
return buffer[index];
|
||||
}
|
||||
|
||||
char String::operator[]( unsigned int index ) const
|
||||
{
|
||||
if (index >= len || !buffer) return 0;
|
||||
return buffer[index];
|
||||
}
|
||||
|
||||
void String::getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index) const
|
||||
{
|
||||
if (!bufsize || !buf) return;
|
||||
if (index >= len) {
|
||||
buf[0] = 0;
|
||||
return;
|
||||
}
|
||||
unsigned int n = bufsize - 1;
|
||||
if (n > len - index) n = len - index;
|
||||
strncpy((char *)buf, buffer + index, n);
|
||||
buf[n] = 0;
|
||||
}
|
||||
|
||||
/*********************************************/
|
||||
/* Search */
|
||||
/*********************************************/
|
||||
|
||||
int String::indexOf(char c) const
|
||||
{
|
||||
return indexOf(c, 0);
|
||||
}
|
||||
|
||||
int String::indexOf( char ch, unsigned int fromIndex ) const
|
||||
{
|
||||
if (fromIndex >= len) return -1;
|
||||
const char* temp = strchr(buffer + fromIndex, ch);
|
||||
if (temp == NULL) return -1;
|
||||
return temp - buffer;
|
||||
}
|
||||
|
||||
int String::indexOf(const String &s2) const
|
||||
{
|
||||
return indexOf(s2, 0);
|
||||
}
|
||||
|
||||
int String::indexOf(const String &s2, unsigned int fromIndex) const
|
||||
{
|
||||
if (fromIndex >= len) return -1;
|
||||
const char *found = strstr(buffer + fromIndex, s2.buffer);
|
||||
if (found == NULL) return -1;
|
||||
return found - buffer;
|
||||
}
|
||||
|
||||
int String::lastIndexOf( char theChar ) const
|
||||
{
|
||||
return lastIndexOf(theChar, len - 1);
|
||||
}
|
||||
|
||||
int String::lastIndexOf(char ch, unsigned int fromIndex) const
|
||||
{
|
||||
if (fromIndex >= len) return -1;
|
||||
char tempchar = buffer[fromIndex + 1];
|
||||
buffer[fromIndex + 1] = '\0';
|
||||
char* temp = strrchr( buffer, ch );
|
||||
buffer[fromIndex + 1] = tempchar;
|
||||
if (temp == NULL) return -1;
|
||||
return temp - buffer;
|
||||
}
|
||||
|
||||
int String::lastIndexOf(const String &s2) const
|
||||
{
|
||||
return lastIndexOf(s2, len - s2.len);
|
||||
}
|
||||
|
||||
int String::lastIndexOf(const String &s2, unsigned int fromIndex) const
|
||||
{
|
||||
if (s2.len == 0 || len == 0 || s2.len > len) return -1;
|
||||
if (fromIndex >= len) fromIndex = len - 1;
|
||||
int found = -1;
|
||||
for (char *p = buffer; p <= buffer + fromIndex; p++) {
|
||||
p = strstr(p, s2.buffer);
|
||||
if (!p) break;
|
||||
if ((unsigned int)(p - buffer) <= fromIndex) found = p - buffer;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
String String::substring(unsigned int left, unsigned int right) const
|
||||
{
|
||||
if (left > right) {
|
||||
unsigned int temp = right;
|
||||
right = left;
|
||||
left = temp;
|
||||
}
|
||||
String out;
|
||||
if (left >= len) return out;
|
||||
if (right > len) right = len;
|
||||
out.copy(buffer + left, right - left);
|
||||
return out;
|
||||
}
|
||||
|
||||
/*********************************************/
|
||||
/* Modification */
|
||||
/*********************************************/
|
||||
|
||||
void String::replace(char find, char replace)
|
||||
{
|
||||
if (!buffer) return;
|
||||
for (char *p = buffer; *p; p++) {
|
||||
if (*p == find) *p = replace;
|
||||
}
|
||||
}
|
||||
|
||||
void String::replace(const String& find, const String& replace)
|
||||
{
|
||||
if (len == 0 || find.len == 0) return;
|
||||
int diff = replace.len - find.len;
|
||||
char *readFrom = buffer;
|
||||
char *foundAt;
|
||||
if (diff == 0) {
|
||||
while ((foundAt = strstr(readFrom, find.buffer)) != NULL) {
|
||||
memcpy(foundAt, replace.buffer, replace.len);
|
||||
readFrom = foundAt + replace.len;
|
||||
}
|
||||
} else if (diff < 0) {
|
||||
unsigned int size = len; // compute size needed for result
|
||||
while ((foundAt = strstr(readFrom, find.buffer)) != NULL) {
|
||||
readFrom = foundAt + find.len;
|
||||
diff = 0 - diff;
|
||||
size -= diff;
|
||||
}
|
||||
if (size == len) return;
|
||||
int index = len - 1;
|
||||
while (index >= 0 && (index = lastIndexOf(find, index)) >= 0) {
|
||||
readFrom = buffer + index + find.len;
|
||||
memmove(readFrom - diff, readFrom, len - (readFrom - buffer));
|
||||
len -= diff;
|
||||
buffer[len] = 0;
|
||||
memcpy(buffer + index, replace.buffer, replace.len);
|
||||
index--;
|
||||
}
|
||||
} else {
|
||||
unsigned int size = len; // compute size needed for result
|
||||
while ((foundAt = strstr(readFrom, find.buffer)) != NULL) {
|
||||
readFrom = foundAt + find.len;
|
||||
size += diff;
|
||||
}
|
||||
if (size == len) return;
|
||||
if (size > capacity && !changeBuffer(size)) return; // XXX: tell user!
|
||||
int index = len - 1;
|
||||
while (index >= 0 && (index = lastIndexOf(find, index)) >= 0) {
|
||||
readFrom = buffer + index + find.len;
|
||||
memmove(readFrom + diff, readFrom, len - (readFrom - buffer));
|
||||
len += diff;
|
||||
buffer[len] = 0;
|
||||
memcpy(buffer + index, replace.buffer, replace.len);
|
||||
index--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void String::remove(unsigned int index){
|
||||
// Pass the biggest integer as the count. The remove method
|
||||
// below will take care of truncating it at the end of the
|
||||
// string.
|
||||
remove(index, (unsigned int)-1);
|
||||
}
|
||||
|
||||
void String::remove(unsigned int index, unsigned int count){
|
||||
if (index >= len) { return; }
|
||||
if (count <= 0) { return; }
|
||||
if (count > len - index) { count = len - index; }
|
||||
char *writeTo = buffer + index;
|
||||
len = len - count;
|
||||
memmove(writeTo, buffer + index + count,len - index);
|
||||
buffer[len] = 0;
|
||||
}
|
||||
|
||||
void String::toLowerCase(void)
|
||||
{
|
||||
if (!buffer) return;
|
||||
for (char *p = buffer; *p; p++) {
|
||||
*p = tolower(*p);
|
||||
}
|
||||
}
|
||||
|
||||
void String::toUpperCase(void)
|
||||
{
|
||||
if (!buffer) return;
|
||||
for (char *p = buffer; *p; p++) {
|
||||
*p = toupper(*p);
|
||||
}
|
||||
}
|
||||
|
||||
void String::trim(void)
|
||||
{
|
||||
if (!buffer || len == 0) return;
|
||||
char *begin = buffer;
|
||||
while (isspace(*begin)) begin++;
|
||||
char *end = buffer + len - 1;
|
||||
while (isspace(*end) && end >= begin) end--;
|
||||
len = end + 1 - begin;
|
||||
if (begin > buffer) memmove(buffer, begin, len);
|
||||
buffer[len] = 0;
|
||||
}
|
||||
|
||||
/*********************************************/
|
||||
/* Parsing / Conversion */
|
||||
/*********************************************/
|
||||
|
||||
long String::toInt(void) const
|
||||
{
|
||||
if (buffer) return atol(buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
float String::toFloat(void) const
|
||||
{
|
||||
return float(toDouble());
|
||||
}
|
||||
|
||||
double String::toDouble(void) const
|
||||
{
|
||||
if (buffer) return atof(buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace arduino
|
||||
#include "../../../ArduinoCore-API/api/String.cpp"
|
||||
|
||||
+2
-259
@@ -1,259 +1,2 @@
|
||||
/*
|
||||
String library for Wiring & Arduino
|
||||
...mostly rewritten by Paul Stoffregen...
|
||||
Copyright (c) 2009-10 Hernando Barragan. All right reserved.
|
||||
Copyright 2011, Paul Stoffregen, paul@pjrc.com
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#ifndef __ARDUINO_STRINGS__
|
||||
#define __ARDUINO_STRINGS__
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#if defined(__AVR__)
|
||||
#include "avr/pgmspace.h"
|
||||
#else
|
||||
#include "deprecated-avr-comp/avr/pgmspace.h"
|
||||
#endif
|
||||
|
||||
namespace arduino {
|
||||
|
||||
// When compiling programs with this class, the following gcc parameters
|
||||
// dramatically increase performance and memory (RAM) efficiency, typically
|
||||
// with little or no increase in code size.
|
||||
// -felide-constructors
|
||||
// -std=c++0x
|
||||
|
||||
class __FlashStringHelper;
|
||||
#define F(string_literal) (reinterpret_cast<const __FlashStringHelper *>(PSTR(string_literal)))
|
||||
|
||||
// An inherited class for holding the result of a concatenation. These
|
||||
// result objects are assumed to be writable by subsequent concatenations.
|
||||
class StringSumHelper;
|
||||
|
||||
// The string class
|
||||
class String
|
||||
{
|
||||
friend class StringSumHelper;
|
||||
// use a function pointer to allow for "if (s)" without the
|
||||
// complications of an operator bool(). for more information, see:
|
||||
// http://www.artima.com/cppsource/safebool.html
|
||||
typedef void (String::*StringIfHelperType)() const;
|
||||
void StringIfHelper() const {}
|
||||
|
||||
static size_t const FLT_MAX_DECIMAL_PLACES = 10;
|
||||
static size_t const DBL_MAX_DECIMAL_PLACES = FLT_MAX_DECIMAL_PLACES;
|
||||
|
||||
public:
|
||||
// constructors
|
||||
// creates a copy of the initial value.
|
||||
// if the initial value is null or invalid, or if memory allocation
|
||||
// fails, the string will be marked as invalid (i.e. "if (s)" will
|
||||
// be false).
|
||||
String(const char *cstr = "");
|
||||
String(const char *cstr, unsigned int length);
|
||||
String(const uint8_t *cstr, unsigned int length) : String((const char*)cstr, length) {}
|
||||
String(const String &str);
|
||||
String(const __FlashStringHelper *str);
|
||||
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
String(String &&rval);
|
||||
String(StringSumHelper &&rval);
|
||||
#endif
|
||||
explicit String(char c);
|
||||
explicit String(unsigned char, unsigned char base=10);
|
||||
explicit String(int, unsigned char base=10);
|
||||
explicit String(unsigned int, unsigned char base=10);
|
||||
explicit String(long, unsigned char base=10);
|
||||
explicit String(unsigned long, unsigned char base=10);
|
||||
explicit String(float, unsigned char decimalPlaces=2);
|
||||
explicit String(double, unsigned char decimalPlaces=2);
|
||||
~String(void);
|
||||
|
||||
// memory management
|
||||
// return true on success, false on failure (in which case, the string
|
||||
// is left unchanged). reserve(0), if successful, will validate an
|
||||
// invalid string (i.e., "if (s)" will be true afterwards)
|
||||
unsigned char reserve(unsigned int size);
|
||||
inline unsigned int length(void) const {return len;}
|
||||
|
||||
// creates a copy of the assigned value. if the value is null or
|
||||
// invalid, or if the memory allocation fails, the string will be
|
||||
// marked as invalid ("if (s)" will be false).
|
||||
String & operator = (const String &rhs);
|
||||
String & operator = (const char *cstr);
|
||||
String & operator = (const __FlashStringHelper *str);
|
||||
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
String & operator = (String &&rval);
|
||||
String & operator = (StringSumHelper &&rval);
|
||||
#endif
|
||||
|
||||
// concatenate (works w/ built-in types)
|
||||
|
||||
// returns true on success, false on failure (in which case, the string
|
||||
// is left unchanged). if the argument is null or invalid, the
|
||||
// concatenation is considered unsucessful.
|
||||
unsigned char concat(const String &str);
|
||||
unsigned char concat(const char *cstr);
|
||||
unsigned char concat(const char *cstr, unsigned int length);
|
||||
unsigned char concat(const uint8_t *cstr, unsigned int length) {return concat((const char*)cstr, length);}
|
||||
unsigned char concat(char c);
|
||||
unsigned char concat(unsigned char num);
|
||||
unsigned char concat(int num);
|
||||
unsigned char concat(unsigned int num);
|
||||
unsigned char concat(long num);
|
||||
unsigned char concat(unsigned long num);
|
||||
unsigned char concat(float num);
|
||||
unsigned char concat(double num);
|
||||
unsigned char concat(const __FlashStringHelper * str);
|
||||
|
||||
// if there's not enough memory for the concatenated value, the string
|
||||
// will be left unchanged (but this isn't signalled in any way)
|
||||
String & operator += (const String &rhs) {concat(rhs); return (*this);}
|
||||
String & operator += (const char *cstr) {concat(cstr); return (*this);}
|
||||
String & operator += (char c) {concat(c); return (*this);}
|
||||
String & operator += (unsigned char num) {concat(num); return (*this);}
|
||||
String & operator += (int num) {concat(num); return (*this);}
|
||||
String & operator += (unsigned int num) {concat(num); return (*this);}
|
||||
String & operator += (long num) {concat(num); return (*this);}
|
||||
String & operator += (unsigned long num) {concat(num); return (*this);}
|
||||
String & operator += (float num) {concat(num); return (*this);}
|
||||
String & operator += (double num) {concat(num); return (*this);}
|
||||
String & operator += (const __FlashStringHelper *str){concat(str); return (*this);}
|
||||
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, char c);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char num);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, int num);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, long num);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, float num);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, double num);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *rhs);
|
||||
|
||||
// comparison (only works w/ Strings and "strings")
|
||||
operator StringIfHelperType() const { return buffer ? &String::StringIfHelper : 0; }
|
||||
int compareTo(const String &s) const;
|
||||
int compareTo(const char *cstr) const;
|
||||
unsigned char equals(const String &s) const;
|
||||
unsigned char equals(const char *cstr) const;
|
||||
|
||||
friend unsigned char operator == (const String &a, const String &b) { return a.equals(b); }
|
||||
friend unsigned char operator == (const String &a, const char *b) { return a.equals(b); }
|
||||
friend unsigned char operator == (const char *a, const String &b) { return b == a; }
|
||||
friend unsigned char operator < (const String &a, const String &b) { return a.compareTo(b) < 0; }
|
||||
friend unsigned char operator < (const String &a, const char *b) { return a.compareTo(b) < 0; }
|
||||
friend unsigned char operator < (const char *a, const String &b) { return b.compareTo(a) > 0; }
|
||||
|
||||
friend unsigned char operator != (const String &a, const String &b) { return !(a == b); }
|
||||
friend unsigned char operator != (const String &a, const char *b) { return !(a == b); }
|
||||
friend unsigned char operator != (const char *a, const String &b) { return !(a == b); }
|
||||
friend unsigned char operator > (const String &a, const String &b) { return b < a; }
|
||||
friend unsigned char operator > (const String &a, const char *b) { return b < a; }
|
||||
friend unsigned char operator > (const char *a, const String &b) { return b < a; }
|
||||
friend unsigned char operator <= (const String &a, const String &b) { return !(b < a); }
|
||||
friend unsigned char operator <= (const String &a, const char *b) { return !(b < a); }
|
||||
friend unsigned char operator <= (const char *a, const String &b) { return !(b < a); }
|
||||
friend unsigned char operator >= (const String &a, const String &b) { return !(a < b); }
|
||||
friend unsigned char operator >= (const String &a, const char *b) { return !(a < b); }
|
||||
friend unsigned char operator >= (const char *a, const String &b) { return !(a < b); }
|
||||
|
||||
unsigned char equalsIgnoreCase(const String &s) const;
|
||||
unsigned char startsWith( const String &prefix) const;
|
||||
unsigned char startsWith(const String &prefix, unsigned int offset) const;
|
||||
unsigned char endsWith(const String &suffix) const;
|
||||
|
||||
// character acccess
|
||||
char charAt(unsigned int index) const;
|
||||
void setCharAt(unsigned int index, char c);
|
||||
char operator [] (unsigned int index) const;
|
||||
char& operator [] (unsigned int index);
|
||||
void getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index=0) const;
|
||||
void toCharArray(char *buf, unsigned int bufsize, unsigned int index=0) const
|
||||
{ getBytes((unsigned char *)buf, bufsize, index); }
|
||||
const char* c_str() const { return buffer; }
|
||||
char* begin() { return buffer; }
|
||||
char* end() { return buffer + length(); }
|
||||
const char* begin() const { return c_str(); }
|
||||
const char* end() const { return c_str() + length(); }
|
||||
|
||||
// search
|
||||
int indexOf( char ch ) const;
|
||||
int indexOf( char ch, unsigned int fromIndex ) const;
|
||||
int indexOf( const String &str ) const;
|
||||
int indexOf( const String &str, unsigned int fromIndex ) const;
|
||||
int lastIndexOf( char ch ) const;
|
||||
int lastIndexOf( char ch, unsigned int fromIndex ) const;
|
||||
int lastIndexOf( const String &str ) const;
|
||||
int lastIndexOf( const String &str, unsigned int fromIndex ) const;
|
||||
String substring( unsigned int beginIndex ) const { return substring(beginIndex, len); };
|
||||
String substring( unsigned int beginIndex, unsigned int endIndex ) const;
|
||||
|
||||
// modification
|
||||
void replace(char find, char replace);
|
||||
void replace(const String& find, const String& replace);
|
||||
void remove(unsigned int index);
|
||||
void remove(unsigned int index, unsigned int count);
|
||||
void toLowerCase(void);
|
||||
void toUpperCase(void);
|
||||
void trim(void);
|
||||
|
||||
// parsing/conversion
|
||||
long toInt(void) const;
|
||||
float toFloat(void) const;
|
||||
double toDouble(void) const;
|
||||
|
||||
protected:
|
||||
char *buffer; // the actual char array
|
||||
unsigned int capacity; // the array length minus one (for the '\0')
|
||||
unsigned int len; // the String length (not counting the '\0')
|
||||
protected:
|
||||
void init(void);
|
||||
void invalidate(void);
|
||||
unsigned char changeBuffer(unsigned int maxStrLen);
|
||||
|
||||
// copy and move
|
||||
String & copy(const char *cstr, unsigned int length);
|
||||
String & copy(const __FlashStringHelper *pstr, unsigned int length);
|
||||
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
void move(String &rhs);
|
||||
#endif
|
||||
};
|
||||
|
||||
class StringSumHelper : public String
|
||||
{
|
||||
public:
|
||||
StringSumHelper(const String &s) : String(s) {}
|
||||
StringSumHelper(const char *p) : String(p) {}
|
||||
StringSumHelper(char c) : String(c) {}
|
||||
StringSumHelper(unsigned char num) : String(num) {}
|
||||
StringSumHelper(int num) : String(num) {}
|
||||
StringSumHelper(unsigned int num) : String(num) {}
|
||||
StringSumHelper(long num) : String(num) {}
|
||||
StringSumHelper(unsigned long num) : String(num) {}
|
||||
StringSumHelper(float num) : String(num) {}
|
||||
StringSumHelper(double num) : String(num) {}
|
||||
};
|
||||
|
||||
} // namespace arduino
|
||||
|
||||
#endif // __cplusplus
|
||||
#endif // __ARDUINO_STRINGS__
|
||||
#pragma once
|
||||
#include "../../../ArduinoCore-API/api/String.h"
|
||||
|
||||
@@ -1,64 +1,2 @@
|
||||
/*
|
||||
USBAPI.h
|
||||
Copyright (c) 2005-2014 Arduino. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __USBAPI__
|
||||
#define __USBAPI__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace arduino {
|
||||
//================================================================================
|
||||
//================================================================================
|
||||
// Low level API
|
||||
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
union {
|
||||
uint8_t bmRequestType;
|
||||
struct {
|
||||
uint8_t direction : 5;
|
||||
uint8_t type : 2;
|
||||
uint8_t transferDirection : 1;
|
||||
};
|
||||
};
|
||||
uint8_t bRequest;
|
||||
uint8_t wValueL;
|
||||
uint8_t wValueH;
|
||||
uint16_t wIndex;
|
||||
uint16_t wLength;
|
||||
} USBSetup;
|
||||
|
||||
}
|
||||
|
||||
//================================================================================
|
||||
// USB APIs (C scope)
|
||||
//================================================================================
|
||||
|
||||
int USB_SendControl(uint8_t flags, const void* d, int len);
|
||||
int USB_RecvControl(void* d, int len);
|
||||
int USB_RecvControlLong(void* d, int len);
|
||||
|
||||
uint8_t USB_Available(uint8_t ep);
|
||||
uint8_t USB_SendSpace(uint8_t ep);
|
||||
int USB_Send(uint8_t ep, const void* data, int len); // blocking
|
||||
int USB_Recv(uint8_t ep, void* data, int len); // non-blocking
|
||||
int USB_Recv(uint8_t ep); // non-blocking
|
||||
void USB_Flush(uint8_t ep);
|
||||
|
||||
#endif
|
||||
#pragma once
|
||||
#include "../../../ArduinoCore-API/api/USBAPI.h"
|
||||
|
||||
+1
-91
@@ -1,92 +1,2 @@
|
||||
/*
|
||||
* Udp.cpp: Library to send/receive UDP packets.
|
||||
*
|
||||
* NOTE: UDP is fast, but has some important limitations (thanks to Warren Gray for mentioning these)
|
||||
* 1) UDP does not guarantee the order in which assembled UDP packets are received. This
|
||||
* might not happen often in practice, but in larger network topologies, a UDP
|
||||
* packet can be received out of sequence.
|
||||
* 2) UDP does not guard against lost packets - so packets *can* disappear without the sender being
|
||||
* aware of it. Again, this may not be a concern in practice on small local networks.
|
||||
* For more information, see http://www.cafeaulait.org/course/week12/35.html
|
||||
*
|
||||
* MIT License:
|
||||
* Copyright (c) 2008 Bjoern Hartmann
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* bjoern@cs.stanford.edu 12/30/2008
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Stream.h"
|
||||
#include "IPAddress.h"
|
||||
|
||||
namespace arduino {
|
||||
|
||||
class UDP : public Stream {
|
||||
|
||||
public:
|
||||
virtual uint8_t begin(uint16_t) =0; // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use
|
||||
virtual uint8_t beginMulticast(IPAddress, uint16_t) { return 0; } // initialize, start listening on specified multicast IP address and port. Returns 1 if successful, 0 on failure
|
||||
virtual void stop() =0; // Finish with the UDP socket
|
||||
|
||||
// Sending UDP packets
|
||||
|
||||
// Start building up a packet to send to the remote host specific in ip and port
|
||||
// Returns 1 if successful, 0 if there was a problem with the supplied IP address or port
|
||||
virtual int beginPacket(IPAddress ip, uint16_t port) =0;
|
||||
// Start building up a packet to send to the remote host specific in host and port
|
||||
// Returns 1 if successful, 0 if there was a problem resolving the hostname or port
|
||||
virtual int beginPacket(const char *host, uint16_t port) =0;
|
||||
// Finish off this packet and send it
|
||||
// Returns 1 if the packet was sent successfully, 0 if there was an error
|
||||
virtual int endPacket() =0;
|
||||
// Write a single byte into the packet
|
||||
virtual size_t write(uint8_t) =0;
|
||||
// Write size bytes from buffer into the packet
|
||||
virtual size_t write(const uint8_t *buffer, size_t size) =0;
|
||||
|
||||
// Start processing the next available incoming packet
|
||||
// Returns the size of the packet in bytes, or 0 if no packets are available
|
||||
virtual int parsePacket() =0;
|
||||
// Number of bytes remaining in the current packet
|
||||
virtual int available() =0;
|
||||
// Read a single byte from the current packet
|
||||
virtual int read() =0;
|
||||
// Read up to len bytes from the current packet and place them into buffer
|
||||
// Returns the number of bytes read, or 0 if none are available
|
||||
virtual int read(unsigned char* buffer, size_t len) =0;
|
||||
// Read up to len characters from the current packet and place them into buffer
|
||||
// Returns the number of characters read, or 0 if none are available
|
||||
virtual int read(char* buffer, size_t len) =0;
|
||||
// Return the next byte from the current packet without moving on to the next byte
|
||||
virtual int peek() =0;
|
||||
virtual void flush() =0; // Finish reading the current packet
|
||||
|
||||
// Return the IP address of the host who sent the current incoming packet
|
||||
virtual IPAddress remoteIP() =0;
|
||||
// Return the port of the host who sent the current incoming packet
|
||||
virtual uint16_t remotePort() =0;
|
||||
protected:
|
||||
uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); };
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
using namespace arduino;
|
||||
#include "../../../ArduinoCore-API/api/Udp.h"
|
||||
|
||||
@@ -1,171 +1,2 @@
|
||||
/*
|
||||
WCharacter.h - Character utility functions for Wiring & Arduino
|
||||
Copyright (c) 2010 Hernando Barragan. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef Character_h
|
||||
#define Character_h
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
namespace arduino {
|
||||
|
||||
// WCharacter.h prototypes
|
||||
inline bool isAlphaNumeric(int c) __attribute__((always_inline));
|
||||
inline bool isAlpha(int c) __attribute__((always_inline));
|
||||
inline bool isAscii(int c) __attribute__((always_inline));
|
||||
inline bool isWhitespace(int c) __attribute__((always_inline));
|
||||
inline bool isControl(int c) __attribute__((always_inline));
|
||||
inline bool isDigit(int c) __attribute__((always_inline));
|
||||
inline bool isGraph(int c) __attribute__((always_inline));
|
||||
inline bool isLowerCase(int c) __attribute__((always_inline));
|
||||
inline bool isPrintable(int c) __attribute__((always_inline));
|
||||
inline bool isPunct(int c) __attribute__((always_inline));
|
||||
inline bool isSpace(int c) __attribute__((always_inline));
|
||||
inline bool isUpperCase(int c) __attribute__((always_inline));
|
||||
inline bool isHexadecimalDigit(int c) __attribute__((always_inline));
|
||||
inline int toAscii(int c) __attribute__((always_inline));
|
||||
inline int toLowerCase(int c) __attribute__((always_inline));
|
||||
inline int toUpperCase(int c)__attribute__((always_inline));
|
||||
|
||||
|
||||
// Checks for an alphanumeric character.
|
||||
// It is equivalent to (isalpha(c) || isdigit(c)).
|
||||
inline bool isAlphaNumeric(int c)
|
||||
{
|
||||
return ( isalnum(c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
|
||||
// Checks for an alphabetic character.
|
||||
// It is equivalent to (isupper(c) || islower(c)).
|
||||
inline bool isAlpha(int c)
|
||||
{
|
||||
return ( isalpha(c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
|
||||
// Checks whether c is a 7-bit unsigned char value
|
||||
// that fits into the ASCII character set.
|
||||
inline bool isAscii(int c)
|
||||
{
|
||||
return ( isascii (c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
|
||||
// Checks for a blank character, that is, a space or a tab.
|
||||
inline bool isWhitespace(int c)
|
||||
{
|
||||
return ( isblank (c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
|
||||
// Checks for a control character.
|
||||
inline bool isControl(int c)
|
||||
{
|
||||
return ( iscntrl (c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
|
||||
// Checks for a digit (0 through 9).
|
||||
inline bool isDigit(int c)
|
||||
{
|
||||
return ( isdigit (c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
|
||||
// Checks for any printable character except space.
|
||||
inline bool isGraph(int c)
|
||||
{
|
||||
return ( isgraph (c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
|
||||
// Checks for a lower-case character.
|
||||
inline bool isLowerCase(int c)
|
||||
{
|
||||
return (islower (c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
|
||||
// Checks for any printable character including space.
|
||||
inline bool isPrintable(int c)
|
||||
{
|
||||
return ( isprint (c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
|
||||
// Checks for any printable character which is not a space
|
||||
// or an alphanumeric character.
|
||||
inline bool isPunct(int c)
|
||||
{
|
||||
return ( ispunct (c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
|
||||
// Checks for white-space characters. For the avr-libc library,
|
||||
// these are: space, formfeed ('\f'), newline ('\n'), carriage
|
||||
// return ('\r'), horizontal tab ('\t'), and vertical tab ('\v').
|
||||
inline bool isSpace(int c)
|
||||
{
|
||||
return ( isspace (c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
|
||||
// Checks for an uppercase letter.
|
||||
inline bool isUpperCase(int c)
|
||||
{
|
||||
return ( isupper (c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
|
||||
// Checks for a hexadecimal digits, i.e. one of 0 1 2 3 4 5 6 7
|
||||
// 8 9 a b c d e f A B C D E F.
|
||||
inline bool isHexadecimalDigit(int c)
|
||||
{
|
||||
return ( isxdigit (c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
|
||||
// Converts c to a 7-bit unsigned char value that fits into the
|
||||
// ASCII character set, by clearing the high-order bits.
|
||||
inline int toAscii(int c)
|
||||
{
|
||||
return toascii (c);
|
||||
}
|
||||
|
||||
|
||||
// Warning:
|
||||
// Many people will be unhappy if you use this function.
|
||||
// This function will convert accented letters into random
|
||||
// characters.
|
||||
|
||||
// Converts the letter c to lower case, if possible.
|
||||
inline int toLowerCase(int c)
|
||||
{
|
||||
return tolower (c);
|
||||
}
|
||||
|
||||
|
||||
// Converts the letter c to upper case, if possible.
|
||||
inline int toUpperCase(int c)
|
||||
{
|
||||
return toupper (c);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
#pragma once
|
||||
#include "../../../ArduinoCore-API/api/WCharacter.h"
|
||||
|
||||
@@ -1,37 +1 @@
|
||||
/*
|
||||
dtostrf - Emulation for dtostrf function from avr-libc
|
||||
Copyright (c) 2016 Arduino LLC. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
// This is a default implementation for dtostrf function.
|
||||
// This file should be used if the standard lib doesn't provide an
|
||||
// implementation of dtostrf.
|
||||
|
||||
// Create a file called "dtostrf.c" with the following include:
|
||||
// #include "api/deprecated-avr-comp/avr/dtostrf.c.impl"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
char *dtostrf (double val, signed char width, unsigned char prec, char *sout) {
|
||||
asm(".global _printf_float");
|
||||
|
||||
char fmt[20];
|
||||
sprintf(fmt, "%%%d.%df", width, prec);
|
||||
sprintf(sout, fmt, val);
|
||||
return sout;
|
||||
}
|
||||
|
||||
#include "../../../../../ArduinoCore-API/api/deprecated-avr-comp/avr/dtostrf.c.impl"
|
||||
|
||||
@@ -1,34 +1,2 @@
|
||||
/*
|
||||
dtostrf - Emulation for dtostrf function from avr-libc
|
||||
Copyright (c) 2015 Arduino LLC. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(ARDUINO_ARCH_AVR)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
char *dtostrf(double val, signed char width, unsigned char prec, char *sout);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#include "../../../../../ArduinoCore-API/api/deprecated-avr-comp/avr/dtostrf.h"
|
||||
|
||||
@@ -1,23 +1,2 @@
|
||||
/*
|
||||
Copyright (c) 2015 Arduino LCC. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
Empty file.
|
||||
This file is here to allow compatibility with sketches (made for AVR)
|
||||
that includes <AVR/interrupt.h>
|
||||
*/
|
||||
#pragma once
|
||||
#include "../../../../../ArduinoCore-API/api/deprecated-avr-comp/avr/interrupt.h"
|
||||
|
||||
@@ -1,158 +1,2 @@
|
||||
/*
|
||||
pgmspace.h - Definitions for compatibility with AVR pgmspace macros
|
||||
|
||||
Copyright (c) 2015 Arduino LLC
|
||||
|
||||
Based on work of Paul Stoffregen on Teensy 3 (http://pjrc.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE
|
||||
*/
|
||||
|
||||
#ifndef __PGMSPACE_H_
|
||||
#define __PGMSPACE_H_ 1
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#define PROGMEM
|
||||
#define PGM_P const char *
|
||||
#define PSTR(str) (str)
|
||||
|
||||
#define _SFR_BYTE(n) (n)
|
||||
|
||||
typedef void prog_void;
|
||||
typedef char prog_char;
|
||||
typedef unsigned char prog_uchar;
|
||||
typedef int8_t prog_int8_t;
|
||||
typedef uint8_t prog_uint8_t;
|
||||
typedef int16_t prog_int16_t;
|
||||
typedef uint16_t prog_uint16_t;
|
||||
typedef int32_t prog_int32_t;
|
||||
typedef uint32_t prog_uint32_t;
|
||||
typedef int64_t prog_int64_t;
|
||||
typedef uint64_t prog_uint64_t;
|
||||
|
||||
typedef const void* int_farptr_t;
|
||||
typedef const void* uint_farptr_t;
|
||||
|
||||
#define memchr_P(s, c, n) memchr((s), (c), (n))
|
||||
#define memcmp_P(s1, s2, n) memcmp((s1), (s2), (n))
|
||||
#define memccpy_P(dest, src, c, n) memccpy((dest), (src), (c), (n))
|
||||
#define memcpy_P(dest, src, n) memcpy((dest), (src), (n))
|
||||
#define memmem_P(haystack, haystacklen, needle, needlelen) memmem((haystack), (haystacklen), (needle), (needlelen))
|
||||
#define memrchr_P(s, c, n) memrchr((s), (c), (n))
|
||||
#define strcat_P(dest, src) strcat((dest), (src))
|
||||
#define strchr_P(s, c) strchr((s), (c))
|
||||
#define strchrnul_P(s, c) strchrnul((s), (c))
|
||||
#define strcmp_P(a, b) strcmp((a), (b))
|
||||
#define strcpy_P(dest, src) strcpy((dest), (src))
|
||||
#define strcasecmp_P(s1, s2) strcasecmp((s1), (s2))
|
||||
#define strcasestr_P(haystack, needle) strcasestr((haystack), (needle))
|
||||
#define strcspn_P(s, accept) strcspn((s), (accept))
|
||||
#define strlcat_P(s1, s2, n) strlcat((s1), (s2), (n))
|
||||
#define strlcpy_P(s1, s2, n) strlcpy((s1), (s2), (n))
|
||||
#define strlen_P(a) strlen((a))
|
||||
#define strnlen_P(s, n) strnlen((s), (n))
|
||||
#define strncmp_P(s1, s2, n) strncmp((s1), (s2), (n))
|
||||
#define strncasecmp_P(s1, s2, n) strncasecmp((s1), (s2), (n))
|
||||
#define strncat_P(s1, s2, n) strncat((s1), (s2), (n))
|
||||
#define strncpy_P(s1, s2, n) strncpy((s1), (s2), (n))
|
||||
#define strpbrk_P(s, accept) strpbrk((s), (accept))
|
||||
#define strrchr_P(s, c) strrchr((s), (c))
|
||||
#define strsep_P(sp, delim) strsep((sp), (delim))
|
||||
#define strspn_P(s, accept) strspn((s), (accept))
|
||||
#define strstr_P(a, b) strstr((a), (b))
|
||||
#define strtok_P(s, delim) strtok((s), (delim))
|
||||
#define strtok_rP(s, delim, last) strtok((s), (delim), (last))
|
||||
|
||||
#define strlen_PF(a) strlen((a))
|
||||
#define strnlen_PF(src, len) strnlen((src), (len))
|
||||
#define memcpy_PF(dest, src, len) memcpy((dest), (src), (len))
|
||||
#define strcpy_PF(dest, src) strcpy((dest), (src))
|
||||
#define strncpy_PF(dest, src, len) strncpy((dest), (src), (len))
|
||||
#define strcat_PF(dest, src) strcat((dest), (src))
|
||||
#define strlcat_PF(dest, src, len) strlcat((dest), (src), (len))
|
||||
#define strncat_PF(dest, src, len) strncat((dest), (src), (len))
|
||||
#define strcmp_PF(s1, s2) strcmp((s1), (s2))
|
||||
#define strncmp_PF(s1, s2, n) strncmp((s1), (s2), (n))
|
||||
#define strcasecmp_PF(s1, s2) strcasecmp((s1), (s2))
|
||||
#define strncasecmp_PF(s1, s2, n) strncasecmp((s1), (s2), (n))
|
||||
#define strstr_PF(s1, s2) strstr((s1), (s2))
|
||||
#define strlcpy_PF(dest, src, n) strlcpy((dest), (src), (n))
|
||||
#define memcmp_PF(s1, s2, n) memcmp((s1), (s2), (n))
|
||||
|
||||
#define sprintf_P(s, f, ...) sprintf((s), (f), __VA_ARGS__)
|
||||
#define snprintf_P(s, f, ...) snprintf((s), (f), __VA_ARGS__)
|
||||
#define vsprintf_P(s, f, ...) vsprintf((s), (f), __VA_ARGS__)
|
||||
#define vsnprintf_P(s, f, ...) vsnprintf((s), (f), __VA_ARGS__)
|
||||
|
||||
#if 0
|
||||
// Requires natural aligned addresses
|
||||
#define pgm_read_byte(addr) (*(const unsigned char *)(addr))
|
||||
#define pgm_read_word(addr) (*(const unsigned short *)(addr))
|
||||
#define pgm_read_dword(addr) (*(const unsigned long *)(addr))
|
||||
#define pgm_read_float(addr) (*(const float *)(addr))
|
||||
#define pgm_read_ptr(addr) (*(void *const *)(addr))
|
||||
#else
|
||||
// Supports misaligned addresses
|
||||
#ifdef __cplusplus
|
||||
extern "C"{
|
||||
#endif
|
||||
static inline unsigned char pgm_read_byte(const void *addr) {
|
||||
return *(const unsigned char *)(addr);
|
||||
}
|
||||
static inline unsigned short pgm_read_word(const void *addr) {
|
||||
const unsigned char *a = (const unsigned char *)addr;
|
||||
return pgm_read_byte(a) | ( pgm_read_byte(a + 1) << 8 );
|
||||
}
|
||||
static inline unsigned long pgm_read_dword(const void *addr) {
|
||||
const unsigned char *a = (const unsigned char *)addr;
|
||||
return pgm_read_byte(a) | ( pgm_read_byte(a + 1) << 8 ) | ( pgm_read_byte(a + 2) << 16 ) | ( pgm_read_byte(a + 3) << 24 );
|
||||
}
|
||||
static inline void *pgm_read_ptr(const void *addr) {
|
||||
return (void*) pgm_read_dword(addr);
|
||||
}
|
||||
static inline float pgm_read_float(const void *addr) {
|
||||
union {
|
||||
void *p;
|
||||
float f;
|
||||
} x;
|
||||
x.p = pgm_read_ptr(addr);
|
||||
return x.f;
|
||||
}
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#define pgm_read_byte_near(addr) pgm_read_byte(addr)
|
||||
#define pgm_read_word_near(addr) pgm_read_word(addr)
|
||||
#define pgm_read_dword_near(addr) pgm_read_dword(addr)
|
||||
#define pgm_read_float_near(addr) pgm_read_float(addr)
|
||||
#define pgm_read_ptr_near(addr) pgm_read_ptr(addr)
|
||||
|
||||
#define pgm_read_byte_far(addr) pgm_read_byte(addr)
|
||||
#define pgm_read_word_far(addr) pgm_read_word(addr)
|
||||
#define pgm_read_dword_far(addr) pgm_read_dword(addr)
|
||||
#define pgm_read_float_far(addr) pgm_read_float(addr)
|
||||
#define pgm_read_ptr_far(addr) pgm_read_ptr(addr)
|
||||
|
||||
#define pgm_get_far_address(addr) (&(addr))
|
||||
|
||||
#endif
|
||||
#pragma once
|
||||
#include "../../../../../ArduinoCore-API/api/deprecated-avr-comp/avr/pgmspace.h"
|
||||
|
||||
+1
-36
@@ -1,37 +1,2 @@
|
||||
/*
|
||||
Copyright (c) 2016 Arduino LLC. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Standard C functions required in Arduino API
|
||||
// If these functions are not provided by the standard library, the
|
||||
// core should supply an implementation of them.
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern char* itoa(int value, char *string, int radix);
|
||||
extern char* ltoa(long value, char *string, int radix);
|
||||
extern char* utoa(unsigned value, char *string, int radix);
|
||||
extern char* ultoa(unsigned long value, char *string, int radix);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#include "../../../ArduinoCore-API/api/itoa.h"
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
For details, see http://sourceforge.net/projects/libb64
|
||||
*/
|
||||
|
||||
#ifndef BASE64_CDECODE_H
|
||||
#define BASE64_CDECODE_H
|
||||
#pragma once
|
||||
|
||||
#define base64_decode_expected_len(n) ((n * 3) / 4)
|
||||
|
||||
@@ -34,5 +33,3 @@ int base64_decode_chars(const char* code_in, const int length_in, char* plaintex
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif /* BASE64_CDECODE_H */
|
||||
@@ -5,8 +5,7 @@
|
||||
For details, see http://sourceforge.net/projects/libb64
|
||||
*/
|
||||
|
||||
#ifndef BASE64_CENCODE_H
|
||||
#define BASE64_CENCODE_H
|
||||
#pragma once
|
||||
|
||||
#define BASE64_CHARS_PER_LINE 72
|
||||
|
||||
@@ -44,5 +43,3 @@ int base64_encode_chars(const char* plaintext_in, int length_in, char* code_out)
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif /* BASE64_CENCODE_H */
|
||||
+107
-8
@@ -25,6 +25,8 @@
|
||||
#include <pico/mutex.h>
|
||||
#include <sys/lock.h>
|
||||
|
||||
#include "_freertos.h"
|
||||
|
||||
// HACK ALERT
|
||||
// Pico-SDK defines mutex which can be at global scope, but when the auto_init_
|
||||
// macros are used they are defined as static. Newlib needs global access to
|
||||
@@ -42,12 +44,75 @@ auto_init_mutex(__lock___dd_hash_mutex);
|
||||
auto_init_mutex(__lock___arc4random_mutex);
|
||||
#undef static
|
||||
|
||||
// FreeRTOS hack - Allow Newlib to use FreeRTOS mutexes which preserve TASKID which
|
||||
// is needed to support multithread
|
||||
|
||||
SemaphoreHandle_t __lock___sinit_recursive_mutex_freertos;
|
||||
SemaphoreHandle_t __lock___sfp_recursive_mutex_freertos;
|
||||
SemaphoreHandle_t __lock___atexit_recursive_mutex_freertos;
|
||||
SemaphoreHandle_t __lock___at_quick_exit_mutex_freertos;
|
||||
SemaphoreHandle_t __lock___malloc_recursive_mutex_freertos;
|
||||
SemaphoreHandle_t __lock___env_recursive_mutex_freertos;
|
||||
SemaphoreHandle_t __lock___tz_mutex_freertos;
|
||||
SemaphoreHandle_t __lock___dd_hash_mutex_freertos;
|
||||
SemaphoreHandle_t __lock___arc4random_mutex_freertos;
|
||||
|
||||
void __initFreeRTOSMutexes() {
|
||||
__lock___sinit_recursive_mutex_freertos = _freertos_recursive_mutex_create();
|
||||
__lock___sfp_recursive_mutex_freertos = _freertos_recursive_mutex_create();
|
||||
__lock___atexit_recursive_mutex_freertos = _freertos_recursive_mutex_create();
|
||||
__lock___at_quick_exit_mutex_freertos = __freertos_mutex_create();
|
||||
__lock___malloc_recursive_mutex_freertos = _freertos_recursive_mutex_create();
|
||||
__lock___env_recursive_mutex_freertos = _freertos_recursive_mutex_create();
|
||||
__lock___tz_mutex_freertos = __freertos_mutex_create();
|
||||
__lock___dd_hash_mutex_freertos = __freertos_mutex_create();
|
||||
__lock___arc4random_mutex_freertos = __freertos_mutex_create();
|
||||
}
|
||||
|
||||
static SemaphoreHandle_t __getFreeRTOSMutex(_LOCK_T lock) {
|
||||
mutex_t *l = (mutex_t *)lock;
|
||||
if (l == &__lock___at_quick_exit_mutex) {
|
||||
return __lock___at_quick_exit_mutex_freertos;
|
||||
} else if (l == &__lock___tz_mutex) {
|
||||
return __lock___tz_mutex_freertos;
|
||||
} else if (l == &__lock___dd_hash_mutex) {
|
||||
return __lock___dd_hash_mutex_freertos;
|
||||
} else if (l == &__lock___arc4random_mutex) {
|
||||
return __lock___arc4random_mutex_freertos;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static SemaphoreHandle_t __getFreeRTOSRecursiveMutex(_LOCK_T lock) {
|
||||
recursive_mutex_t *l = (recursive_mutex_t *)lock;
|
||||
if (l == &__lock___sinit_recursive_mutex) {
|
||||
return __lock___sinit_recursive_mutex_freertos;
|
||||
} else if (l == &__lock___sfp_recursive_mutex) {
|
||||
return __lock___sfp_recursive_mutex_freertos;
|
||||
} else if (l == &__lock___atexit_recursive_mutex) {
|
||||
return __lock___atexit_recursive_mutex_freertos;
|
||||
} else if (l == &__lock___malloc_recursive_mutex) {
|
||||
return __lock___malloc_recursive_mutex_freertos;
|
||||
} else if (l == &__lock___env_recursive_mutex) {
|
||||
return __lock___env_recursive_mutex_freertos;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void __retarget_lock_init(_LOCK_T *lock) {
|
||||
mutex_init((mutex_t*) lock);
|
||||
if (__freeRTOSinitted) {
|
||||
/* Already done in initFreeRTOSMutexes() */
|
||||
} else {
|
||||
mutex_init((mutex_t*) lock);
|
||||
}
|
||||
}
|
||||
|
||||
void __retarget_lock_init_recursive(_LOCK_T *lock) {
|
||||
recursive_mutex_init((recursive_mutex_t*) lock);
|
||||
if (__freeRTOSinitted) {
|
||||
/* Already done in initFreeRTOSMutexes() */
|
||||
} else {
|
||||
recursive_mutex_init((recursive_mutex_t*) lock);
|
||||
}
|
||||
}
|
||||
|
||||
void __retarget_lock_close(_LOCK_T lock) {
|
||||
@@ -59,25 +124,59 @@ void __retarget_lock_close_recursive(_LOCK_T lock) {
|
||||
}
|
||||
|
||||
void __retarget_lock_acquire(_LOCK_T lock) {
|
||||
mutex_enter_blocking((mutex_t*)lock);
|
||||
if (__freeRTOSinitted) {
|
||||
auto mtx = __getFreeRTOSMutex(lock);
|
||||
__freertos_mutex_take(mtx);
|
||||
} else {
|
||||
mutex_enter_blocking((mutex_t*)lock);
|
||||
}
|
||||
}
|
||||
|
||||
void __retarget_lock_acquire_recursive(_LOCK_T lock) {
|
||||
recursive_mutex_enter_blocking((recursive_mutex_t*)lock);
|
||||
if (__freeRTOSinitted) {
|
||||
auto mtx = __getFreeRTOSRecursiveMutex(lock);
|
||||
__freertos_recursive_mutex_take(mtx);
|
||||
} else {
|
||||
recursive_mutex_enter_blocking((recursive_mutex_t*)lock);
|
||||
}
|
||||
}
|
||||
|
||||
int __retarget_lock_try_acquire(_LOCK_T lock) {
|
||||
return mutex_try_enter((mutex_t *)lock, NULL);
|
||||
int ret;
|
||||
if (__freeRTOSinitted) {
|
||||
auto mtx = __getFreeRTOSMutex(lock);
|
||||
ret = __freertos_mutex_try_take(mtx);
|
||||
} else {
|
||||
ret = mutex_try_enter((mutex_t *)lock, nullptr);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int __retarget_lock_try_acquire_recursive(_LOCK_T lock) {
|
||||
return recursive_mutex_try_enter((recursive_mutex_t*)lock, NULL);
|
||||
int ret;
|
||||
if (__freeRTOSinitted) {
|
||||
auto mtx = __getFreeRTOSRecursiveMutex(lock);
|
||||
ret = __freertos_recursive_mutex_try_take(mtx);
|
||||
} else {
|
||||
ret = recursive_mutex_try_enter((recursive_mutex_t*)lock, nullptr);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void __retarget_lock_release(_LOCK_T lock) {
|
||||
mutex_exit((mutex_t*)lock);
|
||||
if (__freeRTOSinitted) {
|
||||
auto mtx = __getFreeRTOSMutex(lock);
|
||||
__freertos_mutex_give(mtx);
|
||||
} else {
|
||||
mutex_exit((mutex_t*)lock);
|
||||
}
|
||||
}
|
||||
|
||||
void __retarget_lock_release_recursive(_LOCK_T lock) {
|
||||
recursive_mutex_exit((recursive_mutex_t*)lock);
|
||||
if (__freeRTOSinitted) {
|
||||
auto mtx = __getFreeRTOSRecursiveMutex(lock);
|
||||
__freertos_recursive_mutex_give(mtx);
|
||||
} else {
|
||||
recursive_mutex_exit((recursive_mutex_t*)lock);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,8 @@ extern void loop();
|
||||
extern void initFreeRTOS() __attribute__((weak));
|
||||
extern void startFreeRTOS() __attribute__((weak));
|
||||
bool __isFreeRTOS;
|
||||
volatile bool __freeRTOSinitted;
|
||||
|
||||
|
||||
// Weak empty variant initialization. May be redefined by variant files.
|
||||
void initVariant() __attribute__((weak));
|
||||
@@ -166,8 +168,6 @@ extern "C" void __register_impure_ptr(struct _reent *p) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO: FreeRTOS should implement this based on thread ID (and each thread should have its own struct _reent
|
||||
extern "C" struct _reent *__wrap___getreent() {
|
||||
if (get_core_num() == 0) {
|
||||
return _impure_ptr;
|
||||
|
||||
@@ -90,8 +90,8 @@ extern "C" int _gettimeofday(struct timeval *tv, void *tz) {
|
||||
(void) tz;
|
||||
uint64_t now_us = to_us_since_boot(get_absolute_time()) + __timedelta_us;
|
||||
if (tv) {
|
||||
tv->tv_sec = now_us / 1000000L;
|
||||
tv->tv_usec = now_us % 1000000L;
|
||||
tv->tv_sec = now_us / 1'000'000L;
|
||||
tv->tv_usec = now_us % 1'000'000L;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -101,7 +101,7 @@ extern "C" int settimeofday(const struct timeval *tv, const struct timezone *tz)
|
||||
uint64_t now_us = to_us_since_boot(get_absolute_time());
|
||||
if (tv) {
|
||||
uint64_t newnow_us;
|
||||
newnow_us = tv->tv_sec * 1000000L;
|
||||
newnow_us = tv->tv_sec * 1'000'000L;
|
||||
newnow_us += tv->tv_usec;
|
||||
__timedelta_us = newnow_us - now_us;
|
||||
}
|
||||
@@ -111,7 +111,7 @@ extern "C" int settimeofday(const struct timeval *tv, const struct timezone *tz)
|
||||
// For NTP
|
||||
extern "C" void __setSystemTime(unsigned long long sec, unsigned long usec) {
|
||||
uint64_t now_us = to_us_since_boot(get_absolute_time());
|
||||
uint64_t newnow_us = sec * 1000000LL + usec;
|
||||
uint64_t newnow_us = sec * 1'000'000LL + usec;
|
||||
__timedelta_us = newnow_us - now_us;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,9 +42,9 @@ extern "C" void analogWriteFreq(uint32_t freq) {
|
||||
if (freq < 100) {
|
||||
DEBUGCORE("ERROR: analogWriteFreq too low (%d)\n", freq);
|
||||
analogFreq = 100;
|
||||
} else if (freq > 1000000) {
|
||||
} else if (freq > 1'000'000) {
|
||||
DEBUGCORE("ERROR: analogWriteFreq too high (%d)\n", freq);
|
||||
analogFreq = 1000000;
|
||||
analogFreq = 1'000'000;
|
||||
} else {
|
||||
analogFreq = freq;
|
||||
}
|
||||
@@ -131,6 +131,7 @@ extern "C" int analogRead(pin_size_t pin) {
|
||||
}
|
||||
if (!adcInitted) {
|
||||
adc_init();
|
||||
adcInitted = true;
|
||||
}
|
||||
adc_gpio_init(pin);
|
||||
adc_select_input(pin - minPin);
|
||||
@@ -145,6 +146,7 @@ extern "C" float analogReadTemp() {
|
||||
}
|
||||
if (!adcInitted) {
|
||||
adc_init();
|
||||
adcInitted = true;
|
||||
}
|
||||
adc_set_temp_sensor_enabled(true);
|
||||
delay(1); // Allow things to settle. Without this, readings can be erratic
|
||||
|
||||
+2
-2
@@ -54,9 +54,9 @@ author = u'Earle F. Philhower, III'
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = u'2.4.1'
|
||||
version = u'2.5.4'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = u'2.4.1'
|
||||
release = u'2.5.4'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
||||
Executable → Regular
+129
-9
@@ -10,8 +10,9 @@ OTA (Over the Air) update is the process of uploading firmware to a Pico using a
|
||||
OTA may be done using:
|
||||
|
||||
- `Arduino IDE <#arduino-ide>`__
|
||||
- `Web Browser <#web-browser>`__ - Coming soon
|
||||
- `HTTP Server <#http-server>`__ - Coming soon
|
||||
- `Web Browser <#web-browser>`__
|
||||
- `HTTP Server <#http-server>`__
|
||||
- Any other method (ZModen receive over a UART port, etc.) by using the ``Updater`` object in your sketch
|
||||
|
||||
The Arduino IDE option is intended primarily for the software development phase. The other two options would be more useful after deployment, to provide the module with application updates either manually with a web browser, or automatically using an HTTP server.
|
||||
|
||||
@@ -48,16 +49,16 @@ Check functionality provided with the `ArduinoOTA <https://github.com/earlephilh
|
||||
void setHostname(const char* hostname);
|
||||
void setPassword(const char* password);
|
||||
|
||||
Certain basic protection is already built in and does not require any additional coding by the developer. `ArduinoOTA <https://github.com/earlephilhower/arduino-pico/tree/master/libraries/ArduinoOTA>`__ and espota.py use `Digest-MD5 <https://en.wikipedia.org/wiki/Digest_access_authentication>`__ to authenticate uploads. Integrity of transferred data is verified on the ESP side using `MD5 <https://en.wikipedia.org/wiki/MD5>`__ checksum.
|
||||
Certain basic protection is already built in and does not require any additional coding by the developer. `ArduinoOTA <https://github.com/earlephilhower/arduino-pico/tree/master/libraries/ArduinoOTA>`__ and espota.py use `Digest-MD5 <https://en.wikipedia.org/wiki/Digest_access_authentication>`__ to authenticate uploads. Integrity of transferred data is verified on the Pico side using `MD5 <https://en.wikipedia.org/wiki/MD5>`__ checksum.
|
||||
|
||||
Make your own risk analysis and, depending on the application, decide what library functions to implement. If required, consider implementation of other means of protection from being hacked, like exposing modules for uploads only according to a specific schedule, triggering OTA only when the user presses a dedicated “Update” button wired to the ESP, etc.
|
||||
Make your own risk analysis and, depending on the application, decide what library functions to implement. If required, consider implementation of other means of protection from being hacked, like exposing modules for uploads only according to a specific schedule, triggering OTA only when the user presses a dedicated “Update” button wired to the Pico, etc.
|
||||
|
||||
Advanced Security - Signed Updates
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
While the above password-based security will dissuade casual hacking attempts, it is not highly secure. For applications where a higher level of security is needed, cryptographically signed OTA updates can be required. This uses SHA256 hashing in place of MD5 (which is known to be cryptographically broken) and RSA-2048 bit level public-key encryption to guarantee that only the holder of a cryptographic private key can produce signed updates accepted by the OTA update mechanisms.
|
||||
|
||||
Signed updates are updates whose compiled binaries are signed with a private key (held by the developer) and verified with a public key (stored in the application and available for all to see). The signing process computes a hash of the binary code, encrypts the hash with the developer's private key, and appends this encrypted hash (also called a signature) to the binary that is uploaded (via OTA, web, or HTTP server). If the code is modified or replaced in any way by anyone except the holder of the developer's private key, the signature will not match and the ESP8266 will reject the upload.
|
||||
Signed updates are updates whose compiled binaries are signed with a private key (held by the developer) and verified with a public key (stored in the application and available for all to see). The signing process computes a hash of the binary code, encrypts the hash with the developer's private key, and appends this encrypted hash (also called a signature) to the binary that is uploaded (via OTA, web, or HTTP server). If the code is modified or replaced in any way by anyone except the holder of the developer's private key, the signature will not match and the Pico will reject the upload.
|
||||
|
||||
Cryptographic signing only protects against tampering with binaries delivered via OTA. If someone has physical access, they will always be able to flash the device over the serial port. Signing also does not encrypt anything but the hash (so that it can't be modified), so this does not protect code inside the device: if a user has physical access they can read out your program.
|
||||
|
||||
@@ -134,7 +135,7 @@ Compile the sketch normally and, once a `.bin` file is available, sign it using
|
||||
|
||||
.. code:: bash
|
||||
|
||||
<ESP8266ArduinoPath>/tools/signing.py --mode sign --privatekey <path-to-private.key> --bin <path-to-unsigned-bin> --out <path-to-signed-binary>
|
||||
<PicoArduinoPath>/tools/signing.py --mode sign --privatekey <path-to-private.key> --bin <path-to-unsigned-bin> --out <path-to-signed-binary>
|
||||
|
||||
Compression
|
||||
-----------
|
||||
@@ -155,14 +156,14 @@ If signing is desired, sign the gzip compressed file *after* compression.
|
||||
.. code:: bash
|
||||
|
||||
gzip -9 sketch.bin
|
||||
<ESP8266ArduinoPath>/tools/signing.py --mode sign --privatekey <path-to-private.key> --bin sketch.bin.gz --out sketch.bin.gz.signed
|
||||
<PicoPath>/tools/signing.py --mode sign --privatekey <path-to-private.key> --bin sketch.bin.gz --out sketch.bin.gz.signed
|
||||
|
||||
Safety
|
||||
~~~~~~
|
||||
|
||||
The OTA process consumes some of the ESP’s resources and bandwidth during upload. Then, the module is restarted and a new sketch executed. Analyse and test how this affects the functionality of the existing and new sketches.
|
||||
The OTA process consumes some of the Pico’s resources and bandwidth during upload. Then, the module is restarted and a new sketch executed. Analyse and test how this affects the functionality of the existing and new sketches.
|
||||
|
||||
If the ESP is in a remote location and controlling some equipment, you should devote additional attention to what happens if operation of this equipment is suddenly interrupted by the update process. Therefore, decide how to put this equipment into a safe state before starting the update. For instance, your module may be controlling a garden watering system in a sequence. If this sequence is not properly shut down and a water valve is left open, the garden may be flooded.
|
||||
If the Pico is in a remote location and controlling some equipment, you should devote additional attention to what happens if operation of this equipment is suddenly interrupted by the update process. Therefore, decide how to put this equipment into a safe state before starting the update. For instance, your module may be controlling a garden watering system in a sequence. If this sequence is not properly shut down and a water valve is left open, the garden may be flooded.
|
||||
|
||||
The following functions are provided with the `ArduinoOTA <https://github.com/earlephilhower/arduino-pico/tree/master/libraries/ArduinoOTA>`__ library and intended to handle functionality of your application during specific stages of OTA, or on an OTA error:
|
||||
|
||||
@@ -215,6 +216,125 @@ You will not be prompted for a reentering the same password next time. Arduino I
|
||||
|
||||
Please note, it is possible to reveal password entered previously in Arduino IDE, if IDE has not been closed since last upload. This can be done by enabling *Show verbose output during: upload* in *File > Preferences* and attempting to upload the module.
|
||||
|
||||
|
||||
|
||||
|
||||
Web Browser
|
||||
-----------
|
||||
|
||||
Updates described in this chapter are done with a web browser that can be useful in the following typical scenarios:
|
||||
|
||||
- after application deployment if loading directly from Arduino IDE is inconvenient or not possible,
|
||||
- after deployment if user is unable to expose module for OTA from external update server,
|
||||
- to provide updates after deployment to small quantity of modules when setting an update server is not practicable.
|
||||
|
||||
Requirements
|
||||
~~~~~~~~~~~~
|
||||
|
||||
- The Pico and the computer must be connected to the same network, or the IP of the Pico should be known if on a different network.
|
||||
|
||||
Implementation Overview
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Updates with a web browser are implemented using ``HTTPUpdateServer`` class together with ``WebServer`` and ``LEAmDNS`` classes. The following code is required to get it work:
|
||||
|
||||
setup()
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
MDNS.begin(host);
|
||||
|
||||
httpUpdater.setup(&httpServer);
|
||||
httpServer.begin();
|
||||
|
||||
MDNS.addService("http", "tcp", 80);
|
||||
|
||||
loop()
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
httpServer.handleClient();
|
||||
|
||||
In case OTA update fails dead after entering modifications in your sketch, you can always recover module by loading it over a serial port. Then diagnose the issue with sketch using Serial Monitor. Once the issue is fixed try OTA again.
|
||||
|
||||
|
||||
HTTP Server
|
||||
-----------
|
||||
|
||||
``HTTPUpdate`` class can check for updates and download a binary file from HTTP web server. It is possible to download updates from every IP or domain address on the network or Internet.
|
||||
|
||||
Note that by default this class closes all other connections except the one used by the update, this is because the update method blocks. This means that if there's another application receiving data then TCP packets will build up in the buffer leading to out of memory errors causing the OTA update to fail. There's also a limited number of receive buffers available and all may be used up by other applications.
|
||||
|
||||
There are some cases where you know that you won't be receiving any data but would still like to send progress updates.
|
||||
It's possible to disable the default behaviour (and keep connections open) by calling closeConnectionsOnUpdate(false).
|
||||
|
||||
Requirements
|
||||
~~~~~~~~~~~~
|
||||
|
||||
- web server
|
||||
|
||||
Arduino code
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Simple updater
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
Simple updater downloads the file every time the function is called.
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
WiFiClient client;
|
||||
HTTPUpdate.update(client, "192.168.0.2", 80, "/arduino.bin");
|
||||
|
||||
Advanced updater
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
Its possible to point the update function to a script on the server. If a version string argument is given, it will be sent to the server. The server side script can use this string to check whether an update should be performed.
|
||||
|
||||
The server-side script can respond as follows: - response code 200, and send the firmware image, - or response code 304 to notify Pico that no update is required.
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
WiFiClient client;
|
||||
t_httpUpdate_return ret = HTTPUpdate.update(client, "192.168.0.2", 80, "/pico/update/arduino.php", "optional current version string here");
|
||||
switch(ret) {
|
||||
case HTTP_UPDATE_FAILED:
|
||||
Serial.println("[update] Update failed.");
|
||||
break;
|
||||
case HTTP_UPDATE_NO_UPDATES:
|
||||
Serial.println("[update] Update no Update.");
|
||||
break;
|
||||
case HTTP_UPDATE_OK:
|
||||
Serial.println("[update] Update ok."); // may not be called since we reboot the RP2040
|
||||
break;
|
||||
}
|
||||
|
||||
TLS updater
|
||||
^^^^^^^^^^^
|
||||
|
||||
Please read and try the examples provided with the library.
|
||||
|
||||
Server request handling
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Simple updater
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
For the simple updater the server only needs to deliver the binary file for update.
|
||||
|
||||
Advanced updater
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
For advanced update management a script (such as a PHP script) can run on the server side. It will receive the following headers which it may use to choose a specific firmware file to serve:
|
||||
|
||||
::
|
||||
[User-Agent] => Pico-HTTP-Update
|
||||
[x-Pico-STA-MAC] => 18:FE:AA:AA:AA:AA
|
||||
[x-Pico-AP-MAC] => 1A:FE:AA:AA:AA:AA
|
||||
[x-Pico-Version] => DOOR-7-g14f53a19
|
||||
[x-Pico-Mode] => sketch
|
||||
|
||||
|
||||
Stream Interface
|
||||
----------------
|
||||
|
||||
|
||||
+18
-4
@@ -33,10 +33,24 @@ values returned may not meet the most stringent random tests. **If your
|
||||
application needs absolute bulletproof random numbers, consider using
|
||||
dedicated external hardware.**
|
||||
|
||||
void reboot()
|
||||
~~~~~~~~~~~~~
|
||||
void rp2040.reboot()
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
Forces a hardware reboot of the Pico.
|
||||
|
||||
Hardware Watchdog
|
||||
_________________
|
||||
|
||||
void rp2040.wdt_begin(uint32_t delay_ms)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Enables the hardware watchdog timer with a delay value of delay_ms
|
||||
microseconds. Note that on the RP2040, once this function has called, the
|
||||
hardware watchdog can _not_ be disabled.
|
||||
|
||||
void rp2040.wdt_reset()
|
||||
~~~~~~~~~~~~~~~~
|
||||
Reloads the watchdog's counter with the amount of time set by wdt_begin.
|
||||
|
||||
|
||||
Memory Information
|
||||
------------------
|
||||
|
||||
@@ -47,8 +61,8 @@ that because there is some overhead, and there may be heap fragmentation,
|
||||
this number is an *upper bound* and you generally will only be able to allocate
|
||||
less than this returned number.
|
||||
|
||||
int rp2040.getUsedHeap
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
int rp2040.getUsedHeap()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Returns the number of bytes allocated out of the heap.
|
||||
|
||||
int rp2040.getTotalHeap()
|
||||
|
||||
@@ -32,9 +32,22 @@ usToPIOCycles KEYWORD2
|
||||
f_cpu KEYWORD2
|
||||
getCycleCount KEYWORD2
|
||||
getCycleCount64 KEYWORD2
|
||||
|
||||
getFreeHeap KEYWORD2
|
||||
getUsedHeap KEYWORD2
|
||||
getTotalHeap KEYWORD2
|
||||
|
||||
idleOtherCore KEYWORD2
|
||||
resumeOtherCore KEYWORD2
|
||||
|
||||
restartCore1 KEYWORD2
|
||||
reboot KEYWORD2
|
||||
restart KEYWORD2
|
||||
|
||||
getChipID KEYWORD2
|
||||
|
||||
hwrand32 KEYWORD2
|
||||
|
||||
PIOProgram KEYWORD2
|
||||
prepare KEYWORD2
|
||||
SerialPIO KEYWORD2
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -132,15 +132,6 @@ SECTIONS
|
||||
} > FLASH
|
||||
__exidx_end = .;
|
||||
|
||||
/* Machine inspectable binary information */
|
||||
. = ALIGN(4);
|
||||
__binary_info_start = .;
|
||||
.binary_info :
|
||||
{
|
||||
KEEP(*(.binary_info.keep.*))
|
||||
*(.binary_info.*)
|
||||
} > FLASH
|
||||
__binary_info_end = .;
|
||||
. = ALIGN(4);
|
||||
|
||||
/* End of .text-like segments */
|
||||
|
||||
@@ -1,3 +1,24 @@
|
||||
/*
|
||||
Arduino OTA.cpp - Simple Arduino IDE OTA handler
|
||||
Modified 2022 Earle F. Philhower, III. All rights reserved.
|
||||
|
||||
Taken from the ESP8266 core libraries, (c) various authors.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <functional>
|
||||
#include <WiFiUdp.h>
|
||||
#include "ArduinoOTA.h"
|
||||
|
||||
@@ -1,3 +1,24 @@
|
||||
/*
|
||||
Arduino OTA.h - Simple Arduino IDE OTA handler
|
||||
Modified 2022 Earle F. Philhower, III. All rights reserved.
|
||||
|
||||
Taken from the ESP8266 core libraries, (c) various authors.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <WiFi.h>
|
||||
@@ -38,10 +59,10 @@ public:
|
||||
void setHostname(const char *hostname);
|
||||
String getHostname();
|
||||
|
||||
//Sets the password that will be required for OTA. Default NULL
|
||||
//Sets the password that will be required for OTA. Default nullptr
|
||||
void setPassword(const char *password);
|
||||
|
||||
//Sets the password as above but in the form MD5(password). Default NULL
|
||||
//Sets the password as above but in the form MD5(password). Default nullptr
|
||||
void setPasswordHash(const char *password);
|
||||
|
||||
//Sets if the device should be rebooted after successful update. Default true
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
#include <WiFi.h>
|
||||
#include <DNSServer.h>
|
||||
#include <WebServer.h>
|
||||
|
||||
const byte DNS_PORT = 53;
|
||||
IPAddress apIP(172, 217, 28, 1);
|
||||
DNSServer dnsServer;
|
||||
WebServer webServer(80);
|
||||
|
||||
String responseHTML = ""
|
||||
"<!DOCTYPE html><html lang='en'><head>"
|
||||
"<meta name='viewport' content='width=device-width'>"
|
||||
"<title>CaptivePortal</title></head><body>"
|
||||
"<h1>Hello World!</h1><p>This is a captive portal example."
|
||||
" All requests will be redirected here.</p></body></html>";
|
||||
|
||||
void setup() {
|
||||
WiFi.mode(WIFI_AP);
|
||||
WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
|
||||
WiFi.softAP("DNSServer CaptivePortal example");
|
||||
|
||||
// if DNSServer is started with "*" for domain name, it will reply with
|
||||
// provided IP to all DNS request
|
||||
dnsServer.start(DNS_PORT, "*", apIP);
|
||||
|
||||
// replay to all requests with same HTML
|
||||
webServer.onNotFound([]() {
|
||||
webServer.send(200, "text/html", responseHTML);
|
||||
});
|
||||
webServer.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
dnsServer.processNextRequest();
|
||||
webServer.handleClient();
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
#include <WiFi.h>
|
||||
#include <WiFiClient.h>
|
||||
#include <WebServer.h>
|
||||
#include <DNSServer.h>
|
||||
#include <LEAmDNS.h>
|
||||
#include <EEPROM.h>
|
||||
|
||||
/*
|
||||
This example serves a "hello world" on a WLAN and a SoftAP at the same time.
|
||||
The SoftAP allow you to configure WLAN parameters at run time. They are not setup in the sketch but saved on EEPROM.
|
||||
|
||||
Connect your computer or cell phone to wifi network pico_ap with password 12345678. A popup may appear and it allow you to go to WLAN config. If it does not then navigate to http://192.168.4.1/wifi and config it there.
|
||||
Then wait for the module to connect to your wifi and take note of the WLAN IP it got. Then you can disconnect from pico_ap and return to your regular WLAN.
|
||||
|
||||
Now the Pico is in your network. You can reach it through http://192.168.x.x/ (the IP you took note of) or maybe at http://picow.local too.
|
||||
|
||||
This is a captive portal because through the softAP it will redirect any http request to http://192.168.4.1/
|
||||
*/
|
||||
|
||||
/* Set these to your desired softAP credentials. They are not configurable at runtime */
|
||||
#ifndef APSSID
|
||||
#define APSSID "pico_ap"
|
||||
#define APPSK "12345678"
|
||||
#endif
|
||||
|
||||
const char *softAP_ssid = APSSID;
|
||||
const char *softAP_password = APPSK;
|
||||
|
||||
/* hostname for mDNS. Should work at least on windows. Try http://picow.local */
|
||||
const char *myHostname = "picow";
|
||||
|
||||
/* Don't set this wifi credentials. They are configurated at runtime and stored on EEPROM */
|
||||
char ssid[33] = "";
|
||||
char password[65] = "";
|
||||
|
||||
// DNS server
|
||||
const byte DNS_PORT = 53;
|
||||
DNSServer dnsServer;
|
||||
|
||||
// Web server
|
||||
WebServer server(80);
|
||||
|
||||
/* Soft AP network parameters */
|
||||
IPAddress apIP(172, 217, 28, 1);
|
||||
IPAddress netMsk(255, 255, 255, 0);
|
||||
|
||||
|
||||
/** Should I connect to WLAN asap? */
|
||||
boolean connect;
|
||||
|
||||
/** Last time I tried to connect to WLAN */
|
||||
unsigned long lastConnectTry = 0;
|
||||
|
||||
/** Current WLAN status */
|
||||
unsigned int status = WL_IDLE_STATUS;
|
||||
|
||||
void setup() {
|
||||
delay(1000);
|
||||
Serial.begin(115200);
|
||||
Serial.println();
|
||||
Serial.println("Configuring access point...");
|
||||
/* You can remove the password parameter if you want the AP to be open. */
|
||||
WiFi.softAPConfig(apIP, apIP, netMsk);
|
||||
WiFi.softAP(softAP_ssid, softAP_password);
|
||||
delay(500); // Without delay I've seen the IP address blank
|
||||
Serial.print("AP IP address: ");
|
||||
Serial.println(WiFi.softAPIP());
|
||||
|
||||
/* Setup the DNS server redirecting all the domains to the apIP */
|
||||
dnsServer.setErrorReplyCode(DNSReplyCode::NoError);
|
||||
dnsServer.start(DNS_PORT, "*", apIP);
|
||||
|
||||
/* Setup web pages: root, wifi config pages, SO captive portal detectors and not found. */
|
||||
server.on("/", handleRoot);
|
||||
server.on("/wifi", handleWifi);
|
||||
server.on("/wifisave", handleWifiSave);
|
||||
server.on("/generate_204", handleRoot); // Android captive portal. Maybe not needed. Might be handled by notFound handler.
|
||||
server.on("/fwlink", handleRoot); // Microsoft captive portal. Maybe not needed. Might be handled by notFound handler.
|
||||
server.onNotFound(handleNotFound);
|
||||
server.begin(); // Web server start
|
||||
Serial.println("HTTP server started");
|
||||
//loadCredentials(); // Load WLAN credentials from network
|
||||
ssid[0] = 0;
|
||||
password[0] = 0;
|
||||
connect = strlen(ssid) > 0; // Request WLAN connect if there is a SSID
|
||||
}
|
||||
|
||||
void connectWifi() {
|
||||
Serial.println("Connecting as wifi client...");
|
||||
WiFi.disconnect();
|
||||
WiFi.end();
|
||||
WiFi.begin(ssid, password);
|
||||
int connRes = WiFi.waitForConnectResult();
|
||||
Serial.print("connRes: ");
|
||||
Serial.println(connRes);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (connect) {
|
||||
Serial.println("Connect requested");
|
||||
connect = false;
|
||||
connectWifi();
|
||||
lastConnectTry = millis();
|
||||
}
|
||||
{
|
||||
unsigned int s = WiFi.status();
|
||||
if (s == 0 && millis() > (lastConnectTry + 60000)) {
|
||||
/* If WLAN disconnected and idle try to connect */
|
||||
/* Don't set retry time too low as retry interfere the softAP operation */
|
||||
connect = true;
|
||||
}
|
||||
if (status != s) { // WLAN status change
|
||||
Serial.print("Status: ");
|
||||
Serial.println(s);
|
||||
status = s;
|
||||
if (s == WL_CONNECTED) {
|
||||
/* Just connected to WLAN */
|
||||
Serial.println("");
|
||||
Serial.print("Connected to ");
|
||||
Serial.println(ssid);
|
||||
Serial.print("IP address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
|
||||
// Setup MDNS responder
|
||||
if (!MDNS.begin(myHostname)) {
|
||||
Serial.println("Error setting up MDNS responder!");
|
||||
} else {
|
||||
Serial.println("mDNS responder started");
|
||||
// Add service to MDNS-SD
|
||||
MDNS.addService("http", "tcp", 80);
|
||||
}
|
||||
} else if (s == WL_NO_SSID_AVAIL) {
|
||||
WiFi.disconnect();
|
||||
}
|
||||
}
|
||||
if (s == WL_CONNECTED) {
|
||||
MDNS.update();
|
||||
}
|
||||
}
|
||||
// Do work:
|
||||
// DNS
|
||||
dnsServer.processNextRequest();
|
||||
// HTTP
|
||||
server.handleClient();
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/** Load WLAN credentials from EEPROM */
|
||||
void loadCredentials() {
|
||||
EEPROM.begin(512);
|
||||
EEPROM.get(0, ssid);
|
||||
EEPROM.get(0 + sizeof(ssid), password);
|
||||
char ok[2 + 1];
|
||||
EEPROM.get(0 + sizeof(ssid) + sizeof(password), ok);
|
||||
EEPROM.end();
|
||||
if (String(ok) != String("OK")) {
|
||||
ssid[0] = 0;
|
||||
password[0] = 0;
|
||||
}
|
||||
Serial.println("Recovered credentials:");
|
||||
Serial.println(ssid);
|
||||
Serial.println(strlen(password) > 0 ? "********" : "<no password>");
|
||||
}
|
||||
|
||||
/** Store WLAN credentials to EEPROM */
|
||||
void saveCredentials() {
|
||||
EEPROM.begin(512);
|
||||
EEPROM.put(0, ssid);
|
||||
EEPROM.put(0 + sizeof(ssid), password);
|
||||
char ok[2 + 1] = "OK";
|
||||
EEPROM.put(0 + sizeof(ssid) + sizeof(password), ok);
|
||||
EEPROM.commit();
|
||||
EEPROM.end();
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/** Handle root or redirect to captive portal */
|
||||
void handleRoot() {
|
||||
if (captivePortal()) { // If caprive portal redirect instead of displaying the page.
|
||||
return;
|
||||
}
|
||||
server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
server.sendHeader("Pragma", "no-cache");
|
||||
server.sendHeader("Expires", "-1");
|
||||
|
||||
String Page;
|
||||
Page += F("<!DOCTYPE html><html lang='en'><head>"
|
||||
"<meta name='viewport' content='width=device-width'>"
|
||||
"<title>CaptivePortal</title></head><body>"
|
||||
"<h1>HELLO WORLD!!</h1>");
|
||||
if (server.client().localIP() == apIP) {
|
||||
Page += String(F("<p>You are connected through the soft AP: ")) + softAP_ssid + F("</p>");
|
||||
} else {
|
||||
Page += String(F("<p>You are connected through the wifi network: ")) + ssid + F("</p>");
|
||||
}
|
||||
Page += F("<p>You may want to <a href='/wifi'>config the wifi connection</a>.</p>"
|
||||
"</body></html>");
|
||||
|
||||
server.send(200, "text/html", Page);
|
||||
}
|
||||
|
||||
/** Redirect to captive portal if we got a request for another domain. Return true in that case so the page handler do not try to handle the request again. */
|
||||
boolean captivePortal() {
|
||||
if (!isIp(server.hostHeader()) && server.hostHeader() != (String(myHostname) + ".local")) {
|
||||
Serial.println("Request redirected to captive portal");
|
||||
server.sendHeader("Location", String("http://") + toStringIp(server.client().localIP()), true);
|
||||
server.send(302, "text/plain", ""); // Empty content inhibits Content-length header so we have to close the socket ourselves.
|
||||
server.client().stop(); // Stop is needed because we sent no content length
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Wifi config page handler */
|
||||
void handleWifi() {
|
||||
server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
server.sendHeader("Pragma", "no-cache");
|
||||
server.sendHeader("Expires", "-1");
|
||||
|
||||
String Page;
|
||||
Page += F("<!DOCTYPE html><html lang='en'><head>"
|
||||
"<meta name='viewport' content='width=device-width'>"
|
||||
"<title>CaptivePortal</title></head><body>"
|
||||
"<h1>Wifi config</h1>");
|
||||
if (server.client().localIP() == apIP) {
|
||||
Page += String(F("<p>You are connected through the soft AP: ")) + softAP_ssid + F("</p>");
|
||||
} else {
|
||||
Page += String(F("<p>You are connected through the wifi network: ")) + ssid + F("</p>");
|
||||
}
|
||||
Page += String(F("\r\n<br />"
|
||||
"<table><tr><th align='left'>SoftAP config</th></tr>"
|
||||
"<tr><td>SSID "))
|
||||
+ String(softAP_ssid) + F("</td></tr>"
|
||||
"<tr><td>IP ")
|
||||
+ toStringIp(WiFi.softAPIP()) + F("</td></tr>"
|
||||
"</table>"
|
||||
"\r\n<br />"
|
||||
"<table><tr><th align='left'>WLAN config</th></tr>"
|
||||
"<tr><td>SSID ")
|
||||
+ String(ssid) + F("</td></tr>"
|
||||
"<tr><td>IP ")
|
||||
+ toStringIp(WiFi.localIP()) + F("</td></tr>"
|
||||
"</table>"
|
||||
"\r\n<br />"
|
||||
"<table><tr><th align='left'>WLAN list (refresh if any missing)</th></tr>");
|
||||
Serial.println("scan start");
|
||||
int n = WiFi.scanNetworks();
|
||||
Serial.println("scan done");
|
||||
if (n > 0) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
Page += String(F("\r\n<tr><td>SSID ")) + WiFi.SSID(i) + ((WiFi.encryptionType(i) == ENC_TYPE_NONE) ? F(" ") : F(" *")) + F(" (") + WiFi.RSSI(i) + F(")</td></tr>");
|
||||
}
|
||||
} else {
|
||||
Page += F("<tr><td>No WLAN found</td></tr>");
|
||||
}
|
||||
Page += F("</table>"
|
||||
"\r\n<br /><form method='POST' action='wifisave'><h4>Connect to network:</h4>"
|
||||
"<input type='text' placeholder='network' name='n'/>"
|
||||
"<br /><input type='password' placeholder='password' name='p'/>"
|
||||
"<br /><input type='submit' value='Connect/Disconnect'/></form>"
|
||||
"<p>You may want to <a href='/'>return to the home page</a>.</p>"
|
||||
"</body></html>");
|
||||
server.send(200, "text/html", Page);
|
||||
server.client().stop(); // Stop is needed because we sent no content length
|
||||
}
|
||||
|
||||
/** Handle the WLAN save form and redirect to WLAN config page again */
|
||||
void handleWifiSave() {
|
||||
Serial.println("wifi save");
|
||||
server.arg("n").toCharArray(ssid, sizeof(ssid) - 1);
|
||||
server.arg("p").toCharArray(password, sizeof(password) - 1);
|
||||
server.sendHeader("Location", "wifi", true);
|
||||
server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
server.sendHeader("Pragma", "no-cache");
|
||||
server.sendHeader("Expires", "-1");
|
||||
server.send(302, "text/plain", ""); // Empty content inhibits Content-length header so we have to close the socket ourselves.
|
||||
server.client().stop(); // Stop is needed because we sent no content length
|
||||
saveCredentials();
|
||||
connect = strlen(ssid) > 0; // Request WLAN connect with new credentials if there is a SSID
|
||||
}
|
||||
|
||||
void handleNotFound() {
|
||||
if (captivePortal()) { // If caprive portal redirect instead of displaying the error page.
|
||||
return;
|
||||
}
|
||||
String message = F("File Not Found\n\n");
|
||||
message += F("URI: ");
|
||||
message += server.uri();
|
||||
message += F("\nMethod: ");
|
||||
message += (server.method() == HTTP_GET) ? "GET" : "POST";
|
||||
message += F("\nArguments: ");
|
||||
message += server.args();
|
||||
message += F("\n");
|
||||
|
||||
for (uint8_t i = 0; i < server.args(); i++) {
|
||||
message += String(F(" ")) + server.argName(i) + F(": ") + server.arg(i) + F("\n");
|
||||
}
|
||||
server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
server.sendHeader("Pragma", "no-cache");
|
||||
server.sendHeader("Expires", "-1");
|
||||
server.send(404, "text/plain", message);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/** Is this an IP? */
|
||||
boolean isIp(String str) {
|
||||
for (size_t i = 0; i < str.length(); i++) {
|
||||
int c = str.charAt(i);
|
||||
if (c != '.' && (c < '0' || c > '9')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** IP to String? */
|
||||
String toStringIp(IPAddress ip) {
|
||||
String res = "";
|
||||
for (int i = 0; i < 3; i++) {
|
||||
res += String((ip >> (8 * i)) & 0xFF) + ".";
|
||||
}
|
||||
res += String(((ip >> 8 * 3)) & 0xFF);
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#include <WiFi.h>
|
||||
#include <DNSServer.h>
|
||||
#include <WebServer.h>
|
||||
|
||||
const byte DNS_PORT = 53;
|
||||
IPAddress apIP(172, 217, 28, 1);
|
||||
DNSServer dnsServer;
|
||||
WebServer webServer(80);
|
||||
|
||||
void setup() {
|
||||
WiFi.mode(WIFI_AP);
|
||||
WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
|
||||
WiFi.softAP("picow", "12345678");
|
||||
|
||||
// modify TTL associated with the domain name (in seconds)
|
||||
// default is 60 seconds
|
||||
dnsServer.setTTL(300);
|
||||
// set which return code will be used for all other domains (e.g. sending
|
||||
// ServerFailure instead of NonExistentDomain will reduce number of queries
|
||||
// sent by clients)
|
||||
// default is DNSReplyCode::NonExistentDomain
|
||||
dnsServer.setErrorReplyCode(DNSReplyCode::ServerFailure);
|
||||
|
||||
// start DNS server for a specific domain name
|
||||
dnsServer.start(DNS_PORT, "www.example.com", apIP);
|
||||
|
||||
// simple HTTP server to see that DNS server is working
|
||||
webServer.onNotFound([]() {
|
||||
String message = "Hello World!\n\n";
|
||||
message += "URI: ";
|
||||
message += webServer.uri();
|
||||
|
||||
webServer.send(200, "text/plain", message);
|
||||
});
|
||||
webServer.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
dnsServer.processNextRequest();
|
||||
webServer.handleClient();
|
||||
}
|
||||
@@ -1,10 +1,29 @@
|
||||
/*
|
||||
DNSServer.cpp - Simple DNS server for the Pico
|
||||
Modified 2022 Earle F. Philhower, III. All rights reserved.
|
||||
|
||||
Taken from the ESP8266 core libraries, (c) various authors.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "WiFi.h"
|
||||
#include "DNSServer.h"
|
||||
#include <lwip/def.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
extern struct rst_info resetInfo;
|
||||
|
||||
#ifdef DEBUG_ESP_PORT
|
||||
#define CONSOLE DEBUG_ESP_PORT
|
||||
#else
|
||||
@@ -49,399 +68,389 @@ extern struct rst_info resetInfo;
|
||||
// Want to keep IDs unique across restarts and continquious
|
||||
static uint32_t _ids __attribute__((section(".noinit")));
|
||||
|
||||
DNSServer::DNSServer()
|
||||
{
|
||||
// I have observed that using 0 for captive and non-zero (600) when
|
||||
// forwarding, will help Android devices recognize the change in connectivity.
|
||||
// They will then report connected.
|
||||
_ttl = lwip_htonl(60);
|
||||
DNSServer::DNSServer() {
|
||||
// I have observed that using 0 for captive and non-zero (600) when
|
||||
// forwarding, will help Android devices recognize the change in connectivity.
|
||||
// They will then report connected.
|
||||
_ttl = lwip_htonl(60);
|
||||
|
||||
srand(rp2040.getCycleCount());
|
||||
_ids = random(0, (1UL << 16) - 1);
|
||||
srand(rp2040.getCycleCount());
|
||||
_ids = random(0, (1UL << 16) - 1);
|
||||
|
||||
_errorReplyCode = DNSReplyCode::NonExistentDomain;
|
||||
_errorReplyCode = DNSReplyCode::NonExistentDomain;
|
||||
}
|
||||
|
||||
void DNSServer::disableForwarder(const String &domainName, bool freeResources)
|
||||
{
|
||||
_forwarder = false;
|
||||
if (domainName != "") {
|
||||
_domainName = domainName;
|
||||
downcaseAndRemoveWwwPrefix(_domainName);
|
||||
}
|
||||
if (freeResources) {
|
||||
_dns = (uint32_t)0;
|
||||
if (_que) {
|
||||
_que = nullptr;
|
||||
DEBUG_PRINTF("from stop, deleted _que\r\n");
|
||||
DEBUG_(({
|
||||
if (_que_ov) {
|
||||
DEBUG_PRINTLN2("DNS forwarder que overflow or no reply to request: ", (_que_ov));
|
||||
void DNSServer::disableForwarder(const String &domainName, bool freeResources) {
|
||||
_forwarder = false;
|
||||
if (domainName != "") {
|
||||
_domainName = domainName;
|
||||
downcaseAndRemoveWwwPrefix(_domainName);
|
||||
}
|
||||
if (freeResources) {
|
||||
_dns = (uint32_t)0;
|
||||
if (_que) {
|
||||
_que = nullptr;
|
||||
DEBUG_PRINTF("from stop, deleted _que\r\n");
|
||||
DEBUG_(({
|
||||
if (_que_ov) {
|
||||
DEBUG_PRINTLN2("DNS forwarder que overflow or no reply to request: ", (_que_ov));
|
||||
}
|
||||
if (_que_drop) {
|
||||
DEBUG_PRINTLN2("DNS forwarder que wrapped, reply dropped: ", (_que_drop));
|
||||
}
|
||||
}));
|
||||
}
|
||||
if (_que_drop) {
|
||||
DEBUG_PRINTLN2("DNS forwarder que wrapped, reply dropped: ", (_que_drop));
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool DNSServer::enableForwarder(const String &domainName, const IPAddress &dns)
|
||||
{
|
||||
disableForwarder(domainName, false); // Just happens to have the same logic needed here.
|
||||
bool DNSServer::enableForwarder(const String &domainName, const IPAddress &dns) {
|
||||
disableForwarder(domainName, false); // Just happens to have the same logic needed here.
|
||||
|
||||
if (dns.isSet()) {
|
||||
_dns = dns;
|
||||
}
|
||||
if (dns.isSet()) {
|
||||
_dns = dns;
|
||||
}
|
||||
|
||||
if (_dns.isSet()) {
|
||||
if (!_que) {
|
||||
_que = std::unique_ptr<DNSS_REQUESTER[]> (new (std::nothrow) DNSS_REQUESTER[kDNSSQueSize]);
|
||||
DEBUG_PRINTF("Created new _que\r\n");
|
||||
if (_que) {
|
||||
for (size_t i = 0; i < kDNSSQueSize; i++) {
|
||||
_que[i].ip = 0;
|
||||
if (_dns.isSet()) {
|
||||
if (!_que) {
|
||||
_que = std::unique_ptr<DNSS_REQUESTER[]> (new (std::nothrow) DNSS_REQUESTER[kDNSSQueSize]);
|
||||
DEBUG_PRINTF("Created new _que\r\n");
|
||||
if (_que) {
|
||||
for (size_t i = 0; i < kDNSSQueSize; i++) {
|
||||
_que[i].ip = 0;
|
||||
}
|
||||
DEBUG_((_que_ov = 0));
|
||||
DEBUG_((_que_drop = 0));
|
||||
}
|
||||
}
|
||||
if (_que) {
|
||||
_forwarder = true;
|
||||
}
|
||||
DEBUG_((_que_ov = 0));
|
||||
DEBUG_((_que_drop = 0));
|
||||
}
|
||||
}
|
||||
if (_que) {
|
||||
_forwarder = true;
|
||||
}
|
||||
}
|
||||
return _forwarder;
|
||||
return _forwarder;
|
||||
}
|
||||
|
||||
bool DNSServer::start(const uint16_t &port, const String &domainName,
|
||||
const IPAddress &resolvedIP, const IPAddress &dns)
|
||||
{
|
||||
_port = (port) ? port : IANA_DNS_PORT;
|
||||
const IPAddress &resolvedIP, const IPAddress &dns) {
|
||||
_port = (port) ? port : IANA_DNS_PORT;
|
||||
|
||||
_resolvedIP[0] = resolvedIP[0];
|
||||
_resolvedIP[1] = resolvedIP[1];
|
||||
_resolvedIP[2] = resolvedIP[2];
|
||||
_resolvedIP[3] = resolvedIP[3];
|
||||
_resolvedIP[0] = resolvedIP[0];
|
||||
_resolvedIP[1] = resolvedIP[1];
|
||||
_resolvedIP[2] = resolvedIP[2];
|
||||
_resolvedIP[3] = resolvedIP[3];
|
||||
|
||||
if (!enableForwarder(domainName, dns) && (dns.isSet() || _dns.isSet())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return _udp.begin(_port) == 1;
|
||||
}
|
||||
|
||||
void DNSServer::setErrorReplyCode(const DNSReplyCode &replyCode)
|
||||
{
|
||||
_errorReplyCode = replyCode;
|
||||
}
|
||||
|
||||
void DNSServer::setTTL(const uint32_t &ttl)
|
||||
{
|
||||
_ttl = lwip_htonl(ttl);
|
||||
}
|
||||
|
||||
uint32_t DNSServer::getTTL()
|
||||
{
|
||||
return lwip_ntohl(_ttl);
|
||||
}
|
||||
|
||||
void DNSServer::stop()
|
||||
{
|
||||
_udp.stop();
|
||||
disableForwarder("", true);
|
||||
}
|
||||
|
||||
void DNSServer::downcaseAndRemoveWwwPrefix(String &domainName)
|
||||
{
|
||||
domainName.toLowerCase();
|
||||
if (domainName.startsWith("www."))
|
||||
domainName.remove(0, 4);
|
||||
}
|
||||
|
||||
void DNSServer::forwardReply(uint8_t *buffer, size_t length)
|
||||
{
|
||||
if (!_forwarder || !_que) {
|
||||
return;
|
||||
}
|
||||
DNSHeader *dnsHeader = (DNSHeader *)buffer;
|
||||
uint16_t id = dnsHeader->ID;
|
||||
// if (kDNSSQueSize <= (uint16_t)((uint16_t)_ids - id)) {
|
||||
if ((uint16_t)kDNSSQueSize <= (uint16_t)_ids - id) {
|
||||
DEBUG_((++_que_drop));
|
||||
DEBUG_PRINTLN2("Forward reply ID: 0x", (String(id, HEX) + F(" dropped!")));
|
||||
return;
|
||||
}
|
||||
size_t i = id & (kDNSSQueSize - 1);
|
||||
|
||||
// Drop duplicate packets
|
||||
if (0 == _que[i].ip) {
|
||||
DEBUG_PRINTLN2("Duplicate reply dropped ID: 0x", String(id, HEX));
|
||||
return;
|
||||
}
|
||||
dnsHeader->ID = _que[i].id;
|
||||
_udp.beginPacket(_que[i].ip, _que[i].port);
|
||||
_udp.write(buffer, length);
|
||||
_udp.endPacket();
|
||||
DEBUG_PRINTLN2("Forward reply ID: 0x", (String(id, HEX) + F(" to ") + IPAddress(_que[i].ip).toString()));
|
||||
_que[i].ip = 0; // This gets used to detect duplicate packets and overflow
|
||||
}
|
||||
|
||||
void DNSServer::forwardRequest(uint8_t *buffer, size_t length)
|
||||
{
|
||||
if (!_forwarder || !_dns.isSet() || !_que) {
|
||||
return;
|
||||
}
|
||||
DNSHeader *dnsHeader = (DNSHeader *)buffer;
|
||||
++_ids;
|
||||
size_t i = _ids & (kDNSSQueSize - 1);
|
||||
DEBUG_(({
|
||||
if (0 != _que[i].ip) {
|
||||
++_que_ov;
|
||||
if (!enableForwarder(domainName, dns) && (dns.isSet() || _dns.isSet())) {
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
_que[i].ip = _udp.remoteIP();
|
||||
_que[i].port = _udp.remotePort();
|
||||
_que[i].id = dnsHeader->ID;
|
||||
dnsHeader->ID = (uint16_t)_ids;
|
||||
_udp.beginPacket(_dns, IANA_DNS_PORT);
|
||||
_udp.write(buffer, length);
|
||||
_udp.endPacket();
|
||||
DEBUG_PRINTLN2("Forward request ID: 0x", (String(dnsHeader->ID, HEX) + F(" to ") + _dns.toString()));
|
||||
|
||||
return _udp.begin(_port) == 1;
|
||||
}
|
||||
|
||||
bool DNSServer::respondToRequest(uint8_t *buffer, size_t length)
|
||||
{
|
||||
DNSHeader *dnsHeader;
|
||||
uint8_t *query, *start;
|
||||
const char *matchString;
|
||||
size_t remaining, labelLength, queryLength;
|
||||
uint16_t qtype, qclass;
|
||||
void DNSServer::setErrorReplyCode(const DNSReplyCode &replyCode) {
|
||||
_errorReplyCode = replyCode;
|
||||
}
|
||||
|
||||
dnsHeader = (DNSHeader *)buffer;
|
||||
void DNSServer::setTTL(const uint32_t &ttl) {
|
||||
_ttl = lwip_htonl(ttl);
|
||||
}
|
||||
|
||||
// Must be a query for us to do anything with it
|
||||
if (dnsHeader->QR != DNS_QR_QUERY) {
|
||||
return false;
|
||||
}
|
||||
uint32_t DNSServer::getTTL() {
|
||||
return lwip_ntohl(_ttl);
|
||||
}
|
||||
|
||||
// If operation is anything other than query, we don't do it
|
||||
if (dnsHeader->OPCode != DNS_OPCODE_QUERY) {
|
||||
replyWithError(dnsHeader, DNSReplyCode::NotImplemented);
|
||||
return false;
|
||||
}
|
||||
void DNSServer::stop() {
|
||||
_udp.stop();
|
||||
disableForwarder("", true);
|
||||
}
|
||||
|
||||
// Only support requests containing single queries - everything else
|
||||
// is badly defined
|
||||
if (dnsHeader->QDCount != lwip_htons(1)) {
|
||||
replyWithError(dnsHeader, DNSReplyCode::FormError);
|
||||
return false;
|
||||
}
|
||||
|
||||
// We must return a FormError in the case of a non-zero ARCount to
|
||||
// be minimally compatible with EDNS resolvers
|
||||
if (dnsHeader->ANCount != 0 || dnsHeader->NSCount != 0
|
||||
|| dnsHeader->ARCount != 0) {
|
||||
replyWithError(dnsHeader, DNSReplyCode::FormError);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Even if we're not going to use the query, we need to parse it
|
||||
// so we can check the address type that's being queried
|
||||
|
||||
query = start = buffer + DNS_HEADER_SIZE;
|
||||
remaining = length - DNS_HEADER_SIZE;
|
||||
while (remaining != 0 && *start != 0) {
|
||||
labelLength = *start;
|
||||
if (labelLength + 1 > remaining) {
|
||||
replyWithError(dnsHeader, DNSReplyCode::FormError);
|
||||
return false;
|
||||
void DNSServer::downcaseAndRemoveWwwPrefix(String &domainName) {
|
||||
domainName.toLowerCase();
|
||||
if (domainName.startsWith("www.")) {
|
||||
domainName.remove(0, 4);
|
||||
}
|
||||
remaining -= (labelLength + 1);
|
||||
start += (labelLength + 1);
|
||||
}
|
||||
}
|
||||
|
||||
// 1 octet labelLength, 2 octet qtype, 2 octet qclass
|
||||
if (remaining < 5) {
|
||||
replyWithError(dnsHeader, DNSReplyCode::FormError);
|
||||
return false;
|
||||
}
|
||||
|
||||
start += 1; // Skip the 0 length label that we found above
|
||||
|
||||
memcpy(&qtype, start, sizeof(qtype));
|
||||
start += 2;
|
||||
memcpy(&qclass, start, sizeof(qclass));
|
||||
start += 2;
|
||||
|
||||
queryLength = start - query;
|
||||
|
||||
if (qclass != lwip_htons(DNS_QCLASS_ANY)
|
||||
&& qclass != lwip_htons(DNS_QCLASS_IN)) {
|
||||
replyWithError(dnsHeader, DNSReplyCode::NonExistentDomain, query, queryLength);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (qtype != lwip_htons(DNS_QTYPE_A)
|
||||
&& qtype != lwip_htons(DNS_QTYPE_ANY)) {
|
||||
replyWithError(dnsHeader, DNSReplyCode::NonExistentDomain, query, queryLength);
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we have no domain name configured, just return an error
|
||||
if (_domainName == "") {
|
||||
if (_forwarder) {
|
||||
return true;
|
||||
} else {
|
||||
replyWithError(dnsHeader, _errorReplyCode, query, queryLength);
|
||||
return false;
|
||||
void DNSServer::forwardReply(uint8_t *buffer, size_t length) {
|
||||
if (!_forwarder || !_que) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
DNSHeader *dnsHeader = (DNSHeader *)buffer;
|
||||
uint16_t id = dnsHeader->ID;
|
||||
// if (kDNSSQueSize <= (uint16_t)((uint16_t)_ids - id)) {
|
||||
if ((uint16_t)kDNSSQueSize <= (uint16_t)_ids - id) {
|
||||
DEBUG_((++_que_drop));
|
||||
DEBUG_PRINTLN2("Forward reply ID: 0x", (String(id, HEX) + F(" dropped!")));
|
||||
return;
|
||||
}
|
||||
size_t i = id & (kDNSSQueSize - 1);
|
||||
|
||||
// If we're running with a wildcard we can just return a result now
|
||||
if (_domainName == "*") {
|
||||
DEBUG_PRINTF("dnsServer - replyWithIP\r\n");
|
||||
replyWithIP(dnsHeader, query, queryLength);
|
||||
return false;
|
||||
}
|
||||
// Drop duplicate packets
|
||||
if (0 == _que[i].ip) {
|
||||
DEBUG_PRINTLN2("Duplicate reply dropped ID: 0x", String(id, HEX));
|
||||
return;
|
||||
}
|
||||
dnsHeader->ID = _que[i].id;
|
||||
_udp.beginPacket(_que[i].ip, _que[i].port);
|
||||
_udp.write(buffer, length);
|
||||
_udp.endPacket();
|
||||
DEBUG_PRINTLN2("Forward reply ID: 0x", (String(id, HEX) + F(" to ") + IPAddress(_que[i].ip).toString()));
|
||||
_que[i].ip = 0; // This gets used to detect duplicate packets and overflow
|
||||
}
|
||||
|
||||
matchString = _domainName.c_str();
|
||||
|
||||
start = query;
|
||||
|
||||
// If there's a leading 'www', skip it
|
||||
if (*start == 3 && strncasecmp("www", (char *) start + 1, 3) == 0)
|
||||
start += 4;
|
||||
|
||||
while (*start != 0) {
|
||||
labelLength = *start;
|
||||
start += 1;
|
||||
while (labelLength > 0) {
|
||||
if (tolower(*start) != *matchString) {
|
||||
if (_forwarder) {
|
||||
return true;
|
||||
} else {
|
||||
replyWithError(dnsHeader, _errorReplyCode, query, queryLength);
|
||||
return false;
|
||||
void DNSServer::forwardRequest(uint8_t *buffer, size_t length) {
|
||||
if (!_forwarder || !_dns.isSet() || !_que) {
|
||||
return;
|
||||
}
|
||||
DNSHeader *dnsHeader = (DNSHeader *)buffer;
|
||||
++_ids;
|
||||
size_t i = _ids & (kDNSSQueSize - 1);
|
||||
DEBUG_(({
|
||||
if (0 != _que[i].ip) {
|
||||
++_que_ov;
|
||||
}
|
||||
}
|
||||
++start;
|
||||
++matchString;
|
||||
--labelLength;
|
||||
}
|
||||
if (*start == 0 && *matchString == '\0') {
|
||||
replyWithIP(dnsHeader, query, queryLength);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (*matchString != '.') {
|
||||
replyWithError(dnsHeader, _errorReplyCode, query, queryLength);
|
||||
return false;
|
||||
}
|
||||
++matchString;
|
||||
}
|
||||
|
||||
replyWithError(dnsHeader, _errorReplyCode, query, queryLength);
|
||||
return false;
|
||||
}));
|
||||
_que[i].ip = _udp.remoteIP();
|
||||
_que[i].port = _udp.remotePort();
|
||||
_que[i].id = dnsHeader->ID;
|
||||
dnsHeader->ID = (uint16_t)_ids;
|
||||
_udp.beginPacket(_dns, IANA_DNS_PORT);
|
||||
_udp.write(buffer, length);
|
||||
_udp.endPacket();
|
||||
DEBUG_PRINTLN2("Forward request ID: 0x", (String(dnsHeader->ID, HEX) + F(" to ") + _dns.toString()));
|
||||
}
|
||||
|
||||
void DNSServer::processNextRequest()
|
||||
{
|
||||
size_t currentPacketSize;
|
||||
bool DNSServer::respondToRequest(uint8_t *buffer, size_t length) {
|
||||
DNSHeader *dnsHeader;
|
||||
uint8_t *query, *start;
|
||||
const char *matchString;
|
||||
size_t remaining, labelLength, queryLength;
|
||||
uint16_t qtype, qclass;
|
||||
|
||||
currentPacketSize = _udp.parsePacket();
|
||||
if (currentPacketSize == 0)
|
||||
return;
|
||||
dnsHeader = (DNSHeader *)buffer;
|
||||
|
||||
// The DNS RFC requires that DNS packets be less than 512 bytes in size,
|
||||
// so just discard them if they are larger
|
||||
if (currentPacketSize > MAX_DNS_PACKETSIZE)
|
||||
return;
|
||||
// Must be a query for us to do anything with it
|
||||
if (dnsHeader->QR != DNS_QR_QUERY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the packet size is smaller than the DNS header, then someone is
|
||||
// messing with us
|
||||
if (currentPacketSize < DNS_HEADER_SIZE)
|
||||
return;
|
||||
// If operation is anything other than query, we don't do it
|
||||
if (dnsHeader->OPCode != DNS_OPCODE_QUERY) {
|
||||
replyWithError(dnsHeader, DNSReplyCode::NotImplemented);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<uint8_t[]> buffer(new (std::nothrow) uint8_t[currentPacketSize]);
|
||||
if (buffer == nullptr)
|
||||
return;
|
||||
// Only support requests containing single queries - everything else
|
||||
// is badly defined
|
||||
if (dnsHeader->QDCount != lwip_htons(1)) {
|
||||
replyWithError(dnsHeader, DNSReplyCode::FormError);
|
||||
return false;
|
||||
}
|
||||
|
||||
_udp.read(buffer.get(), currentPacketSize);
|
||||
if (_dns.isSet() && _udp.remoteIP() == _dns) {
|
||||
// _forwarder may have been set to false; however, for now allow in-flight
|
||||
// replies to finish. //??
|
||||
forwardReply(buffer.get(), currentPacketSize);
|
||||
} else
|
||||
if (respondToRequest(buffer.get(), currentPacketSize)) {
|
||||
forwardRequest(buffer.get(), currentPacketSize);
|
||||
}
|
||||
// We must return a FormError in the case of a non-zero ARCount to
|
||||
// be minimally compatible with EDNS resolvers
|
||||
if (dnsHeader->ANCount != 0 || dnsHeader->NSCount != 0
|
||||
|| dnsHeader->ARCount != 0) {
|
||||
replyWithError(dnsHeader, DNSReplyCode::FormError);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Even if we're not going to use the query, we need to parse it
|
||||
// so we can check the address type that's being queried
|
||||
|
||||
query = start = buffer + DNS_HEADER_SIZE;
|
||||
remaining = length - DNS_HEADER_SIZE;
|
||||
while (remaining != 0 && *start != 0) {
|
||||
labelLength = *start;
|
||||
if (labelLength + 1 > remaining) {
|
||||
replyWithError(dnsHeader, DNSReplyCode::FormError);
|
||||
return false;
|
||||
}
|
||||
remaining -= (labelLength + 1);
|
||||
start += (labelLength + 1);
|
||||
}
|
||||
|
||||
// 1 octet labelLength, 2 octet qtype, 2 octet qclass
|
||||
if (remaining < 5) {
|
||||
replyWithError(dnsHeader, DNSReplyCode::FormError);
|
||||
return false;
|
||||
}
|
||||
|
||||
start += 1; // Skip the 0 length label that we found above
|
||||
|
||||
memcpy(&qtype, start, sizeof(qtype));
|
||||
start += 2;
|
||||
memcpy(&qclass, start, sizeof(qclass));
|
||||
start += 2;
|
||||
|
||||
queryLength = start - query;
|
||||
|
||||
if (qclass != lwip_htons(DNS_QCLASS_ANY)
|
||||
&& qclass != lwip_htons(DNS_QCLASS_IN)) {
|
||||
replyWithError(dnsHeader, DNSReplyCode::NonExistentDomain, query, queryLength);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (qtype != lwip_htons(DNS_QTYPE_A)
|
||||
&& qtype != lwip_htons(DNS_QTYPE_ANY)) {
|
||||
replyWithError(dnsHeader, DNSReplyCode::NonExistentDomain, query, queryLength);
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we have no domain name configured, just return an error
|
||||
if (_domainName == "") {
|
||||
if (_forwarder) {
|
||||
return true;
|
||||
} else {
|
||||
replyWithError(dnsHeader, _errorReplyCode, query, queryLength);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If we're running with a wildcard we can just return a result now
|
||||
if (_domainName == "*") {
|
||||
DEBUG_PRINTF("dnsServer - replyWithIP\r\n");
|
||||
replyWithIP(dnsHeader, query, queryLength);
|
||||
return false;
|
||||
}
|
||||
|
||||
matchString = _domainName.c_str();
|
||||
|
||||
start = query;
|
||||
|
||||
// If there's a leading 'www', skip it
|
||||
if (*start == 3 && strncasecmp("www", (char *) start + 1, 3) == 0) {
|
||||
start += 4;
|
||||
}
|
||||
|
||||
while (*start != 0) {
|
||||
labelLength = *start;
|
||||
start += 1;
|
||||
while (labelLength > 0) {
|
||||
if (tolower(*start) != *matchString) {
|
||||
if (_forwarder) {
|
||||
return true;
|
||||
} else {
|
||||
replyWithError(dnsHeader, _errorReplyCode, query, queryLength);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
++start;
|
||||
++matchString;
|
||||
--labelLength;
|
||||
}
|
||||
if (*start == 0 && *matchString == '\0') {
|
||||
replyWithIP(dnsHeader, query, queryLength);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (*matchString != '.') {
|
||||
replyWithError(dnsHeader, _errorReplyCode, query, queryLength);
|
||||
return false;
|
||||
}
|
||||
++matchString;
|
||||
}
|
||||
|
||||
replyWithError(dnsHeader, _errorReplyCode, query, queryLength);
|
||||
return false;
|
||||
}
|
||||
|
||||
void DNSServer::writeNBOShort(uint16_t value)
|
||||
{
|
||||
_udp.write((unsigned char *)&value, 2);
|
||||
void DNSServer::processNextRequest() {
|
||||
size_t currentPacketSize;
|
||||
|
||||
currentPacketSize = _udp.parsePacket();
|
||||
if (currentPacketSize == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The DNS RFC requires that DNS packets be less than 512 bytes in size,
|
||||
// so just discard them if they are larger
|
||||
if (currentPacketSize > MAX_DNS_PACKETSIZE) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the packet size is smaller than the DNS header, then someone is
|
||||
// messing with us
|
||||
if (currentPacketSize < DNS_HEADER_SIZE) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<uint8_t[]> buffer(new (std::nothrow) uint8_t[currentPacketSize]);
|
||||
if (buffer == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
_udp.read(buffer.get(), currentPacketSize);
|
||||
if (_dns.isSet() && _udp.remoteIP() == _dns) {
|
||||
// _forwarder may have been set to false; however, for now allow in-flight
|
||||
// replies to finish. //??
|
||||
forwardReply(buffer.get(), currentPacketSize);
|
||||
} else if (respondToRequest(buffer.get(), currentPacketSize)) {
|
||||
forwardRequest(buffer.get(), currentPacketSize);
|
||||
}
|
||||
}
|
||||
|
||||
void DNSServer::writeNBOShort(uint16_t value) {
|
||||
_udp.write((unsigned char *)&value, 2);
|
||||
}
|
||||
|
||||
void DNSServer::replyWithIP(DNSHeader *dnsHeader,
|
||||
unsigned char * query,
|
||||
size_t queryLength)
|
||||
{
|
||||
uint16_t value;
|
||||
unsigned char * query,
|
||||
size_t queryLength) {
|
||||
uint16_t value;
|
||||
|
||||
dnsHeader->QR = DNS_QR_RESPONSE;
|
||||
dnsHeader->QDCount = lwip_htons(1);
|
||||
dnsHeader->ANCount = lwip_htons(1);
|
||||
dnsHeader->NSCount = 0;
|
||||
dnsHeader->ARCount = 0;
|
||||
dnsHeader->QR = DNS_QR_RESPONSE;
|
||||
dnsHeader->QDCount = lwip_htons(1);
|
||||
dnsHeader->ANCount = lwip_htons(1);
|
||||
dnsHeader->NSCount = 0;
|
||||
dnsHeader->ARCount = 0;
|
||||
|
||||
_udp.beginPacket(_udp.remoteIP(), _udp.remotePort());
|
||||
_udp.write((unsigned char *) dnsHeader, sizeof(DNSHeader));
|
||||
_udp.write(query, queryLength);
|
||||
_udp.beginPacket(_udp.remoteIP(), _udp.remotePort());
|
||||
_udp.write((unsigned char *) dnsHeader, sizeof(DNSHeader));
|
||||
_udp.write(query, queryLength);
|
||||
|
||||
// Rather than restate the name here, we use a pointer to the name contained
|
||||
// in the query section. Pointers have the top two bits set.
|
||||
value = 0xC000 | DNS_HEADER_SIZE;
|
||||
writeNBOShort(lwip_htons(value));
|
||||
// Rather than restate the name here, we use a pointer to the name contained
|
||||
// in the query section. Pointers have the top two bits set.
|
||||
value = 0xC000 | DNS_HEADER_SIZE;
|
||||
writeNBOShort(lwip_htons(value));
|
||||
|
||||
// Answer is type A (an IPv4 address)
|
||||
writeNBOShort(lwip_htons(DNS_QTYPE_A));
|
||||
// Answer is type A (an IPv4 address)
|
||||
writeNBOShort(lwip_htons(DNS_QTYPE_A));
|
||||
|
||||
// Answer is in the Internet Class
|
||||
writeNBOShort(lwip_htons(DNS_QCLASS_IN));
|
||||
// Answer is in the Internet Class
|
||||
writeNBOShort(lwip_htons(DNS_QCLASS_IN));
|
||||
|
||||
// Output TTL (already NBO)
|
||||
_udp.write((unsigned char*)&_ttl, 4);
|
||||
// Output TTL (already NBO)
|
||||
_udp.write((unsigned char*)&_ttl, 4);
|
||||
|
||||
// Length of RData is 4 bytes (because, in this case, RData is IPv4)
|
||||
writeNBOShort(lwip_htons(sizeof(_resolvedIP)));
|
||||
_udp.write(_resolvedIP, sizeof(_resolvedIP));
|
||||
_udp.endPacket();
|
||||
// Length of RData is 4 bytes (because, in this case, RData is IPv4)
|
||||
writeNBOShort(lwip_htons(sizeof(_resolvedIP)));
|
||||
_udp.write(_resolvedIP, sizeof(_resolvedIP));
|
||||
_udp.endPacket();
|
||||
}
|
||||
|
||||
void DNSServer::replyWithError(DNSHeader *dnsHeader,
|
||||
DNSReplyCode rcode,
|
||||
unsigned char *query,
|
||||
size_t queryLength)
|
||||
{
|
||||
dnsHeader->QR = DNS_QR_RESPONSE;
|
||||
dnsHeader->RCode = (unsigned char) rcode;
|
||||
if (query)
|
||||
dnsHeader->QDCount = lwip_htons(1);
|
||||
else
|
||||
dnsHeader->QDCount = 0;
|
||||
dnsHeader->ANCount = 0;
|
||||
dnsHeader->NSCount = 0;
|
||||
dnsHeader->ARCount = 0;
|
||||
DNSReplyCode rcode,
|
||||
unsigned char *query,
|
||||
size_t queryLength) {
|
||||
dnsHeader->QR = DNS_QR_RESPONSE;
|
||||
dnsHeader->RCode = (unsigned char) rcode;
|
||||
if (query) {
|
||||
dnsHeader->QDCount = lwip_htons(1);
|
||||
} else {
|
||||
dnsHeader->QDCount = 0;
|
||||
}
|
||||
dnsHeader->ANCount = 0;
|
||||
dnsHeader->NSCount = 0;
|
||||
dnsHeader->ARCount = 0;
|
||||
|
||||
_udp.beginPacket(_udp.remoteIP(), _udp.remotePort());
|
||||
_udp.write((unsigned char *)dnsHeader, sizeof(DNSHeader));
|
||||
if (query != NULL)
|
||||
_udp.write(query, queryLength);
|
||||
_udp.endPacket();
|
||||
_udp.beginPacket(_udp.remoteIP(), _udp.remotePort());
|
||||
_udp.write((unsigned char *)dnsHeader, sizeof(DNSHeader));
|
||||
if (query != nullptr) {
|
||||
_udp.write(query, queryLength);
|
||||
}
|
||||
_udp.endPacket();
|
||||
}
|
||||
|
||||
void DNSServer::replyWithError(DNSHeader *dnsHeader,
|
||||
DNSReplyCode rcode)
|
||||
{
|
||||
replyWithError(dnsHeader, rcode, NULL, 0);
|
||||
DNSReplyCode rcode) {
|
||||
replyWithError(dnsHeader, rcode, nullptr, 0);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,25 @@
|
||||
#ifndef DNSServer_h
|
||||
#define DNSServer_h
|
||||
/*
|
||||
DNSServer.h - Simple DNS server for the Pico
|
||||
Modified 2022 Earle F. Philhower, III. All rights reserved.
|
||||
|
||||
Taken from the ESP8266 core libraries, (c) various authors.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <WiFiUdp.h>
|
||||
@@ -25,90 +45,97 @@ constexpr inline uint16_t kIanaDnsPort = IANA_DNS_PORT;
|
||||
#define MAX_DNSNAME_LENGTH 253
|
||||
#define MAX_DNS_PACKETSIZE 512
|
||||
|
||||
enum class DNSReplyCode
|
||||
{
|
||||
NoError = 0,
|
||||
FormError = 1,
|
||||
ServerFailure = 2,
|
||||
NonExistentDomain = 3,
|
||||
NotImplemented = 4,
|
||||
Refused = 5,
|
||||
YXDomain = 6,
|
||||
YXRRSet = 7,
|
||||
NXRRSet = 8
|
||||
enum class DNSReplyCode {
|
||||
NoError = 0,
|
||||
FormError = 1,
|
||||
ServerFailure = 2,
|
||||
NonExistentDomain = 3,
|
||||
NotImplemented = 4,
|
||||
Refused = 5,
|
||||
YXDomain = 6,
|
||||
YXRRSet = 7,
|
||||
NXRRSet = 8
|
||||
};
|
||||
|
||||
struct DNSHeader
|
||||
{
|
||||
uint16_t ID; // identification number
|
||||
unsigned char RD : 1; // recursion desired
|
||||
unsigned char TC : 1; // truncated message
|
||||
unsigned char AA : 1; // authoritative answer
|
||||
unsigned char OPCode : 4; // message_type
|
||||
unsigned char QR : 1; // query/response flag
|
||||
unsigned char RCode : 4; // response code
|
||||
unsigned char Z : 3; // its z! reserved
|
||||
unsigned char RA : 1; // recursion available
|
||||
uint16_t QDCount; // number of question entries
|
||||
uint16_t ANCount; // number of answer entries
|
||||
uint16_t NSCount; // number of authority entries
|
||||
uint16_t ARCount; // number of resource entries
|
||||
struct DNSHeader {
|
||||
uint16_t ID; // identification number
|
||||
unsigned char RD : 1; // recursion desired
|
||||
unsigned char TC : 1; // truncated message
|
||||
unsigned char AA : 1; // authoritative answer
|
||||
unsigned char OPCode : 4; // message_type
|
||||
unsigned char QR : 1; // query/response flag
|
||||
unsigned char RCode : 4; // response code
|
||||
unsigned char Z : 3; // its z! reserved
|
||||
unsigned char RA : 1; // recursion available
|
||||
uint16_t QDCount; // number of question entries
|
||||
uint16_t ANCount; // number of answer entries
|
||||
uint16_t NSCount; // number of authority entries
|
||||
uint16_t ARCount; // number of resource entries
|
||||
};
|
||||
|
||||
constexpr inline size_t kDNSSQueSizeAddrBits = 3; // The number of bits used to address que entries
|
||||
constexpr inline size_t kDNSSQueSize = (1UL << (kDNSSQueSizeAddrBits));
|
||||
constexpr inline size_t kDNSSQueSize = (1UL << (kDNSSQueSizeAddrBits));
|
||||
|
||||
struct DNSS_REQUESTER {
|
||||
uint32_t ip;
|
||||
uint16_t port;
|
||||
uint16_t id;
|
||||
uint32_t ip;
|
||||
uint16_t port;
|
||||
uint16_t id;
|
||||
};
|
||||
|
||||
class DNSServer
|
||||
{
|
||||
public:
|
||||
class DNSServer {
|
||||
public:
|
||||
DNSServer();
|
||||
~DNSServer() {
|
||||
stop();
|
||||
};
|
||||
/*
|
||||
If specified, `enableForwarder` will update the `domainName` that is used
|
||||
to match DNS request to this AP's IP Address. A non-matching request will
|
||||
be forwarded to the DNS server specified by `dns`.
|
||||
If specified, `enableForwarder` will update the `domainName` that is used
|
||||
to match DNS request to this AP's IP Address. A non-matching request will
|
||||
be forwarded to the DNS server specified by `dns`.
|
||||
|
||||
Returns `true` on success.
|
||||
Returns `true` on success.
|
||||
|
||||
Returns `false`,
|
||||
* when forwarding `dns` is not set, or
|
||||
* unable to allocate resources for managing the DNS forward function.
|
||||
Returns `false`,
|
||||
when forwarding `dns` is not set, or
|
||||
unable to allocate resources for managing the DNS forward function.
|
||||
*/
|
||||
bool enableForwarder(const String &domainName = String(""), const IPAddress &dns = (uint32_t)0);
|
||||
/*
|
||||
`disableForwarder` will stop forwarding DNS requests. If specified,
|
||||
updates the `domainName` that is matched for returning this AP's IP Address.
|
||||
Optionally, resources used for the DNS forward function can be freed.
|
||||
`disableForwarder` will stop forwarding DNS requests. If specified,
|
||||
updates the `domainName` that is matched for returning this AP's IP Address.
|
||||
Optionally, resources used for the DNS forward function can be freed.
|
||||
*/
|
||||
void disableForwarder(const String &domainName = String(""), bool freeResources = false);
|
||||
bool isForwarding() { return _forwarder && _dns.isSet(); }
|
||||
void setDNS(const IPAddress& dns) { _dns = dns; }
|
||||
IPAddress getDNS() { return _dns; }
|
||||
bool isDNSSet() { return _dns.isSet(); }
|
||||
bool isForwarding() {
|
||||
return _forwarder && _dns.isSet();
|
||||
}
|
||||
void setDNS(const IPAddress& dns) {
|
||||
_dns = dns;
|
||||
}
|
||||
IPAddress getDNS() {
|
||||
return _dns;
|
||||
}
|
||||
bool isDNSSet() {
|
||||
return _dns.isSet();
|
||||
}
|
||||
|
||||
void processNextRequest();
|
||||
void setErrorReplyCode(const DNSReplyCode &replyCode);
|
||||
void setTTL(const uint32_t &ttl);
|
||||
uint32_t getTTL();
|
||||
String getDomainName() { return _domainName; }
|
||||
String getDomainName() {
|
||||
return _domainName;
|
||||
}
|
||||
|
||||
// Returns true if successful, false if there are no sockets available
|
||||
bool start(const uint16_t &port,
|
||||
const String &domainName,
|
||||
const IPAddress &resolvedIP,
|
||||
const IPAddress &dns = (uint32_t)0);
|
||||
const String &domainName,
|
||||
const IPAddress &resolvedIP,
|
||||
const IPAddress &dns = (uint32_t)0);
|
||||
// stops the DNS server
|
||||
void stop();
|
||||
|
||||
private:
|
||||
private:
|
||||
WiFiUDP _udp;
|
||||
String _domainName;
|
||||
IPAddress _dns;
|
||||
@@ -128,17 +155,16 @@ class DNSServer
|
||||
|
||||
void downcaseAndRemoveWwwPrefix(String &domainName);
|
||||
void replyWithIP(DNSHeader *dnsHeader,
|
||||
unsigned char * query,
|
||||
size_t queryLength);
|
||||
unsigned char * query,
|
||||
size_t queryLength);
|
||||
void replyWithError(DNSHeader *dnsHeader,
|
||||
DNSReplyCode rcode,
|
||||
unsigned char *query,
|
||||
size_t queryLength);
|
||||
DNSReplyCode rcode,
|
||||
unsigned char *query,
|
||||
size_t queryLength);
|
||||
void replyWithError(DNSHeader *dnsHeader,
|
||||
DNSReplyCode rcode);
|
||||
DNSReplyCode rcode);
|
||||
bool respondToRequest(uint8_t *buffer, size_t length);
|
||||
void forwardRequest(uint8_t *buffer, size_t length);
|
||||
void forwardReply(uint8_t *buffer, size_t length);
|
||||
void writeNBOShort(uint16_t value);
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -19,8 +19,7 @@
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef EEPROM_h
|
||||
#define EEPROM_h
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
@@ -85,6 +84,3 @@ protected:
|
||||
};
|
||||
|
||||
extern EEPROMClass EEPROM;
|
||||
|
||||
#endif
|
||||
|
||||
+1
-1
Submodule libraries/ESP8266SdFat updated: 43a65b42d5...255180be14
@@ -0,0 +1,80 @@
|
||||
/* The code in this example is mostly derived from the official FreeRTOS
|
||||
* code examples.
|
||||
*
|
||||
* For more information on static allocation and to read the original
|
||||
* code visit the following links:
|
||||
* https://www.freertos.org/Static_Vs_Dynamic_Memory_Allocation.html
|
||||
* https://www.freertos.org/xTaskCreateStatic.html
|
||||
* https://www.freertos.org/xSemaphoreCreateMutexStatic.html
|
||||
*/
|
||||
|
||||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
#include <semphr.h>
|
||||
|
||||
#define SERIAL_PORT Serial1
|
||||
#define BLINK_ON_TIME 250
|
||||
#define BLINK_OFF_TIME 500
|
||||
|
||||
/* Dimensions of the buffer that the task being created will use as its stack.
|
||||
NOTE: This is the number of words the stack will hold, not the number of
|
||||
bytes. For example, if each stack item is 32-bits, and this is set to 100,
|
||||
then 400 bytes (100 * 32-bits) will be allocated. */
|
||||
#define STACK_SIZE 200
|
||||
|
||||
/* Structure that will hold the TCB of the task being created. */
|
||||
StaticTask_t xTaskBuffer_A;
|
||||
StaticTask_t xTaskBuffer_B;
|
||||
|
||||
/* Buffer that the task being created will use as its stack. Note this is
|
||||
an array of StackType_t variables. The size of StackType_t is dependent on
|
||||
the RTOS port. */
|
||||
StackType_t xStack_A[ STACK_SIZE ];
|
||||
StackType_t xStack_B[ STACK_SIZE ];
|
||||
|
||||
SemaphoreHandle_t xSemaphore = NULL;
|
||||
StaticSemaphore_t xMutexBuffer;
|
||||
|
||||
void setup() {
|
||||
SERIAL_PORT.begin(115200);
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
|
||||
/* Create a mutex semaphore without using any dynamic memory
|
||||
allocation. The mutex's data structures will be saved into
|
||||
the xMutexBuffer variable. */
|
||||
xSemaphore = xSemaphoreCreateMutexStatic( &xMutexBuffer );
|
||||
|
||||
xTaskCreateStatic(led_ON, "led_ON", STACK_SIZE, NULL, configMAX_PRIORITIES - 1, xStack_A, &xTaskBuffer_A);
|
||||
xTaskCreateStatic(led_OFF, "led_OFF", STACK_SIZE, NULL, configMAX_PRIORITIES - 1, xStack_B, &xTaskBuffer_B);
|
||||
}
|
||||
|
||||
void led_ON(void *pvParameters)
|
||||
{
|
||||
(void) pvParameters;
|
||||
while (1)
|
||||
{
|
||||
xSemaphoreTake( xSemaphore, ( TickType_t ) portMAX_DELAY );
|
||||
SERIAL_PORT.println("LED ON!");
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
delay(BLINK_ON_TIME);
|
||||
xSemaphoreGive( xSemaphore );
|
||||
}
|
||||
}
|
||||
|
||||
void led_OFF(void *pvParameters)
|
||||
{
|
||||
(void) pvParameters;
|
||||
while (1)
|
||||
{
|
||||
xSemaphoreTake( xSemaphore, ( TickType_t ) portMAX_DELAY );
|
||||
SERIAL_PORT.println("LED OFF!");
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
delay(BLINK_OFF_TIME);
|
||||
xSemaphoreGive( xSemaphore );
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
SERIAL_PORT.println("Hello!");
|
||||
delay(1000);
|
||||
}
|
||||
@@ -0,0 +1,319 @@
|
||||
// FreeRTOS system call/mutex stress test
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
#include <semphr.h>
|
||||
#define DELAY 1
|
||||
#define SERIAL_DEBUG Serial1
|
||||
#define STACK_SIZE 512
|
||||
#define CORE_0 (1 << 0)
|
||||
#define CORE_1 (1 << 1)
|
||||
|
||||
void semphrTakeConditional(bool useMutexOn, SemaphoreHandle_t xSemaphore);
|
||||
void semphrGiveConditional(bool useMutexOn, SemaphoreHandle_t xSemaphore);
|
||||
|
||||
/*
|
||||
I want to keep the possibility of using different and independent
|
||||
mutexes for each of the functions that operate on the heap.
|
||||
|
||||
If you want to enable the use of these mutexes remove the defines
|
||||
on lines 30 and 31 and enable the their initialization in setup()
|
||||
*/
|
||||
SemaphoreHandle_t xSemaphoreMalloc = NULL;
|
||||
// SemaphoreHandle_t xSemaphoreRealloc = NULL;
|
||||
// SemaphoreHandle_t xSemaphoreFree = NULL;
|
||||
|
||||
/*
|
||||
A lazy way to use the same mutex for malloc, realloc and free
|
||||
in order to bring us back to the same situation as the MCVE
|
||||
posted here: https://github.com/earlephilhower/arduino-pico/issues/795#issuecomment-1227122082
|
||||
*/
|
||||
#define xSemaphoreRealloc xSemaphoreMalloc
|
||||
#define xSemaphoreFree xSemaphoreMalloc
|
||||
|
||||
const bool useMutexOnMalloc = false;
|
||||
const bool useMutexOnRealloc = false;
|
||||
const bool useMutexOnFree = false;
|
||||
|
||||
/*
|
||||
Enabling this, a realloc will be performed and the string "_realloc"
|
||||
will be concateneted to *tmp
|
||||
*/
|
||||
const bool tryRealloc = true;
|
||||
|
||||
TaskHandle_t loop2Handle = NULL;
|
||||
TaskHandle_t loop3Handle = NULL;
|
||||
TaskHandle_t loop4Handle = NULL;
|
||||
TaskHandle_t loop5Handle = NULL;
|
||||
TaskHandle_t loop6Handle = NULL;
|
||||
TaskHandle_t loop7Handle = NULL;
|
||||
|
||||
void loop2(void *pvPramaters);
|
||||
void loop3(void *pvPramaters);
|
||||
void loop4(void *pvPramaters);
|
||||
void loop5(void *pvPramaters);
|
||||
void loop6(void *pvPramaters);
|
||||
void loop7(void *pvPramaters);
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
|
||||
xSemaphoreMalloc = xSemaphoreCreateMutex();
|
||||
// xSemaphoreRealloc = xSemaphoreCreateMutex();
|
||||
// xSemaphoreFree = xSemaphoreCreateMutex();
|
||||
|
||||
xTaskCreate(loop2, "loop2", STACK_SIZE, NULL, 1, &loop2Handle);
|
||||
vTaskCoreAffinitySet(loop2Handle, CORE_0);
|
||||
xTaskCreate(loop3, "loop3", STACK_SIZE, NULL, 1, &loop3Handle);
|
||||
vTaskCoreAffinitySet(loop3Handle, CORE_1);
|
||||
xTaskCreate(loop4, "loop4", STACK_SIZE, NULL, 1, &loop4Handle);
|
||||
vTaskCoreAffinitySet(loop4Handle, CORE_0);
|
||||
xTaskCreate(loop5, "loop5", STACK_SIZE, NULL, 1, &loop5Handle);
|
||||
vTaskCoreAffinitySet(loop5Handle, CORE_1);
|
||||
// xTaskCreate(loop6, "loop6", STACK_SIZE, NULL, 1, &loop6Handle);
|
||||
// vTaskCoreAffinitySet(loop6Handle, CORE_0);
|
||||
// xTaskCreate(loop7, "loop7", STACK_SIZE, NULL, 1, &loop7Handle);
|
||||
// vTaskCoreAffinitySet(loop7Handle, CORE_1);
|
||||
}
|
||||
static int _loop[8];
|
||||
|
||||
void loop()
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
_loop[0]++;
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
delay(500);
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
delay(500);
|
||||
for (int i=0; i<8; i++) Serial.printf("%d ", _loop[i]);
|
||||
Serial.println("");
|
||||
}
|
||||
}
|
||||
|
||||
void loop1()
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
_loop[1]++;
|
||||
char *tmp;
|
||||
|
||||
semphrTakeConditional(useMutexOnMalloc, xSemaphoreMalloc);
|
||||
tmp = (char *)malloc(10 * sizeof(char));
|
||||
semphrGiveConditional(useMutexOnMalloc, xSemaphoreMalloc);
|
||||
|
||||
strcpy(tmp, "foo");
|
||||
|
||||
if (tryRealloc)
|
||||
{
|
||||
semphrTakeConditional(useMutexOnRealloc, xSemaphoreRealloc);
|
||||
tmp = (char *)realloc(tmp, 20 * sizeof(char));
|
||||
semphrGiveConditional(useMutexOnRealloc, xSemaphoreRealloc);
|
||||
strcat(tmp, "_realloc");
|
||||
}
|
||||
|
||||
semphrTakeConditional(useMutexOnFree, xSemaphoreFree);
|
||||
free(tmp);
|
||||
semphrGiveConditional(useMutexOnFree, xSemaphoreFree);
|
||||
|
||||
delay(DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
void loop2(void *pvPramaters)
|
||||
{
|
||||
(void) pvPramaters;
|
||||
while (1)
|
||||
{
|
||||
_loop[2]++;
|
||||
char *tmp;
|
||||
|
||||
semphrTakeConditional(useMutexOnMalloc, xSemaphoreMalloc);
|
||||
tmp = (char *)malloc(10 * sizeof(char));
|
||||
semphrGiveConditional(useMutexOnMalloc, xSemaphoreMalloc);
|
||||
|
||||
strcpy(tmp, "bar");
|
||||
|
||||
if (tryRealloc)
|
||||
{
|
||||
semphrTakeConditional(useMutexOnRealloc, xSemaphoreRealloc);
|
||||
tmp = (char *)realloc(tmp, 20 * sizeof(char));
|
||||
semphrGiveConditional(useMutexOnRealloc, xSemaphoreRealloc);
|
||||
strcat(tmp, "_realloc");
|
||||
}
|
||||
|
||||
semphrTakeConditional(useMutexOnFree, xSemaphoreFree);
|
||||
free(tmp);
|
||||
semphrGiveConditional(useMutexOnFree, xSemaphoreFree);
|
||||
|
||||
delay(DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
void loop3(void *pvPramaters)
|
||||
{
|
||||
(void) pvPramaters;
|
||||
while (1)
|
||||
{
|
||||
_loop[3]++;
|
||||
char *tmp;
|
||||
|
||||
semphrTakeConditional(useMutexOnMalloc, xSemaphoreMalloc);
|
||||
tmp = (char *)malloc(10 * sizeof(char));
|
||||
semphrGiveConditional(useMutexOnMalloc, xSemaphoreMalloc);
|
||||
|
||||
strcpy(tmp, "yeah");
|
||||
|
||||
if (tryRealloc)
|
||||
{
|
||||
semphrTakeConditional(useMutexOnRealloc, xSemaphoreRealloc);
|
||||
tmp = (char *)realloc(tmp, 20 * sizeof(char));
|
||||
semphrGiveConditional(useMutexOnRealloc, xSemaphoreRealloc);
|
||||
strcat(tmp, "_realloc");
|
||||
}
|
||||
|
||||
semphrTakeConditional(useMutexOnFree, xSemaphoreFree);
|
||||
free(tmp);
|
||||
semphrGiveConditional(useMutexOnFree, xSemaphoreFree);
|
||||
|
||||
delay(DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
void loop4(void *pvPramaters)
|
||||
{
|
||||
(void) pvPramaters;
|
||||
while (1)
|
||||
{
|
||||
_loop[4]++;
|
||||
char *tmp;
|
||||
|
||||
semphrTakeConditional(useMutexOnMalloc, xSemaphoreMalloc);
|
||||
tmp = (char *)malloc(10 * sizeof(char));
|
||||
semphrGiveConditional(useMutexOnMalloc, xSemaphoreMalloc);
|
||||
|
||||
strcpy(tmp, "baz");
|
||||
|
||||
if (tryRealloc)
|
||||
{
|
||||
semphrTakeConditional(useMutexOnRealloc, xSemaphoreRealloc);
|
||||
tmp = (char *)realloc(tmp, 20 * sizeof(char));
|
||||
semphrGiveConditional(useMutexOnRealloc, xSemaphoreRealloc);
|
||||
strcat(tmp, "_realloc");
|
||||
}
|
||||
|
||||
semphrTakeConditional(useMutexOnFree, xSemaphoreFree);
|
||||
free(tmp);
|
||||
semphrGiveConditional(useMutexOnFree, xSemaphoreFree);
|
||||
|
||||
delay(DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
void loop5(void *pvPramaters)
|
||||
{
|
||||
(void) pvPramaters;
|
||||
while (1)
|
||||
{
|
||||
_loop[5]++;
|
||||
char *tmp;
|
||||
|
||||
semphrTakeConditional(useMutexOnMalloc, xSemaphoreMalloc);
|
||||
tmp = (char *)malloc(10 * sizeof(char));
|
||||
semphrGiveConditional(useMutexOnMalloc, xSemaphoreMalloc);
|
||||
|
||||
strcpy(tmp, "asd");
|
||||
|
||||
if (tryRealloc)
|
||||
{
|
||||
semphrTakeConditional(useMutexOnRealloc, xSemaphoreRealloc);
|
||||
tmp = (char *)realloc(tmp, 20 * sizeof(char));
|
||||
semphrGiveConditional(useMutexOnRealloc, xSemaphoreRealloc);
|
||||
strcat(tmp, "_realloc");
|
||||
}
|
||||
|
||||
semphrTakeConditional(useMutexOnFree, xSemaphoreFree);
|
||||
free(tmp);
|
||||
semphrGiveConditional(useMutexOnFree, xSemaphoreFree);
|
||||
|
||||
delay(DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
void loop6(void *pvPramaters)
|
||||
{
|
||||
(void) pvPramaters;
|
||||
while (1)
|
||||
{
|
||||
_loop[6]++;
|
||||
char *tmp;
|
||||
|
||||
semphrTakeConditional(useMutexOnMalloc, xSemaphoreMalloc);
|
||||
tmp = (char *)malloc(10 * sizeof(char));
|
||||
semphrGiveConditional(useMutexOnMalloc, xSemaphoreMalloc);
|
||||
|
||||
strcpy(tmp, "lol");
|
||||
|
||||
if (tryRealloc)
|
||||
{
|
||||
semphrTakeConditional(useMutexOnRealloc, xSemaphoreRealloc);
|
||||
tmp = (char *)realloc(tmp, 20 * sizeof(char));
|
||||
semphrGiveConditional(useMutexOnRealloc, xSemaphoreRealloc);
|
||||
strcat(tmp, "_realloc");
|
||||
}
|
||||
|
||||
semphrTakeConditional(useMutexOnFree, xSemaphoreFree);
|
||||
free(tmp);
|
||||
semphrGiveConditional(useMutexOnFree, xSemaphoreFree);
|
||||
|
||||
delay(DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
void loop7(void *pvPramaters)
|
||||
{
|
||||
(void) pvPramaters;
|
||||
while (1)
|
||||
{
|
||||
_loop[7]++;
|
||||
char *tmp;
|
||||
|
||||
semphrTakeConditional(useMutexOnMalloc, xSemaphoreMalloc);
|
||||
tmp = (char *)malloc(10 * sizeof(char));
|
||||
semphrGiveConditional(useMutexOnMalloc, xSemaphoreMalloc);
|
||||
|
||||
strcpy(tmp, "yay");
|
||||
|
||||
if (tryRealloc)
|
||||
{
|
||||
semphrTakeConditional(useMutexOnRealloc, xSemaphoreRealloc);
|
||||
tmp = (char *)realloc(tmp, 20 * sizeof(char));
|
||||
semphrGiveConditional(useMutexOnRealloc, xSemaphoreRealloc);
|
||||
strcat(tmp, "_realloc");
|
||||
}
|
||||
|
||||
semphrTakeConditional(useMutexOnFree, xSemaphoreFree);
|
||||
free(tmp);
|
||||
semphrGiveConditional(useMutexOnFree, xSemaphoreFree);
|
||||
|
||||
delay(DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
void semphrTakeConditional(bool useMutexOn, SemaphoreHandle_t xSemaphore)
|
||||
{
|
||||
if (useMutexOn)
|
||||
{
|
||||
xSemaphoreTake(xSemaphore, TickType_t(portMAX_DELAY));
|
||||
}
|
||||
}
|
||||
|
||||
void semphrGiveConditional(bool useMutexOn, SemaphoreHandle_t xSemaphore)
|
||||
{
|
||||
if (useMutexOn)
|
||||
{
|
||||
xSemaphoreGive(xSemaphore);
|
||||
}
|
||||
}
|
||||
Submodule libraries/FreeRTOS/lib/FreeRTOS-Kernel updated: 0b55ee70ad...b5942ddd07
@@ -24,7 +24,7 @@
|
||||
#define configUSE_COUNTING_SEMAPHORES 1
|
||||
#define configUSE_QUEUE_SETS 1
|
||||
#define configSUPPORT_DYNAMIC_ALLOCATION 1
|
||||
#define configSUPPORT_STATIC_ALLOCATION 0
|
||||
#define configSUPPORT_STATIC_ALLOCATION 1
|
||||
#define configSTACK_DEPTH_TYPE uint32_t
|
||||
#define configUSE_TASK_PREEMPTION_DISABLE 1
|
||||
|
||||
|
||||
@@ -25,24 +25,28 @@
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
|
||||
/* FreeRTOS includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "timers.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/* Arduino Core includes */
|
||||
#include <Arduino.h>
|
||||
#include <RP2040USB.h>
|
||||
#include "tusb.h"
|
||||
|
||||
|
||||
/* Raspberry PI Pico includes */
|
||||
#include <pico.h>
|
||||
#include <pico/time.h>
|
||||
|
||||
/* FreeRTOS includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "timers.h"
|
||||
#include "_freertos.h"
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
extern void __initFreeRTOSMutexes();
|
||||
void initFreeRTOS(void) {
|
||||
__initFreeRTOSMutexes();
|
||||
}
|
||||
|
||||
extern void setup() __attribute__((weak));
|
||||
@@ -107,7 +111,7 @@ extern "C" void yield() {
|
||||
extern mutex_t __usb_mutex;
|
||||
static TaskHandle_t __usbTask;
|
||||
static void __usb(void *param);
|
||||
|
||||
extern volatile bool __freeRTOSinitted;
|
||||
void startFreeRTOS(void) {
|
||||
|
||||
TaskHandle_t c0;
|
||||
@@ -121,6 +125,7 @@ void startFreeRTOS(void) {
|
||||
}
|
||||
|
||||
// Initialise and run the freeRTOS scheduler. Execution should never return here.
|
||||
__freeRTOSinitted = true;
|
||||
vTaskStartScheduler();
|
||||
|
||||
while (true) {
|
||||
@@ -392,3 +397,42 @@ void __USBStart() {
|
||||
xTaskCreate(__usb, "USB", 256, 0, configMAX_PRIORITIES - 1, &__usbTask);
|
||||
vTaskCoreAffinitySet(__usbTask, 1 << 0);
|
||||
}
|
||||
|
||||
|
||||
// Interfaces for the main core to use FreeRTOS mutexes
|
||||
extern "C" {
|
||||
|
||||
SemaphoreHandle_t __freertos_mutex_create() {
|
||||
return xSemaphoreCreateMutex();
|
||||
}
|
||||
|
||||
SemaphoreHandle_t _freertos_recursive_mutex_create() {
|
||||
return xSemaphoreCreateRecursiveMutex();
|
||||
}
|
||||
|
||||
void __freertos_mutex_take(SemaphoreHandle_t mtx) {
|
||||
xSemaphoreTake(mtx, portMAX_DELAY);
|
||||
}
|
||||
|
||||
int __freertos_mutex_try_take(SemaphoreHandle_t mtx) {
|
||||
return xSemaphoreTake(mtx, 0);
|
||||
}
|
||||
|
||||
void __freertos_mutex_give(SemaphoreHandle_t mtx) {
|
||||
xSemaphoreGive(mtx);
|
||||
}
|
||||
|
||||
void __freertos_recursive_mutex_take(SemaphoreHandle_t mtx) {
|
||||
xSemaphoreTakeRecursive(mtx, portMAX_DELAY);
|
||||
}
|
||||
|
||||
int __freertos_recursive_mutex_try_take(SemaphoreHandle_t mtx) {
|
||||
return xSemaphoreTakeRecursive(mtx, 0);
|
||||
}
|
||||
|
||||
void __freertos_recursive_mutex_give(SemaphoreHandle_t mtx) {
|
||||
xSemaphoreGiveRecursive(mtx);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -807,7 +807,7 @@ int HTTPClient::writeToPrint(Print * print) {
|
||||
DEBUG_HTTPCLIENT("[HTTP-Client] chunk header: '%s'\n", chunkHeader.c_str());
|
||||
|
||||
// read size of chunk
|
||||
len = (uint32_t) strtol((const char *) chunkHeader.c_str(), NULL, 16);
|
||||
len = (uint32_t) strtol((const char *) chunkHeader.c_str(), nullptr, 16);
|
||||
size += len;
|
||||
DEBUG_HTTPCLIENT("[HTTP-Client] read chunk len: %d\n", len);
|
||||
|
||||
|
||||
@@ -205,7 +205,7 @@ public:
|
||||
int PATCH(const uint8_t* payload, size_t size);
|
||||
int PATCH(const String& payload);
|
||||
int sendRequest(const char* type, const String& payload);
|
||||
int sendRequest(const char* type, const uint8_t* payload = NULL, size_t size = 0);
|
||||
int sendRequest(const char* type, const uint8_t* payload = nullptr, size_t size = 0);
|
||||
int sendRequest(const char* type, Stream * stream, size_t size = 0);
|
||||
|
||||
void addHeader(const String& name, const String& value, bool first = false, bool replace = true);
|
||||
|
||||
@@ -165,19 +165,19 @@ HTTPUpdateResult HTTPUpdate::handleUpdate(HTTPClient& http, const String& curren
|
||||
http.useHTTP10(true);
|
||||
http.setTimeout(_httpClientTimeout);
|
||||
http.setFollowRedirects(_followRedirects);
|
||||
http.setUserAgent(F("-http-Update"));
|
||||
http.addHeader(F("x--Chip-ID"), String(rp2040.getChipID()));
|
||||
http.addHeader(F("x--STA-MAC"), WiFi.macAddress());
|
||||
http.addHeader(F("x--AP-MAC"), WiFi.softAPmacAddress());
|
||||
http.setUserAgent(F("Pico-HTTP-Update"));
|
||||
http.addHeader(F("x-Pico-Chip-ID"), String(rp2040.getChipID()));
|
||||
http.addHeader(F("x-Pico-STA-MAC"), WiFi.macAddress());
|
||||
http.addHeader(F("x-Pico-AP-MAC"), WiFi.softAPmacAddress());
|
||||
|
||||
if (spiffs) {
|
||||
http.addHeader(F("x--mode"), F("spiffs"));
|
||||
http.addHeader(F("x-Pico-Mode"), F("spiffs"));
|
||||
} else {
|
||||
http.addHeader(F("x--mode"), F("sketch"));
|
||||
http.addHeader(F("x-Pico-Mode"), F("sketch"));
|
||||
}
|
||||
|
||||
if (currentVersion && currentVersion[0] != 0x00) {
|
||||
http.addHeader(F("x--version"), currentVersion);
|
||||
http.addHeader(F("x-Pico-Version"), currentVersion);
|
||||
}
|
||||
|
||||
if (_user != "" && _password != "") {
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
SecureBearSSLUpdater - SSL encrypted, password-protected firmware update
|
||||
|
||||
This example starts a HTTPS server on the Pico to allow firmware updates
|
||||
to be performed. All communication, including the username and password,
|
||||
is encrypted via SSL. Be sure to update the SSID and PASSWORD before running
|
||||
to allow connection to your WiFi network.
|
||||
|
||||
To upload through terminal you can use:
|
||||
curl -u admin:admin -F "image=@firmware.bin" picow-webupdate.local/firmware
|
||||
|
||||
Adapted by Earle F. Philhower, III, from the SecureWebUpdater.ino example.
|
||||
This example is released into the public domain.
|
||||
*/
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <WiFiClient.h>
|
||||
#include <WebServerSecure.h>
|
||||
#include <LEAmDNS.h>
|
||||
#include <HTTPUpdateServer.h>
|
||||
|
||||
#ifndef STASSID
|
||||
#define STASSID "your-ssid"
|
||||
#define STAPSK "your-password"
|
||||
#endif
|
||||
|
||||
const char* host = "picow-webupdate";
|
||||
const char* update_path = "/firmware";
|
||||
const char* update_username = "admin";
|
||||
const char* update_password = "admin";
|
||||
const char* ssid = STASSID;
|
||||
const char* password = STAPSK;
|
||||
|
||||
WebServerSecure httpServer(443);
|
||||
HTTPUpdateServerSecure httpUpdater;
|
||||
|
||||
static const char serverCert[] PROGMEM = R"EOF(
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDSzCCAjMCCQD2ahcfZAwXxDANBgkqhkiG9w0BAQsFADCBiTELMAkGA1UEBhMC
|
||||
VVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU9yYW5nZSBDb3VudHkx
|
||||
EDAOBgNVBAoMB1ByaXZhZG8xGjAYBgNVBAMMEXNlcnZlci56bGFiZWwuY29tMR8w
|
||||
HQYJKoZIhvcNAQkBFhBlYXJsZUB6bGFiZWwuY29tMB4XDTE4MDMwNjA1NDg0NFoX
|
||||
DTE5MDMwNjA1NDg0NFowRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3Rh
|
||||
dGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZI
|
||||
hvcNAQEBBQADggEPADCCAQoCggEBAPVKBwbZ+KDSl40YCDkP6y8Sv4iNGvEOZg8Y
|
||||
X7sGvf/xZH7UiCBWPFIRpNmDSaZ3yjsmFqm6sLiYSGSdrBCFqdt9NTp2r7hga6Sj
|
||||
oASSZY4B9pf+GblDy5m10KDx90BFKXdPMCLT+o76Nx9PpCvw13A848wHNG3bpBgI
|
||||
t+w/vJCX3bkRn8yEYAU6GdMbYe7v446hX3kY5UmgeJFr9xz1kq6AzYrMt/UHhNzO
|
||||
S+QckJaY0OGWvmTNspY3xCbbFtIDkCdBS8CZAw+itnofvnWWKQEXlt6otPh5njwy
|
||||
+O1t/Q+Z7OMDYQaH02IQx3188/kW3FzOY32knER1uzjmRO+jhA8CAwEAATANBgkq
|
||||
hkiG9w0BAQsFAAOCAQEAnDrROGRETB0woIcI1+acY1yRq4yAcH2/hdq2MoM+DCyM
|
||||
E8CJaOznGR9ND0ImWpTZqomHOUkOBpvu7u315blQZcLbL1LfHJGRTCHVhvVrcyEb
|
||||
fWTnRtAQdlirUm/obwXIitoz64VSbIVzcqqfg9C6ZREB9JbEX98/9Wp2gVY+31oC
|
||||
JfUvYadSYxh3nblvA4OL+iEZiW8NE3hbW6WPXxvS7Euge0uWMPc4uEcnsE0ZVG3m
|
||||
+TGimzSdeWDvGBRWZHXczC2zD4aoE5vrl+GD2i++c6yjL/otHfYyUpzUfbI2hMAA
|
||||
5tAF1D5vAAwA8nfPysumlLsIjohJZo4lgnhB++AlOg==
|
||||
-----END CERTIFICATE-----
|
||||
)EOF";
|
||||
|
||||
static const char serverKey[] PROGMEM = R"EOF(
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpQIBAAKCAQEA9UoHBtn4oNKXjRgIOQ/rLxK/iI0a8Q5mDxhfuwa9//FkftSI
|
||||
IFY8UhGk2YNJpnfKOyYWqbqwuJhIZJ2sEIWp2301OnavuGBrpKOgBJJljgH2l/4Z
|
||||
uUPLmbXQoPH3QEUpd08wItP6jvo3H0+kK/DXcDzjzAc0bdukGAi37D+8kJfduRGf
|
||||
zIRgBToZ0xth7u/jjqFfeRjlSaB4kWv3HPWSroDNisy39QeE3M5L5ByQlpjQ4Za+
|
||||
ZM2yljfEJtsW0gOQJ0FLwJkDD6K2eh++dZYpAReW3qi0+HmePDL47W39D5ns4wNh
|
||||
BofTYhDHfXzz+RbcXM5jfaScRHW7OOZE76OEDwIDAQABAoIBAQDKov5NFbNFQNR8
|
||||
djcM1O7Is6dRaqiwLeH4ZH1pZ3d9QnFwKanPdQ5eCj9yhfhJMrr5xEyCqT0nMn7T
|
||||
yEIGYDXjontfsf8WxWkH2TjvrfWBrHOIOx4LJEvFzyLsYxiMmtZXvy6YByD+Dw2M
|
||||
q2GH/24rRdI2klkozIOyazluTXU8yOsSGxHr/aOa9/sZISgLmaGOOuKI/3Zqjdhr
|
||||
eHeSqoQFt3xXa8jw01YubQUDw/4cv9rk2ytTdAoQUimiKtgtjsggpP1LTq4xcuqN
|
||||
d4jWhTcnorWpbD2cVLxrEbnSR3VuBCJEZv5axg5ZPxLEnlcId8vMtvTRb5nzzszn
|
||||
geYUWDPhAoGBAPyKVNqqwQl44oIeiuRM2FYenMt4voVaz3ExJX2JysrG0jtCPv+Y
|
||||
84R6Cv3nfITz3EZDWp5sW3OwoGr77lF7Tv9tD6BptEmgBeuca3SHIdhG2MR+tLyx
|
||||
/tkIAarxQcTGsZaSqra3gXOJCMz9h2P5dxpdU+0yeMmOEnAqgQ8qtNBfAoGBAPim
|
||||
RAtnrd0WSlCgqVGYFCvDh1kD5QTNbZc+1PcBHbVV45EmJ2fLXnlDeplIZJdYxmzu
|
||||
DMOxZBYgfeLY9exje00eZJNSj/csjJQqiRftrbvYY7m5njX1kM5K8x4HlynQTDkg
|
||||
rtKO0YZJxxmjRTbFGMegh1SLlFLRIMtehNhOgipRAoGBAPnEEpJGCS9GGLfaX0HW
|
||||
YqwiEK8Il12q57mqgsq7ag7NPwWOymHesxHV5mMh/Dw+NyBi4xAGWRh9mtrUmeqK
|
||||
iyICik773Gxo0RIqnPgd4jJWN3N3YWeynzulOIkJnSNx5BforOCTc3uCD2s2YB5X
|
||||
jx1LKoNQxLeLRN8cmpIWicf/AoGBANjRSsZTKwV9WWIDJoHyxav/vPb+8WYFp8lZ
|
||||
zaRxQbGM6nn4NiZI7OF62N3uhWB/1c7IqTK/bVHqFTuJCrCNcsgld3gLZ2QWYaMV
|
||||
kCPgaj1BjHw4AmB0+EcajfKilcqtSroJ6MfMJ6IclVOizkjbByeTsE4lxDmPCDSt
|
||||
/9MKanBxAoGAY9xo741Pn9WUxDyRplww606ccdNf/ksHWNc/Y2B5SPwxxSnIq8nO
|
||||
j01SmsCUYVFAgZVOTiiycakjYLzxlc6p8BxSVqy6LlJqn95N8OXoQ+bkwUux/ekg
|
||||
gz5JWYhbD6c38khSzJb0pNXCo3EuYAVa36kDM96k1BtWuhRS10Q1VXk=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
)EOF";
|
||||
|
||||
|
||||
void setup() {
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println();
|
||||
Serial.println("Booting Sketch...");
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.begin(ssid, password);
|
||||
|
||||
while (WiFi.waitForConnectResult() != WL_CONNECTED) {
|
||||
WiFi.begin(ssid, password);
|
||||
Serial.println("WiFi failed, retrying.");
|
||||
}
|
||||
|
||||
configTime(3 * 3600, 0, "pool.ntp.org", "time.nist.gov");
|
||||
|
||||
MDNS.begin(host);
|
||||
|
||||
httpServer.getServer().setRSACert(new BearSSL::X509List(serverCert), new BearSSL::PrivateKey(serverKey));
|
||||
httpUpdater.setup(&httpServer, update_path, update_username, update_password);
|
||||
httpServer.begin();
|
||||
|
||||
MDNS.addService("https", "tcp", 443);
|
||||
Serial.printf("BearSSLUpdateServer ready!\nOpen https://%s.local%s in "
|
||||
"your browser and login with username '%s' and password "
|
||||
"'%s'\n",
|
||||
host, update_path, update_username, update_password);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
httpServer.handleClient();
|
||||
MDNS.update();
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
To upload through terminal you can use: curl -F "image=@firmware.bin" picow-webupdate.local/update
|
||||
*/
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <WiFiClient.h>
|
||||
#include <WebServer.h>
|
||||
#include <LEAmDNS.h>
|
||||
#include <HTTPUpdateServer.h>
|
||||
|
||||
#ifndef STASSID
|
||||
#define STASSID "your-ssid"
|
||||
#define STAPSK "your-password"
|
||||
#endif
|
||||
|
||||
const char* host = "picow-webupdate";
|
||||
const char* ssid = STASSID;
|
||||
const char* password = STAPSK;
|
||||
|
||||
WebServer httpServer(80);
|
||||
HTTPUpdateServer httpUpdater;
|
||||
|
||||
void setup(void) {
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println();
|
||||
Serial.println("Booting Sketch...");
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.begin(ssid, password);
|
||||
|
||||
while (WiFi.waitForConnectResult() != WL_CONNECTED) {
|
||||
WiFi.begin(ssid, password);
|
||||
Serial.println("WiFi failed, retrying.");
|
||||
}
|
||||
|
||||
MDNS.begin(host);
|
||||
|
||||
httpUpdater.setup(&httpServer);
|
||||
httpServer.begin();
|
||||
|
||||
MDNS.addService("http", "tcp", 80);
|
||||
Serial.printf("HTTPUpdateServer ready! Open http://%s.local/update in your browser\n", host);
|
||||
}
|
||||
|
||||
void loop(void) {
|
||||
httpServer.handleClient();
|
||||
MDNS.update();
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
To upload through terminal you can use: curl -u admin:admin -F "image=@firmware.bin" picow-webupdate.local/firmware
|
||||
*/
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <WiFiClient.h>
|
||||
#include <WebServer.h>
|
||||
#include <LEAmDNS.h>
|
||||
#include <HTTPUpdateServer.h>
|
||||
|
||||
#ifndef STASSID
|
||||
#define STASSID "your-ssid"
|
||||
#define STAPSK "your-password"
|
||||
#endif
|
||||
|
||||
const char* host = "picow-webupdate";
|
||||
const char* update_path = "/firmware";
|
||||
const char* update_username = "admin";
|
||||
const char* update_password = "admin";
|
||||
const char* ssid = STASSID;
|
||||
const char* password = STAPSK;
|
||||
|
||||
WebServer httpServer(80);
|
||||
HTTPUpdateServer httpUpdater;
|
||||
|
||||
void setup(void) {
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println();
|
||||
Serial.println("Booting Sketch...");
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.begin(ssid, password);
|
||||
|
||||
while (WiFi.waitForConnectResult() != WL_CONNECTED) {
|
||||
WiFi.begin(ssid, password);
|
||||
Serial.println("WiFi failed, retrying.");
|
||||
}
|
||||
|
||||
MDNS.begin(host);
|
||||
|
||||
httpUpdater.setup(&httpServer, update_path, update_username, update_password);
|
||||
httpServer.begin();
|
||||
|
||||
MDNS.addService("http", "tcp", 80);
|
||||
Serial.printf("HTTPUpdateServer ready! Open http://%s.local%s in your browser and login with username '%s' and password '%s'\n", host, update_path, update_username, update_password);
|
||||
}
|
||||
|
||||
void loop(void) {
|
||||
httpServer.handleClient();
|
||||
MDNS.update();
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#######################################
|
||||
# Syntax Coloring Map For HTTPUpdateServer
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
HTTPUpdateServer KEYWORD1
|
||||
HTTPUpdateServerSecure KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
begin KEYWORD2
|
||||
setup KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
@@ -0,0 +1,10 @@
|
||||
name=HTTPUpdateServer
|
||||
version=1.0
|
||||
author=Ivan Grokhotkov, Miguel Angel Ajo
|
||||
maintainer=Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||
sentence=Simple HTTP Update server based on the Pico WebServer
|
||||
paragraph=The library accepts HTTP post requests to the /update url, and updates the Pico firmware.
|
||||
category=Communication
|
||||
url=https://github.com/earlephilhower/arduino-pico
|
||||
architectures=rp2040
|
||||
dot_a_linkage=false
|
||||
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
HTTPUpdateServer - Support simple web based OTA
|
||||
Modified 2022 Earle F. Philhower, III. All rights reserved.
|
||||
|
||||
Ported from the ESP8266 Arduino core, (c) copyright multiple authors
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <WiFiClient.h>
|
||||
#include <WiFiServer.h>
|
||||
#include <WebServer.h>
|
||||
#include <WiFiUdp.h>
|
||||
#include <LittleFS.h>
|
||||
#include "StreamString.h"
|
||||
#include "HTTPUpdateServer.h"
|
||||
|
||||
extern uint8_t _FS_start;
|
||||
extern uint8_t _FS_end;
|
||||
|
||||
|
||||
static const char serverIndex[] PROGMEM =
|
||||
R"(<!DOCTYPE html>
|
||||
<html lang='en'>
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<meta name='viewport' content='width=device-width,initial-scale=1'/>
|
||||
</head>
|
||||
<body>
|
||||
<form method='POST' action='' enctype='multipart/form-data'>
|
||||
Firmware:<br>
|
||||
<input type='file' accept='.bin,.bin.gz' name='firmware'>
|
||||
<input type='submit' value='Update Firmware'>
|
||||
</form>
|
||||
<form method='POST' action='' enctype='multipart/form-data'>
|
||||
FileSystem:<br>
|
||||
<input type='file' accept='.bin,.bin.gz' name='filesystem'>
|
||||
<input type='submit' value='Update FileSystem'>
|
||||
</form>
|
||||
</body>
|
||||
</html>)";
|
||||
static const char successResponse[] PROGMEM =
|
||||
"<META http-equiv=\"refresh\" content=\"15;URL=/\">Update Success! Rebooting...";
|
||||
|
||||
template <typename ServerType, int ServerPort>
|
||||
HTTPUpdateServerTemplate<ServerType, ServerPort>::HTTPUpdateServerTemplate(bool serial_debug) {
|
||||
_serial_output = serial_debug;
|
||||
_server = nullptr;
|
||||
_username = "";
|
||||
_password = "";
|
||||
_authenticated = false;
|
||||
}
|
||||
|
||||
template <typename ServerType, int ServerPort>
|
||||
void HTTPUpdateServerTemplate<ServerType, ServerPort>::setup(WebServerTemplate<ServerType, ServerPort> *server, const String& path, const String& username, const String& password) {
|
||||
_server = server;
|
||||
_username = username;
|
||||
_password = password;
|
||||
|
||||
// handler for the /update form page
|
||||
_server->on(path.c_str(), HTTP_GET, [&]() {
|
||||
if (_username != "" && _password != "" && !_server->authenticate(_username.c_str(), _password.c_str())) {
|
||||
return _server->requestAuthentication();
|
||||
}
|
||||
_server->send_P(200, PSTR("text/html"), serverIndex);
|
||||
});
|
||||
|
||||
// handler for the /update form page - preflight options
|
||||
_server->on(path.c_str(), HTTP_OPTIONS, [&]() {
|
||||
_server->sendHeader("Access-Control-Allow-Headers", "*");
|
||||
_server->sendHeader("Access-Control-Allow-Origin", "*");
|
||||
_server->send(200, F("text/html"), String(F("y")));
|
||||
}, [&]() {
|
||||
_authenticated = (_username == "" || _password == "" || _server->authenticate(_username.c_str(), _password.c_str()));
|
||||
if (!_authenticated) {
|
||||
if (_serial_output) {
|
||||
Serial.printf("Unauthenticated Update\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
// handler for the /update form POST (once file upload finishes)
|
||||
_server->on(path.c_str(), HTTP_POST, [&]() {
|
||||
_server->sendHeader("Access-Control-Allow-Headers", "*");
|
||||
_server->sendHeader("Access-Control-Allow-Origin", "*");
|
||||
if (!_authenticated) {
|
||||
return _server->requestAuthentication();
|
||||
}
|
||||
if (Update.hasError()) {
|
||||
_server->send(200, F("text/html"), String(F("Update error: ")) + _updaterError);
|
||||
} else {
|
||||
_server->client().setNoDelay(true);
|
||||
_server->send_P(200, PSTR("text/html"), successResponse);
|
||||
delay(100);
|
||||
_server->client().stop();
|
||||
rp2040.restart();
|
||||
}
|
||||
}, [&]() {
|
||||
// handler for the file upload, gets the sketch bytes, and writes
|
||||
// them through the Update object
|
||||
HTTPUpload& upload = _server->upload();
|
||||
|
||||
if (upload.status == UPLOAD_FILE_START) {
|
||||
_updaterError = "";
|
||||
|
||||
_authenticated = (_username == "" || _password == "" || _server->authenticate(_username.c_str(), _password.c_str()));
|
||||
if (!_authenticated) {
|
||||
if (_serial_output) {
|
||||
Serial.printf("Unauthenticated Update\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (_serial_output) {
|
||||
Serial.printf("Update: %s\n", upload.filename.c_str());
|
||||
}
|
||||
if (upload.name == "filesystem") {
|
||||
size_t fsSize = ((size_t)&_FS_end - (size_t)&_FS_start);
|
||||
LittleFS.end();
|
||||
if (!Update.begin(fsSize, U_FS)) { //start with max available size
|
||||
if (_serial_output) {
|
||||
Update.printError(Serial);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
FSInfo64 i;
|
||||
LittleFS.begin();
|
||||
LittleFS.info64(i);
|
||||
uint32_t maxSketchSpace = i.totalBytes - i.usedBytes;
|
||||
if (!Update.begin(maxSketchSpace, U_FLASH)) { //start with max available size
|
||||
_setUpdaterError();
|
||||
}
|
||||
}
|
||||
} else if (_authenticated && upload.status == UPLOAD_FILE_WRITE && !_updaterError.length()) {
|
||||
if (_serial_output) {
|
||||
Serial.printf(".");
|
||||
}
|
||||
if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
|
||||
_setUpdaterError();
|
||||
}
|
||||
} else if (_authenticated && upload.status == UPLOAD_FILE_END && !_updaterError.length()) {
|
||||
if (Update.end(true)) { //true to set the size to the current progress
|
||||
if (_serial_output) {
|
||||
Serial.printf("Update Success: %zu\nRebooting...\n", upload.totalSize);
|
||||
}
|
||||
} else {
|
||||
_setUpdaterError();
|
||||
}
|
||||
} else if (_authenticated && upload.status == UPLOAD_FILE_ABORTED) {
|
||||
Update.end();
|
||||
if (_serial_output) {
|
||||
Serial.println("Update was aborted");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template <typename ServerType, int ServerPort>
|
||||
void HTTPUpdateServerTemplate<ServerType, ServerPort>::_setUpdaterError() {
|
||||
if (_serial_output) {
|
||||
Update.printError(Serial);
|
||||
}
|
||||
StreamString str;
|
||||
Update.printError(str);
|
||||
_updaterError = str.c_str();
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
HTTPUpdateServer - Support simple web based OTA
|
||||
Modified 2022 Earle F. Philhower, III. All rights reserved.
|
||||
|
||||
Ported from the ESP8266 Arduino core, (c) copyright multiple authors
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <WebServer.h>
|
||||
|
||||
template <typename ServerType, int ServerPort>
|
||||
class HTTPUpdateServerTemplate {
|
||||
public:
|
||||
HTTPUpdateServerTemplate(bool serial_debug = false);
|
||||
|
||||
void setup(WebServerTemplate<ServerType, ServerPort> *server) {
|
||||
setup(server, "", "");
|
||||
}
|
||||
|
||||
void setup(WebServerTemplate<ServerType, ServerPort> *server, const String& path) {
|
||||
setup(server, path, "", "");
|
||||
}
|
||||
|
||||
void setup(WebServerTemplate<ServerType, ServerPort> *server, const String& username, const String& password) {
|
||||
setup(server, "/update", username, password);
|
||||
}
|
||||
|
||||
void setup(WebServerTemplate<ServerType, ServerPort> *server, const String& path, const String& username, const String& password);
|
||||
|
||||
void updateCredentials(const String& username, const String& password) {
|
||||
_username = username;
|
||||
_password = password;
|
||||
}
|
||||
|
||||
protected:
|
||||
void _setUpdaterError();
|
||||
|
||||
private:
|
||||
bool _serial_output;
|
||||
WebServerTemplate<ServerType, ServerPort> *_server;
|
||||
String _username;
|
||||
String _password;
|
||||
bool _authenticated;
|
||||
String _updaterError;
|
||||
};
|
||||
|
||||
#include "HTTPUpdateServer-impl.h"
|
||||
|
||||
using HTTPUpdateServer = HTTPUpdateServerTemplate<WiFiServer, 80>;
|
||||
using HTTPUpdateServerSecure = HTTPUpdateServerTemplate<WiFiServerSecure, 443>;
|
||||
@@ -22,8 +22,7 @@
|
||||
|
||||
*/
|
||||
|
||||
#ifndef MDNS_PRIV_H
|
||||
#define MDNS_PRIV_H
|
||||
#pragma once
|
||||
|
||||
namespace esp8266 {
|
||||
|
||||
@@ -186,5 +185,3 @@ namespace MDNSImplementation {
|
||||
|
||||
// Include the main header, so the submodlues only need to include this header
|
||||
#include "LEAmDNS.h"
|
||||
|
||||
#endif // MDNS_PRIV_H
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user