Compare commits

..

1 Commits

Author SHA1 Message Date
adb 8b3c8a671a switch to UIPArtNet v0.1.0 3 years ago

@ -2,298 +2,230 @@
Art-Net Sender/Receiver for Arduino (Ethernet, WiFi)
**NOTE : BREAKING API CHANGES (v0.2.0 or later)**
## Feature
- Art-Net with both Ethernet and WiFi
- Support a lot of boards which can use Ethernet or WiFi
- Multiple receiver callbacks depending on universe
- Mutilple destination streaming with sender
- One-line send to desired destination
- Flexible net/subnet/universe setting
- Easy data forwarding to [FastLED](https://github.com/FastLED/FastLED)
## Supported Platforms
- support Art-Net with both Ethernet and WiFi
- register multiple callbacks depending on universe
- flexible net/subnet/universe setting
- etc.
#### WiFi
### Supported Platforms
- ESP32
- ESP8266
- Arduino Uno WiFi Rev2
- Arduino MKR VIDOR 4000
- Arduino MKR WiFi 1010
- Arduino MKR WiFi 1000
- Arduino Nano 33 IoT
- ESP32, ESP8266 (WiFi)
- Teensy 3.x (Ethernet)
- Arduino Uno/Mega etc. (Ethernet)
#### Ethernet
- Almost all platforms without WiFi
#### Note
Some boards without enough memory may not be able to use integrated sender/receiver.
Please use only sender OR receiver.
## Usage
This library has following Art-Net controller options.
Please use them depending on the situation.
- ArtnetReveiver
- ArtnetSender
- ArtnetReveiver
- Artnet (Integrated Sender/Receiver)
### ArtnetReceiver
### ArtnetSender
```C++
#include <Artnet.h>
ArtnetReceiver artnet;
void callback(const uint8_t* data, const uint16_t size) {
// you can also use pre-defined callbacks
}
// declarations for Ethernet/WiFi
void setup() {
// setup Ethernet/WiFi...
ArtnetSender artnet;
artnet.begin(); // waiting for Art-Net in default port
// artnet.begin(net, subnet); // optionally you can set net and subnet here
void setup()
{
// setup Ethernet/WiFi...
artnet.subscribe(universe1, [](const uint8_t* data, const uint16_t size) {
// if Artnet packet comes to this universe(0-15), this function is called
});
artnet.subscribe(universe2, callback); // you can also use pre-defined callbacks
artnet.begin("127.0.0.1"); // set destination ip
}
void loop() {
artnet.parse(); // check if artnet packet has come and execute callback
void loop()
{
// change send data as you want
artnet.set(universe, data_ptr, size);
artnet.streaming(); // automatically send set data in 40fps
}
```
### ArtnetSender
### ArtnetReceiver
```C++
#include <Artnet.h>
ArtnetSender artnet;
void setup() {
// setup Ethernet/WiFi...
// declarations for Ethernet/WiFi
artnet.begin();
ArtnetReceiver artnet;
void callback(uint8_t* data, uint16_t size)
{
// you can also use pre-defined callbacks
}
void loop() {
// change send data as you want
void setup()
{
// setup Ethernet/WiFi...
artnet.begin(); // waiting for Art-Net in default port
// if Artnet packet comes to this universe, this function is called
artnet.subscribe(universe1, [](uint8_t* data, uint16_t size)
{
// use received data[], and size
});
artnet.send("127.0.0.1", universe15bit, data_ptr, size); // one-line send
// artnet.send("127.0.0.1", net, subnet, univ, data_ptr, size); // or you can set net and subnet
// you can also use pre-defined callbacks
artnet.subscribe(universe2, callback);
}
artnet.streaming_data(data_ptr, size);
artnet.streaming("127.0.0.1", universe15bit); // automatically send set data in 40fps (15bit universe)
// artnet.streaming("127.0.0.1", net, subnet, univ); // or you can set net and subnet here
void loop()
{
artnet.parse(); // check if artnet packet has come and execute callback
}
```
### Artnet (Integrated Sender/Receiver)
```C++
#include <Artnet.h>
// declarations for Ethernet/WiFi
Artnet artnet;
void setup()
{
// setup Ethernet/WiFi...
artnet.begin(); // send to localhost and listen to default port
// artnet.begin(net, subnet); // optionally you can set net and subnet here
artnet.begin("127.0.0.1"); // send to localhost and listen to default port
artnet.subscribe(universe, [&](const uint8_t* data, const uint16_t size) {
// if Artnet packet comes to this universe, this function is called
});
artnet.subscribe([&](const uint32_t univ, const uint8_t* data, const uint16_t size) {
// if Artnet packet comes, this function is called to every universe
// if Artnet packet comes to this universe, this function is called
artnet.subscribe(universe, [&](uint8_t* data, uint16_t size)
{
// do something with data coming to universe
});
}
void loop() {
void loop()
{
artnet.parse(); // check if artnet packet has come and execute callback
// change send data as you want
artnet.send("127.0.0.1", universe15bit, data_ptr, size); // one-line send
// artnet.send("127.0.0.1", net, subnet, univ, data_ptr, size); // or you can set net and subnet
artnet.streaming_data(data_ptr, size);
artnet.streaming("127.0.0.1", universe15bit); // automatically send set data in 40fps (15bit universe)
// artnet.streaming("127.0.0.1", net, subnet, univ); // or you can set net and subnet here
artnet.set(universe, data, size); // set send data
artnet.streaming(); // automatically send set data in 40fps
}
```
## Other Settings
### Artnet Receiver + FastLED
``` C++
#include <Artnet.h>
ArtnetReceiver artnet;
// FastLED
#define NUM_LEDS 1
CRGB leds[NUM_LEDS];
const uint8_t PIN_LED_DATA = 3;
### Net, Sub-Net, Universe, and Universe(15bit)
void setup() {
// setup Ethernet/WiFi...
You can set Net, Sub-Net, Universe and Universe(15bit) flexibly.
// setup FastLED
FastLED.addLeds<NEOPIXEL, PIN_LED>(&leds, NUM_LEDS);
artnet.begin();
// if Artnet packet comes to this universe, forward them to fastled directly
artnet.forward(universe, leds, NUM_LEDS);
// this can be achieved manually as follows
// artnet.subscribe(universe, [](uint8_t* data, uint16_t size)
// {
// // artnet data size per packet is 512 max
// // so there is max 170 pixel per packet (per universe)
// for (size_t pixel = 0; pixel < NUM_LEDS; ++pixel)
// {
// size_t idx = pixel * 3;
// leds[pixel].r = data[idx + 0];
// leds[pixel].g = data[idx + 1];
// leds[pixel].b = data[idx + 2];
// }
// });
}
#### Sender
void loop() {
artnet.parse(); // check if artnet packet has come and execute callback
FastLED.show();
}
```C++
// set separately
artent.net(n);
artent.subnet(s);
artent.universe(u);
artnet.set(data, size);
// set as 15bit universe
artent.universe15bit(u);
artnet.set(data, size);
// set with data and size
artnet.set(universe15bit, data, size);
artnet.set(net, subnet, universe, data, size);
```
## Other Settings
### Subscribing Callbacks with Net, Sub-Net and Universe as you like
- You can set Net (0-127) and Sub-Net (0-15) like `artnet.begin(net, subnet)`
- Universe (0-15) can be set in `artnet.subscribe(universe, callback)`,
- Callbacks are limited to 4 universes (depending on the spec of Art-Net)
#### Receiver
```C++
artnet.begin(net, subnet); // net and subnet can be set only once
artnet.subscribe(univ1, callback1); // 4 callbacks can be set
artnet.subscribe(univ2, callback2); // these universes are reported to
artnet.subscribe(univ3, callback3); // Art-Net controller if it polls
artnet.subscribe(univ4, callback4); // Art-Net devices
artnet.subscribe(universe15bit, function);
artnet.subscribe(net, subnet, universe, function);
```
### Sending Art-Net to Net, Sub-Net and Universe as you like
### One Time Sending (Not Streaming)
#### One-line sender
In Sender class, you can also send Art-Net packet once.
This sends only 1 packet (NOT streaming).
```C++
artnet.send(ip, univ15bit, data, size); // use 15bit universer or
artnet.send(ip, net, subnet, univ, data, size); // net, subnet, and universe
artnet.send(data, size);
artnet.send(universe15bit, data, size);
artnet.send(net, subnet, universe, data, size);
```
#### Streaming
### Set Non-Default Port
```C++
artnet.streaming_data(data, size); // set data first
artnet.streaming(ip, univ15bit); // stream to 15bit universe or
artnet.streaming(ip, net, subnet, univ); // net, subnet, and universe
// ArtnetSender
artnet.begin(ip); // default
artnet.begin(ip, port); // set your own
// ArtnetReceiver
artnet.begin(); // default
artnet.begin(port); // set your own
// Artnet (integrated)
artnet.begin(ip); // default send/receiver
artnet.begin(ip, send_port, recv_port); // set your own
```
### ArtPollReply Setting
- This library supports `ArtPoll` and `ArtPollReply`
- `ArtPoll` is automatically parsed and sends `ArtPollReply`
- `net_sw` `sub_sw` `sw_in` etc. are set automatically based on registerd callbacks
- You can configure the information of `ArtPollReply` as follows
- `void shortname(const String& sn)`
- `void longname(const String& ln)`
- `void nodereport(const String& nr)`
## APIs
### ArtnetSender
```C++
// streaming packet
void streaming_data(const uint8_t* const data, const uint16_t size);
void streaming_data(const uint16_t ch, const uint8_t data);
void streaming(const String& ip, const uint32_t universe_);
void streaming(const String& ip, const uint8_t net_, const uint8_t subnet_, const uint8_t universe_);
// one-line sender
void send(const String& ip, const uint32_t universe_, const uint8_t* const data, const uint16_t size);
void send(const String& ip, const uint8_t net_, const uint8_t subnet_, const uint8_t universe_, const uint8_t* const data, const uint16_t size);
// others
void physical(const uint8_t i);
uint8_t sequence() const;
void net(uint8_t n)
void subnet(uint8_t s)
void universe(uint8_t u)
void universe15bit(uint8_t u)
void set(const uint8_t* const data, uint16_t size = 512)
void set(const uint32_t universe_, const uint8_t* const data, uint16_t size = 512)
void set(const uint8_t net_, const uint8_t subnet_, const uint8_t universe_, const uint8_t* const data, uint16_t size = 512)
void send()
void send(const uint8_t* const data, uint16_t size = 512)
void send(const uint32_t universe_, const uint8_t* const data, uint16_t size = 512)
void send(const uint8_t net_, const uint8_t subnet_, const uint8_t universe_, const uint8_t* const data, uint16_t size = 512)
void streaming()
void physical(uint8_t i)
uint8_t sequence() const
```
### ArtnetReceiver
```C++
OpCode parse();
// subscribers
template <typename F> inline auto subscribe(const uint8_t universe, F&& func);
template <typename F> inline auto subscribe(const uint8_t universe, F* func);
template <typename F> inline auto subscribe(F&& func);
template <typename F> inline auto subscribe(F* func);
// for FastLED
inline void forward(const uint8_t universe, CRGB* leds, const uint16_t num);
// unsubscribe
inline void unsubscribe(const uint8_t universe);
inline void unsubscribe();
inline void clear_subscribers();
// ArtPollReply information
void shortname(const String& sn);
void longname(const String& ln);
void nodereport(const String& nr);
// others
inline const IPAddress& ip() const;
uint16_t port() const;
String id() const;
uint16_t opcode() const;
uint16_t opcode(const uint8_t* p) const;
uint16_t version() const;
uint8_t sequence() const;
uint8_t physical() const;
uint8_t net() const;
uint8_t subnet() const;
uint8_t universe() const;
uint16_t universe15bit() const;
uint16_t length() const;
uint16_t size() const;
uint8_t* data();
uint8_t data(const uint16_t i) const;
bool parse()
inline const IPAddress& ip() const { return remote_ip; }
uint16_t port() const { return remote_port; }
String id() const
uint16_t opcode() const
uint16_t opcode(const uint8_t* p) const
uint16_t version() const
uint8_t sequence() const
uint8_t physical() const
uint8_t net() const
uint8_t subnet() const
uint8_t universe() const
uint16_t universe15bit() const
uint16_t length() const
uint16_t size() const
uint8_t* data()
uint8_t data(const uint16_t i) const
void subscribe(const uint32_t universe, const CallbackType& func)
void subscribe(const CallbackType& func)
void subscribe(const uint8_t net, const uint8_t subnet, const uint8_t universe, const CallbackType& func)
```
### Note
Some boards without enough memory (e.g. Uno, Nano, etc.) may not be able to use integrated sender/receiver because of the lack of enough memory. Please consider to use more powerful board or to use only sender OR receiver.
## Reference
- [Spec (Art-Net 4)](http://artisticlicence.com/WebSiteMaster/User%20Guides/art-net.pdf)
- [Packet Summary](https://art-net.org.uk/structure/packet-summary-2/)
- [Packet Definition](https://art-net.org.uk/structure/streaming-packets/artdmx-packet-definition/)
## Embedded Libraries
- [ArxContainer v0.3.10](https://github.com/hideakitai/ArxContainer)
- [ArxTypeTraits v0.2.1](https://github.com/hideakitai/ArxTypeTraits)
- [TeensyDirtySTLErrorSolution v0.1.0](https://github.com/hideakitai/TeensyDirtySTLErrorSolution)
## License
MIT

@ -0,0 +1,122 @@
#pragma once
#ifndef RINGBUFFER_H
#define RINGBUFFER_H
template<typename T, size_t SIZE>
class RingBuffer
{
public:
inline size_t capacity() const { return SIZE; };
inline size_t size() const { return (tail_ - head_); };
inline const T* data() const { return &(queue_[head_]); }
inline T* data() { return &(queue_[head_]); }
inline bool empty() const { return tail_ == head_; };
inline void clear() { head_ = 0; tail_ = 0; };
inline void pop()
{
if (size() == 0) return;
if (size() == 1) clear();
else head_++;
};
inline void pop_back()
{
if (size() == 0) return;
if (size() == 1) clear();
else tail_--;
};
inline void push(const T& data)
{
queue_[(tail_++) % SIZE] = data;
if (size() > SIZE) head_++;
};
inline void push(T&& data)
{
queue_[(tail_++) % SIZE] = data;
if (size() > SIZE) head_++;
};
inline void push_back(const T& data)
{
queue_[(tail_++) % SIZE] = data;
if (size() > SIZE) head_++;
};
inline void push_back(T&& data)
{
queue_[(tail_++) % SIZE] = data;
if (size() > SIZE) head_++;
};
inline const T& front() const // throw(Exception)
{
// if(empty()) throw Exception();
return *(queue_ + head_ % SIZE);
};
inline T& front() // throw(Exception)
{
// if(empty()) throw Exception();
return *(queue_ + head_ % SIZE);
};
inline const T& back() const // throw(Exception)
{
// if(empty()) throw Exception();
return *(queue_ + (SIZE + tail_ - 1) % SIZE);
}
inline T& back() // throw(Exception)
{
// if(empty()) throw Exception();
return *(queue_ + (SIZE + tail_ - 1) % SIZE);
}
inline const T& operator[] (uint8_t index) const
{
return *(queue_ + (head_ + index) % SIZE);
}
inline T& operator[] (uint8_t index)
{
return *(queue_ + (head_ + index) % SIZE);
}
inline const T* begin() const { return &(queue_[head_]); }
inline T* begin() { return &(queue_[head_]); }
inline const T* end() const { return &(queue_[tail_]); }
inline T* end() { return &(queue_[tail_]); }
inline T* erase(T* p)
{
if (p == end()) return p;
for (T* pos = p + 1; pos != end(); ++pos)
*(pos - 1) = *pos;
--tail_;
return p;
}
inline void resize(size_t sz)
{
size_t s = size();
if (sz > size())
{
for (size_t i = 0; i < sz - s; ++i) push(T());
}
else if (sz < size())
{
for (size_t i = 0; i < s - sz; ++i) pop();
}
}
inline void assign(const T* const first, const T* const end)
{
clear();
const char* p = first;
while (p != end) push(*p++);
}
private:
T queue_[SIZE];
volatile size_t head_ {0};
volatile size_t tail_ {0};
};
#endif // RINGBUFFER_H

@ -7,51 +7,34 @@
// Packet Definition : https://art-net.org.uk/structure/streaming-packets/artdmx-packet-definition/
#include <Arduino.h>
#include "util/ArxTypeTraits/ArxTypeTraits.h"
#include "util/ArxContainer/ArxContainer.h"
#if defined(ESP_PLATFORM) || defined(ESP8266) || defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_SAMD_MKRWIFI1010) || defined(ARDUINO_SAMD_MKRVIDOR4000) || defined(ARDUINO_SAMD_MKR1000) || defined(ARDUINO_SAMD_NANO_33_IOT)
#define ARTNET_ENABLE_WIFI
#endif
#if !defined(ARTNET_ENABLE_WIFI)
#define ARTNET_ENABLE_ETHER
#endif
#if !defined(ARTNET_ENABLE_WIFI) && !defined(ARTNET_ENABLE_ETHER)
#error THIS PLATFORM HAS NO WIFI OR ETHERNET OR NOT SUPPORTED ARCHITECTURE. PLEASE LET ME KNOW!
#ifndef __AVR__
#include <array>
#include <vector>
#include <functional>
#else
#include "RingBuffer.h"
#endif
#ifdef ARTNET_ENABLE_WIFI
#ifdef ESP_PLATFORM
#include <WiFi.h>
#include <WiFiUdp.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#elif defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_SAMD_MKRWIFI1010) || defined(ARDUINO_SAMD_MKRVIDOR4000) || defined(ARDUINO_SAMD_NANO_33_IOT)
#include <SPI.h>
#include <WiFiNINA.h>
#include <WiFiUdp.h>
#elif defined(ARDUINO_SAMD_MKR1000)
#include <SPI.h>
#include <WiFi101.h>
#include <WiFiUdp.h>
#include <WiFi.h>
#include <WiFiUdp.h>
#elif defined (ESP8266)
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#elif defined (TEENSYDUINO) || defined (__AVR__)
#include <UIPEthernet.h>
#include <UIPUdp.h>
#endif
#endif // ARTNET_ENABLE_WIFI
#ifdef ARTNET_ENABLE_ETHER
#include <UIPEthernet.h>
#include <UIPUdp.h>
#include "util/TeensyDirtySTLErrorSolution/TeensyDirtySTLErrorSolution.h"
#endif // ARTNET_ENABLE_ETHER
namespace arx {
namespace artnet {
namespace arduino
{
namespace artnet
{
// Packet Summary : https://art-net.org.uk/structure/packet-summary-2/
// Packet Definition : https://art-net.org.uk/structure/streaming-packets/artdmx-packet-definition/
enum class OpCode : uint16_t {
enum class OpCode : uint16_t
{
// Device Discovery
Poll = 0x2000,
PollReply = 0x2100,
@ -85,14 +68,13 @@ namespace arx {
DirectoryReply = 0x9B00,
FileTnMaster = 0xF400,
FileFnMaster = 0xF500,
FileFnReply = 0xF600,
// N/A
NA = 0x0000,
FileFnReply = 0xF600
};
constexpr uint16_t OPC(OpCode op) { return static_cast<uint16_t>(op); }
enum class Index : uint16_t {
enum class Index : uint16_t
{
ID = 0,
OP_CODE_L = 8,
OP_CODE_H = 9,
@ -109,494 +91,335 @@ namespace arx {
constexpr uint16_t IDX(Index i) { return static_cast<uint16_t>(i); }
constexpr uint16_t DEFAULT_PORT{6454}; // 0x1936
constexpr uint16_t HEADER_SIZE{18};
constexpr uint16_t PACKET_SIZE{530};
constexpr uint16_t PROTOCOL_VER{0x0014};
constexpr uint8_t ID_LENGTH{8};
constexpr char ID[ID_LENGTH]{"Art-Net"};
constexpr float DEFAULT_FPS{40.};
constexpr uint32_t DEFAULT_INTERVAL_MS{(uint32_t)(1000. / DEFAULT_FPS)};
static constexpr uint8_t NUM_PIXELS_PER_UNIV{170};
constexpr uint16_t DEFAULT_PORT { 6454 };
constexpr uint16_t HEADER_SIZE { 18 };
constexpr uint16_t PACKET_SIZE { 530 };
constexpr uint16_t PROTOCOL_VER { 0x0014 };
constexpr uint8_t ID_LENGTH { 8 };
constexpr char ID[ID_LENGTH] { "Art-Net" };
constexpr float DEFAULT_FPS { 40. };
constexpr uint32_t DEFAULT_INTERVAL_MS { (uint32_t)(1000. / DEFAULT_FPS) };
using CallbackAllType = std::function<void(const uint32_t universe, const uint8_t* data, const uint16_t size)>;
using CallbackType = std::function<void(const uint8_t* data, const uint16_t size)>;
static constexpr uint8_t NUM_PIXELS_PER_UNIV { 170 };
#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11
template <uint16_t SIZE>
using Array = std::array<uint8_t, SIZE>;
using IntervalMap = std::map<uint32_t, uint32_t>;
using CallbackMap = std::map<uint32_t, CallbackType>;
using namespace std;
#else
#ifdef __AVR__
template <uint16_t SIZE>
using Array = arx::vector<uint8_t, SIZE>;
using IntervalMap = arx::map<uint32_t, uint32_t>;
using CallbackMap = arx::map<uint32_t, CallbackType, 4>;
using namespace arx;
#endif
union ArtPollReply {
struct {
uint8_t id[8];
uint8_t op_code_l;
uint8_t op_code_h;
uint8_t ip[4];
uint8_t port_l;
uint8_t port_h;
uint8_t ver_h;
uint8_t ver_l;
uint8_t net_sw;
uint8_t sub_sw;
uint8_t oem_h;
uint8_t oem_l;
uint8_t ubea_ver;
uint8_t status_1;
uint8_t esta_man_l;
uint8_t esta_man_h;
uint8_t short_name[18];
uint8_t long_name[64];
uint8_t node_report[64];
uint8_t num_ports_h;
uint8_t num_ports_l;
uint8_t port_types[4];
uint8_t good_input[4];
uint8_t good_output[4];
uint8_t sw_in[4];
uint8_t sw_out[4];
uint8_t sw_video;
uint8_t sw_macro;
uint8_t sw_remote;
uint8_t spare[3];
uint8_t style;
uint8_t mac[6];
uint8_t bind_ip[4];
uint8_t bind_index;
uint8_t status_2;
uint8_t filler[26];
};
uint8_t b[239];
class Array
{
uint8_t buffer[SIZE];
public:
const uint8_t* data() const { return buffer; }
uint8_t* data() { return buffer; }
uint16_t size() const { return SIZE; }
uint8_t operator[] (const size_t i) const { return buffer[i]; }
uint8_t& operator[] (const size_t i) { return buffer[i]; }
};
#endif
template <typename S>
class Sender_ {
class Sender_
{
#ifdef __AVR__
Array<PACKET_SIZE> packet;
uint8_t target_net{0};
uint8_t target_subnet{0};
uint8_t target_universe{0};
uint8_t seq{0};
uint8_t phy{0};
IntervalMap intervals;
#else
std::array<uint8_t, PACKET_SIZE> packet;
#endif
const char* ip;
uint16_t port {DEFAULT_PORT};
uint8_t target_net {0};
uint8_t target_subnet {0};
uint8_t target_universe {0};
uint8_t seq {0};
uint8_t phy {0};
uint32_t prev_send_ms {0};
S* stream;
public:
#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11
#else
Sender_() { packet.resize(PACKET_SIZE); }
#endif
virtual ~Sender_() {}
// streaming packet
void streaming_data(const uint8_t* const data, const uint16_t size) {
void net(uint8_t n) { target_net = n & 0x7F; }
void subnet(uint8_t s) { target_subnet = s & 0x0F; }
void universe(uint8_t u) { target_universe = u & 0x0F; }
void universe15bit(uint8_t u)
{
net((u >> 8) & 0xFF);
subnet((u >> 4) & 0x0F);
universe((u >> 0) & 0x0F);
}
void set(const uint8_t* const data, uint16_t size = 512)
{
packet[IDX(Index::PHYSICAL)] = phy;
packet[IDX(Index::NET)] = target_net;
packet[IDX(Index::SUBUNI)] = (target_subnet << 4) | target_universe;
packet[IDX(Index::LENGTH_H)] = (size >> 8) & 0xFF;
packet[IDX(Index::LENGTH_L)] = (size >> 0) & 0xFF;
memcpy((&packet[IDX(Index::DATA)]), data, size);
}
void streaming_data(const uint16_t ch, const uint8_t data) {
packet[IDX(Index::DATA) + ch] = data;
void set(const uint32_t universe_, const uint8_t* const data, uint16_t size = 512)
{
universe15bit(universe_);
set(data, size);
}
void streaming(const String& ip, const uint32_t universe_) {
uint32_t now = millis();
if (intervals.find(universe_) == intervals.end()) {
intervals.insert(make_pair(universe_, now));
}
if (now >= intervals[universe_] + DEFAULT_INTERVAL_MS) {
set_universe(universe_);
send_packet(ip);
intervals[universe_] = now;
}
void set(const uint8_t net_, const uint8_t subnet_, const uint8_t universe_, const uint8_t* const data, uint16_t size = 512)
{
net(net_);
subnet(subnet_);
universe(universe_);
set(data, size);
}
void streaming(const String& ip, const uint8_t net_, const uint8_t subnet_, const uint8_t universe_) {
uint32_t u = ((uint32_t)net_ << 8) | ((uint32_t)subnet_ << 4) | (uint32_t)universe_;
streaming(ip, u);
void set(const uint16_t ch, const uint8_t data)
{
packet[IDX(Index::DATA) + ch] = data;
}
// one-line sender
void send(const String& ip, const uint32_t universe_, const uint8_t* const data, const uint16_t size) {
set_universe(universe_);
streaming_data(data, size);
send_packet(ip);
void send()
{
packet[IDX(Index::SEQUENCE)] = seq++;
stream->beginPacket(ip, port);
stream->write(packet.data(), packet.size());
stream->endPacket();
}
void send(const uint8_t* const data, uint16_t size = 512)
{
set(data, size);
send();
}
void send(const uint32_t universe_, const uint8_t* const data, uint16_t size = 512)
{
set(universe_, data, size);
send();
}
void send(const String& ip, const uint8_t net_, const uint8_t subnet_, const uint8_t universe_, const uint8_t* const data, const uint16_t size) {
set_universe(net_, subnet_, universe_);
streaming_data(data, size);
send_packet(ip);
void send(const uint8_t net_, const uint8_t subnet_, const uint8_t universe_, const uint8_t* const data, uint16_t size = 512)
{
set(net_, subnet_, universe_, data, size);
send();
}
void physical(const uint8_t i) { phy = constrain(i, 0, 3); }
void streaming()
{
if ((millis() - prev_send_ms) > DEFAULT_INTERVAL_MS)
{
send();
prev_send_ms = millis();
}
}
void physical(uint8_t i) { phy = constrain(i, 0, 3); }
uint8_t sequence() const { return seq; }
protected:
void attach(S& s) {
void attach(S& s, const char* user_ip, uint16_t user_port = DEFAULT_PORT)
{
stream = &s;
ip = user_ip;
port = user_port;
for (size_t i = 0; i < ID_LENGTH; i++) packet[IDX(Index::ID) + i] = static_cast<uint8_t>(ID[i]);
packet[IDX(Index::OP_CODE_H)] = (OPC(OpCode::Dmx) >> 8) & 0x00FF;
packet[IDX(Index::OP_CODE_L)] = (OPC(OpCode::Dmx) >> 0) & 0x00FF;
packet[IDX(Index::PROTOCOL_VER_H)] = (PROTOCOL_VER >> 8) & 0x00FF;
packet[IDX(Index::PROTOCOL_VER_L)] = (PROTOCOL_VER >> 0) & 0x00FF;
}
void send_packet(const String& ip) {
packet[IDX(Index::SEQUENCE)] = seq++;
packet[IDX(Index::PHYSICAL)] = phy;
packet[IDX(Index::NET)] = target_net;
packet[IDX(Index::SUBUNI)] = (target_subnet << 4) | target_universe;
packet[IDX(Index::LENGTH_H)] = (512 >> 8) & 0xFF;
packet[IDX(Index::LENGTH_L)] = (512 >> 0) & 0xFF;
stream->beginPacket(ip.c_str(), DEFAULT_PORT);
stream->write(packet.data(), packet.size());
stream->endPacket();
}
void set_universe(const uint32_t universe_) {
target_net = (universe_ >> 8) & 0x7F;
target_subnet = (universe_ >> 4) & 0x0F;
target_universe = universe_ & 0x0F;
}
void set_universe(const uint8_t net_, const uint8_t subnet_, const uint8_t universe_) {
target_net = net_ & 0x7F;
target_subnet = subnet_ & 0x0F;
target_universe = universe_ & 0x0F;
}
};
template <typename S>
class Receiver_ {
class Receiver_
{
#ifdef __AVR__
typedef void (*CallbackType)(uint8_t* data, uint16_t size);
struct Map { uint32_t universe; CallbackType func; };
using CallbackMap = RingBuffer<Map, 8>;
Array<PACKET_SIZE> packet;
#else
using CallbackType = std::function<void(uint8_t* data, uint16_t size)>;
struct Map { uint32_t universe; CallbackType func; };
using CallbackMap = std::vector<Map>;
std::array<uint8_t, PACKET_SIZE> packet;
#endif
IPAddress remote_ip;
uint16_t remote_port;
uint8_t net_switch; // net of universe
uint8_t sub_switch; // subnet of universe
String short_name{"Arduino ArtNet"};
String long_name{"Ardino ArtNet Protocol by hideakitai/ArtNet"};
String node_report{""};
CallbackMap callbacks;
CallbackAllType callback_all;
S* stream;
public:
#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11
#else
Receiver_() { packet.resize(PACKET_SIZE); }
#endif
virtual ~Receiver_() {}
OpCode parse() {
bool parse()
{
const size_t size = stream->parsePacket();
if (size == 0) return OpCode::NA;
if (size == 0) return false;
uint8_t d[size];
stream->read(d, size);
if (checkID(d)) {
switch (opcode(d)) {
case OPC(OpCode::Dmx): {
memcpy(packet.data(), d, size);
remote_ip = stream->S::remoteIP();
remote_port = (uint16_t)stream->S::remotePort();
if (callback_all) callback_all(universe15bit(), data(), size - HEADER_SIZE);
for (auto& c : callbacks)
if (universe15bit() == c.first) c.second(data(), size - HEADER_SIZE);
return OpCode::Dmx;
}
case OPC(OpCode::Poll): {
remote_ip = stream->S::remoteIP();
remote_port = (uint16_t)stream->S::remotePort();
poll_reply();
return OpCode::Poll;
}
default: {
Serial.print("Unsupported OpCode: ");
Serial.println(opcode(d), HEX);
return OpCode::NA;
if (checkID(d))
{
if (opcode(d) == OPC(OpCode::Dmx))
{
// TODO: std::move...
memcpy(packet.data(), d, size);
remote_ip = stream->S::remoteIP();
remote_port = (uint16_t)stream->S::remotePort();
for (auto& c : callbacks)
{
if (universe15bit() == c.universe) c.func(data(), size);
}
return true;
}
}
return OpCode::NA;
return false;
}
inline const IPAddress& ip() const { return remote_ip; }
inline uint16_t port() const { return remote_port; }
inline String id() const {
inline String id() const
{
String str;
for (uint8_t i = 0; i < ID_LENGTH; ++i) str += packet[IDX(Index::ID) + i];
return str;
}
inline uint16_t opcode() const {
inline uint16_t opcode() const
{
return (packet[IDX(Index::OP_CODE_H)] << 8) | packet[IDX(Index::OP_CODE_L)];
}
inline uint16_t opcode(const uint8_t* p) const {
inline uint16_t opcode(const uint8_t* p) const
{
return (p[IDX(Index::OP_CODE_H)] << 8) | p[IDX(Index::OP_CODE_L)];
}
inline uint16_t version() const {
inline uint16_t version() const
{
return (packet[IDX(Index::PROTOCOL_VER_H)] << 8) | packet[IDX(Index::PROTOCOL_VER_L)];
}
inline uint8_t sequence() const {
inline uint8_t sequence() const
{
return packet[IDX(Index::SEQUENCE)];
}
inline uint8_t physical() const {
inline uint8_t physical() const
{
return packet[IDX(Index::PHYSICAL)];
}
uint8_t net() const {
inline uint8_t net() const
{
return packet[IDX(Index::NET)] & 0x7F;
}
uint8_t subnet() const {
inline uint8_t subnet() const
{
return (packet[IDX(Index::SUBUNI)] >> 4) & 0x0F;
}
inline uint8_t universe() const {
inline uint8_t universe() const
{
return packet[IDX(Index::SUBUNI)] & 0x0F;
}
inline uint16_t universe15bit() const {
inline uint16_t universe15bit() const
{
return (packet[IDX(Index::NET)] << 8) | packet[IDX(Index::SUBUNI)];
}
inline uint16_t length() const {
inline uint16_t length() const
{
return (packet[IDX(Index::LENGTH_H)] << 8) | packet[IDX(Index::LENGTH_L)];
}
inline uint16_t size() const {
inline uint16_t size() const
{
return length();
}
inline uint8_t* data() {
inline uint8_t* data()
{
return &(packet[HEADER_SIZE]);
}
inline uint8_t data(const uint16_t i) const {
inline uint8_t data(const uint16_t i) const
{
return packet[HEADER_SIZE + i];
}
template <typename F>
inline auto subscribe(const uint8_t universe, F&& func)
-> std::enable_if_t<arx::is_callable<F>::value> {
if (callbacks.size() >= 4) {
Serial.println(F("too many callbacks"));
} else {
if (universe > 0xF) {
Serial.println(F("universe out of bounds"));
return;
} else {
uint32_t u = ((uint32_t)net_switch << 8) | ((uint32_t)sub_switch << 4) | (uint32_t)universe;
callbacks.insert(make_pair(u, arx::function_traits<F>::cast(func)));
}
}
}
template <typename F>
inline auto subscribe(const uint8_t universe, F* func)
-> std::enable_if_t<arx::is_callable<F>::value> {
if (callbacks.size() >= 4) {
Serial.println(F("too many callbacks"));
} else {
if (universe > 0xF) {
Serial.println(F("universe out of bounds"));
} else {
uint32_t u = ((uint32_t)net_switch << 8) | ((uint32_t)sub_switch << 4) | (uint32_t)universe;
callbacks.insert(make_pair(u, arx::function_traits<F>::cast(func)));
}
}
}
template <typename F>
inline auto subscribe(F&& func)
-> std::enable_if_t<arx::is_callable<F>::value> {
callback_all = arx::function_traits<F>::cast(func);
}
template <typename F>
inline auto subscribe(F* func)
-> std::enable_if_t<arx::is_callable<F>::value> {
callback_all = arx::function_traits<F>::cast(func);
}
inline void unsubscribe(const uint8_t universe) {
auto it = callbacks.find(universe);
if (it != callbacks.end())
callbacks.erase(it);
}
inline void unsubscribe() {
callback_all = nullptr;
}
inline void clear_subscribers() {
unsubscribe();
callbacks.clear();
inline void subscribe(const uint32_t universe, const CallbackType& func)
{
callbacks.push_back(Map{universe, func});
}
#ifdef FASTLED_VERSION
inline void forward(const uint8_t universe, CRGB* leds, const uint16_t num) {
subscribe(universe, [&](const uint8_t* data, const uint16_t size) {
if (size < num * 3) Serial.println(F("ERROR: Too many LEDs to forward"));
for (size_t pixel = 0; pixel < num; ++pixel) {
size_t idx = pixel * 3;
leds[pixel].r = data[idx + 0];
leds[pixel].g = data[idx + 1];
leds[pixel].b = data[idx + 2];
}
});
}
#endif
void shortname(const String& sn) {
short_name = sn;
inline void subscribe(const CallbackType& func)
{
subscribe(0, func);
}
void longname(const String& ln) {
long_name = ln;
}
void nodereport(const String& nr) {
node_report = nr;
inline void subscribe(const uint8_t net, const uint8_t subnet, const uint8_t universe, const CallbackType& func)
{
uint32_t u = ((uint32_t)net << 8) | ((uint32_t)subnet << 4) | (uint32_t)universe;
subscribe(u, func);
}
protected:
void attach(S& s, const uint8_t subscribe_net = 0, const uint8_t subscribe_subnet = 0) {
stream = &s;
if (subscribe_net > 128) {
Serial.println("Net must be < 128");
} else {
net_switch = subscribe_net;
}
if (subscribe_subnet > 16) {
Serial.println("Subnet must be < 16");
} else {
sub_switch = subscribe_subnet;
}
}
void attach(S& s) { stream = &s; }
private:
inline bool checkID() const {
inline bool checkID() const
{
const char* idptr = reinterpret_cast<const char*>(packet.data());
return !strcmp(ID, idptr);
}
inline bool checkID(const uint8_t* p) const {
inline bool checkID(const uint8_t* p) const
{
const char* idptr = reinterpret_cast<const char*>(p);
return !strcmp(ID, idptr);
}
void poll_reply() {
ArtPollReply r;
for (size_t i = 0; i < ID_LENGTH; i++) r.id[i] = static_cast<uint8_t>(ID[i]);
r.op_code_l = ((uint16_t)OpCode::PollReply >> 0) & 0x00FF;
r.op_code_h = ((uint16_t)OpCode::PollReply >> 8) & 0x00FF;
#ifdef ARTNET_ENABLE_WIFI
IPAddress my_ip = WiFi.localIP();
IPAddress my_subnet = WiFi.subnetMask();
WiFi.macAddress(r.mac);
#endif
#ifdef ARTNET_ENABLE_ETHER
IPAddress my_ip = Ethernet.localIP();
IPAddress my_subnet = Ethernet.subnetMask();
Ethernet.MACAddress(r.mac);
#endif
for (size_t i = 0; i < 4; ++i) r.ip[i] = my_ip[i];
r.port_l = (DEFAULT_PORT >> 0) & 0xFF;
r.port_h = (DEFAULT_PORT >> 8) & 0xFF;
r.ver_h = (PROTOCOL_VER >> 8) & 0x00FF;
r.ver_l = (PROTOCOL_VER >> 0) & 0x00FF;
r.oem_h = 0; // https://github.com/tobiasebsen/ArtNode/blob/master/src/Art-NetOemCodes.h
r.oem_l = 0xFF; // OemUnknown
r.ubea_ver = 0; // UBEA not programmed
r.status_1 = 0x00; // Unknown / Normal
r.esta_man_l = 0; // No EATA manufacture code
r.esta_man_h = 0; // No ESTA manufacture code
memset(r.short_name, 0, 18);
memset(r.long_name, 0, 64);
memset(r.node_report, 0, 64);
memcpy(r.short_name, short_name.c_str(), short_name.length());
memcpy(r.long_name, long_name.c_str(), long_name.length());
memcpy(r.node_report, node_report.c_str(), node_report.length());
r.num_ports_h = 0; // Reserved
r.num_ports_l = callbacks.size(); // This library implements only 4 port
memset(r.sw_in, 0, 4);
memset(r.sw_out, 0, 4);
memset(r.port_types, 0, 4);
memset(r.good_input, 0, 4);
memset(r.good_output, 0, 4);
r.net_sw = net_switch & 0x7F;
r.sub_sw = sub_switch & 0x0F;
size_t i = 0;
for (const auto& pair : callbacks) {
r.sw_in[i] = pair.first & 0x0F;
r.sw_out[i] = i; // dummy: output port is flexible
r.port_types[i] = 0xC0; // I/O available by DMX512
r.good_input[i] = 0x80; // Data received without error
r.good_output[i] = 0x80; // Data transmitted without error
if (++i >= 4) break;
}
r.sw_video = 0; // Video display shows local data
r.sw_macro = 0; // No support for macro key inputs
r.sw_remote = 0; // No support for remote trigger inputs
memset(r.spare, 0x00, 3);
r.style = 0x00; // A DMX to / from Art-Net device
for (size_t i = 0; i < 4; ++i) r.bind_ip[i] = my_ip[i];
r.bind_index = 0;
r.status_2 = 0x08; // sACN capable
memset(r.filler, 0x00, 26);
static const IPAddress local_broadcast_addr = IPAddress((uint32_t)my_ip | ~(uint32_t)my_subnet);
stream->beginPacket(local_broadcast_addr, DEFAULT_PORT);
stream->write(r.b, sizeof(ArtPollReply));
stream->endPacket();
}
}; // namespace artnet
};
template <typename S>
class Manager : public Sender_<S>, public Receiver_<S> {
class Manager : public Sender_<S>, public Receiver_<S>
{
S stream;
public:
void begin(const uint8_t subscribe_net = 0, const uint8_t subscribe_subnet = 0, const uint16_t recv_port = DEFAULT_PORT) {
void begin(const char* send_ip, uint32_t send_port = DEFAULT_PORT, uint32_t recv_port = DEFAULT_PORT)
{
stream.begin(recv_port);
this->Sender_<S>::attach(stream);
this->Receiver_<S>::attach(stream, subscribe_net, subscribe_subnet);
}
void parse() {
this->Receiver_<S>::parse();
this->Sender_<S>::attach(stream, send_ip, send_port);
this->Receiver_<S>::attach(stream);
}
};
template <typename S>
class Sender : public Sender_<S> {
class Sender : public Sender_<S>
{
S stream;
public:
void begin() {
stream.begin(DEFAULT_PORT);
this->Sender_<S>::attach(stream);
void begin(const char* ip, uint32_t port = DEFAULT_PORT)
{
this->Sender_<S>::attach(stream, ip, port);
}
};
template <typename S>
class Receiver : public Receiver_<S> {
class Receiver : public Receiver_<S>
{
S stream;
public:
void begin(const uint8_t subscribe_net = 0, const uint8_t subscribe_subnet = 0, const uint16_t recv_port = DEFAULT_PORT) {
stream.begin(recv_port);
this->Receiver_<S>::attach(stream, subscribe_net, subscribe_subnet);
void begin(uint32_t port = DEFAULT_PORT)
{
stream.begin(port);
this->Receiver_<S>::attach(stream);
}
};
} // namespace artnet
} // namespace arx
#ifdef ARTNET_ENABLE_WIFI
using ArtnetWiFi = arx::artnet::Manager<WiFiUDP>;
using ArtnetWiFiSender = arx::artnet::Sender<WiFiUDP>;
using ArtnetWiFiReceiver = arx::artnet::Receiver<WiFiUDP>;
#endif
#ifdef ARTNET_ENABLE_ETHER
using Artnet = arx::artnet::Manager<EthernetUDP>;
using ArtnetSender = arx::artnet::Sender<EthernetUDP>;
using ArtnetReceiver = arx::artnet::Receiver<EthernetUDP>;
}
}
#if defined (ESP_PLATFORM) || defined (ESP8266)
using Artnet = arduino::artnet::Manager<WiFiUDP>;
using ArtnetSender = arduino::artnet::Sender<WiFiUDP>;
using ArtnetReceiver = arduino::artnet::Receiver<WiFiUDP>;
#elif defined (TEENSYDUINO) || defined (__AVR__)
using Artnet = arduino::artnet::Manager<EthernetUDP>;
using ArtnetSender = arduino::artnet::Sender<EthernetUDP>;
using ArtnetReceiver = arduino::artnet::Receiver<EthernetUDP>;
#endif
#endif // ARDUINO_ARTNET_H
#endif // ARDUINO_ARTNET_H

@ -1,49 +0,0 @@
#include <FastLED.h> // include FastLED *before* Artnet
#include <Artnet.h>
// Ethernet stuff
const IPAddress ip(192, 168, 0, 201);
uint8_t mac[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB};
ArtnetReceiver artnet;
uint8_t universe = 1; // 0 - 15
// FastLED
#define NUM_LEDS 1
CRGB leds[NUM_LEDS];
const uint8_t PIN_LED_DATA = 3;
void setup() {
Serial.begin(115200);
delay(2000);
FastLED.addLeds<NEOPIXEL, PIN_LED_DATA>(leds, NUM_LEDS);
Ethernet.begin(mac, ip);
artnet.begin();
// artnet.subscribe_net(0); // optionally you can change
// artnet.subscribe_subnet(0); // optionally you can change
// if Artnet packet comes to this universe, forward them to fastled directly
artnet.forward(universe, leds, NUM_LEDS);
// this can be achieved manually as follows
// if Artnet packet comes to this universe, this function is called
// artnet.subscribe(universe, [&](uint8_t* data, uint16_t size)
// {
// // set led
// // artnet data size per packet is 512 max
// // so there is max 170 pixel per packet (per universe)
// for (size_t pixel = 0; pixel < NUM_LEDS; ++pixel) {
// size_t idx = pixel * 3;
// leds[pixel].r = data[idx + 0];
// leds[pixel].g = data[idx + 1];
// leds[pixel].b = data[idx + 2];
// }
// });
}
void loop() {
artnet.parse(); // check if artnet packet has come and execute callback
FastLED.show();
}

@ -1,35 +1,34 @@
#include <Artnet.h>
// Ethernet stuff
const IPAddress ip(192, 168, 0, 201);
const IPAddress ip(192, 168, 1, 201);
uint8_t mac[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB};
ArtnetReceiver artnet;
uint32_t universe1 = 1; // 0 - 15
uint32_t universe2 = 2; // 0 - 15
uint32_t universe1 = 1;
uint32_t universe2 = 2;
void callback(const uint8_t* data, const uint16_t size) {
void callback(uint8_t* data, uint16_t size)
{
// you can also use pre-defined callbacks
}
void setup() {
void setup()
{
Serial.begin(115200);
Ethernet.begin(mac, ip);
artnet.begin();
// artnet.subscribe_net(0); // optionally you can change
// artnet.subscribe_subnet(0); // optionally you can change
// if Artnet packet comes to this universe, this function is called
artnet.subscribe(universe1, [&](const uint8_t* data, const uint16_t size) {
artnet.subscribe(universe1, [&](uint8_t* data, uint16_t size)
{
Serial.print("artnet data (universe : ");
Serial.print(universe1);
Serial.print(", size = ");
Serial.print(size);
Serial.print(") :");
for (size_t i = 0; i < size; ++i) {
Serial.print(data[i]);
Serial.print(",");
Serial.println(") = ");
for (size_t i = 0; i < size; ++i)
{
Serial.print(data[i]); Serial.print(",");
}
Serial.println();
});
@ -38,6 +37,7 @@ void setup() {
artnet.subscribe(universe2, callback);
}
void loop() {
artnet.parse(); // check if artnet packet has come and execute callback
void loop()
{
artnet.parse(); // check if artnet packet has come and execute callback
}

@ -1,61 +1,50 @@
#ifdef __AVR__
#warning THIS EXAMPLE MAY USE TOO MUCH MEMORY FOR AVR. WE RECOMMEND TO USE SENDER OR RECEIVER ONLY.
#endif
#include <Artnet.h>
// Ethernet stuff
const IPAddress ip(192, 168, 0, 201);
const IPAddress ip(192, 168, 1, 201);
uint8_t mac[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB};
Artnet artnet;
const String target_ip = "192.168.0.200";
uint8_t universe = 1; // 0 - 15
const uint16_t size = 512;
uint8_t data[size];
uint8_t value = 0;
uint32_t universe = 1;
void setup() {
void setup()
{
Serial.begin(115200);
delay(2000);
Ethernet.begin(mac, ip);
artnet.begin();
// artnet.begin(net, subnet); // optionally you can change
artnet.begin("127.0.0.1"); // send to localhost
Serial.println("set subscriber");
// if Artnet packet comes to this universe, this function is called
artnet.subscribe(universe, [](const uint8_t* data, const uint16_t size) {
artnet.subscribe(universe, [](uint8_t* data, uint16_t size)
{
Serial.print("artnet data (universe : ");
Serial.print(universe);
Serial.print(", size = ");
Serial.print(size);
Serial.print(") :");
for (size_t i = 0; i < size; ++i) {
Serial.print(data[i]);
Serial.print(",");
Serial.println(") = ");
for (size_t i = 0; i < size; ++i)
{
Serial.print(data[i]); Serial.print(",");
}
Serial.println();
});
// if Artnet packet comes, this function is called to every universe
artnet.subscribe([&](const uint32_t univ, const uint8_t* data, const uint16_t size) {
Serial.print("ArtNet data has come to universe: ");
Serial.println(univ);
});
Serial.println("start");
}
void loop() {
artnet.parse(); // check if artnet packet has come and execute callback
void loop()
{
artnet.parse(); // check if artnet packet has come and execute callback
value = (millis() / 4) % 256;
value = millis() % 256;
memset(data, value, size);
artnet.streaming_data(data, size);
artnet.streaming(target_ip, universe); // automatically send set data in 40fps
// artnet.streaming(target_ip, net, subnet, univ); // or you can set net, subnet, and universe
artnet.set(universe, data, size);
artnet.streaming(); // automatically send set data in 40fps
// Serial.println("loop");
}

@ -1,34 +1,27 @@
#include <Artnet.h>
// Ethernet stuff
const IPAddress ip(192, 168, 0, 201);
const IPAddress ip(192, 168, 1, 201);
uint8_t mac[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB};
ArtnetSender artnet;
const String target_ip = "192.168.0.200";
uint32_t universe = 1;
const uint16_t size = 512;
uint8_t data[size];
uint8_t value = 0;
void setup() {
Serial.begin(115200);
delay(2000);
void setup()
{
Ethernet.begin(mac, ip);
artnet.begin();
// artnet.begin(net, subnet); // optionally you can change
Serial.println("start");
Serial.println(UDP_TX_PACKET_MAX_SIZE);
artnet.begin("127.0.0.1");
}
void loop() {
value = (millis() / 4) % 256;
void loop()
{
value = millis() % 256;
memset(data, value, size);
artnet.streaming_data(data, size);
artnet.streaming(target_ip, universe); // automatically send set data in 40fps
// artnet.streaming(target_ip, net, subnet, univ); // or you can set net, subnet, and universe
artnet.set(universe, data, size);
artnet.streaming(); // automatically send set data in 40fps
}

@ -1,60 +0,0 @@
#include <FastLED.h> // include FastLED *before* Artnet
#include <Artnet.h>
// WiFi stuff
const char* ssid = "your-ssid";
const char* pwd = "your-password";
const IPAddress ip(192, 168, 1, 201);
const IPAddress gateway(192, 168, 1, 1);
const IPAddress subnet(255, 255, 255, 0);
ArtnetWiFiReceiver artnet;
uint8_t universe = 1; // 0 - 15
// FastLED
#define NUM_LEDS 1
CRGB leds[NUM_LEDS];
const uint8_t PIN_LED_DATA = 3;
void setup() {
Serial.begin(115200);
delay(2000);
FastLED.addLeds<NEOPIXEL, PIN_LED_DATA>(leds, NUM_LEDS);
// WiFi stuff
WiFi.begin(ssid, pwd);
WiFi.config(ip, gateway, subnet);
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
Serial.print("WiFi connected, IP = ");
Serial.println(WiFi.localIP());
artnet.begin();
// artnet.subscribe_net(0); // optionally you can change
// artnet.subscribe_subnet(0); // optionally you can change
// if Artnet packet comes to this universe, forward them to fastled directly
artnet.forward(universe, leds, NUM_LEDS);
// this can be achieved manually as follows
// if Artnet packet comes to this universe, this function (lambda) is called
// artnet.subscribe(universe, [&](uint8_t* data, uint16_t size) {
// // set led
// // artnet data size per packet is 512 max
// // so there is max 170 pixel per packet (per universe)
// for (size_t pixel = 0; pixel < NUM_LEDS; ++pixel) {
// size_t idx = pixel * 3;
// leds[pixel].r = data[idx + 0];
// leds[pixel].g = data[idx + 1];
// leds[pixel].b = data[idx + 2];
// }
// });
}
void loop() {
artnet.parse(); // check if artnet packet has come and execute callback
FastLED.show();
}

@ -7,41 +7,36 @@ const IPAddress ip(192, 168, 1, 201);
const IPAddress gateway(192, 168, 1, 1);
const IPAddress subnet(255, 255, 255, 0);
ArtnetWiFiReceiver artnet;
uint8_t universe1 = 1; // 0 - 15
uint8_t universe2 = 2; // 0 - 15
ArtnetReceiver artnet;
uint32_t universe1 = 1;
uint32_t universe2 = 2;
void callback(const uint8_t* data, const uint16_t size) {
void callback(uint8_t* data, uint16_t size)
{
// you can also use pre-defined callbacks
}
void setup() {
void setup()
{
Serial.begin(115200);
// WiFi stuff
WiFi.begin(ssid, pwd);
WiFi.config(ip, gateway, subnet);
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
Serial.print("WiFi connected, IP = ");
Serial.println(WiFi.localIP());
while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(500); }
Serial.print("WiFi connected, IP = "); Serial.println(WiFi.localIP());
artnet.begin();
// artnet.subscribe_net(0); // optionally you can change
// artnet.subscribe_subnet(0); // optionally you can change
// if Artnet packet comes to this universe, this function (lambda) is called
artnet.subscribe(universe1, [&](const uint8_t* data, const uint16_t size) {
artnet.subscribe(universe1, [&](uint8_t* data, uint16_t size)
{
Serial.print("lambda : artnet data (universe : ");
Serial.print(universe1);
Serial.print(", size = ");
Serial.print(size);
Serial.print(") :");
for (size_t i = 0; i < size; ++i) {
Serial.print(data[i]);
Serial.print(",");
Serial.println(") = ");
for (size_t i = 0; i < size; ++i)
{
Serial.print(data[i]); Serial.print(",");
}
Serial.println();
});
@ -50,6 +45,7 @@ void setup() {
artnet.subscribe(universe2, callback);
}
void loop() {
artnet.parse(); // check if artnet packet has come and execute callback
void loop()
{
artnet.parse(); // check if artnet packet has come and execute callback
}

@ -7,58 +7,46 @@ const IPAddress ip(192, 168, 1, 201);
const IPAddress gateway(192, 168, 1, 1);
const IPAddress subnet(255, 255, 255, 0);
ArtnetWiFi artnet;
const String target_ip = "192.168.1.200";
uint8_t universe = 1; // 0 - 15
Artnet artnet;
const uint16_t size = 512;
uint8_t data[size];
uint8_t value = 0;
uint32_t universe = 1;
void setup() {
void setup()
{
Serial.begin(115200);
// WiFi stuff
WiFi.begin(ssid, pwd);
WiFi.config(ip, gateway, subnet);
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
Serial.print("WiFi connected, IP = ");
Serial.println(WiFi.localIP());
while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(500); }
Serial.print("WiFi connected, IP = "); Serial.println(WiFi.localIP());
artnet.begin();
// artnet.begin(net, subnet); // optionally you can change net and subnet
artnet.begin("127.0.0.1"); // send to localhost
// if Artnet packet comes to this universe, this function is called
artnet.subscribe(universe, [&](const uint8_t* data, const uint16_t size) {
artnet.subscribe(universe, [&](uint8_t* data, uint16_t size)
{
Serial.print("artnet data (universe : ");
Serial.print(universe);
Serial.print(", size = ");
Serial.print(size);
Serial.print(") :");
for (size_t i = 0; i < size; ++i) {
Serial.print(data[i]);
Serial.print(",");
Serial.println(") = ");
for (size_t i = 0; i < size; ++i)
{
Serial.print(data[i]); Serial.print(",");
}
Serial.println();
});
// if Artnet packet comes, this function is called to every universe
artnet.subscribe([&](const uint32_t univ, const uint8_t* data, const uint16_t size) {
Serial.print("ArtNet data has come to universe: ");
Serial.println(univ);
});
}
void loop() {
artnet.parse(); // check if artnet packet has come and execute callback
void loop()
{
artnet.parse(); // check if artnet packet has come and execute callback
value = (millis() / 4) % 256;
value = millis() % 256;
memset(data, value, size);
artnet.streaming_data(data, size);
artnet.streaming(target_ip, universe); // automatically send set data in 40fps
// artnet.streaming(target_ip, net, subnet, univ); // or you can set net, subnet, and universe
artnet.set(universe, data, size);
artnet.streaming(); // automatically send set data in 40fps
}

@ -7,36 +7,31 @@ const IPAddress ip(192, 168, 1, 201);
const IPAddress gateway(192, 168, 1, 1);
const IPAddress subnet(255, 255, 255, 0);
ArtnetWiFiSender artnet;
const String target_ip = "192.168.1.200";
ArtnetSender artnet;
uint32_t universe = 1;
const uint16_t size = 512;
uint8_t data[size];
uint8_t value = 0;
void setup() {
void setup()
{
Serial.begin(115200);
// WiFi stuff
WiFi.begin(ssid, pwd);
WiFi.config(ip, gateway, subnet);
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
Serial.print("WiFi connected, IP = ");
Serial.println(WiFi.localIP());
artnet.begin();
// artnet.begin(net, subnet); // optionally you can change net and subnet
while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(500); }
Serial.print("WiFi connected, IP = "); Serial.println(WiFi.localIP());
artnet.begin("127.0.0.1");
}
void loop() {
value = (millis() / 4) % 256;
void loop()
{
value = millis() % 256;
memset(data, value, size);
artnet.streaming_data(data, size);
artnet.streaming(target_ip, universe); // automatically send set data in 40fps
// artnet.streaming(target_ip, net, subnet, univ); // or you can set net, subnet, and universe
artnet.set(universe, data, size);
artnet.streaming(); // automatically send set data in 40fps
}

@ -1,17 +1,19 @@
{
"name": "UIPArtNet",
"name": "ArtNet",
"keywords": "Art-Net,Artnet,Ethernet,WiFi",
"description": "Art-Net Sender/Receiver for Arduino (Ethernet, WiFi)binary data packer / unpacker",
"repository": {
"repository":
{
"type": "git",
"url": "https://git.adb.sh/adb/UIPArtnet.git"
"url": "https://github.com/hideakitai/ArtNet.git"
},
"authors": {
"authors":
{
"name": "Hideaki Tai",
"url": "https://github.com/hideakitai",
"maintainer": true
},
"version": "0.2.1",
"version": "0.1.0",
"license": "MIT",
"frameworks": "*",
"platforms": "*"

@ -1,9 +1,9 @@
name=ArtNet
version=0.2.1
version=0.1.0
author=hideakitai
maintainer=hideakitai
sentence=Art-Net Sender/Receiver for Arduino (Ethernet, WiFi)
paragraph=Art-Net Sender/Receiver for Arduino (Ethernet, WiFi)
category=Communication
url=https://github.com/hideakitai/ArtNet
url=https://github.com/hideakitai
architectures=*

@ -1,556 +0,0 @@
#pragma once
#ifndef ARX_RINGBUFFER_H
#define ARX_RINGBUFFER_H
#if __cplusplus < 201103L
#error "C++11 must be enabled in the compiler for this library to work, please check your compiler flags"
#endif
#include "ArxContainer/has_include.h"
#include "ArxContainer/has_libstdcplusplus.h"
#ifdef ARDUINO
#include <Arduino.h>
#endif
#include "ArxContainer/replace_minmax_macros.h"
#include "ArxContainer/initializer_list.h"
#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11
#include <vector>
#include <deque>
#include <map>
#else // Do not have libstdc++11
#ifndef ARX_VECTOR_DEFAULT_SIZE
#define ARX_VECTOR_DEFAULT_SIZE 16
#endif // ARX_VECTOR_DEFAULT_SIZE
#ifndef ARX_DEQUE_DEFAULT_SIZE
#define ARX_DEQUE_DEFAULT_SIZE 16
#endif // ARX_DEQUE_DEFAULT_SIZE
#ifndef ARX_MAP_DEFAULT_SIZE
#define ARX_MAP_DEFAULT_SIZE 16
#endif // ARX_MAP_DEFAULT_SIZE
namespace arx {
namespace container
{
namespace detail
{
template<class T>
T&& move(T& t){ return static_cast<T&&>(t); }
}
}
template<typename T, size_t N>
class RingBuffer
{
protected:
T queue_[N];
int head_ {0};
int tail_ {0};
public:
RingBuffer()
: queue_()
, head_ {0}
, tail_{0}
{
}
RingBuffer(std::initializer_list<T> lst)
: queue_()
, head_(0)
, tail_(0)
{
for (auto it = lst.begin() ; it != lst.end() ; ++it)
{
queue_[tail_] = *it;
++tail_;
}
}
// copy
explicit RingBuffer(const RingBuffer& r)
: queue_()
, head_(r.head_)
, tail_(r.tail_)
{
for (size_t i = 0; i < r.size(); ++i)
queue_[i] = r.queue_[i];
}
RingBuffer& operator= (const RingBuffer& r)
{
head_ = r.head_;
tail_ = r.tail_;
for (size_t i = 0; i < r.size(); ++i)
queue_[i] = r.queue_[i];
return *this;
}
// move
RingBuffer(RingBuffer&& r)
{
head_ = container::detail::move(r.head_);
tail_ = container::detail::move(r.tail_);
for (size_t i = 0; i < r.size(); ++i)
queue_[i] = container::detail::move(r.queue_[i]);
}
RingBuffer& operator= (RingBuffer&& r)
{
head_ = container::detail::move(r.head_);
tail_ = container::detail::move(r.tail_);
for (size_t i = 0; i < r.size(); ++i)
queue_[i] = container::detail::move(r.queue_[i]);
return *this;
}
virtual ~RingBuffer() {}
using iterator = T*;
using const_iterator = const T*;
size_t capacity() const { return N; };
size_t size() const { return tail_ - head_; }
inline const T* data() const { return &(get(head_)); }
T* data() { return &(get(head_)); }
bool empty() const { return tail_ == head_; }
void clear() { head_ = 0; tail_ = 0; }
void pop() { pop_front(); }
void pop_front()
{
if (size() == 0) return;
if (size() == 1) clear();
else head_++;
}
void pop_back()
{
if (size() == 0) return;
if (size() == 1) clear();
else tail_--;
}
void push(const T& data) { push_back(data); }
void push(T&& data) { push_back(data); }
void push_back(const T& data)
{
get(tail_++) = data;
if (size() > N) ++head_;
};
void push_back(T&& data)
{
get(tail_++) = data;
if (size() > N) ++head_;
};
void push_front(const T& data)
{
get(head_--) = data;
if (size() > N) --tail_;
};
void push_front(T&& data)
{
get(head_--) = data;
if (size() > N) --tail_;
};
void emplace(const T& data) { push(data); }
void emplace(T&& data) { push(data); }
void emplace_back(const T& data) { push_back(data); }
void emplace_back(T&& data) { push_back(data); }
const T& front() const { return get(head_); };
T& front() { return get(head_); };
const T& back() const { return get(tail_ - 1); }
T& back() { return get(tail_ - 1); }
const T& operator[] (size_t index) const { return get(head_ + (int)index); }
T& operator[] (size_t index) { return get(head_ + (int)index); }
iterator begin() { return ptr(head_); }
iterator end() { return (queue_ + tail_); }
const_iterator begin() const { return (const_iterator)ptr(head_); }
const_iterator end() const { return (const_iterator)(queue_ + tail_); }
iterator erase(iterator p)
{
if (p == end()) return p;
for (T* pos = p + 1; pos != end(); ++pos)
*(pos - 1) = *pos;
--tail_;
return p;
}
void resize(size_t sz)
{
size_t s = size();
if (sz > size())
{
for (size_t i = 0; i < sz - s; ++i) push(T());
}
else if (sz < size())
{
for (size_t i = 0; i < s - sz; ++i) pop();
}
}
void assign(const_iterator first, const_iterator end)
{
clear();
const char* p = first;
while (p != end) push(*p++);
}
void shrink_to_fit()
{
// dummy
}
void reserve(size_t n)
{
(void)n;
// dummy
}
void insert(const_iterator pos, const_iterator first, const_iterator last)
{
if (pos != end())
{
size_t sz = 0;
{
iterator it = (iterator)first;
for (; it != last; ++it) ++sz;
}
iterator it = end() + sz - 1;
for (int i = sz; i > 0; --i, --it)
{
*it = *(it - sz);
}
it = (iterator)pos;
for (size_t i = 0; i < sz; ++i)
{
*it = *(first + i);
}
}
else
{
iterator it = (iterator)first;
for (; it != last; ++it)
{
push_back(*it);
}
}
}
private:
T& get(const int i)
{
if (i >= 0) return queue_[i % N];
else return queue_[N - abs(i % N)];
}
const T& get(const int i) const
{
if (i >= 0) return queue_[i % N];
else return queue_[N - abs(i % N)];
}
T* ptr(const int i)
{
if (i >= 0) return (T*)(queue_ + i % N);
else return (T*)(queue_ + N - abs(i % N));
}
const T* ptr(const int i) const
{
if (i >= 0) return (T*)(queue_ + i % N);
else return (T*)(queue_ + N - abs(i % N));
}
};
template <typename T, size_t N>
bool operator== (const RingBuffer<T, N>& x, const RingBuffer<T, N>& y)
{
if (x.size() != y.size()) return false;
for (size_t i = 0; i < x.size(); ++i)
if (x[i] != y[i]) return false;
return true;
}
template <typename T, size_t N>
bool operator!= (const RingBuffer<T, N>& x, const RingBuffer<T, N>& y)
{
return !(x == y);
}
template <typename T, size_t N = ARX_VECTOR_DEFAULT_SIZE>
struct vector : public RingBuffer<T, N>
{
vector() : RingBuffer<T, N>() { }
vector(std::initializer_list<T> lst) : RingBuffer<T, N>(lst) { }
// copy
vector(const vector& r) : RingBuffer<T, N>(r) { }
vector& operator= (const vector& r)
{
RingBuffer<T, N>::operator=(r);
return *this;
}
// move
vector(vector&& r) : RingBuffer<T, N>(r) { }
vector& operator= (vector&& r)
{
RingBuffer<T, N>::operator=(r);
return *this;
}
virtual ~vector() {}
private:
using RingBuffer<T, N>::pop;
using RingBuffer<T, N>::pop_front;
using RingBuffer<T, N>::push;
using RingBuffer<T, N>::push_front;
using RingBuffer<T, N>::emplace;
};
template <typename T, size_t N = ARX_DEQUE_DEFAULT_SIZE>
struct deque : public RingBuffer<T, N>
{
deque() : RingBuffer<T, N>() { }
deque(std::initializer_list<T> lst) : RingBuffer<T, N>(lst) { }
// copy
deque(const deque& r) : RingBuffer<T, N>(r) { }
deque& operator= (const deque& r)
{
RingBuffer<T, N>::operator=(r);
return *this;
}
// move
deque(deque&& r) : RingBuffer<T, N>(r) { }
deque& operator= (deque&& r)
{
RingBuffer<T, N>::operator=(r);
return *this;
}
virtual ~deque() {}
private:
using RingBuffer<T, N>::capacity;
using RingBuffer<T, N>::pop;
using RingBuffer<T, N>::push;
using RingBuffer<T, N>::emplace;
using RingBuffer<T, N>::assign;
using RingBuffer<T, N>::begin;
using RingBuffer<T, N>::end;
};
template <class T1, class T2>
struct pair
{
T1 first;
T2 second;
};
template <class T1, class T2>
pair<T1, T2> make_pair(const T1& t1, const T2& t2)
{
return {t1, t2};
};
template <typename T1, typename T2>
bool operator== (const pair<T1, T2>& x, const pair<T1, T2>& y)
{
return (x.first == y.first) && (x.second == y.second);
}
template <typename T1, typename T2>
bool operator!= (const pair<T1, T2>& x, const pair<T1, T2>& y)
{
return !(x == y);
}
template <class Key, class T, size_t N = ARX_MAP_DEFAULT_SIZE>
struct map : public RingBuffer<pair<Key, T>, N>
{
using iterator = typename RingBuffer<pair<Key, T>, N>::iterator;
using const_iterator = typename RingBuffer<pair<Key, T>, N>::const_iterator;
map() : RingBuffer<pair<Key, T>, N>() { }
map(std::initializer_list<pair<Key, T>> lst) : RingBuffer<pair<Key, T>, N>(lst) { }
// copy
map(const map& r) : RingBuffer<pair<Key, T>, N>(r) { }
map& operator= (const map& r)
{
RingBuffer<pair<Key, T>, N>::operator=(r);
return *this;
}
// move
map(map&& r) : RingBuffer<T, N>(r) { }
map& operator= (map&& r)
{
RingBuffer<pair<Key, T>, N>::operator=(r);
return *this;
}
virtual ~map() {}
const_iterator find(const Key& key) const
{
for (size_t i = 0; i < this->size(); ++i)
{
const_iterator it = this->begin() + i;
if (key == it->first)
return it;
}
return this->end();
}
iterator find(const Key& key)
{
for (size_t i = 0; i < this->size(); ++i)
{
iterator it = this->begin() + i;
if (key == it->first)
return it;
}
return this->end();
}
pair<iterator, bool> insert(const Key& key, const T& t)
{
bool b {false};
iterator it = find(key);
if (it == this->end())
{
this->push(make_pair(key, t));
b = true;
it = this->end() - 1;
}
return {it, b};
}
pair<iterator, bool> insert(const pair<Key, T>& p)
{
bool b {false};
const_iterator it = find(p.first);
if (it == this->end())
{
this->push(p);
b = true;
it = this->end() - 1;
}
return {(iterator)it, b};
}
pair<iterator, bool> emplace(const Key& key, const T& t)
{
return insert(key, t);
}
pair<iterator, bool> emplace(const pair<Key, T>& p)
{
return insert(p);
}
const T& at(const Key& key) const
{
// iterator it = find(key);
// if (it != this->end()) return it->second;
// return T();
return find(key)->second;
}
T& at(const Key& key)
{
// iterator it = find(key);
// if (it != this->end()) return it->second;
// return T();
return find(key)->second;
}
iterator erase(const iterator it)
{
iterator i = (iterator)find(it->first);
if (i != this->end())
{
return this->erase(i);
}
return this->end();
}
iterator erase(const size_t index)
{
if (index < this->size())
{
iterator it = this->begin() + index;
return this->erase(it);
}
return this->end();
}
T& operator[] (const Key& key)
{
iterator it = find(key);
if (it != this->end()) return it->second;
insert(::arx::make_pair(key, T()));
return this->back().second;
}
private:
using RingBuffer<pair<Key, T>, N>::capacity;
using RingBuffer<pair<Key, T>, N>::data;
using RingBuffer<pair<Key, T>, N>::pop;
using RingBuffer<pair<Key, T>, N>::pop_front;
using RingBuffer<pair<Key, T>, N>::pop_back;
using RingBuffer<pair<Key, T>, N>::push;
using RingBuffer<pair<Key, T>, N>::push_back;
using RingBuffer<pair<Key, T>, N>::push_front;
using RingBuffer<pair<Key, T>, N>::emplace_back;
using RingBuffer<pair<Key, T>, N>::front;
using RingBuffer<pair<Key, T>, N>::back;
using RingBuffer<pair<Key, T>, N>::resize;
using RingBuffer<pair<Key, T>, N>::assign;
using RingBuffer<pair<Key, T>, N>::shrink_to_fit;
};
} // namespace arx
template<typename T, size_t N>
using ArxRingBuffer = arx::RingBuffer<T, N>;
#endif // Do not have libstdc++11
#endif // ARX_RINGBUFFER_H

@ -1,30 +0,0 @@
#pragma once
#ifndef ARX_TYPE_TRAITS_HAS_INCLUDE_H
#define ARX_TYPE_TRAITS_HAS_INCLUDE_H
// Check whether __has_include is available, but also check the GCC
// version (__has_include was introduced in gcc 5) to catch
// environments (such as ESP8266) where gcc is old, but some system
// header provides a fake __has_include. We also need to check
// against __clang__ here, since clang pretends to be GCC
// 4.something and would otherwise be detected incorrectly here...
#if !defined(__has_include) || defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__)
#if defined(ARDUINO_ARCH_ESP8266)
// ESP8266 does not have a working __has_include, but we
// know it does have a working libstdc++ with all the
// headers we care about, so provide a fake has_include
#define ARX_SYSTEM_HAS_INCLUDE(x) 1
#elif defined(ARDUINO_SAM_DUE)
// Arduino DUE's GCC version is 4.8.3 (GCC < 5.0).
// If libstdc++ is used, std::function causes error
// so currently we disable libstdc++ and use ArxTypeTraits
#define ARX_SYSTEM_HAS_INCLUDE(x) 0
#else
#error "Compiler does not support __has_include, please report a bug against the ArxTypeTraits library about this."
#endif
#else
#define ARX_SYSTEM_HAS_INCLUDE(x) __has_include(x)
#endif
#endif // ARX_TYPE_TRAITS_HAS_INCLUDE_H

@ -1,25 +0,0 @@
#pragma once
#ifndef ARX_TYPE_TRAITS_HAS_LIBSTDCPLUSPLUS_H
#define ARX_TYPE_TRAITS_HAS_LIBSTDCPLUSPLUS_H
#if !defined(ARX_HAVE_LIBSTDCPLUSPLUS)
#if ARX_SYSTEM_HAS_INCLUDE(<cstdlib>)
#include <cstdlib>
#if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION)
// For gcc's libstdc++ and clang's libc++, assume that
// __cplusplus tells us what the standard includes support
#define ARX_HAVE_LIBSTDCPLUSPLUS __cplusplus
#elif defined(__UCLIBCXX_MAJOR__)
// For uclibc++, assume C++98 support only.
#define ARX_HAVE_LIBSTDCPLUSPLUS 199711L
#else
#error "Unknown C++ library found, please report a bug against the ArxTypeTraits library about this."
#endif
#else
// Assume no standard library is available at all (e.g. on AVR)
#define ARX_HAVE_LIBSTDCPLUSPLUS 0
#endif
#endif
#endif // ARX_TYPE_TRAITS_HAS_LIBSTDCPLUSPLUS_H

@ -1,30 +0,0 @@
#pragma once
#ifndef ARX_TYPE_TRAITS_INITIALIZER_H
#define ARX_TYPE_TRAITS_INITIALIZER_H
// Initializer_list *must* be defined in std, so take extra care to only
// define it when <initializer_list> is really not available (e.g.
// ArduinoSTL is C++98 but *does* define <initializer_list>) and not
// already defined (e.g. by ArxContainer).
#if ARX_SYSTEM_HAS_INCLUDE(<initializer_list>)
#include <initializer_list>
#else
namespace std {
template<class T>
class initializer_list
{
private:
const T* array;
size_t len;
initializer_list(const T* a, size_t l) : array(a), len(l) {}
public:
initializer_list() : array(nullptr), len(0) {}
size_t size() const { return len; }
const T *begin() const { return array; }
const T *end() const { return array + len; }
};
} // namespace std
#endif
#endif // ARX_TYPE_TRAITS_INITIALIZER_LIST_H

@ -1,35 +0,0 @@
#pragma once
#ifndef ARX_TYPE_TRAITS_REPLACE_MINMAX_MACROS_H
#define ARX_TYPE_TRAITS_REPLACE_MINMAX_MACROS_H
// Make sure Arduino.h is actually included, since otherwise it might be
// included later and break *uses* of the min/max methods, rather than
// the declarations of it.
#ifdef ARDUINO
#include <Arduino.h>
#endif
// These macros are defined by Arduino.h on some platforms, and conflict
// with min/max methods defined or included by ArxTypeTraits, so replace
// them with macros here.
#ifdef max
#undef max
template <typename T1, typename T2>
constexpr auto max(T1 x, T2 y)
-> decltype(x + y)
{
return (x > y) ? x : y;
}
#endif
#ifdef min
#undef min
template <typename T1, typename T2>
constexpr auto min(T1 x, T2 y)
-> decltype(x + y)
{
return (x < y) ? x : y;
}
#endif
#endif // ARX_TYPE_TRAITS_REPLACE_MINMAX_MACROS_H

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2019 Hideaki Tai
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.

@ -1,174 +0,0 @@
# ArxContainer
C++ container-like classes (`vector`, `deque`, `map` etc.) for Arduino which cannot use STL
## Note
- `ArxContainer` is C++ container-__like__ classes for Arduino
- Containers in this library is defined inside namespace `arx` instad of `std` (e.g. `arx::vector`)
- All of the functions is not supported currently
- If standard libraries are available, automatically use `std` version instead of `arx` version
## Supported Container Types
- `vector`
- `map` (`pair`)
- `deque`
## Supported Boards
`arx` version of containers are enabled only if you use following architecture.
In other borads, `arx` version is disabled and standard libraries (`std` version) will be imported (because they can use them).
- AVR (Uno, Nano, Mega, etc.)
- MEGAAVR (Uno WiFi, Nano Ecery, etc.)
- SAM (Due)
## Usage
### vector
```C++
// initialize with initializer_list
arx::vector<int> vs {1, 2, 3};
// add contents
for (size_t i = 4; i <= 5; ++i)
vs.push_back(i);
// index access
for (size_t i = 0; i < vs.size(); ++i)
Serial.println(vs[i]);
// range-based access
for (const auto& v : vs)
Serial.println(v);
```
### map
``` C++
// initialize with initializer_list
arx::map<String, int> mp {{"one", 1}, {"two", 2}};
// add contents
mp.insert("three", 3);
mp["four"] = 4;
// range based access
for (const auto& m : mp)
{
Serial.print("{");
Serial.print(m.first); Serial.print(",");
Serial.print(m.second);
Serial.println("}");
}
// key access
Serial.print("one = "); Serial.println(mp["one"]);
Serial.print("two = "); Serial.println(mp["two"]);
Serial.print("three = "); Serial.println(mp["three"]);
Serial.print("four = "); Serial.println(mp["four"]);
```
### deque
```C++
// initialize with initializer_list
arx::deque<int> dq {1, 2, 3};
// add contents
for (int i = 4; i <= 5; ++i)
dq.push_back(i);
// index access
for (int i = 0; i < dq.size(); ++i)
Serial.print(dq[i]);
```
## Detail
`ArxContainer` is C++ container-__like__ classes for Arduino.
This library is based on `arx::RingBuffer` and `arx::xxxx` is limited-size container.
`arx::RingBuffer` can be used as:
```C++
ArxRingBuffer<uint8_t, 4> buffer;
buffer.push(1);
buffer.push(2);
buffer.push(3);
for(size_t i = 0; i < buffer.size(); ++i)
Serial.println(buffer[i]);
buffer.pop();
for(auto& b : buffer)
Serial.println(b);
```
`arx::xxxx` are derived from `RingBuffer` and defined as:
``` C++
namespace arx {
template <typename T, size_t N = ARX_VECTOR_DEFAULT_SIZE>
struct vector : public RingBuffer<T, N>
template <class Key, class T, size_t N = ARX_MAP_DEFAULT_SIZE>
struct map : public RingBuffer<pair<Key, T>, N>
template <typename T, size_t N = ARX_DEQUE_DEFAULT_SIZE>
struct deque : public RingBuffer<T, N>
}
```
So range-based loop cannot be applyed to `arx::deque` (iterator is not continuous because it is based on `RingBuffer`).
### Manage Size Limit of Container
Global default size of container can be changed by defining these macros before `#include <ArxContainer.h>`.
``` C++
#define ARX_VECTOR_DEFAULT_SIZE XX // default: 16
#define ARX_MAP_DEFAULT_SIZE XX // default: 16
#define ARX_DEQUE_DEFAULT_SIZE XX // default: 16
```
Or you can change each container size by template argument.
``` C++
arx::vector<int, 3> vs;
arx::map<String, int, 4> ms;
arx::deque<int, 5> ds;
```
## Roadmap
This library will be updated if I want to use more container interfaces on supported boards shown above.
PRs are welcome!
## Used Inside of
- [Packetizer](https://github.com/hideakitai/Packetizer)
- [MsgPack](https://github.com/hideakitai/MsgPack)
- [MsgPacketizer](https://github.com/hideakitai/MsgPacketizer)
- [ArduinoOSC](https://github.com/hideakitai/ArduinoOSC)
- [ArtNet](https://github.com/hideakitai/ArtNet)
- [Tween](https://github.com/hideakitai/Tween)
- [TimeProfiler](https://github.com/hideakitai/TimeProfiler)
- [SceneManager](https://github.com/hideakitai/SceneManager)
- [TaskManager](https://github.com/hideakitai/TaskManager)
- [ArxStringUtils](https://github.com/hideakitai/ArxStringUtils)
- [Debouncer](https://github.com/hideakitai/Debouncer)
## License
MIT

@ -1,18 +0,0 @@
{
"name": "ArxContainer",
"keywords": "ringbuffer, vector, deque, map",
"description": "C++ container-like classes (vector, map, etc.) for Arduino which cannot use STL",
"repository": {
"type": "git",
"url": "https://github.com/hideakitai/ArxContainer.git"
},
"authors": {
"name": "Hideaki Tai",
"url": "https://github.com/hideakitai",
"maintainer": true
},
"version": "0.3.10",
"license": "MIT",
"frameworks": "arduino",
"platforms": "*"
}

@ -1,9 +0,0 @@
name=ArxContainer
version=0.3.10
author=hideakitai
maintainer=hideakitai
sentence=C++ container-like classes (vector, map, etc.) for Arduino which cannot use STL
paragraph=C++ container-like classes (vector, map, etc.) for Arduino which cannot use STL
category=Data Storage
url=https://github.com/hideakitai/ArxContainer
architectures=*

@ -1,42 +0,0 @@
#pragma once
#ifndef ARX_TYPE_TRAITS_H
#define ARX_TYPE_TRAITS_H
#if __cplusplus < 201103L
#error "C++11 must be enabled in the compiler for this library to work, please check your compiler flags"
#endif
#include "ArxTypeTraits/has_include.h"
#include "ArxTypeTraits/has_libstdcplusplus.h"
// Make sure std namespace exists
namespace std { }
// Import everything from the std namespace into arx::std, so that
// anything we import rather than define is also available through
// arx::stdx.
// This includes everything yet to be defined, so we can do this early
// (and must do so, to allow e.g. the C++14 additions in the arx::std
// namespace to reference the C++11 stuff from the system headers.
namespace arx {
namespace stdx {
using namespace ::std;
}
}
// Import everything from arx::std back into the normal std namespace.
// This ensures that you can just use `std::foo` everywhere and you get
// the standard library version if it is available, falling back to arx
// versions for things not supplied by the standard library. Only when
// you really need the arx version (e.g. for constexpr numeric_limits
// when also using ArduinoSTL), you need to qualify with arx::stdx::
namespace std {
using namespace ::arx::stdx;
}
#include "ArxTypeTraits/replace_minmax_macros.h"
#include "ArxTypeTraits/type_traits.h"
#endif // ARX_TYPE_TRAITS_H

@ -1,165 +0,0 @@
#pragma once
#ifndef ARX_TYPE_TRAITS_FUNCTIONAL_H
#define ARX_TYPE_TRAITS_FUNCTIONAL_H
#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11
#include <functional>
#else // Do not have libstdc++11
// If we have a <new> header, include it and assume it has placement new
// (for AVR this has always been true, MEGAAVR does not have placement
// new now, but will probably get it before <new> is added).
// This also handles the case where ArduinoSTL is used, which defines an
// inline placement new which would conflict with the below definition.
#if ARX_SYSTEM_HAS_INCLUDE(<new>)
#include <new>
#else
// When there is no <new> header, there might be a <new.h> header, but
// not all Arduino platform (versions) define a placement new operator
// in there.
// However, it is hard to detect whether it is or is not defined, but
// the versions that do define it, do not define it inline in the
// header, so we can just define it inline here without conflicts.
// Note that there is no need to include anything to declare the
// non-placement new operators, since those are implicit.
inline void* operator new (const size_t size, void* ptr) noexcept { (void)size; return ptr; }
#endif
namespace arx { namespace stdx {
// reference:
// stack overflow https://stackoverflow.com/questions/32074410/stdfunction-bind-like-type-erasure-without-standard-c-library
template<class Signature>
class function;
template<class R, class... Args>
class function<R(Args...)>
{
struct vtable_t
{
void (*mover)(void* src, void* dest);
void (*destroyer)(void*);
R (*invoke)(void const* t, Args&&... args);
template <class T>
static vtable_t const* get()
{
static const vtable_t table =
{
// mover
[] (void* src, void* dest)
{
new(dest) T(move(*static_cast<T*>(src)));
},
// destroyer
[] (void* t)
{
static_cast<T*>(t)->~T();
},
// invoke
[] (void const* t, Args&&... args) -> R
{
return (*static_cast<T const*>(t))(std::forward<Args>(args)...);
}
};
return &table;
}
};
vtable_t const* table {nullptr};
void* data {nullptr};
public:
template <
class Func,
class dF = typename std::decay<Func>::type,
typename enable_if <!std::is_same<dF, function>{}>::type* = nullptr,
typename enable_if <std::is_convertible<typename result_of<dF&(Args...)>::type, R>{}>::type* = nullptr
>
function(const Func& f)
: table(vtable_t::template get<dF>())
{
data = reinterpret_cast<void*>(new Func(f));
}
function(const function& o)
: table(o.table)
{
data = o.data;
}
function(function&& o)
: table(o.table)
{
if (table) table->mover(o.data, data);
}
function()
{
}
~function()
{
if (table) table->destroyer(data);
}
function& operator= (const function& o)
{
this->~function();
new(this) function(move(o));
return *this;
}
function& operator= (function&& o)
{
this->~function();
new(this) function(move(o));
return *this;
}
function& operator= (std::nullptr_t p)
{
(void)p;
this->~function();
return *this;
}
explicit operator bool() const
{
return table;
}
R operator()(Args...args) const
{
return table->invoke(data, forward<Args>(args)...);
}
};
template<class R, class... Args>
inline bool operator== (const function<R(Args...)>& f, std::nullptr_t)
{
return !static_cast<bool>(f);
}
template<class R, class... Args>
inline bool operator== (std::nullptr_t, const function<R(Args...)>& f)
{
return !static_cast<bool>(f);
}
template<class R, class... Args>
inline bool operator!= (const function<R(Args...)>& f, std::nullptr_t)
{
return static_cast<bool>(f);
}
template<class R, class... Args>
inline bool operator!= (std::nullptr_t, const function<R(Args...)>& f)
{
return static_cast<bool>(f);
}
} } // namespace arx::std
#endif // Do not have libstdc++11
#endif // ARX_TYPE_TRAITS_FUNCTIONAL_H

@ -1,30 +0,0 @@
#pragma once
#ifndef ARX_TYPE_TRAITS_HAS_INCLUDE_H
#define ARX_TYPE_TRAITS_HAS_INCLUDE_H
// Check whether __has_include is available, but also check the GCC
// version (__has_include was introduced in gcc 5) to catch
// environments (such as ESP8266) where gcc is old, but some system
// header provides a fake __has_include. We also need to check
// against __clang__ here, since clang pretends to be GCC
// 4.something and would otherwise be detected incorrectly here...
#if !defined(__has_include) || defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__)
#if defined(ARDUINO_ARCH_ESP8266)
// ESP8266 does not have a working __has_include, but we
// know it does have a working libstdc++ with all the
// headers we care about, so provide a fake has_include
#define ARX_SYSTEM_HAS_INCLUDE(x) 1
#elif defined(ARDUINO_SAM_DUE)
// Arduino DUE's GCC version is 4.8.3 (GCC < 5.0).
// If libstdc++ is used, std::function causes error
// so currently we disable libstdc++ and use ArxTypeTraits
#define ARX_SYSTEM_HAS_INCLUDE(x) 0
#else
#error "Compiler does not support __has_include, please report a bug against the ArxTypeTraits library about this."
#endif
#else
#define ARX_SYSTEM_HAS_INCLUDE(x) __has_include(x)
#endif
#endif // ARX_TYPE_TRAITS_HAS_INCLUDE_H

@ -1,25 +0,0 @@
#pragma once
#ifndef ARX_TYPE_TRAITS_HAS_LIBSTDCPLUSPLUS_H
#define ARX_TYPE_TRAITS_HAS_LIBSTDCPLUSPLUS_H
#if !defined(ARX_HAVE_LIBSTDCPLUSPLUS)
#if ARX_SYSTEM_HAS_INCLUDE(<cstdlib>)
#include <cstdlib>
#if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION)
// For gcc's libstdc++ and clang's libc++, assume that
// __cplusplus tells us what the standard includes support
#define ARX_HAVE_LIBSTDCPLUSPLUS __cplusplus
#elif defined(__UCLIBCXX_MAJOR__)
// For uclibc++, assume C++98 support only.
#define ARX_HAVE_LIBSTDCPLUSPLUS 199711L
#else
#error "Unknown C++ library found, please report a bug against the ArxTypeTraits library about this."
#endif
#else
// Assume no standard library is available at all (e.g. on AVR)
#define ARX_HAVE_LIBSTDCPLUSPLUS 0
#endif
#endif
#endif // ARX_TYPE_TRAITS_HAS_LIBSTDCPLUSPLUS_H

@ -1,30 +0,0 @@
#pragma once
#ifndef ARX_TYPE_TRAITS_INITIALIZER_H
#define ARX_TYPE_TRAITS_INITIALIZER_H
// Initializer_list *must* be defined in std, so take extra care to only
// define it when <initializer_list> is really not available (e.g.
// ArduinoSTL is C++98 but *does* define <initializer_list>) and not
// already defined (e.g. by ArxContainer).
#if ARX_SYSTEM_HAS_INCLUDE(<initializer_list>)
#include <initializer_list>
#else
namespace std {
template<class T>
class initializer_list
{
private:
const T* array;
size_t len;
initializer_list(const T* a, size_t l) : array(a), len(l) {}
public:
initializer_list() : array(nullptr), len(0) {}
size_t size() const { return len; }
const T *begin() const { return array; }
const T *end() const { return array + len; }
};
} // namespace std
#endif
#endif // ARX_TYPE_TRAITS_INITIALIZER_LIST_H

@ -1,35 +0,0 @@
#pragma once
#ifndef ARX_TYPE_TRAITS_REPLACE_MINMAX_MACROS_H
#define ARX_TYPE_TRAITS_REPLACE_MINMAX_MACROS_H
// Make sure Arduino.h is actually included, since otherwise it might be
// included later and break *uses* of the min/max methods, rather than
// the declarations of it.
#ifdef ARDUINO
#include <Arduino.h>
#endif
// These macros are defined by Arduino.h on some platforms, and conflict
// with min/max methods defined or included by ArxTypeTraits, so replace
// them with macros here.
#ifdef max
#undef max
template <typename T1, typename T2>
constexpr auto max(T1 x, T2 y)
-> decltype(x + y)
{
return (x > y) ? x : y;
}
#endif
#ifdef min
#undef min
template <typename T1, typename T2>
constexpr auto min(T1 x, T2 y)
-> decltype(x + y)
{
return (x < y) ? x : y;
}
#endif
#endif // ARX_TYPE_TRAITS_REPLACE_MINMAX_MACROS_H

@ -1,82 +0,0 @@
#pragma once
#ifndef ARX_TYPE_TRAITS_TUPLE_H
#define ARX_TYPE_TRAITS_TUPLE_H
#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11
#include <tuple>
#else // Do not have libstdc++11
namespace arx { namespace stdx {
// https://theolizer.com/cpp-school2/cpp-school2-15/
// https://wandbox.org/permlink/C0BWIzjqg4iO3kKZ
template<typename... Ts>
struct tuple
{
tuple() {}
};
template<typename tFirst, typename... tRest>
class tuple<tFirst, tRest...> : public tuple<tRest...>
{
template<size_t N, typename... tTypes> friend struct get_helper;
tFirst mMember;
public:
tuple(tFirst const& iFirst, tRest const&... iRest)
: tuple<tRest...>(iRest...)
, mMember(iFirst)
{ }
constexpr tuple() {}
};
template<size_t N, typename... tTypes>
struct get_helper { };
template<typename tFirst, typename... tRest>
struct get_helper<0, tFirst, tRest...>
{
typedef tFirst type;
static type& get(tuple<tFirst, tRest...>& iTuple)
{
return iTuple.mMember;
}
};
template<size_t N, typename tFirst, typename... tRest>
struct get_helper<N, tFirst, tRest...>
{
typedef typename get_helper<N - 1, tRest...>::type type;
static type& get(tuple<tFirst, tRest...>& iTuple)
{
return get_helper<N - 1, tRest...>::get(iTuple);
}
};
template<size_t N, typename... tTypes>
typename get_helper<N, tTypes...>::type& get(tuple<tTypes...>& iTuple)
{
return get_helper<N, tTypes...>::get(iTuple);
}
template <class T> class tuple_size;
template <class T> class tuple_size<const T>;
template <class T> class tuple_size<volatile T>;
template <class T> class tuple_size<const volatile T>;
template <class... Types>
class tuple_size <tuple<Types...>>
: public integral_constant <size_t, sizeof...(Types)> {};
template <class... Types>
auto make_tuple(Types&&... args)
-> std::tuple<typename std::remove_reference<Types>::type...>
{
return std::tuple<typename std::remove_reference<Types>::type...>(std::forward<typename std::remove_reference<Types>::type>(args)...);
}
} } // namespace arx::std
#endif // Do not have libstdc++11
#endif // ARX_TYPE_TRAITS_TUPLE_H

@ -1,634 +0,0 @@
#pragma once
#ifndef ARX_TYPE_TRAITS_TYPE_TRAITS_H
#define ARX_TYPE_TRAITS_TYPE_TRAITS_H
#if ARX_HAVE_LIBSTDCPLUSPLUS >= 199711L // Have libstdc++98
#include <utility>
#else // Do not have libstdc++98
namespace arx { namespace stdx {
template <class T>
void swap(T& a, T& b)
{
T t = move(a);
a = move(b);
b = move(t);
}
} } // namespace arx::stdx
#endif // Do not have libstdc++98
#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11
#include <limits>
#include <type_traits>
#else // Do not have libstdc++11
#include <float.h>
#include <limits.h>
#include <stdint.h>
namespace arx { namespace stdx {
using nullptr_t = decltype(nullptr);
// numeric_limits
template <typename T>
struct numeric_limits
{
static constexpr T max() { return T(); }
static constexpr T min() { return T(); }
};
template <> constexpr bool numeric_limits<bool>::max() { return true; }
template <> constexpr char numeric_limits<char>::max() { return CHAR_MAX; }
template <> constexpr signed char numeric_limits<signed char>::max() { return SCHAR_MAX; }
template <> constexpr unsigned char numeric_limits<unsigned char>::max() { return UCHAR_MAX; }
template <> constexpr wchar_t numeric_limits<wchar_t>::max() { return WCHAR_MAX; }
// template <> constexpr char8_t numeric_limits<char8_t>::max() { return UCHAR_MAX; }
template <> constexpr char16_t numeric_limits<char16_t>::max() { return UINT_LEAST16_MAX; }
template <> constexpr char32_t numeric_limits<char32_t>::max() { return UINT_LEAST32_MAX; }
template <> constexpr short numeric_limits<short>::max() { return SHRT_MAX; }
template <> constexpr unsigned short numeric_limits<unsigned short>::max() { return USHRT_MAX; }
template <> constexpr int numeric_limits<int>::max() { return INT_MAX; }
template <> constexpr unsigned int numeric_limits<unsigned int>::max() { return UINT_MAX; }
template <> constexpr long numeric_limits<long>::max() { return LONG_MAX; }
template <> constexpr unsigned long numeric_limits<unsigned long>::max() { return ULONG_MAX; }
// template <> constexpr long long numeric_limits<long long>::max() { return LLONG_MAX; }
// template <> constexpr unsigned long long numeric_limits<unsigned long long>::max() { return ULLONG_MAX; }
template <> constexpr float numeric_limits<float>::max() { return FLT_MAX; }
template <> constexpr double numeric_limits<double>::max() { return DBL_MAX; }
template <> constexpr long double numeric_limits<long double>::max() { return LDBL_MAX; }
template <> constexpr bool numeric_limits<bool>::min() { return false; }
template <> constexpr char numeric_limits<char>::min() { return CHAR_MIN; }
template <> constexpr signed char numeric_limits<signed char>::min() { return SCHAR_MIN; }
template <> constexpr unsigned char numeric_limits<unsigned char>::min() { return 0; }
template <> constexpr wchar_t numeric_limits<wchar_t>::min() { return WCHAR_MIN; }
// template <> constexpr char8_t numeric_limits<char8_t>::min() { return 0; }
template <> constexpr char16_t numeric_limits<char16_t>::min() { return 0; }
template <> constexpr char32_t numeric_limits<char32_t>::min() { return 0; }
template <> constexpr short numeric_limits<short>::min() { return SHRT_MIN; }
template <> constexpr unsigned short numeric_limits<unsigned short>::min() { return 0; }
template <> constexpr int numeric_limits<int>::min() { return INT_MIN; }
template <> constexpr unsigned int numeric_limits<unsigned int>::min() { return 0; }
template <> constexpr long numeric_limits<long>::min() { return LONG_MIN; }
template <> constexpr unsigned long numeric_limits<unsigned long>::min() { return 0; }
// template <> constexpr long long numeric_limits<long long>::min() { return LLONG_MIN; }
// template <> constexpr unsigned long long numeric_limits<unsigned long long>::min() { return 0; }
template <> constexpr float numeric_limits<float>::min() { return FLT_MIN; }
template <> constexpr double numeric_limits<double>::min() { return DBL_MIN; }
template <> constexpr long double numeric_limits<long double>::min() { return LDBL_MIN; }
// integral_constant
template<class T, T v>
struct integral_constant
{
static constexpr T value = v;
using value_type = T;
using type = integral_constant;
constexpr operator value_type() const noexcept { return value; }
constexpr value_type operator()() const noexcept { return value; }
};
using true_type = integral_constant<bool, true>;
using false_type = integral_constant<bool, false>;
template <class T>
T declval(); // no implementation
template <bool, typename T = void>
struct enable_if;
template <typename T>
struct enable_if <true, T> { using type = T; };
template<bool, class T, class F>
struct conditional { using type = T; };
template<class T, class F>
struct conditional<false, T, F> { using type = F; };
template <class T> struct remove_cv { using type = T; };
template <class T> struct remove_cv<const T> { using type = T; };
template <class T> struct remove_cv<volatile T> { using type = T; };
template <class T> struct remove_cv<const volatile T> { using type = T; };
template <class T> struct remove_const { using type = T; };
template <class T> struct remove_const<const T> { using type = T; };
template <class T> struct remove_volatile { using type = T; };
template <class T> struct remove_volatile<volatile T> { using type = T; };
template <class T> struct remove_pointer { using type = T; };
template <class T> struct remove_pointer<T*> { using type = T; };
template <class T> struct remove_pointer<T* const> { using type = T; };
template <class T> struct remove_pointer<T* volatile> { using type = T; };
template <class T> struct remove_pointer<T* const volatile> { using type = T; };
template <class T> struct remove_reference { using type = T; };
template <class T> struct remove_reference<T&> { using type = T; };
template <class T> struct remove_reference<T&&> { using type = T; };
template<class T> struct remove_extent { typedef T type; };
template<class T> struct remove_extent<T[]> { typedef T type; };
template<class T, size_t N> struct remove_extent<T[N]> { typedef T type; };
template <class T>
constexpr T&& forward(typename remove_reference<T>::type& t) noexcept
{
return static_cast<T&&>(t);
}
template <class T>
constexpr T&& forward(typename remove_reference<T>::type&& t) noexcept
{
return static_cast<T&&>(t);
}
namespace detail
{
template <class T>
struct type_identity { using type = T; };
template <class T>
auto try_add_pointer(int) -> type_identity<typename remove_reference<T>::type*>;
template <class T>
auto try_add_pointer(...) -> type_identity<T>;
}
template <class T>
struct add_pointer : decltype(detail::try_add_pointer<T>(0)) {};
template <typename T, typename U>
struct is_same : false_type {};
template <typename T>
struct is_same <T, T> : true_type {};
template <typename T>
struct is_integral : false_type {};
template <> struct is_integral <bool> : true_type {};
template <> struct is_integral <char> : true_type {};
template <> struct is_integral <signed char> : true_type {};
template <> struct is_integral <unsigned char> : true_type {};
template <> struct is_integral <char16_t> : true_type {};
template <> struct is_integral <char32_t> : true_type {};
template <> struct is_integral <wchar_t> : true_type {};
template <> struct is_integral <short> : true_type {};
template <> struct is_integral <unsigned short> : true_type {};
template <> struct is_integral <int> : true_type {};
template <> struct is_integral <unsigned> : true_type {};
template <> struct is_integral <long> : true_type {};
template <> struct is_integral <unsigned long> : true_type {};
template <> struct is_integral <long long> : true_type {};
template <> struct is_integral <unsigned long long> : true_type {};
template <typename T>
struct is_floating_point : false_type {};
template <> struct is_floating_point<float> : true_type {};
template <> struct is_floating_point<double> : true_type {};
template <> struct is_floating_point<long double> : true_type {};
template <typename T>
struct is_arithmetic
: conditional<
is_integral<T>::value || is_floating_point<T>::value,
true_type,
false_type
>::type
{};
namespace detail
{
template <typename T, bool = is_arithmetic<T>::value>
struct is_signed : integral_constant<bool, T(-1) < T(0)> {};
template <typename T>
struct is_signed<T, false> : false_type {};
}
template <typename T>
struct is_signed : detail::is_signed<T>::type {};
namespace detail
{
template<typename T, bool = is_arithmetic<T>::value>
struct is_unsigned : integral_constant<bool, T(0) < T(-1)> {};
template<typename T>
struct is_unsigned<T, false> : false_type {};
}
template<typename T>
struct is_unsigned : detail::is_unsigned<T>::type {};
template <class T> struct is_pointer_helper : false_type {};
template <class T> struct is_pointer_helper<T*> : true_type {};
template <class T> struct is_pointer : is_pointer_helper<typename remove_cv<T>::type> {};
template<class T>
struct is_array : false_type {};
template<class T>
struct is_array<T[]> : true_type {};
template<class T, size_t N>
struct is_array<T[N]> : true_type {};
namespace details
{
template <class... Ts>
struct Tester { using type = void; };
template <class... Ts>
using void_t = typename Tester<Ts...>::type;
template<template<class...>class Z, class, class...Ts>
struct can_apply : false_type{};
template<template<class...>class Z, class...Ts>
struct can_apply<Z, void_t<Z<Ts...>>, Ts...> : true_type{};
template<class From, class To>
using try_convert = decltype(To{declval<From>()});
}
template<template<class...>class Z, class...Ts>
using can_apply = details::can_apply<Z, void, Ts...>;
template<class From, class To>
struct is_convertible
: conditional <
can_apply <details::try_convert, From, To>::value
, true_type
, typename conditional <
is_arithmetic<From>::value && is_arithmetic<To>::value,
true_type,
false_type
>::type
>::type
{};
template<>
struct is_convertible<void, void> : true_type{};
// primary template
template<class>
struct is_function : false_type { };
// specialization for regular functions
template<class Ret, class... Args>
struct is_function<Ret(Args...)> : true_type {};
// specialization for variadic functions such as printf
template<class Ret, class... Args>
struct is_function<Ret(Args......)> : true_type {};
// specialization for function types that have cv-qualifiers
template<class Ret, class... Args>
struct is_function<Ret(Args...) const> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) volatile> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const volatile> : true_type {};
// specialization for function types that have ref-qualifiers
template<class Ret, class... Args>
struct is_function<Ret(Args...) &> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const &> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile &> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile &> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) &> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const &> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) volatile &> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const volatile &> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) &&> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const &&> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile &&> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile &&> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) &&> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const &&> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) volatile &&> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const volatile &&> : true_type {};
template<typename T>
struct is_empty : public integral_constant<bool, __is_empty(T)> { };
template <class T>
class decay
{
typedef typename remove_reference<T>::type U;
public:
typedef typename conditional<
is_array<U>::value,
typename remove_extent<U>::type*,
typename conditional<
is_function<U>::value,
typename add_pointer<U>::type,
typename remove_cv<U>::type
>::type
>::type type;
};
namespace details
{
template<class T> struct tag { using type=T; };
template<class Tag> using type_t = typename Tag::type;
template<class G, class...Args>
using invoke_t = decltype( declval<G>()(declval<Args>()...) );
template<class Sig, class = void>
struct result_of {};
template<class G, class...Args>
struct result_of<G(Args...), void_t<invoke_t<G, Args...>>>
: tag <invoke_t<G, Args...>>
{};
}
template<class Sig>
using result_of = details::result_of<Sig>;
} } // namespace arx::stdx
#endif // Do not have libstdc++11
#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201402L // Have libstdc++14
#else // Do not have libstdc++14
namespace arx { namespace stdx {
// `move` must be declared before including `functional.h`
// C++14 constexpr version should be inside of C++14,
// but moved before `functional.h`
template <class T>
constexpr typename remove_reference<T>::type&& move(T&& t) noexcept
{
return static_cast<typename remove_reference<T>::type&&>(t);
}
} } // namespace arx::stdx
#endif // Do not have libstdc++14
#include "initializer_list.h"
#include "tuple.h"
#include "functional.h"
#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201402L // Have libstdc++14
// Nothing to include here, relevant header files were already included
// for C++11 above.
#else // Do not have libstdc++14
namespace arx { namespace stdx {
template <bool B, typename T = void>
using enable_if_t = typename enable_if<B, T>::type;
template <typename T>
using decay_t = typename decay<T>::type;
template<class T>
using remove_cv_t = typename remove_cv<T>::type;
template<class T>
using remove_const_t = typename remove_const<T>::type;
template<class T>
using remove_volatile_t = typename remove_volatile<T>::type;
template<class T>
using remove_reference_t = typename remove_reference<T>::type;
template<class T>
using remove_pointer_t = typename remove_pointer<T>::type;
template<typename T, T ...Ts>
struct integer_sequence
{
using type = integer_sequence;
using value_type = T;
static constexpr size_t size() noexcept { return sizeof...(Ts); }
};
template <size_t ...Is>
using index_sequence = integer_sequence<size_t, Is...>;
// https://stackoverflow.com/questions/17424477/implementation-c14-make-integer-sequence
template<typename S1, typename S2>
struct concat_impl;
template<typename S1, typename S2>
using concat = typename concat_impl<S1, S2>::type;
template<size_t... I1, size_t... I2>
struct concat_impl <index_sequence<I1...>, index_sequence<I2...>>
: index_sequence<I1..., (sizeof...(I1) + I2)...> {};
template<size_t N>
struct make_index_sequence_impl;
template<size_t N>
using make_index_sequence = typename make_index_sequence_impl<N>::type;
template<size_t N>
struct make_index_sequence_impl
: concat<make_index_sequence <N/2>, make_index_sequence <N - N/2>> {};
template<>
struct make_index_sequence_impl <0> : index_sequence<>{};
template<>
struct make_index_sequence_impl <1> : index_sequence<0>{};
template<typename... Ts>
using index_sequence_for = make_index_sequence<sizeof...(Ts)>;
} } // namespace arx::stdx
#endif // Do not have libstdc++14
#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201703L // Have libstdc++17
// Nothing to include here, relevant header files were already included
// for C++11 above.
#else // Do not have libstdc++17
namespace arx { namespace stdx {
template <class... Ts>
struct Tester { using type = void; };
template <class... Ts>
using void_t = typename Tester<Ts...>::type;
template <typename ...Args>
struct disjunction : false_type {};
template <typename Arg>
struct disjunction <Arg> : Arg::type {};
template <typename Arg, typename ...Args>
struct disjunction <Arg, Args...> : conditional<Arg::value, Arg, disjunction<Args...>>::type {};
template <typename ...Args>
struct conjunction : true_type {};
template <typename Arg>
struct conjunction <Arg> : Arg::type {};
template <typename Arg, typename ...Args>
struct conjunction <Arg, Args...> : conditional<Arg::value, conjunction<Args...>, Arg>::type {};
template <typename T>
struct negation : integral_constant<bool, !T::value> {};
// https://qiita.com/_EnumHack/items/92e6e135174f1f781dbb
// without decltype(auto)
template <class F, class Tuple, size_t... I>
constexpr auto apply_impl(F&& f, Tuple&& t, index_sequence<I...>)
-> decltype(f(get<I>(forward<Tuple>(t))...))
{
return f(get<I>(forward<Tuple>(t))...);
}
template <class F, class Tuple>
constexpr auto apply(F&& f, Tuple&& t)
-> decltype(apply_impl(
forward<F>(f),
forward<Tuple>(t),
make_index_sequence<tuple_size<decay_t<Tuple>>::value>{}
))
{
return apply_impl(
forward<F>(f),
forward<Tuple>(t),
make_index_sequence<tuple_size<decay_t<Tuple>>::value>()
);
}
} } // namespace arx::stdx
#endif // Do not have libstdc++17
#if ARX_HAVE_LIBSTDCPLUSPLUS > 201703L // Have libstdc++2a
// Nothing to include here, relevant header files were already included
// for C++11 above.
#else // Do not have libstdc++2a
namespace arx { namespace stdx {
template<class T>
struct remove_cvref
{
typedef remove_cv_t<remove_reference_t<T>> type;
};
template< class T >
using remove_cvref_t = typename remove_cvref<T>::type;
} } // namespace arx::stdx
#endif // Do not have libstdc++2a
namespace arx { // others
template <class AlwaysVoid, template<class...> class Check, class... T>
struct is_detected_impl : std::false_type {};
template <template <class...> class Check, class... T>
struct is_detected_impl <std::void_t<Check<T...>>, Check, T...> : std::true_type {};
template <template <class...> class Check, class... T>
using is_detected = is_detected_impl<void, Check, T...>;
template <typename T>
struct is_callable {
template <typename U, decltype(&U::operator()) = &U::operator()>
struct checker {};
template <typename U> static std::true_type test(checker<U> *);
template <typename> static std::false_type test(...);
static constexpr bool value = decltype(test<T>(nullptr))::value;
};
template <typename R, typename ... Arguments>
struct is_callable<R(*)(Arguments ...)> {
static constexpr bool value = true;
};
template <typename R, typename ... Arguments>
struct is_callable<R(*&)(Arguments ...)> {
static constexpr bool value = true;
};
template <typename R, typename ... Arguments>
struct is_callable<R(&)(Arguments ...)> {
static constexpr bool value = true;
};
template <typename R, typename ... Arguments>
struct is_callable<R(Arguments ...)> {
static constexpr bool value = true;
};
template <typename R, typename ... Arguments>
struct is_callable<std::function<R(Arguments ...)>> {
static constexpr bool value = true;
};
namespace detail {
template <typename ret, typename ... arguments>
struct function_traits {
static constexpr size_t arity = sizeof...(arguments);
using result_type = ret;
using arguments_types_tuple = std::tuple<arguments ...>;
// template <size_t index>
// using argument_type = type_at<index, arguments ...>;
using function_type = std::function<ret(arguments ...)>;
template <typename function_t>
static constexpr function_type cast(function_t f) {
return static_cast<function_type>(f);
}
};
};
template <typename T>
struct function_traits : public function_traits<decltype(&T::operator())> {};
template <typename class_type, typename ret, typename ... arguments>
struct function_traits<ret(class_type::*)(arguments ...) const>
: detail::function_traits<ret, arguments ...> {};
template <typename class_type, typename ret, typename ... arguments>
struct function_traits<ret(class_type::*)(arguments ...)>
: detail::function_traits<ret, arguments ...> {};
template <typename ret, typename ... arguments>
struct function_traits<ret(*)(arguments ...)>
: detail::function_traits<ret, arguments ...> {};
template <typename ret, typename ... arguments>
struct function_traits<ret(*&)(arguments ...)>
: detail::function_traits<ret, arguments ...> {};
template <typename ret, typename ... arguments>
struct function_traits<ret(arguments ...)>
: detail::function_traits<ret, arguments ...> {};
template <typename ret, typename ... arguments>
struct function_traits<std::function<ret(arguments ...)>>
: detail::function_traits<ret, arguments ...> {};
} // namespace arx
#endif // ARX_TYPE_TRAITS_TYPE_TRAITS_H

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2020 Hideaki Tai
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.

@ -1,116 +0,0 @@
# ArxTypeTraits
C++ type_traits for Arduino which cannot use it as default
## Features
- automatically use standard library first if the boards can
- if standard library is not enough (e.g. only C++11 is available), add missing parts listed below
- works almost all Arduino platforms (Let me know if you have errors)
- compatible with [ArduinoSTL](https://github.com/mike-matera/ArduinoSTL) or other [uClibc++](https://www.uclibc.org/) libraries
- thx @matthijskooijman
## Supported Class Templates
### C++11 (defined only for boards before C++11)
- `std::integral_constant`
- `std::true_type`
- `std::false_type`
- `std::declval`
- `std::enable_if`
- `std::conditional`
- `std::remove_cv`
- `std::remove_const`
- `std::remove_volatile`
- `std::remove_pointer`
- `std::remove_reference`
- `std::remove_extent`
- `std::add_pointer`
- `std::forward`
- `std::is_same`
- `std::is_integral`
- `std::is_floating_point`
- `std::is_arithmetic`
- `std::is_signed`
- `std::is_unsigned`
- `std::is_pointer`
- `std::is_array`
- `std::is_convertible`
- `std::is_function`
- `std::is_empty`
- `std::decay`
- `std::result_of`
#### for utility
- `std::numeric_limits` (only `max()` and `min()` now)
- `std::swap`
- `std::initializer_list`
- `std::tuple`
- `std::get`
- `std::tuple_size`
- `std::function`
### C++14 (defined only for boards before C++14)
- `std::enable_if_t`
- `std::decay_t`
- `std::remove_cv_t`
- `std::remove_const_t`
- `std::remove_volatile_t`
- `std::remove_reference_t`
- `std::remove_pointer_t`
- `std::integer_sequence`
- `std::index_sequence`
- `std::make_index_sequence`
- `std::index_sequence_for`
### C++17 (defined only for boards before C++17)
- `std::void_t`
- `std::disjunction`
- `std::conjunction`
- `std::negation`
- `std::apply`
### C++2a
- `std::remove_cvref`
- `std::remove_cvref_t`
### Others (defined for all boards)
- `arx::is_detected`
- `arx::is_callable`
- `arx::function_traits`
## Used Inside of
- [Packetizer](https://github.com/hideakitai/Packetizer)
- [MsgPack](https://github.com/hideakitai/MsgPack)
- [MsgPacketizer](https://github.com/hideakitai/MsgPacketizer)
- [ArduinoOSC](https://github.com/hideakitai/ArduinoOSC)
- [PollingTimer](https://github.com/hideakitai/PollingTimer)
- [Tween](https://github.com/hideakitai/Tween)
- [ArxStringUtils](https://github.com/hideakitai/ArxStringUtils)
- [Filters](https://github.com/hideakitai/Filters)
- [Debouncer](https://github.com/hideakitai/Debouncer)
## Contributors
- [Matthijs Kooijman](https://github.com/matthijskooijman)
## License
MIT

@ -1,18 +0,0 @@
{
"name": "ArxTypeTraits",
"keywords": "type traits, functional, tuple, stl",
"description": "C++ type_traits for Arduino which cannot use it as default",
"repository": {
"type": "git",
"url": "https://github.com/hideakitai/ArxTypeTraits.git"
},
"authors": {
"name": "Hideaki Tai",
"url": "https://github.com/hideakitai",
"maintainer": true
},
"version": "0.2.1",
"license": "MIT",
"frameworks": "arduino",
"platforms": "*"
}

@ -1,9 +0,0 @@
name=ArxTypeTraits
version=0.2.1
author=hideakitai
maintainer=hideakitai
sentence=C++ type_traits for Arduino which cannot use it as default
paragraph=C++ type_traits for Arduino which cannot use it as default
category=Data Storage
url=https://github.com/hideakitai/ArxTypeTraits
architectures=*

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2020 Hideaki Tai
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.

@ -1,57 +0,0 @@
# TeensyDirtySTLErrorSolution
dirty solution to use STL in teensy
## Introduction
Sometimes we want to use STL on Teensy, but Teensy 3.x in Arduino IDE does not support STL by default. Though STL is enabled on Teensy 4.x, but you have to enable it manually on Teensy 3.x. If you use PlatformIO, you can also use STL on Teensy 3.x.
| | Teensy 4.x | Teensy 3.x |
| ----------- | ----------------- | ----------------- |
| PlatformIO | Almost Compilable | Almost Compilable |
| Arduino IDE | Almost Compilable | NOT Compilable |
## Enable STL in Arduino IDE
To enable STL on Teensy 3.x using Arduino IDE, add `-lstdc++` to `build flags`, which is defined in `boards.txt`. Many STL can be used by adding this flag. You have to do this procedure every time you upgrade the version of Teensyduino.
| OS | default location |
| ------- | --------------------------------------------------------------- |
| macOS | `Arduino.app/Contents/Java/hardware/teensy/avr/boards.txt` |
| Windows | `C:\Program Files (x86)\Arduino\hardware\teensy\avr\boards.txt` |
#### Before
``` boards.txt
teensy36.build.flags.libs=-larm_cortexM4lf_math -lm
teensy35.build.flags.libs=-larm_cortexM4lf_math -lm
teensy31.build.flags.libs=-larm_cortexM4l_math -lm
```
#### After
``` boards.txt
teensy36.build.flags.libs=-larm_cortexM4lf_math -lm -lstdc++
teensy35.build.flags.libs=-larm_cortexM4lf_math -lm -lstdc++
teensy31.build.flags.libs=-larm_cortexM4l_math -lm -lstdc++
```
## Do you still have compile error?
Yes, maybe you still have compilation error in both 4.x and 3.x for some STLs... Then you should add this library (header file) to your project. Some dirty solution I found is included in this header file.
``` C++
#include <TeensyDirtySTLErrorSolution.h>
```
## Warning
This method is not recommended because STL is not enabled by default... (if you know the reason, please let me know). I am not responsible for any trouble that may occur as a result of the use of this library. Please use at your own risk.
## License
MIT

@ -1,65 +0,0 @@
#pragma once
#include <Arduino.h>
#ifdef TEENSYDUINO
#ifndef TEENSYDUINO_DIRTY_STL_ERROR_SOLUTION
#define TEENSYDUINO_DIRTY_STL_ERROR_SOLUTION
#if defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) // TEENSY 3.1/3.2, 3.5, 3.6
extern "C"
{
int _write() { return -1; }
}
#elif defined(__IMXRT1062__) // TEENSY4.0
extern "C"
{
void *__exidx_start __attribute__((__visibility__ ("hidden")));
void *__exidx_end __attribute__((__visibility__ ("hidden")));
}
#else
#error NOT SUPPORTED TEENSY VERSION
#endif
// ----- template -----
//
// #if defined(__MK20DX256__) // TEENSY3.1/3.2
// #elif defined(__MK64FX512__) // TEENSY3.5
// #elif defined(__MK66FX1M0__) // TEENSY3.6
// #elif defined(__IMXRT1062__) // TEENSY4.0
//
// extern "C"
// {
// int _getpid() { return -1; }
// int _kill(int pid, int sig) { return -1; }
// int _write() { return -1; }
// void *__exidx_start __attribute__((__visibility__ ("hidden")));
// void *__exidx_end __attribute__((__visibility__ ("hidden")));
// int _getpid();// { return -1; }
// int _kill(int pid, int sig);// { return -1; }
// int _write() { return -1; }
// void *__exidx_start __attribute__((__visibility__ ("hidden")));
// void *__exidx_end __attribute__((__visibility__ ("hidden")));
// }
//
// // copied from https://github.com/gcc-mirror/
// namespace std
// {
// void __throw_bad_alloc() { _GLIBCXX_THROW_OR_ABORT(bad_alloc()); }
// void __throw_length_error(const char* __s __attribute__((unused))) { _GLIBCXX_THROW_OR_ABORT(length_error(_(__s))); }
// void __throw_bad_function_call() { _GLIBCXX_THROW_OR_ABORT(bad_function_call()); }
// void _Rb_tree_decrement(std::_Rb_tree_node_base* a) {}
// void _Rb_tree_insert_and_rebalance(bool, std::_Rb_tree_node_base*, std::_Rb_tree_node_base*, std::_Rb_tree_node_base&) {}
// }
#endif // TEENSYDUINO_DIRTY_STL_ERROR_SOLUTION
#endif // TEENSYDUINO
Loading…
Cancel
Save