 #endif
 
 static unsigned long now () {
-  // FIXME 49-day overflow
-  return millis() / 1000;
+    // FIXME 49-day overflow
+    return millis() / 1000;
 }
 
 static void activityLed (byte on) {
 #ifdef LED_PIN
-  pinMode(LED_PIN, OUTPUT);
-  digitalWrite(LED_PIN, !on);
+    pinMode(LED_PIN, OUTPUT);
+    digitalWrite(LED_PIN, !on);
 #endif
 }
 

//
// With thanks for the inspiration by 2006 David A. Mellis and his AFSoftSerial code
//  All right reserved.
// Connect Tiny84 PA2 to USB-BUB TXD for serial input to sketch.    // Jeenode DIO2
// 9600 or 38400 at present.

#if SERIAL_BAUD == 9600
#define BITDELAY 54      // 9k6 @ 8MHz, 19k2 @16MHz
#endif
#if SERIAL_BAUD == 38400
#define BITDELAY 11     // 38k4 @ 8MHz, 76k8 @16MHz
#endif

#define MAX_NODES 14

}

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
}

