@@ -0,0 +1,17 @@
|
||||
# for module compiling
|
||||
import os
|
||||
Import('remove_components')
|
||||
from building import *
|
||||
|
||||
objs = []
|
||||
cwd = GetCurrentDir()
|
||||
list = os.listdir(cwd)
|
||||
|
||||
for item in list:
|
||||
if item in remove_components:
|
||||
continue
|
||||
|
||||
if os.path.isfile(os.path.join(cwd, item, 'SConscript')):
|
||||
objs = objs + SConscript(os.path.join(item, 'SConscript'))
|
||||
|
||||
Return('objs')
|
||||
@@ -0,0 +1,14 @@
|
||||
# for module compiling
|
||||
import os
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
objs = []
|
||||
list = os.listdir(cwd)
|
||||
|
||||
for d in list:
|
||||
path = os.path.join(cwd, d)
|
||||
if os.path.isfile(os.path.join(path, 'SConscript')):
|
||||
objs = objs + SConscript(os.path.join(d, 'SConscript'))
|
||||
|
||||
Return('objs')
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* File : alarm.h
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-10-27 heyuanjie87 first version.
|
||||
*/
|
||||
|
||||
#ifndef __ALARM_H__
|
||||
#define __ALARM_H__
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#define RT_ALARM_TM_NOW -1 /* set the alarm tm_day,tm_mon,tm_sec,etc.
|
||||
to now.we also call it "don't care" value */
|
||||
|
||||
/* alarm flags */
|
||||
#define RT_ALARM_ONESHOT 0x000 /* only alarm onece */
|
||||
#define RT_ALARM_DAILY 0x100 /* alarm everyday */
|
||||
#define RT_ALARM_WEEKLY 0x200 /* alarm weekly at Monday or Friday etc. */
|
||||
#define RT_ALARM_MONTHLY 0x400 /* alarm monthly at someday */
|
||||
#define RT_ALARM_YAERLY 0x800 /* alarm yearly at a certain date */
|
||||
|
||||
/* alarm control cmd */
|
||||
#define RT_ALARM_CTRL_MODIFY 1 /* modify alarm time or alarm flag */
|
||||
|
||||
typedef struct rt_alarm *rt_alarm_t;
|
||||
typedef void (*rt_alarm_callback_t)(rt_alarm_t alarm, time_t timestamp);
|
||||
|
||||
/* used for low level RTC driver */
|
||||
struct rt_rtc_wkalarm
|
||||
{
|
||||
rt_bool_t enable; /* 0 = alarm disabled, 1 = alarm enabled */
|
||||
rt_int32_t tm_sec; /* alarm at tm_sec */
|
||||
rt_int32_t tm_min; /* alarm at tm_min */
|
||||
rt_int32_t tm_hour; /* alarm at tm_hour */
|
||||
};
|
||||
|
||||
struct rt_alarm
|
||||
{
|
||||
rt_list_t list;
|
||||
rt_uint32_t flag;
|
||||
rt_alarm_callback_t callback;
|
||||
struct tm wktime;
|
||||
};
|
||||
|
||||
struct rt_alarm_setup
|
||||
{
|
||||
rt_uint32_t flag; /* alarm flag */
|
||||
struct tm wktime; /* when will the alarm wake up user */
|
||||
};
|
||||
|
||||
struct rt_alarm_container
|
||||
{
|
||||
rt_list_t head;
|
||||
struct rt_mutex mutex;
|
||||
struct rt_event event;
|
||||
struct rt_alarm *current;
|
||||
};
|
||||
|
||||
rt_alarm_t rt_alarm_create(rt_alarm_callback_t callback,
|
||||
struct rt_alarm_setup *setup);
|
||||
rt_err_t rt_alarm_control(rt_alarm_t alarm, rt_uint8_t cmd, void *arg);
|
||||
void rt_alarm_update(rt_device_t dev, rt_uint32_t event);
|
||||
rt_err_t rt_alarm_delete(rt_alarm_t alarm);
|
||||
rt_err_t rt_alarm_start(rt_alarm_t alarm);
|
||||
rt_err_t rt_alarm_stop(rt_alarm_t alarm);
|
||||
void rt_alarm_system_init(void);
|
||||
|
||||
#endif /* __ALARM_H__ */
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* File : i2c-bit-ops.h
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-04-25 weety first version
|
||||
*/
|
||||
|
||||
#ifndef __I2C_BIT_OPS_H__
|
||||
#define __I2C_BIT_OPS_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct rt_i2c_bit_ops
|
||||
{
|
||||
void *data; /* private data for lowlevel routines */
|
||||
void (*set_sda)(void *data, rt_int32_t state);
|
||||
void (*set_scl)(void *data, rt_int32_t state);
|
||||
rt_int32_t (*get_sda)(void *data);
|
||||
rt_int32_t (*get_scl)(void *data);
|
||||
|
||||
void (*udelay)(rt_uint32_t us);
|
||||
|
||||
rt_uint32_t delay_us; /* scl and sda line delay */
|
||||
rt_uint32_t timeout; /* in tick */
|
||||
};
|
||||
|
||||
rt_err_t rt_i2c_bit_add_bus(struct rt_i2c_bus_device *bus,
|
||||
const char *bus_name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* File : i2c.h
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-04-25 weety first version
|
||||
*/
|
||||
|
||||
#ifndef __I2C_H__
|
||||
#define __I2C_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define RT_I2C_WR 0x0000
|
||||
#define RT_I2C_RD (1u << 0)
|
||||
#define RT_I2C_ADDR_10BIT (1u << 2) /* this is a ten bit chip address */
|
||||
#define RT_I2C_NO_START (1u << 4)
|
||||
#define RT_I2C_IGNORE_NACK (1u << 5)
|
||||
#define RT_I2C_NO_READ_ACK (1u << 6) /* when I2C reading, we do not ACK */
|
||||
|
||||
struct rt_i2c_msg
|
||||
{
|
||||
rt_uint16_t addr;
|
||||
rt_uint16_t flags;
|
||||
rt_uint16_t len;
|
||||
rt_uint8_t *buf;
|
||||
};
|
||||
|
||||
struct rt_i2c_bus_device;
|
||||
|
||||
struct rt_i2c_bus_device_ops
|
||||
{
|
||||
rt_size_t (*master_xfer)(struct rt_i2c_bus_device *bus,
|
||||
struct rt_i2c_msg msgs[],
|
||||
rt_uint32_t num);
|
||||
rt_size_t (*slave_xfer)(struct rt_i2c_bus_device *bus,
|
||||
struct rt_i2c_msg msgs[],
|
||||
rt_uint32_t num);
|
||||
rt_err_t (*i2c_bus_control)(struct rt_i2c_bus_device *bus,
|
||||
rt_uint32_t,
|
||||
rt_uint32_t);
|
||||
};
|
||||
|
||||
/*for i2c bus driver*/
|
||||
struct rt_i2c_bus_device
|
||||
{
|
||||
struct rt_device parent;
|
||||
const struct rt_i2c_bus_device_ops *ops;
|
||||
rt_uint16_t flags;
|
||||
rt_uint16_t addr;
|
||||
struct rt_mutex lock;
|
||||
rt_uint32_t timeout;
|
||||
rt_uint32_t retries;
|
||||
void *priv;
|
||||
};
|
||||
|
||||
#ifdef RT_I2C_DEBUG
|
||||
#define i2c_dbg(fmt, ...) rt_kprintf(fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define i2c_dbg(fmt, ...)
|
||||
#endif
|
||||
|
||||
rt_err_t rt_i2c_bus_device_register(struct rt_i2c_bus_device *bus,
|
||||
const char *bus_name);
|
||||
struct rt_i2c_bus_device *rt_i2c_bus_device_find(const char *bus_name);
|
||||
rt_size_t rt_i2c_transfer(struct rt_i2c_bus_device *bus,
|
||||
struct rt_i2c_msg msgs[],
|
||||
rt_uint32_t num);
|
||||
rt_size_t rt_i2c_master_send(struct rt_i2c_bus_device *bus,
|
||||
rt_uint16_t addr,
|
||||
rt_uint16_t flags,
|
||||
const rt_uint8_t *buf,
|
||||
rt_uint32_t count);
|
||||
rt_size_t rt_i2c_master_recv(struct rt_i2c_bus_device *bus,
|
||||
rt_uint16_t addr,
|
||||
rt_uint16_t flags,
|
||||
rt_uint8_t *buf,
|
||||
rt_uint32_t count);
|
||||
int rt_i2c_core_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* File : i2c_dev.h
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-04-25 weety first version
|
||||
*/
|
||||
|
||||
#ifndef __I2C_DEV_H__
|
||||
#define __I2C_DEV_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define RT_I2C_DEV_CTRL_10BIT 0x20
|
||||
#define RT_I2C_DEV_CTRL_ADDR 0x21
|
||||
#define RT_I2C_DEV_CTRL_TIMEOUT 0x22
|
||||
#define RT_I2C_DEV_CTRL_RW 0x23
|
||||
|
||||
struct rt_i2c_priv_data
|
||||
{
|
||||
struct rt_i2c_msg *msgs;
|
||||
rt_size_t number;
|
||||
};
|
||||
|
||||
rt_err_t rt_i2c_bus_device_device_init(struct rt_i2c_bus_device *bus,
|
||||
const char *name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+182
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* File : mmcsd_card.h
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2006, RT-Thread Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-07-25 weety first version
|
||||
*/
|
||||
|
||||
#ifndef __MMCSD_CARD_H__
|
||||
#define __MMCSD_CARD_H__
|
||||
|
||||
#include <drivers/mmcsd_host.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define SD_SCR_BUS_WIDTH_1 (1 << 0)
|
||||
#define SD_SCR_BUS_WIDTH_4 (1 << 2)
|
||||
|
||||
struct rt_mmcsd_cid {
|
||||
rt_uint8_t mid; /* ManufacturerID */
|
||||
rt_uint8_t prv; /* Product Revision */
|
||||
rt_uint16_t oid; /* OEM/Application ID */
|
||||
rt_uint32_t psn; /* Product Serial Number */
|
||||
rt_uint8_t pnm[5]; /* Product Name */
|
||||
rt_uint8_t reserved1;/* reserved */
|
||||
rt_uint16_t mdt; /* Manufacturing Date */
|
||||
rt_uint8_t crc; /* CID CRC */
|
||||
rt_uint8_t reserved2;/* not used, always 1 */
|
||||
};
|
||||
|
||||
struct rt_mmcsd_csd {
|
||||
rt_uint8_t csd_structure; /* CSD register version */
|
||||
rt_uint8_t taac;
|
||||
rt_uint8_t nsac;
|
||||
rt_uint8_t tran_speed; /* max data transfer rate */
|
||||
rt_uint16_t card_cmd_class; /* card command classes */
|
||||
rt_uint8_t rd_blk_len; /* max read data block length */
|
||||
rt_uint8_t rd_blk_part;
|
||||
rt_uint8_t wr_blk_misalign;
|
||||
rt_uint8_t rd_blk_misalign;
|
||||
rt_uint8_t dsr_imp; /* DSR implemented */
|
||||
rt_uint8_t c_size_mult; /* CSD 1.0 , device size multiplier */
|
||||
rt_uint32_t c_size; /* device size */
|
||||
rt_uint8_t r2w_factor;
|
||||
rt_uint8_t wr_blk_len; /* max wtire data block length */
|
||||
rt_uint8_t wr_blk_partial;
|
||||
rt_uint8_t csd_crc;
|
||||
|
||||
};
|
||||
|
||||
struct rt_sd_scr {
|
||||
rt_uint8_t sd_version;
|
||||
rt_uint8_t sd_bus_widths;
|
||||
};
|
||||
|
||||
struct rt_sdio_cccr {
|
||||
rt_uint8_t sdio_version;
|
||||
rt_uint8_t sd_version;
|
||||
rt_uint8_t direct_cmd:1, /* Card Supports Direct Commands during data transfer
|
||||
only SD mode, not used for SPI mode */
|
||||
multi_block:1, /* Card Supports Multi-Block */
|
||||
read_wait:1, /* Card Supports Read Wait
|
||||
only SD mode, not used for SPI mode */
|
||||
suspend_resume:1, /* Card supports Suspend/Resume
|
||||
only SD mode, not used for SPI mode */
|
||||
s4mi:1, /* generate interrupts during a 4-bit
|
||||
multi-block data transfer */
|
||||
e4mi:1, /* Enable the multi-block IRQ during
|
||||
4-bit transfer for the SDIO card */
|
||||
low_speed:1, /* Card is a Low-Speed card */
|
||||
low_speed_4:1; /* 4-bit support for Low-Speed cards */
|
||||
|
||||
rt_uint8_t bus_width:1, /* Support SDIO bus width, 1:4bit, 0:1bit */
|
||||
cd_disable:1, /* Connect[0]/Disconnect[1] the 10K-90K ohm pull-up
|
||||
resistor on CD/DAT[3] (pin 1) of the card */
|
||||
power_ctrl:1, /* Support Master Power Control */
|
||||
high_speed:1; /* Support High-Speed */
|
||||
|
||||
|
||||
};
|
||||
|
||||
struct rt_sdio_cis {
|
||||
rt_uint16_t manufacturer;
|
||||
rt_uint16_t product;
|
||||
rt_uint16_t func0_blk_size;
|
||||
rt_uint32_t max_tran_speed;
|
||||
};
|
||||
|
||||
/*
|
||||
* SDIO function CIS tuple (unknown to the core)
|
||||
*/
|
||||
struct rt_sdio_function_tuple {
|
||||
struct rt_sdio_function_tuple *next;
|
||||
rt_uint8_t code;
|
||||
rt_uint8_t size;
|
||||
rt_uint8_t *data;
|
||||
};
|
||||
|
||||
struct rt_sdio_function;
|
||||
typedef void (rt_sdio_irq_handler_t)(struct rt_sdio_function *);
|
||||
|
||||
/*
|
||||
* SDIO function devices
|
||||
*/
|
||||
struct rt_sdio_function {
|
||||
struct rt_mmcsd_card *card; /* the card this device belongs to */
|
||||
rt_sdio_irq_handler_t *irq_handler; /* IRQ callback */
|
||||
rt_uint8_t num; /* function number */
|
||||
|
||||
rt_uint8_t func_code; /* Standard SDIO Function interface code */
|
||||
rt_uint16_t manufacturer; /* manufacturer id */
|
||||
rt_uint16_t product; /* product id */
|
||||
|
||||
rt_uint32_t max_blk_size; /* maximum block size */
|
||||
rt_uint32_t cur_blk_size; /* current block size */
|
||||
|
||||
rt_uint32_t enable_timeout_val; /* max enable timeout in msec */
|
||||
|
||||
struct rt_sdio_function_tuple *tuples;
|
||||
};
|
||||
|
||||
#define SDIO_MAX_FUNCTIONS 7
|
||||
|
||||
|
||||
|
||||
struct rt_mmcsd_card {
|
||||
struct rt_mmcsd_host *host;
|
||||
rt_uint32_t rca; /* card addr */
|
||||
rt_uint32_t resp_cid[4]; /* card CID register */
|
||||
rt_uint32_t resp_csd[4]; /* card CSD register */
|
||||
rt_uint32_t resp_scr[2]; /* card SCR register */
|
||||
|
||||
rt_uint16_t tacc_clks; /* data access time by ns */
|
||||
rt_uint32_t tacc_ns; /* data access time by clk cycles */
|
||||
rt_uint32_t max_data_rate; /* max data transfer rate */
|
||||
rt_uint32_t card_capacity; /* card capacity, unit:KB */
|
||||
rt_uint32_t card_blksize; /* card block size */
|
||||
rt_uint16_t card_type;
|
||||
#define CARD_TYPE_MMC 0 /* MMC card */
|
||||
#define CARD_TYPE_SD 1 /* SD card */
|
||||
#define CARD_TYPE_SDIO 2 /* SDIO card */
|
||||
#define CARD_TYPE_SDIO_COMBO 3 /* SD combo (IO+mem) card */
|
||||
|
||||
rt_uint16_t flags;
|
||||
#define CARD_FLAG_HIGHSPEED (1 << 0) /* SDIO bus speed 50MHz */
|
||||
#define CARD_FLAG_SDHC (1 << 1) /* SDHC card */
|
||||
#define CARD_FLAG_SDXC (1 << 2) /* SDXC card */
|
||||
|
||||
struct rt_sd_scr scr;
|
||||
struct rt_mmcsd_csd csd;
|
||||
rt_uint32_t hs_max_data_rate; /* max data transfer rate in high speed mode */
|
||||
|
||||
rt_uint8_t sdio_function_num; /* totol number of SDIO functions */
|
||||
struct rt_sdio_cccr cccr; /* common card info */
|
||||
struct rt_sdio_cis cis; /* common tuple info */
|
||||
struct rt_sdio_function *sdio_function[SDIO_MAX_FUNCTIONS + 1]; /* SDIO functions (devices) */
|
||||
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* File : mmcsd_cmd.h
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2006, RT-Thread Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-07-25 weety first version
|
||||
*/
|
||||
|
||||
#ifndef __CMD_H__
|
||||
#define __CMD_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* class 1 */
|
||||
#define GO_IDLE_STATE 0 /* bc */
|
||||
#define SEND_OP_COND 1 /* bcr [31:0] OCR R3 */
|
||||
#define ALL_SEND_CID 2 /* bcr R2 */
|
||||
#define SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */
|
||||
#define SET_DSR 4 /* bc [31:16] RCA */
|
||||
#define SWITCH 6 /* ac [31:0] See below R1b */
|
||||
#define SELECT_CARD 7 /* ac [31:16] RCA R1 */
|
||||
#define SEND_EXT_CSD 8 /* adtc R1 */
|
||||
#define SEND_CSD 9 /* ac [31:16] RCA R2 */
|
||||
#define SEND_CID 10 /* ac [31:16] RCA R2 */
|
||||
#define READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */
|
||||
#define STOP_TRANSMISSION 12 /* ac R1b */
|
||||
#define SEND_STATUS 13 /* ac [31:16] RCA R1 */
|
||||
#define GO_INACTIVE_STATE 15 /* ac [31:16] RCA */
|
||||
#define SPI_READ_OCR 58 /* spi spi_R3 */
|
||||
#define SPI_CRC_ON_OFF 59 /* spi [0:0] flag spi_R1 */
|
||||
|
||||
/* class 2 */
|
||||
#define SET_BLOCKLEN 16 /* ac [31:0] block len R1 */
|
||||
#define READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */
|
||||
#define READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */
|
||||
|
||||
/* class 3 */
|
||||
#define WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */
|
||||
|
||||
/* class 4 */
|
||||
#define SET_BLOCK_COUNT 23 /* adtc [31:0] data addr R1 */
|
||||
#define WRITE_BLOCK 24 /* adtc [31:0] data addr R1 */
|
||||
#define WRITE_MULTIPLE_BLOCK 25 /* adtc R1 */
|
||||
#define PROGRAM_CID 26 /* adtc R1 */
|
||||
#define PROGRAM_CSD 27 /* adtc R1 */
|
||||
|
||||
/* class 6 */
|
||||
#define SET_WRITE_PROT 28 /* ac [31:0] data addr R1b */
|
||||
#define CLR_WRITE_PROT 29 /* ac [31:0] data addr R1b */
|
||||
#define SEND_WRITE_PROT 30 /* adtc [31:0] wpdata addr R1 */
|
||||
|
||||
/* class 5 */
|
||||
#define ERASE_GROUP_START 35 /* ac [31:0] data addr R1 */
|
||||
#define ERASE_GROUP_END 36 /* ac [31:0] data addr R1 */
|
||||
#define ERASE 38 /* ac R1b */
|
||||
|
||||
/* class 9 */
|
||||
#define FAST_IO 39 /* ac <Complex> R4 */
|
||||
#define GO_IRQ_STATE 40 /* bcr R5 */
|
||||
|
||||
/* class 7 */
|
||||
#define LOCK_UNLOCK 42 /* adtc R1b */
|
||||
|
||||
/* class 8 */
|
||||
#define APP_CMD 55 /* ac [31:16] RCA R1 */
|
||||
#define GEN_CMD 56 /* adtc [0] RD/WR R1 */
|
||||
|
||||
|
||||
/* SD commands type argument response */
|
||||
/* class 0 */
|
||||
/* This is basically the same command as for MMC with some quirks. */
|
||||
#define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */
|
||||
#define SD_SEND_IF_COND 8 /* bcr [11:0] See below R7 */
|
||||
|
||||
/* class 10 */
|
||||
#define SD_SWITCH 6 /* adtc [31:0] See below R1 */
|
||||
|
||||
/* Application commands */
|
||||
#define SD_APP_SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */
|
||||
#define SD_APP_SEND_NUM_WR_BLKS 22 /* adtc R1 */
|
||||
#define SD_APP_OP_COND 41 /* bcr [31:0] OCR R3 */
|
||||
#define SD_APP_SEND_SCR 51 /* adtc R1 */
|
||||
|
||||
#define SCR_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.01 */
|
||||
#define SCR_SPEC_VER_1 1 /* Implements system specification 1.10 */
|
||||
#define SCR_SPEC_VER_2 2 /* Implements system specification 2.00 */
|
||||
|
||||
|
||||
/* SDIO commands type argument response */
|
||||
#define SD_IO_SEND_OP_COND 5 /* bcr [23:0] OCR R4 */
|
||||
#define SD_IO_RW_DIRECT 52 /* ac [31:0] See below R5 */
|
||||
#define SD_IO_RW_EXTENDED 53 /* adtc [31:0] See below R5 */
|
||||
|
||||
|
||||
/* CMD52 arguments */
|
||||
#define SDIO_ARG_CMD52_READ (0<<31)
|
||||
#define SDIO_ARG_CMD52_WRITE (1u<<31)
|
||||
#define SDIO_ARG_CMD52_FUNC_SHIFT 28
|
||||
#define SDIO_ARG_CMD52_FUNC_MASK 0x7
|
||||
#define SDIO_ARG_CMD52_RAW_FLAG (1u<<27)
|
||||
#define SDIO_ARG_CMD52_REG_SHIFT 9
|
||||
#define SDIO_ARG_CMD52_REG_MASK 0x1ffff
|
||||
#define SDIO_ARG_CMD52_DATA_SHIFT 0
|
||||
#define SDIO_ARG_CMD52_DATA_MASK 0xff
|
||||
#define SDIO_R5_DATA(resp) ((resp)[0] & 0xff)
|
||||
|
||||
/* CMD53 arguments */
|
||||
#define SDIO_ARG_CMD53_READ (0<<31)
|
||||
#define SDIO_ARG_CMD53_WRITE (1u<<31)
|
||||
#define SDIO_ARG_CMD53_FUNC_SHIFT 28
|
||||
#define SDIO_ARG_CMD53_FUNC_MASK 0x7
|
||||
#define SDIO_ARG_CMD53_BLOCK_MODE (1u<<27)
|
||||
#define SDIO_ARG_CMD53_INCREMENT (1u<<26)
|
||||
#define SDIO_ARG_CMD53_REG_SHIFT 9
|
||||
#define SDIO_ARG_CMD53_REG_MASK 0x1ffff
|
||||
#define SDIO_ARG_CMD53_LENGTH_SHIFT 0
|
||||
#define SDIO_ARG_CMD53_LENGTH_MASK 0x1ff
|
||||
#define SDIO_ARG_CMD53_LENGTH_MAX 511
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+257
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* File : mmcsd_core.h
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2006, RT-Thread Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-07-25 weety first version
|
||||
*/
|
||||
|
||||
#ifndef __CORE_H__
|
||||
#define __CORE_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <drivers/mmcsd_host.h>
|
||||
#include <drivers/mmcsd_card.h>
|
||||
#include <drivers/mmcsd_cmd.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef RT_MMCSD_DBG
|
||||
#define mmcsd_dbg(fmt, ...) rt_kprintf(fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define mmcsd_dbg(fmt, ...)
|
||||
#endif
|
||||
|
||||
struct rt_mmcsd_data {
|
||||
rt_uint32_t blksize;
|
||||
rt_uint32_t blks;
|
||||
rt_uint32_t *buf;
|
||||
rt_int32_t err;
|
||||
rt_uint32_t flags;
|
||||
#define DATA_DIR_WRITE (1 << 0)
|
||||
#define DATA_DIR_READ (1 << 1)
|
||||
#define DATA_STREAM (1 << 2)
|
||||
|
||||
unsigned int bytes_xfered;
|
||||
|
||||
struct rt_mmcsd_cmd *stop; /* stop command */
|
||||
struct rt_mmcsd_req *mrq; /* associated request */
|
||||
|
||||
rt_uint32_t timeout_ns;
|
||||
rt_uint32_t timeout_clks;
|
||||
};
|
||||
|
||||
struct rt_mmcsd_cmd {
|
||||
rt_uint32_t cmd_code;
|
||||
rt_uint32_t arg;
|
||||
rt_uint32_t resp[4];
|
||||
rt_uint32_t flags;
|
||||
/*rsponse types
|
||||
*bits:0~3
|
||||
*/
|
||||
#define RESP_MASK (0xF)
|
||||
#define RESP_NONE (0)
|
||||
#define RESP_R1 (1 << 0)
|
||||
#define RESP_R1B (2 << 0)
|
||||
#define RESP_R2 (3 << 0)
|
||||
#define RESP_R3 (4 << 0)
|
||||
#define RESP_R4 (5 << 0)
|
||||
#define RESP_R6 (6 << 0)
|
||||
#define RESP_R7 (7 << 0)
|
||||
#define RESP_R5 (8 << 0) /*SDIO command response type*/
|
||||
/*command types
|
||||
*bits:4~5
|
||||
*/
|
||||
#define CMD_MASK (3 << 4) /* command type */
|
||||
#define CMD_AC (0 << 4)
|
||||
#define CMD_ADTC (1 << 4)
|
||||
#define CMD_BC (2 << 4)
|
||||
#define CMD_BCR (3 << 4)
|
||||
|
||||
#define resp_type(cmd) ((cmd)->flags & RESP_MASK)
|
||||
|
||||
/*spi rsponse types
|
||||
*bits:6~8
|
||||
*/
|
||||
#define RESP_SPI_MASK (0x7 << 6)
|
||||
#define RESP_SPI_R1 (1 << 6)
|
||||
#define RESP_SPI_R1B (2 << 6)
|
||||
#define RESP_SPI_R2 (3 << 6)
|
||||
#define RESP_SPI_R3 (4 << 6)
|
||||
#define RESP_SPI_R4 (5 << 6)
|
||||
#define RESP_SPI_R5 (6 << 6)
|
||||
#define RESP_SPI_R7 (7 << 6)
|
||||
|
||||
#define spi_resp_type(cmd) ((cmd)->flags & RESP_SPI_MASK)
|
||||
/*
|
||||
* These are the command types.
|
||||
*/
|
||||
#define cmd_type(cmd) ((cmd)->flags & CMD_MASK)
|
||||
|
||||
rt_int32_t retries; /* max number of retries */
|
||||
rt_int32_t err;
|
||||
|
||||
struct rt_mmcsd_data *data;
|
||||
struct rt_mmcsd_req *mrq; /* associated request */
|
||||
};
|
||||
|
||||
struct rt_mmcsd_req {
|
||||
struct rt_mmcsd_data *data;
|
||||
struct rt_mmcsd_cmd *cmd;
|
||||
struct rt_mmcsd_cmd *stop;
|
||||
};
|
||||
|
||||
/*the following is response bit*/
|
||||
#define R1_OUT_OF_RANGE (1 << 31) /* er, c */
|
||||
#define R1_ADDRESS_ERROR (1 << 30) /* erx, c */
|
||||
#define R1_BLOCK_LEN_ERROR (1 << 29) /* er, c */
|
||||
#define R1_ERASE_SEQ_ERROR (1 << 28) /* er, c */
|
||||
#define R1_ERASE_PARAM (1 << 27) /* ex, c */
|
||||
#define R1_WP_VIOLATION (1 << 26) /* erx, c */
|
||||
#define R1_CARD_IS_LOCKED (1 << 25) /* sx, a */
|
||||
#define R1_LOCK_UNLOCK_FAILED (1 << 24) /* erx, c */
|
||||
#define R1_COM_CRC_ERROR (1 << 23) /* er, b */
|
||||
#define R1_ILLEGAL_COMMAND (1 << 22) /* er, b */
|
||||
#define R1_CARD_ECC_FAILED (1 << 21) /* ex, c */
|
||||
#define R1_CC_ERROR (1 << 20) /* erx, c */
|
||||
#define R1_ERROR (1 << 19) /* erx, c */
|
||||
#define R1_UNDERRUN (1 << 18) /* ex, c */
|
||||
#define R1_OVERRUN (1 << 17) /* ex, c */
|
||||
#define R1_CID_CSD_OVERWRITE (1 << 16) /* erx, c, CID/CSD overwrite */
|
||||
#define R1_WP_ERASE_SKIP (1 << 15) /* sx, c */
|
||||
#define R1_CARD_ECC_DISABLED (1 << 14) /* sx, a */
|
||||
#define R1_ERASE_RESET (1 << 13) /* sr, c */
|
||||
#define R1_STATUS(x) (x & 0xFFFFE000)
|
||||
#define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */
|
||||
#define R1_READY_FOR_DATA (1 << 8) /* sx, a */
|
||||
#define R1_APP_CMD (1 << 5) /* sr, c */
|
||||
|
||||
|
||||
#define R1_SPI_IDLE (1 << 0)
|
||||
#define R1_SPI_ERASE_RESET (1 << 1)
|
||||
#define R1_SPI_ILLEGAL_COMMAND (1 << 2)
|
||||
#define R1_SPI_COM_CRC (1 << 3)
|
||||
#define R1_SPI_ERASE_SEQ (1 << 4)
|
||||
#define R1_SPI_ADDRESS (1 << 5)
|
||||
#define R1_SPI_PARAMETER (1 << 6)
|
||||
/* R1 bit 7 is always zero */
|
||||
#define R2_SPI_CARD_LOCKED (1 << 8)
|
||||
#define R2_SPI_WP_ERASE_SKIP (1 << 9) /* or lock/unlock fail */
|
||||
#define R2_SPI_LOCK_UNLOCK_FAIL R2_SPI_WP_ERASE_SKIP
|
||||
#define R2_SPI_ERROR (1 << 10)
|
||||
#define R2_SPI_CC_ERROR (1 << 11)
|
||||
#define R2_SPI_CARD_ECC_ERROR (1 << 12)
|
||||
#define R2_SPI_WP_VIOLATION (1 << 13)
|
||||
#define R2_SPI_ERASE_PARAM (1 << 14)
|
||||
#define R2_SPI_OUT_OF_RANGE (1 << 15) /* or CSD overwrite */
|
||||
#define R2_SPI_CSD_OVERWRITE R2_SPI_OUT_OF_RANGE
|
||||
|
||||
#define CARD_BUSY 0x80000000 /* Card Power up status bit */
|
||||
|
||||
/* R5 response bits */
|
||||
#define R5_COM_CRC_ERROR (1 << 15)
|
||||
#define R5_ILLEGAL_COMMAND (1 << 14)
|
||||
#define R5_ERROR (1 << 11)
|
||||
#define R5_FUNCTION_NUMBER (1 << 9)
|
||||
#define R5_OUT_OF_RANGE (1 << 8)
|
||||
#define R5_STATUS(x) (x & 0xCB00)
|
||||
#define R5_IO_CURRENT_STATE(x) ((x & 0x3000) >> 12)
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* fls - find last (most-significant) bit set
|
||||
* @x: the word to search
|
||||
*
|
||||
* This is defined the same way as ffs.
|
||||
* Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
|
||||
*/
|
||||
|
||||
rt_inline rt_uint32_t fls(rt_uint32_t val)
|
||||
{
|
||||
rt_uint32_t bit = 32;
|
||||
|
||||
if (!val)
|
||||
return 0;
|
||||
if (!(val & 0xffff0000u))
|
||||
{
|
||||
val <<= 16;
|
||||
bit -= 16;
|
||||
}
|
||||
if (!(val & 0xff000000u))
|
||||
{
|
||||
val <<= 8;
|
||||
bit -= 8;
|
||||
}
|
||||
if (!(val & 0xf0000000u))
|
||||
{
|
||||
val <<= 4;
|
||||
bit -= 4;
|
||||
}
|
||||
if (!(val & 0xc0000000u))
|
||||
{
|
||||
val <<= 2;
|
||||
bit -= 2;
|
||||
}
|
||||
if (!(val & 0x80000000u))
|
||||
{
|
||||
val <<= 1;
|
||||
bit -= 1;
|
||||
}
|
||||
|
||||
return bit;
|
||||
}
|
||||
|
||||
void mmcsd_host_lock(struct rt_mmcsd_host *host);
|
||||
void mmcsd_host_unlock(struct rt_mmcsd_host *host);
|
||||
void mmcsd_req_complete(struct rt_mmcsd_host *host);
|
||||
void mmcsd_send_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req);
|
||||
rt_int32_t mmcsd_send_cmd(struct rt_mmcsd_host *host, struct rt_mmcsd_cmd *cmd, int retries);
|
||||
rt_int32_t mmcsd_go_idle(struct rt_mmcsd_host *host);
|
||||
rt_int32_t mmcsd_spi_read_ocr(struct rt_mmcsd_host *host, rt_int32_t high_capacity, rt_uint32_t *ocr);
|
||||
rt_int32_t mmcsd_all_get_cid(struct rt_mmcsd_host *host, rt_uint32_t *cid);
|
||||
rt_int32_t mmcsd_get_cid(struct rt_mmcsd_host *host, rt_uint32_t *cid);
|
||||
rt_int32_t mmcsd_get_csd(struct rt_mmcsd_card *card, rt_uint32_t *csd);
|
||||
rt_int32_t mmcsd_select_card(struct rt_mmcsd_card *card);
|
||||
rt_int32_t mmcsd_deselect_cards(struct rt_mmcsd_card *host);
|
||||
rt_int32_t mmcsd_spi_use_crc(struct rt_mmcsd_host *host, rt_int32_t use_crc);
|
||||
void mmcsd_set_chip_select(struct rt_mmcsd_host *host, rt_int32_t mode);
|
||||
void mmcsd_set_clock(struct rt_mmcsd_host *host, rt_uint32_t clk);
|
||||
void mmcsd_set_bus_mode(struct rt_mmcsd_host *host, rt_uint32_t mode);
|
||||
void mmcsd_set_bus_width(struct rt_mmcsd_host *host, rt_uint32_t width);
|
||||
void mmcsd_set_data_timeout(struct rt_mmcsd_data *data, const struct rt_mmcsd_card *card);
|
||||
rt_uint32_t mmcsd_select_voltage(struct rt_mmcsd_host *host, rt_uint32_t ocr);
|
||||
void mmcsd_change(struct rt_mmcsd_host *host);
|
||||
void mmcsd_detect(void *param);
|
||||
struct rt_mmcsd_host *mmcsd_alloc_host(void);
|
||||
void mmcsd_free_host(struct rt_mmcsd_host *host);
|
||||
void rt_mmcsd_core_init(void);
|
||||
|
||||
void rt_mmcsd_blk_init(void);
|
||||
rt_int32_t rt_mmcsd_blk_probe(struct rt_mmcsd_card *card);
|
||||
void rt_mmcsd_blk_remove(struct rt_mmcsd_card *card);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* File : mmcsd_host.h
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2006, RT-Thread Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-07-25 weety first version
|
||||
*/
|
||||
|
||||
#ifndef __HOST_H__
|
||||
#define __HOST_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct rt_mmcsd_io_cfg {
|
||||
rt_uint32_t clock; /* clock rate */
|
||||
rt_uint16_t vdd;
|
||||
|
||||
/* vdd stores the bit number of the selected voltage range from below. */
|
||||
|
||||
rt_uint8_t bus_mode; /* command output mode */
|
||||
|
||||
#define MMCSD_BUSMODE_OPENDRAIN 1
|
||||
#define MMCSD_BUSMODE_PUSHPULL 2
|
||||
|
||||
rt_uint8_t chip_select; /* SPI chip select */
|
||||
|
||||
#define MMCSD_CS_IGNORE 0
|
||||
#define MMCSD_CS_HIGH 1
|
||||
#define MMCSD_CS_LOW 2
|
||||
|
||||
rt_uint8_t power_mode; /* power supply mode */
|
||||
|
||||
#define MMCSD_POWER_OFF 0
|
||||
#define MMCSD_POWER_UP 1
|
||||
#define MMCSD_POWER_ON 2
|
||||
|
||||
rt_uint8_t bus_width; /* data bus width */
|
||||
|
||||
#define MMCSD_BUS_WIDTH_1 0
|
||||
#define MMCSD_BUS_WIDTH_4 2
|
||||
#define MMCSD_BUS_WIDTH_8 3
|
||||
|
||||
};
|
||||
|
||||
struct rt_mmcsd_host;
|
||||
struct rt_mmcsd_req;
|
||||
|
||||
struct rt_mmcsd_host_ops {
|
||||
void (*request)(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req);
|
||||
void (*set_iocfg)(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg);
|
||||
rt_int32_t (*get_card_status)(struct rt_mmcsd_host *host);
|
||||
void (*enable_sdio_irq)(struct rt_mmcsd_host *host, rt_int32_t en);
|
||||
};
|
||||
|
||||
struct rt_mmcsd_host {
|
||||
struct rt_mmcsd_card *card;
|
||||
const struct rt_mmcsd_host_ops *ops;
|
||||
rt_uint32_t freq_min;
|
||||
rt_uint32_t freq_max;
|
||||
struct rt_mmcsd_io_cfg io_cfg;
|
||||
rt_uint32_t valid_ocr; /* current valid OCR */
|
||||
#define VDD_165_195 (1 << 7) /* VDD voltage 1.65 - 1.95 */
|
||||
#define VDD_20_21 (1 << 8) /* VDD voltage 2.0 ~ 2.1 */
|
||||
#define VDD_21_22 (1 << 9) /* VDD voltage 2.1 ~ 2.2 */
|
||||
#define VDD_22_23 (1 << 10) /* VDD voltage 2.2 ~ 2.3 */
|
||||
#define VDD_23_24 (1 << 11) /* VDD voltage 2.3 ~ 2.4 */
|
||||
#define VDD_24_25 (1 << 12) /* VDD voltage 2.4 ~ 2.5 */
|
||||
#define VDD_25_26 (1 << 13) /* VDD voltage 2.5 ~ 2.6 */
|
||||
#define VDD_26_27 (1 << 14) /* VDD voltage 2.6 ~ 2.7 */
|
||||
#define VDD_27_28 (1 << 15) /* VDD voltage 2.7 ~ 2.8 */
|
||||
#define VDD_28_29 (1 << 16) /* VDD voltage 2.8 ~ 2.9 */
|
||||
#define VDD_29_30 (1 << 17) /* VDD voltage 2.9 ~ 3.0 */
|
||||
#define VDD_30_31 (1 << 18) /* VDD voltage 3.0 ~ 3.1 */
|
||||
#define VDD_31_32 (1 << 19) /* VDD voltage 3.1 ~ 3.2 */
|
||||
#define VDD_32_33 (1 << 20) /* VDD voltage 3.2 ~ 3.3 */
|
||||
#define VDD_33_34 (1 << 21) /* VDD voltage 3.3 ~ 3.4 */
|
||||
#define VDD_34_35 (1 << 22) /* VDD voltage 3.4 ~ 3.5 */
|
||||
#define VDD_35_36 (1 << 23) /* VDD voltage 3.5 ~ 3.6 */
|
||||
rt_uint32_t flags; /* define device capabilities */
|
||||
#define MMCSD_BUSWIDTH_4 (1 << 0)
|
||||
#define MMCSD_BUSWIDTH_8 (1 << 1)
|
||||
#define MMCSD_MUTBLKWRITE (1 << 2)
|
||||
#define MMCSD_HOST_IS_SPI (1 << 3)
|
||||
#define controller_is_spi(host) (host->flags & MMCSD_HOST_IS_SPI)
|
||||
#define MMCSD_SUP_SDIO_IRQ (1 << 4) /* support signal pending SDIO IRQs */
|
||||
#define MMCSD_SUP_HIGHSPEED (1 << 5) /* support high speed */
|
||||
|
||||
rt_uint32_t max_seg_size; /* maximum size of one dma segment */
|
||||
rt_uint32_t max_dma_segs; /* maximum number of dma segments in one request */
|
||||
rt_uint32_t max_blk_size; /* maximum block size */
|
||||
rt_uint32_t max_blk_count; /* maximum block count */
|
||||
|
||||
rt_uint32_t spi_use_crc;
|
||||
struct rt_semaphore bus_lock;
|
||||
struct rt_semaphore sem_ack;
|
||||
|
||||
rt_uint32_t sdio_irq_num;
|
||||
struct rt_semaphore *sdio_irq_sem;
|
||||
struct rt_thread *sdio_irq_thread;
|
||||
|
||||
void *private_data;
|
||||
};
|
||||
|
||||
rt_inline void mmcsd_delay_ms(rt_uint32_t ms)
|
||||
{
|
||||
if (ms < 1000 / RT_TICK_PER_SECOND)
|
||||
{
|
||||
rt_thread_delay(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_thread_delay(ms/(1000 / RT_TICK_PER_SECOND));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* File : mtd_nand.h
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-12-05 Bernard the first version
|
||||
* 2011-04-02 prife add mark_badblock and check_block
|
||||
*/
|
||||
|
||||
/*
|
||||
* COPYRIGHT (C) 2012, Shanghai Real Thread
|
||||
*/
|
||||
|
||||
#ifndef __MTD_NAND_H__
|
||||
#define __MTD_NAND_H__
|
||||
|
||||
#include <rtdevice.h>
|
||||
|
||||
struct rt_mtd_nand_driver_ops;
|
||||
#define RT_MTD_NAND_DEVICE(device) ((struct rt_mtd_nand_device*)(device))
|
||||
|
||||
#define RT_MTD_EOK 0 /* NO error */
|
||||
#define RT_MTD_EECC 1 /* ECC error */
|
||||
#define RT_MTD_EBUSY 2 /* hardware busy */
|
||||
#define RT_MTD_EIO 3 /* generic IO issue */
|
||||
#define RT_MTD_ENOMEM 4 /* out of memory */
|
||||
#define RT_MTD_ESRC 5 /* source issue */
|
||||
|
||||
struct rt_mtd_nand_device
|
||||
{
|
||||
struct rt_device parent;
|
||||
|
||||
rt_uint16_t page_size; /* The Page size in the flash */
|
||||
rt_uint16_t oob_size; /* Out of bank size */
|
||||
rt_uint16_t oob_free; /* the free area in oob that flash driver not use */
|
||||
rt_uint16_t plane_num; /* the number of plane in the NAND Flash */
|
||||
|
||||
rt_uint32_t pages_per_block; /* The number of page a block */
|
||||
rt_uint16_t block_total;
|
||||
|
||||
rt_uint32_t block_start; /* The start of available block*/
|
||||
rt_uint32_t block_end; /* The end of available block */
|
||||
|
||||
/* operations interface */
|
||||
const struct rt_mtd_nand_driver_ops* ops;
|
||||
};
|
||||
|
||||
struct rt_mtd_nand_driver_ops
|
||||
{
|
||||
rt_err_t (*read_id) (struct rt_mtd_nand_device* device);
|
||||
|
||||
rt_err_t (*read_page)(struct rt_mtd_nand_device* device,
|
||||
rt_off_t page,
|
||||
rt_uint8_t* data, rt_uint32_t data_len,
|
||||
rt_uint8_t * spare, rt_uint32_t spare_len);
|
||||
|
||||
rt_err_t (*write_page)(struct rt_mtd_nand_device * device,
|
||||
rt_off_t page,
|
||||
const rt_uint8_t * data, rt_uint32_t data_len,
|
||||
const rt_uint8_t * spare, rt_uint32_t spare_len);
|
||||
rt_err_t (*move_page) (struct rt_mtd_nand_device *device, rt_off_t src_page, rt_off_t dst_page);
|
||||
|
||||
rt_err_t (*erase_block)(struct rt_mtd_nand_device* device, rt_uint32_t block);
|
||||
rt_err_t (*check_block)(struct rt_mtd_nand_device* device, rt_uint32_t block);
|
||||
rt_err_t (*mark_badblock)(struct rt_mtd_nand_device* device, rt_uint32_t block);
|
||||
};
|
||||
|
||||
rt_err_t rt_mtd_nand_register_device(const char* name, struct rt_mtd_nand_device* device);
|
||||
|
||||
rt_inline rt_uint32_t rt_mtd_nand_read_id(struct rt_mtd_nand_device* device)
|
||||
{
|
||||
return device->ops->read_id(device);
|
||||
}
|
||||
|
||||
rt_inline rt_err_t rt_mtd_nand_read(
|
||||
struct rt_mtd_nand_device* device,
|
||||
rt_off_t page,
|
||||
rt_uint8_t* data, rt_uint32_t data_len,
|
||||
rt_uint8_t * spare, rt_uint32_t spare_len)
|
||||
{
|
||||
return device->ops->read_page(device, page, data, data_len, spare, spare_len);
|
||||
}
|
||||
|
||||
rt_inline rt_err_t rt_mtd_nand_write(
|
||||
struct rt_mtd_nand_device* device,
|
||||
rt_off_t page,
|
||||
const rt_uint8_t* data, rt_uint32_t data_len,
|
||||
const rt_uint8_t * spare, rt_uint32_t spare_len)
|
||||
{
|
||||
return device->ops->write_page(device, page, data, data_len, spare, spare_len);
|
||||
}
|
||||
|
||||
rt_inline rt_err_t rt_mtd_nand_move_page(struct rt_mtd_nand_device* device,
|
||||
rt_off_t src_page, rt_off_t dst_page)
|
||||
{
|
||||
return device->ops->move_page(device, src_page, dst_page);
|
||||
}
|
||||
|
||||
rt_inline rt_err_t rt_mtd_nand_erase_block(struct rt_mtd_nand_device* device, rt_uint32_t block)
|
||||
{
|
||||
return device->ops->erase_block(device, block);
|
||||
}
|
||||
|
||||
rt_inline rt_err_t rt_mtd_nand_check_block(struct rt_mtd_nand_device* device, rt_uint32_t block)
|
||||
{
|
||||
return device->ops->check_block(device, block);
|
||||
}
|
||||
|
||||
rt_inline rt_err_t rt_mtd_nand_mark_badblock(struct rt_mtd_nand_device* device, rt_uint32_t block)
|
||||
{
|
||||
return device->ops->mark_badblock(device, block);
|
||||
}
|
||||
|
||||
#endif /* MTD_NAND_H_ */
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* File : mtd_nor.h
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2012, Shanghai Real-Thread Technology Co., Ltd
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-5-30 Bernard the first version
|
||||
*/
|
||||
|
||||
#ifndef __MTD_NOR_H__
|
||||
#define __MTD_NOR_H__
|
||||
|
||||
#include <rtdevice.h>
|
||||
|
||||
struct rt_mtd_nor_driver_ops;
|
||||
#define RT_MTD_NOR_DEVICE(device) ((struct rt_mtd_nor_device*)(device))
|
||||
|
||||
struct rt_mtd_nor_device
|
||||
{
|
||||
struct rt_device parent;
|
||||
|
||||
rt_uint32_t block_size; /* The Block size in the flash */
|
||||
rt_uint32_t block_start; /* The start of available block*/
|
||||
rt_uint32_t block_end; /* The end of available block */
|
||||
|
||||
/* operations interface */
|
||||
const struct rt_mtd_nor_driver_ops* ops;
|
||||
};
|
||||
|
||||
struct rt_mtd_nor_driver_ops
|
||||
{
|
||||
rt_err_t (*read_id) (struct rt_mtd_nor_device* device);
|
||||
|
||||
rt_size_t (*read) (struct rt_mtd_nor_device* device, rt_off_t offset, rt_uint8_t* data, rt_uint32_t length);
|
||||
rt_size_t (*write) (struct rt_mtd_nor_device* device, rt_off_t offset, const rt_uint8_t* data, rt_uint32_t length);
|
||||
|
||||
rt_err_t (*erase_block)(struct rt_mtd_nor_device* device, rt_off_t offset, rt_uint32_t length);
|
||||
};
|
||||
|
||||
rt_err_t rt_mtd_nor_register_device(const char* name, struct rt_mtd_nor_device* device);
|
||||
|
||||
rt_inline rt_uint32_t rt_mtd_nor_read_id(struct rt_mtd_nor_device* device)
|
||||
{
|
||||
return device->ops->read_id(device);
|
||||
}
|
||||
|
||||
rt_inline rt_size_t rt_mtd_nor_read(
|
||||
struct rt_mtd_nor_device* device,
|
||||
rt_off_t offset, rt_uint8_t* data, rt_uint32_t length)
|
||||
{
|
||||
return device->ops->read(device, offset, data, length);
|
||||
}
|
||||
|
||||
rt_inline rt_size_t rt_mtd_nor_write(
|
||||
struct rt_mtd_nor_device* device,
|
||||
rt_off_t offset, const rt_uint8_t* data, rt_uint32_t length)
|
||||
{
|
||||
return device->ops->write(device, offset, data, length);
|
||||
}
|
||||
|
||||
rt_inline rt_err_t rt_mtd_nor_erase_block(struct rt_mtd_nor_device* device, rt_off_t offset, rt_size_t length)
|
||||
{
|
||||
return device->ops->erase_block(device, offset, length);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* File : rtc.h
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-10-10 aozima first version.
|
||||
*/
|
||||
|
||||
#ifndef RTC_H_INCLUDED
|
||||
#define RTC_H_INCLUDED
|
||||
|
||||
extern rt_err_t set_date(rt_uint32_t year,
|
||||
rt_uint32_t month,
|
||||
rt_uint32_t day);
|
||||
|
||||
extern rt_err_t set_time(rt_uint32_t hour,
|
||||
rt_uint32_t minute,
|
||||
rt_uint32_t second);
|
||||
|
||||
#endif // RTC_H_INCLUDED
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* File : sd.h
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2006, RT-Thread Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-07-25 weety first version
|
||||
*/
|
||||
|
||||
#ifndef __SD_H__
|
||||
#define __SD_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <drivers/mmcsd_host.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
rt_err_t mmcsd_send_if_cond(struct rt_mmcsd_host *host, rt_uint32_t ocr);
|
||||
rt_err_t mmcsd_send_app_op_cond(struct rt_mmcsd_host *host, rt_uint32_t ocr, rt_uint32_t *rocr);
|
||||
rt_int32_t init_sd(struct rt_mmcsd_host *host, rt_uint32_t ocr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+236
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
* File : sdio.h
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2006, RT-Thread Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-01-15 weety first version
|
||||
*/
|
||||
|
||||
#ifndef __SDIO_H__
|
||||
#define __SDIO_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <drivers/mmcsd_host.h>
|
||||
#include <drivers/mmcsd_card.h>
|
||||
#include <drivers/sdio_func_ids.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Card Common Control Registers (CCCR)
|
||||
*/
|
||||
|
||||
#define SDIO_REG_CCCR_CCCR_REV 0x00
|
||||
|
||||
#define SDIO_CCCR_REV_1_00 0 /* CCCR/FBR Version 1.00 */
|
||||
#define SDIO_CCCR_REV_1_10 1 /* CCCR/FBR Version 1.10 */
|
||||
#define SDIO_CCCR_REV_1_20 2 /* CCCR/FBR Version 1.20 */
|
||||
|
||||
#define SDIO_SDIO_REV_1_00 0 /* SDIO Spec Version 1.00 */
|
||||
#define SDIO_SDIO_REV_1_10 1 /* SDIO Spec Version 1.10 */
|
||||
#define SDIO_SDIO_REV_1_20 2 /* SDIO Spec Version 1.20 */
|
||||
#define SDIO_SDIO_REV_2_00 3 /* SDIO Spec Version 2.00 */
|
||||
|
||||
#define SDIO_REG_CCCR_SD_REV 0x01
|
||||
|
||||
#define SDIO_SD_REV_1_01 0 /* SD Physical Spec Version 1.01 */
|
||||
#define SDIO_SD_REV_1_10 1 /* SD Physical Spec Version 1.10 */
|
||||
#define SDIO_SD_REV_2_00 2 /* SD Physical Spec Version 2.00 */
|
||||
|
||||
#define SDIO_REG_CCCR_IO_EN 0x02
|
||||
#define SDIO_REG_CCCR_IO_RDY 0x03
|
||||
|
||||
#define SDIO_REG_CCCR_INT_EN 0x04 /* Function/Master Interrupt Enable */
|
||||
#define SDIO_REG_CCCR_INT_PEND 0x05 /* Function Interrupt Pending */
|
||||
|
||||
#define SDIO_REG_CCCR_IO_ABORT 0x06 /* function abort/card reset */
|
||||
|
||||
#define SDIO_REG_CCCR_BUS_IF 0x07 /* bus interface controls */
|
||||
|
||||
#define SDIO_BUS_WIDTH_1BIT 0x00
|
||||
#define SDIO_BUS_WIDTH_4BIT 0x02
|
||||
#define SDIO_BUS_ECSI 0x20 /* Enable continuous SPI interrupt */
|
||||
#define SDIO_BUS_SCSI 0x40 /* Support continuous SPI interrupt */
|
||||
|
||||
#define SDIO_BUS_ASYNC_INT 0x20
|
||||
|
||||
#define SDIO_BUS_CD_DISABLE 0x80 /* disable pull-up on DAT3 (pin 1) */
|
||||
|
||||
#define SDIO_REG_CCCR_CARD_CAPS 0x08
|
||||
|
||||
#define SDIO_CCCR_CAP_SDC 0x01 /* can do CMD52 while data transfer */
|
||||
#define SDIO_CCCR_CAP_SMB 0x02 /* can do multi-block xfers (CMD53) */
|
||||
#define SDIO_CCCR_CAP_SRW 0x04 /* supports read-wait protocol */
|
||||
#define SDIO_CCCR_CAP_SBS 0x08 /* supports suspend/resume */
|
||||
#define SDIO_CCCR_CAP_S4MI 0x10 /* interrupt during 4-bit CMD53 */
|
||||
#define SDIO_CCCR_CAP_E4MI 0x20 /* enable ints during 4-bit CMD53 */
|
||||
#define SDIO_CCCR_CAP_LSC 0x40 /* low speed card */
|
||||
#define SDIO_CCCR_CAP_4BLS 0x80 /* 4 bit low speed card */
|
||||
|
||||
#define SDIO_REG_CCCR_CIS_PTR 0x09 /* common CIS pointer (3 bytes) */
|
||||
|
||||
/* Following 4 regs are valid only if SBS is set */
|
||||
#define SDIO_REG_CCCR_BUS_SUSPEND 0x0c
|
||||
#define SDIO_REG_CCCR_FUNC_SEL 0x0d
|
||||
#define SDIO_REG_CCCR_EXEC_FLAG 0x0e
|
||||
#define SDIO_REG_CCCR_READY_FLAG 0x0f
|
||||
|
||||
#define SDIO_REG_CCCR_FN0_BLKSIZE 0x10 /* 2bytes, 0x10~0x11 */
|
||||
|
||||
#define SDIO_REG_CCCR_POWER_CTRL 0x12
|
||||
|
||||
#define SDIO_POWER_SMPC 0x01 /* Supports Master Power Control */
|
||||
#define SDIO_POWER_EMPC 0x02 /* Enable Master Power Control */
|
||||
|
||||
#define SDIO_REG_CCCR_SPEED 0x13
|
||||
|
||||
#define SDIO_SPEED_SHS 0x01 /* Supports High-Speed mode */
|
||||
#define SDIO_SPEED_EHS 0x02 /* Enable High-Speed mode */
|
||||
|
||||
/*
|
||||
* Function Basic Registers (FBR)
|
||||
*/
|
||||
|
||||
#define SDIO_REG_FBR_BASE(f) ((f) * 0x100) /* base of function f's FBRs */
|
||||
|
||||
#define SDIO_REG_FBR_STD_FUNC_IF 0x00
|
||||
|
||||
#define SDIO_FBR_SUPPORTS_CSA 0x40 /* supports Code Storage Area */
|
||||
#define SDIO_FBR_ENABLE_CSA 0x80 /* enable Code Storage Area */
|
||||
|
||||
#define SDIO_REG_FBR_STD_IF_EXT 0x01
|
||||
|
||||
#define SDIO_REG_FBR_POWER 0x02
|
||||
|
||||
#define SDIO_FBR_POWER_SPS 0x01 /* Supports Power Selection */
|
||||
#define SDIO_FBR_POWER_EPS 0x02 /* Enable (low) Power Selection */
|
||||
|
||||
#define SDIO_REG_FBR_CIS 0x09 /* CIS pointer (3 bytes) */
|
||||
|
||||
|
||||
#define SDIO_REG_FBR_CSA 0x0C /* CSA pointer (3 bytes) */
|
||||
|
||||
#define SDIO_REG_FBR_CSA_DATA 0x0F
|
||||
|
||||
#define SDIO_REG_FBR_BLKSIZE 0x10 /* block size (2 bytes) */
|
||||
|
||||
/* SDIO CIS Tuple code */
|
||||
#define CISTPL_NULL 0x00
|
||||
#define CISTPL_CHECKSUM 0x10
|
||||
#define CISTPL_VERS_1 0x15
|
||||
#define CISTPL_ALTSTR 0x16
|
||||
#define CISTPL_MANFID 0x20
|
||||
#define CISTPL_FUNCID 0x21
|
||||
#define CISTPL_FUNCE 0x22
|
||||
#define CISTPL_SDIO_STD 0x91
|
||||
#define CISTPL_SDIO_EXT 0x92
|
||||
#define CISTPL_END 0xff
|
||||
|
||||
/* SDIO device id */
|
||||
#define SDIO_ANY_FUNC_ID 0xff
|
||||
#define SDIO_ANY_MAN_ID 0xffff
|
||||
#define SDIO_ANY_PROD_ID 0xffff
|
||||
|
||||
struct rt_sdio_device_id
|
||||
{
|
||||
rt_uint8_t func_code;
|
||||
rt_uint16_t manufacturer;
|
||||
rt_uint16_t product;
|
||||
};
|
||||
|
||||
struct rt_sdio_driver
|
||||
{
|
||||
char *name;
|
||||
rt_int32_t (*probe)(struct rt_mmcsd_card *card);
|
||||
rt_int32_t (*remove)(struct rt_mmcsd_card *card);
|
||||
struct rt_sdio_device_id *id;
|
||||
};
|
||||
|
||||
rt_int32_t sdio_io_send_op_cond(struct rt_mmcsd_host *host,
|
||||
rt_uint32_t ocr,
|
||||
rt_uint32_t *cmd5_resp);
|
||||
rt_int32_t sdio_io_rw_direct(struct rt_mmcsd_card *card,
|
||||
rt_int32_t rw,
|
||||
rt_uint32_t fn,
|
||||
rt_uint32_t reg_addr,
|
||||
rt_uint8_t *pdata,
|
||||
rt_uint8_t raw);
|
||||
rt_int32_t sdio_io_rw_extended(struct rt_mmcsd_card *card,
|
||||
rt_int32_t rw,
|
||||
rt_uint32_t fn,
|
||||
rt_uint32_t addr,
|
||||
rt_int32_t op_code,
|
||||
rt_uint8_t *buf,
|
||||
rt_uint32_t blocks,
|
||||
rt_uint32_t blksize);
|
||||
rt_uint8_t sdio_io_readb(struct rt_sdio_function *func,
|
||||
rt_uint32_t reg,
|
||||
rt_int32_t *err);
|
||||
rt_int32_t sdio_io_writeb(struct rt_sdio_function *func,
|
||||
rt_uint32_t reg,
|
||||
rt_uint8_t data);
|
||||
rt_uint16_t sdio_io_readw(struct rt_sdio_function *func,
|
||||
rt_uint32_t addr,
|
||||
rt_int32_t *err);
|
||||
rt_int32_t sdio_io_writew(struct rt_sdio_function *func,
|
||||
rt_uint16_t data,
|
||||
rt_uint32_t addr);
|
||||
rt_uint32_t sdio_io_readl(struct rt_sdio_function *func,
|
||||
rt_uint32_t addr,
|
||||
rt_int32_t *err);
|
||||
rt_int32_t sdio_io_writel(struct rt_sdio_function *func,
|
||||
rt_uint32_t data,
|
||||
rt_uint32_t addr);
|
||||
rt_int32_t sdio_io_read_multi_fifo_b(struct rt_sdio_function *func,
|
||||
rt_uint32_t addr,
|
||||
rt_uint8_t *buf,
|
||||
rt_uint32_t len);
|
||||
rt_int32_t sdio_io_write_multi_fifo_b(struct rt_sdio_function *func,
|
||||
rt_uint32_t addr,
|
||||
rt_uint8_t *buf,
|
||||
rt_uint32_t len);
|
||||
rt_int32_t sdio_io_read_multi_incr_b(struct rt_sdio_function *func,
|
||||
rt_uint32_t addr,
|
||||
rt_uint8_t *buf,
|
||||
rt_uint32_t len);
|
||||
rt_int32_t sdio_io_write_multi_incr_b(struct rt_sdio_function *func,
|
||||
rt_uint32_t addr,
|
||||
rt_uint8_t *buf,
|
||||
rt_uint32_t len);
|
||||
rt_int32_t init_sdio(struct rt_mmcsd_host *host, rt_uint32_t ocr);
|
||||
rt_int32_t sdio_attach_irq(struct rt_sdio_function *func,
|
||||
rt_sdio_irq_handler_t *handler);
|
||||
rt_int32_t sdio_detach_irq(struct rt_sdio_function *func);
|
||||
void sdio_irq_wakeup(struct rt_mmcsd_host *host);
|
||||
rt_int32_t sdio_enable_func(struct rt_sdio_function *func);
|
||||
rt_int32_t sdio_disable_func(struct rt_sdio_function *func);
|
||||
rt_int32_t sdio_set_block_size(struct rt_sdio_function *func,
|
||||
rt_uint32_t blksize);
|
||||
rt_int32_t sdio_register_driver(struct rt_sdio_driver *driver);
|
||||
rt_int32_t sdio_unregister_driver(struct rt_sdio_driver *driver);
|
||||
void rt_sdio_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* File : sdio_func_ids.h
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2006, RT-Thread Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-02-26 weety first version
|
||||
*/
|
||||
|
||||
#ifndef __SDIO_FUNC_IDS_H__
|
||||
#define __SDIO_FUNC_IDS_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Standard SDIO Function Interfaces */
|
||||
|
||||
#define SDIO_FUNC_CODE_NONE 0x00 /* Not a SDIO standard interface */
|
||||
#define SDIO_FUNC_CODE_UART 0x01 /* SDIO Standard UART */
|
||||
#define SDIO_FUNC_CODE_BT_A 0x02 /* SDIO Type-A for Bluetooth standard interface */
|
||||
#define SDIO_FUNC_CODE_BT_B 0x03 /* SDIO Type-B for Bluetooth standard interface */
|
||||
#define SDIO_FUNC_CODE_GPS 0x04 /* SDIO GPS standard interface */
|
||||
#define SDIO_FUNC_CODE_CAMERA 0x05 /* SDIO Camera standard interface */
|
||||
#define SDIO_FUNC_CODE_PHS 0x06 /* SDIO PHS standard interface */
|
||||
#define SDIO_FUNC_CODE_WLAN 0x07 /* SDIO WLAN interface */
|
||||
#define SDIO_FUNC_CODE_ATA 0x08 /* Embedded SDIO-ATA standard interface */
|
||||
|
||||
/* manufacturer id, product io */
|
||||
|
||||
#define SDIO_MANUFACTURER_ID_MARVELL 0x02df
|
||||
#define SDIO_PRODUCT_ID_MARVELL_88W8686 0x9103
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+182
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* File : serial.h
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-05-15 lgnq first version.
|
||||
* 2012-05-28 bernard change interfaces
|
||||
* 2013-02-20 bernard use RT_SERIAL_RB_BUFSZ to define
|
||||
* the size of ring buffer.
|
||||
*/
|
||||
|
||||
#ifndef __SERIAL_H__
|
||||
#define __SERIAL_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#define BAUD_RATE_2400 2400
|
||||
#define BAUD_RATE_4800 4800
|
||||
#define BAUD_RATE_9600 9600
|
||||
#define BAUD_RATE_38400 38400
|
||||
#define BAUD_RATE_57600 57600
|
||||
#define BAUD_RATE_115200 115200
|
||||
#define BAUD_RATE_230400 230400
|
||||
#define BAUD_RATE_460800 460800
|
||||
#define BAUD_RATE_921600 921600
|
||||
|
||||
#define DATA_BITS_5 5
|
||||
#define DATA_BITS_6 6
|
||||
#define DATA_BITS_7 7
|
||||
#define DATA_BITS_8 8
|
||||
#define DATA_BITS_9 9
|
||||
|
||||
#define STOP_BITS_1 0
|
||||
#define STOP_BITS_2 1
|
||||
#define STOP_BITS_3 2
|
||||
#define STOP_BITS_4 3
|
||||
|
||||
#define PARITY_NONE 0
|
||||
#define PARITY_ODD 1
|
||||
#define PARITY_EVEN 2
|
||||
|
||||
#define BIT_ORDER_LSB 0
|
||||
#define BIT_ORDER_MSB 1
|
||||
|
||||
#define NRZ_NORMAL 0 /* Non Return to Zero : normal mode */
|
||||
#define NRZ_INVERTED 1 /* Non Return to Zero : inverted mode */
|
||||
|
||||
#ifndef RT_SERIAL_RB_BUFSZ
|
||||
#define RT_SERIAL_RB_BUFSZ 64
|
||||
#endif
|
||||
|
||||
#define RT_DEVICE_CTRL_CONFIG 0x03 /* configure device */
|
||||
#define RT_DEVICE_CTRL_SET_INT 0x10 /* enable serial irq */
|
||||
#define RT_DEVICE_CTRL_CLR_INT 0x11 /* disable serial irq */
|
||||
#define RT_DEVICE_CTRL_GET_INT 0x12
|
||||
#define RT_DEVICE_CTRL_GET_FLAG 0x13
|
||||
|
||||
#define RT_SERIAL_EVENT_RX_IND 0x01 /* Rx indication */
|
||||
#define RT_SERIAL_EVENT_TX_DONE 0x02 /* Tx complete */
|
||||
#define RT_SERIAL_EVENT_RX_DMADONE 0x03 /* Rx DMA transfer done */
|
||||
#define RT_SERIAL_EVENT_TX_DMADONE 0x04 /* Tx DMA transfer done */
|
||||
#define RT_SERIAL_EVENT_RX_TIMEOUT 0x05 /* Rx timeout */
|
||||
|
||||
#define RT_SERIAL_DMA_RX 0x01
|
||||
#define RT_SERIAL_DMA_TX 0x02
|
||||
|
||||
#define RT_SERIAL_RX_INT 0x01
|
||||
#define RT_SERIAL_TX_INT 0x02
|
||||
|
||||
#define RT_SERIAL_ERR_OVERRUN 0x01
|
||||
#define RT_SERIAL_ERR_FRAMING 0x02
|
||||
#define RT_SERIAL_ERR_PARITY 0x03
|
||||
|
||||
#define RT_SERIAL_TX_DATAQUEUE_SIZE 2048
|
||||
#define RT_SERIAL_TX_DATAQUEUE_LWM 30
|
||||
|
||||
/* Default config for serial_configure structure */
|
||||
#define RT_SERIAL_CONFIG_DEFAULT \
|
||||
{ \
|
||||
BAUD_RATE_115200, /* 115200 bits/s */ \
|
||||
DATA_BITS_8, /* 8 databits */ \
|
||||
STOP_BITS_1, /* 1 stopbit */ \
|
||||
PARITY_NONE, /* No parity */ \
|
||||
BIT_ORDER_LSB, /* LSB first sent */ \
|
||||
NRZ_NORMAL, /* Normal mode */ \
|
||||
RT_SERIAL_RB_BUFSZ, /* Buffer size */ \
|
||||
0 \
|
||||
}
|
||||
|
||||
struct serial_configure
|
||||
{
|
||||
rt_uint32_t baud_rate;
|
||||
|
||||
rt_uint32_t data_bits :4;
|
||||
rt_uint32_t stop_bits :2;
|
||||
rt_uint32_t parity :2;
|
||||
rt_uint32_t bit_order :1;
|
||||
rt_uint32_t invert :1;
|
||||
rt_uint32_t bufsz :16;
|
||||
rt_uint32_t reserved :4;
|
||||
};
|
||||
|
||||
/*
|
||||
* Serial FIFO mode
|
||||
*/
|
||||
struct rt_serial_rx_fifo
|
||||
{
|
||||
/* software fifo */
|
||||
rt_uint8_t *buffer;
|
||||
|
||||
rt_uint16_t put_index, get_index;
|
||||
};
|
||||
|
||||
struct rt_serial_tx_fifo
|
||||
{
|
||||
struct rt_completion completion;
|
||||
};
|
||||
|
||||
/*
|
||||
* Serial DMA mode
|
||||
*/
|
||||
struct rt_serial_rx_dma
|
||||
{
|
||||
rt_bool_t activated;
|
||||
};
|
||||
|
||||
struct rt_serial_tx_dma
|
||||
{
|
||||
rt_bool_t activated;
|
||||
struct rt_data_queue data_queue;
|
||||
};
|
||||
|
||||
struct rt_serial_device
|
||||
{
|
||||
struct rt_device parent;
|
||||
|
||||
const struct rt_uart_ops *ops;
|
||||
struct serial_configure config;
|
||||
|
||||
void *serial_rx;
|
||||
void *serial_tx;
|
||||
};
|
||||
typedef struct rt_serial_device rt_serial_t;
|
||||
|
||||
/**
|
||||
* uart operators
|
||||
*/
|
||||
struct rt_uart_ops
|
||||
{
|
||||
rt_err_t (*configure)(struct rt_serial_device *serial, struct serial_configure *cfg);
|
||||
rt_err_t (*control)(struct rt_serial_device *serial, int cmd, void *arg);
|
||||
|
||||
int (*putc)(struct rt_serial_device *serial, char c);
|
||||
int (*getc)(struct rt_serial_device *serial);
|
||||
|
||||
rt_size_t (*dma_transmit)(struct rt_serial_device *serial, const rt_uint8_t *buf, rt_size_t size, int direction);
|
||||
};
|
||||
|
||||
void rt_hw_serial_isr(struct rt_serial_device *serial, int event);
|
||||
|
||||
rt_err_t rt_hw_serial_register(struct rt_serial_device *serial,
|
||||
const char *name,
|
||||
rt_uint32_t flag,
|
||||
void *data);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* File : spi.h
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-11-23 Bernard Add extern "C"
|
||||
*/
|
||||
|
||||
#ifndef __SPI_H__
|
||||
#define __SPI_H__
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"{
|
||||
#endif
|
||||
|
||||
#define RT_SPI_CPHA (1<<0) /* bit[0]:CPHA, clock phase */
|
||||
#define RT_SPI_CPOL (1<<1) /* bit[1]:CPOL, clock polarity */
|
||||
/**
|
||||
* At CPOL=0 the base value of the clock is zero
|
||||
* - For CPHA=0, data are captured on the clock's rising edge (low¡úhigh transition)
|
||||
* and data are propagated on a falling edge (high¡úlow clock transition).
|
||||
* - For CPHA=1, data are captured on the clock's falling edge and data are
|
||||
* propagated on a rising edge.
|
||||
* At CPOL=1 the base value of the clock is one (inversion of CPOL=0)
|
||||
* - For CPHA=0, data are captured on clock's falling edge and data are propagated
|
||||
* on a rising edge.
|
||||
* - For CPHA=1, data are captured on clock's rising edge and data are propagated
|
||||
* on a falling edge.
|
||||
*/
|
||||
#define RT_SPI_LSB (0<<2) /* bit[2]: 0-LSB */
|
||||
#define RT_SPI_MSB (1<<2) /* bit[2]: 1-MSB */
|
||||
|
||||
#define RT_SPI_MASTER (0<<3) /* SPI master device */
|
||||
#define RT_SPI_SLAVE (1<<3) /* SPI slave device */
|
||||
|
||||
#define RT_SPI_MODE_0 (0 | 0) /* CPOL = 0, CPHA = 0 */
|
||||
#define RT_SPI_MODE_1 (0 | RT_SPI_CPHA) /* CPOL = 0, CPHA = 1 */
|
||||
#define RT_SPI_MODE_2 (RT_SPI_CPOL | 0) /* CPOL = 1, CPHA = 0 */
|
||||
#define RT_SPI_MODE_3 (RT_SPI_CPOL | RT_SPI_CPHA) /* CPOL = 1, CPHA = 1 */
|
||||
|
||||
#define RT_SPI_MODE_MASK (RT_SPI_CPHA | RT_SPI_CPOL | RT_SPI_MSB)
|
||||
|
||||
/**
|
||||
* SPI message structure
|
||||
*/
|
||||
struct rt_spi_message
|
||||
{
|
||||
const void *send_buf;
|
||||
void *recv_buf;
|
||||
rt_size_t length;
|
||||
struct rt_spi_message *next;
|
||||
|
||||
unsigned cs_take : 1;
|
||||
unsigned cs_release : 1;
|
||||
};
|
||||
|
||||
/**
|
||||
* SPI configuration structure
|
||||
*/
|
||||
struct rt_spi_configuration
|
||||
{
|
||||
rt_uint8_t mode;
|
||||
rt_uint8_t data_width;
|
||||
rt_uint16_t reserved;
|
||||
|
||||
rt_uint32_t max_hz;
|
||||
};
|
||||
|
||||
struct rt_spi_ops;
|
||||
struct rt_spi_bus
|
||||
{
|
||||
struct rt_device parent;
|
||||
const struct rt_spi_ops *ops;
|
||||
|
||||
struct rt_mutex lock;
|
||||
struct rt_spi_device *owner;
|
||||
};
|
||||
|
||||
/**
|
||||
* SPI operators
|
||||
*/
|
||||
struct rt_spi_ops
|
||||
{
|
||||
rt_err_t (*configure)(struct rt_spi_device *device, struct rt_spi_configuration *configuration);
|
||||
rt_uint32_t (*xfer)(struct rt_spi_device *device, struct rt_spi_message *message);
|
||||
};
|
||||
|
||||
/**
|
||||
* SPI Virtual BUS, one device must connected to a virtual BUS
|
||||
*/
|
||||
struct rt_spi_device
|
||||
{
|
||||
struct rt_device parent;
|
||||
struct rt_spi_bus *bus;
|
||||
|
||||
struct rt_spi_configuration config;
|
||||
};
|
||||
#define SPI_DEVICE(dev) ((struct rt_spi_device *)(dev))
|
||||
|
||||
/* register a SPI bus */
|
||||
rt_err_t rt_spi_bus_register(struct rt_spi_bus *bus,
|
||||
const char *name,
|
||||
const struct rt_spi_ops *ops);
|
||||
|
||||
/* attach a device on SPI bus */
|
||||
rt_err_t rt_spi_bus_attach_device(struct rt_spi_device *device,
|
||||
const char *name,
|
||||
const char *bus_name,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* This function takes SPI bus.
|
||||
*
|
||||
* @param device the SPI device attached to SPI bus
|
||||
*
|
||||
* @return RT_EOK on taken SPI bus successfully. others on taken SPI bus failed.
|
||||
*/
|
||||
rt_err_t rt_spi_take_bus(struct rt_spi_device *device);
|
||||
|
||||
/**
|
||||
* This function releases SPI bus.
|
||||
*
|
||||
* @param device the SPI device attached to SPI bus
|
||||
*
|
||||
* @return RT_EOK on release SPI bus successfully.
|
||||
*/
|
||||
rt_err_t rt_spi_release_bus(struct rt_spi_device *device);
|
||||
|
||||
/**
|
||||
* This function take SPI device (takes CS of SPI device).
|
||||
*
|
||||
* @param device the SPI device attached to SPI bus
|
||||
*
|
||||
* @return RT_EOK on release SPI bus successfully. others on taken SPI bus failed.
|
||||
*/
|
||||
rt_err_t rt_spi_take(struct rt_spi_device *device);
|
||||
|
||||
/**
|
||||
* This function releases SPI device (releases CS of SPI device).
|
||||
*
|
||||
* @param device the SPI device attached to SPI bus
|
||||
*
|
||||
* @return RT_EOK on release SPI device successfully.
|
||||
*/
|
||||
rt_err_t rt_spi_release(struct rt_spi_device *device);
|
||||
|
||||
/* set configuration on SPI device */
|
||||
rt_err_t rt_spi_configure(struct rt_spi_device *device,
|
||||
struct rt_spi_configuration *cfg);
|
||||
|
||||
/* send data then receive data from SPI device */
|
||||
rt_err_t rt_spi_send_then_recv(struct rt_spi_device *device,
|
||||
const void *send_buf,
|
||||
rt_size_t send_length,
|
||||
void *recv_buf,
|
||||
rt_size_t recv_length);
|
||||
|
||||
rt_err_t rt_spi_send_then_send(struct rt_spi_device *device,
|
||||
const void *send_buf1,
|
||||
rt_size_t send_length1,
|
||||
const void *send_buf2,
|
||||
rt_size_t send_length2);
|
||||
|
||||
/**
|
||||
* This function transmits data to SPI device.
|
||||
*
|
||||
* @param device the SPI device attached to SPI bus
|
||||
* @param send_buf the buffer to be transmitted to SPI device.
|
||||
* @param recv_buf the buffer to save received data from SPI device.
|
||||
* @param length the length of transmitted data.
|
||||
*
|
||||
* @return the actual length of transmitted.
|
||||
*/
|
||||
rt_size_t rt_spi_transfer(struct rt_spi_device *device,
|
||||
const void *send_buf,
|
||||
void *recv_buf,
|
||||
rt_size_t length);
|
||||
|
||||
/**
|
||||
* This function transfers a message list to the SPI device.
|
||||
*
|
||||
* @param device the SPI device attached to SPI bus
|
||||
* @param message the message list to be transmitted to SPI device
|
||||
*
|
||||
* @return RT_NULL if transmits message list successfully,
|
||||
* SPI message which be transmitted failed.
|
||||
*/
|
||||
struct rt_spi_message *rt_spi_transfer_message(struct rt_spi_device *device,
|
||||
struct rt_spi_message *message);
|
||||
|
||||
rt_inline rt_size_t rt_spi_recv(struct rt_spi_device *device,
|
||||
void *recv_buf,
|
||||
rt_size_t length)
|
||||
{
|
||||
return rt_spi_transfer(device, RT_NULL, recv_buf, length);
|
||||
}
|
||||
|
||||
rt_inline rt_size_t rt_spi_send(struct rt_spi_device *device,
|
||||
const void *send_buf,
|
||||
rt_size_t length)
|
||||
{
|
||||
return rt_spi_transfer(device, send_buf, RT_NULL, length);
|
||||
}
|
||||
|
||||
rt_inline rt_uint8_t rt_spi_sendrecv8(struct rt_spi_device *device,
|
||||
rt_uint8_t data)
|
||||
{
|
||||
rt_uint8_t value;
|
||||
|
||||
rt_spi_send_then_recv(device, &data, 1, &value, 1);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
rt_inline rt_uint16_t rt_spi_sendrecv16(struct rt_spi_device *device,
|
||||
rt_uint16_t data)
|
||||
{
|
||||
rt_uint16_t value;
|
||||
|
||||
rt_spi_send_then_recv(device, &data, 2, &value, 2);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function appends a message to the SPI message list.
|
||||
*
|
||||
* @param list the SPI message list header.
|
||||
* @param message the message pointer to be appended to the message list.
|
||||
*/
|
||||
rt_inline void rt_spi_message_append(struct rt_spi_message *list,
|
||||
struct rt_spi_message *message)
|
||||
{
|
||||
RT_ASSERT(list != RT_NULL);
|
||||
if (message == RT_NULL)
|
||||
return; /* not append */
|
||||
|
||||
while (list->next != RT_NULL)
|
||||
{
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
list->next = message;
|
||||
message->next = RT_NULL;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+433
@@ -0,0 +1,433 @@
|
||||
/*
|
||||
* File : usb_common.h
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2012, RT-Thread Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-10-01 Yi Qiu first version
|
||||
*/
|
||||
|
||||
#ifndef __USB_COMMON_H__
|
||||
#define __USB_COMMON_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#define RT_DEBUG_USB 0x00
|
||||
#define USB_DYNAMIC 0x00
|
||||
|
||||
#define USB_CLASS_DEVICE 0x00
|
||||
#define USB_CLASS_AUDIO 0x01
|
||||
#define USB_CLASS_CDC 0x02
|
||||
#define USB_CLASS_HID 0x03
|
||||
#define USB_CLASS_PHYSICAL 0x05
|
||||
#define USB_CLASS_IMAGE 0x06
|
||||
#define USB_CLASS_PRINTER 0x07
|
||||
#define USB_CLASS_MASS_STORAGE 0x08
|
||||
#define USB_CLASS_HUB 0x09
|
||||
#define USB_CLASS_CDC_DATA 0x0a
|
||||
#define USB_CLASS_SMART_CARD 0x0b
|
||||
#define USB_CLASS_SECURITY 0x0d
|
||||
#define USB_CLASS_VIDEO 0x0e
|
||||
#define USB_CLASS_HEALTHCARE 0x0f
|
||||
#define USB_CLASS_DIAG_DEVICE 0xdc
|
||||
#define USB_CLASS_WIRELESS 0xe0
|
||||
#define USB_CLASS_MISC 0xef
|
||||
#define USB_CLASS_APP_SPECIFIC 0xfe
|
||||
#define USB_CLASS_VEND_SPECIFIC 0xff
|
||||
|
||||
#define USB_DESC_TYPE_DEVICE 0x01
|
||||
#define USB_DESC_TYPE_CONFIGURATION 0x02
|
||||
#define USB_DESC_TYPE_STRING 0x03
|
||||
#define USB_DESC_TYPE_INTERFACE 0x04
|
||||
#define USB_DESC_TYPE_ENDPOINT 0x05
|
||||
#define USB_DESC_TYPE_DEVICEQUALIFIER 0x06
|
||||
#define USB_DESC_TYPE_OTHERSPEED 0x07
|
||||
#define USB_DESC_TYPE_IAD 0x0b
|
||||
#define USB_DESC_TYPE_HID 0x21
|
||||
#define USB_DESC_TYPE_REPORT 0x22
|
||||
#define USB_DESC_TYPE_PHYSICAL 0x23
|
||||
#define USB_DESC_TYPE_HUB 0x29
|
||||
|
||||
#define USB_DESC_LENGTH_DEVICE 0x12
|
||||
#define USB_DESC_LENGTH_CONFIG 0x9
|
||||
#define USB_DESC_LENGTH_IAD 0x8
|
||||
#define USB_DESC_LENGTH_STRING 0x4
|
||||
#define USB_DESC_LENGTH_INTERFACE 0x9
|
||||
#define USB_DESC_LENGTH_ENDPOINT 0x7
|
||||
|
||||
#define USB_REQ_TYPE_STANDARD 0x00
|
||||
#define USB_REQ_TYPE_CLASS 0x20
|
||||
#define USB_REQ_TYPE_VENDOR 0x40
|
||||
#define USB_REQ_TYPE_MASK 0x60
|
||||
|
||||
#define USB_REQ_TYPE_DIR_OUT 0x00
|
||||
#define USB_REQ_TYPE_DIR_IN 0x80
|
||||
|
||||
#define USB_REQ_TYPE_DEVICE 0x00
|
||||
#define USB_REQ_TYPE_INTERFACE 0x01
|
||||
#define USB_REQ_TYPE_ENDPOINT 0x02
|
||||
#define USB_REQ_TYPE_OTHER 0x03
|
||||
#define USB_REQ_TYPE_RECIPIENT_MASK 0x1f
|
||||
|
||||
#define USB_FEATURE_ENDPOINT_HALT 0x00
|
||||
#define USB_FEATURE_DEV_REMOTE_WAKEUP 0x01
|
||||
#define USB_FEATURE_TEST_MODE 0x02
|
||||
|
||||
#define USB_REQ_GET_STATUS 0x00
|
||||
#define USB_REQ_CLEAR_FEATURE 0x01
|
||||
#define USB_REQ_SET_FEATURE 0x03
|
||||
#define USB_REQ_SET_ADDRESS 0x05
|
||||
#define USB_REQ_GET_DESCRIPTOR 0x06
|
||||
#define USB_REQ_SET_DESCRIPTOR 0x07
|
||||
#define USB_REQ_GET_CONFIGURATION 0x08
|
||||
#define USB_REQ_SET_CONFIGURATION 0x09
|
||||
#define USB_REQ_GET_INTERFACE 0x0A
|
||||
#define USB_REQ_SET_INTERFACE 0x0B
|
||||
#define USB_REQ_SYNCH_FRAME 0x0C
|
||||
#define USB_REQ_SET_ENCRYPTION 0x0D
|
||||
#define USB_REQ_GET_ENCRYPTION 0x0E
|
||||
#define USB_REQ_RPIPE_ABORT 0x0E
|
||||
#define USB_REQ_SET_HANDSHAKE 0x0F
|
||||
#define USB_REQ_RPIPE_RESET 0x0F
|
||||
#define USB_REQ_GET_HANDSHAKE 0x10
|
||||
#define USB_REQ_SET_CONNECTION 0x11
|
||||
#define USB_REQ_SET_SECURITY_DATA 0x12
|
||||
#define USB_REQ_GET_SECURITY_DATA 0x13
|
||||
#define USB_REQ_SET_WUSB_DATA 0x14
|
||||
#define USB_REQ_LOOPBACK_DATA_WRITE 0x15
|
||||
#define USB_REQ_LOOPBACK_DATA_READ 0x16
|
||||
#define USB_REQ_SET_INTERFACE_DS 0x17
|
||||
|
||||
#define USB_STRING_LANGID_INDEX 0x00
|
||||
#define USB_STRING_MANU_INDEX 0x01
|
||||
#define USB_STRING_PRODUCT_INDEX 0x02
|
||||
#define USB_STRING_SERIAL_INDEX 0x03
|
||||
#define USB_STRING_CONFIG_INDEX 0x04
|
||||
#define USB_STRING_INTERFACE_INDEX 0x05
|
||||
|
||||
#define USB_PID_OUT 0x01
|
||||
#define USB_PID_ACK 0x02
|
||||
#define USB_PID_DATA0 0x03
|
||||
#define USB_PID_SOF 0x05
|
||||
#define USB_PID_IN 0x09
|
||||
#define USB_PID_NACK 0x0A
|
||||
#define USB_PID_DATA1 0x0B
|
||||
#define USB_PID_PRE 0x0C
|
||||
#define USB_PID_SETUP 0x0D
|
||||
#define USB_PID_STALL 0x0E
|
||||
|
||||
#define USB_EP_DESC_OUT 0x00
|
||||
#define USB_EP_DESC_IN 0x80
|
||||
#define USB_EP_DESC_NUM_MASK 0x0f
|
||||
|
||||
#define USB_EP_ATTR_CONTROL 0x00
|
||||
#define USB_EP_ATTR_ISOC 0x01
|
||||
#define USB_EP_ATTR_BULK 0x02
|
||||
#define USB_EP_ATTR_INT 0x03
|
||||
#define USB_EP_ATTR_TYPE_MASK 0x03
|
||||
|
||||
#define USB_EPNO_MASK 0x7f
|
||||
#define USB_DIR_OUT 0x00
|
||||
#define USB_DIR_IN 0x80
|
||||
#define USB_DIR_MASK 0x80
|
||||
|
||||
#define RH_GET_PORT_STATUS 0
|
||||
#define RH_SET_PORT_STATUS 1
|
||||
#define RH_CLEAR_PORT_FEATURE 2
|
||||
#define RH_SET_PORT_FEATURE 3
|
||||
|
||||
/*
|
||||
* Port feature numbers
|
||||
*/
|
||||
#define PORT_FEAT_CONNECTION 0
|
||||
#define PORT_FEAT_ENABLE 1
|
||||
#define PORT_FEAT_SUSPEND 2
|
||||
#define PORT_FEAT_OVER_CURRENT 3
|
||||
#define PORT_FEAT_RESET 4
|
||||
#define PORT_FEAT_POWER 8
|
||||
#define PORT_FEAT_LOWSPEED 9
|
||||
#define PORT_FEAT_HIGHSPEED 10
|
||||
#define PORT_FEAT_C_CONNECTION 16
|
||||
#define PORT_FEAT_C_ENABLE 17
|
||||
#define PORT_FEAT_C_SUSPEND 18
|
||||
#define PORT_FEAT_C_OVER_CURRENT 19
|
||||
#define PORT_FEAT_C_RESET 20
|
||||
|
||||
/*
|
||||
The HcRhPortStatus[1:NDP] register is used to control and report port events on a per-port
|
||||
basis. NumberDownstreamPorts represents the number of HcRhPortStatus registers that are
|
||||
implemented in hardware. The lower word is used to reflect the port status, whereas the upper
|
||||
word reflects the status change bits. Some status bits are implemented with special write behavior
|
||||
(see below). If a transaction (token through handshake) is in progress when a write to change
|
||||
port status occurs, the resulting port status change must be postponed until the transaction
|
||||
completes. Reserved bits should always be written '0'.
|
||||
*/
|
||||
#define PORT_CCS 0x00000001UL /* R:CurrentConnectStatus - W:ClearPortEnable */
|
||||
#define PORT_PES 0x00000002UL /* R:PortEnableStatus - W:SetPortEnable */
|
||||
#define PORT_PSS 0x00000004UL /* R:PortSuspendStatus - W:SetPortSuspend */
|
||||
#define PORT_POCI 0x00000008UL /* R:PortOverCurrentIndicator - W:ClearSuspendStatus */
|
||||
#define PORT_PRS 0x00000010UL /* R:PortResetStatus - W: SetPortReset */
|
||||
#define PORT_PPS 0x00000100UL /* R:PortPowerStatus - W: SetPortPower */
|
||||
#define PORT_LSDA 0x00000200UL /* R:LowSpeedDeviceAttached - W:ClearPortPower */
|
||||
#define PORT_CCSC 0x00010000UL
|
||||
#define PORT_PESC 0x00020000UL
|
||||
#define PORT_PSSC 0x00040000UL
|
||||
#define PORT_POCIC 0x00080000UL
|
||||
#define PORT_PRSC 0x00100000UL
|
||||
|
||||
/*
|
||||
*Hub Status & Hub Change bit masks
|
||||
*/
|
||||
#define HUB_STATUS_LOCAL_POWER 0x0001
|
||||
#define HUB_STATUS_OVERCURRENT 0x0002
|
||||
|
||||
#define HUB_CHANGE_LOCAL_POWER 0x0001
|
||||
#define HUB_CHANGE_OVERCURRENT 0x0002
|
||||
|
||||
#define USB_EP_ATTR(attr) (attr & USB_EP_ATTR_TYPE_MASK)
|
||||
#define USB_EP_DESC_NUM(addr) (addr & USB_EP_DESC_NUM_MASK)
|
||||
|
||||
#define uswap_32(x) \
|
||||
((((x) & 0xff000000) >> 24) | \
|
||||
(((x) & 0x00ff0000) >> 8) | \
|
||||
(((x) & 0x0000ff00) << 8) | \
|
||||
(((x) & 0x000000ff) << 24))
|
||||
|
||||
#define uswap_8(x) \
|
||||
(((rt_uint16_t)(*((rt_uint8_t *)(x)))) + \
|
||||
(((rt_uint16_t)(*(((rt_uint8_t *)(x)) + 1))) << 8))
|
||||
|
||||
typedef void (*func_callback)(void *context);
|
||||
typedef enum
|
||||
{
|
||||
USB_STATE_NOTATTACHED = 0,
|
||||
USB_STATE_ATTACHED,
|
||||
USB_STATE_POWERED,
|
||||
USB_STATE_RECONNECTING,
|
||||
USB_STATE_UNAUTHENTICATED,
|
||||
USB_STATE_DEFAULT,
|
||||
USB_STATE_ADDRESS,
|
||||
USB_STATE_CONFIGURED,
|
||||
USB_STATE_SUSPENDED
|
||||
}udevice_state_t;
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
struct usb_descriptor
|
||||
{
|
||||
rt_uint8_t bLength;
|
||||
rt_uint8_t type;
|
||||
};
|
||||
typedef struct usb_descriptor* udesc_t;
|
||||
|
||||
struct udevice_descriptor
|
||||
{
|
||||
rt_uint8_t bLength;
|
||||
rt_uint8_t type;
|
||||
rt_uint16_t bcdUSB;
|
||||
rt_uint8_t bDeviceClass;
|
||||
rt_uint8_t bDeviceSubClass;
|
||||
rt_uint8_t bDeviceProtocol;
|
||||
rt_uint8_t bMaxPacketSize0;
|
||||
rt_uint16_t idVendor;
|
||||
rt_uint16_t idProduct;
|
||||
rt_uint16_t bcdDevice;
|
||||
rt_uint8_t iManufacturer;
|
||||
rt_uint8_t iProduct;
|
||||
rt_uint8_t iSerialNumber;
|
||||
rt_uint8_t bNumConfigurations;
|
||||
};
|
||||
typedef struct udevice_descriptor* udev_desc_t;
|
||||
|
||||
struct uconfig_descriptor
|
||||
{
|
||||
rt_uint8_t bLength;
|
||||
rt_uint8_t type;
|
||||
rt_uint16_t wTotalLength;
|
||||
rt_uint8_t bNumInterfaces;
|
||||
rt_uint8_t bConfigurationValue;
|
||||
rt_uint8_t iConfiguration;
|
||||
rt_uint8_t bmAttributes;
|
||||
rt_uint8_t MaxPower;
|
||||
rt_uint8_t data[256];
|
||||
};
|
||||
typedef struct uconfig_descriptor* ucfg_desc_t;
|
||||
|
||||
struct uinterface_descriptor
|
||||
{
|
||||
rt_uint8_t bLength;
|
||||
rt_uint8_t type;
|
||||
rt_uint8_t bInterfaceNumber;
|
||||
rt_uint8_t bAlternateSetting;
|
||||
rt_uint8_t bNumEndpoints;
|
||||
rt_uint8_t bInterfaceClass;
|
||||
rt_uint8_t bInterfaceSubClass;
|
||||
rt_uint8_t bInterfaceProtocol;
|
||||
rt_uint8_t iInterface;
|
||||
};
|
||||
typedef struct uinterface_descriptor* uintf_desc_t;
|
||||
|
||||
/* Interface Association Descriptor (IAD) */
|
||||
struct uiad_descriptor
|
||||
{
|
||||
rt_uint8_t bLength;
|
||||
rt_uint8_t bDescriptorType;
|
||||
rt_uint8_t bFirstInterface;
|
||||
rt_uint8_t bInterfaceCount;
|
||||
rt_uint8_t bFunctionClass;
|
||||
rt_uint8_t bFunctionSubClass;
|
||||
rt_uint8_t bFunctionProtocol;
|
||||
rt_uint8_t iFunction;
|
||||
};
|
||||
typedef struct uiad_descriptor* uiad_desc_t;
|
||||
|
||||
struct uendpoint_descriptor
|
||||
{
|
||||
rt_uint8_t bLength;
|
||||
rt_uint8_t type;
|
||||
rt_uint8_t bEndpointAddress;
|
||||
rt_uint8_t bmAttributes;
|
||||
rt_uint16_t wMaxPacketSize;
|
||||
rt_uint8_t bInterval;
|
||||
};
|
||||
typedef struct uendpoint_descriptor* uep_desc_t;
|
||||
|
||||
struct ustring_descriptor
|
||||
{
|
||||
rt_uint8_t bLength;
|
||||
rt_uint8_t type;
|
||||
rt_uint8_t String[64];
|
||||
};
|
||||
typedef struct ustring_descriptor* ustr_desc_t;
|
||||
|
||||
struct uhub_descriptor
|
||||
{
|
||||
rt_uint8_t length;
|
||||
rt_uint8_t type;
|
||||
rt_uint8_t num_ports;
|
||||
rt_uint16_t characteristics;
|
||||
rt_uint8_t pwron_to_good; /* power on to power good */
|
||||
rt_uint8_t current;
|
||||
rt_uint8_t removable[8];
|
||||
rt_uint8_t pwr_ctl[8];
|
||||
};
|
||||
typedef struct uhub_descriptor* uhub_desc_t;
|
||||
|
||||
struct uhid_descriptor
|
||||
{
|
||||
rt_uint8_t bLength;
|
||||
rt_uint8_t type;
|
||||
rt_uint16_t bcdHID;
|
||||
rt_uint8_t bCountryCode;
|
||||
rt_uint8_t bNumDescriptors;
|
||||
struct hid_descriptor_list
|
||||
{
|
||||
rt_uint8_t type;
|
||||
rt_uint16_t wLength;
|
||||
}Descriptor[1];
|
||||
};
|
||||
typedef struct uhid_descriptor* uhid_desc_t;
|
||||
|
||||
struct ureqest
|
||||
{
|
||||
rt_uint8_t request_type;
|
||||
rt_uint8_t request;
|
||||
rt_uint16_t value;
|
||||
rt_uint16_t index;
|
||||
rt_uint16_t length;
|
||||
};
|
||||
typedef struct ureqest* ureq_t;
|
||||
|
||||
#define MIN(a, b) (a < b ? a : b)
|
||||
#define MAX(a, b) (a > b ? a : b)
|
||||
|
||||
/*
|
||||
* the define related to mass storage
|
||||
*/
|
||||
#define USBREQ_GET_MAX_LUN 0xfe
|
||||
#define USBREQ_MASS_STORAGE_RESET 0xff
|
||||
|
||||
#define SIZEOF_CSW 0x0d
|
||||
#define SIZEOF_CBW 0x1f
|
||||
|
||||
#define CBWFLAGS_DIR_M 0x80
|
||||
#define CBWFLAGS_DIR_IN 0x80
|
||||
#define CBWFLAGS_DIR_OUT 0x00
|
||||
|
||||
#define SCSI_TEST_UNIT_READY 0x00
|
||||
#define SCSI_REQUEST_SENSE 0x03
|
||||
#define SCSI_INQUIRY_CMD 0x12
|
||||
#define SCSI_ALLOW_MEDIUM_REMOVAL 0x1e
|
||||
#define SCSI_MODE_SENSE_6 0x1a
|
||||
#define SCSI_START_STOP 0x1b
|
||||
#define SCSI_READ_CAPACITIES 0x23
|
||||
#define SCSI_READ_CAPACITY 0x25
|
||||
#define SCSI_READ_10 0x28
|
||||
#define SCSI_WRITE_10 0x2a
|
||||
#define SCSI_VERIFY_10 0x2f
|
||||
|
||||
#define CBW_SIGNATURE 0x43425355
|
||||
#define CSW_SIGNATURE 0x53425355
|
||||
#define CBW_TAG_VALUE 0x12345678
|
||||
|
||||
struct ustorage_cbw
|
||||
{
|
||||
rt_uint32_t signature;
|
||||
rt_uint32_t tag;
|
||||
rt_uint32_t xfer_len;
|
||||
rt_uint8_t dflags;
|
||||
rt_uint8_t lun;
|
||||
rt_uint8_t cb_len;
|
||||
rt_uint8_t cb[16];
|
||||
};
|
||||
typedef struct ustorage_cbw* ustorage_cbw_t;
|
||||
|
||||
struct ustorage_csw
|
||||
{
|
||||
rt_uint32_t signature;
|
||||
rt_uint32_t tag;
|
||||
rt_uint32_t data_reside;
|
||||
rt_uint8_t status;
|
||||
};
|
||||
typedef struct ustorage_csw* ustorage_csw_t;
|
||||
|
||||
#pragma pack()
|
||||
|
||||
/*
|
||||
* USB device event loop thread configurations
|
||||
*/
|
||||
/* the stack size of USB thread */
|
||||
#ifndef RT_USBD_THREAD_STACK_SZ
|
||||
#define RT_USBD_THREAD_STACK_SZ 2048
|
||||
#endif
|
||||
|
||||
/* the priority of USB thread */
|
||||
#ifndef RT_USBD_THREAD_PRIO
|
||||
#define RT_USBD_THREAD_PRIO 8
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+316
@@ -0,0 +1,316 @@
|
||||
/*
|
||||
* File : usb_device.h
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2012, RT-Thread Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-10-01 Yi Qiu first version
|
||||
* 2012-12-12 heyuanjie87 change endpoint and class handler
|
||||
*/
|
||||
|
||||
#ifndef __USB_DEVICE_H__
|
||||
#define __USB_DEVICE_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "usb_common.h"
|
||||
|
||||
/* Vendor ID */
|
||||
#ifdef USB_VENDOR_ID
|
||||
#define _VENDOR_ID USB_VENDOR_ID
|
||||
#else
|
||||
#define _VENDOR_ID 0x0EFF
|
||||
#endif
|
||||
/* Product ID */
|
||||
#ifdef USB_PRODUCT_ID
|
||||
#define _PRODUCT_ID USB_PRODUCT_ID
|
||||
#else
|
||||
#define _PRODUCT_ID 0x0001
|
||||
#endif
|
||||
|
||||
#define USB_BCD_DEVICE 0x0200 /* USB Specification Release Number in Binary-Coded Decimal */
|
||||
#define USB_BCD_VERSION 0x0200 /* USB 2.0 */
|
||||
|
||||
struct uclass;
|
||||
struct udevice;
|
||||
struct uendpoint;
|
||||
|
||||
struct udcd_ops
|
||||
{
|
||||
rt_err_t (*set_address)(rt_uint8_t value);
|
||||
rt_err_t (*clear_feature)(rt_uint16_t value, rt_uint16_t index);
|
||||
rt_err_t (*set_feature)(rt_uint16_t value, rt_uint16_t index);
|
||||
rt_err_t (*ep_alloc)(struct uendpoint* ep);
|
||||
rt_err_t (*ep_free)(struct uendpoint* ep);
|
||||
rt_err_t (*ep_stall)(struct uendpoint* ep);
|
||||
rt_err_t (*ep_run)(struct uendpoint* ep);
|
||||
rt_err_t (*ep_stop)(struct uendpoint* ep);
|
||||
rt_err_t (*ep_read)(struct uendpoint* ep, void *buffer, rt_size_t size);
|
||||
rt_size_t (*ep_write)(struct uendpoint* ep, void *buffer, rt_size_t size);
|
||||
rt_err_t (*send_status)(void);
|
||||
};
|
||||
|
||||
struct udcd
|
||||
{
|
||||
struct rt_device parent;
|
||||
struct udcd_ops* ops;
|
||||
struct rt_completion completion;
|
||||
};
|
||||
typedef struct udcd* udcd_t;
|
||||
|
||||
typedef rt_err_t (*udep_handler_t)(struct udevice* device, struct uclass* cls, rt_size_t size);
|
||||
|
||||
struct uendpoint
|
||||
{
|
||||
rt_list_t list;
|
||||
rt_uint8_t* buffer;
|
||||
uep_desc_t ep_desc;
|
||||
udep_handler_t handler;
|
||||
rt_bool_t is_stall;
|
||||
};
|
||||
typedef struct uendpoint* uep_t;
|
||||
|
||||
struct ualtsetting
|
||||
{
|
||||
rt_list_t list;
|
||||
uintf_desc_t intf_desc;
|
||||
void* desc;
|
||||
rt_size_t desc_size;
|
||||
rt_list_t ep_list;
|
||||
};
|
||||
typedef struct ualtsetting* ualtsetting_t;
|
||||
|
||||
typedef rt_err_t (*uintf_handler_t)(struct udevice* device, struct uclass* cls, ureq_t setup);
|
||||
|
||||
struct uinterface
|
||||
{
|
||||
rt_list_t list;
|
||||
rt_uint8_t intf_num;
|
||||
ualtsetting_t curr_setting;
|
||||
rt_list_t setting_list;
|
||||
uintf_handler_t handler;
|
||||
};
|
||||
typedef struct uinterface* uintf_t;
|
||||
|
||||
struct uclass_ops
|
||||
{
|
||||
rt_err_t (*run)(struct udevice* device, struct uclass* cls);
|
||||
rt_err_t (*stop)(struct udevice* device, struct uclass* cls);
|
||||
rt_err_t (*sof_handler)(struct udevice* device, struct uclass* cls);
|
||||
};
|
||||
typedef struct uclass_ops* uclass_ops_t;
|
||||
|
||||
struct uclass
|
||||
{
|
||||
rt_list_t list;
|
||||
uclass_ops_t ops;
|
||||
void* eps;
|
||||
struct udevice* device;
|
||||
udev_desc_t dev_desc;
|
||||
void* user_data;
|
||||
|
||||
rt_list_t intf_list;
|
||||
};
|
||||
typedef struct uclass* uclass_t;
|
||||
|
||||
struct uconfig
|
||||
{
|
||||
rt_list_t list;
|
||||
struct uconfig_descriptor cfg_desc;
|
||||
rt_list_t cls_list;
|
||||
};
|
||||
typedef struct uconfig* uconfig_t;
|
||||
|
||||
struct udevice
|
||||
{
|
||||
rt_list_t list;
|
||||
struct udevice_descriptor dev_desc;
|
||||
const char** str;
|
||||
|
||||
udevice_state_t state;
|
||||
rt_list_t cfg_list;
|
||||
uconfig_t curr_cfg;
|
||||
rt_uint8_t nr_intf;
|
||||
|
||||
udcd_t dcd;
|
||||
};
|
||||
typedef struct udevice* udevice_t;
|
||||
|
||||
enum udev_msg_type
|
||||
{
|
||||
USB_MSG_SETUP_NOTIFY,
|
||||
USB_MSG_DATA_NOTIFY,
|
||||
USB_MSG_SOF,
|
||||
USB_MSG_RESET,
|
||||
/* we don't need to add a "PLUG_IN" event because after the cable is
|
||||
* plugged in(before any SETUP) the classed have nothing to do. If the host
|
||||
* is ready, it will send RESET and we will have USB_MSG_RESET. So, a RESET
|
||||
* should reset and run the class while plug_in is not. */
|
||||
USB_MSG_PLUG_OUT,
|
||||
};
|
||||
typedef enum udev_msg_type udev_msg_type;
|
||||
|
||||
struct udev_msg
|
||||
{
|
||||
udev_msg_type type;
|
||||
udcd_t dcd;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
rt_size_t size;
|
||||
rt_uint8_t ep_addr;
|
||||
} ep_msg;
|
||||
struct
|
||||
{
|
||||
rt_uint32_t* packet;
|
||||
} setup_msg;
|
||||
} content;
|
||||
};
|
||||
typedef struct udev_msg* udev_msg_t;
|
||||
|
||||
udevice_t rt_usbd_device_create(void);
|
||||
uconfig_t rt_usbd_config_create(void);
|
||||
uclass_t rt_usbd_class_create(udevice_t device,
|
||||
udev_desc_t dev_desc,
|
||||
uclass_ops_t ops);
|
||||
uintf_t rt_usbd_interface_create(udevice_t device, uintf_handler_t handler);
|
||||
uep_t rt_usbd_endpoint_create(uep_desc_t ep_desc, udep_handler_t handler);
|
||||
ualtsetting_t rt_usbd_altsetting_create(rt_size_t desc_size);
|
||||
|
||||
rt_err_t rt_usbd_core_init(void);
|
||||
rt_err_t rt_usb_device_init(const char *udc_name);
|
||||
rt_err_t rt_usbd_post_event(struct udev_msg *msg, rt_size_t size);
|
||||
rt_err_t rt_usbd_free_device(udevice_t device);
|
||||
rt_err_t rt_usbd_device_set_controller(udevice_t device, udcd_t dcd);
|
||||
rt_err_t rt_usbd_device_set_descriptor(udevice_t device, udev_desc_t dev_desc);
|
||||
rt_err_t rt_usbd_device_set_string(udevice_t device, const char** ustring);
|
||||
rt_err_t rt_usbd_device_add_config(udevice_t device, uconfig_t cfg);
|
||||
rt_err_t rt_usbd_config_add_class(uconfig_t cfg, uclass_t cls);
|
||||
rt_err_t rt_usbd_class_add_interface(uclass_t cls, uintf_t intf);
|
||||
rt_err_t rt_usbd_interface_add_altsetting(uintf_t intf, ualtsetting_t setting);
|
||||
rt_err_t rt_usbd_altsetting_add_endpoint(ualtsetting_t setting, uep_t ep);
|
||||
rt_err_t rt_usbd_altsetting_config_descriptor(ualtsetting_t setting,
|
||||
const void *desc,
|
||||
rt_off_t intf_pos);
|
||||
rt_err_t rt_usbd_set_config(udevice_t device, rt_uint8_t value);
|
||||
rt_err_t rt_usbd_set_altsetting(uintf_t intf, rt_uint8_t value);
|
||||
|
||||
udevice_t rt_usbd_find_device(udcd_t dcd);
|
||||
uconfig_t rt_usbd_find_config(udevice_t device, rt_uint8_t value);
|
||||
uintf_t rt_usbd_find_interface(udevice_t device,
|
||||
rt_uint8_t value,
|
||||
uclass_t *pcls);
|
||||
uep_t rt_usbd_find_endpoint(udevice_t device,
|
||||
uclass_t *pcls,
|
||||
rt_uint8_t ep_addr);
|
||||
|
||||
uclass_t rt_usbd_class_mstorage_create(udevice_t device);
|
||||
uclass_t rt_usbd_class_cdc_create(udevice_t device);
|
||||
uclass_t rt_usbd_class_rndis_create(udevice_t device);
|
||||
uclass_t rt_usbd_class_dap_create(udevice_t device);
|
||||
|
||||
#ifdef RT_USB_DEVICE_COMPOSITE
|
||||
rt_err_t rt_usbd_class_set_iad(uclass_t cls, uiad_desc_t iad_desc);
|
||||
#endif
|
||||
|
||||
rt_inline rt_err_t dcd_set_address(udcd_t dcd, rt_uint8_t value)
|
||||
{
|
||||
RT_ASSERT(dcd != RT_NULL);
|
||||
|
||||
return dcd->ops->set_address(value);
|
||||
}
|
||||
|
||||
rt_inline rt_err_t dcd_clear_feature(udcd_t dcd,
|
||||
rt_uint16_t value,
|
||||
rt_uint16_t index)
|
||||
{
|
||||
RT_ASSERT(dcd != RT_NULL);
|
||||
|
||||
return dcd->ops->clear_feature(value, index);
|
||||
}
|
||||
|
||||
rt_inline rt_err_t dcd_set_feature(udcd_t dcd,
|
||||
rt_uint8_t value,
|
||||
rt_uint16_t index)
|
||||
{
|
||||
RT_ASSERT(dcd != RT_NULL);
|
||||
|
||||
return dcd->ops->set_feature(value, index);
|
||||
}
|
||||
|
||||
rt_inline rt_err_t dcd_ep_stall(udcd_t dcd, uep_t ep)
|
||||
{
|
||||
RT_ASSERT(dcd != RT_NULL);
|
||||
|
||||
return dcd->ops->ep_stall(ep);
|
||||
}
|
||||
|
||||
rt_inline rt_uint8_t dcd_ep_alloc(udcd_t dcd, uep_t ep)
|
||||
{
|
||||
RT_ASSERT(dcd != RT_NULL);
|
||||
|
||||
return dcd->ops->ep_alloc(ep);
|
||||
}
|
||||
|
||||
rt_inline rt_err_t dcd_ep_free(udcd_t dcd, uep_t ep)
|
||||
{
|
||||
RT_ASSERT(dcd != RT_NULL);
|
||||
|
||||
return dcd->ops->ep_free(ep);
|
||||
}
|
||||
|
||||
rt_inline rt_err_t dcd_ep_run(udcd_t dcd, uep_t ep)
|
||||
{
|
||||
RT_ASSERT(dcd != RT_NULL);
|
||||
|
||||
return dcd->ops->ep_run(ep);
|
||||
}
|
||||
|
||||
rt_inline rt_err_t dcd_ep_stop(udcd_t dcd, uep_t ep)
|
||||
{
|
||||
RT_ASSERT(dcd != RT_NULL);
|
||||
|
||||
return dcd->ops->ep_stop(ep);
|
||||
}
|
||||
|
||||
rt_inline rt_err_t dcd_ep_read(udcd_t dcd, uep_t ep, void *buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
RT_ASSERT(dcd != RT_NULL);
|
||||
|
||||
return dcd->ops->ep_read(ep, buffer, size);
|
||||
}
|
||||
|
||||
rt_inline rt_size_t dcd_ep_write(udcd_t dcd,
|
||||
uep_t ep,
|
||||
void *buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
RT_ASSERT(dcd != RT_NULL);
|
||||
|
||||
return dcd->ops->ep_write(ep, buffer, size);
|
||||
}
|
||||
|
||||
rt_inline rt_err_t dcd_send_status(udcd_t dcd)
|
||||
{
|
||||
RT_ASSERT(dcd != RT_NULL);
|
||||
|
||||
return dcd->ops->send_status();
|
||||
}
|
||||
|
||||
#endif
|
||||
+320
@@ -0,0 +1,320 @@
|
||||
/*
|
||||
* File : usb_host.h
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2011, RT-Thread Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-3-12 Yi Qiu first version
|
||||
*/
|
||||
|
||||
#ifndef __RT_USB_HOST_H__
|
||||
#define __RT_USB_HOST_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "usb_common.h"
|
||||
|
||||
#define USB_MAX_DEVICE 0x20
|
||||
#define USB_MAX_INTERFACE 0x08
|
||||
#define USB_HUB_PORT_NUM 0x04
|
||||
#define SIZEOF_USB_REQUEST 0x08
|
||||
|
||||
#define UINST_STATUS_IDLE 0x00
|
||||
#define UINST_STATUS_BUSY 0x01
|
||||
#define UINST_STATUS_ERROR 0x02
|
||||
|
||||
#define UPIPE_STATUS_OK 0x00
|
||||
#define UPIPE_STATUS_STALL 0x01
|
||||
#define UPIPE_STATUS_ERROR 0x02
|
||||
|
||||
struct uhcd;
|
||||
struct uifinst;
|
||||
struct uhubinst;
|
||||
|
||||
struct uclass_driver
|
||||
{
|
||||
rt_list_t list;
|
||||
int class_code;
|
||||
int subclass_code;
|
||||
|
||||
rt_err_t (*run)(void* arg);
|
||||
rt_err_t (*stop)(void* arg);
|
||||
|
||||
void* user_data;
|
||||
};
|
||||
typedef struct uclass_driver* ucd_t;
|
||||
|
||||
struct uprotocal
|
||||
{
|
||||
rt_list_t list;
|
||||
int pro_id;
|
||||
|
||||
rt_err_t (*init)(void* arg);
|
||||
rt_err_t (*callback)(void* arg);
|
||||
};
|
||||
typedef struct uprotocal* uprotocal_t;
|
||||
|
||||
struct uinstance
|
||||
{
|
||||
struct udevice_descriptor dev_desc;
|
||||
ucfg_desc_t cfg_desc;
|
||||
struct uhcd *hcd;
|
||||
|
||||
rt_uint8_t status;
|
||||
rt_uint8_t type;
|
||||
rt_uint8_t index;
|
||||
rt_uint8_t address;
|
||||
rt_uint8_t speed;
|
||||
rt_uint8_t max_packet_size;
|
||||
rt_uint8_t port;
|
||||
|
||||
struct uhubinst* parent;
|
||||
struct uifinst* ifinst[USB_MAX_INTERFACE];
|
||||
};
|
||||
typedef struct uinstance* uinst_t;
|
||||
|
||||
struct uifinst
|
||||
{
|
||||
uinst_t uinst;
|
||||
uintf_desc_t intf_desc;
|
||||
|
||||
ucd_t drv;
|
||||
void *user_data;
|
||||
};
|
||||
typedef struct uifinst* uifinst_t;
|
||||
|
||||
struct upipe
|
||||
{
|
||||
rt_uint32_t status;
|
||||
struct uendpoint_descriptor ep;
|
||||
uifinst_t ifinst;
|
||||
func_callback callback;
|
||||
void* user_data;
|
||||
};
|
||||
typedef struct upipe* upipe_t;
|
||||
|
||||
struct uhubinst
|
||||
{
|
||||
struct uhub_descriptor hub_desc;
|
||||
rt_uint8_t num_ports;
|
||||
rt_uint32_t port_status[USB_HUB_PORT_NUM];
|
||||
struct uinstance* child[USB_HUB_PORT_NUM];
|
||||
|
||||
rt_bool_t is_roothub;
|
||||
upipe_t pipe_in;
|
||||
rt_uint8_t buffer[8];
|
||||
struct uinstance* self;
|
||||
struct uhcd *hcd;
|
||||
};
|
||||
typedef struct uhubinst* uhubinst_t;
|
||||
|
||||
struct uhcd_ops
|
||||
{
|
||||
int (*ctl_xfer)(uinst_t inst, ureq_t setup, void* buffer, int nbytes,
|
||||
int timeout);
|
||||
int (*bulk_xfer)(upipe_t pipe, void* buffer, int nbytes, int timeout);
|
||||
int (*int_xfer)(upipe_t pipe, void* buffer, int nbytes, int timeout);
|
||||
int (*iso_xfer)(upipe_t pipe, void* buffer, int nbytes, int timeout);
|
||||
|
||||
rt_err_t (*alloc_pipe)(struct upipe** pipe, uifinst_t ifinst, uep_desc_t ep,
|
||||
func_callback callback);
|
||||
rt_err_t (*free_pipe)(upipe_t pipe);
|
||||
rt_err_t (*hub_ctrl)(rt_uint16_t port, rt_uint8_t cmd, void *args);
|
||||
};
|
||||
|
||||
struct uhcd
|
||||
{
|
||||
struct rt_device parent;
|
||||
struct uhcd_ops* ops;
|
||||
};
|
||||
typedef struct uhcd* uhcd_t;
|
||||
|
||||
enum uhost_msg_type
|
||||
{
|
||||
USB_MSG_CONNECT_CHANGE,
|
||||
USB_MSG_CALLBACK,
|
||||
};
|
||||
typedef enum uhost_msg_type uhost_msg_type;
|
||||
|
||||
struct uhost_msg
|
||||
{
|
||||
uhost_msg_type type;
|
||||
union
|
||||
{
|
||||
struct uhubinst* uhub;
|
||||
struct
|
||||
{
|
||||
func_callback function;
|
||||
void *context;
|
||||
}cb;
|
||||
}content;
|
||||
};
|
||||
typedef struct uhost_msg* uhost_msg_t;
|
||||
|
||||
/* usb host system interface */
|
||||
void rt_usb_host_init(void);
|
||||
void rt_usb_hub_thread(void);
|
||||
|
||||
/* usb host core interface */
|
||||
uinst_t rt_usb_alloc_instance(void);
|
||||
rt_err_t rt_usb_attatch_instance(uinst_t uinst);
|
||||
rt_err_t rt_usb_detach_instance(uinst_t uinst);
|
||||
rt_err_t rt_usb_get_descriptor(uinst_t uinst,
|
||||
rt_uint8_t type,
|
||||
void *buffer,
|
||||
int nbytes);
|
||||
rt_err_t rt_usb_set_configure(uinst_t uinst, int config);
|
||||
rt_err_t rt_usb_set_address(uinst_t uinst);
|
||||
rt_err_t rt_usb_set_interface(uinst_t uinst, int intf);
|
||||
rt_err_t rt_usb_clear_feature(uinst_t uinst, int endpoint, int feature);
|
||||
rt_err_t rt_usb_get_interface_descriptor(ucfg_desc_t cfg_desc,
|
||||
int num,
|
||||
uintf_desc_t *intf_desc);
|
||||
rt_err_t rt_usb_get_endpoint_descriptor(uintf_desc_t intf_desc,
|
||||
int num,
|
||||
uep_desc_t *ep_desc);
|
||||
|
||||
/* usb class driver interface */
|
||||
rt_err_t rt_usb_class_driver_init(void);
|
||||
rt_err_t rt_usb_class_driver_register(ucd_t drv);
|
||||
rt_err_t rt_usb_class_driver_unregister(ucd_t drv);
|
||||
rt_err_t rt_usb_class_driver_run(ucd_t drv, void *args);
|
||||
rt_err_t rt_usb_class_driver_stop(ucd_t drv, void *args);
|
||||
ucd_t rt_usb_class_driver_find(int class_code, int subclass_code);
|
||||
|
||||
/* usb class driver implement */
|
||||
ucd_t rt_usb_class_driver_hid(void);
|
||||
ucd_t rt_usb_class_driver_hub(void);
|
||||
ucd_t rt_usb_class_driver_storage(void);
|
||||
ucd_t rt_usb_class_driver_adk(void);
|
||||
|
||||
/* usb hid protocal implement */
|
||||
uprotocal_t rt_usb_hid_protocal_kbd(void);
|
||||
uprotocal_t rt_usb_hid_protocal_mouse(void);
|
||||
|
||||
/* usb adk class driver interface */
|
||||
rt_err_t rt_usb_adk_set_string(const char *manufacturer,
|
||||
const char *model,
|
||||
const char *description,
|
||||
const char *version,
|
||||
const char *uri,
|
||||
const char *serial);
|
||||
|
||||
/* usb hub interface */
|
||||
rt_err_t rt_usb_hub_get_descriptor(uinst_t uinst,
|
||||
rt_uint8_t *buffer,
|
||||
rt_size_t size);
|
||||
rt_err_t rt_usb_hub_get_status(uinst_t uinst, rt_uint8_t *buffer);
|
||||
rt_err_t rt_usb_hub_get_port_status(uhubinst_t uhub,
|
||||
rt_uint16_t port,
|
||||
rt_uint8_t *buffer);
|
||||
rt_err_t rt_usb_hub_clear_port_feature(uhubinst_t uhub,
|
||||
rt_uint16_t port,
|
||||
rt_uint16_t feature);
|
||||
rt_err_t rt_usb_hub_set_port_feature(uhubinst_t uhub,
|
||||
rt_uint16_t port,
|
||||
rt_uint16_t feature);
|
||||
rt_err_t rt_usb_hub_reset_port(uhubinst_t uhub, rt_uint16_t port);
|
||||
rt_err_t rt_usb_post_event(struct uhost_msg* msg, rt_size_t size);
|
||||
|
||||
/* usb host controller driver interface */
|
||||
rt_inline rt_err_t rt_usb_hcd_alloc_pipe(uhcd_t hcd,
|
||||
upipe_t *pipe,
|
||||
uifinst_t ifinst,
|
||||
uep_desc_t ep,
|
||||
func_callback callback)
|
||||
{
|
||||
if (ifinst == RT_NULL)
|
||||
return -RT_EIO;
|
||||
|
||||
return hcd->ops->alloc_pipe(pipe, ifinst, ep, callback);
|
||||
}
|
||||
|
||||
rt_inline rt_err_t rt_usb_hcd_free_pipe(uhcd_t hcd, upipe_t pipe)
|
||||
{
|
||||
RT_ASSERT(pipe != RT_NULL);
|
||||
|
||||
return hcd->ops->free_pipe(pipe);
|
||||
}
|
||||
|
||||
rt_inline int rt_usb_hcd_bulk_xfer(uhcd_t hcd,
|
||||
upipe_t pipe,
|
||||
void *buffer,
|
||||
int nbytes,
|
||||
int timeout)
|
||||
{
|
||||
if (pipe == RT_NULL)
|
||||
return -1;
|
||||
if (pipe->ifinst == RT_NULL)
|
||||
return -1;
|
||||
if (pipe->ifinst->uinst == RT_NULL)
|
||||
return -1;
|
||||
if (pipe->ifinst->uinst->status == UINST_STATUS_IDLE)
|
||||
return -1;
|
||||
|
||||
return hcd->ops->bulk_xfer(pipe, buffer, nbytes, timeout);
|
||||
}
|
||||
|
||||
rt_inline int rt_usb_hcd_control_xfer(uhcd_t hcd,
|
||||
uinst_t uinst,
|
||||
ureq_t setup,
|
||||
void *buffer,
|
||||
int nbytes,
|
||||
int timeout)
|
||||
{
|
||||
if (uinst->status == UINST_STATUS_IDLE)
|
||||
return -1;
|
||||
|
||||
return hcd->ops->ctl_xfer(uinst, setup, buffer, nbytes, timeout);
|
||||
}
|
||||
|
||||
rt_inline int rt_usb_hcd_int_xfer(uhcd_t hcd,
|
||||
upipe_t pipe,
|
||||
void *buffer,
|
||||
int nbytes,
|
||||
int timeout)
|
||||
{
|
||||
if (pipe == RT_NULL)
|
||||
return -1;
|
||||
if (pipe->ifinst == RT_NULL)
|
||||
return -1;
|
||||
if (pipe->ifinst->uinst == RT_NULL)
|
||||
return -1;
|
||||
if (pipe->ifinst->uinst->status == UINST_STATUS_IDLE)
|
||||
return -1;
|
||||
|
||||
return hcd->ops->int_xfer(pipe, buffer, nbytes, timeout);
|
||||
}
|
||||
|
||||
rt_inline rt_err_t rt_usb_hcd_hub_control(uhcd_t hcd,
|
||||
rt_uint16_t port,
|
||||
rt_uint8_t cmd,
|
||||
void *args)
|
||||
{
|
||||
return hcd->ops->hub_ctrl(port, cmd, args);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,361 @@
|
||||
/*
|
||||
* File : rtdevice.h
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-01-08 bernard first version.
|
||||
* 2014-07-12 bernard Add workqueue implementation.
|
||||
*/
|
||||
|
||||
#ifndef __RT_DEVICE_H__
|
||||
#define __RT_DEVICE_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#define RT_DEVICE(device) ((rt_device_t)device)
|
||||
|
||||
/* completion flag */
|
||||
struct rt_completion
|
||||
{
|
||||
rt_uint32_t flag;
|
||||
|
||||
/* suspended list */
|
||||
rt_list_t suspended_list;
|
||||
};
|
||||
|
||||
/* ring buffer */
|
||||
struct rt_ringbuffer
|
||||
{
|
||||
rt_uint8_t *buffer_ptr;
|
||||
/* use the msb of the {read,write}_index as mirror bit. You can see this as
|
||||
* if the buffer adds a virtual mirror and the pointers point either to the
|
||||
* normal or to the mirrored buffer. If the write_index has the same value
|
||||
* with the read_index, but in a different mirror, the buffer is full.
|
||||
* While if the write_index and the read_index are the same and within the
|
||||
* same mirror, the buffer is empty. The ASCII art of the ringbuffer is:
|
||||
*
|
||||
* mirror = 0 mirror = 1
|
||||
* +---+---+---+---+---+---+---+|+~~~+~~~+~~~+~~~+~~~+~~~+~~~+
|
||||
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 ||| 0 | 1 | 2 | 3 | 4 | 5 | 6 | Full
|
||||
* +---+---+---+---+---+---+---+|+~~~+~~~+~~~+~~~+~~~+~~~+~~~+
|
||||
* read_idx-^ write_idx-^
|
||||
*
|
||||
* +---+---+---+---+---+---+---+|+~~~+~~~+~~~+~~~+~~~+~~~+~~~+
|
||||
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 ||| 0 | 1 | 2 | 3 | 4 | 5 | 6 | Empty
|
||||
* +---+---+---+---+---+---+---+|+~~~+~~~+~~~+~~~+~~~+~~~+~~~+
|
||||
* read_idx-^ ^-write_idx
|
||||
*
|
||||
* The tradeoff is we could only use 32KiB of buffer for 16 bit of index.
|
||||
* But it should be enough for most of the cases.
|
||||
*
|
||||
* Ref: http://en.wikipedia.org/wiki/Circular_buffer#Mirroring */
|
||||
rt_uint16_t read_mirror : 1;
|
||||
rt_uint16_t read_index : 15;
|
||||
rt_uint16_t write_mirror : 1;
|
||||
rt_uint16_t write_index : 15;
|
||||
/* as we use msb of index as mirror bit, the size should be signed and
|
||||
* could only be positive. */
|
||||
rt_int16_t buffer_size;
|
||||
};
|
||||
|
||||
/* portal device */
|
||||
struct rt_portal_device
|
||||
{
|
||||
struct rt_device parent;
|
||||
struct rt_device *write_dev;
|
||||
struct rt_device *read_dev;
|
||||
};
|
||||
|
||||
/* pipe device */
|
||||
#define PIPE_DEVICE(device) ((struct rt_pipe_device*)(device))
|
||||
enum rt_pipe_flag
|
||||
{
|
||||
/* both read and write won't block */
|
||||
RT_PIPE_FLAG_NONBLOCK_RDWR = 0x00,
|
||||
/* read would block */
|
||||
RT_PIPE_FLAG_BLOCK_RD = 0x01,
|
||||
/* write would block */
|
||||
RT_PIPE_FLAG_BLOCK_WR = 0x02,
|
||||
/* write to this pipe will discard some data when the pipe is full.
|
||||
* When this flag is set, RT_PIPE_FLAG_BLOCK_WR will be ignored since write
|
||||
* operation will always be success. */
|
||||
RT_PIPE_FLAG_FORCE_WR = 0x04,
|
||||
};
|
||||
|
||||
struct rt_pipe_device
|
||||
{
|
||||
struct rt_device parent;
|
||||
|
||||
/* ring buffer in pipe device */
|
||||
struct rt_ringbuffer ringbuffer;
|
||||
|
||||
enum rt_pipe_flag flag;
|
||||
|
||||
/* suspended list */
|
||||
rt_list_t suspended_read_list;
|
||||
rt_list_t suspended_write_list;
|
||||
|
||||
struct rt_portal_device *write_portal;
|
||||
struct rt_portal_device *read_portal;
|
||||
};
|
||||
|
||||
#define PIPE_CTRL_GET_SPACE 0x14 /**< get the remaining size of a pipe device */
|
||||
|
||||
#define RT_DATAQUEUE_EVENT_UNKNOWN 0x00
|
||||
#define RT_DATAQUEUE_EVENT_POP 0x01
|
||||
#define RT_DATAQUEUE_EVENT_PUSH 0x02
|
||||
#define RT_DATAQUEUE_EVENT_LWM 0x03
|
||||
|
||||
struct rt_data_item;
|
||||
#define RT_DATAQUEUE_SIZE(dq) ((dq)->put_index - (dq)->get_index)
|
||||
#define RT_DATAQUEUE_EMPTY(dq) ((dq)->size - RT_DATAQUEUE_SIZE(dq))
|
||||
/* data queue implementation */
|
||||
struct rt_data_queue
|
||||
{
|
||||
rt_uint16_t size;
|
||||
rt_uint16_t lwm;
|
||||
rt_bool_t waiting_lwm;
|
||||
|
||||
rt_uint16_t get_index;
|
||||
rt_uint16_t put_index;
|
||||
|
||||
struct rt_data_item *queue;
|
||||
|
||||
rt_list_t suspended_push_list;
|
||||
rt_list_t suspended_pop_list;
|
||||
|
||||
/* event notify */
|
||||
void (*evt_notify)(struct rt_data_queue *queue, rt_uint32_t event);
|
||||
};
|
||||
|
||||
/* workqueue implementation */
|
||||
struct rt_workqueue
|
||||
{
|
||||
rt_list_t work_list;
|
||||
rt_thread_t work_thread;
|
||||
};
|
||||
|
||||
struct rt_work
|
||||
{
|
||||
rt_list_t list;
|
||||
|
||||
void (*work_func)(struct rt_work* work, void* work_data);
|
||||
void *work_data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Completion
|
||||
*/
|
||||
void rt_completion_init(struct rt_completion *completion);
|
||||
rt_err_t rt_completion_wait(struct rt_completion *completion,
|
||||
rt_int32_t timeout);
|
||||
void rt_completion_done(struct rt_completion *completion);
|
||||
|
||||
/**
|
||||
* RingBuffer for DeviceDriver
|
||||
*
|
||||
* Please note that the ring buffer implementation of RT-Thread
|
||||
* has no thread wait or resume feature.
|
||||
*/
|
||||
void rt_ringbuffer_init(struct rt_ringbuffer *rb,
|
||||
rt_uint8_t *pool,
|
||||
rt_int16_t size);
|
||||
rt_size_t rt_ringbuffer_put(struct rt_ringbuffer *rb,
|
||||
const rt_uint8_t *ptr,
|
||||
rt_uint16_t length);
|
||||
rt_size_t rt_ringbuffer_put_force(struct rt_ringbuffer *rb,
|
||||
const rt_uint8_t *ptr,
|
||||
rt_uint16_t length);
|
||||
rt_size_t rt_ringbuffer_putchar(struct rt_ringbuffer *rb,
|
||||
const rt_uint8_t ch);
|
||||
rt_size_t rt_ringbuffer_putchar_force(struct rt_ringbuffer *rb,
|
||||
const rt_uint8_t ch);
|
||||
rt_size_t rt_ringbuffer_get(struct rt_ringbuffer *rb,
|
||||
rt_uint8_t *ptr,
|
||||
rt_uint16_t length);
|
||||
rt_size_t rt_ringbuffer_getchar(struct rt_ringbuffer *rb, rt_uint8_t *ch);
|
||||
|
||||
enum rt_ringbuffer_state
|
||||
{
|
||||
RT_RINGBUFFER_EMPTY,
|
||||
RT_RINGBUFFER_FULL,
|
||||
/* half full is neither full nor empty */
|
||||
RT_RINGBUFFER_HALFFULL,
|
||||
};
|
||||
|
||||
rt_inline rt_uint16_t rt_ringbuffer_get_size(struct rt_ringbuffer *rb)
|
||||
{
|
||||
RT_ASSERT(rb != RT_NULL);
|
||||
return rb->buffer_size;
|
||||
}
|
||||
|
||||
rt_inline enum rt_ringbuffer_state
|
||||
rt_ringbuffer_status(struct rt_ringbuffer *rb)
|
||||
{
|
||||
if (rb->read_index == rb->write_index)
|
||||
{
|
||||
if (rb->read_mirror == rb->write_mirror)
|
||||
return RT_RINGBUFFER_EMPTY;
|
||||
else
|
||||
return RT_RINGBUFFER_FULL;
|
||||
}
|
||||
return RT_RINGBUFFER_HALFFULL;
|
||||
}
|
||||
|
||||
/** return the size of data in rb */
|
||||
rt_inline rt_uint16_t rt_ringbuffer_data_len(struct rt_ringbuffer *rb)
|
||||
{
|
||||
switch (rt_ringbuffer_status(rb))
|
||||
{
|
||||
case RT_RINGBUFFER_EMPTY:
|
||||
return 0;
|
||||
case RT_RINGBUFFER_FULL:
|
||||
return rb->buffer_size;
|
||||
case RT_RINGBUFFER_HALFFULL:
|
||||
default:
|
||||
if (rb->write_index > rb->read_index)
|
||||
return rb->write_index - rb->read_index;
|
||||
else
|
||||
return rb->buffer_size - (rb->read_index - rb->write_index);
|
||||
};
|
||||
}
|
||||
|
||||
/** return the size of empty space in rb */
|
||||
#define rt_ringbuffer_space_len(rb) ((rb)->buffer_size - rt_ringbuffer_data_len(rb))
|
||||
|
||||
/**
|
||||
* Pipe Device
|
||||
*/
|
||||
rt_err_t rt_pipe_init(struct rt_pipe_device *pipe,
|
||||
const char *name,
|
||||
enum rt_pipe_flag flag,
|
||||
rt_uint8_t *buf,
|
||||
rt_size_t size);
|
||||
rt_err_t rt_pipe_detach(struct rt_pipe_device *pipe);
|
||||
#ifdef RT_USING_HEAP
|
||||
rt_err_t rt_pipe_create(const char *name, enum rt_pipe_flag flag, rt_size_t size);
|
||||
void rt_pipe_destroy(struct rt_pipe_device *pipe);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Portal for DeviceDriver
|
||||
*/
|
||||
|
||||
rt_err_t rt_portal_init(struct rt_portal_device *portal,
|
||||
const char *portal_name,
|
||||
const char *write_dev,
|
||||
const char *read_dev);
|
||||
rt_err_t rt_portal_detach(struct rt_portal_device *portal);
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
rt_err_t rt_portal_create(const char *name,
|
||||
const char *write_dev,
|
||||
const char *read_dev);
|
||||
void rt_portal_destroy(struct rt_portal_device *portal);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* DataQueue for DeviceDriver
|
||||
*/
|
||||
rt_err_t rt_data_queue_init(struct rt_data_queue *queue,
|
||||
rt_uint16_t size,
|
||||
rt_uint16_t lwm,
|
||||
void (*evt_notify)(struct rt_data_queue *queue, rt_uint32_t event));
|
||||
rt_err_t rt_data_queue_push(struct rt_data_queue *queue,
|
||||
const void *data_ptr,
|
||||
rt_size_t data_size,
|
||||
rt_int32_t timeout);
|
||||
rt_err_t rt_data_queue_pop(struct rt_data_queue *queue,
|
||||
const void **data_ptr,
|
||||
rt_size_t *size,
|
||||
rt_int32_t timeout);
|
||||
rt_err_t rt_data_queue_peak(struct rt_data_queue *queue,
|
||||
const void **data_ptr,
|
||||
rt_size_t *size);
|
||||
void rt_data_queue_reset(struct rt_data_queue *queue);
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
/**
|
||||
* WorkQueue for DeviceDriver
|
||||
*/
|
||||
struct rt_workqueue *rt_workqueue_create(const char* name, rt_uint16_t stack_size, rt_uint8_t priority);
|
||||
rt_err_t rt_workqueue_destroy(struct rt_workqueue* queue);
|
||||
rt_err_t rt_workqueue_dowork(struct rt_workqueue* queue, struct rt_work* work);
|
||||
rt_err_t rt_workqueue_cancel_work(struct rt_workqueue* queue, struct rt_work* work);
|
||||
|
||||
rt_inline void rt_work_init(struct rt_work* work, void (*work_func)(struct rt_work* work, void* work_data),
|
||||
void* work_data)
|
||||
{
|
||||
rt_list_init(&(work->list));
|
||||
work->work_func = work_func;
|
||||
work->work_data = work_data;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_RTC
|
||||
#include "drivers/rtc.h"
|
||||
#ifdef RT_USING_ALARM
|
||||
#include "drivers/alarm.h"
|
||||
#endif
|
||||
#endif /* RT_USING_RTC */
|
||||
|
||||
#ifdef RT_USING_SPI
|
||||
#include "drivers/spi.h"
|
||||
#endif /* RT_USING_SPI */
|
||||
|
||||
#ifdef RT_USING_MTD_NOR
|
||||
#include "drivers/mtd_nor.h"
|
||||
#endif /* RT_USING_MTD_NOR */
|
||||
|
||||
#ifdef RT_USING_MTD_NAND
|
||||
#include "drivers/mtd_nand.h"
|
||||
#endif /* RT_USING_MTD_NAND */
|
||||
|
||||
#ifdef RT_USING_USB_DEVICE
|
||||
#include "drivers/usb_device.h"
|
||||
#endif /* RT_USING_USB_DEVICE */
|
||||
|
||||
#ifdef RT_USING_USB_HOST
|
||||
#include "drivers/usb_host.h"
|
||||
#endif /* RT_USING_USB_HOST */
|
||||
|
||||
#ifdef RT_USING_SERIAL
|
||||
#include "drivers/serial.h"
|
||||
#endif /* RT_USING_SERIAL */
|
||||
|
||||
#ifdef RT_USING_I2C
|
||||
#include "drivers/i2c.h"
|
||||
#include "drivers/i2c_dev.h"
|
||||
|
||||
#ifdef RT_USING_I2C_BITOPS
|
||||
#include "drivers/i2c-bit-ops.h"
|
||||
#endif /* RT_USING_I2C_BITOPS */
|
||||
#endif /* RT_USING_I2C */
|
||||
|
||||
#ifdef RT_USING_SDIO
|
||||
#include "drivers/mmcsd_core.h"
|
||||
#include "drivers/sd.h"
|
||||
#include "drivers/sdio.h"
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_WDT
|
||||
#include "drivers/watchdog.h"
|
||||
#endif
|
||||
|
||||
#endif /* __RT_DEVICE_H__ */
|
||||
@@ -0,0 +1,8 @@
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c')
|
||||
CPPPATH = [cwd + '/../include']
|
||||
group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_SERIAL'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,615 @@
|
||||
/*
|
||||
* File : serial.c
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2006-03-13 bernard first version
|
||||
* 2012-05-15 lgnq modified according bernard's implementation.
|
||||
* 2012-05-28 bernard code cleanup
|
||||
* 2012-11-23 bernard fix compiler warning.
|
||||
* 2013-02-20 bernard use RT_SERIAL_RB_BUFSZ to define
|
||||
* the size of ring buffer.
|
||||
* 2014-07-10 bernard rewrite serial framework
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
/*
|
||||
* Serial poll routines
|
||||
*/
|
||||
rt_inline int _serial_poll_rx(struct rt_serial_device *serial, rt_uint8_t *data, int length)
|
||||
{
|
||||
int ch;
|
||||
int size;
|
||||
|
||||
RT_ASSERT(serial != RT_NULL);
|
||||
size = length;
|
||||
|
||||
while (length)
|
||||
{
|
||||
ch = serial->ops->getc(serial);
|
||||
*data = ch;
|
||||
data ++; length --;
|
||||
|
||||
if (ch == '\n') break;
|
||||
}
|
||||
|
||||
return size - length;
|
||||
}
|
||||
|
||||
rt_inline int _serial_poll_tx(struct rt_serial_device *serial, const rt_uint8_t *data, int length)
|
||||
{
|
||||
int size;
|
||||
RT_ASSERT(serial != RT_NULL);
|
||||
|
||||
size = length;
|
||||
while (length)
|
||||
{
|
||||
/*
|
||||
* to be polite with serial console add a line feed
|
||||
* to the carriage return character
|
||||
*/
|
||||
if (*data == '\n' && (serial->parent.flag & RT_DEVICE_FLAG_STREAM))
|
||||
{
|
||||
serial->ops->putc(serial, '\r');
|
||||
}
|
||||
|
||||
serial->ops->putc(serial, *data);
|
||||
|
||||
++ data;
|
||||
-- length;
|
||||
}
|
||||
|
||||
return size - length;
|
||||
}
|
||||
|
||||
/*
|
||||
* Serial interrupt routines
|
||||
*/
|
||||
rt_inline int _serial_int_rx(struct rt_serial_device *serial, rt_uint8_t *data, int length)
|
||||
{
|
||||
int size;
|
||||
struct rt_serial_rx_fifo* rx_fifo;
|
||||
|
||||
RT_ASSERT(serial != RT_NULL);
|
||||
size = length;
|
||||
|
||||
rx_fifo = (struct rt_serial_rx_fifo*) serial->serial_rx;
|
||||
RT_ASSERT(rx_fifo != RT_NULL);
|
||||
|
||||
/* read from software FIFO */
|
||||
while (length)
|
||||
{
|
||||
int ch;
|
||||
rt_base_t level;
|
||||
|
||||
/* disable interrupt */
|
||||
level = rt_hw_interrupt_disable();
|
||||
if (rx_fifo->get_index != rx_fifo->put_index)
|
||||
{
|
||||
ch = rx_fifo->buffer[rx_fifo->get_index];
|
||||
rx_fifo->get_index += 1;
|
||||
if (rx_fifo->get_index >= serial->config.bufsz) rx_fifo->get_index = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no data, enable interrupt and break out */
|
||||
rt_hw_interrupt_enable(level);
|
||||
break;
|
||||
}
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
*data = ch & 0xff;
|
||||
data ++; length --;
|
||||
}
|
||||
|
||||
return size - length;
|
||||
}
|
||||
|
||||
rt_inline int _serial_int_tx(struct rt_serial_device *serial, const rt_uint8_t *data, int length)
|
||||
{
|
||||
int size;
|
||||
struct rt_serial_tx_fifo *tx;
|
||||
|
||||
RT_ASSERT(serial != RT_NULL);
|
||||
|
||||
size = length;
|
||||
tx = (struct rt_serial_tx_fifo*) serial->serial_tx;
|
||||
RT_ASSERT(tx != RT_NULL);
|
||||
|
||||
while (length)
|
||||
{
|
||||
if (serial->ops->putc(serial, *(char*)data) == -1)
|
||||
{
|
||||
rt_completion_wait(&(tx->completion), RT_WAITING_FOREVER);
|
||||
continue;
|
||||
}
|
||||
|
||||
data ++; length --;
|
||||
}
|
||||
|
||||
return size - length;
|
||||
}
|
||||
|
||||
/*
|
||||
* Serial DMA routines
|
||||
*/
|
||||
rt_inline int _serial_dma_rx(struct rt_serial_device *serial, rt_uint8_t *data, int length)
|
||||
{
|
||||
rt_base_t level;
|
||||
int result = RT_EOK;
|
||||
struct rt_serial_rx_dma *rx_dma;
|
||||
|
||||
RT_ASSERT((serial != RT_NULL) && (data != RT_NULL));
|
||||
rx_dma = (struct rt_serial_rx_dma*)serial->serial_rx;
|
||||
RT_ASSERT(rx_dma != RT_NULL);
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
if (rx_dma->activated != RT_TRUE)
|
||||
{
|
||||
rx_dma->activated = RT_TRUE;
|
||||
serial->ops->dma_transmit(serial, data, length, RT_SERIAL_DMA_RX);
|
||||
}
|
||||
else result = -RT_EBUSY;
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
if (result == RT_EOK) return length;
|
||||
|
||||
rt_set_errno(result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rt_inline int _serial_dma_tx(struct rt_serial_device *serial, const rt_uint8_t *data, int length)
|
||||
{
|
||||
rt_base_t level;
|
||||
rt_err_t result;
|
||||
struct rt_serial_tx_dma *tx_dma;
|
||||
|
||||
tx_dma = (struct rt_serial_tx_dma*)(serial->serial_tx);
|
||||
|
||||
result = rt_data_queue_push(&(tx_dma->data_queue), data, length, RT_WAITING_FOREVER);
|
||||
if (result == RT_EOK)
|
||||
{
|
||||
level = rt_hw_interrupt_disable();
|
||||
if (tx_dma->activated != RT_TRUE)
|
||||
{
|
||||
tx_dma->activated = RT_TRUE;
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
/* make a DMA transfer */
|
||||
serial->ops->dma_transmit(serial, data, length, RT_SERIAL_DMA_TX);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_hw_interrupt_enable(level);
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_set_errno(result);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* RT-Thread Device Interface */
|
||||
/*
|
||||
* This function initializes serial device.
|
||||
*/
|
||||
static rt_err_t rt_serial_init(struct rt_device *dev)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
struct rt_serial_device *serial;
|
||||
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
serial = (struct rt_serial_device *)dev;
|
||||
|
||||
/* initialize rx/tx */
|
||||
serial->serial_rx = RT_NULL;
|
||||
serial->serial_tx = RT_NULL;
|
||||
|
||||
/* apply configuration */
|
||||
if (serial->ops->configure)
|
||||
result = serial->ops->configure(serial, &serial->config);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag)
|
||||
{
|
||||
struct rt_serial_device *serial;
|
||||
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
serial = (struct rt_serial_device *)dev;
|
||||
|
||||
/* check device flag with the open flag */
|
||||
if ((oflag & RT_DEVICE_FLAG_DMA_RX) && !(dev->flag & RT_DEVICE_FLAG_DMA_RX))
|
||||
return -RT_EIO;
|
||||
if ((oflag & RT_DEVICE_FLAG_DMA_TX) && !(dev->flag & RT_DEVICE_FLAG_DMA_TX))
|
||||
return -RT_EIO;
|
||||
if ((oflag & RT_DEVICE_FLAG_INT_RX) && !(dev->flag & RT_DEVICE_FLAG_INT_RX))
|
||||
return -RT_EIO;
|
||||
if ((oflag & RT_DEVICE_FLAG_INT_TX) && !(dev->flag & RT_DEVICE_FLAG_INT_TX))
|
||||
return -RT_EIO;
|
||||
|
||||
/* get open flags */
|
||||
dev->open_flag = oflag & 0xff;
|
||||
|
||||
/* initialize the Rx/Tx structure according to open flag */
|
||||
if (serial->serial_rx == RT_NULL)
|
||||
{
|
||||
if (oflag & RT_DEVICE_FLAG_DMA_RX)
|
||||
{
|
||||
struct rt_serial_rx_dma* rx_dma;
|
||||
|
||||
rx_dma = (struct rt_serial_rx_dma*) rt_malloc (sizeof(struct rt_serial_rx_dma));
|
||||
RT_ASSERT(rx_dma != RT_NULL);
|
||||
rx_dma->activated = RT_FALSE;
|
||||
|
||||
serial->serial_rx = rx_dma;
|
||||
dev->open_flag |= RT_DEVICE_FLAG_DMA_RX;
|
||||
}
|
||||
else if (oflag & RT_DEVICE_FLAG_INT_RX)
|
||||
{
|
||||
struct rt_serial_rx_fifo* rx_fifo;
|
||||
|
||||
rx_fifo = (struct rt_serial_rx_fifo*) rt_malloc (sizeof(struct rt_serial_rx_fifo) +
|
||||
serial->config.bufsz);
|
||||
RT_ASSERT(rx_fifo != RT_NULL);
|
||||
rx_fifo->buffer = (rt_uint8_t*) (rx_fifo + 1);
|
||||
rt_memset(rx_fifo->buffer, 0, RT_SERIAL_RB_BUFSZ);
|
||||
rx_fifo->put_index = 0;
|
||||
rx_fifo->get_index = 0;
|
||||
|
||||
serial->serial_rx = rx_fifo;
|
||||
dev->open_flag |= RT_DEVICE_FLAG_INT_RX;
|
||||
/* configure low level device */
|
||||
serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_RX);
|
||||
}
|
||||
else
|
||||
{
|
||||
serial->serial_rx = RT_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (serial->serial_tx == RT_NULL)
|
||||
{
|
||||
if (oflag & RT_DEVICE_FLAG_DMA_TX)
|
||||
{
|
||||
struct rt_serial_tx_dma* tx_dma;
|
||||
|
||||
tx_dma = (struct rt_serial_tx_dma*) rt_malloc (sizeof(struct rt_serial_tx_dma));
|
||||
RT_ASSERT(tx_dma != RT_NULL);
|
||||
|
||||
rt_data_queue_init(&(tx_dma->data_queue), 8, 4, RT_NULL);
|
||||
serial->serial_tx = tx_dma;
|
||||
|
||||
dev->open_flag |= RT_DEVICE_FLAG_DMA_TX;
|
||||
}
|
||||
else if (oflag & RT_DEVICE_FLAG_INT_TX)
|
||||
{
|
||||
struct rt_serial_tx_fifo *tx_fifo;
|
||||
|
||||
tx_fifo = (struct rt_serial_tx_fifo*) rt_malloc(sizeof(struct rt_serial_tx_fifo));
|
||||
RT_ASSERT(tx_fifo != RT_NULL);
|
||||
|
||||
rt_completion_init(&(tx_fifo->completion));
|
||||
serial->serial_tx = tx_fifo;
|
||||
|
||||
dev->open_flag |= RT_DEVICE_FLAG_INT_TX;
|
||||
/* configure low level device */
|
||||
serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_TX);
|
||||
}
|
||||
else
|
||||
{
|
||||
serial->serial_tx = RT_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t rt_serial_close(struct rt_device *dev)
|
||||
{
|
||||
struct rt_serial_device *serial;
|
||||
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
serial = (struct rt_serial_device *)dev;
|
||||
|
||||
/* this device has more reference count */
|
||||
if (dev->ref_count > 1) return RT_EOK;
|
||||
|
||||
if (dev->open_flag & RT_DEVICE_FLAG_INT_RX)
|
||||
{
|
||||
struct rt_serial_rx_fifo* rx_fifo;
|
||||
|
||||
rx_fifo = (struct rt_serial_rx_fifo*)serial->serial_rx;
|
||||
RT_ASSERT(rx_fifo != RT_NULL);
|
||||
|
||||
rt_free(rx_fifo);
|
||||
serial->serial_rx = RT_NULL;
|
||||
dev->open_flag &= ~RT_DEVICE_FLAG_INT_RX;
|
||||
/* configure low level device */
|
||||
serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void*)RT_DEVICE_FLAG_INT_TX);
|
||||
}
|
||||
else if (dev->open_flag & RT_DEVICE_FLAG_DMA_RX)
|
||||
{
|
||||
struct rt_serial_rx_dma* rx_dma;
|
||||
|
||||
rx_dma = (struct rt_serial_rx_dma*)serial->serial_tx;
|
||||
RT_ASSERT(rx_dma != RT_NULL);
|
||||
|
||||
rt_free(rx_dma);
|
||||
serial->serial_rx = RT_NULL;
|
||||
dev->open_flag &= ~RT_DEVICE_FLAG_DMA_RX;
|
||||
}
|
||||
|
||||
if (dev->open_flag & RT_DEVICE_FLAG_INT_TX)
|
||||
{
|
||||
struct rt_serial_tx_fifo* tx_fifo;
|
||||
|
||||
tx_fifo = (struct rt_serial_tx_fifo*)serial->serial_rx;
|
||||
RT_ASSERT(tx_fifo != RT_NULL);
|
||||
|
||||
rt_free(tx_fifo);
|
||||
serial->serial_tx = RT_NULL;
|
||||
dev->open_flag &= ~RT_DEVICE_FLAG_INT_TX;
|
||||
/* configure low level device */
|
||||
serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void*)RT_DEVICE_FLAG_INT_TX);
|
||||
}
|
||||
else if (dev->open_flag & RT_DEVICE_FLAG_DMA_TX)
|
||||
{
|
||||
struct rt_serial_tx_dma* tx_dma;
|
||||
|
||||
tx_dma = (struct rt_serial_tx_dma*)serial->serial_tx;
|
||||
RT_ASSERT(tx_dma != RT_NULL);
|
||||
|
||||
rt_free(tx_dma);
|
||||
serial->serial_tx = RT_NULL;
|
||||
dev->open_flag &= ~RT_DEVICE_FLAG_DMA_TX;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_size_t rt_serial_read(struct rt_device *dev,
|
||||
rt_off_t pos,
|
||||
void *buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
struct rt_serial_device *serial;
|
||||
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
if (size == 0) return 0;
|
||||
|
||||
serial = (struct rt_serial_device *)dev;
|
||||
|
||||
if (dev->open_flag & RT_DEVICE_FLAG_INT_RX)
|
||||
{
|
||||
return _serial_int_rx(serial, buffer, size);
|
||||
}
|
||||
else if (dev->open_flag & RT_DEVICE_FLAG_DMA_RX)
|
||||
{
|
||||
return _serial_dma_rx(serial, buffer, size);
|
||||
}
|
||||
|
||||
return _serial_poll_rx(serial, buffer, size);
|
||||
}
|
||||
|
||||
static rt_size_t rt_serial_write(struct rt_device *dev,
|
||||
rt_off_t pos,
|
||||
const void *buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
struct rt_serial_device *serial;
|
||||
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
if (size == 0) return 0;
|
||||
|
||||
serial = (struct rt_serial_device *)dev;
|
||||
|
||||
if (dev->open_flag & RT_DEVICE_FLAG_INT_TX)
|
||||
{
|
||||
return _serial_int_tx(serial, buffer, size);
|
||||
}
|
||||
else if (dev->open_flag & RT_DEVICE_FLAG_DMA_TX)
|
||||
{
|
||||
return _serial_dma_tx(serial, buffer, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
return _serial_poll_tx(serial, buffer, size);
|
||||
}
|
||||
}
|
||||
|
||||
static rt_err_t rt_serial_control(struct rt_device *dev,
|
||||
rt_uint8_t cmd,
|
||||
void *args)
|
||||
{
|
||||
struct rt_serial_device *serial;
|
||||
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
serial = (struct rt_serial_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 */
|
||||
serial->ops->configure(serial, (struct serial_configure *)args);
|
||||
break;
|
||||
|
||||
default :
|
||||
/* control device */
|
||||
serial->ops->control(serial, cmd, args);
|
||||
break;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
/*
|
||||
* serial register
|
||||
*/
|
||||
rt_err_t rt_hw_serial_register(struct rt_serial_device *serial,
|
||||
const char *name,
|
||||
rt_uint32_t flag,
|
||||
void *data)
|
||||
{
|
||||
struct rt_device *device;
|
||||
RT_ASSERT(serial != RT_NULL);
|
||||
|
||||
device = &(serial->parent);
|
||||
|
||||
device->type = RT_Device_Class_Char;
|
||||
device->rx_indicate = RT_NULL;
|
||||
device->tx_complete = RT_NULL;
|
||||
|
||||
device->init = rt_serial_init;
|
||||
device->open = rt_serial_open;
|
||||
device->close = rt_serial_close;
|
||||
device->read = rt_serial_read;
|
||||
device->write = rt_serial_write;
|
||||
device->control = rt_serial_control;
|
||||
device->user_data = data;
|
||||
|
||||
/* register a character device */
|
||||
return rt_device_register(device, name, flag);
|
||||
}
|
||||
|
||||
/* ISR for serial interrupt */
|
||||
void rt_hw_serial_isr(struct rt_serial_device *serial, int event)
|
||||
{
|
||||
switch (event & 0xff)
|
||||
{
|
||||
case RT_SERIAL_EVENT_RX_IND:
|
||||
{
|
||||
int ch = -1;
|
||||
rt_base_t level;
|
||||
struct rt_serial_rx_fifo* rx_fifo;
|
||||
|
||||
rx_fifo = (struct rt_serial_rx_fifo*)serial->serial_rx;
|
||||
RT_ASSERT(rx_fifo != RT_NULL);
|
||||
|
||||
/* interrupt mode receive */
|
||||
RT_ASSERT(serial->parent.open_flag & RT_DEVICE_FLAG_INT_RX);
|
||||
|
||||
while (1)
|
||||
{
|
||||
ch = serial->ops->getc(serial);
|
||||
if (ch == -1) break;
|
||||
|
||||
|
||||
/* disable interrupt */
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
rx_fifo->buffer[rx_fifo->put_index] = ch;
|
||||
rx_fifo->put_index += 1;
|
||||
if (rx_fifo->put_index >= serial->config.bufsz) rx_fifo->put_index = 0;
|
||||
|
||||
/* if the next position is read index, discard this 'read char' */
|
||||
if (rx_fifo->put_index == rx_fifo->get_index)
|
||||
{
|
||||
rx_fifo->get_index += 1;
|
||||
if (rx_fifo->get_index >= serial->config.bufsz) rx_fifo->get_index = 0;
|
||||
}
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
}
|
||||
|
||||
/* invoke callback */
|
||||
if (serial->parent.rx_indicate != RT_NULL)
|
||||
{
|
||||
rt_size_t rx_length;
|
||||
|
||||
/* get rx length */
|
||||
level = rt_hw_interrupt_disable();
|
||||
rx_length = (rx_fifo->put_index >= rx_fifo->get_index)? (rx_fifo->put_index - rx_fifo->get_index):
|
||||
(serial->config.bufsz - (rx_fifo->get_index - rx_fifo->put_index));
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
serial->parent.rx_indicate(&serial->parent, rx_length);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RT_SERIAL_EVENT_TX_DONE:
|
||||
{
|
||||
struct rt_serial_tx_fifo* tx_fifo;
|
||||
|
||||
tx_fifo = (struct rt_serial_tx_fifo*)serial->serial_tx;
|
||||
rt_completion_done(&(tx_fifo->completion));
|
||||
break;
|
||||
}
|
||||
case RT_SERIAL_EVENT_TX_DMADONE:
|
||||
{
|
||||
const void *data_ptr;
|
||||
rt_size_t data_size;
|
||||
const void *last_data_ptr;
|
||||
struct rt_serial_tx_dma* tx_dma;
|
||||
|
||||
tx_dma = (struct rt_serial_tx_dma*) serial->serial_tx;
|
||||
|
||||
rt_data_queue_pop(&(tx_dma->data_queue), &last_data_ptr, &data_size, 0);
|
||||
if (rt_data_queue_peak(&(tx_dma->data_queue), &data_ptr, &data_size) == RT_EOK)
|
||||
{
|
||||
/* transmit next data node */
|
||||
tx_dma->activated = RT_TRUE;
|
||||
serial->ops->dma_transmit(serial, data_ptr, data_size, RT_SERIAL_DMA_TX);
|
||||
}
|
||||
else
|
||||
{
|
||||
tx_dma->activated = RT_FALSE;
|
||||
}
|
||||
|
||||
/* invoke callback */
|
||||
if (serial->parent.tx_complete != RT_NULL)
|
||||
{
|
||||
serial->parent.tx_complete(&serial->parent, (void*)last_data_ptr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RT_SERIAL_EVENT_RX_DMADONE:
|
||||
{
|
||||
int length;
|
||||
struct rt_serial_rx_dma* rx_dma;
|
||||
|
||||
rx_dma = (struct rt_serial_rx_dma*)serial->serial_rx;
|
||||
/* get DMA rx length */
|
||||
length = (event & (~0xff)) >> 8;
|
||||
serial->parent.rx_indicate(&(serial->parent), length);
|
||||
rx_dma->activated = RT_FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c')
|
||||
CPPPATH = [cwd + '/../include']
|
||||
group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_DEVICE_IPC'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* File : completion.c
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2012, RT-Thread Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-09-30 Bernard first version.
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#define RT_COMPLETED 1
|
||||
#define RT_UNCOMPLETED 0
|
||||
|
||||
void rt_completion_init(struct rt_completion *completion)
|
||||
{
|
||||
rt_base_t level;
|
||||
RT_ASSERT(completion != RT_NULL);
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
completion->flag = RT_UNCOMPLETED;
|
||||
rt_list_init(&completion->suspended_list);
|
||||
rt_hw_interrupt_enable(level);
|
||||
}
|
||||
|
||||
rt_err_t rt_completion_wait(struct rt_completion *completion,
|
||||
rt_int32_t timeout)
|
||||
{
|
||||
rt_err_t result;
|
||||
rt_base_t level;
|
||||
rt_thread_t thread;
|
||||
RT_ASSERT(completion != RT_NULL);
|
||||
|
||||
result = RT_EOK;
|
||||
thread = rt_thread_self();
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
if (completion->flag != RT_COMPLETED)
|
||||
{
|
||||
/* only one thread can suspend on complete */
|
||||
RT_ASSERT(rt_list_isempty(&(completion->suspended_list)));
|
||||
|
||||
if (timeout == 0)
|
||||
{
|
||||
result = -RT_ETIMEOUT;
|
||||
goto __exit;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* reset thread error number */
|
||||
thread->error = RT_EOK;
|
||||
|
||||
/* suspend thread */
|
||||
rt_thread_suspend(thread);
|
||||
/* add to suspended list */
|
||||
rt_list_insert_before(&(completion->suspended_list),
|
||||
&(thread->tlist));
|
||||
|
||||
/* current context checking */
|
||||
RT_DEBUG_NOT_IN_INTERRUPT;
|
||||
|
||||
/* start timer */
|
||||
if (timeout > 0)
|
||||
{
|
||||
/* reset the timeout of thread timer and start it */
|
||||
rt_timer_control(&(thread->thread_timer),
|
||||
RT_TIMER_CTRL_SET_TIME,
|
||||
&timeout);
|
||||
rt_timer_start(&(thread->thread_timer));
|
||||
}
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
/* do schedule */
|
||||
rt_schedule();
|
||||
|
||||
/* thread is waked up */
|
||||
result = thread->error;
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
/* clean completed flag */
|
||||
completion->flag = RT_UNCOMPLETED;
|
||||
}
|
||||
}
|
||||
|
||||
__exit:
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void rt_completion_done(struct rt_completion *completion)
|
||||
{
|
||||
rt_base_t level;
|
||||
RT_ASSERT(completion != RT_NULL);
|
||||
|
||||
if (completion->flag == RT_COMPLETED)
|
||||
return;
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
completion->flag = RT_COMPLETED;
|
||||
|
||||
if (!rt_list_isempty(&(completion->suspended_list)))
|
||||
{
|
||||
/* there is one thread in suspended list */
|
||||
struct rt_thread *thread;
|
||||
|
||||
/* get thread entry */
|
||||
thread = rt_list_entry(completion->suspended_list.next,
|
||||
struct rt_thread,
|
||||
tlist);
|
||||
|
||||
/* resume it */
|
||||
rt_thread_resume(thread);
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
/* perform a schedule */
|
||||
rt_schedule();
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_hw_interrupt_enable(level);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,353 @@
|
||||
/*
|
||||
* File : dataqueue.c
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2012, RT-Thread Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-09-30 Bernard first version.
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include <rthw.h>
|
||||
|
||||
struct rt_data_item
|
||||
{
|
||||
const void *data_ptr;
|
||||
rt_size_t data_size;
|
||||
};
|
||||
|
||||
rt_err_t
|
||||
rt_data_queue_init(struct rt_data_queue *queue,
|
||||
rt_uint16_t size,
|
||||
rt_uint16_t lwm,
|
||||
void (*evt_notify)(struct rt_data_queue *queue, rt_uint32_t event))
|
||||
{
|
||||
RT_ASSERT(queue != RT_NULL);
|
||||
|
||||
queue->evt_notify = evt_notify;
|
||||
|
||||
queue->size = size;
|
||||
queue->lwm = lwm;
|
||||
queue->waiting_lwm = RT_FALSE;
|
||||
|
||||
queue->get_index = 0;
|
||||
queue->put_index = 0;
|
||||
|
||||
rt_list_init(&(queue->suspended_push_list));
|
||||
rt_list_init(&(queue->suspended_pop_list));
|
||||
|
||||
queue->queue = (struct rt_data_item *)rt_malloc(sizeof(struct rt_data_item) * size);
|
||||
if (queue->queue == RT_NULL)
|
||||
{
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
RTM_EXPORT(rt_data_queue_init);
|
||||
|
||||
rt_err_t rt_data_queue_push(struct rt_data_queue *queue,
|
||||
const void *data_ptr,
|
||||
rt_size_t data_size,
|
||||
rt_int32_t timeout)
|
||||
{
|
||||
rt_uint16_t mask;
|
||||
rt_ubase_t level;
|
||||
rt_thread_t thread;
|
||||
rt_err_t result;
|
||||
|
||||
RT_ASSERT(queue != RT_NULL);
|
||||
|
||||
result = RT_EOK;
|
||||
thread = rt_thread_self();
|
||||
mask = queue->size - 1;
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
while (queue->put_index - queue->get_index == queue->size)
|
||||
{
|
||||
queue->waiting_lwm = RT_TRUE;
|
||||
|
||||
/* queue is full */
|
||||
if (timeout == 0)
|
||||
{
|
||||
result = -RT_ETIMEOUT;
|
||||
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
/* current context checking */
|
||||
RT_DEBUG_NOT_IN_INTERRUPT;
|
||||
|
||||
/* reset thread error number */
|
||||
thread->error = RT_EOK;
|
||||
|
||||
/* suspend thread on the push list */
|
||||
rt_thread_suspend(thread);
|
||||
rt_list_insert_before(&(queue->suspended_push_list), &(thread->tlist));
|
||||
/* start timer */
|
||||
if (timeout > 0)
|
||||
{
|
||||
/* reset the timeout of thread timer and start it */
|
||||
rt_timer_control(&(thread->thread_timer),
|
||||
RT_TIMER_CTRL_SET_TIME,
|
||||
&timeout);
|
||||
rt_timer_start(&(thread->thread_timer));
|
||||
}
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
/* do schedule */
|
||||
rt_schedule();
|
||||
|
||||
/* thread is waked up */
|
||||
result = thread->error;
|
||||
level = rt_hw_interrupt_disable();
|
||||
if (result != RT_EOK) goto __exit;
|
||||
}
|
||||
|
||||
queue->queue[queue->put_index & mask].data_ptr = data_ptr;
|
||||
queue->queue[queue->put_index & mask].data_size = data_size;
|
||||
queue->put_index += 1;
|
||||
|
||||
if (!rt_list_isempty(&(queue->suspended_pop_list)))
|
||||
{
|
||||
/* there is at least one thread in suspended list */
|
||||
|
||||
/* get thread entry */
|
||||
thread = rt_list_entry(queue->suspended_pop_list.next,
|
||||
struct rt_thread,
|
||||
tlist);
|
||||
|
||||
/* resume it */
|
||||
rt_thread_resume(thread);
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
/* perform a schedule */
|
||||
rt_schedule();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
__exit:
|
||||
rt_hw_interrupt_enable(level);
|
||||
if ((result == RT_EOK) && queue->evt_notify != RT_NULL)
|
||||
{
|
||||
queue->evt_notify(queue, RT_DATAQUEUE_EVENT_PUSH);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
RTM_EXPORT(rt_data_queue_push);
|
||||
|
||||
rt_err_t rt_data_queue_pop(struct rt_data_queue *queue,
|
||||
const void** data_ptr,
|
||||
rt_size_t *size,
|
||||
rt_int32_t timeout)
|
||||
{
|
||||
rt_ubase_t level;
|
||||
rt_thread_t thread;
|
||||
rt_err_t result;
|
||||
rt_uint16_t mask;
|
||||
|
||||
RT_ASSERT(queue != RT_NULL);
|
||||
RT_ASSERT(data_ptr != RT_NULL);
|
||||
RT_ASSERT(size != RT_NULL);
|
||||
|
||||
result = RT_EOK;
|
||||
thread = rt_thread_self();
|
||||
mask = queue->size - 1;
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
while (queue->get_index == queue->put_index)
|
||||
{
|
||||
/* queue is empty */
|
||||
if (timeout == 0)
|
||||
{
|
||||
result = -RT_ETIMEOUT;
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
/* current context checking */
|
||||
RT_DEBUG_NOT_IN_INTERRUPT;
|
||||
|
||||
/* reset thread error number */
|
||||
thread->error = RT_EOK;
|
||||
|
||||
/* suspend thread on the pop list */
|
||||
rt_thread_suspend(thread);
|
||||
rt_list_insert_before(&(queue->suspended_pop_list), &(thread->tlist));
|
||||
/* start timer */
|
||||
if (timeout > 0)
|
||||
{
|
||||
/* reset the timeout of thread timer and start it */
|
||||
rt_timer_control(&(thread->thread_timer),
|
||||
RT_TIMER_CTRL_SET_TIME,
|
||||
&timeout);
|
||||
rt_timer_start(&(thread->thread_timer));
|
||||
}
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
/* do schedule */
|
||||
rt_schedule();
|
||||
|
||||
/* thread is waked up */
|
||||
result = thread->error;
|
||||
level = rt_hw_interrupt_disable();
|
||||
if (result != RT_EOK)
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
*data_ptr = queue->queue[queue->get_index & mask].data_ptr;
|
||||
*size = queue->queue[queue->get_index & mask].data_size;
|
||||
|
||||
queue->get_index += 1;
|
||||
|
||||
if ((queue->waiting_lwm == RT_TRUE) &&
|
||||
(queue->put_index - queue->get_index) <= queue->lwm)
|
||||
{
|
||||
queue->waiting_lwm = RT_FALSE;
|
||||
|
||||
/*
|
||||
* there is at least one thread in suspended list
|
||||
* and less than low water mark
|
||||
*/
|
||||
if (!rt_list_isempty(&(queue->suspended_push_list)))
|
||||
{
|
||||
/* get thread entry */
|
||||
thread = rt_list_entry(queue->suspended_push_list.next,
|
||||
struct rt_thread,
|
||||
tlist);
|
||||
|
||||
/* resume it */
|
||||
rt_thread_resume(thread);
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
/* perform a schedule */
|
||||
rt_schedule();
|
||||
}
|
||||
|
||||
if (queue->evt_notify != RT_NULL)
|
||||
queue->evt_notify(queue, RT_DATAQUEUE_EVENT_LWM);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
__exit:
|
||||
rt_hw_interrupt_enable(level);
|
||||
if ((result == RT_EOK) && (queue->evt_notify != RT_NULL))
|
||||
{
|
||||
queue->evt_notify(queue, RT_DATAQUEUE_EVENT_POP);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
RTM_EXPORT(rt_data_queue_pop);
|
||||
|
||||
rt_err_t rt_data_queue_peak(struct rt_data_queue *queue,
|
||||
const void** data_ptr,
|
||||
rt_size_t *size)
|
||||
{
|
||||
rt_ubase_t level;
|
||||
rt_uint16_t mask;
|
||||
|
||||
RT_ASSERT(queue != RT_NULL);
|
||||
|
||||
mask = queue->size - 1;
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
if (queue->get_index == queue->put_index)
|
||||
{
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
return -RT_EEMPTY;
|
||||
}
|
||||
|
||||
*data_ptr = queue->queue[queue->get_index & mask].data_ptr;
|
||||
*size = queue->queue[queue->get_index & mask].data_size;
|
||||
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
RTM_EXPORT(rt_data_queue_peak);
|
||||
|
||||
void rt_data_queue_reset(struct rt_data_queue *queue)
|
||||
{
|
||||
struct rt_thread *thread;
|
||||
register rt_ubase_t temp;
|
||||
|
||||
rt_enter_critical();
|
||||
/* wakeup all suspend threads */
|
||||
|
||||
/* resume on pop list */
|
||||
while (!rt_list_isempty(&(queue->suspended_pop_list)))
|
||||
{
|
||||
/* disable interrupt */
|
||||
temp = rt_hw_interrupt_disable();
|
||||
|
||||
/* get next suspend thread */
|
||||
thread = rt_list_entry(queue->suspended_pop_list.next,
|
||||
struct rt_thread,
|
||||
tlist);
|
||||
/* set error code to RT_ERROR */
|
||||
thread->error = -RT_ERROR;
|
||||
|
||||
/*
|
||||
* resume thread
|
||||
* In rt_thread_resume function, it will remove current thread from
|
||||
* suspend list
|
||||
*/
|
||||
rt_thread_resume(thread);
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(temp);
|
||||
}
|
||||
|
||||
/* resume on push list */
|
||||
while (!rt_list_isempty(&(queue->suspended_push_list)))
|
||||
{
|
||||
/* disable interrupt */
|
||||
temp = rt_hw_interrupt_disable();
|
||||
|
||||
/* get next suspend thread */
|
||||
thread = rt_list_entry(queue->suspended_push_list.next,
|
||||
struct rt_thread,
|
||||
tlist);
|
||||
/* set error code to RT_ERROR */
|
||||
thread->error = -RT_ERROR;
|
||||
|
||||
/*
|
||||
* resume thread
|
||||
* In rt_thread_resume function, it will remove current thread from
|
||||
* suspend list
|
||||
*/
|
||||
rt_thread_resume(thread);
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(temp);
|
||||
}
|
||||
rt_exit_critical();
|
||||
|
||||
rt_schedule();
|
||||
}
|
||||
RTM_EXPORT(rt_data_queue_reset);
|
||||
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* File : pipe.c
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2012, RT-Thread Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-09-30 Bernard first version.
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
static void _rt_pipe_resume_writer(struct rt_pipe_device *pipe)
|
||||
{
|
||||
if (!rt_list_isempty(&pipe->suspended_write_list))
|
||||
{
|
||||
rt_thread_t thread;
|
||||
|
||||
RT_ASSERT(pipe->flag & RT_PIPE_FLAG_BLOCK_WR);
|
||||
|
||||
/* get suspended thread */
|
||||
thread = rt_list_entry(pipe->suspended_write_list.next,
|
||||
struct rt_thread,
|
||||
tlist);
|
||||
|
||||
/* resume the write thread */
|
||||
rt_thread_resume(thread);
|
||||
|
||||
rt_schedule();
|
||||
}
|
||||
}
|
||||
|
||||
static rt_size_t rt_pipe_read(rt_device_t dev,
|
||||
rt_off_t pos,
|
||||
void *buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
rt_uint32_t level;
|
||||
rt_thread_t thread;
|
||||
struct rt_pipe_device *pipe;
|
||||
rt_size_t read_nbytes;
|
||||
|
||||
pipe = PIPE_DEVICE(dev);
|
||||
RT_ASSERT(pipe != RT_NULL);
|
||||
|
||||
if (!(pipe->flag & RT_PIPE_FLAG_BLOCK_RD))
|
||||
{
|
||||
level = rt_hw_interrupt_disable();
|
||||
read_nbytes = rt_ringbuffer_get(&(pipe->ringbuffer), buffer, size);
|
||||
|
||||
/* if the ringbuffer is empty, there won't be any writer waiting */
|
||||
if (read_nbytes)
|
||||
_rt_pipe_resume_writer(pipe);
|
||||
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
return read_nbytes;
|
||||
}
|
||||
|
||||
thread = rt_thread_self();
|
||||
|
||||
/* current context checking */
|
||||
RT_DEBUG_NOT_IN_INTERRUPT;
|
||||
|
||||
do {
|
||||
level = rt_hw_interrupt_disable();
|
||||
read_nbytes = rt_ringbuffer_get(&(pipe->ringbuffer), buffer, size);
|
||||
if (read_nbytes == 0)
|
||||
{
|
||||
rt_thread_suspend(thread);
|
||||
/* waiting on suspended read list */
|
||||
rt_list_insert_before(&(pipe->suspended_read_list),
|
||||
&(thread->tlist));
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
rt_schedule();
|
||||
}
|
||||
else
|
||||
{
|
||||
_rt_pipe_resume_writer(pipe);
|
||||
rt_hw_interrupt_enable(level);
|
||||
break;
|
||||
}
|
||||
} while (read_nbytes == 0);
|
||||
|
||||
return read_nbytes;
|
||||
}
|
||||
|
||||
static void _rt_pipe_resume_reader(struct rt_pipe_device *pipe)
|
||||
{
|
||||
if (pipe->parent.rx_indicate)
|
||||
pipe->parent.rx_indicate(&pipe->parent,
|
||||
rt_ringbuffer_data_len(&pipe->ringbuffer));
|
||||
|
||||
if (!rt_list_isempty(&pipe->suspended_read_list))
|
||||
{
|
||||
rt_thread_t thread;
|
||||
|
||||
RT_ASSERT(pipe->flag & RT_PIPE_FLAG_BLOCK_RD);
|
||||
|
||||
/* get suspended thread */
|
||||
thread = rt_list_entry(pipe->suspended_read_list.next,
|
||||
struct rt_thread,
|
||||
tlist);
|
||||
|
||||
/* resume the read thread */
|
||||
rt_thread_resume(thread);
|
||||
|
||||
rt_schedule();
|
||||
}
|
||||
}
|
||||
|
||||
static rt_size_t rt_pipe_write(rt_device_t dev,
|
||||
rt_off_t pos,
|
||||
const void *buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
rt_uint32_t level;
|
||||
rt_thread_t thread;
|
||||
struct rt_pipe_device *pipe;
|
||||
rt_size_t write_nbytes;
|
||||
|
||||
pipe = PIPE_DEVICE(dev);
|
||||
RT_ASSERT(pipe != RT_NULL);
|
||||
|
||||
if ((pipe->flag & RT_PIPE_FLAG_FORCE_WR) ||
|
||||
!(pipe->flag & RT_PIPE_FLAG_BLOCK_WR))
|
||||
{
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
if (pipe->flag & RT_PIPE_FLAG_FORCE_WR)
|
||||
write_nbytes = rt_ringbuffer_put_force(&(pipe->ringbuffer),
|
||||
buffer, size);
|
||||
else
|
||||
write_nbytes = rt_ringbuffer_put(&(pipe->ringbuffer),
|
||||
buffer, size);
|
||||
|
||||
_rt_pipe_resume_reader(pipe);
|
||||
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
return write_nbytes;
|
||||
}
|
||||
|
||||
thread = rt_thread_self();
|
||||
|
||||
/* current context checking */
|
||||
RT_DEBUG_NOT_IN_INTERRUPT;
|
||||
|
||||
do {
|
||||
level = rt_hw_interrupt_disable();
|
||||
write_nbytes = rt_ringbuffer_put(&(pipe->ringbuffer), buffer, size);
|
||||
if (write_nbytes == 0)
|
||||
{
|
||||
/* pipe full, waiting on suspended write list */
|
||||
rt_thread_suspend(thread);
|
||||
/* waiting on suspended read list */
|
||||
rt_list_insert_before(&(pipe->suspended_write_list),
|
||||
&(thread->tlist));
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
rt_schedule();
|
||||
}
|
||||
else
|
||||
{
|
||||
_rt_pipe_resume_reader(pipe);
|
||||
rt_hw_interrupt_enable(level);
|
||||
break;
|
||||
}
|
||||
} while (write_nbytes == 0);
|
||||
|
||||
return write_nbytes;
|
||||
}
|
||||
|
||||
static rt_err_t rt_pipe_control(rt_device_t dev, rt_uint8_t cmd, void *args)
|
||||
{
|
||||
if (cmd == PIPE_CTRL_GET_SPACE && args)
|
||||
*(rt_size_t*)args = rt_ringbuffer_space_len(&PIPE_DEVICE(dev)->ringbuffer);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will initialize a pipe device and put it under control of
|
||||
* resource management.
|
||||
*
|
||||
* @param pipe the pipe device
|
||||
* @param name the name of pipe device
|
||||
* @param flag the attribute of the pipe device
|
||||
* @param buf the buffer of pipe device
|
||||
* @param size the size of pipe device buffer
|
||||
*
|
||||
* @return the operation status, RT_EOK on successful
|
||||
*/
|
||||
rt_err_t rt_pipe_init(struct rt_pipe_device *pipe,
|
||||
const char *name,
|
||||
enum rt_pipe_flag flag,
|
||||
rt_uint8_t *buf,
|
||||
rt_size_t size)
|
||||
{
|
||||
RT_ASSERT(pipe);
|
||||
RT_ASSERT(buf);
|
||||
|
||||
/* initialize suspended list */
|
||||
rt_list_init(&pipe->suspended_read_list);
|
||||
rt_list_init(&pipe->suspended_write_list);
|
||||
|
||||
/* initialize ring buffer */
|
||||
rt_ringbuffer_init(&pipe->ringbuffer, buf, size);
|
||||
|
||||
pipe->flag = flag;
|
||||
|
||||
/* create pipe */
|
||||
pipe->parent.type = RT_Device_Class_Pipe;
|
||||
pipe->parent.init = RT_NULL;
|
||||
pipe->parent.open = RT_NULL;
|
||||
pipe->parent.close = RT_NULL;
|
||||
pipe->parent.read = rt_pipe_read;
|
||||
pipe->parent.write = rt_pipe_write;
|
||||
pipe->parent.control = rt_pipe_control;
|
||||
|
||||
return rt_device_register(&(pipe->parent), name, RT_DEVICE_FLAG_RDWR);
|
||||
}
|
||||
RTM_EXPORT(rt_pipe_init);
|
||||
|
||||
/**
|
||||
* This function will detach a pipe device from resource management
|
||||
*
|
||||
* @param pipe the pipe device
|
||||
*
|
||||
* @return the operation status, RT_EOK on successful
|
||||
*/
|
||||
rt_err_t rt_pipe_detach(struct rt_pipe_device *pipe)
|
||||
{
|
||||
return rt_device_unregister(&pipe->parent);
|
||||
}
|
||||
RTM_EXPORT(rt_pipe_detach);
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
rt_err_t rt_pipe_create(const char *name, enum rt_pipe_flag flag, rt_size_t size)
|
||||
{
|
||||
rt_uint8_t *rb_memptr = RT_NULL;
|
||||
struct rt_pipe_device *pipe = RT_NULL;
|
||||
|
||||
/* get aligned size */
|
||||
size = RT_ALIGN(size, RT_ALIGN_SIZE);
|
||||
pipe = (struct rt_pipe_device *)rt_calloc(1, sizeof(struct rt_pipe_device));
|
||||
if (pipe == RT_NULL)
|
||||
return -RT_ENOMEM;
|
||||
|
||||
/* create ring buffer of pipe */
|
||||
rb_memptr = rt_malloc(size);
|
||||
if (rb_memptr == RT_NULL)
|
||||
{
|
||||
rt_free(pipe);
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
return rt_pipe_init(pipe, name, flag, rb_memptr, size);
|
||||
}
|
||||
RTM_EXPORT(rt_pipe_create);
|
||||
|
||||
void rt_pipe_destroy(struct rt_pipe_device *pipe)
|
||||
{
|
||||
if (pipe == RT_NULL)
|
||||
return;
|
||||
|
||||
/* un-register pipe device */
|
||||
rt_pipe_detach(pipe);
|
||||
|
||||
/* release memory */
|
||||
rt_free(pipe->ringbuffer.buffer_ptr);
|
||||
rt_free(pipe);
|
||||
|
||||
return;
|
||||
}
|
||||
RTM_EXPORT(rt_pipe_destroy);
|
||||
#endif /* RT_USING_HEAP */
|
||||
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* File : portal.c
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2013, RT-Thread Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-08-19 Grissiom initial version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#define PT_WRITE_DEV(pt) (((struct rt_portal_device*)pt)->write_dev)
|
||||
#define PT_READ_DEV(pt) (((struct rt_portal_device*)pt)->read_dev)
|
||||
|
||||
static rt_err_t _portal_init(rt_device_t dev)
|
||||
{
|
||||
rt_err_t err;
|
||||
struct rt_portal_device *portal;
|
||||
|
||||
RT_ASSERT(dev);
|
||||
|
||||
portal = (struct rt_portal_device*)dev;
|
||||
|
||||
err = rt_device_init(portal->write_dev);
|
||||
if (err != RT_EOK)
|
||||
return err;
|
||||
|
||||
err = rt_device_init(portal->read_dev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static rt_err_t _portal_open(rt_device_t dev, rt_uint16_t oflag)
|
||||
{
|
||||
rt_err_t err;
|
||||
struct rt_portal_device *portal;
|
||||
|
||||
RT_ASSERT(dev);
|
||||
|
||||
if (!oflag)
|
||||
return -RT_ERROR;
|
||||
|
||||
portal = (struct rt_portal_device*)dev;
|
||||
|
||||
if (oflag & RT_DEVICE_OFLAG_RDONLY)
|
||||
{
|
||||
err = rt_device_open(portal->read_dev, RT_DEVICE_OFLAG_RDONLY);
|
||||
if (err != RT_EOK)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (oflag & RT_DEVICE_OFLAG_WRONLY)
|
||||
{
|
||||
err = rt_device_open(portal->write_dev, RT_DEVICE_OFLAG_WRONLY);
|
||||
if (err != RT_EOK)
|
||||
return err;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t _portal_close(rt_device_t dev)
|
||||
{
|
||||
struct rt_portal_device *portal;
|
||||
|
||||
RT_ASSERT(dev);
|
||||
|
||||
portal = (struct rt_portal_device*)dev;
|
||||
|
||||
rt_device_close(portal->write_dev);
|
||||
rt_device_close(portal->read_dev);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_size_t _portal_read(rt_device_t dev,
|
||||
rt_off_t pos,
|
||||
void *buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
return rt_device_read(PT_READ_DEV(dev),
|
||||
pos, buffer, size);
|
||||
}
|
||||
|
||||
static rt_size_t _portal_write(rt_device_t dev,
|
||||
rt_off_t pos,
|
||||
const void *buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
return rt_device_write(PT_WRITE_DEV(dev),
|
||||
pos, buffer, size);
|
||||
}
|
||||
|
||||
static rt_err_t _portal_rx_indicate(rt_device_t dev, rt_size_t size)
|
||||
{
|
||||
struct rt_pipe_device *pipe;
|
||||
|
||||
RT_ASSERT(dev && dev->type == RT_Device_Class_Pipe);
|
||||
|
||||
pipe = (struct rt_pipe_device*)dev;
|
||||
|
||||
if (pipe->read_portal->parent.rx_indicate)
|
||||
return pipe->read_portal->parent.rx_indicate(
|
||||
(rt_device_t)pipe->read_portal, size);
|
||||
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
|
||||
static rt_err_t _portal_tx_complete(rt_device_t dev, void *buf)
|
||||
{
|
||||
struct rt_pipe_device *pipe;
|
||||
|
||||
RT_ASSERT(dev && dev->type == RT_Device_Class_Pipe);
|
||||
|
||||
pipe = (struct rt_pipe_device*)dev;
|
||||
|
||||
if (pipe->write_portal->parent.tx_complete)
|
||||
return pipe->write_portal->parent.tx_complete(
|
||||
(rt_device_t)pipe->write_portal, buf);
|
||||
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will initialize a portal device and put it under control of
|
||||
* resource management.
|
||||
*
|
||||
* Portal is a device that connect devices
|
||||
*
|
||||
* Currently, you can only connect pipes in portal. Pipes are unidirectional.
|
||||
* But with portal, you can construct a bidirectional device with two pipes.
|
||||
* The inner connection is just like this:
|
||||
*
|
||||
* portal0 portal1
|
||||
* read || || write
|
||||
* <--<---||<---<---||<---<-- (pipe0)
|
||||
* || ||
|
||||
* -->--->||--->--->||--->--> (pipe1)
|
||||
* write || || read
|
||||
*
|
||||
* You will always construct two portals on two pipes, say, "portal0" and
|
||||
* "portal1". Data written into "portal0" can be retrieved in "portal1" and
|
||||
* vice versa. `rx_indicate` and `tx_complete` events are propagated
|
||||
* accordingly.
|
||||
*
|
||||
* @param portal the portal device
|
||||
* @param portal_name the name of the portal device
|
||||
* @param write_dev the name of the pipe device that this portal write into
|
||||
* @param read_dev the name of the pipe device that this portal read from
|
||||
*
|
||||
* @return the operation status, RT_EOK on successful. -RT_ENOSYS on one pipe
|
||||
* device could not be found.
|
||||
*/
|
||||
rt_err_t rt_portal_init(struct rt_portal_device *portal,
|
||||
const char *portal_name,
|
||||
const char *write_dev,
|
||||
const char *read_dev)
|
||||
{
|
||||
rt_device_t dev;
|
||||
|
||||
RT_ASSERT(portal);
|
||||
|
||||
portal->parent.type = RT_Device_Class_Portal;
|
||||
portal->parent.init = _portal_init;
|
||||
portal->parent.open = _portal_open;
|
||||
portal->parent.close = _portal_close;
|
||||
portal->parent.write = _portal_write;
|
||||
portal->parent.read = _portal_read;
|
||||
/* single control of the two devices makes no sense */
|
||||
portal->parent.control = RT_NULL;
|
||||
|
||||
dev = rt_device_find(write_dev);
|
||||
if (dev == RT_NULL)
|
||||
return -RT_ENOSYS;
|
||||
RT_ASSERT(dev->type == RT_Device_Class_Pipe);
|
||||
portal->write_dev = dev;
|
||||
rt_device_set_tx_complete(&portal->parent, dev->tx_complete);
|
||||
rt_device_set_tx_complete(dev, _portal_tx_complete);
|
||||
((struct rt_pipe_device*)dev)->write_portal = portal;
|
||||
|
||||
dev = rt_device_find(read_dev);
|
||||
if (dev == RT_NULL)
|
||||
{
|
||||
rt_device_set_tx_complete(dev, portal->parent.tx_complete);
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
RT_ASSERT(dev->type == RT_Device_Class_Pipe);
|
||||
portal->read_dev = dev;
|
||||
rt_device_set_rx_indicate(&portal->parent, dev->rx_indicate);
|
||||
rt_device_set_rx_indicate(dev, _portal_rx_indicate);
|
||||
((struct rt_pipe_device*)dev)->read_portal = portal;
|
||||
|
||||
return rt_device_register(&(portal->parent),
|
||||
portal_name,
|
||||
RT_DEVICE_FLAG_RDWR);
|
||||
}
|
||||
RTM_EXPORT(rt_portal_init);
|
||||
|
||||
/**
|
||||
* This function will detach a portal device from resource management
|
||||
*
|
||||
* @param portal the portal device
|
||||
*
|
||||
* @return the operation status, RT_EOK on successful
|
||||
*/
|
||||
rt_err_t rt_portal_detach(struct rt_portal_device *portal)
|
||||
{
|
||||
return rt_device_unregister(&portal->parent);
|
||||
}
|
||||
RTM_EXPORT(rt_portal_detach);
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
rt_err_t rt_portal_create(const char *name,
|
||||
const char *write_dev,
|
||||
const char *read_dev)
|
||||
{
|
||||
struct rt_portal_device *portal;
|
||||
|
||||
portal = (struct rt_portal_device*)rt_calloc(1, sizeof(*portal));
|
||||
if (portal == RT_NULL)
|
||||
return -RT_ENOMEM;
|
||||
|
||||
return rt_portal_init(portal, name, write_dev, read_dev);
|
||||
}
|
||||
RTM_EXPORT(rt_portal_create);
|
||||
|
||||
void rt_portal_destroy(struct rt_portal_device *portal)
|
||||
{
|
||||
if (portal == RT_NULL)
|
||||
return;
|
||||
|
||||
rt_portal_detach(portal);
|
||||
|
||||
rt_free(portal);
|
||||
|
||||
return;
|
||||
}
|
||||
RTM_EXPORT(rt_portal_destroy);
|
||||
#endif /* RT_USING_HEAP */
|
||||
|
||||
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
* File : ringbuffer.c
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2012, RT-Thread Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-09-30 Bernard first version.
|
||||
* 2013-05-08 Grissiom reimplement
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include <string.h>
|
||||
|
||||
void rt_ringbuffer_init(struct rt_ringbuffer *rb,
|
||||
rt_uint8_t *pool,
|
||||
rt_int16_t size)
|
||||
{
|
||||
RT_ASSERT(rb != RT_NULL);
|
||||
RT_ASSERT(size > 0)
|
||||
|
||||
/* initialize read and write index */
|
||||
rb->read_mirror = rb->read_index = 0;
|
||||
rb->write_mirror = rb->write_index = 0;
|
||||
|
||||
/* set buffer pool and size */
|
||||
rb->buffer_ptr = pool;
|
||||
rb->buffer_size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
|
||||
}
|
||||
RTM_EXPORT(rt_ringbuffer_init);
|
||||
|
||||
/**
|
||||
* put a block of data into ring buffer
|
||||
*/
|
||||
rt_size_t rt_ringbuffer_put(struct rt_ringbuffer *rb,
|
||||
const rt_uint8_t *ptr,
|
||||
rt_uint16_t length)
|
||||
{
|
||||
rt_uint16_t size;
|
||||
|
||||
RT_ASSERT(rb != RT_NULL);
|
||||
|
||||
/* whether has enough space */
|
||||
size = rt_ringbuffer_space_len(rb);
|
||||
|
||||
/* no space */
|
||||
if (size == 0)
|
||||
return 0;
|
||||
|
||||
/* drop some data */
|
||||
if (size < length)
|
||||
length = size;
|
||||
|
||||
if (rb->buffer_size - rb->write_index > length)
|
||||
{
|
||||
/* read_index - write_index = empty space */
|
||||
memcpy(&rb->buffer_ptr[rb->write_index], ptr, length);
|
||||
/* this should not cause overflow because there is enough space for
|
||||
* length of data in current mirror */
|
||||
rb->write_index += length;
|
||||
return length;
|
||||
}
|
||||
|
||||
memcpy(&rb->buffer_ptr[rb->write_index],
|
||||
&ptr[0],
|
||||
rb->buffer_size - rb->write_index);
|
||||
memcpy(&rb->buffer_ptr[0],
|
||||
&ptr[rb->buffer_size - rb->write_index],
|
||||
length - (rb->buffer_size - rb->write_index));
|
||||
|
||||
/* we are going into the other side of the mirror */
|
||||
rb->write_mirror = ~rb->write_mirror;
|
||||
rb->write_index = length - (rb->buffer_size - rb->write_index);
|
||||
|
||||
return length;
|
||||
}
|
||||
RTM_EXPORT(rt_ringbuffer_put);
|
||||
|
||||
/**
|
||||
* put a block of data into ring buffer
|
||||
*
|
||||
* When the buffer is full, it will discard the old data.
|
||||
*/
|
||||
rt_size_t rt_ringbuffer_put_force(struct rt_ringbuffer *rb,
|
||||
const rt_uint8_t *ptr,
|
||||
rt_uint16_t length)
|
||||
{
|
||||
enum rt_ringbuffer_state old_state;
|
||||
|
||||
RT_ASSERT(rb != RT_NULL);
|
||||
|
||||
old_state = rt_ringbuffer_status(rb);
|
||||
|
||||
if (length > rb->buffer_size)
|
||||
length = rb->buffer_size;
|
||||
|
||||
if (rb->buffer_size - rb->write_index > length)
|
||||
{
|
||||
/* read_index - write_index = empty space */
|
||||
memcpy(&rb->buffer_ptr[rb->write_index], ptr, length);
|
||||
/* this should not cause overflow because there is enough space for
|
||||
* length of data in current mirror */
|
||||
rb->write_index += length;
|
||||
|
||||
if (old_state == RT_RINGBUFFER_FULL)
|
||||
rb->read_index = rb->write_index;
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
memcpy(&rb->buffer_ptr[rb->write_index],
|
||||
&ptr[0],
|
||||
rb->buffer_size - rb->write_index);
|
||||
memcpy(&rb->buffer_ptr[0],
|
||||
&ptr[rb->buffer_size - rb->write_index],
|
||||
length - (rb->buffer_size - rb->write_index));
|
||||
|
||||
/* we are going into the other side of the mirror */
|
||||
rb->write_mirror = ~rb->write_mirror;
|
||||
rb->write_index = length - (rb->buffer_size - rb->write_index);
|
||||
|
||||
if (old_state == RT_RINGBUFFER_FULL)
|
||||
{
|
||||
rb->read_mirror = ~rb->read_mirror;
|
||||
rb->read_index = rb->write_index;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
RTM_EXPORT(rt_ringbuffer_put_force);
|
||||
|
||||
/**
|
||||
* get data from ring buffer
|
||||
*/
|
||||
rt_size_t rt_ringbuffer_get(struct rt_ringbuffer *rb,
|
||||
rt_uint8_t *ptr,
|
||||
rt_uint16_t length)
|
||||
{
|
||||
rt_size_t size;
|
||||
|
||||
RT_ASSERT(rb != RT_NULL);
|
||||
|
||||
/* whether has enough data */
|
||||
size = rt_ringbuffer_data_len(rb);
|
||||
|
||||
/* no data */
|
||||
if (size == 0)
|
||||
return 0;
|
||||
|
||||
/* less data */
|
||||
if (size < length)
|
||||
length = size;
|
||||
|
||||
if (rb->buffer_size - rb->read_index > length)
|
||||
{
|
||||
/* copy all of data */
|
||||
memcpy(ptr, &rb->buffer_ptr[rb->read_index], length);
|
||||
/* this should not cause overflow because there is enough space for
|
||||
* length of data in current mirror */
|
||||
rb->read_index += length;
|
||||
return length;
|
||||
}
|
||||
|
||||
memcpy(&ptr[0],
|
||||
&rb->buffer_ptr[rb->read_index],
|
||||
rb->buffer_size - rb->read_index);
|
||||
memcpy(&ptr[rb->buffer_size - rb->read_index],
|
||||
&rb->buffer_ptr[0],
|
||||
length - (rb->buffer_size - rb->read_index));
|
||||
|
||||
/* we are going into the other side of the mirror */
|
||||
rb->read_mirror = ~rb->read_mirror;
|
||||
rb->read_index = length - (rb->buffer_size - rb->read_index);
|
||||
|
||||
return length;
|
||||
}
|
||||
RTM_EXPORT(rt_ringbuffer_get);
|
||||
|
||||
/**
|
||||
* put a character into ring buffer
|
||||
*/
|
||||
rt_size_t rt_ringbuffer_putchar(struct rt_ringbuffer *rb, const rt_uint8_t ch)
|
||||
{
|
||||
RT_ASSERT(rb != RT_NULL);
|
||||
|
||||
/* whether has enough space */
|
||||
if (!rt_ringbuffer_space_len(rb))
|
||||
return 0;
|
||||
|
||||
rb->buffer_ptr[rb->write_index] = ch;
|
||||
|
||||
/* flip mirror */
|
||||
if (rb->write_index == rb->buffer_size-1)
|
||||
{
|
||||
rb->write_mirror = ~rb->write_mirror;
|
||||
rb->write_index = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
rb->write_index++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
RTM_EXPORT(rt_ringbuffer_putchar);
|
||||
|
||||
/**
|
||||
* put a character into ring buffer
|
||||
*
|
||||
* When the buffer is full, it will discard one old data.
|
||||
*/
|
||||
rt_size_t rt_ringbuffer_putchar_force(struct rt_ringbuffer *rb, const rt_uint8_t ch)
|
||||
{
|
||||
enum rt_ringbuffer_state old_state;
|
||||
|
||||
RT_ASSERT(rb != RT_NULL);
|
||||
|
||||
old_state = rt_ringbuffer_status(rb);
|
||||
|
||||
rb->buffer_ptr[rb->write_index] = ch;
|
||||
|
||||
/* flip mirror */
|
||||
if (rb->write_index == rb->buffer_size-1)
|
||||
{
|
||||
rb->write_mirror = ~rb->write_mirror;
|
||||
rb->write_index = 0;
|
||||
if (old_state == RT_RINGBUFFER_FULL)
|
||||
{
|
||||
rb->read_mirror = ~rb->read_mirror;
|
||||
rb->read_index = rb->write_index;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rb->write_index++;
|
||||
if (old_state == RT_RINGBUFFER_FULL)
|
||||
rb->read_index = rb->write_index;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
RTM_EXPORT(rt_ringbuffer_putchar_force);
|
||||
|
||||
/**
|
||||
* get a character from a ringbuffer
|
||||
*/
|
||||
rt_size_t rt_ringbuffer_getchar(struct rt_ringbuffer *rb, rt_uint8_t *ch)
|
||||
{
|
||||
RT_ASSERT(rb != RT_NULL);
|
||||
|
||||
/* ringbuffer is empty */
|
||||
if (!rt_ringbuffer_data_len(rb))
|
||||
return 0;
|
||||
|
||||
/* put character */
|
||||
*ch = rb->buffer_ptr[rb->read_index];
|
||||
|
||||
if (rb->read_index == rb->buffer_size-1)
|
||||
{
|
||||
rb->read_mirror = ~rb->read_mirror;
|
||||
rb->read_index = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
rb->read_index++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
RTM_EXPORT(rt_ringbuffer_getchar);
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
static void _workqueue_thread_entry(void* parameter)
|
||||
{
|
||||
struct rt_work* work;
|
||||
struct rt_workqueue* queue;
|
||||
|
||||
queue = (struct rt_workqueue*) parameter;
|
||||
RT_ASSERT(queue != RT_NULL);
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (rt_list_isempty(&(queue->work_list)))
|
||||
{
|
||||
/* no software timer exist, suspend self. */
|
||||
rt_thread_suspend(rt_thread_self());
|
||||
rt_schedule();
|
||||
}
|
||||
|
||||
/* we have work to do with. */
|
||||
rt_enter_critical();
|
||||
work = rt_list_entry(queue->work_list.next, struct rt_work, list);
|
||||
rt_list_remove(&(work->list));
|
||||
rt_exit_critical();
|
||||
|
||||
/* do work */
|
||||
work->work_func(work, work->work_data);
|
||||
}
|
||||
}
|
||||
|
||||
struct rt_workqueue *rt_workqueue_create(const char* name, rt_uint16_t stack_size, rt_uint8_t priority)
|
||||
{
|
||||
struct rt_workqueue *queue = RT_NULL;
|
||||
|
||||
queue = (struct rt_workqueue*)RT_KERNEL_MALLOC(sizeof(struct rt_workqueue));
|
||||
if (queue != RT_NULL)
|
||||
{
|
||||
/* initialize work list */
|
||||
rt_list_init(&(queue->work_list));
|
||||
|
||||
/* create the work thread */
|
||||
queue->work_thread = rt_thread_create(name, _workqueue_thread_entry, queue, stack_size, priority, 10);
|
||||
if (queue->work_thread == RT_NULL)
|
||||
{
|
||||
RT_KERNEL_FREE(queue);
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
rt_thread_startup(queue->work_thread);
|
||||
}
|
||||
|
||||
return queue;
|
||||
}
|
||||
|
||||
rt_err_t rt_workqueue_destroy(struct rt_workqueue* queue)
|
||||
{
|
||||
RT_ASSERT(queue != RT_NULL);
|
||||
|
||||
rt_thread_delete(queue->work_thread);
|
||||
RT_KERNEL_FREE(queue);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
rt_err_t rt_workqueue_dowork(struct rt_workqueue* queue, struct rt_work* work)
|
||||
{
|
||||
RT_ASSERT(queue != RT_NULL);
|
||||
RT_ASSERT(work != RT_NULL);
|
||||
|
||||
rt_enter_critical();
|
||||
/* NOTE: the work MUST be initialized firstly */
|
||||
rt_list_remove(&(work->list));
|
||||
|
||||
rt_list_insert_after(queue->work_list.prev, &(work->list));
|
||||
if (queue->work_thread->stat != RT_THREAD_READY)
|
||||
{
|
||||
rt_exit_critical();
|
||||
/* resume work thread */
|
||||
rt_thread_resume(queue->work_thread);
|
||||
rt_schedule();
|
||||
}
|
||||
else rt_exit_critical();
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
rt_err_t rt_workqueue_cancel_work(struct rt_workqueue* queue, struct rt_work* work)
|
||||
{
|
||||
RT_ASSERT(queue != RT_NULL);
|
||||
RT_ASSERT(work != RT_NULL);
|
||||
|
||||
rt_enter_critical();
|
||||
rt_list_remove(&(work->list));
|
||||
rt_exit_critical();
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,45 @@
|
||||
Import('rtconfig')
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Split('''
|
||||
shell.c
|
||||
symbol.c
|
||||
cmd.c
|
||||
''')
|
||||
|
||||
fsh_src = Split('''
|
||||
finsh_compiler.c
|
||||
finsh_error.c
|
||||
finsh_heap.c
|
||||
finsh_init.c
|
||||
finsh_node.c
|
||||
finsh_ops.c
|
||||
finsh_parser.c
|
||||
finsh_var.c
|
||||
finsh_vm.c
|
||||
finsh_token.c
|
||||
''')
|
||||
|
||||
msh_src = Split('''
|
||||
msh_cmd.c
|
||||
msh.c
|
||||
''')
|
||||
|
||||
CPPPATH = [cwd]
|
||||
if rtconfig.CROSS_TOOL == 'keil':
|
||||
LINKFLAGS = ' --keep __fsym_*'
|
||||
|
||||
if not GetDepend('FINSH_USING_MSH_ONLY'):
|
||||
LINKFLAGS = LINKFLAGS + ' --keep __vsym_* '
|
||||
else:
|
||||
LINKFLAGS = ''
|
||||
|
||||
if GetDepend('FINSH_USING_MSH'):
|
||||
src = src + msh_src
|
||||
if not GetDepend('FINSH_USING_MSH_ONLY'):
|
||||
src = src + fsh_src
|
||||
|
||||
group = DefineGroup('finsh', src, depend = ['RT_USING_FINSH'], CPPPATH = CPPPATH, LINKFLAGS = LINKFLAGS)
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,893 @@
|
||||
/*
|
||||
* RT-Thread finsh shell commands
|
||||
*
|
||||
* COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team
|
||||
*
|
||||
* This file is part of RT-Thread (http://www.rt-thread.org)
|
||||
* Maintainer: bernard.xiong <bernard.xiong at gmail.com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2006-04-30 Bernard first implementation
|
||||
* 2006-05-04 Bernard add list_thread,
|
||||
* list_sem,
|
||||
* list_timer
|
||||
* 2006-05-20 Bernard add list_mutex,
|
||||
* list_mailbox,
|
||||
* list_msgqueue,
|
||||
* list_event,
|
||||
* list_fevent,
|
||||
* list_mempool
|
||||
* 2006-06-03 Bernard display stack information in list_thread
|
||||
* 2006-08-10 Bernard change version to invoke rt_show_version
|
||||
* 2008-09-10 Bernard update the list function for finsh syscall
|
||||
* list and sysvar list
|
||||
* 2009-05-30 Bernard add list_device
|
||||
* 2010-04-21 yi.qiu add list_module
|
||||
* 2012-04-29 goprife improve the command line auto-complete feature.
|
||||
* 2012-06-02 lgnq add list_memheap
|
||||
* 2012-10-22 Bernard add MS VC++ patch.
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "finsh.h"
|
||||
|
||||
rt_inline unsigned int rt_list_len(const rt_list_t *l)
|
||||
{
|
||||
unsigned int len = 0;
|
||||
const rt_list_t *p = l;
|
||||
while (p->next != l)
|
||||
{
|
||||
p = p->next;
|
||||
len ++;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
long hello(void)
|
||||
{
|
||||
rt_kprintf("Hello RT-Thread!\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT(hello, say hello world);
|
||||
|
||||
extern void rt_show_version(void);
|
||||
long version(void)
|
||||
{
|
||||
rt_show_version();
|
||||
|
||||
return 0;
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT(version, show RT-Thread version information);
|
||||
MSH_CMD_EXPORT(version, show RT-Thread version information);
|
||||
|
||||
extern struct rt_object_information rt_object_container[];
|
||||
|
||||
static long _list_thread(struct rt_list_node *list)
|
||||
{
|
||||
struct rt_thread *thread;
|
||||
struct rt_list_node *node;
|
||||
rt_uint8_t *ptr;
|
||||
|
||||
rt_kprintf(" thread pri status sp stack size max used left tick error\n");
|
||||
rt_kprintf("-------- ---- ------- ---------- ---------- ---------- ---------- ---\n");
|
||||
for (node = list->next; node != list; node = node->next)
|
||||
{
|
||||
thread = rt_list_entry(node, struct rt_thread, list);
|
||||
rt_kprintf("%-8.*s 0x%02x", RT_NAME_MAX, thread->name, thread->current_priority);
|
||||
|
||||
if (thread->stat == RT_THREAD_READY) rt_kprintf(" ready ");
|
||||
else if (thread->stat == RT_THREAD_SUSPEND) rt_kprintf(" suspend");
|
||||
else if (thread->stat == RT_THREAD_INIT) rt_kprintf(" init ");
|
||||
else if (thread->stat == RT_THREAD_CLOSE) rt_kprintf(" close ");
|
||||
|
||||
ptr = (rt_uint8_t*)thread->stack_addr;
|
||||
while (*ptr == '#')ptr ++;
|
||||
|
||||
rt_kprintf(" 0x%08x 0x%08x 0x%08x 0x%08x %03d\n",
|
||||
thread->stack_size + ((rt_uint32_t)thread->stack_addr - (rt_uint32_t)thread->sp),
|
||||
thread->stack_size,
|
||||
thread->stack_size - ((rt_uint32_t) ptr - (rt_uint32_t)thread->stack_addr),
|
||||
thread->remaining_tick,
|
||||
thread->error);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
long list_thread(void)
|
||||
{
|
||||
return _list_thread(&rt_object_container[RT_Object_Class_Thread].object_list);
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT(list_thread, list thread);
|
||||
MSH_CMD_EXPORT(list_thread, list thread);
|
||||
|
||||
static void show_wait_queue(struct rt_list_node *list)
|
||||
{
|
||||
struct rt_thread *thread;
|
||||
struct rt_list_node *node;
|
||||
|
||||
for (node = list->next; node != list; node = node->next)
|
||||
{
|
||||
thread = rt_list_entry(node, struct rt_thread, tlist);
|
||||
rt_kprintf("%s", thread->name);
|
||||
|
||||
if (node->next != list)
|
||||
rt_kprintf("/");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef RT_USING_SEMAPHORE
|
||||
static long _list_sem(struct rt_list_node *list)
|
||||
{
|
||||
struct rt_semaphore *sem;
|
||||
struct rt_list_node *node;
|
||||
|
||||
rt_kprintf("semaphore v suspend thread\n");
|
||||
rt_kprintf("-------- --- --------------\n");
|
||||
for (node = list->next; node != list; node = node->next)
|
||||
{
|
||||
sem = (struct rt_semaphore *)(rt_list_entry(node, struct rt_object, list));
|
||||
if (!rt_list_isempty(&sem->parent.suspend_thread))
|
||||
{
|
||||
rt_kprintf("%-8.*s %03d %d:",
|
||||
RT_NAME_MAX,
|
||||
sem->parent.parent.name,
|
||||
sem->value,
|
||||
rt_list_len(&sem->parent.suspend_thread));
|
||||
show_wait_queue(&(sem->parent.suspend_thread));
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("%-8.*s %03d %d\n",
|
||||
RT_NAME_MAX,
|
||||
sem->parent.parent.name,
|
||||
sem->value,
|
||||
rt_list_len(&sem->parent.suspend_thread));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
long list_sem(void)
|
||||
{
|
||||
return _list_sem(&rt_object_container[RT_Object_Class_Semaphore].object_list);
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT(list_sem, list semaphone in system);
|
||||
MSH_CMD_EXPORT(list_sem, list semaphore in system);
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_EVENT
|
||||
static long _list_event(struct rt_list_node *list)
|
||||
{
|
||||
struct rt_event *e;
|
||||
struct rt_list_node *node;
|
||||
|
||||
rt_kprintf("event set suspend thread\n");
|
||||
rt_kprintf("-------- ---------- --------------\n");
|
||||
for (node = list->next; node != list; node = node->next)
|
||||
{
|
||||
e = (struct rt_event *)(rt_list_entry(node, struct rt_object, list));
|
||||
if (!rt_list_isempty(&e->parent.suspend_thread))
|
||||
{
|
||||
rt_kprintf("%-8.*s 0x%08x %03d:",
|
||||
RT_NAME_MAX,
|
||||
e->parent.parent.name,
|
||||
e->set,
|
||||
rt_list_len(&e->parent.suspend_thread));
|
||||
show_wait_queue(&(e->parent.suspend_thread));
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("%-8.*s 0x%08x 0\n",
|
||||
RT_NAME_MAX, e->parent.parent.name, e->set);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
long list_event(void)
|
||||
{
|
||||
return _list_event(&rt_object_container[RT_Object_Class_Event].object_list);
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT(list_event, list event in system);
|
||||
MSH_CMD_EXPORT(list_event, list event in system);
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_MUTEX
|
||||
static long _list_mutex(struct rt_list_node *list)
|
||||
{
|
||||
struct rt_mutex *m;
|
||||
struct rt_list_node *node;
|
||||
|
||||
rt_kprintf("mutex owner hold suspend thread\n");
|
||||
rt_kprintf("-------- -------- ---- --------------\n");
|
||||
for (node = list->next; node != list; node = node->next)
|
||||
{
|
||||
m = (struct rt_mutex *)(rt_list_entry(node, struct rt_object, list));
|
||||
rt_kprintf("%-8.*s %-8.*s %04d %d\n",
|
||||
RT_NAME_MAX,
|
||||
m->parent.parent.name,
|
||||
RT_NAME_MAX,
|
||||
m->owner->name,
|
||||
m->hold,
|
||||
rt_list_len(&m->parent.suspend_thread));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
long list_mutex(void)
|
||||
{
|
||||
return _list_mutex(&rt_object_container[RT_Object_Class_Mutex].object_list);
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT(list_mutex, list mutex in system);
|
||||
MSH_CMD_EXPORT(list_mutex, list mutex in system);
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_MAILBOX
|
||||
static long _list_mailbox(struct rt_list_node *list)
|
||||
{
|
||||
struct rt_mailbox *m;
|
||||
struct rt_list_node *node;
|
||||
|
||||
rt_kprintf("mailbox entry size suspend thread\n");
|
||||
rt_kprintf("-------- ---- ---- --------------\n");
|
||||
for (node = list->next; node != list; node = node->next)
|
||||
{
|
||||
m = (struct rt_mailbox *)(rt_list_entry(node, struct rt_object, list));
|
||||
if (!rt_list_isempty(&m->parent.suspend_thread))
|
||||
{
|
||||
rt_kprintf("%-8.*s %04d %04d %d:",
|
||||
RT_NAME_MAX,
|
||||
m->parent.parent.name,
|
||||
m->entry,
|
||||
m->size,
|
||||
rt_list_len(&m->parent.suspend_thread));
|
||||
show_wait_queue(&(m->parent.suspend_thread));
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("%-8.*s %04d %04d %d\n",
|
||||
RT_NAME_MAX,
|
||||
m->parent.parent.name,
|
||||
m->entry,
|
||||
m->size,
|
||||
rt_list_len(&m->parent.suspend_thread));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
long list_mailbox(void)
|
||||
{
|
||||
return _list_mailbox(&rt_object_container[RT_Object_Class_MailBox].object_list);
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT(list_mailbox, list mail box in system);
|
||||
MSH_CMD_EXPORT(list_mailbox, list mail box in system);
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_MESSAGEQUEUE
|
||||
static long _list_msgqueue(struct rt_list_node *list)
|
||||
{
|
||||
struct rt_messagequeue *m;
|
||||
struct rt_list_node *node;
|
||||
|
||||
rt_kprintf("msgqueue entry suspend thread\n");
|
||||
rt_kprintf("-------- ---- --------------\n");
|
||||
for (node = list->next; node != list; node = node->next)
|
||||
{
|
||||
m = (struct rt_messagequeue *)(rt_list_entry(node, struct rt_object, list));
|
||||
if (!rt_list_isempty(&m->parent.suspend_thread))
|
||||
{
|
||||
rt_kprintf("%-8.*s %04d %d:",
|
||||
RT_NAME_MAX,
|
||||
m->parent.parent.name,
|
||||
m->entry,
|
||||
rt_list_len(&m->parent.suspend_thread));
|
||||
show_wait_queue(&(m->parent.suspend_thread));
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("%-8.*s %04d %d\n",
|
||||
RT_NAME_MAX,
|
||||
m->parent.parent.name,
|
||||
m->entry,
|
||||
rt_list_len(&m->parent.suspend_thread));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
long list_msgqueue(void)
|
||||
{
|
||||
return _list_msgqueue(&rt_object_container[RT_Object_Class_MessageQueue].object_list);
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT(list_msgqueue, list message queue in system);
|
||||
MSH_CMD_EXPORT(list_msgqueue, list message queue in system);
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_MEMHEAP
|
||||
static long _list_memheap(struct rt_list_node *list)
|
||||
{
|
||||
struct rt_memheap *mh;
|
||||
struct rt_list_node *node;
|
||||
|
||||
rt_kprintf("memheap pool size max used size available size\n");
|
||||
rt_kprintf("-------- ---------- ------------- --------------\n");
|
||||
for (node = list->next; node != list; node = node->next)
|
||||
{
|
||||
mh = (struct rt_memheap *)rt_list_entry(node, struct rt_object, list);
|
||||
|
||||
rt_kprintf("%-8.*s %-010d %-013d %-05d\n",
|
||||
RT_NAME_MAX,
|
||||
mh->parent.name,
|
||||
mh->pool_size,
|
||||
mh->max_used_size,
|
||||
mh->available_size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
long list_memheap(void)
|
||||
{
|
||||
return _list_memheap(&rt_object_container[RT_Object_Class_MemHeap].object_list);
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT(list_memheap, list memory heap in system);
|
||||
MSH_CMD_EXPORT(list_memheap, list memory heap in system);
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_MEMPOOL
|
||||
static long _list_mempool(struct rt_list_node *list)
|
||||
{
|
||||
struct rt_mempool *mp;
|
||||
struct rt_list_node *node;
|
||||
|
||||
rt_kprintf("mempool block total free suspend thread\n");
|
||||
rt_kprintf("-------- ---- ---- ---- --------------\n");
|
||||
for (node = list->next; node != list; node = node->next)
|
||||
{
|
||||
mp = (struct rt_mempool *)rt_list_entry(node, struct rt_object, list);
|
||||
if (mp->suspend_thread_count > 0)
|
||||
{
|
||||
rt_kprintf("%-8.*s %04d %04d %04d %d:",
|
||||
RT_NAME_MAX,
|
||||
mp->parent.name,
|
||||
mp->block_size,
|
||||
mp->block_total_count,
|
||||
mp->block_free_count,
|
||||
mp->suspend_thread_count);
|
||||
show_wait_queue(&(mp->suspend_thread));
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("%-8.*s %04d %04d %04d %d\n",
|
||||
RT_NAME_MAX,
|
||||
mp->parent.name,
|
||||
mp->block_size,
|
||||
mp->block_total_count,
|
||||
mp->block_free_count,
|
||||
mp->suspend_thread_count);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
long list_mempool(void)
|
||||
{
|
||||
return _list_mempool(&rt_object_container[RT_Object_Class_MemPool].object_list);
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT(list_mempool, list memory pool in system)
|
||||
MSH_CMD_EXPORT(list_mempool, list memory pool in system);
|
||||
#endif
|
||||
|
||||
static long _list_timer(struct rt_list_node *list)
|
||||
{
|
||||
struct rt_timer *timer;
|
||||
struct rt_list_node *node;
|
||||
|
||||
rt_kprintf("timer periodic timeout flag\n");
|
||||
rt_kprintf("-------- ---------- ---------- -----------\n");
|
||||
for (node = list->next; node != list; node = node->next)
|
||||
{
|
||||
timer = (struct rt_timer *)(rt_list_entry(node, struct rt_object, list));
|
||||
rt_kprintf("%-8.*s 0x%08x 0x%08x ",
|
||||
RT_NAME_MAX,
|
||||
timer->parent.name,
|
||||
timer->init_tick,
|
||||
timer->timeout_tick);
|
||||
if (timer->parent.flag & RT_TIMER_FLAG_ACTIVATED)
|
||||
rt_kprintf("activated\n");
|
||||
else
|
||||
rt_kprintf("deactivated\n");
|
||||
}
|
||||
|
||||
rt_kprintf("current tick:0x%08x\n", rt_tick_get());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
long list_timer(void)
|
||||
{
|
||||
return _list_timer(&rt_object_container[RT_Object_Class_Timer].object_list);
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT(list_timer, list timer in system);
|
||||
MSH_CMD_EXPORT(list_timer, list timer in system);
|
||||
|
||||
#ifdef RT_USING_DEVICE
|
||||
static long _list_device(struct rt_list_node *list)
|
||||
{
|
||||
struct rt_device *device;
|
||||
struct rt_list_node *node;
|
||||
char * const device_type_str[] =
|
||||
{
|
||||
"Character Device",
|
||||
"Block Device",
|
||||
"Network Interface",
|
||||
"MTD Device",
|
||||
"CAN Device",
|
||||
"RTC",
|
||||
"Sound Device",
|
||||
"Graphic Device",
|
||||
"I2C Bus",
|
||||
"USB Slave Device",
|
||||
"USB Host Bus",
|
||||
"SPI Bus",
|
||||
"SPI Device",
|
||||
"SDIO Bus",
|
||||
"PM Pseudo Device",
|
||||
"Pipe",
|
||||
"Portal Device",
|
||||
"Miscellaneous Device",
|
||||
"Unknown"
|
||||
};
|
||||
|
||||
rt_kprintf("device type \n");
|
||||
rt_kprintf("-------- ---------- \n");
|
||||
for (node = list->next; node != list; node = node->next)
|
||||
{
|
||||
device = (struct rt_device *)(rt_list_entry(node, struct rt_object, list));
|
||||
rt_kprintf("%-8.*s %-8s \n",
|
||||
RT_NAME_MAX,
|
||||
device->parent.name,
|
||||
(device->type <= RT_Device_Class_Unknown) ?
|
||||
device_type_str[device->type] :
|
||||
device_type_str[RT_Device_Class_Unknown]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
long list_device(void)
|
||||
{
|
||||
return _list_device(&rt_object_container[RT_Object_Class_Device].object_list);
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT(list_device, list device in system);
|
||||
MSH_CMD_EXPORT(list_device, list device in system);
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_MODULE
|
||||
#include <rtm.h>
|
||||
|
||||
int list_module(void)
|
||||
{
|
||||
struct rt_module *module;
|
||||
struct rt_list_node *list, *node;
|
||||
|
||||
list = &rt_object_container[RT_Object_Class_Module].object_list;
|
||||
|
||||
rt_kprintf("module name ref\n");
|
||||
rt_kprintf("------------ --------\n");
|
||||
for (node = list->next; node != list; node = node->next)
|
||||
{
|
||||
module = (struct rt_module *)(rt_list_entry(node, struct rt_object, list));
|
||||
rt_kprintf("%-16.*s %-04d\n",
|
||||
RT_NAME_MAX, module->parent.name, module->nref);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT(list_module, list module in system);
|
||||
MSH_CMD_EXPORT(list_module, list module in system);
|
||||
|
||||
int list_mod_detail(const char *name)
|
||||
{
|
||||
int i;
|
||||
struct rt_module *module;
|
||||
|
||||
/* find module */
|
||||
if ((module = rt_module_find(name)) != RT_NULL)
|
||||
{
|
||||
/* module has entry point */
|
||||
if (!(module->parent.flag & RT_MODULE_FLAG_WITHOUTENTRY))
|
||||
{
|
||||
struct rt_thread *thread;
|
||||
struct rt_list_node *tlist;
|
||||
rt_uint8_t *ptr;
|
||||
|
||||
/* list main thread in module */
|
||||
if (module->module_thread != RT_NULL)
|
||||
{
|
||||
rt_kprintf("main thread pri status sp stack size max used left tick error\n");
|
||||
rt_kprintf("------------- ---- ------- ---------- ---------- ---------- ---------- ---\n");
|
||||
thread = module->module_thread;
|
||||
rt_kprintf("%-8.*s 0x%02x", RT_NAME_MAX, thread->name, thread->current_priority);
|
||||
|
||||
if (thread->stat == RT_THREAD_READY) rt_kprintf(" ready ");
|
||||
else if (thread->stat == RT_THREAD_SUSPEND) rt_kprintf(" suspend");
|
||||
else if (thread->stat == RT_THREAD_INIT) rt_kprintf(" init ");
|
||||
|
||||
ptr = (rt_uint8_t*)thread->stack_addr;
|
||||
while (*ptr == '#')ptr ++;
|
||||
|
||||
rt_kprintf(" 0x%08x 0x%08x 0x%08x 0x%08x %03d\n",
|
||||
thread->stack_size + ((rt_uint32_t)thread->stack_addr - (rt_uint32_t)thread->sp),
|
||||
thread->stack_size,
|
||||
thread->stack_size - ((rt_uint32_t) ptr - (rt_uint32_t)thread->stack_addr),
|
||||
thread->remaining_tick,
|
||||
thread->error);
|
||||
}
|
||||
|
||||
/* list sub thread in module */
|
||||
tlist = &module->module_object[RT_Object_Class_Thread].object_list;
|
||||
if (!rt_list_isempty(tlist)) _list_thread(tlist);
|
||||
#ifdef RT_USING_SEMAPHORE
|
||||
/* list semaphored in module */
|
||||
tlist = &module->module_object[RT_Object_Class_Semaphore].object_list;
|
||||
if (!rt_list_isempty(tlist)) _list_sem(tlist);
|
||||
#endif
|
||||
#ifdef RT_USING_MUTEX
|
||||
/* list mutex in module */
|
||||
tlist = &module->module_object[RT_Object_Class_Mutex].object_list;
|
||||
if (!rt_list_isempty(tlist)) _list_mutex(tlist);
|
||||
#endif
|
||||
#ifdef RT_USING_EVENT
|
||||
/* list event in module */
|
||||
tlist = &module->module_object[RT_Object_Class_Event].object_list;
|
||||
if (!rt_list_isempty(tlist)) _list_event(tlist);
|
||||
#endif
|
||||
#ifdef RT_USING_MAILBOX
|
||||
/* list mailbox in module */
|
||||
tlist = &module->module_object[RT_Object_Class_MailBox].object_list;
|
||||
if (!rt_list_isempty(tlist)) _list_mailbox(tlist);
|
||||
#endif
|
||||
#ifdef RT_USING_MESSAGEQUEUE
|
||||
/* list message queue in module */
|
||||
tlist = &module->module_object[RT_Object_Class_MessageQueue].object_list;
|
||||
if (!rt_list_isempty(tlist)) _list_msgqueue(tlist);
|
||||
#endif
|
||||
#ifdef RT_USING_MEMHEAP
|
||||
/* list memory heap in module */
|
||||
tlist = &module->module_object[RT_Object_Class_MemHeap].object_list;
|
||||
if (!rt_list_isempty(tlist)) _list_memheap(tlist);
|
||||
#endif
|
||||
#ifdef RT_USING_MEMPOOL
|
||||
/* list memory pool in module */
|
||||
tlist = &module->module_object[RT_Object_Class_MemPool].object_list;
|
||||
if (!rt_list_isempty(tlist)) _list_mempool(tlist);
|
||||
#endif
|
||||
#ifdef RT_USING_DEVICE
|
||||
/* list device in module */
|
||||
tlist = &module->module_object[RT_Object_Class_Device].object_list;
|
||||
if (!rt_list_isempty(tlist)) _list_device(tlist);
|
||||
#endif
|
||||
/* list timer in module */
|
||||
tlist = &module->module_object[RT_Object_Class_Timer].object_list;
|
||||
if (!rt_list_isempty(tlist)) _list_timer(tlist);
|
||||
}
|
||||
|
||||
if (module->nsym > 0)
|
||||
{
|
||||
rt_kprintf("symbol address \n");
|
||||
rt_kprintf("-------- ----------\n");
|
||||
|
||||
/* list module export symbols */
|
||||
for (i=0; i<module->nsym; i++)
|
||||
{
|
||||
rt_kprintf("%s 0x%x\n",
|
||||
module->symtab[i].name, module->symtab[i].addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT(list_mod_detail, list module objects in system)
|
||||
MSH_CMD_EXPORT(list_mod_detail, list module objects in system)
|
||||
#endif
|
||||
|
||||
long list(void)
|
||||
{
|
||||
#ifndef FINSH_USING_MSH_ONLY
|
||||
struct finsh_syscall_item *syscall_item;
|
||||
struct finsh_sysvar_item *sysvar_item;
|
||||
#endif
|
||||
|
||||
rt_kprintf("--Function List:\n");
|
||||
{
|
||||
struct finsh_syscall *index;
|
||||
for (index = _syscall_table_begin;
|
||||
index < _syscall_table_end;
|
||||
FINSH_NEXT_SYSCALL(index))
|
||||
{
|
||||
/* skip the internal command */
|
||||
if (strncmp((char*)index->name, "__", 2) == 0) continue;
|
||||
|
||||
#ifdef FINSH_USING_DESCRIPTION
|
||||
rt_kprintf("%-16s -- %s\n", index->name, index->desc);
|
||||
#else
|
||||
rt_kprintf("%s\n", index->name);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef FINSH_USING_MSH_ONLY
|
||||
/* list syscall list */
|
||||
syscall_item = global_syscall_list;
|
||||
while (syscall_item != NULL)
|
||||
{
|
||||
rt_kprintf("[l] %s\n", syscall_item->syscall.name);
|
||||
syscall_item = syscall_item->next;
|
||||
}
|
||||
|
||||
rt_kprintf("--Variable List:\n");
|
||||
{
|
||||
struct finsh_sysvar *index;
|
||||
for (index = _sysvar_table_begin;
|
||||
index < _sysvar_table_end;
|
||||
FINSH_NEXT_SYSVAR(index))
|
||||
{
|
||||
#ifdef FINSH_USING_DESCRIPTION
|
||||
rt_kprintf("%-16s -- %s\n", index->name, index->desc);
|
||||
#else
|
||||
rt_kprintf("%s\n", index->name);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
sysvar_item = global_sysvar_list;
|
||||
while (sysvar_item != NULL)
|
||||
{
|
||||
rt_kprintf("[l] %s\n", sysvar_item->sysvar.name);
|
||||
sysvar_item = sysvar_item->next;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT(list, list all symbol in system)
|
||||
|
||||
#ifndef FINSH_USING_MSH_ONLY
|
||||
static int str_is_prefix(const char *prefix, const char *str)
|
||||
{
|
||||
while ((*prefix) && (*prefix == *str))
|
||||
{
|
||||
prefix ++;
|
||||
str ++;
|
||||
}
|
||||
|
||||
if (*prefix == 0)
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int str_common(const char *str1, const char *str2)
|
||||
{
|
||||
const char *str = str1;
|
||||
|
||||
while ((*str != 0) && (*str2 != 0) && (*str == *str2))
|
||||
{
|
||||
str ++;
|
||||
str2 ++;
|
||||
}
|
||||
|
||||
return (str - str1);
|
||||
}
|
||||
|
||||
void list_prefix(char *prefix)
|
||||
{
|
||||
struct finsh_syscall_item *syscall_item;
|
||||
struct finsh_sysvar_item *sysvar_item;
|
||||
rt_uint16_t func_cnt, var_cnt;
|
||||
int length, min_length;
|
||||
const char *name_ptr;
|
||||
|
||||
func_cnt = 0;
|
||||
var_cnt = 0;
|
||||
min_length = 0;
|
||||
name_ptr = RT_NULL;
|
||||
|
||||
/* checks in system function call */
|
||||
{
|
||||
struct finsh_syscall *index;
|
||||
for (index = _syscall_table_begin;
|
||||
index < _syscall_table_end;
|
||||
FINSH_NEXT_SYSCALL(index))
|
||||
{
|
||||
/* skip internal command */
|
||||
if (str_is_prefix("__", index->name) == 0) continue;
|
||||
|
||||
if (str_is_prefix(prefix, index->name) == 0)
|
||||
{
|
||||
if (func_cnt == 0)
|
||||
{
|
||||
rt_kprintf("--function:\n");
|
||||
|
||||
if (*prefix != 0)
|
||||
{
|
||||
/* set name_ptr */
|
||||
name_ptr = index->name;
|
||||
|
||||
/* set initial length */
|
||||
min_length = strlen(name_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
func_cnt ++;
|
||||
|
||||
if (*prefix != 0)
|
||||
{
|
||||
length = str_common(name_ptr, index->name);
|
||||
if (length < min_length)
|
||||
min_length = length;
|
||||
}
|
||||
|
||||
#ifdef FINSH_USING_DESCRIPTION
|
||||
rt_kprintf("%-16s -- %s\n", index->name, index->desc);
|
||||
#else
|
||||
rt_kprintf("%s\n", index->name);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* checks in dynamic system function call */
|
||||
syscall_item = global_syscall_list;
|
||||
while (syscall_item != NULL)
|
||||
{
|
||||
if (str_is_prefix(prefix, syscall_item->syscall.name) == 0)
|
||||
{
|
||||
if (func_cnt == 0)
|
||||
{
|
||||
rt_kprintf("--function:\n");
|
||||
if (*prefix != 0 && name_ptr == NULL)
|
||||
{
|
||||
/* set name_ptr */
|
||||
name_ptr = syscall_item->syscall.name;
|
||||
|
||||
/* set initial length */
|
||||
min_length = strlen(name_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
func_cnt ++;
|
||||
|
||||
if (*prefix != 0)
|
||||
{
|
||||
length = str_common(name_ptr, syscall_item->syscall.name);
|
||||
if (length < min_length)
|
||||
min_length = length;
|
||||
}
|
||||
|
||||
rt_kprintf("[l] %s\n", syscall_item->syscall.name);
|
||||
}
|
||||
syscall_item = syscall_item->next;
|
||||
}
|
||||
|
||||
/* checks in system variable */
|
||||
{
|
||||
struct finsh_sysvar* index;
|
||||
for (index = _sysvar_table_begin;
|
||||
index < _sysvar_table_end;
|
||||
FINSH_NEXT_SYSVAR(index))
|
||||
{
|
||||
if (str_is_prefix(prefix, index->name) == 0)
|
||||
{
|
||||
if (var_cnt == 0)
|
||||
{
|
||||
rt_kprintf("--variable:\n");
|
||||
|
||||
if (*prefix != 0 && name_ptr == NULL)
|
||||
{
|
||||
/* set name_ptr */
|
||||
name_ptr = index->name;
|
||||
|
||||
/* set initial length */
|
||||
min_length = strlen(name_ptr);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
var_cnt ++;
|
||||
|
||||
if (*prefix != 0)
|
||||
{
|
||||
length = str_common(name_ptr, index->name);
|
||||
if (length < min_length)
|
||||
min_length = length;
|
||||
}
|
||||
|
||||
#ifdef FINSH_USING_DESCRIPTION
|
||||
rt_kprintf("%-16s -- %s\n", index->name, index->desc);
|
||||
#else
|
||||
rt_kprintf("%s\n", index->name);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* checks in dynamic system variable */
|
||||
sysvar_item = global_sysvar_list;
|
||||
while (sysvar_item != NULL)
|
||||
{
|
||||
if (str_is_prefix(prefix, sysvar_item->sysvar.name) == 0)
|
||||
{
|
||||
if (var_cnt == 0)
|
||||
{
|
||||
rt_kprintf("--variable:\n");
|
||||
if (*prefix != 0 && name_ptr == NULL)
|
||||
{
|
||||
/* set name_ptr */
|
||||
name_ptr = sysvar_item->sysvar.name;
|
||||
|
||||
/* set initial length */
|
||||
min_length = strlen(name_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
var_cnt ++;
|
||||
|
||||
if (*prefix != 0)
|
||||
{
|
||||
length = str_common(name_ptr, sysvar_item->sysvar.name);
|
||||
if (length < min_length)
|
||||
min_length = length;
|
||||
}
|
||||
|
||||
rt_kprintf("[v] %s\n", sysvar_item->sysvar.name);
|
||||
}
|
||||
sysvar_item = sysvar_item->next;
|
||||
}
|
||||
|
||||
/* only one matched */
|
||||
if (name_ptr != NULL)
|
||||
{
|
||||
rt_strncpy(prefix, name_ptr, min_length);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(FINSH_USING_SYMTAB) && !defined(FINSH_USING_MSH_ONLY)
|
||||
static int dummy = 0;
|
||||
FINSH_VAR_EXPORT(dummy, finsh_type_int, dummy variable for finsh)
|
||||
#endif
|
||||
@@ -0,0 +1,479 @@
|
||||
/*
|
||||
* File : finsh.h
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2006 - 2010, 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
|
||||
* 2010-03-22 Bernard first version
|
||||
*/
|
||||
#ifndef __FINSH_H__
|
||||
#define __FINSH_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma section("FSymTab$f",read)
|
||||
#pragma section("VSymTab",read)
|
||||
#endif
|
||||
|
||||
/* -- the beginning of option -- */
|
||||
#define FINSH_NAME_MAX 16 /* max length of identifier */
|
||||
#define FINSH_NODE_MAX 16 /* max number of node */
|
||||
|
||||
#define FINSH_HEAP_MAX 128 /* max length of heap */
|
||||
#define FINSH_STRING_MAX 128 /* max length of string */
|
||||
#define FINSH_VARIABLE_MAX 8 /* max number of variable */
|
||||
|
||||
#define FINSH_STACK_MAX 64 /* max stack size */
|
||||
#define FINSH_TEXT_MAX 128 /* max text segment size */
|
||||
|
||||
#define HEAP_ALIGNMENT 4 /* heap alignment */
|
||||
|
||||
#define FINSH_GET16(x) (*(x)) | (*((x)+1) << 8)
|
||||
#define FINSH_GET32(x) (rt_uint32_t)(*(x)) | ((rt_uint32_t)*((x)+1) << 8) | \
|
||||
((rt_uint32_t)*((x)+2) << 16) | ((rt_uint32_t)*((x)+3) << 24)
|
||||
|
||||
#define FINSH_SET16(x, v) \
|
||||
do \
|
||||
{ \
|
||||
*(x) = (v) & 0x00ff; \
|
||||
(*((x)+1)) = (v) >> 8; \
|
||||
} while ( 0 )
|
||||
|
||||
#define FINSH_SET32(x, v) \
|
||||
do \
|
||||
{ \
|
||||
*(x) = (rt_uint32_t)(v) & 0x000000ff; \
|
||||
(*((x)+1)) = ((rt_uint32_t)(v) >> 8) & 0x000000ff; \
|
||||
(*((x)+2)) = ((rt_uint32_t)(v) >> 16) & 0x000000ff; \
|
||||
(*((x)+3)) = ((rt_uint32_t)(v) >> 24); \
|
||||
} while ( 0 )
|
||||
|
||||
/* -- the end of option -- */
|
||||
|
||||
#if defined(RT_USING_NEWLIB) || defined (RT_USING_MINILIBC)
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#else
|
||||
typedef unsigned char u_char;
|
||||
typedef unsigned short u_short;
|
||||
typedef unsigned long u_long;
|
||||
|
||||
#if !defined(__CC_ARM) && \
|
||||
!defined(__IAR_SYSTEMS_ICC__) && \
|
||||
!defined(__ADSPBLACKFIN__) && \
|
||||
!defined(_MSC_VER)
|
||||
|
||||
/* only for GNU GCC */
|
||||
|
||||
#if !(defined(__GNUC__) && defined(__x86_64__))
|
||||
typedef unsigned int size_t;
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL RT_NULL
|
||||
#endif
|
||||
|
||||
#else
|
||||
/* use libc of armcc */
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define FINSH_VERSION_MAJOR 1
|
||||
#define FINSH_VERSION_MINOR 0
|
||||
|
||||
/**
|
||||
* @addtogroup finsh
|
||||
*/
|
||||
/*@{*/
|
||||
#define FINSH_ERROR_OK 0 /**< No error */
|
||||
#define FINSH_ERROR_INVALID_TOKEN 1 /**< Invalid token */
|
||||
#define FINSH_ERROR_EXPECT_TYPE 2 /**< Expect a type */
|
||||
#define FINSH_ERROR_UNKNOWN_TYPE 3 /**< Unknown type */
|
||||
#define FINSH_ERROR_VARIABLE_EXIST 4 /**< Variable exist */
|
||||
#define FINSH_ERROR_EXPECT_OPERATOR 5 /**< Expect a operator */
|
||||
#define FINSH_ERROR_MEMORY_FULL 6 /**< Memory full */
|
||||
#define FINSH_ERROR_UNKNOWN_OP 7 /**< Unknown operator */
|
||||
#define FINSH_ERROR_UNKNOWN_NODE 8 /**< Unknown node */
|
||||
#define FINSH_ERROR_EXPECT_CHAR 9 /**< Expect a character */
|
||||
#define FINSH_ERROR_UNEXPECT_END 10 /**< Unexpect end */
|
||||
#define FINSH_ERROR_UNKNOWN_TOKEN 11 /**< Unknown token */
|
||||
#define FINSH_ERROR_NO_FLOAT 12 /**< Float not supported */
|
||||
#define FINSH_ERROR_UNKNOWN_SYMBOL 13 /**< Unknown symbol */
|
||||
#define FINSH_ERROR_NULL_NODE 14 /**< Null node */
|
||||
/*@}*/
|
||||
|
||||
typedef long (*syscall_func)();
|
||||
|
||||
/* system call table */
|
||||
struct finsh_syscall
|
||||
{
|
||||
const char* name; /* the name of system call */
|
||||
#if defined(FINSH_USING_DESCRIPTION) && defined(FINSH_USING_SYMTAB)
|
||||
const char* desc; /* description of system call */
|
||||
#endif
|
||||
syscall_func func; /* the function address of system call */
|
||||
};
|
||||
|
||||
/* system call item */
|
||||
struct finsh_syscall_item
|
||||
{
|
||||
struct finsh_syscall_item* next; /* next item */
|
||||
struct finsh_syscall syscall; /* syscall */
|
||||
};
|
||||
extern struct finsh_syscall *_syscall_table_begin, *_syscall_table_end;
|
||||
extern struct finsh_syscall_item *global_syscall_list;
|
||||
|
||||
/* find out system call, which should be implemented in user program */
|
||||
struct finsh_syscall* finsh_syscall_lookup(const char* name);
|
||||
|
||||
/* system variable table */
|
||||
struct finsh_sysvar
|
||||
{
|
||||
const char* name; /* the name of variable */
|
||||
#if defined(FINSH_USING_DESCRIPTION) && defined(FINSH_USING_SYMTAB)
|
||||
const char* desc; /* description of system variable */
|
||||
#endif
|
||||
u_char type; /* the type of variable */
|
||||
void* var ; /* the address of variable */
|
||||
};
|
||||
|
||||
#if defined(_MSC_VER) || (defined(__GNUC__) && defined(__x86_64__))
|
||||
struct finsh_syscall* finsh_syscall_next(struct finsh_syscall* call);
|
||||
struct finsh_sysvar* finsh_sysvar_next(struct finsh_sysvar* call);
|
||||
#define FINSH_NEXT_SYSCALL(index) index=finsh_syscall_next(index)
|
||||
#define FINSH_NEXT_SYSVAR(index) index=finsh_sysvar_next(index)
|
||||
#else
|
||||
#define FINSH_NEXT_SYSCALL(index) index++
|
||||
#define FINSH_NEXT_SYSVAR(index) index++
|
||||
#endif
|
||||
|
||||
/* system variable item */
|
||||
struct finsh_sysvar_item
|
||||
{
|
||||
struct finsh_sysvar_item *next; /* next item */
|
||||
struct finsh_sysvar sysvar; /* system variable */
|
||||
};
|
||||
extern struct finsh_sysvar *_sysvar_table_begin, *_sysvar_table_end;
|
||||
extern struct finsh_sysvar_item* global_sysvar_list;
|
||||
|
||||
/* find out system variable, which should be implemented in user program */
|
||||
struct finsh_sysvar* finsh_sysvar_lookup(const char* name);
|
||||
|
||||
#ifdef FINSH_USING_SYMTAB
|
||||
|
||||
#ifdef __TI_COMPILER_VERSION__
|
||||
#define __TI_FINSH_EXPORT_FUNCTION(f) PRAGMA(DATA_SECTION(f,"FSymTab"))
|
||||
#define __TI_FINSH_EXPORT_VAR(v) PRAGMA(DATA_SECTION(v,"VSymTab"))
|
||||
#endif
|
||||
|
||||
#ifdef FINSH_USING_DESCRIPTION
|
||||
#ifdef _MSC_VER
|
||||
#define FINSH_FUNCTION_EXPORT_CMD(name, cmd, desc) \
|
||||
const char __fsym_##cmd##_name[] = #cmd; \
|
||||
const char __fsym_##cmd##_desc[] = #desc; \
|
||||
__declspec(allocate("FSymTab$f")) \
|
||||
const struct finsh_syscall __fsym_##cmd = \
|
||||
{ \
|
||||
__fsym_##cmd##_name, \
|
||||
__fsym_##cmd##_desc, \
|
||||
(syscall_func)&name \
|
||||
};
|
||||
#pragma comment(linker, "/merge:FSymTab=mytext")
|
||||
|
||||
#define FINSH_VAR_EXPORT(name, type, desc) \
|
||||
const char __vsym_##name##_name[] = #name; \
|
||||
const char __vsym_##name##_desc[] = #desc; \
|
||||
__declspec(allocate("VSymTab")) \
|
||||
const struct finsh_sysvar __vsym_##name = \
|
||||
{ \
|
||||
__vsym_##name##_name, \
|
||||
__vsym_##name##_desc, \
|
||||
type, \
|
||||
(void*)&name \
|
||||
};
|
||||
|
||||
#elif defined(__TI_COMPILER_VERSION__)
|
||||
#define FINSH_FUNCTION_EXPORT_CMD(name, cmd, desc) \
|
||||
__TI_FINSH_EXPORT_FUNCTION(__fsym_##cmd); \
|
||||
const char __fsym_##cmd##_name[] = #cmd; \
|
||||
const char __fsym_##cmd##_desc[] = #desc; \
|
||||
const struct finsh_syscall __fsym_##cmd = \
|
||||
{ \
|
||||
__fsym_##cmd##_name, \
|
||||
__fsym_##cmd##_desc, \
|
||||
(syscall_func)&name \
|
||||
};
|
||||
|
||||
#define FINSH_VAR_EXPORT(name, type, desc) \
|
||||
__TI_FINSH_EXPORT_VAR(__vsym_##name); \
|
||||
const char __vsym_##name##_name[] = #name; \
|
||||
const char __vsym_##name##_desc[] = #desc; \
|
||||
const struct finsh_sysvar __vsym_##name = \
|
||||
{ \
|
||||
__vsym_##name##_name, \
|
||||
__vsym_##name##_desc, \
|
||||
type, \
|
||||
(void*)&name \
|
||||
};
|
||||
|
||||
#else
|
||||
#define FINSH_FUNCTION_EXPORT_CMD(name, cmd, desc) \
|
||||
const char __fsym_##cmd##_name[] = #cmd; \
|
||||
const char __fsym_##cmd##_desc[] = #desc; \
|
||||
const struct finsh_syscall __fsym_##cmd SECTION("FSymTab")= \
|
||||
{ \
|
||||
__fsym_##cmd##_name, \
|
||||
__fsym_##cmd##_desc, \
|
||||
(syscall_func)&name \
|
||||
};
|
||||
|
||||
#define FINSH_VAR_EXPORT(name, type, desc) \
|
||||
const char __vsym_##name##_name[] = #name; \
|
||||
const char __vsym_##name##_desc[] = #desc; \
|
||||
const struct finsh_sysvar __vsym_##name SECTION("VSymTab")= \
|
||||
{ \
|
||||
__vsym_##name##_name, \
|
||||
__vsym_##name##_desc, \
|
||||
type, \
|
||||
(void*)&name \
|
||||
};
|
||||
|
||||
#endif
|
||||
#else
|
||||
#ifdef _MSC_VER
|
||||
#define FINSH_FUNCTION_EXPORT_CMD(name, cmd, desc) \
|
||||
const char __fsym_##cmd##_name[] = #cmd; \
|
||||
__declspec(allocate("FSymTab$f")) \
|
||||
const struct finsh_syscall __fsym_##cmd = \
|
||||
{ \
|
||||
__fsym_##cmd##_name, \
|
||||
(syscall_func)&name \
|
||||
};
|
||||
#pragma comment(linker, "/merge:FSymTab=mytext")
|
||||
|
||||
#define FINSH_VAR_EXPORT(name, type, desc) \
|
||||
const char __vsym_##name##_name[] = #name; \
|
||||
__declspec(allocate("VSymTab")) const struct finsh_sysvar __vsym_##name = \
|
||||
{ \
|
||||
__vsym_##name##_name, \
|
||||
type, \
|
||||
(void*)&name \
|
||||
};
|
||||
|
||||
#elif defined(__TI_COMPILER_VERSION__)
|
||||
#define FINSH_FUNCTION_EXPORT_CMD(name, cmd, desc) \
|
||||
__TI_FINSH_EXPORT_FUNCTION(__fsym_##cmd); \
|
||||
const char __fsym_##cmd##_name[] = #cmd; \
|
||||
const struct finsh_syscall __fsym_##cmd = \
|
||||
{ \
|
||||
__fsym_##cmd##_name, \
|
||||
(syscall_func)&name \
|
||||
};
|
||||
|
||||
#define FINSH_VAR_EXPORT(name, type, desc) \
|
||||
__TI_FINSH_EXPORT_VAR(__vsym_##name); \
|
||||
const char __vsym_##name##_name[] = #name; \
|
||||
const struct finsh_sysvar __vsym_##name = \
|
||||
{ \
|
||||
__vsym_##name##_name, \
|
||||
type, \
|
||||
(void*)&name \
|
||||
};
|
||||
|
||||
#else
|
||||
#define FINSH_FUNCTION_EXPORT_CMD(name, cmd, desc) \
|
||||
const char __fsym_##cmd##_name[] = #cmd; \
|
||||
const struct finsh_syscall __fsym_##cmd SECTION("FSymTab")= \
|
||||
{ \
|
||||
__fsym_##cmd##_name, \
|
||||
(syscall_func)&name \
|
||||
};
|
||||
|
||||
#define FINSH_VAR_EXPORT(name, type, desc) \
|
||||
const char __vsym_##name##_name[] = #name; \
|
||||
const struct finsh_sysvar __vsym_##name SECTION("VSymTab")= \
|
||||
{ \
|
||||
__vsym_##name##_name, \
|
||||
type, \
|
||||
(void*)&name \
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif /* end of FINSH_USING_DESCRIPTION */
|
||||
#endif /* end of FINSH_USING_SYMTAB */
|
||||
|
||||
/**
|
||||
* @ingroup finsh
|
||||
*
|
||||
* This macro exports a system function to finsh shell.
|
||||
*
|
||||
* @param name the name of function.
|
||||
* @param desc the description of function, which will show in help.
|
||||
*/
|
||||
#define FINSH_FUNCTION_EXPORT(name, desc) \
|
||||
FINSH_FUNCTION_EXPORT_CMD(name, name, desc)
|
||||
|
||||
/**
|
||||
* @ingroup finsh
|
||||
*
|
||||
* This macro exports a system function with an alias name to finsh shell.
|
||||
*
|
||||
* @param name the name of function.
|
||||
* @param alias the alias name of function.
|
||||
* @param desc the description of function, which will show in help.
|
||||
*/
|
||||
#define FINSH_FUNCTION_EXPORT_ALIAS(name, alias, desc) \
|
||||
FINSH_FUNCTION_EXPORT_CMD(name, alias, desc)
|
||||
|
||||
/**
|
||||
* @ingroup finsh
|
||||
*
|
||||
* This macro exports a command to module shell.
|
||||
*
|
||||
* @param command the name of command.
|
||||
* @param desc the description of command, which will show in help.
|
||||
*/
|
||||
#ifdef FINSH_USING_MSH
|
||||
#define MSH_CMD_EXPORT(command, desc) \
|
||||
FINSH_FUNCTION_EXPORT_CMD(command, __cmd_##command, desc)
|
||||
#else
|
||||
#define MSH_CMD_EXPORT(command, desc)
|
||||
#endif
|
||||
|
||||
struct finsh_token
|
||||
{
|
||||
char eof;
|
||||
char replay;
|
||||
|
||||
int position;
|
||||
u_char current_token;
|
||||
|
||||
union {
|
||||
char char_value;
|
||||
int int_value;
|
||||
long long_value;
|
||||
} value;
|
||||
u_char string[128];
|
||||
|
||||
u_char* line;
|
||||
};
|
||||
|
||||
#define FINSH_IDTYPE_VAR 0x01
|
||||
#define FINSH_IDTYPE_SYSVAR 0x02
|
||||
#define FINSH_IDTYPE_SYSCALL 0x04
|
||||
#define FINSH_IDTYPE_ADDRESS 0x08
|
||||
struct finsh_node
|
||||
{
|
||||
u_char node_type; /* node node_type */
|
||||
u_char data_type; /* node data node_type */
|
||||
u_char idtype; /* id node information */
|
||||
|
||||
union { /* value node */
|
||||
char char_value;
|
||||
short short_value;
|
||||
int int_value;
|
||||
long long_value;
|
||||
void* ptr;
|
||||
} value;
|
||||
union
|
||||
{
|
||||
/* point to variable identifier or function identifier */
|
||||
struct finsh_var *var;
|
||||
struct finsh_sysvar *sysvar;
|
||||
struct finsh_syscall*syscall;
|
||||
}id;
|
||||
|
||||
/* sibling and child node */
|
||||
struct finsh_node *sibling, *child;
|
||||
};
|
||||
|
||||
struct finsh_parser
|
||||
{
|
||||
u_char* parser_string;
|
||||
|
||||
struct finsh_token token;
|
||||
struct finsh_node* root;
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup finsh
|
||||
*
|
||||
* The basic data type in finsh shell
|
||||
*/
|
||||
enum finsh_type {
|
||||
finsh_type_unknown = 0, /**< unknown data type */
|
||||
finsh_type_void, /**< void */
|
||||
finsh_type_voidp, /**< void pointer */
|
||||
finsh_type_char, /**< char */
|
||||
finsh_type_uchar, /**< unsigned char */
|
||||
finsh_type_charp, /**< char pointer */
|
||||
finsh_type_short, /**< short */
|
||||
finsh_type_ushort, /**< unsigned short */
|
||||
finsh_type_shortp, /**< short pointer */
|
||||
finsh_type_int, /**< int */
|
||||
finsh_type_uint, /**< unsigned int */
|
||||
finsh_type_intp, /**< int pointer */
|
||||
finsh_type_long, /**< long */
|
||||
finsh_type_ulong, /**< unsigned long */
|
||||
finsh_type_longp /**< long pointer */
|
||||
};
|
||||
|
||||
/* init finsh environment */
|
||||
int finsh_init(struct finsh_parser* parser);
|
||||
/* flush finsh node, text segment */
|
||||
int finsh_flush(struct finsh_parser* parser);
|
||||
/* reset all of finsh */
|
||||
int finsh_reset(struct finsh_parser* parser);
|
||||
#ifdef RT_USING_DEVICE
|
||||
void finsh_set_device(const char* device_name);
|
||||
#endif
|
||||
|
||||
/* run finsh parser to generate abstract synatx tree */
|
||||
void finsh_parser_run (struct finsh_parser* parser, const unsigned char* string);
|
||||
/* run compiler to compile abstract syntax tree */
|
||||
int finsh_compiler_run(struct finsh_node* node);
|
||||
/* run finsh virtual machine */
|
||||
void finsh_vm_run(void);
|
||||
|
||||
/* get variable value */
|
||||
struct finsh_var* finsh_var_lookup(const char* name);
|
||||
/* get bottom value of stack */
|
||||
long finsh_stack_bottom(void);
|
||||
|
||||
/* get error number of finsh */
|
||||
u_char finsh_errno(void);
|
||||
/* get error string */
|
||||
const char* finsh_error_string(u_char type);
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
/**
|
||||
* @ingroup finsh
|
||||
*
|
||||
* This function appends a system call to finsh runtime environment
|
||||
* @param name the name of system call
|
||||
* @param func the function pointer of system call
|
||||
*/
|
||||
void finsh_syscall_append(const char* name, syscall_func func);
|
||||
|
||||
/**
|
||||
* @ingroup finsh
|
||||
*
|
||||
* This function appends a system variable to finsh runtime environment
|
||||
* @param name the name of system variable
|
||||
* @param type the data type of system variable
|
||||
* @param addr the address of system variable
|
||||
*/
|
||||
void finsh_sysvar_append(const char* name, u_char type, void* addr);
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,937 @@
|
||||
/*
|
||||
* RT-Thread finsh shell compiler
|
||||
*
|
||||
* COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team
|
||||
*
|
||||
* This file is part of RT-Thread (http://www.rt-thread.org)
|
||||
* Maintainer: bernard.xiong <bernard.xiong at gmail.com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2010-03-22 Bernard first version
|
||||
*/
|
||||
#include <finsh.h>
|
||||
|
||||
#include "finsh_node.h"
|
||||
#include "finsh_error.h"
|
||||
#include "finsh_var.h"
|
||||
#include "finsh_ops.h"
|
||||
|
||||
union finsh_value* finsh_compile_sp; /* stack pointer */
|
||||
u_char* finsh_compile_pc; /* PC */
|
||||
|
||||
#define finsh_code_byte(x) do { *finsh_compile_pc = (x); finsh_compile_pc ++; } while(0)
|
||||
#define finsh_code_word(x) do { FINSH_SET16(finsh_compile_pc, x); finsh_compile_pc +=2; } while(0)
|
||||
#define finsh_code_dword(x) do { FINSH_SET32(finsh_compile_pc, x); finsh_compile_pc +=4; } while(0)
|
||||
|
||||
static int finsh_compile(struct finsh_node* node)
|
||||
{
|
||||
if (node != NULL)
|
||||
{
|
||||
/* compile child node */
|
||||
if (finsh_node_child(node) != NULL)
|
||||
finsh_compile(finsh_node_child(node));
|
||||
|
||||
/* compile current node */
|
||||
switch (node->node_type)
|
||||
{
|
||||
case FINSH_NODE_ID:
|
||||
{
|
||||
/* identifier::syscall */
|
||||
if (node->idtype & FINSH_IDTYPE_SYSCALL)
|
||||
{
|
||||
/* load address */
|
||||
finsh_code_byte(FINSH_OP_LD_DWORD);
|
||||
finsh_code_dword((long)node->id.syscall->func);
|
||||
}
|
||||
/* identifier::sysvar */
|
||||
else if (node->idtype & FINSH_IDTYPE_SYSVAR)
|
||||
{
|
||||
struct finsh_sysvar* sysvar;
|
||||
|
||||
sysvar = node->id.sysvar;
|
||||
if (sysvar != NULL)
|
||||
{
|
||||
switch (sysvar->type)
|
||||
{
|
||||
case finsh_type_char:
|
||||
case finsh_type_uchar:
|
||||
if (node->idtype & FINSH_IDTYPE_ADDRESS)
|
||||
{
|
||||
/* load address */
|
||||
finsh_code_byte(FINSH_OP_LD_DWORD);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* load value */
|
||||
finsh_code_byte(FINSH_OP_LD_VALUE_BYTE);
|
||||
}
|
||||
|
||||
finsh_code_dword((long)(sysvar->var));
|
||||
break;
|
||||
|
||||
case finsh_type_short:
|
||||
case finsh_type_ushort:
|
||||
if (node->idtype & FINSH_IDTYPE_ADDRESS)
|
||||
{
|
||||
/* load address */
|
||||
finsh_code_byte(FINSH_OP_LD_DWORD);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* load value */
|
||||
finsh_code_byte(FINSH_OP_LD_VALUE_WORD);
|
||||
}
|
||||
|
||||
finsh_code_dword((long)(sysvar->var));
|
||||
break;
|
||||
|
||||
case finsh_type_int:
|
||||
case finsh_type_uint:
|
||||
case finsh_type_long:
|
||||
case finsh_type_ulong:
|
||||
case finsh_type_charp:
|
||||
case finsh_type_shortp:
|
||||
case finsh_type_intp:
|
||||
case finsh_type_longp:
|
||||
if (node->idtype & FINSH_IDTYPE_ADDRESS)
|
||||
{
|
||||
/* load address */
|
||||
finsh_code_byte(FINSH_OP_LD_DWORD);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* load value */
|
||||
finsh_code_byte(FINSH_OP_LD_VALUE_DWORD);
|
||||
}
|
||||
|
||||
finsh_code_dword((long)(sysvar->var));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* identifier::var */
|
||||
else
|
||||
{
|
||||
struct finsh_var* var;
|
||||
|
||||
var = node->id.var;
|
||||
if (var != NULL)
|
||||
{
|
||||
switch (var->type)
|
||||
{
|
||||
case finsh_type_char:
|
||||
case finsh_type_uchar:
|
||||
if (node->idtype & FINSH_IDTYPE_ADDRESS)
|
||||
{
|
||||
/* load address */
|
||||
finsh_code_byte(FINSH_OP_LD_DWORD);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* load value */
|
||||
finsh_code_byte(FINSH_OP_LD_VALUE_BYTE);
|
||||
}
|
||||
|
||||
finsh_code_dword((long)&(var->value.char_value));
|
||||
break;
|
||||
|
||||
case finsh_type_short:
|
||||
case finsh_type_ushort:
|
||||
if (node->idtype & FINSH_IDTYPE_ADDRESS)
|
||||
{
|
||||
/* load address */
|
||||
finsh_code_byte(FINSH_OP_LD_DWORD);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* load value */
|
||||
finsh_code_byte(FINSH_OP_LD_VALUE_WORD);
|
||||
}
|
||||
|
||||
finsh_code_dword((long)&(var->value.short_value));
|
||||
break;
|
||||
|
||||
case finsh_type_int:
|
||||
case finsh_type_uint:
|
||||
case finsh_type_long:
|
||||
case finsh_type_ulong:
|
||||
case finsh_type_charp:
|
||||
case finsh_type_shortp:
|
||||
case finsh_type_intp:
|
||||
case finsh_type_longp:
|
||||
if (node->idtype & FINSH_IDTYPE_ADDRESS)
|
||||
{
|
||||
/* load address */
|
||||
finsh_code_byte(FINSH_OP_LD_DWORD);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* load value */
|
||||
finsh_code_byte(FINSH_OP_LD_VALUE_DWORD);
|
||||
}
|
||||
|
||||
finsh_code_dword((long)&(var->value.long_value));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/* load const */
|
||||
case FINSH_NODE_VALUE_CHAR:
|
||||
finsh_code_byte(FINSH_OP_LD_BYTE);
|
||||
finsh_code_byte(node->value.char_value);
|
||||
break;
|
||||
|
||||
case FINSH_NODE_VALUE_INT:
|
||||
case FINSH_NODE_VALUE_LONG:
|
||||
finsh_code_byte(FINSH_OP_LD_DWORD);
|
||||
finsh_code_dword(node->value.long_value);
|
||||
break;
|
||||
|
||||
case FINSH_NODE_VALUE_NULL:
|
||||
case FINSH_NODE_VALUE_STRING:
|
||||
finsh_code_byte(FINSH_OP_LD_DWORD);
|
||||
finsh_code_dword((u_long)node->value.ptr);
|
||||
break;
|
||||
|
||||
/* arithmetic operation */
|
||||
case FINSH_NODE_SYS_ADD:
|
||||
if (node->data_type == FINSH_DATA_TYPE_BYTE) finsh_code_byte(FINSH_OP_ADD_BYTE);
|
||||
else if (node->data_type == FINSH_DATA_TYPE_WORD) finsh_code_byte(FINSH_OP_ADD_WORD);
|
||||
else if (node->data_type == FINSH_DATA_TYPE_DWORD) finsh_code_byte(FINSH_OP_ADD_DWORD);
|
||||
break;
|
||||
|
||||
case FINSH_NODE_SYS_SUB:
|
||||
if (node->data_type == FINSH_DATA_TYPE_BYTE) finsh_code_byte(FINSH_OP_SUB_BYTE);
|
||||
else if (node->data_type == FINSH_DATA_TYPE_WORD) finsh_code_byte(FINSH_OP_SUB_WORD);
|
||||
else if (node->data_type == FINSH_DATA_TYPE_DWORD) finsh_code_byte(FINSH_OP_SUB_DWORD);
|
||||
break;
|
||||
|
||||
case FINSH_NODE_SYS_MUL:
|
||||
if (node->data_type == FINSH_DATA_TYPE_BYTE) finsh_code_byte(FINSH_OP_MUL_BYTE);
|
||||
else if (node->data_type == FINSH_DATA_TYPE_WORD) finsh_code_byte(FINSH_OP_MUL_WORD);
|
||||
else if (node->data_type == FINSH_DATA_TYPE_DWORD) finsh_code_byte(FINSH_OP_MUL_DWORD);
|
||||
break;
|
||||
|
||||
case FINSH_NODE_SYS_DIV:
|
||||
if (node->data_type == FINSH_DATA_TYPE_BYTE) finsh_code_byte(FINSH_OP_DIV_BYTE);
|
||||
else if (node->data_type == FINSH_DATA_TYPE_WORD) finsh_code_byte(FINSH_OP_DIV_WORD);
|
||||
else if (node->data_type == FINSH_DATA_TYPE_DWORD) finsh_code_byte(FINSH_OP_DIV_DWORD);
|
||||
break;
|
||||
|
||||
case FINSH_NODE_SYS_MOD:
|
||||
if (node->data_type == FINSH_DATA_TYPE_BYTE) finsh_code_byte(FINSH_OP_MOD_BYTE);
|
||||
else if (node->data_type == FINSH_DATA_TYPE_WORD) finsh_code_byte(FINSH_OP_MOD_WORD);
|
||||
else if (node->data_type == FINSH_DATA_TYPE_DWORD) finsh_code_byte(FINSH_OP_MOD_DWORD);
|
||||
break;
|
||||
|
||||
/* bit operation */
|
||||
case FINSH_NODE_SYS_AND:
|
||||
if (node->data_type == FINSH_DATA_TYPE_BYTE) finsh_code_byte(FINSH_OP_AND_BYTE);
|
||||
else if (node->data_type == FINSH_DATA_TYPE_WORD) finsh_code_byte(FINSH_OP_AND_WORD);
|
||||
else if (node->data_type == FINSH_DATA_TYPE_DWORD) finsh_code_byte(FINSH_OP_AND_DWORD);
|
||||
break;
|
||||
|
||||
case FINSH_NODE_SYS_OR:
|
||||
if (node->data_type == FINSH_DATA_TYPE_BYTE) finsh_code_byte(FINSH_OP_OR_BYTE);
|
||||
else if (node->data_type == FINSH_DATA_TYPE_WORD) finsh_code_byte(FINSH_OP_OR_WORD);
|
||||
else if (node->data_type == FINSH_DATA_TYPE_DWORD) finsh_code_byte(FINSH_OP_OR_DWORD);
|
||||
break;
|
||||
|
||||
case FINSH_NODE_SYS_XOR:
|
||||
if (node->data_type == FINSH_DATA_TYPE_BYTE) finsh_code_byte(FINSH_OP_XOR_BYTE);
|
||||
else if (node->data_type == FINSH_DATA_TYPE_WORD) finsh_code_byte(FINSH_OP_XOR_WORD);
|
||||
else if (node->data_type == FINSH_DATA_TYPE_DWORD) finsh_code_byte(FINSH_OP_XOR_DWORD);
|
||||
break;
|
||||
|
||||
case FINSH_NODE_SYS_BITWISE:
|
||||
if (node->data_type == FINSH_DATA_TYPE_BYTE) finsh_code_byte(FINSH_OP_BITWISE_BYTE);
|
||||
else if (node->data_type == FINSH_DATA_TYPE_WORD) finsh_code_byte(FINSH_OP_BITWISE_WORD);
|
||||
else if (node->data_type == FINSH_DATA_TYPE_DWORD) finsh_code_byte(FINSH_OP_BITWISE_DWORD);
|
||||
break;
|
||||
|
||||
case FINSH_NODE_SYS_SHL:
|
||||
if (node->data_type == FINSH_DATA_TYPE_BYTE) finsh_code_byte(FINSH_OP_SHL_BYTE);
|
||||
else if (node->data_type == FINSH_DATA_TYPE_WORD) finsh_code_byte(FINSH_OP_SHL_WORD);
|
||||
else if (node->data_type == FINSH_DATA_TYPE_DWORD) finsh_code_byte(FINSH_OP_SHL_DWORD);
|
||||
break;
|
||||
|
||||
case FINSH_NODE_SYS_SHR:
|
||||
if (node->data_type == FINSH_DATA_TYPE_BYTE) finsh_code_byte(FINSH_OP_SHR_BYTE);
|
||||
else if (node->data_type == FINSH_DATA_TYPE_WORD) finsh_code_byte(FINSH_OP_SHR_WORD);
|
||||
else if (node->data_type == FINSH_DATA_TYPE_DWORD) finsh_code_byte(FINSH_OP_SHR_DWORD);
|
||||
break;
|
||||
|
||||
/* syscall */
|
||||
case FINSH_NODE_SYS_FUNC:
|
||||
{
|
||||
int parameters;
|
||||
struct finsh_node* sibling;
|
||||
|
||||
parameters = 0;
|
||||
if (finsh_node_child(node) != NULL)
|
||||
{
|
||||
sibling = finsh_node_sibling(finsh_node_child(node));
|
||||
while (sibling != NULL)
|
||||
{
|
||||
parameters ++;
|
||||
sibling = finsh_node_sibling(sibling);
|
||||
}
|
||||
|
||||
/* load address of function */
|
||||
// finsh_code_dword((long)&(node->var->value.ptr));
|
||||
|
||||
/* syscall parameters */
|
||||
finsh_code_byte(FINSH_OP_SYSCALL);
|
||||
finsh_code_byte(parameters);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/* assign expression */
|
||||
case FINSH_NODE_SYS_ASSIGN:
|
||||
if (finsh_node_child(node) && finsh_node_child(node)->node_type == FINSH_NODE_ID)
|
||||
{
|
||||
switch (finsh_node_child(node)->data_type)
|
||||
{
|
||||
case FINSH_DATA_TYPE_BYTE:
|
||||
finsh_code_byte(FINSH_OP_ST_BYTE);
|
||||
|
||||
/* load value again */
|
||||
finsh_code_byte(FINSH_OP_LD_VALUE_BYTE_STACK);
|
||||
break;
|
||||
|
||||
case FINSH_DATA_TYPE_WORD:
|
||||
finsh_code_byte(FINSH_OP_ST_WORD);
|
||||
|
||||
/* load value again */
|
||||
finsh_code_byte(FINSH_OP_LD_VALUE_WORD_STACK);
|
||||
break;
|
||||
|
||||
case FINSH_DATA_TYPE_DWORD:
|
||||
finsh_code_byte(FINSH_OP_ST_DWORD);
|
||||
|
||||
/* load value again */
|
||||
finsh_code_byte(FINSH_OP_LD_VALUE_DWORD_STACK);
|
||||
break;
|
||||
|
||||
default:
|
||||
finsh_error_set(FINSH_ERROR_UNKNOWN_TYPE);
|
||||
}
|
||||
}
|
||||
else if (finsh_node_child(node)->node_type == FINSH_NODE_SYS_GETVALUE)
|
||||
{
|
||||
switch ((finsh_node_child(node)->data_type) & 0x0F)
|
||||
{
|
||||
case FINSH_DATA_TYPE_BYTE:
|
||||
finsh_code_byte(FINSH_OP_ST_BYTE);
|
||||
|
||||
/* load value again */
|
||||
finsh_code_byte(FINSH_OP_LD_VALUE_BYTE_STACK);
|
||||
break;
|
||||
|
||||
case FINSH_DATA_TYPE_WORD:
|
||||
finsh_code_byte(FINSH_OP_ST_WORD);
|
||||
|
||||
/* load value again */
|
||||
finsh_code_byte(FINSH_OP_LD_VALUE_WORD_STACK);
|
||||
break;
|
||||
|
||||
case FINSH_DATA_TYPE_DWORD:
|
||||
finsh_code_byte(FINSH_OP_ST_DWORD);
|
||||
|
||||
/* load value again */
|
||||
finsh_code_byte(FINSH_OP_LD_VALUE_DWORD_STACK);
|
||||
break;
|
||||
|
||||
default:
|
||||
finsh_error_set(FINSH_ERROR_UNKNOWN_TYPE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/* pre-increase */
|
||||
case FINSH_NODE_SYS_PREINC:
|
||||
if (finsh_node_child(node) && finsh_node_child(node)->node_type == FINSH_NODE_ID)
|
||||
{
|
||||
struct finsh_var* var;
|
||||
var = finsh_node_child(node)->id.var;
|
||||
|
||||
/* ld_dword &id */
|
||||
// finsh_code_byte(FINSH_OP_LD_DWORD);
|
||||
|
||||
switch (node->data_type)
|
||||
{
|
||||
case FINSH_DATA_TYPE_BYTE:
|
||||
/* address */
|
||||
// finsh_code_dword((long)&(var->value.char_value));
|
||||
|
||||
/* ld_value_byte &id */
|
||||
finsh_code_byte(FINSH_OP_LD_VALUE_BYTE);
|
||||
finsh_code_dword((long)&(var->value.char_value));
|
||||
|
||||
/* ld_byte 1 */
|
||||
finsh_code_byte(FINSH_OP_LD_BYTE);
|
||||
finsh_code_byte(1);
|
||||
|
||||
/* add_byte */
|
||||
finsh_code_byte(FINSH_OP_ADD_BYTE);
|
||||
/* st_byte */
|
||||
finsh_code_byte(FINSH_OP_ST_BYTE);
|
||||
|
||||
/* load value again */
|
||||
finsh_code_byte(FINSH_OP_LD_VALUE_DWORD_STACK);
|
||||
|
||||
break;
|
||||
|
||||
case FINSH_DATA_TYPE_WORD:
|
||||
/* address */
|
||||
// finsh_code_dword((long)&(var->value.short_value));
|
||||
|
||||
/* ld_value_word &id */
|
||||
finsh_code_byte(FINSH_OP_LD_VALUE_WORD);
|
||||
finsh_code_dword((long)&(var->value.short_value));
|
||||
|
||||
/* ld_word 1 */
|
||||
finsh_code_byte(FINSH_OP_LD_WORD);
|
||||
finsh_code_word(1);
|
||||
|
||||
/* add_word */
|
||||
finsh_code_byte(FINSH_OP_ADD_WORD);
|
||||
/* st_word */
|
||||
finsh_code_byte(FINSH_OP_ST_WORD);
|
||||
|
||||
/* load value again */
|
||||
finsh_code_byte(FINSH_OP_LD_VALUE_DWORD_STACK);
|
||||
|
||||
break;
|
||||
|
||||
case FINSH_DATA_TYPE_DWORD:
|
||||
/* address */
|
||||
// finsh_code_dword((long)&(var->value.long_value));
|
||||
|
||||
/* ld_dword &id */
|
||||
finsh_code_byte(FINSH_OP_LD_VALUE_DWORD);
|
||||
finsh_code_dword((long)&(var->value.long_value));
|
||||
|
||||
/* ld_dword 1 */
|
||||
finsh_code_byte(FINSH_OP_LD_DWORD);
|
||||
finsh_code_dword(1);
|
||||
|
||||
/* add_dword */
|
||||
finsh_code_byte(FINSH_OP_ADD_DWORD);
|
||||
/* st_dword */
|
||||
finsh_code_byte(FINSH_OP_ST_DWORD);
|
||||
|
||||
/* load value again */
|
||||
finsh_code_byte(FINSH_OP_LD_VALUE_DWORD_STACK);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/* pre-decrease */
|
||||
case FINSH_NODE_SYS_PREDEC:
|
||||
if (finsh_node_child(node) && finsh_node_child(node)->node_type == FINSH_NODE_ID)
|
||||
{
|
||||
struct finsh_var* var;
|
||||
var = finsh_node_child(node)->id.var;
|
||||
|
||||
/* ld_dword &id */
|
||||
// finsh_code_byte(FINSH_OP_LD_DWORD);
|
||||
|
||||
switch (node->data_type)
|
||||
{
|
||||
case FINSH_DATA_TYPE_BYTE:
|
||||
/* address */
|
||||
// finsh_code_dword((long)&(var->value.char_value));
|
||||
|
||||
/* ld_value_byte &id */
|
||||
finsh_code_byte(FINSH_OP_LD_VALUE_BYTE);
|
||||
finsh_code_dword((long)&(var->value.char_value));
|
||||
|
||||
/* ld_byte 1 */
|
||||
finsh_code_byte(FINSH_OP_LD_BYTE);
|
||||
finsh_code_byte(1);
|
||||
|
||||
/* add_byte */
|
||||
finsh_code_byte(FINSH_OP_SUB_BYTE);
|
||||
/* st_byte */
|
||||
finsh_code_byte(FINSH_OP_ST_BYTE);
|
||||
|
||||
/* load value again */
|
||||
finsh_code_byte(FINSH_OP_LD_VALUE_DWORD_STACK);
|
||||
|
||||
break;
|
||||
|
||||
case FINSH_DATA_TYPE_WORD:
|
||||
/* address */
|
||||
// finsh_code_dword((long)&(var->value.short_value));
|
||||
|
||||
/* ld_value_word &id */
|
||||
finsh_code_byte(FINSH_OP_LD_VALUE_WORD);
|
||||
finsh_code_dword((long)&(var->value.short_value));
|
||||
|
||||
/* ld_word 1 */
|
||||
finsh_code_byte(FINSH_OP_LD_WORD);
|
||||
finsh_code_word(1);
|
||||
|
||||
/* add_word */
|
||||
finsh_code_byte(FINSH_OP_SUB_WORD);
|
||||
/* st_word */
|
||||
finsh_code_byte(FINSH_OP_ST_WORD);
|
||||
|
||||
/* load value again */
|
||||
finsh_code_byte(FINSH_OP_LD_VALUE_DWORD_STACK);
|
||||
|
||||
break;
|
||||
|
||||
case FINSH_DATA_TYPE_DWORD:
|
||||
/* address */
|
||||
// finsh_code_dword((long)&(var->value.long_value));
|
||||
|
||||
/* ld_dword &id */
|
||||
finsh_code_byte(FINSH_OP_LD_VALUE_DWORD);
|
||||
finsh_code_dword((long)&(var->value.long_value));
|
||||
|
||||
/* ld_dword 1 */
|
||||
finsh_code_byte(FINSH_OP_LD_DWORD);
|
||||
finsh_code_dword(1);
|
||||
|
||||
/* add_dword */
|
||||
finsh_code_byte(FINSH_OP_SUB_DWORD);
|
||||
/* st_dword */
|
||||
finsh_code_byte(FINSH_OP_ST_DWORD);
|
||||
|
||||
/* load value again */
|
||||
finsh_code_byte(FINSH_OP_LD_VALUE_DWORD_STACK);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/* increase */
|
||||
case FINSH_NODE_SYS_INC:
|
||||
if (finsh_node_child(node) && finsh_node_child(node)->node_type == FINSH_NODE_ID)
|
||||
{
|
||||
struct finsh_var* var;
|
||||
var = finsh_node_child(node)->id.var;
|
||||
|
||||
switch (node->data_type)
|
||||
{
|
||||
case FINSH_DATA_TYPE_BYTE:
|
||||
/* ld_value_byte &id */
|
||||
// finsh_code_byte(FINSH_OP_LD_VALUE_BYTE);
|
||||
// finsh_code_dword((long)&(var->value.char_value));
|
||||
|
||||
/* ld_dword &id */
|
||||
finsh_code_byte(FINSH_OP_LD_DWORD);
|
||||
finsh_code_dword((long)&(var->value.char_value));
|
||||
|
||||
/* ld_value_byte &id */
|
||||
finsh_code_byte(FINSH_OP_LD_VALUE_BYTE);
|
||||
finsh_code_dword((long)&(var->value.char_value));
|
||||
|
||||
/* ld_byte 1 */
|
||||
finsh_code_byte(FINSH_OP_LD_BYTE);
|
||||
finsh_code_byte(1);
|
||||
|
||||
/* add_byte */
|
||||
finsh_code_byte(FINSH_OP_ADD_BYTE);
|
||||
/* get byte */
|
||||
finsh_code_byte(FINSH_OP_ST_BYTE);
|
||||
|
||||
/* pop */
|
||||
finsh_code_byte(FINSH_OP_POP);
|
||||
break;
|
||||
|
||||
case FINSH_DATA_TYPE_WORD:
|
||||
/* ld_value_word &id */
|
||||
// finsh_code_byte(FINSH_OP_LD_VALUE_WORD);
|
||||
// finsh_code_dword((long)&(var->value.short_value));
|
||||
|
||||
/* ld_dword &id */
|
||||
finsh_code_byte(FINSH_OP_LD_DWORD);
|
||||
finsh_code_dword((long)&(var->value.short_value));
|
||||
|
||||
/* ld_value_word &id */
|
||||
finsh_code_byte(FINSH_OP_LD_VALUE_WORD);
|
||||
finsh_code_dword((long)&(var->value.short_value));
|
||||
|
||||
/* ld_word 1 */
|
||||
finsh_code_byte(FINSH_OP_LD_WORD);
|
||||
finsh_code_word(1);
|
||||
|
||||
/* add_byte */
|
||||
finsh_code_byte(FINSH_OP_ADD_WORD);
|
||||
/* get byte */
|
||||
finsh_code_byte(FINSH_OP_ST_WORD);
|
||||
|
||||
/* pop */
|
||||
finsh_code_byte(FINSH_OP_POP);
|
||||
break;
|
||||
|
||||
case FINSH_DATA_TYPE_DWORD:
|
||||
/* ld_value_dword &id */
|
||||
// finsh_code_byte(FINSH_OP_LD_VALUE_DWORD);
|
||||
// finsh_code_dword((long)&(var->value.long_value));
|
||||
|
||||
/* ld_dword &id */
|
||||
finsh_code_byte(FINSH_OP_LD_DWORD);
|
||||
finsh_code_dword((long)&(var->value.long_value));
|
||||
|
||||
/* ld_value_dword &id */
|
||||
finsh_code_byte(FINSH_OP_LD_VALUE_DWORD);
|
||||
finsh_code_dword((long)&(var->value.long_value));
|
||||
|
||||
/* ld_dword 1 */
|
||||
finsh_code_byte(FINSH_OP_LD_DWORD);
|
||||
finsh_code_dword(1);
|
||||
|
||||
/* add_byte */
|
||||
finsh_code_byte(FINSH_OP_ADD_DWORD);
|
||||
/* get byte */
|
||||
finsh_code_byte(FINSH_OP_ST_DWORD);
|
||||
|
||||
/* pop */
|
||||
finsh_code_byte(FINSH_OP_POP);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/* decrease */
|
||||
case FINSH_NODE_SYS_DEC:
|
||||
if (finsh_node_child(node) && finsh_node_child(node)->node_type == FINSH_NODE_ID)
|
||||
{
|
||||
struct finsh_var* var;
|
||||
var = finsh_node_child(node)->id.var;
|
||||
|
||||
switch (node->data_type)
|
||||
{
|
||||
case FINSH_DATA_TYPE_BYTE:
|
||||
/* ld_value_byte &id */
|
||||
// finsh_code_byte(FINSH_OP_LD_VALUE_BYTE);
|
||||
// finsh_code_dword((long)&(var->value.char_value));
|
||||
|
||||
/* ld_dword &id */
|
||||
finsh_code_byte(FINSH_OP_LD_DWORD);
|
||||
finsh_code_dword((long)&(var->value.char_value));
|
||||
|
||||
/* ld_value_byte &id */
|
||||
finsh_code_byte(FINSH_OP_LD_VALUE_BYTE);
|
||||
finsh_code_dword((long)&(var->value.char_value));
|
||||
|
||||
/* ld_byte 1 */
|
||||
finsh_code_byte(FINSH_OP_LD_BYTE);
|
||||
finsh_code_byte(1);
|
||||
|
||||
/* add_byte */
|
||||
finsh_code_byte(FINSH_OP_SUB_BYTE);
|
||||
/* get byte */
|
||||
finsh_code_byte(FINSH_OP_ST_BYTE);
|
||||
|
||||
/* pop */
|
||||
finsh_code_byte(FINSH_OP_POP);
|
||||
break;
|
||||
|
||||
case FINSH_DATA_TYPE_WORD:
|
||||
/* ld_value_word &id */
|
||||
// finsh_code_byte(FINSH_OP_LD_VALUE_WORD);
|
||||
// finsh_code_dword((long)&(var->value.short_value));
|
||||
|
||||
/* ld_dword &id */
|
||||
finsh_code_byte(FINSH_OP_LD_DWORD);
|
||||
finsh_code_dword((long)&(var->value.short_value));
|
||||
|
||||
/* ld_value_word &id */
|
||||
finsh_code_byte(FINSH_OP_LD_VALUE_WORD);
|
||||
finsh_code_dword((long)&(var->value.short_value));
|
||||
|
||||
/* ld_word 1 */
|
||||
finsh_code_byte(FINSH_OP_LD_WORD);
|
||||
finsh_code_word(1);
|
||||
|
||||
/* add_byte */
|
||||
finsh_code_byte(FINSH_OP_SUB_WORD);
|
||||
/* get byte */
|
||||
finsh_code_byte(FINSH_OP_ST_WORD);
|
||||
|
||||
/* pop */
|
||||
finsh_code_byte(FINSH_OP_POP);
|
||||
break;
|
||||
|
||||
case FINSH_DATA_TYPE_DWORD:
|
||||
/* ld_value_dword &id */
|
||||
// finsh_code_byte(FINSH_OP_LD_VALUE_DWORD);
|
||||
// finsh_code_dword((long)&(var->value.long_value));
|
||||
|
||||
/* ld_dword &id */
|
||||
finsh_code_byte(FINSH_OP_LD_DWORD);
|
||||
finsh_code_dword((long)&(var->value.long_value));
|
||||
|
||||
/* ld_value_dword &id */
|
||||
finsh_code_byte(FINSH_OP_LD_VALUE_DWORD);
|
||||
finsh_code_dword((long)&(var->value.long_value));
|
||||
|
||||
/* ld_dword 1 */
|
||||
finsh_code_byte(FINSH_OP_LD_DWORD);
|
||||
finsh_code_dword(1);
|
||||
|
||||
/* add_byte */
|
||||
finsh_code_byte(FINSH_OP_SUB_DWORD);
|
||||
/* get byte */
|
||||
finsh_code_byte(FINSH_OP_ST_DWORD);
|
||||
|
||||
/* pop */
|
||||
finsh_code_byte(FINSH_OP_POP);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case FINSH_NODE_SYS_NULL:
|
||||
finsh_code_dword(0);
|
||||
break;
|
||||
|
||||
case FINSH_NODE_SYS_GETVALUE:
|
||||
if (node->idtype & FINSH_IDTYPE_ADDRESS)
|
||||
{
|
||||
/* nothing will be generated */
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (node->data_type)
|
||||
{
|
||||
case FINSH_DATA_TYPE_BYTE:
|
||||
finsh_code_byte(FINSH_OP_LD_VALUE_BYTE_STACK);
|
||||
break;
|
||||
case FINSH_DATA_TYPE_WORD:
|
||||
finsh_code_byte(FINSH_OP_LD_VALUE_WORD_STACK);
|
||||
break;
|
||||
case FINSH_DATA_TYPE_DWORD:
|
||||
finsh_code_byte(FINSH_OP_LD_VALUE_DWORD_STACK);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case FINSH_NODE_SYS_GETADDR:
|
||||
/* nothing will be generated */
|
||||
break;
|
||||
|
||||
default:
|
||||
finsh_error_set(FINSH_ERROR_UNKNOWN_NODE);
|
||||
break;
|
||||
}
|
||||
|
||||
/* compile sibling node */
|
||||
if (finsh_node_sibling(node) != NULL)
|
||||
finsh_compile(finsh_node_sibling(node));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int finsh_type_check(struct finsh_node* node, u_char is_addr)
|
||||
{
|
||||
if (node != NULL)
|
||||
{
|
||||
/* address & value */
|
||||
if (node->node_type == FINSH_NODE_SYS_ASSIGN ||
|
||||
node->node_type == FINSH_NODE_SYS_PREINC ||
|
||||
node->node_type == FINSH_NODE_SYS_PREDEC ||
|
||||
node->node_type == FINSH_NODE_SYS_GETADDR)
|
||||
{
|
||||
/* address */
|
||||
finsh_type_check(finsh_node_child(node), FINSH_IDTYPE_ADDRESS);
|
||||
}
|
||||
else if (node->node_type == FINSH_NODE_SYS_GETVALUE && is_addr)
|
||||
{
|
||||
/* change the attribute of getvalue in left expr */
|
||||
finsh_type_check(finsh_node_child(node), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* transfer 'av' to child node */
|
||||
finsh_type_check(finsh_node_child(node), is_addr);
|
||||
}
|
||||
|
||||
/* always does not load address in sibling */
|
||||
finsh_type_check(finsh_node_sibling(node), FINSH_NODE_VALUE);
|
||||
|
||||
/** set attribute of current node */
|
||||
|
||||
/* make sure the current node is address or value */
|
||||
if (node->idtype != FINSH_IDTYPE_SYSCALL) node->idtype |= is_addr;
|
||||
|
||||
if (finsh_node_child(node) != NULL)
|
||||
{
|
||||
node->data_type = finsh_node_child(node)->data_type;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (node->node_type == FINSH_NODE_ID)
|
||||
{
|
||||
if (node->idtype & FINSH_IDTYPE_VAR)
|
||||
{
|
||||
struct finsh_var* var;
|
||||
|
||||
var = node->id.var;
|
||||
if (var != NULL)
|
||||
{
|
||||
switch (var->type)
|
||||
{
|
||||
case finsh_type_void:
|
||||
node->data_type = FINSH_DATA_TYPE_VOID;
|
||||
break;
|
||||
|
||||
case finsh_type_char:
|
||||
case finsh_type_uchar:
|
||||
node->data_type = FINSH_DATA_TYPE_BYTE;
|
||||
break;
|
||||
|
||||
case finsh_type_short:
|
||||
case finsh_type_ushort:
|
||||
node->data_type = FINSH_DATA_TYPE_WORD;
|
||||
break;
|
||||
|
||||
case finsh_type_int:
|
||||
case finsh_type_uint:
|
||||
case finsh_type_long:
|
||||
case finsh_type_ulong:
|
||||
node->data_type = FINSH_DATA_TYPE_DWORD;
|
||||
break;
|
||||
|
||||
case finsh_type_charp:
|
||||
case finsh_type_voidp:
|
||||
case finsh_type_shortp:
|
||||
case finsh_type_intp:
|
||||
case finsh_type_longp:
|
||||
node->data_type = FINSH_DATA_TYPE_DWORD;
|
||||
break;
|
||||
|
||||
default:
|
||||
finsh_error_set(FINSH_ERROR_UNKNOWN_TYPE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (node->idtype & FINSH_IDTYPE_SYSVAR)
|
||||
{
|
||||
struct finsh_sysvar *sysvar;
|
||||
|
||||
sysvar = node->id.sysvar;
|
||||
if (sysvar != NULL)
|
||||
{
|
||||
switch (sysvar->type)
|
||||
{
|
||||
case finsh_type_void:
|
||||
node->data_type = FINSH_DATA_TYPE_VOID;
|
||||
break;
|
||||
|
||||
case finsh_type_char:
|
||||
case finsh_type_uchar:
|
||||
node->data_type = FINSH_DATA_TYPE_BYTE;
|
||||
break;
|
||||
|
||||
case finsh_type_short:
|
||||
case finsh_type_ushort:
|
||||
node->data_type = FINSH_DATA_TYPE_WORD;
|
||||
break;
|
||||
|
||||
case finsh_type_int:
|
||||
case finsh_type_uint:
|
||||
case finsh_type_long:
|
||||
case finsh_type_ulong:
|
||||
node->data_type = FINSH_DATA_TYPE_DWORD;
|
||||
break;
|
||||
|
||||
case finsh_type_charp:
|
||||
case finsh_type_voidp:
|
||||
case finsh_type_shortp:
|
||||
case finsh_type_intp:
|
||||
case finsh_type_longp:
|
||||
node->data_type = FINSH_DATA_TYPE_DWORD;
|
||||
break;
|
||||
|
||||
default:
|
||||
finsh_error_set(FINSH_ERROR_UNKNOWN_TYPE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (node->node_type == FINSH_NODE_VALUE_CHAR)
|
||||
{
|
||||
node->data_type = FINSH_DATA_TYPE_BYTE;
|
||||
}
|
||||
else if (node->node_type == FINSH_NODE_VALUE_INT ||
|
||||
node->node_type == FINSH_NODE_VALUE_LONG ||
|
||||
node->node_type == FINSH_NODE_VALUE_STRING ||
|
||||
node->node_type == FINSH_NODE_VALUE_NULL)
|
||||
{
|
||||
node->data_type = FINSH_DATA_TYPE_DWORD;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int finsh_compiler_run(struct finsh_node* node)
|
||||
{
|
||||
struct finsh_node* sibling;
|
||||
|
||||
/* type check */
|
||||
finsh_type_check(node, FINSH_NODE_VALUE);
|
||||
|
||||
/* clean text segment and vm stack */
|
||||
memset(&text_segment[0], 0, sizeof(text_segment));
|
||||
memset(&finsh_vm_stack[0], 0, sizeof(finsh_vm_stack[0]));
|
||||
|
||||
/* reset compile stack pointer and pc */
|
||||
finsh_compile_sp = &finsh_vm_stack[0];
|
||||
finsh_compile_pc = &text_segment[0];
|
||||
|
||||
/* compile node */
|
||||
sibling = node;
|
||||
while (sibling != NULL)
|
||||
{
|
||||
struct finsh_node* current_node;
|
||||
current_node = sibling;
|
||||
|
||||
/* get sibling node */
|
||||
sibling = current_node->sibling;
|
||||
|
||||
/* clean sibling node */
|
||||
current_node->sibling = NULL;
|
||||
finsh_compile(current_node);
|
||||
|
||||
/* pop current value */
|
||||
if (sibling != NULL) finsh_code_byte(FINSH_OP_POP);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* error number for finsh shell.
|
||||
*
|
||||
* COPYRIGHT (C) 2013, Shanghai Real-Thread Technology Co., Ltd
|
||||
*
|
||||
* This file is part of RT-Thread (http://www.rt-thread.org)
|
||||
* Maintainer: bernard.xiong <bernard.xiong at gmail.com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2010-03-22 Bernard first version
|
||||
*/
|
||||
#include "finsh_error.h"
|
||||
|
||||
u_char global_errno;
|
||||
|
||||
static const char * finsh_error_string_table[] =
|
||||
{
|
||||
"No error",
|
||||
"Invalid token",
|
||||
"Expect a type",
|
||||
"Unknown type",
|
||||
"Variable exist",
|
||||
"Expect a operater",
|
||||
"Memory full",
|
||||
"Unknown operator",
|
||||
"Unknown node",
|
||||
"Expect a character",
|
||||
"Unexpect end",
|
||||
"Unknown token",
|
||||
"Float not supported",
|
||||
"Unknown symbol",
|
||||
"Null node"
|
||||
};
|
||||
|
||||
int finsh_error_init()
|
||||
{
|
||||
global_errno = FINSH_ERROR_OK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int finsh_error_set(u_char type)
|
||||
{
|
||||
global_errno = type;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u_char finsh_errno()
|
||||
{
|
||||
return global_errno;
|
||||
}
|
||||
|
||||
const char* finsh_error_string(u_char type)
|
||||
{
|
||||
return finsh_error_string_table[type];
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* error number for finsh shell.
|
||||
*
|
||||
* COPYRIGHT (C) 2013, Shanghai Real-Thread Technology Co., Ltd
|
||||
*
|
||||
* This file is part of RT-Thread (http://www.rt-thread.org)
|
||||
* Maintainer: bernard.xiong <bernard.xiong at gmail.com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2010-03-22 Bernard first version
|
||||
*/
|
||||
#ifndef __FINSH_ERROR_H__
|
||||
#define __FINSH_ERROR_H__
|
||||
|
||||
#include <finsh.h>
|
||||
|
||||
int finsh_error_init(void);
|
||||
|
||||
/* get error number */
|
||||
u_char finsh_errno(void);
|
||||
|
||||
int finsh_error_set(u_char type);
|
||||
const char* finsh_error_string(u_char type);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,298 @@
|
||||
/*
|
||||
* heap management in finsh shell.
|
||||
*
|
||||
* COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team
|
||||
*
|
||||
* This file is part of RT-Thread (http://www.rt-thread.org)
|
||||
* Maintainer: bernard.xiong <bernard.xiong at gmail.com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2010-03-22 Bernard first version
|
||||
*/
|
||||
#include <finsh.h>
|
||||
|
||||
#include "finsh_var.h"
|
||||
|
||||
ALIGN(RT_ALIGN_SIZE)
|
||||
u_char finsh_heap[FINSH_HEAP_MAX];
|
||||
struct finsh_block_header
|
||||
{
|
||||
u_long length;
|
||||
struct finsh_block_header* next;
|
||||
};
|
||||
#define BLOCK_HEADER(x) (struct finsh_block_header*)(x)
|
||||
#define finsh_block_get_header(data) (struct finsh_block_header*)((u_char*)data - sizeof(struct finsh_block_header))
|
||||
#define finsh_block_get_data(header) (u_char*)((struct finsh_block_header*)header + 1)
|
||||
#define HEAP_ALIGN_SIZE(size) (((size) + HEAP_ALIGNMENT - 1) & ~(HEAP_ALIGNMENT-1))
|
||||
|
||||
static struct finsh_block_header* free_list;
|
||||
static struct finsh_block_header* allocate_list;
|
||||
|
||||
static void finsh_heap_gc(void);
|
||||
|
||||
static void finsh_block_insert(struct finsh_block_header** list, struct finsh_block_header* header);
|
||||
static void finsh_block_remove(struct finsh_block_header** list, struct finsh_block_header* header);
|
||||
static void finsh_block_split(struct finsh_block_header* header, size_t size);
|
||||
static void finsh_block_merge(struct finsh_block_header** list, struct finsh_block_header* header);
|
||||
|
||||
int finsh_heap_init(void)
|
||||
{
|
||||
/* clear heap to zero */
|
||||
memset(&finsh_heap[0], 0, sizeof(finsh_heap));
|
||||
|
||||
/* init free and alloc list */
|
||||
free_list = BLOCK_HEADER(&finsh_heap[0]);
|
||||
free_list->length = FINSH_HEAP_MAX - sizeof(struct finsh_block_header);
|
||||
free_list->next = NULL;
|
||||
|
||||
allocate_list = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* allocate a block from heap
|
||||
*/
|
||||
void* finsh_heap_allocate(size_t size)
|
||||
{
|
||||
struct finsh_block_header* header;
|
||||
|
||||
size = HEAP_ALIGN_SIZE(size);
|
||||
|
||||
/* find the first fit block */
|
||||
for (header = free_list;
|
||||
((header != NULL) && (header->length <= size + sizeof(struct finsh_block_header)));
|
||||
header = header->next) ;
|
||||
|
||||
if (header == NULL)
|
||||
{
|
||||
finsh_heap_gc();
|
||||
|
||||
/* find the first fit block */
|
||||
for (header = free_list;
|
||||
((header != NULL) && (header->length < size + sizeof(struct finsh_block_header)));
|
||||
header = header->next) ;
|
||||
|
||||
/* there is no memory */
|
||||
if (header == NULL) return NULL;
|
||||
}
|
||||
|
||||
/* split block */
|
||||
finsh_block_split(header, size);
|
||||
|
||||
/* remove from free list */
|
||||
finsh_block_remove(&free_list, header);
|
||||
header->next = NULL;
|
||||
|
||||
/* insert to allocate list */
|
||||
finsh_block_insert(&allocate_list, header);
|
||||
|
||||
memset(finsh_block_get_data(header), 0, size);
|
||||
|
||||
return finsh_block_get_data(header);
|
||||
}
|
||||
|
||||
/**
|
||||
* release the allocated block
|
||||
*/
|
||||
void finsh_heap_free(void*ptr)
|
||||
{
|
||||
struct finsh_block_header* header;
|
||||
|
||||
/* get block header */
|
||||
header = finsh_block_get_header(ptr);
|
||||
|
||||
/* remove from allocate list */
|
||||
finsh_block_remove(&allocate_list, header);
|
||||
|
||||
/* insert to free list */
|
||||
finsh_block_insert(&free_list, header);
|
||||
finsh_block_merge(&free_list, header);
|
||||
}
|
||||
|
||||
/**
|
||||
* garbage collector
|
||||
*/
|
||||
static void finsh_heap_gc(void)
|
||||
{
|
||||
int i;
|
||||
struct finsh_block_header *header, *temp;
|
||||
|
||||
temp = NULL;
|
||||
|
||||
/* find the first fit block */
|
||||
for (header = allocate_list; header != NULL; )
|
||||
{
|
||||
for (i = 0; i < FINSH_VARIABLE_MAX; i ++)
|
||||
{
|
||||
if (global_variable[i].type != finsh_type_unknown)
|
||||
{
|
||||
if (global_variable[i].value.ptr == finsh_block_get_data(header))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
temp = header;
|
||||
header = header->next;
|
||||
|
||||
/* this block is an unused block, release it */
|
||||
if (i == FINSH_VARIABLE_MAX)
|
||||
{
|
||||
finsh_heap_free(finsh_block_get_data(temp));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* insert a block to list
|
||||
*/
|
||||
void finsh_block_insert(struct finsh_block_header** list, struct finsh_block_header* header)
|
||||
{
|
||||
struct finsh_block_header* node;
|
||||
|
||||
if (*list == NULL)
|
||||
{
|
||||
*list = header;
|
||||
return;
|
||||
}
|
||||
|
||||
/* find out insert point */
|
||||
node = *list;
|
||||
|
||||
if (node > header)
|
||||
{
|
||||
/* insert node in the header of list */
|
||||
header->next = node;
|
||||
*list = header;
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (node = *list; node; node = node->next)
|
||||
{
|
||||
if (node->next > header) break;
|
||||
|
||||
if (node->next == NULL) break;
|
||||
}
|
||||
}
|
||||
|
||||
/* insert node */
|
||||
if (node->next != NULL) header->next = node->next;
|
||||
node->next = header;
|
||||
}
|
||||
|
||||
/**
|
||||
* remove block from list
|
||||
*/
|
||||
void finsh_block_remove(struct finsh_block_header** list, struct finsh_block_header* header)
|
||||
{
|
||||
struct finsh_block_header* node;
|
||||
|
||||
node = *list;
|
||||
if (node == header)
|
||||
{
|
||||
/* remove list header */
|
||||
*list = header->next;
|
||||
header->next = NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (node = *list; node != NULL; node = node->next)
|
||||
{
|
||||
if (node->next == header)
|
||||
{
|
||||
node->next = header->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* split block
|
||||
*/
|
||||
void finsh_block_split(struct finsh_block_header* header, size_t size)
|
||||
{
|
||||
struct finsh_block_header* next;
|
||||
|
||||
/*
|
||||
* split header into two node:
|
||||
* header->next->...
|
||||
*/
|
||||
next = BLOCK_HEADER((u_char*)header + sizeof(struct finsh_block_header) + size);
|
||||
next->length = header->length - sizeof(struct finsh_block_header) - size;
|
||||
header->length = size;
|
||||
next->next = header->next;
|
||||
|
||||
header->next = next;
|
||||
}
|
||||
|
||||
void finsh_block_merge(struct finsh_block_header** list, struct finsh_block_header* header)
|
||||
{
|
||||
struct finsh_block_header* prev_node;
|
||||
struct finsh_block_header* next_node;
|
||||
|
||||
next_node = header->next;
|
||||
|
||||
if (*list == header) prev_node = NULL;
|
||||
else
|
||||
{
|
||||
/* find out the previous header */
|
||||
for (prev_node = *list; prev_node; prev_node =prev_node->next)
|
||||
{
|
||||
if (prev_node->next == header)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* try merge node */
|
||||
|
||||
/* merge to previous node */
|
||||
if (prev_node != NULL &&
|
||||
((u_char*)prev_node + prev_node->length + sizeof(struct finsh_block_header)
|
||||
== (u_char*)header))
|
||||
{
|
||||
/* is it close to next node? */
|
||||
if ((next_node != NULL) &&
|
||||
((u_char*)header + header->length + sizeof(struct finsh_block_header)
|
||||
== (u_char*)next_node))
|
||||
{
|
||||
/* merge three node */
|
||||
prev_node->length += header->length + next_node->length +
|
||||
2 * sizeof(struct finsh_block_header);
|
||||
|
||||
prev_node->next = next_node->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev_node->length += header->length + sizeof(struct finsh_block_header);
|
||||
prev_node->next = header->next;
|
||||
}
|
||||
}
|
||||
else /* merge to last node */
|
||||
if ( (next_node != NULL) &&
|
||||
((u_char*)header + header->length + sizeof(struct finsh_block_header)
|
||||
== (u_char*)next_node))
|
||||
{
|
||||
header->length += next_node->length + sizeof(struct finsh_block_header);
|
||||
header->next = next_node->next;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* heap management in finsh shell.
|
||||
*
|
||||
* COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team
|
||||
*
|
||||
* This file is part of RT-Thread (http://www.rt-thread.org)
|
||||
* Maintainer: bernard.xiong <bernard.xiong at gmail.com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2010-03-22 Bernard first version
|
||||
*/
|
||||
#include <finsh.h>
|
||||
|
||||
#ifndef __FINSH_HEAP_H__
|
||||
#define __FINSH_HEAP_H__
|
||||
|
||||
int finsh_heap_init(void);
|
||||
void* finsh_heap_allocate(size_t size);
|
||||
void finsh_heap_free(void*ptr);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Initialization procedure for finsh shell.
|
||||
*
|
||||
* COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team
|
||||
*
|
||||
* This file is part of RT-Thread (http://www.rt-thread.org)
|
||||
* Maintainer: bernard.xiong <bernard.xiong at gmail.com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2010-03-22 Bernard first version
|
||||
*/
|
||||
#include <finsh.h>
|
||||
|
||||
#include "finsh_node.h"
|
||||
#include "finsh_vm.h"
|
||||
#include "finsh_parser.h"
|
||||
#include "finsh_var.h"
|
||||
#include "finsh_error.h"
|
||||
#include "finsh_heap.h"
|
||||
|
||||
int finsh_init(struct finsh_parser* parser)
|
||||
{
|
||||
finsh_parser_init(parser);
|
||||
|
||||
/* finsh init */
|
||||
finsh_node_init();
|
||||
finsh_var_init();
|
||||
finsh_error_init();
|
||||
finsh_heap_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
long finsh_stack_bottom()
|
||||
{
|
||||
return finsh_vm_stack[0].long_value;
|
||||
}
|
||||
|
||||
int finsh_flush(struct finsh_parser* parser)
|
||||
{
|
||||
finsh_parser_init(parser);
|
||||
|
||||
/* finsh init */
|
||||
finsh_node_init();
|
||||
finsh_error_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int finsh_reset(struct finsh_parser* parser)
|
||||
{
|
||||
/* finsh init */
|
||||
finsh_node_init();
|
||||
finsh_var_init();
|
||||
finsh_error_init();
|
||||
finsh_heap_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* node routines for finsh shell.
|
||||
*
|
||||
* COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team
|
||||
*
|
||||
* This file is part of RT-Thread (http://www.rt-thread.org)
|
||||
* Maintainer: bernard.xiong <bernard.xiong at gmail.com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2010-03-22 Bernard first version
|
||||
*/
|
||||
#include <finsh.h>
|
||||
|
||||
#include "finsh_node.h"
|
||||
#include "finsh_error.h"
|
||||
#include "finsh_var.h"
|
||||
#include "finsh_heap.h"
|
||||
|
||||
struct finsh_node global_node_table[FINSH_NODE_MAX];
|
||||
|
||||
int finsh_node_init()
|
||||
{
|
||||
memset(global_node_table, 0, sizeof(global_node_table));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct finsh_node* finsh_node_allocate(u_char type)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* find an empty entry */
|
||||
for (i = 0; i < FINSH_NODE_MAX; i ++)
|
||||
{
|
||||
if (global_node_table[i].node_type == FINSH_NODE_UNKNOWN) break;
|
||||
}
|
||||
|
||||
if (i == FINSH_NODE_MAX) return NULL;
|
||||
|
||||
/* fill type field */
|
||||
global_node_table[i].node_type = type;
|
||||
|
||||
/* return this allocated node */
|
||||
return &global_node_table[i];
|
||||
}
|
||||
|
||||
struct finsh_node* finsh_node_new_id(char* id)
|
||||
{
|
||||
struct finsh_node* node;
|
||||
void* symbol;
|
||||
unsigned char type;
|
||||
|
||||
symbol = NULL;
|
||||
type = 0;
|
||||
node = NULL;
|
||||
|
||||
/* lookup variable firstly */
|
||||
symbol = (void*)finsh_var_lookup(id);
|
||||
if (symbol == NULL)
|
||||
{
|
||||
/* then lookup system variable */
|
||||
symbol = (void*)finsh_sysvar_lookup(id);
|
||||
if (symbol == NULL)
|
||||
{
|
||||
/* then lookup system call */
|
||||
symbol = (void*)finsh_syscall_lookup(id);
|
||||
if (symbol != NULL) type = FINSH_IDTYPE_SYSCALL;
|
||||
}
|
||||
else type = FINSH_IDTYPE_SYSVAR;
|
||||
}
|
||||
else type = FINSH_IDTYPE_VAR;
|
||||
|
||||
if (symbol != NULL)
|
||||
{
|
||||
/* allocate a new node */
|
||||
node = finsh_node_allocate(FINSH_NODE_ID);
|
||||
|
||||
/* allocate node error */
|
||||
if (node == NULL)
|
||||
{
|
||||
finsh_error_set(FINSH_ERROR_MEMORY_FULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* fill node value according type */
|
||||
switch (type)
|
||||
{
|
||||
case FINSH_IDTYPE_VAR:
|
||||
node->id.var = (struct finsh_var*)symbol;
|
||||
break;
|
||||
|
||||
case FINSH_IDTYPE_SYSVAR:
|
||||
node->id.sysvar = (struct finsh_sysvar*)symbol;
|
||||
break;
|
||||
|
||||
case FINSH_IDTYPE_SYSCALL:
|
||||
node->id.syscall = (struct finsh_syscall*)symbol;
|
||||
break;
|
||||
}
|
||||
/* fill identifier type */
|
||||
node->idtype = type;
|
||||
}
|
||||
else finsh_error_set(FINSH_ERROR_UNKNOWN_SYMBOL);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
struct finsh_node* finsh_node_new_char(char c)
|
||||
{
|
||||
struct finsh_node* node;
|
||||
|
||||
node = finsh_node_allocate(FINSH_NODE_VALUE_CHAR);
|
||||
if (node == NULL)
|
||||
{
|
||||
finsh_error_set(FINSH_ERROR_MEMORY_FULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node->value.char_value = c;
|
||||
return node;
|
||||
}
|
||||
|
||||
struct finsh_node* finsh_node_new_int(int i)
|
||||
{
|
||||
struct finsh_node* node;
|
||||
|
||||
node = finsh_node_allocate(FINSH_NODE_VALUE_INT);
|
||||
if (node == NULL)
|
||||
{
|
||||
finsh_error_set(FINSH_ERROR_MEMORY_FULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node->value.int_value = i;
|
||||
return node;
|
||||
}
|
||||
|
||||
struct finsh_node* finsh_node_new_long(long l)
|
||||
{
|
||||
struct finsh_node* node;
|
||||
|
||||
node = finsh_node_allocate(FINSH_NODE_VALUE_LONG);
|
||||
if (node == NULL)
|
||||
{
|
||||
finsh_error_set(FINSH_ERROR_MEMORY_FULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node->value.long_value = l;
|
||||
return node;
|
||||
}
|
||||
|
||||
struct finsh_node* finsh_node_new_string(char* s)
|
||||
{
|
||||
struct finsh_node* node;
|
||||
|
||||
node = finsh_node_allocate(FINSH_NODE_VALUE_STRING);
|
||||
if (node == NULL)
|
||||
{
|
||||
finsh_error_set(FINSH_ERROR_MEMORY_FULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* make string */
|
||||
node->value.ptr = finsh_heap_allocate(strlen(s) + 1);
|
||||
strncpy(node->value.ptr, s, strlen(s));
|
||||
((u_char*)node->value.ptr)[strlen(s)] = '\0';
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
struct finsh_node* finsh_node_new_ptr(void* ptr)
|
||||
{
|
||||
struct finsh_node* node;
|
||||
|
||||
node = finsh_node_allocate(FINSH_NODE_VALUE_NULL);
|
||||
if (node == NULL)
|
||||
{
|
||||
finsh_error_set(FINSH_ERROR_MEMORY_FULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node->value.ptr = ptr;
|
||||
return node;
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* node routines for finsh shell.
|
||||
*
|
||||
* COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team
|
||||
*
|
||||
* This file is part of RT-Thread (http://www.rt-thread.org)
|
||||
* Maintainer: bernard.xiong <bernard.xiong at gmail.com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2010-03-22 Bernard first version
|
||||
*/
|
||||
#ifndef __FINSH_NODE_H__
|
||||
#define __FINSH_NODE_H__
|
||||
|
||||
#include <finsh.h>
|
||||
|
||||
#define FINSH_NODE_UNKNOWN 0
|
||||
#define FINSH_NODE_ID 1
|
||||
|
||||
#define FINSH_NODE_VALUE_CHAR 2
|
||||
#define FINSH_NODE_VALUE_INT 3
|
||||
#define FINSH_NODE_VALUE_LONG 4
|
||||
#define FINSH_NODE_VALUE_STRING 5
|
||||
#define FINSH_NODE_VALUE_NULL 6
|
||||
|
||||
#define FINSH_NODE_SYS_ADD 7
|
||||
#define FINSH_NODE_SYS_SUB 8
|
||||
#define FINSH_NODE_SYS_MUL 9
|
||||
#define FINSH_NODE_SYS_DIV 10
|
||||
#define FINSH_NODE_SYS_MOD 11
|
||||
#define FINSH_NODE_SYS_AND 12
|
||||
#define FINSH_NODE_SYS_OR 13
|
||||
#define FINSH_NODE_SYS_XOR 14
|
||||
#define FINSH_NODE_SYS_BITWISE 15
|
||||
#define FINSH_NODE_SYS_SHL 16
|
||||
#define FINSH_NODE_SYS_SHR 17
|
||||
#define FINSH_NODE_SYS_FUNC 18
|
||||
#define FINSH_NODE_SYS_ASSIGN 19
|
||||
#define FINSH_NODE_SYS_CAST 20
|
||||
#define FINSH_NODE_SYS_PREINC 21
|
||||
#define FINSH_NODE_SYS_PREDEC 22
|
||||
#define FINSH_NODE_SYS_INC 23
|
||||
#define FINSH_NODE_SYS_DEC 24
|
||||
#define FINSH_NODE_SYS_GETVALUE 25
|
||||
#define FINSH_NODE_SYS_GETADDR 26
|
||||
#define FINSH_NODE_SYS_NULL 27
|
||||
|
||||
#define FINSH_DATA_TYPE_VOID 0x00
|
||||
#define FINSH_DATA_TYPE_BYTE 0x01
|
||||
#define FINSH_DATA_TYPE_WORD 0x02
|
||||
#define FINSH_DATA_TYPE_DWORD 0x03
|
||||
#define FINSH_DATA_TYPE_PTR 0x10
|
||||
|
||||
#define FINSH_NODE_VALUE 0
|
||||
#define FINSH_NODE_ADDRESS 1
|
||||
#define FINSH_NODE_FUNCTION 2
|
||||
|
||||
int finsh_node_init(void);
|
||||
|
||||
struct finsh_node* finsh_node_allocate(u_char type);
|
||||
struct finsh_node* finsh_node_new_id(char* id);
|
||||
struct finsh_node* finsh_node_new_char(char c);
|
||||
struct finsh_node* finsh_node_new_int(int i);
|
||||
struct finsh_node* finsh_node_new_long(long l);
|
||||
struct finsh_node* finsh_node_new_string(char* s);
|
||||
struct finsh_node* finsh_node_new_ptr(void* ptr);
|
||||
|
||||
#define finsh_node_sibling(node) ((node)->sibling)
|
||||
#define finsh_node_child(node) ((node)->child)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,622 @@
|
||||
/*
|
||||
* operations for finsh shell.
|
||||
*
|
||||
* COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team
|
||||
*
|
||||
* This file is part of RT-Thread (http://www.rt-thread.org)
|
||||
* Maintainer: bernard.xiong <bernard.xiong at gmail.com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2010-03-22 Bernard first version
|
||||
*/
|
||||
#include "finsh_ops.h"
|
||||
#include "finsh_vm.h"
|
||||
|
||||
#define OP_BIN_BYTE(x) do {\
|
||||
(finsh_sp - 2)->char_value = (finsh_sp - 2)->char_value x (finsh_sp - 1)->char_value; \
|
||||
finsh_sp--; \
|
||||
}while (0)
|
||||
|
||||
#define OP_BIN_WORD(x) do {\
|
||||
(finsh_sp - 2)->short_value = (finsh_sp - 2)->short_value x (finsh_sp - 1)->short_value; \
|
||||
finsh_sp--; \
|
||||
}while (0)
|
||||
|
||||
#define OP_BIN_DWORD(x) do {\
|
||||
(finsh_sp - 2)->long_value = (finsh_sp - 2)->long_value x (finsh_sp - 1)->long_value; \
|
||||
finsh_sp--; \
|
||||
}while (0)
|
||||
|
||||
/* --- noop --- */
|
||||
void OP_no_op()
|
||||
{
|
||||
/* none */
|
||||
return ;
|
||||
}
|
||||
|
||||
/* --- add --- */
|
||||
void OP_add_byte()
|
||||
{
|
||||
OP_BIN_BYTE(+);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
void OP_add_word()
|
||||
{
|
||||
OP_BIN_WORD(+);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
void OP_add_dword()
|
||||
{
|
||||
OP_BIN_DWORD(+);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
/* --- sub --- */
|
||||
void OP_sub_byte()
|
||||
{
|
||||
OP_BIN_BYTE(-);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
void OP_sub_word()
|
||||
{
|
||||
OP_BIN_WORD(-);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
void OP_sub_dword()
|
||||
{
|
||||
OP_BIN_DWORD(-);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
/* --- div --- */
|
||||
void OP_div_byte()
|
||||
{
|
||||
OP_BIN_BYTE(/);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
void OP_div_word()
|
||||
{
|
||||
OP_BIN_WORD(/);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
void OP_div_dword()
|
||||
{
|
||||
OP_BIN_DWORD(/);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
/* --- mod --- */
|
||||
void OP_mod_byte()
|
||||
{
|
||||
OP_BIN_BYTE(%);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
void OP_mod_word()
|
||||
{
|
||||
OP_BIN_WORD(%);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
void OP_mod_dword()
|
||||
{
|
||||
OP_BIN_DWORD(%);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
/* --- mul --- */
|
||||
void OP_mul_byte()
|
||||
{
|
||||
OP_BIN_BYTE(*);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
void OP_mul_word()
|
||||
{
|
||||
OP_BIN_WORD(*);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
void OP_mul_dword()
|
||||
{
|
||||
OP_BIN_DWORD(*);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
/* --- and --- */
|
||||
void OP_and_byte()
|
||||
{
|
||||
OP_BIN_BYTE(&);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
void OP_and_word()
|
||||
{
|
||||
OP_BIN_WORD(&);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
void OP_and_dword()
|
||||
{
|
||||
OP_BIN_DWORD(&);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
/* --- or --- */
|
||||
void OP_or_byte()
|
||||
{
|
||||
OP_BIN_BYTE(|);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
void OP_or_word()
|
||||
{
|
||||
OP_BIN_WORD(|);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
void OP_or_dword()
|
||||
{
|
||||
OP_BIN_DWORD(|);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
/* --- xor --- */
|
||||
void OP_xor_byte()
|
||||
{
|
||||
OP_BIN_BYTE(^);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
void OP_xor_word()
|
||||
{
|
||||
OP_BIN_WORD(^);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
void OP_xor_dword()
|
||||
{
|
||||
OP_BIN_DWORD(^);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
/* --- bw --- */
|
||||
void OP_bw_byte()
|
||||
{
|
||||
(finsh_sp - 1)->char_value = ~ ((finsh_sp - 1)->char_value);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
void OP_bw_word()
|
||||
{
|
||||
(finsh_sp - 1)->short_value = ~ ((finsh_sp - 1)->short_value);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
void OP_bw_dword()
|
||||
{
|
||||
(finsh_sp - 1)->long_value = ~ ((finsh_sp - 1)->long_value);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
/* --- shl --- */
|
||||
void OP_shl_byte()
|
||||
{
|
||||
OP_BIN_BYTE(<<);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
void OP_shl_word()
|
||||
{
|
||||
OP_BIN_WORD(<<);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
void OP_shl_dword()
|
||||
{
|
||||
OP_BIN_DWORD(<<);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
/* --- shr --- */
|
||||
void OP_shr_byte()
|
||||
{
|
||||
OP_BIN_BYTE(>>);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
void OP_shr_word()
|
||||
{
|
||||
OP_BIN_WORD(>>);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
void OP_shr_dword()
|
||||
{
|
||||
OP_BIN_DWORD(>>);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
/* --- ld --- */
|
||||
void OP_ld_byte()
|
||||
{
|
||||
finsh_sp->char_value = *finsh_pc;
|
||||
|
||||
finsh_sp++;
|
||||
finsh_pc++;
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
void OP_ld_word()
|
||||
{
|
||||
finsh_sp->short_value = FINSH_GET16(finsh_pc);
|
||||
|
||||
finsh_sp ++;
|
||||
finsh_pc += 2;
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
void OP_ld_dword()
|
||||
{
|
||||
finsh_sp->long_value = FINSH_GET32(finsh_pc);
|
||||
|
||||
finsh_sp ++;
|
||||
finsh_pc += 4;
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
void OP_ld_value_byte()
|
||||
{
|
||||
char* c;
|
||||
|
||||
c = (char*) (FINSH_GET32(finsh_pc));
|
||||
|
||||
finsh_sp->char_value = *c;
|
||||
|
||||
finsh_sp ++;
|
||||
finsh_pc += 4;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void OP_ld_value_byte_stack()
|
||||
{
|
||||
char* c;
|
||||
|
||||
c = (char *)(finsh_sp - 1)->long_value;
|
||||
(finsh_sp - 1)->char_value = *c;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void OP_ld_value_word()
|
||||
{
|
||||
short* s;
|
||||
|
||||
s = (short*) (FINSH_GET32(finsh_pc));
|
||||
|
||||
finsh_sp->short_value = *s;
|
||||
|
||||
finsh_sp ++;
|
||||
finsh_pc += 4;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void OP_ld_value_word_stack()
|
||||
{
|
||||
short* s;
|
||||
|
||||
s = (short *)(finsh_sp - 1)->long_value;
|
||||
(finsh_sp - 1)->short_value = *s;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void OP_ld_value_dword()
|
||||
{
|
||||
long* l;
|
||||
|
||||
l = (long*) (FINSH_GET32(finsh_pc));
|
||||
|
||||
finsh_sp->long_value = *l;
|
||||
|
||||
finsh_sp ++;
|
||||
finsh_pc += 4;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void OP_ld_value_dword_stack()
|
||||
{
|
||||
long* l;
|
||||
|
||||
l = (long *)(finsh_sp - 1)->long_value;
|
||||
(finsh_sp - 1)->long_value = *l;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* --- st --- */
|
||||
/*
|
||||
* 2006-4-16 bernard
|
||||
* fixed the sp move bug
|
||||
*/
|
||||
void OP_st_byte()
|
||||
{
|
||||
*(char*)((finsh_sp - 2)->long_value) = (finsh_sp - 1)->char_value;
|
||||
finsh_sp --;
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
/*
|
||||
* 2006-4-16 bernard
|
||||
* fixed the sp move bug
|
||||
*/
|
||||
void OP_st_word()
|
||||
{
|
||||
*(short*)((finsh_sp - 2)->long_value) = (finsh_sp - 1)->short_value;
|
||||
finsh_sp --;
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
/*
|
||||
* 2006-4-16 bernard
|
||||
* fixed the sp move bug
|
||||
*/
|
||||
void OP_st_dword()
|
||||
{
|
||||
*(long*)((finsh_sp - 2)->long_value) = (finsh_sp - 1)->long_value;
|
||||
finsh_sp --;
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
/* --- pop --- */
|
||||
void OP_pop()
|
||||
{
|
||||
finsh_sp --;
|
||||
return ;
|
||||
}
|
||||
|
||||
/* --- call --- */
|
||||
void OP_call()
|
||||
{
|
||||
/* the max number of arg*/
|
||||
unsigned long parameterv[16];
|
||||
unsigned int parameters, i;
|
||||
|
||||
typedef unsigned long var_t;
|
||||
typedef var_t (*op_func)();
|
||||
op_func f;
|
||||
var_t r;
|
||||
|
||||
parameters = *finsh_pc ++;
|
||||
|
||||
i = 0; finsh_sp --;
|
||||
while (i < parameters)
|
||||
{
|
||||
parameterv[parameters - 1 - i] = finsh_sp->long_value;
|
||||
finsh_sp --;
|
||||
i++;
|
||||
}
|
||||
|
||||
f = (op_func)(finsh_sp->long_value);
|
||||
switch (parameters)
|
||||
{
|
||||
case 0:
|
||||
r = f(0);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
r = f(parameterv[0]);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
r = f(parameterv[0], parameterv[1]);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
r = f(parameterv[0], parameterv[1], parameterv[2]);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3]);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3],
|
||||
parameterv[4]);
|
||||
break;
|
||||
|
||||
case 6:
|
||||
r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3],
|
||||
parameterv[4], parameterv[5]);
|
||||
break;
|
||||
|
||||
case 7:
|
||||
r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3],
|
||||
parameterv[4], parameterv[5], parameterv[6]);
|
||||
break;
|
||||
|
||||
case 8:
|
||||
r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3],
|
||||
parameterv[4], parameterv[5], parameterv[6], parameterv[7]);
|
||||
break;
|
||||
|
||||
case 9:
|
||||
r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3],
|
||||
parameterv[4], parameterv[5], parameterv[6], parameterv[7],
|
||||
parameterv[8]);
|
||||
break;
|
||||
|
||||
case 10:
|
||||
r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3],
|
||||
parameterv[4], parameterv[5], parameterv[6], parameterv[7],
|
||||
parameterv[8], parameterv[9]);
|
||||
break;
|
||||
|
||||
case 11:
|
||||
r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3],
|
||||
parameterv[4], parameterv[5], parameterv[6], parameterv[7],
|
||||
parameterv[8], parameterv[9], parameterv[10]);
|
||||
break;
|
||||
|
||||
case 12:
|
||||
r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3],
|
||||
parameterv[4], parameterv[5], parameterv[6], parameterv[7],
|
||||
parameterv[8], parameterv[9], parameterv[10], parameterv[11]);
|
||||
break;
|
||||
|
||||
case 13:
|
||||
r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3],
|
||||
parameterv[4], parameterv[5], parameterv[6], parameterv[7],
|
||||
parameterv[8], parameterv[9], parameterv[10], parameterv[11],
|
||||
parameterv[12]);
|
||||
break;
|
||||
|
||||
case 14:
|
||||
r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3],
|
||||
parameterv[4], parameterv[5], parameterv[6], parameterv[7],
|
||||
parameterv[8], parameterv[9], parameterv[10], parameterv[11],
|
||||
parameterv[12], parameterv[13]);
|
||||
break;
|
||||
|
||||
case 15:
|
||||
r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3],
|
||||
parameterv[4], parameterv[5], parameterv[6], parameterv[7],
|
||||
parameterv[8], parameterv[9], parameterv[10], parameterv[11],
|
||||
parameterv[12], parameterv[13], parameterv[14]);
|
||||
break;
|
||||
|
||||
case 16:
|
||||
r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3],
|
||||
parameterv[4], parameterv[5], parameterv[6], parameterv[7],
|
||||
parameterv[8], parameterv[9], parameterv[10], parameterv[11],
|
||||
parameterv[12], parameterv[13], parameterv[14], parameterv[15]);
|
||||
break;
|
||||
|
||||
default:
|
||||
r = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
finsh_sp->long_value = r;
|
||||
finsh_sp ++;
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
const op_func op_table[] =
|
||||
{
|
||||
/* 00 */ OP_no_op,
|
||||
/* 01 */ OP_add_byte,
|
||||
/* 02 */ OP_add_word,
|
||||
/* 03 */ OP_add_dword,
|
||||
/* 04 */ OP_sub_byte,
|
||||
/* 05 */ OP_sub_word,
|
||||
/* 06 */ OP_sub_dword,
|
||||
/* 07 */ OP_div_byte,
|
||||
/* 08 */ OP_div_word,
|
||||
/* 09 */ OP_div_dword,
|
||||
/* 10 */ OP_mod_byte,
|
||||
/* 11 */ OP_mod_word,
|
||||
/* 12 */ OP_mod_dword,
|
||||
/* 13 */ OP_mul_byte,
|
||||
/* 14 */ OP_mul_word,
|
||||
/* 15 */ OP_mul_dword,
|
||||
/* 16 */ OP_and_byte,
|
||||
/* 17 */ OP_and_word,
|
||||
/* 18 */ OP_and_dword,
|
||||
/* 19 */ OP_or_byte,
|
||||
/* 20 */ OP_or_word,
|
||||
/* 21 */ OP_or_dword,
|
||||
/* 22 */ OP_xor_byte,
|
||||
/* 23 */ OP_xor_word,
|
||||
/* 24 */ OP_xor_dword,
|
||||
/* 25 */ OP_bw_byte,
|
||||
/* 26 */ OP_bw_word,
|
||||
/* 27 */ OP_bw_dword,
|
||||
/* 28 */ OP_shl_byte,
|
||||
/* 29 */ OP_shl_word,
|
||||
/* 30 */ OP_shl_dword,
|
||||
/* 31 */ OP_shr_byte,
|
||||
/* 32 */ OP_shr_word,
|
||||
/* 33 */ OP_shr_dword,
|
||||
/* 34 */ OP_ld_byte,
|
||||
/* 35 */ OP_ld_word,
|
||||
/* 36 */ OP_ld_dword,
|
||||
/* 37 */ OP_ld_value_byte,
|
||||
/* 38 */ OP_ld_value_word,
|
||||
/* 39 */ OP_ld_value_dword,
|
||||
/* 40 */ OP_st_byte,
|
||||
/* 41 */ OP_st_word,
|
||||
/* 42 */ OP_st_dword,
|
||||
/* 43 */ OP_pop,
|
||||
/* 44 */ OP_call,
|
||||
/* 45 */ OP_ld_value_byte_stack,
|
||||
/* 46 */ OP_ld_value_word_stack,
|
||||
/* 47 */ OP_ld_value_dword_stack,
|
||||
NULL
|
||||
};
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* operations for finsh shell.
|
||||
*
|
||||
* COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team
|
||||
*
|
||||
* This file is part of RT-Thread (http://www.rt-thread.org)
|
||||
* Maintainer: bernard.xiong <bernard.xiong at gmail.com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2010-03-22 Bernard first version
|
||||
*/
|
||||
#ifndef __FINSH_OP_H__
|
||||
#define __FINSH_OP_H__
|
||||
|
||||
#include "finsh_vm.h"
|
||||
|
||||
/*
|
||||
* FinC VM specification
|
||||
* Memory
|
||||
* .VAR
|
||||
*
|
||||
* .STACK
|
||||
*
|
||||
* .HEAP
|
||||
*
|
||||
* .TEXT
|
||||
* OP [op1]
|
||||
*/
|
||||
|
||||
#define FINSH_OP_NOOP 0x00
|
||||
|
||||
/* add @ r1 = r2 + r3 */
|
||||
#define FINSH_OP_ADD_BYTE 0x01
|
||||
#define FINSH_OP_ADD_WORD 0x02
|
||||
#define FINSH_OP_ADD_DWORD 0x03
|
||||
|
||||
/* sub @ r1 = r2 - r3 */
|
||||
#define FINSH_OP_SUB_BYTE 0x04
|
||||
#define FINSH_OP_SUB_WORD 0x05
|
||||
#define FINSH_OP_SUB_DWORD 0x06
|
||||
|
||||
/* div @ r1 = r2 / r3 */
|
||||
#define FINSH_OP_DIV_BYTE 0x07
|
||||
#define FINSH_OP_DIV_WORD 0x08
|
||||
#define FINSH_OP_DIV_DWORD 0x09
|
||||
|
||||
/* mod @ r1 = r2 % r3 */
|
||||
#define FINSH_OP_MOD_BYTE 0x0A
|
||||
#define FINSH_OP_MOD_WORD 0x0B
|
||||
#define FINSH_OP_MOD_DWORD 0x0C
|
||||
|
||||
/* mul @ r1 = r2 * r3 */
|
||||
#define FINSH_OP_MUL_BYTE 0x0D
|
||||
#define FINSH_OP_MUL_WORD 0x0E
|
||||
#define FINSH_OP_MUL_DWORD 0x0F
|
||||
|
||||
/* and @ r1 = r2 & r3 */
|
||||
#define FINSH_OP_AND_BYTE 0x10
|
||||
#define FINSH_OP_AND_WORD 0x11
|
||||
#define FINSH_OP_AND_DWORD 0x12
|
||||
|
||||
/* or @ r1 = r2 | r3 */
|
||||
#define FINSH_OP_OR_BYTE 0x13
|
||||
#define FINSH_OP_OR_WORD 0x14
|
||||
#define FINSH_OP_OR_DWORD 0x15
|
||||
|
||||
/* xor @ r1 = r2 ^ r3 */
|
||||
#define FINSH_OP_XOR_BYTE 0x16
|
||||
#define FINSH_OP_XOR_WORD 0x17
|
||||
#define FINSH_OP_XOR_DWORD 0x18
|
||||
|
||||
/* bw @ r1 = ~r2 */
|
||||
#define FINSH_OP_BITWISE_BYTE 0x19
|
||||
#define FINSH_OP_BITWISE_WORD 0x1A
|
||||
#define FINSH_OP_BITWISE_DWORD 0x1B
|
||||
|
||||
/* shl @ r1 = r2 << r3 */
|
||||
#define FINSH_OP_SHL_BYTE 0x1C
|
||||
#define FINSH_OP_SHL_WORD 0x1D
|
||||
#define FINSH_OP_SHL_DWORD 0x1E
|
||||
|
||||
/* shr @ r1 = r2 >> r3 */
|
||||
#define FINSH_OP_SHR_BYTE 0x1F
|
||||
#define FINSH_OP_SHR_WORD 0x20
|
||||
#define FINSH_OP_SHR_DWORD 0x21
|
||||
|
||||
/* ld @ r1 = [r2] */
|
||||
#define FINSH_OP_LD_BYTE 0x22
|
||||
#define FINSH_OP_LD_WORD 0x23
|
||||
#define FINSH_OP_LD_DWORD 0x24
|
||||
|
||||
#define FINSH_OP_LD_VALUE_BYTE 0x25
|
||||
#define FINSH_OP_LD_VALUE_WORD 0x26
|
||||
#define FINSH_OP_LD_VALUE_DWORD 0x27
|
||||
|
||||
/* st @ [r2] = r1 */
|
||||
#define FINSH_OP_ST_BYTE 0x28
|
||||
#define FINSH_OP_ST_WORD 0x29
|
||||
#define FINSH_OP_ST_DWORD 0x2A
|
||||
|
||||
/* pop */
|
||||
#define FINSH_OP_POP 0x2B
|
||||
|
||||
/* call r1 @ [r1](stack) */
|
||||
#define FINSH_OP_SYSCALL 0x2C
|
||||
|
||||
/* load value from stack */
|
||||
#define FINSH_OP_LD_VALUE_BYTE_STACK 0x2D
|
||||
#define FINSH_OP_LD_VALUE_WORD_STACK 0x2E
|
||||
#define FINSH_OP_LD_VALUE_DWORD_STACK 0x2F
|
||||
|
||||
/* halt */
|
||||
#define FINSH_OP_HALT 0xFF
|
||||
|
||||
typedef void (*op_func)();
|
||||
extern const op_func op_table[];
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* script parser for finsh shell.
|
||||
*
|
||||
* COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team
|
||||
*
|
||||
* This file is part of RT-Thread (http://www.rt-thread.org)
|
||||
* Maintainer: bernard.xiong <bernard.xiong at gmail.com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2010-03-22 Bernard first version
|
||||
*/
|
||||
#ifndef __FINSH_PARSER_H__
|
||||
#define __FINSH_PARSER_H__
|
||||
|
||||
#include <finsh.h>
|
||||
|
||||
int finsh_parser_init(struct finsh_parser* self);
|
||||
void finsh_parser_run(struct finsh_parser* self, const u_char* string);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,603 @@
|
||||
/*
|
||||
* token lex for finsh shell.
|
||||
*
|
||||
* COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team
|
||||
*
|
||||
* This file is part of RT-Thread (http://www.rt-thread.org)
|
||||
* Maintainer: bernard.xiong <bernard.xiong at gmail.com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2010-03-22 Bernard first version
|
||||
* 2013-04-03 Bernard strip more characters.
|
||||
*/
|
||||
#include <finsh.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "finsh_token.h"
|
||||
#include "finsh_error.h"
|
||||
|
||||
#define is_alpha(ch) ((ch | 0x20) - 'a') < 26u
|
||||
#define is_digit(ch) ((ch) >= '0' && (ch) <= '9')
|
||||
#define is_separator(ch) !(((ch) >= 'a' && (ch) <= 'z') \
|
||||
|| ((ch) >= 'A' && (ch) <= 'Z') || ((ch) >= '0' && (ch) <= '9') || ((ch) == '_'))
|
||||
#define is_eof(self) (self)->eof
|
||||
|
||||
struct name_table
|
||||
{
|
||||
char* name;
|
||||
enum finsh_token_type type;
|
||||
};
|
||||
|
||||
/* keyword */
|
||||
static const struct name_table finsh_name_table[] =
|
||||
{
|
||||
{"void", finsh_token_type_void},
|
||||
{"char", finsh_token_type_char},
|
||||
{"short", finsh_token_type_short},
|
||||
{"int", finsh_token_type_int},
|
||||
{"long", finsh_token_type_long},
|
||||
{"unsigned", finsh_token_type_unsigned},
|
||||
|
||||
{"NULL", finsh_token_type_value_null},
|
||||
{"null", finsh_token_type_value_null}
|
||||
};
|
||||
|
||||
static char token_next_char(struct finsh_token* self);
|
||||
static void token_prev_char(struct finsh_token* self);
|
||||
static long token_spec_number(char* string, int length, int b);
|
||||
static void token_run(struct finsh_token* self);
|
||||
static int token_match_name(struct finsh_token* self, const char* str);
|
||||
static void token_proc_number(struct finsh_token* self);
|
||||
static u_char* token_proc_string(struct finsh_token* self);
|
||||
static void token_trim_space(struct finsh_token* self);
|
||||
static char token_proc_char(struct finsh_token* self);
|
||||
static int token_proc_escape(struct finsh_token* self);
|
||||
|
||||
void finsh_token_init(struct finsh_token* self, u_char* line)
|
||||
{
|
||||
memset(self, 0, sizeof(struct finsh_token));
|
||||
|
||||
self->line = line;
|
||||
}
|
||||
|
||||
enum finsh_token_type finsh_token_token(struct finsh_token* self)
|
||||
{
|
||||
if ( self->replay ) self->replay = 0;
|
||||
else token_run(self);
|
||||
|
||||
return (enum finsh_token_type)self->current_token;
|
||||
}
|
||||
|
||||
void finsh_token_get_token(struct finsh_token* self, u_char* token)
|
||||
{
|
||||
strncpy((char*)token, (char*)self->string, FINSH_NAME_MAX);
|
||||
}
|
||||
|
||||
int token_get_string(struct finsh_token* self, u_char* str)
|
||||
{
|
||||
unsigned char *p=str;
|
||||
char ch;
|
||||
|
||||
ch = token_next_char(self);
|
||||
if (is_eof(self)) return -1;
|
||||
|
||||
str[0] = '\0';
|
||||
|
||||
if ( is_digit(ch) )/*the first character of identifier is not a digit.*/
|
||||
{
|
||||
token_prev_char(self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (!is_separator(ch) && !is_eof(self))
|
||||
{
|
||||
*p++ = ch;
|
||||
|
||||
ch = token_next_char(self);
|
||||
}
|
||||
self->eof = 0;
|
||||
|
||||
token_prev_char(self);
|
||||
*p = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
get next character.
|
||||
*/
|
||||
static char token_next_char(struct finsh_token* self)
|
||||
{
|
||||
if (self->eof) return '\0';
|
||||
|
||||
if (self->position == (int)strlen((char*)self->line) || self->line[self->position] =='\n')
|
||||
{
|
||||
self->eof = 1;
|
||||
self->position = 0;
|
||||
return '\0';
|
||||
}
|
||||
|
||||
return self->line[self->position++];
|
||||
}
|
||||
|
||||
static void token_prev_char(struct finsh_token* self)
|
||||
{
|
||||
if ( self->eof ) return;
|
||||
|
||||
if ( self->position == 0 ) return;
|
||||
else self->position--;
|
||||
}
|
||||
|
||||
static void token_run(struct finsh_token* self)
|
||||
{
|
||||
char ch;
|
||||
|
||||
token_trim_space(self); /* first trim space and tab. */
|
||||
token_get_string(self, &(self->string[0]));
|
||||
|
||||
if ( is_eof(self) ) /*if it is eof, break;*/
|
||||
{
|
||||
self->current_token = finsh_token_type_eof;
|
||||
return ;
|
||||
}
|
||||
|
||||
if (self->string[0] != '\0') /*It is a key word or a identifier.*/
|
||||
{
|
||||
if ( !token_match_name(self, (char*)self->string) )
|
||||
{
|
||||
self->current_token = finsh_token_type_identifier;
|
||||
}
|
||||
}
|
||||
else/*It is a operator character.*/
|
||||
{
|
||||
ch = token_next_char(self);
|
||||
|
||||
switch ( ch )
|
||||
{
|
||||
case '(':
|
||||
self->current_token = finsh_token_type_left_paren;
|
||||
break;
|
||||
|
||||
case ')':
|
||||
self->current_token = finsh_token_type_right_paren;
|
||||
break;
|
||||
|
||||
case ',':
|
||||
self->current_token = finsh_token_type_comma;
|
||||
break;
|
||||
|
||||
case ';':
|
||||
self->current_token = finsh_token_type_semicolon;
|
||||
break;
|
||||
|
||||
case '&':
|
||||
self->current_token = finsh_token_type_and;
|
||||
break;
|
||||
|
||||
case '*':
|
||||
self->current_token = finsh_token_type_mul;
|
||||
break;
|
||||
|
||||
case '+':
|
||||
ch = token_next_char(self);
|
||||
|
||||
if ( ch == '+' )
|
||||
{
|
||||
self->current_token = finsh_token_type_inc;
|
||||
}
|
||||
else
|
||||
{
|
||||
token_prev_char(self);
|
||||
self->current_token = finsh_token_type_add;
|
||||
}
|
||||
break;
|
||||
|
||||
case '-':
|
||||
ch = token_next_char(self);
|
||||
|
||||
if ( ch == '-' )
|
||||
{
|
||||
self->current_token = finsh_token_type_dec;
|
||||
}
|
||||
else
|
||||
{
|
||||
token_prev_char(self);
|
||||
self->current_token = finsh_token_type_sub;
|
||||
}
|
||||
break;
|
||||
|
||||
case '/':
|
||||
ch = token_next_char(self);
|
||||
if (ch == '/')
|
||||
{
|
||||
/* line comments, set to end of file */
|
||||
self->current_token = finsh_token_type_eof;
|
||||
}
|
||||
else
|
||||
{
|
||||
token_prev_char(self);
|
||||
self->current_token = finsh_token_type_div;
|
||||
}
|
||||
break;
|
||||
|
||||
case '<':
|
||||
ch = token_next_char(self);
|
||||
|
||||
if ( ch == '<' )
|
||||
{
|
||||
self->current_token = finsh_token_type_shl;
|
||||
}
|
||||
else
|
||||
{
|
||||
token_prev_char(self);
|
||||
self->current_token = finsh_token_type_bad;
|
||||
}
|
||||
break;
|
||||
|
||||
case '>':
|
||||
ch = token_next_char(self);
|
||||
|
||||
if ( ch == '>' )
|
||||
{
|
||||
self->current_token = finsh_token_type_shr;
|
||||
}
|
||||
else
|
||||
{
|
||||
token_prev_char(self);
|
||||
self->current_token = finsh_token_type_bad;
|
||||
}
|
||||
break;
|
||||
|
||||
case '|':
|
||||
self->current_token = finsh_token_type_or;
|
||||
break;
|
||||
|
||||
case '%':
|
||||
self->current_token = finsh_token_type_mod;
|
||||
break;
|
||||
|
||||
case '~':
|
||||
self->current_token = finsh_token_type_bitwise;
|
||||
break;
|
||||
|
||||
case '^':
|
||||
self->current_token = finsh_token_type_xor;
|
||||
break;
|
||||
|
||||
case '=':
|
||||
self->current_token = finsh_token_type_assign;
|
||||
break;
|
||||
|
||||
case '\'':
|
||||
self->value.char_value = token_proc_char(self);
|
||||
self->current_token = finsh_token_type_value_char;
|
||||
break;
|
||||
|
||||
case '"':
|
||||
token_proc_string(self);
|
||||
self->current_token = finsh_token_type_value_string;
|
||||
break;
|
||||
|
||||
default:
|
||||
if ( is_digit(ch) )
|
||||
{
|
||||
token_prev_char(self);
|
||||
token_proc_number(self);
|
||||
break;
|
||||
}
|
||||
|
||||
finsh_error_set(FINSH_ERROR_UNKNOWN_TOKEN);
|
||||
self->current_token = finsh_token_type_bad;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int token_match_name(struct finsh_token* self, const char* str)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(finsh_name_table)/sizeof(struct name_table); i++)
|
||||
{
|
||||
if ( strcmp(finsh_name_table[i].name, str)==0 )
|
||||
{
|
||||
self->current_token = finsh_name_table[i].type;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void token_trim_space(struct finsh_token* self)
|
||||
{
|
||||
char ch;
|
||||
while ( (ch = token_next_char(self)) ==' ' ||
|
||||
ch == '\t' ||
|
||||
ch == '\r');
|
||||
|
||||
token_prev_char(self);
|
||||
}
|
||||
|
||||
static char token_proc_char(struct finsh_token* self)
|
||||
{
|
||||
char ch;
|
||||
char buf[4], *p;
|
||||
|
||||
p = buf;
|
||||
ch = token_next_char(self);
|
||||
|
||||
if ( ch == '\\' )
|
||||
{
|
||||
ch = token_next_char(self);
|
||||
switch ( ch )
|
||||
{
|
||||
case 'n': ch = '\n'; break;
|
||||
case 't': ch = '\t'; break;
|
||||
case 'v': ch = '\v'; break;
|
||||
case 'b': ch = '\b'; break;
|
||||
case 'r': ch = '\r'; break;
|
||||
case '\\': ch = '\\'; break;
|
||||
case '\'': ch = '\''; break;
|
||||
default :
|
||||
while ( is_digit(ch) )/*for '\113' char*/
|
||||
{
|
||||
ch = token_next_char(self);
|
||||
*p++ = ch;
|
||||
}
|
||||
|
||||
token_prev_char(self);
|
||||
*p = '\0';
|
||||
ch = atoi(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( token_next_char(self) != '\'' )
|
||||
{
|
||||
token_prev_char(self);
|
||||
finsh_error_set(FINSH_ERROR_EXPECT_CHAR);
|
||||
return ch;
|
||||
}
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
static u_char* token_proc_string(struct finsh_token* self)
|
||||
{
|
||||
u_char* p;
|
||||
|
||||
for ( p = &self->string[0]; p - &(self->string[0]) < FINSH_STRING_MAX; )
|
||||
{
|
||||
char ch = token_next_char(self);
|
||||
|
||||
if ( is_eof(self) )
|
||||
{
|
||||
finsh_error_set(FINSH_ERROR_UNEXPECT_END);
|
||||
return NULL;;
|
||||
}
|
||||
if ( ch == '\\' )
|
||||
{
|
||||
ch = token_proc_escape(self);
|
||||
}
|
||||
else if ( ch == '"' )/*end of string.*/
|
||||
{
|
||||
*p = '\0';
|
||||
return self->string;
|
||||
}
|
||||
|
||||
*p++ = ch;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int token_proc_escape(struct finsh_token* self)
|
||||
{
|
||||
char ch;
|
||||
int result=0;
|
||||
|
||||
ch = token_next_char(self);
|
||||
switch (ch)
|
||||
{
|
||||
case 'n':
|
||||
result = '\n';
|
||||
break;
|
||||
case 't':
|
||||
result = '\t';
|
||||
break;
|
||||
case 'v':
|
||||
result = '\v';
|
||||
break;
|
||||
case 'b':
|
||||
result = '\b';
|
||||
break;
|
||||
case 'r':
|
||||
result = '\r';
|
||||
break;
|
||||
case 'f':
|
||||
result = '\f';
|
||||
break;
|
||||
case 'a':
|
||||
result = '\007';
|
||||
break;
|
||||
case 'x':
|
||||
result = 0;
|
||||
ch = token_next_char(self);
|
||||
while ( (ch - '0')<16u )
|
||||
{
|
||||
result = result*16 + ch - '0';
|
||||
ch = token_next_char(self);
|
||||
}
|
||||
token_prev_char(self);
|
||||
break;
|
||||
default:
|
||||
if ( (ch - '0') < 8u)
|
||||
{
|
||||
result = 0;
|
||||
while ( (ch - '0') < 8u )
|
||||
{
|
||||
result = result*8 + ch - '0';
|
||||
ch = token_next_char(self);
|
||||
}
|
||||
|
||||
token_prev_char(self);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
(0|0x|0X|0b|0B)number+(l|L)
|
||||
*/
|
||||
static void token_proc_number(struct finsh_token* self)
|
||||
{
|
||||
char ch;
|
||||
char *p, buf[128];
|
||||
long value;
|
||||
|
||||
value = 0;
|
||||
p = buf;
|
||||
|
||||
ch = token_next_char(self);
|
||||
if ( ch == '0' )
|
||||
{
|
||||
int b;
|
||||
ch = token_next_char(self);
|
||||
if ( ch == 'x' || ch == 'X' )/*it's a hex number*/
|
||||
{
|
||||
b = 16;
|
||||
ch = token_next_char(self);
|
||||
while ( is_digit(ch) || is_alpha(ch) )
|
||||
{
|
||||
*p++ = ch;
|
||||
ch = token_next_char(self);
|
||||
}
|
||||
|
||||
*p = '\0';
|
||||
}
|
||||
else if ( ch == 'b' || ch == 'B' )
|
||||
{
|
||||
b = 2;
|
||||
ch = token_next_char(self);
|
||||
while ( (ch=='0')||(ch=='1') )
|
||||
{
|
||||
*p++ = ch;
|
||||
ch = token_next_char(self);
|
||||
}
|
||||
|
||||
*p = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
b = 8;
|
||||
while ( is_digit(ch) )
|
||||
{
|
||||
*p++ = ch;
|
||||
ch = token_next_char(self);
|
||||
}
|
||||
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
self->value.int_value = token_spec_number(buf, strlen(buf), b);
|
||||
self->current_token = finsh_token_type_value_int;
|
||||
}
|
||||
else
|
||||
{
|
||||
while ( is_digit(ch) )
|
||||
{
|
||||
value = value*10 + ( ch - '0' );
|
||||
ch = token_next_char(self);
|
||||
}
|
||||
|
||||
self->value.int_value = value;
|
||||
self->current_token = finsh_token_type_value_int;
|
||||
}
|
||||
|
||||
switch ( ch )
|
||||
{
|
||||
case 'l':
|
||||
case 'L':
|
||||
self->current_token = finsh_token_type_value_long;
|
||||
break;
|
||||
|
||||
default:
|
||||
token_prev_char(self);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*use 64 bit number*/
|
||||
#define BN_SIZE 2
|
||||
|
||||
static long token_spec_number(char* string, int length, int b)
|
||||
{
|
||||
char* p;
|
||||
int t;
|
||||
int i, j, shift=1;
|
||||
unsigned int bn[BN_SIZE], v;
|
||||
long d;
|
||||
|
||||
p = string;
|
||||
i = 0;
|
||||
|
||||
switch ( b )
|
||||
{
|
||||
case 16: shift = 4;
|
||||
break;
|
||||
case 8: shift = 3;
|
||||
break;
|
||||
case 2: shift = 1;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
for ( j=0; j<BN_SIZE ; j++) bn[j] = 0;
|
||||
|
||||
while ( i<length )
|
||||
{
|
||||
t = *p++;
|
||||
if ( t>='a' && t <='f' )
|
||||
{
|
||||
t = t - 'a' +10;
|
||||
}
|
||||
else if ( t >='A' && t <='F' )
|
||||
{
|
||||
t = t - 'A' +10;
|
||||
}
|
||||
else t = t - '0';
|
||||
|
||||
for ( j=0; j<BN_SIZE ; j++)
|
||||
{
|
||||
v = bn[j];
|
||||
bn[j] = (v<<shift) | t;
|
||||
t = v >> (32 - shift);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
d = (long)bn[0];
|
||||
|
||||
return d;
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* token lex for finsh shell.
|
||||
*
|
||||
* COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team
|
||||
*
|
||||
* This file is part of RT-Thread (http://www.rt-thread.org)
|
||||
* Maintainer: bernard.xiong <bernard.xiong at gmail.com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2010-03-22 Bernard first version
|
||||
*/
|
||||
#ifndef __FINSH_TOKEN_H__
|
||||
#define __FINSH_TOKEN_H__
|
||||
|
||||
#include <finsh.h>
|
||||
|
||||
enum finsh_token_type
|
||||
{
|
||||
finsh_token_type_left_paren = 1, /* ( */
|
||||
finsh_token_type_right_paren , /* ) */
|
||||
finsh_token_type_comma , /* , */
|
||||
finsh_token_type_semicolon , /* ; */
|
||||
finsh_token_type_mul , /* * */
|
||||
finsh_token_type_add , /* + */
|
||||
finsh_token_type_inc , /* ++ */
|
||||
finsh_token_type_sub , /* - */
|
||||
finsh_token_type_dec , /* -- */
|
||||
finsh_token_type_div , /* / */
|
||||
finsh_token_type_mod , /* % */
|
||||
finsh_token_type_assign , /* = */
|
||||
finsh_token_type_and, /* & */
|
||||
finsh_token_type_or, /* | */
|
||||
finsh_token_type_xor, /* ^ */
|
||||
finsh_token_type_bitwise, /* ~ */
|
||||
finsh_token_type_shl, /* << */
|
||||
finsh_token_type_shr, /* >> */
|
||||
finsh_token_type_comments, /* // */
|
||||
/*-- data type --*/
|
||||
finsh_token_type_void, /* void */
|
||||
finsh_token_type_char, /* char */
|
||||
finsh_token_type_short, /* short */
|
||||
finsh_token_type_int, /* int */
|
||||
finsh_token_type_long, /* long */
|
||||
finsh_token_type_unsigned, /* unsigned */
|
||||
/* data value type */
|
||||
finsh_token_type_value_char, /* v:char */
|
||||
finsh_token_type_value_int, /* v:int */
|
||||
finsh_token_type_value_long, /* v:long */
|
||||
finsh_token_type_value_string, /* v:string */
|
||||
finsh_token_type_value_null, /* NULL */
|
||||
/*-- others --*/
|
||||
finsh_token_type_identifier, /* ID */
|
||||
finsh_token_type_bad, /* bad token */
|
||||
finsh_token_type_eof
|
||||
};
|
||||
|
||||
#define finsh_token_position(self) (self)->position
|
||||
#define finsh_token_replay(self) (self)->replay = 1
|
||||
|
||||
void finsh_token_init(struct finsh_token* self, u_char* script);
|
||||
|
||||
enum finsh_token_type finsh_token_token(struct finsh_token* self);
|
||||
void finsh_token_get_token(struct finsh_token* self, u_char* token);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Variable implementation in finsh shell.
|
||||
*
|
||||
* COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team
|
||||
*
|
||||
* This file is part of RT-Thread (http://www.rt-thread.org)
|
||||
* Maintainer: bernard.xiong <bernard.xiong at gmail.com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2010-03-22 Bernard first version
|
||||
* 2012-04-27 Bernard fixed finsh_var_delete issue which
|
||||
* is found by Grissiom.
|
||||
*/
|
||||
#include <finsh.h>
|
||||
#include "finsh_var.h"
|
||||
|
||||
struct finsh_var global_variable[FINSH_VARIABLE_MAX];
|
||||
struct finsh_sysvar_item* global_sysvar_list;
|
||||
|
||||
int finsh_var_init()
|
||||
{
|
||||
memset(global_variable, 0, sizeof(global_variable));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int finsh_var_insert(const char* name, int type)
|
||||
{
|
||||
int i, empty;
|
||||
|
||||
empty = -1;
|
||||
for (i = 0; i < FINSH_VARIABLE_MAX; i ++)
|
||||
{
|
||||
/* there is a same name variable exist. */
|
||||
if (strncmp(global_variable[i].name, name, FINSH_NAME_MAX) == 0)
|
||||
return -1;
|
||||
|
||||
if (global_variable[i].type == finsh_type_unknown && empty == -1)
|
||||
{
|
||||
empty = i;
|
||||
}
|
||||
}
|
||||
|
||||
/* there is no empty entry */
|
||||
if (empty == -1) return -1;
|
||||
|
||||
/* insert entry */
|
||||
strncpy(global_variable[empty].name, name, FINSH_NAME_MAX);
|
||||
global_variable[empty].type = type;
|
||||
|
||||
/* return the offset */
|
||||
return empty;
|
||||
}
|
||||
|
||||
int finsh_var_delete(const char* name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < FINSH_VARIABLE_MAX; i ++)
|
||||
{
|
||||
if (strncmp(global_variable[i].name, name, FINSH_NAME_MAX) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
/* can't find variable */
|
||||
if (i == FINSH_VARIABLE_MAX) return -1;
|
||||
|
||||
memset(&global_variable[i], 0, sizeof(struct finsh_var));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct finsh_var* finsh_var_lookup(const char* name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < FINSH_VARIABLE_MAX; i ++)
|
||||
{
|
||||
if (strncmp(global_variable[i].name, name, FINSH_NAME_MAX) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
/* can't find variable */
|
||||
if (i == FINSH_VARIABLE_MAX) return NULL;
|
||||
|
||||
return &global_variable[i];
|
||||
}
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
void finsh_sysvar_append(const char* name, u_char type, void* var_addr)
|
||||
{
|
||||
/* create a sysvar */
|
||||
struct finsh_sysvar_item* item;
|
||||
|
||||
item = (struct finsh_sysvar_item*) rt_malloc (sizeof(struct finsh_sysvar_item));
|
||||
if (item != NULL)
|
||||
{
|
||||
item->next = NULL;
|
||||
item->sysvar.name = rt_strdup(name);
|
||||
item->sysvar.type = type;
|
||||
item->sysvar.var = var_addr;
|
||||
|
||||
if (global_sysvar_list == NULL)
|
||||
{
|
||||
global_sysvar_list = item;
|
||||
}
|
||||
else
|
||||
{
|
||||
item->next = global_sysvar_list;
|
||||
global_sysvar_list = item;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
struct finsh_sysvar* finsh_sysvar_lookup(const char* name)
|
||||
{
|
||||
struct finsh_sysvar* index;
|
||||
struct finsh_sysvar_item* item;
|
||||
|
||||
for (index = _sysvar_table_begin;
|
||||
index < _sysvar_table_end;
|
||||
FINSH_NEXT_SYSVAR(index))
|
||||
{
|
||||
if (strcmp(index->name, name) == 0)
|
||||
return index;
|
||||
}
|
||||
|
||||
/* find in sysvar list */
|
||||
item = global_sysvar_list;
|
||||
while (item != NULL)
|
||||
{
|
||||
if (strncmp(item->sysvar.name, name, strlen(name)) == 0)
|
||||
{
|
||||
return &(item->sysvar);
|
||||
}
|
||||
|
||||
/* move to next item */
|
||||
item = item->next;
|
||||
}
|
||||
|
||||
/* can't find variable */
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Variable implementation in finsh shell.
|
||||
*
|
||||
* COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team
|
||||
*
|
||||
* This file is part of RT-Thread (http://www.rt-thread.org)
|
||||
* Maintainer: bernard.xiong <bernard.xiong at gmail.com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2010-03-22 Bernard first version
|
||||
*/
|
||||
#ifndef __FINSH_VAR_H__
|
||||
#define __FINSH_VAR_H__
|
||||
|
||||
#include <finsh.h>
|
||||
|
||||
/*
|
||||
* The variable in finsh is put in data segment as a global variable.
|
||||
* The 'finsh_var' structure presents the structure of variable in data segment.
|
||||
*/
|
||||
struct finsh_var
|
||||
{
|
||||
char name[FINSH_NAME_MAX + 1]; /* the name of variable */
|
||||
|
||||
u_char type; /* the type of variable */
|
||||
|
||||
/* variable value */
|
||||
union {
|
||||
char char_value;
|
||||
short short_value;
|
||||
int int_value;
|
||||
long long_value;
|
||||
void* ptr;
|
||||
}value;
|
||||
};
|
||||
extern struct finsh_var global_variable[];
|
||||
|
||||
int finsh_var_init(void);
|
||||
int finsh_var_insert(const char* name, int type);
|
||||
int finsh_var_delete(const char* name);
|
||||
struct finsh_var* finsh_var_lookup(const char* name);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,404 @@
|
||||
/*
|
||||
* Virtual machine of finsh shell.
|
||||
*
|
||||
* COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team
|
||||
*
|
||||
* This file is part of RT-Thread (http://www.rt-thread.org)
|
||||
* Maintainer: bernard.xiong <bernard.xiong at gmail.com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2010-03-22 Bernard first version
|
||||
*/
|
||||
#include <finsh.h>
|
||||
|
||||
#include "finsh_vm.h"
|
||||
#include "finsh_ops.h"
|
||||
#include "finsh_var.h"
|
||||
|
||||
/* stack */
|
||||
union finsh_value finsh_vm_stack[FINSH_STACK_MAX];
|
||||
/* text segment */
|
||||
u_char text_segment[FINSH_TEXT_MAX];
|
||||
|
||||
union finsh_value* finsh_sp; /* stack pointer */
|
||||
u_char* finsh_pc; /* PC */
|
||||
|
||||
/* syscall list, for dynamic system call register */
|
||||
struct finsh_syscall_item* global_syscall_list = NULL;
|
||||
|
||||
// #define FINSH_VM_DISASSEMBLE
|
||||
void finsh_vm_run()
|
||||
{
|
||||
u_char op;
|
||||
|
||||
/* if you want to disassemble the byte code, please define FINSH_VM_DISASSEMBLE */
|
||||
#ifdef FINSH_VM_DISASSEMBLE
|
||||
void finsh_disassemble();
|
||||
finsh_disassemble();
|
||||
#endif
|
||||
|
||||
/* set sp(stack pointer) to the beginning of stack */
|
||||
finsh_sp = &finsh_vm_stack[0];
|
||||
|
||||
/* set pc to the beginning of text segment */
|
||||
finsh_pc = &text_segment[0];
|
||||
|
||||
while ((finsh_pc - &text_segment[0] >= 0) &&
|
||||
(finsh_pc - &text_segment[0] < FINSH_TEXT_MAX))
|
||||
{
|
||||
/* get op */
|
||||
op = *finsh_pc++;
|
||||
|
||||
/* call op function */
|
||||
op_table[op]();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
void finsh_syscall_append(const char* name, syscall_func func)
|
||||
{
|
||||
/* create the syscall */
|
||||
struct finsh_syscall_item* item;
|
||||
|
||||
item = (struct finsh_syscall_item*)rt_malloc(sizeof(struct finsh_syscall_item));
|
||||
if (item != RT_NULL)
|
||||
{
|
||||
item->next = NULL;
|
||||
item->syscall.name = rt_strdup(name);
|
||||
item->syscall.func = func;
|
||||
|
||||
if (global_syscall_list == NULL)
|
||||
{
|
||||
global_syscall_list = item;
|
||||
}
|
||||
else
|
||||
{
|
||||
item->next = global_syscall_list;
|
||||
global_syscall_list = item;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) || (defined(__GNUC__) && defined(__x86_64__))
|
||||
struct finsh_syscall* finsh_syscall_next(struct finsh_syscall* call)
|
||||
{
|
||||
unsigned int *ptr;
|
||||
ptr = (unsigned int*) (call + 1);
|
||||
while ((*ptr == 0) && ((unsigned int*)ptr < (unsigned int*) _syscall_table_end))
|
||||
ptr ++;
|
||||
|
||||
return (struct finsh_syscall*)ptr;
|
||||
}
|
||||
|
||||
struct finsh_sysvar* finsh_sysvar_next(struct finsh_sysvar* call)
|
||||
{
|
||||
unsigned int *ptr;
|
||||
ptr = (unsigned int*) (call + 1);
|
||||
while ((*ptr == 0) && ((unsigned int*)ptr < (unsigned int*) _sysvar_table_end))
|
||||
ptr ++;
|
||||
|
||||
return (struct finsh_sysvar*)ptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct finsh_syscall* finsh_syscall_lookup(const char* name)
|
||||
{
|
||||
struct finsh_syscall* index;
|
||||
struct finsh_syscall_item* item;
|
||||
|
||||
for (index = _syscall_table_begin; index < _syscall_table_end; FINSH_NEXT_SYSCALL(index))
|
||||
{
|
||||
if (strcmp(index->name, name) == 0)
|
||||
return index;
|
||||
}
|
||||
|
||||
/* find on syscall list */
|
||||
item = global_syscall_list;
|
||||
while (item != NULL)
|
||||
{
|
||||
if (strncmp(item->syscall.name, name, strlen(name)) == 0)
|
||||
{
|
||||
return &(item->syscall);
|
||||
}
|
||||
|
||||
item = item->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef FINSH_VM_DISASSEMBLE
|
||||
void finsh_disassemble()
|
||||
{
|
||||
u_char *pc, op;
|
||||
|
||||
pc = &text_segment[0];
|
||||
while (*pc != 0)
|
||||
{
|
||||
op = *pc;
|
||||
switch (op)
|
||||
{
|
||||
case FINSH_OP_ADD_BYTE:
|
||||
pc ++;
|
||||
rt_kprintf("addb\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_SUB_BYTE:
|
||||
pc ++;
|
||||
rt_kprintf("subb\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_DIV_BYTE:
|
||||
pc ++;
|
||||
rt_kprintf("divb\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_MOD_BYTE:
|
||||
pc ++;
|
||||
rt_kprintf("modb\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_MUL_BYTE:
|
||||
pc ++;
|
||||
rt_kprintf("mulb\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_AND_BYTE:
|
||||
pc ++;
|
||||
rt_kprintf("andb\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_OR_BYTE:
|
||||
pc ++;
|
||||
rt_kprintf("orb\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_XOR_BYTE:
|
||||
pc ++;
|
||||
rt_kprintf("xorb\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_BITWISE_BYTE:
|
||||
pc ++;
|
||||
rt_kprintf("bwb\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_SHL_BYTE:
|
||||
pc ++;
|
||||
rt_kprintf("shlb\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_SHR_BYTE:
|
||||
pc ++;
|
||||
rt_kprintf("shrb\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_LD_BYTE:
|
||||
pc ++;
|
||||
rt_kprintf("ldb %d\n", *pc++);
|
||||
break;
|
||||
|
||||
case FINSH_OP_LD_VALUE_BYTE:
|
||||
pc ++;
|
||||
rt_kprintf("ldb [0x%x]\n", FINSH_GET32(pc));
|
||||
pc += 4;
|
||||
break;
|
||||
|
||||
case FINSH_OP_ST_BYTE:
|
||||
pc ++;
|
||||
rt_kprintf("stb\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_ADD_WORD:
|
||||
pc ++;
|
||||
rt_kprintf("addw\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_SUB_WORD:
|
||||
pc ++;
|
||||
rt_kprintf("subw\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_DIV_WORD:
|
||||
pc ++;
|
||||
rt_kprintf("divw\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_MOD_WORD:
|
||||
pc ++;
|
||||
rt_kprintf("modw\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_MUL_WORD:
|
||||
pc ++;
|
||||
rt_kprintf("mulw\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_AND_WORD:
|
||||
pc ++;
|
||||
rt_kprintf("andw\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_OR_WORD:
|
||||
pc ++;
|
||||
rt_kprintf("orw\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_XOR_WORD:
|
||||
pc ++;
|
||||
rt_kprintf("xorw\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_BITWISE_WORD:
|
||||
pc ++;
|
||||
rt_kprintf("bww\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_SHL_WORD:
|
||||
pc ++;
|
||||
rt_kprintf("shlw\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_SHR_WORD:
|
||||
pc ++;
|
||||
rt_kprintf("shrw\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_LD_WORD:
|
||||
pc ++;
|
||||
rt_kprintf("ldw %d\n", FINSH_GET16(pc));
|
||||
pc += 2;
|
||||
break;
|
||||
|
||||
case FINSH_OP_LD_VALUE_WORD:
|
||||
pc ++;
|
||||
rt_kprintf("ldw [0x%x]\n", FINSH_GET32(pc));
|
||||
pc += 4;
|
||||
break;
|
||||
|
||||
case FINSH_OP_ST_WORD:
|
||||
pc ++;
|
||||
rt_kprintf("stw\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_ADD_DWORD:
|
||||
pc ++;
|
||||
rt_kprintf("addd\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_SUB_DWORD:
|
||||
pc ++;
|
||||
rt_kprintf("subd\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_DIV_DWORD:
|
||||
pc ++;
|
||||
rt_kprintf("divd\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_MOD_DWORD:
|
||||
pc ++;
|
||||
rt_kprintf("modd\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_MUL_DWORD:
|
||||
pc ++;
|
||||
rt_kprintf("muld\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_AND_DWORD:
|
||||
pc ++;
|
||||
rt_kprintf("andd\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_OR_DWORD:
|
||||
pc ++;
|
||||
rt_kprintf("ord\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_XOR_DWORD:
|
||||
pc ++;
|
||||
rt_kprintf("xord\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_BITWISE_DWORD:
|
||||
pc ++;
|
||||
rt_kprintf("bwd\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_SHL_DWORD:
|
||||
pc ++;
|
||||
rt_kprintf("shld\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_SHR_DWORD:
|
||||
pc ++;
|
||||
rt_kprintf("shrd\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_LD_DWORD:
|
||||
pc ++;
|
||||
rt_kprintf("ldd 0x%x\n", FINSH_GET32(pc));
|
||||
pc += 4;
|
||||
break;
|
||||
|
||||
case FINSH_OP_LD_VALUE_DWORD:
|
||||
pc ++;
|
||||
rt_kprintf("ldd [0x%x]\n", FINSH_GET32(pc));
|
||||
pc += 4;
|
||||
break;
|
||||
|
||||
case FINSH_OP_ST_DWORD:
|
||||
pc ++;
|
||||
rt_kprintf("std\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_POP:
|
||||
rt_kprintf("pop\n");
|
||||
pc ++;
|
||||
break;
|
||||
|
||||
case FINSH_OP_SYSCALL:
|
||||
pc ++;
|
||||
rt_kprintf("syscall %d\n", *pc++);
|
||||
break;
|
||||
|
||||
case FINSH_OP_LD_VALUE_BYTE_STACK:
|
||||
pc ++;
|
||||
rt_kprintf("ldb [sp]\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_LD_VALUE_WORD_STACK:
|
||||
pc ++;
|
||||
rt_kprintf("ldw [sp]\n");
|
||||
break;
|
||||
|
||||
case FINSH_OP_LD_VALUE_DWORD_STACK:
|
||||
pc ++;
|
||||
rt_kprintf("ldd [sp]\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Virtual machine finsh shell.
|
||||
*
|
||||
* COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team
|
||||
*
|
||||
* This file is part of RT-Thread (http://www.rt-thread.org)
|
||||
* Maintainer: bernard.xiong <bernard.xiong at gmail.com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2010-03-22 Bernard first version
|
||||
*/
|
||||
#ifndef __FINSH_VM_H__
|
||||
#define __FINSH_VM_H__
|
||||
|
||||
#include <finsh.h>
|
||||
|
||||
#include "finsh_var.h"
|
||||
|
||||
union finsh_value {
|
||||
char char_value;
|
||||
short short_value;
|
||||
long long_value;
|
||||
void* ptr;
|
||||
};
|
||||
|
||||
extern union finsh_value* finsh_sp; /* stack pointer */
|
||||
extern u_char* finsh_pc; /* PC */
|
||||
|
||||
/* stack */
|
||||
extern union finsh_value finsh_vm_stack[FINSH_STACK_MAX];
|
||||
/* text segment */
|
||||
extern u_char text_segment[FINSH_TEXT_MAX];
|
||||
|
||||
void finsh_vm_run(void);
|
||||
//void finsh_disassemble(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,547 @@
|
||||
/*
|
||||
* RT-Thread module shell implementation.
|
||||
*
|
||||
* COPYRIGHT (C) 2013, Shanghai Real-Thread Technology Co., Ltd
|
||||
*
|
||||
* This file is part of RT-Thread (http://www.rt-thread.org)
|
||||
* Maintainer: bernard.xiong <bernard.xiong at gmail.com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-03-30 Bernard the first verion for finsh
|
||||
* 2014-01-03 Bernard msh can execute module.
|
||||
*/
|
||||
|
||||
#include "msh.h"
|
||||
#include <finsh.h>
|
||||
#include <shell.h>
|
||||
|
||||
#ifdef RT_USING_DFS
|
||||
#include <dfs_posix.h>
|
||||
#endif
|
||||
|
||||
#define RT_FINSH_ARG_MAX 10
|
||||
typedef int (*cmd_function_t)(int argc, char** argv);
|
||||
|
||||
#ifdef FINSH_USING_MSH
|
||||
#ifdef FINSH_USING_MSH_ONLY
|
||||
rt_bool_t msh_is_used(void)
|
||||
{
|
||||
return RT_TRUE;
|
||||
}
|
||||
#else
|
||||
#ifdef FINSH_USING_MSH_DEFAULT
|
||||
static rt_bool_t __msh_state = RT_TRUE;
|
||||
#else
|
||||
static rt_bool_t __msh_state = RT_FALSE;
|
||||
#endif
|
||||
rt_bool_t msh_is_used(void)
|
||||
{
|
||||
return __msh_state;
|
||||
}
|
||||
|
||||
static int msh_exit(int argc, char** argv)
|
||||
{
|
||||
/* return to finsh shell mode */
|
||||
__msh_state = RT_FALSE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(msh_exit, __cmd_exit, return to RT-Thread shell mode.);
|
||||
|
||||
static int msh_enter(void)
|
||||
{
|
||||
/* enter module shell mode */
|
||||
__msh_state = RT_TRUE;
|
||||
return 0;
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(msh_enter, msh, use module shell);
|
||||
#endif
|
||||
|
||||
int msh_help(int argc, char** argv)
|
||||
{
|
||||
rt_kprintf("RT-Thread shell commands:\n");
|
||||
{
|
||||
struct finsh_syscall *index;
|
||||
|
||||
for (index = _syscall_table_begin;
|
||||
index < _syscall_table_end;
|
||||
FINSH_NEXT_SYSCALL(index))
|
||||
{
|
||||
if (strncmp(index->name, "__cmd_", 6) != 0) continue;
|
||||
#if defined(FINSH_USING_DESCRIPTION) && defined(FINSH_USING_SYMTAB)
|
||||
rt_kprintf("%-16s - %s\n", &index->name[6], index->desc);
|
||||
#else
|
||||
rt_kprintf("%s ", &index->name[6]);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
rt_kprintf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(msh_help, __cmd_help, RT-Thread shell help.);
|
||||
|
||||
static int msh_split(char* cmd, rt_size_t length, char* argv[RT_FINSH_ARG_MAX])
|
||||
{
|
||||
char *ptr;
|
||||
rt_size_t position;
|
||||
rt_size_t argc;
|
||||
|
||||
ptr = cmd;
|
||||
position = 0; argc = 0;
|
||||
|
||||
while (position < length)
|
||||
{
|
||||
/* strip bank and tab */
|
||||
while ((*ptr == ' ' || *ptr == '\t') && position < length)
|
||||
{
|
||||
*ptr = '\0';
|
||||
ptr ++; position ++;
|
||||
}
|
||||
if (position >= length) break;
|
||||
|
||||
/* handle string */
|
||||
if (*ptr == '"')
|
||||
{
|
||||
ptr ++; position ++;
|
||||
argv[argc] = ptr; argc ++;
|
||||
|
||||
/* skip this string */
|
||||
while (*ptr != '"' && position < length)
|
||||
{
|
||||
if (*ptr == '\\')
|
||||
{
|
||||
if (*(ptr + 1) == '"')
|
||||
{
|
||||
ptr ++; position ++;
|
||||
}
|
||||
}
|
||||
ptr ++; position ++;
|
||||
}
|
||||
if (position >= length) break;
|
||||
|
||||
/* skip '"' */
|
||||
*ptr = '\0'; ptr ++; position ++;
|
||||
}
|
||||
else
|
||||
{
|
||||
argv[argc] = ptr;
|
||||
argc ++;
|
||||
while ((*ptr != ' ' && *ptr != '\t') && position < length)
|
||||
{
|
||||
ptr ++; position ++;
|
||||
}
|
||||
if (position >= length) break;
|
||||
}
|
||||
}
|
||||
|
||||
return argc;
|
||||
}
|
||||
|
||||
static cmd_function_t msh_get_cmd(char *cmd, int size)
|
||||
{
|
||||
struct finsh_syscall *index;
|
||||
cmd_function_t cmd_func = RT_NULL;
|
||||
|
||||
for (index = _syscall_table_begin;
|
||||
index < _syscall_table_end;
|
||||
FINSH_NEXT_SYSCALL(index))
|
||||
{
|
||||
if (strncmp(index->name, "__cmd_", 6) != 0) continue;
|
||||
|
||||
if (strncmp(&index->name[6], cmd, size) == 0 &&
|
||||
index->name[6 + size] == '\0')
|
||||
{
|
||||
cmd_func = (cmd_function_t)index->func;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return cmd_func;
|
||||
}
|
||||
|
||||
#if defined(RT_USING_MODULE) && defined(RT_USING_DFS)
|
||||
/* Return 0 on module executed. Other value indicate error.
|
||||
*/
|
||||
int msh_exec_module(const char* cmd_line, int size)
|
||||
{
|
||||
int ret;
|
||||
int fd = -1;
|
||||
char *pg_name;
|
||||
int length, cmd_length = 0;
|
||||
|
||||
if (size == 0)
|
||||
return -RT_ERROR;
|
||||
/* get the length of command0 */
|
||||
while ((cmd_line[cmd_length] != ' ' && cmd_line[cmd_length] != '\t') && cmd_length < size)
|
||||
cmd_length ++;
|
||||
|
||||
/* get name length */
|
||||
length = cmd_length + 32;
|
||||
|
||||
/* allocate program name memory */
|
||||
pg_name = (char*) rt_malloc(length);
|
||||
if (pg_name == RT_NULL)
|
||||
return -RT_ENOMEM;
|
||||
|
||||
/* copy command0 */
|
||||
memcpy(pg_name, cmd_line, cmd_length);
|
||||
pg_name[cmd_length] = '\0';
|
||||
|
||||
if (strstr(pg_name, ".mo") != RT_NULL || strstr(pg_name, ".MO") != RT_NULL)
|
||||
{
|
||||
/* try to open program */
|
||||
fd = open(pg_name, O_RDONLY, 0);
|
||||
|
||||
/* search in /bin path */
|
||||
if (fd < 0)
|
||||
{
|
||||
rt_snprintf(pg_name, length - 1, "/bin/%.*s", cmd_length, cmd_line);
|
||||
fd = open(pg_name, O_RDONLY, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* add .mo and open program */
|
||||
|
||||
/* try to open program */
|
||||
strcat(pg_name, ".mo");
|
||||
fd = open(pg_name, O_RDONLY, 0);
|
||||
|
||||
/* search in /bin path */
|
||||
if (fd < 0)
|
||||
{
|
||||
rt_snprintf(pg_name, length - 1, "/bin/%.*s.mo", cmd_length, cmd_line);
|
||||
fd = open(pg_name, O_RDONLY, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (fd >= 0)
|
||||
{
|
||||
/* found program */
|
||||
close(fd);
|
||||
rt_module_exec_cmd(pg_name, cmd_line, size);
|
||||
ret = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
rt_free(pg_name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int system(const char *command)
|
||||
{
|
||||
return msh_exec_module(command, rt_strlen(command));
|
||||
}
|
||||
#endif
|
||||
|
||||
static int _msh_exec_cmd(char* cmd, rt_size_t length, int *retp)
|
||||
{
|
||||
int argc;
|
||||
int cmd0_size = 0;
|
||||
cmd_function_t cmd_func;
|
||||
char *argv[RT_FINSH_ARG_MAX];
|
||||
|
||||
RT_ASSERT(cmd);
|
||||
RT_ASSERT(retp);
|
||||
|
||||
/* find the size of first command */
|
||||
while ((cmd[cmd0_size] != ' ' && cmd[cmd0_size] != '\t') && cmd0_size < length)
|
||||
cmd0_size ++;
|
||||
if (cmd0_size == 0)
|
||||
return -RT_ERROR;
|
||||
|
||||
cmd_func = msh_get_cmd(cmd, cmd0_size);
|
||||
if (cmd_func == RT_NULL)
|
||||
return -RT_ERROR;
|
||||
|
||||
/* split arguments */
|
||||
memset(argv, 0x00, sizeof(argv));
|
||||
argc = msh_split(cmd, length, argv);
|
||||
if (argc == 0)
|
||||
return -RT_ERROR;
|
||||
|
||||
/* exec this command */
|
||||
*retp = cmd_func(argc, argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int msh_exec(char* cmd, rt_size_t length)
|
||||
{
|
||||
int cmd_ret;
|
||||
|
||||
/* strim the beginning of command */
|
||||
while(*cmd == ' ' || *cmd == '\t')
|
||||
{
|
||||
cmd++;
|
||||
length--;
|
||||
}
|
||||
|
||||
if (length == 0)
|
||||
return 0;
|
||||
|
||||
/* Exec sequence:
|
||||
* 1. built-in command
|
||||
* 2. module(if enabled)
|
||||
* 3. chdir to the directry(if possible)
|
||||
*/
|
||||
if (_msh_exec_cmd(cmd, length, &cmd_ret) == 0)
|
||||
{
|
||||
return cmd_ret;
|
||||
}
|
||||
#ifdef RT_USING_MODULE
|
||||
if (msh_exec_module(cmd, length) == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#ifdef DFS_USING_WORKDIR
|
||||
if (chdir(cmd) == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
/* truncate the cmd at the first space. */
|
||||
{
|
||||
char *tcmd;
|
||||
tcmd = cmd;
|
||||
while(*tcmd != ' ' && *tcmd != '\0')
|
||||
{
|
||||
tcmd++;
|
||||
}
|
||||
*tcmd = '\0';
|
||||
}
|
||||
rt_kprintf("%s: command not found.\n", cmd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int str_common(const char *str1, const char *str2)
|
||||
{
|
||||
const char *str = str1;
|
||||
|
||||
while ((*str != 0) && (*str2 != 0) && (*str == *str2))
|
||||
{
|
||||
str ++;
|
||||
str2 ++;
|
||||
}
|
||||
|
||||
return (str - str1);
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DFS
|
||||
void msh_auto_complete_path(char *path)
|
||||
{
|
||||
DIR* dir = RT_NULL;
|
||||
struct dirent *dirent = RT_NULL;
|
||||
char *full_path, *ptr, *index;
|
||||
|
||||
full_path = (char*)rt_malloc(256);
|
||||
if (full_path == RT_NULL) return; /* out of memory */
|
||||
|
||||
ptr = full_path;
|
||||
if (*path != '/')
|
||||
{
|
||||
getcwd(full_path, 256);
|
||||
if (full_path[rt_strlen(full_path) - 1] != '/')
|
||||
strcat(full_path, "/");
|
||||
}
|
||||
else *full_path = '\0';
|
||||
|
||||
index = RT_NULL; ptr = path;
|
||||
for (;;)
|
||||
{
|
||||
if (*ptr == '/') index = ptr + 1; if (!*ptr) break; ptr ++;
|
||||
}
|
||||
if (index == RT_NULL) index = path;
|
||||
|
||||
if (index != RT_NULL)
|
||||
{
|
||||
char *dest = index;
|
||||
|
||||
/* fill the parent path */
|
||||
ptr = full_path;
|
||||
while (*ptr) ptr ++;
|
||||
|
||||
for (index = path; index != dest;)
|
||||
*ptr++ = *index++;
|
||||
*ptr = '\0';
|
||||
|
||||
dir = opendir(full_path);
|
||||
if (dir == RT_NULL) /* open directory failed! */
|
||||
{
|
||||
rt_free(full_path);
|
||||
return;
|
||||
}
|
||||
|
||||
/* restore the index position */
|
||||
index = dest;
|
||||
}
|
||||
|
||||
/* auto complete the file or directory name */
|
||||
if (*index == '\0') /* display all of files and directories */
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
dirent = readdir(dir);
|
||||
if (dirent == RT_NULL) break;
|
||||
|
||||
rt_kprintf("%s\n", dirent->d_name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int length, min_length;
|
||||
|
||||
min_length = 0;
|
||||
for (;;)
|
||||
{
|
||||
dirent = readdir(dir);
|
||||
if (dirent == RT_NULL) break;
|
||||
|
||||
/* matched the prefix string */
|
||||
if (strncmp(index, dirent->d_name, rt_strlen(index)) == 0)
|
||||
{
|
||||
if (min_length == 0)
|
||||
{
|
||||
min_length = rt_strlen(dirent->d_name);
|
||||
/* save dirent name */
|
||||
strcpy(full_path, dirent->d_name);
|
||||
}
|
||||
|
||||
length = str_common(dirent->d_name, full_path);
|
||||
|
||||
if (length < min_length)
|
||||
{
|
||||
min_length = length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (min_length)
|
||||
{
|
||||
if (min_length < rt_strlen(full_path))
|
||||
{
|
||||
/* list the candidate */
|
||||
rewinddir(dir);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
dirent = readdir(dir);
|
||||
if (dirent == RT_NULL) break;
|
||||
|
||||
if (strncmp(index, dirent->d_name, rt_strlen(index)) == 0)
|
||||
rt_kprintf("%s\n", dirent->d_name);
|
||||
}
|
||||
}
|
||||
|
||||
length = index - path;
|
||||
memcpy(index, full_path, min_length);
|
||||
path[length + min_length] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
rt_free(full_path);
|
||||
}
|
||||
#endif
|
||||
|
||||
void msh_auto_complete(char *prefix)
|
||||
{
|
||||
int length, min_length;
|
||||
const char *name_ptr, *cmd_name;
|
||||
struct finsh_syscall *index;
|
||||
|
||||
min_length = 0;
|
||||
name_ptr = RT_NULL;
|
||||
|
||||
if (*prefix == '\0')
|
||||
{
|
||||
msh_help(0, RT_NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DFS
|
||||
/* check whether a spare in the command */
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
ptr = prefix + rt_strlen(prefix);
|
||||
while (ptr != prefix)
|
||||
{
|
||||
if (*ptr == ' ')
|
||||
{
|
||||
msh_auto_complete_path(ptr + 1);
|
||||
break;
|
||||
}
|
||||
|
||||
ptr --;
|
||||
}
|
||||
#ifdef RT_USING_MODULE
|
||||
/* There is a chance that the user want to run the module directly. So
|
||||
* try to complete the file names. If the completed path is not a
|
||||
* module, the system won't crash anyway. */
|
||||
if (ptr == prefix)
|
||||
{
|
||||
msh_auto_complete_path(ptr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/* checks in internal command */
|
||||
{
|
||||
for (index = _syscall_table_begin; index < _syscall_table_end; FINSH_NEXT_SYSCALL(index))
|
||||
{
|
||||
/* skip finsh shell function */
|
||||
if (strncmp(index->name, "__cmd_", 6) != 0) continue;
|
||||
|
||||
cmd_name = (const char*) &index->name[6];
|
||||
if (strncmp(prefix, cmd_name, strlen(prefix)) == 0)
|
||||
{
|
||||
if (min_length == 0)
|
||||
{
|
||||
/* set name_ptr */
|
||||
name_ptr = cmd_name;
|
||||
/* set initial length */
|
||||
min_length = strlen(name_ptr);
|
||||
}
|
||||
|
||||
length = str_common(name_ptr, cmd_name);
|
||||
if (length < min_length)
|
||||
min_length = length;
|
||||
|
||||
rt_kprintf("%s\n", cmd_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* auto complete string */
|
||||
if (name_ptr != NULL)
|
||||
{
|
||||
rt_strncpy(prefix, name_ptr, min_length);
|
||||
}
|
||||
|
||||
return ;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* RT-Thread module shell implementation.
|
||||
*
|
||||
* COPYRIGHT (C) 2013, Shanghai Real-Thread Technology Co., Ltd
|
||||
*
|
||||
* This file is part of RT-Thread (http://www.rt-thread.org)
|
||||
* Maintainer: bernard.xiong <bernard.xiong at gmail.com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-03-30 Bernard the first verion for FinSH
|
||||
*/
|
||||
|
||||
#ifndef __M_SHELL__
|
||||
#define __M_SHELL__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
rt_bool_t msh_is_used(void);
|
||||
int msh_exec(char* cmd, rt_size_t length);
|
||||
void msh_auto_complete(char *prefix);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* internal commands for RT-Thread module shell
|
||||
*
|
||||
* COPYRIGHT (C) 2013, Shanghai Real-Thread Technology Co., Ltd
|
||||
*
|
||||
* This file is part of RT-Thread (http://www.rt-thread.org)
|
||||
* Maintainer: bernard.xiong <bernard.xiong at gmail.com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-03-30 Bernard the first verion for FinSH
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <finsh.h>
|
||||
|
||||
#include "msh.h"
|
||||
|
||||
#ifdef FINSH_USING_MSH
|
||||
#ifdef RT_USING_DFS
|
||||
#include <dfs_posix.h>
|
||||
|
||||
#ifdef DFS_USING_WORKDIR
|
||||
extern char working_directory[];
|
||||
#endif
|
||||
|
||||
int cmd_ls(int argc, char** argv)
|
||||
{
|
||||
extern void ls(const char *pathname);
|
||||
|
||||
if (argc == 1)
|
||||
{
|
||||
#ifdef DFS_USING_WORKDIR
|
||||
ls(working_directory);
|
||||
#else
|
||||
ls("/");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
ls(argv[1]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(cmd_ls, __cmd_ls, List information about the FILEs.);
|
||||
|
||||
int cmd_cp(int argc, char** argv)
|
||||
{
|
||||
void copy(const char *src, const char *dst);
|
||||
|
||||
if (argc != 3)
|
||||
{
|
||||
rt_kprintf("Usage: cp SOURCE DEST\n");
|
||||
rt_kprintf("Copy SOURCE to DEST.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
copy(argv[1], argv[2]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(cmd_cp, __cmd_cp, Copy SOURCE to DEST.);
|
||||
|
||||
int cmd_mv(int argc, char** argv)
|
||||
{
|
||||
if (argc != 3)
|
||||
{
|
||||
rt_kprintf("Usage: mv SOURCE DEST\n");
|
||||
rt_kprintf("Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("%s => %s\n", argv[1], argv[2]);
|
||||
rename(argv[1], argv[2]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(cmd_mv, __cmd_mv, Rename SOURCE to DEST.);
|
||||
|
||||
int cmd_cat(int argc, char** argv)
|
||||
{
|
||||
int index;
|
||||
extern void cat(const char* filename);
|
||||
|
||||
if (argc == 1)
|
||||
{
|
||||
rt_kprintf("Usage: cat [FILE]...\n");
|
||||
rt_kprintf("Concatenate FILE(s)\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (index = 1; index < argc; index ++)
|
||||
{
|
||||
cat(argv[index]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(cmd_cat, __cmd_cat, Concatenate FILE(s));
|
||||
|
||||
int cmd_rm(int argc, char** argv)
|
||||
{
|
||||
int index;
|
||||
|
||||
if (argc == 1)
|
||||
{
|
||||
rt_kprintf("Usage: rm FILE...\n");
|
||||
rt_kprintf("Remove (unlink) the FILE(s).\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (index = 1; index < argc; index ++)
|
||||
{
|
||||
unlink(argv[index]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(cmd_rm, __cmd_rm, Remove (unlink) the FILE(s).);
|
||||
|
||||
#ifdef DFS_USING_WORKDIR
|
||||
int cmd_cd(int argc, char** argv)
|
||||
{
|
||||
if (argc == 1)
|
||||
{
|
||||
rt_kprintf("%s\n", working_directory);
|
||||
}
|
||||
else if (argc == 2)
|
||||
{
|
||||
chdir(argv[1]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(cmd_cd, __cmd_cd, Change the shell working directory.);
|
||||
|
||||
int cmd_pwd(int argc, char** argv)
|
||||
{
|
||||
rt_kprintf("%s\n", working_directory);
|
||||
return 0;
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(cmd_pwd, __cmd_pwd, Print the name of the current working directory.);
|
||||
#endif
|
||||
|
||||
int cmd_mkdir(int argc, char** argv)
|
||||
{
|
||||
if (argc == 1)
|
||||
{
|
||||
rt_kprintf("Usage: mkdir [OPTION] DIRECTORY\n");
|
||||
rt_kprintf("Create the DIRECTORY, if they do not already exist.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
mkdir(argv[1], 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(cmd_mkdir, __cmd_mkdir, Create the DIRECTORY.);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_LWIP
|
||||
int cmd_ifconfig(int argc, char** argv)
|
||||
{
|
||||
extern void list_if(void);
|
||||
|
||||
list_if();
|
||||
return 0;
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(cmd_ifconfig, __cmd_ifconfig, list the information of network interfaces);
|
||||
|
||||
#endif
|
||||
|
||||
int cmd_ps(int argc, char** argv)
|
||||
{
|
||||
extern long list_thread(void);
|
||||
|
||||
list_thread();
|
||||
return 0;
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(cmd_ps, __cmd_ps, List threads in the system.);
|
||||
|
||||
int cmd_time(int argc, char** argv)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(cmd_time, __cmd_time, Execute command with time.);
|
||||
|
||||
int cmd_free(int argc, char** argv)
|
||||
{
|
||||
extern void list_mem(void);
|
||||
|
||||
list_mem();
|
||||
return 0;
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(cmd_free, __cmd_free, Show the memory usage in the system.);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,662 @@
|
||||
/*
|
||||
* shell implementation for finsh shell.
|
||||
*
|
||||
* COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team
|
||||
*
|
||||
* This file is part of RT-Thread (http://www.rt-thread.org)
|
||||
* Maintainer: bernard.xiong <bernard.xiong at gmail.com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2006-04-30 Bernard the first version for FinSH
|
||||
* 2006-05-08 Bernard change finsh thread stack to 2048
|
||||
* 2006-06-03 Bernard add support for skyeye
|
||||
* 2006-09-24 Bernard remove the code related with hardware
|
||||
* 2010-01-18 Bernard fix down then up key bug.
|
||||
* 2010-03-19 Bernard fix backspace issue and fix device read in shell.
|
||||
* 2010-04-01 Bernard add prompt output when start and remove the empty history
|
||||
* 2011-02-23 Bernard fix variable section end issue of finsh shell
|
||||
* initialization when use GNU GCC compiler.
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
|
||||
#include "finsh.h"
|
||||
#include "shell.h"
|
||||
|
||||
#ifdef FINSH_USING_MSH
|
||||
#include "msh.h"
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <stdio.h> /* for putchar */
|
||||
#endif
|
||||
|
||||
/* finsh thread */
|
||||
static struct rt_thread finsh_thread;
|
||||
ALIGN(RT_ALIGN_SIZE)
|
||||
static char finsh_thread_stack[FINSH_THREAD_STACK_SIZE];
|
||||
struct finsh_shell* shell;
|
||||
|
||||
#if defined(FINSH_USING_MSH) || (defined(RT_USING_DFS) && defined(DFS_USING_WORKDIR))
|
||||
#if defined(RT_USING_DFS)
|
||||
#include <dfs_posix.h>
|
||||
#endif
|
||||
const char* finsh_get_prompt()
|
||||
{
|
||||
#define _MSH_PROMPT "msh "
|
||||
#define _PROMPT "finsh "
|
||||
static char finsh_prompt[RT_CONSOLEBUF_SIZE + 1] = {0};
|
||||
|
||||
#ifdef FINSH_USING_MSH
|
||||
if (msh_is_used()) strcpy(finsh_prompt, _MSH_PROMPT);
|
||||
else
|
||||
#endif
|
||||
strcpy(finsh_prompt, _PROMPT);
|
||||
|
||||
#ifdef DFS_USING_WORKDIR
|
||||
/* get current working directory */
|
||||
getcwd(&finsh_prompt[rt_strlen(finsh_prompt)], RT_CONSOLEBUF_SIZE - rt_strlen(finsh_prompt));
|
||||
#endif
|
||||
strcat(finsh_prompt, ">");
|
||||
|
||||
return finsh_prompt;
|
||||
}
|
||||
#endif
|
||||
|
||||
static rt_err_t finsh_rx_ind(rt_device_t dev, rt_size_t size)
|
||||
{
|
||||
RT_ASSERT(shell != RT_NULL);
|
||||
|
||||
/* release semaphore to let finsh thread rx data */
|
||||
rt_sem_release(&shell->rx_sem);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup finsh
|
||||
*
|
||||
* This function sets the input device of finsh shell.
|
||||
*
|
||||
* @param device_name the name of new input device.
|
||||
*/
|
||||
void finsh_set_device(const char* device_name)
|
||||
{
|
||||
rt_device_t dev = RT_NULL;
|
||||
|
||||
RT_ASSERT(shell != RT_NULL);
|
||||
dev = rt_device_find(device_name);
|
||||
if (dev == RT_NULL)
|
||||
{
|
||||
rt_kprintf("finsh: can not find device: %s\n", device_name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* check whether it's a same device */
|
||||
if (dev == shell->device) return;
|
||||
/* open this device and set the new device in finsh shell */
|
||||
if (rt_device_open(dev, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX) == RT_EOK)
|
||||
{
|
||||
if (shell->device != RT_NULL)
|
||||
{
|
||||
/* close old finsh device */
|
||||
rt_device_close(shell->device);
|
||||
rt_device_set_rx_indicate(dev, RT_NULL);
|
||||
}
|
||||
|
||||
shell->device = dev;
|
||||
rt_device_set_rx_indicate(dev, finsh_rx_ind);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup finsh
|
||||
*
|
||||
* This function returns current finsh shell input device.
|
||||
*
|
||||
* @return the finsh shell input device name is returned.
|
||||
*/
|
||||
const char* finsh_get_device()
|
||||
{
|
||||
RT_ASSERT(shell != RT_NULL);
|
||||
return shell->device->parent.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup finsh
|
||||
*
|
||||
* This function set the echo mode of finsh shell.
|
||||
*
|
||||
* FINSH_OPTION_ECHO=0x01 is echo mode, other values are none-echo mode.
|
||||
*
|
||||
* @param echo the echo mode
|
||||
*/
|
||||
void finsh_set_echo(rt_uint32_t echo)
|
||||
{
|
||||
RT_ASSERT(shell != RT_NULL);
|
||||
shell->echo_mode = (rt_uint8_t)echo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup finsh
|
||||
*
|
||||
* This function gets the echo mode of finsh shell.
|
||||
*
|
||||
* @return the echo mode
|
||||
*/
|
||||
rt_uint32_t finsh_get_echo()
|
||||
{
|
||||
RT_ASSERT(shell != RT_NULL);
|
||||
|
||||
return shell->echo_mode;
|
||||
}
|
||||
|
||||
static void shell_auto_complete(char* prefix)
|
||||
{
|
||||
|
||||
rt_kprintf("\n");
|
||||
#ifdef FINSH_USING_MSH
|
||||
if (msh_is_used() == RT_TRUE)
|
||||
{
|
||||
msh_auto_complete(prefix);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#ifndef FINSH_USING_MSH_ONLY
|
||||
extern void list_prefix(char* prefix);
|
||||
list_prefix(prefix);
|
||||
#endif
|
||||
}
|
||||
|
||||
rt_kprintf("%s%s", FINSH_PROMPT, prefix);
|
||||
}
|
||||
|
||||
#ifndef FINSH_USING_MSH_ONLY
|
||||
void finsh_run_line(struct finsh_parser* parser, const char *line)
|
||||
{
|
||||
const char* err_str;
|
||||
|
||||
rt_kprintf("\n");
|
||||
finsh_parser_run(parser, (unsigned char*)line);
|
||||
|
||||
/* compile node root */
|
||||
if (finsh_errno() == 0)
|
||||
{
|
||||
finsh_compiler_run(parser->root);
|
||||
}
|
||||
else
|
||||
{
|
||||
err_str = finsh_error_string(finsh_errno());
|
||||
rt_kprintf("%s\n", err_str);
|
||||
}
|
||||
|
||||
/* run virtual machine */
|
||||
if (finsh_errno() == 0)
|
||||
{
|
||||
char ch;
|
||||
finsh_vm_run();
|
||||
|
||||
ch = (unsigned char)finsh_stack_bottom();
|
||||
if (ch > 0x20 && ch < 0x7e)
|
||||
{
|
||||
rt_kprintf("\t'%c', %d, 0x%08x\n",
|
||||
(unsigned char)finsh_stack_bottom(),
|
||||
(unsigned int)finsh_stack_bottom(),
|
||||
(unsigned int)finsh_stack_bottom());
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("\t%d, 0x%08x\n",
|
||||
(unsigned int)finsh_stack_bottom(),
|
||||
(unsigned int)finsh_stack_bottom());
|
||||
}
|
||||
}
|
||||
|
||||
finsh_flush(parser);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef FINSH_USING_HISTORY
|
||||
static rt_bool_t shell_handle_history(struct finsh_shell* shell)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
int i;
|
||||
rt_kprintf("\r");
|
||||
|
||||
for(i=0; i<= 60; i++)
|
||||
putchar(' ');
|
||||
rt_kprintf("\r");
|
||||
|
||||
#else
|
||||
rt_kprintf("\033[2K\r");
|
||||
#endif
|
||||
rt_kprintf("%s%s", FINSH_PROMPT, shell->line);
|
||||
return RT_FALSE;
|
||||
}
|
||||
|
||||
static void shell_push_history(struct finsh_shell* shell)
|
||||
{
|
||||
if (shell->line_position != 0)
|
||||
{
|
||||
/* push history */
|
||||
if (shell->history_count >= FINSH_HISTORY_LINES)
|
||||
{
|
||||
/* move history */
|
||||
int index;
|
||||
for (index = 0; index < FINSH_HISTORY_LINES - 1; index ++)
|
||||
{
|
||||
memcpy(&shell->cmd_history[index][0],
|
||||
&shell->cmd_history[index + 1][0], FINSH_CMD_SIZE);
|
||||
}
|
||||
memset(&shell->cmd_history[index][0], 0, FINSH_CMD_SIZE);
|
||||
memcpy(&shell->cmd_history[index][0], shell->line, shell->line_position);
|
||||
|
||||
/* it's the maximum history */
|
||||
shell->history_count = FINSH_HISTORY_LINES;
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(&shell->cmd_history[shell->history_count][0], 0, FINSH_CMD_SIZE);
|
||||
memcpy(&shell->cmd_history[shell->history_count][0], shell->line, shell->line_position);
|
||||
|
||||
/* increase count and set current history position */
|
||||
shell->history_count ++;
|
||||
}
|
||||
}
|
||||
shell->current_history = shell->history_count;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef RT_USING_HEAP
|
||||
struct finsh_shell _shell;
|
||||
#endif
|
||||
void finsh_thread_entry(void* parameter)
|
||||
{
|
||||
char ch;
|
||||
|
||||
/* normal is echo mode */
|
||||
shell->echo_mode = 1;
|
||||
|
||||
#ifndef FINSH_USING_MSH_ONLY
|
||||
finsh_init(&shell->parser);
|
||||
#endif
|
||||
rt_kprintf(FINSH_PROMPT);
|
||||
|
||||
/* set console device as shell device */
|
||||
if (shell->device == RT_NULL)
|
||||
{
|
||||
#ifdef RT_USING_CONSOLE
|
||||
shell->device = rt_console_get_device();
|
||||
RT_ASSERT(shell->device);
|
||||
rt_device_set_rx_indicate(shell->device, finsh_rx_ind);
|
||||
rt_device_open(shell->device, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX);
|
||||
#else
|
||||
RT_ASSERT(shell->device);
|
||||
#endif
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* wait receive */
|
||||
if (rt_sem_take(&shell->rx_sem, RT_WAITING_FOREVER) != RT_EOK) continue;
|
||||
|
||||
/* read one character from device */
|
||||
while (rt_device_read(shell->device, 0, &ch, 1) == 1)
|
||||
{
|
||||
/*
|
||||
* handle control key
|
||||
* up key : 0x1b 0x5b 0x41
|
||||
* down key: 0x1b 0x5b 0x42
|
||||
* right key:0x1b 0x5b 0x43
|
||||
* left key: 0x1b 0x5b 0x44
|
||||
*/
|
||||
if (ch == 0x1b)
|
||||
{
|
||||
shell->stat = WAIT_SPEC_KEY;
|
||||
continue;
|
||||
}
|
||||
else if (shell->stat == WAIT_SPEC_KEY)
|
||||
{
|
||||
if (ch == 0x5b)
|
||||
{
|
||||
shell->stat = WAIT_FUNC_KEY;
|
||||
continue;
|
||||
}
|
||||
|
||||
shell->stat = WAIT_NORMAL;
|
||||
}
|
||||
else if (shell->stat == WAIT_FUNC_KEY)
|
||||
{
|
||||
shell->stat = WAIT_NORMAL;
|
||||
|
||||
if (ch == 0x41) /* up key */
|
||||
{
|
||||
#ifdef FINSH_USING_HISTORY
|
||||
/* prev history */
|
||||
if (shell->current_history > 0)
|
||||
shell->current_history --;
|
||||
else
|
||||
{
|
||||
shell->current_history = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* copy the history command */
|
||||
memcpy(shell->line, &shell->cmd_history[shell->current_history][0],
|
||||
FINSH_CMD_SIZE);
|
||||
shell->line_curpos = shell->line_position = strlen(shell->line);
|
||||
shell_handle_history(shell);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
else if (ch == 0x42) /* down key */
|
||||
{
|
||||
#ifdef FINSH_USING_HISTORY
|
||||
/* next history */
|
||||
if (shell->current_history < shell->history_count - 1)
|
||||
shell->current_history ++;
|
||||
else
|
||||
{
|
||||
/* set to the end of history */
|
||||
if (shell->history_count != 0)
|
||||
shell->current_history = shell->history_count - 1;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy(shell->line, &shell->cmd_history[shell->current_history][0],
|
||||
FINSH_CMD_SIZE);
|
||||
shell->line_curpos = shell->line_position = strlen(shell->line);
|
||||
shell_handle_history(shell);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
else if (ch == 0x44) /* left key */
|
||||
{
|
||||
if (shell->line_curpos)
|
||||
{
|
||||
rt_kprintf("\b");
|
||||
shell->line_curpos --;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
else if (ch == 0x43) /* right key */
|
||||
{
|
||||
if (shell->line_curpos < shell->line_position)
|
||||
{
|
||||
rt_kprintf("%c", shell->line[shell->line_curpos]);
|
||||
shell->line_curpos ++;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* handle CR key */
|
||||
if (ch == '\r')
|
||||
{
|
||||
char next;
|
||||
|
||||
if (rt_device_read(shell->device, 0, &next, 1) == 1)
|
||||
ch = next;
|
||||
else ch = '\r';
|
||||
}
|
||||
/* handle tab key */
|
||||
else if (ch == '\t')
|
||||
{
|
||||
int i;
|
||||
/* move the cursor to the beginning of line */
|
||||
for (i = 0; i < shell->line_curpos; i++)
|
||||
rt_kprintf("\b");
|
||||
|
||||
/* auto complete */
|
||||
shell_auto_complete(&shell->line[0]);
|
||||
/* re-calculate position */
|
||||
shell->line_curpos = shell->line_position = strlen(shell->line);
|
||||
|
||||
continue;
|
||||
}
|
||||
/* handle backspace key */
|
||||
else if (ch == 0x7f || ch == 0x08)
|
||||
{
|
||||
/* note that shell->line_curpos >= 0 */
|
||||
if (shell->line_curpos == 0)
|
||||
continue;
|
||||
|
||||
shell->line_position--;
|
||||
shell->line_curpos--;
|
||||
|
||||
if (shell->line_position > shell->line_curpos)
|
||||
{
|
||||
int i;
|
||||
|
||||
rt_memmove(&shell->line[shell->line_curpos],
|
||||
&shell->line[shell->line_curpos + 1],
|
||||
shell->line_position - shell->line_curpos);
|
||||
shell->line[shell->line_position] = 0;
|
||||
|
||||
rt_kprintf("\b%s \b", &shell->line[shell->line_curpos]);
|
||||
|
||||
/* move the cursor to the origin position */
|
||||
for (i = shell->line_curpos; i <= shell->line_position; i++)
|
||||
rt_kprintf("\b");
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("\b \b");
|
||||
shell->line[shell->line_position] = 0;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* handle end of line, break */
|
||||
if (ch == '\r' || ch == '\n')
|
||||
{
|
||||
#ifdef FINSH_USING_HISTORY
|
||||
shell_push_history(shell);
|
||||
#endif
|
||||
|
||||
#ifdef FINSH_USING_MSH
|
||||
if (msh_is_used() == RT_TRUE)
|
||||
{
|
||||
rt_kprintf("\n");
|
||||
msh_exec(shell->line, shell->line_position);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#ifndef FINSH_USING_MSH_ONLY
|
||||
/* add ';' and run the command line */
|
||||
shell->line[shell->line_position] = ';';
|
||||
|
||||
if (shell->line_position != 0) finsh_run_line(&shell->parser, shell->line);
|
||||
else rt_kprintf("\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
rt_kprintf(FINSH_PROMPT);
|
||||
memset(shell->line, 0, sizeof(shell->line));
|
||||
shell->line_curpos = shell->line_position = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* it's a large line, discard it */
|
||||
if (shell->line_position >= FINSH_CMD_SIZE)
|
||||
shell->line_position = 0;
|
||||
|
||||
/* normal character */
|
||||
if (shell->line_curpos < shell->line_position)
|
||||
{
|
||||
int i;
|
||||
|
||||
rt_memmove(&shell->line[shell->line_curpos + 1],
|
||||
&shell->line[shell->line_curpos],
|
||||
shell->line_position - shell->line_curpos);
|
||||
shell->line[shell->line_curpos] = ch;
|
||||
if (shell->echo_mode)
|
||||
rt_kprintf("%s", &shell->line[shell->line_curpos]);
|
||||
|
||||
/* move the cursor to new position */
|
||||
for (i = shell->line_curpos; i < shell->line_position; i++)
|
||||
rt_kprintf("\b");
|
||||
}
|
||||
else
|
||||
{
|
||||
shell->line[shell->line_position] = ch;
|
||||
rt_kprintf("%c", ch);
|
||||
}
|
||||
|
||||
ch = 0;
|
||||
shell->line_position ++;
|
||||
shell->line_curpos++;
|
||||
if (shell->line_position >= 80)
|
||||
{
|
||||
/* clear command line */
|
||||
shell->line_position = 0;
|
||||
shell->line_curpos = 0;
|
||||
}
|
||||
} /* end of device read */
|
||||
}
|
||||
}
|
||||
|
||||
void finsh_system_function_init(const void* begin, const void* end)
|
||||
{
|
||||
_syscall_table_begin = (struct finsh_syscall*) begin;
|
||||
_syscall_table_end = (struct finsh_syscall*) end;
|
||||
}
|
||||
|
||||
void finsh_system_var_init(const void* begin, const void* end)
|
||||
{
|
||||
_sysvar_table_begin = (struct finsh_sysvar*) begin;
|
||||
_sysvar_table_end = (struct finsh_sysvar*) end;
|
||||
}
|
||||
|
||||
#if defined(__ICCARM__) /* for IAR compiler */
|
||||
#ifdef FINSH_USING_SYMTAB
|
||||
#pragma section="FSymTab"
|
||||
#pragma section="VSymTab"
|
||||
#endif
|
||||
#elif defined(__ADSPBLACKFIN__) /* for VisaulDSP++ Compiler*/
|
||||
#ifdef FINSH_USING_SYMTAB
|
||||
extern "asm" int __fsymtab_start;
|
||||
extern "asm" int __fsymtab_end;
|
||||
extern "asm" int __vsymtab_start;
|
||||
extern "asm" int __vsymtab_end;
|
||||
#endif
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma section("FSymTab$a", read)
|
||||
const char __fsym_begin_name[] = "__start";
|
||||
const char __fsym_begin_desc[] = "begin of finsh";
|
||||
__declspec(allocate("FSymTab$a")) const struct finsh_syscall __fsym_begin =
|
||||
{
|
||||
__fsym_begin_name,
|
||||
__fsym_begin_desc,
|
||||
NULL
|
||||
};
|
||||
|
||||
#pragma section("FSymTab$z", read)
|
||||
const char __fsym_end_name[] = "__end";
|
||||
const char __fsym_end_desc[] = "end of finsh";
|
||||
__declspec(allocate("FSymTab$z")) const struct finsh_syscall __fsym_end =
|
||||
{
|
||||
__fsym_end_name,
|
||||
__fsym_end_desc,
|
||||
NULL
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* @ingroup finsh
|
||||
*
|
||||
* This function will initialize finsh shell
|
||||
*/
|
||||
int finsh_system_init(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
#ifdef FINSH_USING_SYMTAB
|
||||
#ifdef __CC_ARM /* ARM C Compiler */
|
||||
extern const int FSymTab$$Base;
|
||||
extern const int FSymTab$$Limit;
|
||||
extern const int VSymTab$$Base;
|
||||
extern const int VSymTab$$Limit;
|
||||
finsh_system_function_init(&FSymTab$$Base, &FSymTab$$Limit);
|
||||
#ifndef FINSH_USING_MSH_ONLY
|
||||
finsh_system_var_init(&VSymTab$$Base, &VSymTab$$Limit);
|
||||
#endif
|
||||
#elif defined (__ICCARM__) /* for IAR Compiler */
|
||||
finsh_system_function_init(__section_begin("FSymTab"),
|
||||
__section_end("FSymTab"));
|
||||
finsh_system_var_init(__section_begin("VSymTab"),
|
||||
__section_end("VSymTab"));
|
||||
#elif defined (__GNUC__) || defined(__TI_COMPILER_VERSION__)
|
||||
/* GNU GCC Compiler and TI CCS */
|
||||
extern const int __fsymtab_start;
|
||||
extern const int __fsymtab_end;
|
||||
extern const int __vsymtab_start;
|
||||
extern const int __vsymtab_end;
|
||||
finsh_system_function_init(&__fsymtab_start, &__fsymtab_end);
|
||||
finsh_system_var_init(&__vsymtab_start, &__vsymtab_end);
|
||||
#elif defined(__ADSPBLACKFIN__) /* for VisualDSP++ Compiler */
|
||||
finsh_system_function_init(&__fsymtab_start, &__fsymtab_end);
|
||||
finsh_system_var_init(&__vsymtab_start, &__vsymtab_end);
|
||||
#elif defined(_MSC_VER)
|
||||
unsigned int *ptr_begin, *ptr_end;
|
||||
|
||||
ptr_begin = (unsigned int*)&__fsym_begin; ptr_begin += (sizeof(struct finsh_syscall)/sizeof(unsigned int));
|
||||
while (*ptr_begin == 0) ptr_begin ++;
|
||||
|
||||
ptr_end = (unsigned int*) &__fsym_end; ptr_end --;
|
||||
while (*ptr_end == 0) ptr_end --;
|
||||
|
||||
finsh_system_function_init(ptr_begin, ptr_end);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* create or set shell structure */
|
||||
#ifdef RT_USING_HEAP
|
||||
shell = (struct finsh_shell*)rt_malloc(sizeof(struct finsh_shell));
|
||||
if (shell == RT_NULL)
|
||||
{
|
||||
rt_kprintf("no memory for shell\n");
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
shell = &_shell;
|
||||
#endif
|
||||
|
||||
memset(shell, 0, sizeof(struct finsh_shell));
|
||||
|
||||
rt_sem_init(&(shell->rx_sem), "shrx", 0, 0);
|
||||
result = rt_thread_init(&finsh_thread,
|
||||
"tshell",
|
||||
finsh_thread_entry, RT_NULL,
|
||||
&finsh_thread_stack[0], sizeof(finsh_thread_stack),
|
||||
FINSH_THREAD_PRIORITY, 10);
|
||||
|
||||
if (result == RT_EOK)
|
||||
rt_thread_startup(&finsh_thread);
|
||||
return 0;
|
||||
}
|
||||
INIT_COMPONENT_EXPORT(finsh_system_init);
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* shell implementation for finsh shell.
|
||||
*
|
||||
* COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team
|
||||
*
|
||||
* This file is part of RT-Thread (http://www.rt-thread.org)
|
||||
* Maintainer: bernard.xiong <bernard.xiong at gmail.com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-06-02 Bernard Add finsh_get_prompt function declaration
|
||||
*/
|
||||
|
||||
#ifndef __SHELL_H__
|
||||
#define __SHELL_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "finsh.h"
|
||||
|
||||
#define FINSH_USING_HISTORY
|
||||
#ifndef FINSH_THREAD_PRIORITY
|
||||
#define FINSH_THREAD_PRIORITY 20
|
||||
#endif
|
||||
#ifndef FINSH_THREAD_STACK_SIZE
|
||||
#define FINSH_THREAD_STACK_SIZE 2048
|
||||
#endif
|
||||
#define FINSH_CMD_SIZE 80
|
||||
|
||||
#define FINSH_OPTION_ECHO 0x01
|
||||
#if defined(FINSH_USING_MSH) || (defined(RT_USING_DFS) && defined(DFS_USING_WORKDIR))
|
||||
#define FINSH_PROMPT finsh_get_prompt()
|
||||
const char* finsh_get_prompt(void);
|
||||
#else
|
||||
#define FINSH_PROMPT "finsh>>"
|
||||
#endif
|
||||
|
||||
#ifdef FINSH_USING_HISTORY
|
||||
#ifndef FINSH_HISTORY_LINES
|
||||
#define FINSH_HISTORY_LINES 5
|
||||
#endif
|
||||
#endif
|
||||
|
||||
enum input_stat
|
||||
{
|
||||
WAIT_NORMAL,
|
||||
WAIT_SPEC_KEY,
|
||||
WAIT_FUNC_KEY,
|
||||
};
|
||||
struct finsh_shell
|
||||
{
|
||||
struct rt_semaphore rx_sem;
|
||||
|
||||
enum input_stat stat;
|
||||
|
||||
rt_uint8_t echo_mode:1;
|
||||
|
||||
#ifdef FINSH_USING_HISTORY
|
||||
rt_uint16_t current_history;
|
||||
rt_uint16_t history_count;
|
||||
|
||||
char cmd_history[FINSH_HISTORY_LINES][FINSH_CMD_SIZE];
|
||||
#endif
|
||||
|
||||
#ifndef FINSH_USING_MSH_ONLY
|
||||
struct finsh_parser parser;
|
||||
#endif
|
||||
|
||||
char line[FINSH_CMD_SIZE];
|
||||
rt_uint8_t line_position;
|
||||
rt_uint8_t line_curpos;
|
||||
|
||||
rt_device_t device;
|
||||
};
|
||||
|
||||
void finsh_set_echo(rt_uint32_t echo);
|
||||
rt_uint32_t finsh_get_echo(void);
|
||||
|
||||
int finsh_system_init(void);
|
||||
void finsh_set_device(const char* device_name);
|
||||
const char* finsh_get_device(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* symbols in finsh shell.
|
||||
*
|
||||
* COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team
|
||||
*
|
||||
* This file is part of RT-Thread (http://www.rt-thread.org)
|
||||
* Maintainer: bernard.xiong <bernard.xiong at gmail.com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2010-03-22 Bernard first version
|
||||
*/
|
||||
#include "finsh.h"
|
||||
|
||||
long hello(void);
|
||||
long version(void);
|
||||
long list(void);
|
||||
long list_thread(void);
|
||||
long list_sem(void);
|
||||
long list_mutex(void);
|
||||
long list_fevent(void);
|
||||
long list_event(void);
|
||||
long list_mailbox(void);
|
||||
long list_msgqueue(void);
|
||||
long list_mempool(void);
|
||||
long list_timer(void);
|
||||
|
||||
#ifdef FINSH_USING_SYMTAB
|
||||
struct finsh_syscall *_syscall_table_begin = NULL;
|
||||
struct finsh_syscall *_syscall_table_end = NULL;
|
||||
struct finsh_sysvar *_sysvar_table_begin = NULL;
|
||||
struct finsh_sysvar *_sysvar_table_end = NULL;
|
||||
#else
|
||||
struct finsh_syscall _syscall_table[] =
|
||||
{
|
||||
{"hello", hello},
|
||||
{"version", version},
|
||||
{"list", list},
|
||||
{"list_thread", list_thread},
|
||||
#ifdef RT_USING_SEMAPHORE
|
||||
{"list_sem", list_sem},
|
||||
#endif
|
||||
#ifdef RT_USING_MUTEX
|
||||
{"list_mutex", list_mutex},
|
||||
#endif
|
||||
#ifdef RT_USING_FEVENT
|
||||
{"list_fevent", list_fevent},
|
||||
#endif
|
||||
#ifdef RT_USING_EVENT
|
||||
{"list_event", list_event},
|
||||
#endif
|
||||
#ifdef RT_USING_MAILBOX
|
||||
{"list_mb", list_mailbox},
|
||||
#endif
|
||||
#ifdef RT_USING_MESSAGEQUEUE
|
||||
{"list_mq", list_msgqueue},
|
||||
#endif
|
||||
#ifdef RT_USING_MEMPOOL
|
||||
{"list_memp", list_mempool},
|
||||
#endif
|
||||
{"list_timer", list_timer},
|
||||
};
|
||||
struct finsh_syscall *_syscall_table_begin = &_syscall_table[0];
|
||||
struct finsh_syscall *_syscall_table_end = &_syscall_table[sizeof(_syscall_table) / sizeof(struct finsh_syscall)];
|
||||
|
||||
struct finsh_sysvar *_sysvar_table_begin = NULL;
|
||||
struct finsh_sysvar *_sysvar_table_end = NULL;
|
||||
#endif
|
||||
Reference in New Issue
Block a user