 static byte stack[RF12_MAXDATA+4], top, sendLen, dest;
 static byte testbuf[RF12_MAXDATA], testCounter;
 
-static byte nodes[MAX_NODES + 1];  // [0] is unused
+static byte nodes[MAX_NODES+1];  // [0] is unused
 static byte postingsIn, postingsOut;
 
 static void showNibble (byte nibble) {
-  char c = '0' + (nibble & 0x0F);
-  if (c > '9')
-    c += 7;
-  Serial.print(c);
+    char c = '0' + (nibble & 0x0F);
+    if (c > '9')
+        c += 7;
+    Serial.print(c);
 }
 
 static void showByte (byte value) {
-  if (config.hex_output) {
-    showNibble(value >> 4);
-    showNibble(value);
-  } else
-    Serial.print((int) value);
+    if (config.hex_output) {
+        showNibble(value >> 4);
+        showNibble(value);
+    } else
+        Serial.print((int) value);
 }
 
 static void loadConfig () {
-  eeprom_read_block(&config, RF12_EEPROM_ADDR, sizeof config);
+    eeprom_read_block(&config, RF12_EEPROM_ADDR, sizeof config);
 }
 
 static void saveConfig () {
-  config.format = MAJOR_VERSION;
-  config.crc = ~0;
-  for (byte i = 0; i < sizeof config - 2; ++i)
-    config.crc = _crc16_update(config.crc, ((byte*) &config)[i]);
-
-  eeprom_write_block(&config, RF12_EEPROM_ADDR, sizeof config);
-  Serial.println(sizeof config);
-
-  if (!rf12_config())
-     showString(INITFAIL);
+    config.format = MAJOR_VERSION;
+    config.crc = ~0;
+    for (byte i = 0; i < sizeof config - 2; ++i)
+        config.crc = _crc16_update(config.crc, ((byte*) &config)[i]);
+
+    eeprom_write_block(&config, RF12_EEPROM_ADDR, sizeof config);
+    Serial.println(sizeof config);
+
+    if (!rf12_config())
+         showString(INITFAIL);
 }
 
 static byte bandToFreq (byte band) {
-   return band == 4 ? RF12_433MHZ : band == 8 ? RF12_868MHZ : band == 9 ? RF12_915MHZ : 0;
+     return band == 4 ? RF12_433MHZ : band == 8 ? RF12_868MHZ : band == 9 ? RF12_915MHZ : 0;
 }
 
 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

}

static void handleInput (char c) {
  if ('0' <= c && c <= '9')
    value = 10 * value + c - '0';
  else if (c == ',') {
    if (top < sizeof stack)
      stack[top++] = value;
    value = 0;
  } else if ('a' <= c && c <='z') {
    showString(PSTR("> "));
    for (byte i = 0; i < top; ++i) {
      Serial.print((int) stack[i]);
      Serial.print(',');
    }
    Serial.print((int) value);
    Serial.println(c);

    switch (c) {
      default:
        showHelp();
        break;

      case 'i': // set node id
        if ((value > 0) && (value <= MAX_NODES + 1)) {
// Node 15 may exist on T84 but only as the RF12Demo node,
//  eeprom address +0, the encryption key storage will be
//  overwritten by the 42j command, similar for n31 on MEGA
          if (value < MAX_NODES) nodes[value] = 0;
        // Prevent auto allocation of this node number
          config.nodeId = (config.nodeId & 0xE0) + (value & 0x1F);
          saveConfig();
        }
        else {
           showString(INVALID1);
        }
        break;

      case 'b': // set band: 4 = 433, 8 = 868, 9 = 915
        value = bandToFreq(value);
        if (value) {
         config.nodeId = (value << 6) + (config.nodeId & 0x3F);
         config.frequency_offset = 1600;
         saveConfig();
        } else {
            showString(INVALID1);
        }
        break;

      case 'o': // Increment frequency within band
          Serial.print(config.frequency_offset);
// Stay within your country's ISM spectrum management guidelines, i.e.
// allowable frequencies and their use when selecting operating frequencies.
          if (value) {
            if ((value > 95) && (value < 3904)) {  // supported by the RFM12B
              config.frequency_offset = value;
              Serial.print('>');
              Serial.println(config.frequency_offset);
              saveConfig();
            }
            else {
              showString(INVALID1);
            }
          }
          else {
            Serial.println();
          }
        break;

      case 'g': // set network group
        config.group = value;
        saveConfig();
        break;

      case 'c': // set collect mode (off = 0, on = 1)
        config.collect_mode = value;
        saveConfig();
        break;

      case 't': // broadcast a maximum size test packet, request an ack
        cmd = 'a';
        sendLen = RF12_MAXDATA;
        dest = 0;
        for (byte i = 0; i < RF12_MAXDATA; ++i)
          testbuf[i] = i + testCounter;
        showString(PSTR("test "));
        Serial.println((int) testCounter); // first byte in test buffer
        ++testCounter;
        break;

      case 'a': // send packet to node ID N, request an ack
      case 's': // send packet to node ID N, no ack
        cmd = c;
        sendLen = top;
        dest = value;
        memcpy(testbuf, stack, top);
        break;

      case 'f': // send FS20 command: <hchi>,<hclo>,<addr>,<cmd>f
        rf12_initialize(0, RF12_868MHZ, 0);
        activityLed(1);
        fs20cmd(256 * stack[0] + stack[1], stack[2], value);
        activityLed(0);
        rf12_configSilent();
        break;

      case 'k': // send KAKU command: <addr>,<dev>,<on>k
        rf12_initialize(0, RF12_433MHZ, 0);
        activityLed(1);
        kakuSend(stack[0], stack[1], value);
        activityLed(0);
        rf12_configSilent();
        break;

      case 'z': // put the ATmega in ultra-low power mode (reset needed)
        if (value == 123)
          Sleep();
        break;

      case 'q': // turn quiet mode on or off (don't report bad packets)
        config.quiet_mode = value;
        saveConfig();
        break;

      case 'x': // set reporting mode to hex (1) or decimal (0)
        config.hex_output = value;
        saveConfig();
        break;

      case 'v': //display the interpreter version
        displayVersion();
        Serial.println();
        break;

#if !TINY
      case 'l': // turn activity LED on or off
        activityLed(value);
        break;

      case 'd': // dump all log markers
        if (df_present())
          df_dump();
        break;

      case 'r': // replay from specified seqnum/time marker
        if (df_present()) {
          word seqnum = (stack[0] << 8) || stack[1];
          long asof = (stack[2] << 8) || stack[3];
          asof = (asof << 16) | ((stack[4] << 8) || value);
          df_replay(seqnum, asof);
        }
        break;

      case 'e': // erase specified 4Kb block
        if (df_present() && stack[0] == 123) {
          word block = (stack[1] << 8) | value;
          df_erase(block);
        }
        break;

      case 'w': // wipe entire flash memory
        if (df_present() && stack[0] == 12 && value == 34) {
          df_wipe();
          showString(PSTR("erased\n"));
        }
        break;

      case 'j':
        if (stack[0] <= MAX_NODES) {
          const uint8_t *ee_entry = RF12_EEPROM_ADDR + (stack[0] * 32);
          for (byte i = 0; i < RF12_EEPROM_SIZE; ++i) {
            byte b = eeprom_read_byte(ee_entry + i);  // http://forum.arduino.cc/index.php?topic=122140.0
            showByte(b);
            testbuf[i] = b;
            if ((value == 42) && (stack[0] == 0)) {
             eeprom_write_byte(RF12_EEPROM_ADDR + (((config.nodeId & RF12_HDR_MASK)*32) + i), b);
            }
          }
          Serial.println();
          displayASCII(testbuf, RF12_EEPROM_SIZE);
        }
        else {
          showString(INVALID1);
        }
        if (!value) break;
        if (value == 42) {
          showString(PSTR("Backed Up\n"));
          break;
        }
        if ((value == 123) && (stack[0] == (config.nodeId & RF12_HDR_MASK))) {   // Only restore this NodeId
          const uint8_t *ee_shadow = RF12_EEPROM_ADDR + ((config.nodeId & RF12_HDR_MASK)*32);
          // Check CRC to be restored
          word crc = ~0;
          for (byte i = 0; i < RF12_EEPROM_SIZE; ++i)
            crc = _crc16_update(crc, eeprom_read_byte(ee_shadow + i));
          if (crc)
            showString(PSTR("Bad CRC\n"));
          else {
            for (byte i = 0; i < RF12_EEPROM_SIZE; ++i) {
              byte b = eeprom_read_byte((ee_shadow) + i);
              showByte(b);
              eeprom_write_byte((RF12_EEPROM_ADDR) + i, b);
            }
            Serial.println();
            showString(PSTR("Restored\n"));
            }
          if (rf12_config())
            loadConfig();
          else
            showString(INITFAIL);
        }
        else {
          showString(INVALID1);
        }
      break;
#endif

      case 'n': // Clear node entries in RAM & eeprom
        if ((stack[0] > 0) && (stack[0] <= MAX_NODES) && (value == 123) && (nodes[stack[0]] == 0)) {
          nodes[stack[0]] = 0xFF;                                           // Clear RAM entry
          for (byte i = 0; i < (RF12_EEPROM_SIZE); ++i) {
            eeprom_write_byte(RF12_EEPROM_ADDR + (stack[0]*32) + i, 0xFF);  // Clear complete eeprom entry
          }
        }
        else {
          showString(INVALID1);
        }
        break;

      case 'p':
        // Post a command for a remote node, to be collected along with the next ACK
        // Format is 20,127p where 20 is the node number and 127 is the desired value to be posted
        // stack[0] contains the target node
        // and value contains the command to be posted
        if ((!stack[0]) && (!value)) {
          Serial.print((int)postingsIn);
          Serial.print(',');
          Serial.println((int)postingsOut);
          nodesShow();
        }
        else {
          if ((stack[0] !=(config.nodeId & RF12_HDR_MASK)) && (stack[0] <= MAX_NODES) && (value < 255) && (nodes[stack[0]] == 0)) {   // No posting to special(31) or overwriting pending post
            nodes[stack[0]] = value;
            postingsIn++;            // Count post
          }
          else
          {
            showString(INVALID1);
          }
        }
       break;
    } // End Switch

    value = top = 0;
    memset(stack, 0, sizeof stack);
  } else if (c == '>') {
    // special case, send to specific band and group, and don't echo cmd
    // input: band,group,node,header,data...
    stack[top++] = value;
    // TODO: frequency offset is kept at default value here, is that ok?
    rf12_initialize(stack[2], bandToFreq(stack[0]), stack[1]);
    rf12_sendNow(stack[3], stack + 4, top - 4);
    rf12_sendWait(2);
    rf12_configSilent();
    value = top = 0;
    memset(stack, 0, sizeof stack);
  } else if (' ' < c && c < 'A') {
    showHelp();
  }
}

static void displayASCII(volatile uint8_t* data, byte count) {
    for (byte i = 0; i < count; ++i) {
      if ((data[i] < 32) || (data[i] > 126))
        {
        showString(PSTR(" ."));
        }
      else
        {
          Serial.print(' ');
          Serial.print((char) data[i]);
        }
    }
    Serial.println();
}

void displayVersion () {
  showString(VERSION);
#if TINY
  showString(PSTR("Tiny "));
#endif
}


// for 25 us SPI overhead to end up with the proper on-the-air pulse widths.
// With thanks to JGJ Veken for his help in getting these values right.
static void ookPulse(int on, int off) {
    rf12_onOff(1);
    delayMicroseconds(on + 150);
    rf12_onOff(0);
    delayMicroseconds(off - 200);
}

static void fs20sendBits(word data, byte bits) {
    if (bits == 8) {
        ++bits;
        data = (data << 1) | parity_even_bit(data);
    }
    for (word mask = bit(bits-1); mask != 0; mask >>= 1) {
        int width = data & mask ? 600 : 400;
        ookPulse(width, width);
    }
}

static void fs20cmd(word house, byte addr, byte cmd) {
    byte sum = 6 + (house >> 8) + house + addr + cmd;
    for (byte i = 0; i < 3; ++i) {
        fs20sendBits(1, 13);
        fs20sendBits(house >> 8, 8);
        fs20sendBits(house, 8);
        fs20sendBits(addr, 8);
        fs20sendBits(cmd, 8);
        fs20sendBits(sum, 8);
        fs20sendBits(0, 1);
        delay(10);
    }
}

static void kakuSend(char addr, byte device, byte on) {
    int cmd = 0x600 | ((device - 1) << 4) | ((addr - 1) & 0xF);
    if (on)
        cmd |= 0x800;
    for (byte i = 0; i < 4; ++i) {
        for (byte bit = 0; bit < 12; ++bit) {
            ookPulse(375, 1125);
            int on = bitRead(cmd, bit) ? 1125 : 375;
            ookPulse(on, 1500 - on);
        }
        ookPulse(375, 375);
        delay(11); // approximate
    }
}

#endif
