⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ttyld.cpp

📁 一个嵌入式系统的C代码
💻 CPP
字号:
//*************************************************************************//  MODULE : TTYLD.CPP - Line Dicipline driver for Terminal devices	  *//  AUTHOR : Ron Chernich                                                 *//  PURPOSE: This class used by RCOS to perform text line input for a	  *//	     Terminal. It performs simple editing (destructive backspace) *//	     input echo and "break" condition checks. One is instantiated *//	     the Kernel when a terminal is OPENED in buffered mode.	  *//	     Concept and design based on Chapter 10 of Bach, M.J. (1986): *//	     "The Design of the Unix Operating System", Prentice-Hall Inc *//  HISTORY:                                                              *//   20-APR-93	Material split from CONX module.			  *//   14-MAY-93	Bug!  <LnReq> not advancing nStart after posting message  *//   20-APR-94  Memory leak through CbNew fixed (Ron, use the Stack!)	  *//*************************************************************************#include "ttyld.hpp"#include "kernel.hpp"/////////////// globals define ansi sequences to destructively backspace, etc//#define LEN_BKSP    4		// length of array declared in LnEdit()#define CLR_SCRN    AFF 	// char to clear screen and home cursor/////////////////////////////////////////////////////////////////////////////		Line Protocol Character Block Methods//-------------------------------------------------------------------------// We can initialsze new CBLOCKS on the stack, 'cause the Double Link List// class copies the passed data to memory allocated from the heap.//PCBLOCK Cblock::CbNew (void){  CBLOCK NewCb;  NewCb.nStart = NewCb.nEnd = 0;  return (PCBLOCK)DblAppend((void*)&NewCb, sizeof(CBLOCK));}/////////////////////////////////////////////////////////////////////////////			TTY Line Driver Methods//-------------------------------------------------------------------------// Initialize our Tx/Rx ports, register with the kernel and ask the her// for a terminal.  If we get a terminal (and we bloody well better, since// the kernel has made sure one is available before calling us into being),// we clear its screen, then request a character. This effectively puts us// to sleep, waiting on some input.//LnDrv::LnDrv (UINT16 n, UINT16 id, Knl *pK)     : port(id, CLS_SysRes, pK), uPid(n){  bBreakOn = TRUE;  cDelim = (char)ACR;  nChReq = nBlkReq = 0;  MSG msg(uID, KM_Open, CLS_VDU, (void*)(TTY_UseANSI));  pTx->SendMsg(ID_Kernel, &msg);  if ((uTerm = msg.wParam) != ID_NULL) {    MSG msg(uID, KM_Read);    pTx->PostMsg(uTerm, &msg);  }}////////////////// Destructor closes the terminal (which flushes its buffers) and closes// our Registration with the Kernel. The DblList destructor will cleanup// any unused CBLOCKS.//LnDrv::~LnDrv (void){  MSG msg(uID, KM_Close, uTerm);  pTx->SendMsg(ID_Kernel, &msg);  msg = message(uID, KM_CheckOut);  pTx->SendMsg(ID_Kernel, &msg);}///////////////////// Line Driver receive port Write requests may only come from our "owner"// PID, or the Kernel, so just process 'em.  Read messages can be requests// from the PID (normally block requests), or raw data from terminal.  Raw// data goes through the edit routine (and thence, back to the terminal).// NOTE NASTY TRICK - if an IoCtrl message is not a Break On/Off, it FALLS// THROUGH and is sent/posted to the TTY driver.//void LnDrv::RxPort (PMSG pM){  switch (pM->wMsgType & ~MM_Sync) {    case KM_IoCtrl:      if ((pM->wParam == DM_BreakOn) || (pM->wParam == DM_BreakOff)) {	bBreakOn = (BOOL)(pM->wParam == DM_BreakOn);	return;      }    case KM_Write:    case KM_WriteBlk:      pM->wSender = uID;      if (IS_SYNCH(pM->wMsgType))	pTx->SendMsg(uTerm, pM);      else	pTx->PostMsg(uTerm, pM);      break;    case KM_ReadBlk:      LnReq();      break;    case KM_Read:      if (pM->wSender == uTerm)	LnEdit((char)pM->wParam);      else {	PCBLOCK pCB = Cblk.CbHead();	if (pCB == NULL)	  ++nChReq;	else {	  pM->wSender = uID;	  pM->wParam = (UINT16)(pCB->cBuf[pCB->nStart++]);	  if (pCB->nStart >= CBLOCK_LEN)	    Cblk.CbDrop();	  pTx->PostMsg(uPid, pM);	}      }      break;  default :    DevError(ET_NoSupport, FALSE);  }}//////////////// Input and line editing routine.  If the char is a backspace (and we// have something to backspace into), backup the buffered data and sned// an appropriate sequence to the terminal. Otherwise put the char in the// buffer(s) and if it was a block delimiter and we have any outstanding// requests for a data block, process the buffer.//// NOTE: At this time, all delimiters are CR's, but in the future, our//   PLL/2 compiler may want to READ space delimited numeric variables..//   hence the two tests for <cDelim> and <ACR>.//void LnDrv::LnEdit (char ch){  MSG msg;  PCBLOCK pCB = Cblk.CbTail();  static char arrBksp[] = { BKSP, ESC, '[', 'K' };  if ((ch == BREAK_CHAR) && bBreakOn) {    msg = message(uID, KM_Break, uTerm);    pTx->PostMsg(uPid, &msg);    return;  }  if ((ch == BKSP) && pCB) {    char *cp = new char[LEN_BKSP];    memcpy(cp, arrBksp, LEN_BKSP);    msg = message(uID, KM_WriteBlk, LEN_BKSP, (void*)cp);    pTx->PostMsg(uTerm, &msg);    if (--(pCB->nEnd) < 0)      Cblk.CbDrop();  }  if ((ch == ACR) || ((ch >= ' ') && (ch < DEL))) {    if (pCB == NULL)      pCB = Cblk.CbNew();    pCB->cBuf[pCB->nEnd++] = ch;    if (pCB->nEnd >= CBLOCK_LEN)      Cblk.CbNew();    msg = message(uID, KM_Write, (UINT16)ch);    pTx->SendMsg(uTerm, &msg);    if (nBlkReq && ((ch == cDelim) || (ch == ACR)))      LnReq();  }  msg = message(uID, KM_Read);  pTx->PostMsg(uTerm, &msg);}////////////////////// This routine is called when we have an outstanding request for data,// AND we have just received a block terminator char, OR WHEN we have no// idea if we have a full block or not, but a request has been received.// In the latter case, if it turns out the data is yet to be terminated,// we simply up the count on the number of blocks we are waiting for.// The process is not as wastefull as it looks.  A request may cause a// single, fruitless char scan through the buffer(s) for a terminator,// but the request itself has put the sender to sleep - we will wake it// up when the terminator finally arrives.//// NOTE: The actual terminator is removed from the buffer, but not//	 included in the posted data block count.//void LnDrv::LnReq (void){  INT16 n = 0;  PCBLOCK pCB = Cblk.CbHead();  while (pCB) {    for (INT16 i = pCB->nStart; i < pCB->nEnd; i++, n++) {      if ((pCB->cBuf[i] == cDelim) || (pCB->cBuf[i] == ACR)) {	pCB = Cblk.CbHead();	char *pBlk = new char[n];	for (i = 0; i <= n; i++) {	  if (i == n)	    pCB->nStart++;	  else	    pBlk[i] = pCB->cBuf[pCB->nStart++];	  if (pCB->nStart >= CBLOCK_LEN) {	    Cblk.CbDrop();	    pCB = Cblk.CbHead();	  }	}	MSG msg(uID, KM_ReadBlk, n, (void*)pBlk);	pTx->PostMsg(uPid, &msg);	if (nBlkReq)	  --nBlkReq;	return;      }    }    pCB = Cblk.CbNext();  }  ++nBlkReq;}/********************************** eof **********************************/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -