Tsctl C API

From embeddedTS Manuals

This reference section documents the tsctl C API. Each class documents the numbering of each function in the API for that class. Each function documents the nature of the function itself, along with any examples of using that function.

The C API always includes an un-named void pointer as its first argument. This argument is analogous to the "this" pointer in C++, and must be a pointer to the class being called, e.g. ob->Function(ob,...); This pointer must be obtained by calling the Init function for the class in question. Please note that the Init functions are not thread safe. The tsctl program handles this by protecting calls to Init functions by a mutex, so that only one Init function at a time can be called.


All functions which return a status will use a positive value for success and a negative value for failure. The negative value will be the error code.

Array

libtsctl uses a special C data structure called an Array (note the upper-case A to distinguish from a normal C array.) The libtsctl convention is to attached the pointer character "*" to the data type when an Array is in use, and to the variable name when the data type is a regular C pointer.

The tsctl Array is document here: TsctlArray

System

System Functions
Name Number
ClassCount 0
InstanceCount 1
APICount 2
LockCount 3
LockHolderInfo 4
ConnWaitInfo 5
CANBusGet 6
BuildTime 7
ModelId 8
BaseBoardId 9
MapLength 10
MapGet 11
MapLookup 12
MapLookupPartial 13
MapAdd 14
MapDelete 15
Note 16
Version 17
UptimeServer 18
UptimeHost 19
FPGARevision 20
EchoNumber 21

Initialization:

System *SystemInit(int instance);

ClassCount

int32 (*ClassCount)(void *);

Obtain the number of classes defined by the server. The value returned is one greater than the maximum value allowed to be passed as the class parameter in any tsctl protocol request to the server.

Examples:

System *sys = SystemInit(0);
printf("There are %d classes defined by the system.\n",sys->ClassCount(sys));

InstanceCount

int32 (*InstanceCount)(void *,int32 ClassNumber);

Obtain the number of instances of the specified class which are available on the server for clients to make requests for through the tsctl protocol. The value returned is one greater than the maximum value allowed to be passed as the instance parameter in any tsctl protocol request to the specified class; if a value equal or greater is passed, the server will signal an exception by closing the connection to the client.

If the server does not have any instances of the specified class, the value returned will be 0.

Examples:

System *sys = SystemInit(0);
printf("There are %d instances of class 1 in the system.\n",sys->InstanceCount(sys,1));

APICount

int32 (*APICount)(void *,int32 ClassNumber);

This function returns the number of API functions implemented in the specified class . The value returned is one greater than the maximum value allowed to be passed as the instance parameter in any tsctl protocol request to the specified class; if a value equal or greater is passed, the server will signal an exception by closing the connection to the client.

If the server does not have any instances of the specified class, the value returned will be 0.

Examples:

System *sys = SystemInit(0);
printf("There are %d API functions in class 1.\n",sys->APICount(sys,1));

LockCount

int32 (*LockCount)(void *);

This function returns the total number of system locks on the server. This value only has meaning if the server was compiled with threading support.

Examples:

System *sys = SystemInit(0);
printf("There are %d locks in the system.\n",sys->LockCount(sys));

LockHolderInfo

LockHolderInf* (*LockHolderInfo)(void *);

This function returns an Array of LockHolderInfo structures, one element for each lock currently held.

The structures are filled in such that the nth element will contain information about the nth lock. The pid field contains the process id (on the server) servicing the connection that holds the lock. The count field contains the number of times the given process has acquired the lock. If this value is zero, then the value of the pid field should be ignored, as the lock is not held.

This function is not useful outside the context of a server, as stand-alone applications do not typically implement the support necessary.

typedef struct LockHolderInfo {
  int pid;
  int count;
} LockHolderInfo;


Examples: Coming Soon!

ConnWaitInfo

ConnectionWaitInf* (*ConnWaitInfo)(void *);

This function returns an Array of information about each connection and what lock it is waiting for.

It does not make sense to use this function outside the context of the tsctl server.

typedef struct ConnectionWaitInfo {
   int pid;
   int wait; // lock waited for, or -1 if none
} ConnectionWaitInfo;

Examples: Coming Soon!

CANBusGet

SystemResult (*CANBusGet)(void *,int32 CANInstance);

This function returns the number of the Bus instance used by the specified CAN instance to access the CAN registers. If the given instance does not have an underlying Bus instance, or if the specified CAN instance does not exist, then a negative value is returned.

Examples:

System *sys = SystemInit(0);
printf("CAN instance 0 uses Bus instance %d\n",sys->CANBusGet(sys,0));

BuildTime

uint32 (*BuildTime)(void *);

This function returns the time at which the binary containing libtsctl and currently being invoked was compiled, expressed in seconds since the beginning of the Unix Epoch.

Examples: Coming Soon!

ModelId

int32 (*ModelId)(void *);

This function returns the Model ID of the board on which the server is running, in hexadecimal. For instance, 0x4200 corresponds to the TS-4200.

Examples:

System *sys = SystemInit(0);
printf("Model Id = %04X\n",sys->ModelId(sys));

BaseBoardId

int32 (*BaseBoardId)(void *);

This function returns the ID of the base board on which the server is running, in hexadecimal. For instance, 0x8160 corresponds to the TS-8160. If no base board is detected, 0 is returned;

Examples: System *sys = SystemInit(0); printf("BaseBoard Id=%04X\n",sys->BaseBoardId(sys));

MapLength

int32 (*MapLength)(void *);

The System object provides a "Map" which associates string names to integer values. This is used to store DIO names, attributes, and other information. This information is automatically populated by reading /etc/dioctl.config at startup.

This function returns the number of string to value mappings.

Examples:

System *sys = SystemInit(0);
printf("There are %d mappings.\n",sys->MapLength(sys));

MapGet

int8* (*MapGet)(void *,int32 MapIndex,int32 Value[1]);

The System object provides a "Map" which associates string names to integer values. This is used to store DIO names, attributes, and other information. This information is automatically populated by reading /etc/dioctl.config at startup.

This function returns the nth string in the string to value mapping as a newly allocated Array. It also places the nth value in the array passed.

Examples:

// dump the list of strings in the map
System *sys = SystemInit(0);
int i,n = sys->MapLength(sys),val;
char* str;

for (i=0;i<n;i++) {
  str = sys->MapGet(sys,i,&val);
  printf("%s=%d\n",str,val);
  ArrayFree(str);
}

MapLookup

int32 (*MapLookup)(void *,const int8* String);

The System object provides a "Map" which associates string names to integer values. This is used to store DIO names, attributes, and other information. This information is automatically populated by reading /etc/dioctl.config at startup.

This function returns the value of the specified string in the mapping. For the purpose of this look up case is ignored in both the String parameter and in the table entries. Returns a negative value if the specified string does not exist in the mapping.

Examples:

System *sys = SystemInit(0);
printf("DIO39=%d\n",sys->MapLookup(sys,ASCIIZLocal("DIO39")));

MapLookupPartial

int8* (*MapLookupPartial)(void *,const int8* StringPrefix,int32 Value);

The System object provides a "Map" which associates string names to integer values. This is used to store DIO names, attributes, and other information. This information is automatically populated by reading /etc/dioctl.config at startup.

This function finds the first string in the mapping that begins with the specified string, and has the specified value, and returns the remainder of the string. If a match is not found, returns an empty strings. In either case, the returned value is newly allocated.

Examples:

 System *sys = SystemInit(0);
 char* str = sys->MapLookupPartial(sys,ASCIIZLocal("attrib.Connector.Name."),1);
 printf("Connector 1 is named '%s'\n",str);
 ArrayFree(str);

MapAdd

SystemResult (*MapAdd)(void *,const int8* String,int32 Value);

The System object provides a "Map" which associates string names to integer values. This is used to store DIO names, attributes, and other information. This information is automatically populated by reading /etc/dioctl.config at startup.

This function adds the specified string:value mapping to the system mapping table. If the given string already has it value in the mapping it will be replaced by the new value. A positive values is returned on success. The string str is internally copied, so the caller is responsible for freeing it as needed.

Note: When invoked in direct mode (i.e. with no host argument and no tsctl server running locally) the System Map does not persist after the current invocation of tsctl and so any additions to the default Map will be lost.

Examples:

System *sys = SystemInit(0);
sys->InstanceCount(sys,ASCIIZLocal("LASER_CTRL"),77);

MapDelete

SystemResult (*MapDelete)(void *,const int8* String);

tsctlSystemMapDeleteDesc Coming Soon!

Examples: Coming Soon!

Note

int8* (*Note)(void *,const int8* Message);

tsctlSystemNoteDesc Coming Soon!

Examples: Coming Soon!

Version

int8* (*Version)(void *);

This function returns a string containing the release version that the libtsctl binary is based on. As of version 0.91 this number replaces the old release number based on year, month, day, hour, and minute. If you make any modifications to libtsctl or any supplied sample applications you are strongly urged to create a unique version scheme to distinguish your fork from the official Technologic Systems customer source code release. This can be accomplished by passing -DLIBTSCTL_ORGANIZATION="yourname" to the compiler when building the part of your application containing libtsctl.

Examples: Coming Soon!

UptimeServer

uint32 (*UptimeServer)(void *);

This function returns the number of seconds since the libtsctl being invoked was first initialized by means of any class being initialized via the appropriate Init call (e.g. BusInit(n) for the Bus class). For tsctl, this is done during startup of the server, or startup of the client when invoking the command in direct mode.

Examples: Coming Soon!

UptimeHost

uint32 (*UptimeHost)(void *);

This function returns the number of seconds since the host machine running the libtsctl based binary was last booted.

Examples: Coming Soon!

FPGARevision

int32 (*FPGARevision)(void *);

This function returns the FPGA revision number. This eliminates the need to know board specific differences in how this value is obtained.

Examples: Coming Soon!

EchoNumber

int32 (*EchoNumber)(void *,int32 n);

This function returns the number that was passed. This is mainly for test purposes. For instance, the tsctl client will automatically perform lookups on strings passed where numbers were expected; this function can be used to see what the lookup is returning without actually using it for anything.

This differs from calling the System MapLookup function because the tsctl client supports adding lookups with the "+" character. Therefore you can determine the final result even with non-trivial lookups.

Examples: Coming Soon!

Bus

Bus Functions
Name Number
Lock 0
Unlock 1
Preempt 2
Peek8 3
Poke8 4
Peek16 5
Poke16 6
Peek32 7
Poke32 8
BitGet8 9
BitAssign8 10
BitSet8 11
BitClear8 12
BitGet16 13
BitAssign16 14
BitSet16 15
BitClear16 16
BitGet32 17
BitAssign32 18
BitSet32 19
BitClear32 20
PeekStream 21
PokeStream 22
Refresh 23
Commit 24
BitToggle8 25
BitToggle16 26
BitToggle32 27
Assign8X 28
Assign16X 29
Assign32X 30
BitsGet8 31
BitsGet16 32
BitsGet32 33

Initialization:

Bus *BusInit(int instance);

Lock

int32 (*Lock)(void *,uint32 num,int32 flags);

This function acquires or releases the Bus resource lock. The lock must be held before any other functions on the given Bus are called.

The num parameter is unused and should be set to 0.

The value of flags must be a bitwise OR of the following:

NONBLOCKING: If the Bus lock can be immediately acquired (without blocking) then it is and the call succeeds, otherwise the lock is not acquired and the call fails.

SHARED: If this flag is set, then a shared (read) lock will be attempted, otherwise an exclusive (write) lock will be attempted. An exclusive lock requires that no shared locks be held before it will succeed. A shared lock requires that no exclusive locks be help before it will succeed. Locking favors readers so as to prevent reader starvation.

NOUNLOCK: Normally, if the thread calling this function holds other locks and this function will block, the other locks held are temporarily dropped and are then re-acquired before the call returns, in order to prevent deadlock. Therefore, the call will not fail, but it could block indefinitely. However if this flag is present, then if other locks are held and the call would block, the function returns failure. Note: deadlock detection is currently disabled pending debugging efforts

This function returns a positive value on success, and a negative value on failure.

enum {
NONBLOCKING=1, SHARED=2, NOUNLOCK=4
};

Examples: Coming Soon!

Unlock

int32 (*Unlock)(void *,uint32 num,int32 flags);

This function releases lock num previously successfully acquired by a call to Lock. The flags parameter must be SHARED if the lock was acquired with that flag, otherwise it must be zero. The other flags do not apply to Unlock and should not be presented. It is an error to unlock with a different SHARED state than the lock was acquired with; the results in this case will be undefined.


enum {
NONBLOCKING=1, SHARED=2, NOUNLOCK=4
};

Examples: Coming Soon!

Preempt

int32 (*Preempt)(void *);

tsctlBusPreemptDesc Coming Soon!

Examples: Coming Soon!

Peek8

uint8 (*Peek8)(void *,int32 Address);

This function performs an 8-bit read of the bus at the specified Address, and returns the value read.

Examples: Coming Soon!

Poke8

void (*Poke8)(void *,int32 Address,uint8 Value);

This function performs an 8-bit write of the bus at the specified Address, with the specified Value.

Examples: Coming Soon!

Peek16

uint16 (*Peek16)(void *,int32 Address);

This function performs a 16-bit read of the bus at the specified Address, and returns the value read.

Examples: Coming Soon!

Poke16

void (*Poke16)(void *,int32 Address,uint16 Value);

This function performs a 16-bit write to the bus at the specified Address, with the specified Value.

Examples: Coming Soon!

Peek32

uint32 (*Peek32)(void *,int32 Address);

This function performs a 32-bit read of the bus at the specified Address, and returns the value read.

Examples: Coming Soon!

Poke32

void (*Poke32)(void *,int32 Address,uint32 Value);

This function performs a 32-bit write to the bus at the specified Address, with the specified Value.

Examples: Coming Soon!

BitGet8

int32 (*BitGet8)(void *,int32 Address,int32 BitNumber);

This function performs an 8-bit read of the bus at the specified Address, and returns 1 if the if the specified bit in the value read is set, or 0 if the bit is cleared.

The bit parameter must be in the range of 0 (lsb) to 7 (msb).

Examples: Coming Soon!

BitAssign8

void (*BitAssign8)(void *,int32 Address,int32 BitNumber,int32 Value);

This function performs an 8-bit read/modify/write to the bus at the specified Address. The modify will assign the specified BitNumber of the value to the specified bit Value, which must be 1 or 0.

The bit parameter must be in the range of 0 to 7.

Examples: Coming Soon!

BitSet8

void (*BitSet8)(void *,int32 Address,int32 BitNumber);

This function performs an 8-bit read/modify/write to the bus at the specified Address. The modify will assign the specified BitNumber of the value to the a value of 1.

The bit parameter must be in the range of 0 to 7.

Examples: Coming Soon!

BitClear8

void (*BitClear8)(void *,int32 Address,int32 BitNumber);

This function performs an 8-bit read/modify/write to the bus at the specified Address. The modify will assign the specified BitNumber of the value to the a value of 0.

The bit parameter must be in the range of 0 to 7.

Examples: Coming Soon!

BitGet16

int32 (*BitGet16)(void *,int32 Address,int32 BitNumber);

This function performs a 16-bit read of the bus at the specified Address, and returns 1 if the if the specified BitNumber in the value read is set, or 0 if the bit is cleared.

The bit parameter must be in the range of 0 to 15.

Examples: Coming Soon!

BitAssign16

void (*BitAssign16)(void *,int32 Address,int32 BitNumber,int32 Value);

This function performs a 16-bit read/modify/write to the bus at the specified Address. The modify will assign the specified BitNumber of the value to the specified bit Value, which must be 1 or 0.

The bit parameter must be in the range of 0 to 15.

Examples: Coming Soon!

BitSet16

void (*BitSet16)(void *,int32 Address,int32 BitNumber);

This function performs a 16-bit read/modify/write to the bus at the specified Address. The modify will assign the specified BitNumber of the value to the a value of 1.

The bit parameter must be in the range of 0 to 15.

Examples: Coming Soon!

BitClear16

void (*BitClear16)(void *,int32 Address,int32 BitNumber);

This function performs a 16-bit read/modify/write to the bus at the specified Address. The modify will assign the specified BitNumber of the value to the a value of 0.

The bit parameter must be in the range of 0 to 15.

Examples: Coming Soon!

BitGet32

int32 (*BitGet32)(void *,int32 Address,int32 BitNumber);

This function performs a 32-bit read of the bus as the specified Address, and returns 1 if the if the specified bit in the value read is set, or 0 if the bit is cleared.

The bit parameter must be in the range of 0 to 31.

Examples: Coming Soon!

BitAssign32

void (*BitAssign32)(void *,int32 Address,int32 BitNumber,int32 Value);

This function performs a 32-bit read/modify/write to the bus at the specified Address. The modify will assign the specified BitNumber of the value to the specified bit Value, which must be 1 or 0.

The bit parameter must be in the range of 0 to 31.

Examples: Coming Soon!

BitSet32

void (*BitSet32)(void *,int32 Address,int32 BitNumber);

This function performs a 32-bit read/modify/write to the bus at the specified Address. The modify will assign the specified BitNumber of the value to the value of 1.

The bit parameter must be in the range of 0 to 31.

Examples: Coming Soon!

BitClear32

void (*BitClear32)(void *,int32 Address,int32 BitNumber);

This function performs a 32-bit read/modify/write to the bus at the specified Address. The modify will assign the specified BitNumber of the value to the value of 0.

The bit parameter must be in the range of 0 to 31.

Examples: Coming Soon!

PeekStream

void (*PeekStream)(void *,int32 address,int32 direction,int8* dest);

This function performs a read burst on the bus. A typical bus will have a native bus size that it performs these reads with. Note that some busses may not support a read burst.

The address parameter specifies the starting address of the burst.

The direction parameter specifies the increment to add (or, for a negative value, to subtract) from the address for each subsequent element. Not all implementations may support this paramter.

The burst is read into the specified dest buffer Array. The number of bytes read will be equal to the length of the Array upon entry.

Examples: Coming Soon!

PokeStream

void (*PokeStream)(void *,int32 address,int32 direction,const int8* data);

This function performs a write burst on the bus. A typical bus will have a native bus size that it performs these writes with. Note that some busses may not support a write burst.

The address parameter specifies the starting address of the burst.

The direction parameter specifies the increment to add (or, for a negative value, to subtract) from the address for each subsequent element. Not all implementations may support this paramter.

The burst is read from the specified data buffer. The number of bytes written to the bus from the buffer is equal to the Array length of data.

Examples: Coming Soon!

Refresh

void (*Refresh)(void *);

Some busses support atomic reading and writing segments of its data. A bus that supports this operation will implement the Refresh function to atomically read those segments that support this function.

One example of a bus that does this is CacheBus. This bus supports caching portions of a (presumably slow) bus backed by hardware registers.

Refresh should always be called before Commit.

Examples: Coming Soon!

Commit

void (*Commit)(void *,int32 ForceAll);

Some busses support atomic reading and writing segments of its data. A bus that supports this operation will implement the Commit function to atomically write those segments that support this function.

One example of a bus that does this is CacheBus. This bus supports caching portions of a (presumably slow) bus backed by registers.

If the forceall parameter is non-zero, all segments will be written, otherwise only those segments which are marked as dirty will be written.

Examples: Coming Soon!

BitToggle8

int32 (*BitToggle8)(void *,int32 Address,int32 BitNumber);

This function performs an 8-bit read/modify/write to the bus at the specified Address. The modify will assign the specified BitNumber of the value to the inversion of its current value.

The BitNumber parameter must be in the range of 0 to 7.

The value returned is the new value of the bit.

Examples: Coming Soon!

BitToggle16

int32 (*BitToggle16)(void *,int32 Address,int32 BitNumber);

This function performs a 16-bit read/modify/write to the bus at the specified Address. The modify will assign the specified BitNumber of the value to the inversion of its current value.

The BitNumber parameter must be in the range of 0 to 15.

The value returned is the new value of the bit.

Examples: Coming Soon!

BitToggle32

int32 (*BitToggle32)(void *,int32 Address,int32 BitNumber);

This function performs a 32-bit read/modify/write to the bus at the specified Address. The modify will assign the specified BitNumber of the value to the inversion of its current value.

The BitNumber parameter must be in the range of 0 to 31.

The value returned is the new value of the bit.

Examples: Coming Soon!

Assign8X

uint8 (*Assign8X)(void *,int32 Address,int32 BitMSB,int32 BitLSB,int32 Value);

This function performs an 8-bit read/modify/write to the bus at the specified Address in order to replace bits from BitMSB down to BitLSB, inclusively, with the specified Value.

The values of BitMSB and BitLSB must be in the range of 0 to 7, inclusively, and BitMSB must be greater than or equal to BitLSB.

Only the bottom-most (BitMSB - BitLSB) bits of value are assigned.

This function returns the new value written to the address.

Examples: Coming Soon!

Assign16X

uint16 (*Assign16X)(void *,int32 Address,int32 BitMSB,int32 BitLSB,int32 Value);

This function performs a 16-bit read/modify/write to the bus at the specified Address in order to replace bits from BitMSB down to BitLSB, inclusively, with the specified Value.

The values of BitMSB and BitLSB must be in the range of 0 to 15, inclusively, and BitMSB must be greater than or equal to BitLSB.

Only the bottom-most (BitMSB - BitLSB) bits of value are assigned.

This function returns the new value written to the address.

Examples: Coming Soon!

Assign32X

uint32 (*Assign32X)(void *,int32 Address,int32 BitMSB,int32 BitLSB,int32 Value);

This function performs a 32-bit read/modify/write to the bus at the specified Address in order to replace bits from BitMSB down to BitLSB, inclusively, with the specified Value.

The values of BitMSB and BitLSB must be in the range of 0 to 31, inclusively, and BitMSB must be greater than or equal to BitLSB.

Only the bottom-most (BitMSB - BitLSB) bits of value are assigned.

This function returns the new value written to the address.

Examples: Coming Soon!

BitsGet8

uint8 (*BitsGet8)(void *,int32 Address,int32 BitMSB,int32 BitLSB);

This function performs an 8-bit read of the value at the specified Address, and returns the value of the bits from BitMSB down to BitLSB, inclusively. This effectively is the same as masking out all bits above BitMSB and shifting the result down (right) by BitLSB bits.

The values of BitMSB and BitLSB must be in the range of 0 to 7, inclusively, and BitMSB must be greater than or equal to BitLSB.

Examples: Coming Soon!

BitsGet16

uint16 (*BitsGet16)(void *,int32 Address,int32 BitMSB,int32 BitLSB);

This function performs a 16-bit read of the value at the specified Address, and returns the value of the bits from BitMSB down to BitLSB, inclusively. This effectively is the same as masking out all bits above BitMSB and shifting the result down (right) by BitLSB bits.

The values of BitMSB and BitLSB must be in the range of 0 to 15, inclusively, and BitMSB must be greater than or equal to BitLSB.

Examples: Coming Soon!

BitsGet32

uint32 (*BitsGet32)(void *,int32 Address,int32 BitMSB,int32 BitLSB);

This function performs a 32-bit read of the value at the specified Address, and returns the value of the bits from BitMSB down to BitLSB, inclusively. This effectively is the same as masking out all bits above BitMSB and shifting the result down (right) by BitLSB bits.

The values of BitMSB and BitLSB must be in the range of 0 to 31, inclusively, and BitMSB must be greater than or equal to BitLSB.

Examples: Coming Soon!

Time

Time Functions
Name Number
Wait 0
Delay 1
Tick 2
usElapsed 3
usFuture 4
TimeoutQ 5
TPS 6

Initialization:

Time *TimeInit(int instance);

Wait

uint32 (*Wait)(void *,uint32 microseconds);

Blocks until at least the specified number of microseconds has passed, then returns the number of microseconds actually waited.

Uses the local system facilities to sleep for periods at least at long as the clock tick, and busy waits amounts of time shorter than this.

Examples: Coming Soon!

Delay

void (*Delay)(void *,uint32 microseconds);

This function delays until at least the specified number of microseconds has passed. For the TCP object, this means that although the call will delay execution on the server it will not block on the client, allowing additional calls to be queued to the server during the delay.

The C function itself will block until the delay is finished.

Examples: Coming Soon!

Tick

uint32 (*Tick)(void *);

A given instance of the time object has an underlying timer or periodically incremented counter which keeps time. The value of this counter is called the "tick". This function returns the current 32-bit value of this counter.

Examples: Coming Soon!

usElapsed

uint32 (*usElapsed)(void *,uint32 start);

The start parameter to this function is the return value of a previous call to the Tick function. This function returns the number of microseconds that have passed since the call to Tick which returned the given start value.

A given Time object will have a maximum amount of elapsed time which can be measured before it will roll over and start at zero again. In addition, a 32-bit microsecond value can only represent a maximum of approximately 4295 seconds. If the Time object can measure longer intervals than this the usElapsed64 function (currently not defined) should be called instead.

Examples: Coming Soon!

usFuture

uint32 (*usFuture)(void *,uint32 start,uint32 microseconds);

This function returns the tick value for a time at the specified number of microseconds from the given start tick.

Calling this function one in conjunction with multple calls to TimeoutQ will generally be more efficient than repeatedly calling usElapsed for determining when a specified amount of time has passed.

Examples: Coming Soon!

TimeoutQ

TimeResult (*TimeoutQ)(void *,uint32 start,uint32 end);

This function returns true if the specified end time relative to the specified start time has been reached.

Note that since the tick value can roll over, the actual amount of time available to detect a timeout is equal to the total time for the tick to iterate through all values, minus the number of ticks between start and end. (end can be less than start; this function will correctly handle roll-over). Therefore, it is recommended that the user not try to measure times too close to the maximum possible (for example, within a few seconds, or the maximum amount of time between calls to TimeoutQ.)

If start and end are equal, then this function will always return true.

Examples: Coming Soon!

TPS

uint32 (*TPS)(void *);

This function returns the number of ticks per second that the timebase used by this Time object ticks at.

Examples: Coming Soon!

Pin

Pin Functions
Name Number
Lock 0
Unlock 1
Preempt 2
ModeGet 3
ModeSet 4

Initialization:

Pin *PinInit(int instance);

Lock

int32 (*Lock)(void *,uint32 num,int32 flags);

This function acquires or releases the Pin resource lock. The should must be held before any other functions are called if there is any chance of other processes competing to access the same pins.

The num parameter is the Pin number to lock.

The value of flags must be a bitwise OR of the following:

NONBLOCKING: If the Pin lock can be immediately acquired (without blocking) then it is and the call succeeds, otherwise the lock is not acquired and the call fails.

SHARED: If this flag is set, then a shared (read) lock will be attempted, otherwise an exclusive (write) lock will be attempted. An exclusive lock requires that no shared locks be held before it will succeed. A shared lock requires that no exclusive locks be help before it will succeed. Locking favors readers so as to prevent reader starvation.

NOUNLOCK: Normally, if the thread calling this function holds other locks and this function will block, the other locks held are temporarily dropped and are then re-acquired before the call returns, in order to prevent deadlock. Therefore, the call will not fail, but it could block indefinitely. However if this flag is present, then if other locks are held and the call would block, the function returns failure. Note: deadlock detection is currently disabled pending debugging efforts

This function returns a positive value on success, and a negative value on failure.

enum {
NONBLOCKING=1, SHARED=2, NOUNLOCK=4
};

Examples: Coming Soon!

Unlock

int32 (*Unlock)(void *,uint32 num,int32 flags);

This function releases lock num previously successfully acquired by a call to Lock. The flags parameter must be SHARED if the lock was acquired with that flag, otherwise it must be zero. The other flags do not apply to Unlock and should not be presented. It is an error to unlock with a different SHARED state than the lock was acquired with; the results in this case will be undefined.

Examples: Coming Soon!

Preempt

int32 (*Preempt)(void *);

tsctlPinPreemptDesc Coming Soon!

Examples: Coming Soon!

ModeGet

PinMode (*ModeGet)(void *,int32 PinNumber);

This function returns the current mode of the specified PinNumber.

Examples: Coming Soon!

ModeSet

PinResult (*ModeSet)(void *,int32 PinNumber,PinMode Mode);

This function sets the mode of the specified PinNumber to the specified Mode.

Available modes include MODE_DIO, MODE_CAN, MODE_SPI, MODE_ADC, MODE_TWI, MODE_UART, MODE_TS, MODE_BUS, MODE_PWM, and MODE_CLK, although most of these are usually not applicable.

Examples: Coming Soon!

DIORaw

DIORaw Functions
Name Number
Lock 0
Unlock 1
Preempt 2
DirSet 3
DataSet 4
DirGet 5
DataGet 6
Count 7

Initialization:

DIORaw *DIORawInit(int instance);

Lock

int32 (*Lock)(void *,uint32 num,int32 flags);

This function acquires or releases the DIORaw resource lock. The lock must be acquired before calling other DIORaw functions.

The num parameter is the DIORaw number to lock.

The value of flags must be a bitwise OR of the following:

NONBLOCKING: If the DIORaw lock can be immediately acquired (without blocking) then it is and the call succeeds, otherwise the lock is not acquired and the call fails.

SHARED: If this flag is set, then a shared (read) lock will be attempted, otherwise an exclusive (write) lock will be attempted. An exclusive lock requires that no shared locks be held before it will succeed. A shared lock requires that no exclusive locks be help before it will succeed. Locking favors readers so as to prevent reader starvation.

NOUNLOCK: Normally, if the thread calling this function holds other locks and this function will block, the other locks held are temporarily dropped and are then re-acquired before the call returns, in order to prevent deadlock. Therefore, the call will not fail, but it could block indefinitely. However if this flag is present, then if other locks are held and the call would block, the function returns failure. Note: deadlock detection is currently disabled pending debugging efforts

This function returns a positive value on success, and a negative value on failure.

enum {
NONBLOCKING=1, SHARED=2, NOUNLOCK=4
};

Examples: Coming Soon!

Unlock

int32 (*Unlock)(void *,uint32 num,int32 flags);

This function releases lock num previously successfully acquired by a call to Lock. The flags parameter must be SHARED if the lock was acquired with that flag, otherwise it must be zero. The other flags do not apply to Unlock and should not be presented. It is an error to unlock with a different SHARED state than the lock was acquired with; the results in this case will be undefined.

Examples: Coming Soon!

Preempt

int32 (*Preempt)(void *);

tsctlDIORawPreemptDesc Coming Soon!

Examples: Coming Soon!

DirSet

void (*DirSet)(void *,int32 num,int32 asOutput);

The specified raw DIO num, relative to the object, is set to an output if asOutput is true, otherwise it is set to an input.

Examples: Coming Soon!

DataSet

void (*DataSet)(void *,int32 num,int32 asHigh);

The data output of the specified raw DIO num, relative to the object, is set to high if asHigh is true, otherwise it is set to low. If the DIO is not currently set as an output this will have no effect on the DIO until it is set to an output.

Examples: Coming Soon!

DirGet

int32 (*DirGet)(void *,int32 num);

Returns the directional state of the specified raw DIO num, relative to the object. A true return indicates the DIO is an output, while a false return indicates it is an input.

Examples: Coming Soon!

DataGet

int32 (*DataGet)(void *,int32 num);

Returns the actual (not set) state of the specified raw DIO num, relative to the object. A true return indicates the DIO is high, while a false return indicates it is an low.

Examples: Coming Soon!

Count

uint32 (*Count)(void *);

Returns the number of DIOs in the object. All DIOs in the object are numbered sequential, starting at 0 and ending at one less than the count returned.

Examples: Coming Soon!

DIO

DIO Functions
Name Number
Lock 0
Unlock 1
Preempt 2
Refresh 3
Commit 4
Set 5
Get 6
SetAsync 7
GetAsync 8
Wait 9
Count 10
Capabilities 11
GetMulti 12

Initialization:

DIO *DIOInit(int instance);

Lock

int32 (*Lock)(void *,uint32 num,int32 flags);

This function acquires or releases the DIO resource lock. The lock must be acquired before calling other DIO functions if there is any chance of another process trying to simultaneously access the DIO. The DIO lock also automatically set the mode of the pin corresponding to the DIO to DIO mode. If the lock is not acquired, the ModeSet of the Pin class must be called appropriately to do this (if needed).

The num parameter is the DIO number to lock.

The value of flags must be a bitwise OR of the following:

NONBLOCKING: If the DIO lock can be immediately acquired (without blocking) then it is and the call succeeds, otherwise the lock is not acquired and the call fails.

SHARED: If this flag is set, then a shared (read) lock will be attempted, otherwise an exclusive (write) lock will be attempted. An exclusive lock requires that no shared locks be held before it will succeed. A shared lock requires that no exclusive locks be help before it will succeed. Locking favors readers so as to prevent reader starvation.

NOUNLOCK: Normally, if the thread calling this function holds other locks and this function will block, the other locks held are temporarily dropped and are then re-acquired before the call returns, in order to prevent deadlock. Therefore, the call will not fail, but it could block indefinitely. However if this flag is present, then if other locks are held and the call would block, the function returns failure. Note: deadlock detection is currently disabled pending debugging efforts

This function returns a positive value on success, and a negative value on failure.

enum {
NONBLOCKING=1, SHARED=2, NOUNLOCK=4
};

Examples: Coming Soon!

Unlock

int32 (*Unlock)(void *,uint32 num,int32 flags);

This function releases lock num previously successfully acquired by a call to Lock. The flags parameter must be SHARED if the lock was acquired with that flag, otherwise it must be zero. The other flags do not apply to Unlock and should not be presented. It is an error to unlock with a different SHARED state than the lock was acquired with; the results in this case will be undefined.

Preempt

int32 (*Preempt)(void *);


Refresh

void (*Refresh)(void *);

The Refresh command causes all synchronous DIO values to update from their current hardware value. Subsequent calls to Get will return the value of each DIO at the last Refresh.

Refresh must always be called at the start of a set of synchronous DIO operations, in order to synchronize the DIO cache with the actual state of the DIOs.

Commit

void (*Commit)(void *,int32 ForceAll);

The Commit command causes all synchronous DIO values to be update to hardware. All calls to Set which have changed the cached value of a DIO since the last Commit will cause the hardware value for that DIO to be updated.

Regardless of how many DIOs change in a single register, the register will be written at most once for a given commit, and not at all if no DIO values have changed since the last Commit.

In general, a Commit should be issued at the end of a set of synchronous DIO operations, in order to synchronize the DIO cache with the actual state of the DIOs. The Commit command only detects synchronous changes, therefore mixing synchronous and asynchronous DIO access must be done with care. More specifically, any asynchronous changes that occur between a Refresh and a Commit will not be detected and may result in the Commit not causing a DIO to reflect the cached state, specifically if the asynchronous change causes a DIO to not match its cached state and the cache state is not marked as dirty.

Set

void (*Set)(void *,int32 DIONum,DIOState State);

Set the synchronous DIO with logical number DIONum relative to the DIO instance to the specified State.

The Refresh function must be called before this function.

The actual DIO state wil not be updated until the next call to Commit.

typedef enum {
  INPUT_LOW=-3, // DIO is an INPUT and read LOW
  INPUT_HIGH=-2, // DIO is an INPUT and read HIGH
  INPUT=-1, // set DIO to an INPUT
  LOW=0, // set DIO to an OUTPUT and drive LOW
  HIGH=1 // set DIO to an OUTPUT and drive HIGH
} DIOState;

Examples: Coming Soon!

Get

DIOState (*Get)(void *,int32 DIONum);

The function returns the synchronous state of the specified DIO DIONum relative to the DIO object. The value returned is the state of the DIO as of the last Refresh call.

typedef enum {
  INPUT_LOW=-3, // DIO is an INPUT and read LOW
  INPUT_HIGH=-2, // DIO is an INPUT and read HIGH
  INPUT=-1, // set DIO to an INPUT
  LOW=0, // set DIO to an OUTPUT and drive LOW
  HIGH=1 // set DIO to an OUTPUT and drive HIGH
} DIOState;

SetAsync

void (*SetAsync)(void *,int32 DIONum,DIOState State);

Set the asynchronous (current) value of the DIO with logical number DIONum relative to the DIO instance to the specified State.

The value is not reflected in the synchronous side of the DIO. For example, if the synchronous value differs from the asynchronous value and a Commit is performed, the asynchronous change will not be detected and the value of the output may or may not be changed depending on whether other DIO values in the same register changes. Because of this indeterminate or difficult to predict behavior mixing of synchronous and asynchronous calls must be done with care.

typedef enum {
  INPUT_LOW=-3, // DIO is an INPUT and read LOW
  INPUT_HIGH=-2, // DIO is an INPUT and read HIGH
  INPUT=-1, // set DIO to an INPUT
  LOW=0, // set DIO to an OUTPUT and drive LOW
  HIGH=1 // set DIO to an OUTPUT and drive HIGH
} DIOState;

GetAsync

DIOState (*GetAsync)(void *,int32 DIONum);

The function returns the asynchronous (current) state of the specified DIO DIONum relative to the DIO object.

typedef enum {
  INPUT_LOW=-3, // DIO is an INPUT and read LOW
  INPUT_HIGH=-2, // DIO is an INPUT and read HIGH
  INPUT=-1, // set DIO to an INPUT
  LOW=0, // set DIO to an OUTPUT and drive LOW
  HIGH=1 // set DIO to an OUTPUT and drive HIGH
} DIOState;

Examples:

int main(int argc,char *argv[]) {
  System *sys;
  DIO *dio;
  int n;
  DIOState state;

  if (argc < 2) {
    printf("usage: %s <dio#>\n",argv[0]);
    return 1;
  }
  sys = SystemInit(0);
  dio = DIOInit(0);
  if (!dio) {
    printf("Error instantiating DIO 0\n");
    return 1;
  }

  // if argument isn't a number, do a lookup
  n = atoi(argv[1]);
  if (n == 0 && argv[1][0] != '0') {
    // Note that we have to pass our C string to ASCIIZ
    // to get the libtsctl array expected by MapLookup
    // for a longer running program we would ArrayFree() it when done...
    n = sys->MapLookup(sys,ASCIIZ(argv[1]));
    if (n < 0) {
      printf("DIO %s not found\n",argv[1]);
    }
  }

 dio->Lock(dio,n,0);
 state = dio->GetAsync(dio,n);
 dio->Unlock(dio,n,0);

 printf("DIO %s state is %s\n",argv[1],DIOValueString(state));
 return 0;
}

Wait

void (*Wait)(void *,int32* match,int32 min,int32 max,const int32* nh,const int32* nl);

The nh Array contains elements which are DIO numbers which match if they are high.

The nl Array contains elements which are DIO numbers which match if they are low.

Waits until the total number of DIOs that match their respective states is between min and max, inclusively.

Upon entry, the length of the match Array must be allocated or null. If it is null, it is ignored. Otherwise, upon return, the match Array length will be resized to the number of DIOs that match and will contain the DIO numbers that matched. If the match Array was not long enough to hold all the DIOs that matched, then the DIOs reported are truncated to the size of the Array as passed by the caller and it is returned length unchanged.

This function polls at the closest available interval to 10ms possible, using Time instance 1 (if available), or Time instance 0 (if instance 1 is not present).

Count

uint32 (*Count)(void *);

Returns the number of DIOs in the object. All DIOs in the object are numbered sequential, starting at 0 and ending at one less than the count returned

Unlike other functions (besides Lock), the DIO object does not need to be locked when this function is called.

Capabilities

DIOCaps (*Capabilities)(void *,uint32 num);

This function returns the capabilities the DIO number num.

typedef enum DIOCaps{
  DIO_NOT_PRESENT=0,
  DIO_CAN_INPUT=1,
  DIO_CAN_DRIVE_HIGH=2,
  DIO_HIGH_SIDE=3,
  DIO_CAN_DRIVE_LOW=4,
  DIO_LOW_SIDE=5,
  DIO_OUTPUT_ONLY=6,
  DIO_NORMAL=7
}DIOCaps;

GetMulti

int32 (*GetMulti)(void *,int8* state,int32 offset);

The function returns the current state of all or some of the DIOs in this instance.

Each byte in the state array is packed with 8 DIO values. The most significant bit of bits[0] contains the value of the logical DIO numbered offset. The next most significant bit contains the value of logical DIO offset+1 and so forth, moving to the next element of bits every time the current element has be filled with the next 8 DIO values.

Each bit upon return contains only the value of the DIO, either 1 for HIGH or 0 for LOW. No indication is returned whether the DIO is an INPUT or OUTPUT.

It is up to the user to correctly size the state Array. If the size is longer than the remaining number of DIO from the starting offset the value of the remaining bits will be undefined. To find the optimal Array length for bits, take the number of DIOs in the instance, as reported by the Count function, and subtract the starting offset. Then, divide by 8, adding one if there is a remainder.

A smaller than optimal size can be specified in order to reduce the range of DIO values returned. In this way it is possible to use this function to return any contiguous subset of DIO values.

This function also supports a "quick" mode. If 32 or fewer bits are needed, pass a zero-length state Array or null pointer for bits, and the return value will be the first 32 DIOs starting at offset with the most significant bit being the value of the logical DIO numbered offset.

TWI

TWI Functions
Name Number
Lock 0
Unlock 1
Preempt 2
Write 3
Read 4

Initialization:

TWI *TWIInit(int instance);

Lock

int32 (*Lock)(void *,uint32 num,int32 flags);

This function acquires or releases the TWI resource lock. The lock must be acquired before calling other TWI functions.

The num parameter is 0.

The value of flags must be a bitwise OR of the following:

NONBLOCKING: If the TWI lock can be immediately acquired (without blocking) then it is and the call succeeds, otherwise the lock is not acquired and the call fails.

SHARED: If this flag is set, then a shared (read) lock will be attempted, otherwise an exclusive (write) lock will be attempted. An exclusive lock requires that no shared locks be held before it will succeed. A shared lock requires that no exclusive locks be help before it will succeed. Locking favors readers so as to prevent reader starvation.

NOUNLOCK: Normally, if the thread calling this function holds other locks and this function will block, the other locks held are temporarily dropped and are then re-acquired before the call returns, in order to prevent deadlock. Therefore, the call will not fail, but it could block indefinitely. However if this flag is present, then if other locks are held and the call would block, the function returns failure. Note: deadlock detection is currently disabled pending debugging efforts

This function returns a positive value on success, and a negative value on failure.

enum {
NONBLOCKING=1, SHARED=2, NOUNLOCK=4
};

Examples: The TWI module should always be locked during use to ensure pin functions are set correctly. See other TWI functions for Lock examples.

Unlock

int32 (*Unlock)(void *,uint32 num,int32 flags);

This function releases lock num previously successfully acquired by a call to Lock. The flags parameter must be SHARED if the lock was acquired with that flag, otherwise it must be zero. The other flags do not apply to Unlock and should not be presented. It is an error to unlock with a different SHARED state than the lock was acquired with; the results in this case will be undefined.

Preempt

int32 (*Preempt)(void *);


Write

TWIResult (*Write)(void *,int32 devadr,int32 adrslen,int32 adrs,const int8* bytes);

This function writes a frame to the two-wire interface.

The devadr parameter specifies the address of the device to talk to.

The adrslen parameter specifies the length of the register address in the device. Valid values for this parameter are 0 through 4.

The adrs parameter specifies the address in the device to write to. If adrslen is 0, this value is ignored. The bytes in the adrs are sent LSB first

The bytes is an Array containing the data to send.

Examples:

int main(int argc, char* argv[]) {
  TWI* twi = TWIInit(0);
  int ret;
  TWIResult tret;
 
  if ((ret=twi->Lock(twi,0,1)) < 0) {
    printf("TWI lock error %d\n", ret);
    return 1;
  }
  // Write 4 byte to device DEV_ID at address REG_ADRS
 
  // Allocate a 4 element libtsctl array of char to hold data to send
  ArrayAutoOfSize(char,val,4);
  // Initialize the data to send
  val[0] = 0x12;
  val[1] = 0x34;
  val[2] = 0x56;
  val[3] = 0x78;

  if ((tret = twi->Write(twi,DEV_ID,1,REG_ADRS,val)) != TWISuccess) {
    printf("Error writing TWI: %d\n",tret);
    return 1;
  }
 
  twi->Unlock(twi,0,0);
}

Read

TWIResult (*Read)(void *,int32 devadr,int32 adrslen,int32 adrs,int8* bytes);

This function reads a frame from the two-wire interface.

The devadr parameter specifies the address of the devise to talk to.

The adrslen parameter specifies the length of the register address in the device. Valid values for this parameter are 0 through 4.

The adrs parameter specifies the address in the device to read from. If adrslen is 0, this value is ignored. The bytes in the adrs are sent LSB first.

The bytes parameter contains an Array to receive the data read, with the length of the Array being the number of bytes to read.

Examples:

int main(int argc, char* argv[]) {
  TWI* twi = TWIInit(0);
  int ret;
  TWIResult tret;

  if ((ret=twi->Lock(twi,0,1)) < 0) {
    printf("TWI lock error %d\n", ret);
    return 1;
  }
  // Read 1 byte from device DEV_ID at address REG_ADRS

  // Allocate a 1 element libtsctl array of char to hold result
  ArrayAutoOfSize(char,val,1);
  if ((tret = twi->Read(twi,DEV_ID,1,REG_ADRS,val)) != TWISuccess) {
    printf("Error reading TWI: %d\n",tret);
    return 1;
  }

  twi->Unlock(twi,0,0);
}

CAN

CAN Functions
Name Number
Rx 0
Tx 1
BaudSet 2
BaudGet 3
Abort 4
RxMulti 5

Initialization:

CAN *CANInit(int instance);

Rx

CANResult (*Rx)(void *,CANMessage message[1]);

Blocks until a message is received from CAN. The message is put into the CANmessage buffer passed by the caller.

In direct mode all available CPU will be used to poll for a message to be received. If this is a problem it is recommended to use the CAN server which uses interrupts.

Returns a positive return value if a message was received into the buffer provided, or a negative value if the receive was aborted. The latter could occur if Abort was explicitly called before the message was received, or if another error such as a Bus Off condition occurred.

struct CANMessage {
  unsigned flags;
  unsigned id;
  unsigned t_sec;
  unsigned t_usec;
  unsigned length;
  unsigned char data[8];
};


typedef enum CANFlags{
  FLAG_BUS_ERROR=1,
  FLAG_ERROR_PASSIVE=2,
  FLAG_DATA_OVERRUN=4,
  FLAG_ERROR_WARNING=8,
  FLAG_RTR=16,
  FLAG_EXT_ID=32,
  FLAG_LOCAL=64,
  FLAG_CONTROL=128
} CANFlags;


The timestamp fields (t_sec, t_usec) contain the server time when the CAN packet was received. For performance reasons some servers may not implement this and may fill these fields with 0.

The length field indicates how many bytes of data are in this CAN frame, and consequently, how many sequential bytes in the data field is valid.

Tx

CANResult (*Tx)(void *,uint32 flags,uint32 id,const int8* data);

Queues A CAN message for transmission with the specified flags, id, and data.

This function will block until the message is queued. For direct access there typically is only room for a single message to be queued at once, and as a result if a message is already waiting to be sent, this function will use all available CPU to poll waiting for the transmit buffer to be empty. Therefore, this function is not recommended to be used in direct mode in cases where this would be a problem.

Returns a negative value on error or a positive value on success.

BaudSet

uint32 (*BaudSet)(void *,uint32 opt_baud);

Change the baud rate of the CAN medium to the closest supported value to that requested. Returns the actual baud rate on return.

The baud rate should always be set before attempting to send or receive any messages. The tsctl client in direct mode retains the previous baud rate between invocations so it is not necessary to set it with each invocation.

On error, a negative error code is returned.

BaudGet

uint32 (*BaudGet)(void *);

Returns the current baud rate of the CAN medium.

Abort

void (*Abort)(void *);

Queues an abort. The purpose of this function is to cancel a pending transmit or receive, which normally block until completion. Abort is signal safe, so it is ideal for using from an alarm or signal handler.

When Tx is called to transmit a message, it will block until the transmit buffering mechanism is ready to accept a message to send. If an abort is pending, the check will be cancelled, the abort cleared, and the Tx function will return a negative error code.

When Rx or RxMulti is called to receive a message (or messages), it will first check if a message is ready to be received, and if not, it will block until a message is ready. If an abort is pending, the check will be cancelled, the abort cleared, and the Rx or RxMulti function will return a negative error code.

RxMulti

CANResult (*RxMulti)(void *,CANMessage* msg,int32 min);

Blocks until at least min messages are received from CAN. The messages received are put into the CANMessage Array msg passed by the caller. Upon entry, the length of this Array must be equal to the maximum number of messages desired. Upon return, the length will be the actual number of messages received.

The return value will be the number of messages received, unless the receive was aborted, in which case a negative value will be returned. The latter could occur if Abort was explicitly called before the message was received, or if another error such as a Bus Off condition occurred.

SPI

SPI Functions
Name Number
Lock 0
Unlock 1
Preempt 2
Write 3
Read 4
ReadWrite 5
ClockSet 6
EdgeSet 7

Initialization:

SPI *SPIInit(int instance);

Lock

int32 (*Lock)(void *,uint32 num,int32 flags);

This function acquires or releases the SPI resource lock. The lock must be acquired before calling other SPI functions.

The num parameter is 0.

The value of flags must be a bitwise OR of the following:

NONBLOCKING: If the SPI lock can be immediately acquired (without blocking) then it is and the call succeeds, otherwise the lock is not acquired and the call fails.

SHARED: If this flag is set, then a shared (read) lock will be attempted, otherwise an exclusive (write) lock will be attempted. An exclusive lock requires that no shared locks be held before it will succeed. A shared lock requires that no exclusive locks be help before it will succeed. Locking favors readers so as to prevent reader starvation.

NOUNLOCK: Normally, if the thread calling this function holds other locks and this function will block, the other locks held are temporarily dropped and are then re-acquired before the call returns, in order to prevent deadlock. Therefore, the call will not fail, but it could block indefinitely. However if this flag is present, then if other locks are held and the call would block, the function returns failure. Note: deadlock detection is currently disabled pending debugging efforts

This function returns a positive value on success, and a negative value on failure.

enum {
NONBLOCKING=1, SHARED=2, NOUNLOCK=4
};

Unlock

int32 (*Unlock)(void *,uint32 num,int32 flags);

This function releases lock num previously successfully acquired by a call to Lock. The flags parameter must be SHARED if the lock was acquired with that flag, otherwise it must be zero. The other flags do not apply to Unlock and should not be presented. It is an error to unlock with a different SHARED state than the lock was acquired with; the results in this case will be undefined.

Preempt

int32 (*Preempt)(void *);

Write

SPIResult (*Write)(void *,int32 adrs,const uint8* buf);

This function initiates a transaction on the SPI bus. The bytes in the Array buf for the length of the Array are written to the SPI bus during the transaction, and the bytes read in are discarded. The chip select line to be asserted is specified by adrs. If the value of adrs is negative, the chip select line will not be de-asserted at the end of the write and -adrs is used as address; if adrs is positive then the chip select will be de-asserted at the end of the write. An adrs of 1 corresponds to CS0, an adrs of 2 corresponds to CS1, etc.

A positive value is returned on success, and a negative value on failure.

Examples:

// Do an SPI write transaction to an FPGA expecting a four byte
// sequence of command, address, 16-bit data
void SPIRegisterWrite(SPI *spi,int adrs,unsigned short data) {
  // First, create a 4 element libtsctl array of char
  ArrayAutoOfSize(unsigned char, spiData, 4);

  // Initialize the array for the transaction
  spiData[0] = 0XE0;
  spiData[1] = adrs;
  spiData[2] = data >> 8;
  spiData[3] = data & 0xff;

  // Lock SPI, do the transaction, and unlock
  spi->Lock(spi, 0, 0);
  spi->Write(spi, 4, spiData);
  spi->Unlock(spi, 0, 0);
}

Read

SPIResult (*Read)(void *,int32 adrs,uint8* buf);

This function initiates a transaction on the SPI buf. The bytes in the Array buf for the length of the Array are filled in with bytes read from the SPI bus during the transaction. The bytes written to the bus during the transaction are undefined. The chip select line to be asserted is specified by adrs. If the value of adrs is negative, the chip select line will not be de-asserted at the end of the read and -adrs is used as address; if adrs is positive then the chip select will be de-asserted at the end of the read. An adrs of 1 corresponds to CS0, an adrs of 2 corresponds to CS1, etc.

A positive value is returned on success, and a negative value on failure.

ReadWrite

SPIResult (*ReadWrite)(void *,int32 adrs,const uint8* wbuf,uint8* rbuf);

This function initiates a transaction on the SPI bus. The bytes in the Array wbuf for the length of the Array are written to the SPI bus during the transaction, and the bytes in rbuf for the same length are filled in with bytes read from the SPI bus during the same transaction. The chip select line to be asserted is specified by adrs. If the value of adrs is negative, the chip select line will not be de-asserted at the end of the readwrite and -adrs is used as address; if adrs is positive then the chip select will be de-asserted at the end of the read/write. An adrs of 1 corresponds to CS0, an adrs of 2 corresponds to CS1, etc.

A positive value is returned on success, and a negative value on failure.

Examples:

// Do an SPI read transaction to an FPGA expecting a four byte
// sequence of command, address, 16-bit data
unsigned short SPIRegisterRead(SPI *spi,int adrs) {
  // First, allocate two 4 element libtsctl arrays of char
  ArrayAutoOfSize(unsigned char, spiData, 4);
  ArrayAutoOfSize(unsigned char, spiResp, 4);

  // Initialize the array for the transaction
  spiData[0] = 0X70;
  spiData[1] = adrs;
  spiData[2] = data >> 8;
  spiData[3] = data & 0xff;

  // Lock SPI, do the transaction, and unlock
  spi->Lock(spi, 0, 0);
  spi->ReadWrite(spi, 4, spiData, spiResp);
  spi->Unlock(spi, 0, 0);
  return ((unsigned short)spiResp[2] << 8) + (unsigned short)spiResp[3];
}

ClockSet

SPIResult (*ClockSet)(void *,uint32 hz);

This function changes the clock speed of the SPI bus to the given hz frequency. Depending on the hardware present, the actual frequency may be different from what is specified, however it will never be faster than the value specified.

A positive value is returned on success, and a negative value on failure.

Examples:

  spi->ClockSet(spi,5000000); // 5MHz

EdgeSet

SPIResult (*EdgeSet)(void *,int32 posedge);

This function changes the edge on which SPI data is clocked.

The posedge parameter encodes both the standard CPOL and CPHA parameters, which are defined as follows:

  • CPOL is the base (inactive) clock state
  • CPHA is the edge to sample on (0=1st or leading, 1=2nd or trailing). Data changes on the opposite edge than it is sampled on. MOSI and MISO change on the same clock edge.

When positive, the posedge parameter primarily denotes the value of CPOL. When negative, the logical bit-wise note of this parameter denotes the value of CPOL. (-1 means CPOL=0 and -2 means CPOL=1)

When posedge is non-negative, CPHA=0. When it is negative, CPHA=1.

The following table summarizes these relationships:

posedgeCPOLCPHA
110
000
-101
-211

Note:The TS-4500/TS-4700/TS-4800 have only CPHA=0, with the posedge parameter being equal to CPOL.

A positive value is returned on success, and a negative value on failure (i.e. if the device does not support the requested posedge value).

AIO

AIO Functions
Name Number
Lock 0
Unlock 1
Preempt 2
Type 3
VoltageRangeList 4
PrecisionList 5
PeriodRangeList 6
TriggerList 7
Channels 8
Reset 9
ChannelEnable 10
ChannelSamplePeriod 11
ChannelPrecision 12
ChannelVoltageRange 13
Configuration 14
ConfigureTest 15
Configure 16
ITrig 17
Get 18
Put 19
Ready 20
Gets8 21
Gets16 22
Gets32 23
Puts8 24
Puts16 25
Puts32 26
Readys8 27
Readys16 28
Readys32 29

Initialization:

AIO *AIOInit(int instance);

Lock

int32 (*Lock)(void *,uint32 num,int32 flags);

This function acquires or releases the AIO resource lock. The lock must be held before any other functions on the given AIO are called.

The num parameter is unused and should be set to 0.

The value of flags must be a bitwise OR of the following:

NONBLOCKING: If the AIO lock can be immediately acquired (without blocking) then it is and the call succeeds, otherwise the lock is not acquired and the call fails.

SHARED: If this flag is set, then a shared (read) lock will be attempted, otherwise an exclusive (write) lock will be attempted. An exclusive lock requires that no shared locks be held before it will succeed. A shared lock requires that no exclusive locks be help before it will succeed. Locking favors readers so as to prevent reader starvation.

NOUNLOCK: Normally, if the thread calling this function holds other locks and this function will block, the other locks held are temporarily dropped and are then re-acquired before the call returns, in order to prevent deadlock. Therefore, the call will not fail, but it could block indefinitely. However if this flag is present, then if other locks are held and the call would block, the function returns failure. Note: deadlock detection is currently disabled pending debugging efforts

This function returns a positive value on success, and a negative value on failure.

enum {
NONBLOCKING=1, SHARED=2, NOUNLOCK=4
};

Unlock

int32 (*Unlock)(void *,uint32 num,int32 flags);

This function releases lock num previously successfully acquired by a call to Lock. The flags parameter must be SHARED if the lock was acquired with that flag, otherwise it must be zero. The other flags do not apply to Unlock and should not be presented. It is an error to unlock with a different SHARED state than the lock was acquired with; the results in this case will be undefined.


enum {
NONBLOCKING=1, SHARED=2, NOUNLOCK=4
};

Preempt

int32 (*Preempt)(void *);


Type

AIOType (*Type)(void *);

typedef enum {
AIO_ADC=0, ADIO_DAC=1
} AIOType;

Returns AIO_ADC if the AIO instance corresponds to an Analog to Digital device, or AIO_DAC if the AIO instance corresponds to a Digital to Analog device.

VoltageRangeList

VoltageRange* (*VoltageRangeList)(void *);

This function returns an Array of allowed voltage ranges for each channel. The returned Array is dynamically allocated by the function but the caller is responsible for freeing it. The length of the Array is equal to the number of voltage ranges supported.

struct VoltageSubRange {
  float start, step;
  unsigned count;
};
struct VoltageRange {
  VoltageSubRange low,high;
};



PrecisionList

int32 (*PrecisionList)(void *);

This function returns a bit-field defining what precisions are possible. The nth bit set in the return indicates that n bits of precision are possible.

PeriodRangeList

PeriodRange* (*PeriodRangeList)(void *);

This function returns an Array of allowed sampling periods for each channel. The returned Array is dynamically allocated by the function but the caller is responsible for freeing it. The length of the Array is equal to the number of period ranges supported.

The period is always expressed in nano-seconds. A period of 0 indicates that the channel can be disabled.

The AIO_HZ() macro can be used to convert back and forth between Hz and nanoseconds.

struct PeriodRange {
  unsigned start, step, count;
};

TriggerList

int32* (*TriggerList)(void *);

This function returns an Array of trigger numbers available. The returned Array is dynamically allocated by the function but the caller is responsible for freeing it. The length of the Array is equal to the number of triggers supported. Trigger 0 is universal and is not contained in the returned Array.

The meaning of a trigger signal number is implementation specific: consult the documentation for your hardware (below) for the meaning of various trigger numbers.

Negative values indicate triggering on a negative edge, while positive values indicate triggering on a positive edge. Zero indicates that conversion begins on demand, in response to a call to Get, Gets8/16/32, Put, Puts8/16/32, Ready, or Readys8/16/32. Note that conversion is always implicitly on-demand, as one of these aforementioned calls is required to begin any conversion.

Hardware Specific Triggers

WBMCP3428 - this is an I2C (TWI) A/D unit present on the TS-8390 and TS-81x0, accessed via the FPGA through a WishBone (WB) interface. Supported by TS-SOCKET boards TS-4200, TS-4500, and TS-4700.

  • No non-zero triggers are available.

ts8820

  • no non-zero triggers are available.

Channels

int32 (*Channels)(void *);

The function returns the number of channels in this module. The channel numbers are zero indexed.

Reset

void (*Reset)(void *);

This function resets the AIO to a default value. This will disable all channels that can be disabled, and will reset to default values the sample period, precision, trigger, and voltage range of each channel along with the interrupt trigger.

The default values for each AIO implementation are listed below.

ts8820ADC

  • all channels disabled
  • sample period: 10,000 ns for all channels enabled via ChannelEnable
  • precision: 16 bits
  • trigger: none
  • voltage range: -10V to +10V

ts8820DIO

  • not yet implemented

ChannelEnable

int32 (*ChannelEnable)(void *,int32 ch,int32 flag);

This function enables (flag == true) or disables (flag == false) sampling for the specified channel ch.

If ChannelSamplePeriod has not been called for this channel since the last call to Reset, the default sample period will be used.

If ChannelPrecision has not been called for this channel since the last call to Reset, the default precision will be used.

If ChannelVoltageRange has not been called for this channel since the last call to Reset, the default voltage range will be used

If ChannelTrigger has not been called for this channel since the last call to Reset, the default trigger will be used.

Upon failure, a negative error code is returned to indicate that the request would result in an unsupported configuration. On success a positive value is returned.

Note that when configuring multiple channels, each interim configuration must be valid. If you have a lot of channels to configure you may wish to use the Configure function instead to configure all channels simultaneously.

ChannelSamplePeriod

uint32 (*ChannelSamplePeriod)(void *,int32 ch,uint32 ns);

This function sets and returns the sample period for the specified channel ch to be the given number of nanoseconds ns. If the channel is not currently enabled, then the sample period will not take effect until ChannelEnable is called for this channel. Otherwise the change will take place immediately.

If a value of 0 is passed for ns, the current value in effect is returned unchanged.

Upon failure, a value of 0 is returned to indicate that the requested sample period cannot be set. If the sample period will not take effect immediately then this cannot occur, so the current sample period will be returned, since the one passed has not yet taken effect.

ChannelPrecision

int32 (*ChannelPrecision)(void *,int32 ch,int32 prec);

This function sets and returns the precision for the specified channel ch to be the given number of bit prec. If the channel is not currently enabled, then the precision will not take effect until ChannelEnable is called for this channel. Otherwise the change will take place immediately.

If a value of 0 is passed for prec, the current value in effect is returned unchanged.

Upon failure, a value of 0 is returned to indicate that the requested precision cannot be set. If the precision will not take effect immediately then this cannot occur, so the current precision will be returned, since the one passed has not yet taken effect.

ChannelVoltageRange

int32 (*ChannelVoltageRange)(void *,int32 ch,real32 low,real32 high);

This function sets the voltage range for the specified channel ch to be between low and high. If the channel is not currently enabled, then the voltage range will not take effect until ChannelEnable is called for this channel. Otherwise the change will take place immediately.

Upon failure, a negative value is returned to indicate that the requested voltage range cannot be set. If the range will not take effect immediately then this cannot occur, so the current range will be returned, since the one passed has not yet taken effect.

Configuration

int32 (*Configuration)(void *,real32* low,real32* high,int32* prec,int32* t,int32* trigger,int32 itrig[1]);

low, high, prec, rate, and trigger are Arrays having lengths equal to the number of channels.

Each element of each array is filled with the current configuration for the corresponding channel except for itrig,which is a single value for the entire module.

A positive value is returned indicating success.

low and high, upon return contain the actual voltage range in effect for each channel.

prec, upon return contains the actual (minimum) precision in bits for each channel

t, upon return contains the actual (maximum) period in ns for each channel. The AIO_HZ() macro can be used to convert back and forth between Hz and nanoseconds.

trigger, upon return contains the trigger signal for activating each channel

itrig, upon return contains the interrupt trigger signal. If this value is non-zero, then when the trigger occurs during a call to Gets8/16/32 or Puts8/16/32, the call will return immediately at the end of the current set of samples, even if the requested number of samples has not yet been taken. A value of zero disables the interrupt trigger.

ConfigureTest

int32 (*ConfigureTest)(void *,const real32* low,const real32* high,const int32* prec,const int32* rate,const int32* trigger,int32 itrig);

Returns true (non-zero) if the specific configuration is legal, and false (0) if it is not.

low and high contain the desired voltage range in effect for each channel. The length of these Arrays must be equal to the number of channels.

prec contains the desired (minimum) precision in bits for each channel. The length of this Array must be equal to the number of channels.

t contains the desired (maximum) period in ns for each channel. The length of this Arrays must be equal to the number of channels. The AIO_HZ() macro can be used to convert back and forth between Hz and nanoseconds.

trigger contains the desired trigger signal for activating each channel. The length of this Arrays must be equal to the number of channels

itrig is the interrupt trigger signal. If this value is non-zero, then when the trigger occurs during a call to Gets or Puts, the call will return immediately at the end of the current set of samples, even if the requested number of samples has not yet been taken. A value of zero disables the interrupt trigger.

Configure

int32 (*Configure)(void *,const real32* low,const real32* high,const int32* prec,const int32* rate,const int32* trigger,int32 itrig);

If the specific configuration is legal, the AIOs are configured to that configuration and a positive value is returned. Otherwise a negative error code is returned. The length of all passed Arrays must be equal to the number of channels.

low and high contain the desired voltage range in effect for each channel.

prec contains the desired (minimum) precision in bits for each channel

t contains the desired (maximum) period in ns for each channel. The AIO_HZ() macro can be used to convert back and forth between Hz and nanoseconds.

trigger contains the desired trigger signal for activating each channel

itrig is the interrupt trigger signal. If this value is non-zero, then when the trigger occurs during a call to Gets8/16/32 or Puts8/16/32, the call will return immediately at the end of the current set of samples, even if the requested number of samples has not yet been taken. A value of zero disables the interrupt trigger.

Hardware capabilities differ; to ensure maximum conversion rates across platforms when using Get or Put, call Configure before each call to only enable the next channel to converted. This will also allow for different channel configurations that would not be legal when enabling multiple channels. For example, suppose an AIO supports either 100Hz sampling at 12 bits or 50Hz sampling at 16 bits. It would not be legal to enable channel 1 for 100Hz@12 bits and channel 2 for 50Hz@16 bits at the same time. However by only enabling one channel at a time in turn before sampling it would be possible to accomplish this as both configurations are not active simultaneously.

Calling Configure while a channel is active will cause the current activity to be terminated, either immediately or after the current sample is complete, depending on the capabilities of the hardware. Any data already waiting for a call to Get or Gets8/16/32 will be discarded.

ITrig

int32 (*ITrig)(void *,int32 itrig);

Change the interrupt trigger for the AIO to the specified trigger. If an existing interrupt trigger has been set it will first be disabled, and any subsequent call to Gets or Puts that would have returned due to the trigger occurring before this call will no longer do so as if the previous trigger never occurred.

Returns a positive value on success, or a negative error code on failure.

Get

int32 (*Get)(void *,int32 channel);

Only valid if AIO is an ADC. If the AIO is a DAC, simply returns the current value being output, e.g. via the last Puts call.

If the specified channel is currently active, waits for it to become inactive, then returns the value just sampled for that channel.

If a different channel is active, either waits for it to become inactive or immediately de-activates it (depending on what the hardware is capable of), then makes the specified channel active, waits for it to become inactive, then returns the value just sampled for that channel.

If the specified channel was the last channel active but has now finished, returns the value sampled for that channel.

If no channel is currently active, makes the specified channel active, waits for it to become inactive, then returns the value just sampled for that channel.

A channel goes through the following states:

  1. When a channel is first made active, it waits for its trigger to occur. If its trigger is "on demand" then not wait is done at this step.
  2. The channel remains active while conversion begins and proceed.
  3. When conversion is finished, the channel becomes inactive as well as the last channel active.

Hardware capabilities differ; to ensure maximum conversion rates across platforms, call Configure() before each Get() or Ready() call to only enable the next channel to converted.

The value returned can be converted to the voltage on the input by the following relationship between the precision (p) in bits and input voltage range (IV) of the channel (max input voltage - minimum input voltage) and the actual voltage (V) as follows:

V = IV / 2^p

Put

int32 (*Put)(void *,int32 channel,int32 value);

Only valid if AIO is a DAC. Return value is a negative error code if AIO is not a DAC and a positive value if the specified value has begun DAC conversion.

If any channel is currently active, waits for it to become inactive, then makes the specified channel active with the specified value to convert, and returns a positive value.

If no channel is currently active, then makes the specified channel active with the specified value to convert, and returns a positive value.

A channel goes through the following states:

  1. When a channel is first made active, it waits for its trigger to occur. If its trigger is "on demand" then not wait is done at this step.
  2. The channel remains active while conversion begins and proceed.
  3. When conversion is finished, the channel becomes inactive as well as the last channel active.

Hardware capabilities differ; to ensure maximum conversion rates across platforms, call Configure before each Get or Ready call to only enable the next channel to converted.

The value passed relates to the voltage to be generated on the output by the following relationship between the precision (p) in bits and output voltage range (OV) of the channel (maximum output voltage - minimum output voltage) and the actual voltage (V) as follows:

V = OV / 2^p

Ready

int32 (*Ready)(void *,int32 channel);

Returns a negative error code if the AIO unit does not support polled conversion. In that case you must call one of the blocking functions instead, i.e. Get, Put, Gets, or Puts as appropriate.

If the specified channel is currently active, returns 0.

If a different channel is active, or an invalid channel was passed, returns a negative error code.

If the specified channel was the last channel active but has now finished, returns a positive value.

If no channel is currently active, makes the specified channel active and returns 0.

A channel goes through the following states:

  1. When a channel is first made active, it waits for its trigger to occur. If its trigger is "on demand" then not wait is done at this step.
  2. The channel remains active while conversion begins and proceed.
  3. When conversion is finished, the channel becomes inactive as well as the last channel active.

A non-positive return value indicates that a subsequent call to Get (for ADC) or Put (for DAC) will block, unless the error code indicates an invalid channel was passed, in which case nothing can be deduced about whether the Get or Put call will block.

Calling Gets (for ADC), Puts (for DAC), or Readys (for either) will override the behavior of this call.

Gets8

int32 (*Gets8)(void *,int8* buf);

This call is only valid if AIO is an ADC. Otherwise a negative error value will be returned.

If the specified buffer was successfully passed to Readys, then this call will block until that conversion is completed. Otherwise, the conversion will be initiated immediately such that each enabled channel will be activated in turn, looping around until the specified number of samples have been taken for each channel and placed into the specified buffer, with the function blocking until all conversions are completed or the interrupt trigger occurs. In either case, a positive return code will be returned indicating the number of samples actually taken.

The function may also return less than the requested number of samples of an overflow or other such error occurs. If fewer than the requested number of samples are returned, the next call may return a negative error code, and the following call will restart acquisition. The intervening error code allows the caller to determine what went wrong, and to resynchronize acquisition. For example, if an overflow occurs, the remaining data before the overflow will be returned, after which the caller will learn of the overflow and can take whatever steps are necessary due to missing samples at that point.

This function is only suitable for calling if the precision of all channels to be sampled is less than or equal to eight bits. Channels that have a higher precision will return truncated data. The format of the data put in the passed array is such that each sampled channel is added in turn. After the last channel is sampled the next sample will start over the with first channel. The length of the Array determines how many samples will be taken: it is not necessary to take a sample of every channel, and if the length of the Array is not an even multiple of the number of channels being sampled the last sampling will not contain all channels.

Gets16

int32 (*Gets16)(void *,int16* buf);

This call is only valid if AIO is an ADC. Otherwise a negative error value will be returned.

If the specified buffer was successfully passed to Readys, then this call will block until that conversion is completed. Otherwise, the conversion will be initiated immediately such that each enabled channel will be activated in turn, looping around until the specified number of samples have been taken for each channel and placed into the specified buffer, with the function blocking until all conversions are completed or the interrupt trigger occurs. In either case, a positive return code will be returned indicating the number of samples actually taken.

The function may also return less than the requested number of samples of an overflow or other such error occurs. If fewer than the requested number of samples are returned, the next call may return a negative error code, and the following call will restart acquisition. The intervening error code allows the caller to determine what went wrong, and to resynchronize acquisition. For example, if an overflow occurs, the remaining data before the overflow will be returned, after which the caller will learn of the overflow and can take whatever steps are necessary due to missing samples at that point.

This function is only suitable for calling if the precision of all channels to be sampled is less than or equal to sixteen bits. Channels that have a higher precision will return truncated data. The format of the data put in the passed array is such that each sampled channel is added in turn. After the last channel is sampled the next sample will start over the with first channel. The length of the Array determines how many samples will be taken: it is not necessary to take a sample of every channel, and if the length of the Array is not an even multiple of the number of channels being sampled the last sampling will not contain all channels.

Gets32

int32 (*Gets32)(void *,int32* buf);

This call is only valid if AIO is an ADC. Otherwise a negative error value will be returned.

If the specified buffer was successfully passed to Readys, then this call will block until that conversion is completed. Otherwise, the conversion will be initiated immediately such that each enabled channel will be activated in turn, looping around until the specified number of samples have been taken for each channel and placed into the specified buffer, with the function blocking until all conversions are completed or the interrupt trigger occurs. In either case, a positive return code will be returned indicating the number of samples actually taken.

The function may also return less than the requested number of samples of an overflow or other such error occurs. If fewer than the requested number of samples are returned, the next call may return a negative error code, and the following call will restart acquisition. The intervening error code allows the caller to determine what went wrong, and to resynchronize acquisition. For example, if an overflow occurs, the remaining data before the overflow will be returned, after which the caller will learn of the overflow and can take whatever steps are necessary due to missing samples at that point.

This function is only suitable for calling if the precision of all channels to be sampled is less than or equal to 32 bits. Channels that have a higher precision will return truncated data. The format of the data put in the passed array is such that each sampled channel is added in turn. After the last channel is sampled the next sample will start over the with first channel. The length of the Array determines how many samples will be taken: it is not necessary to take a sample of every channel, and if the length of the Array is not an even multiple of the number of channels being sampled the last sampling will not contain all channels.

Puts8

int32 (*Puts8)(void *,const int8* buf);

This call is only valid if AIO is a DAC. Otherwise a negative error value will be returned.

If the specified buffer was successfully passed to Readys, then this call will block until that conversion is completed. Otherwise, the conversion will be initiated immediately such that each enabled channel will be activated in turn, looping around until the specified number of samples have been converted from the buffer for each channel, with the function blocking until all conversions are completed or the interrupt trigger occurs. In either case, a positive return code will be returned indicating the number of samples actually taken.

The number of elements in the passed Array determines how many samples will be written. Each sample will be written to a subsequent channel, wrapping around at the end. It is not required that the length be an exact multiple of the number of channels.

Puts16

int32 (*Puts16)(void *,const int16* buf);

This call is only valid if AIO is a DAC. Otherwise a negative error value will be returned.

If the specified buffer was successfully passed to Readys, then this call will block until that conversion is completed. Otherwise, the conversion will be initiated immediately such that each enabled channel will be activated in turn, looping around until the specified number of samples have been converted from the buffer for each channel, with the function blocking until all conversions are completed or the interrupt trigger occurs. In either case, a positive return code will be returned indicating the number of samples actually taken.

The number of elements in the passed Array determines how many samples will be written. Each sample will be written to a subsequent channel, wrapping around at the end. It is not required that the length be an exact multiple of the number of channels.

Puts32

int32 (*Puts32)(void *,const int32* buf);

This call is only valid if AIO is a DAC. Otherwise a negative error value will be returned.

If the specified buffer was successfully passed to Readys, then this call will block until that conversion is completed. Otherwise, the conversion will be initiated immediately such that each enabled channel will be activated in turn, looping around until the specified number of samples have been converted from the buffer for each channel, with the function blocking until all conversions are completed or the interrupt trigger occurs. In either case, a positive return code will be returned indicating the number of samples actually taken.

The number of elements in the passed Array determines how many samples will be written. Each sample will be written to a subsequent channel, wrapping around at the end. It is not required that the length be an exact multiple of the number of channels.

Readys8

int32 (*Readys8)(void *,const int8* buf);

This function prepares a buffer for high speed conversion if supported by the hardware. For an ADC, this sets up the specified buffer to automatically receive the specified number of samples in the Array on the enabled channels, while for a DAC it sets up the specified buffer as containing the values to automatically convert to analog outputs. After the buffer has been set up the hardware is set up to activate the first enabled channel and then automatically activate each subsequent channel in turn as soon as the previous one de-activates, looping back around to the first enabled channel after the last enabled channel has de-activated as long as more samples remain.

For some hardware it may be necessary to match which Readys function is called to the size of the samples expected by the hardware. For example, a 16-bit A/D that supports DMA may require that Readys16 be called because it transfers 16-bit values. Or, it might require 32-bit values even though it takes 16-bit samples. Check for any notes for your hardware to determine if this is the case.

Returns a positive value on success. This indicates that the given buffer has been accepted for queuing.

A negative return value indicates failure. Possible failures include:

  • the specified buffer is already (still) in use. (note: you must deliberately try to provoke this error to determine if a previously requested conversion is completed)
  • the hardware has a limited amount of space for queuing and cannot accept an additional buffer at this time
  • the buffer passed does not conform to hardware requirements, such as alignment
  • the hardware does not support buffer queueing. it is still possible to call Gets or Puts as appropriate but those functions will block until the requested buffer is filled or used up.

Any previous conversion in progress caused by Ready will be finished or cancelled (depending on hardware capabilities) before this request is serviced.

A channel goes through the following states:

  1. When a channel is first made active, it waits for its trigger to occur. If its trigger is "on demand" then not wait is done at this step.
  2. The channel remains active while conversion begins and proceed.
  3. When conversion is finished, the channel becomes inactive as well as the last channel active.

Readys16

int32 (*Readys16)(void *,const int16* buf);

This function prepares a buffer for high speed conversion if supported by the hardware. For an ADC, this sets up the specified buffer to automatically receive the specified number of samples in the Array on the enabled channels, while for a DAC it sets up the specified buffer as containing the values to automatically convert to analog outputs. After the buffer has been set up the hardware is set up to activate the first enabled channel and then automatically activate each subsequent channel in turn as soon as the previous one de-activates, looping back around to the first enabled channel after the last enabled channel has de-activated as long as more samples remain.

For some hardware it may be necessary to match which Readys function is called to the size of the samples expected by the hardware. For example, a 16-bit A/D that supports DMA may require that Readys16 be called because it transfers 16-bit values. Or, it might require 32-bit values even though it takes 16-bit samples. Check for any notes for your hardware to determine if this is the case.

Returns a positive value on success. This indicates that the given buffer has been accepted for queuing.

A negative return value indicates failure. Possible failures include:

  • the specified buffer is already (still) in use. (note: you must deliberately try to provoke this error to determine if a previously requested conversion is completed)
  • the hardware has a limited amount of space for queuing and cannot accept an additional buffer at this time
  • the buffer passed does not conform to hardware requirements, such as alignment
  • the hardware does not support buffer queueing. it is still possible to call Gets or Puts as appropriate but those functions will block until the requested buffer is filled or used up.

Any previous conversion in progress caused by Ready will be finished or cancelled (depending on hardware capabilities) before this request is serviced.

A channel goes through the following states:

  1. When a channel is first made active, it waits for its trigger to occur. If its trigger is "on demand" then not wait is done at this step.
  2. The channel remains active while conversion begins and proceed.
  3. When conversion is finished, the channel becomes inactive as well as the last channel active.

Readys32

int32 (*Readys32)(void *,const int32* buf);

This function prepares a buffer for high speed conversion if supported by the hardware. For an ADC, this sets up the specified buffer to automatically receive the specified number of samples in the Array on the enabled channels, while for a DAC it sets up the specified buffer as containing the values to automatically convert to analog outputs. After the buffer has been set up the hardware is set up to activate the first enabled channel and then automatically activate each subsequent channel in turn as soon as the previous one de-activates, looping back around to the first enabled channel after the last enabled channel has de-activated as long as more samples remain.

For some hardware it may be necessary to match which Readys function is called to the size of the samples expected by the hardware. For example, a 16-bit A/D that supports DMA may require that Readys16 be called because it transfers 16-bit values. Or, it might require 32-bit values even though it takes 16-bit samples. Check for any notes for your hardware to determine if this is the case.

Returns a positive value on success. This indicates that the given buffer has been accepted for queuing.

A negative return value indicates failure. Possible failures include:

  • the specified buffer is already (still) in use. (note: you must deliberately try to provoke this error to determine if a previously requested conversion is completed)
  • the hardware has a limited amount of space for queuing and cannot accept an additional buffer at this time
  • the buffer passed does not conform to hardware requirements, such as alignment
  • the hardware does not support buffer queueing. it is still possible to call Gets or Puts as appropriate but those functions will block until the requested buffer is filled or used up.

Any previous conversion in progress caused by Ready will be finished or cancelled (depending on hardware capabilities) before this request is serviced.

A channel goes through the following states:

  1. When a channel is first made active, it waits for its trigger to occur. If its trigger is "on demand" then not wait is done at this step.
  2. The channel remains active while conversion begins and proceed.
  3. When conversion is finished, the channel becomes inactive as well as the last channel active.

Examples: Coming Soon!

EDIO

EDIO Functions
Name Number
Lock 0
Unlock 1
Preempt 2
QueryFunction 3
PWM 4
QueryPWM 5
PWMfd 6
QueryPWMfd 7
QuadratureCount 8
EdgeCount 9
Glitched 10
HBridge 11

Initialization:

EDIO *EDIOInit(int instance);

Lock

int32 (*Lock)(void *,uint32 num,int32 flags);


Unlock

int32 (*Unlock)(void *,uint32 num,int32 flags);


Preempt

int32 (*Preempt)(void *);

tsctlEDIOPreemptDesc Coming Soon!

Examples: Coming Soon!

QueryFunction

int32* (*QueryFunction)(void *,EDIOType type);

Return a list of top-level logical DIO numbers which support the specified EDIO function type. The type parameter must be one of the following:

typedef enum EDIOType {
  EDIO_PWM=1,
  EDIO_QUADRATURE=2,
  EDIO_EDGECOUNT=3,
  EDIO_GLITCHED=4
} EDIOType;

Examples: Coming Soon!

PWM

int32 (*PWM)(void *,int32 num,uint32 periodHigh,uint32 periodLow);

Set the given DIO to begin producing PWM of the specified parameters on the given DIO num. The periodHigh and periodLow are specified in nanoseconds. If the specific DIO does not support the specified high/low period, priority will be given to setting a duty cycle as close to that implied by periodHigh / (periodHigh + periodLow), using the closest supported frequency.

Examples: Coming Soon!

QueryPWM

int32 (*QueryPWM)(void *,int32 num,uint32 periodHigh[1],uint32 periodLow[1]);

Returns the PWM high and low period for the specified DIO.

Returns a positive value on success, or a negative error code if the specified DIO number cannot do PWM.

Examples: Coming Soon!

PWMfd

int32 (*PWMfd)(void *,int32 num,uint32 freq,uint32 DC);

Set the given DIO to begin producing PWM of the specified parameters on the given DIO num. The mfreq parameter gives the frequency in milliHertz and the uDC parameter gives the duty cycle in millionths of a percent.

If the specific DIO does not support the specified frequency and duty cycle, the closest available frequency and duty cycle will be used.

Examples: Coming Soon!

QueryPWMfd

int32 (*QueryPWMfd)(void *,int32 num,uint32 freq[1],uint32 DC[1]);

Returns the PWM frequency in milliHertz and duty cycle in millionths of a percent.

Returns a positive value on success, or a negative error code if the specified DIO number cannot do PWM.

Examples: Coming Soon!

QuadratureCount

int32 (*QuadratureCount)(void *,int32 num);

Returns the quadrature count on the specific DIO.

Since quadrature actually requires two DIOs, there is always a secondary implied DIO on which the other part of the quadrature takes place. The user is responsible for looking up which DIO this is in the manual, as this API does not provide it.

The counter may be reset after this call.

Examples: Coming Soon!

EdgeCount

uint32 (*EdgeCount)(void *,int32 num,int32 edge);

This function returns the current value of the specified edge counter for pin number num. If edge is positive, then the value of the positive edge counter is returned. Ifedge is negative, then the value of the negative edge counter is returned. If edge is zero, then the value returned will be the sum of the positive and negative edge counters.

The edge counters always start at zero on power-up and increment until they reach the maximum possible value, at which point on the next edge they roll back over to zero. The maximum possible value for each counter is hardware dependant.

The return value is a 64-bit unsigned integer. This is sufficient to count at 1Ghz for over 584 years before roll-over occurs. However, not all hardware will support this size counter natively. Adapter objects in libtsctl will internally poll the edge counters in order to keep a 64-bit total counter, however these will have the limitation of missing edges if the input signal is changing too fast. How fast is too fast will depend on hardware counter side and to some extent CPU loading.

A value of zero will always be returned if the specified edge counter is not supported by the hardware for the given pin.

Examples: Coming Soon!

Glitched

int32 (*Glitched)(void *,int32 num);

Returns true if the given DIO glitched since the last call to this function.

Examples: Coming Soon!

HBridge

int32 (*HBridge)(void *,int32 num,HBState state);

Sets the H-Bridge functionality of the specified pin num to the given state. The possible states are:

  • HB_LEFT : positive voltage is applied on the specified pin, with negative (or ground) on the auxiliary pin associated with this pin.
  • HB_RIGHT : positive voltage is applied on the auxiliary pin associated with the specified pin, with negative (or ground) on the specified pin itself.
  • HB_FREE_RUNNING : no voltage is applied across either pin
  • HB_BRAKING : both pins are connected to the same rail

Returns a negative error code if the specified pin cannot be used as an H-Bridge, or if the specified state is unsupported on this pin.

typedef enum HBState {
  HB_LEFT=1,HB_RIGHT=2,HB_FREE_RUNNING=3,HB_BRAKING=4
} HBState;

Examples: Coming Soon!