CR inteRFACEWARE Help Center
Post
Home > Translator as ASTM TCP Glient (Sender) >
Translator as ASTM TCP Client
Sender)
This post was originally written for Iguana 5 so it uses version 5 screenshots,
and may contain out of date references.
Sending ASTM messages using Translator is not much different fram sending
HLT messages. For this purpose we will use well known lip module from the
tools repo, and rename it and modify to match ASTM protocol particulars and
exclude LLP specific elements,
This Example Dependencies
In order to test this project, it requires to run active ASTM TCP Server
(Listener) and Iguana Webserver to do HTTP POST of ASTM messages to
Iguana.
Data presentation
‘Suggested example will read initial ASTM message data from file (... or from
"Sample Data’ when working in Translator IDE.) Depending on type of fle
system, the end-of-line can be or or combination of both,
Our testdata can be seen below; and one can note that in this data the end-of-
line is Ox0A character (AKA ‘\n' or ,)
]wse STH 1a
a)aneneres) | |DOR-SeRK m) }20121292/m)| 1) °RORIaNE-ZH || 1) 1)
9)3) apeparearoe|| “-ama\**-x\-**c1\"+Ac02\"**mPop) a) | 12345066
sees)" rsm\ “PEAY R||20422231134500) | ||) || 12) 1 am
212)
jaan ein ono
Thus in module main we will examine and normalize input ASTM message
frames; calculate and concatenate respective checksum digits; and pipe result
to sending module.
Because data itself includes numerous control characters, it could optionally be
saved as binary file instead of text.
If data had instead of this would make our example more simple,
but let's see below how to handle non-standard terminator.
Frames must be surrounded by leading STX and trailing ETX, or ETB. This
sample ‘ASTM Sender’ has no way to know if frame has to be terminated with
ETX or ETB unless it has boon promptly specified in data itself.Translator as ASTM TCP Client
For impatient complete ASTM_sender_To_Translator zip project is available for
download.
Modules
We call four modules.
1. The astm_send module handles ASTM specific protocol to send a
message
2. The astn_top module handles TCP communications
3. The astmutil module contains functions to calculate checksum digits,
write debug logs, and send HTTP POST request to Iguana Webserver
4. The stringutil module contains few string manipulation functions
Module Dependencies
Modules don't ‘require’ external to Iguana Lua modules.
Configuration
Three places which will require custom configuration:
1, Please remember to adjust TCP host and port values in function main()
to match host and port of ASTM TCP Server that ASTM messages will
be sent to,
2. The webserver access credential in function astmutil,postJson () in
module astmutil may have to be adjusted as well,
3. The function calculating checksum digits may have to be adjusted to
match specific interface design. In this example Checksum calculation
is defined for not ‘i’ delimiters. Checksum is also defined to exclude
, but to include either , or . In another environment
it potentially can be different. Then algorithm in function
astmutilchecksum() in module astmutil has to be adjusted
Main moduleuw
2.
B.
ua.
.
1.
20.
a.
2.
23.
24
25.
26
ar
28
29
30
31.
32.
33.
34.
35.
36.
38.
39.
40.
require( 'astn_send')
require( ‘stringutit’)
require( ‘astmutit')
-- Data (frames) must be enclosed in leading STX and trailing ETX, or ETB.
-- ‘ASTM Sender’ has no way to know if frame has to be terminated with ETX
++ or £T8 unless it has been promptly specified in data itself.
function main(Data)
Local data = bata:split('\992")
table. renove(data, 1)
for i=
stata do
data[i} :trimRNL()
data[i}="\o02". .data{i)
end
data = addchecksun(data)
Vocal Success, err = astm_send, send(
data,
"192.168.5.4", -- host
6559, => port
18, -- timeout
true) ++ live
if not Success then
iguana. logError(err)
end
end
function addchecksum(data)
vidata do
Vocal é = datalil:
Local ckeastmutil .checksum(d)
Gatalil=d..ck..'\r"
end
for
return data
end
Modules code
‘The astm_send module.
1
require(‘asta_tcp')
Local function astm_initiator(param)4
5 Vocal detrl=(5,4} -- flow control ENQ and EOT values, respectively
6. Vocal gs
7 Local inconversation=false
8
Local tep = asta_tep.connect(host=param[2] ,port=param(3] ,timeout=paran[4},Livesparam(5])
10
uw Local function sendit(d)
2. if type(d) == ‘string’ then
B iguana. logdebug (‘sending *. .d)
rT tep:send(d)
be else
16. tep:send(string.char(d)..'\n')
uw. end
1B.
1. if d == detrt(2] then
20. return
au. end
2.
23. while true do
2a. Vocal s = tepzrecv()
25. gs=s
26. if gs then
2. return gs
28 end
28
30. end
31 end
2
3 gs = sendit(detrt{1])
34 iguana. Logdebug (‘sent EN signal’)
35.
36. if not inconversation and string. byte(gs)
iguana. Logdebug (‘received ASTM ACK")
gsenit
38. inconversation=true
40. end
al.
42. if not inconversation and string. byte(9s)
43, iguana. LogDebug (‘received ASTM NACK")
4a, gs-nit
45. end
46,
a7 Local repeats
48.
49 Local function repeatsends(d)
50 repeats=repeats-1
su gsesendit(a)
82 if string.byte(gs) == 6 then
53. iguana. logdebug (‘received ASTM ACK")5a.
55.
56.
57.
58
59
60.
61
62.
63
64
6.
66.
67.
68.
69.
70.
n.
rR.
2.
ma.
3.
76.
7.
78
79.
89
a1
82,
83.
84
85.
89.
90.
al.
92.
return
elseif repeats > 9 then
iguana. logDebug (‘received ASTM NACK")
repeatsends(d)
else
if repeats == 6 then
iguana. logError(' failed to transmit frame "'..d.."
end
return
end
end
Local function sendpayload()
for k,v in ipairs(paran(1]) do
repeats = 5
repeatsends(param(1}(k)..'\n')
end
end
if inconversation then
sendpayload()
gs = sendit(dctrU(2])
iguana. logdebug (‘sent EOT signal")
elseif not inconversation then
iguana. logError('remote not accepting’) -- some repeat logic could be nice to have.
return
end
tep:close()
end
~ public
astm_send = {)
function asta_send. send (data, Host Port, Timeout ,Live)
Success, err = pcall (astm_initiator, (data,Host Port, Timeout Live})
return Success, err
end
The asim_top module,
Here we expose 2 single function, connect(), that opens
-+ an astm_tcp connection to a remote host, and returns a
-+ to interact with.
+ When debugging, it actually returns a fake connection,
which can be sent ASTM messages, and
)=> replies with ACKs (one ACK per message sent)
If you want to test a real astmtcp connection in the e
pass Livestrue along with your connection settings
=- require('astm_tcp')
local s = astm_tcp. connect {host=" frink', port=8086)
sisend(Data)
~ local Ack
+ siclese()
srecv()
_astm_tep = (
send_astn_tep = function(s, msg)
Vocal sent, text = 0, ms9
repeat
sent = sent + s:send(text, sent+1)
until sent >= text:Len()
return sent
recv_astn_tcp = function(s, buf)
buf=s:reev()
return buf
end;
real_meta = {
index = {
send = function(selt, msg)
return _astm_tcp-send_astm_tcp(self.s, msg)
end;
recy = function(selt)
local msg, skipped
sg = _astn_tep.recv_astm_tep(selt.s, self.bu
turn msg
close = function(self)
self
end
selose()
-- Metatable for Simulation
simulation_neta = (
index = (
send = function(self, msg)
if not self-connected then
error(*not connected’, 2)58.
59.
69.
61.
62.
63
64
65.
66
67
68.
69.
70.
n
R.
2.
m.
5.
76.
7.
78.
79.
80.
Bi.
82
83
84
85,
86
87
88.
89.
90.
gL.
92.
93.
94,
95.
96.
97.
98,
99.
108
11
102
103
104
105
106
107.
end
self.sent = msg
return msg:ten()
end;
recy = function(self)
if not self-connected then
error(‘not connected’, 2)
elseif not self.sent then
error('timeout', 2)
else
Local got = '\906' -- ASTM flow control ACK
self.sent = nil
return got
end
close = function(self)
self. connected = false
end
++ Error Checking
check_arg = function(args, k, t, optional)
Vocal help = [[Connect to a remote astm_tcp host
Takes a table with the following required entries:
"host - the hostnane of the renote site
"port! - the port on the renote site
and optionally these entries
‘timeout’ - maximum wait time, in seconds (default 5s)
‘Live’ - create Live astm_tcp connections in the edit:
1086)
e.g. local s = astm_tcp.connect{hos'
fend(Data)
Local Ack = s:recv()
jostname' , por
selose()
if not args then
error(help, 3)
elseif type(args)
error( ‘Parameter 1 is not a table.\n'..help, 3)
elseif not optional and not args{k) then
‘table’ then
error("Parameter '*..k.."! is required.\n"..help,
elseif args[k] and type(args[k]) ~= t then
error(*Parameter '*..k.."' should be a "..t..'.\n
end
end;108,
109.
nie
un.
12
113
na
15
116
17
us
1s.
129.
1.
122.
123.
124,
125.
128.
127.
128.
129.
130.
ai.
132
133
134
135
136
137
138
139.
~~ Public Interface
astm_tep =
function astm_tcp.connect (args)
Local required, optional = false, true
_astm_tep.check_arg(args, ‘host’, ‘string’, requirs
__astm_tep.check_arg(args, ‘port’, ‘number’, requir
__astm_tep.check_arg(args, ‘timeout’, ‘number’, option:
__astm_tep.check_arg(args, ‘live’, ‘boolean’, option:
if args. Live or not iguana.isTest() then
= Normal behaviour (in running channel).
args. live = nil
Local Success, Socket = peal inet. tcp.connect, args)
if not Success then
-- raise error to caller level
error(Socket, 2)
end
return setmetatable({
s = Socket,
buf =", ~~ input buffer.
>, _astm_tep. reat_meta)
else
= Simulate behaviour white editing
return setmetatable({
connected = true,
}, _astm_tep.simulation_neta)
end
end
The astmutil module.
astmutil
function astmutil.checksum(s)
Sone test data may have wrong delimiters, e.g. rn or
Checksum calculation is defined for r not n delinite,
-- Checksum below is defined to strip , but not