This commit is contained in:
2026-01-15 15:00:21 +08:00
parent e67749e2e4
commit 419f6cc78c
705 changed files with 9981 additions and 35723 deletions

View File

@ -1,46 +0,0 @@
Thank you for opening an issue on an Adafruit Arduino library repository. To
improve the speed of resolution please review the following guidelines and
common troubleshooting steps below before creating the issue:
- **Do not use GitHub issues for troubleshooting projects and issues.** Instead use
the forums at http://forums.adafruit.com to ask questions and troubleshoot why
something isn't working as expected. In many cases the problem is a common issue
that you will more quickly receive help from the forum community. GitHub issues
are meant for known defects in the code. If you don't know if there is a defect
in the code then start with troubleshooting on the forum first.
- **If following a tutorial or guide be sure you didn't miss a step.** Carefully
check all of the steps and commands to run have been followed. Consult the
forum if you're unsure or have questions about steps in a guide/tutorial.
- **For Arduino projects check these very common issues to ensure they don't apply**:
- For uploading sketches or communicating with the board make sure you're using
a **USB data cable** and **not** a **USB charge-only cable**. It is sometimes
very hard to tell the difference between a data and charge cable! Try using the
cable with other devices or swapping to another cable to confirm it is not
the problem.
- **Be sure you are supplying adequate power to the board.** Check the specs of
your board and plug in an external power supply. In many cases just
plugging a board into your computer is not enough to power it and other
peripherals.
- **Double check all soldering joints and connections.** Flakey connections
cause many mysterious problems. See the [guide to excellent soldering](https://learn.adafruit.com/adafruit-guide-excellent-soldering/tools) for examples of good solder joints.
- **Ensure you are using an official Arduino or Adafruit board.** We can't
guarantee a clone board will have the same functionality and work as expected
with this code and don't support them.
If you're sure this issue is a defect in the code and checked the steps above
please fill in the following fields to provide enough troubleshooting information.
You may delete the guideline and text above to just leave the following details:
- Arduino board: **INSERT ARDUINO BOARD NAME/TYPE HERE**
- Arduino IDE version (found in Arduino -> About Arduino menu): **INSERT ARDUINO
VERSION HERE**
- List the steps to reproduce the problem below (if possible attach a sketch or
copy the sketch code in too): **LIST REPRO STEPS BELOW**

View File

@ -1,26 +0,0 @@
Thank you for creating a pull request to contribute to Adafruit's GitHub code!
Before you open the request please review the following guidelines and tips to
help it be more easily integrated:
- **Describe the scope of your change--i.e. what the change does and what parts
of the code were modified.** This will help us understand any risks of integrating
the code.
- **Describe any known limitations with your change.** For example if the change
doesn't apply to a supported platform of the library please mention it.
- **Please run any tests or examples that can exercise your modified code.** We
strive to not break users of the code and running tests/examples helps with this
process.
Thank you again for contributing! We will try to test and integrate the change
as soon as we can, but be aware we have many GitHub repositories to manage and
can't immediately respond to every request. There is no need to bump or check in
on a pull request (it will clutter the discussion of the request).
Also don't be worried if the request is closed or not integrated--sometimes the
priorities of Adafruit's GitHub code (education, ease of use) might not match the
priorities of the pull request. Don't fret, the open source community thrives on
forks and GitHub makes it easy to keep your changes in a forked repo.
After reviewing the guidelines above you can delete this text from the pull request.

View File

@ -1,33 +0,0 @@
name: Arduino Library CI
on: [pull_request, push, repository_dispatch]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/setup-python@v4
with:
python-version: '3.x'
- uses: actions/checkout@v3
- uses: actions/checkout@v3
with:
repository: adafruit/ci-arduino
path: ci
- name: Install the prerequisites
run: bash ci/actions_install.sh
- name: Check for correct code formatting with clang-format
run: python3 ci/run-clang-format.py -e "ci/*" -e "bin/*" -r .
- name: Check for correct documentation with doxygen
env:
GH_REPO_TOKEN: ${{ secrets.GH_REPO_TOKEN }}
PRETTYNAME : "Adafruit Bus IO Library"
run: bash ci/doxy_gen_and_deploy.sh
- name: Test the code on supported platforms
run: python3 ci/build_platform.py main_platforms zero feather32u4

View File

@ -1 +0,0 @@
{"type": "library", "name": "Adafruit BusIO", "version": "1.15.0", "spec": {"owner": "adafruit", "id": 6214, "name": "Adafruit BusIO", "requirements": null, "uri": null}}

View File

@ -1,365 +0,0 @@
#include <Adafruit_BusIO_Register.h>
#if !defined(SPI_INTERFACES_COUNT) || \
(defined(SPI_INTERFACES_COUNT) && (SPI_INTERFACES_COUNT > 0))
/*!
* @brief Create a register we access over an I2C Device (which defines the
* bus and address)
* @param i2cdevice The I2CDevice to use for underlying I2C access
* @param reg_addr The address pointer value for the I2C/SMBus register, can
* be 8 or 16 bits
* @param width The width of the register data itself, defaults to 1 byte
* @param byteorder The byte order of the register (used when width is > 1),
* defaults to LSBFIRST
* @param address_width The width of the register address itself, defaults
* to 1 byte
*/
Adafruit_BusIO_Register::Adafruit_BusIO_Register(Adafruit_I2CDevice *i2cdevice,
uint16_t reg_addr,
uint8_t width,
uint8_t byteorder,
uint8_t address_width) {
_i2cdevice = i2cdevice;
_spidevice = nullptr;
_addrwidth = address_width;
_address = reg_addr;
_byteorder = byteorder;
_width = width;
}
/*!
* @brief Create a register we access over an SPI Device (which defines the
* bus and CS pin)
* @param spidevice The SPIDevice to use for underlying SPI access
* @param reg_addr The address pointer value for the SPI register, can
* be 8 or 16 bits
* @param type The method we use to read/write data to SPI (which is not
* as well defined as I2C)
* @param width The width of the register data itself, defaults to 1 byte
* @param byteorder The byte order of the register (used when width is > 1),
* defaults to LSBFIRST
* @param address_width The width of the register address itself, defaults
* to 1 byte
*/
Adafruit_BusIO_Register::Adafruit_BusIO_Register(Adafruit_SPIDevice *spidevice,
uint16_t reg_addr,
Adafruit_BusIO_SPIRegType type,
uint8_t width,
uint8_t byteorder,
uint8_t address_width) {
_spidevice = spidevice;
_spiregtype = type;
_i2cdevice = nullptr;
_addrwidth = address_width;
_address = reg_addr;
_byteorder = byteorder;
_width = width;
}
/*!
* @brief Create a register we access over an I2C or SPI Device. This is a
* handy function because we can pass in nullptr for the unused interface,
* allowing libraries to mass-define all the registers
* @param i2cdevice The I2CDevice to use for underlying I2C access, if
* nullptr we use SPI
* @param spidevice The SPIDevice to use for underlying SPI access, if
* nullptr we use I2C
* @param reg_addr The address pointer value for the I2C/SMBus/SPI register,
* can be 8 or 16 bits
* @param type The method we use to read/write data to SPI (which is not
* as well defined as I2C)
* @param width The width of the register data itself, defaults to 1 byte
* @param byteorder The byte order of the register (used when width is > 1),
* defaults to LSBFIRST
* @param address_width The width of the register address itself, defaults
* to 1 byte
*/
Adafruit_BusIO_Register::Adafruit_BusIO_Register(
Adafruit_I2CDevice *i2cdevice, Adafruit_SPIDevice *spidevice,
Adafruit_BusIO_SPIRegType type, uint16_t reg_addr, uint8_t width,
uint8_t byteorder, uint8_t address_width) {
_spidevice = spidevice;
_i2cdevice = i2cdevice;
_spiregtype = type;
_addrwidth = address_width;
_address = reg_addr;
_byteorder = byteorder;
_width = width;
}
/*!
* @brief Write a buffer of data to the register location
* @param buffer Pointer to data to write
* @param len Number of bytes to write
* @return True on successful write (only really useful for I2C as SPI is
* uncheckable)
*/
bool Adafruit_BusIO_Register::write(uint8_t *buffer, uint8_t len) {
uint8_t addrbuffer[2] = {(uint8_t)(_address & 0xFF),
(uint8_t)(_address >> 8)};
if (_i2cdevice) {
return _i2cdevice->write(buffer, len, true, addrbuffer, _addrwidth);
}
if (_spidevice) {
if (_spiregtype == ADDRESSED_OPCODE_BIT0_LOW_TO_WRITE) {
// very special case!
// pass the special opcode address which we set as the high byte of the
// regaddr
addrbuffer[0] =
(uint8_t)(_address >> 8) & ~0x01; // set bottom bit low to write
// the 'actual' reg addr is the second byte then
addrbuffer[1] = (uint8_t)(_address & 0xFF);
// the address appears to be a byte longer
return _spidevice->write(buffer, len, addrbuffer, _addrwidth + 1);
}
if (_spiregtype == ADDRBIT8_HIGH_TOREAD) {
addrbuffer[0] &= ~0x80;
}
if (_spiregtype == ADDRBIT8_HIGH_TOWRITE) {
addrbuffer[0] |= 0x80;
}
if (_spiregtype == AD8_HIGH_TOREAD_AD7_HIGH_TOINC) {
addrbuffer[0] &= ~0x80;
addrbuffer[0] |= 0x40;
}
return _spidevice->write(buffer, len, addrbuffer, _addrwidth);
}
return false;
}
/*!
* @brief Write up to 4 bytes of data to the register location
* @param value Data to write
* @param numbytes How many bytes from 'value' to write
* @return True on successful write (only really useful for I2C as SPI is
* uncheckable)
*/
bool Adafruit_BusIO_Register::write(uint32_t value, uint8_t numbytes) {
if (numbytes == 0) {
numbytes = _width;
}
if (numbytes > 4) {
return false;
}
// store a copy
_cached = value;
for (int i = 0; i < numbytes; i++) {
if (_byteorder == LSBFIRST) {
_buffer[i] = value & 0xFF;
} else {
_buffer[numbytes - i - 1] = value & 0xFF;
}
value >>= 8;
}
return write(_buffer, numbytes);
}
/*!
* @brief Read data from the register location. This does not do any error
* checking!
* @return Returns 0xFFFFFFFF on failure, value otherwise
*/
uint32_t Adafruit_BusIO_Register::read(void) {
if (!read(_buffer, _width)) {
return -1;
}
uint32_t value = 0;
for (int i = 0; i < _width; i++) {
value <<= 8;
if (_byteorder == LSBFIRST) {
value |= _buffer[_width - i - 1];
} else {
value |= _buffer[i];
}
}
return value;
}
/*!
* @brief Read cached data from last time we wrote to this register
* @return Returns 0xFFFFFFFF on failure, value otherwise
*/
uint32_t Adafruit_BusIO_Register::readCached(void) { return _cached; }
/*!
* @brief Read a buffer of data from the register location
* @param buffer Pointer to data to read into
* @param len Number of bytes to read
* @return True on successful write (only really useful for I2C as SPI is
* uncheckable)
*/
bool Adafruit_BusIO_Register::read(uint8_t *buffer, uint8_t len) {
uint8_t addrbuffer[2] = {(uint8_t)(_address & 0xFF),
(uint8_t)(_address >> 8)};
if (_i2cdevice) {
return _i2cdevice->write_then_read(addrbuffer, _addrwidth, buffer, len);
}
if (_spidevice) {
if (_spiregtype == ADDRESSED_OPCODE_BIT0_LOW_TO_WRITE) {
// very special case!
// pass the special opcode address which we set as the high byte of the
// regaddr
addrbuffer[0] =
(uint8_t)(_address >> 8) | 0x01; // set bottom bit high to read
// the 'actual' reg addr is the second byte then
addrbuffer[1] = (uint8_t)(_address & 0xFF);
// the address appears to be a byte longer
return _spidevice->write_then_read(addrbuffer, _addrwidth + 1, buffer,
len);
}
if (_spiregtype == ADDRBIT8_HIGH_TOREAD) {
addrbuffer[0] |= 0x80;
}
if (_spiregtype == ADDRBIT8_HIGH_TOWRITE) {
addrbuffer[0] &= ~0x80;
}
if (_spiregtype == AD8_HIGH_TOREAD_AD7_HIGH_TOINC) {
addrbuffer[0] |= 0x80 | 0x40;
}
return _spidevice->write_then_read(addrbuffer, _addrwidth, buffer, len);
}
return false;
}
/*!
* @brief Read 2 bytes of data from the register location
* @param value Pointer to uint16_t variable to read into
* @return True on successful write (only really useful for I2C as SPI is
* uncheckable)
*/
bool Adafruit_BusIO_Register::read(uint16_t *value) {
if (!read(_buffer, 2)) {
return false;
}
if (_byteorder == LSBFIRST) {
*value = _buffer[1];
*value <<= 8;
*value |= _buffer[0];
} else {
*value = _buffer[0];
*value <<= 8;
*value |= _buffer[1];
}
return true;
}
/*!
* @brief Read 1 byte of data from the register location
* @param value Pointer to uint8_t variable to read into
* @return True on successful write (only really useful for I2C as SPI is
* uncheckable)
*/
bool Adafruit_BusIO_Register::read(uint8_t *value) {
if (!read(_buffer, 1)) {
return false;
}
*value = _buffer[0];
return true;
}
/*!
* @brief Pretty printer for this register
* @param s The Stream to print to, defaults to &Serial
*/
void Adafruit_BusIO_Register::print(Stream *s) {
uint32_t val = read();
s->print("0x");
s->print(val, HEX);
}
/*!
* @brief Pretty printer for this register
* @param s The Stream to print to, defaults to &Serial
*/
void Adafruit_BusIO_Register::println(Stream *s) {
print(s);
s->println();
}
/*!
* @brief Create a slice of the register that we can address without
* touching other bits
* @param reg The Adafruit_BusIO_Register which defines the bus/register
* @param bits The number of bits wide we are slicing
* @param shift The number of bits that our bit-slice is shifted from LSB
*/
Adafruit_BusIO_RegisterBits::Adafruit_BusIO_RegisterBits(
Adafruit_BusIO_Register *reg, uint8_t bits, uint8_t shift) {
_register = reg;
_bits = bits;
_shift = shift;
}
/*!
* @brief Read 4 bytes of data from the register
* @return data The 4 bytes to read
*/
uint32_t Adafruit_BusIO_RegisterBits::read(void) {
uint32_t val = _register->read();
val >>= _shift;
return val & ((1 << (_bits)) - 1);
}
/*!
* @brief Write 4 bytes of data to the register
* @param data The 4 bytes to write
* @return True on successful write (only really useful for I2C as SPI is
* uncheckable)
*/
bool Adafruit_BusIO_RegisterBits::write(uint32_t data) {
uint32_t val = _register->read();
// mask off the data before writing
uint32_t mask = (1 << (_bits)) - 1;
data &= mask;
mask <<= _shift;
val &= ~mask; // remove the current data at that spot
val |= data << _shift; // and add in the new data
return _register->write(val, _register->width());
}
/*!
* @brief The width of the register data, helpful for doing calculations
* @returns The data width used when initializing the register
*/
uint8_t Adafruit_BusIO_Register::width(void) { return _width; }
/*!
* @brief Set the default width of data
* @param width the default width of data read from register
*/
void Adafruit_BusIO_Register::setWidth(uint8_t width) { _width = width; }
/*!
* @brief Set register address
* @param address the address from register
*/
void Adafruit_BusIO_Register::setAddress(uint16_t address) {
_address = address;
}
/*!
* @brief Set the width of register address
* @param address_width the width for register address
*/
void Adafruit_BusIO_Register::setAddressWidth(uint16_t address_width) {
_addrwidth = address_width;
}
#endif // SPI exists

View File

@ -1,105 +0,0 @@
#ifndef Adafruit_BusIO_Register_h
#define Adafruit_BusIO_Register_h
#include <Arduino.h>
#if !defined(SPI_INTERFACES_COUNT) || \
(defined(SPI_INTERFACES_COUNT) && (SPI_INTERFACES_COUNT > 0))
#include <Adafruit_I2CDevice.h>
#include <Adafruit_SPIDevice.h>
typedef enum _Adafruit_BusIO_SPIRegType {
ADDRBIT8_HIGH_TOREAD = 0,
/*!<
* ADDRBIT8_HIGH_TOREAD
* When reading a register you must actually send the value 0x80 + register
* address to the device. e.g. To read the register 0x0B the register value
* 0x8B is sent and to write 0x0B is sent.
*/
AD8_HIGH_TOREAD_AD7_HIGH_TOINC = 1,
/*!<
* ADDRBIT8_HIGH_TOWRITE
* When writing to a register you must actually send the value 0x80 +
* the register address to the device. e.g. To write to the register 0x19 the
* register value 0x99 is sent and to read 0x19 is sent.
*/
ADDRBIT8_HIGH_TOWRITE = 2,
/*!<
* ADDRESSED_OPCODE_LOWBIT_TO_WRITE
* Used by the MCP23S series, we send 0x40 |'rd with the opcode
* Then set the lowest bit to write
*/
ADDRESSED_OPCODE_BIT0_LOW_TO_WRITE = 3,
} Adafruit_BusIO_SPIRegType;
/*!
* @brief The class which defines a device register (a location to read/write
* data from)
*/
class Adafruit_BusIO_Register {
public:
Adafruit_BusIO_Register(Adafruit_I2CDevice *i2cdevice, uint16_t reg_addr,
uint8_t width = 1, uint8_t byteorder = LSBFIRST,
uint8_t address_width = 1);
Adafruit_BusIO_Register(Adafruit_SPIDevice *spidevice, uint16_t reg_addr,
Adafruit_BusIO_SPIRegType type, uint8_t width = 1,
uint8_t byteorder = LSBFIRST,
uint8_t address_width = 1);
Adafruit_BusIO_Register(Adafruit_I2CDevice *i2cdevice,
Adafruit_SPIDevice *spidevice,
Adafruit_BusIO_SPIRegType type, uint16_t reg_addr,
uint8_t width = 1, uint8_t byteorder = LSBFIRST,
uint8_t address_width = 1);
bool read(uint8_t *buffer, uint8_t len);
bool read(uint8_t *value);
bool read(uint16_t *value);
uint32_t read(void);
uint32_t readCached(void);
bool write(uint8_t *buffer, uint8_t len);
bool write(uint32_t value, uint8_t numbytes = 0);
uint8_t width(void);
void setWidth(uint8_t width);
void setAddress(uint16_t address);
void setAddressWidth(uint16_t address_width);
void print(Stream *s = &Serial);
void println(Stream *s = &Serial);
private:
Adafruit_I2CDevice *_i2cdevice;
Adafruit_SPIDevice *_spidevice;
Adafruit_BusIO_SPIRegType _spiregtype;
uint16_t _address;
uint8_t _width, _addrwidth, _byteorder;
uint8_t _buffer[4]; // we won't support anything larger than uint32 for
// non-buffered read
uint32_t _cached = 0;
};
/*!
* @brief The class which defines a slice of bits from within a device register
* (a location to read/write data from)
*/
class Adafruit_BusIO_RegisterBits {
public:
Adafruit_BusIO_RegisterBits(Adafruit_BusIO_Register *reg, uint8_t bits,
uint8_t shift);
bool write(uint32_t value);
uint32_t read(void);
private:
Adafruit_BusIO_Register *_register;
uint8_t _bits, _shift;
};
#endif // SPI exists
#endif // BusIO_Register_h

View File

@ -1,317 +0,0 @@
#include "Adafruit_I2CDevice.h"
//#define DEBUG_SERIAL Serial
/*!
* @brief Create an I2C device at a given address
* @param addr The 7-bit I2C address for the device
* @param theWire The I2C bus to use, defaults to &Wire
*/
Adafruit_I2CDevice::Adafruit_I2CDevice(uint8_t addr, TwoWire *theWire) {
_addr = addr;
_wire = theWire;
_begun = false;
#ifdef ARDUINO_ARCH_SAMD
_maxBufferSize = 250; // as defined in Wire.h's RingBuffer
#elif defined(ESP32)
_maxBufferSize = I2C_BUFFER_LENGTH;
#else
_maxBufferSize = 32;
#endif
}
/*!
* @brief Initializes and does basic address detection
* @param addr_detect Whether we should attempt to detect the I2C address
* with a scan. 99% of sensors/devices don't mind, but once in a while they
* don't respond well to a scan!
* @return True if I2C initialized and a device with the addr found
*/
bool Adafruit_I2CDevice::begin(bool addr_detect) {
_wire->begin();
_begun = true;
if (addr_detect) {
return detected();
}
return true;
}
/*!
* @brief De-initialize device, turn off the Wire interface
*/
void Adafruit_I2CDevice::end(void) {
// Not all port implement Wire::end(), such as
// - ESP8266
// - AVR core without WIRE_HAS_END
// - ESP32: end() is implemented since 2.0.1 which is latest at the moment.
// Temporarily disable for now to give time for user to update.
#if !(defined(ESP8266) || \
(defined(ARDUINO_ARCH_AVR) && !defined(WIRE_HAS_END)) || \
defined(ARDUINO_ARCH_ESP32))
_wire->end();
_begun = false;
#endif
}
/*!
* @brief Scans I2C for the address - note will give a false-positive
* if there's no pullups on I2C
* @return True if I2C initialized and a device with the addr found
*/
bool Adafruit_I2CDevice::detected(void) {
// Init I2C if not done yet
if (!_begun && !begin()) {
return false;
}
// A basic scanner, see if it ACK's
_wire->beginTransmission(_addr);
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.print(F("Address 0x"));
DEBUG_SERIAL.print(_addr);
#endif
if (_wire->endTransmission() == 0) {
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println(F(" Detected"));
#endif
return true;
}
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println(F(" Not detected"));
#endif
return false;
}
/*!
* @brief Write a buffer or two to the I2C device. Cannot be more than
* maxBufferSize() bytes.
* @param buffer Pointer to buffer of data to write. This is const to
* ensure the content of this buffer doesn't change.
* @param len Number of bytes from buffer to write
* @param prefix_buffer Pointer to optional array of data to write before
* buffer. Cannot be more than maxBufferSize() bytes. This is const to
* ensure the content of this buffer doesn't change.
* @param prefix_len Number of bytes from prefix buffer to write
* @param stop Whether to send an I2C STOP signal on write
* @return True if write was successful, otherwise false.
*/
bool Adafruit_I2CDevice::write(const uint8_t *buffer, size_t len, bool stop,
const uint8_t *prefix_buffer,
size_t prefix_len) {
if ((len + prefix_len) > maxBufferSize()) {
// currently not guaranteed to work if more than 32 bytes!
// we will need to find out if some platforms have larger
// I2C buffer sizes :/
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println(F("\tI2CDevice could not write such a large buffer"));
#endif
return false;
}
_wire->beginTransmission(_addr);
// Write the prefix data (usually an address)
if ((prefix_len != 0) && (prefix_buffer != nullptr)) {
if (_wire->write(prefix_buffer, prefix_len) != prefix_len) {
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println(F("\tI2CDevice failed to write"));
#endif
return false;
}
}
// Write the data itself
if (_wire->write(buffer, len) != len) {
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println(F("\tI2CDevice failed to write"));
#endif
return false;
}
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.print(F("\tI2CWRITE @ 0x"));
DEBUG_SERIAL.print(_addr, HEX);
DEBUG_SERIAL.print(F(" :: "));
if ((prefix_len != 0) && (prefix_buffer != nullptr)) {
for (uint16_t i = 0; i < prefix_len; i++) {
DEBUG_SERIAL.print(F("0x"));
DEBUG_SERIAL.print(prefix_buffer[i], HEX);
DEBUG_SERIAL.print(F(", "));
}
}
for (uint16_t i = 0; i < len; i++) {
DEBUG_SERIAL.print(F("0x"));
DEBUG_SERIAL.print(buffer[i], HEX);
DEBUG_SERIAL.print(F(", "));
if (i % 32 == 31) {
DEBUG_SERIAL.println();
}
}
if (stop) {
DEBUG_SERIAL.print("\tSTOP");
}
#endif
if (_wire->endTransmission(stop) == 0) {
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println();
// DEBUG_SERIAL.println("Sent!");
#endif
return true;
} else {
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println("\tFailed to send!");
#endif
return false;
}
}
/*!
* @brief Read from I2C into a buffer from the I2C device.
* Cannot be more than maxBufferSize() bytes.
* @param buffer Pointer to buffer of data to read into
* @param len Number of bytes from buffer to read.
* @param stop Whether to send an I2C STOP signal on read
* @return True if read was successful, otherwise false.
*/
bool Adafruit_I2CDevice::read(uint8_t *buffer, size_t len, bool stop) {
size_t pos = 0;
while (pos < len) {
size_t read_len =
((len - pos) > maxBufferSize()) ? maxBufferSize() : (len - pos);
bool read_stop = (pos < (len - read_len)) ? false : stop;
if (!_read(buffer + pos, read_len, read_stop))
return false;
pos += read_len;
}
return true;
}
bool Adafruit_I2CDevice::_read(uint8_t *buffer, size_t len, bool stop) {
#if defined(TinyWireM_h)
size_t recv = _wire->requestFrom((uint8_t)_addr, (uint8_t)len);
#elif defined(ARDUINO_ARCH_MEGAAVR)
size_t recv = _wire->requestFrom(_addr, len, stop);
#else
size_t recv = _wire->requestFrom((uint8_t)_addr, (uint8_t)len, (uint8_t)stop);
#endif
if (recv != len) {
// Not enough data available to fulfill our obligation!
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.print(F("\tI2CDevice did not receive enough data: "));
DEBUG_SERIAL.println(recv);
#endif
return false;
}
for (uint16_t i = 0; i < len; i++) {
buffer[i] = _wire->read();
}
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.print(F("\tI2CREAD @ 0x"));
DEBUG_SERIAL.print(_addr, HEX);
DEBUG_SERIAL.print(F(" :: "));
for (uint16_t i = 0; i < len; i++) {
DEBUG_SERIAL.print(F("0x"));
DEBUG_SERIAL.print(buffer[i], HEX);
DEBUG_SERIAL.print(F(", "));
if (len % 32 == 31) {
DEBUG_SERIAL.println();
}
}
DEBUG_SERIAL.println();
#endif
return true;
}
/*!
* @brief Write some data, then read some data from I2C into another buffer.
* Cannot be more than maxBufferSize() bytes. The buffers can point to
* same/overlapping locations.
* @param write_buffer Pointer to buffer of data to write from
* @param write_len Number of bytes from buffer to write.
* @param read_buffer Pointer to buffer of data to read into.
* @param read_len Number of bytes from buffer to read.
* @param stop Whether to send an I2C STOP signal between the write and read
* @return True if write & read was successful, otherwise false.
*/
bool Adafruit_I2CDevice::write_then_read(const uint8_t *write_buffer,
size_t write_len, uint8_t *read_buffer,
size_t read_len, bool stop) {
if (!write(write_buffer, write_len, stop)) {
return false;
}
return read(read_buffer, read_len);
}
/*!
* @brief Returns the 7-bit address of this device
* @return The 7-bit address of this device
*/
uint8_t Adafruit_I2CDevice::address(void) { return _addr; }
/*!
* @brief Change the I2C clock speed to desired (relies on
* underlying Wire support!
* @param desiredclk The desired I2C SCL frequency
* @return True if this platform supports changing I2C speed.
* Not necessarily that the speed was achieved!
*/
bool Adafruit_I2CDevice::setSpeed(uint32_t desiredclk) {
#if defined(__AVR_ATmega328__) || \
defined(__AVR_ATmega328P__) // fix arduino core set clock
// calculate TWBR correctly
if ((F_CPU / 18) < desiredclk) {
#ifdef DEBUG_SERIAL
Serial.println(F("I2C.setSpeed too high."));
#endif
return false;
}
uint32_t atwbr = ((F_CPU / desiredclk) - 16) / 2;
if (atwbr > 16320) {
#ifdef DEBUG_SERIAL
Serial.println(F("I2C.setSpeed too low."));
#endif
return false;
}
if (atwbr <= 255) {
atwbr /= 1;
TWSR = 0x0;
} else if (atwbr <= 1020) {
atwbr /= 4;
TWSR = 0x1;
} else if (atwbr <= 4080) {
atwbr /= 16;
TWSR = 0x2;
} else { // if (atwbr <= 16320)
atwbr /= 64;
TWSR = 0x3;
}
TWBR = atwbr;
#ifdef DEBUG_SERIAL
Serial.print(F("TWSR prescaler = "));
Serial.println(pow(4, TWSR));
Serial.print(F("TWBR = "));
Serial.println(atwbr);
#endif
return true;
#elif (ARDUINO >= 157) && !defined(ARDUINO_STM32_FEATHER) && \
!defined(TinyWireM_h)
_wire->setClock(desiredclk);
return true;
#else
(void)desiredclk;
return false;
#endif
}

View File

@ -1,36 +0,0 @@
#ifndef Adafruit_I2CDevice_h
#define Adafruit_I2CDevice_h
#include <Arduino.h>
#include <Wire.h>
///< The class which defines how we will talk to this device over I2C
class Adafruit_I2CDevice {
public:
Adafruit_I2CDevice(uint8_t addr, TwoWire *theWire = &Wire);
uint8_t address(void);
bool begin(bool addr_detect = true);
void end(void);
bool detected(void);
bool read(uint8_t *buffer, size_t len, bool stop = true);
bool write(const uint8_t *buffer, size_t len, bool stop = true,
const uint8_t *prefix_buffer = nullptr, size_t prefix_len = 0);
bool write_then_read(const uint8_t *write_buffer, size_t write_len,
uint8_t *read_buffer, size_t read_len,
bool stop = false);
bool setSpeed(uint32_t desiredclk);
/*! @brief How many bytes we can read in a transaction
* @return The size of the Wire receive/transmit buffer */
size_t maxBufferSize() { return _maxBufferSize; }
private:
uint8_t _addr;
TwoWire *_wire;
bool _begun;
size_t _maxBufferSize;
bool _read(uint8_t *buffer, size_t len, bool stop);
};
#endif // Adafruit_I2CDevice_h

View File

@ -1,10 +0,0 @@
#ifndef _ADAFRUIT_I2C_REGISTER_H_
#define _ADAFRUIT_I2C_REGISTER_H_
#include <Adafruit_BusIO_Register.h>
#include <Arduino.h>
typedef Adafruit_BusIO_Register Adafruit_I2CRegister;
typedef Adafruit_BusIO_RegisterBits Adafruit_I2CRegisterBits;
#endif

View File

@ -1,508 +0,0 @@
#include "Adafruit_SPIDevice.h"
//#define DEBUG_SERIAL Serial
/*!
* @brief Create an SPI device with the given CS pin and settings
* @param cspin The arduino pin number to use for chip select
* @param freq The SPI clock frequency to use, defaults to 1MHz
* @param dataOrder The SPI data order to use for bits within each byte,
* defaults to SPI_BITORDER_MSBFIRST
* @param dataMode The SPI mode to use, defaults to SPI_MODE0
* @param theSPI The SPI bus to use, defaults to &theSPI
*/
Adafruit_SPIDevice::Adafruit_SPIDevice(int8_t cspin, uint32_t freq,
BusIOBitOrder dataOrder,
uint8_t dataMode, SPIClass *theSPI) {
#ifdef BUSIO_HAS_HW_SPI
_cs = cspin;
_sck = _mosi = _miso = -1;
_spi = theSPI;
_begun = false;
_spiSetting = new SPISettings(freq, dataOrder, dataMode);
_freq = freq;
_dataOrder = dataOrder;
_dataMode = dataMode;
#else
// unused, but needed to suppress compiler warns
(void)cspin;
(void)freq;
(void)dataOrder;
(void)dataMode;
(void)theSPI;
#endif
}
/*!
* @brief Create an SPI device with the given CS pin and settings
* @param cspin The arduino pin number to use for chip select
* @param sckpin The arduino pin number to use for SCK
* @param misopin The arduino pin number to use for MISO, set to -1 if not
* used
* @param mosipin The arduino pin number to use for MOSI, set to -1 if not
* used
* @param freq The SPI clock frequency to use, defaults to 1MHz
* @param dataOrder The SPI data order to use for bits within each byte,
* defaults to SPI_BITORDER_MSBFIRST
* @param dataMode The SPI mode to use, defaults to SPI_MODE0
*/
Adafruit_SPIDevice::Adafruit_SPIDevice(int8_t cspin, int8_t sckpin,
int8_t misopin, int8_t mosipin,
uint32_t freq, BusIOBitOrder dataOrder,
uint8_t dataMode) {
_cs = cspin;
_sck = sckpin;
_miso = misopin;
_mosi = mosipin;
#ifdef BUSIO_USE_FAST_PINIO
csPort = (BusIO_PortReg *)portOutputRegister(digitalPinToPort(cspin));
csPinMask = digitalPinToBitMask(cspin);
if (mosipin != -1) {
mosiPort = (BusIO_PortReg *)portOutputRegister(digitalPinToPort(mosipin));
mosiPinMask = digitalPinToBitMask(mosipin);
}
if (misopin != -1) {
misoPort = (BusIO_PortReg *)portInputRegister(digitalPinToPort(misopin));
misoPinMask = digitalPinToBitMask(misopin);
}
clkPort = (BusIO_PortReg *)portOutputRegister(digitalPinToPort(sckpin));
clkPinMask = digitalPinToBitMask(sckpin);
#endif
_freq = freq;
_dataOrder = dataOrder;
_dataMode = dataMode;
_begun = false;
}
/*!
* @brief Release memory allocated in constructors
*/
Adafruit_SPIDevice::~Adafruit_SPIDevice() {
if (_spiSetting)
delete _spiSetting;
}
/*!
* @brief Initializes SPI bus and sets CS pin high
* @return Always returns true because there's no way to test success of SPI
* init
*/
bool Adafruit_SPIDevice::begin(void) {
if (_cs != -1) {
pinMode(_cs, OUTPUT);
digitalWrite(_cs, HIGH);
}
if (_spi) { // hardware SPI
#ifdef BUSIO_HAS_HW_SPI
_spi->begin();
#endif
} else {
pinMode(_sck, OUTPUT);
if ((_dataMode == SPI_MODE0) || (_dataMode == SPI_MODE1)) {
// idle low on mode 0 and 1
digitalWrite(_sck, LOW);
} else {
// idle high on mode 2 or 3
digitalWrite(_sck, HIGH);
}
if (_mosi != -1) {
pinMode(_mosi, OUTPUT);
digitalWrite(_mosi, HIGH);
}
if (_miso != -1) {
pinMode(_miso, INPUT);
}
}
_begun = true;
return true;
}
/*!
* @brief Transfer (send/receive) a buffer over hard/soft SPI, without
* transaction management
* @param buffer The buffer to send and receive at the same time
* @param len The number of bytes to transfer
*/
void Adafruit_SPIDevice::transfer(uint8_t *buffer, size_t len) {
//
// HARDWARE SPI
//
if (_spi) {
#ifdef BUSIO_HAS_HW_SPI
#if defined(SPARK)
_spi->transfer(buffer, buffer, len, nullptr);
#elif defined(STM32)
for (size_t i = 0; i < len; i++) {
_spi->transfer(buffer[i]);
}
#else
_spi->transfer(buffer, len);
#endif
return;
#endif
}
//
// SOFTWARE SPI
//
uint8_t startbit;
if (_dataOrder == SPI_BITORDER_LSBFIRST) {
startbit = 0x1;
} else {
startbit = 0x80;
}
bool towrite, lastmosi = !(buffer[0] & startbit);
uint8_t bitdelay_us = (1000000 / _freq) / 2;
for (size_t i = 0; i < len; i++) {
uint8_t reply = 0;
uint8_t send = buffer[i];
/*
Serial.print("\tSending software SPI byte 0x");
Serial.print(send, HEX);
Serial.print(" -> 0x");
*/
// Serial.print(send, HEX);
for (uint8_t b = startbit; b != 0;
b = (_dataOrder == SPI_BITORDER_LSBFIRST) ? b << 1 : b >> 1) {
if (bitdelay_us) {
delayMicroseconds(bitdelay_us);
}
if (_dataMode == SPI_MODE0 || _dataMode == SPI_MODE2) {
towrite = send & b;
if ((_mosi != -1) && (lastmosi != towrite)) {
#ifdef BUSIO_USE_FAST_PINIO
if (towrite)
*mosiPort = *mosiPort | mosiPinMask;
else
*mosiPort = *mosiPort & ~mosiPinMask;
#else
digitalWrite(_mosi, towrite);
#endif
lastmosi = towrite;
}
#ifdef BUSIO_USE_FAST_PINIO
*clkPort = *clkPort | clkPinMask; // Clock high
#else
digitalWrite(_sck, HIGH);
#endif
if (bitdelay_us) {
delayMicroseconds(bitdelay_us);
}
if (_miso != -1) {
#ifdef BUSIO_USE_FAST_PINIO
if (*misoPort & misoPinMask) {
#else
if (digitalRead(_miso)) {
#endif
reply |= b;
}
}
#ifdef BUSIO_USE_FAST_PINIO
*clkPort = *clkPort & ~clkPinMask; // Clock low
#else
digitalWrite(_sck, LOW);
#endif
} else { // if (_dataMode == SPI_MODE1 || _dataMode == SPI_MODE3)
#ifdef BUSIO_USE_FAST_PINIO
*clkPort = *clkPort | clkPinMask; // Clock high
#else
digitalWrite(_sck, HIGH);
#endif
if (bitdelay_us) {
delayMicroseconds(bitdelay_us);
}
if (_mosi != -1) {
#ifdef BUSIO_USE_FAST_PINIO
if (send & b)
*mosiPort = *mosiPort | mosiPinMask;
else
*mosiPort = *mosiPort & ~mosiPinMask;
#else
digitalWrite(_mosi, send & b);
#endif
}
#ifdef BUSIO_USE_FAST_PINIO
*clkPort = *clkPort & ~clkPinMask; // Clock low
#else
digitalWrite(_sck, LOW);
#endif
if (_miso != -1) {
#ifdef BUSIO_USE_FAST_PINIO
if (*misoPort & misoPinMask) {
#else
if (digitalRead(_miso)) {
#endif
reply |= b;
}
}
}
if (_miso != -1) {
buffer[i] = reply;
}
}
}
return;
}
/*!
* @brief Transfer (send/receive) one byte over hard/soft SPI, without
* transaction management
* @param send The byte to send
* @return The byte received while transmitting
*/
uint8_t Adafruit_SPIDevice::transfer(uint8_t send) {
uint8_t data = send;
transfer(&data, 1);
return data;
}
/*!
* @brief Manually begin a transaction (calls beginTransaction if hardware
* SPI)
*/
void Adafruit_SPIDevice::beginTransaction(void) {
if (_spi) {
#ifdef BUSIO_HAS_HW_SPI
_spi->beginTransaction(*_spiSetting);
#endif
}
}
/*!
* @brief Manually end a transaction (calls endTransaction if hardware SPI)
*/
void Adafruit_SPIDevice::endTransaction(void) {
if (_spi) {
#ifdef BUSIO_HAS_HW_SPI
_spi->endTransaction();
#endif
}
}
/*!
* @brief Assert/Deassert the CS pin if it is defined
* @param value The state the CS is set to
*/
void Adafruit_SPIDevice::setChipSelect(int value) {
if (_cs != -1) {
digitalWrite(_cs, value);
}
}
/*!
* @brief Write a buffer or two to the SPI device, with transaction
* management.
* @brief Manually begin a transaction (calls beginTransaction if hardware
* SPI) with asserting the CS pin
*/
void Adafruit_SPIDevice::beginTransactionWithAssertingCS() {
beginTransaction();
setChipSelect(LOW);
}
/*!
* @brief Manually end a transaction (calls endTransaction if hardware SPI)
* with deasserting the CS pin
*/
void Adafruit_SPIDevice::endTransactionWithDeassertingCS() {
setChipSelect(HIGH);
endTransaction();
}
/*!
* @brief Write a buffer or two to the SPI device, with transaction
* management.
* @param buffer Pointer to buffer of data to write
* @param len Number of bytes from buffer to write
* @param prefix_buffer Pointer to optional array of data to write before
* buffer.
* @param prefix_len Number of bytes from prefix buffer to write
* @return Always returns true because there's no way to test success of SPI
* writes
*/
bool Adafruit_SPIDevice::write(const uint8_t *buffer, size_t len,
const uint8_t *prefix_buffer,
size_t prefix_len) {
beginTransactionWithAssertingCS();
// do the writing
#if defined(ARDUINO_ARCH_ESP32)
if (_spi) {
if (prefix_len > 0) {
_spi->transferBytes((uint8_t *)prefix_buffer, nullptr, prefix_len);
}
if (len > 0) {
_spi->transferBytes((uint8_t *)buffer, nullptr, len);
}
} else
#endif
{
for (size_t i = 0; i < prefix_len; i++) {
transfer(prefix_buffer[i]);
}
for (size_t i = 0; i < len; i++) {
transfer(buffer[i]);
}
}
endTransactionWithDeassertingCS();
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.print(F("\tSPIDevice Wrote: "));
if ((prefix_len != 0) && (prefix_buffer != nullptr)) {
for (uint16_t i = 0; i < prefix_len; i++) {
DEBUG_SERIAL.print(F("0x"));
DEBUG_SERIAL.print(prefix_buffer[i], HEX);
DEBUG_SERIAL.print(F(", "));
}
}
for (uint16_t i = 0; i < len; i++) {
DEBUG_SERIAL.print(F("0x"));
DEBUG_SERIAL.print(buffer[i], HEX);
DEBUG_SERIAL.print(F(", "));
if (i % 32 == 31) {
DEBUG_SERIAL.println();
}
}
DEBUG_SERIAL.println();
#endif
return true;
}
/*!
* @brief Read from SPI into a buffer from the SPI device, with transaction
* management.
* @param buffer Pointer to buffer of data to read into
* @param len Number of bytes from buffer to read.
* @param sendvalue The 8-bits of data to write when doing the data read,
* defaults to 0xFF
* @return Always returns true because there's no way to test success of SPI
* writes
*/
bool Adafruit_SPIDevice::read(uint8_t *buffer, size_t len, uint8_t sendvalue) {
memset(buffer, sendvalue, len); // clear out existing buffer
beginTransactionWithAssertingCS();
transfer(buffer, len);
endTransactionWithDeassertingCS();
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.print(F("\tSPIDevice Read: "));
for (uint16_t i = 0; i < len; i++) {
DEBUG_SERIAL.print(F("0x"));
DEBUG_SERIAL.print(buffer[i], HEX);
DEBUG_SERIAL.print(F(", "));
if (len % 32 == 31) {
DEBUG_SERIAL.println();
}
}
DEBUG_SERIAL.println();
#endif
return true;
}
/*!
* @brief Write some data, then read some data from SPI into another buffer,
* with transaction management. The buffers can point to same/overlapping
* locations. This does not transmit-receive at the same time!
* @param write_buffer Pointer to buffer of data to write from
* @param write_len Number of bytes from buffer to write.
* @param read_buffer Pointer to buffer of data to read into.
* @param read_len Number of bytes from buffer to read.
* @param sendvalue The 8-bits of data to write when doing the data read,
* defaults to 0xFF
* @return Always returns true because there's no way to test success of SPI
* writes
*/
bool Adafruit_SPIDevice::write_then_read(const uint8_t *write_buffer,
size_t write_len, uint8_t *read_buffer,
size_t read_len, uint8_t sendvalue) {
beginTransactionWithAssertingCS();
// do the writing
#if defined(ARDUINO_ARCH_ESP32)
if (_spi) {
if (write_len > 0) {
_spi->transferBytes((uint8_t *)write_buffer, nullptr, write_len);
}
} else
#endif
{
for (size_t i = 0; i < write_len; i++) {
transfer(write_buffer[i]);
}
}
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.print(F("\tSPIDevice Wrote: "));
for (uint16_t i = 0; i < write_len; i++) {
DEBUG_SERIAL.print(F("0x"));
DEBUG_SERIAL.print(write_buffer[i], HEX);
DEBUG_SERIAL.print(F(", "));
if (write_len % 32 == 31) {
DEBUG_SERIAL.println();
}
}
DEBUG_SERIAL.println();
#endif
// do the reading
for (size_t i = 0; i < read_len; i++) {
read_buffer[i] = transfer(sendvalue);
}
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.print(F("\tSPIDevice Read: "));
for (uint16_t i = 0; i < read_len; i++) {
DEBUG_SERIAL.print(F("0x"));
DEBUG_SERIAL.print(read_buffer[i], HEX);
DEBUG_SERIAL.print(F(", "));
if (read_len % 32 == 31) {
DEBUG_SERIAL.println();
}
}
DEBUG_SERIAL.println();
#endif
endTransactionWithDeassertingCS();
return true;
}
/*!
* @brief Write some data and read some data at the same time from SPI
* into the same buffer, with transaction management. This is basicaly a wrapper
* for transfer() with CS-pin and transaction management. This /does/
* transmit-receive at the same time!
* @param buffer Pointer to buffer of data to write/read to/from
* @param len Number of bytes from buffer to write/read.
* @return Always returns true because there's no way to test success of SPI
* writes
*/
bool Adafruit_SPIDevice::write_and_read(uint8_t *buffer, size_t len) {
beginTransactionWithAssertingCS();
transfer(buffer, len);
endTransactionWithDeassertingCS();
return true;
}

View File

@ -1,143 +0,0 @@
#ifndef Adafruit_SPIDevice_h
#define Adafruit_SPIDevice_h
#include <Arduino.h>
#if !defined(SPI_INTERFACES_COUNT) || \
(defined(SPI_INTERFACES_COUNT) && (SPI_INTERFACES_COUNT > 0))
// HW SPI available
#include <SPI.h>
#define BUSIO_HAS_HW_SPI
#else
// SW SPI ONLY
enum { SPI_MODE0, SPI_MODE1, SPI_MODE2, _SPI_MODE4 };
typedef uint8_t SPIClass;
#endif
// some modern SPI definitions don't have BitOrder enum
#if (defined(__AVR__) && !defined(ARDUINO_ARCH_MEGAAVR)) || \
defined(ESP8266) || defined(TEENSYDUINO) || defined(SPARK) || \
defined(ARDUINO_ARCH_SPRESENSE) || defined(MEGATINYCORE) || \
defined(DXCORE) || defined(ARDUINO_AVR_ATmega4809) || \
defined(ARDUINO_AVR_ATmega4808) || defined(ARDUINO_AVR_ATmega3209) || \
defined(ARDUINO_AVR_ATmega3208) || defined(ARDUINO_AVR_ATmega1609) || \
defined(ARDUINO_AVR_ATmega1608) || defined(ARDUINO_AVR_ATmega809) || \
defined(ARDUINO_AVR_ATmega808) || defined(ARDUINO_ARCH_ARC32) || \
defined(ARDUINO_ARCH_XMC) || defined(ARDUINO_SILABS)
typedef enum _BitOrder {
SPI_BITORDER_MSBFIRST = MSBFIRST,
SPI_BITORDER_LSBFIRST = LSBFIRST,
} BusIOBitOrder;
#elif defined(ESP32) || defined(__ASR6501__) || defined(__ASR6502__)
// some modern SPI definitions don't have BitOrder enum and have different SPI
// mode defines
typedef enum _BitOrder {
SPI_BITORDER_MSBFIRST = SPI_MSBFIRST,
SPI_BITORDER_LSBFIRST = SPI_LSBFIRST,
} BusIOBitOrder;
#else
// Some platforms have a BitOrder enum but its named MSBFIRST/LSBFIRST
#define SPI_BITORDER_MSBFIRST MSBFIRST
#define SPI_BITORDER_LSBFIRST LSBFIRST
typedef BitOrder BusIOBitOrder;
#endif
#if defined(__IMXRT1062__) // Teensy 4.x
// *Warning* I disabled the usage of FAST_PINIO as the set/clear operations
// used in the cpp file are not atomic and can effect multiple IO pins
// and if an interrupt happens in between the time the code reads the register
// and writes out the updated value, that changes one or more other IO pins
// on that same IO port, those change will be clobbered when the updated
// values are written back. A fast version can be implemented that uses the
// ports set and clear registers which are atomic.
// typedef volatile uint32_t BusIO_PortReg;
// typedef uint32_t BusIO_PortMask;
//#define BUSIO_USE_FAST_PINIO
#elif defined(ARDUINO_ARCH_XMC)
#undef BUSIO_USE_FAST_PINIO
#elif defined(__AVR__) || defined(TEENSYDUINO)
typedef volatile uint8_t BusIO_PortReg;
typedef uint8_t BusIO_PortMask;
#define BUSIO_USE_FAST_PINIO
#elif defined(ESP8266) || defined(ESP32) || defined(__SAM3X8E__) || \
defined(ARDUINO_ARCH_SAMD)
typedef volatile uint32_t BusIO_PortReg;
typedef uint32_t BusIO_PortMask;
#define BUSIO_USE_FAST_PINIO
#elif (defined(__arm__) || defined(ARDUINO_FEATHER52)) && \
!defined(ARDUINO_ARCH_MBED) && !defined(ARDUINO_ARCH_RP2040) && \
!defined(ARDUINO_SILABS)
typedef volatile uint32_t BusIO_PortReg;
typedef uint32_t BusIO_PortMask;
#if !defined(__ASR6501__) && !defined(__ASR6502__)
#define BUSIO_USE_FAST_PINIO
#endif
#else
#undef BUSIO_USE_FAST_PINIO
#endif
/**! The class which defines how we will talk to this device over SPI **/
class Adafruit_SPIDevice {
public:
#ifdef BUSIO_HAS_HW_SPI
Adafruit_SPIDevice(int8_t cspin, uint32_t freq = 1000000,
BusIOBitOrder dataOrder = SPI_BITORDER_MSBFIRST,
uint8_t dataMode = SPI_MODE0, SPIClass *theSPI = &SPI);
#else
Adafruit_SPIDevice(int8_t cspin, uint32_t freq = 1000000,
BusIOBitOrder dataOrder = SPI_BITORDER_MSBFIRST,
uint8_t dataMode = SPI_MODE0, SPIClass *theSPI = nullptr);
#endif
Adafruit_SPIDevice(int8_t cspin, int8_t sck, int8_t miso, int8_t mosi,
uint32_t freq = 1000000,
BusIOBitOrder dataOrder = SPI_BITORDER_MSBFIRST,
uint8_t dataMode = SPI_MODE0);
~Adafruit_SPIDevice();
bool begin(void);
bool read(uint8_t *buffer, size_t len, uint8_t sendvalue = 0xFF);
bool write(const uint8_t *buffer, size_t len,
const uint8_t *prefix_buffer = nullptr, size_t prefix_len = 0);
bool write_then_read(const uint8_t *write_buffer, size_t write_len,
uint8_t *read_buffer, size_t read_len,
uint8_t sendvalue = 0xFF);
bool write_and_read(uint8_t *buffer, size_t len);
uint8_t transfer(uint8_t send);
void transfer(uint8_t *buffer, size_t len);
void beginTransaction(void);
void endTransaction(void);
void beginTransactionWithAssertingCS();
void endTransactionWithDeassertingCS();
private:
#ifdef BUSIO_HAS_HW_SPI
SPIClass *_spi = nullptr;
SPISettings *_spiSetting = nullptr;
#else
uint8_t *_spi = nullptr;
uint8_t *_spiSetting = nullptr;
#endif
uint32_t _freq;
BusIOBitOrder _dataOrder;
uint8_t _dataMode;
void setChipSelect(int value);
int8_t _cs, _sck, _mosi, _miso;
#ifdef BUSIO_USE_FAST_PINIO
BusIO_PortReg *mosiPort, *clkPort, *misoPort, *csPort;
BusIO_PortMask mosiPinMask, misoPinMask, clkPinMask, csPinMask;
#endif
bool _begun;
};
#endif // Adafruit_SPIDevice_h

View File

@ -1,11 +0,0 @@
# Adafruit Bus IO Library
# https://github.com/adafruit/Adafruit_BusIO
# MIT License
cmake_minimum_required(VERSION 3.5)
idf_component_register(SRCS "Adafruit_I2CDevice.cpp" "Adafruit_BusIO_Register.cpp" "Adafruit_SPIDevice.cpp"
INCLUDE_DIRS "."
REQUIRES arduino)
project(Adafruit_BusIO)

View File

@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2017 Adafruit Industries
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.

View File

@ -1,8 +0,0 @@
# Adafruit Bus IO Library [![Build Status](https://github.com/adafruit/Adafruit_BusIO/workflows/Arduino%20Library%20CI/badge.svg)](https://github.com/adafruit/Adafruit_BusIO/actions)
This is a helper library to abstract away I2C & SPI transactions and registers
Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit!
MIT license, all text above must be included in any redistribution

View File

@ -1 +0,0 @@
COMPONENT_ADD_INCLUDEDIRS = .

View File

@ -1,21 +0,0 @@
#include <Adafruit_I2CDevice.h>
Adafruit_I2CDevice i2c_dev = Adafruit_I2CDevice(0x10);
void setup() {
while (!Serial) { delay(10); }
Serial.begin(115200);
Serial.println("I2C address detection test");
if (!i2c_dev.begin()) {
Serial.print("Did not find device at 0x");
Serial.println(i2c_dev.address(), HEX);
while (1);
}
Serial.print("Device found on address 0x");
Serial.println(i2c_dev.address(), HEX);
}
void loop() {
}

View File

@ -1,41 +0,0 @@
#include <Adafruit_I2CDevice.h>
#define I2C_ADDRESS 0x60
Adafruit_I2CDevice i2c_dev = Adafruit_I2CDevice(I2C_ADDRESS);
void setup() {
while (!Serial) { delay(10); }
Serial.begin(115200);
Serial.println("I2C device read and write test");
if (!i2c_dev.begin()) {
Serial.print("Did not find device at 0x");
Serial.println(i2c_dev.address(), HEX);
while (1);
}
Serial.print("Device found on address 0x");
Serial.println(i2c_dev.address(), HEX);
uint8_t buffer[32];
// Try to read 32 bytes
i2c_dev.read(buffer, 32);
Serial.print("Read: ");
for (uint8_t i=0; i<32; i++) {
Serial.print("0x"); Serial.print(buffer[i], HEX); Serial.print(", ");
}
Serial.println();
// read a register by writing first, then reading
buffer[0] = 0x0C; // we'll reuse the same buffer
i2c_dev.write_then_read(buffer, 1, buffer, 2, false);
Serial.print("Write then Read: ");
for (uint8_t i=0; i<2; i++) {
Serial.print("0x"); Serial.print(buffer[i], HEX); Serial.print(", ");
}
Serial.println();
}
void loop() {
}

View File

@ -1,38 +0,0 @@
#include <Adafruit_I2CDevice.h>
#include <Adafruit_BusIO_Register.h>
#define I2C_ADDRESS 0x60
Adafruit_I2CDevice i2c_dev = Adafruit_I2CDevice(I2C_ADDRESS);
void setup() {
while (!Serial) { delay(10); }
Serial.begin(115200);
Serial.println("I2C device register test");
if (!i2c_dev.begin()) {
Serial.print("Did not find device at 0x");
Serial.println(i2c_dev.address(), HEX);
while (1);
}
Serial.print("Device found on address 0x");
Serial.println(i2c_dev.address(), HEX);
Adafruit_BusIO_Register id_reg = Adafruit_BusIO_Register(&i2c_dev, 0x0C, 2, LSBFIRST);
uint16_t id;
id_reg.read(&id);
Serial.print("ID register = 0x"); Serial.println(id, HEX);
Adafruit_BusIO_Register thresh_reg = Adafruit_BusIO_Register(&i2c_dev, 0x01, 2, LSBFIRST);
uint16_t thresh;
thresh_reg.read(&thresh);
Serial.print("Initial threshold register = 0x"); Serial.println(thresh, HEX);
thresh_reg.write(~thresh);
Serial.print("Post threshold register = 0x"); Serial.println(thresh_reg.read(), HEX);
}
void loop() {
}

View File

@ -1,38 +0,0 @@
#include <Adafruit_BusIO_Register.h>
// Define which interface to use by setting the unused interface to NULL!
#define SPIDEVICE_CS 10
Adafruit_SPIDevice *spi_dev = NULL; // new Adafruit_SPIDevice(SPIDEVICE_CS);
#define I2C_ADDRESS 0x5D
Adafruit_I2CDevice *i2c_dev = new Adafruit_I2CDevice(I2C_ADDRESS);
void setup() {
while (!Serial) { delay(10); }
Serial.begin(115200);
Serial.println("I2C or SPI device register test");
if (spi_dev && !spi_dev->begin()) {
Serial.println("Could not initialize SPI device");
}
if (i2c_dev) {
if (i2c_dev->begin()) {
Serial.print("Device found on I2C address 0x");
Serial.println(i2c_dev->address(), HEX);
} else {
Serial.print("Did not find I2C device at 0x");
Serial.println(i2c_dev->address(), HEX);
}
}
Adafruit_BusIO_Register id_reg = Adafruit_BusIO_Register(i2c_dev, spi_dev, ADDRBIT8_HIGH_TOREAD, 0x0F);
uint8_t id=0;
id_reg.read(&id);
Serial.print("ID register = 0x"); Serial.println(id, HEX);
}
void loop() {
}

View File

@ -1,29 +0,0 @@
#include <Adafruit_SPIDevice.h>
#define SPIDEVICE_CS 10
Adafruit_SPIDevice spi_dev = Adafruit_SPIDevice(SPIDEVICE_CS, 100000, SPI_BITORDER_MSBFIRST, SPI_MODE1);
//Adafruit_SPIDevice spi_dev = Adafruit_SPIDevice(SPIDEVICE_CS, 13, 12, 11, 100000, SPI_BITORDER_MSBFIRST, SPI_MODE1);
void setup() {
while (!Serial) { delay(10); }
Serial.begin(115200);
Serial.println("SPI device mode test");
if (!spi_dev.begin()) {
Serial.println("Could not initialize SPI device");
while (1);
}
}
void loop() {
Serial.println("\n\nTransfer test");
for (uint16_t x=0; x<=0xFF; x++) {
uint8_t i = x;
Serial.print("0x"); Serial.print(i, HEX);
spi_dev.read(&i, 1, i);
Serial.print("/"); Serial.print(i, HEX);
Serial.print(", ");
delay(25);
}
}

View File

@ -1,39 +0,0 @@
#include <Adafruit_SPIDevice.h>
#define SPIDEVICE_CS 10
Adafruit_SPIDevice spi_dev = Adafruit_SPIDevice(SPIDEVICE_CS);
void setup() {
while (!Serial) { delay(10); }
Serial.begin(115200);
Serial.println("SPI device read and write test");
if (!spi_dev.begin()) {
Serial.println("Could not initialize SPI device");
while (1);
}
uint8_t buffer[32];
// Try to read 32 bytes
spi_dev.read(buffer, 32);
Serial.print("Read: ");
for (uint8_t i=0; i<32; i++) {
Serial.print("0x"); Serial.print(buffer[i], HEX); Serial.print(", ");
}
Serial.println();
// read a register by writing first, then reading
buffer[0] = 0x8F; // we'll reuse the same buffer
spi_dev.write_then_read(buffer, 1, buffer, 2, false);
Serial.print("Write then Read: ");
for (uint8_t i=0; i<2; i++) {
Serial.print("0x"); Serial.print(buffer[i], HEX); Serial.print(", ");
}
Serial.println();
}
void loop() {
}

View File

@ -1,192 +0,0 @@
/***************************************************
This is an example for how to use Adafruit_BusIO_RegisterBits from Adafruit_BusIO library.
Designed specifically to work with the Adafruit RTD Sensor
----> https://www.adafruit.com/products/3328
uisng a MAX31865 RTD-to-Digital Converter
----> https://datasheets.maximintegrated.com/en/ds/MAX31865.pdf
This sensor uses SPI to communicate, 4 pins are required to
interface.
A fifth pin helps to detect when a new conversion is ready.
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Example written (2020/3) by Andreas Hardtung/AnHard.
BSD license, all text above must be included in any redistribution
****************************************************/
#include <Adafruit_BusIO_Register.h>
#include <Adafruit_SPIDevice.h>
#define MAX31865_SPI_SPEED (5000000)
#define MAX31865_SPI_BITORDER (SPI_BITORDER_MSBFIRST)
#define MAX31865_SPI_MODE (SPI_MODE1)
#define MAX31865_SPI_CS (10)
#define MAX31865_READY_PIN (2)
Adafruit_SPIDevice spi_dev = Adafruit_SPIDevice( MAX31865_SPI_CS, MAX31865_SPI_SPEED, MAX31865_SPI_BITORDER, MAX31865_SPI_MODE, &SPI); // Hardware SPI
// Adafruit_SPIDevice spi_dev = Adafruit_SPIDevice( MAX31865_SPI_CS, 13, 12, 11, MAX31865_SPI_SPEED, MAX31865_SPI_BITORDER, MAX31865_SPI_MODE); // Software SPI
// MAX31865 chip related *********************************************************************************************
Adafruit_BusIO_Register config_reg = Adafruit_BusIO_Register(&spi_dev, 0x00, ADDRBIT8_HIGH_TOWRITE, 1, MSBFIRST);
Adafruit_BusIO_RegisterBits bias_bit = Adafruit_BusIO_RegisterBits(&config_reg, 1, 7);
Adafruit_BusIO_RegisterBits auto_bit = Adafruit_BusIO_RegisterBits(&config_reg, 1, 6);
Adafruit_BusIO_RegisterBits oneS_bit = Adafruit_BusIO_RegisterBits(&config_reg, 1, 5);
Adafruit_BusIO_RegisterBits wire_bit = Adafruit_BusIO_RegisterBits(&config_reg, 1, 4);
Adafruit_BusIO_RegisterBits faultT_bits = Adafruit_BusIO_RegisterBits(&config_reg, 2, 2);
Adafruit_BusIO_RegisterBits faultR_bit = Adafruit_BusIO_RegisterBits(&config_reg, 1, 1);
Adafruit_BusIO_RegisterBits fi50hz_bit = Adafruit_BusIO_RegisterBits(&config_reg, 1, 0);
Adafruit_BusIO_Register rRatio_reg = Adafruit_BusIO_Register(&spi_dev, 0x01, ADDRBIT8_HIGH_TOWRITE, 2, MSBFIRST);
Adafruit_BusIO_RegisterBits rRatio_bits = Adafruit_BusIO_RegisterBits(&rRatio_reg, 15, 1);
Adafruit_BusIO_RegisterBits fault_bit = Adafruit_BusIO_RegisterBits(&rRatio_reg, 1, 0);
Adafruit_BusIO_Register maxRratio_reg = Adafruit_BusIO_Register(&spi_dev, 0x03, ADDRBIT8_HIGH_TOWRITE, 2, MSBFIRST);
Adafruit_BusIO_RegisterBits maxRratio_bits = Adafruit_BusIO_RegisterBits(&maxRratio_reg, 15, 1);
Adafruit_BusIO_Register minRratio_reg = Adafruit_BusIO_Register(&spi_dev, 0x05, ADDRBIT8_HIGH_TOWRITE, 2, MSBFIRST);
Adafruit_BusIO_RegisterBits minRratio_bits = Adafruit_BusIO_RegisterBits(&minRratio_reg, 15, 1);
Adafruit_BusIO_Register fault_reg = Adafruit_BusIO_Register(&spi_dev, 0x07, ADDRBIT8_HIGH_TOWRITE, 1, MSBFIRST);
Adafruit_BusIO_RegisterBits range_high_fault_bit = Adafruit_BusIO_RegisterBits(&fault_reg, 1, 7);
Adafruit_BusIO_RegisterBits range_low_fault_bit = Adafruit_BusIO_RegisterBits(&fault_reg, 1, 6);
Adafruit_BusIO_RegisterBits refin_high_fault_bit = Adafruit_BusIO_RegisterBits(&fault_reg, 1, 5);
Adafruit_BusIO_RegisterBits refin_low_fault_bit = Adafruit_BusIO_RegisterBits(&fault_reg, 1, 4);
Adafruit_BusIO_RegisterBits rtdin_low_fault_bit = Adafruit_BusIO_RegisterBits(&fault_reg, 1, 3);
Adafruit_BusIO_RegisterBits voltage_fault_bit = Adafruit_BusIO_RegisterBits(&fault_reg, 1, 2);
// Print the details of the configuration register.
void printConfig( void ) {
Serial.print("BIAS: "); if (bias_bit.read() ) Serial.print("ON"); else Serial.print("OFF");
Serial.print(", AUTO: "); if (auto_bit.read() ) Serial.print("ON"); else Serial.print("OFF");
Serial.print(", ONES: "); if (oneS_bit.read() ) Serial.print("ON"); else Serial.print("OFF");
Serial.print(", WIRE: "); if (wire_bit.read() ) Serial.print("3"); else Serial.print("2/4");
Serial.print(", FAULTCLEAR: "); if (faultR_bit.read() ) Serial.print("ON"); else Serial.print("OFF");
Serial.print(", "); if (fi50hz_bit.read() ) Serial.print("50HZ"); else Serial.print("60HZ");
Serial.println();
}
// Check and print faults. Then clear them.
void checkFaults( void ) {
if (fault_bit.read()) {
Serial.print("MAX: "); Serial.println(maxRratio_bits.read());
Serial.print("VAL: "); Serial.println( rRatio_bits.read());
Serial.print("MIN: "); Serial.println(minRratio_bits.read());
if (range_high_fault_bit.read() ) Serial.println("Range high fault");
if ( range_low_fault_bit.read() ) Serial.println("Range low fault");
if (refin_high_fault_bit.read() ) Serial.println("REFIN high fault");
if ( refin_low_fault_bit.read() ) Serial.println("REFIN low fault");
if ( rtdin_low_fault_bit.read() ) Serial.println("RTDIN low fault");
if ( voltage_fault_bit.read() ) Serial.println("Voltage fault");
faultR_bit.write(1); // clear fault
}
}
void setup() {
#if (MAX31865_1_READY_PIN != -1)
pinMode(MAX31865_READY_PIN ,INPUT_PULLUP);
#endif
while (!Serial) { delay(10); }
Serial.begin(115200);
Serial.println("SPI Adafruit_BusIO_RegisterBits test on MAX31865");
if (!spi_dev.begin()) {
Serial.println("Could not initialize SPI device");
while (1);
}
// Set up for automode 50Hz. We don't care about selfheating. We want the highest possible sampling rate.
auto_bit.write(0); // Don't switch filtermode while auto_mode is on.
fi50hz_bit.write(1); // Set filter to 50Hz mode.
faultR_bit.write(1); // Clear faults.
bias_bit.write(1); // In automode we want to have the bias current always on.
delay(5); // Wait until bias current settles down.
// 10.5 time constants of the input RC network is required.
// 10ms worst case for 10kω reference resistor and a 0.1µF capacitor across the RTD inputs.
// Adafruit Module has 0.1µF and only 430/4300ω So here 0.43/4.3ms
auto_bit.write(1); // Now we can set automode. Automatically starting first conversion.
// Test the READY_PIN
#if (defined( MAX31865_READY_PIN ) && (MAX31865_READY_PIN != -1))
int i = 0;
while (digitalRead(MAX31865_READY_PIN) && i++ <= 100) { delay(1); }
if (i >= 100) {
Serial.print("ERROR: Max31865 Pin detection does not work. PIN:");
Serial.println(MAX31865_READY_PIN);
}
#else
delay(100);
#endif
// Set ratio range.
// Setting the temperatures would need some more calculation - not related to Adafruit_BusIO_RegisterBits.
uint16_t ratio = rRatio_bits.read();
maxRratio_bits.write( (ratio < 0x8fffu-1000u) ? ratio + 1000u : 0x8fffu );
minRratio_bits.write( (ratio > 1000u) ? ratio - 1000u : 0u );
printConfig();
checkFaults();
}
void loop() {
#if (defined( MAX31865_READY_PIN ) && (MAX31865_1_READY_PIN != -1))
// Is conversion ready?
if (!digitalRead(MAX31865_READY_PIN))
#else
// Warant conversion is ready.
delay(21); // 21ms for 50Hz-mode. 19ms in 60Hz-mode.
#endif
{
// Read ratio, calculate temperature, scale, filter and print.
Serial.println( rRatio2C( rRatio_bits.read() ) * 100.0f, 0); // Temperature scaled by 100
// Check, print, clear faults.
checkFaults();
}
// Do something else.
//delay(15000);
}
// Module/Sensor related. Here Adafruit PT100 module with a 2_Wire PT100 Class C *****************************
float rRatio2C(uint16_t ratio) {
// A simple linear conversion.
const float R0 = 100.0f;
const float Rref = 430.0f;
const float alphaPT = 0.003850f;
const float ADCmax = (1u << 15) - 1.0f;
const float rscale = Rref / ADCmax;
// Measured temperature in boiling water 101.08°C with factor a = 1 and b = 0. Rref and MAX at about 22±2°C.
// Measured temperature in ice/water bath 0.76°C with factor a = 1 and b = 0. Rref and MAX at about 22±2°C.
//const float a = 1.0f / (alphaPT * R0);
const float a = (100.0f/101.08f) / (alphaPT * R0);
//const float b = 0.0f; // 101.08
const float b = -0.76f; // 100.32 > 101.08
return filterRing( ((ratio * rscale) - R0) * a + b );
}
// General purpose *********************************************************************************************
#define RINGLENGTH 250
float filterRing( float newVal ) {
static float ring[RINGLENGTH] = { 0.0 };
static uint8_t ringIndex = 0;
static bool ringFull = false;
if ( ringIndex == RINGLENGTH ) { ringFull = true; ringIndex = 0; }
ring[ringIndex] = newVal;
uint8_t loopEnd = (ringFull) ? RINGLENGTH : ringIndex + 1;
float ringSum = 0.0f;
for (uint8_t i = 0; i < loopEnd; i++) ringSum += ring[i];
ringIndex++;
return ringSum / loopEnd;
}

View File

@ -1,34 +0,0 @@
#include <Adafruit_BusIO_Register.h>
#include <Adafruit_SPIDevice.h>
#define SPIDEVICE_CS 10
Adafruit_SPIDevice spi_dev = Adafruit_SPIDevice(SPIDEVICE_CS);
void setup() {
while (!Serial) { delay(10); }
Serial.begin(115200);
Serial.println("SPI device register test");
if (!spi_dev.begin()) {
Serial.println("Could not initialize SPI device");
while (1);
}
Adafruit_BusIO_Register id_reg = Adafruit_BusIO_Register(&spi_dev, 0x0F, ADDRBIT8_HIGH_TOREAD);
uint8_t id = 0;
id_reg.read(&id);
Serial.print("ID register = 0x"); Serial.println(id, HEX);
Adafruit_BusIO_Register thresh_reg = Adafruit_BusIO_Register(&spi_dev, 0x0C, ADDRBIT8_HIGH_TOREAD, 2, LSBFIRST);
uint16_t thresh = 0;
thresh_reg.read(&thresh);
Serial.print("Initial threshold register = 0x"); Serial.println(thresh, HEX);
thresh_reg.write(~thresh);
Serial.print("Post threshold register = 0x"); Serial.println(thresh_reg.read(), HEX);
}
void loop() {
}

View File

@ -1,9 +0,0 @@
name=Adafruit BusIO
version=1.15.0
author=Adafruit
maintainer=Adafruit <info@adafruit.com>
sentence=This is a library for abstracting away I2C and SPI interfacing
paragraph=This is a library for abstracting away I2C and SPI interfacing
category=Signal Input/Output
url=https://github.com/adafruit/Adafruit_BusIO
architectures=*

View File

@ -1,46 +0,0 @@
Thank you for opening an issue on an Adafruit Arduino library repository. To
improve the speed of resolution please review the following guidelines and
common troubleshooting steps below before creating the issue:
- **Do not use GitHub issues for troubleshooting projects and issues.** Instead use
the forums at http://forums.adafruit.com to ask questions and troubleshoot why
something isn't working as expected. In many cases the problem is a common issue
that you will more quickly receive help from the forum community. GitHub issues
are meant for known defects in the code. If you don't know if there is a defect
in the code then start with troubleshooting on the forum first.
- **If following a tutorial or guide be sure you didn't miss a step.** Carefully
check all of the steps and commands to run have been followed. Consult the
forum if you're unsure or have questions about steps in a guide/tutorial.
- **For Arduino projects check these very common issues to ensure they don't apply**:
- For uploading sketches or communicating with the board make sure you're using
a **USB data cable** and **not** a **USB charge-only cable**. It is sometimes
very hard to tell the difference between a data and charge cable! Try using the
cable with other devices or swapping to another cable to confirm it is not
the problem.
- **Be sure you are supplying adequate power to the board.** Check the specs of
your board and plug in an external power supply. In many cases just
plugging a board into your computer is not enough to power it and other
peripherals.
- **Double check all soldering joints and connections.** Flakey connections
cause many mysterious problems. See the [guide to excellent soldering](https://learn.adafruit.com/adafruit-guide-excellent-soldering/tools) for examples of good solder joints.
- **Ensure you are using an official Arduino or Adafruit board.** We can't
guarantee a clone board will have the same functionality and work as expected
with this code and don't support them.
If you're sure this issue is a defect in the code and checked the steps above
please fill in the following fields to provide enough troubleshooting information.
You may delete the guideline and text above to just leave the following details:
- Arduino board: **INSERT ARDUINO BOARD NAME/TYPE HERE**
- Arduino IDE version (found in Arduino -> About Arduino menu): **INSERT ARDUINO
VERSION HERE**
- List the steps to reproduce the problem below (if possible attach a sketch or
copy the sketch code in too): **LIST REPRO STEPS BELOW**

View File

@ -1,26 +0,0 @@
Thank you for creating a pull request to contribute to Adafruit's GitHub code!
Before you open the request please review the following guidelines and tips to
help it be more easily integrated:
- **Describe the scope of your change--i.e. what the change does and what parts
of the code were modified.** This will help us understand any risks of integrating
the code.
- **Describe any known limitations with your change.** For example if the change
doesn't apply to a supported platform of the library please mention it.
- **Please run any tests or examples that can exercise your modified code.** We
strive to not break users of the code and running tests/examples helps with this
process.
Thank you again for contributing! We will try to test and integrate the change
as soon as we can, but be aware we have many GitHub repositories to manage and
can't immediately respond to every request. There is no need to bump or check in
on a pull request (it will clutter the discussion of the request).
Also don't be worried if the request is closed or not integrated--sometimes the
priorities of Adafruit's GitHub code (education, ease of use) might not match the
priorities of the pull request. Don't fret, the open source community thrives on
forks and GitHub makes it easy to keep your changes in a forked repo.
After reviewing the guidelines above you can delete this text from the pull request.

View File

@ -1,32 +0,0 @@
name: Arduino Library CI
on: [pull_request, push, repository_dispatch]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/setup-python@v4
with:
python-version: '3.x'
- uses: actions/checkout@v3
- uses: actions/checkout@v3
with:
repository: adafruit/ci-arduino
path: ci
- name: pre-install
run: bash ci/actions_install.sh
- name: test platforms
run: python3 ci/build_platform.py main_platforms
- name: clang
run: python3 ci/run-clang-format.py -e "ci/*" -e "bin/*" -r .
- name: doxygen
env:
GH_REPO_TOKEN: ${{ secrets.GH_REPO_TOKEN }}
PRETTYNAME : "Adafruit MLX90614 Arduino Library"
run: bash ci/doxy_gen_and_deploy.sh

View File

@ -1 +0,0 @@
{"type": "library", "name": "Adafruit MLX90614 Library", "version": "2.1.5", "spec": {"owner": "adafruit", "id": 782, "name": "Adafruit MLX90614 Library", "requirements": null, "uri": null}}

View File

@ -1,175 +0,0 @@
/***************************************************
This is a library for the MLX90614 Temp Sensor
Designed specifically to work with the MLX90614 sensors in the
adafruit shop
----> https://www.adafruit.com/products/1747 (3V)
----> https://www.adafruit.com/products/1748 (5V)
These sensors use I2C to communicate, 2 pins are required to
interface
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, all text above must be included in any redistribution
****************************************************/
#include "Adafruit_MLX90614.h"
Adafruit_MLX90614::~Adafruit_MLX90614() {
if (i2c_dev)
delete i2c_dev;
}
/**
* @brief Begin the I2C connection
* @param addr I2C address for the device.
* @param wire Pointer to Wire instance
* @return True if the device was successfully initialized, otherwise false.
*/
bool Adafruit_MLX90614::begin(uint8_t addr, TwoWire *wire) {
_addr = addr; // needed for CRC
if (i2c_dev)
delete i2c_dev;
i2c_dev = new Adafruit_I2CDevice(addr, wire);
return i2c_dev->begin();
}
/**
* @brief Read the raw value from the emissivity register
*
* @return uint16_t The unscaled emissivity value or '0' if reading failed
*/
uint16_t Adafruit_MLX90614::readEmissivityReg(void) {
return read16(MLX90614_EMISS);
}
/**
* @brief Write the raw unscaled emissivity value to the emissivity register
*
* @param ereg The unscaled emissivity value
*/
void Adafruit_MLX90614::writeEmissivityReg(uint16_t ereg) {
write16(MLX90614_EMISS, 0); // erase
delay(10);
write16(MLX90614_EMISS, ereg);
delay(10);
}
/**
* @brief Read the emissivity value from the sensor's register and scale
*
* @return double The emissivity value, ranging from 0.1 - 1.0 or NAN if reading
* failed
*/
double Adafruit_MLX90614::readEmissivity(void) {
uint16_t ereg = read16(MLX90614_EMISS);
if (ereg == 0)
return NAN;
return ((double)ereg) / 65535.0;
}
/**
* @brief Set the emissivity value
*
* @param emissivity The emissivity value to use, between 0.1 and 1.0
*/
void Adafruit_MLX90614::writeEmissivity(double emissivity) {
uint16_t ereg = (uint16_t)(0xffff * emissivity);
writeEmissivityReg(ereg);
}
/**
* @brief Get the current temperature of an object in degrees Farenheit
*
* @return double The temperature in degrees Farenheit or NAN if reading failed
*/
double Adafruit_MLX90614::readObjectTempF(void) {
return (readTemp(MLX90614_TOBJ1) * 9 / 5) + 32;
}
/**
* @brief Get the current ambient temperature in degrees Farenheit
*
* @return double The temperature in degrees Farenheit or NAN if reading failed
*/
double Adafruit_MLX90614::readAmbientTempF(void) {
return (readTemp(MLX90614_TA) * 9 / 5) + 32;
}
/**
* @brief Get the current temperature of an object in degrees Celcius
*
* @return double The temperature in degrees Celcius or NAN if reading failed
*/
double Adafruit_MLX90614::readObjectTempC(void) {
return readTemp(MLX90614_TOBJ1);
}
/**
* @brief Get the current ambient temperature in degrees Celcius
*
* @return double The temperature in degrees Celcius or NAN if reading failed
*/
double Adafruit_MLX90614::readAmbientTempC(void) {
return readTemp(MLX90614_TA);
}
float Adafruit_MLX90614::readTemp(uint8_t reg) {
float temp;
temp = read16(reg);
if (temp == 0)
return NAN;
temp *= .02;
temp -= 273.15;
return temp;
}
/*********************************************************************/
uint16_t Adafruit_MLX90614::read16(uint8_t a) {
uint8_t buffer[3];
buffer[0] = a;
// read two bytes of data + pec
bool status = i2c_dev->write_then_read(buffer, 1, buffer, 3);
if (!status)
return 0;
// return data, ignore pec
return uint16_t(buffer[0]) | (uint16_t(buffer[1]) << 8);
}
byte Adafruit_MLX90614::crc8(byte *addr, byte len)
// The PEC calculation includes all bits except the START, REPEATED START, STOP,
// ACK, and NACK bits. The PEC is a CRC-8 with polynomial X8+X2+X1+1.
{
byte crc = 0;
while (len--) {
byte inbyte = *addr++;
for (byte i = 8; i; i--) {
byte carry = (crc ^ inbyte) & 0x80;
crc <<= 1;
if (carry)
crc ^= 0x7;
inbyte <<= 1;
}
}
return crc;
}
void Adafruit_MLX90614::write16(uint8_t a, uint16_t v) {
uint8_t buffer[4];
buffer[0] = _addr << 1;
buffer[1] = a;
buffer[2] = v & 0xff;
buffer[3] = v >> 8;
uint8_t pec = crc8(buffer, 4);
buffer[0] = buffer[1];
buffer[1] = buffer[2];
buffer[2] = buffer[3];
buffer[3] = pec;
i2c_dev->write(buffer, 4);
}

View File

@ -1,68 +0,0 @@
/***************************************************
This is a library for the MLX90614 Temp Sensor
Designed specifically to work with the MLX90614 sensors in the
adafruit shop
----> https://www.adafruit.com/products/1747 (3V)
----> https://www.adafruit.com/products/1748 (5V)
These sensors use I2C to communicate, 2 pins are required to
interface
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit in any redistribution
****************************************************/
#include <Adafruit_I2CDevice.h>
#include <Arduino.h>
#define MLX90614_I2CADDR 0x5A
// RAM
#define MLX90614_RAWIR1 0x04
#define MLX90614_RAWIR2 0x05
#define MLX90614_TA 0x06
#define MLX90614_TOBJ1 0x07
#define MLX90614_TOBJ2 0x08
// EEPROM
#define MLX90614_TOMAX 0x20
#define MLX90614_TOMIN 0x21
#define MLX90614_PWMCTRL 0x22
#define MLX90614_TARANGE 0x23
#define MLX90614_EMISS 0x24
#define MLX90614_CONFIG 0x25
#define MLX90614_ADDR 0x2E
#define MLX90614_ID1 0x3C
#define MLX90614_ID2 0x3D
#define MLX90614_ID3 0x3E
#define MLX90614_ID4 0x3F
/**
* @brief Class to read from and control a MLX90614 Temp Sensor
*
*/
class Adafruit_MLX90614 {
public:
~Adafruit_MLX90614();
bool begin(uint8_t addr = MLX90614_I2CADDR, TwoWire *wire = &Wire);
double readObjectTempC(void);
double readAmbientTempC(void);
double readObjectTempF(void);
double readAmbientTempF(void);
uint16_t readEmissivityReg(void);
void writeEmissivityReg(uint16_t ereg);
double readEmissivity(void);
void writeEmissivity(double emissivity);
private:
Adafruit_I2CDevice *i2c_dev = NULL; ///< Pointer to I2C bus interface
float readTemp(uint8_t reg);
uint16_t read16(uint8_t addr);
void write16(uint8_t addr, uint16_t data);
byte crc8(byte *addr, byte len);
uint8_t _addr;
};

View File

@ -1,51 +0,0 @@
# Adafruit-MLX90614-Library [![Build Status](https://github.com/adafruit/Adafruit-MLX90614-Library/workflows/Arduino%20Library%20CI/badge.svg)](https://github.com/adafruit/Adafruit-MLX90614-Library/actions)[![Documentation](https://github.com/adafruit/ci-arduino/blob/master/assets/doxygen_badge.svg)](http://adafruit.github.io/Adafruit-MLX90614-Library/html/index.html)
This is a library for the MLX90614 temperature sensor
<a href="https://www.adafruit.com/products/1747"><img src="https://cdn-shop.adafruit.com/970x728/1747-00.jpg" width="500px"></a>
Designed and tested to work with the MLX90614 sensors in the adafruit shop
* https://www.adafruit.com/products/1747 3V version
* https://www.adafruit.com/products/1748 5V version
Check out the links above for our tutorials and wiring diagrams
Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit!
# Installation
To install, use the Arduino Library Manager and search for "Adafruit-MLX90614-Library" and install the library.
# Contributing
Contributions are welcome! Please read our [Code of Conduct](https://github.com/adafruit/Adafruit-MLX90614-Library/blob/master/CODE_OF_CONDUCT.md>)
before contributing to help this project stay welcoming.
## Documentation and doxygen
Documentation is produced by doxygen. Contributions should include documentation for any new code added.
Some examples of how to use doxygen can be found in these guide pages:
https://learn.adafruit.com/the-well-automated-arduino-library/doxygen
https://learn.adafruit.com/the-well-automated-arduino-library/doxygen-tips
## Formatting and clang-format
This library uses [`clang-format`](https://releases.llvm.org/download.html) to standardize the formatting of `.cpp` and `.h` files.
Contributions should be formatted using `clang-format`:
The `-i` flag will make the changes to the file.
```bash
clang-format -i *.cpp *.h
```
If you prefer to make the changes yourself, running `clang-format` without the `-i` flag will print out a formatted version of the file. You can save this to a file and diff it against the original to see the changes.
Note that the formatting output by `clang-format` is what the automated formatting checker will expect. Any diffs from this formatting will result in a failed build until they are addressed. Using the `-i` flag is highly recommended.
### clang-format resources
* [Binary builds and source available on the LLVM downloads page](https://releases.llvm.org/download.html)
* [Documentation and IDE integration](https://clang.llvm.org/docs/ClangFormat.html)
## About this Driver
Written by Limor Fried for Adafruit Industries.
BSD license, check license.txt for more information
All text above must be included in any redistribution

View File

@ -1,127 +0,0 @@
# Adafruit Community Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and leaders pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level or type of
experience, education, socio-economic status, nationality, personal appearance,
race, religion, or sexual identity and orientation.
## Our Standards
We are committed to providing a friendly, safe and welcoming environment for
all.
Examples of behavior that contributes to creating a positive environment
include:
* Be kind and courteous to others
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Collaborating with other community members
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and sexual attention or advances
* The use of inappropriate images, including in a community member's avatar
* The use of inappropriate language, including in a community member's nickname
* Any spamming, flaming, baiting or other attention-stealing behavior
* Excessive or unwelcome helping; answering outside the scope of the question
asked
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate
The goal of the standards and moderation guidelines outlined here is to build
and maintain a respectful community. We ask that you dont just aim to be
"technically unimpeachable", but rather try to be your best self.
We value many things beyond technical expertise, including collaboration and
supporting others within our community. Providing a positive experience for
other community members can have a much more significant impact than simply
providing the correct answer.
## Our Responsibilities
Project leaders are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project leaders have the right and responsibility to remove, edit, or
reject messages, comments, commits, code, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any community member for other behaviors that they deem
inappropriate, threatening, offensive, or harmful.
## Moderation
Instances of behaviors that violate the Adafruit Community Code of Conduct
may be reported by any member of the community. Community members are
encouraged to report these situations, including situations they witness
involving other community members.
You may report in the following ways:
In any situation, you may send an email to <support@adafruit.com>.
On the Adafruit Discord, you may send an open message from any channel
to all Community Helpers by tagging @community helpers. You may also send an
open message from any channel, or a direct message to @kattni#1507,
@tannewt#4653, @Dan Halbert#1614, @cater#2442, @sommersoft#0222, or
@Andon#8175.
Email and direct message reports will be kept confidential.
In situations on Discord where the issue is particularly egregious, possibly
illegal, requires immediate action, or violates the Discord terms of service,
you should also report the message directly to Discord.
These are the steps for upholding our communitys standards of conduct.
1. Any member of the community may report any situation that violates the
Adafruit Community Code of Conduct. All reports will be reviewed and
investigated.
2. If the behavior is an egregious violation, the community member who
committed the violation may be banned immediately, without warning.
3. Otherwise, moderators will first respond to such behavior with a warning.
4. Moderators follow a soft "three strikes" policy - the community member may
be given another chance, if they are receptive to the warning and change their
behavior.
5. If the community member is unreceptive or unreasonable when warned by a
moderator, or the warning goes unheeded, they may be banned for a first or
second offense. Repeated offenses will result in the community member being
banned.
## Scope
This Code of Conduct and the enforcement policies listed above apply to all
Adafruit Community venues. This includes but is not limited to any community
spaces (both public and private), the entire Adafruit Discord server, and
Adafruit GitHub repositories. Examples of Adafruit Community spaces include
but are not limited to meet-ups, audio chats on the Adafruit Discord, or
interaction at a conference.
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. As a community
member, you are representing our community, and are expected to behave
accordingly.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 1.4, available at
<https://www.contributor-covenant.org/version/1/4/code-of-conduct.html>,
and the [Rust Code of Conduct](https://www.rust-lang.org/en-US/conduct.html).
For other projects adopting the Adafruit Community Code of
Conduct, please contact the maintainers of those projects for enforcement.
If you wish to use this code of conduct for your own project, consider
explicitly mentioning your moderation policy or making a copy with your
own moderation policy so as to avoid confusion.

View File

@ -1,47 +0,0 @@
/*
* See app note:
* https://www.melexis.com/en/documents/documentation/application-notes/application-note-mlx90614-changing-emissivity-setting
*
* 1. Write 0x0000 to address 0x04 (erase the EEPROM cell)
* 2. Write the new value to address 0x04
* 3. Read the value in address 0x04 in order to check that the correct value is stored
* 4. Restart the module
*
*/
#include <Adafruit_MLX90614.h>
//== CHANGE THIS ============
double new_emissivity = 0.95;
//===========================
Adafruit_MLX90614 mlx = Adafruit_MLX90614();
void setup() {
// Serial.begin(9600);
// while (!Serial);
Serial.println("Adafruit MLX90614 Emissivity Setter.\n");
// init sensor
if (!mlx.begin()) {
Serial.println("Error connecting to MLX sensor. Check wiring.");
while (1);
};
// read current emissivity
Serial.print("Current emissivity = "); Serial.println(mlx.readEmissivity());
// set new emissivity
Serial.print("Setting emissivity = "); Serial.println(new_emissivity);
mlx.writeEmissivity(new_emissivity); // this does the 0x0000 erase write
// read back
Serial.print("New emissivity = "); Serial.println(mlx.readEmissivity());
// done
Serial.print("DONE. Restart the module.");
}
void loop() {
}

View File

@ -1,46 +0,0 @@
/***************************************************
This is a library example for the MLX90614 Temp Sensor
Designed specifically to work with the MLX90614 sensors in the
adafruit shop
----> https://www.adafruit.com/products/1747 3V version
----> https://www.adafruit.com/products/1748 5V version
These sensors use I2C to communicate, 2 pins are required to
interface
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, all text above must be included in any redistribution
****************************************************/
#include <Adafruit_MLX90614.h>
Adafruit_MLX90614 mlx = Adafruit_MLX90614();
void setup() {
Serial.begin(9600);
while (!Serial);
Serial.println("Adafruit MLX90614 test");
if (!mlx.begin()) {
Serial.println("Error connecting to MLX sensor. Check wiring.");
while (1);
};
Serial.print("Emissivity = "); Serial.println(mlx.readEmissivity());
Serial.println("================================================");
}
void loop() {
Serial.print("Ambient = "); Serial.print(mlx.readAmbientTempC());
Serial.print("*C\tObject = "); Serial.print(mlx.readObjectTempC()); Serial.println("*C");
Serial.print("Ambient = "); Serial.print(mlx.readAmbientTempF());
Serial.print("*F\tObject = "); Serial.print(mlx.readObjectTempF()); Serial.println("*F");
Serial.println();
delay(500);
}

View File

@ -1,10 +0,0 @@
name=Adafruit MLX90614 Library
version=2.1.5
author=Adafruit
maintainer=Adafruit <info@adafruit.com>
sentence=Arduino library for the MLX90614 sensors in the Adafruit shop
paragraph=Arduino library for the MLX90614 sensors in the Adafruit shop
category=Sensors
url=https://github.com/adafruit/Adafruit-MLX90614-Library
architectures=*
depends=Adafruit BusIO

View File

@ -1,26 +0,0 @@
Software License Agreement (BSD License)
Copyright (c) 2020 Limor Fried for Adafruit Industries
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holders nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,7 @@
# See: https://github.com/codespell-project/codespell#using-a-config-file
[codespell]
# In the event of a false positive, add the problematic word, in all lowercase, to a comma-separated list here:
ignore-words-list = ,
check-filenames =
check-hidden =
skip = ./.git,./src/utility/URLParser

View File

@ -0,0 +1,12 @@
# See: https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates#about-the-dependabotyml-file
version: 2
updates:
# Configure check for outdated GitHub Actions actions in workflows.
# See: https://docs.github.com/en/github/administering-a-repository/keeping-your-actions-up-to-date-with-dependabot
- package-ecosystem: github-actions
directory: / # Check the repository's workflows under /.github/workflows/
schedule:
interval: daily
labels:
- "topic: infrastructure"

View File

@ -0,0 +1,28 @@
name: Check Arduino
# See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows
on:
push:
pull_request:
schedule:
# Run every Tuesday at 8 AM UTC to catch breakage caused by new rules added to Arduino Lint.
- cron: "0 8 * * TUE"
workflow_dispatch:
repository_dispatch:
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Arduino Lint
uses: arduino/arduino-lint-action@v1
with:
compliance: specification
library-manager: update
# Always use this setting for official repositories. Remove for 3rd party projects.
official: true
project-type: library

View File

@ -0,0 +1,63 @@
name: Compile Examples
# See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows
on:
push:
paths:
- ".github/workflows/compile-examples.yml"
- "examples/**"
- "src/**"
pull_request:
paths:
- ".github/workflows/compile-examples.yml"
- "examples/**"
- "src/**"
schedule:
# Run every Tuesday at 8 AM UTC to catch breakage caused by changes to external resources (libraries, platforms).
- cron: "0 8 * * TUE"
workflow_dispatch:
repository_dispatch:
jobs:
build:
name: ${{ matrix.board.fqbn }}
runs-on: ubuntu-latest
env:
SKETCHES_REPORTS_PATH: sketches-reports
strategy:
fail-fast: false
matrix:
board:
- fqbn: arduino:samd:mkr1000
platforms: |
- name: arduino:samd
artifact-name-suffix: arduino-samd-mkr1000
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Compile examples
uses: arduino/compile-sketches@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
fqbn: ${{ matrix.board.fqbn }}
platforms: ${{ matrix.board.platforms }}
libraries: |
# Install the library from the local path.
- source-path: ./
- name: WiFi101
sketch-paths: |
- examples
enable-deltas-report: true
sketches-report-path: ${{ env.SKETCHES_REPORTS_PATH }}
- name: Save sketches report as workflow artifact
uses: actions/upload-artifact@v4
with:
if-no-files-found: error
path: ${{ env.SKETCHES_REPORTS_PATH }}
name: sketches-report-${{ matrix.board.artifact-name-suffix }}

View File

@ -0,0 +1,24 @@
name: Report Size Deltas
# See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows
on:
push:
paths:
- ".github/workflows/report-size-deltas.yml"
schedule:
# Run at the minimum interval allowed by GitHub Actions.
# Note: GitHub Actions periodically has outages which result in workflow failures.
# In this event, the workflows will start passing again once the service recovers.
- cron: "*/5 * * * *"
workflow_dispatch:
repository_dispatch:
jobs:
report:
runs-on: ubuntu-latest
steps:
- name: Comment size deltas reports to PRs
uses: arduino/report-size-deltas@v1
with:
# Regex matching the names of the workflow artifacts created by the "Compile Examples" workflow
sketches-reports-source: ^sketches-report-.+

View File

@ -0,0 +1,22 @@
name: Spell Check
# See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows
on:
push:
pull_request:
schedule:
# Run every Tuesday at 8 AM UTC to catch new misspelling detections resulting from dictionary updates.
- cron: "0 8 * * TUE"
workflow_dispatch:
repository_dispatch:
jobs:
spellcheck:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Spell check
uses: codespell-project/actions-codespell@master

View File

@ -0,0 +1,138 @@
# Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/sync-labels.md
name: Sync Labels
# See: https://docs.github.com/en/actions/reference/events-that-trigger-workflows
on:
push:
paths:
- ".github/workflows/sync-labels.ya?ml"
- ".github/label-configuration-files/*.ya?ml"
pull_request:
paths:
- ".github/workflows/sync-labels.ya?ml"
- ".github/label-configuration-files/*.ya?ml"
schedule:
# Run daily at 8 AM UTC to sync with changes to shared label configurations.
- cron: "0 8 * * *"
workflow_dispatch:
repository_dispatch:
env:
CONFIGURATIONS_FOLDER: .github/label-configuration-files
CONFIGURATIONS_ARTIFACT: label-configuration-files
jobs:
check:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download JSON schema for labels configuration file
id: download-schema
uses: carlosperate/download-file-action@v2
with:
file-url: https://raw.githubusercontent.com/arduino/tooling-project-assets/main/workflow-templates/assets/sync-labels/arduino-tooling-gh-label-configuration-schema.json
location: ${{ runner.temp }}/label-configuration-schema
- name: Install JSON schema validator
run: |
sudo npm install \
--global \
ajv-cli \
ajv-formats
- name: Validate local labels configuration
run: |
# See: https://github.com/ajv-validator/ajv-cli#readme
ajv validate \
--all-errors \
-c ajv-formats \
-s "${{ steps.download-schema.outputs.file-path }}" \
-d "${{ env.CONFIGURATIONS_FOLDER }}/*.{yml,yaml}"
download:
needs: check
runs-on: ubuntu-latest
strategy:
matrix:
filename:
# Filenames of the shared configurations to apply to the repository in addition to the local configuration.
# https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/sync-labels
- universal.yml
steps:
- name: Download
uses: carlosperate/download-file-action@v2
with:
file-url: https://raw.githubusercontent.com/arduino/tooling-project-assets/main/workflow-templates/assets/sync-labels/${{ matrix.filename }}
- name: Pass configuration files to next job via workflow artifact
uses: actions/upload-artifact@v4
with:
path: |
*.yaml
*.yml
if-no-files-found: error
name: ${{ env.CONFIGURATIONS_ARTIFACT }}
sync:
needs: download
runs-on: ubuntu-latest
steps:
- name: Set environment variables
run: |
# See: https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-environment-variable
echo "MERGED_CONFIGURATION_PATH=${{ runner.temp }}/labels.yml" >> "$GITHUB_ENV"
- name: Determine whether to dry run
id: dry-run
if: >
github.event_name == 'pull_request' ||
(
(
github.event_name == 'push' ||
github.event_name == 'workflow_dispatch'
) &&
github.ref != format('refs/heads/{0}', github.event.repository.default_branch)
)
run: |
# Use of this flag in the github-label-sync command will cause it to only check the validity of the
# configuration.
echo "::set-output name=flag::--dry-run"
- name: Checkout repository
uses: actions/checkout@v4
- name: Download configuration files artifact
uses: actions/download-artifact@v4
with:
name: ${{ env.CONFIGURATIONS_ARTIFACT }}
path: ${{ env.CONFIGURATIONS_FOLDER }}
- name: Remove unneeded artifact
uses: geekyeggo/delete-artifact@v5
with:
name: ${{ env.CONFIGURATIONS_ARTIFACT }}
- name: Merge label configuration files
run: |
# Merge all configuration files
shopt -s extglob
cat "${{ env.CONFIGURATIONS_FOLDER }}"/*.@(yml|yaml) > "${{ env.MERGED_CONFIGURATION_PATH }}"
- name: Install github-label-sync
run: sudo npm install --global github-label-sync
- name: Sync labels
env:
GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# See: https://github.com/Financial-Times/github-label-sync
github-label-sync \
--labels "${{ env.MERGED_CONFIGURATION_PATH }}" \
${{ steps.dry-run.outputs.flag }} \
${{ github.repository }}

View File

@ -3,3 +3,4 @@ examples/node_test_server/node_modules/
*.DS_Store
*/.DS_Store
examples/.DS_Store
.idea/

View File

@ -1 +1 @@
{"type": "library", "name": "ArduinoHttpClient", "version": "0.4.0", "spec": {"owner": "arduino-libraries", "id": 798, "name": "ArduinoHttpClient", "requirements": null, "uri": null}}
{"type": "library", "name": "ArduinoHttpClient", "version": "0.6.1", "spec": {"owner": "arduino-libraries", "id": 798, "name": "ArduinoHttpClient", "requirements": null, "uri": null}}

View File

@ -9,7 +9,7 @@
## ArduinoHttpClient 0.3.1 - 2017.09.25
* Changed examples to support Arduino Create secret tabs
* Increase WebSocket secrect-key length to 24 characters
* Increase WebSocket secret-key length to 24 characters
## ArduinoHttpClient 0.3.0 - 2017.04.20

View File

@ -1,5 +1,9 @@
# ArduinoHttpClient
[![Check Arduino status](https://github.com/arduino-libraries/ArduinoHttpClient/actions/workflows/check-arduino.yml/badge.svg)](https://github.com/arduino-libraries/ArduinoHttpClient/actions/workflows/check-arduino.yml)
[![Compile Examples status](https://github.com/arduino-libraries/ArduinoHttpClient/actions/workflows/compile-examples.yml/badge.svg)](https://github.com/arduino-libraries/ArduinoHttpClient/actions/workflows/compile-examples.yml)
[![Spell Check status](https://github.com/arduino-libraries/ArduinoHttpClient/actions/workflows/spell-check.yml/badge.svg)](https://github.com/arduino-libraries/ArduinoHttpClient/actions/workflows/spell-check.yml)
ArduinoHttpClient is a library to make it easier to interact with web servers from Arduino.
Derived from [Adrian McEwen's HttpClient library](https://github.com/amcewen/HttpClient)

View File

@ -15,7 +15,7 @@
#include <WiFi101.h>
#include "arduino_secrets.h"
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
/////// Wifi Settings ///////
/////// WiFi Settings ///////
char ssid[] = SECRET_SSID;
char pass[] = SECRET_PASS;

View File

@ -15,7 +15,7 @@
#include "arduino_secrets.h"
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
/////// Wifi Settings ///////
/////// WiFi Settings ///////
char ssid[] = SECRET_SSID;
char pass[] = SECRET_PASS;

View File

@ -20,7 +20,7 @@
#include "arduino_secrets.h"
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
/////// Wifi Settings ///////
/////// WiFi Settings ///////
char ssid[] = SECRET_SSID;
char pass[] = SECRET_PASS;

View File

@ -16,7 +16,7 @@
#include "arduino_secrets.h"
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
/////// Wifi Settings ///////
/////// WiFi Settings ///////
char ssid[] = SECRET_SSID;
char pass[] = SECRET_PASS;

View File

@ -10,7 +10,7 @@
The body of the PUT request looks like this:
{"on": true} or {"on":false}
This example shows how to concatenate Strings to assemble the
This example shows how to concatenate Strings to assemble the
PUT request and the body of the request.
modified 15 Feb 2016
@ -23,16 +23,16 @@
#include "arduino_secrets.h"
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
/////// Wifi Settings ///////
/////// WiFi Settings ///////
char ssid[] = SECRET_SSID;
char pass[] = SECRET_PASS;
int status = WL_IDLE_STATUS; // the Wifi radio's status
int status = WL_IDLE_STATUS; // the WiFi radio's status
char hueHubIP[] = "192.168.0.3"; // IP address of the HUE bridge
String hueUserName = "huebridgeusername"; // hue bridge username
// make a wifi instance and a HttpClient instance:
// make a WiFiClient instance and a HttpClient instance:
WiFiClient wifi;
HttpClient httpClient = HttpClient(wifi, hueHubIP);
@ -42,7 +42,7 @@ void setup() {
Serial.begin(9600);
while (!Serial); // wait for serial port to connect.
// attempt to connect to Wifi network:
// attempt to connect to WiFi network:
while ( status != WL_CONNECTED) {
Serial.print("Attempting to connect to WPA SSID: ");
Serial.println(ssid);
@ -95,4 +95,4 @@ void sendRequest(int light, String cmd, String value) {
Serial.print("Server response: ");
Serial.println(response);
Serial.println();
}
}

View File

@ -0,0 +1,29 @@
#include "URLParser.h"
void setup() {
Serial.begin(9600);
while(!Serial);
Serial.println("starting");
ParsedUrl url(
"https://www.google.com/search?q=arduino"
);
Serial.print("parsed URL schema: \"");
Serial.print(url.schema());
Serial.print("\"\nparsed URL host: \"");
Serial.print(url.host());
Serial.print("\"\nparsed URL path: \"");
Serial.print(url.path());
Serial.print("\"\nparsed URL query: \"");
Serial.print(url.query());
Serial.print("\"\nparsed URL userinfo: \"");
Serial.print(url.userinfo());
Serial.println("\"");
}
void loop() { }

View File

@ -1,7 +1,7 @@
/*
POST with headers client for ArduinoHttpClient library
Connects to server once every five seconds, sends a POST request
with custome headers and a request body
with custom headers and a request body
created 14 Feb 2016
by Tom Igoe
@ -18,7 +18,7 @@
#include "arduino_secrets.h"
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
/////// Wifi Settings ///////
/////// WiFi Settings ///////
char ssid[] = SECRET_SSID;
char pass[] = SECRET_PASS;

View File

@ -15,7 +15,7 @@
#include "arduino_secrets.h"
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
/////// Wifi Settings ///////
/////// WiFi Settings ///////
char ssid[] = SECRET_SSID;
char pass[] = SECRET_PASS;

View File

@ -14,7 +14,7 @@
#include "arduino_secrets.h"
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
/////// Wifi Settings ///////
/////// WiFi Settings ///////
char ssid[] = SECRET_SSID;
char pass[] = SECRET_PASS;

View File

@ -2,7 +2,7 @@
// Released under Apache License, version 2.0
//
// Simple example to show how to use the HttpClient library
// Get's the web page given at http://<kHostname><kPath> and
// Gets the web page given at http://<kHostname><kPath> and
// outputs the content to the serial port
#include <SPI.h>
@ -14,7 +14,7 @@
#include "arduino_secrets.h"
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
/////// Wifi Settings ///////
/////// WiFi Settings ///////
char ssid[] = SECRET_SSID;
char pass[] = SECRET_PASS;
@ -42,7 +42,7 @@ void setup()
; // wait for serial port to connect. Needed for native USB port only
}
// attempt to connect to Wifi network:
// attempt to connect to WiFi network:
Serial.print("Attempting to connect to WPA SSID: ");
Serial.println(ssid);
while (WiFi.begin(ssid, pass) != WL_CONNECTED) {
@ -129,5 +129,3 @@ void loop()
// And just stop, now that we've tried a download
while(1);
}

View File

@ -14,7 +14,7 @@
#include "arduino_secrets.h"
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
/////// Wifi Settings ///////
/////// WiFi Settings ///////
char ssid[] = SECRET_SSID;
char pass[] = SECRET_PASS;

View File

@ -14,7 +14,7 @@
#include "arduino_secrets.h"
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
/////// Wifi Settings ///////
/////// WiFi Settings ///////
char ssid[] = SECRET_SSID;
char pass[] = SECRET_PASS;

View File

@ -15,7 +15,7 @@
#include "arduino_secrets.h"
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
/////// Wifi Settings ///////
/////// WiFi Settings ///////
char ssid[] = SECRET_SSID;
char pass[] = SECRET_PASS;

View File

@ -1,5 +1,5 @@
#######################################
# Syntax Coloring Map For HttpClient
# Syntax Coloring Map For ArduinoHttpClient
#######################################
#######################################

View File

@ -1,12 +0,0 @@
{
"name": "ArduinoHttpClient",
"keywords": "http, web, client, ethernet, wifi, GSM",
"description": "Easily interact with web servers from Arduino, using HTTP and WebSocket's.",
"repository": {
"type": "git",
"url": "https://github.com/arduino-libraries/ArduinoHttpClient.git"
},
"frameworks": "arduino",
"platforms": "*",
"version": "0.4.0"
}

View File

@ -1,8 +1,8 @@
name=ArduinoHttpClient
version=0.4.0
version=0.6.1
author=Arduino
maintainer=Arduino <info@arduino.cc>
sentence=[EXPERIMENTAL] Easily interact with web servers from Arduino, using HTTP and WebSocket's.
sentence=[EXPERIMENTAL] Easily interact with web servers from Arduino, using HTTP and WebSockets.
paragraph=This library can be used for HTTP (GET, POST, PUT, DELETE) requests to a web server. It also supports exchanging messages with WebSocket servers. Based on Adrian McEwen's HttpClient library.
category=Communication
url=https://github.com/arduino-libraries/ArduinoHttpClient

View File

@ -4,6 +4,7 @@
#include "HttpClient.h"
#include "b64.h"
// Initialize constants
const char* HttpClient::kUserAgent = "Arduino/2.2.0";
const char* HttpClient::kContentLengthPrefix = HTTP_HEADER_CONTENT_LENGTH ": ";
@ -39,6 +40,7 @@ void HttpClient::resetState()
iIsChunked = false;
iChunkLength = 0;
iHttpResponseTimeout = kHttpResponseTimeout;
iHttpWaitForDataDelay = kHttpWaitForDataDelay;
}
void HttpClient::stop()
@ -83,7 +85,7 @@ int HttpClient::startRequest(const char* aURLPath, const char* aHttpMethod,
{
if (iServerName)
{
if (!iClient->connect(iServerName, iServerPort) > 0)
if (!(iClient->connect(iServerName, iServerPort) > 0))
{
#ifdef LOGGING
Serial.println("Connection failed");
@ -93,7 +95,7 @@ int HttpClient::startRequest(const char* aURLPath, const char* aHttpMethod,
}
else
{
if (!iClient->connect(iServerAddress, iServerPort) > 0)
if (!(iClient->connect(iServerAddress, iServerPort) > 0))
{
#ifdef LOGGING
Serial.println("Connection failed");
@ -160,7 +162,7 @@ int HttpClient::sendInitialHeaders(const char* aURLPath, const char* aHttpMethod
{
iClient->print("Host: ");
iClient->print(iServerName);
if (iServerPort != kHttpPort)
if (iServerPort != kHttpPort && iServerPort != kHttpsPort)
{
iClient->print(":");
iClient->print(iServerPort);
@ -420,7 +422,7 @@ int HttpClient::responseStatusCode()
{
if (available())
{
c = read();
c = HttpClient::read();
if (c != -1)
{
switch(iState)
@ -472,7 +474,7 @@ int HttpClient::responseStatusCode()
{
// We haven't got any data, so let's pause to allow some to
// arrive
delay(kHttpWaitForDataDelay);
delay(iHttpWaitForDataDelay);
}
}
if ( (c == '\n') && (iStatusCode < 200 && iStatusCode != 101) )
@ -521,7 +523,7 @@ int HttpClient::skipResponseHeaders()
{
// We haven't got any data, so let's pause to allow some to
// arrive
delay(kHttpWaitForDataDelay);
delay(iHttpWaitForDataDelay);
}
}
if (endOfHeadersReached())
@ -541,7 +543,7 @@ bool HttpClient::endOfHeadersReached()
return (iState == eReadingBody || iState == eReadingChunkLength || iState == eReadingBodyChunk);
};
int HttpClient::contentLength()
long HttpClient::contentLength()
{
// skip the response headers, if they haven't been read already
if (!endOfHeadersReached())
@ -586,7 +588,7 @@ String HttpClient::responseBody()
}
if (bodyLength > 0 && (unsigned int)bodyLength != response.length()) {
// failure, we did not read in reponse content length bytes
// failure, we did not read in response content length bytes
return String((const char*)NULL);
}
@ -684,12 +686,12 @@ int HttpClient::read()
bool HttpClient::headerAvailable()
{
// clear the currently store header line
// clear the currently stored header line
iHeaderLine = "";
while (!endOfHeadersReached())
{
uint64_t i =0;
{
// read a byte from the header
int c = readHeader();
if (c == '\r' || c == '\n')
@ -705,13 +707,7 @@ bool HttpClient::headerAvailable()
continue;
}
}
i++;
if(i > 1024*2)
{
return false;
}
// append byte to header line
iHeaderLine += (char)c;
}
@ -767,7 +763,7 @@ int HttpClient::read(uint8_t *buf, size_t size)
int HttpClient::readHeader()
{
char c = read();
char c = HttpClient::read();
if (endOfHeadersReached())
{
@ -823,7 +819,11 @@ int HttpClient::readHeader()
case eReadingContentLength:
if (isdigit(c))
{
iContentLength = iContentLength*10 + (c - '0');
long _iContentLength = iContentLength*10 + (c - '0');
// Only apply if the value didn't wrap around
if (_iContentLength > iContentLength) {
iContentLength = _iContentLength;
}
}
else
{

View File

@ -43,6 +43,7 @@ class HttpClient : public Client
public:
static const int kNoContentLengthHeader =-1;
static const int kHttpPort =80;
static const int kHttpsPort =443;
static const char* kUserAgent;
// FIXME Write longer API request, using port and user-agent, example
@ -228,7 +229,7 @@ public:
*/
String readHeaderName();
/** Read the vallue of the current response header.
/** Read the value of the current response header.
Returns empty string if a header is not available.
*/
String readHeaderValue();
@ -272,7 +273,7 @@ public:
@return Length of the body, in bytes, or kNoContentLengthHeader if no
Content-Length header was returned by the server
*/
int contentLength();
long contentLength();
/** Returns if the response body is chunked
@return true if response body is chunked, false otherwise
@ -317,6 +318,8 @@ public:
virtual operator bool() { return bool(iClient); };
virtual uint32_t httpResponseTimeout() { return iHttpResponseTimeout; };
virtual void setHttpResponseTimeout(uint32_t timeout) { iHttpResponseTimeout = timeout; };
virtual uint32_t httpWaitForDataDelay() { return iHttpWaitForDataDelay; };
virtual void setHttpWaitForDataDelay(uint32_t delay) { iHttpWaitForDataDelay = delay; };
protected:
/** Reset internal state data back to the "just initialised" state
*/
@ -340,8 +343,8 @@ protected:
// Number of milliseconds that we wait each time there isn't any data
// available to be read (during status code and header processing)
static const int kHttpWaitForDataDelay = 1000;
// Number of milliseconds that we'll wait in total without receiveing any
static const int kHttpWaitForDataDelay = 100;
// Number of milliseconds that we'll wait in total without receiving any
// data before returning HTTP_ERROR_TIMED_OUT (during status code and header
// processing)
static const int kHttpResponseTimeout = 30*1000;
@ -372,7 +375,7 @@ protected:
// Stores the status code for the response, once known
int iStatusCode;
// Stores the value of the Content-Length header, if present
int iContentLength;
long iContentLength;
// How many bytes of the response body have been read by the user
int iBodyLengthConsumed;
// How far through a Content-Length header prefix we are
@ -384,6 +387,7 @@ protected:
// Stores the value of the current chunk length, if present
int iChunkLength;
uint32_t iHttpResponseTimeout;
uint32_t iHttpWaitForDataDelay;
bool iConnectionClose;
bool iSendDefaultRequestHeaders;
String iHeaderLine;

View File

@ -0,0 +1,108 @@
/*
* PackageLicenseDeclared: Apache-2.0
* Copyright (c) 2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* The following class is defined in mbed libraries, in case of STM32H7 include the original library
*/
#if defined __has_include
# if __has_include(<utility/http_parsed_url.h>)
# include <utility/http_parsed_url.h>
# else
# define NO_HTTP_PARSED
# endif
#endif
#ifdef NO_HTTP_PARSED
#ifndef _MBED_HTTP_PARSED_URL_H_
#define _MBED_HTTP_PARSED_URL_H_
#include "utility/URLParser/http_parser.h"
class ParsedUrl {
public:
ParsedUrl(const char* url) {
struct http_parser_url parsed_url;
http_parser_parse_url(url, strlen(url), false, &parsed_url);
for (size_t ix = 0; ix < UF_MAX; ix++) {
char* value;
if (parsed_url.field_set & (1 << ix)) {
value = (char*)calloc(parsed_url.field_data[ix].len + 1, 1);
memcpy(value, url + parsed_url.field_data[ix].off,
parsed_url.field_data[ix].len);
}
else {
value = (char*)calloc(1, 1);
}
switch ((http_parser_url_fields)ix) {
case UF_SCHEMA: _schema = value; break;
case UF_HOST: _host = value; break;
case UF_PATH: _path = value; break;
case UF_QUERY: _query = value; break;
case UF_USERINFO: _userinfo = value; break;
default:
// PORT is already parsed, FRAGMENT is not relevant for HTTP requests
free(value);
break;
}
}
_port = parsed_url.port;
if (!_port) {
if (strcmp(_schema, "https") == 0 || strcmp(_schema, "wss") == 0) {
_port = 443;
}
else {
_port = 80;
}
}
if (strcmp(_path, "") == 0) {
free(_path);
_path = (char*)calloc(2, 1);
_path[0] = '/';
}
}
~ParsedUrl() {
if (_schema) free(_schema);
if (_host) free(_host);
if (_path) free(_path);
if (_query) free(_query);
if (_userinfo) free(_userinfo);
}
uint16_t port() const { return _port; }
char* schema() const { return _schema; }
char* host() const { return _host; }
char* path() const { return _path; }
char* query() const { return _query; }
char* userinfo() const { return _userinfo; }
private:
uint16_t _port;
char* _schema;
char* _host;
char* _path;
char* _query;
char* _userinfo;
};
#endif // _MBED_HTTP_PARSED_URL_H_
#endif // NO_HTTP_PARSED
#undef NO_HTTP_PARSED

View File

@ -8,6 +8,10 @@
#include "HttpClient.h"
#ifndef WS_TX_BUFFER_SIZE
#define WS_TX_BUFFER_SIZE 128
#endif
static const int TYPE_CONTINUATION = 0x0;
static const int TYPE_TEXT = 0x1;
static const int TYPE_BINARY = 0x2;
@ -86,7 +90,7 @@ private:
private:
bool iTxStarted;
uint8_t iTxMessageType;
uint8_t iTxBuffer[128];
uint8_t iTxBuffer[WS_TX_BUFFER_SIZE];
uint64_t iTxSize;
uint8_t iRxOpCode;

View File

@ -1,21 +1,23 @@
MIT License
http_parser.c is based on src/http/ngx_http_parse.c from NGINX copyright
Igor Sysoev.
Copyright (c) 2021 jpb10
Additional changes are licensed under the same terms as NGINX and
copyright Joyent, Inc. and other Node contributors. All rights reserved.
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
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 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.
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.

View File

@ -0,0 +1,5 @@
# http_parser library
This code is imported from: https://github.com/arduino/ArduinoCore-mbed/tree/4.1.1/libraries/SocketWrapper/src/utility/http_parser
The code is shrinked in size by deleting all the unrelated code to url parse.

View File

@ -0,0 +1,591 @@
#if defined __has_include
# if ! __has_include(<utility/http_parser/http_parser.h>) && ! __has_include(<http_parser.h>)
# define NO_HTTP_PARSER
# endif
#endif
#ifdef NO_HTTP_PARSER
/* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev
*
* Additional changes are licensed under the same terms as NGINX and
* copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* 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.
*/
#include "http_parser.h"
#include <assert.h>
#include <stddef.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#ifndef BIT_AT
# define BIT_AT(a, i) \
(!!((unsigned int) (a)[(unsigned int) (i) >> 3] & \
(1 << ((unsigned int) (i) & 7))))
#endif
#define SET_ERRNO(e) \
do { \
parser->http_errno = (e); \
} while(0)
#if HTTP_PARSER_STRICT
# define T(v) 0
#else
# define T(v) v
#endif
static const uint8_t normal_url_char[32] = {
/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */
0 | T(2) | 0 | 0 | T(16) | 0 | 0 | 0,
/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */
0 | 2 | 4 | 0 | 16 | 32 | 64 | 128,
/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */
1 | 2 | 4 | 8 | 16 | 32 | 64 | 0,
/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */
1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, };
#undef T
enum state
{ s_dead = 1 /* important that this is > 0 */
, s_start_req
, s_req_spaces_before_url
, s_req_schema
, s_req_schema_slash
, s_req_schema_slash_slash
, s_req_server_start
, s_req_server
, s_req_server_with_at
, s_req_path
, s_req_query_string_start
, s_req_query_string
, s_req_fragment_start
, s_req_fragment
, s_headers_done
};
enum http_host_state
{
s_http_host_dead = 1
, s_http_userinfo_start
, s_http_userinfo
, s_http_host_start
, s_http_host_v6_start
, s_http_host
, s_http_host_v6
, s_http_host_v6_end
, s_http_host_v6_zone_start
, s_http_host_v6_zone
, s_http_host_port_start
, s_http_host_port
};
/* Macros for character classes; depends on strict-mode */
#define LOWER(c) (unsigned char)(c | 0x20)
#define IS_ALPHA(c) (LOWER(c) >= 'a' && LOWER(c) <= 'z')
#define IS_NUM(c) ((c) >= '0' && (c) <= '9')
#define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c))
#define IS_HEX(c) (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f'))
#define IS_MARK(c) ((c) == '-' || (c) == '_' || (c) == '.' || \
(c) == '!' || (c) == '~' || (c) == '*' || (c) == '\'' || (c) == '(' || \
(c) == ')')
#define IS_USERINFO_CHAR(c) (IS_ALPHANUM(c) || IS_MARK(c) || (c) == '%' || \
(c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || \
(c) == '$' || (c) == ',')
#if HTTP_PARSER_STRICT
#define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c))
#define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-')
#else
#define IS_URL_CHAR(c) \
(BIT_AT(normal_url_char, (unsigned char)c) || ((c) & 0x80))
#define IS_HOST_CHAR(c) \
(IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_')
#endif
/* Our URL parser.
*
* This is designed to be shared by http_parser_execute() for URL validation,
* hence it has a state transition + byte-for-byte interface. In addition, it
* is meant to be embedded in http_parser_parse_url(), which does the dirty
* work of turning state transitions URL components for its API.
*
* This function should only be invoked with non-space characters. It is
* assumed that the caller cares about (and can detect) the transition between
* URL and non-URL states by looking for these.
*/
static enum state
parse_url_char(enum state s, const char ch)
{
if (ch == ' ' || ch == '\r' || ch == '\n') {
return s_dead;
}
#if HTTP_PARSER_STRICT
if (ch == '\t' || ch == '\f') {
return s_dead;
}
#endif
switch (s) {
case s_req_spaces_before_url:
/* Proxied requests are followed by scheme of an absolute URI (alpha).
* All methods except CONNECT are followed by '/' or '*'.
*/
if (ch == '/' || ch == '*') {
return s_req_path;
}
if (IS_ALPHA(ch)) {
return s_req_schema;
}
break;
case s_req_schema:
if (IS_ALPHA(ch)) {
return s;
}
if (ch == ':') {
return s_req_schema_slash;
}
break;
case s_req_schema_slash:
if (ch == '/') {
return s_req_schema_slash_slash;
}
break;
case s_req_schema_slash_slash:
if (ch == '/') {
return s_req_server_start;
}
break;
case s_req_server_with_at:
if (ch == '@') {
return s_dead;
}
/* FALLTHROUGH */
case s_req_server_start:
case s_req_server:
if (ch == '/') {
return s_req_path;
}
if (ch == '?') {
return s_req_query_string_start;
}
if (ch == '@') {
return s_req_server_with_at;
}
if (IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') {
return s_req_server;
}
break;
case s_req_path:
if (IS_URL_CHAR(ch)) {
return s;
}
switch (ch) {
case '?':
return s_req_query_string_start;
case '#':
return s_req_fragment_start;
}
break;
case s_req_query_string_start:
case s_req_query_string:
if (IS_URL_CHAR(ch)) {
return s_req_query_string;
}
switch (ch) {
case '?':
/* allow extra '?' in query string */
return s_req_query_string;
case '#':
return s_req_fragment_start;
}
break;
case s_req_fragment_start:
if (IS_URL_CHAR(ch)) {
return s_req_fragment;
}
switch (ch) {
case '?':
return s_req_fragment;
case '#':
return s;
}
break;
case s_req_fragment:
if (IS_URL_CHAR(ch)) {
return s;
}
switch (ch) {
case '?':
case '#':
return s;
}
break;
default:
break;
}
/* We should never fall out of the switch above unless there's an error */
return s_dead;
}
static enum http_host_state
http_parse_host_char(enum http_host_state s, const char ch) {
switch(s) {
case s_http_userinfo:
case s_http_userinfo_start:
if (ch == '@') {
return s_http_host_start;
}
if (IS_USERINFO_CHAR(ch)) {
return s_http_userinfo;
}
break;
case s_http_host_start:
if (ch == '[') {
return s_http_host_v6_start;
}
if (IS_HOST_CHAR(ch)) {
return s_http_host;
}
break;
case s_http_host:
if (IS_HOST_CHAR(ch)) {
return s_http_host;
}
/* FALLTHROUGH */
case s_http_host_v6_end:
if (ch == ':') {
return s_http_host_port_start;
}
break;
case s_http_host_v6:
if (ch == ']') {
return s_http_host_v6_end;
}
/* FALLTHROUGH */
case s_http_host_v6_start:
if (IS_HEX(ch) || ch == ':' || ch == '.') {
return s_http_host_v6;
}
if (s == s_http_host_v6 && ch == '%') {
return s_http_host_v6_zone_start;
}
break;
case s_http_host_v6_zone:
if (ch == ']') {
return s_http_host_v6_end;
}
/* FALLTHROUGH */
case s_http_host_v6_zone_start:
/* RFC 6874 Zone ID consists of 1*( unreserved / pct-encoded) */
if (IS_ALPHANUM(ch) || ch == '%' || ch == '.' || ch == '-' || ch == '_' ||
ch == '~') {
return s_http_host_v6_zone;
}
break;
case s_http_host_port:
case s_http_host_port_start:
if (IS_NUM(ch)) {
return s_http_host_port;
}
break;
default:
break;
}
return s_http_host_dead;
}
static int
http_parse_host(const char * buf, struct http_parser_url *u, int found_at) {
enum http_host_state s;
const char *p;
uint32_t buflen = u->field_data[UF_HOST].off + u->field_data[UF_HOST].len;
assert(u->field_set & (1 << UF_HOST));
u->field_data[UF_HOST].len = 0;
s = found_at ? s_http_userinfo_start : s_http_host_start;
for (p = buf + u->field_data[UF_HOST].off; p < buf + buflen; p++) {
enum http_host_state new_s = http_parse_host_char(s, *p);
if (new_s == s_http_host_dead) {
return 1;
}
switch(new_s) {
case s_http_host:
if (s != s_http_host) {
u->field_data[UF_HOST].off = p - buf;
}
u->field_data[UF_HOST].len++;
break;
case s_http_host_v6:
if (s != s_http_host_v6) {
u->field_data[UF_HOST].off = p - buf;
}
u->field_data[UF_HOST].len++;
break;
case s_http_host_v6_zone_start:
case s_http_host_v6_zone:
u->field_data[UF_HOST].len++;
break;
case s_http_host_port:
if (s != s_http_host_port) {
u->field_data[UF_PORT].off = p - buf;
u->field_data[UF_PORT].len = 0;
u->field_set |= (1 << UF_PORT);
}
u->field_data[UF_PORT].len++;
break;
case s_http_userinfo:
if (s != s_http_userinfo) {
u->field_data[UF_USERINFO].off = p - buf ;
u->field_data[UF_USERINFO].len = 0;
u->field_set |= (1 << UF_USERINFO);
}
u->field_data[UF_USERINFO].len++;
break;
default:
break;
}
s = new_s;
}
/* Make sure we don't end somewhere unexpected */
switch (s) {
case s_http_host_start:
case s_http_host_v6_start:
case s_http_host_v6:
case s_http_host_v6_zone_start:
case s_http_host_v6_zone:
case s_http_host_port_start:
case s_http_userinfo:
case s_http_userinfo_start:
return 1;
default:
break;
}
return 0;
}
void
http_parser_url_init(struct http_parser_url *u) {
memset(u, 0, sizeof(*u));
}
int
http_parser_parse_url(const char *buf, uint32_t buflen, int is_connect,
struct http_parser_url *u)
{
enum state s;
const char *p;
enum http_parser_url_fields uf, old_uf;
int found_at = 0;
u->port = u->field_set = 0;
s = is_connect ? s_req_server_start : s_req_spaces_before_url;
old_uf = UF_MAX;
for (p = buf; p < buf + buflen; p++) {
s = parse_url_char(s, *p);
/* Figure out the next field that we're operating on */
switch (s) {
case s_dead:
return 1;
/* Skip delimeters */
case s_req_schema_slash:
case s_req_schema_slash_slash:
case s_req_server_start:
case s_req_query_string_start:
case s_req_fragment_start:
continue;
case s_req_schema:
uf = UF_SCHEMA;
break;
case s_req_server_with_at:
found_at = 1;
/* FALLTROUGH */
case s_req_server:
uf = UF_HOST;
break;
case s_req_path:
uf = UF_PATH;
break;
case s_req_query_string:
uf = UF_QUERY;
break;
case s_req_fragment:
uf = UF_FRAGMENT;
break;
default:
assert(!"Unexpected state");
return 1;
}
/* Nothing's changed; soldier on */
if (uf == old_uf) {
u->field_data[uf].len++;
continue;
}
u->field_data[uf].off = p - buf;
u->field_data[uf].len = 1;
u->field_set |= (1 << uf);
old_uf = uf;
}
/* host must be present if there is a schema */
/* parsing http:///toto will fail */
if ((u->field_set & (1 << UF_SCHEMA)) &&
(u->field_set & (1 << UF_HOST)) == 0) {
return 1;
}
if (u->field_set & (1 << UF_HOST)) {
if (http_parse_host(buf, u, found_at) != 0) {
return 1;
}
}
/* CONNECT requests can only contain "hostname:port" */
if (is_connect && u->field_set != ((1 << UF_HOST)|(1 << UF_PORT))) {
return 1;
}
if (u->field_set & (1 << UF_PORT)) {
/* Don't bother with endp; we've already validated the string */
unsigned long v = strtoul(buf + u->field_data[UF_PORT].off, NULL, 10);
/* Ports have a max value of 2^16 */
if (v > 0xffff) {
return 1;
}
u->port = (uint16_t) v;
}
return 0;
}
unsigned long
http_parser_version(void) {
return HTTP_PARSER_VERSION_MAJOR * 0x10000 |
HTTP_PARSER_VERSION_MINOR * 0x00100 |
HTTP_PARSER_VERSION_PATCH * 0x00001;
}
#endif // NO_HTTP_PARSER

View File

@ -0,0 +1,96 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* 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 http_parser_h
#define http_parser_h
#ifdef __cplusplus
extern "C" {
#endif
/* Also update SONAME in the Makefile whenever you change these. */
#define HTTP_PARSER_VERSION_MAJOR 2
#define HTTP_PARSER_VERSION_MINOR 7
#define HTTP_PARSER_VERSION_PATCH 1
#include <stdint.h>
/* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run
* faster
*/
#ifndef HTTP_PARSER_STRICT
# define HTTP_PARSER_STRICT 1
#endif
enum http_parser_url_fields
{ UF_SCHEMA = 0
, UF_HOST = 1
, UF_PORT = 2
, UF_PATH = 3
, UF_QUERY = 4
, UF_FRAGMENT = 5
, UF_USERINFO = 6
, UF_MAX = 7
};
/* Result structure for http_parser_parse_url().
*
* Callers should index into field_data[] with UF_* values iff field_set
* has the relevant (1 << UF_*) bit set. As a courtesy to clients (and
* because we probably have padding left over), we convert any port to
* a uint16_t.
*/
struct http_parser_url {
uint16_t field_set; /* Bitmask of (1 << UF_*) values */
uint16_t port; /* Converted UF_PORT string */
struct {
uint16_t off; /* Offset into buffer in which field starts */
uint16_t len; /* Length of run in buffer */
} field_data[UF_MAX];
};
/* Returns the library version. Bits 16-23 contain the major version number,
* bits 8-15 the minor version number and bits 0-7 the patch level.
* Usage example:
*
* unsigned long version = http_parser_version();
* unsigned major = (version >> 16) & 255;
* unsigned minor = (version >> 8) & 255;
* unsigned patch = version & 255;
* printf("http_parser v%u.%u.%u\n", major, minor, patch);
*/
unsigned long http_parser_version(void);
/* Initialize all http_parser_url members to 0 */
void http_parser_url_init(struct http_parser_url *u);
/* Parse a URL; return nonzero on failure */
int http_parser_parse_url(const char *buf, uint32_t buflen,
int is_connect,
struct http_parser_url *u);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1 +1 @@
{"type": "library", "name": "ArduinoJson", "version": "6.21.5", "spec": {"owner": "bblanchon", "id": 64, "name": "ArduinoJson", "requirements": null, "uri": null}}
{"type": "library", "name": "ArduinoJson", "version": "7.4.2", "spec": {"owner": "bblanchon", "id": 64, "name": "ArduinoJson", "requirements": null, "uri": null}}

View File

@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2025, Benoit BLANCHON
// MIT License
#include "src/ArduinoJson.h"

View File

@ -1,7 +1,7 @@
The MIT License (MIT)
---------------------
Copyright © 2014-2023, Benoit BLANCHON
Copyright © 2014-2025, Benoit BLANCHON
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:

View File

@ -4,13 +4,10 @@
---
[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/bblanchon/ArduinoJson/ci.yml?branch=6.x&logo=github)](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A6.x)
[![Continuous Integration](https://ci.appveyor.com/api/projects/status/m7s53wav1l0abssg/branch/6.x?svg=true)](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/6.x)
[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/bblanchon/ArduinoJson/ci.yml?branch=7.x&logo=github)](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A7.x)
[![Continuous Integration](https://ci.appveyor.com/api/projects/status/m7s53wav1l0abssg/branch/7.x?svg=true)](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/7.x)
[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/arduinojson.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:arduinojson)
[![Coveralls branch](https://img.shields.io/coveralls/github/bblanchon/ArduinoJson/6.x?logo=coveralls)](https://coveralls.io/github/bblanchon/ArduinoJson?branch=6.x)
[![Arduino Library Manager](https://img.shields.io/static/v1?label=Arduino&message=v6.21.5&logo=arduino&logoColor=white&color=blue)](https://www.ardu-badge.com/ArduinoJson/6.21.5)
[![PlatformIO Registry](https://badges.registry.platformio.org/packages/bblanchon/library/ArduinoJson.svg?version=6.21.5)](https://registry.platformio.org/packages/libraries/bblanchon/ArduinoJson?version=6.21.5)
[![ESP IDF](https://img.shields.io/static/v1?label=ESP+IDF&message=v6.21.5&logo=cpu&logoColor=white&color=blue)](https://components.espressif.com/components/bblanchon/arduinojson)
[![Coveralls branch](https://img.shields.io/coveralls/github/bblanchon/ArduinoJson/7.x?logo=coveralls)](https://coveralls.io/github/bblanchon/ArduinoJson?branch=7.x)
[![GitHub stars](https://img.shields.io/github/stars/bblanchon/ArduinoJson?style=flat&logo=github&color=orange)](https://github.com/bblanchon/ArduinoJson/stargazers)
[![GitHub Sponsors](https://img.shields.io/github/sponsors/bblanchon?logo=github&color=orange)](https://github.com/sponsors/bblanchon)
@ -18,31 +15,28 @@ ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things).
## Features
* [JSON deserialization](https://arduinojson.org/v6/api/json/deserializejson/)
* [Optionally decodes UTF-16 escape sequences to UTF-8](https://arduinojson.org/v6/api/config/decode_unicode/)
* [Optionally stores links to the input buffer (zero-copy)](https://arduinojson.org/v6/api/json/deserializejson/)
* [Optionally supports comments in the input](https://arduinojson.org/v6/api/config/enable_comments/)
* [Optionally filters the input to keep only desired values](https://arduinojson.org/v6/api/json/deserializejson/#filtering)
* [JSON deserialization](https://arduinojson.org/v7/api/json/deserializejson/)
* [Optionally decodes UTF-16 escape sequences to UTF-8](https://arduinojson.org/v7/api/config/decode_unicode/)
* [Optionally supports comments in the input](https://arduinojson.org/v7/api/config/enable_comments/)
* [Optionally filters the input to keep only desired values](https://arduinojson.org/v7/api/json/deserializejson/#filtering)
* Supports single quotes as a string delimiter
* Compatible with [NDJSON](http://ndjson.org/) and [JSON Lines](https://jsonlines.org/)
* [JSON serialization](https://arduinojson.org/v6/api/json/serializejson/)
* [Can write to a buffer or a stream](https://arduinojson.org/v6/api/json/serializejson/)
* [Optionally indents the document (prettified JSON)](https://arduinojson.org/v6/api/json/serializejsonpretty/)
* [MessagePack serialization](https://arduinojson.org/v6/api/msgpack/serializemsgpack/)
* [MessagePack deserialization](https://arduinojson.org/v6/api/msgpack/deserializemsgpack/)
* [JSON serialization](https://arduinojson.org/v7/api/json/serializejson/)
* [Can write to a buffer or a stream](https://arduinojson.org/v7/api/json/serializejson/)
* [Optionally indents the document (prettified JSON)](https://arduinojson.org/v7/api/json/serializejsonpretty/)
* [MessagePack serialization](https://arduinojson.org/v7/api/msgpack/serializemsgpack/)
* [MessagePack deserialization](https://arduinojson.org/v7/api/msgpack/deserializemsgpack/)
* Efficient
* [Twice smaller than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/)
* [Almost 10% faster than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/)
* [Consumes roughly 10% less RAM than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/)
* [Fixed memory allocation, no heap fragmentation](https://arduinojson.org/v6/api/jsondocument/)
* [Optionally works without heap memory (zero malloc)](https://arduinojson.org/v6/api/staticjsondocument/)
* [Deduplicates strings](https://arduinojson.org/news/2020/08/01/version-6-16-0/)
* Versatile
* Supports [custom allocators (to use external RAM chip, for example)](https://arduinojson.org/v6/how-to/use-external-ram-on-esp32/)
* Supports [`String`](https://arduinojson.org/v6/api/config/enable_arduino_string/), [`std::string`](https://arduinojson.org/v6/api/config/enable_std_string/), and [`std::string_view`](https://arduinojson.org/v6/api/config/enable_string_view/)
* Supports [`Stream`](https://arduinojson.org/v6/api/config/enable_arduino_stream/) and [`std::istream`/`std::ostream`](https://arduinojson.org/v6/api/config/enable_std_stream/)
* Supports [Flash strings](https://arduinojson.org/v6/api/config/enable_progmem/)
* Supports [custom readers](https://arduinojson.org/v6/api/json/deserializejson/#custom-reader) and [custom writers](https://arduinojson.org/v6/api/json/serializejson/#custom-writer)
* Supports [custom allocators (to use external RAM chip, for example)](https://arduinojson.org/v7/how-to/use-external-ram-on-esp32/)
* Supports [`String`](https://arduinojson.org/v7/api/config/enable_arduino_string/), [`std::string`](https://arduinojson.org/v7/api/config/enable_std_string/), and [`std::string_view`](https://arduinojson.org/v7/api/config/enable_string_view/)
* Supports [`Stream`](https://arduinojson.org/v7/api/config/enable_arduino_stream/) and [`std::istream`/`std::ostream`](https://arduinojson.org/v7/api/config/enable_std_stream/)
* Supports [Flash strings](https://arduinojson.org/v7/api/config/enable_progmem/)
* Supports [custom readers](https://arduinojson.org/v7/api/json/deserializejson/#custom-reader) and [custom writers](https://arduinojson.org/v7/api/json/serializejson/#custom-writer)
* Supports [custom converters](https://arduinojson.org/news/2021/05/04/version-6-18-0/)
* Portable
* Usable on any C++ project (not limited to Arduino)
@ -72,29 +66,29 @@ ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things).
* [Visual Micro](http://www.visualmicro.com/)
* [Visual Studio](https://www.visualstudio.com/)
* [Even works with online compilers like wandbox.org](https://wandbox.org/permlink/RlZSKy17DjJ6HcdN)
* [CMake friendly](https://arduinojson.org/v6/how-to/use-arduinojson-with-cmake/)
* [CMake friendly](https://arduinojson.org/v7/how-to/use-arduinojson-with-cmake/)
* Well designed
* [Elegant API](http://arduinojson.org/v6/example/)
* [Elegant API](http://arduinojson.org/v7/example/)
* [Thread-safe](https://en.wikipedia.org/wiki/Thread_safety)
* Self-contained (no external dependency)
* `const` friendly
* [`for` friendly](https://arduinojson.org/v6/api/jsonobject/begin_end/)
* [`for` friendly](https://arduinojson.org/v7/api/jsonobject/begin_end/)
* [TMP friendly](https://en.wikipedia.org/wiki/Template_metaprogramming)
* Handles [integer overflows](https://arduinojson.org/v6/api/jsonvariant/as/#integer-overflows)
* Handles [integer overflows](https://arduinojson.org/v7/api/jsonvariant/as/#integer-overflows)
* Well tested
* [Unit test coverage close to 100%](https://coveralls.io/github/bblanchon/ArduinoJson?branch=6.x)
* [Unit test coverage close to 100%](https://coveralls.io/github/bblanchon/ArduinoJson?branch=7.x)
* Continuously tested on
* [Visual Studio 2017, 2019, 2022](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/6.x)
* [GCC 5, 6, 7, 8, 9, 10, 11](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22)
* [Clang 3.8, 3.9, 4.0, 5.0, 6.0, 7, 8, 9, 10](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22)
* [Visual Studio 2017, 2019, 2022](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/7.x)
* [GCC 4.8, 5, 6, 7, 8, 9, 10, 11, 12](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22)
* [Clang 7 to 19](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22)
* [Continuously fuzzed with Google OSS Fuzz](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:arduinojson)
* Passes all default checks of [clang-tidy](https://releases.llvm.org/10.0.0/tools/clang/tools/extra/docs/clang-tidy/)
* Well documented
* [Tutorials](https://arduinojson.org/v6/doc/deserialization/)
* [Examples](https://arduinojson.org/v6/example/)
* [How-tos](https://arduinojson.org/v6/example/)
* [FAQ](https://arduinojson.org/v6/faq/)
* [Troubleshooter](https://arduinojson.org/v6/troubleshooter/)
* [Tutorials](https://arduinojson.org/v7/doc/deserialization/)
* [Examples](https://arduinojson.org/v7/example/)
* [How-tos](https://arduinojson.org/v7/example/)
* [FAQ](https://arduinojson.org/v7/faq/)
* [Troubleshooter](https://arduinojson.org/v7/troubleshooter/)
* [Book](https://arduinojson.org/book/)
* [Changelog](CHANGELOG.md)
* Vibrant user community
@ -109,9 +103,9 @@ ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things).
Here is a program that parses a JSON document with ArduinoJson.
```c++
char json[] = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
const char* json = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
DynamicJsonDocument doc(1024);
JsonDocument doc;
deserializeJson(doc, json);
const char* sensor = doc["sensor"];
@ -120,14 +114,14 @@ double latitude = doc["data"][0];
double longitude = doc["data"][1];
```
See the [tutorial on arduinojson.org](https://arduinojson.org/v6/doc/deserialization/)
See the [tutorial on arduinojson.org](https://arduinojson.org/v7/doc/deserialization/)
### Serialization
Here is a program that generates a JSON document with ArduinoJson:
```c++
DynamicJsonDocument doc(1024);
JsonDocument doc;
doc["sensor"] = "gps";
doc["time"] = 1351824120;
@ -139,21 +133,19 @@ serializeJson(doc, Serial);
// {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
```
See the [tutorial on arduinojson.org](https://arduinojson.org/v6/doc/serialization/)
See the [tutorial on arduinojson.org](https://arduinojson.org/v7/doc/serialization/)
## Sponsors
ArduinoJson is thankful to its sponsors. Please give them a visit; they deserve it!
<p>
<a href="https://www.programmingelectronics.com/" rel="sponsored">
<img src="https://arduinojson.org/images/2021/10/programmingeleactronicsacademy.png" alt="Programming Electronics Academy" width="200">
</a>
</p>
<p>
<a href="https://github.com/1technophile" rel="sponsored">
<img alt="1technophile" src="https://avatars.githubusercontent.com/u/12672732?s=40&v=4">
</a>
<a href="https://github.com/LArkema" rel="sponsored">
<img alt="LArkema" src="https://avatars.githubusercontent.com/u/38381313?s=40&v=4">
</a>
</p>
If you run a commercial project that embeds ArduinoJson, think about [sponsoring the library's development](https://github.com/sponsors/bblanchon): it ensures the code that your products rely on stays actively maintained. It can also give your project some exposure to the makers' community.

View File

@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2025, Benoit BLANCHON
// MIT License
//
// This example shows how to store your project configuration in a file.
@ -17,35 +17,28 @@
// * CLK <-> pin 13
// * CS <-> pin 4
//
// https://arduinojson.org/v6/example/config/
// https://arduinojson.org/v7/example/config/
#include <ArduinoJson.h>
#include <SD.h>
#include <SPI.h>
// Our configuration structure.
//
// Never use a JsonDocument to store the configuration!
// A JsonDocument is *not* a permanent storage; it's only a temporary storage
// used during the serialization phase. See:
// https://arduinojson.org/v6/faq/why-must-i-create-a-separate-config-object/
struct Config {
char hostname[64];
int port;
};
const char *filename = "/config.txt"; // <- SD library uses 8.3 filenames
const char* filename = "/config.txt"; // <- SD library uses 8.3 filenames
Config config; // <- global configuration object
// Loads the configuration from a file
void loadConfiguration(const char *filename, Config &config) {
void loadConfiguration(const char* filename, Config& config) {
// Open file for reading
File file = SD.open(filename);
// Allocate a temporary JsonDocument
// Don't forget to change the capacity to match your requirements.
// Use https://arduinojson.org/v6/assistant to compute the capacity.
StaticJsonDocument<512> doc;
JsonDocument doc;
// Deserialize the JSON document
DeserializationError error = deserializeJson(doc, file);
@ -63,7 +56,7 @@ void loadConfiguration(const char *filename, Config &config) {
}
// Saves the configuration to a file
void saveConfiguration(const char *filename, const Config &config) {
void saveConfiguration(const char* filename, const Config& config) {
// Delete existing file, otherwise the configuration is appended to the file
SD.remove(filename);
@ -75,9 +68,7 @@ void saveConfiguration(const char *filename, const Config &config) {
}
// Allocate a temporary JsonDocument
// Don't forget to change the capacity to match your requirements.
// Use https://arduinojson.org/assistant to compute the capacity.
StaticJsonDocument<256> doc;
JsonDocument doc;
// Set the values in the document
doc["hostname"] = config.hostname;
@ -93,7 +84,7 @@ void saveConfiguration(const char *filename, const Config &config) {
}
// Prints the content of a file to the Serial
void printFile(const char *filename) {
void printFile(const char* filename) {
// Open file for reading
File file = SD.open(filename);
if (!file) {
@ -114,7 +105,8 @@ void printFile(const char *filename) {
void setup() {
// Initialize serial port
Serial.begin(9600);
while (!Serial) continue;
while (!Serial)
continue;
// Initialize SD library
const int chipSelect = 4;
@ -144,7 +136,7 @@ void loop() {
// ------------------
//
// File is an unbuffered stream, which is not optimal for ArduinoJson.
// See: https://arduinojson.org/v6/how-to/improve-speed/
// See: https://arduinojson.org/v7/how-to/improve-speed/
// See also
// --------

View File

@ -1,17 +1,18 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2025, Benoit BLANCHON
// MIT License
//
// This example shows how to use DeserializationOption::Filter
//
// https://arduinojson.org/v6/example/filter/
// https://arduinojson.org/v7/example/filter/
#include <ArduinoJson.h>
void setup() {
// Initialize serial port
Serial.begin(9600);
while (!Serial) continue;
while (!Serial)
continue;
// The huge input: an extract from OpenWeatherMap response
auto input_json = F(
@ -33,12 +34,12 @@ void setup() {
"1000000,\"timezone\":0,\"sunrise\":1581492085,\"sunset\":1581527294}}");
// The filter: it contains "true" for each value we want to keep
StaticJsonDocument<200> filter;
JsonDocument filter;
filter["list"][0]["dt"] = true;
filter["list"][0]["main"]["temp"] = true;
// Deserialize the document
StaticJsonDocument<400> doc;
JsonDocument doc;
deserializeJson(doc, input_json, DeserializationOption::Filter(filter));
// Print the result

View File

@ -1,43 +1,32 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2025, Benoit BLANCHON
// MIT License
//
// This example shows how to generate a JSON document with ArduinoJson.
//
// https://arduinojson.org/v6/example/generator/
// https://arduinojson.org/v7/example/generator/
#include <ArduinoJson.h>
void setup() {
// Initialize Serial port
Serial.begin(9600);
while (!Serial) continue;
while (!Serial)
continue;
// Allocate the JSON document
//
// Inside the brackets, 200 is the RAM allocated to this document.
// Don't forget to change this value to match your requirement.
// Use https://arduinojson.org/v6/assistant to compute the capacity.
StaticJsonDocument<200> doc;
// StaticJsonObject allocates memory on the stack, it can be
// replaced by DynamicJsonDocument which allocates in the heap.
//
// DynamicJsonDocument doc(200);
JsonDocument doc;
// Add values in the document
//
doc["sensor"] = "gps";
doc["time"] = 1351824120;
// Add an array.
//
JsonArray data = doc.createNestedArray("data");
// Add an array
JsonArray data = doc["data"].to<JsonArray>();
data.add(48.756080);
data.add(2.302038);
// Generate the minified JSON and send it to the Serial port.
//
// Generate the minified JSON and send it to the Serial port
serializeJson(doc, Serial);
// The above line prints:
// {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
@ -45,8 +34,7 @@ void setup() {
// Start a new line
Serial.println();
// Generate the prettified JSON and send it to the Serial port.
//
// Generate the prettified JSON and send it to the Serial port
serializeJsonPretty(doc, Serial);
// The above line prints:
// {

View File

@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2025, Benoit BLANCHON
// MIT License
//
// This example shows how to parse a JSON document in an HTTP response.
@ -16,7 +16,7 @@
// ]
// }
//
// https://arduinojson.org/v6/example/http-client/
// https://arduinojson.org/v7/example/http-client/
#include <ArduinoJson.h>
#include <Ethernet.h>
@ -25,7 +25,8 @@
void setup() {
// Initialize Serial port
Serial.begin(9600);
while (!Serial) continue;
while (!Serial)
continue;
// Initialize Ethernet library
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
@ -77,9 +78,7 @@ void setup() {
}
// Allocate the JSON document
// Use https://arduinojson.org/v6/assistant to compute the capacity.
const size_t capacity = JSON_OBJECT_SIZE(3) + JSON_ARRAY_SIZE(2) + 60;
DynamicJsonDocument doc(capacity);
JsonDocument doc;
// Parse JSON object
DeserializationError error = deserializeJson(doc, client);
@ -109,7 +108,7 @@ void loop() {
// ------------------
//
// EthernetClient is an unbuffered stream, which is not optimal for ArduinoJson.
// See: https://arduinojson.org/v6/how-to/improve-speed/
// See: https://arduinojson.org/v7/how-to/improve-speed/
// See also
// --------

View File

@ -1,52 +1,37 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2025, Benoit BLANCHON
// MIT License
//
// This example shows how to deserialize a JSON document with ArduinoJson.
//
// https://arduinojson.org/v6/example/parser/
// https://arduinojson.org/v7/example/parser/
#include <ArduinoJson.h>
void setup() {
// Initialize serial port
Serial.begin(9600);
while (!Serial) continue;
while (!Serial)
continue;
// Allocate the JSON document
//
// Inside the brackets, 200 is the capacity of the memory pool in bytes.
// Don't forget to change this value to match your JSON document.
// Use https://arduinojson.org/v6/assistant to compute the capacity.
StaticJsonDocument<200> doc;
// StaticJsonDocument<N> allocates memory on the stack, it can be
// replaced by DynamicJsonDocument which allocates in the heap.
//
// DynamicJsonDocument doc(200);
JsonDocument doc;
// JSON input string.
//
// Using a char[], as shown here, enables the "zero-copy" mode. This mode uses
// the minimal amount of memory because the JsonDocument stores pointers to
// the input buffer.
// If you use another type of input, ArduinoJson must copy the strings from
// the input to the JsonDocument, so you need to increase the capacity of the
// JsonDocument.
char json[] =
const char* json =
"{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
// Deserialize the JSON document
DeserializationError error = deserializeJson(doc, json);
// Test if parsing succeeds.
// Test if parsing succeeds
if (error) {
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
return;
}
// Fetch values.
// Fetch the values
//
// Most of the time, you can rely on the implicit casts.
// In other case, you can do doc["time"].as<long>();
@ -55,7 +40,7 @@ void setup() {
double latitude = doc["data"][0];
double longitude = doc["data"][1];
// Print values.
// Print the values
Serial.println(sensor);
Serial.println(time);
Serial.println(latitude, 6);

View File

@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2025, Benoit BLANCHON
// MIT License
//
// This example shows how to implement an HTTP server that sends a JSON document
@ -13,7 +13,7 @@
// "digital": [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0]
// }
//
// https://arduinojson.org/v6/example/http-server/
// https://arduinojson.org/v7/example/http-server/
#include <ArduinoJson.h>
#include <Ethernet.h>
@ -25,7 +25,8 @@ EthernetServer server(80);
void setup() {
// Initialize serial port
Serial.begin(9600);
while (!Serial) continue;
while (!Serial)
continue;
// Initialize Ethernet libary
if (!Ethernet.begin(mac)) {
@ -52,14 +53,14 @@ void loop() {
Serial.println(F("New client"));
// Read the request (we ignore the content in this example)
while (client.available()) client.read();
while (client.available())
client.read();
// Allocate a temporary JsonDocument
// Use https://arduinojson.org/v6/assistant to compute the capacity.
StaticJsonDocument<500> doc;
JsonDocument doc;
// Create the "analog" array
JsonArray analogValues = doc.createNestedArray("analog");
JsonArray analogValues = doc["analog"].to<JsonArray>();
for (int pin = 0; pin < 6; pin++) {
// Read the analog input
int value = analogRead(pin);
@ -69,7 +70,7 @@ void loop() {
}
// Create the "digital" array
JsonArray digitalValues = doc.createNestedArray("digital");
JsonArray digitalValues = doc["digital"].to<JsonArray>();
for (int pin = 0; pin < 14; pin++) {
// Read the digital input
int value = digitalRead(pin);
@ -101,7 +102,7 @@ void loop() {
// ------------------
//
// EthernetClient is an unbuffered stream, which is not optimal for ArduinoJson.
// See: https://arduinojson.org/v6/how-to/improve-speed/
// See: https://arduinojson.org/v7/how-to/improve-speed/
// See also
// --------

View File

@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2025, Benoit BLANCHON
// MIT License
//
// This example shows how to send a JSON document to a UDP socket.
@ -17,7 +17,7 @@
// $ ncat -ulp 8888
// See https://nmap.org/ncat/
//
// https://arduinojson.org/v6/example/udp-beacon/
// https://arduinojson.org/v7/example/udp-beacon/
#include <ArduinoJson.h>
#include <Ethernet.h>
@ -32,7 +32,8 @@ EthernetUDP udp;
void setup() {
// Initialize serial port
Serial.begin(9600);
while (!Serial) continue;
while (!Serial)
continue;
// Initialize Ethernet libary
if (!Ethernet.begin(mac)) {
@ -46,11 +47,10 @@ void setup() {
void loop() {
// Allocate a temporary JsonDocument
// Use https://arduinojson.org/v6/assistant to compute the capacity.
StaticJsonDocument<500> doc;
JsonDocument doc;
// Create the "analog" array
JsonArray analogValues = doc.createNestedArray("analog");
JsonArray analogValues = doc["analog"].to<JsonArray>();
for (int pin = 0; pin < 6; pin++) {
// Read the analog input
int value = analogRead(pin);
@ -60,7 +60,7 @@ void loop() {
}
// Create the "digital" array
JsonArray digitalValues = doc.createNestedArray("digital");
JsonArray digitalValues = doc["digital"].to<JsonArray>();
for (int pin = 0; pin < 14; pin++) {
// Read the digital input
int value = digitalRead(pin);
@ -90,7 +90,7 @@ void loop() {
// ------------------
//
// EthernetUDP is an unbuffered stream, which is not optimal for ArduinoJson.
// See: https://arduinojson.org/v6/how-to/improve-speed/
// See: https://arduinojson.org/v7/how-to/improve-speed/
// See also
// --------

View File

@ -1,39 +1,24 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2025, Benoit BLANCHON
// MIT License
//
// This example shows how to deserialize a MessagePack document with
// ArduinoJson.
//
// https://arduinojson.org/v6/example/msgpack-parser/
// https://arduinojson.org/v7/example/msgpack-parser/
#include <ArduinoJson.h>
void setup() {
// Initialize serial port
Serial.begin(9600);
while (!Serial) continue;
while (!Serial)
continue;
// Allocate the JSON document
//
// Inside the brackets, 200 is the capacity of the memory pool in bytes.
// Don't forget to change this value to match your JSON document.
// Use https://arduinojson.org/v6/assistant to compute the capacity.
StaticJsonDocument<200> doc;
JsonDocument doc;
// StaticJsonObject allocates memory on the stack, it can be
// replaced by DynamicJsonObject which allocates in the heap.
//
// DynamicJsonObject doc(200);
// MessagePack input string.
//
// Using a char[], as shown here, enables the "zero-copy" mode. This mode uses
// the minimal amount of memory because the JsonDocument stores pointers to
// the input buffer.
// If you use another type of input, ArduinoJson must copy the strings from
// the input to the JsonDocument, so you need to increase the capacity of the
// JsonDocument.
// The MessagePack input string
uint8_t input[] = {131, 166, 115, 101, 110, 115, 111, 114, 163, 103, 112, 115,
164, 116, 105, 109, 101, 206, 80, 147, 50, 248, 164, 100,
97, 116, 97, 146, 203, 64, 72, 96, 199, 58, 188, 148,
@ -45,16 +30,17 @@ void setup() {
// "data": [48.75608, 2.302038]
// }
// Parse the input
DeserializationError error = deserializeMsgPack(doc, input);
// Test if parsing succeeded.
// Test if parsing succeeded
if (error) {
Serial.print("deserializeMsgPack() failed: ");
Serial.println(error.f_str());
return;
}
// Fetch values.
// Fetch the values
//
// Most of the time, you can rely on the implicit casts.
// In other case, you can do doc["time"].as<long>();
@ -63,7 +49,7 @@ void setup() {
double latitude = doc["data"][0];
double longitude = doc["data"][1];
// Print values.
// Print the values
Serial.println(sensor);
Serial.println(time);
Serial.println(latitude, 6);

View File

@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2025, Benoit BLANCHON
// MIT License
//
// This example shows the different ways you can use Flash strings with
@ -9,12 +9,12 @@
// JsonDocument. Prefer plain old char*, as they are more efficient in term of
// code size, speed, and memory usage.
//
// https://arduinojson.org/v6/example/progmem/
// https://arduinojson.org/v7/example/progmem/
#include <ArduinoJson.h>
void setup() {
DynamicJsonDocument doc(1024);
JsonDocument doc;
// You can use a Flash String as your JSON input.
// WARNING: the strings in the input will be duplicated in the JsonDocument.

View File

@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2025, Benoit BLANCHON
// MIT License
//
// This example shows the different ways you can use String with ArduinoJson.
@ -8,12 +8,12 @@
// JsonDocument. Prefer plain old char[], as they are more efficient in term of
// code size, speed, and memory usage.
//
// https://arduinojson.org/v6/example/string/
// https://arduinojson.org/v7/example/string/
#include <ArduinoJson.h>
void setup() {
DynamicJsonDocument doc(1024);
JsonDocument doc;
// You can use a String as your JSON input.
// WARNING: the string in the input will be duplicated in the JsonDocument.
@ -55,7 +55,6 @@ void setup() {
}
// Lastly, you can print the resulting JSON to a String
// WARNING: it doesn't replace the content but appends to it
String output;
serializeJson(doc, output);
}

View File

@ -1,13 +1,13 @@
{
"name": "ArduinoJson",
"keywords": "json, rest, http, web",
"description": "A simple and efficient JSON library for embedded C++. ArduinoJson supports serialization, deserialization, MessagePack, ✔ fixed allocation, ✔ zero-copy, ✔ streams, filtering, and more. It is the most popular Arduino library on GitHub ❤❤❤❤❤. Check out arduinojson.org for a comprehensive documentation.",
"description": "A simple and efficient JSON library for embedded C++. ⭐ 6953 stars on GitHub! Supports serialization, deserialization, MessagePack, streams, filtering, and more. Fully tested and documented.",
"homepage": "https://arduinojson.org/?utm_source=meta&utm_medium=library.json",
"repository": {
"type": "git",
"url": "https://github.com/bblanchon/ArduinoJson.git"
},
"version": "6.21.5",
"version": "7.4.2",
"authors": {
"name": "Benoit Blanchon",
"url": "https://blog.benoitblanchon.fr"

View File

@ -1,9 +1,9 @@
name=ArduinoJson
version=6.21.5
version=7.4.2
author=Benoit Blanchon <blog.benoitblanchon.fr>
maintainer=Benoit Blanchon <blog.benoitblanchon.fr>
sentence=A simple and efficient JSON library for embedded C++.
paragraph=ArduinoJson supports serialization, deserialization, MessagePack, ✔ fixed allocation, ✔ zero-copy, ✔ streams, filtering, and more. It is the most popular Arduino library on GitHub ❤❤❤❤❤. Check out arduinojson.org for a comprehensive documentation.
paragraph=⭐ 6953 stars on GitHub! Supports serialization, deserialization, MessagePack, streams, filtering, and more. Fully tested and documented.
category=Data Processing
url=https://arduinojson.org/?utm_source=meta&utm_medium=library.properties
architectures=*

View File

@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2025, Benoit BLANCHON
// MIT License
#pragma once

View File

@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2025, Benoit BLANCHON
// MIT License
#pragma once
@ -26,27 +26,40 @@
# endif
#endif
// Remove true and false macros defined by some cores, such as Arduino Due's
// See issues #2181 and arduino/ArduinoCore-sam#50
#ifdef true
# undef true
#endif
#ifdef false
# undef false
#endif
#include "ArduinoJson/Array/JsonArray.hpp"
#include "ArduinoJson/Object/JsonObject.hpp"
#include "ArduinoJson/Variant/JsonVariantConst.hpp"
#include "ArduinoJson/Document/DynamicJsonDocument.hpp"
#include "ArduinoJson/Document/StaticJsonDocument.hpp"
#include "ArduinoJson/Document/JsonDocument.hpp"
#include "ArduinoJson/Array/ArrayImpl.hpp"
#include "ArduinoJson/Array/ElementProxy.hpp"
#include "ArduinoJson/Array/JsonArrayImpl.hpp"
#include "ArduinoJson/Array/Utilities.hpp"
#include "ArduinoJson/Collection/CollectionImpl.hpp"
#include "ArduinoJson/Object/JsonObjectImpl.hpp"
#include "ArduinoJson/Memory/ResourceManagerImpl.hpp"
#include "ArduinoJson/Object/MemberProxy.hpp"
#include "ArduinoJson/Object/ObjectImpl.hpp"
#include "ArduinoJson/Variant/ConverterImpl.hpp"
#include "ArduinoJson/Variant/JsonVariantCopier.hpp"
#include "ArduinoJson/Variant/VariantCompare.hpp"
#include "ArduinoJson/Variant/VariantImpl.hpp"
#include "ArduinoJson/Variant/VariantRefBaseImpl.hpp"
#include "ArduinoJson/Json/JsonDeserializer.hpp"
#include "ArduinoJson/Json/JsonSerializer.hpp"
#include "ArduinoJson/Json/PrettyJsonSerializer.hpp"
#include "ArduinoJson/MsgPack/MsgPackBinary.hpp"
#include "ArduinoJson/MsgPack/MsgPackDeserializer.hpp"
#include "ArduinoJson/MsgPack/MsgPackExtension.hpp"
#include "ArduinoJson/MsgPack/MsgPackSerializer.hpp"
#include "ArduinoJson/compatibility.hpp"

View File

@ -0,0 +1,66 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2025, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Collection/CollectionData.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
class ArrayData : public CollectionData {
public:
VariantData* addElement(ResourceManager* resources);
static VariantData* addElement(ArrayData* array, ResourceManager* resources) {
if (!array)
return nullptr;
return array->addElement(resources);
}
template <typename T>
bool addValue(const T& value, ResourceManager* resources);
template <typename T>
static bool addValue(ArrayData* array, const T& value,
ResourceManager* resources) {
if (!array)
return false;
return array->addValue(value, resources);
}
VariantData* getOrAddElement(size_t index, ResourceManager* resources);
VariantData* getElement(size_t index, const ResourceManager* resources) const;
static VariantData* getElement(const ArrayData* array, size_t index,
const ResourceManager* resources) {
if (!array)
return nullptr;
return array->getElement(index, resources);
}
void removeElement(size_t index, ResourceManager* resources);
static void removeElement(ArrayData* array, size_t index,
ResourceManager* resources) {
if (!array)
return;
array->removeElement(index, resources);
}
void remove(iterator it, ResourceManager* resources) {
CollectionData::removeOne(it, resources);
}
static void remove(ArrayData* array, iterator it,
ResourceManager* resources) {
if (array)
return array->remove(it, resources);
}
private:
iterator at(size_t index, const ResourceManager* resources) const;
};
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@ -0,0 +1,79 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2025, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Array/ArrayData.hpp>
#include <ArduinoJson/Variant/VariantCompare.hpp>
#include <ArduinoJson/Variant/VariantData.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
inline ArrayData::iterator ArrayData::at(
size_t index, const ResourceManager* resources) const {
auto it = createIterator(resources);
while (!it.done() && index) {
it.next(resources);
--index;
}
return it;
}
inline VariantData* ArrayData::addElement(ResourceManager* resources) {
auto slot = resources->allocVariant();
if (!slot)
return nullptr;
CollectionData::appendOne(slot, resources);
return slot.ptr();
}
inline VariantData* ArrayData::getOrAddElement(size_t index,
ResourceManager* resources) {
auto it = createIterator(resources);
while (!it.done() && index > 0) {
it.next(resources);
index--;
}
if (it.done())
index++;
VariantData* element = it.data();
while (index > 0) {
element = addElement(resources);
if (!element)
return nullptr;
index--;
}
return element;
}
inline VariantData* ArrayData::getElement(
size_t index, const ResourceManager* resources) const {
return at(index, resources).data();
}
inline void ArrayData::removeElement(size_t index, ResourceManager* resources) {
remove(at(index, resources), resources);
}
template <typename T>
inline bool ArrayData::addValue(const T& value, ResourceManager* resources) {
ARDUINOJSON_ASSERT(resources != nullptr);
auto slot = resources->allocVariant();
if (!slot)
return false;
JsonVariant variant(slot.ptr(), resources);
if (!variant.set(value)) {
resources->freeVariant(slot);
return false;
}
CollectionData::appendOne(slot, resources);
return true;
}
// Returns the size (in bytes) of an array with n elements.
constexpr size_t sizeofArray(size_t n) {
return n * ResourceManager::slotSize;
}
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2025, Benoit BLANCHON
// MIT License
#pragma once
@ -9,48 +9,63 @@
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
// A proxy class to get or set an element of an array.
// https://arduinojson.org/v6/api/jsonarray/subscript/
// https://arduinojson.org/v7/api/jsonarray/subscript/
template <typename TUpstream>
class ElementProxy : public VariantRefBase<ElementProxy<TUpstream>>,
public VariantOperators<ElementProxy<TUpstream>> {
friend class VariantAttorney;
friend class VariantRefBase<ElementProxy<TUpstream>>;
template <typename, typename>
friend class MemberProxy;
template <typename>
friend class ElementProxy;
public:
ElementProxy(TUpstream upstream, size_t index)
: upstream_(upstream), index_(index) {}
ElementProxy(const ElementProxy& src)
: upstream_(src.upstream_), index_(src.index_) {}
FORCE_INLINE ElementProxy& operator=(const ElementProxy& src) {
ElementProxy& operator=(const ElementProxy& src) {
this->set(src);
return *this;
}
template <typename T>
FORCE_INLINE ElementProxy& operator=(const T& src) {
ElementProxy& operator=(const T& src) {
this->set(src);
return *this;
}
template <typename T>
FORCE_INLINE ElementProxy& operator=(T* src) {
ElementProxy& operator=(T* src) {
this->set(src);
return *this;
}
private:
FORCE_INLINE MemoryPool* getPool() const {
return VariantAttorney::getPool(upstream_);
// clang-format off
ElementProxy(const ElementProxy& src) // Error here? See https://arduinojson.org/v7/proxy-non-copyable/
: upstream_(src.upstream_), index_(src.index_) {}
// clang-format on
ResourceManager* getResourceManager() const {
return VariantAttorney::getResourceManager(upstream_);
}
FORCE_INLINE VariantData* getData() const {
return variantGetElement(VariantAttorney::getData(upstream_), index_);
return VariantData::getElement(
VariantAttorney::getData(upstream_), index_,
VariantAttorney::getResourceManager(upstream_));
}
FORCE_INLINE VariantData* getOrCreateData() const {
return variantGetOrAddElement(VariantAttorney::getOrCreateData(upstream_),
index_, VariantAttorney::getPool(upstream_));
VariantData* getOrCreateData() const {
auto data = VariantAttorney::getOrCreateData(upstream_);
if (!data)
return nullptr;
return data->getOrAddElement(
index_, VariantAttorney::getResourceManager(upstream_));
}
TUpstream upstream_;

View File

@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2025, Benoit BLANCHON
// MIT License
#pragma once
@ -12,163 +12,196 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
class JsonObject;
// A reference to an array in a JsonDocument
// https://arduinojson.org/v6/api/jsonarray/
// https://arduinojson.org/v7/api/jsonarray/
class JsonArray : public detail::VariantOperators<JsonArray> {
friend class detail::VariantAttorney;
public:
typedef JsonArrayIterator iterator;
using iterator = JsonArrayIterator;
// Constructs an unbound reference.
FORCE_INLINE JsonArray() : data_(0), pool_(0) {}
JsonArray() : data_(0), resources_(0) {}
// INTERNAL USE ONLY
FORCE_INLINE JsonArray(detail::MemoryPool* pool, detail::CollectionData* data)
: data_(data), pool_(pool) {}
JsonArray(detail::ArrayData* data, detail::ResourceManager* resources)
: data_(data), resources_(resources) {}
// Returns a JsonVariant pointing to the array.
// https://arduinojson.org/v6/api/jsonvariant/
// https://arduinojson.org/v7/api/jsonvariant/
operator JsonVariant() {
void* data = data_; // prevent warning cast-align
return JsonVariant(pool_, reinterpret_cast<detail::VariantData*>(data));
return JsonVariant(reinterpret_cast<detail::VariantData*>(data),
resources_);
}
// Returns a read-only reference to the array.
// https://arduinojson.org/v6/api/jsonarrayconst/
// https://arduinojson.org/v7/api/jsonarrayconst/
operator JsonArrayConst() const {
return JsonArrayConst(data_);
return JsonArrayConst(data_, resources_);
}
// Appends a new (empty) element to the array.
// Returns a reference to the new element.
// https://arduinojson.org/v7/api/jsonarray/add/
template <typename T, detail::enable_if_t<
!detail::is_same<T, JsonVariant>::value, int> = 0>
T add() const {
return add<JsonVariant>().to<T>();
}
// Appends a new (null) element to the array.
// Returns a reference to the new element.
// https://arduinojson.org/v6/api/jsonarray/add/
// https://arduinojson.org/v7/api/jsonarray/add/
template <typename T, detail::enable_if_t<
detail::is_same<T, JsonVariant>::value, int> = 0>
JsonVariant add() const {
if (!data_)
return JsonVariant();
return JsonVariant(pool_, data_->addElement(pool_));
return JsonVariant(detail::ArrayData::addElement(data_, resources_),
resources_);
}
// Appends a value to the array.
// https://arduinojson.org/v6/api/jsonarray/add/
// https://arduinojson.org/v7/api/jsonarray/add/
template <typename T>
FORCE_INLINE bool add(const T& value) const {
return add().set(value);
bool add(const T& value) const {
return detail::ArrayData::addValue(data_, value, resources_);
}
// Appends a value to the array.
// https://arduinojson.org/v6/api/jsonarray/add/
template <typename T>
FORCE_INLINE bool add(T* value) const {
return add().set(value);
// https://arduinojson.org/v7/api/jsonarray/add/
template <typename T,
detail::enable_if_t<!detail::is_const<T>::value, int> = 0>
bool add(T* value) const {
return detail::ArrayData::addValue(data_, value, resources_);
}
// Returns an iterator to the first element of the array.
// https://arduinojson.org/v6/api/jsonarray/begin/
FORCE_INLINE iterator begin() const {
// https://arduinojson.org/v7/api/jsonarray/begin/
iterator begin() const {
if (!data_)
return iterator();
return iterator(pool_, data_->head());
return iterator(data_->createIterator(resources_), resources_);
}
// Returns an iterator following the last element of the array.
// https://arduinojson.org/v6/api/jsonarray/end/
FORCE_INLINE iterator end() const {
// https://arduinojson.org/v7/api/jsonarray/end/
iterator end() const {
return iterator();
}
// Copies an array.
// https://arduinojson.org/v6/api/jsonarray/set/
FORCE_INLINE bool set(JsonArrayConst src) const {
if (!data_ || !src.data_)
// https://arduinojson.org/v7/api/jsonarray/set/
bool set(JsonArrayConst src) const {
if (!data_)
return false;
return data_->copyFrom(*src.data_, pool_);
}
// Compares the content of two arrays.
FORCE_INLINE bool operator==(JsonArray rhs) const {
return JsonArrayConst(data_) == JsonArrayConst(rhs.data_);
clear();
for (auto element : src) {
if (!add(element))
return false;
}
return true;
}
// Removes the element at the specified iterator.
// ⚠️ Doesn't release the memory associated with the removed element.
// https://arduinojson.org/v6/api/jsonarray/remove/
FORCE_INLINE void remove(iterator it) const {
if (!data_)
return;
data_->removeSlot(it.slot_);
// https://arduinojson.org/v7/api/jsonarray/remove/
void remove(iterator it) const {
detail::ArrayData::remove(data_, it.iterator_, resources_);
}
// Removes the element at the specified index.
// ⚠️ Doesn't release the memory associated with the removed element.
// https://arduinojson.org/v6/api/jsonarray/remove/
FORCE_INLINE void remove(size_t index) const {
if (!data_)
return;
data_->removeElement(index);
// https://arduinojson.org/v7/api/jsonarray/remove/
void remove(size_t index) const {
detail::ArrayData::removeElement(data_, index, resources_);
}
// Removes the element at the specified index.
// https://arduinojson.org/v7/api/jsonarray/remove/
template <typename TVariant,
detail::enable_if_t<detail::IsVariant<TVariant>::value, int> = 0>
void remove(const TVariant& variant) const {
if (variant.template is<size_t>())
remove(variant.template as<size_t>());
}
// Removes all the elements of the array.
// ⚠️ Doesn't release the memory associated with the removed elements.
// https://arduinojson.org/v6/api/jsonarray/clear/
// https://arduinojson.org/v7/api/jsonarray/clear/
void clear() const {
if (!data_)
return;
data_->clear();
detail::ArrayData::clear(data_, resources_);
}
// Gets or sets the element at the specified index.
// https://arduinojson.org/v6/api/jsonarray/subscript/
FORCE_INLINE detail::ElementProxy<JsonArray> operator[](size_t index) const {
return {*this, index};
// https://arduinojson.org/v7/api/jsonarray/subscript/
template <typename T,
detail::enable_if_t<detail::is_integral<T>::value, int> = 0>
detail::ElementProxy<JsonArray> operator[](T index) const {
return {*this, size_t(index)};
}
// Creates an object and appends it to the array.
// https://arduinojson.org/v6/api/jsonarray/createnestedobject/
FORCE_INLINE JsonObject createNestedObject() const;
// Creates an array and appends it to the array.
// https://arduinojson.org/v6/api/jsonarray/createnestedarray/
FORCE_INLINE JsonArray createNestedArray() const {
return add().to<JsonArray>();
// Gets or sets the element at the specified index.
// https://arduinojson.org/v7/api/jsonarray/subscript/
template <typename TVariant,
detail::enable_if_t<detail::IsVariant<TVariant>::value, int> = 0>
detail::ElementProxy<JsonArray> operator[](const TVariant& variant) const {
if (variant.template is<size_t>())
return {*this, variant.template as<size_t>()};
else
return {*this, size_t(-1)};
}
operator JsonVariantConst() const {
return JsonVariantConst(collectionToVariant(data_));
return JsonVariantConst(collectionToVariant(data_), resources_);
}
// Returns true if the reference is unbound.
// https://arduinojson.org/v6/api/jsonarray/isnull/
FORCE_INLINE bool isNull() const {
// https://arduinojson.org/v7/api/jsonarray/isnull/
bool isNull() const {
return data_ == 0;
}
// Returns true if the reference is bound.
// https://arduinojson.org/v6/api/jsonarray/isnull/
FORCE_INLINE operator bool() const {
// https://arduinojson.org/v7/api/jsonarray/isnull/
operator bool() const {
return data_ != 0;
}
// Returns the number of bytes occupied by the array.
// https://arduinojson.org/v6/api/jsonarray/memoryusage/
FORCE_INLINE size_t memoryUsage() const {
return data_ ? data_->memoryUsage() : 0;
}
// Returns the depth (nesting level) of the array.
// https://arduinojson.org/v6/api/jsonarray/nesting/
FORCE_INLINE size_t nesting() const {
return variantNesting(collectionToVariant(data_));
// https://arduinojson.org/v7/api/jsonarray/nesting/
size_t nesting() const {
return detail::VariantData::nesting(collectionToVariant(data_), resources_);
}
// Returns the number of elements in the array.
// https://arduinojson.org/v6/api/jsonarray/size/
FORCE_INLINE size_t size() const {
return data_ ? data_->size() : 0;
// https://arduinojson.org/v7/api/jsonarray/size/
size_t size() const {
return data_ ? data_->size(resources_) : 0;
}
// DEPRECATED: use add<JsonVariant>() instead
ARDUINOJSON_DEPRECATED("use add<JsonVariant>() instead")
JsonVariant add() const {
return add<JsonVariant>();
}
// DEPRECATED: use add<JsonArray>() instead
ARDUINOJSON_DEPRECATED("use add<JsonArray>() instead")
JsonArray createNestedArray() const {
return add<JsonArray>();
}
// DEPRECATED: use add<JsonObject>() instead
ARDUINOJSON_DEPRECATED("use add<JsonObject>() instead")
JsonObject createNestedObject() const;
// DEPRECATED: always returns zero
ARDUINOJSON_DEPRECATED("always returns zero")
size_t memoryUsage() const {
return 0;
}
private:
detail::MemoryPool* getPool() const {
return pool_;
detail::ResourceManager* getResourceManager() const {
return resources_;
}
detail::VariantData* getData() const {
@ -179,33 +212,8 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
return collectionToVariant(data_);
}
detail::CollectionData* data_;
detail::MemoryPool* pool_;
};
template <>
struct Converter<JsonArray> : private detail::VariantAttorney {
static void toJson(JsonVariantConst src, JsonVariant dst) {
variantCopyFrom(getData(dst), getData(src), getPool(dst));
}
static JsonArray fromJson(JsonVariant src) {
auto data = getData(src);
auto pool = getPool(src);
return JsonArray(pool, data != 0 ? data->asArray() : 0);
}
static detail::InvalidConversion<JsonVariantConst, JsonArray> fromJson(
JsonVariantConst);
static bool checkJson(JsonVariantConst) {
return false;
}
static bool checkJson(JsonVariant src) {
auto data = getData(src);
return data && data->isArray();
}
detail::ArrayData* data_;
detail::ResourceManager* resources_;
};
ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2025, Benoit BLANCHON
// MIT License
#pragma once
@ -13,98 +13,89 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
class JsonObject;
// A read-only reference to an array in a JsonDocument
// https://arduinojson.org/v6/api/jsonarrayconst/
// https://arduinojson.org/v7/api/jsonarrayconst/
class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
friend class JsonArray;
friend class detail::VariantAttorney;
public:
typedef JsonArrayConstIterator iterator;
using iterator = JsonArrayConstIterator;
// Returns an iterator to the first element of the array.
// https://arduinojson.org/v6/api/jsonarrayconst/begin/
FORCE_INLINE iterator begin() const {
// https://arduinojson.org/v7/api/jsonarrayconst/begin/
iterator begin() const {
if (!data_)
return iterator();
return iterator(data_->head());
return iterator(data_->createIterator(resources_), resources_);
}
// Returns an iterator to the element following the last element of the array.
// https://arduinojson.org/v6/api/jsonarrayconst/end/
FORCE_INLINE iterator end() const {
// https://arduinojson.org/v7/api/jsonarrayconst/end/
iterator end() const {
return iterator();
}
// Creates an unbound reference.
FORCE_INLINE JsonArrayConst() : data_(0) {}
JsonArrayConst() : data_(0), resources_(0) {}
// INTERNAL USE ONLY
FORCE_INLINE JsonArrayConst(const detail::CollectionData* data)
: data_(data) {}
JsonArrayConst(const detail::ArrayData* data,
const detail::ResourceManager* resources)
: data_(data), resources_(resources) {}
// Compares the content of two arrays.
// Returns true if the two arrays are equal.
FORCE_INLINE bool operator==(JsonArrayConst rhs) const {
if (data_ == rhs.data_)
return true;
if (!data_ || !rhs.data_)
return false;
iterator it1 = begin();
iterator it2 = rhs.begin();
for (;;) {
bool end1 = it1 == end();
bool end2 = it2 == rhs.end();
if (end1 && end2)
return true;
if (end1 || end2)
return false;
if (*it1 != *it2)
return false;
++it1;
++it2;
}
// Returns the element at the specified index.
// https://arduinojson.org/v7/api/jsonarrayconst/subscript/
template <typename T,
detail::enable_if_t<detail::is_integral<T>::value, int> = 0>
JsonVariantConst operator[](T index) const {
return JsonVariantConst(
detail::ArrayData::getElement(data_, size_t(index), resources_),
resources_);
}
// Returns the element at the specified index.
// https://arduinojson.org/v6/api/jsonarrayconst/subscript/
FORCE_INLINE JsonVariantConst operator[](size_t index) const {
return JsonVariantConst(data_ ? data_->getElement(index) : 0);
// https://arduinojson.org/v7/api/jsonarrayconst/subscript/
template <typename TVariant,
detail::enable_if_t<detail::IsVariant<TVariant>::value, int> = 0>
JsonVariantConst operator[](const TVariant& variant) const {
if (variant.template is<size_t>())
return operator[](variant.template as<size_t>());
else
return JsonVariantConst();
}
operator JsonVariantConst() const {
return JsonVariantConst(collectionToVariant(data_));
return JsonVariantConst(getData(), resources_);
}
// Returns true if the reference is unbound.
// https://arduinojson.org/v6/api/jsonarrayconst/isnull/
FORCE_INLINE bool isNull() const {
// https://arduinojson.org/v7/api/jsonarrayconst/isnull/
bool isNull() const {
return data_ == 0;
}
// Returns true if the reference is bound.
// https://arduinojson.org/v6/api/jsonarrayconst/isnull/
FORCE_INLINE operator bool() const {
// https://arduinojson.org/v7/api/jsonarrayconst/isnull/
operator bool() const {
return data_ != 0;
}
// Returns the number of bytes occupied by the array.
// https://arduinojson.org/v6/api/jsonarrayconst/memoryusage/
FORCE_INLINE size_t memoryUsage() const {
return data_ ? data_->memoryUsage() : 0;
}
// Returns the depth (nesting level) of the array.
// https://arduinojson.org/v6/api/jsonarrayconst/nesting/
FORCE_INLINE size_t nesting() const {
return variantNesting(collectionToVariant(data_));
// https://arduinojson.org/v7/api/jsonarrayconst/nesting/
size_t nesting() const {
return detail::VariantData::nesting(getData(), resources_);
}
// Returns the number of elements in the array.
// https://arduinojson.org/v6/api/jsonarrayconst/size/
FORCE_INLINE size_t size() const {
return data_ ? data_->size() : 0;
// https://arduinojson.org/v7/api/jsonarrayconst/size/
size_t size() const {
return data_ ? data_->size(resources_) : 0;
}
// DEPRECATED: always returns zero
ARDUINOJSON_DEPRECATED("always returns zero")
size_t memoryUsage() const {
return 0;
}
private:
@ -112,24 +103,31 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
return collectionToVariant(data_);
}
const detail::CollectionData* data_;
const detail::ArrayData* data_;
const detail::ResourceManager* resources_;
};
template <>
struct Converter<JsonArrayConst> : private detail::VariantAttorney {
static void toJson(JsonVariantConst src, JsonVariant dst) {
variantCopyFrom(getData(dst), getData(src), getPool(dst));
}
// Compares the content of two arrays.
// Returns true if the two arrays are equal.
inline bool operator==(JsonArrayConst lhs, JsonArrayConst rhs) {
if (!lhs && !rhs)
return true;
if (!lhs || !rhs)
return false;
static JsonArrayConst fromJson(JsonVariantConst src) {
auto data = getData(src);
return data ? data->asArray() : 0;
}
auto a = lhs.begin();
auto b = rhs.begin();
static bool checkJson(JsonVariantConst src) {
auto data = getData(src);
return data && data->isArray();
for (;;) {
if (a == b) // same pointer or both null
return true;
if (a == lhs.end() || b == rhs.end())
return false;
if (*a != *b)
return false;
++a;
++b;
}
};
}
ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@ -1,36 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Array/JsonArray.hpp>
#include <ArduinoJson/Object/JsonObject.hpp>
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
inline JsonObject JsonArray::createNestedObject() const {
return add().to<JsonObject>();
}
ARDUINOJSON_END_PUBLIC_NAMESPACE
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <typename TDerived>
inline JsonArray VariantRefBase<TDerived>::createNestedArray() const {
return add().template to<JsonArray>();
}
template <typename TDerived>
inline JsonObject VariantRefBase<TDerived>::createNestedObject() const {
return add().template to<JsonObject>();
}
template <typename TDerived>
inline ElementProxy<TDerived> VariantRefBase<TDerived>::operator[](
size_t index) const {
return ElementProxy<TDerived>(derived(), index);
}
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@ -1,121 +1,96 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2025, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Variant/JsonVariant.hpp>
#include <ArduinoJson/Variant/SlotFunctions.hpp>
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
class VariantPtr {
template <typename T>
class Ptr {
public:
VariantPtr(detail::MemoryPool* pool, detail::VariantData* data)
: variant_(pool, data) {}
Ptr(T value) : value_(value) {}
JsonVariant* operator->() {
return &variant_;
T* operator->() {
return &value_;
}
JsonVariant& operator*() {
return variant_;
T& operator*() {
return value_;
}
private:
JsonVariant variant_;
T value_;
};
class JsonArrayIterator {
friend class JsonArray;
public:
JsonArrayIterator() : slot_(0) {}
explicit JsonArrayIterator(detail::MemoryPool* pool,
detail::VariantSlot* slot)
: pool_(pool), slot_(slot) {}
JsonArrayIterator() {}
explicit JsonArrayIterator(detail::ArrayData::iterator iterator,
detail::ResourceManager* resources)
: iterator_(iterator), resources_(resources) {}
JsonVariant operator*() const {
return JsonVariant(pool_, slot_->data());
JsonVariant operator*() {
return JsonVariant(iterator_.data(), resources_);
}
VariantPtr operator->() {
return VariantPtr(pool_, slot_->data());
Ptr<JsonVariant> operator->() {
return operator*();
}
bool operator==(const JsonArrayIterator& other) const {
return slot_ == other.slot_;
return iterator_ == other.iterator_;
}
bool operator!=(const JsonArrayIterator& other) const {
return slot_ != other.slot_;
return iterator_ != other.iterator_;
}
JsonArrayIterator& operator++() {
slot_ = slot_->next();
return *this;
}
JsonArrayIterator& operator+=(size_t distance) {
slot_ = slot_->next(distance);
iterator_.next(resources_);
return *this;
}
private:
detail::MemoryPool* pool_;
detail::VariantSlot* slot_;
};
class VariantConstPtr {
public:
VariantConstPtr(const detail::VariantData* data) : variant_(data) {}
JsonVariantConst* operator->() {
return &variant_;
}
JsonVariantConst& operator*() {
return variant_;
}
private:
JsonVariantConst variant_;
detail::ArrayData::iterator iterator_;
detail::ResourceManager* resources_;
};
class JsonArrayConstIterator {
friend class JsonArray;
public:
JsonArrayConstIterator() : slot_(0) {}
explicit JsonArrayConstIterator(const detail::VariantSlot* slot)
: slot_(slot) {}
JsonArrayConstIterator() {}
explicit JsonArrayConstIterator(detail::ArrayData::iterator iterator,
const detail::ResourceManager* resources)
: iterator_(iterator), resources_(resources) {}
JsonVariantConst operator*() const {
return JsonVariantConst(slot_->data());
return JsonVariantConst(iterator_.data(), resources_);
}
VariantConstPtr operator->() {
return VariantConstPtr(slot_->data());
Ptr<JsonVariantConst> operator->() {
return operator*();
}
bool operator==(const JsonArrayConstIterator& other) const {
return slot_ == other.slot_;
return iterator_ == other.iterator_;
}
bool operator!=(const JsonArrayConstIterator& other) const {
return slot_ != other.slot_;
return iterator_ != other.iterator_;
}
JsonArrayConstIterator& operator++() {
slot_ = slot_->next();
return *this;
}
JsonArrayConstIterator& operator+=(size_t distance) {
slot_ = slot_->next(distance);
iterator_.next(resources_);
return *this;
}
private:
const detail::VariantSlot* slot_;
detail::ArrayData::iterator iterator_;
const detail::ResourceManager* resources_;
};
ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2025, Benoit BLANCHON
// MIT License
#pragma once
@ -11,30 +11,29 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
// Copies a value to a JsonVariant.
// This is a degenerated form of copyArray() to stop the recursion.
template <typename T>
inline typename detail::enable_if<!detail::is_array<T>::value, bool>::type
copyArray(const T& src, JsonVariant dst) {
template <typename T, detail::enable_if_t<!detail::is_array<T>::value, int> = 0>
inline bool copyArray(const T& src, JsonVariant dst) {
return dst.set(src);
}
// Copies values from an array to a JsonArray or a JsonVariant.
// https://arduinojson.org/v6/api/misc/copyarray/
template <typename T, size_t N, typename TDestination>
inline typename detail::enable_if<
!detail::is_base_of<JsonDocument, TDestination>::value, bool>::type
copyArray(T (&src)[N], const TDestination& dst) {
// https://arduinojson.org/v7/api/misc/copyarray/
template <typename T, size_t N, typename TDestination,
detail::enable_if_t<
!detail::is_base_of<JsonDocument, TDestination>::value, int> = 0>
inline bool copyArray(T (&src)[N], const TDestination& dst) {
return copyArray(src, N, dst);
}
// Copies values from an array to a JsonArray or a JsonVariant.
// https://arduinojson.org/v6/api/misc/copyarray/
template <typename T, typename TDestination>
inline typename detail::enable_if<
!detail::is_base_of<JsonDocument, TDestination>::value, bool>::type
copyArray(const T* src, size_t len, const TDestination& dst) {
// https://arduinojson.org/v7/api/misc/copyarray/
template <typename T, typename TDestination,
detail::enable_if_t<
!detail::is_base_of<JsonDocument, TDestination>::value, int> = 0>
inline bool copyArray(const T* src, size_t len, const TDestination& dst) {
bool ok = true;
for (size_t i = 0; i < len; i++) {
ok &= copyArray(src[i], dst.add());
ok &= copyArray(src[i], dst.template add<JsonVariant>());
}
return ok;
}
@ -47,14 +46,14 @@ inline bool copyArray(const char* src, size_t, const TDestination& dst) {
}
// Copies values from an array to a JsonDocument.
// https://arduinojson.org/v6/api/misc/copyarray/
// https://arduinojson.org/v7/api/misc/copyarray/
template <typename T>
inline bool copyArray(const T& src, JsonDocument& dst) {
return copyArray(src, dst.to<JsonArray>());
}
// Copies an array to a JsonDocument.
// https://arduinojson.org/v6/api/misc/copyarray/
// https://arduinojson.org/v7/api/misc/copyarray/
template <typename T>
inline bool copyArray(const T* src, size_t len, JsonDocument& dst) {
return copyArray(src, len, dst.to<JsonArray>());
@ -62,22 +61,21 @@ inline bool copyArray(const T* src, size_t len, JsonDocument& dst) {
// Copies a value from a JsonVariant.
// This is a degenerated form of copyArray() to stop the recursion.
template <typename T>
inline typename detail::enable_if<!detail::is_array<T>::value, size_t>::type
copyArray(JsonVariantConst src, T& dst) {
template <typename T, detail::enable_if_t<!detail::is_array<T>::value, int> = 0>
inline size_t copyArray(JsonVariantConst src, T& dst) {
dst = src.as<T>();
return 1;
}
// Copies values from a JsonArray or JsonVariant to an array.
// https://arduinojson.org/v6/api/misc/copyarray/
// https://arduinojson.org/v7/api/misc/copyarray/
template <typename T, size_t N>
inline size_t copyArray(JsonArrayConst src, T (&dst)[N]) {
return copyArray(src, dst, N);
}
// Copies values from a JsonArray or JsonVariant to an array.
// https://arduinojson.org/v6/api/misc/copyarray/
// https://arduinojson.org/v7/api/misc/copyarray/
template <typename T>
inline size_t copyArray(JsonArrayConst src, T* dst, size_t len) {
size_t i = 0;
@ -101,13 +99,13 @@ inline size_t copyArray(JsonVariantConst src, char (&dst)[N]) {
}
// Copies values from a JsonDocument to an array.
// https://arduinojson.org/v6/api/misc/copyarray/
template <typename TSource, typename T>
inline typename detail::enable_if<
detail::is_array<T>::value &&
detail::is_base_of<JsonDocument, TSource>::value,
size_t>::type
copyArray(const TSource& src, T& dst) {
// https://arduinojson.org/v7/api/misc/copyarray/
template <
typename TSource, typename T,
detail::enable_if_t<detail::is_array<T>::value &&
detail::is_base_of<JsonDocument, TSource>::value,
int> = 0>
inline size_t copyArray(const TSource& src, T& dst) {
return copyArray(src.template as<JsonArrayConst>(), dst);
}

View File

@ -1,9 +1,10 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2025, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Memory/MemoryPool.hpp>
#include <ArduinoJson/Namespace.hpp>
#include <ArduinoJson/Polyfills/assert.hpp>
@ -11,74 +12,100 @@
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
class MemoryPool;
class VariantData;
class VariantSlot;
class ResourceManager;
class CollectionData {
VariantSlot* head_;
VariantSlot* tail_;
class CollectionIterator {
friend class CollectionData;
public:
// Must be a POD!
// - no constructor
// - no destructor
// - no virtual
// - no inheritance
CollectionIterator() : slot_(nullptr), currentId_(NULL_SLOT) {}
// Array only
void next(const ResourceManager* resources);
VariantData* addElement(MemoryPool* pool);
VariantData* getElement(size_t index) const;
VariantData* getOrAddElement(size_t index, MemoryPool* pool);
void removeElement(size_t index);
// Object only
template <typename TAdaptedString>
VariantData* addMember(TAdaptedString key, MemoryPool* pool);
template <typename TAdaptedString>
VariantData* getMember(TAdaptedString key) const;
template <typename TAdaptedString>
VariantData* getOrAddMember(TAdaptedString key, MemoryPool* pool);
template <typename TAdaptedString>
void removeMember(TAdaptedString key) {
removeSlot(getSlot(key));
bool done() const {
return slot_ == nullptr;
}
template <typename TAdaptedString>
bool containsKey(const TAdaptedString& key) const;
bool operator==(const CollectionIterator& other) const {
return slot_ == other.slot_;
}
// Generic
bool operator!=(const CollectionIterator& other) const {
return slot_ != other.slot_;
}
void clear();
size_t memoryUsage() const;
size_t size() const;
VariantData* operator->() {
ARDUINOJSON_ASSERT(slot_ != nullptr);
return data();
}
VariantSlot* addSlot(MemoryPool*);
void removeSlot(VariantSlot* slot);
VariantData& operator*() {
ARDUINOJSON_ASSERT(slot_ != nullptr);
return *data();
}
bool copyFrom(const CollectionData& src, MemoryPool* pool);
const VariantData& operator*() const {
ARDUINOJSON_ASSERT(slot_ != nullptr);
return *data();
}
VariantSlot* head() const {
VariantData* data() {
return reinterpret_cast<VariantData*>(slot_);
}
const VariantData* data() const {
return reinterpret_cast<const VariantData*>(slot_);
}
private:
CollectionIterator(VariantData* slot, SlotId slotId);
VariantData* slot_;
SlotId currentId_, nextId_;
};
class CollectionData {
SlotId head_ = NULL_SLOT;
SlotId tail_ = NULL_SLOT;
public:
// Placement new
static void* operator new(size_t, void* p) noexcept {
return p;
}
static void operator delete(void*, void*) noexcept {}
using iterator = CollectionIterator;
iterator createIterator(const ResourceManager* resources) const;
size_t size(const ResourceManager*) const;
size_t nesting(const ResourceManager*) const;
void clear(ResourceManager* resources);
static void clear(CollectionData* collection, ResourceManager* resources) {
if (!collection)
return;
collection->clear(resources);
}
SlotId head() const {
return head_;
}
void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance);
protected:
void appendOne(Slot<VariantData> slot, const ResourceManager* resources);
void appendPair(Slot<VariantData> key, Slot<VariantData> value,
const ResourceManager* resources);
void removeOne(iterator it, ResourceManager* resources);
void removePair(iterator it, ResourceManager* resources);
private:
VariantSlot* getSlot(size_t index) const;
template <typename TAdaptedString>
VariantSlot* getSlot(TAdaptedString key) const;
VariantSlot* getPreviousSlot(VariantSlot*) const;
Slot<VariantData> getPreviousSlot(VariantData*, const ResourceManager*) const;
};
inline const VariantData* collectionToVariant(

View File

@ -1,197 +1,137 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2025, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Collection/CollectionData.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp>
#include <ArduinoJson/Memory/Alignment.hpp>
#include <ArduinoJson/Strings/StringAdapters.hpp>
#include <ArduinoJson/Variant/VariantCompare.hpp>
#include <ArduinoJson/Variant/VariantData.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
inline VariantSlot* CollectionData::addSlot(MemoryPool* pool) {
VariantSlot* slot = pool->allocVariant();
if (!slot)
return 0;
inline CollectionIterator::CollectionIterator(VariantData* slot, SlotId slotId)
: slot_(slot), currentId_(slotId) {
nextId_ = slot_ ? slot_->next() : NULL_SLOT;
}
if (tail_) {
ARDUINOJSON_ASSERT(pool->owns(tail_)); // Can't alter a linked array/object
tail_->setNextNotNull(slot);
tail_ = slot;
inline void CollectionIterator::next(const ResourceManager* resources) {
ARDUINOJSON_ASSERT(currentId_ != NULL_SLOT);
slot_ = resources->getVariant(nextId_);
currentId_ = nextId_;
if (slot_)
nextId_ = slot_->next();
}
inline CollectionData::iterator CollectionData::createIterator(
const ResourceManager* resources) const {
return iterator(resources->getVariant(head_), head_);
}
inline void CollectionData::appendOne(Slot<VariantData> slot,
const ResourceManager* resources) {
if (tail_ != NULL_SLOT) {
auto tail = resources->getVariant(tail_);
tail->setNext(slot.id());
tail_ = slot.id();
} else {
head_ = slot;
tail_ = slot;
head_ = slot.id();
tail_ = slot.id();
}
}
inline void CollectionData::appendPair(Slot<VariantData> key,
Slot<VariantData> value,
const ResourceManager* resources) {
key->setNext(value.id());
if (tail_ != NULL_SLOT) {
auto tail = resources->getVariant(tail_);
tail->setNext(key.id());
tail_ = value.id();
} else {
head_ = key.id();
tail_ = value.id();
}
}
inline void CollectionData::clear(ResourceManager* resources) {
auto next = head_;
while (next != NULL_SLOT) {
auto currId = next;
auto slot = resources->getVariant(next);
next = slot->next();
resources->freeVariant({slot, currId});
}
slot->clear();
return slot;
head_ = NULL_SLOT;
tail_ = NULL_SLOT;
}
inline VariantData* CollectionData::addElement(MemoryPool* pool) {
return slotData(addSlot(pool));
}
template <typename TAdaptedString>
inline VariantData* CollectionData::addMember(TAdaptedString key,
MemoryPool* pool) {
VariantSlot* slot = addSlot(pool);
if (!slotSetKey(slot, key, pool)) {
removeSlot(slot);
return 0;
}
return slot->data();
}
inline void CollectionData::clear() {
head_ = 0;
tail_ = 0;
}
template <typename TAdaptedString>
inline bool CollectionData::containsKey(const TAdaptedString& key) const {
return getSlot(key) != 0;
}
inline bool CollectionData::copyFrom(const CollectionData& src,
MemoryPool* pool) {
clear();
for (VariantSlot* s = src.head_; s; s = s->next()) {
VariantData* var;
if (s->key() != 0) {
JsonString key(s->key(),
s->ownsKey() ? JsonString::Copied : JsonString::Linked);
var = addMember(adaptString(key), pool);
} else {
var = addElement(pool);
}
if (!var)
return false;
if (!var->copyFrom(*s->data(), pool))
return false;
}
return true;
}
template <typename TAdaptedString>
inline VariantSlot* CollectionData::getSlot(TAdaptedString key) const {
if (key.isNull())
return 0;
VariantSlot* slot = head_;
while (slot) {
if (stringEquals(key, adaptString(slot->key())))
inline Slot<VariantData> CollectionData::getPreviousSlot(
VariantData* target, const ResourceManager* resources) const {
auto prev = Slot<VariantData>();
auto currentId = head_;
while (currentId != NULL_SLOT) {
auto currentSlot = resources->getVariant(currentId);
if (currentSlot == target)
break;
slot = slot->next();
prev = Slot<VariantData>(currentSlot, currentId);
currentId = currentSlot->next();
}
return slot;
return prev;
}
inline VariantSlot* CollectionData::getSlot(size_t index) const {
if (!head_)
return 0;
return head_->next(index);
}
inline VariantSlot* CollectionData::getPreviousSlot(VariantSlot* target) const {
VariantSlot* current = head_;
while (current) {
VariantSlot* next = current->next();
if (next == target)
return current;
current = next;
}
return 0;
}
template <typename TAdaptedString>
inline VariantData* CollectionData::getMember(TAdaptedString key) const {
VariantSlot* slot = getSlot(key);
return slot ? slot->data() : 0;
}
template <typename TAdaptedString>
inline VariantData* CollectionData::getOrAddMember(TAdaptedString key,
MemoryPool* pool) {
// ignore null key
if (key.isNull())
return 0;
// search a matching key
VariantSlot* slot = getSlot(key);
if (slot)
return slot->data();
return addMember(key, pool);
}
inline VariantData* CollectionData::getElement(size_t index) const {
VariantSlot* slot = getSlot(index);
return slot ? slot->data() : 0;
}
inline VariantData* CollectionData::getOrAddElement(size_t index,
MemoryPool* pool) {
VariantSlot* slot = head_;
while (slot && index > 0) {
slot = slot->next();
index--;
}
if (!slot)
index++;
while (index > 0) {
slot = addSlot(pool);
index--;
}
return slotData(slot);
}
inline void CollectionData::removeSlot(VariantSlot* slot) {
if (!slot)
inline void CollectionData::removeOne(iterator it, ResourceManager* resources) {
if (it.done())
return;
VariantSlot* prev = getPreviousSlot(slot);
VariantSlot* next = slot->next();
auto curr = it.slot_;
auto prev = getPreviousSlot(curr, resources);
auto next = curr->next();
if (prev)
prev->setNext(next);
else
head_ = next;
if (!next)
tail_ = prev;
if (next == NULL_SLOT)
tail_ = prev.id();
resources->freeVariant({it.slot_, it.currentId_});
}
inline void CollectionData::removeElement(size_t index) {
removeSlot(getSlot(index));
}
inline size_t CollectionData::memoryUsage() const {
size_t total = 0;
for (VariantSlot* s = head_; s; s = s->next()) {
total += sizeof(VariantSlot) + s->data()->memoryUsage();
if (s->ownsKey())
total += strlen(s->key()) + 1;
}
return total;
}
inline size_t CollectionData::size() const {
return slotSize(head_);
}
template <typename T>
inline void movePointer(T*& p, ptrdiff_t offset) {
if (!p)
inline void CollectionData::removePair(ObjectData::iterator it,
ResourceManager* resources) {
if (it.done())
return;
p = reinterpret_cast<T*>(
reinterpret_cast<void*>(reinterpret_cast<char*>(p) + offset));
ARDUINOJSON_ASSERT(isAligned(p));
auto keySlot = it.slot_;
auto valueId = it.nextId_;
auto valueSlot = resources->getVariant(valueId);
// remove value slot
keySlot->setNext(valueSlot->next());
resources->freeVariant({valueSlot, valueId});
// remove key slot
removeOne(it, resources);
}
inline void CollectionData::movePointers(ptrdiff_t stringDistance,
ptrdiff_t variantDistance) {
movePointer(head_, variantDistance);
movePointer(tail_, variantDistance);
for (VariantSlot* slot = head_; slot; slot = slot->next())
slot->movePointers(stringDistance, variantDistance);
inline size_t CollectionData::nesting(const ResourceManager* resources) const {
size_t maxChildNesting = 0;
for (auto it = createIterator(resources); !it.done(); it.next(resources)) {
size_t childNesting = it->nesting(resources);
if (childNesting > maxChildNesting)
maxChildNesting = childNesting;
}
return maxChildNesting + 1;
}
inline size_t CollectionData::size(const ResourceManager* resources) const {
size_t count = 0;
for (auto it = createIterator(resources); !it.done(); it.next(resources))
count++;
return count;
}
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@ -1,10 +1,11 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2025, Benoit BLANCHON
// MIT License
#pragma once
// Support std::istream and std::ostream
// https://arduinojson.org/v7/config/enable_std_stream/
#ifndef ARDUINOJSON_ENABLE_STD_STREAM
# ifdef __has_include
# if __has_include(<istream>) && \
@ -25,6 +26,7 @@
#endif
// Support std::string
// https://arduinojson.org/v7/config/enable_std_string/
#ifndef ARDUINOJSON_ENABLE_STD_STRING
# ifdef __has_include
# if __has_include(<string>) && !defined(min) && !defined(max)
@ -54,51 +56,105 @@
# endif
#endif
// Pointer size: a heuristic to set sensible defaults
#ifndef ARDUINOJSON_SIZEOF_POINTER
# if defined(__SIZEOF_POINTER__)
# define ARDUINOJSON_SIZEOF_POINTER __SIZEOF_POINTER__
# elif defined(_WIN64) && _WIN64
# define ARDUINOJSON_SIZEOF_POINTER 8 // 64 bits
# else
# define ARDUINOJSON_SIZEOF_POINTER 4 // assume 32 bits otherwise
# endif
#endif
// Store floating-point values with float (0) or double (1)
// https://arduinojson.org/v7/config/use_double/
#ifndef ARDUINOJSON_USE_DOUBLE
# define ARDUINOJSON_USE_DOUBLE 1
# if ARDUINOJSON_SIZEOF_POINTER >= 4 // 32 & 64 bits systems
# define ARDUINOJSON_USE_DOUBLE 1
# else
# define ARDUINOJSON_USE_DOUBLE 0
# endif
#endif
// Store integral values with long (0) or long long (1)
// https://arduinojson.org/v7/config/use_long_long/
#ifndef ARDUINOJSON_USE_LONG_LONG
# if defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ >= 4 || \
defined(_MSC_VER)
# if ARDUINOJSON_SIZEOF_POINTER >= 4 // 32 & 64 bits systems
# define ARDUINOJSON_USE_LONG_LONG 1
# else
# define ARDUINOJSON_USE_LONG_LONG 0
# endif
#endif
#ifndef ARDUINOJSON_USE_LONG_LONG
# define ARDUINOJSON_USE_LONG_LONG 0
#endif
// Limit nesting as the stack is likely to be small
// https://arduinojson.org/v7/config/default_nesting_limit/
#ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT
# define ARDUINOJSON_DEFAULT_NESTING_LIMIT 10
#endif
// Number of bits to store the pointer to next node
// (saves RAM but limits the number of values in a document)
#ifndef ARDUINOJSON_SLOT_OFFSET_SIZE
# if defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ <= 2
// Address space == 16-bit => max 127 values
# define ARDUINOJSON_SLOT_OFFSET_SIZE 1
# elif defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ >= 8 || \
defined(_WIN64) && _WIN64
// Address space == 64-bit => max 2147483647 values
# define ARDUINOJSON_SLOT_OFFSET_SIZE 4
// Number of bytes to store a slot id
// https://arduinojson.org/v7/config/slot_id_size/
#ifndef ARDUINOJSON_SLOT_ID_SIZE
# if ARDUINOJSON_SIZEOF_POINTER <= 2
// 8-bit and 16-bit archs => up to 255 slots
# define ARDUINOJSON_SLOT_ID_SIZE 1
# elif ARDUINOJSON_SIZEOF_POINTER == 4
// 32-bit arch => up to 65535 slots
# define ARDUINOJSON_SLOT_ID_SIZE 2
# else
// Address space == 32-bit => max 32767 values
# define ARDUINOJSON_SLOT_OFFSET_SIZE 2
// 64-bit arch => up to 4294967295 slots
# define ARDUINOJSON_SLOT_ID_SIZE 4
# endif
#endif
// Capacity of each variant pool (in slots)
#ifndef ARDUINOJSON_POOL_CAPACITY
# if ARDUINOJSON_SLOT_ID_SIZE == 1
# define ARDUINOJSON_POOL_CAPACITY 16 // 96 bytes
# elif ARDUINOJSON_SLOT_ID_SIZE == 2
# define ARDUINOJSON_POOL_CAPACITY 128 // 1024 bytes
# else
# define ARDUINOJSON_POOL_CAPACITY 256 // 4096 bytes
# endif
#endif
// Initial capacity of the pool list
#ifndef ARDUINOJSON_INITIAL_POOL_COUNT
# define ARDUINOJSON_INITIAL_POOL_COUNT 4
#endif
// Automatically call shrinkToFit() from deserializeXxx()
// Disabled by default on 8-bit platforms because it's not worth the increase in
// code size
#ifndef ARDUINOJSON_AUTO_SHRINK
# if ARDUINOJSON_SIZEOF_POINTER <= 2
# define ARDUINOJSON_AUTO_SHRINK 0
# else
# define ARDUINOJSON_AUTO_SHRINK 1
# endif
#endif
// Number of bytes to store the length of a string
// https://arduinojson.org/v7/config/string_length_size/
#ifndef ARDUINOJSON_STRING_LENGTH_SIZE
# if ARDUINOJSON_SIZEOF_POINTER <= 2
# define ARDUINOJSON_STRING_LENGTH_SIZE 1 // up to 255 characters
# else
# define ARDUINOJSON_STRING_LENGTH_SIZE 2 // up to 65535 characters
# endif
#endif
#ifdef ARDUINO
// Enable support for Arduino's String class
// https://arduinojson.org/v7/config/enable_arduino_string/
# ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING
# define ARDUINOJSON_ENABLE_ARDUINO_STRING 1
# endif
// Enable support for Arduino's Stream class
// https://arduinojson.org/v7/config/enable_arduino_stream/
# ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM
# define ARDUINOJSON_ENABLE_ARDUINO_STREAM 1
# endif
@ -109,6 +165,7 @@
# endif
// Enable support for PROGMEM
// https://arduinojson.org/v7/config/enable_progmem/
# ifndef ARDUINOJSON_ENABLE_PROGMEM
# define ARDUINOJSON_ENABLE_PROGMEM 1
# endif
@ -116,11 +173,13 @@
#else // ARDUINO
// Disable support for Arduino's String class
// https://arduinojson.org/v7/config/enable_arduino_string/
# ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING
# define ARDUINOJSON_ENABLE_ARDUINO_STRING 0
# endif
// Disable support for Arduino's Stream class
// https://arduinojson.org/v7/config/enable_arduino_stream/
# ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM
# define ARDUINOJSON_ENABLE_ARDUINO_STREAM 0
# endif
@ -131,6 +190,7 @@
# endif
// Enable PROGMEM support on AVR only
// https://arduinojson.org/v7/config/enable_progmem/
# ifndef ARDUINOJSON_ENABLE_PROGMEM
# ifdef __AVR__
# define ARDUINOJSON_ENABLE_PROGMEM 1
@ -142,32 +202,38 @@
#endif // ARDUINO
// Convert unicode escape sequence (\u0123) to UTF-8
// https://arduinojson.org/v7/config/decode_unicode/
#ifndef ARDUINOJSON_DECODE_UNICODE
# define ARDUINOJSON_DECODE_UNICODE 1
#endif
// Ignore comments in input
// https://arduinojson.org/v7/config/enable_comments/
#ifndef ARDUINOJSON_ENABLE_COMMENTS
# define ARDUINOJSON_ENABLE_COMMENTS 0
#endif
// Support NaN in JSON
// https://arduinojson.org/v7/config/enable_nan/
#ifndef ARDUINOJSON_ENABLE_NAN
# define ARDUINOJSON_ENABLE_NAN 0
#endif
// Support Infinity in JSON
// https://arduinojson.org/v7/config/enable_infinity/
#ifndef ARDUINOJSON_ENABLE_INFINITY
# define ARDUINOJSON_ENABLE_INFINITY 0
#endif
// Control the exponentiation threshold for big numbers
// CAUTION: cannot be more that 1e9 !!!!
// https://arduinojson.org/v7/config/positive_exponentiation_threshold/
#ifndef ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD
# define ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD 1e7
#endif
// Control the exponentiation threshold for small numbers
// https://arduinojson.org/v7/config/negative_exponentiation_threshold/
#ifndef ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD
# define ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD 1e-5
#endif
@ -195,10 +261,6 @@
# define ARDUINOJSON_TAB " "
#endif
#ifndef ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
# define ARDUINOJSON_ENABLE_STRING_DEDUPLICATION 1
#endif
#ifndef ARDUINOJSON_STRING_BUFFER_SIZE
# define ARDUINOJSON_STRING_BUFFER_SIZE 32
#endif
@ -211,6 +273,12 @@
# endif
#endif
#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_DOUBLE
# define ARDUINOJSON_USE_EXTENSIONS 1
#else
# define ARDUINOJSON_USE_EXTENSIONS 0
#endif
#if defined(nullptr)
# error nullptr is defined as a macro. Remove the faulty #define or #undef nullptr
// See https://github.com/bblanchon/ArduinoJson/issues/1355

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