This is PageSupplier.m in view mode; [Download] [Up]
/* (c) 1992 Dirk Schwarzhans, Matthias Braun
Use under the terms of the GNU General Public License */
#import "PageSupplier.h"
#import <appkit/Application.h>
#import <soundkit/soundkit.h>
#import <mach_error.h>
#import <sys/message.h>
#import <sound/sound.h>
#import <sound/sounddriver.h>
#import <string.h>
#import <appkit/Panel.h>
/* Host-Messages and den DSP (ACHTUNG: muû mit dsp.asm öbereinstimmen) */
#define HM_REQ_PAGE 0x200000 // setzt Anforderungsdaten
#define HM_DISP_CNTL 0x210000 // setzt die Display-Control-Register
#define HM_DISP_MODE 0x220000 // setzt das Display-Modus-Register
#define HM_DSP_STOP 0x230000 // Arbeit einstellen
#define HM_SYS_CONFIG 0x240000 // Messages und Uhrzeit schalten
#define HM_MODE 0x250000 // Modus-Register Bits 2:0 schreiben
#define DMA_BUFFER_SIZE 1024 // in Bytes
#define LOW_WATER_MARK 4 * 1024 // Konfiguration des šbertragungskanals
#define HIGH_WATER_MARK 8 * 1024 // vom DSP
#define READ_WIDTH 1 // Bytes pro Sample
#define BIN2ASC(a) (((a) < 10) ? ((a) + '0') : ((a) + 'A' - 10))
// die folgende Struktur nimmt die Daten för jedes Fenster auf
typedef struct
{
VTPageNumber page; // angeforderte Seite
VTSubpageNumber subpage; // und Unterseite
BOOL hold; // Flag, ob Fenster angehalten
BOOL careSubpage; // Flag, ob bestimmte Unterseite angef.
} windowInfo;
extern const char *NXArgv[];
static void dspThread(PageSupplier *self);
static void comThread(PageSupplier *self);
static void dataHandler(PageSupplier *self, int tag, unsigned char *data, int n);
static void msgHandler(PageSupplier *self, int *data, int n);
@implementation PageSupplier
// lokale Methoden
// holt das Storage-Objekt einer Seite; legt es notfalls an, wenn gefordert
- (Storage *)dataOfPage:(VTPageNumber)page subpage:(VTSubpageNumber)subpage
create:(BOOL)flag
{
void *key;
HashTable *subpages;
Storage *pageContainer;
key = *((void **)&page); // Umwandlung för HashTable erforderlich
subpages = [allPages valueForKey:key];
if (subpages == nil && flag)
{
// Tabelle mit allen Unterseiten dieser Seite neu anlegen
subpages = [[HashTable alloc] initKeyDesc:"i" valueDesc:"@"];
[allPages insertKey:key value:subpages];
}
// möglicherweise ist subpages nil, was aber nichts ausmacht
key = *((void **)&subpage);
pageContainer = [subpages valueForKey:key];
if (pageContainer == nil && flag)
{
// Unterseitenspeicher neu anlegen
pageContainer = [[Storage alloc] initCount:1 elementSize:1024
description:"[1024c]"];
[subpages insertKey:key value:pageContainer];
}
return pageContainer;
}
// holt von einer gegebenen Seite die höchste Unterseite unterhalb einer
// öbergebenen Unterseitennummer; gibt bei Nichtvorhandensein nil zuröck
- (Storage *)greatestSubpageOf:(VTPageNumber)page
beforeSubpage:(VTSubpageNumber)margin
newSubpage:(VTSubpageNumber *)new
{
NXHashState state;
VTSubpageNumber maxSubpage, subpage;
HashTable *subpages;
Storage *maxPageContainer,*pageContainer;
subpages = [allPages valueForKey:*((void **)&page)];
maxSubpage = (VTSubpageNumber)0;
maxPageContainer = nil;
state = [subpages initState];
while ([subpages nextState:&state key:(void *)&subpage
value:(void *)&pageContainer])
{
if (subpage < margin && subpage >= maxSubpage)
{
// bessere Seite gefunden
maxSubpage = subpage;
maxPageContainer = pageContainer;
}
}
if (new != NULL && maxPageContainer != nil)
*new = maxSubpage;
return maxPageContainer;
}
// holt von einer gegebenen Seite die kleinste Unterseite oberhalb einer
// öbergebenen Unterseitennummer; gibt bei Nichtvorhandensein nil zuröck
- (Storage *)smallestSubpageOf:(VTPageNumber)page
afterSubpage:(VTSubpageNumber)margin
newSubpage:(VTSubpageNumber *)new
{
NXHashState state;
VTSubpageNumber minSubpage, subpage;
HashTable *subpages;
Storage *minPageContainer,*pageContainer;
subpages = [allPages valueForKey:*((void **)&page)];
minSubpage = (VTSubpageNumber)0x00ffffff;
minPageContainer = nil;
state = [subpages initState];
while ([subpages nextState:&state key:(void *)&subpage
value:(void *)&pageContainer])
{
if (subpage > margin && subpage <= minSubpage)
{
// bessere Seite gefunden
minSubpage = subpage;
minPageContainer = pageContainer;
}
}
if (new != NULL && minPageContainer != nil)
*new = minSubpage;
return minPageContainer;
}
// öberpröft, ob eine Seite gesendet werden kann und tut dies gegebenfalls
// wenn das nicht möglich sein sollte, wird die laufende Seitennummer eing.
- sendPageIfPossible
{
Storage *pageContainer;
windowInfo *info;
if ((info = [(Storage *)[windowTable valueForKey:actualWindow]
elementAt:0]) != NULL)
{
if (info->hold)
[self requestPageMessages:NO];
else
{
pageContainer = [self dataOfPage:info->page subpage:info->subpage
create:NO];
if (pageContainer == nil && !info->careSubpage)
{ // möglicherweise andere Unterseite finden
pageContainer = [self smallestSubpageOf:info->page
afterSubpage:(VTSubpageNumber)0
newSubpage:&info->subpage];
}
if (pageContainer != nil)
{
mutex_lock(self->comMem);
self->pagePacket.data = [pageContainer elementAt:0];
self->pagePacket.window = actualWindow;
self->pagePacket.tag = tag;
self->pageReady = YES;
mutex_unlock(self->comMem);
condition_signal(self->comMemChanged);
}
else
[self requestPageMessages:YES];
}
}
return self;
}
- init
{
return [self initPort:PORT_NULL];
}
- initPort:(port_t)port
{
int soundError, protocol;
Sound *dspCode;
BOOL retry;
dev_port=0;
owner_port=0;
do
{
retry = NO;
soundError = SNDAcquire(SND_ACCESS_DSP, 0, 0, 0, NULL_NEGOTIATION_FUN,
0, &dev_port, &owner_port);
if (soundError != SND_ERR_NONE)
{
retry = (NXRunAlertPanel(NULL, "DSP schon belegt.",
"Nochmal", "Abbruch", NULL) == NX_ALERTDEFAULT);
if (!retry)
return nil;
}
}while(retry);
snddriver_get_dsp_cmd_port(dev_port, owner_port, &cmd_port);
port_allocate(task_self(), &reply_port);
protocol = SNDDRIVER_DSP_PROTO_RAW;
snddriver_stream_setup(dev_port, owner_port,
SNDDRIVER_DMA_STREAM_FROM_DSP,
DMA_BUFFER_SIZE, READ_WIDTH,
LOW_WATER_MARK, HIGH_WATER_MARK,
&protocol, &read_port);
snddriver_dsp_protocol(dev_port, owner_port, protocol);
dspCode = [Sound newFromMachO:"DSP.snd"];
soundError = SNDBootDSP(dev_port, owner_port, [dspCode soundStruct]);
[dspCode free];
if (soundError != SND_ERR_NONE)
{
NXRunAlertPanel(NULL, "DSP-Fehler: konnte nicht booten!",
NULL, NULL, NULL);
return nil;
}
DSPThreadAborted = threadsAborted = NO;
strcpy(clockString,"12345678");
strcpy(pageString,"123");
interruptedSequenz = NO;
allPages = [[HashTable alloc] initKeyDesc:"i" valueDesc:"@"];
windowTable = [[HashTable alloc] initKeyDesc:"@" valueDesc:"@"];
actualWindow = nil;
tag = 0;
clockMessages = pageMessages = NO;
depositFull = NO;
depositValid = NO;
deposit = [[Storage alloc] initCount:1 elementSize:1024
description:"[1024c]"];
VTNumbersFromInt(&(VTPageNumber)depositPage,
&(VTSubpageNumber)depositSubpage, 0, 0);
memoryInUse = mutex_alloc();
comMem = mutex_alloc();
comMemChanged = condition_alloc();
sending = mutex_alloc();
pageReady = clockReady = pageNumReady = error = NO;
errorString = NULL;
port_allocate(task_self(), &speakerReplyPort);
speaker = [[VTSpeaker alloc] init];
[speaker setSendPort:port];
[speaker setReplyPort:speakerReplyPort];
cthread_detach(cthread_fork((cthread_fn_t)dspThread, (any_t)self));
cthread_detach(cthread_fork((cthread_fn_t)comThread, (any_t)self));
return self;
}
- stopThreads
{
int hostMsg;
hostMsg = HM_DSP_STOP;
mutex_lock(sending);
snddriver_dsp_write(cmd_port, &hostMsg, 1, sizeof(int),
SNDDRIVER_HIGH_PRIORITY);
mutex_unlock(sending);
return self;
}
- free
{
if (!threadsAborted)
return self;
SNDRelease(SND_ACCESS_DSP, dev_port, owner_port); // Ports freigeben ???
port_deallocate(task_self(), read_port);
port_deallocate(task_self(), reply_port);
port_deallocate(task_self(), cmd_port);
[windowTable freeObjects];
[windowTable free];
[self forgetAll];
[allPages free];
[deposit free];
[speaker free];
port_deallocate(task_self(), speakerReplyPort);
mutex_free(memoryInUse);
mutex_free(comMem);
condition_free(comMemChanged);
mutex_free(sending);
return [super free];
}
// löscht den gesamten Seitenspeicher und fordert die aktuelle Seite neu an
- (unsigned)forgetAll
{
NXHashState state;
VTPageNumber pageNum;
HashTable *allSubpages;
windowInfo *info;
int hostMsg;
mutex_lock(memoryInUse);
tag++;
depositFull = NO; // vorsichtshalber
// Seitenspeicher löschen
state = [allPages initState];
while ([allPages nextState:&state key:(void *)&pageNum
value:(void *)&allSubpages])
{
[allSubpages freeObjects];
}
[allPages freeObjects];
// falls ein Fenster aktiv ist, dessen Seite neu anfordern
if ((info = [(Storage *)[windowTable valueForKey:actualWindow]
elementAt:0]) != NULL)
{
[self requestPageMessages:YES];
info->hold = NO;
hostMsg = HM_REQ_PAGE | info->page;
mutex_lock(sending);
snddriver_dsp_write(cmd_port, &hostMsg, 1, sizeof(int),
SNDDRIVER_HIGH_PRIORITY);
mutex_unlock(sending);
}
mutex_unlock(memoryInUse);
return tag;
}
// aktuelles Fenster setzen
- (unsigned)setMainWindow:(Window *)window
{
Storage *infoContainer;
windowInfo *info;
int hostMsg;
mutex_lock(memoryInUse);
tag++;
// Wenn das Fenster bisher unbekannt ist, dann Tabelleneintrag erzeugen und
// nach Seite 100.XXXX suchen
if ((infoContainer = [windowTable valueForKey:window]) == nil)
{
infoContainer = [[Storage alloc] initCount:1 elementSize:sizeof(*info)
description:"iicc"];
[windowTable insertKey:window value:infoContainer];
info = [infoContainer elementAt:0];
VTNumbersFromInt(&info->page, &info->subpage, 100, 0);
info->hold = NO;
info->careSubpage = NO;
}
actualWindow = window;
info = [infoContainer elementAt:0];
// Seitenanforderung an den DSP senden
hostMsg = HM_REQ_PAGE | info->page;
mutex_lock(sending);
snddriver_dsp_write(cmd_port, &hostMsg, 1, sizeof(int),
SNDDRIVER_HIGH_PRIORITY);
mutex_unlock(sending);
// evtl. schon im Cache vorhandene Seite zuröckgeben
[self sendPageIfPossible];
mutex_unlock(memoryInUse);
return tag;
}
// ein Fenster wurde geschlossen
- (unsigned)windowClosed:(Window *)window
{
mutex_lock(memoryInUse);
tag++;
if (window == actualWindow)
{
[self requestPageMessages:NO];
actualWindow = nil;
}
[(Storage *)[windowTable valueForKey:window] free];
[windowTable removeKey:window];
mutex_unlock(memoryInUse);
return tag;
}
// Seitenanforderung ohne Beachtung von Unterseitennummern
- (unsigned)pageRequest:(VTPageNumber)number
{
windowInfo *info;
int hostMsg;
mutex_lock(memoryInUse);
tag++;
if ((info = [(Storage *)[windowTable valueForKey:actualWindow]
elementAt:0]) != NULL)
{
VTNumbersFromInt(&info->page, &info->subpage, 0, 0);
info->page = number;
info->hold = info->careSubpage = NO;
hostMsg = HM_REQ_PAGE | number;
mutex_lock(sending);
snddriver_dsp_write(cmd_port, &hostMsg, 1, sizeof(int),
SNDDRIVER_HIGH_PRIORITY);
mutex_unlock(sending);
[self sendPageIfPossible];
}
mutex_unlock(memoryInUse);
return tag;
}
// Seitenanforderung mit Beachtung von Unterseitennummern
- (unsigned)pageRequest:(VTPageNumber)page subpage:(VTSubpageNumber)subpage
{
windowInfo *info;
int hostMsg;
mutex_lock(memoryInUse);
tag++;
if ((info = [(Storage *)[windowTable valueForKey:actualWindow]
elementAt:0]) != NULL)
{
info = [(Storage *)[windowTable valueForKey:actualWindow] elementAt:0];
info->subpage = subpage;
info->page = page;
info->hold = NO;
info->careSubpage = YES;
hostMsg = HM_REQ_PAGE | page;
mutex_lock(sending);
snddriver_dsp_write(cmd_port, &hostMsg, 1, sizeof(int),
SNDDRIVER_HIGH_PRIORITY);
mutex_unlock(sending);
[self sendPageIfPossible];
}
mutex_unlock(memoryInUse);
return tag;
}
- (unsigned)doCareSubpage:(VTSubpageNumber)number
{
windowInfo *info;
mutex_lock(memoryInUse);
tag++;
if ((info = [(Storage *)[windowTable valueForKey:actualWindow]
elementAt:0]) != NULL)
{
info->hold = NO;
info->subpage = number;
info->careSubpage = YES;
[self sendPageIfPossible];
}
mutex_unlock(memoryInUse);
return tag;
}
- (unsigned)dontCareSubpage
{
windowInfo *info;
mutex_lock(memoryInUse);
tag++;
if ((info = [(Storage *)[windowTable valueForKey:actualWindow]
elementAt:0]) != NULL)
{
info->careSubpage = NO;
}
mutex_unlock(memoryInUse);
return tag;
}
- (unsigned)holdPage:(BOOL)hold;
{
windowInfo *info;
mutex_lock(memoryInUse);
tag++;
if ((info = [(Storage *)[windowTable valueForKey:actualWindow]
elementAt:0]) != NULL)
{
info->hold = hold;
[self sendPageIfPossible];
}
mutex_unlock(memoryInUse);
return tag;
}
- (unsigned)nextSubpage:(VTSubpageNumber *)requested
{
windowInfo *info;
VTSubpageNumber new;
mutex_lock(memoryInUse);
tag++;
if ((info = [(Storage *)[windowTable valueForKey:actualWindow]
elementAt:0]) != NULL)
{
info->hold = NO;
info->careSubpage = YES;
if ([self smallestSubpageOf:info->page afterSubpage:info->subpage
newSubpage:&new] != nil)
{
info->subpage = new;
}
if (requested != NULL)
*requested = info->subpage;
[self sendPageIfPossible];
}
mutex_unlock(memoryInUse);
return tag;
}
- (unsigned)previousSubpage:(VTSubpageNumber *)requested
{
windowInfo *info;
VTSubpageNumber new;
mutex_lock(memoryInUse);
tag++;
if ((info = [(Storage *)[windowTable valueForKey:actualWindow]
elementAt:0]) != NULL)
{
info->hold = NO;
info->careSubpage = YES;
if ([self greatestSubpageOf:info->page beforeSubpage:info->subpage
newSubpage:&new] != nil)
{
info->subpage = new;
}
if (requested != NULL)
*requested = info->subpage;
[self sendPageIfPossible];
}
mutex_unlock(memoryInUse);
return tag;
}
- requestClockMessages:(BOOL)flag
{
int hostMsg;
clockMessages = flag;
hostMsg = HM_SYS_CONFIG;
if (pageMessages)
hostMsg |= 1;
if (clockMessages)
hostMsg |= 2;
mutex_lock(sending);
snddriver_dsp_write(cmd_port, &hostMsg, 1, sizeof(int),
SNDDRIVER_HIGH_PRIORITY);
mutex_unlock(sending);
return self;
}
- requestPageMessages:(BOOL)flag
{
int hostMsg;
pageMessages = flag;
hostMsg = HM_SYS_CONFIG;
if (pageMessages)
hostMsg |= 1;
if (clockMessages)
hostMsg |= 2;
mutex_lock(sending);
snddriver_dsp_write(cmd_port, &hostMsg, 1, sizeof(int),
SNDDRIVER_HIGH_PRIORITY);
mutex_unlock(sending);
return self;
}
- writeModeRegister:(unsigned char)data
{
int hostMsg;
hostMsg = HM_MODE | data;
mutex_lock(sending);
snddriver_dsp_write(cmd_port, &hostMsg, 1, sizeof(int),
SNDDRIVER_HIGH_PRIORITY);
mutex_unlock(sending);
return self;
}
- writeDisplayControlRegisters:(unsigned char)normal:(unsigned char)news
{
int hostMsg;
hostMsg = HM_DISP_CNTL | (normal << 8) | news;
mutex_lock(sending);
snddriver_dsp_write(cmd_port, &hostMsg, 1, sizeof(int),
SNDDRIVER_HIGH_PRIORITY);
mutex_unlock(sending);
return self;
}
- writeDisplayModeRegister:(unsigned char)data
{
int hostMsg;
hostMsg = HM_DISP_MODE | data;
mutex_lock(sending);
snddriver_dsp_write(cmd_port, &hostMsg, 1, sizeof(int),
SNDDRIVER_HIGH_PRIORITY);
mutex_unlock(sending);
return self;
}
@end
static void dspThread(PageSupplier *self)
{
snddriver_handlers_t handlers = {self, 0, 0, 0, 0, 0, 0, 0,
(sndreply_recorded_data_t)dataHandler,
0, (sndreply_dsp_msg_t)msgHandler};
msg_header_t *reply_msg;
msg_return_t retValue;
reply_msg = (msg_header_t *)malloc(MSG_SIZE_MAX);
snddriver_stream_start_reading(self->read_port, NULL, DMA_BUFFER_SIZE,
0, 0, 0, 0, 0, 0, 0, self->reply_port);
snddriver_stream_start_reading(self->read_port, NULL, DMA_BUFFER_SIZE,
0, 0, 0, 0, 0, 0, 0, self->reply_port);
snddriver_dspcmd_req_msg(self->cmd_port, self->reply_port);
while (!self->DSPThreadAborted)
{
reply_msg->msg_size = MSG_SIZE_MAX;
reply_msg->msg_local_port = self->reply_port;
retValue = msg_receive(reply_msg, MSG_OPTION_NONE, 0);
if (retValue != RCV_SUCCESS)
{
mutex_lock(self->comMem);
self->error = YES;
self->errorString = "Fehler beim Nachrichtenempfang";
mutex_unlock(self->comMem);
condition_signal(self->comMemChanged);
self->DSPThreadAborted = YES;
}
else
{
snddriver_reply_handler(reply_msg, &handlers);
}
}
}
static void dataHandler(PageSupplier *self, int tag, unsigned char *data, int n)
{
Storage *pageContainer;
VTPageNumber pageNum;
VTSubpageNumber subpageNum;
windowInfo *info;
if (n == 1024)
{
VTNumbersFromPageData(&pageNum, &subpageNum, data);
mutex_lock(self->memoryInUse);
// Daten in Cache eintragen, wenn erlaubt
if (!self->depositValid || self->depositPage != pageNum ||
self->depositSubpage != subpageNum)
{
pageContainer = [self dataOfPage:pageNum subpage:subpageNum
create:YES];
[pageContainer replace:data at:0];
}
else // sonst zwischenspeichern
{
[self->deposit replace:data at:0];
self->depositFull = YES;
pageContainer = nil;
}
if (((info = [(Storage *)[self->windowTable
valueForKey:self->actualWindow] elementAt:0]) != NULL) &&
(!info->hold) && (info->page == pageNum) &&
((!info->careSubpage) || (info->subpage == subpageNum)))
{
info->subpage = subpageNum;
if (pageContainer != nil)
{
mutex_lock(self->comMem);
self->pagePacket.data = [pageContainer elementAt:0];
self->pagePacket.window = self->actualWindow;
self->pagePacket.tag = self->tag;
self->pageReady = YES;
mutex_unlock(self->comMem);
condition_signal(self->comMemChanged);
}
}
mutex_unlock(self->memoryInUse);
}
if (snddriver_stream_start_reading(self->read_port, NULL, DMA_BUFFER_SIZE,
0, 0, 0, 0, 0, 0, 0, self->reply_port) != 0)
{
mutex_lock(self->comMem);
self->error = YES;
self->errorString = "Fehler beim Anfordern weiterer Seitendaten.";
mutex_unlock(self->comMem);
condition_signal(self->comMemChanged);
self->DSPThreadAborted = YES;
}
vm_deallocate(task_self(), (pointer_t)data, n);
}
static void msgHandler(PageSupplier *self, int *data, int n)
{
int i,j;
for (i=0; i<n; i++)
{
switch (data[i] >> 16)
{
case 0x10:
self->pageString[2] = BIN2ASC((data[i] >> 10) & 0xf);
self->pageString[1] = BIN2ASC((data[i] >> 5) & 0xf);
break;
case 0x11:
break;
case 0x12:
self->interruptedSequenz = (data[i] & 0x1000) ? YES : NO;
self->pageString[0] = BIN2ASC(data[i] & 0x7);
if (self->pageString[0] == '0')
self->pageString[0] = '8';
mutex_lock(self->comMem);
if (!self->interruptedSequenz && self->pageMessages)
{
for (j=0; j<4; j++)
self->pageString2[j] = self->pageString[j];
self->pageNumReady = YES;
}
mutex_unlock(self->comMem);
condition_signal(self->comMemChanged);
break;
case 0x13:
self->clockString[0] = (data[i] >> 8) & 0xff;
self->clockString[1] = data[i] & 0xff;
break;
case 0x14:
self->clockString[2] = (data[i] >> 8) & 0xff;
self->clockString[3] = data[i] & 0xff;
break;
case 0x15:
self->clockString[4] = (data[i] >> 8) & 0xff;
self->clockString[5] = data[i] & 0xff;
break;
case 0x16:
self->clockString[6] = (data[i] >> 8) & 0xff;
self->clockString[7] = data[i] & 0xff;
mutex_lock(self->comMem);
for (j=0; j<9; j++)
self->clockString2[j] = self->clockString[j];
self->clockReady = YES;
mutex_unlock(self->comMem);
condition_signal(self->comMemChanged);
break;
case 0x17:
mutex_lock(self->comMem);
self->error = YES;
mutex_unlock(self->comMem);
condition_signal(self->comMemChanged);
self->DSPThreadAborted = YES;
break;
default:
break;
}
}
if (!self->DSPThreadAborted)
if (snddriver_dspcmd_req_msg(self->cmd_port, self->reply_port) != 0)
{
mutex_lock(self->comMem);
self->error = YES;
self->errorString = "Fehler beim Anfordern weiterer DSP-Messages.";
mutex_unlock(self->comMem);
condition_signal(self->comMemChanged);
self->DSPThreadAborted = YES;
}
}
static void comThread(PageSupplier *self)
{
enum {pag, clk, pgn, stop} whatToDo;
PagePacket pagePacket;
char clockString[9];
char pageString[4];
char *errorString;
int i, dummy;
errorString = NULL;
while (!self->threadsAborted)
{
mutex_lock(self->comMem);
while(!self->pageReady && !self->clockReady &&
!self->pageNumReady && !self->error)
condition_wait(self->comMemChanged, self->comMem);
if (self->pageReady)
{
whatToDo = pag;
pagePacket = self->pagePacket;
self->pageReady = NO;
}
else if (self->clockReady)
{
whatToDo = clk;
for (i=0; i<9; i++)
clockString[i] = self->clockString2[i];
self->clockReady = NO;
}
else if (self->pageNumReady)
{
whatToDo = pgn;
for (i=0; i<4; i++)
pageString[i] = self->pageString2[i];
self->pageNumReady = NO;
}
else
{
whatToDo = stop;
errorString = (char *)self->errorString;
}
mutex_unlock(self->comMem);
switch (whatToDo)
{
case pag:
mutex_lock(self->memoryInUse);
if (self->tag == pagePacket.tag)
{
[self requestPageMessages:NO];
// ab jetzt dörfen die Seitendaten nicht mehr verÙndert werden
VTNumbersFromPageData(&(VTPageNumber)self->depositPage,
&(VTSubpageNumber)self->depositSubpage,
pagePacket.data);
self->depositValid = YES;
mutex_unlock(self->memoryInUse);
// richtige Seitennummer senden
stringFromVTPageNumber(pageString, self->depositPage);
[self->speaker updateRollingHeader:pageString
size:4 return:&dummy];
// Seitendaten senden
[self->speaker updatePageData:(char *)&pagePacket
size:sizeof(pagePacket) return:&dummy];
// evtl. zwischengespeicherte Seite einfögen
mutex_lock(self->memoryInUse);
if (self->depositFull)
{
[[self dataOfPage:self->depositPage
subpage:self->depositSubpage
create:YES] replace:[self->deposit elementAt:0] at:0];
}
self->depositFull = NO;
self->depositValid = NO;
mutex_unlock(self->memoryInUse);
// šberschreiben der Seitennummer verhindern
self->pageNumReady = NO;
}
else
mutex_unlock(self->memoryInUse);
break;
case clk:
[self->speaker updateClock:clockString
size:9 return:&dummy];
break;
case pgn:
[self->speaker updateRollingHeader:pageString
size:4 return:&dummy];
break;
case stop:
if (errorString != NULL)
[self->speaker printError:errorString];
[self->speaker threadsStopped];
self->threadsAborted = YES;
break;
}
}
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.