/************************************************************************** * serial.c: Serial port access functions. * Part of MP, the MIDI Playground. * * Author: Daniel Barrett * Version: See the file "version.h". * Copyright: None! This program is in the Public Domain. * Please share it with others. ***************************************************************************/ #include "mp.h" #include "midi.h" static struct MsgPort *MidiPort = NULL; static struct IOExtSer *Midi = NULL; long serialFlags = 0L; #define F_MIDIPORT 1 #define F_MIDI 2 #define F_DEVICE 4 #define F_SERPARAMS 8 BOOL AllDigits(char *str); char *GetEnv(char *str); BOOL MakeSerialDeviceName(char *str, char *device, int *unit); /**************************************************************************** * SerialSetup: Open the serial port and its message port. * Allow for an alternate MIDI device in an environment variable. ***************************************************************************/ BOOL SerialSetup(FLAGS sysex) { char deviceName[BUFSIZ], *envVar; int unit; /* Set the defaults. */ strcpy(deviceName, DEFAULT_MIDI_DEVICE); unit = DEFAULT_MIDI_UNIT; /* If environment variable is set, find the real MIDI device info. */ if ((envVar = GetEnv(MIDI_ENV_VAR)) && (!MakeSerialDeviceName(envVar, deviceName, &unit))) return(FALSE); /* Create a port. */ if (! (MidiPort = CreatePort(0, 0)) ) { fprintf(stderr, "Cannot create port\n"); SerialShutdown(); return(FALSE); } else serialFlags |= F_MIDIPORT; /* Create an extended I/O structure. */ if (! (Midi = (struct IOExtSer *) CreateExtIO(MidiPort, sizeof(struct IOExtSer)))) { fprintf(stderr, "Cannot create extended I/O structure\n"); SerialShutdown(); return(FALSE); } else serialFlags |= F_MIDI; /* Open the serial device. */ Midi->io_SerFlags = SERF_SHARED; if (OpenDevice(deviceName, unit, (struct IORequest *)Midi, 0)) { fprintf(stderr, "Cannot open serial device \"%s\", unit %d.\n", deviceName, unit); SerialShutdown(); return(FALSE); } else serialFlags |= F_DEVICE; /* Set the serial device parameters. */ Midi->io_SerFlags = SERF_RAD_BOOGIE; if (sysex) { Midi->io_TermArray.TermArray0 = 0xF7F7F7F7; Midi->io_TermArray.TermArray1 = 0xF7F7F7F7; Midi->io_SerFlags |= SERF_EOFMODE; } Midi->io_Baud = MIDI_BAUD_RATE; Midi->io_ExtFlags = 0; /* For future compatibility */ Midi->IOSer.io_Command = SDCMD_SETPARAMS; if (DoIO((struct IORequest *)Midi) != 0) { fprintf(stderr, "Cannot set serial parameters.\n"); SerialShutdown(); return(FALSE); } else serialFlags |= F_SERPARAMS; return(TRUE); } /**************************************************************************** * SerialShutdown: Close the serial port and its message port. ***************************************************************************/ void SerialShutdown(void) { if (serialFlags & F_DEVICE) { ResetSerialPort(); AbortIO((struct IORequest *)Midi); WaitIO((struct IORequest *)Midi); CloseDevice((struct IORequest *)Midi); } if (serialFlags & F_MIDI) DeleteExtIO((struct IORequest *)Midi); if (serialFlags & F_MIDIPORT) DeletePort(MidiPort); } /**************************************************************************** * ResetSerialPort: Clear all data from the serial port. ***************************************************************************/ void ResetSerialPort(void) { Midi->IOSer.io_Command = CMD_CLEAR; DoIO((struct IORequest *)Midi); } /**************************************************************************** * Is any data there? ***************************************************************************/ long AnyMidiData(void) { Midi->IOSer.io_Command = SDCMD_QUERY; DoIO((struct IORequest *)Midi); return(Midi->IOSer.io_Actual); } /**************************************************************************** * PrepareToReadMidi: Prepare a READ request for the MIDI port. * PrepareToWriteMidi: Prepare a WRITE request for the MIDI port. ***************************************************************************/ void PrepareToReadMidi(UBYTE buf[], int len) { Midi->IOSer.io_Command = CMD_READ; Midi->IOSer.io_Data = (APTR)buf; Midi->IOSer.io_Length = len; } void PrepareToWriteMidi(UBYTE buf[], int len) { Midi->IOSer.io_Command = CMD_WRITE; Midi->IOSer.io_Data = (APTR)buf; Midi->IOSer.io_Length = len; } /**************************************************************************** * DoTheIO: General-purpose MIDI I/O routine. Quits on ^C. ****************************************************************************/ long DoTheIO(void) { int mask, temp; long bytesDone = 0L; mask = SIGBREAKF_CTRL_C | (1L << MidiPort->mp_SigBit); SendIO((struct IORequest *)Midi); while (1) { temp = Wait(mask); if (temp & SIGBREAKF_CTRL_C) { bytesDone = CTRL_C_NO_BYTES; break; } if (CheckIO((struct IORequest *)Midi)) { WaitIO((struct IORequest *)Midi); bytesDone = Midi->IOSer.io_Actual; break; } } AbortIO((struct IORequest *)Midi); WaitIO((struct IORequest *)Midi); return(bytesDone); } /**************************************************************************** * Fast serial reading routine, from idea on 1.3 RKM's page 863. * If any data is waiting, get all of it with DoIO(). Otherwise, post an * asynchronous request for 1 byte. Repeat this in the calling program. ****************************************************************************/ long FastSerialRead(UBYTE buf[]) { long bytesWaiting, bytesRead; if ((bytesWaiting = AnyMidiData()) > 0) { PrepareToReadMidi(buf, MIN(bytesWaiting, BUFSIZ)); DoIO((struct IORequest *)Midi); return(Midi->IOSer.io_Actual); } else { PrepareToReadMidi(buf, 1); return(DoTheIO()); } } /**************************************************************************** * Allow the use of another MIDI device than serial.device. * Environment variable syntax is "DEVICENAME:UNITNUMBER". * For example: "midi.device:2". * * "device" MUST be preallocated. ****************************************************************************/ BOOL MakeSerialDeviceName(char *str, char *device, int *unit) { while (str && *str && (*str != ':')) *(device++) = *(str++); *device = '\0'; if ((*str != ':') || *(str+1) == '\0') { fprintf(stderr, "Your MIDI device name (variable " MIDI_ENV_VAR ") is missing a colon\nand/or a unit number.\n"); return(FALSE); } str++; if (!AllDigits(str)) { fprintf(stderr, "Your MIDI device unit number (variable " MIDI_ENV_VAR ") must be\na positive integer.\n"); return(FALSE); } else *unit = atoi(str); return(TRUE); } /* AllDigits: Return TRUE iff the string "str" consists only of digits. */ BOOL AllDigits(char *str) { if ((!str) || (*str == '\0')) /* NULL or empty string. */ return(FALSE); else while (*str) /* For each character... */ if (!isdigit(*str)) /* if not a digit... */ return(FALSE); /* goodbye! */ else str++; return(TRUE); /* All were digits. */ }