December 22, 2014
Hot Topics:

Palm OS Communications Primer: IR Library

  • August 31, 2004
  • By Alex Gusev
  • Send Email »
  • More Articles »

Coming back to IR Library itself, let's first overview a typical scenario. Usually, you'll be required to do the following steps:

  • Search for IR Library with SysLibFind
  • Open IR Library with IrOpen
  • Obtain a local LSAP selector and bind the connection with the protocol stack with IrBind
  • Check that media is ready
  • Discover devices in range with IrDiscoverReq
  • Make IrLAP connection to desired device with IrConnectIrLap
  • Run IAS query to get remote LSAP
  • Make IrLmp or Tiny TP connection with IrConnectReq
  • Exchange data with e.g. printer or phone IrDataReq
  • Disconnect
  • Close IR Library with IrClose

Most of the IR Library functions return control immediately. Your application will be notified about events occurring in the system via a callback mechanism. You're passing a pointer to the callback function as the last parameter of IrBind API. The same model also works for IAS queries. As a result, your application must support some method of waiting for the result of the IR API called. Besides, it'd be nice not to hang up the UI while communications are in a waitable state, so you have to take care about event processing when it's needed. Below, we will consider all stages step by step.

Initialization

This part is relatively simple. Take a look at following code snippet:

Byte _deviceInfoXID[] = { IR_HINT_PDA, 0, 'P', 'a', 'l', 'm' };

static void MainFormInit(FormType *frmP)
{
   ...
   if(SysLibFind(irLibName, &_IrLibraryRefNum)!=0)
   {
      StrPrintF(_szInfo,"SysLibFind(%s) failed\n", irLibName);
      Log(_szInfo);
      _bIsIrLibAvailable = false;
   }
   StrPrintF(_szInfo,"IR library reference: %d\n", _IrLibraryRefNum);
   Log(_szInfo);

   if ( IrOpen(_IrLibraryRefNum, irOpenOptSpeed115200) != 0 )
   {
      Log("IrOpen() failed\n");
      return;
   }

   if( IrBind(_IrLibraryRefNum, &_IrConnection, IrCallback) !=
              IR_STATUS_SUCCESS )
   {
      Log("IrBind() failed\n");
      IrClose(_IrLibraryRefNum);
      return;
   }

   if( IrSetDeviceInfo(_IrLibraryRefNum, _deviceInfoXID,
                       sizeof(_deviceInfoXID)) != IR_STATUS_SUCCESS )
   {
      Log("IrSetDeviceInfo() failed\n");
      return;
   }

   if ( !waitUntilMediaReady() )
   {
      Log("IR media is busy!\n");
      return;
   }
   ...
}

It does exactly those calls we discussed above. The only thing that was not mentioned before is the IrSetDeviceInfo function. According its name, it sets the XID part of IrDeviceInfo struct. This information will be used during the discovery process; thus, other devices can know who are you. The XID struct contains the device hints (first two bytes) and nickname. By using the attached sample project, you can get some examples for different types of discovered IR devices, such as printers or mobile phones. Finally, after all initialization is completed, we wait for the media to be ready to carry out the next IR calls.

Callback Events

Throughout the rest of this article, we will refer to different events occuring at different stages of an IR session. The following table gives you short explanation of each of them:

Event Description
LEVENT_TEST_IND This event indicates that a TEST command frame has been received by the IR library. The received data is in rxBuff with size rxLen. The default response packet is set up with the received data, but it can be changed by modifying the packet. No explicit action is required for the TEST command to be responded to.
LEVENT_TEST_CNF This event indicates that a TEST command has completed. The status field indicates whether the test was successful. IR_STATUS_SUCCESS indicates success, and the response can be found in rxBuff with size rxLen. IR_STATUS_FAILED indicates that no TEST response was received. The packet passed to perform the test command is passed back in the packet field, and is now available. No separate packet handled event will occur.
LEVENT_DISCOVERY_CNF This event indicates that a discovery operation has completed. The field deviceList points to the discovery list. This list may be empty. Discovery can never fail, so this event always occurs after a discovery is initiated.
LEVENT_LAP_CON_IND This event occurs when the other side is trying to make a LAP connection. In practice, this event may be immediately followed by an LEVENT_LAP_DISCON_IND if the connection attempt fails.
LEVENT_LAP_CON_CNF This event occurs when a requested IrLAP connection has been successfully made.
LEVENT_LAP_DISCON_IND This event occurs when a request to initiate an IrLAP connection fails. It also occurs when the IrLAP connection has gone down. The event occurs on both sides. In practice, this event may immediately follow an LEVENT_LAP_CON_IND if the connection attempt fails. This event implies that the IrLMP connection has also gone down, if it was up. No separate event occurs for the IrLMP connection, except on Palm OS 4.0.
LEVENT_LM_CON_IND This event occurs when the other side has initiated an IrLMP connection. If we want to accept this connection, we must respond by calling IrConnectRsp(). The connection request includes arbitrary data that can be found at rxBuff with size rxLen. This data can be used to decide whether to accept the connection. The response also includes data to be sent back.
LEVENT_LM_CON_CNF This event indicates that the requested IrLMP connection has been made successfully. The connection response includes arbitrary data that can be found at rxBuff with size rxLen.
LEVENT_LM_DISCON_IND This event indicates that the IrLMP connection has been disconnected. Any data associated with the disconnection indication can be found at rxBuff with size rxLen. In practice, this event does not occur when the connection is broken, but does occur when this side attempts to initiate an IrLMP connection and the attempt fails. On Palm OS 4.0, this event also occurs when this side disconnects at the LAP level. The documentation is vague on this issue. In particular, the documentation says that LEVENT_LAP_DISCON_IND implies that the IrLMP connection has gone down, and that no other event will occur for this.
LEVENT_PACKET_HANDLED This event occurs when a packet passed in earlier becomes free again. This event occurs after IrDataReq, IrConnectReq, and IrConnectRsp, but not after IrTestReq. The test packet is considered handled when LEVENT_TEST_IND occurs.
LEVENT_DATA_IND This event occurs when data has been received. It can be accessed via rxBuff and rxLen. This event only occurs when data is sent by the other side using IrDataReq. It doesn't occur when data is received as part of an IrLMP connection request or response.
LEVENT_STATUS_IND This event occurs when the status changes. In practice, it is possible to get consecutive status events with the same status. The status field contains the new status, which can be one of:
  • IR_STATUS_NO_PROGRESS
    Means that IrLAP has made no progress for three seconds (beam is blocked).
  • IR_STATUS_LINK_OK
    Means that a no progress condition has cleared.
  • IR_STATUS_MEDIA_NOT_BUSY
    Means IR media was busy and is no longer.

You'll be responsible for providing the required code in response to incoming events.

Discovering devices in range

To to make any connection, you should first know what your target is. This process is called 'discovering'. The following sample code gives a simple example of how to do it:

static void DoDiscover()
{
   IrStatus ret;

   if ( !_bIsIrLibAvailable )
      return;

   _pendingCommand =  DiscoveryCommand;

   if( (ret=IrDiscoverReq(_IrLibraryRefNum, &_IrConnection)) !=
                         IR_STATUS_PENDING )
   {
      StrPrintF(_szInfo,"IrDiscoverReq() failed: %s\n",
                StatusName(ret));
      Log(_szInfo);
      return;
   }

   if ( !waitForResult() )
   {
      Log("Discovery has failed due to timeout or error\n");
   }
}

void IrCallback(IrConnect *connect, IrCallBackParms *parms)
{
   int i;
   
   switch(parms->event)
   {
   ...
   case LEVENT_DISCOVERY_CNF:
      if(parms->deviceList->nItems > 0)
      {
         MemMove(&_deviceInfo,&parms->deviceList->dev[0],
                 sizeof(IrDeviceInfo));
         for(i=0;i<parms->deviceList->nItems;i++)
         {
            DeviceType(parms->deviceList->dev[i],szDevInfo);
            StrPrintF(_szInfo,"Discovered: %s\n%sAddress: 0x%lx\n",
               &parms->deviceList->dev[i].xid[2],
               szDevInfo,
               parms->deviceList->dev[i].hDevice.u32);
            Log(_szInfo);
         }

         _commandSucceed = true;
      }
      else
      {
         Log("no IrDA devices in range\n");
         _commandSucceed = false;
      }
      _pendingCommand = NoCommand;
      break;
   ...
    }
}

Actually, the main part is happening in callback. You just save the received info about discovered devices somewhere for possible future usage.





Page 2 of 3



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Sitemap | Contact Us

Rocket Fuel