📄 cmxio3.c
字号:
/*********************************************************
Copyright (c) CMX Company. 1991, 1992. All rights reserved
*********************************************************/
/* version 3.00 */
#include <cxfuncs.h>
#include <cxextern.h> /* get cmx include header file */
#include <ioh83003.h> /* get H8/300H processor register header file */
/* #include <???.h> include the processor io header file. */
/* WARNING ---- UPDATE ---- WARNING
The uart_update() function has been broken into 2 (two) different
functions, which are the K_Update_Recv function and the
K_Update_Xmit function, call respectively by the reciever
and transmitter interrupt handlers
WARNING ---- UPDATE ---- WARNING */
/**************************************************************
!!! CAUTION !!!
It is up to the interrupt handler that either calls the K_Update_Recv
and K_Update_Xmit functions to clear or set any need bits in the UART
registers (IF NEED BE), so as to properly handle the sending and recieving
of characters thru the UART. This may include reloading a timer, clearing
the recieve char bit, error flags, etc, depending upon the processor and
mode that the UART is operating in.
CMX does NOT do anything to any UART register bits. It will just recieve
a character and transmit a character. However it will start the transmitter
when need be, according to the XMIT_INT_ON define set below by user.
**************************************************************/
/**************************************************************
The user MAY have to tweak some of the following code, depending
upon the processor that they are working with. This is because
there are many different ways to configure a UART and many modes
that a UART can operate under.
Probally the most the user will have to do is to properly enable the
UART transmitter and possibly properly clear the reciever ready flag
if needed to be done by software. Also the user must tell the "C"
functions where the UART registers are located. The user will
have to at the most, possibly manipulate the following functions:
K_Init_Xmit() initialize transmitter
K_Init_Recv() initialize reciever
NOTE: in most cases the processor and "C" compiler will
allow you to access the IO registers by either including
the proper *.h file or by casting the register
to an absolute address. However their are some exceptions
to this, and if so, the user must create their own
assembly routines to properly set, clear and test bits and
to get and send a byte or word to these register.
********************************************************/
/**************************************************************
The user must set these to the CPU that they are working with
#define XMIT_INT_ON ??? enable the transmitter
#define RECV_REG reciever register
#define XMIT_REG transmit register
***************************************************************/
/******************************************************
The following is for the H8/83003 processor
NOTE: set up for serial channel 0
********************************************************/
#define XMIT_INT_ON (SCI0_SCR |= 0x80) /* enable transmitter interrupt. */
#define XMIT_REG SCI0_TDR
#define RECV_REG SCI0_RDR
#define XMIT_SIZE 256 /* size of transmitter buffer */
#define RECV_SIZE 256 /* size of reciever buffer */
word16 K_I_Get_Char_Common(byte *,word16,word16,byte);
byte K_I_Put_Char_Common(byte *,word16,word16,byte);
byte K_I_Remove_Link(void);
void K_I_Insert_Link(word16);
/* NOTES:
The recieve interrupt could determine that the last character came in
and signal an event indicating this, or wake a task, etc.
*/
/* THE FOLLOWING ARE TRANSMITTER FLAGS */
#define XMIT_BUSY 0x01
/* THE FOLLOWING ARE RECIEVER FLAGS */
#define OE 0x02
#define FE 0x04
#define PE 0x08
#define FULL 0x20
#define RECV_BUFF_ERR 0x40
#define AER_UART_BUSY 0x20 /* error code pass back to calling task */
struct {
byte *head; /* head pointer for characters going into buffer. */
byte *tail; /* tail pointer for characters going out of buffer. */
word16 bytes_out; /* number of bytes to transmit. */
byte flag; /* the transmit flags. */
tcbpointer tcbptr; /* the task is waiting for transmitter to finish. */
byte buff[XMIT_SIZE]; /* the transmit buufer. */
} xmit, *uart_xmit1;
struct {
byte *head; /* head pointer for characters going into buffer. */
byte *tail; /* tail pointer for characters going out of buffer. */
word16 bytes_in; /* number of bytes in reciever . */
word16 bytes_wanted; /* number of bytes wanted. */
byte flag; /* the reciever flags. */
tcbpointer tcbptr; /* the task that is waiting on the reciever. */
byte buff[RECV_SIZE]; /* the reciever buffer. */
} rec, *uart_recv1;
byte K_Init_Xmit(void)
{
/* set up BAUD rate, parity, data bits, stop bits */
uart_xmit1 = &xmit;
uart_xmit1->flag = 0x00; /* clear flags. */
}
byte K_Init_Recv(void)
{
/* set up BAUD rate, parity, data bits, stop bits */
/* also enable reciever, if need be. */
uart_recv1 = &rec;
uart_recv1->head = uart_recv1->tail = &rec.buff[0];
}
/* The following can only be called by the interrupt. No
Parameters are passed. */
void K_Update_Xmit(void)
{
if (uart_xmit1->flag & XMIT_BUSY) /* see if transmitter should transmit. */
{
if (uart_xmit1->bytes_out--) /* decrement count and send. */
{
XMIT_REG = *uart_xmit1->tail++; /* send character out. */
}
else
{
uart_xmit1->flag &= ~XMIT_BUSY; /* transmitter done. */
if (uart_xmit1->tcbptr) /* see if task needs to be notified. */
{
if (uart_xmit1->tcbptr->tcbstate & WAIT)
{
uart_xmit1->tcbptr->tcbstate = RESUME; /* allow task to resume. */
if (uart_xmit1->tcbptr->priority < active_priority)
cmx_flag1 |= preempted; /* yes, set preempted K_I_Scheduler flag */
}
}
}
}
}
/* The following can only be called by the interrupt. No
Parameters are passed. */
void K_Update_Recv(void)
{
if (!(uart_recv1->flag & FULL)) /* see if reciever NOT full. */
{
*uart_recv1->head = RECV_REG; /* get character and store in buffer. */
if (++uart_recv1->head == &rec.buff[RECV_SIZE]) /* see if wrap. */
uart_recv1->head = &rec.buff[0];
if (uart_recv1->bytes_in++ == RECV_SIZE) /* is buffer full. */
{
uart_recv1->flag |= FULL; /* yes set flag. */
}
if (uart_recv1->bytes_wanted) /* is task waiting for number of bytes. */
{
if (!(--uart_recv1->bytes_wanted)) /* yes, decrement and test. */
{
if (uart_recv1->tcbptr->tcbstate & WAIT) /* see if task waiting. */
{
uart_recv1->tcbptr->tcbstate = RESUME; /* yes, wake task. */
if (uart_recv1->tcbptr->priority < active_priority)
cmx_flag1 |= preempted; /* yes, set preempted K_I_Scheduler flag */
}
}
}
}
else
{
uart_recv1->flag |= RECV_BUFF_ERR; /* flag that buffer overrun
occurred char lost. */
}
}
byte K_I_Put_Char_Common(byte *byte_ptr,word16 cnt,word16 timecnt,byte wait)
{
K_I_Disable_Sched(); /* set task block. */
K_OS_Disable_Interrupts(); /* DISABLE INTERRUPTS. */
if (uart_xmit1->flag & XMIT_BUSY) /* is transmitter busy. */
{
if (wait) /* should task wait. */
{
if (timecnt) /* wait on time too? */
activetcb->tcbstate = WAIT | TIME; /* put task to sleep, idicating why */
else
activetcb->tcbstate = WAIT; /* put task to sleep, idicating why */
uart_xmit1->tcbptr = activetcb; /* tell transmitter task waiting. */
K_OS_Enable_Interrupts(); /* RE-ENABLE INTERRUPTS */
K_I_Insert_Link(timecnt); /* insert it into time link. */
uart_xmit1->tcbptr = NULL; /* task will return to here. */
K_I_Disable_Sched(); /* set task block. */
if(K_I_Remove_Link()) /* remove from link. */
{
K_I_Func_Return(); /* time out occurred. */
return(K_TIMEOUT);
}
}
else
{
K_OS_Enable_Interrupts(); /* RE-ENABLE INTERRUPTS */
K_I_Func_Return(); /* release task lock. */
return(AER_UART_BUSY); /* return error that transmitter busy. */
}
}
else
{
K_OS_Enable_Interrupts(); /* RE-ENABLE INTERRUPTS */
}
/* the following sets up the transmitter buffer, and starts transmission. */
uart_xmit1->flag |= XMIT_BUSY;
uart_xmit1->bytes_out = cnt; /* number of characters to transmit. */
uart_xmit1->head = &xmit.buff[0]; /* reset head. */
uart_xmit1->tail = &xmit.buff[0]; /* reset tail. */
while(cnt--)
{
*uart_xmit1->head++ = *byte_ptr++; /* load bytes in. */
}
XMIT_INT_ON; /* enable transmitter. */
K_I_Func_Return();
return(K_OK);
}
/* for sending out characters to uart buffer*/
/* this works with uart buffer */
byte K_Put_Str(void *byte_ptr,word16 cnt)
{
return(K_I_Put_Char_Common((byte *)byte_ptr,cnt,0,0));
}
byte K_Put_Str_Wait(void *byte_ptr,word16 cnt,word16 timecnt)
{
return(K_I_Put_Char_Common((byte *)byte_ptr,cnt,timecnt,1));
}
byte K_Put_Char(void *byte_ptr)
{
return(K_I_Put_Char_Common((byte *)byte_ptr,1,0,0));
}
byte K_Put_Char_Wait(void *byte_ptr,word16 timecnt)
{
return(K_I_Put_Char_Common((byte *)byte_ptr,1,timecnt,1));
}
/* for recieving characters from uart buffer*/
/* this works with uart buffer */
word16 K_I_Get_Char_Common(byte *byte_ptr,word16 cnt,word16 timecnt,byte wait)
{
word16 count;
K_I_Disable_Sched(); /* set task lock. */
K_OS_Disable_Interrupts(); /* DISABLE INTERRUPTS. */
if (!cnt) /* vaiable length command, get current contents */
{
cnt = uart_recv1->bytes_in; /* get number of chars. already in. */
K_OS_Enable_Interrupts(); /* RE-ENABLE INTERRUPTS */
}
else
{
if (cnt > uart_recv1->bytes_in) /* see if in count > then requested. */
{
if (wait) /* should task waiti. */
{
if (timecnt) /* yes, also time period. */
activetcb->tcbstate = WAIT | TIME; /* put task to sleep, idicating why */
else
activetcb->tcbstate = WAIT; /* put task to sleep, idicating why */
uart_recv1->tcbptr = activetcb; /* tell reciever. */
/* calculate number of bytes needed to satisfy. */
uart_recv1->bytes_wanted = (cnt - uart_recv1->bytes_in);
K_OS_Enable_Interrupts(); /* RE-ENABLE INTERRUPTS */
K_I_Insert_Link(timecnt); /* insert into time link. */
K_I_Disable_Sched(); /* set task lock. */
uart_recv1->bytes_wanted = 0; /* reset wanted count. */
if(K_I_Remove_Link()) /* remove from link if need be. */
{
if (wait == 0x02) /* see if variable count mode. */
{
K_OS_Disable_Interrupts(); /* DISABLE INTERRUPTS. */
cnt = uart_recv1->bytes_in; /* set number of bytes to move. */
K_OS_Enable_Interrupts(); /* RE-ENABLE INTERRUPTS */
}
else
{
K_I_Func_Return(); /* release task block. */
return(0); /* return ZERO count status. */
}
}
}
else
{
K_OS_Enable_Interrupts(); /* RE-ENABLE INTERRUPTS */
K_I_Func_Return(); /* release task block. */
return(0); /* return ZERO count status. */
}
}
else
{
K_OS_Enable_Interrupts(); /* RE-ENABLE INTERRUPTS */
}
}
count = 0;
/* load callers pointer with bytes. */
while (cnt-- && uart_recv1->bytes_in)
{
*byte_ptr++ = *uart_recv1->tail;
/* see if wrap. */
if (++uart_recv1->tail == &rec.buff[RECV_SIZE])
uart_recv1->tail = &rec.buff[0];
count++; /* increment count. */
K_OS_Disable_Interrupts(); /* disable interrupts. */
--uart_recv1->bytes_in; /* decrement count of number of bytes in reciever. */
uart_recv1->flag &= ~FULL; /* reset flag. */
K_OS_Enable_Interrupts(); /* re-enable interrupts. */
}
K_I_Func_Return();
return(count);
}
word16 K_Recv_Count(void)
{
return(uart_recv1->bytes_in);
}
/* get single character, no time out, no wait */
word16 K_Get_Char(void *byte_ptr)
{
return(K_I_Get_Char_Common((byte *)byte_ptr,1,0,0));
}
/* get single character, wait, if after wait no character, return nothing */
word16 K_Get_Char_Wait(void *byte_ptr,word16 timecnt)
{
return(K_I_Get_Char_Common((byte *)byte_ptr,1,timecnt,1));
}
/* get requested number of char. , if number requested
not there, return nothing, NO wait */
word16 K_Get_Str(void *byte_ptr,word16 cnt)
{
return(K_I_Get_Char_Common((byte *)byte_ptr,cnt,0,0));
}
/* get requested number of char. , wait for timeout if number requested
not there, if after wait correct number NOT there , return nothing */
word16 K_Get_Str_Wait(void *byte_ptr,word16 cnt,word16 timecnt)
{
return(K_I_Get_Char_Common((byte *)byte_ptr,cnt,timecnt,1));
}
/* get requested number of char. , wait for timeout if number requested
not there, if after wait correct number NOT there , return the
number that came in */
word16 K_Get_Str_Wait_Return(void *byte_ptr,word16 cnt,word16 timecnt)
{
return(K_I_Get_Char_Common((byte *)byte_ptr,cnt,timecnt,2));
}
/* get ALL character in buffer, do not wait */
word16 K_Get_Str_Return(void *byte_ptr)
{
return(K_I_Get_Char_Common((byte *)byte_ptr,0,0,0));
}
/* inset task into time wait link, if need be. */
void K_I_Insert_Link(word16 timecnt)
{
activetcb->tcbtimer = timecnt; /* load task time counter with proper time */
if (timecnt) /* put into timer chain ?? */
{
/* let task sleep, indicating why and also waiting on time */
if (tsk_timer_lnk->ftlink != (tcbpointer)tsk_timer_lnk)
{
activetcb->ftlink = tsk_timer_lnk->btlink->ftlink;
tsk_timer_lnk->btlink->ftlink = activetcb;
activetcb->btlink = tsk_timer_lnk->btlink;
}
else
{
activetcb->ftlink = activetcb->btlink = (tcbpointer)tsk_timer_lnk;
tsk_timer_lnk->ftlink = activetcb;
}
tsk_timer_lnk->btlink = activetcb;
}
cmx_flag1 |= preempted; /* set the K_I_Scheduler flag */
K_I_Func_Return(); /* release task block */
}
/* remove from time link, if need be. */
byte K_I_Remove_Link()
{
if (activetcb->tcbtimer)
{
activetcb->ftlink->btlink = activetcb->btlink;
activetcb->btlink->ftlink = activetcb->ftlink;
}
/* see if task was woken, because the thing it was waiting for happened,
or that the time period specified has elapsed */
if (activetcb->tcbstate & TIME_EXPIRED)
{
return(K_TIMEOUT); /* return the warning: that the time period expired */
}
else
{
return(K_OK); /* return good, time period did NOT expire. */
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -