Added support for local message processing and some cleanups.
authorppisa <ppisa>
Sun, 26 Oct 2003 17:46:22 +0000 (17:46 +0000)
committerppisa <ppisa>
Sun, 26 Oct 2003 17:46:22 +0000 (17:46 +0000)
The local messages processing feature suggested by Unicontrols.
Driver can be directed by "processlocal" parameter to
distribute sent messages back to the local clients.
Values 0 .. disabled, 1 .. can be enabled by CANQUE_FILT IOCTL,
2 .. enabled by default, but can be specified on per queue as well.

12 files changed:
lincan/include/can.h
lincan/include/can_queue.h
lincan/include/main.h
lincan/src/can_queue.c
lincan/src/i82527.c
lincan/src/ioctl.c
lincan/src/main.c
lincan/src/read.c
lincan/src/sja1000.c
lincan/src/sja1000p.c
lincan/src/write.c
lincan/utils/readburst.c

index 344dcf6..8247c35 100644 (file)
 
 /**
  * struct canmsg_t - structure representing CAN message
- * @flags:  message flags, %MSG_RTR .. message is Remote Transmission Request,
- *     %MSG_EXT .. message with extended ID, %MSG_OVR indication of queue
- *     overflow condition
+ * @flags:  message flags
+ *      %MSG_RTR .. message is Remote Transmission Request,
+ *     %MSG_EXT .. message with extended ID, 
+ *      %MSG_OVR .. indication of queue overflow condition,
+ *     %MSG_LOCAL .. message originates from this node.
  * @cob:    communication object number (not used)
  * @id:     ID of CAN message
  * @timestamp: not used
@@ -32,17 +34,51 @@ struct canmsg_t {
        unsigned char   data[CAN_MSG_LENGTH];
 } PACKED;
 
+/**
+ * struct canfilt_t - structure for acceptance filter setup
+ * @flags:  message flags
+ *      %MSG_RTR .. message is Remote Transmission Request,
+ *     %MSG_EXT .. message with extended ID, 
+ *      %MSG_OVR .. indication of queue overflow condition,
+ *     %MSG_LOCAL .. message originates from this node.
+ *     there are corresponding mask bits
+ *     %MSG_RTR_MASK, %MSG_EXT_MASK, %MSG_LOCAL_MASK.
+ *     %MSG_PROCESSLOCAL enables local messages processing in the
+ *     combination with global setting
+ * @queid:  CAN queue identification in the case of the multiple
+ *         queues per one user (open instance)
+ * @cob:    communication object number (not used)
+ * @id:     selected required value of cared ID id bits
+ * @mask:   select bits significand for the comparation;
+ *          1 .. take care about corresponding ID bit, 0 .. don't care
+ *
+ * Header: can.h
+ */
 struct canfilt_t {
        int             flags;
+       int             queid;
        int             cob;
        unsigned long   id;
        unsigned long   mask;
 };
 
-/* Definitions to use for canmsg_t flags */
-#define MSG_RTR (1<<0)
-#define MSG_OVR (1<<1)
-#define MSG_EXT (1<<2)
+/* Definitions to use for canmsg_t and canfilt_t flags */
+#define MSG_RTR   (1<<0)
+#define MSG_OVR   (1<<1)
+#define MSG_EXT   (1<<2)
+#define MSG_LOCAL (1<<3)
+/* If you change above lines, check canque_filtid2internal function */
+
+/* Additional definitions used for canfilt_t only */
+#define MSG_FILT_MASK_SHIFT   8
+#define MSG_RTR_MASK   (MSG_RTR<<MSG_FILT_MASK_SHIFT)
+#define MSG_EXT_MASK   (MSG_EXT<<MSG_FILT_MASK_SHIFT)
+#define MSG_LOCAL_MASK (MSG_LOCAL<<MSG_FILT_MASK_SHIFT)
+#define MSG_PROCESSLOCAL (MSG_OVR<<MSG_FILT_MASK_SHIFT)
+
+
+/* Can message ID mask */
+#define MSG_ID_MASK ((1l<<29)-1)
 
 /* CAN ioctl magic number */
 #define CAN_IOC_MAGIC 'd'
@@ -66,6 +102,7 @@ typedef unsigned short channel_t;
 //#define CONF_FDISABLE
 
 #define STAT _IO(CAN_IOC_MAGIC, 9)
-#define CONF_FILTER_QUE0 _IOW(CAN_IOC_MAGIC, 10, struct canfilt_t)
+#define CANQUE_FILTER _IOW(CAN_IOC_MAGIC, 10, struct canfilt_t)
+#define CANQUE_FLUSH  _IO(CAN_IOC_MAGIC, 11)
 
 #endif /*_CANMSG_T_H*/
index 51f1d9b..648dca0 100644 (file)
@@ -437,6 +437,21 @@ void canque_activate_edge(struct canque_ends_t *inends, struct canque_edge_t *qe
        spin_unlock_irqrestore(&inends->ends_lock, flags);
 }
 
+/**
+ * canque_filtid2internal - converts message ID and filter flags into internal format
+ * @qedge: pointer to the edge structure
+ * @inends: input side of the edge
+ *
+ * This function maps message ID and %MSG_RTR, %MSG_EXT and %MSG_LOCAL into one 32 bit number
+ */
+static inline
+unsigned int canque_filtid2internal(unsigned long id, int filtflags)
+{
+       filtflags &= MSG_RTR|MSG_EXT|MSG_LOCAL;
+       filtflags += filtflags&MSG_RTR;
+       return (id&MSG_ID_MASK) | (filtflags<<28);
+}
+
 int canque_get_inslot(struct canque_ends_t *qends,
        struct canque_edge_t **qedgep, struct canque_slot_t **slotp, int cmd);
        
@@ -462,8 +477,8 @@ int canque_again_outslot(struct canque_ends_t *qends,
        struct canque_edge_t *qedge, struct canque_slot_t *slot);
 
 int canque_set_filt(struct canque_edge_t *qedge,
-       unsigned long filtid, unsigned long filtmask);
-
+       unsigned long filtid, unsigned long filtmask, int flags);
+       
 int canque_flush(struct canque_edge_t *qedge);
 
 struct canque_edge_t *canque_new_edge_kern(int slotsnr);
index 17e8f55..3bdc912 100644 (file)
@@ -185,6 +185,7 @@ struct chip_t {
  * @tx_slot: slot holding transmitted message, slot is taken from
  *     canque_test_outslot() call and is freed by canque_free_outslot()
  *     or rescheduled canque_again_outslot()
+ * @tx_retry_cnt: transmission attempt counter
  * @rx_msg: temporary storage to hold received messages before
  *     calling to canque_filter_msg2edges()
  * @hostchip: pointer to the &chip_t structure this object belongs to
@@ -200,8 +201,11 @@ struct msgobj_t {
        int ret;
 
        struct canque_ends_t *qends;
+
        struct canque_edge_t *tx_qedge;
        struct canque_slot_t *tx_slot;
+       int tx_retry_cnt;
+       
        struct canmsg_t rx_msg;
 
        struct chip_t *hostchip;
@@ -333,6 +337,7 @@ extern int baudrate;
 extern char *hw[MAX_HW_CARDS];
 extern int irq[MAX_IRQ];
 extern unsigned long io[MAX_HW_CARDS];
+extern int processlocal;
 
 extern struct canhardware_t *hardware_p;
 extern struct chip_t *chips_p[MAX_TOT_CHIPS];
index 62d8e19..75853a9 100644 (file)
 #include "../include/can.h"
 #include "../include/can_queue.h"
 
+/* 
+ * Modifies Tx message processing 
+ *  0 .. local message processing disabled
+ *  1 .. local messages disabled by default but can be enabled by canque_set_filt
+ *  2 .. local messages enabled by default, can be disabled by canque_set_filt
+ */
+extern int processlocal;
+
+/*#define CAN_DEBUG*/
+
 #ifdef CAN_DEBUG
        #define DEBUGQUE(fmt,args...) printk(KERN_ERR "can_queue (debug): " fmt,\
        ##args)
@@ -47,11 +57,14 @@ int canque_fifo_flush_slots(struct canque_fifo_t *fifo)
        struct canque_slot_t *slot;
        spin_lock_irqsave(&fifo->fifo_lock, flags);
        slot=fifo->head;
-       *fifo->tail=fifo->flist;
-       fifo->flist=slot;
-       fifo->head=NULL;
-       fifo->tail=&fifo->head;
-       ret=canque_fifo_test_and_set_fl(fifo,EMPTY);
+       if(slot){
+               *fifo->tail=fifo->flist;
+               fifo->flist=slot;
+               fifo->head=NULL;
+               fifo->tail=&fifo->head;
+       }
+       canque_fifo_clear_fl(fifo,FULL);
+       ret=canque_fifo_test_and_set_fl(fifo,EMPTY)?0:1;
        spin_unlock_irqrestore(&fifo->fifo_lock, flags);
        return ret;
 }
@@ -288,18 +301,22 @@ int canque_filter_msg2edges(struct canque_ends_t *qends, struct canmsg_t *msg)
        int destnr=0;
        int ret;
        unsigned long flags;
+       unsigned long msgid;
        struct canque_edge_t *edge;
        struct list_head *entry;
        struct canque_slot_t *slot;
        
-       DEBUGQUE("canque_filter_msg2edges for msg ID %ld\n",msg->id);
+       DEBUGQUE("canque_filter_msg2edges for msg ID 0x%08lx and flags 0x%02x\n",
+                       msg->id, msg->flags);
+       msgid = canque_filtid2internal(msg->id, msg->flags);
+
        spin_lock_irqsave(&qends->ends_lock, flags);
        list_for_each(entry,&qends->inlist){
                edge=list_entry(entry,struct canque_edge_t,inpeers);
                if(canque_fifo_test_fl(&edge->fifo,BLOCK)||canque_fifo_test_fl(&edge->fifo,DEAD))
                        continue;
                /* FIXME: the next comparison should be outside of ends lock */
-               if((msg->id^edge->filtid)&edge->filtmask)
+               if((msgid^edge->filtid)&edge->filtmask)
                        continue;
                atomic_inc(&edge->edge_used);
                spin_unlock_irqrestore(&qends->ends_lock, flags);
@@ -432,19 +449,24 @@ int canque_again_outslot(struct canque_ends_t *qends,
  * @qedge: pointer to the edge
  * @filtid: ID to set for the edge
  * @filtmask: mask used for ID match check
+ * @filtflags: required filer flags
  *
  * Return Value: Negative value is returned if edge is in the process of delete.
  */
 int canque_set_filt(struct canque_edge_t *qedge,
-       unsigned long filtid, unsigned long filtmask)
+       unsigned long filtid, unsigned long filtmask, int filtflags)
 {
        int ret;
        unsigned long flags;
 
        spin_lock_irqsave(&qedge->fifo.fifo_lock,flags);
-       atomic_inc(&qedge->edge_used);
-       qedge->filtid=filtid;
-       qedge->filtmask=filtmask;
+       
+       if(!(filtflags&MSG_PROCESSLOCAL) && (processlocal<2))
+               filtflags |= MSG_LOCAL_MASK;
+       
+       qedge->filtid=canque_filtid2internal(filtid, filtflags);
+       qedge->filtmask=canque_filtid2internal(filtmask, filtflags>>MSG_FILT_MASK_SHIFT);
+       
        if(canque_fifo_test_fl(&qedge->fifo,DEAD)) ret=-1;
        else ret=canque_fifo_test_and_set_fl(&qedge->fifo,BLOCK)?1:0;
 
@@ -454,11 +476,10 @@ int canque_set_filt(struct canque_edge_t *qedge,
        }
        spin_lock_irqsave(&qedge->fifo.fifo_lock,flags);
        if(!ret)canque_fifo_clear_fl(&qedge->fifo,BLOCK);
-       if(atomic_dec_and_test(&qedge->edge_used))
-               canque_notify_bothends(qedge,CANQUEUE_NOTIFY_NOUSR);
        spin_unlock_irqrestore(&qedge->fifo.fifo_lock,flags);
        
-       DEBUGQUE("canque_set_filt for edge %d, ID %ld and mask %ld returned %d\n",qedge->edge_num,filtid,filtmask,ret);
+       DEBUGQUE("canque_set_filt for edge %d, ID %ld, mask %ld, flags %d returned %d\n",
+                 qedge->edge_num,filtid,filtmask,filtflags,ret);
        return ret;
 }
 
@@ -477,7 +498,6 @@ int canque_flush(struct canque_edge_t *qedge)
        int ret;
        unsigned long flags;
 
-       atomic_inc(&qedge->edge_used);
        ret=canque_fifo_flush_slots(&qedge->fifo);
        if(ret){
                canque_notify_inends(qedge,CANQUEUE_NOTIFY_EMPTY);
@@ -488,8 +508,6 @@ int canque_flush(struct canque_edge_t *qedge)
                        list_del(&qedge->outpeers);
                        list_add(&qedge->outpeers,&qedge->outends->idle);
                }
-               if(atomic_dec_and_test(&qedge->edge_used))
-                       canque_notify_bothends(qedge,CANQUEUE_NOTIFY_NOUSR);
                spin_unlock(&qedge->fifo.fifo_lock);
                spin_unlock_irqrestore(&qedge->outends->ends_lock, flags);
        }
@@ -654,7 +672,7 @@ struct canque_edge_t *canque_new_edge_kern(int slotsnr)
        }
        atomic_set(&qedge->edge_used,0);
        qedge->filtid = 0;
-       qedge->filtmask = 0;
+       qedge->filtmask = canque_filtid2internal(0l, (processlocal<2)? MSG_LOCAL:0);
        qedge->edge_prio = 0;
     #ifdef CAN_DEBUG
        /* not exactly clean, but enough for debugging */
index c10db6b..ec99430 100644 (file)
@@ -302,16 +302,16 @@ int i82527_pre_write_config(struct chip_t *chip, struct msgobj_t *obj,
                                                        struct canmsg_t *msg)
 {
        int i=0,id0=0,id1=0,id2=0,id3=0;
+       int len;
+       
+       len = msg->length;
+       if(len > CAN_MSG_LENGTH) len = CAN_MSG_LENGTH;
 
        canobj_write_reg(chip,obj,(RMPD_RES|TXRQ_RES|CPUU_SET|NEWD_RES),iMSGCTL1);
        canobj_write_reg(chip,obj,(MVAL_SET|TXIE_SET|RXIE_RES|INTPD_RES),iMSGCTL0);
-       if (extended) {
-               canobj_write_reg(chip,obj,(msg->length<<4)+(MCFG_DIR|MCFG_XTD),iMSGCFG);
-       }
-       else {
-               canobj_write_reg(chip,obj,(msg->length<<4)+MCFG_DIR,iMSGCFG);
-       }
-       if (extended) {
+
+       if (extended || (msg->flags&MSG_EXT)) {
+               canobj_write_reg(chip,obj,(len<<4)|(MCFG_DIR|MCFG_XTD),iMSGCFG);
                id0 = (unsigned char) (msg->id<<3);
                id1 = (unsigned char) (msg->id>>5);
                id2 = (unsigned char) (msg->id>>13);
@@ -322,13 +322,14 @@ int i82527_pre_write_config(struct chip_t *chip, struct msgobj_t *obj,
                canobj_write_reg(chip,obj,id3,iMSGID0);
        }
        else {
+               canobj_write_reg(chip,obj,(len<<4)|MCFG_DIR,iMSGCFG);
                id1 = (unsigned char) (msg->id<<5);
                id0 = (unsigned char) (msg->id>>3);
                canobj_write_reg(chip,obj,id1,iMSGID1);
                canobj_write_reg(chip,obj,id0,iMSGID0);
        }
        canobj_write_reg(chip,obj,0xfa,iMSGCTL1);
-       for (i=0; i<msg->length; i++) {
+       for (i=0; i<len; i++) {
                canobj_write_reg(chip,obj,msg->data[i],iMSGDAT0+i);
        }
 
@@ -409,6 +410,12 @@ inline void i82527_irq_write_handler(struct chip_t *chip, struct msgobj_t *obj)
        canobj_write_reg(chip,obj,(MVAL_RES|TXIE_RES|RXIE_RES|INTPD_RES),+iMSGCTL0);
 
        if(obj->tx_slot){
+               /* Do local transmitted message distribution if enabled */
+               if (processlocal){
+                       obj->tx_slot->msg.flags |= MSG_LOCAL;
+                       canque_filter_msg2edges(obj->qends, &obj->tx_slot->msg);
+               }
+               /* Free transmitted slot */
                canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot);
                obj->tx_slot=NULL;
        }
@@ -436,19 +443,20 @@ inline void i82527_irq_write_handler(struct chip_t *chip, struct msgobj_t *obj)
 inline void i82527_irq_read_handler(struct chip_t *chip, struct msgobj_t *obj,
                                    unsigned long message_id)
 {
-       int i=0, tmp=1 ;
+       int i=0, tmp=1, len;
        
        while (tmp) {
                canobj_write_reg(chip,obj,(RMPD_RES|TXRQ_RES|MLST_RES|NEWD_RES),iMSGCTL1);
                canobj_write_reg(chip,obj,(MVAL_SET|TXIE_RES|RXIE_SET|INTPD_RES),iMSGCTL0);
 
-               obj->rx_msg.length =(canobj_read_reg(chip,obj,iMSGCFG) & 0xf0) >> 4;
+               len = (canobj_read_reg(chip,obj,iMSGCFG) >> 4) & 0xf;
+               obj->rx_msg.length = len;
                obj->rx_msg.id = message_id;
+
+               if(len > CAN_MSG_LENGTH) len = CAN_MSG_LENGTH;
                for (i=0; i < obj->rx_msg.length; i++)
                        obj->rx_msg.data[i] = canobj_read_reg(chip,obj,iMSGDAT0+i);
 
-//FIXME: Add buffer overflow check, currently it's silently over written!
-
                canque_filter_msg2edges(obj->qends, &obj->rx_msg);
 
                if (!((tmp=canobj_read_reg(chip,obj,iMSGCTL1)) & NEWD_SET)) {
index 40a4204..08b3aa0 100644 (file)
@@ -63,6 +63,10 @@ int can_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned
                                return -1;
                        break;
                }
+               case CANQUE_FLUSH: {
+                       canque_flush(canuser->rx_edge0);
+                       break;
+               }
                case CONF_FILTER: {
                    #if 0
                        if (!strcmp(chip->chip_type,"i82527")) {
@@ -83,19 +87,17 @@ int can_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned
                        /* In- and output buffer re-initialization */
                        
                        if(canuser->rx_edge0){
-                               canque_set_filt(canuser->rx_edge0, arg, ~0);
-                               canque_flush(canuser->rx_edge0);
+                               canque_set_filt(canuser->rx_edge0, arg, ~0, 0);
                        }
 
                        break;
                }
                
-               case CONF_FILTER_QUE0: {
+               case CANQUE_FILTER: {
                        struct canfilt_t canfilt;
                        copy_from_user(&canfilt, (void*)arg, sizeof(struct canfilt_t));
                        if(canuser->rx_edge0){
-                               canque_set_filt(canuser->rx_edge0, canfilt.id, canfilt.mask);
-                               canque_flush(canuser->rx_edge0);
+                               canque_set_filt(canuser->rx_edge0, canfilt.id, canfilt.mask, canfilt.flags);
                        }
                        break;
                }
index 0f5f60a..1e84d34 100644 (file)
@@ -84,6 +84,8 @@ int extmask=0;
 MODULE_PARM(extmask, "1i");
 int mo15mask=0;
 MODULE_PARM(mo15mask, "1i");
+int processlocal=0;
+MODULE_PARM(processlocal, "1i");
 
 /* Other module attributes */
 #ifdef MODULE_SUPPORTED_DEVICE
index 92fcb68..b179897 100644 (file)
@@ -152,11 +152,6 @@ ssize_t can_read(struct file *file, char *buffer, size_t length, loff_t *offset)
                DEBUGMSG("this will always return zero.\n");
                return 0;
        }
-       if (length > 8 * sizeof(struct canmsg_t)) {
-               DEBUGMSG("Reading more than 8 CAN messages, this is not supported.\n");
-               DEBUGMSG("Defaulting to 8 messages.\n");
-               length = 8 * sizeof(struct canmsg_t);
-       }
        /* Initialize hardware pointers */
        obj = canuser->msgobj;
        if (obj == NULL) {
index bca1fec..46033f2 100644 (file)
@@ -222,6 +222,7 @@ int sja1000_pre_write_config(struct chip_t *chip, struct msgobj_t *obj,
                                                        struct canmsg_t *msg)
 {
        int i=0, id=0;
+       int len;
 
        sja1000_start_chip(chip); //sja1000 goes automatically into reset mode on errors
 
@@ -236,7 +237,7 @@ int sja1000_pre_write_config(struct chip_t *chip, struct msgobj_t *obj,
                can_write_reg(chip, CMR_AT, SJACMR);
                i=0;
                while ( !(can_read_reg(chip, SJASR) & SR_TBS) &&
-                                               i++<MAX_TRANSMIT_WAIT_LOOPS) {
+                               i++<MAX_TRANSMIT_WAIT_LOOPS) {
                        udelay(i);
                }
                if (!(can_read_reg(chip, SJASR) & SR_TBS)) {
@@ -245,12 +246,14 @@ int sja1000_pre_write_config(struct chip_t *chip, struct msgobj_t *obj,
                }
        }
 
-       id = (msg->id<<5) | ((msg->flags&MSG_RTR)?ID0_RTR:0) | msg->length;
+       len = msg->length;
+       if(len > CAN_MSG_LENGTH) len = CAN_MSG_LENGTH;
+       id = (msg->id<<5) | ((msg->flags&MSG_RTR)?ID0_RTR:0) | len;
 
        can_write_reg(chip, id>>8, SJATXID1);
        can_write_reg(chip, id & 0xff , SJATXID0);
 
-       for (i=0; i<msg->length; i++)
+       for (i=0; i<len; i++)
                can_write_reg(chip, msg->data[i], SJATXDAT0+i);
 
        return 0;
@@ -382,17 +385,18 @@ irqreturn_t sja1000_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
 
 void sja1000_irq_read_handler(struct chip_t *chip, struct msgobj_t *obj)
 {
-       int i=0, id=0;
+       int i=0, id=0, len;
 
        do {
                id = can_read_reg(chip, SJARXID0) | (can_read_reg(chip, SJARXID1)<<8);
-               obj->rx_msg.length = id & 0x0f;
+               obj->rx_msg.length = len = id & 0x0f;
                obj->rx_msg.flags = id&ID0_RTR ? MSG_RTR : 0;
                obj->rx_msg.timestamp = 0;
                obj->rx_msg.cob = 0;
                obj->rx_msg.id = id>>5;
 
-               for (i=0; i<obj->rx_msg.length; i++)
+               if(len > CAN_MSG_LENGTH) len = CAN_MSG_LENGTH;
+               for (i=0; i<len; i++)
                        obj->rx_msg.data[i]=can_read_reg(chip, SJARXDAT0 + i);
 
                can_write_reg(chip, CMR_RRB, SJACMR);
@@ -406,6 +410,12 @@ void sja1000_irq_write_handler(struct chip_t *chip, struct msgobj_t *obj)
        int cmd;
        
        if(obj->tx_slot){
+               /* Do local transmitted message distribution if enabled */
+               if (processlocal){
+                       obj->tx_slot->msg.flags |= MSG_LOCAL;
+                       canque_filter_msg2edges(obj->qends, &obj->tx_slot->msg);
+               }
+               /* Free transmitted slot */
                canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot);
                obj->tx_slot=NULL;
        }
index ef587dd..b71b5a0 100644 (file)
@@ -92,6 +92,9 @@ int sja1000p_disable_configuration(struct chip_t *chip)
  */
 int sja1000p_chip_config(struct chip_t *chip)
 {
+       int i;
+       unsigned char n, r;
+       
        if (sja1000p_enable_configuration(chip))
                return -ENODEV;
 
@@ -99,6 +102,20 @@ int sja1000p_chip_config(struct chip_t *chip)
        can_write_reg(chip,CDR_PELICAN|chip->sja_cdr_reg,SJACDR); 
        /* Set driver output configuration */
        can_write_reg(chip,chip->sja_ocr_reg,SJAOCR); 
+       
+       /* Simple check for chip presence */
+       for (i=0, n=0x5a; i<8; i++, n+=0xf) {
+               can_write_reg(chip,n,SJAACR0+i);
+       }
+       for (i=0, n=0x5a; i<8; i++, n+=0xf) {
+               r = n^can_read_reg(chip,SJAACR0+i);
+               if (r) {
+                       CANMSG("sja1000p_chip_config: chip connection broken,"
+                               " readback differ 0x%02x\n", r);
+                       return -ENODEV;
+               }
+       }
+       
 
        if (sja1000p_extended_mask(chip,0x00000000, 0xffffffff))
                return -ENODEV;
@@ -248,10 +265,11 @@ void sja1000p_read(struct chip_t *chip, struct msgobj_t *obj) {
                        ((flags & FRM_RTR) ? MSG_RTR : 0) |
                        ((flags & FRM_FF) ? MSG_EXT : 0);
                len = flags & FRM_DLC_M;
+               obj->rx_msg.length = len;
+               if(len > CAN_MSG_LENGTH) len = CAN_MSG_LENGTH;
                for(i=0; i< len; i++) {
                        obj->rx_msg.data[i]=can_read_reg(chip,datastart+i);
                }
-               obj->rx_msg.length = len;
 
                canque_filter_msg2edges(obj->qends, &obj->rx_msg);
 
@@ -314,6 +332,7 @@ int sja1000p_pre_write_config(struct chip_t *chip, struct msgobj_t *obj,
        int i=0; 
        unsigned int id;
        int status;
+       int len;
 
        /* Wait until Transmit Buffer Status is released */
        while ( !((status=can_read_reg(chip, SJASR)) & SR_TBS) && 
@@ -347,10 +366,11 @@ int sja1000p_pre_write_config(struct chip_t *chip, struct msgobj_t *obj,
                        return -EIO;
                }
        }
-       msg->length &= FRM_DLC_M;
+       len = msg->length;
+       if(len > CAN_MSG_LENGTH) len = CAN_MSG_LENGTH;
+       /* len &= FRM_DLC_M; ensured by above condition already */
        can_write_reg(chip, ((msg->flags&MSG_EXT)?FRM_FF:0) |
-               ((msg->flags & MSG_RTR) ? FRM_RTR : 0) |
-               msg->length, SJAFRM);
+               ((msg->flags & MSG_RTR) ? FRM_RTR : 0) | len, SJAFRM);
        if(msg->flags&MSG_EXT) {
                id=msg->id<<3;
                can_write_reg(chip, id & 0xff, SJAID3);
@@ -360,14 +380,14 @@ int sja1000p_pre_write_config(struct chip_t *chip, struct msgobj_t *obj,
                can_write_reg(chip, id & 0xff, SJAID1);
                id >>= 8;
                can_write_reg(chip, id, SJAID0);
-               for(i=0; i < msg->length; i++) {
+               for(i=0; i < len; i++) {
                        can_write_reg(chip, msg->data[i], SJADATE+i);
                }
        } else {
                id=msg->id<<5;
                can_write_reg(chip, (id >> 8) & 0xff, SJAID0);
                can_write_reg(chip, id & 0xff, SJAID1);
-               for(i=0; i < msg->length; i++) {
+               for(i=0; i < len; i++) {
                        can_write_reg(chip, msg->data[i], SJADATS+i);
                }
        }
@@ -541,6 +561,12 @@ void sja1000p_irq_write_handler(struct chip_t *chip, struct msgobj_t *obj)
        int cmd;
        
        if(obj->tx_slot){
+               /* Do local transmitted message distribution if enabled */
+               if (processlocal){
+                       obj->tx_slot->msg.flags |= MSG_LOCAL;
+                       canque_filter_msg2edges(obj->qends, &obj->tx_slot->msg);
+               }
+               /* Free transmitted slot */
                canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot);
                obj->tx_slot=NULL;
        }
@@ -586,7 +612,6 @@ void sja1000p_irq_write_handler(struct chip_t *chip, struct msgobj_t *obj)
 irqreturn_t sja1000p_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
 {
        int irq_register, status, error_code;
-       int static retransmitted=0; /* FIXME - should go into chip struct */
        struct chip_t *chip=(struct chip_t *)dev_id;
        struct msgobj_t *obj=chip->msgobj[0];
 
@@ -637,9 +662,9 @@ irqreturn_t sja1000p_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
                        obj->ret= -ENXIO;
                        /* no such device or address - no ACK received */
                }
-               if(retransmitted++>MAX_RETR) {
+               if(obj->tx_retry_cnt++>MAX_RETR) {
                        can_write_reg(chip, CMR_AT, SJACMR); // cancel any transmition
-                       retransmitted = 0;
+                       obj->tx_retry_cnt = 0;
                }
                if(status&SR_BS) {
                        CANMSG("bus-off, resetting sja1000p\n");
@@ -653,7 +678,7 @@ irqreturn_t sja1000p_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
                }
 
        } else {
-               retransmitted=0;
+               obj->tx_retry_cnt=0;
        }
 
        return IRQ_HANDLED;
@@ -680,8 +705,10 @@ int sja1000p_wakeup_tx(struct chip_t *chip, struct msgobj_t *obj)
        while(!test_and_set_bit(OBJ_TX_LOCK,&obj->flags)){
                clear_bit(OBJ_TX_REQUEST,&obj->flags);
 
-               if (can_read_reg(chip, SJASR) & SR_TBS)
+               if (can_read_reg(chip, SJASR) & SR_TBS){
+                       obj->tx_retry_cnt=0;
                        sja1000p_irq_write_handler(chip, obj);
+               }
        
                clear_bit(OBJ_TX_LOCK,&obj->flags);
                if(!test_bit(OBJ_TX_REQUEST,&obj->flags)) break;
index 2874003..2f32b2e 100644 (file)
@@ -61,6 +61,8 @@ ssize_t can_write(struct file *file, const char *buffer, size_t length, loff_t *
 
        /* Prepare first message */
        copy_from_user(&msg_buff, buffer, sizeof(struct canmsg_t));
+       /* Automatic selection of extended format if "extended" set and ID>2047 */
+       if (extended) if (msg_buff.id & ~0x7ffl ) msg_buff.flags |= MSG_EXT;
 
        /* If the output buffer is full, return immediately in case O_NONBLOCK
         * has been specified or loop until space becomes available.
@@ -93,6 +95,8 @@ ssize_t can_write(struct file *file, const char *buffer, size_t length, loff_t *
        while (bytes_to_copy > 0) {
                /* Prepare first message */
                copy_from_user(&msg_buff, buffer, sizeof(struct canmsg_t));
+               /* Automatic selection of extended format if "extended" set and ID>2047 */
+               if (extended) if (msg_buff.id & ~0x7ffl ) msg_buff.flags |= MSG_EXT;
                /* Get slot */
                if(canque_get_inslot4id(qends, &qedge, &slot, 
                        0, msg_buff.id, 0) < 0) break;
index 8c61069..8a6d552 100644 (file)
 #include <stdio.h>
-#include <fcntl.h>
+#include <stdlib.h>
 #include <unistd.h>
 #include <errno.h>
+#include <signal.h>
+#include <getopt.h>
+#include <fcntl.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/time.h>
-#include <signal.h>
+#include <sys/ioctl.h>
 
 #include "../include/can.h"
 
 int fd;
 
+struct canfilt_t canfilt = {
+       .flags = 0,
+       .queid = 0,
+       .cob = 0,
+       .id = 0,
+       .mask = 0
+};
+
+int canfilt_fl;
+
+int can_wait_sec = 5;
+
+char *can_dev_name = "/dev/can0";
+
+#define PRT_PREFIX_SIZE 40
+char prt_prefix[PRT_PREFIX_SIZE];
+
+char *prt_prefix_in = "CAN %s : ";
+
 int can_fd_wait(int fd, int wait_sec)
 {
-  int ret;
-  struct timeval timeout;
-  fd_set set;
-
-  FD_ZERO (&set);
-  FD_SET (fd, &set);
-  timeout.tv_sec = wait_sec;
-  timeout.tv_usec = 0;
-  while ((ret=select(FD_SETSIZE,&set, NULL, NULL,&timeout))==-1
+       int ret;
+       struct timeval timeout;
+       fd_set set;
+
+       FD_ZERO (&set);
+       FD_SET (fd, &set);
+       timeout.tv_sec = wait_sec;
+       timeout.tv_usec = 0;
+       while ((ret=select(FD_SETSIZE,&set, NULL, NULL,&timeout))==-1
           &&errno==-EINTR);
-  return ret;
+       return ret;
 }
 
 
 /*--- handler on SIGINT signal : the program quit with CTL-C ---*/
 void sortie(int sig)
-       {
+{
        close(fd);
        printf("Terminated by user\n");
        exit(0);
-       }
+}
+
+static void
+usage(void)
+{
+  printf("usage: readburst\n");
+  printf("  -d, --device  <name>     name of CAN device [/dev/can0]\n");
+  printf("  -m, --mask  <num>        CAN filter mask\n");
+  printf("  -i, --id  <num>          CAN filter message ID\n");
+  printf("  -f, --flags <num>        CAN filter flags\n");
+  printf("  -w, --wait <num>         number of seconds to wait in select call\n");
+  printf("  -p, --prefix <str>       string prefix for output\n");
+  printf("  -V, --version            show version\n");
+  printf("  -h, --help               this usage screen\n");
+}
+
+
+int main(int argc, char *argv[])
+{
+       static struct option long_opts[] = {
+               { "uldev", 1, 0, 'd' },
+               { "mask",  1, 0, 'm' },
+               { "id",    1, 0, 'i' },
+               { "flags", 1, 0, 'f' },
+               { "wait",  1, 0, 'w' },
+               { "prefix",1, 0, 'p' },
+               { "version",0,0, 'V' },
+               { "help",  0, 0, 'h' },
+               { 0, 0, 0, 0}
+       };
+       int opt;
 
-int main(void)
-       {
        int n,ret;
        unsigned long i=0;
        struct canmsg_t readmsg={0,0,5,0,0,{0,}};
        struct sigaction act;
 
+
+       while ((opt = getopt_long(argc, argv, "d:m:i:f:w:p:Vh",
+                           &long_opts[0], NULL)) != EOF) switch (opt) {
+               case 'd':
+                       can_dev_name=optarg;
+                       break;
+               case 'm':
+                       canfilt_fl=1;
+                       canfilt.mask = strtol(optarg,NULL,0);
+                       break;
+               case 'i':
+                       canfilt_fl=1;
+                       canfilt.id = strtol(optarg,NULL,0);
+                       break;
+               case 'f':
+                       canfilt_fl=1;
+                       canfilt.flags = strtol(optarg,NULL,0);
+                       break;
+               case 'w':
+                       can_wait_sec = strtol(optarg,NULL,0);
+                       break;
+               case 'p':
+                       prt_prefix_in = optarg;
+                       break;
+               case 'V':
+                       fputs("LinCAN utilities v0.2\n", stdout);
+                       exit(0);
+               case 'h':
+               default:
+                       usage();
+                       exit(opt == 'h' ? 0 : 1);
+       }
+
+
        /*------- register handler on SIGINT signal -------*/
        act.sa_handler=sortie;
        sigemptyset(&act.sa_mask);
@@ -49,39 +133,43 @@ int main(void)
        sigaction(SIGINT,&act,0);
        /*---------------------------------------*/     
 
-       if ((fd=open("/dev/can0",O_RDWR)) < 0) 
-               {
+       if ((fd=open(can_dev_name, O_RDWR)) < 0) {
                perror("open");
-               printf("Error opening /dev/can0\n");
+               printf("Error opening %s\n", can_dev_name);
                exit(1);        
+       }
+       
+       if (canfilt_fl) {
+               ret = ioctl(fd, CANQUE_FILTER, &canfilt);
+               if(ret<0) {
+                       perror("ioctl FILTER_QUE");
                }
+       }
 
-       while (1)
-               {
+       snprintf(prt_prefix, PRT_PREFIX_SIZE, prt_prefix_in, can_dev_name);
+       
+       while (1) {
                readmsg.flags=0;
                readmsg.cob=0;
                readmsg.timestamp=0;
            #if 1
-               ret=can_fd_wait(fd, 5);
-               printf("can_fd_wait returnet %d\n",ret);
+               ret=can_fd_wait(fd, can_wait_sec);
+               printf("%scan_fd_wait returned %d\n", prt_prefix, ret);
            #endif
                ret=read(fd,&readmsg,sizeof(struct canmsg_t));
-               if(ret <0) 
-                       {
-                       printf("Error reading message\n");
-                       }
-               else if(ret == 0)
-                       {
-                       printf("No message arrived\n");
-                       }
-               else 
-                       {
-                       printf("Received message #%lu: id=%lX dlc=%u",i,readmsg.id,readmsg.length);
+               if(ret <0) {
+                       printf("%sError reading message\n", prt_prefix);
+               }
+               else if(ret == 0) {
+                       printf("%sNo message arrived\n", prt_prefix);
+               } else {
+                       printf("%sRx msg #%lu: id=%lX dlc=%u flg=0x%02x",
+                               prt_prefix,i,readmsg.id,readmsg.length,readmsg.flags);
                        for(n=0 ; n<readmsg.length ; n++)
                                printf(" %.2X",(unsigned char)readmsg.data[n]);
                        printf("\n");
                        i++;
-                       }
                }
+       }
        return 0;
 }