pySoftcheck is a Python script for easy automatic communication with the serial interfaces that the 
Pilot ONE supports (serial interface, Ethernet, ModbusTCP and USB Port).
The module script.py is the script that can be changed by the user.
Note: This module has been written for python 3.6.

The following script demonstrates the basic capabilities.

'''
Created on 28.10.2013

@author: jo
'''
from softcheck.logic import Com

def script():

	#Serial Interface
    #create a new com object and specify interface and timeout
    com = Com("serial", 2.1)
    com.open(0, 9600)

    for i in range(20):
        com.send("Ti?\r\n")
        com.check("TI ")
    com.close()

	#USB Interface (under Linux)
    #create a new com object and specify interface and timeout
    com = Com("serial", 2.1)
    com.open('/dev/ttyACM0', 9600)

    for i in range(20):
        com.send("Ti?\r\n")
        com.check("TI ")
    com.close()

    #Ethernet
    #create a new com object and specify interface and timeout
    com = Com("ethernet", 2)
    com.open("192.168.0.126", 8101)

    for i in range(20):
        com.send("Ti?\r\n")
        com.check("TI ")
    com.close()
    
    #ModbusTCP
    #create a new com object and specify interface and timeout
    com = Com("modbustcp", 2.1)
    com.open("192.168.0.126, 502) #open ethernet port 502          
    com.send_bytes(bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x41]))
    com.check_bytes(bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x41]))    
    com.close()

script()


The programm can be executed under Windows like this:
python path_to_pySoftcheck\script.py

under Linux:
./script.py
oder
path_to_pySoftcheck/script.py

In the standard configuration the program will complain about an error. 

---------------------------------------------------
API:
---------------------------------------------------

Com object:
Namespace: from softcheck.logic import Com
To construct a new Com class - which is used for communication with the device - the following arguments are needed:
Ethernet:          Com("ethernet", TIMEOUT)
ModbusTCP:		   Com("modbustcp", TIMEOUT)
Serial interface:  Com("serial", TIMEOUT)
Example: com = Com("serial", 2.1)
As 3rd parameter the verbosity level can be given. "1" means that the program explains what goes wrong in case of an error. "2" means that the sent and received strings will be printed and "3" prints the time information for each command also. 
4th parameter: When set to True (default), the program throws an exception in case of an error, otherwise the program goes on.   

open:
opens the chosen interface. 
Ethernet/ModbusTCP: The first parameter us the IP address, the second one the port.
Serial interface: The first parameter is the port number (0 for COM1), the second one the baud rate
Example: com.open("192.169.253.1", 8101) # open Ethernet socket
Example2: com.open("192.169.253.1", 502) # open ModbusTCP socket
Example3: com.open(0, 9600) #opens Com1 with 9600 Baud 
Example4: com.open('/dev/ttyACM0', 9600) # open ACM driver

send:
Sends a command to the interface. CR and LF have to be noted also
Example: send("TI? /r/n")

send_bytes:
(for ModbusTCP usage)
Sends a bytearray to the interface
Example: send_bytes(bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x41]))

check:
checks the start of the message received from the interface. 
Example: check("TI ")
Example2: check("[S01G")

check_bytes:
(for ModbusTCP usage) 
checks if the received bytearray from the interface matches the expected bytearray 
Example: check_bytes(bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x41]))

check_regex:
Checks the answer received from the interface. Regular Expressions can be used here. For easier work with regular Expressions it is advisable to use an "r" in Front of the Expression. Attention should be payed also to the notation: When there are characters like '[' in the command (LAI), they must be escaped: "\["
Example: check_regex("TI ")
Example2: check_regex("\[S01G")

close:
The chosen interface is closed.
Example: com.close()

recv:
Receives the answer from the interface.
This command is helpful when the answer from the interface should be processed further. No check takes place.
Example: str = com.recv()

recv_bytes:
(for ModbusTCP usage)
Recveis the answer from the interface as a bytearray
This command is helpful when the answer from the interface should be processed further. No check takes place.
Example: ba = com.recv_bytes()

get_runtime:
Returns the runtime of the last command that has been received. The runtime is the time of a command send till echo (if there is an echo).  
Example: runtime = com.get_runtime()

get_max_runtime:
Returns the maximum runtime of all the commands that has been send and received.   
Example: max_runtime = com.get_max_runtime()

get_min_runtime:
Returns the minimum runtime of all the commands that has been send and received.   
Example: min_runtime = com.get_min_runtime()

get_avg_runtime:
Returns the average runtime of all the commands that has been send and received.   
Example: avg_runtime = com.get_avg_runtime()

get_nr_cmds_sent:
Returns the number of commands sent since the initialization of the Com object
Example: nr_commands = com.get_nr_cmds_sent()

get_nr_answers:
Returns the number of answers received since the initialization of the Com object
Example: nr_answers = com.get_nr_answers()

get_nr_timeouts:
Returns the number of timeouts occurred since the initialization of the Com object
Example: nr_timeouts = com.get_nr_timeouts()

get_std_deviation:
Returns the standard deviation from the runtime
Example: std_dev = com.get_std_deviation()

--------------

ComStore object:
Namespace: from softcheck.logic import ComStore
With this object data traces can be stored in a file.
Example:
comstore = ComStore(filename + ".txt")    
com.send("TI?\r\n")
com.store_string(comstore, "TI?\r\n")
com.store_answer(comstore)        

store_string:
This command saves a arbitrary string in a file maintained by the ComStore object. 
com.store_string(comstore, "TI?\r\n")

store_answer:
This command saves the answer from a device in a file maintained by the ComStore object.
com.store_answer(comstore)

--------------

PbCom object:
Namespace: from softcheck.pb_commands import PbCom
To construct a new PbCom class - which is used for communication with PB commands with the device - the following arguments are needed:
Example: pb = PbCom(com)
Example2: pb = PbCom(com)
The 1st parameter must be a configured Com object.
As 2nd parameter the verbosity level can be given. "1" means that the program explains what goes wrong in case of an error. "2" means that the sent and received strings will be printed and "3" prints the time information for each command also. 
3rd parameter: When set to True (default), the program throws an exception in case of an error, otherwise the program goes on.   

int2hexstr:
converts the value of an pb command to a hex string.
The first argument is the number, the second gives the number of bytes used for transformation
Return value is the hex string.
pb.int2hexstr(number, 16) 

check:
checks if the value of a pb command is like expected
The first argument is the value of the command to check, the second the value of the PB command expected.
Return value True if check is o.k. 
pb.check(30, 1)

check_range:
checks if the value of the pb command is within the range expected
The first argument is the value of the command to check, the second the minimum and the third the maximum value.
Return value True if check is o.k.
pb.check_range(30, 0, 32767)

send:
sends a pb command with a certain value
The first argument is the PB command to send, the second one the value.
pb.send(30, 5)

request:
Requests the value of a command. The function only sends a request to the remote.
As argument the command number must be given.
pb.request(30)

request_echo:
sends a request command and waits for the answer from the remote.
As argument the command number must be given.
pb.request_echo(30)

get_bit:
gets the value of a given bit position in a command value (sends request command and extracts information).
The argument is the command number
Return value is the value of the bit position 
get_bit(10, 12)

set_bit:
sets a bit to 1 on a given bit position (and sends the command)
First argument is the command number, the second one is the bit position
Return value is the value of the bit position that has been set
set_bit(10, 12)

clear_bit:
clears a bit to 0 on a given bit position (and sends the command)
The argument is the command number
Return value is the value of the bit position 
clear_bit(10, 12)

--------------

PpCom object:
Namespace: from softcheck.pp_commands import PpCom
To construct a new PpCom class - which is used for communication with PP commands with the device - the following arguments are needed:
Example: pp = PpCom(com)
Example2: pp = PpCom(com)
The 1st parameter must be a configured Com object.
As 2nd parameter the verbosity level can be given. "1" means that the program explains what goes wrong in case of an error.  
3rd parameter: When set to True (default), the program throws an exception in case of an error, otherwise the program goes on.   

check:
checks if the value of a pp command is like expected
The first argument is the command to check, the second the value of the PP command expected.
Return value True if check is o.k. 
pp.check("SP", 2000)

check_range:
checks if the value of the pb command is within the range expected
The first argument the command to check, the second the minimum and the third the maximum value.
Return value True if check is o.k.
pp.check_range("TI", 1000, 1500)

send:
sends a pp command with a certain value
The first argument is the PP command to send, the second one the value.
pp.send("SP", 1500)

change_to:
changes the command given to the value given (sends the value to the Circulator and checks the answer for correctness)    
The first argument is the command string and the second the value to be set.
pp.change_to("SP", 2000):

request:
Requests the value of a command. The function only sends a request to the remote.
As argument the command string must be given.
pp.request("TI")

request_echo:
sends a request command and waits for the answer from the remote.
As argument the command string must be given.
pp.request_echo("TI")

--------------

LaiCom object:
Namespace: from softcheck.lai_commands import LaiCom
To construct a new LaiCom class - which is used for communication with Lai commands with the device - the following arguments are needed:
Example: lai = LaiCom(com, 1)
Example2: lai = LaiCom(com, 1)
The 1st parameter must be a configured Com object.
The 2nd parameter is the slave address that uses the Circulator 
As 3rd parameter the verbosity level can be given. "1" means that the program explains what goes wrong in case of an error.  
4th parameter: When set to True (default), the program throws an exception in case of an error, otherwise the program goes on.   

int2hex:
converts a value to a LAI hex string (without 0x and leading zeros)
The 1st parameter is the value that is given (integer)
The 2nd parameter are the number of bytes the result should use
As return value one can get the hex string without leading 0x and leading zeros
lai.int2hex(1500, 2)

hex2int:
converts a LAI hex string (value) to an integer
The first parameter is the hex string that is to be converted to an int (e.g. received from peer)
If the second parameter is True the returned value will be signed (default), if False it will be unsigned
the return value is the int value of the given hex string
lai.hex2int("A012") # signed value
lai.hex2int("A012", False) # unsigned value

send:
sends a LAI command with a certain value
The first argument is the LAI command to send, the second one the value.
lai.send("G", "E0****")

check:
checks if the value of a LAI command is like expected
The first argument is the command to check, the second the value of the LAI command expected.
Return value True if check is o.k. 
lai.send("V")
lai.check("Pilot ONE-Trainee V1.0")

check_regex:
checks if the value of a LAI command is like expected
The first argument is the command to check, the second the regular expression of the LAI command expected.
Return value True if check is o.k. 
lai.send("G", "C0****")
# O: off, 0: no Alarm, tttt: setpoint, iiii: internal temp., dddd: external temp.
lai.check_regex(r"O0[0-9A-F]{4}[0-9A-F]{4}[0-9A-F]{4}")
    
check_hex:
checks if the hex value (string) of a lai command is like expected
The first argument is a hex value (part of the LAI command) to check, the second the int value to compare against the hex_string 
Return value True if check is o.k. 
self.lai.send("G", "C0****")
# O: off, 0: no Alarm, tttt: setpoint, iiii: internal temp., dddd: external temp.
self.lai.check_regex(r"O0[0-9A-F]{4}[0-9A-F]{4}[0-9A-F]{4}")
string = self.lai.get_last_value()
self.lai.check_hex(string[2:6], 1500)

check_hex_range:
checks if the hex value (string) of a lai command is in the range expected
The 1st argument is a hex value (part of the LAI command) to check
The 2nd parameter is the minimum value allowed and the 3rd parameter is the maximum value allowed 
Returns True if everything is o.k., False otherwise         
self.lai.send("G", "C0****")
# O: off, 0: no Alarm, tttt: setpoint, iiii: internal temp., dddd: external temp.
self.lai.check_regex(r"O0[0-9A-F]{4}[0-9A-F]{4}[0-9A-F]{4}")
string = self.lai.get_last_value()
self.lai.check_hex_range(string[6:10], 1000, 3000)

get_last_value:
Returns the last value received. This can be useful if one sends a string with "send", checks the received string with "check" and wants to use the answer further. 
see above

change_to:
Changes the command/value pair given and ensures that set correctly 
1st parameter is the command to be sent (send and check if really set)
2nd parameter is the value to be set
lai.change_to("I", slave_address)

request_echo:
Sends a request command and waits for the answer from the remote.
As argument the command string must be given.
string = lai.request_echo("L", "********")

--------------

MbTCPCommand object:
Namespace: from softcheck.mb_commands import MbTCPCommand
To construct a new MbTCPCommand class - which is used for ModbusTCP commands - the following arguments are needed:
The 1st parameter is the bytearray of user_data. This must be at least the modbus function code.
As 2nd parameter the unit identifier (1 byte) has to be set.
As 3rd parameter the transaction identifier (2 bytes) can be specified.
As 4th parameter the protocol identifier (2 bytes) can be specified. ModbusTCP needs 0x0000 for protocol identifier.
Example: mb_command = MbTCPCommand(bytearray([0x41]), 0xFF)

--------------

MbCom object:
Namespace: from softcheck.mb_commands import MbCom
To construct a new MbCom class - which is used for communication with Modbus commands with the device - the following arguments are needed:
The 1st parameter must be a configured Com object.
As 2nd parameter the protocol mode can be given. Only "tcp" is supported.
As 3rd parameter the the verbosity level can be given. "1" means that the program explains what goes wrong in case of an error. "2" means that the sent and received strings will be printed and "3" prints the time information for each command also. 
4th parameter: When set to True (default), the program throws an exception in case of an error, otherwise the program goes on.   
Example: mb = MbCom(com, "tcp")

request:
sends the MbTCPCommand object as a bytearray
Example: mb.request(MbTCPCommand(bytearray([0x41]), 0xFF)

requst_echo:
sends the MbTCPCommand object as a byte array and waits for the received MbTCPCommand
Example: recv_obj = mb.request_echo(MbTCPCommand(bytearray([0x41]), 0xFF))

check:
checks if two MbTCPCommand objects are equal
send_obj = MbTCPCommand(bytearray([0x41]), 0xFF)
recv_obj = MbTCPCommand(bytearray([0x41]), 0xFF)
Example: ret = mb.check(send_obj, recv_obj)

request_echo_check:
sends the MbTCPCommand object as a byte array and waits for the received MbTCPCommand
after that the received MbTCPCommand object is compared with the expected object
send_obj = MbTCPCommand(bytearray([0x41]), 0xFF)
expected_recv_obj = MbTCPCommand(bytearray([0x41]), 0xFF)
Example: ret = mb.request_echo_check(send_obj, expected_recv_obj)

--------------

MbFunc object:
Namespace: from softcheck.mb_commands import MbFunc
Class contains static methods specially for the huber defined modbus functions
