diff --git a/README.md b/README.md index 7186c09..8c73192 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,15 @@ -# **Arduino OSC library for GrandMA3 consoles v3** +# **Arduino OSC library for GrandMA3 consoles v4** An object orientated library for Arduino to control GrandMA3 consoles with OSC over Ethernet UDP/TCP. The goal of the library is to have a smart toolbox to create your own hardware which covers your needing by endless combinations of hardware elements. +### Changes for v4 +- support for DataPools +- virtual inputs for touch screens and external I/O devices +- Pools and Pages classes instead of button class +- minor improvements for pages and pools functions +- new Parser class which support also TCP receive +- simplified network configuration, you can use TCP or UDP +- no more support for extern OSC buttons, this should done with console macros + ### Changes for v3 - global / local page() numbering - command() function for sending raw commands @@ -15,13 +24,11 @@ An object orientated library for Arduino to control GrandMA3 consoles with OSC o - change license to CC BY-NC-SA 4.0 ## Installation -1. Download from Releases -2. Follow the instruction on the Arduino website https://www.arduino.cc/en/Guide/Libraries -You can import the .zip file from the IDE with *Sketch / Include Library / Add .ZIP Library...* -3. For PlatformIO Unzip and move the folder to the lib folder of your project. +You can install directly with the library manager of the Arduino IDE. +Simply search for "gma3" ## Boards -You can use any Arduino compatible board which gives you the possibility of an ethernet port. Some boards like Teensy or STM32 Nucleo-F767ZI have an Ethernet port build in, others need an external ethernet port based e.g. on WIZnet W5500 boards like USR-ES1 or Arduino EthernetShield 2. +You can use any Arduino compatible board which gives you the possibility of an ethernet connection. Some boards like Teensy or STM32 Nucleo-F767ZI have an Ethernet port build in, others need an external ethernet port based e.g. on WIZnet W5500 boards like USR-ES1 or Arduino EthernetShield 2. WLAN boards like ESP32 should work but are not tested and there is no guarantee for a stable connection. There are also some Arduino based SPS controllers on the market which are ideal for rough environment using 24V. @@ -35,17 +42,27 @@ The in the Arduino board example used Ethernet library only supports the Wiznet **!!! Beware, the Ethernet libraries have different init procedures !!!** **WIZNet w5500 boards like Ethernet Shield 2** -- an Arduino compatible Ethernet library like Ethernet3 https://github.com/sstaub/Ethernet3 -- optional for Teensy MAC address https://github.com/sstaub/TeensyID +- an Arduino compatible Ethernet libraries + - Ethernet3 https://github.com/sstaub/Ethernet3 + - Ethernet https://github.com/arduino-libraries/Ethernet **Teensy 4.1 with build-in Ethernet** + +optional for Teensy MAC address https://github.com/sstaub/TeensyID + +based on FNET - https://github.com/vjmuzik/NativeEthernet - https://github.com/vjmuzik/FNET +or LWIP based +- https://github.com/ssilverman/QNEthernet + **STM32duino (https://github.com/stm32duino)** - https://github.com/stm32duino/STM32Ethernet - https://github.com/stm32duino/LwIP +Following Nucleo boards are supported with Ethernet: F207ZG / F429ZI / F746ZG / F756ZG / F767ZI + ## Hardware The library support hardware elements like encoders, faders, buttons with some helper functions. The library allows you to use hardware elements as an object and with the use of the helper functions, code becomes much easier to write and read and to understand. - **Buttons** @@ -102,6 +119,10 @@ Before using Ethernet there a some things that must be done. It can be different #include "Ethernet3.h" #include "EthernetUdp3.h" ``` +- or for the original Arduino Ethernet library +```cpp +#include "Ethernet.h" +``` - STM32-Nucleo (e.g. Nucleo-F767ZI) ```cpp @@ -117,100 +138,118 @@ Before using Ethernet there a some things that must be done. It can be different #include ``` +- Teensy 4.1 with QNEthernet network stack +```cpp +#include +#include +``` + 2. You need to define IP addresses, ports and sockets - **mac** - You need a unique MAC address, for Teensy 3.x / 4.1 you can use the TeensyID library on this GitHub site, for STM32-Nucleo there is a build in MAC address - **localIP** - You need a static IP address for your Arduino in the subnet range of network system -- **subnet** - A subnet range is necessary +- **dns** - DNS address is optional necessary +- **gateway** - A gateway range is optional necessary +- **subnet** - A subnet range is optional necessary - **localPort** - This is the destination port of your Arduino - **gma3IP** - This is the GrandMA3 console IP address - **gma3Port** - This is the destination port of the GrandMA3 console +**Example** must done before ```setup()``` ```cpp -// configuration example, must done before setup() -uint8_t mac[] = {0x90, 0xA2, 0xDA, 0x10, 0x14, 0x48}; // MAC Address only needed for WIZNet5500 chips -// for Teensy this can empty: uint8_t mac[6]; - +// Network config #define GMA3_UDP_PORT 8000 // UDP Port configured in gma3 -#define GMA3_TCP_PORT 9000 // TCP Port configured in gma3 -IPAddress localIP(10, 101, 1, 201); // IP address of the microcontroller board +#define GMA3_TCP_PORT 9000 // UDP Port configured in gma3 + +uint8_t mac[] = {0x90, 0xA2, 0xDA, 0x10, 0x14, 0x48}; +IPAddress ip(10, 101, 1, 201); // IP address of the microcontroller board IPAddress subnet(255, 255, 0, 0); // subnet range +IPAddress dns(10, 101, 1, 100); // DNS address of your device +IPAddress gateway(10, 101, 1, 100); // Gateway address of your device uint16_t localUdpPort = GMA3_UDP_PORT; IPAddress gma3IP(10, 101, 1, 100); // IP address of the gma3 console uint16_t gma3UdpPort = GMA3_UDP_PORT; uint16_t gma3TcpPort = GMA3_TCP_PORT; ``` -3. You need an UDP/TCP socket, must done before setup(). +3. You need an UDP orTCP socket, must done before ```setup()```. ```cpp -EthernetUDP udp; -EthernetClient tcp; +EthernetUDP udp; // for UDP connection +EthernetClient tcp; // for TCP connection ``` -4. In the beginning of setup() you must start network services. +4. In the beginning of ```setup()``` you must start network services. ```cpp -// for Teensy call: teensyMAC(mac); -Ethernet.begin(mac, localIP, subnet); -// for STM32 use: Ethernet.begin(localIP, subnet); -interfaceGMA3(gma3IP); -interfaceUDP(udp, gma3UdpPort); -interfaceTCP(tcp, gma3TcpPort); +Ethernet.begin(mac, ip, dns, gateway, subnet); // for Arduino ETH library +interface(udp, gma3IP, gma3UdpPort); // for UDP +// interface(tcp, TCP, gma3IP, gma3TcpPort); // for TCP ``` ## Example A simple example for use with an Arduino UNO with EthernetShield 2 ```cpp -#include -#include +#include #include "gma3.h" -#define BTN_KEY 2 -#define ENC_1_A 3 -#define ENC_1_B 4 -#define BTN_CMD 5 -#define FADER A0 +// I/O config +#define BTN_KEY_1 2 +#define BTN_KEY_2 3 +#define BTN_KEY_3 4 +#define BTN_KEY_4 5 +#define ENC_1_A 6 +#define ENC_1_B 7 +#define ENC_2_A 8 +#define ENC_2_B 9 +#define BTN_CMD 10 +#define FADER A0 + +// Network config +#define GMA3_UDP_PORT 8000 // UDP Port configured in gma3 +#define GMA3_TCP_PORT 9000 // UDP Port configured in gma3 -// network data uint8_t mac[] = {0x90, 0xA2, 0xDA, 0x10, 0x14, 0x48}; -#define GMA3_UDP_PORT 8000 // UDP Port configured in gma3 -#define GMA3_TCP_PORT 9000 // UDP Port configured in gma3 - -IPAddress localIP(10, 101, 1, 201); // IP address of the microcontroller board -IPAddress subnet(255, 255, 0, 0); // subnet range +IPAddress localIp(10, 101, 1, 201); // IP address of the microcontroller board +IPAddress subnet(255, 255, 0, 0); // optional subnet range +IPAddress dns(10, 101, 1, 100); // optional DNS address of your device +IPAddress gateway(10, 101, 1, 100); // optional Gateway address of your device +uint16_t localUdpPort = GMA3_UDP_PORT; IPAddress gma3IP(10, 101, 1, 100); // IP address of the gma3 console uint16_t gma3UdpPort = GMA3_UDP_PORT; uint16_t gma3TcpPort = GMA3_TCP_PORT; -EthernetUDP udp; -EthernetClient tcp; +// EthernetUDP udp; // for UDP +EthernetClient tcp; // for TCP // hardware definitions +Key key101(BTN_KEY_1, 101); Fader fader201(FADER, 201); -Key key201(BTN_KEY, 201, TCP); // using TCP +Key key201(BTN_KEY_2, 201); +Key key301(BTN_KEY_3, 301); ExecutorKnob enc301(ENC_1_A, ENC_1_B, 301); +Key key401(BTN_KEY_4, 401); +ExecutorKnob enc401(ENC_2_A, ENC_2_B, 301); CmdButton macro1(BTN_CMD, "GO+ Macro 1"); void setup() { Serial.begin(9600); - Ethernet.begin(mac, localIP, subnet); - interfaceGMA3(gma3IP); - interfaceUDP(udp, gma3UdpPort); - interfaceTCP(tcp, gma3TcpPort); + Ethernet.begin(mac, localIp); + //interface(udp, gma3IP, gma3UdpPort); // for UDP + interface(tcp, TCP, gma3IP, gma3TcpPort); // for TCP } void loop() { + key101.update(); key201.update(); + key301.update(); + key401.update(); fader201.update(); enc301.update(); + enc401.update(); macro1.update(); } ``` ### Examples folders -There are some basic examples for for different board types using the Arduino IDE. -Also a new example for the Selection class with an Up / Down button for page change and fetching. - -### gma3_Arduino_PIO -Is a project folder for use with PlatformIO and includes an example code for an Arduino MEGA as a starting point. It also include an extra button for a GO command to QLab. +There are some basic examples for different board types using the Arduino IDE. ## RAM usage adjustment Because using strictly stack allocation of OSC strings, @@ -218,27 +257,45 @@ you need to adjust the allocation size in the gma3.h file. ```cpp // OSC settings #define OSC_PATTERN_SIZE 64 // length depends on naming conventions -#define OSC_STRING_SIZE 64 // length depends on maximum command length +#define OSC_STRING_SIZE 64 // length depends on maximum command length +#define OSC_STRING_SIZE 64 // max. size of string arguments #define OSC_MESSAGE_SIZE 128 // this should OSC_PATTERN_SIZE + OSC_STRING_SIZE ``` ## Transport modes - **UDPOSC** standard mode using UDP protocol -- **TCP** for OSC 1.0 supported by GrandMA3 using TCP -- **TCPSLIP** for OSC 1.1 e.g. for QLab TCP with SLIP encoding +- **TCP** pure TCP without extra encoding like SLIP or length declaimer ## GrandMA3 naming conventions -This has changed from v1.x to avoid performance problems. -Naming of prefix and others are done in the gma3.h file. -The standard prefix is **gma3** now, when changing the prefix you should also change the PREFIX_PATTERN, this is needed for echo replay. The naming must the same as in the GrandMA3 software ```cpp -// GMA3 naming conventions -#define PREFIX "gma3" -#define PAGE "Page" -#define FADER "Fader" -#define EXECUTOR_KNOB "Encoder" -#define KEY "Key" +// GMA3 default naming conventions +char namePrefix[NAME_LENGTH_MAX] = "gma3"; +char namePool[NAME_LENGTH_MAX] = "DataPool"; // Page name +char namePage[NAME_LENGTH_MAX] = "Page"; // Page name +char nameFader[NAME_LENGTH_MAX] = "Fader"; // Fader name +char nameExecutorKnob[NAME_LENGTH_MAX] = "Encoder"; // ExecutorKnob name +char nameKey[NAME_LENGTH_MAX] = "Key"; // Key name +``` + +The names can changed by following functions, this should done in ```setup()``` +```cpp +void prefixName(const char *prefix); +void dataPoolName(const char *pool); +void pageName(const char *page); +void faderName(const char *fader); +void executorKnobName(const char *executorKnob); +void keyName(const char *key); +``` + +**Examples** +```cpp +prefixName("gma3"); +dataPoolName("DataPool"); +pageName("Page"); +faderName("Fader"); +executorKnobName("Encoder"); +keyName("Key"); ``` # Setup functions @@ -250,162 +307,271 @@ Following settings must done in ```setup()```: - name of the UDP class member - name of the TCP class member - IP Address of the GrandMA3 console -- OSC Port, set in the GrandMA3 console, standard for UDP is port 8000, for TCP 9000 -- IP addresses and ports for external receivers using ```oscButton()``` function +- OSC Port, set in the GrandMA3 console, standard port for + - UDP is 8000 + - TCP is 9000 -### interfaceGMA3() +### interface() ```cpp -void interfaceGMA3(IPAddress gma3IP) +void interface(UDP &udp, IPAddress ip, uint16_t port = 8000); ``` -Set the IP address of the GrandMA3 software +- **UDP &udp** - UDP socket +- **IPAddress ip** - IP address of the console +- **uint16_t port = 8000** - UDP port of the GrandMA3 software, default UDP port is 8000 -### interfaceUDP() ```cpp -void interfaceUDP(UDP &udp, uint16_t port = 8000) +void interface(Client &tcp, protocol_t protocol, IPAddress ip, uint16_t port = 9000); ``` -Set the UDP socket and port of the GrandMA3 software, standard UDP port is 8000 +- **Client &tcp** - TCP socket +- **protocol_t protocol** - Protocol Type, only TCP without special encoding is supported +- **IPAddress ip** - IP address of the console +- **uint16_t port = 9000** - TCP port of the GrandMA3 software, default UDP port is 9000 -### interfaceTCP() +**Examples** ```cpp -void interfaceTCP(UDP &tcp, uint16_t port = 9000) +interface(udp, gma3IP, gma3UdpPort); +interface(tcp, TCP, gma3IP, gma3TcpPort); ``` -Set the TCP socket and port of the GrandMA3 software, standard TCP port is 9000 +**You can only use TCP or UDP, not both at once!** + +# Helper Functions -### interfaceExternUDP() +## Pool Number +You can change the Pool number common for all classes or for a single class member. + +### Common Page Number +For changing the common page number use ```cpp -void interfaceExternUDP(UDP &udp, uint16_t port) +void poolCommon(uint16_t pool); ``` -Set the UDP socket and port external receivers accessing via ```oscButton()``` function +Default is **Pool 1** -### interfaceExternTCP() +Example ```cpp -void interfaceExternTCP(UDP &tcp, uint16_t port) +poolCommon(2); // set common pool to 2 ``` -Set the TCP socket and port external receivers accessing via ```oscButton()``` function -**Examples** +### Pool Number by class +Refer to the classes documentation + +### Send Pool Number +You can change the pool number of the the console + ```cpp -interfaceGMA3(gma3IP); -interfaceUDP(udp, gma3UdpPort); -interfaceTCP(tcp, gma3TcpPort); -interfaceExternUDP(udpQLab, qlabIP, qlabPort); -interfaceExternTCP(tcpQLab, qlabIP, qlabPort); +void sendPool(uint16_t pool); +``` + +**Example** +```cpp +poolSend(2); // set the console pool to 2 ``` ## Page Number -You can change the Page number now global or local. +You can change the Page number common for all classes or for a single class member. -### Global Page Number -For changing the global page number use +### Common Page Number +For changing the common page number use ```cpp -void page(uint16_t page) +void pageCommon(uint16_t page); ``` -Standard is **Page 1** +Default is **Page 1** -Example +**Example** ```cpp -page(2); // set global page to 2 +pageCommon(2); // set common page to 2 ``` -### Local Page Number +### Page Number by class Refer to the classes documentation -# Functions +### Send Page Number +You can change the page number of the the console -#### command() ```cpp -void command(const char command[], protocol_t protocol = UDPOSC); +void sendPage(uint16_t page); +``` + +**Example** +```cpp +pageSend(2); // set the console page to 2 ``` + +## **command()** Send a command message +```cpp +void command(const char command[], protocol_t protocol = UDPOSC); +``` -Example +**Example** ```cpp command("Page+"); ``` # Classes +## **Parser** +This class parse the message send from the console + +### Constructor +```cpp +Parser(cbptr callback); +``` +- **callback** callback pointer to a function which is called when a new message arrived + +**Example** +```cpp +void parse() { + Serial.print("OSC Pattern: "); + Serial.print(parser.patternOSC()); + Serial.print(" String: "); + Serial.print(parser.stringOSC()); + Serial.print(" Integer 1: "); + Serial.print(parser.int1OSC()); + Serial.print(" Integer 2: "); + Serial.print(parser.int2OSC()); + Serial.print(" Float: "); + Serial.println(parser.floatOSC()); + } +Parser parser(parse); +``` + +The OSC data consists of the OSC pattern and max. 3 arguments, +1 String, up to two Integers and one Float argument +To get the OSC data inside you can use following class members: + +```cpp +const char* patternOSC(); // returns the pattern string +int dataStructure(uint8_t level); // returns the parts of the internal data structure as an integer, the level can 0 thru 4 +const char* stringOSC(); // returns the string argument which the command +int32_t int1OSC(); // returns the 1. integer argument +int32_t int2OSC(); // returns the 2. integer argument if available +float floatOSC(); // returns the float argument if available +``` + +Example Outputs are +``` +OSC Pattern: 13.13.1.5.2 String: Go+ Integer 1: 1 Integer 2: 0 Float: 0.00 +OSC Pattern: 13.13.1.5.2 String: Go+ Integer 1: 0 Integer 2: 0 Float: 0.00 +OSC Pattern: 13.13.1.5.2 String: FaderMaster Integer 1: 1 Integer 2: 0 Float: 100.00 +``` +The OSC pattern data is very cryptic because of the representation of the internal structure which there is no real documentation. + +### Update +To get the messages send by console you must call inside the ```loop()``` function +```cpp +void update(); +``` +Example, this must happen in the ```loop()``` function +```cpp +parser.update(); +``` + +# Hardware Classes +It is now possible to use virtual devices like touchscreens e.g. from Nextion https://github.com/sstaub/NextionX2 or I/O expanders for analog (MCP3208 https://github.com/sstaub/MCP_3208) and digital (MCP32017 https://github.com/sstaub/MCP_23017) inputs. You can find Libraries for this devices are on the my GitHub + ## **Key** With this class you can create Key objects which can be triggered with a button. ### Constructor ```cpp -Key(uint8_t pin, uint16_t key, protocol_t protocol = UDPOSC); +Key(uint8_t pin, uint16_t key); +Key(uint16_t key); // for virtual control +``` +- **pin** are the connection Pin for the button hardware, this is not needed for virtual control +- **key** is the key number of the executors, refer to the GrandMA3 manual + +**Example** this should done before the ```setup()``` +```cpp +Key key201(2, 201); +// executor button 201, using pin 2 +Key key201(201); // for virtual control ``` -- ```pin``` are the connection Pin for the button hardware -- ```key``` is the key number of the executors, refer to the GrandMA3 manual -- ```protocol``` is the transport protocol you want to use, it can UDPOSC and TCP -Example, this should done before the setup() +### Pool ```cpp -Key key201(2, 201, TCP); -// executor button 201, using pin 2, transport with TCP +void pool(uint16_t poolLocal = 0); ``` +- **poolLocal** is the pool number of the executors, refer to the GrandMA3 manual + +Set a local page number which overrides the global. -### Destructor +**Example** ```cpp -~Key(); +key201.pool(2); // set local pool 2 +key201.pool(); // reset to global pool ``` -Use for destructing a Key object ### Page ```cpp void page(uint16_t pageLocal = 0); ``` -- ```pageLocal``` is the page number of the executors, refer to the GrandMA3 manual +- **pageLocal** is the page number of the executors, refer to the GrandMA3 manual Set a local page number which overrides the global. -Example +**Example** ```cpp key201.page(2); // set local page 2 key201.page(); // reset to global page ``` ### Update -To get the actual button state you must call inside the ```loop()``` function ```cpp void update(); +void update(bool state); // for virtual control ``` +- **state** optional for virtual devices, TRUE if button press + +To get the actual button state you must call inside the ```loop()``` function + Example, this must happen in the ```loop()``` function ```cpp key201.update(); +// key201.update(TRUE); ``` ## **Fader** This class allows you to control a fader containing with a hardware (slide) potentiometer as an executor fader. ### Timing constants -``` +```cpp #define FADER_UPDATE_RATE_MS 1 // update rate, must low at possible for fetching #define FADER_THRESHOLD 4 // Jitter threshold of the faders ``` ### Constructor ```cpp -Fader(uint8_t analogPin, uint16_t fader, protocol_t protocol = UDPOSC); +Fader(uint8_t analogPin, uint16_t fader); +Fader(uint16_t fader); // for virtual control +``` +- **analogPin** are the connection Analog Pin for the fader leveler, this is not needed for virtual control +- **fader** is the fader number of the executors, refer to the GrandMA3 manual + +Example, this should done before the ```setup()``` +```cpp +Fader fader201(A0, 201); // leveler is Analog Pin A0, executor number of the fader is 201 +Fader fader201(201); // for virtual control ``` -- ```analogPin``` are the connection Analog Pin for the fader leveler -- ```fader``` is the fader number of the executors, refer to the GrandMA3 manual -- ```protocol``` is the transport the protocol you want to use, it can UDPOSC and TCP, UDPOSC is recommended -Example, this should done before the setup() +### Pool ```cpp -Fader fader201(A0, 201); -// leveler is Analog Pin A0, executor number of the fader is 201, using UDPOSC as standard +void pool(uint16_t poolLocal = 0); ``` +- **poolLocal** is the pool number of the executors, refer to the GrandMA3 manual + +Set a local page number which overrides the global. -### Destructor +**Example** ```cpp -~Fader(); +fader201.pool(2); // set local pool 2 +fader201.pool(); // reset to global pool ``` -Use for destructing a Fader object ### Page ```cpp void page(uint16_t pageLocal = 0); ``` -- ```pageLocal``` is the page number of the executors, refer to the GrandMA3 manual +- **pageLocal** is the page number of the executors, refer to the GrandMA3 manual Set a local page number which overrides the global. @@ -430,7 +596,7 @@ int32_t value = fader201.value(); ```cpp void fetch(uint16_t value); ``` -- ```value``` unlock value +- **value** unlock value Lock the sending of OSC fader data until the value defined in fetch() is reached.
This functionality is intended for page changing. So you need to fetch the fader before you can use it. @@ -447,8 +613,8 @@ void lock(bool state); ``` Get or set the state of the fetch function, can used for indication of the fader state or force a new state. -- ```true``` locked fader -- ```false``` unlocked fader +- **true** locked fader +- **false** unlocked fader Example ```cpp @@ -475,39 +641,53 @@ fader201.jitter(2); // set fetch range to +/- 2 To get the actual button state you must call inside the ```loop()``` function ```cpp void update(); +void update(uint16_t value); // for virtual control ``` + +- **value** optional for virtual inputs with 10 bits + Example, this must happen in the ```loop()``` function ```cpp fader201.update(); +void update(255); // about 25% ``` ## **ExecutorKnob** The ExecutorKnob class creates an encoder object which allows to control the executor knobs: ```cpp -ExecutorKnob(uint8_t pinA, uint8_t pinB, uint16_t executorKnob, protocol_t protocol = UDPOSC, uint8_t direction = FORWARD); +ExecutorKnob(uint8_t pinA, uint8_t pinB, uint16_t executorKnob, uint8_t direction = FORWARD); +ExecutorKnob(uint16_t executorKnob, uint8_t direction = FORWARD); ``` -- ```pinA``` and **pinB** are the connection Pins for the encoder hardware -- ```executorKnob``` is the number of the executor knob, refer to the GrandMA3 manual -- ```protocol``` is the transport protocol you want to use, it can UDPOSC and TCP -- ```direction``` is used for changing the direction of the encoder to clockwise if pinA and pinB are swapped. The directions are FORWARD (standard) or REVERSE +- **pinA** and **pinB** are the connection Pins for the encoder hardware, this is not needed for virtual control +- **executorKnob** is the number of the executor knob, refer to the GrandMA3 manual +- **direction** is used for changing the direction of the encoder to clockwise if pinA and pinB are swapped. The directions are FORWARD (standard) or REVERSE -Example, this should done before the setup() +Example, this should done before the ```setup()``` ```cpp -ExecutorKnob enc301(3, 4, 301, UDPOSC, REVERSE); -// the encoder pins are 3/4, the number of the executorKnob is 301, send with UDP, encoder pins are swapped (REVERSE) +ExecutorKnob enc301(3, 4, 301, REVERSE); +// the encoder pins are 3/4, the number of the executorKnob is 301, encoder pins are swapped (REVERSE) +ExecutorKnob enc301(301, REVERSE); // for virtual control ``` -### Destructor +### Pool ```cpp -~ExecutorKnob(); +void pool(uint16_t poolLocal = 0); +``` +- **poolLocal** is the pool number of the executors, refer to the GrandMA3 manual + +Set a local page number which overrides the global. + +**Example** +```cpp +enc301.pool(2); // set local pool 2 +enc301.pool(); // reset to global pool ``` -Use for destructing a Fader object ### Page ```cpp void page(uint16_t pageLocal = 0); ``` -- ```pageLocal``` is the page number of the executors, refer to the GrandMA3 manual +- **pageLocal** is the page number of the executors, refer to the GrandMA3 manual Set a local page number which overrides the global. @@ -521,205 +701,183 @@ enc301.page(); // reset to global page To get the actual encoder state you must call inside the ```loop()``` function ```cpp void update(); +void update(uint8_t stateA, uint8_t stateB); // for virtual control ``` +- **stateA** optional for virtual devices, TRUE if encoderA contacts +- **stateB** optional for virtual devices, TRUE if encoderB contacts + Example, this must happen in the ```loop()``` function ```cpp enc301.update(); +enc301.update(TRUE, FALSE); // for virtual control ``` ## **CmdButton** With this class you can create a button which allows to send commands to the console. ```cpp -CmdButton(uint8_t pin, const char command[], protocol_t protocol = UDPOSC); +CmdButton(uint8_t pin, const char command[]); +CmdButton(const char *command); // for virtual control ``` -- ```pin``` are the connection Pin for the button hardware -- ```command``` is a command string which should send to the console, refer also to the GrandMA3 manual -- ```protocol``` is the transport protocol you want to use, it can UDPOSC and TCP +- **pin** are the connection Pin for the button hardware, this not needed for virtual control +- **command** is a command string which should send to the console, refer also to the GrandMA3 manual - -Example, this should done before the setup() +Example, this should done before the ```setup()``` ```cpp -CmdButton macro1(A2, "GO+ Macro 1"); -// button on pin A2, fires Macro 1 +CmdButton macro1(A2, "GO+ Macro 1"); // button on pin A2, fires Macro 1 +CmdButton macro1("GO+ Macro 1"); // for virtual control ``` -### Destructor -```cpp -~CmdButton(); -``` -Use for destructing a Fader object - ### Update To get the actual button state you must call inside the ```loop()``` function ```cpp void update(); +void update(bool state); // for virtual control ``` +- **state** optional for virtual devices, TRUE if button press + Example, this must happen in the ```loop()``` function ```cpp macro1.update(); +macro1.update(TRUE); // for virtual button press ``` -## **OscButton** -With this class you can create generic buttons which allows you to control other OSC compatible software in the network like QLab. The class initializer is overloaded to allow sending different OSC data types: Integer 32 bit, Float, Strings or no data.
-**! When using integer or float, 0 or 0.0 is explicit send when releasing the button !** +## **Pages** +With this class you can create a Page object which can be controlled with a two button. ### Constructor ```cpp -OscButton(uint8_t pin, const char pattern[], int32_t integer32, protocol_t protocol = UDPOSC); -OscButton(uint8_t pin, const char pattern[], float float32, protocol_t protocol = UDPOSC); -OscButton(uint8_t pin, const char pattern[], const char message[], protocol_t protocol = UDPOSC); -OscButton(uint8_t pin, const char pattern[], protocol_t protocol = UDPOSC); +Pages(uint8_t pinUp, uint8_t pinDown, uint8_t pagesStart, uint8_t pagesEnd, send_t mode = GLOBAL, cbptr callback = nullptr); +Pages(uint8_t pagesStart, uint8_t pagesEnd, send_t mode = GLOBAL, cbptr callback = nullptr); // for virtual control +``` +- **pinUp** are the connection Pin for the up button hardware, this is not needed for virtual control +- **pinDown** are the connection Pin for the up button hardware, this is not needed for virtual control +- **pageStart** is the start page number +- **pageLast** is the last used page number +- **mode** you can control how page information is used + - LOCAL page is only used for internal use + - CONSOLE page is only send to the console + - GLOBAL page is used overall +- **callback** callback pointer to a function which is called when a button is pressed, within the callback function you can proceed fetch() or display functions using ```currentPage()``` and ```lastPage()``` functions + +**Example** this should done before the ```setup()``` +```cpp +Pages pages(2, 3, 1, PAGES, GLOBAL, pageChange); // up button pin 2, down button pin 3, start with page 1, last page is 4, global control, pageChange() is callback function name +Pages pages(1, PAGES, GLOBAL, pageChange); // for virtual control +``` + +### currentPage +```cpp +uint16_t currentPage(); ``` -- ```pin``` the connection Pin for the button hardware -- ```pattern``` the OSC address pattern -- ```integer32``` optional Integer data to send, you must cast this data e.g. ```(int32_t)1``` -- ```float32``` optional Float data to send, you must cast this data e.g. ```1.0f``` -- ```message``` optional String to send -- ```protocol``` is the transport protocol you want to use, it can UDPOSC, TCP and TCPSLIP +Get the current page number. -Example for Ethernet UDP using a button on Pin 0, this should done before the setup() +**Example** ```cpp -#define QLAB_GO_PIN 0 -IPAddress qlabIP(10, 101, 1, 101); // IP of QLab -uint16_t qlabPort = 53000; // QLab receive port -OscButton qlabGo(QLAB_GO_PIN , "/go", qlabIP, qlabPort); +uint16_t pageCurrent = pages.currentPage() ``` -### Destructor +### lastPage ```cpp -~OscButton(); +uint16_t lastPage(); +``` + +Get the last used page number. + +**Example** +```cpp +uint16_t pageLast = pages.lastPage() ``` -Use for destructing a Fader object ### Update -To get the actual button state you must call inside the ```loop()``` function ```cpp void update(); +void update(bool stateUp, bool stateDown); // for virtual control ``` +- **stateUp** state of the up button, optional for virtual devices, TRUE if button press +- **stateDown** state of the down button, optional for virtual devices, TRUE if button press + +To get the actual button states you must call inside the ```loop()``` function + Example, this must happen in the ```loop()``` function ```cpp -qlabGo.update(); +pages.update(); +pages.update(TRUE, FALSE); // for virtual control ``` -## **Button** -This is a simple class to create a button which triggers a callback function.
-There is following order in the program code needed before ```setup()```: -- Initialization of the hardware classes -- Declaration (and optional Initialization) of the callback functions -- Initialization of the Button classes +## **Pools** +With this class you can create a Pool object which can be controlled with a two button. ### Constructor ```cpp -Button(uint8_t pin, cbptr callback); +Pools(uint8_t pinUp, uint8_t pinDown, uint8_t poolsStart, uint8_t poolsEnd, send_t mode = GLOBAL, cbptr callback = nullptr); +Pools(uint8_t pagesStart, uint8_t pagesEnd, send_t mode = GLOBAL, cbptr callback = nullptr); // for virtual control ``` -- ```pin``` are the connection Pin for the button hardware -- ```callback``` pointer to the callback function for the button +- **pinUp** are the connection Pin for the up button hardware, this is not needed for virtual control +- **pinDown** are the connection Pin for the up button hardware, this is not needed for virtual control +- **pageStart** is the start page number +- **pageLast** is the last used page number +- **mode** you can control how page information is used + - LOCAL page is only used for internal use + - CONSOLE page is only send to the console + - GLOBAL page is used overall +- **callback** callback pointer to a function which is called when a button is pressed, within the callback function you can proceed fetch() or display functions using ```currentPage()``` and ```lastPage()``` functions -Example, this should done before the setup() +**Example** this should done before the ```setup()``` ```cpp -#define PAGES 4 -int pageNumber = 1; // start page -void upButton() { // callback function the Up button - if (pageNumber >= PAGES) pageNumber = 1; // wrap around - else pageNumber++; - char cmd[12] = "Page "; - strcat(cmd, itoa(pageNumber)); - command(cmd); // send command - page(pageNumber); // change global page - Serial.print("Page "); - Serial.println(pageNumber); - } -void downButton() { // callback function the Up button - if (pageNumber <= 1) pageNumber = PAGES; - else pageNumber--; - char cmd[12] = "Page "; - strcat(cmd, itoa(pageNumber)); - command(cmd); // send command - page(pageNumber); // change global page - Serial.print("Page "); - Serial.println(pageNumber); - } -Button pageUp(2, upButton); -Button pageDown(3, downButton); +Pools pools(4, 5, 1, PAGES, GLOBAL, pageChange); // up button pin 4, down button pin 5, start with page 1, last page is 4, global control, pageChange() is callback function name +Pages pages(1, PAGES, GLOBAL, pageChange); // for virtual control ``` -### Update -To get the actual button state you must call inside the ```loop()``` function +### currentPool ```cpp -void update(); +uint16_t currentPool(); ``` -Example, this must happen in the ```loop()``` function + +Get the current pool number. + +**Example** ```cpp -pageUp.update(); -pageDown.update(); +uint16_t poolCurrent = pools.currentPool() ``` -## Send OSC message manually -Two steps are needed for send OSC messages manually: -1. Create an OSC message using +### lastPool ```cpp -void oscMessage(const char pattern[], int32_t int32, protocol_t protocol = UDPOSC); -void oscMessage(const char pattern[], float float32, protocol_t protocol = UDPOSC); -void oscMessage(const char pattern[], const char string[], protocol_t protocol = UDPOSC); -void oscMessage(const char pattern[], protocol_t protocol = UDPOSC); +uint16_t lastPool(); ``` -- ```const char pattern[]``` is the OSC pattern -- ```int32_t int32``` for integer data -- ```float float32``` for float date -- ```const char string[]``` for strings -- it is also possible to send no argument, e.g. for QLab Go cmd -- ```protocol_t protocol``` is the protocol type UDPOSC, TCP or TCPSLIP -1. Send an OSC Message, depending on the chosen interface. -This functions can called inside setup() or loop() after init the interface. +Get the last used pool number. + +**Example** ```cpp -void sendUDP(); -void sendExternUDP(); -void sendTCP(); -void sendExternTCP(); +uint16_t poolLast = pools.lastPool() ``` -## Receive UDP data with ```receiveUdp()``` -You can receive the data send by the GrandMA software. Only UDP receive is supported. -With the ```receiveUdp()``` function you get the data which are automatic parsed to seperate the OSC data. +### Update ```cpp -bool receiveUDP(); // returns true if there is data present +void update(); +void update(bool stateUp, bool stateDown); // for virtual control ``` +- **stateUp** state of the up button, optional for virtual devices, TRUE if button press +- **stateDown** state of the down button, optional for virtual devices, TRUE if button press -The OSC data consists of the OSC pattern and max. 3 arguments, -1 String, up to two Integers and one Float argument -To get the OSC data inside you can use following functions: +To get the actual button states you must call inside the ```loop()``` function +Example, this must happen in the ```loop()``` function ```cpp -patternOSC() // returns the pattern string -stringOSC() // returns the string argument which the command -int1OSC() // returns the 1. integer argument -int2OSC() // returns the 2. integer argument if available -floatOSC() // returns the float argument if available -``` - -**Example** -This must happen in the ```loop()``` function -```cpp -if (receiveUDP()) { - Serial.print("OSC Pattern: "); - Serial.print(patternOSC()); - Serial.print(" String: "); - Serial.print(stringOSC()); - Serial.print(" Integer 1: "); - Serial.print(int1OSC()); - Serial.print(" Integer 2: "); - Serial.print(int2OSC()); - Serial.print(" Float: "); - Serial.println(floatOSC()); - } +pools.update(); +pools.update(TRUE, FALSE); // for virtual control ``` -Example Outputs are -``` -OSC Pattern: /gma3/13.13.1.5.2 String: Go+ Integer 1: 1 Integer 2: 0 Float: 0.00 -OSC Pattern: /gma3/13.13.1.5.2 String: Go+ Integer 1: 0 Integer 2: 0 Float: 0.00 -OSC Pattern: /gma3/13.13.1.5.2 String: FaderMaster Integer 1: 1 Integer 2: 0 Float: 100.00 +# Send an OSC message manually +Send an OSC message with different data tags +```cpp +void oscMessage(const char pattern[], int32_t int32); +void oscMessage(const char pattern[], float float32); +void oscMessage(const char pattern[], const char string[]); +void oscMessage(const char pattern[]); ``` -The OSC pattern data is very cryptic because of the representation of the internal structure which there is no real documentation. +- **const char pattern[]** is the OSC pattern +- **int32_t int32** for integer data +- **float float32** for float date +- **const char string[]** for strings diff --git a/examples/gma3_Arduino/gma3_Arduino.ino b/examples/gma3_Arduino/gma3_Arduino.ino index bc8524c..611f9ec 100644 --- a/examples/gma3_Arduino/gma3_Arduino.ino +++ b/examples/gma3_Arduino/gma3_Arduino.ino @@ -1,71 +1,83 @@ -#include -#include +// Example for Arduino with Ethernetshield 2 + +#include // for Arduino Ethernet library https://github.com/arduino-libraries/Ethernet +// #include // for Ethernet3 library https://github.com/sstaub/Ethernet3 +// #include #include "gma3.h" -#define BTN_KEY 2 -#define ENC_1_A 3 -#define ENC_1_B 4 -#define BTN_CMD 5 -#define FADER A0 +// I/O config +#define BTN_KEY_1 2 +#define BTN_KEY_2 3 +#define BTN_KEY_3 4 +#define BTN_KEY_4 5 +#define ENC_1_A 6 +#define ENC_1_B 7 +#define ENC_2_A 8 +#define ENC_2_B 9 +#define BTN_CMD 10 +#define FADER A0 -// network data -uint8_t mac[] = {0x90, 0xA2, 0xDA, 0x10, 0x14, 0x48}; -#define GMA3_UDP_PORT 8000 // UDP Port configured in gma3 -#define GMA3_TCP_PORT 9000 // UDP Port configured in gma3 +// Network config +#define GMA3_UDP_PORT 8000 // UDP Port configured in gma3 +#define GMA3_TCP_PORT 9000 // UDP Port configured in gma3 -IPAddress localIP(10, 101, 1, 201); // IP address of the microcontroller board -IPAddress subnet(255, 255, 0, 0); // subnet range +uint8_t mac[] = {0x90, 0xA2, 0xDA, 0x10, 0x14, 0x48}; +IPAddress localIp(10, 101, 1, 201); // IP address of the microcontroller board +IPAddress subnet(255, 255, 0, 0); // optional subnet range +IPAddress dns(10, 101, 1, 100); // optional DNS address of your device +IPAddress gateway(10, 101, 1, 100); // optional Gateway address of your device +uint16_t localUdpPort = GMA3_UDP_PORT; IPAddress gma3IP(10, 101, 1, 100); // IP address of the gma3 console uint16_t gma3UdpPort = GMA3_UDP_PORT; uint16_t gma3TcpPort = GMA3_TCP_PORT; -EthernetUDP udp; -EthernetUDP udpQLab; -EthernetClient tcp; -EthernetClient tcpQLab; +// EthernetUDP udp; // for UDP +EthernetClient tcp; // for TCP + +// functions prototypes +void parse(); // hardware definitions +Key key101(BTN_KEY_1, 101); Fader fader201(FADER, 201); -Key key201(BTN_KEY, 201, TCP); +Key key201(BTN_KEY_2, 201); +Key key301(BTN_KEY_3, 301); ExecutorKnob enc301(ENC_1_A, ENC_1_B, 301); -CmdButton macro1(BTN_CMD, "GO+ Macro 1", TCP); - -// use of generic OSC button -#define QLAB_GO_PIN 6 -IPAddress qlabIP(10, 101, 1, 100); // IP of QLab -uint16_t qlabPort = 53000; // QLab receive port -OscButton qlabGo(QLAB_GO_PIN , "/go", TCPSLIP); +Key key401(BTN_KEY_4, 401); +ExecutorKnob enc401(ENC_2_A, ENC_2_B, 301); +CmdButton macro1(BTN_CMD, "GO+ Macro 1"); +Parser parser(parse); void setup() { Serial.begin(9600); - /* for USR-ES1 module - Ethernet.setRstPin(9); - Ethernet.hardreset(); - */ - Ethernet.begin(mac, localIP, subnet); - interfaceGMA3(gma3IP); - interfaceUDP(udp, gma3UdpPort); - interfaceTCP(tcp, gma3TcpPort); - interfaceExternUDP(udpQLab, qlabIP, qlabPort); - interfaceExternTCP(tcpQLab, qlabIP, qlabPort); + Ethernet.begin(mac, localIp); + //interface(udp, gma3IP, gma3UdpPort); // for UDP + interface(tcp, TCP, gma3IP, gma3TcpPort); // for TCP } void loop() { + key101.update(); key201.update(); + key301.update(); + key401.update(); fader201.update(); enc301.update(); + enc401.update(); macro1.update(); - qlabGo.update(); - if (receiveUDP()) { - Serial.print("OSC Pattern: "); - Serial.print(patternOSC()); - Serial.print(" String: "); - Serial.print(stringOSC()); - Serial.print(" Integer 1: "); - Serial.print(int1OSC()); - Serial.print(" Integer 2: "); - Serial.print(int2OSC()); - Serial.print(" Float: "); - Serial.println(floatOSC()); - } + parser.update(); + } + +void parse() { + Serial.print("OSC Message at "); + Serial.print(millis()); + Serial.print("ms Pattern: "); + Serial.print(parser.patternOSC()); + Serial.print(" String: "); + Serial.print(parser.stringOSC()); + Serial.print(" Integer 1: "); + Serial.print(parser.int1OSC()); + Serial.print(" Integer 2: "); + Serial.print(parser.int2OSC()); + Serial.print(" Float: "); + Serial.println(parser.floatOSC()); } diff --git a/examples/gma3_Arduino_PIO/platformio.ini b/examples/gma3_Arduino_PIO/platformio.ini deleted file mode 100755 index 019af3d..0000000 --- a/examples/gma3_Arduino_PIO/platformio.ini +++ /dev/null @@ -1,16 +0,0 @@ -; PlatformIO Project Configuration File -; -; Build options: build flags, source filter -; Upload options: custom upload port, speed and extra flags -; Library options: dependencies, extra library storages -; Advanced options: extra scripting -; -; Please visit documentation for the other options and examples -; http://docs.platformio.org/page/projectconf.html - - -[env:megaatmega2560] -platform = atmelavr -framework = arduino -board = megaatmega2560 - diff --git a/examples/gma3_Arduino_PIO/src/main.cpp b/examples/gma3_Arduino_PIO/src/main.cpp deleted file mode 100755 index 4ffb065..0000000 --- a/examples/gma3_Arduino_PIO/src/main.cpp +++ /dev/null @@ -1,118 +0,0 @@ -#include "Arduino.h" -#include "Ethernet3.h" -#include "gma3.h" - -// constants and macros - -#define BTN_1 2 // GO button -#define BTN_2 3 // Macro button -#define BTN_3 4 // page up button -#define BTN_4 5 // page down button -#define BTN_5 6 // QLab GO button -#define ENC_1_A 7 // encoder A -#define ENC_1_B 8 // encoder B -#define FADER_1 A0 // fader - -// Network config -#define GMA3_UDP_PORT 8000 // UDP Port configured in gma3 -#define GMA3_TCP_PORT 9000 // UDP Port configured in gma3 - -uint8_t mac[] = {0x90, 0xA2, 0xDA, 0x10, 0x14, 0x48}; -IPAddress localIP(10, 101, 1, 201); // IP address of the microcontroller board -IPAddress subnet(255, 255, 0, 0); // subnet range -uint16_t localUdpPort = GMA3_UDP_PORT; -IPAddress gma3IP(10, 101, 1, 100); // IP address of the gma3 console -uint16_t gma3UdpPort = GMA3_UDP_PORT; -uint16_t gma3TcpPort = GMA3_TCP_PORT; - -EthernetUDP udp; -EthernetUDP udpQLab; -EthernetClient tcp; -EthernetClient tcpQLab; - -#define PAGES 4 -int pageNumber = 1; -int16_t value[PAGES]; - -// hardware definitions -Key key201(BTN_1, 201, TCP); -Fader fader201(FADER_1, 201); -ExecutorKnob enc301(ENC_1_A, ENC_1_B, 301, UDPOSC, REVERSE); -CmdButton macro1(BTN_2, "GO+ Macro 1"); - -void upButton() { - if (fader201.lock() == false) - value[pageNumber] = fader201.value(); // stores value if the fader is not locked - if (pageNumber >= PAGES) pageNumber = 1; // rollover to last page - else pageNumber++; - char cmd[12] = "Page "; - strcat(cmd, itoa(pageNumber)); - command(cmd); - page(pageNumber); - if (value[pageNumber] != fader201.value()) - fader201.fetch(value[pageNumber]); // force to value of the new page - else fader201.lock(false); // no lock needed because stored and fader value are equal - Serial.print("Page "); - Serial.println(pageNumber); - } - -void downButton() { - if (fader201.lock() == false) - value[pageNumber] = fader201.value(); // stores value if the fader is not locked - if (pageNumber <= 1) pageNumber = PAGES; // rollover to first page - else pageNumber--; - char cmd[12] = "Page "; - strcat(cmd, itoa(pageNumber)); - command(cmd); - page(pageNumber); - if (value[pageNumber] != fader201.value()) - fader201.fetch(value[pageNumber]); // force to value of the new page - else fader201.lock(false); // no lock needed because stored and fader value are equal - Serial.print("Page "); - Serial.println(pageNumber); - } - -Button pageUp(BTN_3, upButton); -Button pageDown(BTN_4, downButton); - -// use of generic OSC button -IPAddress qlabIP(10, 101, 1, 100); // IP of QLab -uint16_t qlabPort = 53000; // QLab receive port -OscButton qlabGo(BTN_5 , "/go"); - -void setup() { - pinMode(LED_BUILTIN, OUTPUT); - Serial.begin(9600); - Ethernet.begin(mac, localIP, subnet); - interfaceGMA3(gma3IP); - interfaceUDP(udp, gma3UdpPort); - interfaceTCP(tcp, gma3TcpPort); - interfaceExternUDP(udpQLab, qlabIP, qlabPort); - interfaceExternTCP(tcpQLab, qlabIP, qlabPort); - fader201.fetch(0); - } - -void loop() { - pageUp.update(); - pageDown.update(); - if (receiveUDP()) { - Serial.print("OSC Pattern: "); - Serial.print(patternOSC()); - Serial.print(" String: "); - Serial.print(stringOSC()); - Serial.print(" Integer 1: "); - Serial.print(int1OSC()); - Serial.print(" Integer 2: "); - Serial.print(int2OSC()); - Serial.print(" Float: "); - Serial.println(floatOSC()); - } - - key201.update(); - fader201.update(); - enc301.update(); - macro1.update(); - qlabGo.update(); - - digitalWrite(LED_BUILTIN, fader201.lock()); - } diff --git a/examples/gma3_Fetch/gma3_Fetch.ino b/examples/gma3_Fetch/gma3_Fetch.ino index e4cd0a8..992c2ad 100755 --- a/examples/gma3_Fetch/gma3_Fetch.ino +++ b/examples/gma3_Fetch/gma3_Fetch.ino @@ -1,10 +1,9 @@ // simple example for paging and fetching -#include "Arduino.h" -#include "Ethernet3.h" +#include "Ethernet.h" #include "gma3.h" -// constants and macros +// I/O config #define BTN_1 2 #define BTN_2 3 #define FADER_1 A0 @@ -16,71 +15,44 @@ uint8_t mac[] = {0x90, 0xA2, 0xDA, 0x10, 0x14, 0x48}; IPAddress localIP(10, 101, 1, 201); // IP address of the microcontroller board IPAddress subnet(255, 255, 0, 0); // subnet range +IPAddress dns(10, 101, 1, 100); // DNS address of your device +IPAddress gateway(10, 101, 1, 100); // Gateway address of your device uint16_t localUdpPort = GMA3_UDP_PORT; IPAddress gma3IP(10, 101, 1, 100); // IP address of the gma3 console uint16_t gma3UdpPort = GMA3_UDP_PORT; uint16_t gma3TcpPort = GMA3_TCP_PORT; EthernetUDP udp; -EthernetUDP udpQLab; EthernetClient tcp; -EthernetClient tcpQLab; #define PAGES 4 -int pageNumber = 1; -int16_t value[PAGES]; +int16_t value[PAGES + 1] = {0}; +void pageChange(); Fader fader201(FADER_1, 201); - -void upButton() { - if (fader201.lock() == false) - value[pageNumber] = fader201.value(); // stores value if the fader is not locked - if (pageNumber >= PAGES) pageNumber = 1; // rollover to last page - else pageNumber++; - char cmd[12] = "Page "; - strcat(cmd, itoa(pageNumber)); - command(cmd); - page(pageNumber); - if (value[pageNumber] != fader201.value()) - fader201.fetch(value[pageNumber]); // force to value of the new page - else fader201.lock(false); // no lock needed because stored and fader value are equal - Serial.print("Page "); - Serial.println(pageNumber); - } - -void downButton() { - if (fader201.lock() == false) - value[pageNumber] = fader201.value(); // stores value if the fader is not locked - if (pageNumber <= 1) pageNumber = PAGES; // rollover to first page - else pageNumber--; - char cmd[12] = "Page "; - strcat(cmd, itoa(pageNumber)); - command(cmd); - page(pageNumber); - if (value[pageNumber] != fader201.value()) - fader201.fetch(value[pageNumber]); // force to value of the new page - else fader201.lock(false); // no lock needed because stored and fader value are equal - Serial.print("Page "); - Serial.println(pageNumber); - } - -// add Up / Down keys -Button pageUp(BTN_1, upButton); -Button pageDown(BTN_2, downButton); +Pages pages(BTN_1, BTN_2, 1, 4, GLOBAL, pageChange); // using 4 pages starting with page 1 void setup() { pinMode(LED_BUILTIN, OUTPUT); Serial.begin(9600); - Ethernet.begin(mac, localIP, subnet); - interfaceGMA3(gma3IP); - interfaceUDP(udp, gma3UdpPort); - interfaceTCP(tcp, gma3TcpPort); + Ethernet.begin(mac, localIP); + interface(tcp, TCP, gma3IP, gma3TcpPort); // init inteface for TCP + //interface(udp, gma3IP, gma3UdpPort); // init interface for UDP + fader201.jitter(2); fader201.fetch(0); // force fader to 0 } void loop() { fader201.update(); - pageUp.update(); - pageDown.update(); + pages.update(); digitalWrite(LED_BUILTIN, fader201.lock()); // shows if fader is locked + } + +void pageChange() { + if(fader201.lock() == false) value[pages.lastPage()] = fader201.value(); // if not locked store the value for the last page + if(fader201.value() != value[pages.currentPage()]) { // if the fader value is not the expected value then fetch to current value + fader201.fetch(value[pages.currentPage()]); + } + Serial.print("Page changed to page "); + Serial.println(pages.currentPage()); } \ No newline at end of file diff --git a/examples/gma3_Paging/gma3_Paging.ino b/examples/gma3_Paging/gma3_Paging.ino deleted file mode 100755 index 004b601..0000000 --- a/examples/gma3_Paging/gma3_Paging.ino +++ /dev/null @@ -1,64 +0,0 @@ -#include "Arduino.h" -#include "Ethernet3.h" -#include "gma3.h" - -// constants and macros -#define BTN_1 2 -#define BTN_2 3 - -// Network config -#define GMA3_UDP_PORT 8000 // UDP Port configured in gma3 -#define GMA3_TCP_PORT 9000 // UDP Port configured in gma3 - -uint8_t mac[] = {0x90, 0xA2, 0xDA, 0x10, 0x14, 0x48}; -IPAddress localIP(10, 101, 1, 201); // IP address of the microcontroller board -IPAddress subnet(255, 255, 0, 0); // subnet range -uint16_t localUdpPort = GMA3_UDP_PORT; -IPAddress gma3IP(10, 101, 1, 100); // IP address of the gma3 console -uint16_t gma3UdpPort = GMA3_UDP_PORT; -uint16_t gma3TcpPort = GMA3_TCP_PORT; - -EthernetUDP udp; -EthernetUDP udpQLab; -EthernetClient tcp; -EthernetClient tcpQLab; - -int pageNumber = 1; -void upButton() { - if (pageNumber >= 9) pageNumber = 1; - else pageNumber++; - char cmd[12] = "Page "; - strcat(cmd, itoa(pageNumber)); - command(cmd); // send page command - page(pageNumber); // set page number - Serial.print("Page "); - Serial.println(pageNumber); -} - -void downButton() { - if (pageNumber <= 1) pageNumber = 9; - else pageNumber--; - char cmd[12] = "Page "; - strcat(cmd, itoa(pageNumber)); - command(cmd); // send page command - page(pageNumber); // set page number - Serial.print("Page "); - Serial.println(pageNumber); - } - -// add Up / Down keys -Button pageUp(BTN_1, upButton); -Button pageDown(BTN_2, downButton); - -void setup() { - Serial.begin(9600); - Ethernet.begin(mac, localIP, subnet); - interfaceGMA3(gma3IP); - interfaceUDP(udp, gma3UdpPort); - interfaceTCP(tcp, gma3TcpPort); - } - -void loop() { - pageUp.update(); - pageDown.update(); - } \ No newline at end of file diff --git a/examples/gma3_STM32/gma3_STM32.ino b/examples/gma3_STM32/gma3_STM32.ino index e4b56e4..2e20fe9 100755 --- a/examples/gma3_STM32/gma3_STM32.ino +++ b/examples/gma3_STM32/gma3_STM32.ino @@ -1,61 +1,84 @@ +// Example for STM32 Nucleo boards with built-in ethernet + #include #include #include -#include "OSCMessage.h" #include "gma3.h" -// network data -#define GMA3_UDP_PORT 8000 // UDP Port configured in gma3 -#define GMA3_TCP_PORT 9000 // UDP Port configured in gma3 +// I/O config +#define BTN_KEY_1 2 +#define BTN_KEY_2 3 +#define BTN_KEY_3 4 +#define BTN_KEY_4 5 +#define ENC_1_A 6 +#define ENC_1_B 7 +#define ENC_2_A 8 +#define ENC_2_B 9 +#define BTN_CMD 10 +#define FADER A0 + +// Network config +#define GMA3_UDP_PORT 8000 // UDP Port configured in gma3 +#define GMA3_TCP_PORT 9000 // UDP Port configured in gma3 -IPAddress localIP(10, 101, 1, 201); // IP address of the microcontroller board -IPAddress subnet(255, 255, 0, 0); // subnet range +uint8_t mac[] = {0x90, 0xA2, 0xDA, 0x10, 0x14, 0x48}; +IPAddress localIp(10, 101, 1, 201); // IP address of the microcontroller board +IPAddress subnet(255, 255, 0, 0); // optional subnet range +IPAddress dns(10, 101, 1, 100); // optional DNS address of your device +IPAddress gateway(10, 101, 1, 100); // optional Gateway address of your device +uint16_t localUdpPort = GMA3_UDP_PORT; IPAddress gma3IP(10, 101, 1, 100); // IP address of the gma3 console uint16_t gma3UdpPort = GMA3_UDP_PORT; uint16_t gma3TcpPort = GMA3_TCP_PORT; -EthernetUDP udp; -EthernetUDP udpQLab; -EthernetClient tcp; -EthernetClient tcpQLab; +// EthernetUDP udp; // for UDP +EthernetClient tcp; // for TCP + +// functions prototypes +void parse(); // hardware definitions +Key key101(BTN_KEY_1, 101); Fader fader201(FADER, 201); -Key key201(BTN_KEY, 201, TCP); +Key key201(BTN_KEY_2, 201); +Key key301(BTN_KEY_3, 301); ExecutorKnob enc301(ENC_1_A, ENC_1_B, 301); -CmdButton macro1(BTN_CMD, "GO+ Macro 1", TCP); - -// use of generic OSC button -#define QLAB_GO_PIN 6 -IPAddress qlabIP(10, 101, 1, 100); // IP of QLab -uint16_t qlabPort = 53000; // QLab receive port -OscButton qlabGo(QLAB_GO_PIN , "/go", TCPSLIP); +Key key401(BTN_KEY_4, 401); +ExecutorKnob enc401(ENC_2_A, ENC_2_B, 301); +CmdButton macro1(BTN_CMD, "GO+ Macro 1"); +Parser parser(parse); void setup() { - Ethernet.begin(localIP, subnet); - interfaceGMA3(gma3IP); - interfaceUDP(udp, gma3UdpPort); - interfaceTCP(tcp, gma3TcpPort); - interfaceExternUDP(udpQLab, qlabIP, qlabPort); - interfaceExternTCP(tcpQLab, qlabIP, qlabPort); + Serial.begin(9600); + Ethernet.begin(localIp); + //interface(udp, gma3IP, gma3UdpPort); // for UDP + interface(tcp, TCP, gma3IP, gma3TcpPort); // for TCP } void loop() { + key101.update(); key201.update(); + key301.update(); + key401.update(); fader201.update(); enc301.update(); + enc401.update(); macro1.update(); - qlabGo.update(); - if (receiveUDP()) { - Serial.print("OSC Pattern: "); - Serial.print(patternOSC()); - Serial.print(" String: "); - Serial.print(stringOSC()); - Serial.print(" Integer 1: "); - Serial.print(int1OSC()); - Serial.print(" Integer 2: "); - Serial.print(int2OSC()); - Serial.print(" Float: "); - Serial.println(floatOSC()); - } + parser.update(); } + +void parse() { + Serial.print("OSC Message at "); + Serial.print(millis()); + Serial.print("ms Pattern: "); + Serial.print(parser.patternOSC()); + Serial.print(" String: "); + Serial.print(parser.stringOSC()); + Serial.print(" Integer 1: "); + Serial.print(parser.int1OSC()); + Serial.print(" Integer 2: "); + Serial.print(parser.int2OSC()); + Serial.print(" Float: "); + Serial.println(parser.floatOSC()); + } + diff --git a/examples/gma3_Teensy41/gma3_Teensy41.ino b/examples/gma3_Teensy41/gma3_Teensy41.ino index 6a22795..5ce41e9 100644 --- a/examples/gma3_Teensy41/gma3_Teensy41.ino +++ b/examples/gma3_Teensy41/gma3_Teensy41.ino @@ -1,63 +1,88 @@ +// Example for Teensy 4.1 with built-in Ethernet, use the TeensyID library for MAC address + #include -#include -#include +#include // for NativeEthernet library https://github.com/vjmuzik/NativeEthernet +#include // +//#include // for QNEthernet library https://github.com/ssilverman/QNEthernet #include "gma3.h" -// network data -uint8_t mac[6]; -#define GMA3_UDP_PORT 8000 // UDP Port configured in gma3 -#define GMA3_TCP_PORT 9000 // UDP Port configured in gma3 +// I/O config +#define BTN_KEY_1 2 +#define BTN_KEY_2 3 +#define BTN_KEY_3 4 +#define BTN_KEY_4 5 +#define ENC_1_A 6 +#define ENC_1_B 7 +#define ENC_2_A 8 +#define ENC_2_B 9 +#define BTN_CMD 10 +#define FADER A0 -IPAddress localIP(10, 101, 1, 201); // IP address of the microcontroller board -IPAddress subnet(255, 255, 0, 0); // subnet range +// Network config +#define GMA3_UDP_PORT 8000 // UDP Port configured in gma3 +#define GMA3_TCP_PORT 9000 // UDP Port configured in gma3 + +uint8_t mac[] = {0x90, 0xA2, 0xDA, 0x10, 0x14, 0x48}; +IPAddress localIp(10, 101, 1, 201); // IP address of the microcontroller board +IPAddress subnet(255, 255, 0, 0); // optional subnet range +IPAddress dns(10, 101, 1, 100); // optional DNS address of your device +IPAddress gateway(10, 101, 1, 100); // optional Gateway address of your device +uint16_t localUdpPort = GMA3_UDP_PORT; IPAddress gma3IP(10, 101, 1, 100); // IP address of the gma3 console uint16_t gma3UdpPort = GMA3_UDP_PORT; uint16_t gma3TcpPort = GMA3_TCP_PORT; -EthernetUDP udp; -EthernetUDP udpQLab; -EthernetClient tcp; -EthernetClient tcpQLab; +uint8_t mac[6]; + +// EthernetUDP udp; // for UDP +EthernetClient tcp; // for TCP + +// functions prototypes +void parse(); // hardware definitions +Key key101(BTN_KEY_1, 101); Fader fader201(FADER, 201); -Key key201(BTN_KEY, 201, TCP); +Key key201(BTN_KEY_2, 201); +Key key301(BTN_KEY_3, 301); ExecutorKnob enc301(ENC_1_A, ENC_1_B, 301); -CmdButton macro1(BTN_CMD, "GO+ Macro 1", TCP); +Key key401(BTN_KEY_4, 401); +ExecutorKnob enc401(ENC_2_A, ENC_2_B, 301); +CmdButton macro1(BTN_CMD, "GO+ Macro 1"); +Parser parser(parse); -// use of generic OSC button -#define QLAB_GO_PIN 6 -IPAddress qlabIP(10, 101, 1, 100); // IP of QLab -uint16_t qlabPort = 53000; // QLab receive port -OscButton qlabGo(QLAB_GO_PIN , "/go", TCPSLIP); void setup() { Serial.begin(9600); teensyMAC(mac); Ethernet.begin(mac, localIP, subnet); - interfaceGMA3(gma3IP); - interfaceUDP(udp, gma3UdpPort); - interfaceTCP(tcp, gma3TcpPort); - interfaceExternUDP(udpQLab, qlabIP, qlabPort); - interfaceExternTCP(tcpQLab, qlabIP, qlabPort); + //interface(udp, gma3IP, gma3UdpPort); // for UDP + interface(tcp, TCP, gma3IP, gma3TcpPort); // for TCP } void loop() { + key101.update(); key201.update(); + key301.update(); + key401.update(); fader201.update(); enc301.update(); + enc401.update(); macro1.update(); - qlabGo.update(); - if (receiveUDP()) { - Serial.print("OSC Pattern: "); - Serial.print(patternOSC()); - Serial.print(" String: "); - Serial.print(stringOSC()); - Serial.print(" Integer 1: "); - Serial.print(int1OSC()); - Serial.print(" Integer 2: "); - Serial.print(int2OSC()); - Serial.print(" Float: "); - Serial.println(floatOSC()); - } + parser.update(); + } + +void parse() { + Serial.print("OSC Message at "); + Serial.print(millis()); + Serial.print("ms Pattern: "); + Serial.print(parser.patternOSC()); + Serial.print(" String: "); + Serial.print(parser.stringOSC()); + Serial.print(" Integer 1: "); + Serial.print(parser.int1OSC()); + Serial.print(" Integer 2: "); + Serial.print(parser.int2OSC()); + Serial.print(" Float: "); + Serial.println(parser.floatOSC()); } diff --git a/images/gma3_osc_setup.png b/images/gma3_osc_setup.png index 12718e7..b4686b8 100644 Binary files a/images/gma3_osc_setup.png and b/images/gma3_osc_setup.png differ diff --git a/keywords.txt b/keywords.txt index da1f284..202f329 100755 --- a/keywords.txt +++ b/keywords.txt @@ -4,37 +4,41 @@ Fader KEYWORD1 ExecutorKnob KEYWORD1 CmdButton KEYWORD1 OscButton KEYWORD1 -Button KEYWORD1 +Parser KEYWORD1 +Pools KEYWORD1 +Pages KEYWORD1 # gma3 Class mebers +pool KEYWORD2 page KEYWORD2 value KEYWORD2 fetch KEYWORD2 jitter KEYWORD2 lock KEYWORD2 +dataStructure KEYWORD2 +patternOSC KEYWORD2 +stringOSC KEYWORD2 +int1OSC KEYWORD2 +int2OSC KEYWORD2 +floatOSC KEYWORD2 update KEYWORD2 # gma3 functions -interfaceGMA3 KEYWORD2 -interfaceUDP KEYWORD2 -interfaceTCP KEYWORD2 -interfaceExternUDP KEYWORD2 -interfaceExternTCP KEYWORD2 +prefixName KEYWORD2 +dataPoolName KEYWORD2 +pageName KEYWORD2 +keyName KEYWORD2 +FaderName KEYWORD2 +executorKnobName KEYWORD2 +interface KEYWORD2 sendUDP KEYWORD2 -sendExternUDP KEYWORD2 receiveUDP KEYWORD2 sendTCP KEYWORD2 -sendExternTCP KEYWORD2 -page KEYWORD2 +receiveTCP KEYWORD2 +globalPool KEYWORD2 +globalPage KEYWORD2 command KEYWORD2 -parseOSC KEYWORD2 -patternOSC KEYWORD2 -stringOSC KEYWORD2 -int1OSC KEYWORD2 -int2OSC KEYWORD2 -floatOSC KEYWORD2 oscMessage KEYWORD2 -slipEncode KEYWORD2 htof KEYWORD2 ftoh KEYWORD2 htoi KEYWORD2 @@ -48,12 +52,6 @@ FORWARD LITERAL1 REVERSE LITERAL1 FADER_UPDATE_RATE_MS LITERAL1 FADER_THRESHOLD LITERAL1 -PREFIX LITERAL1 -PREFIX_PATTERN LITERAL1 -PAGE LITERAL1 -FADER LITERAL1 -KEY LITERAL1 -EXECUTOR_KNOB LITERAL1 END LITERAL1 ESC LITERAL1 ESC_END LITERAL1 diff --git a/library.properties b/library.properties index 90fdc8d..c72bcd5 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=gma3 -version=3.0.2 +version=4.0.0 author=Stefan Staub maintainer=Stefan Staub sentence=GrandMA3 library for OSC diff --git a/src/gma3.cpp b/src/gma3.cpp index 5d51af3..6b3265b 100644 --- a/src/gma3.cpp +++ b/src/gma3.cpp @@ -1,162 +1,193 @@ #include "gma3.h" // internal structs -struct Message oscIn, oscOut; -struct OSC osc; +struct Message receiveMessage, sendMessage; -// network IP addresses +// network IP address IPAddress ipGma3; -IPAddress ipExternUdp; -IPAddress ipExternTcp; // network sockets UDP *udpGma3; -UDP *udpExtern; Client *tcpGma3; -Client *tcpExtern; // network ports uint16_t portUdpGma3; uint16_t portTcpGma3; -uint16_t portExternUdp; -uint16_t portExternTcp; -uint16_t pageGlobal = 1; +// global variables +uint16_t pageCommon = 1; +uint16_t poolCommon = 1; +char namePrefix[NAME_LENGTH_MAX] = "gma3"; +char namePrefixSearch[NAME_LENGTH_MAX] = "/gma3/"; +char namePool[NAME_LENGTH_MAX] = "DataPool"; // Page name +char namePage[NAME_LENGTH_MAX] = "Page"; // Page name +char nameFader[NAME_LENGTH_MAX] = "Fader"; // Fader name +char nameExecutorKnob[NAME_LENGTH_MAX] = "Encoder"; // ExecutorKnob name +char nameKey[NAME_LENGTH_MAX] = "Key"; // Key name + +void prefixName(const char *prefix) { + memset(namePrefix, 0, NAME_LENGTH_MAX); + strcpy(namePrefix, prefix); + memset(namePrefixSearch, 0, NAME_LENGTH_MAX); + if (strlen(prefix) != 0) { + strcpy(namePrefixSearch, "/"); + strcat(namePrefixSearch, prefix); + strcat(namePrefixSearch, "/"); + } + } -void interfaceGMA3(IPAddress ip) { - ipGma3 = ip; +void dataPoolName(const char *pool) { + memset(namePool, 0, NAME_LENGTH_MAX); + strcpy(namePool, pool); + } + +void pageName(const char *page) { + memset(namePage, 0, NAME_LENGTH_MAX); + strcpy(namePage, page); } -void interfaceUDP(UDP &udp, uint16_t port) { +void faderName(const char *fader) { + memset(nameFader, 0, NAME_LENGTH_MAX); + strcpy(nameFader, fader); + } + +void executorKnobName(const char *executorKnob) { + memset(nameExecutorKnob, 0, NAME_LENGTH_MAX); + strcpy(nameExecutorKnob, executorKnob); + } + +void keyName(const char *key) { + memset(nameKey, 0, NAME_LENGTH_MAX); + strcpy(nameKey, key); + } + +void interface(UDP &udp, IPAddress ip, uint16_t port) { + ipGma3 = ip; udpGma3 = &udp; portUdpGma3 = port; + sendMessage.protocol = UDPOSC; + receiveMessage.protocol = UDPOSC; udpGma3->begin(port); } -void interfaceTCP(Client &tcp, uint16_t port) { +void interface(Client &tcp, protocol_t protocol, IPAddress ip, uint16_t port) { + ipGma3 = ip; tcpGma3 = &tcp; portTcpGma3 = port; + sendMessage.protocol = TCP; + receiveMessage.protocol = TCP; tcpGma3->connect(ipGma3, port); } -void interfaceExternUDP(UDP &udp, IPAddress ip, uint16_t port) { - udpExtern = &udp; - ipExternUdp = ip; - portExternUdp = port; +void sendOSC() { + switch (sendMessage.protocol) { + case UDPOSC: + udpGma3->beginPacket(ipGma3, portUdpGma3); + udpGma3->write(sendMessage.message, sendMessage.size); + udpGma3->endPacket(); + break; + case TCP: + if (!tcpGma3->connected()) tcpGma3->connect(ipGma3, portTcpGma3); + tcpGma3->write(sendMessage.message, sendMessage.size); + break; + } } -void interfaceExternTCP(Client &tcp, IPAddress ip, uint16_t port) { - tcpExtern = &tcp; - ipExternTcp = ip; - portExternTcp = port; - tcpExtern->connect(ip, port); +void command(const char cmd[]) { + char pattern[OSC_PATTERN_SIZE]; + memset(pattern, 0, sizeof(pattern)); + pattern[0] = '/'; + if (strlen(namePrefix) != 0) { + strcat(pattern, namePrefix); + pattern[strlen(pattern)] = '/'; + } + strcat(pattern, "cmd"); + oscMessage(pattern, cmd); } -void sendUDP() { - udpGma3->beginPacket(ipGma3 ,portUdpGma3); - udpGma3->write(oscOut.message, oscOut.size); - udpGma3->endPacket(); +uint16_t commonPool() { + return poolCommon; } -void sendExternUDP() { - udpExtern->beginPacket(ipExternUdp ,portExternUdp); - udpExtern->write(oscOut.message, oscOut.size); - udpExtern->endPacket(); +void commonPool(uint16_t pool) { + poolCommon = pool; } -bool receiveUDP() { - size_t size = udpGma3->parsePacket(); - if (size > 0) { - oscIn.size = size; - memset(oscIn.message, 0, OSC_MESSAGE_SIZE); - if (size <= sizeof(oscIn.message)) { - udpGma3->read(oscIn.message, size); - parseOSC(oscIn.message); - oscIn.update = true; - return true; - } - } - return false; +uint16_t commonPage() { + return pageCommon; } -void sendTCP() { - if (!tcpGma3->connected()) { - tcpGma3->connect(ipGma3, portTcpGma3); - } - tcpGma3->write(oscOut.message, oscOut.size); +void commonPage(uint16_t page) { + pageCommon = page; } -void sendExternTCP() { - if (!tcpExtern->connected()) { - tcpExtern->connect(ipExternTcp, portExternTcp); - } - tcpExtern->write(oscOut.message, oscOut.size); +Parser::Parser(cbptr callback) { + this->callback = callback; } -void sendOSC() { - switch (oscOut.protocol) { - case UDPOSC: - sendUDP(); - break; - case TCP: - sendTCP(); - break; - case TCPSLIP: - sendTCP(); - break; - } +const char* Parser::patternOSC() { + return receiveData.pattern + strlen(namePrefixSearch); } -void sendExternOSC() { - switch (oscOut.protocol) { - case UDPOSC: - sendExternUDP(); - break; - case TCP: - sendExternTCP(); - break; - case TCPSLIP: - sendExternTCP(); - break; - } +int Parser::dataStructure(uint8_t level) { + if (level < 5) return dataValue[level]; + return 0; } -void command(const char cmd[], protocol_t protocol) { - char pattern[OSC_PATTERN_SIZE]; - memset(pattern, 0, sizeof(pattern)); - pattern[0] = '/'; - if (strlen(PREFIX) != 0) { - strcat(pattern, PREFIX); - pattern[strlen(pattern)] = '/'; +const char* Parser::stringOSC() { + return receiveData.string; + } + +int32_t Parser::int1OSC() { + return receiveData.int32[0]; + } + +int32_t Parser::int2OSC() { + return receiveData.int32[1]; + } + +float Parser::floatOSC() { + return receiveData.float32; + } + +void Parser::update() { + if(receiveMessage.protocol == UDPOSC) { + if(receiveUDP()) { + if (callback != nullptr) callback(); + return; + } + } + if(receiveMessage.protocol == TCP) { + if(receiveTCP()) { + if (callback != nullptr) callback(); + } } - strcat(pattern, "cmd"); - oscMessage(pattern, cmd, protocol); - sendOSC(); } -void parseOSC(uint8_t *msg) { - memset(osc.pattern, 0, sizeof(osc.pattern)); - memset(osc.tag, 0, sizeof(osc.tag)); - memset(osc.string, 0, sizeof(osc.string)); // what happens with to string - *osc.int32 = 0; - osc.float32 = 0.0f; +void Parser::parseOSC() { + memset(receiveData.pattern, 0, sizeof(receiveData.pattern)); + memset(receiveData.tag, 0, sizeof(receiveData.tag)); + memset(receiveData.string, 0, sizeof(receiveData.string)); // what happens with to string + *receiveData.int32 = 0; + receiveData.float32 = 0.0f; int dataStart; - strncpy(osc.pattern, (char*)msg, sizeof(osc.pattern) - 1); - int patternSize = strlen(osc.pattern); + strncpy(receiveData.pattern, (char*)receiveMessage.message, sizeof(receiveData.pattern) - 1); + sscanf(receiveData.pattern + strlen(namePrefixSearch), "%d.%d.%d.%d.%d", &dataValue[0], &dataValue[1], &dataValue[2], &dataValue[3], &dataValue[4]); + int patternSize = strlen(receiveData.pattern); int patternOffset = patternSize % 4; int tagStart; if (patternOffset == 0) tagStart = patternSize + 4; else tagStart = patternSize + (4 - patternOffset); - strncpy(osc.tag, (char*)msg + tagStart, sizeof(osc.tag) - 1); - int tagSize = strlen(osc.tag); // including ',' + strncpy(receiveData.tag, (char*)receiveMessage.message + tagStart, sizeof(receiveData.tag) - 1); + int tagSize = strlen(receiveData.tag); // including ',' int tagOffset = tagSize % 4; if (tagOffset == 0) dataStart = tagSize + 4 + tagStart; else dataStart = tagSize + (4 - tagOffset) + tagStart; - if (osc.tag[1] != 0) { - if (osc.tag[1] == 's') { - strncpy(osc.string, (char*)msg + dataStart, sizeof(osc.string) - 1); - int stringSize = strlen(osc.string); + if (receiveData.tag[1] != 0) { + if (receiveData.tag[1] == 's') { + strncpy(receiveData.string, (char*)receiveMessage.message + dataStart, sizeof(receiveData.string) - 1); + int stringSize = strlen(receiveData.string); int stringOffset = stringSize % 4; if (stringOffset == 0) dataStart = dataStart + stringSize + 4; else dataStart = dataStart + stringSize + (4 - stringOffset); @@ -164,79 +195,282 @@ void parseOSC(uint8_t *msg) { } else return; - if (osc.tag[2] != 0) { - if (osc.tag[2] == 'i') { - osc.int32[0] = htoi(msg, dataStart); + if (receiveData.tag[2] != 0) { + if (receiveData.tag[2] == 'i') { + receiveData.int32[0] = htoi(receiveMessage.message, dataStart); dataStart = dataStart + 4; } } else return; - if (osc.tag[3] != 0) { - if (osc.tag[3] == 'i') { - osc.int32[1] = htoi(msg, dataStart); + if (receiveData.tag[3] != 0) { + if (receiveData.tag[3] == 'i') { + receiveData.int32[1] = htoi(receiveMessage.message, dataStart); dataStart = dataStart + 4; } - else if (osc.tag[3] == 'f') { - osc.float32 = htof(msg, dataStart); + else if (receiveData.tag[3] == 'f') { + receiveData.float32 = htof(receiveMessage.message, dataStart); dataStart = dataStart + 4; } } } -const char* patternOSC() { - return osc.pattern; +bool Parser::receiveUDP() { + size_t size = udpGma3->parsePacket(); + if (size > 0) { + receiveMessage.size = size; + memset(receiveMessage.message, 0, OSC_MESSAGE_SIZE); + if (size <= sizeof(receiveMessage.message)) { + udpGma3->read(receiveMessage.message, size); + if (strlen(namePrefix) != 0) { + if (memcmp(receiveMessage.message, namePrefixSearch, strlen(namePrefixSearch)) != 0) return false; + } + parseOSC(); + return true; + } + } + return false; } -const char* stringOSC() { - return osc.string; +bool Parser::receiveTCP() { + size_t size = tcpGma3->available(); + if (size > 0) { + receiveMessage.size = size; + memset(receiveMessage.message, 0, OSC_MESSAGE_SIZE); + if (size <= sizeof(receiveMessage.message)) { + tcpGma3->read(receiveMessage.message, size); + if (strlen(namePrefix) != 0) { + if (memcmp(receiveMessage.message, namePrefixSearch, strlen(namePrefixSearch)) != 0) return false; + } + parseOSC(); + return true; + } + } + return false; } -int32_t int1OSC() { - return osc.int32[0]; +Pools::Pools(uint8_t pinUp, uint8_t pinDown, uint8_t poolsStart, uint8_t poolsEnd, send_t mode, cbptr callback) { + this->pinUp = pinUp; + pinMode(pinUp, INPUT_PULLUP); + pinUpLast = digitalRead(pinUp); + this->pinDown = pinDown; + pinMode(pinDown, INPUT_PULLUP); + pinDownLast = digitalRead(pinDown); + this->poolsStart = poolsStart; + this->poolsEnd = poolsEnd; + this->callback = callback; + this->mode = mode; + poolNumber = poolsStart; + poolCommon = poolsStart; } -int32_t int2OSC() { - return osc.int32[1]; +Pools::Pools(uint8_t poolsStart, uint8_t poolsEnd, send_t mode, cbptr callback) { + this->poolsStart = poolsStart; + this->poolsEnd = poolsEnd; + this->callback = callback; + this->mode = mode; + poolNumber = poolsStart; + poolCommon = poolsStart; } -float floatOSC() { - return osc.float32; +uint16_t Pools::currentPool() { + return poolCommon; } -void page(uint16_t page) { - pageGlobal = page; +uint16_t Pools::lastPool() { + return poolLast; } -Button::Button(uint8_t pin, cbptr callback) { - this->pin = pin; - pinMode(pin, INPUT_PULLUP); - pinLast = digitalRead(pin); +void Pools::update() { + if (digitalRead(pinUp) != pinUpLast) { + if (pinUpLast == false) { + pinUpLast = true; // button release + } + else { // button press + pinUpLast = false; + poolLast = poolNumber; + if (poolNumber >= poolsEnd) poolNumber = poolsStart; // rollover to first page + else poolNumber++; + if(mode == GLOBAL || mode == CONSOLE) sendPool(poolNumber); + poolCommon = poolNumber; + if (callback != nullptr) callback(); // execute callback + } + return; + } + if (digitalRead(pinDown) != pinDownLast) { + if (pinDownLast == false) { + pinDownLast = true; // button release + } + else { // button press + pinDownLast = false; + poolLast = poolNumber; + if (poolNumber <= poolsStart) poolNumber = poolsEnd; // rollover to last page + else poolNumber--; + if(mode == GLOBAL || mode == CONSOLE) sendPool(poolNumber); + poolCommon = poolNumber; + if (callback != nullptr) callback(); // execute callback + } + return; + } + } + +void Pools::update(bool stateUp, bool stateDown) { + if (stateUp != pinUpLast) { + if (pinUpLast == false) { + pinUpLast = true; // button press + poolLast = poolNumber; + if (poolNumber >= poolsEnd) poolNumber = poolsStart; // rollover to first page + else poolNumber++; + if(mode == GLOBAL || mode == CONSOLE) sendPool(poolNumber); + poolCommon = poolNumber; + if (callback != nullptr) callback(); // execute callback + } + else { // button release + pinUpLast = false; + } + return; + } + if (stateDown != pinDownLast) { + if (pinDownLast == false) { + pinDownLast = true; // button press + poolLast = poolNumber; + if (poolNumber <= poolsStart) poolNumber = poolsEnd; // rollover to last page + else poolNumber--; + if(mode == GLOBAL || mode == CONSOLE) sendPool(poolNumber); + poolCommon = poolNumber; + if (callback != nullptr) callback(); // execute callback + } + else { // button release + pinDownLast = false; + } + return; + } + } + +void Pools::sendPool(uint16_t pool) { + char cmd[12] = "dataPool "; + strcat(cmd, itoa(pool)); + command(cmd); + } + +Pages::Pages(uint8_t pinUp, uint8_t pinDown, uint8_t pagesStart, uint8_t pagesEnd, send_t mode, cbptr callback) { + this->pinUp = pinUp; + pinMode(pinUp, INPUT_PULLUP); + pinUpLast = digitalRead(pinUp); + this->pinDown = pinDown; + pinMode(pinDown, INPUT_PULLUP); + pinDownLast = digitalRead(pinDown); + this->pagesStart = pagesStart; + this->pagesEnd = pagesEnd; + this->mode = mode; + this->callback = callback; + pageLast = pagesStart; + pageCommon = pagesStart; + } + +Pages::Pages(uint8_t pagesStart, uint8_t pagesEnd, send_t mode, cbptr callback) { + this->pagesStart = pagesStart; + this->pagesEnd = pagesEnd; + this->mode = mode; this->callback = callback; + pageLast = pagesStart; + pageCommon = pagesStart; } -void Button::update() { - if (digitalRead(pin) != pinLast) { - if (pinLast == false) { - pinLast = true; // button release +uint16_t Pages::currentPage() { + return pageCommon; + } + +uint16_t Pages::lastPage() { + return pageLast; + } + +void Pages::update() { + if (digitalRead(pinUp) != pinUpLast) { + if (pinUpLast == false) { + pinUpLast = true; // button release + } + else { // button press + pinUpLast = false; + pageLast = pageNumber; + if (pageNumber >= pagesEnd) pageNumber = pagesStart; // rollover to first page + else pageNumber++; + if(mode == GLOBAL || mode == CONSOLE) sendPage(pageNumber); + pageCommon = pageNumber; + if (callback != nullptr) callback(); // execute callback + } + return; + } + if (digitalRead(pinDown) != pinDownLast) { + if (pinDownLast == false) { + pinDownLast = true; // button release } else { // button press - pinLast = false; + pinDownLast = false; + pageLast = pageNumber; + if (pageNumber <= pagesStart) pageNumber = pagesEnd; // rollover to last page + else pageNumber--; + if(mode == GLOBAL || mode == CONSOLE) sendPage(pageNumber); + pageCommon = pageNumber; if (callback != nullptr) callback(); // execute callback } return; } } -Key::Key(uint8_t pin, uint16_t key, protocol_t protocol) { +void Pages::update(bool stateUp, bool stateDown) { + if (stateUp != pinUpLast) { + if (pinUpLast == false) { + pinUpLast = true; // button press + pageLast = pageNumber; + if (pageNumber >= pagesEnd) pageNumber = pagesStart; // rollover to first page + else pageNumber++; + if(mode == GLOBAL || mode == CONSOLE) sendPage(pageNumber); + pageCommon = pageNumber; + if (callback != nullptr) callback(); // execute callback + } + else { // button release + pinUpLast = false; + } + return; + } + if (stateDown != pinDownLast) { + if (pinDownLast == false) { + pinDownLast = true; // button press + pageLast = pageNumber; + if (pageNumber <= pagesStart) pageNumber = pagesEnd; // rollover to last page + else pageNumber--; + if(mode == GLOBAL || mode == CONSOLE) sendPage(pageNumber); + pageCommon = pageNumber; + if (callback != nullptr) callback(); // execute callback + } + else { // button release + pinDownLast = false; + } + return; + } + } + +void Pages::sendPage(uint16_t page) { + char cmd[12] = "Page "; + strcat(cmd, itoa(page)); + command(cmd); + } + +Key::Key(uint8_t pin, uint16_t key) { this->pin = pin; pinMode(pin, INPUT_PULLUP); - last = digitalRead(pin); + last = HIGH; this->key = key; - this->protocol = protocol; } -Key::~Key() {} +Key::Key(uint16_t key) { + this->key = key; + } + +void Key::pool(uint16_t poolLocal) { + this->poolLocal = poolLocal; + } void Key::page(uint16_t pageLocal) { this->pageLocal = pageLocal; @@ -247,37 +481,85 @@ void Key::update() { char pattern[OSC_PATTERN_SIZE]; memset(pattern, 0, sizeof(pattern)); pattern[0] = '/'; - if (strlen(PREFIX) != 0) { - strcat(pattern, PREFIX); + if (strlen(namePrefix)) { + strcat(pattern, namePrefix); pattern[strlen(pattern)] = '/'; } - strcat(pattern, PAGE); - if (pageLocal > 0) strcat(pattern, itoa(pageLocal)); - else strcat(pattern, itoa(pageGlobal)); - pattern[strlen(pattern)] = '/'; - strcat(pattern, KEY); + if(strlen(namePool)) { + strcat(pattern, namePool); + if (poolLocal > 0) strcat(pattern, itoa(poolLocal)); + else strcat(pattern, itoa(poolCommon)); + pattern[strlen(pattern)] = '/'; + } + if(strlen(namePage)) { + strcat(pattern, namePage); + if (pageLocal > 0) strcat(pattern, itoa(pageLocal)); + else strcat(pattern, itoa(pageCommon)); + pattern[strlen(pattern)] = '/'; + } + strcat(pattern, nameKey); strcat(pattern, itoa(key)); if (last == LOW) { last = HIGH; - oscMessage(pattern, BUTTON_RELEASE, protocol); + oscMessage(pattern, BUTTON_RELEASE); } else { last = LOW; - oscMessage(pattern, BUTTON_PRESS, protocol); + oscMessage(pattern, BUTTON_PRESS); } - sendOSC(); } } -Fader::Fader(uint8_t analogPin, uint16_t fader, protocol_t protocol) { +void Key::update(bool state) { + if (state != last) { + char pattern[OSC_PATTERN_SIZE]; + memset(pattern, 0, sizeof(pattern)); + pattern[0] = '/'; + if (strlen(namePrefix)) { + strcat(pattern, namePrefix); + pattern[strlen(pattern)] = '/'; + } + if(strlen(namePool)) { + strcat(pattern, namePool); + if (poolLocal > 0) strcat(pattern, itoa(poolLocal)); + else strcat(pattern, itoa(poolCommon)); + pattern[strlen(pattern)] = '/'; + } + if(strlen(namePage)) { + strcat(pattern, namePage); + if (pageLocal > 0) strcat(pattern, itoa(pageLocal)); + else strcat(pattern, itoa(pageCommon)); + pattern[strlen(pattern)] = '/'; + } + strcat(pattern, nameKey); + strcat(pattern, itoa(key)); + if (last == LOW) { + last = HIGH; + oscMessage(pattern, BUTTON_PRESS); + } + else { + last = LOW; + oscMessage(pattern, BUTTON_RELEASE); + } + } + } + +Fader::Fader(uint8_t analogPin, uint16_t fader) { this->analogPin = analogPin; this->fader = fader; - this->protocol = protocol; - analogLast = 0xFFFF; // forces an osc output of the fader + analogLast = 0xFFFF; // forces an receiveData output of the fader updateTime = millis(); } -Fader::~Fader() {} +Fader::Fader(uint16_t fader) { + this->fader = fader; + analogLast = 0xFFFF; // forces an receiveData output of the fader + updateTime = millis(); + } + +void Fader::pool(uint16_t poolLocal) { + this->poolLocal = poolLocal; + } void Fader::page(uint16_t pageLocal) { this->pageLocal = pageLocal; @@ -306,11 +588,51 @@ void Fader::lock(bool state) { void Fader::update() { if ((updateTime + FADER_UPDATE_RATE_MS) < millis()) { - int16_t raw = analogRead(analogPin); - raw = constrain(raw, FADER_THRESHOLD * 2, 1015); // ignore jitter + int16_t raw = analogRead(analogPin) >> 2; + if (raw < (analogLast - FADER_THRESHOLD) || raw > (analogLast + FADER_THRESHOLD)) { + analogLast = raw; + int32_t value = map(analogLast, FADER_THRESHOLD, 255 - FADER_THRESHOLD, 0, 100); // convert to 0...100 + if (valueLast != value) { + valueLast = value; + if (lockState == true) { + if ((valueLast <= fetchValue + delta) && (valueLast >= fetchValue - delta)) lockState = false; + } + if (lockState == false) { + char pattern[OSC_PATTERN_SIZE]; + memset(pattern, 0, sizeof(pattern)); + pattern[0] = '/'; + if (strlen(namePrefix)) { + strcat(pattern, namePrefix); + pattern[strlen(pattern)] = '/'; + } + if(strlen(namePool)) { + strcat(pattern, namePool); + if (poolLocal > 0) strcat(pattern, itoa(poolLocal)); + else strcat(pattern, itoa(poolCommon)); + pattern[strlen(pattern)] = '/'; + } + if(strlen(namePage)) { + strcat(pattern, namePage); + if (pageLocal > 0) strcat(pattern, itoa(pageLocal)); + else strcat(pattern, itoa(pageCommon)); + pattern[strlen(pattern)] = '/'; + } + strcat(pattern, nameFader); + strcat(pattern, itoa(fader)); + oscMessage(pattern, value); + } + } + } + updateTime = millis(); + } + } + +void Fader::update(uint16_t analog) { + if ((updateTime + FADER_UPDATE_RATE_MS) < millis()) { + int16_t raw = analog >> 2; if (raw < (analogLast - FADER_THRESHOLD) || raw > (analogLast + FADER_THRESHOLD)) { analogLast = raw; - int32_t value = map(analogLast, 8, 1015, 0, 100); // convert to 0...100 + int32_t value = map(analogLast, FADER_THRESHOLD, 255 - FADER_THRESHOLD, 0, 100); // convert to 0...100 if (valueLast != value) { valueLast = value; if (lockState == true) { @@ -320,18 +642,25 @@ void Fader::update() { char pattern[OSC_PATTERN_SIZE]; memset(pattern, 0, sizeof(pattern)); pattern[0] = '/'; - if (strlen(PREFIX) != 0) { - strcat(pattern, PREFIX); + if (strlen(namePrefix)) { + strcat(pattern, namePrefix); + pattern[strlen(pattern)] = '/'; + } + if(strlen(namePool)) { + strcat(pattern, namePool); + if (poolLocal > 0) strcat(pattern, itoa(poolLocal)); + else strcat(pattern, itoa(poolCommon)); pattern[strlen(pattern)] = '/'; } - strcat(pattern, PAGE); - if (pageLocal > 0) strcat(pattern, itoa(pageLocal)); - else strcat(pattern, itoa(pageGlobal)); - pattern[strlen(pattern)] = '/'; - strcat(pattern, FADER); + if(strlen(namePage)) { + strcat(pattern, namePage); + if (pageLocal > 0) strcat(pattern, itoa(pageLocal)); + else strcat(pattern, itoa(pageCommon)); + pattern[strlen(pattern)] = '/'; + } + strcat(pattern, nameFader); strcat(pattern, itoa(fader)); - oscMessage(pattern, value, protocol); - sendOSC(); + oscMessage(pattern, value); } } } @@ -339,17 +668,23 @@ void Fader::update() { } } -ExecutorKnob::ExecutorKnob(uint8_t pinA, uint8_t pinB, uint16_t executorKnob, protocol_t protocol, uint8_t direction) { +ExecutorKnob::ExecutorKnob(uint8_t pinA, uint8_t pinB, uint16_t executorKnob, uint8_t direction) { this->pinA = pinA; this->pinB = pinB; - this->direction = direction; pinMode(pinA, INPUT_PULLUP); pinMode(pinB, INPUT_PULLUP); + this->direction = direction; this->executorKnob = executorKnob; - this->protocol = protocol; } -ExecutorKnob::~ExecutorKnob() {} +ExecutorKnob::ExecutorKnob(uint16_t executorKnob, uint8_t direction) { + this->direction = direction; + this->executorKnob = executorKnob; + } + +void ExecutorKnob::pool(uint16_t poolLocal) { + this->poolLocal = poolLocal; + } void ExecutorKnob::page(uint16_t pageLocal) { this->pageLocal = pageLocal; @@ -372,35 +707,77 @@ void ExecutorKnob::update() { char pattern[OSC_PATTERN_SIZE]; memset(pattern, 0, sizeof(pattern)); pattern[0] = '/'; - if (strlen(PREFIX) != 0) { - strcat(pattern, PREFIX); + if (strlen(namePrefix)) { + strcat(pattern, namePrefix); pattern[strlen(pattern)] = '/'; } - strcat(pattern, PAGE); - if (pageLocal > 0) strcat(pattern, itoa(pageLocal)); - else strcat(pattern, itoa(pageGlobal)); - pattern[strlen(pattern)] = '/'; - strcat(pattern, EXECUTOR_KNOB); + if(strlen(namePool)) { + strcat(pattern, namePool); + if (poolLocal > 0) strcat(pattern, itoa(poolLocal)); + else strcat(pattern, itoa(poolCommon)); + pattern[strlen(pattern)] = '/'; + } + if(strlen(namePage)) { + strcat(pattern, namePage); + if (pageLocal > 0) strcat(pattern, itoa(pageLocal)); + else strcat(pattern, itoa(pageCommon)); + pattern[strlen(pattern)] = '/'; + } + strcat(pattern, nameExecutorKnob); + strcat(pattern, itoa(executorKnob)); + oscMessage(pattern, (int32_t)encoderMotion); + } + } + +void ExecutorKnob::update(uint8_t stateA, uint8_t stateB) { + encoderMotion = 0; + pinACurrent = stateA; + if ((pinALast) && (!pinACurrent)) { + if (stateB) { + encoderMotion = - 1; + } + else { + encoderMotion = 1; + } + if (direction == REVERSE) encoderMotion = -encoderMotion; + } + pinALast = pinACurrent; + if (encoderMotion != 0) { + char pattern[OSC_PATTERN_SIZE]; + memset(pattern, 0, sizeof(pattern)); + pattern[0] = '/'; + if (strlen(namePrefix)) { + strcat(pattern, namePrefix); + pattern[strlen(pattern)] = '/'; + } + if(strlen(namePool)) { + strcat(pattern, namePool); + if (poolLocal > 0) strcat(pattern, itoa(poolLocal)); + else strcat(pattern, itoa(poolCommon)); + pattern[strlen(pattern)] = '/'; + } + if(strlen(namePage)) { + strcat(pattern, namePage); + if (pageLocal > 0) strcat(pattern, itoa(pageLocal)); + else strcat(pattern, itoa(pageCommon)); + pattern[strlen(pattern)] = '/'; + } + strcat(pattern, nameExecutorKnob); strcat(pattern, itoa(executorKnob)); - oscMessage(pattern, (int32_t)encoderMotion, protocol); - sendOSC(); + oscMessage(pattern, (int32_t)encoderMotion); } } -CmdButton::CmdButton(uint8_t pin, const char command[], protocol_t protocol) { +CmdButton::CmdButton(uint8_t pin, const char *command) { this->pin = pin; pinMode(pin, INPUT_PULLUP); - last = digitalRead(pin); - this->protocol = protocol; - if (strlen(PREFIX) != 0) { - strcat(pattern, PREFIX); - strcat(pattern, "/"); - } - strcat(pattern, "cmd"); + last = HIGH; strncpy(cmdString, command, OSC_STRING_SIZE - 1); } -CmdButton::~CmdButton() {} +CmdButton::CmdButton(const char *command) { + strncpy(cmdString, command, OSC_STRING_SIZE - 1); + } void CmdButton::update() { if ((digitalRead(pin)) != last) { @@ -409,229 +786,102 @@ void CmdButton::update() { } else { last = LOW; - oscMessage(pattern, cmdString, protocol); - sendOSC(); + char pattern[OSC_PATTERN_SIZE]; + memset(pattern, 0, sizeof(pattern)); + pattern[0] = '/'; + if (strlen(namePrefix)) { + strcat(pattern, namePrefix); + strcat(pattern, "/"); + } + strcat(pattern, "cmd"); + oscMessage(pattern, cmdString); } } } - -OscButton::OscButton(uint8_t pin, const char pattern[], int32_t integer32, protocol_t protocol) { - this->pin = pin; - this->integer32 = integer32; - this->protocol = protocol; - pinMode(pin, INPUT_PULLUP); - last = digitalRead(pin); - typ = INT32; - memset(patternString, 0, sizeof(patternString)); - strcpy(patternString, pattern); - } - -OscButton::OscButton(uint8_t pin, const char pattern[], float float32, protocol_t protocol) { - this->pin = pin; - this->float32 = float32; - this->protocol = protocol; - pinMode(pin, INPUT_PULLUP); - last = digitalRead(pin); - typ = FLOAT32; - memset(patternString, 0, sizeof(patternString)); - strcpy(patternString, pattern); - } - -OscButton::OscButton(uint8_t pin, const char pattern[], const char message [], protocol_t protocol) { - this->pin = pin; - this->protocol = protocol; - pinMode(pin, INPUT_PULLUP); - last = digitalRead(pin); - typ = STRING; - memset(patternString, 0, sizeof(patternString)); - strcpy(patternString, pattern); - memset(messageString, 0, sizeof(messageString)); - strcpy(messageString, message); - } - -OscButton::OscButton(uint8_t pin, const char pattern[], protocol_t protocol) { - this->pin = pin; - this->protocol = protocol; - pinMode(pin, INPUT_PULLUP); - last = digitalRead(pin); - typ = NODATA; - memset(patternString, 0, sizeof(patternString)); - strcpy(patternString, pattern); - } - -OscButton::~OscButton() {} - -void OscButton::update() { - if ((digitalRead(pin)) != last) { +void CmdButton::update(bool state) { + if (state != last) { if (last == LOW) { last = HIGH; - if (typ == INT32) { - oscMessage(patternString, (int32_t)0, protocol); - sendExternOSC(); - return; - } - if (typ == FLOAT32) { - oscMessage(patternString, 0.0f, protocol); - sendExternOSC(); - return; + char pattern[OSC_PATTERN_SIZE]; + memset(pattern, 0, sizeof(pattern)); + pattern[0] = '/'; + if (strlen(namePrefix)) { + strcat(pattern, namePrefix); + strcat(pattern, "/"); } + strcat(pattern, "cmd"); + oscMessage(pattern, cmdString); } else { last = LOW; - switch (typ) { - case INT32: - oscMessage(patternString, integer32, protocol); - break; - case FLOAT32: - oscMessage(patternString, float32, protocol); - break; - case STRING: - oscMessage(patternString, messageString, protocol); - break; - case NODATA: - oscMessage(patternString, protocol); - break; - } - sendExternOSC(); } - } + } } -void oscMessage(const char pattern[], const char string[], protocol_t protocol) { - memset(oscOut.message, 0, sizeof(oscOut.message)); - oscOut.size = 0; +void oscMessage(const char pattern[], const char string[]) { + memset(sendMessage.message, 0, sizeof(sendMessage.message)); + sendMessage.size = 0; int patternLength = strlen(pattern); int stringLength = strlen(string); - memcpy(oscOut.message, pattern, patternLength); + memcpy(sendMessage.message, pattern, patternLength); int patternOffset = patternLength % 4; int tagStart; if (patternOffset == 0) tagStart = patternLength + 4; else tagStart = patternLength + (4 - patternOffset); - memcpy(oscOut.message + tagStart, ",s\0\0", 4); + memcpy(sendMessage.message + tagStart, ",s\0\0", 4); int stringStart = tagStart + 4; - memcpy(oscOut.message + stringStart, string, stringLength); + memcpy(sendMessage.message + stringStart, string, stringLength); int stringOffset = stringLength % 4; - if (stringOffset == 0) oscOut.size = stringStart + stringLength + 4; - else oscOut.size = stringStart + stringLength + (4 - stringOffset); - switch (protocol) { - case UDPOSC: - oscOut.protocol = UDPOSC; - break; - case TCP: - oscOut.protocol = TCP; - break; - case TCPSLIP: - slipEncode(); - oscOut.protocol = TCPSLIP; - break; - } + if (stringOffset == 0) sendMessage.size = stringStart + stringLength + 4; + else sendMessage.size = stringStart + stringLength + (4 - stringOffset); + sendOSC(); } -void oscMessage(const char pattern[], float float32, protocol_t protocol) { - memset(oscOut.message, 0, sizeof(oscOut.message)); - oscOut.size = 0; +void oscMessage(const char pattern[], float float32) { + memset(sendMessage.message, 0, sizeof(sendMessage.message)); + sendMessage.size = 0; int patternLength = strlen(pattern); - memcpy(oscOut.message, pattern, patternLength); + memcpy(sendMessage.message, pattern, patternLength); int patternOffset = patternLength % 4; int tagStart; if (patternOffset == 0) tagStart = patternLength + 4; else tagStart = patternLength + (4 - patternOffset); - memcpy(oscOut.message + tagStart, ",f\0\0", 4); + memcpy(sendMessage.message + tagStart, ",f\0\0", 4); int dataStart = tagStart + 4; - ftoh(oscOut.message, dataStart, float32); - oscOut.size = dataStart + 4; - switch (protocol) { - case UDPOSC: - oscOut.protocol = UDPOSC; - break; - case TCP: - oscOut.protocol = TCP; - break; - case TCPSLIP: - slipEncode(); - oscOut.protocol = TCPSLIP; - break; - } + ftoh(sendMessage.message, dataStart, float32); + sendMessage.size = dataStart + 4; + sendOSC(); } -void oscMessage(const char pattern[], int32_t int32, protocol_t protocol) { - memset(oscOut.message, 0, sizeof(oscOut.message)); - oscOut.size = 0; +void oscMessage(const char pattern[], int32_t int32) { + memset(sendMessage.message, 0, sizeof(sendMessage.message)); + sendMessage.size = 0; int patternLength = strlen(pattern); - memcpy(oscOut.message, pattern, patternLength); + memcpy(sendMessage.message, pattern, patternLength); int patternOffset = patternLength % 4; int tagStart; if (patternOffset == 0) tagStart = patternLength + 4; else tagStart = patternLength + (4 - patternOffset); - memcpy(oscOut.message + tagStart, ",i\0\0", 4); + memcpy(sendMessage.message + tagStart, ",i\0\0", 4); int dataStart = tagStart + 4; - itoh(oscOut.message, dataStart, int32); - oscOut.size = dataStart + 4; - switch (protocol) { - case UDPOSC: - oscOut.protocol = UDPOSC; - break; - case TCP: - oscOut.protocol = TCP; - break; - case TCPSLIP: - slipEncode(); - oscOut.protocol = TCPSLIP; - break; - } + itoh(sendMessage.message, dataStart, int32); + sendMessage.size = dataStart + 4; + sendOSC(); } -void oscMessage(const char pattern[], protocol_t protocol) { - memset(oscOut.message, 0, sizeof(oscOut.message)); - oscOut.size = 0; +void oscMessage(const char pattern[]) { + memset(sendMessage.message, 0, sizeof(sendMessage.message)); + sendMessage.size = 0; int patternLength = strlen(pattern); - memcpy(oscOut.message, pattern, patternLength); + memcpy(sendMessage.message, pattern, patternLength); int patternOffset = patternLength % 4; int tagStart; if (patternOffset == 0) tagStart = patternLength + 4; else tagStart = patternLength + (4 - patternOffset); - memcpy(oscOut.message + tagStart, ",\0\0\0", 4); - oscOut.size = tagStart + 4; - switch (protocol) { - case UDPOSC: - oscOut.protocol = UDPOSC; - break; - case TCP: - oscOut.protocol = TCP; - break; - case TCPSLIP: - slipEncode(); - oscOut.protocol = TCPSLIP; - break; - } - } - -void slipEncode() { - uint8_t buffer[OSC_MESSAGE_SIZE] = {0}; - int slipLength = 0; - buffer[0] = END; - slipLength++; - for (int i = 0; i < oscOut.size; i++) { - if (oscOut.message[i] == END) { - buffer[slipLength] = ESC; - buffer[slipLength + 1] = ESC_END; - slipLength = slipLength + 2; - } - else if (oscOut.message[i] == ESC) { - buffer[slipLength] = ESC; - buffer[slipLength + 1] = ESC_ESC; - slipLength = slipLength + 2; - } - else { - buffer[slipLength] = oscOut.message[i]; - slipLength++; - } - } - buffer[slipLength] = END; - slipLength++; - oscOut.size = slipLength; - memcpy(oscOut.message, buffer, oscOut.size); + memcpy(sendMessage.message + tagStart, ",\0\0\0", 4); + sendMessage.size = tagStart + 4; + sendOSC(); } float htof(uint8_t *msg, uint8_t dataStart) { diff --git a/src/gma3.h b/src/gma3.h index ca32419..2d5863c 100644 --- a/src/gma3.h +++ b/src/gma3.h @@ -1,5 +1,5 @@ /* -gma3 for GrandMa3 consoles by Stefan Staub (c) 2021 is licensed under CC BY-NC-SA 4.0 +gma3 for GrandMa3 consoles by Stefan Staub (c) 2023 is licensed under CC BY-NC-SA 4.0 Attribution-NonCommercial-ShareAlike 4.0 International */ @@ -7,12 +7,14 @@ Attribution-NonCommercial-ShareAlike 4.0 International * @brief hardware sugestions * - fader is a linear type with 10kOhm, from Bourns or ALPS and can be 60/80/100mm long * - put a 10nF ceramic capitors between GND and fader leveler to prevent analog noise - * - Arduino UNO, MEGA: + * - Arduino UNO, MEGA * use AREF instead +5V to the top (single pin) of the fader (100%), use the GND next to AREF * GND to the center button pin (2 pins, the outer pin is normaly for the leveler) of the fader (0%) - * - TEENSY 3.x: + * - TEENSY 3.x * use ANALOG GND instead of the normal GND - * - put 100nF ceramic capitors between ground and the input of the buttons and ecoders + * - STM32 + * use AGND and AVDD + * - put 100nF ceramic capitors between ground and the inputs of the buttons and ecoders */ #ifndef GMA3_H @@ -22,7 +24,7 @@ Attribution-NonCommercial-ShareAlike 4.0 International #include "Udp.h" #include "Client.h" -// callback +// callback type typedef void (*cbptr)(); // button values @@ -34,8 +36,8 @@ typedef void (*cbptr)(); #define REVERSE 1 // fader settings -#define FADER_UPDATE_RATE_MS 1 // update rate, must low at possible for fetching -#define FADER_THRESHOLD 4 // Jitter threshold of the faders +#define FADER_UPDATE_RATE_MS 40 // update rate, must low at possible for fetching +#define FADER_THRESHOLD 2 // Jitter threshold of the faders // OSC settings #define NAME_LENGTH_MAX 32 @@ -49,13 +51,6 @@ typedef void (*cbptr)(); #define ESC_END 0xDC // ESC ESC_END means END data byte #define ESC_ESC 0xDD // ESC ESC_ESC means ESC data byte -// GMA3 naming conventions -#define PREFIX "gma3" -#define PAGE "Page" -#define FADER "Fader" -#define EXECUTOR_KNOB "Encoder" -#define KEY "Key" - /** * @brief Network protocol type and coding * @@ -63,7 +58,6 @@ typedef void (*cbptr)(); typedef enum ProtocolType { UDPOSC, TCP, - TCPSLIP, } protocol_t; /** @@ -77,14 +71,19 @@ typedef enum OscType { STRING, } osc_t; +typedef enum SendMode { + GLOBAL, + CONSOLE, + LOCAL, + } send_t; + struct Message { uint8_t message[OSC_MESSAGE_SIZE]; int32_t size; protocol_t protocol; - bool update; }; -struct OSC { +struct Data { char pattern[OSC_PATTERN_SIZE]; char tag[12]; char string[OSC_STRING_SIZE]; @@ -93,134 +92,294 @@ struct OSC { }; /** - * @brief Set GMA3 IP address + * @brief set the Prefix name * - * @param gma3IP GMA3 console IP address + * @param prefix */ -void interfaceGMA3(IPAddress ip); +void prefixName(const char *prefix); /** - * @brief Set UDP interface + * @brief set the DataPool name * - * @param gma3Udp UDP interface - * @param gma3UdpPort UDP port off GrandMA3, standard port is 8000 + * @param pool */ -void interfaceUDP(UDP &udp, uint16_t port = 8000); +void dataPoolName(const char *pool); /** - * @brief Set TCP interface + * @brief set the Page name * - * @param tcp TCP interface - * @param eosTcpPort TCP port off GrandMA3, standard port is 9000 + * @param page + */ +void pageName(const char *page); + +/** + * @brief set the Fader name + * + * @param fader + */ +void faderName(const char *fader); + +/** + * @brief set the ExecutorKnob name + * + * @param executorKnob + */ +void executorKnobName(const char *executorKnob); + +/** + * @brief set the Key name + * + * @param key */ -void interfaceTCP(Client &tcp, uint16_t port = 9000); +void keyName(const char *key); /** * @brief Set UDP interface * * @param udp UDP interface - * @param ip IP address of the receiver - * @param port UDP port of the receiver + * @param ip GMA3 console IP address + * @param port UDP port off GrandMA3, standard port is 8000 */ -void interfaceExternUDP(UDP &udp, IPAddress ip, uint16_t port); +void interface(UDP &udp, IPAddress ip, uint16_t port = 8000); /** * @brief Set TCP interface * * @param tcp TCP interface - * @param ip IP address of the receiver - * @param port TCP port of the receiver + * @param protocol_t protocol only TCP is possible in the moment + * @param ip GMA3 console IP address + * @param port TCP port off GrandMA3, standard port is 9000 */ -void interfaceExternTCP(Client &tcp, IPAddress ip, uint16_t port); +void interface(Client &tcp, protocol_t protocol, IPAddress ip, uint16_t port = 9000); /** - * @brief Send an OSC message via UDP to gma3 or external receiver + * @brief Send OSC data to gma3 or external receiver * */ -void sendUDP(); -void sendExternUDP(); +void sendOSC(); /** - * @brief Receive an OSC message via UDP + * @brief Send a command to the console * - * @return true if there is an OSC message received - * @return false + * @param cmd */ -bool receiveUDP(); +void command(const char cmd[]); /** - * @brief Send an OSC message via TCP to gma3 or external receiver + * @brief Get the common DataPool number * + * @return uint16_t common DataPool number */ -void sendTCP(); -void sendExternTCP(); +uint16_t commonPool(); /** - * @brief Send OSC data to gma3 or external receiver + * @brief Set the common DataPool number * + * @param pool DataPool number */ -void sendOSC(); -void sendExternOSC(); +void commonPool(uint16_t pool); -void command(const char cmd[], protocol_t protocol = UDPOSC); +/** + * @brief Get the common Page number + * + * @return uint16_t common page number + */ +uint16_t commonPage(); /** - * @brief Parse the oscmessage - * following assumtions + * @brief Set the common Page number + * + * @param page page number + */ +void commonPage(uint16_t page); + +/** + * @brief Parser object to handle messages from the console + * * following assumtions * - the gma3 osc message could contains 1 string, max. 2 integer and 1 float * - the first item can only be a type of string * - the second item can only be a type of integer * - the third item can be a type of integer or float - * @param msg OSC message */ -void parseOSC(uint8_t *msg); +class Parser { + public: + /** + * @brief + * + * @param callback function callback + */ + Parser(cbptr callback = nullptr); -/** - * @brief Return the parser results - * - * @return const char* OSC pattern - * @return const char* OSC tag string - * @return const char* string argument - * @return int32_t the two integer arguments - * @return float the float argument used for fader level - */ -const char* patternOSC(); -const char* stringOSC(); -int32_t int1OSC(); -int32_t int2OSC(); -float floatOSC(); + /** + * @brief Return the dataPool pattern send by the console + * + * @return const char* dataPool pattern + */ + const char* patternOSC(); + + /** + * @brief Parse for dataPool level + * + * @param level 0 - 4, root is 0 + * @return uint8_t + */ + int dataStructure(uint8_t level); + + /** + * @brief Return the string argument send by the console + * + * @return const char* + */ + const char* stringOSC(); + + /** + * @brief Return the first interger argument send by the console + * + * @return int32_t + */ + int32_t int1OSC(); + + /** + * @brief Return the second interger argument send by the console + * + * @return int32_t + */ + int32_t int2OSC(); + + /** + * @brief Return the float argument send by the console + * + * @return float + */ + float floatOSC(); + + void update(); + + private: + void parseOSC(); + bool receiveUDP(); + bool receiveTCP(); + int dataValue[5]; + cbptr callback = nullptr; + struct Data receiveData; + }; /** - * @brief Set the global page number + * @brief Pools object to handle DataPools via buttons + * allows to step through an defined amount of data pools * - * @param page */ -void page(uint16_t page); +class Pools { + public: + /** + * @brief Construct a new Pools object with warp around functionality + * + * @param pinUp pin of the up button, not needed for virtual devices + * @param pinDown pin of the down button, not needed for virtual devices + * @param poolsStart number of the first pool you want to use + * @param poolsEnd number of the last pool you want to use + * @param mode this can send the pool number to the console, for internal use or both + * - CONSOLE for use only with the console + * - LOCAL for local use + * - GLOBAL both internal and console + * @param callback function to call when pool change + */ + Pools(uint8_t pinUp, uint8_t pinDown, uint8_t poolsStart, uint8_t poolsEnd, send_t mode = GLOBAL, cbptr callback = nullptr); + Pools(uint8_t poolsStart, uint8_t poolsEnd, send_t mode = GLOBAL, cbptr callback = nullptr); + + /** + * @brief Get the current common pool number + * + * @return uint16_t pool number + */ + uint16_t currentPool(); + + /** + * @brief Get the last common pool number + * + * @return uint16_t pool number + */ + uint16_t lastPool(); + + /** + * @brief Update the output of the pool buttons, must be in loop() + * + * @param stateUp optional for virtual devices, TRUE if button press + * @param stateDown optional for virtual devices, TRUE if button press + */ + void update(); + void update(bool stateUp, bool stateDown); + + private: + void sendPool(uint16_t pool); + uint8_t pinUp; + uint8_t pinUpLast; + uint8_t pinDown; + uint8_t pinDownLast; + uint16_t poolsStart; + uint16_t poolsEnd; + uint16_t poolNumber = 1; + uint16_t poolLast; + send_t mode; + cbptr callback; + }; /** - * @brief Button object + * @brief Pools object to handle DataPools via buttons * */ -class Button { +class Pages { public: /** - * @brief Construct a new Button object + * @brief Construct a new pages object * - * @param pin button to trigger up callback - * @param callback pointer to the calback for the button + * @param pinUp pin of the up button, not needed for virtual devices + * @param pinDown pin of the down button, not needed for virtual devices + * @param poolsStart number of the first pool you want to use + * @param poolsEnd number of the last pool you want to use + * @param mode this can send the pool number to the console, for internal use or both + * - CONSOLE for use only with the console + * - LOCAL for local use + * - GLOBAL both internal and console + * @param callback function to call when page change */ - Button(uint8_t pin, cbptr callback); + Pages(uint8_t pinUp, uint8_t pinDown, uint8_t pagesStart, uint8_t pagesEnd, send_t mode = GLOBAL, cbptr callback = nullptr); + Pages(uint8_t pagesStart, uint8_t pagesEnd, send_t mode = GLOBAL, cbptr callback = nullptr); /** - * @brief Check for updated selection + * @brief Get the current common page number * + * @return uint16_t page number */ - void update(); + uint16_t currentPage(); + + /** + * @brief Get the last common page number + * + * @return uint16_t page number + */ + uint16_t lastPage(); + /** + * @brief Update the output of the pool buttons, must be in loop() + * + * @param stateUp optional for virtual devices, TRUE if button press + * @param stateDown optional for virtual devices, TRUE if button press + */ + void update(); + void update(bool stateUp, bool stateDown); private: - uint8_t pin; - uint8_t pinLast; - cbptr callback = nullptr; + void sendPage(uint16_t page); + uint8_t pinUp; + uint8_t pinUpLast; + uint8_t pinDown; + uint8_t pinDownLast; + uint16_t pagesStart; + uint16_t pagesEnd; + uint16_t pageNumber = 1; + uint16_t pageLast; + send_t mode; + cbptr callback; }; /** @@ -232,37 +391,40 @@ class Key { /** * @brief Construct a new Key object * - * @param pin button pin - * @param page number of the page + * @param pin button pin, not needed for virtual devices * @param key number of the executor button */ - Key(uint8_t pin, uint16_t key, protocol_t protocol = UDPOSC); + Key(uint8_t pin, uint16_t key); + Key(uint16_t key); /** - * @brief Destroy the Key object + * @brief Set a local pool number * + * @param page number must between 1 and 9999, if 0 common pool number is used */ - ~Key(); + void pool(uint16_t poolLocal = 0); /** * @brief set a local page number * - * @param page number must between 1 and 9999, if 0 glaobal page number is used + * @param page number must between 1 and 9999, if 0 common page number is used */ void page(uint16_t pageLocal = 0); /** * @brief Update the state of the Key button, must in loop() * + * @param state optional for virtual devices, TRUE if button press */ void update(); + void update(bool state); private: uint8_t pin; - protocol_t protocol; + uint8_t last; uint16_t key; + uint16_t poolLocal = 0; uint16_t pageLocal = 0; - uint8_t last; }; /** @@ -274,17 +436,18 @@ class Fader { /** * @brief Construct a new Fader object * - * @param analogPin pin for the fader leveler - * @param pageNumber number of the page + * @param analogPin pin for the fader leveler, not needed for virtual devices * @param faderNumber number of the executor fader */ - Fader(uint8_t analogPin, uint16_t fader, protocol_t protocol = UDPOSC); + Fader(uint8_t analogPin, uint16_t fader); + Fader(uint16_t fader); /** - * @brief Destroy the Fader object + * @brief Set a local pool number * + * @param page number must between 1 and 9999, if 0 common pool number is used */ - ~Fader(); + void pool(uint16_t poolLocal = 0); /** * @brief Set a local page number @@ -331,21 +494,24 @@ class Fader { /** * @brief Update the state of the fader, must in loop() + * @brief For use with virtual inputs: * + * @param value optional for virtual inputs with 10 bits */ void update(); + void update(uint16_t value); private: + bool lockState = false; uint8_t analogPin; + uint8_t delta; uint16_t fader; + int16_t poolLocal = 0; uint16_t pageLocal = 0; - protocol_t protocol; + int16_t fetchValue; int16_t analogLast; int32_t valueLast; uint32_t updateTime; - bool lockState = false; - int16_t fetchValue; - uint8_t delta; }; /** @@ -357,44 +523,48 @@ class ExecutorKnob { /** * @brief Construct a new ExecutorKnob object * - * @param pinA pin A of the encoder - * @param pinB pin B of the encoder - * @param pageNumber number of the page + * @param pinA pin A of the encoder, not needed for virtual devices + * @param pinB pin B of the encoder, not needed for virtual devices * @param executorKnobNumber number of the executorKnob * @param direction the direction for the encoder, can be FORWARD or REVERSE, depends on hardware alignment */ - ExecutorKnob(uint8_t pinA, uint8_t pinB, uint16_t executorKnob, protocol_t protocol = UDPOSC, uint8_t direction = FORWARD); + ExecutorKnob(uint8_t pinA, uint8_t pinB, uint16_t executorKnob, uint8_t direction = FORWARD); + ExecutorKnob(uint16_t executorKnob, uint8_t direction = FORWARD); /** - * @brief Destroy the Executor Knob object + * @brief Set a local pool number * + * @param page number must between 1 and 9999, if 0 common pool number is used */ - ~ExecutorKnob(); + void pool(uint16_t poolLocal = 0); /** * @brief Set a local page number * - * @param page number must between 1 and 9999, if 0 glaobal page number is used + * @param page number must between 1 and 9999, if 0 common page number is used */ void page(uint16_t pageLocal = 0); /** * @brief Update the output of the executorKnob, must be in loop() * + * @param stateA optional for virtual devices, TRUE if button press + * @param stateB optional for virtual devices, TRUE if button press */ void update(); + void update(uint8_t stateA, uint8_t stateB); private: uint8_t pinA; uint8_t pinB; - uint16_t executorKnob; - uint16_t pageLocal = 0; - protocol_t protocol; uint8_t pinALast; uint8_t pinACurrent; uint8_t direction; - int8_t encoderMotion; uint8_t value; + int8_t encoderMotion; + uint16_t executorKnob; + uint16_t poolLocal = 0; + uint16_t pageLocal = 0; }; /** @@ -406,109 +576,36 @@ class CmdButton { /** * @brief Construct a new CmdButton object * - * @param pin button pin - * @param cmdPattern command string - */ - CmdButton(uint8_t pin, const char command[], protocol_t protocol = UDPOSC); - - /** - * @brief Destroy the Cmd Button object - * + * @param pin button pin, not needed for virtual devices + * @param command command string */ - ~CmdButton(); + CmdButton(uint8_t pin, const char *command); + CmdButton(const char *command); /** * @brief Update the state of the cmdButton, must in loop() * + * @param state optional for virtual devices, TRUE if button press */ void update(); + void update(bool state); private: - char cmdString[OSC_STRING_SIZE]; - protocol_t protocol; - char pattern[OSC_PATTERN_SIZE] = "/"; - uint8_t pin; - uint8_t last; - }; - -class OscButton { - public: - /** - * @brief Construct a new osc Button object for sending an integer value - * - * @param pin button pin - * @param pattern OSC address - * @param integer32 value must cast (int32_t) when using with a non matching size - */ - OscButton(uint8_t pin, const char pattern[], int32_t integer32, protocol_t protocol = UDPOSC); - - /** - * @brief Construct a new osc Button object for sending a float value - * - * @param pin button pin - * @param pattern OSC address - * @param float32 float value - */ - OscButton(uint8_t pin, const char pattern[], float float32, protocol_t protocol = UDPOSC); - - /** - * @brief Construct a new osc Button object for sending a string - * - * @param pin button pin - * @param pattern OSC address - * @param message message string - */ - OscButton(uint8_t pin, const char pattern[], const char message[], protocol_t protocol = UDPOSC); - - /** - * @brief Construct a new osc Button object with no value - * - * @param pin button pin - * @param pattern OSC address - */ - OscButton(uint8_t pin, const char pattern[], protocol_t protocol = UDPOSC); - - /** - * @brief Destroy the Osc Button object - * - */ - ~OscButton(); - - /** - * @brief Update the state of the OSC button, must in loop() - * - */ - void update(); - - private: - enum osc_t {NODATA, INT32, FLOAT32, STRING}; - osc_t typ; - char patternString[OSC_PATTERN_SIZE]; - int32_t integer32; - float float32; - char messageString[OSC_STRING_SIZE]; - protocol_t protocol; uint8_t pin; - uint8_t last; + uint8_t last; + char cmdString[OSC_STRING_SIZE]; }; /** - * @brief Creates osc messages with different data types + * @brief Creates osc messages with different data types and send it * * @param osc message * @param value integer32, float, string value and nodata argument - * @param protocol type of the used protocol, UDP, TCP or TCPSLIP - */ -void oscMessage(const char pattern[], int32_t int32, protocol_t protocol = UDPOSC); -void oscMessage(const char pattern[], float float32, protocol_t protocol = UDPOSC); -void oscMessage(const char pattern[], const char string[], protocol_t protocol = UDPOSC); -void oscMessage(const char pattern[], protocol_t protocol = UDPOSC); - -/** - * @brief Encode TCPSLIP messages for external OSC buttons - * */ -void slipEncode(); +void oscMessage(const char pattern[], int32_t int32); +void oscMessage(const char pattern[], float float32); +void oscMessage(const char pattern[], const char string[]); +void oscMessage(const char pattern[]); /** * @brief Big endian array to float conversation