Fixed TransmitInterrupt example

Fixed TransmitInterrupt example

--- examples/TransmitInterrupt/TransmitInterrupt.ino
+++ examples/TransmitInterrupt/TransmitInterrupt.ino
@@ -26,9 +26,12 @@
 // DIO1 pin:  3
 // IMPORTANT: because this example uses external interrupts,
 //            DIO0 MUST be connected to Arduino pin 2 or 3.
-//            DIO1 MAY be connected to any free pin
+//            DIO1 MAY be connected to any free pin
 //            or left floating.
 SX1278 lora = new LoRa;
+
+// save transmission state between loops
+int transmissionState = ERR_NONE;

 void setup() {
   Serial.begin(9600);
@@ -53,7 +56,7 @@
     while (true);
   }

-  // set the function that will be called
+  // set the function that will be called
   // when packet transmission is finished
   lora.setDio0Action(setFlag);

@@ -62,7 +65,7 @@

   // you can transmit C-string or Arduino string up to
   // 256 characters long
-  state = lora.startTransmit("Hello World!");
+  transmissionState = lora.startTransmit("Hello World!");

   // you can also transmit byte array up to 256 bytes long
   /*
@@ -70,36 +73,62 @@
                       0x78, 0xAB, 0xCD, 0xEF};
     state = lora.startTransmit(byteArr, 8);
   */
-
-  if (state != ERR_NONE) {
-    Serial.print(F("failed, code "));
-    Serial.println(state);
-  }
 }

 // flag to indicate that a packet was received
 volatile bool transmittedFlag = false;

+// disable interrupt when it's not needed
+volatile bool enableInterrupt = true;
+
+// this function is called when a complete packet
+// is transmitted by the module
+// IMPORTANT: this function MUST be 'void' type
+//            and MUST NOT have any arguments!
 void setFlag(void) {
-  // packet transmission is finished, set the flag
+  // check if the interrupt is enabled
+  if(!enableInterrupt) {
+    return;
+  }
+
+  // we sent a packet, set the flag
   transmittedFlag = true;
 }

 void loop() {
   // check if the previous transmission finished
   if(transmittedFlag) {
-    Serial.println(F("transmission finished!"));
+    // disable the interrupt service routine while
+    // processing the data
+    enableInterrupt = false;

-    // wait one second before next transmission
+    // reset flag
+    transmittedFlag = false;
+
+    if (transmissionState == ERR_NONE) {
+      // packet was successfully sent
+      Serial.println(F("transmission finished!"));
+
+      // NOTE: when using interrupt-driven transmit method,
+      //       it is not possible to automatically measure
+      //       transmission data rate using getDataRate()
+
+    } else {
+      Serial.print(F("failed, code "));
+      Serial.println(transmissionState);
+
+    }
+
+    // wait a second before transmitting again
     delay(1000);

-    // send another packet
+    // send another one
     Serial.print(F("Sending another packet ... "));

     // you can transmit C-string or Arduino string up to
     // 256 characters long
-    int state = lora.startTransmit("Hello World!");
-
+    transmissionState = lora.startTransmit("Hello World!");
+
     // you can also transmit byte array up to 256 bytes long
     /*
       byte byteArr[] = {0x01, 0x23, 0x45, 0x56,
@@ -107,14 +136,8 @@
       int state = lora.transmit(byteArr, 8);
     */

-    // NOTE: when using interrupt-driven transmit method,
-    //       it is not possible to automatically measure
-    //       transmission data rate using getDataRate()
-
-    if (state != ERR_NONE) {
-      Serial.print(F("failed, code "));
-      Serial.println(state);
-    }
+    // we're ready to send more packets,
+    // enable interrupt service routine
+    enableInterrupt = true;
   }
-
 }


updated esc_calib to prevent motors from running while uploading the sketch

--- arduino/src/T-80AFLAME/esc_calib/esc_calib.ino
+++ arduino/src/T-80AFLAME/esc_calib/esc_calib.ino
@@ -179,6 +179,12 @@
   ESC3.attach(MOTOR_BL);
   ESC4.attach(MOTOR_BR);

+  // Set RC channel value to "rest"
+  channels[0] = RC_MIN;
+  channels[1] = RC_MID;
+  channels[2] = RC_MID;
+  channels[3] = RC_MID;
+
   delay(10);

 }
@@ -187,7 +193,13 @@
 {
   readRC(channels);

-  // map(channels[0], RC_MIN, RC_MAX, ESC_MIN, ESC_MAX)
+  if (channels[1] == 0 & channels[2] == 0 & channels[3] == 0) {
+    channels[0] = RC_MIN;
+    channels[1] = RC_MID;
+    channels[2] = RC_MID;
+    channels[3] = RC_MID;
+  }
+
   rcthr = channels[0];
   rcroll = map(channels[1], RC_MIN, RC_MAX, -150, 150);
   rcpit = map(channels[2], RC_MIN, RC_MAX, -150, 150);


Add command for setting screen (breaks protocol)

--- arduino/udp-flippers-serial-switches/udppins-serial.ino
+++ arduino/udp-flippers-serial-switches/udppins-serial.ino
@@ -126,23 +126,39 @@

 }

+
 void loop(void) {
     uint8_t oldstate = 0;
     if (udpServer.available()) {

-      char buffer[UDP_READ_BUFFER_SIZE];
+      byte buffer[UDP_READ_BUFFER_SIZE];
       int n = udpServer.readData(buffer, UDP_READ_BUFFER_SIZE);  // n contains # of bytes read into buffer

-      if (n >= 1) {
-        uint8_t state = buffer[0];
-        for (int i = 0; i < 4; i++) {
-          digitalWrite(6+i, state & (1 << i) ? HIGH : LOW);
+      if (n >= 2) {
+	byte msg = buffer[0];
+
+	// Message 1: 0xff then byte with new state
+	if (msg == 0xff) {
+	  byte state = buffer[1];
+
+          for (int i = 0; i < 4; i++) {
+            digitalWrite(6+i, state & (1 << i) ? HIGH : LOW);
+          }
+          if (oldstate != state) {
+            lcd.setBacklight(WHITE);
+            lcd.setBacklight(GREEN);
+          }
+          oldstate = state;
         }
-        if (oldstate != state) {
-          lcd.setBacklight(WHITE);
-          lcd.setBacklight(GREEN);
-        }
-        oldstate = state;
+	// Message 2: length then that many bytes with new lcd text
+	else {
+	  lcd.setCursor(0,0);
+	  lcd.print("                ");
+	  lcd.setCursor(0,0);
+	  for (int i = 1; i <= max(max(msg, n), 16); i++) {
+	    lcd.print(msg[i]);
+	  }
+	}
       }
    }
 }


Delete Project_19_Scanner.ino

Delete Project_19_Scanner.ino

--- Arduino/Project_19_Scanner/Project_19_Scanner.ino
+++ Arduino/Project_19_Scanner/Project_19_Scanner.ino
@@ -1,33 +0,0 @@
-
-const int scanPin = A0;
-const int resetPin = A1;
-const int pulseLength = 1000;
-const int period = 5000;
-const int numStations = 5;
-
-int count = 0;
-
-void setup()
-{
-  pinMode(scanPin, INPUT);
-  pinMode(resetPin, INPUT);
-}
-
-void loop()
-{
-  delay(period);
-  pinMode(scanPin, OUTPUT);
-  digitalWrite(scanPin, HIGH);
-  delay(pulseLength);
-  pinMode(scanPin, INPUT);
-  count ++;
-  if (count == numStations)
-  {
-    count = 0;
-    pinMode(resetPin, OUTPUT);
-    digitalWrite(resetPin, HIGH);
-    delay(pulseLength);
-    pinMode(resetPin, INPUT);
-  }
-}
-


done with i/o

done with i/o

--- colors_arduino/colors_arduino.ino
+++ colors_arduino/colors_arduino.ino
@@ -21,29 +21,34 @@
 boolean gameInProgress = false;
 boolean buttonPressed = false;

-// Pins for inputs (push buttons) and outputs (shift registers / LEDs)
+// Pins for inputs (push buttons)
 const int UP_PIN = A0;
-const int RIGHT_PIN = 0; // TODO
-const int DOWN_PIN = 0; // TODO
-const int LEFT_PIN = 0; // TODO
-const int FOO = 13; // TODO
-
-const int colorMap[8] = {0, 0, 0, 0, 0, 0, 0, 0}; // TODO
-const int pinMap[4]]4]; // TODO
+const int RIGHT_PIN = A1;
+const int DOWN_PIN = A2;
+const int LEFT_PIN = A3;
+
+// Pins for outputs (shift registers / LEDs)
+const int LATCH_PIN = 8; // green
+const int CLOCK_PIN = 12; // yellow
+const int DATA_PIN = 11; // blue

 /* Initializes all connections and creates a new game. */
 void setup() {
     // Initialize serial
     Serial.begin(9600);

-    // Initialize inputs and outputs
+    // Initialize inputs (push buttons) and outputs (shift registers and LEDs)
     pinMode(UP_PIN, INPUT);
     pinMode(RIGHT_PIN, INPUT);
     pinMode(DOWN_PIN, INPUT);
     pinMode(LEFT_PIN, INPUT);
-    pinMode(FOO, OUTPUT); // TODO
-
-    // TODO ~ Seed the PRNG with something reasonable
+
+    pinMode(LATCH_PIN, OUTPUT);
+    pinMode(CLOCK_PIN, OUTPUT);
+    pinMode(DATA_PIN, OUTPUT);
+
+    // Seed the PRNG with the read from an unconnected pin
+    randomSeed(analogRead(A4));

     // Begin game
     newGame();
@@ -57,27 +62,27 @@
     }

     // Read inputs
-    int upVal = digitalRead(UP_PIN);
-    int rightVal = digitalRead(RIGHT_PIN);
-    int downVal = digitalRead(DOWN_PIN);
-    int leftVal = digitalRead(LEFT_PIN);
+    int upVal = analogRead(UP_PIN);
+    int rightVal = analogRead(RIGHT_PIN);
+    int downVal = analogRead(DOWN_PIN);
+    int leftVal = analogRead(LEFT_PIN);

     // Confirm that there was no previous button press (so we don't respond too many times)
     if (!buttonPressed) {
         // Make a move
-        if (upVal == HIGH) {
+        if (upVal) {
             buttonPressed = true;
             makeMove(UP);
         }
-        else if (rightVal == HIGH) {
+        else if (rightVal) {
             buttonPressed = true;
             makeMove(RIGHT);
         }
-        else if (downVal == HIGH) {
+        else if (downVal) {
             buttonPressed = true;
             makeMove(DOWN);
         }
-        else if (leftVal == HIGH) {
+        else if (leftVal) {
             buttonPressed = true;
             makeMove(LEFT);
         }
@@ -145,24 +150,44 @@

     switch(dir) {
         case UP:
-            // TODO
+            for (int j = 0; j <= 3; j++) {
+                for (int i = 0; i <= 3; i++) {
+                    if (i == 0) {
+                        continue;
+                    }
+                    movedAnythingYet = attemptTileMove(i, j, i - 1, j) || movedAnythingYet;
+                }
+            }
         break;

         case RIGHT:
-            // TODO
+            for (int i = 0; i <= 3; i++) {
+                for (int j = 3; j >= 0; j--) {
+                    if (j == 3) {
+                        continue;
+                    }
+                    movedAnythingYet = attemptTileMove(i, j, i, j + 1) || movedAnythingYet;
+                }
+            }
         break;

         case DOWN:
-            // TODO
+            for (int j = 0; j <= 3; j++) {
+                for (int i = 3; i >= 0; i--) {
+                    if (i == 3) {
+                        continue;
+                    }
+                    movedAnythingYet = attemptTileMove(i, j, i + 1, j) || movedAnythingYet;
+                }
+            }
         break;

         case LEFT:
-            for (int i = 0; i < 4; i++) {
-                for (int j = 0; j < 4; j++) {
+            for (int i = 0; i <= 3; i++) {
+                for (int j = 0; j <= 3; j++) {
                     if (j == 0) {
                         continue;
                     }
-
                     movedAnythingYet = attemptTileMove(i, j, i, j - 1) || movedAnythingYet;
                 }
             }
@@ -174,8 +199,7 @@
         return false;
     }

-    // Otherwise, it was valid, so add a new tile
-    // TODO
+    // TODO ~ Insert new tile

     return true;
 }
@@ -189,33 +213,67 @@
     }

     // Whoops, we lost the game
-    lostGame();
-}
-
-void lostGame() {
-    // Update game state
     gameInProgress = false;
-
-    // TODO ~ Do something to show they lost (womp womp)
-}
-
-void wonGame() {
-    // Update game state
-    gameInProgress = false;
-
-    // TODO ~ Do something to show they won (woohooo!)
+    Serial.println("L");
 }

 /****************************************
  ********** DISPLAY  METHODS ************
  ****************************************/

- void renderBoard() {
-    // TODO ~ Hahahahahahahaha
+byte colors[8] = {7, 6, 4, 5, 1, 3, 2, 0};
+
+byte color(int tileNum) {
+    tileNum -= 1;
+    int i = tileNum / 4;
+    int j = tileNum % 4;
+    int value = board[i][j];
+    return colors[value];
+}
+
+void renderBoard() {
+    byte A = color(15) % 2     << 0
+           + color( 1)         << 1
+           + color( 2)         << 4
+           + color( 3) % 2     << 7;
+
+    byte B = color(15) % 4 / 2 << 0
+           + color( 3) / 2     << 1
+           + color( 4)         << 3
+           + color( 5) % 4     << 6;
+
+    byte C = color(15) / 4     << 0
+           + color( 5) / 4     << 1
+           + color( 6)         << 2
+           + color( 7)         << 5;
+
+    byte D = color(16) % 2     << 0
+           + color( 8)         << 1
+           + color( 9)         << 4
+           + color(10) % 2     << 7;
+
+    byte E = color(16) % 4 / 2 << 0
+           + color(10) / 2     << 1
+           + color(11)         << 3
+           + color(12) % 4     << 6;
+
+    byte F = color(16) / 4     << 0
+           + color(12) / 4     << 1
+           + color(13)         << 2
+           + color(14)         << 5;
+
+    digitalWrite(LATCH_PIN, LOW);
+    shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, F);
+    shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, E);
+    shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, D);
+    shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, C);
+    shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, B);
+    shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, A);
+    digitalWrite(LATCH_PIN, HIGH);
  }

- /* Prints board to serial. For debugging. */
- void printBoard() {
+/* Prints board to serial. For debugging. */
+void printBoard() {
     for (int i = 0; i < 4; i++) {
         for (int j = 0; j < 4; j++) {
             Serial.print(board[i][j]);
@@ -224,13 +282,13 @@
     }
  }

- /****************************************
- ********** UTILITY METHODS *************
- ****************************************/
-
- /* Randomly returns either 0 or 1. */
+/****************************************
+********** UTILITY METHODS *************
+****************************************/
+
+/* Randomly returns either 1 or 2. */
 int randomTile() {
-    return random(0, 2);
+    return random(1, 3);

 }

@@ -258,6 +316,13 @@
     if (tempBoard[i][j] == tempBoard[i2][j2]) {
         tempBoard[i][j] = 0;
         tempBoard[i2][j2]++;
+
+        // They won!
+        if (tempBoard[i2][j2] == 6) {
+            gameInProgress = false;
+            Serial.println("W");
+        }
+
         return true;
     }


Update AnalogReadSendBytes.ino

Update AnalogReadSendBytes.ino

--- Arduino/SerialCommunication/AnalogReadSendBytes/AnalogReadSendBytes.ino
+++ Arduino/SerialCommunication/AnalogReadSendBytes/AnalogReadSendBytes.ino
@@ -15,8 +15,6 @@
   while (!Serial) {
     ; // wait for serial port to connect. Needed for native USB port only
   }
-
-  pinMode(2, INPUT);   // digital sensor is on digital pin 2  establishContact();  // send a byte to establish contact until receiver responds
 }

 void loop() {


Random LEDs turn on

Random LEDs turn on

Turns on a random number of LEDs
It creates a list of LED numbers from 1 to 4
of random length

Also, corrected an error with the looping over
the array of LEDs to turn on

Signed-off-by: nisha <ba6353e519422079c5746796dcd035c620a84798@gmail.com>

--- sketch_blinkybracelet/sketch_blinkybracelet.ino
+++ sketch_blinkybracelet/sketch_blinkybracelet.ino
@@ -45,9 +45,9 @@
  * We need to do a list because the LEDs
  * are all tied together
  */
-void turnOn(int indexArray[], int no)
+void turnOn(int indexArray[], int len)
 {
-  for (int i=0; i<no; i++)
+  for (int i=0; i<len; i++)
   {
     int ledNo = indexArray[i]-1;
     // set pinmode
@@ -61,12 +61,23 @@
   }
 }

-void setup() {
+void setup()
+{
   reset();
+  randomSeed(analogRead(A0)); //seed random number generator
+  Serial.begin(9600);
 }

 void loop() {
-  // Turn on 1 and 4
-  int onLeds[] = {1, 4};
-  turnOn(onLeds, sizeof(onLeds));
+  // Generate a random number of leds
+  int noLeds = (int) random(1,5);
+  int onLeds[noLeds];
+  for (int i=0; i<noLeds; i++)
+  {
+    onLeds[i] = i+1;
+  }
+  for (int i=0; i<1000; i++)
+  {
+    turnOn(onLeds, noLeds);
+  }
 }


Moved refresh client from html meta tag to http header Fixes #953

--- libraries/Ethernet/examples/WebServer/WebServer.ino
+++ libraries/Ethernet/examples/WebServer/WebServer.ino
@@ -22,7 +22,7 @@
 // The IP address will be dependent on your local network:
 byte mac[] = {
   0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
-IPAddress ip(192,168,1, 177);
+IPAddress ip(192,168,1,177);

 // Initialize the Ethernet server library
 // with the IP address and port you want to use
@@ -64,11 +64,10 @@
           client.println("HTTP/1.1 200 OK");
           client.println("Content-Type: text/html");
           client.println("Connection: close");
+	  client.println("Refresh: 5");
           client.println();
           client.println("<!DOCTYPE HTML>");
           client.println("<html>");
-                    // add a meta refresh tag, so the browser pulls again every 5 seconds:
-          client.println("<meta http-equiv=\"refresh\" content=\"5\">");
           // output the value of each analog input pin
           for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
             int sensorReading = analogRead(analogChannel);


Final Implementation (Minus PartyMode)

Final Implementation (Minus PartyMode)

--- LED_CODE.ino
+++ LED_CODE.ino
@@ -102,7 +102,6 @@
 	pinMode(9,OUTPUT);
 	pinMode(10,OUTPUT);
 	pinMode(11,OUTPUT);
-	Serial.begin(9600);
 	analogReference(EXTERNAL);
 }

@@ -161,10 +160,9 @@
 		delay(10);        // delay in between reads for stability
   	}
   	if(ar[0]==ar[1] && ar[1]==ar[2]){
-
 		if (ar[1]==1023)
 			return(4);
-		if (ar[1]==513)
+		if (ar[1]==512)
 			return(1);
 		if (ar[1]==256)
 			return(3);
@@ -192,9 +190,15 @@
 }

 void apply(int r, int g, int b){
-	analogWrite(10,r); // red transistor base pin @ 9
-	analogWrite(11,g); // green transistor base pin @ 10
-	analogWrite(9,b); // blue transistor base pin @ 11
+	analogWrite(10,r);
+	analogWrite(11,g);
+	analogWrite(9,b);
+}
+void screenApply(int r, int g, int b){
+	analogWrite(3, 255-g);
+	analogWrite(5, 255-b);
+	analogWrite(6, 255-r);
+
 }

 void fullfade(){   // fade from red to green
@@ -259,8 +263,8 @@
 		lcd.print(bpot*10/102);
 		if(consolidate()==LEFT) return;
 		lcd.print(" ");
-		apply(rpot/4,gpot/4,bpot/4)
-;	}
+		apply(rpot/4,gpot/4,bpot/4);
+	}
 }

 void strobeMode(){
@@ -282,9 +286,8 @@
 }
 void loop(){ //Menu navigation - pushes to the functions.
 	if(millis()<100){delay(100);} // don't jump the gun!
-	apply(modeCols[2][0],modeCols[2][1],modeCols[2][2]);
+	screenApply(modeCols[2][0],modeCols[2][1],modeCols[2][2]);
 	int cons=consolidate();
-	Serial.println(cons);
 	switch(cons){ // Choose what to do with an input/ no input
 		case NONE: //No movement(Display the screen)
 			lcd.setCursor(0,0);
@@ -302,8 +305,6 @@
 					lcd.print("-");
 					break;
 				default:
-				lcd.setCursor(0,0);
-		  			lcd.print('error');
 		  			break;
 			}
 			break;
@@ -323,7 +324,6 @@
 			    	menuPos[currentMenu]-=1;
 			    	break;
 			    default:
-			    	Serial.print("error45");
 			    	break;
 			}
 			break;
@@ -343,7 +343,6 @@
 				    	menuPos[currentMenu]+=1;
 				    	break;
 				    default:
-				    	Serial.print("error55");
 				    	break;
 			}
 			break;
@@ -386,7 +385,6 @@
 			    			break;

 			    		default:
-			    			lcd.print("Balls");
 			    			break;
 			    	}
 			    	break;
@@ -403,13 +401,11 @@

 			    default:
-			    Serial.print("tester");
 			      break;
 			}
 			break;

 		default:
-			Serial.print("error05");
 			break;

 }


Fine-tune the reset function.  Before, it was too fast and sometimes the drives would not respond or would respond incorrectly.


Disable interrupts while resetting; it fixes all the reset problems.

--- Arduino/Moppy/Moppy.ino
+++ Arduino/Moppy/Moppy.ino
@@ -136,8 +136,10 @@
     if(currentTick[2]>=currentPeriod[2]){
       if(currentPosition[2]>=MAX_POSITION){
         sbi(portd,3);
+        sbi(portddirection,3);
       }else if(currentPosition[2]<=MIN_POSITION){
         cbi(portd,3);
+        cbi(portddirection,3);
       }

       //Update currentPosition
@@ -150,10 +152,8 @@
       //Pulse the control pin
       if(ebi(portd,2)){
         cbi(portd,2);
-        cbi(portddirection,2);
       }else{
         sbi(portd,2);
-        sbi(portddirection,2);
       }
       currentTick[2]=0;
     }
@@ -163,8 +163,10 @@
     if(currentTick[4]>=currentPeriod[4]){
       if(currentPosition[4]>=MAX_POSITION){
         sbi(portd,5);
+        sbi(portddirection,5);
       }else if(currentPosition[4]<=MIN_POSITION){
         cbi(portd,5);
+        cbi(portddirection,5);
       }

       if(ebi(portd,5)){
@@ -175,10 +177,8 @@

       if(ebi(portd,4)){
         cbi(portd,4);
-        cbi(portddirection,4);
       }else{
         sbi(portd,4);
-        sbi(portddirection,4);
       }
       currentTick[4]=0;
     }
@@ -188,8 +188,10 @@
     if(currentTick[6]>=currentPeriod[6]){
       if(currentPosition[6]>=MAX_POSITION){
         sbi(portd,7);
+        sbi(portddirection,7);
       }else if(currentPosition[6]<=MIN_POSITION){
         cbi(portd,7);
+        cbi(portddirection,7);
       }

       if(ebi(portd,7)){
@@ -200,10 +202,8 @@

       if(ebi(portd,6)){
         cbi(portd,6);
-        cbi(portddirection,6);
       }else{
         sbi(portd,6);
-        sbi(portddirection,6);
       }
       currentTick[6]=0;
     }
@@ -213,8 +213,10 @@
     if(currentTick[8]>=currentPeriod[8]){
       if(currentPosition[8]>=MAX_POSITION){
         sbi(portb,1);
+        sbi(portbdirection,1);
       }else if(currentPosition[8]<=MIN_POSITION){
         cbi(portb,1);
+        cbi(portbdirection,1);
       }

       if(ebi(portb,1)){
@@ -225,10 +227,8 @@

       if(ebi(portb,0)){
         cbi(portb,0);
-        cbi(portbdirection,0);
       }else{
         sbi(portb,0);
-        sbi(portbdirection,0);
       }
       currentTick[8]=0;
     }
@@ -238,8 +238,10 @@
     if(currentTick[10]>=currentPeriod[10]){
       if(currentPosition[10]>=MAX_POSITION){
         sbi(portb,3);
+        sbi(portbdirection,3);
       }else if(currentPosition[10]<=MIN_POSITION){
         cbi(portb,3);
+        cbi(portbdirection,3);
       }

       if(ebi(portb,3)){
@@ -250,10 +252,8 @@

       if(ebi(portb,2)){
         cbi(portb,2);
-        cbi(portbdirection,2);
       }else{
         sbi(portb,2);
-        sbi(portbdirection,2);
       }
       currentTick[10]=0;
     }
@@ -263,8 +263,10 @@
     if(currentTick[12]>=currentPeriod[12]){
       if(currentPosition[12]>=MAX_POSITION){
         sbi(portb,5);
+        sbi(portbdirection,5);
       }else if(currentPosition[12]<=MIN_POSITION){
         cbi(portb,5);
+        cbi(portbdirection,5);
       }

       if(ebi(portb,5)){
@@ -275,10 +277,8 @@

       if(ebi(portb,4)){
         cbi(portb,4);
-        cbi(portbdirection,4);
       }else{
         sbi(portb,4);
-        sbi(portbdirection,4);
       }
       currentTick[12]=0;
     }
@@ -288,8 +288,10 @@
     if(currentTick[14]>=currentPeriod[14]){
       if(currentPosition[14]>=MAX_POSITION){
         sbi(portc,1);
+        sbi(portcdirection,1);
       }else if(currentPosition[14]<=MIN_POSITION){
         cbi(portc,1);
+        cbi(portcdirection,1);
       }

       if(ebi(portc,1)){
@@ -300,10 +302,8 @@

       if(ebi(portc,0)){
         cbi(portc,0);
-        cbi(portcdirection,0);
       }else{
         sbi(portc,0);
-        sbi(portcdirection,0);
       }
       currentTick[14]=0;
     }
@@ -313,8 +313,10 @@
     if(currentTick[16]>=currentPeriod[16]){
       if(currentPosition[16]>=MAX_POSITION){
         sbi(portc,3);
+        sbi(portcdirection,3);
       }else if(currentPosition[16]<=MIN_POSITION){
         cbi(portc,3);
+        cbi(portcdirection,3);
       }

       if(ebi(portc,3)){
@@ -325,10 +327,8 @@

       if(ebi(portc,2)){
         cbi(portc,2);
-        cbi(portcdirection,2);
       }else{
         sbi(portc,2);
-        sbi(portcdirection,2);
       }
       currentTick[16]=0;
     }
@@ -353,6 +353,8 @@
 //Resets all the pins
 void resetAll(){

+  //Interrupts must be disabled while resetting, otherwise bad things happen
+  cli();
   //Set all the pins to reverse
   PORTD=B10101000;
   PORTB=B00101010;
@@ -364,21 +366,22 @@
     PORTD=B11111100;
     PORTB=B00111111;
     PORTC=B00111111;
-    delay(3);
+    delay(100);
     PORTD=B10101000;
     PORTB=B00101010;
     PORTC=B00101010;
-    delay(5);
+    delay(100);
   }

   //Reset the current position array
   for (byte p=FIRST_PIN;p<=LAST_PIN;p+=2){
-    currentPosition[p] = 0; // We're reset.
+    currentPosition[p]=0;
   }

   //Reset the outputs to forward
   PORTD=portd=portddirection=B00000000;
   PORTB=portb=portbdirection=B00000000;
   PORTC=portc=portcdirection=B00000000;
+  sei();
 }


Update ArduCAM_Mini_5MP_OV5642_Plus_Functions.ino

--- ArduCAM/examples/mini/ArduCAM_Mini_5MP_OV5642_Plus_Functions/ArduCAM_Mini_5MP_OV5642_Plus_Functions.ino
+++ ArduCAM/examples/mini/ArduCAM_Mini_5MP_OV5642_Plus_Functions/ArduCAM_Mini_5MP_OV5642_Plus_Functions.ino
@@ -784,7 +784,7 @@
     {
       Serial.write(pgm_read_byte(&bmp_header[temp]));
     }
-    SPI.transfer(0x00);
+    //SPI.transfer(0x00);
     char VH, VL;
     int i = 0, j = 0;
     for (i = 0; i < 240; i++)


turn off rim by default for now

turn off rim by default for now

--- tests/Light/ButtonTest/ButtonTest.ino
+++ tests/Light/ButtonTest/ButtonTest.ino
@@ -54,7 +54,7 @@
 void setup() {
   Serial.begin(115200);
   configureAnimations();
-  //setStripColor(&rimJob, 255, 255, 255);
+  setStripColor(&rimJob, LED_OFF, LED_OFF, LED_OFF);
   Serial << "Setup Complete" << endl;
 }

@@ -63,7 +63,7 @@
  ******************************************************************************/
 void loop() {
   if (fasterStripUpdateInterval.check()) {
-    animator.animate(colorWipeMatrix, rimConfig);
+    //animator.animate(colorWipeMatrix, rimConfig);
     animator.animate(laserWipe, redButtonConfig);
     animator.animate(laserWipe, greenButtonConfig);
     animator.animate(laserWipe, blueButtonConfig);


Got scaffolding in for basic sketch

Got scaffolding in for basic sketch

--- examples/firmware/src/testBackpack.ino
+++ examples/firmware/src/testBackpack.ino
@@ -0,0 +1,90 @@
+#include "interchange.h"
+
+#define FIRMWARE_VERSION "0.1.0"
+#define DEFAULT_I2C_SENSOR_ADDRESS 0x61
+
+byte register_map[REGISTER_MAP_SIZE];
+
+void setup() {
+
+    // does the configuration check to determine if we're in config mode
+    // or not. This is defaulted to pulling D2 HIGH.
+    config_check();
+
+    if (state == CONFIG) {
+        Serial.begin(9600);
+        run_config(Serial, FIRMWARE_VERSION);
+
+    } else if (state == RUNNING) {
+        uint8_t i2c_address;
+
+        // look up whether we need to use a custom address (eg it's been
+        // set by the interchange client in EEPROM or not. If not use the
+        // default that has been defined above.
+        if (use_custom_address() ) {
+            if (get_i2c_address() > 0) {
+                i2c_address = get_i2c_address();
+            } else {
+                i2c_address = DEFAULT_I2C_SENSOR_ADDRESS;
+            }
+        } else {
+            i2c_address = DEFAULT_I2C_SENSOR_ADDRESS;
+        }
+
+        // fire up the I2C wire protocol and register a callback.
+        Wire.begin(i2c_address);
+        Wire.onRequest(requestData);
+    }
+
+#if _DEBUG
+    if (state != CONFIG) {
+        Serial.begin(9600);
+    }
+
+    // handy debug output to just make sure you're getting what you set properly.
+    Serial.println(F("Test Backpack firmware - DEBUG MODE"));
+    Serial.print(F("Use custom: "));
+    Serial.println(use_custom_address());
+    Serial.print(F("I2C address: "));
+    Serial.println(get_i2c_address());
+#endif
+}
+
+void loop() {
+
+    // main loop is a very simple state machine check to see if we're RUNNING
+    // or in CONFIG mode. If in config we hand off to the interchange lib to
+    // manage this. If not then we can hand over to a function to do some work
+    // in this case we call out to generate_couter()
+    if (state == RUNNING) {
+        generate_counter();
+        delay(1);
+    } else if (state == CONFIG) {
+        interchange_commands();
+    }
+}
+
+void generate_counter() {
+    // simply increments a counter periodically that can be sent back to an
+    // I2C request.
+}
+
+
+void requestData() {
+
+    // when we get a request for data we simply pass the two bytes of the duration
+    // into the register map and then we write that back out on the wire.
+    register_map[0] = duration >> 8;    //MSB
+    register_map[1] = duration & 0xFF;  //LSB
+
+    // write out via I2C using the buffer
+    Wire.write(register_map, REGISTER_MAP_SIZE);
+
+#if _DEBUG
+    Serial.print("rm: ");
+    Serial.print(register_map[0]);
+    Serial.print(" ");
+    Serial.print(register_map[1]);
+    Serial.println();
+#endif
+}


Improving documentation of circuit and wiring.

--- examples/Sandbox/CosaSD/CosaSD.ino
+++ examples/Sandbox/CosaSD/CosaSD.ino
@@ -16,7 +16,17 @@
  * Lesser General Public License for more details.
  *
  * @section Description
- * Demonstration and test of the SD card device driver.
+ * Demonstration and test of the SD card device driver. Allows trace
+ * to the ST7735 TFT Canvas and Textbox (IOStream::Device). This also
+ * allows test and validation of the multiple SPI device handling.
+ *
+ * @section Circuit
+ * This sketch was designed for a HY-1.8 SPI LCD/SD module but may be
+ * used with other SD modules and ST7735 TFT modules. The sketch uses
+ * SPI pins (MOSI, MISO, SCK) and chip/mode select pins. The SPI pins
+ * are common to both SD and TFT. TFT does not use MISO. The default
+ * pins for chip/mode select are used; SD::CS/D8, TFT::CS/D10 and
+ * TFT::A0/D9 (this is the mode pin).
  *
  * This file is part of the Arduino Che Cosa project.
  */
@@ -27,28 +37,27 @@
 #include "Cosa/IOStream/Driver/UART.hh"
 #include "Cosa/Watchdog.hh"

-SD sd;
-
-#define USE_ST7735
-
+// Uncomment to allow trace output to TFT/Canvas/Textbox
+// #define USE_ST7735
 #ifdef USE_ST7735
 #include "Cosa/Canvas.hh"
 #include "Cosa/Canvas/Element/Textbox.hh"
 #include "Cosa/Canvas/Driver/ST7735.hh"

+// Use ST7735 default pins; SPI (MOSI, SCK), CS (D10), AO (D9)
 ST7735 tft;
 Textbox textbox(&tft);
+static const uint8_t WIDTH = 6;
+#else
+static const uint8_t WIDTH = 32;
 #endif
+
+// Use SD default pins; SPI (MISO, MOSI, SCK), CS (D8)
+SD sd;

 void setup()
 {
-  uint8_t buf[SD::BLOCK_MAX];
-  uint8_t save[16];
-  SD::cid_t* cid = (SD::cid_t*) save;
-  SD::csd_t* csd = (SD::csd_t*) save;
-
 #ifdef USE_ST7735
-  static const uint8_t WIDTH = 6;
   IOStream::Device* dev = &textbox;
   tft.begin();
   tft.set_canvas_color(Canvas::WHITE);
@@ -58,13 +67,20 @@
   tft.fill_screen();
 #else
   IOStream::Device* dev = &uart;
-  static const uint8_t WIDTH = 32;
   uart.begin(9600);
 #endif

   Watchdog::begin();
   RTC::begin();
   trace.begin(dev, PSTR("CosaDS: started"));
+}
+
+void loop()
+{
+  uint8_t buf[SD::BLOCK_MAX];
+  uint8_t save[16];
+  SD::cid_t* cid = (SD::cid_t*) save;
+  SD::csd_t* csd = (SD::csd_t*) save;

   INFO("Connect to card and switch to a higher clock frequency", 0);
   ASSERT(sd.begin(SPI::DIV4_CLOCK));
@@ -124,9 +140,5 @@
   SLEEP(1);

   ASSERT(sd.end());
-}
-
-void loop()
-{
   ASSERT(true == false);
 }


Update to use standard WiFi instead of WiFiMulti

I made this change because i need to connect also hidden SSIDs

--- esp8266/cheerlights.ino
+++ esp8266/cheerlights.ino
@@ -5,7 +5,6 @@
 #include <ESP8266WiFi.h>
 #include <ESP8266HTTPClient.h>
 #include <WiFiClient.h>
-#include <ESP8266WiFiMulti.h>
 #include <ESP8266WebServer.h>
 #define FASTLED_ALLOW_INTERRUPTS 0
 #include <FastLED.h>
@@ -15,9 +14,6 @@

 // WEB server configuration port
 #define WEB_SERVER_PORT 80
-
-// Wifi
-ESP8266WiFiMulti wifiMulti;

 // Configuration WIFI name
 #define WIFI_AP_SSID "CheerlightsConfig"
@@ -265,9 +261,9 @@
   delay (2000);

   Serial.print ("Connecting to "); Serial.print (config.apName); Serial.print (' ');
-  wifiMulti.addAP (config.apName, config.password);
+  WiFi.begin (config.apName, config.password);
   delay (5000);
-  while (wifiMulti.run() != WL_CONNECTED) {
+  while (WiFi.status() != WL_CONNECTED) {
     yield();
     setColor (100, 0, 100);
     delay(500);
@@ -324,7 +320,7 @@
     updateColor();

     if (millis() - lastInteractionTime > (long)config.updateFrequency * 1000L) {
-      if (wifiMulti.run() == WL_CONNECTED) {
+      if (WiFi.status() == WL_CONNECTED) {
         WiFiClient client;

         // connect to ThingSpeak


update example for api changes

update example for api changes

--- examples/strandtest/strandtest.ino
+++ examples/strandtest/strandtest.ino
@@ -4,15 +4,16 @@
 #define NUM_PIXELS 30

 Apa102Adapter strip;
-//Apa102Adapter strip(APA102_RGB, 1000000L); // change color order to RGB and data speed to 1MHz
+//Apa102Adapter strip(APA102_RGB); // change color order to RGB

 void setup() {
     strip.begin();
+//    strip.begin(8000000L); // change the data speed to 8MHz
 }

 void loop() {
     for (int counter = 0; counter < NUM_PIXELS; counter++) {
-        strip.show(NUM_PIXELS, [](uint16_t index, uint8_t rgbv[]) {
+        strip.show(NUM_PIXELS, [counter](uint16_t index, uint8_t rgbv[]) {
             //if color order is set right, this should show a bright red pixel on dim green background
             if (counter == index) {
                 rgbv[0] = 255;


Made struct variables private

Made struct variables private

Class, anyone?

--- software/_proto_DriverFirmware/MainControlFirmware/MainControlFirmware.ino
+++ software/_proto_DriverFirmware/MainControlFirmware/MainControlFirmware.ino
@@ -33,7 +33,7 @@

 Timer t;  //Instantiate timer

-struct Display {
+class Display {
 	public:
 		Display(int deviceID);
 		~Display();
@@ -44,6 +44,7 @@
 		void setLeft(char input);
 		void setRight(char * input);
 		void setRight(char input);
+	private:
 		I2cDiscreteIoExpander * device;
 		uint16_t current;
 		uint16_t left;
@@ -90,7 +91,7 @@

   uint16_t to_write = 0;

-  if(!timing){  //Time to do the asynch task
+  if(!timing){  //Time to do the asynch tasks
 	//PCComm.println("[Processing configureToWrite]");

 	i = ++i%10;


Version 1.2a 18th June 2016

Version 1.2a 18th June 2016

* A simple, unified I2C and SPI interface using read-byte and write-byte to transmit data via the appropriate interface, and streams to identify which interface is being used. For more details see I2C and SPI serial interfaces.
* The bitwise logical operators logand, logior, logxor, lognot, logbitp, and the bitwise shift operator ash.
* 1.2a included a minor change that fixed a subtle problem affecting dolist.

--- ulisp.ino
+++ ulisp.ino
@@ -1,10 +1,11 @@
-/* uLisp Version 1.1 - www.ulisp.com
+/* uLisp Version 1.2a - www.ulisp.com
    Copyright (c) 2016 David Johnson-Davies

    Licensed under the MIT license: https://opensource.org/licenses/MIT
 */

 #include <setjmp.h>
+#include <SPI.h>

 // Compile options

@@ -19,6 +20,7 @@

 #define first(x)           (((object *) (x))->car)
 #define second(x)          (car(cdr(x)))
+#define cddr(x)            (cdr(cdr(x)))
 #define third(x)           (car(cdr(cdr(x))))
 #define fourth(x)          (car(cdr(cdr(cdr(x)))))

@@ -26,8 +28,9 @@
 #define pop(y)             ((y) = cdr(y))

 #define numberp(x)         ((x)->type == NUMBER)
-#define listp(x)           ((x)->type != NUMBER && (x)->type != SYMBOL)
-#define consp(x)           ((x)->type != NUMBER && (x)->type != SYMBOL && (x) != NULL)
+#define streamp(x)         ((x)->type == STREAM)
+#define listp(x)           ((x)->type >= PAIR || (x)->type == ZERO)
+#define consp(x)           (((x)->type >= PAIR || (x)->type == ZERO) && (x) != NULL)

 #define mark(x)            (car(x) = (object *)(((unsigned int)(car(x))) | 0x8000))
 #define unmark(x)          (car(x) = (object *)(((unsigned int)(car(x))) & 0x7FFF))
@@ -38,35 +41,26 @@
 // #define debug2

 // Constants
-
-#if defined(__AVR_ATmega328P__)
-const int workspacesize = 317;
-const int EEPROMsize = 1024;
-#elif defined(__AVR_ATmega32U4__)
-const int workspacesize = 421;
-const int EEPROMsize = 1024;
-#elif defined(__AVR_ATmega2560__)
-const int workspacesize = 1461;
-const int EEPROMsize = 4096;
-#elif defined(__AVR_ATmega1284P__)
-const int workspacesize = 3000;
-const int EEPROMsize = 4096;
-#else
-const int workspacesize = 317;
-const int EEPROMsize = 1024;
-#endif
+// RAMSTART, RAMEND, and E2END are defined by the processor's ioxxx.h file
+
+const int RAMsize = RAMEND - RAMSTART + 1;
+const int workspacesize = (RAMsize - RAMsize/4 - 268)/4;
+const int EEPROMsize = E2END;

 const int buflen = 17;  // Length of longest symbol + 1
-enum type {NONE, SYMBOL, NUMBER};
-enum token { UNUSED, BRA, KET, QUO, DOT};
-
-enum function { SYMBOLS, NIL, TEE, LAMBDA, LET, LETSTAR, CLOSURE, SPECIAL_FORMS, QUOTE, DEFUN, DEFVAR, SETQ, LOOP, PUSH, POP, INCF,
-DECF, DOLIST, DOTIMES, FORMILLIS, TAIL_FORMS, PROGN, RETURN, IF, COND, WHEN, UNLESS, AND, OR, FUNCTIONS, NOT, NULLFN, CONS, ATOM,
-LISTP, CONSP, NUMBERP, EQ, CAR, FIRST, CDR, REST, CAAR, CADR, SECOND, CDAR, CDDR, CAAAR, CAADR, CADAR, CADDR, THIRD, CDAAR, CDADR,
-CDDAR, CDDDR, LENGTH, LIST, REVERSE, NTH, ASSOC, MEMBER, APPLY, FUNCALL, APPEND, MAPC, MAPCAR, ADD, SUBTRACT, MULTIPLY, DIVIDE, MOD,
-ONEPLUS, ONEMINUS, ABS, RANDOM, MAX, MIN, NUMEQ, LESS, LESSEQ, GREATER, GREATEREQ, NOTEQ, PLUSP, MINUSP, ZEROP, ODDP, EVENP, READ,
-EVAL, LOCALS, GLOBALS, MAKUNBOUND, BREAK, PRINT, PRINC, GC, SAVEIMAGE, LOADIMAGE, PINMODE, DIGITALREAD, DIGITALWRITE, ANALOGREAD,
-ANALOGWRITE, DELAY, MILLIS, SHIFTOUT, SHIFTIN, NOTE, ENDFUNCTIONS };
+enum type {ZERO, SYMBOL, NUMBER, STREAM, PAIR };
+enum token { UNUSED, BRA, KET, QUO, DOT };
+enum stream { SERIALSTREAM, I2CSTREAM, SPISTREAM };
+
+enum function { SYMBOLS, NIL, TEE, LAMBDA, LET, LETSTAR, CLOSURE, SPECIAL_FORMS, QUOTE, DEFUN, DEFVAR,
+SETQ, LOOP, PUSH, POP, INCF, DECF, DOLIST, DOTIMES, FORMILLIS, WITHI2C, WITHSPI, TAIL_FORMS, PROGN, RETURN,
+IF, COND, WHEN, UNLESS, AND, OR, FUNCTIONS, NOT, NULLFN, CONS, ATOM, LISTP, CONSP, NUMBERP, STREAMP, EQ,
+CAR, FIRST, CDR, REST, CAAR, CADR, SECOND, CDAR, CDDR, CAAAR, CAADR, CADAR, CADDR, THIRD, CDAAR, CDADR,
+CDDAR, CDDDR, LENGTH, LIST, REVERSE, NTH, ASSOC, MEMBER, APPLY, FUNCALL, APPEND, MAPC, MAPCAR, ADD, SUBTRACT,
+MULTIPLY, DIVIDE, MOD, ONEPLUS, ONEMINUS, ABS, RANDOM, MAX, MIN, NUMEQ, LESS, LESSEQ, GREATER, GREATEREQ,
+NOTEQ, PLUSP, MINUSP, ZEROP, ODDP, EVENP, LOGAND, LOGIOR, LOGXOR, LOGNOT, ASH, LOGBITP, READ, EVAL, GLOBALS,
+MAKUNBOUND, BREAK, PRINT, PRINC, WRITEBYTE, READBYTE, RESTARTI2C, GC, SAVEIMAGE, LOADIMAGE, PINMODE, DIGITALREAD,
+DIGITALWRITE, ANALOGREAD, ANALOGWRITE, DELAY, MILLIS, NOTE, ENDFUNCTIONS };

 // Typedefs

@@ -103,6 +97,7 @@
 char ReturnFlag = 0;
 object *freelist;
 extern uint8_t _end;
+int i2cCount;

 object *GlobalEnv;
 object *GCStack = NULL;
@@ -171,6 +166,13 @@
   return ptr;
 }

+object *stream (unsigned char streamtype, unsigned char address) {
+  object *ptr = (object *) myalloc ();
+  ptr->type = STREAM;
+  ptr->integer = streamtype<<8 | address;
+  return ptr;
+}
+
 // Garbage collection

 void markobject (object *obj) {
@@ -183,7 +185,7 @@
   int type = obj->type;
   mark(obj);

-  if (type != SYMBOL && type != NUMBER) { // cons
+  if (type >= PAIR || type == ZERO) { // cons
     markobject(arg);
     obj = cdr(obj);
     goto MARK;
@@ -237,7 +239,7 @@
   for (int i=0; i<workspacesize; i++) {
     object *obj = &workspace[i];
     int type = (obj->type) & 0x7FFF;
-    if (marked(obj) && type != SYMBOL && type != NUMBER) {
+    if (marked(obj) && type >= PAIR) {
       if (car(obj) == (object *)((unsigned int)from | 0x8000))
         car(obj) = (object *)((unsigned int)to | 0x8000);
       if (cdr(obj) == from) cdr(obj) = to;
@@ -361,6 +363,11 @@
   return obj->integer;
 }

+int istream(object *obj){
+  if(obj->type != STREAM) error(F("not a stream"));
+  return obj->integer;
+}
+
 int issymbol(object *obj, unsigned int n) {
   return obj->type == SYMBOL && obj->name == n;
 }
@@ -471,6 +478,73 @@
   if (!listp(arg)) error(F("Can't take cdr"));
   if (arg == nil) return nil;
   return cdr(arg);
+}
+
+// I2C interface
+
+#if defined(__AVR_ATmega328P__)
+uint8_t const TWI_SDA_PIN = 18;
+uint8_t const TWI_SCL_PIN = 19;
+#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
+uint8_t const TWI_SDA_PIN = 20;
+uint8_t const TWI_SCL_PIN = 21;
+#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__)
+uint8_t const TWI_SDA_PIN = 17;
+uint8_t const TWI_SCL_PIN = 16;
+#elif defined(__AVR_ATmega32U4__)
+uint8_t const TWI_SDA_PIN = 6;
+uint8_t const TWI_SCL_PIN = 5;
+#endif
+
+uint32_t const F_TWI = 400000L;  // Hardware I2C clock in Hz
+uint8_t const TWSR_MTX_DATA_ACK = 0x28;
+uint8_t const TWSR_MTX_ADR_ACK = 0x18;
+uint8_t const TWSR_MRX_ADR_ACK = 0x40;
+uint8_t const TWSR_START = 0x08;
+uint8_t const TWSR_REP_START = 0x10;
+uint8_t const I2C_READ = 1;
+uint8_t const I2C_WRITE = 0;
+
+void I2Cinit(bool enablePullup) {
+  TWSR = 0;                        // no prescaler
+  TWBR = (F_CPU/F_TWI - 16)/2;     // set bit rate factor
+  if (enablePullup) {
+    digitalWrite(TWI_SDA_PIN, HIGH);
+    digitalWrite(TWI_SCL_PIN, HIGH);
+  }
+}
+
+uint8_t I2Cread(uint8_t last) {
+  TWCR = 1<<TWINT | 1<<TWEN | (last ? 0 : (1<<TWEA));
+  while (!(TWCR & 1<<TWINT));
+  return TWDR;
+}
+
+bool I2Cwrite(uint8_t data) {
+  TWDR = data;
+  TWCR = 1<<TWINT | 1 << TWEN;
+  while (!(TWCR & 1<<TWINT));
+  return (TWSR & 0xF8) == TWSR_MTX_DATA_ACK;
+}
+
+bool I2Cstart(uint8_t addressRW) {
+  TWCR = 1<<TWINT | 1<<TWSTA | 1<<TWEN;    // send START condition
+  while (!(TWCR & 1<<TWINT));
+  if ((TWSR & 0xF8) != TWSR_START && (TWSR & 0xF8) != TWSR_REP_START) return false;
+  TWDR = addressRW;  // send device address and direction
+  TWCR = 1<<TWINT | 1<<TWEN;
+  while (!(TWCR & 1<<TWINT));
+  if (addressRW & I2C_READ) return (TWSR & 0xF8) == TWSR_MRX_ADR_ACK;
+  else return (TWSR & 0xF8) == TWSR_MTX_ADR_ACK;
+}
+
+bool I2Crestart(uint8_t addressRW) {
+  return I2Cstart(addressRW);
+}
+
+void I2Cstop(void) {
+  TWCR = 1<<TWINT | 1<<TWEN | 1<<TWSTO;
+  while (TWCR & 1<<TWSTO); // wait until stop and bus released
 }

 // Special forms
@@ -544,7 +618,8 @@
   object *pair = findvalue(var, env);
   int result = integer(eval(var, env));
   int temp = 1;
-  if (cdr(args) != NULL) temp = integer(eval(second(args), env));
+  args = cdr(args);
+  if (args != NULL) temp = integer(eval(first(args), env));
   #if defined(checkoverflow)
   if (temp < 1) { if (-32768 - temp > result) error(F("'incf' arithmetic overflow")); }
   else { if (32767 - temp < result) error(F("'incf' arithmetic overflow")); }
@@ -560,7 +635,8 @@
   object *pair = findvalue(var, env);
   int result = integer(eval(var, env));
   int temp = 1;
-  if (cdr(args) != NULL) temp = integer(eval(second(args), env));
+  args = cdr(args);
+  if (args != NULL) temp = integer(eval(first(args), env));
   #if defined(checkoverflow)
   if (temp < 1) { if (32767 + temp < result) error(F("'decf' arithmetic overflow")); }
   else { if (-32768 + temp > result) error(F("'decf' arithmetic overflow")); }
@@ -576,6 +652,7 @@
   object *var = first(params);
   object *list = eval(second(params), env);
   if (!listp(list)) error(F("'dolist' argument is not a list"));
+  push(list, GCStack); // Don't GC the list
   object *pair = cons(var,nil);
   push(pair,env);
   object *result = third(params);
@@ -586,6 +663,7 @@
     eval(tf_progn(forms,env), env);
   }
   cdr(pair) = nil;
+  pop(GCStack);
   return eval(result, env);
 }

@@ -618,6 +696,57 @@
   return nil;
 }

+object *sp_withi2c (object *args, object *env) {
+  object *params = first(args);
+  object *var = first(params);
+  int address = integer(eval(second(params), env));
+  params = cddr(params);
+  int read = 0; // Write
+  i2cCount = 0;
+  if (params != NULL) {
+    object *rw = eval(first(params), env);
+    if (numberp(rw)) i2cCount = integer(rw);
+    read = (rw != NULL);
+  }
+  I2Cinit(1); // Pullups
+  object *pair = cons(var, (I2Cstart(address<<1 | read)) ? stream(I2CSTREAM, address) : nil);
+  push(pair,env);
+  object *forms = cdr(args);
+  object *result = eval(tf_progn(forms,env), env);
+  I2Cstop();
+  return result;
+}
+
+object *sp_withspi (object *args, object *env) {
+  object *params = first(args);
+  object *var = first(params);
+  int pin = integer(eval(second(params), env));
+  object *pair = cons(var, stream(SPISTREAM, pin));
+  push(pair,env);
+  SPI.begin();
+  params = cddr(params);
+  if (params != NULL) {
+    int d = integer(eval(first(params), env));
+    if (d<1 || d>7) error(F("'with-spi' invalid divider"));
+    if (d == 7) SPI.setClockDivider(3);
+    else if (d & 1) SPI.setClockDivider((d>>1) + 4);
+    else SPI.setClockDivider((d>>1) - 1);
+    params = cdr(params);
+    if (params != NULL) {
+      SPI.setBitOrder(eval(first(params), env) == NULL);
+      params = cdr(params);
+      if (params != NULL) SPI.setDataMode(integer(eval(first(params), env)));
+    }
+  }
+  pinMode(pin, OUTPUT);
+  digitalWrite(pin, LOW);
+  object *forms = cdr(args);
+  object *result = eval(tf_progn(forms,env), env);
+  digitalWrite(pin, HIGH);
+  SPI.end();
+  return result;
+}
+
 // Tail-recursive forms

 object *tf_progn (object *args, object *env) {
@@ -690,7 +819,7 @@

 object *fn_not (object *args, object *env) {
   (void) env;
-  if (first(args) == nil) return tee; else return nil;
+  return (first(args) == nil) ? tee : nil;
 }

 object *fn_cons (object *args, object *env) {
@@ -701,32 +830,38 @@
 object *fn_atom (object *args, object *env) {
   (void) env;
   object *arg1 = first(args);
-  if (consp(arg1)) return nil; else return tee;
+  return consp(arg1) ? nil : tee;
 }

 object *fn_listp (object *args, object *env) {
   (void) env;
   object *arg1 = first(args);
-  if (listp(arg1)) return tee; else return nil;
+  return listp(arg1) ? tee : nil;
 }

 object *fn_consp (object *args, object *env) {
   (void) env;
   object *arg1 = first(args);
-  if (consp(arg1)) return tee; else return nil;
+  return consp(arg1) ? tee : nil;
 }

 object *fn_numberp (object *args, object *env) {
   (void) env;
   object *arg1 = first(args);
-  if (numberp(arg1)) return tee; else return nil;
+  return numberp(arg1) ? tee : nil;
+}
+
+object *fn_streamp (object *args, object *env) {
+  (void) env;
+  object *arg1 = first(args);
+  return streamp(arg1) ? tee : nil;
 }

 object *fn_eq (object *args, object *env) {
   (void) env;
   object *arg1 = first(args);
   object *arg2 = second(args);
-  if(eq(arg1, arg2)) return tee; else return nil;
+  return eq(arg1, arg2) ? tee : nil;
 }

 // List functions
@@ -1220,6 +1355,61 @@
   else return nil;
 }

+// Bitwise operators
+
+object *fn_logand (object *args, object *env) {
+  (void) env;
+  unsigned int result = 0xFFFF;
+  while (args != NULL) {
+    result = result & integer(first(args));
+    args = cdr(args);
+  }
+  return number(result);
+}
+
+object *fn_logior (object *args, object *env) {
+  (void) env;
+  unsigned int result = 0;
+  while (args != NULL) {
+    result = result | integer(first(args));
+    args = cdr(args);
+  }
+  return number(result);
+}
+
+object *fn_logxor (object *args, object *env) {
+  (void) env;
+  unsigned int result = 0;
+  while (args != NULL) {
+    result = result ^ integer(first(args));
+    args = cdr(args);
+  }
+  return number(result);
+}
+
+object *fn_lognot (object *args, object *env) {
+  (void) env;
+  int result = integer(car(args));
+  return number(~result);
+}
+
+object *fn_ash (object *args, object *env) {
+  (void) env;
+  int value = integer(first(args));
+  int count = integer(second(args));
+  if (count >= 0)
+    return number(value << count);
+  else
+    return number(value >> abs(count));
+}
+
+object *fn_logbitp (object *args, object *env) {
+  (void) env;
+  int index = integer(first(args));
+  int value = integer(second(args));
+  return (bitRead(value, index) == 1) ? tee : nil;
+}
+
 // System functions

 object *fn_read (object *args, object *env) {
@@ -1232,15 +1422,16 @@
   return eval(first(args), env);
 }

-object *fn_locals (object *args, object *env) {
-  (void) args;
-  return env;
-}
-
 object *fn_globals (object *args, object *env) {
   (void) args;
   (void) env;
-  return GlobalEnv;
+  object *list = GlobalEnv;
+  while (list != NULL) {
+    printobject(car(car(list)));
+    Serial.println();
+    list = cdr(list);
+  }
+  return nil;
 }

 object *fn_makunbound (object *args, object *env) {
@@ -1289,6 +1480,55 @@
   return obj;
 }

+object *fn_writebyte (object *args, object *env) {
+  (void) env;
+  object *val = first(args);
+  int value = integer(val);
+  int stream = SERIALSTREAM<<8;
+  args = cdr(args);
+  if (args != NULL) stream = istream(first(args));
+  if (stream>>8 == I2CSTREAM) return (I2Cwrite(value)) ? tee : nil;
+  else if (stream>>8 == SPISTREAM) return number(SPI.transfer(value));
+  else if (stream == SERIALSTREAM<<8) Serial.write(value);
+  else error(F("'write-byte' unknown stream type"));
+  return nil;
+}
+
+object *fn_readbyte (object *args, object *env) {
+  (void) env;
+  int stream = SERIALSTREAM<<8;
+  int last = 0;
+  if (args != NULL) stream = istream(first(args));
+  args = cdr(args);
+  if (args != NULL) last = (first(args) != NULL);
+  if (stream>>8 == I2CSTREAM) {
+    if (i2cCount >= 0) i2cCount--;
+    return number(I2Cread((i2cCount == 0) || last));
+  } else if (stream>>8 == SPISTREAM) return number(SPI.transfer(0));
+  else if (stream == SERIALSTREAM<<8) return number(Serial.read());
+  else error(F("'read-byte' unknown stream type"));
+  return nil;
+}
+
+object *fn_restarti2c (object *args, object *env) {
+  (void) env;
+  int stream = first(args)->integer;
+  args = cdr(args);
+  int read = 0; // Write
+  i2cCount = 0;
+  if (args != NULL) {
+    object *rw = first(args);
+    if (numberp(rw)) i2cCount = integer(rw);
+    read = (rw != NULL);
+  }
+  int address = stream & 0xFF;
+  if (stream>>8 == I2CSTREAM) {
+    if (!I2Crestart(address<<1 | read)) error(F("'i2c-restart' failed"));
+  }
+  else error(F("'restart' not i2c"));
+  return tee;
+}
+
 object *fn_gc (object *obj, object *env) {
   unsigned long start = micros();
   int initial = freespace;
@@ -1376,25 +1616,6 @@
   if (temp > 32767) error(F("'millis' arithmetic overflow"));
   #endif
   return number(temp);
-}
-
-object *fn_shiftout (object *args, object *env) {
-  (void) env;
-  int datapin = integer(first(args));
-  int clockpin = integer(second(args));
-  int order = (third(args) != nil);
-  object *value = fourth(args);
-  shiftOut(datapin, clockpin, order, integer(value));
-  return value;
-}
-
-object *fn_shiftin (object *args, object *env) {
-  (void) env;
-  int datapin = integer(first(args));
-  int clockpin = integer(second(args));
-  int order = (third(args) != nil);
-  int value = shiftIn(datapin, clockpin, order);
-  return number(value);
 }

 const uint8_t scale[] PROGMEM = { 239,225,213,201,190,179,169,159,150,142,134,127};
@@ -1413,7 +1634,7 @@
       TCCR2A = 1<<COM2A0 | 0<<COM2B0 | 2<<WGM20; // Toggle OC2A on match
     } else error(F("'note' pin not supported"));
     int prescaler = 0;
-    if (cdr(cdr(args)) != NULL) prescaler = integer(third(args));
+    if (cddr(args) != NULL) prescaler = integer(third(args));
     prescaler = 9 - prescaler - note/12;
     if (prescaler<3 || prescaler>6) error(F("'note' octave out of range"));
     OCR2A = pgm_read_byte(&scale[note%12]);
@@ -1432,7 +1653,7 @@
       TCCR2A = 1<<COM2A0 | 0<<COM2B0 | 2<<WGM20; // Toggle OC2A on match
     } else error(F("'note' pin not supported"));
     int prescaler = 0;
-    if (cdr(cdr(args)) != NULL) prescaler = integer(third(args));
+    if (cddr(args) != NULL) prescaler = integer(third(args));
     prescaler = 9 - prescaler - note/12;
     if (prescaler<3 || prescaler>6) error(F("'note' octave out of range"));
     OCR2A = pgm_read_byte(&scale[note%12]);
@@ -1451,7 +1672,7 @@
       TCCR2A = 1<<COM2A0 | 0<<COM2B0 | 2<<WGM20; // Toggle OC2A on match
     } else error(F("'note' pin not supported"));
     int prescaler = 0;
-    if (cdr(cdr(args)) != NULL) prescaler = integer(third(args));
+    if (cddr(args) != NULL) prescaler = integer(third(args));
     prescaler = 9 - prescaler - note/12;
     if (prescaler<3 || prescaler>6) error(F("'note' octave out of range"));
     OCR2A = pgm_read_byte(&scale[note%12]);
@@ -1462,7 +1683,6 @@
 }

 // Insert your own function definitions here
-

 // Built-in procedure names - stored in PROGMEM

@@ -1486,96 +1706,105 @@
 const char string17[] PROGMEM = "dolist";
 const char string18[] PROGMEM = "dotimes";
 const char string19[] PROGMEM = "for-millis";
-const char string20[] PROGMEM = "tail_forms";
-const char string21[] PROGMEM = "progn";
-const char string22[] PROGMEM = "return";
-const char string23[] PROGMEM = "if";
-const char string24[] PROGMEM = "cond";
-const char string25[] PROGMEM = "when";
-const char string26[] PROGMEM = "unless";
-const char string27[] PROGMEM = "and";
-const char string28[] PROGMEM = "or";
-const char string29[] PROGMEM = "functions";
-const char string30[] PROGMEM = "not";
-const char string31[] PROGMEM = "null";
-const char string32[] PROGMEM = "cons";
-const char string33[] PROGMEM = "atom";
-const char string34[] PROGMEM = "listp";
-const char string35[] PROGMEM = "consp";
-const char string36[] PROGMEM = "numberp";
-const char string37[] PROGMEM = "eq";
-const char string38[] PROGMEM = "car";
-const char string39[] PROGMEM = "first";
-const char string40[] PROGMEM = "cdr";
-const char string41[] PROGMEM = "rest";
-const char string42[] PROGMEM = "caar";
-const char string43[] PROGMEM = "cadr";
-const char string44[] PROGMEM = "second";
-const char string45[] PROGMEM = "cdar";
-const char string46[] PROGMEM = "cddr";
-const char string47[] PROGMEM = "caaar";
-const char string48[] PROGMEM = "caadr";
-const char string49[] PROGMEM = "cadar";
-const char string50[] PROGMEM = "caddr";
-const char string51[] PROGMEM = "third";
-const char string52[] PROGMEM = "cdaar";
-const char string53[] PROGMEM = "cdadr";
-const char string54[] PROGMEM = "cddar";
-const char string55[] PROGMEM = "cdddr";
-const char string56[] PROGMEM = "length";
-const char string57[] PROGMEM = "list";
-const char string58[] PROGMEM = "reverse";
-const char string59[] PROGMEM = "nth";
-const char string60[] PROGMEM = "assoc";
-const char string61[] PROGMEM = "member";
-const char string62[] PROGMEM = "apply";
-const char string63[] PROGMEM = "funcall";
-const char string64[] PROGMEM = "append";
-const char string65[] PROGMEM = "mapc";
-const char string66[] PROGMEM = "mapcar";
-const char string67[] PROGMEM = "+";
-const char string68[] PROGMEM = "-";
-const char string69[] PROGMEM = "*";
-const char string70[] PROGMEM = "/";
-const char string71[] PROGMEM = "mod";
-const char string72[] PROGMEM = "1+";
-const char string73[] PROGMEM = "1-";
-const char string74[] PROGMEM = "abs";
-const char string75[] PROGMEM = "random";
-const char string76[] PROGMEM = "max";
-const char string77[] PROGMEM = "min";
-const char string78[] PROGMEM = "=";
-const char string79[] PROGMEM = "<";
-const char string80[] PROGMEM = "<=";
-const char string81[] PROGMEM = ">";
-const char string82[] PROGMEM = ">=";
-const char string83[] PROGMEM = "/=";
-const char string84[] PROGMEM = "plusp";
-const char string85[] PROGMEM = "minusp";
-const char string86[] PROGMEM = "zerop";
-const char string87[] PROGMEM = "oddp";
-const char string88[] PROGMEM = "evenp";
-const char string89[] PROGMEM = "read";
-const char string90[] PROGMEM = "eval";
-const char string91[] PROGMEM = "locals";
-const char string92[] PROGMEM = "globals";
-const char string93[] PROGMEM = "makunbound";
-const char string94[] PROGMEM = "break";
-const char string95[] PROGMEM = "print";
-const char string96[] PROGMEM = "princ";
-const char string97[] PROGMEM = "gc";
-const char string98[] PROGMEM = "save-image";
-const char string99[] PROGMEM = "load-image";
-const char string100[] PROGMEM = "pinmode";
-const char string101[] PROGMEM = "digitalread";
-const char string102[] PROGMEM = "digitalwrite";
-const char string103[] PROGMEM = "analogread";
-const char string104[] PROGMEM = "analogwrite";
-const char string105[] PROGMEM = "delay";
-const char string106[] PROGMEM = "millis";
-const char string107[] PROGMEM = "shiftout";
-const char string108[] PROGMEM = "shiftin";
-const char string109[] PROGMEM = "note";
+const char string20[] PROGMEM = "with-i2c";
+const char string21[] PROGMEM = "with-spi";
+const char string22[] PROGMEM = "tail_forms";
+const char string23[] PROGMEM = "progn";
+const char string24[] PROGMEM = "return";
+const char string25[] PROGMEM = "if";
+const char string26[] PROGMEM = "cond";
+const char string27[] PROGMEM = "when";
+const char string28[] PROGMEM = "unless";
+const char string29[] PROGMEM = "and";
+const char string30[] PROGMEM = "or";
+const char string31[] PROGMEM = "functions";
+const char string32[] PROGMEM = "not";
+const char string33[] PROGMEM = "null";
+const char string34[] PROGMEM = "cons";
+const char string35[] PROGMEM = "atom";
+const char string36[] PROGMEM = "listp";
+const char string37[] PROGMEM = "consp";
+const char string38[] PROGMEM = "numberp";
+const char string39[] PROGMEM = "streamp";
+const char string40[] PROGMEM = "eq";
+const char string41[] PROGMEM = "car";
+const char string42[] PROGMEM = "first";
+const char string43[] PROGMEM = "cdr";
+const char string44[] PROGMEM = "rest";
+const char string45[] PROGMEM = "caar";
+const char string46[] PROGMEM = "cadr";
+const char string47[] PROGMEM = "second";
+const char string48[] PROGMEM = "cdar";
+const char string49[] PROGMEM = "cddr";
+const char string50[] PROGMEM = "caaar";
+const char string51[] PROGMEM = "caadr";
+const char string52[] PROGMEM = "cadar";
+const char string53[] PROGMEM = "caddr";
+const char string54[] PROGMEM = "third";
+const char string55[] PROGMEM = "cdaar";
+const char string56[] PROGMEM = "cdadr";
+const char string57[] PROGMEM = "cddar";
+const char string58[] PROGMEM = "cdddr";
+const char string59[] PROGMEM = "length";
+const char string60[] PROGMEM = "list";
+const char string61[] PROGMEM = "reverse";
+const char string62[] PROGMEM = "nth";
+const char string63[] PROGMEM = "assoc";
+const char string64[] PROGMEM = "member";
+const char string65[] PROGMEM = "apply";
+const char string66[] PROGMEM = "funcall";
+const char string67[] PROGMEM = "append";
+const char string68[] PROGMEM = "mapc";
+const char string69[] PROGMEM = "mapcar";
+const char string70[] PROGMEM = "+";
+const char string71[] PROGMEM = "-";
+const char string72[] PROGMEM = "*";
+const char string73[] PROGMEM = "/";
+const char string74[] PROGMEM = "mod";
+const char string75[] PROGMEM = "1+";
+const char string76[] PROGMEM = "1-";
+const char string77[] PROGMEM = "abs";
+const char string78[] PROGMEM = "random";
+const char string79[] PROGMEM = "max";
+const char string80[] PROGMEM = "min";
+const char string81[] PROGMEM = "=";
+const char string82[] PROGMEM = "<";
+const char string83[] PROGMEM = "<=";
+const char string84[] PROGMEM = ">";
+const char string85[] PROGMEM = ">=";
+const char string86[] PROGMEM = "/=";
+const char string87[] PROGMEM = "plusp";
+const char string88[] PROGMEM = "minusp";
+const char string89[] PROGMEM = "zerop";
+const char string90[] PROGMEM = "oddp";
+const char string91[] PROGMEM = "evenp";
+const char string92[] PROGMEM = "logand";
+const char string93[] PROGMEM = "logior";
+const char string94[] PROGMEM = "logxor";
+const char string95[] PROGMEM = "lognot";
+const char string96[] PROGMEM = "ash";
+const char string97[] PROGMEM = "logbitp";
+const char string98[] PROGMEM = "read";
+const char string99[] PROGMEM = "eval";
+const char string100[] PROGMEM = "globals";
+const char string101[] PROGMEM = "makunbound";
+const char string102[] PROGMEM = "break";
+const char string103[] PROGMEM = "print";
+const char string104[] PROGMEM = "princ";
+const char string105[] PROGMEM = "write-byte";
+const char string106[] PROGMEM = "read-byte";
+const char string107[] PROGMEM = "restart-i2c";
+const char string108[] PROGMEM = "gc";
+const char string109[] PROGMEM = "save-image";
+const char string110[] PROGMEM = "load-image";
+const char string111[] PROGMEM = "pinmode";
+const char string112[] PROGMEM = "digitalread";
+const char string113[] PROGMEM = "digitalwrite";
+const char string114[] PROGMEM = "analogread";
+const char string115[] PROGMEM = "analogwrite";
+const char string116[] PROGMEM = "delay";
+const char string117[] PROGMEM = "millis";
+const char string118[] PROGMEM = "note";

 const tbl_entry_t lookup_table[] PROGMEM = {
   { string0, NULL, NIL, NIL },
@@ -1598,96 +1827,105 @@
   { string17, sp_dolist, 1, 127 },
   { string18, sp_dotimes, 1, 127 },
   { string19, sp_formillis, 1, 127 },
-  { string20, NULL, NIL, NIL },
-  { string21, tf_progn, 0, 127 },
-  { string22, tf_return, 0, 127 },
-  { string23, tf_if, 2, 3 },
-  { string24, tf_cond, 0, 127 },
-  { string25, tf_when, 1, 127 },
-  { string26, tf_unless, 1, 127 },
-  { string27, tf_and, 0, 127 },
-  { string28, tf_or, 0, 127 },
-  { string29, NULL, NIL, NIL },
-  { string30, fn_not, 1, 1 },
-  { string31, fn_not, 1, 1 },
-  { string32, fn_cons, 2, 2 },
-  { string33, fn_atom, 1, 1 },
-  { string34, fn_listp, 1, 1 },
-  { string35, fn_consp, 1, 1 },
-  { string36, fn_numberp, 1, 1 },
-  { string37, fn_eq, 2, 2 },
-  { string38, fn_car, 1, 1 },
-  { string39, fn_car, 1, 1 },
-  { string40, fn_cdr, 1, 1 },
-  { string41, fn_cdr, 1, 1 },
-  { string42, fn_caar, 1, 1 },
-  { string43, fn_cadr, 1, 1 },
-  { string44, fn_cadr, 1, 1 },
-  { string45, fn_cdar, 1, 1 },
-  { string46, fn_cddr, 1, 1 },
-  { string47, fn_caaar, 1, 1 },
-  { string48, fn_caadr, 1, 1 },
-  { string49, fn_cadar, 1, 1 },
-  { string50, fn_caddr, 1, 1 },
-  { string51, fn_caddr, 1, 1 },
-  { string52, fn_cdaar, 1, 1 },
-  { string53, fn_cdadr, 1, 1 },
-  { string54, fn_cddar, 1, 1 },
-  { string55, fn_cdddr, 1, 1 },
-  { string56, fn_length, 1, 1 },
-  { string57, fn_list, 0, 127 },
-  { string58, fn_reverse, 1, 1 },
-  { string59, fn_nth, 2, 2 },
-  { string60, fn_assoc, 2, 2 },
-  { string61, fn_member, 2, 2 },
-  { string62, fn_apply, 2, 127 },
-  { string63, fn_funcall, 1, 127 },
-  { string64, fn_append, 0, 127 },
-  { string65, fn_mapc, 2, 3 },
-  { string66, fn_mapcar, 2, 3 },
-  { string67, fn_add, 0, 127 },
-  { string68, fn_subtract, 1, 127 },
-  { string69, fn_multiply, 0, 127 },
-  { string70, fn_divide, 2, 127 },
-  { string71, fn_mod, 2, 2 },
-  { string72, fn_oneplus, 1, 1 },
-  { string73, fn_oneminus, 1, 1 },
-  { string74, fn_abs, 1, 1 },
-  { string75, fn_random, 1, 1 },
-  { string76, fn_max, 1, 127 },
-  { string77, fn_min, 1, 127 },
-  { string78, fn_numeq, 1, 127 },
-  { string79, fn_less, 1, 127 },
-  { string80, fn_lesseq, 1, 127 },
-  { string81, fn_greater, 1, 127 },
-  { string82, fn_greatereq, 1, 127 },
-  { string83, fn_noteq, 1, 127 },
-  { string84, fn_plusp, 1, 1 },
-  { string85, fn_minusp, 1, 1 },
-  { string86, fn_zerop, 1, 1 },
-  { string87, fn_oddp, 1, 1 },
-  { string88, fn_evenp, 1, 1 },
-  { string89, fn_read, 0, 0 },
-  { string90, fn_eval, 1, 1 },
-  { string91, fn_locals, 0, 0 },
-  { string92, fn_globals, 0, 0 },
-  { string93, fn_makunbound, 1, 1 },
-  { string94, fn_break, 0, 0 },
-  { string95, fn_print, 1, 1 },
-  { string96, fn_princ, 1, 1 },
-  { string97, fn_gc, 0, 0 },
-  { string98, fn_saveimage, 0, 1 },
-  { string99, fn_loadimage, 0, 0 },
-  { string100, fn_pinmode, 2, 2 },
-  { string101, fn_digitalread, 1, 1 },
-  { string102, fn_digitalwrite, 2, 2 },
-  { string103, fn_analogread, 1, 1 },
-  { string104, fn_analogwrite, 2, 2 },
-  { string105, fn_delay, 1, 1 },
-  { string106, fn_millis, 0, 0 },
-  { string107, fn_shiftout, 4, 4 },
-  { string108, fn_shiftin, 3, 3 },
-  { string109, fn_note, 0, 3 },
+  { string20, sp_withi2c, 1, 127 },
+  { string21, sp_withspi, 1, 127 },
+  { string22, NULL, NIL, NIL },
+  { string23, tf_progn, 0, 127 },
+  { string24, tf_return, 0, 127 },
+  { string25, tf_if, 2, 3 },
+  { string26, tf_cond, 0, 127 },
+  { string27, tf_when, 1, 127 },
+  { string28, tf_unless, 1, 127 },
+  { string29, tf_and, 0, 127 },
+  { string30, tf_or, 0, 127 },
+  { string31, NULL, NIL, NIL },
+  { string32, fn_not, 1, 1 },
+  { string33, fn_not, 1, 1 },
+  { string34, fn_cons, 2, 2 },
+  { string35, fn_atom, 1, 1 },
+  { string36, fn_listp, 1, 1 },
+  { string37, fn_consp, 1, 1 },
+  { string38, fn_numberp, 1, 1 },
+  { string39, fn_streamp, 1, 1 },
+  { string40, fn_eq, 2, 2 },
+  { string41, fn_car, 1, 1 },
+  { string42, fn_car, 1, 1 },
+  { string43, fn_cdr, 1, 1 },
+  { string44, fn_cdr, 1, 1 },
+  { string45, fn_caar, 1, 1 },
+  { string46, fn_cadr, 1, 1 },
+  { string47, fn_cadr, 1, 1 },
+  { string48, fn_cdar, 1, 1 },
+  { string49, fn_cddr, 1, 1 },
+  { string50, fn_caaar, 1, 1 },
+  { string51, fn_caadr, 1, 1 },
+  { string52, fn_cadar, 1, 1 },
+  { string53, fn_caddr, 1, 1 },
+  { string54, fn_caddr, 1, 1 },
+  { string55, fn_cdaar, 1, 1 },
+  { string56, fn_cdadr, 1, 1 },
+  { string57, fn_cddar, 1, 1 },
+  { string58, fn_cdddr, 1, 1 },
+  { string59, fn_length, 1, 1 },
+  { string60, fn_list, 0, 127 },
+  { string61, fn_reverse, 1, 1 },
+  { string62, fn_nth, 2, 2 },
+  { string63, fn_assoc, 2, 2 },
+  { string64, fn_member, 2, 2 },
+  { string65, fn_apply, 2, 127 },
+  { string66, fn_funcall, 1, 127 },
+  { string67, fn_append, 0, 127 },
+  { string68, fn_mapc, 2, 3 },
+  { string69, fn_mapcar, 2, 3 },
+  { string70, fn_add, 0, 127 },
+  { string71, fn_subtract, 1, 127 },
+  { string72, fn_multiply, 0, 127 },
+  { string73, fn_divide, 2, 127 },
+  { string74, fn_mod, 2, 2 },
+  { string75, fn_oneplus, 1, 1 },
+  { string76, fn_oneminus, 1, 1 },
+  { string77, fn_abs, 1, 1 },
+  { string78, fn_random, 1, 1 },
+  { string79, fn_max, 1, 127 },
+  { string80, fn_min, 1, 127 },
+  { string81, fn_numeq, 1, 127 },
+  { string82, fn_less, 1, 127 },
+  { string83, fn_lesseq, 1, 127 },
+  { string84, fn_greater, 1, 127 },
+  { string85, fn_greatereq, 1, 127 },
+  { string86, fn_noteq, 1, 127 },
+  { string87, fn_plusp, 1, 1 },
+  { string88, fn_minusp, 1, 1 },
+  { string89, fn_zerop, 1, 1 },
+  { string90, fn_oddp, 1, 1 },
+  { string91, fn_evenp, 1, 1 },
+  { string92, fn_logand, 0, 127 },
+  { string93, fn_logior, 0, 127 },
+  { string94, fn_logxor, 0, 127 },
+  { string95, fn_lognot, 1, 1 },
+  { string96, fn_ash, 2, 2 },
+  { string97, fn_logbitp, 2, 2 },
+  { string98, fn_read, 0, 0 },
+  { string99, fn_eval, 1, 1 },
+  { string100, fn_globals, 0, 0 },
+  { string101, fn_makunbound, 1, 1 },
+  { string102, fn_break, 0, 0 },
+  { string103, fn_print, 1, 1 },
+  { string104, fn_princ, 1, 1 },
+  { string105, fn_writebyte, 1, 2 },
+  { string106, fn_readbyte, 0, 2 },
+  { string107, fn_restarti2c, 1, 2 },
+  { string108, fn_gc, 0, 0 },
+  { string109, fn_saveimage, 0, 1 },
+  { string110, fn_loadimage, 0, 0 },
+  { string111, fn_pinmode, 2, 2 },
+  { string112, fn_digitalread, 1, 1 },
+  { string113, fn_digitalwrite, 2, 2 },
+  { string114, fn_analogread, 1, 1 },
+  { string115, fn_analogwrite, 2, 2 },
+  { string116, fn_delay, 1, 1 },
+  { string117, fn_millis, 0, 0 },
+  { string118, fn_note, 0, 3 },
 };

 // Table lookup functions
@@ -1720,8 +1958,6 @@
 }

 // Main evaluator
-
-// unsigned int Canary = 0xA5A5;

 object *eval (object *form, object *env) {
   int TC=0;
@@ -1866,10 +2102,18 @@
       printobject(form);
     }
     Serial.print(')');
-  } else if (form->type == NUMBER){
+  } else if (form->type == NUMBER) {
     Serial.print(integer(form));
-  } else if (form->type == SYMBOL){
+  } else if (form->type == SYMBOL) {
     Serial.print(name(form));
+  } else if (form->type == STREAM) {
+    Serial.print(F("<"));
+    if ((form->integer)>>8 == SPISTREAM) Serial.print(F("spi"));
+    else if ((form->integer)>>8 == I2CSTREAM) Serial.print(F("i2c"));
+    else Serial.print(F("serial"));
+    Serial.print(F("-stream #x"));
+    Serial.print(form->integer & 0xFF, HEX);
+    Serial.print('>');
   } else
     error(F("Error in print."));
 }
@@ -1924,7 +2168,7 @@
   int isnumber = (digitvalue(ch)<base);
   buffer[2] = '\0'; // In case variable is one letter

-  while(!isspace(ch) && ch != ')' && index < buflen){
+  while(!isspace(ch) && ch != ')' && ch != '(' && index < buflen){
     buffer[index++] = ch;
     int temp = digitvalue(ch);
     result = result * base + temp;
@@ -1934,6 +2178,7 @@

   buffer[index] = '\0';
   if (ch == ')') LastChar = ')';
+  if (ch == '(') LastChar = '(';

   if (isnumber) {
     if (base == 10 && result > ((unsigned int)32767+(1-sign)/2)) {
@@ -1990,7 +2235,7 @@
   initworkspace();
   initenv();
   _end = 0xA5;
-  Serial.println(F("uLisp 1.1"));
+  Serial.println(F("uLisp 1.2a"));
 }

 // Read/Evaluate/Print loop


Sent initial value of switch characteristic

--- libraries/CurieBle/examples/CallbackLED/CallbackLED.ino
+++ libraries/CurieBle/examples/CallbackLED/CallbackLED.ino
@@ -49,6 +49,7 @@
   // assign event handlers for characteristic
   switchChar.setEventHandler(BLEWritten, switchCharacteristicWritten);

+  switchChar.setValue(0);

   // advertise the service
   blePeripheral.begin();


Delete readFromAndroid.ino

Delete readFromAndroid.ino

--- readFromAndroid.ino
+++ readFromAndroid.ino
@@ -1,48 +0,0 @@
-#include <SoftwareSerial.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-const byte numChars = 32;
-char receivedChars[numChars];   // an array to store the received data
-
-const char s[2] = ",";          // Character to split in the strtok function
-char *token;                    // Strtok tockens
-
-int LeftJoy = 0;                // Left joystick value
-int RightJoy = 0;               // Right Joystick value
-
-void setup() {
-  Serial.begin(9600);
-
-  // Wait for the serial port to connect. Needed for native USB
-  while (!Serial) { ; }
-  delay(2000);
-  Serial.println("Arduino is ready to receive...");
-}
-
-void loop() {
-  int charsRead;
-  while (Serial.available() > 0) {
-    charsRead = Serial.readBytesUntil('&', receivedChars, sizeof(receivedChars) - 1); // Read until '>' or 31 chars
-    receivedChars[charsRead] = '\0';    // Overwrite '>' to make it a string
-
-    token = strtok(receivedChars, s);
-    if (token != NULL) {
-      RightJoy = atoi(token + 1);
-    }
-    token = strtok(NULL, s);
-    if (token != NULL) {
-      LeftJoy = atoi(token);
-    }
-
-    Serial.print("Left Stick: ");
-    Serial.print(LeftJoy);
-    Serial.print("\t\tRight Stick: ");
-    Serial.println(RightJoy);
-    Serial.println();
-
-    // Clear receive buffer so we're ready to receive the next line
-    receivedChars[0] = NULL;
-  }
-}


at version 1. everything seems to work ok

--- moth-lights/src/mothLights.ino
+++ moth-lights/src/mothLights.ino
@@ -28,7 +28,7 @@
 #define neo_01 2
 #define neo_02 7
 #define neo_03 4
-#define NUMPIXELS      60
+#define NUMPIXELS      180

 #define button_01 A0
 #define button_02 A1
@@ -36,6 +36,7 @@
 #define INVERT true        //Since the pullup resistor will keep the pin high unless the
 #define DEBOUNCE_MS 20     //A debounce time of 20 milliseconds usually works well for tactile button switches.
 #define LONG_PRESS 500    //We define a "long press" to be 1000 milliseconds.
+#define LONG_LONG_PRESS 3000
 enum {RUN, TO_COLOR_SETTINGS, COLOR_SETTINGS, TO_ONOFF_SETTINGS, ONOFF_SETTINGS, TO_TIME_SETTINGS, TIME_SETTINGS, TO_RUN};
 uint8_t STATE;

@@ -47,23 +48,24 @@
 Button Bu_2(button_02, PULLUP, INVERT, DEBOUNCE_MS);

 // Adafruit_NeoPixel p1 = Adafruit_NeoPixel(NUMPIXELS, neo_01, NEO_RGBW);
-void fadeComplete();
+//
 NeoPatterns p1(NUMPIXELS, neo_01, NEO_RGBW);
 NeoPatterns p2(NUMPIXELS, neo_02, NEO_RGBW);
 NeoPatterns p3(NUMPIXELS, neo_03, NEO_RGBW);

 int dayLength = 12;
 int dawn_duskLength = 10;
+uint32_t color1Day = p1.Color(0,0,0,255);
+uint32_t color2Day = p2.Color(0,0,0,255);
+uint32_t color3Day = p3.Color(0,0,0,255);
+int sunriseHour = 6;
+int sunriseMinute = 0;
+
 DateTime sunriseStartTime;
 DateTime sunsetFinishTime;
-int sunriseHour = 6;
-int sunriseMinute = 0;
-uint32_t color1Start = p1.Color(0,0,0,0);
-uint32_t color1End = p1.Color(0,255,0,0);
-uint32_t color2Start = p1.Color(0,0,0,0);
-uint32_t color2End = p1.Color(0,0,0,0);
-uint32_t color3Start = p1.Color(0,0,0,0);
-uint32_t color3End = p1.Color(0,0,0,0);
+
+uint32_t colorStart = p1.Color(0,0,50,0);
+uint32_t colorEnd = p1.Color(50,0,0,0);

 int cursorRow = 0;
 int cursorCol = 0;
@@ -73,22 +75,51 @@
 bool EVENING = 0;
 bool NIGHT = 0;

+struct Settings {
+  uint32_t c1 = p1.Color(0,0,0,255);;
+  uint32_t c2 = p2.Color(0,0,0,255);
+  uint32_t c3 = p3.Color(0,0,0,255);
+  uint16_t dayL = 12;
+  uint16_t fadeT = 10;
+  uint16_t riseH = 6;
+  uint16_t riseM = 0;
+};
+Settings theSettings;
+uint32_t EEPROM_ADDR = 1;
+
 void setup() {
+  // EEPROM.put(EEPROM_ADDR, theSettings);
+  loadSavedSettings();
   Serial.begin(115200);
   Wire.begin();
-  if (! rtc.begin()) Serial.println("Couldn't find RTC");
-  if (! rtc.initialized()) Serial.println("RTC is NOT running!");
-  // rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
-
+  lcd.begin(20, 4); // set up the LCD's number of columns and rows:
+  setLCDBacklight(50, 255, 50);
   pinMode(lcd_BCKLGHT_R, OUTPUT);
   pinMode(lcd_BCKLGHT_G, OUTPUT);
   pinMode(lcd_BCKLGHT_B, OUTPUT);
-  lcd.begin(20, 4); // set up the LCD's number of columns and rows:
-  setLCDBacklight(255, 0, 255);
-
-
+  if (! rtc.begin())
+  {
+    lcd.setCursor(0, 0);
+    lcd.print("Couldn't find RTC");
+    lcd.setCursor(0, 1);
+    lcd.print("Please power cycle");
+    while(1);
+  }
+  if (! rtc.initialized())
+  {
+    lcd.setCursor(0, 0);
+    lcd.print("Failed to init RTC");
+    lcd.setCursor(0, 1);
+    lcd.print("Please power cycle");
+    while(1);
+  }
+  rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
   p1.begin();
+  p2.begin();
+  p3.begin();
   p1.show();
+  p2.show();
+  p3.show();
   now = rtc.now();
   // sunriseStartTime = DateTime(now.year(), now.month(), now.day(), sunriseHour, sunriseMinute, 0) + TimeSpan(1,0,0,0);
   sunriseStartTime = DateTime(now.year(), now.month(), now.day(), sunriseHour, sunriseMinute, 0);
@@ -107,15 +138,17 @@
         STATE = TO_ONOFF_SETTINGS;
         lcd.clear();
         lcd.cursor();
-        setLCDBacklight(255, 255, 0);
+        setLCDBacklight(255, 10, 255);
       } else if(Bu_2.pressedFor(LONG_PRESS))
       {
         STATE = TO_COLOR_SETTINGS;
         lcd.clear();
         lcd.noCursor();
-        setLCDBacklight(0,255,0);
-        lcd.setCursor(0, 2);
-        lcd.println("SET COLOR");
+        setLCDBacklight(255,255,255);
+        cursorCol = 5;
+        cursorRow = 3;
+        lcd.setCursor(cursorCol, cursorRow);
+        lcd.print("color settings");
       } else
       {
         now = rtc.now();
@@ -129,12 +162,15 @@
         lcd.print(now.minute());
         lcd.print(" ");
         lcd.setCursor(0, 1);
-        lcd.print("FadeT ");
+        lcd.print("fadeT ");
         lcd.print(dawn_duskLength);
-        lcd.print(" DayL ");
+        lcd.print("m");
+        lcd.setCursor(12, 1);
+        lcd.print("dayL ");
         lcd.print(dayLength);
+        lcd.print("h");
         lcd.setCursor(0, 2);
-        lcd.print("OnT ");
+        lcd.print("onTime ");
         lcd.print(sunriseStartTime.month());
         lcd.print('/');
         lcd.print(sunriseStartTime.day());
@@ -143,7 +179,7 @@
         lcd.print(":");
         lcd.print(sunriseStartTime.minute());
         lcd.setCursor(0, 3);
-        lcd.print("OffT ");
+        lcd.print("offTime ");
         lcd.print(sunsetFinishTime.month());
         lcd.print('/');
         lcd.print(sunsetFinishTime.day());
@@ -158,34 +194,55 @@
       if(Bu_1.wasReleased())
       {
         STATE = ONOFF_SETTINGS;
-        cursorCol = 20-6;
+        cursorCol = 5;
         cursorRow = 3;
         lcd.setCursor(cursorCol, cursorRow);
-        lcd.print("on/off");
+        lcd.print("on/off settings");
         cursorCol = 0;
         cursorRow = 0;
         lcd.setCursor(cursorCol, cursorRow);
-        lcd.print("dayLength(hr):");
+        lcd.print("dayLength(hr) ");
         lcd.print(dayLength);
         lcd.setCursor(cursorCol, cursorRow+=1);
-        lcd.print("rise/set(m):");
+        lcd.print("rise/set(min) ");
         lcd.print(dawn_duskLength);
         lcd.setCursor(cursorCol, cursorRow+=1);
         // sunriseStartTime = DateTime(now.year(), now.month(), now.day(), sunriseHour, sunriseMinute, 0) + TimeSpan(1,0,0,0);
         sunriseStartTime = DateTime(now.year(), now.month(), now.day(), sunriseHour, sunriseMinute, 0);
         sunsetFinishTime = sunriseStartTime + TimeSpan(0, dayLength, dawn_duskLength*2, 0);
-        lcd.print("sunrise:");
+        lcd.print("sunrise ");
         lcd.print(sunriseStartTime.hour()); lcd.print(":"); lcd.print(sunriseStartTime.minute());
+        lcd.print("am");
         cursorCol = 0;
         cursorRow = 0;
         lcd.setCursor(cursorCol, cursorRow);
       }
       break;
     case ONOFF_SETTINGS:
-      if(Bu_1.pressedFor(LONG_PRESS))
+      if(Bu_2.pressedFor(LONG_LONG_PRESS))
       {
         STATE = TO_TIME_SETTINGS;
+        theSettings.dayL = dayLength;
+        theSettings.fadeT = dawn_duskLength;
+        theSettings.riseH = sunriseHour;
+        theSettings.riseM = sunriseMinute;
+        EEPROM.put(EEPROM_ADDR, theSettings);
         lcd.clear();
+        lcd.setCursor(20-4, 2);
+        lcd.print("set");
+        lcd.setCursor(20-4, 3);
+        lcd.print("time");
+      } else if(Bu_1.pressedFor(LONG_PRESS))
+      {
+        STATE = TO_RUN;
+        theSettings.dayL = dayLength;
+        theSettings.fadeT = dawn_duskLength;
+        theSettings.riseH = sunriseHour;
+        theSettings.riseM = sunriseMinute;
+        EEPROM.put(EEPROM_ADDR, theSettings);
+        lcd.clear();
+        lcd.noCursor();
+        setLCDBacklight(255, 0, 255);
       } else if(Bu_1.wasReleased())
       {
         cursorRow++;
@@ -217,24 +274,25 @@
           }
           int p_cR = cursorRow;
           int p_cC = cursorCol;
-          cursorCol = 20-6;
+          cursorCol = 5;
           cursorRow = 3;
           lcd.setCursor(cursorCol, cursorRow);
-          lcd.print("on/off");
+          lcd.print("on/off settings");
           cursorCol = 0;
           cursorRow = 0;
           lcd.setCursor(cursorCol, cursorRow);
-          lcd.print("dayLength(hr):");
+          lcd.print("dayLength(hr) ");
           lcd.print(dayLength);
           lcd.setCursor(cursorCol, cursorRow+=1);
-          lcd.print("rise/set(m):");
+          lcd.print("rise/set(min) ");
           lcd.print(dawn_duskLength);
           lcd.setCursor(cursorCol, cursorRow+=1);
           // sunriseStartTime = DateTime(now.year(), now.month(), now.day(), sunriseHour, sunriseMinute, 0) + TimeSpan(1,0,0,0);
           sunriseStartTime = DateTime(now.year(), now.month(), now.day(), sunriseHour, sunriseMinute, 0);
           sunsetFinishTime = sunriseStartTime + TimeSpan(0, dayLength, dawn_duskLength*2, 0);
-          lcd.print("sunrise:");
+          lcd.print("sunrise ");
           lcd.print(sunriseStartTime.hour()); lcd.print(":"); lcd.print(sunriseStartTime.minute());
+          lcd.print("am");
           cursorCol = p_cC;
           cursorRow = p_cR;
           lcd.setCursor(cursorCol, cursorRow);
@@ -242,7 +300,7 @@
       }
       break;
     case TO_TIME_SETTINGS:
-      if(Bu_1.wasReleased())
+      if(Bu_2.wasReleased())
       {
         STATE = TIME_SETTINGS;
         set = now;
@@ -276,6 +334,13 @@
       if(Bu_1.pressedFor(LONG_PRESS))
       {
         STATE = TO_RUN;
+        if(set.unixtime() != now.unixtime()) {
+          rtc.adjust(set);
+          MORNING = 0;
+          DAY = 0;
+          EVENING = 0;
+          NIGHT = 0;
+        }
         lcd.clear();
         lcd.noCursor();
         setLCDBacklight(255, 0, 255);
@@ -346,19 +411,12 @@
     case TO_RUN:
       if(Bu_1.wasReleased()) {
         STATE = RUN;
-        setLCDBacklight(0,255,255);
-        if(set.unixtime() != now.unixtime()) {
-          rtc.adjust(set);
-          MORNING = 0;
-          DAY = 0;
-          EVENING = 0;
-          NIGHT = 0;
-        }
-        p1.setPixelColor(5, 0,0,0,0);
-        p1.show();
+        setLCDBacklight(50, 255, 50);
+        // p1.setPixelColor(5, 0,0,0,0);
+        // p1.show();
       } else if(Bu_2.wasReleased()) {
         STATE = RUN;
-        setLCDBacklight(0,255,255);
+        setLCDBacklight(50, 255, 50);
       }
       break;

@@ -370,97 +428,78 @@
         cursorCol = 0;
         cursorRow = 0;
         lcd.setCursor(cursorCol, cursorRow);
-        lcd.print("Start: Color 1");
+        lcd.print("Panel 1");
+        cursorCol = 5;
+        cursorRow = 3;
+        lcd.setCursor(cursorCol, cursorRow);
+        lcd.print("color settings");
         cursorCol = 0;
         cursorRow = 0;
         lcd.setCursor(cursorCol, cursorRow);
       }
       break;
     case COLOR_SETTINGS:
-      if(Bu_2.pressedFor(LONG_PRESS))
+      if(Bu_1.pressedFor(LONG_PRESS))
       {
         STATE = TO_RUN;
+        theSettings.c1 = color1Day;
+        theSettings.c2 = color2Day;
+        theSettings.c3 = color3Day;
+        EEPROM.put(EEPROM_ADDR, theSettings);
         lcd.clear();
-      } else if(Bu_2.wasReleased())
+      } else if(Bu_1.wasReleased())
       {
         cursorRow++;
-        cursorRow %= 6;
+        cursorRow %= 3;
         if(cursorRow == 0)
         {
           int p_cR = cursorRow;
           int p_cC = cursorCol;
-          for(int i = 0; i < NUMPIXELS; i++) p1.setPixelColor(i, color1Start);
+          for(int i = 0; i < NUMPIXELS; i++) p1.setPixelColor(i, color1Day);
           p1.show();
           lcd.clear();
           cursorCol = 0;
           cursorRow = 0;
           lcd.setCursor(cursorCol, cursorRow);
-          lcd.print("Start: Color 1");
+          lcd.print("Panel 1");
+          cursorCol = 5;
+          cursorRow = 3;
+          lcd.setCursor(cursorCol, cursorRow);
+          lcd.print("color settings");
           cursorCol = p_cC;
           cursorRow = p_cR;
         } else if(cursorRow == 1)
         {
           int p_cR = cursorRow;
           int p_cC = cursorCol;
-          for(int i = 0; i < NUMPIXELS; i++) p1.setPixelColor(i, color1End);
-          p1.show();
+          for(int i = 0; i < NUMPIXELS; i++) p2.setPixelColor(i, color2Day);
+          p2.show();
           lcd.clear();
           cursorCol = 0;
           cursorRow = 0;
           lcd.setCursor(cursorCol, cursorRow);
-          lcd.print("End: Color 1");
+          lcd.print("Panel 2");
+          cursorCol = 5;
+          cursorRow = 3;
+          lcd.setCursor(cursorCol, cursorRow);
+          lcd.print("color settings");
           cursorCol = p_cC;
           cursorRow = p_cR;
         } else if(cursorRow == 2)
         {
           int p_cR = cursorRow;
           int p_cC = cursorCol;
-          for(int i = 0; i < NUMPIXELS; i++) p1.setPixelColor(i, color2Start);
-          p1.show();
+          for(int i = 0; i < NUMPIXELS; i++) p3.setPixelColor(i, color3Day);
+          p3.show();
           lcd.clear();
           cursorCol = 0;
           cursorRow = 0;
           lcd.setCursor(cursorCol, cursorRow);
-          lcd.print("Start: Color 2");
-          cursorCol = p_cC;
-          cursorRow = p_cR;
-        } else if(cursorRow == 3)
-        {
-          int p_cR = cursorRow;
-          int p_cC = cursorCol;
-          for(int i = 0; i < NUMPIXELS; i++) p1.setPixelColor(i, color2End);
-          p1.show();
-          lcd.clear();
-          cursorCol = 0;
-          cursorRow = 0;
-          lcd.setCursor(cursorCol, cursorRow);
-          lcd.print("End: Color 2");
-          cursorCol = p_cC;
-          cursorRow = p_cR;
-        } else if(cursorRow == 4)
-        {
-          int p_cR = cursorRow;
-          int p_cC = cursorCol;
-          for(int i = 0; i < NUMPIXELS; i++) p1.setPixelColor(i, color3Start);
-          p1.show();
-          lcd.clear();
-          cursorCol = 0;
-          cursorRow = 0;
-          lcd.setCursor(cursorCol, cursorRow);
-          lcd.print("Start: Color 3");
-          cursorCol = p_cC;
-          cursorRow = p_cR;
-        } else if(cursorRow == 5)
-        {
-          int p_cR = cursorRow;
-          int p_cC = cursorCol;
-          for(int i = 0; i < NUMPIXELS; i++) p1.setPixelColor(i, color3End);
-          p1.show();
-          lcd.clear();
-          cursorCol = 0;
-          cursorRow = 0;
-          lcd.setCursor(cursorCol, cursorRow);
-          lcd.print("End: Color 3");
+          lcd.print("Panel 3");
+          cursorCol = 5;
+          cursorRow = 3;
+          lcd.setCursor(cursorCol, cursorRow);
+          lcd.print("color settings");
           cursorCol = p_cC;
           cursorRow = p_cR;
         }
@@ -469,79 +508,40 @@
         if(cursorRow == 0) {
           for(int i = 0; i < 5; i++) p1.setPixelColor(i, getColor());
           p1.show();
-          if(Bu_1.wasReleased()) {
-            color1Start = getColor();
+          if(Bu_2.wasReleased()) {
+            color1Day = getColor();
             for(int i = 0; i < NUMPIXELS; i++) {
-              p1.setPixelColor(i, color1Start);
+              p1.setPixelColor(i, color1Day);
             }
             p1.show();
-            lcd.setCursor(0, 2);
-            lcd.print("-Stored");
+            lcd.setCursor(10, 0);
+            lcd.print("-stored");
           }
         }
         if(cursorRow == 1) {
-          for(int i = 0; i < 5; i++) p1.setPixelColor(i, getColor());
-          p1.show();
-          if(Bu_1.wasReleased()){
-            color1End = getColor();
+          for(int i = 0; i < 5; i++) p2.setPixelColor(i, getColor());
+          p2.show();
+          if(Bu_2.wasReleased()){
+            color2Day = getColor();
             for(int i = 0; i < NUMPIXELS; i++) {
-              p1.setPixelColor(i, color1End);
+              p2.setPixelColor(i, color2Day);
             }
-            p1.show();
-            lcd.setCursor(0, 2);
-            lcd.print("-Stored");
+            p2.show();
+            lcd.setCursor(10, 0);
+            lcd.print("-stored");
           }
         }
         if(cursorRow == 2) {
-          for(int i = 0; i < 5; i++) p1.setPixelColor(i, getColor());
-          p1.show();
-          if(Bu_1.wasReleased()){
-            color2Start = getColor();
+          for(int i = 0; i < 5; i++) p3.setPixelColor(i, getColor());
+          p3.show();
+          if(Bu_2.wasReleased()){
+            color3Day = getColor();
             for(int i = 0; i < NUMPIXELS; i++) {
-              p1.setPixelColor(i, color2Start);
+              p3.setPixelColor(i, color3Day);
             }
-            p1.show();
-            lcd.setCursor(0, 2);
-            lcd.print("-Stored");
-          }
-        }
-        if(cursorRow == 3) {
-          for(int i = 0; i < 5; i++) p1.setPixelColor(i, getColor());
-          p1.show();
-          if(Bu_1.wasReleased()){
-            color2End = getColor();
-            for(int i = 0; i < NUMPIXELS; i++) {
-              p1.setPixelColor(i, color2End);
-            }
-            p1.show();
-            lcd.setCursor(0, 2);
-            lcd.print("-Stored");
-          }
-        }
-        if(cursorRow == 4) {
-          for(int i = 0; i < 5; i++) p1.setPixelColor(i, getColor());
-          p1.show();
-          if(Bu_1.wasReleased()){
-            color3Start = getColor();
-            for(int i = 0; i < NUMPIXELS; i++) {
-              p1.setPixelColor(i, color3Start);
-            }
-            p1.show();
-            lcd.setCursor(0, 2);
-            lcd.print("-Stored");
-          }
-        }
-        if(cursorRow == 5) {
-          for(int i = 0; i < 5; i++) p1.setPixelColor(i, getColor());
-          p1.show();
-          if(Bu_1.wasReleased()){
-            color3End = getColor();
-            for(int i = 0; i < NUMPIXELS; i++) {
-              p1.setPixelColor(i, color3End);
-            }
-            p1.show();
-            lcd.setCursor(0, 2);
-            lcd.print("-Stored");
+            p3.show();
+            lcd.setCursor(10, 0);
+            lcd.print("-stored");
           }
         }
       }
@@ -554,11 +554,9 @@
   // normalize the red LED - its brighter than the rest!
   r = map(r, 0, 255, 0, 100); //100
   g = map(g, 0, 255, 0, 100); //150
-
   r = map(r, 0, 255, 0, lcd_brightness);
   g = map(g, 0, 255, 0, lcd_brightness);
   b = map(b, 0, 255, 0, lcd_brightness);
-
   // common anode so invert!
   r = map(r, 0, 255, 255, 0);
   g = map(g, 0, 255, 255, 0);
@@ -596,65 +594,116 @@
   DateTime sunsetStartTime;
   sunriseFinishTime = sunriseStartTime + TimeSpan(0, 0, dawn_duskLength, 0);
   sunsetStartTime = sunsetFinishTime - TimeSpan(0,0, dawn_duskLength,0);
-  // Serial.print("rise "); Serial.println(sunriseStartTime.unixtime());
-  // Serial.print("now  "); Serial.println(now.unixtime());
-  // Serial.println();
+
   if(now.unixtime() > sunriseStartTime.unixtime() && now.unixtime() < sunriseFinishTime.unixtime())
   {
-    if(!MORNING) {
+    if(!MORNING)
+    {
       MORNING = 1;
       NIGHT = 0;
-      p1.Fade(color1Start, color1End, dawn_duskLength, FORWARD);
+      p1.Fade(colorStart, color1Day, dawn_duskLength);
+      p2.Fade(colorStart, color2Day, dawn_duskLength);
+      p3.Fade(colorStart, color3Day, dawn_duskLength);
       lcd.clear();
     }
     p1.Update();
-    lcd.setCursor(20-6, 0);
-    lcd.print("Morn");
-  } else if(now.unixtime() > sunriseFinishTime.unixtime() && now.unixtime() < sunsetStartTime.unixtime())
+    p2.Update();
+    p3.Update();
+    lcd.setCursor(20-7, 0);
+    lcd.print("||MORN|");
+  }
+  else if(now.unixtime() > sunriseFinishTime.unixtime() && now.unixtime() < sunsetStartTime.unixtime())
   {
-    if(!DAY) {
+    if(!DAY)
+    {
       DAY = 1;
       MORNING = 0;
       lcd.clear();
     }
-    for(int i = 0; i < NUMPIXELS; i++) p1.setPixelColor(i, color1End);
+    for(int i = 0; i < NUMPIXELS; i++)
+    {
+      p1.setPixelColor(i, color1Day);
+      p2.setPixelColor(i, color2Day);
+      p3.setPixelColor(i, color3Day);
+    }
     p1.show();
-    lcd.setCursor(20-6, 0);
-    lcd.print("Day");
-  } else if(now.unixtime() > sunsetStartTime.unixtime() && now.unixtime() < sunsetFinishTime.unixtime())
+    p2.show();
+    p3.show();
+    lcd.setCursor(20-7, 0);
+    lcd.print("||DAY||");
+  }
+  else if(now.unixtime() > sunsetStartTime.unixtime() && now.unixtime() < sunsetFinishTime.unixtime())
   {
-    if(!EVENING) {
+    if(!EVENING)
+    {
       EVENING = 1;
       DAY = 0;
-      p1.Fade(color1Start, color1End, dawn_duskLength, REVERSE);
+      p1.Fade(color1Day, colorEnd, dawn_duskLength);
+      p2.Fade(color2Day, colorEnd, dawn_duskLength);
+      p3.Fade(color3Day, colorEnd, dawn_duskLength);
       lcd.clear();
     }
     p1.Update();
-    lcd.setCursor(20-6, 0);
-    lcd.print("Eve");
-  } else if(now.unixtime() > sunsetFinishTime.unixtime() && now.unixtime() < sunriseStartTime.unixtime())
+    p2.Update();
+    p3.Update();
+    lcd.setCursor(20-7, 0);
+    lcd.print("||EVE||");
+  }
+  else if(now.unixtime() > sunsetFinishTime.unixtime() && now.unixtime() < sunriseStartTime.unixtime())
   {
-    if(!NIGHT) {
-      NIGHT = 1;
-      EVENING = 0;
-      lcd.clear();
-      //Set Next Alarm for Tomorrow!
-      sunriseStartTime = DateTime(now.year(), now.month(), now.day(), sunriseHour, sunriseMinute, 0) + TimeSpan(1,0,0,0);
-      sunsetFinishTime = sunriseStartTime + TimeSpan(0, dayLength, dawn_duskLength*2, 0);
-    }
-    for(int i = 0; i < NUMPIXELS; i++) p1.setPixelColor(i, color1Start);
-    p1.show();
-    lcd.setCursor(20-6, 0);
-    lcd.print("Night");
-  } else if(now.unixtime() < sunriseStartTime.unixtime()){
-    if(!NIGHT) {
+    if(!NIGHT)
+    {
       NIGHT = 1;
       EVENING = 0;
       lcd.clear();
     }
-    for(int i = 0; i < NUMPIXELS; i++) p1.setPixelColor(i, color1Start);
+    for(int i = 0; i < NUMPIXELS; i++)
+    {
+      p1.setPixelColor(i, 0);
+      p2.setPixelColor(i, 0);
+      p3.setPixelColor(i, 0);
+    }
     p1.show();
-    lcd.setCursor(20-6, 0);
-    lcd.print("Night");
+    p2.show();
+    p3.show();
+    lcd.setCursor(20-7, 0);
+    lcd.print("||NIGHT");
+  }
+  else if(now.unixtime() < sunriseStartTime.unixtime())
+  {
+    if(!NIGHT)
+    {
+      NIGHT = 1;
+      EVENING = 0;
+      lcd.clear();
+    }
+    for(int i = 0; i < NUMPIXELS; i++)
+    {
+      p1.setPixelColor(i, 0);
+      p2.setPixelColor(i, 0);
+      p3.setPixelColor(i, 0);
+    }
+    p1.show();
+    p2.show();
+    p3.show();
+    lcd.setCursor(20-7, 0);
+    lcd.print("||NIGHT");
+  }
+  else if(now.unixtime() > sunsetFinishTime.unixtime())
+  {
+    sunriseStartTime = DateTime(now.year(), now.month(), now.day(), sunriseHour, sunriseMinute, 0) + TimeSpan(1,0,0,0);
+    // sunriseStartTime = DateTime(now.year(), now.month(), now.day(), sunriseHour, sunriseMinute, 0);
+    sunsetFinishTime = sunriseStartTime + TimeSpan(0, dayLength, dawn_duskLength*2, 0);
   }
 }
+
+void loadSavedSettings(){
+  EEPROM.get(EEPROM_ADDR, theSettings);
+  color1Day = theSettings.c1;
+  color2Day = theSettings.c2;
+  color3Day = theSettings.c3;
+  dayLength = theSettings.dayL;
+  dawn_duskLength = theSettings.fadeT;
+  sunriseHour = theSettings.riseH;
+  sunriseMinute = theSettings.riseM;
+}


Change to test of downlink channel 3 and DR4

--- examples/raw-feather/raw-feather.ino
+++ examples/raw-feather/raw-feather.ino
@@ -206,7 +206,7 @@
   // handle multiple nodes; in that case we'd have a way to do
   // production test and qualification. However, using an RWC5020A
   // is a much better use of development time.
-  const static bool fDownlink = true;
+  const static bool fDownlink = false;
   const static uint8_t kDownlinkChannel = 3;
   const static uint8_t kUplinkChannel = 8 + 3;
   uint32_t uBandwidth;
@@ -236,9 +236,9 @@

   // Use a suitable spreading factor
   if (uBandwidth < 500)
-        LMIC.datarate = DR_SF10;        // DR0
+        LMIC.datarate = US915_DR_SF7;         // DR4
   else
-        LMIC.datarate = DR_SF12CR;      // DR8
+        LMIC.datarate = US915_DR_SF12CR;      // DR8

   // default tx power for US: 21 dBm
   LMIC.txpow = 21;


added LWT + connected message

added LWT + connected message

--- T0/src/AFE-API-MQTT.ino
+++ T0/src/AFE-API-MQTT.ino
@@ -48,8 +48,13 @@
       if (delayStartTime == 0) {
         delayStartTime = millis();

+        /* LWT Topic */
+        char mqttLWTMessage[38];
+        sprintf(mqttLWTMessage, "%sstate", MQTTConfiguration.topic);
+
         if (Broker.connect(deviceName, MQTTConfiguration.user,
-                           MQTTConfiguration.password)) {
+                           MQTTConfiguration.password, mqttLWTMessage, 2, false,
+                           "disconnected")) {

           /*
                     Serial << endl << "INFO: Connected";
@@ -60,6 +65,9 @@
           Broker.subscribe((char *)mqttTopicForSubscription);

           //        Serial << endl << "INFO: Subsribed";
+
+          /* Publishing message that device has been connected */
+          publish(MQTTConfiguration.topic, "state", "connected");

           /* Setting Relay state after connection to MQTT */
           for (uint8_t i = 0; i < sizeof(Device.configuration.isRelay); i++) {


Affiche les lettre sur la matrice 8x8

Affiche les lettre sur la matrice 8x8

Double défi, la matrice n'est pas disposé en S, mais en peigne comme un écran
traditionel.

--- arduino/eqbe-painless-mesh/eqbe-painless-mesh.ino
+++ arduino/eqbe-painless-mesh/eqbe-painless-mesh.ino
@@ -15,8 +15,9 @@
 #define BRIGHTNESS          60
 #define FRAMES_PER_SECOND   125 // 125 frames/sec <=> 8 milli/frame

-//#define NUM_LEDS  25
-#define NUM_LEDS  64
+//#define NUM_LEDS_SIDE 5
+#define NUM_LEDS_SIDE 8
+#define NUM_LEDS      (NUM_LEDS_SIDE * NUM_LEDS_SIDE)

 #define LED_TYPE    PL9823
 //#define LED_TYPE    WS2812B
@@ -502,8 +503,34 @@
   uint32_t singleBit = 1;

   // FIXME: Use font size instead of magic 5*5
-  for ( uint8_t i = 0; i < 25; i++) {
-    leds[i] = CHSV(gHue, 255, letterA & singleBit ? 255 : 0);
+
+  int8_t offset = 0;
+  int8_t invert = 0;
+  for (int8_t i = 0; i < 25; i++) {
+    invert = 0;
+    if (NUM_LEDS_SIDE > 5) {
+        if (i % 5 == 0) {
+            int8_t skip = (NUM_LEDS_SIDE - 5);
+            for (int8_t j = 0; j < skip; j += 1) {
+                leds[i + offset + j] = CHSV(HUE_BLUE, 255, 100);
+            }
+            offset += skip;
+        }
+        if (i % 10 == 5) {
+            invert = 4;
+        }
+        if (i % 10 == 6) {
+            invert = 2;
+        }
+        if (i % 10 == 8) {
+            invert = -2;
+        }
+        if (i % 10 == 9) {
+            invert = -4;
+        }
+    }
+    leds[i + offset + invert] = CHSV(gHue, 255, letterA & singleBit ? 255 : 0);
     singleBit <<= 1;
-  }
-}
+
+  }
+}


Removed temporary code

Removed temporary code

--- V0p2_Main/V0p2_Main.ino
+++ V0p2_Main/V0p2_Main.ino
@@ -135,13 +135,6 @@
   LED_HEATCALL_ON();
   OTV0P2BASE::sleepLowPowerMs(1000); // TODO: use this time to gather entropy.

-  // TODO temp code
-  pinMode(6, INPUT); // force QM-1 on
-  fastDigitalWrite(6, HIGH);
-  pinMode(A2, INPUT); // set up RN2483 reset (currently shorting to ground)
-  fastDigitalWrite(A2, LOW);
-  pinMode(A3, OUTPUT); // force QM-1 on
-  fastDigitalWrite(A3, HIGH);
   }
 #endif // ALT_MAIN_LOOP


retransmit command too long renamed to relay

--- XV_Lidar_Controller.ino
+++ XV_Lidar_Controller.ino
@@ -35,7 +35,7 @@

 boolean debug_motor_rpm = false;
 boolean motor_enable = true;
-boolean retransmit = true;
+boolean relay = true;

 PID rpmPID(&motor_rpm, &pwm_val, &xv_config.rpm_setpoint, xv_config.Kp, xv_config.Ki, xv_config.Kd, DIRECT);

@@ -73,11 +73,11 @@

   sCmd.readSerial();  // check for incoming serial commands

-  // read byte from LIDAR and retransmit to USB
+  // read byte from LIDAR and relay to USB
   if (Serial1.available() > 0) {
     inByte = Serial1.read();  // get incoming byte:
-    if (retransmit) {
-      Serial.print(inByte, BYTE);  // retransmit
+    if (relay) {
+      Serial.print(inByte, BYTE);  // relay
     }
     decodeData(inByte);
   }
@@ -192,8 +192,8 @@
   sCmd.addCommand("HideRPM",       hideRPM);
   sCmd.addCommand("MotorOff",      motorOff);
   sCmd.addCommand("MotorOn",       motorOn);
-  sCmd.addCommand("RetransmitOff", retransmitOff);
-  sCmd.addCommand("RetransmitOn",  retransmitOn);
+  sCmd.addCommand("RelayOff", relayOff);
+  sCmd.addCommand("RelayOn",  relayOn);

   // XV Commands
   sCmd.addCommand("GetPrompt",  getPrompt);
@@ -222,13 +222,13 @@
   Serial.println("Motor on");
 }

-void retransmitOff() {
-  retransmit = false;
+void relayOff() {
+  relay = false;
   Serial.println("Lidar data disabled");
 }

-void retransmitOn() {
-  retransmit = true;
+void relayOn() {
+  relay = true;
   Serial.println("Lidar data enabled");
 }

@@ -358,7 +358,7 @@
 }

 void help() {
-  Serial.println("List of available commands (case sensitive");
+  Serial.println("List of available commands (case sensitive)");
   Serial.println("  GetConfig");
   Serial.println("  SaveConfig");
   Serial.println("  ResetConfig");
@@ -370,8 +370,8 @@
   Serial.println("  HideRPM");
   Serial.println("  MotorOff");
   Serial.println("  MotorOn");
-  Serial.println("  RetransmitOff");
-  Serial.println("  RetransmitOn");
+  Serial.println("  RelayOff");
+  Serial.println("  RelayOn");
 }

 void getConfig() {