1、【增加】RT-Thread 系统 Demo。

Signed-off-by: armink <armink.ztl@gmail.com>
This commit is contained in:
armink
2017-04-15 15:14:49 +08:00
parent cee09e4a57
commit b536a063d6
247 changed files with 137359 additions and 2 deletions
@@ -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')
@@ -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__ */
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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_ */
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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