📄 serial.c
字号:
/*
* TOPPERS/JSP Kernel
* Toyohashi Open Platform for Embedded Real-Time Systems/
* Just Standard Profile Kernel
*
* Copyright (C) 2000-2003 by Embedded and Real-Time Systems Laboratory
* Toyohashi Univ. of Technology, JAPAN
*
* 忋婰挊嶌尃幰偼丆埲壓偺 (1)乣(4) 偺忦審偐丆Free Software Foundation
* 偵傛偭偰岞昞偝傟偰偄傞 GNU General Public License 偺 Version 2 偵婰
* 弎偝傟偰偄傞忦審傪枮偨偡応崌偵尷傝丆杮僜僼僩僂僃傾乮杮僜僼僩僂僃傾
* 傪夵曄偟偨傕偺傪娷傓丏埲壓摨偠乯傪巊梡丒暋惢丒夵曄丒嵞攝晍乮埲壓丆
* 棙梡偲屇傇乯偡傞偙偲傪柍彏偱嫋戻偡傞丏
* (1) 杮僜僼僩僂僃傾傪僜乕僗僐乕僪偺宍偱棙梡偡傞応崌偵偼丆忋婰偺挊嶌
* 尃昞帵丆偙偺棙梡忦審偍傛傃壓婰偺柍曐徹婯掕偑丆偦偺傑傑偺宍偱僜乕
* 僗僐乕僪拞偵娷傑傟偰偄傞偙偲丏
* (2) 杮僜僼僩僂僃傾傪丆儔僀僽儔儕宍幃側偳丆懠偺僜僼僩僂僃傾奐敪偵巊
* 梡偱偒傞宍偱嵞攝晍偡傞応崌偵偼丆嵞攝晍偵敽偆僪僉儏儊儞僩乮棙梡
* 幰儅僯儏傾儖側偳乯偵丆忋婰偺挊嶌尃昞帵丆偙偺棙梡忦審偍傛傃壓婰
* 偺柍曐徹婯掕傪宖嵹偡傞偙偲丏
* (3) 杮僜僼僩僂僃傾傪丆婡婍偵慻傒崬傓側偳丆懠偺僜僼僩僂僃傾奐敪偵巊
* 梡偱偒側偄宍偱嵞攝晍偡傞応崌偵偼丆師偺偄偢傟偐偺忦審傪枮偨偡偙
* 偲丏
* (a) 嵞攝晍偵敽偆僪僉儏儊儞僩乮棙梡幰儅僯儏傾儖側偳乯偵丆忋婰偺挊
* 嶌尃昞帵丆偙偺棙梡忦審偍傛傃壓婰偺柍曐徹婯掕傪宖嵹偡傞偙偲丏
* (b) 嵞攝晍偺宍懺傪丆暿偵掕傔傞曽朄偵傛偭偰丆TOPPERS僾儘僕僃僋僩偵
* 曬崘偡傞偙偲丏
* (4) 杮僜僼僩僂僃傾偺棙梡偵傛傝捈愙揑傑偨偼娫愙揑偵惗偠傞偄偐側傞懝
* 奞偐傜傕丆忋婰挊嶌尃幰偍傛傃TOPPERS僾儘僕僃僋僩傪柶愑偡傞偙偲丏
*
* 杮僜僼僩僂僃傾偼丆柍曐徹偱採嫙偝傟偰偄傞傕偺偱偁傞丏忋婰挊嶌尃幰偍
* 傛傃TOPPERS僾儘僕僃僋僩偼丆杮僜僼僩僂僃傾偵娭偟偰丆偦偺揔梡壜擻惈傕
* 娷傔偰丆偄偐側傞曐徹傕峴傢側偄丏傑偨丆杮僜僼僩僂僃傾偺棙梡偵傛傝捈
* 愙揑傑偨偼娫愙揑偵惗偠偨偄偐側傞懝奞偵娭偟偰傕丆偦偺愑擟傪晧傢側偄丏
*
* @(#) $Id: serial.c,v 1.12 2003/06/04 01:48:33 hiro Exp $
*/
/*
* 僔儕傾儖僀儞僞僼僃乕僗僪儔僀僶
*/
#include <t_services.h>
#include <serial.h>
#include "hw_serial.h"
#include "kernel_id.h"
/*
* 僶僢僼傽僒僀僘偲僼儘乕惂屼偵娭楢偡傞掕悢
*/
#define SERIAL_BUFSZ 256 /* 僪儔僀僶偺僶僢僼傽僒僀僘 */
#define FC_STOP '\023' /* 僐儞僩儘乕儖-S */
#define FC_START '\021' /* 僐儞僩儘乕儖-Q */
#define BUFCNT_STOP (SERIAL_BUFSZ - 64) /* STOP傪憲傞婎弨暥帤悢 */
#define BUFCNT_START (SERIAL_BUFSZ - 128) /* START傪憲傞婎弨暥帤悢 */
/*
* 僋儘乕僘偺嵺偵憲怣傪懸偮嵟戝帪娫乮msec扨埵乯
*/
#define MAX_FLUSH_WAIT 1000
/*
* 僔儕傾儖億乕僩弶婜壔僽儘僢僋
*/
typedef struct serial_port_initialization_block {
ID rcv_semid; /* 庴怣僶僢僼傽娗棟梡僙儅僼僅偺ID */
ID snd_semid; /* 憲怣僶僢僼傽娗棟梡僙儅僼僅偺ID */
} SPINIB;
static const SPINIB spinib_table[TNUM_PORT] = {
{ SERIAL_RCV_SEM1, SERIAL_SND_SEM1 },
#if TNUM_PORT >= 2
{ SERIAL_RCV_SEM2, SERIAL_SND_SEM2 },
#endif
#if TNUM_PORT >= 3
{ SERIAL_RCV_SEM3, SERIAL_SND_SEM3 },
#endif
};
/*
* 僔儕傾儖億乕僩娗棟僽儘僢僋
*/
typedef struct serial_port_control_block {
const SPINIB *spinib; /* 僔儖傾儖億乕僩弶婜壔僽儘僢僋 */
SIOPCB *siopcb; /* 僔儕傾儖I/O億乕僩娗棟僽儘僢僋 */
BOOL openflag; /* 僆乕僾儞嵪傒僼儔僌 */
UINT ioctl; /* 摦嶌惂屼偺愝掕抣 */
UINT rcv_read_ptr; /* 庴怣僶僢僼傽撉弌偟億僀儞僞 */
UINT rcv_write_ptr; /* 庴怣僶僢僼傽彂崬傒億僀儞僞 */
UINT rcv_count; /* 庴怣僶僢僼傽拞偺暥帤悢 */
char rcv_fc_chr; /* 憲傞傋偒 START/STOP */
BOOL rcv_stopped; /* STOP 傪憲偭偨忬懺偐丠 */
UINT snd_read_ptr; /* 憲怣僶僢僼傽撉弌偟億僀儞僞 */
UINT snd_write_ptr; /* 憲怣僶僢僼傽彂崬傒億僀儞僞 */
UINT snd_count; /* 憲怣僶僢僼傽拞偺暥帤悢 */
BOOL snd_stopped; /* STOP 傪庴偗庢偭偨忬懺偐丠 */
char rcv_buffer[SERIAL_BUFSZ]; /* 庴怣僶僢僼傽 */
char snd_buffer[SERIAL_BUFSZ]; /* 憲怣僶僢僼傽 */
} SPCB;
static SPCB spcb_table[TNUM_PORT];
/*
* 僔儕傾儖億乕僩ID偐傜僔儕傾儖億乕僩娗棟僽儘僢僋傪庢傝弌偡偨傔偺儅僋儘
*/
#define INDEX_PORT(portid) ((UINT)((portid) - 1))
#define get_spcb(portid) (&(spcb_table[INDEX_PORT(portid)]))
/*
* 億僀儞僞偺僀儞僋儕儊儞僩
*/
#define INC_PTR(ptr) { if (++ptr == SERIAL_BUFSZ) ptr = 0; }
/*
* 僔儕傾儖僀儞僞僼僃乕僗僪儔僀僶偺弶婜壔儖乕僠儞
*/
void
serial_initialize(VP_INT exinf)
{
SPCB *spcb;
UINT i;
sio_initialize();
for (spcb = spcb_table, i = 0; i < TNUM_PORT; spcb++, i++) {
spcb->spinib = &(spinib_table[i]);
spcb->openflag = FALSE;
}
}
/*
* 僔儕傾儖億乕僩偺僆乕僾儞
*/
ER
serial_opn_por(ID portid)
{
SPCB *spcb;
ER ercd;
if (sns_ctx()) { /* 僐儞僥僉僗僩偺僠僃僢僋 */
return(E_CTX);
}
if (!(1 <= portid && portid <= TNUM_PORT)) {
return(E_ID); /* 億乕僩斣崋偺僠僃僢僋 */
}
spcb = get_spcb(portid);
_syscall(loc_cpu());
if (spcb->openflag) { /* 僆乕僾儞嵪傒偐偺僠僃僢僋 */
ercd = E_OBJ;
}
else {
/*
* 曄悢偺弶婜壔
*/
spcb->ioctl = (IOCTL_ECHO | IOCTL_CRLF
| IOCTL_FCSND | IOCTL_FCRCV);
spcb->rcv_read_ptr = spcb->rcv_write_ptr = 0;
spcb->rcv_count = 0;
spcb->rcv_fc_chr = '\0';
spcb->rcv_stopped = FALSE;
spcb->snd_read_ptr = spcb->snd_write_ptr = 0;
spcb->snd_count = 0;
spcb->snd_stopped = FALSE;
/*
* 僴乕僪僂僃傾埶懚偺僆乕僾儞張棟
*/
spcb->siopcb = sio_opn_por(portid, (VP_INT) spcb);
/*
* 庴怣捠抦僐乕儖僶僢僋傪嫋壜偡傞丏
*/
sio_ena_cbr(spcb->siopcb, SIO_ERDY_RCV);
spcb->openflag = TRUE;
ercd = E_OK;
}
_syscall(unl_cpu());
return(ercd);
}
/*
* 僔儕傾儖億乕僩偺僋儘乕僘
*/
ER
serial_cls_por(ID portid)
{
SPCB *spcb;
ER ercd;
if (sns_ctx()) { /* 僐儞僥僉僗僩偺僠僃僢僋 */
return(E_CTX);
}
if (!(1 <= portid && portid <= TNUM_PORT)) {
return(E_ID); /* 億乕僩斣崋偺僠僃僢僋 */
}
spcb = get_spcb(portid);
_syscall(loc_cpu());
if (!(spcb->openflag)) { /* 僆乕僾儞嵪傒偐偺僠僃僢僋 */
ercd = E_OBJ;
}
else {
/*
* 僴乕僪僂僃傾埶懚偺僋儘乕僘張棟
*/
sio_cls_por(spcb->siopcb);
spcb->openflag = FALSE;
ercd = E_OK;
}
_syscall(unl_cpu());
return(ercd);
}
/*
* 僔儕傾儖億乕僩傊偺暥帤憲怣
*/
Inline BOOL
serial_snd_chr(SPCB *spcb, char c)
{
if (sio_snd_chr(spcb->siopcb, c)) {
return(TRUE);
}
else {
sio_ena_cbr(spcb->siopcb, SIO_ERDY_SND);
return(FALSE);
}
}
/*
* 僔儕傾儖億乕僩傊偺憲怣
*/
static BOOL
serial_wri_chr(SPCB *spcb, char c)
{
BOOL buffer_full;
/*
* LF 偺慜偵 CR 傪憲怣偡傞丏
*/
if (c == '\n' && (spcb->ioctl & IOCTL_CRLF) != 0) {
if (serial_wri_chr(spcb, '\r')) {
_syscall(wai_sem(spcb->spinib->snd_semid));
}
}
_syscall(loc_cpu());
if (spcb->snd_count == 0 && !(spcb->snd_stopped)
&& serial_snd_chr(spcb, c)) {
/*
* 僔儕傾儖I/O僨僶僀僗偺憲怣儗僕僗僞偵暥帤傪擖傟傞偙
* 偲偵惉岟偟偨応崌丏
*/
buffer_full = FALSE;
}
else {
/*
* 憲怣僶僢僼傽偵暥帤傪擖傟傞丏
*/
spcb->snd_buffer[spcb->snd_write_ptr] = c;
INC_PTR(spcb->snd_write_ptr);
spcb->snd_count++;
buffer_full = (spcb->snd_count == SERIAL_BUFSZ);
}
_syscall(unl_cpu());
return(buffer_full);
}
ER_UINT
serial_wri_dat(ID portid, char *buf, UINT len)
{
SPCB *spcb;
BOOL buffer_full;
UINT i;
if (sns_dpn()) { /* 僐儞僥僉僗僩偺僠僃僢僋 */
return(E_CTX);
}
if (!(1 <= portid && portid <= TNUM_PORT)) {
return(E_ID); /* 億乕僩斣崋偺僠僃僢僋 */
}
spcb = get_spcb(portid);
if (!(spcb->openflag)) { /* 僆乕僾儞嵪傒偐偺僠僃僢僋 */
return(E_OBJ);
}
buffer_full = TRUE; /* 儖乕僾偺1夞傔偼 wai_sem 偡傞 */
for (i = 0; i < len; i++) {
if (buffer_full) {
_syscall(wai_sem(spcb->spinib->snd_semid));
}
buffer_full = serial_wri_chr(spcb, *buf++);
}
if (!buffer_full) {
_syscall(sig_sem(spcb->spinib->snd_semid));
}
return(len);
}
/*
* 僔儕傾儖億乕僩偐傜偺庴怣
*/
static BOOL
serial_rea_chr(SPCB *spcb, char *c)
{
BOOL buffer_empty;
_syscall(loc_cpu());
/*
* 庴怣僶僢僼傽偐傜暥帤傪庢傝弌偡丏
*/
*c = spcb->rcv_buffer[spcb->rcv_read_ptr];
INC_PTR(spcb->rcv_read_ptr);
spcb->rcv_count--;
buffer_empty = (spcb->rcv_count == 0);
/*
* START 傪憲怣偡傞丏
*/
if (spcb->rcv_stopped && spcb->rcv_count <= BUFCNT_START) {
if (!serial_snd_chr(spcb, FC_START)) {
spcb->rcv_fc_chr = FC_START;
}
spcb->rcv_stopped = FALSE;
}
_syscall(unl_cpu());
/*
* 僄僐乕僶僢僋張棟丏
*/
if ((spcb->ioctl & IOCTL_ECHO) != 0) {
_syscall(wai_sem(spcb->spinib->snd_semid));
if (!serial_wri_chr(spcb, *c)) {
_syscall(sig_sem(spcb->spinib->snd_semid));
}
}
return(buffer_empty);
}
ER_UINT
serial_rea_dat(ID portid, char *buf, UINT len)
{
SPCB *spcb;
BOOL buffer_empty;
UINT i;
if (sns_dpn()) { /* 僐儞僥僉僗僩偺僠僃僢僋 */
return(E_CTX);
}
if (!(1 <= portid && portid <= TNUM_PORT)) {
return(E_ID); /* 億乕僩斣崋偺僠僃僢僋 */
}
spcb = get_spcb(portid);
if (!(spcb->openflag)) { /* 僆乕僾儞嵪傒偐偺僠僃僢僋 */
return(E_OBJ);
}
buffer_empty = TRUE; /* 儖乕僾偺1夞傔偼 wai_sem 偡傞 */
for (i = 0; i < len; i++) {
if (buffer_empty) {
_syscall(wai_sem(spcb->spinib->rcv_semid));
}
buffer_empty = serial_rea_chr(spcb, buf++);
}
if (!buffer_empty) {
_syscall(sig_sem(spcb->spinib->rcv_semid));
}
return(len);
}
/*
* 僔儕傾儖億乕僩偺惂屼
*/
ER
serial_ctl_por(ID portid, UINT ioctl)
{
SPCB *spcb;
if (sns_ctx()) { /* 僐儞僥僉僗僩偺僠僃僢僋 */
return(E_CTX);
}
if (!(1 <= portid && portid <= TNUM_PORT)) {
return(E_ID); /* 億乕僩斣崋偺僠僃僢僋 */
}
spcb = get_spcb(portid);
if (!(spcb->openflag)) { /* 僆乕僾儞嵪傒偐偺僠僃僢僋 */
return(E_OBJ);
}
spcb->ioctl = ioctl;
return(E_OK);
}
/*
* 僔儕傾儖億乕僩忬懺偺嶲徠
*/
ER
serial_ref_por(ID portid, T_SERIAL_RPOR *pk_rpor)
{
SPCB *spcb;
if (sns_ctx()) { /* 僐儞僥僉僗僩偺僠僃僢僋 */
return(E_CTX);
}
if (!(1 <= portid && portid <= TNUM_PORT)) {
return(E_ID); /* 億乕僩斣崋偺僠僃僢僋 */
}
spcb = get_spcb(portid);
if (!(spcb->openflag)) { /* 僆乕僾儞嵪傒偐偺僠僃僢僋 */
return(E_OBJ);
}
pk_rpor->reacnt = spcb->rcv_count;
pk_rpor->wricnt = spcb->snd_count;
return(E_OK);
}
/*
* 僔儕傾儖億乕僩偐傜偺憲怣壜擻僐乕儖僶僢僋
*/
void
sio_ierdy_snd(VP_INT exinf)
{
SPCB *spcb;
spcb = (SPCB *) exinf;
if (spcb->rcv_fc_chr != '\0') {
/*
* START/STOP 傪憲怣偡傞丏
*/
(void) sio_snd_chr(spcb->siopcb, spcb->rcv_fc_chr);
spcb->rcv_fc_chr = '\0';
}
else if (!(spcb->snd_stopped) && spcb->snd_count > 0) {
/*
* 憲怣僶僢僼傽拞偐傜暥帤傪庢傝弌偟偰憲怣偡傞丏
*/
(void) sio_snd_chr(spcb->siopcb,
spcb->snd_buffer[spcb->snd_read_ptr]);
INC_PTR(spcb->snd_read_ptr);
if (spcb->snd_count == SERIAL_BUFSZ) {
_syscall(isig_sem(spcb->spinib->snd_semid));
}
spcb->snd_count--;
}
else {
/*
* 憲怣偡傋偒暥帤偑側偄応崌偼丆憲怣壜擻僐乕儖僶僢僋傪
* 嬛巭偡傞丏
*/
sio_dis_cbr(spcb->siopcb, SIO_ERDY_SND);
}
}
/*
* 僔儕傾儖億乕僩偐傜偺庴怣捠抦僐乕儖僶僢僋
*/
void
sio_ierdy_rcv(VP_INT exinf)
{
SPCB *spcb;
char c;
spcb = (SPCB *) exinf;
c = (char) sio_rcv_chr(spcb->siopcb);
if ((spcb->ioctl & IOCTL_FCSND) != 0 && c == FC_STOP) {
/*
* 憲怣傪堦帪掆巭偡傞丏憲怣拞偺暥帤偼偦偺傑傑憲怣偡傞丏
*/
spcb->snd_stopped = TRUE;
}
else if (spcb->snd_stopped && (c == FC_START
|| (spcb->ioctl & IOCTL_FCANY) != 0)) {
/*
* 憲怣傪嵞奐偡傞丏
*/
spcb->snd_stopped = FALSE;
if (spcb->snd_count > 0) {
c = spcb->snd_buffer[spcb->snd_read_ptr];
if (serial_snd_chr(spcb, c)) {
INC_PTR(spcb->snd_read_ptr);
if (spcb->snd_count == SERIAL_BUFSZ) {
_syscall(isig_sem(spcb->spinib
->snd_semid));
}
spcb->snd_count--;
}
}
}
else if ((spcb->ioctl & IOCTL_FCSND) != 0 && c == FC_START) {
/*
* 憲怣偵懳偟偰僼儘乕惂屼偟偰偄傞応崌丆START 偼幪偰傞丏
*/
}
else if (spcb->rcv_count == SERIAL_BUFSZ) {
/*
* 僶僢僼傽僼儖偺応崌丆庴怣偟偨暥帤傪幪偰傞丏
*/
}
else {
/*
* 庴怣偟偨暥帤傪庴怣僶僢僼傽偵擖傟傞丏
*/
spcb->rcv_buffer[spcb->rcv_write_ptr] = c;
INC_PTR(spcb->rcv_write_ptr);
if (spcb->rcv_count == 0) {
_syscall(isig_sem(spcb->spinib->rcv_semid));
}
spcb->rcv_count++;
/*
* STOP 傪憲怣偡傞丏
*/
if ((spcb->ioctl & IOCTL_FCRCV) != 0 && !(spcb->rcv_stopped)
&& (spcb->rcv_count >= BUFCNT_STOP)) {
if (!serial_snd_chr(spcb, FC_STOP)) {
spcb->rcv_fc_chr = FC_STOP;
}
spcb->rcv_stopped = TRUE;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -