<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Modbus Reply Script]]></title><description><![CDATA[<p dir="auto">Hello.  I'm evaluating IO Ninja to see if I can use it to simulate some Modbus RTU devices.  What I'm currently trying to do is write a simple script that will reply to a particular Modbus Master request of Read Holding Registers.  Is there a script example for using the ModbusRtuReadReplyPacket template to send a response to a Read Holding Registers request?</p>
]]></description><link>http://64.23.185.212/forum/topic/61/modbus-reply-script</link><generator>RSS for Node</generator><lastBuildDate>Wed, 11 Mar 2026 13:20:14 GMT</lastBuildDate><atom:link href="http://64.23.185.212/forum/topic/61.rss" rel="self" type="application/rss+xml"/><pubDate>Fri, 10 Feb 2023 13:56:30 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Modbus Reply Script on Mon, 03 Feb 2025 04:23:28 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="http://64.23.185.212/forum/uid/1831">@gary-biagioni</a></p>
<blockquote>
<p dir="auto">I guess the above just goes into the scripting panes. One problem I have is how do I debug the program I write. Not sure how to be able to do that, for example, look at the contents of a variable.</p>
</blockquote>
<p dir="auto">You can use the good old printf debugging.</p>
<pre><code>import "hexEncoding.jnc"

void main() {
	int a = 10;
	char s[] = "abcdef";
	char buf[] = 0x"01 02 03 04 05";
	
	string_t msg = $"a: %1/0x%(1;02x) s: %2 buf: %3"(a, s, encodeHexString(buf, sizeof(buf), ' '));
	// string_t msg = $"a: %d/0x%02x s: %s buf: %s"(a, a, s, encodeHexString(buf, sizeof(buf), ' ')); // same
	printf($"This will go to the system log: $msg\n");
	g_logWriter.write(log.StdRecordCode.PlainText, $"This will go to the normal log: $msg\n");
}
</code></pre>
<p dir="auto">The system log can be viewed via Menu-&gt;View-&gt;System Log</p>
]]></description><link>http://64.23.185.212/forum/post/748</link><guid isPermaLink="true">http://64.23.185.212/forum/post/748</guid><dc:creator><![CDATA[Vladimir]]></dc:creator><pubDate>Mon, 03 Feb 2025 04:23:28 GMT</pubDate></item><item><title><![CDATA[Reply to Modbus Reply Script on Mon, 03 Feb 2025 04:23:11 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="http://64.23.185.212/forum/uid/1831">@gary-biagioni</a></p>
<blockquote>
<p dir="auto">That said above this looks super interesting to handle responses</p>
<p dir="auto"><a href="https://ioninja.com/doc/developer-manual/tutorial-ias-server.html" rel="nofollow ugc">https://ioninja.com/doc/developer-manual/tutorial-ias-server.html</a></p>
</blockquote>
<p dir="auto">At the moment of writing this tutoiral, <code>onLogRecord</code> was the only approach to reading incoming data bytes.</p>
<p dir="auto">Of course, it still works, but we now have <code>receive</code> and <code>receiveAll</code> functions. I believe they are much easier to use.</p>
]]></description><link>http://64.23.185.212/forum/post/747</link><guid isPermaLink="true">http://64.23.185.212/forum/post/747</guid><dc:creator><![CDATA[Vladimir]]></dc:creator><pubDate>Mon, 03 Feb 2025 04:23:11 GMT</pubDate></item><item><title><![CDATA[Reply to Modbus Reply Script on Mon, 03 Feb 2025 04:12:55 GMT]]></title><description><![CDATA[<p dir="auto">Hi Gary,</p>
<p dir="auto">Sorry, the API documentation is currently just a placeholder; it's auto-generated from the script sources (you can also check those sources directly at <code>$IONINA_DIR/scripts/api/</code>). However, we also have some scripting tutorials in the Developer Manual (<a href="https://ioninja.com/doc/developer-manual/tutorials.html" rel="nofollow ugc">https://ioninja.com/doc/developer-manual/tutorials.html</a>) -- those should be helpful.</p>
<p dir="auto">For the in-app-scripting inside the "Script" pane, all the available function declarations can be found at <code>scripts/api/ias.jnc</code></p>
<p dir="auto">To answer your question, the <code>receive</code> and <code>receiveAll</code> functions are used to collect raw data bytes that appear in your log as the RX (incoming) stream.</p>
<p dir="auto"><code>receive</code> is the most basic method; it accepts the buffer and <code>timeout</code> and works as such:</p>
<ol>
<li>if there are any incoming data bytes at the moment of call -- those data bytes are returned immediately;</li>
</ol>
<ol start="2">
<li>otherwise, <code>receive</code> waits for incoming data for at most <code>timeout</code> milliseconds before returning. If a chunk of incoming data arrives before <code>timeout</code> expires, it will be returned as soon as received. If <code>timeout</code> expires and no data arrives -- <code>0</code> will be returned. <code>timeout</code> defaults to <code>-1</code> which is equivalent to infinite wait for data (<code>receive</code> will not return until at least one byte of incoming data arrives).</li>
</ol>
<p dir="auto"><code>receiveAll</code> is a helper wrapper around <code>receive</code> and is used to fill the supplied buffer entirely (you can see its implementation in <code>ias.jnc</code>). This is convenient when your script needs to fill a fixed-size packet header before proceeding. If a packet arrives in chunks, the <code>receiveAll</code> will wait until the buffer is complete and only then return. The overloaded version of <code>receiveAll</code> with the <code>timeout</code> parameter will <em>attempt</em> to fill the buffer entirely -- but will bail after <code>timeout</code> milliseconds.</p>
<p dir="auto">Hope this helps; feel free to ask more.</p>
]]></description><link>http://64.23.185.212/forum/post/746</link><guid isPermaLink="true">http://64.23.185.212/forum/post/746</guid><dc:creator><![CDATA[Vladimir]]></dc:creator><pubDate>Mon, 03 Feb 2025 04:12:55 GMT</pubDate></item><item><title><![CDATA[Reply to Modbus Reply Script on Sat, 01 Feb 2025 04:18:47 GMT]]></title><description><![CDATA[<p dir="auto">I guess the above just goes into the scripting panes.  One problem I have is how do I debug the program I write.  Not sure how to be able to do that, for example, look at the contents of a variable.</p>
]]></description><link>http://64.23.185.212/forum/post/745</link><guid isPermaLink="true">http://64.23.185.212/forum/post/745</guid><dc:creator><![CDATA[Gary Biagioni]]></dc:creator><pubDate>Sat, 01 Feb 2025 04:18:47 GMT</pubDate></item><item><title><![CDATA[Reply to Modbus Reply Script on Sat, 01 Feb 2025 03:55:11 GMT]]></title><description><![CDATA[<p dir="auto">That said above this looks super interesting to handle responses</p>
<p dir="auto"><a href="https://ioninja.com/doc/developer-manual/tutorial-ias-server.html" rel="nofollow ugc">https://ioninja.com/doc/developer-manual/tutorial-ias-server.html</a></p>
]]></description><link>http://64.23.185.212/forum/post/744</link><guid isPermaLink="true">http://64.23.185.212/forum/post/744</guid><dc:creator><![CDATA[Gary Biagioni]]></dc:creator><pubDate>Sat, 01 Feb 2025 03:55:11 GMT</pubDate></item><item><title><![CDATA[Reply to Modbus Reply Script on Sat, 01 Feb 2025 03:45:49 GMT]]></title><description><![CDATA[<p dir="auto">I found the manual at</p>
<p dir="auto"><a href="https://ioninja.com/doc/developer-manual/group_proto-modbus.html?srsltid=AfmBOoqJfrT4qjexVkCA_l9euYmY_8MPLPnjL9Qix4fknICMRvOxF7aS" rel="nofollow ugc">https://ioninja.com/doc/developer-manual/group_proto-modbus.html?srsltid=AfmBOoqJfrT4qjexVkCA_l9euYmY_8MPLPnjL9Qix4fknICMRvOxF7aS</a></p>
<p dir="auto">not quite enough detail for programming for example</p>
<p dir="auto">size_t errorcode receiveAll(<br />
void* p,<br />
size_t size,<br />
uint_t timeout<br />
);</p>
<p dir="auto">what it timeout in milliseconds?  and what are the values or error code and what do they mean - I could not find that</p>
]]></description><link>http://64.23.185.212/forum/post/743</link><guid isPermaLink="true">http://64.23.185.212/forum/post/743</guid><dc:creator><![CDATA[Gary Biagioni]]></dc:creator><pubDate>Sat, 01 Feb 2025 03:45:49 GMT</pubDate></item><item><title><![CDATA[Reply to Modbus Reply Script on Tue, 28 Jan 2025 16:51:25 GMT]]></title><description><![CDATA[<p dir="auto">I have just started using ioNinja (evaluation) as well.  Where is the documentation for the libraries that are imported in the above script.</p>
]]></description><link>http://64.23.185.212/forum/post/742</link><guid isPermaLink="true">http://64.23.185.212/forum/post/742</guid><dc:creator><![CDATA[Gary Biagioni]]></dc:creator><pubDate>Tue, 28 Jan 2025 16:51:25 GMT</pubDate></item><item><title><![CDATA[Reply to Modbus Reply Script on Wed, 15 Feb 2023 13:49:42 GMT]]></title><description><![CDATA[<p dir="auto">Thank you for the example.  This is exactly what I was looking for.</p>
]]></description><link>http://64.23.185.212/forum/post/222</link><guid isPermaLink="true">http://64.23.185.212/forum/post/222</guid><dc:creator><![CDATA[Patrick Murphy]]></dc:creator><pubDate>Wed, 15 Feb 2023 13:49:42 GMT</pubDate></item><item><title><![CDATA[Reply to Modbus Reply Script on Wed, 15 Feb 2023 07:04:37 GMT]]></title><description><![CDATA[<p dir="auto">Hello,</p>
<p dir="auto">Here's a script that receives <code>Read Holding Register</code> (or <code>Read Input Register</code>) requests and replies with ever-increasing values (1, 2, 3,...):</p>
<pre><code>import "io_Modbus.jnc"
import "crc16.jnc"

pragma(Alignment, 1)

struct Request:
	io.ModbusRtuAduHdr,
	io.ModbusReadPdu {
	uint16_t m_crc;
}
	
struct Reply: 
	io.ModbusRtuAduHdr,
	io.ModbusReadReplyPdu {
	uint16_t m_data[128]; // big enough
}

void main() {
	Request request;
	Reply reply;	

	int value = 0;

	for (;;) {
		receiveAll(&amp;request, sizeof(request)); // read request

		// prepare reply

		size_t dataSize = request.m_count * sizeof(uint16_t);
		reply.m_func = request.m_func;
		reply.m_deviceAddress = request.m_deviceAddress;
		reply.m_size = dataSize;

		bigendian uint16_t* p = reply.m_data; // Modbus values are bigendian
		for (size_t i = 0; i &lt; request.m_count; i++)
			p[i] = ++value; // adjust values accordingly

		size_t size = offsetof(Reply.m_data) + dataSize; // not including Modbus checksum
		reply.m_data[request.m_count] = crc16_ansi(reply, size, 0xffff); 

		// transmit reply
		
		transmit(reply, size + sizeof(uint16_t)); // including Modbus checksum
	}
}
</code></pre>
<p dir="auto">The result might look like this:</p>
<p dir="auto"><img src="/forum/assets/uploads/files/1676444129810-f7d227b6-48f0-4e34-9f61-13aafaf1b018-image.png" alt="f7d227b6-48f0-4e34-9f61-13aafaf1b018-image.png" class=" img-responsive img-markdown" width="1325" height="1009" /></p>
<p dir="auto">Above, I used a pair of <strong>TCP Server</strong> and <strong>TCP Connection</strong> sessions to issue sample <code>Read Holding Register</code> requests, but in your case, you most likely want to use a <strong>Serial</strong> session to talk to a real device.</p>
]]></description><link>http://64.23.185.212/forum/post/221</link><guid isPermaLink="true">http://64.23.185.212/forum/post/221</guid><dc:creator><![CDATA[Vladimir]]></dc:creator><pubDate>Wed, 15 Feb 2023 07:04:37 GMT</pubDate></item></channel></rss>