diff options
| author | BernardXiong <[email protected]> | 2015-05-18 18:16:59 +0800 |
|---|---|---|
| committer | BernardXiong <[email protected]> | 2015-05-18 18:16:59 +0800 |
| commit | 7d73fb8bdbca622142e9802dc7a9a495563638f0 (patch) | |
| tree | b9e96572c375829c2029ec6605e835b76569a5ad /components | |
| parent | 8de629c0b0408e2bd45f985cbca58bb99cf2f1bf (diff) | |
| parent | 0d1ee90f2815bded610dd96d9a07701b4f83a797 (diff) | |
Merge remote-tracking branch 'upstream/master'
Diffstat (limited to 'components')
| -rw-r--r-- | components/drivers/can/SConscript | 8 | ||||
| -rw-r--r-- | components/drivers/can/can.c | 907 | ||||
| -rw-r--r-- | components/drivers/can/readme-zh.txt | 132 | ||||
| -rw-r--r-- | components/drivers/include/drivers/can.h | 293 | ||||
| -rw-r--r-- | components/drivers/include/rtdevice.h | 4 | ||||
| -rw-r--r-- | components/drivers/spi/spi_flash_w25qxx.c | 7 | ||||
| -rw-r--r-- | components/net/lwip/apps/ftpd.c | 264 | ||||
| -rw-r--r-- | components/net/lwip_dhcpd/dhcp_server.c | 21 |
8 files changed, 1594 insertions, 42 deletions
diff --git a/components/drivers/can/SConscript b/components/drivers/can/SConscript new file mode 100644 index 0000000000..84ae2a10da --- /dev/null +++ b/components/drivers/can/SConscript @@ -0,0 +1,8 @@ +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') +CPPPATH = [cwd + '/../include'] +group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_CAN'], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/drivers/can/can.c b/components/drivers/can/can.c new file mode 100644 index 0000000000..8ac3029533 --- /dev/null +++ b/components/drivers/can/can.c @@ -0,0 +1,907 @@ +/* + * File : can.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2015, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2015-05-14 [email protected] first version + */ +#include <rthw.h> +#include <rtthread.h> +#include <rtdevice.h> + +static rt_err_t rt_can_init(struct rt_device *dev) +{ + rt_err_t result = RT_EOK; + struct rt_can_device *can; + + RT_ASSERT(dev != RT_NULL); + can = (struct rt_can_device *)dev; + + /* initialize rx/tx */ + can->can_rx = RT_NULL; + can->can_tx = RT_NULL; + + /* apply configuration */ + if (can->ops->configure) + result = can->ops->configure(can, &can->config); + + return result; +} +/* + * can interrupt routines + */ +rt_inline int _can_int_rx(struct rt_can_device *can, struct rt_can_msg *data, int msgs) +{ + int size; + struct rt_can_rx_fifo* rx_fifo; + + RT_ASSERT(can != RT_NULL); + size = msgs; + + rx_fifo = (struct rt_can_rx_fifo*) can->can_rx; + RT_ASSERT(rx_fifo != RT_NULL); + + /* read from software FIFO */ + while (msgs) + { + rt_base_t level; + struct rt_can_msg_list *listmsg=RT_NULL; + /* disable interrupt */ + level = rt_hw_interrupt_disable(); +#ifdef RT_CAN_USING_HDR + rt_int32_t hdr = data->hdr; + if (hdr >=0 && can->hdr && hdr < can->config.maxhdr && !rt_list_isempty(&can->hdr[hdr].list)) + { + listmsg=rt_list_entry(can->hdr[hdr].list.next, struct rt_can_msg_list, hdrlist); + rt_list_remove(&listmsg->list); + rt_list_remove(&listmsg->hdrlist); + if(can->hdr[hdr].msgs) { + can->hdr[hdr].msgs--; + } + listmsg->owner = RT_NULL; + } else +#endif /*RT_CAN_USING_HDR*/ + if (!rt_list_isempty(&rx_fifo->uselist)) + { + listmsg=rt_list_entry(rx_fifo->uselist.next, struct rt_can_msg_list, list); + rt_list_remove(&listmsg->list); +#ifdef RT_CAN_USING_HDR + rt_list_remove(&listmsg->hdrlist); + if(listmsg->owner != RT_NULL && listmsg->owner->msgs) { + listmsg->owner->msgs--; + } + listmsg->owner = RT_NULL; +#endif + } + else + { + /* no data, enable interrupt and break out */ + rt_hw_interrupt_enable(level); + break; + } + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + if(listmsg!=RT_NULL) + { + rt_memcpy(data,&listmsg->data,sizeof(struct rt_can_msg)); + level = rt_hw_interrupt_disable(); + rt_list_insert_before(&rx_fifo->freelist,&listmsg->list); + rx_fifo->freenumbers++; + RT_ASSERT(rx_fifo->freenumbers <= can->config.msgboxsz); + rt_hw_interrupt_enable(level); + listmsg = RT_NULL; + } + data ++; msgs -= sizeof(struct rt_can_msg); + } + + return (size - msgs); +} + +rt_inline int _can_int_tx(struct rt_can_device *can, const struct rt_can_msg *data, int msgs) +{ + int size; + struct rt_can_tx_fifo *tx_fifo; + + RT_ASSERT(can != RT_NULL); + + size = msgs; + tx_fifo = (struct rt_can_tx_fifo*) can->can_tx; + RT_ASSERT(tx_fifo != RT_NULL); + + while (msgs) + { + rt_base_t level; + rt_uint32_t no; + struct rt_can_sndbxinx_list* tx_tosnd = RT_NULL; + level = rt_hw_interrupt_disable(); + if(!rt_list_isempty(&tx_fifo->freelist)) + { + tx_tosnd = rt_list_entry(tx_fifo->freelist.next, struct rt_can_sndbxinx_list, list); + RT_ASSERT(tx_tosnd != RT_NULL); + rt_list_remove(&tx_tosnd->list); + } else { + rt_hw_interrupt_enable(level); + rt_completion_wait(&(tx_fifo->completion), RT_WAITING_FOREVER); + continue; + } + rt_hw_interrupt_enable(level); + no=((rt_uint32_t)tx_tosnd-(rt_uint32_t)tx_fifo->buffer)/sizeof(struct rt_can_sndbxinx_list); + tx_tosnd->result = RT_CAN__SND_RESUTL_WAIT; + if (can->ops->sendmsg(can, data ,no)) + { + level = rt_hw_interrupt_disable(); + rt_list_insert_after(&tx_fifo->freelist,&tx_tosnd->list); + rt_hw_interrupt_enable(level); + continue; + } + can->status.sndchange = 1; + rt_completion_wait(&(tx_tosnd->completion), RT_WAITING_FOREVER); + level = rt_hw_interrupt_disable(); + rt_uint32_t result = tx_tosnd->result; + if(!rt_list_isempty(&tx_tosnd->list)) { + rt_list_remove(&tx_tosnd->list); + } + rt_list_insert_before(&tx_fifo->freelist,&tx_tosnd->list); + rt_hw_interrupt_enable(level); + + if(result == RT_CAN__SND_RESUTL_OK) + { + level = rt_hw_interrupt_disable(); + can->status.sndpkg++; + rt_hw_interrupt_enable(level); + data ++; msgs -= sizeof(struct rt_can_msg); + if(!msgs) break; + } + else + { + level = rt_hw_interrupt_disable(); + can->status.dropedsndpkg++; + rt_hw_interrupt_enable(level); + break; + } + + level = rt_hw_interrupt_disable(); + if(rt_list_isempty(&tx_fifo->freelist)) + { + rt_hw_interrupt_enable(level); + rt_completion_done(&(tx_fifo->completion)); + } + else + { + rt_hw_interrupt_enable(level); + } + } + + return (size - msgs); +} +rt_inline int _can_int_tx_priv(struct rt_can_device *can, const struct rt_can_msg *data, int msgs) +{ + int size; + struct rt_can_tx_fifo *tx_fifo; + + RT_ASSERT(can != RT_NULL); + + size = msgs; + tx_fifo = (struct rt_can_tx_fifo*) can->can_tx; + RT_ASSERT(tx_fifo != RT_NULL); + + rt_base_t level; + rt_uint32_t no; + rt_uint32_t result; + while (msgs) + { + no = data->priv; + if(no >= can->config.sndboxnumber) { + break; + } + level = rt_hw_interrupt_disable(); + if((tx_fifo->buffer[no].result != RT_CAN__SND_RESUTL_OK)) { + rt_hw_interrupt_enable(level); + rt_completion_wait(&(tx_fifo->buffer[no].completion), RT_WAITING_FOREVER); + continue; + } + tx_fifo->buffer[no].result = RT_CAN__SND_RESUTL_WAIT; + rt_hw_interrupt_enable(level); + if (can->ops->sendmsg(can, data ,no) != RT_EOK) + { + continue; + } + can->status.sndchange = 1; + rt_completion_wait(&(tx_fifo->buffer[no].completion), RT_WAITING_FOREVER); + result = tx_fifo->buffer[no].result; + if(result == RT_CAN__SND_RESUTL_OK) + { + level = rt_hw_interrupt_disable(); + can->status.sndpkg++; + rt_hw_interrupt_enable(level); + data ++; msgs -= sizeof(struct rt_can_msg); + if(!msgs) break; + } + else + { + level = rt_hw_interrupt_disable(); + can->status.dropedsndpkg++; + rt_hw_interrupt_enable(level); + break; + } + } + + return (size - msgs); +} +static rt_err_t rt_can_open(struct rt_device *dev, rt_uint16_t oflag) +{ + struct rt_can_device *can; + + RT_ASSERT(dev != RT_NULL); + can = (struct rt_can_device *)dev; + + /* get open flags */ + dev->open_flag = oflag & 0xff; + rt_enter_critical(); + if (can->can_rx == RT_NULL) + { + if (oflag & RT_DEVICE_FLAG_INT_RX) + { + struct rt_can_rx_fifo* rx_fifo; + + rx_fifo = (struct rt_can_rx_fifo*) rt_malloc (sizeof(struct rt_can_rx_fifo) + + can->config.msgboxsz * sizeof(struct rt_can_msg_list)); + RT_ASSERT(rx_fifo != RT_NULL); + rx_fifo->buffer = (struct rt_can_msg_list*) (rx_fifo + 1); + rt_memset(rx_fifo->buffer, 0, can->config.msgboxsz * sizeof(struct rt_can_msg_list)); + rt_list_init(&rx_fifo->freelist); + rt_list_init(&rx_fifo->uselist); + rx_fifo->freenumbers=can->config.msgboxsz; + int i = 0; + for(i = 0; i< can->config.msgboxsz; i++) + { + rt_list_insert_before(&rx_fifo->freelist,&rx_fifo->buffer[i].list); +#ifdef RT_CAN_USING_HDR + rt_list_init(&rx_fifo->buffer[i].hdrlist); + rx_fifo->buffer[i].owner = RT_NULL; +#endif + } + can->can_rx = rx_fifo; + rt_exit_critical(); + dev->open_flag |= RT_DEVICE_FLAG_INT_RX; + /* configure low level device */ + can->ops->control(can, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_RX); + } + else + { + can->can_rx = RT_NULL; + rt_exit_critical(); + } + } else { + rt_exit_critical(); + } + rt_enter_critical(); + if (can->can_tx == RT_NULL) + { + if (oflag & RT_DEVICE_FLAG_INT_TX) + { + struct rt_can_tx_fifo *tx_fifo; + + tx_fifo = (struct rt_can_tx_fifo*) rt_malloc(sizeof(struct rt_can_tx_fifo)+ + can->config.sndboxnumber*sizeof(struct rt_can_sndbxinx_list)); + RT_ASSERT(tx_fifo != RT_NULL); + tx_fifo->buffer = (struct rt_can_sndbxinx_list *) (tx_fifo + 1); + rt_memset(tx_fifo->buffer, 0, + can->config.sndboxnumber*sizeof(struct rt_can_sndbxinx_list)); + rt_list_init(&tx_fifo->freelist); + int i = 0; + for(i = 0; i< can->config.sndboxnumber; i++) + { + rt_list_insert_before(&tx_fifo->freelist,&tx_fifo->buffer[i].list); + rt_completion_init(&(tx_fifo->buffer[i].completion)); + tx_fifo->buffer[i].result = RT_CAN__SND_RESUTL_OK; + } + rt_completion_init(&(tx_fifo->completion)); + can->can_tx = tx_fifo; + rt_exit_critical(); + dev->open_flag |= RT_DEVICE_FLAG_INT_TX; + /* configure low level device */ + can->ops->control(can, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_TX); + } + else + { + can->can_tx = RT_NULL; + rt_exit_critical(); + } + } else { + rt_exit_critical(); + } + can->ops->control(can, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_CAN_INT_ERR); +#ifdef RT_CAN_USING_HDR + rt_enter_critical(); + if(can->hdr == RT_NULL) { + struct rt_can_hdr * phdr; + phdr = (struct rt_can_hdr *) rt_malloc(can->config.maxhdr*sizeof(struct rt_can_hdr)); + RT_ASSERT(phdr != RT_NULL); + rt_memset(phdr, 0,can->config.maxhdr*sizeof(struct rt_can_hdr)); + int i = 0; + for(i = 0; i< can->config.maxhdr; i++) + { + rt_list_init(&phdr[i].list); + } + can->hdr = phdr; + rt_exit_critical(); + } else { + rt_exit_critical(); + } +#endif + rt_enter_critical(); + if(!can->timerinitflag) { + can->timerinitflag = 1; + rt_exit_critical(); + #ifdef RT_CAN_USING_LED + if(can->config.rcvled != RT_NULL) { + rt_pin_mode(can->config.rcvled->pin,can->config.rcvled->mode); + rt_pin_write(can->config.rcvled->pin,can->config.rcvled->init); + } + if(can->config.sndled != RT_NULL) { + rt_pin_mode(can->config.sndled->pin,can->config.sndled->mode); + rt_pin_write(can->config.sndled->pin,can->config.sndled->init); + } + if(can->config.errled != RT_NULL) { + rt_pin_mode(can->config.errled->pin,can->config.errled->mode); + rt_pin_write(can->config.errled->pin,can->config.errled->init); + } + #endif + rt_timer_start(&can->timer); + } else { + rt_exit_critical(); + } + return RT_EOK; +} + +static rt_err_t rt_can_close(struct rt_device *dev) +{ + struct rt_can_device *can; + + RT_ASSERT(dev != RT_NULL); + can = (struct rt_can_device *)dev; + + /* this device has more reference count */ + if (dev->ref_count > 1) return RT_EOK; + rt_enter_critical(); + if(can->timerinitflag) { + can->timerinitflag = 0; + rt_exit_critical(); + rt_timer_stop(&can->timer); + #ifdef RT_CAN_USING_LED + rt_pin_write(can->config.rcvled->pin,can->config.rcvled->init); + rt_pin_write(can->config.rcvled->pin,can->config.sndled->init); + rt_pin_write(can->config.rcvled->pin,can->config.errled->init); + #endif + } else { + rt_exit_critical(); + } + rt_enter_critical(); + can->status_indicate.ind = RT_NULL; + can->status_indicate.args = RT_NULL; + rt_exit_critical(); +#ifdef RT_CAN_USING_HDR + rt_enter_critical(); + if(can->hdr != RT_NULL) { + rt_free(can->hdr); + can->hdr = RT_NULL; + rt_exit_critical(); + } else { + rt_exit_critical(); + } +#endif + if (dev->open_flag & RT_DEVICE_FLAG_INT_RX) + { + struct rt_can_rx_fifo* rx_fifo; + + rx_fifo = (struct rt_can_rx_fifo*)can->can_rx; + RT_ASSERT(rx_fifo != RT_NULL); + + rt_free(rx_fifo); + dev->open_flag &= ~RT_DEVICE_FLAG_INT_RX; + /* configure low level device */ + can->ops->control(can, RT_DEVICE_CTRL_CLR_INT, (void*)RT_DEVICE_FLAG_INT_TX); + } + if (dev->open_flag & RT_DEVICE_FLAG_INT_TX) + { + struct rt_can_tx_fifo* tx_fifo; + + tx_fifo = (struct rt_can_tx_fifo*)can->can_rx; + RT_ASSERT(tx_fifo != RT_NULL); + + rt_free(tx_fifo); + dev->open_flag &= ~RT_DEVICE_FLAG_INT_TX; + /* configure low level device */ + can->ops->control(can, RT_DEVICE_CTRL_CLR_INT, (void*)RT_DEVICE_FLAG_INT_TX); + } + can->ops->control(can, RT_DEVICE_CTRL_CLR_INT, (void *)RT_DEVICE_CAN_INT_ERR); + return RT_EOK; +} + +static rt_size_t rt_can_read(struct rt_device *dev, + rt_off_t pos, + void *buffer, + rt_size_t size) +{ + struct rt_can_device *can; + + RT_ASSERT(dev != RT_NULL); + if (size == 0) return 0; + + can = (struct rt_can_device *)dev; + + if (dev->open_flag & RT_DEVICE_FLAG_INT_RX) + { + return _can_int_rx(can, buffer, size); + } + return 0; +} + +static rt_size_t rt_can_write(struct rt_device *dev, + rt_off_t pos, + const void *buffer, + rt_size_t size) +{ + struct rt_can_device *can; + + RT_ASSERT(dev != RT_NULL); + if (size == 0) return 0; + + can = (struct rt_can_device *)dev; + + if (dev->open_flag & RT_DEVICE_FLAG_INT_TX) + { + if(can->config.privmode) { + return _can_int_tx_priv(can, buffer, size); + } else { + return _can_int_tx(can, buffer, size); + } + } + return 0; +} + +static rt_err_t rt_can_control(struct rt_device *dev, + rt_uint8_t cmd, + void *args) +{ + struct rt_can_device *can; + rt_err_t res; + + RT_ASSERT(dev != RT_NULL); + can = (struct rt_can_device *)dev; + + switch (cmd) + { + case RT_DEVICE_CTRL_SUSPEND: + /* suspend device */ + dev->flag |= RT_DEVICE_FLAG_SUSPENDED; + break; + + case RT_DEVICE_CTRL_RESUME: + /* resume device */ + dev->flag &= ~RT_DEVICE_FLAG_SUSPENDED; + break; + + case RT_DEVICE_CTRL_CONFIG: + /* configure device */ + can->ops->configure(can, (struct can_configure *)args); + break; + case RT_CAN_CMD_SET_PRIV: + /* configure device */ + if((rt_uint32_t)args != can->config.privmode) { + if(res = can->ops->control(can, cmd, args) != RT_EOK) { + return res; + } + struct rt_can_tx_fifo* tx_fifo; + tx_fifo = (struct rt_can_tx_fifo*) can->can_tx; + int i; + rt_base_t level; + if(can->config.privmode) { + rt_completion_done(&(tx_fifo->completion)); + level = rt_hw_interrupt_disable(); + for(i = 0; i< can->config.sndboxnumber; i++) + { + rt_list_remove(&tx_fifo->buffer[i].list); + } + rt_hw_interrupt_enable(level); + } else { + for(i = 0; i< can->config.sndboxnumber; i++) + { + rt_base_t level; + level = rt_hw_interrupt_disable(); + if(tx_fifo->buffer[i].result == RT_CAN__SND_RESUTL_OK) { + rt_list_insert_before(&tx_fifo->freelist,&tx_fifo->buffer[i].list); + } + rt_hw_interrupt_enable(level); + } + } + return RT_EOK; + } + break; + case RT_CAN_CMD_SET_STATUS_IND: + can->status_indicate.ind = ((rt_can_status_ind_type_t)args)->ind; + can->status_indicate.args = ((rt_can_status_ind_type_t)args)->args; + break; +#ifdef RT_CAN_USING_HDR + case RT_CAN_CMD_SET_FILTER: + res = can->ops->control(can, cmd, args); + if(res != RT_EOK || can->hdr == RT_NULL) { + return res; + } + { + struct rt_can_filter_config* pfilter; + struct rt_can_filter_item* pitem; + rt_uint32_t count; + rt_base_t level; + pfilter = (struct rt_can_filter_config*)args; + count = pfilter->count; + pitem = pfilter->items; + if(pfilter->actived) { + while(count) { + if(pitem->hdr >= can->config.maxhdr || pitem->hdr < 0) { + count--; + pitem++; + continue; + } + level = rt_hw_interrupt_disable(); + if(!can->hdr[pitem->hdr].connected) { + rt_memcpy(&can->hdr[pitem->hdr].filter,pitem, + sizeof(struct rt_can_filter_item)); + can->hdr[pitem->hdr].connected = 1; + can->hdr[pitem->hdr].msgs = 0; + rt_list_init(&can->hdr[pitem->hdr].list); + } + rt_hw_interrupt_enable(level); + count--; + pitem++; + } + } else { + while(count) { + if(pitem->hdr >= can->config.maxhdr || pitem->hdr < 0) { + count--; + pitem++; + continue; + } + level = rt_hw_interrupt_disable(); + if(can->hdr[pitem->hdr].connected) { + rt_memset(&can->hdr[pitem->hdr].filter,0, + sizeof(struct rt_can_filter_item)); + can->hdr[pitem->hdr].connected = 0; + can->hdr[pitem->hdr].msgs = 0; + if(!rt_list_isempty(&can->hdr[pitem->hdr].list)) + { + rt_list_remove(can->hdr[pitem->hdr].list.next); + } + } + rt_hw_interrupt_enable(level); + count--; + pitem++; + } + } + } + break; +#endif /*RT_CAN_USING_HDR*/ + default : + /* control device */ + if(can->ops->control != RT_NULL) + { + can->ops->control(can, cmd, args); + } + break; + } + + return RT_EOK; +} +/* + * can timer + */ +static void cantimeout(void* arg) +{ + rt_uint32_t ledonflag = 0; + rt_can_t can = (rt_can_t)arg; + rt_device_control((rt_device_t)can,RT_CAN_CMD_GET_STATUS,(void* )&can->status); + if(can->timerinitflag == 1) { + ledonflag = 1; + can->timerinitflag = 0xFF; + } + #ifdef RT_CAN_USING_LED + if(can->config.rcvled != RT_NULL && can->config.sndled == RT_NULL) { + if(ledonflag == 1) { + rt_pin_write(can->config.rcvled->pin,can->config.rcvled->init?0:1); + } else { + if(can->status.rcvchange == 1 || can->status.sndchange == 1) + { + can->status.rcvchange = 0; + can->status.sndchange = 0; + rt_pin_write(can->config.rcvled->pin,rt_pin_read(can->config.rcvled->pin)?0:1); + } else { + rt_pin_write(can->config.rcvled->pin,can->config.rcvled->init); + } + } + } else if(can->config.rcvled != RT_NULL && can->config.sndled != RT_NULL) { + if(ledonflag == 1) { + rt_pin_write(can->config.rcvled->pin,can->config.rcvled->init?0:1); + rt_pin_write(can->config.sndled->pin,can->config.sndled->init?0:1); + } else { + if(can->status.rcvchange == 1) + { + can->status.rcvchange = 0; + rt_pin_write(can->config.rcvled->pin,rt_pin_read(can->config.rcvled->pin)?0:1); + } else { + rt_pin_write(can->config.rcvled->pin,can->config.rcvled->init); + } + if(can->status.sndchange == 1) + { + can->status.sndchange = 0; + rt_pin_write(can->config.sndled->pin,rt_pin_read(can->config.sndled->pin)?0:1); + } else { + rt_pin_write(can->config.sndled->pin,can->config.sndled->init); + } + } + } else if(can->config.rcvled == RT_NULL && can->config.sndled != RT_NULL) { + if(ledonflag == 1) { + rt_pin_write(can->config.sndled->pin,can->config.sndled->init?0:1); + } else { + if(can->status.rcvchange == 1 || can->status.sndchange == 1) + { + can->status.rcvchange = 0; + can->status.sndchange = 0; + rt_pin_write(can->config.sndled->pin,rt_pin_read(can->config.sndled->pin)?0:1); + } else { + rt_pin_write(can->config.sndled->pin,can->config.sndled->init); + } + } + } + if(ledonflag == 1) { + rt_pin_write(can->config.errled->pin,can->config.errled->init?0:1); + } else { + if(can->status.errcode) { + rt_pin_write(can->config.errled->pin,can->config.errled->init?0:1); + } else { + rt_pin_write(can->config.errled->pin,can->config.errled->init); + } + } + #endif + if(can->status_indicate.ind != RT_NULL) + { + can->status_indicate.ind(can,can->status_indicate.args); + } +} + +/* + * can register + */ +rt_err_t rt_hw_can_register(struct rt_can_device *can, + const char *name, + const struct rt_can_ops *ops, + void *data) +{ + struct rt_device *device; + RT_ASSERT(can != RT_NULL); + + device = &(can->parent); + + device->type = RT_Device_Class_CAN; + device->rx_indicate = RT_NULL; + device->tx_complete = RT_NULL; +#ifdef RT_CAN_USING_HDR + can->hdr = RT_NULL; +#endif + can->can_rx = RT_NULL; + can->can_tx = RT_NULL; + device->init = rt_can_init; + device->open = rt_can_open; + device->close = rt_can_close; + device->read = rt_can_read; + device->write = rt_can_write; + device->control = rt_can_control; + can->ops = ops; + + can->status_indicate.ind = RT_NULL; + can->status_indicate.args = RT_NULL; + rt_memset(&can->status,0,sizeof(can->status)); + + device->user_data = data; + can->timerinitflag = 0; + if(can->config.rcvled != RT_NULL || + can->config.sndled != RT_NULL || + can->config.errled != RT_NULL) + { + rt_timer_init(&can->timer, + name, + cantimeout, + (void*)can, + can->config.ticks, + RT_TIMER_FLAG_PERIODIC); + } + /* register a character device */ + return rt_device_register(device, name, RT_DEVICE_FLAG_RDWR); +} + +/* ISR for can interrupt */ +void rt_hw_can_isr(struct rt_can_device *can, int event) +{ + switch (event & 0xff) + { + case RT_CAN_EVENT_RXOF_IND: + { + rt_base_t level; + level = rt_hw_interrupt_disable(); + can->status.dropedrcvpkg++; + rt_hw_interrupt_enable(level); + } + case RT_CAN_EVENT_RX_IND: + { + struct rt_can_msg tmpmsg; + struct rt_can_rx_fifo* rx_fifo; + struct rt_can_msg_list* listmsg=RT_NULL; +#ifdef RT_CAN_USING_HDR + rt_int32_t hdr; +#endif + int ch = -1; + rt_base_t level; + rx_fifo = (struct rt_can_rx_fifo*)can->can_rx; + RT_ASSERT(rx_fifo != RT_NULL); + /* interrupt mode receive */ + RT_ASSERT(can->parent.open_flag & RT_DEVICE_FLAG_INT_RX); + + rt_uint32_t no; + no = event >> 8; + ch = can->ops->recvmsg(can,&tmpmsg,no); + if (ch == -1) break; + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + can->status.rcvpkg++; + can->status.rcvchange = 1; + if(!rt_list_isempty(&rx_fifo->freelist)) + { + listmsg = rt_list_entry(rx_fifo->freelist.next, struct rt_can_msg_list, list); + rt_list_remove(&listmsg->list); +#ifdef RT_CAN_USING_HDR + rt_list_remove(&listmsg->hdrlist); + if(listmsg->owner != RT_NULL && listmsg->owner->msgs) { + listmsg->owner->msgs--; + } + listmsg->owner = RT_NULL; +#endif /*RT_CAN_USING_HDR*/ + RT_ASSERT(rx_fifo->freenumbers >0); + rx_fifo->freenumbers--; + } else if(!rt_list_isempty(&rx_fifo->uselist)) { + listmsg = rt_list_entry(rx_fifo->uselist.next, struct rt_can_msg_list, list); + can->status.dropedrcvpkg++; + rt_list_remove(&listmsg->list); +#ifdef RT_CAN_USING_HDR + rt_list_remove(&listmsg->hdrlist); + if(listmsg->owner != RT_NULL && listmsg->owner->msgs) { + listmsg->owner->msgs--; + } + listmsg->owner = RT_NULL; +#endif + } + /* enable interrupt */ + rt_hw_interrupt_enable(level); + if(listmsg != RT_NULL) { + rt_memcpy(&listmsg->data,&tmpmsg,sizeof(struct rt_can_msg)); + level = rt_hw_interrupt_disable(); + rt_list_insert_before(&rx_fifo->uselist,&listmsg->list); +#ifdef RT_CAN_USING_HDR + hdr = tmpmsg.hdr; + if(can->hdr != RT_NULL) { + RT_ASSERT(hdr < can->config.maxhdr && hdr >= 0); + if(can->hdr[hdr].connected) { + rt_list_insert_before(&can->hdr[hdr].list,&listmsg->hdrlist); + listmsg->owner = &can->hdr[hdr]; + can->hdr[hdr].msgs++; + } + + } +#endif + rt_hw_interrupt_enable(level); + } + + /* invoke callback */ +#ifdef RT_CAN_USING_HDR + if(can->hdr != RT_NULL && can->hdr[hdr].connected && can->hdr[hdr].filter.ind) { + RT_ASSERT(hdr < can->config.maxhdr && hdr >= 0); + rt_size_t rx_length; + level = rt_hw_interrupt_disable(); + rx_length = can->hdr[hdr].msgs * sizeof(struct rt_can_msg); + rt_hw_interrupt_enable(level); + can->hdr[hdr].filter.ind(&can->parent, can->hdr[hdr].filter.args, hdr, rx_length); + + } else +#endif + if (can->parent.rx_indicate != RT_NULL) { + rt_size_t rx_length; + /* get rx length */ + level = rt_hw_interrupt_disable(); + rx_length = rx_fifo->freenumbers*sizeof(struct rt_can_msg); + rt_hw_interrupt_enable(level); + + can->parent.rx_indicate(&can->parent, rx_length); + } + break; + } + case RT_CAN_EVENT_TX_DONE: + case RT_CAN_EVENT_TX_FAIL: + { + struct rt_can_tx_fifo* tx_fifo; + rt_uint32_t no; + no = event >> 8; + tx_fifo = (struct rt_can_tx_fifo*) can->can_tx; + RT_ASSERT(tx_fifo != RT_NULL); + if((event & 0xff) == RT_CAN_EVENT_TX_DONE) { + tx_fifo->buffer[no].result = RT_CAN__SND_RESUTL_OK; + } else { + tx_fifo->buffer[no].result = RT_CAN__SND_RESUTL_ERR; + } + rt_completion_done(&(tx_fifo->buffer[no].completion)); + break; + } + } +} +#ifdef RT_USING_FINSH +#include <finsh.h> +int cmd_canstat(int argc,void** argv) +{ + static const char* ErrCode[] = { + "No Error!", + "Warning !", + "Passive !", + "Bus Off !" + }; + if(argc >= 2) { + rt_device_t candev = rt_device_find(argv[1]); + if(!candev) { + rt_kprintf(" Can't find can device %s\n",argv[1]); + return -1; + } + rt_kprintf(" Finded can device: %s...",argv[1]); + struct rt_can_status status; + rt_device_control(candev,RT_CAN_CMD_GET_STATUS,&status); + rt_kprintf("\n Receive...error..count: %010ld. Send.....error....count: %010ld.", + status.rcverrcnt,status.snderrcnt); + rt_kprintf("\n Bit..pad..error..count: %010ld. Format...error....count: %010ld", + status.bitpaderrcnt,status.formaterrcnt); + rt_kprintf("\n Ack.......error..count: %010ld. Bit......error....count: %010ld.", + status.ackerrcnt,status.biterrcnt); + rt_kprintf("\n CRC.......error..count: %010ld. Error.code.[%010ld]: ", + status.crcerrcnt,status.errcode); + switch(status.errcode) { + case 0: + rt_kprintf("%s.",ErrCode[0]); + break; + case 1: + rt_kprintf("%s.",ErrCode[1]); + break; + case 2: + case 3: + rt_kprintf("%s.",ErrCode[2]); + break; + case 4: + case 5: + case 6: + case 7: + rt_kprintf("%s.",ErrCode[3]); + break; + } + rt_kprintf("\n Total.receive.packages: %010ld. Droped.receive.packages: %010ld.", + status.rcvpkg,status.dropedrcvpkg); + rt_kprintf("\n Total..send...packages: %010ld. Droped...send..packages: %010ld.\n", + status.sndpkg + status.dropedsndpkg,status.dropedsndpkg); + } else { + rt_kprintf(" Invalid Call %s\n",argv[0]); + rt_kprintf(" Please using %s cannamex .Here canname is driver name and x is candrive number.\n",argv[0]); + } + return 0; +} +FINSH_FUNCTION_EXPORT_ALIAS(cmd_canstat, __cmd_canstat, Stat Can Device Status.); +#endif diff --git a/components/drivers/can/readme-zh.txt b/components/drivers/can/readme-zh.txt new file mode 100644 index 0000000000..3eb63d155f --- /dev/null +++ b/components/drivers/can/readme-zh.txt @@ -0,0 +1,132 @@ +说明: +本驱动完成了can控制器硬件抽象 +一 CAN Driver 注册 + Can driver注册需要填充以下几个数据结构: + 1、struct can_configure + { + rt_uint32_t baud_rate; + rt_uint32_t msgboxsz; + rt_uint32_t sndboxnumber; + rt_uint32_t mode :8; + rt_uint32_t privmode :8; + rt_uint32_t reserved :16; + #ifdef RT_CAN_USING_LED + const struct rt_can_led* rcvled; + const struct rt_can_led* sndled; + const struct rt_can_led* errled; + #endif /*RT_CAN_USING_LED*/ + rt_uint32_t ticks; + #ifdef RT_CAN_USING_HDR + rt_uint32_t maxhdr; + #endif + }; + struct can_configure 为can驱动的基本配置信息: + baud_rate : + enum CANBAUD + { + CAN1MBaud=0, // 1 MBit/sec + CAN800kBaud, // 800 kBit/sec + CAN500kBaud, // 500 kBit/sec + CAN250kBaud, // 250 kBit/sec + CAN125kBaud, // 125 kBit/sec + CAN100kBaud, // 100 kBit/sec + CAN50kBaud, // 50 kBit/sec + CAN20kBaud, // 20 kBit/sec + CAN10kBaud // 10 kBit/sec + }; + 配置Can的波特率。 + msgboxsz : Can接收邮箱缓冲数量,本驱动在软件层开辟msgboxsz个接收邮箱。 + sndboxnumber : can 发送通道数量,该配置为Can控制器实际的发送通道数量。 + mode : + #define RT_CAN_MODE_NORMAL 0 正常模式 + #define RT_CAN_MODE_LISEN 1 只听模式 + #define RT_CAN_MODE_LOOPBACK 2 自发自收模式 + #define RT_CAN_MODE_LOOPBACKANLISEN 3 自发自收只听模式 + 配置Can 的工作状态。 + privmode : + #define RT_CAN_MODE_PRIV 0x01 处于优先级模式,高优先级的消息优先发送。 + #define RT_CAN_MODE_NOPRIV 0x00 + 配置Can driver的优先级模式。 + #ifdef RT_CAN_USING_LED + const struct rt_can_led* rcvled; + const struct rt_can_led* sndled; + const struct rt_can_led* errled; + #endif /*RT_CAN_USING_LED*/ + 配置can led信息, 当前can驱动的led使用了 pin驱动, + 开启RT_CAN_USING_LED时要确保当前系统已实现pin驱动。 + rt_uint32_t ticks : 配置Can driver timer周期。 + #ifdef RT_CAN_USING_HDR + rt_uint32_t maxhdr; + #endif + 如果使用硬件过滤,则开启RT_CAN_USING_HDR, maxhdr 为Can控制器过滤表的数量。 + 2、struct rt_can_ops + { + rt_err_t (*configure)(struct rt_can_device *can, struct can_configure *cfg); + rt_err_t (*control)(struct rt_can_device *can, int cmd, void *arg); + int (*sendmsg)(struct rt_can_device *can, const void* buf, rt_uint32_t boxno); + int (*recvmsg)(struct rt_can_device *can,void* buf, rt_uint32_t boxno); + }; + struct rt_can_ops 为要实现的特定的can控制器操作。 + rt_err_t (*configure)(struct rt_can_device *can, struct can_configure *cfg); + configure根据配置信息初始化Can控制器工作模式。 + rt_err_t (*control)(struct rt_can_device *can, int cmd, void *arg); + control 当前接受以下cmd参数: + #define RT_CAN_CMD_SET_FILTER 0x13 + #define RT_CAN_CMD_SET_BAUD 0x14 + #define RT_CAN_CMD_SET_MODE 0x15 + #define RT_CAN_CMD_SET_PRIV 0x16 + #define RT_CAN_CMD_GET_STATUS 0x17 + #define RT_CAN_CMD_SET_STATUS_IND 0x18 + int (*sendmsg)(struct rt_can_device *can, const void* buf, rt_uint32_t boxno); + sendmsg向Can控制器发送数,boxno为发送通道号。 + int (*recvmsg)(struct rt_can_device *can,void* buf, rt_uint32_t boxno); + recvmsg从Can控制器接收数据,boxno为接收通道号。 + struct rt_can_device + { + struct rt_device parent; + + const struct rt_can_ops *ops; + struct can_configure config; + struct rt_can_status status; + rt_uint32_t timerinitflag; + struct rt_timer timer; + struct rt_can_status_ind_type status_indicate; + #ifdef RT_CAN_USING_HDR + struct rt_can_hdr* hdr; + #endif + void *can_rx; + void *can_tx; + }; + 填充完成后,便可调用rt_hw_can_register完成can驱动的注册。 +二、 CAN Driver 的添加: + 要添加一个新的Can驱动,至少要完成以下接口。 + 1、struct rt_can_ops + { + rt_err_t (*configure)(struct rt_can_device *can, struct can_configure *cfg); + rt_err_t (*control)(struct rt_can_device *can, int cmd, void *arg); + int (*sendmsg)(struct rt_can_device *can, const void* buf, rt_uint32_t boxno); + int (*recvmsg)(struct rt_can_device *can,void* buf, rt_uint32_t boxno); + }; + 2、 rt_err_t (*control)(struct rt_can_device *can, int cmd, void *arg); + 接口的 + #define RT_CAN_CMD_SET_FILTER 0x13 + #define RT_CAN_CMD_SET_BAUD 0x14 + #define RT_CAN_CMD_SET_MODE 0x15 + #define RT_CAN_CMD_SET_PRIV 0x16 + #define RT_CAN_CMD_GET_STATUS 0x17 + #define RT_CAN_CMD_SET_STATUS_IND 0x18 + 若干命令。 + 3、can口中断,要完接收,发送结束,以及错误中断。 + #define RT_CAN_EVENT_RX_IND 0x01 /* Rx indication */ + #define RT_CAN_EVENT_TX_DONE 0x02 /* Tx complete */ + #define RT_CAN_EVENT_TX_FAIL 0x03 /* Tx complete */ + #define RT_CAN_EVENT_RX_TIMEOUT 0x05 /* Rx timeout */ + #define RT_CAN_EVENT_RXOF_IND 0x06 /* Rx overflow */ + 中断产生后,调用rt_hw_can_isr(struct rt_can_device *can, int event) + 进入相应的操作,其中接收发送中断的event,最低8位为上面的事件,16到24位为通信通道号。 + 一个作为一个例子,参见bsp/stm32f10x/driver下的bxcan.c 。 +三、CAN Driver的使用: + 一个使用的例子,参数bsp/stm32f10x/applications下的canapp.c +四、当前Can驱动,没有实现轮模式,采用中断模式,bxcan驱动工作在loopback模式下的时候不能读数据。 + +五、当前Can驱动,在stm32f105上测试,暂无问题。 diff --git a/components/drivers/include/drivers/can.h b/components/drivers/include/drivers/can.h new file mode 100644 index 0000000000..3a24162f03 --- /dev/null +++ b/components/drivers/include/drivers/can.h @@ -0,0 +1,293 @@ +/* + * File : can.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2015, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2015-05-14 [email protected] first version + */ +#ifndef CAN_H_ +#define CAN_H_ + +#ifndef RT_CANMSG_BOX_SZ +#define RT_CANMSG_BOX_SZ 16 +#endif +#ifndef RT_CANSND_BOX_NUM +#define RT_CANSND_BOX_NUM 1 +#endif + +enum CANBAUD +{ + CAN1MBaud=0, // 1 MBit/sec + CAN800kBaud, // 800 kBit/sec + CAN500kBaud, // 500 kBit/sec + CAN250kBaud, // 250 kBit/sec + CAN125kBaud, // 125 kBit/sec + CAN100kBaud, // 100 kBit/sec + CAN50kBaud, // 50 kBit/sec + CAN20kBaud, // 20 kBit/sec + CAN10kBaud // 10 kBit/sec +}; +#define RT_CAN_MODE_NORMAL 0 +#define RT_CAN_MODE_LISEN 1 +#define RT_CAN_MODE_LOOPBACK 2 +#define RT_CAN_MODE_LOOPBACKANLISEN 3 + +#define RT_CAN_MODE_PRIV 0x01 +#define RT_CAN_MODE_NOPRIV 0x00 + +#ifdef RT_CAN_USING_LED +struct rt_can_led +{ + rt_uint32_t pin,mode,init; + struct rt_timer* timer; + const char* timer_name; +}; +#endif /*RT_CAN_USING_LED*/ + +struct rt_can_filter_item +{ + rt_uint32_t id :29; + rt_uint32_t ide :1; + rt_uint32_t rtr :1; + rt_uint32_t mode :1; + rt_uint32_t mask; + rt_int32_t hdr; + rt_err_t (*ind)(rt_device_t dev, void* args ,rt_int32_t hdr, rt_size_t size); + void* args; +}; +#ifdef RT_CAN_USING_HDR +#define RT_CAN_FILTER_ITEM_INIT(id,ide,rtr,mode,mask,ind,args) \ + {\ + id,\ + ide,\ + rtr,\ + mode,\ + mask,\ + -1,\ + ind,\ + args,\ + } +#define RT_CAN_FILTER_STD_INIT(id,ind,args) \ + RT_CAN_FILTER_ITEM_INIT(id,0,0,0,0xFFFFFFFF,ind,args) +#define RT_CAN_FILTER_EXT_INIT(id,ind,args) \ + RT_CAN_FILTER_ITEM_INIT(id,1,0,0,0xFFFFFFFF,ind,args) +#define RT_CAN_STD_RMT_FILTER_INIT(id,ind,args) \ + RT_CAN_FILTER_ITEM_INIT(id,0,1,0,0xFFFFFFFF,ind,args) +#define RT_CAN_EXT_RMT_FILTER_INIT(id,ind,args) \ + RT_CAN_FILTER_ITEM_INIT(id,1,1,0,0xFFFFFFFF,ind,args) +#define RT_CAN_STD_RMT_DATA_FILTER_INIT(id,ind,args) \ + RT_CAN_FILTER_ITEM_INIT(id,0,0,1,0xFFFFFFFF,ind,args) +#define RT_CAN_EXT_RMT_DATA_FILTER_INIT(id,ind,args) \ + RT_CAN_FILTER_ITEM_INIT(id,1,0,1,0xFFFFFFFF,ind,args) +#else +#define RT_CAN_FILTER_ITEM_INIT(id,ide,rtr,mode,mask,args) \ + {\ + id,\ + ide,\ + rtr,\ + mode,\ + mask,\ + -1,\ + args,\ + } +#define RT_CAN_FILTER_STD_INIT(id,args) \ + RT_CAN_FILTER_ITEM_INIT(id,0,0,0,0xFFFFFFFF,args) +#define RT_CAN_FILTER_EXT_INIT(id,args) \ + RT_CAN_FILTER_ITEM_INIT(id,1,0,0,0xFFFFFFFF,args) +#define RT_CAN_STD_RMT_FILTER_INIT(id,args) \ + RT_CAN_FILTER_ITEM_INIT(id,0,1,0,0xFFFFFFFF,args) +#define RT_CAN_EXT_RMT_FILTER_INIT(id,args) \ + RT_CAN_FILTER_ITEM_INIT(id,1,1,0,0xFFFFFFFF,args) +#define RT_CAN_STD_RMT_DATA_FILTER_INIT(id,args) \ + RT_CAN_FILTER_ITEM_INIT(id,0,0,1,0xFFFFFFFF,args) +#define RT_CAN_EXT_RMT_DATA_FILTER_INIT(id,args) \ + RT_CAN_FILTER_ITEM_INIT(id,1,0,1,0xFFFFFFFF,args) +#endif + +struct rt_can_filter_config +{ + rt_uint32_t count; + rt_uint32_t actived; + struct rt_can_filter_item* items; +}; +struct can_configure +{ + rt_uint32_t baud_rate; + rt_uint32_t msgboxsz; + rt_uint32_t sndboxnumber; + rt_uint32_t mode :8; + rt_uint32_t privmode :8; + rt_uint32_t reserved :16; + #ifdef RT_CAN_USING_LED + const struct rt_can_led* rcvled; + const struct rt_can_led* sndled; + const struct rt_can_led* errled; + #endif /*RT_CAN_USING_LED*/ + rt_uint32_t ticks; +#ifdef RT_CAN_USING_HDR + rt_uint32_t maxhdr; +#endif +}; + +#define CANDEFAULTCONFIG \ +{\ + CAN1MBaud,\ + RT_CANMSG_BOX_SZ,\ + RT_CANSND_BOX_NUM,\ + RT_CAN_MODE_NORMAL,\ +}; + +struct rt_can_ops; +#define RT_CAN_CMD_SET_FILTER 0x13 +#define RT_CAN_CMD_SET_BAUD 0x14 +#define RT_CAN_CMD_SET_MODE 0x15 +#define RT_CAN_CMD_SET_PRIV 0x16 +#define RT_CAN_CMD_GET_STATUS 0x17 +#define RT_CAN_CMD_SET_STATUS_IND 0x18 + +#define RT_DEVICE_CAN_INT_ERR 0x1000 + +enum RT_CAN_STATUS_MODE +{ + NORMAL = 0, + ERRWARNING = 1, + ERRPASSIVE = 2, + BUSOFF = 4, +}; +enum RT_CAN_BUS_ERR +{ + RT_CAN_BUS_NO_ERR = 0, + RT_CAN_BUS_BIT_PAD_ERR = 1, + RT_CAN_BUS_FORMAT_ERR = 2, + RT_CAN_BUS_ACK_ERR = 3, + RT_CAN_BUS_IMPLICIT_BIT_ERR = 4, + RT_CAN_BUS_EXPLICIT_BIT_ERR = 5, + RT_CAN_BUS_CRC_ERR = 6, +}; +struct rt_can_status +{ + rt_uint32_t rcverrcnt; + rt_uint32_t snderrcnt; + rt_uint32_t errcode; + rt_uint32_t rcvpkg; + rt_uint32_t dropedrcvpkg; + rt_uint32_t sndpkg; + rt_uint32_t dropedsndpkg; + rt_uint32_t bitpaderrcnt; + rt_uint32_t formaterrcnt; + rt_uint32_t ackerrcnt; + rt_uint32_t biterrcnt; + rt_uint32_t crcerrcnt; + rt_uint32_t rcvchange; + rt_uint32_t sndchange; + rt_uint32_t lasterrtype; +}; +#ifdef RT_CAN_USING_HDR +struct rt_can_hdr { + rt_uint32_t connected; + rt_uint32_t msgs; + struct rt_can_filter_item filter; + struct rt_list_node list; +}; +#endif +struct rt_can_device; +typedef rt_err_t (*rt_canstatus_ind)(struct rt_can_device*, void*); +typedef struct rt_can_status_ind_type +{ + rt_canstatus_ind ind; + void* args; +} *rt_can_status_ind_type_t; +struct rt_can_device +{ + struct rt_device parent; + + const struct rt_can_ops *ops; + struct can_configure config; + struct rt_can_status status; + rt_uint32_t timerinitflag; + struct rt_timer timer; + struct rt_can_status_ind_type status_indicate; +#ifdef RT_CAN_USING_HDR + struct rt_can_hdr* hdr; +#endif + void *can_rx; + void *can_tx; +}; +typedef struct rt_can_device *rt_can_t; + +#define RT_CAN_STDID 0 +#define RT_CAN_EXTID 1 +#define RT_CAN_DTR 0 +#define RT_CAN_RTR 1 + +typedef struct rt_can_status * rt_can_status_t; +struct rt_can_msg +{ + rt_uint32_t id :29; + rt_uint32_t ide :1; + rt_uint32_t rtr :1; + rt_uint32_t rsv :1; + rt_uint32_t len :8; + rt_uint32_t priv :8; + rt_uint32_t hdr :8; + rt_uint32_t reserved :8; + rt_uint8_t data[8]; +}; +typedef struct rt_can_msg* rt_can_msg_t; +struct rt_can_msg_list { + struct rt_list_node list; +#ifdef RT_CAN_USING_HDR + struct rt_list_node hdrlist; + struct rt_can_hdr* owner; +#endif + struct rt_can_msg data; +}; +struct rt_can_rx_fifo +{ + /* software fifo */ + struct rt_can_msg_list *buffer; + rt_uint32_t freenumbers; + struct rt_list_node freelist; + struct rt_list_node uselist; +}; + +#define RT_CAN__SND_RESUTL_OK 0 +#define RT_CAN__SND_RESUTL_ERR 1 +#define RT_CAN__SND_RESUTL_WAIT 2 + +#define RT_CAN_EVENT_RX_IND 0x01 /* Rx indication */ +#define RT_CAN_EVENT_TX_DONE 0x02 /* Tx complete */ +#define RT_CAN_EVENT_TX_FAIL 0x03 /* Tx complete */ +#define RT_CAN_EVENT_RX_TIMEOUT 0x05 /* Rx timeout */ +#define RT_CAN_EVENT_RXOF_IND 0x06 /* Rx overflow */ + +struct rt_can_sndbxinx_list { + struct rt_list_node list; + struct rt_completion completion; + rt_uint32_t result; +}; +struct rt_can_tx_fifo +{ + struct rt_can_sndbxinx_list *buffer; + struct rt_completion completion; + struct rt_list_node freelist; +}; +struct rt_can_ops +{ + rt_err_t (*configure)(struct rt_can_device *can, struct can_configure *cfg); + rt_err_t (*control)(struct rt_can_device *can, int cmd, void *arg); + int (*sendmsg)(struct rt_can_device *can, const void* buf, rt_uint32_t boxno); + int (*recvmsg)(struct rt_can_device *can,void* buf, rt_uint32_t boxno); +}; +rt_err_t rt_hw_can_register(struct rt_can_device *can, + const char *name, + const struct rt_can_ops *ops, + void *data); +void rt_hw_can_isr(struct rt_can_device *can, int event); +#endif /*_CAN_H*/ diff --git a/components/drivers/include/rtdevice.h b/components/drivers/include/rtdevice.h index 5d74ed6199..f4d967831c 100644 --- a/components/drivers/include/rtdevice.h +++ b/components/drivers/include/rtdevice.h @@ -366,6 +366,10 @@ rt_inline void rt_work_init(struct rt_work* work, void (*work_func)(struct rt_wo #include "drivers/pin.h" #endif +#ifdef RT_USING_CAN +#include "drivers/can.h" +#endif + #ifdef __cplusplus } #endif diff --git a/components/drivers/spi/spi_flash_w25qxx.c b/components/drivers/spi/spi_flash_w25qxx.c index bdcdbd83c1..6e002c38c8 100644 --- a/components/drivers/spi/spi_flash_w25qxx.c +++ b/components/drivers/spi/spi_flash_w25qxx.c @@ -13,6 +13,7 @@ * 2012-05-06 aozima can page write. * 2012-08-23 aozima add flash lock. * 2012-08-24 aozima fixed write status register BUG. + * 2015-05-13 bernard add GD25Q flash ID. */ #include <stdint.h> @@ -28,8 +29,10 @@ #define PAGE_SIZE 4096 -/* JEDEC Manufacturer��s ID */ +/* JEDEC Manufacturer��s ID */ #define MF_ID (0xEF) +#define GD_ID (0xC8) + /* JEDEC Device ID: Memory type and Capacity */ #define MTC_W25Q16_BV_CL_CV (0x4015) /* W25Q16BV W25Q16CL W25Q16CV */ #define MTC_W25Q16_DW (0x6015) /* W25Q16DW */ @@ -297,7 +300,7 @@ rt_err_t w25qxx_init(const char * flash_device_name, const char * spi_device_nam flash_unlock(&spi_flash_device); - if(id_recv[0] != MF_ID) + if(id_recv[0] != MF_ID && id_recv[0] != GD_ID) { FLASH_TRACE("Manufacturers ID error!\r\n"); FLASH_TRACE("JEDEC Read-ID Data : %02X %02X %02X\r\n", id_recv[0], id_recv[1], id_recv[2]); diff --git a/components/net/lwip/apps/ftpd.c b/components/net/lwip/apps/ftpd.c index af48237e42..df1609fe1d 100644 --- a/components/net/lwip/apps/ftpd.c +++ b/components/net/lwip/apps/ftpd.c @@ -11,17 +11,24 @@ #define FTP_MAX_CONNECTION 2 #define FTP_USER "rtt" #define FTP_PASSWORD "demo" -#define FTP_WELCOME_MSG "220-= welcome on RT-Thread FTP server =-\r\n220 \r\n" +#define FTP_WELCOME_MSG "220 welcome on RT-Thread FTP server.\r\n" #define FTP_BUFFER_SIZE 1024 +#define INET_ADDRSTRLEN 16 + + struct ftp_session { rt_bool_t is_anonymous; int sockfd; struct sockaddr_in remote; + struct sockaddr_in server; + + char serveraddr[INET_ADDRSTRLEN]; /* pasv data */ + int pasv_listen_sockfd; char pasv_active; int pasv_sockfd; @@ -43,6 +50,7 @@ struct ftp_session* ftp_new_session() struct ftp_session* session; session = (struct ftp_session*)rt_malloc(sizeof(struct ftp_session)); + rt_memset((void *)session, 0, sizeof(struct ftp_session)); session->next = session_list; session_list = session; @@ -71,6 +79,83 @@ void ftp_close_session(struct ftp_session* session) rt_free(session); } +static int open_data_connection(struct ftp_session* session) +{ + socklen_t len = sizeof(struct sockaddr); + struct sockaddr_in sin; +#if 0 + /* Previous PORT command from client */ + if (ctrl->data_address[0]) { + ctrl->data_sd = socket(AF_INET, SOCK_STREAM, 0); + if (-1 == ctrl->data_sd) { + printf("Failed creating data socket"); + return -1; + } + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = htons(ctrl->data_port); + inet_aton(ctrl->data_address, &(sin.sin_addr)); + + if (connect(ctrl->data_sd, (struct sockaddr *)&sin, len) == -1) { + printf("Failed connecting data socket to client"); + close(ctrl->data_sd); + ctrl->data_sd = -1; + + return -1; + } + + DBG("Connected successfully to client's previously requested address:PORT %s:%d", ctrl->data_address, ctrl->data_port); + return 0; + } +#endif + /* Previous PASV command, accept connect from client */ + if (session->pasv_listen_sockfd > 0) { + char client_ip[100]; + + session->pasv_sockfd = accept(session->pasv_listen_sockfd, (struct sockaddr *)&sin, &len); + if (-1 == session->pasv_sockfd) { + printf("Failed accepting connection from client"); + return -1; + } + + len = sizeof(struct sockaddr); + if (-1 == getpeername(session->pasv_sockfd, (struct sockaddr *)&sin, &len)) { + printf("Cannot determine client address"); + closesocket(session->pasv_sockfd); + session->pasv_sockfd = -1; + return -1; + } + + printf("Client PASV data connection from %s\n", inet_ntoa(sin.sin_addr)); + } + + return 0; +} + +static void close_data_connection(struct ftp_session* session) +{ + /* PASV server listening socket */ + if (session->pasv_listen_sockfd > 0) { + closesocket(session->pasv_listen_sockfd); + session->pasv_listen_sockfd = -1; + } + + /* PASV client socket */ + if (session->pasv_sockfd > 0) { + closesocket(session->pasv_sockfd); + session->pasv_sockfd = -1; + } +#if 0 + /* PORT */ + if (ctrl->data_address[0]) { + ctrl->data_address[0] = 0; + ctrl->data_port = 0; + } +#endif +} + + int ftp_get_filesize(char * filename) { int pos; @@ -179,6 +264,10 @@ void ftpd_thread_entry(void* parameter) session = ftp_new_session(); if (session != NULL) { + if (-1 == getsockname(com_socket, (struct sockaddr *)&session->server, &addr_len)) { + printf("Cannot determine our address, need it if client should connect to us\n"); + } + ipaddr_ntoa_r(&(session->server.sin_addr), session->serveraddr, sizeof(session->serveraddr)); strcpy(session->currentdir, FTP_SRV_ROOT); session->sockfd = com_socket; session->remote = remote; @@ -201,6 +290,7 @@ void ftpd_thread_entry(void* parameter) rt_kprintf("Client %s disconnected\n", inet_ntoa(session->remote.sin_addr)); FD_CLR(session->sockfd, &readfds); closesocket(session->sockfd); + session->sockfd = -1; ftp_close_session(session); } else @@ -210,6 +300,7 @@ void ftpd_thread_entry(void* parameter) { rt_kprintf("Client %s disconnected\r\n", inet_ntoa(session->remote.sin_addr)); closesocket(session->sockfd); + session->sockfd = -1; ftp_close_session(session); } } @@ -359,7 +450,7 @@ int ftp_process_request(struct ftp_session* session, char *buf) } else if (strcmp(parameter_ptr, FTP_USER) == 0) { - session->is_anonymous = RT_FALSE; + session->is_anonymous = RT_FALSE; rt_sprintf(sbuf, "331 Password required for %s\r\n", parameter_ptr); send(session->sockfd, sbuf, strlen(sbuf), 0); } @@ -380,25 +471,26 @@ int ftp_process_request(struct ftp_session* session, char *buf) session->is_anonymous == RT_TRUE) { // password correct - rt_sprintf(sbuf, "230 User logged in\r\n"); + rt_sprintf(sbuf, "230 User logged in.\r\n"); send(session->sockfd, sbuf, strlen(sbuf), 0); - rt_free(sbuf); + rt_free(sbuf); return 0; } // incorrect password rt_sprintf(sbuf, "530 Login or Password incorrect. Bye!\r\n"); send(session->sockfd, sbuf, strlen(sbuf), 0); - rt_free(sbuf); + rt_free(sbuf); return -1; } else if(str_begin_with(buf, "LIST")==0 ) { memset(sbuf,0,FTP_BUFFER_SIZE); + open_data_connection(session); rt_sprintf(sbuf, "150 Opening Binary mode connection for file list.\r\n"); send(session->sockfd, sbuf, strlen(sbuf), 0); do_list(session->currentdir, session->pasv_sockfd); - closesocket(session->pasv_sockfd); + close_data_connection(session); session->pasv_active = 0; rt_sprintf(sbuf, "226 Transfert Complete.\r\n"); send(session->sockfd, sbuf, strlen(sbuf), 0); @@ -408,8 +500,9 @@ int ftp_process_request(struct ftp_session* session, char *buf) memset(sbuf, 0, FTP_BUFFER_SIZE); rt_sprintf(sbuf, "150 Opening Binary mode connection for file list.\r\n"); send(session->sockfd, sbuf, strlen(sbuf), 0); + open_data_connection(session); do_simple_list(session->currentdir, session->pasv_sockfd); - closesocket(session->pasv_sockfd); + close_data_connection(session); session->pasv_active = 0; rt_sprintf(sbuf, "226 Transfert Complete.\r\n"); send(session->sockfd, sbuf, strlen(sbuf), 0); @@ -436,8 +529,20 @@ int ftp_process_request(struct ftp_session* session, char *buf) else if(str_begin_with(buf, "PASV")==0) { int dig1, dig2; - int sockfd; - char optval='1'; + //int sockfd; + int optval=1; + int port; + struct sockaddr_in data; + socklen_t len = sizeof(struct sockaddr); + char *msg, *p; + + if (session->pasv_sockfd > 0) { + closesocket(session->pasv_sockfd); + session->pasv_sockfd = -1; + } + + if (session->pasv_listen_sockfd > 0) + closesocket(session->pasv_listen_sockfd); session->pasv_port = 10000; session->pasv_active = 1; @@ -448,40 +553,63 @@ int ftp_process_request(struct ftp_session* session, char *buf) dig2 = session->pasv_port % 256; FD_ZERO(&readfds); - if((sockfd=socket(PF_INET, SOCK_STREAM, 0))==-1) + if((session->pasv_listen_sockfd=socket(PF_INET, SOCK_STREAM, 0))==-1) { - rt_sprintf(sbuf, "425 Can't open data connection.\r\n"); + rt_sprintf(sbuf, "425 Can't open data connection0.\r\n"); send(session->sockfd, sbuf, strlen(sbuf), 0); goto err1; } - if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))==-1) + if(setsockopt(session->pasv_listen_sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))==-1) { - rt_sprintf(sbuf, "425 Can't open data connection.\r\n"); + rt_sprintf(sbuf, "425 Can't open data connection1.\r\n"); send(session->sockfd, sbuf, strlen(sbuf), 0); goto err1; } - if(bind(sockfd, (struct sockaddr *)&local, addr_len)==-1) + if(bind(session->pasv_listen_sockfd, (struct sockaddr *)&local, addr_len)==-1) { - rt_sprintf(sbuf, "425 Can't open data connection.\r\n"); + rt_sprintf(sbuf, "425 Can't open data connection2.\r\n"); send(session->sockfd, sbuf, strlen(sbuf), 0); goto err1; } - if(listen(sockfd, 1)==-1) + if(listen(session->pasv_listen_sockfd, 1)==-1) { - rt_sprintf(sbuf, "425 Can't open data connection.\r\n"); + rt_sprintf(sbuf, "425 Can't open data connection3.\r\n"); + send(session->sockfd, sbuf, strlen(sbuf), 0); + goto err1; + } + if (-1 == getsockname(session->pasv_listen_sockfd, (struct sockaddr *)&data, &len)) { + rt_kprintf("Cannot determine our address, need it if client should connect to us\n"); + goto err1; + } + + port = ntohs(data.sin_port); + rt_kprintf("Port %d\n", port); + + /* Convert server IP address and port to comma separated list */ + msg = strdup(session->serveraddr); + if (!msg) { + rt_sprintf(sbuf, "426 Internal server error.\r\n"); send(session->sockfd, sbuf, strlen(sbuf), 0); goto err1; } + p = msg; + while ((p = strchr(p, '.'))) + *p++ = ','; + rt_kprintf("Listening %d seconds @ port %d\n", tv.tv_sec, session->pasv_port); - rt_sprintf(sbuf, "227 Entering passive mode (%d,%d,%d,%d,%d,%d)\r\n", 127, 0, 0, 1, dig1, dig2); + rt_sprintf(sbuf, "227 Entering passive mode (%s,%d,%d)\r\n", msg, port / 256, port % 256); send(session->sockfd, sbuf, strlen(sbuf), 0); + rt_free(sbuf); + rt_free(msg); + return 0; + #if 0 FD_SET(sockfd, &readfds); select(0, &readfds, 0, 0, &tv); if(FD_ISSET(sockfd, &readfds)) { if((session->pasv_sockfd = accept(sockfd, (struct sockaddr*)&pasvremote, &addr_len))==-1) { - rt_sprintf(sbuf, "425 Can't open data connection.\r\n"); + rt_sprintf(sbuf, "425 Can't open data connection4.\r\n"); send(session->sockfd, sbuf, strlen(sbuf), 0); goto err1; } @@ -500,11 +628,21 @@ err1: rt_free(sbuf); return 0; } + #endif +err1: + close_data_connection(session); + session->pasv_active = 0; + rt_free(sbuf); + rt_free(msg); + return 0; + } else if (str_begin_with(buf, "RETR")==0) { int file_size; + open_data_connection(session); + strcpy(filename, buf + 5); build_full_path(session, parameter_ptr, filename, 256); @@ -514,13 +652,15 @@ err1: rt_sprintf(sbuf, "550 \"%s\" : not a regular file\r\n", filename); send(session->sockfd, sbuf, strlen(sbuf), 0); session->offset=0; - rt_free(sbuf); + close_data_connection(session); + rt_free(sbuf); return 0; } fd = open(filename, O_RDONLY, 0); if (fd < 0) { + close_data_connection(session); rt_free(sbuf); return 0; } @@ -543,14 +683,16 @@ err1: rt_sprintf(sbuf, "226 Finished.\r\n"); send(session->sockfd, sbuf, strlen(sbuf), 0); close(fd); - closesocket(session->pasv_sockfd); + close_data_connection(session); } else if (str_begin_with(buf, "STOR")==0) { + open_data_connection(session); if(session->is_anonymous == RT_TRUE) { rt_sprintf(sbuf, "550 Permission denied.\r\n"); send(session->sockfd, sbuf, strlen(sbuf), 0); + close_data_connection(session); rt_free(sbuf); return 0; } @@ -562,6 +704,7 @@ err1: { rt_sprintf(sbuf, "550 Cannot open \"%s\" for writing.\r\n", filename); send(session->sockfd, sbuf, strlen(sbuf), 0); + close_data_connection(session); rt_free(sbuf); return 0; } @@ -579,7 +722,7 @@ err1: else if(numbytes==0) { close(fd); - closesocket(session->pasv_sockfd); + close_data_connection(session); rt_sprintf(sbuf, "226 Finished.\r\n"); send(session->sockfd, sbuf, strlen(sbuf), 0); break; @@ -587,12 +730,12 @@ err1: else if(numbytes==-1) { close(fd); - closesocket(session->pasv_sockfd); + close_data_connection(session); rt_free(sbuf); return -1; } } - closesocket(session->pasv_sockfd); + close_data_connection(session); } else if(str_begin_with(buf, "SIZE")==0) { @@ -659,7 +802,7 @@ err1: send(session->sockfd, sbuf, strlen(sbuf), 0); closesocket(session->pasv_sockfd); session->pasv_active = 0; - rt_free(sbuf); + rt_free(sbuf); return 0; } pasvremote.sin_addr.s_addr=inet_addr(tmpip); @@ -674,7 +817,7 @@ err1: rt_sprintf(sbuf, "425 Can't open data connection.\r\n"); send(session->sockfd, sbuf, strlen(sbuf), 0); closesocket(session->pasv_sockfd); - rt_free(sbuf); + rt_free(sbuf); return 0; } } @@ -697,9 +840,9 @@ err1: { if (session->is_anonymous == RT_TRUE) { - rt_sprintf(sbuf, "550 Permission denied.\r\n"); + rt_sprintf(sbuf, "530 Permission denied.\r\n"); send(session->sockfd, sbuf, strlen(sbuf), 0); - rt_free(sbuf); + rt_free(sbuf); return 0; } @@ -720,7 +863,7 @@ err1: { if (session->is_anonymous == RT_TRUE) { - rt_sprintf(sbuf, "550 Permission denied.\r\n"); + rt_sprintf(sbuf, "530 Permission denied.\r\n"); send(session->sockfd, sbuf, strlen(sbuf), 0); rt_free(sbuf); return 0; @@ -740,9 +883,9 @@ err1: { if (session->is_anonymous == RT_TRUE) { - rt_sprintf(sbuf, "550 Permission denied.\r\n"); + rt_sprintf(sbuf, "530 Permission denied.\r\n"); send(session->sockfd, sbuf, strlen(sbuf), 0); - rt_free(sbuf); + rt_free(sbuf); return 0; } build_full_path(session, parameter_ptr, filename, 256); @@ -758,12 +901,53 @@ err1: send(session->sockfd, sbuf, strlen(sbuf), 0); } } - + else if(str_begin_with(buf, "RNFR")==0) + { + if (session->is_anonymous == RT_TRUE) + { + rt_sprintf(sbuf, "530 Permission denied.\r\n"); + send(session->sockfd, sbuf, strlen(sbuf), 0); + rt_free(sbuf); + return 0; + } + build_full_path(session, parameter_ptr, filename, 256); + + rt_sprintf(sbuf, "350 Successfully rececive old file \"%s\".\r\n", filename); + send(session->sockfd, sbuf, strlen(sbuf), 0); + } + else if(str_begin_with(buf, "RNTO")==0) + { + char new_filename[256]; + if (session->is_anonymous == RT_TRUE) + { + rt_sprintf(sbuf, "530 Permission denied.\r\n"); + send(session->sockfd, sbuf, strlen(sbuf), 0); + rt_free(sbuf); + return 0; + } + build_full_path(session, parameter_ptr, new_filename, 256); + + if(rename(filename, new_filename) == -1) + { + rt_sprintf(sbuf, "553 rename file \"%s\" error.\r\n", filename); + send(session->sockfd, sbuf, strlen(sbuf), 0); + } + else + { + rt_sprintf(sbuf, "250 Successfully rename to new file \"%s\".\r\n", filename); + send(session->sockfd, sbuf, strlen(sbuf), 0); + } + } + else if((str_begin_with(buf, "NOOP")==0) || str_begin_with(buf, "noop")==0) + { + rt_sprintf(sbuf, "200 noop!\r\n"); + send(session->sockfd, sbuf, strlen(sbuf), 0); + } else if(str_begin_with(buf, "QUIT")==0) { rt_sprintf(sbuf, "221 Bye!\r\n"); send(session->sockfd, sbuf, strlen(sbuf), 0); - rt_free(sbuf); + rt_free(sbuf); return -1; } else @@ -771,7 +955,7 @@ err1: rt_sprintf(sbuf, "502 Not Implemented.\r\n"); send(session->sockfd, sbuf, strlen(sbuf), 0); } - rt_free(sbuf); + rt_free(sbuf); return 0; } @@ -787,5 +971,15 @@ void ftpd_start() #ifdef RT_USING_FINSH #include <finsh.h> -FINSH_FUNCTION_EXPORT(ftpd_start, start ftp server) +FINSH_FUNCTION_EXPORT(ftpd_start, start ftp server); + +#ifdef FINSH_USING_MSH +int cmd_ftpd_start(int argc, char** argv) +{ + ftpd_start(); + return 0; +} +FINSH_FUNCTION_EXPORT_ALIAS(cmd_ftpd_start, __cmd_ftpd_start, start ftp server.); +#endif + #endif diff --git a/components/net/lwip_dhcpd/dhcp_server.c b/components/net/lwip_dhcpd/dhcp_server.c index 47547a598b..cb3fc0f464 100644 --- a/components/net/lwip_dhcpd/dhcp_server.c +++ b/components/net/lwip_dhcpd/dhcp_server.c @@ -376,13 +376,24 @@ static void dhcpd_thread_entry(void *parameter) void dhcpd_start(char* netif_name) { rt_thread_t thread; - struct netif *netif = RT_NULL; + struct netif *netif = netif_list; - /* find ethernet interface. */ - netif = netif_find(netif_name); - if (netif == RT_NULL) + if(strlen(netif_name) > sizeof(netif->name)) + { + rt_kprintf("network interface name too long!\r\n"); + return; + } + while(netif != RT_NULL) { - DEBUG_PRINTF("Not found network interface:%s\n", netif_name); + if(strncmp(netif_name, netif->name, sizeof(netif->name)) == 0) + break; + + netif = netif->next; + if( netif == RT_NULL ) + { + rt_kprintf("network interface: %s not found!\r\n", netif_name); + return; + } } thread = rt_thread_create("dhcpd", |
