12.1 ClientLib and NativeLib API Implementations |
The SP-ICE-3 Client API is provided as two implementations for each of the supported Host-PC platforms:
Windows | DLL Name | intended Client Program Type |
---|---|---|
ClientLib | RAYLASE.SPICE3.ClientLib.dll | .Net Application , written using any of the .NET languages ( C#, VB.NET, etc) |
NativeLib | RAYLASE.SPICE3.Native.ClientLib.dll | Native Application, written using any language which allows linking with DLLs via the stdc calling convention (e.g. C, C++ (unmanaged), python, FORTRAN IV, etc.)[Note 1] |
GNU/Linux |
DLL or SO | intended Client Program Type |
ClientLib | RAYLASE.SPICE3.ClientLib.dll | .Net Application , written using any of the managed .NET languages ( C#, VB.NET, etc) |
NativeLib | libRAYLASE.SPICE3.Native.ClientLib-1.##.#.so | Native Application, written using any language which allows linking with SOs via the stdc calling convention (e.g. C, C++ (unmanaged), python, FORTRAN IV, etc.)[Note 1] |
The differences between the implementations are discussed below.
The main purpose of the SP-ICE-3 ClientLib is to abstract communications with the SP-ICE-3 Card, and to provide the programmer with comfortable access to the card's functionality.
The top-level ClientAPI class must be instantiated once for each card that your application program wishes to control. Thereafter, it serves two main purposes:
handles communications with the individual card;
provides access to the card's functional sub-units via members which each present an instance of a particular sub-unit's API.
Important |
---|
Please make sure that a suitable version of the .NET Framework is installed on your Host-PC. |
The NativeLib mirrors the ClientLib's functionality almost 1:1, so that the SP-ICE-3 Card can be easily accessed from unmanaged (native) applications.
Obviously, a few minor exceptions and allowances must be made:
All native functions appear in the global namespace.
For most of the methods defined by the sub-unit APIs in the ClientLib namespace, there are equivalent functions in the NativeLib, but they are renamed according to the convention:
ClientLib API method | NativeLib API equivalent function |
---|---|
ClientAPI.<SubAPIMemberName>.<Methodname>(...) | rl<SubAPIMemberName><Methodname>(handle, ...) |
Thus, for instance: |
|
client.Scanner.GetConfig() | rlScannerGetConfig(hClient, *config) |
For futher examples, see below.
Method signatures remain generally unchanged in the NativeLib, EXCEPT for an additional leading parameter of type rlHandle, which is a handle to something appropriate:
in many cases, this will be the handle for a particular client-instance (i.e. for a particular SP-ICE-3 Card), as returned by rlConnect(...)[Note 2]
sometimes it might be a local structure instance such as a command list, etc.
Some methods in the ClientLib (managed) return a value but take no parameters.
Their equivalents in the NativeLib take a pointer-to-buffer parameter for the returned value.
See the example for GetConfig(), above.
Note |
---|
Native programs cannot use .NET-Exceptions, so for the NativeLib:
|
The NativeLib does not provide equivalents for certain ClientLib functions which are implemented using Reflection.
Please note that the NativeLib implementation of the SP-ICE-3 Client API is NOT inherently thread-safe.
Note |
---|
This code is provided for comparison only, and is neither complete, nor guaranteed to run as it stands. |
For the sake of simplicity, we assume that we already know the address of the SP-ICE-3 Card : otherwise, we would need to use the discovery mechanism.
Note in particular how much easier it is to implement proper error handling with .NET Exceptions ... :-)
ClientLib | NativeLib |
---|---|
C# 1using System; 2using RAYLASE.SPICE3.ClientLib; 3 4public class ClientLibExampleMarkSquare 5{ 6 const string MyKnownCardAddress = "192.168.1.1"; 7 8 public static void Main( string[] args ) 9 { 10 try 11 { 12 // establish a connection with the card 13 using ( ClientAPI client = new ClientAPI( MyKnownCardAddress ) ) 14 { 15 // Reset the card to its default settings: 16 // This restores the following settings to the values that were last saved on the card: 17 // - scanner configuration (such as field size, field correction, etc.) 18 // - laser configuration (such as gate/LM timing parameters, power target, etc.) 19 // - process variables (such as jump speed, settling times, mark speed, etc.) 20 client.System.ResetToDefaults(); 21 22 // do the real work here 23 MarkSquare( client ); 24 } 25 } 26 catch ( Exception ex ) 27 { 28 Console.WriteLine( ex.ToString() ); 29 } 30 } 31 32 public static void MarkSquare( ClientAPI client ) 33 { 34 // get the scanner's current field size 35 double fieldSize = client.Scanner.GetConfig().FieldSizeX; 36 37 double squareSize = 32760 / 32768.0 * fieldSize; 38 39 double jumpSpeed = 10.0; 40 double markSpeed = 3.0; 41 42 // Create a list locally on the host computer, 43 // and fill it with macro-vectors defining a square. 44 int listID = 0; 45 Console.WriteLine( "Preparing list: ID={1}...", listID ); 46 CommandList list = new CommandList(); 47 48 list.AppendJumpSpeed( jumpSpeed ); 49 50 list.AppendMarkSpeed( markSpeed ); 51 52 list.AppendJumpAbs( 0, 0 ); 53 54 list.AppendJumpRel( -squareSize / 2, -squareSize / 2 ); 55 56 list.AppendMarkRel( squareSize, 0 ); 57 58 list.AppendMarkRel( 0, squareSize ); 59 60 list.AppendMarkRel( -squareSize, 0 ); 61 62 list.AppendMarkRel( 0, -squareSize ); 63 64 // transfer list contents to card 65 client.List.Set( listID, list ); 66 67 // run the list, and wait until its execution has completed 68 Console.WriteLine( "Executing list: ID={1}...", listID ); 69 client.List.Execute( listID ); 70 71 Nullable<int> timeoutMs = 30000; 72 Nullable<int> doneID; 73 74 Console.WriteLine( "Waiting until list execution is done: ID={1}...", listID ); 75 if ( !client.List.WaitForListDone( out doneID, timeoutMs ) ) 76 throw new Exception( "Timed out waiting for ListDone" ); 77 78 Console.WriteLine( "List done: ID={1}...", doneID ); 79 80 // delete list on the card: this frees the memory occupied by the list on the card. 81 Console.WriteLine( "Deleting list: ID={1}...", listID ); 82 client.List.Delete( listID ); 83 84 // 85 // (No need to "delete" the local list.) 86 // 87 } 88} | C++ 1#include <stdio.h> 2#include "ClientAPI.h" 3 4#define MY_KNOWN_CARD_ADDRESS "192.168.1.1" 5static rlResult markSquare(rlHandle handle); 6static int printLastError(void); 7 8int _tmain(int argc, char* argv[]) 9{ 10 // establish a connection with the card 11 rlHandle handle = rlConnect(MY_KNOWN_CARD_ADDRESS, 49374); 12 if (handle < 0) 13 return printLastError(); 14 15 rlResult status = rlSUCCESS; 16 17 // Reset the card to its default settings: 18 // This restores the following settings to the values that were last saved on the card: 19 // - scanner configuration (such as field size, field correction, etc.) 20 // - laser configuration (such as gate/LM timing parameters, power target, etc.) 21 // - process variables (such as jump speed, settling times, mark speed, etc.) 22 if ((status = rlSystemResetToDefaults(handle)) != rlSUCCESS) 23 goto Cleanup; 24 25 // do the real work here 26 status = MarkSquare(handle)); 27 28Cleanup: 29 // print any errors 30 if (status != rlSUCCESS) 31 printLastError(); 32 33 // disconnect from the card 34 printf("Disconnecting from card...\n"); 35 if (rlDisconnect(handle) != rlSUCCESS) 36 return printLastError(); 37 38 printf("Exiting with status = %d\n", status); 39 return status; 40} 41 42static rlResult MarkSquare(rlHandle handle) 43{ 44 rlResult result; 45 46 // get the scanner's current field size 47 rlScannerConfig sc; 48 if ((result = rlScannerGetConfig(handle, &sc)) != rlSUCCESS) 49 return result; 50 51 double squareSize = 32760 / 32768.0 * fieldSize; 52 53 double jumpSpeed = 10.0; 54 double markSpeed = 3.0; 55 56 // Create a list locally on the host computer, 57 // and fill it with macro-vectors defining a square. 58 int listIndex = 0; 59 printf("Preparing list: index=%d...\n", listIndex); 60 rlCommandListHandle list = rlListAllocate(handle, listIndex); 61 62 if ((result = rlListAppendJumpSpeed(list, jumpSpeed)) != rlSUCCESS) 63 return result; 64 if ((result = rlListAppendMarkSpeed(list, markSpeed)) != rlSUCCESS) 65 return result; 66 if ((result = rlListAppendJumpAbs2D(list, 0, 0)) != rlSUCCESS) 67 return result; 68 if ((result = rlListAppendJumpRel2D(list, -squareSize/2, -squareSize/2)) != rlSUCCESS) 69 return result; 70 if ((result = rlListAppendMarkRel2D(list, squareSize, 0)) != rlSUCCESS) 71 return result; 72 if ((result = rlListAppendMarkRel2D(list, 0, squareSize)) != rlSUCCESS) 73 return result; 74 if ((result = rlListAppendMarkRel2D(list, -squareSize, 0)) != rlSUCCESS) 75 return result; 76 if ((result = rlListAppendMarkRel2D(list, 0, -squareSize)) != rlSUCCESS) 77 return result; 78 79 // close the list causing its contents to be transferred to the card 80 printf("Closing list: index=%d...\n", listIndex); 81 if ((result = rlListSet(handle, list)) != rlSUCCESS) 82 return result; 83 84 // run the list, and wait until its execution has completed 85 printf("Executing list: index=%d...\n", listIndex); 86 if ((result = rlListExecute(handle, listIndex)) != rlSUCCESS) 87 return result; 88 89 int timeoutMs = 30000; 90 bool done = false; 91 int32_t listID; 92 printf("Waiting until list execution is done: index=%d...\n", listIndex); 93 if ((result = rlListWaitForExecutionDone(handle, timeoutMs, &done, &listID)) != rlSUCCESS) 94 return result; 95 if (!done) 96 { 97 printf("Timeout: execution has not completed after %d ms!", timeoutMs); 98 return rlERROR; 99 } 100 printf("Execution done: index=%d...\n", listIndex); 101 102 // delete list on the card: this frees the card's memory occupied by the list 103 printf("Deleting list: index=%d...\n", listIndex); 104 if ((result = rlListDelete(handle, listIndex)) != rlSUCCESS) 105 return result; 106 107 // delete the local list: this frees the PC's memory occupied by the card 108 if ((result = rlListReleaseHandle(list)) != rlSUCCESS) 109 return result; 110 111 return result; 112} 113 114// helper function which displays the description of the last error 115static int printLastError(void) 116{ 117 char errBuffer[1024] = { 0 }; 118 rlGetLastError(errBuffer, sizeof(errBuffer) - 1); 119 printf("%s", errBuffer); 120 return rlERROR; 121} |
Ok, that last one is actually intended to be a joke...
rlConnect(...) itself being one of the handful of NativeLib functions which have no direct equivalent in the ClientLib.