home *** CD-ROM | disk | FTP | other *** search
- //
- // $Id: IrConnection.cc,v 1.3 2000/06/06 09:30:53 sergey Exp $
- //
-
- #include <Pilot.h>
- #include <irlib.h>
- #include "IrConnection.h"
- #include "IrCallback.h"
- #include "IrIAS.h"
- #include "IrError.h"
- #include "Util/Assert.h"
- #include "Util/System.h"
-
-
- namespace IrDA
- {
- //==============================================================================
- // Constants
- //==============================================================================
-
- const Word NULL_REF_NUM = 0xFFFF;
- const Byte DEFAULT_TTP_CREDIT = 126;
-
- const int OPERATION_TIME_OUT = 5; // sec
- const int OPERATION_POLLING_PERIOD = 10; // ticks (~0.1 sec?)
-
- const int MIN_CONTROL_CHANNEL_SIZE = 1; // min size in bytes of the control channel (for cooked protocols)
-
-
- //==============================================================================
- // Connection class
- //==============================================================================
-
- Connection* Connection::_this = NULL;
-
- Connection::Connection():
- _refNum(NULL_REF_NUM),
- _bound(false),
- _ready(false),
- _dataSendReady(false),
- _cookedProtocol(false),
- _pendingCommand(NoCommand),
- _commandSucceed(false),
- _callback(NULL)
- {
- assert(_this == NULL); // ensures only one instance
- _this = this;
- }
-
- Connection::~Connection()
- {
- shutdown();
- _this = NULL;
- }
-
- // operations
-
- bool Connection::init(Word refNum, Callback* callback)
- {
- _refNum = refNum;
- _callback = callback;
-
- if (bind())
- {
- if (setDeviceInfo())
- return true;
-
- unbind();
- }
-
- return false;
- }
-
- void Connection::shutdown()
- {
- disconnect();
- unbind();
-
- _packetBuffer.free();
- }
-
- bool Connection::connect()
- {
- assert(_bound);
- assert(!_ready);
-
- waitUntilMediaReady();
-
- if (discovery())
- {
- if (connectLap())
- {
- if (connectComm())
- {
- _dataSendReady = true;
- return true;
- }
-
- disconnectLap();
- }
- }
-
- return false;
- }
-
- void Connection::disconnect()
- {
- if (_bound)
- disconnectLap();
- }
-
- bool Connection::sendData(const Byte* data, int size)
- {
- assert(_ready);
-
- if (!_dataSendReady)
- return false;
-
- _pendingCommand = SendDataCommand;
- _dataSendReady = false;
-
- initDataPacket(data, size);
-
- if (IrDataReq(_refNum, &_connect, &_packet) != IR_STATUS_PENDING)
- {
- IrError::sendDataError(getMaxTxSize(), size);
-
- _dataSendReady = true; // give it another try
- return false;
- }
-
- return waitForResult();
- }
-
- bool Connection::blockingSendData(const Byte* data, int size)
- {
- // Watch the ready state too - it could be dropped during the wait.
- if (waitUntilDataSendReady() && ready())
- return sendData(data, size);
-
- return false;
- }
-
- // attributes
-
- int Connection::getMaxTxSize() const
- {
- assert(_ready);
-
- int size = IrMaxTxSize(_refNum, const_cast<IrConnect*>(&_connect));
- return _cookedProtocol? size-MIN_CONTROL_CHANNEL_SIZE : size;
- }
-
- int Connection::getMaxRxSize() const
- {
- assert(_ready);
- return IrMaxRxSize(_refNum, const_cast<IrConnect*>(&_connect));
- }
-
- // implementation
-
- bool Connection::bind()
- {
- if (IrBind(_refNum, &_connect, irCallback) != IR_STATUS_SUCCESS)
- {
- IrError::bindError();
- return false;
- }
-
- _bound = true;
- return true;
- }
-
- void Connection::unbind()
- {
- if (_bound)
- {
- if (IrUnbind(_refNum, &_connect) == IR_STATUS_SUCCESS)
- _bound = false;
- else
- IrError::unbindError();
- }
- }
-
- bool Connection::discovery()
- {
- _pendingCommand = DiscoveryCommand;
-
- if (IrDiscoverReq(_refNum, &_connect) != IR_STATUS_PENDING)
- {
- IrError::discoveryError();
- return false;
- }
-
- return waitForResult();
- }
-
- bool Connection::connectLap()
- {
- _pendingCommand = ConnectLapCommand;
-
- // _deviceInfo must be set by discovery command
- if (IrConnectIrLap(_refNum, _deviceInfo.hDevice) != IR_STATUS_PENDING)
- {
- IrError::lapConnectionError();
- return false;
- }
-
- return waitForResult();
- }
-
- bool Connection::disconnectLap()
- {
- if (IrIsIrLapConnected(_refNum))
- {
- _pendingCommand = DisconnectLapCommand;
-
- if (IrDisconnectIrLap(_refNum) != IR_STATUS_PENDING)
- {
- IrError::lapDisconnectionError();
- return false;
- }
-
- return waitForResult();
- }
-
- return false;
- }
-
- bool Connection::connectComm()
- {
- Byte remoteLsap;
- IasQuery iasQuery(_refNum);
-
- // Try connect to printer. LPT port uses LMP protocol and has fixed IrLPT class
- if (iasQuery.getRemoteLsap(IrLptClass, IrLmpProtocol, remoteLsap))
- return connectLmp(remoteLsap);
-
- // Try to make LMP, IrCOMM connection (3-Wire raw)
- if (iasQuery.getRemoteLsap(IrCommClass, IrLmpProtocol, remoteLsap))
- return connectLmp(remoteLsap);
-
- // Try to make TinyTP IrCOMM connection (3-Wire, 9-Wire)
- if (iasQuery.getRemoteLsap(IrCommClass, IrTpProtocol, remoteLsap))
- return connectTinyTp(remoteLsap);
-
- IrError::getRemoteLsapError();
- return false;
- }
-
- bool Connection::connectLmp(Byte remoteLsap)
- {
- _pendingCommand = ConnectLmCommand;
-
- IrSetConTypeLMP(&_connect);
- _cookedProtocol = false; // LMP used only for non-cooked protcols (LPT, 3-Wire raw)
-
- _connect.rLsap = remoteLsap;
- _packet.buff = NULL;
- _packet.len = 0;
-
- if (IrConnectReq(_refNum, &_connect, &_packet, 0) != IR_STATUS_PENDING)
- {
- IrError::lmpConnectionError();
- return false;
- }
- return waitForResult();
- }
-
- bool Connection::connectTinyTp(Byte remoteLsap)
- {
- _pendingCommand = ConnectLmCommand;
-
- IrSetConTypeTTP(&_connect);
- _cookedProtocol = true; // TTP used only for cooked protcols (3-Wire, 9-Wire, Centronics)
-
- _connect.rLsap = remoteLsap;
- initServiceTypePacket();
-
- if (IrConnectReq(_refNum, &_connect, &_packet, DEFAULT_TTP_CREDIT) != IR_STATUS_PENDING)
- {
- IrError::tinyTpConnectionError();
- return false;
- }
-
- return waitForResult();
- }
-
- bool Connection::setDeviceInfo()
- {
- // PDA, supports IrCOMM extension
- static Byte deviceInfoXID[] = { IR_HINT_PDA, 0, 'P', 'a', 'l', 'm' };
-
- if(IrSetDeviceInfo(_refNum, deviceInfoXID, sizeof(deviceInfoXID)) != IR_STATUS_SUCCESS)
- {
- IrError::setDeviceInfoError();
- return false;
- }
-
- return true;
- }
-
- void Connection::initServiceTypePacket()
- {
- struct ServiceTypePacket
- {
- Byte PI;
- Byte PL;
- Byte PV;
- };
-
- static ServiceTypePacket controlPacket =
- {
- 0x00, // ServiceType packet
- 0x01, // length
- 0x02 // 3-Wire service type
- };
-
- _packet.buff = (Byte*)&controlPacket;
- _packet.len = sizeof(controlPacket);
- }
-
- void Connection::initDataPacket(const Byte* data, int size)
- {
- if (_packetBuffer.isLocked())
- _packetBuffer.unlock();
-
- if (_cookedProtocol)
- {
- _packet.buff = (Byte*)_packetBuffer.lock(size+MIN_CONTROL_CHANNEL_SIZE);
- _packet.len = size+MIN_CONTROL_CHANNEL_SIZE;
-
- _packet.buff[0] = 0; // control channel size is 0
- MemMove(_packet.buff+MIN_CONTROL_CHANNEL_SIZE, data, size);
- }
- else
- {
- _packet.buff = (Byte*)data;
- _packet.len = size;
- }
- }
-
- // utilities
-
- bool Connection::waitUntilMediaReady() const
- {
- int count = OPERATION_TIME_OUT*SysTicksPerSecond()/OPERATION_POLLING_PERIOD;
-
- for (int i = 0; i < count && IrIsMediaBusy(_refNum); ++i)
- Util::YieldControlToSystem(OPERATION_POLLING_PERIOD, false);
-
- return !IrIsMediaBusy(_refNum);
- }
-
- bool Connection::waitUntilDataSendReady() const
- {
- int count = OPERATION_TIME_OUT*SysTicksPerSecond()/OPERATION_POLLING_PERIOD;
-
- for (int i = 0; i < count && !dataSendReady(); ++i)
- Util::YieldControlToSystem(OPERATION_POLLING_PERIOD, false);
-
- return dataSendReady();
- }
-
- bool Connection::waitForResult() const
- {
- // wait until the pending command will be executed
-
- int count = OPERATION_TIME_OUT*SysTicksPerSecond()/OPERATION_POLLING_PERIOD;
-
- for (int i = 0; i < count && _pendingCommand != NoCommand; ++i)
- Util::YieldControlToSystem(OPERATION_POLLING_PERIOD, false);
-
- return _pendingCommand == NoCommand && _commandSucceed;
- }
-
- // callback handling
-
- void Connection::irCallback(IrConnect* conn, IrCallBackParms* params)
- {
- #ifdef IR_DEBUG
- _this->debugPrintEvent(params->event);
- #endif
-
- switch (params->event)
- {
- case LEVENT_DISCOVERY_CNF:
- _this->discovered(params->deviceList);
- break;
-
- case LEVENT_LAP_CON_CNF:
- _this->connectedLap();
- break;
-
- case LEVENT_LAP_CON_IND:
- _this->requestedLapConnection();
- break;
-
- case LEVENT_LAP_DISCON_IND:
- _this->disconnectedLap();
- break;
-
- case LEVENT_LM_CON_CNF:
- _this->connectedLm();
- break;
-
- case LEVENT_LM_CON_IND:
- _this->requestedLmConnection();
- break;
-
- case LEVENT_LM_DISCON_IND:
- _this->disconnectedLm();
- break;
-
- case LEVENT_PACKET_HANDLED:
- _this->packetHandled();
- break;
-
- case LEVENT_DATA_IND:
- _this->dataReceived(params->rxBuff, params->rxLen);
- break;
-
- case LEVENT_STATUS_IND:
- _this->statusChanged(params->status);
- break;
- }
- }
-
- void Connection::discovered(IrDeviceList* devices)
- {
- if (_pendingCommand == DiscoveryCommand)
- {
- if (devices->nItems > 0)
- {
- _deviceInfo = devices->dev[0];
- _commandSucceed = true;
-
- #ifdef IR_DEBUG
- debugPrintDeviceInfo(_deviceInfo);
- #endif
- }
- else
- {
- _commandSucceed = false;
- }
-
- _pendingCommand = NoCommand;
- }
- }
-
- void Connection::connectedLap()
- {
- if (_pendingCommand == ConnectLapCommand)
- {
- _pendingCommand = NoCommand;
- _commandSucceed = true;
- }
-
- if(_callback != NULL)
- _callback->connected();
- }
-
- void Connection::requestedLapConnection()
- {
- if(_callback != NULL)
- _callback->connected();
- }
-
- void Connection::disconnectedLap()
- {
- if (_pendingCommand == ConnectLapCommand || _pendingCommand == DisconnectLapCommand)
- {
- _pendingCommand = NoCommand;
- _commandSucceed = _pendingCommand == DisconnectLapCommand;
- }
-
- _ready = false;
-
- if (_callback != NULL)
- _callback->disconnected();
- }
-
- void Connection::connectedLm()
- {
- if (_pendingCommand == ConnectLmCommand)
- {
- _pendingCommand = NoCommand;
- _commandSucceed = true;
- }
-
- _ready = true;
- }
-
- void Connection::requestedLmConnection()
- {
- }
-
- void Connection::disconnectedLm()
- {
- _ready = false;
-
- if (_callback != NULL)
- _callback->disconnected();
- }
-
- void Connection::packetHandled()
- {
- if (_pendingCommand == SendDataCommand)
- {
- _pendingCommand = NoCommand;
- _commandSucceed = true;
-
- _dataSendReady = true;
- if (_callback != NULL)
- _callback->dataSendReady();
- }
- }
-
- void Connection::dataReceived(const Byte* data, int size)
- {
- if (_callback != NULL)
- {
- // In case of cooked protocol first byte is the size of the control packet. Simply ignore it.
- int offset = _cookedProtocol? data[0]+1 : 0;
-
- _callback->dataReceived(data+offset, size-offset);
- }
- }
-
- void Connection::statusChanged(IrStatus irStatus)
- {
- #ifdef IR_DEBUG
- debugPrintStatus(irStatus);
- #endif
-
- if (_callback != NULL)
- {
- Callback::Status status;
-
- switch(irStatus)
- {
- case IR_STATUS_MEDIA_NOT_BUSY:
- status = Callback::MediaNotBusyStatus;
- break;
- case IR_STATUS_NO_PROGRESS:
- status = Callback::NoProgressStatus;
- break;
- case IR_STATUS_LINK_OK:
- status = Callback::LineOkStatus;
- break;
- default:
- return;
- }
-
- _callback->statusChanged(status);
- }
- }
-
- // debug
-
- #ifdef IR_DEBUG
-
- void Connection::debugPrintStatus(IrStatus status)
- {
- static const char* statusText[] =
- {
- "IR_STATUS_SUCCESS",
- "IR_STATUS_FAILED",
- "IR_STATUS_PENDING",
- "IR_STATUS_DISCONNECT",
- "IR_STATUS_NO_IRLAP",
- "IR_STATUS_MEDIA_BUSY",
- "IR_STATUS_MEDIA_NOT_BUSY",
- "IR_STATUS_NO_PROGRESS",
- "IR_STATUS_LINK_OK"
- };
-
- Util::DebugPrintf("Status #%d: %s\n", (int)status, statusText[status]);
- }
-
- void Connection::debugPrintEvent(IrEvent event)
- {
- static const char* eventText[] =
- {
- "LEVENT_LM_CON_IND",
- "LEVENT_LM_DISCON_IND",
- "LEVENT_DATA_IND",
- "LEVENT_PACKET_HANDLED",
- "LEVENT_LAP_CON_IND",
- "LEVENT_LAP_DISCON_IND",
- "LEVENT_DISCOVERY_CNF",
- "LEVENT_LAP_CON_CNF",
- "LEVENT_LM_CON_CNF",
- "LEVENT_STATUS_IND",
- "LEVENT_TEST_IND",
- "LEVENT_TEST_CNF"
- };
-
- Util::DebugPrintf("Event #%d: %s\n", (int)event, eventText[event]);
- }
-
- void Connection::debugPrintDeviceInfo(IrDeviceInfo& deviceInfo)
- {
- Util::DebugPrintf("DeviceInfo: 0x%x, 0x%x, '%s'\n",
- _deviceInfo.xid[0],
- _deviceInfo.xid[1],
- (char*)_deviceInfo.xid+2);
- }
-
- #endif // IR_DEBUG
- }
- // namespace IrDA
-