#include "IrGlue.h"
#include "IrLAP.h"
#include "IrLMP.h"
#include "IrLAPConn.h"
#include "IrEvent.h"
#include "CTimer.h"
#include "IrDiscovery.h"
#include "CIrDevice.h"
#include "IrQOS.h"
#include "IrDALog.h"
#include "IrStream.h"
#include "IrIASService.h"
#include "IrIASServer.h"
#include "IrLSAPConn.h"
#include "IrDAUserClient.h"
#include "AppleIrDA.h"
#define private static
#if (hasTracing > 0 && hasIrGlueTracing > 0)
enum IrGlueTraceCodes
{
kLogNew = 1,
kLogInit,
kLogFree,
kLogReadComplete,
kLogTransmitComplete,
kLogSetSpeedComplete,
kLogRunQueue,
kObtainLSAPIdEvent,
kReleaseLSAPIdEvent,
kConnectStartEvent,
kListenStartEvent,
kAllocateEventBlock,
kGrabEventBlock,
kReleaseEventBlock,
kDeleteEventBlock,
kStartTerminateEntry,
kStartTerminateExit,
kLogStartTimer,
kLogStopTimer,
kLogTimerNotifier,
kLogTimerNotifier1,
kLogTimerNotifier2,
kLogTimerNotifierDone,
kLogTimerComplete
};
private
EventTraceCauseDesc IrGlueTraceEvents[] = {
{kLogNew, "irglue: Create, obj="},
{kLogInit, "irglue: Init"},
{kLogFree, "irglue: Free"},
{kLogReadComplete, "irglue: read complete"},
{kLogTransmitComplete, "irglue: transmit complete"},
{kLogSetSpeedComplete, "irglue: set speed complete"},
{kLogRunQueue, "irglue: run event queue"},
{kObtainLSAPIdEvent, "irglue: Obtain LSAP Id"},
{kReleaseLSAPIdEvent, "irglue: Release LSAP Id"},
{kConnectStartEvent, "irglue: Connect request, myid, peerid, deviceaddr"},
{kListenStartEvent, "irglue: Listen request"},
{kAllocateEventBlock, "irglue: Allocate Event Block"},
{kGrabEventBlock, "irglue: Grab Event Block"},
{kReleaseEventBlock, "irglue: Release Event Block"},
{kDeleteEventBlock, "irglue: Delete Event Block"},
{kStartTerminateEntry, "irglue: Disconnected - start"},
{kStartTerminateExit, "irglue: Disconnected - done"},
{kLogStartTimer, "irglue: Start timer delay, #"},
{kLogStopTimer, "irglue: Stop timer #"},
{kLogTimerNotifier, "irglue: timer notifier, id="},
{kLogTimerNotifier1, "irglue: timer notifier, owner="},
{kLogTimerNotifier2, "irglue: timer notifier, timesrc="},
{kLogTimerNotifierDone, "irglue: timer notifier finished"},
{kLogTimerComplete, "irglue: timer complete, signature="}
};
#define XTRACE(x, y, z) IrDALogAdd (x, y, (uintptr_t)z & 0xffff, IrGlueTraceEvents, true )
#else
#define XTRACE(x, y, z) ((void)0)
#endif
static void TimerNotifier(OSObject *owner, IrDATimerEventSource *sender);
const UInt8 kIASDeviceClassStr[] = "Device";
const UInt8 kIASDeviceNameAttrStr[] = "DeviceName";
const UInt8 kIASDeviceName[] = "Macintosh";
const UInt8 kIASLMPSupportAttrStr[] = "IrLMPSupport";
const UInt8 kIASLMPSupportValue[] = { 0x01, 0x00, 0x00};
#define super OSObject
OSDefineMetaClassAndStructors(TIrGlue, OSObject);
TIrGlue *
TIrGlue::tIrGlue(AppleIrDASerial *driver, AppleIrDA *appleirda, IOWorkLoop *workloop, USBIrDAQoS *qos)
{
TIrGlue *obj = new TIrGlue;
XTRACE(kLogNew, 0, obj);
if (obj && !obj->init(driver, appleirda, workloop, qos)) {
obj->release();
obj = nil;
}
return obj;
}
Boolean TIrGlue::init(AppleIrDASerial *driver, AppleIrDA *appleirda, IOWorkLoop *workloop, USBIrDAQoS *qos)
{
IrDAErr err;
int i;
XTRACE(kLogInit, 0, 0);
fAppleIrDA = appleirda;
bzero(fTimers, sizeof(fTimers));
fLSAPIdsInUse = (UInt32) (1 << kNameServerLSAPId);
fIrLAP = nil;
fIrLMP = nil;
fIrLAPConn = nil;
fIrDevice = nil;
fIrDiscovery = nil;
fMyQOS = fPeerQOS = nil;
fNameServer = nil;
fNameService = nil;
fLastState = kIrDAStatusOff;
if (!super::init()) return false;
err = TIrEvent::InitEventLists();
nrequire(err, Fail);
for (i = 0; i < kNumTimers; i++) {
fTimers[i] = CTimer::cTimer(workloop, this, &::TimerNotifier);
require (fTimers[i], Fail);
}
fMyQOS = TIrQOS::tIrQOS(qos);
fPeerQOS = TIrQOS::tIrQOS(qos);
fIrLAP = TIrLAP::tIrLAP(this, fMyQOS, fPeerQOS);
require(fIrLAP, Fail);
fIrLMP = TIrLMP::tIrLMP(this);
require(fIrLMP, Fail);
fIrLAPConn = TIrLAPConn::tIrLAPConn(this);
require(fIrLAPConn, Fail);
fIrDevice = CIrDevice::cIrDevice(this, driver);
require(fIrDevice, Fail);
fNameService = TIASService::tIASService(); require(fNameService, Fail);
fNameServer = TIASServer::tIASServer(this, fNameService);
require(fNameServer, Fail);
fIrDiscovery = CIrDiscovery::cIrDiscovery(this);
require(fIrDiscovery, Fail );
require(InitNameService(), Fail);
fNameServer->ListenStart();
return true;
Fail:
XTRACE(kLogInit, 0xdead, 0xbeef);
return false;
}
#define FREE(x) {if (x) { (x)->release(); x = nil; } }
void
TIrGlue::free()
{
int i;
XTRACE(kLogFree, 0, this);
for (i = 0 ; i < kNumTimers; i++) { FREE(fTimers[i]);
}
FREE(fMyQOS);
FREE(fPeerQOS);
FREE(fIrDiscovery);
FREE(fIrDevice);
FREE(fIrLAPConn);
FREE(fIrLMP);
FREE(fIrLAP);
FREE(fNameServer);
FREE(fNameService);
TIrEvent::DeleteEventLists();
super::free();
}
void
TIrGlue::ReadComplete(UInt8 *buffer, UInt32 length)
{
XTRACE(kLogReadComplete, length >> 16, length);
if (fIrDevice)
fIrDevice->ReadComplete(buffer, length);
}
void
TIrGlue::TransmitComplete(Boolean worked)
{
XTRACE(kLogTransmitComplete, 0, worked);
if (fIrDevice)
fIrDevice->TransmitComplete(worked);
}
void
TIrGlue::SetSpeedComplete(Boolean worked)
{
XTRACE(kLogSetSpeedComplete, 0, worked);
if (fIrDevice)
fIrDevice->SetSpeedComplete(worked);
}
void
TIrGlue::RunQueue(void)
{
IrDAStatus status;
XTRACE(kLogRunQueue, 0, 0);
TIrStream::RunQueue();
XTRACE(kLogRunQueue, 0x1111, 0x1111);
GetIrDAStatus(&status);
XTRACE(kLogRunQueue, 0x2222, 0x2222);
if (fLastState != status.connectionState) {
fLastState = status.connectionState;
XTRACE(kLogRunQueue, 0x3333, 0x3333);
if (fAppleIrDA)
fAppleIrDA->messageClients(kIrDACallBack_Status, &fLastState, 1);
}
XTRACE(kLogRunQueue, 0xffff, 0xffff);
}
void
TIrGlue::Start()
{
if (fIrDevice)
fIrDevice->Start();
fLastState = kIrDAStatusIdle;
if (fAppleIrDA)
fAppleIrDA->messageClients(kIrDACallBack_Status, &fLastState, 1);
}
void
TIrGlue::Stop()
{
int i;
if (fIrDevice) fIrDevice->Stop();
for (i = 0 ; i < kNumTimers; i++)
StopTimer(i);
Disconnected(true);
fLastState = kIrDAStatusOff;
if (fAppleIrDA)
fAppleIrDA->messageClients(kIrDACallBack_Status, &fLastState, 1);
}
#pragma mark ---- Event blocks
TIrEvent *
TIrGlue::GrabEventBlock(UInt32 event, UInt32 size)
{
return TIrEvent::GrabEventBlock(event, size);
}
void
TIrGlue::ReleaseEventBlock(TIrEvent* reqBlock)
{
return TIrEvent::ReleaseEventBlock(reqBlock);
}
#pragma mark ---- Timers
void TIrGlue::StartTimer(int id, TTimeout timeDelay, UInt32 refCon)
{
XTRACE(kLogStartTimer, id, timeDelay);
require(id < kNumTimers && id >= 0, Fail);
if (fTimers[id])
fTimers[id]->StartTimer(timeDelay, refCon);
Fail:
return;
}
void TIrGlue::StopTimer(int id)
{
XTRACE(kLogStopTimer, 0, id);
require(id < kNumTimers && id >= 0, Fail);
if (fTimers[id])
fTimers[id]->StopTimer();
Fail:
return;
}
void TIrGlue::TimerComplete(UInt32 refCon)
{
XTRACE(kLogTimerComplete, 0, refCon);
if ((refCon >= kIrFirstIrLAPTimerEvent) && (refCon <= kIrLastIrLAPTimerEvent)) {
fIrLAP->TimerComplete(refCon); }
else
if ((refCon >= kIrFirstIrLMPTimerEvent) && (refCon <= kIrLastIrLMPTimerEvent)) {
fIrLMP->TimerComplete(refCon);
}
RunQueue();
}
private
void TimerNotifier(OSObject *owner, IrDATimerEventSource *iotimer)
{
TIrGlue *obj;
XTRACE(kLogTimerNotifier1, 0, owner);
XTRACE(kLogTimerNotifier2, 0, iotimer);
require(owner, Failed);
require(iotimer, Failed);
obj = OSDynamicCast(TIrGlue, owner);
require(obj, Failed);
for (int i = 0 ; i < kNumTimers; i++) {
CTimer *ctimer = obj->GetTimer(i);
if (ctimer && ctimer->GetIOTimer() == iotimer) { XTRACE(kLogTimerNotifier, 0, i);
obj->TimerComplete(ctimer->GetSignature()); XTRACE(kLogTimerNotifierDone, 0xffff, 0xffff);
return;
}
}
Failed:
XTRACE(kLogTimerNotifier, 0xdead, 0xbeef);
return;
}
#pragma mark ---- Lap Async Disconnect
void TIrGlue::Disconnected(Boolean reset_lap)
{
XTRACE(kStartTerminateEntry, 0, reset_lap);
fMyQOS->Reset();
fPeerQOS->Reset();
if (reset_lap) {
fIrLMP->Reset(); fIrLAP->Reset(); }
XTRACE(kStartTerminateExit, 0, 0);
}
Boolean TIrGlue::IsLAPConnected(void) {
require(fIrLAP, Fail);
return fIrLAP->IsConnected();
Fail:
return false;
}
void TIrGlue::DoIdleDisconnect()
{
require(fIrLAPConn, Fail);
fIrLAPConn->DoIdleDisconnect();
Fail:
return;
}
#pragma mark ---- Name and LSAPId Service
Boolean TIrGlue::InitNameService()
{
IrDAErr err;
err = fNameService->AddStringEntry(kIASDeviceClassStr, kIASDeviceNameAttrStr, kIASDeviceName, kIASCharSetAscii, 0);
nrequire(err, Fail);
err = fNameService->AddNBytesEntry(kIASDeviceClassStr, kIASLMPSupportAttrStr, kIASLMPSupportValue, sizeof(kIASLMPSupportValue));
nrequire(err, Fail);
return true;
Fail:
return false;
}
IrDAErr TIrGlue::ObtainLSAPId( UInt32 & desiredLSAPId )
{
UByte lsapId;
if (fLSAPIdsInUse == 0xFFFFFFFF) {
DebugLog("TIrGlue::ObtainLSAPId: no more LSAP Ids available");
return kIrDAErrResourceNotAvailable;
}
if (desiredLSAPId == kAssignDynamicLSAPId) {
lsapId = (UByte)random() & 0x1F; }
else {
if (desiredLSAPId > 0x1F ) {
DebugLog("TIrGlue::ObtainLSAPId: LSAP id out of range");
return kIrDAErrBadParameter;
}
lsapId = (UByte)desiredLSAPId; }
while ((lsapId == 0) || (fLSAPIdsInUse & (1 << lsapId))) {
lsapId = (lsapId + 1) & 0x1F;
}
if ((desiredLSAPId != kAssignDynamicLSAPId) && (lsapId != desiredLSAPId)) {
return kIrDAErrResourceNotAvailable;
}
desiredLSAPId = (ULong)lsapId;
fLSAPIdsInUse |= (1 << lsapId);
XTRACE(kObtainLSAPIdEvent, lsapId, fLSAPIdsInUse);
return noErr;
}
void TIrGlue::ReleaseLSAPId( UInt32 lsapId)
{
check( lsapId != kNameServerLSAPId );
check( lsapId < 32 );
check( fLSAPIdsInUse & (1 << lsapId) );
fLSAPIdsInUse &= ~(1 << lsapId);
XTRACE( kReleaseLSAPIdEvent, lsapId, fLSAPIdsInUse );
}
IrDAErr TIrGlue::RegisterMyNameAndLSAPId(UInt8 * className, UInt8 * attrName, UInt32 * reqLSAP)
{
IrDAErr result = kIrDAErrWrongState;
UInt32 tempLSAP = *reqLSAP;
require(fNameService, Fail);
require(className, Fail);
require(attrName, Fail);
result = ObtainLSAPId(tempLSAP);
nrequire(result, Fail);
*reqLSAP = tempLSAP;
result = fNameService->AddIntegerEntry(className, attrName, tempLSAP );
nrequire(result, Fail_RegisterLSAPId);
return noErr;
Fail_RegisterLSAPId:
ReleaseLSAPId( ( UByte )tempLSAP );
Fail:
return result;
}
#pragma mark ---- Connect and Listen
IrDAErr TIrGlue::ConnectStart( TIrStream * client, UInt32 myLSAPId, UInt32 devAddr, UInt32 peerLSAPId, CBuffer * clientData,
TLSAPConn ** theLSAP ) {
TIrConnLstnRequest *connectRequest = nil;
TLSAPConn *lsap = nil;
XTRACE( kConnectStartEvent, ( myLSAPId<<8 ) + peerLSAPId, devAddr );
connectRequest = (TIrConnLstnRequest*)GrabEventBlock(kIrConnectRequestEvent);
require(connectRequest, Fail);
if (*theLSAP == nil) { lsap = TLSAPConn::tLSAPConn(this, client); require(lsap, Fail_NewLSAPConn);
lsap->AssignId(myLSAPId);
*theLSAP = lsap; }
else
lsap = *theLSAP;
connectRequest->fDevAddr = devAddr;
connectRequest->fLSAPId = (UInt8)peerLSAPId;
connectRequest->fMyQOS = GetMyQOS();
connectRequest->fPeerQOS = GetPeerQOS();
connectRequest->fData = clientData;
connectRequest->fClient = client;
lsap->EnqueueEvent(connectRequest);
return noErr;
Fail_NewLSAPConn:
ReleaseEventBlock(connectRequest);
Fail:
return kIrDAErrNoMemory;
}
IrDAErr TIrGlue::ListenStart( TIrStream * client, UInt32 lsapId, CBuffer * clientData, TLSAPConn ** theLSAP ) {
TLSAPConn *lsap;
TIrConnLstnRequest *listenRequest;
XTRACE(kListenStartEvent, lsapId, 0);
listenRequest = (TIrConnLstnRequest *)GrabEventBlock(kIrListenRequestEvent);
require(listenRequest, Fail);
if (*theLSAP == nil) { lsap = TLSAPConn::tLSAPConn(this, client); require(lsap, Fail_NewLSAPConn);
lsap->AssignId( lsapId );
*theLSAP = lsap; }
else
lsap = *theLSAP;
listenRequest->fMyQOS = GetMyQOS();
listenRequest->fPeerQOS = GetPeerQOS();
listenRequest->fData = clientData;
lsap->EnqueueEvent( listenRequest );
return noErr;
Fail_NewLSAPConn:
ReleaseEventBlock(listenRequest);
Fail:
return kIrDAErrNoMemory;
}
void
TIrGlue::GetIrDAStatus(IrDAStatus *status)
{
Boolean connected = false;
Boolean discoverActive = false;
Boolean brokenConnection = false;
if (fIrDevice && fIrLAP && status) {
fIrDevice->GetStatus(status);
connected = fIrLAP->IsConnected();
brokenConnection = fIrLAP->InBrokenBeam();
discoverActive = fIrLAP->Discovering();
if( brokenConnection )
status->connectionState = kIrDAStatusBrokenConnection;
else
if( connected )
status->connectionState = kIrDAStatusConnected;
else
if( discoverActive )
status->connectionState = kIrDAStatusDiscoverActive;
else
status->connectionState = kIrDAStatusIdle;
status->connectionSpeed = fIrDevice->GetSpeed();
fIrLAP->GetNickName(status->nickName, sizeof(status->nickName));
}
}
#ifdef NOT_NOW
#pragma mark ------------------ NOT NOW ----------
extern "C"
pascal void XDeferredTaskProc( void *parm );
NewtonErr TIrGlue::Init()
{
NewtonErr result;
OSErr err;
XTRACE(kInit, (int)this >> 16, this);
gIrDAPrefs.Init();
fMyQOS.Reset(); fPeerQOS.Reset();
result = InitEventBlockList();
nrequire( result, Fail_Init );
result = fIrLAP.Init(this, &fIrLMP); nrequire( result, Fail_Init );
result = fIrLMP.Init(this, &fIrLAP); nrequire( result, Fail_Init );
result = fIrDiscovery.Init( this );
nrequire( result, Fail_Init );
InitNameService();
return noErr;
Fail_Init:
DeInit(); return -1;
}
void TIrGlue::free(void)
{
XTRACE(kDeInit, 0, 0);
fTimer1.DeInit();
fTimer2.DeInit();
fTimer3.DeInit();
DeleteEventBlockList();
}
#endif // NOT_NOW