text: /*
   * Copyright (c) 2016 Intel Corporation
   * Copyright (c) 2015 Jules Dourlens (jdourlens@gmail.com)
   *
   * SPDX-License-Identifier: MIT
   */
  
  #pragma once
  
  #include <pthread.h>
  
  #include "uart.h"
  
  #define MODE_INPUT 0x00
  #define MODE_OUTPUT 0x01
  #define MODE_ANALOG 0x02
  #define MODE_PWM 0x03
  #define MODE_SERVO 0x04
  #define MODE_SHIFT 0x05
  #define MODE_I2C 0x06
  
  #define LOW 0
  #define HIGH 1
  
  #define FIRMATA_START_SYSEX 0xF0       // start a MIDI Sysex message
  #define FIRMATA_END_SYSEX 0xF7         // end a MIDI Sysex message
  #define FIRMATA_PIN_MODE_QUERY 0x72    // ask for current and supported pin modes
  #define FIRMATA_PIN_MODE_RESPONSE 0x73 // reply with current and supported pin modes
  #define FIRMATA_PIN_STATE_QUERY 0x6D
  #define FIRMATA_PIN_STATE_RESPONSE 0x6E
  #define FIRMATA_CAPABILITY_QUERY 0x6B
  #define FIRMATA_CAPABILITY_RESPONSE 0x6C
  #define FIRMATA_ANALOG_MAPPING_QUERY 0x69
  #define FIRMATA_ANALOG_MAPPING_RESPONSE 0x6A
  
  #define FIRMATA_DIGITAL_MESSAGE 0x90 // send data for a digital pin
  #define FIRMATA_ANALOG_MESSAGE 0xE0  // send data for an analog pin (or PWM)
  #define FIRMATA_ANALOG_MESSAGE 0xE0  // send data for an analog pin (or PWM)
  #define FIRMATA_REPORT_ANALOG 0xC0   // enable analog input by pin #
  #define FIRMATA_REPORT_DIGITAL 0xD0  // enable digital input by port pair
  
  #define FIRMATA_I2C_CONFIG 0x78
  #define FIRMATA_I2C_REPLY 0x77
  #define FIRMATA_I2C_REQUEST 0x76
  
  #define I2C_MODE_WRITE 0x00
  #define I2C_MODE_READ 0x01
  #define I2C_CONTINUOUSREAD 0x02
  #define I2C_STOP_READING 0x03
  
  #define FIRMATA_SET_PIN_MODE 0xF4 // set a pin to INPUT/OUTPUT/PWM/etc
  
  #define FIRMATA_REPORT_VERSION 0xF9 // report protocol version
  #define FIRMATA_SYSTEM_RESET 0xFF   // reset from MIDI
  
  #define FIRMATA_START_SYSEX 0xF0 // start a MIDI Sysex message
  #define FIRMATA_END_SYSEX 0xF7   // end a MIDI Sysex message
  
  // extended command set using sysex (0-127/0x00-0x7F)
  /* 0x00-0x0F reserved for custom commands */
  #define FIRMATA_EXTENDED_ANALOG 0x6F    // analog write (PWM, Servo, etc) to any pin
  #define FIRMATA_SERVO_CONFIG 0x70       // set max angle, minPulse, maxPulse, freq
  #define FIRMATA_STRING 0x71             // a string message with 14-bits per char
  #define FIRMATA_REPORT_FIRMWARE 0x79    // report name and version of the firmware
  #define FIRMATA_SYSEX_NON_REALTIME 0x7E // MIDI Reserved for non-realtime messages
  #define FIRMATA_SYSEX_REALTIME 0x7F     // MIDI Reserved for realtime messages
  
  // Serial command bytes
  #define FIRMATA_SERIAL_DATA                 0x60 // communicate with serial devices, including other boards
  #define FIRMATA_SERIAL_CONFIG               0x10
  #define FIRMATA_SERIAL_WRITE                0x20
  #define FIRMATA_SERIAL_READ                 0x30
  #define FIRMATA_SERIAL_REPLY                0x40
  #define FIRMATA_SERIAL_CLOSE                0x50
  #define FIRMATA_SERIAL_FLUSH                0x60
  #define FIRMATA_SERIAL_LISTEN               0x70
  #define FIRMATA_DEFAULT_BAUD                115200
  #define FIRMATA_MSG_LEN 1024
  
  // SPI mode bytes
  #define FIRMATA_SPI_DATA                    0x68 // communicate with serial devices, including other board
  #define FIRMATA_SPI_BEGIN                   0x00
  #define FIRMATA_SPI_BEGIN_TRANSACTION       0x01
  #define FIRMATA_SPI_END_TRANSACTION         0x02
  #define FIRMATA_SPI_TRANSFER                0x03
  #define FIRMATA_SPI_WRITE                   0x04
  #define FIRMATA_SPI_READ                    0x05
  #define FIRMATA_SPI_REPLY                   0x06
  #define FIRMATA_SPI_END                     0x07
  
  #define TOTAL_ANALOG_PINS       6
  #define TOTAL_GPIO_PINS         14
  #define TOTAL_I2C_BUS           2
  #define TOTAL_UART_DEV          3
  #define TOTAL_PINS              25 // 14 digital + 6 analog + 2 i2c + 3 spi
  
  typedef struct s_pin {
      uint8_t mode;
      uint8_t analog_channel;
      uint64_t supported_modes;
      uint32_t value;
  } t_pin;
  
  typedef struct s_firmata {
      mraa_uart_context uart;
      t_pin pins[128];
      int i2cmsg[256][256];
      int uartmsg[256][256];
      int spimsg[256][256];
      int parse_command_len;
      int parse_count;
      uint8_t parse_buff[FIRMATA_MSG_LEN];
      int isReady;
      char firmware[140];
      uint8_t dev_count;
      struct _firmata** devs;
      pthread_spinlock_t lock;
  } t_firmata;
  
  t_firmata* firmata_new(const char* name);
  void firmata_initPins(t_firmata* firmata);
  int firmata_askFirmware(t_firmata* firmata);
  int firmata_pinMode(t_firmata* firmata, int pin, int mode);
  int firmata_digitalWrite(t_firmata* firmata, int pin, int value);
  int firmata_analogWrite(t_firmata* firmata, int pin, int value);
  int firmata_analogRead(t_firmata* firmata, int pin,int value);
  int firmata_pull(t_firmata* firmata);
  void firmata_parse(t_firmata* firmata, const uint8_t* buf, int len);
  void firmata_endParse(t_firmata* firmata);
  void firmata_close(t_firmata* firmata);
  