home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gold Fish 2
/
goldfish_vol2_cd1.bin
/
files
/
comm
/
misc
/
cyberpager
/
source
/
dialer
/
serial.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-10-05
|
13KB
|
627 lines
#include "/include/memory.h"
#include "dialer.h"
/*
* note that you probably don't want to have both debug's turned on at the
* same time...
*/
/* #define DEBUG_WRITES */
/* #define DEBUG_READS */
/* storage for various magic items */
static struct IOExtSer SerialRead;
static struct IOExtSer SerialWrite;
static struct MsgPort *SReadPort;
static struct MsgPort *SWritePort;
static ULONG SReadSigMask;
static ULONG SWriteSigMask;
static BOOL SerialUp = FALSE;
static UBYTE SReadBuf[256];
static ULONG SReadPos;
static ULONG SReadSize;
static UBYTE SWriteBuf[256];
static ULONG SWritePos;
/* hold some magic info */
static struct MsgPort *TimerPort;
struct timerequest TimerIO;
ULONG TimerSigMask;
BOOL TimerUp = FALSE;
/* open up the timer for use */
static BOOL OpenTimer(void)
{
if (!(TimerPort = CreatePort(NULL, 0)))
return FALSE;
TimerSigMask = 1L << TimerPort->mp_SigBit;
if (OpenDevice(TIMERNAME, UNIT_VBLANK, (struct IORequest *)&TimerIO, 0)) {
DeletePort(TimerPort);
return FALSE;
}
TimerIO.tr_node.io_Message.mn_ReplyPort = TimerPort;
TimerUp = TRUE;
return TRUE;
}
/* shut down our timer handling stuff */
static void CloseTimer(void)
{
if (TimerUp) {
CloseDevice((struct IORequest *)&TimerIO);
DeletePort(TimerPort);
TimerUp = FALSE;
}
}
typedef struct {
STRPTR mi_Device;
ULONG mi_Unit;
ULONG mi_MaxBaud;
BOOL mi_MatchDTE;
BOOL mi_CTSRTS;
UBYTE mi_ModemInit[1];
}
ModemInfo_t;
ModemInfo_t *openedMi = NULL;
ULONG currentBaud;
BOOL use8N1;
/* try and OpenDevice() and set the appropriate serial parameters */
static BOOL InitSer(ModemInfo_t * mi)
{
register struct IOExtSer *ior = &SerialRead;
register struct IOExtSer *iow = &SerialWrite;
/* try and open the device */
ior->io_SerFlags = 0;
if (mi->mi_CTSRTS)
ior->io_SerFlags |= SERF_7WIRE;
else
ior->io_SerFlags &= ~SERF_7WIRE;
ior->IOSer.io_Message.mn_ReplyPort = SReadPort;
if (OpenDevice(openedMi->mi_Device, openedMi->mi_Unit, (struct IORequest *)ior, 0)) {
return FALSE;
}
ior->IOSer.io_Command = SDCMD_QUERY;
DoIO((struct IORequest *)ior);
/*
* supposedly you are only allowed to set SERF_7WIRE before you open
* the device. However, it seems that the oldser.device used by the
* A2232 is screwing this up. So we reset it after out open device
* call just in case.
*/
if (mi->mi_CTSRTS)
ior->io_SerFlags |= SERF_7WIRE;
else
ior->io_SerFlags &= ~SERF_7WIRE;
ior->io_Baud = currentBaud;
ior->io_StopBits = 1;
ior->io_RBufLen = 1024;
if (use8N1) {
ior->io_ReadLen = ior->io_WriteLen = 8;
ior->io_SerFlags &= ~(SERF_PARTY_ODD | SERF_PARTY_ON | SERF_XDISABLED); /* insure no parity is
* in use */
}
else {
ior->io_ReadLen = ior->io_WriteLen = 7;
ior->io_SerFlags &= ~(SERF_PARTY_ODD | SERF_XDISABLED);
ior->io_SerFlags |= SERF_PARTY_ON;
ior->io_ExtFlags &= ~SEXTF_MSPON;
};
ior->IOSer.io_Command = SDCMD_SETPARAMS;
if (DoIO((struct IORequest *)ior)) {
CloseDevice((struct IORequest *)&SerialRead);
return FALSE;
}
CopyMem((APTR)ior, (APTR)iow, sizeof(struct IOExtSer));
iow->IOSer.io_Message.mn_ReplyPort = SWritePort;
SReadPos = SReadSize = 0;
SerialUp = TRUE;
return TRUE;
}
/* open up the serial device */
static BOOL OpenSerial(ModemInfo_t * mi, BOOL AttemptMode)
{
STRPTR ODUresult;
/* save these away for when we need to close the device */
openedMi = mi;
/* allocate our message ports */
if (!(SReadPort = CreatePort(NULL, 0))) {
openedMi = NULL;
return FALSE;
}
if (!(SWritePort = CreatePort(NULL, 0))) {
DeletePort(SReadPort);
openedMi = NULL;
return FALSE;
}
SReadSigMask = 1L << SReadPort->mp_SigBit;
SWriteSigMask = 1L << SWritePort->mp_SigBit;
if (AttemptMode)
ODUresult = AttemptDevUnit(openedMi->mi_Device, openedMi->mi_Unit, PROGNAME, 0L);
else
ODUresult = LockDevUnit(openedMi->mi_Device, openedMi->mi_Unit, PROGNAME, 0L);
if (ODUresult) {
DeletePort(SWritePort);
DeletePort(SReadPort);
openedMi = NULL;
return FALSE;
}
currentBaud = mi->mi_MaxBaud;
use8N1 = FALSE;
if (!InitSer(mi)) {
FreeDevUnit(openedMi->mi_Device, openedMi->mi_Unit);
DeletePort(SWritePort);
DeletePort(SReadPort);
openedMi = NULL;
return FALSE;
}
if (!OpenTimer()) {
CloseSerial();
return FALSE;
}
return TRUE;
}
/* this expects that the baud rate passed in is the baud rate of the service */
void SwitchBaud(ULONG baud)
{
currentBaud = baud;
if (openedMi->mi_MatchDTE) {
if (baud > openedMi->mi_MaxBaud)
baud = openedMi->mi_MaxBaud;
}
else
baud = openedMi->mi_MaxBaud;
SerialRead.io_Baud = baud;
SerialRead.IOSer.io_Command = SDCMD_SETPARAMS;
DoIO((struct IORequest *)&SerialRead);
SerialWrite.io_Baud = baud;
SerialWrite.IOSer.io_Command = SDCMD_SETPARAMS;
DoIO((struct IORequest *)&SerialWrite);
}
BOOL Connected(void)
{
SerialRead.IOSer.io_Command = SDCMD_QUERY;
DoIO((struct IORequest *)&SerialRead);
if (SerialRead.io_Status & (1L << 5))
return FALSE;
else
return TRUE;
}
#define MODEM_TEMPLATE "DEVICE/A,UNIT/N/A,MAXBAUD/N/A,MATCHDTE/A,CTSRTS/A,INITSTRING/A"
enum ModemArgs {
ARG_DEVICE,
ARG_UNIT,
ARG_BAUD,
ARG_DTE,
ARG_CTS,
ARG_INIT,
ARG_sizeof
};
static ModemInfo_t *ReadModemInfo(LONG modemNumber)
{
ModemInfo_t *mi = NULL;
UBYTE modemName[32];
STRPTR modemConfig;
STRPTR buffer;
struct RDArgs *ArgsPtr;
struct RDArgs *MyArgs;
STRPTR ArgArray[ARG_sizeof];
sprintf(modemName, "MODEM%ld", modemNumber);
if (modemNumber == 1)
modemConfig = FindPagerConfigDefault(ph, modemName, "serial.device 0 1200 y n ATZ\\r\\d\\d\\dATM0\\r\\dATD");
else
modemConfig = FindPagerConfig(ph, modemName);
if (modemConfig) {
if (buffer = MyAllocVec(strlen(modemConfig) + 4)) {
strcpy(buffer, modemConfig);
strcat(buffer, "\n");
if (MyArgs = (struct RDArgs *)AllocDosObject(DOS_RDARGS, TAG_DONE)) {
MyArgs->RDA_Flags |= RDAF_NOPROMPT;
MyArgs->RDA_Source.CS_Buffer = buffer;
MyArgs->RDA_Source.CS_Length = strlen(buffer);
MyArgs->RDA_Source.CS_CurChr = 0L;
memset((char *)ArgArray, 0, sizeof(ArgArray));
if (ArgsPtr = ReadArgs(MODEM_TEMPLATE, (LONG *)&ArgArray, MyArgs)) {
if (mi = (ModemInfo_t *) MyAllocVec(sizeof(ModemInfo_t) + strlen(ArgArray[ARG_DEVICE]) + strlen(ArgArray[ARG_INIT]) + 2)) {
strcpy(mi->mi_ModemInit, ArgArray[ARG_INIT]);
mi->mi_Device = &mi->mi_ModemInit[strlen(mi->mi_ModemInit) + 1];
strcpy(mi->mi_Device, ArgArray[ARG_DEVICE]);
mi->mi_Unit = *((LONG *)ArgArray[ARG_UNIT]);
mi->mi_MaxBaud = *((LONG *)ArgArray[ARG_BAUD]);
mi->mi_MatchDTE = PagerConfigYesNo(ArgArray[ARG_DTE]);
mi->mi_CTSRTS = PagerConfigYesNo(ArgArray[ARG_CTS]);
}
else
ErrorMsg("out of memory!");
FreeArgs(ArgsPtr);
}
else {
ErrorMsg("%s config entry badly formatted.", modemName);
ULog(ph, -1, "%s config entry badly formatted.", modemName);
}
FreeDosObject(DOS_RDARGS, MyArgs);
}
else
ErrorMsg("out of memory!");
MyFreeVec(buffer);
}
else
ErrorMsg("out of memory!");
FreePagerConfig(modemConfig);
}
return mi;
}
LONG OpenModem(LONG modemNumber, LONG modemStart)
{
ModemInfo_t *mi;
online = FALSE;
if (modemNumber) {
if (mi = ReadModemInfo(modemNumber)) {
if (OpenSerial(mi, FALSE) == FALSE) {
MyFreeVec(mi);
return 0L;
}
else
return modemNumber;
}
}
else {
modemNumber = modemStart;
while (mi = ReadModemInfo(modemNumber++))
if (OpenSerial(mi, TRUE))
return modemNumber - 1;
return 0L;
}
}
/* close down the serial handling stuff */
void CloseSerial(void)
{
CloseTimer();
if (SerialUp) {
CloseDevice((struct IORequest *)&SerialRead);
online = SerialUp = FALSE;
}
FreeDevUnit(openedMi->mi_Device, openedMi->mi_Unit);
MyFreeVec(openedMi);
openedMi = NULL;
DeletePort(SWritePort);
DeletePort(SReadPort);
}
/* hang up the modem -- we use a DTR drop to do this */
BOOL HangUp(void)
{
if (SerialUp) {
CloseDevice((struct IORequest *)&SerialRead);
online = SerialUp = FALSE;
}
Delay(TICKS_PER_SECOND);
return InitSer(openedMi);
}
/* determine if we should be using 8N1 or 7E1 */
BOOL Use8N1(BOOL set8N1)
{
BOOL old8N1;
old8N1 = use8N1;
use8N1 = set8N1;
/*
* if they really changed the use8N1 state then we need to check to
* see if the modem is currently on-line and reset it if so.
*/
if (use8N1 != old8N1) {
if (SerialUp) {
CloseDevice((struct IORequest *)&SerialRead);
online = SerialUp = FALSE;
}
Delay(TICKS_PER_SECOND);
return InitSer(openedMi);
}
else
return TRUE;
}
/* flush out the serial read buffer */
void ClearSerial(void)
{
SReadPos = SReadSize = 0;
SerialRead.IOSer.io_Command = CMD_CLEAR;
DoIO((struct IORequest *)&SerialRead);
}
/* send a string to the serial device */
void SerWrite(STRPTR Buf, ULONG Len)
{
#ifdef DEBUG_WRITES
FWrite(Output(), Buf, 1, Len);
#endif
SerialWrite.IOSer.io_Command = CMD_WRITE;
SerialWrite.IOSer.io_Length = Len;
SerialWrite.IOSer.io_Data = (APTR)Buf;
DoIO((struct IORequest *)&SerialWrite);
if (SerialWrite.IOSer.io_Error)
ULog(ph, -1, "serial write error %ld", SerialWrite.IOSer.io_Error);
}
void SerPutChar(UBYTE value)
{
UBYTE Buf[2];
#ifdef DEBUG_WRITES
FPutC(Output(), value);
#endif
Buf[0] = value;
SerialWrite.IOSer.io_Command = CMD_WRITE;
SerialWrite.IOSer.io_Length = 1;
SerialWrite.IOSer.io_Data = (APTR)Buf;
DoIO((struct IORequest *)&SerialWrite);
if (SerialWrite.IOSer.io_Error)
ULog(ph, -1, "serial write error %ld", SerialWrite.IOSer.io_Error);
}
/*
* wait for a specific string to be read from the device. this is
* case-insensitive
*/
BOOL SerWaitString(STRPTR target, LONG timeout)
{
UWORD byteRead;
int i, len;
len = strlen(target);
i = 0;
while ((byteRead = SerGetRawChar(timeout)) != TIMEOUT) {
if (tolower(byteRead) == tolower(target[i])) {
if (++i == len)
return TRUE;
}
else
i = 0;
}
return FALSE;
}
/* get a character from the serial device with a timeout */
UWORD SerGetRawChar(LONG timeout)
{
UBYTE Buffer[2];
ULONG Signals;
ULONG secs, micro;
if (timeout < 0) {
secs = 0;
micro = -timeout;
}
else {
secs = timeout;
micro = 0;
}
if (SReadPos < SReadSize) {
#ifdef DEBUG_READS
Printf("%lc", SReadBuf[SReadPos]);
#endif
return (UWORD)SReadBuf[SReadPos++];
}
SetSignal(0L, SReadSigMask | TimerSigMask);
SerialRead.IOSer.io_Command = CMD_READ;
SerialRead.IOSer.io_Length = 1;
SerialRead.IOSer.io_Data = (APTR)Buffer;
SendIO((struct IORequest *)&SerialRead);
TimerIO.tr_node.io_Command = TR_ADDREQUEST;
TimerIO.tr_time.tv_secs = secs;
TimerIO.tr_time.tv_micro = micro;
SendIO((struct IORequest *)&TimerIO);
Signals = Wait(SReadSigMask | TimerSigMask);
if (Signals & SReadSigMask) {
if (!CheckIO((struct IORequest *)&TimerIO)) {
AbortIO((struct IORequest *)&TimerIO);
}
WaitIO((struct IORequest *)&TimerIO);
WaitIO((struct IORequest *)&SerialRead);
if (!SerialRead.IOSer.io_Error && SerialRead.IOSer.io_Actual) {
SerialRead.IOSer.io_Command = SDCMD_QUERY;
DoIO((struct IORequest *)&SerialRead);
if (SerialRead.IOSer.io_Actual) {
SerialRead.IOSer.io_Command = CMD_READ;
SerialRead.IOSer.io_Length = min(sizeof(SReadBuf), SerialRead.IOSer.io_Actual);
SerialRead.IOSer.io_Data = (APTR)SReadBuf;
DoIO((struct IORequest *)&SerialRead);
if (!SerialRead.IOSer.io_Error) {
SReadPos = 0;
SReadSize = SerialRead.IOSer.io_Actual;
}
}
#ifdef DEBUG_READS
Printf("%lc", Buffer[0]);
#endif
return (UWORD)Buffer[0];
}
else
return 0;
}
if (Signals & TimerSigMask)
WaitIO((struct IORequest *)&TimerIO);
/* if we get down here we have timed out waiting for a character */
if (!CheckIO((struct IORequest *)&SerialRead)) {
AbortIO((struct IORequest *)&SerialRead);
}
WaitIO((struct IORequest *)&SerialRead);
return TIMEOUT;
}
BOOL InitModem(void)
{
STRPTR ptr;
UWORD c;
BOOL validEscape;
#define MAX_AT_RETRIES (3)
/* try to get the modem's attention. */
for (c = 0; c < MAX_AT_RETRIES; c++) {
SerWrite("AT\r", 3);
if (SerWaitString("OK\r\n", 6))
break;
}
if (c == MAX_AT_RETRIES) {
ErrorMsg("modem %ld not responding.", openedModem);
ULog(ph, -1, "modem %ld not responding.", openedModem);
return FALSE;
}
Delay(TICKS_PER_SECOND);
ClearSerial();
/* now start sending the init string out */
ptr = openedMi->mi_ModemInit;
while (c = *ptr++) {
validEscape = FALSE;
if (c == '\\') {
validEscape = TRUE;
switch (tolower(*ptr)) {
case 'd':
Delay(2 * TICKS_PER_SECOND);
c = 0xFFFF;
break;
case 'r':
c = '\r';
break;
default:
validEscape = FALSE;
break;
}
}
if (c != 0xFFFF)
SerPutChar(c);
if (c == '\r')
while ((c = SerGetRawChar(-100)) != TIMEOUT) ;
if (validEscape) {
ptr++;
}
}
return TRUE;
}