COMPORT COMMANDER
www.comportcommander.com
(c) 2019 by Ross Mernyk


INTRO

If you're designing or using a device that talks RS232 or RS485 you need CC. Using very simple commands you put in a script file, you send and receive messages on multiple comports to test, exercise, and control your devices.



SCREEN CAPTURES



For more screen captures click here .



FEATURES


OVERVIEW

CC is a free program released for Windows, Apple, and Linux. It runs a simple script file for communicating on 1-8 comports simultaneously. The script file is a flat ascii text file which you create in any text editor, like notepad.

The scripting language is very simple yet powerful. CC is designed for automated testing of devices, software validation of embedded processors, and exercising electro-mechanical equipment.

In its simplest use, you use CC to send a series of commands to a device. Using the SEND command, you send a message to any comport. Using the LOOP or LIST commands, you execute any series of commands multiple times, and drop into those commands a series of values.

Using the RECV command, CC can verify responses from a device. For example you can send a series of commands to setup a device, and verify each response from the device is exactly as expected.

CC includes a versatile checksum facility, allowing you to define almost any checksum algorithm using just 10 parameters. You can define up to 26 checksum algorithms in the script. Thereafter you merely refer to the selected checksum algorithm when you use a SENDC or RECVC command, and CC does all the work.

Using multiple ports and a digital i/o pod, CC can fully verify electro-mechanical device operation. For example you can SEND a command to your motorized device on comport A to move to a certain position, then DELAY a few seconds, then SEND a query to your i/o pod on comport B to ask which electric eye sensor detects the position of your device.

Exact expected replies are handled with the RECV command. Varying replies (like from a distance sensor, or from an analog i/o pod) are handled using the CAPT command to capture the reply, then the PARSE command to convert the varying values into variables. You can use the MATH command to process those variables if needed, and the SKIP command to verify the range of those variables.

CC provides 52 general purpose integer variables (A-Z and a-z) with the range -2B to +2B. The LOOP and LIST commands set any variable iteratively. The MATH command can executes an RPN stack machine to set any variable from a formula of other variables. And any variable can be dropped into any command or message, in ascii decimal, ascii hex, or binary, with zero fill or variable width.

CC provides 10K labels, which are used as targets for the GOTO and CALL commands. Coupled with the conditional SKIP command (which can test any combination of variables and constants), this provides conditional branching to your CC script.

CC provides fault tolerant execution (if you activate it), to prevent errors in all receive and parse commands from causing script abort (instead CC increments a variable). This allows you to exercise a device or system, and compile error statistics.

The script file size is unlimited, and each line can have up to 1000 characters. Indentation and spacing is unrestricted. Comments are allowed on any line, or alone, and blank lines are permitted.



EXAMPLE SCRIPTS

Note I have made up an absurd message structure for illustration only.


; script 1
; send device group 75 to position 0 then 50 then 100
 
port A 9600 0 ; open port A at 9600 baud
send A >go,grp=75,pos=0\r ; send devices to position 0
delay 10   ; delay 10 sec
send A >go,grp=75,pos=50\r ; send devices to position 50
delay 10   ; delay 10 sec
send A >go,grp=75,pos=100\r ; send devices to position 100
 
 
; script 2
; perform script one 100 times
 
port A 9600 0  
loop N 1 100 1 ; loop var N from 1 to 100
send A >go,grp=75,pos=0\r  
delay 10    
send A >go,grp=75,pos=50\r  
delay 10    
send A >go,grp=75,pos=100\r  
delay 10    
loopend N   ; end of loop N
 
 
; script 3
; perform script one 100 times each for groups 75,113,119,205,206
; note "\V1G" in the strings means drop in var G as decimal ascii of 1 or more chars
 
port A 9600 0  
list G 75 113 119 205 206 ; list var G for 75,113,119,205,206
loop N 1 100 1 ; loop var N from 1 to 100
send A >go,grp=\V1G,pos=0\r  
delay 10    
send A >go,grp=\V1G,pos=50\r  
delay 10    
send A >go,grp=\V1G,pos=100\r  
delay 10    
loopend N   ; end of loop N
listend G   ; end of list G
 
 
; script 4
; clear 50 config items in the device, using checksums on all messages
; note this chksum command means: chksum R does a simple sum of all bytes except
; the last one, and inserts two hex ascii chars just before the end of the message
 
chksum Ross   sum 0 1 0 0 255 %02X insert -1 2    
port A 9600 0  
loop I 1 50 1 ; loop for each item
sendc r A >write,item=\V1I,value=0\r ; set item I to value 0
recvc r   A 2 <value,item=\V1I,value=0\r   ; verify msg reply was good
loopend I   ; end of item loop



CONTACT

Comport Commander was written by Ross Mernyk, New York City USA
Email: ross at ComportCommander period RhymesWithMom
Phone: 646-522-4359

Program site:  www.comportcommander.com
Personal site: www.rossmernyk.com

Updated: 2019-07-07



INSTALLATION

CC is a small program (less than 1 MB), which operates in the JRE (Java Runtime Environment). You download the JRE (appx 60 MB) for free directly from Oracle, and install it. Then place CC wherever you want on your computer (no installation). CC requires JRE version 1.8.0 or later (which is called JRE 8).

DOCUMENTATION
Save the HTML file you are looking at, or view it online. If you want all 7 screen captures, save screens.html and cc-screen-01.jpg thru cc-screen-07.jpg, all in the main folder.

WINDOWS
ComportCommander-100.exe (SHA1 = 1748D480FB5911D192AF8615FFBE2A2413A9A895)

APPLE & LINUX
ComportCommander-100.jar (SHA1 = 616B60BD6D3CC885A633D257DE1C38FAD5A006B3)
ComportCommander-100.ico (SHA1 = 18C59AA5FADE36A4F3CF2D81674A6251937089CE)

WINDOWS & APPLE & LINUX
Download and install the most-recent JRE for free directly from Oracle here.

Apple note: I know very little about Apple computers. Let me know and I'll improve this paragraph. I understand the default Apple behavior for JAR files is to OPEN them rather than RUN them. You need to change some system setting, or maybe RIGHT-click to RUN the JAR.

Linux note 1: I know very little about Linux computers. Let me know and I'll improve this paragraph. There are MANY settings which need to be changed to run JAR files.

Linux note 2 (thank you Fazecast for this note): Serial port access is limited to certain users and groups in Linux. To enable user access, you must open a terminal and enter the following 4 commands to give CC access to the ports, for each user on your system. It's ok if some of the commands fail. Replace "username" with your own. To determine your username, type "whoami" in the terminal. If using SUSE 11.3 or higher, replace the "-a -G" flags below with just "-A". After making the changes, log out and log back in. You do this whole process only once.
sudo usermod -a -G uucp username
sudo usermod -a -G dialout username
sudo usermod -a -G lock username
sudo usermod -a -G tty username

CHANGES
1.00   Added ALIGN command.
  Added FAULTT command CLEAR option.
  Improved FAULTT handling in PARSE command.
  Continue button now cleans up backscroll before resuming.
0.07   Made labels into strings and allowed 10K of them.
  Made variables case sensitive so you get 52 of them.
  Added VARS command.
0.06   Added DELAYM command.
  Added BREAK command.
  Fixed CAPTC command bug which appeared when CAPTC was used iteratively.



HARDWARE INFO

CC operates 1-8 comports. UART-based comports, USB comports, comm boards, and bluetooth comports all work.

MOST testing can be done with a single comport, because many device protocols can coexist (on the same comport) with an i/o pod such as Advantech Adam. Thus a laptop with a single comport is usually enough to command an electro-mechanical device, verify its replies, and determine whether it moved appropriately.

Devices with button inputs can be actuated with solenoids and digital outputs (on an i/o pod). For firmware validation consider adapting i/o pod digital outputs electrically to your device's button inputs.

The Advantech Adam-4000 series is an inexpensive line of RS485 i/o pods. Multiple pods can share a single RS485 line. Consider these pods:

Adam-4017 - 8  channel analog input (isolated)
Adam-4018 - 8  channel thermocouple input (isolated)
Adam-4024 - 4  channel analog output (isolated)
Adam-4050 - 15 channel digital (8 output + 7 input)
Adam-4051 - 16 channel digital input (isolated)
Adam-4052 - 8  channel digital input (isolated)
Adam-4053 - 16 channel digital input
Adam-4055 - 16 channel digital (8 output + 8 input) (isolated)
Adam-4056 - 12 channel digital output (source or sink) (isolated)
Adam-4060 - 4  channel relay output (2 form A + 2 form C)
Adam-4068 - 8  channel relay output (4 form A + 4 form C)
Adam-4069 - 8  channel power relay output (4 form A + 4 form C)
Adam-4080 - 4  channel digital (2 output + 2 counter/frequency input)
Adam-4150 - 15 channel digital (8 output w/pulse + 7 input w/event)



SCRIPT FILE FORMAT

The script file is a flat ascii text file.
The filename can have any extension, but I prefer CCS (CC script).
Fields on each line are delimited by any combo of spaces and tabs.
Fields themselves never contain spaces or tabs.
Blank lines are permitted anywhere in the file.
If the comment char appears on a line, all chars after it are ignored.
A line may just contain a comment, and spaces and tabs may preceed it.
The first line of the file is line #1.
Lines may be up to 1000 chars long.

The first field on each line is a command.
Additional fields carry the command's arguments.
The command and all its arguments must be on the same line.
The command does not have to begin in column 1.
All commands and arguments in CC are case insensitive, however chars in send/recv strings are sent/received exactly as shown, and vars can be made case sensitive using the "vars 52" command.

Certain arguments appear in many commands, and are described here.
Arguments appearing in only one command are described with that command.

<var> any variable A-Z or a-z.
<port> any comport  A-H or a-h.
<lab> any label up to 32 chars long, 0-9 A-Z a-z and underscore permitted.
<string> may contain any ascii chars, but no spaces or tabs.
  may also contain escape sequences, described later.
<value> accepts any integer -2 billion thru +2 billion,
  or any <var> A-Z a-z (and uses its value), or "capt"
  which uses the number of chars that are in captbuf.
<timeout>   accepts any positive <value> as a timeout in seconds.
<calg> checksum algorithm A-Z a-z to employ with this command.

Delays and timeouts specified in seconds, provide AT LEAST the duration you specify, and at most add 200 msec to that duration.

All numeric arguments in all commands are decimal, except those in escape sequences in strings, which are always hex.



SCRIPT FILE COMMANDS

COMMUNICATE
 
port <port> <baudrate> <linedelay> <echo> <odd> <even> <stop2>
  opens or re-opens <port> at specified <baudrate>.
  any pending chars from <port> are discarded.
  sets delay (in msec) to use before sending each message to <port>.
  delays are inaccurate due to unavoidable computer design issues.
  <baudrate> and <linedelay> are <values>.
  optional arg "echo" tells CC that the comm hardware echos every
  char sent to port, so CC should swallow the echos. optional args
  "odd"/"even"/"stop2" activate those parameters for transmit only.
  for receive, CC always accepts odd/even/none parity, 1/2 stop bits.
 
send <port> <string>
sendc <calg> <port> <string>
  send string to port, optionally applying a chksum algorithm.
  <linedelay> applied (see PORT command).
 
recv <port> <timeout> <string>
recvc <calg> <port> <timeout> <string>
  receive string from port, optionally applying chksum algorithm.
  string must arrive exactly, within <timeout> seconds, else FAIL.
  once <string> arrives, proceed immediately.
  no other chars may arrive before <string> arrives.
  if chars arrive after <string>, leave them in input buffer.
 
scan <port> <timeout> <string>
scanc <calg> <port> <timeout> <string>
  scan all incoming chars from port for <string>, optionally
  applying chksum algorithm. <string> must arrive exactly,
  within <timeout> seconds, else FAIL. unlike the RECV cmds,
  other chars may arrive before <string> arrives, and they will
  be discarded until <string> arrives. once <string> arrives,
  proceed immediately. if chars arrive after <string>,
  leave them in input buffer.
 
capt <port> <timeout> etx <etx>
capt <port> <timeout> len <len>
capt <port> <timeout> elen <pos> <multdiv> <xor> <add> <and>
capt <port> <timeout> sdn
captc <calg> <port> <timeout> etx <etx>
captc <calg> <port> <timeout> len <len>
captc <calg> <port> <timeout> elen <pos> <multdiv> <xor> <add> <and>
captc <calg> <port> <timeout> sdn
  capture any message from <port>, optionally applying chksum algorithm.
  holds message in capt buf until next CAPT/CAPTC command, allowing for
  multiple PARSE commands to be applied to the same captured message.
  if using CAPTC, the msg chksum is verified but not retained in capt buf.
  all arguments except <port> and <calg> are <values>.
  if ender is "etx" (end of transmission), then <etx> specifies the
  ascii code of the etx character 0-255. if ender is "len" (length),
  then <len> specifies the number of bytes to receive 0-1000.
  if ender is "sdn" (Somfy Digital Network), then message length
  is taken from the second byte in the message.
  if ender is "elen" (embedded length), then <pos> specifies the position
  in the message where the length is found (first byte in msg is pos==1).
  <multdiv> is positive to multiply or negative to divide the embedded length.
  after <multdiv> is applied, the result is then xored by <xor>,
  then <add> is added, and the result is finally anded with <and>.
  note the ender "sdn" is shorthand for elen 2 1 31 0 31 .
 
chksum <name> <func> <start> <end> <xor> <add> <and> <fmt> <put> <where> <clen>
  this cmd defines a custom checksum algorithm. see the section below.
 
clear <port>
  discard all pending chars from <port> input buffer.
 
quiet <port>
  the port must have NO chars in its input buffer, else FAIL.
 
break <port> <tempbaud> <bytetosend>
  Send break signal. Note this is a kluge, so read the break signals section below.
  <tempbaud> is the temporary baudrate. <bytetosend> is the byte to send at that
  baudrate to create the break. both are <values>.
 
sendd <port> <string>
sendl <port> <string>
  send string to port, optionally preceeded by a string length byte.
  each byte from <string> is sent as ascii decimal (1-3 chars) preceeded
  by a dot. one \r is sent after all chars are complete.
  <linedelay> not applied. these 2 commands are for downloading tables.
 
CONTROL
 
delay <seconds>
delaym <milliseconds>
  delay seconds or milliseconds. <seconds> or <milliseconds> are <values>.
  arriving chars on all ports accumulate in their input buffers during the delay.
 
align <seconds>
  wait for time of day to be multiple of <seconds> past midnight.
  will not match present second to prevent multiple matches in same second.
  useful for logging data at even intervals (see SHOW ONLY and SHOW VARS commands).
  arriving chars on all ports accumulate in their input buffers while waiting.
 
pause allow
pause ignore
pause <timeout> <message>
  display <message> and wait up to <timeout> seconds for Continue
  button to be pressed. when <timeout> elapses, script processing
  continues (it is not a FAIL). set <timeout> to 0 to wait forever.
  <message> may be absent and may contain spaces.
  use PAUSE ignore and PAUSE allow, surrounding critical script fragments,
  to prevent pressing of the Pause button from causing a script timeout
  and thus script FAIL.
 
list <var> <value1> [ <value2> ] ...
listend <var>
  executes the lines between LIST and LISTEND, with <var> set to
  each <value> specified, in succession. up to 100 <values> allowed.
  lists and loops may be nested interchangeably, up to 26 levels deep.
 
loop <var> <first1> <last1> <step1> [ <first2> <last2> <step2> ] ...
loopend   <var>
  executes the lines between LOOP and LOOPEND, with <var> cycling
  through each loop specified. <var> will be set to <first1>,
  then <first1> + <step1>, and so on thru <last1>. after <var>
  has stepped past <last1>, the next triplet on the line is executed,
  and so on. up to 33 triplets can be specified in the LOOP command.
  <firstX> <lastX> <stepX> are all <values>, and may also be negative.
  lists and loops may be nested interchangeably, up to 26 levels deep.
 
skip     <value1> <cmp1> <value2> [ <andor> <value3> <cmp2> <value4> ] ...
skipn <n> <value1> <cmp1> <value2> [ <andor> <value3> <cmp2> <value4> ] ...
  compare a <value> with another <value>.
  <cmpX> can be one of: > >= < <= == !=
  if the comparison is true then skip the next 1 or <n> lines.
  <n> is a <value> 0 or greater. optional <andor> can be && or ||
  to chain up to 20 comparisons together.
  all && are evaluated before any || is evaluated.
  SKIPN is also handy to reduce label clutter.
 
label <lab>
goto <lab>
  jump to label.
  forward and backward references permitted.
  very powerful when used after SKIP command.
 
return  
call <lab>
  call label, and save return address. return to the
  saved address when return command is executed.
  forward and backward references permitted.
  very powerful when used after SKIP command.
  call/return can be nested up to 26 levels deep.
 
exit <message>
  exit the script.
  message may be absent and may contain spaces.
  very powerful when used after SKIP command.
 
beep  
  makes an audible beep from your computer
 
MISC
 
vars 26
vars 52
  causes variables after this command to be case insensitive (26) or case sensitive (52),
  giving you 26 or 52 variables to work with. default when CC starts is 26, thus Q and q
  are the same variable. using "vars 52" makes Q and q different variables.
 
faultt off
faultt <var>
faultt clear <seconds>
  causes RECV/RECVC/SCAN/SCANC/CAPT/CAPTC/PARSE/QUIET commands to be
  fault tolerant. instead of terminating the script, CC increments <var>.
  the fault tolerance applies to communication, not syntax and usage.
  you may tally certain errors or all errors. you may tally all errors
  to one var, or different errors to different vars. using "clear" causes
  all future trapped faults, after incrementing, to delay <seconds> then
  clear that port's input buffer. set <seconds> to 0 to stop clearing.
 
parse <pstring>
  parses the capt buf. see parse string section below.
 
match <var> <ormask> <string>
  compare <string> against keep buf. if they differ, proceed
  without error. if they match then do: <var> |= <ormask>.
  this is useful when a device may send several messages
  in an unpredictable order. <ormask> is a <value>.
 
math <oper> <oper> ...
  performs math operations like an RPN stack machine.
  all math is performed with long signed integers (-2B to +2B).
  no error checking. stack is unchanged between MATH commands.
  stack is 26 levels deep. operators are described later.
 
set <var> <value>
set captbuf <string>
  this command is for script development and debug.
  setting <var> to <value> can be done in a math command,
  but SET is more convenient. set capt buf to a <string>
  to help you develop PARSE commands in your script.
 
unset <var>
  release var for reuse. needed if you break out of a list/loop,
  so you can re-use the var in that or another list/loop.
  unset also removes vars from the trace output (screen & file).
 
comment <newchar>
  change the comment char from this point forward in the script file.
  <newchar> can be numeric 0-255 or any single character. CC default is semicolon.
 
show only
show auxbuf
show binbuf
show captbuf
show keepbuf
show string <string>
show chksum <calg>
show vars   <var> ...
  these cmds are for script development, debug, and selected output.
  show string - to help you develop var escape sequences (<string> expanded into binbuf)
  show chksum - to help you develop custom chksums (chksum <calg> applied to binbuf)
  show capt/keep bufs - to help you develop PARSE commands.
  show aux/bin bufs - to inspect most-recent SEND/RECV command messages.
  show only - to henceforth limit the output file to only show cmds.
  show vars - to show the values of a list of vars, handy to produce data to
  later import into excel, best used after "show only" and "align" commands.



VARIABLES

CC provides variables A-Z and a-z.
By default they are case insensitive, so you have 26 variables to use.
The "vars 52" command makes them case sensitive, giving you 52 variables to use.

Each variable is a 4-byte long integer.
Each variable can hold any integer value, -2 billion thru +2 billion.
Their main use is in lists and loops.
Using variable escape sequences, you can use the value of a variable in a SEND or RECV string.

Variables are also useful to receive input that varies. For example, you may want to receive a 2-byte value from a device, and verify it is between 1000 and 1050. Use CAPT or CAPTC to capture the message. Use PARSE to verify the message structure, to extract the two bytes, and to assemble them into one var. If needed use MATH to modify the var or combine it with others. Use SKIP to range-check the result, and conditionally skip the next script line. Use EXIT on that line.



STRINGS

Strings may contain any ascii chars, but no spaces or tabs.
Ascii chars are sent/received exactly as shown (case is respected).

Strings may also contain simple escape sequences:
\r  means a carriage return character (ascii 13)
\n  means a newline character (ascii 10)
\s  means a space character (ascii 32)
\00 thru \FF means a single byte (specified as 2 hex chars)

Strings may also contain variable escape sequences in the form: \WFV
W specifies what part of the variable is sent/received
        L means byte 0 (low byte)
        H means byte 1 (high byte)
        U means byte 2 (upper byte)
        X means byte 3 (extra byte)
        V means the entire variable
F specifies the format for sending/receiving
        1-9 mean a signed decimal ascii string with
                minimum 1-9 chars, zero filled if needed
        A-H mean an unsigned hex ascii string with minimum
                1-8 chars, zero filled if needed
        X means a single binary byte
        Z means put ".0" into the string <var> times,
                the chosen part of <var> must be 0-500.
V specifies the variable letter A-Z or a-z

Simple example:
ab\scd\41ef\r --> "ab cdAef\r"

Variable example:
given variable J has value hex 12345678 = decimal 305419896
note hex values 12/34/56/78 equal decimal values 18/52/86/120
abc\L1Jdef\U5Jghi\V2Jjk --> "abc120def00052ghi305419896jk"
abc\HCJdef\UAJghi\VAJjk --> "abc056def34ghi12345678jk"
abc\UXJdef --> "abc4def"



PARSE STRINGS

Parse strings (PSs) are only used in the PARSE command, and allow you to inspect the capt buf which you captured using a CAPT/CAPTC command. PSs also allow you to convert any area of the capt buf into a variable, so you can test its range.

PSs support ALL characters and escape sequences (ESs) which are permitted in send/recv strings. As CC is evaluating your PS, all chars and ESs in your PS are verified to be in the capt buf, else FAIL. PSs may also contain parsing escape sequences (PESs) which are listed below. PESs position the capt buf ptr, and convert areas of the capt buf into vars.

At the start of each PARSE command, the capt buf ptr points at the first char in capt buf (pos=1), and the keep buf is cleared. The capt buf persists until the next CAPT/CAPTC command, so you can run several PARSE commands on the same captured message.

\>H     means move ptr right H chars (H can be 0-9 A-Z here)
\<H     means move ptr left H chars (H can be 0-9 A-Z here)
\(      means move ptr to first char in capt buf
\)      means move ptr to just after last char in capt buf

\?HH    means move ptr to just after the next ascii HH char
\~HH    means move ptr to just after previous ascii HH char
\.      means move ptr to just after the next dot char
\,      means move ptr to just after the next comma char

\%      means move ptr to next decimal char (0-9)
\&      means move ptr to next hex char (0-9 A-F)
\_      means move ptr to next whitespace char (space tab)
\*      means move ptr to next stx char (> + ? * # ! $ @)

\[      begin keeping into keep buf at present ptr
\]      end keeping into keep buf just before present ptr
\@A     add the character A to the keep buf

\$WFV   means convert and store a var which begins at present ptr.
        afterward ptr points at char just after converted chars.
        conversion ends after F chars, or at first non-convertible char.
        W specifies what part of var is stored
                L means byte 0 (low byte)
                H means byte 1 (high byte)
                U means byte 2 (upper byte)
                X means byte 3 (extra byte)
                V means the entire variable
        F specifies the format for conversion
                1-9 mean a signed decimal ascii string with
                        maximum 1-9 chars, zero/space/tab filled
                A-H mean an unsigned hex ascii string with
                        maximum 1-8 chars, zero/space/tab filled
                X means a single binary byte
        V specifies the variable letter A-Z or a-z

The PESs which search for a single char \? \~ \. \, may match the capt buf char at the present position, and always leave the ptr pointing just right of the matched char.

The PESs which search for a type of char \% \& \_ \* may match the capt buf char at the present position, and always leave the ptr pointing at the matched char.

Error checking is performed on all movement PESs, but NOT performed on numeric conversions. Thus if you try to convert from a decimal ascii value "q123" in the capt buf, you simply get 0 because "q" is the first non-convertible character. If you try to convert from hex ascii "FFWEST" you get 255.



MATH COMMAND

CC includes a powerful math facility, which performs math operations like an RPN stack machine. The stack is 26 levels deep, and is unchanged between MATH commands. All math is with long signed integers, thus 7/2 = 3, and 75/80 = 0. No error checking is performed.

The math operators are evaluated left to right as they occur in the MATH command. As each operator is encountered, CC immediately performs the operation. If a constant or variable is encountered, the value is pushed onto the top of the stack. If an operator is encountered, its action is performed.

Unary operators modify the value on the top of stack. They do not change the stack depth. Binary operators pop the 2 operands off the stack, then push the result onto the stack.

OPERATORS

The list below describes how each math operator works. The left column shows the operator itself. The expression in the right column describes the action performed by the operator, but does NOT describe the syntax you would use in CC.

"top" means top of stack.
"ben" means value just beneath top of stack.
"res" means result.

V       push var V onto stack
N       push signed decimal integer value N onto stack
add     res = ben + top
sub     res = ben - top
mult    res = ben * top
div     res = ben / top
mod     res = ben modulo top
and     res = ben & top
or      res = ben | top
xor     res = ben ^ top
shl     res = ben << top
shr     res = ben >> top
shra    res = ben >> top (bit 31 unchanged)
sgnext  res = ben sign extended from bit top-1
min     res = min (ben, top)
max     res = max (ben, top)
abs     top = abs (top)
neg     top = -top
com     top = ~top
low     top = (top & 0x000000FF)
high    top = (top & 0x0000FF00) >> 8
upper   top = (top & 0x00FF0000) >> 16
extra   top = (top & 0xFF000000) >> 24
push    push duplicate of top onto stack
pop     discard top of stack
swap    swap top of stack with item just beneath it
sto     store top to var shown just BEFORE the sto operator
capt    push how many chars in capt buf onto stack
time    push time of day in seconds (0-86399) onto stack
tick    push time CC has been running (200 msec ticks) onto stack
rand15  push a random number 0-32767      (2^15-1) onto stack
rand31  push a random number 0-2147483647 (2^31-1) onto stack
rand    push a random number 0-2147483647 (2^31-1) onto stack
seedn   seed random number generator from top
seedt   seed random number generator from system time

EXAMPLES

given var A is 65 or 66, set I to 64 or 128:
math A 64 sub 64 mult I sto

given a 12 bit adc reading, which was captured then parsed into var A,
convert A from unsigned (0 to 4095) to signed (-2048 to +2047).
value was 11 bits plus sign bit:
math A 12 sgnext A sto

set vars A B C from bits 0 1 2 of var P:
math P 1 and A sto P 1 shr 1 and B sto P 2 shr 1 and C sto



CHECKSUMS

CC provides a powerful versatile custom checksumming system. You describe a chksum algorithm using the CHKSUM command. You refer to that algorithm as one letter A-Z in the <calg> item of the SENDC/RECVC/SCANC/CAPTC commands. CC adds the chksum to outgoing messages, and verifies and removes the chksum from incoming messages. CC does the tedious work for you. The CHKSUM command has the form:

chksum <name> <func> <start> <end> <xor> <add> <and> <fmt> <put> <where> <clen>

<name> = To keep your CHKSUM algorithms organized, CC allows you to name them. The first letter of <name> is used as <calg> in SENDC/RECVC/SCANC/CAPTC commands.

<func> = sum, sumc, sumn, xor, crc32, poly
sum    = sum the selected bytes of the msg
sumc   = sum the ones complements of the selected bytes of the msg
sumn   = sum the negatives of the selected bytes of the msg
xor    = xor the selected bytes of the msg
crc32  = perform standard 32-bit communications crc on the selected bytes
poly   = any <value> used for <func> means "compute 16-bit crc with this polynomial"
         thus for the typical crc16 based upon 0x1081 set <func> to "4225"

<start>/<end> = specify number of bytes to exclude (do not sum them) at start/end of msg

<xor>/<add>/<and> = after summing we apply these 3 <values>, in order, to the sum. note you can negate a value by complementing it (xor with -1) and then incrementing it (add 1).

<fmt> = any java formatter string
most chksum algorithms use %d for 1 or more chars of decimal ascii, %02X for 2 hex ascii chars with zero fill, or %c to output a single binary byte 0-255. to specify a particular sum byte rather than the entire sum, just after the "%" insert a 2$ for low byte only, 3$ for high byte only, 4$ for upper byte only, or 5$ for extra byte only. any chars before the "%" or after the d or X or c, are included as is. <fmt> can include multiple % formatters.

<put> = how to put the chksum into the msg
use "replace" if the bytes are always present in the msg and are NOT removed upon reception. use "insert" to prepend/insert/append the chksum into the msg.

<where> = where to put the chksum in the msg
+1 thru +999 is position measured from start of msg (first byte is +1).
-1 thru -999 is position measured from end of msg (last byte is -1).
use +1 to prepend the chksum to the msg, use 0 to append the chksum to the msg.

<clen> = chksum length
this argument is used only in CAPTC cmd, for removal of chksum from the captured msg. use 1-16 to specify the fixed length of the chksum in bytes. use "dec" or "hex" to specify variable length chksum, where first char is anything, and remaining chars (if any) are ascii decimal or hex chars. if <put> is "replace", then no chars are removed regardless of <fmt>. if <put> is "insert" and <where> is positive, then CC knows where the chksum begins, and CC finds the end by including all following consecutive ascii dec/hex chars. if <put> is "insert" and <where> is negative or zero, then CC knows where the chksum ends, and CC finds the beginning by walking backward, including all preceeding consecutive ascii dec/hex chars, and including the first non-numeric char it encounters.

EXAMPLES

chksum Adam sum 0 1 0 0 255 %02X insert -1 2

Advantech Adam checksums are "00" thru "FF" and are inserted just before the \r at the end of most messages. When using SENDC/RECVC/SCANC/CAPTC, omit the 2 char chksum from your string, but include the \r. CC will insert the chksum to your string before sending/receiving.

chksum Opto22 sum 1 1 0 0 255 %02X insert -1 2

Opto22 checksums are identical to Advantech Adam chksums, except Opto22 does not include the first char in it's sum. When using SENDC/RECVC/SCANC/CAPTC, omit the 2 char chksum from your string, but include the \r. CC will insert the chksum to your string before sending/receiving.

chksum Somfy sum 0 0 0 0 65535 %3$c%2$c insert 0 2

Somfy checksums are binary and are appended to the msg. When using SENDC/RECVC/SCANC/CAPTC, omit the 2 byte chksum from your string. CC will append the chksum to your string before sending/receiving.

CAPTURE

To use the CAPTC command to capture Adam or Opto22 messages, use the form:
captc <calg> <port> <timeout> etx 13
This tells CC to capture all bytes until and including a \r, then verify and remove the Adam or Opto22 checksum from what was captured.

To use the CAPTC command to capture Somfy messages, use one of the forms:
captc s <port> <timeout> sdn
captc s <port> <timeout> elen 2 1 31 0 31
Either of these tells CC to capture all bytes of the msg, whose length is the ones complement of the lowest 5 bits of the 2nd byte of the msg, then verify and remove the chksum from the tail of what was captured.



ONE-WAY SENSOR DEVICES

If you have a talk-only sensor device, it will generally send you a message periodically, for example every second. Let's say that sensor reports device position in millimeters (0 thru 10000) in a simple text form like "+0\r" thru "+10000\r". Let's also say it takes several seconds for your device to move its position. Now you have a programming problem. You can't STAY aligned to the sensor because it takes your device 5-10 seconds to move, and you can't just discard old chars from the sensor and then read it, because you MAY chop a msg in half.

The way to handle this message alignment problem is the two CAPT commands in this script:

port A 9600 0 ; port A talks to your device
port B 9600 0 ; port B listens to the sensor
send A >go,pos=100\r ; tell your device to go to position 100
delay 10   ; delay 10 sec for your device to move
clear   B   ; discard all pending chars from sensor
capt B 2   etx 13 ; capt and ignore FIRST msg or fragment
capt B 2 etx 13 ; capt NEW msg, which will be complete
parse   +\$V9P\r ; see below
skip   P >= 500 && P <= 525   ; see below
exit    ; see below

The parse string verifies the leading "+" is present. The PES "\$V9P" means convert and store an ascii decimal string up to 9 chars long to var P. After the conversion, the capt pointer is just after the numbers, and the parse string verifies the trailing \r is where it belongs, without stray characters. The SKIP command range checks P, and if P is good skips the EXIT command.



VARYING INPUT

In many cases, you can verify operation of your electro-mechanical device using a digital input pod, and a few electric eyes. In such testing scenarios, you would send a command to your device to move to a certain position, and a piece of opaque tape attached to your device would break a beam when your device arrived. Your script would delay after sending the move command, then read the digital inputs, which should return a specific pattern, indicating your device is where you expect it to be, and nowhere else.

But sometimes your device operation cannot be verified by a digital position. Perhaps you need to read an analog sensor reporting your device's position in millimeters, or its temperature in degrees. And perhaps a range of values is acceptable. To process varying values like this, your script cannot use the RECV command, but must use the CAPT and PARSE commands.

For example lets say you have a 6-input analog input pod or sensor, on port B, and it returns 6 values in one message of ascii. Consider the message form:
<status,123,45,6789,0,0,17\r
which may be returned from the sensor, and consider the value of interest to you is the 6789 in the middle.

You would use SEND to ask for the status of the 6 inputs:
send B >read\r

You would use CAPT to capture the status msg reply into the capt buf:
capt B 2 etx 13

You would use PARSE to verify as much as possible of the received msg, and to absorb the item of interest into a variable (we will use P).
parse <status,\,\,\$V9P,\,\,

If you want to verify even more of the message, you could convert all 6 values from the message into variables, which assures every value is clean ascii decimal, discarding the 5 values of no interest by sending them each into the same variable (we will use X).
parse <status,\$V9X,\$V9X,\$V9P,\$V9X,\$V9X,\$V9X\r

Finally, to pass/fail the result we use SKIP and EXIT commands:
skip P >= 6500 && P <= 7000
exit



RANDOM NUMBERS

CC contains a pseudo-random number generator accessible through the MATH command using operators: RAND,RAND15,RAND31,SEEDN,SEEDT. The generator is seeded from the system time every time you press the Run button. The sequence generated has periodicity 2^48.

The RAND15 operator returns a random value 0-32767      (2^15-1)
The RAND31 operator returns a random value 0-2147483647 (2^31-1)
The RAND   operator returns a random value 0-2147483647 (2^31-1)

The SEEDN  operator seeds the generator from the top of the math stack.
The SEEDT  operator seeds the generator from the system time.

To set variable R to a random value 0-255 use cmd:
math rand 256 mod R sto

To set variable R to a random value -10 to +10 use cmd:
math rand 21 mod 10 sub R sto

To set variable R to a random value -10 to +10 except 0 use cmd:
math rand 10 mod 1 add rand 2 mod 2 mult 1 sub mult R sto

To generate a random sequence you can RECREATE later, use the SEEDN operator (which seeds the generator from the top of the math stack). For example, let's say your device has 50 configuration items, each of which is a number 0-99. And you want to verify that your device properly saves those numbers.

We would start by generating a random number, seeding the generator from it, and saving it in a variable (we will use R). Then in a loop we set all 50 config items, each item 1-100. Note I have made up an absurd message structure for illustration only. Next we reset our device, re-seed the generator from the same value, then in a loop we read back all 50 values verifying each was as we originally set it.

math   rand seedn R sto ; random seed to RNG and var R
 
loop I 1 50 1 ; loop for each item
math   rand 100 mod 1 add V sto ; set V to random number 1-100
send A >write,item=\V1I,value=\V1V\r ; set item I to random value V
recv A 2 <value,item=\V1I,value=\V1V\r ; verify msg reply was good
loopend I   ; end of item loop
 
delay 2   ; delay 2 sec for config to write
send A >reset\r ; reset device
delay 10   ; delay 10 sec while device resets
clear A   ; discard any reply or reset msg
 
math   R seedn ; re-seed RNG to old seed
 
loop I 1 50 1 ; loop for each item
math   rand 100 mod 1 add V sto ; set V to random number 1-100
send A <read,item=\V1I\r ; read item I
recv A 2   <value,item=\V1I,value=\V1V\r   ; verify msg reply is correct
loopend   I   ; end of item loop

The above approach can be used repeatedly inside your script, by using CALL/RETURN or by enclosing it inside an outer loop. Though random values do not thoroughly test your device's ability to set and get config items, if executed 10-20 times each time you run your script, it is very likely any bugs will be exposed. In the above example, if a bug is found the R variable enables you to re-create the same random sequence, to verify the bug is fixed.



BREAK SIGNALS

Break signals are generally 12+ bits of continuous active line. At present the comm library used by CC does not support break signal generation. So CC kluges this feature by sending a byte at a slower baudrate. Unfortunately the library delays 200 msec when changing baudrates, causing a 200 msec gap and blind spot before the break, and another one after the break. Note the 200 msec delay is present on Windows systems. I have not measured the delay on Apple or Linux systems.

If you need to send a break with tighter timing and no blind spots, do NOT use the BREAK command. Instead, simply use the SEND command, with an additional comport wired in parallel to the main port, and leave that port at a slower baudrate than the main port. If using RS485, just wire the additional port in parallel. If using RS232, use 2 diodes and a resistor, coupling the transmit lines.

To calculate the temporary baudrate and byte to send, note RS232 has the LSB travel first, and 0 bits are active like the start bit. So to send a 12-bit break signal at baudrate X, send 6 bits active at baudrate X/2, which is the start bit plus 5 LSBs, so send byte 0xE0. Also note you can't halve 57600 baud, but 12 bits at 57600 baud equals 8 bits at 38400 baud (send a 0x80).