This is Distributor.m in view mode; [Download] [Up]
//
// Distributor.m
// LGDCommunicationKit Examples, Release 1.0 (prerelease)
//
// Copyright (c) 1993, Looking Glass Design, Inc.
// All rights reserved.
//
// Project Manager: Paul Girone
// Original Author: Mike Gobbi
// Creation Date: June 10, 1993
// $Revision: 1.3 $
//
#import "Distributor.h"
#import <appkit/Application.h>
#import <appkit/ButtonCell.h>
#import <appkit/Matrix.h>
#import <appkit/Menu.h>
#import <assert.h>
#import <errno.h>
#import <lgd/commkit/LGDAppSerialPort.h>
#import <libc.h>
#import <pwd.h>
#import <signal.h>
#import "TextExtensions.h"
#define POPUP_STRING(button) [button title]
static id port;
void hangup(void)
{
// close the connection
if ([port isOpen]) {
[port close];
}
// unlock the device
if ([port isLocked]) {
[port unlock];
}
}
void cleanup(void)
{
// ensure that we are hung up, then die
hangup();
exit(1);
}
@implementation Distributor
// Status
- displayStatus:sender
{
NXRunAlertPanel(NULL, "%s\ndevice %s (fd %d) is %s and %s, errno=%d",
NULL, NULL, NULL,
[serialPort statusString],
[serialPort device],
[serialPort _fileDescriptor],
[serialPort isLocked] ? "locked" : "unlocked",
[serialPort isOpen] ? "open" : "closed",
errno);
return self;
}
// Communication
- send:sender
{
int result;
char buffer[20];
// either treat field as integer...
if ([byteSwitch state]) {
result = [serialPort sendCharacter:[inputField intValue]];
sprintf(buffer, "<%d>", [inputField intValue]);
[outgoingField appendString:buffer addNewline:YES];
// ...or else treat field as string
} else {
result = [serialPort sendString:[inputField stringValue]
withTrailer:"\r"];
[outgoingField appendString:[inputField stringValue]
addNewline:YES];
}
// check for errors
if (result<0) {
NXRunAlertPanel(NULL, "%s",
NULL, NULL, NULL,
[serialPort statusString]);
[serialPort clearStatus];
}
// tidy up the GUI
[outgoingField scrollSelToVisible];
[inputField selectText:self];
return self;
}
- poll:sender
{
char buffer[80];
int count;
int character;
// either display input as integers...
if ([byteSwitch state]) {
for (count=[serialPort getCharacter:&character];
count > 0;
count=[serialPort getCharacter:&character]) {
assert(character!=EOF);
sprintf(buffer, "<%d>", character);
[incomingField appendString:buffer addNewline:YES];
[incomingField scrollSelToVisible];
}
// ... or else display as a string
} else {
for (count=[serialPort getString:buffer
max:80
termChars:"\n\r"];
count > 0;
count=[serialPort getString:buffer
max:80
termChars:"\n\r"]) {
[incomingField appendString:buffer addNewline:NO];
[incomingField scrollSelToVisible];
}
}
// check for errors
if (count!=0) {
NXRunAlertPanel(NULL, "%s",
NULL, NULL, NULL,
[serialPort statusString]);
[serialPort clearStatus];
// don't keep trying if we had an error
if ([serialPort action]){
[autoPollSwitch performClick:self];
}
}
// tidy up the GUI
// we want to use a delayed call because in auto-polling
// the continual flicker as multiple lines are polled looks
// bad. The 1/2 second delay will ensure that no reselection
// takes place during multiple-poll operations.
[inputField
perform:@selector(selectText:)
with:self
afterDelay:0.5
cancelPrevious:YES];
return self;
}
- peek:sender
{
BOOL flag;
// determine whether there is any data
flag = [serialPort dataAvailable];
// notify the user
if ([serialPort status]) {
NXRunAlertPanel(NULL, "%s",
NULL, NULL, NULL,
[serialPort statusString]);
[serialPort clearStatus];
// or display error message
} else {
NXRunAlertPanel(NULL, "There is %s data ready to be read",
NULL, NULL, NULL,
flag ? "new" : "no");
}
return self;
}
- clearTextFields:sender
{
[[incomingField setText:""] selectText:self];
[[outgoingField setText:""] selectText:self];
[inputField selectText:self];
return self;
}
// Buffers
- flushInput:sender
{
if (![serialPort flushInput]) {
NXRunAlertPanel(NULL, "%s",
NULL, NULL, NULL,
[serialPort statusString]);
[serialPort clearStatus];
}
return self;
}
- flushOutput:sender
{
if (![serialPort flushOutput]) {
NXRunAlertPanel(NULL, "%s",
NULL, NULL, NULL,
[serialPort statusString]);
[serialPort clearStatus];
}
return self;
}
- flushAll:sender
{
if (![serialPort flush]) {
NXRunAlertPanel(NULL, "%s",
NULL, NULL, NULL,
[serialPort statusString]);
[serialPort clearStatus];
}
return self;
}
// Settings
- takeCRModFrom:sender
{
id cell = [sender isKindOf:[Cell class]]
? sender : [sender selectedCell];
[serialPort setCRMassage:[cell state]];
if ([serialPort status]) {
NXRunAlertPanel(NULL, "%s",
NULL, NULL, NULL,
[serialPort statusString]);
[serialPort clearStatus];
}
return self;
}
- takeDuplexFrom:sender
{
id cell = [sender isKindOf:[Cell class]]
? sender : [sender selectedCell];
// confirm that this rather foolish course of action
// is in fact desired.
if ([cell state] && NXRunAlertPanel("Feedback warning",
"If your modem is set to echo, then setting the "
"port to echo will result in the next character "
"you send bouncing back and forth forever, and "
"you will have to send this process a HUP signal "
"to regain control.", "Cancel", "Ok", NULL)) {
// turn off switch if the user changed their mind
[cell perform:@selector(setState:)
with:(id)(int)NO
afterDelay:0
cancelPrevious:YES];
[window perform:@selector(display)
with:nil
afterDelay:0
cancelPrevious:YES];
return self;
}
// if they really do want to, then do it
[serialPort setDuplex:[cell state]
? LGD_SP_FULLDUPLEX : LGD_SP_HALFDUPLEX];
if ([serialPort status]) {
NXRunAlertPanel(NULL, "%s",
NULL, NULL, NULL,
[serialPort statusString]);
[serialPort clearStatus];
}
return self;
}
- takeAutoPollFrom:sender
{
id cell = [sender isKindOf:[Cell class]]
? sender : [sender selectedCell];
// we set the target in awakeFromNib, so we need only
// set the action here
[serialPort setAction:[cell state]
? @selector(poll:) : NULL];
return self;
}
- takeModeFrom:sender
{
id cell = [sender isKindOf:[Cell class]]
? sender : [sender selectedCell];
if (![serialPort isOpen]) {
return self;
}
[serialPort setMode:[cell tag]];
if ([serialPort status]) {
NXRunAlertPanel(NULL, "%s",
NULL, NULL, NULL,
[serialPort statusString]);
[serialPort clearStatus];
}
return self;
}
// Signals
- raiseDTR:sender
{
[serialPort raiseDTR];
if ([serialPort status]) {
NXRunAlertPanel(NULL, "%s",
NULL, NULL, NULL,
[serialPort statusString]);
[serialPort clearStatus];
}
return self;
}
- lowerDTR:sender
{
[serialPort lowerDTR];
if ([serialPort status]) {
NXRunAlertPanel(NULL, "%s",
NULL, NULL, NULL,
[serialPort statusString]);
[serialPort clearStatus];
}
return self;
}
- raiseBRK:sender
{
[serialPort raiseBreak];
if ([serialPort status]) {
NXRunAlertPanel(NULL, "%s",
NULL, NULL, NULL,
[serialPort statusString]);
[serialPort clearStatus];
}
return self;
}
- lowerBRK:sender
{
[serialPort lowerBreak];
if ([serialPort status]) {
NXRunAlertPanel(NULL, "%s",
NULL, NULL, NULL,
[serialPort statusString]);
[serialPort clearStatus];
}
return self;
}
// Application delegate methods
- appDidInit:anApplication
{
char *username;
int signals[] = {
SIGINT, SIGQUIT, SIGBUS, SIGSEGV, SIGTERM, 0
};
int i;
// set ourself up to die nicely no matter what happens
// (well, almost whatever. We can't catch KILL)
port = serialPort;
signal(SIGHUP, (void*)hangup);
for (i=0; signals[i]; i++) {
signal(signals[i], (void *)cleanup);
}
// check uid
username = getpwuid(geteuid())->pw_name;
if (strcmp(username, "root") && strcmp(username, "uucp")) {
NXRunAlertPanel("Process Owner", "WARNING: %s. %s",
NULL, NULL, NULL,
"Not running as root or uucp",
"Permission errors are likely");
}
return self;
}
- appWillTerminate:anApplication
{
// try the orderly shutdown first
if ([serialPort isOpen] && ![serialPort unlockAndClose]) {
NXRunAlertPanel(NULL, "%s",
NULL, NULL, NULL,
[serialPort statusString]);
[serialPort clearStatus];
}
// freeing the serial port is the best way to ensure that
// it is disconnected properly if the orderly shutdown failed
[serialPort free];
return self;
}
// SerialPort delegate methods
- serialPortWillOpen:aPort
{
const char *device = POPUP_STRING(devicePopup);
[aPort setDevice:device];
return self;
}
- serialPortDidOpen:aPort
{
[self takeModeFrom:modeMatrix];
[self takeCRModFrom:CRModSwitch];
[self takeDuplexFrom:duplexSwitch];
[sendButton setEnabled:YES];
[pollButton setEnabled:YES];
[peekButton setEnabled:YES];
[devicePopup setEnabled:NO];
[inputField selectText:self];
return self;
}
- serialPortDidClose:aPort
{
[sendButton setEnabled:NO];
[pollButton setEnabled:NO];
[peekButton setEnabled:NO];
[devicePopup setEnabled:YES];
return self;
}
// Archiving
- awakeFromNib
{
[sendButton setEnabled:NO];
[pollButton setEnabled:NO];
[peekButton setEnabled:NO];
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.