home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Elysian Archive
/
AmigaElysianArchive.iso
/
comm
/
term23_2.lha
/
Source_Code
/
termSource
/
termSerial.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-08-18
|
21KB
|
1,091 lines
/*
** $Id: termSerial.c,v 1.3 92/08/15 20:15:13 olsen Sta Locker: olsen $
** $Revision: 1.3 $
** $Date: 92/08/15 20:15:13 $
**
** Serial driver support routines
**
** Copyright © 1990-1992 by Olaf `Olsen' Barthel & MXM
** All Rights Reserved
*/
#include "termGlobal.h"
/* Include the OwnDevUnit definitions. */
#include "OwnDevUnit.h"
/* Local copy of serial driver name and unit number. */
STATIC UBYTE SerialDevice[40];
STATIC LONG UnitNumber = -1;
/* SetFlags(struct IOExtSer *SomeRequest):
*
* Set the contents of a serial device request according
* to the current configuration settings.
*/
VOID __regargs
SetFlags(struct IOExtSer *SomeRequest)
{
SomeRequest -> io_Baud = Config . BaudRate;
SomeRequest -> io_BrkTime = Config . BreakLength;
SomeRequest -> io_ReadLen = Config . BitsPerChar;
SomeRequest -> io_WriteLen = Config . BitsPerChar;
SomeRequest -> io_StopBits = Config . StopBits;
SomeRequest -> io_ExtFlags &= ~(SEXTF_MSPON|SEXTF_MARK);
SomeRequest -> io_SerFlags &= ~(SERF_PARTY_ON|SERF_PARTY_ODD|SERF_7WIRE|SERF_RAD_BOOGIE);
switch(Config . Parity)
{
case PARITY_EVEN: SomeRequest -> io_SerFlags |= SERF_PARTY_ON;
break;
case PARITY_ODD: SomeRequest -> io_SerFlags |= SERF_PARTY_ON|SERF_PARTY_ODD;
break;
case PARITY_MARK: SomeRequest -> io_SerFlags |= SERF_PARTY_ON;
SomeRequest -> io_ExtFlags |= SEXTF_MSPON|SEXTF_MARK;
break;
case PARITY_SPACE: SomeRequest -> io_SerFlags |= SERF_PARTY_ON;
SomeRequest -> io_ExtFlags |= SEXTF_MSPON;
break;
default: break;
}
if(Config . HandshakingProtocol != HANDSHAKING_NONE)
SomeRequest -> io_SerFlags |= SERF_7WIRE;
if(Config . HighSpeed & ~SERIAL_SHARED)
SomeRequest -> io_SerFlags |= SERF_RAD_BOOGIE;
if(Config . HighSpeed & SERIAL_SHARED)
SomeRequest -> io_SerFlags |= SERF_SHARED;
SomeRequest -> io_SerFlags |= SERF_XDISABLED;
}
/* GetFlags(struct Configuration *Config,struct IOExtSer *SomeRequest):
*
* Update configuration with serial settings.
*/
VOID __regargs
GetFlags(struct Configuration *Config,struct IOExtSer *SomeRequest)
{
Config -> BaudRate = SomeRequest -> io_Baud;
Config -> BreakLength = SomeRequest -> io_BrkTime;
Config -> BitsPerChar = SomeRequest -> io_ReadLen;
Config -> BitsPerChar = SomeRequest -> io_WriteLen;
Config -> StopBits = SomeRequest -> io_StopBits;
if(SomeRequest -> io_SerFlags & SERF_PARTY_ON)
{
if(SomeRequest -> io_SerFlags & SERF_PARTY_ODD)
Config -> Parity = PARITY_ODD;
else
{
if(SomeRequest -> io_ExtFlags & SEXTF_MSPON)
{
if(SomeRequest -> io_ExtFlags & SEXTF_MARK)
Config -> Parity = PARITY_MARK;
else
Config -> Parity = PARITY_SPACE;
}
}
}
else
Config -> Parity = PARITY_NONE;
if(SomeRequest -> io_SerFlags & SERF_7WIRE)
Config -> HandshakingProtocol = HANDSHAKING_RTSCTS;
else
Config -> HandshakingProtocol = HANDSHAKING_NONE;
if(SomeRequest -> io_SerFlags & SERF_RAD_BOOGIE)
Config -> HighSpeed = TRUE;
else
Config -> HighSpeed = FALSE;
if(SomeRequest -> io_SerFlags & SERF_SHARED)
Config -> HighSpeed |= SERIAL_SHARED;
SomeRequest -> io_SerFlags |= SERF_XDISABLED;
}
/* CallMenu(UBYTE *Name,ULONG Code):
*
* Call a menu function either through the name of the corresponding
* menu item or a menu number.
*/
STATIC VOID __regargs
CallMenu(UBYTE *Name,ULONG Code)
{
WORD MenuNum = -1,Item = 0,Sub = 0,i;
/* Are we to look for a name? */
if(Name)
{
WORD Len = strlen(Name);
/* Scan the menu list... */
for(i = 0 ; TermMenu[i] . nm_Type != NM_END ; i++)
{
switch(TermMenu[i] . nm_Type)
{
case NM_TITLE: MenuNum++;
Item = Sub = 0;
break;
case NM_ITEM: Sub = 0;
break;
}
/* Did we get a valid name string? */
if(TermMenu[i] . nm_Label != NM_BARLABEL)
{
/* Does the name match our template? */
if(!Strnicmp(TermMenu[i] . nm_Label,Name,Len))
{
struct MenuItem *MenuItem = ItemAddress(Menu,FULLMENUNUM(MenuNum,Item,Sub));
if(MenuItem)
HandleCode((ULONG)TermMenu[i] . nm_UserData,NULL,MenuItem);
break;
}
}
switch(TermMenu[i] . nm_Type)
{
case NM_ITEM: Item++;
break;
case NM_SUB: Sub++;
break;
}
}
}
else
{
WORD TheMenu = Code % 100,
TheItem = (Code / 100) % 100,
TheSub = Code / 10000;
/* Scan the menu list... */
for(i = 0 ; TermMenu[i] . nm_Type != NM_END ; i++)
{
switch(TermMenu[i] . nm_Type)
{
case NM_TITLE: MenuNum++;
Item = Sub = 0;
break;
case NM_ITEM: Sub = 0;
break;
}
/* Is it the menu number we want? */
if(TheMenu == MenuNum && TheItem == Item && TheSub == Sub)
{
if(TermMenu[i] . nm_Label != NM_BARLABEL)
{
struct MenuItem *MenuItem = ItemAddress(Menu,FULLMENUNUM(MenuNum,Item,Sub));
if(MenuItem)
HandleCode((ULONG)TermMenu[i] . nm_UserData,NULL,MenuItem);
}
break;
}
switch(TermMenu[i] . nm_Type)
{
case NM_ITEM: Item++;
break;
case NM_SUB: Sub++;
break;
}
}
}
}
/* SerialCommand(UBYTE *String):
*
* Send a command string to the serial line and
* interprete the control sequences.
*/
VOID __regargs
SerialCommand(UBYTE *String)
{
LONG Count = 0,i,Len = strlen(String);
BYTE GotControl = FALSE,
GotEscape = FALSE,
OldStatus,
BlockSet;
/* Scan the string. */
for(i = 0 ; i < Len ; i++)
{
/* We are looking for plain characters
* and the control ('\') and escape
* ('^') characters.
*/
if(!GotControl && !GotEscape)
{
/* Got a control character,
* the next byte will probably be
* a command sequence.
*/
if(String[i] == '\\')
{
GotControl = TRUE;
continue;
}
/* Got an escape character,
* the next byte will be some
* kind of control character
* (such as XON, XOF, bell, etc.).
*/
if(String[i] == '^')
{
GotEscape = TRUE;
continue;
}
/* This tells us to wait another
* second before continuing with
* the scanning.
*/
if(String[i] == '~')
{
if(Count)
{
SerWrite(SharedBuffer,Count);
Count = 0;
}
WaitTime(0,MILLION / 2);
HandleSerial();
continue;
}
/* Stuff the character into the
* buffer.
*/
SharedBuffer[Count++] = String[i];
}
else
{
/* Convert the character to a control
* style character (^C, etc.).
*/
if(GotEscape)
{
if(ToUpper(String[i]) >= 'A' && ToUpper(String[i]) <= '_')
SharedBuffer[Count++] = ToUpper(String[i]) - '@';
else
SharedBuffer[Count++] = String[i];
GotEscape = FALSE;
}
/* The next character represents a command. */
if(GotControl)
{
switch(ToUpper(String[i]))
{
/* Execute an AmigaDOS command. */
case 'D': if(!WeAreBlocking)
{
BlockSet = TRUE;
BlockWindows();
}
else
BlockSet = FALSE;
SendAmigaDOSCommand(&String[i + 1]);
if(BlockSet)
ReleaseWindows();
return;
/* Execute an ARexx command. */
case 'A': if(!WeAreBlocking)
{
BlockSet = TRUE;
BlockWindows();
}
else
BlockSet = FALSE;
SendARexxCommand(&String[i + 1]);
if(BlockSet)
ReleaseWindows();
return;
/* Add the control character ('\'). */
case '\\': SharedBuffer[Count++] = '\\';
break;
/* This is a backspace. */
case 'B': SharedBuffer[Count++] = '\b';
break;
/* This is a form feed. */
case 'F': SharedBuffer[Count++] = '\f';
break;
/* This is a line feed. */
case 'N': SharedBuffer[Count++] = '\n';
break;
/* Send the current password. */
case 'P': if(Password[0])
{
if(Count)
{
SerWrite(SharedBuffer,Count);
Count = 0;
}
SerWrite(Password,strlen(Password));
}
break;
/* This is a carriage return. */
case 'R': SharedBuffer[Count++] = '\r';
break;
/* This is a tab. */
case 'T': SharedBuffer[Count++] = '\t';
break;
/* Send the current user name. */
case 'U': if(UserName[0])
{
if(Count)
{
SerWrite(SharedBuffer,Count);
Count = 0;
}
SerWrite(UserName,strlen(UserName));
}
break;
/* Send a break across the serial line. */
case 'X': if(Count)
{
SerWrite(SharedBuffer,Count);
Count = 0;
}
if(WriteRequest)
{
OldStatus = Status;
Status = STATUS_BREAKING;
WriteRequest -> IOSer . io_Command = SDCMD_BREAK;
DoIO(WriteRequest);
Status = OldStatus;
}
break;
/* Feed the contents of the
* clipboard into the input
* stream.
*/
case 'I': if(Count)
SerWrite(SharedBuffer,Count);
Count = LoadClip(SharedBuffer,256);
break;
/* Send a string to the clipboard. */
case 'G': if(String[i + 1])
SaveClip(&String[i + 1],strlen(&String[i + 1]));
return;
/* Produce the escape character. */
case 'E': SharedBuffer[Count++] = ESC;
break;
/* Call a menu item. */
case 'C': i++;
/* Scan for a menu number or
* a single quote...
*/
while(i < Len)
{
if(String[i] >= '0' && String[i] <= '9')
break;
if(String[i] == '\'')
break;
if(String[i] != ' ')
break;
i++;
}
if(i < Len)
{
UBYTE DummyBuffer[256];
/* Did we get a quote? */
if(String[i] == '\'')
{
LONG Start = ++i;
if(String[Start])
{
WORD Length;
while(i < Len)
{
if(String[i] != '\'')
i++;
else
break;
}
if(String[i] == '\'')
Length = i - Start;
else
Length = i - Start + 1;
memcpy(DummyBuffer,&String[Start],Length);
DummyBuffer[Length] = 0;
CallMenu(DummyBuffer,0);
}
}
else
{
if(String[i] >= '0' && String[i] <= '9')
{
LONG Start = i,Length;
while(i < Len)
{
if(String[i] >= '0' && String[i] <= '9')
i++;
else
break;
}
if(i == Start)
Length = 1;
else
Length = i - Start;
memcpy(DummyBuffer,&String[Start],Length);
DummyBuffer[Length] = 0;
CallMenu(NULL,atol(DummyBuffer));
}
}
}
break;
/* Stuff the character into the buffer. */
default: SharedBuffer[Count++] = String[i];
break;
}
GotControl = FALSE;
}
}
/* If the buffer is full, release it. */
if(Count == 256)
{
SerWrite(SharedBuffer,Count);
Count = 0;
}
}
if(Count)
SerWrite(SharedBuffer,Count);
}
/* SerWrite(APTR Buffer,LONG Size):
*
* Send a number of bytes across the serial line.
*/
VOID __regargs
SerWrite(APTR Buffer,LONG Size)
{
if(WriteRequest && Size)
{
if(XProtocolBase)
{
/* xpr wants to see the data before it is
* transferred.
*/
if(TransferBits & XPRS_USERMON)
{
if(!(Size = XProtocolUserMon(XprIO,Buffer,Size,Size)))
return;
}
}
BytesOut += Size;
/* If full duplex is enabled, send the entire
* buffer.
*/
if(Config . Duplex == DUPLEX_FULL)
{
WriteRequest -> IOSer . io_Command = CMD_WRITE;
WriteRequest -> IOSer . io_Data = Buffer;
WriteRequest -> IOSer . io_Length = Size;
DoIO(WriteRequest);
}
else
{
if(XEmulatorBase)
{
WriteRequest -> IOSer . io_Command = CMD_WRITE;
WriteRequest -> IOSer . io_Data = Buffer;
WriteRequest -> IOSer . io_Length = Size;
SendIO(WriteRequest);
ConProcess(Buffer,Size);
WaitIO(WriteRequest);
}
else
{
UBYTE *ByteBuffer = Buffer;
/* Half duplex is enabled, send only
* a single character at a time.
*/
while(Size--)
{
WriteRequest -> IOSer . io_Command = CMD_WRITE;
WriteRequest -> IOSer . io_Length = 1;
WriteRequest -> IOSer . io_Data = ByteBuffer;
SendIO(WriteRequest);
ConProcess(ByteBuffer,1);
WaitIO(WriteRequest);
ByteBuffer++;
}
}
}
}
}
/* ClearSerial():
*
* Terminate all read/write activity on the serial
* line.
*/
VOID
ClearSerial()
{
if(ReadRequest)
{
if(!CheckIO(ReadRequest))
AbortIO(ReadRequest);
WaitIO(ReadRequest);
}
if(WriteRequest)
{
WriteRequest -> IOSer . io_Command = CMD_CLEAR;
DoIO(WriteRequest);
}
}
/* DropDTR():
*
* Drop the data terminal ready signal (i.e. close, wait a bit
* and then reopen the serial drive).
*/
BYTE
DropDTR()
{
/* Finish all serial read activity. */
ClearSerial();
/* Do we have any channels to work with? */
if(ReadRequest && WriteRequest)
{
/* Close the device. */
CloseDevice(ReadRequest);
/* Wait a bit. */
WaitTime(1,0);
/* Set up the original configuration data. */
SetFlags(ReadRequest);
ReadRequest -> io_RBufLen = Config . SerBuffSize;
/* Reopen the driver. */
if(!OpenDevice(Config . SerialDevice,Config . UnitNumber,ReadRequest,0))
{
struct MsgPort *WritePort = WriteRequest -> IOSer . io_Message . mn_ReplyPort;
/* Fill in the rest. */
CopyMem(ReadRequest,WriteRequest,sizeof(struct IOExtSer));
WriteRequest -> IOSer . io_Message . mn_ReplyPort = WritePort;
WriteRequest -> IOSer . io_Command = SDCMD_SETPARAMS;
SetFlags(WriteRequest);
DoIO(WriteRequest);
/* Restart read activity. */
ReadRequest -> IOSer . io_Command = CMD_READ;
ReadRequest -> IOSer . io_Data = ReadBuffer;
ReadRequest -> IOSer . io_Length = 1;
SetSignal(0,SIG_SERIAL);
SendIO(ReadRequest);
return(TRUE);
}
else
DeleteSerial();
}
else
{
DeleteSerial();
return(TRUE);
}
return(FALSE);
}
/* DeleteSerial():
*
* Close the serial device and release all associated
* resources.
*/
VOID
DeleteSerial()
{
BYTE Closed = FALSE;
if(ReadRequest)
{
if(ReadRequest -> IOSer . io_Device)
{
if(!(Config . HighSpeed & SERIAL_SHARED))
{
ReadRequest -> IOSer . io_Command = CMD_RESET;
DoIO(ReadRequest);
}
CloseDevice(ReadRequest);
Closed = TRUE;
}
DeleteIORequest(ReadRequest);
ReadRequest = NULL;
}
if(WriteRequest)
{
if(WriteRequest -> IOSer . io_Device && !Closed)
{
if(!(Config . HighSpeed & SERIAL_SHARED))
{
ReadRequest -> IOSer . io_Command = CMD_RESET;
DoIO(ReadRequest);
}
CloseDevice(WriteRequest);
}
if(WriteRequest -> IOSer . io_Message . mn_ReplyPort)
DeleteMsgPort(WriteRequest -> IOSer . io_Message . mn_ReplyPort);
DeleteIORequest(WriteRequest);
WriteRequest = NULL;
}
if(ReadPort)
{
DeleteMsgPort(ReadPort);
ReadPort = NULL;
}
if(ReadBuffer)
{
FreeVec(ReadBuffer);
ReadBuffer = NULL;
}
if(HostReadBuffer)
{
FreeVec(HostReadBuffer);
HostReadBuffer = NULL;
}
if(OwnDevUnitBase && SerialDevice[0] && UnitNumber != -1)
{
FreeDevUnit(SerialDevice,UnitNumber);
SerialDevice[0] = 0;
UnitNumber = -1;
}
}
/* GetSerialError(LONG Error,BYTE *Reset):
*
* Return an error message for each possible serial device error.
*/
STRPTR
GetSerialError(LONG Error,BYTE *Reset)
{
switch(Error)
{
case SerErr_DevBusy: if(Reset)
*Reset = FALSE;
return(LocaleString(MSG_SERIAL_ERROR_DEVBUSY_TXT));
case SerErr_BaudMismatch: if(Reset)
*Reset = TRUE;
return(LocaleString(MSG_SERIAL_ERROR_BAUDMISMATCH_TXT));
case SerErr_BufErr: if(Reset)
*Reset = FALSE;
return(LocaleString(MSG_SERIAL_ERROR_BUFERR_TXT));
case SerErr_InvParam: if(Reset)
*Reset = TRUE;
return(LocaleString(MSG_SERIAL_ERROR_INVPARAM_TXT));
case SerErr_LineErr: if(Reset)
*Reset = FALSE;
return(LocaleString(MSG_SERIAL_ERROR_LINEERR_TXT));
case SerErr_ParityErr: if(Reset)
*Reset = TRUE;
return(LocaleString(MSG_SERIAL_ERROR_PARITYERR_TXT));
case SerErr_TimerErr: if(Reset)
*Reset = FALSE;
return(LocaleString(MSG_SERIAL_ERROR_TIMERERR_TXT));
case SerErr_BufOverflow: if(Reset)
*Reset = FALSE;
return(LocaleString(MSG_SERIAL_ERROR_BUFOVERFLOW_TXT));
case SerErr_NoDSR: if(Reset)
*Reset = FALSE;
return(LocaleString(MSG_SERIAL_ERROR_NODSR_TXT));
/* case SerErr_UnitBusy: */
case 16: if(Reset)
*Reset = FALSE;
return(LocaleString(MSG_SERIAL_ERROR_UNIT_BUSY_TXT));
default: return(NULL);
}
}
/* CreateSerial():
*
* Create handles for the serial device and open it.
*/
UBYTE *
CreateSerial()
{
struct MsgPort *WritePort;
/* If OwnDevUnit.library is available, try to lock
* the serial driver.
*/
Start: if(OwnDevUnitBase)
{
UBYTE *Error;
/* Attempt to lock the device unit... */
if(Error = AttemptDevUnit(Config . SerialDevice,Config . UnitNumber,TermIDString,NULL))
{
/* Check for error type if any. */
if(!Strnicmp(Error,ODUERR_LEADCHAR,1))
SPrintf(SharedBuffer,LocaleString(MSG_SERIAL_ERROR_ACCESSING_TXT),Config . SerialDevice,Config . UnitNumber,&Error[1]);
else
SPrintf(SharedBuffer,LocaleString(MSG_SERIAL_DEVICE_IN_USE_TXT),Config . SerialDevice,Config . UnitNumber,Error);
SerialDevice[0] = 0;
UnitNumber = -1;
return(SharedBuffer);
}
else
{
strcpy(SerialDevice,Config . SerialDevice);
UnitNumber = Config . UnitNumber;
}
}
if(ReadBuffer = AllocVec(Config . SerBuffSize,MEMF_ANY))
{
if(XProtocolBase && (TransferBits & XPRS_HOSTNOWAIT))
HostReadBuffer = AllocVec(Config . SerBuffSize,MEMF_ANY);
else
HostReadBuffer = NULL;
if(ReadPort = (struct MsgPort *)CreateMsgPort())
{
if(ReadRequest = (struct IOExtSer *)CreateIORequest(ReadPort,sizeof(struct IOExtSer)))
{
LONG Error;
SetFlags(ReadRequest);
ReadRequest -> io_RBufLen = Config . SerBuffSize;
if(!(Error = OpenDevice(Config . SerialDevice,Config . UnitNumber,ReadRequest,0)))
{
if(WritePort = (struct MsgPort *)CreateMsgPort())
{
if(WriteRequest = (struct IOExtSer *)CreateIORequest(WritePort,sizeof(struct IOExtSer)))
{
CopyMem(ReadRequest,WriteRequest,sizeof(struct IOExtSer));
WriteRequest -> IOSer . io_Message . mn_ReplyPort = WritePort;
WriteRequest -> IOSer . io_Command = SDCMD_SETPARAMS;
SetFlags(WriteRequest);
DoIO(WriteRequest);
/* If RTS/CTS (7 wire handshaking) is
* selected, have a look at the DSR
* line to see whether the modem
* connected is willing to support
* this handshaking mode.
*/
if(Config . HandshakingProtocol == HANDSHAKING_RTSCTS_DSR)
{
Retry: WriteRequest -> IOSer . io_Command = SDCMD_QUERY;
DoIO(WriteRequest);
/* If the line happens to
* be high, there is no
* DSR signal present.
*/
if(WriteRequest -> io_Status & (1 << 3))
{
if(MyEasyRequest(Window,LocaleString(MSG_SERIAL_NO_DSR_SIGNAL_TXT),LocaleString(MSG_SERIAL_RETRY_CANCEL_TXT)))
goto Retry;
else
{
DeleteSerial();
Config . HandshakingProtocol = HANDSHAKING_NONE;
SerialMessage = LocaleString(MSG_SERIAL_NO_DSR_SIGNAL_HANDSHAKING_DISABLED_TXT);
goto Start;
}
}
}
ReadRequest -> IOSer . io_Command = CMD_READ;
ReadRequest -> IOSer . io_Data = ReadBuffer;
ReadRequest -> IOSer . io_Length = 1;
SetSignal(0,SIG_SERIAL);
SendIO(ReadRequest);
return(NULL);
}
else
{
SerialMessage = NULL;
DeleteSerial();
return(LocaleString(MSG_SERIAL_NOT_ENOUGH_MEMORY_TXT));
}
}
else
{
SerialMessage = NULL;
DeleteSerial();
return(LocaleString(MSG_SERIAL_FAILED_TO_CREATE_WRITE_PORT_TXT));
}
}
else
{
STRPTR String;
ReadRequest -> IOSer . io_Device = NULL;
DeleteSerial();
SerialMessage = NULL;
if(!(String = GetSerialError(Error,NULL)))
String = LocaleString(MSG_SERIAL_ERROR_DEVBUSY_TXT);
SPrintf(SharedBuffer,String,Config . SerialDevice,Config . UnitNumber);
return(SharedBuffer);
}
}
else
{
SerialMessage = NULL;
DeleteSerial();
return(LocaleString(MSG_SERIAL_NOT_ENOUGH_MEMORY_TXT));
}
}
else
{
SerialMessage = NULL;
DeleteSerial();
return(LocaleString(MSG_SERIAL_FAILED_TO_CREATE_READ_PORT_TXT));
}
}
else
{
SerialMessage = NULL;
DeleteSerial();
return(LocaleString(MSG_SERIAL_NOT_ENOUGH_MEMORY_TXT));
}
}