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.
/**
* 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
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'
//#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*/
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);
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);
* @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
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;
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];
#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)
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;
}
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);
* @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;
}
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;
}
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);
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);
}
}
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 */
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);
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);
}
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;
}
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)) {
return -1;
break;
}
+ case CANQUE_FLUSH: {
+ canque_flush(canuser->rx_edge0);
+ break;
+ }
case CONF_FILTER: {
#if 0
if (!strcmp(chip->chip_type,"i82527")) {
/* 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;
}
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
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) {
struct canmsg_t *msg)
{
int i=0, id=0;
+ int len;
sja1000_start_chip(chip); //sja1000 goes automatically into reset mode on errors
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)) {
}
}
- 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;
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);
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;
}
*/
int sja1000p_chip_config(struct chip_t *chip)
{
+ int i;
+ unsigned char n, r;
+
if (sja1000p_enable_configuration(chip))
return -ENODEV;
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;
((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);
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) &&
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);
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);
}
}
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;
}
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];
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");
}
} else {
- retransmitted=0;
+ obj->tx_retry_cnt=0;
}
return IRQ_HANDLED;
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;
/* 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.
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;
#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);
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;
}