To register the desktop application with the PenComm Service, do the following:
To receive data from a particular package, do the following:
using System; using System.Collections.Generic; using System.Threading; using System.IO; using System.Runtime.InteropServices; using System.Reflection; using Livescribe.DesktopSDK.PenComm; using Livescribe.DesktopSDK.PenComm.Interop; using Livescribe.DesktopSDK.PenData; using Livescribe.DesktopSDK.AFP; using PenComm = Livescribe.DesktopSDK.PenComm; namespace DataCapture { class DataCapture { private static Smartpens smartpens; private const string APP_NAME = "DataCapture"; private const string PENCOMM_LOG = "DataCapture.log"; private const string PENLET_DATA_FILE = "penletData.zip"; private const string PENLET_NAME = "GetBoundingBoxes"; private const string DATA_FILE = "data.txt"; private static bool foundPen = false; private static bool handlerRegistered = false; // This sample gets data from the GetBoundingBoxes penlet and displays it on the console. After displaying // the the data last captured using the penlet we establish a data handler and wait for new data to show up. static void Main(string[] args) { System.Console.WriteLine("===================================================="); System.Console.WriteLine("Read data written by the " + PENLET_NAME + " penlet."); System.Console.WriteLine("===================================================="); InitializePenCommLib(); // Waiting just a bit to give the pen attach event time to run if the pen is already there. Thread.Sleep(1000); if (!DataCapture.foundPen) { // But if it isn't let the user know we're waiting for it. System.Console.Write("Waiting for pen."); } // Keep processing until user presses a key to terminate while (!Console.KeyAvailable) { if (!DataCapture.foundPen) { // If we've never found a pen remind the user that we're waiting for one. Console.Write("."); } Thread.Sleep(2000); } } // Initialize PenComm library private static void InitializePenCommLib() { smartpens = new Smartpens(true, PENCOMM_LOG); // The PulsePens object keeps track of attach event handlers in "PulsePenAttachNormalEvent" // Create a new callback object for our PenAttachEvent method and register it by adding it // to the list of attach event handlers. smartpens.SmartpenAttachNormalEvent += new Smartpens.SmartpenChangeCallback(PenAttachEvent); // Do the same for our detach event handler. smartpens.SmartpenDetachNormalEvent += new Smartpens.SmartpenChangeCallback(PenDetachEvent); // Search for any already docked pens smartpens.Find(); } // Register our data handler (NewData). It will be invoked whenever new data appears for our penlet of // interest (PENLET_NAME). private static void RegisterForNewApplicationData() { if (!handlerRegistered) { try { // Application registration information. RegAppInfo appInfo = new RegAppInfo(); appInfo.autoStart = PenAPI.AutoStartTypes.Disabled; appInfo.path = Assembly.GetExecutingAssembly().Location; appInfo.description = APP_NAME; appInfo.version = "1.0"; // Register Application (that's us) AppHandle appHandle = smartpens.DesktopApplications.RegisterApp(appInfo); // Register for a data callback so that every time the penlet PENLET_NAME has new data, it will // be passed to our callback (NewData). PenAPI.DataCallback dataCallback = new PenAPI.DataCallback(NewData); smartpens.DesktopApplications.RegisterDataCallback(appHandle, dataCallback, null); // Register Penlet Information of the GetBoundingBoxes penlet RegPackageInfo regPackageInfo = new RegPackageInfo(); regPackageInfo.appHandle = appHandle; regPackageInfo.penId = PenComm.PenId.Zero(); regPackageInfo.uniqueName = PENLET_NAME; // Register the GetBoundingBoxes penlet PackageHandle packageHandle = smartpens.DesktopApplications.RegisterPackage(regPackageInfo); handlerRegistered = true; } catch (Exception e) { HandleError(e); } } } private static PenAPI.DataOpTypes NewData(PenDataCallbackInfo dataInfo, IntPtr userParam) { try { // Construct a file name that will be unique to a single stroke in which to save our data. // Note: we need to save the data in a file in the event that the stroke is transferred to // us in multiple invocations of the the callback. This may happen as a stroke can be // comprised of many co-ordinates. String filePath = Path.GetTempPath() + "Pen" + dataInfo.penId + "_Penlet" + dataInfo.penletHandle + "_Time" + dataInfo.startRtc + ".zip"; // Create or append to the file depending on whether we're starting with the first co-ordinate BinaryWriter bw = null; if (dataInfo.pos == 0) { bw = new BinaryWriter(new FileStream(filePath, FileMode.Create)); } else { bw = new BinaryWriter(new FileStream(filePath, FileMode.Append)); } byte[] buf = new byte[dataInfo.bufSize]; Marshal.Copy(dataInfo.buffer, buf, 0, dataInfo.bufSize); bw.Write(buf); bw.Close(); if (dataInfo.packetStatus != PenAPI.DataPacketStatus.MorePackets) { PenletData penletData = new Container(filePath).PenletData; DisplayData(penletData); } } catch (Exception e) { HandleError(e); } return PenAPI.DataOpTypes.Continue; } // Read and display penlet data. private static void DisplayData(PenletData penletData) { try { // The penlet data file is a zip file which is structured like this: // userdata/[Pen Serial]/[Penlet Name]/[InstanceId]... // // PenItem corresponds to [Pen Serial] // AppItem corresponds to [Penlet Name] // InstanceItem corresponds to [InstanceId] // // The PENLET_NAME penlet data file is named: // userdata/[Pen Serial]/[Penlet Name]/[InstanceId]/data.txt foreach (PenItem penItem in penletData.PenItems) { foreach (AppItem appItem in penItem) { foreach (InstanceItem instanceItem in appItem.InstanceItems) { AFDStream afdStream = instanceItem.OpenStream(DATA_FILE); BinaryReader reader = new BinaryReader(afdStream); byte[] data = reader.ReadBytes(1024); String value = System.Text.Encoding.ASCII.GetString(data); System.Console.WriteLine(String.Format("Data: {0}", value)); reader.Close(); afdStream.Close(); } } } penletData.FileContext.CloseContext(); } catch (Exception e) { HandleError(e); } } // This is called when a pen is attached. The first time a pen is attached or if the PENLET_NAME penlet was // never installed and run we want to check for the penlet and process the data. After that we register for // new data and only respond to new data events. If we only wanted to respond to new data we could register // our application during initialization and not even have a pen attach handler. private static void PenAttachEvent(Smartpen pen) { DataCapture.foundPen = true; Console.WriteLine("\n\n--> Pen " + pen.PenSerial + " connected"); if (!handlerRegistered) { PenletData penletData = null; try { // Retrieve the data for the GetBoundingBox penlet and store it in a temporary file. The data is // in zip format and can be processed with any zip reader. pen.DataGet(PENLET_NAME, 0, PENLET_DATA_FILE); // From the data file we create a container and extract a PenletData object from it for easy processing penletData = new Container(PENLET_DATA_FILE).PenletData; } catch (Exception e) { System.Console.WriteLine("\nThe " + PENLET_NAME + " penlet is not installed on your pen or has not been run"); System.Console.WriteLine("successfully. Please install it using the PlatformSDK. Once installed you"); System.Console.WriteLine("will need to run it and draw a shape on Livescribe Paper.\n"); return; } DisplayData(penletData); RegisterForNewApplicationData(); } } private static void PenDetachEvent(Smartpen pen) { Console.WriteLine("<-- Pen " + pen.PenSerial + " disconnected"); } private static void HandleError(Exception ex) { System.Console.WriteLine("Exception: " + ex.Message, "Error"); } } }