PCSC sample in OCaml
Here is the PCSC sample in OCaml language I promised in PC/SC sample in different languages.
Manuel Preliteiro wrote a OCaml PC/SC OCaml PC/SC
Binding to the PCSC standard started in 2003 and still active in 2007. The latest version of the project is 0.6 and is still in beta but works fine according to my tests.
Installation
You first need to install OCaml. A simple
apt-get install ocaml
is enough on a Debian (or derivative like Ubuntu) system. Then get the ocamlpcsc-0.6.tar.gz archive from OCaml PC/SCBinding to the PCSC standard.
ocamlpcsc-0.6$ make
cc `pkg-config libpcsclite --cflags` -c convert.c
ocamlopt -c pcscmacros.ml
ocamlc -c pcscmacros.ml
cc -I /usr/lib/ocaml/3.10.2 `pkg-config libpcsclite --cflags` -c pcscC.c
ocamlopt -pp camlp4o -c pcscML.ml
ocamlc -custom -pp camlp4o -c pcscML.ml
Source code
I am not a Caml or OCaml expert. The example is just a modification of the example from Manuel to use my applet.
open Pcscmacros;; open Printf;; open PcscML;; open Str;; let func () = let (rvEstablishContext, hContext) = sCardEstablishContext scard_scope_system () () in if (rvEstablishContext != scard_s_success) then ( printf "SCardEstablishContext: Cannot Connect to Resource Manager %d\n" rvEstablishContext; flush(stdout); () ); let (rvListReaders, readers) = sCardListReaders () in printf "Readers List: \n"; Array.iter (fun z -> print_string (z ^ " : ")) readers; printf "\n"; flush(stdout); let reader1 = readers.(0) in let (rvSCardConnect, hCard, dwActiveProtocol) = sCardConnect reader1 scard_share_shared scard_protocol_t1 in if (rvSCardConnect != scard_s_success) then ( printf "SCardConnect: Cannot connect to card %d\n" rvSCardConnect; flush(stdout); () ); let pioSendPci = (scard_protocol_t1, 0) in let commande1 = [|0x00; 0xA4; 0x04; 0x00; 0x0A; 0xA0; 0x00; 0x00; 0x00; 0x62; 0x03; 0x01; 0x0C; 0x06; 0x01|] in let dwSendLength = Array.length commande1 in let (rvSCardTransmit, pioRecvPci, pcRecvBuffer) = sCardTransmit hCard pioSendPci commande1 dwSendLength in if (rvSCardTransmit != scard_s_success) then ( printf "SCardTransmit: Cannot transmit to card %d\n" rvSCardTransmit; flush(stdout); () ) else ( let (_, _) = pioRecvPci in printf "Data transmited with success: "; Array.iter (fun z -> print_string ((string_of_int z) ^ " : ")) pcRecvBuffer; print_string "\n"; flush(stdout) ); let commande2 = [|0x00; 0x00; 0x00; 0x00|] in let dwSendLength = Array.length commande2 in let (rvSCardTransmit, pioRecvPci, pcRecvBuffer) = sCardTransmit hCard pioSendPci commande2 dwSendLength in if (rvSCardTransmit != scard_s_success) then ( printf "SCardTransmit: Cannot transmit to card %d\n" rvSCardTransmit; flush(stdout); () ) else ( let (_, _) = pioRecvPci in printf "Data transmited with success: "; Array.iter (fun z -> print_string ((string_of_int z) ^ " : ")) pcRecvBuffer; print_string "\n"; Array.iter (fun z -> print_char (char_of_int z)) pcRecvBuffer; print_string "\n"; flush(stdout) ); let rvSCardDisconnect = sCardDisconnect hCard scard_leave_card in if (rvSCardDisconnect != scard_s_success) then ( printf "SCardDisconnect: Cannot disconect card %d\n" rvSCardDisconnect; flush(stdout); () ); ;; let _ = func ();; (** ocamlopt -c demo.ml **) (** ocamlopt -pp camlp4o str.cmxa -cclib '-lpcsclite convert.o pcscC.o' -o demo pcscML.cmx pcscmacros.cmx demo.cmx **)
The last two line are the commands to execute to compile the program.
Output
Readers List:
Gemplus GemPC Twin 00 00 :
Data transmited with success: 144 : 0 :
Data transmited with success: 72 : 101 : 108 : 108 : 111 : 32 : 119 : 111 : 114 : 108 : 100 : 33 : 144 : 0 :
Hello world!?
You can see a
?
character at the end. It is the status word 0x90 0x90 badly converted in ASCII. An improvement would be to only display n-2 first characters. This is left as an exercise to the reader.Conclusion
Nothing much to say. If you are a OCaml user you may be interested by this wrapper.
This blog entry is dedicated to Alexandre.