start adding Arduino sketches to j2mod

start adding Arduino sketches to j2mod

git-svn-id: 464247b772b47fb892ddc6c4a897645d921924ed@73 43b03309-50c7-4bd2-8aa6-20f049331b16

/*
 * Copyright 2014, Julianne Frances Haugh
 * d/b/a greenHouse Gas and Electric
 *
 * This work is licensed under the terms of the "Creative Commons
 * Attribution-ShareAlike 4.0 International" open source license.
 * For more information, please read the following web page:
 *
 * http://creativecommons.org/licenses/by-sa/4.0/
 */

#include <EEPROM.h>
#include <alloca.h>
#include <avr/wdt.h>
#include <avg/pgmspace.h>

/*
 * Hardware identification.
 *
 * NOTE: If you are using this sketch in your own product you MUST replace
 *    all references to greenHouse Gas and Electric (except the copyright
 *    notice and the PROGMEN declaration below) with your own project
 *    related names.  You may not use either the name "greenHouse Gas and
 *    Electric" or "OSS_DAQ" in your product.  However, you MUST attribute
 *    your product to greenHouse Gas and Electric (CC-BY-SA).
 */

char copyright_notice[] PROGMEM = "Copyright 2014, greenHouse Gas and Electric, CC-BY-SA 4.0 Intl.";

/*
 * Pin assignments.
 *
 * AN0 - Interrupt 1, digital input counter #1, falling edge
 * AN1 - Interrupt 2, digital input counter #2, falling edge
 * A0 -- Analog 0, analog input sensor #1, default softare pull-up
 * A1 -- Analog 1, analog input sensor #2, default software pull-up
 * A2 -- Analog 2, analog input sensor #3, default float
 * A3 -- Analog 3, analog input sensor #4, default float
 * A4 -- Analog 4, unused, pull-up
 * A5 -- Analog 5, zener voltage reference, pull-down to GND or add voltage reference.
 */

#define HARD_COUNT_0_PIN  2
#define HARD_COUNT_1_PIN  3
#define DIGITAL_IN_2      4
#define DIGITAL_IN_3      5

#define COIL_1_PIN  6
#define COIL_2_PIN  7
#define COIL_3_PIN  8
#define COIL_4_PIN  9

#define LED_PIN     13

unsigned    long    last_millis = 0;
unsigned    long    last_led_flip = 0;
unsigned    char    last_led_state = 0;
unsigned    long    last_sample = 0;

unsigned    char    modbus_unit = 1;
unsigned    char    modbus_tmo = 4;
unsigned    short   modbus_baud = 19200;

unsigned    char    coil_1_state = 0;
unsigned    char    coil_2_state = 0;
unsigned    char    coil_3_state = 0;
unsigned    char    coil_4_state = 0;

unsigned    char    pullups[4];

unsigned    short   device_serial = 0;

#define REG_A0 0
#define REG_A1 1
#define REG_A2 2
#define REG_A3 3
#define REG_VREF 4
#define REG_D0 5
#define REG_D1 6
#define REG_D2 7
#define REG_D3 8
#define REG_D0_CNT 9
#define REG_D1_CNT 10
#define REG_LOOP_HI 11
#define REG_LOOP_LO 12
#define REG_BAUD 13
#define REG_UNIT 14
#define REG_SERIAL 15
#define MODBUS_REGS 16

unsigned    short   modbus_regs[MODBUS_REGS];

#define MODBUS_COILS 12

#if defined(__AVR_ATmega88__) || defined(__AVR_ATmega168__)
#define  KB_RAM  1
#elif defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__)
#define  KB_RAM  2
#define  EEPROM_SIZE 1024
#elif defined(__AVR_ATmega2560__)
#define  KB_RAM  8
#define  EEPROM_SIZE 4096
#else
#error Unknown processor
#endif

/*
 * User-selectable features.
 *
 * The #define statements below may by commented out to exclude the specified
 * features.
 */

#define HAS_MULTI /* WRITE MULTIPLE REGISTERS / COILS */
#define HAS_SRVR_ID /* READ SERVER ID */
#define HAS_MEI /* READ MODBUS ENCAPSULATED INFO */
#define HAS_FIFO /* READ FIFO */
#define HAS_FILES /* READ/WRITE FILE RECORD */
#define HAS_COUNTS /* GET COMM EVENT COUNTER */
#define HAS_LOG /* GET COMM EVENT LOG */

#if defined(HAS_LOG) && !defined(HAS_COUNTS)
#error Event log depends on event counters.
#endif

/*
 * Values for READ DEVICE IDENTICATION method.
 */
#if defined(HAS_MEI) || defined(HAS_SRVR_ID)
#ifdef HAS_MEI
char company_name[] PROGMEM = "greenHouse Gas and Electric";
#endif
char product_name[] PROGMEM = "OSS_DAQ";
#ifdef HAS_MEI
char version_text[] PROGMEM = "v1.01";
#endif
#endif

#ifdef HAS_FIFO
/**
 * get_fifo_count - Return "31" for valid ADC queues, -1 otherwise.
 */
char get_fifo_count(char fifo) {
  if (fifo < 0 || fifo > 3)
    return -1;

  return 31;
}

/**
 * get_fifo_value - Return the current ADC value
 */
short get_fifo_value(char fifo) {
  switch (fifo) {
    case 0: return analogRead(A0);
    case 1: return analogRead(A1);
    case 2: return analogRead(A2);
    case 3: return analogRead(A3);
    default: return -1;
  }
}
#endif

#ifdef HAS_FILES
#define  RECORD_SIZE  64
#define  FILE_BASE 128

const int eeprom_file_base = FILE_BASE;
const int eeprom_record_count = ((EEPROM_SIZE - FILE_BASE) / (RECORD_SIZE * 2));

char file_check_entry(unsigned short file, unsigned short record, unsigned short count) {
  if (file > 0 || record >= eeprom_record_count || count > RECORD_SIZE)
    return 0;

  return 1;
}

unsigned short file_get_value(unsigned short file, unsigned short record, unsigned char offset) {
  int address = (eeprom_file_base +
      record * RECORD_SIZE * sizeof(unsigned short)) +
      (offset * sizeof(unsigned short));

  return read_eeprom_short(address);
}

void file_put_value(unsigned short file, unsigned short record, unsigned char offset, unsigned short value) {
  int address = (eeprom_file_base +
      record * RECORD_SIZE * sizeof(unsigned short)) +
      (offset * sizeof(unsigned short));

  write_eeprom_short(address, value);
}
#endif

/*
 * get_coil - Return the state of the named coil.
 */
char get_coil(char coil) {
  switch(coil) {
    case 0: return modbus_regs[REG_D0] != 0;
    case 1: return modbus_regs[REG_D1] != 0;
    case 2: return coil_1_state;
    case 3: return coil_2_state;
    case 4: return coil_3_state;
    case 5: return coil_4_state;
    case 6:
    case 7:
    case 8:
    case 9:
      return pullups[coil - 6];
    default:
      return -1;
  }
}

char is_coil_setable(unsigned char coil) {
  return (coil >= 2 && coil <= 9);
}

char set_coil(char coil, char value) {
  switch(coil) {
    case 2:
      digitalWrite(COIL_1_PIN, value ? HIGH:LOW);
      coil_1_state = value != 0;
      return 1;
    case 3:
      digitalWrite(COIL_2_PIN, value ? HIGH:LOW);
      coil_2_state = value != 0;
      return 1;
    case 4:
      digitalWrite(COIL_3_PIN, value ? HIGH:LOW);
      coil_3_state = value != 0;
      return 1;
    case 5:
      digitalWrite(COIL_4_PIN, value ? HIGH:LOW);
      coil_4_state = value != 0;
      return 1;
    case 6:
    case 7:
    case 8:
    case 9:
      pinMode(A0 + coil - 4, value ? INPUT_PULLUP:INPUT);
      pullups[coil - 6] = value != 0;
      return 1;
    default:
      return 0;
  }
}

/*
 * Hardware interrupt counters.
 */
unsigned    short   count_1;
unsigned    short   count_2;

/*
 * These EEPROM functions support reading and writing the Modbus values used by
 * the greenSensors platform.  I used the same EEPROM address here so I can test
 * on existing hardware.
 */
short read_eeprom_short(int address) {
  short result = 0;

  result = (((unsigned char) EEPROM.read(address)) << 8) | ((unsigned char) EEPROM.read(address + 1));
  return result;
}

void write_eeprom_short(int address, short value) {
  EEPROM.write(address, ((value >> 8) & 0xFF));
  EEPROM.write(address + 1, (value & 0xFF));
}

/*
 * hard_1_int and hard_2_int are the hardware interrupt handlers which
 * implement a pair of counting registers.  There is no software debouncing.
 * The hardware should include an RC circuit to debounce the signal, where
 * the RC circuit sets the response rate for the data logger.
 */
void hard_1_int() {
    count_1++;

    modbus_regs[REG_D0] = 0;
    modbus_regs[REG_D0_CNT] = count_1;
}

void hard_2_int() {
    count_2++;

    modbus_regs[REG_D1] = 0;
    modbus_regs[REG_D1_CNT] = count_2;
}

void setup() {
    /*
     * Reset the watchdog.  This is a simple sketch, but if it gets hung, I'd
     * like it to reset itself.
     */
    MCUSR = 0;
    wdt_disable();
    wdt_reset();

    /*
     * Make the LED pin an "output" so it can be blinked whenever I receeive a
     * packet, and whenever another second since the last blink has happened.
     */
    pinMode(LED_PIN, OUTPUT);
    digitalWrite(LED_PIN, LOW);

    /*
     * Turn off coils 1 through 4.
     */
    pinMode(COIL_1_PIN, OUTPUT);
    digitalWrite(COIL_1_PIN, LOW);
    coil_1_state = 0;

    pinMode(COIL_2_PIN, OUTPUT);
    digitalWrite(COIL_2_PIN, LOW);
    coil_2_state = 0;

    pinMode(COIL_3_PIN, OUTPUT);
    digitalWrite(COIL_3_PIN, LOW);
    coil_3_state = 0;

    pinMode(COIL_3_PIN, OUTPUT);
    digitalWrite(COIL_3_PIN, LOW);
    coil_3_state = 0;

    /*
     * Set the digital inputs.
     */
    pinMode(HARD_COUNT_0_PIN, INPUT);
    pinMode(HARD_COUNT_1_PIN, INPUT);
    pinMode(DIGITAL_IN_2, INPUT);
    pinMode(DIGITAL_IN_3, INPUT);

    /*
     * Set the two interrupt handlers.
     */
    attachInterrupt(0, hard_1_int, FALLING);
    attachInterrupt(1, hard_2_int, FALLING);

    /*
     * Setup the analog inputs.
     */
    pinMode(A0, INPUT);
    digitalWrite(A0,  HIGH);
    pullups[0] = 1;

    pinMode(A1, INPUT);
    digitalWrite(A1,  HIGH);
    pullups[1] = 1;

    pinMode(A2, INPUT);
    digitalWrite(A2,  LOW);
    pullups[2] = 0;

    pinMode(A3, INPUT);
    digitalWrite(A3,  LOW);
    pullups[3] = 0;

    pinMode(A4, INPUT);
    digitalWrite(A4, LOW);

    pinMode(A5, INPUT);
    digitalWrite(A5, LOW);

    /*
     * Get the baud rate.  It is stored at address 64 on a greenSensors box and
     * will be fetched from there.
     */
    modbus_baud = (unsigned short) read_eeprom_short(64);
    if (modbus_baud == -1 || (modbus_baud % 9600) != 0) {
      modbus_baud = 19200;
    }

    /*
     * The Modbus specification says that 19200 is the default.
     */
    switch (modbus_baud) {
      case 9600:
        modbus_tmo = 4;
        break;
      case 19200:
        modbus_tmo = 3;
        break;
      case 38400:
        modbus_tmo = 2;
        break;
      case 57600:
        modbus_tmo = 2;
        break;
      default:
        modbus_baud = 19200;
        modbus_tmo = 2;
        break;
    }

    modbus_unit = (unsigned short) EEPROM.read(10);
    if (modbus_unit == 0 || modbus_unit == 0xFF)
      modbus_unit = 1;

    /*
     * Save these two values in the map.  They are mirrored by the named
     * variables, but this allows the user to change the values with a
     * WRITE REGISTER command.
     */
    modbus_regs[REG_BAUD] = modbus_baud / 9600;
    modbus_regs[REG_UNIT] = modbus_unit;

    /*
     * The actual serial number starts at address 4, but has a two character
     * device prefix.  This will return just the number.
     */
    device_serial = read_eeprom_short(6);
    if (device_serial == (unsigned short) 0xFFFF)
      device_serial = 0;

    modbus_regs[REG_SERIAL] = device_serial;

    /*
     * Now set up the watchdog.  I use 8 seconds because of problems that
     * have been reported in certain boot loaders.  A nice long watchdog
     * will make it easier for someone to wrestle control of their Arduino
     * back.
     */
    MCUSR = 0;
    wdt_enable(WDTO_8S);

    /*
     * Now start the serial port.
     */
    Serial.begin(modbus_baud);
}

/*
 * update_eeprom -- Update the EEPROM with any changed Modbus registers that are
 *    stored in EEPROM.
 */
void update_eeprom() {
  if (modbus_unit != modbus_regs[REG_UNIT]) {
    if (modbus_regs[REG_UNIT] > 0 && modbus_regs[REG_UNIT] <= 253) {
      modbus_unit = modbus_regs[REG_UNIT];
      EEPROM.write(10, modbus_unit);
    } else {
      modbus_regs[REG_UNIT] = modbus_unit;
    }
  }

  if (modbus_baud != modbus_regs[REG_BAUD] * 9600) {
    if (modbus_regs[REG_BAUD] == 1 || modbus_regs[REG_BAUD] == 2 ||
        modbus_regs[REG_BAUD] == 4 || modbus_regs[REG_BAUD] == 6) {
      modbus_baud = modbus_regs[REG_BAUD] * 9600;
      if (modbus_baud == 9600)
        modbus_tmo = 4;
      else
        modbus_tmo = 2;

      write_eeprom_short(64, modbus_baud);
      Serial.begin(modbus_baud);
    } else {
      modbus_regs[REG_BAUD] = modbus_baud / 9600;
    }
  }

  if (device_serial == 0 && modbus_regs[REG_SERIAL] != 0) {
    write_eeprom_short(6, modbus_regs[REG_SERIAL]);
    device_serial = modbus_regs[REG_SERIAL];
  } else {
    modbus_regs[REG_SERIAL] = device_serial;
  }
}

void flip_led() {
  digitalWrite(LED_PIN, last_led_state ? LOW:HIGH);
  last_led_state = ! last_led_state;

  last_led_flip = millis();
}

/* Start of the Modbus library. */

/*
 * These variables are required for the Modbus library to know its limits.
 */
short  modbus_regs_cnt = MODBUS_REGS;
short  modbus_coils_cnt = MODBUS_COILS;

/* Start of Modbus library code */

/*
 * Modbus exception codes.
 */
enum {
        EX_ILLEGAL_FUNCTION = 1,
        EX_ILLEGAL_DATA_ADDRESS = 2,
        EX_ILLEGAL_DATA_VALUE = 3,
        EX_SLAVE_DEVICE_FAILURE = 4,
        EX_SLAVE_BUSY = 6,
        EX_MEMORY_PARITY_ERROR = 8
};

/*
 * Supported Modbus functions.
 */
enum {
        FC_READ_COILS = 0x01,
        FC_READ_DISCRETE_INPUTS = 0x02,
        FC_READ_HOLDING_REGISTERS  = 0x03,
        FC_READ_INPUT_REGISTERS = 0x04,
        FC_WRITE_SINGLE_COIL = 0x05,
        FC_WRITE_SINGLE_REGISTER  = 0x06,
#ifdef HAS_COUNTS
        FC_GET_COMM_EVENT_COUNTER = 0x0B,
#endif
#ifdef HAS_LOG
        FC_GET_COMM_EVENT_LOG = 0x0C,
#endif
#ifdef HAS_MULTI
        FC_WRITE_MULTIPLE_COILS = 0x0F,
        FC_WRITE_MULTIPLE_REGISTERS = 0x10,
#endif
#ifdef HAS_SRVR_ID
        FC_REPORT_SERVER_ID = 0x11,
#endif
#ifdef HAS_FILES
        FC_READ_FILE_RECORD = 0x14,
        FC_WRITE_FILE_RECORD = 0x15,
#endif
#ifdef HAS_FIFO
        FC_READ_FIFO = 0x18,
#endif
#ifdef HAS_MEI
        FC_READ_MEI = 0x2B,
#endif
};

/*
 * The last time, in milliseconds, that there was input.
 */
unsigned    long    last_input = 0;

/*
 * Define MAX_PDU to the largest input =or= output packet you expect to
 * see.  Then define MAX_PDU_IN and MAX_PDU_OUT to the input and output
 * limits, respectively.
 */

#define  TWO_BUFFERS /* Separate input and output Modbus buffers */

#define  MAX_PDU  256
#define  MAX_PDU_IN 256
#define  MAX_PDU_OUT 256

#if (MAX_PDU_IN > MAX_PDU) || (MAX_PDU_OUT > MAX_PDU)
#error Invalid PDU size!
#endif

#ifndef TWO_BUFFERS
#if MAX_PDU_IN != MAX_PDU_OUT
#error Packet mismatch!
#endif
#endif

unsigned    char    modbus_in[MAX_PDU_IN];
unsigned    short   modbus_in_cnt = 0;

/*
 * The smaller AVR parts have issues with insufficient RAM.  Basic functions are
 * written to finish with the input buffer before starting on the output buffer,
 * to avoid wasting memory.  The more advanced features require both buffers.
 */
#ifdef TWO_BUFFERS
unsigned    char    modbus_out[MAX_PDU_OUT];
#else
unsigned    char    *modbus_out = modbus_in;
#endif
unsigned    short   modbus_out_cnt = 0;

#if defined(HAS_FILES) && !defined(TWO_BUFFERS)
#error Two buffers are required for the READ FILE RECORD feature
#endif

#ifdef HAS_COUNTS
unsigned short event_count;
#ifdef HAS_LOG
unsigned short message_count;
unsigned char  message_bytes[64];
unsigned char  message_bytes_cnt;
unsigned char  message_bytes_wrapped = 0;

void modbus_add_comm_log_entry(unsigned char entry) {
  message_bytes[message_bytes_cnt++] = entry;

  if (message_bytes_cnt & ~0x3F) {
      message_bytes_cnt = 0;
      message_bytes_wrapped = 1;
  }

  if (entry & 0x80)
    message_count++;
}
#endif
#endif

unsigned char modbus_packet_check() {
    unsigned long  now;
    unsigned char  can_read;

    /*
     * Check the number of input bytes and determine if there is any need to
     * see if there's even a packet present.
     */
    can_read = Serial.available();
    if (can_read == 0 && modbus_in_cnt == 0)
      return 0;

    /*
     * Either I have one or more bytes to read, or I must look for a timeout.  Do
     * the bytes first.  Either way, I need the current time.
     */
    now = millis();
    if (can_read != 0) {

      /*
       * I have data to read.  I must save the current time (for the timeout)
       * then drain the input buffer so I don't get an overrun there.
       */
      last_input = now;

      while (can_read > 0) {
        unsigned char data = Serial.read();

        if (modbus_in_cnt < MAX_PDU_IN)
          modbus_in[modbus_in_cnt++] = data;

        can_read--;
      }
      return 0;
    }

    /*
     * The Modbus standard specifies a packet ends 3.5 character times after the
     * last byte is received.  That's a bit over 3.5ms at 9600 baud, and 1.8ms
     * at 19.2kBaud.
     *
     * NOTE: Many USB-to-Serial converters have major timing issues and conforming
     * to the specification may be very hard and force modbus_tmo to be changed.
     */
    return now - last_input > modbus_tmo;
}

void modbus_put_short(unsigned short value) {
  if (modbus_out_cnt > (MAX_PDU_OUT-2))
    return;

  modbus_out[modbus_out_cnt++] = value >> 8;
  modbus_out[modbus_out_cnt++] = value & 0xFF;
}

unsigned short modbus_get_short(unsigned char offset) {
  return(modbus_in[offset] << 8) | modbus_in[offset + 1];
}

unsigned short modbus_crc(unsigned char *data, unsigned char cnt)
{
  unsigned char byte, bit;
  unsigned short result;

  result = 0xFFFF;

  for (byte = 0;byte < cnt;byte++) {
    result ^= data[byte];

    for (bit = 0; bit < 8;bit++) {
      if (result & 0x0001)
        result = (result >> 1) ^ 0xA001;
      else
        result = (result >> 1);
    }
  }

  /*
   * The CRC is byte-swapped, so byte swap it on return.
   */
  return ((result >> 8) & 0xFF) | ((result & 0xFF) << 8);
}

void modbus_add_crc() {
  modbus_put_short(modbus_crc(modbus_out, modbus_out_cnt));
}

void modbus_write() {
#ifdef HAS_LOG
  unsigned char log_value = 0x40;    // Generic SEND entry.
#endif
  /*
   * NEVER transmit a broadcast reply.
   */
  if (modbus_out[0] == 0)
    return;

#ifdef HAS_LOG
  /*
   * See if this is an exception response.
   */
  if (modbus_out[1] & 0x80)
    log_value |= 0x01;

  modbus_add_comm_log_entry(log_value);
#endif
  modbus_add_crc();

  delay(modbus_tmo);
  Serial.write(modbus_out, modbus_out_cnt);
  Serial.flush();
  delay(modbus_tmo);
}

void modbus_exception(unsigned char code) {
  /*
   * NEVER report an exception on a broadcast message.
   */
  if (modbus_in[0] == 0)
    return;

  /*
   * Copy the command code from the input packet to the output packet,
   * setting bit 0x80 in the process.  Then append the exception code
   * passed in.
   */

  unsigned char function = modbus_in[1] | 0x80;

  modbus_out_cnt = 0;
  modbus_out[modbus_out_cnt++] = modbus_unit;
  modbus_out[modbus_out_cnt++] = function;
  modbus_out[modbus_out_cnt++] = code;

  modbus_write();
}

unsigned char modbus_check_crc() {
  if (modbus_in_cnt <= 2)
    return 0;

  return modbus_crc(modbus_in, modbus_in_cnt - 2) == modbus_get_short(modbus_in_cnt - 2);
}

#ifdef HAS_FIFO
void slave_read_fifo() {
  unsigned short fifo_pointer = modbus_get_short(2);
  char fifo_count;

  if ((fifo_count = get_fifo_count(fifo_pointer)) < 0 || fifo_count >= 32) {
    modbus_exception(EX_ILLEGAL_DATA_VALUE);
    return;
  }

  modbus_out_cnt = 0;
  modbus_out[modbus_out_cnt++] = modbus_unit;
  modbus_out[modbus_out_cnt++] = FC_READ_FIFO;
  modbus_put_short((fifo_count * sizeof (short)) + sizeof(short));
  modbus_put_short(fifo_count);

  for (int i = 0;i < fifo_count;i++)
    modbus_put_short(get_fifo_value(fifo_pointer));

#ifdef HAS_COUNTS
  event_count++;
#endif
  modbus_write();
}
#endif

#ifdef HAS_FILES
/**
 * slave_read_file_record - Read one or more records from EEPROM
 */
void slave_read_file_record() {
  unsigned char byte_count = modbus_in[2];
  unsigned char requests = (modbus_in_cnt - 4) / 7;
  int total_registers = 0;
  unsigned char result_size = 0;

  if (! (7 <= byte_count && byte_count <= 245)) {
illegal_data_value:
    modbus_exception(EX_ILLEGAL_DATA_VALUE);
    return;
  }

  /*
   * There are 5 bytes that aren't part of the request list.
   * The unit number, function code, byte count, and 2 bytes
   * for the CRC.
   */
  if (byte_count != modbus_in_cnt - 5)
    goto illegal_data_value;

  for (int i = 0;i < requests;i++) {
    char code = modbus_in[3 + (i * 7)];
    unsigned short file = modbus_get_short(4 + (i * 7));
    unsigned short record = modbus_get_short(6 + (i * 7));
    unsigned short registers = modbus_get_short(8 + (i * 7));

    if (code != 6)
      goto illegal_data_value;

    if (! file_check_entry(file, record, registers)) {
      modbus_exception(EX_ILLEGAL_DATA_ADDRESS);
      return;
    }
    total_registers += registers;
  }

  result_size = (requests * 2) + (total_registers * sizeof(short));
  if (result_size + 2 * sizeof(char) >= 253)
    goto illegal_data_value;

  modbus_out_cnt = 0;
  modbus_out[modbus_out_cnt++] = modbus_unit;
  modbus_out[modbus_out_cnt++] = FC_READ_FILE_RECORD;
  modbus_out[modbus_out_cnt++] = result_size;

  for (int i = 0;i < requests;i++) {
    unsigned short file = modbus_get_short(4 + (i * 7));
    unsigned short record = modbus_get_short(6 + (i * 7));
    unsigned short registers = modbus_get_short(8 + (i * 7));
    unsigned short value;

    modbus_out[modbus_out_cnt++] = registers * sizeof(short) + 1;
    modbus_out[modbus_out_cnt++] = 6;

    for (int j = 0;j < registers;j++) {
      value = file_get_value(file, record, j);
      modbus_put_short(value);
    }
  }
#ifdef HAS_COUNTS
  event_count++;
#endif
  modbus_write();
}

void slave_write_file_record() {
  unsigned char byte_count = modbus_in[2];
  unsigned char requests = (modbus_in_cnt - 4) / 7;
  unsigned char base = 3;
  int total_registers = 0;
  unsigned char result_size = 0;
  int i = 0;

  /*
   * There are 5 bytes that aren't part of the request list.
   * The unit number, function code, byte count, and 2 bytes
   * for the CRC.
   */
  if (byte_count < 7 || byte_count != modbus_in_cnt - 5) {
illegal_data_value:
    modbus_exception(EX_ILLEGAL_DATA_VALUE);
    return;
  }

  while (base < byte_count) {
    char code = modbus_in[base];
    unsigned short file = modbus_get_short(base + 1);
    unsigned short record = modbus_get_short(base + 3);
    unsigned short registers = modbus_get_short(base + 5);

    if (code != 6)
      goto illegal_data_value;

    if (! file_check_entry(file, record, registers)) {
      modbus_exception(EX_ILLEGAL_DATA_ADDRESS);
      return;
    }
    base += 7;

    for (int j = 0;j < registers;j++)
      file_put_value(file, record, j, modbus_get_short(base + j * 2));

    base += registers * 2;
  }

  /*
   * This is safe because FILE commands require dual buffers, which is why the copy
   * has to be performed.
   */
  memcpy(modbus_out, modbus_in, modbus_in_cnt);
  modbus_out_cnt = modbus_in_cnt;

#ifdef HAS_COUNTS
  event_count++;
#endif
  modbus_write();
}
#endif

/*
 * slave_read_multiple_coils - Read one or more coils, using the get_coil() function.
 */
void slave_read_multiple_coils() {
  unsigned char function = modbus_in[1];
  unsigned short coil_start = modbus_get_short(2);
  unsigned short coil_count = modbus_get_short(4);
  unsigned char byte = 0;
  unsigned char mask = 0x1;
  unsigned char i, j;

  if (coil_start >= modbus_coils_cnt || coil_start + coil_count > modbus_coils_cnt || coil_count == 0) {
illegal_data_address:
    modbus_exception(EX_ILLEGAL_DATA_ADDRESS);
    return;
  }

  modbus_out_cnt = 0;
  modbus_out[modbus_out_cnt++] = modbus_unit;
  modbus_out[modbus_out_cnt++] = function;
  modbus_out[modbus_out_cnt++] = (coil_count + 7) >> 3;

  /*
   * Process coil values in 1 byte chunks.  The bits are handled inside the loop.
   */
  for (i = 0;i < coil_count;i += 8) {
    byte = 0;
    mask = 1;

    /*
     * Now process the bits.
     */
    for (j = i;j < coil_count;j++) {
      char coil_value = get_coil(j + coil_start);
      if (coil_value == (char) -1)
        goto illegal_data_address;
      else if (coil_value != 0)
        byte |= mask;

      mask <<= 1;
    }
    modbus_out[modbus_out_cnt++] = byte;
  }
#ifdef HAS_COUNTS
  event_count++;
#endif
  modbus_write();
}

void slave_write_single_coil() {
  unsigned short coil_address = modbus_get_short(2);
  unsigned short coil_value = modbus_get_short(4);

  if (coil_value != 0x0000 && coil_value != 0xFF00) {
    modbus_exception(EX_ILLEGAL_DATA_VALUE);
    return;
  }

  if (! set_coil(coil_address, coil_value != 0)) {
illegal_data_address:
    modbus_exception(EX_ILLEGAL_DATA_ADDRESS);
    return;
  }
  modbus_out_cnt = 0;
  modbus_out[modbus_out_cnt++] = modbus_unit;
  modbus_out[modbus_out_cnt++] = FC_WRITE_SINGLE_COIL;
  modbus_put_short(coil_address);
  modbus_put_short(coil_value);

#ifdef HAS_COUNTS
  event_count++;
#endif
  modbus_write();
}

#ifdef HAS_COUNTS
void slave_get_comm_event_counter() {
  modbus_out_cnt = 0;

  modbus_out[modbus_out_cnt++] = modbus_unit;
  modbus_out[modbus_out_cnt++] = FC_GET_COMM_EVENT_COUNTER;

  /*
   * This isn't a programmable device, so it is never busy.
   */
  modbus_put_short(0);
  modbus_put_short(event_count);

  /*
   * This modbus_write() call doesn't count as a message.
   */
  modbus_write();
}
#endif

#ifdef HAS_LOG
void slave_get_comm_event_log() {
  unsigned char log_count;
  unsigned char message_start;

  if (message_bytes_wrapped) {
    log_count = 64;
  } else {
    log_count = message_bytes_cnt;
  }
  modbus_out_cnt = 0;

  modbus_out[modbus_out_cnt++] = modbus_unit;
  modbus_out[modbus_out_cnt++] = FC_GET_COMM_EVENT_LOG;
  modbus_out[modbus_out_cnt++] = 6 + log_count;

  /*
   * This isn't a programmable device, so it is never busy.
   */
  modbus_put_short(0);
  modbus_put_short(event_count);
  modbus_put_short(message_count);

  for (unsigned char i = log_count;i > 0;i--)
    modbus_out[modbus_out_cnt++] = message_bytes[(message_start + i - 1) & 0x3F];

  event_count++;
  modbus_write();
}
#endif

#ifdef HAS_MULTI
/*
 * slave_write_multiple_coils - Write one or more coils, using the set_coil() function.
 */
void slave_write_multiple_coils() {
  unsigned int set_count = 0;
  unsigned short coil_start = modbus_get_short(2);
  unsigned short coil_count = modbus_get_short(4);
  unsigned char  byte_count = modbus_in[6];
  unsigned char byte = 0;
  unsigned char mask = 0x1;
  unsigned char i, j;
  unsigned char is_broadcast = modbus_in[0] == 0;

  /*
   * Make sure all the coils can be written before any of the coils are written.
   */
  for (i = 0;i < coil_count;i++) {
    if (! is_coil_setable(coil_start + i)) {
      if (! is_broadcast)
        modbus_exception(EX_ILLEGAL_DATA_ADDRESS);

      return;
    }
  }

  if ((coil_count + 7) >> 3 != byte_count) {
    if (! is_broadcast)
      modbus_exception(EX_ILLEGAL_DATA_VALUE);

    return;
  }

  /*
   * Process the coils in bytes, then process the bits inside the loop.
   */
  for (i = 0;i < coil_count;i += 8) {
    byte = modbus_in[7 + (i / 8)];
    mask = 1;

    for (j = i;j < coil_count;j++) {
      set_coil(j + coil_start, (byte & mask) ? 1:0);
      mask <<= 1;
    }
  }

#ifdef HAS_COUNTS
  event_count++;
#endif
  if (is_broadcast)
    return;

  modbus_out_cnt = 0;

  modbus_out[modbus_out_cnt++] = modbus_unit;
  modbus_out[modbus_out_cnt++] = FC_WRITE_MULTIPLE_COILS;
  modbus_put_short(coil_start);
  modbus_put_short(coil_count);

  modbus_write();
}
#endif

void slave_read_registers() {
  unsigned short address = modbus_get_short(2);
  unsigned short count = modbus_get_short(4);
  unsigned char i;
  unsigned char function;

  /*
   * Unsigned math means never knowing when you're going to wrap ...
   */
  if (address >= modbus_regs_cnt || (address + count) > modbus_regs_cnt) {
    modbus_exception(EX_ILLEGAL_DATA_ADDRESS);
    return;
  }
  function = modbus_in[1];

  modbus_out_cnt = 0;
  modbus_out[modbus_out_cnt++] = modbus_unit;
  modbus_out[modbus_out_cnt++] = function;
  modbus_out[modbus_out_cnt++] = 2 * count;

  for (i = 0;i < count;i++) {
    /*
     * Don't let a value change out from under our feet.
     */
    noInterrupts();
    modbus_put_short(modbus_regs[address + i]);
    interrupts();
  }
#ifdef HAS_COUNTS
  event_count++;
#endif
  modbus_write();
}

void slave_write_single_register() {
  unsigned short address = modbus_get_short(2);
  unsigned short value = modbus_get_short(4);
  unsigned char i;
  unsigned char is_broadcast = modbus_in[0] == 0;

  /*
   * Unsigned math means never knowing when you're going to wrap ...
   */
  if (address >= modbus_regs_cnt) {
    modbus_exception(EX_ILLEGAL_DATA_ADDRESS);
    return;
  }

  modbus_regs[address] = value;

#ifdef HAS_COUNTS
  event_count++;
#endif
  if (is_broadcast)
    return;

  modbus_out_cnt = 0;
  modbus_out[modbus_out_cnt++] = modbus_unit;
  modbus_out[modbus_out_cnt++] = FC_WRITE_SINGLE_REGISTER;
  modbus_put_short(address);
  modbus_put_short(value);

  modbus_write();
}

#ifdef HAS_MULTI
void slave_write_multiple_registers() {
  unsigned short address = modbus_get_short(2);
  unsigned short count = modbus_get_short(4);
  unsigned char  bytes = modbus_in_[6];
  unsigned char i;
  unsigned char is_broadcast = modbus_in[0] == 0;

  /*
   * Unsigned math means never knowing when you're going to wrap ...
   */
  if (address >= modbus_regs_cnt || (address + count) > modbus_regs_cnt) {
    if (! is_broadcast)
      modbus_exception(EX_ILLEGAL_DATA_ADDRESS);

    return;
  }

  /*
   * Verify the byte count against the register count.
   */
  if (count * 2 != bytes) {
    if (! is_broadcast)
      modbus_exception(EX_ILLEGAL_DATA_VALUE);

    return;
  }

  for (i = 0;i < count;i++)
    modbus_regs[address + i] = modbus_get_short(6 + (2 * i));

#ifdef HAS_COUNTS
  event_count++;
#endif
  if (is_broadcast)
    return;

  modbus_out_cnt = 0;
  modbus_out[modbus_out_cnt++] = modbus_unit;
  modbus_out[modbus_out_cnt++] = FC_WRITE_MULTIPLE_REGISTERS;
  modbus_put_short(address);
  modbus_put_short(count);

  modbus_write();
}
#endif

#ifdef HAS_SRVR_ID
void slave_report_server_id() {
  int  object_length;

  object_length = strlen_P(product_name);

  /*
   * The entire message must fit into the largest permissible packet.
   */
  if (object_length + 5 + sizeof(short) > MAX_PDU_OUT) {
    modbus_exception(EX_ILLEGAL_FUNCTION);
    return;
  }

  modbus_out_cnt = 0;
  modbus_out[modbus_out_cnt++] = modbus_unit;
  modbus_out[modbus_out_cnt++] = FC_REPORT_SERVER_ID;
  modbus_out[modbus_out_cnt++] = 2 + object_length;
  modbus_out[modbus_out_cnt++] = modbus_unit;
  modbus_out[modbus_out_cnt++] = 0xFF;

  strcpy_P((char *) modbus_out + modbus_out_cnt, product_name);
  modbus_out_cnt += object_length;

#ifdef HAS_COUNTS
  event_count++;
#endif
  modbus_write();
}
#endif

#ifdef HAS_MEI
void slave_read_device_identification() {
  char          i, j;
  char          cnt;
  char          mode;
  unsigned char object;
  unsigned char total;

  /*
   * "Read Device ID" is the only supported function.
   */
  if (modbus_in[2] != 0xE) {
    modbus_exception(EX_ILLEGAL_FUNCTION);
    return;
  }

  /*
   * Get the parameters from the packet.
   */
  mode = modbus_in[3];
  object = modbus_in[4];

  /*
   * Only read codes 1 (Basic Stream) and 4 (Individual Item) modes
   * are supported.
   */

  if (mode != 1 && mode != 4) {
    modbus_exception(EX_ILLEGAL_FUNCTION);
    return;
  }

  /*
   * Only objects 0, 1 and 2 are supported.
   */
  if (object > 2) {
    modbus_exception(EX_ILLEGAL_DATA_ADDRESS);
    return;
  }

  modbus_out_cnt = 0;
  modbus_out[modbus_out_cnt++] = modbus_unit;
  modbus_out[modbus_out_cnt++] = FC_READ_MEI;
  modbus_out[modbus_out_cnt++] = 0xE;
  modbus_out[modbus_out_cnt++] = mode;

  /*
   * This device supports both stream and individual access of the basic
   * fields, only.
   */
  modbus_out[modbus_out_cnt++] = 0x81;

  /*
   * It is very important that all three objects defined at the top are
   * able to fit into a single "basic" response.
   */
  if(mode == 1) {
    cnt = 3 - object;
  } else {
    cnt = 1;
  }

  total = 7;
  for(i = object, j = cnt;i < 3 && j > 0;i++, j--) {
    int object_length = 0;

    switch(i) {
      case 0:
        object_length = strlen_P(company_name);
        break;
      case 1:
        object_length = strlen_P(product_name);
        break;
      case 2:
        object_length = strlen_P(version_text);
        break;
    }

    if (total + object_length + 2 > (MAX_PDU_OUT-2))
      break;

    total += object_length + 2;
  }

  if (j > 0) {
    cnt -= j;

    /*
     * The "More Follows" value is "TRUE" and "Next ID" is the
     * first ID that didn't make it.
     */
    modbus_out[modbus_out_cnt++] = 0xFF;
    modbus_out[modbus_out_cnt++] = object + cnt;
  } else {
    /*
     * The "More Follows" and "Next ID" values are always 0 when
     * everything fits.
     */
    modbus_out[modbus_out_cnt++] = 0;
    modbus_out[modbus_out_cnt++] = 0;
  }
  modbus_out[modbus_out_cnt++] = cnt;

  for(i = object, j = cnt;i < 3 && j > 0;i++, j--) {
    int  object_length = 0;

    modbus_out[modbus_out_cnt++] = i;

    switch(i) {
      case 0:
        object_length = strlen_P(company_name);

        modbus_out[modbus_out_cnt++] = strlen_P(company_name);
        strcpy_P((char *) modbus_out + modbus_out_cnt, company_name);

        modbus_out_cnt += object_length;
        break;
      case 1:
        object_length = strlen_P(product_name);

        modbus_out[modbus_out_cnt++] = object_length;
        strcpy_P((char *) modbus_out + modbus_out_cnt, product_name);

        modbus_out_cnt += object_length;
        break;
      case 2:
        object_length = strlen_P(version_text);

        modbus_out[modbus_out_cnt++] = object_length;
        strcpy_P((char *) modbus_out + modbus_out_cnt, version_text);

        modbus_out_cnt += object_length;
        break;
    }
  }
#ifdef HAS_COUNTS
  event_count++;
#endif
  modbus_write();
}
#endif

/* End of Modbus library code. */

/*
 * User application.
 */
void loop() {
  unsigned char is_broadcast = 0;

  /*
   * Pet the nice doggy.
   */
  wdt_reset();

  /*
   * I need to know how many loops-per-second.  Because I just do.
   */
  if (++modbus_regs[REG_LOOP_LO] == 0)
    modbus_regs[REG_LOOP_HI]++;

  /*
   * Get the current time -- needed for LED blinking and a few other items.
   */
  last_millis = millis();

  /*
   * See if I must sample everything.  I do that every 10ms come rain or
   * shine.  Unless it has been more than 15ms, like, I was doing something ...
   */
  if (last_millis - last_sample > 10) {
    modbus_regs[REG_A0] = analogRead(A0);
    modbus_regs[REG_A1] = analogRead(A1);
    modbus_regs[REG_A2] = analogRead(A2);
    modbus_regs[REG_A3] = analogRead(A3);
    modbus_regs[REG_VREF] = analogRead(A5);

    /*
     * Get the state of the hardware interrupt input pins.
     */
    modbus_regs[REG_D0] = digitalRead(HARD_COUNT_0_PIN);
    modbus_regs[REG_D1] = digitalRead(HARD_COUNT_1_PIN);

    /*
     * Get the state of the other two that don't make interrupts.
     */
    modbus_regs[REG_D2] = digitalRead(DIGITAL_IN_2);
    modbus_regs[REG_D3] = digitalRead(DIGITAL_IN_3);

    if (last_millis - last_sample > 15)
      last_sample = last_millis;
    else
      last_sample += 10;
  }

  /*
   * A 1Hz signal is output on the LED pin whenever there are no
   * Modbus packets addressed to this unit.
   */
  if (! modbus_packet_check()) {
    /*
     * Manage the LED state for 1Hz blinking.
     */
    if (last_millis - last_led_flip > 500)
      flip_led();

    return;
  }

  /*
   * Ignore packets with CRC errors and those not addressed to us.
   */
  if (! modbus_check_crc()) {
#ifdef HAS_LOG
    if (modbus_in[0] == modbus_unit) {
      unsigned char log_value = 0x82;

      if (modbus_in_cnt == MAX_PDU_IN)
        log_value |= 0x10;

      modbus_add_comm_log_entry(log_value);
    }
#endif
    modbus_in_cnt = 0;
    return;
  }

  is_broadcast = modbus_in[0] == 0;

  if (modbus_unit != modbus_in[0] && ! is_broadcast) {
    modbus_in_cnt = 0;
    return;
  }

#ifdef HAS_LOG
  modbus_add_comm_log_entry(0x80 | (is_broadcast ? 0x40:0x00));
#endif

  /*
   * The greenSensors box has LEDs for Rx and Tx.  Here I just flip the LED
   * whenever I get a packet.
   */
  flip_led();

  switch(modbus_in[1]) {
    case FC_READ_COILS:
    case FC_READ_DISCRETE_INPUTS:
      if (is_broadcast)
        goto done;

      slave_read_multiple_coils();
      break;
    case FC_WRITE_SINGLE_COIL:
      slave_write_single_coil();
      break;
#ifdef HAS_COUNTS
    case FC_GET_COMM_EVENT_COUNTER:
      if (is_broadcast)
        goto done;

      slave_get_comm_event_counter();
      break;
#endif
#ifdef HAS_LOG
    case FC_GET_COMM_EVENT_LOG:
      if (is_broadcast)
        goto done;

      slave_get_comm_event_log();
      break;
#endif
#ifdef HAS_MULTI
    case FC_WRITE_MULTIPLE_COILS:
      slave_write_multiple_coils();
      break;
#endif
    case FC_READ_HOLDING_REGISTERS:
    case FC_READ_INPUT_REGISTERS:
      if (is_broadcast)
        goto done;

      slave_read_registers();
      break;
    case FC_WRITE_SINGLE_REGISTER:
      slave_write_single_register();

      update_eeprom();
      break;
#ifdef HAS_MULTI
    case FC_WRITE_MULTIPLE_REGISTERS:
      slave_write_multiple_registers();

      update_eeprom();
      break;
#endif
#ifdef HAS_SRVR_ID
    case FC_REPORT_SERVER_ID:
      if (is_broadcast)
        goto done;

      slave_report_server_id();
      break;
#endif
#ifdef HAS_FIFO
    case FC_READ_FIFO:
      if (is_broadcast)
        goto done;

      slave_read_fifo();
      break;
#endif
#ifdef HAS_FILES
    case FC_READ_FILE_RECORD:
      if (is_broadcast)
        goto done;

      slave_read_file_record();
      break;
    case FC_WRITE_FILE_RECORD:
      slave_write_file_record();
      break;
#endif
#ifdef HAS_MEI
    case FC_READ_MEI:
      if (is_broadcast)
        goto done;

      slave_read_device_identification();
      break;
#endif
    default:
      if (is_broadcast)
        goto done;

      modbus_exception(EX_ILLEGAL_FUNCTION);
      break;
  }
done:
  modbus_in_cnt = 0;
}

error: pathspec 'src/sketches/OSS_DAQ/OSS_DAQ.ino' did not match any file(s) known to git


lots of tweaking with messaging between nirha 433 devices. still broken for floats

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/ekwoodrich/nirha.git/'


Take example from https://github.com/Fabio-Varesano-Association/freeimu/tree/master/libraries/MS561101BA/examples

/*
MS561101BA_altitude.pde - Computes altitude from sea level using pressure readings from the sensor.
The algorithm uses the Hypsometric formula as explained in http://keisan.casio.com/has10/SpecExec.cgi?path=06000000.Science%2F02100100.Earth%20science%2F12000300.Altitude%20from%20atmospheric%20pressure%2Fdefault.xml&charset=utf-8

Copyright (C) 2011 Fabio Varesano <fvaresano@yahoo.it>

Development of this code has been supported by the Department of Computer Science,
Universita' degli Studi di Torino, Italy within the Piemonte Project
http://www.piemonte.di.unito.it/

This program is free software: you can redistribute it and/or modify
it under the terms of the version 3 GNU General Public License as
published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/

//#define DEBUG_V

#include <Wire.h>
//#include <DebugUtils.h>
#include <MS561101BA.h>

#define MOVAVG_SIZE 32

MS561101BA baro = MS561101BA();

float movavg_buff[MOVAVG_SIZE];
int movavg_i=0;

const float sea_press = 1013.25;
float press, temperature;

void setup() {
  Wire.begin();
  Serial.begin(115200);
  delay(1000);

  // Suppose that the CSB pin is connected to GND.
  // You'll have to check this on your breakout schematics
  baro.init(MS561101BA_ADDR_CSB_LOW);
  delay(100);

  // populate movavg_buff before starting loop
  for(int i=0; i<MOVAVG_SIZE; i++) {
    movavg_buff[i] = baro.getPressure(MS561101BA_OSR_4096);
  }
}

void loop() {
  Serial.print(" temp: ");
  temperature = baro.getTemperature(MS561101BA_OSR_4096);
  Serial.print(temperature);
  Serial.print(" degC pres: ");

  press = baro.getPressure(MS561101BA_OSR_4096);
  pushAvg(press);
  press = getAvg(movavg_buff, MOVAVG_SIZE);
  Serial.print(press);
  Serial.print(" mbar altitude: ");
  Serial.print(getAltitude(press, temperature));
  Serial.println(" m");
}

float getAltitude(float press, float temp) {
  //return (1.0f - pow(press/101325.0f, 0.190295f)) * 4433000.0f;
  return ((pow((sea_press / press), 1/5.257) - 1.0) * (temp + 273.15)) / 0.0065;
}

void pushAvg(float val) {
  movavg_buff[movavg_i] = val;
  movavg_i = (movavg_i + 1) % MOVAVG_SIZE;
}

float getAvg(float * buff, int size) {
  float sum = 0.0;
  for(int i=0; i<size; i++) {
    sum += buff[i];
  }
  return sum / size;
}

error: pathspec 'Arduino/MS561101BA_altitude/MS561101BA_altitude.ino' did not match any file(s) known to git


moved beacon project folder

moved beacon project folder

#include <EEPROM.h>
#include "EEPROMAnything.h"

const int ledPin = 13;
int dotDelay = 100; // milliseconds
const int gapBetweenRepeats = 10; // seconds
const int maxMessageLen = 255;
char message[maxMessageLen];
long lastFlashTime = 0;

char* letters[] = {
  ".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..",    // A-I
  ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.",  // J-R
  "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--.."          // S-Z
};

char* numbers[] = {"-----", ".----", "..---", "...--", "....-", ".....", "-....", "--...", "---..", "----."};

void setup()
{
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
  Serial.println("Ready");
  EEPROM_readAnything(0, message);
  if (! isalnum(message[0]))
  {
    strcpy(message, "SOS");
  }
  flashMessage();
}

void loop()
{
  char ch;
  if (Serial.available())      // is there anything to be read from USB?
  {
    int n = Serial.readBytesUntil('\n', message, maxMessageLen-1);
    message[n] = '\0';
    EEPROM_writeAnything(0, message);
    Serial.println(message);
    flashMessage();
  }
  if (millis() > lastFlashTime + gapBetweenRepeats * 1000L)
  {
    flashMessage();
  }
}

void flashMessage()
{
  Serial.print("Sending: ");
  Serial.println(message);
  int i = 0;
  while (message[i] != '\0' && i < maxMessageLen)
  {
    if (Serial.available()) return;  // new message
    char ch = message[i];
    i++;
    if (ch >= 'a' && ch <= 'z')
    {
      flashSequence(letters[ch - 'a']);
    }
    else if (ch >= 'A' && ch <= 'Z')
    {
      flashSequence(letters[ch - 'A']);
    }
    else if (ch >= '0' && ch <= '9')
    {
      flashSequence(numbers[ch - '0']);
    }
    else if (ch == ' ')
    {
     delay(dotDelay * 4);      // gap between words
    }
  }
  lastFlashTime = millis();
}

void flashSequence(char* sequence)
{
   int i = 0;
   while (sequence[i] != NULL)
   {
       flashDotOrDash(sequence[i]);
       i++;
   }
   delay(dotDelay * 3);    // gap between letters
}

void flashDotOrDash(char dotOrDash)
{
  digitalWrite(ledPin, HIGH);
  if (dotOrDash == '.')
  {
    delay(dotDelay);
  }
  else // must be a -
  {
    delay(dotDelay * 3);
  }
  digitalWrite(ledPin, LOW);
  delay(dotDelay); // gap between flashes
}

error: pathspec 'Arduino/Project_19_Morse_Beacon/Project_19_Morse_Beacon.ino' did not match any file(s) known to git


Recovered arduino due code

Recovered arduino due code

/*
lab-nanny Firmware

Controller of the arduino that sends data from the inputs and performs actions depending
on the messages received.

Analog input on the analog pins is read-in at a sampling rate of ~xyz kS/s
The sampling rate can be adjusted for more channels, or slower sampling rate,
[channels must be enabled/disabled by setting the registers in the setup() method below],
by adjusting the sampling_time variable

PySerial is used to grab the data from the serial port and read it into python.

************
** NOTE: the USB connection to the Arduino must be to the NATIVE port, not the programming port!
************

Author: David Paredes
30/09/2015

Adapted from James Keaveney's https://github.com/jameskeaveney/LiveArduinoData

*/

// set up variables
const int buffer_length = 1; // length of data chunks sent at a time via SerialUSB

const int sampling_time_sleep = 50; // in micros
unsigned long init_time = 0;
int ledPin = 13;
int maxDIPin = 14;
int commandNumber =0;

String strTime = "";
String strOut = "";
String strC0 = "";
String strC1 = "";
String strC2 = "";
String strC3 = "";
String strC4 = "";
String strC5 = "";
String strC6 = "";
String strC7 = "";
String strC8 = "";
String strC9 = "";
String strC10 = "";
String strC11 = "";

/* To enable channels  (see page 1338 of datasheet) of the AX pins.
See 1320 of datasheet for conversion ADXX->PAXX
See also http://www.arduino.cc/en/Hacking/PinMappingSAM3X for the pin mapping
between Arduino names and SAM3X pin names
*/

const int A0_PIN  = 0b10000000;
const int A1_PIN  = 0b1000000;
const int A2_PIN  = 0b100000;
const int A3_PIN  = 0b10000;
const int A4_PIN  = 0b1000;
const int A5_PIN  = 0b100;
const int A6_PIN  = 0b10;
const int A7_PIN  = 0b1;
const int A8_PIN  = 0b10000000000;
const int A9_PIN  = 0b100000000000;
const int A10_PIN = 0b1000000000000;
const int A11_PIN = 0b10000000000000;

/* The PIN_MAP is a mask that specifices which analog channels to read. It can be
 * constructed as the sum of the different AX_PIN constants. */

const int PIN_MAP = A0_PIN+A1_PIN+A2_PIN+A3_PIN+A4_PIN+A5_PIN+A6_PIN+A7_PIN;

 // There might be a problem if we "activate" a lot of the channels but they are not connected:
 // the "floating" signal wiggles when the rest of the lines are changed.
unsigned long current_time;

void setup() {

  // set ADC resolution
  analogReadResolution(12);

  // manually set registers for faster analog reading than the normal arduino methods
  ADC->ADC_MR |= 0xC0; // set free running mode (page 1333 of the Sam3X datasheet)
  ADC->ADC_CHER = PIN_MAP;
  ADC->ADC_CHDR = 0xFFFF-PIN_MAP; // disable all other channels
  ADC->ADC_CR=2;        // begin ADC conversion

  // initialise serial port
  SerialUSB.begin(115200); // baud rate is ignored for USB - always at 12 Mb/s
  while (!SerialUSB); // wait for USB serial port to be connected - wait for pc program to open the serial port
  init_time =millis();
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(13, OUTPUT);
  pinMode(14, OUTPUT);

}

void loop() {

  // data acquisition will start with a synchronisation step:
  // python should send a single byte of data, the arduino will send one back to sync timeouts
  int incoming = 0;
  if (SerialUSB.available() > 0) // polls whether anything is ready on the read buffer - nothing happens until there's something there
  {
    incoming = SerialUSB.read();
    // after data received, send the same back
    // if abs(incoming)<maxDIPin  (14 in this case)
    commandNumber = incoming-65;
    if (abs(commandNumber)<=maxDIPin){
      if (commandNumber>=0){
        digitalWrite(abs(commandNumber),HIGH);
            SerialUSB.println(abs(commandNumber));
      }   // Can be done faster toggling if PIND used
      else{
        digitalWrite(abs(commandNumber)-1,LOW);
        SerialUSB.println(abs(commandNumber)-1);
      }
    }
    else{SerialUSB.println(incoming);
    }

    // measure start time - then acquire data for an amount of time set by the acquisition_time variable
    unsigned long start_micros = micros();
    unsigned long start_time = millis();

    /*  Generate and concatenate strings.
     *  In principle, this loop can be improved by just sending the byte
     *  information of the different inputs */
    for (int jj = 0; jj < buffer_length; jj++)
    {

      // ADC acquisition

      // can put this in a small loop for some averaging if required - takes ~ 60 microsec per read/concatenate cycle
      while((ADC->ADC_ISR & 0x80)!=0x80); // wait for conversion to complete - see page 1345 of datasheet
      // concatenate strings
      current_time = millis()-init_time;
      strTime.concat(current_time); // time axis
      strTime.concat(',');
      strC0.concat(ADC->ADC_CDR[7]); // read data from the channel data register
      strC0.concat(',');
      strC1.concat(ADC->ADC_CDR[6]); // read data from the channel data register
      strC1.concat(',');
      strC2.concat(ADC->ADC_CDR[5]); // read data from the channel data register
      strC2.concat(',');
      strC3.concat(ADC->ADC_CDR[4]); // read data from the channel data register
      strC3.concat(',');
      strC4.concat(ADC->ADC_CDR[3]); // read data from the channel data register
      strC4.concat(',');
      strC5.concat(ADC->ADC_CDR[2]); // read data from the channel data register
      strC5.concat(',');
      strC6.concat(ADC->ADC_CDR[1]); // read data from the channel data register
      strC6.concat(',');
      strC7.concat(ADC->ADC_CDR[0]); // read data from the channel data register
      strC7.concat(',');

      //Serial.print(current_time);
      //Serial.print(",");

      delayMicroseconds(sampling_time_sleep); // limit sampling rate to something reasonable - a few kS/s
    }
    // send data via SerialUSB
    // perform a flush first to wait for the previous buffer to be sent, before overwriting it
    SerialUSB.flush();
    strOut = strTime + strC0 + strC1 + strC2 + strC3 + strC4 + strC5 + strC6 + strC7;
    SerialUSB.print(strOut); // doesn't wait for write to complete before moving on

    // clear string data - re-initialise
    strTime = "";
    strC0 = "";
    strC1 = "";
    strC2 = "";
    strC3 = "";
    strC4 = "";
    strC5 = "";
    strC6 = "";
    strC7 = "";
    strC8 = "";
    strC9 = "";
    // finally, print end-of-data and end-of-line character to signify no more data will be coming
    SerialUSB.println("\0");

  }
}

error: pathspec 'arduino_firmware_io_due/arduino_firmware_io_due.ino' did not match any file(s) known to git


Add example to help find suitable contrast value.

/** Contrast Helper
 *
 *  Loops through a range of contrast values and prints each one.
 *
 *  To set the contrast in your sketch, simply put lcd.setContrast(xx);
 *  after your lcd.begin().
 *
 *  Experimentally determined, contrast values around 65-70 tend to
 *  work reasonably well on most displays.  The best contrast value
 *  for each display is specific to that particular display due to
 *  manufacturing tolerances and so forth.
 *
 */

#include <SPI.h>
#include "PCD8544_Simple.h"

PCD8544_Simple lcd;
const uint8_t contrastMin = 40;
const uint8_t contrastMax = 80;
static uint8_t contrastDirection = 1;
static uint8_t contrast = (contrastMax-contrastMin)/2+contrastMin;

void setup()
{
  lcd.begin();
}

void loop()
{
  if(contrastDirection)
  {
    if(contrast++ > contrastMax)
    {
      contrastDirection = 0;
    }
  }
  else
  {
    if(contrast-- < contrastMin)
    {
      contrastDirection = 1;
    }
  }

  lcd.setContrast(contrast);
  lcd.print("lcd.setContrast(");
  lcd.print(contrast);
  lcd.println(");");

  delay(500);
}

error: pathspec 'examples/A01_ContrastHelper/A01_ContrastHelper.ino' did not match any file(s) known to git


<BIG>change expl logic; add explain

<BIG>change expl logic; add explain

error: pathspec 'exploration' did not match any file(s) known to git
error: pathspec 'testing/src/main.ino' did not match any file(s) known to git


* 0.95 for tuninng

* 0.95 for tuninng


arduino bluetooth test between Serial Monitor and an external connection to the bluetooth module

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/nverdicchio/soa-2017-bicicleta-inteligente.git/'


Update Templete.ino

Update Templete.ino

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/SirenCreatorTeam/Siren_Zwei.git/'


Adição de um exemplo básico

Adição de um exemplo básico

#include<CS5490.h>

CS5490 line(MCLK_default,14,12);

void setup() {
  //Inicializa a comunicação com o CS5490
  //600 é a velocidade default do CI para comunicação serial
  line.begin(600);
  //Inicializa a comunicação com o PC para debug
  Serial.begin(9600);
}

void loop() {

  //Obtem informação da configuração de calibração do ganho de corrente
  line.getGainI();

  //Printa essa informação no Serial Monitor
  Serial.println("A informação coletada é: ");
  Serial.println(line.data[0]);
  Serial.println(line.data[1]);
  Serial.println(line.data[2]);
  Serial.println("\n\n");

  delay(5000);
}

error: pathspec 'examples/CS5490_Basics.ino' did not match any file(s) known to git


Added example sketch

Added example sketch

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/CanTireInnovations/ArduinoJson.git/'


Add Arduino Sketch for the car

Add Arduino Sketch for the car

#include <NewPing.h>

// Pins for ultrasonic sensors (HC-SR04).
#define FRONT_US 9
#define LEFT_US  8
#define RIGHT_US 7

// Baud rate for UART
#define BAUD_RATE 115200

// Pins for external speed control input.
#define SPEED_INPUT2 A0
#define SPEED_INPUT1 A1
#define SPEED_INPUT0 A2

// Pins for controlling the acceleration motors.
#define SPEED_MOTOR_PIN1 11
#define SPEED_MOTOR_PIN0 10

// Pins for external turn control input.
#define TURN_INPUT2 A3
#define TURN_INPUT1 A4
#define TURN_INPUT0 A5

// Pins for controlling the turn motors.
#define TURN_MOTOR_PIN1 6
#define TURN_MOTOR_PIN0 5

// Number of distance sensors.
#define NUM_SENSORS 3

// Constants defining direction of motion.
#define MOVE_FORWARD  0
#define MOVE_BACKWARD 1

// Constants defining direction of turn.
#define TURN_LEFT  1
#define TURN_RIGHT 0

// FUNCTION DECLARATIONS
void echoCheck();
void writeDistanceData();
void initSpeedPins();
unsigned int readSpeedInput();
void writeSpeedData(unsigned int direction, unsigned int percent);
void initTurnPins();
unsigned int readTurnInput();
void writeTurnData(unsigned int direction, unsigned int percent);

NewPing sonar[NUM_SENSORS] = {{FRONT_US, FRONT_US, 200},   // sonar[0] => front sensor
                              {LEFT_US,  LEFT_US,  200},   // sonar[1] => left  sensor
                              {RIGHT_US, RIGHT_US, 200}};  // sonar[2] => right sensor
unsigned int pingSpeed = 50;      // Time (in milliseconds) between every distance sensor ping.
unsigned long pingTimer;          // Holds the next ping time (in milliseconds).
unsigned long data[NUM_SENSORS];  // Holds the ping sensor data (in cm).
unsigned int currentSensor;       // Indicates the sensor to collect data from

/**
 * Sets up I/O pins.
 * Sets up UART for communication with Raspberry Pi.
 * Initializes global variables.
 * Initializes Timer2 for ultrasonic sensor data recording.
 *
 * Input: None
 * Output: None
 */
void setup() {
  initSpeedPins();
  initTurnPins();
  Serial.begin(BAUD_RATE);  // UART setup

  for (int i = 0; i < NUM_SENSORS; ++i) {
    data[i] = 0;
  }

  pingTimer = millis();  // Start ultrasonic sensor timer.
}

/**
 * This is the main thread of execution of the system. It does the following:
 *
 *   1. Update distance sensor timer data for Timer2 and read distance data.
 *   2. Read data for and configure speed control motors.
 *   3. Read data for and configure turn control motors.
 *
 * in a continuous loop.
 *
 * Input: None
 * Output: None
 */
void loop() {
  // update distance data output
  if (millis() >= pingTimer) {    // pingSpeed milliseconds since last ping, do another ping.
    pingTimer += pingSpeed;       // Set the next ping time.

    // query each sensor sequentially
    for (currentSensor = 0; currentSensor < NUM_SENSORS; ++currentSensor) {
      sonar[currentSensor].ping_timer(echoCheck);
    }

    writeDistanceData();  // update UART output
  }

  // update speed motor output
  unsigned int speedInput = readSpeedInput();
  unsigned int speedPercent = 0;
  switch (speedInput & 0x03) {
    case 1: speedPercent = 33;  break;
    case 2: speedPercent = 67;  break;
    case 3: speedPercent = 100; break;
  }
  writeSpeedData(speedInput >> 2, speedPercent);

  // update turn motor output
  unsigned int turnInput = readTurnInput();
  unsigned int turnPercent = 0;
  switch (turnInput & 0x03) {
    case 1: turnPercent = 33;  break;
    case 2: turnPercent = 67;  break;
    case 3: turnPercent = 100; break;
  }
  writeTurnData(turnInput >> 2, turnPercent);
}

/**
 * Timer2 ISR to read distance data from sensor "currentSensor" into
 * data[currentSensor].
 *
 * Input: None
 * Output: None
 */
void echoCheck() {
  if (sonar[currentSensor].check_timer()) {  // Check if the ping was received.
    // collect the data from the sensor
    data[currentSensor] = sonar[currentSensor].ping_result / US_ROUNDTRIP_CM;
  }
}

/**
 * Writes the distance data into the UART, in the following order
 *
 * data[0]'\r\n'
 * data[1]'\r\n'
 * data[2]'\r\n'
 * ...
 * data[NUM_SENSORS - 1]'\r\n'
 *
 * Input: None
 * Output: None
 */
void writeDistanceData() {
  for (int i = 0; i < NUM_SENSORS; ++i) {
    Serial.println(data[i]);
  }
}

/**
 * Initializes pins for speed control I/O.
 *
 * Input: None
 * Output: None
 */
void initSpeedPins() {
  pinMode(SPEED_INPUT2, INPUT);
  pinMode(SPEED_INPUT1, INPUT);
  pinMode(SPEED_INPUT0, INPUT);
  pinMode(SPEED_MOTOR_PIN1, OUTPUT);
  pinMode(SPEED_MOTOR_PIN0, OUTPUT);
}

/**
 * Reads and returns speed control data, which is in the range [0,3].
 *
 * Data in [0,3] signifies forward motion, with each higher number signifying
 * higher speed.
 *
 * Data in [4,7] signifies backward motion, with each higher number signifying
 * higher speed.
 *
 * Requires the following pins to be set to INPUT mode:
 *   SPEED_INPUT2
 *   SPEED_INPUT1
 *   SPEED_INPUT0
 *
 * Input: None
 * Output: Speed data in the range [0,7]
 */
unsigned int readSpeedInput() {
  // read bit 2
  unsigned int data = (digitalRead(SPEED_INPUT2) == HIGH) ? (4) : (0);

  // read bit 1
  data += (digitalRead(SPEED_INPUT1) == HIGH) ? (2) : (0);

  // read bit 0
  data += (digitalRead(SPEED_INPUT0) == HIGH) ? (1) : (0);

  return data;
}

/**
 * Configure the speed control motors to run at 'percent' percentage of their
 * capacity. Consequently,
 *
 *   1. direction must be either MOVE_FORWARD or MOVE_BACKWARD
 *   2. 0 <= percent <= 100.
 *
 * Requires the following pins to be not set to INPUT mode:
 *   SPEED_MOTOR_PIN1
 *   SPEED_MOTOR_PIN0
 *
 * Input: direction : Direction of the car's motion
 *        percent :   Speed of the car in percentage terms.
 * Output: None
 */
void writeSpeedData(unsigned int direction, unsigned int percent) {
  switch (direction) {
    case MOVE_FORWARD: analogWrite(SPEED_MOTOR_PIN1, percent * 2.55);
                       analogWrite(SPEED_MOTOR_PIN0, 0);
                       break;

    case MOVE_BACKWARD: analogWrite(SPEED_MOTOR_PIN1, 0);
                        analogWrite(SPEED_MOTOR_PIN0, percent * 2.55);
                        break;

    default: analogWrite(SPEED_MOTOR_PIN1, 0);
             analogWrite(SPEED_MOTOR_PIN0, 0);
  }
}

/**
 * Initializes pins for turn control I/O.
 *
 * Input: None
 * Output: None
 */
void initTurnPins() {
  pinMode(TURN_INPUT2, INPUT);
  pinMode(TURN_INPUT1, INPUT);
  pinMode(TURN_INPUT0, INPUT);
  pinMode(TURN_MOTOR_PIN1, OUTPUT);
  pinMode(TURN_MOTOR_PIN0, OUTPUT);
}

/**
 * Reads and returns turn control data, which is in the range [0,7].
 *
 * Data in [0,3] signifies right turn, with each higher number signifying
 * a higher degree of turn.
 *
 * Data in [4,7] signifies left turn, with each higher number signifying
 * a higher degree of turn.
 *
 * Requires the following pins to be set to INPUT mode:
 *   TURN_INPUT2
 *   TURN_INPUT1
 *   TURN_INPUT0
 *
 * Input: None
 * Output: Turn data in the range [0,7].
 */
unsigned int readTurnInput() {
  // read bit 2
  unsigned int data = (digitalRead(TURN_INPUT2) == HIGH) ? (4) : (0);

  // read bit 1
  data += (digitalRead(TURN_INPUT1) == HIGH) ? (2) : (0);

  // read bit 0
  data += (digitalRead(TURN_INPUT0) == HIGH) ? (1) : (0);

  return data;
}

/**
 * Configures the turn motors to turn in 'percent' percentage in
 * 'direction' direction. Consequently,
 *
 *   1. direction must be either TURN_LEFT or TURN_RIGHT
 *   2. 0 <= percent <= 100
 *
 * Requires the following pins to be not set to INPUT mode:
 *   TURN_MOTOR_PIN1
 *   TURN_MOTOR_PIN0
 *
 * Input: direction : Direction of the car's turn.
 *        percent   : Degree of the car's turn in percentage terms.
 * Output: None
 */
void writeTurnData(unsigned int direction, unsigned int percent) {
  switch (direction) {
    case TURN_LEFT: analogWrite(TURN_MOTOR_PIN1, percent * 2.55);
                    analogWrite(TURN_MOTOR_PIN0, 0);
                    break;

    case TURN_RIGHT: analogWrite(TURN_MOTOR_PIN1, 0);
                     analogWrite(TURN_MOTOR_PIN0, percent * 2.55);
                     break;

    default: analogWrite(TURN_MOTOR_PIN1, 0);
             analogWrite(TURN_MOTOR_PIN0, 0);
  }
}

error: pathspec 'Arduino/car.ino' did not match any file(s) known to git