first submission
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2019, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2017-07-24 Tanek the first version
|
||||
* 2018-11-12 Ernest Chen modify copyright
|
||||
*/
|
||||
|
||||
#include "board.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include "drv_usart.h"
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
|
||||
// Holds the system core clock, which is the system clock
|
||||
// frequency supplied to the SysTick timer and the processor
|
||||
// core clock.
|
||||
extern uint32_t SystemCoreClock;
|
||||
|
||||
static uint32_t _SysTick_Config(rt_uint32_t ticks)
|
||||
{
|
||||
NVIC_SetPriority(SysTicK_IRQn,0xf0);
|
||||
NVIC_SetPriority(Software_IRQn,0xf0);
|
||||
NVIC_EnableIRQ(SysTicK_IRQn);
|
||||
NVIC_EnableIRQ(Software_IRQn);
|
||||
SysTick->CTLR=0;
|
||||
SysTick->SR=0;
|
||||
SysTick->CNT=0;
|
||||
SysTick->CMP=ticks-1;
|
||||
SysTick->CTLR=0xF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
|
||||
#define RT_HEAP_SIZE (1024)
|
||||
static uint32_t rt_heap[RT_HEAP_SIZE]; // heap default size: 4K(1024 * 4)
|
||||
RT_WEAK void *rt_heap_begin_get(void)
|
||||
{
|
||||
return rt_heap;
|
||||
}
|
||||
|
||||
RT_WEAK void *rt_heap_end_get(void)
|
||||
{
|
||||
return rt_heap + RT_HEAP_SIZE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This function will initial your board.
|
||||
*/
|
||||
void rt_hw_board_init()
|
||||
{
|
||||
/* System Tick Configuration */
|
||||
_SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
|
||||
/* Call components board initial (use INIT_BOARD_EXPORT()) */
|
||||
#ifdef RT_USING_COMPONENTS_INIT
|
||||
rt_components_board_init();
|
||||
#endif
|
||||
#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
|
||||
rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get());
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_CONSOLE
|
||||
rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void SysTick_Handler(void) __attribute__((interrupt()));
|
||||
void SysTick_Handler(void)
|
||||
{
|
||||
GET_INT_SP();
|
||||
/* enter interrupt */
|
||||
rt_interrupt_enter();
|
||||
SysTick->SR=0;
|
||||
rt_tick_increase();
|
||||
/* leave interrupt */
|
||||
rt_interrupt_leave();
|
||||
FREE_INT_SP();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* File : board.h
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2009, 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
|
||||
* 2009-09-22 Bernard add board.h to this bsp
|
||||
* 2017-10-20 ZYH emmm...setup for HAL Libraries
|
||||
*/
|
||||
|
||||
// <<< Use Configuration Wizard in Context Menu >>>
|
||||
#ifndef __BOARD_H__
|
||||
#define __BOARD_H__
|
||||
|
||||
#include "ch32v20x.h"
|
||||
#define ch32v20x_PIN_NUMBERS 48
|
||||
/* board configuration */
|
||||
#define SRAM_SIZE 20
|
||||
#define SRAM_END (0x20000000 + SRAM_SIZE * 1024)
|
||||
|
||||
extern int _ebss;
|
||||
#define HEAP_BEGIN ((void *)&_ebss)
|
||||
#define HEAP_END (SRAM_END-__stack_size)
|
||||
|
||||
|
||||
|
||||
void rt_hw_board_init(void);
|
||||
|
||||
#endif /* __BOARD_H__ */
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* File : pin.h
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2015, 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
|
||||
* 2015-01-20 Bernard the first version
|
||||
* 2017-10-20 ZYH add mode open drain and input pull down
|
||||
*/
|
||||
|
||||
#ifndef PIN_H__
|
||||
#define PIN_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* pin device and operations for RT-Thread */
|
||||
struct rt_device_pin
|
||||
{
|
||||
struct rt_device parent;
|
||||
const struct rt_pin_ops *ops;
|
||||
};
|
||||
|
||||
#define PIN_LOW 0x00
|
||||
#define PIN_HIGH 0x01
|
||||
|
||||
#define PIN_MODE_OUTPUT 0x00
|
||||
#define PIN_MODE_INPUT 0x01
|
||||
#define PIN_MODE_INPUT_PULLUP 0x02
|
||||
#define PIN_MODE_INPUT_PULLDOWN 0x03
|
||||
#define PIN_MODE_OUTPUT_OD 0x04
|
||||
|
||||
#define PIN_MODE_INPUT_AIN 0x05
|
||||
#define PIN_MODE_OUTPUT_AF_OD 0x06
|
||||
#define PIN_MODE_OUTPUT_AF_PP 0x07
|
||||
|
||||
|
||||
|
||||
#define PIN_IRQ_MODE_RISING 0x00
|
||||
#define PIN_IRQ_MODE_FALLING 0x01
|
||||
#define PIN_IRQ_MODE_RISING_FALLING 0x02
|
||||
#define PIN_IRQ_MODE_HIGH_LEVEL 0x03
|
||||
#define PIN_IRQ_MODE_LOW_LEVEL 0x04
|
||||
|
||||
#define PIN_IRQ_DISABLE 0x00
|
||||
#define PIN_IRQ_ENABLE 0x01
|
||||
|
||||
#define PIN_IRQ_PIN_NONE -1
|
||||
|
||||
struct rt_device_pin_mode
|
||||
{
|
||||
rt_uint16_t pin;
|
||||
rt_uint16_t mode;
|
||||
};
|
||||
struct rt_device_pin_status
|
||||
{
|
||||
rt_uint16_t pin;
|
||||
rt_uint16_t status;
|
||||
};
|
||||
struct rt_pin_irq_hdr
|
||||
{
|
||||
rt_int16_t pin;
|
||||
rt_uint16_t mode;
|
||||
void (*hdr)(void *args);
|
||||
void *args;
|
||||
};
|
||||
struct rt_pin_ops
|
||||
{
|
||||
void (*pin_mode)(struct rt_device *device, rt_base_t pin, rt_base_t mode);
|
||||
void (*pin_write)(struct rt_device *device, rt_base_t pin, rt_base_t value);
|
||||
int (*pin_read)(struct rt_device *device, rt_base_t pin);
|
||||
|
||||
/* TODO: add GPIO interrupt */
|
||||
rt_err_t (*pin_attach_irq)(struct rt_device *device, rt_int32_t pin,
|
||||
rt_uint32_t mode, void (*hdr)(void *args), void *args);
|
||||
rt_err_t (*pin_dettach_irq)(struct rt_device *device, rt_int32_t pin);
|
||||
rt_err_t (*pin_irq_enable)(struct rt_device *device, rt_base_t pin, rt_uint32_t enabled);
|
||||
};
|
||||
|
||||
int rt_device_pin_register(const char *name, const struct rt_pin_ops *ops, void *user_data);
|
||||
|
||||
void rt_pin_mode(rt_base_t pin, rt_base_t mode);
|
||||
void rt_pin_write(rt_base_t pin, rt_base_t value);
|
||||
int rt_pin_read(rt_base_t pin);
|
||||
rt_err_t rt_pin_attach_irq(rt_int32_t pin, rt_uint32_t mode,
|
||||
void (*hdr)(void *args), void *args);
|
||||
rt_err_t rt_pin_dettach_irq(rt_int32_t pin);
|
||||
rt_err_t rt_pin_irq_enable(rt_base_t pin, rt_uint32_t enabled);
|
||||
|
||||
int rt_device_pin_irq_register(const char *name, const struct rt_pin_ops *ops,
|
||||
void *user_data);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* 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_19200 19200
|
||||
#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 BAUD_RATE_2000000 2000000
|
||||
#define BAUD_RATE_3000000 3000000
|
||||
|
||||
#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
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#define PARITY_NONE 0
|
||||
#define PARITY_ODD 1
|
||||
#define PARITY_EVEN 2
|
||||
#endif
|
||||
|
||||
#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_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;
|
||||
|
||||
rt_bool_t is_full;
|
||||
};
|
||||
|
||||
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, 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,23 @@
|
||||
#ifndef COMPLETION_H_
|
||||
#define COMPLETION_H_
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
/**
|
||||
* Completion
|
||||
*/
|
||||
|
||||
struct rt_completion
|
||||
{
|
||||
rt_uint32_t flag;
|
||||
|
||||
/* suspended list */
|
||||
rt_list_t suspended_list;
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,53 @@
|
||||
#ifndef DATAQUEUE_H__
|
||||
#define DATAQUEUE_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#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);
|
||||
};
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,36 @@
|
||||
#ifndef PIPE_H__
|
||||
#define PIPE_H__
|
||||
|
||||
/**
|
||||
* Pipe Device
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#ifndef RT_PIPE_BUFSZ
|
||||
#define PIPE_BUFSZ 512
|
||||
#else
|
||||
#define PIPE_BUFSZ RT_PIPE_BUFSZ
|
||||
#endif
|
||||
|
||||
struct rt_pipe_device
|
||||
{
|
||||
struct rt_device parent;
|
||||
|
||||
/* ring buffer in pipe device */
|
||||
struct rt_ringbuffer *fifo;
|
||||
rt_uint16_t bufsz;
|
||||
|
||||
rt_uint8_t readers;
|
||||
rt_uint8_t writers;
|
||||
|
||||
rt_wqueue_t reader_queue;
|
||||
rt_wqueue_t writer_queue;
|
||||
|
||||
struct rt_mutex lock;
|
||||
};
|
||||
typedef struct rt_pipe_device rt_pipe_t;
|
||||
|
||||
rt_pipe_t *rt_pipe_create(const char *name, int bufsz);
|
||||
int rt_pipe_delete(const char *name);
|
||||
#endif /* PIPE_H__ */
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* File : poll.h
|
||||
* This file is part of Device File System in RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2006-2017, 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
|
||||
* 2016-09-19 Heyuanjie The first version.
|
||||
* 2016-12-26 Bernard Update poll interface
|
||||
*/
|
||||
#ifndef IPC_POLL_H__
|
||||
#define IPC_POLL_H__
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct rt_pollreq;
|
||||
typedef void (*poll_queue_proc)(rt_wqueue_t *, struct rt_pollreq *);
|
||||
|
||||
typedef struct rt_pollreq
|
||||
{
|
||||
poll_queue_proc _proc;
|
||||
short _key;
|
||||
} rt_pollreq_t;
|
||||
|
||||
rt_inline void rt_poll_add(rt_wqueue_t *wq, rt_pollreq_t *req)
|
||||
{
|
||||
if (req && req->_proc && wq)
|
||||
{
|
||||
req->_proc(wq, req);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,88 @@
|
||||
#ifndef RINGBUFFER_H__
|
||||
#define RINGBUFFER_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
/* 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;
|
||||
};
|
||||
|
||||
enum rt_ringbuffer_state
|
||||
{
|
||||
RT_RINGBUFFER_EMPTY,
|
||||
RT_RINGBUFFER_FULL,
|
||||
/* half full is neither full nor empty */
|
||||
RT_RINGBUFFER_HALFFULL,
|
||||
};
|
||||
|
||||
/**
|
||||
* 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);
|
||||
void rt_ringbuffer_reset(struct rt_ringbuffer *rb);
|
||||
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);
|
||||
rt_size_t rt_ringbuffer_data_len(struct rt_ringbuffer *rb);
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
struct rt_ringbuffer* rt_ringbuffer_create(rt_uint16_t length);
|
||||
void rt_ringbuffer_destroy(struct rt_ringbuffer *rb);
|
||||
#endif
|
||||
|
||||
rt_inline rt_uint16_t rt_ringbuffer_get_size(struct rt_ringbuffer *rb)
|
||||
{
|
||||
RT_ASSERT(rb != RT_NULL);
|
||||
return rb->buffer_size;
|
||||
}
|
||||
|
||||
/** return the size of empty space in rb */
|
||||
#define rt_ringbuffer_space_len(rb) ((rb)->buffer_size - rt_ringbuffer_data_len(rb))
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* File : waitqueue.h
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2006 - 2018, 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
|
||||
* 2018/06/26 Bernard Fix the wait queue issue when wakeup a soon
|
||||
* to blocked thread.
|
||||
*/
|
||||
|
||||
#ifndef WAITQUEUE_H__
|
||||
#define WAITQUEUE_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#define RT_WQ_FLAG_CLEAN 0x00
|
||||
#define RT_WQ_FLAG_WAKEUP 0x01
|
||||
|
||||
struct rt_wqueue_node;
|
||||
typedef int (*rt_wqueue_func_t)(struct rt_wqueue_node *wait, void *key);
|
||||
|
||||
struct rt_wqueue_node
|
||||
{
|
||||
rt_thread_t polling_thread;
|
||||
rt_list_t list;
|
||||
|
||||
rt_wqueue_func_t wakeup;
|
||||
rt_uint32_t key;
|
||||
};
|
||||
typedef struct rt_wqueue_node rt_wqueue_node_t;
|
||||
|
||||
int __wqueue_default_wake(struct rt_wqueue_node *wait, void *key);
|
||||
|
||||
rt_inline void rt_wqueue_init(rt_wqueue_t *queue)
|
||||
{
|
||||
RT_ASSERT(queue != RT_NULL);
|
||||
|
||||
queue->flag = RT_WQ_FLAG_CLEAN;
|
||||
rt_list_init(&(queue->waiting_list));
|
||||
}
|
||||
|
||||
void rt_wqueue_add(rt_wqueue_t *queue, struct rt_wqueue_node *node);
|
||||
void rt_wqueue_remove(struct rt_wqueue_node *node);
|
||||
int rt_wqueue_wait(rt_wqueue_t *queue, int condition, int timeout);
|
||||
void rt_wqueue_wakeup(rt_wqueue_t *queue, void *key);
|
||||
|
||||
#define DEFINE_WAIT_FUNC(name, function) \
|
||||
struct rt_wqueue_node name = { \
|
||||
rt_current_thread, \
|
||||
RT_LIST_OBJECT_INIT(((name).list)), \
|
||||
\
|
||||
function, \
|
||||
0 \
|
||||
}
|
||||
|
||||
#define DEFINE_WAIT(name) DEFINE_WAIT_FUNC(name, __wqueue_default_wake)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,44 @@
|
||||
#ifndef WORKQUEUE_H__
|
||||
#define WORKQUEUE_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
/* workqueue implementation */
|
||||
struct rt_workqueue
|
||||
{
|
||||
rt_list_t work_list;
|
||||
struct rt_work *work_current; /* current work */
|
||||
|
||||
struct rt_semaphore sem;
|
||||
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;
|
||||
};
|
||||
|
||||
#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_err_t rt_workqueue_cancel_work_sync(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
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
#include "ipc/ringbuffer.h"
|
||||
#include "ipc/completion.h"
|
||||
#include "ipc/dataqueue.h"
|
||||
#include "ipc/workqueue.h"
|
||||
#include "ipc/waitqueue.h"
|
||||
#include "ipc/pipe.h"
|
||||
#include "ipc/poll.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define RT_DEVICE(device) ((rt_device_t)device)
|
||||
|
||||
#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
|
||||
|
||||
#ifdef RT_USING_PIN
|
||||
#include "drivers/pin.h"
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_CAN
|
||||
#include "drivers/can.h"
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_HWTIMER
|
||||
#include "drivers/hwtimer.h"
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_AUDIO
|
||||
#include "drivers/audio.h"
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_CPUTIME
|
||||
#include "drivers/cputime.h"
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_PWM
|
||||
#include "drivers/rt_drv_pwm.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __RT_DEVICE_H__ */
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* File : pin.c
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2015, 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
|
||||
* 2015-01-20 Bernard the first version
|
||||
*/
|
||||
|
||||
#include <drivers/pin.h>
|
||||
|
||||
#ifdef RT_USING_FINSH
|
||||
#include <finsh.h>
|
||||
#endif
|
||||
|
||||
static struct rt_device_pin _hw_pin;
|
||||
static rt_size_t _pin_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
|
||||
{
|
||||
struct rt_device_pin_status *status;
|
||||
struct rt_device_pin *pin = (struct rt_device_pin *)dev;
|
||||
|
||||
/* check parameters */
|
||||
RT_ASSERT(pin != RT_NULL);
|
||||
|
||||
status = (struct rt_device_pin_status *) buffer;
|
||||
if (status == RT_NULL || size != sizeof(*status)) return 0;
|
||||
|
||||
status->status = pin->ops->pin_read(dev, status->pin);
|
||||
return size;
|
||||
}
|
||||
|
||||
static rt_size_t _pin_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
|
||||
{
|
||||
struct rt_device_pin_status *status;
|
||||
struct rt_device_pin *pin = (struct rt_device_pin *)dev;
|
||||
|
||||
/* check parameters */
|
||||
RT_ASSERT(pin != RT_NULL);
|
||||
|
||||
status = (struct rt_device_pin_status *) buffer;
|
||||
if (status == RT_NULL || size != sizeof(*status)) return 0;
|
||||
|
||||
pin->ops->pin_write(dev, (rt_base_t)status->pin, (rt_base_t)status->status);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static rt_err_t _pin_control(rt_device_t dev, int cmd, void *args)
|
||||
{
|
||||
struct rt_device_pin_mode *mode;
|
||||
struct rt_device_pin *pin = (struct rt_device_pin *)dev;
|
||||
|
||||
/* check parameters */
|
||||
RT_ASSERT(pin != RT_NULL);
|
||||
|
||||
mode = (struct rt_device_pin_mode *) args;
|
||||
if (mode == RT_NULL) return -RT_ERROR;
|
||||
|
||||
pin->ops->pin_mode(dev, (rt_base_t)mode->pin, (rt_base_t)mode->mode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rt_device_pin_register(const char *name, const struct rt_pin_ops *ops, void *user_data)
|
||||
{
|
||||
_hw_pin.parent.type = RT_Device_Class_Miscellaneous;
|
||||
_hw_pin.parent.rx_indicate = RT_NULL;
|
||||
_hw_pin.parent.tx_complete = RT_NULL;
|
||||
|
||||
_hw_pin.parent.init = RT_NULL;
|
||||
_hw_pin.parent.open = RT_NULL;
|
||||
_hw_pin.parent.close = RT_NULL;
|
||||
_hw_pin.parent.read = _pin_read;
|
||||
_hw_pin.parent.write = _pin_write;
|
||||
_hw_pin.parent.control = _pin_control;
|
||||
|
||||
_hw_pin.ops = ops;
|
||||
_hw_pin.parent.user_data = user_data;
|
||||
|
||||
/* register a character device */
|
||||
rt_device_register(&_hw_pin.parent, name, RT_DEVICE_FLAG_RDWR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
rt_err_t rt_pin_attach_irq(rt_int32_t pin, rt_uint32_t mode,
|
||||
void (*hdr)(void *args), void *args)
|
||||
{
|
||||
RT_ASSERT(_hw_pin.ops != RT_NULL);
|
||||
if(_hw_pin.ops->pin_attach_irq)
|
||||
{
|
||||
return _hw_pin.ops->pin_attach_irq(&_hw_pin.parent, pin, mode, hdr, args);
|
||||
}
|
||||
return RT_ENOSYS;
|
||||
}
|
||||
rt_err_t rt_pin_dettach_irq(rt_int32_t pin)
|
||||
{
|
||||
RT_ASSERT(_hw_pin.ops != RT_NULL);
|
||||
if(_hw_pin.ops->pin_dettach_irq)
|
||||
{
|
||||
return _hw_pin.ops->pin_dettach_irq(&_hw_pin.parent, pin);
|
||||
}
|
||||
return RT_ENOSYS;
|
||||
}
|
||||
rt_err_t rt_pin_irq_enable(rt_base_t pin, rt_uint32_t enabled)
|
||||
{
|
||||
RT_ASSERT(_hw_pin.ops != RT_NULL);
|
||||
if(_hw_pin.ops->pin_irq_enable)
|
||||
{
|
||||
return _hw_pin.ops->pin_irq_enable(&_hw_pin.parent, pin, enabled);
|
||||
}
|
||||
return RT_ENOSYS;
|
||||
}
|
||||
/* RT-Thread Hardware PIN APIs */
|
||||
void rt_pin_mode(rt_base_t pin, rt_base_t mode)
|
||||
{
|
||||
RT_ASSERT(_hw_pin.ops != RT_NULL);
|
||||
_hw_pin.ops->pin_mode(&_hw_pin.parent, pin, mode);
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(rt_pin_mode, pinMode, set hardware pin mode);
|
||||
|
||||
void rt_pin_write(rt_base_t pin, rt_base_t value)
|
||||
{
|
||||
RT_ASSERT(_hw_pin.ops != RT_NULL);
|
||||
_hw_pin.ops->pin_write(&_hw_pin.parent, pin, value);
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(rt_pin_write, pinWrite, write value to hardware pin);
|
||||
|
||||
int rt_pin_read(rt_base_t pin)
|
||||
{
|
||||
RT_ASSERT(_hw_pin.ops != RT_NULL);
|
||||
return _hw_pin.ops->pin_read(&_hw_pin.parent, pin);
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(rt_pin_read, pinRead, read status from hardware pin);
|
||||
@@ -0,0 +1,444 @@
|
||||
/*
|
||||
* 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
|
||||
* 2014-12-31 bernard use open_flag for poll_tx stream mode.
|
||||
* 2015-05-19 Quintin fix DMA tx mod tx_dma->activated flag !=RT_FALSE BUG
|
||||
* in open function.
|
||||
* 2015-11-10 bernard fix the poll rx issue when there is no data.
|
||||
* 2016-05-10 armink add fifo mode to DMA rx when serial->config.bufsz != 0.
|
||||
* 2017-01-19 aubr.cool prevent change serial rx bufsz when serial is opened.
|
||||
* 2017-11-07 JasonJia fix data bits error issue when using tcsetattr.
|
||||
* 2017-11-15 JasonJia fix poll rx issue when data is full.
|
||||
* add TCFLSH and FIONREAD support.
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
// #define DEBUG_ENABLE
|
||||
#define DEBUG_LEVEL DBG_LOG
|
||||
#define DBG_SECTION_NAME "[UART]"
|
||||
#define DEBUG_COLOR
|
||||
#include <rtdbg.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);
|
||||
if (ch == -1) break;
|
||||
|
||||
*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.open_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();
|
||||
|
||||
/* there's no data: */
|
||||
if ((rx_fifo->get_index == rx_fifo->put_index) && (rx_fifo->is_full == RT_FALSE))
|
||||
{
|
||||
/* no data, enable interrupt and break out */
|
||||
rt_hw_interrupt_enable(level);
|
||||
break;
|
||||
}
|
||||
|
||||
/* otherwise there's the data: */
|
||||
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;
|
||||
|
||||
if (rx_fifo->is_full == RT_TRUE)
|
||||
{
|
||||
rx_fifo->is_full = RT_FALSE;
|
||||
}
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
*data = ch & 0xff;
|
||||
data ++; length --;
|
||||
}
|
||||
|
||||
return size - length;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
rt_uint16_t stream_flag = 0;
|
||||
struct rt_serial_device *serial;
|
||||
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
serial = (struct rt_serial_device *)dev;
|
||||
|
||||
dbg_log(DBG_LOG, "open serial device: 0x%08x with open flag: 0x%04x\n",
|
||||
dev, oflag);
|
||||
/* check device flag with the open flag */
|
||||
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;
|
||||
|
||||
/* keep steam flag */
|
||||
if ((oflag & RT_DEVICE_FLAG_STREAM) || (dev->open_flag & RT_DEVICE_FLAG_STREAM))
|
||||
stream_flag = RT_DEVICE_FLAG_STREAM;
|
||||
|
||||
/* 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_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, serial->config.bufsz);
|
||||
rx_fifo->put_index = 0;
|
||||
rx_fifo->get_index = 0;
|
||||
rx_fifo->is_full = RT_FALSE;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (oflag & RT_DEVICE_FLAG_INT_RX)
|
||||
dev->open_flag |= RT_DEVICE_FLAG_INT_RX;
|
||||
}
|
||||
|
||||
if (serial->serial_tx == RT_NULL)
|
||||
{
|
||||
|
||||
serial->serial_tx = RT_NULL;
|
||||
}
|
||||
|
||||
/* set stream flag */
|
||||
dev->open_flag |= stream_flag;
|
||||
|
||||
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_RX);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
return _serial_poll_tx(serial, buffer, size);
|
||||
}
|
||||
|
||||
static rt_err_t rt_serial_control(struct rt_device *dev,
|
||||
int cmd,
|
||||
void *args)
|
||||
{
|
||||
rt_err_t ret = RT_EOK;
|
||||
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:
|
||||
if (args)
|
||||
{
|
||||
struct serial_configure *pconfig = (struct serial_configure *) args;
|
||||
if (pconfig->bufsz != serial->config.bufsz && serial->parent.ref_count)
|
||||
{
|
||||
/*can not change buffer size*/
|
||||
return RT_EBUSY;
|
||||
}
|
||||
/* set serial configure */
|
||||
serial->config = *pconfig;
|
||||
if (serial->parent.ref_count)
|
||||
{
|
||||
/* serial device has been opened, to configure it */
|
||||
serial->ops->configure(serial, (struct serial_configure *) args);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default :
|
||||
/* control device */
|
||||
ret = serial->ops->control(serial, cmd, args);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* serial register
|
||||
*/
|
||||
rt_err_t rt_hw_serial_register(struct rt_serial_device *serial,
|
||||
const char *name,
|
||||
rt_uint32_t flag,
|
||||
void *data)
|
||||
{
|
||||
rt_err_t ret;
|
||||
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 */
|
||||
ret = rt_device_register(device, name, flag);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
/* interrupt mode receive */
|
||||
rx_fifo = (struct rt_serial_rx_fifo*)serial->serial_rx;
|
||||
RT_ASSERT(rx_fifo != RT_NULL);
|
||||
|
||||
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;
|
||||
rx_fifo->is_full = RT_TRUE;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
* File : finsh.h
|
||||
* COPYRIGHT (C) 2006 - 2018, 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
|
||||
* 2010-03-22 Bernard first version
|
||||
*/
|
||||
#ifndef __FINSH_H__
|
||||
#define __FINSH_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "finsh_api.h"
|
||||
|
||||
/* -- 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 -- */
|
||||
|
||||
/* std header file */
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#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 */
|
||||
/*@}*/
|
||||
|
||||
/* system call item */
|
||||
struct finsh_syscall_item
|
||||
{
|
||||
struct finsh_syscall_item* next; /* next item */
|
||||
struct finsh_syscall syscall; /* syscall */
|
||||
};
|
||||
extern struct finsh_syscall_item *global_syscall_list;
|
||||
|
||||
/* 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
|
||||
uint8_t 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);
|
||||
|
||||
|
||||
struct finsh_token
|
||||
{
|
||||
char eof;
|
||||
char replay;
|
||||
|
||||
int position;
|
||||
uint8_t current_token;
|
||||
|
||||
union {
|
||||
char char_value;
|
||||
int int_value;
|
||||
long long_value;
|
||||
} value;
|
||||
uint8_t string[FINSH_STRING_MAX];
|
||||
|
||||
uint8_t* line;
|
||||
};
|
||||
|
||||
#define FINSH_IDTYPE_VAR 0x01
|
||||
#define FINSH_IDTYPE_SYSVAR 0x02
|
||||
#define FINSH_IDTYPE_SYSCALL 0x04
|
||||
#define FINSH_IDTYPE_ADDRESS 0x08
|
||||
struct finsh_node
|
||||
{
|
||||
uint8_t node_type; /* node node_type */
|
||||
uint8_t data_type; /* node data node_type */
|
||||
uint8_t 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
|
||||
{
|
||||
uint8_t* 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 */
|
||||
uint8_t finsh_errno(void);
|
||||
/* get error string */
|
||||
const char* finsh_error_string(uint8_t 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, uint8_t type, void* addr);
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* File : finsh_api.h
|
||||
* COPYRIGHT (C) 2006 - 2018, 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
|
||||
* 2010-03-22 Bernard first version
|
||||
*/
|
||||
#ifndef FINSH_API_H__
|
||||
#define FINSH_API_H__
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma section("FSymTab$f",read)
|
||||
#pragma section("VSymTab",read)
|
||||
#endif
|
||||
|
||||
typedef long (*syscall_func)(void);
|
||||
|
||||
/* 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 */
|
||||
};
|
||||
extern struct finsh_syscall *_syscall_table_begin, *_syscall_table_end;
|
||||
|
||||
/* find out system call, which should be implemented in user program */
|
||||
struct finsh_syscall* finsh_syscall_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[] SECTION(".rodata.name") = #cmd; \
|
||||
const char __fsym_##cmd##_desc[] SECTION(".rodata.name") = #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[] SECTION(".rodata.name") = #name; \
|
||||
const char __vsym_##name##_desc[] SECTION(".rodata.name") = #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)
|
||||
#define MSH_CMD_EXPORT_ALIAS(command, alias, desc) \
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(command, __cmd_##alias, desc)
|
||||
#else
|
||||
#define MSH_CMD_EXPORT(command, desc)
|
||||
#define MSH_CMD_EXPORT_ALIAS(command, alias, desc)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,585 @@
|
||||
/*
|
||||
* 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.
|
||||
* 2017-07-19 Aubr.Cool limit argc to RT_FINSH_ARG_MAX
|
||||
*/
|
||||
|
||||
#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;
|
||||
rt_size_t i;
|
||||
|
||||
ptr = cmd;
|
||||
position = 0; argc = 0;
|
||||
|
||||
while (position < length)
|
||||
{
|
||||
/* strip bank and tab */
|
||||
while ((*ptr == ' ' || *ptr == '\t') && position < length)
|
||||
{
|
||||
*ptr = '\0';
|
||||
ptr ++; position ++;
|
||||
}
|
||||
|
||||
if(argc >= RT_FINSH_ARG_MAX)
|
||||
{
|
||||
rt_kprintf("Too many args ! We only Use:\n");
|
||||
for(i = 0; i < argc; i++)
|
||||
{
|
||||
rt_kprintf("%s ", argv[i]);
|
||||
}
|
||||
rt_kprintf("\n");
|
||||
break;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int ret = -RT_ENOMEM;
|
||||
char *cmd = rt_strdup(command);
|
||||
|
||||
if (cmd)
|
||||
{
|
||||
ret = msh_exec(cmd, rt_strlen(cmd));
|
||||
rt_free(cmd);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
RTM_EXPORT(system);
|
||||
#endif
|
||||
|
||||
static int _msh_exec_cmd(char *cmd, rt_size_t length, int *retp)
|
||||
{
|
||||
int argc;
|
||||
rt_size_t 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
|
||||
|
||||
#if defined(RT_USING_DFS) && defined(DFS_USING_WORKDIR)
|
||||
if (msh_exec_script(cmd, length) == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* change to this directory */
|
||||
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;
|
||||
|
||||
if (!path)
|
||||
return;
|
||||
|
||||
full_path = (char *)rt_malloc(256);
|
||||
if (full_path == RT_NULL) return; /* out of memory */
|
||||
|
||||
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
|
||||
{
|
||||
rt_size_t 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,42 @@
|
||||
/*
|
||||
* 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);
|
||||
|
||||
int msh_exec_module(const char *cmd_line, int size);
|
||||
int msh_exec_script(const char *cmd_line, int size);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,434 @@
|
||||
/*
|
||||
* internal commands for RT-Thread module shell
|
||||
*
|
||||
* COPYRIGHT (C) 2013-2015, 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
|
||||
* 2015-08-28 Bernard Add mkfs command.
|
||||
*/
|
||||
|
||||
#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
|
||||
{
|
||||
int fd;
|
||||
char *dest = RT_NULL;
|
||||
|
||||
rt_kprintf("%s => %s\n", argv[1], argv[2]);
|
||||
|
||||
fd = open(argv[2], O_DIRECTORY, 0);
|
||||
if (fd >= 0)
|
||||
{
|
||||
char *src;
|
||||
|
||||
close(fd);
|
||||
|
||||
/* it's a directory */
|
||||
dest = (char *)rt_malloc(DFS_PATH_MAX);
|
||||
if (dest == RT_NULL)
|
||||
{
|
||||
rt_kprintf("out of memory\n");
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
src = argv[1] + rt_strlen(argv[1]);
|
||||
while (src != argv[1])
|
||||
{
|
||||
if (*src == '/') break;
|
||||
src --;
|
||||
}
|
||||
|
||||
rt_snprintf(dest, DFS_PATH_MAX - 1, "%s/%s", argv[2], src);
|
||||
}
|
||||
else
|
||||
{
|
||||
fd = open(argv[2], O_RDONLY, 0);
|
||||
if (fd >= 0)
|
||||
{
|
||||
close(fd);
|
||||
|
||||
unlink(argv[2]);
|
||||
}
|
||||
|
||||
dest = argv[2];
|
||||
}
|
||||
|
||||
rename(argv[1], dest);
|
||||
if (dest != RT_NULL && dest != argv[2]) rt_free(dest);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (chdir(argv[1]) != 0)
|
||||
{
|
||||
rt_kprintf("No such directory: %s\n", 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.);
|
||||
|
||||
int cmd_mkfs(int argc, char **argv)
|
||||
{
|
||||
int result = 0;
|
||||
char *type = "elm"; /* use the default file system type as 'fatfs' */
|
||||
|
||||
if (argc == 2)
|
||||
{
|
||||
result = dfs_mkfs(type, argv[1]);
|
||||
}
|
||||
else if (argc == 4)
|
||||
{
|
||||
if (strcmp(argv[1], "-t") == 0)
|
||||
{
|
||||
type = argv[2];
|
||||
result = dfs_mkfs(type, argv[3]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("Usage: mkfs [-t type] device\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
rt_kprintf("mkfs failed, result=%d\n", result);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(cmd_mkfs, __cmd_mkfs, format disk with file system);
|
||||
|
||||
extern int df(const char *path);
|
||||
int cmd_df(int argc, char** argv)
|
||||
{
|
||||
if (argc != 2)
|
||||
{
|
||||
df("/");
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((strcmp(argv[1], "--help") == 0) || (strcmp(argv[1], "-h") == 0))
|
||||
{
|
||||
rt_kprintf("df [path]\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
df(argv[1]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(cmd_df, __cmd_df, disk free);
|
||||
|
||||
int cmd_echo(int argc, char** argv)
|
||||
{
|
||||
if (argc == 2)
|
||||
{
|
||||
rt_kprintf("%s\n", argv[1]);
|
||||
}
|
||||
else if (argc == 3)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = open(argv[2], O_RDWR | O_APPEND | O_CREAT, 0);
|
||||
if (fd >= 0)
|
||||
{
|
||||
write (fd, argv[1], strlen(argv[1]));
|
||||
close(fd);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("open file:%s failed!\n", argv[2]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("Usage: echo \"string\" [filename]\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(cmd_echo, __cmd_echo, echo string to file);
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_LWIP
|
||||
int cmd_ifconfig(int argc, char **argv)
|
||||
{
|
||||
extern void list_if(void);
|
||||
extern void set_if(char *netif_name, char *ip_addr, char *gw_addr, char *nm_addr);
|
||||
|
||||
|
||||
if (argc == 1)
|
||||
{
|
||||
list_if();
|
||||
}
|
||||
else if (argc == 5)
|
||||
{
|
||||
rt_kprintf("config : %s\n", argv[1]);
|
||||
rt_kprintf("IP addr: %s\n", argv[2]);
|
||||
rt_kprintf("Gateway: %s\n", argv[3]);
|
||||
rt_kprintf("netmask: %s\n", argv[4]);
|
||||
set_if(argv[1], argv[2], argv[3], argv[4]);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("bad parameter! e.g: ifconfig e0 192.168.1.30 192.168.1.1 255.255.255.0\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(cmd_ifconfig, __cmd_ifconfig, list the information of network interfaces);
|
||||
|
||||
#ifdef RT_LWIP_DNS
|
||||
#include <lwip/api.h>
|
||||
#include <lwip/dns.h>
|
||||
#include <lwip/ip_addr.h>
|
||||
#include <lwip/init.h>
|
||||
|
||||
int cmd_dns(int argc, char **argv)
|
||||
{
|
||||
extern void set_dns(char* dns_server);
|
||||
|
||||
if (argc == 1)
|
||||
{
|
||||
int index;
|
||||
|
||||
#if (LWIP_VERSION) < 0x02000000U
|
||||
ip_addr_t ip_addr;
|
||||
for(index=0; index<DNS_MAX_SERVERS; index++)
|
||||
{
|
||||
ip_addr = dns_getserver(index);
|
||||
rt_kprintf("dns server #%d: %s\n", index, ipaddr_ntoa(&ip_addr));
|
||||
}
|
||||
#else
|
||||
const ip_addr_t *ip_addr;
|
||||
for(index=0; index<DNS_MAX_SERVERS; index++)
|
||||
{
|
||||
ip_addr = dns_getserver(index);
|
||||
rt_kprintf("dns server #%d: %s\n", index, ipaddr_ntoa(ip_addr));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if (argc == 2)
|
||||
{
|
||||
rt_kprintf("dns : %s\n", argv[1]);
|
||||
set_dns(argv[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("bad parameter! e.g: dns 114.114.114.114\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(cmd_dns, __cmd_dns, list the information of dns);
|
||||
#endif
|
||||
|
||||
#ifdef RT_LWIP_TCP
|
||||
int cmd_netstat(int argc, char **argv)
|
||||
{
|
||||
extern void list_tcps(void);
|
||||
|
||||
list_tcps();
|
||||
return 0;
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(cmd_netstat, __cmd_netstat, list the information of TCP / IP);
|
||||
#endif
|
||||
#endif /* RT_USING_LWIP */
|
||||
|
||||
int cmd_ps(int argc, char **argv)
|
||||
{
|
||||
extern long list_thread(void);
|
||||
extern int list_module(void);
|
||||
|
||||
#ifdef RT_USING_MODULE
|
||||
if ((argc == 2) && (strcmp(argv[1], "-m") == 0))
|
||||
list_module();
|
||||
else
|
||||
#endif
|
||||
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);
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
int cmd_free(int argc, char **argv)
|
||||
{
|
||||
extern void list_mem(void);
|
||||
extern void list_memheap(void);
|
||||
|
||||
#ifdef RT_USING_MEMHEAP_AS_HEAP
|
||||
list_memheap();
|
||||
#else
|
||||
list_mem();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(cmd_free, __cmd_free, Show the memory usage in the system);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* script for RT-Thread module shell
|
||||
*
|
||||
* COPYRIGHT (C) 2013-2015, 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
|
||||
* 2015-09-25 Bernard the first verion for FinSH
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <finsh.h>
|
||||
|
||||
#include "msh.h"
|
||||
|
||||
#if defined(FINSH_USING_MSH) && defined(RT_USING_DFS)
|
||||
#include <dfs_posix.h>
|
||||
|
||||
static int msh_readline(int fd, char *line_buf, int size)
|
||||
{
|
||||
char ch;
|
||||
int index = 0;
|
||||
|
||||
do
|
||||
{
|
||||
if (read(fd, &ch, 1) != 1)
|
||||
{
|
||||
/* nothing in this file */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
while (ch == '\n' || ch == '\r');
|
||||
|
||||
/* set the first character */
|
||||
line_buf[index ++] = ch;
|
||||
|
||||
while (index < size)
|
||||
{
|
||||
if (read(fd, &ch, 1) == 1)
|
||||
{
|
||||
if (ch == '\n' || ch == '\r')
|
||||
{
|
||||
line_buf[index] = '\0';
|
||||
break;
|
||||
}
|
||||
|
||||
line_buf[index++] = ch;
|
||||
}
|
||||
else
|
||||
{
|
||||
line_buf[index] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
int msh_exec_script(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, ".sh") != RT_NULL || strstr(pg_name, ".SH") != 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);
|
||||
}
|
||||
}
|
||||
|
||||
rt_free(pg_name);
|
||||
if (fd >= 0)
|
||||
{
|
||||
/* found script */
|
||||
char *line_buf;
|
||||
int length;
|
||||
|
||||
line_buf = (char *) rt_malloc(RT_CONSOLEBUF_SIZE);
|
||||
|
||||
/* read line by line and then exec it */
|
||||
do
|
||||
{
|
||||
length = msh_readline(fd, line_buf, RT_CONSOLEBUF_SIZE);
|
||||
if (length > 0)
|
||||
{
|
||||
char ch = '\0';
|
||||
int index;
|
||||
|
||||
for (index = 0; index < length; index ++)
|
||||
{
|
||||
ch = line_buf[index];
|
||||
if (ch == ' ' || ch == '\t') continue;
|
||||
else break;
|
||||
}
|
||||
|
||||
if (ch != '#') /* not a comment */
|
||||
msh_exec(line_buf, length);
|
||||
}
|
||||
}
|
||||
while (length > 0);
|
||||
|
||||
close(fd);
|
||||
rt_free(line_buf);
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,798 @@
|
||||
/*
|
||||
* 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.
|
||||
* 2016-11-26 armink add password authentication
|
||||
*/
|
||||
|
||||
#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 */
|
||||
#ifndef RT_USING_HEAP
|
||||
static struct rt_thread finsh_thread;
|
||||
ALIGN(RT_ALIGN_SIZE)
|
||||
static char finsh_thread_stack[FINSH_THREAD_STACK_SIZE];
|
||||
#endif
|
||||
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);
|
||||
|
||||
#if defined(RT_USING_DFS) && defined(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 char finsh_getchar(void)
|
||||
{
|
||||
#ifdef RT_USING_POSIX
|
||||
return getchar();
|
||||
#else
|
||||
char ch;
|
||||
|
||||
RT_ASSERT(shell != RT_NULL);
|
||||
while (rt_device_read(shell->device, -1, &ch, 1) != 1)
|
||||
rt_sem_take(&shell->rx_sem, RT_WAITING_FOREVER);
|
||||
|
||||
return ch;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef RT_USING_POSIX
|
||||
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_DEVICE_FLAG_STREAM) == RT_EOK)
|
||||
{
|
||||
if (shell->device != RT_NULL)
|
||||
{
|
||||
/* close old finsh device */
|
||||
rt_device_close(shell->device);
|
||||
rt_device_set_rx_indicate(shell->device, RT_NULL);
|
||||
}
|
||||
|
||||
/* clear line buffer before switch to new device */
|
||||
memset(shell->line, 0, sizeof(shell->line));
|
||||
shell->line_curpos = shell->line_position = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
#ifdef FINSH_USING_AUTH
|
||||
/**
|
||||
* set a new password for finsh
|
||||
*
|
||||
* @param password new password
|
||||
*
|
||||
* @return result, RT_EOK on OK, -RT_ERROR on the new password length is less than
|
||||
* FINSH_PASSWORD_MIN or greater than FINSH_PASSWORD_MAX
|
||||
*/
|
||||
rt_err_t finsh_set_password(const char *password) {
|
||||
rt_ubase_t level;
|
||||
rt_size_t pw_len = rt_strlen(password);
|
||||
|
||||
if (pw_len < FINSH_PASSWORD_MIN || pw_len > FINSH_PASSWORD_MAX)
|
||||
return -RT_ERROR;
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
rt_strncpy(shell->password, password, FINSH_PASSWORD_MAX);
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the finsh password
|
||||
*
|
||||
* @return password
|
||||
*/
|
||||
const char *finsh_get_password(void)
|
||||
{
|
||||
return shell->password;
|
||||
}
|
||||
|
||||
static void finsh_wait_auth(void)
|
||||
{
|
||||
char ch;
|
||||
rt_bool_t input_finish = RT_FALSE;
|
||||
char password[FINSH_PASSWORD_MAX] = { 0 };
|
||||
rt_size_t cur_pos = 0;
|
||||
/* password not set */
|
||||
if (rt_strlen(finsh_get_password()) == 0) return;
|
||||
|
||||
while (1)
|
||||
{
|
||||
rt_kprintf("Password for login: ");
|
||||
while (!input_finish)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
/* read one character from device */
|
||||
ch = finsh_getchar();
|
||||
|
||||
if (ch >= ' ' && ch <= '~' && cur_pos < FINSH_PASSWORD_MAX)
|
||||
{
|
||||
/* change the printable characters to '*' */
|
||||
rt_kprintf("*");
|
||||
password[cur_pos++] = ch;
|
||||
}
|
||||
else if (ch == '\b' && cur_pos > 0)
|
||||
{
|
||||
/* backspace */
|
||||
password[cur_pos] = '\0';
|
||||
cur_pos--;
|
||||
rt_kprintf("\b \b");
|
||||
}
|
||||
else if (ch == '\r' || ch == '\n')
|
||||
{
|
||||
rt_kprintf("\n");
|
||||
input_finish = RT_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!rt_strncmp(shell->password, password, FINSH_PASSWORD_MAX)) return;
|
||||
else
|
||||
{
|
||||
/* authentication failed, delay 2S for retry */
|
||||
rt_thread_delay(2 * RT_TICK_PER_SECOND);
|
||||
rt_kprintf("Sorry, try again.\n");
|
||||
cur_pos = 0;
|
||||
input_finish = RT_FALSE;
|
||||
rt_memset(password, '\0', FINSH_PASSWORD_MAX);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* FINSH_USING_AUTH */
|
||||
|
||||
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;
|
||||
|
||||
if(shell->echo_mode)
|
||||
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)
|
||||
{
|
||||
/* if current cmd is same as last cmd, don't push */
|
||||
if (memcmp(&shell->cmd_history[FINSH_HISTORY_LINES - 1], shell->line, FINSH_CMD_SIZE))
|
||||
{
|
||||
/* 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
|
||||
{
|
||||
/* if current cmd is same as last cmd, don't push */
|
||||
if (shell->history_count == 0 || memcmp(&shell->cmd_history[shell->history_count - 1], shell->line, FINSH_CMD_SIZE))
|
||||
{
|
||||
shell->current_history = shell->history_count;
|
||||
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 */
|
||||
#ifndef FINSH_ECHO_DISABLE_DEFAULT
|
||||
shell->echo_mode = 1;
|
||||
#else
|
||||
shell->echo_mode = 0;
|
||||
#endif
|
||||
|
||||
#ifndef FINSH_USING_MSH_ONLY
|
||||
finsh_init(&shell->parser);
|
||||
#endif
|
||||
|
||||
#ifndef RT_USING_POSIX
|
||||
/* set console device as shell device */
|
||||
if (shell->device == RT_NULL)
|
||||
{
|
||||
rt_device_t console = rt_console_get_device();
|
||||
if (console)
|
||||
{
|
||||
finsh_set_device(console->parent.name);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef FINSH_USING_AUTH
|
||||
/* set the default password when the password isn't setting */
|
||||
if (rt_strlen(finsh_get_password()) == 0)
|
||||
{
|
||||
if (finsh_set_password(FINSH_DEFAULT_PASSWORD) != RT_EOK)
|
||||
{
|
||||
rt_kprintf("Finsh password set failed.\n");
|
||||
}
|
||||
}
|
||||
/* waiting authenticate success */
|
||||
finsh_wait_auth();
|
||||
#endif
|
||||
|
||||
rt_kprintf(FINSH_PROMPT);
|
||||
|
||||
while (1)
|
||||
{
|
||||
ch = finsh_getchar();
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* received null or error */
|
||||
if (ch == '\0' || ch == 0xFF) continue;
|
||||
/* 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)
|
||||
{
|
||||
if (shell->echo_mode)
|
||||
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
|
||||
if (shell->echo_mode) rt_kprintf("\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
rt_kprintf(FINSH_PROMPT);
|
||||
memset(shell->line, 0, sizeof(shell->line));
|
||||
shell->line_curpos = shell->line_position = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
if (shell->echo_mode)
|
||||
rt_kprintf("%c", ch);
|
||||
}
|
||||
|
||||
ch = 0;
|
||||
shell->line_position ++;
|
||||
shell->line_curpos++;
|
||||
if (shell->line_position >= FINSH_CMD_SIZE)
|
||||
{
|
||||
/* 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__) || defined(__ICCRX__) /* 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 = RT_EOK;
|
||||
rt_thread_t tid;
|
||||
|
||||
#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__) || defined(__ICCRX__) /* 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
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
/* create or set shell structure */
|
||||
shell = (struct finsh_shell *)rt_calloc(1, sizeof(struct finsh_shell));
|
||||
if (shell == RT_NULL)
|
||||
{
|
||||
rt_kprintf("no memory for shell\n");
|
||||
return -1;
|
||||
}
|
||||
tid = rt_thread_create(FINSH_THREAD_NAME,
|
||||
finsh_thread_entry, RT_NULL,
|
||||
FINSH_THREAD_STACK_SIZE, FINSH_THREAD_PRIORITY, 10);
|
||||
#else
|
||||
shell = &_shell;
|
||||
tid = &finsh_thread;
|
||||
result = rt_thread_init(&finsh_thread,
|
||||
FINSH_THREAD_NAME,
|
||||
finsh_thread_entry, RT_NULL,
|
||||
&finsh_thread_stack[0], sizeof(finsh_thread_stack),
|
||||
FINSH_THREAD_PRIORITY, 10);
|
||||
#endif /* RT_USING_HEAP */
|
||||
|
||||
rt_sem_init(&(shell->rx_sem), "shrx", 0, 0);
|
||||
|
||||
if (tid != NULL && result == RT_EOK)
|
||||
rt_thread_startup(tid);
|
||||
return 0;
|
||||
}
|
||||
INIT_APP_EXPORT(finsh_system_init);
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
#ifndef FINSH_THREAD_PRIORITY
|
||||
#define FINSH_THREAD_PRIORITY 20
|
||||
#endif
|
||||
#ifndef FINSH_THREAD_STACK_SIZE
|
||||
#define FINSH_THREAD_STACK_SIZE 2048
|
||||
#endif
|
||||
#ifndef FINSH_CMD_SIZE
|
||||
#define FINSH_CMD_SIZE 80
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
#ifdef FINSH_USING_AUTH
|
||||
#ifndef FINSH_PASSWORD_MAX
|
||||
#define FINSH_PASSWORD_MAX RT_NAME_MAX
|
||||
#endif
|
||||
#ifndef FINSH_PASSWORD_MIN
|
||||
#define FINSH_PASSWORD_MIN 6
|
||||
#endif
|
||||
#ifndef FINSH_DEFAULT_PASSWORD
|
||||
#define FINSH_DEFAULT_PASSWORD "rtthread"
|
||||
#endif
|
||||
#endif /* FINSH_USING_AUTH */
|
||||
|
||||
#ifndef FINSH_THREAD_NAME
|
||||
#define FINSH_THREAD_NAME "tshell"
|
||||
#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;
|
||||
|
||||
#ifndef RT_USING_POSIX
|
||||
rt_device_t device;
|
||||
#endif
|
||||
|
||||
#ifdef FINSH_USING_AUTH
|
||||
char password[FINSH_PASSWORD_MAX];
|
||||
#endif
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
#ifdef FINSH_USING_AUTH
|
||||
rt_err_t finsh_set_password(const char *password);
|
||||
const char *finsh_get_password(void);
|
||||
#endif
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef LIBC_DIRENT_H__
|
||||
#define LIBC_DIRENT_H__
|
||||
|
||||
#define DT_UNKNOWN 0x00
|
||||
#define DT_REG 0x01
|
||||
#define DT_DIR 0x02
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2016-11-12 Bernard The first version
|
||||
*/
|
||||
|
||||
#ifndef LIBC_ERRNO_H__
|
||||
#define LIBC_ERRNO_H__
|
||||
|
||||
#include <rtconfig.h>
|
||||
|
||||
#if defined(RT_USING_NEWLIB) || defined(_WIN32)
|
||||
/* use errno.h file in toolchains */
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#if defined(__CC_ARM)
|
||||
/*
|
||||
defined in armcc/errno.h
|
||||
|
||||
#define EDOM 1
|
||||
#define ERANGE 2
|
||||
#define EILSEQ 4
|
||||
#define ESIGNUM 3
|
||||
#define EINVAL 5
|
||||
#define ENOMEM 6
|
||||
*/
|
||||
#define ERROR_BASE_NO 7
|
||||
|
||||
#elif defined(__IAR_SYSTEMS_ICC__)
|
||||
/* defined in iar/errno.h
|
||||
#define EDOM 33
|
||||
#define ERANGE 34
|
||||
#define EFPOS 35
|
||||
#define EILSEQ 36
|
||||
*/
|
||||
#define ERROR_BASE_NO 36
|
||||
|
||||
#else
|
||||
|
||||
#define ERROR_BASE_NO 0
|
||||
#endif
|
||||
|
||||
#if !defined(RT_USING_NEWLIB) && !defined(_WIN32)
|
||||
|
||||
#define EPERM (ERROR_BASE_NO + 1)
|
||||
#define ENOENT (ERROR_BASE_NO + 2)
|
||||
#define ESRCH (ERROR_BASE_NO + 3)
|
||||
#define EINTR (ERROR_BASE_NO + 4)
|
||||
#define EIO (ERROR_BASE_NO + 5)
|
||||
#define ENXIO (ERROR_BASE_NO + 6)
|
||||
#define E2BIG (ERROR_BASE_NO + 7)
|
||||
#define ENOEXEC (ERROR_BASE_NO + 8)
|
||||
#define EBADF (ERROR_BASE_NO + 9)
|
||||
#define ECHILD (ERROR_BASE_NO + 10)
|
||||
#define EAGAIN (ERROR_BASE_NO + 11)
|
||||
|
||||
#ifndef ENOMEM
|
||||
#define ENOMEM (ERROR_BASE_NO + 12)
|
||||
#endif
|
||||
|
||||
#define EACCES (ERROR_BASE_NO + 13)
|
||||
#define EFAULT (ERROR_BASE_NO + 14)
|
||||
#define ENOTBLK (ERROR_BASE_NO + 15)
|
||||
#define EBUSY (ERROR_BASE_NO + 16)
|
||||
#define EEXIST (ERROR_BASE_NO + 17)
|
||||
#define EXDEV (ERROR_BASE_NO + 18)
|
||||
#define ENODEV (ERROR_BASE_NO + 19)
|
||||
#define ENOTDIR (ERROR_BASE_NO + 20)
|
||||
#define EISDIR (ERROR_BASE_NO + 21)
|
||||
|
||||
#ifndef EINVAL
|
||||
#define EINVAL (ERROR_BASE_NO + 22)
|
||||
#endif
|
||||
|
||||
#define ENFILE (ERROR_BASE_NO + 23)
|
||||
#define EMFILE (ERROR_BASE_NO + 24)
|
||||
#define ENOTTY (ERROR_BASE_NO + 25)
|
||||
#define ETXTBSY (ERROR_BASE_NO + 26)
|
||||
#define EFBIG (ERROR_BASE_NO + 27)
|
||||
#define ENOSPC (ERROR_BASE_NO + 28)
|
||||
#define ESPIPE (ERROR_BASE_NO + 29)
|
||||
#define EROFS (ERROR_BASE_NO + 30)
|
||||
#define EMLINK (ERROR_BASE_NO + 31)
|
||||
#define EPIPE (ERROR_BASE_NO + 32)
|
||||
|
||||
#ifndef EDOM
|
||||
#define EDOM (ERROR_BASE_NO + 33)
|
||||
#endif
|
||||
|
||||
#ifndef ERANGE
|
||||
#define ERANGE (ERROR_BASE_NO + 34)
|
||||
#endif
|
||||
|
||||
#define EDEADLK (ERROR_BASE_NO + 35)
|
||||
#define ENAMETOOLONG (ERROR_BASE_NO + 36)
|
||||
#define ENOLCK (ERROR_BASE_NO + 37)
|
||||
#define ENOSYS (ERROR_BASE_NO + 38)
|
||||
#define ENOTEMPTY (ERROR_BASE_NO + 39)
|
||||
#define ELOOP (ERROR_BASE_NO + 40)
|
||||
#define EWOULDBLOCK EAGAIN
|
||||
#define ENOMSG (ERROR_BASE_NO + 42)
|
||||
#define EIDRM (ERROR_BASE_NO + 43)
|
||||
#define ECHRNG (ERROR_BASE_NO + 44)
|
||||
#define EL2NSYNC (ERROR_BASE_NO + 45)
|
||||
#define EL3HLT (ERROR_BASE_NO + 46)
|
||||
#define EL3RST (ERROR_BASE_NO + 47)
|
||||
#define ELNRNG (ERROR_BASE_NO + 48)
|
||||
#define EUNATCH (ERROR_BASE_NO + 49)
|
||||
#define ENOCSI (ERROR_BASE_NO + 50)
|
||||
#define EL2HLT (ERROR_BASE_NO + 51)
|
||||
#define EBADE (ERROR_BASE_NO + 52)
|
||||
#define EBADR (ERROR_BASE_NO + 53)
|
||||
#define EXFULL (ERROR_BASE_NO + 54)
|
||||
#define ENOANO (ERROR_BASE_NO + 55)
|
||||
#define EBADRQC (ERROR_BASE_NO + 56)
|
||||
#define EBADSLT (ERROR_BASE_NO + 57)
|
||||
#define EDEADLOCK EDEADLK
|
||||
#define EBFONT (ERROR_BASE_NO + 59)
|
||||
#define ENOSTR (ERROR_BASE_NO + 60)
|
||||
#define ENODATA (ERROR_BASE_NO + 61)
|
||||
#define ETIME (ERROR_BASE_NO + 62)
|
||||
#define ENOSR (ERROR_BASE_NO + 63)
|
||||
#define ENONET (ERROR_BASE_NO + 64)
|
||||
#define ENOPKG (ERROR_BASE_NO + 65)
|
||||
#define EREMOTE (ERROR_BASE_NO + 66)
|
||||
#define ENOLINK (ERROR_BASE_NO + 67)
|
||||
#define EADV (ERROR_BASE_NO + 68)
|
||||
#define ESRMNT (ERROR_BASE_NO + 69)
|
||||
#define ECOMM (ERROR_BASE_NO + 70)
|
||||
#define EPROTO (ERROR_BASE_NO + 71)
|
||||
#define EMULTIHOP (ERROR_BASE_NO + 72)
|
||||
#define EDOTDOT (ERROR_BASE_NO + 73)
|
||||
#define EBADMSG (ERROR_BASE_NO + 74)
|
||||
#define EOVERFLOW (ERROR_BASE_NO + 75)
|
||||
#define ENOTUNIQ (ERROR_BASE_NO + 76)
|
||||
#define EBADFD (ERROR_BASE_NO + 77)
|
||||
#define EREMCHG (ERROR_BASE_NO + 78)
|
||||
#define ELIBACC (ERROR_BASE_NO + 79)
|
||||
#define ELIBBAD (ERROR_BASE_NO + 80)
|
||||
#define ELIBSCN (ERROR_BASE_NO + 81)
|
||||
#define ELIBMAX (ERROR_BASE_NO + 82)
|
||||
#define ELIBEXEC (ERROR_BASE_NO + 83)
|
||||
|
||||
#ifndef EILSEQ
|
||||
#define EILSEQ (ERROR_BASE_NO + 84)
|
||||
#endif
|
||||
|
||||
#define ERESTART (ERROR_BASE_NO + 85)
|
||||
#define ESTRPIPE (ERROR_BASE_NO + 86)
|
||||
#define EUSERS (ERROR_BASE_NO + 87)
|
||||
#define ENOTSOCK (ERROR_BASE_NO + 88)
|
||||
#define EDESTADDRREQ (ERROR_BASE_NO + 89)
|
||||
#define EMSGSIZE (ERROR_BASE_NO + 90)
|
||||
#define EPROTOTYPE (ERROR_BASE_NO + 91)
|
||||
#define ENOPROTOOPT (ERROR_BASE_NO + 92)
|
||||
#define EPROTONOSUPPORT (ERROR_BASE_NO + 93)
|
||||
#define ESOCKTNOSUPPORT (ERROR_BASE_NO + 94)
|
||||
#define EOPNOTSUPP (ERROR_BASE_NO + 95)
|
||||
#define ENOTSUP EOPNOTSUPP
|
||||
#define EPFNOSUPPORT (ERROR_BASE_NO + 96)
|
||||
#define EAFNOSUPPORT (ERROR_BASE_NO + 97)
|
||||
#define EADDRINUSE (ERROR_BASE_NO + 98)
|
||||
#define EADDRNOTAVAIL (ERROR_BASE_NO + 99)
|
||||
#define ENETDOWN (ERROR_BASE_NO + 100)
|
||||
#define ENETUNREACH (ERROR_BASE_NO + 101)
|
||||
#define ENETRESET (ERROR_BASE_NO + 102)
|
||||
#define ECONNABORTED (ERROR_BASE_NO + 103)
|
||||
#define ECONNRESET (ERROR_BASE_NO + 104)
|
||||
#define ENOBUFS (ERROR_BASE_NO + 105)
|
||||
#define EISCONN (ERROR_BASE_NO + 106)
|
||||
#define ENOTCONN (ERROR_BASE_NO + 107)
|
||||
#define ESHUTDOWN (ERROR_BASE_NO + 108)
|
||||
#define ETOOMANYREFS (ERROR_BASE_NO + 109)
|
||||
#define ETIMEDOUT (ERROR_BASE_NO + 110)
|
||||
#define ECONNREFUSED (ERROR_BASE_NO + 111)
|
||||
#define EHOSTDOWN (ERROR_BASE_NO + 112)
|
||||
#define EHOSTUNREACH (ERROR_BASE_NO + 113)
|
||||
#define EALREADY (ERROR_BASE_NO + 114)
|
||||
#define EINPROGRESS (ERROR_BASE_NO + 115)
|
||||
#define ESTALE (ERROR_BASE_NO + 116)
|
||||
#define EUCLEAN (ERROR_BASE_NO + 117)
|
||||
#define ENOTNAM (ERROR_BASE_NO + 118)
|
||||
#define ENAVAIL (ERROR_BASE_NO + 119)
|
||||
#define EISNAM (ERROR_BASE_NO + 120)
|
||||
#define EREMOTEIO (ERROR_BASE_NO + 121)
|
||||
#define EDQUOT (ERROR_BASE_NO + 122)
|
||||
#define ENOMEDIUM (ERROR_BASE_NO + 123)
|
||||
#define EMEDIUMTYPE (ERROR_BASE_NO + 124)
|
||||
#define ECANCELED (ERROR_BASE_NO + 125)
|
||||
#define ENOKEY (ERROR_BASE_NO + 126)
|
||||
#define EKEYEXPIRED (ERROR_BASE_NO + 127)
|
||||
#define EKEYREVOKED (ERROR_BASE_NO + 128)
|
||||
#define EKEYREJECTED (ERROR_BASE_NO + 129)
|
||||
#define EOWNERDEAD (ERROR_BASE_NO + 130)
|
||||
#define ENOTRECOVERABLE (ERROR_BASE_NO + 131)
|
||||
#define ERFKILL (ERROR_BASE_NO + 132)
|
||||
#define EHWPOISON (ERROR_BASE_NO + 133)
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* File : libc_fcntl.h
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2018-02-07 Bernard Add O_DIRECTORY definition in NEWLIB mode.
|
||||
* 2018-02-09 Bernard Add O_BINARY definition
|
||||
*/
|
||||
|
||||
#ifndef LIBC_FCNTL_H__
|
||||
#define LIBC_FCNTL_H__
|
||||
|
||||
#if defined(RT_USING_NEWLIB) || defined(_WIN32)
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifndef O_NONBLOCK
|
||||
#define O_NONBLOCK 0x4000
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define O_ACCMODE (_O_RDONLY | _O_WRONLY | _O_RDWR)
|
||||
#endif
|
||||
|
||||
#ifndef F_GETFL
|
||||
#define F_GETFL 3
|
||||
#endif
|
||||
#ifndef F_SETFL
|
||||
#define F_SETFL 4
|
||||
#endif
|
||||
|
||||
#ifndef O_DIRECTORY
|
||||
#define O_DIRECTORY 0x200000
|
||||
#endif
|
||||
|
||||
#ifndef O_BINARY
|
||||
#ifdef _O_BINARY
|
||||
#define O_BINARY _O_BINARY
|
||||
#else
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define O_RDONLY 00
|
||||
#define O_WRONLY 01
|
||||
#define O_RDWR 02
|
||||
|
||||
#define O_CREAT 0100
|
||||
#define O_EXCL 0200
|
||||
#define O_NOCTTY 0400
|
||||
#define O_TRUNC 01000
|
||||
#define O_APPEND 02000
|
||||
#define O_NONBLOCK 04000
|
||||
#define O_DSYNC 010000
|
||||
#define O_SYNC 04010000
|
||||
#define O_RSYNC 04010000
|
||||
#define O_BINARY 0100000
|
||||
#define O_DIRECTORY 0200000
|
||||
#define O_NOFOLLOW 0400000
|
||||
#define O_CLOEXEC 02000000
|
||||
|
||||
#define O_ASYNC 020000
|
||||
#define O_DIRECT 040000
|
||||
#define O_LARGEFILE 0100000
|
||||
#define O_NOATIME 01000000
|
||||
#define O_PATH 010000000
|
||||
#define O_TMPFILE 020200000
|
||||
#define O_NDELAY O_NONBLOCK
|
||||
|
||||
#define O_SEARCH O_PATH
|
||||
#define O_EXEC O_PATH
|
||||
|
||||
#define O_ACCMODE (03|O_SEARCH)
|
||||
|
||||
#define F_DUPFD 0
|
||||
#define F_GETFD 1
|
||||
#define F_SETFD 2
|
||||
#define F_GETFL 3
|
||||
#define F_SETFL 4
|
||||
|
||||
#define F_SETOWN 8
|
||||
#define F_GETOWN 9
|
||||
#define F_SETSIG 10
|
||||
#define F_GETSIG 11
|
||||
|
||||
#define F_GETLK 12
|
||||
#define F_SETLK 13
|
||||
#define F_SETLKW 14
|
||||
|
||||
#define F_SETOWN_EX 15
|
||||
#define F_GETOWN_EX 16
|
||||
|
||||
#define F_GETOWNER_UIDS 17
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* File : libc_errno.h
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2017-10-30 Bernard The first version
|
||||
*/
|
||||
|
||||
#ifndef LIBC_FDSET_H__
|
||||
#define LIBC_FDSET_H__
|
||||
|
||||
#include <rtconfig.h>
|
||||
|
||||
#if defined(RT_USING_NEWLIB) || defined(_WIN32)
|
||||
#include <sys/types.h>
|
||||
#if defined(HAVE_SYS_SELECT_H)
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#ifdef SAL_USING_POSIX
|
||||
|
||||
#ifdef FD_SETSIZE
|
||||
#undef FD_SETSIZE
|
||||
#endif
|
||||
|
||||
#define FD_SETSIZE DFS_FD_MAX
|
||||
#endif
|
||||
|
||||
# ifndef FD_SETSIZE
|
||||
# define FD_SETSIZE 32
|
||||
# endif
|
||||
|
||||
# define NBBY 8 /* number of bits in a byte */
|
||||
|
||||
typedef long fd_mask;
|
||||
# define NFDBITS (sizeof (fd_mask) * NBBY) /* bits per mask */
|
||||
# ifndef howmany
|
||||
# define howmany(x,y) (((x)+((y)-1))/(y))
|
||||
# endif
|
||||
|
||||
/* We use a macro for fd_set so that including Sockets.h afterwards
|
||||
can work. */
|
||||
typedef struct _types_fd_set {
|
||||
fd_mask fds_bits[howmany(FD_SETSIZE, NFDBITS)];
|
||||
} _types_fd_set;
|
||||
|
||||
#define fd_set _types_fd_set
|
||||
|
||||
# define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1L << ((n) % NFDBITS)))
|
||||
# define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1L << ((n) % NFDBITS)))
|
||||
# define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1L << ((n) % NFDBITS)))
|
||||
# define FD_ZERO(p) memset((void*)(p), 0, sizeof(*(p)))
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* File : libc_ioctl.h
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2017-01-21 Bernard the first version
|
||||
*/
|
||||
|
||||
#ifndef LIBC_IOCTL_H__
|
||||
#define LIBC_IOCTL_H__
|
||||
|
||||
#define _IOC(a,b,c,d) ( ((a)<<30) | ((b)<<8) | (c) | ((d)<<16) )
|
||||
#define _IOC_NONE 0U
|
||||
#define _IOC_WRITE 1U
|
||||
#define _IOC_READ 2U
|
||||
|
||||
#ifndef _WIN32
|
||||
#define _IO(a,b) _IOC(_IOC_NONE,(a),(b),0)
|
||||
#define _IOW(a,b,c) _IOC(_IOC_WRITE,(a),(b),sizeof(c))
|
||||
#define _IOR(a,b,c) _IOC(_IOC_READ,(a),(b),sizeof(c))
|
||||
#define _IOWR(a,b,c) _IOC(_IOC_READ|_IOC_WRITE,(a),(b),sizeof(c))
|
||||
|
||||
#define FIONREAD _IOR('f', 127, int) /* get # bytes to read */
|
||||
#define FIONBIO _IOW('f', 126, int) /* set/clear non-blocking i/o */
|
||||
#define FIONWRITE _IOR('f', 121, int) /* get # bytes outstanding
|
||||
* in send queue. */
|
||||
#endif
|
||||
|
||||
#define TCGETS 0x5401
|
||||
#define TCSETS 0x5402
|
||||
#define TCSETSW 0x5403
|
||||
#define TCSETSF 0x5404
|
||||
#define TCGETA 0x5405
|
||||
#define TCSETA 0x5406
|
||||
#define TCSETAW 0x5407
|
||||
#define TCSETAF 0x5408
|
||||
#define TCSBRK 0x5409
|
||||
#define TCXONC 0x540A
|
||||
#define TCFLSH 0x540B
|
||||
#define TIOCEXCL 0x540C
|
||||
#define TIOCNXCL 0x540D
|
||||
#define TIOCSCTTY 0x540E
|
||||
#define TIOCGPGRP 0x540F
|
||||
#define TIOCSPGRP 0x5410
|
||||
#define TIOCOUTQ 0x5411
|
||||
#define TIOCSTI 0x5412
|
||||
#define TIOCGWINSZ 0x5413
|
||||
#define TIOCSWINSZ 0x5414
|
||||
#define TIOCMGET 0x5415
|
||||
#define TIOCMBIS 0x5416
|
||||
#define TIOCMBIC 0x5417
|
||||
#define TIOCMSET 0x5418
|
||||
#define TIOCGSOFTCAR 0x5419
|
||||
#define TIOCSSOFTCAR 0x541A
|
||||
// #define FIONREAD 0x541B
|
||||
#define TIOCINQ FIONREAD
|
||||
#define TIOCLINUX 0x541C
|
||||
#define TIOCCONS 0x541D
|
||||
#define TIOCGSERIAL 0x541E
|
||||
#define TIOCSSERIAL 0x541F
|
||||
#define TIOCPKT 0x5420
|
||||
// #define FIONBIO 0x5421
|
||||
#define TIOCNOTTY 0x5422
|
||||
#define TIOCSETD 0x5423
|
||||
#define TIOCGETD 0x5424
|
||||
#define TCSBRKP 0x5425
|
||||
#define TIOCSBRK 0x5427
|
||||
#define TIOCCBRK 0x5428
|
||||
#define TIOCGSID 0x5429
|
||||
#define TIOCGRS485 0x542E
|
||||
#define TIOCSRS485 0x542F
|
||||
#define TIOCGPTN 0x80045430
|
||||
#define TIOCSPTLCK 0x40045431
|
||||
#define TIOCGDEV 0x80045432
|
||||
#define TCGETX 0x5432
|
||||
#define TCSETX 0x5433
|
||||
#define TCSETXF 0x5434
|
||||
#define TCSETXW 0x5435
|
||||
#define TIOCSIG 0x40045436
|
||||
#define TIOCVHANGUP 0x5437
|
||||
#define TIOCGPKT 0x80045438
|
||||
#define TIOCGPTLCK 0x80045439
|
||||
#define TIOCGEXCL 0x80045440
|
||||
|
||||
#define FIONCLEX 0x5450
|
||||
#define FIOCLEX 0x5451
|
||||
|
||||
#ifndef _WIN32
|
||||
#define FIOASYNC 0x5452
|
||||
#endif
|
||||
|
||||
#define TIOCSERCONFIG 0x5453
|
||||
#define TIOCSERGWILD 0x5454
|
||||
#define TIOCSERSWILD 0x5455
|
||||
#define TIOCGLCKTRMIOS 0x5456
|
||||
#define TIOCSLCKTRMIOS 0x5457
|
||||
#define TIOCSERGSTRUCT 0x5458
|
||||
#define TIOCSERGETLSR 0x5459
|
||||
#define TIOCSERGETMULTI 0x545A
|
||||
#define TIOCSERSETMULTI 0x545B
|
||||
|
||||
#define TIOCMIWAIT 0x545C
|
||||
#define TIOCGICOUNT 0x545D
|
||||
#define FIOQSIZE 0x5460
|
||||
|
||||
#define TIOCPKT_DATA 0
|
||||
#define TIOCPKT_FLUSHREAD 1
|
||||
#define TIOCPKT_FLUSHWRITE 2
|
||||
#define TIOCPKT_STOP 4
|
||||
#define TIOCPKT_START 8
|
||||
#define TIOCPKT_NOSTOP 16
|
||||
#define TIOCPKT_DOSTOP 32
|
||||
#define TIOCPKT_IOCTL 64
|
||||
|
||||
#define TIOCSER_TEMT 0x01
|
||||
|
||||
struct winsize {
|
||||
unsigned short ws_row;
|
||||
unsigned short ws_col;
|
||||
unsigned short ws_xpixel;
|
||||
unsigned short ws_ypixel;
|
||||
};
|
||||
|
||||
#define TIOCM_LE 0x001
|
||||
#define TIOCM_DTR 0x002
|
||||
#define TIOCM_RTS 0x004
|
||||
#define TIOCM_ST 0x008
|
||||
#define TIOCM_SR 0x010
|
||||
#define TIOCM_CTS 0x020
|
||||
#define TIOCM_CAR 0x040
|
||||
#define TIOCM_RNG 0x080
|
||||
#define TIOCM_DSR 0x100
|
||||
#define TIOCM_CD TIOCM_CAR
|
||||
#define TIOCM_RI TIOCM_RNG
|
||||
#define TIOCM_OUT1 0x2000
|
||||
#define TIOCM_OUT2 0x4000
|
||||
#define TIOCM_LOOP 0x8000
|
||||
|
||||
#define N_TTY 0
|
||||
#define N_SLIP 1
|
||||
#define N_MOUSE 2
|
||||
#define N_PPP 3
|
||||
#define N_STRIP 4
|
||||
#define N_AX25 5
|
||||
#define N_X25 6
|
||||
#define N_6PACK 7
|
||||
#define N_MASC 8
|
||||
#define N_R3964 9
|
||||
#define N_PROFIBUS_FDL 10
|
||||
#define N_IRDA 11
|
||||
#define N_SMSBLOCK 12
|
||||
#define N_HDLC 13
|
||||
#define N_SYNC_PPP 14
|
||||
#define N_HCI 15
|
||||
|
||||
#define FIOSETOWN 0x8901
|
||||
#define SIOCSPGRP 0x8902
|
||||
#define FIOGETOWN 0x8903
|
||||
#define SIOCGPGRP 0x8904
|
||||
// #define SIOCATMARK 0x8905
|
||||
#define SIOCGSTAMP 0x8906
|
||||
#define SIOCGSTAMPNS 0x8907
|
||||
|
||||
#define SIOCADDRT 0x890B
|
||||
#define SIOCDELRT 0x890C
|
||||
#define SIOCRTMSG 0x890D
|
||||
|
||||
#define SIOCGIFNAME 0x8910
|
||||
#define SIOCSIFLINK 0x8911
|
||||
#define SIOCGIFCONF 0x8912
|
||||
#define SIOCGIFFLAGS 0x8913
|
||||
#define SIOCSIFFLAGS 0x8914
|
||||
#define SIOCGIFADDR 0x8915
|
||||
#define SIOCSIFADDR 0x8916
|
||||
#define SIOCGIFDSTADDR 0x8917
|
||||
#define SIOCSIFDSTADDR 0x8918
|
||||
#define SIOCGIFBRDADDR 0x8919
|
||||
#define SIOCSIFBRDADDR 0x891a
|
||||
#define SIOCGIFNETMASK 0x891b
|
||||
#define SIOCSIFNETMASK 0x891c
|
||||
#define SIOCGIFMETRIC 0x891d
|
||||
#define SIOCSIFMETRIC 0x891e
|
||||
#define SIOCGIFMEM 0x891f
|
||||
#define SIOCSIFMEM 0x8920
|
||||
#define SIOCGIFMTU 0x8921
|
||||
#define SIOCSIFMTU 0x8922
|
||||
#define SIOCSIFNAME 0x8923
|
||||
#define SIOCSIFHWADDR 0x8924
|
||||
#define SIOCGIFENCAP 0x8925
|
||||
#define SIOCSIFENCAP 0x8926
|
||||
#define SIOCGIFHWADDR 0x8927
|
||||
#define SIOCGIFSLAVE 0x8929
|
||||
#define SIOCSIFSLAVE 0x8930
|
||||
#define SIOCADDMULTI 0x8931
|
||||
#define SIOCDELMULTI 0x8932
|
||||
#define SIOCGIFINDEX 0x8933
|
||||
#define SIOGIFINDEX SIOCGIFINDEX
|
||||
#define SIOCSIFPFLAGS 0x8934
|
||||
#define SIOCGIFPFLAGS 0x8935
|
||||
#define SIOCDIFADDR 0x8936
|
||||
#define SIOCSIFHWBROADCAST 0x8937
|
||||
#define SIOCGIFCOUNT 0x8938
|
||||
|
||||
#define SIOCGIFBR 0x8940
|
||||
#define SIOCSIFBR 0x8941
|
||||
|
||||
#define SIOCGIFTXQLEN 0x8942
|
||||
#define SIOCSIFTXQLEN 0x8943
|
||||
|
||||
#define SIOCDARP 0x8953
|
||||
#define SIOCGARP 0x8954
|
||||
#define SIOCSARP 0x8955
|
||||
|
||||
#define SIOCDRARP 0x8960
|
||||
#define SIOCGRARP 0x8961
|
||||
#define SIOCSRARP 0x8962
|
||||
|
||||
#define SIOCGIFMAP 0x8970
|
||||
#define SIOCSIFMAP 0x8971
|
||||
|
||||
#define SIOCADDDLCI 0x8980
|
||||
#define SIOCDELDLCI 0x8981
|
||||
|
||||
#define SIOCDEVPRIVATE 0x89F0
|
||||
#define SIOCPROTOPRIVATE 0x89E0
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2017-09-12 Bernard The first version
|
||||
*/
|
||||
|
||||
#ifndef LIBC_SIGNAL_H__
|
||||
#define LIBC_SIGNAL_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CCONFIG_H
|
||||
#include <cconfig.h>
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_SIGVAL
|
||||
/* Signal Generation and Delivery, P1003.1b-1993, p. 63
|
||||
NOTE: P1003.1c/D10, p. 34 adds sigev_notify_function and
|
||||
sigev_notify_attributes to the sigevent structure. */
|
||||
|
||||
union sigval
|
||||
{
|
||||
int sival_int; /* Integer signal value */
|
||||
void *sival_ptr; /* Pointer signal value */
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_SIGEVENT
|
||||
struct sigevent
|
||||
{
|
||||
int sigev_notify; /* Notification type */
|
||||
int sigev_signo; /* Signal number */
|
||||
union sigval sigev_value; /* Signal value */
|
||||
void (*sigev_notify_function)( union sigval );
|
||||
/* Notification function */
|
||||
void *sigev_notify_attributes; /* Notification Attributes, really pthread_attr_t */
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_SIGINFO
|
||||
struct siginfo
|
||||
{
|
||||
rt_uint16_t si_signo;
|
||||
rt_uint16_t si_code;
|
||||
|
||||
union sigval si_value;
|
||||
};
|
||||
typedef struct siginfo siginfo_t;
|
||||
#endif
|
||||
|
||||
#define SI_USER 0x01 /* Signal sent by kill(). */
|
||||
#define SI_QUEUE 0x02 /* Signal sent by sigqueue(). */
|
||||
#define SI_TIMER 0x03 /* Signal generated by expiration of a
|
||||
timer set by timer_settime(). */
|
||||
#define SI_ASYNCIO 0x04 /* Signal generated by completion of an
|
||||
asynchronous I/O request. */
|
||||
#define SI_MESGQ 0x05 /* Signal generated by arrival of a
|
||||
message on an empty message queue. */
|
||||
|
||||
#ifdef RT_USING_NEWLIB
|
||||
#include <sys/signal.h>
|
||||
#endif
|
||||
|
||||
#if defined(__CC_ARM) || defined(__CLANG_ARM)
|
||||
#include <signal.h>
|
||||
typedef unsigned long sigset_t;
|
||||
|
||||
#define SIGHUP 1
|
||||
/* #define SIGINT 2 */
|
||||
#define SIGQUIT 3
|
||||
/* #define SIGILL 4 */
|
||||
#define SIGTRAP 5
|
||||
/* #define SIGABRT 6 */
|
||||
#define SIGEMT 7
|
||||
/* #define SIGFPE 8 */
|
||||
#define SIGKILL 9
|
||||
#define SIGBUS 10
|
||||
/* #define SIGSEGV 11 */
|
||||
#define SIGSYS 12
|
||||
#define SIGPIPE 13
|
||||
#define SIGALRM 14
|
||||
/* #define SIGTERM 15 */
|
||||
#define SIGURG 16
|
||||
#define SIGSTOP 17
|
||||
#define SIGTSTP 18
|
||||
#define SIGCONT 19
|
||||
#define SIGCHLD 20
|
||||
#define SIGTTIN 21
|
||||
#define SIGTTOU 22
|
||||
#define SIGPOLL 23
|
||||
#define SIGWINCH 24
|
||||
/* #define SIGUSR1 25 */
|
||||
/* #define SIGUSR2 26 */
|
||||
#define SIGRTMIN 27
|
||||
#define SIGRTMAX 31
|
||||
#define NSIG 32
|
||||
|
||||
#define SIG_SETMASK 0 /* set mask with sigprocmask() */
|
||||
#define SIG_BLOCK 1 /* set of signals to block */
|
||||
#define SIG_UNBLOCK 2 /* set of signals to, well, unblock */
|
||||
|
||||
typedef void (*_sig_func_ptr)(int);
|
||||
|
||||
struct sigaction
|
||||
{
|
||||
_sig_func_ptr sa_handler;
|
||||
sigset_t sa_mask;
|
||||
int sa_flags;
|
||||
};
|
||||
|
||||
#define sigaddset(what,sig) (*(what) |= (1<<(sig)), 0)
|
||||
#define sigdelset(what,sig) (*(what) &= ~(1<<(sig)), 0)
|
||||
#define sigemptyset(what) (*(what) = 0, 0)
|
||||
#define sigfillset(what) (*(what) = ~(0), 0)
|
||||
#define sigismember(what,sig) (((*(what)) & (1<<(sig))) != 0)
|
||||
|
||||
int sigprocmask (int how, const sigset_t *set, sigset_t *oset);
|
||||
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
|
||||
|
||||
#elif defined(__IAR_SYSTEMS_ICC__)
|
||||
#include <signal.h>
|
||||
typedef unsigned long sigset_t;
|
||||
|
||||
#define SIGHUP 1
|
||||
#define SIGINT 2
|
||||
#define SIGQUIT 3
|
||||
#define SIGILL 4
|
||||
#define SIGTRAP 5
|
||||
/* #define SIGABRT 6 */
|
||||
#define SIGEMT 7
|
||||
#define SIGFPE 8
|
||||
#define SIGKILL 9
|
||||
#define SIGBUS 10
|
||||
#define SIGSEGV 11
|
||||
#define SIGSYS 12
|
||||
#define SIGPIPE 13
|
||||
#define SIGALRM 14
|
||||
#define SIGTERM 15
|
||||
#define SIGURG 16
|
||||
#define SIGSTOP 17
|
||||
#define SIGTSTP 18
|
||||
#define SIGCONT 19
|
||||
#define SIGCHLD 20
|
||||
#define SIGTTIN 21
|
||||
#define SIGTTOU 22
|
||||
#define SIGPOLL 23
|
||||
#define SIGWINCH 24
|
||||
#define SIGUSR1 25
|
||||
#define SIGUSR2 26
|
||||
#define SIGRTMIN 27
|
||||
#define SIGRTMAX 31
|
||||
#define NSIG 32
|
||||
|
||||
#define SIG_SETMASK 0 /* set mask with sigprocmask() */
|
||||
#define SIG_BLOCK 1 /* set of signals to block */
|
||||
#define SIG_UNBLOCK 2 /* set of signals to, well, unblock */
|
||||
|
||||
typedef void (*_sig_func_ptr)(int);
|
||||
|
||||
struct sigaction
|
||||
{
|
||||
_sig_func_ptr sa_handler;
|
||||
sigset_t sa_mask;
|
||||
int sa_flags;
|
||||
};
|
||||
|
||||
#define sigaddset(what,sig) (*(what) |= (1<<(sig)), 0)
|
||||
#define sigdelset(what,sig) (*(what) &= ~(1<<(sig)), 0)
|
||||
#define sigemptyset(what) (*(what) = 0, 0)
|
||||
#define sigfillset(what) (*(what) = ~(0), 0)
|
||||
#define sigismember(what,sig) (((*(what)) & (1<<(sig))) != 0)
|
||||
|
||||
int sigprocmask (int how, const sigset_t *set, sigset_t *oset);
|
||||
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef LIBC_STAT_H__
|
||||
#define LIBC_STAT_H__
|
||||
|
||||
#include <rtconfig.h>
|
||||
|
||||
#if defined(RT_USING_NEWLIB)
|
||||
/* use header file of newlib */
|
||||
#include <sys/stat.h>
|
||||
|
||||
#elif defined(_WIN32)
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define S_IRWXU 00700
|
||||
#define S_IRUSR 00400
|
||||
#define S_IWUSR 00200
|
||||
#define S_IXUSR 00100
|
||||
|
||||
#define S_IRWXG 00070
|
||||
#define S_IRGRP 00040
|
||||
#define S_IWGRP 00020
|
||||
#define S_IXGRP 00010
|
||||
|
||||
#define S_IRWXO 00007
|
||||
#define S_IROTH 00004
|
||||
#define S_IWOTH 00002
|
||||
#define S_IXOTH 00001
|
||||
|
||||
#define S_IFSOCK 0140000
|
||||
#define S_IFLNK 0120000
|
||||
#define S_IFBLK 0060000
|
||||
#define S_IFIFO 0010000
|
||||
#define S_ISUID 0004000
|
||||
#define S_ISGID 0002000
|
||||
#define S_ISVTX 0001000
|
||||
|
||||
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
|
||||
|
||||
#else
|
||||
#define S_IFMT 00170000
|
||||
#define S_IFSOCK 0140000
|
||||
#define S_IFLNK 0120000
|
||||
#define S_IFREG 0100000
|
||||
#define S_IFBLK 0060000
|
||||
#define S_IFDIR 0040000
|
||||
#define S_IFCHR 0020000
|
||||
#define S_IFIFO 0010000
|
||||
#define S_ISUID 0004000
|
||||
#define S_ISGID 0002000
|
||||
#define S_ISVTX 0001000
|
||||
|
||||
#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
|
||||
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
|
||||
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
|
||||
#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
|
||||
#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
|
||||
#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
|
||||
#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
|
||||
|
||||
#define S_IRWXU 00700
|
||||
#define S_IRUSR 00400
|
||||
#define S_IWUSR 00200
|
||||
#define S_IXUSR 00100
|
||||
|
||||
#define S_IRWXG 00070
|
||||
#define S_IRGRP 00040
|
||||
#define S_IWGRP 00020
|
||||
#define S_IXGRP 00010
|
||||
|
||||
#define S_IRWXO 00007
|
||||
#define S_IROTH 00004
|
||||
#define S_IWOTH 00002
|
||||
#define S_IXOTH 00001
|
||||
|
||||
/* stat structure */
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
struct stat
|
||||
{
|
||||
struct rt_device *st_dev;
|
||||
uint16_t st_ino;
|
||||
uint16_t st_mode;
|
||||
uint16_t st_nlink;
|
||||
uint16_t st_uid;
|
||||
uint16_t st_gid;
|
||||
struct rt_device *st_rdev;
|
||||
uint32_t st_size;
|
||||
time_t st_atime;
|
||||
long st_spare1;
|
||||
time_t st_mtime;
|
||||
long st_spare2;
|
||||
time_t st_ctime;
|
||||
long st_spare3;
|
||||
uint32_t st_blksize;
|
||||
uint32_t st_blocks;
|
||||
long st_spare4[2];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2016-11-12 Bernard The first version
|
||||
* 2018-05-25 armink Add simple API, such as LOG_D, LOG_E
|
||||
*/
|
||||
|
||||
/*
|
||||
* The macro definitions for debug
|
||||
*
|
||||
* These macros are defined in static. If you want to use debug macro, you can
|
||||
* use as following code:
|
||||
*
|
||||
* In your C/C++ file, enable/disable DEBUG_ENABLE macro, and then include this
|
||||
* header file.
|
||||
*
|
||||
* #define DBG_TAG "MOD_TAG"
|
||||
* #define DBG_LVL DBG_INFO
|
||||
* #include <rtdbg.h> // must after of DBG_LVL, DBG_TAG or other options
|
||||
*
|
||||
* Then in your C/C++ file, you can use LOG_X macro to print out logs:
|
||||
* LOG_D("this is a debug log!");
|
||||
* LOG_E("this is a error log!");
|
||||
*/
|
||||
|
||||
#ifndef RT_DBG_H__
|
||||
#define RT_DBG_H__
|
||||
|
||||
#include <rtconfig.h>
|
||||
|
||||
/* the debug log will force enable when RT_DEBUG macro is defined */
|
||||
#if defined(RT_DEBUG) && !defined(DBG_ENABLE)
|
||||
#define DBG_ENABLE
|
||||
#endif
|
||||
|
||||
/* it will force output color log when RT_DEBUG_COLOR macro is defined */
|
||||
#if defined(RT_DEBUG_COLOR) && !defined(DBG_COLOR)
|
||||
#define DBG_COLOR
|
||||
#endif
|
||||
|
||||
#if defined(RT_USING_ULOG)
|
||||
/* using ulog compatible with rtdbg */
|
||||
#include <ulog.h>
|
||||
#else
|
||||
|
||||
/* DEBUG level */
|
||||
#define DBG_ERROR 0
|
||||
#define DBG_WARNING 1
|
||||
#define DBG_INFO 2
|
||||
#define DBG_LOG 3
|
||||
|
||||
#ifdef DBG_TAG
|
||||
#ifndef DBG_SECTION_NAME
|
||||
#define DBG_SECTION_NAME DBG_TAG
|
||||
#endif
|
||||
#else
|
||||
/* compatible with old version */
|
||||
#ifndef DBG_SECTION_NAME
|
||||
#define DBG_SECTION_NAME "DBG"
|
||||
#endif
|
||||
#endif /* DBG_TAG */
|
||||
|
||||
#ifdef DBG_ENABLE
|
||||
|
||||
#ifdef DBG_LVL
|
||||
#ifndef DBG_LEVEL
|
||||
#define DBG_LEVEL DBG_LVL
|
||||
#endif
|
||||
#else
|
||||
/* compatible with old version */
|
||||
#ifndef DBG_LEVEL
|
||||
#define DBG_LEVEL DBG_WARNING
|
||||
#endif
|
||||
#endif /* DBG_LVL */
|
||||
|
||||
/*
|
||||
* The color for terminal (foreground)
|
||||
* BLACK 30
|
||||
* RED 31
|
||||
* GREEN 32
|
||||
* YELLOW 33
|
||||
* BLUE 34
|
||||
* PURPLE 35
|
||||
* CYAN 36
|
||||
* WHITE 37
|
||||
*/
|
||||
#ifdef DBG_COLOR
|
||||
#define _DBG_COLOR(n) rt_kprintf("\033["#n"m")
|
||||
#define _DBG_LOG_HDR(lvl_name, color_n) \
|
||||
rt_kprintf("\033["#color_n"m["lvl_name"/"DBG_SECTION_NAME"] ")
|
||||
#define _DBG_LOG_X_END \
|
||||
rt_kprintf("\033[0m\n")
|
||||
#else
|
||||
#define _DBG_COLOR(n)
|
||||
#define _DBG_LOG_HDR(lvl_name, color_n) \
|
||||
rt_kprintf("["lvl_name"/"DBG_SECTION_NAME"] ")
|
||||
#define _DBG_LOG_X_END \
|
||||
rt_kprintf("\n")
|
||||
#endif /* DBG_COLOR */
|
||||
|
||||
/*
|
||||
* static debug routine
|
||||
* NOTE: This is a NOT RECOMMENDED API. Please using LOG_X API.
|
||||
* It will be DISCARDED later. Because it will take up more resources.
|
||||
*/
|
||||
#define dbg_log(level, fmt, ...) \
|
||||
if ((level) <= DBG_LEVEL) \
|
||||
{ \
|
||||
switch(level) \
|
||||
{ \
|
||||
case DBG_ERROR: _DBG_LOG_HDR("E", 31); break; \
|
||||
case DBG_WARNING: _DBG_LOG_HDR("W", 33); break; \
|
||||
case DBG_INFO: _DBG_LOG_HDR("I", 32); break; \
|
||||
case DBG_LOG: _DBG_LOG_HDR("D", 0); break; \
|
||||
default: break; \
|
||||
} \
|
||||
rt_kprintf(fmt, ##__VA_ARGS__); \
|
||||
_DBG_COLOR(0); \
|
||||
}
|
||||
|
||||
#define dbg_here \
|
||||
if ((DBG_LEVEL) <= DBG_LOG){ \
|
||||
rt_kprintf(DBG_SECTION_NAME " Here %s:%d\n", \
|
||||
__FUNCTION__, __LINE__); \
|
||||
}
|
||||
|
||||
#define dbg_log_line(lvl, color_n, fmt, ...) \
|
||||
do \
|
||||
{ \
|
||||
_DBG_LOG_HDR(lvl, color_n); \
|
||||
rt_kprintf(fmt, ##__VA_ARGS__); \
|
||||
_DBG_LOG_X_END; \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define dbg_raw(...) rt_kprintf(__VA_ARGS__);
|
||||
|
||||
#else
|
||||
#define dbg_log(level, fmt, ...)
|
||||
#define dbg_here
|
||||
#define dbg_enter
|
||||
#define dbg_exit
|
||||
#define dbg_log_line(lvl, color_n, fmt, ...)
|
||||
#define dbg_raw(...)
|
||||
#endif /* DBG_ENABLE */
|
||||
|
||||
#if (DBG_LEVEL >= DBG_LOG)
|
||||
#define LOG_D(fmt, ...) dbg_log_line("D", 0, fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define LOG_D(...)
|
||||
#endif
|
||||
|
||||
#if (DBG_LEVEL >= DBG_INFO)
|
||||
#define LOG_I(fmt, ...) dbg_log_line("I", 32, fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define LOG_I(...)
|
||||
#endif
|
||||
|
||||
#if (DBG_LEVEL >= DBG_WARNING)
|
||||
#define LOG_W(fmt, ...) dbg_log_line("W", 33, fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define LOG_W(...)
|
||||
#endif
|
||||
|
||||
#if (DBG_LEVEL >= DBG_ERROR)
|
||||
#define LOG_E(fmt, ...) dbg_log_line("E", 31, fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define LOG_E(...)
|
||||
#endif
|
||||
|
||||
#define LOG_RAW(...) dbg_raw(__VA_ARGS__)
|
||||
|
||||
#endif /* defined(RT_USING_ULOG) && define(DBG_ENABLE) */
|
||||
|
||||
#endif /* RT_DBG_H__ */
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __RTDEBUG_H__
|
||||
#define __RTDEBUG_H__
|
||||
|
||||
#include <rtconfig.h>
|
||||
|
||||
/* settings depend check */
|
||||
#ifdef RT_USING_POSIX
|
||||
#if !defined(RT_USING_DFS) || !defined(RT_USING_DFS_DEVFS)
|
||||
#error "POSIX poll/select, stdin need file system(RT_USING_DFS) and device file system(RT_USING_DFS_DEVFS)"
|
||||
#endif
|
||||
|
||||
#if !defined(RT_USING_LIBC)
|
||||
#error "POSIX layer need standard C library(RT_USING_LIBC)"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_POSIX_TERMIOS
|
||||
#if !defined(RT_USING_POSIX)
|
||||
#error "termios need POSIX layer(RT_USING_POSIX)"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Using this macro to control all kernel debug features. */
|
||||
#ifdef RT_DEBUG
|
||||
|
||||
/* Turn on some of these (set to non-zero) to debug kernel */
|
||||
#ifndef RT_DEBUG_MEM
|
||||
#define RT_DEBUG_MEM 0
|
||||
#endif
|
||||
|
||||
#ifndef RT_DEBUG_MEMHEAP
|
||||
#define RT_DEBUG_MEMHEAP 0
|
||||
#endif
|
||||
|
||||
#ifndef RT_DEBUG_MODULE
|
||||
#define RT_DEBUG_MODULE 0
|
||||
#endif
|
||||
|
||||
#ifndef RT_DEBUG_SCHEDULER
|
||||
#define RT_DEBUG_SCHEDULER 0
|
||||
#endif
|
||||
|
||||
#ifndef RT_DEBUG_SLAB
|
||||
#define RT_DEBUG_SLAB 0
|
||||
#endif
|
||||
|
||||
#ifndef RT_DEBUG_THREAD
|
||||
#define RT_DEBUG_THREAD 0
|
||||
#endif
|
||||
|
||||
#ifndef RT_DEBUG_TIMER
|
||||
#define RT_DEBUG_TIMER 0
|
||||
#endif
|
||||
|
||||
#ifndef RT_DEBUG_IRQ
|
||||
#define RT_DEBUG_IRQ 0
|
||||
#endif
|
||||
|
||||
#ifndef RT_DEBUG_IPC
|
||||
#define RT_DEBUG_IPC 0
|
||||
#endif
|
||||
|
||||
#ifndef RT_DEBUG_INIT
|
||||
#define RT_DEBUG_INIT 0
|
||||
#endif
|
||||
|
||||
/* Turn on this to enable context check */
|
||||
#ifndef RT_DEBUG_CONTEXT_CHECK
|
||||
#define RT_DEBUG_CONTEXT_CHECK 1
|
||||
#endif
|
||||
|
||||
#define RT_DEBUG_LOG(type, message) \
|
||||
do \
|
||||
{ \
|
||||
if (type) \
|
||||
rt_kprintf message; \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define RT_ASSERT(EX) \
|
||||
if (!(EX)) \
|
||||
{ \
|
||||
rt_assert_handler(#EX, __FUNCTION__, __LINE__); \
|
||||
}
|
||||
|
||||
/* Macro to check current context */
|
||||
#if RT_DEBUG_CONTEXT_CHECK
|
||||
#define RT_DEBUG_NOT_IN_INTERRUPT \
|
||||
do \
|
||||
{ \
|
||||
rt_base_t level; \
|
||||
level = rt_hw_interrupt_disable(); \
|
||||
if (rt_interrupt_get_nest() != 0) \
|
||||
{ \
|
||||
rt_kprintf("Function[%s] shall not be used in ISR\n", __FUNCTION__); \
|
||||
RT_ASSERT(0) \
|
||||
} \
|
||||
rt_hw_interrupt_enable(level); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
/* "In thread context" means:
|
||||
* 1) the scheduler has been started
|
||||
* 2) not in interrupt context.
|
||||
*/
|
||||
#define RT_DEBUG_IN_THREAD_CONTEXT \
|
||||
do \
|
||||
{ \
|
||||
rt_base_t level; \
|
||||
level = rt_hw_interrupt_disable(); \
|
||||
if (rt_thread_self() == RT_NULL) \
|
||||
{ \
|
||||
rt_kprintf("Function[%s] shall not be used before scheduler start\n", \
|
||||
__FUNCTION__); \
|
||||
RT_ASSERT(0) \
|
||||
} \
|
||||
RT_DEBUG_NOT_IN_INTERRUPT; \
|
||||
rt_hw_interrupt_enable(level); \
|
||||
} \
|
||||
while (0)
|
||||
#else
|
||||
#define RT_DEBUG_NOT_IN_INTERRUPT
|
||||
#define RT_DEBUG_IN_THREAD_CONTEXT
|
||||
#endif
|
||||
|
||||
#else /* RT_DEBUG */
|
||||
|
||||
#define RT_ASSERT(EX)
|
||||
#define RT_DEBUG_LOG(type, message)
|
||||
#define RT_DEBUG_NOT_IN_INTERRUPT
|
||||
#define RT_DEBUG_IN_THREAD_CONTEXT
|
||||
|
||||
#endif /* RT_DEBUG */
|
||||
|
||||
#endif /* __RTDEBUG_H__ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2006-03-18 Bernard the first version
|
||||
* 2006-04-25 Bernard add rt_hw_context_switch_interrupt declaration
|
||||
* 2006-09-24 Bernard add rt_hw_context_switch_to declaration
|
||||
* 2012-12-29 Bernard add rt_hw_exception_install declaration
|
||||
* 2017-10-17 Hichard add some micros
|
||||
*/
|
||||
|
||||
#ifndef __RT_HW_H__
|
||||
#define __RT_HW_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Some macros define
|
||||
*/
|
||||
#ifndef HWREG32
|
||||
#define HWREG32(x) (*((volatile rt_uint32_t *)(x)))
|
||||
#endif
|
||||
#ifndef HWREG16
|
||||
#define HWREG16(x) (*((volatile rt_uint16_t *)(x)))
|
||||
#endif
|
||||
#ifndef HWREG8
|
||||
#define HWREG8(x) (*((volatile rt_uint8_t *)(x)))
|
||||
#endif
|
||||
|
||||
#ifndef RT_CPU_CACHE_LINE_SZ
|
||||
#define RT_CPU_CACHE_LINE_SZ 32
|
||||
#endif
|
||||
|
||||
enum RT_HW_CACHE_OPS
|
||||
{
|
||||
RT_HW_CACHE_FLUSH = 0x01,
|
||||
RT_HW_CACHE_INVALIDATE = 0x02,
|
||||
};
|
||||
|
||||
/*
|
||||
* CPU interfaces
|
||||
*/
|
||||
void rt_hw_cpu_icache_enable(void);
|
||||
void rt_hw_cpu_icache_disable(void);
|
||||
rt_base_t rt_hw_cpu_icache_status(void);
|
||||
void rt_hw_cpu_icache_ops(int ops, void* addr, int size);
|
||||
|
||||
void rt_hw_cpu_dcache_enable(void);
|
||||
void rt_hw_cpu_dcache_disable(void);
|
||||
rt_base_t rt_hw_cpu_dcache_status(void);
|
||||
void rt_hw_cpu_dcache_ops(int ops, void* addr, int size);
|
||||
|
||||
void rt_hw_cpu_reset(void);
|
||||
void rt_hw_cpu_shutdown(void);
|
||||
|
||||
rt_uint8_t *rt_hw_stack_init(void *entry,
|
||||
void *parameter,
|
||||
rt_uint8_t *stack_addr,
|
||||
void *exit);
|
||||
|
||||
/*
|
||||
* Interrupt handler definition
|
||||
*/
|
||||
typedef void (*rt_isr_handler_t)(int vector, void *param);
|
||||
|
||||
struct rt_irq_desc
|
||||
{
|
||||
rt_isr_handler_t handler;
|
||||
void *param;
|
||||
|
||||
#ifdef RT_USING_INTERRUPT_INFO
|
||||
char name[RT_NAME_MAX];
|
||||
rt_uint32_t counter;
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* Interrupt interfaces
|
||||
*/
|
||||
void rt_hw_interrupt_init(void);
|
||||
void rt_hw_interrupt_mask(int vector);
|
||||
void rt_hw_interrupt_umask(int vector);
|
||||
rt_isr_handler_t rt_hw_interrupt_install(int vector,
|
||||
rt_isr_handler_t handler,
|
||||
void *param,
|
||||
const char *name);
|
||||
|
||||
rt_base_t rt_hw_interrupt_disable(void);
|
||||
void rt_hw_interrupt_enable(rt_base_t level);
|
||||
|
||||
/*
|
||||
* Context interfaces
|
||||
*/
|
||||
void rt_hw_context_switch(rt_uint32_t from, rt_uint32_t to);
|
||||
void rt_hw_context_switch_to(rt_uint32_t to);
|
||||
void rt_hw_context_switch_interrupt(rt_uint32_t from, rt_uint32_t to);
|
||||
|
||||
void rt_hw_console_output(const char *str);
|
||||
|
||||
void rt_hw_backtrace(rt_uint32_t *fp, rt_uint32_t thread_entry);
|
||||
void rt_hw_show_memory(rt_uint32_t addr, rt_uint32_t size);
|
||||
|
||||
/*
|
||||
* Exception interfaces
|
||||
*/
|
||||
void rt_hw_exception_install(rt_err_t (*exception_handle)(void *context));
|
||||
|
||||
/*
|
||||
* delay interfaces
|
||||
*/
|
||||
void rt_hw_us_delay(rt_uint32_t us);
|
||||
|
||||
#define RT_DEFINE_SPINLOCK(x)
|
||||
#define RT_DECLARE_SPINLOCK(x) rt_ubase_t x
|
||||
|
||||
#define rt_hw_spin_lock(lock) *(lock) = rt_hw_interrupt_disable()
|
||||
#define rt_hw_spin_unlock(lock) rt_hw_interrupt_enable(*(lock))
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2017-01-21 Bernard the first version
|
||||
*/
|
||||
|
||||
#ifndef RTLIBC_H__
|
||||
#define RTLIBC_H__
|
||||
|
||||
/* definitions for libc if toolchain has no these definitions */
|
||||
#include "libc/libc_stat.h"
|
||||
#include "libc/libc_errno.h"
|
||||
|
||||
#include "libc/libc_fcntl.h"
|
||||
#include "libc/libc_ioctl.h"
|
||||
#include "libc/libc_dirent.h"
|
||||
#include "libc/libc_signal.h"
|
||||
#include "libc/libc_fdset.h"
|
||||
|
||||
#if defined(__CC_ARM) || defined(__CLANG_ARM) || defined(__IAR_SYSTEMS_ICC__)
|
||||
typedef signed long off_t;
|
||||
typedef int mode_t;
|
||||
#endif
|
||||
|
||||
#if defined(__MINGW32__) || defined(_WIN32)
|
||||
typedef signed long off_t;
|
||||
typedef int mode_t;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __RTM_H__
|
||||
#define __RTM_H__
|
||||
|
||||
#include <rtdef.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
#ifdef RT_USING_MODULE
|
||||
struct rt_module_symtab
|
||||
{
|
||||
void *addr;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma section("RTMSymTab$f",read)
|
||||
#define RTM_EXPORT(symbol) \
|
||||
__declspec(allocate("RTMSymTab$f"))const char __rtmsym_##symbol##_name[] = "__vs_rtm_"#symbol;
|
||||
#pragma comment(linker, "/merge:RTMSymTab=mytext")
|
||||
|
||||
#elif defined(__MINGW32__)
|
||||
#define RTM_EXPORT(symbol)
|
||||
|
||||
#else
|
||||
#define RTM_EXPORT(symbol) \
|
||||
const char __rtmsym_##symbol##_name[] SECTION(".rodata.name") = #symbol; \
|
||||
const struct rt_module_symtab __rtmsym_##symbol SECTION("RTMSymTab")= \
|
||||
{ \
|
||||
(void *)&symbol, \
|
||||
__rtmsym_##symbol##_name \
|
||||
};
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define RTM_EXPORT(symbol)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2006-03-16 Bernard the first version
|
||||
* 2006-09-07 Bernard move the kservice APIs to rtthread.h
|
||||
* 2007-06-27 Bernard fix the rt_list_remove bug
|
||||
* 2012-03-22 Bernard rename kservice.h to rtservice.h
|
||||
* 2017-11-15 JasonJia Modify rt_slist_foreach to rt_slist_for_each_entry.
|
||||
* Make code cleanup.
|
||||
*/
|
||||
|
||||
#ifndef __RT_SERVICE_H__
|
||||
#define __RT_SERVICE_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @addtogroup KernelService
|
||||
*/
|
||||
|
||||
/**@{*/
|
||||
|
||||
/**
|
||||
* rt_container_of - return the member address of ptr, if the type of ptr is the
|
||||
* struct type.
|
||||
*/
|
||||
#define rt_container_of(ptr, type, member) \
|
||||
((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member)))
|
||||
|
||||
|
||||
/**
|
||||
* @brief initialize a list object
|
||||
*/
|
||||
#define RT_LIST_OBJECT_INIT(object) { &(object), &(object) }
|
||||
|
||||
/**
|
||||
* @brief initialize a list
|
||||
*
|
||||
* @param l list to be initialized
|
||||
*/
|
||||
rt_inline void rt_list_init(rt_list_t *l)
|
||||
{
|
||||
l->next = l->prev = l;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief insert a node after a list
|
||||
*
|
||||
* @param l list to insert it
|
||||
* @param n new node to be inserted
|
||||
*/
|
||||
rt_inline void rt_list_insert_after(rt_list_t *l, rt_list_t *n)
|
||||
{
|
||||
l->next->prev = n;
|
||||
n->next = l->next;
|
||||
|
||||
l->next = n;
|
||||
n->prev = l;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief insert a node before a list
|
||||
*
|
||||
* @param n new node to be inserted
|
||||
* @param l list to insert it
|
||||
*/
|
||||
rt_inline void rt_list_insert_before(rt_list_t *l, rt_list_t *n)
|
||||
{
|
||||
l->prev->next = n;
|
||||
n->prev = l->prev;
|
||||
|
||||
l->prev = n;
|
||||
n->next = l;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief remove node from list.
|
||||
* @param n the node to remove from the list.
|
||||
*/
|
||||
rt_inline void rt_list_remove(rt_list_t *n)
|
||||
{
|
||||
n->next->prev = n->prev;
|
||||
n->prev->next = n->next;
|
||||
|
||||
n->next = n->prev = n;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief tests whether a list is empty
|
||||
* @param l the list to test.
|
||||
*/
|
||||
rt_inline int rt_list_isempty(const rt_list_t *l)
|
||||
{
|
||||
return l->next == l;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get the list length
|
||||
* @param l the list to get.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get the struct for this entry
|
||||
* @param node the entry point
|
||||
* @param type the type of structure
|
||||
* @param member the name of list in structure
|
||||
*/
|
||||
#define rt_list_entry(node, type, member) \
|
||||
rt_container_of(node, type, member)
|
||||
|
||||
/**
|
||||
* rt_list_for_each - iterate over a list
|
||||
* @pos: the rt_list_t * to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define rt_list_for_each(pos, head) \
|
||||
for (pos = (head)->next; pos != (head); pos = pos->next)
|
||||
|
||||
/**
|
||||
* rt_list_for_each_safe - iterate over a list safe against removal of list entry
|
||||
* @pos: the rt_list_t * to use as a loop cursor.
|
||||
* @n: another rt_list_t * to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define rt_list_for_each_safe(pos, n, head) \
|
||||
for (pos = (head)->next, n = pos->next; pos != (head); \
|
||||
pos = n, n = pos->next)
|
||||
|
||||
/**
|
||||
* rt_list_for_each_entry - iterate over list of given type
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define rt_list_for_each_entry(pos, head, member) \
|
||||
for (pos = rt_list_entry((head)->next, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = rt_list_entry(pos->member.next, typeof(*pos), member))
|
||||
|
||||
/**
|
||||
* rt_list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @n: another type * to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define rt_list_for_each_entry_safe(pos, n, head, member) \
|
||||
for (pos = rt_list_entry((head)->next, typeof(*pos), member), \
|
||||
n = rt_list_entry(pos->member.next, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = n, n = rt_list_entry(n->member.next, typeof(*n), member))
|
||||
|
||||
/**
|
||||
* rt_list_first_entry - get the first element from a list
|
||||
* @ptr: the list head to take the element from.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*
|
||||
* Note, that list is expected to be not empty.
|
||||
*/
|
||||
#define rt_list_first_entry(ptr, type, member) \
|
||||
rt_list_entry((ptr)->next, type, member)
|
||||
|
||||
#define RT_SLIST_OBJECT_INIT(object) { RT_NULL }
|
||||
|
||||
/**
|
||||
* @brief initialize a single list
|
||||
*
|
||||
* @param l the single list to be initialized
|
||||
*/
|
||||
rt_inline void rt_slist_init(rt_slist_t *l)
|
||||
{
|
||||
l->next = RT_NULL;
|
||||
}
|
||||
|
||||
rt_inline void rt_slist_append(rt_slist_t *l, rt_slist_t *n)
|
||||
{
|
||||
struct rt_slist_node *node;
|
||||
|
||||
node = l;
|
||||
while (node->next) node = node->next;
|
||||
|
||||
/* append the node to the tail */
|
||||
node->next = n;
|
||||
n->next = RT_NULL;
|
||||
}
|
||||
|
||||
rt_inline void rt_slist_insert(rt_slist_t *l, rt_slist_t *n)
|
||||
{
|
||||
n->next = l->next;
|
||||
l->next = n;
|
||||
}
|
||||
|
||||
rt_inline unsigned int rt_slist_len(const rt_slist_t *l)
|
||||
{
|
||||
unsigned int len = 0;
|
||||
const rt_slist_t *list = l->next;
|
||||
while (list != RT_NULL)
|
||||
{
|
||||
list = list->next;
|
||||
len ++;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
rt_inline rt_slist_t *rt_slist_remove(rt_slist_t *l, rt_slist_t *n)
|
||||
{
|
||||
/* remove slist head */
|
||||
struct rt_slist_node *node = l;
|
||||
while (node->next && node->next != n) node = node->next;
|
||||
|
||||
/* remove node */
|
||||
if (node->next != (rt_slist_t *)0) node->next = node->next->next;
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
rt_inline rt_slist_t *rt_slist_first(rt_slist_t *l)
|
||||
{
|
||||
return l->next;
|
||||
}
|
||||
|
||||
rt_inline rt_slist_t *rt_slist_tail(rt_slist_t *l)
|
||||
{
|
||||
while (l->next) l = l->next;
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
rt_inline rt_slist_t *rt_slist_next(rt_slist_t *n)
|
||||
{
|
||||
return n->next;
|
||||
}
|
||||
|
||||
rt_inline int rt_slist_isempty(rt_slist_t *l)
|
||||
{
|
||||
return l->next == RT_NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get the struct for this single list node
|
||||
* @param node the entry point
|
||||
* @param type the type of structure
|
||||
* @param member the name of list in structure
|
||||
*/
|
||||
#define rt_slist_entry(node, type, member) \
|
||||
rt_container_of(node, type, member)
|
||||
|
||||
/**
|
||||
* rt_slist_for_each - iterate over a single list
|
||||
* @pos: the rt_slist_t * to use as a loop cursor.
|
||||
* @head: the head for your single list.
|
||||
*/
|
||||
#define rt_slist_for_each(pos, head) \
|
||||
for (pos = (head)->next; pos != RT_NULL; pos = pos->next)
|
||||
|
||||
/**
|
||||
* rt_slist_for_each_entry - iterate over single list of given type
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @head: the head for your single list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define rt_slist_for_each_entry(pos, head, member) \
|
||||
for (pos = rt_slist_entry((head)->next, typeof(*pos), member); \
|
||||
&pos->member != (RT_NULL); \
|
||||
pos = rt_slist_entry(pos->member.next, typeof(*pos), member))
|
||||
|
||||
/**
|
||||
* rt_slist_first_entry - get the first element from a slist
|
||||
* @ptr: the slist head to take the element from.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the slist_struct within the struct.
|
||||
*
|
||||
* Note, that slist is expected to be not empty.
|
||||
*/
|
||||
#define rt_slist_first_entry(ptr, type, member) \
|
||||
rt_slist_entry((ptr)->next, type, member)
|
||||
|
||||
/**
|
||||
* rt_slist_tail_entry - get the tail element from a slist
|
||||
* @ptr: the slist head to take the element from.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the slist_struct within the struct.
|
||||
*
|
||||
* Note, that slist is expected to be not empty.
|
||||
*/
|
||||
#define rt_slist_tail_entry(ptr, type, member) \
|
||||
rt_slist_entry(rt_slist_tail(ptr), type, member)
|
||||
|
||||
/**@}*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,533 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2006-03-18 Bernard the first version
|
||||
* 2006-04-26 Bernard add semaphore APIs
|
||||
* 2006-08-10 Bernard add version information
|
||||
* 2007-01-28 Bernard rename RT_OBJECT_Class_Static to RT_Object_Class_Static
|
||||
* 2007-03-03 Bernard clean up the definitions to rtdef.h
|
||||
* 2010-04-11 yi.qiu add module feature
|
||||
* 2013-06-24 Bernard add rt_kprintf re-define when not use RT_USING_CONSOLE.
|
||||
* 2016-08-09 ArdaFu add new thread and interrupt hook.
|
||||
*/
|
||||
|
||||
#ifndef __RT_THREAD_H__
|
||||
#define __RT_THREAD_H__
|
||||
|
||||
#include <rtconfig.h>
|
||||
#include <rtdebug.h>
|
||||
#include <rtdef.h>
|
||||
#include <rtservice.h>
|
||||
#include <rtm.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @addtogroup KernelObject
|
||||
*/
|
||||
|
||||
/**@{*/
|
||||
|
||||
/*
|
||||
* kernel object interface
|
||||
*/
|
||||
void rt_system_object_init(void);
|
||||
struct rt_object_information *
|
||||
rt_object_get_information(enum rt_object_class_type type);
|
||||
void rt_object_init(struct rt_object *object,
|
||||
enum rt_object_class_type type,
|
||||
const char *name);
|
||||
void rt_object_detach(rt_object_t object);
|
||||
rt_object_t rt_object_allocate(enum rt_object_class_type type,
|
||||
const char *name);
|
||||
void rt_object_delete(rt_object_t object);
|
||||
rt_bool_t rt_object_is_systemobject(rt_object_t object);
|
||||
rt_uint8_t rt_object_get_type(rt_object_t object);
|
||||
rt_object_t rt_object_find(const char *name, rt_uint8_t type);
|
||||
|
||||
#ifdef RT_USING_HOOK
|
||||
void rt_object_attach_sethook(void (*hook)(struct rt_object *object));
|
||||
void rt_object_detach_sethook(void (*hook)(struct rt_object *object));
|
||||
void rt_object_trytake_sethook(void (*hook)(struct rt_object *object));
|
||||
void rt_object_take_sethook(void (*hook)(struct rt_object *object));
|
||||
void rt_object_put_sethook(void (*hook)(struct rt_object *object));
|
||||
#endif
|
||||
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
* @addtogroup Clock
|
||||
*/
|
||||
|
||||
/**@{*/
|
||||
|
||||
/*
|
||||
* clock & timer interface
|
||||
*/
|
||||
void rt_system_tick_init(void);
|
||||
rt_tick_t rt_tick_get(void);
|
||||
void rt_tick_set(rt_tick_t tick);
|
||||
void rt_tick_increase(void);
|
||||
rt_tick_t rt_tick_from_millisecond(rt_int32_t ms);
|
||||
|
||||
void rt_system_timer_init(void);
|
||||
void rt_system_timer_thread_init(void);
|
||||
|
||||
void rt_timer_init(rt_timer_t timer,
|
||||
const char *name,
|
||||
void (*timeout)(void *parameter),
|
||||
void *parameter,
|
||||
rt_tick_t time,
|
||||
rt_uint8_t flag);
|
||||
rt_err_t rt_timer_detach(rt_timer_t timer);
|
||||
rt_timer_t rt_timer_create(const char *name,
|
||||
void (*timeout)(void *parameter),
|
||||
void *parameter,
|
||||
rt_tick_t time,
|
||||
rt_uint8_t flag);
|
||||
rt_err_t rt_timer_delete(rt_timer_t timer);
|
||||
rt_err_t rt_timer_start(rt_timer_t timer);
|
||||
rt_err_t rt_timer_stop(rt_timer_t timer);
|
||||
rt_err_t rt_timer_control(rt_timer_t timer, int cmd, void *arg);
|
||||
|
||||
rt_tick_t rt_timer_next_timeout_tick(void);
|
||||
void rt_timer_check(void);
|
||||
|
||||
#ifdef RT_USING_HOOK
|
||||
void rt_timer_enter_sethook(void (*hook)(struct rt_timer *timer));
|
||||
void rt_timer_exit_sethook(void (*hook)(struct rt_timer *timer));
|
||||
#endif
|
||||
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
* @addtogroup Thread
|
||||
*/
|
||||
|
||||
/**@{*/
|
||||
|
||||
/*
|
||||
* thread interface
|
||||
*/
|
||||
rt_err_t rt_thread_init(struct rt_thread *thread,
|
||||
const char *name,
|
||||
void (*entry)(void *parameter),
|
||||
void *parameter,
|
||||
void *stack_start,
|
||||
rt_uint32_t stack_size,
|
||||
rt_uint8_t priority,
|
||||
rt_uint32_t tick);
|
||||
rt_err_t rt_thread_detach(rt_thread_t thread);
|
||||
rt_thread_t rt_thread_create(const char *name,
|
||||
void (*entry)(void *parameter),
|
||||
void *parameter,
|
||||
rt_uint32_t stack_size,
|
||||
rt_uint8_t priority,
|
||||
rt_uint32_t tick);
|
||||
rt_thread_t rt_thread_self(void);
|
||||
rt_thread_t rt_thread_find(char *name);
|
||||
rt_err_t rt_thread_startup(rt_thread_t thread);
|
||||
rt_err_t rt_thread_delete(rt_thread_t thread);
|
||||
|
||||
rt_err_t rt_thread_yield(void);
|
||||
rt_err_t rt_thread_delay(rt_tick_t tick);
|
||||
rt_err_t rt_thread_mdelay(rt_int32_t ms);
|
||||
rt_err_t rt_thread_control(rt_thread_t thread, int cmd, void *arg);
|
||||
rt_err_t rt_thread_suspend(rt_thread_t thread);
|
||||
rt_err_t rt_thread_resume(rt_thread_t thread);
|
||||
void rt_thread_timeout(void *parameter);
|
||||
|
||||
#ifdef RT_USING_SIGNALS
|
||||
void rt_thread_alloc_sig(rt_thread_t tid);
|
||||
void rt_thread_free_sig(rt_thread_t tid);
|
||||
int rt_thread_kill(rt_thread_t tid, int sig);
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_HOOK
|
||||
void rt_thread_suspend_sethook(void (*hook)(rt_thread_t thread));
|
||||
void rt_thread_resume_sethook (void (*hook)(rt_thread_t thread));
|
||||
void rt_thread_inited_sethook (void (*hook)(rt_thread_t thread));
|
||||
#endif
|
||||
|
||||
/*
|
||||
* idle thread interface
|
||||
*/
|
||||
void rt_thread_idle_init(void);
|
||||
#if defined(RT_USING_HOOK) || defined(RT_USING_IDLE_HOOK)
|
||||
rt_err_t rt_thread_idle_sethook(void (*hook)(void));
|
||||
rt_err_t rt_thread_idle_delhook(void (*hook)(void));
|
||||
#endif
|
||||
void rt_thread_idle_excute(void);
|
||||
rt_thread_t rt_thread_idle_gethandler(void);
|
||||
|
||||
/*
|
||||
* schedule service
|
||||
*/
|
||||
void rt_system_scheduler_init(void);
|
||||
void rt_system_scheduler_start(void);
|
||||
|
||||
void rt_schedule(void);
|
||||
void rt_schedule_insert_thread(struct rt_thread *thread);
|
||||
void rt_schedule_remove_thread(struct rt_thread *thread);
|
||||
|
||||
void rt_enter_critical(void);
|
||||
void rt_exit_critical(void);
|
||||
rt_uint16_t rt_critical_level(void);
|
||||
|
||||
#ifdef RT_USING_HOOK
|
||||
void rt_scheduler_sethook(void (*hook)(rt_thread_t from, rt_thread_t to));
|
||||
#endif
|
||||
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
* @addtogroup Signals
|
||||
* @{
|
||||
*/
|
||||
#ifdef RT_USING_SIGNALS
|
||||
void rt_signal_mask(int signo);
|
||||
void rt_signal_unmask(int signo);
|
||||
rt_sighandler_t rt_signal_install(int signo, rt_sighandler_t handler);
|
||||
int rt_signal_wait(const rt_sigset_t *set, rt_siginfo_t *si, rt_int32_t timeout);
|
||||
|
||||
int rt_system_signal_init(void);
|
||||
#endif
|
||||
/*@}*/
|
||||
|
||||
/**
|
||||
* @addtogroup MM
|
||||
*/
|
||||
|
||||
/**@{*/
|
||||
|
||||
/*
|
||||
* memory management interface
|
||||
*/
|
||||
#ifdef RT_USING_MEMPOOL
|
||||
/*
|
||||
* memory pool interface
|
||||
*/
|
||||
rt_err_t rt_mp_init(struct rt_mempool *mp,
|
||||
const char *name,
|
||||
void *start,
|
||||
rt_size_t size,
|
||||
rt_size_t block_size);
|
||||
rt_err_t rt_mp_detach(struct rt_mempool *mp);
|
||||
rt_mp_t rt_mp_create(const char *name,
|
||||
rt_size_t block_count,
|
||||
rt_size_t block_size);
|
||||
rt_err_t rt_mp_delete(rt_mp_t mp);
|
||||
|
||||
void *rt_mp_alloc(rt_mp_t mp, rt_int32_t time);
|
||||
void rt_mp_free(void *block);
|
||||
|
||||
#ifdef RT_USING_HOOK
|
||||
void rt_mp_alloc_sethook(void (*hook)(struct rt_mempool *mp, void *block));
|
||||
void rt_mp_free_sethook(void (*hook)(struct rt_mempool *mp, void *block));
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
/*
|
||||
* heap memory interface
|
||||
*/
|
||||
void rt_system_heap_init(void *begin_addr, void *end_addr);
|
||||
|
||||
void *rt_malloc(rt_size_t nbytes);
|
||||
void rt_free(void *ptr);
|
||||
void *rt_realloc(void *ptr, rt_size_t nbytes);
|
||||
void *rt_calloc(rt_size_t count, rt_size_t size);
|
||||
void *rt_malloc_align(rt_size_t size, rt_size_t align);
|
||||
void rt_free_align(void *ptr);
|
||||
|
||||
void rt_memory_info(rt_uint32_t *total,
|
||||
rt_uint32_t *used,
|
||||
rt_uint32_t *max_used);
|
||||
|
||||
#ifdef RT_USING_SLAB
|
||||
void *rt_page_alloc(rt_size_t npages);
|
||||
void rt_page_free(void *addr, rt_size_t npages);
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_HOOK
|
||||
void rt_malloc_sethook(void (*hook)(void *ptr, rt_size_t size));
|
||||
void rt_free_sethook(void (*hook)(void *ptr));
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_MEMHEAP
|
||||
/**
|
||||
* memory heap object interface
|
||||
*/
|
||||
rt_err_t rt_memheap_init(struct rt_memheap *memheap,
|
||||
const char *name,
|
||||
void *start_addr,
|
||||
rt_size_t size);
|
||||
rt_err_t rt_memheap_detach(struct rt_memheap *heap);
|
||||
void *rt_memheap_alloc(struct rt_memheap *heap, rt_size_t size);
|
||||
void *rt_memheap_realloc(struct rt_memheap *heap, void *ptr, rt_size_t newsize);
|
||||
void rt_memheap_free(void *ptr);
|
||||
#endif
|
||||
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
* @addtogroup IPC
|
||||
*/
|
||||
|
||||
/**@{*/
|
||||
|
||||
#ifdef RT_USING_SEMAPHORE
|
||||
/*
|
||||
* semaphore interface
|
||||
*/
|
||||
rt_err_t rt_sem_init(rt_sem_t sem,
|
||||
const char *name,
|
||||
rt_uint32_t value,
|
||||
rt_uint8_t flag);
|
||||
rt_err_t rt_sem_detach(rt_sem_t sem);
|
||||
rt_sem_t rt_sem_create(const char *name, rt_uint32_t value, rt_uint8_t flag);
|
||||
rt_err_t rt_sem_delete(rt_sem_t sem);
|
||||
|
||||
rt_err_t rt_sem_take(rt_sem_t sem, rt_int32_t time);
|
||||
rt_err_t rt_sem_trytake(rt_sem_t sem);
|
||||
rt_err_t rt_sem_release(rt_sem_t sem);
|
||||
rt_err_t rt_sem_control(rt_sem_t sem, int cmd, void *arg);
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_MUTEX
|
||||
/*
|
||||
* mutex interface
|
||||
*/
|
||||
rt_err_t rt_mutex_init(rt_mutex_t mutex, const char *name, rt_uint8_t flag);
|
||||
rt_err_t rt_mutex_detach(rt_mutex_t mutex);
|
||||
rt_mutex_t rt_mutex_create(const char *name, rt_uint8_t flag);
|
||||
rt_err_t rt_mutex_delete(rt_mutex_t mutex);
|
||||
|
||||
rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t time);
|
||||
rt_err_t rt_mutex_release(rt_mutex_t mutex);
|
||||
rt_err_t rt_mutex_control(rt_mutex_t mutex, int cmd, void *arg);
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_EVENT
|
||||
/*
|
||||
* event interface
|
||||
*/
|
||||
rt_err_t rt_event_init(rt_event_t event, const char *name, rt_uint8_t flag);
|
||||
rt_err_t rt_event_detach(rt_event_t event);
|
||||
rt_event_t rt_event_create(const char *name, rt_uint8_t flag);
|
||||
rt_err_t rt_event_delete(rt_event_t event);
|
||||
|
||||
rt_err_t rt_event_send(rt_event_t event, rt_uint32_t set);
|
||||
rt_err_t rt_event_recv(rt_event_t event,
|
||||
rt_uint32_t set,
|
||||
rt_uint8_t opt,
|
||||
rt_int32_t timeout,
|
||||
rt_uint32_t *recved);
|
||||
rt_err_t rt_event_control(rt_event_t event, int cmd, void *arg);
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_MAILBOX
|
||||
/*
|
||||
* mailbox interface
|
||||
*/
|
||||
rt_err_t rt_mb_init(rt_mailbox_t mb,
|
||||
const char *name,
|
||||
void *msgpool,
|
||||
rt_size_t size,
|
||||
rt_uint8_t flag);
|
||||
rt_err_t rt_mb_detach(rt_mailbox_t mb);
|
||||
rt_mailbox_t rt_mb_create(const char *name, rt_size_t size, rt_uint8_t flag);
|
||||
rt_err_t rt_mb_delete(rt_mailbox_t mb);
|
||||
|
||||
rt_err_t rt_mb_send(rt_mailbox_t mb, rt_uint32_t value);
|
||||
rt_err_t rt_mb_send_wait(rt_mailbox_t mb,
|
||||
rt_uint32_t value,
|
||||
rt_int32_t timeout);
|
||||
rt_err_t rt_mb_recv(rt_mailbox_t mb, rt_uint32_t *value, rt_int32_t timeout);
|
||||
rt_err_t rt_mb_control(rt_mailbox_t mb, int cmd, void *arg);
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_MESSAGEQUEUE
|
||||
/*
|
||||
* message queue interface
|
||||
*/
|
||||
rt_err_t rt_mq_init(rt_mq_t mq,
|
||||
const char *name,
|
||||
void *msgpool,
|
||||
rt_size_t msg_size,
|
||||
rt_size_t pool_size,
|
||||
rt_uint8_t flag);
|
||||
rt_err_t rt_mq_detach(rt_mq_t mq);
|
||||
rt_mq_t rt_mq_create(const char *name,
|
||||
rt_size_t msg_size,
|
||||
rt_size_t max_msgs,
|
||||
rt_uint8_t flag);
|
||||
rt_err_t rt_mq_delete(rt_mq_t mq);
|
||||
|
||||
rt_err_t rt_mq_send(rt_mq_t mq, void *buffer, rt_size_t size);
|
||||
rt_err_t rt_mq_urgent(rt_mq_t mq, void *buffer, rt_size_t size);
|
||||
rt_err_t rt_mq_recv(rt_mq_t mq,
|
||||
void *buffer,
|
||||
rt_size_t size,
|
||||
rt_int32_t timeout);
|
||||
rt_err_t rt_mq_control(rt_mq_t mq, int cmd, void *arg);
|
||||
#endif
|
||||
|
||||
/**@}*/
|
||||
|
||||
#ifdef RT_USING_DEVICE
|
||||
/**
|
||||
* @addtogroup Device
|
||||
*/
|
||||
|
||||
/**@{*/
|
||||
|
||||
/*
|
||||
* device (I/O) system interface
|
||||
*/
|
||||
rt_device_t rt_device_find(const char *name);
|
||||
|
||||
rt_err_t rt_device_register(rt_device_t dev,
|
||||
const char *name,
|
||||
rt_uint16_t flags);
|
||||
rt_err_t rt_device_unregister(rt_device_t dev);
|
||||
|
||||
rt_device_t rt_device_create(int type, int attach_size);
|
||||
void rt_device_destroy(rt_device_t device);
|
||||
|
||||
rt_err_t rt_device_init_all(void);
|
||||
|
||||
rt_err_t
|
||||
rt_device_set_rx_indicate(rt_device_t dev,
|
||||
rt_err_t (*rx_ind)(rt_device_t dev, rt_size_t size));
|
||||
rt_err_t
|
||||
rt_device_set_tx_complete(rt_device_t dev,
|
||||
rt_err_t (*tx_done)(rt_device_t dev, void *buffer));
|
||||
|
||||
rt_err_t rt_device_init (rt_device_t dev);
|
||||
rt_err_t rt_device_open (rt_device_t dev, rt_uint16_t oflag);
|
||||
rt_err_t rt_device_close(rt_device_t dev);
|
||||
rt_size_t rt_device_read (rt_device_t dev,
|
||||
rt_off_t pos,
|
||||
void *buffer,
|
||||
rt_size_t size);
|
||||
rt_size_t rt_device_write(rt_device_t dev,
|
||||
rt_off_t pos,
|
||||
const void *buffer,
|
||||
rt_size_t size);
|
||||
rt_err_t rt_device_control(rt_device_t dev, int cmd, void *arg);
|
||||
|
||||
/**@}*/
|
||||
#endif
|
||||
|
||||
/*
|
||||
* interrupt service
|
||||
*/
|
||||
|
||||
/*
|
||||
* rt_interrupt_enter and rt_interrupt_leave only can be called by BSP
|
||||
*/
|
||||
void rt_interrupt_enter(void);
|
||||
void rt_interrupt_leave(void);
|
||||
|
||||
/*
|
||||
* the number of nested interrupts.
|
||||
*/
|
||||
rt_uint8_t rt_interrupt_get_nest(void);
|
||||
|
||||
#ifdef RT_USING_HOOK
|
||||
void rt_interrupt_enter_sethook(void (*hook)(void));
|
||||
void rt_interrupt_leave_sethook(void (*hook)(void));
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_COMPONENTS_INIT
|
||||
void rt_components_init(void);
|
||||
void rt_components_board_init(void);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @addtogroup KernelService
|
||||
*/
|
||||
|
||||
/**@{*/
|
||||
|
||||
/*
|
||||
* general kernel service
|
||||
*/
|
||||
#ifndef RT_USING_CONSOLE
|
||||
#define rt_kprintf(...)
|
||||
#define rt_kputs(str)
|
||||
#else
|
||||
void rt_kprintf(const char *fmt, ...);
|
||||
void rt_kputs(const char *str);
|
||||
#endif
|
||||
rt_int32_t rt_vsprintf(char *dest, const char *format, va_list arg_ptr);
|
||||
rt_int32_t rt_vsnprintf(char *buf, rt_size_t size, const char *fmt, va_list args);
|
||||
rt_int32_t rt_sprintf(char *buf, const char *format, ...);
|
||||
rt_int32_t rt_snprintf(char *buf, rt_size_t size, const char *format, ...);
|
||||
|
||||
#if defined(RT_USING_DEVICE) && defined(RT_USING_CONSOLE)
|
||||
rt_device_t rt_console_set_device(const char *name);
|
||||
rt_device_t rt_console_get_device(void);
|
||||
#endif
|
||||
|
||||
rt_err_t rt_get_errno(void);
|
||||
void rt_set_errno(rt_err_t no);
|
||||
int *_rt_errno(void);
|
||||
#if !defined(RT_USING_NEWLIB) && !defined(_WIN32)
|
||||
#ifndef errno
|
||||
#define errno *_rt_errno()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int __rt_ffs(int value);
|
||||
|
||||
void *rt_memset(void *src, int c, rt_ubase_t n);
|
||||
void *rt_memcpy(void *dest, const void *src, rt_ubase_t n);
|
||||
|
||||
rt_int32_t rt_strncmp(const char *cs, const char *ct, rt_ubase_t count);
|
||||
rt_int32_t rt_strcmp(const char *cs, const char *ct);
|
||||
rt_size_t rt_strlen(const char *src);
|
||||
rt_size_t rt_strnlen(const char *s, rt_ubase_t maxlen);
|
||||
char *rt_strdup(const char *s);
|
||||
#if defined(__CC_ARM) || defined(__CLANG_ARM)
|
||||
/* leak strdup interface */
|
||||
char* strdup(const char* str);
|
||||
#endif
|
||||
|
||||
char *rt_strstr(const char *str1, const char *str2);
|
||||
rt_int32_t rt_sscanf(const char *buf, const char *fmt, ...);
|
||||
char *rt_strncpy(char *dest, const char *src, rt_ubase_t n);
|
||||
void *rt_memmove(void *dest, const void *src, rt_ubase_t n);
|
||||
rt_int32_t rt_memcmp(const void *cs, const void *ct, rt_ubase_t count);
|
||||
rt_uint32_t rt_strcasecmp(const char *a, const char *b);
|
||||
|
||||
void rt_show_version(void);
|
||||
|
||||
#ifdef RT_DEBUG
|
||||
extern void (*rt_assert_hook)(const char *ex, const char *func, rt_size_t line);
|
||||
void rt_assert_set_hook(void (*hook)(const char *ex, const char *func, rt_size_t line));
|
||||
|
||||
void rt_assert_handler(const char *ex, const char *func, rt_size_t line);
|
||||
#endif /* RT_DEBUG */
|
||||
|
||||
#ifdef RT_USING_FINSH
|
||||
#include <finsh_api.h>
|
||||
#endif
|
||||
|
||||
/**@}*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-09-09 WCH the first version
|
||||
*/
|
||||
|
||||
#include "cpuport.h"
|
||||
|
||||
/*
|
||||
* #ifdef RT_USING_SMP
|
||||
* void rt_hw_context_switch_to(rt_ubase_t to, stuct rt_thread *to_thread);
|
||||
* #else
|
||||
* void rt_hw_context_switch_to(rt_ubase_t to);
|
||||
* #endif
|
||||
* a0 --> to
|
||||
* a1 --> to_thread
|
||||
*/
|
||||
.globl rt_hw_context_switch_to
|
||||
rt_hw_context_switch_to:
|
||||
/* first save interrupt stack */
|
||||
la t0, _eusrstack
|
||||
addi t0, t0, -512
|
||||
csrw mscratch,t0
|
||||
|
||||
LOAD sp, (a0)
|
||||
LOAD a0, 2 * REGBYTES(sp)
|
||||
csrw mstatus, a0
|
||||
j rt_hw_context_switch_exit
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch(rt_ubase_t from, rt_ubase_t to);
|
||||
* a0 --> from
|
||||
* a1 --> to
|
||||
*/
|
||||
.globl rt_hw_context_switch
|
||||
rt_hw_context_switch:
|
||||
/* switch in thread */
|
||||
#ifdef ARCH_RISCV_FPU
|
||||
addi sp, sp, -32*FREGBYTES
|
||||
|
||||
FSTORE f0, 0 * FREGBYTES(sp)
|
||||
FSTORE f1, 1 * FREGBYTES(sp)
|
||||
FSTORE f2, 2 * FREGBYTES(sp)
|
||||
FSTORE f3, 3 * FREGBYTES(sp)
|
||||
FSTORE f4, 4 * FREGBYTES(sp)
|
||||
FSTORE f5, 5 * FREGBYTES(sp)
|
||||
FSTORE f6, 6 * FREGBYTES(sp)
|
||||
FSTORE f7, 7 * FREGBYTES(sp)
|
||||
FSTORE f8, 8 * FREGBYTES(sp)
|
||||
FSTORE f9, 9 * FREGBYTES(sp)
|
||||
FSTORE f10, 10 * FREGBYTES(sp)
|
||||
FSTORE f11, 11 * FREGBYTES(sp)
|
||||
FSTORE f12, 12 * FREGBYTES(sp)
|
||||
FSTORE f13, 13 * FREGBYTES(sp)
|
||||
FSTORE f14, 14 * FREGBYTES(sp)
|
||||
FSTORE f15, 15 * FREGBYTES(sp)
|
||||
FSTORE f16, 16 * FREGBYTES(sp)
|
||||
FSTORE f17, 17 * FREGBYTES(sp)
|
||||
FSTORE f18, 18 * FREGBYTES(sp)
|
||||
FSTORE f19, 19 * FREGBYTES(sp)
|
||||
FSTORE f20, 20 * FREGBYTES(sp)
|
||||
FSTORE f21, 21 * FREGBYTES(sp)
|
||||
FSTORE f22, 22 * FREGBYTES(sp)
|
||||
FSTORE f23, 23 * FREGBYTES(sp)
|
||||
FSTORE f24, 24 * FREGBYTES(sp)
|
||||
FSTORE f25, 25 * FREGBYTES(sp)
|
||||
FSTORE f26, 26 * FREGBYTES(sp)
|
||||
FSTORE f27, 27 * FREGBYTES(sp)
|
||||
FSTORE f28, 28 * FREGBYTES(sp)
|
||||
FSTORE f29, 29 * FREGBYTES(sp)
|
||||
FSTORE f30, 30 * FREGBYTES(sp)
|
||||
FSTORE f31, 31 * FREGBYTES(sp)
|
||||
#endif
|
||||
|
||||
addi sp, sp, -32 * REGBYTES
|
||||
/* save from sp */
|
||||
STORE sp, 0(a0)
|
||||
/* save ra to epc */
|
||||
STORE x1, 0 * REGBYTES(sp)
|
||||
STORE x1, 1 * REGBYTES(sp)
|
||||
STORE x5, 5 * REGBYTES(sp)
|
||||
|
||||
csrr t0, mstatus
|
||||
andi t0, t0, 8
|
||||
/* if MIE be enabled,set MPIE */
|
||||
beqz t0, 1f
|
||||
li t0, 0x80
|
||||
|
||||
1: STORE t0, 2 * REGBYTES(sp)
|
||||
STORE x4, 4 * REGBYTES(sp)
|
||||
|
||||
STORE x6, 6 * REGBYTES(sp)
|
||||
STORE x7, 7 * REGBYTES(sp)
|
||||
STORE x8, 8 * REGBYTES(sp)
|
||||
STORE x9, 9 * REGBYTES(sp)
|
||||
STORE x10, 10 * REGBYTES(sp)
|
||||
STORE x11, 11 * REGBYTES(sp)
|
||||
STORE x12, 12 * REGBYTES(sp)
|
||||
STORE x13, 13 * REGBYTES(sp)
|
||||
STORE x14, 14 * REGBYTES(sp)
|
||||
STORE x15, 15 * REGBYTES(sp)
|
||||
STORE x16, 16 * REGBYTES(sp)
|
||||
STORE x17, 17 * REGBYTES(sp)
|
||||
STORE x18, 18 * REGBYTES(sp)
|
||||
STORE x19, 19 * REGBYTES(sp)
|
||||
STORE x20, 20 * REGBYTES(sp)
|
||||
STORE x21, 21 * REGBYTES(sp)
|
||||
STORE x22, 22 * REGBYTES(sp)
|
||||
STORE x23, 23 * REGBYTES(sp)
|
||||
STORE x24, 24 * REGBYTES(sp)
|
||||
STORE x25, 25 * REGBYTES(sp)
|
||||
STORE x26, 26 * REGBYTES(sp)
|
||||
STORE x27, 27 * REGBYTES(sp)
|
||||
STORE x28, 28 * REGBYTES(sp)
|
||||
STORE x29, 29 * REGBYTES(sp)
|
||||
STORE x30, 30 * REGBYTES(sp)
|
||||
STORE x31, 31 * REGBYTES(sp)
|
||||
|
||||
/* get "to" thread sp */
|
||||
LOAD sp, 0(a1)
|
||||
j rt_hw_context_switch_exit
|
||||
|
||||
|
||||
|
||||
.global rt_hw_context_switch_exit
|
||||
rt_hw_context_switch_exit:
|
||||
/* resw ra to mepc */
|
||||
LOAD a0, 0 * REGBYTES(sp)
|
||||
csrw mepc, a0
|
||||
|
||||
LOAD x1, 1 * REGBYTES(sp)
|
||||
|
||||
/* keep machine mode */
|
||||
li a0, 0x1800
|
||||
csrs mstatus, a0
|
||||
/* resume MPIE */
|
||||
LOAD a0, 2*REGBYTES(sp)
|
||||
csrs mstatus, a0
|
||||
|
||||
LOAD x4, 4 * REGBYTES(sp)
|
||||
LOAD x5, 5 * REGBYTES(sp)
|
||||
LOAD x6, 6 * REGBYTES(sp)
|
||||
LOAD x7, 7 * REGBYTES(sp)
|
||||
LOAD x8, 8 * REGBYTES(sp)
|
||||
LOAD x9, 9 * REGBYTES(sp)
|
||||
LOAD x10, 10 * REGBYTES(sp)
|
||||
LOAD x11, 11 * REGBYTES(sp)
|
||||
LOAD x12, 12 * REGBYTES(sp)
|
||||
LOAD x13, 13 * REGBYTES(sp)
|
||||
LOAD x14, 14 * REGBYTES(sp)
|
||||
LOAD x15, 15 * REGBYTES(sp)
|
||||
LOAD x16, 16 * REGBYTES(sp)
|
||||
LOAD x17, 17 * REGBYTES(sp)
|
||||
LOAD x18, 18 * REGBYTES(sp)
|
||||
LOAD x19, 19 * REGBYTES(sp)
|
||||
LOAD x20, 20 * REGBYTES(sp)
|
||||
LOAD x21, 21 * REGBYTES(sp)
|
||||
LOAD x22, 22 * REGBYTES(sp)
|
||||
LOAD x23, 23 * REGBYTES(sp)
|
||||
LOAD x24, 24 * REGBYTES(sp)
|
||||
LOAD x25, 25 * REGBYTES(sp)
|
||||
LOAD x26, 26 * REGBYTES(sp)
|
||||
LOAD x27, 27 * REGBYTES(sp)
|
||||
LOAD x28, 28 * REGBYTES(sp)
|
||||
LOAD x29, 29 * REGBYTES(sp)
|
||||
LOAD x30, 30 * REGBYTES(sp)
|
||||
LOAD x31, 31 * REGBYTES(sp)
|
||||
addi sp, sp, 32 * REGBYTES
|
||||
|
||||
/* load float reg */
|
||||
#ifdef ARCH_RISCV_FPU
|
||||
|
||||
FLOAD f0, 0 * FREGBYTES(sp)
|
||||
FLOAD f1, 1 * FREGBYTES(sp)
|
||||
FLOAD f2, 2 * FREGBYTES(sp)
|
||||
FLOAD f3, 3 * FREGBYTES(sp)
|
||||
FLOAD f4, 4 * FREGBYTES(sp)
|
||||
FLOAD f5, 5 * FREGBYTES(sp)
|
||||
FLOAD f6, 6 * FREGBYTES(sp)
|
||||
FLOAD f7, 7 * FREGBYTES(sp)
|
||||
FLOAD f8, 8 * FREGBYTES(sp)
|
||||
FLOAD f9, 9 * FREGBYTES(sp)
|
||||
FLOAD f10, 10 * FREGBYTES(sp)
|
||||
FLOAD f11, 11 * FREGBYTES(sp)
|
||||
FLOAD f12, 12 * FREGBYTES(sp)
|
||||
FLOAD f13, 13 * FREGBYTES(sp)
|
||||
FLOAD f14, 14 * FREGBYTES(sp)
|
||||
FLOAD f15, 15 * FREGBYTES(sp)
|
||||
FLOAD f16, 16 * FREGBYTES(sp)
|
||||
FLOAD f17, 17 * FREGBYTES(sp)
|
||||
FLOAD f18, 18 * FREGBYTES(sp)
|
||||
FLOAD f19, 19 * FREGBYTES(sp)
|
||||
FLOAD f20, 20 * FREGBYTES(sp)
|
||||
FLOAD f21, 21 * FREGBYTES(sp)
|
||||
FLOAD f22, 22 * FREGBYTES(sp)
|
||||
FLOAD f23, 23 * FREGBYTES(sp)
|
||||
FLOAD f24, 24 * FREGBYTES(sp)
|
||||
FLOAD f25, 25 * FREGBYTES(sp)
|
||||
FLOAD f26, 26 * FREGBYTES(sp)
|
||||
FLOAD f27, 27 * FREGBYTES(sp)
|
||||
FLOAD f28, 28 * FREGBYTES(sp)
|
||||
FLOAD f29, 29 * FREGBYTES(sp)
|
||||
FLOAD f30, 30 * FREGBYTES(sp)
|
||||
FLOAD f31, 31 * FREGBYTES(sp)
|
||||
addi sp, sp, 32 * FREGBYTES
|
||||
#endif
|
||||
|
||||
mret
|
||||
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-09-09 WCH the first version
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include "ch32v20x.h"
|
||||
#include "cpuport.h"
|
||||
|
||||
#ifndef RT_USING_SMP
|
||||
volatile rt_ubase_t rt_interrupt_from_thread = 0;
|
||||
volatile rt_ubase_t rt_interrupt_to_thread = 0;
|
||||
volatile rt_uint32_t rt_thread_switch_interrupt_flag = 0;
|
||||
#endif
|
||||
|
||||
struct rt_hw_stack_frame
|
||||
{
|
||||
rt_ubase_t epc; /* epc - epc - program counter */
|
||||
rt_ubase_t ra; /* x1 - ra - return address for jumps */
|
||||
rt_ubase_t mstatus; /* - machine status register */
|
||||
rt_ubase_t gp; /* x3 - gp - global pointer */
|
||||
rt_ubase_t tp; /* x4 - tp - thread pointer */
|
||||
rt_ubase_t t0; /* x5 - t0 - temporary register 0 */
|
||||
rt_ubase_t t1; /* x6 - t1 - temporary register 1 */
|
||||
rt_ubase_t t2; /* x7 - t2 - temporary register 2 */
|
||||
rt_ubase_t s0_fp; /* x8 - s0/fp - saved register 0 or frame pointer */
|
||||
rt_ubase_t s1; /* x9 - s1 - saved register 1 */
|
||||
rt_ubase_t a0; /* x10 - a0 - return value or function argument 0 */
|
||||
rt_ubase_t a1; /* x11 - a1 - return value or function argument 1 */
|
||||
rt_ubase_t a2; /* x12 - a2 - function argument 2 */
|
||||
rt_ubase_t a3; /* x13 - a3 - function argument 3 */
|
||||
rt_ubase_t a4; /* x14 - a4 - function argument 4 */
|
||||
rt_ubase_t a5; /* x15 - a5 - function argument 5 */
|
||||
rt_ubase_t a6; /* x16 - a6 - function argument 6 */
|
||||
rt_ubase_t a7; /* x17 - s7 - function argument 7 */
|
||||
rt_ubase_t s2; /* x18 - s2 - saved register 2 */
|
||||
rt_ubase_t s3; /* x19 - s3 - saved register 3 */
|
||||
rt_ubase_t s4; /* x20 - s4 - saved register 4 */
|
||||
rt_ubase_t s5; /* x21 - s5 - saved register 5 */
|
||||
rt_ubase_t s6; /* x22 - s6 - saved register 6 */
|
||||
rt_ubase_t s7; /* x23 - s7 - saved register 7 */
|
||||
rt_ubase_t s8; /* x24 - s8 - saved register 8 */
|
||||
rt_ubase_t s9; /* x25 - s9 - saved register 9 */
|
||||
rt_ubase_t s10; /* x26 - s10 - saved register 10 */
|
||||
rt_ubase_t s11; /* x27 - s11 - saved register 11 */
|
||||
rt_ubase_t t3; /* x28 - t3 - temporary register 3 */
|
||||
rt_ubase_t t4; /* x29 - t4 - temporary register 4 */
|
||||
rt_ubase_t t5; /* x30 - t5 - temporary register 5 */
|
||||
rt_ubase_t t6; /* x31 - t6 - temporary register 6 */
|
||||
|
||||
/* float register */
|
||||
#ifdef ARCH_RISCV_FPU
|
||||
rv_floatreg_t f0; /* f0 */
|
||||
rv_floatreg_t f1; /* f1 */
|
||||
rv_floatreg_t f2; /* f2 */
|
||||
rv_floatreg_t f3; /* f3 */
|
||||
rv_floatreg_t f4; /* f4 */
|
||||
rv_floatreg_t f5; /* f5 */
|
||||
rv_floatreg_t f6; /* f6 */
|
||||
rv_floatreg_t f7; /* f7 */
|
||||
rv_floatreg_t f8; /* f8 */
|
||||
rv_floatreg_t f9; /* f9 */
|
||||
rv_floatreg_t f10; /* f10 */
|
||||
rv_floatreg_t f11; /* f11 */
|
||||
rv_floatreg_t f12; /* f12 */
|
||||
rv_floatreg_t f13; /* f13 */
|
||||
rv_floatreg_t f14; /* f14 */
|
||||
rv_floatreg_t f15; /* f15 */
|
||||
rv_floatreg_t f16; /* f16 */
|
||||
rv_floatreg_t f17; /* f17 */
|
||||
rv_floatreg_t f18; /* f18 */
|
||||
rv_floatreg_t f19; /* f19 */
|
||||
rv_floatreg_t f20; /* f20 */
|
||||
rv_floatreg_t f21; /* f21 */
|
||||
rv_floatreg_t f22; /* f22 */
|
||||
rv_floatreg_t f23; /* f23 */
|
||||
rv_floatreg_t f24; /* f24 */
|
||||
rv_floatreg_t f25; /* f25 */
|
||||
rv_floatreg_t f26; /* f26 */
|
||||
rv_floatreg_t f27; /* f27 */
|
||||
rv_floatreg_t f28; /* f28 */
|
||||
rv_floatreg_t f29; /* f29 */
|
||||
rv_floatreg_t f30; /* f30 */
|
||||
rv_floatreg_t f31; /* f31 */
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* This function will initialize thread stack
|
||||
*
|
||||
* @param tentry the entry of thread
|
||||
* @param parameter the parameter of entry
|
||||
* @param stack_addr the beginning stack address
|
||||
* @param texit the function will be called when thread exit
|
||||
*
|
||||
* @return stack address
|
||||
*/
|
||||
rt_uint8_t *rt_hw_stack_init(void *tentry,
|
||||
void *parameter,
|
||||
rt_uint8_t *stack_addr,
|
||||
void *texit)
|
||||
{
|
||||
struct rt_hw_stack_frame *frame;
|
||||
rt_uint8_t *stk;
|
||||
int i;
|
||||
|
||||
stk = stack_addr + sizeof(rt_ubase_t);
|
||||
stk = (rt_uint8_t *)RT_ALIGN_DOWN((rt_ubase_t)stk, REGBYTES);
|
||||
stk -= sizeof(struct rt_hw_stack_frame);
|
||||
|
||||
frame = (struct rt_hw_stack_frame *)stk;
|
||||
|
||||
for (i = 0; i < sizeof(struct rt_hw_stack_frame) / sizeof(rt_ubase_t); i++)
|
||||
{
|
||||
((rt_ubase_t *)frame)[i] = 0xdeadbeef;
|
||||
}
|
||||
|
||||
frame->ra = (rt_ubase_t)texit;
|
||||
frame->a0 = (rt_ubase_t)parameter;
|
||||
frame->epc = (rt_ubase_t)tentry;
|
||||
|
||||
/* force to machine mode(MPP=11) and set MPIE to 1 */
|
||||
frame->mstatus = 0x00001880;
|
||||
return stk;
|
||||
}
|
||||
|
||||
/*
|
||||
* trigger soft interrupt
|
||||
*/
|
||||
void sw_setpend(void)
|
||||
{
|
||||
SysTick->CTLR |= (1<<31);
|
||||
}
|
||||
|
||||
/*
|
||||
* clear soft interrupt
|
||||
*/
|
||||
void sw_clearpend(void)
|
||||
{
|
||||
SysTick->CTLR &= ~(1<<31);
|
||||
}
|
||||
|
||||
/*
|
||||
* disable interrupt and save mstatus
|
||||
*/
|
||||
rt_base_t rt_hw_interrupt_disable(void)
|
||||
{
|
||||
rt_base_t value=0;
|
||||
asm("csrrw %0, mstatus, %1":"=r"(value):"r"(0x1800));
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
* enable interrupt and resume mstatus
|
||||
*/
|
||||
void rt_hw_interrupt_enable(rt_base_t level)
|
||||
{
|
||||
asm("csrw mstatus, %0": :"r"(level));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* #ifdef RT_USING_SMP
|
||||
* void rt_hw_context_switch_interrupt(void *context, rt_ubase_t from, rt_ubase_t to, struct rt_thread *to_thread);
|
||||
* #else
|
||||
* void rt_hw_context_switch_interrupt(rt_ubase_t from, rt_ubase_t to);
|
||||
* #endif
|
||||
*/
|
||||
void rt_hw_context_switch_interrupt(rt_ubase_t from, rt_ubase_t to)
|
||||
{
|
||||
if (rt_thread_switch_interrupt_flag == 0)
|
||||
rt_interrupt_from_thread = from;
|
||||
|
||||
rt_interrupt_to_thread = to;
|
||||
rt_thread_switch_interrupt_flag = 1;
|
||||
/* switch just in SW_Handler */
|
||||
sw_setpend();
|
||||
}
|
||||
|
||||
/* shutdown CPU */
|
||||
void rt_hw_cpu_shutdown(void)
|
||||
{
|
||||
rt_uint32_t level;
|
||||
rt_kprintf("shutdown...\n");
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
while (level)
|
||||
{
|
||||
RT_ASSERT(0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-09-09 WCH the first version
|
||||
*/
|
||||
|
||||
#ifndef CPUPORT_H__
|
||||
#define CPUPORT_H__
|
||||
|
||||
/* bytes of register width */
|
||||
//#define ARCH_RISCV_FPU
|
||||
#define ARCH_RISCV_FPU_S
|
||||
|
||||
#ifdef ARCH_CPU_64BIT
|
||||
#define STORE sd
|
||||
#define LOAD ld
|
||||
#define REGBYTES 8
|
||||
#else
|
||||
#define STORE sw
|
||||
#define LOAD lw
|
||||
#define REGBYTES 4
|
||||
#endif
|
||||
|
||||
/* FPU */
|
||||
#ifdef ARCH_RISCV_FPU
|
||||
#ifdef ARCH_RISCV_FPU_D
|
||||
#define FSTORE fsd
|
||||
#define FLOAD fld
|
||||
#define FREGBYTES 8
|
||||
#define rv_floatreg_t rt_int64_t
|
||||
#endif
|
||||
#ifdef ARCH_RISCV_FPU_S
|
||||
#define FSTORE fsw
|
||||
#define FLOAD flw
|
||||
#define FREGBYTES 4
|
||||
#define rv_floatreg_t rt_int32_t
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-09-09 WCH the first version
|
||||
*/
|
||||
|
||||
#include "cpuport.h"
|
||||
|
||||
.global SW_Handler
|
||||
.align 2
|
||||
SW_Handler:
|
||||
/* save all from thread context */
|
||||
#ifdef ARCH_RISCV_FPU
|
||||
addi sp, sp, -32 * FREGBYTES
|
||||
FSTORE f0, 0 * FREGBYTES(sp)
|
||||
FSTORE f1, 1 * FREGBYTES(sp)
|
||||
FSTORE f2, 2 * FREGBYTES(sp)
|
||||
FSTORE f3, 3 * FREGBYTES(sp)
|
||||
FSTORE f4, 4 * FREGBYTES(sp)
|
||||
FSTORE f5, 5 * FREGBYTES(sp)
|
||||
FSTORE f6, 6 * FREGBYTES(sp)
|
||||
FSTORE f7, 7 * FREGBYTES(sp)
|
||||
FSTORE f8, 8 * FREGBYTES(sp)
|
||||
FSTORE f9, 9 * FREGBYTES(sp)
|
||||
FSTORE f10, 10 * FREGBYTES(sp)
|
||||
FSTORE f11, 11 * FREGBYTES(sp)
|
||||
FSTORE f12, 12 * FREGBYTES(sp)
|
||||
FSTORE f13, 13 * FREGBYTES(sp)
|
||||
FSTORE f14, 14 * FREGBYTES(sp)
|
||||
FSTORE f15, 15 * FREGBYTES(sp)
|
||||
FSTORE f16, 16 * FREGBYTES(sp)
|
||||
FSTORE f17, 17 * FREGBYTES(sp)
|
||||
FSTORE f18, 18 * FREGBYTES(sp)
|
||||
FSTORE f19, 19 * FREGBYTES(sp)
|
||||
FSTORE f20, 20 * FREGBYTES(sp)
|
||||
FSTORE f21, 21 * FREGBYTES(sp)
|
||||
FSTORE f22, 22 * FREGBYTES(sp)
|
||||
FSTORE f23, 23 * FREGBYTES(sp)
|
||||
FSTORE f24, 24 * FREGBYTES(sp)
|
||||
FSTORE f25, 25 * FREGBYTES(sp)
|
||||
FSTORE f26, 26 * FREGBYTES(sp)
|
||||
FSTORE f27, 27 * FREGBYTES(sp)
|
||||
FSTORE f28, 28 * FREGBYTES(sp)
|
||||
FSTORE f29, 29 * FREGBYTES(sp)
|
||||
FSTORE f30, 30 * FREGBYTES(sp)
|
||||
FSTORE f31, 31 * FREGBYTES(sp)
|
||||
#endif
|
||||
|
||||
addi sp, sp, -32 * REGBYTES
|
||||
STORE x5, 5 * REGBYTES(sp)
|
||||
|
||||
/* saved MPIE */
|
||||
li t0, 0x80
|
||||
STORE t0, 2 * REGBYTES(sp)
|
||||
|
||||
/* Temporarily disable HPE */
|
||||
// li t0, 0x20
|
||||
// csrs 0x804, t0
|
||||
|
||||
STORE x1, 1 * REGBYTES(sp)
|
||||
STORE x4, 4 * REGBYTES(sp)
|
||||
STORE x6, 6 * REGBYTES(sp)
|
||||
STORE x7, 7 * REGBYTES(sp)
|
||||
STORE x8, 8 * REGBYTES(sp)
|
||||
STORE x9, 9 * REGBYTES(sp)
|
||||
STORE x10, 10 * REGBYTES(sp)
|
||||
STORE x11, 11 * REGBYTES(sp)
|
||||
STORE x12, 12 * REGBYTES(sp)
|
||||
STORE x13, 13 * REGBYTES(sp)
|
||||
STORE x14, 14 * REGBYTES(sp)
|
||||
STORE x15, 15 * REGBYTES(sp)
|
||||
STORE x16, 16 * REGBYTES(sp)
|
||||
STORE x17, 17 * REGBYTES(sp)
|
||||
STORE x18, 18 * REGBYTES(sp)
|
||||
STORE x19, 19 * REGBYTES(sp)
|
||||
STORE x20, 20 * REGBYTES(sp)
|
||||
STORE x21, 21 * REGBYTES(sp)
|
||||
STORE x22, 22 * REGBYTES(sp)
|
||||
STORE x23, 23 * REGBYTES(sp)
|
||||
STORE x24, 24 * REGBYTES(sp)
|
||||
STORE x25, 25 * REGBYTES(sp)
|
||||
STORE x26, 26 * REGBYTES(sp)
|
||||
STORE x27, 27 * REGBYTES(sp)
|
||||
STORE x28, 28 * REGBYTES(sp)
|
||||
STORE x29, 29 * REGBYTES(sp)
|
||||
STORE x30, 30 * REGBYTES(sp)
|
||||
STORE x31, 31 * REGBYTES(sp)
|
||||
|
||||
/* switch to interrupt stack */
|
||||
csrrw sp,mscratch,sp
|
||||
call rt_interrupt_enter
|
||||
/* clear interrupt */
|
||||
jal sw_clearpend
|
||||
call rt_interrupt_leave
|
||||
/* switch to from thread stack */
|
||||
csrrw sp,mscratch,sp
|
||||
|
||||
/* if rt_thread_switch_interrupt_flag=1,then clear it */
|
||||
la s0, rt_thread_switch_interrupt_flag
|
||||
lw s2, 0(s0)
|
||||
beqz s2, 1f
|
||||
sw zero, 0(s0)
|
||||
#1:
|
||||
csrr a0, mepc
|
||||
STORE a0, 0 * REGBYTES(sp)
|
||||
|
||||
la s0, rt_interrupt_from_thread
|
||||
LOAD s1, 0(s0)
|
||||
STORE sp, 0(s1)
|
||||
|
||||
la s0, rt_interrupt_to_thread
|
||||
LOAD s1, 0(s0)
|
||||
LOAD sp, 0(s1)
|
||||
|
||||
LOAD a0, 0 * REGBYTES(sp)
|
||||
csrw mepc, a0
|
||||
|
||||
1: LOAD x1, 1 * REGBYTES(sp)
|
||||
|
||||
li t0,0x1800
|
||||
csrs mstatus, t0
|
||||
LOAD t0, 2*REGBYTES(sp)
|
||||
csrs mstatus, t0
|
||||
|
||||
LOAD x4, 4 * REGBYTES(sp)
|
||||
LOAD x5, 5 * REGBYTES(sp)
|
||||
LOAD x6, 6 * REGBYTES(sp)
|
||||
LOAD x7, 7 * REGBYTES(sp)
|
||||
LOAD x8, 8 * REGBYTES(sp)
|
||||
LOAD x9, 9 * REGBYTES(sp)
|
||||
LOAD x10, 10 * REGBYTES(sp)
|
||||
LOAD x11, 11 * REGBYTES(sp)
|
||||
LOAD x12, 12 * REGBYTES(sp)
|
||||
LOAD x13, 13 * REGBYTES(sp)
|
||||
LOAD x14, 14 * REGBYTES(sp)
|
||||
LOAD x15, 15 * REGBYTES(sp)
|
||||
LOAD x16, 16 * REGBYTES(sp)
|
||||
LOAD x17, 17 * REGBYTES(sp)
|
||||
LOAD x18, 18 * REGBYTES(sp)
|
||||
LOAD x19, 19 * REGBYTES(sp)
|
||||
LOAD x20, 20 * REGBYTES(sp)
|
||||
LOAD x21, 21 * REGBYTES(sp)
|
||||
LOAD x22, 22 * REGBYTES(sp)
|
||||
LOAD x23, 23 * REGBYTES(sp)
|
||||
LOAD x24, 24 * REGBYTES(sp)
|
||||
LOAD x25, 25 * REGBYTES(sp)
|
||||
LOAD x26, 26 * REGBYTES(sp)
|
||||
LOAD x27, 27 * REGBYTES(sp)
|
||||
LOAD x28, 28 * REGBYTES(sp)
|
||||
LOAD x29, 29 * REGBYTES(sp)
|
||||
LOAD x30, 30 * REGBYTES(sp)
|
||||
LOAD x31, 31 * REGBYTES(sp)
|
||||
addi sp, sp, 32 * REGBYTES
|
||||
|
||||
/* load float reg */
|
||||
#ifdef ARCH_RISCV_FPU
|
||||
FLOAD f0, 0 * FREGBYTES(sp)
|
||||
FLOAD f1, 1 * FREGBYTES(sp)
|
||||
FLOAD f2, 2 * FREGBYTES(sp)
|
||||
FLOAD f3, 3 * FREGBYTES(sp)
|
||||
FLOAD f4, 4 * FREGBYTES(sp)
|
||||
FLOAD f5, 5 * FREGBYTES(sp)
|
||||
FLOAD f6, 6 * FREGBYTES(sp)
|
||||
FLOAD f7, 7 * FREGBYTES(sp)
|
||||
FLOAD f8, 8 * FREGBYTES(sp)
|
||||
FLOAD f9, 9 * FREGBYTES(sp)
|
||||
FLOAD f10, 10 * FREGBYTES(sp)
|
||||
FLOAD f11, 11 * FREGBYTES(sp)
|
||||
FLOAD f12, 12 * FREGBYTES(sp)
|
||||
FLOAD f13, 13 * FREGBYTES(sp)
|
||||
FLOAD f14, 14 * FREGBYTES(sp)
|
||||
FLOAD f15, 15 * FREGBYTES(sp)
|
||||
FLOAD f16, 16 * FREGBYTES(sp)
|
||||
FLOAD f17, 17 * FREGBYTES(sp)
|
||||
FLOAD f18, 18 * FREGBYTES(sp)
|
||||
FLOAD f19, 19 * FREGBYTES(sp)
|
||||
FLOAD f20, 20 * FREGBYTES(sp)
|
||||
FLOAD f21, 21 * FREGBYTES(sp)
|
||||
FLOAD f22, 22 * FREGBYTES(sp)
|
||||
FLOAD f23, 23 * FREGBYTES(sp)
|
||||
FLOAD f24, 24 * FREGBYTES(sp)
|
||||
FLOAD f25, 25 * FREGBYTES(sp)
|
||||
FLOAD f26, 26 * FREGBYTES(sp)
|
||||
FLOAD f27, 27 * FREGBYTES(sp)
|
||||
FLOAD f28, 28 * FREGBYTES(sp)
|
||||
FLOAD f29, 29 * FREGBYTES(sp)
|
||||
FLOAD f30, 30 * FREGBYTES(sp)
|
||||
FLOAD f31, 31 * FREGBYTES(sp)
|
||||
addi sp, sp, 32 * FREGBYTES
|
||||
#endif
|
||||
mret
|
||||
@@ -0,0 +1,159 @@
|
||||
/* RT-Thread config file */
|
||||
|
||||
#ifndef __RTTHREAD_CFG_H__
|
||||
#define __RTTHREAD_CFG_H__
|
||||
|
||||
#if defined(__CC_ARM) || defined(__CLANG_ARM)
|
||||
#include "RTE_Components.h"
|
||||
|
||||
#if defined(RTE_USING_FINSH)
|
||||
#define RT_USING_FINSH
|
||||
#endif //RTE_USING_FINSH
|
||||
|
||||
#endif //(__CC_ARM) || (__CLANG_ARM)
|
||||
|
||||
// <<< Use Configuration Wizard in Context Menu >>>
|
||||
// <h>Basic Configuration
|
||||
// <o>Maximal level of thread priority <8-256>
|
||||
// <i>Default: 32
|
||||
#define RT_THREAD_PRIORITY_MAX 16
|
||||
// <o>OS tick per second
|
||||
// <i>Default: 1000 (1ms)
|
||||
#define RT_TICK_PER_SECOND 1000
|
||||
// <o>Alignment size for CPU architecture data access
|
||||
// <i>Default: 4
|
||||
#define RT_ALIGN_SIZE 4
|
||||
// <o>the max length of object name<2-16>
|
||||
// <i>Default: 8
|
||||
#define RT_NAME_MAX 8
|
||||
// <c1>Using RT-Thread components initialization
|
||||
// <i>Using RT-Thread components initialization
|
||||
#define RT_USING_COMPONENTS_INIT
|
||||
// </c>
|
||||
|
||||
#define RT_USING_USER_MAIN
|
||||
|
||||
// <o>the stack size of main thread<1-4086>
|
||||
// <i>Default: 512
|
||||
#define RT_MAIN_THREAD_STACK_SIZE 512
|
||||
|
||||
// </h>
|
||||
|
||||
// <h>Debug Configuration
|
||||
// <c1>enable kernel debug configuration
|
||||
// <i>Default: enable kernel debug configuration
|
||||
//#define RT_DEBUG
|
||||
// </c>
|
||||
// <o>enable components initialization debug configuration<0-1>
|
||||
// <i>Default: 0
|
||||
#define RT_DEBUG_INIT 0
|
||||
// <c1>thread stack over flow detect
|
||||
// <i> Diable Thread stack over flow detect
|
||||
//#define RT_USING_OVERFLOW_CHECK
|
||||
// </c>
|
||||
// </h>
|
||||
|
||||
// <h>Hook Configuration
|
||||
// <c1>using hook
|
||||
// <i>using hook
|
||||
#define RT_USING_HOOK
|
||||
// </c>
|
||||
// <c1>using idle hook
|
||||
// <i>using idle hook
|
||||
#define RT_USING_IDLE_HOOK
|
||||
// </c>
|
||||
// </h>
|
||||
|
||||
// <e>Software timers Configuration
|
||||
// <i> Enables user timers
|
||||
#define RT_USING_TIMER_SOFT 0
|
||||
#if RT_USING_TIMER_SOFT == 0
|
||||
#undef RT_USING_TIMER_SOFT
|
||||
#endif
|
||||
// <o>The priority level of timer thread <0-31>
|
||||
// <i>Default: 4
|
||||
#define RT_TIMER_THREAD_PRIO 4
|
||||
// <o>The stack size of timer thread <0-8192>
|
||||
// <i>Default: 512
|
||||
#define RT_TIMER_THREAD_STACK_SIZE 512
|
||||
// </e>
|
||||
|
||||
// <h>IPC(Inter-process communication) Configuration
|
||||
// <c1>Using Semaphore
|
||||
// <i>Using Semaphore
|
||||
#define RT_USING_SEMAPHORE
|
||||
// </c>
|
||||
// <c1>Using Mutex
|
||||
// <i>Using Mutex
|
||||
#define RT_USING_MUTEX
|
||||
// </c>
|
||||
// <c1>Using Event
|
||||
// <i>Using Event
|
||||
#define RT_USING_EVENT
|
||||
// </c>
|
||||
// <c1>Using MailBox
|
||||
// <i>Using MailBox
|
||||
#define RT_USING_MAILBOX
|
||||
// </c>
|
||||
// <c1>Using Message Queue
|
||||
// <i>Using Message Queue
|
||||
#define RT_USING_MESSAGEQUEUE
|
||||
// </c>
|
||||
// </h>
|
||||
|
||||
|
||||
// <h>Memory Management Configuration
|
||||
// <c1>Dynamic Heap Management
|
||||
// <i>Dynamic Heap Management
|
||||
//#define RT_USING_MEMPOOL
|
||||
//#define RT_USING_MEMHEAP
|
||||
#define RT_USING_SMALL_MEM
|
||||
#define RT_USING_HEAP
|
||||
|
||||
|
||||
// </c>
|
||||
// <c1>using tiny size of memory
|
||||
// <i>using tiny size of memory
|
||||
//#define RT_USING_TINY_SIZE
|
||||
// </c>
|
||||
// </h>
|
||||
|
||||
/* Kernel Device Object */
|
||||
|
||||
#define RT_USING_DEVICE
|
||||
#define RT_USING_CONSOLE
|
||||
#define RT_CONSOLEBUF_SIZE 128
|
||||
#define RT_CONSOLE_DEVICE_NAME "uart1"
|
||||
|
||||
|
||||
#define RT_USING_FINSH
|
||||
#if defined(RT_USING_FINSH)
|
||||
#define FINSH_USING_MSH
|
||||
#define FINSH_USING_MSH_DEFAULT
|
||||
#define FINSH_USING_MSH_ONLY
|
||||
#define FINSH_THREAD_NAME "tshell"
|
||||
|
||||
#define __FINSH_THREAD_PRIORITY 5
|
||||
#define FINSH_THREAD_PRIORITY (RT_THREAD_PRIORITY_MAX / 8 * __FINSH_THREAD_PRIORITY + 1)
|
||||
// <o>the stack of finsh thread <1-4096>
|
||||
// <i>the stack of finsh thread
|
||||
// <i>Default: 4096 (4096Byte)
|
||||
#define FINSH_THREAD_STACK_SIZE 1024
|
||||
|
||||
#define FINSH_USING_HISTORY
|
||||
#define FINSH_HISTORY_LINES 5
|
||||
#define FINSH_USING_SYMTAB
|
||||
#define FINSH_USING_DESCRIPTION
|
||||
#define FINSH_CMD_SIZE 80
|
||||
|
||||
// </h>
|
||||
#endif
|
||||
|
||||
// <<< end of configuration section >>>
|
||||
|
||||
#define RT_USING_SERIAL
|
||||
#define RT_USING_PIN
|
||||
#define RT_USING_UART1
|
||||
#define RT_USING_DEVICE_IPC
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2006-03-12 Bernard first version
|
||||
* 2006-05-27 Bernard add support for same priority thread schedule
|
||||
* 2006-08-10 Bernard remove the last rt_schedule in rt_tick_increase
|
||||
* 2010-03-08 Bernard remove rt_passed_second
|
||||
* 2010-05-20 Bernard fix the tick exceeds the maximum limits
|
||||
* 2010-07-13 Bernard fix rt_tick_from_millisecond issue found by kuronca
|
||||
* 2011-06-26 Bernard add rt_tick_set function.
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
static rt_tick_t rt_tick = 0;
|
||||
|
||||
/**
|
||||
* This function will init system tick and set it to zero.
|
||||
* @ingroup SystemInit
|
||||
*
|
||||
* @deprecated since 1.1.0, this function does not need to be invoked
|
||||
* in the system initialization.
|
||||
*/
|
||||
void rt_system_tick_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @addtogroup Clock
|
||||
*/
|
||||
|
||||
/**@{*/
|
||||
|
||||
/**
|
||||
* This function will return current tick from operating system startup
|
||||
*
|
||||
* @return current tick
|
||||
*/
|
||||
rt_tick_t rt_tick_get(void)
|
||||
{
|
||||
/* return the global tick */
|
||||
return rt_tick;
|
||||
}
|
||||
RTM_EXPORT(rt_tick_get);
|
||||
|
||||
/**
|
||||
* This function will set current tick
|
||||
*/
|
||||
void rt_tick_set(rt_tick_t tick)
|
||||
{
|
||||
rt_base_t level;
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
rt_tick = tick;
|
||||
rt_hw_interrupt_enable(level);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will notify kernel there is one tick passed. Normally,
|
||||
* this function is invoked by clock ISR.
|
||||
*/
|
||||
void rt_tick_increase(void)
|
||||
{
|
||||
struct rt_thread *thread;
|
||||
|
||||
/* increase the global tick */
|
||||
++ rt_tick;
|
||||
|
||||
/* check time slice */
|
||||
thread = rt_thread_self();
|
||||
|
||||
-- thread->remaining_tick;
|
||||
if (thread->remaining_tick == 0)
|
||||
{
|
||||
/* change to initialized tick */
|
||||
thread->remaining_tick = thread->init_tick;
|
||||
|
||||
/* yield */
|
||||
rt_thread_yield();
|
||||
}
|
||||
|
||||
/* check timer */
|
||||
rt_timer_check();
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will calculate the tick from millisecond.
|
||||
*
|
||||
* @param ms the specified millisecond
|
||||
* - Negative Number wait forever
|
||||
* - Zero not wait
|
||||
* - Max 0x7fffffff
|
||||
*
|
||||
* @return the calculated tick
|
||||
*/
|
||||
rt_tick_t rt_tick_from_millisecond(rt_int32_t ms)
|
||||
{
|
||||
rt_tick_t tick;
|
||||
|
||||
if (ms < 0)
|
||||
{
|
||||
tick = (rt_tick_t)RT_WAITING_FOREVER;
|
||||
}
|
||||
else
|
||||
{
|
||||
tick = RT_TICK_PER_SECOND * (ms / 1000);
|
||||
tick += (RT_TICK_PER_SECOND * (ms % 1000) + 999) / 1000;
|
||||
}
|
||||
|
||||
/* return the calculated tick */
|
||||
return tick;
|
||||
}
|
||||
RTM_EXPORT(rt_tick_from_millisecond);
|
||||
|
||||
/**@}*/
|
||||
|
||||
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-09-20 Bernard Change the name to components.c
|
||||
* And all components related header files.
|
||||
* 2012-12-23 Bernard fix the pthread initialization issue.
|
||||
* 2013-06-23 Bernard Add the init_call for components initialization.
|
||||
* 2013-07-05 Bernard Remove initialization feature for MS VC++ compiler
|
||||
* 2015-02-06 Bernard Remove the MS VC++ support and move to the kernel
|
||||
* 2015-05-04 Bernard Rename it to components.c because compiling issue
|
||||
* in some IDEs.
|
||||
* 2015-07-29 Arda.Fu Add support to use RT_USING_USER_MAIN with IAR
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
#ifdef RT_USING_USER_MAIN
|
||||
#ifndef RT_MAIN_THREAD_STACK_SIZE
|
||||
#define RT_MAIN_THREAD_STACK_SIZE 2048
|
||||
#endif
|
||||
#ifndef RT_MAIN_THREAD_PRIORITY
|
||||
#define RT_MAIN_THREAD_PRIORITY (RT_THREAD_PRIORITY_MAX / 3)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_COMPONENTS_INIT
|
||||
/*
|
||||
* Components Initialization will initialize some driver and components as following
|
||||
* order:
|
||||
* rti_start --> 0
|
||||
* BOARD_EXPORT --> 1
|
||||
* rti_board_end --> 1.end
|
||||
*
|
||||
* DEVICE_EXPORT --> 2
|
||||
* COMPONENT_EXPORT --> 3
|
||||
* FS_EXPORT --> 4
|
||||
* ENV_EXPORT --> 5
|
||||
* APP_EXPORT --> 6
|
||||
*
|
||||
* rti_end --> 6.end
|
||||
*
|
||||
* These automatically initialization, the driver or component initial function must
|
||||
* be defined with:
|
||||
* INIT_BOARD_EXPORT(fn);
|
||||
* INIT_DEVICE_EXPORT(fn);
|
||||
* ...
|
||||
* INIT_APP_EXPORT(fn);
|
||||
* etc.
|
||||
*/
|
||||
static int rti_start(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
INIT_EXPORT(rti_start, "0");
|
||||
|
||||
static int rti_board_start(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
INIT_EXPORT(rti_board_start, "0.end");
|
||||
|
||||
static int rti_board_end(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
INIT_EXPORT(rti_board_end, "1.end");
|
||||
|
||||
static int rti_end(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
INIT_EXPORT(rti_end, "6.end");
|
||||
|
||||
/**
|
||||
* RT-Thread Components Initialization for board
|
||||
*/
|
||||
void rt_components_board_init(void)
|
||||
{
|
||||
#if RT_DEBUG_INIT
|
||||
int result;
|
||||
const struct rt_init_desc *desc;
|
||||
for (desc = &__rt_init_desc_rti_board_start; desc < &__rt_init_desc_rti_board_end; desc ++)
|
||||
{
|
||||
rt_kprintf("initialize %s", desc->fn_name);
|
||||
result = desc->fn();
|
||||
rt_kprintf(":%d done\n", result);
|
||||
}
|
||||
#else
|
||||
const init_fn_t *fn_ptr;
|
||||
|
||||
for (fn_ptr = &__rt_init_rti_board_start; fn_ptr < &__rt_init_rti_board_end; fn_ptr++)
|
||||
{
|
||||
(*fn_ptr)();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* RT-Thread Components Initialization
|
||||
*/
|
||||
void rt_components_init(void)
|
||||
{
|
||||
#if RT_DEBUG_INIT
|
||||
int result;
|
||||
const struct rt_init_desc *desc;
|
||||
|
||||
rt_kprintf("do components initialization.\n");
|
||||
for (desc = &__rt_init_desc_rti_board_end; desc < &__rt_init_desc_rti_end; desc ++)
|
||||
{
|
||||
rt_kprintf("initialize %s", desc->fn_name);
|
||||
result = desc->fn();
|
||||
rt_kprintf(":%d done\n", result);
|
||||
}
|
||||
#else
|
||||
const init_fn_t *fn_ptr;
|
||||
|
||||
for (fn_ptr = &__rt_init_rti_board_end; fn_ptr < &__rt_init_rti_end; fn_ptr ++)
|
||||
{
|
||||
(*fn_ptr)();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef RT_USING_USER_MAIN
|
||||
|
||||
void rt_application_init(void);
|
||||
void rt_hw_board_init(void);
|
||||
int rtthread_startup(void);
|
||||
|
||||
#if defined(__CC_ARM) || defined(__CLANG_ARM)
|
||||
extern int $Super$$main(void);
|
||||
/* re-define main function */
|
||||
int $Sub$$main(void)
|
||||
{
|
||||
rtthread_startup();
|
||||
return 0;
|
||||
}
|
||||
#elif defined(__ICCARM__)
|
||||
extern int main(void);
|
||||
/* __low_level_init will auto called by IAR cstartup */
|
||||
extern void __iar_data_init3(void);
|
||||
int __low_level_init(void)
|
||||
{
|
||||
// call IAR table copy function.
|
||||
__iar_data_init3();
|
||||
rtthread_startup();
|
||||
return 0;
|
||||
}
|
||||
#elif defined(__GNUC__)
|
||||
extern int main(void);
|
||||
/* Add -eentry to arm-none-eabi-gcc argument */
|
||||
int entry(void)
|
||||
{
|
||||
rtthread_startup();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef RT_USING_HEAP
|
||||
/* if there is not enable heap, we should use static thread and stack. */
|
||||
ALIGN(8)
|
||||
static rt_uint8_t main_stack[RT_MAIN_THREAD_STACK_SIZE];
|
||||
struct rt_thread main_thread;
|
||||
#endif
|
||||
|
||||
/* the system main thread */
|
||||
void main_thread_entry(void *parameter)
|
||||
{
|
||||
// extern int main(void);
|
||||
// extern int $Super$$main(void);
|
||||
|
||||
/* RT-Thread components initialization */
|
||||
rt_components_init();
|
||||
|
||||
/* invoke system main function */
|
||||
#if defined(__CC_ARM) || defined(__CLANG_ARM)
|
||||
$Super$$main(); /* for ARMCC. */
|
||||
#elif defined(__ICCARM__) || defined(__GNUC__)
|
||||
main();
|
||||
#endif
|
||||
}
|
||||
|
||||
void rt_application_init(void)
|
||||
{
|
||||
rt_thread_t tid;
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
tid = rt_thread_create("main", main_thread_entry, RT_NULL,
|
||||
RT_MAIN_THREAD_STACK_SIZE, RT_MAIN_THREAD_PRIORITY, 20);
|
||||
RT_ASSERT(tid != RT_NULL);
|
||||
#else
|
||||
rt_err_t result;
|
||||
|
||||
tid = &main_thread;
|
||||
result = rt_thread_init(tid, "main", main_thread_entry, RT_NULL,
|
||||
main_stack, sizeof(main_stack), RT_MAIN_THREAD_PRIORITY, 20);
|
||||
RT_ASSERT(result == RT_EOK);
|
||||
|
||||
/* if not define RT_USING_HEAP, using to eliminate the warning */
|
||||
(void)result;
|
||||
#endif
|
||||
|
||||
rt_thread_startup(tid);
|
||||
}
|
||||
|
||||
int rtthread_startup(void)
|
||||
{
|
||||
rt_hw_interrupt_disable();
|
||||
|
||||
/* board level initialization
|
||||
* NOTE: please initialize heap inside board initialization.
|
||||
*/
|
||||
rt_hw_board_init();
|
||||
|
||||
/* show RT-Thread version */
|
||||
rt_show_version();
|
||||
|
||||
/* timer system initialization */
|
||||
rt_system_timer_init();
|
||||
|
||||
/* scheduler system initialization */
|
||||
rt_system_scheduler_init();
|
||||
|
||||
#ifdef RT_USING_SIGNALS
|
||||
/* signal system initialization */
|
||||
rt_system_signal_init();
|
||||
#endif
|
||||
|
||||
/* create init_thread */
|
||||
rt_application_init();
|
||||
|
||||
/* timer thread initialization */
|
||||
rt_system_timer_thread_init();
|
||||
|
||||
/* idle thread initialization */
|
||||
rt_thread_idle_init();
|
||||
|
||||
/* start scheduler */
|
||||
rt_system_scheduler_start();
|
||||
|
||||
/* never reach here */
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2018-10-30 Bernard The first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rthw.h>
|
||||
|
||||
/* nothing on non-smp version */
|
||||
@@ -0,0 +1,494 @@
|
||||
/*
|
||||
* File : device.c
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2006 - 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
|
||||
* 2007-01-21 Bernard the first version
|
||||
* 2010-05-04 Bernard add rt_device_init implementation
|
||||
* 2012-10-20 Bernard add device check in register function,
|
||||
* provided by Rob <rdent@iinet.net.au>
|
||||
* 2012-12-25 Bernard return RT_EOK if the device interface not exist.
|
||||
* 2013-07-09 Grissiom add ref_count support
|
||||
* 2016-04-02 Bernard fix the open_flag initialization issue.
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#if defined(RT_USING_POSIX)
|
||||
#include <rtdevice.h> /* for wqueue_init */
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_DEVICE
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
#define device_init (dev->ops->init)
|
||||
#define device_open (dev->ops->open)
|
||||
#define device_close (dev->ops->close)
|
||||
#define device_read (dev->ops->read)
|
||||
#define device_write (dev->ops->write)
|
||||
#define device_control (dev->ops->control)
|
||||
#else
|
||||
#define device_init (dev->init)
|
||||
#define device_open (dev->open)
|
||||
#define device_close (dev->close)
|
||||
#define device_read (dev->read)
|
||||
#define device_write (dev->write)
|
||||
#define device_control (dev->control)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This function registers a device driver with specified name.
|
||||
*
|
||||
* @param dev the pointer of device driver structure
|
||||
* @param name the device driver's name
|
||||
* @param flags the capabilities flag of device
|
||||
*
|
||||
* @return the error code, RT_EOK on initialization successfully.
|
||||
*/
|
||||
rt_err_t rt_device_register(rt_device_t dev,
|
||||
const char *name,
|
||||
rt_uint16_t flags)
|
||||
{
|
||||
if (dev == RT_NULL)
|
||||
return -RT_ERROR;
|
||||
|
||||
if (rt_device_find(name) != RT_NULL)
|
||||
return -RT_ERROR;
|
||||
|
||||
rt_object_init(&(dev->parent), RT_Object_Class_Device, name);
|
||||
dev->flag = flags;
|
||||
dev->ref_count = 0;
|
||||
dev->open_flag = 0;
|
||||
|
||||
#if defined(RT_USING_POSIX)
|
||||
dev->fops = RT_NULL;
|
||||
rt_wqueue_init(&(dev->wait_queue));
|
||||
#endif
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
RTM_EXPORT(rt_device_register);
|
||||
|
||||
/**
|
||||
* This function removes a previously registered device driver
|
||||
*
|
||||
* @param dev the pointer of device driver structure
|
||||
*
|
||||
* @return the error code, RT_EOK on successfully.
|
||||
*/
|
||||
rt_err_t rt_device_unregister(rt_device_t dev)
|
||||
{
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device);
|
||||
RT_ASSERT(rt_object_is_systemobject(&dev->parent));
|
||||
|
||||
rt_object_detach(&(dev->parent));
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
RTM_EXPORT(rt_device_unregister);
|
||||
|
||||
/**
|
||||
* This function initializes all registered device driver
|
||||
*
|
||||
* @return the error code, RT_EOK on successfully.
|
||||
*
|
||||
* @deprecated since 1.2.x, this function is not needed because the initialization
|
||||
* of a device is performed when applicaiton opens it.
|
||||
*/
|
||||
rt_err_t rt_device_init_all(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function finds a device driver by specified name.
|
||||
*
|
||||
* @param name the device driver's name
|
||||
*
|
||||
* @return the registered device driver on successful, or RT_NULL on failure.
|
||||
*/
|
||||
rt_device_t rt_device_find(const char *name)
|
||||
{
|
||||
struct rt_object *object;
|
||||
struct rt_list_node *node;
|
||||
struct rt_object_information *information;
|
||||
|
||||
/* enter critical */
|
||||
if (rt_thread_self() != RT_NULL)
|
||||
rt_enter_critical();
|
||||
|
||||
/* try to find device object */
|
||||
information = rt_object_get_information(RT_Object_Class_Device);
|
||||
RT_ASSERT(information != RT_NULL);
|
||||
for (node = information->object_list.next;
|
||||
node != &(information->object_list);
|
||||
node = node->next)
|
||||
{
|
||||
object = rt_list_entry(node, struct rt_object, list);
|
||||
if (rt_strncmp(object->name, name, RT_NAME_MAX) == 0)
|
||||
{
|
||||
/* leave critical */
|
||||
if (rt_thread_self() != RT_NULL)
|
||||
rt_exit_critical();
|
||||
|
||||
return (rt_device_t)object;
|
||||
}
|
||||
}
|
||||
|
||||
/* leave critical */
|
||||
if (rt_thread_self() != RT_NULL)
|
||||
rt_exit_critical();
|
||||
|
||||
/* not found */
|
||||
return RT_NULL;
|
||||
}
|
||||
RTM_EXPORT(rt_device_find);
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
/**
|
||||
* This function creates a device object with user data size.
|
||||
*
|
||||
* @param type, the kind type of this device object.
|
||||
* @param attach_size, the size of user data.
|
||||
*
|
||||
* @return the allocated device object, or RT_NULL when failed.
|
||||
*/
|
||||
rt_device_t rt_device_create(int type, int attach_size)
|
||||
{
|
||||
int size;
|
||||
rt_device_t device;
|
||||
|
||||
size = RT_ALIGN(sizeof(struct rt_device), RT_ALIGN_SIZE);
|
||||
attach_size = RT_ALIGN(attach_size, RT_ALIGN_SIZE);
|
||||
/* use the totoal size */
|
||||
size += attach_size;
|
||||
|
||||
device = (rt_device_t)rt_malloc(size);
|
||||
if (device)
|
||||
{
|
||||
rt_memset(device, 0x0, sizeof(struct rt_device));
|
||||
device->type = (enum rt_device_class_type)type;
|
||||
}
|
||||
|
||||
return device;
|
||||
}
|
||||
RTM_EXPORT(rt_device_create);
|
||||
|
||||
/**
|
||||
* This function destroy the specific device object.
|
||||
*
|
||||
* @param dev, the specific device object.
|
||||
*/
|
||||
void rt_device_destroy(rt_device_t dev)
|
||||
{
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device);
|
||||
RT_ASSERT(rt_object_is_systemobject(&dev->parent) == RT_FALSE);
|
||||
|
||||
rt_object_detach(&(dev->parent));
|
||||
|
||||
/* release this device object */
|
||||
rt_free(dev);
|
||||
}
|
||||
RTM_EXPORT(rt_device_destroy);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This function will initialize the specified device
|
||||
*
|
||||
* @param dev the pointer of device driver structure
|
||||
*
|
||||
* @return the result
|
||||
*/
|
||||
rt_err_t rt_device_init(rt_device_t dev)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
|
||||
/* get device init handler */
|
||||
if (device_init != RT_NULL)
|
||||
{
|
||||
if (!(dev->flag & RT_DEVICE_FLAG_ACTIVATED))
|
||||
{
|
||||
result = device_init(dev);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
rt_kprintf("To initialize device:%s failed. The error code is %d\n",
|
||||
dev->parent.name, result);
|
||||
}
|
||||
else
|
||||
{
|
||||
dev->flag |= RT_DEVICE_FLAG_ACTIVATED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will open a device
|
||||
*
|
||||
* @param dev the pointer of device driver structure
|
||||
* @param oflag the flags for device open
|
||||
*
|
||||
* @return the result
|
||||
*/
|
||||
rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflag)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device);
|
||||
|
||||
/* if device is not initialized, initialize it. */
|
||||
if (!(dev->flag & RT_DEVICE_FLAG_ACTIVATED))
|
||||
{
|
||||
if (device_init != RT_NULL)
|
||||
{
|
||||
result = device_init(dev);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
rt_kprintf("To initialize device:%s failed. The error code is %d\n",
|
||||
dev->parent.name, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
dev->flag |= RT_DEVICE_FLAG_ACTIVATED;
|
||||
}
|
||||
|
||||
/* device is a stand alone device and opened */
|
||||
if ((dev->flag & RT_DEVICE_FLAG_STANDALONE) &&
|
||||
(dev->open_flag & RT_DEVICE_OFLAG_OPEN))
|
||||
{
|
||||
return -RT_EBUSY;
|
||||
}
|
||||
|
||||
/* call device open interface */
|
||||
if (device_open != RT_NULL)
|
||||
{
|
||||
result = device_open(dev, oflag);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* set open flag */
|
||||
dev->open_flag = (oflag & RT_DEVICE_OFLAG_MASK);
|
||||
}
|
||||
|
||||
/* set open flag */
|
||||
if (result == RT_EOK || result == -RT_ENOSYS)
|
||||
{
|
||||
dev->open_flag |= RT_DEVICE_OFLAG_OPEN;
|
||||
|
||||
dev->ref_count++;
|
||||
/* don't let bad things happen silently. If you are bitten by this assert,
|
||||
* please set the ref_count to a bigger type. */
|
||||
RT_ASSERT(dev->ref_count != 0);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
RTM_EXPORT(rt_device_open);
|
||||
|
||||
/**
|
||||
* This function will close a device
|
||||
*
|
||||
* @param dev the pointer of device driver structure
|
||||
*
|
||||
* @return the result
|
||||
*/
|
||||
rt_err_t rt_device_close(rt_device_t dev)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device);
|
||||
|
||||
if (dev->ref_count == 0)
|
||||
return -RT_ERROR;
|
||||
|
||||
dev->ref_count--;
|
||||
|
||||
if (dev->ref_count != 0)
|
||||
return RT_EOK;
|
||||
|
||||
/* call device close interface */
|
||||
if (device_close != RT_NULL)
|
||||
{
|
||||
result = device_close(dev);
|
||||
}
|
||||
|
||||
/* set open flag */
|
||||
if (result == RT_EOK || result == -RT_ENOSYS)
|
||||
dev->open_flag = RT_DEVICE_OFLAG_CLOSE;
|
||||
|
||||
return result;
|
||||
}
|
||||
RTM_EXPORT(rt_device_close);
|
||||
|
||||
/**
|
||||
* This function will read some data from a device.
|
||||
*
|
||||
* @param dev the pointer of device driver structure
|
||||
* @param pos the position of reading
|
||||
* @param buffer the data buffer to save read data
|
||||
* @param size the size of buffer
|
||||
*
|
||||
* @return the actually read size on successful, otherwise negative returned.
|
||||
*
|
||||
* @note since 0.4.0, the unit of size/pos is a block for block device.
|
||||
*/
|
||||
rt_size_t rt_device_read(rt_device_t dev,
|
||||
rt_off_t pos,
|
||||
void *buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device);
|
||||
|
||||
if (dev->ref_count == 0)
|
||||
{
|
||||
rt_set_errno(-RT_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* call device read interface */
|
||||
if (device_read != RT_NULL)
|
||||
{
|
||||
return device_read(dev, pos, buffer, size);
|
||||
}
|
||||
|
||||
/* set error code */
|
||||
rt_set_errno(-RT_ENOSYS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
RTM_EXPORT(rt_device_read);
|
||||
|
||||
/**
|
||||
* This function will write some data to a device.
|
||||
*
|
||||
* @param dev the pointer of device driver structure
|
||||
* @param pos the position of written
|
||||
* @param buffer the data buffer to be written to device
|
||||
* @param size the size of buffer
|
||||
*
|
||||
* @return the actually written size on successful, otherwise negative returned.
|
||||
*
|
||||
* @note since 0.4.0, the unit of size/pos is a block for block device.
|
||||
*/
|
||||
rt_size_t rt_device_write(rt_device_t dev,
|
||||
rt_off_t pos,
|
||||
const void *buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device);
|
||||
|
||||
if (dev->ref_count == 0)
|
||||
{
|
||||
rt_set_errno(-RT_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* call device write interface */
|
||||
if (device_write != RT_NULL)
|
||||
{
|
||||
return device_write(dev, pos, buffer, size);
|
||||
}
|
||||
|
||||
/* set error code */
|
||||
rt_set_errno(-RT_ENOSYS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
RTM_EXPORT(rt_device_write);
|
||||
|
||||
/**
|
||||
* This function will perform a variety of control functions on devices.
|
||||
*
|
||||
* @param dev the pointer of device driver structure
|
||||
* @param cmd the command sent to device
|
||||
* @param arg the argument of command
|
||||
*
|
||||
* @return the result
|
||||
*/
|
||||
rt_err_t rt_device_control(rt_device_t dev, int cmd, void *arg)
|
||||
{
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device);
|
||||
|
||||
/* call device write interface */
|
||||
if (device_control != RT_NULL)
|
||||
{
|
||||
return device_control(dev, cmd, arg);
|
||||
}
|
||||
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
RTM_EXPORT(rt_device_control);
|
||||
|
||||
/**
|
||||
* This function will set the reception indication callback function. This callback function
|
||||
* is invoked when this device receives data.
|
||||
*
|
||||
* @param dev the pointer of device driver structure
|
||||
* @param rx_ind the indication callback function
|
||||
*
|
||||
* @return RT_EOK
|
||||
*/
|
||||
rt_err_t
|
||||
rt_device_set_rx_indicate(rt_device_t dev,
|
||||
rt_err_t (*rx_ind)(rt_device_t dev, rt_size_t size))
|
||||
{
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device);
|
||||
|
||||
dev->rx_indicate = rx_ind;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
RTM_EXPORT(rt_device_set_rx_indicate);
|
||||
|
||||
/**
|
||||
* This function will set the indication callback function when device has
|
||||
* written data to physical hardware.
|
||||
*
|
||||
* @param dev the pointer of device driver structure
|
||||
* @param tx_done the indication callback function
|
||||
*
|
||||
* @return RT_EOK
|
||||
*/
|
||||
rt_err_t
|
||||
rt_device_set_tx_complete(rt_device_t dev,
|
||||
rt_err_t (*tx_done)(rt_device_t dev, void *buffer))
|
||||
{
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device);
|
||||
|
||||
dev->tx_complete = tx_done;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
RTM_EXPORT(rt_device_set_tx_complete);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2006-03-23 Bernard the first version
|
||||
* 2010-11-10 Bernard add cleanup callback function in thread exit.
|
||||
* 2012-12-29 Bernard fix compiling warning.
|
||||
* 2013-12-21 Grissiom let rt_thread_idle_excute loop until there is no
|
||||
* dead thread.
|
||||
* 2016-08-09 ArdaFu add method to get the handler of the idle thread.
|
||||
* 2018-02-07 Bernard lock scheduler to protect tid->cleanup.
|
||||
* 2018-07-14 armink add idle hook list
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
#ifdef RT_USING_MODULE
|
||||
#include <dlmodule.h>
|
||||
#endif
|
||||
|
||||
#if defined (RT_USING_HOOK)
|
||||
#ifndef RT_USING_IDLE_HOOK
|
||||
#define RT_USING_IDLE_HOOK
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef IDLE_THREAD_STACK_SIZE
|
||||
#if defined (RT_USING_IDLE_HOOK) || defined(RT_USING_HEAP)
|
||||
#define IDLE_THREAD_STACK_SIZE 512
|
||||
#else
|
||||
#define IDLE_THREAD_STACK_SIZE 256
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static struct rt_thread idle;
|
||||
ALIGN(RT_ALIGN_SIZE)
|
||||
static rt_uint8_t rt_thread_stack[IDLE_THREAD_STACK_SIZE];
|
||||
|
||||
extern rt_list_t rt_thread_defunct;
|
||||
|
||||
#ifdef RT_USING_IDLE_HOOK
|
||||
|
||||
#ifndef RT_IDEL_HOOK_LIST_SIZE
|
||||
#define RT_IDEL_HOOK_LIST_SIZE 4
|
||||
#endif
|
||||
|
||||
static void (*idle_hook_list[RT_IDEL_HOOK_LIST_SIZE])();
|
||||
|
||||
/**
|
||||
* @ingroup Hook
|
||||
* This function sets a hook function to idle thread loop. When the system performs
|
||||
* idle loop, this hook function should be invoked.
|
||||
*
|
||||
* @param hook the specified hook function
|
||||
*
|
||||
* @return RT_EOK: set OK
|
||||
* -RT_EFULL: hook list is full
|
||||
*
|
||||
* @note the hook function must be simple and never be blocked or suspend.
|
||||
*/
|
||||
rt_err_t rt_thread_idle_sethook(void (*hook)(void))
|
||||
{
|
||||
rt_size_t i;
|
||||
rt_base_t level;
|
||||
rt_err_t ret = -RT_EFULL;
|
||||
|
||||
/* disable interrupt */
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
for (i = 0; i < RT_IDEL_HOOK_LIST_SIZE; i++)
|
||||
{
|
||||
if (idle_hook_list[i] == RT_NULL)
|
||||
{
|
||||
idle_hook_list[i] = hook;
|
||||
ret = RT_EOK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* delete the idle hook on hook list
|
||||
*
|
||||
* @param hook the specified hook function
|
||||
*
|
||||
* @return RT_EOK: delete OK
|
||||
* -RT_ENOSYS: hook was not found
|
||||
*/
|
||||
rt_err_t rt_thread_idle_delhook(void (*hook)(void))
|
||||
{
|
||||
rt_size_t i;
|
||||
rt_base_t level;
|
||||
rt_err_t ret = -RT_ENOSYS;
|
||||
|
||||
/* disable interrupt */
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
for (i = 0; i < RT_IDEL_HOOK_LIST_SIZE; i++)
|
||||
{
|
||||
if (idle_hook_list[i] == hook)
|
||||
{
|
||||
idle_hook_list[i] = RT_NULL;
|
||||
ret = RT_EOK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Return whether there is defunctional thread to be deleted. */
|
||||
rt_inline int _has_defunct_thread(void)
|
||||
{
|
||||
/* The rt_list_isempty has prototype of "int rt_list_isempty(const rt_list_t *l)".
|
||||
* So the compiler has a good reason that the rt_thread_defunct list does
|
||||
* not change within rt_thread_idle_excute thus optimize the "while" loop
|
||||
* into a "if".
|
||||
*
|
||||
* So add the volatile qualifier here. */
|
||||
const volatile rt_list_t *l = (const volatile rt_list_t *)&rt_thread_defunct;
|
||||
|
||||
return l->next != l;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup Thread
|
||||
*
|
||||
* This function will perform system background job when system idle.
|
||||
*/
|
||||
void rt_thread_idle_excute(void)
|
||||
{
|
||||
/* Loop until there is no dead thread. So one call to rt_thread_idle_excute
|
||||
* will do all the cleanups. */
|
||||
while (_has_defunct_thread())
|
||||
{
|
||||
rt_base_t lock;
|
||||
rt_thread_t thread;
|
||||
#ifdef RT_USING_MODULE
|
||||
struct rt_dlmodule *module = RT_NULL;
|
||||
#endif
|
||||
RT_DEBUG_NOT_IN_INTERRUPT;
|
||||
|
||||
/* disable interrupt */
|
||||
lock = rt_hw_interrupt_disable();
|
||||
|
||||
/* re-check whether list is empty */
|
||||
if (_has_defunct_thread())
|
||||
{
|
||||
/* get defunct thread */
|
||||
thread = rt_list_entry(rt_thread_defunct.next,
|
||||
struct rt_thread,
|
||||
tlist);
|
||||
#ifdef RT_USING_MODULE
|
||||
module = (struct rt_dlmodule*)thread->module_id;
|
||||
if (module)
|
||||
{
|
||||
dlmodule_destroy(module);
|
||||
}
|
||||
#endif
|
||||
/* remove defunct thread */
|
||||
rt_list_remove(&(thread->tlist));
|
||||
|
||||
/* lock scheduler to prevent scheduling in cleanup function. */
|
||||
rt_enter_critical();
|
||||
|
||||
/* invoke thread cleanup */
|
||||
if (thread->cleanup != RT_NULL)
|
||||
thread->cleanup(thread);
|
||||
|
||||
#ifdef RT_USING_SIGNALS
|
||||
rt_thread_free_sig(thread);
|
||||
#endif
|
||||
|
||||
/* if it's a system object, not delete it */
|
||||
if (rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE)
|
||||
{
|
||||
/* detach this object */
|
||||
rt_object_detach((rt_object_t)thread);
|
||||
/* unlock scheduler */
|
||||
rt_exit_critical();
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(lock);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* unlock scheduler */
|
||||
rt_exit_critical();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(lock);
|
||||
|
||||
/* may the defunct thread list is removed by others, just return */
|
||||
return;
|
||||
}
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(lock);
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
/* release thread's stack */
|
||||
RT_KERNEL_FREE(thread->stack_addr);
|
||||
/* delete thread object */
|
||||
rt_object_delete((rt_object_t)thread);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
extern void rt_system_power_manager(void);
|
||||
static void rt_thread_idle_entry(void *parameter)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
// printf("idle\n");
|
||||
#ifdef RT_USING_IDLE_HOOK
|
||||
rt_size_t i;
|
||||
|
||||
for (i = 0; i < RT_IDEL_HOOK_LIST_SIZE; i++)
|
||||
{
|
||||
if (idle_hook_list[i] != RT_NULL)
|
||||
{
|
||||
idle_hook_list[i]();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
rt_thread_idle_excute();
|
||||
#ifdef RT_USING_PM
|
||||
rt_system_power_manager();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup SystemInit
|
||||
*
|
||||
* This function will initialize idle thread, then start it.
|
||||
*
|
||||
* @note this function must be invoked when system init.
|
||||
*/
|
||||
void rt_thread_idle_init(void)
|
||||
{
|
||||
/* initialize thread */
|
||||
rt_thread_init(&idle,
|
||||
"tidle",
|
||||
rt_thread_idle_entry,
|
||||
RT_NULL,
|
||||
&rt_thread_stack[0],
|
||||
sizeof(rt_thread_stack),
|
||||
RT_THREAD_PRIORITY_MAX - 1,
|
||||
32);
|
||||
|
||||
/* startup */
|
||||
rt_thread_startup(&idle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup Thread
|
||||
*
|
||||
* This function will get the handler of the idle thread.
|
||||
*
|
||||
*/
|
||||
rt_thread_t rt_thread_idle_gethandler(void)
|
||||
{
|
||||
return (rt_thread_t)(&idle);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2006-02-24 Bernard first version
|
||||
* 2006-05-03 Bernard add IRQ_DEBUG
|
||||
* 2016-08-09 ArdaFu add interrupt enter and leave hook.
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
#ifdef RT_USING_HOOK
|
||||
|
||||
static void (*rt_interrupt_enter_hook)(void);
|
||||
static void (*rt_interrupt_leave_hook)(void);
|
||||
|
||||
/**
|
||||
* @ingroup Hook
|
||||
* This function set a hook function when the system enter a interrupt
|
||||
*
|
||||
* @note the hook function must be simple and never be blocked or suspend.
|
||||
*/
|
||||
void rt_interrupt_enter_sethook(void (*hook)(void))
|
||||
{
|
||||
rt_interrupt_enter_hook = hook;
|
||||
}
|
||||
/**
|
||||
* @ingroup Hook
|
||||
* This function set a hook function when the system exit a interrupt.
|
||||
*
|
||||
* @note the hook function must be simple and never be blocked or suspend.
|
||||
*/
|
||||
void rt_interrupt_leave_sethook(void (*hook)(void))
|
||||
{
|
||||
rt_interrupt_leave_hook = hook;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* #define IRQ_DEBUG */
|
||||
|
||||
/**
|
||||
* @addtogroup Kernel
|
||||
*/
|
||||
|
||||
/**@{*/
|
||||
|
||||
volatile rt_uint8_t rt_interrupt_nest;
|
||||
|
||||
/**
|
||||
* This function will be invoked by BSP, when enter interrupt service routine
|
||||
*
|
||||
* @note please don't invoke this routine in application
|
||||
*
|
||||
* @see rt_interrupt_leave
|
||||
*/
|
||||
void rt_interrupt_enter(void)
|
||||
{
|
||||
rt_base_t level;
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_IRQ, ("irq coming..., irq nest:%d\n",
|
||||
rt_interrupt_nest));
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
rt_interrupt_nest ++;
|
||||
RT_OBJECT_HOOK_CALL(rt_interrupt_enter_hook,());
|
||||
rt_hw_interrupt_enable(level);
|
||||
}
|
||||
RTM_EXPORT(rt_interrupt_enter);
|
||||
|
||||
/**
|
||||
* This function will be invoked by BSP, when leave interrupt service routine
|
||||
*
|
||||
* @note please don't invoke this routine in application
|
||||
*
|
||||
* @see rt_interrupt_enter
|
||||
*/
|
||||
void rt_interrupt_leave(void)
|
||||
{
|
||||
rt_base_t level;
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_IRQ, ("irq leave, irq nest:%d\n",
|
||||
rt_interrupt_nest));
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
rt_interrupt_nest --;
|
||||
RT_OBJECT_HOOK_CALL(rt_interrupt_leave_hook,());
|
||||
rt_hw_interrupt_enable(level);
|
||||
}
|
||||
RTM_EXPORT(rt_interrupt_leave);
|
||||
|
||||
/**
|
||||
* This function will return the nest of interrupt.
|
||||
*
|
||||
* User application can invoke this function to get whether current
|
||||
* context is interrupt context.
|
||||
*
|
||||
* @return the number of nested interrupts.
|
||||
*/
|
||||
rt_uint8_t rt_interrupt_get_nest(void)
|
||||
{
|
||||
return rt_interrupt_nest;
|
||||
}
|
||||
RTM_EXPORT(rt_interrupt_get_nest);
|
||||
|
||||
RTM_EXPORT(rt_hw_interrupt_disable);
|
||||
RTM_EXPORT(rt_hw_interrupt_enable);
|
||||
|
||||
/**@}*/
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,698 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2008-7-12 Bernard the first version
|
||||
* 2010-06-09 Bernard fix the end stub of heap
|
||||
* fix memory check in rt_realloc function
|
||||
* 2010-07-13 Bernard fix RT_ALIGN issue found by kuronca
|
||||
* 2010-10-14 Bernard fix rt_realloc issue when realloc a NULL pointer.
|
||||
* 2017-07-14 armink fix rt_realloc issue when new size is 0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
* Simon Goldschmidt
|
||||
*
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
#ifndef RT_USING_MEMHEAP_AS_HEAP
|
||||
|
||||
/* #define RT_MEM_DEBUG */
|
||||
#define RT_MEM_STATS
|
||||
|
||||
#if defined (RT_USING_HEAP) && defined (RT_USING_SMALL_MEM)
|
||||
#ifdef RT_USING_HOOK
|
||||
static void (*rt_malloc_hook)(void *ptr, rt_size_t size);
|
||||
static void (*rt_free_hook)(void *ptr);
|
||||
|
||||
/**
|
||||
* @addtogroup Hook
|
||||
*/
|
||||
|
||||
/**@{*/
|
||||
|
||||
/**
|
||||
* This function will set a hook function, which will be invoked when a memory
|
||||
* block is allocated from heap memory.
|
||||
*
|
||||
* @param hook the hook function
|
||||
*/
|
||||
void rt_malloc_sethook(void (*hook)(void *ptr, rt_size_t size))
|
||||
{
|
||||
rt_malloc_hook = hook;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will set a hook function, which will be invoked when a memory
|
||||
* block is released to heap memory.
|
||||
*
|
||||
* @param hook the hook function
|
||||
*/
|
||||
void rt_free_sethook(void (*hook)(void *ptr))
|
||||
{
|
||||
rt_free_hook = hook;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
||||
#endif
|
||||
|
||||
#define HEAP_MAGIC 0x1ea0
|
||||
struct heap_mem
|
||||
{
|
||||
/* magic and used flag */
|
||||
rt_uint16_t magic;
|
||||
rt_uint16_t used;
|
||||
|
||||
rt_size_t next, prev;
|
||||
|
||||
#ifdef RT_USING_MEMTRACE
|
||||
rt_uint8_t thread[4]; /* thread name */
|
||||
#endif
|
||||
};
|
||||
|
||||
/** pointer to the heap: for alignment, heap_ptr is now a pointer instead of an array */
|
||||
static rt_uint8_t *heap_ptr;
|
||||
|
||||
/** the last entry, always unused! */
|
||||
static struct heap_mem *heap_end;
|
||||
|
||||
#define MIN_SIZE 12
|
||||
#define MIN_SIZE_ALIGNED RT_ALIGN(MIN_SIZE, RT_ALIGN_SIZE)
|
||||
#define SIZEOF_STRUCT_MEM RT_ALIGN(sizeof(struct heap_mem), RT_ALIGN_SIZE)
|
||||
|
||||
static struct heap_mem *lfree; /* pointer to the lowest free block */
|
||||
|
||||
static struct rt_semaphore heap_sem;
|
||||
static rt_size_t mem_size_aligned;
|
||||
|
||||
#ifdef RT_MEM_STATS
|
||||
static rt_size_t used_mem, max_mem;
|
||||
#endif
|
||||
#ifdef RT_USING_MEMTRACE
|
||||
rt_inline void rt_mem_setname(struct heap_mem *mem, const char *name)
|
||||
{
|
||||
int index;
|
||||
for (index = 0; index < sizeof(mem->thread); index ++)
|
||||
{
|
||||
if (name[index] == '\0') break;
|
||||
mem->thread[index] = name[index];
|
||||
}
|
||||
|
||||
for (; index < sizeof(mem->thread); index ++)
|
||||
{
|
||||
mem->thread[index] = ' ';
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void plug_holes(struct heap_mem *mem)
|
||||
{
|
||||
struct heap_mem *nmem;
|
||||
struct heap_mem *pmem;
|
||||
|
||||
RT_ASSERT((rt_uint8_t *)mem >= heap_ptr);
|
||||
RT_ASSERT((rt_uint8_t *)mem < (rt_uint8_t *)heap_end);
|
||||
RT_ASSERT(mem->used == 0);
|
||||
|
||||
/* plug hole forward */
|
||||
nmem = (struct heap_mem *)&heap_ptr[mem->next];
|
||||
if (mem != nmem &&
|
||||
nmem->used == 0 &&
|
||||
(rt_uint8_t *)nmem != (rt_uint8_t *)heap_end)
|
||||
{
|
||||
/* if mem->next is unused and not end of heap_ptr,
|
||||
* combine mem and mem->next
|
||||
*/
|
||||
if (lfree == nmem)
|
||||
{
|
||||
lfree = mem;
|
||||
}
|
||||
mem->next = nmem->next;
|
||||
((struct heap_mem *)&heap_ptr[nmem->next])->prev = (rt_uint8_t *)mem - heap_ptr;
|
||||
}
|
||||
|
||||
/* plug hole backward */
|
||||
pmem = (struct heap_mem *)&heap_ptr[mem->prev];
|
||||
if (pmem != mem && pmem->used == 0)
|
||||
{
|
||||
/* if mem->prev is unused, combine mem and mem->prev */
|
||||
if (lfree == mem)
|
||||
{
|
||||
lfree = pmem;
|
||||
}
|
||||
pmem->next = mem->next;
|
||||
((struct heap_mem *)&heap_ptr[mem->next])->prev = (rt_uint8_t *)pmem - heap_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup SystemInit
|
||||
*
|
||||
* This function will initialize system heap memory.
|
||||
*
|
||||
* @param begin_addr the beginning address of system heap memory.
|
||||
* @param end_addr the end address of system heap memory.
|
||||
*/
|
||||
void rt_system_heap_init(void *begin_addr, void *end_addr)
|
||||
{
|
||||
struct heap_mem *mem;
|
||||
rt_uint32_t begin_align = RT_ALIGN((rt_uint32_t)begin_addr, RT_ALIGN_SIZE);
|
||||
rt_uint32_t end_align = RT_ALIGN_DOWN((rt_uint32_t)end_addr, RT_ALIGN_SIZE);
|
||||
|
||||
RT_DEBUG_NOT_IN_INTERRUPT;
|
||||
|
||||
/* alignment addr */
|
||||
if ((end_align > (2 * SIZEOF_STRUCT_MEM)) &&
|
||||
((end_align - 2 * SIZEOF_STRUCT_MEM) >= begin_align))
|
||||
{
|
||||
/* calculate the aligned memory size */
|
||||
mem_size_aligned = end_align - begin_align - 2 * SIZEOF_STRUCT_MEM;
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("mem init, error begin address 0x%x, and end address 0x%x\n",
|
||||
(rt_uint32_t)begin_addr, (rt_uint32_t)end_addr);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* point to begin address of heap */
|
||||
heap_ptr = (rt_uint8_t *)begin_align;
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_MEM, ("mem init, heap begin address 0x%x, size %d\n",
|
||||
(rt_uint32_t)heap_ptr, mem_size_aligned));
|
||||
|
||||
/* initialize the start of the heap */
|
||||
mem = (struct heap_mem *)heap_ptr;
|
||||
mem->magic = HEAP_MAGIC;
|
||||
mem->next = mem_size_aligned + SIZEOF_STRUCT_MEM;
|
||||
mem->prev = 0;
|
||||
mem->used = 0;
|
||||
#ifdef RT_USING_MEMTRACE
|
||||
rt_mem_setname(mem, "INIT");
|
||||
#endif
|
||||
|
||||
/* initialize the end of the heap */
|
||||
heap_end = (struct heap_mem *)&heap_ptr[mem->next];
|
||||
heap_end->magic = HEAP_MAGIC;
|
||||
heap_end->used = 1;
|
||||
heap_end->next = mem_size_aligned + SIZEOF_STRUCT_MEM;
|
||||
heap_end->prev = mem_size_aligned + SIZEOF_STRUCT_MEM;
|
||||
#ifdef RT_USING_MEMTRACE
|
||||
rt_mem_setname(heap_end, "INIT");
|
||||
#endif
|
||||
|
||||
rt_sem_init(&heap_sem, "heap", 1, RT_IPC_FLAG_FIFO);
|
||||
|
||||
/* initialize the lowest-free pointer to the start of the heap */
|
||||
lfree = (struct heap_mem *)heap_ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @addtogroup MM
|
||||
*/
|
||||
|
||||
/**@{*/
|
||||
|
||||
/**
|
||||
* Allocate a block of memory with a minimum of 'size' bytes.
|
||||
*
|
||||
* @param size is the minimum size of the requested block in bytes.
|
||||
*
|
||||
* @return pointer to allocated memory or NULL if no free memory was found.
|
||||
*/
|
||||
void *rt_malloc(rt_size_t size)
|
||||
{
|
||||
rt_size_t ptr, ptr2;
|
||||
struct heap_mem *mem, *mem2;
|
||||
|
||||
if (size == 0)
|
||||
return RT_NULL;
|
||||
|
||||
RT_DEBUG_NOT_IN_INTERRUPT;
|
||||
|
||||
if (size != RT_ALIGN(size, RT_ALIGN_SIZE))
|
||||
RT_DEBUG_LOG(RT_DEBUG_MEM, ("malloc size %d, but align to %d\n",
|
||||
size, RT_ALIGN(size, RT_ALIGN_SIZE)));
|
||||
else
|
||||
RT_DEBUG_LOG(RT_DEBUG_MEM, ("malloc size %d\n", size));
|
||||
|
||||
/* alignment size */
|
||||
size = RT_ALIGN(size, RT_ALIGN_SIZE);
|
||||
|
||||
if (size > mem_size_aligned)
|
||||
{
|
||||
RT_DEBUG_LOG(RT_DEBUG_MEM, ("no memory\n"));
|
||||
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
/* every data block must be at least MIN_SIZE_ALIGNED long */
|
||||
if (size < MIN_SIZE_ALIGNED)
|
||||
size = MIN_SIZE_ALIGNED;
|
||||
|
||||
/* take memory semaphore */
|
||||
rt_sem_take(&heap_sem, RT_WAITING_FOREVER);
|
||||
|
||||
for (ptr = (rt_uint8_t *)lfree - heap_ptr;
|
||||
ptr < mem_size_aligned - size;
|
||||
ptr = ((struct heap_mem *)&heap_ptr[ptr])->next)
|
||||
{
|
||||
mem = (struct heap_mem *)&heap_ptr[ptr];
|
||||
|
||||
if ((!mem->used) && (mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size)
|
||||
{
|
||||
/* mem is not used and at least perfect fit is possible:
|
||||
* mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */
|
||||
|
||||
if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >=
|
||||
(size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED))
|
||||
{
|
||||
/* (in addition to the above, we test if another struct heap_mem (SIZEOF_STRUCT_MEM) containing
|
||||
* at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem')
|
||||
* -> split large block, create empty remainder,
|
||||
* remainder must be large enough to contain MIN_SIZE_ALIGNED data: if
|
||||
* mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size,
|
||||
* struct heap_mem would fit in but no data between mem2 and mem2->next
|
||||
* @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty
|
||||
* region that couldn't hold data, but when mem->next gets freed,
|
||||
* the 2 regions would be combined, resulting in more free memory
|
||||
*/
|
||||
ptr2 = ptr + SIZEOF_STRUCT_MEM + size;
|
||||
|
||||
/* create mem2 struct */
|
||||
mem2 = (struct heap_mem *)&heap_ptr[ptr2];
|
||||
mem2->magic = HEAP_MAGIC;
|
||||
mem2->used = 0;
|
||||
mem2->next = mem->next;
|
||||
mem2->prev = ptr;
|
||||
#ifdef RT_USING_MEMTRACE
|
||||
rt_mem_setname(mem2, " ");
|
||||
#endif
|
||||
|
||||
/* and insert it between mem and mem->next */
|
||||
mem->next = ptr2;
|
||||
mem->used = 1;
|
||||
|
||||
if (mem2->next != mem_size_aligned + SIZEOF_STRUCT_MEM)
|
||||
{
|
||||
((struct heap_mem *)&heap_ptr[mem2->next])->prev = ptr2;
|
||||
}
|
||||
#ifdef RT_MEM_STATS
|
||||
used_mem += (size + SIZEOF_STRUCT_MEM);
|
||||
if (max_mem < used_mem)
|
||||
max_mem = used_mem;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
/* (a mem2 struct does no fit into the user data space of mem and mem->next will always
|
||||
* be used at this point: if not we have 2 unused structs in a row, plug_holes should have
|
||||
* take care of this).
|
||||
* -> near fit or excact fit: do not split, no mem2 creation
|
||||
* also can't move mem->next directly behind mem, since mem->next
|
||||
* will always be used at this point!
|
||||
*/
|
||||
mem->used = 1;
|
||||
#ifdef RT_MEM_STATS
|
||||
used_mem += mem->next - ((rt_uint8_t *)mem - heap_ptr);
|
||||
if (max_mem < used_mem)
|
||||
max_mem = used_mem;
|
||||
#endif
|
||||
}
|
||||
/* set memory block magic */
|
||||
mem->magic = HEAP_MAGIC;
|
||||
#ifdef RT_USING_MEMTRACE
|
||||
if (rt_thread_self())
|
||||
rt_mem_setname(mem, rt_thread_self()->name);
|
||||
else
|
||||
rt_mem_setname(mem, "NONE");
|
||||
#endif
|
||||
|
||||
if (mem == lfree)
|
||||
{
|
||||
/* Find next free block after mem and update lowest free pointer */
|
||||
while (lfree->used && lfree != heap_end)
|
||||
lfree = (struct heap_mem *)&heap_ptr[lfree->next];
|
||||
|
||||
RT_ASSERT(((lfree == heap_end) || (!lfree->used)));
|
||||
}
|
||||
|
||||
rt_sem_release(&heap_sem);
|
||||
RT_ASSERT((rt_uint32_t)mem + SIZEOF_STRUCT_MEM + size <= (rt_uint32_t)heap_end);
|
||||
RT_ASSERT((rt_uint32_t)((rt_uint8_t *)mem + SIZEOF_STRUCT_MEM) % RT_ALIGN_SIZE == 0);
|
||||
RT_ASSERT((((rt_uint32_t)mem) & (RT_ALIGN_SIZE - 1)) == 0);
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_MEM,
|
||||
("allocate memory at 0x%x, size: %d\n",
|
||||
(rt_uint32_t)((rt_uint8_t *)mem + SIZEOF_STRUCT_MEM),
|
||||
(rt_uint32_t)(mem->next - ((rt_uint8_t *)mem - heap_ptr))));
|
||||
|
||||
RT_OBJECT_HOOK_CALL(rt_malloc_hook,
|
||||
(((void *)((rt_uint8_t *)mem + SIZEOF_STRUCT_MEM)), size));
|
||||
|
||||
/* return the memory data except mem struct */
|
||||
return (rt_uint8_t *)mem + SIZEOF_STRUCT_MEM;
|
||||
}
|
||||
}
|
||||
|
||||
rt_sem_release(&heap_sem);
|
||||
|
||||
return RT_NULL;
|
||||
}
|
||||
RTM_EXPORT(rt_malloc);
|
||||
|
||||
/**
|
||||
* This function will change the previously allocated memory block.
|
||||
*
|
||||
* @param rmem pointer to memory allocated by rt_malloc
|
||||
* @param newsize the required new size
|
||||
*
|
||||
* @return the changed memory block address
|
||||
*/
|
||||
void *rt_realloc(void *rmem, rt_size_t newsize)
|
||||
{
|
||||
rt_size_t size;
|
||||
rt_size_t ptr, ptr2;
|
||||
struct heap_mem *mem, *mem2;
|
||||
void *nmem;
|
||||
|
||||
RT_DEBUG_NOT_IN_INTERRUPT;
|
||||
|
||||
/* alignment size */
|
||||
newsize = RT_ALIGN(newsize, RT_ALIGN_SIZE);
|
||||
if (newsize > mem_size_aligned)
|
||||
{
|
||||
RT_DEBUG_LOG(RT_DEBUG_MEM, ("realloc: out of memory\n"));
|
||||
|
||||
return RT_NULL;
|
||||
}
|
||||
else if (newsize == 0)
|
||||
{
|
||||
rt_free(rmem);
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
/* allocate a new memory block */
|
||||
if (rmem == RT_NULL)
|
||||
return rt_malloc(newsize);
|
||||
|
||||
rt_sem_take(&heap_sem, RT_WAITING_FOREVER);
|
||||
|
||||
if ((rt_uint8_t *)rmem < (rt_uint8_t *)heap_ptr ||
|
||||
(rt_uint8_t *)rmem >= (rt_uint8_t *)heap_end)
|
||||
{
|
||||
/* illegal memory */
|
||||
rt_sem_release(&heap_sem);
|
||||
|
||||
return rmem;
|
||||
}
|
||||
|
||||
mem = (struct heap_mem *)((rt_uint8_t *)rmem - SIZEOF_STRUCT_MEM);
|
||||
|
||||
ptr = (rt_uint8_t *)mem - heap_ptr;
|
||||
size = mem->next - ptr - SIZEOF_STRUCT_MEM;
|
||||
if (size == newsize)
|
||||
{
|
||||
/* the size is the same as */
|
||||
rt_sem_release(&heap_sem);
|
||||
|
||||
return rmem;
|
||||
}
|
||||
|
||||
if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE < size)
|
||||
{
|
||||
/* split memory block */
|
||||
#ifdef RT_MEM_STATS
|
||||
used_mem -= (size - newsize);
|
||||
#endif
|
||||
|
||||
ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;
|
||||
mem2 = (struct heap_mem *)&heap_ptr[ptr2];
|
||||
mem2->magic = HEAP_MAGIC;
|
||||
mem2->used = 0;
|
||||
mem2->next = mem->next;
|
||||
mem2->prev = ptr;
|
||||
#ifdef RT_USING_MEMTRACE
|
||||
rt_mem_setname(mem2, " ");
|
||||
#endif
|
||||
mem->next = ptr2;
|
||||
if (mem2->next != mem_size_aligned + SIZEOF_STRUCT_MEM)
|
||||
{
|
||||
((struct heap_mem *)&heap_ptr[mem2->next])->prev = ptr2;
|
||||
}
|
||||
|
||||
plug_holes(mem2);
|
||||
|
||||
rt_sem_release(&heap_sem);
|
||||
|
||||
return rmem;
|
||||
}
|
||||
rt_sem_release(&heap_sem);
|
||||
|
||||
/* expand memory */
|
||||
nmem = rt_malloc(newsize);
|
||||
if (nmem != RT_NULL) /* check memory */
|
||||
{
|
||||
rt_memcpy(nmem, rmem, size < newsize ? size : newsize);
|
||||
rt_free(rmem);
|
||||
}
|
||||
|
||||
return nmem;
|
||||
}
|
||||
RTM_EXPORT(rt_realloc);
|
||||
|
||||
/**
|
||||
* This function will contiguously allocate enough space for count objects
|
||||
* that are size bytes of memory each and returns a pointer to the allocated
|
||||
* memory.
|
||||
*
|
||||
* The allocated memory is filled with bytes of value zero.
|
||||
*
|
||||
* @param count number of objects to allocate
|
||||
* @param size size of the objects to allocate
|
||||
*
|
||||
* @return pointer to allocated memory / NULL pointer if there is an error
|
||||
*/
|
||||
void *rt_calloc(rt_size_t count, rt_size_t size)
|
||||
{
|
||||
void *p;
|
||||
|
||||
/* allocate 'count' objects of size 'size' */
|
||||
p = rt_malloc(count * size);
|
||||
|
||||
/* zero the memory */
|
||||
if (p)
|
||||
rt_memset(p, 0, count * size);
|
||||
|
||||
return p;
|
||||
}
|
||||
RTM_EXPORT(rt_calloc);
|
||||
|
||||
/**
|
||||
* This function will release the previously allocated memory block by
|
||||
* rt_malloc. The released memory block is taken back to system heap.
|
||||
*
|
||||
* @param rmem the address of memory which will be released
|
||||
*/
|
||||
void rt_free(void *rmem)
|
||||
{
|
||||
struct heap_mem *mem;
|
||||
|
||||
if (rmem == RT_NULL)
|
||||
return;
|
||||
|
||||
RT_DEBUG_NOT_IN_INTERRUPT;
|
||||
|
||||
RT_ASSERT((((rt_uint32_t)rmem) & (RT_ALIGN_SIZE - 1)) == 0);
|
||||
RT_ASSERT((rt_uint8_t *)rmem >= (rt_uint8_t *)heap_ptr &&
|
||||
(rt_uint8_t *)rmem < (rt_uint8_t *)heap_end);
|
||||
|
||||
RT_OBJECT_HOOK_CALL(rt_free_hook, (rmem));
|
||||
|
||||
if ((rt_uint8_t *)rmem < (rt_uint8_t *)heap_ptr ||
|
||||
(rt_uint8_t *)rmem >= (rt_uint8_t *)heap_end)
|
||||
{
|
||||
RT_DEBUG_LOG(RT_DEBUG_MEM, ("illegal memory\n"));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the corresponding struct heap_mem ... */
|
||||
mem = (struct heap_mem *)((rt_uint8_t *)rmem - SIZEOF_STRUCT_MEM);
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_MEM,
|
||||
("release memory 0x%x, size: %d\n",
|
||||
(rt_uint32_t)rmem,
|
||||
(rt_uint32_t)(mem->next - ((rt_uint8_t *)mem - heap_ptr))));
|
||||
|
||||
|
||||
/* protect the heap from concurrent access */
|
||||
rt_sem_take(&heap_sem, RT_WAITING_FOREVER);
|
||||
|
||||
/* ... which has to be in a used state ... */
|
||||
if (!mem->used || mem->magic != HEAP_MAGIC)
|
||||
{
|
||||
rt_kprintf("to free a bad data block:\n");
|
||||
rt_kprintf("mem: 0x%08x, used flag: %d, magic code: 0x%04x\n", mem, mem->used, mem->magic);
|
||||
}
|
||||
RT_ASSERT(mem->used);
|
||||
RT_ASSERT(mem->magic == HEAP_MAGIC);
|
||||
/* ... and is now unused. */
|
||||
mem->used = 0;
|
||||
mem->magic = HEAP_MAGIC;
|
||||
#ifdef RT_USING_MEMTRACE
|
||||
rt_mem_setname(mem, " ");
|
||||
#endif
|
||||
|
||||
if (mem < lfree)
|
||||
{
|
||||
/* the newly freed struct is now the lowest */
|
||||
lfree = mem;
|
||||
}
|
||||
|
||||
#ifdef RT_MEM_STATS
|
||||
used_mem -= (mem->next - ((rt_uint8_t *)mem - heap_ptr));
|
||||
#endif
|
||||
|
||||
/* finally, see if prev or next are free also */
|
||||
plug_holes(mem);
|
||||
rt_sem_release(&heap_sem);
|
||||
}
|
||||
RTM_EXPORT(rt_free);
|
||||
|
||||
#ifdef RT_MEM_STATS
|
||||
void rt_memory_info(rt_uint32_t *total,
|
||||
rt_uint32_t *used,
|
||||
rt_uint32_t *max_used)
|
||||
{
|
||||
if (total != RT_NULL)
|
||||
*total = mem_size_aligned;
|
||||
if (used != RT_NULL)
|
||||
*used = used_mem;
|
||||
if (max_used != RT_NULL)
|
||||
*max_used = max_mem;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_FINSH
|
||||
#include <finsh.h>
|
||||
|
||||
void list_mem(void)
|
||||
{
|
||||
rt_kprintf("total memory: %d\n", mem_size_aligned);
|
||||
rt_kprintf("used memory : %d\n", used_mem);
|
||||
rt_kprintf("maximum allocated memory: %d\n", max_mem);
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT(list_mem, list memory usage information)
|
||||
|
||||
#ifdef RT_USING_MEMTRACE
|
||||
int memcheck(void)
|
||||
{
|
||||
int position;
|
||||
rt_uint32_t level;
|
||||
struct heap_mem *mem;
|
||||
level = rt_hw_interrupt_disable();
|
||||
for (mem = (struct heap_mem *)heap_ptr; mem != heap_end; mem = (struct heap_mem *)&heap_ptr[mem->next])
|
||||
{
|
||||
position = (rt_uint32_t)mem - (rt_uint32_t)heap_ptr;
|
||||
if (position < 0) goto __exit;
|
||||
if (position > mem_size_aligned) goto __exit;
|
||||
if (mem->magic != HEAP_MAGIC) goto __exit;
|
||||
if (mem->used != 0 && mem->used != 1) goto __exit;
|
||||
}
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
return 0;
|
||||
__exit:
|
||||
rt_kprintf("Memory block wrong:\n");
|
||||
rt_kprintf("address: 0x%08x\n", mem);
|
||||
rt_kprintf(" magic: 0x%04x\n", mem->magic);
|
||||
rt_kprintf(" used: %d\n", mem->used);
|
||||
rt_kprintf(" size: %d\n", mem->next - position - SIZEOF_STRUCT_MEM);
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
return 0;
|
||||
}
|
||||
MSH_CMD_EXPORT(memcheck, check memory data);
|
||||
|
||||
int memtrace(int argc, char **argv)
|
||||
{
|
||||
struct heap_mem *mem;
|
||||
|
||||
list_mem();
|
||||
|
||||
rt_kprintf("\nmemory heap address:\n");
|
||||
rt_kprintf("heap_ptr: 0x%08x\n", heap_ptr);
|
||||
rt_kprintf("lfree : 0x%08x\n", lfree);
|
||||
rt_kprintf("heap_end: 0x%08x\n", heap_end);
|
||||
|
||||
rt_kprintf("\n--memory item information --\n");
|
||||
for (mem = (struct heap_mem *)heap_ptr; mem != heap_end; mem = (struct heap_mem *)&heap_ptr[mem->next])
|
||||
{
|
||||
int position = (rt_uint32_t)mem - (rt_uint32_t)heap_ptr;
|
||||
int size;
|
||||
|
||||
rt_kprintf("[0x%08x - ", mem);
|
||||
|
||||
size = mem->next - position - SIZEOF_STRUCT_MEM;
|
||||
if (size < 1024)
|
||||
rt_kprintf("%5d", size);
|
||||
else if (size < 1024 * 1024)
|
||||
rt_kprintf("%4dK", size / 1024);
|
||||
else
|
||||
rt_kprintf("%4dM", size / (1024 * 1024));
|
||||
|
||||
rt_kprintf("] %c%c%c%c", mem->thread[0], mem->thread[1], mem->thread[2], mem->thread[3]);
|
||||
if (mem->magic != HEAP_MAGIC)
|
||||
rt_kprintf(": ***\n");
|
||||
else
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
MSH_CMD_EXPORT(memtrace, dump memory trace information);
|
||||
#endif /* end of RT_USING_MEMTRACE */
|
||||
#endif /* end of RT_USING_FINSH */
|
||||
|
||||
#endif
|
||||
|
||||
/**@}*/
|
||||
|
||||
#endif /* end of RT_USING_HEAP */
|
||||
#endif /* end of RT_USING_MEMHEAP_AS_HEAP */
|
||||
@@ -0,0 +1,717 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* File : memheap.c
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-04-10 Bernard first implementation
|
||||
* 2012-10-16 Bernard add the mutex lock for heap object.
|
||||
* 2012-12-29 Bernard memheap can be used as system heap.
|
||||
* change mutex lock to semaphore lock.
|
||||
* 2013-04-10 Bernard add rt_memheap_realloc function.
|
||||
* 2013-05-24 Bernard fix the rt_memheap_realloc issue.
|
||||
* 2013-07-11 Grissiom fix the memory block splitting issue.
|
||||
* 2013-07-15 Grissiom optimize rt_memheap_realloc
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
#ifdef RT_USING_MEMHEAP
|
||||
|
||||
/* dynamic pool magic and mask */
|
||||
#define RT_MEMHEAP_MAGIC 0x1ea01ea0
|
||||
#define RT_MEMHEAP_MASK 0xfffffffe
|
||||
#define RT_MEMHEAP_USED 0x01
|
||||
#define RT_MEMHEAP_FREED 0x00
|
||||
|
||||
#define RT_MEMHEAP_IS_USED(i) ((i)->magic & RT_MEMHEAP_USED)
|
||||
#define RT_MEMHEAP_MINIALLOC 12
|
||||
|
||||
#define RT_MEMHEAP_SIZE RT_ALIGN(sizeof(struct rt_memheap_item), RT_ALIGN_SIZE)
|
||||
#define MEMITEM_SIZE(item) ((rt_uint32_t)item->next - (rt_uint32_t)item - RT_MEMHEAP_SIZE)
|
||||
|
||||
/*
|
||||
* The initialized memory pool will be:
|
||||
* +-----------------------------------+--------------------------+
|
||||
* | whole freed memory block | Used Memory Block Tailer |
|
||||
* +-----------------------------------+--------------------------+
|
||||
*
|
||||
* block_list --> whole freed memory block
|
||||
*
|
||||
* The length of Used Memory Block Tailer is 0,
|
||||
* which is prevents block merging across list
|
||||
*/
|
||||
rt_err_t rt_memheap_init(struct rt_memheap *memheap,
|
||||
const char *name,
|
||||
void *start_addr,
|
||||
rt_size_t size)
|
||||
{
|
||||
struct rt_memheap_item *item;
|
||||
|
||||
RT_ASSERT(memheap != RT_NULL);
|
||||
|
||||
/* initialize pool object */
|
||||
rt_object_init(&(memheap->parent), RT_Object_Class_MemHeap, name);
|
||||
|
||||
memheap->start_addr = start_addr;
|
||||
memheap->pool_size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
|
||||
memheap->available_size = memheap->pool_size - (2 * RT_MEMHEAP_SIZE);
|
||||
memheap->max_used_size = memheap->pool_size - memheap->available_size;
|
||||
|
||||
/* initialize the free list header */
|
||||
item = &(memheap->free_header);
|
||||
item->magic = RT_MEMHEAP_MAGIC;
|
||||
item->pool_ptr = memheap;
|
||||
item->next = RT_NULL;
|
||||
item->prev = RT_NULL;
|
||||
item->next_free = item;
|
||||
item->prev_free = item;
|
||||
|
||||
/* set the free list to free list header */
|
||||
memheap->free_list = item;
|
||||
|
||||
/* initialize the first big memory block */
|
||||
item = (struct rt_memheap_item *)start_addr;
|
||||
item->magic = RT_MEMHEAP_MAGIC;
|
||||
item->pool_ptr = memheap;
|
||||
item->next = RT_NULL;
|
||||
item->prev = RT_NULL;
|
||||
item->next_free = item;
|
||||
item->prev_free = item;
|
||||
|
||||
item->next = (struct rt_memheap_item *)
|
||||
((rt_uint8_t *)item + memheap->available_size + RT_MEMHEAP_SIZE);
|
||||
item->prev = item->next;
|
||||
|
||||
/* block list header */
|
||||
memheap->block_list = item;
|
||||
|
||||
/* place the big memory block to free list */
|
||||
item->next_free = memheap->free_list->next_free;
|
||||
item->prev_free = memheap->free_list;
|
||||
memheap->free_list->next_free->prev_free = item;
|
||||
memheap->free_list->next_free = item;
|
||||
|
||||
/* move to the end of memory pool to build a small tailer block,
|
||||
* which prevents block merging
|
||||
*/
|
||||
item = item->next;
|
||||
/* it's a used memory block */
|
||||
item->magic = RT_MEMHEAP_MAGIC | RT_MEMHEAP_USED;
|
||||
item->pool_ptr = memheap;
|
||||
item->next = (struct rt_memheap_item *)start_addr;
|
||||
item->prev = (struct rt_memheap_item *)start_addr;
|
||||
/* not in free list */
|
||||
item->next_free = item->prev_free = RT_NULL;
|
||||
|
||||
/* initialize semaphore lock */
|
||||
rt_sem_init(&(memheap->lock), name, 1, RT_IPC_FLAG_FIFO);
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
|
||||
("memory heap: start addr 0x%08x, size %d, free list header 0x%08x\n",
|
||||
start_addr, size, &(memheap->free_header)));
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
RTM_EXPORT(rt_memheap_init);
|
||||
|
||||
rt_err_t rt_memheap_detach(struct rt_memheap *heap)
|
||||
{
|
||||
RT_ASSERT(heap);
|
||||
RT_ASSERT(rt_object_get_type(&heap->parent) == RT_Object_Class_MemHeap);
|
||||
RT_ASSERT(rt_object_is_systemobject(&heap->parent));
|
||||
|
||||
rt_object_detach(&(heap->lock.parent.parent));
|
||||
rt_object_detach(&(heap->parent));
|
||||
|
||||
/* Return a successful completion. */
|
||||
return RT_EOK;
|
||||
}
|
||||
RTM_EXPORT(rt_memheap_detach);
|
||||
|
||||
void *rt_memheap_alloc(struct rt_memheap *heap, rt_size_t size)
|
||||
{
|
||||
rt_err_t result;
|
||||
rt_uint32_t free_size;
|
||||
struct rt_memheap_item *header_ptr;
|
||||
|
||||
RT_ASSERT(heap != RT_NULL);
|
||||
RT_ASSERT(rt_object_get_type(&heap->parent) == RT_Object_Class_MemHeap);
|
||||
|
||||
/* align allocated size */
|
||||
size = RT_ALIGN(size, RT_ALIGN_SIZE);
|
||||
if (size < RT_MEMHEAP_MINIALLOC)
|
||||
size = RT_MEMHEAP_MINIALLOC;
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("allocate %d on heap:%8.*s",
|
||||
size, RT_NAME_MAX, heap->parent.name));
|
||||
|
||||
if (size < heap->available_size)
|
||||
{
|
||||
/* search on free list */
|
||||
free_size = 0;
|
||||
|
||||
/* lock memheap */
|
||||
result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
rt_set_errno(result);
|
||||
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
/* get the first free memory block */
|
||||
header_ptr = heap->free_list->next_free;
|
||||
while (header_ptr != heap->free_list && free_size < size)
|
||||
{
|
||||
/* get current freed memory block size */
|
||||
free_size = MEMITEM_SIZE(header_ptr);
|
||||
if (free_size < size)
|
||||
{
|
||||
/* move to next free memory block */
|
||||
header_ptr = header_ptr->next_free;
|
||||
}
|
||||
}
|
||||
|
||||
/* determine if the memory is available. */
|
||||
if (free_size >= size)
|
||||
{
|
||||
/* a block that satisfies the request has been found. */
|
||||
|
||||
/* determine if the block needs to be split. */
|
||||
if (free_size >= (size + RT_MEMHEAP_SIZE + RT_MEMHEAP_MINIALLOC))
|
||||
{
|
||||
struct rt_memheap_item *new_ptr;
|
||||
|
||||
/* split the block. */
|
||||
new_ptr = (struct rt_memheap_item *)
|
||||
(((rt_uint8_t *)header_ptr) + size + RT_MEMHEAP_SIZE);
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
|
||||
("split: block[0x%08x] nextm[0x%08x] prevm[0x%08x] to new[0x%08x]\n",
|
||||
header_ptr,
|
||||
header_ptr->next,
|
||||
header_ptr->prev,
|
||||
new_ptr));
|
||||
|
||||
/* mark the new block as a memory block and freed. */
|
||||
new_ptr->magic = RT_MEMHEAP_MAGIC;
|
||||
|
||||
/* put the pool pointer into the new block. */
|
||||
new_ptr->pool_ptr = heap;
|
||||
|
||||
/* break down the block list */
|
||||
new_ptr->prev = header_ptr;
|
||||
new_ptr->next = header_ptr->next;
|
||||
header_ptr->next->prev = new_ptr;
|
||||
header_ptr->next = new_ptr;
|
||||
|
||||
/* remove header ptr from free list */
|
||||
header_ptr->next_free->prev_free = header_ptr->prev_free;
|
||||
header_ptr->prev_free->next_free = header_ptr->next_free;
|
||||
header_ptr->next_free = RT_NULL;
|
||||
header_ptr->prev_free = RT_NULL;
|
||||
|
||||
/* insert new_ptr to free list */
|
||||
new_ptr->next_free = heap->free_list->next_free;
|
||||
new_ptr->prev_free = heap->free_list;
|
||||
heap->free_list->next_free->prev_free = new_ptr;
|
||||
heap->free_list->next_free = new_ptr;
|
||||
RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("new ptr: next_free 0x%08x, prev_free 0x%08x\n",
|
||||
new_ptr->next_free,
|
||||
new_ptr->prev_free));
|
||||
|
||||
/* decrement the available byte count. */
|
||||
heap->available_size = heap->available_size -
|
||||
size -
|
||||
RT_MEMHEAP_SIZE;
|
||||
if (heap->pool_size - heap->available_size > heap->max_used_size)
|
||||
heap->max_used_size = heap->pool_size - heap->available_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* decrement the entire free size from the available bytes count. */
|
||||
heap->available_size = heap->available_size - free_size;
|
||||
if (heap->pool_size - heap->available_size > heap->max_used_size)
|
||||
heap->max_used_size = heap->pool_size - heap->available_size;
|
||||
|
||||
/* remove header_ptr from free list */
|
||||
RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
|
||||
("one block: block[0x%08x], next_free 0x%08x, prev_free 0x%08x\n",
|
||||
header_ptr,
|
||||
header_ptr->next_free,
|
||||
header_ptr->prev_free));
|
||||
|
||||
header_ptr->next_free->prev_free = header_ptr->prev_free;
|
||||
header_ptr->prev_free->next_free = header_ptr->next_free;
|
||||
header_ptr->next_free = RT_NULL;
|
||||
header_ptr->prev_free = RT_NULL;
|
||||
}
|
||||
|
||||
/* Mark the allocated block as not available. */
|
||||
header_ptr->magic |= RT_MEMHEAP_USED;
|
||||
|
||||
/* release lock */
|
||||
rt_sem_release(&(heap->lock));
|
||||
|
||||
/* Return a memory address to the caller. */
|
||||
RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
|
||||
("alloc mem: memory[0x%08x], heap[0x%08x], size: %d\n",
|
||||
(void *)((rt_uint8_t *)header_ptr + RT_MEMHEAP_SIZE),
|
||||
header_ptr,
|
||||
size));
|
||||
|
||||
return (void *)((rt_uint8_t *)header_ptr + RT_MEMHEAP_SIZE);
|
||||
}
|
||||
|
||||
/* release lock */
|
||||
rt_sem_release(&(heap->lock));
|
||||
}
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("allocate memory: failed\n"));
|
||||
|
||||
/* Return the completion status. */
|
||||
return RT_NULL;
|
||||
}
|
||||
RTM_EXPORT(rt_memheap_alloc);
|
||||
|
||||
void *rt_memheap_realloc(struct rt_memheap *heap, void *ptr, rt_size_t newsize)
|
||||
{
|
||||
rt_err_t result;
|
||||
rt_size_t oldsize;
|
||||
struct rt_memheap_item *header_ptr;
|
||||
struct rt_memheap_item *new_ptr;
|
||||
|
||||
RT_ASSERT(heap);
|
||||
RT_ASSERT(rt_object_get_type(&heap->parent) == RT_Object_Class_MemHeap);
|
||||
|
||||
if (newsize == 0)
|
||||
{
|
||||
rt_memheap_free(ptr);
|
||||
|
||||
return RT_NULL;
|
||||
}
|
||||
/* align allocated size */
|
||||
newsize = RT_ALIGN(newsize, RT_ALIGN_SIZE);
|
||||
if (newsize < RT_MEMHEAP_MINIALLOC)
|
||||
newsize = RT_MEMHEAP_MINIALLOC;
|
||||
|
||||
if (ptr == RT_NULL)
|
||||
{
|
||||
return rt_memheap_alloc(heap, newsize);
|
||||
}
|
||||
|
||||
/* get memory block header and get the size of memory block */
|
||||
header_ptr = (struct rt_memheap_item *)
|
||||
((rt_uint8_t *)ptr - RT_MEMHEAP_SIZE);
|
||||
oldsize = MEMITEM_SIZE(header_ptr);
|
||||
/* re-allocate memory */
|
||||
if (newsize > oldsize)
|
||||
{
|
||||
void *new_ptr;
|
||||
struct rt_memheap_item *next_ptr;
|
||||
|
||||
/* lock memheap */
|
||||
result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
rt_set_errno(result);
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
next_ptr = header_ptr->next;
|
||||
|
||||
/* header_ptr should not be the tail */
|
||||
RT_ASSERT(next_ptr > header_ptr);
|
||||
|
||||
/* check whether the following free space is enough to expand */
|
||||
if (!RT_MEMHEAP_IS_USED(next_ptr))
|
||||
{
|
||||
rt_int32_t nextsize;
|
||||
|
||||
nextsize = MEMITEM_SIZE(next_ptr);
|
||||
RT_ASSERT(next_ptr > 0);
|
||||
|
||||
/* Here is the ASCII art of the situation that we can make use of
|
||||
* the next free node without alloc/memcpy, |*| is the control
|
||||
* block:
|
||||
*
|
||||
* oldsize free node
|
||||
* |*|-----------|*|----------------------|*|
|
||||
* newsize >= minialloc
|
||||
* |*|----------------|*|-----------------|*|
|
||||
*/
|
||||
if (nextsize + oldsize > newsize + RT_MEMHEAP_MINIALLOC)
|
||||
{
|
||||
/* decrement the entire free size from the available bytes count. */
|
||||
heap->available_size = heap->available_size - (newsize - oldsize);
|
||||
if (heap->pool_size - heap->available_size > heap->max_used_size)
|
||||
heap->max_used_size = heap->pool_size - heap->available_size;
|
||||
|
||||
/* remove next_ptr from free list */
|
||||
RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
|
||||
("remove block: block[0x%08x], next_free 0x%08x, prev_free 0x%08x",
|
||||
next_ptr,
|
||||
next_ptr->next_free,
|
||||
next_ptr->prev_free));
|
||||
|
||||
next_ptr->next_free->prev_free = next_ptr->prev_free;
|
||||
next_ptr->prev_free->next_free = next_ptr->next_free;
|
||||
next_ptr->next->prev = next_ptr->prev;
|
||||
next_ptr->prev->next = next_ptr->next;
|
||||
|
||||
/* build a new one on the right place */
|
||||
next_ptr = (struct rt_memheap_item *)((char *)ptr + newsize);
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
|
||||
("new free block: block[0x%08x] nextm[0x%08x] prevm[0x%08x]",
|
||||
next_ptr,
|
||||
next_ptr->next,
|
||||
next_ptr->prev));
|
||||
|
||||
/* mark the new block as a memory block and freed. */
|
||||
next_ptr->magic = RT_MEMHEAP_MAGIC;
|
||||
|
||||
/* put the pool pointer into the new block. */
|
||||
next_ptr->pool_ptr = heap;
|
||||
|
||||
next_ptr->prev = header_ptr;
|
||||
next_ptr->next = header_ptr->next;
|
||||
header_ptr->next->prev = next_ptr;
|
||||
header_ptr->next = next_ptr;
|
||||
|
||||
/* insert next_ptr to free list */
|
||||
next_ptr->next_free = heap->free_list->next_free;
|
||||
next_ptr->prev_free = heap->free_list;
|
||||
heap->free_list->next_free->prev_free = next_ptr;
|
||||
heap->free_list->next_free = next_ptr;
|
||||
RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("new ptr: next_free 0x%08x, prev_free 0x%08x",
|
||||
next_ptr->next_free,
|
||||
next_ptr->prev_free));
|
||||
|
||||
/* release lock */
|
||||
rt_sem_release(&(heap->lock));
|
||||
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
/* release lock */
|
||||
rt_sem_release(&(heap->lock));
|
||||
|
||||
/* re-allocate a memory block */
|
||||
new_ptr = (void *)rt_memheap_alloc(heap, newsize);
|
||||
if (new_ptr != RT_NULL)
|
||||
{
|
||||
rt_memcpy(new_ptr, ptr, oldsize < newsize ? oldsize : newsize);
|
||||
rt_memheap_free(ptr);
|
||||
}
|
||||
|
||||
return new_ptr;
|
||||
}
|
||||
|
||||
/* don't split when there is less than one node space left */
|
||||
if (newsize + RT_MEMHEAP_SIZE + RT_MEMHEAP_MINIALLOC >= oldsize)
|
||||
return ptr;
|
||||
|
||||
/* lock memheap */
|
||||
result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
rt_set_errno(result);
|
||||
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
/* split the block. */
|
||||
new_ptr = (struct rt_memheap_item *)
|
||||
(((rt_uint8_t *)header_ptr) + newsize + RT_MEMHEAP_SIZE);
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
|
||||
("split: block[0x%08x] nextm[0x%08x] prevm[0x%08x] to new[0x%08x]\n",
|
||||
header_ptr,
|
||||
header_ptr->next,
|
||||
header_ptr->prev,
|
||||
new_ptr));
|
||||
|
||||
/* mark the new block as a memory block and freed. */
|
||||
new_ptr->magic = RT_MEMHEAP_MAGIC;
|
||||
/* put the pool pointer into the new block. */
|
||||
new_ptr->pool_ptr = heap;
|
||||
|
||||
/* break down the block list */
|
||||
new_ptr->prev = header_ptr;
|
||||
new_ptr->next = header_ptr->next;
|
||||
header_ptr->next->prev = new_ptr;
|
||||
header_ptr->next = new_ptr;
|
||||
|
||||
/* determine if the block can be merged with the next neighbor. */
|
||||
if (!RT_MEMHEAP_IS_USED(new_ptr->next))
|
||||
{
|
||||
struct rt_memheap_item *free_ptr;
|
||||
|
||||
/* merge block with next neighbor. */
|
||||
free_ptr = new_ptr->next;
|
||||
heap->available_size = heap->available_size - MEMITEM_SIZE(free_ptr);
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
|
||||
("merge: right node 0x%08x, next_free 0x%08x, prev_free 0x%08x\n",
|
||||
header_ptr, header_ptr->next_free, header_ptr->prev_free));
|
||||
|
||||
free_ptr->next->prev = new_ptr;
|
||||
new_ptr->next = free_ptr->next;
|
||||
|
||||
/* remove free ptr from free list */
|
||||
free_ptr->next_free->prev_free = free_ptr->prev_free;
|
||||
free_ptr->prev_free->next_free = free_ptr->next_free;
|
||||
}
|
||||
|
||||
/* insert the split block to free list */
|
||||
new_ptr->next_free = heap->free_list->next_free;
|
||||
new_ptr->prev_free = heap->free_list;
|
||||
heap->free_list->next_free->prev_free = new_ptr;
|
||||
heap->free_list->next_free = new_ptr;
|
||||
RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("new free ptr: next_free 0x%08x, prev_free 0x%08x\n",
|
||||
new_ptr->next_free,
|
||||
new_ptr->prev_free));
|
||||
|
||||
/* increment the available byte count. */
|
||||
heap->available_size = heap->available_size + MEMITEM_SIZE(new_ptr);
|
||||
|
||||
/* release lock */
|
||||
rt_sem_release(&(heap->lock));
|
||||
|
||||
/* return the old memory block */
|
||||
return ptr;
|
||||
}
|
||||
RTM_EXPORT(rt_memheap_realloc);
|
||||
|
||||
void rt_memheap_free(void *ptr)
|
||||
{
|
||||
rt_err_t result;
|
||||
struct rt_memheap *heap;
|
||||
struct rt_memheap_item *header_ptr, *new_ptr;
|
||||
rt_uint32_t insert_header;
|
||||
|
||||
/* NULL check */
|
||||
if (ptr == RT_NULL) return;
|
||||
|
||||
/* set initial status as OK */
|
||||
insert_header = 1;
|
||||
new_ptr = RT_NULL;
|
||||
header_ptr = (struct rt_memheap_item *)
|
||||
((rt_uint8_t *)ptr - RT_MEMHEAP_SIZE);
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("free memory: memory[0x%08x], block[0x%08x]\n",
|
||||
ptr, header_ptr));
|
||||
|
||||
/* check magic */
|
||||
RT_ASSERT((header_ptr->magic & RT_MEMHEAP_MASK) == RT_MEMHEAP_MAGIC);
|
||||
RT_ASSERT(header_ptr->magic & RT_MEMHEAP_USED);
|
||||
/* check whether this block of memory has been over-written. */
|
||||
RT_ASSERT((header_ptr->next->magic & RT_MEMHEAP_MASK) == RT_MEMHEAP_MAGIC);
|
||||
|
||||
/* get pool ptr */
|
||||
heap = header_ptr->pool_ptr;
|
||||
|
||||
RT_ASSERT(heap);
|
||||
RT_ASSERT(rt_object_get_type(&heap->parent) == RT_Object_Class_MemHeap);
|
||||
|
||||
/* lock memheap */
|
||||
result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
rt_set_errno(result);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
/* Mark the memory as available. */
|
||||
header_ptr->magic &= ~RT_MEMHEAP_USED;
|
||||
/* Adjust the available number of bytes. */
|
||||
heap->available_size = heap->available_size + MEMITEM_SIZE(header_ptr);
|
||||
|
||||
/* Determine if the block can be merged with the previous neighbor. */
|
||||
if (!RT_MEMHEAP_IS_USED(header_ptr->prev))
|
||||
{
|
||||
RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("merge: left node 0x%08x\n",
|
||||
header_ptr->prev));
|
||||
|
||||
/* adjust the available number of bytes. */
|
||||
heap->available_size = heap->available_size + RT_MEMHEAP_SIZE;
|
||||
|
||||
/* yes, merge block with previous neighbor. */
|
||||
(header_ptr->prev)->next = header_ptr->next;
|
||||
(header_ptr->next)->prev = header_ptr->prev;
|
||||
|
||||
/* move header pointer to previous. */
|
||||
header_ptr = header_ptr->prev;
|
||||
/* don't insert header to free list */
|
||||
insert_header = 0;
|
||||
}
|
||||
|
||||
/* determine if the block can be merged with the next neighbor. */
|
||||
if (!RT_MEMHEAP_IS_USED(header_ptr->next))
|
||||
{
|
||||
/* adjust the available number of bytes. */
|
||||
heap->available_size = heap->available_size + RT_MEMHEAP_SIZE;
|
||||
|
||||
/* merge block with next neighbor. */
|
||||
new_ptr = header_ptr->next;
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
|
||||
("merge: right node 0x%08x, next_free 0x%08x, prev_free 0x%08x\n",
|
||||
new_ptr, new_ptr->next_free, new_ptr->prev_free));
|
||||
|
||||
new_ptr->next->prev = header_ptr;
|
||||
header_ptr->next = new_ptr->next;
|
||||
|
||||
/* remove new ptr from free list */
|
||||
new_ptr->next_free->prev_free = new_ptr->prev_free;
|
||||
new_ptr->prev_free->next_free = new_ptr->next_free;
|
||||
}
|
||||
|
||||
if (insert_header)
|
||||
{
|
||||
/* no left merge, insert to free list */
|
||||
header_ptr->next_free = heap->free_list->next_free;
|
||||
header_ptr->prev_free = heap->free_list;
|
||||
heap->free_list->next_free->prev_free = header_ptr;
|
||||
heap->free_list->next_free = header_ptr;
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
|
||||
("insert to free list: next_free 0x%08x, prev_free 0x%08x\n",
|
||||
header_ptr->next_free, header_ptr->prev_free));
|
||||
}
|
||||
|
||||
/* release lock */
|
||||
rt_sem_release(&(heap->lock));
|
||||
}
|
||||
RTM_EXPORT(rt_memheap_free);
|
||||
|
||||
#ifdef RT_USING_MEMHEAP_AS_HEAP
|
||||
static struct rt_memheap _heap;
|
||||
|
||||
void rt_system_heap_init(void *begin_addr, void *end_addr)
|
||||
{
|
||||
/* initialize a default heap in the system */
|
||||
rt_memheap_init(&_heap,
|
||||
"heap",
|
||||
begin_addr,
|
||||
(rt_uint32_t)end_addr - (rt_uint32_t)begin_addr);
|
||||
}
|
||||
|
||||
void *rt_malloc(rt_size_t size)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
/* try to allocate in system heap */
|
||||
ptr = rt_memheap_alloc(&_heap, size);
|
||||
if (ptr == RT_NULL)
|
||||
{
|
||||
struct rt_object *object;
|
||||
struct rt_list_node *node;
|
||||
struct rt_memheap *heap;
|
||||
struct rt_object_information *information;
|
||||
|
||||
/* try to allocate on other memory heap */
|
||||
information = rt_object_get_information(RT_Object_Class_MemHeap);
|
||||
RT_ASSERT(information != RT_NULL);
|
||||
for (node = information->object_list.next;
|
||||
node != &(information->object_list);
|
||||
node = node->next)
|
||||
{
|
||||
object = rt_list_entry(node, struct rt_object, list);
|
||||
heap = (struct rt_memheap *)object;
|
||||
|
||||
RT_ASSERT(heap);
|
||||
RT_ASSERT(rt_object_get_type(&heap->parent) == RT_Object_Class_MemHeap);
|
||||
|
||||
/* not allocate in the default system heap */
|
||||
if (heap == &_heap)
|
||||
continue;
|
||||
|
||||
ptr = rt_memheap_alloc(heap, size);
|
||||
if (ptr != RT_NULL)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
RTM_EXPORT(rt_malloc);
|
||||
|
||||
void rt_free(void *rmem)
|
||||
{
|
||||
rt_memheap_free(rmem);
|
||||
}
|
||||
RTM_EXPORT(rt_free);
|
||||
|
||||
void *rt_realloc(void *rmem, rt_size_t newsize)
|
||||
{
|
||||
void *new_ptr;
|
||||
struct rt_memheap_item *header_ptr;
|
||||
|
||||
if (rmem == RT_NULL)
|
||||
return rt_malloc(newsize);
|
||||
|
||||
if (newsize == 0)
|
||||
{
|
||||
rt_free(rmem);
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
/* get old memory item */
|
||||
header_ptr = (struct rt_memheap_item *)
|
||||
((rt_uint8_t *)rmem - RT_MEMHEAP_SIZE);
|
||||
|
||||
new_ptr = rt_memheap_realloc(header_ptr->pool_ptr, rmem, newsize);
|
||||
if (new_ptr == RT_NULL && newsize != 0)
|
||||
{
|
||||
/* allocate memory block from other memheap */
|
||||
new_ptr = rt_malloc(newsize);
|
||||
if (new_ptr != RT_NULL && rmem != RT_NULL)
|
||||
{
|
||||
rt_size_t oldsize;
|
||||
|
||||
/* get the size of old memory block */
|
||||
oldsize = MEMITEM_SIZE(header_ptr);
|
||||
if (newsize > oldsize)
|
||||
rt_memcpy(new_ptr, rmem, oldsize);
|
||||
else
|
||||
rt_memcpy(new_ptr, rmem, newsize);
|
||||
|
||||
rt_free(rmem);
|
||||
}
|
||||
}
|
||||
|
||||
return new_ptr;
|
||||
}
|
||||
RTM_EXPORT(rt_realloc);
|
||||
|
||||
void *rt_calloc(rt_size_t count, rt_size_t size)
|
||||
{
|
||||
void *ptr;
|
||||
rt_size_t total_size;
|
||||
|
||||
total_size = count * size;
|
||||
ptr = rt_malloc(total_size);
|
||||
if (ptr != RT_NULL)
|
||||
{
|
||||
/* clean memory */
|
||||
rt_memset(ptr, 0, total_size);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
RTM_EXPORT(rt_calloc);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,454 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2006-05-27 Bernard implement memory pool
|
||||
* 2006-06-03 Bernard fix the thread timer init bug
|
||||
* 2006-06-30 Bernard fix the allocate/free block bug
|
||||
* 2006-08-04 Bernard add hook support
|
||||
* 2006-08-10 Bernard fix interrupt bug in rt_mp_alloc
|
||||
* 2010-07-13 Bernard fix RT_ALIGN issue found by kuronca
|
||||
* 2010-10-26 yi.qiu add module support in rt_mp_delete
|
||||
* 2011-01-24 Bernard add object allocation check.
|
||||
* 2012-03-22 Bernard fix align issue in rt_mp_init and rt_mp_create.
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
#ifdef RT_USING_MEMPOOL
|
||||
|
||||
#ifdef RT_USING_HOOK
|
||||
static void (*rt_mp_alloc_hook)(struct rt_mempool *mp, void *block);
|
||||
static void (*rt_mp_free_hook)(struct rt_mempool *mp, void *block);
|
||||
|
||||
/**
|
||||
* @addtogroup Hook
|
||||
*/
|
||||
|
||||
/**@{*/
|
||||
|
||||
/**
|
||||
* This function will set a hook function, which will be invoked when a memory
|
||||
* block is allocated from memory pool.
|
||||
*
|
||||
* @param hook the hook function
|
||||
*/
|
||||
void rt_mp_alloc_sethook(void (*hook)(struct rt_mempool *mp, void *block))
|
||||
{
|
||||
rt_mp_alloc_hook = hook;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will set a hook function, which will be invoked when a memory
|
||||
* block is released to memory pool.
|
||||
*
|
||||
* @param hook the hook function
|
||||
*/
|
||||
void rt_mp_free_sethook(void (*hook)(struct rt_mempool *mp, void *block))
|
||||
{
|
||||
rt_mp_free_hook = hook;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @addtogroup MM
|
||||
*/
|
||||
|
||||
/**@{*/
|
||||
|
||||
/**
|
||||
* This function will initialize a memory pool object, normally which is used
|
||||
* for static object.
|
||||
*
|
||||
* @param mp the memory pool object
|
||||
* @param name the name of memory pool
|
||||
* @param start the star address of memory pool
|
||||
* @param size the total size of memory pool
|
||||
* @param block_size the size for each block
|
||||
*
|
||||
* @return RT_EOK
|
||||
*/
|
||||
rt_err_t rt_mp_init(struct rt_mempool *mp,
|
||||
const char *name,
|
||||
void *start,
|
||||
rt_size_t size,
|
||||
rt_size_t block_size)
|
||||
{
|
||||
rt_uint8_t *block_ptr;
|
||||
register rt_size_t offset;
|
||||
|
||||
/* parameter check */
|
||||
RT_ASSERT(mp != RT_NULL);
|
||||
|
||||
/* initialize object */
|
||||
rt_object_init(&(mp->parent), RT_Object_Class_MemPool, name);
|
||||
|
||||
/* initialize memory pool */
|
||||
mp->start_address = start;
|
||||
mp->size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
|
||||
|
||||
/* align the block size */
|
||||
block_size = RT_ALIGN(block_size, RT_ALIGN_SIZE);
|
||||
mp->block_size = block_size;
|
||||
|
||||
/* align to align size byte */
|
||||
mp->block_total_count = mp->size / (mp->block_size + sizeof(rt_uint8_t *));
|
||||
mp->block_free_count = mp->block_total_count;
|
||||
|
||||
/* initialize suspended thread list */
|
||||
rt_list_init(&(mp->suspend_thread));
|
||||
mp->suspend_thread_count = 0;
|
||||
|
||||
/* initialize free block list */
|
||||
block_ptr = (rt_uint8_t *)mp->start_address;
|
||||
for (offset = 0; offset < mp->block_total_count; offset ++)
|
||||
{
|
||||
*(rt_uint8_t **)(block_ptr + offset * (block_size + sizeof(rt_uint8_t *))) =
|
||||
(rt_uint8_t *)(block_ptr + (offset + 1) * (block_size + sizeof(rt_uint8_t *)));
|
||||
}
|
||||
|
||||
*(rt_uint8_t **)(block_ptr + (offset - 1) * (block_size + sizeof(rt_uint8_t *))) =
|
||||
RT_NULL;
|
||||
|
||||
mp->block_list = block_ptr;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
RTM_EXPORT(rt_mp_init);
|
||||
|
||||
/**
|
||||
* This function will detach a memory pool from system object management.
|
||||
*
|
||||
* @param mp the memory pool object
|
||||
*
|
||||
* @return RT_EOK
|
||||
*/
|
||||
rt_err_t rt_mp_detach(struct rt_mempool *mp)
|
||||
{
|
||||
struct rt_thread *thread;
|
||||
register rt_ubase_t temp;
|
||||
|
||||
/* parameter check */
|
||||
RT_ASSERT(mp != RT_NULL);
|
||||
RT_ASSERT(rt_object_get_type(&mp->parent) == RT_Object_Class_MemPool);
|
||||
RT_ASSERT(rt_object_is_systemobject(&mp->parent));
|
||||
|
||||
/* wake up all suspended threads */
|
||||
while (!rt_list_isempty(&(mp->suspend_thread)))
|
||||
{
|
||||
/* disable interrupt */
|
||||
temp = rt_hw_interrupt_disable();
|
||||
|
||||
/* get next suspend thread */
|
||||
thread = rt_list_entry(mp->suspend_thread.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);
|
||||
|
||||
/* decrease suspended thread count */
|
||||
mp->suspend_thread_count --;
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(temp);
|
||||
}
|
||||
|
||||
/* detach object */
|
||||
rt_object_detach(&(mp->parent));
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
RTM_EXPORT(rt_mp_detach);
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
/**
|
||||
* This function will create a mempool object and allocate the memory pool from
|
||||
* heap.
|
||||
*
|
||||
* @param name the name of memory pool
|
||||
* @param block_count the count of blocks in memory pool
|
||||
* @param block_size the size for each block
|
||||
*
|
||||
* @return the created mempool object
|
||||
*/
|
||||
rt_mp_t rt_mp_create(const char *name,
|
||||
rt_size_t block_count,
|
||||
rt_size_t block_size)
|
||||
{
|
||||
rt_uint8_t *block_ptr;
|
||||
struct rt_mempool *mp;
|
||||
register rt_size_t offset;
|
||||
|
||||
RT_DEBUG_NOT_IN_INTERRUPT;
|
||||
|
||||
/* allocate object */
|
||||
mp = (struct rt_mempool *)rt_object_allocate(RT_Object_Class_MemPool, name);
|
||||
/* allocate object failed */
|
||||
if (mp == RT_NULL)
|
||||
return RT_NULL;
|
||||
|
||||
/* initialize memory pool */
|
||||
block_size = RT_ALIGN(block_size, RT_ALIGN_SIZE);
|
||||
mp->block_size = block_size;
|
||||
mp->size = (block_size + sizeof(rt_uint8_t *)) * block_count;
|
||||
|
||||
/* allocate memory */
|
||||
mp->start_address = rt_malloc((block_size + sizeof(rt_uint8_t *)) *
|
||||
block_count);
|
||||
if (mp->start_address == RT_NULL)
|
||||
{
|
||||
/* no memory, delete memory pool object */
|
||||
rt_object_delete(&(mp->parent));
|
||||
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
mp->block_total_count = block_count;
|
||||
mp->block_free_count = mp->block_total_count;
|
||||
|
||||
/* initialize suspended thread list */
|
||||
rt_list_init(&(mp->suspend_thread));
|
||||
mp->suspend_thread_count = 0;
|
||||
|
||||
/* initialize free block list */
|
||||
block_ptr = (rt_uint8_t *)mp->start_address;
|
||||
for (offset = 0; offset < mp->block_total_count; offset ++)
|
||||
{
|
||||
*(rt_uint8_t **)(block_ptr + offset * (block_size + sizeof(rt_uint8_t *)))
|
||||
= block_ptr + (offset + 1) * (block_size + sizeof(rt_uint8_t *));
|
||||
}
|
||||
|
||||
*(rt_uint8_t **)(block_ptr + (offset - 1) * (block_size + sizeof(rt_uint8_t *)))
|
||||
= RT_NULL;
|
||||
|
||||
mp->block_list = block_ptr;
|
||||
|
||||
return mp;
|
||||
}
|
||||
RTM_EXPORT(rt_mp_create);
|
||||
|
||||
/**
|
||||
* This function will delete a memory pool and release the object memory.
|
||||
*
|
||||
* @param mp the memory pool object
|
||||
*
|
||||
* @return RT_EOK
|
||||
*/
|
||||
rt_err_t rt_mp_delete(rt_mp_t mp)
|
||||
{
|
||||
struct rt_thread *thread;
|
||||
register rt_ubase_t temp;
|
||||
|
||||
RT_DEBUG_NOT_IN_INTERRUPT;
|
||||
|
||||
/* parameter check */
|
||||
RT_ASSERT(mp != RT_NULL);
|
||||
RT_ASSERT(rt_object_get_type(&mp->parent) == RT_Object_Class_MemPool);
|
||||
RT_ASSERT(rt_object_is_systemobject(&mp->parent) == RT_FALSE);
|
||||
|
||||
/* wake up all suspended threads */
|
||||
while (!rt_list_isempty(&(mp->suspend_thread)))
|
||||
{
|
||||
/* disable interrupt */
|
||||
temp = rt_hw_interrupt_disable();
|
||||
|
||||
/* get next suspend thread */
|
||||
thread = rt_list_entry(mp->suspend_thread.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);
|
||||
|
||||
/* decrease suspended thread count */
|
||||
mp->suspend_thread_count --;
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(temp);
|
||||
}
|
||||
|
||||
/* release allocated room */
|
||||
rt_free(mp->start_address);
|
||||
|
||||
/* detach object */
|
||||
rt_object_delete(&(mp->parent));
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
RTM_EXPORT(rt_mp_delete);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This function will allocate a block from memory pool
|
||||
*
|
||||
* @param mp the memory pool object
|
||||
* @param time the waiting time
|
||||
*
|
||||
* @return the allocated memory block or RT_NULL on allocated failed
|
||||
*/
|
||||
void *rt_mp_alloc(rt_mp_t mp, rt_int32_t time)
|
||||
{
|
||||
rt_uint8_t *block_ptr;
|
||||
register rt_base_t level;
|
||||
struct rt_thread *thread;
|
||||
rt_uint32_t before_sleep = 0;
|
||||
|
||||
/* get current thread */
|
||||
thread = rt_thread_self();
|
||||
|
||||
/* disable interrupt */
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
while (mp->block_free_count == 0)
|
||||
{
|
||||
/* memory block is unavailable. */
|
||||
if (time == 0)
|
||||
{
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
rt_set_errno(-RT_ETIMEOUT);
|
||||
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
RT_DEBUG_NOT_IN_INTERRUPT;
|
||||
|
||||
thread->error = RT_EOK;
|
||||
|
||||
/* need suspend thread */
|
||||
rt_thread_suspend(thread);
|
||||
rt_list_insert_after(&(mp->suspend_thread), &(thread->tlist));
|
||||
mp->suspend_thread_count++;
|
||||
|
||||
if (time > 0)
|
||||
{
|
||||
/* get the start tick of timer */
|
||||
before_sleep = rt_tick_get();
|
||||
|
||||
/* init thread timer and start it */
|
||||
rt_timer_control(&(thread->thread_timer),
|
||||
RT_TIMER_CTRL_SET_TIME,
|
||||
&time);
|
||||
rt_timer_start(&(thread->thread_timer));
|
||||
}
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
/* do a schedule */
|
||||
rt_schedule();
|
||||
|
||||
if (thread->error != RT_EOK)
|
||||
return RT_NULL;
|
||||
|
||||
if (time > 0)
|
||||
{
|
||||
time -= rt_tick_get() - before_sleep;
|
||||
if (time < 0)
|
||||
time = 0;
|
||||
}
|
||||
/* disable interrupt */
|
||||
level = rt_hw_interrupt_disable();
|
||||
}
|
||||
|
||||
/* memory block is available. decrease the free block counter */
|
||||
mp->block_free_count--;
|
||||
|
||||
/* get block from block list */
|
||||
block_ptr = mp->block_list;
|
||||
RT_ASSERT(block_ptr != RT_NULL);
|
||||
|
||||
/* Setup the next free node. */
|
||||
mp->block_list = *(rt_uint8_t **)block_ptr;
|
||||
|
||||
/* point to memory pool */
|
||||
*(rt_uint8_t **)block_ptr = (rt_uint8_t *)mp;
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
RT_OBJECT_HOOK_CALL(rt_mp_alloc_hook,
|
||||
(mp, (rt_uint8_t *)(block_ptr + sizeof(rt_uint8_t *))));
|
||||
|
||||
return (rt_uint8_t *)(block_ptr + sizeof(rt_uint8_t *));
|
||||
}
|
||||
RTM_EXPORT(rt_mp_alloc);
|
||||
|
||||
/**
|
||||
* This function will release a memory block
|
||||
*
|
||||
* @param block the address of memory block to be released
|
||||
*/
|
||||
void rt_mp_free(void *block)
|
||||
{
|
||||
rt_uint8_t **block_ptr;
|
||||
struct rt_mempool *mp;
|
||||
struct rt_thread *thread;
|
||||
register rt_base_t level;
|
||||
|
||||
/* get the control block of pool which the block belongs to */
|
||||
block_ptr = (rt_uint8_t **)((rt_uint8_t *)block - sizeof(rt_uint8_t *));
|
||||
mp = (struct rt_mempool *)*block_ptr;
|
||||
|
||||
RT_OBJECT_HOOK_CALL(rt_mp_free_hook, (mp, block));
|
||||
|
||||
/* disable interrupt */
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
/* increase the free block count */
|
||||
mp->block_free_count ++;
|
||||
|
||||
/* link the block into the block list */
|
||||
*block_ptr = mp->block_list;
|
||||
mp->block_list = (rt_uint8_t *)block_ptr;
|
||||
|
||||
if (mp->suspend_thread_count > 0)
|
||||
{
|
||||
/* get the suspended thread */
|
||||
thread = rt_list_entry(mp->suspend_thread.next,
|
||||
struct rt_thread,
|
||||
tlist);
|
||||
|
||||
/* set error */
|
||||
thread->error = RT_EOK;
|
||||
|
||||
/* resume thread */
|
||||
rt_thread_resume(thread);
|
||||
|
||||
/* decrease suspended thread count */
|
||||
mp->suspend_thread_count --;
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
/* do a schedule */
|
||||
rt_schedule();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
}
|
||||
RTM_EXPORT(rt_mp_free);
|
||||
|
||||
/**@}*/
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,518 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2006-03-14 Bernard the first version
|
||||
* 2006-04-21 Bernard change the scheduler lock to interrupt lock
|
||||
* 2006-05-18 Bernard fix the object init bug
|
||||
* 2006-08-03 Bernard add hook support
|
||||
* 2007-01-28 Bernard rename RT_OBJECT_Class_Static to RT_Object_Class_Static
|
||||
* 2010-10-26 yi.qiu add module support in rt_object_allocate and rt_object_free
|
||||
* 2017-12-10 Bernard Add object_info enum.
|
||||
* 2018-01-25 Bernard Fix the object find issue when enable MODULE.
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rthw.h>
|
||||
|
||||
#ifdef RT_USING_MODULE
|
||||
#include <dlmodule.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* define object_info for the number of rt_object_container items.
|
||||
*/
|
||||
enum rt_object_info_type
|
||||
{
|
||||
RT_Object_Info_Thread = 0, /**< The object is a thread. */
|
||||
#ifdef RT_USING_SEMAPHORE
|
||||
RT_Object_Info_Semaphore, /**< The object is a semaphore. */
|
||||
#endif
|
||||
#ifdef RT_USING_MUTEX
|
||||
RT_Object_Info_Mutex, /**< The object is a mutex. */
|
||||
#endif
|
||||
#ifdef RT_USING_EVENT
|
||||
RT_Object_Info_Event, /**< The object is a event. */
|
||||
#endif
|
||||
#ifdef RT_USING_MAILBOX
|
||||
RT_Object_Info_MailBox, /**< The object is a mail box. */
|
||||
#endif
|
||||
#ifdef RT_USING_MESSAGEQUEUE
|
||||
RT_Object_Info_MessageQueue, /**< The object is a message queue. */
|
||||
#endif
|
||||
#ifdef RT_USING_MEMHEAP
|
||||
RT_Object_Info_MemHeap, /**< The object is a memory heap */
|
||||
#endif
|
||||
#ifdef RT_USING_MEMPOOL
|
||||
RT_Object_Info_MemPool, /**< The object is a memory pool. */
|
||||
#endif
|
||||
#ifdef RT_USING_DEVICE
|
||||
RT_Object_Info_Device, /**< The object is a device */
|
||||
#endif
|
||||
RT_Object_Info_Timer, /**< The object is a timer. */
|
||||
#ifdef RT_USING_MODULE
|
||||
RT_Object_Info_Module, /**< The object is a module. */
|
||||
#endif
|
||||
RT_Object_Info_Unknown, /**< The object is unknown. */
|
||||
};
|
||||
|
||||
#define _OBJ_CONTAINER_LIST_INIT(c) \
|
||||
{&(rt_object_container[c].object_list), &(rt_object_container[c].object_list)}
|
||||
static struct rt_object_information rt_object_container[RT_Object_Info_Unknown] =
|
||||
{
|
||||
/* initialize object container - thread */
|
||||
{RT_Object_Class_Thread, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Thread), sizeof(struct rt_thread)},
|
||||
#ifdef RT_USING_SEMAPHORE
|
||||
/* initialize object container - semaphore */
|
||||
{RT_Object_Class_Semaphore, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Semaphore), sizeof(struct rt_semaphore)},
|
||||
#endif
|
||||
#ifdef RT_USING_MUTEX
|
||||
/* initialize object container - mutex */
|
||||
{RT_Object_Class_Mutex, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Mutex), sizeof(struct rt_mutex)},
|
||||
#endif
|
||||
#ifdef RT_USING_EVENT
|
||||
/* initialize object container - event */
|
||||
{RT_Object_Class_Event, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Event), sizeof(struct rt_event)},
|
||||
#endif
|
||||
#ifdef RT_USING_MAILBOX
|
||||
/* initialize object container - mailbox */
|
||||
{RT_Object_Class_MailBox, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MailBox), sizeof(struct rt_mailbox)},
|
||||
#endif
|
||||
#ifdef RT_USING_MESSAGEQUEUE
|
||||
/* initialize object container - message queue */
|
||||
{RT_Object_Class_MessageQueue, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MessageQueue), sizeof(struct rt_messagequeue)},
|
||||
#endif
|
||||
#ifdef RT_USING_MEMHEAP
|
||||
/* initialize object container - memory heap */
|
||||
{RT_Object_Class_MemHeap, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MemHeap), sizeof(struct rt_memheap)},
|
||||
#endif
|
||||
#ifdef RT_USING_MEMPOOL
|
||||
/* initialize object container - memory pool */
|
||||
{RT_Object_Class_MemPool, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MemPool), sizeof(struct rt_mempool)},
|
||||
#endif
|
||||
#ifdef RT_USING_DEVICE
|
||||
/* initialize object container - device */
|
||||
{RT_Object_Class_Device, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Device), sizeof(struct rt_device)},
|
||||
#endif
|
||||
/* initialize object container - timer */
|
||||
{RT_Object_Class_Timer, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Timer), sizeof(struct rt_timer)},
|
||||
#ifdef RT_USING_MODULE
|
||||
/* initialize object container - module */
|
||||
{RT_Object_Class_Module, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Module), sizeof(struct rt_dlmodule)},
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef RT_USING_HOOK
|
||||
static void (*rt_object_attach_hook)(struct rt_object *object);
|
||||
static void (*rt_object_detach_hook)(struct rt_object *object);
|
||||
void (*rt_object_trytake_hook)(struct rt_object *object);
|
||||
void (*rt_object_take_hook)(struct rt_object *object);
|
||||
void (*rt_object_put_hook)(struct rt_object *object);
|
||||
|
||||
/**
|
||||
* @addtogroup Hook
|
||||
*/
|
||||
|
||||
/**@{*/
|
||||
|
||||
/**
|
||||
* This function will set a hook function, which will be invoked when object
|
||||
* attaches to kernel object system.
|
||||
*
|
||||
* @param hook the hook function
|
||||
*/
|
||||
void rt_object_attach_sethook(void (*hook)(struct rt_object *object))
|
||||
{
|
||||
rt_object_attach_hook = hook;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will set a hook function, which will be invoked when object
|
||||
* detaches from kernel object system.
|
||||
*
|
||||
* @param hook the hook function
|
||||
*/
|
||||
void rt_object_detach_sethook(void (*hook)(struct rt_object *object))
|
||||
{
|
||||
rt_object_detach_hook = hook;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will set a hook function, which will be invoked when object
|
||||
* is taken from kernel object system.
|
||||
*
|
||||
* The object is taken means:
|
||||
* semaphore - semaphore is taken by thread
|
||||
* mutex - mutex is taken by thread
|
||||
* event - event is received by thread
|
||||
* mailbox - mail is received by thread
|
||||
* message queue - message is received by thread
|
||||
*
|
||||
* @param hook the hook function
|
||||
*/
|
||||
void rt_object_trytake_sethook(void (*hook)(struct rt_object *object))
|
||||
{
|
||||
rt_object_trytake_hook = hook;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will set a hook function, which will be invoked when object
|
||||
* have been taken from kernel object system.
|
||||
*
|
||||
* The object have been taken means:
|
||||
* semaphore - semaphore have been taken by thread
|
||||
* mutex - mutex have been taken by thread
|
||||
* event - event have been received by thread
|
||||
* mailbox - mail have been received by thread
|
||||
* message queue - message have been received by thread
|
||||
* timer - timer is started
|
||||
*
|
||||
* @param hook the hook function
|
||||
*/
|
||||
void rt_object_take_sethook(void (*hook)(struct rt_object *object))
|
||||
{
|
||||
rt_object_take_hook = hook;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will set a hook function, which will be invoked when object
|
||||
* is put to kernel object system.
|
||||
*
|
||||
* @param hook the hook function
|
||||
*/
|
||||
void rt_object_put_sethook(void (*hook)(struct rt_object *object))
|
||||
{
|
||||
rt_object_put_hook = hook;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @ingroup SystemInit
|
||||
*
|
||||
* This function will initialize system object management.
|
||||
*
|
||||
* @deprecated since 0.3.0, this function does not need to be invoked
|
||||
* in the system initialization.
|
||||
*/
|
||||
void rt_system_object_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @addtogroup KernelObject
|
||||
*/
|
||||
|
||||
/**@{*/
|
||||
|
||||
/**
|
||||
* This function will return the specified type of object information.
|
||||
*
|
||||
* @param type the type of object
|
||||
* @return the object type information or RT_NULL
|
||||
*/
|
||||
struct rt_object_information *
|
||||
rt_object_get_information(enum rt_object_class_type type)
|
||||
{
|
||||
int index;
|
||||
|
||||
for (index = 0; index < RT_Object_Info_Unknown; index ++)
|
||||
if (rt_object_container[index].type == type) return &rt_object_container[index];
|
||||
|
||||
return RT_NULL;
|
||||
}
|
||||
RTM_EXPORT(rt_object_get_information);
|
||||
|
||||
/**
|
||||
* This function will initialize an object and add it to object system
|
||||
* management.
|
||||
*
|
||||
* @param object the specified object to be initialized.
|
||||
* @param type the object type.
|
||||
* @param name the object name. In system, the object's name must be unique.
|
||||
*/
|
||||
void rt_object_init(struct rt_object *object,
|
||||
enum rt_object_class_type type,
|
||||
const char *name)
|
||||
{
|
||||
register rt_base_t temp;
|
||||
struct rt_list_node *node = RT_NULL;
|
||||
struct rt_object_information *information;
|
||||
#ifdef RT_USING_MODULE
|
||||
struct rt_dlmodule *module = dlmodule_self();
|
||||
#endif
|
||||
|
||||
/* get object information */
|
||||
information = rt_object_get_information(type);
|
||||
RT_ASSERT(information != RT_NULL);
|
||||
|
||||
/* check object type to avoid re-initialization */
|
||||
|
||||
/* enter critical */
|
||||
rt_enter_critical();
|
||||
/* try to find object */
|
||||
for (node = information->object_list.next;
|
||||
node != &(information->object_list);
|
||||
node = node->next)
|
||||
{
|
||||
struct rt_object *obj;
|
||||
|
||||
obj = rt_list_entry(node, struct rt_object, list);
|
||||
RT_ASSERT(obj != object);
|
||||
}
|
||||
/* leave critical */
|
||||
rt_exit_critical();
|
||||
|
||||
/* initialize object's parameters */
|
||||
/* set object type to static */
|
||||
object->type = type | RT_Object_Class_Static;
|
||||
/* copy name */
|
||||
rt_strncpy(object->name, name, RT_NAME_MAX);
|
||||
|
||||
RT_OBJECT_HOOK_CALL(rt_object_attach_hook, (object));
|
||||
|
||||
/* lock interrupt */
|
||||
temp = rt_hw_interrupt_disable();
|
||||
|
||||
#ifdef RT_USING_MODULE
|
||||
if (module)
|
||||
{
|
||||
rt_list_insert_after(&(module->object_list), &(object->list));
|
||||
object->module_id = (void *)module;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* insert object into information object list */
|
||||
rt_list_insert_after(&(information->object_list), &(object->list));
|
||||
}
|
||||
|
||||
/* unlock interrupt */
|
||||
rt_hw_interrupt_enable(temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will detach a static object from object system,
|
||||
* and the memory of static object is not freed.
|
||||
*
|
||||
* @param object the specified object to be detached.
|
||||
*/
|
||||
void rt_object_detach(rt_object_t object)
|
||||
{
|
||||
register rt_base_t temp;
|
||||
|
||||
/* object check */
|
||||
RT_ASSERT(object != RT_NULL);
|
||||
|
||||
RT_OBJECT_HOOK_CALL(rt_object_detach_hook, (object));
|
||||
|
||||
/* reset object type */
|
||||
object->type = 0;
|
||||
|
||||
/* lock interrupt */
|
||||
temp = rt_hw_interrupt_disable();
|
||||
|
||||
/* remove from old list */
|
||||
rt_list_remove(&(object->list));
|
||||
|
||||
/* unlock interrupt */
|
||||
rt_hw_interrupt_enable(temp);
|
||||
}
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
/**
|
||||
* This function will allocate an object from object system
|
||||
*
|
||||
* @param type the type of object
|
||||
* @param name the object name. In system, the object's name must be unique.
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
rt_object_t rt_object_allocate(enum rt_object_class_type type, const char *name)
|
||||
{
|
||||
struct rt_object *object;
|
||||
register rt_base_t temp;
|
||||
struct rt_object_information *information;
|
||||
#ifdef RT_USING_MODULE
|
||||
struct rt_dlmodule *module = dlmodule_self();
|
||||
#endif
|
||||
|
||||
RT_DEBUG_NOT_IN_INTERRUPT;
|
||||
|
||||
/* get object information */
|
||||
information = rt_object_get_information(type);
|
||||
RT_ASSERT(information != RT_NULL);
|
||||
|
||||
object = (struct rt_object *)RT_KERNEL_MALLOC(information->object_size);
|
||||
if (object == RT_NULL)
|
||||
{
|
||||
/* no memory can be allocated */
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
/* clean memory data of object */
|
||||
rt_memset(object, 0x0, information->object_size);
|
||||
|
||||
/* initialize object's parameters */
|
||||
|
||||
/* set object type */
|
||||
object->type = type;
|
||||
|
||||
/* set object flag */
|
||||
object->flag = 0;
|
||||
|
||||
/* copy name */
|
||||
rt_strncpy(object->name, name, RT_NAME_MAX);
|
||||
|
||||
RT_OBJECT_HOOK_CALL(rt_object_attach_hook, (object));
|
||||
|
||||
/* lock interrupt */
|
||||
temp = rt_hw_interrupt_disable();
|
||||
|
||||
#ifdef RT_USING_MODULE
|
||||
if (module)
|
||||
{
|
||||
rt_list_insert_after(&(module->object_list), &(object->list));
|
||||
object->module_id = (void *)module;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* insert object into information object list */
|
||||
rt_list_insert_after(&(information->object_list), &(object->list));
|
||||
}
|
||||
|
||||
/* unlock interrupt */
|
||||
rt_hw_interrupt_enable(temp);
|
||||
|
||||
/* return object */
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will delete an object and release object memory.
|
||||
*
|
||||
* @param object the specified object to be deleted.
|
||||
*/
|
||||
void rt_object_delete(rt_object_t object)
|
||||
{
|
||||
register rt_base_t temp;
|
||||
|
||||
/* object check */
|
||||
RT_ASSERT(object != RT_NULL);
|
||||
RT_ASSERT(!(object->type & RT_Object_Class_Static));
|
||||
|
||||
RT_OBJECT_HOOK_CALL(rt_object_detach_hook, (object));
|
||||
|
||||
/* reset object type */
|
||||
object->type = 0;
|
||||
|
||||
/* lock interrupt */
|
||||
temp = rt_hw_interrupt_disable();
|
||||
|
||||
/* remove from old list */
|
||||
rt_list_remove(&(object->list));
|
||||
|
||||
/* unlock interrupt */
|
||||
rt_hw_interrupt_enable(temp);
|
||||
|
||||
/* free the memory of object */
|
||||
RT_KERNEL_FREE(object);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This function will judge the object is system object or not.
|
||||
* Normally, the system object is a static object and the type
|
||||
* of object set to RT_Object_Class_Static.
|
||||
*
|
||||
* @param object the specified object to be judged.
|
||||
*
|
||||
* @return RT_TRUE if a system object, RT_FALSE for others.
|
||||
*/
|
||||
rt_bool_t rt_object_is_systemobject(rt_object_t object)
|
||||
{
|
||||
/* object check */
|
||||
RT_ASSERT(object != RT_NULL);
|
||||
|
||||
if (object->type & RT_Object_Class_Static)
|
||||
return RT_TRUE;
|
||||
|
||||
return RT_FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will return the type of object without
|
||||
* RT_Object_Class_Static flag.
|
||||
*
|
||||
* @param object the specified object to be get type.
|
||||
*
|
||||
* @return the type of object.
|
||||
*/
|
||||
rt_uint8_t rt_object_get_type(rt_object_t object)
|
||||
{
|
||||
/* object check */
|
||||
RT_ASSERT(object != RT_NULL);
|
||||
|
||||
return object->type & ~RT_Object_Class_Static;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will find specified name object from object
|
||||
* container.
|
||||
*
|
||||
* @param name the specified name of object.
|
||||
* @param type the type of object
|
||||
*
|
||||
* @return the found object or RT_NULL if there is no this object
|
||||
* in object container.
|
||||
*
|
||||
* @note this function shall not be invoked in interrupt status.
|
||||
*/
|
||||
rt_object_t rt_object_find(const char *name, rt_uint8_t type)
|
||||
{
|
||||
struct rt_object *object = RT_NULL;
|
||||
struct rt_list_node *node = RT_NULL;
|
||||
struct rt_object_information *information = RT_NULL;
|
||||
|
||||
/* parameter check */
|
||||
if ((name == RT_NULL) || (type > RT_Object_Class_Unknown))
|
||||
return RT_NULL;
|
||||
|
||||
/* which is invoke in interrupt status */
|
||||
RT_DEBUG_NOT_IN_INTERRUPT;
|
||||
|
||||
/* enter critical */
|
||||
rt_enter_critical();
|
||||
|
||||
/* try to find object */
|
||||
if (information == RT_NULL)
|
||||
{
|
||||
information = rt_object_get_information((enum rt_object_class_type)type);
|
||||
RT_ASSERT(information != RT_NULL);
|
||||
}
|
||||
for (node = information->object_list.next;
|
||||
node != &(information->object_list);
|
||||
node = node->next)
|
||||
{
|
||||
object = rt_list_entry(node, struct rt_object, list);
|
||||
if (rt_strncmp(object->name, name, RT_NAME_MAX) == 0)
|
||||
{
|
||||
/* leave critical */
|
||||
rt_exit_critical();
|
||||
|
||||
return object;
|
||||
}
|
||||
}
|
||||
|
||||
/* leave critical */
|
||||
rt_exit_critical();
|
||||
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
@@ -0,0 +1,436 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2006-03-17 Bernard the first version
|
||||
* 2006-04-28 Bernard fix the scheduler algorthm
|
||||
* 2006-04-30 Bernard add SCHEDULER_DEBUG
|
||||
* 2006-05-27 Bernard fix the scheduler algorthm for same priority
|
||||
* thread schedule
|
||||
* 2006-06-04 Bernard rewrite the scheduler algorithm
|
||||
* 2006-08-03 Bernard add hook support
|
||||
* 2006-09-05 Bernard add 32 priority level support
|
||||
* 2006-09-24 Bernard add rt_system_scheduler_start function
|
||||
* 2009-09-16 Bernard fix _rt_scheduler_stack_check
|
||||
* 2010-04-11 yi.qiu add module feature
|
||||
* 2010-07-13 Bernard fix the maximal number of rt_scheduler_lock_nest
|
||||
* issue found by kuronca
|
||||
* 2010-12-13 Bernard add defunct list initialization even if not use heap.
|
||||
* 2011-05-10 Bernard clean scheduler debug log.
|
||||
* 2013-12-21 Grissiom add rt_critical_level
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rthw.h>
|
||||
static rt_int16_t rt_scheduler_lock_nest;
|
||||
extern volatile rt_uint8_t rt_interrupt_nest;
|
||||
|
||||
rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX];
|
||||
struct rt_thread *rt_current_thread;
|
||||
|
||||
rt_uint8_t rt_current_priority;
|
||||
|
||||
#if RT_THREAD_PRIORITY_MAX > 32
|
||||
/* Maximum priority level, 256 */
|
||||
rt_uint32_t rt_thread_ready_priority_group;
|
||||
rt_uint8_t rt_thread_ready_table[32];
|
||||
#else
|
||||
/* Maximum priority level, 32 */
|
||||
rt_uint32_t rt_thread_ready_priority_group;
|
||||
#endif
|
||||
|
||||
rt_list_t rt_thread_defunct;
|
||||
|
||||
#ifdef RT_USING_HOOK
|
||||
static void (*rt_scheduler_hook)(struct rt_thread *from, struct rt_thread *to);
|
||||
|
||||
/**
|
||||
* @addtogroup Hook
|
||||
*/
|
||||
|
||||
/**@{*/
|
||||
|
||||
/**
|
||||
* This function will set a hook function, which will be invoked when thread
|
||||
* switch happens.
|
||||
*
|
||||
* @param hook the hook function
|
||||
*/
|
||||
void
|
||||
rt_scheduler_sethook(void (*hook)(struct rt_thread *from, struct rt_thread *to))
|
||||
{
|
||||
rt_scheduler_hook = hook;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_OVERFLOW_CHECK
|
||||
static void _rt_scheduler_stack_check(struct rt_thread *thread)
|
||||
{
|
||||
RT_ASSERT(thread != RT_NULL);
|
||||
|
||||
#if defined(ARCH_CPU_STACK_GROWS_UPWARD)
|
||||
if (*((rt_uint8_t *)((rt_ubase_t)thread->stack_addr + thread->stack_size - 1)) != '#' ||
|
||||
#else
|
||||
if (*((rt_uint8_t *)thread->stack_addr) != '#' ||
|
||||
#endif
|
||||
(rt_uint32_t)thread->sp <= (rt_uint32_t)thread->stack_addr ||
|
||||
(rt_uint32_t)thread->sp >
|
||||
(rt_uint32_t)thread->stack_addr + (rt_uint32_t)thread->stack_size)
|
||||
{
|
||||
rt_uint32_t level;
|
||||
|
||||
rt_kprintf("thread:%s stack overflow\n", thread->name);
|
||||
#ifdef RT_USING_FINSH
|
||||
{
|
||||
extern long list_thread(void);
|
||||
list_thread();
|
||||
}
|
||||
#endif
|
||||
level = rt_hw_interrupt_disable();
|
||||
while (level);
|
||||
}
|
||||
#if defined(ARCH_CPU_STACK_GROWS_UPWARD)
|
||||
else if ((rt_uint32_t)thread->sp > ((rt_uint32_t)thread->stack_addr + thread->stack_size))
|
||||
{
|
||||
rt_kprintf("warning: %s stack is close to the top of stack address.\n",
|
||||
thread->name);
|
||||
}
|
||||
#else
|
||||
else if ((rt_uint32_t)thread->sp <= ((rt_uint32_t)thread->stack_addr + 32))
|
||||
{
|
||||
rt_kprintf("warning: %s stack is close to the bottom of stack address.\n",
|
||||
thread->name);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @ingroup SystemInit
|
||||
* This function will initialize the system scheduler
|
||||
*/
|
||||
void rt_system_scheduler_init(void)
|
||||
{
|
||||
register rt_base_t offset;
|
||||
|
||||
rt_scheduler_lock_nest = 0;
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("start scheduler: max priority 0x%02x\n",
|
||||
RT_THREAD_PRIORITY_MAX));
|
||||
|
||||
for (offset = 0; offset < RT_THREAD_PRIORITY_MAX; offset ++)
|
||||
{
|
||||
rt_list_init(&rt_thread_priority_table[offset]);
|
||||
}
|
||||
|
||||
rt_current_priority = RT_THREAD_PRIORITY_MAX - 1;
|
||||
rt_current_thread = RT_NULL;
|
||||
|
||||
/* initialize ready priority group */
|
||||
rt_thread_ready_priority_group = 0;
|
||||
|
||||
#if RT_THREAD_PRIORITY_MAX > 32
|
||||
/* initialize ready table */
|
||||
rt_memset(rt_thread_ready_table, 0, sizeof(rt_thread_ready_table));
|
||||
#endif
|
||||
|
||||
/* initialize thread defunct */
|
||||
rt_list_init(&rt_thread_defunct);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup SystemInit
|
||||
* This function will startup scheduler. It will select one thread
|
||||
* with the highest priority level, then switch to it.
|
||||
*/
|
||||
void rt_system_scheduler_start(void)
|
||||
{
|
||||
register struct rt_thread *to_thread;
|
||||
register rt_ubase_t highest_ready_priority;
|
||||
|
||||
#if RT_THREAD_PRIORITY_MAX > 32
|
||||
register rt_ubase_t number;
|
||||
|
||||
number = __rt_ffs(rt_thread_ready_priority_group) - 1;
|
||||
highest_ready_priority = (number << 3) + __rt_ffs(rt_thread_ready_table[number]) - 1;
|
||||
#else
|
||||
highest_ready_priority = __rt_ffs(rt_thread_ready_priority_group) - 1;
|
||||
#endif
|
||||
|
||||
/* get switch to thread */
|
||||
to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,
|
||||
struct rt_thread,
|
||||
tlist);
|
||||
|
||||
rt_current_thread = to_thread;
|
||||
|
||||
/* switch to new thread */
|
||||
rt_hw_context_switch_to((rt_uint32_t)&to_thread->sp);
|
||||
|
||||
/* never come back */
|
||||
}
|
||||
|
||||
/**
|
||||
* @addtogroup Thread
|
||||
*/
|
||||
|
||||
/**@{*/
|
||||
|
||||
/**
|
||||
* This function will perform one schedule. It will select one thread
|
||||
* with the highest priority level, then switch to it.
|
||||
*/
|
||||
void rt_schedule(void)
|
||||
{
|
||||
rt_base_t level;
|
||||
struct rt_thread *to_thread;
|
||||
struct rt_thread *from_thread;
|
||||
|
||||
/* disable interrupt */
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
/* check the scheduler is enabled or not */
|
||||
if (rt_scheduler_lock_nest == 0)
|
||||
{
|
||||
register rt_ubase_t highest_ready_priority;
|
||||
|
||||
#if RT_THREAD_PRIORITY_MAX <= 32
|
||||
highest_ready_priority = __rt_ffs(rt_thread_ready_priority_group) - 1;
|
||||
#else
|
||||
register rt_ubase_t number;
|
||||
|
||||
number = __rt_ffs(rt_thread_ready_priority_group) - 1;
|
||||
highest_ready_priority = (number << 3) + __rt_ffs(rt_thread_ready_table[number]) - 1;
|
||||
#endif
|
||||
|
||||
/* get switch to thread */
|
||||
to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,
|
||||
struct rt_thread,
|
||||
tlist);
|
||||
|
||||
/* if the destination thread is not the same as current thread */
|
||||
if (to_thread != rt_current_thread)
|
||||
{
|
||||
rt_current_priority = (rt_uint8_t)highest_ready_priority;
|
||||
from_thread = rt_current_thread;
|
||||
rt_current_thread = to_thread;
|
||||
|
||||
RT_OBJECT_HOOK_CALL(rt_scheduler_hook, (from_thread, to_thread));
|
||||
|
||||
/* switch to new thread */
|
||||
RT_DEBUG_LOG(RT_DEBUG_SCHEDULER,
|
||||
("[%d]switch to priority#%d "
|
||||
"thread:%.*s(sp:0x%p), "
|
||||
"from thread:%.*s(sp: 0x%p)\n",
|
||||
rt_interrupt_nest, highest_ready_priority,
|
||||
RT_NAME_MAX, to_thread->name, to_thread->sp,
|
||||
RT_NAME_MAX, from_thread->name, from_thread->sp));
|
||||
|
||||
#ifdef RT_USING_OVERFLOW_CHECK
|
||||
_rt_scheduler_stack_check(to_thread);
|
||||
#endif
|
||||
|
||||
if (rt_interrupt_nest == 0)
|
||||
{
|
||||
rt_hw_context_switch((rt_uint32_t)&from_thread->sp,
|
||||
(rt_uint32_t)&to_thread->sp);
|
||||
|
||||
#ifdef RT_USING_SIGNALS
|
||||
if (rt_current_thread->stat & RT_THREAD_STAT_SIGNAL_PENDING)
|
||||
{
|
||||
extern void rt_thread_handle_sig(rt_bool_t clean_state);
|
||||
|
||||
rt_current_thread->stat &= ~RT_THREAD_STAT_SIGNAL_PENDING;
|
||||
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
/* check signal status */
|
||||
rt_thread_handle_sig(RT_TRUE);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
}
|
||||
|
||||
return ;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("switch in interrupt\n"));
|
||||
rt_hw_context_switch_interrupt((rt_uint32_t)&from_thread->sp,
|
||||
(rt_uint32_t)&to_thread->sp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function will insert a thread to system ready queue. The state of
|
||||
* thread will be set as READY and remove from suspend queue.
|
||||
*
|
||||
* @param thread the thread to be inserted
|
||||
* @note Please do not invoke this function in user application.
|
||||
*/
|
||||
void rt_schedule_insert_thread(struct rt_thread *thread)
|
||||
{
|
||||
register rt_base_t temp;
|
||||
|
||||
RT_ASSERT(thread != RT_NULL);
|
||||
|
||||
/* disable interrupt */
|
||||
temp = rt_hw_interrupt_disable();
|
||||
|
||||
/* change stat */
|
||||
thread->stat = RT_THREAD_READY | (thread->stat & ~RT_THREAD_STAT_MASK);
|
||||
|
||||
/* insert thread to ready list */
|
||||
rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),
|
||||
&(thread->tlist));
|
||||
|
||||
/* set priority mask */
|
||||
#if RT_THREAD_PRIORITY_MAX <= 32
|
||||
RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("insert thread[%.*s], the priority: %d\n",
|
||||
RT_NAME_MAX, thread->name, thread->current_priority));
|
||||
#else
|
||||
RT_DEBUG_LOG(RT_DEBUG_SCHEDULER,
|
||||
("insert thread[%.*s], the priority: %d 0x%x %d\n",
|
||||
RT_NAME_MAX,
|
||||
thread->name,
|
||||
thread->number,
|
||||
thread->number_mask,
|
||||
thread->high_mask));
|
||||
#endif
|
||||
|
||||
#if RT_THREAD_PRIORITY_MAX > 32
|
||||
rt_thread_ready_table[thread->number] |= thread->high_mask;
|
||||
#endif
|
||||
rt_thread_ready_priority_group |= thread->number_mask;
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(temp);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function will remove a thread from system ready queue.
|
||||
*
|
||||
* @param thread the thread to be removed
|
||||
*
|
||||
* @note Please do not invoke this function in user application.
|
||||
*/
|
||||
void rt_schedule_remove_thread(struct rt_thread *thread)
|
||||
{
|
||||
register rt_base_t temp;
|
||||
|
||||
RT_ASSERT(thread != RT_NULL);
|
||||
|
||||
/* disable interrupt */
|
||||
temp = rt_hw_interrupt_disable();
|
||||
|
||||
#if RT_THREAD_PRIORITY_MAX <= 32
|
||||
RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("remove thread[%.*s], the priority: %d\n",
|
||||
RT_NAME_MAX, thread->name,
|
||||
thread->current_priority));
|
||||
#else
|
||||
RT_DEBUG_LOG(RT_DEBUG_SCHEDULER,
|
||||
("remove thread[%.*s], the priority: %d 0x%x %d\n",
|
||||
RT_NAME_MAX,
|
||||
thread->name,
|
||||
thread->number,
|
||||
thread->number_mask,
|
||||
thread->high_mask));
|
||||
#endif
|
||||
|
||||
/* remove thread from ready list */
|
||||
rt_list_remove(&(thread->tlist));
|
||||
if (rt_list_isempty(&(rt_thread_priority_table[thread->current_priority])))
|
||||
{
|
||||
#if RT_THREAD_PRIORITY_MAX > 32
|
||||
rt_thread_ready_table[thread->number] &= ~thread->high_mask;
|
||||
if (rt_thread_ready_table[thread->number] == 0)
|
||||
{
|
||||
rt_thread_ready_priority_group &= ~thread->number_mask;
|
||||
}
|
||||
#else
|
||||
rt_thread_ready_priority_group &= ~thread->number_mask;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will lock the thread scheduler.
|
||||
*/
|
||||
void rt_enter_critical(void)
|
||||
{
|
||||
register rt_base_t level;
|
||||
|
||||
/* disable interrupt */
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
/*
|
||||
* the maximal number of nest is RT_UINT16_MAX, which is big
|
||||
* enough and does not check here
|
||||
*/
|
||||
rt_scheduler_lock_nest ++;
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
}
|
||||
RTM_EXPORT(rt_enter_critical);
|
||||
|
||||
/**
|
||||
* This function will unlock the thread scheduler.
|
||||
*/
|
||||
void rt_exit_critical(void)
|
||||
{
|
||||
register rt_base_t level;
|
||||
|
||||
/* disable interrupt */
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
rt_scheduler_lock_nest --;
|
||||
if (rt_scheduler_lock_nest <= 0)
|
||||
{
|
||||
rt_scheduler_lock_nest = 0;
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
if (rt_current_thread)
|
||||
{
|
||||
/* if scheduler is started, do a schedule */
|
||||
rt_schedule();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
}
|
||||
}
|
||||
RTM_EXPORT(rt_exit_critical);
|
||||
|
||||
/**
|
||||
* Get the scheduler lock level
|
||||
*
|
||||
* @return the level of the scheduler lock. 0 means unlocked.
|
||||
*/
|
||||
rt_uint16_t rt_critical_level(void)
|
||||
{
|
||||
return rt_scheduler_lock_nest;
|
||||
}
|
||||
RTM_EXPORT(rt_critical_level);
|
||||
/**@}*/
|
||||
|
||||
@@ -0,0 +1,937 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* File : slab.c
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2008-07-12 Bernard the first version
|
||||
* 2010-07-13 Bernard fix RT_ALIGN issue found by kuronca
|
||||
* 2010-10-23 yi.qiu add module memory allocator
|
||||
* 2010-12-18 yi.qiu fix zone release bug
|
||||
*/
|
||||
|
||||
/*
|
||||
* KERN_SLABALLOC.C - Kernel SLAB memory allocator
|
||||
*
|
||||
* Copyright (c) 2003,2004 The DragonFly Project. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The DragonFly Project
|
||||
* by Matthew Dillon <dillon@backplane.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name of The DragonFly Project nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific, prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
#define RT_MEM_STATS
|
||||
|
||||
#if defined (RT_USING_HEAP) && defined (RT_USING_SLAB)
|
||||
/* some statistical variable */
|
||||
#ifdef RT_MEM_STATS
|
||||
static rt_size_t used_mem, max_mem;
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_HOOK
|
||||
static void (*rt_malloc_hook)(void *ptr, rt_size_t size);
|
||||
static void (*rt_free_hook)(void *ptr);
|
||||
|
||||
/**
|
||||
* @addtogroup Hook
|
||||
*/
|
||||
|
||||
/**@{*/
|
||||
|
||||
/**
|
||||
* This function will set a hook function, which will be invoked when a memory
|
||||
* block is allocated from heap memory.
|
||||
*
|
||||
* @param hook the hook function
|
||||
*/
|
||||
void rt_malloc_sethook(void (*hook)(void *ptr, rt_size_t size))
|
||||
{
|
||||
rt_malloc_hook = hook;
|
||||
}
|
||||
RTM_EXPORT(rt_malloc_sethook);
|
||||
|
||||
/**
|
||||
* This function will set a hook function, which will be invoked when a memory
|
||||
* block is released to heap memory.
|
||||
*
|
||||
* @param hook the hook function
|
||||
*/
|
||||
void rt_free_sethook(void (*hook)(void *ptr))
|
||||
{
|
||||
rt_free_hook = hook;
|
||||
}
|
||||
RTM_EXPORT(rt_free_sethook);
|
||||
|
||||
/**@}*/
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* slab allocator implementation
|
||||
*
|
||||
* A slab allocator reserves a ZONE for each chunk size, then lays the
|
||||
* chunks out in an array within the zone. Allocation and deallocation
|
||||
* is nearly instantanious, and fragmentation/overhead losses are limited
|
||||
* to a fixed worst-case amount.
|
||||
*
|
||||
* The downside of this slab implementation is in the chunk size
|
||||
* multiplied by the number of zones. ~80 zones * 128K = 10MB of VM per cpu.
|
||||
* In a kernel implementation all this memory will be physical so
|
||||
* the zone size is adjusted downward on machines with less physical
|
||||
* memory. The upside is that overhead is bounded... this is the *worst*
|
||||
* case overhead.
|
||||
*
|
||||
* Slab management is done on a per-cpu basis and no locking or mutexes
|
||||
* are required, only a critical section. When one cpu frees memory
|
||||
* belonging to another cpu's slab manager an asynchronous IPI message
|
||||
* will be queued to execute the operation. In addition, both the
|
||||
* high level slab allocator and the low level zone allocator optimize
|
||||
* M_ZERO requests, and the slab allocator does not have to pre initialize
|
||||
* the linked list of chunks.
|
||||
*
|
||||
* XXX Balancing is needed between cpus. Balance will be handled through
|
||||
* asynchronous IPIs primarily by reassigning the z_Cpu ownership of chunks.
|
||||
*
|
||||
* XXX If we have to allocate a new zone and M_USE_RESERVE is set, use of
|
||||
* the new zone should be restricted to M_USE_RESERVE requests only.
|
||||
*
|
||||
* Alloc Size Chunking Number of zones
|
||||
* 0-127 8 16
|
||||
* 128-255 16 8
|
||||
* 256-511 32 8
|
||||
* 512-1023 64 8
|
||||
* 1024-2047 128 8
|
||||
* 2048-4095 256 8
|
||||
* 4096-8191 512 8
|
||||
* 8192-16383 1024 8
|
||||
* 16384-32767 2048 8
|
||||
* (if RT_MM_PAGE_SIZE is 4K the maximum zone allocation is 16383)
|
||||
*
|
||||
* Allocations >= zone_limit go directly to kmem.
|
||||
*
|
||||
* API REQUIREMENTS AND SIDE EFFECTS
|
||||
*
|
||||
* To operate as a drop-in replacement to the FreeBSD-4.x malloc() we
|
||||
* have remained compatible with the following API requirements:
|
||||
*
|
||||
* + small power-of-2 sized allocations are power-of-2 aligned (kern_tty)
|
||||
* + all power-of-2 sized allocations are power-of-2 aligned (twe)
|
||||
* + malloc(0) is allowed and returns non-RT_NULL (ahc driver)
|
||||
* + ability to allocate arbitrarily large chunks of memory
|
||||
*/
|
||||
|
||||
/*
|
||||
* Chunk structure for free elements
|
||||
*/
|
||||
typedef struct slab_chunk
|
||||
{
|
||||
struct slab_chunk *c_next;
|
||||
} slab_chunk;
|
||||
|
||||
/*
|
||||
* The IN-BAND zone header is placed at the beginning of each zone.
|
||||
*/
|
||||
typedef struct slab_zone
|
||||
{
|
||||
rt_int32_t z_magic; /* magic number for sanity check */
|
||||
rt_int32_t z_nfree; /* total free chunks / ualloc space in zone */
|
||||
rt_int32_t z_nmax; /* maximum free chunks */
|
||||
|
||||
struct slab_zone *z_next; /* zoneary[] link if z_nfree non-zero */
|
||||
rt_uint8_t *z_baseptr; /* pointer to start of chunk array */
|
||||
|
||||
rt_int32_t z_uindex; /* current initial allocation index */
|
||||
rt_int32_t z_chunksize; /* chunk size for validation */
|
||||
|
||||
rt_int32_t z_zoneindex; /* zone index */
|
||||
slab_chunk *z_freechunk; /* free chunk list */
|
||||
} slab_zone;
|
||||
|
||||
#define ZALLOC_SLAB_MAGIC 0x51ab51ab
|
||||
#define ZALLOC_ZONE_LIMIT (16 * 1024) /* max slab-managed alloc */
|
||||
#define ZALLOC_MIN_ZONE_SIZE (32 * 1024) /* minimum zone size */
|
||||
#define ZALLOC_MAX_ZONE_SIZE (128 * 1024) /* maximum zone size */
|
||||
#define NZONES 72 /* number of zones */
|
||||
#define ZONE_RELEASE_THRESH 2 /* threshold number of zones */
|
||||
|
||||
static slab_zone *zone_array[NZONES]; /* linked list of zones NFree > 0 */
|
||||
static slab_zone *zone_free; /* whole zones that have become free */
|
||||
|
||||
static int zone_free_cnt;
|
||||
static int zone_size;
|
||||
static int zone_limit;
|
||||
static int zone_page_cnt;
|
||||
|
||||
/*
|
||||
* Misc constants. Note that allocations that are exact multiples of
|
||||
* RT_MM_PAGE_SIZE, or exceed the zone limit, fall through to the kmem module.
|
||||
*/
|
||||
#define MIN_CHUNK_SIZE 8 /* in bytes */
|
||||
#define MIN_CHUNK_MASK (MIN_CHUNK_SIZE - 1)
|
||||
|
||||
/*
|
||||
* Array of descriptors that describe the contents of each page
|
||||
*/
|
||||
#define PAGE_TYPE_FREE 0x00
|
||||
#define PAGE_TYPE_SMALL 0x01
|
||||
#define PAGE_TYPE_LARGE 0x02
|
||||
struct memusage
|
||||
{
|
||||
rt_uint32_t type: 2 ; /* page type */
|
||||
rt_uint32_t size: 30; /* pages allocated or offset from zone */
|
||||
};
|
||||
static struct memusage *memusage = RT_NULL;
|
||||
#define btokup(addr) \
|
||||
(&memusage[((rt_uint32_t)(addr) - heap_start) >> RT_MM_PAGE_BITS])
|
||||
|
||||
static rt_uint32_t heap_start, heap_end;
|
||||
|
||||
/* page allocator */
|
||||
struct rt_page_head
|
||||
{
|
||||
struct rt_page_head *next; /* next valid page */
|
||||
rt_size_t page; /* number of page */
|
||||
|
||||
/* dummy */
|
||||
char dummy[RT_MM_PAGE_SIZE - (sizeof(struct rt_page_head *) + sizeof(rt_size_t))];
|
||||
};
|
||||
static struct rt_page_head *rt_page_list;
|
||||
static struct rt_semaphore heap_sem;
|
||||
|
||||
void *rt_page_alloc(rt_size_t npages)
|
||||
{
|
||||
struct rt_page_head *b, *n;
|
||||
struct rt_page_head **prev;
|
||||
|
||||
if (npages == 0)
|
||||
return RT_NULL;
|
||||
|
||||
/* lock heap */
|
||||
rt_sem_take(&heap_sem, RT_WAITING_FOREVER);
|
||||
for (prev = &rt_page_list; (b = *prev) != RT_NULL; prev = &(b->next))
|
||||
{
|
||||
if (b->page > npages)
|
||||
{
|
||||
/* splite pages */
|
||||
n = b + npages;
|
||||
n->next = b->next;
|
||||
n->page = b->page - npages;
|
||||
*prev = n;
|
||||
break;
|
||||
}
|
||||
|
||||
if (b->page == npages)
|
||||
{
|
||||
/* this node fit, remove this node */
|
||||
*prev = b->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* unlock heap */
|
||||
rt_sem_release(&heap_sem);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
void rt_page_free(void *addr, rt_size_t npages)
|
||||
{
|
||||
struct rt_page_head *b, *n;
|
||||
struct rt_page_head **prev;
|
||||
|
||||
RT_ASSERT(addr != RT_NULL);
|
||||
RT_ASSERT((rt_uint32_t)addr % RT_MM_PAGE_SIZE == 0);
|
||||
RT_ASSERT(npages != 0);
|
||||
|
||||
n = (struct rt_page_head *)addr;
|
||||
|
||||
/* lock heap */
|
||||
rt_sem_take(&heap_sem, RT_WAITING_FOREVER);
|
||||
|
||||
for (prev = &rt_page_list; (b = *prev) != RT_NULL; prev = &(b->next))
|
||||
{
|
||||
RT_ASSERT(b->page > 0);
|
||||
RT_ASSERT(b > n || b + b->page <= n);
|
||||
|
||||
if (b + b->page == n)
|
||||
{
|
||||
if (b + (b->page += npages) == b->next)
|
||||
{
|
||||
b->page += b->next->page;
|
||||
b->next = b->next->next;
|
||||
}
|
||||
|
||||
goto _return;
|
||||
}
|
||||
|
||||
if (b == n + npages)
|
||||
{
|
||||
n->page = b->page + npages;
|
||||
n->next = b->next;
|
||||
*prev = n;
|
||||
|
||||
goto _return;
|
||||
}
|
||||
|
||||
if (b > n + npages)
|
||||
break;
|
||||
}
|
||||
|
||||
n->page = npages;
|
||||
n->next = b;
|
||||
*prev = n;
|
||||
|
||||
_return:
|
||||
/* unlock heap */
|
||||
rt_sem_release(&heap_sem);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the page allocator
|
||||
*/
|
||||
static void rt_page_init(void *addr, rt_size_t npages)
|
||||
{
|
||||
RT_ASSERT(addr != RT_NULL);
|
||||
RT_ASSERT(npages != 0);
|
||||
|
||||
rt_page_list = RT_NULL;
|
||||
rt_page_free(addr, npages);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup SystemInit
|
||||
*
|
||||
* This function will init system heap
|
||||
*
|
||||
* @param begin_addr the beginning address of system page
|
||||
* @param end_addr the end address of system page
|
||||
*/
|
||||
void rt_system_heap_init(void *begin_addr, void *end_addr)
|
||||
{
|
||||
rt_uint32_t limsize, npages;
|
||||
|
||||
RT_DEBUG_NOT_IN_INTERRUPT;
|
||||
|
||||
/* align begin and end addr to page */
|
||||
heap_start = RT_ALIGN((rt_uint32_t)begin_addr, RT_MM_PAGE_SIZE);
|
||||
heap_end = RT_ALIGN_DOWN((rt_uint32_t)end_addr, RT_MM_PAGE_SIZE);
|
||||
|
||||
if (heap_start >= heap_end)
|
||||
{
|
||||
rt_kprintf("rt_system_heap_init, wrong address[0x%x - 0x%x]\n",
|
||||
(rt_uint32_t)begin_addr, (rt_uint32_t)end_addr);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
limsize = heap_end - heap_start;
|
||||
npages = limsize / RT_MM_PAGE_SIZE;
|
||||
|
||||
/* initialize heap semaphore */
|
||||
rt_sem_init(&heap_sem, "heap", 1, RT_IPC_FLAG_FIFO);
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_SLAB, ("heap[0x%x - 0x%x], size 0x%x, 0x%x pages\n",
|
||||
heap_start, heap_end, limsize, npages));
|
||||
|
||||
/* init pages */
|
||||
rt_page_init((void *)heap_start, npages);
|
||||
|
||||
/* calculate zone size */
|
||||
zone_size = ZALLOC_MIN_ZONE_SIZE;
|
||||
while (zone_size < ZALLOC_MAX_ZONE_SIZE && (zone_size << 1) < (limsize / 1024))
|
||||
zone_size <<= 1;
|
||||
|
||||
zone_limit = zone_size / 4;
|
||||
if (zone_limit > ZALLOC_ZONE_LIMIT)
|
||||
zone_limit = ZALLOC_ZONE_LIMIT;
|
||||
|
||||
zone_page_cnt = zone_size / RT_MM_PAGE_SIZE;
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_SLAB, ("zone size 0x%x, zone page count 0x%x\n",
|
||||
zone_size, zone_page_cnt));
|
||||
|
||||
/* allocate memusage array */
|
||||
limsize = npages * sizeof(struct memusage);
|
||||
limsize = RT_ALIGN(limsize, RT_MM_PAGE_SIZE);
|
||||
memusage = rt_page_alloc(limsize / RT_MM_PAGE_SIZE);
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_SLAB, ("memusage 0x%x, size 0x%x\n",
|
||||
(rt_uint32_t)memusage, limsize));
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the zone index for the allocation request size and set the
|
||||
* allocation request size to that particular zone's chunk size.
|
||||
*/
|
||||
rt_inline int zoneindex(rt_size_t *bytes)
|
||||
{
|
||||
/* unsigned for shift opt */
|
||||
rt_uint32_t n = (rt_uint32_t)(*bytes);
|
||||
|
||||
if (n < 128)
|
||||
{
|
||||
*bytes = n = (n + 7) & ~7;
|
||||
|
||||
/* 8 byte chunks, 16 zones */
|
||||
return (n / 8 - 1);
|
||||
}
|
||||
if (n < 256)
|
||||
{
|
||||
*bytes = n = (n + 15) & ~15;
|
||||
|
||||
return (n / 16 + 7);
|
||||
}
|
||||
if (n < 8192)
|
||||
{
|
||||
if (n < 512)
|
||||
{
|
||||
*bytes = n = (n + 31) & ~31;
|
||||
|
||||
return (n / 32 + 15);
|
||||
}
|
||||
if (n < 1024)
|
||||
{
|
||||
*bytes = n = (n + 63) & ~63;
|
||||
|
||||
return (n / 64 + 23);
|
||||
}
|
||||
if (n < 2048)
|
||||
{
|
||||
*bytes = n = (n + 127) & ~127;
|
||||
|
||||
return (n / 128 + 31);
|
||||
}
|
||||
if (n < 4096)
|
||||
{
|
||||
*bytes = n = (n + 255) & ~255;
|
||||
|
||||
return (n / 256 + 39);
|
||||
}
|
||||
*bytes = n = (n + 511) & ~511;
|
||||
|
||||
return (n / 512 + 47);
|
||||
}
|
||||
if (n < 16384)
|
||||
{
|
||||
*bytes = n = (n + 1023) & ~1023;
|
||||
|
||||
return (n / 1024 + 55);
|
||||
}
|
||||
|
||||
rt_kprintf("Unexpected byte count %d", n);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @addtogroup MM
|
||||
*/
|
||||
|
||||
/**@{*/
|
||||
|
||||
/**
|
||||
* This function will allocate a block from system heap memory.
|
||||
* - If the nbytes is less than zero,
|
||||
* or
|
||||
* - If there is no nbytes sized memory valid in system,
|
||||
* the RT_NULL is returned.
|
||||
*
|
||||
* @param size the size of memory to be allocated
|
||||
*
|
||||
* @return the allocated memory
|
||||
*/
|
||||
void *rt_malloc(rt_size_t size)
|
||||
{
|
||||
slab_zone *z;
|
||||
rt_int32_t zi;
|
||||
slab_chunk *chunk;
|
||||
struct memusage *kup;
|
||||
|
||||
/* zero size, return RT_NULL */
|
||||
if (size == 0)
|
||||
return RT_NULL;
|
||||
|
||||
/*
|
||||
* Handle large allocations directly. There should not be very many of
|
||||
* these so performance is not a big issue.
|
||||
*/
|
||||
if (size >= zone_limit)
|
||||
{
|
||||
size = RT_ALIGN(size, RT_MM_PAGE_SIZE);
|
||||
|
||||
chunk = rt_page_alloc(size >> RT_MM_PAGE_BITS);
|
||||
if (chunk == RT_NULL)
|
||||
return RT_NULL;
|
||||
|
||||
/* set kup */
|
||||
kup = btokup(chunk);
|
||||
kup->type = PAGE_TYPE_LARGE;
|
||||
kup->size = size >> RT_MM_PAGE_BITS;
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_SLAB,
|
||||
("malloc a large memory 0x%x, page cnt %d, kup %d\n",
|
||||
size,
|
||||
size >> RT_MM_PAGE_BITS,
|
||||
((rt_uint32_t)chunk - heap_start) >> RT_MM_PAGE_BITS));
|
||||
|
||||
/* lock heap */
|
||||
rt_sem_take(&heap_sem, RT_WAITING_FOREVER);
|
||||
|
||||
#ifdef RT_MEM_STATS
|
||||
used_mem += size;
|
||||
if (used_mem > max_mem)
|
||||
max_mem = used_mem;
|
||||
#endif
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* lock heap */
|
||||
rt_sem_take(&heap_sem, RT_WAITING_FOREVER);
|
||||
|
||||
/*
|
||||
* Attempt to allocate out of an existing zone. First try the free list,
|
||||
* then allocate out of unallocated space. If we find a good zone move
|
||||
* it to the head of the list so later allocations find it quickly
|
||||
* (we might have thousands of zones in the list).
|
||||
*
|
||||
* Note: zoneindex() will panic of size is too large.
|
||||
*/
|
||||
zi = zoneindex(&size);
|
||||
RT_ASSERT(zi < NZONES);
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_SLAB, ("try to malloc 0x%x on zone: %d\n", size, zi));
|
||||
|
||||
if ((z = zone_array[zi]) != RT_NULL)
|
||||
{
|
||||
RT_ASSERT(z->z_nfree > 0);
|
||||
|
||||
/* Remove us from the zone_array[] when we become empty */
|
||||
if (--z->z_nfree == 0)
|
||||
{
|
||||
zone_array[zi] = z->z_next;
|
||||
z->z_next = RT_NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* No chunks are available but nfree said we had some memory, so
|
||||
* it must be available in the never-before-used-memory area
|
||||
* governed by uindex. The consequences are very serious if our zone
|
||||
* got corrupted so we use an explicit rt_kprintf rather then a KASSERT.
|
||||
*/
|
||||
if (z->z_uindex + 1 != z->z_nmax)
|
||||
{
|
||||
z->z_uindex = z->z_uindex + 1;
|
||||
chunk = (slab_chunk *)(z->z_baseptr + z->z_uindex * size);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* find on free chunk list */
|
||||
chunk = z->z_freechunk;
|
||||
|
||||
/* remove this chunk from list */
|
||||
z->z_freechunk = z->z_freechunk->c_next;
|
||||
}
|
||||
|
||||
#ifdef RT_MEM_STATS
|
||||
used_mem += z->z_chunksize;
|
||||
if (used_mem > max_mem)
|
||||
max_mem = used_mem;
|
||||
#endif
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* If all zones are exhausted we need to allocate a new zone for this
|
||||
* index.
|
||||
*
|
||||
* At least one subsystem, the tty code (see CROUND) expects power-of-2
|
||||
* allocations to be power-of-2 aligned. We maintain compatibility by
|
||||
* adjusting the base offset below.
|
||||
*/
|
||||
{
|
||||
rt_int32_t off;
|
||||
|
||||
if ((z = zone_free) != RT_NULL)
|
||||
{
|
||||
/* remove zone from free zone list */
|
||||
zone_free = z->z_next;
|
||||
-- zone_free_cnt;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* unlock heap, since page allocator will think about lock */
|
||||
rt_sem_release(&heap_sem);
|
||||
|
||||
/* allocate a zone from page */
|
||||
z = rt_page_alloc(zone_size / RT_MM_PAGE_SIZE);
|
||||
if (z == RT_NULL)
|
||||
{
|
||||
chunk = RT_NULL;
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
/* lock heap */
|
||||
rt_sem_take(&heap_sem, RT_WAITING_FOREVER);
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_SLAB, ("alloc a new zone: 0x%x\n",
|
||||
(rt_uint32_t)z));
|
||||
|
||||
/* set message usage */
|
||||
for (off = 0, kup = btokup(z); off < zone_page_cnt; off ++)
|
||||
{
|
||||
kup->type = PAGE_TYPE_SMALL;
|
||||
kup->size = off;
|
||||
|
||||
kup ++;
|
||||
}
|
||||
}
|
||||
|
||||
/* clear to zero */
|
||||
rt_memset(z, 0, sizeof(slab_zone));
|
||||
|
||||
/* offset of slab zone struct in zone */
|
||||
off = sizeof(slab_zone);
|
||||
|
||||
/*
|
||||
* Guarentee power-of-2 alignment for power-of-2-sized chunks.
|
||||
* Otherwise just 8-byte align the data.
|
||||
*/
|
||||
if ((size | (size - 1)) + 1 == (size << 1))
|
||||
off = (off + size - 1) & ~(size - 1);
|
||||
else
|
||||
off = (off + MIN_CHUNK_MASK) & ~MIN_CHUNK_MASK;
|
||||
|
||||
z->z_magic = ZALLOC_SLAB_MAGIC;
|
||||
z->z_zoneindex = zi;
|
||||
z->z_nmax = (zone_size - off) / size;
|
||||
z->z_nfree = z->z_nmax - 1;
|
||||
z->z_baseptr = (rt_uint8_t *)z + off;
|
||||
z->z_uindex = 0;
|
||||
z->z_chunksize = size;
|
||||
|
||||
chunk = (slab_chunk *)(z->z_baseptr + z->z_uindex * size);
|
||||
|
||||
/* link to zone array */
|
||||
z->z_next = zone_array[zi];
|
||||
zone_array[zi] = z;
|
||||
|
||||
#ifdef RT_MEM_STATS
|
||||
used_mem += z->z_chunksize;
|
||||
if (used_mem > max_mem)
|
||||
max_mem = used_mem;
|
||||
#endif
|
||||
}
|
||||
|
||||
done:
|
||||
rt_sem_release(&heap_sem);
|
||||
RT_OBJECT_HOOK_CALL(rt_malloc_hook, ((char *)chunk, size));
|
||||
|
||||
__exit:
|
||||
return chunk;
|
||||
}
|
||||
RTM_EXPORT(rt_malloc);
|
||||
|
||||
/**
|
||||
* This function will change the size of previously allocated memory block.
|
||||
*
|
||||
* @param ptr the previously allocated memory block
|
||||
* @param size the new size of memory block
|
||||
*
|
||||
* @return the allocated memory
|
||||
*/
|
||||
void *rt_realloc(void *ptr, rt_size_t size)
|
||||
{
|
||||
void *nptr;
|
||||
slab_zone *z;
|
||||
struct memusage *kup;
|
||||
|
||||
if (ptr == RT_NULL)
|
||||
return rt_malloc(size);
|
||||
if (size == 0)
|
||||
{
|
||||
rt_free(ptr);
|
||||
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the original allocation's zone. If the new request winds up
|
||||
* using the same chunk size we do not have to do anything.
|
||||
*/
|
||||
kup = btokup((rt_uint32_t)ptr & ~RT_MM_PAGE_MASK);
|
||||
if (kup->type == PAGE_TYPE_LARGE)
|
||||
{
|
||||
rt_size_t osize;
|
||||
|
||||
osize = kup->size << RT_MM_PAGE_BITS;
|
||||
if ((nptr = rt_malloc(size)) == RT_NULL)
|
||||
return RT_NULL;
|
||||
rt_memcpy(nptr, ptr, size > osize ? osize : size);
|
||||
rt_free(ptr);
|
||||
|
||||
return nptr;
|
||||
}
|
||||
else if (kup->type == PAGE_TYPE_SMALL)
|
||||
{
|
||||
z = (slab_zone *)(((rt_uint32_t)ptr & ~RT_MM_PAGE_MASK) -
|
||||
kup->size * RT_MM_PAGE_SIZE);
|
||||
RT_ASSERT(z->z_magic == ZALLOC_SLAB_MAGIC);
|
||||
|
||||
zoneindex(&size);
|
||||
if (z->z_chunksize == size)
|
||||
return (ptr); /* same chunk */
|
||||
|
||||
/*
|
||||
* Allocate memory for the new request size. Note that zoneindex has
|
||||
* already adjusted the request size to the appropriate chunk size, which
|
||||
* should optimize our bcopy(). Then copy and return the new pointer.
|
||||
*/
|
||||
if ((nptr = rt_malloc(size)) == RT_NULL)
|
||||
return RT_NULL;
|
||||
|
||||
rt_memcpy(nptr, ptr, size > z->z_chunksize ? z->z_chunksize : size);
|
||||
rt_free(ptr);
|
||||
|
||||
return nptr;
|
||||
}
|
||||
|
||||
return RT_NULL;
|
||||
}
|
||||
RTM_EXPORT(rt_realloc);
|
||||
|
||||
/**
|
||||
* This function will contiguously allocate enough space for count objects
|
||||
* that are size bytes of memory each and returns a pointer to the allocated
|
||||
* memory.
|
||||
*
|
||||
* The allocated memory is filled with bytes of value zero.
|
||||
*
|
||||
* @param count number of objects to allocate
|
||||
* @param size size of the objects to allocate
|
||||
*
|
||||
* @return pointer to allocated memory / NULL pointer if there is an error
|
||||
*/
|
||||
void *rt_calloc(rt_size_t count, rt_size_t size)
|
||||
{
|
||||
void *p;
|
||||
|
||||
/* allocate 'count' objects of size 'size' */
|
||||
p = rt_malloc(count * size);
|
||||
|
||||
/* zero the memory */
|
||||
if (p)
|
||||
rt_memset(p, 0, count * size);
|
||||
|
||||
return p;
|
||||
}
|
||||
RTM_EXPORT(rt_calloc);
|
||||
|
||||
/**
|
||||
* This function will release the previous allocated memory block by rt_malloc.
|
||||
* The released memory block is taken back to system heap.
|
||||
*
|
||||
* @param ptr the address of memory which will be released
|
||||
*/
|
||||
void rt_free(void *ptr)
|
||||
{
|
||||
slab_zone *z;
|
||||
slab_chunk *chunk;
|
||||
struct memusage *kup;
|
||||
|
||||
/* free a RT_NULL pointer */
|
||||
if (ptr == RT_NULL)
|
||||
return ;
|
||||
|
||||
RT_OBJECT_HOOK_CALL(rt_free_hook, (ptr));
|
||||
|
||||
/* get memory usage */
|
||||
#if RT_DEBUG_SLAB
|
||||
{
|
||||
rt_uint32_t addr = ((rt_uint32_t)ptr & ~RT_MM_PAGE_MASK);
|
||||
RT_DEBUG_LOG(RT_DEBUG_SLAB,
|
||||
("free a memory 0x%x and align to 0x%x, kup index %d\n",
|
||||
(rt_uint32_t)ptr,
|
||||
(rt_uint32_t)addr,
|
||||
((rt_uint32_t)(addr) - heap_start) >> RT_MM_PAGE_BITS));
|
||||
}
|
||||
#endif
|
||||
|
||||
kup = btokup((rt_uint32_t)ptr & ~RT_MM_PAGE_MASK);
|
||||
/* release large allocation */
|
||||
if (kup->type == PAGE_TYPE_LARGE)
|
||||
{
|
||||
rt_uint32_t size;
|
||||
|
||||
/* lock heap */
|
||||
rt_sem_take(&heap_sem, RT_WAITING_FOREVER);
|
||||
/* clear page counter */
|
||||
size = kup->size;
|
||||
kup->size = 0;
|
||||
|
||||
#ifdef RT_MEM_STATS
|
||||
used_mem -= size * RT_MM_PAGE_SIZE;
|
||||
#endif
|
||||
rt_sem_release(&heap_sem);
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_SLAB,
|
||||
("free large memory block 0x%x, page count %d\n",
|
||||
(rt_uint32_t)ptr, size));
|
||||
|
||||
/* free this page */
|
||||
rt_page_free(ptr, size);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* lock heap */
|
||||
rt_sem_take(&heap_sem, RT_WAITING_FOREVER);
|
||||
|
||||
/* zone case. get out zone. */
|
||||
z = (slab_zone *)(((rt_uint32_t)ptr & ~RT_MM_PAGE_MASK) -
|
||||
kup->size * RT_MM_PAGE_SIZE);
|
||||
RT_ASSERT(z->z_magic == ZALLOC_SLAB_MAGIC);
|
||||
|
||||
chunk = (slab_chunk *)ptr;
|
||||
chunk->c_next = z->z_freechunk;
|
||||
z->z_freechunk = chunk;
|
||||
|
||||
#ifdef RT_MEM_STATS
|
||||
used_mem -= z->z_chunksize;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Bump the number of free chunks. If it becomes non-zero the zone
|
||||
* must be added back onto the appropriate list.
|
||||
*/
|
||||
if (z->z_nfree++ == 0)
|
||||
{
|
||||
z->z_next = zone_array[z->z_zoneindex];
|
||||
zone_array[z->z_zoneindex] = z;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the zone becomes totally free, and there are other zones we
|
||||
* can allocate from, move this zone to the FreeZones list. Since
|
||||
* this code can be called from an IPI callback, do *NOT* try to mess
|
||||
* with kernel_map here. Hysteresis will be performed at malloc() time.
|
||||
*/
|
||||
if (z->z_nfree == z->z_nmax &&
|
||||
(z->z_next || zone_array[z->z_zoneindex] != z))
|
||||
{
|
||||
slab_zone **pz;
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_SLAB, ("free zone 0x%x\n",
|
||||
(rt_uint32_t)z, z->z_zoneindex));
|
||||
|
||||
/* remove zone from zone array list */
|
||||
for (pz = &zone_array[z->z_zoneindex]; z != *pz; pz = &(*pz)->z_next)
|
||||
;
|
||||
*pz = z->z_next;
|
||||
|
||||
/* reset zone */
|
||||
z->z_magic = -1;
|
||||
|
||||
/* insert to free zone list */
|
||||
z->z_next = zone_free;
|
||||
zone_free = z;
|
||||
|
||||
++ zone_free_cnt;
|
||||
|
||||
/* release zone to page allocator */
|
||||
if (zone_free_cnt > ZONE_RELEASE_THRESH)
|
||||
{
|
||||
register rt_base_t i;
|
||||
|
||||
z = zone_free;
|
||||
zone_free = z->z_next;
|
||||
-- zone_free_cnt;
|
||||
|
||||
/* set message usage */
|
||||
for (i = 0, kup = btokup(z); i < zone_page_cnt; i ++)
|
||||
{
|
||||
kup->type = PAGE_TYPE_FREE;
|
||||
kup->size = 0;
|
||||
kup ++;
|
||||
}
|
||||
|
||||
/* unlock heap */
|
||||
rt_sem_release(&heap_sem);
|
||||
|
||||
/* release pages */
|
||||
rt_page_free(z, zone_size / RT_MM_PAGE_SIZE);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* unlock heap */
|
||||
rt_sem_release(&heap_sem);
|
||||
}
|
||||
RTM_EXPORT(rt_free);
|
||||
|
||||
#ifdef RT_MEM_STATS
|
||||
void rt_memory_info(rt_uint32_t *total,
|
||||
rt_uint32_t *used,
|
||||
rt_uint32_t *max_used)
|
||||
{
|
||||
if (total != RT_NULL)
|
||||
*total = heap_end - heap_start;
|
||||
|
||||
if (used != RT_NULL)
|
||||
*used = used_mem;
|
||||
|
||||
if (max_used != RT_NULL)
|
||||
*max_used = max_mem;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_FINSH
|
||||
#include <finsh.h>
|
||||
|
||||
void list_mem(void)
|
||||
{
|
||||
rt_kprintf("total memory: %d\n", heap_end - heap_start);
|
||||
rt_kprintf("used memory : %d\n", used_mem);
|
||||
rt_kprintf("maximum allocated memory: %d\n", max_mem);
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT(list_mem, list memory usage information)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**@}*/
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,802 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2006-03-28 Bernard first version
|
||||
* 2006-04-29 Bernard implement thread timer
|
||||
* 2006-04-30 Bernard added THREAD_DEBUG
|
||||
* 2006-05-27 Bernard fixed the rt_thread_yield bug
|
||||
* 2006-06-03 Bernard fixed the thread timer init bug
|
||||
* 2006-08-10 Bernard fixed the timer bug in thread_sleep
|
||||
* 2006-09-03 Bernard changed rt_timer_delete to rt_timer_detach
|
||||
* 2006-09-03 Bernard implement rt_thread_detach
|
||||
* 2008-02-16 Bernard fixed the rt_thread_timeout bug
|
||||
* 2010-03-21 Bernard change the errno of rt_thread_delay/sleep to
|
||||
* RT_EOK.
|
||||
* 2010-11-10 Bernard add cleanup callback function in thread exit.
|
||||
* 2011-09-01 Bernard fixed rt_thread_exit issue when the current
|
||||
* thread preempted, which reported by Jiaxing Lee.
|
||||
* 2011-09-08 Bernard fixed the scheduling issue in rt_thread_startup.
|
||||
* 2012-12-29 Bernard fixed compiling warning.
|
||||
* 2016-08-09 ArdaFu add thread suspend and resume hook.
|
||||
* 2017-04-10 armink fixed the rt_thread_delete and rt_thread_detach
|
||||
bug when thread has not startup.
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rthw.h>
|
||||
|
||||
extern rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX];
|
||||
extern struct rt_thread *rt_current_thread;
|
||||
extern rt_list_t rt_thread_defunct;
|
||||
|
||||
#ifdef RT_USING_HOOK
|
||||
|
||||
static void (*rt_thread_suspend_hook)(rt_thread_t thread);
|
||||
static void (*rt_thread_resume_hook) (rt_thread_t thread);
|
||||
static void (*rt_thread_inited_hook) (rt_thread_t thread);
|
||||
|
||||
/**
|
||||
* @ingroup Hook
|
||||
* This function sets a hook function when the system suspend a thread.
|
||||
*
|
||||
* @param hook the specified hook function
|
||||
*
|
||||
* @note the hook function must be simple and never be blocked or suspend.
|
||||
*/
|
||||
void rt_thread_suspend_sethook(void (*hook)(rt_thread_t thread))
|
||||
{
|
||||
rt_thread_suspend_hook = hook;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup Hook
|
||||
* This function sets a hook function when the system resume a thread.
|
||||
*
|
||||
* @param hook the specified hook function
|
||||
*
|
||||
* @note the hook function must be simple and never be blocked or suspend.
|
||||
*/
|
||||
void rt_thread_resume_sethook(void (*hook)(rt_thread_t thread))
|
||||
{
|
||||
rt_thread_resume_hook = hook;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup Hook
|
||||
* This function sets a hook function when a thread is initialized.
|
||||
*
|
||||
* @param hook the specified hook function
|
||||
*/
|
||||
void rt_thread_inited_sethook(void (*hook)(rt_thread_t thread))
|
||||
{
|
||||
rt_thread_inited_hook = hook;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void rt_thread_exit(void)
|
||||
{
|
||||
struct rt_thread *thread;
|
||||
register rt_base_t level;
|
||||
|
||||
/* get current thread */
|
||||
thread = rt_current_thread;
|
||||
|
||||
/* disable interrupt */
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
/* remove from schedule */
|
||||
rt_schedule_remove_thread(thread);
|
||||
/* change stat */
|
||||
thread->stat = RT_THREAD_CLOSE;
|
||||
|
||||
/* remove it from timer list */
|
||||
rt_timer_detach(&thread->thread_timer);
|
||||
|
||||
if ((rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE) &&
|
||||
thread->cleanup == RT_NULL)
|
||||
{
|
||||
rt_object_detach((rt_object_t)thread);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* insert to defunct thread list */
|
||||
rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));
|
||||
}
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
/* switch to next task */
|
||||
rt_schedule();
|
||||
}
|
||||
|
||||
static rt_err_t _rt_thread_init(struct rt_thread *thread,
|
||||
const char *name,
|
||||
void (*entry)(void *parameter),
|
||||
void *parameter,
|
||||
void *stack_start,
|
||||
rt_uint32_t stack_size,
|
||||
rt_uint8_t priority,
|
||||
rt_uint32_t tick)
|
||||
{
|
||||
/* init thread list */
|
||||
rt_list_init(&(thread->tlist));
|
||||
|
||||
thread->entry = (void *)entry;
|
||||
thread->parameter = parameter;
|
||||
|
||||
/* stack init */
|
||||
thread->stack_addr = stack_start;
|
||||
thread->stack_size = stack_size;
|
||||
|
||||
/* init thread stack */
|
||||
rt_memset(thread->stack_addr, '#', thread->stack_size);
|
||||
#ifdef ARCH_CPU_STACK_GROWS_UPWARD
|
||||
thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter,
|
||||
(void *)((char *)thread->stack_addr),
|
||||
(void *)rt_thread_exit);
|
||||
#else
|
||||
thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter,
|
||||
(void *)((char *)thread->stack_addr + thread->stack_size - 4),
|
||||
(void *)rt_thread_exit);
|
||||
#endif
|
||||
|
||||
/* priority init */
|
||||
RT_ASSERT(priority < RT_THREAD_PRIORITY_MAX);
|
||||
thread->init_priority = priority;
|
||||
thread->current_priority = priority;
|
||||
|
||||
thread->number_mask = 0;
|
||||
#if RT_THREAD_PRIORITY_MAX > 32
|
||||
thread->number = 0;
|
||||
thread->high_mask = 0;
|
||||
#endif
|
||||
|
||||
/* tick init */
|
||||
thread->init_tick = tick;
|
||||
thread->remaining_tick = tick;
|
||||
|
||||
/* error and flags */
|
||||
thread->error = RT_EOK;
|
||||
thread->stat = RT_THREAD_INIT;
|
||||
|
||||
/* initialize cleanup function and user data */
|
||||
thread->cleanup = 0;
|
||||
thread->user_data = 0;
|
||||
|
||||
/* init thread timer */
|
||||
rt_timer_init(&(thread->thread_timer),
|
||||
thread->name,
|
||||
rt_thread_timeout,
|
||||
thread,
|
||||
0,
|
||||
RT_TIMER_FLAG_ONE_SHOT);
|
||||
|
||||
/* initialize signal */
|
||||
#ifdef RT_USING_SIGNALS
|
||||
thread->sig_mask = 0x00;
|
||||
thread->sig_pending = 0x00;
|
||||
|
||||
thread->sig_ret = RT_NULL;
|
||||
thread->sig_vectors = RT_NULL;
|
||||
thread->si_list = RT_NULL;
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_LWP
|
||||
thread->lwp = RT_NULL;
|
||||
#endif
|
||||
|
||||
RT_OBJECT_HOOK_CALL(rt_thread_inited_hook, (thread));
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @addtogroup Thread
|
||||
*/
|
||||
|
||||
/**@{*/
|
||||
|
||||
/**
|
||||
* This function will initialize a thread, normally it's used to initialize a
|
||||
* static thread object.
|
||||
*
|
||||
* @param thread the static thread object
|
||||
* @param name the name of thread, which shall be unique
|
||||
* @param entry the entry function of thread
|
||||
* @param parameter the parameter of thread enter function
|
||||
* @param stack_start the start address of thread stack
|
||||
* @param stack_size the size of thread stack
|
||||
* @param priority the priority of thread
|
||||
* @param tick the time slice if there are same priority thread
|
||||
*
|
||||
* @return the operation status, RT_EOK on OK, -RT_ERROR on error
|
||||
*/
|
||||
rt_err_t rt_thread_init(struct rt_thread *thread,
|
||||
const char *name,
|
||||
void (*entry)(void *parameter),
|
||||
void *parameter,
|
||||
void *stack_start,
|
||||
rt_uint32_t stack_size,
|
||||
rt_uint8_t priority,
|
||||
rt_uint32_t tick)
|
||||
{
|
||||
/* thread check */
|
||||
RT_ASSERT(thread != RT_NULL);
|
||||
RT_ASSERT(stack_start != RT_NULL);
|
||||
|
||||
/* init thread object */
|
||||
rt_object_init((rt_object_t)thread, RT_Object_Class_Thread, name);
|
||||
|
||||
return _rt_thread_init(thread,
|
||||
name,
|
||||
entry,
|
||||
parameter,
|
||||
stack_start,
|
||||
stack_size,
|
||||
priority,
|
||||
tick);
|
||||
}
|
||||
RTM_EXPORT(rt_thread_init);
|
||||
|
||||
/**
|
||||
* This function will return self thread object
|
||||
*
|
||||
* @return the self thread object
|
||||
*/
|
||||
rt_thread_t rt_thread_self(void)
|
||||
{
|
||||
return rt_current_thread;
|
||||
}
|
||||
RTM_EXPORT(rt_thread_self);
|
||||
|
||||
/**
|
||||
* This function will start a thread and put it to system ready queue
|
||||
*
|
||||
* @param thread the thread to be started
|
||||
*
|
||||
* @return the operation status, RT_EOK on OK, -RT_ERROR on error
|
||||
*/
|
||||
rt_err_t rt_thread_startup(rt_thread_t thread)
|
||||
{
|
||||
/* thread check */
|
||||
RT_ASSERT(thread != RT_NULL);
|
||||
RT_ASSERT((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_INIT);
|
||||
RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
|
||||
|
||||
/* set current priority to init priority */
|
||||
thread->current_priority = thread->init_priority;
|
||||
|
||||
/* calculate priority attribute */
|
||||
#if RT_THREAD_PRIORITY_MAX > 32
|
||||
thread->number = thread->current_priority >> 3; /* 5bit */
|
||||
thread->number_mask = 1L << thread->number;
|
||||
thread->high_mask = 1L << (thread->current_priority & 0x07); /* 3bit */
|
||||
#else
|
||||
thread->number_mask = 1L << thread->current_priority;
|
||||
#endif
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_THREAD, ("startup a thread:%s with priority:%d\n",
|
||||
thread->name, thread->init_priority));
|
||||
/* change thread stat */
|
||||
thread->stat = RT_THREAD_SUSPEND;
|
||||
/* then resume it */
|
||||
rt_thread_resume(thread);
|
||||
if (rt_thread_self() != RT_NULL)
|
||||
{
|
||||
/* do a scheduling */
|
||||
rt_schedule();
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
RTM_EXPORT(rt_thread_startup);
|
||||
|
||||
/**
|
||||
* This function will detach a thread. The thread object will be removed from
|
||||
* thread queue and detached/deleted from system object management.
|
||||
*
|
||||
* @param thread the thread to be deleted
|
||||
*
|
||||
* @return the operation status, RT_EOK on OK, -RT_ERROR on error
|
||||
*/
|
||||
rt_err_t rt_thread_detach(rt_thread_t thread)
|
||||
{
|
||||
rt_base_t lock;
|
||||
|
||||
/* thread check */
|
||||
RT_ASSERT(thread != RT_NULL);
|
||||
RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
|
||||
RT_ASSERT(rt_object_is_systemobject((rt_object_t)thread));
|
||||
|
||||
if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_INIT)
|
||||
{
|
||||
/* remove from schedule */
|
||||
rt_schedule_remove_thread(thread);
|
||||
}
|
||||
|
||||
/* release thread timer */
|
||||
rt_timer_detach(&(thread->thread_timer));
|
||||
|
||||
/* change stat */
|
||||
thread->stat = RT_THREAD_CLOSE;
|
||||
|
||||
if ((rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE) &&
|
||||
thread->cleanup == RT_NULL)
|
||||
{
|
||||
rt_object_detach((rt_object_t)thread);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* disable interrupt */
|
||||
lock = rt_hw_interrupt_disable();
|
||||
/* insert to defunct thread list */
|
||||
rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(lock);
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
RTM_EXPORT(rt_thread_detach);
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
/**
|
||||
* This function will create a thread object and allocate thread object memory
|
||||
* and stack.
|
||||
*
|
||||
* @param name the name of thread, which shall be unique
|
||||
* @param entry the entry function of thread
|
||||
* @param parameter the parameter of thread enter function
|
||||
* @param stack_size the size of thread stack
|
||||
* @param priority the priority of thread
|
||||
* @param tick the time slice if there are same priority thread
|
||||
*
|
||||
* @return the created thread object
|
||||
*/
|
||||
rt_thread_t rt_thread_create(const char *name,
|
||||
void (*entry)(void *parameter),
|
||||
void *parameter,
|
||||
rt_uint32_t stack_size,
|
||||
rt_uint8_t priority,
|
||||
rt_uint32_t tick)
|
||||
{
|
||||
struct rt_thread *thread;
|
||||
void *stack_start;
|
||||
|
||||
thread = (struct rt_thread *)rt_object_allocate(RT_Object_Class_Thread,
|
||||
name);
|
||||
if (thread == RT_NULL)
|
||||
return RT_NULL;
|
||||
|
||||
stack_start = (void *)RT_KERNEL_MALLOC(stack_size);
|
||||
if (stack_start == RT_NULL)
|
||||
{
|
||||
/* allocate stack failure */
|
||||
rt_object_delete((rt_object_t)thread);
|
||||
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
_rt_thread_init(thread,
|
||||
name,
|
||||
entry,
|
||||
parameter,
|
||||
stack_start,
|
||||
stack_size,
|
||||
priority,
|
||||
tick);
|
||||
|
||||
return thread;
|
||||
}
|
||||
RTM_EXPORT(rt_thread_create);
|
||||
|
||||
/**
|
||||
* This function will delete a thread. The thread object will be removed from
|
||||
* thread queue and deleted from system object management in the idle thread.
|
||||
*
|
||||
* @param thread the thread to be deleted
|
||||
*
|
||||
* @return the operation status, RT_EOK on OK, -RT_ERROR on error
|
||||
*/
|
||||
rt_err_t rt_thread_delete(rt_thread_t thread)
|
||||
{
|
||||
rt_base_t lock;
|
||||
|
||||
/* thread check */
|
||||
RT_ASSERT(thread != RT_NULL);
|
||||
RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
|
||||
RT_ASSERT(rt_object_is_systemobject((rt_object_t)thread) == RT_FALSE);
|
||||
|
||||
if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_INIT)
|
||||
{
|
||||
/* remove from schedule */
|
||||
rt_schedule_remove_thread(thread);
|
||||
}
|
||||
|
||||
/* release thread timer */
|
||||
rt_timer_detach(&(thread->thread_timer));
|
||||
|
||||
/* change stat */
|
||||
thread->stat = RT_THREAD_CLOSE;
|
||||
|
||||
/* disable interrupt */
|
||||
lock = rt_hw_interrupt_disable();
|
||||
|
||||
/* insert to defunct thread list */
|
||||
rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(lock);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
RTM_EXPORT(rt_thread_delete);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This function will let current thread yield processor, and scheduler will
|
||||
* choose a highest thread to run. After yield processor, the current thread
|
||||
* is still in READY state.
|
||||
*
|
||||
* @return RT_EOK
|
||||
*/
|
||||
rt_err_t rt_thread_yield(void)
|
||||
{
|
||||
register rt_base_t level;
|
||||
struct rt_thread *thread;
|
||||
|
||||
/* disable interrupt */
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
/* set to current thread */
|
||||
thread = rt_current_thread;
|
||||
|
||||
/* if the thread stat is READY and on ready queue list */
|
||||
if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_READY &&
|
||||
thread->tlist.next != thread->tlist.prev)
|
||||
{
|
||||
/* remove thread from thread list */
|
||||
rt_list_remove(&(thread->tlist));
|
||||
|
||||
/* put thread to end of ready queue */
|
||||
rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),
|
||||
&(thread->tlist));
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
rt_schedule();
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
RTM_EXPORT(rt_thread_yield);
|
||||
|
||||
/**
|
||||
* This function will let current thread sleep for some ticks.
|
||||
*
|
||||
* @param tick the sleep ticks
|
||||
*
|
||||
* @return RT_EOK
|
||||
*/
|
||||
rt_err_t rt_thread_sleep(rt_tick_t tick)
|
||||
{
|
||||
register rt_base_t temp;
|
||||
struct rt_thread *thread;
|
||||
|
||||
/* disable interrupt */
|
||||
temp = rt_hw_interrupt_disable();
|
||||
/* set to current thread */
|
||||
thread = rt_current_thread;
|
||||
RT_ASSERT(thread != RT_NULL);
|
||||
RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
|
||||
|
||||
/* suspend thread */
|
||||
rt_thread_suspend(thread);
|
||||
|
||||
/* reset the timeout of thread timer and start it */
|
||||
rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &tick);
|
||||
rt_timer_start(&(thread->thread_timer));
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(temp);
|
||||
|
||||
rt_schedule();
|
||||
|
||||
/* clear error number of this thread to RT_EOK */
|
||||
if (thread->error == -RT_ETIMEOUT)
|
||||
thread->error = RT_EOK;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will let current thread delay for some ticks.
|
||||
*
|
||||
* @param tick the delay ticks
|
||||
*
|
||||
* @return RT_EOK
|
||||
*/
|
||||
rt_err_t rt_thread_delay(rt_tick_t tick)
|
||||
{
|
||||
return rt_thread_sleep(tick);
|
||||
}
|
||||
RTM_EXPORT(rt_thread_delay);
|
||||
|
||||
/**
|
||||
* This function will let current thread delay for some milliseconds.
|
||||
*
|
||||
* @param tick the delay time
|
||||
*
|
||||
* @return RT_EOK
|
||||
*/
|
||||
rt_err_t rt_thread_mdelay(rt_int32_t ms)
|
||||
{
|
||||
rt_tick_t tick;
|
||||
|
||||
tick = rt_tick_from_millisecond(ms);
|
||||
|
||||
return rt_thread_sleep(tick);
|
||||
}
|
||||
RTM_EXPORT(rt_thread_mdelay);
|
||||
|
||||
/**
|
||||
* This function will control thread behaviors according to control command.
|
||||
*
|
||||
* @param thread the specified thread to be controlled
|
||||
* @param cmd the control command, which includes
|
||||
* RT_THREAD_CTRL_CHANGE_PRIORITY for changing priority level of thread;
|
||||
* RT_THREAD_CTRL_STARTUP for starting a thread;
|
||||
* RT_THREAD_CTRL_CLOSE for delete a thread.
|
||||
* @param arg the argument of control command
|
||||
*
|
||||
* @return RT_EOK
|
||||
*/
|
||||
rt_err_t rt_thread_control(rt_thread_t thread, int cmd, void *arg)
|
||||
{
|
||||
register rt_base_t temp;
|
||||
|
||||
/* thread check */
|
||||
RT_ASSERT(thread != RT_NULL);
|
||||
RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case RT_THREAD_CTRL_CHANGE_PRIORITY:
|
||||
/* disable interrupt */
|
||||
temp = rt_hw_interrupt_disable();
|
||||
|
||||
/* for ready thread, change queue */
|
||||
if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_READY)
|
||||
{
|
||||
/* remove thread from schedule queue first */
|
||||
rt_schedule_remove_thread(thread);
|
||||
|
||||
/* change thread priority */
|
||||
thread->current_priority = *(rt_uint8_t *)arg;
|
||||
|
||||
/* recalculate priority attribute */
|
||||
#if RT_THREAD_PRIORITY_MAX > 32
|
||||
thread->number = thread->current_priority >> 3; /* 5bit */
|
||||
thread->number_mask = 1 << thread->number;
|
||||
thread->high_mask = 1 << (thread->current_priority & 0x07); /* 3bit */
|
||||
#else
|
||||
thread->number_mask = 1 << thread->current_priority;
|
||||
#endif
|
||||
|
||||
/* insert thread to schedule queue again */
|
||||
rt_schedule_insert_thread(thread);
|
||||
}
|
||||
else
|
||||
{
|
||||
thread->current_priority = *(rt_uint8_t *)arg;
|
||||
|
||||
/* recalculate priority attribute */
|
||||
#if RT_THREAD_PRIORITY_MAX > 32
|
||||
thread->number = thread->current_priority >> 3; /* 5bit */
|
||||
thread->number_mask = 1 << thread->number;
|
||||
thread->high_mask = 1 << (thread->current_priority & 0x07); /* 3bit */
|
||||
#else
|
||||
thread->number_mask = 1 << thread->current_priority;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(temp);
|
||||
break;
|
||||
|
||||
case RT_THREAD_CTRL_STARTUP:
|
||||
return rt_thread_startup(thread);
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
case RT_THREAD_CTRL_CLOSE:
|
||||
return rt_thread_delete(thread);
|
||||
#endif
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
RTM_EXPORT(rt_thread_control);
|
||||
|
||||
/**
|
||||
* This function will suspend the specified thread.
|
||||
*
|
||||
* @param thread the thread to be suspended
|
||||
*
|
||||
* @return the operation status, RT_EOK on OK, -RT_ERROR on error
|
||||
*
|
||||
* @note if suspend self thread, after this function call, the
|
||||
* rt_schedule() must be invoked.
|
||||
*/
|
||||
rt_err_t rt_thread_suspend(rt_thread_t thread)
|
||||
{
|
||||
register rt_base_t temp;
|
||||
|
||||
/* thread check */
|
||||
RT_ASSERT(thread != RT_NULL);
|
||||
RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread suspend: %s\n", thread->name));
|
||||
|
||||
if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_READY)
|
||||
{
|
||||
RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread suspend: thread disorder, 0x%2x\n",
|
||||
thread->stat));
|
||||
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
/* disable interrupt */
|
||||
temp = rt_hw_interrupt_disable();
|
||||
|
||||
/* change thread stat */
|
||||
thread->stat = RT_THREAD_SUSPEND | (thread->stat & ~RT_THREAD_STAT_MASK);
|
||||
rt_schedule_remove_thread(thread);
|
||||
|
||||
/* stop thread timer anyway */
|
||||
rt_timer_stop(&(thread->thread_timer));
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(temp);
|
||||
|
||||
RT_OBJECT_HOOK_CALL(rt_thread_suspend_hook, (thread));
|
||||
return RT_EOK;
|
||||
}
|
||||
RTM_EXPORT(rt_thread_suspend);
|
||||
|
||||
/**
|
||||
* This function will resume a thread and put it to system ready queue.
|
||||
*
|
||||
* @param thread the thread to be resumed
|
||||
*
|
||||
* @return the operation status, RT_EOK on OK, -RT_ERROR on error
|
||||
*/
|
||||
rt_err_t rt_thread_resume(rt_thread_t thread)
|
||||
{
|
||||
register rt_base_t temp;
|
||||
|
||||
/* thread check */
|
||||
RT_ASSERT(thread != RT_NULL);
|
||||
RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread resume: %s\n", thread->name));
|
||||
|
||||
if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_SUSPEND)
|
||||
{
|
||||
RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread resume: thread disorder, %d\n",
|
||||
thread->stat));
|
||||
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
/* disable interrupt */
|
||||
temp = rt_hw_interrupt_disable();
|
||||
|
||||
/* remove from suspend list */
|
||||
rt_list_remove(&(thread->tlist));
|
||||
|
||||
rt_timer_stop(&thread->thread_timer);
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(temp);
|
||||
|
||||
/* insert to schedule ready list */
|
||||
rt_schedule_insert_thread(thread);
|
||||
|
||||
RT_OBJECT_HOOK_CALL(rt_thread_resume_hook, (thread));
|
||||
return RT_EOK;
|
||||
}
|
||||
RTM_EXPORT(rt_thread_resume);
|
||||
|
||||
/**
|
||||
* This function is the timeout function for thread, normally which is invoked
|
||||
* when thread is timeout to wait some resource.
|
||||
*
|
||||
* @param parameter the parameter of thread timeout function
|
||||
*/
|
||||
void rt_thread_timeout(void *parameter)
|
||||
{
|
||||
struct rt_thread *thread;
|
||||
|
||||
thread = (struct rt_thread *)parameter;
|
||||
|
||||
/* thread check */
|
||||
RT_ASSERT(thread != RT_NULL);
|
||||
RT_ASSERT((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND);
|
||||
RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
|
||||
|
||||
/* set error number */
|
||||
thread->error = -RT_ETIMEOUT;
|
||||
|
||||
/* remove from suspend list */
|
||||
rt_list_remove(&(thread->tlist));
|
||||
|
||||
/* insert to schedule ready list */
|
||||
rt_schedule_insert_thread(thread);
|
||||
|
||||
/* do schedule */
|
||||
rt_schedule();
|
||||
}
|
||||
RTM_EXPORT(rt_thread_timeout);
|
||||
|
||||
/**
|
||||
* This function will find the specified thread.
|
||||
*
|
||||
* @param name the name of thread finding
|
||||
*
|
||||
* @return the found thread
|
||||
*
|
||||
* @note please don't invoke this function in interrupt status.
|
||||
*/
|
||||
rt_thread_t rt_thread_find(char *name)
|
||||
{
|
||||
struct rt_object_information *information;
|
||||
struct rt_object *object;
|
||||
struct rt_list_node *node;
|
||||
|
||||
/* enter critical */
|
||||
if (rt_thread_self() != RT_NULL)
|
||||
rt_enter_critical();
|
||||
|
||||
/* try to find device object */
|
||||
information = rt_object_get_information(RT_Object_Class_Thread);
|
||||
RT_ASSERT(information != RT_NULL);
|
||||
for (node = information->object_list.next;
|
||||
node != &(information->object_list);
|
||||
node = node->next)
|
||||
{
|
||||
object = rt_list_entry(node, struct rt_object, list);
|
||||
if (rt_strncmp(object->name, name, RT_NAME_MAX) == 0)
|
||||
{
|
||||
/* leave critical */
|
||||
if (rt_thread_self() != RT_NULL)
|
||||
rt_exit_critical();
|
||||
|
||||
return (rt_thread_t)object;
|
||||
}
|
||||
}
|
||||
|
||||
/* leave critical */
|
||||
if (rt_thread_self() != RT_NULL)
|
||||
rt_exit_critical();
|
||||
|
||||
/* not found */
|
||||
return RT_NULL;
|
||||
}
|
||||
RTM_EXPORT(rt_thread_find);
|
||||
|
||||
/**@}*/
|
||||
@@ -0,0 +1,721 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2006-03-12 Bernard first version
|
||||
* 2006-04-29 Bernard implement thread timer
|
||||
* 2006-06-04 Bernard implement rt_timer_control
|
||||
* 2006-08-10 Bernard fix the periodic timer bug
|
||||
* 2006-09-03 Bernard implement rt_timer_detach
|
||||
* 2009-11-11 LiJin add soft timer
|
||||
* 2010-05-12 Bernard fix the timer check bug.
|
||||
* 2010-11-02 Charlie re-implement tick overflow issue
|
||||
* 2012-12-15 Bernard fix the next timeout issue in soft timer
|
||||
* 2014-07-12 Bernard does not lock scheduler when invoking soft-timer
|
||||
* timeout function.
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rthw.h>
|
||||
|
||||
/* hard timer list */
|
||||
static rt_list_t rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL];
|
||||
|
||||
#ifdef RT_USING_TIMER_SOFT
|
||||
#ifndef RT_TIMER_THREAD_STACK_SIZE
|
||||
#define RT_TIMER_THREAD_STACK_SIZE 512
|
||||
#endif
|
||||
|
||||
#ifndef RT_TIMER_THREAD_PRIO
|
||||
#define RT_TIMER_THREAD_PRIO 0
|
||||
#endif
|
||||
|
||||
/* soft timer list */
|
||||
static rt_list_t rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL];
|
||||
static struct rt_thread timer_thread;
|
||||
ALIGN(RT_ALIGN_SIZE)
|
||||
static rt_uint8_t timer_thread_stack[RT_TIMER_THREAD_STACK_SIZE];
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_HOOK
|
||||
extern void (*rt_object_take_hook)(struct rt_object *object);
|
||||
extern void (*rt_object_put_hook)(struct rt_object *object);
|
||||
static void (*rt_timer_enter_hook)(struct rt_timer *timer);
|
||||
static void (*rt_timer_exit_hook)(struct rt_timer *timer);
|
||||
|
||||
/**
|
||||
* @addtogroup Hook
|
||||
*/
|
||||
|
||||
/**@{*/
|
||||
|
||||
/**
|
||||
* This function will set a hook function, which will be invoked when enter
|
||||
* timer timeout callback function.
|
||||
*
|
||||
* @param hook the hook function
|
||||
*/
|
||||
void rt_timer_enter_sethook(void (*hook)(struct rt_timer *timer))
|
||||
{
|
||||
rt_timer_enter_hook = hook;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will set a hook function, which will be invoked when exit
|
||||
* timer timeout callback function.
|
||||
*
|
||||
* @param hook the hook function
|
||||
*/
|
||||
void rt_timer_exit_sethook(void (*hook)(struct rt_timer *timer))
|
||||
{
|
||||
rt_timer_exit_hook = hook;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
#endif
|
||||
|
||||
static void _rt_timer_init(rt_timer_t timer,
|
||||
void (*timeout)(void *parameter),
|
||||
void *parameter,
|
||||
rt_tick_t time,
|
||||
rt_uint8_t flag)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* set flag */
|
||||
timer->parent.flag = flag;
|
||||
|
||||
/* set deactivated */
|
||||
timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
|
||||
|
||||
timer->timeout_func = timeout;
|
||||
timer->parameter = parameter;
|
||||
|
||||
timer->timeout_tick = 0;
|
||||
timer->init_tick = time;
|
||||
|
||||
/* initialize timer list */
|
||||
for (i = 0; i < RT_TIMER_SKIP_LIST_LEVEL; i++)
|
||||
{
|
||||
rt_list_init(&(timer->row[i]));
|
||||
}
|
||||
}
|
||||
|
||||
/* the fist timer always in the last row */
|
||||
static rt_tick_t rt_timer_list_next_timeout(rt_list_t timer_list[])
|
||||
{
|
||||
struct rt_timer *timer;
|
||||
|
||||
if (rt_list_isempty(&timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1]))
|
||||
return RT_TICK_MAX;
|
||||
|
||||
timer = rt_list_entry(timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1].next,
|
||||
struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL - 1]);
|
||||
|
||||
return timer->timeout_tick;
|
||||
}
|
||||
|
||||
rt_inline void _rt_timer_remove(rt_timer_t timer)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < RT_TIMER_SKIP_LIST_LEVEL; i++)
|
||||
{
|
||||
rt_list_remove(&timer->row[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#if RT_DEBUG_TIMER
|
||||
static int rt_timer_count_height(struct rt_timer *timer)
|
||||
{
|
||||
int i, cnt = 0;
|
||||
|
||||
for (i = 0; i < RT_TIMER_SKIP_LIST_LEVEL; i++)
|
||||
{
|
||||
if (!rt_list_isempty(&timer->row[i]))
|
||||
cnt++;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
void rt_timer_dump(rt_list_t timer_heads[])
|
||||
{
|
||||
rt_list_t *list;
|
||||
|
||||
for (list = timer_heads[RT_TIMER_SKIP_LIST_LEVEL - 1].next;
|
||||
list != &timer_heads[RT_TIMER_SKIP_LIST_LEVEL - 1];
|
||||
list = list->next)
|
||||
{
|
||||
struct rt_timer *timer = rt_list_entry(list,
|
||||
struct rt_timer,
|
||||
row[RT_TIMER_SKIP_LIST_LEVEL - 1]);
|
||||
rt_kprintf("%d", rt_timer_count_height(timer));
|
||||
}
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @addtogroup Clock
|
||||
*/
|
||||
|
||||
/**@{*/
|
||||
|
||||
/**
|
||||
* This function will initialize a timer, normally this function is used to
|
||||
* initialize a static timer object.
|
||||
*
|
||||
* @param timer the static timer object
|
||||
* @param name the name of timer
|
||||
* @param timeout the timeout function
|
||||
* @param parameter the parameter of timeout function
|
||||
* @param time the tick of timer
|
||||
* @param flag the flag of timer
|
||||
*/
|
||||
void rt_timer_init(rt_timer_t timer,
|
||||
const char *name,
|
||||
void (*timeout)(void *parameter),
|
||||
void *parameter,
|
||||
rt_tick_t time,
|
||||
rt_uint8_t flag)
|
||||
{
|
||||
/* timer check */
|
||||
RT_ASSERT(timer != RT_NULL);
|
||||
|
||||
/* timer object initialization */
|
||||
rt_object_init((rt_object_t)timer, RT_Object_Class_Timer, name);
|
||||
|
||||
_rt_timer_init(timer, timeout, parameter, time, flag);
|
||||
}
|
||||
RTM_EXPORT(rt_timer_init);
|
||||
|
||||
/**
|
||||
* This function will detach a timer from timer management.
|
||||
*
|
||||
* @param timer the static timer object
|
||||
*
|
||||
* @return the operation status, RT_EOK on OK; RT_ERROR on error
|
||||
*/
|
||||
rt_err_t rt_timer_detach(rt_timer_t timer)
|
||||
{
|
||||
register rt_base_t level;
|
||||
|
||||
/* timer check */
|
||||
RT_ASSERT(timer != RT_NULL);
|
||||
RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);
|
||||
RT_ASSERT(rt_object_is_systemobject(&timer->parent));
|
||||
|
||||
/* disable interrupt */
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
_rt_timer_remove(timer);
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
rt_object_detach((rt_object_t)timer);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
RTM_EXPORT(rt_timer_detach);
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
/**
|
||||
* This function will create a timer
|
||||
*
|
||||
* @param name the name of timer
|
||||
* @param timeout the timeout function
|
||||
* @param parameter the parameter of timeout function
|
||||
* @param time the tick of timer
|
||||
* @param flag the flag of timer
|
||||
*
|
||||
* @return the created timer object
|
||||
*/
|
||||
rt_timer_t rt_timer_create(const char *name,
|
||||
void (*timeout)(void *parameter),
|
||||
void *parameter,
|
||||
rt_tick_t time,
|
||||
rt_uint8_t flag)
|
||||
{
|
||||
struct rt_timer *timer;
|
||||
|
||||
/* allocate a object */
|
||||
timer = (struct rt_timer *)rt_object_allocate(RT_Object_Class_Timer, name);
|
||||
if (timer == RT_NULL)
|
||||
{
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
_rt_timer_init(timer, timeout, parameter, time, flag);
|
||||
|
||||
return timer;
|
||||
}
|
||||
RTM_EXPORT(rt_timer_create);
|
||||
|
||||
/**
|
||||
* This function will delete a timer and release timer memory
|
||||
*
|
||||
* @param timer the timer to be deleted
|
||||
*
|
||||
* @return the operation status, RT_EOK on OK; RT_ERROR on error
|
||||
*/
|
||||
rt_err_t rt_timer_delete(rt_timer_t timer)
|
||||
{
|
||||
register rt_base_t level;
|
||||
|
||||
/* timer check */
|
||||
RT_ASSERT(timer != RT_NULL);
|
||||
RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);
|
||||
RT_ASSERT(rt_object_is_systemobject(&timer->parent) == RT_FALSE);
|
||||
|
||||
/* disable interrupt */
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
_rt_timer_remove(timer);
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
rt_object_delete((rt_object_t)timer);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
RTM_EXPORT(rt_timer_delete);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This function will start the timer
|
||||
*
|
||||
* @param timer the timer to be started
|
||||
*
|
||||
* @return the operation status, RT_EOK on OK, -RT_ERROR on error
|
||||
*/
|
||||
rt_err_t rt_timer_start(rt_timer_t timer)
|
||||
{
|
||||
unsigned int row_lvl;
|
||||
rt_list_t *timer_list;
|
||||
register rt_base_t level;
|
||||
rt_list_t *row_head[RT_TIMER_SKIP_LIST_LEVEL];
|
||||
unsigned int tst_nr;
|
||||
static unsigned int random_nr;
|
||||
|
||||
/* timer check */
|
||||
RT_ASSERT(timer != RT_NULL);
|
||||
RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);
|
||||
|
||||
/* stop timer firstly */
|
||||
level = rt_hw_interrupt_disable();
|
||||
/* remove timer from list */
|
||||
_rt_timer_remove(timer);
|
||||
/* change status of timer */
|
||||
timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(timer->parent)));
|
||||
|
||||
/*
|
||||
* get timeout tick,
|
||||
* the max timeout tick shall not great than RT_TICK_MAX/2
|
||||
*/
|
||||
RT_ASSERT(timer->init_tick < RT_TICK_MAX / 2);
|
||||
timer->timeout_tick = rt_tick_get() + timer->init_tick;
|
||||
|
||||
/* disable interrupt */
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
#ifdef RT_USING_TIMER_SOFT
|
||||
if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER)
|
||||
{
|
||||
/* insert timer to soft timer list */
|
||||
timer_list = rt_soft_timer_list;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* insert timer to system timer list */
|
||||
timer_list = rt_timer_list;
|
||||
}
|
||||
|
||||
row_head[0] = &timer_list[0];
|
||||
for (row_lvl = 0; row_lvl < RT_TIMER_SKIP_LIST_LEVEL; row_lvl++)
|
||||
{
|
||||
for (; row_head[row_lvl] != timer_list[row_lvl].prev;
|
||||
row_head[row_lvl] = row_head[row_lvl]->next)
|
||||
{
|
||||
struct rt_timer *t;
|
||||
rt_list_t *p = row_head[row_lvl]->next;
|
||||
|
||||
/* fix up the entry pointer */
|
||||
t = rt_list_entry(p, struct rt_timer, row[row_lvl]);
|
||||
|
||||
/* If we have two timers that timeout at the same time, it's
|
||||
* preferred that the timer inserted early get called early.
|
||||
* So insert the new timer to the end the the some-timeout timer
|
||||
* list.
|
||||
*/
|
||||
if ((t->timeout_tick - timer->timeout_tick) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if ((t->timeout_tick - timer->timeout_tick) < RT_TICK_MAX / 2)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (row_lvl != RT_TIMER_SKIP_LIST_LEVEL - 1)
|
||||
row_head[row_lvl + 1] = row_head[row_lvl] + 1;
|
||||
}
|
||||
|
||||
/* Interestingly, this super simple timer insert counter works very very
|
||||
* well on distributing the list height uniformly. By means of "very very
|
||||
* well", I mean it beats the randomness of timer->timeout_tick very easily
|
||||
* (actually, the timeout_tick is not random and easy to be attacked). */
|
||||
random_nr++;
|
||||
tst_nr = random_nr;
|
||||
|
||||
rt_list_insert_after(row_head[RT_TIMER_SKIP_LIST_LEVEL - 1],
|
||||
&(timer->row[RT_TIMER_SKIP_LIST_LEVEL - 1]));
|
||||
for (row_lvl = 2; row_lvl <= RT_TIMER_SKIP_LIST_LEVEL; row_lvl++)
|
||||
{
|
||||
if (!(tst_nr & RT_TIMER_SKIP_LIST_MASK))
|
||||
rt_list_insert_after(row_head[RT_TIMER_SKIP_LIST_LEVEL - row_lvl],
|
||||
&(timer->row[RT_TIMER_SKIP_LIST_LEVEL - row_lvl]));
|
||||
else
|
||||
break;
|
||||
/* Shift over the bits we have tested. Works well with 1 bit and 2
|
||||
* bits. */
|
||||
tst_nr >>= (RT_TIMER_SKIP_LIST_MASK + 1) >> 1;
|
||||
}
|
||||
|
||||
timer->parent.flag |= RT_TIMER_FLAG_ACTIVATED;
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
#ifdef RT_USING_TIMER_SOFT
|
||||
if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER)
|
||||
{
|
||||
/* check whether timer thread is ready */
|
||||
if ((timer_thread.stat & RT_THREAD_STAT_MASK) != RT_THREAD_READY)
|
||||
{
|
||||
/* resume timer thread to check soft timer */
|
||||
rt_thread_resume(&timer_thread);
|
||||
rt_schedule();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
RTM_EXPORT(rt_timer_start);
|
||||
|
||||
/**
|
||||
* This function will stop the timer
|
||||
*
|
||||
* @param timer the timer to be stopped
|
||||
*
|
||||
* @return the operation status, RT_EOK on OK, -RT_ERROR on error
|
||||
*/
|
||||
rt_err_t rt_timer_stop(rt_timer_t timer)
|
||||
{
|
||||
register rt_base_t level;
|
||||
|
||||
/* timer check */
|
||||
RT_ASSERT(timer != RT_NULL);
|
||||
RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);
|
||||
|
||||
if (!(timer->parent.flag & RT_TIMER_FLAG_ACTIVATED))
|
||||
return -RT_ERROR;
|
||||
|
||||
RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(timer->parent)));
|
||||
|
||||
/* disable interrupt */
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
_rt_timer_remove(timer);
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
/* change stat */
|
||||
timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
RTM_EXPORT(rt_timer_stop);
|
||||
|
||||
/**
|
||||
* This function will get or set some options of the timer
|
||||
*
|
||||
* @param timer the timer to be get or set
|
||||
* @param cmd the control command
|
||||
* @param arg the argument
|
||||
*
|
||||
* @return RT_EOK
|
||||
*/
|
||||
rt_err_t rt_timer_control(rt_timer_t timer, int cmd, void *arg)
|
||||
{
|
||||
/* timer check */
|
||||
RT_ASSERT(timer != RT_NULL);
|
||||
RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case RT_TIMER_CTRL_GET_TIME:
|
||||
*(rt_tick_t *)arg = timer->init_tick;
|
||||
break;
|
||||
|
||||
case RT_TIMER_CTRL_SET_TIME:
|
||||
timer->init_tick = *(rt_tick_t *)arg;
|
||||
break;
|
||||
|
||||
case RT_TIMER_CTRL_SET_ONESHOT:
|
||||
timer->parent.flag &= ~RT_TIMER_FLAG_PERIODIC;
|
||||
break;
|
||||
|
||||
case RT_TIMER_CTRL_SET_PERIODIC:
|
||||
timer->parent.flag |= RT_TIMER_FLAG_PERIODIC;
|
||||
break;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
RTM_EXPORT(rt_timer_control);
|
||||
|
||||
/**
|
||||
* This function will check timer list, if a timeout event happens, the
|
||||
* corresponding timeout function will be invoked.
|
||||
*
|
||||
* @note this function shall be invoked in operating system timer interrupt.
|
||||
*/
|
||||
void rt_timer_check(void)
|
||||
{
|
||||
struct rt_timer *t;
|
||||
rt_tick_t current_tick;
|
||||
register rt_base_t level;
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_TIMER, ("timer check enter\n"));
|
||||
|
||||
current_tick = rt_tick_get();
|
||||
|
||||
/* disable interrupt */
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
while (!rt_list_isempty(&rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1]))
|
||||
{
|
||||
t = rt_list_entry(rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1].next,
|
||||
struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL - 1]);
|
||||
|
||||
/*
|
||||
* It supposes that the new tick shall less than the half duration of
|
||||
* tick max.
|
||||
*/
|
||||
if ((current_tick - t->timeout_tick) < RT_TICK_MAX / 2)
|
||||
{
|
||||
RT_OBJECT_HOOK_CALL(rt_timer_enter_hook, (t));
|
||||
|
||||
/* remove timer from timer list firstly */
|
||||
_rt_timer_remove(t);
|
||||
|
||||
/* call timeout function */
|
||||
t->timeout_func(t->parameter);
|
||||
|
||||
/* re-get tick */
|
||||
current_tick = rt_tick_get();
|
||||
|
||||
RT_OBJECT_HOOK_CALL(rt_timer_exit_hook, (t));
|
||||
RT_DEBUG_LOG(RT_DEBUG_TIMER, ("current tick: %d\n", current_tick));
|
||||
|
||||
if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) &&
|
||||
(t->parent.flag & RT_TIMER_FLAG_ACTIVATED))
|
||||
{
|
||||
/* start it */
|
||||
t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
|
||||
rt_timer_start(t);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* stop timer */
|
||||
t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_TIMER, ("timer check leave\n"));
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will return the next timeout tick in the system.
|
||||
*
|
||||
* @return the next timeout tick in the system
|
||||
*/
|
||||
rt_tick_t rt_timer_next_timeout_tick(void)
|
||||
{
|
||||
return rt_timer_list_next_timeout(rt_timer_list);
|
||||
}
|
||||
|
||||
#ifdef RT_USING_TIMER_SOFT
|
||||
/**
|
||||
* This function will check timer list, if a timeout event happens, the
|
||||
* corresponding timeout function will be invoked.
|
||||
*/
|
||||
void rt_soft_timer_check(void)
|
||||
{
|
||||
rt_tick_t current_tick;
|
||||
rt_list_t *n;
|
||||
struct rt_timer *t;
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_TIMER, ("software timer check enter\n"));
|
||||
|
||||
current_tick = rt_tick_get();
|
||||
|
||||
/* lock scheduler */
|
||||
rt_enter_critical();
|
||||
|
||||
for (n = rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1].next;
|
||||
n != &(rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1]);)
|
||||
{
|
||||
t = rt_list_entry(n, struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL - 1]);
|
||||
|
||||
/*
|
||||
* It supposes that the new tick shall less than the half duration of
|
||||
* tick max.
|
||||
*/
|
||||
if ((current_tick - t->timeout_tick) < RT_TICK_MAX / 2)
|
||||
{
|
||||
RT_OBJECT_HOOK_CALL(rt_timer_enter_hook, (t));
|
||||
|
||||
/* move node to the next */
|
||||
n = n->next;
|
||||
|
||||
/* remove timer from timer list firstly */
|
||||
_rt_timer_remove(t);
|
||||
|
||||
/* not lock scheduler when performing timeout function */
|
||||
rt_exit_critical();
|
||||
/* call timeout function */
|
||||
t->timeout_func(t->parameter);
|
||||
|
||||
/* re-get tick */
|
||||
current_tick = rt_tick_get();
|
||||
|
||||
RT_OBJECT_HOOK_CALL(rt_timer_exit_hook, (t));
|
||||
RT_DEBUG_LOG(RT_DEBUG_TIMER, ("current tick: %d\n", current_tick));
|
||||
|
||||
/* lock scheduler */
|
||||
rt_enter_critical();
|
||||
|
||||
if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) &&
|
||||
(t->parent.flag & RT_TIMER_FLAG_ACTIVATED))
|
||||
{
|
||||
/* start it */
|
||||
t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
|
||||
rt_timer_start(t);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* stop timer */
|
||||
t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
|
||||
}
|
||||
}
|
||||
else break; /* not check anymore */
|
||||
}
|
||||
|
||||
/* unlock scheduler */
|
||||
rt_exit_critical();
|
||||
|
||||
RT_DEBUG_LOG(RT_DEBUG_TIMER, ("software timer check leave\n"));
|
||||
}
|
||||
|
||||
/* system timer thread entry */
|
||||
static void rt_thread_timer_entry(void *parameter)
|
||||
{
|
||||
rt_tick_t next_timeout;
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* get the next timeout tick */
|
||||
next_timeout = rt_timer_list_next_timeout(rt_soft_timer_list);
|
||||
if (next_timeout == RT_TICK_MAX)
|
||||
{
|
||||
/* no software timer exist, suspend self. */
|
||||
rt_thread_suspend(rt_thread_self());
|
||||
rt_schedule();
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_tick_t current_tick;
|
||||
|
||||
/* get current tick */
|
||||
current_tick = rt_tick_get();
|
||||
|
||||
if ((next_timeout - current_tick) < RT_TICK_MAX / 2)
|
||||
{
|
||||
/* get the delta timeout tick */
|
||||
next_timeout = next_timeout - current_tick;
|
||||
rt_thread_delay(next_timeout);
|
||||
}
|
||||
}
|
||||
|
||||
/* check software timer */
|
||||
rt_soft_timer_check();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @ingroup SystemInit
|
||||
*
|
||||
* This function will initialize system timer
|
||||
*/
|
||||
void rt_system_timer_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(rt_timer_list) / sizeof(rt_timer_list[0]); i++)
|
||||
{
|
||||
rt_list_init(rt_timer_list + i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup SystemInit
|
||||
*
|
||||
* This function will initialize system timer thread
|
||||
*/
|
||||
void rt_system_timer_thread_init(void)
|
||||
{
|
||||
#ifdef RT_USING_TIMER_SOFT
|
||||
int i;
|
||||
|
||||
for (i = 0;
|
||||
i < sizeof(rt_soft_timer_list) / sizeof(rt_soft_timer_list[0]);
|
||||
i++)
|
||||
{
|
||||
rt_list_init(rt_soft_timer_list + i);
|
||||
}
|
||||
|
||||
/* start software timer thread */
|
||||
rt_thread_init(&timer_thread,
|
||||
"timer",
|
||||
rt_thread_timer_entry,
|
||||
RT_NULL,
|
||||
&timer_thread_stack[0],
|
||||
sizeof(timer_thread_stack),
|
||||
RT_TIMER_THREAD_PRIO,
|
||||
10);
|
||||
|
||||
/* startup */
|
||||
rt_thread_startup(&timer_thread);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
Reference in New Issue
Block a user