Add SNES controller with Macro support

Add SNES controller with Macro support

// This project uses 4 8-bit shift register, such as 74HC595 or HCF4094, in cascading format
/*
  SNES Controller v1.0 for Arduino UNO by WhatAboutGaming
  For use in the Twitch.TV stream TwitchTriesToPlay.
  https://www.twitch.tv/twitchtriestoplay
  https://github.com/WhatAboutGaming/Twitch-Plays-Stuff

  Reference:
  https://github.com/marcosassis/gamepaduino/wiki/SNES-controller-interface
  https://www.repairfaq.org/REPAIR/F_SNES.html
*/

#define latchPin 2 // HCF4094/74HC595 Latch/Strobe Input
#define dataPin 3 // HCF4094/74HC595 Data Input
#define clockPin 4 // HCF4094/74HC595 Clock Input

#define buttonB 0 // Left 3
#define buttonY 1 // Left 4
#define buttonSelect 2 // Left 5
#define buttonStart 3 // Left 6

#define buttonUp 4 // Left 7
#define buttonDown 5 // Left 8
#define buttonLeft A0 // Left 9
#define buttonRight 7 // Left 10

#define buttonA 8 // Left 11
#define buttonX 9 // Left 12

#define buttonLHalf 10 // Left 13
#define buttonLFull 11 // Left 13
#define buttonRHalf 12 // Left 14
#define buttonRFull 13 // Left 14

#define startingMacroIndex 0x40
#define endingMacroIndex 0x80

unsigned int macroIndex = 0;
unsigned int currentMacroIndexRunning = 0;
unsigned int macroInputsToRun = 0;
unsigned int loopMacro = 0; //0 = Don't loop, 1 = loop
unsigned int timesToLoop = 0; //0 = Loop indefinitely, >0 = loop n times
unsigned int loopCounter = 0;

bool defaultStatus[] = {LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW};
bool inputStatus[] =   {LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW};
unsigned int commandArray[] = {buttonB, buttonY, buttonSelect, buttonStart, buttonUp, buttonDown, buttonLeft, buttonRight, buttonA, buttonX, buttonLHalf, buttonLFull, buttonRHalf, buttonRFull, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};

boolean isInputting = false;
boolean isInputtingDelayed = false;

unsigned long inputDelay = 0;
unsigned long previousInputDelay = 0;
unsigned long currentMillis = 0;

unsigned long baudRate = 2000000;

byte serial_rx_buffer[12];
byte current_macro_input[12];
byte macro_buffer[64][12];
unsigned long controller = 0;

void setup()
{
  Serial.begin(baudRate);

  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(buttonLeft, OUTPUT);

  digitalWrite(latchPin, LOW);
  for (int i = 31; i >= 0; i--)
  {
    digitalWrite(clockPin, LOW);
    digitalWrite(dataPin, !defaultStatus[i]);
    digitalWrite(buttonLeft, !defaultStatus[1]);
    digitalWrite(clockPin, HIGH);
  }
  digitalWrite(latchPin, HIGH);

  //  Reset everything
  serial_rx_buffer[0] = 0x00;
  serial_rx_buffer[1] = 0x00;
  serial_rx_buffer[2] = 0x00;
  serial_rx_buffer[3] = 0x00;
  serial_rx_buffer[4] = 0x00;
  serial_rx_buffer[5] = 0x00;
  serial_rx_buffer[6] = 0x00;
  serial_rx_buffer[7] = 0x00;
  serial_rx_buffer[8] = 0x00;
  serial_rx_buffer[9] = 0x00;
  serial_rx_buffer[10] = 0x00;
  serial_rx_buffer[11] = 0x00;

  current_macro_input[0] = 0x00;
  current_macro_input[1] = 0x00;
  current_macro_input[2] = 0x00;
  current_macro_input[3] = 0x00;
  current_macro_input[4] = 0x00;
  current_macro_input[5] = 0x00;
  current_macro_input[6] = 0x00;
  current_macro_input[7] = 0x00;
  current_macro_input[8] = 0x00;
  current_macro_input[9] = 0x00;
  current_macro_input[10] = 0x00;
  current_macro_input[11] = 0x00;
}

void loop()
{
  currentMillis = millis();
  if (Serial.available() > 0)
  {
    controller = Serial.readBytes(serial_rx_buffer, sizeof(serial_rx_buffer)) && 0xFF;

    //  Set Start Byte (Preamble Byte) and End Byte (Postamble Byte)
    //  1 == 0x01
    if ((serial_rx_buffer[0] == 0x01) && (serial_rx_buffer[11] == 0x01))
    {
      for (unsigned int currentInputIndex = 0; currentInputIndex < sizeof(serial_rx_buffer); currentInputIndex++) {
        current_macro_input[currentInputIndex] = serial_rx_buffer[currentInputIndex];
      }
      // Make the button presses actually work
      macroIndex = 0;
      currentMacroIndexRunning = 0;
      macroInputsToRun = 0;
      loopMacro = 0;
      timesToLoop = 0;
      loopCounter = 0;
      isInputting = true;
      previousInputDelay = currentMillis;
    }
    if ((serial_rx_buffer[0] >= startingMacroIndex) && (serial_rx_buffer[11] >= startingMacroIndex))
    {
      if ((serial_rx_buffer[0] < endingMacroIndex) && (serial_rx_buffer[11] < endingMacroIndex))
      {
        if (serial_rx_buffer[0] == serial_rx_buffer[11]) {
          // Stop the current loop when we receive a new macro
          macroIndex = 0;
          currentMacroIndexRunning = 0;
          macroInputsToRun = 0;
          loopMacro = 0;
          timesToLoop = 0;
          loopCounter = 0;
          //isInputting = false;
          macroIndex = serial_rx_buffer[0] - startingMacroIndex;
          /*
            Serial.print("Received ");
            Serial.print(serial_rx_buffer[0]);

            Serial.print(" macro index ");
            Serial.println(macroIndex);
          */
          for (unsigned int macroInputIndex = 0; macroInputIndex < sizeof(serial_rx_buffer); macroInputIndex++) {
            macro_buffer[macroIndex][macroInputIndex] = serial_rx_buffer[macroInputIndex];
            //Serial.println(macro_buffer[macroIndex][macroInputIndex]);
          }
        }
      }
    }
    if ((serial_rx_buffer[0] == 0x80) && (serial_rx_buffer[11] == 0x80))
    {
      // Stop the current loop when we receive a new macro setter (The thing that tells how a macro should be executed, if it should loop, how many inputs it has to iterate through)
      macroIndex = 0;
      currentMacroIndexRunning = 0;
      macroInputsToRun = 0;
      loopMacro = 0;
      timesToLoop = 0;
      loopCounter = 0;
      isInputting = false;

      macroInputsToRun = serial_rx_buffer[1];
      loopMacro = serial_rx_buffer[2];
      currentMacroIndexRunning = serial_rx_buffer[3];
      timesToLoop = serial_rx_buffer[4];
      loopCounter = serial_rx_buffer[5];
      //isInputting = true;
      //previousInputDelay = currentMillis;
    }
  }
  runMacro();
  pressButtons();
} // Close Loop Function

void runMacro()
{
  if (isInputting == false) {
    if (macroInputsToRun != 0) {
      if (macroInputsToRun > currentMacroIndexRunning)
      {
        if (loopCounter <= timesToLoop) {
          for (unsigned int currentInputIndex = 0; currentInputIndex < sizeof(serial_rx_buffer); currentInputIndex++) {
            current_macro_input[currentInputIndex] = macro_buffer[currentMacroIndexRunning][currentInputIndex];
            //Serial.println(macro_buffer[currentMacroIndexRunning][currentInputIndex]);
          }
          // Make the button presses actually work
          isInputting = true;
          previousInputDelay = currentMillis;
        }
      }
      if (currentMacroIndexRunning < macroInputsToRun) {
        currentMacroIndexRunning++;
      }
      if (loopMacro != 0) {
        if (currentMacroIndexRunning >= macroInputsToRun) {
          currentMacroIndexRunning = 0;
          if (timesToLoop <= 0) {
            //
          }
          if (timesToLoop > 0 && loopCounter <= timesToLoop) {
            //Serial.print(loopCounter);
            //Serial.print(" ");
            loopCounter++;
            //Serial.println(loopCounter);
          }
        }
      }
    }
  }
}

void pressButtons()
{
  if (isInputtingDelayed == false)
  {
    //  Define input delay (If Buffer Array Element 9 and 10 !=0)
    inputDelay = (unsigned long)current_macro_input[9] << 8 | (unsigned long)current_macro_input[10];
  }
  if (isInputting == true)
  {
    //  Press Button

    //  First 8 buttons, Buffer Array Element 1
    //  B, Y, SELECT, START, UP, DOWN, LEFT, RIGHT
    inputStatus[4] =  (current_macro_input[1] & B00000001); // B
    inputStatus[5] =  (current_macro_input[1] & B00000010); // Y
    inputStatus[6] =  (current_macro_input[1] & B00000100); // Select
    inputStatus[7] =  (current_macro_input[1] & B00001000); // Start
    inputStatus[8] =  (current_macro_input[1] & B00010000); // Up
    inputStatus[10] = (current_macro_input[1] & B00100000); // Down
    inputStatus[1] =  (current_macro_input[1] & B01000000); // Left
    inputStatus[0] =  (current_macro_input[1] & B10000000); // Right

    //  Second 4 buttons, Buffer Array Element 2
    //  A, X, L, R, N/A, N/A, N/A, N/A
    inputStatus[24] =  (current_macro_input[2] & B00000001); // A
    inputStatus[3] =   (current_macro_input[2] & B00000010); // X

    // Because the L and R buttons are connected to a board where
    // it outputs pseudo-analog levels, we have to set 2 bits low
    // or high to be able to actually press the buttons
    inputStatus[20] = (current_macro_input[2] & B00000100); // L
    inputStatus[21] = (current_macro_input[2] & B00000100); // L
    inputStatus[22] = (current_macro_input[2] & B00001000); // R
    inputStatus[23] = (current_macro_input[2] & B00001000); // R

    digitalWrite(latchPin, LOW);
    for (int i = 31; i >= 0; i--)
    {
      digitalWrite(clockPin, LOW);
      digitalWrite(dataPin, !inputStatus[i]);
      digitalWrite(buttonLeft, !inputStatus[1]); // This is the Left Dpad button, which isn't on the shift registers, it's on the output A0
      digitalWrite(clockPin, HIGH);
    }
    digitalWrite(latchPin, HIGH);

    //  Buffer Array Elements 9 and 10 are used to tell the Arduino how long commands are executed, on a delay ranging from 1-65535ms
    if (inputDelay != 0)
    {
      isInputtingDelayed = true;
      //  The block below executes Soft Delay for holding the buttons down
      if (isInputtingDelayed == true)
      {
        if (currentMillis - previousInputDelay >= inputDelay)
        {
          //  Now we need to stop the Soft Delay

          //  Reset everything
          serial_rx_buffer[0] = 0x00;
          serial_rx_buffer[1] = 0x00;
          serial_rx_buffer[2] = 0x00;
          serial_rx_buffer[3] = 0x00;
          serial_rx_buffer[4] = 0x00;
          serial_rx_buffer[5] = 0x00;
          serial_rx_buffer[6] = 0x00;
          serial_rx_buffer[7] = 0x00;
          serial_rx_buffer[8] = 0x00;
          serial_rx_buffer[9] = 0x00;
          serial_rx_buffer[10] = 0x00;
          serial_rx_buffer[11] = 0x00;

          current_macro_input[0] = 0x00;
          current_macro_input[1] = 0x00;
          current_macro_input[2] = 0x00;
          current_macro_input[3] = 0x00;
          current_macro_input[4] = 0x00;
          current_macro_input[5] = 0x00;
          current_macro_input[6] = 0x00;
          current_macro_input[7] = 0x00;
          current_macro_input[8] = 0x00;
          current_macro_input[9] = 0x00;
          current_macro_input[10] = 0x00;
          current_macro_input[11] = 0x00;

          //  First 8 buttons, Buffer Array Element 1
          //  B, Y, SELECT, START, UP, DOWN, LEFT, RIGHT
          inputStatus[4] =  (current_macro_input[1] & B00000001); // B
          inputStatus[5] =  (current_macro_input[1] & B00000010); // Y
          inputStatus[6] =  (current_macro_input[1] & B00000100); // Select
          inputStatus[7] =  (current_macro_input[1] & B00001000); // Start
          inputStatus[8] =  (current_macro_input[1] & B00010000); // Up
          inputStatus[10] = (current_macro_input[1] & B00100000); // Down
          inputStatus[1] =  (current_macro_input[1] & B01000000); // Left
          inputStatus[0] =  (current_macro_input[1] & B10000000); // Right

          //  Second 8 buttons, Buffer Array Element 2
          //  A, X, L, R, N/A, N/A, N/A, N/A
          inputStatus[24] =  (current_macro_input[2] & B00000001); // A
          inputStatus[3] =   (current_macro_input[2] & B00000010); // X

          // Because the L and R buttons are connected to a board where
          // it outputs pseudo-analog levels, we have to set 2 bits low
          // or high to be able to actually press the
          inputStatus[20] = (current_macro_input[2] & B00000100); // L
          inputStatus[21] = (current_macro_input[2] & B00000100); // L
          inputStatus[22] = (current_macro_input[2] & B00001000); // R
          inputStatus[23] = (current_macro_input[2] & B00001000); // R

          digitalWrite(latchPin, LOW);
          for (int i = 31; i >= 0; i--)
          {
            digitalWrite(clockPin, LOW);
            digitalWrite(dataPin, !inputStatus[i]);
            digitalWrite(buttonLeft, !inputStatus[1]); // This is the Left Dpad button, which isn't on the shift registers, it's on the output A0
            digitalWrite(clockPin, HIGH);
          }
          digitalWrite(latchPin, HIGH);

          isInputtingDelayed = false;
          isInputting = false;
          previousInputDelay += inputDelay;
          inputDelay = 0;
        }
      }
    }
  }
}

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


Button for changing LED brightness

Button for changing LED brightness

/*
 * Simple Button & LED
 * This program uses a button to
 * change an LED light's brightness
 */

const int switchPin = 8;
const int ledPin = 11;

bool lastPress = LOW;
bool currentButton = LOW;
int ledLevel = 0;

void setup()
{
  pinMode(switchPin, INPUT);
  pinMode(ledPin, OUTPUT);
}

// Fixes the issue with "bouncing" of the switch
bool debounce(bool last)
{
  bool current = digitalRead(switchPin);
  if (last != current)
  {
    delay(5);
    current = digitalRead(switchPin);
  }
  return current;
}

void loop()
{
  currentButton = debounce(lastButton);

  // If the switch/button has been pressed, toggle the ledOn variable
  if (lastButton == LOW && currentButton == HIGH)
  {
    ledLevel = (ledLevel + 51) % 255; // Add 51 units of brightness level, limiting to 255
  }

  lastButton = currentButton;
  analogWrite(ledPin, ledLevel);
}

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


Update ProjectHomeAutomation.ino

Update ProjectHomeAutomation.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/Electroscholars/HomeAutomation.git/'


added temperature

added temperature


the arduino side seems to finish a motion quite nicely

this is just code to verify that

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/trinamic/T-Bone.git/'


Polished code

Polished code

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/fbatta/wbox-nodejs.git/'


added 6.

added 6.

error: pathspec '6.Turn' did not match any file(s) known to git
error: pathspec 'on' did not match any file(s) known to git
error: pathspec 'LED' did not match any file(s) known to git
error: pathspec 'when' did not match any file(s) known to git
error: pathspec 'dark.ino' did not match any file(s) known to git


adds cc3k digital out example

adds cc3k digital out example

#include <Adafruit_CC3000.h>
#include <PubSubClient.h>
#include <SPI.h>

#define ADAFRUIT_CC3000_IRQ   3
#define ADAFRUIT_CC3000_VBAT  5
#define ADAFRUIT_CC3000_CS    10
#define LIGHT                 8

Adafruit_CC3000 cc3000 = Adafruit_CC3000(ADAFRUIT_CC3000_CS,
                                         ADAFRUIT_CC3000_IRQ,
                                         ADAFRUIT_CC3000_VBAT,
                                         SPI_CLOCK_DIVIDER);

Adafruit_CC3000_Client cc3000_client = Adafruit_CC3000_Client();
PubSubClient client("io.adafruit.com", 1883, mqtt_callback, cc3000_client);

// replace with your WiFi connection info
#define WLAN_SSID "test"
#define WLAN_PASS "secretpass"
#define WLAN_SECURITY WLAN_SEC_WPA2

// replace xxxxxxxxx with your Adafruit IO key
#define AIO_KEY "xxxxxxxxx"
#define MQTT_TOPIC "api/feeds/Light/data/receive.json"

// light state
int state = 0;

void setup() {

  // set power switch tail pin as an output
  pinMode(LIGHT, OUTPUT);

  // wait until serial is available
  while (!Serial);

  // Serial init
  Serial.begin(115200);
  Serial.println(F("Initializing....(May take a few seconds)"));

  // cc3300 init
  if (! cc3000.begin()) {
    Serial.println(F("Couldn't begin()! Check your wiring?"));
    while(1);
  }

  Serial.print(F("\nAttempting to connect to "));
  Serial.println(WLAN_SSID);

  if (!cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY)) {
    Serial.println(F("Failed!"));
    while(1);
  }

  Serial.println(F("Connected!"));

  Serial.println(F("Request DHCP"));
  while (!cc3000.checkDHCP()) {
    delay(100);
  }

  // connect to AIO
  mqtt_connect();

}

void loop() {

  // required for MQTT connection
  client.loop();

  // reconnect if we lost connection to AIO
  if(! client.connected()) {
    Serial.print(F("AIO connection dropped. Attempting reconnect"));
    mqtt_connect();
  }

  // write the state to the relay
  digitalWrite(LIGHT, state == 1 ? HIGH : LOW);

}

void mqtt_connect() {

  char client_name[30];

  // generate new client name
  sprintf(client_name, "adafruit-cc3000-%ul", micros());

  // attempt connection
  if (client.connect(client_name, AIO_KEY, NULL)) {
    Serial.println(F("Connected to AIO"));
    client.subscribe(MQTT_TOPIC);
    client.loop();
  } else {
    Serial.println(F("AIO connect failed"));
  }

}

void mqtt_callback (char* topic, byte* payload, unsigned int length) {

  // dump topic and payload from subscription
  Serial.print(F("Receieved: "));
  Serial.println(topic);
  Serial.write(payload, length);
  Serial.println(topic);

  // make sure we received a message from the correct feed
  if(strcmp(topic, MQTT_TOPIC) =! 0)
    return;

  // convert the MQTT payload to int
  int value = to_int(payload, length);

  // make sure we have a 0 or 1
  if(value != 0 && value != 1)
    return;

  // save the new state
  state = value;

}

int to_int(byte* payload, int length) {

  int i;
  char val[2];

  // convert payload to char
  for(i = 0; i < length; i++) {
    val[i] = payload[i];
  }

  val[i] = '\0';

  // convert char to int and return
  return atoi(val);

}

error: pathspec 'arduino-cc3000/digital-out/digital-out.ino' did not match any file(s) known to git


Create QR_Code_Gen3V38_Public.ino

Create QR_Code_Gen3V38_Public.ino

/*
QR_Code_Gen3
(c)2014 William L. "Bud" Nail, Technological Services Company
This program and support functions fully implement the generation of several useful versions of the QR Code standard from a text string.

It does this in a relatively small memory foot print such as the Arduino Uno and still leaves room for additional application functions.
It can be easily modified to support additional QR codes with some limitations.

This program is licensed under GPL 2, 3 or LGPL (your choice) that work well for non-commercial and some limited commercial projects (IMHO).
If you are interested in a simple low cost commercial or developer's license for embedding in your projects,
see  www.technologicalservicescompany.com for contact information.

Donations are also accepted for further development.

Regardless of the license, the code is free for review and experimentation by individuals and commercial or non-commercial enterprises.

History:
When this program development began, in early 2014, it was thought by most (from reviewing forums on the subject) that it would be next to impossible
to implement a dynamic QR code generator on a processor such as the Arduino UNO that has so little SRAM.

I had a specific project in mind that would use the Arduino UNO chip on a custom board with a small graphics display.
Researching, I discovered that the U8g (universal 8 bit graphics) library supported all of the several displays I was considering using.
I also found that David Hend had successfully created a dynamic QR code on a larger processor, when other people were only capable
of generating static codes. He referenced "Thonky's" excellent tutorial on programming QR code generators.

With those references I proceeded to build my own QR generator that would fit in a Arduino UNO or similar embedded processor's foot print.

So far, this program is capable of generating QR version 1Q, 2Q, 3L, and 3M code format. Then it displays
that information as a QR code on the screen.

Many thanks to David for giving me a starting point and a link to Thonky's tutorial (www.thonky.com) he used as the basis for his design.
Seeing his code and comparing it to the tutorial, helped greatly in understanding what is required to build a fuller implementation.
I basically replaced his code modules one by one while using his remaining code to test results against. If any of his code remains it
is not intentional, though I continue to use some of the same function names.

Thanks also to Thonky.com for a great learning resource.

For those interested:

Here are design features:
(1) A general purpose graphics library is being used instead of the TFT library David used, so that it can support more devices.
(2) This version is significantly altered to allow use in low memory devices such as the Arduino Uno
    and devices with the same or similar chip sets. This is accomplished by moving constants to PROGMEM and downsizing variables.
(3) This version defaults to a 2x2 pixel module rather than the fixed 10x10 pixel module in David's work.
(4) Completely new logic has been added to fully conform to the QR spec(as for as I know) for the versions implemented.
    Instead of simply picking a mask and hoping it works (it didn't always), each mask is tried and scored according
    to the spec and the best mask is used.
(5) This version has been restructured so that new QR versions can be added without significantly rewriting the code.
(6) While currently a 2x2 pixel module is hard coded, much of the supporting functions are resolution independent.
(7) The code is designed to "fail gracefully".  That is to say if your try to send a message that is not legal according
    to the spec, it sends what it can, rather than crashing or generating an unreadable code. It shortens messages
    that are too long and substitutes illegal characters with legal characters.

Hardware Consideratons:
The current version of the program has been targeted specifically to work with the DOG102 series of Displays. But,
since it uses the U8glib library for Universal 8 bit graphics, the program should be usable with most any graphic display.
Simply take one of the U8glib examples and pull the line that looks equivalent to:
//set up SPI for model display used and wiring
U8GLIB_DOGS102 u8g(13, 11, 10, 9);		// SPI Com: SCK = 13, MOSI = 11, CS = 10, A0(also referenced as CD) = 9
Replace this line with the one that matches your display.
Adjust the SPI communication ports to match the ones on your hardware.

To Do: (1) build the qr code in a buffer area so that it can be built repeatedly for each mask 0-7 - done
       (2) build the test to score the mask methods. - done
       (3) build the best scoring and Display - done
       (4) turn the process into a function so that any message string can be sent to it at any time.
       (5) make all methods work with QR code Versions 2 and 3 as well as 1 - done
       (6) auto covert lower case to upper case since trying to encode lowercase is a common mistake - done
       (7) change encoding to include allowed non alpha numeric - done
       (8) - maybe add numeric encoding vs only alphanumeric encoding - this will require changes throughout
       (9) The current version uses 2x2 pixels per QR code module. Make the size selectable.

Version History:
V3 added the option to choose other mask types - the specification requires you try all 7 and use the best.
   this version only provides that you can use any of the 7
V5 Fixed the bug in the ECC calculation that would give bad ECC.
V6 adds scalable templates for versions 1, 2 and 3
V7 adds a QRcode Buffer that lets you generate the code off screen for grading - currently only the template
v8 adds some text functions for debugging.
v9 clears out a lot of the old methods and comments,
   added function to create format bits for all ECCs and Masks
   modified the informationBits function to place format bits for QR code versions 1-3, probably works up to version 6
   started on making the data bits in the informationBits function work for several QR versions
   modified and tested up1 portion so far.
v10 added improved version of placing the data and ecc into the qr matix up to where the transition from data to ecc occurs
    at this point it became apparent that the data and ecc need to be strung together first to avoid all the possible
    points where this transition occurs. not complete.
v11 ran into more memory problems so worked on shrinking SRAM usage, moved log table to progmem (flash memory)
    This freed up an additional 512 bytes of SRAM memory
v12 moved format information bits of Mosk 0-7 of ECC Q to PROGMEM also
    verified that info written to display is correct for each mask type of Q
    however - none of the other mask patterns seem to work
V13 transition from using array of bytes to represent binary arrays where there is one byte to bit to bit for bit
V14 clean up of old methods so that the portion of databits to ecc bits can change
    most masks tested. Even number of chars work, problem with last char of odd length
V15 fixed bug of last odd character cleaned out some debugging code. Now all lengths and all Masks work for 1Q type
V16 start fleshing out provision for  other ECC levels: L, M, and H, added information bit arrays for each
    Added grading of image logic - not tested.
V17 Tested and debugged grading system - results corresponded to thonky's QR generator
    Automatic selection of best code not implemented yet.
v18 Modified info bits to drow to buffer or screen
v20 This version fully supports Mask grading and automatically picks the best mask for the qr code and uses it.
v21 Cleaned up removed most old unused code. Added complete punctuation allowed. Auto convert lower case to upper
V22 Expanded arrays to accomodate QR Version 2 Q. Verified there was still enough SRAM to function.
    Removed the size dependencies from calculating the QR code data and ECC
    All that remains (I think) is to make changes to the drawing of the QR code for various versions
V23 implemented placing information bits for Version 2 and 3
V24 Now capable of generating Type 2 Q QR codes, though the mask scoring does not match up with Thonky's Generator
V26 Got rid of additional strings that grows when scaling up for Type 3
V28 Got rid of last bad string "dataString"
V29 Cleaned up and rewrote much of ECC to work with different number of ECC and Message code words
    Still has a bug - works for Type 2 but not Type 3
V30 Now Supports Versions 1Q,2Q, and 3L,
V31 Now Supports Versions 1Q,2Q,3L and 3M
V32 Cleaned out old comments - first publically released version
V33 Various optimizations
V34 Starting adding application code and memory got a bit tight, looking for more memory
V35 Eliminated an 80 character array and haved another, saving 120 bytes of sram, with improved math
    Eliminated the last dependency on String objects that really suck up the sram
V38_Public Removed GPS Logging code for public version

Developer Notes:
  Basic steps are:
     0. select the QR code type
     1. translate the message into data bits
     2. Calculate the Error Correction Codes using polynomial division
     3. Place the data and ECC bits within a template for evaluation
     3. Find the best mask to use for the QR code by trying them all and picking the best (grading)
     3. drawing the qr code on the screen using the mask selected above

  Key functions and data structures:
     qrBuff[] - An off screen buffer 32x32 bits is provided for testing QR codes before displaying them

     "bitString" functions - read and write functions as if there was a string of bits data type (we pre-use qrBuff[] for temporary storage)

     setMod2(int m,int x,int y,int c) - where m is mode, x is column, y is row and c is color (0 white, 1 black)
       it draws a qr module to the screen (mode = 0) or to the buffer(mode = 1)
       this is the lowest drawing level that you might use to add new qr versions

      calculateQRCode() is where the message is translated into data bits - do this before the functions below
       this is where you would add new calculations for different QR code versions

      ecc() calculates the error correction code words for the data code words

      drawTemplate(int mode) places the standard template on the screen or in the buffer. mode = 0(screen), 1 (buffer)

      informationBits2(int mode) places the data bits in the qr code either on the screen or in the buffer. mode = 0(screen), 1 (buffer)

      formatBits() places the information about the QR code type and mask selected into the QRcode, always on screen.
        should not be used in the buffer as part of the grading process.

  Limitations:
    The offscreen buffer is only designed to work up to version 3 which is 29 x 29 modules. Each module is represented by 1 bit.
    Working with more than the 32 bits present in an unsigned long int has its challenges.
    This version only supports codes that have a single block of ECC appended at the end. Not interleaved versions, starting with 3Q
*/

//start includes
#include <stdint.h>
//wln included pgmspace to move log table(s) and other constants to flash memory and save SRAM
#include <avr/pgmspace.h>
//wln include the universal graphics library
#include "U8glib.h"

//wln...
//set up SPI for model display used and wiring for Ardunino Uno style devices
//simply change this next line to match your wiring scheme
U8GLIB_DOGS102 u8g(13, 11, 10, 9);		// SPI Com: SCK = 13, MOSI = 11, CS = 10, A0 = 9
//...wln
//Set to true to enable serial debug information
boolean debug = false;

/*
Log/Anti-Log table used to switch between integer notation
and alpha notation when performing arithmetic to calculate
ecc bits. Arduino supports log functions but does not work
in the same way as this table does.
***wln changed table from 4 elements per row to 2, removing the duplicate index values
*** also changed to use a byte table from the orginal unsigned int to save memory. reduced 2020 bytes to 510 bytes of ram
*** Newer ultra low memory use version moves Log table from SRAM to flash. Separate Log and AntiLog tables used now.
*/
//wln Log table in Flash Memory
// to lookup values use form "y = pgm_read_byte_near(antiLogTableF + x);" where y^x
PROGMEM  prog_uchar antiLogTableF[]  = {
  1,
  2,
  4,
  8,
  16,
  32,
  64,
  128,
  29,
  58,
  116,
  232,
  205,
  135,
  19,
  38,
  76,
  152,
  45,
  90,
  180,
  117,
  234,
  201,
  143,
  3,
  6,
  12,
  24,
  48,
  96,
  192,
  157,
  39,
  78,
  156,
  37,
  74,
  148,
  53,
  106,
  212,
  181,
  119,
  238,
  193,
  159,
  35,
  70,
  140,
  5,
  10,
  20,
  40,
  80,
  160,
  93,
  186,
  105,
  210,
  185,
  111,
  222,
  161,
  95,
  190,
  97,
  194,
  153,
  47,
  94,
  188,
  101,
  202,
  137,
  15,
  30,
  60,
  120,
  240,
  253,
  231,
  211,
  187,
  107,
  214,
  177,
  127,
  254,
  225,
  223,
  163,
  91,
  182,
  113,
  226,
  217,
  175,
  67,
  134,
  17,
  34,
  68,
  136,
  13,
  26,
  52,
  104,
  208,
  189,
  103,
  206,
  129,
  31,
  62,
  124,
  248,
  237,
  199,
  147,
  59,
  118,
  236,
  197,
  151,
  51,
  102,
  204,
  133,
  23,
  46,
  92,
  184,
  109,
  218,
  169,
  79,
  158,
  33,
  66,
  132,
  21,
  42,
  84,
  168,
  77,
  154,
  41,
  82,
  164,
  85,
  170,
  73,
  146,
  57,
  114,
  228,
  213,
  183,
  115,
  230,
  209,
  191,
  99,
  198,
  145,
  63,
  126,
  252,
  229,
  215,
  179,
  123,
  246,
  241,
  255,
  227,
  219,
  171,
  75,
  150,
  49,
  98,
  196,
  149,
  55,
  110,
  220,
  165,
  87,
  174,
  65,
  130,
  25,
  50,
  100,
  200,
  141,
  7,
  14,
  28,
  56,
  112,
  224,
  221,
  167,
  83,
  166,
  81,
  162,
  89,
  178,
  121,
  242,
  249,
  239,
  195,
  155,
  43,
  86,
  172,
  69,
  138,
  9,
  18,
  36,
  72,
  144,
  61,
  122,
  244,
  245,
  247,
  243,
  251,
  235,
  203,
  139,
  11,
  22,
  44,
  88,
  176,
  125,
  250,
  233,
  207,
  131,
  27,
  54,
  108,
  216,
  173,
  71,
  142,
  1,
};//end of antiLog table
// to lookup values use form "x = pgm_read_byte_near(LogTableF + y);" where y^x
//the first element is really empty but something had to be put there.
PROGMEM  prog_uchar LogTableF[]  = {
  0,
  0,
  1,
  25,
  2,
  50,
  26,
  198,
  3,
  223,
  51,
  238,
  27,
  104,
  199,
  75,
  4,
  100,
  224,
  14,
  52,
  141,
  239,
  129,
  28,
  193,
  105,
  248,
  200,
  8,
  76,
  113,
  5,
  138,
  101,
  47,
  225,
  36,
  15,
  33,
  53,
  147,
  142,
  218,
  240,
  18,
  130,
  69,
  29,
  181,
  194,
  125,
  106,
  39,
  249,
  185,
  201,
  154,
  9,
  120,
  77,
  228,
  114,
  166,
  6,
  191,
  139,
  98,
  102,
  221,
  48,
  253,
  226,
  152,
  37,
  179,
  16,
  145,
  34,
  136,
  54,
  208,
  148,
  206,
  143,
  150,
  219,
  189,
  241,
  210,
  19,
  92,
  131,
  56,
  70,
  64,
  30,
  66,
  182,
  163,
  195,
  72,
  126,
  110,
  107,
  58,
  40,
  84,
  250,
  133,
  186,
  61,
  202,
  94,
  155,
  159,
  10,
  21,
  121,
  43,
  78,
  212,
  229,
  172,
  115,
  243,
  167,
  87,
  7,
  112,
  192,
  247,
  140,
  128,
  99,
  13,
  103,
  74,
  222,
  237,
  49,
  197,
  254,
  24,
  227,
  165,
  153,
  119,
  38,
  184,
  180,
  124,
  17,
  68,
  146,
  217,
  35,
  32,
  137,
  46,
  55,
  63,
  209,
  91,
  149,
  188,
  207,
  205,
  144,
  135,
  151,
  178,
  220,
  252,
  190,
  97,
  242,
  86,
  211,
  171,
  20,
  42,
  93,
  158,
  132,
  60,
  57,
  83,
  71,
  109,
  65,
  162,
  31,
  45,
  67,
  216,
  183,
  123,
  164,
  118,
  196,
  23,
  73,
  236,
  127,
  12,
  111,
  246,
  108,
  161,
  59,
  82,
  41,
  157,
  85,
  170,
  251,
  96,
  134,
  177,
  187,
  204,
  62,
  90,
  203,
  89,
  95,
  176,
  156,
  169,
  160,
  81,
  11,
  245,
  22,
  235,
  122,
  117,
  44,
  215,
  79,
  174,
  213,
  233,
  230,
  231,
  173,
  232,
  116,
  214,
  244,
  234,
  168,
  80,
  88,
  175
};//end of Log table

//Store format bit patterns in Flash. i.e QM0 is Q type ECC Mask 0
// These could be changed to single unsigned int with a little work if Flash mem gets tight.
/* commented out ECC types you are not using to save memory, uncomment to use
// ECC type H
PROGMEM  prog_uchar HM0[]  = {0,0,1,0,1,1,0,1,0,0,0,1,0,0,1};//ECC Level H Mask 0
PROGMEM  prog_uchar HM1[]  = {0,0,1,0,0,1,1,1,0,1,1,1,1,1,0};//ECC Level H Mask 1
PROGMEM  prog_uchar HM2[]  = {0,0,1,1,1,0,0,1,1,1,0,0,1,1,1};//ECC Level H Mask 2
PROGMEM  prog_uchar HM3[]  = {0,0,1,1,0,0,1,1,1,0,1,0,0,0,0};//ECC Level H Mask 3
PROGMEM  prog_uchar HM4[]  = {0,0,0,0,1,1,1,0,1,1,0,0,0,1,0};//ECC Level H Mask 4
PROGMEM  prog_uchar HM5[]  = {0,0,0,0,0,1,0,0,1,0,1,0,1,0,1};//ECC Level H Mask 5,
PROGMEM  prog_uchar HM6[]  = {0,0,0,1,1,0,1,0,0,0,0,1,1,0,0};//ECC Level H Mask 6
PROGMEM  prog_uchar HM7[]  = {0,0,0,1,0,0,0,0,0,1,1,1,0,1,1};//ECC Level H Mask 7,

// ECC type Q finished and tested
PROGMEM  prog_uchar QM0[]  = {0,1,1,0,1,0,1,0,1,0,1,1,1,1,1};//ECC Level Q Mask 0
PROGMEM  prog_uchar QM1[]  = {0,1,1,0,0,0,0,0,1,1,0,1,0,0,0};//ECC Level Q Mask 1
PROGMEM  prog_uchar QM2[]  = {0,1,1,1,1,1,1,0,0,1,1,0,0,0,1};//ECC Level Q Mask 2
PROGMEM  prog_uchar QM3[]  = {0,1,1,1,0,1,0,0,0,0,0,0,1,1,0};//ECC Level Q Mask 3
PROGMEM  prog_uchar QM4[]  = {0,1,0,0,1,0,0,1,0,1,1,0,1,0,0};//ECC Level Q Mask 4
PROGMEM  prog_uchar QM5[]  = {0,1,0,0,0,0,1,1,0,0,0,0,0,1,1};//ECC Level Q Mask 5,
PROGMEM  prog_uchar QM6[]  = {0,1,0,1,1,1,0,1,1,0,1,1,0,1,0};//ECC Level Q Mask 6
PROGMEM  prog_uchar QM7[]  = {0,1,0,1,0,1,1,1,1,1,0,1,1,0,1};//ECC Level Q Mask 7,
// ECC type M
PROGMEM  prog_uchar MM0[]  = {1,0,1,0,1,0,0,0,0,0,1,0,0,1,0};//ECC Level M Mask 0
PROGMEM  prog_uchar MM1[]  = {1,0,1,0,0,0,1,0,0,1,0,0,1,0,1};//ECC Level M Mask 1
PROGMEM  prog_uchar MM2[]  = {1,0,1,1,1,1,0,0,1,1,1,1,1,0,0};//ECC Level M Mask 2
PROGMEM  prog_uchar MM3[]  = {1,0,1,1,0,1,1,0,1,0,0,1,0,1,1};//ECC Level M Mask 3
PROGMEM  prog_uchar MM4[]  = {1,0,0,0,1,0,1,1,1,1,1,1,0,0,1};//ECC Level M Mask 4
PROGMEM  prog_uchar MM5[]  = {1,0,0,0,0,0,0,1,1,0,0,1,1,1,0};//ECC Level M Mask 5,
PROGMEM  prog_uchar MM6[]  = {1,0,0,1,1,1,1,1,0,0,1,0,1,1,1};//ECC Level M Mask 6
PROGMEM  prog_uchar MM7[]  = {1,0,0,1,0,1,0,1,0,1,0,0,0,0,0};//ECC Level M Mask 7,
*/
// ECC type L
PROGMEM  prog_uchar LM0[]  = {1,1,1,0,1,1,1,1,1,0,0,0,1,0,0};//ECC Level L Mask 0
PROGMEM  prog_uchar LM1[]  = {1,1,1,0,0,1,0,1,1,1,1,0,0,1,1};//ECC Level L Mask 1
PROGMEM  prog_uchar LM2[]  = {1,1,1,1,1,0,1,1,0,1,0,1,0,1,0};//ECC Level L Mask 2
PROGMEM  prog_uchar LM3[]  = {1,1,1,1,0,0,0,1,0,0,1,1,1,0,1};//ECC Level L Mask 3
PROGMEM  prog_uchar LM4[]  = {1,1,0,0,1,1,0,0,0,1,0,1,1,1,1};//ECC Level L Mask 4
PROGMEM  prog_uchar LM5[]  = {1,1,0,0,0,1,1,0,0,0,1,1,0,0,0};//ECC Level L Mask 5,
PROGMEM  prog_uchar LM6[]  = {1,1,0,1,1,0,0,0,1,0,0,0,0,0,1};//ECC Level L Mask 6
PROGMEM  prog_uchar LM7[]  = {1,1,0,1,0,0,1,0,1,1,1,0,1,1,0};//ECC Level L Mask 7,

int maskType = 0;//Place holde for the QR code mask type
// wln change for trying different masks
//int maskType = 0;//(row + column) mod 2 == 0
//int maskType = 1;//(row) mod 2 == 0
//int maskType = 2;//(column) mod 3 == 0
//int maskType = 3;//(row + column) mod 3 == 0
//int maskType = 4;//( floor(row / 2) + floor(column / 3) ) mod 2 == 0
//int maskType = 5;//((row * column) mod 2) + ((row * column) mod 3) == 0
//int maskType = 6;//( ((row * column) mod 2) + ((row * column) mod 3) ) mod 2 == 0
//int maskType = 7;//( ((row + column) mod 2) + ((row * column) mod 3) ) mod 2 == 0 (according to thonky this is correct not what is in QR specification Page 51

//place holder for Message in binary form - use smallest version for application to save SRAM
//byte BinaryMessComp[26]={};//big enough for Version 1. one bit per bit rather than byte for bit holds both Message and ECC, saves 174 bytes of SRAM
//byte BinaryMessComp[44]={};//big enough for Version 2.
byte BinaryMessComp[70]={};//big enough for Version 3.

//Array to hold Message in Integer format (used in poly arithmetic) - use smallest version for application to save SRAM
//unsigned int MessageI[13] = {};//big enough for Version 1 Q
//unsigned int MessageI[22] = {};//big enough for Version 2 Q
unsigned int MessageI[55] = {};//big enough for Version 3 L
//unsigned int MessageI[44] = {};//big enough for Version 3 M

//Array to hold Message in Alpha Notation (used in arithmetic) - use smallest version for application to save SRAM
//unsigned int MessageA[13] = {};//big enough for Version 1 Q
//unsigned int MessageA[22] = {};//big enough for Version 2 Q
unsigned int MessageA[55] = {};//big enough for Version 3 L
//unsigned int MessageA[44] = {};//big enough for Version 3 M

// QR code Version - These are set up below
// qrV = QR version 1, 2, or 3
// qrE =Error Correction Level, L, M, Q, or H

// for additional Generator Polynomials see http://www.thonky.com/qr-code-tutorial/generator-polynomial-tool/?degree=13
// These could be moved to PROGMEM to save SRAM
// If you want to add other Versions use the types provided as examples. You must also edit the following functions for new types:
//   encodeDataLength() : the length of the longest message in bytes allowed
//   getReqDataWords()  : the number of required data code words
//   getReqECCWords()   : the number of required Error Correction Code words

//**** CHange the QRversion by uncommenting ONE of the lines below. Comment out the one you are not using
//The line below is for version 1 Q where the ECC polynomial is:
//  x13 + α74x12 + α152x11 + α176x10 + α100x9 + α86x8 + α100x7 + α106x6 + α104x5 + α130x4 + α218x3 + α206x2 + α140x + α78
//int qrV = 1;char qrE = 'Q';unsigned int GeneratorA[14] = {0,74,152,176,100,86,100,106,104,130,218,206,140,78};//version 1Q

//The line below is for version 2 Q where the ECC polynomial is:
//  x22 + α210x21 + α171x20 + α247x19 + α242x18 + α93x17 + α230x16 + α14x15 + α109x14 + α221x13 + α53x12 + α200x11 + α74x10 + α8x9 + α172x8 + α98x7 + α80x6 + α219x5 + α134x4 + α160x3 + α105x2 + α165x + α231
//int qrV = 2;char qrE = 'Q';unsigned int GeneratorA[23] = {0,210,171,247,242,93,230,14,109,221,53,200,74,8,172,98,80,219,134,160,105,165,231};//version 2Q

//Version 3 L where the ECC polynomial is:
//x15 + α8x14 + α183x13 + α61x12 + α91x11 + α202x10 + α37x9 + α51x8 + α58x7 + α58x6 + α237x5 + α140x4 + α124x3 + α5x2 + α99x + α105
int qrV = 3;char qrE = 'L';unsigned int GeneratorA[16] = {0,8,183,61,91,202,37,51,58,58,237,140,124,5,99,105};//version 3L

//Version 3 M where the ECC polynomial is:
//x26 + α173x25 + α125x24 + α158x23 + α2x22 + α103x21 + α182x20 + α118x19 + α17x18 + α145x17 + α201x16 + α111x15 + α28x14 + α165x13 + α53x12 + α161x11 + α21x10 + α245x9 + α142x8 + α13x7 + α102x6 + α48x5 + α227x4 + α153x3 + α145x2 + α218x + α70
//int qrV = 3;char qrE = 'M';unsigned int GeneratorA[27] ={0,173,125,158,2,103,182,118,17,145,201,111,28,165,53,161,21,245,142,13,102,48,227,153,145,218,70};

//Holder for Result from arithmitic - use smallest version for application to save SRAM
//unsigned int Result[15] = {};//big enough for V 1 Q
//unsigned int Result[24] = {};//big enough for V 2 Q
unsigned int Result[56] = {};//big enough for V 3 L
//unsigned int Result[45] = {};//big enough for V 3 M

//Holder for Result from XOR operation (used in arithmetic) - use smallest version for application to save SRAM
//unsigned int xorResult[15] = {};//big enough for V 1 Q
//unsigned int xorResult[24] = {};//big enough for V 2 Q
unsigned int xorResult[56] = {};//big enough for V 3 L
//unsigned int xorResult[45] = {};//big enough for V 3 M

// QR image buffer for grading. supports up to version 3, 29 x29 modules
unsigned long qrBuff[29] = {};//sized for 1, 2 and 3. Does double duty as offscreen graphics buffer and bit string storage (V27 and later)
int qrBuffindex = 0;// holds pointer to the next available bit in the qrBuff when using it for bit string storage
// QR module width and height
byte qrS = 2;//2 means a 2x2 pix per module
int qrM = 21;//number of modules per side default version 1, changed automatically to correct size based on qrV
// QR module pixel offsets. moves the the QR code from the corner on the display - can be whatever you like but are overridden by centerFlag
//byte xOffs = 25; byte yOffs = 40;
byte xOffs = 3; byte yOffs = 22;
int centerFlag = 3;// if not 0 overides xOffs and yOffs to center the code, 1 centers Horz, 2 centers Vert, 3 centers both directions

//char array we hope to convert (a C string) - just a place holder at this point
// Size the array for the maximum number of characters you intend to encode plus 1.
//char charsToEncode[78] = = "";
//must be uppercase and numeric
//various test strings
  //String messageToEncode = "HACKADAY";
  //String messageToEncode = "S211111S";
  //String messageToEncode = "123456789012345";
//char charsToEncode[10] = "JOHN 3:16";
char charsToEncode[78] = "http://www.technologicalservicescompany.com";
//char charsToEncode[78] = "ROMANS 6:13";
//String messageToEncode = "A123456789";//Mask 4 - works
 //String messageToEncode = "ABCDEFGHIJ";//Mask 0 - works
//String messageToEncode = "12345ABCDE";//Mask 5 - works
 //String  messageToEncode = "A1B2C3D4E5";//mask 0 - works
//String messageToEncode = "AZ123";//mask 2 - odd length test
//String messageToEncode = "aA1. ..$%*+_/:";// - odd char  test
//String messageToEncode = "0123456789ABCDEFGHI";// - too long message  test for Type 1
//char charsToEncode[78] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXY";//Type 3 test
//String messageToEncode = "AZ12";//mask 7
//char charsToEncode[5] = "AZ12";//mask 7
//char charsToEncode[78] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int grade =0;//place holder for qrmask grade
//ECC words in binary

//char array length
int length = 77;//max length version 3L
//byte counter
int byteCounter = 0;
//Keeps track of data displayed
int counter = 0;
int led = 4;// used in my hardware for troubleshooting
int PPS;//pulse per second
char mess9[10]="John 3:16";//a place holder for 9 character messages to be displayed on screen
char mess3[4]="000";//a place holder for 3 character messages to be displayed on screen
byte button;//status of button

void setup(void)
{
  //Start Serial at 115200 baud Used for trouble shooting
 Serial.begin(115200);//saves 290 bytes if not using
  //Init LCD
  //wln
 // turn on LED
 //pinMode(led, OUTPUT);// used in my hardware for troubleshooting
 //digitalWrite(led,HIGH); // used in my hardware for troubleshooting
 pinMode(A3, INPUT);//use as input
 digitalWrite(A3,HIGH);//turn on internal pullup
 //setupGPS();//specific to my hardware, comment out for public QR_Cod_Gen3

 //------------------------- QR Stuff ---------------
  //Generate data used for QR.  This is where the real work is done
  calculateQRCode();//this is in the generateBits tab(file)

  // rotate screen - optional - tested
  u8g.setRot90();
  //u8g.setRot180();
  //u8g.setRot270();
  //set font size
  u8g.setFont(u8g_font_7x13);
  //set # modules/side and position based on version
  if(qrV==2){
    qrM=25;
  }
  if(qrV==3){
    qrM=29;
  }
  // set the offsets to center code if center flag is set
  if(centerFlag > 0){//overide offsets
    if(centerFlag & 1){//center horz
    xOffs = getCenterOffsetX();
    }
    if(centerFlag & 2){//center vert
    yOffs = getCenterOffsetY();
    }
  }
   maskType = findBestMask();//find the best mask for the current message
}

void draw(void) {
  // graphic commands to redraw the complete screen should be placed here
 // text to draw
  //u8g.setFont(u8g_font_baby);
  //u8g.setFont(u8g_font_7x13);
  u8g.setColorIndex(1);//black ink
  //char mess[]="John 3:16";
  u8g.drawStr( 0, 10, mess9);
  //u8g.setPrintPos(70, 20); // for debugging
  //u8g.print(maskType);// for debugging

 //Draw QR code template
  drawTemplate(0);//mode 0 is to the screen
  //Fill in data bits
  informationBits2(0);//mode 0 is to screen. fill in bits over the template

  formatBits();//drow format bits. this puts the Code Type and Mask Type into the code
  if(button){
    u8g.setColorIndex(1);//black ink
    u8g.drawStr( 0, 100, mess3);
  }

  // the following just blinks a 6x6 area to show that the program has not crashed
  // very useful as your program expands.
  /*
  if(PPS){
     u8g.setColorIndex(0);//white ink
     u8g.drawBox(0,0,6,6);//
  }else{
    u8g.setColorIndex(1);//black ink
     u8g.drawBox(0,0,6,6);//
  }
  */
 // u8g.drawStr( 0, 10, "John 3:16");
}

void loop()
{
  //mess9[0]='0' + millis()/1000 % 10;
  // proves we have not run out of memory if the draw() function is flashing an area of the screen
  if(millis() % 1000 < 500){
    if(PPS==LOW){
     // mess9[0]=' ';
    }
  PPS = HIGH;

  }else{
    if(PPS==HIGH){
     // mess9[0]='J';
    }
    PPS=LOW;

  }
  button = digitalRead(A3);//read the button

  //GPShandler();//specific to my hardware,comment out for public QR_Code_Gen3
  if(millis() % 1000 < 10){//up date display every second or so
   // picture loop as recommended by the U8glib examples
   //
    u8g.firstPage();
    do {
      draw();
    } while( u8g.nextPage() );
      {
      }
      delay(100);
  }
}

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


add chapter5 arduino example

add chapter5 arduino example

void setup() {
  Serial.begin(9600);
}

void loop() {
  if (Serial.available()) {
    char inChar = (char)Serial.read();
    Serial.write(inChar );
  }
}

error: pathspec 'chapter5/arduino-serial/arduino-serial.ino' did not match any file(s) known to git


removed debug code from controller arduino stuff

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/'


Comment updates

Comment updates

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/onordbo/mood-cloud.git/'


source

source

#include <Arduino.h>
#include <ESP8266WiFi.h>
extern "C" {
  #include "user_interface.h"
}

//Don't forget to change the number 192
String apNames[] = {"Afghanistan", "Albania", "Algeria", "Andorra", "Angola", "Antigua and Barbuda", "Argentina", "Armenia", "Australia", "Austria", "Azerbaijan", "Bahamas", "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium", "Belize", "Benin", "Bhutan", "Bolivia", "Bosnia and Herzegovina", "Botswana", "Brazil", "Brunei Darussalam", "Bulgaria", "Burkina Faso", "Burundi", "Cabo Verde", "Cambodia", "Cameroon", "Canada", "Central African Republic", "Chad", "Chile", "China", "Colombia", "Comoros", "Congo", "Costa Rica", "Cote dIvoire", "Croatia", "Cuba", "Cyprus", "Czech Republic", "North Korea", "Republic of the Congo", "Denmark", "Djibouti", "Dominica", "Dominican Republic", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea", "Estonia", "Ethiopia", "Fiji", "Finland", "France", "Gabon", "Gambia", "Georgia", "Germany", "Ghana", "Greece", "Grenada", "Guatemala", "Guinea", "Guinea-Bissau", "Guyana", "Haiti", "Honduras", "Hungary", "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Jamaica", "Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Kuwait", "Kyrgyzstan", "Republic of Lao", "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg", "Macedonia", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands", "Mauritania", "Mauritius", "Mexico", "Micronesia", "Monaco", "Mongolia", "Montenegro", "Morocco", "Mozambique", "Myanmar", "Namibia", "Nauru", "Nepal", "Netherlands", "New Zealand", "Nicaragua", "Niger", "Nigeria", "Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru", "Philippines", "Poland", "Portugal", "Qatar", "South Korea", "Republic of Moldova", "Romania", "Russian Federation", "Rwanda", "Saint Kitts and Nevis", "Saint Lucia", "Samoa", "San Marino", "Sao Tome and Principe", "Saudi Arabia", "Senegal", "Serbia", "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands", "Somalia", "South Africa", "South Sudan", "Spain", "Sri Lanka", "Sudan", "Suriname", "Swaziland", "Sweden", "Switzerland", "Syrian Arab Republic", "Tajikistan", "Thailand", "Timor-Leste", "Togo", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey", "Turkmenistan", "Tuvalu", "Uganda", "Ukraine", "United Arab Emirates", "United Kingdom", "Tanzania", "United States of America", "Uruguay", "Uzbekistan", "Vanuatu", "Venezuela", "Vietnam", "Yemen", "Zambia", "Zimbabwe"};
byte apMACs[192][6];
int apCount = 192;

int currentAP = 0;
int bPointer = 52;
char prefix = '#';

//Beacon Packet buffer
byte packet[128] = {
  /* IEEE 802.11 Beacon Frame */
  /*0*/   0x80, 0x00, 0x00, 0x00,  //type/subtype = beacon
  /*4*/   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, //dst addr = broadcast
  /*10*/  0x01, 0x02, 0x03, 0x04, 0x05, 0x06, //src addr = random MAC
  /*16*/  0x01, 0x02, 0x03, 0x04, 0x05, 0x06, //bss id = src addr
  /*22*/  0x90, 0x53, //seq number 1337 + frag number 0
  /*24*/  0xDE, 0xAD, 0x00, 0xBE, 0xEF, 0x00, 0xF0, 0x0D, //timestamp
  /*32*/  0x64, 0x00, //beacon interval (~100ms)
  /*34*/  0x01, 0x04, //capabilities info

  /* IEEE 802.11 wireless LAN managment frame */
  /*36*/  0x01, 0x08, //tag = Supported Rates, size
          0x82, 0x84, 0x8b, 0x96, 0x24, 0x30, 0x48, 0x6c,
  /*46*/  0x03, 0x01, 0xFF, //tag = Channel, size, random channel

  /*49*/  0x00, 0xFF, 0x23 //tag = SSID, size, prefix char
};

void fillMACs() {
  for (int j = 0; j < apCount; j++) {
    apMACs[j][0] = random(256);
    apMACs[j][1] = random(256);
    apMACs[j][2] = random(256);
    apMACs[j][3] = random(256);
    apMACs[j][4] = random(256);
    apMACs[j][5] = random(256);
  }
}

void setup() {
  delay(100);
  wifi_set_opmode(STATION_MODE);
  wifi_promiscuous_enable(1);
  packet[51] = prefix;
  fillMACs();
}

void loop() {
  if (currentAP == apCount) {
    currentAP = 0;
  }

  //Set random channel (pinning this variable wasn't giving me good results)
  byte channel = random(1, 11);
  wifi_set_channel(channel);
  packet[48] = channel;

  //Copying src addr and bssid to packet buffer
  packet[10] = packet[16] = apMACs[currentAP][0];
  packet[11] = packet[17] = apMACs[currentAP][1];
  packet[12] = packet[18] = apMACs[currentAP][2];
  packet[13] = packet[19] = apMACs[currentAP][3];
  packet[14] = packet[20] = apMACs[currentAP][4];
  packet[15] = packet[21] = apMACs[currentAP][5];

  //Copying SSID to packet buffer
  byte currLenght = apNames[currentAP].length();
  packet[50] = currLenght+1;
  for (int i = bPointer; i < bPointer+currLenght; i++) {
    packet[i] = apNames[currentAP][i-bPointer];
  }

  //Sending beacon. Feel free to play with the numbers here, this was the best combination I found.
  for (int i = 0; i < 8; i++) {
    wifi_send_pkt_freedom(packet, bPointer+currLenght, 0);
    delayMicroseconds(64);
  }
  delay(4);

  currentAP++;
}

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


Optimise data types

Optimise data types

fatal: remote error: upload-pack: not our ref 8b50da8de7974c06bc2e1672521cace690051025
fatal: the remote end hung up unexpectedly


Create sensoreColore.ino

Create sensoreColore.ino

[code]
#define VCC  12
#define OUT  10
#define S2   8
#define S3   9
#define S0   6
#define S1   7

#define  Filters_R  0
#define  Filters_G  1
#define  Filters_B  2

long count = 0;
int counter = 0;
int G_flag = 1;
int RGB = 0;
float scaleFactor[3];

/******************************************
* IMPORTANT - Make sure you calibrate
* your sensor for White Balance initially
* e.g. place your TCS3200 in front
* of a piece of white paper
*******************************************/

void setup()
{
  pinMode(OUT, INPUT);
  pinMode(S2, OUTPUT);
  pinMode(S3, OUTPUT);
  pinMode(S0, OUTPUT);
  pinMode(S1, OUTPUT);

  digitalWrite(S2, HIGH);
  digitalWrite(S3, LOW);
  digitalWrite(S0, LOW);  // OUTPUT FREQUENCY SCALING 2%
  digitalWrite(S1, HIGH);

  Serial.begin(9600);
  Serial.println("Starting...");

  digitalWrite(VCC, HIGH);
  delay(100);

  for(int i=0; i<3; i++)
  {
    Select_Filters(i);
    int lastDigitalRead = HIGH;
    for(int j=0; j<20000; j++)
    {
      int digitalReadValue = digitalRead(OUT);
      if (lastDigitalRead == LOW && digitalReadValue == HIGH)
      {
        count++;
      }
      counter++;
      lastDigitalRead = digitalReadValue;
    }

    scaleFactor[i] = 255.0/count;

    Serial.print("count: ");
    Serial.println(count);
    Serial.print("counter: ");
    Serial.println(counter);
    Serial.print("scaleFactor: ");
    Serial.println(scaleFactor[i],9);
    counter=0;
    count=0;
  }

  digitalWrite(VCC, LOW);

}

void loop()
{
  Serial.println("loop");

  digitalWrite(VCC, HIGH);
  delay(100);

  for(int i=0; i<3; i++)
  {
    RGB=i;
    Select_Filters(i);
    count=0;
    int lastDigitalRead = HIGH;
    for(int j=0; j<20000; j++)
    {
      int digitalReadValue = digitalRead(OUT);
      if (lastDigitalRead == LOW && digitalReadValue == HIGH)
      {
        count++;
      }
      counter++;
      lastDigitalRead = digitalReadValue;
    }

    Serial.print("value: ");
    Serial.println(scaleFactor[i]*count);
    Serial.print("counter ");
    Serial.println(counter);
    counter=0;
    count=0;
  }

  digitalWrite(VCC, LOW);
  digitalWrite(S2, LOW);
  digitalWrite(S3, LOW);
  digitalWrite(S0, LOW);
  digitalWrite(S1, LOW);

  delay(6000);
  digitalWrite(S1, HIGH);
}

void Select_Filters(int RGB)
{
  switch(RGB)
  {
    case Filters_R:          //Red
    digitalWrite(S2, LOW);
    digitalWrite(S3, LOW);
    Serial.println("-----select Red color");
    break;

    case Filters_G:          //Green
    digitalWrite(S2, HIGH);
    digitalWrite(S3, HIGH);
    Serial.println("-----select Green color");
    break;

    case Filters_B:          //Blue
    digitalWrite(S2, LOW);
    digitalWrite(S3, HIGH);
    Serial.println("-----select Blue color");
    break;

    default:                  //Clear(no filter)
    digitalWrite(S2, HIGH);
    digitalWrite(S3, LOW);
    Serial.println("-----no filter");
    break;
  }
}

[/code]

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


Create robottino_run.ino

Create robottino_run.ino

/**
Bruno Santos, 2013
feiticeir0@whatgeek.com.pt
modified by Gaspar Torriero 2015

DC motors - 2x with a L298 Dual H-Bridge Motor Driver
2 x HC-SR04 ultrasound sensors
**/

#include <Wire.h>
//Ultrasound sensor
#define ECHOPINR 12
#define TRIGPINR 11
#define ECHOPINL 7
#define TRIGPINL 6
//Minimum distance from obstacle
int minDistance = 10;
int medDistance = 20;
int cmR;
int cmL;

//TDC Motors
//Define Pins
//Motor A
int enableA = 10;
int pinA1 = 2;
int pinA2 = 3;

//Motor B
int enableB = 9;
int pinB1 = 4;
int pinB2 = 5;
//define time for run
// in milliseconds
int running = 10000; //10 secons
boolean play;

void setup() {
  //Serial.begin (9600);
  //Configue sensor pin modes
  pinMode(ECHOPINR, INPUT);
  pinMode(TRIGPINR, OUTPUT);
  pinMode(ECHOPINL, INPUT);
  pinMode(TRIGPINL, OUTPUT);

  //configure motor pin modes
  pinMode (enableA, OUTPUT);
  pinMode (pinA1, OUTPUT);
  pinMode (pinA2, OUTPUT);

  pinMode (enableB, OUTPUT);
  pinMode (pinB1, OUTPUT);
  pinMode (pinB2, OUTPUT);

  play = true;

}
//Defining functions so it's more easy

//motor functions
void motorAforward() {
  digitalWrite (pinA1, HIGH);
  digitalWrite (pinA2, LOW);
}
void motorBforward() {
  digitalWrite (pinB1, LOW);
  digitalWrite (pinB2, HIGH);
}
void motorAbackward() {
  digitalWrite (pinA1, LOW);
  digitalWrite (pinA2, HIGH);
}
void motorBbackward() {
  digitalWrite (pinB1, HIGH);
  digitalWrite (pinB2, LOW);
}
void motorAstop() {
  digitalWrite (pinA1, HIGH);
  digitalWrite (pinA2, HIGH);
}
void motorBstop() {
  digitalWrite (pinB1, HIGH);
  digitalWrite (pinB2, HIGH);
}
void motorAcoast() {
  digitalWrite (pinA1, LOW);
  digitalWrite (pinA2, LOW);
}
void motorBcoast() {
  digitalWrite (pinB1, LOW);
  digitalWrite (pinB2, LOW);
}
void motorAon() {
  digitalWrite (enableA, HIGH);
}
void motorBon() {
  digitalWrite (enableB, HIGH);
}
void motorAoff() {
  digitalWrite (enableA, LOW);
}
void motorBoff() {
  digitalWrite (enableB, LOW);
}
// Movement functions
void forward (int duration) {
  motorAforward();
  motorBforward();
  delay (duration);
}
void backward (int duration) {
  motorAbackward();
  motorBbackward();
  delay (duration);
}
void hardleft (int duration) {
  motorBbackward();
  motorAforward();
  delay (duration);
}
void hardright (int duration) {
  motorBforward();
  motorAbackward();
  delay (duration);
}
void left (int duration) {
  motorBstop();
  motorAforward();
  delay (duration);
}
void right (int duration) {
  motorBforward();
  motorAstop();
  delay (duration);
}
void coast (int duration) {
  motorAcoast();
  motorBcoast();
  delay (duration);
}
void breakRobot (int duration) {
  motorAstop();
  motorBstop();
  delay (duration);
}
void disableMotors() {
  motorAoff();
  motorBoff();
}
void enableMotors() {
  motorAon();
  motorBon();
}

void loop() {

  while (play) {
    enableMotors();
    //   hardright (1);

    //Measure obstacle distance in cm

    digitalWrite(TRIGPINR, LOW);
    delayMicroseconds(2);
    digitalWrite(TRIGPINR, HIGH);
    delayMicroseconds(10);
    digitalWrite(TRIGPINR, LOW);
    float distanceR = pulseIn(ECHOPINR, HIGH);
    cmR = distanceR / 58;

    digitalWrite(TRIGPINL, LOW);
    delayMicroseconds(2);
    digitalWrite(TRIGPINL, HIGH);
    delayMicroseconds(10);
    digitalWrite(TRIGPINL, LOW);
    float distanceL = pulseIn(ECHOPINL, HIGH);
    cmL = distanceL / 58;

    if ((cmR < minDistance) || (cmL < minDistance)) {
      if (cmR < cmL) {
        hardleft(5);
      }
      else if (cmL < cmR) {
        hardright (5);
      }
    }
    else if ((cmR < medDistance) || (cmL < medDistance)) {
      if (cmR < cmL) {
        left(5);
      }
      else if (cmL < cmR) {
        right (5);
      }
    }
    else {
      forward (5);
    }
  }
}

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


add example

add example

/**
 * AATR
 *
 * @author    Ibán Domínguez <ibandominguez@hotmail.com>
 * @copyright 2015 Ibán Domínguez (http://www.ibandominguez.com)
 * @license   http://www.opensource.org/licenses/mit-license.php MIT
 * @link      https://github.com/ibandominguez/aatr
 */

#include "aatr.h"

AATR *sensor = new AATR(A0);

void setup() {
  Serial.begin(9600);
}

void loop() {
  Serial.print("Celcius:\t");
  Serial.print(sensor->read()->getTmp('C'));
  Serial.print("\n");

  delay(500);
}

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


Combined accelerometer and data logger.

Combined accelerometer and data logger.

//-------------------------------------------------------------------------------
//  TinyCircuits Accelerometer TinyShield Example Sketch
//  Using Bosch BMA250 in I2C mode
//
//  Created 6/30/2013
//  by Ken Burns, TinyCircuits http://Tiny-Circuits.com
//
//  This example code is in the public domain.
//
//-------------------------------------------------------------------------------

#include <Wire.h>
#include <SD.h>
#include <stdlib.h>

#define BMA250_I2CADDR      0x18
#define BMA250_RANGE        0x03   // 0x03 = 2g, 0x05 = 4g, 0x08 = 8g, 0x0C = 16g
#define BMA250_BW           0x08   // 7.81Hz (update time of 64ms)

int AccelX;
int AccelY;
int AccelZ;
float AccelTemperature;
const int chipSelect = 10;
char buffer[50];

void setup()
{
  Wire.begin();
  Serial.begin(9600);
  BMA250Init();

  Serial.print("Initializing SD card...");
  // make sure that the default chip select pin is set to
  // output, even if you don't use it:
  pinMode(10, OUTPUT);

  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");

}

void loop()
{
  BMA250ReadAccel();

  // make a string for assembling the data to log:
  String dataString = "";

  // Print out the accelerometer data
  dataString += "x: ";
  dataString += String(AccelX);
  dataString += ", y: ";
  dataString += String(AccelY);
  dataString += ", z: ";
  dataString += String(AccelZ);
  dataString += ", t: ";
  dtostrf(AccelTemperature,10,5,buffer);
  dataString += buffer;
  dataString += "degC";

  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  File dataFile = SD.open("datalog.txt", FILE_WRITE);

  // if the file is available, write to it:
  if (dataFile) {
    dataFile.println(dataString);
    dataFile.close();
    // print to the serial port too:
    Serial.println(dataString);
  }
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening datalog.txt");
  }
  delay(100);
}

void BMA250Init()
{
  // Setup the range measurement setting
  Wire.beginTransmission(BMA250_I2CADDR);
  Wire.write(0x0F);
  Wire.write(BMA250_RANGE);
  Wire.endTransmission();

  // Setup the bandwidth
  Wire.beginTransmission(BMA250_I2CADDR);
  Wire.write(0x10);
  Wire.write(BMA250_BW);
  Wire.endTransmission();
}

int BMA250ReadAccel()
{
  uint8_t ReadBuff[8];

  // Read the 7 data bytes from the BMA250
  Wire.beginTransmission(BMA250_I2CADDR);
  Wire.write(0x02);
  Wire.endTransmission();
  Wire.requestFrom(BMA250_I2CADDR,7);

  for(int i = 0; i < 7;i++)
  {
    ReadBuff[i] = Wire.read();
  }

  AccelX = ReadBuff[1] << 8;
  AccelX |= ReadBuff[0];
  AccelX >>= 6;

  AccelY = ReadBuff[3] << 8;
  AccelY |= ReadBuff[2];
  AccelY >>= 6;

  AccelZ = ReadBuff[5] << 8;
  AccelZ |= ReadBuff[4];
  AccelZ >>= 6;

  AccelTemperature = (ReadBuff[6] * 0.5) + 24.0;
}

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


Create CRGBSet_example2.ino

Create CRGBSet_example2.ino

// Marc Miller, Oct 2017

#include "FastLED.h"
#define NUM_LEDS 32

//CRGB leds[NUM_LEDS];  // Not using this.  Using CRGBArray instead.
CRGBArray<NUM_LEDS> leds;

CRGBSet partA(leds(0,NUM_LEDS/2-1));  // First half of strip.
CRGBSet partB(leds(NUM_LEDS/2,NUM_LEDS-1));  // Second half of strip.

//---------------------------------------------------------------
void setup() {
  delay(500);
  FastLED.addLeds<LPD8806, 11, 13, GRB>(leds, NUM_LEDS);
  FastLED.setBrightness(255);
}

//---------------------------------------------------------------
void loop()
{
  //Fill first half of strip with moving rainbow
  fill_rainbow( partA, NUM_LEDS/2, millis()/20);

  /*Three different ways to copy the data.
   * The second two mirror the data.
   * Uncomment one at a time to test out. */

  //partB = partA;  //creates dupicate copy in second half of strip
  leds(NUM_LEDS-1,NUM_LEDS/2) = partA;  //creates mirrored copy in second half of strip
  //partB = leds(NUM_LEDS/2-1,0);  //creates mirrored copy in second half of strip

  FastLED.show();
  delay(2);
}

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