From d913cca19238e9684196ac60c97ff99f1dcf947d Mon Sep 17 00:00:00 2001 From: Guilherme Sanches Date: Thu, 12 Oct 2017 19:38:36 +0200 Subject: [PATCH] Working in progress regarding the canbus driver. The fifo API has been renew to a none dynamic queue and replaced on their own files. On the occan. and .h full implementation of the API has to be done (see the TODO tags). On the API side the force command has to be fully implemented on the occan_fifo_put. The transfer of messages from the internal fifo to the external buffers also has to be implemented. Message filters have to be implemented as well. --- .../iop_backup/iop_physical_device_0.c | 132 +++++ .../iop_can/iop/iop_physical_device_0.c | 16 + xky/examples/iop_can/sampling/occan_lib.c | 522 +++++++++++++++++ xky/libs/libiop/drivers/can/include/occan.h | 29 +- .../drivers/can/include/occan_msg_queue.h | 30 + xky/libs/libiop/drivers/can/occan.c | 533 +++++++++--------- xky/libs/libiop/drivers/can/occan_msg_queue.c | 64 +++ xky/libs/libiop/include/can_support.h | 2 + 8 files changed, 1058 insertions(+), 270 deletions(-) create mode 100644 xky/examples/iop_backup/iop_physical_device_0.c create mode 100644 xky/examples/iop_can/sampling/occan_lib.c create mode 100644 xky/libs/libiop/drivers/can/include/occan_msg_queue.h create mode 100644 xky/libs/libiop/drivers/can/occan_msg_queue.c diff --git a/xky/examples/iop_backup/iop_physical_device_0.c b/xky/examples/iop_backup/iop_physical_device_0.c new file mode 100644 index 00000000..f9d0f695 --- /dev/null +++ b/xky/examples/iop_backup/iop_physical_device_0.c @@ -0,0 +1,132 @@ +/* + * ============================================================================ + * This file was generated by the GMV's Configurator Tool and is part of an I/O + * partition configuration. + * File Purpose: IO Partition user configuration. Contains the configuration + * options for Ethernet's GRETH devices. + * ============================================================================ + */ +#include +#include +#include + +/** + * @brief IOP remote ports + */ +extern iop_port_t remote_ports[2]; + +/** + * @brief IOP buffers + */ +static iop_buffer_t iop_buffers[64]; +static uint8_t iop_buffers_storage[64 * IOP_BUFFER_SIZE]; + +/** + * @brief TX descriptor to IOP buffer mapping + */ +static iop_buffer_t *tx_iop_buffer[32]; +/** + * @brief RX descriptor to IOP buffer mapping + */ +static iop_buffer_t *rx_iop_buffer[32]; + +/** + * @brief RX and TX descriptor table + * @warning this should be 2048, but we need 3072 to ensure the 0x400 alignment + */ +//static uint8_t descriptor_table[3072]; + +/** @brief GRETH control structure*/ +static occan_priv occan_driver = \ +{ + .speed = 250000, // TODO maybe use a enum in the future + .code = {0, 0, 0, 0}, + .mask = {0, 0, 0, 0}, + + .iop_buffers = iop_buffers, + .iop_buffers_storage = iop_buffers_storage, + + /** @note descriptor table address are split and aligned at the runtime */ +// .txdesc = descriptor_table, +// .rxdesc = descriptor_table, + + .tx_iop_buffer = tx_iop_buffer, + .rx_iop_buffer = rx_iop_buffer +}; + +/** @brief GRETH driver configuration */ +static iop_can_device_t device_configuration = \ +{ + /* device configuration */ + .dev = { + + .driver = (void *)&occan_driver, + .init = occan_initialize, + .open = occan_open, + .read = occan_read, + .write = occan_write, + .close = occan_close, + }, + .dev_name ="/dev/occan0", + .count = 0, + .flags = 0, + .bytes_moved = 0, +}; + +/** + * @brief Device Scheduling + */ +static uint32_t reads_per_period[] = \ + { 5 }; + +/** + * @brief Routes Headers + */ +static iop_header_t route_header[1] = \ +{ + { + .can_header = { + .extended = 0, + .rtr = 0, + .sshot = 0, + .id = 2, + }, + } +}; + +/** + * @brief Routes Scheduling + */ +static uint32_t route_schedule_0[1] = \ + { 1 }; + +/** + * @brief Routes Configuration + */ +static iop_physical_route_t physical_routes[1] =\ +{ + { + .schedule = route_schedule_0, + .header = &route_header[0], + .port = &remote_ports[2] + }, +}; + +/** + * @brief Pysical Device configuration + */ +iop_physical_device_t physical_device_0 =\ +{ + .driver = (iop_device_driver_t *)&device_configuration, + .routes = { + .length = 2, + .elements = physical_routes + }, + .reads_per_period = reads_per_period, + + .reader_task = can_reader, + .writer_task = can_write, + .header_prebuild = can_prebuild_header, + .header_compare = can_compare_header, + .header_copy = can_copy_header, +}; diff --git a/xky/examples/iop_can/iop/iop_physical_device_0.c b/xky/examples/iop_can/iop/iop_physical_device_0.c index f9d0f695..1abfab33 100644 --- a/xky/examples/iop_can/iop/iop_physical_device_0.c +++ b/xky/examples/iop_can/iop/iop_physical_device_0.c @@ -30,6 +30,13 @@ static iop_buffer_t *tx_iop_buffer[32]; */ static iop_buffer_t *rx_iop_buffer[32]; +/** + * @brief Allocation of for the internal message queue + * to be used by the occan driver + */ + +static CANMsg msg_queue[32]; + /** * @brief RX and TX descriptor table * @warning this should be 2048, but we need 3072 to ensure the 0x400 alignment @@ -46,6 +53,15 @@ static occan_priv occan_driver = \ .iop_buffers = iop_buffers, .iop_buffers_storage = iop_buffers_storage, + .internal_msg_queue = { + .cnt = 0, + .ovcnt = 0, + .next = 0, + .last = 0, + .max = 32, + .fifo = msg_queue, + }, + /** @note descriptor table address are split and aligned at the runtime */ // .txdesc = descriptor_table, // .rxdesc = descriptor_table, diff --git a/xky/examples/iop_can/sampling/occan_lib.c b/xky/examples/iop_can/sampling/occan_lib.c new file mode 100644 index 00000000..a5d0c06e --- /dev/null +++ b/xky/examples/iop_can/sampling/occan_lib.c @@ -0,0 +1,522 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "occan_lib.h" + +/* The rtems to errno table + * +rtems_assoc_t errno_assoc[] = { + { "OK", RTEMS_SUCCESSFUL, 0 }, + { "BUSY", RTEMS_RESOURCE_IN_USE, EBUSY }, + { "INVALID NAME", RTEMS_INVALID_NAME, EINVAL }, + { "NOT IMPLEMENTED", RTEMS_NOT_IMPLEMENTED, ENOSYS }, + { "TIMEOUT", RTEMS_TIMEOUT, ETIMEDOUT }, + { "NO MEMORY", RTEMS_NO_MEMORY, ENOMEM }, + { "NO DEVICE", RTEMS_UNSATISFIED, ENODEV }, + { "INVALID NUMBER", RTEMS_INVALID_NUMBER, EBADF}, + { "NOT RESOURCE OWNER", RTEMS_NOT_OWNER_OF_RESOURCE, EPERM}, + { "IO ERROR", RTEMS_IO_ERROR, EIO}, + { 0, 0, 0 }, +}; +*/ + +occan_t occanlib_open(char *name) { + int fd; + occan_t ret = NULL; + + printk("occanlib_open: Opening driver %s\n", name); + + fd = open(name, O_RDWR); + if ( fd >= 0 ){ + printk("occanlib_open: allocating memory %d\n",sizeof(*ret)); + ret = calloc(sizeof(*ret),1); + ret->fd = fd; + }else{ + if ( errno == ENODEV ){ + printk("occanlib_open: channel %s doesn't exist\n", name); + }else if ( errno == EBUSY ){ + printk("occanlib_open: channel already taken\n"); + }else if ( errno == ENOMEM ){ + printk("occanlib_open: unable to allocate default buffers\n"); + }else{ + printk("occanlib_open: errno: %d, ret: %d\n",errno,fd); + } + } + + return ret; +} + +void occanlib_close(occan_t chan){ + if ( !chan ) + return; + close(chan->fd); + free(chan); +} + +int occanlib_send_multiple(occan_t chan, CANMsg *msgs, int msgcnt){ + int ret, len, cnt; + if ( !chan || !msgs || (msgcnt<0) ) + return -1; + + if ( msgcnt == 0 ) + return 0; + + len = sizeof(CANMsg)*msgcnt; + + ret = write(chan->fd,msgs,len); + if ( ret < 0 ){ + /* something went wrong + * OR in non-blocking mode + * that would block + */ + if ( !chan->txblk && (errno == ETIMEDOUT) ){ + /* would block ==> 0 sent is ok */ + return 0; + } + + if ( errno == EBUSY ){ + /* CAN must be started before receiving */ + printk("occanlib_send_multiple: CAN is not started\n"); + return -2; + } + + if ( errno == EINVAL ){ + /* CAN must be started before receiving */ + printk("occanlib_send_multiple: length of buffer wrong\n"); + return -1; + } + + printk("occanlib_send_multiple: error in write, errno: %d, returned: %d\n",errno,ret); + return -1; + } + + if ( ret != len ){ + cnt = ret / sizeof(CANMsg); + return cnt; + } + /* sent all of them */ + return msgcnt; +} + +int occanlib_send(occan_t chan, CANMsg *msg){ + return occanlib_send_multiple(chan,msg,1); +} + +int occanlib_recv_multiple(occan_t chan, CANMsg *msgs, int msgcnt){ + int ret, len, cnt; + + if ( !chan || !msgs || (msgcnt<0) ) + return -1; + + if ( msgcnt == 0 ) + return 0; + + /* calc total length in bytes */ + len = sizeof(CANMsg)*msgcnt; + + errno = 0; + ret = read(chan->fd,msgs,len); + if ( ret < 0 ){ + /* something went wrong + * OR in non-blocking mode + * that would block + */ + if ( !chan->rxblk && (errno == ETIMEDOUT) ){ + return 0; + } + + if ( chan->rxblk && (errno == EIO) ){ + /* BUS OFF */ + printk("occanlib_recv_multiple: BUS OFF during blocking read\n"); + return -3; + } + + if ( errno == EBUSY ){ + /* CAN must be started before receiving */ + printk("occanlib_recv_multiple: CAN is not started\n"); + return -2; + } + + if ( errno == EINVAL ){ + /* CAN must be started before receiving */ + printk("occanlib_recv_multiple: length of input wrong\n"); + return -1; + } + + printk("occanlib_recv_multiple: error in read, errno: %d, returned: %d\n",errno,ret); + return -1; + } + + if ( ret != len ){ + cnt = ret / sizeof(CANMsg); + return cnt; + } + /* sent all of them */ + return msgcnt; +} + +int occanlib_recv(occan_t chan, CANMsg *msg){ + return occanlib_recv_multiple(chan,msg,1); +} + +int occanlib_set_speed(occan_t chan, unsigned int speed){ + int ret; + if ( !chan ) + return -1; + + ret = ioctl(chan->fd,OCCAN_IOC_SET_SPEED,speed); + if ( ret < 0 ){ + + if ( errno == EBUSY ){ + /* started */ + printk("occanlib_set_speed: started\n"); + return -2; + } + + if ( errno == EINVAL ){ + printk("occanlib_set_speed: invalid speed: %d\n",speed); + return -3; + } + + printk("occanlib_set_speed: failed, errno: %d, ret: %d\n",errno,ret); + return -1; + } + + return 0; +} + +int occanlib_set_speed_auto(occan_t chan){ + if ( !chan ) + return -1; + + printk("occanlib_set_speed_auto: not implemented\n"); + return -100; +} + +int occanlib_set_btrs(occan_t chan, unsigned char btr0, unsigned char btr1){ + int ret; + unsigned int btr0btr1; + + if ( !chan ) + return -1; + + btr0btr1 = (btr0<<8) | btr1; + + ret = ioctl(chan->fd,OCCAN_IOC_SET_BTRS,btr0btr1); + if ( ret < 0 ){ + if ( errno == EBUSY ){ + /* started */ + printk("occanlib_set_btrs: started\n"); + return -2; + } + + printk("occanlib_set_btrs: failed, errno: %d, ret: %d\n",errno,ret); + return -1; + } + + return 0; +} + +int occanlib_set_buf_length(occan_t chan, unsigned short txlen, unsigned short rxlen){ + int ret; + unsigned int lengths; + + if ( !chan ) + return -1; + + lengths = txlen<<16 | rxlen; + + ret = ioctl(chan->fd,OCCAN_IOC_SET_BUFLEN,lengths); + if ( ret < 0 ){ + if ( errno == EBUSY ){ + /* started */ + printk("occanlib_set_buf_length: started\n"); + return -2; + } + + if ( errno == ENOMEM ){ + /* started */ + printk("occanlib_set_buf_length: no memory for buffers: rxlen: %d, txlen: %d\n",rxlen,txlen); + return -3; + } + + printk("occanlib_set_buf_length: failed, errno: %d, ret: %d\n",errno,ret); + return -1; + } + + return 0; +} + +int occanlib_get_stats(occan_t chan, occan_stats *stats){ + int ret; + + if ( !chan || !stats ) + return -1; + + ret = ioctl(chan->fd,OCCAN_IOC_GET_STATS,stats); + if ( ret < 0 ){ + if ( errno == EINVAL ){ + printk("occanlib_get_stats: stats not valid: 0x%p\n", stats); + return -3; + } + + printk("occanlib_get_stats: failed, errno: %d, ret: %d\n",errno,ret); + return -1; + } + + return 0; +} + +int occanlib_set_filter(occan_t chan, struct occan_afilter *new_filter){ + int ret; + + if ( !chan || !new_filter ) + return -1; + + ret = ioctl(chan->fd,OCCAN_IOC_SET_FILTER,new_filter); + if ( ret < 0 ){ + + if ( errno == EBUSY ){ + /* started */ + printk("occanlib_set_filter: started\n"); + return -2; + } + + if ( errno == EINVAL ){ + /* started */ + printk("occanlib_set_filter: new_filter not valid: 0x%p\n", new_filter); + return -3; + } + + printk("occanlib_set_filter: failed, errno: %d, ret: %d\n",errno,ret); + return -1; + } + + return 0; +} + +int occanlib_set_blocking_mode(occan_t chan, int txblocking, int rxblocking){ + unsigned int arg = 0; + int ret; + + if ( !chan ) + return -1; + + if ( rxblocking ) + arg |= OCCAN_BLK_MODE_RX; + + if ( txblocking ) + arg |= OCCAN_BLK_MODE_TX; + + ret = ioctl(chan->fd,OCCAN_IOC_SET_BLK_MODE,arg); + if ( ret < 0 ){ + printk("occanlib_set_blocking_mode: failed, errno: %d, ret: %d\n",errno,ret); + return -1; + } + /* remember blocking state */ + chan->txblk = txblocking; + chan->rxblk = rxblocking; + return 0; +} + +int occanlib_get_status(occan_t chan, unsigned int *status){ + int ret; + + if ( !chan || !status ) + return -1; + + ret = ioctl(chan->fd,OCCAN_IOC_GET_STATUS,status); + if ( ret < 0 ){ + + if ( errno == EINVAL ){ + printk("occanlib_get_status: status is NULL pointer\n"); + return -1; + } + + printk("occanlib_get_status: failed, errno: %d, ret: %d\n",errno,ret); + return -1; + } + if ( *status == OCCAN_STATUS_RESET ){ + printk("OCCAN_STATUS_RESET\n"); + return -1; + } + + + return 0; +} + +int occanlib_start(occan_t chan){ + int ret; + + if ( !chan ) + return -1; + + ret = ioctl(chan->fd,OCCAN_IOC_START,0); + if ( ret < 0 ){ + + if ( errno == EBUSY ){ + printk("occanlib_start: already started\n"); + return -2; + } + + if ( errno == ENOMEM ){ + printk("occanlib_start: rx/tx not properly allocated, forgot to check" \ + "return status from failing occanlib_set_buf_length?\n"); + return -3; + } + + printk("occanlib_start: failed, errno: %d, ret: %d\n",errno,ret); + return -1; + } + return 0; +} + +int occanlib_stop(occan_t chan){ + int ret; + + if ( !chan ) + return -1; + + ret = ioctl(chan->fd,OCCAN_IOC_STOP,0); + if ( ret < 0 ){ + + if ( errno == EBUSY ){ + printk("occanlib_stop: not started\n"); + return -2; + } + + printk("occanlib_stop: failed, errno: %d, ret: %d\n",errno,ret); + return -1; + } + return 0; +} + + +void occanlib_stats_summary_print(occan_stats *stats){ + printk("Messages Received: %d\n",stats->rx_msgs); + printk("Messages Transmitted: %d\n",stats->tx_msgs); + printk("Error Warning Interrupts: %d\n",stats->err_warn); + printk("Data Overrun Interrupts: %d\n",stats->err_dovr); + printk("Error Passive Interrupts: %d\n",stats->err_errp); + printk("Arbitration Losses: %d\n",stats->err_arb); + printk("Bus error Interrupts: %d\n",stats->err_bus); + printk("Total number of interrupts: %d\n",stats->ints); +} + +/* Print out */ +void occanlib_stats_arblost_print(occan_stats *stats){ + int i; + printk("Arbitration loss frequency per bit:\n"); + for(i=0; i<32; i++){ + if ( i>=10 ) + printk("Arb bit%d: %d\n",i,stats->err_arb_bitnum[i]); + else + printk("Arb bit%d: %d\n",i,stats->err_arb_bitnum[i]); + } +} + +void occanlib_stats_buserr_print(occan_stats *stats){ + printk("Transmission errors: %d\n",stats->err_bus_rx); + printk("Reception errors: %d\n",stats->err_bus_tx); + + printk("Bit errors: %d\n",stats->err_bus_bit); + printk("Form erros: %d\n",stats->err_bus_form); + printk("Stuff errors: %d\n",stats->err_bus_stuff); + printk("Other errors: %d\n",stats->err_bus_other); + + printk("Stats where error occured in frame:\n"); + printk("ID 28..21: %d\n",stats->err_bus_segs[OCCAN_SEG_ID28]); + printk("ID 20..18: %d\n",stats->err_bus_segs[OCCAN_SEG_ID20]); + printk("ID 17..13: %d\n",stats->err_bus_segs[OCCAN_SEG_ID17]); + printk("ID 12..5: %d\n",stats->err_bus_segs[OCCAN_SEG_ID12]); + printk("ID 4..0: %d\n",stats->err_bus_segs[OCCAN_SEG_ID4]); + printk("Start of Frame: %d\n",stats->err_bus_segs[OCCAN_SEG_START]); + printk("Bit SRTR: %d\n",stats->err_bus_segs[OCCAN_SEG_SRTR]); + printk("Bit IDE: %d\n",stats->err_bus_segs[OCCAN_SEG_IDE]); + printk("Bit RTR: %d\n",stats->err_bus_segs[OCCAN_SEG_RTR]); + printk("Bit Resv0: %d\n",stats->err_bus_segs[OCCAN_SEG_RSV0]); + printk("Bit Resv1: %d\n",stats->err_bus_segs[OCCAN_SEG_RSV1]); + printk("Data Length: %d\n",stats->err_bus_segs[OCCAN_SEG_DLEN]); + printk("Data Field: %d\n",stats->err_bus_segs[OCCAN_SEG_DFIELD]); + printk("CRC Sequence: %d\n",stats->err_bus_segs[OCCAN_SEG_CRC_SEQ]); + printk("CRC Delimiter: %d\n",stats->err_bus_segs[OCCAN_SEG_CRC_DELIM]); + printk("Ack Slot: %d\n",stats->err_bus_segs[OCCAN_SEG_ACK_SLOT]); + printk("Ack Delimiter: %d\n",stats->err_bus_segs[OCCAN_SEG_ACK_DELIM]); + printk("End of Frame: %d\n",stats->err_bus_segs[OCCAN_SEG_EOF]); + printk("Intermission: %d\n",stats->err_bus_segs[OCCAN_SEG_INTERMISSION]); + printk("Active error flag: %d\n",stats->err_bus_segs[OCCAN_SEG_ACT_ERR]); + printk("Passive error flag: %d\n",stats->err_bus_segs[OCCAN_SEG_PASS_ERR]); + printk("Tolerate dominant bits: %d\n",stats->err_bus_segs[OCCAN_SEG_DOMINANT]); + printk("Error delimiter: %d\n",stats->err_bus_segs[OCCAN_SEG_EDELIM]); + printk("Oveload flag: %d\n",stats->err_bus_segs[OCCAN_SEG_OVERLOAD]); +} + +void occanlib_stats_print(occan_stats *stats){ + /* Print all stats */ + occanlib_stats_summary_print(stats); + occanlib_stats_buserr_print(stats); + occanlib_stats_arblost_print(stats); +} + + +/* CAN HELP DEBUG FUNCTIONS */ +char *msgstr_type[2] = {"STD", "EXT"}; +char *msgstr_rtr[2] = {"", " RTR"}; + +void print_msg(int i, CANMsg *msg){ + int j; + char data_str_buf[64]; + int ofs; + + if ( !msg ) + return; + + if ( i > 0 ){ + printk("MSG[%d]: %s%s length: %d, id: 0x%x\n",i,msgstr_type[(int)msg->extended],msgstr_rtr[(int)msg->rtr],msg->len,msg->id); + /* print data */ + if ( msg->len > 0 ){ + ofs = printk(data_str_buf,"MSGDATA[%d]: ",i); + for(j=0; jlen; j++){ + ofs+=printk(data_str_buf+ofs,"0x%02x ",msg->data[j]); + } + printk("%s ",data_str_buf); + ofs=0; + for(j=0; jlen; j++){ + if ( isalnum(msg->data[j]) ) + ofs+=printk(data_str_buf+ofs,"%c",msg->data[j]); + else + ofs+=printk(data_str_buf+ofs,"."); + } + printk("%s\n",data_str_buf); + } + }else{ + printk("MSG: %s%s length: %d, id: 0x%x\n",msgstr_type[(int)msg->extended],msgstr_rtr[(int)msg->rtr],msg->len,msg->id); + /* print data */ + if ( msg->len > 0 ){ + ofs = printk(data_str_buf,"MSGDATA: "); + for(j=0; jlen; j++){ + ofs+=printk(data_str_buf+ofs,"0x%02x ",msg->data[j]); + } + printk("%s ",data_str_buf); + ofs=0; + for(j=0; jlen; j++){ + if ( isalnum(msg->data[j]) ) + ofs+=printk(data_str_buf+ofs,"%c",msg->data[j]); + else + ofs+=printk(data_str_buf+ofs,"."); + } + printk("%s\n",data_str_buf); + } + } +} + + diff --git a/xky/libs/libiop/drivers/can/include/occan.h b/xky/libs/libiop/drivers/can/include/occan.h index 0c2a3049..4bd53d8d 100644 --- a/xky/libs/libiop/drivers/can/include/occan.h +++ b/xky/libs/libiop/drivers/can/include/occan.h @@ -57,18 +57,8 @@ extern "C" { #define OCCAN_NCORE_OFS 0x100 #define DEFAULT_CLKDIV 0x7 #define DEFAULT_EXTENDED_MODE 1 -#define DEFAULT_RX_FIFO_LEN 64 -#define DEFAULT_TX_FIFO_LEN 64 - -/* CAN MESSAGE */ -typedef struct { - char extended; /* 1= Extended Frame (29-bit id), 0= STD Frame (11-bit id) */ - char rtr; /* RTR - Remote Transmission Request */ - char sshot; /* single shot */ - unsigned char len; - unsigned char data[8]; - unsigned int id; -} CANMsg; +//#define DEFAULT_RX_FIFO_LEN 64 +//#define DEFAULT_TX_FIFO_LEN 64 /* PELICAN */ #ifdef OCCAN_BYTE_REGS @@ -234,6 +224,12 @@ typedef struct { } occan_stats; +/* TODO See if necessary */ +//typedef struct _occan_txrxdesc { +// int count; +// uint32_t * addr; +//} occan_txrxdesc; + typedef struct { /* hardware shortcuts */ pelican_regs *regs; @@ -258,10 +254,13 @@ typedef struct { unsigned char code[4]; unsigned char mask[4]; - /* IOP descriptors */ - unsigned int tx_ptr; - unsigned int rx_ptr; + occan_fifo *internal_msg_queue; + /* IOP descriptors */ +// occan_txrxdesc txdesc; +// occan_txrxdesc rxdesc; + /*unsigned int tx_ptr; /* Buffer pointerl + unsigned int rx_ptr;*/ /* IOP standard buffers */ iop_buffer_t *iop_buffers; uint8_t *iop_buffers_storage; diff --git a/xky/libs/libiop/drivers/can/include/occan_msg_queue.h b/xky/libs/libiop/drivers/can/include/occan_msg_queue.h new file mode 100644 index 00000000..dd629328 --- /dev/null +++ b/xky/libs/libiop/drivers/can/include/occan_msg_queue.h @@ -0,0 +1,30 @@ +#ifndef __OCCAN_MSG_QUEUE_H__ +#define __OCCAN_MSG_QUEUE_H__ + +/* CAN MESSAGE */ +typedef struct { + char extended; /* 1= Extended Frame (29-bit id), 0= STD Frame (11-bit id) */ + char rtr; /* RTR - Remote Transmission Request */ + char sshot; /* single shot */ + unsigned char len; + unsigned char data[8]; + unsigned int id; +} CANMsg; + +typedef struct { + int cnt; + int ovcnt; + int next; + int last; + static int max; + CANMsg *fifo; + +} occan_fifo; + +void occan_fifo_clear(occan_fifo *queue); +uint8_t occan_fifo_put(occan_fifo *queue, CANMsg *new, int force); +CANMsg * occan_fifo_get(occan_fifo *queue); +uint8_t occan_fifo_full(occan_fifo *queue); +uint8_t occan_fifo_empty(occan_fifo *queue); + +#endif /* __OCCAN_MSG_QUEUE_H__ */ diff --git a/xky/libs/libiop/drivers/can/occan.c b/xky/libs/libiop/drivers/can/occan.c index 0d9bd4bb..147cabe0 100644 --- a/xky/libs/libiop/drivers/can/occan.c +++ b/xky/libs/libiop/drivers/can/occan.c @@ -21,6 +21,7 @@ #include #include #include +#include /* RTEMS -> ERRNO decoding table @@ -205,15 +206,18 @@ static void pelican_open(occan_priv *priv){ static int pelican_start(occan_priv *priv){ unsigned char tmp; /* Start HW communication */ -l - if ( !priv->rxfifo || !priv->txfifo ) + + if ( !priv->tx_iop_buffer || !priv->rx_iop_buffer + || !*(priv->tx_iop_buffer) || !*(priv->rx_iop_buffer)) return -1; /* In case we were started before and stopped we * should empty the TX fifo or try to resend those * messages. We make it simple... */ - occan_fifo_clr(priv->txfifo); + // TODO Clean buffers +// occan_fifo_clr(priv->txfifo); + occan_fifo_clear(priv->internal_msg_queue); /* Clear status bits */ priv->status = 0; @@ -848,20 +852,25 @@ uint32_t occan_open(iop_device_driver_t *iop_dev, void *arg){ rtems_semaphore_release(can->devsem); /* allocate fifos */ - can->rxfifo = occan_fifo_create(DEFAULT_RX_FIFO_LEN); - if ( !can->rxfifo ){ +// can->rxfifo = occan_fifo_create(DEFAULT_RX_FIFO_LEN); + /* FIFOS are not allocated here any longer. This is a iop_physical + * device.c job */ + /* check buffers allocation */ + if ( !can->rx_iop_buffer && !(*(can->rx_iop_buffer))){ can->open = 0; return RTEMS_NO_MEMORY; /* ENOMEM */ } - can->txfifo = occan_fifo_create(DEFAULT_TX_FIFO_LEN); - if ( !can->txfifo ){ - occan_fifo_free(can->rxfifo); - can->rxfifo= NULL; +// can->txfifo = occan_fifo_create(DEFAULT_TX_FIFO_LEN); + /* Checking buffers allocation */ + if ( !can->tx_iop_buffer && !(*(can->tx_iop_buffer))){ +// occan_fifo_free(can->rxfifo); +// can->rxfifo= NULL; can->open = 0; return RTEMS_NO_MEMORY; /* ENOMEM */ } + /* Buffers allocation are good */ iop_debug("OCCAN: Opening success\n\r"); can->started = 0; @@ -899,8 +908,8 @@ uint32_t occan_close(iop_device_driver_t *iop_dev, void *arg){ // occan_fifo_free(can->rxfifo); // occan_fifo_free(can->txfifo); - can->rxfifo = NULL; - can->txfifo = NULL; +// can->rxfifo = NULL; +// can->txfifo = NULL; return RTEMS_SUCCESSFUL; } @@ -909,12 +918,14 @@ uint32_t occan_read(iop_device_driver_t *iop_dev, void *arg){ iop_can_device_t *device = (iop_can_device_t *) iop_dev; occan_priv *can = (occan_priv *) device->dev.driver; -// rtems_libio_device_t *device=(rtems_libio_device_t *) arg; - iop_wrapper_t *wrapper = (iop_wrapper_t *) arg; CANMsg *dstmsg, *srcmsg; rtems_interrupt_level oldLevel; int left; + /* get IOP buffer */ + iop_wrapper_t *wrapper = (iop_wrapper_t *) arg; + iop_buffer_t *iop_buffer = wrapper->buffer; + if ( !can->started ){ iop_debug("OCCAN: cannot read when not started\n\r"); return RTEMS_RESOURCE_IN_USE; /* -EBUSY*/ @@ -927,9 +938,13 @@ uint32_t occan_read(iop_device_driver_t *iop_dev, void *arg){ return RTEMS_INVALID_NAME; /* -EINVAL */ } + /* Check if buffer was well allocated on the upper level */ + if(iop_buffer->v_addr == NULL) { + return RTEMS_INVALID_NAME; + } + /* get pointer to start where to put CAN messages */ dstmsg = (CANMsg *)wrapper->buffer->v_addr; -// dstmsg = (CANMsg *) wrapper->buffer->v_addr; if ( !dstmsg ){ iop_debug("OCCAN: input buffer is NULL\n\r"); @@ -950,6 +965,8 @@ uint32_t occan_read(iop_device_driver_t *iop_dev, void *arg){ } srcmsg = occan_fifo_claim_get(can->rxfifo); +// srcmsg = obtain_wrapper(&pdev->sendqueue); + if ( !srcmsg ){ /* no more messages in reception fifo. * Wait for incoming packets only if in @@ -999,7 +1016,7 @@ uint32_t occan_read(iop_device_driver_t *iop_dev, void *arg){ /* Return borrowed message, RX interrupt can use it again */ - occan_fifo_get(can->rxfifo); + occan_fifo_get(can->internal_msg_queue); /* turn on interrupts again */ rtems_interrupt_enable(oldLevel); @@ -1063,7 +1080,7 @@ uint32_t occan_write(iop_device_driver_t *iop_dev, void *arg){ * try to send first message by putting it directly * into the HW TX fifo. */ - if ( occan_fifo_empty(can->txfifo) ){ + if ( occan_fifo_empty(can->tx_iop_buffer[can->txdesc->addr] ) ){ /*pelican_regs_print(cans[minor+1].regs);*/ if ( !pelican_send(can,msg) ) { /* First message put directly into HW TX fifo @@ -1288,6 +1305,7 @@ uint32_t occan_ioctl(iop_can_device_t *device, void *arg){ if ( can->started ) return RTEMS_RESOURCE_IN_USE; /* EBUSY */ + /* TODO see about the using the filter */ // afilter = (struct occan_afilter *)ioarg->buffer; // // if ( !afilter ) @@ -1338,248 +1356,253 @@ uint32_t occan_ioctl(iop_can_device_t *device, void *arg){ return RTEMS_SUCCESSFUL; } // -//static void occan_interrupt(occan_priv *can){ -// unsigned char iflags; -// pelican_regs *regs = can->regs; +static void occan_interrupt(occan_priv *can){ + unsigned char iflags; + pelican_regs *regs = can->regs; // CANMsg *msg; -// int signal_rx=0, signal_tx=0; -// unsigned char tmp, errcode, arbcode; -// int tx_error_cnt,rx_error_cnt; -// -// can->stats.ints++; -// -// while ( (iflags = READ_REG(&can->regs->intflags)) != 0 ){ -// /* still interrupts to handle */ -// -// if ( iflags & PELICAN_IF_RX ){ -// /* the rx fifo is not empty -// * put 1 message into rxfifo for later use -// */ -// -// /* get empty (or make room) message */ + CANMsg msg; /* Temporary vairable to hold the message */ + int signal_rx=0, signal_tx=0; + unsigned char tmp, errcode, arbcode; + int tx_error_cnt,rx_error_cnt; + + can->stats.ints++; + + while ( (iflags = READ_REG(&can->regs->intflags)) != 0 ){ + /* still interrupts to handle */ + + if ( iflags & PELICAN_IF_RX ){ + /* the rx fifo is not empty + * put 1 message into rxfifo for later use + */ + + /* get empty (or make room) message */ // msg = occan_fifo_put_claim(can->rxfifo,1); -// tmp = READ_REG(®s->rx_fi_xff); -// msg->extended = tmp >> 7; -// msg->rtr = (tmp >> 6) & 1; -// msg->len = tmp = tmp & 0x0f; -// -// if ( msg->extended ){ -// /* extended message */ -// msg->id = READ_REG(®s->msg.rx_eff.id[0])<<(5+8+8) | -// READ_REG(®s->msg.rx_eff.id[1])<<(5+8) | -// READ_REG(®s->msg.rx_eff.id[2])<<5 | -// READ_REG(®s->msg.rx_eff.id[3])>>3; -// while(tmp--){ -// msg->data[tmp] = READ_REG(®s->msg.rx_eff.data[tmp]); -// } -// /* -// msg->data[0] = READ_REG(®s->msg.rx_eff.data[0]); -// msg->data[1] = READ_REG(®s->msg.rx_eff.data[1]); -// msg->data[2] = READ_REG(®s->msg.rx_eff.data[2]); -// msg->data[3] = READ_REG(®s->msg.rx_eff.data[3]); -// msg->data[4] = READ_REG(®s->msg.rx_eff.data[4]); -// msg->data[5] = READ_REG(®s->msg.rx_eff.data[5]); -// msg->data[6] = READ_REG(®s->msg.rx_eff.data[6]); -// msg->data[7] = READ_REG(®s->msg.rx_eff.data[7]); -// */ -// }else{ -// /* standard message */ -// msg->id = READ_REG(®s->msg.rx_sff.id[0])<<3 | -// READ_REG(®s->msg.rx_sff.id[1])>>5; -// -// while(tmp--){ -// msg->data[tmp] = READ_REG(®s->msg.rx_sff.data[tmp]); -// } -// /* -// msg->data[0] = READ_REG(®s->msg.rx_sff.data[0]); -// msg->data[1] = READ_REG(®s->msg.rx_sff.data[1]); -// msg->data[2] = READ_REG(®s->msg.rx_sff.data[2]); -// msg->data[3] = READ_REG(®s->msg.rx_sff.data[3]); -// msg->data[4] = READ_REG(®s->msg.rx_sff.data[4]); -// msg->data[5] = READ_REG(®s->msg.rx_sff.data[5]); -// msg->data[6] = READ_REG(®s->msg.rx_sff.data[6]); -// msg->data[7] = READ_REG(®s->msg.rx_sff.data[7]); -// */ -// } -// -// /* Re-Enable RX buffer for a new message */ -// regs->cmd = PELICAN_CMD_RELRXBUF; -// -// /* make message available to the user */ + tmp = READ_REG(®s->rx_fi_xff); + msg.extended = tmp >> 7; + msg.rtr = (tmp >> 6) & 1; + msg.len = tmp = tmp & 0x0f; + + if ( msg.extended ){ + /* extended message */ + msg.id = READ_REG(®s->msg.rx_eff.id[0])<<(5+8+8) | + READ_REG(®s->msg.rx_eff.id[1])<<(5+8) | + READ_REG(®s->msg.rx_eff.id[2])<<5 | + READ_REG(®s->msg.rx_eff.id[3])>>3; + while(tmp--){ + msg.data[tmp] = READ_REG(®s->msg.rx_eff.data[tmp]); + } + /* + msg->data[0] = READ_REG(®s->msg.rx_eff.data[0]); + msg->data[1] = READ_REG(®s->msg.rx_eff.data[1]); + msg->data[2] = READ_REG(®s->msg.rx_eff.data[2]); + msg->data[3] = READ_REG(®s->msg.rx_eff.data[3]); + msg->data[4] = READ_REG(®s->msg.rx_eff.data[4]); + msg->data[5] = READ_REG(®s->msg.rx_eff.data[5]); + msg->data[6] = READ_REG(®s->msg.rx_eff.data[6]); + msg->data[7] = READ_REG(®s->msg.rx_eff.data[7]); + */ + }else{ + /* standard message */ + msg.id = READ_REG(®s->msg.rx_sff.id[0])<<3 | + READ_REG(®s->msg.rx_sff.id[1])>>5; + + while(tmp--){ + msg.data[tmp] = READ_REG(®s->msg.rx_sff.data[tmp]); + } + /* + msg->data[0] = READ_REG(®s->msg.rx_sff.data[0]); + msg->data[1] = READ_REG(®s->msg.rx_sff.data[1]); + msg->data[2] = READ_REG(®s->msg.rx_sff.data[2]); + msg->data[3] = READ_REG(®s->msg.rx_sff.data[3]); + msg->data[4] = READ_REG(®s->msg.rx_sff.data[4]); + msg->data[5] = READ_REG(®s->msg.rx_sff.data[5]); + msg->data[6] = READ_REG(®s->msg.rx_sff.data[6]); + msg->data[7] = READ_REG(®s->msg.rx_sff.data[7]); + */ + } + + /* Re-Enable RX buffer for a new message */ + regs->cmd = PELICAN_CMD_RELRXBUF; + + /* make message available to the user */ // occan_fifo_put(can->rxfifo); -// -// /* bump stat counters */ -// can->stats.rx_msgs++; -// -// /* signal the semaphore only once */ -// signal_rx = 1; -// } -// -// if ( iflags & PELICAN_IF_TX ){ -// /* there is room in tx fifo of HW */ -// -// if ( !occan_fifo_empty(can->txfifo) ){ -// /* send 1 more messages */ -// msg = occan_fifo_claim_get(can->txfifo); -// -// if ( pelican_send(can,msg) ){ -// /* ERROR! We got an TX interrupt telling us -// * tx fifo is empty, yet it is not. -// * -// * Complain about this max 10 times -// */ -// if ( can->stats.tx_buf_error < 10 ){ -// iop_debug("OCCAN: got TX interrupt but TX fifo in not empty (%d)\n\r",can->stats.tx_buf_error); -// } -// can->status |= OCCAN_STATUS_QUEUE_ERROR; -// can->stats.tx_buf_error++; -// } -// -// /* free software-fifo space taken by sent message */ -// occan_fifo_get(can->txfifo); -// -// /* bump stat counters */ -// can->stats.tx_msgs++; -// -// /* wake any sleeping thread waiting for "fifo not full" */ -// signal_tx = 1; -// } -// } -// -// if ( iflags & PELICAN_IF_ERRW ){ -// tx_error_cnt = READ_REG(®s->tx_err_cnt); -// rx_error_cnt = READ_REG(®s->rx_err_cnt); -// -// /* 1. if bus off tx error counter = 127 */ -// if ( (tx_error_cnt > 96) || (rx_error_cnt > 96) ){ -// /* in Error Active Warning area or BUS OFF */ -// can->status |= OCCAN_STATUS_WARN; -// -// /* check reset bit for reset mode */ -// if ( READ_REG(®s->mode) & PELICAN_MOD_RESET ){ -// /* in reset mode ==> bus off */ -// can->status |= OCCAN_STATUS_ERR_BUSOFF | OCCAN_STATUS_RESET; -// -// /***** pelican_stop(can) ****** -// * turn off interrupts -// * enter reset mode (HW already done that for us) -// */ -// regs->inten = 0; -// -// /* Indicate that we are not started any more. -// * This will make write/read return with EBUSY -// * on read/write attempts. -// * -// * User must issue a ioctl(START) to get going again. -// */ -// can->started = 0; -// -// /* signal any waiting read/write threads, so that they -// * can handle the bus error. -// */ -// signal_rx = 1; -// signal_tx = 1; -// -// /* ingnore any old pending interrupt */ -// break; -// } -// -// }else{ -// /* not in Upper Error Active area any more */ -// can->status &= ~(OCCAN_STATUS_WARN); -// } -// can->stats.err_warn++; -// } -// -// if ( iflags & PELICAN_IF_DOVR){ -// can->status |= OCCAN_STATUS_OVERRUN; -// can->stats.err_dovr++; -// iop_debug("OCCAN_INT: DOVR\n\r"); -// } -// -// if ( iflags & PELICAN_IF_ERRP){ -// /* Let the error counters decide what kind of -// * interrupt it was. In/Out of EPassive area. -// */ -// tx_error_cnt = READ_REG(®s->tx_err_cnt); -// rx_error_cnt = READ_REG(®s->rx_err_cnt); -// -// if ( (tx_error_cnt > 127) || (rx_error_cnt > 127) ){ -// can->status |= OCCAN_STATUS_ERR_PASSIVE; -// }else{ -// can->status &= ~(OCCAN_STATUS_ERR_PASSIVE); -// } -// -// /* increase Error Passive In/out interrupt counter */ -// can->stats.err_errp++; -// } -// -// if ( iflags & PELICAN_IF_ARB){ -// arbcode = READ_REG(®s->arbcode); -// can->stats.err_arb_bitnum[arbcode & PELICAN_ARB_BITS]++; -// can->stats.err_arb++; -// iop_debug("OCCAN_INT: ARB (0x%x)\n\r",arbcode & PELICAN_ARB_BITS); -// } -// -// if ( iflags & PELICAN_IF_BUS){ -// /* Some kind of BUS error, only used for -// * statistics. Error Register is decoded -// * and put into can->stats. -// */ -// errcode = READ_REG(®s->errcode); -// switch( errcode & PELICAN_ECC_CODE ){ -// case PELICAN_ECC_CODE_BIT: -// can->stats.err_bus_bit++; -// break; -// case PELICAN_ECC_CODE_FORM: -// can->stats.err_bus_form++; -// break; -// case PELICAN_ECC_CODE_STUFF: -// can->stats.err_bus_stuff++; -// break; -// case PELICAN_ECC_CODE_OTHER: -// can->stats.err_bus_other++; -// break; -// } -// -// /* Get Direction (TX/RX) */ -// if ( errcode & PELICAN_ECC_DIR ){ -// can->stats.err_bus_rx++; -// }else{ -// can->stats.err_bus_tx++; -// } -// -// /* Get Segment in frame that went wrong */ -// can->stats.err_bus_segs[errcode & PELICAN_ECC_SEG]++; -// -// /* total number of bus errors */ -// can->stats.err_bus++; -// } -// } -// -// /* signal Binary semaphore, messages available! */ -// if ( signal_rx ){ -// rtems_semaphore_release(can->rxsem); -// } -// -// if ( signal_tx ){ -// rtems_semaphore_release(can->txsem); -// } -//} -// -////#ifdef OCCAN_DEFINE_INTHANDLER -//static void occan_interrupt_handler(rtems_vector_number v){ -// int minor; -// -// /* convert to */ -// for(minor = 0; minor < can_cores; minor++) { -// if ( v == (cans[minor].irq+0x10) ) { -// occan_interrupt(&cans[minor]); -// return; -// } -// } -//} -//#endif + + /* Queue the received message to make it available + * to the user */ + occan_fifo_put(can->internal_msg_queue, &msg,1); + + /* bump stat counters */ + can->stats.rx_msgs++; + + /* signal the semaphore only once */ + signal_rx = 1; + } + + if ( iflags & PELICAN_IF_TX ){ + /* there is room in tx fifo of HW */ + + if ( !occan_fifo_empty(can->txfifo) ){ + /* send 1 more messages */ + msg = occan_fifo_claim_get(can->txfifo); + + if ( pelican_send(can,msg) ){ + /* ERROR! We got an TX interrupt telling us + * tx fifo is empty, yet it is not. + * + * Complain about this max 10 times + */ + if ( can->stats.tx_buf_error < 10 ){ + iop_debug("OCCAN: got TX interrupt but TX fifo in not empty (%d)\n\r",can->stats.tx_buf_error); + } + can->status |= OCCAN_STATUS_QUEUE_ERROR; + can->stats.tx_buf_error++; + } + + /* free software-fifo space taken by sent message */ + occan_fifo_get(can->txfifo); + + /* bump stat counters */ + can->stats.tx_msgs++; + + /* wake any sleeping thread waiting for "fifo not full" */ + signal_tx = 1; + } + } + + if ( iflags & PELICAN_IF_ERRW ){ + tx_error_cnt = READ_REG(®s->tx_err_cnt); + rx_error_cnt = READ_REG(®s->rx_err_cnt); + + /* 1. if bus off tx error counter = 127 */ + if ( (tx_error_cnt > 96) || (rx_error_cnt > 96) ){ + /* in Error Active Warning area or BUS OFF */ + can->status |= OCCAN_STATUS_WARN; + + /* check reset bit for reset mode */ + if ( READ_REG(®s->mode) & PELICAN_MOD_RESET ){ + /* in reset mode ==> bus off */ + can->status |= OCCAN_STATUS_ERR_BUSOFF | OCCAN_STATUS_RESET; + + /***** pelican_stop(can) ****** + * turn off interrupts + * enter reset mode (HW already done that for us) + */ + regs->inten = 0; + + /* Indicate that we are not started any more. + * This will make write/read return with EBUSY + * on read/write attempts. + * + * User must issue a ioctl(START) to get going again. + */ + can->started = 0; + + /* signal any waiting read/write threads, so that they + * can handle the bus error. + */ + signal_rx = 1; + signal_tx = 1; + + /* ingnore any old pending interrupt */ + break; + } + + }else{ + /* not in Upper Error Active area any more */ + can->status &= ~(OCCAN_STATUS_WARN); + } + can->stats.err_warn++; + } + + if ( iflags & PELICAN_IF_DOVR){ + can->status |= OCCAN_STATUS_OVERRUN; + can->stats.err_dovr++; + iop_debug("OCCAN_INT: DOVR\n\r"); + } + + if ( iflags & PELICAN_IF_ERRP){ + /* Let the error counters decide what kind of + * interrupt it was. In/Out of EPassive area. + */ + tx_error_cnt = READ_REG(®s->tx_err_cnt); + rx_error_cnt = READ_REG(®s->rx_err_cnt); + + if ( (tx_error_cnt > 127) || (rx_error_cnt > 127) ){ + can->status |= OCCAN_STATUS_ERR_PASSIVE; + }else{ + can->status &= ~(OCCAN_STATUS_ERR_PASSIVE); + } + + /* increase Error Passive In/out interrupt counter */ + can->stats.err_errp++; + } + + if ( iflags & PELICAN_IF_ARB){ + arbcode = READ_REG(®s->arbcode); + can->stats.err_arb_bitnum[arbcode & PELICAN_ARB_BITS]++; + can->stats.err_arb++; + iop_debug("OCCAN_INT: ARB (0x%x)\n\r",arbcode & PELICAN_ARB_BITS); + } + + if ( iflags & PELICAN_IF_BUS){ + /* Some kind of BUS error, only used for + * statistics. Error Register is decoded + * and put into can->stats. + */ + errcode = READ_REG(®s->errcode); + switch( errcode & PELICAN_ECC_CODE ){ + case PELICAN_ECC_CODE_BIT: + can->stats.err_bus_bit++; + break; + case PELICAN_ECC_CODE_FORM: + can->stats.err_bus_form++; + break; + case PELICAN_ECC_CODE_STUFF: + can->stats.err_bus_stuff++; + break; + case PELICAN_ECC_CODE_OTHER: + can->stats.err_bus_other++; + break; + } + + /* Get Direction (TX/RX) */ + if ( errcode & PELICAN_ECC_DIR ){ + can->stats.err_bus_rx++; + }else{ + can->stats.err_bus_tx++; + } + + /* Get Segment in frame that went wrong */ + can->stats.err_bus_segs[errcode & PELICAN_ECC_SEG]++; + + /* total number of bus errors */ + can->stats.err_bus++; + } + } + + /* signal Binary semaphore, messages available! */ + if ( signal_rx ){ + rtems_semaphore_release(can->rxsem); + } + + if ( signal_tx ){ + rtems_semaphore_release(can->txsem); + } +} + +//#ifdef OCCAN_DEFINE_INTHANDLER +static void occan_interrupt_handler(rtems_vector_number v){ + int minor; + + /* convert to */ + for(minor = 0; minor < can_cores; minor++) { + if ( v == (cans[minor].irq+0x10) ) { + occan_interrupt(&cans[minor]); + return; + } + } +} +#endif #define OCCAN_DRIVER_TABLE_ENTRY { occan_initialize, occan_open, occan_close, occan_read, occan_write, occan_ioctl } diff --git a/xky/libs/libiop/drivers/can/occan_msg_queue.c b/xky/libs/libiop/drivers/can/occan_msg_queue.c new file mode 100644 index 00000000..0df617d3 --- /dev/null +++ b/xky/libs/libiop/drivers/can/occan_msg_queue.c @@ -0,0 +1,64 @@ +#include + +/* Clear all entries on the fifo and + * control data */ + +void occan_fifo_clear(occan_fifo *queue ){ + int i; + + for(i = 0; i < queue->max; i++){ + queue->fifo[i].extended = 0; + queue->fifo[i].rtr = 0; + queue->fifo[i].id = 0; + queue->fifo[i].len = 0; + queue->fifo[i].sshot = 0; + } + queue->cnt = 0; + queue->ovcnt = 0; + queue->last = 0; + queue->next = 0; +} + +/* TODO force put option for when the queue is full */ +uint8_t occan_fifo_put(occan_fifo *queue, CANMsg *new, int force){ + if(queue->max -queue->cnt < 1){ + /* queue is full */ + return 0; + } + + queue->fifo[queue->last] = new; + queue->cnt++; + + if(queue->last + 1 >= queue->max){ + queue->last = 0; + }else{ + queue->last++; + } +} + +CANMsg *occan_fifo_get(occan_fifo *queue){ + if(queue->cnt == 0 ){ + /* Queue is empty */ + return NULL; + } + int tmp = queue->next; + queue->cnt--; + if(queue->next >= queue->max){ + queue->next = 0; + } + return queue->fifo[tmp]; +} + +uint8_t occan_fifo_full(occan_fifo *queue) { + if(queue->max == queue->cnt){ + return 1; + } + return 0; +} + +uint8_t occan_fifo_empty(occan_fifo *queue){ + if(queue->cnt == 0){ + return 1; + } + return 0; +} diff --git a/xky/libs/libiop/include/can_support.h b/xky/libs/libiop/include/can_support.h index 71a6401d..17936a15 100644 --- a/xky/libs/libiop/include/can_support.h +++ b/xky/libs/libiop/include/can_support.h @@ -9,6 +9,7 @@ #include #include #include +#include //typedef struct { // uint16_t identifier; @@ -30,6 +31,7 @@ typedef struct { uint32_t count; uint32_t flags; uint32_t bytes_moved; + } iop_can_device_t; /* Not used right now TODO take it or leave it*/ -- GitLab