sl3 — Satlink 3 and XLink 500 API

This module provides the Application Programming Interface for Satlink 3 and XLink 500. It consists of functions that provide access to the embedded systems.

List of classes

Functions and classes

exception sl3.SetupError
class sl3.Log(count=None, match=None, oldest=None, newest=None, pos=1)

The Log class is used to access the log. It may be used to search the log, matching a log entry label. The search may be bound by specifiying an oldest and/or a newest time.

To access any of the log methods you must create an instance of the Log class:

>>> from sl3 import *
>>> l = Log()
>>> l.get_oldest()
04/04/2017,18:01:43,RS232 Connected,0,,G
>>> l.get_newer()
04/04/2017,18:01:43,Reset Soft,278,,G
>>> l.get_newer()
04/04/2017,18:01:44,Usb Drive Connected,0,,G

Notes:

  • most Log functions return an instance of the Reading class
  • the current position in the log is tracked on a per thread basis to prevent conflicts
  • it’s recommended to avoid creating a Log() instance in a global variable to avoid potential conflict with other threads.
Matching by label and time

If you want to match certain labels, you can pass it in as the match property; an oldest time or a newest time can be specified as well.

Retrieve the most recent Soft Reset event:

>>> from sl3 import Log
>>> Log(match='Reset Soft').get_newest()
05/09/2017,15:06:54,Reset Soft,115,,G

Retrieve the last Soft Reset event that occurred yesterday:

>>> t = localtime()
>>> # localtime() returns the current time in a tuple which is not-modifiable, but we can
>>> # convert it into a list and create a unique copy with the list() function:
>>> t1 = list(t)
>>> # subtract 1 from the day, and set the HH:MM:SS to 00:00:00
>>> t1[2:6] = (t1[2] - 1, 00, 00, 00)
>>> # use the list() function to make another unique copy of the current time:
>>> t2 = list(t)
>>> # subtract 1 from the day, and set the HH:MM:SS to 23:59:59
>>> t2[2:6] = (t2[2] - 1, 23, 59, 59)
>>> # create a Log() instance with the label we wish to match and the oldest time and newest 
>>> # time and call get__newest() to start searching for a match moving  backwards in time:
>>> Log(match='Reset Soft', oldest=mktime(t1), newest=mktime(t2)).get_newest()
05/08/2017,22:21:16,Reset Soft,115,,G

Retrieve the next earlier matching Soft Reset event:

>>> Log(match='Reset Soft', oldest=mktime(t1), newest=mktime(t2), pos=LOG_CURRENT).get_older()
05/08/2017,22:19:58,Reset Soft,114,,G

Or to be more efficient we can copy the Log() instance into a variable and then just re-use it:

>>> log = Log(match='Reset Soft', oldest=mktime(t1), newest=mktime(t2))
>>> log.get_older()
5/08/2017,22:11:54,Reset Soft,113,,G
>>> log.get_older()
05/08/2017,17:59:44,Reset Soft,112,,G
Iterating with the Log Class

If we want to manipulate a block of Log entries in Python, we can take advantage of the fact that the Log() class supports iteration. That means we can loop on it. Here’s an example that displays the last 2 soft resets that have occured:

>>> from sl3 import Log
>>> for reading in Log(2, "Reset Soft"):
...     print(reading)
05/08/2017,22:21:16,Reset Soft,115,,G
05/08/2017,22:19:58,Reset Soft,114,,G

It’s also possible to use a list comprehension to build a list of log readings and process them:

# print out the newest 10 stage readings in oldest to newest order
from sl3 import *
my_list = [r for r in Log(10, "stage")]
my_list.reverse()
for r in my_list:
    print(r)
Search limit

When searching for a matching label or time in the log, the Log class imposes a limit on the number if items that will be scanned called limit. This can be changed for all instances of the Log class or for just a specific instance. The default is just 1000 and that may not be sufficient if you want to search far back in the log. In this first example we will change that limit to one million for all future Log searches:

>>> from sl3 import Log
>>> Log.limit = 1000000
>>> for reading in Log(5, "Reset Soft"):
...     print(reading)
05/08/2017,22:21:16,Reset Soft,115,,G
05/08/2017,22:19:58,Reset Soft,114,,G
05/08/2017,22:11:54,Reset Soft,113,,G
05/08/2017,17:59:44,Reset Soft,112,,G
05/08/2017,16:12:37,Reset Soft,111,,G 

Alternatively, the limit can be changed just on an instance of the Log class, leaving the default limit of 1000 items in place:

>>> from sl3 import Log
>>> my_log = Log(5, "Reset Soft")
>>> my_log.limit = 1000000
>>> for reading in my_log:
...     print(reading)
05/08/2017,22:21:16,Reset Soft,115,,G
05/08/2017,22:19:58,Reset Soft,114,,G
05/08/2017,22:11:54,Reset Soft,113,,G
05/08/2017,17:59:44,Reset Soft,112,,G
05/08/2017,16:12:37,Reset Soft,111,,G 
__init__(count=None, match=None, oldest=None, newest=None, pos=1)

Creates an instance of the log class.

Parameters:
  • count – limit the number of log entries read
  • match – label value to match
  • oldest – match entries greater than or equal to this time
  • newest – match entries less or equal to this time
  • pos

    specify the start position in the log (defaults to LOG_NEWEST)

    Option Description
    LOG_CURRENT Does not change the position. Whenever the script is loaded (or reloaded), the position will pointed to the newest data in the log and set to retrieve newer data as it’s logged.
    LOG_NEWEST Log readings will be retrieved from the newest part of the log, moving towards older data.
    LOG_OLDEST Log readings will be retrieved from the oldest part of the log, moving towards the newer data.
get_newer()

Returns the next newer entry in the log

Return type:Reading
Raises:LogAccessError
get_newest()

Returns the newest entry in the log

Return type:Reading
Raises:LogAccessError
get_older()

Returns the previous older entry in the log

Return type:Reading
Raises:LogAccessError
get_oldest()

Returns the oldest entry in the log

Return type:Reading
Raises:LogAccessError
next()

Returns either the next newer or previous older entry depending on whichever direction was retrieved last. By default, the most recent entries that have been added to the log since the script started running is returned.

Return type:Reading
Raises:LogAccessError
count = None

number of Readings to iterate

limit = 1000

a limit on the number entries to search when looking for a match

match = None

a label to match

newest = None

a newest time to match

oldest = None

a oldest time to match

class sl3.Reading(time=0, label=’’, value=0.0, units=’’, quality=’G’, right_digits=2, etype=’M’)
This class is used to represent a log entry and a measurement result.
  • It is used when reading and writing to the log.
  • It is also used when getting the results of a measurement reading.

Here is a summary of the properties of a Reading and their default values:

Property Default Description
time 0 time is represented in seconds since 1970 as returned by utime.time()
label “” a name for the reading
value 0.0 the value of the reading
units “” the units of the reading (up to 3 characters)
quality “G” can be either ‘G’ for good or ‘B’ for bad
right_digits 0 the number of digits to the right of the decimal point to display
etype “M”

represents the type of reading:

  • ‘M’: a measurement
  • ‘E’: an event
  • ‘D’: a debug message
Notes
  • When a Reading is printed, the full contents are displayed using csv format:

    >>> from sl3 import *
    >>> from utime import time
    >>> r = Reading(time(), "stage", 5.2, "ft", "G")
    >>> print(r)
    08/14/2017,23:23:06,stage,5.20,ft,G
    
  • Readings may be concatenated with strings using the + and += operators:

    >>> from sl3 import *
    >>> from utime import time
    >>> output_format = "HEADER: "
    >>> r1 = Reading(value=4.3, quality='G', label='test', time=time())
    >>> output_format += r1
    >>> print(output_format)
    HEADER: 08/14/2017,23:37:43,test,4.30,,G
    
  • Two Reading’s may be compared for equality (or inequality):

     >>> from sl3 import *
     >>> from utime import time
    >>> r1 = Reading(value=4.3, quality='G', label='test', time=time())
    >>> r2 = Reading(value=4.3, quality='G', label='test', time=r1.time)
    >>> r1 == r2
    True
    >>> r1 != r2
    False
    
__init__(time=0, label=’’, value=0.0, units=’’, quality=’G’, right_digits=2, etype=’M’)

A Reading can be initialized with another Reading or a tuple, or fields. Here are some examples of differents ways a Reading can be constructed:

from sl3 import *
from utime import time

# Create a Reading by filling out the fields one by one:
r = Reading()
r.time = time()
r.value = -9.7
r.label = "at"
r.quality = 'G'
r.right_digits = 1
r.units = 'C' 

# Create a Reading by passing one or more of time, label, value, units, quality, right_digits,
# and entry type:
r = Reading(time(), "stage", 5.2, "ft", "G")

# Create a Reading by passing keyword arguments (order doesn't matter):
r = Reading(value=4.3, quality='G', label='test', time=time())

# Create a Reading by passing another reading:
r2 = Reading(r)

# Create a Reading by passing a tuple containing the properties
r = Reading((time(), "stage", 5.2, "ft", "G", 2, 'M'))
asctime()

Converts the time of the Reading into an ASCII string :return: the time in MM/DD/YYYY,HH:MM:SS :rtype: str

write_log(reading)

Writes the reading to the log:

reading = Reading(value=4.3, quality='G', label='test', time=time())
reading.write_log()
etype = ‘M’
Represents the type of reading
  • ‘M’: a measurement
  • ‘E’: an event
  • ‘D’: a debug message
label = ‘’

A name for the reading; a string up to 11 bytes

quality = ‘G’

A single byte indicating the quailty of the reading, with B indicating a bad value, and G indicating a good value

right_digits = 0

The number of right digits of the value to show

time = 0

Time is represented in seconds since 1970 as returned by utime.time()

units = ‘’

The units expressed as a string up to three bytes long

value = 0.0

The value of the reading, a float

class sl3.Serial_number

Provies the serial number of SL3, microboard, and transmitter board. Returned values are ASCII strings containig the serial number.

classmethod microboard()
classmethod sl3()
classmethod transmitter()
sl3.ascii_time(time_t)

Converts the provided time into an ASCII string:

>>> ascii_time(utime.localtime())
'07/03/2017,21:40:57'
Parameters:time_t

two options:

time as a float number of seconds since 1970, just like utime.time()

time as a tuple, as per utime.localtime()

Returns:the time in MM/DD/YYYY,HH:MM:SS
Return type:str
sl3.ascii_time_hms(time_t)

Converts the provided time into an ASCII string HH:MM:SS:

>>> ascii_time_hms(utime.localtime())
'21:40:57'
Parameters:time_t

two options:

time as a float number of seconds since 1970, just like utime.time()

time as a tuple, as per utime.localtime()

Returns:the time in HH:MM:SS
Return type:str
sl3.batt()

Measures Satlink’s supply voltage :return: battery voltage :rtype: float

sl3.bin6(num, count=3, right_digits=0, is_signed=True)

Converts a number in to a count byte long 6-bit packed binary string (used for GOES formatting). The maximum number of bytes is 3, which allows a representation range of [-131072 .. 131071]. The more right_digits you request, the smaller the range. For instance with 2 right_digits, the the maximum range becomes limited to [-1310.72 .. 1310.71], and even less with fewer bytes.

Examples:

>>> import sl3
>>> # Convert 12345 to 6-bit pseudo-binary:
>>> sl3.bin6(12345)
b'C@Y'
>>> # Convert BV in to a 3-byte 18-bit value:
>>> BV = 12.32
>>> sl3.bin6(BV, 3, 2)
b'@SP'
Parameters:
  • num (float) – A number to convert to pseudo-binary format.
  • count (int) – The number of bytes to format (1 to 3).
  • right_digits (int) – The number of decimal digits to retain via scaling.
  • is_signed (bool) – True if negative values should be allowed.
Returns:

A byte string containing 6-bit binary data.

Return type:

bytes

sl3.bin_to_str(num, count)

Converts a number in to a (count) byte long binary string. For example, bin(65,1) would return b’A’. If the number is a floating point number, then count must be either 4 or 8 to have the number stored in IEEE 32 bit or 64 bit single or double precisions respectively. If the count is not 4 or 8 (or -4 or -8), then the number is treated as an integer. The sign of count determines the byte order. When count is positive, the most significant byte is stored first (Compatible with ARGOS 8-bit binary formats). When count is negative, the least significant byte is stored first.

Example:

>>> import sl3
>>> sl3.bin_to_str(1094861636, 4)
b'ABCD'
Parameters:
  • num (int,float) – Integer or float number to be converted to byte string
  • count (int) – Number of bytes to converted num to. Byte count must be large enough to hold the number passed in.
Returns:

Returns binary string representation of the number passed in.

Return type:

bytes

sl3.bit_convert(string, type)

Converts a binary string of specific format tye into a number. This is the opposite of bin function. The following types are supported:

Type string contents
1 4 byte integer, least significant byte (LSB) first
2 4 byte integer, most significant byte (MSB) first
3 IEEE 754 32 bit float, least significant byte (LSB) first
4 IEEE 754 32 bit float, most significant byte (MSB) first
5 IEEE 754 64 bit float, least significant byte (LSB) first
6 IEEE 754 64 bit float, most significant byte (MSB) first

Example:

>>> import sl3
>>> sl3.bit_convert(b'DCBA', 1)
1094861636
>>> sl3.bit_convert(b'@\x9c\xcc\xcd', 4)
4.9
Parameters:
  • string (bytes) – A string of bytes to be converted to a number.
  • type (int) – See above table for valid options.
Returns:

Returns the integer or float value representing the byte string passed in.

Return type:

int or float

sl3.bytes_to_str(b)

MicroPython does not support the latin1 character set, but this is equivalent to str(s, ‘latin1’) which converts a string to bytes without regard to unicode encoding

sl3.clear_stats()

Clears Satlink’s counters, including transmission counts, reset counts, and more

sl3.command_line(command, buf_size=512)

Issue commands to Satlink’s command line.

Parameters:
  • command (str) – command line function to execute, e.g. “Hello” “M1 LAST”
  • buf_size (int) – size of buffer for reply
Returns:

command line reply

Return type:

str

sl3.crc(data, polynomial, initial_value=0, reflect=False, invert=False, reverse=False)

Computes the CRC-16 over data The following web site contains a lot of details on different CRC implementations, those details compromise the variables passed in to the crc function:

Example:

>>> from sl3 import *
>>> hex(crc("123456789", 0x1021))
'0x31c3'
Parameters:
  • data (str) – A str or bytes to compute a CRC across.
  • polynomial (int) – A 16-bit number that varies based on the type of CRC and determines how the CRC operates.
  • initial_value (int) – The intial value for the generator, typically 0, or 0xffff.
  • reflect (bool) – There are two common versions of the CRC-16 algorithm, one that works by shifting the polynomial value left on each operation (normal), and one that works by shifting the reflected polynomial value right on each operation.
  • invert (bool) – True to invert the result. Some variations require this.
  • reverse (bool) – True to reverse the final byte order. Some variations require this.
Returns:

The computed 16-bit CRC value

Return type:

int

sl3.crc_dnp(data)

Computes the DNP CRC over data

Parameters:data (str) – A str or bytes to compute a CRC across.
Returns:The computed 16-bit CRC value
Return type:int
sl3.crc_kermit(data)

Computes the Kermit CRC-CCITT over data

Parameters:data (str) – A str or bytes to compute a CRC across.
Returns:The computed 16-bit CRC value
Return type:int
sl3.crc_modbus(data)

Computes the ModBus CRC-16 over data

Parameters:data (str) – A str or bytes to compute a CRC across.
Returns:The computed 16-bit CRC value
Return type:int
sl3.crc_ssp(data)

Computes the SSP CRC-16 over data

Parameters:data (str) – A str or bytes to compute a CRC across.
Returns:The computed 16-bit CRC value
Return type:int
sl3.crc_xmodem(data)

Computes the Xmodem CRC-CCITT over data

Parameters:data (str) – A str or bytes to compute a CRC across.
Returns:The computed 16-bit CRC value
Return type:int
sl3.digital_input_sample(port)

Samples one of the digital input lines. Requires API ver 0.3

Parameters:port – which input to sample, string. options are ‘DIN1’, ‘DIN2’
Returns:Boolean indicating whether the digital input is active
sl3.get_api_version()

The version of the API.

Returns:API version
Return type:float
sl3.index()

Returns the index of the calling measurement or transmission or script task. For example, if a script hooked into measurement M7 were to call this function, it would return 7. If not called from a meas/tx/task, routine returns 1.

Returns:index of caller
Return type:int
sl3.internal_temp()

Measures Satlink’s internal temperature sensor :return: temperature in Celsius :rtype: float

sl3.is_being_tested()

Tells you whether the function is being called as a part of a test operation.

Returns:If a Python function is being tested by the customer, the value is True. If the function was invoked by Satlink as a part of normal operation, the value is False.
Return type:bool
sl3.is_clock_updated()

For Satlink environmental satellite transmissions only, this value is true if the clock has been updated since the last transmission. May only be used by custom formatting TXFORMAT routines

Returns:True if there has been a GPS synce since the previous transmission
Return type:bool
sl3.is_meas_valid()

Only usable by @MEASUREMENT scripts. This routine tells you if the measurement is valid. A measurement may be invalid in cases of bad setup, errors in communication with digital sensors, or other reasons.

Returns:True if current measurement is valid
Return type:bool
sl3.is_scheduled()

Tells you whether the calling measurement/transmission/script task was scheduled.

Returns:True if scheduled.s
Return type:bool
sl3.lock()

lock() and unlock() may be used to protect global variables from being corrupted by code designed to be run by multiple tasks at the same time. They do this by allowing only one task to proceed past the lock() statement at a time. Consider Example 1 where a global variable is decremented. Without the lock, two tasks could interfere with each other and prevent the global variable from being decremented correctly. Similarly a section of code can be protected, such that only one task can enter that code at a time. If you need to protect a section of code that’s more substantial than some quick operations, consider using _thread.allocate_lock() to create a unique lock variable instead, and reserve lock()/unlock() for the quick sections.

Example 1 - Simple lock/unlock:

from sl3 import lock, unlock
global my_global
lock()
my_global = my_global - 1
unlock()

Example 2 - Exception safe lock/unlock:

from sl3 import lock, unlock
# use try-finally to make sure the global lock is always released
# even if an exception occurs:
try:
    lock()
    call_my_function()
finally:
    unlock()

Example 3 - Exception safe using GLOBAL_LOCK:

# try-finally is a little cumbersome, here's a simpler way to protect a section of code
# in an exception-safe way:
from sl3 import GLOBAL_LOCK
with GLOBAL_LOCK:
    call_my_function()

Example 4 - Custom lock:

# in cases where long sections of code must be protected, it's possible to introduce 
# custom locks to avoid holding up code which use lock()/unlock():
import _thread
MY_LOCK = _thread.allocate_lock()
#
@MEASUREMENT
def shared_measurement(num):
    with MY_LOCK:
        return my_function(num)
sl3.meas_as_index(meas_index_or_label)

Routine converts provided parameter to a measurement index as an integer

Parameters:meas_index_or_label (int or string) – either the index or the label of the meas. 1 or ‘Sense1’
Returns:measurement index
Return type:int
sl3.meas_as_reading(value)

Only usable by @MEASUREMENT scripts. Returns current measurement as a Reading class

Parameters:value – the current sensor reading as a float
Returns:the current measurement as a Reading class
sl3.meas_do_not_log()

Only usable by @MEASUREMENT scripts. Once script returns, the measurement reading will NOT be logged, no matter the measurement setup. Please note this happens once script returns, not when this function is called.

sl3.meas_find_index(meas_label)

Tells you the index of the measurement

Parameters:meas_label (string) – the customer set label for the measurement
Returns:measurement index if a match is found. zero if no match is found
Return type:int
sl3.meas_find_label(meas_index)

Returns the customer set Label of the measurement.

sl3.meas_log_this()

Only usable by @MEASUREMENT scripts. Once script returns, the measurement reading will be logged, no matter the measurement setup. Please note this happens once script returns, not when this function is called.

sl3.meas_make_invalid()

Only usable by @MEASUREMENT scripts. Call to make said measurement result invalid. An invalid result is marked as bad in the log, and its value is overwritten with the setup “Log Error Value”, which defaults to -999.9

sl3.meas_make_valid()

Only usable by @MEASUREMENT scripts. Call to make said measurement result valid. Valid measurements are marked as good in the log.

sl3.measure(meas_identifier, meas_action=2)

Used to access sensor results via Measurements. Requires that the measurement be setup. Usage examples:

>>> measure(2)
08/03/1987,19:42:56,AT,28.5,C,G
>>> measure(2).value
28.5
>>> measure('AT').value
28.5

>>> r2 = measure(2)
>>> r2.value
28.0
>>> r2.value += 5
>>> r2.value
33.0
>>> r2.write_log()
>>> Log().get_newest()
08/03/1987,19:45:58,AT,33.0,C,G
Parameters:
  • meas_identifier

    either the measurement index as an int, or the meas label as a str

    index is 1 based, e.g. 4 for M4.

    the label is the customer set label for the meas, e.g. “Sense01” or “AT”

  • meas_action
    One of the available constants indicating what action to take. Options:
    const:READING_LAST The reading produced when measurement was last made. Does not start a new measurement.
    const:READING_LAST_SCHED Like last, but returns the last scheduled (as opposed to live/forced reading).
    const:READING_MEAS_SYNC Picks up the last reading synchronized to the schedule. Avoids extraneous readings. If the caller is scheduled for 12:15, this will use the measurement reading made at 12:15, waiting if need be. If system is not running, it will make a new measurement
    const:READING_MEAS_FORCE Initiates a new measurement every time
Returns:

The result of the sensor measurements

Return type:

Reading

sl3.output_control(port, turn_on)

Drives the digital output lines

Parameters:
  • port – which output to drive, string. options are ‘OUTPUT1’, ‘OUTPUT2’
  • turn_on – whether to turn on or off the output, Boolean
sl3.output_sample(port)

Samples one of the output lines.

Parameters:port – which output to drive, string. options are ‘OUTPUT1’, ‘OUTPUT2’
Returns:Boolean indicating whether the output is on
sl3.power_control(port, turn_on)

Controls the various power output lines.

Parameters:
  • port – which port to drive, string: ‘SW1’, ‘SW2’, ‘PROT12’, ‘RS232’, ‘VREF’, ‘PREF’
  • turn_on – Boolean indicating whether to turn on (True) or turn off (False) the power output
sl3.power_sample(port)

Samples one of the various power output lines.

Parameters:port – which port to sample, string: ‘SW1’, ‘SW2’, ‘PROT12’, ‘RS232’, ‘VREF’, ‘PREF’
Returns:Boolean indicating whether the power output is on
sl3.reset_count()

Tells you how many times Satlink has reset

Returns:number of resets
Return type:integer
sl3.seconds_since_midnight()

returns the number of seconds that have elapsed since midnight as an integer

sl3.setup_read(parameter)

Read SL3 setup for specified parameter. Examples:

>>> From sl3 import *
>>> setup_read("station name")
"Sutron Satlink 3"
>>> setup_read("recording")
"On"
Parameters:parameter (str) – SL3 setup value to read
Returns:parameter value in SL3
Return type:str
sl3.setup_write(parameter, value)

Change setup for specified parameter. Nothing is returned if write is successful. A SetupError will be raised if write failed.

Examples:

>>> From sl3 import *
>>> setup_write("station name", "Little Creek")
>>> setup_write("M1 slope", 1.5)
Parameters:
  • parameter (str) – SL3 setup parameter to change.
  • value – Value to change the setup to. Can be str, bytes, float, int.
Returns:

Nothing is returned if successful. Raises SetupError if the write failed or the setup did not take on the exact value.

sl3.sgn(number)

Returns an integer indicating the sign of provided number

Parameters:number (integer) – number whose sign we are interested in
Returns:the sign of the number: 1 when above 0, returns 0 when 0, and returns –1 when negative
Return type:integer
sl3.sl3_hms_to_seconds(str_hms)

Convert a HH:MM:SS string to a number of seconds.

Parameters:str_hms (str) – time string HH:MM:SS
Returns:time in seconds
Return type:int
sl3.sl3_time_to_seconds(str_dt)

Convert a string to time.

Parameters:str_dt (str) – SL3 date and time string YYYY/MM/DD HH:MM:SS or HH:MM:SS MM/DD/YYYY
Returns:time in seconds since 1970, just like utime.time()
Return type:float
sl3.str_to_bytes(s)

MicroPython does not support the latin1 character set, but this is equivalent to bytes(s, ‘latin1’) which converts bytes to string keeping the bytes exactly as-is without regard to unicode encoding

sl3.time_scheduled()

Returns the time the calling measurement or transmission or script task was scheduled to run.

Returns:time in seconds since 1970, just like utime.time()
Return type:float
sl3.tls()

The tls() function returns a structure that may be used to store thread-local storage variables

In Python, when you create a global variable, every task, every custom format routine, and every measurement may access that variable. That can be useful when data must be shared, but sometimes separate storage is needed that is unique to the script task, formatter, or measurement That is what the tls() function provides.

Creating a value in thread local storage is done by assigning a name in tls a value:
tls().daily_rain = 100.0
Referencing a variable stored in thread local storage is just as simple:
tls().daily_rain = tls().daily_rain + hourly_rain

But how can we tell if a variable already exists so we can tell whether we need to initialize it? We can use hasattr(). The code below initializes daily rainfall:

if not hasattr(tls(), "daily_rain"):
    tls().daily_rain = 0.0

We can also use getattr() to retrieve a value regardless of whether one exists in tls(). The code below will retrieve a value for slope if one has been stored in tls(), otherwise use 1.0:”:

slope = getattr(tls(), "slope", 1.0)

Finally, tls is not limited to simple values. Any data-type that can be assigned to a variable may be stored including strings, lists, and other objects.

sl3.trigger_meas(meas_index)

Initiates a live reading of said measurement. Does not wait for measurement to complete.

Parameters:meas_index – measurement index int, 1 to 32. Use 0 to trigger all measurement.
Returns:None
sl3.trigger_script_task(task_index)

Initiates said script task. Does not wait for completion.

Parameters:task_index – Script task index int, 1 to 8. Use 0 to trigger all tasks.
Returns:None
sl3.trigger_tx(tx_index)

Initiates a transmission. Does not wait for transmission to complete.

Parameters:tx_index – Index of transmission. You may not trigger all transmissions by passing in 0.
Returns:None
sl3.unlock()

lock() and unlock() are typically used together to protect global variables.

sl3.ver()

Tells the Satlink software version:

>>> ver()
[8, 10, 2578]
Returns:major, minor, and revision
Return type:tuple
sl3.ver_boot()

Tells the Satlink bootloader software version:

>>> ver_boot()
[8, 10, 0]
Returns:major, minor, and revision. revision is always 0 for bootloader
Return type:tuple
sl3.wait_for(device, pattern)

Wait for a pattern of bytes to be received over a communications device

Parameters:
  • device (Serial) – Any Serial, File, or Stream object with a read() method.
  • pattern (str) – A string to look for in the input stream of the device.
Returns:

True if a match was found or False if a timeout occured.

Return type:

bool

patterns::
  • a “?” in the pattern will match any single character
  • a “*” will match anything (ie “A*G” would match “ABCDEFG”)
  • control characters may be embedded with “^” (ie “^C” would match a ctrl-c)
  • special characters may also be embedded with “” (ie “ÿ” would match a 255 ascii)
  • any of the special codes may be matched by escaping with a “” (ex: “*”) wait_for is written to accept either byte or string oriented devices and patterns