]> rtime.felk.cvut.cz Git - lincan.git/blobdiff - embedded/app/usbcan/main.c
Used sysless functions for IRQ handling. Used access functions to the chip register...
[lincan.git] / embedded / app / usbcan / main.c
index 205ae3561b025957db11be36a72a73a30d4bd40f..71fb5e7a575e0352fe73f8ed390bfc61cc5a6e34 100644 (file)
@@ -1,3 +1,35 @@
+/**************************************************************************/
+/* File: main.c - setup and main loop of USB<->CAN converter              */
+/*                                                                        */
+/* LinCAN - (Not only) Linux CAN bus driver                               */
+/* Copyright (C) 2002-2011 DCE FEE CTU Prague <http://dce.felk.cvut.cz>   */
+/* Copyright (C) 2008 Jan Kriz email:johen@post.cz                        */
+/*                                                                        */
+/* LinCAN is free software; you can redistribute it and/or modify it      */
+/* under terms of the GNU General Public License as published by the      */
+/* Free Software Foundation; either version 2, or (at your option) any    */
+/* later version.  LinCAN 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    */
+/* General Public License for more details. You should have received a    */
+/* copy of the GNU General Public License along with LinCAN; see file     */
+/* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave,  */
+/* Cambridge, MA 02139, USA.                                              */
+/*                                                                        */
+/* To allow use of LinCAN in the compact embedded systems firmware        */
+/* and RT-executives (RTEMS for example), main authors agree with next    */
+/* special exception:                                                     */
+/*                                                                        */
+/* Including LinCAN header files in a file, instantiating LinCAN generics */
+/* or templates, or linking other files with LinCAN objects to produce    */
+/* an application image/executable, does not by itself cause the          */
+/* resulting application image/executable to be covered by                */
+/* the GNU General Public License.                                        */
+/* This exception does not however invalidate any other reasons           */
+/* why the executable file might be covered by the GNU Public License.    */
+/* Publication of enhanced or derived LinCAN files is required although.  */
+/**************************************************************************/
+
 #include <stdio.h>
 #include <string.h>
 #include <cpu_def.h>
 #include <lpciap.h>
 #include <lpciap_kvpb.h>
 
+#include <endian.h>
+#if __BYTE_ORDER == __BIG_ENDIAN
+  #include <byteswap.h>
+#endif
+
 #include "./can/can.h"
 #include "./can/sja1000p.h"
 #include "./can/main.h"
 
-#include "./can/can_sysdep.h"
+// #include "./can/can_sysdep.h"
 #include "./can/modparms.h"
 #include "./can/devcommon.h"
 
-#include "./can/ul_usb1.h"
-//#include "./can/setup.h"
+//#include "./can/ul_usb1.h"
+
+#include "./can/setup.h"
+
+#include "./usb/usb_defs.h"
+#include "./usb/usb_vend.h"
+
+
+#include "can/lpc17xx_can.h"
 
 #define MASK_EP1RX  0x01
 #define MASK_EP1TX  0x02
 
-#ifdef USB_MAX_PACKET
-       #undef USB_MAX_PACKET
-       #define USB_MAX_PACKET 8
-#endif
-
 #define CAN_OP_MASK 0x80
 #define CAN_OP_READ 0x80
 #define CAN_OP_WRITE 0x00
 
+#ifdef USB_MAX_PACKET
+       #undef USB_MAX_PACKET
+       #define USB_MAX_PACKET 16
+#endif
+/***********************************************************************
+ * Note:
+ * Comparing to LinCAN, there is no need to sleep for processes
+ * because the degree of filling of fifo from the client side
+ * is solved in main cycle (no new messages are accepted when full)
+ * and on the server side by speed of USB interface. FIFO in edge
+ * from SJA chip to USB interface should never be filled.
+ ***********************************************************************/
+
+/***********************************************************************
+ * Note:
+ * Code is wittingly complex in order to ease future changes in hardware
+ * configuration and to make it as much similar as the code of LinCAN
+ ***********************************************************************/
 
 LT_TIMER_DEC(lt_10msec)
 LT_TIMER_IMP(lt_10msec)
@@ -48,17 +105,20 @@ LT_TIMER_IMP(lt_2sec)
 
 typedef void (*FNC)(); //function ptr
 
-/***********************************/
-// global variables
+/***********************************************************************
+ * global variables
+ ***********************************************************************/
 
 usb_device_t usb_device;
 
-usb_ep_t eps[2];
+usb_ep_t eps[NUM_ENDPOINTS];
 unsigned char ep1_rx_buff[USB_MAX_PACKET];
 unsigned char ep1_tx_buff[USB_MAX_PACKET];
-uint8_t timer_str,timer_rx_off,timer_tx_off,timer_configured,usb_can_send;
+uint8_t timer_str,timer_rx_off,timer_tx_off,timer_configured;
 volatile uint8_t bootloader_run;
 
+uint8_t vendor_ret;
+
 int processlocal;
 
 int baudrate[MAX_TOT_CHIPS];
@@ -67,11 +127,18 @@ struct canhardware_t *hardware_p=&canhardware;
 struct canchip_t *chips_p[MAX_TOT_CHIPS];
 struct msgobj_t *objects_p[MAX_TOT_MSGOBJS];
 
+struct canuser_t *canuser;
+
+extern int init_chip_struct(struct candevice_t *candev, int chipnr, int irq, long baudrate);
+extern int register_chip_struct(struct canchip_t *chip, int minorbase);
+extern int register_obj_struct(struct msgobj_t *obj, int minorbase);
+
+/***********************************************************************
+ * IF SOMETHING BAD HAPPENED
+ ***********************************************************************/
 
-/**
-       SOMETHING BAD HAPPENED
-*/
 int sys_err(){
+  
   unsigned char i=0;
 
   while(1) {
@@ -89,9 +156,23 @@ int sys_err(){
   }
 }
 
-/**
-       Routine for visible LED blinking
+/***********************************************************************
+ * Microsecond delay routine
+ ***********************************************************************/
+/*
+void udelay(long time)
+{
+  volatile long ticks=(time * CCLK) / 2000000;
+  do{
+    ticks--;
+  } while(ticks>0);
+}
 */
+
+/***********************************************************************
+ * Routine for visible LED blinking (on USB transmission)
+ ***********************************************************************/
+
 void timer_10ms(void)
 {
   if (timer_tx_off!=0) timer_tx_off--;
@@ -108,26 +189,53 @@ void timer_10ms(void)
   }*/
 }
 
-/***********************************/
+/***********************************************************************
+ * Main routine
+ ***********************************************************************/
+
 int main(void)
 {
        struct candevice_t *candev;
-       struct canchip_t *chip;
+       struct canchip_t *chip=NULL;
+       struct msgobj_t *obj;
+       struct canque_ends_t *qends;
+       struct canque_edge_t *edge,*qedge;
+       struct canque_slot_t *slot;
+       struct canmsg_t canmsg;
+       can_spin_irqflags_t iflags;
+
        int chipnr,bd;
+       int i,size,m=0;
+
+       CANMSG("Starting USBCAN module firmware...\n");
 
 //     volatile int i=0;
        bootloader_run=0;
        /***********************************/
+
        lt_10msec_init();
        lt_100msec_init();
        lt_2sec_init();
 
-       SET_OUT_PIN(LED_PORT,LED_ERR);
-       CLR_OUT_PIN(LED_PORT,LED_GP);
+       // DEBUG
+       //SET_OUT_PIN(LED_PORT,LED_ERR);
+       //CLR_OUT_PIN(LED_PORT,LED_GP);
+
+       if (USB_MAX_PACKET<16){
+               CANMSG("Maximum packet size less than 16B (is %dB)\n",USB_MAX_PACKET);
+               sys_err();
+       }
+
+
+       //***********************************************************************
+       // * CAN device initialization - device side (adapted from LinCAN setup.c)
+       // ***********************************************************************
+
+//     useless with lpc17xx (defined in can_lpcbusemu.c)
+//     can_init();
 
-       /// *************************
-       /// CAN device initialization
 
+       DEBUGMSG("Initiating CAN device initialization\n");
        baudrate[0]=1000;
 
        canqueue_kern_initialize();
@@ -135,8 +243,11 @@ int main(void)
        hardware_p->nr_boards=1;
 
        candev=(struct candevice_t *)malloc(sizeof(struct candevice_t));
-               if (candev==NULL) sys_err();
-               memset(candev, 0, sizeof(struct candevice_t));
+       if (!candev){
+               CANMSG("No space left in memory\n");
+               sys_err();
+       }
+       memset(candev, 0, sizeof(struct candevice_t));
 
        hardware_p->candevice[0]=candev;
        candev->candev_idx=0;
@@ -144,24 +255,61 @@ int main(void)
        candev->dev_base_addr=0;
 
        candev->hwspecops=(struct hwspecops_t *)malloc(sizeof(struct hwspecops_t));
-               if (candev->hwspecops==NULL) sys_err();
-               memset(candev->hwspecops, 0, sizeof(struct hwspecops_t));
+       if (!candev->hwspecops){
+               CANMSG("No space left in memory\n");
+               sys_err();
+       }
+       memset(candev->hwspecops, 0, sizeof(struct hwspecops_t));
+
+       
 
-       ul_usb1_register(candev->hwspecops);
+       // DEBUG
+       //ul_usb1_register(candev->hwspecops);  //(defined in ul_usb1.c)
+       // register for another board:
+       can_lmc1_register(candev->hwspecops);
+
+       
 
        bd=baudrate[0];
-       if (candev->hwspecops->init_hw_data(candev)) sys_err();
-       /* Alocate and initialize the chip structures */
+       if (candev->hwspecops->init_hw_data(candev)){
+               CANMSG("HW data could not be initialized\n");
+               sys_err();
+       }
+
+       // Alocate and initialize the chip structures
        for (chipnr=0; chipnr < candev->nr_all_chips; chipnr++) {
-/*             if(chipnr<irqnum)
-                       irqsig=irq[*irq_param_idx_p+chipnr];*/
-               if (init_chip_struct(candev, chipnr, 0, bd*1000)) sys_err();
+//             if(chipnr<irqnum)
+//                     irqsig=irq[*irq_param_idx_p+chipnr];
+               if (init_chip_struct(candev, chipnr, 0, bd*1000)){
+                       CANMSG("Chip structure could not be initialized\n");
+                       sys_err();
+               }
        }
+
+
+
+       for (chipnr=0; chipnr < candev->nr_all_chips; chipnr++) {
+               struct canchip_t *chip=candev->chip[chipnr];
+               int objnr;
+
+               register_chip_struct(chip, m);
+
+               for (objnr=0; objnr<chip->max_objects; objnr++) {
+                       register_obj_struct(chip->msgobj[objnr], m);
+                       if(m>=0) m++;
+               }
+       }
+
+
        if (candev->hwspecops->request_io(candev))
                sys_err();
        candev->flags|=CANDEV_IO_RESERVED;
+
+
        if (candev->hwspecops->reset(candev))
                sys_err();
+
+
        for(chipnr=0; chipnr<candev->nr_all_chips; chipnr++) {
                if((chip=candev->chip[chipnr])==NULL)
                        continue;
@@ -173,11 +321,12 @@ int main(void)
 
                chip->flags |= CHIP_ATTACHED;
 
-// Interrupts from chip are served in main cycle
-/*             if(can_chip_setup_irq(chip)<0) {
-//                     CANMSG("Error to setup chip IRQ\n");
+               // used with lpc17xx:
+               if(can_chip_setup_irq(chip)<0) {
+                       CANMSG("Error to setup chip IRQ\n");
                        sys_err();
-               }*/
+               }
+
        }
 
        if (candev->flags & CANDEV_PROGRAMMABLE_IRQ)
@@ -186,19 +335,69 @@ int main(void)
                        sys_err();
                }
 
+       //***********************************************************************
+       // * CAN device initialization - client side (adapted from LinCAN open.c)
+       // ***********************************************************************
+
+
+       chip=candev->chip[0];
+       obj=chip->msgobj[0];
+       atomic_inc(&obj->obj_used);
+       can_msgobj_set_fl(obj,OPENED);
+
+       if (chip->flags & CHIP_CONFIGURED)
+               DEBUGMSG("Device is already configured.\n");
+       else {
+               if (chip->chipspecops->chip_config(chip))
+                       CANMSG("Error configuring chip.\n");
+               else
+                       chip->flags |= CHIP_CONFIGURED;
+
+               if (chip->chipspecops->pre_read_config(chip,obj)<0)
+                       CANMSG("Error initializing chip for receiving\n");
 
+       } // End of chip configuration
 
-       /// ***************************************
-       /// CAN device initialization - client side
 
-       ///*********
-       /// USB init
+       canuser = (struct canuser_t *)malloc(sizeof(struct canuser_t));
+       if(canuser == NULL) sys_err();
+       canuser->flags=0;
+//     canuser->userinfo.fileinfo.file = file;
+       canuser->msgobj = obj;
+//     canuser->magic = CAN_USER_MAGIC;
+//     file->private_data = canuser;
+
+       qends = (struct canque_ends_t *)malloc(sizeof(struct canque_ends_t));
+       if(qends == NULL) sys_err();
+       canqueue_ends_init_kern(qends);
+       canuser->qends = qends;
+
+       //required to synchronize with RT-Linux context
+       can_spin_lock_irqsave(&canuser_manipulation_lock, iflags);
+       list_add(&canuser->peers, &obj->obj_users);
+       can_spin_unlock_irqrestore(&canuser_manipulation_lock, iflags);
+
+       if(canqueue_connect_edge(edge=canque_new_edge_kern(MAX_BUF_LENGTH),
+               canuser->qends, obj->qends)<0) sys_err();
+
+       if(canqueue_connect_edge(canuser->rx_edge0=canque_new_edge_kern(MAX_BUF_LENGTH),
+               obj->qends, canuser->qends)<0) sys_err();
+       //FIXME: more generic model should be used there
+       canque_edge_decref(canuser->rx_edge0);
+       canque_edge_decref(edge);
+
+
+
+       /***********************************************************************
+        * USB Init
+        ***********************************************************************/
 
        memset( &usb_device, 0, sizeof( usb_device));
        usb_device.id = 1;
+       usb_device.devdes_table = &usb_devdes_table;
        usb_device.init = usb_lpc_init;
        usb_debug_set_level(DEBUG_LEVEL_NONE);
-       usb_device.cntep = 3;
+       usb_device.cntep = NUM_ENDPOINTS;
        usb_device.ep = eps;
 
        eps[0].max_packet_size = USB_MAX_PACKET;
@@ -210,50 +409,133 @@ int main(void)
        eps[0].udev = &usb_device;
        eps[1].udev = &usb_device;
 
-//  usb_device.vendor_fnc=usb_loader;
+       usb_device.vendor_fnc=usbcan_vendor;
 
        usb_init(&usb_device);
        usb_connect(&usb_device);
+       usb_device.ep_events |= MASK_EP1TX;
+
+       /***********************************************************************
+        * Start
+        ***********************************************************************/
+
+       timer_rx_off=timer_tx_off=timer_str=timer_configured=0;
 
-       can_init();
-       usb_can_send=1;
 
-       /********************/
-       // start
-  timer_rx_off=timer_tx_off=timer_str=timer_configured=0;
+       printf("Main loop\n");
+
        while (1) {
 
                usb_check_events(&usb_device);
                usb_control_response(&usb_device);
 
-               if ((usb_device.ep_events & MASK_EP1RX)&&(usb_can_send)) {  //EP1RX
-                       int size;
-                       uint8_t *data;
-                       uint8_t val;
-                       size=usb_udev_read_endpoint(&eps[0],ep1_rx_buff,USB_MAX_PACKET);
-                       data=(uint8_t *)ep1_rx_buff;
-                       if (size==2){
-                               if (((*data)&CAN_OP_MASK)==CAN_OP_READ){ // Get data from CAN device and return to caller
-                                       can_read((*data) & 0x7F,&val);
+// useless with lpc17xx:
+//             if (!(IO0PIN&P0_SJA1000_INT_PIN)) //INT PIN is inverted
+//                     chip->chipspecops->irq_handler(0,chip);
+
+               if (usb_device.ep_events & MASK_EP1RX) {  //EP1RX - data waiting to receive
+                       
+                       if (canque_get_inslot(qends, &qedge, &slot, 0)>=0){ //Free slot obtained
+
+                               size=usb_udev_read_endpoint(&eps[0],ep1_rx_buff,16);
+                               if (size==16){
+                                       uint16_t msgflags;
+                                       uint32_t msgid;
+                                       canmsg.cob=0;
+                                       canmsg.length=*(uint8_t *)(ep1_rx_buff+1);
+                                       if (canmsg.length > CAN_MSG_LENGTH)
+                                               canmsg.length=CAN_MSG_LENGTH;
+                                       msgflags=*(uint16_t *)(ep1_rx_buff+2);
+                                       msgid=*(uint32_t *)(ep1_rx_buff+4);
+                                       #if __BYTE_ORDER == __BIG_ENDIAN
+                                               msgflags  = bswap_16( msgflags);
+                                               msgid  = bswap_32( msgid);
+                                       #endif
+                                       canmsg.flags=msgflags;
+                                       canmsg.id=msgid;
+
+                                       for (i=0;i<canmsg.length;i++){
+                                               canmsg.data[i]=*(unsigned char*)(ep1_rx_buff+8+i);
+                                       }
+                                       for (;i<CAN_MSG_LENGTH;i++){
+                                               canmsg.data[i]=0;
+                                       }
+                                       /* Automatic selection of extended format if ID>2047 */
+                                       if (canmsg.id & ~0x7ffl & MSG_ID_MASK ) canmsg.flags |= MSG_EXT;
+                                       /* has been dependent on "extended" option */
+                       
+                                       slot->msg=canmsg;
+                                       canque_put_inslot(qends, qedge, slot);
+
+                               }
+                               else
+                                       canque_abort_inslot(qends,qedge,slot);
+                                       
+
+                               timer_rx_off=50;        //rosviceni diody pri prijmu
+                               CLR_OUT_PIN(LED_PORT,LED2_BIT);
+                               usb_device.ep_events &= ~MASK_EP1RX;
+                       
+                                       
+                       }
+                       
+
+/*                     if (size==2){
+                               uint8_t val;
+                               if ((data[0]&CAN_OP_MASK)==CAN_OP_READ){ // Get data from CAN device and return to caller
+                                       val = can_read(data[0] & ~CAN_OP_MASK);
                                        *(data+1)=val;
                                        usb_udev_write_endpoint(&eps[1],(unsigned char *)data,size);
                                        timer_rx_off=50;        //rosviceni diody pri prijmu
                                        CLR_OUT_PIN(LED_PORT,LED2_BIT);
                                        usb_can_send=0;
                                }
-                               if (((*data)&CAN_OP_MASK)==CAN_OP_WRITE){ // Save data to CAN device
-                                       can_write((*data)&(~CAN_OP_MASK),data+1);
+                               if ((data[0]&CAN_OP_MASK)==CAN_OP_WRITE){ // Save data to CAN device
+                                       can_write(data[1], data[0] & ~CAN_OP_MASK);
                                        timer_tx_off=50;                //rozsviceni diod pri vysilani
                                        CLR_OUT_PIN(LED_PORT,LED1_BIT);
                                }
-                       }
-                       usb_device.ep_events &= ~MASK_EP1RX;
+                       }*/
                }
 
-               if(usb_device.ep_events & MASK_EP1TX){
-                       usb_can_send=1;
-                       usb_device.ep_events &= ~MASK_EP1TX;
+               
+               if(usb_device.ep_events & MASK_EP1TX){ //EP1TX - data transmitted
+                       if(canque_test_outslot(qends, &qedge, &slot)>=0){
+                               DEBUGMSG("CAN message ready to send over usb\n");
+                               uint16_t msgflags;
+                               uint32_t msgid;
+
+                               *(uint8_t *)(ep1_tx_buff)=0;
+                               *(uint8_t *)(ep1_tx_buff+1)=slot->msg.length;
+
+                               msgflags=slot->msg.flags;
+                               msgid=slot->msg.id;
+                               #if __BYTE_ORDER == __BIG_ENDIAN
+                                       msgflags  = bswap_16( msgflags);
+                                       msgid  = bswap_32( msgid);
+                               #endif
+
+                               *(uint16_t *)(ep1_tx_buff+2)=msgflags;
+                               *(uint32_t *)(ep1_tx_buff+4)=msgid;
+                               for (i=0;i<slot->msg.length;i++){
+                                       *(uint8_t *)(ep1_tx_buff+8+i)=slot->msg.data[i];
+                               }
+                               for (;i<CAN_MSG_LENGTH;i++){
+                                       *(uint8_t *)(ep1_tx_buff+8+i)=0;
+                               }
+                               usb_udev_write_endpoint(&eps[1],ep1_tx_buff,16);
+
+                               canque_free_outslot(qends, qedge, slot);
+                               timer_tx_off=50;                //rozsviceni diod pri vysilani
+                               CLR_OUT_PIN(LED_PORT,LED1_BIT);
+                               usb_device.ep_events &= ~MASK_EP1TX;
+
+                       }
+                       
                }
+               
+
+               //if (usb_can_send && )
 
 #ifdef WATCHDOG_ENABLED
                watchdog_feed();