401 lines
10 KiB
C
401 lines
10 KiB
C
/*
|
|
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without modification,
|
|
* are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
* 3. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
* OF SUCH DAMAGE.
|
|
*
|
|
* This file is part of the lwIP TCP/IP stack.
|
|
*
|
|
*/
|
|
|
|
#include "lwip/opt.h"
|
|
#include "lwip/sys.h"
|
|
#include "lwip/sio.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
|
|
#include <Errors.h>
|
|
#include <Files.h>
|
|
#include <Devices.h>
|
|
#include <Serial.h>
|
|
|
|
/**
|
|
* SIO_DEBUG: Enable debugging for SIO.
|
|
*/
|
|
#ifndef SIO_DEBUG
|
|
#define SIO_DEBUG LWIP_DBG_OFF
|
|
#endif
|
|
|
|
/**
|
|
* MACOS_INPUT_BUFF_SIZE: Set the ppp input buffer.
|
|
* 64 or less uses driver's default 64 byte buffer.
|
|
*/
|
|
#ifndef MACOS_SIO_BUFF_SIZE
|
|
#define MACOS_SIO_BUFF_SIZE 64
|
|
#endif
|
|
|
|
|
|
/* sio_fd_t is supposed to be a void pointer, so we need to do some casting back. */
|
|
#define PORT_NUM(sd) (*(short *)sd)
|
|
|
|
#define IN_REF(sd) (int)(PORT_NUM(sd) + 3) * -2
|
|
#define OUT_REF(sd) (int)IN_REF(sd)-1
|
|
|
|
u8_t sio_setup(sio_fd_t sd);
|
|
OSErr ROMSDOpen(SPortSel whichPort);
|
|
|
|
char *sio_input_buffer;
|
|
|
|
#if NO_SYS==0
|
|
static unsigned char sio_abort = 0xFF;
|
|
#endif
|
|
|
|
#pragma segment LWUPDN
|
|
u8_t sio_setup(sio_fd_t fd)
|
|
{
|
|
OSErr error;
|
|
|
|
unsigned short baud;
|
|
short databits;
|
|
short stopbits;
|
|
short parity;
|
|
short config;
|
|
SerShk shake;
|
|
|
|
/* Set the new data */
|
|
baud = baud19200; /* 19200 */
|
|
parity = noParity; /* None*/
|
|
databits = data8; /* 8 */
|
|
stopbits = stop10; /* 1 */
|
|
|
|
/* do not use flow control */
|
|
shake.fXOn = 0;
|
|
shake.fCTS = 0;
|
|
shake.xOn = 0;
|
|
shake.xOff = 0;
|
|
shake.errs = 0;
|
|
shake.evts = 0;
|
|
shake.fInX = 0;
|
|
shake.fDTR = 0;
|
|
|
|
config = baud + parity + databits + stopbits;
|
|
//config = (baud | parity | databits | stopbits);
|
|
|
|
LWIP_DEBUGF(SIO_DEBUG, ("sio_setup(%d, %d)\n", IN_REF(fd), OUT_REF(fd))) ;
|
|
|
|
if (error = SerReset(IN_REF(fd), config))
|
|
LWIP_DEBUGF(SIO_DEBUG | LWIP_DBG_LEVEL_WARNING, ("sio_setup(%d) can't configure serial port due to \'SerReset\' error:%d. Continuing...\n", IN_REF(fd), error)) ;
|
|
if (error = SerHShake(IN_REF(fd), &shake))
|
|
LWIP_DEBUGF(SIO_DEBUG | LWIP_DBG_LEVEL_WARNING, ("sio_setup(%d) can't disable serial handshake due to \'SerHShake\' error:%d. Continuing...\n", IN_REF(fd), error)) ;
|
|
|
|
if (error = SerReset(OUT_REF(fd), config))
|
|
LWIP_DEBUGF(SIO_DEBUG | LWIP_DBG_LEVEL_WARNING, ("sio_setup(%d) can't configure serial port due to \'SerReset\' error:%d. Continuing...\n", OUT_REF(fd), error)) ;
|
|
if (error = SerHShake(OUT_REF(fd), &shake))
|
|
LWIP_DEBUGF(SIO_DEBUG | LWIP_DBG_LEVEL_WARNING, ("sio_setup(%d) can't disable serial handshake due to \'SerHShake\' error:%d. Continuing...\n", OUT_REF(fd), error)) ;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
OSErr ROMSDOpen(SPortSel whichPort)
|
|
{
|
|
OSErr error = fnfErr;
|
|
short inRef, outRef;
|
|
|
|
char *inDriver;
|
|
char *outDriver;
|
|
|
|
switch (whichPort)
|
|
{
|
|
case sPortA:
|
|
inDriver = ".AIn";
|
|
outDriver = ".AOut";
|
|
break;
|
|
|
|
case sPortB:
|
|
inDriver = ".BIn";
|
|
outDriver = ".BOut";
|
|
break;
|
|
|
|
default:
|
|
return error;
|
|
break;
|
|
}
|
|
|
|
error = opendriver(outDriver, &outRef);
|
|
LWIP_DEBUGF(SIO_DEBUG, ("ROMSDOpen(%d) 'opendriver(%s, %d)\n", whichPort, outDriver, outRef )) ;
|
|
if (error == noErr)
|
|
{
|
|
error = opendriver(inDriver, &inRef);
|
|
LWIP_DEBUGF(SIO_DEBUG, ("ROMSDOpen(%d) 'opendriver(%s, %d)\n", whichPort, inDriver, inRef )) ;
|
|
}
|
|
|
|
LWIP_DEBUGF(SIO_DEBUG, ("ROMSDOpen(%d) will return: %d\n", whichPort, error));
|
|
|
|
return error;
|
|
}
|
|
|
|
/**
|
|
* Opens a serial device for communication.
|
|
*
|
|
* @param devnum device number
|
|
* @return handle to serial device if successful, NULL otherwise
|
|
*/
|
|
sio_fd_t sio_open(u8_t devnum)
|
|
{
|
|
OSErr error = fnfErr;
|
|
/* These are the the serial port numbers that 'sio_fd_t sd' points to. */
|
|
static const short modemPort = sPortA;
|
|
static const short printerPort = sPortB;
|
|
/* The serial port device is just a pointer to one of the constant port numbers. */
|
|
sio_fd_t sd;
|
|
|
|
/* Keep track of the port name for debugging and warnings. */
|
|
char* port_name;
|
|
|
|
/* We don't have devices, but sPortA (0) is Modem and sPortB (1) is Printer. */
|
|
switch (devnum)
|
|
{
|
|
case 'P' :
|
|
case 'p' :
|
|
case 'b' :
|
|
case 'B' :
|
|
case sPortB :
|
|
port_name = "Printer";
|
|
sd = (sio_fd_t)&printerPort;
|
|
error = ROMSDOpen(sPortB);
|
|
break;
|
|
|
|
case 'M' :
|
|
case 'm' :
|
|
case 'a' :
|
|
case 'A' :
|
|
case sPortA :
|
|
default:
|
|
port_name = "Modem";
|
|
sd = (sio_fd_t)&modemPort;
|
|
error = ROMSDOpen(sPortA);
|
|
|
|
/* PPP was overflowing the input buffer, so make it bigger.*/
|
|
if (MACOS_SIO_BUFF_SIZE > 64 && sio_input_buffer == NULL)
|
|
{
|
|
sio_input_buffer = (char *)malloc(MACOS_SIO_BUFF_SIZE);
|
|
LWIP_ASSERT("sio_open() can't allocate memory", sio_input_buffer != NULL);
|
|
}
|
|
if ( error == noErr && sio_input_buffer)
|
|
SerSetBuf(IN_REF(sd), sio_input_buffer, MACOS_SIO_BUFF_SIZE);
|
|
break;
|
|
}
|
|
|
|
switch (error)
|
|
{
|
|
case (int)noErr: //0
|
|
LWIP_DEBUGF(SIO_TRACE, ("Serial Port successfully opened.\n", devnum));
|
|
break;
|
|
case (int)badUnitErr: //-21
|
|
LWIP_ERROR("Bad Reference Number for Serial Port.\n", (error == noErr ), return NULL;);
|
|
break;
|
|
case (int)dInstErr: //-26
|
|
LWIP_ERROR("Couldn't Find Serial Driver in Resource File.\n", (error == noErr ), return NULL;);
|
|
break;
|
|
case (int)openErr: //-23
|
|
LWIP_ERROR("Driver can't perform the requested reading or writing.\n", (error == noErr ), return NULL;);
|
|
break;
|
|
case (int)unitEmptyErr: //-22
|
|
LWIP_ERROR("Bad Reference Number for Serial Port.\n", (error == noErr ), return NULL;);
|
|
break;
|
|
case (int)fnfErr: //-43
|
|
LWIP_ERROR(("Serial Port Not Found.\n"), (error == noErr ), return NULL;);
|
|
break;
|
|
default:
|
|
//printf("%d", (int)error);
|
|
LWIP_ERROR("Unknown Error opening Serial Port.\n", (error == noErr ), return NULL;);
|
|
break;
|
|
}
|
|
|
|
sio_setup(sd);
|
|
|
|
LWIP_DEBUGF(SIO_DEBUG, ("%s Port Successfully Opened.\n", (PORT_NUM(sd) == (int)sPortA)? "Modem":"Printer"));
|
|
|
|
return sd;
|
|
}
|
|
|
|
|
|
/**
|
|
* Closes a serial device.
|
|
*
|
|
* @param fd device
|
|
*/
|
|
void
|
|
sio_close(sio_fd_t fd)
|
|
{
|
|
if (PORT_NUM(fd) == (int)sPortA && sio_input_buffer)
|
|
SerSetBuf(IN_REF(fd), sio_input_buffer, 0);
|
|
|
|
/* Don't Close the ROM Serial Driver */
|
|
}
|
|
|
|
/**
|
|
* Sends a single character to the serial device.
|
|
*
|
|
* @param c character to send
|
|
* @param fd serial device handle
|
|
*
|
|
* @note This function will block until the character can be sent.
|
|
*/
|
|
#pragma segment LWPPP
|
|
void sio_send(u8_t c, sio_fd_t fd)
|
|
{
|
|
OSErr error;
|
|
long count = 1;
|
|
|
|
error = FSWrite(OUT_REF(fd), &count, &(char)c);
|
|
|
|
if (error)
|
|
LWIP_DEBUGF(SIO_DEBUG | LWIP_DBG_LEVEL_WARNING, ("sio_send(%c, %d) failed due to \'FSWrite\' error: %d.\n", c, PORT_NUM(fd), error));
|
|
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* Receives a single character from the serial device.
|
|
*
|
|
* @param fd serial device handle
|
|
*
|
|
* @note This function will block until a character is received. The blocking
|
|
* can be cancelled by calling sio_read_abort().
|
|
*/
|
|
|
|
#if NO_SYS==0
|
|
u8_t sio_recv(sio_fd_t fd)
|
|
{
|
|
static unsigned char cbuff;
|
|
|
|
sio_read(fd, &(char)cbuff, 1);
|
|
|
|
return cbuff;
|
|
}
|
|
#endif
|
|
|
|
|
|
/**
|
|
* Reads from the serial device.
|
|
*
|
|
* @param fd serial device handle
|
|
* @param data pointer to data buffer for receiving
|
|
* @param len maximum length (in bytes) of data to receive
|
|
* @return number of bytes actually received - may be 0 if aborted by sio_read_abort
|
|
*
|
|
* @note If NO_SYS is > 0, this function will block until data can be received.
|
|
* The blocking can be cancelled by calling sio_read_abort().
|
|
*/
|
|
|
|
u32_t sio_read(sio_fd_t fd, u8_t* data, u32_t len)
|
|
{
|
|
long count = 0;
|
|
|
|
#if NO_SYS==0
|
|
while (sio_abort != IN_REF(fd) && count < len)
|
|
#endif
|
|
{
|
|
count = sio_tryread(fd, data, len);
|
|
}
|
|
#if NO_SYS==0
|
|
if (sio_abort == IN_REF(fd))
|
|
sio_abort = 0xFF;
|
|
#endif
|
|
|
|
return count;
|
|
}
|
|
|
|
|
|
/**
|
|
* Non-Blocking Read from the serial device.
|
|
*
|
|
* @param fd serial device handle
|
|
* @param data pointer to data buffer for receiving
|
|
* @param len maximum length (in bytes) of data to receive
|
|
* @return number of bytes actually received - may be 0
|
|
*
|
|
*/
|
|
u32_t sio_tryread(sio_fd_t fd, u8_t* data, u32_t len)
|
|
{
|
|
OSErr error;
|
|
long count = 0;
|
|
|
|
(void)SerGetBuf(IN_REF(fd), &count);
|
|
|
|
if (count)
|
|
{
|
|
/* only get up to the length asked for. */
|
|
if (count > len) count = (long)len;
|
|
|
|
if ((error = FSRead(IN_REF(fd), &count, (char *)data)))
|
|
LWIP_DEBUGF(SIO_DEBUG | LWIP_DBG_LEVEL_WARNING, ("sio_read(%d, %d) failed due to \'FSRead\' error: %d.\n", IN_REF(fd), len, error));
|
|
}
|
|
return count;
|
|
}
|
|
|
|
|
|
/**
|
|
* Writes to the serial device.
|
|
*
|
|
* @param fd serial device handle
|
|
* @param data pointer to data to send
|
|
* @param len length (in bytes) of data to send
|
|
* @return number of bytes actually sent
|
|
*
|
|
* @note This function will block until all data can be sent.
|
|
*/
|
|
u32_t sio_write(sio_fd_t fd, u8_t* data, u32_t len)
|
|
{
|
|
OSErr error;
|
|
long count = (long)len;
|
|
|
|
error = FSWrite(OUT_REF(fd), &count, (char *)data);
|
|
|
|
// The ppp module will log the error for us.
|
|
if (error)
|
|
return error;
|
|
|
|
return len;
|
|
}
|
|
|
|
#if NO_SYS==0
|
|
/**
|
|
* Aborts a blocking sio_read() call.
|
|
*
|
|
* @param fd serial device handle
|
|
*/
|
|
void sio_read_abort(sio_fd_t fd)
|
|
{
|
|
LWIP_DEBUGF(SIO_DEBUG, ("sio_read_abort(%d)\n", IN_REF(fd) ));
|
|
sio_abort = IN_REF(fd);
|
|
return;
|
|
}
|
|
|
|
#endif
|
|
|