1 /**************************************************************************/
2 /* File: main.c - setup and main loop of USB<->CAN converter */
4 /* LinCAN - (Not only) Linux CAN bus driver */
5 /* Copyright (C) 2002-2011 DCE FEE CTU Prague <http://dce.felk.cvut.cz> */
6 /* Copyright (C) 2008 Jan Kriz email:johen@post.cz */
8 /* LinCAN is free software; you can redistribute it and/or modify it */
9 /* under terms of the GNU General Public License as published by the */
10 /* Free Software Foundation; either version 2, or (at your option) any */
11 /* later version. LinCAN is distributed in the hope that it will be */
12 /* useful, but WITHOUT ANY WARRANTY; without even the implied warranty */
13 /* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
14 /* General Public License for more details. You should have received a */
15 /* copy of the GNU General Public License along with LinCAN; see file */
16 /* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, */
17 /* Cambridge, MA 02139, USA. */
19 /* To allow use of LinCAN in the compact embedded systems firmware */
20 /* and RT-executives (RTEMS for example), main authors agree with next */
21 /* special exception: */
23 /* Including LinCAN header files in a file, instantiating LinCAN generics */
24 /* or templates, or linking other files with LinCAN objects to produce */
25 /* an application image/executable, does not by itself cause the */
26 /* resulting application image/executable to be covered by */
27 /* the GNU General Public License. */
28 /* This exception does not however invalidate any other reasons */
29 /* why the executable file might be covered by the GNU Public License. */
30 /* Publication of enhanced or derived LinCAN files is required although. */
31 /**************************************************************************/
36 #include <system_def.h>
38 #include <local_config.h>
39 #include <usb/usbdebug.h>
42 #include <usb/usb_srq.h>
44 #include <keyval_id.h>
45 #include <hal_machperiph.h>
46 #include <keyval_loc.h>
48 #include <lpciap_kvpb.h>
51 #if __BYTE_ORDER == __BIG_ENDIAN
55 #include "./can/can.h"
56 #include "./can/sja1000p.h"
57 #include "./can/main.h"
59 // #include "./can/can_sysdep.h"
60 #include "./can/modparms.h"
61 #include "./can/devcommon.h"
63 //#include "./can/ul_usb1.h"
65 //#include "./can/setup.h"
67 #include "./usb/usb_defs.h"
68 #include "./usb/usb_vend.h"
71 #include "can/lpc17xx_can.h"
74 #define MASK_EP1RX 0x01
75 #define MASK_EP1TX 0x02
77 #define CAN_OP_MASK 0x80
78 #define CAN_OP_READ 0x80
79 #define CAN_OP_WRITE 0x00
83 #define USB_MAX_PACKET 16
85 /***********************************************************************
87 * Comparing to LinCAN, there is no need to sleep for processes
88 * because the degree of filling of fifo from the client side
89 * is solved in main cycle (no new messages are accepted when full)
90 * and on the server side by speed of USB interface. FIFO in edge
91 * from SJA chip to USB interface should never be filled.
92 ***********************************************************************/
94 /***********************************************************************
96 * Code is wittingly complex in order to ease future changes in hardware
97 * configuration and to make it as much similar as the code of LinCAN
98 ***********************************************************************/
100 LT_TIMER_DEC(lt_10msec)
101 LT_TIMER_IMP(lt_10msec)
102 LT_TIMER_DEC(lt_100msec)
103 LT_TIMER_IMP(lt_100msec)
104 LT_TIMER_DEC(lt_2sec)
105 LT_TIMER_IMP(lt_2sec)
107 typedef void (*FNC)(); //function ptr
109 /***********************************************************************
111 ***********************************************************************/
112 volatile uint32_t cnt;
114 usb_device_t usb_device;
116 usb_ep_t eps[NUM_ENDPOINTS];
117 unsigned char ep1_rx_buff[USB_MAX_PACKET];
118 unsigned char ep1_tx_buff[USB_MAX_PACKET];
119 uint8_t timer_str,timer_rx_off,timer_tx_off,timer_configured;
120 volatile uint8_t bootloader_run;
126 int baudrate[MAX_TOT_CHIPS];
127 struct canhardware_t canhardware;
128 struct canhardware_t *hardware_p=&canhardware;
129 struct canchip_t *chips_p[MAX_TOT_CHIPS];
130 struct msgobj_t *objects_p[MAX_TOT_MSGOBJS];
132 struct canuser_t *canuser;
134 extern int init_chip_struct(struct candevice_t *candev, int chipnr, int irq, long baudrate);
135 extern int register_chip_struct(struct canchip_t *chip, int minorbase);
136 extern int register_obj_struct(struct msgobj_t *obj, int minorbase);
138 /***********************************************************************
139 * IF SOMETHING BAD HAPPENED
140 ***********************************************************************/
147 if (lt_100msec_expired(100)) {
150 SET_OUT_PIN(LED_PORT,LED_ERR);
152 CLR_OUT_PIN(LED_PORT,LED_ERR);
154 #ifdef WATCHDOG_ENABLED
156 #endif /* WATCHDOG_ENABLED */
161 /***********************************************************************
162 * Microsecond delay routine
163 ***********************************************************************/
165 void udelay(long time)
167 volatile long ticks=(time * CCLK) / 2000000;
174 /***********************************************************************
175 * Routine for visible LED blinking (on USB transmission)
176 ***********************************************************************/
178 void timer_10ms(void)
180 if (timer_tx_off!=0) timer_tx_off--;
181 else SET_OUT_PIN(LED_PORT,LED1_BIT);
182 if (timer_rx_off!=0) timer_rx_off--;
183 else SET_OUT_PIN(LED_PORT,LED2_BIT);
185 /* if (timer_configured!=0) timer_configured--;
188 CLR_OUT_PIN(LED_PORT,LED1_BIT);
189 CLR_OUT_PIN(LED_PORT,LED2_BIT);
190 timer_rx_off=timer_tx_off=5;
194 /***********************************************************************
196 ***********************************************************************/
200 struct candevice_t *candev;
201 struct canchip_t *chip=NULL;
202 struct msgobj_t *obj;
203 struct canque_ends_t *qends;
204 struct canque_edge_t *edge,*qedge;
205 struct canque_slot_t *slot;
206 struct canmsg_t canmsg;
207 can_spin_irqflags_t iflags;
214 CANMSG("Starting USBCAN module firmware...\n");
218 /***********************************/
225 //SET_OUT_PIN(LED_PORT,LED_ERR);
226 //CLR_OUT_PIN(LED_PORT,LED_GP);
228 if (USB_MAX_PACKET<16){
229 CANMSG("Maximum packet size less than 16B (is %dB)\n",USB_MAX_PACKET);
233 // !!! DEBUG - transmitting and receiving CAN messages with usage of queue system from LinCAN - first version!
236 //***********************************************************************
237 // * CAN device initialization - device side (adapted from LinCAN setup.c)
238 // ***********************************************************************
241 //can_init(); // only for successful compiling (defined in can_lpcbusemu.c)
244 DEBUGMSG("Initiating CAN device initialization\n");
247 canqueue_kern_initialize();
249 hardware_p->nr_boards=1;
251 candev=(struct candevice_t *)malloc(sizeof(struct candevice_t));
253 CANMSG("No space left in memory\n");
256 memset(candev, 0, sizeof(struct candevice_t));
258 hardware_p->candevice[0]=candev;
259 candev->candev_idx=0;
261 candev->dev_base_addr=0;
263 candev->hwspecops=(struct hwspecops_t *)malloc(sizeof(struct hwspecops_t));
264 if (!candev->hwspecops){
265 CANMSG("No space left in memory\n");
268 memset(candev->hwspecops, 0, sizeof(struct hwspecops_t));
273 //ul_usb1_register(candev->hwspecops); // only for successful compiling (defined in ul_usb1.c)
274 // register for another board
275 can_lmc1_register(candev->hwspecops);
280 if (candev->hwspecops->init_hw_data(candev)){
281 CANMSG("HW data could not be initialized\n");
285 // Alocate and initialize the chip structures
286 for (chipnr=0; chipnr < candev->nr_all_chips; chipnr++) {
288 // irqsig=irq[*irq_param_idx_p+chipnr];
289 if (init_chip_struct(candev, chipnr, 0, bd*1000)){
290 CANMSG("Chip structure could not be initialized\n");
297 for (chipnr=0; chipnr < candev->nr_all_chips; chipnr++) {
298 struct canchip_t *chip=candev->chip[chipnr];
301 register_chip_struct(chip, m);
303 for (objnr=0; objnr<chip->max_objects; objnr++) {
304 register_obj_struct(chip->msgobj[objnr], m);
310 if (candev->hwspecops->request_io(candev))
312 candev->flags|=CANDEV_IO_RESERVED;
315 if (candev->hwspecops->reset(candev))
319 for(chipnr=0; chipnr<candev->nr_all_chips; chipnr++) {
320 if((chip=candev->chip[chipnr])==NULL)
323 if(chip->chipspecops->attach_to_chip(chip)<0) {
324 // CANMSG("Initial attach to the chip HW failed\n");
328 chip->flags |= CHIP_ATTACHED;
330 // Interrupts from chip are served in main cycle
331 // if(can_chip_setup_irq(chip)<0) {
332 // CANMSG("Error to setup chip IRQ\n");
337 if (candev->flags & CANDEV_PROGRAMMABLE_IRQ)
338 if (candev->hwspecops->program_irq(candev)){
339 // CANMSG("Error to program board interrupt\n");
343 //***********************************************************************
344 // * CAN device initialization - client side (adapted from LinCAN open.c)
345 // ***********************************************************************
348 chip=candev->chip[0];
350 atomic_inc(&obj->obj_used);
351 can_msgobj_set_fl(obj,OPENED);
353 if (chip->flags & CHIP_CONFIGURED)
354 DEBUGMSG("Device is already configured.\n");
356 if (chip->chipspecops->chip_config(chip))
357 CANMSG("Error configuring chip.\n");
359 chip->flags |= CHIP_CONFIGURED;
361 if (chip->chipspecops->pre_read_config(chip,obj)<0)
362 CANMSG("Error initializing chip for receiving\n");
364 } // End of chip configuration
367 canuser = (struct canuser_t *)malloc(sizeof(struct canuser_t));
368 if(canuser == NULL) sys_err();
370 // canuser->userinfo.fileinfo.file = file;
371 canuser->msgobj = obj;
372 // canuser->magic = CAN_USER_MAGIC;
373 // file->private_data = canuser;
375 qends = (struct canque_ends_t *)malloc(sizeof(struct canque_ends_t));
376 if(qends == NULL) sys_err();
377 canqueue_ends_init_kern(qends);
378 canuser->qends = qends;
380 //required to synchronize with RT-Linux context
381 can_spin_lock_irqsave(&canuser_manipulation_lock, iflags);
382 list_add(&canuser->peers, &obj->obj_users);
383 can_spin_unlock_irqrestore(&canuser_manipulation_lock, iflags);
385 if(canqueue_connect_edge(edge=canque_new_edge_kern(MAX_BUF_LENGTH),
386 canuser->qends, obj->qends)<0) sys_err();
388 if(canqueue_connect_edge(canuser->rx_edge0=canque_new_edge_kern(MAX_BUF_LENGTH),
389 obj->qends, canuser->qends)<0) sys_err();
390 //FIXME: more generic model should be used there
391 canque_edge_decref(canuser->rx_edge0);
392 canque_edge_decref(edge);
396 /***********************************************************************
398 ***********************************************************************/
400 memset( &usb_device, 0, sizeof( usb_device));
402 usb_device.devdes_table = &usb_devdes_table;
403 usb_device.init = usb_lpc_init;
404 usb_debug_set_level(DEBUG_LEVEL_NONE);
405 usb_device.cntep = NUM_ENDPOINTS;
408 eps[0].max_packet_size = USB_MAX_PACKET;
409 eps[1].max_packet_size = USB_MAX_PACKET;
412 eps[0].event_mask = 0x04;
413 eps[1].event_mask = 0x08;
414 eps[0].udev = &usb_device;
415 eps[1].udev = &usb_device;
417 usb_device.vendor_fnc=usbcan_vendor;
419 usb_init(&usb_device);
420 usb_connect(&usb_device);
421 usb_device.ep_events |= MASK_EP1TX;
423 /***********************************************************************
425 ***********************************************************************/
427 timer_rx_off=timer_tx_off=timer_str=timer_configured=0;
430 printf("Main loop\n");
434 usb_check_events(&usb_device);
435 usb_control_response(&usb_device);
438 // if (!(IO0PIN&P0_SJA1000_INT_PIN)) //INT PIN is inverted
439 // chip->chipspecops->irq_handler(0,chip);
441 // if (CAN1SR & CAN_SR_RBS)
442 // chip->chipspecops->irq_handler(0,chip);
445 if (usb_device.ep_events & MASK_EP1RX) { //EP1RX - data waiting to receive
447 if (canque_get_inslot(qends, &qedge, &slot, 0)>=0){ //Free slot obtained
449 size=usb_udev_read_endpoint(&eps[0],ep1_rx_buff,16);
454 canmsg.length=*(uint8_t *)(ep1_rx_buff+1);
455 if (canmsg.length > CAN_MSG_LENGTH)
456 canmsg.length=CAN_MSG_LENGTH;
457 msgflags=*(uint16_t *)(ep1_rx_buff+2);
458 msgid=*(uint32_t *)(ep1_rx_buff+4);
459 #if __BYTE_ORDER == __BIG_ENDIAN
460 msgflags = bswap_16( msgflags);
461 msgid = bswap_32( msgid);
463 canmsg.flags=msgflags;
466 for (i=0;i<canmsg.length;i++){
467 canmsg.data[i]=*(unsigned char*)(ep1_rx_buff+8+i);
469 for (;i<CAN_MSG_LENGTH;i++){
472 /* Automatic selection of extended format if ID>2047 */
473 if (canmsg.id & ~0x7ffl & MSG_ID_MASK ) canmsg.flags |= MSG_EXT;
474 /* has been dependent on "extended" option */
477 canque_put_inslot(qends, qedge, slot);
481 canque_abort_inslot(qends,qedge,slot);
484 timer_rx_off=50; //rosviceni diody pri prijmu
485 CLR_OUT_PIN(LED_PORT,LED2_BIT);
486 usb_device.ep_events &= ~MASK_EP1RX;
494 if ((data[0]&CAN_OP_MASK)==CAN_OP_READ){ // Get data from CAN device and return to caller
495 val = can_read(data[0] & ~CAN_OP_MASK);
497 usb_udev_write_endpoint(&eps[1],(unsigned char *)data,size);
498 timer_rx_off=50; //rosviceni diody pri prijmu
499 CLR_OUT_PIN(LED_PORT,LED2_BIT);
502 if ((data[0]&CAN_OP_MASK)==CAN_OP_WRITE){ // Save data to CAN device
503 can_write(data[1], data[0] & ~CAN_OP_MASK);
504 timer_tx_off=50; //rozsviceni diod pri vysilani
505 CLR_OUT_PIN(LED_PORT,LED1_BIT);
511 if(usb_device.ep_events & MASK_EP1TX){ //EP1TX - data transmitted
512 if(canque_test_outslot(qends, &qedge, &slot)>=0){
513 DEBUGMSG("CAN message ready to send over usb\n");
517 *(uint8_t *)(ep1_tx_buff)=0;
518 *(uint8_t *)(ep1_tx_buff+1)=slot->msg.length;
520 msgflags=slot->msg.flags;
522 #if __BYTE_ORDER == __BIG_ENDIAN
523 msgflags = bswap_16( msgflags);
524 msgid = bswap_32( msgid);
527 *(uint16_t *)(ep1_tx_buff+2)=msgflags;
528 *(uint32_t *)(ep1_tx_buff+4)=msgid;
529 for (i=0;i<slot->msg.length;i++){
530 *(uint8_t *)(ep1_tx_buff+8+i)=slot->msg.data[i];
532 for (;i<CAN_MSG_LENGTH;i++){
533 *(uint8_t *)(ep1_tx_buff+8+i)=0;
535 usb_udev_write_endpoint(&eps[1],ep1_tx_buff,16);
537 //printf("ID: %d\n", msgid);
539 canque_free_outslot(qends, qedge, slot);
540 timer_tx_off=50; //rozsviceni diod pri vysilani
541 CLR_OUT_PIN(LED_PORT,LED1_BIT);
542 usb_device.ep_events &= ~MASK_EP1TX;
549 //if (usb_can_send && )
551 #ifdef WATCHDOG_ENABLED
553 #endif /* WATCHDOG_ENABLED */
556 if (lt_10msec_expired(10))
560 SET_OUT_PIN(LED_PORT,LED_GP);
561 SET_OUT_PIN(LED_PORT,LED_ERR);
563 /* unreachable code */
565 vec_jmp(0x0); /* need to call a function from misc to correct linking */