#include "IrComm.h"
#include "IrDAComm.h"
#include "IrGlue.h"
#include "CBufferSegment.h"
#include "ttppdu.h"
#include "IrDALog.h"
#pragma mark -- Globals
#if (hasTracing > 0 && hasIrCommTracing > 0)
enum TraceCodes
{
kLogNew = 1,
kLogFree,
kLogInit,
kLogTxAvail,
kLogWrite,
kLogReturnCredit,
kLogBackEnable,
kLogTryConnect,
kLogListen,
kLogDisconnect,
kLogDiscoverComplete,
kLogLkupDone,
kLogConnectConfirm,
kLogDisconnected,
kLogConnectIndication,
kLogAcceptDone,
kLogTTPDataRead,
kLogTTPDataRead2,
kLogDataWrite,
kLogDataRead
};
static
EventTraceCauseDesc gTraceEvents[] = {
{kLogNew, "IrComm: new, obj="},
{kLogFree, "IrComm: free, obj="},
{kLogInit, "IrComm: init, obj="},
{kLogTxAvail, "IrComm: tx available, returning="},
{kLogWrite, "IrComm: write, count="},
{kLogReturnCredit, "IrComm: return credit. bytes consumed, count="},
{kLogBackEnable, "IrComm: back eable"},
{kLogTryConnect, "IrComm: try to connect"},
{kLogListen, "IrComm: listen"},
{kLogDisconnect, "IrComm: disconnect request"},
{kLogDiscoverComplete, "IrComm: discover complete, numfound=, result="},
{kLogLkupDone, "IrComm: lookup done, result=, peerid="},
{kLogConnectConfirm, "IrComm: connect confirm, result="},
{kLogDisconnected, "IrComm: disconnected. reason="},
{kLogConnectIndication, "IrComm: listen complete"},
{kLogAcceptDone, "IrComm: accept done"},
{kLogTTPDataRead, "IrComm: read complete, result=, len="},
{kLogTTPDataRead2, "IrComm: read ctlLen=, dataLen="},
{kLogDataWrite, "IrComm: write data"},
{kLogDataRead, "IrComm: read data"}
};
#define XTRACE(x, y, z) IrDALogAdd( x, y, (uintptr_t)z & 0xffff, gTraceEvents, true )
#else
#define XTRACE(x, y, z) ((void)0)
#endif
#pragma mark -- Prototypes
void InitSizeQueue(void); void AddPacketSize(short length); short FirstPacketSize(void); void ShrinkFirstPacketSize(short length); void NukeFirstPacketSize(void);
extern IrDAErr Dequeue(QElemPtr qElement, QHdrPtr qHeader); extern IrDAErr Enqueue(QElemPtr qElement, QHdrPtr qHeader);
#if (hasTracing > 0 && hasIrCommTracing > 1)
void IrDALogData(int msg, UInt8 *buf, int count); #define LOGDATA(msg, buf, count) IrDALogData(msg, buf, count)
#else
#define LOGDATA(msg, buf, count) (void)0)
#endif
#define super TTinyTP
OSDefineMetaClassAndStructors(IrComm, TTinyTP);
IrComm *
IrComm::irComm(TIrGlue *irda, IrDAComm *irdacomm)
{
IrComm *obj = new IrComm;
XTRACE(kLogNew, 0, obj);
if (obj && !obj->Init(irda, irdacomm)) {
obj->release();
obj = nil;
}
return obj;
}
void
IrComm::free(void)
{
XTRACE(kLogFree, 0, this);
super::free();
}
Boolean
IrComm::Init(TIrGlue *irda, IrDAComm *irdacomm)
{
XTRACE(kLogInit, 0, this);
UInt8 *classname = (UInt8 *)"IrDA:IrCOMM";
fIrDAComm = irdacomm;
fConnected = false;
fMaxPacketSize = 2048;
InitSizeQueue();
if (!super::TTPInitialize(
irda,
(UInt32)kTinyTPCredit, (UInt32)kAssignDynamicLSAPId, classname, (ULong)kDevInfoHintIrCOMM)) return false;
return true;
}
UInt32
IrComm::TxBufferAvailable(void)
{
if (fConnected) {
UInt32 count;
count = TTPXmitQueueSize(fMaxPacketSize) * fMaxPacketSize;
XTRACE(kLogTxAvail, count >> 16, count);
return count;
}
XTRACE(kLogTxAvail, 0xffff, 0xffff);
return 30*1024; }
UInt32
IrComm::Write(UInt8 *buf, UInt32 length)
{
UInt32 written = 0;
XTRACE(kLogWrite, length >> 16, length);
require(buf, Done);
require(length > 0, Done);
while (length > 0) {
CBufferSegment *pkt;
int rc, len;
require(TTPXmitQueueSize(fMaxPacketSize) > 0, Done);
len = Min(length, fMaxPacketSize);
require(len > 0, Done);
require(len < 2047, Done);
pkt = BufAlloc(len + 1);
require(pkt, Done);
rc = pkt->Put(0); check(rc == 0);
rc = pkt->Putn(buf, len);
require(rc == len, Done);
BufHideRest(pkt);
DoDataRequest(pkt);
BufFree(pkt);
buf += len;
written += len;
length -= len;
}
Done:
return written;
}
void
IrComm::ReturnCredit(UInt32 bytecount)
{
XTRACE(kLogReturnCredit, bytecount >> 16, bytecount);
short x;
while (bytecount > 0) { x = FirstPacketSize(); require(x > 0, Fail);
if (bytecount >= (UInt32)x) { NukeFirstPacketSize(); bytecount -= x; TTPRxDone(); }
else { ShrinkFirstPacketSize(bytecount);
bytecount = 0; }
}
Fail:
return;
}
void
IrComm::TryConnect(int slots)
{
XTRACE(kLogTryConnect, 0, fConnected);
if (fConnected == false)
DoDiscoverRequest(slots); }
void
IrComm::Listen(void)
{
CBufferSegment *buf;
XTRACE(kLogListen, 0, fConnected);
require(fConnected == false, Fail);
buf = BufAlloc(1000); require(buf, Fail);
DoListenRequest(buf);
Fail:
return;
}
void
IrComm::Disconnect(void)
{
XTRACE(kLogDisconnect, 0, 0);
DoDisconnectRequest(nil);
}
#pragma mark ==== TinyTP Callbacks ====
void IrComm::TTPDiscoverComplete(int numFound, IrDAErr result)
{
int peer_index; Boolean found_ircomm_peer = false;
XTRACE(kLogDiscoverComplete, numFound, result);
#if (hasTracing > 0 && hasIrCommTracing > 1)
peer_index = 0; DebugLog("numFound=%d, result=%ld", numFound, result);
#else
peer_index = -1; #endif
if (numFound > 0) {
int i;
#if (hasTracing > 0 && hasIrCommTracing > 1)
for (i = 0 ; i < numFound; i++) { DebugLog("discovered at %ld nicname '%s' hints 0x%lx",
fDiscoverInfo[i].addr,
fDiscoverInfo[i].name,
fDiscoverInfo[i].serviceHints);
}
#endif
for (i = 0 ; i < numFound; i++) { if (fDiscoverInfo[i].serviceHints & kDevInfoHintIrCOMM) { peer_index = i;
found_ircomm_peer = true;
break;
}
}
if (peer_index >= 0) { IrDAErr err;
UInt8 *classname = (UInt8 *)"IrDA:IrCOMM";
UInt8 *attrname = (UInt8 *)"IrDA:TinyTP:LsapSel";
#if (hasTracing > 0 && hasIrCommTracing > 0)
if (found_ircomm_peer == false) classname = (UInt8 *)"HP-BDP"; #endif
fPeerAddress = fDiscoverInfo[peer_index].addr;
err = LSAPLookup(classname, attrname, fDiscoverInfo[peer_index].addr);
ncheck(err);
if (err == noErr) return;
}
}
if (fIrDAComm)
fIrDAComm->ConnectionStatus(false);
}
void IrComm::TTPLookupComplete(IrDAErr result,UInt32 peerLSAPId)
{
XTRACE(kLogLkupDone, result, peerLSAPId);
#if (hasTracing > 0 && hasIrCommTracing > 0)
DebugLog("lookup complete, result=%ld, lsap=%ld", (long int)result, (long int)peerLSAPId);
#endif
if (result == noErr && peerLSAPId > 0) {
DoConnectRequest ( fPeerAddress, peerLSAPId, nil, 0, nil); }
else {
fConnected = false;
if (fIrDAComm)
fIrDAComm->ConnectionStatus(false); }
}
void
IrComm::TTPConnectIndication ( IrDAErr result,
TTPSAP SAP, TIrQOS *ourQOS, TIrQOS *peerQOS, int MaxSduSize, TTPBuf *UserData) {
XTRACE(kLogConnectIndication, 0, result);
require(UserData, Fail); BufFree(UserData);
if (result == noErr) {
if (peerQOS) fMaxPacketSize = peerQOS->GetDataSize() - 5;
else fMaxPacketSize = 2048;
DoConnectResponse ( SAP, 0, nil); }
else if (fIrDAComm)
fIrDAComm->ConnectionStatus(false);
Fail:
return;
}
void
IrComm::TTPConnectConfirm ( TTPSAP SAP, TIrQOS *ourQOS, TIrQOS *peerQOS, int MaxSduSize, TTPBuf *UserData) {
XTRACE(kLogConnectConfirm, 0, 0);
check(ourQOS);
check(peerQOS);
if (peerQOS) {
fMaxPacketSize = peerQOS->GetDataSize() - 5;
}
else {
fMaxPacketSize = 2048; }
if (fIrDAComm) {
fConnected = true;
fIrDAComm->ConnectionStatus(true);
}
}
void
IrComm::TTPDisconnectIndication ( int reason,
TTPBuf *UserData)
{
XTRACE(kLogDisconnected, 0, reason);
fConnected = false;
if (fIrDAComm)
fIrDAComm->ConnectionStatus(false); }
void
IrComm::TTPDataIndication(TTPBuf *userdata, TTP_Read_Status status)
{
UInt32 ctlLen, dataLen, count;
UInt8 *ctlBuffer, *dataBuffer, *buf;
require(userdata, Fail);
nrequire(status, Fail);
XTRACE(kLogTTPDataRead, status, BufSize(userdata));
count = BufSize(userdata);
buf = BufBase(userdata);
ctlLen = *buf; ctlBuffer = buf + 1;
dataLen = count - ctlLen - 1; dataBuffer = ctlBuffer + ctlLen;
XTRACE(kLogTTPDataRead2, ctlLen, dataLen);
if (dataLen) { AddPacketSize(dataLen); if (fIrDAComm)
fIrDAComm->IrCommDataRead(dataBuffer, dataLen); }
else TTPRxDone();
BufFree(userdata);
Fail:
return;
}
void
IrComm::TTPUDataIndication(TTPBuf *UserData)
{
}
void
IrComm::TTPAcceptDoneIndication(IrDAErr result) {
XTRACE(kLogAcceptDone, 0, result);
fConnected = (result == noErr);
if (fIrDAComm)
fIrDAComm->ConnectionStatus(result == noErr);
}
void
IrComm::TTPBackEnable(void) {
XTRACE(kLogBackEnable, 0, 0);
if (fIrDAComm)
fIrDAComm->BackEnable();
}
#pragma mark ==== Really silly packet size FIFO ====
#define kSizeQueueLength (kTinyTPCredit+2) // if more, then should never ever run out
QElem gSizeQueueArray[kSizeQueueLength]; QHdr gAvailSizeQueue; QHdr gSizeQueue;
void
InitSizeQueue(void)
{
int i;
gAvailSizeQueue.qFlags = gSizeQueue.qFlags = 0;
gAvailSizeQueue.qHead = gSizeQueue.qHead = nil;
gAvailSizeQueue.qTail = gSizeQueue.qTail = nil;
for (i = 0 ; i < kSizeQueueLength; i++) {
Enqueue(&gSizeQueueArray[i], &gAvailSizeQueue);
}
}
void
AddPacketSize(short length)
{
QElemPtr q;
IrDAErr err;
q = gAvailSizeQueue.qHead;
require(q, Fail);
err = Dequeue(q, &gAvailSizeQueue);
nrequire(err, Fail);
q->qLink = nil;
q->qType = 123;
q->qData[0] = length;
Enqueue(q, &gSizeQueue);
Fail:
return;
}
short
FirstPacketSize(void)
{
QElemPtr q;
q = gSizeQueue.qHead;
if (q == nil) return 0;
return q->qData[0];
}
void
ShrinkFirstPacketSize(short length)
{
QElemPtr q;
q = gSizeQueue.qHead;
require(q, Fail);
q->qData[0] -= length;
Fail:
return;
}
void
NukeFirstPacketSize(void)
{
QElemPtr q;
IrDAErr err;
q = gSizeQueue.qHead;
require(q, Fail);
err = Dequeue(q, &gSizeQueue);
nrequire(err, Fail);
Enqueue(q, &gAvailSizeQueue);
Fail:
return;
}
#if (hasTracing > 0 && hasIrCommTracing > 1)
void IrDALogData(int msg, UInt8 *buf, int count) {
UInt32 x = 0;
int i = 0;
while (count-- > 0) {
x = x << 8;
x |= *buf++;
if (++i == 4) {
XTRACE(msg, x >> 16, x);
i = 0;
x = 0;
}
}
if (i) XTRACE(msg, x >> 16, x);
}
#endif