etisserant@0: /*
etisserant@0: This file is part of CanFestival, a library implementing CanOpen Stack.
etisserant@0: 
etisserant@0:  Author: Christian Fortin (canfestival@canopencanada.ca)
etisserant@0: 
etisserant@0: See COPYING file for copyrights details.
etisserant@0: 
etisserant@0: This library is free software; you can redistribute it and/or
etisserant@0: modify it under the terms of the GNU Lesser General Public
etisserant@0: License as published by the Free Software Foundation; either
etisserant@0: version 2.1 of the License, or (at your option) any later version.
etisserant@0: 
etisserant@0: This library is distributed in the hope that it will be useful,
etisserant@0: but WITHOUT ANY WARRANTY; without even the implied warranty of
etisserant@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
etisserant@0: Lesser General Public License for more details.
etisserant@0: 
etisserant@0: You should have received a copy of the GNU Lesser General Public
etisserant@0: License along with this library; if not, write to the Free Software
etisserant@0: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
etisserant@0: */
etisserant@0: 
etisserant@0: #include <stdlib.h>
etisserant@0: 
etisserant@0: #include <sys/time.h>
etisserant@0: #include <signal.h>
etisserant@0: 
etisserant@0: #include <cyg/kernel/kapi.h>
etisserant@0: #include <cyg/hal/hal_arch.h>
etisserant@0: 
etisserant@0: #include "applicfg.h"
etisserant@0: #include <data.h>
etisserant@0: #include <def.h>
etisserant@0: #include <can.h>
etisserant@0: #include <can_driver.h>
etisserant@0: #include <objdictdef.h>
etisserant@0: #include <objacces.h>
etisserant@0: 
etisserant@0: #include "lpc2138_pinout.h"
etisserant@0: #include "lpc2138_defs.h"
etisserant@0: #include "lpc2138.h"
etisserant@0: 
etisserant@0: #include "sja1000.h"
etisserant@0: 
etisserant@0: #include "time_slicer.h"
etisserant@0: 
etisserant@0: 
etisserant@0: /*
etisserant@0: 	SEND/RECEIVE
etisserant@0: */
etisserant@0: CAN_HANDLE canOpen(s_BOARD *board)
etisserant@0: {
etisserant@0: 	return NULL;
etisserant@0: }
etisserant@0: 
etisserant@0: /***************************************************************************/
etisserant@0: int canClose(CAN_HANDLE fd0)
etisserant@0: {
etisserant@0: 	return 0;
etisserant@0: }
etisserant@0: 
etisserant@0: UNS8 canReceive(CAN_HANDLE fd0, Message *m)
etisserant@0: /*
etisserant@0: Message *m :
etisserant@0: 	typedef struct {
etisserant@0: 	  SHORT_CAN cob_id;     // l'ID du mesg
etisserant@0: 	  UNS8 rtr;             // remote transmission request. 0 if not rtr,
etisserant@0:         	                // 1 for a rtr message
etisserant@0: 	  UNS8 len;             // message length (0 to 8)
etisserant@0: 	  UNS8 data[8];         // data
etisserant@0: 	} Message;
etisserant@0: 
etisserant@0: Fill the structure "Message" with data from the CAN receive buffer
etisserant@0: 
etisserant@0: return : 0
etisserant@0: */
etisserant@0: {
etisserant@0: /*
etisserant@0: 	the sja1000 must be set to the PeliCAN mode
etisserant@0: */
etisserant@0:     m->cob_id.w = sja1000_read(16) + (sja1000_read(17)<<8); // IO_PORTS_16(CAN0 + CANRCVID) >> 5
etisserant@0: 
etisserant@0:     m->rtr = (sja1000_read(17) >> 4) & 0x01; // (IO_PORTS_8(CAN0 + CANRCVID + 1) >> 4) & 0x01; 
etisserant@0: 
etisserant@0:     m->len = sja1000_read(18);
etisserant@0: 
etisserant@0:     m->data[0] = sja1000_read(19);
etisserant@0:     m->data[1] = sja1000_read(20);
etisserant@0:     m->data[2] = sja1000_read(21);
etisserant@0:     m->data[3] = sja1000_read(22);
etisserant@0:     m->data[4] = sja1000_read(23);
etisserant@0:     m->data[5] = sja1000_read(24);
etisserant@0:     m->data[6] = sja1000_read(25);
etisserant@0:     m->data[7] = sja1000_read(26);
etisserant@0: 
etisserant@0:     sja1000_write(CMR, 1<<RRB );        // release fifo
etisserant@0: 
etisserant@0:     return 0;
etisserant@0: }
etisserant@0: 
etisserant@0: 
etisserant@0: UNS8 canSend(CAN_HANDLE fd0, Message *m)
etisserant@0: /*
etisserant@0: Message *m :
etisserant@0: 	typedef struct {
etisserant@0: 	  SHORT_CAN cob_id;     // l'ID du mesg
etisserant@0: 	  UNS8 rtr;                     // remote transmission request. 0 if not rtr,
etisserant@0:         	                        // 1 for a rtr message
etisserant@0: 	  UNS8 len;                     // message length (0 to 8)
etisserant@0: 	  UNS8 data[8];         // data
etisserant@0: 	} Message;
etisserant@0: 
etisserant@0: Send the content of the structure "Message" to the CAN transmit buffer
etisserant@0: 
etisserant@0: return : 0 if OK, 1 if error
etisserant@0: */
etisserant@0: {
etisserant@0:     unsigned char rec_buf;
etisserant@0: 
etisserant@0:     do
etisserant@0:     {
etisserant@0:         rec_buf = sja1000_read(SR);
etisserant@0:     }
etisserant@0:     while ( (rec_buf & (1<<TBS))==0);           // loop until TBS high
etisserant@0: 
etisserant@0:     sja1000_write(16, m->cob_id.w & 0xff); 
etisserant@0:     sja1000_write(17, (m->cob_id.w >> 8) & 0xff);
etisserant@0:     sja1000_write(18, m->len);
etisserant@0: 
etisserant@0:     sja1000_write(19, m->data[0]); // tx data 1
etisserant@0:     sja1000_write(20, m->data[1]); // tx data 2
etisserant@0:     sja1000_write(21, m->data[2]); // tx data 3
etisserant@0:     sja1000_write(22, m->data[3]); // tx data 4
etisserant@0:     sja1000_write(23, m->data[4]); // tx data 5
etisserant@0:     sja1000_write(24, m->data[5]); // tx data 6
etisserant@0:     sja1000_write(25, m->data[6]); // tx data 7
etisserant@0:     sja1000_write(26, m->data[7]); // tx data 8
etisserant@0: 
etisserant@0:     sja1000_write(CMR,( (0<<SRR) | (0<<CDO) | (0<<RRB) | (0<<AT) | (1<<TR)));
etisserant@0:     do
etisserant@0:     {
etisserant@0:         rec_buf = sja1000_read(SR);
etisserant@0:     }
etisserant@0:     while ( (rec_buf & (1<<TBS))==0);           // loop until TBS high
etisserant@0: 
etisserant@0:     return 0;
etisserant@0: }
etisserant@0: 
etisserant@0: 
etisserant@0: /*
etisserant@0: 	SEQUENTIAL I/O TO FLASH
etisserant@0: 	those functions are for continous writing and read
etisserant@0: */
etisserant@0: 
etisserant@0: 
etisserant@0: int nvram_open(void)
etisserant@0: {
oremeq@3: 	int n = NVRAM_BLOCK_SIZE / sizeof(unsigned int);
oremeq@3: 
etisserant@0: 	/* some actions to initialise the flash */
etisserant@0: 	data_len = 0;
oremeq@3: 	data_num_pages = 0;
oremeq@3: 
oremeq@3: 	data_page = (unsigned int *)malloc(sizeof(unsigned int) * n);
oremeq@3: 	memset(data_page, 0, sizeof(unsigned int)*n);
etisserant@0: 
etisserant@0: 	if (data_page == NULL)
etisserant@0: 		return -1;
etisserant@0: 
oremeq@3: 	regs_page = (unsigned int *)malloc(sizeof(unsigned int) * n);
oremeq@3: 	memset(regs_page, 0, sizeof(unsigned int)*n);
oremeq@3: 	if (regs_page == NULL)
oremeq@3: 		return -2;
oremeq@3: 
oremeq@3: 	iat_flash_read_regs();
oremeq@3: 
oremeq@3: 	/* start the data at the location specified in the registers */ 
oremeq@3: 	if (0) /* for now it is 0, but put here a test to know whether
oremeq@3:                   or not the NVRAM has been written before */
oremeq@3: 		data_addr = regs_page[1];
oremeq@3: 	else
oremeq@3: 		data_addr = NVRAM_BLOCK_SIZE; /* let start at block 1 */
oremeq@3: 
etisserant@0: 	return 0;
etisserant@0: }
etisserant@0: 
etisserant@0: 
etisserant@0: void nvram_close(void)
etisserant@0: {
oremeq@3: 	/* write the last page before closing */
oremeq@3: 	iat_flash_write_page(data_addr);
oremeq@3: 
etisserant@0: 	/* some actions to end accessing the flash */
etisserant@0: 	free(data_page);
oremeq@3: 
oremeq@3: 	regs_page[4] = data_num_pages;
oremeq@3: 	/* write the registers to the NVRAM before closing */
oremeq@3: 	iat_flash_write_regs();
oremeq@3: 	free(regs_page);
oremeq@3: }
oremeq@3: 
oremeq@3: 
oremeq@3: void nvram_set_pos(UNS32 pos)
oremeq@3: /* set the current position in the NVRAM to pos */
oremeq@3: {
oremeq@3: }
oremeq@3: 
oremeq@3: 
oremeq@3: void nvram_new_firmwave()
oremeq@3: {
oremeq@3: /*
oremeq@3: 	this function is called whenever a new firmware is about
oremeq@3: 	to be written in the NVRAM
oremeq@3: */
oremeq@3: 	data_addr = regs_page[1] + regs_page[4]*NVRAM_BLOCK_SIZE;
oremeq@3: 	if (data_addr > NVRAM_MAX_SIZE)
oremeq@3: 		data_addr = NVRAM_BLOCK_SIZE;
etisserant@0: }
etisserant@0: 
etisserant@0: int _get_data_len(int type)
etisserant@0: {
etisserant@0: 	int len = 0; /* number of bytes */
etisserant@0: 	switch(type)
etisserant@0: 	{
etisserant@0: 		case  boolean:
etisserant@0: 			len = 1;
etisserant@0: 			break;
etisserant@0: 
etisserant@0: 		case  int8:
etisserant@0: 		case  uint8:
etisserant@0: 			len = 1;
etisserant@0: 			break;
etisserant@0: 		case  int16:
etisserant@0: 		case  uint16:
etisserant@0: 			len = 2;
etisserant@0: 			break;
etisserant@0: 		case  int24:
etisserant@0: 		case  uint24:
etisserant@0: 			len = 3;
etisserant@0: 			break;
etisserant@0: 		case  int32:
etisserant@0: 		case  uint32:
etisserant@0: 		case  real32:
etisserant@0: 			len = 4;
etisserant@0: 			break;
etisserant@0: 		case  int40:
etisserant@0: 		case  uint40:
etisserant@0: 			len = 5;
etisserant@0: 			break;
etisserant@0: 		case  int48:
etisserant@0: 		case  uint48:
etisserant@0: 			len = 6;
etisserant@0: 			break;
etisserant@0: 		case  int56:
etisserant@0: 		case  uint56:
etisserant@0: 			len = 7;
etisserant@0: 			break;
etisserant@0: 		case  int64:
etisserant@0: 		case  uint64:
etisserant@0: 		case  real64:
etisserant@0: 			len = 8;
etisserant@0: 			break;
etisserant@0: #if 0
etisserant@0: /* TO DO */
etisserant@0: 		case  visible_string:
etisserant@0: 		case  octet_string:
etisserant@0: 		case  unicode_string:
etisserant@0: 		case  time_of_day:
etisserant@0: 		case  time_difference:
etisserant@0: #endif
etisserant@0: 	}
etisserant@0: 
etisserant@0: 	return len;
etisserant@0: }
etisserant@0: 
etisserant@0: 
oremeq@3: char nvram_write_data(int type, int access_attr, void *data)
etisserant@0: /* return 0 if successfull */
etisserant@0: {
etisserant@0: 	int len = _get_data_len(type);
etisserant@0: 
oremeq@3: 	if (data_len+len > NVRAM_BLOCK_SIZE)
etisserant@0: 	{
etisserant@0: 		iat_flash_write_page(data_addr);
etisserant@0: 		data_len = 0;
oremeq@3: 		data_addr += NVRAM_BLOCK_SIZE; 
oremeq@3: 
oremeq@3: 		/* wrap-around address pointer */
oremeq@3: 		if (data_addr > NVRAM_MAX_SIZE)
oremeq@3: 			data_addr = NVRAM_BLOCK_SIZE;
oremeq@3: 
oremeq@3: 		data_num_pages++;
etisserant@0: 	}
etisserant@0: 		
etisserant@0: 	memcpy(((char *)data_page)+data_len, data, len);
etisserant@0: 
etisserant@0: 	data_len += len;
etisserant@0: 
etisserant@0: 	return 0;
etisserant@0: }
etisserant@0: 
etisserant@0: 
oremeq@3: char nvram_read_data(int type, int access_attr, void *data)
etisserant@0: /* return 0 if successful */
etisserant@0: {
etisserant@0: 	int len = _get_data_len(type);
etisserant@0: 
oremeq@3: 	if (data_len+len > NVRAM_BLOCK_SIZE)
etisserant@0: 	{
oremeq@3: 		data_addr += NVRAM_BLOCK_SIZE;
oremeq@3: 
oremeq@3: 		/* wrap-around address pointer */
oremeq@3: 		if (data_addr > NVRAM_MAX_SIZE)
oremeq@3: 			data_addr = NVRAM_BLOCK_SIZE;
oremeq@3: 
etisserant@0: 		iat_flash_read_page(data_addr);
etisserant@0: 		data_len = 0;		
etisserant@0: 	}
etisserant@0: 
etisserant@0: 	memcpy(data, ((char *)data_page)+data_len, len);
etisserant@0: 
etisserant@0: 	data_len += len;
etisserant@0: 
etisserant@0: 	return 0;
etisserant@0: }
etisserant@0: 
oremeq@3: /*
oremeq@3: 	NVRAM registers at block 0
oremeq@3: 	pos        description
oremeq@3: 	0          version of the current dictionnary
oremeq@3: 	1          starting address for data block
oremeq@3: 	2          date of last writing
oremeq@3: 	3          address of the previous dictionnary          
oremeq@3: 	4          size in pages of the current dict
oremeq@3: */
oremeq@3: void nvram_write_reg(UNS32 reg, UNS16 pos)
oremeq@3: /* write reg at the position in the data block 0 */
oremeq@3: {
oremeq@3: 	regs_page[pos] = reg;
oremeq@3: }
oremeq@3: 
oremeq@3: UNS32 nvram_read_reg(UNS16 pos)
oremeq@3: /* read reg at the position in the data block 0 */
oremeq@3: {
oremeq@3: 	return regs_page[pos];
oremeq@3: }
oremeq@3: 
etisserant@0: 
etisserant@0: /*
etisserant@0: 	LED
etisserant@0: */
etisserant@0: 
oremeq@3: void led_set_redgreen(UNS8 bits)
oremeq@3: /* bits : each bit of this uns8 is assigned a led 
oremeq@3:           0=off, 1=on
oremeq@3: */
etisserant@0: {
etisserant@0: 	lpc2138_redgreenled_set(bits);
etisserant@0: }
etisserant@0: