Compare commits

...
188 Commits
Author SHA1 Message Date
Earle F. Philhower, III d9478801ed Update version 2022-09-21 17:56:26 -07:00
Earle F. Philhower, III 77fe24f798 Update Cytron Pico SPI pinout (#869)
See #851.  Add SPI1.
2022-09-21 17:55:41 -07:00
Brent Rubell 4e77ee02e8 Add WDT functions to RP2040 Helper (#862) 2022-09-21 17:51:42 -07:00
Pontus Oldberg 91b4bdb58f Adds Challenger RP2040 NFC board (#846) 2022-09-09 07:41:33 -07:00
Dario GogliandoloandDario Gogliandolo d6628972c5 Enabled static memory allocation with example (#842)
Co-authored-by: Dario Gogliandolo <dario.gogliandolo@smartme.io>
2022-09-08 07:09:38 -07:00
Earle F. Philhower, III b0d0e292c9 Minor - Add number separators (#845) 2022-09-07 15:19:12 -07:00
Earle F. Philhower, III e2b04e7405 Minor tweak, NULL=>nullptr (#844) 2022-09-07 14:41:04 -07:00
Earle F. Philhower, III f79b0867b6 Remove duplicated ArduinoCore-API files (#840)
Use #include .... to reference them from the cores directory to ensure
they keep up to date.
2022-09-06 13:21:49 -07:00
Earle F. Philhower, III db337a9b36 Increase SerialUSB speed (#833)
Add calls to `tud_task` to pump the USB interface in the SerialUSB methods.

See #832 for more info.
2022-09-06 12:44:34 -07:00
Khoi Hoang 1303ef55b2 Add Serial3 for Arduino Nano Connect RP2040. Fix #807 (#838) 2022-09-06 12:34:49 -07:00
Earle F. Philhower, III 85d39cf242 Restore GPIO functions on SerialUART::end (#836)
Fix #834
2022-09-04 19:23:51 -07:00
Earle F. Philhower, III 2d777accc6 Update README.md 2022-09-04 11:38:58 -07:00
Earle F. Philhower, III 3f36f7fab1 Update README.md 2022-09-04 11:38:46 -07:00
Earle F. Philhower, III 1812b829dc Update version 2022-09-03 09:34:46 -07:00
Earle F. Philhower, III 36d5cebde6 Remove binary info header, was crashing picotool (#831)
Because OTA has changed the flash map from standard, picotool ends up
crashing or hanging while trying to operate on the current built files.

Remove the binary_info calls and structures completely to avoid any
issue.

Fixes #803
2022-09-02 23:17:03 -07:00
Earle F. Philhower, III 34d311fd81 Update version 2022-09-02 08:59:01 -07:00
Earle F. Philhower, III 59bd3b5144 Update DNSServer.h 2022-09-01 21:04:41 -07:00
Earle F. Philhower, III 805d20d199 Use pipes between GCC stages (#827)
Should speed builds up slightly, depending on the OS and virus scanning.
2022-09-01 18:49:05 -07:00
Earle F. Philhower, III 166f63f955 Update PicoOTA.h 2022-08-31 14:40:53 -07:00
Earle F. Philhower, III d2beb2da19 Add upsteam multicast compatibility APIs (#821)
Fixes #747 while remaining ESP8266 compatible
2022-08-31 11:06:18 -07:00
Earle F. Philhower, III 7ef44d9878 Clean up WebServer send() methods (#820)
Avoid creating Strings when sending out results.
2022-08-31 08:21:16 -07:00
Earle F. Philhower, III 408813c387 Add SDFS header to SpeedTest to simplify use 2022-08-31 08:09:42 -07:00
Earle F. Philhower, III 4d2f64a12b Add bidirectional bulk SPI transfer, update SdFAT (#819)
Should speed up SD transfers significantly (2.5x+).

See #801
2022-08-31 07:42:34 -07:00
Earle F. Philhower, III 9997461e3a Shrink MIME table flash usage by ~500 bytes (#818)
Decreases WebServer sketch sizes.
2022-08-30 19:21:57 -07:00
Earle F. Philhower, III 4699522299 Remove completed TODO 2022-08-30 16:28:24 -07:00
Earle F. Philhower, III a582ca7b95 Avoid potential lockup w/Serial.read unconnected (#817)
Fixes #816

If a byte is available, return it even if the USB stack reports
disconnected.
2022-08-30 12:05:08 -07:00
Filipe Mendonça 024ae9bb42 Fix WiFi MAC Address string output (#812)
Fixes #811
2022-08-29 17:51:40 -07:00
Earle F. Philhower, III 38bcf4f956 Minor WebServer style/unused var cleanup (#810) 2022-08-29 13:25:32 -07:00
Earle F. Philhower, III 486caf42a0 Remove microscopic malloc() from WebServer (#809)
Don't try and heap allocate temporaty <16b chunks.
2022-08-29 12:35:14 -07:00
Earle F. Philhower, III 92f2ca9108 Don't re-initialize ADC for every reading (#808) 2022-08-29 11:46:05 -07:00
Earle F. Philhower, III bde4da2b7e Protect core/Newlib mutexes from task preemption under FreeRTOS (#798)
Fixes #795 

Replace all CoreMutex and Newlib mutex accesses with FreeRTOS calls
when in FreeRTOS mode.  Avoid issues with hange/etc. due to priority
inversion.

No changes to normal operating mode.

Add a FreeRTOS stress test that caught the issue fixed here.
2022-08-29 08:56:59 -07:00
Earle F. Philhower, III b4b1c39049 Add ExteremeElectric JSON 2022-08-28 12:38:14 -07:00
Earle F. Philhower, III b233cb6e7f Identify boards when in compound USB device mode (#806)
Allows the IDE to detect boards when using the Keyboard, Joystick,
or Mouse libraries.

Thanks @DaleMitchell for the idea!
2022-08-28 12:34:06 -07:00
Danilo Campos 95d1bfb760 Add Home Assistant starter to tutorials listing (#804) 2022-08-28 09:45:49 -07:00
Earle F. Philhower, III 064dd4794f Minor header/directrory cleanup (#802) 2022-08-27 13:04:57 -07:00
Earle F. Philhower, III 257db5ac7d Update version 2022-08-27 09:33:50 -07:00
Earle F. Philhower, III 9ff31b91f4 Add ExtremeElectronics RC2040 (#799)
Fixes #797
2022-08-25 12:47:39 -07:00
Earle F. Philhower, III 0edba2ee2a Add WebServer, WebServerSecure, HTTPUpdateServer, HTTPUpdateServerSecure (#791)
* Add HTTP-parser lib to support ESP32 WebServer
* Add WebServer from ESP32.  Only supports HTTP
* Separate HTTP server from the network server
Instead of managing the WiFiServer/WiFiServerSecure in the same object
as the HTTP handling, split them into separate objects.  This lets
HTTP and HTTPS servers work without templates or duplicating code.
The HTTP block just gets a `WiFiClient*` and works with that to only
do HTTP processing, while the upper object handles the appropriate
server and client types.
* Add HTTPS server
* Clean up some THandlerFunction refs
* Refactor into a template-ized WebServer/WebServerSecure
* Add DNSServer examples which need WebServer
* Fix CoreMutex infinite recursion crash
Core could crash while Serial debugging was going on and prints were
happening from LWIP/IRQ land and the main app.
* Add HTTPUpdateServer(Secure)
* Add MIME include, optimize WebServer::send(size,len)
When send()ing a large buffer, the WebServer::send() call would
actually convert that buffer into a String (i.e. duplicate it, and
potential issues with embedded \0s in binary data).
Make a simple override to send(size, len) to allow writing from the
source buffer instead.
* Fix WiFiClient::send(Stream), add FSBrowser example
2022-08-23 15:51:32 -07:00
NuclearPhoenix c501306c4f Fix functions in docs: RP2040 Helper Class (#793) 2022-08-23 07:40:18 -07:00
Earle F. Philhower, III 8aad2ca3d2 Update version 2022-08-21 19:54:11 -07:00
Earle F. Philhower, III de215a6e1b Add WiFi.getHostname() call 2022-08-21 19:53:18 -07:00
Earle F. Philhower, III 0b390d7dc4 Add HTTPUpdate class to pull updates from HTTP(S) (#789)
* Add HTTPUpdate class to pull updates from HTTP(S)
* Increase GH runners for pulls
WiFi builds and examples are taking some serious time now
* HTTPUpdate tests build on Pico W
2022-08-21 18:24:59 -07:00
Earle F. Philhower, III a3f5fee6a5 Make StreamDev stubs private to HTTPClient (#788) 2022-08-21 17:20:34 -07:00
Earle F. Philhower, III a3f4d89bc4 Ensure OTA errors are sent in single UDP packet (#787)
OTA text error messages were getting lost because they were sent in
multiple UDP packets, one per print(). Now collect the full error and
report in a single print, allowing text messages to appear in ESPOTA.
2022-08-21 15:29:23 -07:00
Earle F. Philhower, III 2044d2e51c Fix OTA signing (#786)
Force the builder to include the path where we build the signing header.

Undo a breaking bug in the Updater class (TBD fix in ESP8266)

Fixes #783
2022-08-21 15:20:00 -07:00
Earle F. Philhower, III f9e3278863 Report "no filesystem" on OTA uploads w/o a FS (#785)
Give a meaningful error when OTA is attempted against a chip which does
not have a filesystem configured.
2022-08-21 13:19:26 -07:00
Earle F. Philhower, III 0d15723444 Add HTTPClient, ported from the ESP8266 (#784)
Remove the need to have a separate WiFiClient that's destroyed after
the HTTPClient.  Let the object handle its own client, and pass through
any SSL requests.

Also supports the original ::begin methods which need a
WiFiClient(Secure) to be passed in and managed by the app.
2022-08-21 12:49:06 -07:00
Earle F. Philhower, III 6e0d6a27ec Avoid rescanning/connecting on WiFiMulti.run (#782)
If the WiFi network is already up, don't run the scan and connection
algorithm in WiFiMulti.
2022-08-21 08:33:17 -07:00
Earle F. Philhower, III a2465f5fb7 Port ESP8266 DNSServer (#779)
Add a simple DNS server for AP mode
Point DHCP server DNS entry to GW for DNSServer
2022-08-20 17:58:54 -07:00
arturo182 88e98f17b6 EEPROM: Add an update function (#780)
According to the Arduino docs, update works just like put, but it first checks if the value is different from the current one.
This is how our put already works, so we just alias update to put and we're done.
Function added to be more compatible with the Arduino API.
Also see #778
2022-08-20 17:50:40 -07:00
Earle F. Philhower, III b4db1ad54a Fix softAP config call 2022-08-20 12:24:08 -07:00
Earle F. Philhower, III 7be472932b Add ESP8266 compat functions for AP mode (#777)
Fixes #767
2022-08-20 12:00:05 -07:00
Earle F. Philhower, III d019f31ef1 Report ::connected() as false when WiFi link drops (#774)
There may be an issue in the CYW43 driver that causes a link to never be
reported as going down once it has connected, when it was disassociated or
when the wlan shuts off unexpectedly.

Work around it by clearing the internal link active in a TCP callback for
the CYW43 driver.

Reports disconnection properly now, as well as reconnection.

Fixes #762
2022-08-19 18:03:21 -07:00
Earle F. Philhower, III e2afeaef27 Add simple WiFiMulti support (#771)
Takes a list of APs, finds the one with highest RSSI, and tries to connect.
2022-08-19 12:28:56 -07:00
Earle F. Philhower, III 2b6ab6c19d Don't return from reboot (#772)
rp2040.reboot() would set a reboot timer for 100ms in the future, but then
return to user code and ran it until the timer expired.  Now infinite loop
until the WDT fires.
2022-08-19 12:21:17 -07:00
Earle F. Philhower, III 0ef026cfa4 Avoid spurious -O3 warning (#770)
Fixes #768
2022-08-18 13:56:09 -07:00
Earle F. Philhower, III 5787b4c02b Allow selecting SPI port for SD/SDFS filesystem (#759)
Fixes #758
2022-08-14 21:59:13 -07:00
Earle F. Philhower, III e947895119 Update version 2022-08-12 12:29:32 -07:00
Earle F. Philhower, III bb91d978b1 Add OTA.O to make p.io builds function (#755)
Partial #754
2022-08-12 06:09:29 -07:00
Earle F. Philhower, III da86a8942b Add OTA update support (#711)
Adds a 12K OTA stub 3rd stage bootloader, which reads new firmware
from the LittleFS filesystem and flashes on reboot.

By storing the OTA commands in a file in flash, it is possible to
recover from a power failure during OTA programming.  On power
resume, the OTA block will simply re-program from the beginning.

Support cryptographic signed OTA updates, if desired.  Includes
host-side signing logic via openssl.

Add PicoOTA library which encapsulates the file format for
the updater, including CRC32 checking.

Add LEAmDNS support to allow Arduino IDE discovery

Add ArduinoOTA class for IDE uploads

Add MD5Builder class

Add Updater class which supports writing and validating
cryptographically signed binaries from any source (http,
Ethernet, WiFi, Serial, etc.)

Add documentation and readmes.
2022-08-12 00:26:51 -07:00
freeasabeer 71be07e69f Increase FreeRTOS timer task stack to 1024 (#752) 2022-08-11 14:30:57 -07:00
Odd Stråbø be18c76c99 Udp: default local_ip to IP_ANY_TYPE when IPv6 is enabled (#750) 2022-08-10 15:25:02 -07:00
Earle F. Philhower, IIIandOdd Stråbø af2671d8eb IPv6 initial support from @oddstr13 (#748)
* Apply @oddstr13 multicast patch to cyw43 driver
* Initial work for enabling IPv6
* Allow accessing CYW43 stats when LWIP_SYS_CHECK_MS is not set
* Use cyw43_set_allmulti to allow receiving multicast
* Add tools/libpico/build to gitignore

Co-authored-by: Odd Stråbø <oddstr13@openshell.no>
2022-08-09 18:05:43 -07:00
Maximilian Gerhardt 11cb82b058 Fix typo in XIAO board name (#745) 2022-08-09 09:57:51 -07:00
Earle F. Philhower, III ab6a2aaadb Update README.md 2022-08-07 21:36:23 -07:00
Sabas a358f892d3 Add board ElectronicCats Hunter Cat NFC (#741)
* add board ElectronicCats Hunter Cat NFC

* update huntercat nfc
2022-08-07 21:36:04 -07:00
Earle F. Philhower, III cabb06d495 Fix UART wrong ::available() during wraparound (#739)
Fixes #735 .  Thanks to @ Haggarman for the find and fix.
2022-08-06 09:38:16 -07:00
Earle F. Philhower, III 005cba3acd Stop random crashes while writing to flash (#730)
FreeRTOS SMP was updated to:
a) Move ths SYSTICK handler, which cannot be disabled and can fire
   even with IRQs disabled, to RAM
b) Add a flag from the core to the SYSTICK handler to hold off on
   any PendSV (task switch) calls while we are doing the idleOtherCore.

The core now sets this flag, _holdPendSV, and adds add'l FreeRTOS SMP
calls to really, really tell the OS we can't, don't, and better not
be swapped out while writing to flash.

Fixes #719
2022-07-29 22:40:48 -07:00
Earle F. Philhower, III bb029cc287 Increase LWIP MEM_SIZE to > TCP_SND_BUF (#731)
The send buffers are set to 8 * MSS = ~11.5K.  MEM_SIZE is now set to
be larger than that, 16K, in order to help avoid having tcp_write fail
with ENOMEM.  The attempt to use a smaller size is still included, which
will allow a tcp_write of up to 16 * 16K = 256K, i.e. all of memory.

Fixes #725
2022-07-29 22:35:37 -07:00
Earle F. Philhower, III 8fd56ada8b Adjust tcp_write size when memory is tight (#729)
Increases the MEM_SIZE outstanding write buffer to 8K

Allows the ClientContext to attempt to send smaller buffer chunks in the
case where MEM_SIZE won't allow the full tcp_sndbuf() transfer.

Fixes #725
2022-07-29 13:40:03 -07:00
Earle F. Philhower, III 5ab19e9a9f Fix I2S timing (#728)
BCLK was running at 50% of expected speed.

Fixes #714
2022-07-29 12:40:04 -07:00
Earle F. Philhower, III 82abc76e0c Add CMSIS defines to Platform.io (#721)
Ref: https://github.com/earlephilhower/arduino-pico/pull/717#issuecomment-1197921851
2022-07-28 12:29:16 -07:00
AngeloGioacchino Del Regno 6e0175bd8e platform.txt: Add compiler flags for ARM CMSIS (#717)
Adds compiler flags to correctly build Cortex-M0/M0+ code variants for
libraries inside of the ARM CMSIS codebase.

This was tested with the Arduino_CMSIS-DSP library.
2022-07-27 19:11:50 -07:00
Pontus OldbergandEarle F. Philhower, III e6e87fd307 Added to possibility to have extra compiler directives for a board. (#713)
* Adds support for Challenger RP2040 WiFi boards

* Added Challenger board to makeboards build script

* Adds new challenger board with LTE modem.

* Updated after getting approved PID from Raspberry Pi

* Add support for reverse numbering of analog pins.

* Added minimal HW support for onboard WiFi modem.

* Added challenger-nb-rp2040-wifi and RPICO32 module.

* Updated PID for RPICO32

* Added a simple support class for challenger LTE boards

* Update ChallengerLTE.cpp

Fixed spelling error

* Adds option for setting USB max power in makeboards.py

* Added new board Challenger RP2040 LoRa

* Added new lora board to readme.

* Added missing SERIAL2 and LoRa module GIO pins.

* Added support for enabling UART CTS and RTS pins.

* Updated boards.txt after merge conflict of makeboards.py

* Fixed incorrect indention

* Fixed PR comments

* Add new Challenger RP2040 WiFi/BLE board (https://ilabs.se/challenger-rp2040-wifi-ble-datasheet)

* * Updated PID for WiFi/BLE board
* Added abstraction pins for both versions of wifi modules
* Added support for replacing support class serial port.
* Added support for retrieving support class serial port.

* Fixed spelling errors.

* Updated helper class for Challenger NB board.

* Added Challenger sdrtc and subghz boards.

* Updated readme.

* Re ran makeboards to generate new index.

* Added to possibility to have extra compiler directives for a board.

* Added extra compiler options to JSON generation.

* Allows having a list of extra macros to define

* Fixed incorrect USB PID for Challenger NB board.

* Added board initialization for all wifi boards.

Co-authored-by: Earle F. Philhower, III <earlephilhower@yahoo.com>
2022-07-27 08:36:50 -07:00
Earle F. Philhower, III 1f5139d209 Update version 2022-07-24 12:58:02 -07:00
Earle F. Philhower, III 2397d034e3 Remove SPI init from CYW43 ethernet shim 2022-07-23 14:20:10 -07:00
Earle F. Philhower, III c889a3c1f0 Add NTP waitSet callback (#705)
Allows printing "."s or flashing an LED while NTP is waiting for sync.
2022-07-23 14:07:11 -07:00
Earle F. Philhower, III cfc05dab2c Add basic ESP32 WiFiClientSecure support (#704)
Simple sketches should work without modification, but some modes (listed
in the docs) are not possible to support on the Pico W with BearSSL.

Fixes #691
2022-07-23 10:59:40 -07:00
Earle F. Philhower, III 4a174106cc Add BearSSL to README 2022-07-22 12:48:52 -07:00
Earle F. Philhower, III f04c8536c8 Make AP mode report WL_CONNECTED (#702) 2022-07-22 12:32:28 -07:00
Earle F. Philhower, III a97dc38e87 Uploading for the first time docs from @fjansson (#699)
Fixes #688
2022-07-21 12:09:49 -07:00
Earle F. Philhower, III 042c6af887 Add USB VID/PID to Platform.IO HWIDs (#698) 2022-07-21 12:08:21 -07:00
Earle F. Philhower, III 0e18f0986a Enable IPv4 or IPv4/IPv6 stacks, Ethernet class (#695)
IPv4-only mode saves 20KB+ of flash memory.

Add some backwards compatibility with the global Arduino Ethernet
class when running in IPv4 only mode.

Fixes #687

* Speed P.IO build by not cloning 2GB of sources
* Document P.IO new option
2022-07-21 11:57:21 -07:00
Maximilian Gerhardt 40f4fdf246 Fix PlatformIO linking for variant-specific overrides (#696) 2022-07-21 04:49:09 -07:00
Benjamin AignerandBenjamin Aigner 67b3c8fc25 Adding a Joystick library, concurrently usable with Keyboard & Mouse (#692)
Co-authored-by: Benjamin Aigner <beni@asterics-foundation.org>
2022-07-21 04:40:04 -07:00
Earle F. Philhower, III b88ad3d143 Support original Pico with ROM B0 (#693)
The SDK disabled float/double support for some functions by default on the
original B0 ROMs.  Manually re-enable it.

Fixes #689
2022-07-20 12:07:34 -07:00
Maximilian Gerhardt be9e25785c Correct PlatformIO build for Pico W, add to CI (#686)
* Add LWIP defines from platform.txt

* Add WiFi example to PIO CI
2022-07-19 08:09:47 -07:00
Earle F. Philhower, III 824070b899 Update version 2022-07-18 20:28:49 -07:00
Earle F. Philhower, III c3a580ee89 Add WiFiClientSecure and WifiServerSecure (TLS) support, NTP (#683)
* Add TLS (https) support
* Add NTP server
* Clean up include path, add BearSSL headers
* Allow 2 NTP servers, add ESP8266 compat define
* Add MFLN SSL example, free/used/total heap getters
* Enable stack thunking
* Add tested SSL examples
* Add BSSL_validation demo
* Add Client Certificate example
* Add RP2040 helper docs
* Clean up doc errors, missing doc version info
* Add WiFiClientSecure documentation
* Add NTP docs

Fixes #679
2022-07-18 20:24:11 -07:00
Earle F. Philhower, III 53cecae109 Update version 2022-07-17 05:52:01 -07:00
Earle F. Philhower, III 61742c9357 Disable WiFi.begin on plain Pico, add JSON (#682) 2022-07-17 05:51:03 -07:00
Earle F. Philhower, III fee036604c Provide dummy CYW43 callbacks when no WiFi used (#681)
Fixes #680
2022-07-16 11:57:27 -07:00
Earle F. Philhower, III 988940b25e Update version 2022-07-15 16:49:36 -07:00
Earle F. Philhower, III abf2c586c7 Add Pico W WiFi support (#670)
* Add support for the WiFi chip on the Pico W board.
* USB interrupt now no longer hard coded (conflicted with the WiFi IRQ).
* Add in Pico W board to makeboards.py
* Add in GPIO and variant support
* Initialize WiFi in the Variant
* Use manual LWIP, fix size accounting
* Remove the SDK WiFi overrides
* Pulling in work done in the ESP8266 core.
* Make IPAddress support IPv6
* Build LWIP with IPv4 and IPv6 support
* Use proper MAC
* Avoid cyw_warn crash.  Make macro to a comment while building
* Add WiFiServer
* Add WiFiUdp
* Move LWIP-specific support files to LWIP_Ethernet
* Add WiFi::ping (ICMP ping)
* Move ICMP echo (ping) to LWIPIntfDev
* Move hostByName to LwipIntfDev
* Add AP mode with simple DHCP server
* Add some examples and basic ESP8266 compat hacks
* Update Adafruit TinyUSB to fix crash
* Set DHCP hostname
* Make Wifi.begin() return CONNECTED with link + IP
* Return connected() on WiFi::begin
* Fix spurious TCP retransmission
* Protect LWIP from reentrancy

The Pico SDK calls "sys_check_timeouts() from inside a periodic interrupt.
This appears unsafe, as the interrupt could happen while already in the
(non-reentrant) LWIP code.

Block the interrupt from calling sys_check_timeouts by using a global flag
manually set via an RAII recursive lock.

Add interrupt protection macros around critical sections inside LWIP via
the standard defines.

These two changes should make LWIP significantly more stable and long
running.

* Support disconnecting and reconnecting WiFi
* Add WiFiServer simple example
* Update documentation

Fixes #666
Fixed #665
2022-07-15 16:47:53 -07:00
Earle F. Philhower, III c025c4a1f8 Fix ::printf/etc. due to mutex size conflict (#677)
When real multicore/lockign support was added to newlib, there was an opaque
field in FILE that was used as a mutex, but was only 4 bytes in size.  The
recursive mutexes on the RP2040 are 8 bytes.  This mismatch caused corruption
of the FILE structure and crashes of the system when ::printf/::puts/etc. were
run.

Adjust the lock field size in FILE to 8 bytes and rebuild the toolchain to
fix.
2022-07-14 09:04:02 -07:00
Earle F. Philhower, III fb05d96979 Add delay to 2nd core start for Picoprobe (#676)
No idea why, but when a Picoprobe upload and reset is used, the 2nd core
does not start w/o a __wfe() call on the first one before launch.

Fixes #674
Fixes #402
2022-07-14 07:43:27 -07:00
Earle F. Philhower, III 8eb030ed89 Update TinyUSB to 1.13.3 (#672)
Fix errors in WebUSB buffering
Fixes #642
2022-07-08 13:45:01 -07:00
Pontus Oldberg 5be405308e Add support for new SD/RTC and SubGHz boards (#663) 2022-06-30 10:16:44 -07:00
Earle F. Philhower, III af0c1c87f5 Automatically update the JSON file in makeboards (#664)
Keep the Arduino Board Manager list up-to-date from makeboards.py
2022-06-29 12:50:42 -07:00
Earle F. Philhower, III cfaae84813 Update version 2022-06-28 15:07:55 -07:00
Earle F. Philhower, III da8ab1e9dd Return # of bytes written by SerialUSB::write (#662)
Before always returned 0 on a ::write.  Now properly return the count
of bytes that were sent to the USB port.

Thanks to Terry Haas for the report.
2022-06-28 13:01:06 -07:00
Maximilian Gerhardt baf65f510f Add notes on TinyUSB documentation and quirks (#659)
Fixes #648
2022-06-26 15:26:23 -07:00
Maximilian Gerhardt 13f68fbc64 Make TinyUSB linking work automatically with PIO (#658) 2022-06-26 13:24:55 -07:00
Stefan Staub 3071b3f2dd Update GPIO docs (digital.rst) (#656) 2022-06-25 10:00:29 -07:00
Earle F. Philhower, III de069cf8c9 Update version 2022-06-24 11:25:21 -07:00
Earle F. Philhower, III 8cf8923a18 Update to Adafruit_TinyUSB_Arduino 1.12.0 (#654)
* Update to Adafruit_TinyUSB_Arduino 1.12.0

* DualRole requires add'l libraries, skip in CI
2022-06-24 11:24:31 -07:00
Earle F. Philhower, III d954510c9d Update to latest pico-sdk develop branch (#653)
Fixes #651
2022-06-24 02:19:24 -07:00
Earle F. Philhower, III 8966a9b094 Actually pass in the PIO key for auto-publishing (#652)
Need to manually list the secrets to export to the environment.
2022-06-23 17:12:21 -07:00
Earle F. Philhower, III 3d9611d020 Update FreeRTOS SMP branch to latest upstream (#649) 2022-06-22 17:18:50 -07:00
Earle F. Philhower, III 78b7f26076 Update README.md 2022-06-20 19:17:52 -07:00
Earle F. Philhower, III 7233c39166 Update to latest pico-sdk, allow lock.c->lock.cpp (#646)
Minor change to keep the core all CPP.  Patch just made it into pico-sdk
develop branch allowing recursive mutexes to be auto_init in C++.
Update and rebuild libpico.a.
2022-06-20 11:14:31 -07:00
Earle F. Philhower, III 0ee072671b Update version 2022-06-20 08:30:24 -07:00
Earle F. Philhower, III 1130007761 Make mutexes init in DATA, not ((counstructor)) (#645)
There was a race condition in making mutexes that were only init in
an __attribute((constructor)) code block.  For example, a global
object might do a `malloc` in its constructor which would depend on
the malloc mutex...which may not yet have been initted.

Make them initted in the .data section, instead, which is guaranteed
good before any global constructors are called.
2022-06-20 08:29:08 -07:00
Earle F. Philhower, III a0060d9c3a Add dependency file generation to build (#644)
Fixes #643
2022-06-20 07:50:28 -07:00
Earle F. Philhower, III 66eb0613b0 Major multicore fixes Newlib and FreeRTOS (#640)
Instead of wrapping the memory functions in the link stage, rebuild
Newlib and enable retargetable locks.  Override the weak definitions
in the libc.a with our own, SDK based ones.

The wrapping utilized before catches app-level memory allocations
but misses allocations inside Newlib libc (like printf/etc.).

Each core needs its own _impure_ptr or else crashes like the one seen
in parallel printf_floats can happen.  Enable it in the toolchain
build and implement a simple swapper here.

FreeRTOS SMP doesn't support Newlib's dynamic reent which is needed
to allow save MT support.  Minor patch to FreeRTOS and update the
FreeRTOS variant.cpp and setup to support it.
2022-06-20 07:35:30 -07:00
Earle F. Philhower, III af8f544913 Update pio publish to match PIO PR build (#641) 2022-06-19 09:14:08 -07:00
Earle F. Philhower, III 803184c164 Update to latest Adafruit_TinyUSB (#639)
Fixes #582
2022-06-19 08:57:14 -07:00
Earle F. Philhower, III 857f91771f Update to develop branch of pico-sdk (#636)
The realloc() wrapper was included in the develop branch of pico-sdk, so
use it instead of a local, unreproducible version of the SDK.

Should have no effect on code.
2022-06-17 12:13:01 -07:00
Maximilian Gerhardt 592418d9f3 Minor PIO Docs Fixup (#635)
* Fix link display in PlatformIO Docs, Remove JLink warning

* Remove unfinished sentence
2022-06-17 09:49:51 -07:00
Maximilian Gerhardt 0a23dfeb42 Update PlatformIO board files, add PIO CI (#634)
* Shift arduino attribute higher in JSON file

* Try out PlatformIO CI

* Trigger CI

* Clone recursively, actually use own repo

* Fix YAML

* Build Verbose

* Revert to checkout@v2 version, add TinyUSB to examples

* Try fix TInyUSB example

* Pull repo recursively

* Use v3 after all, correct path to example

* Only do CI on PR
2022-06-17 08:57:18 -07:00
Maximilian Gerhardt 4a94677ee5 Update PlatformIO builder script and docs (#633)
* Update board generation, use renamed function

* Update documentation with new platform integration state

* Remove accidentally pushed file

* Use correct update command

* Use correct highlighting

* Use correct language

* Add section on debugging

* Add docs on filesystem, minor corrections

* Use -iprefix in compilation, but still expose all include paths to IDE

* Add exception and RTTI support, document them

* Fix typo
2022-06-16 18:59:46 -07:00
mnltake 3414b73172 Add analogReadResolution() docs (#631) 2022-06-16 08:16:58 -07:00
Pontus Oldberg 3bcbb24603 Updated helper class for Challenger NB board. (#629) 2022-06-15 09:16:47 -07:00
Ha Thach 26752f6f90 Aadd f_cpu 120, 240 mhz option (#628) 2022-06-15 09:12:43 -07:00
Earle F. Philhower, III 8999ec2c7a Add Platform.IO publish to release process 2022-06-14 13:07:19 -07:00
Earle F. Philhower, III 778cf4cb9e Update version 2022-06-14 12:34:22 -07:00
Earle F. Philhower, III b6a9e756e4 Remove unneeded and invalid file changes
The makever script sets up the repo properly, so no need to patch things
in the package stage.
2022-06-14 12:32:26 -07:00
Earle F. Philhower, III 285c964c98 Update version 2022-06-14 12:05:48 -07:00
Earle F. Philhower, III 1d6f66f834 Shrink flash and RAM usage even more (#627)
Remove MIDI support from the core's main TinyUSB.  MIDI is still supported
using the Adafruit TinyUSB library, just like before (the core never
did use it).

Compile the Pico-SDK using `-Os`

Remove unneeded warning in UF2 upload

Blink.ino shows a savings of 3.5KB flash and 400 bytes of RAM.

For comparison, with this PR blink.ino reports:
````
Sketch uses 49908 bytes (3%) of program storage space. Maximum is 1568768 bytes.
Global variables use 7024 bytes (2%) of dynamic memory, leaving 255120 bytes for local variables. Maximum is 262144 bytes.
````

As comparison, using the MBED core blink.ino reports:
````
Sketch uses 78882 bytes (0%) of program storage space. Maximum is 16777216 bytes.
Global variables use 42780 bytes (15%) of dynamic memory, leaving 227556 bytes for local variables. Maximum is 270336 bytes.
````

So, with this PR we use **37% less flash** and and **87% less RAM**
for simple sketches.
2022-06-13 11:54:38 -07:00
Earle F. Philhower, III 3fb8cbf39f Temporary fix for muilticore realloc (#625)
This PR includes a pico-sdk built using the fix in
https://github.com/raspberrypi/pico-sdk/pull/864

To properly fix it requires a new pico-sdk release. but until then I am
building against my own fork of pico-sdk and including the binary.
When 1.3.2 is out (and assuming my PR is approved) I'll update the pico-sdk
link.

Fixes #614
2022-06-12 13:38:02 -07:00
Earle F. Philhower, III c352105176 Remove IRQ-level malloc from USB setup
Fixes a hang found while debugging #614.  Do all memory allocations and
USB descriptor setup in main code prior to `tusb_init()`.  Avoids potential
deadlock in cases where the app is allocating while the USB port is being
set up.
2022-06-10 22:58:23 -07:00
Earle F. Philhower, III c4623f4297 Disable Wire slave interrupt on ::end (#621)
Fixes #620
2022-06-10 11:42:04 -07:00
Maximilian Gerhardt 1c85a1ca52 Activate default -Os optimization for Platform.IO (#619) 2022-06-10 09:28:26 -07:00
Earle F. Philhower, III fdf30febea Hide get.py download percent when not interactive (#618)
When get.py is run in a script the percent-update printouts shown while
downloading the toolchain end up as 100s to 1000s of lines in log files.

When stdout is not a terminal, avoid printing these percentages and
shrink logfiles significantly. Errors/etc. are still reported as normal.
2022-06-09 18:00:45 -07:00
Earle F. Philhower, III 7d5e7f5dda Remove obsolete include paths from build.inc (#616)
As noted in #615
2022-06-09 15:35:24 -07:00
Maximilian Gerhardt e3a1debc65 Fix IDE include paths / Intellisense (#615) 2022-06-09 15:30:22 -07:00
Earle F. Philhower, III 578d3d2a76 Reduce flash, RAM use, reduce download/install (#613)
Free up 4K of RAM and 6K of flash when no exceptions are enables (default).
The original toolchain was including exception code in libstdc++ by default.

Reduce installation by ~50MB and download by ~25M by removing unused LTO
gcc support.
2022-06-07 16:07:07 -07:00
Earle F. Philhower, III e3053f69f8 Add GCC stack protector support (#611) 2022-06-06 20:07:40 -07:00
Earle F. Philhower, III 04ec75e515 Try and upload ASAP instead of hard-waiting 10sec (#610)
Fixes #609 and a niggling slowness in uploads.  Try to find the drive
in a loop for 10 seconds, instead of only checking once after 10 seconds.
Avoid 100% CPU usage while waiting for Pico drive
2022-06-06 18:21:34 -07:00
Earle F. Philhower, III 420d669a4b Add C++ exception option to menus (#607)
Depends on new toolchain from
https://github.com/earlephilhower/pico-quick-toolchain/pull/11

Fixes #251
2022-06-06 10:28:54 -07:00
FeuerSturm 9e3f6ade61 Fix WizFi360-EVB-Pico pins_arduino.h (#608)
Slight difference to generic RP2040
PIN_SERIAL2_TX + PIN_SERIAL2_RX are
switched with PIN_WIRE0_SDA + PIN_WIRE0_SCL
2022-06-05 16:59:22 -07:00
Earle F. Philhower, III 0aa0f973aa Update version 2022-06-05 10:18:10 -07:00
Earle F. Philhower, III 8fc9c19af9 Add new WizNet boards to README 2022-06-05 10:17:37 -07:00
Earle F. Philhower, III 10b869ef30 Fix XIAO RP2040, allow swapping HW units 0/1 (#606)
Add plumbing to allow `Wire`, `Serial1`, `SPI1` to map to the 2nd
hardware unit for devices where the PCB layout only brings out the
2nd port.

Fix the Seeedstudio XAIO pins

Fixes #594
2022-06-04 21:37:28 -07:00
FeuerSturm c863dad73e New WIZnet boards (#605)
- added WIZnet WizFi360-EVB-Pico
- added WIZnet W5500-EVB-Pico
- corrected WIZnet W5100S-EVB-Pico PID
2022-06-03 11:56:13 -07:00
Earle F. Philhower, III 24583494c6 Fix Wire::available() when ::requestFrom fails (#604)
Avoids returning 2^32 bytes in the case of a requestFrom read fails
due to timeout.
2022-06-01 17:58:54 -07:00
Earle F. Philhower, III 4ede3ff8a4 Add attachInterruptParam (#602)
Fixed #601

Allows apps to provide a callback parameter in the `attachInterrupt` call
to be passed back to the function when the interrupt happens.
2022-05-31 18:14:34 -07:00
Arya11111andArya11111 a58154b52b Modify DFRobot Beetle pin_arduinos.h (#597)
Co-authored-by: Arya11111 <xuepeng@dfrobot.com>
2022-05-25 15:13:25 -07:00
Earle F. Philhower, III 9e659b003c Deallocate resources on SerialPIO::end (#596)
Fixes #593

When SerialPIO::end is called, stop the PIO SMs and potentially
disable the IRQ handler if this is the last RX port on that PIO.
2022-05-25 03:08:50 -07:00
Earle F. Philhower, III 7d30e6da61 Update piouart.rst 2022-05-24 08:09:01 -07:00
Pontus Oldberg a9b24827e2 Updated PID for WiFi/BLE board and other changes (#595) 2022-05-24 08:07:49 -07:00
Earle F. Philhower, III fc55e1e778 Update version 2022-05-20 12:05:12 -07:00
Earle F. Philhower, III 0188ccf696 Remove obsolete programmers.txt entries (not used) 2022-05-20 11:59:29 -07:00
Earle F. Philhower, III 65d50e4d8b Upgrade to Pico-SDK 1.3.1 (#588)
Looks like only minor changes to the SDK, should not affect the core.
2022-05-20 11:53:20 -07:00
Earle F. Philhower, III 3ce961f84d Add in missing JSON files 2022-05-20 05:27:57 -07:00
Earle F. Philhower, III eaf5e049eb Update package_pico_index.template.json 2022-05-20 05:27:03 -07:00
Pontus Oldberg e4153b03bc Add new Challenger RP2040 WiFi/BLE board (#587) 2022-05-20 05:26:01 -07:00
Earle F. Philhower, III a3a5abac23 Fix Wire I2C restart handling (#586)
Fixes #585

On an I2C bus restart, call the onReceive callback and clear the buffer.

Thanks to @DWiskow for the debug and patch!
2022-05-19 16:00:52 -07:00
Earle F. Philhower, III 8054015bff Clean up misc obsolete references (#584)
Remove pico-extras from makelibpico.sh
Remove refs to SPIFFS in FS.h
Remove travis::: markers
Update Arduino IDE URL
2022-05-18 17:33:16 -07:00
Arya11111andArya11111 646d56046f DFRobot Beetle modify some notes. (#580)
Co-authored-by: Arya11111 <xuepeng@dfrobot.com>
2022-05-11 07:29:59 -07:00
Earle F. Philhower, III 7b296a4dc9 Remove pico-extras from package 2022-05-10 08:44:18 -07:00
Earle F. Philhower, III 61ac01c31b Update version 2022-05-10 08:42:22 -07:00
Earle F. Philhower, III 79a2128704 Remove doc refs to Pico-Extras
Fixes #578
2022-05-08 09:27:48 -07:00
Earle F. Philhower, III 0c9359cddd Fix picoprobe and pico-debug upload recipes (#577)
Need to munge the platform.txt on release.

Fixes #576
2022-05-07 18:53:02 -07:00
Arya11111andArya11111 dbf855e1aa Modify DFRobot pins_arduino.h (#573)
Co-authored-by: Arya11111 <xuepeng@dfrobot.com>
2022-05-05 11:35:20 -07:00
Earle F. Philhower, III 0afd6ae54f Fix order of bootsel IRQ/idle calls (#572)
Reverse the order of IRQ and idle restore to match the way
they were initiated.
2022-05-04 18:48:35 -07:00
Earle F. Philhower, III 07500e89db Rewrite I2S from scratch, add I2S input support (#569)
Rewrite the I2S code from scratch to eliminate the dependence on the
pico-extras implementation and to support I2S input as well.

8-bit, 16-bit, 24-bit, and 32-bit words are supported.

Multiple I2S ports are allowed (theoretically up to 6 because
2 DMA channels are required per port).

I2S input and I2S output are supported.

Add input example

Fixes #535
Fixes #99
Fixes #562
2022-05-04 18:43:27 -07:00
iKK001andStephan Korner 3adc1c5321 Correct Serial1 and Serial2 pinout definitions added (#570)
Co-authored-by: Stephan Korner <stephan.korner@trihow.com>
2022-05-04 13:04:01 -07:00
ogatatsu 55394a7dcd Fix compile error when configSUPPORT_STATIC_ALLOCATION is set to 1 (#564) (#566) 2022-04-30 19:07:21 -07:00
Earle F. Philhower, III 230758b1ee Add invert option to SWSerial (#563)
Thanks to @StefanKellerAC !
2022-04-28 08:17:12 -07:00
Earle F. Philhower, III d7e02c6f34 Fix SWSerial polarity. (#560) 2022-04-27 21:05:16 -07:00
Earle F. Philhower, III c32ad45724 Clean up some minor doc errors/formats (#559) 2022-04-27 16:07:27 -07:00
Earle F. Philhower, III 541e23d663 Update to major version 2.0.0 2022-04-27 12:10:55 -07:00
Earle F. Philhower, III 65fe176795 Make default CPU speed 133MHz (#557)
The chip supports 133MHz and the other Pico core already defaults to
the higher speed, so make 133 the default.

It can still be changed through the menus and will stay at 125 unless
pre-existing users change it so they will see no difference.
2022-04-27 11:31:21 -07:00
Earle F. Philhower, III cfc91804c8 Fix memory corruption introducted in FreeRTOS port (#556)
To remove compiler warning the valid core macro was modified to only check
that the core passed in was < # of total cores.  Unfortunately there are
parts of the FreeRTOS code where the passed in core # is -1.  The upstream
catches this and returns FALSE, but my hacked version returned TRUE.  This
caused interesting memory corruption errors and crashes when the
current task block[-1] was updated.

Undo the change and fix the 1 spot where a warning happens instead.

Undo the forced compiler -O0 for port.c, it was only masking the fault.
2022-04-27 09:42:15 -07:00
Earle F. Philhower, III 88d213a30b Additional FreeRTOS adjustments (#555)
Use low power WFE when idle.

Set PORT.C to built `-O0` always because it seems to occasinally end
up with interrupts disabled in task code, causing the SYSTICK never to
fire and killing task switching.

No need for dynamic exceptions.  We don't move the execbase.
2022-04-27 03:53:07 -07:00
Earle F. Philhower, III 189b796499 More FreeRTOS ISR work 2022-04-25 19:11:38 -07:00
Earle F. Philhower, III af7f430227 Change the RTD theme (#554)
Alabaster is not my favorite, try something with colors...
2022-04-25 18:03:07 -07:00
Andy2No 797abb5a7f Update SimpleTone.ino (#552)
Adds code to define which pins are used, moving them from the defaults, which are the same as the only three analogue input pins, and adding comments to explain how to change them.

The original didn't give any clues about which pins were used, which isn't ideal for a beginner - it was necessary to look at the code for the library, to work that out.

The new code redundantly defines a pWS pin number (as pBCLK+1), which isn't used in the example, but is meant as a reminder to the person using it, of how to wire up WS.
2022-04-25 12:21:34 -07:00
Earle F. Philhower, III ffff21a936 Update FreeRTOS library to avoid random crashes (#553) 2022-04-25 12:10:48 -07:00
Earle F. Philhower, III 781fb3ab48 Update docs, increase max analogWriteFreq to 1MHz (#551) 2022-04-25 08:23:50 -07:00
Earle F. Philhower, III bda630e419 Add FreeRTOS support thanks to @hfellner (#533)
Using all the work from @hfellner and others, add FreeRTOS
SMP support.

Allow idling cores through the FreeRTOS FIFO queue to
allow for file system and EEPROM support.

Make delay a weak function so FreeRTOS can override.

Add cycle count support under FreeRTOS using a PIO SM.

Use a task-based approach for handling the USB periodic work
instead of the IRQ-based one in the main core.

Set 8 prio levels so it fits in 3 bits nicely (0..7).
2022-04-24 20:59:57 -07:00
Earle F. Philhower, III 9afdc48ddd Add SoftwareSerial wrapper around SerialPIO (#548)
I receive mails weekly asking how to use `SoftwareSerial` on this core.
Avoid the issue by including a simple wrapper class around `SerialPIO`
which gives the proper class name and constructor parameters.

Note that inverted mode is not supported.
2022-04-24 15:07:55 -07:00
Earle F. Philhower, III 3ee031abc9 Add ::overflow() return to SerialUART/SerialPIO (#547)
Matching the Arduino SoftwareSerial API
2022-04-24 14:44:23 -07:00
Earle F. Philhower, III d1f9bce083 Document the Generic RP2040 option (#546)
Fixes #522
2022-04-24 11:04:17 -07:00
Earle F. Philhower, III 670957487a Update version 2022-04-22 12:55:08 -07:00
Earle F. Philhower, III 1c0133704e Update to LittleFS 2.5 (#545) 2022-04-22 12:22:27 -07:00
Earle F. Philhower, III 5927d4ee2b Fix SerialPIO sampling, avoid reading random garbage (#544)
Adjust the 1/2 bit time to match the number of extra cycles in the actual
PIO loop.

Throw out the entire start bit, which results in sampling the data at the
midpoint and not the starting time of a bit (which was causing random
failures on read data).

Tested at 300bps all the way to 2,000,000bps using a loopback connection.

Fixes #360
2022-04-21 19:48:30 -07:00
505 changed files with 79892 additions and 7918 deletions
+55 -18
View File
@@ -14,21 +14,21 @@ jobs:
name: Check spelling
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
submodules: true
- name: Run codespell
uses: codespell-project/actions-codespell@master
with:
skip: ./pico-extras,./ArduinoCore-API,./libraries/ESP8266SdFat,./libraries/Adafruit_TinyUSB_Arduino,./libraries/LittleFS/lib,./tools/pyserial,./pico-sdk,./.github,./docs/i2s.rst,./cores/rp2040/api
ignore_words_list: ser,DOUT
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
astyle:
name: Style, Boards, Package
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
submodules: false
- name: Check package references
@@ -57,9 +57,9 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
chunk: [0, 1, 2, 3]
chunk: [0, 1, 2, 3, 4, 5]
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
submodules: true
- uses: actions/setup-python@v2
@@ -76,13 +76,11 @@ jobs:
TRAVIS_BUILD_DIR: ${{ github.workspace }}
TRAVIS_TAG: ${{ github.ref }}
BUILD_PARITY: custom
mod: 4
mod: 6
rem: ${{ matrix.chunk }}
run: |
cd pico-sdk
git submodule update --init
cd ../pico-extras
git submodule update --init
cd ..
bash ./tests/build.sh
@@ -91,7 +89,7 @@ jobs:
name: Build TinyUSB Examples
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
submodules: true
- uses: actions/setup-python@v2
@@ -111,8 +109,6 @@ jobs:
run: |
cd pico-sdk
git submodule update --init
cd ../pico-extras
git submodule update --init
cd ..
bash ./tests/build-tinyusb.sh
@@ -121,7 +117,7 @@ jobs:
name: Windows
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
submodules: true
- uses: actions/setup-python@v2
@@ -147,8 +143,6 @@ jobs:
try { Get-Command python3 } catch { copy (get-command python).source (get-command python).source.Replace("python.exe", "python3.exe") }
cd pico-sdk
git submodule update --init
cd ../pico-extras
git submodule update --init
cd ..
bash ./tests/build.sh
@@ -158,7 +152,7 @@ jobs:
name: Mac
runs-on: macOS-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
submodules: true
- uses: actions/setup-python@v2
@@ -181,8 +175,51 @@ jobs:
run: |
cd pico-sdk
git submodule update --init
cd ../pico-extras
git submodule update --init
cd ..
bash ./tests/build.sh
# Build a few examples with PlatformIO to test if integration works
build-platformio:
name: Build PlatformIO Examples
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: 'true'
- name: Initialize needed submodules
run: |
cd pico-sdk
git submodule update --init
cd ../libraries/Adafruit_TinyUSB_Arduino
git submodule update --init
cd ../..
- name: Cache pip
uses: actions/cache@v2
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Cache PlatformIO
uses: actions/cache@v2
with:
path: ~/.platformio
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
- name: Set up Python
uses: actions/setup-python@v2
- name: Install PlatformIO
run: |
python -m pip install --upgrade pip
pip install --upgrade platformio
pio pkg install --global --platform https://github.com/maxgerhardt/platform-raspberrypi.git
pio pkg install --global --tool symlink://.
- name: Build Multicore Example
run: pio ci --board=rpipico --board=adafruit_feather -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/rp2040/examples/Multicore/Multicore.ino
- name: Build Fade Example
run: pio ci --board=rpipico --board=adafruit_feather -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/rp2040/examples/Fade/Fade.ino
- name: Build TinyUSB Example
run: pio ci --board=rpipico --board=adafruit_feather -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" -O "build_flags=-DUSE_TINYUSB" libraries/Adafruit_TinyUSB_Arduino/examples/CDC/cdc_multi/cdc_multi.ino
- name: Build WiFi Example
run: pio ci --board=rpipicow -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/WiFi/examples/ScanNetworks/ScanNetworks.ino
- name: Build Signed OTA Example
run: pio ci --board=rpipicow -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/ArduinoOTA/examples/SignedOTA/SignedOTA.ino
+20
View File
@@ -12,16 +12,36 @@ jobs:
- uses: actions/checkout@v2
with:
submodules: true
- name: Cache pip
uses: actions/cache@v2
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Cache PlatformIO
uses: actions/cache@v2
with:
path: ~/.platformio
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
- uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Install PlatformIO
run: |
python -m pip install --upgrade pip
pip install --upgrade platformio
- name: Deploy updated JSON
env:
TRAVIS_BUILD_DIR: ${{ github.workspace }}
BUILD_TYPE: package
CI_GITHUB_API_KEY: ${{ secrets.GITHUB_TOKEN }}
PLATFORMIO_AUTH_TOKEN: ${{ secrets.PLATFORMIO_AUTH_TOKEN }}
run: |
pip3 install PyGithub
TAG=$(git describe --exact-match --tags)
curl -L -o package_rp2040_index.json "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/releases/download/$TAG/package_rp2040_index.json"
./package/update_release.py --token ${CI_GITHUB_API_KEY} --repo "$GITHUB_REPOSITORY" --tag global package_rp2040_index.json
# Upload to Platform.IO
curl -LO $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/releases/download/$TAG/rp2040-$TAG.zip
pio package publish rp2040-$TAG.zip --non-interactive
@@ -29,7 +29,6 @@ jobs:
CI_GITHUB_API_KEY: ${{ secrets.GITHUB_TOKEN }}
run: |
(cd pico-sdk && git submodule update --init)
(cd pico-extras && git submodule update --init)
(cd ./package && bash ./build_boards_manager_package.sh)
pip3 install PyGithub
# Create a draft release and upload the ZIP and JSON files.
+4
View File
@@ -1,3 +1,7 @@
.DS_Store
system
tools/dist
docs/_build
ota/build
tools/libpico/build
platform.local.txt
+16 -4
View File
@@ -3,7 +3,7 @@
url = https://github.com/earlephilhower/ArduinoCore-API.git
[submodule "pico-sdk"]
path = pico-sdk
url = https://github.com/raspberrypi/pico-sdk.git
url = https://github.com/earlephilhower/pico-sdk.git
[submodule "system/pyserial"]
path = tools/pyserial
url = https://github.com/pyserial/pyserial.git
@@ -13,15 +13,27 @@
[submodule "libraries/SdFat"]
path = libraries/ESP8266SdFat
url = https://github.com/earlephilhower/ESP8266SdFat.git
[submodule "pico-extras"]
path = pico-extras
url = https://github.com/raspberrypi/pico-extras.git
[submodule "libraries/Keyboard"]
path = libraries/Keyboard
url = https://github.com/earlephilhower/Keyboard
[submodule "libraries/Mouse"]
path = libraries/Mouse
url = https://github.com/earlephilhower/Mouse
[submodule "libraries/Joystick"]
path = libraries/Joystick
url = https://github.com/benjaminaigner/Joystick
[submodule "libraries/Adafruit_TinyUSB_Arduino"]
path = libraries/Adafruit_TinyUSB_Arduino
url = https://github.com/adafruit/Adafruit_TinyUSB_Arduino.git
[submodule "libraries/FreeRTOS/lib/FreeRTOS-Kernel"]
path = libraries/FreeRTOS/lib/FreeRTOS-Kernel
url = https://github.com/earlephilhower/FreeRTOS-Kernel.git
[submodule "tools/libbearssl/bearssl"]
path = tools/libbearssl/bearssl
url = https://github.com/earlephilhower/bearssl-esp8266.git
[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
+28 -6
View File
@@ -11,6 +11,7 @@ See https://arduino-pico.readthedocs.io/en/latest/ along with the examples for m
# Supported Boards
* Raspberry Pi Pico
* Raspberry Pi Pico W
* Adafruit Feather RP2040
* Adafruit ItsyBitsy RP2040
* Adafruit KB2040
@@ -23,10 +24,15 @@ See https://arduino-pico.readthedocs.io/en/latest/ along with the examples for m
* Cytron Maker Nano RP2040
* 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
* Invector Labs Challenger RP2040 LTE
* Invector Labs Challenger RP2040 LoRa
* Invector Labs Challenger RP2040 SubGHz
* Invector Labs Challenger RP2040 SD/RTC
* Invector Labs RPICO32
* Melopero Shake RP2040
* Seeed XIAO RP2040
@@ -35,6 +41,8 @@ See https://arduino-pico.readthedocs.io/en/latest/ along with the examples for m
* SparkFun Thing Plus RP2040
* uPesy RP2040 DevKit
* WIZnet W5100S-EVB-Pico
* WIZnet W5500-EVB-Pico
* WIZnet WizFi360-EVB-Pico
* Generic (configurable flash, I/O pins)
# Installing via Arduino Boards Manager
@@ -70,8 +78,6 @@ cd ~/Arduino/hardware/pico/rp2040
git submodule update --init
cd pico-sdk
git submodule update --init
cd ../pico-extras
git submodule update --init
cd ../tools
python3 ./get.py
`````
@@ -141,16 +147,22 @@ The installed tools include a version of OpenOCD (in the pqt-openocd directory)
# Features
* 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())
* FreeRTOS SMP support
* Overclocking and underclocking from the menus
* digitalWrite/Read, shiftIn/Out, tone, analogWrite(PWM)/Read, temperature
* Peripherals: SPI master, Wire(I2C) master/slave, dual UART, emulated EEPROM, I2S audio output, Servo
* Peripherals: SPI master, Wire(I2C) master/slave, dual UART, emulated EEPROM, I2S audio input, I2S audio output, Servo
* printf (i.e. debug) output over USB serial
The RP2040 PIO state machines (SMs) are used to generate jitter-free:
* Servos
* Tones
* I2S Input
* I2S Output
* Software UARTs (Serial ports)
@@ -161,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.
@@ -168,11 +181,20 @@ If you want to contribute or have bugfixes, drop me a note at <earlephilhower@ya
# Licensing and Credits
* The [Arduino IDE and ArduinoCore-API](https://arduino.cc) are developed and maintained by the Arduino team. The IDE is licensed under GPL.
* The [RP2040 GCC-based toolchain](https://github.com/earlephilhower/pico-quick-toolchain) is licensed under under the GPL.
* The [Pico-SDK](https://github.com/raspberrypi/pico-sdk) and [Pico-Extras](https://github.com/raspberrypi/pico-extras) are by Raspberry Pi (Trading) Ltd and licensed under the BSD 3-Clause license.
* The [Pico-SDK](https://github.com/raspberrypi/pico-sdk) is by Raspberry Pi (Trading) Ltd and licensed under the BSD 3-Clause license.
* [Arduino-Pico](https://github.com/earlephilhower/arduino-pico) core files are licensed under the LGPL.
* [LittleFS](https://github.com/ARMmbed/littlefs) library written by ARM Limited and released under the [BSD 3-clause license](https://github.com/ARMmbed/littlefs/blob/master/LICENSE.md).
* [UF2CONV.PY](https://github.com/microsoft/uf2) is by Microsoft Corporation and licensed under the MIT license.
* Some filesystem code taken from the [ESP8266 Arduino Core](https://github.com/esp8266/Arduino) and licensed under the LGPL.
* Networking and filesystem code taken from the [ESP8266 Arduino Core](https://github.com/esp8266/Arduino) and licensed under the LGPL.
* DHCP server for AP host mode from the [Micropython Project](https://micropython.org), distributed under the MIT License.
* [FreeRTOS](https://freertos.org) is Copyright Amazon.com, Inc. or its affiliates, and distributed under the MIT license.
* [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.
* [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
-Earle F. Philhower, III
earlephilhower@yahoo.com
+8743 -1318
View File
File diff suppressed because it is too large Load Diff
+13 -4
View File
@@ -18,8 +18,7 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef Arduino_h
#define Arduino_h
#pragma once
#include <stdint.h>
#include <stdlib.h>
@@ -79,6 +78,9 @@ void analogWriteFreq(uint32_t freq);
void analogWriteRange(uint32_t range);
void analogWriteResolution(int res);
// FreeRTOS potential calls
extern bool __isFreeRTOS;
#ifdef __cplusplus
} // extern "C"
#endif
@@ -88,6 +90,15 @@ void analogWriteResolution(int res);
#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
@@ -109,5 +120,3 @@ constexpr uint32_t __bitset(const int (&a)[N], size_t i = 0U) {
return i < N ? (1L << a[i]) | __bitset(a, i + 1) : 0;
}
#endif
#endif // Arduino_h
+1 -1
View File
@@ -47,8 +47,8 @@ static bool __no_inline_not_in_flash_func(get_bootsel_button)() {
GPIO_OVERRIDE_NORMAL << IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_LSB,
IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS);
interrupts();
rp2040.resumeOtherCore();
interrupts();
return button_state;
}
+21 -8
View File
@@ -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);
}
}
}
+6 -22
View File
@@ -18,8 +18,7 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef FS_H
#define FS_H
#pragma once
#include <memory>
#include <Arduino.h>
@@ -51,7 +50,9 @@ enum SeekMode {
class File : public Stream {
public:
File(FileImplPtr p = FileImplPtr(), FS *baseFS = nullptr) : _p(p), _fakeDir(nullptr), _baseFS(baseFS) { }
File(FileImplPtr p = FileImplPtr(), FS *baseFS = nullptr) : _p(p), _fakeDir(nullptr), _baseFS(baseFS) {
_startMillis = millis(); /* workaround -O3 spurious warning #768 */
}
// Print methods:
size_t write(uint8_t) override;
@@ -91,9 +92,8 @@ public:
uint8_t obuf[256];
size_t doneLen = 0;
size_t sentLen;
int i;
while (src.available() > sizeof(obuf)) {
while ((size_t)src.available() > sizeof(obuf)) {
src.read(obuf, sizeof(obuf));
sentLen = write(obuf, sizeof(obuf));
doneLen = doneLen + sentLen;
@@ -188,15 +188,6 @@ public:
bool _autoFormat;
};
class SPIFFSConfig : public FSConfig {
public:
static constexpr uint32_t FSId = 0x53504946;
SPIFFSConfig(bool autoFormat = true) : FSConfig(FSId, autoFormat) { }
// Inherit _type and _autoFormat
// nothing yet, enableTime TBD when SPIFFS has metadate
};
class FS {
public:
FS(FSImplPtr impl) : _impl(impl) {
@@ -249,7 +240,7 @@ protected:
}
time_t (*_timeCallback)(void) = nullptr;
static time_t _defaultTimeCB(void) {
return time(NULL);
return time(nullptr);
}
};
@@ -272,11 +263,4 @@ using fs::SeekCur;
using fs::SeekEnd;
using fs::FSInfo;
using fs::FSConfig;
using fs::SPIFFSConfig;
#endif //FS_NO_GLOBALS
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SPIFFS)
extern fs::FS SPIFFS __attribute__((deprecated("SPIFFS has been deprecated. Please consider moving to LittleFS or other filesystems.")));
#endif
#endif //FS_H
+2 -4
View File
@@ -17,8 +17,8 @@
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 FSIMPL_H
#define FSIMPL_H
#pragma once
#include <stddef.h>
#include <stdint.h>
@@ -149,5 +149,3 @@ protected:
};
} // namespace fs
#endif //FSIMPL_H
+41
View File
@@ -0,0 +1,41 @@
/*
WiFiMutex.h - Ensure the timer-driven sys_check_timeouts doesn't
get executed while we're in the user-level TCP stack.
Copyright (c) 2022 Earle F. Philhower, III. All rights reserved.
Implements the API defined by the Arduino WiFiNINA library,
copyright (c) 2018 Arduino SA. 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
extern "C" volatile bool __inLWIP;
class LWIPMutex {
public:
LWIPMutex() {
__inLWIP = true;
_ref++;
}
~LWIPMutex() {
if (0 == --_ref) {
__inLWIP = false;
}
}
private:
static int _ref;
};
+290
View File
@@ -0,0 +1,290 @@
/*
PolledTimeout.h - Encapsulation of a polled Timeout
Copyright (c) 2018 Daniel Salazar. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
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 <limits> // std::numeric_limits
#include <type_traits> // std::is_unsigned
#define IRAM_ATTR
namespace esp8266 {
namespace polledTimeout {
namespace YieldPolicy {
struct DoNothing {
static void execute() {}
};
struct YieldOrSkip {
static void execute() {} //{esp_yield();}
};
template <unsigned long delayMs>
struct YieldAndDelayMs {
static void execute() {
delay(delayMs);
}
};
} //YieldPolicy
namespace TimePolicy {
struct TimeSourceMillis {
// time policy in milli-seconds based on millis()
using timeType = decltype(millis());
static timeType time() {
return millis();
}
static constexpr timeType ticksPerSecond = 1000;
static constexpr timeType ticksPerSecondMax = 1000;
};
struct TimeSourceCycles {
// time policy based on esp_get_cycle_count()
// this particular time measurement is intended to be called very often
// (every loop, every yield)
using timeType = decltype(rp2040.getCycleCount());
static timeType time() {
return rp2040.getCycleCount();
}
static constexpr timeType ticksPerSecond = F_CPU;
static constexpr timeType ticksPerSecondMax = F_CPU;
};
template <typename TimeSourceType, unsigned long long second_th>
// "second_th" units of timeType for one second
struct TimeUnit {
using timeType = typename TimeSourceType::timeType;
#if __GNUC__ < 5
// gcc-4.8 cannot compile the constexpr-only version of this function
// using #defines instead luckily works
static constexpr timeType computeRangeCompensation() {
#define number_of_secondTh_in_one_tick ((1.0 * second_th) / ticksPerSecond)
#define fractional (number_of_secondTh_in_one_tick - (long)number_of_secondTh_in_one_tick)
return ({
fractional == 0 ?
1 : // no need for compensation
(number_of_secondTh_in_one_tick / fractional) + 0.5; // scalar multiplier allowing exact division
});
#undef number_of_secondTh_in_one_tick
#undef fractional
}
#else
static constexpr timeType computeRangeCompensation() {
return ({
constexpr double number_of_secondTh_in_one_tick = (1.0 * second_th) / ticksPerSecond;
constexpr double fractional = number_of_secondTh_in_one_tick - (long)number_of_secondTh_in_one_tick;
fractional == 0 ?
1 : // no need for compensation
(number_of_secondTh_in_one_tick / fractional) + 0.5; // scalar multiplier allowing exact division
});
}
#endif
static constexpr timeType ticksPerSecond = TimeSourceType::ticksPerSecond;
static constexpr timeType ticksPerSecondMax = TimeSourceType::ticksPerSecondMax;
static constexpr timeType rangeCompensate = computeRangeCompensation();
static constexpr timeType user2UnitMultiplierMax = (ticksPerSecondMax * rangeCompensate) / second_th;
static constexpr timeType user2UnitMultiplier = (ticksPerSecond * rangeCompensate) / second_th;
static constexpr timeType user2UnitDivider = rangeCompensate;
// std::numeric_limits<timeType>::max() is reserved
static constexpr timeType timeMax = (std::numeric_limits<timeType>::max() - 1) / user2UnitMultiplierMax;
static timeType toTimeTypeUnit(const timeType userUnit) {
return (userUnit * user2UnitMultiplier) / user2UnitDivider;
}
static timeType toUserUnit(const timeType internalUnit) {
return (internalUnit * user2UnitDivider) / user2UnitMultiplier;
}
static timeType time() {
return TimeSourceType::time();
}
};
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
template <bool PeriodicT, typename YieldPolicyT = YieldPolicy::DoNothing, typename TimePolicyT = TimePolicy::TimeMillis>
class timeoutTemplate {
public:
using timeType = typename TimePolicyT::timeType;
static_assert(std::is_unsigned<timeType>::value == true, "timeType must be unsigned");
static constexpr timeType alwaysExpired = 0;
static constexpr timeType neverExpires = std::numeric_limits<timeType>::max();
static constexpr timeType rangeCompensate = TimePolicyT::rangeCompensate; //debug
timeoutTemplate(const timeType userTimeout) {
reset(userTimeout);
}
IRAM_ATTR // fast
bool expired() {
YieldPolicyT::execute(); //in case of DoNothing: gets optimized away
if (PeriodicT) { //in case of false: gets optimized away
return expiredRetrigger();
}
return expiredOneShot();
}
IRAM_ATTR // fast
operator bool() {
return expired();
}
bool canExpire() const {
return !_neverExpires;
}
bool canWait() const {
return _timeout != alwaysExpired;
}
// Resets, will trigger after this new timeout.
IRAM_ATTR // called from ISR
void reset(const timeType newUserTimeout) {
reset();
_timeout = TimePolicyT::toTimeTypeUnit(newUserTimeout);
_neverExpires = (newUserTimeout < 0) || (newUserTimeout > timeMax());
}
// Resets, will trigger after the timeout previously set.
IRAM_ATTR // called from ISR
void reset() {
_start = TimePolicyT::time();
}
// Resets to just expired so that on next poll the check will immediately trigger for the user,
// also change timeout (after next immediate trigger).
IRAM_ATTR // called from ISR
void resetAndSetExpired(const timeType newUserTimeout) {
reset(newUserTimeout);
_start -= _timeout;
}
// Resets to just expired so that on next poll the check will immediately trigger for the user.
IRAM_ATTR // called from ISR
void resetAndSetExpired() {
reset();
_start -= _timeout;
}
void resetToNeverExpires() {
_timeout = alwaysExpired + 1; // because canWait() has precedence
_neverExpires = true;
}
timeType getTimeout() const {
return TimePolicyT::toUserUnit(_timeout);
}
static constexpr timeType timeMax() {
return TimePolicyT::timeMax;
}
private:
IRAM_ATTR // fast
bool checkExpired(const timeType internalUnit) const {
// canWait() is not checked here
// returns "can expire" and "time expired"
return (!_neverExpires) && ((internalUnit - _start) >= _timeout);
}
protected:
IRAM_ATTR // fast
bool expiredRetrigger() {
if (!canWait()) {
return true;
}
timeType current = TimePolicyT::time();
if (checkExpired(current)) {
unsigned long n = (current - _start) / _timeout; //how many _timeouts periods have elapsed, will usually be 1 (current - _start >= _timeout)
_start += n * _timeout;
return true;
}
return false;
}
IRAM_ATTR // fast
bool expiredOneShot() const {
// returns "always expired" or "has expired"
return !canWait() || checkExpired(TimePolicyT::time());
}
timeType _timeout;
timeType _start;
bool _neverExpires;
};
// legacy type names, deprecated (unit is milliseconds)
using oneShot = polledTimeout::timeoutTemplate<false> /*__attribute__((deprecated("use oneShotMs")))*/;
using periodic = polledTimeout::timeoutTemplate<true> /*__attribute__((deprecated("use periodicMs")))*/;
// standard versions (based on millis())
// timeMax() is 49.7 days ((2^32)-2 ms)
using oneShotMs = polledTimeout::timeoutTemplate<false>;
using periodicMs = polledTimeout::timeoutTemplate<true>;
// Time policy based on esp_get_cycle_count(), and intended to be called very often:
// "Fast" versions sacrifices time range for improved precision and reduced execution time (by 86%)
// (cpu cycles for ::expired(): 372 (millis()) vs 52 (esp_get_cycle_count()))
// timeMax() values:
// Ms: max is 26843 ms (26.8 s)
// Us: max is 26843545 us (26.8 s)
// Ns: max is 1073741823 ns ( 1.07 s)
// (time policy based on esp_get_cycle_count() is intended to be called very often)
using oneShotFastMs = polledTimeout::timeoutTemplate<false, YieldPolicy::DoNothing, TimePolicy::TimeFastMillis>;
using periodicFastMs = polledTimeout::timeoutTemplate<true, YieldPolicy::DoNothing, TimePolicy::TimeFastMillis>;
using oneShotFastUs = polledTimeout::timeoutTemplate<false, YieldPolicy::DoNothing, TimePolicy::TimeFastMicros>;
using periodicFastUs = polledTimeout::timeoutTemplate<true, YieldPolicy::DoNothing, TimePolicy::TimeFastMicros>;
using oneShotFastNs = polledTimeout::timeoutTemplate<false, YieldPolicy::DoNothing, TimePolicy::TimeFastNanos>;
using periodicFastNs = polledTimeout::timeoutTemplate<true, YieldPolicy::DoNothing, TimePolicy::TimeFastNanos>;
} //polledTimeout
/* A 1-shot timeout that auto-yields when in CONT can be built as follows:
using oneShotYieldMs = esp8266::polledTimeout::timeoutTemplate<false, esp8266::polledTimeout::YieldPolicy::YieldOrSkip>;
Other policies can be implemented by the user, e.g.: simple yield that panics in SYS, and the polledTimeout types built as needed as shown above, without modifying this file.
*/
}//esp8266
+197 -88
View File
@@ -21,11 +21,20 @@
#include <hardware/clocks.h>
#include <hardware/irq.h>
#include <hardware/pio.h>
#include <pico/unique_id.h>
#include <hardware/exception.h>
#include <hardware/watchdog.h>
#include <hardware/structs/rosc.h>
#include <hardware/structs/systick.h>
#include <pico/multicore.h>
#include <pico/util/queue.h>
#include <CoreMutex.h>
#include "CoreMutex.h"
#include "ccount.pio.h"
#include <malloc.h>
#include "_freertos.h"
extern "C" volatile bool __otherCoreIdled;
class _MFIFO {
public:
@@ -45,9 +54,12 @@ public:
}
void registerCore() {
multicore_fifo_clear_irq();
irq_set_exclusive_handler(SIO_IRQ_PROC0 + get_core_num(), _irq);
irq_set_enabled(SIO_IRQ_PROC0 + get_core_num(), true);
if (!__isFreeRTOS) {
multicore_fifo_clear_irq();
irq_set_exclusive_handler(SIO_IRQ_PROC0 + get_core_num(), _irq);
irq_set_enabled(SIO_IRQ_PROC0 + get_core_num(), true);
}
// FreeRTOS port.c will handle the IRQ hooking
}
void push(uint32_t val) {
@@ -78,10 +90,15 @@ public:
if (!_multicore) {
return;
}
__holdUpPendSV = 1;
if (__isFreeRTOS) {
vTaskPreemptionDisable(nullptr);
vTaskSuspendAll();
}
mutex_enter_blocking(&_idleMutex);
_otherIdled = false;
__otherCoreIdled = false;
multicore_fifo_push_blocking(_GOTOSLEEP);
while (!_otherIdled) { /* noop */ }
while (!__otherCoreIdled) { /* noop */ }
}
void resumeOtherCore() {
@@ -89,9 +106,15 @@ public:
return;
}
mutex_exit(&_idleMutex);
_otherIdled = false;
__otherCoreIdled = false;
if (__isFreeRTOS) {
xTaskResumeAll();
vTaskPreemptionEnable(nullptr);
}
__holdUpPendSV = 0;
// Other core will exit busy-loop and return to operation
// once otherIdled == false.
// once __otherCoreIdled == false.
}
void clear() {
@@ -108,98 +131,34 @@ public:
private:
static void __no_inline_not_in_flash_func(_irq)() {
multicore_fifo_clear_irq();
noInterrupts(); // We need total control, can't run anything
while (multicore_fifo_rvalid()) {
if (_GOTOSLEEP == multicore_fifo_pop_blocking()) {
_otherIdled = true;
while (_otherIdled) { /* noop */ }
break;
if (!__isFreeRTOS) {
multicore_fifo_clear_irq();
noInterrupts(); // We need total control, can't run anything
while (multicore_fifo_rvalid()) {
if (_GOTOSLEEP == multicore_fifo_pop_blocking()) {
__otherCoreIdled = true;
while (__otherCoreIdled) { /* noop */ }
break;
}
}
interrupts();
}
interrupts();
}
bool _multicore = false;
mutex_t _idleMutex;
static volatile bool _otherIdled;
queue_t _queue[2];
static constexpr int _GOTOSLEEP = 0x66666666;
static constexpr uint32_t _GOTOSLEEP = 0xC0DED02E;
};
class RP2040;
extern RP2040 rp2040;
extern "C" void main1();
class PIOProgram;
class RP2040 {
public:
RP2040() {
_epoch = 0;
// Enable SYSTICK exception
exception_set_exclusive_handler(SYSTICK_EXCEPTION, _SystickHandler);
systick_hw->csr = 0x7;
systick_hw->rvr = 0x00FFFFFF;
}
~RP2040() { /* noop */ }
// 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));
}
// Get current clock frequency
static int f_cpu() {
return clock_get_hz(clk_sys);
}
// Get CPU cycle count. Needs to do magic to extens 24b HW to something longer
volatile uint64_t _epoch = 0;
inline uint32_t getCycleCount() {
uint32_t epoch;
uint32_t ctr;
do {
epoch = (uint32_t)_epoch;
ctr = systick_hw->cvr;
} while (epoch != (uint32_t)_epoch);
return epoch + (1 << 24) - ctr; /* CTR counts down from 1<<24-1 */
}
inline uint64_t getCycleCount64() {
uint64_t epoch;
uint64_t ctr;
do {
epoch = _epoch;
ctr = systick_hw->cvr;
} while (epoch != _epoch);
return epoch + (1LL << 24) - ctr;
}
void idleOtherCore() {
fifo.idleOtherCore();
}
void resumeOtherCore() {
fifo.resumeOtherCore();
}
void restartCore1() {
multicore_reset_core1();
fifo.clear();
multicore_launch_core1(main1);
}
// Multicore comms FIFO
_MFIFO fifo;
private:
static void _SystickHandler() {
rp2040._epoch += 1LL << 24;
}
};
extern "C" char __StackLimit;
extern "C" char __bss_end__;
// Wrapper class for PIO programs, abstracting common operations out
// TODO - Add unload/destructor
@@ -255,3 +214,153 @@ private:
const pio_program_t *_pgm;
};
class RP2040 {
public:
RP2040() { /* noop */ }
~RP2040() { /* noop */ }
void begin() {
_epoch = 0;
if (!__isFreeRTOS) {
// Enable SYSTICK exception
exception_set_exclusive_handler(SYSTICK_EXCEPTION, _SystickHandler);
systick_hw->csr = 0x7;
systick_hw->rvr = 0x00FFFFFF;
} else {
int off = 0;
_ccountPgm = new PIOProgram(&ccount_program);
_ccountPgm->prepare(&_pio, &_sm, &off);
ccount_program_init(_pio, _sm, off);
pio_sm_set_enabled(_pio, _sm, true);
}
}
// 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) / 1'000'000));
}
// Get current clock frequency
static int f_cpu() {
return clock_get_hz(clk_sys);
}
// Get CPU cycle count. Needs to do magic to extens 24b HW to something longer
volatile uint64_t _epoch = 0;
inline uint32_t getCycleCount() {
if (!__isFreeRTOS) {
uint32_t epoch;
uint32_t ctr;
do {
epoch = (uint32_t)_epoch;
ctr = systick_hw->cvr;
} while (epoch != (uint32_t)_epoch);
return epoch + (1 << 24) - ctr; /* CTR counts down from 1<<24-1 */
} else {
return ccount_read(_pio, _sm);
}
}
inline uint64_t getCycleCount64() {
if (!__isFreeRTOS) {
uint64_t epoch;
uint64_t ctr;
do {
epoch = _epoch;
ctr = systick_hw->cvr;
} while (epoch != _epoch);
return epoch + (1LL << 24) - ctr;
} else {
return ccount_read(_pio, _sm);
}
}
inline int getFreeHeap() {
return getTotalHeap() - getUsedHeap();
}
inline int getUsedHeap() {
struct mallinfo m = mallinfo();
return m.uordblks;
}
inline int getTotalHeap() {
return &__StackLimit - &__bss_end__;
}
void idleOtherCore() {
fifo.idleOtherCore();
}
void resumeOtherCore() {
fifo.resumeOtherCore();
}
void restartCore1() {
multicore_reset_core1();
fifo.clear();
multicore_launch_core1(main1);
}
void reboot() {
watchdog_reboot(0, 0, 10);
while (1) {
continue;
}
}
inline void restart() {
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]) {
pico_get_unique_board_id_string(id, sizeof(id));
}
return id;
}
// Multicore comms FIFO
_MFIFO fifo;
// TODO - Not so great HW random generator. 32-bits wide. Cryptographers somewhere are crying
uint32_t hwrand32() {
// Try and whiten the HW ROSC bit
uint32_t r = 0;
for (int k = 0; k < 32; k++) {
unsigned long int b;
do {
b = rosc_hw->randombit & 1;
if (b != (rosc_hw->randombit & 1)) {
break;
}
} while (true);
r <<= 1;
r |= b;
}
// Stir using the cycle count LSBs. In any WiFi use case this will be a random # since the connection time is not cycle-accurate
uint64_t rr = (((uint64_t)~r) << 32LL) | r;
rr >>= rp2040.getCycleCount() & 32LL;
return (uint32_t)rr;
}
private:
static void _SystickHandler() {
rp2040._epoch += 1LL << 24;
}
PIO _pio;
int _sm;
PIOProgram *_ccountPgm;
};
+105 -67
View File
@@ -40,7 +40,7 @@ mutex_t __usb_mutex;
// USB processing will be a periodic timer task
#define USB_TASK_INTERVAL 1000
#define USB_TASK_IRQ 31
static int __usb_task_irq;
// USB VID/PID (note that PID can change depending on the add'l interfaces)
#define USBD_VID (0x2E8A) // Raspberry Pi
@@ -71,8 +71,6 @@ mutex_t __usb_mutex;
#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 && !__USBInstallMIDI) {
if (__USBInstallSerial && !__USBInstallKeyboard && !__USBInstallMouse && !__USBInstallJoystick) {
// Can use as-is, this is the default USB case
return (const uint8_t *)&usbd_desc_device;
}
@@ -102,8 +100,8 @@ const uint8_t *tud_descriptor_device_cb(void) {
if (__USBInstallMouse) {
usbd_desc_device.idProduct |= 0x4000;
}
if (__USBInstallMIDI) {
usbd_desc_device.idProduct |= 0x2000;
if (__USBInstallJoystick) {
usbd_desc_device.idProduct |= 0x0100;
}
// Set the device class to 0 to indicate multiple device classes
usbd_desc_device.bDeviceClass = 0;
@@ -120,49 +118,91 @@ int __USBGetMouseReportID() {
return __USBInstallKeyboard ? 2 : 1;
}
int __USBGetJoystickReportID() {
int i = 1;
if (__USBInstallKeyboard) {
i++;
}
if (__USBInstallMouse) {
i++;
}
return i;
}
static int __hid_report_len = 0;
static uint8_t *__hid_report = nullptr;
static uint8_t *GetDescHIDReport(int *len) {
static uint8_t *report = nullptr;
int report_len = 0;
if (report) {
free(report);
report = nullptr;
}
if (__USBInstallKeyboard && __USBInstallMouse) {
uint8_t desc_hid_report[] = {
TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(1)),
TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(2))
};
report_len = sizeof(desc_hid_report);
report = (uint8_t *)malloc(report_len);
if (report) {
memcpy(report, desc_hid_report, report_len);
}
} else if (__USBInstallKeyboard && ! __USBInstallMouse) {
uint8_t desc_hid_report[] = {
TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(1))
};
report_len = sizeof(desc_hid_report);
report = (uint8_t *)malloc(report_len);
if (report) {
memcpy(report, desc_hid_report, report_len);
}
} else { // if (!__USBInstallKeyboard && __USBInstallMouse) {
uint8_t desc_hid_report[] = {
TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(1))
};
report_len = sizeof(desc_hid_report);
report = (uint8_t *)malloc(report_len);
if (report) {
memcpy(report, desc_hid_report, report_len);
}
}
if (len) {
*len = report_len;
*len = __hid_report_len;
}
return __hid_report;
}
void __SetupDescHIDReport() {
//allocate memory for the HID report descriptors. We don't use them, but need the size here.
uint8_t desc_hid_report_mouse[] = { TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(1)) };
uint8_t desc_hid_report_joystick[] = { TUD_HID_REPORT_DESC_GAMEPAD(HID_REPORT_ID(1)) };
uint8_t desc_hid_report_keyboard[] = { TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(1)) };
int size = 0;
//accumulate the size of all used HID report descriptors
if (__USBInstallKeyboard) {
size += sizeof(desc_hid_report_keyboard);
}
if (__USBInstallMouse) {
size += sizeof(desc_hid_report_mouse);
}
if (__USBInstallJoystick) {
size += sizeof(desc_hid_report_joystick);
}
//no HID used at all
if (size == 0) {
__hid_report = nullptr;
__hid_report_len = 0;
return;
}
//allocate the "real" HID report descriptor
__hid_report = (uint8_t *)malloc(size);
if (__hid_report) {
__hid_report_len = size;
//now copy the descriptors
//1.) keyboard descriptor, if requested
if (__USBInstallKeyboard) {
memcpy(__hid_report, desc_hid_report_keyboard, sizeof(desc_hid_report_keyboard));
}
//2.) mouse descriptor, if necessary. Additional offset & new array is necessary if there is a keyboard.
if (__USBInstallMouse) {
//determine if we need an offset (USB keyboard is installed)
if (__USBInstallKeyboard) {
uint8_t desc_local[] = { TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(2)) };
memcpy(__hid_report + sizeof(desc_hid_report_keyboard), desc_local, sizeof(desc_local));
} else {
memcpy(__hid_report, desc_hid_report_mouse, sizeof(desc_hid_report_mouse));
}
}
//3.) joystick descriptor. 2 additional checks are necessary for mouse and/or keyboard
if (__USBInstallJoystick) {
uint8_t reportid = 1;
int offset = 0;
if (__USBInstallKeyboard) {
reportid++;
offset += sizeof(desc_hid_report_keyboard);
}
if (__USBInstallMouse) {
reportid++;
offset += sizeof(desc_hid_report_mouse);
}
uint8_t desc_local[] = { TUD_HID_REPORT_DESC_GAMEPAD(HID_REPORT_ID(reportid)) };
memcpy(__hid_report + offset, desc_local, sizeof(desc_local));
}
}
return report;
}
// Invoked when received GET HID REPORT DESCRIPTOR
@@ -173,15 +213,17 @@ uint8_t const * tud_hid_descriptor_report_cb(uint8_t instance) {
return GetDescHIDReport(nullptr);
}
static uint8_t *usbd_desc_cfg = nullptr;
const uint8_t *tud_descriptor_configuration_cb(uint8_t index) {
(void)index;
static uint8_t *usbd_desc_cfg = nullptr;
return usbd_desc_cfg;
}
void __SetupUSBDescriptor() {
if (!usbd_desc_cfg) {
bool hasHID = __USBInstallKeyboard || __USBInstallMouse;
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
@@ -196,13 +238,7 @@ const uint8_t *tud_descriptor_configuration_cb(uint8_t index) {
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
@@ -224,12 +260,8 @@ const uint8_t *tud_descriptor_configuration_cb(uint8_t index) {
memcpy(ptr, hid_desc, sizeof(hid_desc));
ptr += sizeof(hid_desc);
}
if (__USBInstallMIDI) {
memcpy(ptr, midi_desc, sizeof(midi_desc));
}
}
}
return usbd_desc_cfg;
}
const uint16_t *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
@@ -257,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) {
@@ -276,31 +308,37 @@ 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);
}
}
static int64_t timer_task(__unused alarm_id_t id, __unused void *user_data) {
irq_set_pending(USB_TASK_IRQ);
irq_set_pending(__usb_task_irq);
return USB_TASK_INTERVAL;
}
void __USBStart() __attribute__((weak));
void __USBStart() {
if (tusb_inited()) {
// Already called
return;
}
__SetupDescHIDReport();
__SetupUSBDescriptor();
mutex_init(&__usb_mutex);
tusb_init();
irq_set_exclusive_handler(USB_TASK_IRQ, usb_irq);
irq_set_enabled(USB_TASK_IRQ, true);
__usb_task_irq = user_irq_claim_unused(true);
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);
}
+2 -1
View File
@@ -24,8 +24,8 @@
// Weak function definitions for each type of endpoint
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
@@ -34,6 +34,7 @@ extern mutex_t __usb_mutex;
// HID report ID inquiry (report ID will vary depending on the number/type of other HID)
int __USBGetKeyboardReportID();
int __USBGetMouseReportID();
int __USBGetJoystickReportID();
// Called by main() to init the USB HW/SW.
void __USBStart();
+4 -4
View File
@@ -1,5 +1,5 @@
#pragma once
#define ARDUINO_PICO_MAJOR 1
#define ARDUINO_PICO_MINOR 13
#define ARDUINO_PICO_REVISION 2
#define ARDUINO_PICO_VERSION_STR "1.13.2"
#define ARDUINO_PICO_MAJOR 2
#define ARDUINO_PICO_MINOR 5
#define ARDUINO_PICO_REVISION 3
#define ARDUINO_PICO_VERSION_STR "2.5.3"
+37 -5
View File
@@ -97,7 +97,7 @@ void __not_in_flash_func(SerialPIO::_handleIRQ)() {
}
while (!pio_sm_is_rx_fifo_empty(_rxPIO, _rxSM)) {
uint32_t decode = _rxPIO->rxf[_rxSM];
decode >>= 32 - _rxBits;
decode >>= 33 - _rxBits;
uint32_t val = 0;
for (int b = 0; b < _bits + 1; b++) {
val |= (decode & (1 << (b * 2))) ? 1 << b : 0;
@@ -127,7 +127,7 @@ void __not_in_flash_func(SerialPIO::_handleIRQ)() {
asm volatile("" ::: "memory"); // Ensure the queue is written before the written count advances
_writer = next_writer;
} else {
// TODO: Overflow
_overflow = true;
}
}
}
@@ -146,6 +146,7 @@ SerialPIO::~SerialPIO() {
}
void SerialPIO::begin(unsigned long baud, uint16_t config) {
_overflow = false;
_baud = baud;
switch (config & SERIAL_PARITY_MASK) {
case SERIAL_PARITY_EVEN:
@@ -229,7 +230,7 @@ void SerialPIO::begin(unsigned long baud, uint16_t config) {
pio_sm_clear_fifos(_rxPIO, _rxSM); // Remove any existing data
// Put phase divider into OSR w/o using add'l program memory
pio_sm_put_blocking(_rxPIO, _rxSM, clock_get_hz(clk_sys) / (_baud * 2) - 2);
pio_sm_put_blocking(_rxPIO, _rxSM, clock_get_hz(clk_sys) / (_baud * 2) - 5 /* insns in PIO halfbit loop */);
pio_sm_exec(_rxPIO, _rxSM, pio_encode_pull(false, false));
// Join the TX FIFO to the RX one now that we don't need it
@@ -256,8 +257,23 @@ void SerialPIO::end() {
if (!_running) {
return;
}
// TODO: Deallocate PIO resources, stop them
_pioSP[pio_get_index(_rxPIO)][_rxSM] = nullptr;
if (_tx != NOPIN) {
pio_sm_set_enabled(_txPIO, _txSM, false);
}
if (_rx != NOPIN) {
pio_sm_set_enabled(_rxPIO, _rxSM, false);
_pioSP[pio_get_index(_rxPIO)][_rxSM] = nullptr;
// If no more active, disable the IRQ
auto pioNum = pio_get_index(_rxPIO);
bool used = false;
for (int i = 0; i < 4; i++) {
used = used || !!_pioSP[pioNum][i];
}
if (!used) {
auto irqno = pioNum == 0 ? PIO0_IRQ_0 : PIO1_IRQ_0;
irq_set_enabled(irqno, false);
}
}
_running = false;
}
@@ -289,6 +305,17 @@ int SerialPIO::read() {
return -1;
}
bool SerialPIO::overflow() {
CoreMutex m(&_mutex);
if (!_running || !m || (_rx == NOPIN)) {
return false;
}
bool hold = _overflow;
_overflow = false;
return hold;
}
int SerialPIO::available() {
CoreMutex m(&_mutex);
if (!_running || !m || (_rx == NOPIN)) {
@@ -343,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
+8 -1
View File
@@ -47,19 +47,21 @@ public:
virtual int availableForWrite() override;
virtual void flush() override;
virtual size_t write(uint8_t c) override;
bool overflow();
using Print::write;
operator bool() override;
// Not to be called by users, only from the IRQ handler. In public so that the C-language IQR callback can access it
void _handleIRQ();
private:
protected:
bool _running = false;
pin_size_t _tx, _rx;
int _baud;
int _bits;
uart_parity_t _parity;
int _stop;
bool _overflow;
mutex_t _mutex;
PIOProgram *_txPgm;
@@ -78,3 +80,8 @@ private:
uint32_t _reader;
uint8_t *_queue;
};
#ifdef ARDUINO_NANO_RP2040_CONNECT
// NINA updates
extern SerialPIO Serial3;
#endif
+58 -16
View File
@@ -131,6 +131,7 @@ void SerialUART::begin(unsigned long baud, uint16_t config) {
if (_running) {
end();
}
_overflow = false;
_queue = new uint8_t[_fifoSize];
_baud = baud;
uart_init(_uart, baud);
@@ -170,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);
@@ -210,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);
@@ -218,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() {
@@ -271,6 +287,16 @@ int SerialUART::read() {
return -1;
}
bool SerialUART::overflow() {
CoreMutex m(&_mutex);
if (!_running || !m) {
return false;
}
bool hold = _overflow;
_overflow = false;
return hold;
}
int SerialUART::available() {
CoreMutex m(&_mutex);
if (!_running || !m) {
@@ -281,7 +307,7 @@ int SerialUART::available() {
} else {
_pumpFIFO();
}
return (_writer - _reader) % _fifoSize;
return (_fifoSize + _writer - _reader) % _fifoSize;
}
int SerialUART::availableForWrite() {
@@ -339,18 +365,6 @@ SerialUART::operator bool() {
return _running;
}
#if defined(PIN_SERIAL1_RTS)
SerialUART Serial1(uart0, PIN_SERIAL1_TX, PIN_SERIAL1_RX, PIN_SERIAL1_RTS, PIN_SERIAL1_CTS);
#else
SerialUART Serial1(uart0, PIN_SERIAL1_TX, PIN_SERIAL1_RX);
#endif
#if defined(PIN_SERIAL2_RTS)
SerialUART Serial2(uart1, PIN_SERIAL2_TX, PIN_SERIAL2_RX, PIN_SERIAL2_RTS, PIN_SERIAL2_CTS);
#else
SerialUART Serial2(uart1, PIN_SERIAL2_TX, PIN_SERIAL2_RX);
#endif
void arduino::serialEvent1Run(void) {
if (serialEvent1 && Serial1.available()) {
serialEvent1();
@@ -387,7 +401,7 @@ void __not_in_flash_func(SerialUART::_handleIRQ)(bool inIRQ) {
// Avoid using division or mod because the HW divider could be in use
_writer = next_writer;
} else {
// TODO: Overflow
_overflow = true;
}
}
if (inIRQ) {
@@ -395,10 +409,38 @@ void __not_in_flash_func(SerialUART::_handleIRQ)(bool inIRQ) {
}
}
#ifndef __SERIAL1_DEVICE
#define __SERIAL1_DEVICE uart0
#endif
#ifndef __SERIAL2_DEVICE
#define __SERIAL2_DEVICE uart1
#endif
#if defined(PIN_SERIAL1_RTS)
SerialUART Serial1(__SERIAL1_DEVICE, PIN_SERIAL1_TX, PIN_SERIAL1_RX, PIN_SERIAL1_RTS, PIN_SERIAL1_CTS);
#else
SerialUART Serial1(__SERIAL1_DEVICE, PIN_SERIAL1_TX, PIN_SERIAL1_RX);
#endif
#if defined(PIN_SERIAL2_RTS)
SerialUART Serial2(__SERIAL2_DEVICE, PIN_SERIAL2_TX, PIN_SERIAL2_RX, PIN_SERIAL2_RTS, PIN_SERIAL2_CTS);
#else
SerialUART Serial2(__SERIAL2_DEVICE, PIN_SERIAL2_TX, PIN_SERIAL2_RX);
#endif
static void __not_in_flash_func(_uart0IRQ)() {
Serial1._handleIRQ();
if (__SERIAL1_DEVICE == uart0) {
Serial1._handleIRQ();
} else {
Serial2._handleIRQ();
}
}
static void __not_in_flash_func(_uart1IRQ)() {
Serial2._handleIRQ();
if (__SERIAL2_DEVICE == uart1) {
Serial2._handleIRQ();
} else {
Serial1._handleIRQ();
}
}
+3
View File
@@ -60,6 +60,7 @@ public:
virtual size_t write(uint8_t c) override;
virtual size_t write(const uint8_t *p, size_t len) override;
using Print::write;
bool overflow();
operator bool() override;
// Not to be called by users, only from the IRQ handler. In public so that the C-language IQR callback can access it
@@ -70,9 +71,11 @@ 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;
bool _overflow;
// Lockless, IRQ-handled circular queue
uint32_t _writer;
+18 -11
View File
@@ -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,13 +122,13 @@ 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;
}
static uint64_t last_avail_time;
int i = 0;
int written = 0;
if (tud_cdc_connected()) {
for (size_t i = 0; i < length;) {
int n = length - i;
@@ -136,12 +141,13 @@ size_t SerialUSB::write(const uint8_t *buf, size_t length) {
tud_task();
tud_cdc_write_flush();
i += n2;
written += n2;
last_avail_time = time_us_64();
} else {
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;
}
}
@@ -150,11 +156,12 @@ size_t SerialUSB::write(const uint8_t *buf, size_t length) {
// reset our timeout
last_avail_time = 0;
}
return i;
tud_task();
return written;
}
SerialUSB::operator bool() {
CoreMutex m(&__usb_mutex);
CoreMutex m(&__usb_mutex, false);
if (!_running || !m) {
return false;
}
+1 -4
View File
@@ -18,8 +18,7 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __SERIALUSB_H__
#define __SERIALUSB_H__
#pragma once
#include <Arduino.h>
#include "api/HardwareSerial.h"
@@ -54,5 +53,3 @@ extern SerialUSB Serial;
namespace arduino {
extern void serialEventRun(void) __attribute__((weak));
};
#endif
+59
View File
@@ -0,0 +1,59 @@
/*
SoftwareSerial wrapper for SerialPIO
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 "SerialPIO.h"
class SoftwareSerial : public SerialPIO {
public:
// Note the rx/tx pins are swapped in PIO vs SWSerial
SoftwareSerial(pin_size_t rx, pin_size_t tx, bool invert = false) : SerialPIO(tx, rx) {
_invert = invert;
}
~SoftwareSerial() {
if (_invert) {
gpio_set_outover(_tx, 0);
gpio_set_outover(_rx, 0);
}
}
virtual void begin(unsigned long baud = 115200) override {
begin(baud, SERIAL_8N1);
};
void begin(unsigned long baud, uint16_t config) override {
SerialPIO::begin(baud, config);
if (_invert) {
gpio_set_outover(_tx, GPIO_OVERRIDE_INVERT);
gpio_set_inover(_rx, GPIO_OVERRIDE_INVERT);
}
}
void listen() { /* noop */ }
bool isListening() {
return true;
}
private:
bool _invert;
};
+247
View File
@@ -0,0 +1,247 @@
/**
StreamString.h
Copyright (c) 2020 D. Gauchard. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
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 __STREAMSTRING_H
#define __STREAMSTRING_H
#include <limits>
#include <algorithm>
#include "Stream.h"
#include "api/String.h"
///////////////////////////////////////////////////////////////
// S2Stream points to a String and makes it a Stream
// (it is also the helper for StreamString)
class S2Stream: public Stream {
public:
S2Stream(String& string, int peekPointer = -1) : string(&string), peekPointer(peekPointer) { }
S2Stream(String* string, int peekPointer = -1) : string(string), peekPointer(peekPointer) { }
virtual int available() override {
return string->length();
}
virtual int availableForWrite() override {
return std::numeric_limits<int16_t>::max();
}
virtual int read() override {
if (peekPointer < 0) {
// consume chars
if (string->length()) {
char c = string->charAt(0);
string->remove(0, 1);
return c;
}
} else if (peekPointer < (int)string->length()) {
// return pointed and move pointer
return string->charAt(peekPointer++);
}
// everything is read
return -1;
}
virtual size_t write(uint8_t data) override {
return string->concat((char)data);
}
// virtual int read(uint8_t* buffer, size_t len) override
// {
// if (peekPointer < 0)
// {
// // string will be consumed
// size_t l = std::min(len, (size_t)string->length());
// memcpy(buffer, string->c_str(), l);
// string->remove(0, l);
// return l;
// }
//
// if (peekPointer >= (int)string->length())
// {
// return 0;
// }
//
// // only the pointer is moved
// size_t l = std::min(len, (size_t)(string->length() - peekPointer));
// memcpy(buffer, string->c_str() + peekPointer, l);
// peekPointer += l;
// return l;
// }
virtual size_t write(const uint8_t* buffer, size_t len) override {
return string->concat((const char*)buffer, len) ? len : 0;
}
virtual int peek() override {
if (peekPointer < 0) {
if (string->length()) {
return string->charAt(0);
}
} else if (peekPointer < (int)string->length()) {
return string->charAt(peekPointer);
}
return -1;
}
virtual void flush() override {
// nothing to do
}
#if 0
virtual bool inputCanTimeout() override {
return false;
}
virtual bool outputCanTimeout() override {
return false;
}
//// Stream's peekBufferAPI
virtual bool hasPeekBufferAPI() const override {
return true;
}
virtual size_t peekAvailable() {
if (peekPointer < 0) {
return string->length();
}
return string->length() - peekPointer;
}
virtual const char* peekBuffer() override {
if (peekPointer < 0) {
return string->c_str();
}
if (peekPointer < (int)string->length()) {
return string->c_str() + peekPointer;
}
return nullptr;
}
virtual void peekConsume(size_t consume) override {
if (peekPointer < 0) {
// string is really consumed
string->remove(0, consume);
} else {
// only the pointer is moved
peekPointer = std::min((size_t)string->length(), peekPointer + consume);
}
}
virtual ssize_t streamRemaining() override {
return peekPointer < 0 ? string->length() : string->length() - peekPointer;
}
// calling setConsume() will consume bytes as the stream is read
// (enabled by default)
void setConsume() {
peekPointer = -1;
}
#endif
// Reading this stream will mark the string as read without consuming
// (not enabled by default)
// Calling resetPointer() resets the read state and allows rereading.
void resetPointer(int pointer = 0) {
peekPointer = pointer;
}
protected:
String* string;
int peekPointer; // -1:String is consumed / >=0:resettable pointer
};
// StreamString is a S2Stream holding the String
class StreamString: public String, public S2Stream {
protected:
void resetpp() {
if (peekPointer > 0) {
peekPointer = 0;
}
}
public:
StreamString(StreamString&& bro) : String(bro), S2Stream(this) { }
StreamString(const StreamString& bro) : String(bro), S2Stream(this) { }
// duplicate String constructors and operator=:
StreamString(const char* text = nullptr) : String(text), S2Stream(this) { }
StreamString(const String& string) : String(string), S2Stream(this) { }
StreamString(const __FlashStringHelper* str) : String(str), S2Stream(this) { }
StreamString(String&& string) : String(string), S2Stream(this) { }
explicit StreamString(char c) : String(c), S2Stream(this) { }
explicit StreamString(unsigned char c, unsigned char base = 10) :
String(c, base), S2Stream(this) {
}
explicit StreamString(int i, unsigned char base = 10) : String(i, base), S2Stream(this) { }
explicit StreamString(unsigned int i, unsigned char base = 10) : String(i, base), S2Stream(this) {
}
explicit StreamString(long l, unsigned char base = 10) : String(l, base), S2Stream(this) { }
explicit StreamString(unsigned long l, unsigned char base = 10) :
String(l, base), S2Stream(this) {
}
explicit StreamString(float f, unsigned char decimalPlaces = 2) :
String(f, decimalPlaces), S2Stream(this) {
}
explicit StreamString(double d, unsigned char decimalPlaces = 2) :
String(d, decimalPlaces), S2Stream(this) {
}
StreamString& operator=(const StreamString& rhs) {
String::operator=(rhs);
resetpp();
return *this;
}
StreamString& operator=(const String& rhs) {
String::operator=(rhs);
resetpp();
return *this;
}
StreamString& operator=(const char* cstr) {
String::operator=(cstr);
resetpp();
return *this;
}
StreamString& operator=(const __FlashStringHelper* str) {
String::operator=(str);
resetpp();
return *this;
}
StreamString& operator=(String&& rval) {
String::operator=(rval);
resetpp();
return *this;
}
};
#endif // __STREAMSTRING_H
+1 -1
View File
@@ -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;
}
+51
View File
@@ -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!
}
+64
View File
@@ -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;
+2 -57
View File
@@ -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
View File
@@ -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 -45
View File
@@ -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
View File
@@ -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
View File
@@ -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"
+2 -16
View File
@@ -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 -46
View File
@@ -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 -129
View File
@@ -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 -104
View File
@@ -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 -127
View File
@@ -1,127 +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 "IPAddress.h"
#include "Print.h"
using namespace arduino;
IPAddress::IPAddress()
{
_address.dword = 0;
}
IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet)
{
_address.bytes[0] = first_octet;
_address.bytes[1] = second_octet;
_address.bytes[2] = third_octet;
_address.bytes[3] = fourth_octet;
}
IPAddress::IPAddress(uint32_t address)
{
_address.dword = address;
}
IPAddress::IPAddress(const uint8_t *address)
{
memcpy(_address.bytes, address, sizeof(_address.bytes));
}
bool IPAddress::fromString(const char *address)
{
// TODO: add support for "a", "a.b", "a.b.c" formats
int16_t acc = -1; // Accumulator
uint8_t dots = 0;
while (*address)
{
char c = *address++;
if (c >= '0' && c <= '9')
{
acc = (acc < 0) ? (c - '0') : 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;
}
if (acc < 0) {
/* No value between dots, e.g. '1..' */
return false;
}
_address.bytes[dots++] = acc;
acc = -1;
}
else
{
// Invalid char
return false;
}
}
if (dots != 3) {
// Too few dots (there must be 3 dots)
return false;
}
if (acc < 0) {
/* No value between dots, e.g. '1..' */
return false;
}
_address.bytes[3] = acc;
return true;
}
IPAddress& IPAddress::operator=(const uint8_t *address)
{
memcpy(_address.bytes, address, sizeof(_address.bytes));
return *this;
}
IPAddress& IPAddress::operator=(uint32_t address)
{
_address.dword = address;
return *this;
}
bool IPAddress::operator==(const uint8_t* addr) const
{
return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0;
}
size_t IPAddress::printTo(Print& p) const
{
size_t n = 0;
for (int i =0; i < 3; i++)
{
n += p.print(_address.bytes[i], DEC);
n += p.print('.');
}
n += p.print(_address.bytes[3], DEC);
return n;
}
const IPAddress arduino::INADDR_NONE(0,0,0,0);
#include "../../../ArduinoCore-API/api/IPAddress.cpp"
+1 -84
View File
@@ -1,85 +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 "Printable.h"
#include "String.h"
// forward declartions of global name space friend classes
class EthernetClass;
class DhcpClass;
class DNSClient;
namespace arduino {
// A class to make it easier to handle and pass around IP addresses
class IPAddress : public Printable {
private:
union {
uint8_t bytes[4]; // IPv4 address
uint32_t dword;
} _address;
// 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 _address.bytes; };
public:
// Constructors
IPAddress();
IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet);
IPAddress(uint32_t 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 _address.dword; };
bool operator==(const IPAddress& addr) const { return _address.dword == addr._address.dword; };
bool operator!=(const IPAddress& addr) const { return _address.dword != addr._address.dword; };
bool operator==(const uint8_t* addr) const;
// Overloaded index operator to allow getting and setting individual octets of the address
uint8_t operator[](int index) const { return _address.bytes[index]; };
uint8_t& operator[](int index) { return _address.bytes[index]; };
// Overloaded copy operators to allow initialisation of IPAddress objects from other types
IPAddress& operator=(const uint8_t *address);
IPAddress& operator=(uint32_t address);
virtual size_t printTo(Print& p) const;
friend class UDP;
friend class Client;
friend class Server;
friend ::EthernetClass;
friend ::DhcpClass;
friend ::DNSClient;
};
extern const IPAddress INADDR_NONE;
}
#include "../../../ArduinoCore-API/api/IPAddress.h"
+2 -44
View File
@@ -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 = &param;
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
View File
@@ -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"
+2 -78
View File
@@ -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
View File
@@ -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 -99
View File
@@ -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 -38
View File
@@ -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
View File
@@ -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 -30
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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"
+2 -64
View File
@@ -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
View File
@@ -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"
+2 -171
View File
@@ -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
View File
@@ -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"
+62
View File
@@ -0,0 +1,62 @@
; Cycle Count for the Raspberry Pi Pico RP2040
;
; 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
; Cycle count is stored in {-y, -x}
.program ccount
cnt:
jmp x-- cnt
epoch:
jmp y-- cnt
% c-sdk {
static inline void ccount_program_init(PIO pio, uint sm, uint offset) {
pio_sm_config c = ccount_program_get_default_config(offset);
pio_sm_init(pio, sm, offset, &c);
pio_sm_exec(pio, sm, pio_encode_set(pio_x, 0));
pio_sm_exec(pio, sm, pio_encode_set(pio_y, 0));
}
static inline uint64_t ccount_read(PIO pio, uint sm) {
static uint64_t extra = 0;
// Guard against having the epoch rollover while we're reading the time.
// If epoch2 != epoch1, we looped in middle and get new LSW
pio_sm_exec(pio, sm, pio_encode_mov(pio_isr, pio_y));
pio_sm_exec(pio, sm, pio_encode_push(false, false));
pio_sm_exec(pio, sm, pio_encode_mov(pio_isr, pio_x));
pio_sm_exec(pio, sm, pio_encode_push(false, false));
pio_sm_exec(pio, sm, pio_encode_mov(pio_isr, pio_y));
pio_sm_exec(pio, sm, pio_encode_push(false, false));
pio_sm_exec(pio, sm, pio_encode_mov(pio_isr, pio_x));
pio_sm_exec(pio, sm, pio_encode_push(false, false));
extra += 8;
uint32_t y1 = -((int)pio_sm_get_blocking(pio, sm));
uint32_t x1 = -((int)pio_sm_get_blocking(pio, sm));
uint32_t y2 = -((int)pio_sm_get_blocking(pio, sm));
uint32_t x2 = -((int)pio_sm_get_blocking(pio, sm));
uint64_t val;
if (y2 != y1) {
val = ((((uint64_t)y2) << 32LL) | x2) + y2 /* adjust for missed cycle every epoch increment */;
} else {
val = ((((uint64_t)y1) << 32LL) | x1) + y1 /* adjust for missed cycle every epoch increment */;
}
return val + extra;
}
%}
+71
View File
@@ -0,0 +1,71 @@
// -------------------------------------------------- //
// This file is autogenerated by pioasm; do not edit! //
// -------------------------------------------------- //
#pragma once
#if !PICO_NO_HARDWARE
#include "hardware/pio.h"
#endif
// ------ //
// ccount //
// ------ //
#define ccount_wrap_target 0
#define ccount_wrap 1
static const uint16_t ccount_program_instructions[] = {
// .wrap_target
0x0040, // 0: jmp x--, 0
0x0080, // 1: jmp y--, 0
// .wrap
};
#if !PICO_NO_HARDWARE
static const struct pio_program ccount_program = {
.instructions = ccount_program_instructions,
.length = 2,
.origin = -1,
};
static inline pio_sm_config ccount_program_get_default_config(uint offset) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, offset + ccount_wrap_target, offset + ccount_wrap);
return c;
}
static inline void ccount_program_init(PIO pio, uint sm, uint offset) {
pio_sm_config c = ccount_program_get_default_config(offset);
pio_sm_init(pio, sm, offset, &c);
pio_sm_exec(pio, sm, pio_encode_set(pio_x, 0));
pio_sm_exec(pio, sm, pio_encode_set(pio_y, 0));
}
static inline uint64_t ccount_read(PIO pio, uint sm) {
static uint64_t extra = 0;
// Guard against having the epoch rollover while we're reading the time.
// If epoch2 != epoch1, we looped in middle and get new LSW
pio_sm_exec(pio, sm, pio_encode_mov(pio_isr, pio_y));
pio_sm_exec(pio, sm, pio_encode_push(false, false));
pio_sm_exec(pio, sm, pio_encode_mov(pio_isr, pio_x));
pio_sm_exec(pio, sm, pio_encode_push(false, false));
pio_sm_exec(pio, sm, pio_encode_mov(pio_isr, pio_y));
pio_sm_exec(pio, sm, pio_encode_push(false, false));
pio_sm_exec(pio, sm, pio_encode_mov(pio_isr, pio_x));
pio_sm_exec(pio, sm, pio_encode_push(false, false));
extra += 8;
uint32_t y1 = -((int)pio_sm_get_blocking(pio, sm));
uint32_t x1 = -((int)pio_sm_get_blocking(pio, sm));
uint32_t y2 = -((int)pio_sm_get_blocking(pio, sm));
uint32_t x2 = -((int)pio_sm_get_blocking(pio, sm));
uint64_t val;
if (y2 != y1) {
val = ((((uint64_t)y2) << 32LL) | x2) + y2 /* adjust for missed cycle every epoch increment */;
} else {
val = ((((uint64_t)y1) << 32LL) | x1) + y1 /* adjust for missed cycle every epoch increment */;
}
return val + extra;
}
#endif
+3
View File
@@ -25,6 +25,9 @@
#include "Adafruit_TinyUSB_API.h"
#endif
extern "C" void delay(unsigned long ms) __attribute__((weak));
extern "C" void yield() __attribute__((weak));
extern "C"
{
+7
View File
@@ -0,0 +1,7 @@
libb64: Base64 Encoding/Decoding Routines
======================================
Authors:
-------
Chris Venter chris.venter@gmail.com http://rocketpod.blogspot.com
+29
View File
@@ -0,0 +1,29 @@
Copyright-Only Dedication (based on United States law)
or Public Domain Certification
The person or persons who have associated work with this document (the
"Dedicator" or "Certifier") hereby either (a) certifies that, to the best of
his knowledge, the work of authorship identified is in the public domain of the
country from which the work is published, or (b) hereby dedicates whatever
copyright the dedicators holds in the work of authorship identified below (the
"Work") to the public domain. A certifier, moreover, dedicates any copyright
interest he may have in the associated work, and for these purposes, is
described as a "dedicator" below.
A certifier has taken reasonable steps to verify the copyright status of this
work. Certifier recognizes that his good faith efforts may not shield him from
liability if in fact the work certified is not in the public domain.
Dedicator makes this dedication for the benefit of the public at large and to
the detriment of the Dedicator's heirs and successors. Dedicator intends this
dedication to be an overt act of relinquishment in perpetuity of all present
and future rights under copyright law, whether vested or contingent, in the
Work. Dedicator understands that such relinquishment of all rights includes
the relinquishment of all rights to enforce (by lawsuit or otherwise) those
copyrights in the Work.
Dedicator recognizes that, once placed in the public domain, the Work may be
freely reproduced, distributed, transmitted, used, modified, built upon, or
otherwise exploited by anyone for any purpose, commercial or non-commercial,
and in any way, including by methods that have not yet been invented or
conceived.
+111
View File
@@ -0,0 +1,111 @@
/*
cdecoder.c - c source to a base64 decoding algorithm implementation
This is part of the libb64 project, and has been placed in the public domain.
For details, see http://sourceforge.net/projects/libb64
*/
#include <pgmspace.h>
#include <stdint.h>
#include "cdecode.h"
extern "C" {
static int base64_decode_value_signed(int8_t value_in) {
static const int8_t decoding[] PROGMEM = {62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51};
static const int8_t decoding_size = sizeof(decoding);
value_in -= 43;
if (value_in < 0 || value_in > decoding_size) {
return -1;
}
return pgm_read_byte(&decoding[(int)value_in]);
}
void base64_init_decodestate(base64_decodestate* state_in) {
state_in->step = step_a;
state_in->plainchar = 0;
}
static int base64_decode_block_signed(const int8_t* code_in, const int length_in, int8_t* plaintext_out, base64_decodestate* state_in) {
const int8_t* codechar = code_in;
int8_t* plainchar = plaintext_out;
int8_t fragment;
*plainchar = state_in->plainchar;
switch (state_in->step) {
while (1) {
case step_a:
do {
if (codechar == code_in + length_in) {
state_in->step = step_a;
state_in->plainchar = *plainchar;
return plainchar - plaintext_out;
}
fragment = (int8_t)base64_decode_value_signed(*codechar++);
} while (fragment < 0);
*plainchar = (fragment & 0x03f) << 2;
// falls through
case step_b:
do {
if (codechar == code_in + length_in) {
state_in->step = step_b;
state_in->plainchar = *plainchar;
return plainchar - plaintext_out;
}
fragment = (int8_t)base64_decode_value_signed(*codechar++);
} while (fragment < 0);
*plainchar++ |= (fragment & 0x030) >> 4;
*plainchar = (fragment & 0x00f) << 4;
// falls through
case step_c:
do {
if (codechar == code_in + length_in) {
state_in->step = step_c;
state_in->plainchar = *plainchar;
return plainchar - plaintext_out;
}
fragment = (int8_t)base64_decode_value_signed(*codechar++);
} while (fragment < 0);
*plainchar++ |= (fragment & 0x03c) >> 2;
*plainchar = (fragment & 0x003) << 6;
// falls through
case step_d:
do {
if (codechar == code_in + length_in) {
state_in->step = step_d;
state_in->plainchar = *plainchar;
return plainchar - plaintext_out;
}
fragment = (int8_t)base64_decode_value_signed(*codechar++);
} while (fragment < 0);
*plainchar++ |= (fragment & 0x03f);
}
}
/* control should not reach here */
return plainchar - plaintext_out;
}
static int base64_decode_chars_signed(const int8_t* code_in, const int length_in, int8_t* plaintext_out) {
base64_decodestate _state;
base64_init_decodestate(&_state);
int len = base64_decode_block_signed(code_in, length_in, plaintext_out, &_state);
if (len > 0) {
plaintext_out[len] = 0;
}
return len;
}
int base64_decode_value(char value_in) {
return base64_decode_value_signed(*((int8_t *) &value_in));
}
int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in) {
return base64_decode_block_signed((int8_t *) code_in, length_in, (int8_t *) plaintext_out, state_in);
}
int base64_decode_chars(const char* code_in, const int length_in, char* plaintext_out) {
return base64_decode_chars_signed((int8_t *) code_in, length_in, (int8_t *) plaintext_out);
}
};
+35
View File
@@ -0,0 +1,35 @@
/*
cdecode.h - c header for a base64 decoding algorithm
This is part of the libb64 project, and has been placed in the public domain.
For details, see http://sourceforge.net/projects/libb64
*/
#pragma once
#define base64_decode_expected_len(n) ((n * 3) / 4)
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
step_a, step_b, step_c, step_d
} base64_decodestep;
typedef struct {
base64_decodestep step;
char plainchar;
} base64_decodestate;
void base64_init_decodestate(base64_decodestate* state_in);
int base64_decode_value(char value_in);
int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in);
int base64_decode_chars(const char* code_in, const int length_in, char* plaintext_out);
#ifdef __cplusplus
} // extern "C"
#endif
+126
View File
@@ -0,0 +1,126 @@
/*
cencoder.c - c source to a base64 encoding algorithm implementation
This is part of the libb64 project, and has been placed in the public domain.
For details, see http://sourceforge.net/projects/libb64
*/
#include "cencode.h"
extern "C" {
void base64_init_encodestate(base64_encodestate* state_in) {
state_in->step = step_A;
state_in->result = 0;
state_in->stepcount = 0;
state_in->stepsnewline = BASE64_CHARS_PER_LINE;
}
void base64_init_encodestate_nonewlines(base64_encodestate* state_in) {
base64_init_encodestate(state_in);
state_in->stepsnewline = -1;
}
char base64_encode_value(const char n) {
char r;
if (n < 26) {
r = n + 'A';
} else if (n < 26 + 26) {
r = n - 26 + 'a';
} else if (n < 26 + 26 + 10) {
r = n - 26 - 26 + '0';
} else if (n == 62) {
r = '+';
} else {
r = '/';
}
return r;
}
int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in) {
const char* plainchar = plaintext_in;
const char* const plaintextend = plaintext_in + length_in;
char* codechar = code_out;
char result;
char fragment;
result = state_in->result;
switch (state_in->step) {
while (1) {
case step_A:
if (plainchar == plaintextend) {
state_in->result = result;
state_in->step = step_A;
return codechar - code_out;
}
fragment = *plainchar++;
result = (fragment & 0x0fc) >> 2;
*codechar++ = base64_encode_value(result);
result = (fragment & 0x003) << 4;
// falls through
case step_B:
if (plainchar == plaintextend) {
state_in->result = result;
state_in->step = step_B;
return codechar - code_out;
}
fragment = *plainchar++;
result |= (fragment & 0x0f0) >> 4;
*codechar++ = base64_encode_value(result);
result = (fragment & 0x00f) << 2;
// falls through
case step_C:
if (plainchar == plaintextend) {
state_in->result = result;
state_in->step = step_C;
return codechar - code_out;
}
fragment = *plainchar++;
result |= (fragment & 0x0c0) >> 6;
*codechar++ = base64_encode_value(result);
result = (fragment & 0x03f) >> 0;
*codechar++ = base64_encode_value(result);
++(state_in->stepcount);
if ((state_in->stepcount == BASE64_CHARS_PER_LINE / 4) && (state_in->stepsnewline > 0)) {
*codechar++ = '\n';
state_in->stepcount = 0;
}
}
}
/* control should not reach here */
return codechar - code_out;
}
int base64_encode_blockend(char* code_out, base64_encodestate* state_in) {
char* codechar = code_out;
switch (state_in->step) {
case step_B:
*codechar++ = base64_encode_value(state_in->result);
*codechar++ = '=';
*codechar++ = '=';
break;
case step_C:
*codechar++ = base64_encode_value(state_in->result);
*codechar++ = '=';
break;
case step_A:
break;
}
*codechar = 0x00;
return codechar - code_out;
}
int base64_encode_chars(const char* plaintext_in, int length_in, char* code_out) {
base64_encodestate _state;
base64_init_encodestate(&_state);
int len = base64_encode_block(plaintext_in, length_in, code_out, &_state);
return len + base64_encode_blockend((code_out + len), &_state);
}
};
+45
View File
@@ -0,0 +1,45 @@
/*
cencode.h - c header for a base64 encoding algorithm
This is part of the libb64 project, and has been placed in the public domain.
For details, see http://sourceforge.net/projects/libb64
*/
#pragma once
#define BASE64_CHARS_PER_LINE 72
#define base64_encode_expected_len_nonewlines(n) ((((4 * (n)) / 3) + 3) & ~3)
#define base64_encode_expected_len(n) \
(base64_encode_expected_len_nonewlines(n) + ((n / ((BASE64_CHARS_PER_LINE * 3) / 4)) + 1))
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
step_A, step_B, step_C
} base64_encodestep;
typedef struct {
base64_encodestep step;
char result;
int stepcount;
int stepsnewline;
} base64_encodestate;
void base64_init_encodestate(base64_encodestate* state_in);
void base64_init_encodestate_nonewlines(base64_encodestate* state_in);
char base64_encode_value(char value_in);
int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in);
int base64_encode_blockend(char* code_out, base64_encodestate* state_in);
int base64_encode_chars(const char* plaintext_in, int length_in, char* code_out);
#ifdef __cplusplus
} // extern "C"
#endif
+182
View File
@@ -0,0 +1,182 @@
/*
Newlib retargetable lock class using RP2040 SDK
Overrides weak functions in Newlib for locking to safely support
multi-core operation. Does not need any --wrap for memory allocators.
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 <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
// these mutextes, so instead of hacking pico-sdk just make "static" a no-op.
#define static
auto_init_recursive_mutex(__lock___sinit_recursive_mutex);
auto_init_recursive_mutex(__lock___sfp_recursive_mutex);
auto_init_recursive_mutex(__lock___atexit_recursive_mutex);
auto_init_mutex(__lock___at_quick_exit_mutex);
auto_init_recursive_mutex(__lock___malloc_recursive_mutex);
auto_init_recursive_mutex(__lock___env_recursive_mutex);
auto_init_mutex(__lock___tz_mutex);
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) {
if (__freeRTOSinitted) {
/* Already done in initFreeRTOSMutexes() */
} else {
mutex_init((mutex_t*) lock);
}
}
void __retarget_lock_init_recursive(_LOCK_T *lock) {
if (__freeRTOSinitted) {
/* Already done in initFreeRTOSMutexes() */
} else {
recursive_mutex_init((recursive_mutex_t*) lock);
}
}
void __retarget_lock_close(_LOCK_T lock) {
(void) lock;
}
void __retarget_lock_close_recursive(_LOCK_T lock) {
(void) lock;
}
void __retarget_lock_acquire(_LOCK_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) {
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) {
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) {
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) {
if (__freeRTOSinitted) {
auto mtx = __getFreeRTOSMutex(lock);
__freertos_mutex_give(mtx);
} else {
mutex_exit((mutex_t*)lock);
}
}
void __retarget_lock_release_recursive(_LOCK_T lock) {
if (__freeRTOSinitted) {
auto mtx = __getFreeRTOSRecursiveMutex(lock);
__freertos_recursive_mutex_give(mtx);
} else {
recursive_mutex_exit((recursive_mutex_t*)lock);
}
}
+92 -26
View File
@@ -22,22 +22,33 @@
#include "RP2040USB.h"
#include <pico/stdlib.h>
#include <pico/multicore.h>
#include "LWIPMutex.h"
#include <reent.h>
RP2040 rp2040;
extern "C" {
volatile bool __otherCoreIdled = false;
int __holdUpPendSV = 0;
};
volatile bool _MFIFO::_otherIdled = false;
mutex_t _pioMutex;
int LWIPMutex::_ref = 0;
extern void setup();
extern void loop();
// FreeRTOS potential includes
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));
void initVariant() { }
// Optional 2nd core setup and loop
extern void setup1() __attribute__((weak));
extern void loop1() __attribute__((weak));
@@ -53,14 +64,47 @@ extern "C" void main1() {
}
}
extern void __loop() {
#ifdef USE_TINYUSB
yield();
#endif
if (arduino::serialEventRun) {
arduino::serialEventRun();
}
if (arduino::serialEvent1Run) {
arduino::serialEvent1Run();
}
if (arduino::serialEvent2Run) {
arduino::serialEvent2Run();
}
}
static struct _reent *_impure_ptr1 = nullptr;
extern "C" int main() {
#if F_CPU != 125000000
set_sys_clock_khz(F_CPU / 1000, true);
#endif
// Let rest of core know if we're using FreeRTOS
__isFreeRTOS = initFreeRTOS ? true : false;
// Allocate impure_ptr (newlib temps) if there is a 2nd core running
if (!__isFreeRTOS && (setup1 || loop1)) {
_impure_ptr1 = (struct _reent*)calloc(sizeof(struct _reent), 1);
_REENT_INIT_PTR(_impure_ptr1);
}
mutex_init(&_pioMutex);
rp2040.begin();
initVariant();
if (__isFreeRTOS) {
initFreeRTOS();
}
#ifndef NO_USB
#ifdef USE_TINYUSB
TinyUSB_Device_Init(0);
@@ -69,43 +113,65 @@ extern "C" int main() {
__USBStart();
#ifndef DISABLE_USB_SERIAL
// Enable serial port for reset/upload always
Serial.begin(115200);
if (!__isFreeRTOS) {
// Enable serial port for reset/upload always
Serial.begin(115200);
}
#endif
#endif
#endif
#if defined DEBUG_RP2040_PORT
DEBUG_RP2040_PORT.begin(115200);
if (!__isFreeRTOS) {
DEBUG_RP2040_PORT.begin(115200);
}
#endif
#ifndef NO_USB
if (setup1 || loop1) {
rp2040.fifo.begin(2);
multicore_launch_core1(main1);
} else {
rp2040.fifo.begin(1);
if (!__isFreeRTOS) {
if (setup1 || loop1) {
rp2040.fifo.begin(2);
} else {
rp2040.fifo.begin(1);
}
rp2040.fifo.registerCore();
}
rp2040.fifo.registerCore();
#endif
setup();
while (true) {
loop();
#ifdef USE_TINYUSB
yield();
#endif
if (arduino::serialEventRun) {
arduino::serialEventRun();
if (!__isFreeRTOS) {
if (setup1 || loop1) {
delay(1); // Needed to make Picoprobe upload start 2nd core
multicore_launch_core1(main1);
}
if (arduino::serialEvent1Run) {
arduino::serialEvent1Run();
}
if (arduino::serialEvent2Run) {
arduino::serialEvent2Run();
setup();
while (true) {
loop();
__loop();
}
} else {
rp2040.fifo.begin(2);
startFreeRTOS();
}
return 0;
}
extern "C" unsigned long ulMainGetRunTimeCounterValue() {
return rp2040.getCycleCount64();
}
extern "C" void __register_impure_ptr(struct _reent *p) {
if (get_core_num() == 0) {
_impure_ptr = p;
} else {
_impure_ptr1 = p;
}
}
extern "C" struct _reent *__wrap___getreent() {
if (get_core_num() == 0) {
return _impure_ptr;
} else {
return _impure_ptr1;
}
}
+10 -3
View File
@@ -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,13 +101,20 @@ 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;
}
return 0;
}
// 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 * 1'000'000LL + usec;
__timedelta_us = newnow_us - now_us;
}
extern "C" int _isatty(int file) {
(void) file;
errno = ENOSYS;
@@ -0,0 +1,348 @@
/*
Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
SPDX-License-Identifier: BSD-3-Clause
*/
// Taken from the Pico-SDK v1.4.0 and hacked by EFP3 to allow overriding the LWIP setup
#include <stdio.h>
#include "pico/cyw43_arch.h"
#include "pico/mutex.h"
#include "pico/sem.h"
#include "hardware/gpio.h"
#include "hardware/irq.h"
#include "cyw43_stats.h"
#include <lwip/init.h>
#include "lwip/timeouts.h"
#ifndef CYW43_PIN_WL_HOST_WAKE
#define CYW43_PIN_WL_HOST_WAKE 24
#endif
#ifndef CYW43_PIN_WL_REG_ON
#define CYW43_PIN_WL_REG_ON 23
#endif
#ifndef CYW43_WL_GPIO_COUNT
#define CYW43_WL_GPIO_COUNT 3
#endif
#ifndef CYW43_WL_GPIO_LED_PIN
#define CYW43_WL_GPIO_LED_PIN 0
#endif
volatile bool __inLWIP = false;
// note same code
#if PICO_CYW43_ARCH_THREADSAFE_BACKGROUND
#if PICO_CYW43_ARCH_THREADSAFE_BACKGROUND && CYW43_LWIP && !NO_SYS
#error PICO_CYW43_ARCH_THREADSAFE_BACKGROUND requires lwIP NO_SYS=1
#endif
#if PICO_CYW43_ARCH_THREADSAFE_BACKGROUND && CYW43_LWIP && MEM_LIBC_MALLOC
#error MEM_LIBC_MALLOC is incompatible with PICO_CYW43_ARCH_THREADSAFE_BACKGROUND
#endif
// todo right now we are now always doing a cyw43_dispatch along with a lwip one when hopping cores in low_prio_irq_schedule_dispatch
#ifndef CYW43_SLEEP_CHECK_MS
#define CYW43_SLEEP_CHECK_MS 50 // How often to run lwip callback
#endif
static alarm_id_t periodic_alarm = -1;
static inline uint recursive_mutex_enter_count(recursive_mutex_t *mutex) {
return mutex->enter_count;
}
static inline lock_owner_id_t recursive_mutex_owner(recursive_mutex_t *mutex) {
return mutex->owner;
}
#define CYW43_GPIO_IRQ_HANDLER_PRIORITY 0x40
enum {
CYW43_DISPATCH_SLOT_CYW43 = 0,
CYW43_DISPATCH_SLOT_ADAPTER,
CYW43_DISPATCH_SLOT_ENUM_COUNT
};
#ifndef CYW43_DISPATCH_SLOT_COUNT
#define CYW43_DISPATCH_SLOT_COUNT CYW43_DISPATCH_SLOT_ENUM_COUNT
#endif
typedef void (*low_prio_irq_dispatch_t)(void);
static void low_prio_irq_schedule_dispatch(size_t slot, low_prio_irq_dispatch_t f);
static uint8_t cyw43_core_num;
#ifndef NDEBUG
static bool in_low_priority_irq;
#endif
static uint8_t low_priority_irq_num;
static bool low_priority_irq_missed;
static low_prio_irq_dispatch_t low_priority_irq_dispatch_slots[CYW43_DISPATCH_SLOT_COUNT];
static recursive_mutex_t cyw43_mutex;
semaphore_t cyw43_irq_sem;
// Called in low priority pendsv interrupt only to do lwip processing and check cyw43 sleep
static void periodic_worker(void) {
#if CYW43_USE_STATS && LWIP_SYS_CHECK_MS
static uint32_t counter;
if (counter++ % (30000 / LWIP_SYS_CHECK_MS) == 0) {
cyw43_dump_stats();
}
#endif
CYW43_STAT_INC(LWIP_RUN_COUNT);
//#if CYW43_LWIP
if (!__inLWIP) {
sys_check_timeouts();
}
//#endif
if (cyw43_poll) {
if (cyw43_sleep > 0) {
if (--cyw43_sleep == 0) {
low_prio_irq_schedule_dispatch(CYW43_DISPATCH_SLOT_CYW43, cyw43_poll);
}
}
}
}
// Regular callback to get lwip to check for timeouts
static int64_t periodic_alarm_handler(__unused alarm_id_t id, __unused void *user_data) {
// Do lwip processing in low priority pendsv interrupt
low_prio_irq_schedule_dispatch(CYW43_DISPATCH_SLOT_ADAPTER, periodic_worker);
return CYW43_SLEEP_CHECK_MS * 1000;
}
void cyw43_await_background_or_timeout_us(uint32_t timeout_us) {
// if we are called from within an IRQ, then don't wait (we are only ever called in a polling loop)
if (!__get_current_exception()) {
sem_acquire_timeout_us(&cyw43_irq_sem, timeout_us);
}
}
// GPIO interrupt handler to tell us there's cyw43 has work to do
static void gpio_irq_handler(void) {
uint32_t events = gpio_get_irq_event_mask(CYW43_PIN_WL_HOST_WAKE);
if (events & GPIO_IRQ_LEVEL_HIGH) {
// As we use a high level interrupt, it will go off forever until it's serviced
// So disable the interrupt until this is done. It's re-enabled again by CYW43_POST_POLL_HOOK
// which is called at the end of cyw43_poll_func
gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, false);
// also clear the force bit which we use to progratically cause this handler to fire (on the right core)
io_irq_ctrl_hw_t *irq_ctrl_base = get_core_num() ?
&iobank0_hw->proc1_irq_ctrl : &iobank0_hw->proc0_irq_ctrl;
hw_clear_bits(&irq_ctrl_base->intf[CYW43_PIN_WL_HOST_WAKE / 8], GPIO_IRQ_LEVEL_HIGH << (4 * (CYW43_PIN_WL_HOST_WAKE & 7)));
low_prio_irq_schedule_dispatch(CYW43_DISPATCH_SLOT_CYW43, cyw43_poll);
CYW43_STAT_INC(IRQ_COUNT);
}
}
// Low priority interrupt handler to perform background processing
static void low_priority_irq_handler(void) {
assert(cyw43_core_num == get_core_num());
if (recursive_mutex_try_enter(&cyw43_mutex, NULL)) {
if (recursive_mutex_enter_count(&cyw43_mutex) != 1) {
low_priority_irq_missed = true;
CYW43_STAT_INC(PENDSV_DISABLED_COUNT);
} else {
CYW43_STAT_INC(PENDSV_RUN_COUNT);
#ifndef NDEBUG
in_low_priority_irq = true;
#endif
for (size_t i = 0; i < count_of(low_priority_irq_dispatch_slots); i++) {
if (low_priority_irq_dispatch_slots[i] != NULL) {
low_prio_irq_dispatch_t f = low_priority_irq_dispatch_slots[i];
low_priority_irq_dispatch_slots[i] = NULL;
f();
}
}
#ifndef NDEBUG
in_low_priority_irq = false;
#endif
}
recursive_mutex_exit(&cyw43_mutex);
} else {
CYW43_STAT_INC(PENDSV_DISABLED_COUNT);
low_priority_irq_missed = true;
}
sem_release(&cyw43_irq_sem);
}
static bool low_prio_irq_init(uint8_t priority) {
assert(get_core_num() == cyw43_core_num);
int irq = user_irq_claim_unused(false);
if (irq < 0) {
return false;
}
low_priority_irq_num = (uint8_t) irq;
irq_set_exclusive_handler(low_priority_irq_num, low_priority_irq_handler);
irq_set_enabled(low_priority_irq_num, true);
irq_set_priority(low_priority_irq_num, priority);
return true;
}
static void low_prio_irq_deinit(void) {
if (low_priority_irq_num > 0) {
irq_set_enabled(low_priority_irq_num, false);
irq_remove_handler(low_priority_irq_num, low_priority_irq_handler);
user_irq_unclaim(low_priority_irq_num);
low_priority_irq_num = 0;
}
}
int cyw43_arch_init(void) {
cyw43_core_num = get_core_num();
recursive_mutex_init(&cyw43_mutex);
cyw43_init(&cyw43_state);
sem_init(&cyw43_irq_sem, 0, 1);
// Start regular lwip callback to handle timeouts
periodic_alarm = add_alarm_in_us(CYW43_SLEEP_CHECK_MS * 1000, periodic_alarm_handler, NULL, true);
if (periodic_alarm < 0) {
return PICO_ERROR_GENERIC;
}
gpio_add_raw_irq_handler_with_order_priority(IO_IRQ_BANK0, gpio_irq_handler, CYW43_GPIO_IRQ_HANDLER_PRIORITY);
gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, true);
irq_set_enabled(IO_IRQ_BANK0, true);
lwip_init();
// start low priority handler (no background work is done before this)
bool ok = low_prio_irq_init(PICO_LOWEST_IRQ_PRIORITY);
if (!ok) {
cyw43_arch_deinit();
return PICO_ERROR_GENERIC;
}
return PICO_OK;
}
void cyw43_arch_deinit(void) {
if (periodic_alarm >= 0) {
cancel_alarm(periodic_alarm);
periodic_alarm = -1;
}
gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, false);
gpio_remove_raw_irq_handler(IO_IRQ_BANK0, gpio_irq_handler);
low_prio_irq_deinit();
}
void cyw43_post_poll_hook(void) {
gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, true);
}
// This is called in the gpio and low_prio_irq interrupts and on either core
static void low_prio_irq_schedule_dispatch(size_t slot, low_prio_irq_dispatch_t f) {
assert(slot < count_of(low_priority_irq_dispatch_slots));
low_priority_irq_dispatch_slots[slot] = f;
if (cyw43_core_num == get_core_num()) {
//on same core, can dispatch directly
irq_set_pending(low_priority_irq_num);
} else {
// on wrong core, so force via GPIO IRQ which itself calls this method for the CYW43 slot.
// since the CYW43 slot always uses the same function, this is fine with the addition of an
// extra (but harmless) CYW43 slot call when another SLOT is invoked.
// We could do better, but would have to track why the IRQ was called.
io_irq_ctrl_hw_t *irq_ctrl_base = cyw43_core_num ?
&iobank0_hw->proc1_irq_ctrl : &iobank0_hw->proc0_irq_ctrl;
hw_set_bits(&irq_ctrl_base->intf[CYW43_PIN_WL_HOST_WAKE / 8], GPIO_IRQ_LEVEL_HIGH << (4 * (CYW43_PIN_WL_HOST_WAKE & 7)));
}
}
void cyw43_schedule_internal_poll_dispatch(void (*func)(void)) {
low_prio_irq_schedule_dispatch(CYW43_DISPATCH_SLOT_CYW43, func);
}
// Prevent background processing in pensv and access by the other core
// These methods are called in pensv context and on either core
// They can be called recursively
void cyw43_thread_enter(void) {
// Lock the other core and stop low_prio_irq running
recursive_mutex_enter_blocking(&cyw43_mutex);
}
#ifndef NDEBUG
void cyw43_thread_lock_check(void) {
// Lock the other core and stop low_prio_irq running
if (recursive_mutex_enter_count(&cyw43_mutex) < 1 || recursive_mutex_owner(&cyw43_mutex) != lock_get_caller_owner_id()) {
panic("cyw43_thread_lock_check failed");
}
}
#endif
// Re-enable background processing
void cyw43_thread_exit(void) {
// Run low_prio_irq if needed
if (1 == recursive_mutex_enter_count(&cyw43_mutex)) {
// note the outer release of the mutex is not via cyw43_exit in the low_priority_irq case (it is a direct mutex exit)
assert(!in_low_priority_irq);
// if (low_priority_irq_missed) {
// low_priority_irq_missed = false;
if (low_priority_irq_dispatch_slots[CYW43_DISPATCH_SLOT_CYW43]) {
low_prio_irq_schedule_dispatch(CYW43_DISPATCH_SLOT_CYW43, cyw43_poll);
}
// }
}
recursive_mutex_exit(&cyw43_mutex);
}
static void cyw43_delay_until(absolute_time_t until) {
// sleep can be called in IRQs, so there's not much we can do there
if (__get_current_exception()) {
busy_wait_until(until);
} else {
sleep_until(until);
}
}
void cyw43_delay_ms(uint32_t ms) {
cyw43_delay_until(make_timeout_time_ms(ms));
}
void cyw43_delay_us(uint32_t us) {
cyw43_delay_until(make_timeout_time_us(us));
}
void cyw43_arch_poll() {
// should not be necessary
// if (cyw43_poll) {
// low_prio_irq_schedule_dispatch(CYW43_DISPATCH_SLOT_CYW43, cyw43_poll);
// }
}
#ifdef ARDUINO_RASPBERRY_PI_PICO_W
void __attribute__((weak)) cyw43_cb_tcpip_init(cyw43_t *self, int itf);
void cyw43_cb_tcpip_init(cyw43_t *self, int itf) {
(void) self;
(void) itf;
}
void __attribute__((weak)) cyw43_cb_tcpip_deinit(cyw43_t *self, int itf);
void cyw43_cb_tcpip_deinit(cyw43_t *self, int itf) {
(void) self;
(void) itf;
}
void __attribute__((weak)) cyw43_cb_tcpip_set_link_up(cyw43_t *self, int itf);
void cyw43_cb_tcpip_set_link_up(cyw43_t *self, int itf) {
(void) self;
(void) itf;
}
void __attribute__((weak)) cyw43_cb_tcpip_set_link_down(cyw43_t *self, int itf);
void cyw43_cb_tcpip_set_link_down(cyw43_t *self, int itf) {
(void) self;
(void) itf;
}
void __attribute__((weak)) cyw43_cb_process_ethernet(void *cb_data, int itf, size_t len, const uint8_t *buf);
void cyw43_cb_process_ethernet(void *cb_data, int itf, size_t len, const uint8_t *buf) {
(void) cb_data;
(void) itf;
(void) len;
(void) buf;
}
#endif
#endif
+1 -5
View File
@@ -19,8 +19,7 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef STDLIB_NONISO_H
#define STDLIB_NONISO_H
#pragma once
#ifdef __cplusplus
extern "C" {
@@ -54,6 +53,3 @@ const char* strrstr(const char*__restrict p_pcString,
#ifdef __cplusplus
} // extern "C"
#endif
#endif
+5 -3
View File
@@ -27,7 +27,7 @@
#include <hardware/adc.h>
static uint32_t analogScale = 255;
static uint16_t analogFreq = 1000;
static uint32_t analogFreq = 1000;
static bool pwmInitted = false;
static bool adcInitted = false;
static uint16_t analogWritePseudoScale = 1;
@@ -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 > 60000) {
} else if (freq > 1'000'000) {
DEBUGCORE("ERROR: analogWriteFreq too high (%d)\n", freq);
analogFreq = 60000;
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
+6 -3
View File
@@ -23,7 +23,8 @@
static PinMode _pm[30];
extern "C" void pinMode(pin_size_t ulPin, PinMode ulMode) {
extern "C" void pinMode(pin_size_t ulPin, PinMode ulMode) __attribute__((weak, alias("__pinMode")));
extern "C" void __pinMode(pin_size_t ulPin, PinMode ulMode) {
switch (ulMode) {
case INPUT:
gpio_init(ulPin);
@@ -76,7 +77,8 @@ extern "C" void pinMode(pin_size_t ulPin, PinMode ulMode) {
_pm[ulPin] = ulMode;
}
extern "C" void digitalWrite(pin_size_t ulPin, PinStatus ulVal) {
extern "C" void digitalWrite(pin_size_t ulPin, PinStatus ulVal) __attribute__((weak, alias("__digitalWrite")));
extern "C" void __digitalWrite(pin_size_t ulPin, PinStatus ulVal) {
if (ulPin > 29) {
DEBUGCORE("ERROR: Illegal pin in pinMode (%d)\n", ulPin);
return;
@@ -99,7 +101,8 @@ extern "C" void digitalWrite(pin_size_t ulPin, PinStatus ulVal) {
}
}
extern "C" PinStatus digitalRead(pin_size_t ulPin) {
extern "C" PinStatus digitalRead(pin_size_t ulPin) __attribute__((weak, alias("__digitalRead")));
extern "C" PinStatus __digitalRead(pin_size_t ulPin) {
if (ulPin > 29) {
DEBUGCORE("ERROR: Illegal pin in digitalRead (%d)\n", ulPin);
return LOW;
+53 -15
View File
@@ -45,26 +45,40 @@ extern "C" void noInterrupts() {
// Only 1 GPIO IRQ callback for all pins, so we need to look at the pin it's for and
// dispatch to the real callback manually
auto_init_mutex(_irqMutex);
static std::map<pin_size_t, voidFuncPtr> _map;
class CBInfo {
public:
CBInfo(voidFuncPtr cb) : _cb(cb), _useParam(false), _param(nullptr) { };
CBInfo(voidFuncPtrParam cbParam, void *param) : _cbParam(cbParam), _useParam(true), _param(param) { };
void callback() {
if (_useParam && _cbParam) {
_cbParam(_param);
} else if (_cb) {
_cb();
}
}
private:
union {
voidFuncPtr _cb;
voidFuncPtrParam _cbParam;
};
bool _useParam;
void *_param;
};
static std::map<pin_size_t, CBInfo> _map;
void _gpioInterruptDispatcher(uint gpio, uint32_t events) {
(void) events;
// Only need to lock around the std::map check, not the whole IRQ callback
voidFuncPtr cb = nullptr;
{
CoreMutex m(&_irqMutex);
if (m) {
auto irq = _map.find(gpio);
if (irq != _map.end()) {
cb = irq->second;
}
CoreMutex m(&_irqMutex);
if (m) {
auto irq = _map.find(gpio);
if (irq != _map.end()) {
auto cb = irq->second;
cb.callback();
}
}
if (cb) {
cb(); // Do the callback
} else {
// ERROR, but we're in an IRQ so do nothing
}
}
extern "C" void attachInterrupt(pin_size_t pin, voidFuncPtr callback, PinStatus mode) {
@@ -84,7 +98,31 @@ extern "C" void attachInterrupt(pin_size_t pin, voidFuncPtr callback, PinStatus
}
noInterrupts();
detachInterrupt(pin);
_map.insert({pin, callback});
CBInfo cb(callback);
_map.insert({pin, cb});
gpio_set_irq_enabled_with_callback(pin, events, true, _gpioInterruptDispatcher);
interrupts();
}
void attachInterruptParam(pin_size_t pin, voidFuncPtrParam callback, PinStatus mode, void *param) {
CoreMutex m(&_irqMutex);
if (!m) {
return;
}
uint32_t events;
switch (mode) {
case LOW: events = 1; break;
case HIGH: events = 2; break;
case FALLING: events = 4; break;
case RISING: events = 8; break;
case CHANGE: events = 4 | 8; break;
default: return; // ERROR
}
noInterrupts();
detachInterrupt(pin);
CBInfo cb(callback, param);
_map.insert({pin, cb});
gpio_set_irq_enabled_with_callback(pin, events, true, _gpioInterruptDispatcher);
interrupts();
}
+17 -1
View File
@@ -13,6 +13,11 @@ int analogRead(pin_size_t pin = A0..A3)
Returns a value from 0...4095 correspionding to the ADC reading
of the specific pin.
void analogReadResolution(int bits)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Determines the resolution (in bits) of the value returned by the analogRead() function.
Default resolution is 10bit.
float analogReadTemp()
~~~~~~~~~~~~~~~~~~~~~~
Returns the temperature, in Celsius, of the onboard thermal sensor.
@@ -30,10 +35,21 @@ While up to 16 PWM channels can be generated, they are not independent
and there are significant restrictions as to allowed pins in parallel.
See the `RP2040 datasheet <https://datasheets.raspberrypi.org/rp2040/rp2040-datasheet.pdf>`_ for full details.
Analog Output Restrictions
--------------------------
The PWM generator source clock restricts the legal combinations of
frequency and ranges. For example, at 1MHz only about 6 bits of range
are possible. When you define an ``analogWriteFreq`` and ``analogWriteRange``
that can't be fulfilled by the hardware, the frequency will be preserved
but the accuracy (range) will be reduced automatically. Your code will
still send in the range you specify, but the core itself will transparently
map it into the allowable PWN range.
void analogWriteFreq(uint32_t freq)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the master PWM frequency used (i.e. how often the PWM output cycles).
From 100Hz to 60KHz are supported.
From 100Hz to 1MHz are supported.
void analogWriteRange(uint32_t range) and analogWriteResolution(int res)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+146
View File
@@ -0,0 +1,146 @@
:orphan:
WiFiClientSecure Class
======================
`BearSSL::WiFiClientSecure` is the object which actually handles TLS encrypted WiFi connections to a remote server or client. It extends `WiFiClient` and so can be used with minimal changes to code that does unsecured communications.
Validating X509 Certificates (Am I talking to the server I think I'm talking to?)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Prior to connecting to a server, the `BearSSL::WiFiClientSecure` needs to be told how to verify the identity of the other machine. **By default BearSSL will not validate any connections and will refuse to connect to any server.**
There are multiple modes to tell BearSSL how to verify the identity of the remote server. See the `BearSSL_Validation` example for real uses of the following methods:
setInsecure()
^^^^^^^^^^^^^
Don't verify any X509 certificates. There is no guarantee that the server connected to is the one you think it is in this case.
setKnownKey(const BearSSL::PublicKey \*pk)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Assume the server is using the specific public key. This does not verify the identity of the server or the X509 certificate it sends, it simply assumes that its public key is the one given. If the server updates its public key at a later point then connections will fail.
setFingerprint(const uint8_t fp[20]) / setFingerprint(const char \*fpStr)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Verify the SHA1 fingerprint of the certificate returned matches this one. If the server certificate changes, it will fail. If an array of 20 bytes are sent in, it is assumed they are the binary SHA1 values. If a `char*` string is passed in, it is parsed as a series of human-readable hex values separated by spaces or colons (e.g. `setFingerprint("00:01:02:03:...:1f");`)
This fingerprint is calculated on the raw X509 certificate served by the server. In very rare cases, these certificates have certain encodings which should be normalized before taking a fingerprint (but in order to preserve memory BearSSL does not do this normalization since it would need RAM for an entire copy of the cert), and the fingerprint BearSSL calculates will not match the fingerprint OpenSSL calculates. In this case, you can enable SSL debugging and get a dump of BearSSL's calculated fingerprint and use that one in your code, or use full certificate validation. See the `original issue and debug here <https://github.com/esp8266/Arduino/issues/6209>`__.
setTrustAnchors(BearSSL::X509List \*ta)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Use the passed-in certificate(s) as a trust anchor, accepting remote certificates signed by any of these. If you have many trust anchors it may make sense to use a `BearSSL::CertStore` because it will only require RAM for a single trust anchor (while the `setTrustAnchors` call requires memory for all certificates in the list).
setX509Time(time_t now)
^^^^^^^^^^^^^^^^^^^^^^^
For `setTrustAnchors` and `CertStore` , the current time (set via SNTP) is used to verify the certificate against the list, so SNTP must be enabled and functioning before the connection is attempted. If you cannot use SNTP for some reason, you can manually set the "present time" that BearSSL will use to validate a certificate with this call where `now` is standard UNIX time.
Client Certificates (Proving I'm who I say I am to the server)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TLS servers can request that a client identify themselves with an X509 certificate signed by a trust anchor it honors (i.e. a global TA or a private CA). This is commonly done for applications like MQTT. By default the client doesn't send a certificate, and in cases where a certificate is required the server will disconnect and no connection will be possible.
setClientRSACert / setClientECCert
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Sets a client certificate to send to a TLS server that requests one. It should be called before `connect()` to add a certificate to the client in case the server requests it. Note that certificates include both a certificate and a private key. Both should be provided to you by your certificate generator. Elliptic Curve (EC) keys require additional information, as shown in the prototype.
MFLN or Maximum Fragment Length Negotiation (Saving RAM)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Because TLS was developed on systems with many megabytes of memory, they require by default a 16KB buffer for receive and transmit. That's enormous for the ESP8266, which has only around 40KB total heap available.
We can (and do) minimize the transmission buffer down to slightly more than 512 bytes to save memory, since BearSSL can internally ensure transmissions larger than that are broken up into smaller chunks that do fit. But that still leaves the 16KB receive buffer requirement since we cannot in general guarantee the TLS peer will send in smaller chunks.
TLS 1.2 added MFLN, which lets a client negotiate smaller buffers with a server and reduce the memory requirements on the ESP8266. Unfortunately, BearSSL needs to know the buffer sizes before it begins connection, so applications that want to use smaller buffers need to check the remote server's support before `connect()` .
probeMaxFragmentLength(host, port, len)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Use one of these calls **before** connection to determine if a specific fragment length is supported (len must be a power of two from 512 to 4096, per the specification). This does **not** initiate a SSL connection, it simply opens a TCP port and performs a trial handshake to check support.
setBufferSizes(int recv, int xmit)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Once you have verified (or know beforehand) that MFLN is supported you can use this call to set the size of memory buffers allocated by the connection object. This must be called **before** `connect()` or it will be ignored.
In certain applications where the TLS server does not support MFLN (not many do as of this writing as it is relatively new to OpenSSL), but you control both the ESP8266 and the server to which it is communicating, you may still be able to `setBufferSizes()` smaller if you guarantee no chunk of data will overflow those buffers.
bool getMFLNStatus()
^^^^^^^^^^^^^^^^^^^^
After a successful connection, this method returns whether or not MFLN negotiation succeeded or not. If it did not succeed, and you reduced the receive buffer with `setBufferSizes` then you may experience reception errors if the server attempts to send messages larger than your receive buffer.
Sessions (Resuming connections fast)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
setSession(BearSSL::Session &sess)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If you are connecting to a server repeatedly in a fixed time period (usually 30 or 60 minutes, but normally configurable at the server), a TLS session can be used to cache crypto settings and speed up connections significantly.
Errors
~~~~~~
BearSSL can fail in many more unique and interesting ways. Use these calls to get more information when something fails.
getLastSSLError(char \*dest = NULL, size_t len = 0)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Returns the last BearSSL error code encountered and optionally set a user-allocated buffer to a human-readable form of the error. To only get the last error integer code, just call without any parameters (`int errCode = getLastSSLError();`).
Limiting Ciphers (New connections faster)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
There is very rarely reason to use these calls, but they are available.
setCiphers()
^^^^^^^^^^^^
Takes an array (in PROGMEM is valid) or a std::vector of 16-bit BearSSL cipher identifiers and restricts BearSSL to only use them. If the server requires a different cipher, then connection will fail. Generally this is not useful except in cases where you want to connect to servers using a specific cipher. See the BearSSL headers for more information on the supported ciphers.
setCiphersLessSecure()
^^^^^^^^^^^^^^^^^^^^^^
Helper function which essentially limits BearSSL to less secure ciphers than it would natively choose, but they may be helpful and faster if your server depended on specific crypto options.
Limiting TLS(SSL) Versions
~~~~~~~~~~~~~~~~~~~~~~~~~~
By default, BearSSL will connect with TLS 1.0, TLS 1.1, or TLS 1.2 protocols (depending on the request of the remote side). If you want to limit to a subset, use the following call:
setSSLVersion(uint32_t min, uint32_t max)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Valid values for min and max are `BR_TLS10`, `BR_TLS11`, `BR_TLS12`. Min and max may be set to the same value if only a single TLS version is desired.
ESP32 Compatibility
===================
Simple ESP32 ``WiFiClientSecure`` compatibility is built-in, allow for some sketches to run without any modification.
The following methods are implemented:
.. code :: cpp
void setCACert(const char *rootCA);
void setCertificate(const char *client_ca);
void setPrivateKey(const char *private_key);
bool loadCACert(Stream& stream, size_t size);
bool loadCertificate(Stream& stream, size_t size);
bool loadPrivateKey(Stream& stream, size_t size);
int connect(IPAddress ip, uint16_t port, int32_t timeout);
int connect(const char *host, uint16_t port, int32_t timeout);
int connect(IPAddress ip, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key);
int connect(const char *host, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key);
Note that the SSL backend is very different between Arduino-Pico and ESP32-Arduino (BearSSL vs. mbedTLS). This means
that, for instance, the SSL connection will check valid dates of certificates (and hence require system time to be
set on the Pico, which is automatically done in this case).
TLS-Pre Shared Keys (PSK) is not supported by BearSSL, and hence not implemented here. Neither is ALPN.
For more advanced control, it is recommended to port to the native Pico calls which allows much more flexibility and control.
+64
View File
@@ -0,0 +1,64 @@
:orphan:
WiFiServerSecure Class
----------------------
Implements a TLS encrypted server with optional client certificate validation. See `Server Class <server-class.rst>`__ for general information and `BearSSL Secure Client Class <bearssl-client-secure-class.rst>`__ for basic server and BearSSL concepts.
setBufferSizes(int recv, int xmit)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Similar to the `BearSSL::WiFiClientSecure` method, sets the receive and transmit buffer sizes. Note that servers cannot request a buffer size from the client, so if these are shrunk and the client tries to send a chunk larger than the receive buffer, it will always fail. Needs to be called before `begin()`
Setting Server Certificates
~~~~~~~~~~~~~~~~~~~~~~~~~~~
TLS servers require a certificate identifying itself and containing its public key, and a private key they will use to encrypt information with. The application author is responsible for generating this certificate and key, either using a self-signed generator or using a commercial certification authority. **Do not re-use the certificates included in the examples provided.**
This example command will generate a RSA 2048-bit key and certificate:
.. code:: bash
openssl req -x509 -nodes -newkey rsa:2048 -keyout key.pem -out cert.pem -days 4096
Again, it is up to the application author to generate this certificate and key and keep the private key safe and **private.**
setRSACert(const BearSSL::X509List \*chain, const BearSSL::PrivateKey \*sk)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Sets a RSA certificate and key to be used by the server when connections are received. Needs to be called before `begin()`
setECCert(const BearSSL::X509List \*chain, unsigned cert_issuer_key_type, const BearSSL::PrivateKey \*sk)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Sets an elliptic curve certificate and key for the server. Needs to be called before `begin()`.
Client sessions (Resuming connections fast)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The TLS handshake process takes a long time because of all the back and forth between the client and the server. You can shorten it by caching the clients' sessions which will skip a few steps in the TLS handshake. In order for this to work, your client also needs to cache the session. `BearSSL::WiFiClientSecure <bearssl-client-secure-class.rst#sessions-resuming-connections-fast>`__ can do that as well as modern web browsers.
Here are the kind of performance improvements that you'll be able to see for TLS handshakes with an ESP8266 with it's clock set at 160MHz on a network with fairly low latency:
* With an EC key of 256 bits, a request taking ~360ms without caching takes ~60ms with caching.
* With an RSA key of 2048 bits, a request taking ~1850ms without caching takes ~70ms with caching.
setCache(BearSSL::ServerSessions \*cache)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Sets the cache for the server's sessions. When choosing the size of the cache, remember that each client session takes 100 bytes. If you setup a cache for 10 sessions, it will take 1000 bytes. Needs to be called before `begin()`
When creating the cache, you can use any of the 2 available constructors:
* `BearSSL::ServerSessions(ServerSession *sessions, uint32_t size)`: Creates a cache with the given buffer and number of sessions.
* `BearSSL::ServerSessions(uint32_t size)`: Dynamically allocates a cache for the given number of sessions.
Requiring Client Certificates
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TLS servers can request the client to identify itself by transmitting a certificate during handshake. If the client cannot transmit the certificate, the connection will be dropped by the server.
setClientTrustAnchor(const BearSSL::X509List \*client_CA_ta)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Sets the trust anchor (normally a self-signing CA) that all received certificates will be verified against. Needs to be called before `begin()`.
+113
View File
@@ -0,0 +1,113 @@
:orphan:
BearSSL WiFi Classes
--------------------
Methods and properties described in this section are specific to the Raspberry Pi Pico W and the ESP8266. They are not covered in `Arduino WiFi library <https://www.arduino.cc/en/Reference/WiFi>`__ documentation. Before they are fully documented please refer to information below.
The `BearSSL <https://bearssl.org>`__ library (with modifications for ESP8266 compatibility and to use ROM tables whenever possible) is used to perform all cryptography and TLS operations. The main ported repo is available `on GitHub <https://github.com/earlephilhower/bearssl-esp8266>`__.
CPU Requirements
~~~~~~~~~~~~~~~~
SSL operations take significant CPU cycles to run, so it will connect significantly slower than unprotected connections on the Pico, but the actual data transfer rates once connected are similar.
See the section on `sessions <#sessions-resuming-connections-fast>`__ and `limiting cryptographic negotiation <#limiting-ciphers-new-connections-faster>`__ for ways of ensuring faster modes are used.
Memory Requirements
~~~~~~~~~~~~~~~~~~~
BearSSL doesn't perform memory allocations at runtime, but it does require allocation of memory at the beginning of a connection. There are two memory chunks required:
. A per-application secondary stack
. A per-connection TLS receive/transmit buffer plus overhead
The per-application secondary stack is approximately 7KB in size and is used for temporary variables during BearSSL processing. Only one stack is required, and it will be allocated whenever any `BearSSL::WiFiClientSecure` or `BearSSL::WiFiServerSecure` are instantiated. So, in the case of a global client or server, the memory will be allocated before `setup()` is called.
The per-connection buffers are approximately 22KB in size, but in certain circumstances it can be reduced dramatically by using MFLN or limiting message sizes. See the `MLFN section <#mfln-or-maximum-fragment-length-negotiation-saving-ram>`__ below for more information.
Object Lifetimes
~~~~~~~~~~~~~~~~
There are many configuration options that require passing in a pointer to an object (i.e. a pointer to a private key, or a certificate list). In order to preserve memory, BearSSL does NOT copy the objects passed in via these pointers and as such any pointer passed in to BearSSL needs to be preserved for the life of the client object. For example, the following code is **in error**:
.. code:: cpp
BearSSL::WiFiClientSecure client;
const char x509CA PROGMEM = ".......";
void setup() {
BearSSL::X509List x509(x509CA);
client.setTrustAnchor(&x509);
}
void loop() {
client.connect("192.168.1.1", 443);
}
Because the pointer to the local object `x509` no longer is valid after setup(), expect to crash in the main `loop()` where it is accessed by the `client` object.
As a rule, either keep your objects global, use `new` to create them, or ensure that all objects needed live inside the same scope as the client.
TLS and HTTPS Basics
~~~~~~~~~~~~~~~~~~~~
The following discussion is only intended to give a rough idea of TLS/HTTPS(which is just HTTP over a TLS connection) and the components an application needs to manage to make a TLS connection. For more detailed information, please check the relevant `RFC 5246 <https://tools.ietf.org/search/rfc5246>`__ and others.
TLS can be broken into two stages: verifying the identities of server (and potentially client), and then encrypting blocks of data bidirectionally. Verifying the identity of the other partner is handled via keys encoded in X509 certificates, optionally signed by a series of other entities.
Public and Private Keys
~~~~~~~~~~~~~~~~~~~~~~~
Cryptographic keys are required for many of the BearSSL functions. Both public and private keys are supported, with either Elliptic Curve or RSA key support.
To generate a public or private key from an existing PEM (ASCII format) or DER (binary format), the simplest method is to use the constructor:
.. code:: cpp
BearSSL::PublicKey(const char *pemString)
... or ...
BearSSL::PublicKey(const uint8_t *derArray, size_t derLen)
Note that `PROGMEM` strings and arrays are natively supported by these constructors and no special `*_P` modes are required. There are additional functions to identify the key type and access the underlying BearSSL proprietary types, but they are not needed by user applications.
TLS Sessions
~~~~~~~~~~~~
TLS supports the notion of a session (completely independent and different from HTTP sessions) which allow clients to reconnect to a server without having to renegotiate encryption settings or validate X509 certificates. This can save significant time (3-4 seconds in the case of EC keys) and can help save power by allowing the ESP8266 to sleep for a long time, reconnect and transmit some samples using the SSL session, and then jump back to sleep quicker.
`BearSSL::Session` is an opaque class. Use the `BearSSL::WiFiClientSecure.setSession(&BearSSLSession)` method to apply it before the first `BearSSL::WiFiClientSecure.connect()` and it will be updated with session parameters during the operation of the connection. After the connection has had `.close()` called on it, serialize the `BearSSL::Session` object to stable storage (EEPROM, RTC RAM, etc.) and restore it before trying to reconnect. See the `BearSSL_Sessions` example for a detailed example.
`Sessions <#sessions-resuming-connections-fast>`__ contains additional information on the sessions API.
X.509 Certificate(s)
~~~~~~~~~~~~~~~~~~~~
X509 certificates are used to identify peers in TLS connections. Normally only the server identifies itself, but the client can also supply an X509 certificate if desired (this is often done in MQTT applications). The certificate contains many fields, but the most interesting in our applications are the name, the public key, and potentially a chain of signing that leads back to a trusted authority (like a global internet CA or a company-wide private certificate authority).
Any call that takes an X509 certificate can also take a list of X509 certificates, so there is no special `X509` class, simply `BearSSL::X509List` (which may only contain a single certificate).
Generating a certificate to be used to validate using the constructor
.. code:: cpp
BearSSL::X509List(const char *pemX509);
...or...
BearSSL::X509List(const uint8_t *derCert, size_t derLen);
If you need to add additional certificates (unlikely in normal operation), the `::append()` operation can be used.
Certificate Stores
~~~~~~~~~~~~~~~~~~
The web browser you're using to read this document keeps a list of 100s of certification authorities (CAs) worldwide that it trusts to attest to the identity of websites.
In many cases your application will know the specific CA it needs to validate web or MQTT servers against (often just a single, self-signing CA private to your institution). Simply load your private CA in a `BearSSL::X509List` and use that as your trust anchor.
However, there are cases where you will not know beforehand which CA you will need (i.e. a user enters a website through a keypad), and you need to keep the list of CAs just like your web browser. In those cases, you need to generate a certificate bundle on the PC while compiling your application, upload the `certs.ar` bundle to LittleFS or SD when uploading your application binary, and pass it to a `BearSSL::CertStore()` in order to validate TLS peers.
See the `BearSSL_CertStore` example for full details.
Supported Crypto
~~~~~~~~~~~~~~~~
Please see the `BearSSL website <https://bearssl.org>`__ for detailed cryptographic information. In general, TLS 1.2, TLS 1.1, and TLS 1.0 are supported with RSA and Elliptic Curve keys and a very rich set of hashing and symmetric encryption codes. Please note that Elliptic Curve (EC) key operations take a significant amount of time.
+6 -6
View File
@@ -19,7 +19,7 @@
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
import sphinx_rtd_theme
# -- General configuration ------------------------------------------------
@@ -30,7 +30,7 @@
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = []
extensions = ['sphinx_rtd_theme']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
@@ -46,7 +46,7 @@ master_doc = 'index'
# General information about the project.
project = u'Arduino-Pico'
copyright = u'2021, Earle F. Philhower, III'
copyright = u'2022, Earle F. Philhower, III'
author = u'Earle F. Philhower, III'
# The version info for the project you're documenting, acts as replacement for
@@ -54,9 +54,9 @@ author = u'Earle F. Philhower, III'
# built documents.
#
# The short X.Y version.
version = u'1.0.0'
version = u'2.5.3'
# The full version, including alpha/beta/rc tags.
release = u'1.0.0'
release = u'2.5.3'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@@ -82,7 +82,7 @@ todo_include_todos = False
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'alabaster'
html_theme = 'sphinx_rtd_theme'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
+8
View File
@@ -6,6 +6,14 @@ Board-Specific Pins
The Raspberry Pi Pico RP2040 chip supports up to 30 digital I/O pins,
however not all boards provide access to all pins.
Input Modes
-----------
The Raspberry Pi Pico has 3 Input modes settings for use with `pinMode`: `INPUT`, `INPUT_PULLUP` and `INPUT_PULLDOWN`
Output Modes (Pad Strength)
---------------------------
The Raspberry Pi Pico has the ability to set the current that a pin (actually the pad associated with it) is capable of supplying. The current can be set to values of 2mA, 4mA, 8mA and 12mA. By default, on a reset, the setting is 4mA. A `pinMode(x, OUTPUT)`, where `x` is the pin number, is also the default setting. 4 settings have been added for use with `pinMode`: `OUTPUT_2MA`, `OUTPUT_4MA`, which has the same behavior as `OUTPUT`, `OUTPUT_8MA` and `OUTPUT_12MA`.
Tone/noTone
-----------
Simple square wave tone generation is possible for up to 8 channels using
+1 -1
View File
@@ -55,4 +55,4 @@ Returns the length of the EEPROM (i.e. the value specified in
EEPROM Examples
---------------
Three EEPROM `examples<https://github.com/earlephilhower/arduino-pico/tree/master/libraries/EEPROM>`_ are included.
Three EEPROM `examples <https://github.com/earlephilhower/arduino-pico/tree/master/libraries/EEPROM>`_ are included.
+49
View File
@@ -0,0 +1,49 @@
FreeRTOS SMP
============
The SMP (multicore) port of FreeRTOS is included with the core. This allows complex
task operations and real preemptive multithreading in your sketches. While the
``setup1`` and ``loop1`` way of multitasking is simplest for most folks, FreeRTOS
is much more powerful.
Enabling FreeRTOS
-----------------
To enable FreeRTOS, simply add
.. code:: c++
#include <FreeRTOS.h>
to your sketch and it will be included and enabled automatically.
Configuration and Predefined Tasks
----------------------------------
FreeRTOS is configured with 8 priority levels (0 through 7) and a process for
``setup()/loop()``, ``setup1()/loop1()``, and the USB port will be created. The task
quantum is 1 millisecond (i.e. 1,000 switches per second).
``setup()`` and ``loop()`` are assigned to only run on core 0, while ``setup1()`` and ``loop1()``
only run in core 1 in this mode, the same as the default multithreading mode.
You can launch and manage additional processes using the standard FreeRTOS routines.
``delay()`` and ``yield()`` free the CPU for other tasks, while ``delayMicroseconds()`` does not.
Caveats
-------
While the core now supports FreeRTOS, most (probably all) Arduino libraries were not written
to support preemptive multithreading. This means that all calls to a particular library should
be made from a single task.
In particular, the ``LittleFS`` and ``SDFS`` libraries can not be called from different
threads. Do all ``File`` operations from a single thread or else undefined behavior
(aka strange crashes or data corruption) can occur.
More Information
----------------
For full FreeRTOS documentation look at `FreeRTOS.org <https://freertos.org/index.html>`__
and `FreeRTOS SMP support <https://freertos.org/symmetric-multiprocessing-introduction.html>`__.
+11 -1
View File
@@ -98,9 +98,19 @@ The included ``SD`` library is the Arduino standard one. Please refer to
the [Arduino SD reference](https://www.arduino.cc/en/reference/SD) for
more information.
Using Second SPI port for SD
----------------------------
The ``SD`` library ``begin()`` has been modified to allow you to use the
second SPI port, ``SPI1``. Just use the following call in place of
``SD.begin(cspin)``
.. code:: cpp
SD.begin(cspin, SPI1);
File system object (LittleFS/SD/SDFS)
--------------------------------------------
-------------------------------------
setConfig
~~~~~~~~~
+40
View File
@@ -0,0 +1,40 @@
HTTPClient Library
==================
A simple HTTP requestor that can handle both HTTP and HTTP requests is
included as the ``HTTPClient`` library.
Check the examples for use under HTTP and HTTPS configurations. In general,
for HTTP connections (unsecured and very uncommon on the internet today) simply
passing in a URL and performiung a GET is sufficient to transfer data.
.. code:: cpp
// Error checking is left as an exercise for the reader...
HTTPClient http;
if (http.begin("http://my.server/url")) {
if (http.GET() > 0) {
String data = http.getString();
}
http.end();
}
For HTTPS connections, simply add the appropriate WiFiClientSecure calls
as needed (i.e. ``setInsecure()``, ``setTrustAnchor``, etc.). See the
WiFiClientSecure documentation for more details.
.. code:: cpp
// Error checking is left as an exercise for the reader...
HTTPClient https;
https.setInsecure(); // Use certs, but do not check their authenticity
if (https.begin("https://my.secure.server/url")) {
if (http.GET() > 0) {
String data = http.getString();
}
http.end();
}
Unlike the ESP8266 and ESP32 ``HTTPClient`` implementations it is not necessary
to create a ``WiFiClient`` or ``WiFiClientSecure`` to pass in to the ``HTTPClient``
object.
+144 -52
View File
@@ -1,89 +1,181 @@
I2S (Digital Audio) Output Library
==================================
I2S (Digital Audio) Audio Library
=================================
While the RP2040 chip on the Raspberry Pi Pico does not include a hardware
I2S device, it is possible to use the PIO (Programmable I/O) state machines
to implement one dynamically.
This I2S library uses the ``pico-extras`` I2S audio library and wraps it in
an Arduino I2S library. It supports 16 bits/sample and frequencies of up
to 48kHZ, with configurable BCLK, LRCLK(always pin "BCLK + 1"), and DOUT pins.
Digital audio input and output are supported at 8, 16, 24, and 32 bits per
sample.
Theoretically up to 6 I2S ports may be created, but in practice there
may not be enough resources (DMA, PIO SM) to actually create and use so
many.
Create an I2S port by instantiating a variable of the I2S class
specifying the direction. Configure it using API calls below before
using it.
**Note:** This I2S device takes over the entire PIO1 (second) unit and adjusts
its clock frequency to meet the I2S needs. That means when only 4 Tones
or only 4 Servos may be used when the I2S device is used.
I2S Class API
-------------
I2S(OUTPUT)
~~~~~~~~~~~
Creates an I2S output port. Needs to be connected up to the
desired pins (see below) and started before any output can happen.
I2S(INPUT)
~~~~~~~~~~
Creates an I2S input port. Needs to be connected up to the
desired pins (see below) and started before any input can happen.
bool setBCLK(pin_size_t pin)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the BCLK pin of the I2S device. The LRCLK/word clock will be ``pin + 1``
due to limitations of the PIO state machines. Call this before ``I2S.begin()``
Default BCLK = 26, LRCLK = 27
due to limitations of the PIO state machines. Call this before ``I2S::begin()``
bool setDOUT(pin_size_t pin)
bool setDATA(pin_size_t pin)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the DOUT pin of the I2S device. Any pin may be used. Default DOUT = 28
Call before ``I2S.begin()``
Sets the DOUT or DIN pin of the I2S device. Any pin may be used.
Call before ``I2S::begin()``
bool begin(long sampleRate)
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Start the I2S device up with the given sample rate. The pins selected above
will be turned to output and the I2S will begin to drive silence frames (all
zero) out.
bool setBitsPerSample(int bits)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Specify how many bits per audio sample to read or write. Note that
for 24-bit samples, audio samples must be left-aligned (i.e. bits 31...8).
Call before ``I2S::begin()``
bool setBuffers(size_t buffers, size_t bufferWords, int32_t silenceSample = 0)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Set the number of DMA buffers and their size in 32-bit words as well as
the word to fill when no data is available to send to the I2S hardware.
Call before ``I2S::begin()``.
bool setFrequency(long sampleRate)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the word clock frequency, but does not start the I2S device if not
already running. May be called after ``I2S::begin()`` to change the
sample rate on-the-fly.
bool begin()/begin(long sampleRate)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Start the I2S device up with the given sample rate, or with the value set
using the prior ``setFrequency`` call.
void end()
~~~~~~~~~~
Stops the I2S device. **Note, at present the memory allocated for I2S buffers
is not freed leading to a memory leak when ``end()`` is called. This is due
to the state of the ``pico-extras`` release which this code uses.**
Stops the I2S device.
void flush()
~~~~~~~~~~~~
Sends any partial frames in memory to the I2S output device. They may NOT play
immediately. Potential use case for this call would be when the frequency of
the output will be changing.
Waits until all the I2S buffers have been output.
size_t write(uint8_t)
~~~~~~~~~~~~~~~~~~~~~
Provided for compatibility, but not very useful. Writes a sample from 0...255
to the I2S buffer. See ``write(int16_t)`` for a better one
size_t write(uint8_t/int8_t/int16_t/int32_t)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Writes a single sample of ``bitsPerSample`` to the buffer. It is up to the
user to keep track of left/right channels. Note this writes data equivalent
to one channel's data, not the size of the passed in variable (i.e. if you have
a 16-bit sample size and ``write((int8_t)-5); write((int8_t)5);`` you will have
written **2 samples** to the I2S buffer of whatever the I2S size, not a single
16-bit sample.
This call will block (wait) until space is available to actually write
the data.
size_t write(int32_t val, bool sync)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Writes 32 bits of data to the I2S buffer (regardless of the configured I2S
bit size). When ``sync`` is true, it will not return until the data has
been writte. When ``sync`` is false, it will return ``0`` immediately if
there is no space present in the I2S buffer.
size_t write(const uint8_t \*buffer, size_t size)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Transfers number of bytes from an application buffer to the I2S output buffer.
Be aware that ``size`` is in *bytes** and not samples. Size must be a multiple
of **4 bytes** (i.e. one left/right sample). Will not block, so check
the return value to find out how many bytes were actually written.
of **4 bytes**. Will not block, so check the return value to find out how
many bytes were actually written.
int availableForWrite()
~~~~~~~~~~~~~~~~~~~~~~~
Returns the number of **32-bit L/R samples** that can be written without
Returns the number of L/R samples that can be written without
potentially blocking.
bool setFrequency(int newFreq)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Adjusts the I2S output frequency. When changing frequency while I2S output
is underway, be sure to use ``I2S.flush()`` before changing the frequency to
ensure the older data is played at the right frequency.
int read()
~~~~~~~~~~
Reads a single sample of I2S data, whatever the I2S sample size is configured.
Will not return until data is available.
size_t write(int16_t)
~~~~~~~~~~~~~~~~~~~~~
Writes a single 16-bit left or right sample to the I2S output buffer. The
user is required to ensure that an even number of samples is written (i.e.
left and right) over the application lifetime. The application also needs
to track which sample is next to be written (right/left). For this reason,
the ``write(void *b, size_t lrsamples)`` call may be easier and faster to use.
int peek()
~~~~~~~~~~
Returns the next sample to be read from the I2S buffer (without actually
removing it).
size_t write(const void \*buffer, size_t lrsamples)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Writes up to size left+right packed samples to the I2S device. Non-blocking,
will writefrom 0...size samples and return that count. Be sure your app
handles partial writes (i.e. by ``yield()`` ing and then retrying to write the
remaining data.)
void onTransmit(void (\*fn)(void))
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets a callback to be called when an I2S DMA buffer is fully transmitted.
Will be in an interrupt context so the specified function must operate
quickly and not use blocking calls like delay() or write to the I2S.
The ``onTransmit`` callback is not supported.
void onReceive(void (\*fn)(void))
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets a callback to be called when an I2S DMA buffer is fully read in.
Will be in an interrupt context so the specified function must operate
quickly and not use blocking calls like delay() or read from the I2S.
See the `ESP8266Audio <https://github.com/earlephilhower/ESP8266Audio>`_ library
for a working example, or look at the included sample tone generator.
Sample Writing/Reading API
--------------------------
Because I2S streams consist of a natural left and right sample, it is often
convenient to write or read both with a single call. The following calls
allow applications to read or write both samples at the same time, and
explicitly indicate the bit widths required (to avoid potential issues with
type conversion on calls).
size_t write8(int8_t l, int8_t r)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Writes a left and right 8-bit sample to the I2S buffers. Blocks until space
is available.
size_t write16(int16_t l, int16_t r)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Writes a left and right 16-bit sample to the I2S buffers. Blocks until space
is available.
size_t write24(int32_t l, int32_t r)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Writes a left and right 24-bit sample to the I2S buffers. See note below
about 24-bit mode. Blocks until space is available.
size_t write32(int32_t l, int32_t r)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Writes a left and right 32-bit sample to the I2S buffers. Blocks until space
is available.
bool read8(int8_t \*l, int8_t \*r)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Reads a left and right 8-bit sample and returns ``true`` on success. Will block
until data is available.
bool read16(int16_t \*l, int16_t \*r)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Reads a left and right 16-bit sample and returns ``true`` on success. Will block
until data is available.
bool read24(int32_t \*l, int32_t \*r)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Reads a left and right 24-bit sample and returns ``true`` on success. See note below
about 24-bit mode. Will block until data is available.
bool read32(int32_t \*l, int32_t \*r)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Reads a left and right 32-bit sample and returns ``true`` on success. Will block
until data is available.
Note About 24-bit Samples
-------------------------
24-bit samples are stored as left-aligned 32-bit values with bits 7..0
ignored. Only the upper 24 bits 31...8 will be transmitted or
received. The actual I2S protocol will only transmit or receive 24 bits
in this mode, even though the data is 32-bit packed.
+37
View File
@@ -34,3 +34,40 @@ Debug messages from `printf` and the Core can be printed to a Serial port
to allow for easier debugging. Select the desired port and verbosity.
Selecting a port for debug output does not stop a sketch from using it
for normal operations.
Generic RP2040 Support
----------------------
If your RP2040 board isn't in the menus you can still use it with the
IDE by using the `Board->Generic RP2040` menu option. You will need to
then set the flash size (see above) and tell the IDE how to communicate
with the flash chip using the `Tools->Boot Stage 2` menu.
Boot Stage 2 Options for Generic RP2040
---------------------------------------
The Arduino Pico needs to set up its internal flash interface to talk to
whatever flash chip is in the system. While all flash chips support a
basic (and slow) 1-bit operation using common timings, each different
brand (and sometimes model) of flash chip require custom timings to work
in QSPI (4-bit) mode. The `Boot Stage 2` menu lets you select from
the supported timings.
The options with `/2` in them divide the system clock by 2 to drive the
bus. Options with `/4` divide the clock by 4 and so are slower but more
compatible.
If you can't match a chip name in the menu to your flash chip, a simple
test can be run to determine which is correct. Simpily load the `Blink`
example, select the first option in the `Boot Stage 2` menu, and upload.
If that works, note it and continue. Iterate through the options and
note which ones work. If an option doesn't work, unplug the chip and
hold the BOOTSEL button down while re-inserting it to enter the ROM
uploader mode. (The CPU and flash will not be harmed if the test fails.)
If one of the custom bootloaders (not `Generic SPI /2 or /4`) worked, use
that option to get best performance. If none worked other than the
`Generic SPI /2 or /4` then use that. The `/2` options of all models
is preferred as it is faster, but some boards do require `/4` on the
custom chip interfaces.
When in doubt, `Generic SPI /4` should work with any flash chip but is
slow.
Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

+18 -1
View File
@@ -7,7 +7,7 @@ Arduino-Pico. Arduino-Pico is a community port of the RP2040
to make it easier and more fun to use and program the Raspberry Pi
Pico / RP2040 based boards.
This Arduino core uses a custom toolset with GCC 10.2 and Newlib 4.0.0
This Arduino core uses a custom toolset with GCC 10.3 and Newlib 4.0.0
and doesn't require any system-installed prerequisites.
For the latest version, always check https://github.com/earlephilhower/arduino-pico
@@ -24,6 +24,8 @@ For the latest version, always check https://github.com/earlephilhower/arduino-p
Pin (Re)Assignment <pins>
RP2040 Helper <rp2040>
Analog I/O <analog>
Digital I/O <digital>
EEPROM <eeprom>
@@ -37,6 +39,21 @@ For the latest version, always check https://github.com/earlephilhower/arduino-p
USB (Arduino and Adafruit_TinyUSB) <usb>
Multicore Processing <multicore>
FreeRTOS SMP (multicore) <freertos>
WiFi (Pico-W Support) <wifi>
WiFiClient <wificlient>
WiFiServer <wifiserver>
WiFiUDP <wifiudp>
NTP client <wifintp>
BearSSL Encrypted TLS <bearssl>
WiFiClientSecure (TLS/SSL/HTTPS) <bearssl-client-secure-class>
WiFiServerSecure (TLS/SSL/HTTPS) <bearssl-server-secure-class>
HTTP/HTTPS Client <httpclient>
Over-the-Air (OTA) Updates <ota>
Ported/Optimized Libraries <libraries>
Using Pico-SDK <sdk>
+22 -4
View File
@@ -5,7 +5,7 @@ The Arduino-Pico core can be installed using the Arduino IDE Boards Manager
or using `git`. If you want to simply write programs for your RP2040 board,
the Boards Manager installation will suffice, but if you want to try the
latest pre-release versions and submit improvements, you will need the `git`
instllation.
installation.
Installing via Arduino Boards Manager
-------------------------------------
@@ -40,8 +40,6 @@ To install via GIT (for latest and greatest versions):
git submodule update --init
cd pico-sdk
git submodule update --init
cd pico-extras
git submodule update --init
cd ../tools
python3 ./get.py
@@ -67,6 +65,26 @@ Them hit the upload button and your sketch should upload and run.
In some cases the Pico will encounter a hard hang and its USB port will not respond to the auto-reset request. Should this happen, just
follow the initial procedure of holding the BOOTSEL button down while plugging in the Pico to enter the ROM bootloader.
Unable to Upload First Sketch
-----------------------------
If the Arduino IDE has never seen a serial port from a working device (Pico, AVR, or any other serial port), you
may not be able to install using the prior directions because the ``Tools->Port`` menu will be grayed out and
empty. In this case, a special workaround identified by @fjansson in `this issue report <https://github.com/earlephilhower/arduino-pico/issues/688>`_ .
To allow subsequent uploads to automatically work, you will need to manually install a UF2 binary onto the Raspberry Pi Pico one time to
allow it to present a Serial port for the Arduino IDE to detect and save.
Perform the following steps to program a dummy sketch:
1. Open a new, empty sketch (doesn't work with a read-only example sketch).
2. Compile it by pressing the "Verify" checkmark button.
3. Select the ``Sketch -> Export Compiled Binary`` menu. Select a location e.g. the desktop. A folder is created there, containing a file ending in .uf2
4. Copy this file to the Pico's drive, by drag and drop in the Explorer.
The Pico restarts and now now has a serial port. Now the Port menu in Arduino is not gray anymore, select the port there.
After this, normal uploading from the Arduino editor should work.
Windows 7 Driver Notes
----------------------
@@ -87,7 +105,7 @@ When running MalwareBytes antivirus (or others) the scanner may lock the compile
Symptoms include:
*Access denied during update in the boards manager - affects the .exe files, because MalwareBytes has locked them.
* Access denied during update in the boards manager - affects the .exe files, because MalwareBytes has locked them.
* Access denied during compilation, to one of the .exe files - same reason.
* Can't delete the .exe files - they're locked by MalwareBytes.
+2 -2
View File
@@ -71,8 +71,8 @@ uint32_t rp2040.fifo.pop()
Reads a value from this core's FIFO. Blocks until one is available.
bool rp2040.fifo.pop_nb(uint32_t *dest)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool rp2040.fifo.pop_nb(uint32_t \*dest)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Reads a value from this core's FIFO and places it in dest. Will return
``true`` if successful, or ``false`` if the pop would block.
+359
View File
@@ -0,0 +1,359 @@
OTA Updates
===========
Introduction
------------
OTA (Over the Air) update is the process of uploading firmware to a Pico using a Wi-Fi, Ethernet, or other connection rather than a serial port. This is especially useful for WiFi enabled Picos, like the Pico W, because it lets systems be updated remotely, without needing physical access.
OTA may be done using:
- `Arduino IDE <#arduino-ide>`__
- `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.
In any case, the first firmware upload has to be done over a serial port. If the OTA routines are correctly implemented in the sketch, then all subsequent uploads may be done over the air.
By default, there is no imposed security for the OTA process. It is up to the developer to ensure that updates are allowed only from legitimate / trusted sources. Once the update is complete, the module restarts, and the new code is executed. The developer should ensure that the application running on the module is shut down and restarted in a safe manner. Chapters below provide additional information regarding security and safety of OTA updates.
OTA Requirements
~~~~~~~~~~~~~~~~
OTA requires a LittleFS partition to store firmware upgrade files. Make sure that you configure the sketch with a filesystem large enough to handle whatever size firmware binary you expect. Updates may be compressed, minimizing the total space needed.
Power Fail Safety
~~~~~~~~~~~~~~~~~
The update commands are all stored in flash, so a power cycle during update (except if the OTA bootloader is being changed) should not brick the device because when power is restored the OTA bootloader will begin the process from scratch once again.
Security Disclaimer
~~~~~~~~~~~~~~~~~~~
No guarantees as to the level of security provided for your application by the following methods is implied. Please refer to the GNU LGPL license associated for this project for full disclaimers. If you do find security weaknesses, please don't hesitate to contact the maintainers or supply pull requests with fixes. The MD5 verification and password protection schemes are already known to supply a very weak level of security.
Basic Security
~~~~~~~~~~~~~~
The module has to be exposed wirelessly to get it updated with a new sketch. That poses a risk of the module being violently hacked and programmed with some other code. To reduce the likelihood of being hacked, consider protecting your uploads with a password, selecting certain OTA port, etc.
Check functionality provided with the `ArduinoOTA <https://github.com/earlephilhower/arduino-pico/tree/master/libraries/ArduinoOTA>`__ library that may improve security:
.. code:: cpp
void setPort(uint16_t port);
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 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 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 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.
**Securing your private key is paramount. The same private/public key pair that was used with the original upload must also be used to sign later binaries. Loss of the private key associated with a binary means that you will not be able to OTA-update any of your devices in the field. Alternatively, if someone else copies the private key, then they will be able to use it to sign binaries which will be accepted by the Pico.**
Signed Binary Format
^^^^^^^^^^^^^^^^^^^^
The format of a signed binary is compatible with the standard binary format, and can be uploaded to a non-signed Pico via serial or OTA without any conditions. Note, however, that once an unsigned OTA app is overwritten by this signed version, further updates will require signing.
As shown below, the signed hash is appended to the unsigned binary, followed by the total length of the signed hash (i.e., if the signed hash was 64 bytes, then this uint32 data segment will contain 64). This format allows for extensibility (such as adding a CA-based validation scheme allowing multiple signing keys all based on a trust anchor). Pull requests are always welcome. (currently it uses SHA256 with RSASSA-PKCS1-V1_5-SIGN signature scheme from RSA PKCS #1 v1.5)
.. code:: bash
NORMAL-BINARY <SIGNATURE> <uint32 LENGTH-OF-SIGNATURE>
Signed Binary Prerequisites
^^^^^^^^^^^^^^^^^^^^^^^^^^^
OpenSSL is required to run the standard signing steps, and should be available on any UNIX-like or Windows system. As usual, the latest stable version of OpenSSL is recommended.
Signing requires the generation of an RSA-2048 key (other bit lengths are supported as well, but 2048 is a good selection today) using any appropriate tool. The following shell commands will generate a new public/private key pair. Run them in the sketch directory:
.. code:: bash
openssl genrsa -out private.key 2048
openssl rsa -in private.key -outform PEM -pubout -out public.key
Automatic Signing
^^^^^^^^^^^^^^^^^
The simplest way of implementing signing is to use the automatic mode, which presently is only possible on Linux and Mac due to some of the tools not being available for Windows. This mode uses the IDE to configure the source code to enable sigining verification with a given public key, and signs binaries as part of the standard build process using a given public key.
To enable this mode, just include `private.key` and `public.key` in the sketch `.ino` directory. The IDE will call a helper script (`tools/signing.py`) before the build begins to create a header to enable key validation using the given public key, and to actually do the signing after the build process, generating a `sketch.bin.signed` file. When OTA is enabled (ArduinoOTA, Web, or HTTP), the binary will automatically only accept signed updates.
When the signing process starts, the message:
.. code:: bash
Enabling binary signing
will appear in the IDE window before a compile is launched. At the completion of the build, the signed binary file well be displayed in the IDE build window as:
.. code:: bash
Signed binary: /full/path/to/sketch.bin.signed
If you receive either of the following messages in the IDE window, the signing was not completed and you will need to verify the `public.key` and `private.key`:
.. code:: bash
Not enabling binary signing
... or ...
Not signing the generated binary
Manual Signing of Binaries
^^^^^^^^^^^^^^^^^^^^^^^^^^
Users may also manually sign executables and require the OTA process to verify their signature. In the main code, before enabling any update methods, add the following declarations and function call:
.. code:: cpp
<in globals>
BearSSL::PublicKey signPubKey( ... key contents ... );
BearSSL::HashSHA256 hash;
BearSSL::SigningVerifier sign( &signPubKey );
...
<in setup()>
Update.installSignature( &hash, &sign );
The above snippet creates a BearSSL public key and a SHA256 hash verifier, and tells the Update object to use them to validate any updates it receives from any method.
Compile the sketch normally and, once a `.bin` file is available, sign it using the signer script:
.. code:: bash
<PicoArduinoPath>/tools/signing.py --mode sign --privatekey <path-to-private.key> --bin <path-to-unsigned-bin> --out <path-to-signed-binary>
Compression
-----------
The eboot bootloader incorporates a GZIP decompressor, built for very low code requirements. For applications, this optional decompression is completely transparent. For uploading compressed filesystems, the application must be built with `ATOMIC_FS_UPDATE` defined because, otherwise, eboot will not be involved in writing the filesystem.
No changes to the application are required. The `Updater` class and `eboot` bootloader (which performs actual application overwriting on update) automatically search for the `gzip` header in the uploaded binary, and if found, handle it.
Compress an application `.bin` file or filesystem package using any `gzip` available, at any desired compression level (`gzip -9` is recommended because it provides the maximum compression and uncompresses as fast as any other compressino level). For example:
.. code:: bash
gzip -9 sketch.bin # Maximum compression, output sketch.bin.gz
<Upload the resultant sketch.bin.gz>
If signing is desired, sign the gzip compressed file *after* compression.
.. code:: bash
gzip -9 sketch.bin
<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 Picos 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 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:
.. code:: cpp
void onStart(OTA_CALLBACK(fn));
void onEnd(OTA_CALLBACK(fn));
void onProgress(OTA_CALLBACK_PROGRESS(fn));
void onError(OTA_CALLBACK_ERROR (fn));
Uploading from the Arduino IDE
------------------------------
Uploading modules wirelessly from Arduino IDE is intended for the following typical scenarios:
- During firmware development as a quicker alternative to loading over a serial port,
- For updating a small number of modules,
- Only if modules are accessible on the same network as the computer with the Arduino IDE.
- For all IDE uploads,m the Pico W and the computer must be connected to the same network.
To upload wirelessly from the IDE:
1. Build a sketch starts ``WiFi`` and includes the appropriare calls to ``ArduinoOTA`` (see the examples for reference). These include the ``ArduinoOTA.begin()`` call in ``setup()`` and periodically calling ``ArduinoOTA.handle();`` from the ``loop()``
2. Upload using standard USB connection the first time.
3. The ``Tools->Port`` should now list ``pico-######`` under the ``Network Ports``. Select it (you won't be able to use the serial monitor, of course).
4. Try another upload. It should display the OTA process in place of the serial port upload.
Password Protection
-------------------
Protecting your OTA uploads with password is really straightforward. All you need to do, is to include the following statement in your code:
.. code:: cpp
ArduinoOTA.setPassword((const char *)"123");
Where ``123`` is a sample password that you should replace with your own.
Before implementing it in your sketch, it is a good idea to check how it works using *BasicOTA.ino* sketch available under *File > Examples > ArduinoOTA*. Go ahead, open *BasicOTA.ino*, uncomment the above statement that is already there, and upload the sketch. To make troubleshooting easier, do not modify example sketch besides what is absolutely required. This is including original simple ``123`` OTA password. Then attempt to upload sketch again (using OTA). After compilation is complete, once upload is about to begin, you should see prompt for password.
Enter the password and upload should be initiated as usual with the only difference being ``Authenticating...OK`` message visible in upload log.
You will not be prompted for a reentering the same password next time. Arduino IDE will remember it for you. You will see prompt for password only after reopening IDE, or if you change it in your sketch, upload the sketch and then try to upload it again.
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
----------------
The Stream Interface is the base for all other update modes like OTA, HTTP Server / client. Given a Stream-class variable `streamVar` providing `byteCount` bytes of firmware, it can store the firmware as follows:
.. code:: cpp
Update.begin(firmwareLengthInBytes);
Update.writeStream(streamVar);
Update.end();
OTA Bootloader and Memory Map
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A firmware file is uploaded via any method (Ethernet, WiFi, serial ZModem, etc.) and stored on the LittleFS filesystem as a normal file. The Updater class (or the underlying PicoOTA) will make a special "OTA command" file on the filesystem, which will be read by the OTA bootloader. On a reboot, this OTA bootloader will check for an upgrade file, verify its contents, and then perform the requested update and reboot. If no upgrade file is present, the OTA bootloader simply jumps to the main sketch.
The ROM layout consists of:
.. code:: cpp
[boot2.S] [OTA Bootloader] [0-pad] [OTA partition table] [Main sketch] [LittleFS filesystem] [EEPROM]
-5
View File
@@ -60,8 +60,3 @@ it use a non-default pinout with a simple call
SPI.setCS(5);
SD.begin(5);
}
Pad Strength
============
The Raspberry Pi Pico has the ability to set the current that a pin (actually the pad associated with it) is capable of supplying. The current can be set to values of 2mA, 4mA, 8mA and 12mA. By default, on a reset, the setting is 4mA. A `pinMode(x, OUTPUT)`, where `x` is the pin number, is also the default setting. 4 settings have been added for use with `pinMode`: `OUTPUT_2MA`, `OUTPUT_4MA`, which has the same behavior as `OUTPUT`, `OUTPUT_8MA` and `OUTPUT_12MA`.
+15 -2
View File
@@ -3,8 +3,8 @@
Equivalent to the Arduino SoftwareSerial library, an emulated UART using
one or two PIO state machines is included in the Arduino-Pico core. This
allows for up to 8 additional serial ports to be run from the RP2040 without
requiring additional CPU resources.
allows for up to 4 bidirectional or up to 8 unidirectional serial ports to
be run from the RP2040 without requiring additional CPU resources.
Instantiate a ``SerialPIO(txpin, rxpin, fifosize)`` object in your sketch and then
use it the same as any other serial port. Even, odd, and no parity modes
@@ -21,3 +21,16 @@ For example, to make a transmit-only port on GP16
For detailed information about the Serial ports, see the
Arduino `Serial Reference <https://www.arduino.cc/reference/en/language/functions/communication/serial/>`_ .
SoftwareSerial Emulation
========================
A ``SoftwareSerial`` wrapper is included to provide plug-and-play compatibility
with the Arduino `Software Serial <https://docs.arduino.cc/learn/built-in-libraries/software-serial>`_
library. Use the normal ``#include <SoftwareSerial.h>`` to include it. The following
differences from the Arduino standard are present:
* Inverted mode is not supported
* All ports are always listening
* ``listen`` call is a no-op
* ``isListening()`` always returns ``true``
+112 -14
View File
@@ -19,14 +19,14 @@ The PlatformIO experience:
Refer to the general documentation at https://docs.platformio.org/.
Especially useful is the `Getting started with VSCode + PlatformIO <https://docs.platformio.org/en/latest/integration/ide/vscode.html#installation), [CLI reference](https://docs.platformio.org/en/latest/core/index.html) and [platformio.ini options](https://docs.platformio.org/en/latest/projectconf/index.html)>`__ page.
Especially useful is the `Getting started with VSCode + PlatformIO <https://docs.platformio.org/en/latest/integration/ide/vscode.html#installation>`_, `CLI reference <https://docs.platformio.org/en/latest/core/index.html>`_ and the `platformio.ini options <https://docs.platformio.org/en/latest/projectconf/index.html>`_ page.
Hereafter it is assumed that you have a basic understanding of PlatformIO in regards to project creation, project file structure and building and uploading PlatformIO projects, through reading the above pages.
Current state of development
----------------------------
At the time of writing, PlatformIO integration for this core is a work-in-progress and not yet merged into mainline PlatformIO. This is subject to change soon.
At the time of writing, PlatformIO integration for this core is a work-in-progress and not yet merged into mainline PlatformIO. This is subject to change once `this pull request <https://github.com/platformio/platform-raspberrypi/pull/36>`_ is merged.
If you want to use the PlatformIO integration right now, make sure you first create a standard Raspberry Pi Pico + Arduino project within PlatformIO.
This will give you a project with the ``platformio.ini``
@@ -38,8 +38,7 @@ This will give you a project with the ``platformio.ini``
board = pico
framework = arduino
Here, you need to change the `platform` to take advantage of the features described hereunder.
You *also* need to inject two PlatformIO packages, one for the compiler toolchain and one for the Arduino core package.
Here, you need to change the `platform` to take advantage of the features described hereunder and switch to the new core.
.. code:: ini
@@ -47,12 +46,32 @@ You *also* need to inject two PlatformIO packages, one for the compiler toolchai
platform = https://github.com/maxgerhardt/platform-raspberrypi.git
board = pico
framework = arduino
board_build.core = earlephilhower
When the support for this core has been merged into mainline PlatformIO, this notice will be removed and a standard `platformio.ini` as shown above will work as a base.
Deprecation warnings
---------------------
Previous versions of this documentation told users to inject the framework and toolchain package into the project by using
.. code:: ini
; note that download link for toolchain is specific for OS. see https://github.com/earlephilhower/pico-quick-toolchain/releases.
platform_packages =
maxgerhardt/framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git
maxgerhardt/toolchain-pico@https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.1-a/x86_64-w64-mingw32.arm-none-eabi-7855b0c.210706.zip
When the support for this core has been merged into mainline PlatformIO, this notice will be removed and a standard `platformio.ini` as shown above will work as a base.
This is now **deprecated** and should not be done anymore. Users should delete these ``platform_packages`` lines and update the platform integration by issuing the command
.. code:: bash
pio pkg update -g -p https://github.com/maxgerhardt/platform-raspberrypi.git
in the `PlatformIO CLI <https://docs.platformio.org/en/latest/integration/ide/vscode.html#platformio-core-cli>`_. The same can be achieved by using the VSCode PIO Home -> Platforms -> Updates GUI.
The toolchain, which was also renamed to ``toolchain-rp2040-earlephilhower`` is downloaded automatically from the registry. The same goes for the ``framework-arduinopico`` toolchain package, which points directly to the Arduino-Pico Github repository.
However, users can still select a custom fork or branch of the core if desired so, as detailed in a chapter below.
Selecting the new core
----------------------
@@ -61,8 +80,8 @@ Prerequisite for using this core is to tell PlatformIO to switch to it.
There will be board definition files where the Earle-Philhower core will
be the default since it's a board that only exists in this core (and not
the other https://github.com/arduino/ArduinoCore-mbed). To switch boards
for which this is not the default core (e.g. the standard
``board = pico``), the directive
for which this is not the default core (which are only
``board = pico`` and ``board = nanorp2040connect``), the directive
.. code:: ini
@@ -72,6 +91,8 @@ must be added to the ``platformio.ini``. This controls the `core
switching
logic <https://github.com/maxgerhardt/platform-raspberrypi/blob/77e0d3a29d1dbf00fd3ec3271104e3bf4820869c/builder/frameworks/arduino/arduino.py#L27-L32>`__.
When using Arduino-Pico-only boards like ``board = rpipico`` or ``board = adafruit_feather``, this is not needed.
Flash size
----------
@@ -154,6 +175,37 @@ either a sing line or a newline-separated expression.
-DDEBUG_RP2040_CORE
-DDEBUG_RP2040_PORT=Serial2
C++ Exceptions
--------------
Exceptions are disabled by default. To enable them, use
.. code:: ini
; Enable Exceptions
build_flags = -DPIO_FRAMEWORK_ARDUINO_ENABLE_EXCEPTIONS
Stack Protector
---------------
To enable GCC's stack protection feature, use
.. code:: ini
; Enable Stack Protector
build_flags = -fstack-protector
RTTI
----
RTTI (run-time type information) is disabled by default. To enable it, use
.. code:: ini
; Enable RTTI
build_flags = -DPIO_FRAMEWORK_ARDUINO_ENABLE_RTTI
USB Stack
---------
@@ -170,6 +222,18 @@ default Pico SDK USB stack. To change it, add
Note that the special "No USB" setting is also supported, through the
shortcut-define ``PIO_FRAMEWORK_ARDUINO_NO_USB``.
IP Stack
---------
The lwIP stack can be configured to support only IPv4 (default) or additionally IPv6. To activate IPv6 support, add
.. code:: ini
; IPv6
build_flags = -DPIO_FRAMEWORK_ARDUINO_ENABLE_IPV6
to the ``platformio.ini``.
Selecting a different core version
----------------------------------
@@ -188,8 +252,8 @@ directive to do so. Simply specify that the framework package
Whereas the ``#master`` can also be replaced by a ``#branchname`` or a
``#commithash``. If left out, it will pull the default branch, which is ``master``.
The ``file://`` pseudo-protocol can also be used instead of ``https://`` to point to a
local copy of the core (with e.g. some modifications) on disk.
The ``file://`` and ``symlink://`` pseudo-protocols can also be used instead of ``https://`` to point to a
local copy of the core (with e.g. some modifications) on disk (`see documentation <https://docs.platformio.org/en/latest/core/userguide/pkg/cmd_install.html?#local-folder>`_).
Note that this can only be done for versions that have the PlatformIO
builder script it in, so versions before 1.9.2 are not supported.
@@ -206,14 +270,48 @@ and 0.5MByte filesystem.
platform = https://github.com/maxgerhardt/platform-raspberrypi.git
board = pico
framework = arduino
; board can use both Arduino cores -- we select Arduino-Pico here
board_build.core = earlephilhower
board_build.filesystem_size = 0.5m
; note that download link for toolchain is specific for OS. see https://github.com/earlephilhower/pico-quick-toolchain/releases.
platform_packages =
maxgerhardt/framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git
maxgerhardt/toolchain-pico@https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.1-a/x86_64-w64-mingw32.arm-none-eabi-7855b0c.210706.zip
The initial project structure should be generated just creating a new
project for the Pico and the Arduino framework, after which the
auto-generated ``platformio.ini`` can be adapted per above.
Debugging
---------
With recent updates to the toolchain and OpenOCD, debugging firmwares is also possible.
To specify the debugging adapter, use ``debug_tool`` (`documentation <https://docs.platformio.org/en/latest/projectconf/section_env_debug.html#debug-tool>`_). Supported values are:
* ``picoprobe``
* ``cmsis-dap``
* ``jlink``
* ``raspberrypi-swd``
These values can also be used in ``upload_protocol`` if you want PlatformIO to upload the regular firmware through this method, which you likely want.
Especially the PicoProbe method is convenient when you have two Raspberry Pi Pico boards. One of them can be flashed with the PicoProbe firmware (`documentation <https://www.raspberrypi.com/documentation/microcontrollers/raspberry-pi-pico.html#debugging-using-another-raspberry-pi-pico>`_) and is then connected to the target Raspberry Pi Pico board (see `documentation <https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf>`_ chapter "Picoprobe Wiring"). Remember that on Windows, you have to use `Zadig <https://zadig.akeo.ie/>`_ to also load "WinUSB" drivers for the "Picoprobe (Interface 2)" device so that OpenOCD can speak to it.
With that set up, debugging can be started via the left debugging sidebar and works nicely: Setup breakpoints, inspect the value of variables in the code, step through the code line by line. When a breakpoint is hit or execution is halted, you can even see the execution state both Cortex-M0+ cores of the RP2040.
.. image:: images/pio_debugging.png
For further information on customizing debug options, like the initial breakpoint or debugging / SWD speed, consult `the documentation <https://docs.platformio.org/en/latest/projectconf/section_env_debug.html>`_.
Filesystem Uploading
--------------------
For the Arduino IDE, `a plugin <https://github.com/earlephilhower/arduino-pico#uploading-filesystem-images>`_ is available that enables a data folder to be packed as a LittleFS filesystem binary and uploaded to the Pico.
This functionality is also built-in in the PlatformIO integration. Open the `project tasks <https://docs.platformio.org/en/latest/integration/ide/vscode.html#project-tasks>`_ and expand the "Platform" tasks:
.. image:: images/pio_fs_upload.png
The files you want to upload should be placed in a folder called ``data`` inside the project. This can be customized `if needed <https://docs.platformio.org/en/latest/projectconf/section_platformio.html#data-dir>`_.
The task "Build Filesystem Image" will take all files in the data directory and create a ``littlefs.bin`` file from it using the ``mklittlefs`` tool.
The task "Upload Filesystem Image" will upload the filesystem image to the Pico via the specified ``upload_protocol``.
+72
View File
@@ -0,0 +1,72 @@
RP2040 Helper Class
===================
Some of the core functionality of the RP2040 chip powering the Raspberry Pi
Pico is exposed in the RP2040 class variable ``rp2040``.
Core Internals
--------------
int rp2040.f_cpu()
~~~~~~~~~~~~~~~~~~
Returns the current frequency of the core clock. This is read at runtime,
versus the constant ``F_CPU`` macro that is also available. This is useful
in cases where your code changes the core clock (i.e. low power modes, etc.)
uint32_t rp2040.getCycleCount()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Returns a 32-bit cycle count from then the core started running. Because it
is only 32-bits, and the Pico runs at 133MHz, this value can loop around
in a matter of seconds.
uint64_t rp2040.getCycleCount64()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Returns a 64-bit cycle count from then the core started running. This value
should never loop around in normal mode (at 133MHz it would take over 4,000
years to overflow).
uint32_t rp2040.hwrand32()
~~~~~~~~~~~~~~~~~~~~~~~~~~
Returns a 32-bit value derived from the CPU cycle counter and the ROSC
oscillator. Because the ROSC bit is not a true random number generator, the
values returned may not meet the most stringent random tests. **If your
application needs absolute bulletproof random numbers, consider using
dedicated external hardware.**
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
------------------
int rp2040.getFreeHeap()
~~~~~~~~~~~~~~~~~~~~~~~~
Returns the number of bytes free for heap allocation (i.e. malloc, new). Note
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()
~~~~~~~~~~~~~~~~~~~~~~~~
Returns the number of bytes allocated out of the heap.
int rp2040.getTotalHeap()
~~~~~~~~~~~~~~~~~~~~~~~~~
Returns the total heap that was available to this program at compile time (i.e.
the Pico RAM size minus things like the ``.data`` and ``.bss`` sections and other
overhead).

Some files were not shown because too many files have changed in this diff Show More