From 659b098309c2bca57ac60a35a1b9900d6f28e74d Mon Sep 17 00:00:00 2001 From: ppisa Date: Sun, 26 Oct 2003 17:46:22 +0000 Subject: [PATCH] Added support for local message processing and some cleanups. 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. --- lincan/include/can.h | 53 +++++++++++-- lincan/include/can_queue.h | 19 ++++- lincan/include/main.h | 5 ++ lincan/src/can_queue.c | 54 ++++++++----- lincan/src/i82527.c | 32 +++++--- lincan/src/ioctl.c | 12 +-- lincan/src/main.c | 2 + lincan/src/read.c | 5 -- lincan/src/sja1000.c | 22 ++++-- lincan/src/sja1000p.c | 49 +++++++++--- lincan/src/write.c | 4 + lincan/utils/readburst.c | 158 +++++++++++++++++++++++++++++-------- 12 files changed, 313 insertions(+), 102 deletions(-) diff --git a/lincan/include/can.h b/lincan/include/can.h index 344dcf6..8247c35 100644 --- a/lincan/include/can.h +++ b/lincan/include/can.h @@ -12,9 +12,11 @@ /** * 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<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); diff --git a/lincan/include/main.h b/lincan/include/main.h index 17e8f55..3bdc912 100644 --- a/lincan/include/main.h +++ b/lincan/include/main.h @@ -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]; diff --git a/lincan/src/can_queue.c b/lincan/src/can_queue.c index 62d8e19..75853a9 100644 --- a/lincan/src/can_queue.c +++ b/lincan/src/can_queue.c @@ -18,6 +18,16 @@ #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 */ diff --git a/lincan/src/i82527.c b/lincan/src/i82527.c index c10db6b..ec99430 100644 --- a/lincan/src/i82527.c +++ b/lincan/src/i82527.c @@ -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; ilength; i++) { + for (i=0; idata[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)) { diff --git a/lincan/src/ioctl.c b/lincan/src/ioctl.c index 40a4204..08b3aa0 100644 --- a/lincan/src/ioctl.c +++ b/lincan/src/ioctl.c @@ -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; } diff --git a/lincan/src/main.c b/lincan/src/main.c index 0f5f60a..1e84d34 100644 --- a/lincan/src/main.c +++ b/lincan/src/main.c @@ -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 diff --git a/lincan/src/read.c b/lincan/src/read.c index 92fcb68..b179897 100644 --- a/lincan/src/read.c +++ b/lincan/src/read.c @@ -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) { diff --git a/lincan/src/sja1000.c b/lincan/src/sja1000.c index bca1fec..46033f2 100644 --- a/lincan/src/sja1000.c +++ b/lincan/src/sja1000.c @@ -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++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; ilength; i++) + for (i=0; idata[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; irx_msg.length; i++) + if(len > CAN_MSG_LENGTH) len = CAN_MSG_LENGTH; + for (i=0; irx_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; } diff --git a/lincan/src/sja1000p.c b/lincan/src/sja1000p.c index ef587dd..b71b5a0 100644 --- a/lincan/src/sja1000p.c +++ b/lincan/src/sja1000p.c @@ -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; diff --git a/lincan/src/write.c b/lincan/src/write.c index 2874003..2f32b2e 100644 --- a/lincan/src/write.c +++ b/lincan/src/write.c @@ -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; diff --git a/lincan/utils/readburst.c b/lincan/utils/readburst.c index 8c61069..8a6d552 100644 --- a/lincan/utils/readburst.c +++ b/lincan/utils/readburst.c @@ -1,47 +1,131 @@ #include -#include +#include #include #include +#include +#include +#include #include #include #include -#include +#include #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 of CAN device [/dev/can0]\n"); + printf(" -m, --mask CAN filter mask\n"); + printf(" -i, --id CAN filter message ID\n"); + printf(" -f, --flags CAN filter flags\n"); + printf(" -w, --wait number of seconds to wait in select call\n"); + printf(" -p, --prefix 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