DesktopSDK 0.7 - PenComm Library (C#) Documentation
ContentsIndexHome
Register Application Example
Examples

To register the desktop application with the PenComm Service, do the following:

  1. Provide register information in a RegAppInfo struct that has the members: Auto Start, Description, Version and Application Path.
  2. Call Smartpens.DesktopApplications.RegisterApp(). The call will return the application handle. You must provide the application handle when calling Smartpens.DesktopApplications.RegisterPackage() and Smartpens.DesktopApplications.RegisterDataCallback().
 

To receive data from a particular package, do the following:

  1. Register a package as a 'package of interest' for your desktop application by calling Smartpens.DesktopApplications.RegisterPackage(). For the regPackageInfo parameter, create a RegPackageInfo structure and store:
The Smartpens.DesktopApplications.RegisterPackage() function will return the package handle. 

  1. Register a PenAPI.DataCallback using Smartpens.DesktopApplications.RegisterDataCallback(). Whenever a registered package of interest has new data, the desktop application will receive the data via the registered data callback.
 

 

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");
        }
    }
}
Created with a commercial version of Doc-O-Matic. In order to make this message disappear you need to register this software. If you have problems registering this software please contact us at support@toolsfactory.com.
Copyright © 2010 Livescribe, Inc. All rights reserved.