Thursday, July 30, 2009

WebOS Development - First Steps

So, what is WebOS development about? First thing is to learn some 'Web OS speak'. The application begins with creating a 'stage' which is more or less like a main page for a website. The webpages, or what we call 'Forms' in Windows Forms, are called 'scenes'. These are html files. There is also code-behing for the scenes, it is javascript and called 'assistants' in Web OS speak. The command to generate the application template is

palm-generate -p "{title:'My Application Title', id:com.mystuff.myapp, version:'1.0.0'}" MyAppVersionOne

More on application structure here

Application Structure

So, my first app has two pages scenes. On the first one I can press a button and this will insert a record in a database table. Another button will take me to the second scene. On the second scene the database table records are displayed and the button that takes me back to the first scene. Pretty basic stuff. The scene markup is as simple as that

The add_button adds the record, the display_button takes me to the next scene. Other divs I use for debugging - they just display text. Now to the code-behind assistant.

function FirstAssistant() {
/* this is the creator function for your scene assistant object. It will be passed all the
additional parameters (after the scene name) that were passed to pushScene. The reference
to the scene controller (this.controller) has not be established yet, so any initialization
that needs the scene controller hould be done in the setup function below. */
this.db = null;
}

FirstAssistant.prototype.setup = function() {
this.CreateDB();
Mojo.Event.listen($('add_button'), Mojo.Event.tap, this.AddEntry.bind(this));
Mojo.Event.listen($('display_button'), Mojo.Event.tap, this.DisplayEntries.bind(this));
$('result2').update('debug comment');
}

Okay, you can read the comments. Define variables, subscribe to events, open or create the database - set to go! This is the CreateDB function by the way

FirstAssistant.prototype.CreateDB = function(){
try
{
this.db = openDatabase('SampleDB', '', 'Sample Data Store', 65536);
if(!this.db)
{
$(result).update('error opening db');
}
else
{
$(result).update('opened db');

var string = 'CREATE TABLE IF NOT EXISTS table1 (col1 TEXT NOT NULL DEFAULT "nothing", col2 TEXT NOT NULL DEFAULT "nothing"); GO;';

this.db.transaction(
(function (transaction) {
transaction.executeSql(string, [], this.createTableDataHandler.bind(this), this.errorHandler.bind(this));
}).bind(this) );
}
}
catch (e)
{
$(result).update(e);
}
}

WebOS uses Sqlite as a database engine. This is how a record is inserted:

FirstAssistant.prototype.AddEntry = function() {
var string = 'INSERT INTO table1 (col1, col2) VALUES ("test","test"); GO;';

this.db.transaction(
(function (transaction) {
transaction.executeSql(string, [], this.createRecordDataHandler.bind(this), this.errorHandler.bind(this));
}).bind(this)
);
}

This is how I move to the next scene:

FirstAssistant.prototype.DisplayEntries = function() {
this.controller.stageController.pushScene('second', this.db);
}

I pass the name of the scene I want to 'push' and then the parameters. On the second scene I will grab these parameters and use them. Almost as the first scene, but now I have the database open already so I pass it to the second scene.

function SecondAssistant(origdb) {
this.db = origdb;
}

Okay, displaying the results and formatting them are outside of the scope of this brief post. Also, I copied the code from one of the samples on developer.palm.com, the application is called Data and the code can be found under Data\app\assistants\storage\sqlite and Data\app\views\storage\sqlite. Here is how the scenes look on the emulator

by . Also posted on my website

Wednesday, July 29, 2009

WebOS Development

Quite a while ago (around 8 years) I was doing some development for PalmOS devices. With the new Palm Pre soon to be released in Australia and the Mojo SDK now freely available to everyone I decided to have a look at WebOS development. There is no need to have a Palm Pre device to begin development, I only had to download and install the SDK, Java and the VirtualBox to run the emulator. There is also a possibility of using Eclipse with the WebOS plugin but since I'm just starting and not doing anything complex, I'm happy to use Notepad++ as the IDE.

Installing the Palm® Mojo™ SDK on Windows

The Hello World page gives an understanding of the steps required to create, compile and install a WebOS application. The "SDLC" is simple and takes a few seconds - generate the application, add some functionality, package, install on the emulator, have a look, improve/fix functionality, package, install on the emulator, have a look ...

Hello, World!

There are also sample applications available and in the first few hours that I spent I learned a few things about how the applications function - scenes, assistants etc. - and also a few basic things about how the databases are used.

Samples

by . Also posted on my website

Wednesday, July 22, 2009

Mifare 1K Memory Structure

To complete the task I'm working on and read/write to smart cards, I had to understand the memory structure of the Mifare Standard 1K card. This was no easy task for a weak and small brain of mine! I figured it out finally and here is a very short summary of my understanding:

The total memory of 1024 bytes is divided into 16 sectors of 64 bytes, each of the sectors is divided into 4 blocks of 16 bytes. Blocks 0, 1 and 2 of each sector can store data and block 3 is used to store keys and access bits (the exception is the ‘Manufacturer Block’ which can not store data).

The data in any sector can be protected by either Key A or both Key A and Key B security keys. I do not need to use Key B, and in this case the bytes in the trailer can be used for data. If the sector is protected by the security key, this key has to be loaded before data can be accessed by using a special command.

Access bits define the way the data in the sector trailer and the data blocks can be accessed. Access bits are stored twice – inverted and non-inverted in the sector trailer as shown in the images.

Some examples:

Data stored in the sector trailer:
01 02 03 04 05 06 FF 07 80 69 11 12 13 14 15 16
01 02 03 04 05 06 – Key A
FF 07 80 69 – Access bits
11 12 13 14 15 16 – Key B (or data if Key B is not used)

Bytes 6, 7, 8 are access data
FF 07 80

Binary representation:
11111111 = FF
00000111 = 07
10000000 = 80

The bits that are bolded and underscored are the ones that define access to keys (C13, C23, C33 in the image above) and they form the 001 sequence. The bits that are bolded and not underscored are the same bits inverted. They form, as expected, the sequence 110.

From the table above I can see that 001 means that Key A can not be read, but can be written and Key B may be read. This is the "transport configuration" and was read from the card that was never used.

A bit more on Mifare 1K commands next time.

by . Also posted on my website

Sunday, July 19, 2009

Smart Cards Do Not Hurt Anymore

Ah, the great mystery of talking to the smart card is solved. The tool that helped me to do it is called CHIPDRIVE Smartcard Commander. It is a free tool and can easily be found, downloaded and installed.

When I positioned the card in the reader and started the Smartcard Commander, I could immediately see that it knows a lot of stuff about the card.

But what's more important, it has some sample scripts that can be loaded when I select "CPU Card" from the System tree and use the Load Script button. The sample script shows me how to construct commands that can be send to the card, I can also run them immediately and see the results.

I only need to send the proper commands now...

by . Also posted on my website

Friday, July 17, 2009

Smart Cards Hurt - 3

Resolved the problem with the Smart Card reader. After everything else failed, I tried installing the pritner and reader on the clean PC. Surprisingly, it worked. Then I tried uninstalling all drivers from my PC, restarting and reinstalling again. Unsurprisingly, it did not work (I tried doing this before).

Next thing, I decided to compare the driver versions between my PC and clean PC. And here it was - my driver said "SCM Microsystems 4.35.00.01" and the one on the clean PC said "SCM Microsystems 5.15". And, of course, the S331DICL.sys files had different dates. So, I copied the S331DICL.sys and installed the drivers again. That did not quite help though, the driver version was now the proper one, but the device version itself was not.

Why are the versions different? Only when I searched for S331DICL.sys on the whole computer I could figure out what was the most likely reason for my problem - looks like the old the driver version was installed by the 3M scanner installer. I found the old S331DICL.sys in one of the subfolders under its Program Files folder. Now, when I was installing the driver, it remembered the location and used the old file that came with the 3M scanner. So I uninstalled the 3M application, made sure that the S331DICL.sys file is deleted completely from my computer, copied over the new version and pointed to the new version of S331DICL.sys file when installing the smart card drivers. Now it finally worked.

Next thing is to actually implement communication to the smart card ...

by . Also posted on my website

Wednesday, July 15, 2009

Unit Testing - First Attempts

I had some time to use while I was investigating the smart card issues, so I decided to do the right thing. Something I have never done before. To learn how to write and use unit tests. Since I had a very small application that was testing the capabilities of the printer, it looked like a perfect guinea pig for my experiment. It turned out that writing tests is not so hard as I expected it to be. Well, I can not promise that I did it right, of course, because no one writes them here anyway and there is no one to mentor me or point to my mistakes.

So first of all I downloaded and installed NUnit framework

NUnit framework

Then I added a project of type class library to my solution and a single class called UnitTest to this solution. Here is the full code of the UnitTest class:

using System;
using NUnit.Framework;
using SmartCardTest;
using DataCardCP40;

[TestFixture]
public class UnitTest
{
public DataCardPrinter printer;
ICE_API.DOCINFO di;

[Test]
public void CreateObjects()
{
printer = new DataCardPrinter();
di = DataCardPrinter.InitializeDI();
printer.CreateHDC();
Assert.AreNotEqual(printer.Hdc, 0);
Assert.Greater(di.cbSize, 0);
}

[Test]
public void SetInteractiveMode()
{
int res = ICE_API.SetInteractiveMode(printer.Hdc, true);
Assert.Greater(res, 0);
}

[Test]
public void StartDoc()
{
int res = ICE_API.StartDoc(printer.Hdc, ref di);
Assert.Greater(res, 0);
}

[Test]
public void StartPage()
{
int res = ICE_API.StartPage(printer.Hdc);
Assert.Greater(res, 0);
}

[Test]
public void RotateCardSide()
{
int res = ICE_API.RotateCardSide(printer.Hdc, 1);
Assert.Greater(res, 0);
}

[Test]
public void FeedCard()
{
int res = ICE_API.FeedCard(printer.Hdc, ICE_API.ICE_SMARTCARD_FRONT + ICE_API.ICE_GRAPHICS_FRONT);
Assert.Greater(res, 0);
}

[Test]
public void SmartCardContinue()
{
int res = ICE_API.SmartCardContinue(printer.Hdc, ICE_API.ICE_SMART_CARD_GOOD);
Assert.Greater(res, 0);
}

[Test]
public void EndPage()
{
int res = ICE_API.EndPage(printer.Hdc);
Assert.Greater(res, 0);
}

[Test]
public void EndDoc()
{
int res = ICE_API.EndDoc(printer.Hdc);
Assert.Greater(res, 0);
}
}

There's not much to explain. First I create the objects required and verify that the device context was created and the DOCINFO struct was initialized. All the other tests just check the return codes of the printer functions. The error code is 0, so the check is for return value being greater than zero.

After compiling and fixing errors I realized that I have no way to set the sequence of the execution. Supposedly, as the theory teaches us, each test should be able to run alone and independent of whether the rest were passed, failed or run at all. Well, does not work so well in my case - if I want to test that the card can be ejected from the printer, I need to somehow insert it first! I found out, however, that the tests are executed in the alphabetic order of their names. Okay, that'll do for now. So I just renamed my tests like this A_CreateObjects(), B_SetInteractiveMode() etc. Then I compiled the solution, creating the "DataCardTest.dll". Next step is to run NUnit and open the dll. Wow! The smart thing can see all my tests now. When ready, just select Test->Run all from the menu and enjoy ...

It does not alway end that well, however - it might be like this (see how it tells what was the line where the error happened and how the expected test result was different from the actual).

What happened here? Took me some time to figure out ... the default printer was not set to my card printer.

by . Also posted on my website

Friday, July 10, 2009

Smart Cards Hurt - 2

Now, the slightly harder part is communicating with the Smart Card reader. Most, if not all, of the functionality resides within the winscard.dll. For functions reference, this MSDN page could be a start.

Smart Card Functions

I also found a nice example using google code search which resides here

ACR120Driver.cs

and using this code as a template, I used the following code to test the functionality of my SCM reader.

long retCode;
int hContext = 0;
int ReaderCount = 0;
int Protocol = 0;
int hCard = 0;
string defaultReader = null;
int SendLen, RecvLen;

byte[] SendBuff = new byte[262];
byte[] RecvBuff = new byte[262];

ModWinsCard.SCARD_IO_REQUEST ioRequest;

retCode = ModWinsCard.SCardEstablishContext(ModWinsCard.SCARD_SCOPE_USER, 0, 0, ref hContext);
if (retCode != ModWinsCard.SCARD_S_SUCCESS)
{
System.Diagnostics.Debug.WriteLine(ModWinsCard.GetScardErrMsg(retCode));
}

retCode = ModWinsCard.SCardListReaders(hContext, null, null, ref ReaderCount);

if (retCode != ModWinsCard.SCARD_S_SUCCESS)
{
System.Diagnostics.Debug.WriteLine(ModWinsCard.GetScardErrMsg(retCode));
}

byte[] retData = new byte[ReaderCount];
byte[] sReaderGroup = new byte[0];

//Get the list of reader present again but this time add sReaderGroup, retData as 2rd & 3rd parameter respectively.
retCode = ModWinsCard.SCardListReaders(hContext, sReaderGroup, retData, ref ReaderCount);

if (retCode != ModWinsCard.SCARD_S_SUCCESS)
{
System.Diagnostics.Debug.WriteLine(ModWinsCard.GetScardErrMsg(retCode));
}

//Convert retData(Hexadecimal) value to String
string readerStr = System.Text.ASCIIEncoding.ASCII.GetString(retData);
string[] rList = readerStr.Split('\0');

foreach (string readerName in rList)
{
if (readerName != null && readerName.Length > 1)
{
defaultReader = readerName;
break;
}
}

if (defaultReader != null)
{
retCode = ModWinsCard.SCardConnect(hContext, defaultReader, ModWinsCard.SCARD_SHARE_DIRECT,
ModWinsCard.SCARD_PROTOCOL_UNDEFINED, ref hCard, ref Protocol);
//Check if it connects successfully
if (retCode != ModWinsCard.SCARD_S_SUCCESS)
{
string error = ModWinsCard.GetScardErrMsg(retCode);
}
else
{
int pcchReaderLen = 256;
int state = 0;
byte atr = 0;
int atrLen = 255;

//get card status
retCode = ModWinsCard.SCardStatus(hCard, defaultReader, ref pcchReaderLen, ref state, ref Protocol, ref atr, ref atrLen);

if (retCode != ModWinsCard.SCARD_S_SUCCESS)
{
return;
}

//read/write data etc.

.....
}
}

ModWinsCard.cs is, again, a wrapper for the winscard.dll functions, data structures, and declares all required constants.

Anyway, this code actually worked fine, except one little detail - the state variable that gets returned by the SCardStatus returned the value of 2. And the possible values are explained here:

SCardStatus

"2" is SCARD_PRESENT, which means "A card is present in the card reader, but it is not in position for use". A better result would be something like SCARD_NEGOTIABLE which is "The card has been reset and is waiting for protocol negotiation".

Also, using SCardConnect with preferred protocol set to T0 or T1 returned SCARD_W_UNRESPONSIVE_CARD error.

Now this is the point where I had to consult with the printer manufacturer because there's a number of possible reasons for the errors - hardware, firmware, drivers or incompatible card. Work still in progress.

by . Also posted on my website

Tuesday, July 7, 2009

Smart Cards Hurt - 1

So here's the new toy I've got to play with - the DataCard CP40 Plus card printer with the SCM SCR331-DI Smart Card reader.

Datacard CP40 Plus

Developing the application for the printer consists mostly of two parts - communicating with the printer and communicating with the smart card reader. You tell the printer to pick up the card, you tell the printer to position the card for smart card processing, you tell the smart card reader to write data to the smart card, you tell the printer to encode the magstripe and print something on the card, you tell the printer to finish with the print job.

It does not look so easy when you read the manual. This is how the programming flow looks like:

In reality, though, the whole printer communication is mostly done by the following code:

printer.Hdc = PrintDoc.PrinterSettings.CreateMeasurementGraphics().GetHdc().ToInt32();

/* Set Interactive mode */
if (ICE_API.SetInteractiveMode(printer.Hdc, true) > 0)
{
ICE_API.DOCINFO di = new ICE_API.DOCINFO();
/* Initialize DOCINFO */
di.cbSize = 16;
di.lpszDocName = "Card Printer SDK Test";
di.lpszDataType = string.Empty;
di.lpszOutput = string.Empty;

/* Start document and page */
if (ICE_API.StartDoc(printer.Hdc, ref di) > 0)
{
if (ICE_API.StartPage(printer.Hdc) > 0)
{
/* Set card rotation on */
ICE_API.RotateCardSide(printer.Hdc, 1);
/* Feed the card into the smart card reader */
if (ICE_API.FeedCard(printer.Hdc, ICE_API.ICE_SMARTCARD_FRONT + ICE_API.ICE_GRAPHICS_FRONT) > 0)
{
/* Put any SmartCard processing/communication here */
TalkToSmartCard();
}
/* Remove the card from the reader and continue printing */
ICE_API.SmartCardContinue(printer.Hdc, ICE_API.ICE_SMART_CARD_GOOD);
/* End the page */
ICE_API.EndPage(printer.Hdc);
}
/* End job */
ICE_API.EndDoc(printer.Hdc);
}
}

The ICE_API mostly contains wrappings for the functions from the ICE_API.dll which comes with the printer and defines some constants and data structures, like this

[StructLayout(LayoutKind.Sequential)]
public struct DOCINFO
{
public int cbSize;
public string lpszDocName;
public string lpszOutput;
public string lpszDataType;
}

........

[DllImport("ICE_API.dll")]
public static extern int FeedCard(int hdc, int dwCardData);

[DllImport("ICE_API.dll")]
public static extern int GetCardId(int hdc, CARDIDTYPE pCardId);

[DllImport("ICE_API.dll")]
public static extern int SmartCardContinue(int hdc, int dwCommand);

.........

public const int ICE_SMARTCARD_FRONT = 0x10;
public const int ICE_GRAPHICS_FRONT = 0x1;

public const int ICE_SMART_CARD_GOOD = 0;
public const int ICE_SMART_CARD_ABORT = 1;

Now that was the easy part.

by . Also posted on my website