I really need to commit more often

I really need to commit more often

--- teensy/teensy.ino
+++ teensy/teensy.ino
@@ -29,15 +29,9 @@
 #include <SdFat.h>
 #include <BlockDriver.h>
 #include <SysCall.h>
-
-#define SD_SS_PIN 4
+#include <DMAChannel.h>
+
 #define STATUS_PIN 13
-#define CS 10
-#define DC 9
-#define RESET 7 // Moved from 8, which is in use by the N64
-
-#define NEXT 2
-#define SELECT 3

 #define SERIAL_BAUD_RATE 115200

@@ -50,10 +44,25 @@
 #define LED_HIGH (CORE_PIN13_PORTSET = CORE_PIN13_BITMASK) //digitalWriteFast(STATUS_PIN, HIGH)
 #define LED_LOW (CORE_PIN13_PORTCLEAR = CORE_PIN13_BITMASK) //digitalWriteFast(STATUS_PIN, LOW)

-#define INPUT_BUFFER_SIZE 512 // This is ideal since it allows us to read 256*4/2 = 512 bytes
-// at once. 512 bytes is an optimization for reading the sd card and skips using another buffer.
+#define INPUT_BUFFER_SIZE 2048 // Multiples of 512 are ideal since we can read 256*4/2 = 512 bytes at once.
+// 512 bytes is an optimization for reading the sd card and skips using another buffer.

 #define INPUT_BUFFER_UPDATE_TIMEOUT 10 // 10 ms
+
+template<class T> void lockedPrintln(const T& input)
+{
+  noInterrupts();
+  Serial.println(input);
+  interrupts();
+}
+
+template<class A, class B> void lockedPrintln(const A& a, const B& b)
+{
+  noInterrupts();
+  Serial.print(a);
+  Serial.println(b);
+  interrupts();
+}

 static char n64_raw_dump[36]; // maximum recv is 1+2+32 bytes + 1 bit
 // n64_raw_dump does not include the command byte. That gets pushed into
@@ -61,20 +70,67 @@
 static int n64_command;
 // bytes to send to the 64
 // maximum we'll need to send is 33, 32 for a read request and 1 CRC byte
-static unsigned char n64_buffer[33];
+static unsigned char output_buffer[33];
 static void get_n64_command();
 static void n64_send(unsigned char *buffer, char length, bool wide_stop);

 // Simple switch buffer. (If buffer A fails to load while buffer B is in use,
 // we still okay, and will try again next loop)
-static unsigned long inputBuffer[INPUT_BUFFER_SIZE];
-static bool bufferALoaded, bufferBLoaded;
-static bool bufferAInUse, bufferBInUse;
-static long bufferEndPos;
-static bool bufferOneMore;
-static long bufferPos;
+static char inputBuffer[INPUT_BUFFER_SIZE];
+static size_t bufferEndPos;
+static volatile size_t bufferPos;
+static volatile bool bufferHasData;
 static void updateInputBuffer();

+static size_t getNextRegion(size_t& size) {
+  size_t currentPos = bufferPos;
+  if ((currentPos == bufferEndPos || (currentPos == 0 && bufferEndPos == INPUT_BUFFER_SIZE)) && bufferHasData) {
+    size = 0;
+    return 0;
+  }
+  size_t ret = bufferEndPos;
+  if (ret == INPUT_BUFFER_SIZE)
+    ret = 0;
+  size = INPUT_BUFFER_SIZE - ret;
+  if (ret < currentPos)
+    size = currentPos - ret;
+  return ret;
+}
+
+void initBuffers()
+{
+  bufferEndPos = 0;
+  bufferPos = 0;
+  bufferHasData = false;
+}
+
+static void advanceBuffer(long bytes)
+{
+  size_t pos = bufferPos + bytes;
+  if (pos == bufferEndPos) {
+    bufferHasData = false;
+    bufferPos = pos;
+    return;
+  }
+  if (pos >= INPUT_BUFFER_SIZE)
+      pos = 0;
+  bufferPos = pos;
+}
+
+static size_t appendInputs(const String& data)
+{
+  size_t totalWritten = 0;
+  size_t writeLen = 0;
+  do {
+    size_t dataLeft = data.length() - totalWritten;
+    size_t writePos = getNextRegion(writeLen);
+    if (writeLen > dataLeft)
+      writeLen = dataLeft;
+    memcpy(inputBuffer + writePos, data.c_str() + totalWritten, writeLen);
+    totalWritten += writeLen;
+  } while (writeLen > 0);
+  return totalWritten;
+}

 static FatFile m64File;
 static bool m64OpenSuccess = false;
@@ -84,11 +140,10 @@

 //static unsigned int progressPos = 0;
 static unsigned long numFrames = 0, curFrame = 0;
+static int edgesRead = 0;
+static int incompleteCommand = 0;

 SdFatSdioEX sd;
-
-#define dirPos curFrame
-#define numFiles numFrames

 #define MICRO_CYCLES (F_CPU / 1000000)

@@ -96,15 +151,14 @@
 {
   FatFile dir;
   if (!dir.open(&sd, path.c_str(), O_READ)) {
-    Serial.println(F("Failed to open requested directory"));
+    Serial.println(F("E:Failed to open requested directory"));
     return;
   }
   dir.rewind();
   while (m64File.openNext(&dir)) {
     char name[256];
     m64File.getName(name, sizeof(name));
-    Serial.print("A:");
-    Serial.println(name);
+    lockedPrintln("A:", name);
     m64File.close();
   }
   dir.close();
@@ -134,21 +188,15 @@
   // Initialize SD card
   if (!sd.begin()) {
     m64OpenSuccess = false;
-    Serial.println(F("SD initialization failed!"));
+    Serial.println(F("E:SD initialization failed!"));
     return;
   }
-  Serial.println(F("SD initialization done."));
+  Serial.println(F("L:SD initialization done."));

   // Setup buffer
-  bufferALoaded = false;
-  bufferBLoaded = false;
-  bufferAInUse = false;
-  bufferBInUse = false;
-  bufferEndPos = -1;
-  bufferOneMore = true;
-  bufferPos = -1;
-
-  Serial.println(F("Initialization done."));
+  initBuffers();
+
+  Serial.println(F("L:Initialization done."));
 }

 void logFrame()
@@ -208,7 +256,36 @@
   return true;
 }

+String hextobin(const String& hex)
+{
+  String ret;
+  ret.reserve((hex.length() + 1) / 2);
+
+  // mapping of ASCII characters to hex values
+  static const uint8_t map[] = {
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // 01234567
+    0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 89:;<=>?
+    0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, // @ABCDEFG
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // HIJKLMNO
+  };
+
+  for (size_t pos = 0; pos < hex.length(); pos += 2) {
+    size_t idx0 = ((uint8_t)hex[pos]     & 0x1F) ^ 0x10,
+           idx1 = ((uint8_t)hex[pos + 1] & 0x1F) ^ 0x10;
+    ret += (char)((map[idx0] << 4) | map[idx1]);
+  }
+
+  return ret;
+}
+
 static FatFile writeFile;
+
+static void appendData(const String& data) {
+  if (writeFile.write(data.c_str(), data.length()) == (int)data.length())
+    Serial.println("AP:OK");
+  else
+    Serial.println("AP:NAK");
+}

 bool skippingInput = false;
 static String inputString;
@@ -222,44 +299,49 @@
   } else if (cmd.startsWith("L:")) {
     emitList(cmd.substring(2));
   } else if (cmd.startsWith("MK:")) {
-    Serial.print("MK:");
-    Serial.println(sd.mkdir(cmd.substring(3).c_str()));
+    lockedPrintln("MK:", sd.mkdir(cmd.substring(3).c_str()));
   } else if (cmd.startsWith("CR:")) {
     if (writeFile.isOpen()) {
       writeFile.close();
     }
-    if (writeFile.open(&sd, cmd.substring(3).c_str(), O_WRITE | O_CREAT)) {
-      Serial.println("CR:OK");
+    if (writeFile.open(&sd, cmd.substring(3).c_str(), O_WRITE | O_CREAT | O_TRUNC)) {
+      lockedPrintln("CR:OK");
     } else {
-      Serial.println("CR:NAK");
+      lockedPrintln("CR:NAK");
     }
   } else if (cmd.startsWith("AP:")) {
-
+    appendData(hextobin(cmd.substring(3)));
+  } else if (cmd.startsWith("IN:")) {
+    size_t len = appendInputs(hextobin(cmd.substring(3)));
+    lockedPrintln("IN:", len);
   } else if (cmd.startsWith("CL:")) {
     writeFile.close();
+    lockedPrintln("CL:OK");
   } else if (cmd.startsWith("PM:")) {
     setPinMode(cmd.substring(3));
   } else if (cmd.startsWith("DW:")) {
     writePin(cmd.substring(3));
   } else {
-    Serial.print("Unknown CMD:");
-    Serial.println(cmd.c_str());
-  }
-}
+    lockedPrintln("E:Unknown CMD:", cmd.c_str());
+  }
+}
+
+#define MAX_CMD_LEN 4096
+#define MAX_LOOP_LEN 10240

 static void inputLoop()
 {
   int newChar;
   int charsRead = 0;
-  while ((newChar = Serial.read()) != -1 && (charsRead++ <= 1024)) {
+  while ((newChar = Serial.read()) != -1 && (charsRead++ <= MAX_LOOP_LEN)) {
     if (newChar == '\n') {
       if (skippingInput)
-        Serial.println("Skipped line longer than 256 chars");
+        Serial.println("E:Skipped too-long line");
       else
         handleCommand(inputString);
       inputString = "";
       skippingInput = false;
-    } else if (inputString.length() > 256) {
+    } else if (inputString.length() > MAX_CMD_LEN) {
       skippingInput = true;
     } else {
       inputString += (char)newChar;
@@ -295,8 +377,10 @@

 static void n64Interrupt()
 {
-    long pos;
+    noInterrupts();
+
     unsigned char data, addr;
+    int ticksSinceLast = readTimer();
     startTimer();
     volatile uint32_t *config = portConfigRegister(N64_PIN);
     uint32_t oldConfig = *config;
@@ -304,9 +388,7 @@

     // Bail if file open failed
     if (!m64OpenSuccess)
-        return;
-
-    noInterrupts();
+        goto end;

     *config &= ~0x000F0000;

@@ -323,7 +405,7 @@
         case 0x00:
         case 0xFF:
             // identify
-            // mutilate the n64_buffer array with our status
+            // mutilate the output_buffer array with our status
             // we return 0x050001 to indicate we have a rumble pack
             // or 0x050002 to indicate the expansion slot is empty
             //
@@ -331,26 +413,26 @@
             // I don't know why it's different, but the controllers seem to
             // send a set of status bytes afterwards the same as 0x00, and
             // it won't work without it.
-            n64_buffer[0] = 0x05;
-            n64_buffer[1] = 0x00;
-            n64_buffer[2] = 0x01;
-
-            n64_send(n64_buffer, 3, 1);
-            Serial.println(F("Controller identified"));
+            output_buffer[0] = 0x05;
+            output_buffer[1] = 0x00;
+            output_buffer[2] = 0x01;
+
+            n64_send(output_buffer, 3, 1);
             Serial.println("P:");
             break;
         case 0x01:
             // If the TAS is finished, there's nothing left to do.
-            if (finished && !bufferOneMore)
-              memset(n64_buffer, 0, 4);
+            if (finished || !bufferHasData)
+              memset(output_buffer, 0, 4);
             else
-              memcpy(n64_buffer, inputBuffer + bufferPos, 4);
+              memcpy(output_buffer, inputBuffer + bufferPos, 4);

-            // blast out the pre-assembled array in n64_buffer
-            n64_send(n64_buffer, 4, 1);
-
-            if (finished)
+            // blast out the pre-assembled array in output_buffer
+            n64_send(output_buffer, 4, 1);
+
+            if (finished) {
               break;
+            }

             logFrame();

@@ -362,17 +444,14 @@
             Serial.println(inputBuffer[bufferPos]);*/

             if (curFrame == numFrames && !finished) {
-              Serial.println(F("TAS finished playing"));
               Serial.println("C:");
               finished = true;
             }

             curFrame++;

-            pos = bufferPos + 1;
-            if (pos >= INPUT_BUFFER_SIZE)
-                pos = 0;
-            bufferPos = pos;
+            if (!finished && bufferHasData)
+              advanceBuffer(4);

 //            while (Serial.availableForWrite() && readTimer() < 10 * 1000 * MICRO_CYCLES && N64_QUERY);

@@ -392,11 +471,11 @@

             // Assume it's a read for 0x8000, which is the only thing it should
             // be requesting anyways
-            memset(n64_buffer, 0x80, 32);
-            n64_buffer[32] = 0xB8; // CRC
-
-            n64_send(n64_buffer, 33, 1);
-            Serial.println(F("Got a read, what?"));
+            memset(output_buffer, 0x80, 32);
+            output_buffer[32] = 0xB8; // CRC
+
+            n64_send(output_buffer, 33, 1);
+            Serial.println(F("L:Got a read, what?"));

             //Serial.println("It was 0x02: the read command");
             break;
@@ -420,11 +499,11 @@

             // get crc byte, invert it, as per the protocol for
             // having a memory card attached
-            n64_buffer[0] = crc_repeating_table[data] ^ 0xFF;
+            output_buffer[0] = crc_repeating_table[data] ^ 0xFF;

             // send it
-            n64_send(n64_buffer, 1, 1);
-            Serial.println(F("Got a write, what?"));
+            n64_send(output_buffer, 1, 1);
+            Serial.println(F("L:Got a write, what?"));

             // end of time critical code
             // was the address the rumble latch at 0xC000?
@@ -448,16 +527,35 @@
             break;

         case -1:
-            Serial.println(F("Timed out reading N64 command"));
+            if (finished)
+              break;
+            Serial.print(F("W:Read timeout; "));
+            Serial.print(edgesRead);
+            Serial.println(F(" edges read"));
+            if (edgesRead >= 2) {
+              Serial.print(F("W: partial byte: "));
+              Serial.println(incompleteCommand, HEX);
+            }
+            Serial.print(F("W:"));
+            Serial.print(ticksSinceLast);
+            Serial.println(F(" cycles since last"));
+            if (curFrame > 100)
+              Serial.println(F("D:timeout"));
             waitForIdle(1000);
             break;

         default:
-            Serial.print(F("Unknown command: 0x"));
+            if (finished)
+              break;
+            Serial.print(F("W:Unknown command: 0x"));
             Serial.println(n64_command, HEX);
+            if (curFrame > 100)
+              Serial.println(F("D:inval"));
+            waitForIdle(1000);
             break;
     }

+end:
     *config = oldConfig;

     interrupts();
@@ -478,7 +576,7 @@
     Serial.println(path);

     // Open the file for reading:
-    Serial.print(F("Opening file '"));
+    Serial.print(F("L:Opening file '"));
     Serial.print(path);
     Serial.println(F("'..."));

@@ -489,26 +587,26 @@

     // Error check
     if (!m64File.open(&sd, path.c_str(), O_READ)) {
-        Serial.println(F("Error in opening file"));
+        Serial.println(F("E:Error in opening file"));
         return false;
     }

     // Open header
     if (m64File.read(signature, 4) != 4 || m64File.read(&version, 4) != 4) {
         m64File.close();
-        Serial.println(F("Failed to read signature"));
+        Serial.println(F("E:Failed to read signature"));
         return false;
     }

     // Validate file signature
     if (memcmp(signature, "M64\x1A", 4) != 0) {
-        Serial.println(F("m64 signature invalid"));
+        Serial.println(F("E:m64 signature invalid"));
         m64File.close();
         return false;
     }

     // Print version
-    Serial.print(F("M64 Version: "));
+    Serial.print(F("L:M64 Version: "));
     Serial.println(version);

     Serial.flush();
@@ -516,9 +614,10 @@
     m64File.seekSet(0x018);

     // Open header
-    if (m64File.read(&numFrames, 4) != 4) {
+    int32_t newNumFrames;
+    if (m64File.read(&newNumFrames, 4) != 4) {
         m64File.close();
-        Serial.println(F("Failed to read frame count"));
+        Serial.println(F("E:Failed to read frame count"));
         return false;
     }

@@ -533,33 +632,22 @@
             break;
         default:
           // Unknown version
-            Serial.println(F("Error: unknown M64 version"));
+            Serial.println(F("E:unknown M64 version"));
             m64File.close();
             return false;
     }

     // Final check
     if (!m64File.available()) {
-        Serial.println(F("No input data found in file"));
+        Serial.println(F("E:No input data found in file"));
         m64File.close();
         return false;
     }

-    Serial.println(F("File opened successfully"));
-
-    Serial.print(F("Total size: "));
-    Serial.println(m64File.fileSize());
-
-    Serial.print(F("Position: "));
-    Serial.println(m64File.curPosition());
-
-    Serial.print(F("Expected Frames: "));
-    Serial.println((m64File.fileSize() - m64File.curPosition()) / 4);
-
-    numFrames = min(numFrames, (m64File.fileSize() - m64File.curPosition()) / 4);
+    newNumFrames = min(newNumFrames, (m64File.fileSize() - m64File.curPosition()) / 4);

     Serial.write("N:");
-    Serial.println(numFrames);
+    Serial.println(newNumFrames);

     Serial.flush();

@@ -574,131 +662,41 @@
     noInterrupts();
     m64OpenSuccess = true;
     finished = false;
-    bufferPos = -1;
-    bufferALoaded = false;
-    bufferBLoaded = false;
+    initBuffers();
+    curFrame = 0;
+    numFrames = newNumFrames;
     interrupts();

     return true;
 }

-
 static void updateInputBuffer() {
-    if (finished || !m64OpenSuccess)
+    if (finished || !m64File.isOpen())
       return;
-
-    long readBytes = 0;
-    if (bufferPos == -1) {
-        // Initially, both of our buffers are not in use
-        bufferPos = 0;
-        bufferAInUse = false;
-        bufferBInUse = false;
-    }
-    else {
-        // Calculate next buffer position
-        // Wrap position
-
-        // Calculate which buffer (A or B) is in use
-        if (bufferPos < INPUT_BUFFER_SIZE / 2) {
-            // Verify the buffer in use is loaded
-            if (!bufferALoaded) {
-                Serial.println(F("Error: New input was not loaded in buffer."));
-            }
-
-            // Clear old buffer when loading
-            if (!bufferAInUse) {
-                bufferBLoaded = false;
-            }
-
-            bufferAInUse = true;
-            bufferBInUse = false;
-        } else {
-            if (!bufferBLoaded) {
-                Serial.println(F("Error: New input was not loaded in buffer."));
-            }
-
-            // Clear old buffer when loading
-            if (!bufferBInUse) {
-                bufferALoaded = false;
-            }
-
-            bufferAInUse = false;
-            bufferBInUse = true;
-        }
-    }
-
-    // If we have loaded all inputs, wrap up
-    if (bufferEndPos != -1) {
-        // Perform one more input then end once the last input data has been queued.
-        if (bufferOneMore && bufferPos == bufferEndPos)
-            bufferOneMore = false;
-
-        return;
-    }

     // Check for file end
     if (!m64File.available()) {
-//        screen.println(F("End of M64 loaded into buffer"));
-
-        // Set end
-        if (!bufferAInUse) {
-            // End of buffer B marks end when
-            bufferEndPos = INPUT_BUFFER_SIZE - 1;
-        }
-        else if (!bufferBInUse) {
-            // End of buffer A marks end
-            bufferEndPos = INPUT_BUFFER_SIZE/2 - 1;
-        } else {
-            // Da fuq? (This should never happen)
-            Serial.println(F("Unexpected ending of input file"));
-
-            // End immediatley
-            bufferEndPos = 0;
-            finished = true;
-        }
-
-        // Close file
         m64File.close();
         return;
     }
-
-    // Load buffer A when its not in use
-    if (!bufferALoaded && !bufferAInUse) {
-        //Serial.println(F("Loading inputs into buffer A"));
-        // Read bytes
-        readBytes = m64File.read(inputBuffer, INPUT_BUFFER_SIZE*2);
-        if (readBytes == 0) {
-            Serial.println(F("Failed to read next inputs from file. (This is recoverable)"));
-        }
-        else {
-            bufferALoaded = true;
-            if (readBytes != INPUT_BUFFER_SIZE*2) {
-//                screen.println(F("End of M64 file found. Loading remaining bytes."));
-                bufferEndPos = readBytes / 4 - 1;
-                // Close file
-                m64File.close();
-            }
-        }
-    }
-    // Load buffer B when its not in use
-    else if (!bufferBLoaded && !bufferBInUse) {
-        //Serial.println(F("Loading inputs into buffer B"));
-        // Read bytes
-        readBytes = m64File.read(inputBuffer + (INPUT_BUFFER_SIZE / 2), INPUT_BUFFER_SIZE*2);
-        if (readBytes == 0) {
-            Serial.println(F("Failed to read next inputs from file. (This is recoverable)"));
-        }
-        else {
-            bufferBLoaded = true;
-            if (readBytes != INPUT_BUFFER_SIZE*2) {
-//                screen.println(F("End of M64 file found. Loading remaining bytes."));
-                // buffer end is offset from middle
-                bufferEndPos = INPUT_BUFFER_SIZE / 2 + readBytes / 4 - 1;
-                // Close file
-                m64File.close();
-            }
-        }
-    }
+
+    size_t availableSize;
+    size_t writePos = getNextRegion(availableSize);
+
+    // Optimized chunk reads
+    if ((availableSize < 512 && (writePos % 512) == 0) || !availableSize)
+        return;
+
+    int readBytes = m64File.read(inputBuffer + writePos, availableSize);
+    if (readBytes <= 0) {
+      lockedPrintln(F("W:Failed to read next inputs from file. (This is recoverable)"));
+      return;
+    }
+
+    noInterrupts();
+    bufferEndPos = writePos + readBytes;
+    bufferHasData = true;
+    interrupts();
 }

 static void startTimer()
@@ -771,15 +769,19 @@
   } \
 }\

+    edgesRead = 0;
+
     for (int i = 1; i <= bitcount; i++) {
         while (!N64_QUERY)
           FAIL_TIMEOUT;
         long lowTime = readTimer();
         startTimer();
+        edgesRead++;
         while (N64_QUERY)
           FAIL_TIMEOUT;
         long highTime = readTimer();
         startTimer();
+        edgesRead++;
         char bit = (lowTime < highTime);
         newByte <<= 1;
         newByte |= bit;
@@ -817,6 +819,7 @@
     while (readTimer() < MICRO_CYCLES * 2);

 fail:
+    incompleteCommand = newByte;

     LED_LOW;
 }


Polling successfully test. Card timeout is modifiable

--- module/module.ino
+++ module/module.ino
@@ -8,6 +8,7 @@
 // Start and End bytes for command/response packets
 #define STX 0xAA
 #define ETX 0xBB
+#define MSB 0xFF

 // MiFare Classic commands
 #define CMD_READ 0x20
@@ -15,7 +16,6 @@
 #define CMD_GET_SNR 0x25

 SoftwareSerial RDM880(RDM880_RX, RDM880_TX);
-//char txrxbuffer[bufferSize];

 const int ledPin = 13;
 const int signalPin = 4;
@@ -85,11 +85,11 @@
 	}

-	// Write time data to card
+	/*// Write time data to card
 	MF_WRITE(0x01, 0x05, elapsedTime);
 	delay(200);
 	responseFlag = getResponse(readData);
-	if(responseFlag == false) Serial.println("Unexpected result");
+	if(responseFlag == false) Serial.println("Unexpected result");*/

 }
@@ -246,20 +246,20 @@
 */
 unsigned long accumulator(void) {
 	unsigned long startTime, endTime = 0;
-	int pollCounter = 0;
+	unsigned long pollCounter = 0;
 	int signalState;
 	int previousState;
-	bool cardPresent;
+	unsigned char A[bufferSize];

 	while(1) {
 		// poll for card
 		MF_SNR();
-		cardPresent = getResponse();
-		delay(cardTimeout);
-		pollCounter += 1;
-		if(!getResponse()) {
-			Serial.println("Card not detected.");
-			return 0;
+		if(!getResponse(A)) {
+			delay(cardTimeout);
+			if(!getResponse(A)) {
+				Serial.println("Card not detected.");
+				return 0;
+			}
 		}

 		// read signal state
@@ -277,7 +277,7 @@
 			// check for OFF signal aka falling edge
 			else if(previousState == HIGH && signalState == LOW) {
 				// calculate elapsed time
-				endTime = (millis() - startTime)/1000 - (2 * pollCounter);
+				endTime = (millis() - startTime)/1000;
 				if(endTime != 0) {
 					Serial.print("Elapsed time: ");
 					Serial.println(endTime);


Initialize servos, properly?

Initialize servos, properly?

--- src/arbotix_sketch/arbotix_sketch.ino
+++ src/arbotix_sketch/arbotix_sketch.ino
@@ -25,6 +25,8 @@
 void setup()
 {
   Serial.begin(9600);
+
+  ax12Init(1000000);

   SetPosition(PORT_SERVO, 90 * ANGLE_CONVERSION);
   SetPosition(STBD_SERVO, 90 * ANGLE_CONVERSION);


Refactor: sort order etc.

Refactor: sort order etc.

--- ptw-wheel.ino
+++ ptw-wheel.ino
@@ -3,17 +3,17 @@

 // Arduino Nano v2.x, v3.x

-// ----------------
+// debug mode and pixels settings :::::::::
 // LEDのテスト用に200個のLEDをレインボー表示させるモードにするフラグ
 // ここをtrueにするときは、その下のTOTAL_PIXELSも200にして、その後のTOTAL_PIXELSの定義をコメントアウトしておくこと
 bool debug = false;
-// #define TOTAL_PIXELS 200 // for debug mode
-// ----------------
-
-// #define TOTAL_PIXELS 72 // 子供用バスケ（黃）A
-// #define TOTAL_PIXELS 85 // 子供用スポーツ（青）B
+
+//#define TOTAL_PIXELS 200 // for debug mode
+
+//#define TOTAL_PIXELS 72 // 子供用バスケ（黃）A
+//#define TOTAL_PIXELS 85 // 子供用スポーツ（青）B
 #define TOTAL_PIXELS 99 // 大人用 C,D,E
-// #define TOTAL_PIXELS 94 // 大人用 F
+//#define TOTAL_PIXELS 94 // 大人用 F

 // common settings :::::::::


COH-80: WIP

COH-80: WIP

--- Arduino/COHEAT2015/20160316-COHEAT-M1/COHEAT-M1/COHEAT-M1.ino
+++ Arduino/COHEAT2015/20160316-COHEAT-M1/COHEAT-M1/COHEAT-M1.ino
@@ -368,26 +368,29 @@
     return(PrimaryRadio.sendRaw(txbuf, bodylen, 0, OTRadioLink::OTRadioLink::TXmax));
     }
 #else
-    uint8_t key[16];
-    if(!OTV0P2BASE::getPrimaryBuilding16ByteSecretKey(key))
-      {
-      OTV0P2BASE::serialPrintlnAndFlush("!TX key");
-      return(false); // Failed.
-      }
-    const OTRadioLink::SimpleSecureFrame32or0BodyTXBase::fixed32BTextSize12BNonce16BTagSimpleEnc_ptr_t e = OTAESGCM::fixed32BTextSize12BNonce16BTagSimpleEnc_DEFAULT_STATELESS;
-    const uint8_t txIDLen = OTRadioLink::ENC_BODY_DEFAULT_ID_BYTES;
-    uint8_t buf[OTRadioLink::SimpleSecureFrame32or0BodyTXBase::generateSecureBeaconMaxBufSize];
-    const uint8_t bodylen = secureTXState.generateSecureBeaconRawForTX(buf, sizeof(buf), 2, e, NULL, key);
-    // ASSUME FRAMED CHANNEL 0 (but could check with config isUnframed flag).
-    // When sending on a channel with framing, do not explicitly send the frame length byte.
-    // DO NOT attempt to send if construction of the secure frame failed;
-    // doing so may reuse IVs and destroy the cipher security.
-    const bool success = (0 != bodylen) && PrimaryRadio.sendRaw(buf+1, bodylen-1);
+  uint8_t key[16];
+  if(!OTV0P2BASE::getPrimaryBuilding16ByteSecretKey(key))
+    {
+    OTV0P2BASE::serialPrintlnAndFlush("!TX key");
+    return(false); // Failed.
+    }
+  const OTRadioLink::SimpleSecureFrame32or0BodyTXBase::fixed32BTextSize12BNonce16BTagSimpleEnc_ptr_t e = OTAESGCM::fixed32BTextSize12BNonce16BTagSimpleEnc_DEFAULT_STATELESS;
+  const uint8_t txIDLen = OTRadioLink::ENC_BODY_DEFAULT_ID_BYTES;
+  uint8_t buf[OTRadioLink::SimpleSecureFrame32or0BodyTXBase::generateSecureBeaconMaxBufSize];
+  const uint8_t bodylen = secureTXState.generateSecureBeaconRawForTX(buf, sizeof(buf), 2, e, NULL, key);
+  // ASSUME FRAMED CHANNEL 0 (but could check with config isUnframed flag).
+  // When sending on a channel with framing, do not explicitly send the frame length byte.
+  // DO NOT attempt to send if construction of the secure frame failed;
+  // doing so may reuse IVs and destroy the cipher security.
+  const bool success = (0 != bodylen) && PrimaryRadio.sendRaw(buf+1, bodylen-1);
 #if 1 && defined(DEBUG)
-    if(!success) { OTV0P2BASE::serialPrintlnAndFlush("!TX"); }
-#endif
+  if(!success) { OTV0P2BASE::serialPrintlnAndFlush("!TX"); }
+  else { OTV0P2BASE::serialPrintlnAndFlush("TX alert"); }
+#endif
+  if(success) { return(true); } // Done!
 #endif // ENABLE_OTSECUREFRAME_ENCODING_SUPPORT
-  return(false); // Failed.
+  // FAILED if fallen through to here.
+  return(false);
   }
 #endif


refactor handleMemoryButtons

refactor handleMemoryButtons

--- vfobox.ino
+++ vfobox.ino
@@ -66,11 +66,9 @@
 long lastClick = 0;
 long lastBlink = 0;
 long lastStatus = 0;
-long last_mem[NUMBER_MEM_BUTTONS];

 boolean blinkState = false;
 boolean statusDisplayed = false;
-boolean mem_armed[NUMBER_MEM_BUTTONS];

 int eeAddressStart = 0;
 int threshold = 0;
@@ -188,101 +186,13 @@
   }
 }

-void setup() {
-  lcd.begin(16,2);
-  strcpy(statusLine,"5R8SV SIG GEN");
-  update_status();
-
-  // Set up DDS
-  pinMode(FQ_UD, OUTPUT);
-  pinMode(W_CLK, OUTPUT);
-  pinMode(DATAPIN, OUTPUT);
-  pinMode(RESET, OUTPUT);
-
-
-  // Set up Rotary Encoder
-  pinMode(A_PIN, INPUT_PULLUP);
-  pinMode(B_PIN, INPUT_PULLUP);
-  attachInterrupt(0, evaluateRotary, CHANGE);
-  attachInterrupt(1, evaluateRotary, CHANGE);
-  pinMode(RotEncSwPin, INPUT_PULLUP);
-
-  // Set up Output Monitoring
-  pinMode(WARN_LED, OUTPUT);
-  digitalWrite(WARN_LED, LOW);
-  analogReference(INTERNAL);
-  threshold = 1023L * THRESHOLD_VOLTAGE / 1100;
-
-  // Set up memory buttons
-  for (int buttons=0; buttons < NUMBER_MEM_BUTTONS; buttons++) {
-    mem_armed[buttons] = false;
-    last_mem[buttons] = 0;
-    pinMode(MEM_BUTTON_START_PIN + buttons,INPUT_PULLUP);
-  }
-
- // start on M1 freq
-  EEPROM.get(eeAddressStart,freq);
-  if(freq < bandStart || freq > bandEnd) {
-    freq = bandInit;
-    EEPROM.put(eeAddressStart,freq);
-  }
-
- // start up the DDS...
-  pulseHigh(RESET);
-  pulseHigh(W_CLK);
-  pulseHigh(FQ_UD);
-  // start the oscillator...
-  send_frequency(freq);
-  display_frequency(freq);
-}
-
-void loop() {
-  int freqCursorPosition = 4;
-
-  // change freq dependent on rotary encoder spin direction
-  if(spinDirection != 0) {
-    if (spinDirection == 1) {
-      freq=constrain(freq-freqDelta,bandStart,bandEnd);
-    } else {
-      freq=constrain(freq+freqDelta,bandStart,bandEnd);
-    }
-    spinDirection = 0;
-    display_frequency(freq); // push the frequency to LCD display
-    send_frequency(freq);  // set the DDS to the new frequency
-  }
-
-  // check for the click of the rotary encoder
-  if (!digitalRead(RotEncSwPin) && millis() - lastClick > 200) { // push button debounce
-    // if user clicks rotary encoder, change the size of the increment
-    if (freqDelta == 10) {
-      freqDelta = 1000000;
-    } else {
-      freqDelta /= 10;
-    }
-    lastClick = millis();
-  }
-
-  //blink the cursor to show selected frequency resolution
-  if (millis() - lastBlink > 300) {
-    freqCursorPosition = 8;
-    for (long tempDelta = 10; tempDelta/freqDelta != 1; tempDelta *= 10) {
-      freqCursorPosition--;
-      if (freqCursorPosition == 2 || freqCursorPosition == 6) {  //hop the punctuation
-        freqCursorPosition--;
-      }
-    }
-    lcd.setCursor(freqCursorPosition,0);
-    if(blinkState) {
-      lcd.noBlink();
-    } else {
-      lcd.blink();
-    }
-    blinkState = !blinkState;
-    lastBlink = millis();
-  }
-
-  // handle memory buttons
-  for (int buttons = 0; buttons < NUMBER_MEM_BUTTONS; buttons++) {
+//Handle Memory Button Pushes
+void handleMemoryButtons() {
+
+  static boolean mem_armed[NUMBER_MEM_BUTTONS];
+  static long last_mem[NUMBER_MEM_BUTTONS];
+
+  for (int buttons = 0; buttons < NUMBER_MEM_BUTTONS; buttons++) {
     if(!mem_armed[buttons] && !digitalRead(MEM_BUTTON_START_PIN+buttons) && millis() - last_mem[buttons] > 50) {
       last_mem[buttons] = millis();
       mem_armed[buttons] = true;
@@ -312,7 +222,101 @@
       last_mem[buttons] = millis();
     }
   }
-
+}
+
+void setup() {
+  lcd.begin(16,2);
+  strcpy(statusLine,"5R8SV SIG GEN");
+  update_status();
+
+  // Set up DDS
+  pinMode(FQ_UD, OUTPUT);
+  pinMode(W_CLK, OUTPUT);
+  pinMode(DATAPIN, OUTPUT);
+  pinMode(RESET, OUTPUT);
+
+
+  // Set up Rotary Encoder
+  pinMode(A_PIN, INPUT_PULLUP);
+  pinMode(B_PIN, INPUT_PULLUP);
+  attachInterrupt(0, evaluateRotary, CHANGE);
+  attachInterrupt(1, evaluateRotary, CHANGE);
+  pinMode(RotEncSwPin, INPUT_PULLUP);
+
+  // Set up Output Monitoring
+  pinMode(WARN_LED, OUTPUT);
+  digitalWrite(WARN_LED, LOW);
+  analogReference(INTERNAL);
+  threshold = 1023L * THRESHOLD_VOLTAGE / 1100;
+
+  // Set up memory buttons
+  for (int buttons=0; buttons < NUMBER_MEM_BUTTONS; buttons++) {
+    pinMode(MEM_BUTTON_START_PIN + buttons,INPUT_PULLUP);
+  }
+
+ // start on M1 freq
+  EEPROM.get(eeAddressStart,freq);
+  if(freq < bandStart || freq > bandEnd) {
+    freq = bandInit;
+    EEPROM.put(eeAddressStart,freq);
+  }
+
+ // start up the DDS...
+  pulseHigh(RESET);
+  pulseHigh(W_CLK);
+  pulseHigh(FQ_UD);
+  // start the oscillator...
+  send_frequency(freq);
+  display_frequency(freq);
+}
+
+void loop() {
+  int freqCursorPosition = 4;
+
+  // change freq dependent on rotary encoder spin direction
+  if(spinDirection != 0) {
+    if (spinDirection == 1) {
+      freq=constrain(freq-freqDelta,bandStart,bandEnd);
+    } else {
+      freq=constrain(freq+freqDelta,bandStart,bandEnd);
+    }
+    spinDirection = 0;
+    display_frequency(freq); // push the frequency to LCD display
+    send_frequency(freq);  // set the DDS to the new frequency
+  }
+
+  // check for the click of the rotary encoder
+  if (!digitalRead(RotEncSwPin) && millis() - lastClick > 200) { // push button debounce
+    // if user clicks rotary encoder, change the size of the increment
+    if (freqDelta == 10) {
+      freqDelta = 1000000;
+    } else {
+      freqDelta /= 10;
+    }
+    lastClick = millis();
+  }
+
+  //blink the cursor to show selected frequency resolution
+  if (millis() - lastBlink > 300) {
+    freqCursorPosition = 8;
+    for (long tempDelta = 10; tempDelta/freqDelta != 1; tempDelta *= 10) {
+      freqCursorPosition--;
+      if (freqCursorPosition == 2 || freqCursorPosition == 6) {  //hop the punctuation
+        freqCursorPosition--;
+      }
+    }
+    lcd.setCursor(freqCursorPosition,0);
+    if(blinkState) {
+      lcd.noBlink();
+    } else {
+      lcd.blink();
+    }
+    blinkState = !blinkState;
+    lastBlink = millis();
+  }
+
+
+  handleMemoryButtons();
   checkOutputLevel();
   wipeStaleStatus();
 }


code formatted /BB

code formatted /BB

--- datasafe.ino
+++ datasafe.ino
@@ -38,7 +38,7 @@
 NFCLib nfclib;

 char nfc_key[6] = {
-  0, 0, 0, 0, 0, 0 }; // the key buffer
+	0, 0, 0, 0, 0, 0 }; // the key buffer
 uint8_t nfc_key_count = 0;

@@ -75,11 +75,11 @@

 /**** messages ****/
 static const char* screen_message[] = {
-  "DataSave",
-  "v1.0",
-  "nfc card login",
-  "unlock the nfc card with your key!",
-  "put your nfc card on the nfc reader!"
+	"DataSave",
+	"v1.0",
+	"nfc card login",
+	"unlock the nfc card with your key!",
+	"put your nfc card on the nfc reader!"
 };

@@ -88,38 +88,38 @@
 /**** display prepare functions ****/

 void clearScreen() {
-  screen.clearScreen();
+	screen.clearScreen();
 }

 void reset() {
-  // reset all global variables
-  current_state = STATE_RESET;
-  //  last_key_press_ms = 0;
-  //  last_key = 0;
-  memset(nfc_key, 0, sizeof(nfc_key));
-  nfc_key_count = 0;
-
-  // show the splash screen
-  showSplashScreen();
-
-  // reset the sd card controller
-  // sd.setup();
-
-  // reset the touchscreen
-  uint16_t x, y;
-  uint8_t z;
-  while (!screen.getTouchScreen().bufferEmpty()) {
-    screen.getTouchScreen().readData(&x, &y, &z);
-    Serial.println(screen.getTouchScreen().bufferSize());
-  }
-  screen.getTouchScreen().writeRegister8(STMPE_INT_STA, 0xFF);
-
-  // setup nfc
-  nfclib.setupHost();
-
-  // show the nfc screen
-  showNFCKeyScreen();
+	// reset all global variables
+	current_state = STATE_RESET;
+	//  last_key_press_ms = 0;
+	//  last_key = 0;
+	memset(nfc_key, 0, sizeof(nfc_key));
+	nfc_key_count = 0;
+
+	// show the splash screen
+	showSplashScreen();
+
+	// reset the sd card controller
+	// sd.setup();
+
+	// reset the touchscreen
+	uint16_t x, y;
+	uint8_t z;
+	while (!screen.getTouchScreen().bufferEmpty()) {
+		screen.getTouchScreen().readData(&x, &y, &z);
+		Serial.println(screen.getTouchScreen().bufferSize());
+	}
+	screen.getTouchScreen().writeRegister8(STMPE_INT_STA, 0xFF);
+
+	// setup nfc
+	nfclib.setupHost();
+
+	// show the nfc screen
+	showNFCKeyScreen();
 }

@@ -128,49 +128,49 @@
 /**** show screen functions ****/

 void showSplashScreen() {
-  screen.fillScreen(ILI9341_BLACK);
-  screen.setCursor(BOXSIZE, BOXSIZE);
-  screen.setTextColor(ILI9341_RED);
-  screen.setTextSize(4);
-  screen.println(screen_message[0]);
-
-  screen.setCursor(BOXSIZE*3, BOXSIZE*3);
-  screen.setTextColor(ILI9341_WHITE);
-  screen.setTextSize(2);
-  screen.println(screen_message[1]);
+	screen.fillScreen(ILI9341_BLACK);
+	screen.setCursor(BOXSIZE, BOXSIZE);
+	screen.setTextColor(ILI9341_RED);
+	screen.setTextSize(4);
+	screen.println(screen_message[0]);
+
+	screen.setCursor(BOXSIZE*3, BOXSIZE*3);
+	screen.setTextColor(ILI9341_WHITE);
+	screen.setTextSize(2);
+	screen.println(screen_message[1]);
 }

 void showNFCKeyScreen() {
-  current_state = STATE_NFC_KEY_LOGIN;
-  clearScreen();
-  screen.writeTextToTop(screen_message[2]);
-  screen.writeTextToBottom(screen_message[3]);
-  screen.drawKeyboard();
+	current_state = STATE_NFC_KEY_LOGIN;
+	clearScreen();
+	screen.writeTextToTop(screen_message[2]);
+	screen.writeTextToBottom(screen_message[3]);
+	screen.drawKeyboard();
 }

 void showNFCCardScreen() {
-  current_state = STATE_NFC_CARD_LOGIN;
-  clearScreen();
-  screen.writeTextToTop(screen_message[2]);
-  screen.writeTextToBottom(screen_message[4]);
+	current_state = STATE_NFC_CARD_LOGIN;
+	clearScreen();
+	screen.writeTextToTop(screen_message[2]);
+	screen.writeTextToBottom(screen_message[4]);
 }

 void showDataScreen() {
-  current_state = STATE_SHOW_DATA;
-  screen.fillScreen(ILI9341_BLACK);
-  screen.setCursor(0, 0);
-  screen.setTextColor(ILI9341_WHITE);
-  screen.setTextSize(2);
-  screen.println("The data:");
-
-  screen.setCursor(BOXSIZE*2, BOXSIZE*2);
-  screen.println("MY SECRET DATA !!");
-
-  //  sd.showFile("test.txt");
-
-  delay(3000);
+	current_state = STATE_SHOW_DATA;
+	screen.fillScreen(ILI9341_BLACK);
+	screen.setCursor(0, 0);
+	screen.setTextColor(ILI9341_WHITE);
+	screen.setTextSize(2);
+	screen.println("The data:");
+
+	screen.setCursor(BOXSIZE*2, BOXSIZE*2);
+	screen.println("MY SECRET DATA !!");
+
+	//  sd.showFile("test.txt");
+
+	delay(3000);
 }

@@ -181,58 +181,58 @@
 /**** touchscreen action functions ****/

 void actOnTouchScreenInteraction(uint16_t x, uint16_t y, boolean keyboardOn) {
-  uint16_t millis_now = millis();
-  uint16_t millis_delta = millis_now - last_key_press_ms;
-  char c;
-
-  // check polling
-  if (millis_delta <= KEYBOARD_POLLING_MS) {
-    return;
-  }
-
-  // actions
-  actOnButtonPress(x, y);
-
-  if (keyboardOn) {
-    if ( nfc_key_count > 5) {
-      return;
-    }
-    c = screen.actOnKeyboardKeyPress(x, y);
-    if (c != 0) {
-      nfc_key[nfc_key_count] = c;
-      nfc_key_count++;
-
-      char dest[12];
-      strcpy(dest, "key: ");
-      strcat(dest, nfc_key);
-      dest[11] = '\0';
-      screen.writeTextToBottom(dest);
-
-
-      // show the nfc screen when password is fullfilled
-      if (nfc_key_count > 5) {
-        showNFCCardScreen();
-      }
-
-    }
-  }
-
-
-  // set last key press for polling
-  last_key_press_ms = millis_now;
+	uint16_t millis_now = millis();
+	uint16_t millis_delta = millis_now - last_key_press_ms;
+	char c;
+
+	// check polling
+	if (millis_delta <= KEYBOARD_POLLING_MS) {
+		return;
+	}
+
+	// actions
+	actOnButtonPress(x, y);
+
+	if (keyboardOn) {
+		if ( nfc_key_count > 5) {
+			return;
+		}
+		c = screen.actOnKeyboardKeyPress(x, y);
+		if (c != 0) {
+			nfc_key[nfc_key_count] = c;
+			nfc_key_count++;
+
+			char dest[12];
+			strcpy(dest, "key: ");
+			strcat(dest, nfc_key);
+			dest[11] = '\0';
+			screen.writeTextToBottom(dest);
+
+
+			// show the nfc screen when password is fullfilled
+			if (nfc_key_count > 5) {
+				showNFCCardScreen();
+			}
+
+		}
+	}
+
+
+	// set last key press for polling
+	last_key_press_ms = millis_now;
 }

 void actOnButtonPress(uint16_t x, uint16_t y) {
-  if (SCREEN_BUTTON_MINY + SCREEN_TEXT_PADDING*2.7 >= y && y <= SCREEN_BUTTON_MINY + SCREEN_TEXT_PADDING*2.7 + SCREEN_BUTTON_SIZE * 2) {
-    if (SCREEN_TEXT_PADDING*3 >= x && x <= SCREEN_TEXT_PADDING*3 + SCREEN_BUTTON_SIZE * 2) {
-	  Serial.print("Button pressed: ");
-	  Serial.print(x);
-	  Serial.print(" / ");
-	  Serial.print(y);
-	  Serial.println("");
-      reset();
-    }
-  }
+	if (SCREEN_BUTTON_MINY + SCREEN_TEXT_PADDING*2.7 >= y && y <= SCREEN_BUTTON_MINY + SCREEN_TEXT_PADDING*2.7 + SCREEN_BUTTON_SIZE * 2) {
+		if (SCREEN_TEXT_PADDING*3 >= x && x <= SCREEN_TEXT_PADDING*3 + SCREEN_BUTTON_SIZE * 2) {
+			Serial.print("Button pressed: ");
+			Serial.print(x);
+			Serial.print(" / ");
+			Serial.print(y);
+			Serial.println("");
+			reset();
+		}
+	}
 }

@@ -241,60 +241,60 @@
 /**** state functions ****/

 void nextState() {
-  current_state++;
-  if (current_state == STATE_END) {
-    current_state = STATE_RESET;
-  }
+	current_state++;
+	if (current_state == STATE_END) {
+		current_state = STATE_RESET;
+	}
 }

 void doStateReset() {
-  // show the splash screen
-  reset();
+	// show the splash screen
+	reset();
 }

 void doStateNfcKeyLogin() {
-  // wait for the touch and show it
-  if (screen.getTouchScreen().bufferEmpty()) {
-    return;
-  }
-  if (! screen.getTouchScreen().touched()) {
-    return;
-  }
-
-
-  // Retrieve a point
-  TS_Point p = screen.touchscreenGetPoint();
-  /*
+	// wait for the touch and show it
+	if (screen.getTouchScreen().bufferEmpty()) {
+		return;
+	}
+	if (! screen.getTouchScreen().touched()) {
+		return;
+	}
+
+
+	// Retrieve a point
+	TS_Point p = screen.touchscreenGetPoint();
+	/*
     if (p.z == 0) {
-   return;
-   }
-   */
-
-  // act on touchscreen interaction
-  actOnTouchScreenInteraction(p.x, p.y, true);
+	 return;
+	 }
+	 */
+
+	// act on touchscreen interaction
+	actOnTouchScreenInteraction(p.x, p.y, true);
 }

 void doStateNfcCardLogin() {

-  // read the nfc card
-  //uint8_t success;
-  uint8_t uid[] = {
-    0, 0, 0, 0, 0, 0, 0   };                    // Buffer to store the returned UID
-  uint8_t uidLength = nfclib.initTarget(&*uid);               // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
-  uidLength = nfclib.printTarget();
-
-  // show the data
-  showDataScreen();
-
-  // reset everything()
-  reset();
+	// read the nfc card
+	//uint8_t success;
+	uint8_t uid[] = {
+		0, 0, 0, 0, 0, 0, 0   	};                    // Buffer to store the returned UID
+	uint8_t uidLength = nfclib.initTarget(&*uid);               // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
+	uidLength = nfclib.printTarget();
+
+	// show the data
+	showDataScreen();
+
+	// reset everything()
+	reset();
 }

 void doStateShowData() {
-  // show the data
-  showDataScreen();
-
-  nextState();
+	// show the data
+	showDataScreen();
+
+	nextState();
 }

@@ -303,36 +303,37 @@
 /**** arduino default functions ****/

 void setup(void) {
-  // setup the screen
-  screen.setup();
+	// setup the screen
+	screen.setup();
 }

 void loop()
 {
-  // working with the state pattern because we have different screens (states)
-  switch (current_state) {
-  case STATE_RESET:
-    doStateReset();
-    break;
-  case STATE_NFC_KEY_LOGIN:
-    doStateNfcKeyLogin();
-    break;
-  case STATE_NFC_CARD_LOGIN:
-    doStateNfcCardLogin();
-    break;
-  case STATE_SHOW_DATA:
-    doStateShowData();
-    break;
-  case STATE_END:
-    nextState();
-    break;
-  default:
-    doStateReset();
-    break;
-  }
-
-}
-
-
-
-
+	// working with the state pattern because we have different screens (states)
+	switch (current_state) {
+	case STATE_RESET:
+		doStateReset();
+		break;
+	case STATE_NFC_KEY_LOGIN:
+		doStateNfcKeyLogin();
+		break;
+	case STATE_NFC_CARD_LOGIN:
+		doStateNfcCardLogin();
+		break;
+	case STATE_SHOW_DATA:
+		doStateShowData();
+		break;
+	case STATE_END:
+		nextState();
+		break;
+	default:
+		doStateReset();
+		break;
+	}
+
+}
+
+
+
+
+


Update Arduino_8_Zone_Irrigation_Controller.ino

updated version to 3.1.1

--- 8_Zone_Controller/Arduino_8_Zone_Irrigation_Controller.ino
+++ 8_Zone_Controller/Arduino_8_Zone_Irrigation_Controller.ino
@@ -2,7 +2,7 @@
 /**
 *
  ****************************************************************************************************************************
- * Irrigation Controller v3.1
+ * Irrigation Controller v3.1.1
  * Simple, elegant irrigation controller that takes advantage of the cloud and SmartThings ecosystem
  * Arduino UNO with SmartThings Shield  and an 8 Relay Module
  * Works by receiving irrigation run times from the Cloud and then builds a queue to execute


show test counter according to output mode, avoids T84 issue, see #460

--- examples/RF12/RF12demo/RF12demo.ino
+++ examples/RF12/RF12demo/RF12demo.ino
@@ -421,7 +421,7 @@
             for (byte i = 0; i < RF12_MAXDATA; ++i)
                 stack[i] = i + testCounter;
             showString(PSTR("test "));
-            Serial.println(testCounter); // first byte in test buffer
+            showByte(testCounter); // first byte in test buffer
             ++testCounter;
             break;


add sleep mode command

add sleep mode command

--- examples/RF12/RF12demo/RF12demo.ino
+++ examples/RF12/RF12demo/RF12demo.ino
@@ -539,6 +539,7 @@
     "  ...,<nn> s - send data packet to node <nn>, no ack" "\n"
     "  <n> l      - turn activity LED on PB1 on or off" "\n"
     "  <n> q      - set quiet mode (1 = don't report bad packets)" "\n"
+    "  123 z      - total power down, needs a reset to start up again" "\n"
     "Remote control commands:" "\n"
     "  <hchi>,<hclo>,<addr>,<cmd> f     - FS20 command (868 MHz)" "\n"
     "  <addr>,<dev>,<on> k              - KAKU command (433 MHz)" "\n"
@@ -667,6 +668,14 @@
             case 'q': // turn quiet mode on or off (don't report bad packets)
                 quiet = value;
                 break;
+            case 'z': // put the ATmega in ultra-low power mode (reset needed)
+                if (value == 123) {
+                    delay(10);
+                    rf12_sleep(RF12_SLEEP);
+                    cli();
+                    Sleepy::powerDown();
+                }
+                break;
         }
         value = top = 0;
         memset(stack, 0, sizeof stack);


Refactor to be used as callable library function:  pinmux_report(pinno, buffer, pinName);

--- SAMD_pins.ino
+++ SAMD_pins.ino
@@ -14,10 +14,18 @@
 /*
  * For Sparkfun SAMD21 boards, use SerialUSB device
  */
+
 #define mySerial SerialUSB
-#define PRINT(...) mySerial.print(__VA_ARGS__)
-#define PRINTLN(...) mySerial.println(__VA_ARGS__)
-
+#if 0
+#define PRINTS(...) mySerial.print(__VA_ARGS__)
+#define PRINTN(...) mySerial.print(__VA_ARGS__)
+#else
+#define PRINTS(...) print_s(__VA_ARGS__)
+#define PRINTN(...) print_n2(__VA_ARGS__)
+#endif
+
+static char buffer[80];
+static char *bufp;

 /*
  * Standard Arduio setup() function.
@@ -27,8 +35,8 @@
   mySerial.begin(9600);
   while (!mySerial)
     ;
-  PRINTLN("SAMD Pin State Report");
-  PRINTLN();
+  mySerial.println("SAMD Pin State Report");
+  mySerial.println();

   // Set some pins up doing something different, so that the display will be
   //   more ... interesting.
@@ -44,40 +52,16 @@
 }

 void loop() {
+  pinmux_report(PIN_LED_RXL, buffer, "RXL");
+  mySerial.println(buffer);
   for (int pin = 0; pin < PINS_COUNT; pin++) {  // For all defined pins
-    if (print_pinno(pin)) {  // Does pin exist?
-
-      int bitno = g_APinDescription[pin].ulPin;
-      PortGroup *port = digitalPinToPort(pin);
-      int pmuxval;
-
-      print_portname(pin);
-
-      if (port->PINCFG[bitno].bit.PMUXEN) {  // Is pinmux enabled?
-        // If pinmux is enabled, further report it's value
-        if (bitno & 1) {
-          // Odd pin numbers
-          pmuxval = port->PMUX[bitno / 2].bit.PMUXO;
-        } else {
-          pmuxval = port->PMUX[bitno / 2].bit.PMUXE;
-        }
-	print_pinmux(pin, pmuxval);
-      } else {
-        // Pinmux not enabled - port is GPIO
-        PRINT("GPIO ");
-        if (port->DIR.reg & (1 << bitno)) { // Decode pinmode (direction.)
-          PRINT("O");
-        } else {
-          PRINT("I");
-        }
-      } // Pinmux or GPIO
-    } // Pin existance
-    PRINTLN();
+    pinmux_report(pin, buffer, 0);
+    mySerial.println(buffer);
   } // "pin" for loop

   while (mySerial.read() < 0)
     ;  // wait for character to run again.
-  PRINTLN("\nRunning again!\n");
+  mySerial.println("\nRunning again!\n");
 }

@@ -85,21 +69,23 @@
  * Print an Arduino pin number, and it's "name."
  * (in particular, check for the Analog pins and label them)
  */
-boolean print_pinno(int i)
+static boolean print_pinno(int i, char *name)
 {
   int pintype = g_APinDescription[i].ulPinType;
   if (pintype == PIO_NOT_A_PIN) {
     return false;
   }
-  PRINT(i);
-  if (i < 10)
-    PRINT(" ");
-  if (pintype == PIO_ANALOG) {  // try to detect and renumber Analog pins.
-    PRINT(" (A");
-    PRINT(i - PIN_A0);
-    PRINT(") ");
+  PRINTN(i);
+  if (name && *name) {
+    PRINTS(" [");
+    PRINTS(name);
+    PRINTS("] ");
+  } else if (pintype == PIO_ANALOG) {  // try to detect and renumber Analog pins.
+    PRINTS(" (A");
+    PRINTN(i - PIN_A0);
+    PRINTS(") ");
   } else {
-    PRINT("      ");
+    PRINTS("      ");
   }
   return true;
 }
@@ -116,7 +102,7 @@
  * can apply to one of six different SERCOM modules on a SAMD21, and an ANALOG
  * PMUX value could be ADC, REF, DAC, or TouchController.)
  */
-void (*PMUX_decode_func[8])(int, int) = {
+static void (*PMUX_decode_func[8])(int, int) = {
   decode_EIC,
   decode_ADC,
   decode_SERCOM,
@@ -129,27 +115,26 @@

 /*
  * Print the raw PMUX value
- * Call via the function table for name and
-details.
- */
-void print_pinmux(int pin, int pmuxval)
-{
-  PRINT("PMUX");
-  PRINT("(");
-  PRINT(pmuxval);
-  PRINT(") ");
+ * Call via the function table for name and details.
+ */
+static void print_pinmux(int pin, int pmuxval)
+{
+  PRINTS("PMUX");
+  PRINTS("(");
+  PRINTN(pmuxval);
+  PRINTS(") ");
   if (pmuxval < ARRAYSIZE(PMUX_decode_func)) {
     PMUX_decode_func[pmuxval](pin, pmuxval);
   }
 }

-char *nullstr = "";
+static char *nullstr = "";

 /*
  *   Pin multiplexer value names (PMUXn.PMUXE/O)
  */
-const char *pinmux_names[8] = {
+static const char *pinmux_names[8] = {
   "EIC",   // "A": External Interrupts
   "ADC",   // "B": REF, ADC, AC, PTC, DAC
   "SERCOM",   /* "C": SerCom */
@@ -161,14 +146,14 @@
 };

-void decode_EIC(int pin, int pmux)
-{
-  PRINT(pinmux_names[pmux]);   // default action
-}
-
-void decode_ADC(int pin, int pmux)
-{
-  PRINT(pinmux_names[pmux]);   // default action
+static void decode_EIC(int pin, int pmux)
+{
+  PRINTS(pinmux_names[pmux]);   // default action
+}
+
+static void decode_ADC(int pin, int pmux)
+{
+  PRINTS(pinmux_names[pmux]);   // default action
 }

 /*
@@ -179,54 +164,54 @@
  * between "pad" and actual function is controlled by fields in the CTRLA reg
  */

-const char *pin_to_SERCOMA_info[] = {
+static const char *pin_to_SERCOMA_info[] = {
   /* PA00 */ nullstr,
   /* PA01 */ nullstr,
   /* PA02 */ nullstr,
-/* PA03 */ nullstr,
-/* PA04 */ nullstr,
-/* PA05 */ nullstr,
-/* PA06 */ nullstr,
-/* PA07 */ nullstr,
-/* PA08 */ "0 P0",
-/* PA09 */ "0 P1",
-/* PA10 */ "0 P2",
-/* PA11 */ "0 P3",
-/* PA12 */ "2 P0",
-/* PA13 */ "2 P1",
-/* PA14 */ "2 P2",
-/* PA15 */ "2 P3",
-/* PA16 */ "1 P0",
-/* PA17 */ "1 P1",
-/* PA18 */ "1 P2",
-/* PA19 */ "1 P3",
-/* PA20 */ "5 P2",
-/* PA21 */ "5 P3",
-/* PA22 */ "3 P0",
-/* PA23 */ "3 P1",
-/* PA24 */ "3 P2",
-/* PA25 */ "3 P3"
-};
-
-const char *pin_to_SERCOMB_info[] = {
-/* PB00 */ nullstr,
-/* PB01 */ nullstr,
-/* PB02 */ nullstr,
-/* PB03 */ nullstr,
-/* PB04 */ nullstr,
-/* PB05 */ nullstr,
-/* PB06 */ nullstr,
-/* PB07 */ nullstr,
-/* PB08 */ nullstr,
-/* PB09 */ nullstr,
-/* PB10 */ nullstr,
-/* PB11 */ nullstr,
-/* PB12 */ "4 P0",
-/* PB13 */ "4 P1",
-/* PB14 */ "4 P2",
-/* PB15 */ "4 P3",
-/* PB16 */ "5 P0",
-/* PB17 */ "5 P1"
+  /* PA03 */ nullstr,
+  /* PA04 */ nullstr,
+  /* PA05 */ nullstr,
+  /* PA06 */ nullstr,
+  /* PA07 */ nullstr,
+  /* PA08 */ "0 P0",
+  /* PA09 */ "0 P1",
+  /* PA10 */ "0 P2",
+  /* PA11 */ "0 P3",
+  /* PA12 */ "2 P0",
+  /* PA13 */ "2 P1",
+  /* PA14 */ "2 P2",
+  /* PA15 */ "2 P3",
+  /* PA16 */ "1 P0",
+  /* PA17 */ "1 P1",
+  /* PA18 */ "1 P2",
+  /* PA19 */ "1 P3",
+  /* PA20 */ "5 P2",
+  /* PA21 */ "5 P3",
+  /* PA22 */ "3 P0",
+  /* PA23 */ "3 P1",
+  /* PA24 */ "3 P2",
+  /* PA25 */ "3 P3"
+};
+
+static const char *pin_to_SERCOMB_info[] = {
+  /* PB00 */ nullstr,
+  /* PB01 */ nullstr,
+  /* PB02 */ nullstr,
+  /* PB03 */ nullstr,
+  /* PB04 */ nullstr,
+  /* PB05 */ nullstr,
+  /* PB06 */ nullstr,
+  /* PB07 */ nullstr,
+  /* PB08 */ nullstr,
+  /* PB09 */ nullstr,
+  /* PB10 */ nullstr,
+  /* PB11 */ nullstr,
+  /* PB12 */ "4 P0",
+  /* PB13 */ "4 P1",
+  /* PB14 */ "4 P2",
+  /* PB15 */ "4 P3",
+  /* PB16 */ "5 P0",
+  /* PB17 */ "5 P1"
 };

 /*
@@ -235,12 +220,12 @@
  * have more than others.
  */

-Sercom * sercomports[] = SERCOM_INSTS;
+static Sercom * sercomports[] = SERCOM_INSTS;

 /*
  * Sercom configuration type indexed by CTRLA.MODE
  */
-char *sercomtype_names[] = {
+static char *sercomtype_names[] = {
   "(USART)",
   "(UART)",
   "(SPI Slave)",
@@ -250,17 +235,17 @@
 };

-void decode_SERCOM(int pin, int pmux)
+static void decode_SERCOM(int pin, int pmux)
 {
   PortGroup *port = digitalPinToPort(pin);
   int bitno = g_APinDescription[pin].ulPin;
   int sercomno, sercomtype;
   Sercom *s;

-  PRINT(pinmux_names[pmux]);
+  PRINTS(pinmux_names[pmux]);
   if (port == &PORT->Group[0]) {
     if (bitno < ARRAYSIZE(pin_to_SERCOMA_info)) {
-      PRINT(pin_to_SERCOMA_info[bitno]);
+      PRINTS(pin_to_SERCOMA_info[bitno]);
       /*
        * Get sercom number from the string.  (Ugly, but saves space.)
        */
@@ -269,7 +254,7 @@
   }
   if (port == &PORT->Group[1]) {
     if (bitno < ARRAYSIZE(pin_to_SERCOMB_info)) {
-      PRINT(pin_to_SERCOMB_info[bitno]);
+      PRINTS(pin_to_SERCOMB_info[bitno]);
       /*
        * Get sercom number from the string.  (Ugly, but saves space.)
        */
@@ -280,7 +265,7 @@
     s = sercomports[sercomno];
     sercomtype = s->USART.CTRLA.bit.MODE;
     if (sercomtype < ARRAYSIZE(sercomtype_names)) {
-      PRINT(sercomtype_names[sercomtype]);
+      PRINTS(sercomtype_names[sercomtype]);
     }
   }
 }
@@ -289,87 +274,87 @@
  * Tables for SercomALT PMUX value
  */

-const char *pin_to_SERCOMALTA_info[] = {
-/* PA00 */ "1 P0",
-/* PA01 */ "1 P1",
-/* PA02 */ nullstr,
-/* PA03 */ nullstr,
-/* PA04 */ "0 P0",
-/* PA05 */ "0 P1",
-/* PA06 */ "0 P2",
-/* PA07 */ "0 P3",
-/* PA08 */ "2 P0",
-/* PA09 */ "2 P1",
-/* PA10 */ "2 P2",
-/* PA11 */ "2 P3",
-/* PA12 */ "4 P0",
-/* PA13 */ "4 P1",
-/* PA14 */ "4 P2",
-/* PA15 */ "4 P3",
-/* PA16 */ "3 P0",
-/* PA17 */ "3 P1",
-/* PA18 */ "3 P2",
-/* PA19 */ "3 P3",
-/* PA20 */ "3 P2",
-/* PA21 */ "3 P3",
-/* PA22 */ "5 P0",
-/* PA23 */ "5 P1",
-/* PA24 */ "5 P2",
-/* PA25 */ "5 P3",
-/* PA26 */ nullstr,
-/* PA27 */ nullstr,
-/* PA28 */ nullstr,
-/* PA29 */ nullstr,
-/* PA30 */ "1 P2",
-/* PA31 */ "1 P3",
-};
-
-const char *pin_to_SERCOMALTB_info[] = {
-/* PB00 */ "5 P2",
-/* PB01 */ "5 P3",
-/* PB02 */ "5 P0",
-/* PB03 */ "5 P1",
-/* PB04 */ nullstr,
-/* PB05 */ nullstr,
-/* PB06 */ nullstr,
-/* PB07 */ nullstr,
-/* PB08 */ "4 P0",
-/* PB09 */ "4 P1",
-/* PB10 */ "4 P2",
-/* PB11 */ "4 P3",
-/* PB12 */ nullstr,
-/* PB13 */ nullstr,
-/* PB14 */ nullstr,
-/* PB15 */ nullstr,
-/* PB16 */ nullstr,
-/* PB17 */ nullstr,
-/* PB18 */ nullstr,
-/* PB19 */ nullstr,
-/* PB20 */ nullstr,
-/* PB21 */ nullstr,
-/* PB22 */ "5 P2",
-/* PB23 */ "5 P3",
-/* PB24 */ nullstr,
-/* PB25 */ nullstr,
-/* PB26 */ nullstr,
-/* PB27 */ nullstr,
-/* PB28 */ nullstr,
-/* PB29 */ nullstr,
-/* PB30 */ "5 P0",
-/* PB31 */ "5 P1"
-};
-
-void decode_SERCOMA(int pin, int pmux)
+static const char *pin_to_SERCOMALTA_info[] = {
+  /* PA00 */ "1 P0",
+  /* PA01 */ "1 P1",
+  /* PA02 */ nullstr,
+  /* PA03 */ nullstr,
+  /* PA04 */ "0 P0",
+  /* PA05 */ "0 P1",
+  /* PA06 */ "0 P2",
+  /* PA07 */ "0 P3",
+  /* PA08 */ "2 P0",
+  /* PA09 */ "2 P1",
+  /* PA10 */ "2 P2",
+  /* PA11 */ "2 P3",
+  /* PA12 */ "4 P0",
+  /* PA13 */ "4 P1",
+  /* PA14 */ "4 P2",
+  /* PA15 */ "4 P3",
+  /* PA16 */ "3 P0",
+  /* PA17 */ "3 P1",
+  /* PA18 */ "3 P2",
+  /* PA19 */ "3 P3",
+  /* PA20 */ "3 P2",
+  /* PA21 */ "3 P3",
+  /* PA22 */ "5 P0",
+  /* PA23 */ "5 P1",
+  /* PA24 */ "5 P2",
+  /* PA25 */ "5 P3",
+  /* PA26 */ nullstr,
+  /* PA27 */ nullstr,
+  /* PA28 */ nullstr,
+  /* PA29 */ nullstr,
+  /* PA30 */ "1 P2",
+  /* PA31 */ "1 P3",
+};
+
+static const char *pin_to_SERCOMALTB_info[] = {
+  /* PB00 */ "5 P2",
+  /* PB01 */ "5 P3",
+  /* PB02 */ "5 P0",
+  /* PB03 */ "5 P1",
+  /* PB04 */ nullstr,
+  /* PB05 */ nullstr,
+  /* PB06 */ nullstr,
+  /* PB07 */ nullstr,
+  /* PB08 */ "4 P0",
+  /* PB09 */ "4 P1",
+  /* PB10 */ "4 P2",
+  /* PB11 */ "4 P3",
+  /* PB12 */ nullstr,
+  /* PB13 */ nullstr,
+  /* PB14 */ nullstr,
+  /* PB15 */ nullstr,
+  /* PB16 */ nullstr,
+  /* PB17 */ nullstr,
+  /* PB18 */ nullstr,
+  /* PB19 */ nullstr,
+  /* PB20 */ nullstr,
+  /* PB21 */ nullstr,
+  /* PB22 */ "5 P2",
+  /* PB23 */ "5 P3",
+  /* PB24 */ nullstr,
+  /* PB25 */ nullstr,
+  /* PB26 */ nullstr,
+  /* PB27 */ nullstr,
+  /* PB28 */ nullstr,
+  /* PB29 */ nullstr,
+  /* PB30 */ "5 P0",
+  /* PB31 */ "5 P1"
+};
+
+static void decode_SERCOMA(int pin, int pmux)
 {
   PortGroup *port = digitalPinToPort(pin);
   int bitno = g_APinDescription[pin].ulPin;
   int sercomno, sercomtype;
   Sercom *s;

-  PRINT(pinmux_names[pmux]);
+  PRINTS(pinmux_names[pmux]);
   if (port == &PORT->Group[0]) {
     if (bitno < ARRAYSIZE(pin_to_SERCOMALTA_info)) {
-      PRINT(pin_to_SERCOMALTA_info[bitno]);
+      PRINTS(pin_to_SERCOMALTA_info[bitno]);
       /*
        * Get sercom number from the string.  (Ugly, but saves space.)
        */
@@ -378,7 +363,7 @@
   }
   if (port == &PORT->Group[1]) {
     if (bitno < ARRAYSIZE(pin_to_SERCOMALTB_info)) {
-      PRINT(pin_to_SERCOMALTB_info[bitno]);
+      PRINTS(pin_to_SERCOMALTB_info[bitno]);
       /*
        * Get sercom number from the string.  (Ugly, but saves space.)
        */
@@ -389,7 +374,7 @@
     s = sercomports[sercomno];
     sercomtype = s->USART.CTRLA.bit.MODE;
     if (sercomtype < ARRAYSIZE(sercomtype_names)) {
-      PRINT(sercomtype_names[sercomtype]);
+      PRINTS(sercomtype_names[sercomtype]);
     }
   }
 }
@@ -401,152 +386,153 @@
  * Arduino PWM-based analogWrite() functionality.
  */

-const char *pin_to_tc_info_a[] = {
-/* PA00 */ "TCC2/WO0",
-/* PA01 */ "TCC2/WO1",
-/* PA02 */ nullstr,
-/* PA03 */ nullstr,
-/* PA04 */ "TCC0/WO0",
-/* PA05 */ "TCC0/WO1",
-/* PA06 */ "TCC1/WO0",
-/* PA07 */ "TCC1/WO1",
-/* PA08 */ "TCC0/WO0",
-/* PA09 */ "TCC0/WO1",
-/* PA10 */ "TCC1/WO0",
-/* PA11 */ "TCC1/WO1",
-/* PA12 */ "TCC2/WO0",
-/* PA13 */ "TCC2/WO1",
-/* PA14 */ "TC3/WO0",
-/* PA15 */ "TC3/WO1",
-/* PA16 */ "TCC2/WO0",
-/* PA17 */ "TCC2/WO1",
-/* PA18 */ "TC3/WO0",
-/* PA19 */ "TC3/WO1",
-/* PA20 */ "TC7/WO0",
-/* PA21 */ "TC7/WO1",
-/* PA22 */ "TC4/WO0",
-/* PA23 */ "TC4/WO1",
-/* PA24 */ "TC5/WO0",
-/* PA25 */ "TC5/WO1",
-/* PA26 */ nullstr,
-/* PA27 */ nullstr,
-/* PA28 */ nullstr,
-/* PA29 */ nullstr,
-/* PA30 */ "TCC1/WO0",
-/* PA31 */ "TCC1/WO0"
-};
-
-const char *pin_to_tc_info_b[] = {
-/* PB00 */ "TC7/WO0",
-/* PB01 */ "TC7/WO1",
-/* PB02 */ "TC6/WO0",
-/* PB03 */ "TC6/WO1",
-/* PB04 */ nullstr,
-/* PB05 */ nullstr,
-/* PB06 */ nullstr,
-/* PB07 */ nullstr,
-/* PB08 */ "TC4/WO0",
-/* PB09 */ "TC4/WO1",
-/* PB10 */ "TC5/WO0",
-/* PB11 */ "TC5/WO1",
-/* PB12 */ "TC4/WO0",
-/* PB13 */ "TC4/WO1",
-/* PB14 */ "TC5/WO0",
-/* PB15 */ "TC5/WO1",
-/* PB16 */ "TC6/WO0",
-/* PB17 */ "TC6/WO1",
-/* PB18,19,20, 21 */ nullstr, nullstr, nullstr, nullstr,
-/* PB22 */ "TC7/WO0",
-/* PB23 */ "TC7/WO1",
-/* PB24-29 */ nullstr,nullstr,nullstr,nullstr,nullstr,nullstr,
-/* PB30 */ "TCC0/WO0",
-/* PB31 */ "TCC0/WO1",
-};
-
-void decode_TC(int pin, int pmux)
+static const char *pin_to_tc_info_a[] = {
+  /* PA00 */ "TCC2/WO0",
+  /* PA01 */ "TCC2/WO1",
+  /* PA02 */ nullstr,
+  /* PA03 */ nullstr,
+  /* PA04 */ "TCC0/WO0",
+  /* PA05 */ "TCC0/WO1",
+  /* PA06 */ "TCC1/WO0",
+  /* PA07 */ "TCC1/WO1",
+  /* PA08 */ "TCC0/WO0",
+  /* PA09 */ "TCC0/WO1",
+  /* PA10 */ "TCC1/WO0",
+  /* PA11 */ "TCC1/WO1",
+  /* PA12 */ "TCC2/WO0",
+  /* PA13 */ "TCC2/WO1",
+  /* PA14 */ "TC3/WO0",
+  /* PA15 */ "TC3/WO1",
+  /* PA16 */ "TCC2/WO0",
+  /* PA17 */ "TCC2/WO1",
+  /* PA18 */ "TC3/WO0",
+  /* PA19 */ "TC3/WO1",
+  /* PA20 */ "TC7/WO0",
+  /* PA21 */ "TC7/WO1",
+  /* PA22 */ "TC4/WO0",
+  /* PA23 */ "TC4/WO1",
+  /* PA24 */ "TC5/WO0",
+  /* PA25 */ "TC5/WO1",
+  /* PA26 */ nullstr,
+  /* PA27 */ nullstr,
+  /* PA28 */ nullstr,
+  /* PA29 */ nullstr,
+  /* PA30 */ "TCC1/WO0",
+  /* PA31 */ "TCC1/WO0"
+};
+
+static const char *pin_to_tc_info_b[] = {
+  /* PB00 */ "TC7/WO0",
+  /* PB01 */ "TC7/WO1",
+  /* PB02 */ "TC6/WO0",
+  /* PB03 */ "TC6/WO1",
+  /* PB04 */ nullstr,
+  /* PB05 */ nullstr,
+  /* PB06 */ nullstr,
+  /* PB07 */ nullstr,
+  /* PB08 */ "TC4/WO0",
+  /* PB09 */ "TC4/WO1",
+  /* PB10 */ "TC5/WO0",
+  /* PB11 */ "TC5/WO1",
+  /* PB12 */ "TC4/WO0",
+  /* PB13 */ "TC4/WO1",
+  /* PB14 */ "TC5/WO0",
+  /* PB15 */ "TC5/WO1",
+  /* PB16 */ "TC6/WO0",
+  /* PB17 */ "TC6/WO1",
+  /* PB18,19,20, 21 */ nullstr, nullstr, nullstr, nullstr,
+  /* PB22 */ "TC7/WO0",
+  /* PB23 */ "TC7/WO1",
+  /* PB24-29 */ nullstr,nullstr,nullstr,nullstr,nullstr,nullstr,
+  /* PB30 */ "TCC0/WO0",
+  /* PB31 */ "TCC0/WO1",
+};
+
+static void decode_TC(int pin, int pmux)
 {
   PortGroup *port = digitalPinToPort(pin);
   int bitno = g_APinDescription[pin].ulPin;

   if (port == &PORT->Group[0]) {
     if (bitno < ARRAYSIZE(pin_to_tc_info_a)) {
-      PRINT(pin_to_tc_info_a[bitno]);
+      PRINTS(pin_to_tc_info_a[bitno]);
     }
   }
   if (port == &PORT->Group[1]) {
     if (bitno < ARRAYSIZE(pin_to_tc_info_a)) {
-      PRINT(pin_to_tc_info_b[bitno]);
-    }
-  }
-}
-const char *pin_to_tcc_info_a[] = {
-/* PA00 */ nullstr,
-/* PA01 */ nullstr,
-/* PA02 */ nullstr,
-/* PA03 */ nullstr,
-/* PA04 */ nullstr,
-/* PA05 */ nullstr,
-/* PA06 */ nullstr,
-/* PA07 */ nullstr,
-/* PA08 */ "TCC1/WO2",
-/* PA09 */ "TCC1/WO3",
-/* PA10 */ "TCC0/WO2",
-/* PA11 */ "TCC0/WO3",
-/* PA12 */ "TCC0/WO6",
-/* PA13 */ "TCC0/WO7",
-/* PA14 */ "TCC0/WO4",
-/* PA15 */ "TCC0/WO5",
-/* PA16 */ "TCC0/WO6",
-/* PA17 */ "TCC0/WO7",
-/* PA18 */ "TCC0/WO2",
-/* PA19 */ "TCC0/WO3",
-/* PA20 */ "TCCO/WO6",
-/* PA21 */ "TCC0/WO7",
-/* PA22 */ "TCC0/WO5",
-/* PA23 */ "TCC1/WO2",
-/* PA24 */ "TCC1/WO3",
-};
-
-
-const char *pin_to_tcc_info_b[] = {
-/* PB00 */  nullstr,
-/* PB01 */  nullstr,
-/* PB02 */  nullstr,
-/* PB03 */  nullstr,
-/* PB04 */  nullstr,
-/* PB05 */  nullstr,
-/* PB06 */  nullstr,
-/* PB07 */  nullstr,
-/* PB08 */  nullstr,
-/* PB09 */  nullstr,
-/* PB10 */ "TCC0/WO4",
-/* PB11 */ "TCC0/WO5",
-/* PB12 */ "TCC0/WO6",
-/* PB13 */ "TCC0/WO7",
-/* PB14 */  nullstr,
-/* PB15 */  nullstr,
-/* PB16 */ "TCC0/WO4",
-/* PB17 */ "TCC0/WO5",
-/* 18-21 */  nullstr, nullstr, nullstr, nullstr,
-/* PB22-29 */  nullstr,nullstr,nullstr,nullstr,nullstr,nullstr,nullstr,nullstr,
-/* PB30 */ "TCC1/WO2",
-/* PB31 */ "TCC1/WO3"
-};
-
-
-void decode_TCC(int pin, int pmux)
+      PRINTS(pin_to_tc_info_b[bitno]);
+    }
+  }
+}
+
+static const char *pin_to_tcc_info_a[] = {
+  /* PA00 */ nullstr,
+  /* PA01 */ nullstr,
+  /* PA02 */ nullstr,
+  /* PA03 */ nullstr,
+  /* PA04 */ nullstr,
+  /* PA05 */ nullstr,
+  /* PA06 */ nullstr,
+  /* PA07 */ nullstr,
+  /* PA08 */ "TCC1/WO2",
+  /* PA09 */ "TCC1/WO3",
+  /* PA10 */ "TCC0/WO2",
+  /* PA11 */ "TCC0/WO3",
+  /* PA12 */ "TCC0/WO6",
+  /* PA13 */ "TCC0/WO7",
+  /* PA14 */ "TCC0/WO4",
+  /* PA15 */ "TCC0/WO5",
+  /* PA16 */ "TCC0/WO6",
+  /* PA17 */ "TCC0/WO7",
+  /* PA18 */ "TCC0/WO2",
+  /* PA19 */ "TCC0/WO3",
+  /* PA20 */ "TCCO/WO6",
+  /* PA21 */ "TCC0/WO7",
+  /* PA22 */ "TCC0/WO5",
+  /* PA23 */ "TCC1/WO2",
+  /* PA24 */ "TCC1/WO3",
+};
+
+
+static const char *pin_to_tcc_info_b[] = {
+  /* PB00 */  nullstr,
+  /* PB01 */  nullstr,
+  /* PB02 */  nullstr,
+  /* PB03 */  nullstr,
+  /* PB04 */  nullstr,
+  /* PB05 */  nullstr,
+  /* PB06 */  nullstr,
+  /* PB07 */  nullstr,
+  /* PB08 */  nullstr,
+  /* PB09 */  nullstr,
+  /* PB10 */ "TCC0/WO4",
+  /* PB11 */ "TCC0/WO5",
+  /* PB12 */ "TCC0/WO6",
+  /* PB13 */ "TCC0/WO7",
+  /* PB14 */  nullstr,
+  /* PB15 */  nullstr,
+  /* PB16 */ "TCC0/WO4",
+  /* PB17 */ "TCC0/WO5",
+  /* 18-21 */  nullstr, nullstr, nullstr, nullstr,
+  /* PB22-29 */  nullstr,nullstr,nullstr,nullstr,nullstr,nullstr,nullstr,nullstr,
+  /* PB30 */ "TCC1/WO2",
+  /* PB31 */ "TCC1/WO3"
+};
+
+
+static void decode_TCC(int pin, int pmux)
 {
   PortGroup *port = digitalPinToPort(pin);
   int bitno = g_APinDescription[pin].ulPin;

   if (port == &PORT->Group[0]) {
     if (bitno < ARRAYSIZE(pin_to_tc_info_a)) {
-      PRINT(pin_to_tcc_info_a[bitno]);
+      PRINTS(pin_to_tcc_info_a[bitno]);
     }
   }
   if (port == &PORT->Group[1]) {
     if (bitno < ARRAYSIZE(pin_to_tc_info_a)) {
-      PRINT(pin_to_tcc_info_b[bitno]);
+      PRINTS(pin_to_tcc_info_b[bitno]);
     }
   }
 }
@@ -554,43 +540,104 @@
 /*
  * "COM" are special communications peripherals like USB, SWD, or ISS
  */
-void decode_COMM(int pin, int pmux)
+static void decode_COMM(int pin, int pmux)
 {
   PortGroup *port = digitalPinToPort(pin);
   int bitno = g_APinDescription[pin].ulPin;

-  PRINT(pinmux_names[pmux]);
+  PRINTS(pinmux_names[pmux]);
   // PA23..PA25 are for USB
   if (port == &PORT->Group[0] && (bitno >= 23 && bitno <= 25)) {
-    PRINT("(USB)");
+    PRINTS("(USB)");
   }
   // PA30..PA31 are for SWD (Serial JTAG debug)
   if (port == &PORT->Group[0] && (bitno >= 30 && bitno <= 31)) {
-    PRINT("(SWD)");
-  }
-}
-void decode_CLK(int pin, int pmux)
-{
-  PRINT(pinmux_names[pmux]);   // default action
+    PRINTS("(SWD)");
+  }
+}
+
+static void decode_CLK(int pin, int pmux)
+{
+  PRINTS(pinmux_names[pmux]);   // default action
 }

 /*
  * Given an Arduino pin number, print the datasheet-style Port and Bit numbers
  */
-void print_portname(int pin)
+static void print_portname(int pin)
 {
   PortGroup *port = digitalPinToPort(pin);
   int bitno = g_APinDescription[pin].ulPin;

   if (port == &PORT->Group[0]) {
-    PRINT("PA");
+    PRINTS("PA");
   }
   if (port == &PORT->Group[1]) {
-    PRINT("PB");
-  }
-  if (bitno < 10) {
-    PRINT("0");      // Output formatting with possible leading 0
-  }
-  PRINT(bitno);
-  PRINT("  ");
-}
+    PRINTS("PB");
+  }
+  PRINTN(bitno);
+  PRINTS("  ");
+}
+
+/*
+ * copy ("print") a string to the temporary buffer
+ */
+static void print_s(const char *s)
+{
+  while (*s) {
+    *bufp++ = *s++;
+  }
+  *bufp = 0;
+}
+
+/*
+ * copy ("print") a two digit decimal number to the temporary buffer
+ */
+static void print_n2(int n)
+{
+  if (n <= 99) {
+    *bufp++ = (n/10) + '0';
+    *bufp++ = (n % 10) + '0';
+    *bufp = 0;
+  } else {
+    print_s("***");
+  }
+}
+
+/*
+ * generate a pinmux report for a single pin.  Pass in a buffer of sufficient size,
+ * and an optional name.
+ */
+
+void pinmux_report(byte pin, char *p, char *name)
+{
+  bufp = p;
+  *bufp = 0;
+  if (print_pinno(pin, name)) {  // Does pin exist?
+
+    int bitno = g_APinDescription[pin].ulPin;
+    PortGroup *port = digitalPinToPort(pin);
+    int pmuxval;
+
+    print_portname(pin);
+
+    if (port->PINCFG[bitno].bit.PMUXEN) {  // Is pinmux enabled?
+      // If pinmux is enabled, further report it's value
+      if (bitno & 1) {
+	// Odd pin numbers
+	pmuxval = port->PMUX[bitno / 2].bit.PMUXO;
+      } else {
+	pmuxval = port->PMUX[bitno / 2].bit.PMUXE;
+      }
+      print_pinmux(pin, pmuxval);
+    } else {
+      // Pinmux not enabled - port is GPIO
+      PRINTS("GPIO ");
+      if (port->DIR.reg & (1 << bitno)) { // Decode pinmode (direction.)
+	PRINTS("O");
+      } else {
+	PRINTS("I");
+      }
+    } // Pinmux or GPIO
+  } // Pin existance
+}


Fix #800: make it easier to patch APPEUI, DEVEUI and APPKEY

--- examples/compliance-otaa-halconfig/compliance-otaa-halconfig.ino
+++ examples/compliance-otaa-halconfig/compliance-otaa-halconfig.ino
@@ -30,20 +30,20 @@
 // collisions with a registered app on TTN.
 //

-// This EUI must be in little-endian format, so least-significant-byte
-// first.  This corresponds to 0x0000000000000001
-// static const u1_t PROGMEM APPEUI[8]= { 1, 0, 0, 0, 0, 0, 0, 0 };
-void os_getArtEui (u1_t* buf) { memset(buf, 0, 8); buf[0] = 1; }
-
-// This should also be in little endian format, see above.
+// AppEUI: must be in little-endian format, so least-significant-byte
+// first.  This corresponds to 0x0000000000000000
+static const u1_t PROGMEM APPEUI[8]= { 0, 0, 0, 0, 0, 0, 0, 0 };
+void os_getArtEui (u1_t* buf) { memcpy_P(buf, APPEUI, 8); }
+
+// DevEUI: This should also be in little endian format, see above.
 // This corresponds to 0x0000000000000001
-// static const u1_t PROGMEM DEVEUI[8]= { 1, 0, 0, 0, 0, 0, 0, 0 };
-void os_getDevEui (u1_t* buf) { memset(buf, 0, 8); buf[0] = 1; }
+static const u1_t PROGMEM DEVEUI[8]= { 1, 0, 0, 0, 0, 0, 0, 0 };
+void os_getDevEui (u1_t* buf) { memcpy_P(buf, DEVEUI, 8); }

 // This key should be in big endian format (or, since it is not really a
 // number but a block of memory, endianness does not really apply).
-// static const u1_t PROGMEM APPKEY[16] = { 0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 2 };
-void os_getDevKey (u1_t* buf) { memset(buf, 0, 16); buf[15] = 2; }
+static const u1_t PROGMEM APPKEY[16] = { 0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 2 };
+void os_getDevKey (u1_t* buf) { memcpy_P(buf, APPKEY, 16); }

 // this data must be kept short -- max is 11 bytes for US DR0
 static uint8_t mydata[] = { 0xCA, 0xFE, 0xF0, 0x0D };


Create init function

Create init function

--- examples/FadeInOut/FadeInOut.ino
+++ examples/FadeInOut/FadeInOut.ino
@@ -13,6 +13,7 @@

 void setup()
 {
+  leds.init();
 }

 byte power = 0;


Resetting when time up

Resetting when time up

--- Project_8/Project_8.ino
+++ Project_8/Project_8.ino
@@ -1,8 +1,8 @@
 const int switchPin = 8;
 unsigned long previousTime = 0;
-int switchState = 0;
-int prevSwitchState = 0;
-int led = 2;
+short switchState = 0;
+short prevSwitchState = 0;
+short led = 2;
 long interval = 10000;

 void setup() {
@@ -19,7 +19,11 @@
     digitalWrite(led, HIGH);
     led++;
     if (led == 7) {
-
+      for (int i = 2; i < 8; i++) {
+      digitalWrite(i, LOW);
+    }
+    led = 2;
+    previousTime = currentTime;
     }
   }
   switchState = digitalRead(switchPin);


Included all currently planned serial commands implement fix for PID to work from EEPROM values - needs testing

--- XV_Lidar_Controller.ino
+++ XV_Lidar_Controller.ino
@@ -14,8 +14,6 @@
 #include "EEPROMAnything.h"
 #include <SerialCommand.h>

-#define DEBUG_MOTOR_RPM false
-
 struct EEPROM_Config
 {
   byte id;
@@ -32,13 +30,15 @@

 const byte EEPROM_ID = 0x99;  // used to validate EEPROM initialized

-double pwm_val = xv_config.pwm_min;  // start slow
+double pwm_val;
 double pwm_last;
 double motor_rpm;

+boolean debug_motor_rpm = false;
 boolean motor_enable = true;
-
-PID myPID(&motor_rpm, &pwm_val, &xv_config.rpm_setpoint,xv_config.Kp,xv_config.Ki,xv_config.Kd, DIRECT);
+boolean retransmit = true;
+
+PID rpmPID(&motor_rpm, &pwm_val, &xv_config.rpm_setpoint, xv_config.Kp, xv_config.Ki, xv_config.Kd, DIRECT);

 int inByte = 0;  // incoming serial byte
 unsigned char data_status = 0;
@@ -60,11 +60,12 @@
   Serial1.begin(115200);  // XV LDS data

   Timer3.initialize(30); // set PWM frequency to 32.768kHz
-  Timer3.pwm(xv_config.motor_pwm_pin, pwm_val); // replacement for analogWrite()
-
-  myPID.SetOutputLimits(xv_config.pwm_min,xv_config.pwm_max);
-  myPID.SetSampleTime(20);
-  myPID.SetMode(AUTOMATIC);
+  Timer3.pwm(xv_config.motor_pwm_pin, xv_config.pwm_min); // replacement for analogWrite()
+
+  rpmPID.SetOutputLimits(xv_config.pwm_min,xv_config.pwm_max);
+  rpmPID.SetSampleTime(20);
+  rpmPID.SetTunings(xv_config.Kp, xv_config.Ki, xv_config.Kd);
+  rpmPID.SetMode(AUTOMATIC);

   initSerialCommands();
 }
@@ -76,12 +77,14 @@
   // read byte from LIDAR and retransmit to USB
   if (Serial1.available() > 0) {
     inByte = Serial1.read();  // get incoming byte:
-    Serial.print(inByte, BYTE);  // retransmit
+    if (retransmit) {
+      Serial.print(inByte, BYTE);  // retransmit
+    }
     decodeData(inByte);
   }

   if (motor_enable) {
-    myPID.Compute();
+    rpmPID.Compute();
     if (pwm_val != pwm_last) {
       Timer3.pwm(xv_config.motor_pwm_pin, pwm_val);
       pwm_last = pwm_val;
@@ -145,13 +148,15 @@
     motor_rph_high_byte = inByte;
     motor_rph = (motor_rph_high_byte << 8) | motor_rph_low_byte;
     motor_rpm = float( (motor_rph_high_byte << 8) | motor_rph_low_byte ) / 64.0;
-#if DEBUG_MOTOR_RPM
-    Serial.print(motor_rph_low_byte, HEX);
-    Serial.println(motor_rph_high_byte, HEX);
-    Serial.print(motor_rpm);
-    Serial.print("  ");
-    Serial.println(pwm_val);
-#endif
+    if (debug_motor_rpm) {
+//      Serial.print("Motor RPH HEX: ");
+//      Serial.print(motor_rph_low_byte, HEX);
+//      Serial.println(motor_rph_high_byte, HEX);
+      Serial.print("RPM: ");
+      Serial.print(motor_rpm);
+      Serial.print("  PWM: ");
+      Serial.println(pwm_val);
+    }
     break;
   default: // others do checksum
     break;
@@ -173,20 +178,37 @@
 }

 void initSerialCommands() {
-  sCmd.addCommand("help",    help);
-  sCmd.addCommand("Help",    help);
-  sCmd.addCommand("GetConfig",    getConfig);
-  sCmd.addCommand("SetRPM",    setRPM);
-  sCmd.addCommand("SetKp",    setKp);
-  sCmd.addCommand("SetKi",    setKi);
-  sCmd.addCommand("SetKd",    setKd);
-
-  sCmd.addCommand("MotorOff",    motorOff);
-  sCmd.addCommand("MotorOn",     motorOn);
+  sCmd.addCommand("help",       help);
+  sCmd.addCommand("Help",       help);
+  sCmd.addCommand("GetConfig",  getConfig);
+  sCmd.addCommand("SaveConfig", saveConfig);
+  sCmd.addCommand("ResetConfig",initEEPROM);
+
+  sCmd.addCommand("SetRPM",  setRPM);
+  sCmd.addCommand("SetKp",   setKp);
+  sCmd.addCommand("SetKi",   setKi);
+  sCmd.addCommand("SetKd",   setKd);
+
+  sCmd.addCommand("ShowRPM",       showRPM);
+  sCmd.addCommand("HideRPM",       hideRPM);
+  sCmd.addCommand("MotorOff",      motorOff);
+  sCmd.addCommand("MotorOn",       motorOn);
+  sCmd.addCommand("RetransmitOff", retransmitOff);
+  sCmd.addCommand("RetransmitOn",  retransmitOn);

   // XV Commands
   sCmd.addCommand("GetPrompt",  getPrompt);
   sCmd.addCommand("GetVersion",  getVersion);
+}
+
+void showRPM() {
+  debug_motor_rpm = true;
+  Serial.println("Showing RPM data");
+}
+
+void hideRPM() {
+  debug_motor_rpm = false;
+  Serial.println("Hiding RPM data");
 }

 void motorOff() {
@@ -199,6 +221,16 @@
   motor_enable = true;
   Timer3.pwm(xv_config.motor_pwm_pin, xv_config.pwm_min);
   Serial.println("Motor on");
+}
+
+void retransmitOff() {
+  retransmit = false;
+  Serial.println("Lidar data disabled");
+}
+
+void retransmitOn() {
+  retransmit = true;
+  Serial.println("Lidar data enabled");
 }

 void setRPM() {
@@ -254,7 +286,9 @@
   }
   else {
     Serial.print("Setting Kp to: ");
-    Serial.println(sVal);
+    Serial.println(sVal);
+    xv_config.Kp = sVal;
+    rpmPID.SetTunings(xv_config.Kp, xv_config.Ki, xv_config.Kd);
   }
 }

@@ -282,6 +316,8 @@
   else {
     Serial.print("Setting Ki to: ");
     Serial.println(sVal);
+    xv_config.Ki = sVal;
+    rpmPID.SetTunings(xv_config.Kp, xv_config.Ki, xv_config.Kd);
   }
 }

@@ -309,6 +345,8 @@
   else {
     Serial.print("Setting Kd to: ");
     Serial.println(sVal);
+    xv_config.Kd = sVal;
+    rpmPID.SetTunings(xv_config.Kp, xv_config.Ki, xv_config.Kd);
   }
 }

@@ -321,13 +359,44 @@
 }

 void help() {
-  Serial.println("List of available commands");
-  Serial.println("All commands are case sensitive");
-
+  Serial.println("List of available commands (case sensitive");
+  Serial.println("  GetConfig");
+  Serial.println("  SaveConfig");
+  Serial.println("  ResetConfig");
+  Serial.println("  SetRPM");
+  Serial.println("  SetKp");
+  Serial.println("  SetKi");
+  Serial.println("  SetKp");
+  Serial.println("  ShowRPM");
+  Serial.println("  HideRPM");
+  Serial.println("  MotorOff");
+  Serial.println("  MotorOn");
+  Serial.println("  RetransmitOff");
+  Serial.println("  RetransmitOn");
 }

 void getConfig() {
-
-}
-
-
+  Serial.print("PWM pin: ");
+  Serial.println(xv_config.motor_pwm_pin);
+
+  Serial.print("Target RPM: ");
+  Serial.println(xv_config.rpm_setpoint);
+
+  Serial.print("Max PWM: ");
+  Serial.println(xv_config.pwm_max);
+  Serial.print("Min PWM: ");
+  Serial.println(xv_config.pwm_min);
+
+  Serial.print("PID Kp: ");
+  Serial.println(xv_config.Kp);
+  Serial.print("PID Ki: ");
+  Serial.println(xv_config.Ki);
+  Serial.print("PID Kd: ");
+  Serial.println(xv_config.Kd);
+}
+
+void saveConfig() {
+  EEPROM_writeAnything(0, xv_config);
+}
+
+


When using ShowAngle, angle values interpreted from data stream instead of just incrementing for valid data in case of packet loss. Lowered PWM min to work with generic replacement motors. Added failsafe to shut down the motor when at 100% duty cycle and RPM not within range

--- XV_Lidar_Controller.ino
+++ XV_Lidar_Controller.ino
@@ -1,5 +1,5 @@
 /*
-  XV Lidar Controller v1.2.1
+  XV Lidar Controller v1.2.2

  Copyright 2014 James LeRoy getSurreal
  https://github.com/getSurreal/XV_Lidar_Controller
@@ -19,11 +19,13 @@
 struct EEPROM_Config {
   byte id;
   char version[6];
-  int motor_pwm_pin;  // pin connected to mosfet for motor speed control
+  int motor_pwm_pin;    // pin connected to mosfet for motor speed control
   double rpm_setpoint;  // desired RPM (uses double to be compatible with PID library)
-  double pwm_max;  // max analog value.  probably never needs to change from 1023
-  double pwm_min;  // min analog pulse value to spin the motor
-  int sample_time;  // how often to calculate the PID values
+  double rpm_min;
+  double rpm_max;
+  double pwm_max;       // max analog value.  probably never needs to change from 1023
+  double pwm_min;       // min analog pulse value to spin the motor
+  int sample_time;      // how often to calculate the PID values

   // PID tuning values
   double Kp;
@@ -38,11 +40,16 @@
 }
 xv_config;

-const byte EEPROM_ID = 0x04;  // used to validate EEPROM initialized
-
-double pwm_val;
+const byte EEPROM_ID = 0x05;  // used to validate EEPROM initialized
+
+double pwm_val = 500;  // start with ~50% power
 double pwm_last;
 double motor_rpm;
+unsigned long now;
+unsigned long motor_check_timer = millis();
+unsigned long motor_check_interval = 200;
+unsigned int rpm_err_thresh = 10;  // 2 seconds (10 * 200ms) to shutdown motor with improper RPM and high voltage
+unsigned int rpm_err = 0;
 unsigned long curMillis;
 unsigned long lastMillis = millis();

@@ -103,6 +110,7 @@
       Timer3.pwm(xv_config.motor_pwm_pin, pwm_val);  // replacement for analogWrite()
       pwm_last = pwm_val;
     }
+    motorCheck();
   }
 }

@@ -151,8 +159,8 @@
   switch (data_loop_index) {
   case 1: // 4 degree index
     data_4deg_index = inByte - 0xA0;
-    if (data_4deg_index == 0) {
-      angle = 0;
+    angle = data_4deg_index * 4;  // 1st angle in the set of 4
+    if (angle == 0) {
       if (ledState) {
         ledState = LOW;
       }
@@ -179,7 +187,7 @@
     motor_rph_high_byte = inByte;
     motor_rph = (motor_rph_high_byte << 8) | motor_rph_low_byte;
     motor_rpm = float( (motor_rph_high_byte << 8) | motor_rph_low_byte ) / 64.0;
-    if (xv_config.show_rpm) {
+    if (xv_config.show_rpm and angle == 0) {
       Serial.print(F("RPM: "));
       Serial.print(motor_rpm);
       Serial.print(F("  PWM: "));
@@ -215,11 +223,11 @@
         Serial.print(quality);
         Serial.println(F(")"));
       }
-    }
-    angle++;
+    }
     break;

   case 8:
+    angle = data_4deg_index * 4 + 1; // 2nd angle in the set
     data0 = inByte;
     break;

@@ -248,10 +256,10 @@
         Serial.println(F(")"));
       }
     }
-    angle++;
     break;

   case 12:
+    angle = data_4deg_index * 4 + 2; // 3rd angle in the set
     data0 = inByte;
     break;

@@ -280,10 +288,10 @@
         Serial.println(F(")"));
       }
     }
-    angle++;
     break;

   case 16:
+    angle = data_4deg_index * 4 + 3;  // 4th angle in the set
     data0 = inByte;
     break;

@@ -312,7 +320,6 @@
         Serial.println(F(")"));
       }
     }
-    angle++;
     break;

   default: // others do checksum
@@ -321,17 +328,19 @@
 }

 void initEEPROM() {
-  xv_config.id = 0x04;
-  strcpy(xv_config.version, "1.2.1");
+  xv_config.id = 0x05;
+  strcpy(xv_config.version, "1.2.2");
   xv_config.motor_pwm_pin = 9;  // pin connected N-Channel Mosfet

   xv_config.rpm_setpoint = 300;  // desired RPM
+  xv_config.rpm_min = 200;
+  xv_config.rpm_max = 300;
+  xv_config.pwm_min = 100;
   xv_config.pwm_max = 1023;
-  xv_config.pwm_min = 550;
   xv_config.sample_time = 20;
-  xv_config.Kp = 1.0;
-  xv_config.Ki = 0.5;
-  xv_config.Kd = 0.00;
+  xv_config.Kp = 2.0;
+  xv_config.Ki = 1.0;
+  xv_config.Kd = 0.0;

   xv_config.motor_enable = true;
   xv_config.raw_data = true;
@@ -446,10 +455,29 @@

 void motorOn() {
   xv_config.motor_enable = true;
-  Timer3.pwm(xv_config.motor_pwm_pin, xv_config.pwm_min);
+  Timer3.pwm(xv_config.motor_pwm_pin, pwm_val);
+  rpm_err = 0;  // reset rpm error
   Serial.println(F(" "));
   Serial.print(F("Motor on"));
   Serial.println(F(" "));
+}
+
+void motorCheck() {  // Make sure the motor RPMs are good else shut it down
+  now = millis();
+  if (now - motor_check_timer > motor_check_interval){
+    if ((motor_rpm < xv_config.rpm_min or motor_rpm > xv_config.rpm_max) and pwm_val > 1000) {
+      rpm_err++;
+    }
+    else {
+      rpm_err = 0;
+    }
+    if (rpm_err > rpm_err_thresh) {
+      motorOff();
+      ledState = LOW;
+      digitalWrite(ledPin, ledState);
+    }
+    motor_check_timer = millis();
+  }
 }

 void hideRaw() {
@@ -476,16 +504,18 @@
   arg = sCmd.next();
   if (arg != NULL) {
     sVal = atof(arg);    // Converts a char string to a float
-    if (sVal < 200) {
-      sVal = 200;
+    if (sVal < xv_config.rpm_min) {
+      sVal = xv_config.rpm_min;
       Serial.println(F(" "));
-      Serial.print(F("Setting to minimum 200"));
+      Serial.print(F("RPM too low. Setting to minimum "));
+      Serial.print(xv_config.rpm_min);
       Serial.println(F(" "));
     }
-    if (sVal > 300) {
-      sVal = 300;
+    if (sVal > xv_config.rpm_max) {
+      sVal = xv_config.rpm_max;
       Serial.println(F(" "));
-      Serial.print(F("Setting to maximum 300"));
+      Serial.print(F("RPM too high. Setting to maximum "));
+      Serial.print(xv_config.rpm_max);
       Serial.println(F(" "));
     }
   }
@@ -504,6 +534,7 @@
     Serial.println(F(" "));
   }
   else {
+    xv_config.rpm_setpoint = sVal;
     Serial.println(F(" "));
     Serial.print(F("New RPM setpoint: "));
     Serial.println(sVal);
@@ -738,3 +769,4 @@
 }

+


RFID shizzle

RFID shizzle

--- turtleCode/arduino/final/LCD12864_test/LCD12864_test.ino
+++ turtleCode/arduino/final/LCD12864_test/LCD12864_test.ino
@@ -52,7 +52,6 @@

 int answer;
 int input;
-int counter = 0;

 unsigned char fuse[1024];

@@ -207,24 +206,12 @@
     // Stop encryption on PCD
     mfrc522.PCD_StopCrypto1();

-    counter++;
-
-    if (answer > 9 && counter == 2){
-      input += buffer[0];
-      checkInput(input, answer);
-      counter = 0;
-    }
-    else if (answer > 9 && counter == 1){
-      input = 10*buffer[0];
-      return;
-    }
-    else{
-      input = buffer[0];
-      checkInput(input, answer);
-      counter = 0;
-    }
-
-}
+   input = buffer[0];
+   Serial.println(input);
+   checkInput(input, answer);
+
+
+}

 void dump_byte_array(byte *buffer, byte bufferSize) { //dump byte array function


light cleanup of imu sample setting gain and calibration for my test device

--- BasicIMU/BasicIMU.ino
+++ BasicIMU/BasicIMU.ino
@@ -1,4 +1,3 @@
-#define TWI_FREQ 400000L
 #include <Wire.h>
 #include <L3G.h>
 #include <LSM303.h>
@@ -12,7 +11,6 @@
 void setup()
 {
   I2C_Init();
-  Accel_Init();
   Compass_Init();
   Gyro_Init();

@@ -68,16 +66,17 @@
   gyro.writeReg(L3G_CTRL_REG1, 0xCF); // normal power mode, all axes enabled, 760 Hz
 }

-void Accel_Init()
+void Compass_Init()
 {
-  compass.init();
-  compass.writeAccReg(LSM303_CTRL_REG1_A, 0x77); // normal power mode, all axes enabled, 400 Hz
+  compass.init(LSM303DLHC_DEVICE);
+  compass.enableDefault();
+  compass.writeAccReg(LSM303_CTRL_REG1_A, 0x27); // Bump accelerometer from 50 hz to 400 hz
+
+  // Lowest possible gain value that doesn't overflow and return -4096
+  compass.setMagGain(LSM303::magGain_40);
+
+  // Calibration values, use Calibrate example program to get the values for your compass.
+  compass.m_min.x = 1821; compass.m_min.y = -1770; compass.m_min.z = 904;
+  compass.m_max.x = 2030; compass.m_max.y = -1396; compass.m_max.z = 1161;
 }

-void Compass_Init()
-{
-  compass.writeMagReg(LSM303_CRA_REG_M, 0x10); // 1C == 220 hz, 10 == 15 hz
-  compass.writeMagReg(LSM303_CRB_REG_M, 0x20); // Lowest gain
-  compass.writeMagReg(LSM303_MR_REG_M, 0x00); // continuous conversion mode
-}
-