/* ******************************************************************************
 * 	VSCP (Very Simple Control Protocol) 
 * 	http://www.vscp.org
 * 	akhe@eurosource.se
 *
 *  Copyright (C) 1995-2006 Ake Hedman, eurosource
 *  Copyright (C) 2014 David Steeman, www.steeman.be
 *
 *  Changelog:
 *  Mespelare_v1.2:
 *      - adapted Hasselt firmware for Mespelare module (vscp_node_defines.h)
 *
 *  Mespelare_v1.3:
 *      - test for upgrading to XC8 (didn't work)
 *
 *  Mespelare_v1.4:
 *      - upgraded to XC8 compiler (but relocate functionality for boot loader removed)
 *      - upgraded to latest vscp_firmware (20140101)
 *      - DoDM(), ActionOn/Off/Toggle() tested, SetOut() tested
 *      - (input buttons work, send events)
 *
 *  Mespelare_v1.5:
 *      - write doActionPulse() function - tested
 *
 *  Mespelare_v1.6:
 *      - consolidate tick_10ms and counter_10ms into a single counter - tested but input buttons broken
 *      - modify code to support additional outputs 8-14
 *          - MDF mesp10.xml, vscp_node_defines_10 - uses paginated registers - issue!
 *          - MDF mesp11.xml, vscp_node_defines_11 as temp workaround arounf pagination issue - tested
 *      - add functionality (register, action) for buzzer - tested (buzzer = output 15)
 *      - make PERMANENT_NICK user definable - tested
 *
 *  Mespelare_v1.7:
 *      - added 1ms timer to timer0 interrupt routine to support PWM routine - tested
 *      - consolidate tick_10ms and counter_10ms into a single counter - tested / in v1.7 there is doubt so rolled back
 *
 *  Mespelare_v1.8:
 *      - allow outputs to be PWM controlled (to dim LEDs) - PWM_output() function - tested and works (crudely) but room for improvement
 *
 *  Mespelare_v1.9:
 *      - support extended page read/write / implement sendCANFrame() timeout functionality as per Ake's mail
 *
 *  Mespelare_v1.13: (based on v1.9)
 *      - added functionality to allow inputs to switch outputs directly in application code ( ActuateUponLocalEvent() ) - tested
 *      - fixed PulseOut() indexing (consistent use of "i + 1")
 *      - bug in pulsing of output 10 - no falling edge - to fix
 *
 *  Mespelare_v1.14: (based on v1.14)
 *      - check and possibly remove unwanted functionality (relay protection timer, PWM Kurt's code)
 *      - bug in pulsing of output 10 - no falling edge - to fix
 *      - bug in ProcessInputs() - triggers wrong events - to fix
 *      - fixed bug in Handle PulseOut() logic
 *
 *  Mespelare_v1.16: (based on v1.14) - production dd. 17 May 2015
 *      - changed CAN speed to 125kbps ( in vscp18f_init() )
 *      - test Steve's bootloader work
 *      - fixed bug in ActuateUponLocalEvent (>=0)
 *
 *  Mespelare_v1.16b: (based on v1.14)
 *      - inverted O8-14 state
 *
 *  Mespelare_v1.19: (based on v1.16b) - production dd 01. Jun 2015
 *      - Make doActionPulse reply with SendInformationEvent (through DM and through local input event handling)
 *
 *
 *  To do:
 *      - upgrade to ECAN
 *      - split vscp_node_defines.h into vscp_node_defines.h and vscp_node_registers.h
 *	- include boot loader (https://github.com/grodansparadis/vscp_firmware/tree/master/pic/bootloader/Microchip/vscp_can_bootloader_18f)
 *      - loop send and receive events so that a node can receive is own events - possibly introduce circular tx and rx buffers in application code
 *
 *
 * This software is provided 'as-is', without any express or implied
 * warranty.  In no event will the authors be held liable for any damages
 * arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must not
 *    claim that you wrote the original software. If you use this software
 *    in a product, an acknowledgment in the product documentation would be
 *    appreciated but is not required.
 * 2. Altered source versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.
 * 3. This notice may not be removed or altered from any source distribution.
 * 
 *	This file is part of VSCP - Very Simple Control Protocol 	
 *	http://www.vscp.org
 *
 * ******************************************************************************
 *
 * This software is part of the VSCP node 'Mespelare'
 * Based on original VSCP source code of 'Paris' copyright by Ake Hedman
 * 
 * ******************************************************************************
*/

#define MESPELARE_V9   // node hardware board version

//debug defines. For production builds, comment these out.
//#define PERMANENT_NICK  0xF2 //This sets a permanent nickname irrespective of what is in EEPROM
//#define DEBUG         //david: debugging mode on
#ifdef DEBUG
#define DEBUG_DEBUGPIN  // use a spare pin on the microcontroller for debugging (defined in vscp_node_defines.h)
#define SERIAL_DEBUG //david: enable debugging via serial port (9k6 8n1 no flow). Uses pin INP7
#ifdef SERIAL_DEBUG
//#define SERIAL_DEBUG_DUMPEEPROM //david: enable DumpEEPROM() function, dumps EEPROM contents to USART
//#define SERIAL_DEBUG_RW_APP_REG //david: enable vscp_readAppReg() and vscp_writeAppReg() debugging
//#define SERIAL_DEBUG_DM  //david: enable debug info for DoDM()
//#define SERIAL_DEBUG_DM_ACTIONS
#define SERIAL_DEBUG_INPUTS  //david: enable debug info on input status changes
//#define SERIAL_DEBUG_VSCP_INIT  //david: debug VSCP protocol init functionality
//#define SERIAL_DEBUG_TICK_10MS  //debug tick_10ms counter
//#define SERIAL_DEBUG_PWM_OUTPUTS    //debug output PWM'ing
//#define SERIAL_DEBUG_SENDCANFRAME   //debug sendCANFrame() function, timeout
//#define SERIAL_DEBUG_OUTPUTS    //debug outputs
//#define DEBUG_PULSEOUT
//#define SERIAL_DEBUG_ActuateUponLocalEvent
#endif
#endif

#include <xc.h>
#include <timers.h>

#ifdef SERIAL_DEBUG
    #include <usart.h> // Include function definitions for the USART library
    #include <stdio.h>
#endif

#include "eeprom.h"         //copied common files to local common directory since checking out whole SVN is huge
#include "can18F66K80.h"
#include "vscp_firmware.h"  //copied common files to local
#include "vscp_class.h"     //copied common files to local
#include "vscp_type.h"      //copied common files to local

#ifdef MESPELARE_V6
#include "VSCP_node_defines_06.h"
#endif
#ifdef MESPELARE_V9
#include "VSCP_node_defines_14.h"
#endif

#include "main.h" 
#include <delays.h>   //david xxx Needed for Delay10KTCYx() function to make buzzer beep at startup and OneWire


/* --- configure DS1820 temperature sensor --- */
//#include "types.h"
//#include "ds1820.h"
//#include "ow.h"
//#include "ds18s20.h"

#if defined(__18F25K80) || defined(__18F26K80) || defined(__18F45K80) || defined(__18F46K80) || defined(__18F65K80) || defined(__18F66K80)
#pragma config FOSC = HS1 //INTIO1 //HS1
#pragma config PLLCFG = ON
#pragma config SOSCSEL = DIG
#pragma config PWRTEN = ON
#pragma config STVREN = ON
#pragma config CPB = OFF
#pragma config CANMX = PORTB
#pragma config XINST = OFF
#if defined(RELEASE)
#pragma config WDTEN = ON
#pragma config BOREN = ON
#pragma config BORV = 3
#else
#pragma config WDTEN = OFF
#pragma config BOREN = OFF
#pragma config BORV = 3
#endif
#endif


void FillEEPROM(void);
void DumpEEPROM(void);
void DumpDM(void);
void daf_puts1USART ( char *data);
void daf_putrs1USART ( const MEM_MODEL char *data);


// The device URL (max 32 characters including null termination)
const uint8_t vscp_deviceURL[] = "192.168.1.245/mesp14b.xml";

volatile unsigned long measurement_clock;	// Clock for measurements
uint8_t tick_10ms;                       // General purpose 10ms clock counter, used for DoWork()
uint8_t counter_10ms;                    // General purpose 10ms clock counter, used for PulseOut()
uint8_t counter_1ms;                     // General purpose 10ms clock counter
uint8_t counter_1_to_10ms = 0;           // Counter used to generate counter_10ms from 1ms interrupt
uint8_t counter_10ms_doWork;

// Used for PWM'ing outputs
uint8_t counter_PWM = 0;
uint8_t PWM_reg = 0;
BOOL PWM_done = FALSE;
BOOL output_on[15];

struct PulseOutputStruct {
    BOOL Active;                     // Channel is being pulsed
    unsigned short Counter;          // Pulse duration counter for PulseOut()
    BOOL Status;                     // Output status, OUTPUT_ON or OUTPUT_OFF
} OutputVar[15];

char seconds;					// counter for seconds
char minutes;					// counter for minutes
char hours;					// Counter for hours

uint8_t sendTimer = 0;                   // timer for sendCANFrame() function


uint8_t counter;
uint16_t Timer1Reload = 45000;

unsigned short INP_state[8];
unsigned short INP_hold_timer[8];

static uint8_t BufferINP1 = 0;
static uint8_t BufferINP2 = 0;
static uint8_t BufferINP3 = 0;
static uint8_t BufferINP4 = 0;
static uint8_t BufferINP5 = 0;
static uint8_t BufferINP6 = 0;
static uint8_t BufferINP7 = 0;
static uint8_t BufferINP8 = 0;

#ifdef SERIAL_DEBUG
char debugstring[80];
#endif

void SoundBuzzer(void);
void ToggleOutputs(void);


///////////////////////////////////////////////////////////////////////////////
// Isr() 	- Interrupt Service Routine
//      	- Services Timer0 Overflow
//////////////////////////////////////////////////////////////////////////////

void interrupt low_priority isr_low( void ){
	//if ( PIR1bits.TMR2IF ) {	// If a Timer2 Interrupt, Then...
	if ( INTCONbits.TMR0IF ) {	// If a Timer0 overflow Interrupt, Then...
            counter_1ms++;
            // put 1ms work here
//            PWM_outputs();

            counter_1_to_10ms++;
            if ( counter_1_to_10ms >= 10 ) {        // if 10ms have expired
                counter_1_to_10ms = 0;              // reset counter for next pass

                //put 10ms work here
#ifdef DEBUG_DEBUGPIN_DISABLED
            DEBUG_PIN = ~DEBUG_PIN;     // toggle pin
#endif

                vscp_timer++;
                measurement_clock++;
                tick_10ms++;
                counter_10ms++;

                // Check for init INP
                if ( !INIT_BUTTON ) {
                    vscp_initbtncnt++;
                    if (vscp_initbtncnt>100) {
                        vscp_initbtncnt = 101;
                    }
                }

                // Status LED
                vscp_statuscnt++;
                if ( ( VSCP_LED_BLINK1 == vscp_initledfunc ) && ( vscp_statuscnt > 100 ) ) {
                    if ( INIT_LED ) {
                        INIT_LED = 0;
                    }
                    else {
                        INIT_LED = 1;
                    }
                    vscp_statuscnt = 0;
                }
                else if ( VSCP_LED_ON == vscp_initledfunc ) {
                    INIT_LED = 0;
                    vscp_statuscnt = 0;
                }
                else if ( VSCP_LED_OFF == vscp_initledfunc ) {
                    INIT_LED = 1;
                    vscp_statuscnt = 0;
                }
            }

            //PIR1bits.TMR2IF = 0;     // Clear Timer2 Interrupt Flag
            Timer1Reload = Timer1Reload + 10;
            if (Timer1Reload >= 64000) {
                Timer1Reload = 45000;
            }

            WriteTimer0(Timer0ReloadValue);
            INTCONbits.TMR0IF = 0; //clear overflow IRQ
	}
	return;
}


///////////////////////////////////////////////////////////////////////////////
// Isr() 	- Interrupt Service Routine (high)
//      	- Services Timer1 Overflow for sound generation
//////////////////////////////////////////////////////////////////////////////

void interrupt isr_high (void) {
/*    if (PIR1bits.TMR1IF) {
        LATCbits.LATC0 = !LATCbits.LATC0; //temporary to test audio generation  // David: C0 = OUT?
        WriteTimer1(Timer1Reload);
        PIR1bits.TMR1IF = 0;
    }
*/
}



//***************************************************************************
// Main() - Main Routine
//***************************************************************************
void main()
{
    unsigned char a;
    unsigned int i;
    unsigned char keyval;
//    BOOL bOn = FALSE;
//    unsigned char shortpress;

    init();                 // Initialize Microcontroller

    SoundBuzzer();          // Sound the buzzer at startup, debug

#ifdef SERIAL_DEBUG_VSCP_INIT
    daf_putrs1USART("\r\nEntering vscp_init() when starting main()");
#endif

    vscp_init();		// Initialize the VSCP functionality

//  FillEEPROM();
        
#ifdef SERIAL_DEBUG
    sprintf(debugstring, "\r\n\r\n*****START MAIN*****\r\nvscp_deviceURL[] = ");
    daf_puts1USART(debugstring);
    daf_putrs1USART(vscp_deviceURL);
    sprintf(debugstring, "\r\nSoftware version %d.%d.%d, nickname 0x%02x",
        FIRMWARE_MAJOR_VERSION, FIRMWARE_MINOR_VERSION, FIRMWARE_SUB_MINOR_VERSION, vscp_nickname);
    daf_puts1USART(debugstring);
    daf_putrs1USART("\r\n");
#endif

#ifdef SERIAL_DEBUG_PWM_OUTPUTS
    sprintf(debugstring, "\r\nTEST_PWM_OUT1: %d", PWM_reg );
    daf_puts1USART(debugstring);
#endif

    while ( 1 ) {           // Loop Forever
#ifdef DEBUG_DEBUGPIN_DISABLED
        DEBUG_PIN = ~DEBUG_PIN; // toggle debugpin
#endif

        // *** Clear watchdog ***
        ClrWdt();			// Feed the dog

        // *** handle init button ***
        // Updated init INP code
        if (INIT_BUTTON) {  // button released
#ifdef SERIAL_DEBUG_DUMPEEPROM
            if (( vscp_initbtncnt > 51 ) ) {           //if INIT_BUTTON was held (and released)
                daf_putrs1USART("\r\nINIT_BUTTON held");
//              ToggleOutputs();        // toggle outputs on and off again
//              DumpDM();               // dump DM EEPROM contents to USART
//                DumpEEPROM();           // dump EEPROM contents to USART
            }
#endif
            if (( vscp_initbtncnt > 100 ) && ( VSCP_STATE_INIT != vscp_node_state ) ) {
                vscp_nickname = VSCP_ADDRESS_FREE;
                writeEEPROM( VSCP_EEPROM_NICKNAME, VSCP_ADDRESS_FREE );
#ifdef SERIAL_DEBUG_VSCP_INIT
                daf_putrs1USART("\r\nEntering vscp_init() from INIT state in main()");
#endif
      		vscp_init();
            }
            if (( vscp_initbtncnt > 51 ) && ( VSCP_STATE_ACTIVE == vscp_node_state ) ) {
              SendProbeAck(vscp_initbtncnt); 
            }
            vscp_initbtncnt = 0;
	}

	// *** Check for a valid  event***
	vscp_imsg.flags = 0;
	vscp_getEvent();

	// *** one second clock ***
	if ( measurement_clock > 100 ) {                                // every second
            measurement_clock = 0;
            // Do VSCP one second jobs
            vscp_doOneSecondWork();

            if ( VSCP_STATE_ACTIVE == vscp_node_state  ) {
                // Do application one second jobs
		doApplicationOneSecondWork();	
            }
	}	
		
        // *** handle time counters ***
	if ( seconds > 59 ) {
            seconds = 0;
            minutes++;
            if ( minutes > 59 ) {
                minutes = 0;
                hours++;
            }
            if ( hours > 23 ) {
                hours = 0;
            }
	}

        // *** Handle VSCP node state logic
	switch ( vscp_node_state ) {
            case VSCP_STATE_STARTUP:			// Cold/warm reset
#ifdef SERIAL_DEBUG_VSCP_INIT
            daf_putrs1USART("\r\nEntering switch(vscp_node_state), case VSCP_STATE_STATUP");
#endif
                // Get nickname from EEPROM
		if ( VSCP_ADDRESS_FREE == vscp_nickname ) {
                    // new on segment need a nickname
                    vscp_node_state = VSCP_STATE_INIT;
#ifdef SERIAL_DEBUG_VSCP_INIT
    daf_putrs1USART("\r\nvscp_node_state = VSCP_STATE_INIT");
#endif
                }
		else {
                    // been here before - go on
#ifdef SERIAL_DEBUG_VSCP_INIT
    daf_putrs1USART("\r\nvscp_node_state = VSCP_STATE_ACTIVE, vscp_goActiveState()");
#endif
                    vscp_node_state = VSCP_STATE_ACTIVE;
                    vscp_goActiveState();
		}
		break;

            case VSCP_STATE_INIT:			// Assigning nickname
#ifdef SERIAL_DEBUG_VSCP_INIT
    daf_putrs1USART("\r\ncase VSCP_STATE_INIT, vscp_handleProbeState()");
#endif
		vscp_handleProbeState();
		break;

            case VSCP_STATE_PREACTIVE:		// Waiting for host initialisation
                vscp_goActiveState();
		break;

            case VSCP_STATE_ACTIVE:			// The normal state
                if ( vscp_imsg.flags & VSCP_VALID_MSG ) {	// incoming message?
                    vscp_handleProtocolEvent();
                    doDM();
		}
		break;

            case VSCP_STATE_ERROR:			// Everything is *very* *very* bad.
                vscp_error();
		break;

            default:					// Should not be here...
                vscp_node_state = VSCP_STATE_STARTUP;
		break;
        }

        // *** do application work
	doWork();

    } // end while
} // end main



void SoundBuzzer(void) { // david
    BUZZER = 1;
    Delay10KTCYx(500);
    BUZZER = 0;
    Delay10KTCYx(100);
}

void ToggleOutputs(void) {
    unsigned int delay=100;

    OUT1 = 1; Delay10KTCYx(delay);
    OUT2 = 1; Delay10KTCYx(delay);
    OUT3 = 1; Delay10KTCYx(delay);
    OUT4 = 1; Delay10KTCYx(delay);
    OUT5 = 1; Delay10KTCYx(delay);
    OUT6 = 1; Delay10KTCYx(delay);
    OUT7 = 1; Delay10KTCYx(delay);
    OUT8 = 1; Delay10KTCYx(delay);
    OUT9 = 1; Delay10KTCYx(delay);
    OUT10 = 1; Delay10KTCYx(delay);
    OUT11 = 1; Delay10KTCYx(delay);
    OUT12 = 1; Delay10KTCYx(delay);
    OUT13 = 1; Delay10KTCYx(delay);
    OUT14 = 1; Delay10KTCYx(delay);
    OUT15 = 1;
    Delay10KTCYx(500);
    OUT1 = 0; Delay10KTCYx(delay);
    OUT2 = 0; Delay10KTCYx(delay);
    OUT3 = 0; Delay10KTCYx(delay);
    OUT4 = 0; Delay10KTCYx(delay);
    OUT5 = 0; Delay10KTCYx(delay);
    OUT6 = 0; Delay10KTCYx(delay);
    OUT7 = 0; Delay10KTCYx(delay);
    OUT8 = 0; Delay10KTCYx(delay);
    OUT9 = 0; Delay10KTCYx(delay);
    OUT10 = 0; Delay10KTCYx(delay);
    OUT11 = 0; Delay10KTCYx(delay);
    OUT12 = 0; Delay10KTCYx(delay);
    OUT13 = 0; Delay10KTCYx(delay);
    OUT14 = 0; Delay10KTCYx(delay);
    OUT15 = 0;
}

void DumpDM(void) {
#ifdef SERIAL_DEBUG
    unsigned int i;
    
    daf_putrs1USART("\r\nDumpDM() reading from EEPROM");
    for (i=0; i< DESCISION_MATRIX_ELEMENTS; i++) {
        sprintf(debugstring,
            "\r\nRow=%1i, oaddr=0x%02x, dmflags=0x%02x, class_mask=0x%02x, ",
            i,
            readEEPROM(VSCP_EEPROM_END + REG_DESCISION_MATRIX + (8*i) + VSCP_DM_POS_OADDR),
            readEEPROM(VSCP_EEPROM_END + REG_DESCISION_MATRIX + (8*i) + VSCP_DM_POS_FLAGS),
            readEEPROM(VSCP_EEPROM_END + REG_DESCISION_MATRIX + (8*i) + VSCP_DM_POS_CLASSMASK)
        );
        daf_puts1USART(debugstring);
        sprintf(debugstring,
            "class_filter=0x%02x, type_mask=0x%02x, type_filter=0x%02x, ",
            readEEPROM(VSCP_EEPROM_END + REG_DESCISION_MATRIX + (8*i) + VSCP_DM_POS_CLASSFILTER),
            readEEPROM(VSCP_EEPROM_END + REG_DESCISION_MATRIX + (8*i) + VSCP_DM_POS_TYPEMASK),
            readEEPROM(VSCP_EEPROM_END + REG_DESCISION_MATRIX + (8*i) + VSCP_DM_POS_TYPEFILTER)
        );
        daf_puts1USART(debugstring);
        sprintf(debugstring,
            " action=0x%02x, action_param=0x%02x",
            readEEPROM(VSCP_EEPROM_END + REG_DESCISION_MATRIX + (8*i) + VSCP_DM_POS_ACTION),
            readEEPROM(VSCP_EEPROM_END + REG_DESCISION_MATRIX + (8*i) + VSCP_DM_POS_ACTIONPARAM)
        );
        daf_puts1USART(debugstring);
    }
#endif
}



///////////////////////////////////////////////////////////////////////////////
// PWM_outputs - fast switches outputs according to a defined PWM value
// Intended purpose: being able to dim indicator LEDs on illuminated switches
//
void PWM_outputs( void ) {  //TODO: works crudely but room for improvement
    if ( counter_PWM > 9) {
        counter_PWM = 0;
        PWM_done = FALSE;
    }
    if ( counter_PWM == 0 && PWM_reg > 0) {     // first pass, make rising edge of pulse
        if (output_on[0] != 0)   SetOut(0, OUTPUT_ON, FALSE);   // if output has been switched on, set rising edge of pulse
        if (output_on[1] != 0)   SetOut(1, OUTPUT_ON, FALSE);
        if (output_on[2] != 0)   SetOut(2, OUTPUT_ON, FALSE);
        if (output_on[3] != 0)   SetOut(3, OUTPUT_ON, FALSE);
        if (output_on[4] != 0)   SetOut(4, OUTPUT_ON, FALSE);
        if (output_on[5] != 0)   SetOut(5, OUTPUT_ON, FALSE);
    }
    if ( counter_PWM > PWM_reg && !PWM_done ) {   // falling edge
        SetOut(0, OUTPUT_OFF, FALSE);
        SetOut(1, OUTPUT_OFF, FALSE);
        SetOut(2, OUTPUT_OFF, FALSE);
        SetOut(3, OUTPUT_OFF, FALSE);
        SetOut(4, OUTPUT_OFF, FALSE);
        SetOut(5, OUTPUT_OFF, FALSE);
        PWM_done = TRUE;
    }
    counter_PWM++;
}


///////////////////////////////////////////////////////////////////////////////
// Init - Initialization Routine
//  

void init()
{
//    char msgdata[ 8 ];

    // Initialize data
    OSCCON = 0b01110000;
    OSCTUNE = 0b01000000;

    // Initialize the TRIS registers. 0 is output, 1 is input
    //   pins 76543210
#ifdef MESPELARE_V6
    TRISA = 0b00000000;                                                     // Hasselt: 0b11000000;
    TRISB = 0b11111011;                                                     // Hasselt: 0b11001100;
    TRISC = 0b01000000;                                                     // Hasselt: not set
    TRISD = 0b10000000;                                                     // Hasselt: 0b11111110;
    TRISE = 0b00000000;                                                     // Hasselt: not set
#endif
#ifdef MESPELARE_V9
    TRISA = 0b00000000;
    TRISB = 0b01111011;
    TRISC = 0b11000000;
    TRISD = 0b10000000;
    TRISE = 0b00000000;
#endif

#ifdef SERIAL_DEBUG  //david: enable serial debugging
    // baud rate calculator: http://dkitsch.com/pic-spbrg-baud-rate-calculator/
    TRISCbits.TRISC6 = 0; //TX pin set as output

    Open1USART(USART_TX_INT_OFF & USART_RX_INT_OFF & USART_ASYNCH_MODE & USART_EIGHT_BIT &
//               USART_BRGH_LOW, 51); //9600 baud - error 0,16% - works
//               USART_BRGH_LOW, 16);  //28800 baud - error 2.12% - works
//               USART_BRGH_LOW, 12);  //38400 baud - error 0.16% - works
               USART_BRGH_LOW, 8);  //57600 baud - error 3.55%- works
//               USART_BRGH_LOW, 3);  //115200 baud - error 8.5% - frame error too high?
#endif

    INIT_LED = 1; // Status LED on

    init_app_ram();

    // Timer 0 used as 10ms clock tick
    OpenTimer0( TIMER_INT_ON &
                T0_16BIT &
		Timer0Prescaler &
		T0_SOURCE_INT );
        
    WriteTimer0(Timer0ReloadValue);
    // Timer 1 used as sound generator using high interrupt
    WriteTimer1(61000);
    /*OpenTimer1( TIMER_INT_ON &
                    T1_16BIT_RW &
                    T1_SOURCE_FOSC &
                    T1_PS_1_1,0 );
        */
    WriteTimer1(61000);

    RCONbits.IPEN = 1;              //enable prioritized interrupts
    INTCONbits.GIEH = 1;            //enable high priority interrupts
    INTCONbits.GIEL = 1;            //enable low priority interrupts
    INTCON2bits.TMR0IP = 0;         //TMR0 overflow = low interrupt
    IPR1bits.TMR1IP = 1;            //TMR1 overflow = high interrupt
        
    //IPR1bits.TMR2IP = 1;          //assign low priority to TMR2 interrupt
    //PIE1bits.TMR2IE=1;            //enable Timer2 interrupt
    //INTCONbits.PEIE = 1;          // Enable peripheral interrupt
    //INTCONbits.GIE = 1;           // Enable global interrupt

    vscp18f_init( TRUE );
	
    // set multiplexed I/O / AD pins to I/O mode
    ANCON0 = 0;                     //set all pins to digital I/O
    ANCON1 = 0;                     //set all pins to digital I/O

    // Enable peripheral interrupt
	
    // EnableCAN Receive Error Interrupt
    //PIE3bits.IRXIE = 1;

    return;
}

///////////////////////////////////////////////////////////////////////////////
// init_app_ram
//

void init_app_ram( void )
{
    unsigned int i;
	
    measurement_clock = 0;	// start a new mezsurement cycle
	
    for ( i=0; i<8 ; i++) {  // initialize input (button) variables
        INP_hold_timer[i] = 0;
	INP_state[i] = INP_RELEASED;
    }

    for ( i=0; i<15 ; i++) {
        SetOut(i, OUTPUT_OFF, TRUE); // set outputs to default.
        OutputVar[i].Status = OUTPUT_OFF; // reset output status
        OutputVar[i].Active = FALSE;   // reset pulse handling logic
        output_on[i] = FALSE;               // reset output status
    }

    seconds = 0;
    minutes = 0;
    hours = 0;

    PWM_reg = readEEPROM( VSCP_EEPROM_END + PWM_OUT );    // set output PWM initial value
}
 

///////////////////////////////////////////////////////////////////////////////
// init_app_eeprom
//

void init_app_eeprom( void )
{
    unsigned char i,j;
	
    for ( i=0 ; i<15; i++){
        writeEEPROM( VSCP_EEPROM_END + REG_STATUS_OUT1 + i, 0);  //Set all output registers to off
        SetOut(i, OUTPUT_OFF, TRUE); // Actually set the outputs to off
        writeEEPROM( VSCP_EEPROM_END + REG_SUBZONE_OUT1 + i, 0); //set all subzones to zero
        writeEEPROM( VSCP_EEPROM_END + REG_CONTROL_OUT1 + i, RELAY_CONTROLBIT_ONEVENT | RELAY_CONTROLBIT_OFFEVENT | RELAY_CONTROLBIT_ENABLED); //enable all outputs & have them send on/off event. No protection timer as most likely the outputs are indicator leds.
    }
         
    // * * * Decision Matrix * * *
    // All elements disabled.
    for ( i=0; i<DESCISION_MATRIX_ELEMENTS; i++ ) {
        for ( j=0; j<8; j++ ) {
            writeEEPROM( VSCP_EEPROM_END + REG_DESCISION_MATRIX + i*8 + j, 0 );
	}
    }
}

/*void readTemp(void) {
    char testdata1,testdata2;

    Delay100TCYx(30);
    ow_write_byte(0xCC);
    Delay100TCYx(1);
    ow_write_byte(0x44);
    Delay10KTCYx(255);
    Delay10KTCYx(255);
    ow_reset();
    Delay100TCYx(30);
    ow_write_byte(0xCC);
    Delay100TCYx(1);
    ow_write_byte(0xBE);
    Delay100TCYx(1);
    testdata1=ow_read_byte();
    Delay10TCYx(1);
    testdata2=ow_read_byte();
    ow_reset();
    Delay10KTCYx(255);

    sprintf(debugstring, "\r\ntemp: %c %c", testdata1, testdata2 );
    daf_puts1USART(debugstring);
}
*/

///////////////////////////////////////////////////////////////////////////////
// doApplicationOneSecondWork
//

void doApplicationOneSecondWork( void )
{
    unsigned char i;
    unsigned char controlbits;

    sendTimer++;        // timer for sendCANFrame() function

#ifdef SERIAL_DEBUG
//    daf_putrs1USART("\r\n-->Entering doApplicationOneSecondWork");
    daf_putrs1USART("."); //output one dot per second to the terminal (crude timestamp indication)
#endif

/*    if ( DS1820_FindFirstDevice() ) {
        daf_putrs1USART("\r\nDS1820 device found");
    }

    sprintf(debugstring, "\r\ntemp: %f", DS1820_GetTempFloat() );
    daf_puts1USART(debugstring);
*/
//    readTemp();
    
    for ( i=0; i<15; i++ ) {
        controlbits = readEEPROM( VSCP_EEPROM_END + REG_CONTROL_OUT1 + i ); // Read control bits for this output
/*
#ifdef SERIAL_DEBUG  
    sprintf(debugstring, 
        "\r\ni=%2i, controlbits=0x%2x, REG_CONTROL_OUT1+i=0x%2x, %2i",
        (int)i, controlbits, REG_CONTROL_OUT1+i, REG_CONTROL_OUT1+i);
    daf_puts1USART(debugstring);
#endif
*/
    }
}
 

///////////////////////////////////////////////////////////////////////////////
// Get Major version number for this hardware module
//
unsigned char getMajorVersion()
{
    return FIRMWARE_MAJOR_VERSION;
}

///////////////////////////////////////////////////////////////////////////////
// Get Minor version number for this hardware module
//
unsigned char getMinorVersion()
{
    return FIRMWARE_MINOR_VERSION;
}

///////////////////////////////////////////////////////////////////////////////
// Get Subminor version number for this hardware module
//
unsigned char getSubMinorVersion()
{
    return FIRMWARE_SUB_MINOR_VERSION;
}

///////////////////////////////////////////////////////////////////////////////
// Get GUID from EEPROM
//
#ifdef GUID_IN_EEPROM
unsigned char getGuidFromEEprom( unsigned char idx )
{
    readEEPROM( EEPROM_REG_GUIID0 + idx );
}
#endif

///////////////////////////////////////////////////////////////////////////////
// Get Manufacturer id and subid from EEPROM
//
#ifdef MANUFACTURER_INFO_IN_EEPROM
unsigned char getManufacturerIdFromEEprom( unsigned char idx )
{
    readEEPROM( EEPROM_REG_MANUFACTUR_ID0 + idx );
}
#endif

///////////////////////////////////////////////////////////////////////////////
// Get the bootloader algorithm code
//
unsigned char getBootLoaderAlgorithm( void ) 
{
    return VSCP_BOOTLOADER_PIC1;
}

///////////////////////////////////////////////////////////////////////////////
// Get the buffer size
//
unsigned char getBufferSize( void ) 
{
    return 8;	// Standard CAN frame
}


///////////////////////////////////////////////////////////////////////////////
//  vscp_readNicknamePermanent
//
uint8_t vscp_readNicknamePermanent( void )
{
    unsigned int nickname;

#ifdef SERIAL_DEBUG_VSCP_INIT
    daf_putrs1USART("\r\nvEntered vscp_readNicknamePermanent()");
#endif

    nickname = readEEPROM( VSCP_EEPROM_NICKNAME );
#ifdef PERMANENT_NICK
    nickname = PERMANENT_NICK;                                          //This sets a permanent nickname irrispective of what is in EEPROM
#endif                                                                  //because this is oftwen overwritten when debugging, which is annoying
                                                                        //TODO: remove this line when ready debugging
    if (nickname == 0xff) nickname = readFPM(VSCP_FPM_DEFAULT_NICK);
    return nickname;
}


///////////////////////////////////////////////////////////////////////////////
//  vscp_writeNicknamePermanent
//
void vscp_writeNicknamePermanent( uint8_t nickname )
{
    writeEEPROM( VSCP_EEPROM_NICKNAME, nickname );
}

///////////////////////////////////////////////////////////////////////////////
// vscp_getZone
//
uint8_t vscp_getZone( void )
{
    return readEEPROM( VSCP_EEPROM_END + EEPROM_ZONE );
}

///////////////////////////////////////////////////////////////////////////////
// vscp_getSubzone
//
uint8_t vscp_getSubzone( void )
{
    return readEEPROM( VSCP_EEPROM_END + EEPROM_SUBZONE );
}

///////////////////////////////////////////////////////////////////////////////
// doWork
//
// The actual work is done here.
//

void doWork( void )
{
    uint8_t i;

    if ( VSCP_STATE_ACTIVE == vscp_node_state ) {
        if ( tick_10ms > 0) {                                         //execute every 10 ms

            tick_10ms = 0;

#ifdef DEBUG_DEBUGPIN
        DEBUG_PIN = ~DEBUG_PIN; // toggle debugpin
#endif

            // *** Handle input debouncing
            ProcessInputs();                                            // input debounce

            // *** Handle PulseOut() logic
            for (i=0; i<15; i++) {           // for each output
                if ( OutputVar[i].Active ) {// if channel is currently in the middle of a pulse
#ifdef DEBUG_PULSEOUT
    sprintf(debugstring, "\r\nHandle PulseOut() logic, counter: %d, %d: ( OutputVar[ %d ].Counter + PULSE_OUT_PERIOD )%%256",
                        counter_10ms, ( OutputVar[i].Counter + PULSE_OUT_PERIOD )%256, i );
    daf_puts1USART(debugstring);
#endif
                    if ( counter_10ms == ( OutputVar[i].Counter + PULSE_OUT_PERIOD )%256 ||    // if at least 10 * 10ms has elapsed
                         counter_10ms == ( OutputVar[i].Counter + PULSE_OUT_PERIOD + 1 )%256 ||   // allow 5*10ms window incase the above condition didn't catch
                         counter_10ms == ( OutputVar[i].Counter + PULSE_OUT_PERIOD + 2 )%256 ||   // allow 5*10ms window incase the above condition didn't catch
                         counter_10ms == ( OutputVar[i].Counter + PULSE_OUT_PERIOD + 3 )%256 ||   // allow 5*10ms window incase the above condition didn't catch
                         counter_10ms == ( OutputVar[i].Counter + PULSE_OUT_PERIOD + 4 )%256 )    // allow 5*10ms window incase the above condition didn't catch
                    {
                        OutputVar[i].Active = FALSE;   // done pulsing, reset pulse status for output
                        SetOut(i, OUTPUT_OFF, FALSE);        // Switch output off = falling edge of pulse
                    } // end if
                } // end if
            } // end for
         } //end if 10ms
    }
}

///////////////////////////////////////////////////////////////////////////////
// vscp_readAppReg
//
uint8_t vscp_readAppReg( uint8_t reg )
{
    uint8_t rv;
//  int tmpval;
//  unsigned char val, checksum;
    uint16_t userreg;

    rv = 0x00; // default return value
    userreg = reg + (vscp_page_select * 128);           // handle register pagination (see Register Abstraction Model)

    switch (userreg) {
        case REG_STATUS_OUT1:
        case REG_STATUS_OUT2:
        case REG_STATUS_OUT3:
        case REG_STATUS_OUT4:
        case REG_STATUS_OUT5:
        case REG_STATUS_OUT6:
        case REG_STATUS_OUT7:
        case REG_STATUS_OUT8:
        case REG_STATUS_OUT9:
        case REG_STATUS_OUT10:
        case REG_STATUS_OUT11:
        case REG_STATUS_OUT12:
        case REG_STATUS_OUT13:
        case REG_STATUS_OUT14:
        case REG_STATUS_OUT15:
            rv = ReadOut( userreg - (REG_STATUS_OUT1) );   // these registers only show status and are not in EEPROM
#ifdef SERIAL_DEBUG_RW_APP_REG
            daf_putrs1USART("\r\nCHECK READ");
#endif
            break;
        default:   
            if ( userreg <= USER_EEPROM_LAST_POS ) {
                rv = readEEPROM( VSCP_EEPROM_END + userreg );
#ifdef SERIAL_DEBUG_RW_APP_REG
    sprintf(debugstring,
            "\r\nRead app register: %02id:%02id (0x%02x:0x%02x), paginated: %02id, read value: %02id (0x%02x)",
            vscp_page_select, reg, vscp_page_select, reg, userreg, rv, rv );
    daf_puts1USART(debugstring);         //print to USART
#endif
            }
            break;
        }
	
	return rv;
}

////////    ///////////////////////////////////////////////////////////////////////
// vscp_writeAppReg
//

uint8_t vscp_writeAppReg( uint8_t reg, uint8_t val )
{
    uint8_t rv;
    uint16_t userreg;

    rv = ~val; // on error, return inverted value
    userreg = reg + (vscp_page_select * 128);           // handle register pagination (see Register Abstraction Model)

    switch (userreg) {
        case REG_STATUS_OUT1:
        case REG_STATUS_OUT2:
        case REG_STATUS_OUT3:
        case REG_STATUS_OUT4:
        case REG_STATUS_OUT5:
        case REG_STATUS_OUT6:
        case REG_STATUS_OUT7:
        case REG_STATUS_OUT8:
        case REG_STATUS_OUT9:
        case REG_STATUS_OUT10:
        case REG_STATUS_OUT11:
        case REG_STATUS_OUT12:
        case REG_STATUS_OUT13:
        case REG_STATUS_OUT14:
        case REG_STATUS_OUT15:
#ifdef SERIAL_DEBUG_RW_APP_REG
            sprintf(debugstring,
                    "\r\nvscp_writeAppReg(), reg: 0x%02x, vscp_page_select: 0x%02x, userreg: 0x%02x, value: %d.",
                  reg, vscp_page_select, userreg, val);
           daf_puts1USART(debugstring);
            sprintf(debugstring,
                   "\r\nuserreg (0x%02x) = reg (0x%02x) + (vscp_page_select (0x%02x) * 128).",
                   userreg, reg, vscp_page_select);
            daf_puts1USART(debugstring);
           sprintf(debugstring,
                  "\r\nSetOut( (userreg (0x%02x) - REG_STATUS_OUT1 (0x%02x) + 1) = 0x%02x, val (0x%02x)).",
//                  (unsigned int)userreg, (unsigned int)REG_STATUS_OUT1, (char)(((unsigned int)userreg - (unsigned int)REG_STATUS_OUT1) + 1), val);
//                  (unsigned int)userreg, 256* 0 + 82, (char)( (unsigned int)userreg - (REG_STATUS_OUT1) + 1), val );
                  (unsigned int)userreg, 256* 0 + 82, ( userreg - (REG_STATUS_OUT1) + 1), val );

            daf_puts1USART(debugstring);
#endif
            if ( 1 == val ) {
#ifdef SERIAL_DEBUG_RW_APP_REG
                daf_putrs1USART("\r\nREG_STATUS_OUT set to SetOut(1)");
#endif
                SetOut( userreg - (REG_STATUS_OUT1), OUTPUT_ON, TRUE);  // these registers only show status so no use writing them to EEPROM
/*              sprintf(debugstring,
                        "\r\nSetOut() called, reg: %02i, userreg: %02i, REG_STATUS_OUT1: %02i, output: %i, value: %i",
                        reg, userreg, REG_STATUS_OUT1, (userreg - REG_STATUS_OUT1 + 1), 1);
                daf_puts1USART(debugstring);*/
            }
            if ( 0 == val ) {
#ifdef SERIAL_DEBUG_RW_APP_REG
                daf_putrs1USART("\r\nREG_STATUS_OUT set to SetOut(0)");
#endif
                SetOut( userreg - (REG_STATUS_OUT1), OUTPUT_OFF, TRUE);  // these registers only show status so no use writing them to EEPROM
/*              sprintf(debugstring,
                        "\r\nSetOut() called, userreg: %02i, REG_STATUS_OUT1: %02i, output: %i, value: %i",
                      userreg, REG_STATUS_OUT1, (userreg - REG_STATUS_OUT1 + 1),0);
                daf_puts1USART(debugstring);*/
            }
            rv = val;  // return OK
            break;
        case PWM_OUT:
            if ( val > 10 ) val = 10;   // limit range to 0-10
            PWM_reg = val;      // update current PWM value
            if ( userreg <= USER_EEPROM_LAST_POS ) {   //avoid overwriting registers outside of app register space
                writeEEPROM( VSCP_EEPROM_END + userreg, val );
                rv = readEEPROM( VSCP_EEPROM_END + userreg );   // VSCP read will write fail here if val was > 10
            } 
            break;
        default:
            if ( userreg <= USER_EEPROM_LAST_POS ) {   //avoid overwriting registers outside of app register space
                writeEEPROM( VSCP_EEPROM_END + userreg, val );
                rv = readEEPROM( VSCP_EEPROM_END + userreg );
            } 
            break;
    }
#ifdef SERIAL_DEBUG_RW_APP_REG
    sprintf(debugstring,
            "\r\nWrite app reg: %02id:%02id (0x%02x:0x%02x), paginated: %02id (0x%02x), ",
            vscp_page_select, reg, vscp_page_select, reg, userreg, userreg );
    daf_puts1USART(debugstring);         //print to USART
    sprintf(debugstring,
            "EEPROM loc.: %02id (0x%02x), write value: %02id, re-read value: %id",
             VSCP_EEPROM_END + userreg, VSCP_EEPROM_END + userreg, val, rv );
    daf_puts1USART(debugstring);         //print to USART
#endif
	
    return rv;
}

///////////////////////////////////////////////////////////////////////////////
// Send Decsion Matrix Information
//
void sendDMatrixInfo( void )
{
    vscp_omsg.priority = VSCP_PRIORITY_MEDIUM;
    vscp_omsg.flags = VSCP_VALID_MSG + 2;
    vscp_omsg.vscp_class = VSCP_CLASS1_PROTOCOL;
    vscp_omsg.vscp_type = VSCP_TYPE_PROTOCOL_GET_MATRIX_INFO_RESPONSE;

    vscp_omsg.data[ 0 ] = DESCISION_MATRIX_ELEMENTS;
    vscp_omsg.data[ 1 ] = REG_DESCISION_MATRIX;

    vscp_sendEvent();	// Send data
}


///////////////////////////////////////////////////////////////////////////////
// SendInformationEvent
//
void SendInformationEvent( unsigned char idx, unsigned char eventClass, unsigned char eventTypeId) 
{
    vscp_omsg.priority = VSCP_PRIORITY_MEDIUM;
    vscp_omsg.flags = VSCP_VALID_MSG + 3;
    vscp_omsg.vscp_class = eventClass;
    vscp_omsg.vscp_type = eventTypeId;

    vscp_omsg.data[ 0 ] = idx;                                          //index
    vscp_omsg.data[ 1 ] = readEEPROM( VSCP_EEPROM_END + EEPROM_ZONE );  //zone
    vscp_omsg.data[ 2 ] = readEEPROM( VSCP_EEPROM_END + idx );          //subzone //xxx add subzone like in data[1]?

    vscp_sendEvent();	// Send data
}


///////////////////////////////////////////////////////////////////////////////
// SendInformationEventData
//
void SendInformationEventData( unsigned char eventClass, unsigned char eventTypeId, 
                               unsigned char data0, unsigned char data1, unsigned char data2, unsigned char data3, unsigned char data4)
{
    vscp_omsg.priority = VSCP_PRIORITY_MEDIUM;
    vscp_omsg.flags = VSCP_VALID_MSG + 3;
    vscp_omsg.vscp_class = eventClass;
    vscp_omsg.vscp_type = eventTypeId;

    vscp_omsg.data[ 0 ] = data0;
    vscp_omsg.data[ 1 ] = data1;
    vscp_omsg.data[ 2 ] = data2;
    if (data3 != '\0') vscp_omsg.data[ 3 ] = data3;
    if (data4 != '\0') vscp_omsg.data[ 4 ] = data4;

    vscp_sendEvent();	// Send data
}


///////////////////////////////////////////////////////////////////////////////
// Send Probe Ack
//
void SendProbeAck( unsigned char INPtime )
{
	vscp_omsg.priority = VSCP_PRIORITY_MEDIUM;
	vscp_omsg.flags = VSCP_VALID_MSG+1;
	vscp_omsg.vscp_class = VSCP_CLASS1_PROTOCOL;
	vscp_omsg.vscp_type = VSCP_TYPE_PROTOCOL_PROBE_ACK;
	vscp_omsg.data[ 0] = INPtime;

	vscp_sendEvent();	// Send data		
}


///////////////////////////////////////////////////////////////////////////////
// Do decision Matrix handling
// 
// The routine expects vscp_imsg to contain a vaild incoming event
//
void doDM( void )
{
    unsigned char i;
    unsigned char dmflags;
    unsigned short class_filter;
    unsigned short class_mask;
    unsigned char type_filter;
    unsigned char type_mask;

    // Don't deal with the control functionality
    if ( VSCP_CLASS1_PROTOCOL == vscp_imsg.vscp_class ) return;

#ifdef SERIAL_DEBUG_DM
        //Skip heartbeat messages on the bus from displaying on the serial terminal
        if ( vscp_imsg.vscp_class == 0x14 && vscp_imsg.vscp_type == 0x09) {
            return;
        }
#endif

	for ( i=0; i<DESCISION_MATRIX_ELEMENTS; i++ ) {
		// Get DM flags for this row
        dmflags = readEEPROM( VSCP_EEPROM_END + REG_DESCISION_MATRIX + 1 + ( 8 * i ) );

#ifdef SERIAL_DEBUG_DM
    sprintf(debugstring,
        "\r\n1********************* DoDM() row=%1i, flags=0x%02x, oaddr=0x%02x, zone=0x%02x, ",
        i, dmflags, vscp_imsg.oaddr, vscp_imsg.data[1]);
    daf_puts1USART(debugstring);
/*    sprintf(debugstring,
        "VSCP_DM_FLAG_ENABLED=%x, VSCP_DM_FLAG_CHECK_OADDR=%x, VSCP_DM_FLAG_CHECK_ZONE=%x, ",
        dmflags & VSCP_DM_FLAG_ENABLED, dmflags & VSCP_DM_FLAG_CHECK_OADDR, dmflags & VSCP_DM_FLAG_CHECK_ZONE );
    daf_puts1USART(debugstring);*/
    sprintf(debugstring,
        " action=0x%02x, action_param=0x%02x",
        readEEPROM(VSCP_EEPROM_END + REG_DESCISION_MATRIX + (8*i) + VSCP_DM_POS_ACTION), readEEPROM(VSCP_EEPROM_END + REG_DESCISION_MATRIX + (8*i) + VSCP_DM_POS_ACTIONPARAM) );
    daf_puts1USART(debugstring);
#endif

        // Is the DM row enabled?
        if ( dmflags & VSCP_DM_FLAG_ENABLED ) {
#ifdef SERIAL_DEBUG_DM
    sprintf(debugstring, "\r\n2-DM row enabled, dmflags=0x%02x", dmflags);    daf_puts1USART(debugstring);
#endif
			// Should the originating id be checked and if so is it the same?
            if ( ( dmflags & VSCP_DM_FLAG_CHECK_OADDR ) &&
                 ( vscp_imsg.oaddr != readEEPROM( VSCP_EEPROM_END + REG_DESCISION_MATRIX + ( 8 * i ) ) ) ) {
#ifdef SERIAL_DEBUG_DM
    sprintf(debugstring,
            "\r\n3-Oaddr is checked and does not match, oaddr: 0x%02x, this node's addr: 0x%02x (vscp_nickname= 0x02x)",
            vscp_imsg.oaddr, readEEPROM( VSCP_EEPROM_END + REG_DESCISION_MATRIX + ( 8 * i ) ), vscp_nickname );
    daf_puts1USART(debugstring);
#endif
				continue; // if oaddr doesn't match, skip to for-loop's next iteration
			}	

			// Check if zone should match and if so if it match
			if ( dmflags & VSCP_DM_FLAG_CHECK_ZONE ) {
#ifdef SERIAL_DEBUG_DM
    sprintf(debugstring, "\r\n4a-Check zone flag is set");
    daf_puts1USART(debugstring);
#endif
				if ( 255 != vscp_imsg.data[ 1 ] ) {
					if ( vscp_imsg.data[ 1 ] != readEEPROM( VSCP_EEPROM_END + EEPROM_ZONE  ) ) {
#ifdef SERIAL_DEBUG_DM
    sprintf(debugstring,
            "\r\n5-Zones do not match, received zone: 0x%02x, this node's zone: 0x%02x ",
            vscp_imsg.data[1], readEEPROM( VSCP_EEPROM_END + EEPROM_ZONE ) );
    daf_puts1USART(debugstring);
    sprintf(debugstring,
            ", VSCP_EEPROM_END: 0x%02x, EEPROM_ZONE: 0x%02x, sum: 0x%x",
            VSCP_EEPROM_END, EEPROM_ZONE, (VSCP_EEPROM_END + EEPROM_ZONE) );  
    daf_puts1USART(debugstring);
#endif
						continue;
					} else {
#ifdef SERIAL_DEBUG_DM
    sprintf(debugstring,
            "\r\n6-Zones match, received zone: 0x%04x, this node's zone: 0x%04x ",
            vscp_imsg.data[1], readEEPROM( VSCP_EEPROM_END + EEPROM_ZONE ) );
    daf_puts1USART(debugstring);
    sprintf(debugstring,
            ", VSCP_EEPROM_END: 0x%04x, EEPROM_ZONE: 0x%04x, sum: 0x%04x",
            VSCP_EEPROM_END, EEPROM_ZONE, (VSCP_EEPROM_END + EEPROM_ZONE) );  
    daf_puts1USART(debugstring);
#endif
                    }
                }
			} else {
#ifdef SERIAL_DEBUG_DM
    sprintf(debugstring, "\r\n4b-Check zone flag is NOT set");
    daf_puts1USART(debugstring);
#endif
            }

            class_filter = ( dmflags & VSCP_DM_FLAG_CLASS_FILTER )*256 +
							readEEPROM( VSCP_EEPROM_END + REG_DESCISION_MATRIX + ( 8 * i ) + VSCP_DM_POS_CLASSFILTER  );
            class_mask = ( dmflags & VSCP_DM_FLAG_CLASS_MASK )*256 +
							readEEPROM( VSCP_EEPROM_END + REG_DESCISION_MATRIX + ( 8 * i ) + VSCP_DM_POS_CLASSMASK  );
            type_filter = readEEPROM( VSCP_EEPROM_END + REG_DESCISION_MATRIX + ( 8 * i ) + VSCP_DM_POS_TYPEFILTER );
            type_mask = readEEPROM( VSCP_EEPROM_END + REG_DESCISION_MATRIX + ( 8 * i ) + VSCP_DM_POS_TYPEMASK  );

#ifdef SERIAL_DEBUG_DM_ACTIONS
//          if (vscp_imsg.vscp_class != 0x14 && vscp_imsg.vscp_type != 0x09) {   // do not display heartbeat events
                sprintf(debugstring,
                   "\r\n7-This node: Class mask: 0x%02x, Class filter: 0x%02x, Type mask: 0x%02x, Type filter: 0x%02x",
                   class_mask, class_filter, type_mask, type_filter );
                daf_puts1USART(debugstring);
                sprintf(debugstring,
                   "\r\n8-Received event: Class: 0x%02x, Type: 0x%02x, Data[0]: 0x%02x, Data[1]: 0x%02x, Data[2]: 0x%02x, Data[3]: 0x%02x",
                    vscp_imsg.vscp_class, vscp_imsg.vscp_type, vscp_imsg.data[0], vscp_imsg.data[1], vscp_imsg.data[2], vscp_imsg.data[3] );
                daf_puts1USART(debugstring);
                sprintf(debugstring,
                   "\r\n15-(class_filter ^ vscp_imsg.vscp_class) = 0x%02x, ((class_filter ^ vscp_imsg.vscp_class) & class_mask ) = 0x%02x, ",
                   (class_filter ^ vscp_imsg.vscp_class), ((class_filter ^ vscp_imsg.vscp_class) & class_mask) );
                daf_puts1USART(debugstring);
                sprintf(debugstring,
                    "\r\n(type_filter ^ vscp_imsg.vscp_type) = 0x%02x, ((type_filter ^ vscp_imsg.vscp_type) & type_mask ) = 0x%02x",
                    (type_filter ^ vscp_imsg.vscp_type), ((type_filter ^ vscp_imsg.vscp_type) & type_mask) );
                daf_puts1USART(debugstring);
//          }
#endif
//uint16_t vscp_class; ///< VSCP class
//uint8_t vscp_type; ///< VSCP type
//unsigned short class_filter;
//unsigned short class_mask;
            if ( !( ( class_filter ^ vscp_imsg.vscp_class ) & class_mask ) &&
                 !( ( type_filter ^ vscp_imsg.vscp_type ) & type_mask )) { //issue here
#ifdef SERIAL_DEBUG_DM_ACTIONS
                sprintf(debugstring, "\r\n14-Class and type match");
                daf_puts1USART(debugstring);
                sprintf(debugstring, "\r\n15-Action: 0x%02x", readEEPROM( VSCP_EEPROM_END + REG_DESCISION_MATRIX + ( 8 * i ) + VSCP_DM_POS_ACTION) );
                daf_puts1USART(debugstring);
#endif
                // OK Trigger this action
                switch ( readEEPROM( VSCP_EEPROM_END + REG_DESCISION_MATRIX + ( 8 * i ) + VSCP_DM_POS_ACTION  ) ) {
                    case ACTION_ON:			// Enable relays
#ifdef SERIAL_DEBUG_DM_ACTIONS
                        sprintf(debugstring, "\r\n10-DoDM() -> ACTION_ON 0x%02x", ACTION_ON);
                        daf_puts1USART(debugstring);
/*    sprintf(debugstring,
            ", action param: 0x%02x (register 0x%02x)",
            readEEPROM( VSCP_EEPROM_END + REG_DESCISION_MATRIX + ( 8 * i ) + VSCP_DM_POS_ACTIONPARAM ),
            REG_DESCISION_MATRIX + ( 8 * i ) + VSCP_DM_POS_ACTIONPARAM );
    daf_puts1USART(debugstring);*/
#endif
                        doActionOn( dmflags, readEEPROM( VSCP_EEPROM_END + REG_DESCISION_MATRIX + ( 8 * i ) + VSCP_DM_POS_ACTIONPARAM  ) );
                        break;
						
                    case ACTION_OFF: 		// Disable relays
#ifdef SERIAL_DEBUG_DM_ACTIONS
                        sprintf(debugstring, "\r\n10-DoDM() -> ACTION_OFF 0x%02x", ACTION_OFF);
                        daf_puts1USART(debugstring);
#endif
                        doActionOff(dmflags,  readEEPROM( VSCP_EEPROM_END + REG_DESCISION_MATRIX + ( 8 * i ) + VSCP_DM_POS_ACTIONPARAM  ) );
                        break;
                    case ACTION_TOGGLE: 		// Disable relays
#ifdef SERIAL_DEBUG_DM_ACTIONS
                        sprintf(debugstring, "\r\n11-DoDM() -> ACTION_TOGGLE 0x%02x", ACTION_TOGGLE);
                        daf_puts1USART(debugstring);
#endif
                        doActionToggle(dmflags,  readEEPROM( VSCP_EEPROM_END + REG_DESCISION_MATRIX + ( 8 * i ) + VSCP_DM_POS_ACTIONPARAM  ) );
                        break;
                    case ACTION_PULSE: 		// Disable relays
#ifdef SERIAL_DEBUG_DM_ACTIONS
                        sprintf(debugstring, "\r\n13-DoDM() -> ACTION_PULSE 0x%02x", ACTION_PULSE);
                        daf_puts1USART(debugstring);
#endif
                        doActionPulse(dmflags,  readEEPROM( VSCP_EEPROM_END + REG_DESCISION_MATRIX + ( 8 * i ) + VSCP_DM_POS_ACTIONPARAM  ) );
                        break;
                } // switch/case
            } // Filter/mask
        } // Row enabled
    } // for each row
}

///////////////////////////////////////////////////////////////////////////////
// doActionOn
void doActionOn( unsigned char dmflags, unsigned char arg )  // passed: dmflags, action param
{
    unsigned char i;
    unsigned char controlbits;
	
    for ( i=0; i<15; i++ ) { // for each output

//david: it seems that arg is ignored in this code, and that all outputs are switched on if their zone matches what was sent
        // If the output should not be handled just move on
	//if ( !( arg & ( 1 << i ) ) ) continue;

	// Check if subzone should match and if so if it matches
	if ( dmflags & VSCP_DM_FLAG_CHECK_SUBZONE ) {
            if ( vscp_imsg.data[ 2 ] != readEEPROM( VSCP_EEPROM_END + REG_SUBZONE_OUT1 + i ) ) {
                continue;  // skip code that follows and go straight to next iteration of for loop
            }
	}
        controlbits = readEEPROM( VSCP_EEPROM_END + REG_CONTROL_OUT1 + i); //read the control bits for the output
        if ( !( controlbits & RELAY_CONTROLBIT_ENABLED ) ) continue; //Check if the output is enabled only then continue
        SetOut(i, OUTPUT_ON, TRUE); //activate the output
	if( controlbits & RELAY_CONTROLBIT_ONEVENT ) { // Should on event be sent?
//            SendInformationEvent( REG_SUBZONE_OUT1 + i, VSCP_CLASS1_INFORMATION, VSCP_TYPE_INFORMATION_ON );
            SendInformationEventData( VSCP_CLASS1_INFORMATION, VSCP_TYPE_INFORMATION_ON, 
                                      i, readEEPROM( VSCP_EEPROM_END + EEPROM_ZONE ),
                                      readEEPROM( VSCP_EEPROM_END + REG_SUBZONE_OUT1 + i ),
                                      '\0', '\0');
	}
    }
}

///////////////////////////////////////////////////////////////////////////////
// doActionOff
void doActionOff( unsigned char dmflags, unsigned char arg )
{
    unsigned char i;
    unsigned char controlbits;
	
    for ( i=0; i<15; i++ ) {
		
        // If the output should not be handled just move on
	// if ( !( arg & ( 1 << i ) ) ) continue;
		
	// Check if subzone should match and if so if it match
	if ( dmflags & VSCP_DM_FLAG_CHECK_SUBZONE ) {
            if ( vscp_imsg.data[ 2 ] != readEEPROM( VSCP_EEPROM_END + REG_SUBZONE_OUT1 + i ) ) {
                continue;
            }
	}
        controlbits = readEEPROM( VSCP_EEPROM_END + REG_CONTROL_OUT1 + i); //read the control bits for the output
        if ( !( controlbits & RELAY_CONTROLBIT_ENABLED ) ) continue; //Check if the output is enabled only then continue
        SetOut(i, OUTPUT_OFF, TRUE); //disable the output
	if( controlbits & RELAY_CONTROLBIT_ONEVENT ) { // Should on event be sent?
            SendInformationEventData( VSCP_CLASS1_INFORMATION, VSCP_TYPE_INFORMATION_OFF,
                                      i, readEEPROM( VSCP_EEPROM_END + EEPROM_ZONE ),
                                      readEEPROM( VSCP_EEPROM_END + REG_SUBZONE_OUT1 + i ),
                                      '\0', '\0');
	}
    }
}

///////////////////////////////////////////////////////////////////////////////
// doActionToggle
void doActionToggle( unsigned char dmflags, unsigned char arg )
{
//  unsigned char i;
    uint8_t i;
    unsigned char controlbits;
//    BOOL bOn = FALSE;

    for ( i=0; i<15; i++ ) {

	// If the rely should not be handled just move on
	// if ( !( arg & ( 1 << i ) ) ) continue;

	// Check if subzone should match
	if ( dmflags & VSCP_DM_FLAG_CHECK_SUBZONE ) {
#ifdef SERIAL_DEBUG_DM_ACTIONS
            sprintf(debugstring, "\r\n1-doActionToggle(), subzones should match. arg: 0x02%x, received zone: 0x%02x, this node's zone: 0x%02x",
            arg, vscp_imsg.data[ 2 ], readEEPROM( VSCP_EEPROM_END + REG_SUBZONE_OUT1 + i ) );
    daf_puts1USART(debugstring);
#endif
            if ( vscp_imsg.data[ 2 ] != readEEPROM( VSCP_EEPROM_END + REG_SUBZONE_OUT1 + i ) ) {  //subzone does not match
#ifdef SERIAL_DEBUG_DM_ACTIONS
                sprintf(debugstring, "\r\n2-Subzone does not match. Received zone: 0x%02x, this node's zone: 0x%02x",
                        vscp_imsg.data[ 2 ], readEEPROM( VSCP_EEPROM_END + REG_SUBZONE_OUT1 + i ) );
                daf_puts1USART(debugstring);
#endif
		continue;
            }
	}
#ifdef SERIAL_DEBUG_DM_ACTIONS
        daf_puts1USART("\r\n3-Subzones match, or shouldn't match.");
#endif

        if ( vscp_imsg.data[ 0 ] != INP_PRESSED )
            continue;  //check if button press event (not repeat or release) otherwise continue next i in loop
#ifdef SERIAL_DEBUG_DM_ACTIONS
        daf_puts1USART("\r\n4-Buttonpress event (INP_PRESSED), not repeat or release");
#endif
        controlbits = readEEPROM( VSCP_EEPROM_END + REG_CONTROL_OUT1 + i); //read the control bits for the output
        if ( !( controlbits & RELAY_CONTROLBIT_ENABLED ) )
            continue; //Check if the output is enabled only then continue
#ifdef SERIAL_DEBUG_DM_ACTIONS
        daf_puts1USART("\r\n5-Output is enabled");
#endif
        if ( ReadOut( i ) ) {
#ifdef SERIAL_DEBUG_DM_ACTIONS
            sprintf(debugstring, "\r\n6-SetOut(%i,%i), OUT1: %i", i+ OUTPUT_OFF, OUT1 );
            daf_puts1USART(debugstring);
#endif
            SetOut(i, OUTPUT_OFF, TRUE);
            if( controlbits & RELAY_CONTROLBIT_OFFEVENT ) {
#ifdef SERIAL_DEBUG_DM_ACTIONS
                sprintf(debugstring, "\r\nSendInformationEvent INFORMATION_OFF triggered");
                daf_puts1USART(debugstring);
#endif
                SendInformationEventData( VSCP_CLASS1_INFORMATION, VSCP_TYPE_INFORMATION_OFF,
                                      i, readEEPROM( VSCP_EEPROM_END + EEPROM_ZONE ),
                                      readEEPROM( VSCP_EEPROM_END + REG_SUBZONE_OUT1 + i ),
                                      '\0', '\0');
            }
         } else {
#ifdef SERIAL_DEBUG_DM_ACTIONS
            sprintf(debugstring, "\r\n7-SetOut(%i,%i), OUT1: %i", i+ OUTPUT_ON, OUT1 );
            daf_puts1USART(debugstring);
#endif
            SetOut(i, OUTPUT_ON, TRUE);
            if( controlbits & RELAY_CONTROLBIT_ONEVENT ) {
#ifdef SERIAL_DEBUG_DM_ACTIONS
                sprintf(debugstring, "\r\nSendInformationEvent INFORMATION_ON triggered");
                daf_puts1USART(debugstring);
#endif
                SendInformationEventData( VSCP_CLASS1_INFORMATION, VSCP_TYPE_INFORMATION_ON,
                                      i, readEEPROM( VSCP_EEPROM_END + EEPROM_ZONE ),
                                      readEEPROM( VSCP_EEPROM_END + REG_SUBZONE_OUT1 + i ),
                                      '\0', '\0');
            }
        }
    }
}


///////////////////////////////////////////////////////////////////////////////
// doActionPulse

void doActionPulse( unsigned char dmflags, unsigned char arg )
{
//	unsigned char i;
    uint8_t i;
    unsigned char controlbits;
//    BOOL bOn = FALSE;

    for ( i=0; i<15; i++ ) {

        // If the rely should not be handled just move on
	// if ( !( arg & ( 1 << i ) ) ) continue;

	// Check if subzone should match
	if ( dmflags & VSCP_DM_FLAG_CHECK_SUBZONE ) {
#ifdef SERIAL_DEBUG_DM_ACTIONS
            sprintf(debugstring, "\r\n1-doActionPulse(), subzones should match. arg: 0x02%x, received zone: 0x%02x, this node's zone: 0x%02x",
                        arg, vscp_imsg.data[ 2 ], readEEPROM( VSCP_EEPROM_END + REG_SUBZONE_OUT1 + i ) );
            daf_puts1USART(debugstring);
#endif
            if ( vscp_imsg.data[ 2 ] != readEEPROM( VSCP_EEPROM_END + REG_SUBZONE_OUT1 + i ) ) {  //subzone does not match
#ifdef SERIAL_DEBUG_DM_ACTIONS
                sprintf(debugstring, "\r\n2-Subzone does not match. Received zone: 0x%02x, this node's zone: 0x%02x",
                        vscp_imsg.data[ 2 ], readEEPROM( VSCP_EEPROM_END + REG_SUBZONE_OUT1 + i ) );
                daf_puts1USART(debugstring);
#endif
                continue;
            }
	}
#ifdef SERIAL_DEBUG_DM_ACTIONS
        daf_puts1USART("\r\n3-Subzones match, or shouldn't match.");
#endif

        if ( vscp_imsg.data[ 0 ] != INP_PRESSED )
            continue;  //check if button press event (not repeat or release) otherwise continue next i in loop
#ifdef SERIAL_DEBUG_DM_ACTIONS
        daf_puts1USART("\r\n4-Buttonpress event (INP_PRESSED), not repeat or release");
#endif

        controlbits = readEEPROM( VSCP_EEPROM_END + REG_CONTROL_OUT1 + i); //read the control bits for the output
        if ( !( controlbits & RELAY_CONTROLBIT_ENABLED ) )
            continue; //Check if the output is enabled only then continue
#ifdef SERIAL_DEBUG_DM_ACTIONS
        daf_puts1USART("\r\n5-Output is enabled");
#endif

#ifdef SERIAL_DEBUG_DM_ACTIONS
        sprintf(debugstring, "\r\n6-PulseOut(%i,%i), OUT1: %i", i+1, OUTPUT_OFF, OUT1 );
        daf_puts1USART(debugstring);
#endif
        PulseOut(i);  // Pulse output

        if( controlbits & RELAY_CONTROLBIT_ONEVENT ) {
#ifdef SERIAL_DEBUG_DM_ACTIONS
            sprintf(debugstring, "\r\nSendInformationEvent INFORMATION_ON/OFF triggered, subzone:  %d", readEEPROM( VSCP_EEPROM_END + REG_SUBZONE_OUT1 + i ));
            daf_puts1USART(debugstring);
#endif
            if ( OutputVar[i].Status == OUTPUT_ON ) { //xxxh
                SendInformationEventData( VSCP_CLASS1_INFORMATION, VSCP_TYPE_INFORMATION_ON,
                                      i, readEEPROM( VSCP_EEPROM_END + EEPROM_ZONE ),
                                      readEEPROM( VSCP_EEPROM_END + REG_SUBZONE_OUT1 + i ),
                                      '\0', '\0');
            } else {
                SendInformationEventData( VSCP_CLASS1_INFORMATION, VSCP_TYPE_INFORMATION_OFF,
                                      i, readEEPROM( VSCP_EEPROM_END + EEPROM_ZONE ),
                                      readEEPROM( VSCP_EEPROM_END + REG_SUBZONE_OUT1 + i ),
                                      '\0', '\0');
            }
        }
    } //for
}




///////////////////////////////////////////////////////////////////////////////
//                        VSCP Required Methods
//////////////////////////////////////////////////////////////////////////////



///////////////////////////////////////////////////////////////////////////////
// Get Major version number for this hardware module
//

unsigned char vscp_getMajorVersion()
{
	return FIRMWARE_MAJOR_VERSION;
}

///////////////////////////////////////////////////////////////////////////////
// Get Minor version number for this hardware module
//

unsigned char vscp_getMinorVersion()
{
	return FIRMWARE_MINOR_VERSION;
}

///////////////////////////////////////////////////////////////////////////////
// Get Subminor version number for this hardware module
//

unsigned char vscp_getSubMinorVersion()
{
	return FIRMWARE_SUB_MINOR_VERSION;
}

///////////////////////////////////////////////////////////////////////////////
// getVSCP_GUID
//
// Get GUID from EEPROM
//

uint8_t vscp_getGUID( uint8_t idx )
{
	return readFPM( VSCP_FPM_GUID + idx );
}


///////////////////////////////////////////////////////////////////////////////
// getDeviceURL
//
// Get device URL from EEPROM
//

uint8_t vscp_getMDF_URL( uint8_t idx )
{
	return vscp_deviceURL[ idx ];
}

///////////////////////////////////////////////////////////////////////////////
// Get Manufacturer id and subid from EEPROM
//

uint8_t vscp_getUserID( uint8_t idx )
{
	return readEEPROM( VSCP_EEPROM_REG_USERID + idx );	
}

///////////////////////////////////////////////////////////////////////////////
//  setVSCPUserID
//

void vscp_setUserID( uint8_t idx, uint8_t data )
{
	writeEEPROM( idx + VSCP_EEPROM_REG_USERID, data );
}

///////////////////////////////////////////////////////////////////////////////
// getVSCPManufacturerId
// 
// Get Manufacturer id and subid from EEPROM
//

uint8_t vscp_getManufacturerId( uint8_t idx )
{
	return readEEPROM( VSCP_EEPROM_REG_MANUFACTUR_ID0 + idx );	
}

///////////////////////////////////////////////////////////////////////////////
// getVSCPManufacturerId
// 
// Get Manufacturer id and subid from EEPROM
//

void vscp_setManufacturerId( uint8_t idx, uint8_t data )
{
	writeEEPROM( VSCP_EEPROM_REG_MANUFACTUR_ID0 + idx, data );	
}

///////////////////////////////////////////////////////////////////////////////
// Get the bootloader algorithm code
//

uint8_t vscp_getBootLoaderAlgorithm( void ) 
{
	return VSCP_BOOTLOADER_PIC1;	
}

///////////////////////////////////////////////////////////////////////////////
// Get the buffer size
//

uint8_t vscp_getBufferSize( void ) 
{
	return 8;	// Standard CAN frame
}

	
///////////////////////////////////////////////////////////////////////////////
//  getNickname
//

uint8_t vscp_getNickname( void )
{
	return readEEPROM( VSCP_EEPROM_NICKNAME );
}

///////////////////////////////////////////////////////////////////////////////
//  setNickname
//

void vscp_setNickname( uint8_t nickname )
{
	writeEEPROM( VSCP_EEPROM_NICKNAME, nickname );
}

///////////////////////////////////////////////////////////////////////////////
//  getSegmentCRC
//

uint8_t vscp_getSegmentCRC( void )
{
	return readEEPROM( VSCP_EEPROM_SEGMENT_CRC );
}

///////////////////////////////////////////////////////////////////////////////
//  setSegmentCRC
//

void vscp_setSegmentCRC( uint8_t crc )
{
	writeEEPROM( VSCP_EEPROM_SEGMENT_CRC, crc );
}

///////////////////////////////////////////////////////////////////////////////
//  setVSCPControlByte
//

void vscp_setControlByte( uint8_t ctrl )
{
	writeEEPROM( VSCP_EEPROM_CONTROL, ctrl );
}


///////////////////////////////////////////////////////////////////////////////
//  getVSCPControlByte
//

uint8_t vscp_getControlByte( void )
{
	return readEEPROM( VSCP_EEPROM_CONTROL );
}

///////////////////////////////////////////////////////////////////////////////
//  vscp_getEmbeddedMdfInfo
//

void vscp_getEmbeddedMdfInfo( void )
{
	// No embedded DM so we respond with info about that
	
	vscp_omsg.priority = VSCP_PRIORITY_NORMAL;
	vscp_omsg.flags = VSCP_VALID_MSG + 3;
	vscp_omsg.vscp_class = VSCP_CLASS1_PROTOCOL;
	vscp_omsg.vscp_type = VSCP_TYPE_PROTOCOL_RW_RESPONSE;

	vscp_omsg.data[ 0 ] = 0;
	vscp_omsg.data[ 1 ] = 0;
	vscp_omsg.data[ 2 ] = 0;	
	
	// send the message
	vscp_sendEvent();
}
/*!
		Get device family code
		return zero for not known.
*/
uint32_t vscp_getFamilyCode(void){
    return 0;
}
/*!
		Restore defaults
		If 0x55/0xaa is written to register location
		162 within one second defaults should be loaded
		by the device.
 */
void vscp_restoreDefaults(void){

}
/*!
		Get device family type
		return zero for not known.
*/
uint32_t vscp_getFamilyType(void){
    return 0;
}
/*
///////////////////////////////////////////////////////////////////////////////
// vscp_getZone
//

uint8_t vscp_getZone( void )
{
	return readEEPROM( EEPROM_ZONE );  //david: shouldn't this be prefixed by VSCP_EEPROM_END?
}

///////////////////////////////////////////////////////////////////////////////
// vscp_getSubzone
//

uint8_t vscp_getSubzone( void )
{
	return readEEPROM( EEPROM_SUBZONE ); //david: shouldn't this be prefixed by VSCP_EEPROM_END?
}
*/

///////////////////////////////////////////////////////////////////////////////
// vscp_goBootloaderMode
//

void vscp_goBootloaderMode( void )
{	 											
	// OK, We should enter boot loader mode
	// 	First, activate bootloader mode
	writeEEPROM( VSCP_EEPROM_BOOTLOADER_FLAG, VSCP_BOOT_FLAG );
					
	//_asm goto _startup reset _endasm
	asm ("reset");
}


///////////////////////////////////////////////////////////////////////////////
//  vscp_getMatrixInfo
//

void vscp_getMatrixInfo( char *pData )
{
	uint8_t i;
	
	for ( i = 0; i < 8; i++ ) {
		vscp_omsg.data[ i ] = 0;
	}	
	vscp_omsg.data[ 0 ] = DESCISION_MATRIX_ELEMENTS; //[KURT] added for test  //TODO
	vscp_omsg.data[ 1 ] = REG_DESCISION_MATRIX; //[KURT] added for test       //TODO
}

///////////////////////////////////////////////////////////////////////////////
//
//

uint8_t vscp_getRegisterPagesUsed( void )
{
	return 3;	// One page used   // this register is obsolete so return value doesn't matter
}

///////////////////////////////////////////////////////////////////////////////
// sendVSCPFrame
//

int8_t sendVSCPFrame( uint16_t vscpclass, 
                      uint8_t vscptype,
                      uint8_t nodeid,
		      uint8_t priority,
		      uint8_t size,
	              uint8_t *pData )
{
	uint32_t id = ( (uint32_t)priority << 26 ) |
						( (uint32_t)vscpclass << 16 ) |
						( (uint32_t)vscptype << 8) |
						nodeid;		// nodeaddress (our address)
	
	if ( !sendCANFrame( id, size, pData ) ) {
		// Failed to send message
		vscp_errorcnt++;
		return FALSE;
	}
	
	return TRUE;
}


///////////////////////////////////////////////////////////////////////////////
// getVSCPFrame
//

int8_t getVSCPFrame( uint16_t *pvscpclass, 
                    uint8_t *pvscptype,
                    uint8_t *pNodeId,
                    uint8_t *pPriority,
                    uint8_t *pSize,
                    uint8_t *pData )
{
	uint32_t id;
	
	if ( !getCANFrame( &id, pSize, pData ) ) {
		return FALSE;
	}

	*pNodeId = id & 0x0ff;
	*pvscptype = ( id >> 8 ) & 0xff;
	*pvscpclass = ( id >> 16 ) & 0x1ff;
        *pPriority = (uint16_t)( 0x07 & ( id >> 26 ) );
    
	return TRUE;
}

///////////////////////////////////////////////////////////////////////////////
// sendCANFrame
//

/*int8_t sendCANFrame( uint32_t id, uint8_t dlc, uint8_t *pdata )     //original function
{
    if ( !vscp18f_sendMsg( id, pdata , dlc, CAN_TX_XTD_FRAME  ) ) {
    // Failed to send message
        return FALSE;
    }

    vscp_omsg.flags = 0;
    return TRUE;
}*/

int8_t sendCANFrame(uint32_t id, uint8_t dlc, uint8_t *pdata)       // Ake's Paris implementation
{
    uint8_t rv = FALSE;
    unsigned short i = 0;

    sendTimer = 0;
    while ( sendTimer < 1 ) {

#ifdef SERIAL_DEBUG_SENDCANFRAME
    sprintf(debugstring, "+");
    daf_puts1USART(debugstring);
#endif

        ClrWdt();			// Feed the dog
        i++;
//        if ( ECANSendMessage( id, pdata, dlc, ECAN_TX_XTD_FRAME ) ) {
        if ( vscp18f_sendMsg( id, pdata , dlc, CAN_TX_XTD_FRAME ) ) {
            rv = TRUE;
            break;
        }
#ifdef SERIAL_DEBUG_SENDCANFRAME
    sprintf(debugstring, "\r\nrv: %d, i: %d, sendTimer: %d", rv, i, sendTimer);
    daf_puts1USART(debugstring);
#endif
    }

    vscp_omsg.flags = 0;

    return rv;
}


///////////////////////////////////////////////////////////////////////////////
// getCANFrame
//

int8_t getCANFrame( uint32_t *pid, uint8_t *pdlc, uint8_t *pdata )
{
	uint8_t flags;

	// Dont read in new message if there already is a message
	// in the input buffer
	if ( vscp_imsg.flags & VSCP_VALID_MSG ) return FALSE;

	if ( vscp18f_readMsg( pid, pdata, pdlc, &flags ) ) {

		// RTR not interesting
		if ( flags & CAN_RX_RTR_FRAME ) return FALSE;

		// Must be extended frame
		if ( !( flags & CAN_RX_XTD_FRAME ) ) return FALSE;
		
		return TRUE;
	}	
	
	return FALSE;
}


///////////////////////////////////////////////////////////////////////////////
// DebounceSwitch
//

unsigned char DebounceINP1(void)
{
// <<11111111011101110001111100000110000000keypressed000000000001100101111011111111111111<<
BufferINP1=(BufferINP1<<1) | INP1 | 0xe0;   // 11100000
if(BufferINP1==0xf0)return INP_PRESSED;     // 11110000
if(BufferINP1==0xe0)return INP_HOLD;        // 11100000
if(BufferINP1==0xe1)return INP_RELEASED;    // 11100001
return FALSE;
}

unsigned char DebounceINP2(void)
{
BufferINP2=(BufferINP2<<1) | INP2 | 0xe0;
if(BufferINP2==0xf0) {
#ifdef SERIAL_DEBUG_INPUTS
    daf_puts1USART("%");
#endif
    return INP_PRESSED;
}
if(BufferINP2==0xe0)return INP_HOLD;
if(BufferINP2==0xe1)return INP_RELEASED;
return FALSE;
}

unsigned char DebounceINP3(void)
{
BufferINP3=(BufferINP3<<1) | INP3 | 0xe0;
if(BufferINP3==0xf0)return INP_PRESSED;
if(BufferINP3==0xe0)return INP_HOLD;
if(BufferINP3==0xe1)return INP_RELEASED;
return FALSE;
}

unsigned char DebounceINP4(void)
{
BufferINP4=(BufferINP4<<1) | INP4 | 0xe0;
if(BufferINP4==0xf0)return INP_PRESSED;
if(BufferINP4==0xe0)return INP_HOLD;
if(BufferINP4==0xe1)return INP_RELEASED;
return FALSE;
}

unsigned char DebounceINP5(void)
{
BufferINP5=(BufferINP5<<1) | INP5 | 0xe0;
if(BufferINP5==0xf0)return INP_PRESSED;
if(BufferINP5==0xe0)return INP_HOLD;
if(BufferINP5==0xe1)return INP_RELEASED;
return FALSE;
}

unsigned char DebounceINP6(void)
{
BufferINP6=(BufferINP6<<1) | INP6 | 0xe0;
if(BufferINP6==0xf0)return INP_PRESSED;
if(BufferINP6==0xe0)return INP_HOLD;
if(BufferINP6==0xe1)return INP_RELEASED;
return FALSE;
}

unsigned char DebounceINP7(void)
{
BufferINP7=(BufferINP7<<1) | INP7 | 0xe0;
if(BufferINP7==0xf0)return INP_PRESSED;
if(BufferINP7==0xe0)return INP_HOLD;
if(BufferINP7==0xe1)return INP_RELEASED;
return FALSE;
}



uint8_t ReadOut(uint8_t output) {    

#ifdef SERIAL_DEBUG_OUTPUTS
    sprintf(debugstring, "\r\nReadOut(%d)= %d", output, output_on[ output ] );
    daf_puts1USART(debugstring);
#endif

    return output_on[ output ];
}


void SetOut(uint8_t output, BOOL value, BOOL changeStatus)  // output: 0-14, value: 0 or 1
{
    output_on[output] = value;

    if ( changeStatus ) {
        OutputVar[output].Status = value;
    }

#ifdef SERIAL_DEBUG_OUTPUTS
    sprintf(debugstring, "\r\nIn SetOut(), changeStatus: %d, OutputVar[%d].Status: %d", changeStatus, output, OutputVar[output].Status );
    daf_puts1USART(debugstring);
#endif

    if (output >= 7 && output <= 13) {  // invert output ogic for output 8-14 since they are open collector and are active low
        value = !value;
    }

#ifdef SERIAL_DEBUG_OUTPUTS
    sprintf(debugstring, "\r\nSetOut(%d, %d)", output, value );
    daf_puts1USART(debugstring);
#endif

    switch ( output ) {
        case 0:             // output 1
            OUT1 = value;
            break;
        case 1:
            OUT2 = value;
            break;
        case 2:
            OUT3 = value;
            break;
        case 3:
            OUT4 = value;
            break;
        case 4:
            OUT5 = value;
            break;
        case 5:
            OUT6 = value;
            break;
        case 6:
            OUT7 = value;
            break;
        case 7:
            OUT8 = value;
            break;
        case 8:
            OUT9 = value;
            break;
        case 9:
            OUT10 = value;
            break;
        case 10:
            OUT11 = value;
            break;
        case 11:
            OUT12 = value;
            break;
        case 12:
            OUT13 = value;
            break;
        case 13:
            OUT14 = value;
            break;
        case 14:
            OUT15 = value;
            break;
    } //switch
}


void PulseOut( uint8_t output )  // output: 0->14 = output1->output15
{
#ifdef DEBUG_PULSEOUT
    sprintf(debugstring, "\r\nIn PulseOut(%d)", output );
    daf_puts1USART(debugstring);
#endif

    BOOL outputStatus = OutputVar[output].Status; // store output status

#ifdef SERIAL_DEBUG_OUTPUTS
    sprintf(debugstring, "\r\nIn PulseOut(), OutputVar[%d].Status: %d", output, OutputVar[output].Status );
    daf_puts1USART(debugstring);
#endif

    SetOut(output, OUTPUT_OFF, FALSE);                 // set output low, as starting point for pulse
    OutputVar[output].Active = TRUE;            // we are in a pulse now
    OutputVar[output].Counter = counter_10ms;   // set this output's counter, main() WHILE-loop watches this to set falling edge of pulse


#ifdef DEBUG_PULSEOUT
    sprintf(debugstring, "\r\ncounter_10ms set to: %d", counter_10ms );
    daf_puts1USART(debugstring);
#endif
    SetOut(output, OUTPUT_ON, TRUE);                         // set output high, i.e. rising edge of pulse

    OutputVar[output].Status ^= outputStatus;               // invert status

#ifdef SERIAL_DEBUG_OUTPUTS
    sprintf(debugstring, "\r\nIn PulseOut(), OutputVar[%d].Status: %d", output, OutputVar[output].Status );
    daf_puts1USART(debugstring);
#endif
}


void ActuateUponLocalEvent( uint8_t input ) {  // input: 0->6 = input1->input7, setOut(): 0->14 = output1->output15
#ifdef SERIAL_DEBUG_ActuateUponLocalEvent
    sprintf(debugstring, 
            "\r\nActuateUponLocalEvent(%d), IN_OUT_MAPPING_ACTION: 0x%02x, IN_OUT_MAPPING1+input-1: 0x%02x)",
            input, readEEPROM( VSCP_EEPROM_END + IN_OUT_MAPPING_ACTION ),
            readEEPROM( VSCP_EEPROM_END + IN_OUT_MAPPING1 + input ) - 1 );
    daf_puts1USART(debugstring);
#endif

    if ( readEEPROM( VSCP_EEPROM_END + IN_OUT_MAPPING1 + input ) > 0 &&     // bug fix to integrate in newer version!
         readEEPROM( VSCP_EEPROM_END + IN_OUT_MAPPING1 + input ) <= 15 ) {  // valid output selected

        switch ( readEEPROM( VSCP_EEPROM_END + IN_OUT_MAPPING_ACTION ) ) {
            case ACTION_ON:
#ifdef SERIAL_DEBUG_ActuateUponLocalEvent
                sprintf(debugstring,
                    "\r\nACTION_ON, calling SetOut(%d, %d)",
                    readEEPROM( VSCP_EEPROM_END + IN_OUT_MAPPING1 + input  ) - 1, OUTPUT_ON );
                daf_puts1USART(debugstring);
#endif 
                SetOut( readEEPROM( VSCP_EEPROM_END + IN_OUT_MAPPING1 + input ) - 1, OUTPUT_ON, TRUE);  //switch output off

                if( readEEPROM( VSCP_EEPROM_END + REG_CONTROL_OUT1 + input ) & RELAY_CONTROLBIT_ONEVENT ) {
#ifdef SERIAL_DEBUG_ActuateUponLocalEvent
            sprintf(debugstring, "\r\nSendInformationEvent INFORMATION_ON triggered");
            daf_puts1USART(debugstring);
#endif
                    SendInformationEventData( VSCP_CLASS1_INFORMATION, VSCP_TYPE_INFORMATION_ON,
                                      readEEPROM( VSCP_EEPROM_END + IN_OUT_MAPPING1 + input ) - 1,
                                      readEEPROM( VSCP_EEPROM_END + EEPROM_ZONE ),
                                      readEEPROM( VSCP_EEPROM_END + REG_SUBZONE_OUT1 + readEEPROM( VSCP_EEPROM_END + IN_OUT_MAPPING1 + input ) - 1 ), // subzone of output to which input maps
                                      '\0', '\0');
                }

                break;
            case ACTION_OFF:
#ifdef SERIAL_DEBUG_ActuateUponLocalEvent
                sprintf(debugstring,
                    "\r\nACTION_OFF, calling SetOut(%d, %d)",
                    readEEPROM( VSCP_EEPROM_END + IN_OUT_MAPPING1 + input ) - 1, OUTPUT_OFF );
                daf_puts1USART(debugstring);
#endif
                SetOut( readEEPROM( VSCP_EEPROM_END + IN_OUT_MAPPING1 + input ) - 1, OUTPUT_OFF, TRUE);  //switch output off

                if( readEEPROM( VSCP_EEPROM_END + REG_CONTROL_OUT1 + input ) & RELAY_CONTROLBIT_ONEVENT ) {
#ifdef SERIAL_DEBUG_ActuateUponLocalEvent
            sprintf(debugstring, "\r\nSendInformationEvent INFORMATION_OFF triggered");
            daf_puts1USART(debugstring);
#endif
                    SendInformationEventData( VSCP_CLASS1_INFORMATION, VSCP_TYPE_INFORMATION_OFF,
                                      readEEPROM( VSCP_EEPROM_END + IN_OUT_MAPPING1 + input ) - 1,
                                      readEEPROM( VSCP_EEPROM_END + EEPROM_ZONE ),
                                      readEEPROM( VSCP_EEPROM_END + REG_SUBZONE_OUT1 + readEEPROM( VSCP_EEPROM_END + IN_OUT_MAPPING1 + input ) - 1 ), // subzone of output to which input maps
                                      '\0', '\0');
                }

                break;
            case ACTION_PULSE:
#ifdef SERIAL_DEBUG_ActuateUponLocalEvent
                sprintf(debugstring,
                    "\r\nACTION_PULSE, calling PulseOut(%d)",
                    readEEPROM( VSCP_EEPROM_END + IN_OUT_MAPPING1 + input ) - 1 );
                daf_puts1USART(debugstring);
#endif
                PulseOut( readEEPROM( VSCP_EEPROM_END + IN_OUT_MAPPING1 + input ) - 1 ); // actuate local output corresponding to this button

                if( readEEPROM( VSCP_EEPROM_END + REG_CONTROL_OUT1 + input ) & RELAY_CONTROLBIT_ONEVENT ) {
                    if ( OutputVar[readEEPROM( VSCP_EEPROM_END + IN_OUT_MAPPING1 + input ) - 1].Status == OUTPUT_ON ) {
#ifdef SERIAL_DEBUG_ActuateUponLocalEvent
            sprintf(debugstring, "\r\nSendInformationEvent INFORMATION_ON triggered; %d", readEEPROM( VSCP_EEPROM_END + IN_OUT_MAPPING1 + input ) - 1);
            daf_puts1USART(debugstring);
#endif
#ifdef SERIAL_DEBUG_OUTPUTS
    sprintf(debugstring, "\r\nOutputVar[%d].Status: %d", readEEPROM( VSCP_EEPROM_END + IN_OUT_MAPPING1 + input ) - 1, OutputVar[readEEPROM( VSCP_EEPROM_END + IN_OUT_MAPPING1 + input ) - 1].Status );
    daf_puts1USART(debugstring);
#endif
                        SendInformationEventData( VSCP_CLASS1_INFORMATION, VSCP_TYPE_INFORMATION_ON,
                                      readEEPROM( VSCP_EEPROM_END + IN_OUT_MAPPING1 + input ) - 1,
                                      readEEPROM( VSCP_EEPROM_END + EEPROM_ZONE ),
                                      readEEPROM( VSCP_EEPROM_END + REG_SUBZONE_OUT1 + readEEPROM( VSCP_EEPROM_END + IN_OUT_MAPPING1 + input ) - 1 ), // subzone of output to which input maps
                                      '\0', '\0');
                    } else {
#ifdef SERIAL_DEBUG_ActuateUponLocalEvent
            sprintf(debugstring, "\r\nSendInformationEvent INFORMATION_OFF triggered");
            daf_puts1USART(debugstring);
#endif
                        SendInformationEventData( VSCP_CLASS1_INFORMATION, VSCP_TYPE_INFORMATION_OFF,
                                      readEEPROM( VSCP_EEPROM_END + IN_OUT_MAPPING1 + input ) - 1,
                                      readEEPROM( VSCP_EEPROM_END + EEPROM_ZONE ),
                                      readEEPROM( VSCP_EEPROM_END + REG_SUBZONE_OUT1 + readEEPROM( VSCP_EEPROM_END + IN_OUT_MAPPING1 + input ) - 1 ), // subzone of output to which input maps
                                      '\0', '\0');
                    }
                }

                break;
            case ACTION_TOGGLE:
                if ( ReadOut( readEEPROM( VSCP_EEPROM_END + IN_OUT_MAPPING1 + input ) - 1 ) ) {  // if output is on
#ifdef SERIAL_DEBUG_ActuateUponLocalEvent
                    sprintf(debugstring,
                        "\r\nACTION_TOGGLE1, calling SetOut(%d, %d), current state was %d",
                        readEEPROM( VSCP_EEPROM_END + IN_OUT_MAPPING1 + input ) - 1, OUTPUT_OFF,
                        ReadOut( readEEPROM( VSCP_EEPROM_END + IN_OUT_MAPPING1 + input ) - 1 ) );
                    daf_puts1USART(debugstring);
#endif
                    SetOut( readEEPROM( VSCP_EEPROM_END + IN_OUT_MAPPING1 + input ) - 1, OUTPUT_OFF, TRUE);

                    if( readEEPROM( VSCP_EEPROM_END + REG_CONTROL_OUT1 + input ) & RELAY_CONTROLBIT_ONEVENT ) {
#ifdef SERIAL_DEBUG_ActuateUponLocalEvent
            sprintf(debugstring, "\r\nSendInformationEvent INFORMATION_OFF triggered");
            daf_puts1USART(debugstring);
#endif
                        SendInformationEventData( VSCP_CLASS1_INFORMATION, VSCP_TYPE_INFORMATION_OFF,
                                      readEEPROM( VSCP_EEPROM_END + IN_OUT_MAPPING1 + input ) - 1,
                                      readEEPROM( VSCP_EEPROM_END + EEPROM_ZONE ),
                                      readEEPROM( VSCP_EEPROM_END + REG_SUBZONE_OUT1 + readEEPROM( VSCP_EEPROM_END + IN_OUT_MAPPING1 + input ) - 1 ), // subzone of output to which input maps
                                      '\0', '\0');
                    }

                } else {
#ifdef SERIAL_DEBUG_ActuateUponLocalEvent
                    sprintf(debugstring,
                        "\r\nACTION_TOGGLE2, calling SetOut(%d, %d), current state was %d",
                        readEEPROM( VSCP_EEPROM_END + IN_OUT_MAPPING1 + input ) - 1, OUTPUT_ON,
                        ReadOut(readEEPROM( VSCP_EEPROM_END + IN_OUT_MAPPING1 + input ) - 1 ) );
                    daf_puts1USART(debugstring);
#endif
                    SetOut( readEEPROM( VSCP_EEPROM_END + IN_OUT_MAPPING1 + input ) - 1, OUTPUT_ON, TRUE);

                    if( readEEPROM( VSCP_EEPROM_END + REG_CONTROL_OUT1 + input ) & RELAY_CONTROLBIT_ONEVENT ) {
#ifdef SERIAL_DEBUG_ActuateUponLocalEvent
            sprintf(debugstring, "\r\nSendInformationEvent INFORMATION_ON triggered");
            daf_puts1USART(debugstring);
#endif
                      SendInformationEventData( VSCP_CLASS1_INFORMATION, VSCP_TYPE_INFORMATION_ON,
                                      readEEPROM( VSCP_EEPROM_END + IN_OUT_MAPPING1 + input ) - 1,
                                      readEEPROM( VSCP_EEPROM_END + EEPROM_ZONE ),
                                      readEEPROM( VSCP_EEPROM_END + REG_SUBZONE_OUT1 + readEEPROM( VSCP_EEPROM_END + IN_OUT_MAPPING1 + input ) - 1 ), // subzone of output to which input maps
                                      '\0', '\0');
                    }
                }
                break;
            default:
                break;
        } // switch
    } // if
}


void ProcessInputs()
{
    unsigned int i;
    unsigned char keyval, controlbits;

    for ( i=0 ; i<7; i++) {     // for each input
        switch (i) {
            case 0:
                keyval = DebounceINP1();
                break;
            case 1:
                keyval = DebounceINP2();
                break;
            case 2:
                keyval = DebounceINP3();
                break;
            case 3:
                keyval = DebounceINP4();
                break;
            case 4:
                keyval = DebounceINP5();
                break;
            case 5:
                keyval = DebounceINP6();
                break;
            case 6:
                keyval = DebounceINP7();
                break;
        }
        controlbits = readEEPROM( VSCP_EEPROM_END + REG_CONTROL_INP1 + i );
        switch (INP_state[i]) {
            case INP_RELEASED:                  // button was released
                if (keyval == INP_PRESSED) {    // and is now pressed
#ifdef SERIAL_DEBUG_INPUTS
        sprintf(debugstring,
            "\r\nINP_state[%d]: 0x%02x, keyval: 0x%02x", i, INP_state[i], keyval);
        daf_puts1USART(debugstring);
#endif
                    INP_state[i] = INP_PRESSED;
#ifdef SERIAL_DEBUG_INPUTS
    daf_putrs1USART("\r\nINP_PRESSED, rising edge");
#endif
                    if( controlbits & INP_CONTROLBIT_REDG ) {       // trigger on raising edge
                        SendInformationEventData( VSCP_CLASS1_INFORMATION, VSCP_TYPE_INFORMATION_BUTTON, 
                                                  INP_PRESSED,
                                                  readEEPROM( VSCP_EEPROM_END + EEPROM_ZONE ),
                                                  readEEPROM( VSCP_EEPROM_END + REG_SUBZONE_INP1 + i ),
                                                  '\0', '\0' ); //xxxl
                        ActuateUponLocalEvent( i );    //actuate local output corresponding to this button
                    }
                }
                if (keyval == INP_RELEASED) {       // and is still released
                    INP_state[i] = INP_RELEASED;
                    INP_hold_timer[i] = 0;
                }
                break;
            case INP_PRESSED:                       // button was pressed
                if (keyval == INP_RELEASED) {       // and is now released
                    INP_state[i] = INP_RELEASED;
#ifdef SERIAL_DEBUG_INPUTS
    daf_putrs1USART("\r\nINP_PRESSED, falling edge");
#endif
                    if( controlbits & INP_CONTROLBIT_FEDG ) {       // trigger on falling edge
                        SendInformationEventData( VSCP_CLASS1_INFORMATION, VSCP_TYPE_INFORMATION_BUTTON,
                                                  INP_KEY,
                                                  readEEPROM( VSCP_EEPROM_END + EEPROM_ZONE ),
                                                  readEEPROM( VSCP_EEPROM_END + REG_SUBZONE_INP1 + i ),
                                                  '\0', '\0' ); //xxxl
                        ActuateUponLocalEvent( i );    //actuate local output corresponding to this button
                    }
                }
                if (keyval == INP_HOLD) {           // and is now still pressed
                    INP_state[i] = INP_HOLD;
                }
                break;
            case INP_HOLD:                          // button was held
                if (keyval == INP_RELEASED) {       // and is now released
                    INP_state[i] = INP_RELEASED;
#ifdef SERIAL_DEBUG_INPUTS
    daf_putrs1USART("\r\nINP_RELEASED after INP_HOLD");
#endif
                    if( controlbits & INP_CONTROLBIT_FEDG ) {       // trigger on falling edge
//                        SendInformationEventData( i , VSCP_CLASS1_INFORMATION, VSCP_TYPE_INFORMATION_BUTTON, INP_KEY );
                        SendInformationEventData( VSCP_CLASS1_INFORMATION, VSCP_TYPE_INFORMATION_BUTTON,
                                                  INP_KEY,
                                                  readEEPROM( VSCP_EEPROM_END + EEPROM_ZONE ),
                                                  readEEPROM( VSCP_EEPROM_END + REG_SUBZONE_INP1 + i ),
                                                  '\0', '\0' ); //xxxl
                        ActuateUponLocalEvent( i );    //actuate local output corresponding to this button
                    }
                }
                if (keyval == INP_HOLD) {           // and is still held
                    INP_hold_timer[i] += 1;
                    if ( INP_hold_timer[i] > 50 ) {
                        INP_state[i] = INP_HOLD_REPEAT;
#ifdef SERIAL_DEBUG_INPUTS
    daf_putrs1USART("\r\nINP_HOLD");
#endif
                        if( controlbits & INP_CONTROLBIT_RPT ) {           // trigger on repeat
//                            SendInformationEventData( i , VSCP_CLASS1_INFORMATION, VSCP_TYPE_INFORMATION_BUTTON, INP_HOLD );
                            SendInformationEventData( VSCP_CLASS1_INFORMATION, VSCP_TYPE_INFORMATION_BUTTON,
                                                  INP_HOLD,
                                                  readEEPROM( VSCP_EEPROM_END + EEPROM_ZONE ),
                                                  readEEPROM( VSCP_EEPROM_END + REG_SUBZONE_INP1 + i ),
                                                  '\0', '\0' ); //xxxl
                            ActuateUponLocalEvent( i );    //actuate local output corresponding to this button
                        }
                        INP_hold_timer[i] = 0;
                    }
                    else INP_state[i] = INP_HOLD;
                }
                break;
            case INP_HOLD_REPEAT:                   // button was held for > 500ms(?)
                if (keyval == INP_RELEASED) {       // and is now released
                    INP_state[i] = INP_RELEASED;
#ifdef SERIAL_DEBUG_INPUTS
    daf_putrs1USART("\r\nINP_RELEASED after INP_HOLD_REPEAT");
#endif
                    if( controlbits & INP_CONTROLBIT_FEDG ) {       // trigger on falling edge
//                        SendInformationEventData( i , VSCP_CLASS1_INFORMATION, VSCP_TYPE_INFORMATION_BUTTON, INP_RELEASED );
                        SendInformationEventData( VSCP_CLASS1_INFORMATION, VSCP_TYPE_INFORMATION_BUTTON,
                                                  INP_RELEASED,
                                                  readEEPROM( VSCP_EEPROM_END + EEPROM_ZONE ),
                                                  readEEPROM( VSCP_EEPROM_END + REG_SUBZONE_INP1 + i ),
                                                  '\0', '\0' ); //xxxl
                        ActuateUponLocalEvent( i );    //actuate local output corresponding to this button
                    }
                    INP_hold_timer[i] = 0;
                }
                if (keyval == INP_HOLD) {           // and is still held
                    INP_hold_timer[i] += 1;
#ifdef SERIAL_DEBUG_INPUTS
    daf_putrs1USART("\r\nINP_HOLD after INP_HOLD_REPEAT");
#endif
                    if ( INP_hold_timer[i] > 5 ) {
                        if( controlbits & INP_CONTROLBIT_RPT ) {        // trigger on repeat
//                            SendInformationEventData( i , VSCP_CLASS1_INFORMATION, VSCP_TYPE_INFORMATION_BUTTON, INP_HOLD );
                        SendInformationEventData( VSCP_CLASS1_INFORMATION, VSCP_TYPE_INFORMATION_BUTTON,
                                                  INP_HOLD,
                                                  readEEPROM( VSCP_EEPROM_END + EEPROM_ZONE ),
                                                  readEEPROM( VSCP_EEPROM_END + REG_SUBZONE_INP1 + i ),
                                                  '\0', '\0' ); //xxxl
                            ActuateUponLocalEvent( i );    //actuate local output corresponding to this button
                        }
                        INP_hold_timer[i] = 0;
                    }
                    INP_state[i] = INP_HOLD_REPEAT;
                }
                break;
         } // end switch
    } //end for i
}


void FillEEPROM(void) { //write EEPROM contents with 0's or incrimental numbers, for debugging
#ifdef SERIAL_DEBUG_DUMPEEPROM
    unsigned int LocationIndex;
    unsigned int StartLocation = 0;            //TODO: change to actual VSCP EEPROM location
    unsigned int EndLocation = 1023;//USER_EEPROM_LAST_POS;

    if (EndLocation > 1023)                                 // prevent reading beyond EEPROM memory end
        EndLocation = 1023;

    sprintf(debugstring,
            "\r\n*** FillEEPROM(), StartLocation = %i, EndLocation = %i\r\n",
            StartLocation, EndLocation );
    daf_puts1USART(debugstring);

    for (LocationIndex=0; LocationIndex <= EndLocation; LocationIndex++) {   //for each line
        writeEEPROM( LocationIndex, 0xFF );  //make empty
//        writeEEPROM( LocationIndex, Value);  //fill with incremental value
        sprintf(debugstring,
                "0x%02x:0x%02x\r\n",
//                LocationIndex, Value );  // fill with incremental value
                LocationIndex, readEEPROM( LocationIndex) );
        daf_puts1USART(debugstring);
//        Value++;
    }
    daf_putrs1USART("\r\n");
#endif
}


void DumpEEPROM(void) {  //dump EEPROM contents to USART, for debugging
#ifdef SERIAL_DEBUG_DUMPEEPROM
    int i, j;                           //i = element index, j = column index
    int StartLocation, EndLocation, StartLocationDM, EndLocationDM;
    int colums = 8;

    StartLocation = VSCP_EEPROM_END;  // start off app registers
//    StartLocation = 0;                  // start of vscp registers (app registers follow)
//    EndLocation = VSCP_EEPROM_END + USER_EEPROM_LAST_POS;
    EndLocation = 383;
//    StartLocationDM = (unsigned int)REG_DESCISION_MATRIX;
//    EndLocationDM = (unsigned int)REG_DESCISION_MATRIX + 8 * (unsigned int)DESCISION_MATRIX_ELEMENTS;

    if (EndLocation > 1023)                                 // prevent reading beyond EEPROM memory end
        EndLocation = 1023;
//    if (EndLocationDM > 1023)                                 // prevent reading beyond EEPROM memory end
//        EndLocationDM = 1023;

    sprintf(debugstring,
            "\r\n*** DumpEEPROM(), StartLocation = %i, EndLocation = %i, USER_EEPROM_LAST_POS = %i\r\n",
            StartLocation, EndLocation, USER_EEPROM_LAST_POS );
    daf_puts1USART(debugstring);
    sprintf(debugstring,
            "page select MSB (0x92): %02xx (%02id), LSB (0x93): %02xx (%02id)\r\n",
            (vscp_page_select >> 8) & 0xff, (vscp_page_select >> 8) & 0xff, vscp_page_select & 0xff, vscp_page_select & 0xff );
    daf_puts1USART(debugstring);

/*    sprintf(debugstring,
            "\r\nStartLocationDM = %i, EndLocationDM = %i\r\n",
            StartLocationDM, EndLocationDM);
    daf_puts1USART(debugstring);
*/

    for (i=StartLocation; i <= EndLocation; i++) {   //just dump contents, one line per value (app registers)
//    for (i=0; i <= 530; i++) {   //don't take into account defined locations
        sprintf(debugstring,                 //print EEPROM location and its content
                "%4i:0x%02X / %03id (page 0 reg %i)\r\n",
                i, readEEPROM(i), readEEPROM(i), i - VSCP_EEPROM_END );
        if ( i >= 0 && i <= EndLocation ) {   // page 0 app reg
//        if ( (i>=0   && i<=128) ||  // page 0 app reg
//             (i>=256 && i<=383) ) { // page 1 app reg
            daf_puts1USART(debugstring);         //print to USART
        }
    }

/*    for (i=StartLocationDM; i <= EndLocationDM; i++) {   //just dump contents, one line per value (DM registers)
        sprintf(debugstring,                 //print EEPROM location and its content
                "%4i:0x%02X / %03id (page 1 reg %i)\r\n",
                i, readEEPROM(i), readEEPROM(i), 256 - i );
        daf_puts1USART(debugstring);         //print to USART
    }
*/
/*    //print EEPROM locations in a neat table
    for (i=0; i < ( (EndLocation - StartLocation) / colums ) ; i++) {   //for each line
        for (j=0; j<colums; j++) {               //for each element in this row
            sprintf(debugstring,                 //print EEPROM location and its content
                    "%4i:0x%02X ",
                    ( (EndLocation - StartLocation) / colums * j + i + StartLocation),
                    readEEPROM( (EndLocation - StartLocation) / colums * j + i + StartLocation) );
            daf_puts1USART(debugstring);         //print to USART
        }
        daf_putrs1USART("\r\n");                 //next line
    }
*/
#endif
}

//modified by David so that the function no longer prints the \0 termination character
void daf_puts1USART( char *data)
{
  do
  {  // Transmit a byte
    while(Busy1USART());
    putc1USART(*data);
  } while( *data++ && *data!='\0' );
}

//modified by David so that the function no longer prints the \0 termination character
void daf_putrs1USART(const char *data)
{
  do
  {  // Transmit a byte
    while(Busy1USART());
    putc1USART(*data);
  } while( *data++ && *data!='\0' );
}

