📄 sys_arch.c
字号:
/*
*********************************************************************************************************
* ModbusTCP
* programmable human machine interface
*
* (c) Copyright 2007, 浙大中自集成控制股份有限公司开发二部
* All Rights Reserved
*
* File : LcdDriver.c
* By : lb
*********************************************************************************************************
*/
/***********************************************
系统的驱动,移植了ucosii的一些功能,但是memmange不是用ucos的而是lwip自己的。
************************************************/
#include "sys_arch.h"
#include "def.h"
#include "sys.h"
//////////////////////////////////////////////////
/*#define ARCH_OK 2
#if ARCH_OK == 1
#define MAX_QUEUES 10
#define MAX_QUEUE_ENTRIES 20
#define SYS_MBOX_NULL (void*)0
#define SYS_SEM_NULL (void*)0
typedef struct
{
OS_EVENT * pQ; //ucosii中指向事件控制块的指针
void * pvQEntries[MAX_QUEUE_ENTRIES]; //MAX_QUEUE_ENTRIES消息队列中对多的消息数
} Q_DESCR, *Q_DESCRPt;
typedef Q_DESCRPt sys_mbox_t;
typedef INT8U sys_sem_t;
typedef INT8U sys_thread_t;
#endif*/
//////////////////////////////////////////////////
struct sys_timeouts NullTimeouts;
struct sys_timeouts LwipTimeouts[LWIP_TASK_MAX];
static INT8U QueueMemoryPool[MAX_QUEUES][sizeof(Q_DESCR)]; //在内存中建立一个能容纳MAX_QUEUES个队列的内存池
OS_MEM * QueueMemPt;
static INT8U ModbusTcpBuf[MAX_MODBUSTCP_BUF_NUM][272];
OS_MEM * ModbusTcpBufPt;
/*定义关于协议栈任务的一些变量和常量*/
//#define LWIP_TASK_MAX 5
#define LWIP_TASK_STK_SIZE 1024
INT8U lwip_task_prio_offset[LWIP_TASK_MAX]; //这个主要是避免了写程序的时候分配的优先级混乱,我把它叫做优先级对号入座。
OS_STK LwipTaskStack[LWIP_TASK_MAX][LWIP_TASK_STK_SIZE];
OS_STK LwipTreadStack[2048];
unsigned char LwipTreadHasCreated=0;
//这个任务的堆栈主要是为了创建多个lwip线程所设置的,它所用的堆栈也是随着任务的创建的先后而区分的。
/*sys_init()--系统初始化函数,应用在一切开始之前,所以,这个可以对应于ucosii的 OSinit()初始化μC/OS-Ⅱ,
对这个函数的调用必须在调用OSStart()函数之前,而OSStart()函数真正开始运行多任务。sys_init既然可以用OSinit代替,
那么它做的东西可以更加有针对性,例如初始化信号量和邮箱以及消息队列,那么它的伪代码可以写成如下状态*/
void sys_init(void)
{
//初始化了一个内存缓冲池,用于放MAX_QUEUES个ucosii的消息队列。
unsigned char err;
QueueMemPt = OSMemCreate((void *)QueueMemoryPool, MAX_QUEUES, sizeof(Q_DESCR), &err);
ModbusTcpBufPt = OSMemCreate((void *)ModbusTcpBuf, MAX_MODBUSTCP_BUF_NUM, 272, &err);
}
void *sys_mem_get(INT8U *err)
{
void * userbuf;
userbuf = OSMemGet(ModbusTcpBufPt, err);
return userbuf;
}
void sys_mem_free(void *Pblk)
{
OSMemPut(ModbusTcpBufPt, Pblk);
}
/*sys_thread_new()-- 系统的线程创建函数,它相当于ucosii中的taskcreate,因此将其封装出taskcreate的功能即可*/
sys_thread_t sys_thread_new(void (*function)(void *arg), void *arg, int prio) //后面两个参数形同虚设
{
INT8U CreatState;
if((!prio) && (!LwipTreadHasCreated))
//if((prio) && (!LwipTreadHasCreated))
{
CreatState = OSTaskCreate(function, (void *)0x5555, &LwipTreadStack[2048-1],\
(LWIP_TASK_START_PRIO+(unsigned char)prio));
LwipTreadHasCreated = 1;
if(!CreatState){
lwip_task_prio_offset[prio]=1; //成功创建了一个任务后,将其加1,以便下一个创建的任务使用。
return 1;
}
else{
return 0;
}
}
else if(LwipTreadHasCreated)
{
if(prio>(LWIP_TASK_MAX-1))
return 0;
if(lwip_task_prio_offset[prio])
return 0;
CreatState = OSTaskCreate(function, (void *)0x5555, &LwipTaskStack[prio][LWIP_TASK_STK_SIZE-1],\
(LWIP_TASK_START_PRIO+(unsigned char)prio));
if(!CreatState){
lwip_task_prio_offset[prio]=1; //成功创建了一个任务后,将其加1,以便下一个创建的任务使用。
return 1;
}
else{
return 0;
}
}
else
return 0;
}
/*创建一个邮箱,但是这个邮箱相当于ucosii中的消息队列*/
sys_mbox_t sys_mbox_new(void)
{
unsigned char err;
Q_DESCRPt QDescPt;
QDescPt = OSMemGet(QueueMemPt, &err); //在内存池中分配出一个队列结构的空间,并将此空间赋成这个结构。
if(err == OS_NO_ERR){
QDescPt->pQ = OSQCreate(&(QDescPt->pvQEntries[0]), MAX_QUEUE_ENTRIES); //创建队列,但是队列只是lwip队列结构的一个成员。
if(QDescPt->pQ != NULL){
return QDescPt;
}
}
return SYS_MBOX_NULL;
}
/*释放并删除一个邮箱,相当于ucosii中的消息队列的清空、删除和释放*/
void sys_mbox_free(sys_mbox_t mbox)
{
unsigned char err;
OSQDel((OS_EVENT *)(&(mbox->pvQEntries[0])), 0, &err);
//具体怎样保证安全性还需要再考虑
OSQFlush( mbox->pQ ); //清除队列事件
OSQDel( mbox->pQ, OS_DEL_NO_PEND, &err); //删除队列
err = OSMemPut( QueueMemPt, mbox); //把队列所占内存放入内存池
}
/*向一个邮箱发送消息,相当于osii中向队列发送消息*/
void sys_mbox_post(sys_mbox_t mbox, void *data) //由于lwip会发空消息,而ucosii对空消息会当错处理,所以我们把lwip的空做成ucosii的一个特定值。
{
unsigned char err;
if(!data)
data = (void *)0xffffffff;
err = OSQPost(mbox->pQ, data);
}
unsigned long sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, unsigned long timeout)
{
unsigned char err;
unsigned short ucos_timeout = 0;
/*由于lwip中的timeout时间是ms,而ucosii的是timer tick,所以要转换,将timeout转换成ucos_timeout*/
//首先确保输入参数的合理性
if(timeout){
ucos_timeout = (timeout * OS_TICKS_PER_SEC)/1000;
if(ucos_timeout < 1)
ucos_timeout = 1;
else if(ucos_timeout > 65535)
ucos_timeout = 65535;
}
if(!mbox)
return SYS_ARCH_TIMEOUT;
//因为OSQPend()有返回值,则看有没有可返回的地址,有则返回,无则不返回。
if(msg != NULL){
*msg = OSQPend(mbox->pQ, (unsigned short)ucos_timeout, &err);
}
else{
OSQPend(mbox->pQ, (unsigned short)ucos_timeout, &err);
}
if(err == OS_TIMEOUT){
timeout = SYS_ARCH_TIMEOUT;
}
else{
if(*msg == (void *)0xffffffff)
*msg = NULL;
timeout = (ucos_timeout - err) * (1000/OS_TICKS_PER_SEC);
}
return timeout;
}
/*创建信号量*/
sys_sem_t sys_sem_new(unsigned char count)
{
sys_sem_t SemPt;
SemPt = OSSemCreate(count);
if(SemPt != NULL)
return SemPt;
return SYS_SEM_NULL;
}
/*释放并删除一个信号量*/
void sys_sem_free(sys_sem_t sem)
{
unsigned char err;
OSSemDel((OS_EVENT *)sem, OS_DEL_NO_PEND, &err );
}
/*发送一个信号量*/
void sys_sem_signal(sys_sem_t sem)
{
OSSemPost((OS_EVENT *)sem);
}
unsigned long sys_arch_sem_wait(sys_sem_t sem, unsigned long timeout) //同队列
{
unsigned char err;
unsigned short ucos_timeout = 0;
/*由于lwip中的timeout时间是ms,而ucosii的是timer tick,所以要转换,将timeout转换成ucos_timeout*/
//首先确保输入参数的合理性
if(timeout){
ucos_timeout = (timeout * OS_TICKS_PER_SEC)/1000;
if(ucos_timeout < 1)
ucos_timeout = 1;
else if(ucos_timeout > 65535)
ucos_timeout = 65535;
}
OSSemPend ((OS_EVENT *)sem,(u16_t)ucos_timeout, (u8_t *)&err);
if(err == OS_TIMEOUT){
return 0;
}
else{
return 1;
}
}
/*设置一个超时事件*/
struct sys_timeouts *sys_arch_timeouts(void)
{
unsigned char CurrPrio;
signed short err, offset;
OS_TCB CurrTaskPcb;
NullTimeouts.next = NULL;
err = OSTaskQuery(OS_PRIO_SELF, &CurrTaskPcb);
CurrPrio = CurrTaskPcb.OSTCBPrio;
offset = CurrPrio - LWIP_TASK_START_PRIO;
if(offset<0 || offset >= LWIP_TASK_MAX){
return &NullTimeouts;
}
return &LwipTimeouts[offset];
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -