ADDED LED to TESTMASTERSLAVE. It looks nice!
authororemeq
Fri, 12 May 2006 22:14:03 +0200
changeset 3 d9cf34cd6823
parent 2 8d4a822f95e4
child 4 986061160dbb
ADDED LED to TESTMASTERSLAVE. It looks nice!
Some code for the NVRAM support
drivers/Makefile.in
drivers/can_virtual/Makefile.in
drivers/can_virtual/led_virtual.c
drivers/ecos_lpc2138_sja1000/canOpenDriver.c
drivers/ecos_lpc2138_sja1000/lpc2138.h
drivers/ecos_lpc2138_sja1000/lpc2138_pinout.h
drivers/ecos_lpc2138_sja1000/notes.txt
drivers/ecos_lpc2138_sja1000/nvram.h
drivers/ecos_lpc2138_sja1000/nvram_iap.c
drivers/ecos_lpc2138_sja1000/nvram_iap.h
drivers/ecos_lpc2138_sja1000/nvram_readme
drivers/ecos_lpc2138_sja1000/sja1000.c
examples/TestMasterSlave/Makefile.in
include/can_driver.h
include/led.h
src/Makefile.in
src/led.c
--- a/drivers/Makefile.in	Thu May 11 13:52:43 2006 +0200
+++ b/drivers/Makefile.in	Fri May 12 22:14:03 2006 +0200
@@ -24,6 +24,7 @@
 TARGET = SUB_TARGET
 CAN_DRIVER = SUB_CAN_DRIVER
 TIMERS_DRIVER = SUB_TIMERS_DRIVER
+LED_ENABLE = SUB_LED_ENABLE
 
 all: driver
 
--- a/drivers/can_virtual/Makefile.in	Thu May 11 13:52:43 2006 +0200
+++ b/drivers/can_virtual/Makefile.in	Fri May 12 22:14:03 2006 +0200
@@ -33,6 +33,7 @@
 TARGET = SUB_TARGET
 CAN_DRIVER = SUB_CAN_DRIVER
 TIMERS_DRIVER = SUB_TIMERS_DRIVER
+LED_ENABLE = SUB_LED_ENABLE
 
 INCLUDES = -I../../include -I../../include/$(TARGET) -I../../include/$(CAN_DRIVER) -I../../include/$(TIMERS_DRIVER)
 
--- a/drivers/can_virtual/led_virtual.c	Thu May 11 13:52:43 2006 +0200
+++ b/drivers/can_virtual/led_virtual.c	Fri May 12 22:14:03 2006 +0200
@@ -1,20 +1,18 @@
 /***************************************************************************/
+#include <data.h>
 #include <led.h>
 
-void led_set_redgreen(CO_Data *d, int state)
+void led_set_redgreen(CO_Data *d, unsigned char state)
 {
+        if (state & 0x01)
+                printf("\e[41m ERROR LED ON \e[m          ");
+        else
+                printf("\e[31m error led off \e[m         ");
 
-        printf("LEDS %d\n",bits);
-
-        if (bits & 0x01)
-                printf("\e[41m ERROR LED ON \e[m\n");
-        else
-                printf("error led off\n");
-
-        if (bits & 0x02)
+        if (state & 0x02)
                 printf("\e[34;42m RUN LED ON \e[m\n");
         else
-                printf("run led off\n");
+                printf("\e[32m run led off \e[m\n");
 }
 
 
--- a/drivers/ecos_lpc2138_sja1000/canOpenDriver.c	Thu May 11 13:52:43 2006 +0200
+++ b/drivers/ecos_lpc2138_sja1000/canOpenDriver.c	Fri May 12 22:14:03 2006 +0200
@@ -155,25 +155,66 @@
 
 int nvram_open(void)
 {
+	int n = NVRAM_BLOCK_SIZE / sizeof(unsigned int);
+
 	/* some actions to initialise the flash */
 	data_len = 0;
-
-	data_addr = 0; 
-
-	data_page = (unsigned int *)malloc(sizeof(unsigned int) * 64);
-	memset(data_page, 0, sizeof(unsigned int)*64);
+	data_num_pages = 0;
+
+	data_page = (unsigned int *)malloc(sizeof(unsigned int) * n);
+	memset(data_page, 0, sizeof(unsigned int)*n);
 
 	if (data_page == NULL)
 		return -1;
 
+	regs_page = (unsigned int *)malloc(sizeof(unsigned int) * n);
+	memset(regs_page, 0, sizeof(unsigned int)*n);
+	if (regs_page == NULL)
+		return -2;
+
+	iat_flash_read_regs();
+
+	/* start the data at the location specified in the registers */ 
+	if (0) /* for now it is 0, but put here a test to know whether
+                  or not the NVRAM has been written before */
+		data_addr = regs_page[1];
+	else
+		data_addr = NVRAM_BLOCK_SIZE; /* let start at block 1 */
+
 	return 0;
 }
 
 
 void nvram_close(void)
 {
+	/* write the last page before closing */
+	iat_flash_write_page(data_addr);
+
 	/* some actions to end accessing the flash */
 	free(data_page);
+
+	regs_page[4] = data_num_pages;
+	/* write the registers to the NVRAM before closing */
+	iat_flash_write_regs();
+	free(regs_page);
+}
+
+
+void nvram_set_pos(UNS32 pos)
+/* set the current position in the NVRAM to pos */
+{
+}
+
+
+void nvram_new_firmwave()
+{
+/*
+	this function is called whenever a new firmware is about
+	to be written in the NVRAM
+*/
+	data_addr = regs_page[1] + regs_page[4]*NVRAM_BLOCK_SIZE;
+	if (data_addr > NVRAM_MAX_SIZE)
+		data_addr = NVRAM_BLOCK_SIZE;
 }
 
 int _get_data_len(int type)
@@ -233,16 +274,22 @@
 }
 
 
-char nvram_write(int type, int access_attr, void *data)
+char nvram_write_data(int type, int access_attr, void *data)
 /* return 0 if successfull */
 {
 	int len = _get_data_len(type);
 
-	if (data_len+len > 256)
+	if (data_len+len > NVRAM_BLOCK_SIZE)
 	{
 		iat_flash_write_page(data_addr);
 		data_len = 0;
-		data_addr += 256;
+		data_addr += NVRAM_BLOCK_SIZE; 
+
+		/* wrap-around address pointer */
+		if (data_addr > NVRAM_MAX_SIZE)
+			data_addr = NVRAM_BLOCK_SIZE;
+
+		data_num_pages++;
 	}
 		
 	memcpy(((char *)data_page)+data_len, data, len);
@@ -253,14 +300,19 @@
 }
 
 
-char nvram_read(int type, int access_attr, void *data)
+char nvram_read_data(int type, int access_attr, void *data)
 /* return 0 if successful */
 {
 	int len = _get_data_len(type);
 
-	if (data_len+len > 256)
+	if (data_len+len > NVRAM_BLOCK_SIZE)
 	{
-		data_addr += 256;
+		data_addr += NVRAM_BLOCK_SIZE;
+
+		/* wrap-around address pointer */
+		if (data_addr > NVRAM_MAX_SIZE)
+			data_addr = NVRAM_BLOCK_SIZE;
+
 		iat_flash_read_page(data_addr);
 		data_len = 0;		
 	}
@@ -272,12 +324,36 @@
 	return 0;
 }
 
+/*
+	NVRAM registers at block 0
+	pos        description
+	0          version of the current dictionnary
+	1          starting address for data block
+	2          date of last writing
+	3          address of the previous dictionnary          
+	4          size in pages of the current dict
+*/
+void nvram_write_reg(UNS32 reg, UNS16 pos)
+/* write reg at the position in the data block 0 */
+{
+	regs_page[pos] = reg;
+}
+
+UNS32 nvram_read_reg(UNS16 pos)
+/* read reg at the position in the data block 0 */
+{
+	return regs_page[pos];
+}
+
 
 /*
 	LED
 */
 
-void led_set_redgreen(unsigned char bits)
+void led_set_redgreen(UNS8 bits)
+/* bits : each bit of this uns8 is assigned a led 
+          0=off, 1=on
+*/
 {
 	lpc2138_redgreenled_set(bits);
 }
--- a/drivers/ecos_lpc2138_sja1000/lpc2138.h	Thu May 11 13:52:43 2006 +0200
+++ b/drivers/ecos_lpc2138_sja1000/lpc2138.h	Fri May 12 22:14:03 2006 +0200
@@ -25,10 +25,16 @@
 #define _LPC2138_H_
 
 
+/* block and maximum size of NVRRAM in bytes */ 
+#define NVRAM_BLOCK_SIZE 256
+#define NVRAM_MAX_SIZE 1024*512
+
 extern short data_len;
+extern short data_num_pages;
 extern unsigned int *data_page;
 extern unsigned int data_addr;
 
+extern unsigned int *regs_page;
 
 void lpc2138_pinsel_set(int pin, LPC2138_PORT port, int size, int func); 
 void lpc2138_pinsel_clear(void); 
@@ -45,7 +51,9 @@
 void iat_flash_erase(unsigned int command_ee,unsigned int result_ee[]);
 void iat_flash_write_page(unsigned int addr);
 void iat_flash_read_page(unsigned int addr);
-
+ 
+void iat_flash_write_regs(void);
+void iat_flash_read_regs(void);
 
 #endif
 
--- a/drivers/ecos_lpc2138_sja1000/lpc2138_pinout.h	Thu May 11 13:52:43 2006 +0200
+++ b/drivers/ecos_lpc2138_sja1000/lpc2138_pinout.h	Fri May 12 22:14:03 2006 +0200
@@ -1,7 +1,19 @@
 /*
 This file is part of CanFestival, a library implementing CanOpen Stack.
+  ____    _    _   _
+ / ___|  / \  | \ | | ___  _ __   ___ _ __
+| |     / _ \ |  \| |/ _ \| '_ \ / _ \ '_ \
+| |___ / ___ \| |\  | (_) | |_) |  __/ | | |
+ \____/_/   \_\_| \_|\___/| .__/ \___|_| |_|
+                          |_|
+          ____                      _
+         / ___|__ _ _ __   __ _  __| | __ _
+        | |   / _` | '_ \ / _` |/ _` |/ _` |
+        | |__| (_| | | | | (_| | (_| | (_| |
+         \____\__,_|_| |_|\__,_|\__,_|\__,_|
 
- Author: Christian Fortin (canfestival@canopencanada.ca)
+                   canfestival@canopencanada.ca
+/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
 
 See COPYING file for copyrights details.
 
@@ -82,9 +94,13 @@
 #define LPC2138_ale_PORT               P0
 #define LPC2138_ale_SIZE                1
 
-#define LPC2138_redgreenled             27 /* Pin 27 */
-#define LPC2138_redgreenled_PORT        P0
-#define LPC2138_redgreenled_SIZE        2
+#define LPC2138_redled                 27 /* Pin 27 */
+#define LPC2138_redled_PORT            P0
+#define LPC2138_redled_SIZE             1
+
+#define LPC2138_greenled               28 /* Pin 28 */
+#define LPC2138_greenled_PORT          P0
+#define LPC2138_greenled_SIZE           1
 
 #define LPC2138_rd                     29 /* Pin 29 */
 #define LPC2138_rd_PORT                P0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/ecos_lpc2138_sja1000/notes.txt	Fri May 12 22:14:03 2006 +0200
@@ -0,0 +1,18 @@
+canOpenDriver.c
+	f_can_send
+	f_can_receive
+	interrupts
+	nvram_save/load
+	baudrate
+
+sja1000.c
+	hardware init 
+	
+lpc2138.c
+	iat_flash
+
+time_slicer.c
+	settimer
+	alarm
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/ecos_lpc2138_sja1000/nvram.h	Fri May 12 22:14:03 2006 +0200
@@ -0,0 +1,49 @@
+/*
+This file is part of CanFestival, a library implementing CanOpen Stack.
+  ____    _    _   _
+ / ___|  / \  | \ | | ___  _ __   ___ _ __
+| |     / _ \ |  \| |/ _ \| '_ \ / _ \ '_ \
+| |___ / ___ \| |\  | (_) | |_) |  __/ | | |
+ \____/_/   \_\_| \_|\___/| .__/ \___|_| |_|
+                          |_|
+          ____                      _
+         / ___|__ _ _ __   __ _  __| | __ _
+        | |   / _` | '_ \ / _` |/ _` |/ _` |
+        | |__| (_| | | | | (_| | (_| | (_| |
+         \____\__,_|_| |_|\__,_|\__,_|\__,_|
+
+                   canfestival@canopencanada.ca
+/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
+
+See COPYING file for copyrights details.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#if !defined(_NVRAM_IO_H_)
+#define _NVRAM_IO_H_
+
+
+int    nvram_open(void);
+void   nvram_close(void);
+
+char nvram_write_data(int type, int access_attr, void *data);
+char nvram_read_data(int type, int access_attr, void *data);
+
+void nvram_write_regs(void);
+void nvram_read_regs(void);
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/ecos_lpc2138_sja1000/nvram_iap.c	Fri May 12 22:14:03 2006 +0200
@@ -0,0 +1,318 @@
+/*
+                   canfestival@canopencanada.ca
+
+See COPYING file for copyrights details.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+flash.c
+	save to / retrieve from  the non-volatile memory
+	to be tested
+	- can we write/read into an address without working with the whole page (256bytes)
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "applicfg.h"
+#include "data.h"
+#include "objdictdef.h"
+
+#include "lpc2138_defs.h"                    /* LPC21xx definitions */
+
+#define IAP_LOCATION 			0x7ffffff1
+
+
+// define a page of data of NVRAM_BLOCK_SIZE bytes
+//
+short data_len; /* 0 to NVRAM_BLOCK_SIZE bytes */
+short data_num_pages;
+unsigned int *data_page = NULL;
+unsigned int data_addr;
+
+unsigned int *regs_page = NULL;
+
+// local definitons
+void ee_erase(unsigned int ,unsigned int[]);		//function erases EEPROM
+void ee_write_page(unsigned int);	//function adds a record in EEPROM
+void ee_read_page(unsigned int);	//function reads the latest valid record in EEPROM
+
+typedef void (*IAP)(unsigned int [],unsigned int[]);
+IAP iap_entry;
+
+
+
+/************************************************************************/
+/*                                                                    	*/
+/* function:								*/
+/*  void ee_erase(unsigned int command_ee,unsigned int result_ee[])	*/
+/*                                                                     	*/
+/* type: void                                                          	*/
+/*                                                                     	*/
+/* parameters: 								*/
+/* 	command_ee   - Not used.  	               			*/
+/*  result_ee[0] - Returns a response to the last IAP command used.	*/
+/*                 0 - EEPROM successfully erased.			*/
+/*                 For all other response values, see microcontroller 	*/
+/*		   User Manual, IAP Commands and Status Codes Summary.	*/
+/*  result_ee[1] - Not used.                         			*/
+/*                                                                     	*/
+/* version: 1.1 (01/27/2006)                                           	*/
+/*                                                                     	*/
+/* constants defined in LPC2k_ee.h used in this function:              	*/
+/*  EE_SEC_L 	 - microcontroller's Flash sector where EEPROM begins	*/
+/*  EE_SEC_H 	 - microcontroller's Flash sector where EEPROM ends	*/
+/*  EE_CCLK		 - microcontroller's system clock (cclk)        */
+/*                                                                     	*/
+/* description:								*/
+/*  This function erases LPC2000 on-chip Flash sectors selected to act 	*/
+/*  as an EEPROM. All Flash sectors between EE_SEC_L abd EE_SEC_H	*/
+/*  (including these sectors) will be erased using the In Application	*/
+/*  Programming (IAP) routines (see User Manual for more details). 	*/
+/*  Also, this function disables all interrupts while erasing the       */
+/*  EEPROM. If this is not needed, three lines of the ee_erase          */
+/*  subroutine can simply be commented-out without affecting the        */
+/*  routine performance at all.                                         */
+/*                                                                     	*/
+/* revision history:                                                   	*/
+/* - Rev. 1.1 adds interrupt disable feature.				*/
+/*                                                                     	*/
+/************************************************************************/
+void ee_erase(unsigned int command_ee,unsigned int result_ee[])
+{
+	unsigned int command_iap[5];
+	unsigned int result_iap[3];
+	unsigned long int enabled_interrupts;
+
+	enabled_interrupts = VICIntEnable;  //disable all interrupts
+	VICIntEnClr        = enabled_interrupts;
+
+	command_iap[0]=50;	// prepare sectors from EE_SEC_L to EE_SEC_H for erase
+	command_iap[1]=EE_SEC_L;
+	command_iap[2]=EE_SEC_H;
+	iap_entry=(IAP) IAP_LOCATION;
+	iap_entry(command_iap,result_iap);
+
+	command_iap[0]=52;	// erase sectors from EE_SEC_L to EE_SEC_H
+	command_iap[1]=EE_SEC_L;
+	command_iap[2]=EE_SEC_H;
+	command_iap[3]=EE_CCLK;
+	iap_entry=(IAP) IAP_LOCATION;
+	iap_entry(command_iap,result_iap);
+
+	command_iap[0]=53;	// blankcheck sectors from EE_SEC_L to EE_SEC_H
+	command_iap[1]=EE_SEC_L;
+	command_iap[2]=EE_SEC_H;
+	iap_entry=(IAP) IAP_LOCATION;
+	iap_entry(command_iap,result_iap);
+
+	VICIntEnable = enabled_interrupts;  //restore interrupt enable register
+
+	result_ee[0]=result_iap[0];
+	return;
+}
+
+/************************************************************************/
+/*                                                                    	*/
+/* function: 								*/
+/*  void ee_write(unsigned int command_ee,unsigned int result_ee[])	*/
+/*                                                                     	*/
+/* type: void                                                          	*/
+/*                                                                     	*/
+/* parameters: 								*/
+/* 	command_ee   - An address of a content of ee_data type that has	*/
+/*                 to be programmed into EEPROM.                       	*/
+/*  result_ee[0] - Returns a response to the last IAP command used.	*/
+/*                 0 - data successfully programmed in EEPROM.		*/
+/*               501 - no space in EEPROM to program data.             	*/
+/*                 For all other response values, see microcontroller 	*/
+/*		   User Manual, IAP Commands and Status Codes Summary.	*/
+/*  result_ee[1] - Not used.                           			*/
+/*                                                                     	*/
+/* version: 1.1 (01/27/2006)                                           	*/
+/*                                                                     	*/
+/* constants defined in LPC2k_ee.h used in this function:              	*/
+/*  EE_BUFFER_SIZE 	   - IAP buffer size; must be 256 or 512 	*/
+/*  NO_SPACE_IN_EEPROM - EEPROM is full and no data can be programmed	*/
+/*  EE_BUFFER_MASK	   - parameter used for interfacing with IAP	*/
+/*  EE_REC_SIZE   	   - ee_data structure size in bytes        	*/
+/*  EE_SEC_L 	 	   - micro's Flash sector where EEPROM begins	*/
+/*  EE_SEC_H 	 	   - micro's Flash sector where EEPROM ends	*/
+/*  EE_CCLK		 	   - micro's system clock (cclk)       	*/
+/*                                                                     	*/
+/* description:								*/
+/*  This function writes a single structure of ee_data type into the	*/
+/*  EEPROM using an In Application	Programming (IAP) routines (see */
+/*  User Manual for more details). command_ee contains an address of	*/
+/*  this structure. EEPROM is scanned for the last (if any) record 	*/
+/*  identifier (EE_REC_ID), and a new record is added next to it.      	*/
+/*  Also, this function disables all interrupts while erasing the       */
+/*  EEPROM. If this is not needed, three lines of the ee_write          */
+/*  subroutine can simply be commented-out without affecting the        */
+/*  routine performance at all.                                         */
+/*                                                                     	*/
+/* revision history:                                                   	*/
+/* - Rev. 1.1 fixes a bug related to verifying a content written into	*/
+/*   the EEPROM. 1.0 was reporting missmatch even when there were no	*/
+/*   problems at all.							*/
+/*   Rev. 1.1 adds interrupt disable feature.				*/
+/*                                                                     	*/
+/************************************************************************/
+
+void ee_write_page(unsigned int addr)
+{
+	unsigned long int enabled_interrupts;
+	// unsigned char ee_buffer[16];
+	unsigned int command_iap[5], result_iap[3];
+
+	enabled_interrupts = VICIntEnable;  //disable all interrupts
+	VICIntEnClr        = enabled_interrupts;
+
+	iap_entry = (IAP) IAP_LOCATION;
+
+	// prepare sectors from EE_SEC_L to EE_SEC_H for erase
+	command_iap[0] = 50;			
+	command_iap[1] = EE_SEC_L;
+	command_iap[2] = EE_SEC_H;
+	iap_entry(command_iap, result_iap);
+
+	// copy RAM to flash/eeprom
+	command_iap[0] = 51;
+	command_iap[1] = (unsigned int) (addr & EE_START_MASK); // 256 kb boundary
+	command_iap[2] = (unsigned int) (data_page);            // should be on a word boundary
+	command_iap[3] = 256;
+	command_iap[4] = EE_CCLK;
+	iap_entry(command_iap, result_iap);
+
+#if 0 
+	// compare RAM and flash/eeprom
+	command_iap[0] = 56;
+	command_iap[1] = (unsigned int) data;
+	command_iap[2] = addr;
+	command_iap[3] = dlen;
+	iap_entry(command_iap, result_iap);
+#endif
+
+	VICIntEnable = enabled_interrupts;  //restore interrupt enable register
+}
+
+
+/************************************************************************/
+/*                                                                    	*/
+/* function: 								*/
+/*  void ee_read(unsigned int command_ee,unsigned int result_ee[])	*/
+/*                                                                     	*/
+/* type: void                                                          	*/
+/*                                                                     	*/
+/* parameters: 								*/
+/* 	command_ee   - Not used.					*/
+/*  result_ee[0] - Returns a response.					*/
+/*                 0 - data successfully found in EEPROM.		*/
+/*               500 - no data/records available in EEPROM.		*/
+/*  result_ee[1] - an address of the last record of ee_data type	*/
+/*				   in EEPROM.  	              		*/
+/*                                                                     	*/
+/* version: 1.1 (01/27/2006)                                           	*/
+/*                                                                     	*/
+/* constants defined in LPC2k_ee.h used in this function:              	*/
+/*  NO_RECORDS_AVAILABLE - EEPROM is empty/no records identifiable	*/
+/*			   with a record identifier (EE_REC_ID) found	*/
+/*  EE_ADR_L 	    - micro's Flash address from where EEPROM begins	*/
+/*  EE_REC_SIZE    - size (in bytes) of a ee_data structure        	*/
+/*                                                                 	*/
+/* description:								*/
+/*  This function scans an EEPROM content looking for the last record 	*/
+/*  that can be identified with a record identifier (EE_REC_ID). When 	*/
+/*  such data is found, its address is passed as result_ee[1].		*/
+/*                                                                     	*/
+/* revision history:                                                   	*/
+/* - Rev. 1.0 had problems with accessing the last record in a fully	*/
+/*   occupied EEPROM. Rev. 1.1 fixes this.				*/
+/*                                                                     	*/
+/************************************************************************/
+void ee_read_page(unsigned int addr)
+{
+	memcpy(data_page, (unsigned int *)addr, sizeof(unsigned int)*64);
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+/*
+	CAN FESTIVAL interface functions
+*/
+
+
+int _get_data_len(int type)
+{
+	int len = 0; /* number of bytes */
+	switch(type)
+	{
+		case  boolean:
+			len = 1;
+			break;
+
+		case  int8:
+		case  uint8:
+			len = 1;
+			break;
+		case  int16:
+		case  uint16:
+			len = 2;
+			break;
+		case  int24:
+		case  uint24:
+			len = 3;
+			break;
+		case  int32:
+		case  uint32:
+		case  real32:
+			len = 4;
+			break;
+		case  int40:
+		case  uint40:
+			len = 5;
+			break;
+		case  int48:
+		case  uint48:
+			len = 6;
+			break;
+		case  int56:
+		case  uint56:
+			len = 7;
+			break;
+		case  int64:
+		case  uint64:
+		case  real64:
+			len = 8;
+			break;
+#if 0
+/* TO DO */
+		case  visible_string:
+		case  octet_string:
+		case  unicode_string:
+		case  time_of_day:
+		case  time_difference:
+#endif
+	}
+
+	return len;
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/ecos_lpc2138_sja1000/nvram_iap.h	Fri May 12 22:14:03 2006 +0200
@@ -0,0 +1,176 @@
+/*
+This file is part of CanFestival, a library implementing CanOpen Stack.
+                   canfestival@canopencanada.ca
+
+See COPYING file for copyrights details.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+/************************************************************************/
+/*                                                                    	*/
+/*	LPC2k_ee.H:  Header file enabling EEPROM support		*/
+/* 	for Philips LPC2000 microcontroller's on-chip Flash memory	*/
+/*     	(revision 1.0, May 13th, 2005.)					*/
+/*                                                             		*/
+/*	This file is to be used with LPC2k_ee.c	file 		  	*/
+/*                                                                     	*/
+/* IMPORTANT: on-chip Flash memory sector(s) intended to be used as 	*/
+/* an EEPROM will be unavailable for regular code storage! The smallest	*/
+/* amount of Flash memory that can be used as an EEPROM is a single 	*/
+/* Flash sector (regardless of the Flash sector actual size). 		*/
+/*                                                                     	*/
+/* If size of desired EEPROM requires several Flash sectors, these	*/
+/* sectors must be a consecutive ones.					*/
+/*                                                                     	*/
+/************************************************************************/
+
+#define EE_SEC_L		1		//Flash sector where EEPROM begins (see UM for details)
+#define EE_SEC_H		3	  	//Flash sector where EEPROM ends (see UM for details)
+#define EE_ADDR_L		0x00001000	//Must match the EE_SEC_L Flash sector start address
+#define EE_ADDR_H		0x00003FFF 	//Must match the EE_SEC_H Flash sector end address
+#define EE_CCLK			60000		//system clock cclk expressed in kHz (5*12 MHz)
+
+/************************************************************************/
+/*                                                                    	*/
+/* ee_data structure can be defined differently from this example.	*/
+/* The only requirement is to have _id field as it is defined here	*/
+/* since EE_REC_ID character is used to identify a record's presence	*/
+/* in the EEPROM memory.						*/
+/*                                                                     	*/
+/* ====================================================================	*/
+/*                                                                     	*/
+/* IMPORTANT ARM memory access considerations:				*/
+/*                                                                     	*/
+/* char	: byte alligned. Can be accessed at any location in memory.	*/
+/*                                                                     	*/
+/* short int: occupies 2 consecutive bytes. It can be read/write 	*/
+/*	  accessed only when half-word alligned. Therefore, it is	*/
+/* 	  located at addresses ending with 0x0, 0x2, 0x4, 0x6, 0x8,	*/
+/*	  0xA, 0xC or 0xE.						*/
+/*                                                                     	*/
+/* int	: occupies 4 consecutive bytes.	It can be read/write 		*/
+/*	  accessed only when half-word alligned. Therefore, it is	*/
+/* 	  located at addresses ending with 0x0, 0x4, 0x8 or 0xC.	*/
+/*                                                                     	*/
+/* ====================================================================	*/
+/*                                                                     	*/
+/* Due to the LPC2000 Flash memory characteristics, an ee_data 		*/
+/* structure size (EE_REC_SIZE) is limited to the following set:	*/
+/*                                                                     	*/
+/* LPC2101/2/3, LPC2131/2/4/6/8, LPC2141/2/4/6/8: 0x10, 0x20, 0x40,     */ 
+/*                                                0x80 or 0x100         */
+/*                                                                     	*/
+/* LPC2104/5/6, LPC2112/4/9, LPC2124/9, LPC2192/4: 0x10, 0x20, 0x40,    */
+/*                                                 0x80, 0x100 or 0x200 */
+/*                                                                     	*/
+/* ====================================================================	*/
+/*                                                                     	*/
+/* example1:                                                          	*/
+/*                                                                     	*/
+/* struct ee_data{		//structure starts as word alligned	*/
+/*	unsigned char	_id;	//1 byte  - no allignement restr.	*/
+/*                                  // 	    3 BYTE GAP!!!!         	*/		
+/*	unsigned int	_rec_count; //4 bytes - must be word alligned!	*/
+/*	unsigned char	_cs;	//1 byte  - no allignement restr.	*/
+/*};				// next structure will start as		*/
+/*                                  // word alligned...                 */
+/* Structure in example 1 occupies 12 bytes of memory			*/
+/*                                                                     	*/
+/* --------------------------------------------------------------------	*/
+/*                                                                     	*/
+/* example2:                                                          	*/
+/*                                                                     	*/
+/* struct ee_data{		//structure starts as word alligned	*/
+/*	unsigned char	_id;	//1 byte  - no allignement restr.	*/
+/*	unsigned char	_cs;	//1 byte  - no allignement restr.	*/
+/*                              //  	    2 BYTE GAP!!!!         	*/		
+/*	unsigned int	_rec_count; //4 bytes - must be word alligned!	*/
+/*};				// next structure will start as		*/
+/*                                  // word alligned...                 */
+/* Structure in example 2 occupies 8 bytes of memory			*/
+/*                                                                     	*/
+/************************************************************************/
+
+struct ee_data{
+	unsigned char	_id;		//  4 bytes: 1 byte (char) + 3 byte GAP!
+	unsigned int	_rec_count;	//  4 bytes (int)
+	unsigned int	_counter;	//  4 bytes (int)
+	unsigned char	_cs;		//  4 bytes: 1 byte (char) + 3 byte GAP!
+};					// 16 bytes total
+
+/************************************************************************/
+/*									*/
+/* 	Disclaimer: all observations presented in example1, example 2 and */
+/*	ee_data structure defined here are based on Keil's ARM compiler. */
+/*	If another compiler is used, memory usage would have to be 	*/
+/*	re-examined and verified.					*/
+/*									*/
+/************************************************************************/
+
+
+#define EE_REC_SIZE		0x10	//see restrictions from above
+
+/********************************************************************/
+/*									*/
+/* 	Valid combinations for 						*/
+/* EE_REC_SIZE, EE_BUFFER_SIZE, EE_BUFFER_MASK and EE_START_MASK	*/
+/*									*/
+/* EE_BUFFER_SIZE ! EE_START_MASK ! EE_REC_SIZE ! EE_BUFFER_MASK	*/
+/* ----------------------------------------------------------------	*/
+/*    	256	0xFFFFFF00		0x010	  	0xF0		*/
+/*	256	0xFFFFFF00		0x020	 	0xE0		*/
+/*    	256	0xFFFFFF00		0x040	  	0xC0		*/
+/*	256	0xFFFFFF00		0x080	 	0x80		*/
+/*	256	0xFFFFFF00		0x100		0x00		*/
+/* ---------------------------------------------------------------- */
+/*    	512	0xFFFFFE00		0x010	  	0x1F0		*/
+/*	512	0xFFFFFE00		0x020	 	0x1E0		*/
+/*    	512	0xFFFFFE00		0x040	  	0x1C0		*/
+/*	512	0xFFFFFE00		0x080		0x180	 	*/
+/*	512	0xFFFFFE00		0x100	 	0x100		*/
+/*	512	0xFFFFFE00		0x200	 	0x000		*/
+/********************************************************************/
+/*	For LPC2101/2/3, LPC213x and LPC214x EE_BUFFER_SIZE is 256. */
+/*	For all other LPC2000 devices EE_BUFFER_SIZE is always 512. */
+/********************************************************************/
+#define EE_BUFFER_SIZE	256
+#define EE_START_MASK	0xFFFFFF00
+#define EE_BUFFER_MASK	0x000000F0
+
+/********************************************************************/
+/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
+/*!!								  !!*/
+/*!!								  !!*/
+/*!! 	DO NOT MODIFY THE FOLLOWING CODE!!!			  !!*/
+/*!!	===================================			  !!*/
+/*!!								  !!*/
+/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
+/********************************************************************/
+
+#define EE_REC_ID 				0xAA
+#define EE_SIZE					(EE_ADDR_H+1-EE_ADDR_L)
+#define NO_RECORDS_AVAILABLE	500
+#define NO_SPACE_IN_EEPROM		501
+#define INDEX_OUT_OF_RANGE		502
+
+#ifndef _EEPROM_
+	extern const unsigned char eeprom[];
+	extern void ee_erase(unsigned int , unsigned int []);	//function erases EEPROM
+	extern void ee_write(unsigned int , unsigned int []);	//function adds a record in EEPROM
+	extern void ee_read (unsigned int , unsigned int []);	//function reads the latest valid record in EEPROM
+	extern void ee_readn(unsigned int , unsigned int []);	//function reads n-th record in EEPROM
+	extern void ee_count(unsigned int , unsigned int []);	//function counts records in EEPROM
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/ecos_lpc2138_sja1000/nvram_readme	Fri May 12 22:14:03 2006 +0200
@@ -0,0 +1,61 @@
+procedure for NVRAM
+===================
+
+data block 0
+------------
+This data block is located at the beginning of the NVRAM and contains
+a series of registers.
+eg. 1. the version number of the current dictionnary (32 bits)
+    2. pointer to the current dictionnary (32 bits)
+    3. date of last dictionnary dump (32 bits)
+    4. pointer to the last dict (32 bits)
+    5. size in page of the current dict
+
+a minimum number of registers should always be in this block (including a number of 'for future use' 32 bits registers). the remaining space will be left to the developper
+
+a 256kb data block could handled 64 registers 
+
+data block 1 to N
+-----------------
+The place where to put the content of the dictionnary
+
+
+procedure to write in the NVRAM
+-------------------------------
+for each sub-index
+add a flag indicating the state
+	= 0  : normal
+	= -1 : this is a old sub-index, no longer used
+	= +1 : this is a new sub-index
+
+the sub-indexed flaged to -1 could be remove when doing a new release of dictionnary
+eg. from BIOS V0 to V1, flag the old sub-index to -1.  but when going to V2, those must be remove from the dictionnary
+
+this flag is important when reloading the old NVRAM content. Since the writing and reading are done sequentially, the dictionnary and the NVRAM must be synchronised.
+
+
+ON BOOT
+-------
+1. read the block data 0 and check the NVRAM version number against the current dictionnary
+if the dict version = NVRAM version, then read the NVRAM using the normal procedure (state=0 and state=+1)
+if the dict version is newer then the NVRAM, read the NVRAM using the state=0 and state=-1 . this will ensure a synchone reading of the data
+
+2. if this is a new NVRAM, write the whole dictionnary to a NEW position in the NVRAM.
+	write all sub-indexes with state=0 and =+1, do not write does with state=-1
+	write the new version number in the registery and the date
+
+
+ON WRITE
+--------
+write the content of the whole dict (only those sub-indexes that must be saved) to the NVRAM
+write the version number  
+write the date
+
+
+NEW VERSION OF BIOS
+-------------------
+When a new version of BIOS is downloaded into the device, special procedure must be taken (cf. ON BOOT and ON WRITE). But to avoid problem during the update (i.e. lost of NVRAM data or worst NVRAM corruption) fewer NVRAM manipulation should be performed. Therefore, when writing the new dictionary to NVRAM, it should be put AFTER the previous one. This will provide a way to go back and fetch the previous dictionnary saved values if needed. 
+
+Obviously, the NVRAM has a limited capacity and it is possible that the new BIOS will overshoot the upper limit of memory. In that case, the algorithm should do a loop-around the addressed. Meaning, if the last block of data is reached, go back to data block 1 (data block 0 = registers). If the NVRAM is large enough, it should not cause problem (i.e. overwritting the beginning of the actual dict).
+
+Data Block 0 has the offset in memory to access the current dict. It also containt the pointer to the last version of the dict. Since the algo writing to the NVRAM does not compact memory, the size of the dict is not necessarily the size of the NVRAM memory it occupies.
--- a/drivers/ecos_lpc2138_sja1000/sja1000.c	Thu May 11 13:52:43 2006 +0200
+++ b/drivers/ecos_lpc2138_sja1000/sja1000.c	Fri May 12 22:14:03 2006 +0200
@@ -20,4 +20,159 @@
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 
+#include <cyg/kernel/kapi.h>
+#include <cyg/hal/hal_arch.h>
 
+#include "lpc2138_pinout.h"
+#include "lpc2138_defs.h"
+#include "lpc2138.h"
+
+#include "sja1000.h"
+
+
+#define CYGNUM_HAL_INTERRUPT_1 CYGNUM_HAL_INTERRUPT_EINT1
+#define CYGNUM_HAL_PRI_HIGH    0
+
+
+cyg_uint32 interrupt_1_isr(cyg_vector_t vector, cyg_addrword_t data);
+void interrupt_1_dsr(cyg_vector_t   vector,
+                            cyg_ucount32   count,
+                            cyg_addrword_t data);
+
+
+/* Interrupt for CAN device. */
+static cyg_interrupt interrupt_1;
+static cyg_handle_t  interrupt_1_handle;
+
+
+void init_sja1000(void)
+{
+    do
+    {
+        sja1000_write(MOD, 1<<RM);                  /* demande reset */
+    }
+    while ((sja1000_read(MOD) & (1<<RM)) == 0);   /* loop until reset good */
+
+/*
+    sja1000_write(bustiming0, ((0<<SJW1)|(0<<SJW0)|(0<<BRP5)|(0<<BRP4)|(0<<BRP3)|(0<<BRP2)|(0<<BRP1)|(0<<BRP0)));
+    sja1000_write(bustiming1, ((1<<SAM)|(0<<TSEG22)|(1<<TSEG21)|(0<<TSEG20)|(0<<TSEG13)|(1<<TSEG12)|(0<<TSEG11)|(0<<TSEG10)));
+*/
+
+/* OUTPUT CONTROL REGISTER */
+    sja1000_write(outputcontrol, ((1<<OCTP1)|(1<<OCTN1)|(0<<OCPOL1)|(1<<OCTP0)|(1<<OCTN0)|(0<<OCPOL0)|(1<<OCMODE1)|(0<<OCMODE0)));
+
+
+    sja1000_write(clockdivider, ((1<<CANmode)|(1<<CBP)|(1<<RXINTEN)|(0<<clockoff)|(1<<CD2)|(1<<CD1)|(1<<CD0)));
+    sja1000_write(16,  0x01);   /* 0 code all accept block high bit */
+    sja1000_write(17,  0x00);   /* 0 all accept block high bit */
+    sja1000_write(18,  0x00);   /* 0 all accept block high bit */
+    sja1000_write(19,  0x00);   /* 0 all accept block high bit */
+    sja1000_write(20,  0xFE);   /* 1 mask */
+    sja1000_write(21,  0xFF);
+    sja1000_write(22,  0xFF);
+    sja1000_write(23,  0xFF);
+    sja1000_write(IER, 0x01);
+    sja1000_write(clockdivider, ((1<<CANmode)|(1<<CBP)|(1<<RXINTEN)|(0<<clockoff)|(1<<CD2)|(1<<CD1)|(0<<CD0)));
+
+    do
+    {
+        sja1000_write(MOD, (1<<AFM)|(0<<STM)|(0<<RM));
+    }
+    while ((sja1000_read(MOD) & (1<<RM)) == 1);   /* loop until reset gone */
+}
+
+
+/***************************************************************************/
+
+
+void init_interrupts(void)
+{
+    cyg_vector_t   interrupt_1_vector   = CYGNUM_HAL_INTERRUPT_1;
+    cyg_priority_t interrupt_1_priority = CYGNUM_HAL_PRI_HIGH;
+
+    cyg_interrupt_create(
+        interrupt_1_vector,
+        interrupt_1_priority,
+        (cyg_addrword_t) 0,
+        (cyg_ISR_t *) &interrupt_1_isr,
+        (cyg_DSR_t *) &interrupt_1_dsr,
+        &interrupt_1_handle,
+        &interrupt_1);
+
+    cyg_interrupt_attach(interrupt_1_handle);
+
+    cyg_interrupt_acknowledge(interrupt_1_vector);
+
+    cyg_interrupt_unmask(interrupt_1_vector);
+}
+
+/* External Interrupt 1 Service */
+void eint1_srv(void) /*__irq*/ 
+{
+	//++intrp_count;                              // increment interrupt count
+	EXTINT      = 2;                            // Clear EINT1 interrupt flag
+	VICVectAddr = 0;                            // Acknowledge Interrupt
+}
+
+
+/* Initialize EINT1 Interrupt Pin */
+void init_eint1(void)
+{
+	EXTMODE       = 0x2;                         // Edge sensitive mode on EINT1
+	EXTPOLAR      = 0;                           // falling edge sensitive
+	P0_PINSEL0   |= 2 << 28;                     // Enable EINT1 on GPIO_0.14
+	VICVectAddr0  = (unsigned long) eint1_srv;   // set interrupt vector in VIC 0
+	VICVectCntl0  = 0x20 | 15;                   // use VIC 0 for EINT1 Interrupt
+	EXTINT        = 2;
+	VICIntEnable  = 1 << 15;                     // Enable EINT1 Interrupt
+}
+
+
+/*
+{
+	unsigned char byte=sja1000_read(0x02);
+
+	if (byte & 0x01)
+	{
+		// RXFIFO full
+	}
+	
+	if (byte & 0x02)
+	{
+		// overrun
+	}
+	
+	if (byte & 0x04)
+	{
+		// the cpu may write a msg
+	}
+	
+	if (byte & 0x08)
+	{
+		// tx complete
+	}
+	
+	if (byte & 0x10)
+	{
+		// receiving
+	}
+	
+	if (byte & 0x20)
+	{
+		// transmitting
+	}
+	
+	if (byte & 0x40)
+	{
+		// at least one of the error counter has reached or exceeeded
+		// the CPU warning limit
+	}
+	
+	if (byte & 0x80)
+	{
+		// bus off
+	}
+}
+*/
+
+
--- a/examples/TestMasterSlave/Makefile.in	Thu May 11 13:52:43 2006 +0200
+++ b/examples/TestMasterSlave/Makefile.in	Fri May 12 22:14:03 2006 +0200
@@ -32,6 +32,7 @@
 TARGET = SUB_TARGET
 CAN_DRIVER = SUB_CAN_DRIVER
 TIMERS_DRIVER = SUB_TIMERS_DRIVER
+LED_ENABLE = SUB_LED_ENABLE
 
 INCLUDES = -I../../include -I../../include/$(TARGET) -I../../include/$(CAN_DRIVER) -I../../include/$(TIMERS_DRIVER)
 
@@ -43,6 +44,12 @@
 	PROGDEFINES = -DUSE_XENO
 endif
 
+ifeq ($(LED_ENABLE),YES)
+OBJS += ../../drivers/can_virtual/led_virtual.o 
+PROG_CFLAGS += -DLED_ENABLE
+endif
+
+
 all: TestMasterSlave
 
 ../../drivers/$(TARGET)/libcanfestival_$(TARGET).a:
--- a/include/can_driver.h	Thu May 11 13:52:43 2006 +0200
+++ b/include/can_driver.h	Fri May 12 22:14:03 2006 +0200
@@ -37,15 +37,15 @@
 int canClose(CAN_HANDLE fd0);
 void canReceiveLoop(CAN_HANDLE fd0);
 
-void led_set_redgreen(unsigned char bits);
+#include "data.h"
+
+void led_set_redgreen(CO_Data *d, unsigned char bits);
 
 int nvram_open(void);
 void nvram_close(void);
 char nvram_write(int type, int access_attr, void *data);
 char nvram_read(int type, int access_attr, void *data);
 
-#include "data.h"
-
 struct struct_s_BOARD {
   char * busname;
   int baudrate;
--- a/include/led.h	Thu May 11 13:52:43 2006 +0200
+++ b/include/led.h	Fri May 12 22:14:03 2006 +0200
@@ -39,5 +39,4 @@
 
 void led_set_state(CO_Data *d, int state);
 
-
 #endif
--- a/src/Makefile.in	Thu May 11 13:52:43 2006 +0200
+++ b/src/Makefile.in	Fri May 12 22:14:03 2006 +0200
@@ -30,9 +30,9 @@
 PREFIX = SUB_PREFIX
 BINUTILS_PREFIX = SUB_BINUTILS_PREFIX
 TARGET = SUB_TARGET
-LSS_ENABLE=SUB_LSS_ENABLE
-LED_ENABLE=SUB_LED_ENABLE
-NVRAM_ENABLE=SUB_NVRAM_ENABLE
+LSS_ENABLE = SUB_LSS_ENABLE
+LED_ENABLE = SUB_LED_ENABLE
+NVRAM_ENABLE = SUB_NVRAM_ENABLE
 CAN_DRIVER = SUB_CAN_DRIVER
 TIMERS_DRIVER = SUB_TIMERS_DRIVER
 TIMERS_ENABLE = SUB_TIMERS_ENABLE
@@ -73,6 +73,7 @@
 ifeq ($(LED_ENABLE),YES)
 OBJS += $(TARGET)_led.o
 SRC_HFILES += ../include/led.h
+PROG_CFLAGS += -DLED_ENABLE
 endif 
 
 ifeq ($(NVRAM_ENABLE),YES)
--- a/src/led.c	Thu May 11 13:52:43 2006 +0200
+++ b/src/led.c	Fri May 12 22:14:03 2006 +0200
@@ -65,6 +65,8 @@
 
 void led_set_state(CO_Data *d, int state)
 {
+printf("led_set_state(%x)\n", state);
+
 	switch(state)
 	{
 		case Initialisation:
@@ -100,8 +102,8 @@
 	{
 		led_stop_timer();
 
-		led_set_green(led_state_green);
-		led_set_red(led_state_red);
+		//led_set_green(led_state_green);
+		//led_set_red(led_state_red);
 	}
 
 	else
@@ -168,15 +170,15 @@
 		}
 
 		led_start_timer(d, 200);
-		led_set_red(led_state_red);
+		//led_set_red(led_state_red);
 	}
 
 	if (led_state_green < 2  &&  led_state_red < 2)
 	{
 		led_stop_timer();
 
-		led_set_green(led_state_green);
-		led_set_red(led_state_red);
+		//led_set_green(led_state_green);
+		//led_set_red(led_state_red);
 	}
 }
 
@@ -197,7 +199,7 @@
 
 void led_callback(CO_Data *d, UNS32 id)
 {
-	unsigned char bits = 0;
+	UNS8 bits = 0;
 
 	// RED LED
 	if (led_sequence_table[led_sequence_red][led_seq_index_red] == '1')
@@ -233,7 +235,7 @@
 	if (led_seq_index_green > strlen(led_sequence_table[led_sequence_green]))
 		led_seq_index_green = 0;
 
-	led_set_redgreen(bits);
+	led_set_redgreen(d, bits);
 }