<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
		<id>http://softmc.servotronix.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Omri</id>
		<title>SoftMC-Wiki - User contributions [en]</title>
		<link rel="self" type="application/atom+xml" href="http://softmc.servotronix.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Omri"/>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/wiki/Special:Contributions/Omri"/>
		<updated>2026-05-20T10:01:51Z</updated>
		<subtitle>User contributions</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=File:MB_Required_files.zip&amp;diff=132422</id>
		<title>File:MB Required files.zip</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=File:MB_Required_files.zip&amp;diff=132422"/>
				<updated>2018-01-04T17:12:15Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: Omri uploaded a new version of &amp;amp;quot;File:MB Required files.zip&amp;amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=File:MB_Required_files.zip&amp;diff=132404</id>
		<title>File:MB Required files.zip</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=File:MB_Required_files.zip&amp;diff=132404"/>
				<updated>2018-01-03T09:07:45Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: Omri uploaded a new version of &amp;amp;quot;File:MB Required files.zip&amp;amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=File:MB_Required_files.zip&amp;diff=132172</id>
		<title>File:MB Required files.zip</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=File:MB_Required_files.zip&amp;diff=132172"/>
				<updated>2017-11-05T12:23:22Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: Omri uploaded a new version of &amp;amp;quot;File:MB Required files.zip&amp;amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Communication&amp;diff=132171</id>
		<title>Communication</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Communication&amp;diff=132171"/>
				<updated>2017-11-05T12:15:16Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: /* Modbus */ removed link to old API&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages}}&lt;br /&gt;
=LAN=&lt;br /&gt;
* [[IP Address|'''IP Address''']]&lt;br /&gt;
* [[Socket keep-alive timeouts|'''Keepalive''']]&lt;br /&gt;
* [[Communication/FastData|'''UDP FastData''']]&amp;lt;br&amp;gt;&lt;br /&gt;
* '''[[:File:FTPSCRN.PNG| FTP]]'''  standard ftp file accesses &lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
=Motion Bus=&lt;br /&gt;
* [[CANopen_Protocol|'''CANopen''']] - ''Functions are available since version'' SOCKCAN 0.4.11.2rc8 / CANOPEN 0.4.11.2rc8&lt;br /&gt;
** [[:Category:CANopen:Firmware Functions|CANopen Firmware Functions Reference]] - CANopen functions provided by firmware&lt;br /&gt;
** [[:Category:CANopen:Functions|CANopen Functions Reference]] - A list of CANopen functions&lt;br /&gt;
** [[:Category:CANOpen:Setup|CANopen Setup]] - How to setup can open network and device(s)&lt;br /&gt;
** [[Program_Examples:CANOpen:DS402_CAN_Drive_Setup|DS402 CAN Drive Setup]] - program example&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
*'''[[EtherCAT]]'''&lt;br /&gt;
** [[:Category:EtherCAT:ECAT_GENERAL_GUIDE|EtherCAT - General Guide]]&lt;br /&gt;
** [[:Category:EtherCAT:EC SETUP|Setup EtherCAT]] - How to setup EtherCAT&lt;br /&gt;
** [[:Category:EtherCAT:Functions|EtherCAT Functions Reference]] - A list of basic EtherCAT functions&lt;br /&gt;
** [[:Category:EtherCAT:Advanced Functions|Advanced EtherCAT Functions Reference]] - A list of advanced EtherCAT functions&lt;br /&gt;
** [[:EtherCAT:DIGITAL-IOS|Digital IOs]] - Associate between System Digital IOs and drives and IO Modules IOs&lt;br /&gt;
** [[:EtherCAT:Drive Control Bits|Drive Control Bits]] - Implementation of Drive Control Bits under EtherCAT&lt;br /&gt;
** [[:EtherCAT:EC_INSTALL_STX_CDHD|EC_INSTALL_STX_CDHD]] - How to configure CDHD drives&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
=Serial=&lt;br /&gt;
[[Serial Communication|'''Serial Communication''']]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
=Modbus=&lt;br /&gt;
[[Modbus Communication API|'''Modbus Communication]]&amp;lt;br/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=File:MB_Required_files.zip&amp;diff=126037</id>
		<title>File:MB Required files.zip</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=File:MB_Required_files.zip&amp;diff=126037"/>
				<updated>2016-12-08T08:52:11Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: Omri uploaded a new version of &amp;amp;quot;File:MB Required files.zip&amp;amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=File:MB_Required_files.zip&amp;diff=126036</id>
		<title>File:MB Required files.zip</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=File:MB_Required_files.zip&amp;diff=126036"/>
				<updated>2016-12-05T11:54:13Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: Omri uploaded a new version of &amp;amp;quot;File:MB Required files.zip&amp;amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Communication&amp;diff=126035</id>
		<title>Communication</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Communication&amp;diff=126035"/>
				<updated>2016-12-05T11:53:26Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: Modbus new API&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''LAN'''&lt;br /&gt;
* [[IP Address|'''IP Address''']]&lt;br /&gt;
* [[Socket keep-alive timeouts|'''Keepalive''']]&lt;br /&gt;
* TCP/IP Communication (''to be completed'')&lt;br /&gt;
** Setup&lt;br /&gt;
** [[Program_Examples:TCP_IP:TCPIP_Simple_Server]] Simple TCP/IP server&lt;br /&gt;
** [[Program_Examples:TCP_IP:TCPIP_TelNet_Server]] Simple Telnet server and command parser&lt;br /&gt;
** [[Program_Examples:TCP_IP:TCPIP_Simple_Client]] Simple TCP/IP client&lt;br /&gt;
** [[Program_Examples:TCP_IP:TCPIP_Multi_Server]]  Multi client TCP/IP server&lt;br /&gt;
** [[Program_Examples:TCP_IP:TCPIP_Winsock_Client]] An example written in C langauge, corresponds to the [[Program_Examples:TCP_IP:TCPIP_TelNet_Server|TCP/IP TelNet Server]] example&lt;br /&gt;
* [[Communication/FastData|'''UDP FastData''']]&amp;lt;br&amp;gt;&lt;br /&gt;
* '''[[:File:FTPSCRN.PNG| FTP]]'''  standard ftp file accesses &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Automation Bus'''&lt;br /&gt;
* [[CANopen_Protocol|'''CANopen''']] - ''Functions are available since version'' SOCKCAN 0.4.11.2rc8 / CANOPEN 0.4.11.2rc8&lt;br /&gt;
** [[:Category:CANopen:Firmware Functions|CANopen Firmware Functions Reference]] - CANopen functions provided by firmware&lt;br /&gt;
** [[:Category:CANopen:Functions|CANopen Functions Reference]] - A list of CANopen functions&lt;br /&gt;
** [[:Category:CANOpen:Setup|CANopen Setup]] - How to setup can open network and device(s)&lt;br /&gt;
** [[Program_Examples:CANOpen:DS402_CAN_Drive_Setup|DS402 CAN Drive Setup]] - program example&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
*'''[[EtherCAT]]'''&lt;br /&gt;
** [[:Category:EtherCAT:ECAT_GENERAL_GUIDE|EtherCAT - General Guide]]&lt;br /&gt;
** [[:Category:EtherCAT:EC SETUP|Setup EtherCAT]] - How to setup EtherCAT&lt;br /&gt;
** [[:Category:EtherCAT:Functions|EtherCAT Functions Reference]] - A list of basic EtherCAT functions&lt;br /&gt;
** [[:Category:EtherCAT:Advanced Functions|Advanced EtherCAT Functions Reference]] - A list of advanced EtherCAT functions&lt;br /&gt;
** [[:EtherCAT:DIGITAL-IOS|Digital IOs]] - Associate between System Digital IOs and drives and IO Modules IOs&lt;br /&gt;
** [[:EtherCAT:Drive Control Bits|Drive Control Bits]] - Implementation of Drive Control Bits under EtherCAT&lt;br /&gt;
** [[:EtherCAT:EC_INSTALL_STX_CDHD|EC_INSTALL_STX_CDHD]] - How to configure CDHD drives&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
[[Serial Communication|'''Serial Communication''']]&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
[[Modbus Communication API|'''Modbus Communication]]&amp;lt;br/&amp;gt;&lt;br /&gt;
[[Modbus Communication|'''Modbus Communication (Depricated)''']]&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
[[Category:Control:Offline]]&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125985</id>
		<title>Modbus Communication API</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125985"/>
				<updated>2016-11-01T06:19:24Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
=== Basic Overview ===&lt;br /&gt;
* This describes how to set up Modbus communication for the softMC, and how to generate softMC scripts to handle Modbus communication.&lt;br /&gt;
* It is assumed you are familiar with the principles of Modbus communication, although some of them will be described in this page.&lt;br /&gt;
* It is also assumed your are familiar with the softMC, ControlStudio and MC-Basic programming.&lt;br /&gt;
&lt;br /&gt;
=== Modbus Communication Background ===&lt;br /&gt;
* A Motion Controller (MC) can act as a server (slave), a client (master) or both at the same time.&lt;br /&gt;
* Each MC connection (TCP/RTU) can be used either as a server component (if the connection is used by the MC’s server-side) or as a client component (if the connection is used by the MC’s client-side).&lt;br /&gt;
* Each component has its own parameters that defines it.&lt;br /&gt;
* When the MC acts as a server, all server components share the '''same''' memory address space, thus acting as one server with multiple connections.&lt;br /&gt;
* Each server (slave) on a Modbus network has its own deviceID, which is a number between 1 and 247.&lt;br /&gt;
&lt;br /&gt;
=== The Modbus server registers ===&lt;br /&gt;
* There are 4 types of registers in the Modbus Server address space:&lt;br /&gt;
*# Bits (1-bit registers)&lt;br /&gt;
*# Input Bits (1-bit READ-ONLY registers)&lt;br /&gt;
*# Holding Registers (16-bit registers)&lt;br /&gt;
*# Input Registers (16-bit READ-ONLY registers)&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
In order to get started in using the Modbus features:&lt;br /&gt;
# Download the required files: [[:File:MB_Required_files.zip]]&lt;br /&gt;
# Using the ControlStudio File Manager, Upload the following files to your MC:&lt;br /&gt;
#* mb_x86.O ''(for softMC7 )'' / mb_armA9.O ''(for softMC3)''&lt;br /&gt;
#* Modbus.lib&lt;br /&gt;
#* MB_Load.prg&lt;br /&gt;
#:[[File:modbus;newAPI-upload.jpg|850px]]&lt;br /&gt;
# Load MB_Load.prg by typing: &amp;lt;pre&amp;gt;Load MB_Load.prg&amp;lt;/pre&amp;gt;&lt;br /&gt;
#:This will load the mb_x86.O / mb_armA9.O, depending on your current system, along with the Modbus.LIB Library file.&lt;br /&gt;
# '''Alternatively''', you can load the Object file and the Modbus library manually, by typing:&lt;br /&gt;
#:&amp;lt;Pre&amp;gt;&lt;br /&gt;
#::Oload mb_x86.O&lt;br /&gt;
#::Loadglobal Modbus.LIB&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That's it! You're now ready to configure the Modbus system.&lt;br /&gt;
&lt;br /&gt;
== Initializing the Modbus Environment ==&lt;br /&gt;
To initialize the Modbus environment, including the server address space, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;?init_multi_server([bits],[input_bits],[holding registers],[input_registers])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The function prints &amp;quot;success&amp;quot; and returns 0 on success, or return an error code on failure.&lt;br /&gt;
* &amp;lt;u&amp;gt;'''Notice:'''&amp;lt;/u&amp;gt; You MUST call this method even if you only need Client components. In that case, just pass 0 as the required registers' size.&lt;br /&gt;
* &amp;lt;u&amp;gt;'''Notice:'''&amp;lt;/u&amp;gt; You can call this method only if there are no active server components.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Memory allocation failure.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Some servers are still running and using an already mapped address space.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to create a modbus mapping.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Server Components ==&lt;br /&gt;
=== '''Adding server components''' ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Creating a TCP server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_server_create([port],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens a TCP connection to the server on port [port] with deviceID [deviceID], and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Failed to create main socket.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|}&lt;br /&gt;
==== Creating an RTU server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_server_create([type],[port],[baudrate],[data bits],[stop bits],[parity],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens an RTU connection with the given parameters, and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Invalid device string.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Invalid parity.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed opening RTU.&lt;br /&gt;
|-&lt;br /&gt;
| -5&lt;br /&gt;
| Failed allocating query buffer memory.&lt;br /&gt;
|-&lt;br /&gt;
| -6&lt;br /&gt;
| Failed to set RTU mode.&lt;br /&gt;
|-&lt;br /&gt;
| -7&lt;br /&gt;
| Unable to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -8&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|-&lt;br /&gt;
| -9&lt;br /&gt;
| The device is already in use by another system component.&lt;br /&gt;
|}&lt;br /&gt;
=== '''Stopping Server Components''' ===&lt;br /&gt;
==== Stopping a specific server component ====&lt;br /&gt;
You can stop a specific server component by passing its handle to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate server component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
==== Stopping all server components ====&lt;br /&gt;
You can stop all server components with a single call to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop_all&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function will:&lt;br /&gt;
* Stop and free all server components.&lt;br /&gt;
* Free the shared address space.&lt;br /&gt;
* Return 0 on success, -1 on failure.&lt;br /&gt;
== Client Components ==&lt;br /&gt;
=== '''Adding client components''' ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Adding a TCP Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_client_create([ip],[port])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will opens a TCP connection to the client on the given ip and port, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
==== Adding an RTU Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_client_create([type],[port],[baudrate],[data bits],[stop bits],[parity])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will open an RTU connection to the client with the given parameters, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
=== Stopping client components ===&lt;br /&gt;
A specific client can be stopped by calling:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_client_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate client component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reset the Modbus System ==&lt;br /&gt;
Sometimes, a user may wish to stop all server and client components at once, and reset the Modbus system (for example, when a user want to initialize a different Modbus system). To do that, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_reset&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function:&lt;br /&gt;
* Stops all running servers and clients.&lt;br /&gt;
* Frees their memory.&lt;br /&gt;
* Frees the shared address space.&lt;br /&gt;
* Reset the handle counter.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;u&amp;gt;Notice:&amp;lt;/u&amp;gt;''' This function is called &amp;lt;u&amp;gt;automatically&amp;lt;/u&amp;gt; when calling ''reset all''.&lt;br /&gt;
&lt;br /&gt;
== Reading and Writing ==&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
* Therefore, Servers and clients use different functions to read/write data from the address space.&lt;br /&gt;
=== '''Server Components''' ===&lt;br /&gt;
&amp;lt;hr&amp;gt;&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers and return them.&lt;br /&gt;
* When a read error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_REG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_READ_BIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_INREG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt; val = MB_SERVER_READ_INBIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data into the different types of registers.&lt;br /&gt;
* When a write error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Writing to holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_BIT([index],[new value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_INBIT([index],[value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| New value&lt;br /&gt;
| The value to write, must be from the appropriate type.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Error codes ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Invalid index.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Local server's address space isn't mapped yet.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to catch the register mutex.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to release the register mutex.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== '''Client Components''' ===&lt;br /&gt;
&amp;lt;hr&amp;gt;&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The read value is inserted into an existing variable from the appropriate type (long/double).&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_REG_LONG([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_BITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_LONG ([handle],[deviceID],[addr],[dest ptr]) &lt;br /&gt;
Val = MB_CLIENT_READ_INREG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_INBITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to read from.&lt;br /&gt;
|-&lt;br /&gt;
| Num of bits (Reading bits)&lt;br /&gt;
| The number of bits to read.&lt;br /&gt;
|-&lt;br /&gt;
| dest ptr / dest arr ptr&lt;br /&gt;
| The variable to store the read data. When reading bits, this must be an array of longs in the appropriate size (&amp;gt;= Num of bits).&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data from existing variables to the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Writing to Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_LONG([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_SHORT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_FLOAT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_DOUBLE([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_WRITE_BIT([handle],[deviceID],[addr],[src ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to start writing to.&lt;br /&gt;
|-&lt;br /&gt;
| src ptr&lt;br /&gt;
| The variable that stores the data to be written. This must be a variable from the appropriate type.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== '''Reading and Writing Summary''' ===&lt;br /&gt;
[[File:modbus;newAPI-readwriteSummary.jpg|850px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Modbus Configurator=&lt;br /&gt;
== Background ==&lt;br /&gt;
=== General ===&lt;br /&gt;
The Modbus Communication Scripts Generator ('''Modbus Configurator''') is a tool that allows you to map your softMC application variables to Modbus tags.&lt;br /&gt;
&lt;br /&gt;
'''Note''':	Tag access is defined from the HMI perspective. In other words:&lt;br /&gt;
* '''Read Access''' variables are written by the softMC to the Modbus address space.&lt;br /&gt;
* '''Write Access''' variables are read by the softMC from the Modbus address space.&lt;br /&gt;
&lt;br /&gt;
You can define whether a variable has Read Access, or Write Access. Currently, it is not possible to define a variable as having both Read Access and Write Access. However, all Write Access variables can be written once by the softMC upon system startup by a special routine that is generated in HMIMBMAP.LIB (see section below).&lt;br /&gt;
&lt;br /&gt;
The MCMBConfigurator creates three files:&lt;br /&gt;
* '''HMIMBMAP.LIB''' and '''HMIMBMAP.PRG''' files are MC-Basic scripts that are used to start a softMC task. These are default file names, which you can change, but must retain the 8.3 format. This task cyclically and indefinitely reads/writes Modbus tags according to access type. &lt;br /&gt;
* A '''.CSV''' format file that can be used by an HMI development environment, such as '''JMobile Studio''' or '''Indusoft''', to automatically import Modbus tags. You define the HMI development environment by selecting various Python scripts that will generate the .csv file.&lt;br /&gt;
=== Mapping Variables ===&lt;br /&gt;
* Variables destined to be mapped to Modbus tags must be defined as global variables by the '''common Shared''' declaration.&lt;br /&gt;
* In order to map the variables, the program must be loaded in the softMC.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
#Start the Modbus Configurator: from the ControlStudio toolbar, select '''Tools &amp;gt; Modbus Configurator'''. The Modbus Configurator tool will appear.&lt;br /&gt;
#From the top menu, Select '''Connection &amp;gt; Setting'''.&lt;br /&gt;
#'''Enter the MC's IP and port''' (default connection port is 5001), then '''click OK'''.&lt;br /&gt;
# From the top menu, Select '''Connection &amp;gt; Connect'''.&lt;br /&gt;
# Configure the Modbus Address Space&lt;br /&gt;
## From the top menu, Select '''Modbus Comm. Settings'''.&lt;br /&gt;
## In the '''General''' tab, Select the appropriate python script.&lt;br /&gt;
## In the '''Registers''' tab, enter the amount of registers needed per type, and the registers offset (Optional).&lt;br /&gt;
##* Notice: The maximum register number is 65536.&lt;br /&gt;
## In the '''Connections''' tab, add the server connections (TCP/RTU).&lt;br /&gt;
## Click '''OK'''.&lt;br /&gt;
# Map your variables&lt;br /&gt;
#* Once the Modbus Configurator is connected to softMC it gets updated with the complete list of all the global variables. Double-clicking on variables automatically maps them to Modbus tags in consecutive order. The automatic Modbus address and data type are displayed in the table, along with the Modbus address space area in which the data will be stored (Default: Holding Registers).&lt;br /&gt;
#* If a mapped variable is '''defined as CONST''', its access type will automatically set to &amp;quot;Read&amp;quot;. In such instances the access type cannot be changed. &amp;quot;Read Access variables are read only by the HMI; therefore the softMC only &amp;lt;u&amp;gt;writes&amp;lt;/u&amp;gt; them to the Modbus address space.&lt;br /&gt;
#* If a mapped variable is '''not defined as CONST''', it automatically appears with &amp;quot;Write&amp;quot; Access. '''Double-click on the access type''' to toggle the variable between Read Access and Write Access, and thus determine whether the variable will be read or written by softMC.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(4).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Generating and Using Scripts==&lt;br /&gt;
After you are done mapping variables and defining the access types, a snapshot of the current configuration must be saved in order to generate the Modbus-handling scripts.&lt;br /&gt;
&lt;br /&gt;
1. Click '''Files''', and then '''Save As'''.&lt;br /&gt;
&lt;br /&gt;
:The mapping is saved in an '''.mbas''' file.&lt;br /&gt;
&lt;br /&gt;
:If you makes changes after saving the .mbas file, the MBAS file indicator in the status bar will light up.&lt;br /&gt;
&lt;br /&gt;
2. To generate the product files, click '''Generate'''.&lt;br /&gt;
&lt;br /&gt;
:The Log windows will display Success messages.&lt;br /&gt;
&lt;br /&gt;
:The product files were created in the target folder you chose when saving the .mbas file.&lt;br /&gt;
&lt;br /&gt;
:The files HMIMBMAP.LIB and HMIMBMAP.PRG will automatically open in ControlStudio.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(5).png|600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Using the Modbus-Handling Scripts==&lt;br /&gt;
1. Using the ControlStudio File Manager, copy HMIMBMAP.LIB and HMIMBMAP.PRG to the softMC.&lt;br /&gt;
&lt;br /&gt;
'''Note''':	Before these files can be loaded and used, your application must be loaded, and all mapped variables must exist in the softMC memory.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(6).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Using the ControlStudio Terminal, load the library HMIMBMAP.LIB:&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.LIB&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Since HMIMBMAP.PRG imports this library it must not be loaded globally. This code can be executed wherever is convenient.&lt;br /&gt;
&lt;br /&gt;
2. Verify that the library was loaded successfully:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;?tasklist&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Start the Modbus communication task by loading the program:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.PRG&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
HMIMBMAP.PRG is defined as '''Program Continue''', therefore it starts automatically after it is loaded and it does not require an explicit StartTask command.&lt;br /&gt;
&lt;br /&gt;
Of course, HMIMBMAP.PRG can be loaded and executed only after HMIMBMAP.LIB is loaded. Therefore, you should add the following code to AUTOEXEC.PRG or wherever is convenient:&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.LIB&lt;br /&gt;
Load HMIMBMAP.PRG&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HMIMBMAP.PRG Explained==&lt;br /&gt;
The code:&lt;br /&gt;
&amp;lt;pre&amp;gt;import HMIMBMAP.LIB&lt;br /&gt;
Program Continue&lt;br /&gt;
	dim retVal as long = 0&lt;br /&gt;
	retVal = Init_Modbus&lt;br /&gt;
	while 1&lt;br /&gt;
		retVal = Read_Modbus_Registers&lt;br /&gt;
		retVal = Write_Modbus_Registers&lt;br /&gt;
		sleep 1&lt;br /&gt;
	end while&lt;br /&gt;
End Program&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The functions '''Init_Modbus''', '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are implemented in '''HMIMBMAP.LIB''', which is automatically generated by a Python script.&lt;br /&gt;
&lt;br /&gt;
The function '''Init_Modbus''' starts the Modbus server and then writes to the Modbus address space all the '''Write Access Variables''' (i.e., all the variables read by the softMC from the Modbus address space). This feature allows you to setup the system to start with an initialized Modbus address space before the HMI/PLC connects to it. The HMI/PLC can read the address space and initialize itself accordingly.&lt;br /&gt;
&lt;br /&gt;
The functions '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are invoked cyclically and indefinitely. '''Read_Modbus_Registers''' reads all the tags that are written by the HMI/PLC and updates the '''Write Access''' variables with new values, while '''Write_Modbus_Registers''' does the opposite.&lt;br /&gt;
&lt;br /&gt;
=HMI IDEs and .CSV Files=&lt;br /&gt;
Each line in the .csv file generated by the MCMBConfigurator file holds data about a single variable, such as Modbus address or data type.&lt;br /&gt;
 &lt;br /&gt;
This data can be used by an HMI IDE to import Modbus tags and associate them with HMI functionality.&lt;br /&gt;
&lt;br /&gt;
Different manufacturer IDEs use different .csv formatting; therefore, various Python scripts are used to create the specific .csv files suitable for a particular manufacturer IDE.&lt;br /&gt;
&lt;br /&gt;
==JMobile Studio==&lt;br /&gt;
Python script: '''JMobile_csv.py''' &lt;br /&gt;
&lt;br /&gt;
Default target .csv file name: '''JMobile_HMI.csv''' (user-definable)&lt;br /&gt;
&lt;br /&gt;
To import tags, perform the following procedure in JMobile Studio.&lt;br /&gt;
&lt;br /&gt;
===Define Protocol===&lt;br /&gt;
1. In the ProjectView pane, select '''Protocols'''.&lt;br /&gt;
&lt;br /&gt;
2. Click the blue '''+''' sign.&lt;br /&gt;
&lt;br /&gt;
3. From the list, select Modbus TCP.&lt;br /&gt;
&lt;br /&gt;
4. In the Modbus TCP configuration window, define: &lt;br /&gt;
&lt;br /&gt;
:IP Address: Set the IP address of your softMC.&lt;br /&gt;
&lt;br /&gt;
:PLC Models: Select '''Generic Modbus''' (0-based), meaning the softMC Modbus server starts addressing tags from 0.&lt;br /&gt;
&lt;br /&gt;
:Click '''OK'''.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(7).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
===Import Tags===&lt;br /&gt;
1. In the ProjectView pane, select '''Tags'''.&lt;br /&gt;
&lt;br /&gt;
2. From the list, select '''Modbus TCP''' protocol defined previously.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(8).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
3. Click the '''Import Tags''' button. &lt;br /&gt;
&lt;br /&gt;
4. Open the generated file '''JMobile_HMI.csv'''.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(9).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
5. Select the tags you want to add to your project, and click the ''Import tags'' button.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(10).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==AdvancedHMI==&lt;br /&gt;
AdvancedHMI is an open source project (http://www.advancedhmi.com/), which is downloaded as a Visual Basic project. You can then open the project, add widgets, compile, and run it.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(11).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Drag and drop '''ModbusTCPCom''' into MainForm.vb [Design].&lt;br /&gt;
&lt;br /&gt;
2. The driver appears the bottom of the screen (circled in green). &lt;br /&gt;
&lt;br /&gt;
:Click the driver, and then use the Properties pane (circled in red) to setup the IP address of the Modbus server.&lt;br /&gt;
&lt;br /&gt;
:For example, drag and drop DigitalPanelMeter and MomentaryButton into MainForm.vb [Design].&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(12).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
3. For both widgets, use the Properties pane to set the Modbus address that is associated with the variables from the softMC application.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(13).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
'''Note''':&lt;br /&gt;
::MC Modbus server addressing starts from '''40000'''.&lt;br /&gt;
::AdvancedHMI Modbus client addressing starts from '''40001'''.&lt;br /&gt;
::Prefix the address with the letter '''L'''.&lt;br /&gt;
&lt;br /&gt;
4. Save the project (Ctrl+S).&lt;br /&gt;
&lt;br /&gt;
5. Build the project (Ctrl+Shift+B).&lt;br /&gt;
&lt;br /&gt;
6. Run the project (F5).&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=File:MB_Required_files.zip&amp;diff=125919</id>
		<title>File:MB Required files.zip</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=File:MB_Required_files.zip&amp;diff=125919"/>
				<updated>2016-05-16T09:20:24Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: Omri uploaded a new version of &amp;amp;quot;File:MB Required files.zip&amp;amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=File:MB_Required_files.zip&amp;diff=125918</id>
		<title>File:MB Required files.zip</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=File:MB_Required_files.zip&amp;diff=125918"/>
				<updated>2016-05-08T08:05:52Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: Omri uploaded a new version of &amp;amp;quot;File:MB Required files.zip&amp;amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125917</id>
		<title>Modbus Communication API</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125917"/>
				<updated>2016-05-03T13:28:12Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: /* Reset the Modbus System */ Added a note&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
=== Basic Overview ===&lt;br /&gt;
* This describes how to set up Modbus communication for the softMC, and how to generate softMC scripts to handle Modbus communication.&lt;br /&gt;
* It is assumed you are familiar with the principles of Modbus communication, although some of them will be described in this page.&lt;br /&gt;
* It is also assumed your are familiar with the softMC, ControlStudio and MC-Basic programming.&lt;br /&gt;
&lt;br /&gt;
=== Modbus Communication Background ===&lt;br /&gt;
* A Motion Controller (MC) can act as a server (slave), a client (master) or both at the same time.&lt;br /&gt;
* Each MC connection (TCP/RTU) can be used either as a server component (if the connection is used by the MC’s server-side) or as a client component (if the connection is used by the MC’s client-side).&lt;br /&gt;
* Each component has its own parameters that defines it.&lt;br /&gt;
* When the MC acts as a server, all server components share the '''same''' memory address space, thus acting as one server with multiple connections.&lt;br /&gt;
* Each server (slave) on a Modbus network has its own deviceID, which is a number between 1 and 247.&lt;br /&gt;
&lt;br /&gt;
=== The Modbus server registers ===&lt;br /&gt;
* There are 4 types of registers in the Modbus Server address space:&lt;br /&gt;
*# Bits (1-bit registers)&lt;br /&gt;
*# Input Bits (1-bit READ-ONLY registers)&lt;br /&gt;
*# Holding Registers (16-bit registers)&lt;br /&gt;
*# Input Registers (16-bit READ-ONLY registers)&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
In order to get started in using the Modbus features:&lt;br /&gt;
# Download the required files: [[:File:MB_Required_files.zip]]&lt;br /&gt;
# Using the ControlStudio File Manager, Upload the following files to your MC:&lt;br /&gt;
#* mb_x86.O ''(for softMC7 )'' / mb_armA9.O ''(for softMC3)''&lt;br /&gt;
#* Modbus.lib&lt;br /&gt;
#* MB_Load.prg&lt;br /&gt;
#:[[File:modbus;newAPI-upload.jpg|850px]]&lt;br /&gt;
# Load MB_Load.prg by typing: &amp;lt;pre&amp;gt;Load MB_Load.prg&amp;lt;/pre&amp;gt;&lt;br /&gt;
#:This will load the mb_x86.O / mb_armA9.O, depending on your current system, along with the Modbus.LIB Library file.&lt;br /&gt;
# '''Alternatively''', you can load the Object file and the Modbus library manually, by typing:&lt;br /&gt;
#:&amp;lt;Pre&amp;gt;&lt;br /&gt;
#::Oload mb_x86.O&lt;br /&gt;
#::Loadglobal Modbus.LIB&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That's it! You're now ready to configure the Modbus system.&lt;br /&gt;
&lt;br /&gt;
== Initializing a Modbus Server ==&lt;br /&gt;
To initialize the Modbus server address space, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;?init_multi_server([bits],[input_bits],[holding registers],[input_registers])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The function prints &amp;quot;success&amp;quot; and returns 0 on success, or return an error code on failure.&lt;br /&gt;
* &amp;lt;u&amp;gt;'''Notice:'''&amp;lt;/u&amp;gt; You can call this method only if there are no active server components.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Memory allocation failure.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Some servers are still running and using an already mapped address space.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to create a modbus mapping.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Server Components ==&lt;br /&gt;
=== '''Adding server components''' ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Creating a TCP server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_server_create([port],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens a TCP connection to the server on port [port] with deviceID [deviceID], and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Failed to create main socket.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|}&lt;br /&gt;
==== Creating an RTU server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_server_create([type],[port],[baudrate],[data bits],[stop bits],[parity],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens an RTU connection with the given parameters, and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Invalid device string.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Invalid parity.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed opening RTU.&lt;br /&gt;
|-&lt;br /&gt;
| -5&lt;br /&gt;
| Failed allocating query buffer memory.&lt;br /&gt;
|-&lt;br /&gt;
| -6&lt;br /&gt;
| Failed to set RTU mode.&lt;br /&gt;
|-&lt;br /&gt;
| -7&lt;br /&gt;
| Unable to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -8&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|-&lt;br /&gt;
| -9&lt;br /&gt;
| The device is already in use by another system component.&lt;br /&gt;
|}&lt;br /&gt;
=== '''Stopping Server Components''' ===&lt;br /&gt;
==== Stopping a specific server component ====&lt;br /&gt;
You can stop a specific server component by passing its handle to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate server component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
==== Stopping all server components ====&lt;br /&gt;
You can stop all server components with a single call to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop_all&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function will:&lt;br /&gt;
* Stop and free all server components.&lt;br /&gt;
* Free the shared address space.&lt;br /&gt;
* Return 0 on success, -1 on failure.&lt;br /&gt;
== Client Components ==&lt;br /&gt;
=== '''Adding client components''' ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Adding a TCP Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_client_create([ip],[port])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will opens a TCP connection to the client on the given ip and port, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
==== Adding an RTU Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_client_create([type],[port],[baudrate],[data bits],[stop bits],[parity])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will open an RTU connection to the client with the given parameters, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
=== Stopping client components ===&lt;br /&gt;
A specific client can be stopped by calling:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_client_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate client component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reset the Modbus System ==&lt;br /&gt;
Sometimes, a user may wish to stop all server and client components at once, and reset the Modbus system (for example, when a user want to initialize a different Modbus system). To do that, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_reset&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function:&lt;br /&gt;
* Stops all running servers and clients.&lt;br /&gt;
* Frees their memory.&lt;br /&gt;
* Frees the shared address space.&lt;br /&gt;
* Reset the handle counter.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;u&amp;gt;Notice:&amp;lt;/u&amp;gt;''' This function is called &amp;lt;u&amp;gt;automatically&amp;lt;/u&amp;gt; when calling ''reset all''.&lt;br /&gt;
&lt;br /&gt;
== Reading and Writing ==&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
* Therefore, Servers and clients use different functions to read/write data from the address space.&lt;br /&gt;
=== '''Server Components''' ===&lt;br /&gt;
&amp;lt;hr&amp;gt;&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers and return them.&lt;br /&gt;
* When a read error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_REG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_READ_BIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_INREG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt; val = MB_SERVER_READ_INBIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data into the different types of registers.&lt;br /&gt;
* When a write error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Writing to holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_BIT([index],[new value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_INBIT([index],[value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| New value&lt;br /&gt;
| The value to write, must be from the appropriate type.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Error codes ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Invalid index.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Local server's address space isn't mapped yet.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to catch the register mutex.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to release the register mutex.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== '''Client Components''' ===&lt;br /&gt;
&amp;lt;hr&amp;gt;&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The read value is inserted into an existing variable from the appropriate type (long/double).&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_REG_LONG([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_BITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_LONG ([handle],[deviceID],[addr],[dest ptr]) &lt;br /&gt;
Val = MB_CLIENT_READ_INREG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_INBITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to read from.&lt;br /&gt;
|-&lt;br /&gt;
| Num of bits (Reading bits)&lt;br /&gt;
| The number of bits to read.&lt;br /&gt;
|-&lt;br /&gt;
| dest ptr / dest arr ptr&lt;br /&gt;
| The variable to store the read data. When reading bits, this must be an array of longs in the appropriate size (&amp;gt;= Num of bits).&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data from existing variables to the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Writing to Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_LONG([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_SHORT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_FLOAT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_DOUBLE([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_WRITE_BIT([handle],[deviceID],[addr],[src ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to start writing to.&lt;br /&gt;
|-&lt;br /&gt;
| src ptr&lt;br /&gt;
| The variable that stores the data to be written. This must be a variable from the appropriate type.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== '''Reading and Writing Summary''' ===&lt;br /&gt;
[[File:modbus;newAPI-readwriteSummary.jpg|850px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Modbus Configurator=&lt;br /&gt;
== Background ==&lt;br /&gt;
=== General ===&lt;br /&gt;
The Modbus Communication Scripts Generator ('''Modbus Configurator''') is a tool that allows you to map your softMC application variables to Modbus tags.&lt;br /&gt;
&lt;br /&gt;
'''Note''':	Tag access is defined from the HMI perspective. In other words:&lt;br /&gt;
* '''Read Access''' variables are written by the softMC to the Modbus address space.&lt;br /&gt;
* '''Write Access''' variables are read by the softMC from the Modbus address space.&lt;br /&gt;
&lt;br /&gt;
You can define whether a variable has Read Access, or Write Access. Currently, it is not possible to define a variable as having both Read Access and Write Access. However, all Write Access variables can be written once by the softMC upon system startup by a special routine that is generated in HMIMBMAP.LIB (see section below).&lt;br /&gt;
&lt;br /&gt;
The MCMBConfigurator creates three files:&lt;br /&gt;
* '''HMIMBMAP.LIB''' and '''HMIMBMAP.PRG''' files are MC-Basic scripts that are used to start a softMC task. These are default file names, which you can change, but must retain the 8.3 format. This task cyclically and indefinitely reads/writes Modbus tags according to access type. &lt;br /&gt;
* A '''.CSV''' format file that can be used by an HMI development environment, such as '''JMobile Studio''' or '''Indusoft''', to automatically import Modbus tags. You define the HMI development environment by selecting various Python scripts that will generate the .csv file.&lt;br /&gt;
=== Mapping Variables ===&lt;br /&gt;
* Variables destined to be mapped to Modbus tags must be defined as global variables by the '''common Shared''' declaration.&lt;br /&gt;
* In order to map the variables, the program must be loaded in the softMC.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
#Start the Modbus Configurator: from the ControlStudio toolbar, select '''Tools &amp;gt; Modbus Configurator'''. The Modbus Configurator tool will appear.&lt;br /&gt;
#From the top menu, Select '''Connection &amp;gt; Setting'''.&lt;br /&gt;
#'''Enter the MC's IP and port''' (default connection port is 5001), then '''click OK'''.&lt;br /&gt;
# From the top menu, Select '''Connection &amp;gt; Connect'''.&lt;br /&gt;
# Configure the Modbus Address Space&lt;br /&gt;
## From the top menu, Select '''Modbus Comm. Settings'''.&lt;br /&gt;
## In the '''General''' tab, Select the appropriate python script.&lt;br /&gt;
## In the '''Registers''' tab, enter the amount of registers needed per type, and the registers offset (Optional).&lt;br /&gt;
##* Notice: The maximum register number is 65536.&lt;br /&gt;
## In the '''Connections''' tab, add the server connections (TCP/RTU).&lt;br /&gt;
## Click '''OK'''.&lt;br /&gt;
# Map your variables&lt;br /&gt;
#* Once the Modbus Configurator is connected to softMC it gets updated with the complete list of all the global variables. Double-clicking on variables automatically maps them to Modbus tags in consecutive order. The automatic Modbus address and data type are displayed in the table, along with the Modbus address space area in which the data will be stored (Default: Holding Registers).&lt;br /&gt;
#* If a mapped variable is '''defined as CONST''', its access type will automatically set to &amp;quot;Read&amp;quot;. In such instances the access type cannot be changed. &amp;quot;Read Access variables are read only by the HMI; therefore the softMC only &amp;lt;u&amp;gt;writes&amp;lt;/u&amp;gt; them to the Modbus address space.&lt;br /&gt;
#* If a mapped variable is '''not defined as CONST''', it automatically appears with &amp;quot;Write&amp;quot; Access. '''Double-click on the access type''' to toggle the variable between Read Access and Write Access, and thus determine whether the variable will be read or written by softMC.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(4).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Generating and Using Scripts==&lt;br /&gt;
After you are done mapping variables and defining the access types, a snapshot of the current configuration must be saved in order to generate the Modbus-handling scripts.&lt;br /&gt;
&lt;br /&gt;
1. Click '''Files''', and then '''Save As'''.&lt;br /&gt;
&lt;br /&gt;
:The mapping is saved in an '''.mbas''' file.&lt;br /&gt;
&lt;br /&gt;
:If you makes changes after saving the .mbas file, the MBAS file indicator in the status bar will light up.&lt;br /&gt;
&lt;br /&gt;
2. To generate the product files, click '''Generate'''.&lt;br /&gt;
&lt;br /&gt;
:The Log windows will display Success messages.&lt;br /&gt;
&lt;br /&gt;
:The product files were created in the target folder you chose when saving the .mbas file.&lt;br /&gt;
&lt;br /&gt;
:The files HMIMBMAP.LIB and HMIMBMAP.PRG will automatically open in ControlStudio.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(5).png|600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Using the Modbus-Handling Scripts==&lt;br /&gt;
1. Using the ControlStudio File Manager, copy HMIMBMAP.LIB and HMIMBMAP.PRG to the softMC.&lt;br /&gt;
&lt;br /&gt;
'''Note''':	Before these files can be loaded and used, your application must be loaded, and all mapped variables must exist in the softMC memory.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(6).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Using the ControlStudio Terminal, load the library HMIMBMAP.LIB:&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.LIB&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Since HMIMBMAP.PRG imports this library it must not be loaded globally. This code can be executed wherever is convenient.&lt;br /&gt;
&lt;br /&gt;
2. Verify that the library was loaded successfully:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;?tasklist&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Start the Modbus communication task by loading the program:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.PRG&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
HMIMBMAP.PRG is defined as '''Program Continue''', therefore it starts automatically after it is loaded and it does not require an explicit StartTask command.&lt;br /&gt;
&lt;br /&gt;
Of course, HMIMBMAP.PRG can be loaded and executed only after HMIMBMAP.LIB is loaded. Therefore, you should add the following code to AUTOEXEC.PRG or wherever is convenient:&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.LIB&lt;br /&gt;
Load HMIMBMAP.PRG&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HMIMBMAP.PRG Explained==&lt;br /&gt;
The code:&lt;br /&gt;
&amp;lt;pre&amp;gt;import HMIMBMAP.LIB&lt;br /&gt;
Program Continue&lt;br /&gt;
	dim retVal as long = 0&lt;br /&gt;
	retVal = Init_Modbus&lt;br /&gt;
	while 1&lt;br /&gt;
		retVal = Read_Modbus_Registers&lt;br /&gt;
		retVal = Write_Modbus_Registers&lt;br /&gt;
		sleep 1&lt;br /&gt;
	end while&lt;br /&gt;
End Program&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The functions '''Init_Modbus''', '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are implemented in '''HMIMBMAP.LIB''', which is automatically generated by a Python script.&lt;br /&gt;
&lt;br /&gt;
The function '''Init_Modbus''' starts the Modbus server and then writes to the Modbus address space all the '''Write Access Variables''' (i.e., all the variables read by the softMC from the Modbus address space). This feature allows you to setup the system to start with an initialized Modbus address space before the HMI/PLC connects to it. The HMI/PLC can read the address space and initialize itself accordingly.&lt;br /&gt;
&lt;br /&gt;
The functions '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are invoked cyclically and indefinitely. '''Read_Modbus_Registers''' reads all the tags that are written by the HMI/PLC and updates the '''Write Access''' variables with new values, while '''Write_Modbus_Registers''' does the opposite.&lt;br /&gt;
&lt;br /&gt;
=HMI IDEs and .CSV Files=&lt;br /&gt;
Each line in the .csv file generated by the MCMBConfigurator file holds data about a single variable, such as Modbus address or data type.&lt;br /&gt;
 &lt;br /&gt;
This data can be used by an HMI IDE to import Modbus tags and associate them with HMI functionality.&lt;br /&gt;
&lt;br /&gt;
Different manufacturer IDEs use different .csv formatting; therefore, various Python scripts are used to create the specific .csv files suitable for a particular manufacturer IDE.&lt;br /&gt;
&lt;br /&gt;
==JMobile Studio==&lt;br /&gt;
Python script: '''JMobile_csv.py''' &lt;br /&gt;
&lt;br /&gt;
Default target .csv file name: '''JMobile_HMI.csv''' (user-definable)&lt;br /&gt;
&lt;br /&gt;
To import tags, perform the following procedure in JMobile Studio.&lt;br /&gt;
&lt;br /&gt;
===Define Protocol===&lt;br /&gt;
1. In the ProjectView pane, select '''Protocols'''.&lt;br /&gt;
&lt;br /&gt;
2. Click the blue '''+''' sign.&lt;br /&gt;
&lt;br /&gt;
3. From the list, select Modbus TCP.&lt;br /&gt;
&lt;br /&gt;
4. In the Modbus TCP configuration window, define: &lt;br /&gt;
&lt;br /&gt;
:IP Address: Set the IP address of your softMC.&lt;br /&gt;
&lt;br /&gt;
:PLC Models: Select '''Generic Modbus''' (0-based), meaning the softMC Modbus server starts addressing tags from 0.&lt;br /&gt;
&lt;br /&gt;
:Click '''OK'''.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(7).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
===Import Tags===&lt;br /&gt;
1. In the ProjectView pane, select '''Tags'''.&lt;br /&gt;
&lt;br /&gt;
2. From the list, select '''Modbus TCP''' protocol defined previously.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(8).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
3. Click the '''Import Tags''' button. &lt;br /&gt;
&lt;br /&gt;
4. Open the generated file '''JMobile_HMI.csv'''.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(9).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
5. Select the tags you want to add to your project, and click the ''Import tags'' button.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(10).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==AdvancedHMI==&lt;br /&gt;
AdvancedHMI is an open source project (http://www.advancedhmi.com/), which is downloaded as a Visual Basic project. You can then open the project, add widgets, compile, and run it.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(11).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Drag and drop '''ModbusTCPCom''' into MainForm.vb [Design].&lt;br /&gt;
&lt;br /&gt;
2. The driver appears the bottom of the screen (circled in green). &lt;br /&gt;
&lt;br /&gt;
:Click the driver, and then use the Properties pane (circled in red) to setup the IP address of the Modbus server.&lt;br /&gt;
&lt;br /&gt;
:For example, drag and drop DigitalPanelMeter and MomentaryButton into MainForm.vb [Design].&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(12).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
3. For both widgets, use the Properties pane to set the Modbus address that is associated with the variables from the softMC application.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(13).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
'''Note''':&lt;br /&gt;
::MC Modbus server addressing starts from '''40000'''.&lt;br /&gt;
::AdvancedHMI Modbus client addressing starts from '''40001'''.&lt;br /&gt;
::Prefix the address with the letter '''L'''.&lt;br /&gt;
&lt;br /&gt;
4. Save the project (Ctrl+S).&lt;br /&gt;
&lt;br /&gt;
5. Build the project (Ctrl+Shift+B).&lt;br /&gt;
&lt;br /&gt;
6. Run the project (F5).&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125916</id>
		<title>Modbus Communication API</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125916"/>
				<updated>2016-05-02T08:00:16Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: updated link to required files&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
=== Basic Overview ===&lt;br /&gt;
* This describes how to set up Modbus communication for the softMC, and how to generate softMC scripts to handle Modbus communication.&lt;br /&gt;
* It is assumed you are familiar with the principles of Modbus communication, although some of them will be described in this page.&lt;br /&gt;
* It is also assumed your are familiar with the softMC, ControlStudio and MC-Basic programming.&lt;br /&gt;
&lt;br /&gt;
=== Modbus Communication Background ===&lt;br /&gt;
* A Motion Controller (MC) can act as a server (slave), a client (master) or both at the same time.&lt;br /&gt;
* Each MC connection (TCP/RTU) can be used either as a server component (if the connection is used by the MC’s server-side) or as a client component (if the connection is used by the MC’s client-side).&lt;br /&gt;
* Each component has its own parameters that defines it.&lt;br /&gt;
* When the MC acts as a server, all server components share the '''same''' memory address space, thus acting as one server with multiple connections.&lt;br /&gt;
* Each server (slave) on a Modbus network has its own deviceID, which is a number between 1 and 247.&lt;br /&gt;
&lt;br /&gt;
=== The Modbus server registers ===&lt;br /&gt;
* There are 4 types of registers in the Modbus Server address space:&lt;br /&gt;
*# Bits (1-bit registers)&lt;br /&gt;
*# Input Bits (1-bit READ-ONLY registers)&lt;br /&gt;
*# Holding Registers (16-bit registers)&lt;br /&gt;
*# Input Registers (16-bit READ-ONLY registers)&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
In order to get started in using the Modbus features:&lt;br /&gt;
# Download the required files: [[:File:MB_Required_files.zip]]&lt;br /&gt;
# Using the ControlStudio File Manager, Upload the following files to your MC:&lt;br /&gt;
#* mb_x86.O ''(for softMC7 )'' / mb_armA9.O ''(for softMC3)''&lt;br /&gt;
#* Modbus.lib&lt;br /&gt;
#* MB_Load.prg&lt;br /&gt;
#:[[File:modbus;newAPI-upload.jpg|850px]]&lt;br /&gt;
# Load MB_Load.prg by typing: &amp;lt;pre&amp;gt;Load MB_Load.prg&amp;lt;/pre&amp;gt;&lt;br /&gt;
#:This will load the mb_x86.O / mb_armA9.O, depending on your current system, along with the Modbus.LIB Library file.&lt;br /&gt;
# '''Alternatively''', you can load the Object file and the Modbus library manually, by typing:&lt;br /&gt;
#:&amp;lt;Pre&amp;gt;&lt;br /&gt;
#::Oload mb_x86.O&lt;br /&gt;
#::Loadglobal Modbus.LIB&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That's it! You're now ready to configure the Modbus system.&lt;br /&gt;
&lt;br /&gt;
== Initializing a Modbus Server ==&lt;br /&gt;
To initialize the Modbus server address space, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;?init_multi_server([bits],[input_bits],[holding registers],[input_registers])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The function prints &amp;quot;success&amp;quot; and returns 0 on success, or return an error code on failure.&lt;br /&gt;
* &amp;lt;u&amp;gt;'''Notice:'''&amp;lt;/u&amp;gt; You can call this method only if there are no active server components.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Memory allocation failure.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Some servers are still running and using an already mapped address space.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to create a modbus mapping.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Server Components ==&lt;br /&gt;
=== '''Adding server components''' ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Creating a TCP server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_server_create([port],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens a TCP connection to the server on port [port] with deviceID [deviceID], and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Failed to create main socket.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|}&lt;br /&gt;
==== Creating an RTU server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_server_create([type],[port],[baudrate],[data bits],[stop bits],[parity],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens an RTU connection with the given parameters, and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Invalid device string.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Invalid parity.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed opening RTU.&lt;br /&gt;
|-&lt;br /&gt;
| -5&lt;br /&gt;
| Failed allocating query buffer memory.&lt;br /&gt;
|-&lt;br /&gt;
| -6&lt;br /&gt;
| Failed to set RTU mode.&lt;br /&gt;
|-&lt;br /&gt;
| -7&lt;br /&gt;
| Unable to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -8&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|-&lt;br /&gt;
| -9&lt;br /&gt;
| The device is already in use by another system component.&lt;br /&gt;
|}&lt;br /&gt;
=== '''Stopping Server Components''' ===&lt;br /&gt;
==== Stopping a specific server component ====&lt;br /&gt;
You can stop a specific server component by passing its handle to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate server component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
==== Stopping all server components ====&lt;br /&gt;
You can stop all server components with a single call to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop_all&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function will:&lt;br /&gt;
* Stop and free all server components.&lt;br /&gt;
* Free the shared address space.&lt;br /&gt;
* Return 0 on success, -1 on failure.&lt;br /&gt;
== Client Components ==&lt;br /&gt;
=== '''Adding client components''' ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Adding a TCP Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_client_create([ip],[port])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will opens a TCP connection to the client on the given ip and port, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
==== Adding an RTU Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_client_create([type],[port],[baudrate],[data bits],[stop bits],[parity])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will open an RTU connection to the client with the given parameters, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
=== Stopping client components ===&lt;br /&gt;
A specific client can be stopped by calling:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_client_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate client component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reset the Modbus System ==&lt;br /&gt;
Sometimes, a user may wish to stop all server and client components at once, and reset the Modbus system (for example, when a user want to initialize a different Modbus system). To do that, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_reset&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function:&lt;br /&gt;
* Stops all running servers and clients.&lt;br /&gt;
* Frees their memory.&lt;br /&gt;
* Frees the shared address space.&lt;br /&gt;
* Reset the handle counter.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reading and Writing ==&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
* Therefore, Servers and clients use different functions to read/write data from the address space.&lt;br /&gt;
=== '''Server Components''' ===&lt;br /&gt;
&amp;lt;hr&amp;gt;&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers and return them.&lt;br /&gt;
* When a read error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_REG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_READ_BIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_INREG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt; val = MB_SERVER_READ_INBIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data into the different types of registers.&lt;br /&gt;
* When a write error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Writing to holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_BIT([index],[new value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_INBIT([index],[value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| New value&lt;br /&gt;
| The value to write, must be from the appropriate type.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Error codes ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Invalid index.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Local server's address space isn't mapped yet.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to catch the register mutex.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to release the register mutex.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== '''Client Components''' ===&lt;br /&gt;
&amp;lt;hr&amp;gt;&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The read value is inserted into an existing variable from the appropriate type (long/double).&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_REG_LONG([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_BITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_LONG ([handle],[deviceID],[addr],[dest ptr]) &lt;br /&gt;
Val = MB_CLIENT_READ_INREG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_INBITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to read from.&lt;br /&gt;
|-&lt;br /&gt;
| Num of bits (Reading bits)&lt;br /&gt;
| The number of bits to read.&lt;br /&gt;
|-&lt;br /&gt;
| dest ptr / dest arr ptr&lt;br /&gt;
| The variable to store the read data. When reading bits, this must be an array of longs in the appropriate size (&amp;gt;= Num of bits).&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data from existing variables to the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Writing to Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_LONG([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_SHORT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_FLOAT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_DOUBLE([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_WRITE_BIT([handle],[deviceID],[addr],[src ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to start writing to.&lt;br /&gt;
|-&lt;br /&gt;
| src ptr&lt;br /&gt;
| The variable that stores the data to be written. This must be a variable from the appropriate type.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== '''Reading and Writing Summary''' ===&lt;br /&gt;
[[File:modbus;newAPI-readwriteSummary.jpg|850px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Modbus Configurator=&lt;br /&gt;
== Background ==&lt;br /&gt;
=== General ===&lt;br /&gt;
The Modbus Communication Scripts Generator ('''Modbus Configurator''') is a tool that allows you to map your softMC application variables to Modbus tags.&lt;br /&gt;
&lt;br /&gt;
'''Note''':	Tag access is defined from the HMI perspective. In other words:&lt;br /&gt;
* '''Read Access''' variables are written by the softMC to the Modbus address space.&lt;br /&gt;
* '''Write Access''' variables are read by the softMC from the Modbus address space.&lt;br /&gt;
&lt;br /&gt;
You can define whether a variable has Read Access, or Write Access. Currently, it is not possible to define a variable as having both Read Access and Write Access. However, all Write Access variables can be written once by the softMC upon system startup by a special routine that is generated in HMIMBMAP.LIB (see section below).&lt;br /&gt;
&lt;br /&gt;
The MCMBConfigurator creates three files:&lt;br /&gt;
* '''HMIMBMAP.LIB''' and '''HMIMBMAP.PRG''' files are MC-Basic scripts that are used to start a softMC task. These are default file names, which you can change, but must retain the 8.3 format. This task cyclically and indefinitely reads/writes Modbus tags according to access type. &lt;br /&gt;
* A '''.CSV''' format file that can be used by an HMI development environment, such as '''JMobile Studio''' or '''Indusoft''', to automatically import Modbus tags. You define the HMI development environment by selecting various Python scripts that will generate the .csv file.&lt;br /&gt;
=== Mapping Variables ===&lt;br /&gt;
* Variables destined to be mapped to Modbus tags must be defined as global variables by the '''common Shared''' declaration.&lt;br /&gt;
* In order to map the variables, the program must be loaded in the softMC.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
#Start the Modbus Configurator: from the ControlStudio toolbar, select '''Tools &amp;gt; Modbus Configurator'''. The Modbus Configurator tool will appear.&lt;br /&gt;
#From the top menu, Select '''Connection &amp;gt; Setting'''.&lt;br /&gt;
#'''Enter the MC's IP and port''' (default connection port is 5001), then '''click OK'''.&lt;br /&gt;
# From the top menu, Select '''Connection &amp;gt; Connect'''.&lt;br /&gt;
# Configure the Modbus Address Space&lt;br /&gt;
## From the top menu, Select '''Modbus Comm. Settings'''.&lt;br /&gt;
## In the '''General''' tab, Select the appropriate python script.&lt;br /&gt;
## In the '''Registers''' tab, enter the amount of registers needed per type, and the registers offset (Optional).&lt;br /&gt;
##* Notice: The maximum register number is 65536.&lt;br /&gt;
## In the '''Connections''' tab, add the server connections (TCP/RTU).&lt;br /&gt;
## Click '''OK'''.&lt;br /&gt;
# Map your variables&lt;br /&gt;
#* Once the Modbus Configurator is connected to softMC it gets updated with the complete list of all the global variables. Double-clicking on variables automatically maps them to Modbus tags in consecutive order. The automatic Modbus address and data type are displayed in the table, along with the Modbus address space area in which the data will be stored (Default: Holding Registers).&lt;br /&gt;
#* If a mapped variable is '''defined as CONST''', its access type will automatically set to &amp;quot;Read&amp;quot;. In such instances the access type cannot be changed. &amp;quot;Read Access variables are read only by the HMI; therefore the softMC only &amp;lt;u&amp;gt;writes&amp;lt;/u&amp;gt; them to the Modbus address space.&lt;br /&gt;
#* If a mapped variable is '''not defined as CONST''', it automatically appears with &amp;quot;Write&amp;quot; Access. '''Double-click on the access type''' to toggle the variable between Read Access and Write Access, and thus determine whether the variable will be read or written by softMC.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(4).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Generating and Using Scripts==&lt;br /&gt;
After you are done mapping variables and defining the access types, a snapshot of the current configuration must be saved in order to generate the Modbus-handling scripts.&lt;br /&gt;
&lt;br /&gt;
1. Click '''Files''', and then '''Save As'''.&lt;br /&gt;
&lt;br /&gt;
:The mapping is saved in an '''.mbas''' file.&lt;br /&gt;
&lt;br /&gt;
:If you makes changes after saving the .mbas file, the MBAS file indicator in the status bar will light up.&lt;br /&gt;
&lt;br /&gt;
2. To generate the product files, click '''Generate'''.&lt;br /&gt;
&lt;br /&gt;
:The Log windows will display Success messages.&lt;br /&gt;
&lt;br /&gt;
:The product files were created in the target folder you chose when saving the .mbas file.&lt;br /&gt;
&lt;br /&gt;
:The files HMIMBMAP.LIB and HMIMBMAP.PRG will automatically open in ControlStudio.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(5).png|600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Using the Modbus-Handling Scripts==&lt;br /&gt;
1. Using the ControlStudio File Manager, copy HMIMBMAP.LIB and HMIMBMAP.PRG to the softMC.&lt;br /&gt;
&lt;br /&gt;
'''Note''':	Before these files can be loaded and used, your application must be loaded, and all mapped variables must exist in the softMC memory.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(6).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Using the ControlStudio Terminal, load the library HMIMBMAP.LIB:&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.LIB&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Since HMIMBMAP.PRG imports this library it must not be loaded globally. This code can be executed wherever is convenient.&lt;br /&gt;
&lt;br /&gt;
2. Verify that the library was loaded successfully:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;?tasklist&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Start the Modbus communication task by loading the program:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.PRG&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
HMIMBMAP.PRG is defined as '''Program Continue''', therefore it starts automatically after it is loaded and it does not require an explicit StartTask command.&lt;br /&gt;
&lt;br /&gt;
Of course, HMIMBMAP.PRG can be loaded and executed only after HMIMBMAP.LIB is loaded. Therefore, you should add the following code to AUTOEXEC.PRG or wherever is convenient:&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.LIB&lt;br /&gt;
Load HMIMBMAP.PRG&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HMIMBMAP.PRG Explained==&lt;br /&gt;
The code:&lt;br /&gt;
&amp;lt;pre&amp;gt;import HMIMBMAP.LIB&lt;br /&gt;
Program Continue&lt;br /&gt;
	dim retVal as long = 0&lt;br /&gt;
	retVal = Init_Modbus&lt;br /&gt;
	while 1&lt;br /&gt;
		retVal = Read_Modbus_Registers&lt;br /&gt;
		retVal = Write_Modbus_Registers&lt;br /&gt;
		sleep 1&lt;br /&gt;
	end while&lt;br /&gt;
End Program&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The functions '''Init_Modbus''', '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are implemented in '''HMIMBMAP.LIB''', which is automatically generated by a Python script.&lt;br /&gt;
&lt;br /&gt;
The function '''Init_Modbus''' starts the Modbus server and then writes to the Modbus address space all the '''Write Access Variables''' (i.e., all the variables read by the softMC from the Modbus address space). This feature allows you to setup the system to start with an initialized Modbus address space before the HMI/PLC connects to it. The HMI/PLC can read the address space and initialize itself accordingly.&lt;br /&gt;
&lt;br /&gt;
The functions '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are invoked cyclically and indefinitely. '''Read_Modbus_Registers''' reads all the tags that are written by the HMI/PLC and updates the '''Write Access''' variables with new values, while '''Write_Modbus_Registers''' does the opposite.&lt;br /&gt;
&lt;br /&gt;
=HMI IDEs and .CSV Files=&lt;br /&gt;
Each line in the .csv file generated by the MCMBConfigurator file holds data about a single variable, such as Modbus address or data type.&lt;br /&gt;
 &lt;br /&gt;
This data can be used by an HMI IDE to import Modbus tags and associate them with HMI functionality.&lt;br /&gt;
&lt;br /&gt;
Different manufacturer IDEs use different .csv formatting; therefore, various Python scripts are used to create the specific .csv files suitable for a particular manufacturer IDE.&lt;br /&gt;
&lt;br /&gt;
==JMobile Studio==&lt;br /&gt;
Python script: '''JMobile_csv.py''' &lt;br /&gt;
&lt;br /&gt;
Default target .csv file name: '''JMobile_HMI.csv''' (user-definable)&lt;br /&gt;
&lt;br /&gt;
To import tags, perform the following procedure in JMobile Studio.&lt;br /&gt;
&lt;br /&gt;
===Define Protocol===&lt;br /&gt;
1. In the ProjectView pane, select '''Protocols'''.&lt;br /&gt;
&lt;br /&gt;
2. Click the blue '''+''' sign.&lt;br /&gt;
&lt;br /&gt;
3. From the list, select Modbus TCP.&lt;br /&gt;
&lt;br /&gt;
4. In the Modbus TCP configuration window, define: &lt;br /&gt;
&lt;br /&gt;
:IP Address: Set the IP address of your softMC.&lt;br /&gt;
&lt;br /&gt;
:PLC Models: Select '''Generic Modbus''' (0-based), meaning the softMC Modbus server starts addressing tags from 0.&lt;br /&gt;
&lt;br /&gt;
:Click '''OK'''.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(7).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
===Import Tags===&lt;br /&gt;
1. In the ProjectView pane, select '''Tags'''.&lt;br /&gt;
&lt;br /&gt;
2. From the list, select '''Modbus TCP''' protocol defined previously.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(8).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
3. Click the '''Import Tags''' button. &lt;br /&gt;
&lt;br /&gt;
4. Open the generated file '''JMobile_HMI.csv'''.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(9).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
5. Select the tags you want to add to your project, and click the ''Import tags'' button.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(10).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==AdvancedHMI==&lt;br /&gt;
AdvancedHMI is an open source project (http://www.advancedhmi.com/), which is downloaded as a Visual Basic project. You can then open the project, add widgets, compile, and run it.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(11).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Drag and drop '''ModbusTCPCom''' into MainForm.vb [Design].&lt;br /&gt;
&lt;br /&gt;
2. The driver appears the bottom of the screen (circled in green). &lt;br /&gt;
&lt;br /&gt;
:Click the driver, and then use the Properties pane (circled in red) to setup the IP address of the Modbus server.&lt;br /&gt;
&lt;br /&gt;
:For example, drag and drop DigitalPanelMeter and MomentaryButton into MainForm.vb [Design].&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(12).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
3. For both widgets, use the Properties pane to set the Modbus address that is associated with the variables from the softMC application.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(13).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
'''Note''':&lt;br /&gt;
::MC Modbus server addressing starts from '''40000'''.&lt;br /&gt;
::AdvancedHMI Modbus client addressing starts from '''40001'''.&lt;br /&gt;
::Prefix the address with the letter '''L'''.&lt;br /&gt;
&lt;br /&gt;
4. Save the project (Ctrl+S).&lt;br /&gt;
&lt;br /&gt;
5. Build the project (Ctrl+Shift+B).&lt;br /&gt;
&lt;br /&gt;
6. Run the project (F5).&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=File:MB_Required_files.zip&amp;diff=125915</id>
		<title>File:MB Required files.zip</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=File:MB_Required_files.zip&amp;diff=125915"/>
				<updated>2016-05-02T07:55:37Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: -&amp;gt; Creation failed: Unsupported filetype!&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125914</id>
		<title>Modbus Communication API</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125914"/>
				<updated>2016-05-02T07:20:20Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: /* Getting Started */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
=== Basic Overview ===&lt;br /&gt;
* This describes how to set up Modbus communication for the softMC, and how to generate softMC scripts to handle Modbus communication.&lt;br /&gt;
* It is assumed you are familiar with the principles of Modbus communication, although some of them will be described in this page.&lt;br /&gt;
* It is also assumed your are familiar with the softMC, ControlStudio and MC-Basic programming.&lt;br /&gt;
&lt;br /&gt;
=== Modbus Communication Background ===&lt;br /&gt;
* A Motion Controller (MC) can act as a server (slave), a client (master) or both at the same time.&lt;br /&gt;
* Each MC connection (TCP/RTU) can be used either as a server component (if the connection is used by the MC’s server-side) or as a client component (if the connection is used by the MC’s client-side).&lt;br /&gt;
* Each component has its own parameters that defines it.&lt;br /&gt;
* When the MC acts as a server, all server components share the '''same''' memory address space, thus acting as one server with multiple connections.&lt;br /&gt;
* Each server (slave) on a Modbus network has its own deviceID, which is a number between 1 and 247.&lt;br /&gt;
&lt;br /&gt;
=== The Modbus server registers ===&lt;br /&gt;
* There are 4 types of registers in the Modbus Server address space:&lt;br /&gt;
*# Bits (1-bit registers)&lt;br /&gt;
*# Input Bits (1-bit READ-ONLY registers)&lt;br /&gt;
*# Holding Registers (16-bit registers)&lt;br /&gt;
*# Input Registers (16-bit READ-ONLY registers)&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
In order to get started in using the Modbus features:&lt;br /&gt;
# Download the required files, according to your system's type:&lt;br /&gt;
#* Required files for [[File:modbus_requiredFiles_x86.zip|modbus_X86.ZIP]].&lt;br /&gt;
#* Required files for ARM systems.&lt;br /&gt;
# Using the ControlStudio File Manager, Upload the following files to your MC:&lt;br /&gt;
#* mb_x86.O ''(for softMC7 )'' / mb_armA9.O ''(for softMC3)''&lt;br /&gt;
#* Modbus.lib&lt;br /&gt;
#* MB_Load.prg&lt;br /&gt;
#:[[File:modbus;newAPI-upload.jpg|850px]]&lt;br /&gt;
# Load MB_Load.prg by typing: &amp;lt;pre&amp;gt;Load MB_Load.prg&amp;lt;/pre&amp;gt;&lt;br /&gt;
#:This will load the mb_x86.O / mb_armA9.O, depending on your current system, along with the Modbus.LIB Library file.&lt;br /&gt;
# '''Alternatively''', you can load the Object file and the Modbus library manually, by typing:&lt;br /&gt;
#:&amp;lt;Pre&amp;gt;&lt;br /&gt;
#::Oload mb_x86.O&lt;br /&gt;
#::Loadglobal Modbus.LIB&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That's it! You're now ready to configure the Modbus system.&lt;br /&gt;
&lt;br /&gt;
== Initializing a Modbus Server ==&lt;br /&gt;
To initialize the Modbus server address space, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;?init_multi_server([bits],[input_bits],[holding registers],[input_registers])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The function prints &amp;quot;success&amp;quot; and returns 0 on success, or return an error code on failure.&lt;br /&gt;
* &amp;lt;u&amp;gt;'''Notice:'''&amp;lt;/u&amp;gt; You can call this method only if there are no active server components.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Memory allocation failure.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Some servers are still running and using an already mapped address space.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to create a modbus mapping.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Server Components ==&lt;br /&gt;
=== '''Adding server components''' ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Creating a TCP server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_server_create([port],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens a TCP connection to the server on port [port] with deviceID [deviceID], and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Failed to create main socket.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|}&lt;br /&gt;
==== Creating an RTU server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_server_create([type],[port],[baudrate],[data bits],[stop bits],[parity],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens an RTU connection with the given parameters, and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Invalid device string.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Invalid parity.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed opening RTU.&lt;br /&gt;
|-&lt;br /&gt;
| -5&lt;br /&gt;
| Failed allocating query buffer memory.&lt;br /&gt;
|-&lt;br /&gt;
| -6&lt;br /&gt;
| Failed to set RTU mode.&lt;br /&gt;
|-&lt;br /&gt;
| -7&lt;br /&gt;
| Unable to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -8&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|-&lt;br /&gt;
| -9&lt;br /&gt;
| The device is already in use by another system component.&lt;br /&gt;
|}&lt;br /&gt;
=== '''Stopping Server Components''' ===&lt;br /&gt;
==== Stopping a specific server component ====&lt;br /&gt;
You can stop a specific server component by passing its handle to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate server component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
==== Stopping all server components ====&lt;br /&gt;
You can stop all server components with a single call to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop_all&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function will:&lt;br /&gt;
* Stop and free all server components.&lt;br /&gt;
* Free the shared address space.&lt;br /&gt;
* Return 0 on success, -1 on failure.&lt;br /&gt;
== Client Components ==&lt;br /&gt;
=== '''Adding client components''' ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Adding a TCP Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_client_create([ip],[port])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will opens a TCP connection to the client on the given ip and port, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
==== Adding an RTU Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_client_create([type],[port],[baudrate],[data bits],[stop bits],[parity])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will open an RTU connection to the client with the given parameters, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
=== Stopping client components ===&lt;br /&gt;
A specific client can be stopped by calling:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_client_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate client component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reset the Modbus System ==&lt;br /&gt;
Sometimes, a user may wish to stop all server and client components at once, and reset the Modbus system (for example, when a user want to initialize a different Modbus system). To do that, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_reset&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function:&lt;br /&gt;
* Stops all running servers and clients.&lt;br /&gt;
* Frees their memory.&lt;br /&gt;
* Frees the shared address space.&lt;br /&gt;
* Reset the handle counter.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reading and Writing ==&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
* Therefore, Servers and clients use different functions to read/write data from the address space.&lt;br /&gt;
=== '''Server Components''' ===&lt;br /&gt;
&amp;lt;hr&amp;gt;&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers and return them.&lt;br /&gt;
* When a read error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_REG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_READ_BIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_INREG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt; val = MB_SERVER_READ_INBIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data into the different types of registers.&lt;br /&gt;
* When a write error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Writing to holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_BIT([index],[new value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_INBIT([index],[value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| New value&lt;br /&gt;
| The value to write, must be from the appropriate type.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Error codes ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Invalid index.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Local server's address space isn't mapped yet.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to catch the register mutex.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to release the register mutex.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== '''Client Components''' ===&lt;br /&gt;
&amp;lt;hr&amp;gt;&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The read value is inserted into an existing variable from the appropriate type (long/double).&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_REG_LONG([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_BITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_LONG ([handle],[deviceID],[addr],[dest ptr]) &lt;br /&gt;
Val = MB_CLIENT_READ_INREG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_INBITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to read from.&lt;br /&gt;
|-&lt;br /&gt;
| Num of bits (Reading bits)&lt;br /&gt;
| The number of bits to read.&lt;br /&gt;
|-&lt;br /&gt;
| dest ptr / dest arr ptr&lt;br /&gt;
| The variable to store the read data. When reading bits, this must be an array of longs in the appropriate size (&amp;gt;= Num of bits).&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data from existing variables to the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Writing to Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_LONG([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_SHORT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_FLOAT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_DOUBLE([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_WRITE_BIT([handle],[deviceID],[addr],[src ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to start writing to.&lt;br /&gt;
|-&lt;br /&gt;
| src ptr&lt;br /&gt;
| The variable that stores the data to be written. This must be a variable from the appropriate type.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== '''Reading and Writing Summary''' ===&lt;br /&gt;
[[File:modbus;newAPI-readwriteSummary.jpg|850px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Modbus Configurator=&lt;br /&gt;
== Background ==&lt;br /&gt;
=== General ===&lt;br /&gt;
The Modbus Communication Scripts Generator ('''Modbus Configurator''') is a tool that allows you to map your softMC application variables to Modbus tags.&lt;br /&gt;
&lt;br /&gt;
'''Note''':	Tag access is defined from the HMI perspective. In other words:&lt;br /&gt;
* '''Read Access''' variables are written by the softMC to the Modbus address space.&lt;br /&gt;
* '''Write Access''' variables are read by the softMC from the Modbus address space.&lt;br /&gt;
&lt;br /&gt;
You can define whether a variable has Read Access, or Write Access. Currently, it is not possible to define a variable as having both Read Access and Write Access. However, all Write Access variables can be written once by the softMC upon system startup by a special routine that is generated in HMIMBMAP.LIB (see section below).&lt;br /&gt;
&lt;br /&gt;
The MCMBConfigurator creates three files:&lt;br /&gt;
* '''HMIMBMAP.LIB''' and '''HMIMBMAP.PRG''' files are MC-Basic scripts that are used to start a softMC task. These are default file names, which you can change, but must retain the 8.3 format. This task cyclically and indefinitely reads/writes Modbus tags according to access type. &lt;br /&gt;
* A '''.CSV''' format file that can be used by an HMI development environment, such as '''JMobile Studio''' or '''Indusoft''', to automatically import Modbus tags. You define the HMI development environment by selecting various Python scripts that will generate the .csv file.&lt;br /&gt;
=== Mapping Variables ===&lt;br /&gt;
* Variables destined to be mapped to Modbus tags must be defined as global variables by the '''common Shared''' declaration.&lt;br /&gt;
* In order to map the variables, the program must be loaded in the softMC.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
#Start the Modbus Configurator: from the ControlStudio toolbar, select '''Tools &amp;gt; Modbus Configurator'''. The Modbus Configurator tool will appear.&lt;br /&gt;
#From the top menu, Select '''Connection &amp;gt; Setting'''.&lt;br /&gt;
#'''Enter the MC's IP and port''' (default connection port is 5001), then '''click OK'''.&lt;br /&gt;
# From the top menu, Select '''Connection &amp;gt; Connect'''.&lt;br /&gt;
# Configure the Modbus Address Space&lt;br /&gt;
## From the top menu, Select '''Modbus Comm. Settings'''.&lt;br /&gt;
## In the '''General''' tab, Select the appropriate python script.&lt;br /&gt;
## In the '''Registers''' tab, enter the amount of registers needed per type, and the registers offset (Optional).&lt;br /&gt;
##* Notice: The maximum register number is 65536.&lt;br /&gt;
## In the '''Connections''' tab, add the server connections (TCP/RTU).&lt;br /&gt;
## Click '''OK'''.&lt;br /&gt;
# Map your variables&lt;br /&gt;
#* Once the Modbus Configurator is connected to softMC it gets updated with the complete list of all the global variables. Double-clicking on variables automatically maps them to Modbus tags in consecutive order. The automatic Modbus address and data type are displayed in the table, along with the Modbus address space area in which the data will be stored (Default: Holding Registers).&lt;br /&gt;
#* If a mapped variable is '''defined as CONST''', its access type will automatically set to &amp;quot;Read&amp;quot;. In such instances the access type cannot be changed. &amp;quot;Read Access variables are read only by the HMI; therefore the softMC only &amp;lt;u&amp;gt;writes&amp;lt;/u&amp;gt; them to the Modbus address space.&lt;br /&gt;
#* If a mapped variable is '''not defined as CONST''', it automatically appears with &amp;quot;Write&amp;quot; Access. '''Double-click on the access type''' to toggle the variable between Read Access and Write Access, and thus determine whether the variable will be read or written by softMC.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(4).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Generating and Using Scripts==&lt;br /&gt;
After you are done mapping variables and defining the access types, a snapshot of the current configuration must be saved in order to generate the Modbus-handling scripts.&lt;br /&gt;
&lt;br /&gt;
1. Click '''Files''', and then '''Save As'''.&lt;br /&gt;
&lt;br /&gt;
:The mapping is saved in an '''.mbas''' file.&lt;br /&gt;
&lt;br /&gt;
:If you makes changes after saving the .mbas file, the MBAS file indicator in the status bar will light up.&lt;br /&gt;
&lt;br /&gt;
2. To generate the product files, click '''Generate'''.&lt;br /&gt;
&lt;br /&gt;
:The Log windows will display Success messages.&lt;br /&gt;
&lt;br /&gt;
:The product files were created in the target folder you chose when saving the .mbas file.&lt;br /&gt;
&lt;br /&gt;
:The files HMIMBMAP.LIB and HMIMBMAP.PRG will automatically open in ControlStudio.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(5).png|600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Using the Modbus-Handling Scripts==&lt;br /&gt;
1. Using the ControlStudio File Manager, copy HMIMBMAP.LIB and HMIMBMAP.PRG to the softMC.&lt;br /&gt;
&lt;br /&gt;
'''Note''':	Before these files can be loaded and used, your application must be loaded, and all mapped variables must exist in the softMC memory.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(6).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Using the ControlStudio Terminal, load the library HMIMBMAP.LIB:&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.LIB&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Since HMIMBMAP.PRG imports this library it must not be loaded globally. This code can be executed wherever is convenient.&lt;br /&gt;
&lt;br /&gt;
2. Verify that the library was loaded successfully:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;?tasklist&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Start the Modbus communication task by loading the program:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.PRG&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
HMIMBMAP.PRG is defined as '''Program Continue''', therefore it starts automatically after it is loaded and it does not require an explicit StartTask command.&lt;br /&gt;
&lt;br /&gt;
Of course, HMIMBMAP.PRG can be loaded and executed only after HMIMBMAP.LIB is loaded. Therefore, you should add the following code to AUTOEXEC.PRG or wherever is convenient:&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.LIB&lt;br /&gt;
Load HMIMBMAP.PRG&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HMIMBMAP.PRG Explained==&lt;br /&gt;
The code:&lt;br /&gt;
&amp;lt;pre&amp;gt;import HMIMBMAP.LIB&lt;br /&gt;
Program Continue&lt;br /&gt;
	dim retVal as long = 0&lt;br /&gt;
	retVal = Init_Modbus&lt;br /&gt;
	while 1&lt;br /&gt;
		retVal = Read_Modbus_Registers&lt;br /&gt;
		retVal = Write_Modbus_Registers&lt;br /&gt;
		sleep 1&lt;br /&gt;
	end while&lt;br /&gt;
End Program&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The functions '''Init_Modbus''', '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are implemented in '''HMIMBMAP.LIB''', which is automatically generated by a Python script.&lt;br /&gt;
&lt;br /&gt;
The function '''Init_Modbus''' starts the Modbus server and then writes to the Modbus address space all the '''Write Access Variables''' (i.e., all the variables read by the softMC from the Modbus address space). This feature allows you to setup the system to start with an initialized Modbus address space before the HMI/PLC connects to it. The HMI/PLC can read the address space and initialize itself accordingly.&lt;br /&gt;
&lt;br /&gt;
The functions '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are invoked cyclically and indefinitely. '''Read_Modbus_Registers''' reads all the tags that are written by the HMI/PLC and updates the '''Write Access''' variables with new values, while '''Write_Modbus_Registers''' does the opposite.&lt;br /&gt;
&lt;br /&gt;
=HMI IDEs and .CSV Files=&lt;br /&gt;
Each line in the .csv file generated by the MCMBConfigurator file holds data about a single variable, such as Modbus address or data type.&lt;br /&gt;
 &lt;br /&gt;
This data can be used by an HMI IDE to import Modbus tags and associate them with HMI functionality.&lt;br /&gt;
&lt;br /&gt;
Different manufacturer IDEs use different .csv formatting; therefore, various Python scripts are used to create the specific .csv files suitable for a particular manufacturer IDE.&lt;br /&gt;
&lt;br /&gt;
==JMobile Studio==&lt;br /&gt;
Python script: '''JMobile_csv.py''' &lt;br /&gt;
&lt;br /&gt;
Default target .csv file name: '''JMobile_HMI.csv''' (user-definable)&lt;br /&gt;
&lt;br /&gt;
To import tags, perform the following procedure in JMobile Studio.&lt;br /&gt;
&lt;br /&gt;
===Define Protocol===&lt;br /&gt;
1. In the ProjectView pane, select '''Protocols'''.&lt;br /&gt;
&lt;br /&gt;
2. Click the blue '''+''' sign.&lt;br /&gt;
&lt;br /&gt;
3. From the list, select Modbus TCP.&lt;br /&gt;
&lt;br /&gt;
4. In the Modbus TCP configuration window, define: &lt;br /&gt;
&lt;br /&gt;
:IP Address: Set the IP address of your softMC.&lt;br /&gt;
&lt;br /&gt;
:PLC Models: Select '''Generic Modbus''' (0-based), meaning the softMC Modbus server starts addressing tags from 0.&lt;br /&gt;
&lt;br /&gt;
:Click '''OK'''.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(7).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
===Import Tags===&lt;br /&gt;
1. In the ProjectView pane, select '''Tags'''.&lt;br /&gt;
&lt;br /&gt;
2. From the list, select '''Modbus TCP''' protocol defined previously.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(8).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
3. Click the '''Import Tags''' button. &lt;br /&gt;
&lt;br /&gt;
4. Open the generated file '''JMobile_HMI.csv'''.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(9).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
5. Select the tags you want to add to your project, and click the ''Import tags'' button.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(10).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==AdvancedHMI==&lt;br /&gt;
AdvancedHMI is an open source project (http://www.advancedhmi.com/), which is downloaded as a Visual Basic project. You can then open the project, add widgets, compile, and run it.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(11).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Drag and drop '''ModbusTCPCom''' into MainForm.vb [Design].&lt;br /&gt;
&lt;br /&gt;
2. The driver appears the bottom of the screen (circled in green). &lt;br /&gt;
&lt;br /&gt;
:Click the driver, and then use the Properties pane (circled in red) to setup the IP address of the Modbus server.&lt;br /&gt;
&lt;br /&gt;
:For example, drag and drop DigitalPanelMeter and MomentaryButton into MainForm.vb [Design].&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(12).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
3. For both widgets, use the Properties pane to set the Modbus address that is associated with the variables from the softMC application.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(13).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
'''Note''':&lt;br /&gt;
::MC Modbus server addressing starts from '''40000'''.&lt;br /&gt;
::AdvancedHMI Modbus client addressing starts from '''40001'''.&lt;br /&gt;
::Prefix the address with the letter '''L'''.&lt;br /&gt;
&lt;br /&gt;
4. Save the project (Ctrl+S).&lt;br /&gt;
&lt;br /&gt;
5. Build the project (Ctrl+Shift+B).&lt;br /&gt;
&lt;br /&gt;
6. Run the project (F5).&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125913</id>
		<title>Modbus Communication API</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125913"/>
				<updated>2016-05-02T06:53:57Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: /* Getting Started */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
=== Basic Overview ===&lt;br /&gt;
* This describes how to set up Modbus communication for the softMC, and how to generate softMC scripts to handle Modbus communication.&lt;br /&gt;
* It is assumed you are familiar with the principles of Modbus communication, although some of them will be described in this page.&lt;br /&gt;
* It is also assumed your are familiar with the softMC, ControlStudio and MC-Basic programming.&lt;br /&gt;
&lt;br /&gt;
=== Modbus Communication Background ===&lt;br /&gt;
* A Motion Controller (MC) can act as a server (slave), a client (master) or both at the same time.&lt;br /&gt;
* Each MC connection (TCP/RTU) can be used either as a server component (if the connection is used by the MC’s server-side) or as a client component (if the connection is used by the MC’s client-side).&lt;br /&gt;
* Each component has its own parameters that defines it.&lt;br /&gt;
* When the MC acts as a server, all server components share the '''same''' memory address space, thus acting as one server with multiple connections.&lt;br /&gt;
* Each server (slave) on a Modbus network has its own deviceID, which is a number between 1 and 247.&lt;br /&gt;
&lt;br /&gt;
=== The Modbus server registers ===&lt;br /&gt;
* There are 4 types of registers in the Modbus Server address space:&lt;br /&gt;
*# Bits (1-bit registers)&lt;br /&gt;
*# Input Bits (1-bit READ-ONLY registers)&lt;br /&gt;
*# Holding Registers (16-bit registers)&lt;br /&gt;
*# Input Registers (16-bit READ-ONLY registers)&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
In order to get started in using the Modbus features:&lt;br /&gt;
# Download the required files, according to your system's type:&lt;br /&gt;
#* Required files for [[File:modbus_requiredFiles_x86.zip|modbus_X86.ZIP]].&lt;br /&gt;
#* Required files for ARM systems.&lt;br /&gt;
# Using the ControlStudio File Manager, Upload the following files to your MC:&lt;br /&gt;
#* mb_x86.O ''(for softMC7 )'' / mb_armA9.O ''(for softMC3)''&lt;br /&gt;
#* Modbus.lib&lt;br /&gt;
#* MB_Load.prg&lt;br /&gt;
#:[[File:modbus;newAPI-upload.jpg|850px]]&lt;br /&gt;
# Load MB_Load.prg by typing: &amp;lt;pre&amp;gt;Load MB_Load.prg&amp;lt;/pre&amp;gt;&lt;br /&gt;
#:This will load the mb_x86.O / mb_armA9.O, depending on your current system, along with the Modbus.LIB Library file.&lt;br /&gt;
# '''Alternatively''', you can load the Object file and the Modbus library manually, by typing: &amp;lt;pre&amp;gt;Oload mb_x86.O&lt;br /&gt;
#: Loadglobal Modbus.LIB&amp;lt;/pre&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
That's it! You're now ready to configure the Modbus system.&lt;br /&gt;
&lt;br /&gt;
== Initializing a Modbus Server ==&lt;br /&gt;
To initialize the Modbus server address space, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;?init_multi_server([bits],[input_bits],[holding registers],[input_registers])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The function prints &amp;quot;success&amp;quot; and returns 0 on success, or return an error code on failure.&lt;br /&gt;
* &amp;lt;u&amp;gt;'''Notice:'''&amp;lt;/u&amp;gt; You can call this method only if there are no active server components.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Memory allocation failure.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Some servers are still running and using an already mapped address space.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to create a modbus mapping.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Server Components ==&lt;br /&gt;
=== '''Adding server components''' ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Creating a TCP server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_server_create([port],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens a TCP connection to the server on port [port] with deviceID [deviceID], and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Failed to create main socket.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|}&lt;br /&gt;
==== Creating an RTU server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_server_create([type],[port],[baudrate],[data bits],[stop bits],[parity],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens an RTU connection with the given parameters, and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Invalid device string.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Invalid parity.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed opening RTU.&lt;br /&gt;
|-&lt;br /&gt;
| -5&lt;br /&gt;
| Failed allocating query buffer memory.&lt;br /&gt;
|-&lt;br /&gt;
| -6&lt;br /&gt;
| Failed to set RTU mode.&lt;br /&gt;
|-&lt;br /&gt;
| -7&lt;br /&gt;
| Unable to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -8&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|-&lt;br /&gt;
| -9&lt;br /&gt;
| The device is already in use by another system component.&lt;br /&gt;
|}&lt;br /&gt;
=== '''Stopping Server Components''' ===&lt;br /&gt;
==== Stopping a specific server component ====&lt;br /&gt;
You can stop a specific server component by passing its handle to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate server component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
==== Stopping all server components ====&lt;br /&gt;
You can stop all server components with a single call to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop_all&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function will:&lt;br /&gt;
* Stop and free all server components.&lt;br /&gt;
* Free the shared address space.&lt;br /&gt;
* Return 0 on success, -1 on failure.&lt;br /&gt;
== Client Components ==&lt;br /&gt;
=== '''Adding client components''' ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Adding a TCP Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_client_create([ip],[port])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will opens a TCP connection to the client on the given ip and port, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
==== Adding an RTU Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_client_create([type],[port],[baudrate],[data bits],[stop bits],[parity])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will open an RTU connection to the client with the given parameters, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
=== Stopping client components ===&lt;br /&gt;
A specific client can be stopped by calling:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_client_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate client component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reset the Modbus System ==&lt;br /&gt;
Sometimes, a user may wish to stop all server and client components at once, and reset the Modbus system (for example, when a user want to initialize a different Modbus system). To do that, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_reset&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function:&lt;br /&gt;
* Stops all running servers and clients.&lt;br /&gt;
* Frees their memory.&lt;br /&gt;
* Frees the shared address space.&lt;br /&gt;
* Reset the handle counter.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reading and Writing ==&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
* Therefore, Servers and clients use different functions to read/write data from the address space.&lt;br /&gt;
=== '''Server Components''' ===&lt;br /&gt;
&amp;lt;hr&amp;gt;&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers and return them.&lt;br /&gt;
* When a read error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_REG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_READ_BIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_INREG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt; val = MB_SERVER_READ_INBIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data into the different types of registers.&lt;br /&gt;
* When a write error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Writing to holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_BIT([index],[new value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_INBIT([index],[value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| New value&lt;br /&gt;
| The value to write, must be from the appropriate type.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Error codes ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Invalid index.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Local server's address space isn't mapped yet.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to catch the register mutex.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to release the register mutex.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== '''Client Components''' ===&lt;br /&gt;
&amp;lt;hr&amp;gt;&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The read value is inserted into an existing variable from the appropriate type (long/double).&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_REG_LONG([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_BITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_LONG ([handle],[deviceID],[addr],[dest ptr]) &lt;br /&gt;
Val = MB_CLIENT_READ_INREG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_INBITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to read from.&lt;br /&gt;
|-&lt;br /&gt;
| Num of bits (Reading bits)&lt;br /&gt;
| The number of bits to read.&lt;br /&gt;
|-&lt;br /&gt;
| dest ptr / dest arr ptr&lt;br /&gt;
| The variable to store the read data. When reading bits, this must be an array of longs in the appropriate size (&amp;gt;= Num of bits).&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data from existing variables to the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Writing to Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_LONG([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_SHORT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_FLOAT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_DOUBLE([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_WRITE_BIT([handle],[deviceID],[addr],[src ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to start writing to.&lt;br /&gt;
|-&lt;br /&gt;
| src ptr&lt;br /&gt;
| The variable that stores the data to be written. This must be a variable from the appropriate type.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== '''Reading and Writing Summary''' ===&lt;br /&gt;
[[File:modbus;newAPI-readwriteSummary.jpg|850px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Modbus Configurator=&lt;br /&gt;
== Background ==&lt;br /&gt;
=== General ===&lt;br /&gt;
The Modbus Communication Scripts Generator ('''Modbus Configurator''') is a tool that allows you to map your softMC application variables to Modbus tags.&lt;br /&gt;
&lt;br /&gt;
'''Note''':	Tag access is defined from the HMI perspective. In other words:&lt;br /&gt;
* '''Read Access''' variables are written by the softMC to the Modbus address space.&lt;br /&gt;
* '''Write Access''' variables are read by the softMC from the Modbus address space.&lt;br /&gt;
&lt;br /&gt;
You can define whether a variable has Read Access, or Write Access. Currently, it is not possible to define a variable as having both Read Access and Write Access. However, all Write Access variables can be written once by the softMC upon system startup by a special routine that is generated in HMIMBMAP.LIB (see section below).&lt;br /&gt;
&lt;br /&gt;
The MCMBConfigurator creates three files:&lt;br /&gt;
* '''HMIMBMAP.LIB''' and '''HMIMBMAP.PRG''' files are MC-Basic scripts that are used to start a softMC task. These are default file names, which you can change, but must retain the 8.3 format. This task cyclically and indefinitely reads/writes Modbus tags according to access type. &lt;br /&gt;
* A '''.CSV''' format file that can be used by an HMI development environment, such as '''JMobile Studio''' or '''Indusoft''', to automatically import Modbus tags. You define the HMI development environment by selecting various Python scripts that will generate the .csv file.&lt;br /&gt;
=== Mapping Variables ===&lt;br /&gt;
* Variables destined to be mapped to Modbus tags must be defined as global variables by the '''common Shared''' declaration.&lt;br /&gt;
* In order to map the variables, the program must be loaded in the softMC.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
#Start the Modbus Configurator: from the ControlStudio toolbar, select '''Tools &amp;gt; Modbus Configurator'''. The Modbus Configurator tool will appear.&lt;br /&gt;
#From the top menu, Select '''Connection &amp;gt; Setting'''.&lt;br /&gt;
#'''Enter the MC's IP and port''' (default connection port is 5001), then '''click OK'''.&lt;br /&gt;
# From the top menu, Select '''Connection &amp;gt; Connect'''.&lt;br /&gt;
# Configure the Modbus Address Space&lt;br /&gt;
## From the top menu, Select '''Modbus Comm. Settings'''.&lt;br /&gt;
## In the '''General''' tab, Select the appropriate python script.&lt;br /&gt;
## In the '''Registers''' tab, enter the amount of registers needed per type, and the registers offset (Optional).&lt;br /&gt;
##* Notice: The maximum register number is 65536.&lt;br /&gt;
## In the '''Connections''' tab, add the server connections (TCP/RTU).&lt;br /&gt;
## Click '''OK'''.&lt;br /&gt;
# Map your variables&lt;br /&gt;
#* Once the Modbus Configurator is connected to softMC it gets updated with the complete list of all the global variables. Double-clicking on variables automatically maps them to Modbus tags in consecutive order. The automatic Modbus address and data type are displayed in the table, along with the Modbus address space area in which the data will be stored (Default: Holding Registers).&lt;br /&gt;
#* If a mapped variable is '''defined as CONST''', its access type will automatically set to &amp;quot;Read&amp;quot;. In such instances the access type cannot be changed. &amp;quot;Read Access variables are read only by the HMI; therefore the softMC only &amp;lt;u&amp;gt;writes&amp;lt;/u&amp;gt; them to the Modbus address space.&lt;br /&gt;
#* If a mapped variable is '''not defined as CONST''', it automatically appears with &amp;quot;Write&amp;quot; Access. '''Double-click on the access type''' to toggle the variable between Read Access and Write Access, and thus determine whether the variable will be read or written by softMC.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(4).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Generating and Using Scripts==&lt;br /&gt;
After you are done mapping variables and defining the access types, a snapshot of the current configuration must be saved in order to generate the Modbus-handling scripts.&lt;br /&gt;
&lt;br /&gt;
1. Click '''Files''', and then '''Save As'''.&lt;br /&gt;
&lt;br /&gt;
:The mapping is saved in an '''.mbas''' file.&lt;br /&gt;
&lt;br /&gt;
:If you makes changes after saving the .mbas file, the MBAS file indicator in the status bar will light up.&lt;br /&gt;
&lt;br /&gt;
2. To generate the product files, click '''Generate'''.&lt;br /&gt;
&lt;br /&gt;
:The Log windows will display Success messages.&lt;br /&gt;
&lt;br /&gt;
:The product files were created in the target folder you chose when saving the .mbas file.&lt;br /&gt;
&lt;br /&gt;
:The files HMIMBMAP.LIB and HMIMBMAP.PRG will automatically open in ControlStudio.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(5).png|600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Using the Modbus-Handling Scripts==&lt;br /&gt;
1. Using the ControlStudio File Manager, copy HMIMBMAP.LIB and HMIMBMAP.PRG to the softMC.&lt;br /&gt;
&lt;br /&gt;
'''Note''':	Before these files can be loaded and used, your application must be loaded, and all mapped variables must exist in the softMC memory.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(6).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Using the ControlStudio Terminal, load the library HMIMBMAP.LIB:&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.LIB&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Since HMIMBMAP.PRG imports this library it must not be loaded globally. This code can be executed wherever is convenient.&lt;br /&gt;
&lt;br /&gt;
2. Verify that the library was loaded successfully:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;?tasklist&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Start the Modbus communication task by loading the program:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.PRG&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
HMIMBMAP.PRG is defined as '''Program Continue''', therefore it starts automatically after it is loaded and it does not require an explicit StartTask command.&lt;br /&gt;
&lt;br /&gt;
Of course, HMIMBMAP.PRG can be loaded and executed only after HMIMBMAP.LIB is loaded. Therefore, you should add the following code to AUTOEXEC.PRG or wherever is convenient:&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.LIB&lt;br /&gt;
Load HMIMBMAP.PRG&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HMIMBMAP.PRG Explained==&lt;br /&gt;
The code:&lt;br /&gt;
&amp;lt;pre&amp;gt;import HMIMBMAP.LIB&lt;br /&gt;
Program Continue&lt;br /&gt;
	dim retVal as long = 0&lt;br /&gt;
	retVal = Init_Modbus&lt;br /&gt;
	while 1&lt;br /&gt;
		retVal = Read_Modbus_Registers&lt;br /&gt;
		retVal = Write_Modbus_Registers&lt;br /&gt;
		sleep 1&lt;br /&gt;
	end while&lt;br /&gt;
End Program&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The functions '''Init_Modbus''', '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are implemented in '''HMIMBMAP.LIB''', which is automatically generated by a Python script.&lt;br /&gt;
&lt;br /&gt;
The function '''Init_Modbus''' starts the Modbus server and then writes to the Modbus address space all the '''Write Access Variables''' (i.e., all the variables read by the softMC from the Modbus address space). This feature allows you to setup the system to start with an initialized Modbus address space before the HMI/PLC connects to it. The HMI/PLC can read the address space and initialize itself accordingly.&lt;br /&gt;
&lt;br /&gt;
The functions '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are invoked cyclically and indefinitely. '''Read_Modbus_Registers''' reads all the tags that are written by the HMI/PLC and updates the '''Write Access''' variables with new values, while '''Write_Modbus_Registers''' does the opposite.&lt;br /&gt;
&lt;br /&gt;
=HMI IDEs and .CSV Files=&lt;br /&gt;
Each line in the .csv file generated by the MCMBConfigurator file holds data about a single variable, such as Modbus address or data type.&lt;br /&gt;
 &lt;br /&gt;
This data can be used by an HMI IDE to import Modbus tags and associate them with HMI functionality.&lt;br /&gt;
&lt;br /&gt;
Different manufacturer IDEs use different .csv formatting; therefore, various Python scripts are used to create the specific .csv files suitable for a particular manufacturer IDE.&lt;br /&gt;
&lt;br /&gt;
==JMobile Studio==&lt;br /&gt;
Python script: '''JMobile_csv.py''' &lt;br /&gt;
&lt;br /&gt;
Default target .csv file name: '''JMobile_HMI.csv''' (user-definable)&lt;br /&gt;
&lt;br /&gt;
To import tags, perform the following procedure in JMobile Studio.&lt;br /&gt;
&lt;br /&gt;
===Define Protocol===&lt;br /&gt;
1. In the ProjectView pane, select '''Protocols'''.&lt;br /&gt;
&lt;br /&gt;
2. Click the blue '''+''' sign.&lt;br /&gt;
&lt;br /&gt;
3. From the list, select Modbus TCP.&lt;br /&gt;
&lt;br /&gt;
4. In the Modbus TCP configuration window, define: &lt;br /&gt;
&lt;br /&gt;
:IP Address: Set the IP address of your softMC.&lt;br /&gt;
&lt;br /&gt;
:PLC Models: Select '''Generic Modbus''' (0-based), meaning the softMC Modbus server starts addressing tags from 0.&lt;br /&gt;
&lt;br /&gt;
:Click '''OK'''.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(7).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
===Import Tags===&lt;br /&gt;
1. In the ProjectView pane, select '''Tags'''.&lt;br /&gt;
&lt;br /&gt;
2. From the list, select '''Modbus TCP''' protocol defined previously.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(8).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
3. Click the '''Import Tags''' button. &lt;br /&gt;
&lt;br /&gt;
4. Open the generated file '''JMobile_HMI.csv'''.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(9).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
5. Select the tags you want to add to your project, and click the ''Import tags'' button.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(10).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==AdvancedHMI==&lt;br /&gt;
AdvancedHMI is an open source project (http://www.advancedhmi.com/), which is downloaded as a Visual Basic project. You can then open the project, add widgets, compile, and run it.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(11).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Drag and drop '''ModbusTCPCom''' into MainForm.vb [Design].&lt;br /&gt;
&lt;br /&gt;
2. The driver appears the bottom of the screen (circled in green). &lt;br /&gt;
&lt;br /&gt;
:Click the driver, and then use the Properties pane (circled in red) to setup the IP address of the Modbus server.&lt;br /&gt;
&lt;br /&gt;
:For example, drag and drop DigitalPanelMeter and MomentaryButton into MainForm.vb [Design].&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(12).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
3. For both widgets, use the Properties pane to set the Modbus address that is associated with the variables from the softMC application.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(13).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
'''Note''':&lt;br /&gt;
::MC Modbus server addressing starts from '''40000'''.&lt;br /&gt;
::AdvancedHMI Modbus client addressing starts from '''40001'''.&lt;br /&gt;
::Prefix the address with the letter '''L'''.&lt;br /&gt;
&lt;br /&gt;
4. Save the project (Ctrl+S).&lt;br /&gt;
&lt;br /&gt;
5. Build the project (Ctrl+Shift+B).&lt;br /&gt;
&lt;br /&gt;
6. Run the project (F5).&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125912</id>
		<title>Modbus Communication API</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125912"/>
				<updated>2016-05-02T06:48:26Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: /* Getting Started */ Added instructions for automaed/manual load of the shared object&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
=== Basic Overview ===&lt;br /&gt;
* This describes how to set up Modbus communication for the softMC, and how to generate softMC scripts to handle Modbus communication.&lt;br /&gt;
* It is assumed you are familiar with the principles of Modbus communication, although some of them will be described in this page.&lt;br /&gt;
* It is also assumed your are familiar with the softMC, ControlStudio and MC-Basic programming.&lt;br /&gt;
&lt;br /&gt;
=== Modbus Communication Background ===&lt;br /&gt;
* A Motion Controller (MC) can act as a server (slave), a client (master) or both at the same time.&lt;br /&gt;
* Each MC connection (TCP/RTU) can be used either as a server component (if the connection is used by the MC’s server-side) or as a client component (if the connection is used by the MC’s client-side).&lt;br /&gt;
* Each component has its own parameters that defines it.&lt;br /&gt;
* When the MC acts as a server, all server components share the '''same''' memory address space, thus acting as one server with multiple connections.&lt;br /&gt;
* Each server (slave) on a Modbus network has its own deviceID, which is a number between 1 and 247.&lt;br /&gt;
&lt;br /&gt;
=== The Modbus server registers ===&lt;br /&gt;
* There are 4 types of registers in the Modbus Server address space:&lt;br /&gt;
*# Bits (1-bit registers)&lt;br /&gt;
*# Input Bits (1-bit READ-ONLY registers)&lt;br /&gt;
*# Holding Registers (16-bit registers)&lt;br /&gt;
*# Input Registers (16-bit READ-ONLY registers)&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
In order to get started in using the Modbus features:&lt;br /&gt;
# Download the required files, according to your system's type:&lt;br /&gt;
#* Required files for [[File:modbus_requiredFiles_x86.zip|modbus_X86.ZIP]].&lt;br /&gt;
#* Required files for ARM systems.&lt;br /&gt;
# Using the ControlStudio File Manager, Upload the following files to your MC:&lt;br /&gt;
#* mb_x86.O ''(for softMC7 )'' / mb_armA9.O ''(for softMC3)''&lt;br /&gt;
#* Modbus.lib&lt;br /&gt;
#* MB_Load.prg&lt;br /&gt;
#:[[File:modbus;newAPI-upload.jpg|850px]]&lt;br /&gt;
# Load MB_Load.prg by typing: &amp;lt;pre&amp;gt;Load MB_Load.prg&amp;lt;/pre&amp;gt;&lt;br /&gt;
#:This will load the mb_x86.O / mb_armA9.O, depending on your current system.&lt;br /&gt;
# '''Alternatively''', you can load the Object file manually by typing: &amp;lt;pre&amp;gt;Oload mb_x86.O&amp;lt;/pre&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
That's it! You're now ready to configure the Modbus system.&lt;br /&gt;
&lt;br /&gt;
== Initializing a Modbus Server ==&lt;br /&gt;
To initialize the Modbus server address space, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;?init_multi_server([bits],[input_bits],[holding registers],[input_registers])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The function prints &amp;quot;success&amp;quot; and returns 0 on success, or return an error code on failure.&lt;br /&gt;
* &amp;lt;u&amp;gt;'''Notice:'''&amp;lt;/u&amp;gt; You can call this method only if there are no active server components.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Memory allocation failure.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Some servers are still running and using an already mapped address space.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to create a modbus mapping.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Server Components ==&lt;br /&gt;
=== '''Adding server components''' ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Creating a TCP server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_server_create([port],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens a TCP connection to the server on port [port] with deviceID [deviceID], and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Failed to create main socket.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|}&lt;br /&gt;
==== Creating an RTU server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_server_create([type],[port],[baudrate],[data bits],[stop bits],[parity],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens an RTU connection with the given parameters, and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Invalid device string.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Invalid parity.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed opening RTU.&lt;br /&gt;
|-&lt;br /&gt;
| -5&lt;br /&gt;
| Failed allocating query buffer memory.&lt;br /&gt;
|-&lt;br /&gt;
| -6&lt;br /&gt;
| Failed to set RTU mode.&lt;br /&gt;
|-&lt;br /&gt;
| -7&lt;br /&gt;
| Unable to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -8&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|-&lt;br /&gt;
| -9&lt;br /&gt;
| The device is already in use by another system component.&lt;br /&gt;
|}&lt;br /&gt;
=== '''Stopping Server Components''' ===&lt;br /&gt;
==== Stopping a specific server component ====&lt;br /&gt;
You can stop a specific server component by passing its handle to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate server component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
==== Stopping all server components ====&lt;br /&gt;
You can stop all server components with a single call to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop_all&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function will:&lt;br /&gt;
* Stop and free all server components.&lt;br /&gt;
* Free the shared address space.&lt;br /&gt;
* Return 0 on success, -1 on failure.&lt;br /&gt;
== Client Components ==&lt;br /&gt;
=== '''Adding client components''' ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Adding a TCP Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_client_create([ip],[port])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will opens a TCP connection to the client on the given ip and port, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
==== Adding an RTU Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_client_create([type],[port],[baudrate],[data bits],[stop bits],[parity])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will open an RTU connection to the client with the given parameters, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
=== Stopping client components ===&lt;br /&gt;
A specific client can be stopped by calling:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_client_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate client component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reset the Modbus System ==&lt;br /&gt;
Sometimes, a user may wish to stop all server and client components at once, and reset the Modbus system (for example, when a user want to initialize a different Modbus system). To do that, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_reset&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function:&lt;br /&gt;
* Stops all running servers and clients.&lt;br /&gt;
* Frees their memory.&lt;br /&gt;
* Frees the shared address space.&lt;br /&gt;
* Reset the handle counter.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reading and Writing ==&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
* Therefore, Servers and clients use different functions to read/write data from the address space.&lt;br /&gt;
=== '''Server Components''' ===&lt;br /&gt;
&amp;lt;hr&amp;gt;&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers and return them.&lt;br /&gt;
* When a read error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_REG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_READ_BIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_INREG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt; val = MB_SERVER_READ_INBIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data into the different types of registers.&lt;br /&gt;
* When a write error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Writing to holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_BIT([index],[new value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_INBIT([index],[value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| New value&lt;br /&gt;
| The value to write, must be from the appropriate type.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Error codes ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Invalid index.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Local server's address space isn't mapped yet.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to catch the register mutex.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to release the register mutex.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== '''Client Components''' ===&lt;br /&gt;
&amp;lt;hr&amp;gt;&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The read value is inserted into an existing variable from the appropriate type (long/double).&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_REG_LONG([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_BITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_LONG ([handle],[deviceID],[addr],[dest ptr]) &lt;br /&gt;
Val = MB_CLIENT_READ_INREG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_INBITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to read from.&lt;br /&gt;
|-&lt;br /&gt;
| Num of bits (Reading bits)&lt;br /&gt;
| The number of bits to read.&lt;br /&gt;
|-&lt;br /&gt;
| dest ptr / dest arr ptr&lt;br /&gt;
| The variable to store the read data. When reading bits, this must be an array of longs in the appropriate size (&amp;gt;= Num of bits).&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data from existing variables to the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Writing to Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_LONG([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_SHORT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_FLOAT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_DOUBLE([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_WRITE_BIT([handle],[deviceID],[addr],[src ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to start writing to.&lt;br /&gt;
|-&lt;br /&gt;
| src ptr&lt;br /&gt;
| The variable that stores the data to be written. This must be a variable from the appropriate type.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== '''Reading and Writing Summary''' ===&lt;br /&gt;
[[File:modbus;newAPI-readwriteSummary.jpg|850px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Modbus Configurator=&lt;br /&gt;
== Background ==&lt;br /&gt;
=== General ===&lt;br /&gt;
The Modbus Communication Scripts Generator ('''Modbus Configurator''') is a tool that allows you to map your softMC application variables to Modbus tags.&lt;br /&gt;
&lt;br /&gt;
'''Note''':	Tag access is defined from the HMI perspective. In other words:&lt;br /&gt;
* '''Read Access''' variables are written by the softMC to the Modbus address space.&lt;br /&gt;
* '''Write Access''' variables are read by the softMC from the Modbus address space.&lt;br /&gt;
&lt;br /&gt;
You can define whether a variable has Read Access, or Write Access. Currently, it is not possible to define a variable as having both Read Access and Write Access. However, all Write Access variables can be written once by the softMC upon system startup by a special routine that is generated in HMIMBMAP.LIB (see section below).&lt;br /&gt;
&lt;br /&gt;
The MCMBConfigurator creates three files:&lt;br /&gt;
* '''HMIMBMAP.LIB''' and '''HMIMBMAP.PRG''' files are MC-Basic scripts that are used to start a softMC task. These are default file names, which you can change, but must retain the 8.3 format. This task cyclically and indefinitely reads/writes Modbus tags according to access type. &lt;br /&gt;
* A '''.CSV''' format file that can be used by an HMI development environment, such as '''JMobile Studio''' or '''Indusoft''', to automatically import Modbus tags. You define the HMI development environment by selecting various Python scripts that will generate the .csv file.&lt;br /&gt;
=== Mapping Variables ===&lt;br /&gt;
* Variables destined to be mapped to Modbus tags must be defined as global variables by the '''common Shared''' declaration.&lt;br /&gt;
* In order to map the variables, the program must be loaded in the softMC.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
#Start the Modbus Configurator: from the ControlStudio toolbar, select '''Tools &amp;gt; Modbus Configurator'''. The Modbus Configurator tool will appear.&lt;br /&gt;
#From the top menu, Select '''Connection &amp;gt; Setting'''.&lt;br /&gt;
#'''Enter the MC's IP and port''' (default connection port is 5001), then '''click OK'''.&lt;br /&gt;
# From the top menu, Select '''Connection &amp;gt; Connect'''.&lt;br /&gt;
# Configure the Modbus Address Space&lt;br /&gt;
## From the top menu, Select '''Modbus Comm. Settings'''.&lt;br /&gt;
## In the '''General''' tab, Select the appropriate python script.&lt;br /&gt;
## In the '''Registers''' tab, enter the amount of registers needed per type, and the registers offset (Optional).&lt;br /&gt;
##* Notice: The maximum register number is 65536.&lt;br /&gt;
## In the '''Connections''' tab, add the server connections (TCP/RTU).&lt;br /&gt;
## Click '''OK'''.&lt;br /&gt;
# Map your variables&lt;br /&gt;
#* Once the Modbus Configurator is connected to softMC it gets updated with the complete list of all the global variables. Double-clicking on variables automatically maps them to Modbus tags in consecutive order. The automatic Modbus address and data type are displayed in the table, along with the Modbus address space area in which the data will be stored (Default: Holding Registers).&lt;br /&gt;
#* If a mapped variable is '''defined as CONST''', its access type will automatically set to &amp;quot;Read&amp;quot;. In such instances the access type cannot be changed. &amp;quot;Read Access variables are read only by the HMI; therefore the softMC only &amp;lt;u&amp;gt;writes&amp;lt;/u&amp;gt; them to the Modbus address space.&lt;br /&gt;
#* If a mapped variable is '''not defined as CONST''', it automatically appears with &amp;quot;Write&amp;quot; Access. '''Double-click on the access type''' to toggle the variable between Read Access and Write Access, and thus determine whether the variable will be read or written by softMC.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(4).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Generating and Using Scripts==&lt;br /&gt;
After you are done mapping variables and defining the access types, a snapshot of the current configuration must be saved in order to generate the Modbus-handling scripts.&lt;br /&gt;
&lt;br /&gt;
1. Click '''Files''', and then '''Save As'''.&lt;br /&gt;
&lt;br /&gt;
:The mapping is saved in an '''.mbas''' file.&lt;br /&gt;
&lt;br /&gt;
:If you makes changes after saving the .mbas file, the MBAS file indicator in the status bar will light up.&lt;br /&gt;
&lt;br /&gt;
2. To generate the product files, click '''Generate'''.&lt;br /&gt;
&lt;br /&gt;
:The Log windows will display Success messages.&lt;br /&gt;
&lt;br /&gt;
:The product files were created in the target folder you chose when saving the .mbas file.&lt;br /&gt;
&lt;br /&gt;
:The files HMIMBMAP.LIB and HMIMBMAP.PRG will automatically open in ControlStudio.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(5).png|600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Using the Modbus-Handling Scripts==&lt;br /&gt;
1. Using the ControlStudio File Manager, copy HMIMBMAP.LIB and HMIMBMAP.PRG to the softMC.&lt;br /&gt;
&lt;br /&gt;
'''Note''':	Before these files can be loaded and used, your application must be loaded, and all mapped variables must exist in the softMC memory.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(6).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Using the ControlStudio Terminal, load the library HMIMBMAP.LIB:&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.LIB&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Since HMIMBMAP.PRG imports this library it must not be loaded globally. This code can be executed wherever is convenient.&lt;br /&gt;
&lt;br /&gt;
2. Verify that the library was loaded successfully:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;?tasklist&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Start the Modbus communication task by loading the program:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.PRG&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
HMIMBMAP.PRG is defined as '''Program Continue''', therefore it starts automatically after it is loaded and it does not require an explicit StartTask command.&lt;br /&gt;
&lt;br /&gt;
Of course, HMIMBMAP.PRG can be loaded and executed only after HMIMBMAP.LIB is loaded. Therefore, you should add the following code to AUTOEXEC.PRG or wherever is convenient:&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.LIB&lt;br /&gt;
Load HMIMBMAP.PRG&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HMIMBMAP.PRG Explained==&lt;br /&gt;
The code:&lt;br /&gt;
&amp;lt;pre&amp;gt;import HMIMBMAP.LIB&lt;br /&gt;
Program Continue&lt;br /&gt;
	dim retVal as long = 0&lt;br /&gt;
	retVal = Init_Modbus&lt;br /&gt;
	while 1&lt;br /&gt;
		retVal = Read_Modbus_Registers&lt;br /&gt;
		retVal = Write_Modbus_Registers&lt;br /&gt;
		sleep 1&lt;br /&gt;
	end while&lt;br /&gt;
End Program&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The functions '''Init_Modbus''', '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are implemented in '''HMIMBMAP.LIB''', which is automatically generated by a Python script.&lt;br /&gt;
&lt;br /&gt;
The function '''Init_Modbus''' starts the Modbus server and then writes to the Modbus address space all the '''Write Access Variables''' (i.e., all the variables read by the softMC from the Modbus address space). This feature allows you to setup the system to start with an initialized Modbus address space before the HMI/PLC connects to it. The HMI/PLC can read the address space and initialize itself accordingly.&lt;br /&gt;
&lt;br /&gt;
The functions '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are invoked cyclically and indefinitely. '''Read_Modbus_Registers''' reads all the tags that are written by the HMI/PLC and updates the '''Write Access''' variables with new values, while '''Write_Modbus_Registers''' does the opposite.&lt;br /&gt;
&lt;br /&gt;
=HMI IDEs and .CSV Files=&lt;br /&gt;
Each line in the .csv file generated by the MCMBConfigurator file holds data about a single variable, such as Modbus address or data type.&lt;br /&gt;
 &lt;br /&gt;
This data can be used by an HMI IDE to import Modbus tags and associate them with HMI functionality.&lt;br /&gt;
&lt;br /&gt;
Different manufacturer IDEs use different .csv formatting; therefore, various Python scripts are used to create the specific .csv files suitable for a particular manufacturer IDE.&lt;br /&gt;
&lt;br /&gt;
==JMobile Studio==&lt;br /&gt;
Python script: '''JMobile_csv.py''' &lt;br /&gt;
&lt;br /&gt;
Default target .csv file name: '''JMobile_HMI.csv''' (user-definable)&lt;br /&gt;
&lt;br /&gt;
To import tags, perform the following procedure in JMobile Studio.&lt;br /&gt;
&lt;br /&gt;
===Define Protocol===&lt;br /&gt;
1. In the ProjectView pane, select '''Protocols'''.&lt;br /&gt;
&lt;br /&gt;
2. Click the blue '''+''' sign.&lt;br /&gt;
&lt;br /&gt;
3. From the list, select Modbus TCP.&lt;br /&gt;
&lt;br /&gt;
4. In the Modbus TCP configuration window, define: &lt;br /&gt;
&lt;br /&gt;
:IP Address: Set the IP address of your softMC.&lt;br /&gt;
&lt;br /&gt;
:PLC Models: Select '''Generic Modbus''' (0-based), meaning the softMC Modbus server starts addressing tags from 0.&lt;br /&gt;
&lt;br /&gt;
:Click '''OK'''.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(7).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
===Import Tags===&lt;br /&gt;
1. In the ProjectView pane, select '''Tags'''.&lt;br /&gt;
&lt;br /&gt;
2. From the list, select '''Modbus TCP''' protocol defined previously.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(8).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
3. Click the '''Import Tags''' button. &lt;br /&gt;
&lt;br /&gt;
4. Open the generated file '''JMobile_HMI.csv'''.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(9).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
5. Select the tags you want to add to your project, and click the ''Import tags'' button.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(10).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==AdvancedHMI==&lt;br /&gt;
AdvancedHMI is an open source project (http://www.advancedhmi.com/), which is downloaded as a Visual Basic project. You can then open the project, add widgets, compile, and run it.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(11).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Drag and drop '''ModbusTCPCom''' into MainForm.vb [Design].&lt;br /&gt;
&lt;br /&gt;
2. The driver appears the bottom of the screen (circled in green). &lt;br /&gt;
&lt;br /&gt;
:Click the driver, and then use the Properties pane (circled in red) to setup the IP address of the Modbus server.&lt;br /&gt;
&lt;br /&gt;
:For example, drag and drop DigitalPanelMeter and MomentaryButton into MainForm.vb [Design].&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(12).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
3. For both widgets, use the Properties pane to set the Modbus address that is associated with the variables from the softMC application.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(13).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
'''Note''':&lt;br /&gt;
::MC Modbus server addressing starts from '''40000'''.&lt;br /&gt;
::AdvancedHMI Modbus client addressing starts from '''40001'''.&lt;br /&gt;
::Prefix the address with the letter '''L'''.&lt;br /&gt;
&lt;br /&gt;
4. Save the project (Ctrl+S).&lt;br /&gt;
&lt;br /&gt;
5. Build the project (Ctrl+Shift+B).&lt;br /&gt;
&lt;br /&gt;
6. Run the project (F5).&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125911</id>
		<title>Modbus Communication API</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125911"/>
				<updated>2016-05-02T06:36:36Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: /* Getting Started */ Added instructions for the new Modbus Comm. Settings window.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
=== Basic Overview ===&lt;br /&gt;
* This describes how to set up Modbus communication for the softMC, and how to generate softMC scripts to handle Modbus communication.&lt;br /&gt;
* It is assumed you are familiar with the principles of Modbus communication, although some of them will be described in this page.&lt;br /&gt;
* It is also assumed your are familiar with the softMC, ControlStudio and MC-Basic programming.&lt;br /&gt;
&lt;br /&gt;
=== Modbus Communication Background ===&lt;br /&gt;
* A Motion Controller (MC) can act as a server (slave), a client (master) or both at the same time.&lt;br /&gt;
* Each MC connection (TCP/RTU) can be used either as a server component (if the connection is used by the MC’s server-side) or as a client component (if the connection is used by the MC’s client-side).&lt;br /&gt;
* Each component has its own parameters that defines it.&lt;br /&gt;
* When the MC acts as a server, all server components share the '''same''' memory address space, thus acting as one server with multiple connections.&lt;br /&gt;
* Each server (slave) on a Modbus network has its own deviceID, which is a number between 1 and 247.&lt;br /&gt;
&lt;br /&gt;
=== The Modbus server registers ===&lt;br /&gt;
* There are 4 types of registers in the Modbus Server address space:&lt;br /&gt;
*# Bits (1-bit registers)&lt;br /&gt;
*# Input Bits (1-bit READ-ONLY registers)&lt;br /&gt;
*# Holding Registers (16-bit registers)&lt;br /&gt;
*# Input Registers (16-bit READ-ONLY registers)&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
In order to get started in using the Modbus features:&lt;br /&gt;
# Download the required files, according to your system's type:&lt;br /&gt;
#* Required files for [[File:modbus_requiredFiles_x86.zip|modbus_X86.ZIP]].&lt;br /&gt;
#* Required files for ARM systems.&lt;br /&gt;
# Using the ControlStudio File Manager, Upload the following files to your MC:&lt;br /&gt;
#* mb_x86.O ''(for softMC7 )'' / mb_armA9.O ''(for softMC3)''&lt;br /&gt;
#* Modbus.lib&lt;br /&gt;
#* MB_Loader.prg&lt;br /&gt;
#:[[File:modbus;newAPI-upload.jpg|850px]]&lt;br /&gt;
# Run MB_Loader.prg&lt;br /&gt;
&lt;br /&gt;
That's it! You're now ready to configure the Modbus system.&lt;br /&gt;
&lt;br /&gt;
== Initializing a Modbus Server ==&lt;br /&gt;
To initialize the Modbus server address space, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;?init_multi_server([bits],[input_bits],[holding registers],[input_registers])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The function prints &amp;quot;success&amp;quot; and returns 0 on success, or return an error code on failure.&lt;br /&gt;
* &amp;lt;u&amp;gt;'''Notice:'''&amp;lt;/u&amp;gt; You can call this method only if there are no active server components.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Memory allocation failure.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Some servers are still running and using an already mapped address space.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to create a modbus mapping.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Server Components ==&lt;br /&gt;
=== '''Adding server components''' ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Creating a TCP server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_server_create([port],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens a TCP connection to the server on port [port] with deviceID [deviceID], and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Failed to create main socket.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|}&lt;br /&gt;
==== Creating an RTU server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_server_create([type],[port],[baudrate],[data bits],[stop bits],[parity],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens an RTU connection with the given parameters, and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Invalid device string.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Invalid parity.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed opening RTU.&lt;br /&gt;
|-&lt;br /&gt;
| -5&lt;br /&gt;
| Failed allocating query buffer memory.&lt;br /&gt;
|-&lt;br /&gt;
| -6&lt;br /&gt;
| Failed to set RTU mode.&lt;br /&gt;
|-&lt;br /&gt;
| -7&lt;br /&gt;
| Unable to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -8&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|-&lt;br /&gt;
| -9&lt;br /&gt;
| The device is already in use by another system component.&lt;br /&gt;
|}&lt;br /&gt;
=== '''Stopping Server Components''' ===&lt;br /&gt;
==== Stopping a specific server component ====&lt;br /&gt;
You can stop a specific server component by passing its handle to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate server component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
==== Stopping all server components ====&lt;br /&gt;
You can stop all server components with a single call to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop_all&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function will:&lt;br /&gt;
* Stop and free all server components.&lt;br /&gt;
* Free the shared address space.&lt;br /&gt;
* Return 0 on success, -1 on failure.&lt;br /&gt;
== Client Components ==&lt;br /&gt;
=== '''Adding client components''' ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Adding a TCP Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_client_create([ip],[port])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will opens a TCP connection to the client on the given ip and port, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
==== Adding an RTU Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_client_create([type],[port],[baudrate],[data bits],[stop bits],[parity])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will open an RTU connection to the client with the given parameters, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
=== Stopping client components ===&lt;br /&gt;
A specific client can be stopped by calling:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_client_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate client component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reset the Modbus System ==&lt;br /&gt;
Sometimes, a user may wish to stop all server and client components at once, and reset the Modbus system (for example, when a user want to initialize a different Modbus system). To do that, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_reset&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function:&lt;br /&gt;
* Stops all running servers and clients.&lt;br /&gt;
* Frees their memory.&lt;br /&gt;
* Frees the shared address space.&lt;br /&gt;
* Reset the handle counter.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reading and Writing ==&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
* Therefore, Servers and clients use different functions to read/write data from the address space.&lt;br /&gt;
=== '''Server Components''' ===&lt;br /&gt;
&amp;lt;hr&amp;gt;&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers and return them.&lt;br /&gt;
* When a read error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_REG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_READ_BIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_INREG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt; val = MB_SERVER_READ_INBIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data into the different types of registers.&lt;br /&gt;
* When a write error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Writing to holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_BIT([index],[new value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_INBIT([index],[value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| New value&lt;br /&gt;
| The value to write, must be from the appropriate type.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Error codes ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Invalid index.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Local server's address space isn't mapped yet.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to catch the register mutex.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to release the register mutex.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== '''Client Components''' ===&lt;br /&gt;
&amp;lt;hr&amp;gt;&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The read value is inserted into an existing variable from the appropriate type (long/double).&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_REG_LONG([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_BITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_LONG ([handle],[deviceID],[addr],[dest ptr]) &lt;br /&gt;
Val = MB_CLIENT_READ_INREG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_INBITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to read from.&lt;br /&gt;
|-&lt;br /&gt;
| Num of bits (Reading bits)&lt;br /&gt;
| The number of bits to read.&lt;br /&gt;
|-&lt;br /&gt;
| dest ptr / dest arr ptr&lt;br /&gt;
| The variable to store the read data. When reading bits, this must be an array of longs in the appropriate size (&amp;gt;= Num of bits).&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data from existing variables to the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Writing to Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_LONG([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_SHORT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_FLOAT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_DOUBLE([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_WRITE_BIT([handle],[deviceID],[addr],[src ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to start writing to.&lt;br /&gt;
|-&lt;br /&gt;
| src ptr&lt;br /&gt;
| The variable that stores the data to be written. This must be a variable from the appropriate type.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== '''Reading and Writing Summary''' ===&lt;br /&gt;
[[File:modbus;newAPI-readwriteSummary.jpg|850px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Modbus Configurator=&lt;br /&gt;
== Background ==&lt;br /&gt;
=== General ===&lt;br /&gt;
The Modbus Communication Scripts Generator ('''Modbus Configurator''') is a tool that allows you to map your softMC application variables to Modbus tags.&lt;br /&gt;
&lt;br /&gt;
'''Note''':	Tag access is defined from the HMI perspective. In other words:&lt;br /&gt;
* '''Read Access''' variables are written by the softMC to the Modbus address space.&lt;br /&gt;
* '''Write Access''' variables are read by the softMC from the Modbus address space.&lt;br /&gt;
&lt;br /&gt;
You can define whether a variable has Read Access, or Write Access. Currently, it is not possible to define a variable as having both Read Access and Write Access. However, all Write Access variables can be written once by the softMC upon system startup by a special routine that is generated in HMIMBMAP.LIB (see section below).&lt;br /&gt;
&lt;br /&gt;
The MCMBConfigurator creates three files:&lt;br /&gt;
* '''HMIMBMAP.LIB''' and '''HMIMBMAP.PRG''' files are MC-Basic scripts that are used to start a softMC task. These are default file names, which you can change, but must retain the 8.3 format. This task cyclically and indefinitely reads/writes Modbus tags according to access type. &lt;br /&gt;
* A '''.CSV''' format file that can be used by an HMI development environment, such as '''JMobile Studio''' or '''Indusoft''', to automatically import Modbus tags. You define the HMI development environment by selecting various Python scripts that will generate the .csv file.&lt;br /&gt;
=== Mapping Variables ===&lt;br /&gt;
* Variables destined to be mapped to Modbus tags must be defined as global variables by the '''common Shared''' declaration.&lt;br /&gt;
* In order to map the variables, the program must be loaded in the softMC.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
#Start the Modbus Configurator: from the ControlStudio toolbar, select '''Tools &amp;gt; Modbus Configurator'''. The Modbus Configurator tool will appear.&lt;br /&gt;
#From the top menu, Select '''Connection &amp;gt; Setting'''.&lt;br /&gt;
#'''Enter the MC's IP and port''' (default connection port is 5001), then '''click OK'''.&lt;br /&gt;
# From the top menu, Select '''Connection &amp;gt; Connect'''.&lt;br /&gt;
# Configure the Modbus Address Space&lt;br /&gt;
## From the top menu, Select '''Modbus Comm. Settings'''.&lt;br /&gt;
## In the '''General''' tab, Select the appropriate python script.&lt;br /&gt;
## In the '''Registers''' tab, enter the amount of registers needed per type, and the registers offset (Optional).&lt;br /&gt;
##* Notice: The maximum register number is 65536.&lt;br /&gt;
## In the '''Connections''' tab, add the server connections (TCP/RTU).&lt;br /&gt;
## Click '''OK'''.&lt;br /&gt;
# Map your variables&lt;br /&gt;
#* Once the Modbus Configurator is connected to softMC it gets updated with the complete list of all the global variables. Double-clicking on variables automatically maps them to Modbus tags in consecutive order. The automatic Modbus address and data type are displayed in the table, along with the Modbus address space area in which the data will be stored (Default: Holding Registers).&lt;br /&gt;
#* If a mapped variable is '''defined as CONST''', its access type will automatically set to &amp;quot;Read&amp;quot;. In such instances the access type cannot be changed. &amp;quot;Read Access variables are read only by the HMI; therefore the softMC only &amp;lt;u&amp;gt;writes&amp;lt;/u&amp;gt; them to the Modbus address space.&lt;br /&gt;
#* If a mapped variable is '''not defined as CONST''', it automatically appears with &amp;quot;Write&amp;quot; Access. '''Double-click on the access type''' to toggle the variable between Read Access and Write Access, and thus determine whether the variable will be read or written by softMC.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(4).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Generating and Using Scripts==&lt;br /&gt;
After you are done mapping variables and defining the access types, a snapshot of the current configuration must be saved in order to generate the Modbus-handling scripts.&lt;br /&gt;
&lt;br /&gt;
1. Click '''Files''', and then '''Save As'''.&lt;br /&gt;
&lt;br /&gt;
:The mapping is saved in an '''.mbas''' file.&lt;br /&gt;
&lt;br /&gt;
:If you makes changes after saving the .mbas file, the MBAS file indicator in the status bar will light up.&lt;br /&gt;
&lt;br /&gt;
2. To generate the product files, click '''Generate'''.&lt;br /&gt;
&lt;br /&gt;
:The Log windows will display Success messages.&lt;br /&gt;
&lt;br /&gt;
:The product files were created in the target folder you chose when saving the .mbas file.&lt;br /&gt;
&lt;br /&gt;
:The files HMIMBMAP.LIB and HMIMBMAP.PRG will automatically open in ControlStudio.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(5).png|600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Using the Modbus-Handling Scripts==&lt;br /&gt;
1. Using the ControlStudio File Manager, copy HMIMBMAP.LIB and HMIMBMAP.PRG to the softMC.&lt;br /&gt;
&lt;br /&gt;
'''Note''':	Before these files can be loaded and used, your application must be loaded, and all mapped variables must exist in the softMC memory.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(6).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Using the ControlStudio Terminal, load the library HMIMBMAP.LIB:&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.LIB&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Since HMIMBMAP.PRG imports this library it must not be loaded globally. This code can be executed wherever is convenient.&lt;br /&gt;
&lt;br /&gt;
2. Verify that the library was loaded successfully:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;?tasklist&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Start the Modbus communication task by loading the program:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.PRG&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
HMIMBMAP.PRG is defined as '''Program Continue''', therefore it starts automatically after it is loaded and it does not require an explicit StartTask command.&lt;br /&gt;
&lt;br /&gt;
Of course, HMIMBMAP.PRG can be loaded and executed only after HMIMBMAP.LIB is loaded. Therefore, you should add the following code to AUTOEXEC.PRG or wherever is convenient:&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.LIB&lt;br /&gt;
Load HMIMBMAP.PRG&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HMIMBMAP.PRG Explained==&lt;br /&gt;
The code:&lt;br /&gt;
&amp;lt;pre&amp;gt;import HMIMBMAP.LIB&lt;br /&gt;
Program Continue&lt;br /&gt;
	dim retVal as long = 0&lt;br /&gt;
	retVal = Init_Modbus&lt;br /&gt;
	while 1&lt;br /&gt;
		retVal = Read_Modbus_Registers&lt;br /&gt;
		retVal = Write_Modbus_Registers&lt;br /&gt;
		sleep 1&lt;br /&gt;
	end while&lt;br /&gt;
End Program&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The functions '''Init_Modbus''', '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are implemented in '''HMIMBMAP.LIB''', which is automatically generated by a Python script.&lt;br /&gt;
&lt;br /&gt;
The function '''Init_Modbus''' starts the Modbus server and then writes to the Modbus address space all the '''Write Access Variables''' (i.e., all the variables read by the softMC from the Modbus address space). This feature allows you to setup the system to start with an initialized Modbus address space before the HMI/PLC connects to it. The HMI/PLC can read the address space and initialize itself accordingly.&lt;br /&gt;
&lt;br /&gt;
The functions '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are invoked cyclically and indefinitely. '''Read_Modbus_Registers''' reads all the tags that are written by the HMI/PLC and updates the '''Write Access''' variables with new values, while '''Write_Modbus_Registers''' does the opposite.&lt;br /&gt;
&lt;br /&gt;
=HMI IDEs and .CSV Files=&lt;br /&gt;
Each line in the .csv file generated by the MCMBConfigurator file holds data about a single variable, such as Modbus address or data type.&lt;br /&gt;
 &lt;br /&gt;
This data can be used by an HMI IDE to import Modbus tags and associate them with HMI functionality.&lt;br /&gt;
&lt;br /&gt;
Different manufacturer IDEs use different .csv formatting; therefore, various Python scripts are used to create the specific .csv files suitable for a particular manufacturer IDE.&lt;br /&gt;
&lt;br /&gt;
==JMobile Studio==&lt;br /&gt;
Python script: '''JMobile_csv.py''' &lt;br /&gt;
&lt;br /&gt;
Default target .csv file name: '''JMobile_HMI.csv''' (user-definable)&lt;br /&gt;
&lt;br /&gt;
To import tags, perform the following procedure in JMobile Studio.&lt;br /&gt;
&lt;br /&gt;
===Define Protocol===&lt;br /&gt;
1. In the ProjectView pane, select '''Protocols'''.&lt;br /&gt;
&lt;br /&gt;
2. Click the blue '''+''' sign.&lt;br /&gt;
&lt;br /&gt;
3. From the list, select Modbus TCP.&lt;br /&gt;
&lt;br /&gt;
4. In the Modbus TCP configuration window, define: &lt;br /&gt;
&lt;br /&gt;
:IP Address: Set the IP address of your softMC.&lt;br /&gt;
&lt;br /&gt;
:PLC Models: Select '''Generic Modbus''' (0-based), meaning the softMC Modbus server starts addressing tags from 0.&lt;br /&gt;
&lt;br /&gt;
:Click '''OK'''.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(7).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
===Import Tags===&lt;br /&gt;
1. In the ProjectView pane, select '''Tags'''.&lt;br /&gt;
&lt;br /&gt;
2. From the list, select '''Modbus TCP''' protocol defined previously.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(8).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
3. Click the '''Import Tags''' button. &lt;br /&gt;
&lt;br /&gt;
4. Open the generated file '''JMobile_HMI.csv'''.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(9).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
5. Select the tags you want to add to your project, and click the ''Import tags'' button.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(10).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==AdvancedHMI==&lt;br /&gt;
AdvancedHMI is an open source project (http://www.advancedhmi.com/), which is downloaded as a Visual Basic project. You can then open the project, add widgets, compile, and run it.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(11).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Drag and drop '''ModbusTCPCom''' into MainForm.vb [Design].&lt;br /&gt;
&lt;br /&gt;
2. The driver appears the bottom of the screen (circled in green). &lt;br /&gt;
&lt;br /&gt;
:Click the driver, and then use the Properties pane (circled in red) to setup the IP address of the Modbus server.&lt;br /&gt;
&lt;br /&gt;
:For example, drag and drop DigitalPanelMeter and MomentaryButton into MainForm.vb [Design].&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(12).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
3. For both widgets, use the Properties pane to set the Modbus address that is associated with the variables from the softMC application.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(13).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
'''Note''':&lt;br /&gt;
::MC Modbus server addressing starts from '''40000'''.&lt;br /&gt;
::AdvancedHMI Modbus client addressing starts from '''40001'''.&lt;br /&gt;
::Prefix the address with the letter '''L'''.&lt;br /&gt;
&lt;br /&gt;
4. Save the project (Ctrl+S).&lt;br /&gt;
&lt;br /&gt;
5. Build the project (Ctrl+Shift+B).&lt;br /&gt;
&lt;br /&gt;
6. Run the project (F5).&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125910</id>
		<title>Modbus Communication API</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125910"/>
				<updated>2016-05-02T06:20:32Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: /* Modbus Configurator */ Updated with new configurator options&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
=== Basic Overview ===&lt;br /&gt;
* This describes how to set up Modbus communication for the softMC, and how to generate softMC scripts to handle Modbus communication.&lt;br /&gt;
* It is assumed you are familiar with the principles of Modbus communication, although some of them will be described in this page.&lt;br /&gt;
* It is also assumed your are familiar with the softMC, ControlStudio and MC-Basic programming.&lt;br /&gt;
&lt;br /&gt;
=== Modbus Communication Background ===&lt;br /&gt;
* A Motion Controller (MC) can act as a server (slave), a client (master) or both at the same time.&lt;br /&gt;
* Each MC connection (TCP/RTU) can be used either as a server component (if the connection is used by the MC’s server-side) or as a client component (if the connection is used by the MC’s client-side).&lt;br /&gt;
* Each component has its own parameters that defines it.&lt;br /&gt;
* When the MC acts as a server, all server components share the '''same''' memory address space, thus acting as one server with multiple connections.&lt;br /&gt;
* Each server (slave) on a Modbus network has its own deviceID, which is a number between 1 and 247.&lt;br /&gt;
&lt;br /&gt;
=== The Modbus server registers ===&lt;br /&gt;
* There are 4 types of registers in the Modbus Server address space:&lt;br /&gt;
*# Bits (1-bit registers)&lt;br /&gt;
*# Input Bits (1-bit READ-ONLY registers)&lt;br /&gt;
*# Holding Registers (16-bit registers)&lt;br /&gt;
*# Input Registers (16-bit READ-ONLY registers)&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
In order to get started in using the Modbus features:&lt;br /&gt;
# Download the required files, according to your system's type:&lt;br /&gt;
#* Required files for [[File:modbus_requiredFiles_x86.zip|modbus_X86.ZIP]].&lt;br /&gt;
#* Required files for ARM systems.&lt;br /&gt;
# Using the ControlStudio File Manager, Upload the following files to your MC:&lt;br /&gt;
#* mb_x86.O ''(for softMC7 )'' / mb_armA9.O ''(for softMC3)''&lt;br /&gt;
#* Modbus.lib&lt;br /&gt;
#* MB_Loader.prg&lt;br /&gt;
#:[[File:modbus;newAPI-upload.jpg|850px]]&lt;br /&gt;
# Run MB_Loader.prg&lt;br /&gt;
&lt;br /&gt;
That's it! You're now ready to configure the Modbus system.&lt;br /&gt;
&lt;br /&gt;
== Initializing a Modbus Server ==&lt;br /&gt;
To initialize the Modbus server address space, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;?init_multi_server([bits],[input_bits],[holding registers],[input_registers])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The function prints &amp;quot;success&amp;quot; and returns 0 on success, or return an error code on failure.&lt;br /&gt;
* &amp;lt;u&amp;gt;'''Notice:'''&amp;lt;/u&amp;gt; You can call this method only if there are no active server components.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Memory allocation failure.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Some servers are still running and using an already mapped address space.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to create a modbus mapping.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Server Components ==&lt;br /&gt;
=== '''Adding server components''' ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Creating a TCP server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_server_create([port],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens a TCP connection to the server on port [port] with deviceID [deviceID], and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Failed to create main socket.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|}&lt;br /&gt;
==== Creating an RTU server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_server_create([type],[port],[baudrate],[data bits],[stop bits],[parity],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens an RTU connection with the given parameters, and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Invalid device string.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Invalid parity.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed opening RTU.&lt;br /&gt;
|-&lt;br /&gt;
| -5&lt;br /&gt;
| Failed allocating query buffer memory.&lt;br /&gt;
|-&lt;br /&gt;
| -6&lt;br /&gt;
| Failed to set RTU mode.&lt;br /&gt;
|-&lt;br /&gt;
| -7&lt;br /&gt;
| Unable to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -8&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|-&lt;br /&gt;
| -9&lt;br /&gt;
| The device is already in use by another system component.&lt;br /&gt;
|}&lt;br /&gt;
=== '''Stopping Server Components''' ===&lt;br /&gt;
==== Stopping a specific server component ====&lt;br /&gt;
You can stop a specific server component by passing its handle to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate server component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
==== Stopping all server components ====&lt;br /&gt;
You can stop all server components with a single call to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop_all&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function will:&lt;br /&gt;
* Stop and free all server components.&lt;br /&gt;
* Free the shared address space.&lt;br /&gt;
* Return 0 on success, -1 on failure.&lt;br /&gt;
== Client Components ==&lt;br /&gt;
=== '''Adding client components''' ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Adding a TCP Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_client_create([ip],[port])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will opens a TCP connection to the client on the given ip and port, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
==== Adding an RTU Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_client_create([type],[port],[baudrate],[data bits],[stop bits],[parity])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will open an RTU connection to the client with the given parameters, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
=== Stopping client components ===&lt;br /&gt;
A specific client can be stopped by calling:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_client_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate client component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reset the Modbus System ==&lt;br /&gt;
Sometimes, a user may wish to stop all server and client components at once, and reset the Modbus system (for example, when a user want to initialize a different Modbus system). To do that, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_reset&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function:&lt;br /&gt;
* Stops all running servers and clients.&lt;br /&gt;
* Frees their memory.&lt;br /&gt;
* Frees the shared address space.&lt;br /&gt;
* Reset the handle counter.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reading and Writing ==&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
* Therefore, Servers and clients use different functions to read/write data from the address space.&lt;br /&gt;
=== '''Server Components''' ===&lt;br /&gt;
&amp;lt;hr&amp;gt;&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers and return them.&lt;br /&gt;
* When a read error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_REG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_READ_BIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_INREG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt; val = MB_SERVER_READ_INBIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data into the different types of registers.&lt;br /&gt;
* When a write error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Writing to holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_BIT([index],[new value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_INBIT([index],[value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| New value&lt;br /&gt;
| The value to write, must be from the appropriate type.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Error codes ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Invalid index.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Local server's address space isn't mapped yet.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to catch the register mutex.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to release the register mutex.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== '''Client Components''' ===&lt;br /&gt;
&amp;lt;hr&amp;gt;&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The read value is inserted into an existing variable from the appropriate type (long/double).&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_REG_LONG([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_BITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_LONG ([handle],[deviceID],[addr],[dest ptr]) &lt;br /&gt;
Val = MB_CLIENT_READ_INREG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_INBITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to read from.&lt;br /&gt;
|-&lt;br /&gt;
| Num of bits (Reading bits)&lt;br /&gt;
| The number of bits to read.&lt;br /&gt;
|-&lt;br /&gt;
| dest ptr / dest arr ptr&lt;br /&gt;
| The variable to store the read data. When reading bits, this must be an array of longs in the appropriate size (&amp;gt;= Num of bits).&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data from existing variables to the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Writing to Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_LONG([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_SHORT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_FLOAT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_DOUBLE([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_WRITE_BIT([handle],[deviceID],[addr],[src ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to start writing to.&lt;br /&gt;
|-&lt;br /&gt;
| src ptr&lt;br /&gt;
| The variable that stores the data to be written. This must be a variable from the appropriate type.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== '''Reading and Writing Summary''' ===&lt;br /&gt;
[[File:modbus;newAPI-readwriteSummary.jpg|850px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Modbus Configurator=&lt;br /&gt;
== Background ==&lt;br /&gt;
=== General ===&lt;br /&gt;
The Modbus Communication Scripts Generator ('''Modbus Configurator''') is a tool that allows you to map your softMC application variables to Modbus tags.&lt;br /&gt;
&lt;br /&gt;
'''Note''':	Tag access is defined from the HMI perspective. In other words:&lt;br /&gt;
* '''Read Access''' variables are written by the softMC to the Modbus address space.&lt;br /&gt;
* '''Write Access''' variables are read by the softMC from the Modbus address space.&lt;br /&gt;
&lt;br /&gt;
You can define whether a variable has Read Access, or Write Access. Currently, it is not possible to define a variable as having both Read Access and Write Access. However, all Write Access variables can be written once by the softMC upon system startup by a special routine that is generated in HMIMBMAP.LIB (see section below).&lt;br /&gt;
&lt;br /&gt;
The MCMBConfigurator creates three files:&lt;br /&gt;
* '''HMIMBMAP.LIB''' and '''HMIMBMAP.PRG''' files are MC-Basic scripts that are used to start a softMC task. These are default file names, which you can change, but must retain the 8.3 format. This task cyclically and indefinitely reads/writes Modbus tags according to access type. &lt;br /&gt;
* A '''.CSV''' format file that can be used by an HMI development environment, such as '''JMobile Studio''' or '''Indusoft''', to automatically import Modbus tags. You define the HMI development environment by selecting various Python scripts that will generate the .csv file.&lt;br /&gt;
=== Mapping Variables ===&lt;br /&gt;
* Variables destined to be mapped to Modbus tags must be defined as global variables by the '''common Shared''' declaration.&lt;br /&gt;
* In order to map the variables, the program must be loaded in the softMC.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
#Start the Modbus Configurator: from the ControlStudio toolbar, select '''Tools &amp;gt; Modbus Configurator'''. The Modbus Configurator tool will appear.&lt;br /&gt;
#From the top menu, Select '''Connection &amp;gt; Setting'''.&lt;br /&gt;
#'''Enter the MC's IP and port''' (default connection port is 5001), then '''click OK'''.&lt;br /&gt;
# From the top menu, Select '''Connection &amp;gt; Connect'''.&lt;br /&gt;
&lt;br /&gt;
Once the Modbus Configurator is connected to softMC it gets updated with the complete list of all the global variables. Double-clicking on variables automatically maps them to Modbus tags in consecutive order. The automatic Modbus address and data type are displayed in the table, along with the Modbus address space area in which the data will be stored (Default: Holding Registers).&lt;br /&gt;
&lt;br /&gt;
* If a mapped variable is '''defined as CONST''', its access type will automatically set to &amp;quot;Read&amp;quot;. In such instances the access type cannot be changed. &amp;quot;Read Access variables are read only by the HMI; therefore the softMC only &amp;lt;u&amp;gt;writes&amp;lt;/u&amp;gt; them to the Modbus address space.&lt;br /&gt;
&lt;br /&gt;
* If a mapped variable is '''not defined as CONST''', it automatically appears with &amp;quot;Write&amp;quot; Access. '''Double-click on the access type''' to toggle the variable between Read Access and Write Access, and thus determine whether the variable will be read or written by softMC.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(4).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
==Generating and Using Scripts==&lt;br /&gt;
After you are done mapping variables and defining the access types, a snapshot of the current configuration must be saved in order to generate the Modbus-handling scripts.&lt;br /&gt;
&lt;br /&gt;
1. Click '''Files''', and then '''Save As'''.&lt;br /&gt;
&lt;br /&gt;
:The mapping is saved in an '''.mbas''' file.&lt;br /&gt;
&lt;br /&gt;
:If you makes changes after saving the .mbas file, the MBAS file indicator in the status bar will light up.&lt;br /&gt;
&lt;br /&gt;
2. To generate the product files, click '''Generate'''.&lt;br /&gt;
&lt;br /&gt;
:The Log windows will display Success messages.&lt;br /&gt;
&lt;br /&gt;
:The product files were created in the target folder you chose when saving the .mbas file.&lt;br /&gt;
&lt;br /&gt;
:The files HMIMBMAP.LIB and HMIMBMAP.PRG will automatically open in ControlStudio.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(5).png|600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Using the Modbus-Handling Scripts==&lt;br /&gt;
1. Using the ControlStudio File Manager, copy HMIMBMAP.LIB and HMIMBMAP.PRG to the softMC.&lt;br /&gt;
&lt;br /&gt;
'''Note''':	Before these files can be loaded and used, your application must be loaded, and all mapped variables must exist in the softMC memory.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(6).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Using the ControlStudio Terminal, load the library HMIMBMAP.LIB:&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.LIB&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Since HMIMBMAP.PRG imports this library it must not be loaded globally. This code can be executed wherever is convenient.&lt;br /&gt;
&lt;br /&gt;
2. Verify that the library was loaded successfully:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;?tasklist&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Start the Modbus communication task by loading the program:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.PRG&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
HMIMBMAP.PRG is defined as '''Program Continue''', therefore it starts automatically after it is loaded and it does not require an explicit StartTask command.&lt;br /&gt;
&lt;br /&gt;
Of course, HMIMBMAP.PRG can be loaded and executed only after HMIMBMAP.LIB is loaded. Therefore, you should add the following code to AUTOEXEC.PRG or wherever is convenient:&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.LIB&lt;br /&gt;
Load HMIMBMAP.PRG&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HMIMBMAP.PRG Explained==&lt;br /&gt;
The code:&lt;br /&gt;
&amp;lt;pre&amp;gt;import HMIMBMAP.LIB&lt;br /&gt;
Program Continue&lt;br /&gt;
	dim retVal as long = 0&lt;br /&gt;
	retVal = Init_Modbus&lt;br /&gt;
	while 1&lt;br /&gt;
		retVal = Read_Modbus_Registers&lt;br /&gt;
		retVal = Write_Modbus_Registers&lt;br /&gt;
		sleep 1&lt;br /&gt;
	end while&lt;br /&gt;
End Program&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The functions '''Init_Modbus''', '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are implemented in '''HMIMBMAP.LIB''', which is automatically generated by a Python script.&lt;br /&gt;
&lt;br /&gt;
The function '''Init_Modbus''' starts the Modbus server and then writes to the Modbus address space all the '''Write Access Variables''' (i.e., all the variables read by the softMC from the Modbus address space). This feature allows you to setup the system to start with an initialized Modbus address space before the HMI/PLC connects to it. The HMI/PLC can read the address space and initialize itself accordingly.&lt;br /&gt;
&lt;br /&gt;
The functions '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are invoked cyclically and indefinitely. '''Read_Modbus_Registers''' reads all the tags that are written by the HMI/PLC and updates the '''Write Access''' variables with new values, while '''Write_Modbus_Registers''' does the opposite.&lt;br /&gt;
&lt;br /&gt;
=HMI IDEs and .CSV Files=&lt;br /&gt;
Each line in the .csv file generated by the MCMBConfigurator file holds data about a single variable, such as Modbus address or data type.&lt;br /&gt;
 &lt;br /&gt;
This data can be used by an HMI IDE to import Modbus tags and associate them with HMI functionality.&lt;br /&gt;
&lt;br /&gt;
Different manufacturer IDEs use different .csv formatting; therefore, various Python scripts are used to create the specific .csv files suitable for a particular manufacturer IDE.&lt;br /&gt;
&lt;br /&gt;
==JMobile Studio==&lt;br /&gt;
Python script: '''JMobile_csv.py''' &lt;br /&gt;
&lt;br /&gt;
Default target .csv file name: '''JMobile_HMI.csv''' (user-definable)&lt;br /&gt;
&lt;br /&gt;
To import tags, perform the following procedure in JMobile Studio.&lt;br /&gt;
&lt;br /&gt;
===Define Protocol===&lt;br /&gt;
1. In the ProjectView pane, select '''Protocols'''.&lt;br /&gt;
&lt;br /&gt;
2. Click the blue '''+''' sign.&lt;br /&gt;
&lt;br /&gt;
3. From the list, select Modbus TCP.&lt;br /&gt;
&lt;br /&gt;
4. In the Modbus TCP configuration window, define: &lt;br /&gt;
&lt;br /&gt;
:IP Address: Set the IP address of your softMC.&lt;br /&gt;
&lt;br /&gt;
:PLC Models: Select '''Generic Modbus''' (0-based), meaning the softMC Modbus server starts addressing tags from 0.&lt;br /&gt;
&lt;br /&gt;
:Click '''OK'''.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(7).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
===Import Tags===&lt;br /&gt;
1. In the ProjectView pane, select '''Tags'''.&lt;br /&gt;
&lt;br /&gt;
2. From the list, select '''Modbus TCP''' protocol defined previously.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(8).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
3. Click the '''Import Tags''' button. &lt;br /&gt;
&lt;br /&gt;
4. Open the generated file '''JMobile_HMI.csv'''.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(9).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
5. Select the tags you want to add to your project, and click the ''Import tags'' button.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(10).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==AdvancedHMI==&lt;br /&gt;
AdvancedHMI is an open source project (http://www.advancedhmi.com/), which is downloaded as a Visual Basic project. You can then open the project, add widgets, compile, and run it.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(11).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Drag and drop '''ModbusTCPCom''' into MainForm.vb [Design].&lt;br /&gt;
&lt;br /&gt;
2. The driver appears the bottom of the screen (circled in green). &lt;br /&gt;
&lt;br /&gt;
:Click the driver, and then use the Properties pane (circled in red) to setup the IP address of the Modbus server.&lt;br /&gt;
&lt;br /&gt;
:For example, drag and drop DigitalPanelMeter and MomentaryButton into MainForm.vb [Design].&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(12).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
3. For both widgets, use the Properties pane to set the Modbus address that is associated with the variables from the softMC application.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(13).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
'''Note''':&lt;br /&gt;
::MC Modbus server addressing starts from '''40000'''.&lt;br /&gt;
::AdvancedHMI Modbus client addressing starts from '''40001'''.&lt;br /&gt;
::Prefix the address with the letter '''L'''.&lt;br /&gt;
&lt;br /&gt;
4. Save the project (Ctrl+S).&lt;br /&gt;
&lt;br /&gt;
5. Build the project (Ctrl+Shift+B).&lt;br /&gt;
&lt;br /&gt;
6. Run the project (F5).&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125883</id>
		<title>Modbus Communication API</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125883"/>
				<updated>2016-04-18T13:42:43Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: minor formatting changes&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
=== Basic Overview ===&lt;br /&gt;
* This describes how to set up Modbus communication for the softMC, and how to generate softMC scripts to handle Modbus communication.&lt;br /&gt;
* It is assumed you are familiar with the principles of Modbus communication, although some of them will be described in this page.&lt;br /&gt;
* It is also assumed your are familiar with the softMC, ControlStudio and MC-Basic programming.&lt;br /&gt;
&lt;br /&gt;
=== Modbus Communication Background ===&lt;br /&gt;
* A Motion Controller (MC) can act as a server (slave), a client (master) or both at the same time.&lt;br /&gt;
* Each MC connection (TCP/RTU) can be used either as a server component (if the connection is used by the MC’s server-side) or as a client component (if the connection is used by the MC’s client-side).&lt;br /&gt;
* Each component has its own parameters that defines it.&lt;br /&gt;
* When the MC acts as a server, all server components share the '''same''' memory address space, thus acting as one server with multiple connections.&lt;br /&gt;
* Each server (slave) on a Modbus network has its own deviceID, which is a number between 1 and 247.&lt;br /&gt;
&lt;br /&gt;
=== The Modbus server registers ===&lt;br /&gt;
* There are 4 types of registers in the Modbus Server address space:&lt;br /&gt;
*# Bits (1-bit registers)&lt;br /&gt;
*# Input Bits (1-bit READ-ONLY registers)&lt;br /&gt;
*# Holding Registers (16-bit registers)&lt;br /&gt;
*# Input Registers (16-bit READ-ONLY registers)&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
In order to get started in using the Modbus features:&lt;br /&gt;
# Download the required files, according to your system's type:&lt;br /&gt;
#* Required files for [[File:modbus_requiredFiles_x86.zip|modbus_X86.ZIP]].&lt;br /&gt;
#* Required files for ARM systems.&lt;br /&gt;
# Using the ControlStudio File Manager, Upload the following files to your MC:&lt;br /&gt;
#* mb_x86.O ''(for softMC7 )'' / mb_armA9.O ''(for softMC3)''&lt;br /&gt;
#* Modbus.lib&lt;br /&gt;
#* MB_Loader.prg&lt;br /&gt;
#:[[File:modbus;newAPI-upload.jpg|850px]]&lt;br /&gt;
# Run MB_Loader.prg&lt;br /&gt;
&lt;br /&gt;
That's it! You're now ready to configure the Modbus system.&lt;br /&gt;
&lt;br /&gt;
== Initializing a Modbus Server ==&lt;br /&gt;
To initialize the Modbus server address space, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;?init_multi_server([bits],[input_bits],[holding registers],[input_registers])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The function prints &amp;quot;success&amp;quot; and returns 0 on success, or return an error code on failure.&lt;br /&gt;
* &amp;lt;u&amp;gt;'''Notice:'''&amp;lt;/u&amp;gt; You can call this method only if there are no active server components.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Memory allocation failure.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Some servers are still running and using an already mapped address space.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to create a modbus mapping.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Server Components ==&lt;br /&gt;
=== '''Adding server components''' ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Creating a TCP server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_server_create([port],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens a TCP connection to the server on port [port] with deviceID [deviceID], and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Failed to create main socket.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|}&lt;br /&gt;
==== Creating an RTU server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_server_create([type],[port],[baudrate],[data bits],[stop bits],[parity],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens an RTU connection with the given parameters, and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Invalid device string.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Invalid parity.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed opening RTU.&lt;br /&gt;
|-&lt;br /&gt;
| -5&lt;br /&gt;
| Failed allocating query buffer memory.&lt;br /&gt;
|-&lt;br /&gt;
| -6&lt;br /&gt;
| Failed to set RTU mode.&lt;br /&gt;
|-&lt;br /&gt;
| -7&lt;br /&gt;
| Unable to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -8&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|-&lt;br /&gt;
| -9&lt;br /&gt;
| The device is already in use by another system component.&lt;br /&gt;
|}&lt;br /&gt;
=== '''Stopping Server Components''' ===&lt;br /&gt;
==== Stopping a specific server component ====&lt;br /&gt;
You can stop a specific server component by passing its handle to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate server component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
==== Stopping all server components ====&lt;br /&gt;
You can stop all server components with a single call to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop_all&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function will:&lt;br /&gt;
* Stop and free all server components.&lt;br /&gt;
* Free the shared address space.&lt;br /&gt;
* Return 0 on success, -1 on failure.&lt;br /&gt;
== Client Components ==&lt;br /&gt;
=== '''Adding client components''' ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Adding a TCP Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_client_create([ip],[port])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will opens a TCP connection to the client on the given ip and port, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
==== Adding an RTU Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_client_create([type],[port],[baudrate],[data bits],[stop bits],[parity])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will open an RTU connection to the client with the given parameters, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
=== Stopping client components ===&lt;br /&gt;
A specific client can be stopped by calling:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_client_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate client component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reset the Modbus System ==&lt;br /&gt;
Sometimes, a user may wish to stop all server and client components at once, and reset the Modbus system (for example, when a user want to initialize a different Modbus system). To do that, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_reset&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function:&lt;br /&gt;
* Stops all running servers and clients.&lt;br /&gt;
* Frees their memory.&lt;br /&gt;
* Frees the shared address space.&lt;br /&gt;
* Reset the handle counter.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reading and Writing ==&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
* Therefore, Servers and clients use different functions to read/write data from the address space.&lt;br /&gt;
=== '''Server Components''' ===&lt;br /&gt;
&amp;lt;hr&amp;gt;&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers and return them.&lt;br /&gt;
* When a read error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_REG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_READ_BIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_INREG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt; val = MB_SERVER_READ_INBIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data into the different types of registers.&lt;br /&gt;
* When a write error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Writing to holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_BIT([index],[new value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_INBIT([index],[value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| New value&lt;br /&gt;
| The value to write, must be from the appropriate type.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Error codes ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Invalid index.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Local server's address space isn't mapped yet.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to catch the register mutex.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to release the register mutex.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== '''Client Components''' ===&lt;br /&gt;
&amp;lt;hr&amp;gt;&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The read value is inserted into an existing variable from the appropriate type (long/double).&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_REG_LONG([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_BITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_LONG ([handle],[deviceID],[addr],[dest ptr]) &lt;br /&gt;
Val = MB_CLIENT_READ_INREG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_INBITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to read from.&lt;br /&gt;
|-&lt;br /&gt;
| Num of bits (Reading bits)&lt;br /&gt;
| The number of bits to read.&lt;br /&gt;
|-&lt;br /&gt;
| dest ptr / dest arr ptr&lt;br /&gt;
| The variable to store the read data. When reading bits, this must be an array of longs in the appropriate size (&amp;gt;= Num of bits).&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data from existing variables to the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Writing to Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_LONG([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_SHORT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_FLOAT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_DOUBLE([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_WRITE_BIT([handle],[deviceID],[addr],[src ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to start writing to.&lt;br /&gt;
|-&lt;br /&gt;
| src ptr&lt;br /&gt;
| The variable that stores the data to be written. This must be a variable from the appropriate type.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== '''Reading and Writing Summary''' ===&lt;br /&gt;
[[File:modbus;newAPI-readwriteSummary.jpg|850px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Modbus Configurator=&lt;br /&gt;
The Modbus Communication Scripts Generator ('''Modbus Configurator''') is a tool that allows you to map your softMC application variables to Modbus tags.&lt;br /&gt;
&lt;br /&gt;
'''Note''':	Tag access is defined from the HMI perspective. In other words:&lt;br /&gt;
* '''Read Access''' variables are written by the softMC to the Modbus address space.&lt;br /&gt;
* '''Write Access''' variables are read by the softMC from the Modbus address space.&lt;br /&gt;
&lt;br /&gt;
You can define whether a variable has Read Access (meaning it is read by the HMI/PLC), or Write Access (meaning it is written by the HMI/PLC). Currently, it is not possible to define a variable as having both Read Access and Write Access. However, all Write Access variables can be written once by the softMC upon system startup by a special routine that is generated in HMIMBMAP.LIB (see section below).&lt;br /&gt;
&lt;br /&gt;
The MCMBConfigurator creates three files:&lt;br /&gt;
* '''HMIMBMAP.LIB''' and '''HMIMBMAP.PRG''' files are MC-Basic scripts that are used to start a softMC task. These are default file names, which you can change, but must retain the 8.3 format. This task cyclically and indefinitely reads/writes Modbus tags according to access type. &lt;br /&gt;
* A '''.CSV''' format file that can be used by an HMI development environment, such as '''JMobile Studio''' or '''Indusoft''', to automatically import Modbus tags. You define the HMI development environment by selecting various Python scripts that will generate the .csv file.&lt;br /&gt;
&lt;br /&gt;
== Mapping Variables==&lt;br /&gt;
'''Note''': 	Variables destined to be mapped to Modbus tags must be defined as global variables by the Common Shared declaration.&lt;br /&gt;
&lt;br /&gt;
1. In order to map the variables, the program must be loaded in the softMC.&lt;br /&gt;
&lt;br /&gt;
2. Start the Modbus Configuration: from the ControlStudio toolbar, select  Tools, and then Modbus Configurator…&lt;br /&gt;
&lt;br /&gt;
:The Modbus Configurator windows opens.&lt;br /&gt;
&lt;br /&gt;
3. Click Connection, and select Setting.&lt;br /&gt;
&lt;br /&gt;
:The setting dialog box opens, with fields showing the following (default) settings:&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(3).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
* Modbus offset: Used to start the mapping from an address other than zero.&lt;br /&gt;
* Script file name: A Python script that generates the product files. Different scripts create different .csv files.&lt;br /&gt;
* Output LIB, Output Prog, HMI CSV file name: Used to define target file names. &lt;br /&gt;
:'''Note''': The softMC file names must be UPPERCASE and in 8.3 format.&lt;br /&gt;
* MC IP address: Used to set the IP address of your softMC.&lt;br /&gt;
Make any necessary changes in the Settings dialog box. Then click Connection, and then Connect.&lt;br /&gt;
&lt;br /&gt;
Once the Modbus Configurator is connected to softMC it gets updated with the complete list of all the global variables. Double-clicking on variables automatically maps them to Modbus tags in consecutive order. The automatic Modbus address and data type are displayed in the table.&lt;br /&gt;
&lt;br /&gt;
If a mapped variable is defined as CONST, its access type is automatically set to Read. In such instances the access type cannot be changed. Read Access variables are read only by the HMI; therefore the softMC only writes them to the Modbus address space.&lt;br /&gt;
&lt;br /&gt;
A variable that is not defined as CONST automatically appears as Write Access. Double-click on the access type to toggle the variable between Read Access and Write Access, and thus determine whether the variable will be read or written by softMC.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(4).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
==Generating and Using Scripts==&lt;br /&gt;
After you are done mapping variables and defining the access types, a snapshot of the current configuration must be saved in order to generate the Modbus-handling scripts.&lt;br /&gt;
&lt;br /&gt;
1. Click '''Files''', and then '''Save As'''.&lt;br /&gt;
&lt;br /&gt;
:The mapping is saved in an '''.mbas''' file.&lt;br /&gt;
&lt;br /&gt;
:If you makes changes after saving the .mbas file, the MBAS file indicator in the status bar will light up.&lt;br /&gt;
&lt;br /&gt;
2. To generate the product files, click '''Generate'''.&lt;br /&gt;
&lt;br /&gt;
:The Log windows will display Success messages.&lt;br /&gt;
&lt;br /&gt;
:The product files were created in the target folder you chose when saving the .mbas file.&lt;br /&gt;
&lt;br /&gt;
:The files HMIMBMAP.LIB and HMIMBMAP.PRG will automatically open in ControlStudio.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(5).png|600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Using the Modbus-Handling Scripts==&lt;br /&gt;
1. Using the ControlStudio File Manager, copy HMIMBMAP.LIB and HMIMBMAP.PRG to the softMC.&lt;br /&gt;
&lt;br /&gt;
'''Note''':	Before these files can be loaded and used, your application must be loaded, and all mapped variables must exist in the softMC memory.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(6).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Using the ControlStudio Terminal, load the library HMIMBMAP.LIB:&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.LIB&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Since HMIMBMAP.PRG imports this library it must not be loaded globally. This code can be executed wherever is convenient.&lt;br /&gt;
&lt;br /&gt;
2. Verify that the library was loaded successfully:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;?tasklist&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Start the Modbus communication task by loading the program:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.PRG&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
HMIMBMAP.PRG is defined as '''Program Continue''', therefore it starts automatically after it is loaded and it does not require an explicit StartTask command.&lt;br /&gt;
&lt;br /&gt;
Of course, HMIMBMAP.PRG can be loaded and executed only after HMIMBMAP.LIB is loaded. Therefore, you should add the following code to AUTOEXEC.PRG or wherever is convenient:&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.LIB&lt;br /&gt;
Load HMIMBMAP.PRG&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HMIMBMAP.PRG Explained==&lt;br /&gt;
The code:&lt;br /&gt;
&amp;lt;pre&amp;gt;import HMIMBMAP.LIB&lt;br /&gt;
Program Continue&lt;br /&gt;
	dim retVal as long = 0&lt;br /&gt;
	retVal = Init_Modbus&lt;br /&gt;
	while 1&lt;br /&gt;
		retVal = Read_Modbus_Registers&lt;br /&gt;
		retVal = Write_Modbus_Registers&lt;br /&gt;
		sleep 1&lt;br /&gt;
	end while&lt;br /&gt;
End Program&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The functions '''Init_Modbus''', '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are implemented in '''HMIMBMAP.LIB''', which is automatically generated by a Python script.&lt;br /&gt;
&lt;br /&gt;
The function '''Init_Modbus''' starts the Modbus server and then writes to the Modbus address space all the '''Write Access Variables''' (i.e., all the variables read by the softMC from the Modbus address space). This feature allows you to setup the system to start with an initialized Modbus address space before the HMI/PLC connects to it. The HMI/PLC can read the address space and initialize itself accordingly.&lt;br /&gt;
&lt;br /&gt;
The functions '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are invoked cyclically and indefinitely. '''Read_Modbus_Registers''' reads all the tags that are written by the HMI/PLC and updates the '''Write Access''' variables with new values, while '''Write_Modbus_Registers''' does the opposite.&lt;br /&gt;
&lt;br /&gt;
=HMI IDEs and .CSV Files=&lt;br /&gt;
Each line in the .csv file generated by the MCMBConfigurator file holds data about a single variable, such as Modbus address or data type.&lt;br /&gt;
 &lt;br /&gt;
This data can be used by an HMI IDE to import Modbus tags and associate them with HMI functionality.&lt;br /&gt;
&lt;br /&gt;
Different manufacturer IDEs use different .csv formatting; therefore, various Python scripts are used to create the specific .csv files suitable for a particular manufacturer IDE.&lt;br /&gt;
&lt;br /&gt;
==JMobile Studio==&lt;br /&gt;
Python script: '''JMobile_csv.py''' &lt;br /&gt;
&lt;br /&gt;
Default target .csv file name: '''JMobile_HMI.csv''' (user-definable)&lt;br /&gt;
&lt;br /&gt;
To import tags, perform the following procedure in JMobile Studio.&lt;br /&gt;
&lt;br /&gt;
===Define Protocol===&lt;br /&gt;
1. In the ProjectView pane, select '''Protocols'''.&lt;br /&gt;
&lt;br /&gt;
2. Click the blue '''+''' sign.&lt;br /&gt;
&lt;br /&gt;
3. From the list, select Modbus TCP.&lt;br /&gt;
&lt;br /&gt;
4. In the Modbus TCP configuration window, define: &lt;br /&gt;
&lt;br /&gt;
:IP Address: Set the IP address of your softMC.&lt;br /&gt;
&lt;br /&gt;
:PLC Models: Select '''Generic Modbus''' (0-based), meaning the softMC Modbus server starts addressing tags from 0.&lt;br /&gt;
&lt;br /&gt;
:Click '''OK'''.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(7).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
===Import Tags===&lt;br /&gt;
1. In the ProjectView pane, select '''Tags'''.&lt;br /&gt;
&lt;br /&gt;
2. From the list, select '''Modbus TCP''' protocol defined previously.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(8).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
3. Click the '''Import Tags''' button. &lt;br /&gt;
&lt;br /&gt;
4. Open the generated file '''JMobile_HMI.csv'''.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(9).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
5. Select the tags you want to add to your project, and click the ''Import tags'' button.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(10).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==AdvancedHMI==&lt;br /&gt;
AdvancedHMI is an open source project (http://www.advancedhmi.com/), which is downloaded as a Visual Basic project. You can then open the project, add widgets, compile, and run it.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(11).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Drag and drop '''ModbusTCPCom''' into MainForm.vb [Design].&lt;br /&gt;
&lt;br /&gt;
2. The driver appears the bottom of the screen (circled in green). &lt;br /&gt;
&lt;br /&gt;
:Click the driver, and then use the Properties pane (circled in red) to setup the IP address of the Modbus server.&lt;br /&gt;
&lt;br /&gt;
:For example, drag and drop DigitalPanelMeter and MomentaryButton into MainForm.vb [Design].&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(12).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
3. For both widgets, use the Properties pane to set the Modbus address that is associated with the variables from the softMC application.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(13).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
'''Note''':&lt;br /&gt;
::MC Modbus server addressing starts from '''40000'''.&lt;br /&gt;
::AdvancedHMI Modbus client addressing starts from '''40001'''.&lt;br /&gt;
::Prefix the address with the letter '''L'''.&lt;br /&gt;
&lt;br /&gt;
4. Save the project (Ctrl+S).&lt;br /&gt;
&lt;br /&gt;
5. Build the project (Ctrl+Shift+B).&lt;br /&gt;
&lt;br /&gt;
6. Run the project (F5).&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125882</id>
		<title>Modbus Communication API</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125882"/>
				<updated>2016-04-18T13:38:28Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: /* Client Components */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
=== Basic Overview ===&lt;br /&gt;
* This describes how to set up Modbus communication for the softMC, and how to generate softMC scripts to handle Modbus communication.&lt;br /&gt;
* It is assumed you are familiar with the principles of Modbus communication, although some of them will be described in this page.&lt;br /&gt;
* It is also assumed your are familiar with the softMC, ControlStudio and MC-Basic programming.&lt;br /&gt;
&lt;br /&gt;
=== Modbus Communication Background ===&lt;br /&gt;
* A Motion Controller (MC) can act as a server (slave), a client (master) or both at the same time.&lt;br /&gt;
* Each MC connection (TCP/RTU) can be used either as a server component (if the connection is used by the MC’s server-side) or as a client component (if the connection is used by the MC’s client-side).&lt;br /&gt;
* Each component has its own parameters that defines it.&lt;br /&gt;
* When the MC acts as a server, all server components share the '''same''' memory address space, thus acting as one server with multiple connections.&lt;br /&gt;
* Each server (slave) on a Modbus network has its own deviceID, which is a number between 1 and 247.&lt;br /&gt;
&lt;br /&gt;
=== The Modbus server registers ===&lt;br /&gt;
* There are 4 types of registers in the Modbus Server address space:&lt;br /&gt;
*# Bits (1-bit registers)&lt;br /&gt;
*# Input Bits (1-bit READ-ONLY registers)&lt;br /&gt;
*# Holding Registers (16-bit registers)&lt;br /&gt;
*# Input Registers (16-bit READ-ONLY registers)&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
In order to get started in using the Modbus features:&lt;br /&gt;
# Download the required files, according to your system's type:&lt;br /&gt;
#* Required files for [[File:modbus_requiredFiles_x86.zip|modbus_X86.ZIP]].&lt;br /&gt;
#* Required files for ARM systems.&lt;br /&gt;
# Using the ControlStudio File Manager, Upload the following files to your MC:&lt;br /&gt;
#* mb_x86.O ''(for softMC7 )'' / mb_armA9.O ''(for softMC3)''&lt;br /&gt;
#* Modbus.lib&lt;br /&gt;
#* MB_Loader.prg&lt;br /&gt;
#:[[File:modbus;newAPI-upload.jpg|850px]]&lt;br /&gt;
# Run MB_Loader.prg&lt;br /&gt;
&lt;br /&gt;
That's it! You're now ready to configure the Modbus system.&lt;br /&gt;
&lt;br /&gt;
== Initializing a Modbus Server ==&lt;br /&gt;
To initialize the Modbus server address space, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;?init_multi_server([bits],[input_bits],[holding registers],[input_registers])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The function prints &amp;quot;success&amp;quot; and returns 0 on success, or return an error code on failure.&lt;br /&gt;
* &amp;lt;u&amp;gt;'''Notice:'''&amp;lt;/u&amp;gt; You can call this method only if there are no active server components.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Memory allocation failure.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Some servers are still running and using an already mapped address space.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to create a modbus mapping.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Server Components ==&lt;br /&gt;
=== Adding server components ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Creating a TCP server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_server_create([port],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens a TCP connection to the server on port [port] with deviceID [deviceID], and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Failed to create main socket.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|}&lt;br /&gt;
==== Creating an RTU server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_server_create([type],[port],[baudrate],[data bits],[stop bits],[parity],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens an RTU connection with the given parameters, and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Invalid device string.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Invalid parity.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed opening RTU.&lt;br /&gt;
|-&lt;br /&gt;
| -5&lt;br /&gt;
| Failed allocating query buffer memory.&lt;br /&gt;
|-&lt;br /&gt;
| -6&lt;br /&gt;
| Failed to set RTU mode.&lt;br /&gt;
|-&lt;br /&gt;
| -7&lt;br /&gt;
| Unable to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -8&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|-&lt;br /&gt;
| -9&lt;br /&gt;
| The device is already in use by another system component.&lt;br /&gt;
|}&lt;br /&gt;
=== Stopping Server Components ===&lt;br /&gt;
==== Stopping a specific server component ====&lt;br /&gt;
You can stop a specific server component by passing its handle to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate server component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
==== Stopping all server components ====&lt;br /&gt;
You can stop all server components with a single call to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop_all&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function will:&lt;br /&gt;
* Stop and free all server components.&lt;br /&gt;
* Free the shared address space.&lt;br /&gt;
* Return 0 on success, -1 on failure.&lt;br /&gt;
== Client Components ==&lt;br /&gt;
=== Adding client components ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Adding a TCP Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_client_create([ip],[port])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will opens a TCP connection to the client on the given ip and port, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
==== Adding an RTU Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_client_create([type],[port],[baudrate],[data bits],[stop bits],[parity])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will open an RTU connection to the client with the given parameters, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
=== Stopping client components ===&lt;br /&gt;
A specific client can be stopped by calling:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_client_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate client component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reset the Modbus System ==&lt;br /&gt;
Sometimes, a user may wish to stop all server and client components at once, and reset the Modbus system (for example, when a user want to initialize a different Modbus system). To do that, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_reset&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function:&lt;br /&gt;
* Stops all running servers and clients.&lt;br /&gt;
* Frees their memory.&lt;br /&gt;
* Frees the shared address space.&lt;br /&gt;
* Reset the handle counter.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reading and Writing ==&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
* Therefore, Servers and clients use different functions to read/write data from the address space.&lt;br /&gt;
=== '''Server Components''' ===&lt;br /&gt;
&amp;lt;hr&amp;gt;&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers and return them.&lt;br /&gt;
* When a read error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_REG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_READ_BIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_INREG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt; val = MB_SERVER_READ_INBIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data into the different types of registers.&lt;br /&gt;
* When a write error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Writing to holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_BIT([index],[new value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_INBIT([index],[value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| New value&lt;br /&gt;
| The value to write, must be from the appropriate type.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Error codes ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Invalid index.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Local server's address space isn't mapped yet.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to catch the register mutex.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to release the register mutex.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== '''Client Components''' ===&lt;br /&gt;
&amp;lt;hr&amp;gt;&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The read value is inserted into an existing variable from the appropriate type (long/double).&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_REG_LONG([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_BITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_LONG ([handle],[deviceID],[addr],[dest ptr]) &lt;br /&gt;
Val = MB_CLIENT_READ_INREG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_INBITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to read from.&lt;br /&gt;
|-&lt;br /&gt;
| Num of bits (Reading bits)&lt;br /&gt;
| The number of bits to read.&lt;br /&gt;
|-&lt;br /&gt;
| dest ptr / dest arr ptr&lt;br /&gt;
| The variable to store the read data. When reading bits, this must be an array of longs in the appropriate size (&amp;gt;= Num of bits).&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data from existing variables to the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Writing to Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_LONG([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_SHORT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_FLOAT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_DOUBLE([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_WRITE_BIT([handle],[deviceID],[addr],[src ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to start writing to.&lt;br /&gt;
|-&lt;br /&gt;
| src ptr&lt;br /&gt;
| The variable that stores the data to be written. This must be a variable from the appropriate type.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Reading and Writing Summary ===&lt;br /&gt;
[[File:modbus;newAPI-readwriteSummary.jpg|850px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Modbus Configurator=&lt;br /&gt;
The Modbus Communication Scripts Generator ('''Modbus Configurator''') is a tool that allows you to map your softMC application variables to Modbus tags.&lt;br /&gt;
&lt;br /&gt;
'''Note''':	Tag access is defined from the HMI perspective. In other words:&lt;br /&gt;
* '''Read Access''' variables are written by the softMC to the Modbus address space.&lt;br /&gt;
* '''Write Access''' variables are read by the softMC from the Modbus address space.&lt;br /&gt;
&lt;br /&gt;
You can define whether a variable has Read Access (meaning it is read by the HMI/PLC), or Write Access (meaning it is written by the HMI/PLC). Currently, it is not possible to define a variable as having both Read Access and Write Access. However, all Write Access variables can be written once by the softMC upon system startup by a special routine that is generated in HMIMBMAP.LIB (see section below).&lt;br /&gt;
&lt;br /&gt;
The MCMBConfigurator creates three files:&lt;br /&gt;
* '''HMIMBMAP.LIB''' and '''HMIMBMAP.PRG''' files are MC-Basic scripts that are used to start a softMC task. These are default file names, which you can change, but must retain the 8.3 format. This task cyclically and indefinitely reads/writes Modbus tags according to access type. &lt;br /&gt;
* A '''.CSV''' format file that can be used by an HMI development environment, such as '''JMobile Studio''' or '''Indusoft''', to automatically import Modbus tags. You define the HMI development environment by selecting various Python scripts that will generate the .csv file.&lt;br /&gt;
&lt;br /&gt;
== Mapping Variables==&lt;br /&gt;
'''Note''': 	Variables destined to be mapped to Modbus tags must be defined as global variables by the Common Shared declaration.&lt;br /&gt;
&lt;br /&gt;
1. In order to map the variables, the program must be loaded in the softMC.&lt;br /&gt;
&lt;br /&gt;
2. Start the Modbus Configuration: from the ControlStudio toolbar, select  Tools, and then Modbus Configurator…&lt;br /&gt;
&lt;br /&gt;
:The Modbus Configurator windows opens.&lt;br /&gt;
&lt;br /&gt;
3. Click Connection, and select Setting.&lt;br /&gt;
&lt;br /&gt;
:The setting dialog box opens, with fields showing the following (default) settings:&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(3).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
* Modbus offset: Used to start the mapping from an address other than zero.&lt;br /&gt;
* Script file name: A Python script that generates the product files. Different scripts create different .csv files.&lt;br /&gt;
* Output LIB, Output Prog, HMI CSV file name: Used to define target file names. &lt;br /&gt;
:'''Note''': The softMC file names must be UPPERCASE and in 8.3 format.&lt;br /&gt;
* MC IP address: Used to set the IP address of your softMC.&lt;br /&gt;
Make any necessary changes in the Settings dialog box. Then click Connection, and then Connect.&lt;br /&gt;
&lt;br /&gt;
Once the Modbus Configurator is connected to softMC it gets updated with the complete list of all the global variables. Double-clicking on variables automatically maps them to Modbus tags in consecutive order. The automatic Modbus address and data type are displayed in the table.&lt;br /&gt;
&lt;br /&gt;
If a mapped variable is defined as CONST, its access type is automatically set to Read. In such instances the access type cannot be changed. Read Access variables are read only by the HMI; therefore the softMC only writes them to the Modbus address space.&lt;br /&gt;
&lt;br /&gt;
A variable that is not defined as CONST automatically appears as Write Access. Double-click on the access type to toggle the variable between Read Access and Write Access, and thus determine whether the variable will be read or written by softMC.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(4).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
==Generating and Using Scripts==&lt;br /&gt;
After you are done mapping variables and defining the access types, a snapshot of the current configuration must be saved in order to generate the Modbus-handling scripts.&lt;br /&gt;
&lt;br /&gt;
1. Click '''Files''', and then '''Save As'''.&lt;br /&gt;
&lt;br /&gt;
:The mapping is saved in an '''.mbas''' file.&lt;br /&gt;
&lt;br /&gt;
:If you makes changes after saving the .mbas file, the MBAS file indicator in the status bar will light up.&lt;br /&gt;
&lt;br /&gt;
2. To generate the product files, click '''Generate'''.&lt;br /&gt;
&lt;br /&gt;
:The Log windows will display Success messages.&lt;br /&gt;
&lt;br /&gt;
:The product files were created in the target folder you chose when saving the .mbas file.&lt;br /&gt;
&lt;br /&gt;
:The files HMIMBMAP.LIB and HMIMBMAP.PRG will automatically open in ControlStudio.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(5).png|600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Using the Modbus-Handling Scripts==&lt;br /&gt;
1. Using the ControlStudio File Manager, copy HMIMBMAP.LIB and HMIMBMAP.PRG to the softMC.&lt;br /&gt;
&lt;br /&gt;
'''Note''':	Before these files can be loaded and used, your application must be loaded, and all mapped variables must exist in the softMC memory.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(6).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Using the ControlStudio Terminal, load the library HMIMBMAP.LIB:&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.LIB&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Since HMIMBMAP.PRG imports this library it must not be loaded globally. This code can be executed wherever is convenient.&lt;br /&gt;
&lt;br /&gt;
2. Verify that the library was loaded successfully:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;?tasklist&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Start the Modbus communication task by loading the program:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.PRG&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
HMIMBMAP.PRG is defined as '''Program Continue''', therefore it starts automatically after it is loaded and it does not require an explicit StartTask command.&lt;br /&gt;
&lt;br /&gt;
Of course, HMIMBMAP.PRG can be loaded and executed only after HMIMBMAP.LIB is loaded. Therefore, you should add the following code to AUTOEXEC.PRG or wherever is convenient:&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.LIB&lt;br /&gt;
Load HMIMBMAP.PRG&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HMIMBMAP.PRG Explained==&lt;br /&gt;
The code:&lt;br /&gt;
&amp;lt;pre&amp;gt;import HMIMBMAP.LIB&lt;br /&gt;
Program Continue&lt;br /&gt;
	dim retVal as long = 0&lt;br /&gt;
	retVal = Init_Modbus&lt;br /&gt;
	while 1&lt;br /&gt;
		retVal = Read_Modbus_Registers&lt;br /&gt;
		retVal = Write_Modbus_Registers&lt;br /&gt;
		sleep 1&lt;br /&gt;
	end while&lt;br /&gt;
End Program&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The functions '''Init_Modbus''', '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are implemented in '''HMIMBMAP.LIB''', which is automatically generated by a Python script.&lt;br /&gt;
&lt;br /&gt;
The function '''Init_Modbus''' starts the Modbus server and then writes to the Modbus address space all the '''Write Access Variables''' (i.e., all the variables read by the softMC from the Modbus address space). This feature allows you to setup the system to start with an initialized Modbus address space before the HMI/PLC connects to it. The HMI/PLC can read the address space and initialize itself accordingly.&lt;br /&gt;
&lt;br /&gt;
The functions '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are invoked cyclically and indefinitely. '''Read_Modbus_Registers''' reads all the tags that are written by the HMI/PLC and updates the '''Write Access''' variables with new values, while '''Write_Modbus_Registers''' does the opposite.&lt;br /&gt;
&lt;br /&gt;
=HMI IDEs and .CSV Files=&lt;br /&gt;
Each line in the .csv file generated by the MCMBConfigurator file holds data about a single variable, such as Modbus address or data type.&lt;br /&gt;
 &lt;br /&gt;
This data can be used by an HMI IDE to import Modbus tags and associate them with HMI functionality.&lt;br /&gt;
&lt;br /&gt;
Different manufacturer IDEs use different .csv formatting; therefore, various Python scripts are used to create the specific .csv files suitable for a particular manufacturer IDE.&lt;br /&gt;
&lt;br /&gt;
==JMobile Studio==&lt;br /&gt;
Python script: '''JMobile_csv.py''' &lt;br /&gt;
&lt;br /&gt;
Default target .csv file name: '''JMobile_HMI.csv''' (user-definable)&lt;br /&gt;
&lt;br /&gt;
To import tags, perform the following procedure in JMobile Studio.&lt;br /&gt;
&lt;br /&gt;
===Define Protocol===&lt;br /&gt;
1. In the ProjectView pane, select '''Protocols'''.&lt;br /&gt;
&lt;br /&gt;
2. Click the blue '''+''' sign.&lt;br /&gt;
&lt;br /&gt;
3. From the list, select Modbus TCP.&lt;br /&gt;
&lt;br /&gt;
4. In the Modbus TCP configuration window, define: &lt;br /&gt;
&lt;br /&gt;
:IP Address: Set the IP address of your softMC.&lt;br /&gt;
&lt;br /&gt;
:PLC Models: Select '''Generic Modbus''' (0-based), meaning the softMC Modbus server starts addressing tags from 0.&lt;br /&gt;
&lt;br /&gt;
:Click '''OK'''.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(7).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
===Import Tags===&lt;br /&gt;
1. In the ProjectView pane, select '''Tags'''.&lt;br /&gt;
&lt;br /&gt;
2. From the list, select '''Modbus TCP''' protocol defined previously.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(8).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
3. Click the '''Import Tags''' button. &lt;br /&gt;
&lt;br /&gt;
4. Open the generated file '''JMobile_HMI.csv'''.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(9).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
5. Select the tags you want to add to your project, and click the ''Import tags'' button.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(10).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==AdvancedHMI==&lt;br /&gt;
AdvancedHMI is an open source project (http://www.advancedhmi.com/), which is downloaded as a Visual Basic project. You can then open the project, add widgets, compile, and run it.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(11).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Drag and drop '''ModbusTCPCom''' into MainForm.vb [Design].&lt;br /&gt;
&lt;br /&gt;
2. The driver appears the bottom of the screen (circled in green). &lt;br /&gt;
&lt;br /&gt;
:Click the driver, and then use the Properties pane (circled in red) to setup the IP address of the Modbus server.&lt;br /&gt;
&lt;br /&gt;
:For example, drag and drop DigitalPanelMeter and MomentaryButton into MainForm.vb [Design].&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(12).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
3. For both widgets, use the Properties pane to set the Modbus address that is associated with the variables from the softMC application.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(13).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
'''Note''':&lt;br /&gt;
::MC Modbus server addressing starts from '''40000'''.&lt;br /&gt;
::AdvancedHMI Modbus client addressing starts from '''40001'''.&lt;br /&gt;
::Prefix the address with the letter '''L'''.&lt;br /&gt;
&lt;br /&gt;
4. Save the project (Ctrl+S).&lt;br /&gt;
&lt;br /&gt;
5. Build the project (Ctrl+Shift+B).&lt;br /&gt;
&lt;br /&gt;
6. Run the project (F5).&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125881</id>
		<title>Modbus Communication API</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125881"/>
				<updated>2016-04-18T13:37:48Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: /* Server Components */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
=== Basic Overview ===&lt;br /&gt;
* This describes how to set up Modbus communication for the softMC, and how to generate softMC scripts to handle Modbus communication.&lt;br /&gt;
* It is assumed you are familiar with the principles of Modbus communication, although some of them will be described in this page.&lt;br /&gt;
* It is also assumed your are familiar with the softMC, ControlStudio and MC-Basic programming.&lt;br /&gt;
&lt;br /&gt;
=== Modbus Communication Background ===&lt;br /&gt;
* A Motion Controller (MC) can act as a server (slave), a client (master) or both at the same time.&lt;br /&gt;
* Each MC connection (TCP/RTU) can be used either as a server component (if the connection is used by the MC’s server-side) or as a client component (if the connection is used by the MC’s client-side).&lt;br /&gt;
* Each component has its own parameters that defines it.&lt;br /&gt;
* When the MC acts as a server, all server components share the '''same''' memory address space, thus acting as one server with multiple connections.&lt;br /&gt;
* Each server (slave) on a Modbus network has its own deviceID, which is a number between 1 and 247.&lt;br /&gt;
&lt;br /&gt;
=== The Modbus server registers ===&lt;br /&gt;
* There are 4 types of registers in the Modbus Server address space:&lt;br /&gt;
*# Bits (1-bit registers)&lt;br /&gt;
*# Input Bits (1-bit READ-ONLY registers)&lt;br /&gt;
*# Holding Registers (16-bit registers)&lt;br /&gt;
*# Input Registers (16-bit READ-ONLY registers)&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
In order to get started in using the Modbus features:&lt;br /&gt;
# Download the required files, according to your system's type:&lt;br /&gt;
#* Required files for [[File:modbus_requiredFiles_x86.zip|modbus_X86.ZIP]].&lt;br /&gt;
#* Required files for ARM systems.&lt;br /&gt;
# Using the ControlStudio File Manager, Upload the following files to your MC:&lt;br /&gt;
#* mb_x86.O ''(for softMC7 )'' / mb_armA9.O ''(for softMC3)''&lt;br /&gt;
#* Modbus.lib&lt;br /&gt;
#* MB_Loader.prg&lt;br /&gt;
#:[[File:modbus;newAPI-upload.jpg|850px]]&lt;br /&gt;
# Run MB_Loader.prg&lt;br /&gt;
&lt;br /&gt;
That's it! You're now ready to configure the Modbus system.&lt;br /&gt;
&lt;br /&gt;
== Initializing a Modbus Server ==&lt;br /&gt;
To initialize the Modbus server address space, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;?init_multi_server([bits],[input_bits],[holding registers],[input_registers])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The function prints &amp;quot;success&amp;quot; and returns 0 on success, or return an error code on failure.&lt;br /&gt;
* &amp;lt;u&amp;gt;'''Notice:'''&amp;lt;/u&amp;gt; You can call this method only if there are no active server components.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Memory allocation failure.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Some servers are still running and using an already mapped address space.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to create a modbus mapping.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Server Components ==&lt;br /&gt;
=== Adding server components ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Creating a TCP server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_server_create([port],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens a TCP connection to the server on port [port] with deviceID [deviceID], and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Failed to create main socket.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|}&lt;br /&gt;
==== Creating an RTU server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_server_create([type],[port],[baudrate],[data bits],[stop bits],[parity],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens an RTU connection with the given parameters, and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Invalid device string.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Invalid parity.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed opening RTU.&lt;br /&gt;
|-&lt;br /&gt;
| -5&lt;br /&gt;
| Failed allocating query buffer memory.&lt;br /&gt;
|-&lt;br /&gt;
| -6&lt;br /&gt;
| Failed to set RTU mode.&lt;br /&gt;
|-&lt;br /&gt;
| -7&lt;br /&gt;
| Unable to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -8&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|-&lt;br /&gt;
| -9&lt;br /&gt;
| The device is already in use by another system component.&lt;br /&gt;
|}&lt;br /&gt;
=== Stopping Server Components ===&lt;br /&gt;
==== Stopping a specific server component ====&lt;br /&gt;
You can stop a specific server component by passing its handle to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate server component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
==== Stopping all server components ====&lt;br /&gt;
You can stop all server components with a single call to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop_all&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function will:&lt;br /&gt;
* Stop and free all server components.&lt;br /&gt;
* Free the shared address space.&lt;br /&gt;
* Return 0 on success, -1 on failure.&lt;br /&gt;
== Client Components ==&lt;br /&gt;
=== Adding client components ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Adding a TCP Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_client_create([ip],[port])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will opens a TCP connection to the client on the given ip and port, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
==== Adding an RTU Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_client_create([type],[port],[baudrate],[data bits],[stop bits],[parity])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will open an RTU connection to the client with the given parameters, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
=== Stopping client components ===&lt;br /&gt;
A specific client can be stopped by calling:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_client_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate client component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reset the Modbus System ==&lt;br /&gt;
Sometimes, a user may wish to stop all server and client components at once, and reset the Modbus system (for example, when a user want to initialize a different Modbus system). To do that, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_reset&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function:&lt;br /&gt;
* Stops all running servers and clients.&lt;br /&gt;
* Frees their memory.&lt;br /&gt;
* Frees the shared address space.&lt;br /&gt;
* Reset the handle counter.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reading and Writing ==&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
* Therefore, Servers and clients use different functions to read/write data from the address space.&lt;br /&gt;
=== '''Server Components''' ===&lt;br /&gt;
&amp;lt;hr&amp;gt;&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers and return them.&lt;br /&gt;
* When a read error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_REG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_READ_BIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_INREG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt; val = MB_SERVER_READ_INBIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data into the different types of registers.&lt;br /&gt;
* When a write error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Writing to holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_BIT([index],[new value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_INBIT([index],[value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| New value&lt;br /&gt;
| The value to write, must be from the appropriate type.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Error codes ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Invalid index.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Local server's address space isn't mapped yet.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to catch the register mutex.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to release the register mutex.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Client Components ===&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The read value is inserted into an existing variable from the appropriate type (long/double).&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_REG_LONG([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_BITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_LONG ([handle],[deviceID],[addr],[dest ptr]) &lt;br /&gt;
Val = MB_CLIENT_READ_INREG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_INBITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to read from.&lt;br /&gt;
|-&lt;br /&gt;
| Num of bits (Reading bits)&lt;br /&gt;
| The number of bits to read.&lt;br /&gt;
|-&lt;br /&gt;
| dest ptr / dest arr ptr&lt;br /&gt;
| The variable to store the read data. When reading bits, this must be an array of longs in the appropriate size (&amp;gt;= Num of bits).&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data from existing variables to the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Writing to Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_LONG([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_SHORT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_FLOAT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_DOUBLE([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_WRITE_BIT([handle],[deviceID],[addr],[src ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to start writing to.&lt;br /&gt;
|-&lt;br /&gt;
| src ptr&lt;br /&gt;
| The variable that stores the data to be written. This must be a variable from the appropriate type.&lt;br /&gt;
|}&lt;br /&gt;
=== Reading and Writing Summary ===&lt;br /&gt;
[[File:modbus;newAPI-readwriteSummary.jpg|850px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Modbus Configurator=&lt;br /&gt;
The Modbus Communication Scripts Generator ('''Modbus Configurator''') is a tool that allows you to map your softMC application variables to Modbus tags.&lt;br /&gt;
&lt;br /&gt;
'''Note''':	Tag access is defined from the HMI perspective. In other words:&lt;br /&gt;
* '''Read Access''' variables are written by the softMC to the Modbus address space.&lt;br /&gt;
* '''Write Access''' variables are read by the softMC from the Modbus address space.&lt;br /&gt;
&lt;br /&gt;
You can define whether a variable has Read Access (meaning it is read by the HMI/PLC), or Write Access (meaning it is written by the HMI/PLC). Currently, it is not possible to define a variable as having both Read Access and Write Access. However, all Write Access variables can be written once by the softMC upon system startup by a special routine that is generated in HMIMBMAP.LIB (see section below).&lt;br /&gt;
&lt;br /&gt;
The MCMBConfigurator creates three files:&lt;br /&gt;
* '''HMIMBMAP.LIB''' and '''HMIMBMAP.PRG''' files are MC-Basic scripts that are used to start a softMC task. These are default file names, which you can change, but must retain the 8.3 format. This task cyclically and indefinitely reads/writes Modbus tags according to access type. &lt;br /&gt;
* A '''.CSV''' format file that can be used by an HMI development environment, such as '''JMobile Studio''' or '''Indusoft''', to automatically import Modbus tags. You define the HMI development environment by selecting various Python scripts that will generate the .csv file.&lt;br /&gt;
&lt;br /&gt;
== Mapping Variables==&lt;br /&gt;
'''Note''': 	Variables destined to be mapped to Modbus tags must be defined as global variables by the Common Shared declaration.&lt;br /&gt;
&lt;br /&gt;
1. In order to map the variables, the program must be loaded in the softMC.&lt;br /&gt;
&lt;br /&gt;
2. Start the Modbus Configuration: from the ControlStudio toolbar, select  Tools, and then Modbus Configurator…&lt;br /&gt;
&lt;br /&gt;
:The Modbus Configurator windows opens.&lt;br /&gt;
&lt;br /&gt;
3. Click Connection, and select Setting.&lt;br /&gt;
&lt;br /&gt;
:The setting dialog box opens, with fields showing the following (default) settings:&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(3).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
* Modbus offset: Used to start the mapping from an address other than zero.&lt;br /&gt;
* Script file name: A Python script that generates the product files. Different scripts create different .csv files.&lt;br /&gt;
* Output LIB, Output Prog, HMI CSV file name: Used to define target file names. &lt;br /&gt;
:'''Note''': The softMC file names must be UPPERCASE and in 8.3 format.&lt;br /&gt;
* MC IP address: Used to set the IP address of your softMC.&lt;br /&gt;
Make any necessary changes in the Settings dialog box. Then click Connection, and then Connect.&lt;br /&gt;
&lt;br /&gt;
Once the Modbus Configurator is connected to softMC it gets updated with the complete list of all the global variables. Double-clicking on variables automatically maps them to Modbus tags in consecutive order. The automatic Modbus address and data type are displayed in the table.&lt;br /&gt;
&lt;br /&gt;
If a mapped variable is defined as CONST, its access type is automatically set to Read. In such instances the access type cannot be changed. Read Access variables are read only by the HMI; therefore the softMC only writes them to the Modbus address space.&lt;br /&gt;
&lt;br /&gt;
A variable that is not defined as CONST automatically appears as Write Access. Double-click on the access type to toggle the variable between Read Access and Write Access, and thus determine whether the variable will be read or written by softMC.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(4).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
==Generating and Using Scripts==&lt;br /&gt;
After you are done mapping variables and defining the access types, a snapshot of the current configuration must be saved in order to generate the Modbus-handling scripts.&lt;br /&gt;
&lt;br /&gt;
1. Click '''Files''', and then '''Save As'''.&lt;br /&gt;
&lt;br /&gt;
:The mapping is saved in an '''.mbas''' file.&lt;br /&gt;
&lt;br /&gt;
:If you makes changes after saving the .mbas file, the MBAS file indicator in the status bar will light up.&lt;br /&gt;
&lt;br /&gt;
2. To generate the product files, click '''Generate'''.&lt;br /&gt;
&lt;br /&gt;
:The Log windows will display Success messages.&lt;br /&gt;
&lt;br /&gt;
:The product files were created in the target folder you chose when saving the .mbas file.&lt;br /&gt;
&lt;br /&gt;
:The files HMIMBMAP.LIB and HMIMBMAP.PRG will automatically open in ControlStudio.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(5).png|600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Using the Modbus-Handling Scripts==&lt;br /&gt;
1. Using the ControlStudio File Manager, copy HMIMBMAP.LIB and HMIMBMAP.PRG to the softMC.&lt;br /&gt;
&lt;br /&gt;
'''Note''':	Before these files can be loaded and used, your application must be loaded, and all mapped variables must exist in the softMC memory.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(6).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Using the ControlStudio Terminal, load the library HMIMBMAP.LIB:&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.LIB&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Since HMIMBMAP.PRG imports this library it must not be loaded globally. This code can be executed wherever is convenient.&lt;br /&gt;
&lt;br /&gt;
2. Verify that the library was loaded successfully:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;?tasklist&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Start the Modbus communication task by loading the program:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.PRG&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
HMIMBMAP.PRG is defined as '''Program Continue''', therefore it starts automatically after it is loaded and it does not require an explicit StartTask command.&lt;br /&gt;
&lt;br /&gt;
Of course, HMIMBMAP.PRG can be loaded and executed only after HMIMBMAP.LIB is loaded. Therefore, you should add the following code to AUTOEXEC.PRG or wherever is convenient:&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.LIB&lt;br /&gt;
Load HMIMBMAP.PRG&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HMIMBMAP.PRG Explained==&lt;br /&gt;
The code:&lt;br /&gt;
&amp;lt;pre&amp;gt;import HMIMBMAP.LIB&lt;br /&gt;
Program Continue&lt;br /&gt;
	dim retVal as long = 0&lt;br /&gt;
	retVal = Init_Modbus&lt;br /&gt;
	while 1&lt;br /&gt;
		retVal = Read_Modbus_Registers&lt;br /&gt;
		retVal = Write_Modbus_Registers&lt;br /&gt;
		sleep 1&lt;br /&gt;
	end while&lt;br /&gt;
End Program&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The functions '''Init_Modbus''', '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are implemented in '''HMIMBMAP.LIB''', which is automatically generated by a Python script.&lt;br /&gt;
&lt;br /&gt;
The function '''Init_Modbus''' starts the Modbus server and then writes to the Modbus address space all the '''Write Access Variables''' (i.e., all the variables read by the softMC from the Modbus address space). This feature allows you to setup the system to start with an initialized Modbus address space before the HMI/PLC connects to it. The HMI/PLC can read the address space and initialize itself accordingly.&lt;br /&gt;
&lt;br /&gt;
The functions '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are invoked cyclically and indefinitely. '''Read_Modbus_Registers''' reads all the tags that are written by the HMI/PLC and updates the '''Write Access''' variables with new values, while '''Write_Modbus_Registers''' does the opposite.&lt;br /&gt;
&lt;br /&gt;
=HMI IDEs and .CSV Files=&lt;br /&gt;
Each line in the .csv file generated by the MCMBConfigurator file holds data about a single variable, such as Modbus address or data type.&lt;br /&gt;
 &lt;br /&gt;
This data can be used by an HMI IDE to import Modbus tags and associate them with HMI functionality.&lt;br /&gt;
&lt;br /&gt;
Different manufacturer IDEs use different .csv formatting; therefore, various Python scripts are used to create the specific .csv files suitable for a particular manufacturer IDE.&lt;br /&gt;
&lt;br /&gt;
==JMobile Studio==&lt;br /&gt;
Python script: '''JMobile_csv.py''' &lt;br /&gt;
&lt;br /&gt;
Default target .csv file name: '''JMobile_HMI.csv''' (user-definable)&lt;br /&gt;
&lt;br /&gt;
To import tags, perform the following procedure in JMobile Studio.&lt;br /&gt;
&lt;br /&gt;
===Define Protocol===&lt;br /&gt;
1. In the ProjectView pane, select '''Protocols'''.&lt;br /&gt;
&lt;br /&gt;
2. Click the blue '''+''' sign.&lt;br /&gt;
&lt;br /&gt;
3. From the list, select Modbus TCP.&lt;br /&gt;
&lt;br /&gt;
4. In the Modbus TCP configuration window, define: &lt;br /&gt;
&lt;br /&gt;
:IP Address: Set the IP address of your softMC.&lt;br /&gt;
&lt;br /&gt;
:PLC Models: Select '''Generic Modbus''' (0-based), meaning the softMC Modbus server starts addressing tags from 0.&lt;br /&gt;
&lt;br /&gt;
:Click '''OK'''.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(7).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
===Import Tags===&lt;br /&gt;
1. In the ProjectView pane, select '''Tags'''.&lt;br /&gt;
&lt;br /&gt;
2. From the list, select '''Modbus TCP''' protocol defined previously.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(8).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
3. Click the '''Import Tags''' button. &lt;br /&gt;
&lt;br /&gt;
4. Open the generated file '''JMobile_HMI.csv'''.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(9).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
5. Select the tags you want to add to your project, and click the ''Import tags'' button.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(10).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==AdvancedHMI==&lt;br /&gt;
AdvancedHMI is an open source project (http://www.advancedhmi.com/), which is downloaded as a Visual Basic project. You can then open the project, add widgets, compile, and run it.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(11).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Drag and drop '''ModbusTCPCom''' into MainForm.vb [Design].&lt;br /&gt;
&lt;br /&gt;
2. The driver appears the bottom of the screen (circled in green). &lt;br /&gt;
&lt;br /&gt;
:Click the driver, and then use the Properties pane (circled in red) to setup the IP address of the Modbus server.&lt;br /&gt;
&lt;br /&gt;
:For example, drag and drop DigitalPanelMeter and MomentaryButton into MainForm.vb [Design].&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(12).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
3. For both widgets, use the Properties pane to set the Modbus address that is associated with the variables from the softMC application.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(13).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
'''Note''':&lt;br /&gt;
::MC Modbus server addressing starts from '''40000'''.&lt;br /&gt;
::AdvancedHMI Modbus client addressing starts from '''40001'''.&lt;br /&gt;
::Prefix the address with the letter '''L'''.&lt;br /&gt;
&lt;br /&gt;
4. Save the project (Ctrl+S).&lt;br /&gt;
&lt;br /&gt;
5. Build the project (Ctrl+Shift+B).&lt;br /&gt;
&lt;br /&gt;
6. Run the project (F5).&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125880</id>
		<title>Modbus Communication API</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125880"/>
				<updated>2016-04-18T13:26:27Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: /* Initializing a Modbus Server */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
=== Basic Overview ===&lt;br /&gt;
* This describes how to set up Modbus communication for the softMC, and how to generate softMC scripts to handle Modbus communication.&lt;br /&gt;
* It is assumed you are familiar with the principles of Modbus communication, although some of them will be described in this page.&lt;br /&gt;
* It is also assumed your are familiar with the softMC, ControlStudio and MC-Basic programming.&lt;br /&gt;
&lt;br /&gt;
=== Modbus Communication Background ===&lt;br /&gt;
* A Motion Controller (MC) can act as a server (slave), a client (master) or both at the same time.&lt;br /&gt;
* Each MC connection (TCP/RTU) can be used either as a server component (if the connection is used by the MC’s server-side) or as a client component (if the connection is used by the MC’s client-side).&lt;br /&gt;
* Each component has its own parameters that defines it.&lt;br /&gt;
* When the MC acts as a server, all server components share the '''same''' memory address space, thus acting as one server with multiple connections.&lt;br /&gt;
* Each server (slave) on a Modbus network has its own deviceID, which is a number between 1 and 247.&lt;br /&gt;
&lt;br /&gt;
=== The Modbus server registers ===&lt;br /&gt;
* There are 4 types of registers in the Modbus Server address space:&lt;br /&gt;
*# Bits (1-bit registers)&lt;br /&gt;
*# Input Bits (1-bit READ-ONLY registers)&lt;br /&gt;
*# Holding Registers (16-bit registers)&lt;br /&gt;
*# Input Registers (16-bit READ-ONLY registers)&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
In order to get started in using the Modbus features:&lt;br /&gt;
# Download the required files, according to your system's type:&lt;br /&gt;
#* Required files for [[File:modbus_requiredFiles_x86.zip|modbus_X86.ZIP]].&lt;br /&gt;
#* Required files for ARM systems.&lt;br /&gt;
# Using the ControlStudio File Manager, Upload the following files to your MC:&lt;br /&gt;
#* mb_x86.O ''(for softMC7 )'' / mb_armA9.O ''(for softMC3)''&lt;br /&gt;
#* Modbus.lib&lt;br /&gt;
#* MB_Loader.prg&lt;br /&gt;
#:[[File:modbus;newAPI-upload.jpg|850px]]&lt;br /&gt;
# Run MB_Loader.prg&lt;br /&gt;
&lt;br /&gt;
That's it! You're now ready to configure the Modbus system.&lt;br /&gt;
&lt;br /&gt;
== Initializing a Modbus Server ==&lt;br /&gt;
To initialize the Modbus server address space, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;?init_multi_server([bits],[input_bits],[holding registers],[input_registers])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The function prints &amp;quot;success&amp;quot; and returns 0 on success, or return an error code on failure.&lt;br /&gt;
* &amp;lt;u&amp;gt;'''Notice:'''&amp;lt;/u&amp;gt; You can call this method only if there are no active server components.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Memory allocation failure.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Some servers are still running and using an already mapped address space.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to create a modbus mapping.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Server Components ==&lt;br /&gt;
=== Adding server components ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Creating a TCP server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_server_create([port],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens a TCP connection to the server on port [port] with deviceID [deviceID], and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Failed to create main socket.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|}&lt;br /&gt;
==== Creating an RTU server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_server_create([type],[port],[baudrate],[data bits],[stop bits],[parity],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens an RTU connection with the given parameters, and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Invalid device string.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Invalid parity.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed opening RTU.&lt;br /&gt;
|-&lt;br /&gt;
| -5&lt;br /&gt;
| Failed allocating query buffer memory.&lt;br /&gt;
|-&lt;br /&gt;
| -6&lt;br /&gt;
| Failed to set RTU mode.&lt;br /&gt;
|-&lt;br /&gt;
| -7&lt;br /&gt;
| Unable to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -8&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|-&lt;br /&gt;
| -9&lt;br /&gt;
| The device is already in use by another system component.&lt;br /&gt;
|}&lt;br /&gt;
=== Stopping Server Components ===&lt;br /&gt;
==== Stopping a specific server component ====&lt;br /&gt;
You can stop a specific server component by passing its handle to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate server component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
==== Stopping all server components ====&lt;br /&gt;
You can stop all server components with a single call to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop_all&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function will:&lt;br /&gt;
* Stop and free all server components.&lt;br /&gt;
* Free the shared address space.&lt;br /&gt;
* Return 0 on success, -1 on failure.&lt;br /&gt;
== Client Components ==&lt;br /&gt;
=== Adding client components ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Adding a TCP Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_client_create([ip],[port])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will opens a TCP connection to the client on the given ip and port, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
==== Adding an RTU Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_client_create([type],[port],[baudrate],[data bits],[stop bits],[parity])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will open an RTU connection to the client with the given parameters, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
=== Stopping client components ===&lt;br /&gt;
A specific client can be stopped by calling:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_client_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate client component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reset the Modbus System ==&lt;br /&gt;
Sometimes, a user may wish to stop all server and client components at once, and reset the Modbus system (for example, when a user want to initialize a different Modbus system). To do that, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_reset&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function:&lt;br /&gt;
* Stops all running servers and clients.&lt;br /&gt;
* Frees their memory.&lt;br /&gt;
* Frees the shared address space.&lt;br /&gt;
* Reset the handle counter.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reading and Writing ==&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
* Therefore, Servers and clients use different functions to read/write data from the address space.&lt;br /&gt;
=== Server Components ===&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers and return them.&lt;br /&gt;
* When a read error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_REG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_READ_BIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_INREG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt; val = MB_SERVER_READ_INBIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data into the different types of registers.&lt;br /&gt;
* When a write error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Writing to holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_BIT([index],[new value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_INBIT([index],[value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| New value&lt;br /&gt;
| The value to write, must be from the appropriate type.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Error codes ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Invalid index.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Local server's address space isn't mapped yet.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to catch the register mutex.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to release the register mutex.&lt;br /&gt;
|}&lt;br /&gt;
=== Client Components ===&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The read value is inserted into an existing variable from the appropriate type (long/double).&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_REG_LONG([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_BITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_LONG ([handle],[deviceID],[addr],[dest ptr]) &lt;br /&gt;
Val = MB_CLIENT_READ_INREG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_INBITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to read from.&lt;br /&gt;
|-&lt;br /&gt;
| Num of bits (Reading bits)&lt;br /&gt;
| The number of bits to read.&lt;br /&gt;
|-&lt;br /&gt;
| dest ptr / dest arr ptr&lt;br /&gt;
| The variable to store the read data. When reading bits, this must be an array of longs in the appropriate size (&amp;gt;= Num of bits).&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data from existing variables to the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Writing to Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_LONG([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_SHORT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_FLOAT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_DOUBLE([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_WRITE_BIT([handle],[deviceID],[addr],[src ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to start writing to.&lt;br /&gt;
|-&lt;br /&gt;
| src ptr&lt;br /&gt;
| The variable that stores the data to be written. This must be a variable from the appropriate type.&lt;br /&gt;
|}&lt;br /&gt;
=== Reading and Writing Summary ===&lt;br /&gt;
[[File:modbus;newAPI-readwriteSummary.jpg|850px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Modbus Configurator=&lt;br /&gt;
The Modbus Communication Scripts Generator ('''Modbus Configurator''') is a tool that allows you to map your softMC application variables to Modbus tags.&lt;br /&gt;
&lt;br /&gt;
'''Note''':	Tag access is defined from the HMI perspective. In other words:&lt;br /&gt;
* '''Read Access''' variables are written by the softMC to the Modbus address space.&lt;br /&gt;
* '''Write Access''' variables are read by the softMC from the Modbus address space.&lt;br /&gt;
&lt;br /&gt;
You can define whether a variable has Read Access (meaning it is read by the HMI/PLC), or Write Access (meaning it is written by the HMI/PLC). Currently, it is not possible to define a variable as having both Read Access and Write Access. However, all Write Access variables can be written once by the softMC upon system startup by a special routine that is generated in HMIMBMAP.LIB (see section below).&lt;br /&gt;
&lt;br /&gt;
The MCMBConfigurator creates three files:&lt;br /&gt;
* '''HMIMBMAP.LIB''' and '''HMIMBMAP.PRG''' files are MC-Basic scripts that are used to start a softMC task. These are default file names, which you can change, but must retain the 8.3 format. This task cyclically and indefinitely reads/writes Modbus tags according to access type. &lt;br /&gt;
* A '''.CSV''' format file that can be used by an HMI development environment, such as '''JMobile Studio''' or '''Indusoft''', to automatically import Modbus tags. You define the HMI development environment by selecting various Python scripts that will generate the .csv file.&lt;br /&gt;
&lt;br /&gt;
== Mapping Variables==&lt;br /&gt;
'''Note''': 	Variables destined to be mapped to Modbus tags must be defined as global variables by the Common Shared declaration.&lt;br /&gt;
&lt;br /&gt;
1. In order to map the variables, the program must be loaded in the softMC.&lt;br /&gt;
&lt;br /&gt;
2. Start the Modbus Configuration: from the ControlStudio toolbar, select  Tools, and then Modbus Configurator…&lt;br /&gt;
&lt;br /&gt;
:The Modbus Configurator windows opens.&lt;br /&gt;
&lt;br /&gt;
3. Click Connection, and select Setting.&lt;br /&gt;
&lt;br /&gt;
:The setting dialog box opens, with fields showing the following (default) settings:&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(3).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
* Modbus offset: Used to start the mapping from an address other than zero.&lt;br /&gt;
* Script file name: A Python script that generates the product files. Different scripts create different .csv files.&lt;br /&gt;
* Output LIB, Output Prog, HMI CSV file name: Used to define target file names. &lt;br /&gt;
:'''Note''': The softMC file names must be UPPERCASE and in 8.3 format.&lt;br /&gt;
* MC IP address: Used to set the IP address of your softMC.&lt;br /&gt;
Make any necessary changes in the Settings dialog box. Then click Connection, and then Connect.&lt;br /&gt;
&lt;br /&gt;
Once the Modbus Configurator is connected to softMC it gets updated with the complete list of all the global variables. Double-clicking on variables automatically maps them to Modbus tags in consecutive order. The automatic Modbus address and data type are displayed in the table.&lt;br /&gt;
&lt;br /&gt;
If a mapped variable is defined as CONST, its access type is automatically set to Read. In such instances the access type cannot be changed. Read Access variables are read only by the HMI; therefore the softMC only writes them to the Modbus address space.&lt;br /&gt;
&lt;br /&gt;
A variable that is not defined as CONST automatically appears as Write Access. Double-click on the access type to toggle the variable between Read Access and Write Access, and thus determine whether the variable will be read or written by softMC.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(4).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
==Generating and Using Scripts==&lt;br /&gt;
After you are done mapping variables and defining the access types, a snapshot of the current configuration must be saved in order to generate the Modbus-handling scripts.&lt;br /&gt;
&lt;br /&gt;
1. Click '''Files''', and then '''Save As'''.&lt;br /&gt;
&lt;br /&gt;
:The mapping is saved in an '''.mbas''' file.&lt;br /&gt;
&lt;br /&gt;
:If you makes changes after saving the .mbas file, the MBAS file indicator in the status bar will light up.&lt;br /&gt;
&lt;br /&gt;
2. To generate the product files, click '''Generate'''.&lt;br /&gt;
&lt;br /&gt;
:The Log windows will display Success messages.&lt;br /&gt;
&lt;br /&gt;
:The product files were created in the target folder you chose when saving the .mbas file.&lt;br /&gt;
&lt;br /&gt;
:The files HMIMBMAP.LIB and HMIMBMAP.PRG will automatically open in ControlStudio.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(5).png|600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Using the Modbus-Handling Scripts==&lt;br /&gt;
1. Using the ControlStudio File Manager, copy HMIMBMAP.LIB and HMIMBMAP.PRG to the softMC.&lt;br /&gt;
&lt;br /&gt;
'''Note''':	Before these files can be loaded and used, your application must be loaded, and all mapped variables must exist in the softMC memory.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(6).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Using the ControlStudio Terminal, load the library HMIMBMAP.LIB:&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.LIB&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Since HMIMBMAP.PRG imports this library it must not be loaded globally. This code can be executed wherever is convenient.&lt;br /&gt;
&lt;br /&gt;
2. Verify that the library was loaded successfully:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;?tasklist&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Start the Modbus communication task by loading the program:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.PRG&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
HMIMBMAP.PRG is defined as '''Program Continue''', therefore it starts automatically after it is loaded and it does not require an explicit StartTask command.&lt;br /&gt;
&lt;br /&gt;
Of course, HMIMBMAP.PRG can be loaded and executed only after HMIMBMAP.LIB is loaded. Therefore, you should add the following code to AUTOEXEC.PRG or wherever is convenient:&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.LIB&lt;br /&gt;
Load HMIMBMAP.PRG&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HMIMBMAP.PRG Explained==&lt;br /&gt;
The code:&lt;br /&gt;
&amp;lt;pre&amp;gt;import HMIMBMAP.LIB&lt;br /&gt;
Program Continue&lt;br /&gt;
	dim retVal as long = 0&lt;br /&gt;
	retVal = Init_Modbus&lt;br /&gt;
	while 1&lt;br /&gt;
		retVal = Read_Modbus_Registers&lt;br /&gt;
		retVal = Write_Modbus_Registers&lt;br /&gt;
		sleep 1&lt;br /&gt;
	end while&lt;br /&gt;
End Program&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The functions '''Init_Modbus''', '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are implemented in '''HMIMBMAP.LIB''', which is automatically generated by a Python script.&lt;br /&gt;
&lt;br /&gt;
The function '''Init_Modbus''' starts the Modbus server and then writes to the Modbus address space all the '''Write Access Variables''' (i.e., all the variables read by the softMC from the Modbus address space). This feature allows you to setup the system to start with an initialized Modbus address space before the HMI/PLC connects to it. The HMI/PLC can read the address space and initialize itself accordingly.&lt;br /&gt;
&lt;br /&gt;
The functions '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are invoked cyclically and indefinitely. '''Read_Modbus_Registers''' reads all the tags that are written by the HMI/PLC and updates the '''Write Access''' variables with new values, while '''Write_Modbus_Registers''' does the opposite.&lt;br /&gt;
&lt;br /&gt;
=HMI IDEs and .CSV Files=&lt;br /&gt;
Each line in the .csv file generated by the MCMBConfigurator file holds data about a single variable, such as Modbus address or data type.&lt;br /&gt;
 &lt;br /&gt;
This data can be used by an HMI IDE to import Modbus tags and associate them with HMI functionality.&lt;br /&gt;
&lt;br /&gt;
Different manufacturer IDEs use different .csv formatting; therefore, various Python scripts are used to create the specific .csv files suitable for a particular manufacturer IDE.&lt;br /&gt;
&lt;br /&gt;
==JMobile Studio==&lt;br /&gt;
Python script: '''JMobile_csv.py''' &lt;br /&gt;
&lt;br /&gt;
Default target .csv file name: '''JMobile_HMI.csv''' (user-definable)&lt;br /&gt;
&lt;br /&gt;
To import tags, perform the following procedure in JMobile Studio.&lt;br /&gt;
&lt;br /&gt;
===Define Protocol===&lt;br /&gt;
1. In the ProjectView pane, select '''Protocols'''.&lt;br /&gt;
&lt;br /&gt;
2. Click the blue '''+''' sign.&lt;br /&gt;
&lt;br /&gt;
3. From the list, select Modbus TCP.&lt;br /&gt;
&lt;br /&gt;
4. In the Modbus TCP configuration window, define: &lt;br /&gt;
&lt;br /&gt;
:IP Address: Set the IP address of your softMC.&lt;br /&gt;
&lt;br /&gt;
:PLC Models: Select '''Generic Modbus''' (0-based), meaning the softMC Modbus server starts addressing tags from 0.&lt;br /&gt;
&lt;br /&gt;
:Click '''OK'''.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(7).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
===Import Tags===&lt;br /&gt;
1. In the ProjectView pane, select '''Tags'''.&lt;br /&gt;
&lt;br /&gt;
2. From the list, select '''Modbus TCP''' protocol defined previously.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(8).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
3. Click the '''Import Tags''' button. &lt;br /&gt;
&lt;br /&gt;
4. Open the generated file '''JMobile_HMI.csv'''.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(9).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
5. Select the tags you want to add to your project, and click the ''Import tags'' button.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(10).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==AdvancedHMI==&lt;br /&gt;
AdvancedHMI is an open source project (http://www.advancedhmi.com/), which is downloaded as a Visual Basic project. You can then open the project, add widgets, compile, and run it.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(11).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Drag and drop '''ModbusTCPCom''' into MainForm.vb [Design].&lt;br /&gt;
&lt;br /&gt;
2. The driver appears the bottom of the screen (circled in green). &lt;br /&gt;
&lt;br /&gt;
:Click the driver, and then use the Properties pane (circled in red) to setup the IP address of the Modbus server.&lt;br /&gt;
&lt;br /&gt;
:For example, drag and drop DigitalPanelMeter and MomentaryButton into MainForm.vb [Design].&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(12).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
3. For both widgets, use the Properties pane to set the Modbus address that is associated with the variables from the softMC application.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(13).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
'''Note''':&lt;br /&gt;
::MC Modbus server addressing starts from '''40000'''.&lt;br /&gt;
::AdvancedHMI Modbus client addressing starts from '''40001'''.&lt;br /&gt;
::Prefix the address with the letter '''L'''.&lt;br /&gt;
&lt;br /&gt;
4. Save the project (Ctrl+S).&lt;br /&gt;
&lt;br /&gt;
5. Build the project (Ctrl+Shift+B).&lt;br /&gt;
&lt;br /&gt;
6. Run the project (F5).&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125879</id>
		<title>Modbus Communication API</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125879"/>
				<updated>2016-04-18T13:23:42Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: /* Getting Started */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
=== Basic Overview ===&lt;br /&gt;
* This describes how to set up Modbus communication for the softMC, and how to generate softMC scripts to handle Modbus communication.&lt;br /&gt;
* It is assumed you are familiar with the principles of Modbus communication, although some of them will be described in this page.&lt;br /&gt;
* It is also assumed your are familiar with the softMC, ControlStudio and MC-Basic programming.&lt;br /&gt;
&lt;br /&gt;
=== Modbus Communication Background ===&lt;br /&gt;
* A Motion Controller (MC) can act as a server (slave), a client (master) or both at the same time.&lt;br /&gt;
* Each MC connection (TCP/RTU) can be used either as a server component (if the connection is used by the MC’s server-side) or as a client component (if the connection is used by the MC’s client-side).&lt;br /&gt;
* Each component has its own parameters that defines it.&lt;br /&gt;
* When the MC acts as a server, all server components share the '''same''' memory address space, thus acting as one server with multiple connections.&lt;br /&gt;
* Each server (slave) on a Modbus network has its own deviceID, which is a number between 1 and 247.&lt;br /&gt;
&lt;br /&gt;
=== The Modbus server registers ===&lt;br /&gt;
* There are 4 types of registers in the Modbus Server address space:&lt;br /&gt;
*# Bits (1-bit registers)&lt;br /&gt;
*# Input Bits (1-bit READ-ONLY registers)&lt;br /&gt;
*# Holding Registers (16-bit registers)&lt;br /&gt;
*# Input Registers (16-bit READ-ONLY registers)&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
In order to get started in using the Modbus features:&lt;br /&gt;
# Download the required files, according to your system's type:&lt;br /&gt;
#* Required files for [[File:modbus_requiredFiles_x86.zip|modbus_X86.ZIP]].&lt;br /&gt;
#* Required files for ARM systems.&lt;br /&gt;
# Using the ControlStudio File Manager, Upload the following files to your MC:&lt;br /&gt;
#* mb_x86.O ''(for softMC7 )'' / mb_armA9.O ''(for softMC3)''&lt;br /&gt;
#* Modbus.lib&lt;br /&gt;
#* MB_Loader.prg&lt;br /&gt;
#:[[File:modbus;newAPI-upload.jpg|850px]]&lt;br /&gt;
# Run MB_Loader.prg&lt;br /&gt;
&lt;br /&gt;
That's it! You're now ready to configure the Modbus system.&lt;br /&gt;
&lt;br /&gt;
== Initializing a Modbus Server ==&lt;br /&gt;
To initialize the Modbus server address space, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;?init_multi_server([bits],[input_bits],[holding registers],[input_registers])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The function prints &amp;quot;success&amp;quot; and returns 0 on success, or return an error code on failure.&lt;br /&gt;
* &amp;lt;u&amp;gt;'''Notice:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
*# This is '''NOT''' required when softMC does not run a modbus server.&lt;br /&gt;
*# You can call this method only if no servers are running.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Memory allocation failure.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Some servers are still running and using an already mapped address space.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to create a modbus mapping.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Server Components ==&lt;br /&gt;
=== Adding server components ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Creating a TCP server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_server_create([port],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens a TCP connection to the server on port [port] with deviceID [deviceID], and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Failed to create main socket.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|}&lt;br /&gt;
==== Creating an RTU server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_server_create([type],[port],[baudrate],[data bits],[stop bits],[parity],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens an RTU connection with the given parameters, and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Invalid device string.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Invalid parity.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed opening RTU.&lt;br /&gt;
|-&lt;br /&gt;
| -5&lt;br /&gt;
| Failed allocating query buffer memory.&lt;br /&gt;
|-&lt;br /&gt;
| -6&lt;br /&gt;
| Failed to set RTU mode.&lt;br /&gt;
|-&lt;br /&gt;
| -7&lt;br /&gt;
| Unable to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -8&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|-&lt;br /&gt;
| -9&lt;br /&gt;
| The device is already in use by another system component.&lt;br /&gt;
|}&lt;br /&gt;
=== Stopping Server Components ===&lt;br /&gt;
==== Stopping a specific server component ====&lt;br /&gt;
You can stop a specific server component by passing its handle to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate server component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
==== Stopping all server components ====&lt;br /&gt;
You can stop all server components with a single call to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop_all&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function will:&lt;br /&gt;
* Stop and free all server components.&lt;br /&gt;
* Free the shared address space.&lt;br /&gt;
* Return 0 on success, -1 on failure.&lt;br /&gt;
== Client Components ==&lt;br /&gt;
=== Adding client components ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Adding a TCP Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_client_create([ip],[port])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will opens a TCP connection to the client on the given ip and port, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
==== Adding an RTU Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_client_create([type],[port],[baudrate],[data bits],[stop bits],[parity])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will open an RTU connection to the client with the given parameters, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
=== Stopping client components ===&lt;br /&gt;
A specific client can be stopped by calling:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_client_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate client component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reset the Modbus System ==&lt;br /&gt;
Sometimes, a user may wish to stop all server and client components at once, and reset the Modbus system (for example, when a user want to initialize a different Modbus system). To do that, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_reset&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function:&lt;br /&gt;
* Stops all running servers and clients.&lt;br /&gt;
* Frees their memory.&lt;br /&gt;
* Frees the shared address space.&lt;br /&gt;
* Reset the handle counter.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reading and Writing ==&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
* Therefore, Servers and clients use different functions to read/write data from the address space.&lt;br /&gt;
=== Server Components ===&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers and return them.&lt;br /&gt;
* When a read error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_REG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_READ_BIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_INREG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt; val = MB_SERVER_READ_INBIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data into the different types of registers.&lt;br /&gt;
* When a write error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Writing to holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_BIT([index],[new value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_INBIT([index],[value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| New value&lt;br /&gt;
| The value to write, must be from the appropriate type.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Error codes ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Invalid index.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Local server's address space isn't mapped yet.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to catch the register mutex.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to release the register mutex.&lt;br /&gt;
|}&lt;br /&gt;
=== Client Components ===&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The read value is inserted into an existing variable from the appropriate type (long/double).&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_REG_LONG([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_BITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_LONG ([handle],[deviceID],[addr],[dest ptr]) &lt;br /&gt;
Val = MB_CLIENT_READ_INREG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_INBITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to read from.&lt;br /&gt;
|-&lt;br /&gt;
| Num of bits (Reading bits)&lt;br /&gt;
| The number of bits to read.&lt;br /&gt;
|-&lt;br /&gt;
| dest ptr / dest arr ptr&lt;br /&gt;
| The variable to store the read data. When reading bits, this must be an array of longs in the appropriate size (&amp;gt;= Num of bits).&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data from existing variables to the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Writing to Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_LONG([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_SHORT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_FLOAT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_DOUBLE([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_WRITE_BIT([handle],[deviceID],[addr],[src ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to start writing to.&lt;br /&gt;
|-&lt;br /&gt;
| src ptr&lt;br /&gt;
| The variable that stores the data to be written. This must be a variable from the appropriate type.&lt;br /&gt;
|}&lt;br /&gt;
=== Reading and Writing Summary ===&lt;br /&gt;
[[File:modbus;newAPI-readwriteSummary.jpg|850px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Modbus Configurator=&lt;br /&gt;
The Modbus Communication Scripts Generator ('''Modbus Configurator''') is a tool that allows you to map your softMC application variables to Modbus tags.&lt;br /&gt;
&lt;br /&gt;
'''Note''':	Tag access is defined from the HMI perspective. In other words:&lt;br /&gt;
* '''Read Access''' variables are written by the softMC to the Modbus address space.&lt;br /&gt;
* '''Write Access''' variables are read by the softMC from the Modbus address space.&lt;br /&gt;
&lt;br /&gt;
You can define whether a variable has Read Access (meaning it is read by the HMI/PLC), or Write Access (meaning it is written by the HMI/PLC). Currently, it is not possible to define a variable as having both Read Access and Write Access. However, all Write Access variables can be written once by the softMC upon system startup by a special routine that is generated in HMIMBMAP.LIB (see section below).&lt;br /&gt;
&lt;br /&gt;
The MCMBConfigurator creates three files:&lt;br /&gt;
* '''HMIMBMAP.LIB''' and '''HMIMBMAP.PRG''' files are MC-Basic scripts that are used to start a softMC task. These are default file names, which you can change, but must retain the 8.3 format. This task cyclically and indefinitely reads/writes Modbus tags according to access type. &lt;br /&gt;
* A '''.CSV''' format file that can be used by an HMI development environment, such as '''JMobile Studio''' or '''Indusoft''', to automatically import Modbus tags. You define the HMI development environment by selecting various Python scripts that will generate the .csv file.&lt;br /&gt;
&lt;br /&gt;
== Mapping Variables==&lt;br /&gt;
'''Note''': 	Variables destined to be mapped to Modbus tags must be defined as global variables by the Common Shared declaration.&lt;br /&gt;
&lt;br /&gt;
1. In order to map the variables, the program must be loaded in the softMC.&lt;br /&gt;
&lt;br /&gt;
2. Start the Modbus Configuration: from the ControlStudio toolbar, select  Tools, and then Modbus Configurator…&lt;br /&gt;
&lt;br /&gt;
:The Modbus Configurator windows opens.&lt;br /&gt;
&lt;br /&gt;
3. Click Connection, and select Setting.&lt;br /&gt;
&lt;br /&gt;
:The setting dialog box opens, with fields showing the following (default) settings:&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(3).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
* Modbus offset: Used to start the mapping from an address other than zero.&lt;br /&gt;
* Script file name: A Python script that generates the product files. Different scripts create different .csv files.&lt;br /&gt;
* Output LIB, Output Prog, HMI CSV file name: Used to define target file names. &lt;br /&gt;
:'''Note''': The softMC file names must be UPPERCASE and in 8.3 format.&lt;br /&gt;
* MC IP address: Used to set the IP address of your softMC.&lt;br /&gt;
Make any necessary changes in the Settings dialog box. Then click Connection, and then Connect.&lt;br /&gt;
&lt;br /&gt;
Once the Modbus Configurator is connected to softMC it gets updated with the complete list of all the global variables. Double-clicking on variables automatically maps them to Modbus tags in consecutive order. The automatic Modbus address and data type are displayed in the table.&lt;br /&gt;
&lt;br /&gt;
If a mapped variable is defined as CONST, its access type is automatically set to Read. In such instances the access type cannot be changed. Read Access variables are read only by the HMI; therefore the softMC only writes them to the Modbus address space.&lt;br /&gt;
&lt;br /&gt;
A variable that is not defined as CONST automatically appears as Write Access. Double-click on the access type to toggle the variable between Read Access and Write Access, and thus determine whether the variable will be read or written by softMC.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(4).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
==Generating and Using Scripts==&lt;br /&gt;
After you are done mapping variables and defining the access types, a snapshot of the current configuration must be saved in order to generate the Modbus-handling scripts.&lt;br /&gt;
&lt;br /&gt;
1. Click '''Files''', and then '''Save As'''.&lt;br /&gt;
&lt;br /&gt;
:The mapping is saved in an '''.mbas''' file.&lt;br /&gt;
&lt;br /&gt;
:If you makes changes after saving the .mbas file, the MBAS file indicator in the status bar will light up.&lt;br /&gt;
&lt;br /&gt;
2. To generate the product files, click '''Generate'''.&lt;br /&gt;
&lt;br /&gt;
:The Log windows will display Success messages.&lt;br /&gt;
&lt;br /&gt;
:The product files were created in the target folder you chose when saving the .mbas file.&lt;br /&gt;
&lt;br /&gt;
:The files HMIMBMAP.LIB and HMIMBMAP.PRG will automatically open in ControlStudio.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(5).png|600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Using the Modbus-Handling Scripts==&lt;br /&gt;
1. Using the ControlStudio File Manager, copy HMIMBMAP.LIB and HMIMBMAP.PRG to the softMC.&lt;br /&gt;
&lt;br /&gt;
'''Note''':	Before these files can be loaded and used, your application must be loaded, and all mapped variables must exist in the softMC memory.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(6).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Using the ControlStudio Terminal, load the library HMIMBMAP.LIB:&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.LIB&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Since HMIMBMAP.PRG imports this library it must not be loaded globally. This code can be executed wherever is convenient.&lt;br /&gt;
&lt;br /&gt;
2. Verify that the library was loaded successfully:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;?tasklist&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Start the Modbus communication task by loading the program:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.PRG&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
HMIMBMAP.PRG is defined as '''Program Continue''', therefore it starts automatically after it is loaded and it does not require an explicit StartTask command.&lt;br /&gt;
&lt;br /&gt;
Of course, HMIMBMAP.PRG can be loaded and executed only after HMIMBMAP.LIB is loaded. Therefore, you should add the following code to AUTOEXEC.PRG or wherever is convenient:&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.LIB&lt;br /&gt;
Load HMIMBMAP.PRG&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HMIMBMAP.PRG Explained==&lt;br /&gt;
The code:&lt;br /&gt;
&amp;lt;pre&amp;gt;import HMIMBMAP.LIB&lt;br /&gt;
Program Continue&lt;br /&gt;
	dim retVal as long = 0&lt;br /&gt;
	retVal = Init_Modbus&lt;br /&gt;
	while 1&lt;br /&gt;
		retVal = Read_Modbus_Registers&lt;br /&gt;
		retVal = Write_Modbus_Registers&lt;br /&gt;
		sleep 1&lt;br /&gt;
	end while&lt;br /&gt;
End Program&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The functions '''Init_Modbus''', '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are implemented in '''HMIMBMAP.LIB''', which is automatically generated by a Python script.&lt;br /&gt;
&lt;br /&gt;
The function '''Init_Modbus''' starts the Modbus server and then writes to the Modbus address space all the '''Write Access Variables''' (i.e., all the variables read by the softMC from the Modbus address space). This feature allows you to setup the system to start with an initialized Modbus address space before the HMI/PLC connects to it. The HMI/PLC can read the address space and initialize itself accordingly.&lt;br /&gt;
&lt;br /&gt;
The functions '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are invoked cyclically and indefinitely. '''Read_Modbus_Registers''' reads all the tags that are written by the HMI/PLC and updates the '''Write Access''' variables with new values, while '''Write_Modbus_Registers''' does the opposite.&lt;br /&gt;
&lt;br /&gt;
=HMI IDEs and .CSV Files=&lt;br /&gt;
Each line in the .csv file generated by the MCMBConfigurator file holds data about a single variable, such as Modbus address or data type.&lt;br /&gt;
 &lt;br /&gt;
This data can be used by an HMI IDE to import Modbus tags and associate them with HMI functionality.&lt;br /&gt;
&lt;br /&gt;
Different manufacturer IDEs use different .csv formatting; therefore, various Python scripts are used to create the specific .csv files suitable for a particular manufacturer IDE.&lt;br /&gt;
&lt;br /&gt;
==JMobile Studio==&lt;br /&gt;
Python script: '''JMobile_csv.py''' &lt;br /&gt;
&lt;br /&gt;
Default target .csv file name: '''JMobile_HMI.csv''' (user-definable)&lt;br /&gt;
&lt;br /&gt;
To import tags, perform the following procedure in JMobile Studio.&lt;br /&gt;
&lt;br /&gt;
===Define Protocol===&lt;br /&gt;
1. In the ProjectView pane, select '''Protocols'''.&lt;br /&gt;
&lt;br /&gt;
2. Click the blue '''+''' sign.&lt;br /&gt;
&lt;br /&gt;
3. From the list, select Modbus TCP.&lt;br /&gt;
&lt;br /&gt;
4. In the Modbus TCP configuration window, define: &lt;br /&gt;
&lt;br /&gt;
:IP Address: Set the IP address of your softMC.&lt;br /&gt;
&lt;br /&gt;
:PLC Models: Select '''Generic Modbus''' (0-based), meaning the softMC Modbus server starts addressing tags from 0.&lt;br /&gt;
&lt;br /&gt;
:Click '''OK'''.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(7).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
===Import Tags===&lt;br /&gt;
1. In the ProjectView pane, select '''Tags'''.&lt;br /&gt;
&lt;br /&gt;
2. From the list, select '''Modbus TCP''' protocol defined previously.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(8).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
3. Click the '''Import Tags''' button. &lt;br /&gt;
&lt;br /&gt;
4. Open the generated file '''JMobile_HMI.csv'''.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(9).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
5. Select the tags you want to add to your project, and click the ''Import tags'' button.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(10).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==AdvancedHMI==&lt;br /&gt;
AdvancedHMI is an open source project (http://www.advancedhmi.com/), which is downloaded as a Visual Basic project. You can then open the project, add widgets, compile, and run it.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(11).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Drag and drop '''ModbusTCPCom''' into MainForm.vb [Design].&lt;br /&gt;
&lt;br /&gt;
2. The driver appears the bottom of the screen (circled in green). &lt;br /&gt;
&lt;br /&gt;
:Click the driver, and then use the Properties pane (circled in red) to setup the IP address of the Modbus server.&lt;br /&gt;
&lt;br /&gt;
:For example, drag and drop DigitalPanelMeter and MomentaryButton into MainForm.vb [Design].&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(12).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
3. For both widgets, use the Properties pane to set the Modbus address that is associated with the variables from the softMC application.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(13).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
'''Note''':&lt;br /&gt;
::MC Modbus server addressing starts from '''40000'''.&lt;br /&gt;
::AdvancedHMI Modbus client addressing starts from '''40001'''.&lt;br /&gt;
::Prefix the address with the letter '''L'''.&lt;br /&gt;
&lt;br /&gt;
4. Save the project (Ctrl+S).&lt;br /&gt;
&lt;br /&gt;
5. Build the project (Ctrl+Shift+B).&lt;br /&gt;
&lt;br /&gt;
6. Run the project (F5).&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125878</id>
		<title>Modbus Communication API</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125878"/>
				<updated>2016-04-18T13:23:21Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: /* Getting Started */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
=== Basic Overview ===&lt;br /&gt;
* This describes how to set up Modbus communication for the softMC, and how to generate softMC scripts to handle Modbus communication.&lt;br /&gt;
* It is assumed you are familiar with the principles of Modbus communication, although some of them will be described in this page.&lt;br /&gt;
* It is also assumed your are familiar with the softMC, ControlStudio and MC-Basic programming.&lt;br /&gt;
&lt;br /&gt;
=== Modbus Communication Background ===&lt;br /&gt;
* A Motion Controller (MC) can act as a server (slave), a client (master) or both at the same time.&lt;br /&gt;
* Each MC connection (TCP/RTU) can be used either as a server component (if the connection is used by the MC’s server-side) or as a client component (if the connection is used by the MC’s client-side).&lt;br /&gt;
* Each component has its own parameters that defines it.&lt;br /&gt;
* When the MC acts as a server, all server components share the '''same''' memory address space, thus acting as one server with multiple connections.&lt;br /&gt;
* Each server (slave) on a Modbus network has its own deviceID, which is a number between 1 and 247.&lt;br /&gt;
&lt;br /&gt;
=== The Modbus server registers ===&lt;br /&gt;
* There are 4 types of registers in the Modbus Server address space:&lt;br /&gt;
*# Bits (1-bit registers)&lt;br /&gt;
*# Input Bits (1-bit READ-ONLY registers)&lt;br /&gt;
*# Holding Registers (16-bit registers)&lt;br /&gt;
*# Input Registers (16-bit READ-ONLY registers)&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
In order to get started in using the Modbus features:&lt;br /&gt;
# Download the required files, according to your system's type:&lt;br /&gt;
#* Required files for [[File:modbus_requiredFiles_x86.zip|modbus_X86.ZIP]].&lt;br /&gt;
#* Required files for ARM systems.&lt;br /&gt;
# Using the ControlStudio File Manager, Upload the following files to your MC:&lt;br /&gt;
#* mb_x86.O ''(for softMC7 )'' / mb_armA9.O ''(for softMC3)''&lt;br /&gt;
#* Modbus.lib&lt;br /&gt;
#* MB_Loader.prg&lt;br /&gt;
#:[[File:modbus;newAPI-upload.jpg|850px]]&lt;br /&gt;
# Run MB_Loader.prg&lt;br /&gt;
# That's it! You're now ready to configure the Modbus system.&lt;br /&gt;
&lt;br /&gt;
== Initializing a Modbus Server ==&lt;br /&gt;
To initialize the Modbus server address space, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;?init_multi_server([bits],[input_bits],[holding registers],[input_registers])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The function prints &amp;quot;success&amp;quot; and returns 0 on success, or return an error code on failure.&lt;br /&gt;
* &amp;lt;u&amp;gt;'''Notice:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
*# This is '''NOT''' required when softMC does not run a modbus server.&lt;br /&gt;
*# You can call this method only if no servers are running.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Memory allocation failure.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Some servers are still running and using an already mapped address space.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to create a modbus mapping.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Server Components ==&lt;br /&gt;
=== Adding server components ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Creating a TCP server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_server_create([port],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens a TCP connection to the server on port [port] with deviceID [deviceID], and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Failed to create main socket.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|}&lt;br /&gt;
==== Creating an RTU server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_server_create([type],[port],[baudrate],[data bits],[stop bits],[parity],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens an RTU connection with the given parameters, and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Invalid device string.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Invalid parity.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed opening RTU.&lt;br /&gt;
|-&lt;br /&gt;
| -5&lt;br /&gt;
| Failed allocating query buffer memory.&lt;br /&gt;
|-&lt;br /&gt;
| -6&lt;br /&gt;
| Failed to set RTU mode.&lt;br /&gt;
|-&lt;br /&gt;
| -7&lt;br /&gt;
| Unable to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -8&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|-&lt;br /&gt;
| -9&lt;br /&gt;
| The device is already in use by another system component.&lt;br /&gt;
|}&lt;br /&gt;
=== Stopping Server Components ===&lt;br /&gt;
==== Stopping a specific server component ====&lt;br /&gt;
You can stop a specific server component by passing its handle to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate server component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
==== Stopping all server components ====&lt;br /&gt;
You can stop all server components with a single call to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop_all&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function will:&lt;br /&gt;
* Stop and free all server components.&lt;br /&gt;
* Free the shared address space.&lt;br /&gt;
* Return 0 on success, -1 on failure.&lt;br /&gt;
== Client Components ==&lt;br /&gt;
=== Adding client components ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Adding a TCP Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_client_create([ip],[port])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will opens a TCP connection to the client on the given ip and port, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
==== Adding an RTU Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_client_create([type],[port],[baudrate],[data bits],[stop bits],[parity])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will open an RTU connection to the client with the given parameters, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
=== Stopping client components ===&lt;br /&gt;
A specific client can be stopped by calling:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_client_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate client component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reset the Modbus System ==&lt;br /&gt;
Sometimes, a user may wish to stop all server and client components at once, and reset the Modbus system (for example, when a user want to initialize a different Modbus system). To do that, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_reset&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function:&lt;br /&gt;
* Stops all running servers and clients.&lt;br /&gt;
* Frees their memory.&lt;br /&gt;
* Frees the shared address space.&lt;br /&gt;
* Reset the handle counter.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reading and Writing ==&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
* Therefore, Servers and clients use different functions to read/write data from the address space.&lt;br /&gt;
=== Server Components ===&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers and return them.&lt;br /&gt;
* When a read error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_REG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_READ_BIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_INREG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt; val = MB_SERVER_READ_INBIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data into the different types of registers.&lt;br /&gt;
* When a write error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Writing to holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_BIT([index],[new value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_INBIT([index],[value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| New value&lt;br /&gt;
| The value to write, must be from the appropriate type.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Error codes ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Invalid index.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Local server's address space isn't mapped yet.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to catch the register mutex.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to release the register mutex.&lt;br /&gt;
|}&lt;br /&gt;
=== Client Components ===&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The read value is inserted into an existing variable from the appropriate type (long/double).&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_REG_LONG([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_BITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_LONG ([handle],[deviceID],[addr],[dest ptr]) &lt;br /&gt;
Val = MB_CLIENT_READ_INREG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_INBITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to read from.&lt;br /&gt;
|-&lt;br /&gt;
| Num of bits (Reading bits)&lt;br /&gt;
| The number of bits to read.&lt;br /&gt;
|-&lt;br /&gt;
| dest ptr / dest arr ptr&lt;br /&gt;
| The variable to store the read data. When reading bits, this must be an array of longs in the appropriate size (&amp;gt;= Num of bits).&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data from existing variables to the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Writing to Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_LONG([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_SHORT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_FLOAT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_DOUBLE([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_WRITE_BIT([handle],[deviceID],[addr],[src ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to start writing to.&lt;br /&gt;
|-&lt;br /&gt;
| src ptr&lt;br /&gt;
| The variable that stores the data to be written. This must be a variable from the appropriate type.&lt;br /&gt;
|}&lt;br /&gt;
=== Reading and Writing Summary ===&lt;br /&gt;
[[File:modbus;newAPI-readwriteSummary.jpg|850px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Modbus Configurator=&lt;br /&gt;
The Modbus Communication Scripts Generator ('''Modbus Configurator''') is a tool that allows you to map your softMC application variables to Modbus tags.&lt;br /&gt;
&lt;br /&gt;
'''Note''':	Tag access is defined from the HMI perspective. In other words:&lt;br /&gt;
* '''Read Access''' variables are written by the softMC to the Modbus address space.&lt;br /&gt;
* '''Write Access''' variables are read by the softMC from the Modbus address space.&lt;br /&gt;
&lt;br /&gt;
You can define whether a variable has Read Access (meaning it is read by the HMI/PLC), or Write Access (meaning it is written by the HMI/PLC). Currently, it is not possible to define a variable as having both Read Access and Write Access. However, all Write Access variables can be written once by the softMC upon system startup by a special routine that is generated in HMIMBMAP.LIB (see section below).&lt;br /&gt;
&lt;br /&gt;
The MCMBConfigurator creates three files:&lt;br /&gt;
* '''HMIMBMAP.LIB''' and '''HMIMBMAP.PRG''' files are MC-Basic scripts that are used to start a softMC task. These are default file names, which you can change, but must retain the 8.3 format. This task cyclically and indefinitely reads/writes Modbus tags according to access type. &lt;br /&gt;
* A '''.CSV''' format file that can be used by an HMI development environment, such as '''JMobile Studio''' or '''Indusoft''', to automatically import Modbus tags. You define the HMI development environment by selecting various Python scripts that will generate the .csv file.&lt;br /&gt;
&lt;br /&gt;
== Mapping Variables==&lt;br /&gt;
'''Note''': 	Variables destined to be mapped to Modbus tags must be defined as global variables by the Common Shared declaration.&lt;br /&gt;
&lt;br /&gt;
1. In order to map the variables, the program must be loaded in the softMC.&lt;br /&gt;
&lt;br /&gt;
2. Start the Modbus Configuration: from the ControlStudio toolbar, select  Tools, and then Modbus Configurator…&lt;br /&gt;
&lt;br /&gt;
:The Modbus Configurator windows opens.&lt;br /&gt;
&lt;br /&gt;
3. Click Connection, and select Setting.&lt;br /&gt;
&lt;br /&gt;
:The setting dialog box opens, with fields showing the following (default) settings:&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(3).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
* Modbus offset: Used to start the mapping from an address other than zero.&lt;br /&gt;
* Script file name: A Python script that generates the product files. Different scripts create different .csv files.&lt;br /&gt;
* Output LIB, Output Prog, HMI CSV file name: Used to define target file names. &lt;br /&gt;
:'''Note''': The softMC file names must be UPPERCASE and in 8.3 format.&lt;br /&gt;
* MC IP address: Used to set the IP address of your softMC.&lt;br /&gt;
Make any necessary changes in the Settings dialog box. Then click Connection, and then Connect.&lt;br /&gt;
&lt;br /&gt;
Once the Modbus Configurator is connected to softMC it gets updated with the complete list of all the global variables. Double-clicking on variables automatically maps them to Modbus tags in consecutive order. The automatic Modbus address and data type are displayed in the table.&lt;br /&gt;
&lt;br /&gt;
If a mapped variable is defined as CONST, its access type is automatically set to Read. In such instances the access type cannot be changed. Read Access variables are read only by the HMI; therefore the softMC only writes them to the Modbus address space.&lt;br /&gt;
&lt;br /&gt;
A variable that is not defined as CONST automatically appears as Write Access. Double-click on the access type to toggle the variable between Read Access and Write Access, and thus determine whether the variable will be read or written by softMC.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(4).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
==Generating and Using Scripts==&lt;br /&gt;
After you are done mapping variables and defining the access types, a snapshot of the current configuration must be saved in order to generate the Modbus-handling scripts.&lt;br /&gt;
&lt;br /&gt;
1. Click '''Files''', and then '''Save As'''.&lt;br /&gt;
&lt;br /&gt;
:The mapping is saved in an '''.mbas''' file.&lt;br /&gt;
&lt;br /&gt;
:If you makes changes after saving the .mbas file, the MBAS file indicator in the status bar will light up.&lt;br /&gt;
&lt;br /&gt;
2. To generate the product files, click '''Generate'''.&lt;br /&gt;
&lt;br /&gt;
:The Log windows will display Success messages.&lt;br /&gt;
&lt;br /&gt;
:The product files were created in the target folder you chose when saving the .mbas file.&lt;br /&gt;
&lt;br /&gt;
:The files HMIMBMAP.LIB and HMIMBMAP.PRG will automatically open in ControlStudio.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(5).png|600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Using the Modbus-Handling Scripts==&lt;br /&gt;
1. Using the ControlStudio File Manager, copy HMIMBMAP.LIB and HMIMBMAP.PRG to the softMC.&lt;br /&gt;
&lt;br /&gt;
'''Note''':	Before these files can be loaded and used, your application must be loaded, and all mapped variables must exist in the softMC memory.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(6).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Using the ControlStudio Terminal, load the library HMIMBMAP.LIB:&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.LIB&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Since HMIMBMAP.PRG imports this library it must not be loaded globally. This code can be executed wherever is convenient.&lt;br /&gt;
&lt;br /&gt;
2. Verify that the library was loaded successfully:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;?tasklist&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Start the Modbus communication task by loading the program:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.PRG&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
HMIMBMAP.PRG is defined as '''Program Continue''', therefore it starts automatically after it is loaded and it does not require an explicit StartTask command.&lt;br /&gt;
&lt;br /&gt;
Of course, HMIMBMAP.PRG can be loaded and executed only after HMIMBMAP.LIB is loaded. Therefore, you should add the following code to AUTOEXEC.PRG or wherever is convenient:&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.LIB&lt;br /&gt;
Load HMIMBMAP.PRG&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HMIMBMAP.PRG Explained==&lt;br /&gt;
The code:&lt;br /&gt;
&amp;lt;pre&amp;gt;import HMIMBMAP.LIB&lt;br /&gt;
Program Continue&lt;br /&gt;
	dim retVal as long = 0&lt;br /&gt;
	retVal = Init_Modbus&lt;br /&gt;
	while 1&lt;br /&gt;
		retVal = Read_Modbus_Registers&lt;br /&gt;
		retVal = Write_Modbus_Registers&lt;br /&gt;
		sleep 1&lt;br /&gt;
	end while&lt;br /&gt;
End Program&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The functions '''Init_Modbus''', '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are implemented in '''HMIMBMAP.LIB''', which is automatically generated by a Python script.&lt;br /&gt;
&lt;br /&gt;
The function '''Init_Modbus''' starts the Modbus server and then writes to the Modbus address space all the '''Write Access Variables''' (i.e., all the variables read by the softMC from the Modbus address space). This feature allows you to setup the system to start with an initialized Modbus address space before the HMI/PLC connects to it. The HMI/PLC can read the address space and initialize itself accordingly.&lt;br /&gt;
&lt;br /&gt;
The functions '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are invoked cyclically and indefinitely. '''Read_Modbus_Registers''' reads all the tags that are written by the HMI/PLC and updates the '''Write Access''' variables with new values, while '''Write_Modbus_Registers''' does the opposite.&lt;br /&gt;
&lt;br /&gt;
=HMI IDEs and .CSV Files=&lt;br /&gt;
Each line in the .csv file generated by the MCMBConfigurator file holds data about a single variable, such as Modbus address or data type.&lt;br /&gt;
 &lt;br /&gt;
This data can be used by an HMI IDE to import Modbus tags and associate them with HMI functionality.&lt;br /&gt;
&lt;br /&gt;
Different manufacturer IDEs use different .csv formatting; therefore, various Python scripts are used to create the specific .csv files suitable for a particular manufacturer IDE.&lt;br /&gt;
&lt;br /&gt;
==JMobile Studio==&lt;br /&gt;
Python script: '''JMobile_csv.py''' &lt;br /&gt;
&lt;br /&gt;
Default target .csv file name: '''JMobile_HMI.csv''' (user-definable)&lt;br /&gt;
&lt;br /&gt;
To import tags, perform the following procedure in JMobile Studio.&lt;br /&gt;
&lt;br /&gt;
===Define Protocol===&lt;br /&gt;
1. In the ProjectView pane, select '''Protocols'''.&lt;br /&gt;
&lt;br /&gt;
2. Click the blue '''+''' sign.&lt;br /&gt;
&lt;br /&gt;
3. From the list, select Modbus TCP.&lt;br /&gt;
&lt;br /&gt;
4. In the Modbus TCP configuration window, define: &lt;br /&gt;
&lt;br /&gt;
:IP Address: Set the IP address of your softMC.&lt;br /&gt;
&lt;br /&gt;
:PLC Models: Select '''Generic Modbus''' (0-based), meaning the softMC Modbus server starts addressing tags from 0.&lt;br /&gt;
&lt;br /&gt;
:Click '''OK'''.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(7).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
===Import Tags===&lt;br /&gt;
1. In the ProjectView pane, select '''Tags'''.&lt;br /&gt;
&lt;br /&gt;
2. From the list, select '''Modbus TCP''' protocol defined previously.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(8).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
3. Click the '''Import Tags''' button. &lt;br /&gt;
&lt;br /&gt;
4. Open the generated file '''JMobile_HMI.csv'''.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(9).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
5. Select the tags you want to add to your project, and click the ''Import tags'' button.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(10).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==AdvancedHMI==&lt;br /&gt;
AdvancedHMI is an open source project (http://www.advancedhmi.com/), which is downloaded as a Visual Basic project. You can then open the project, add widgets, compile, and run it.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(11).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Drag and drop '''ModbusTCPCom''' into MainForm.vb [Design].&lt;br /&gt;
&lt;br /&gt;
2. The driver appears the bottom of the screen (circled in green). &lt;br /&gt;
&lt;br /&gt;
:Click the driver, and then use the Properties pane (circled in red) to setup the IP address of the Modbus server.&lt;br /&gt;
&lt;br /&gt;
:For example, drag and drop DigitalPanelMeter and MomentaryButton into MainForm.vb [Design].&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(12).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
3. For both widgets, use the Properties pane to set the Modbus address that is associated with the variables from the softMC application.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(13).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
'''Note''':&lt;br /&gt;
::MC Modbus server addressing starts from '''40000'''.&lt;br /&gt;
::AdvancedHMI Modbus client addressing starts from '''40001'''.&lt;br /&gt;
::Prefix the address with the letter '''L'''.&lt;br /&gt;
&lt;br /&gt;
4. Save the project (Ctrl+S).&lt;br /&gt;
&lt;br /&gt;
5. Build the project (Ctrl+Shift+B).&lt;br /&gt;
&lt;br /&gt;
6. Run the project (F5).&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=File:modbus;newAPI-upload.jpg&amp;diff=125877</id>
		<title>File:modbus;newAPI-upload.jpg</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=File:modbus;newAPI-upload.jpg&amp;diff=125877"/>
				<updated>2016-04-18T13:21:41Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: -&amp;gt; Creation failed: Unsupported filetype!&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125875</id>
		<title>Modbus Communication API</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125875"/>
				<updated>2016-04-18T11:40:40Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: /* Getting Started */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
=== Basic Overview ===&lt;br /&gt;
* This describes how to set up Modbus communication for the softMC, and how to generate softMC scripts to handle Modbus communication.&lt;br /&gt;
* It is assumed you are familiar with the principles of Modbus communication, although some of them will be described in this page.&lt;br /&gt;
* It is also assumed your are familiar with the softMC, ControlStudio and MC-Basic programming.&lt;br /&gt;
&lt;br /&gt;
=== Modbus Communication Background ===&lt;br /&gt;
* A Motion Controller (MC) can act as a server (slave), a client (master) or both at the same time.&lt;br /&gt;
* Each MC connection (TCP/RTU) can be used either as a server component (if the connection is used by the MC’s server-side) or as a client component (if the connection is used by the MC’s client-side).&lt;br /&gt;
* Each component has its own parameters that defines it.&lt;br /&gt;
* When the MC acts as a server, all server components share the '''same''' memory address space, thus acting as one server with multiple connections.&lt;br /&gt;
* Each server (slave) on a Modbus network has its own deviceID, which is a number between 1 and 247.&lt;br /&gt;
&lt;br /&gt;
=== The Modbus server registers ===&lt;br /&gt;
* There are 4 types of registers in the Modbus Server address space:&lt;br /&gt;
*# Bits (1-bit registers)&lt;br /&gt;
*# Input Bits (1-bit READ-ONLY registers)&lt;br /&gt;
*# Holding Registers (16-bit registers)&lt;br /&gt;
*# Input Registers (16-bit READ-ONLY registers)&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
In order to get started in using the Modbus features:&lt;br /&gt;
# Download the required files, according to your system's type:&lt;br /&gt;
## Required files for [[File:modbus_requiredFiles_x86.zip|modbus_X86.ZIP]].&lt;br /&gt;
## Required files for ARM systems.&lt;br /&gt;
# Using the ControlStudio File Manager, Upload the following files to your MC:&lt;br /&gt;
## mb_x86.O ''(for softMC7 )'' / mb_armA9.O ''(for softMC3)''&lt;br /&gt;
## Modbus.lib&lt;br /&gt;
## MB_Loader.prg&lt;br /&gt;
#:[[File:modbus;newAPI-upload.jpg|850px]]&lt;br /&gt;
# Load (Run) MB_Loader.prg&lt;br /&gt;
# Use the ControlStudio Terminal to enter the following:&lt;br /&gt;
#:&amp;lt;pre&amp;gt;&lt;br /&gt;
#::reset all&lt;br /&gt;
#::?tasklist&amp;lt;/pre&amp;gt;&lt;br /&gt;
#: The system's response: &amp;lt;pre&amp;gt;GlobalLibraryName=MODBUS.LIB&amp;lt;/pre&amp;gt;&lt;br /&gt;
#:This indicates that library MODBUS.LIB has been loaded globally.&lt;br /&gt;
#:[[File:softMC_Modbus_HMI_(2).png|300px]]&lt;br /&gt;
# That's it! You're now ready to configure the Modbus system.&lt;br /&gt;
&lt;br /&gt;
== Initializing a Modbus Server ==&lt;br /&gt;
To initialize the Modbus server address space, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;?init_multi_server([bits],[input_bits],[holding registers],[input_registers])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The function prints &amp;quot;success&amp;quot; and returns 0 on success, or return an error code on failure.&lt;br /&gt;
* &amp;lt;u&amp;gt;'''Notice:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
*# This is '''NOT''' required when softMC does not run a modbus server.&lt;br /&gt;
*# You can call this method only if no servers are running.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Memory allocation failure.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Some servers are still running and using an already mapped address space.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to create a modbus mapping.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Server Components ==&lt;br /&gt;
=== Adding server components ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Creating a TCP server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_server_create([port],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens a TCP connection to the server on port [port] with deviceID [deviceID], and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Failed to create main socket.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|}&lt;br /&gt;
==== Creating an RTU server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_server_create([type],[port],[baudrate],[data bits],[stop bits],[parity],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens an RTU connection with the given parameters, and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Invalid device string.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Invalid parity.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed opening RTU.&lt;br /&gt;
|-&lt;br /&gt;
| -5&lt;br /&gt;
| Failed allocating query buffer memory.&lt;br /&gt;
|-&lt;br /&gt;
| -6&lt;br /&gt;
| Failed to set RTU mode.&lt;br /&gt;
|-&lt;br /&gt;
| -7&lt;br /&gt;
| Unable to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -8&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|-&lt;br /&gt;
| -9&lt;br /&gt;
| The device is already in use by another system component.&lt;br /&gt;
|}&lt;br /&gt;
=== Stopping Server Components ===&lt;br /&gt;
==== Stopping a specific server component ====&lt;br /&gt;
You can stop a specific server component by passing its handle to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate server component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
==== Stopping all server components ====&lt;br /&gt;
You can stop all server components with a single call to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop_all&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function will:&lt;br /&gt;
* Stop and free all server components.&lt;br /&gt;
* Free the shared address space.&lt;br /&gt;
* Return 0 on success, -1 on failure.&lt;br /&gt;
== Client Components ==&lt;br /&gt;
=== Adding client components ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Adding a TCP Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_client_create([ip],[port])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will opens a TCP connection to the client on the given ip and port, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
==== Adding an RTU Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_client_create([type],[port],[baudrate],[data bits],[stop bits],[parity])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will open an RTU connection to the client with the given parameters, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
=== Stopping client components ===&lt;br /&gt;
A specific client can be stopped by calling:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_client_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate client component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reset the Modbus System ==&lt;br /&gt;
Sometimes, a user may wish to stop all server and client components at once, and reset the Modbus system (for example, when a user want to initialize a different Modbus system). To do that, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_reset&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function:&lt;br /&gt;
* Stops all running servers and clients.&lt;br /&gt;
* Frees their memory.&lt;br /&gt;
* Frees the shared address space.&lt;br /&gt;
* Reset the handle counter.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reading and Writing ==&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
* Therefore, Servers and clients use different functions to read/write data from the address space.&lt;br /&gt;
=== Server Components ===&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers and return them.&lt;br /&gt;
* When a read error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_REG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_READ_BIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_INREG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt; val = MB_SERVER_READ_INBIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data into the different types of registers.&lt;br /&gt;
* When a write error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Writing to holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_BIT([index],[new value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_INBIT([index],[value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| New value&lt;br /&gt;
| The value to write, must be from the appropriate type.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Error codes ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Invalid index.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Local server's address space isn't mapped yet.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to catch the register mutex.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to release the register mutex.&lt;br /&gt;
|}&lt;br /&gt;
=== Client Components ===&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The read value is inserted into an existing variable from the appropriate type (long/double).&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_REG_LONG([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_BITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_LONG ([handle],[deviceID],[addr],[dest ptr]) &lt;br /&gt;
Val = MB_CLIENT_READ_INREG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_INBITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to read from.&lt;br /&gt;
|-&lt;br /&gt;
| Num of bits (Reading bits)&lt;br /&gt;
| The number of bits to read.&lt;br /&gt;
|-&lt;br /&gt;
| dest ptr / dest arr ptr&lt;br /&gt;
| The variable to store the read data. When reading bits, this must be an array of longs in the appropriate size (&amp;gt;= Num of bits).&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data from existing variables to the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Writing to Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_LONG([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_SHORT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_FLOAT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_DOUBLE([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_WRITE_BIT([handle],[deviceID],[addr],[src ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to start writing to.&lt;br /&gt;
|-&lt;br /&gt;
| src ptr&lt;br /&gt;
| The variable that stores the data to be written. This must be a variable from the appropriate type.&lt;br /&gt;
|}&lt;br /&gt;
=== Reading and Writing Summary ===&lt;br /&gt;
[[File:modbus;newAPI-readwriteSummary.jpg|850px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Modbus Configurator=&lt;br /&gt;
The Modbus Communication Scripts Generator ('''Modbus Configurator''') is a tool that allows you to map your softMC application variables to Modbus tags.&lt;br /&gt;
&lt;br /&gt;
'''Note''':	Tag access is defined from the HMI perspective. In other words:&lt;br /&gt;
* '''Read Access''' variables are written by the softMC to the Modbus address space.&lt;br /&gt;
* '''Write Access''' variables are read by the softMC from the Modbus address space.&lt;br /&gt;
&lt;br /&gt;
You can define whether a variable has Read Access (meaning it is read by the HMI/PLC), or Write Access (meaning it is written by the HMI/PLC). Currently, it is not possible to define a variable as having both Read Access and Write Access. However, all Write Access variables can be written once by the softMC upon system startup by a special routine that is generated in HMIMBMAP.LIB (see section below).&lt;br /&gt;
&lt;br /&gt;
The MCMBConfigurator creates three files:&lt;br /&gt;
* '''HMIMBMAP.LIB''' and '''HMIMBMAP.PRG''' files are MC-Basic scripts that are used to start a softMC task. These are default file names, which you can change, but must retain the 8.3 format. This task cyclically and indefinitely reads/writes Modbus tags according to access type. &lt;br /&gt;
* A '''.CSV''' format file that can be used by an HMI development environment, such as '''JMobile Studio''' or '''Indusoft''', to automatically import Modbus tags. You define the HMI development environment by selecting various Python scripts that will generate the .csv file.&lt;br /&gt;
&lt;br /&gt;
== Mapping Variables==&lt;br /&gt;
'''Note''': 	Variables destined to be mapped to Modbus tags must be defined as global variables by the Common Shared declaration.&lt;br /&gt;
&lt;br /&gt;
1. In order to map the variables, the program must be loaded in the softMC.&lt;br /&gt;
&lt;br /&gt;
2. Start the Modbus Configuration: from the ControlStudio toolbar, select  Tools, and then Modbus Configurator…&lt;br /&gt;
&lt;br /&gt;
:The Modbus Configurator windows opens.&lt;br /&gt;
&lt;br /&gt;
3. Click Connection, and select Setting.&lt;br /&gt;
&lt;br /&gt;
:The setting dialog box opens, with fields showing the following (default) settings:&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(3).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
* Modbus offset: Used to start the mapping from an address other than zero.&lt;br /&gt;
* Script file name: A Python script that generates the product files. Different scripts create different .csv files.&lt;br /&gt;
* Output LIB, Output Prog, HMI CSV file name: Used to define target file names. &lt;br /&gt;
:'''Note''': The softMC file names must be UPPERCASE and in 8.3 format.&lt;br /&gt;
* MC IP address: Used to set the IP address of your softMC.&lt;br /&gt;
Make any necessary changes in the Settings dialog box. Then click Connection, and then Connect.&lt;br /&gt;
&lt;br /&gt;
Once the Modbus Configurator is connected to softMC it gets updated with the complete list of all the global variables. Double-clicking on variables automatically maps them to Modbus tags in consecutive order. The automatic Modbus address and data type are displayed in the table.&lt;br /&gt;
&lt;br /&gt;
If a mapped variable is defined as CONST, its access type is automatically set to Read. In such instances the access type cannot be changed. Read Access variables are read only by the HMI; therefore the softMC only writes them to the Modbus address space.&lt;br /&gt;
&lt;br /&gt;
A variable that is not defined as CONST automatically appears as Write Access. Double-click on the access type to toggle the variable between Read Access and Write Access, and thus determine whether the variable will be read or written by softMC.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(4).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
==Generating and Using Scripts==&lt;br /&gt;
After you are done mapping variables and defining the access types, a snapshot of the current configuration must be saved in order to generate the Modbus-handling scripts.&lt;br /&gt;
&lt;br /&gt;
1. Click '''Files''', and then '''Save As'''.&lt;br /&gt;
&lt;br /&gt;
:The mapping is saved in an '''.mbas''' file.&lt;br /&gt;
&lt;br /&gt;
:If you makes changes after saving the .mbas file, the MBAS file indicator in the status bar will light up.&lt;br /&gt;
&lt;br /&gt;
2. To generate the product files, click '''Generate'''.&lt;br /&gt;
&lt;br /&gt;
:The Log windows will display Success messages.&lt;br /&gt;
&lt;br /&gt;
:The product files were created in the target folder you chose when saving the .mbas file.&lt;br /&gt;
&lt;br /&gt;
:The files HMIMBMAP.LIB and HMIMBMAP.PRG will automatically open in ControlStudio.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(5).png|600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Using the Modbus-Handling Scripts==&lt;br /&gt;
1. Using the ControlStudio File Manager, copy HMIMBMAP.LIB and HMIMBMAP.PRG to the softMC.&lt;br /&gt;
&lt;br /&gt;
'''Note''':	Before these files can be loaded and used, your application must be loaded, and all mapped variables must exist in the softMC memory.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(6).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Using the ControlStudio Terminal, load the library HMIMBMAP.LIB:&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.LIB&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Since HMIMBMAP.PRG imports this library it must not be loaded globally. This code can be executed wherever is convenient.&lt;br /&gt;
&lt;br /&gt;
2. Verify that the library was loaded successfully:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;?tasklist&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Start the Modbus communication task by loading the program:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.PRG&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
HMIMBMAP.PRG is defined as '''Program Continue''', therefore it starts automatically after it is loaded and it does not require an explicit StartTask command.&lt;br /&gt;
&lt;br /&gt;
Of course, HMIMBMAP.PRG can be loaded and executed only after HMIMBMAP.LIB is loaded. Therefore, you should add the following code to AUTOEXEC.PRG or wherever is convenient:&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.LIB&lt;br /&gt;
Load HMIMBMAP.PRG&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HMIMBMAP.PRG Explained==&lt;br /&gt;
The code:&lt;br /&gt;
&amp;lt;pre&amp;gt;import HMIMBMAP.LIB&lt;br /&gt;
Program Continue&lt;br /&gt;
	dim retVal as long = 0&lt;br /&gt;
	retVal = Init_Modbus&lt;br /&gt;
	while 1&lt;br /&gt;
		retVal = Read_Modbus_Registers&lt;br /&gt;
		retVal = Write_Modbus_Registers&lt;br /&gt;
		sleep 1&lt;br /&gt;
	end while&lt;br /&gt;
End Program&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The functions '''Init_Modbus''', '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are implemented in '''HMIMBMAP.LIB''', which is automatically generated by a Python script.&lt;br /&gt;
&lt;br /&gt;
The function '''Init_Modbus''' starts the Modbus server and then writes to the Modbus address space all the '''Write Access Variables''' (i.e., all the variables read by the softMC from the Modbus address space). This feature allows you to setup the system to start with an initialized Modbus address space before the HMI/PLC connects to it. The HMI/PLC can read the address space and initialize itself accordingly.&lt;br /&gt;
&lt;br /&gt;
The functions '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are invoked cyclically and indefinitely. '''Read_Modbus_Registers''' reads all the tags that are written by the HMI/PLC and updates the '''Write Access''' variables with new values, while '''Write_Modbus_Registers''' does the opposite.&lt;br /&gt;
&lt;br /&gt;
=HMI IDEs and .CSV Files=&lt;br /&gt;
Each line in the .csv file generated by the MCMBConfigurator file holds data about a single variable, such as Modbus address or data type.&lt;br /&gt;
 &lt;br /&gt;
This data can be used by an HMI IDE to import Modbus tags and associate them with HMI functionality.&lt;br /&gt;
&lt;br /&gt;
Different manufacturer IDEs use different .csv formatting; therefore, various Python scripts are used to create the specific .csv files suitable for a particular manufacturer IDE.&lt;br /&gt;
&lt;br /&gt;
==JMobile Studio==&lt;br /&gt;
Python script: '''JMobile_csv.py''' &lt;br /&gt;
&lt;br /&gt;
Default target .csv file name: '''JMobile_HMI.csv''' (user-definable)&lt;br /&gt;
&lt;br /&gt;
To import tags, perform the following procedure in JMobile Studio.&lt;br /&gt;
&lt;br /&gt;
===Define Protocol===&lt;br /&gt;
1. In the ProjectView pane, select '''Protocols'''.&lt;br /&gt;
&lt;br /&gt;
2. Click the blue '''+''' sign.&lt;br /&gt;
&lt;br /&gt;
3. From the list, select Modbus TCP.&lt;br /&gt;
&lt;br /&gt;
4. In the Modbus TCP configuration window, define: &lt;br /&gt;
&lt;br /&gt;
:IP Address: Set the IP address of your softMC.&lt;br /&gt;
&lt;br /&gt;
:PLC Models: Select '''Generic Modbus''' (0-based), meaning the softMC Modbus server starts addressing tags from 0.&lt;br /&gt;
&lt;br /&gt;
:Click '''OK'''.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(7).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
===Import Tags===&lt;br /&gt;
1. In the ProjectView pane, select '''Tags'''.&lt;br /&gt;
&lt;br /&gt;
2. From the list, select '''Modbus TCP''' protocol defined previously.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(8).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
3. Click the '''Import Tags''' button. &lt;br /&gt;
&lt;br /&gt;
4. Open the generated file '''JMobile_HMI.csv'''.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(9).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
5. Select the tags you want to add to your project, and click the ''Import tags'' button.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(10).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==AdvancedHMI==&lt;br /&gt;
AdvancedHMI is an open source project (http://www.advancedhmi.com/), which is downloaded as a Visual Basic project. You can then open the project, add widgets, compile, and run it.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(11).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Drag and drop '''ModbusTCPCom''' into MainForm.vb [Design].&lt;br /&gt;
&lt;br /&gt;
2. The driver appears the bottom of the screen (circled in green). &lt;br /&gt;
&lt;br /&gt;
:Click the driver, and then use the Properties pane (circled in red) to setup the IP address of the Modbus server.&lt;br /&gt;
&lt;br /&gt;
:For example, drag and drop DigitalPanelMeter and MomentaryButton into MainForm.vb [Design].&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(12).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
3. For both widgets, use the Properties pane to set the Modbus address that is associated with the variables from the softMC application.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(13).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
'''Note''':&lt;br /&gt;
::MC Modbus server addressing starts from '''40000'''.&lt;br /&gt;
::AdvancedHMI Modbus client addressing starts from '''40001'''.&lt;br /&gt;
::Prefix the address with the letter '''L'''.&lt;br /&gt;
&lt;br /&gt;
4. Save the project (Ctrl+S).&lt;br /&gt;
&lt;br /&gt;
5. Build the project (Ctrl+Shift+B).&lt;br /&gt;
&lt;br /&gt;
6. Run the project (F5).&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=File:modbus;newAPI-readwriteSummary.jpg&amp;diff=125874</id>
		<title>File:modbus;newAPI-readwriteSummary.jpg</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=File:modbus;newAPI-readwriteSummary.jpg&amp;diff=125874"/>
				<updated>2016-04-18T11:27:49Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: -&amp;gt; Creation failed: Unsupported filetype!&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125870</id>
		<title>Modbus Communication API</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125870"/>
				<updated>2016-04-17T07:45:51Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: /* 4 HMI IDEs and .CSV Files */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
=== Basic Overview ===&lt;br /&gt;
* This describes how to set up Modbus communication for the softMC, and how to generate softMC scripts to handle Modbus communication.&lt;br /&gt;
* It is assumed you are familiar with the principles of Modbus communication, although some of them will be described in this page.&lt;br /&gt;
* It is also assumed your are familiar with the softMC, ControlStudio and MC-Basic programming.&lt;br /&gt;
&lt;br /&gt;
=== Modbus Communication Background ===&lt;br /&gt;
* A Motion Controller (MC) can act as a server (slave), a client (master) or both at the same time.&lt;br /&gt;
* Each MC connection (TCP/RTU) can be used either as a server component (if the connection is used by the MC’s server-side) or as a client component (if the connection is used by the MC’s client-side).&lt;br /&gt;
* Each component has its own parameters that defines it.&lt;br /&gt;
* When the MC acts as a server, all server components share the '''same''' memory address space, thus acting as one server with multiple connections.&lt;br /&gt;
* Each server (slave) on a Modbus network has its own deviceID, which is a number between 1 and 247.&lt;br /&gt;
&lt;br /&gt;
=== The Modbus server registers ===&lt;br /&gt;
* There are 4 types of registers in the Modbus Server address space:&lt;br /&gt;
*# Bits (1-bit registers)&lt;br /&gt;
*# Input Bits (1-bit READ-ONLY registers)&lt;br /&gt;
*# Holding Registers (16-bit registers)&lt;br /&gt;
*# Input Registers (16-bit READ-ONLY registers)&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
In order to get started in using the Modbus features:&lt;br /&gt;
# Download the required files, according to your system's type:&lt;br /&gt;
## Required files for [[File:modbus_requiredFiles_x86.zip|modbus_X86.ZIP]].&lt;br /&gt;
## Required files for ARM systems.&lt;br /&gt;
# Using the ControlStudio File Manager, Upload the following files to your MC:&lt;br /&gt;
## mb_x86.O ''(for X86 Systems)'' / mb_armA9.O ''(for ARM Systems)''&lt;br /&gt;
## Modbus.lib&lt;br /&gt;
#* '''Notice:''' From now on, in our examples, we'll use the X86 configuration.&amp;lt;br&amp;gt;[[File:modbus;newAPI-upload.jpg|850px]]&lt;br /&gt;
# Access the file CONFIG.PRG and modify the program by adding the following two lines:&lt;br /&gt;
#:&amp;lt;pre&amp;gt;&lt;br /&gt;
#::Program&lt;br /&gt;
#::	Oload mb_x86.O&lt;br /&gt;
#::	Load modbus.lib&lt;br /&gt;
#::...&lt;br /&gt;
#::...&lt;br /&gt;
#::End Program&amp;lt;/pre&amp;gt;&lt;br /&gt;
# Upload CONFIG.PRG to the softMC.&lt;br /&gt;
# Use the ControlStudio Terminal to enter the following:&lt;br /&gt;
#:&amp;lt;pre&amp;gt;&lt;br /&gt;
#::reset all&lt;br /&gt;
#::?tasklist&amp;lt;/pre&amp;gt;&lt;br /&gt;
#: The system's response: &amp;lt;pre&amp;gt;GlobalLibraryName=MODBUS.LIB&amp;lt;/pre&amp;gt;&lt;br /&gt;
#:This indicates that library MODBUS.LIB has been loaded globally.&lt;br /&gt;
#:[[File:softMC_Modbus_HMI_(2).png|300px]]&lt;br /&gt;
# That's it! You're now ready to configure the Modbus system.&lt;br /&gt;
== Initializing a Modbus Server ==&lt;br /&gt;
To initialize the Modbus server address space, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;?init_multi_server([bits],[input_bits],[holding registers],[input_registers])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The function prints &amp;quot;success&amp;quot; and returns 0 on success, or return an error code on failure.&lt;br /&gt;
* &amp;lt;u&amp;gt;'''Notice:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
*# This is '''NOT''' required when softMC does not run a modbus server.&lt;br /&gt;
*# You can call this method only if no servers are running.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Memory allocation failure.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Some servers are still running and using an already mapped address space.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to create a modbus mapping.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Server Components ==&lt;br /&gt;
=== Adding server components ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Creating a TCP server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_server_create([port],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens a TCP connection to the server on port [port] with deviceID [deviceID], and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Failed to create main socket.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|}&lt;br /&gt;
==== Creating an RTU server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_server_create([type],[port],[baudrate],[data bits],[stop bits],[parity],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens an RTU connection with the given parameters, and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Invalid device string.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Invalid parity.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed opening RTU.&lt;br /&gt;
|-&lt;br /&gt;
| -5&lt;br /&gt;
| Failed allocating query buffer memory.&lt;br /&gt;
|-&lt;br /&gt;
| -6&lt;br /&gt;
| Failed to set RTU mode.&lt;br /&gt;
|-&lt;br /&gt;
| -7&lt;br /&gt;
| Unable to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -8&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|-&lt;br /&gt;
| -9&lt;br /&gt;
| The device is already in use by another system component.&lt;br /&gt;
|}&lt;br /&gt;
=== Stopping Server Components ===&lt;br /&gt;
==== Stopping a specific server component ====&lt;br /&gt;
You can stop a specific server component by passing its handle to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate server component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
==== Stopping all server components ====&lt;br /&gt;
You can stop all server components with a single call to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop_all&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function will:&lt;br /&gt;
* Stop and free all server components.&lt;br /&gt;
* Free the shared address space.&lt;br /&gt;
* Return 0 on success, -1 on failure.&lt;br /&gt;
== Client Components ==&lt;br /&gt;
=== Adding client components ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Adding a TCP Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_client_create([ip],[port])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will opens a TCP connection to the client on the given ip and port, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
==== Adding an RTU Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_client_create([type],[port],[baudrate],[data bits],[stop bits],[parity])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will open an RTU connection to the client with the given parameters, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
=== Stopping client components ===&lt;br /&gt;
A specific client can be stopped by calling:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_client_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate client component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reset the Modbus System ==&lt;br /&gt;
Sometimes, a user may wish to stop all server and client components at once, and reset the Modbus system (for example, when a user want to initialize a different Modbus system). To do that, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_reset&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function:&lt;br /&gt;
* Stops all running servers and clients.&lt;br /&gt;
* Frees their memory.&lt;br /&gt;
* Frees the shared address space.&lt;br /&gt;
* Reset the handle counter.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reading and Writing ==&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
* Therefore, Servers and clients use different functions to read/write data from the address space.&lt;br /&gt;
=== Server Components ===&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers and return them.&lt;br /&gt;
* When a read error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_REG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_READ_BIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_INREG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt; val = MB_SERVER_READ_INBIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data into the different types of registers.&lt;br /&gt;
* When a write error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Writing to holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_BIT([index],[new value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_INBIT([index],[value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| New value&lt;br /&gt;
| The value to write, must be from the appropriate type.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Error codes ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Invalid index.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Local server's address space isn't mapped yet.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to catch the register mutex.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to release the register mutex.&lt;br /&gt;
|}&lt;br /&gt;
=== Client Components ===&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The read value is inserted into an existing variable from the appropriate type (long/double).&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_REG_LONG([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_BITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_LONG ([handle],[deviceID],[addr],[dest ptr]) &lt;br /&gt;
Val = MB_CLIENT_READ_INREG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_INBITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to read from.&lt;br /&gt;
|-&lt;br /&gt;
| Num of bits (Reading bits)&lt;br /&gt;
| The number of bits to read.&lt;br /&gt;
|-&lt;br /&gt;
| dest ptr / dest arr ptr&lt;br /&gt;
| The variable to store the read data. When reading bits, this must be an array of longs in the appropriate size (&amp;gt;= Num of bits).&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data from existing variables to the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Writing to Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_LONG([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_SHORT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_FLOAT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_DOUBLE([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_WRITE_BIT([handle],[deviceID],[addr],[src ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to start writing to.&lt;br /&gt;
|-&lt;br /&gt;
| src ptr&lt;br /&gt;
| The variable that stores the data to be written. This must be a variable from the appropriate type.&lt;br /&gt;
|}&lt;br /&gt;
=== Reading and Writing Summary ===&lt;br /&gt;
[[File:modbus;newAPI-readwriteSummary.jpg|850px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Modbus Configurator=&lt;br /&gt;
The Modbus Communication Scripts Generator ('''Modbus Configurator''') is a tool that allows you to map your softMC application variables to Modbus tags.&lt;br /&gt;
&lt;br /&gt;
'''Note''':	Tag access is defined from the HMI perspective. In other words:&lt;br /&gt;
* '''Read Access''' variables are written by the softMC to the Modbus address space.&lt;br /&gt;
* '''Write Access''' variables are read by the softMC from the Modbus address space.&lt;br /&gt;
&lt;br /&gt;
You can define whether a variable has Read Access (meaning it is read by the HMI/PLC), or Write Access (meaning it is written by the HMI/PLC). Currently, it is not possible to define a variable as having both Read Access and Write Access. However, all Write Access variables can be written once by the softMC upon system startup by a special routine that is generated in HMIMBMAP.LIB (see section below).&lt;br /&gt;
&lt;br /&gt;
The MCMBConfigurator creates three files:&lt;br /&gt;
* '''HMIMBMAP.LIB''' and '''HMIMBMAP.PRG''' files are MC-Basic scripts that are used to start a softMC task. These are default file names, which you can change, but must retain the 8.3 format. This task cyclically and indefinitely reads/writes Modbus tags according to access type. &lt;br /&gt;
* A '''.CSV''' format file that can be used by an HMI development environment, such as '''JMobile Studio''' or '''Indusoft''', to automatically import Modbus tags. You define the HMI development environment by selecting various Python scripts that will generate the .csv file.&lt;br /&gt;
&lt;br /&gt;
== Mapping Variables==&lt;br /&gt;
'''Note''': 	Variables destined to be mapped to Modbus tags must be defined as global variables by the Common Shared declaration.&lt;br /&gt;
&lt;br /&gt;
1. In order to map the variables, the program must be loaded in the softMC.&lt;br /&gt;
&lt;br /&gt;
2. Start the Modbus Configuration: from the ControlStudio toolbar, select  Tools, and then Modbus Configurator…&lt;br /&gt;
&lt;br /&gt;
:The Modbus Configurator windows opens.&lt;br /&gt;
&lt;br /&gt;
3. Click Connection, and select Setting.&lt;br /&gt;
&lt;br /&gt;
:The setting dialog box opens, with fields showing the following (default) settings:&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(3).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
* Modbus offset: Used to start the mapping from an address other than zero.&lt;br /&gt;
* Script file name: A Python script that generates the product files. Different scripts create different .csv files.&lt;br /&gt;
* Output LIB, Output Prog, HMI CSV file name: Used to define target file names. &lt;br /&gt;
:'''Note''': The softMC file names must be UPPERCASE and in 8.3 format.&lt;br /&gt;
* MC IP address: Used to set the IP address of your softMC.&lt;br /&gt;
Make any necessary changes in the Settings dialog box. Then click Connection, and then Connect.&lt;br /&gt;
&lt;br /&gt;
Once the Modbus Configurator is connected to softMC it gets updated with the complete list of all the global variables. Double-clicking on variables automatically maps them to Modbus tags in consecutive order. The automatic Modbus address and data type are displayed in the table.&lt;br /&gt;
&lt;br /&gt;
If a mapped variable is defined as CONST, its access type is automatically set to Read. In such instances the access type cannot be changed. Read Access variables are read only by the HMI; therefore the softMC only writes them to the Modbus address space.&lt;br /&gt;
&lt;br /&gt;
A variable that is not defined as CONST automatically appears as Write Access. Double-click on the access type to toggle the variable between Read Access and Write Access, and thus determine whether the variable will be read or written by softMC.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(4).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
==Generating and Using Scripts==&lt;br /&gt;
After you are done mapping variables and defining the access types, a snapshot of the current configuration must be saved in order to generate the Modbus-handling scripts.&lt;br /&gt;
&lt;br /&gt;
1. Click '''Files''', and then '''Save As'''.&lt;br /&gt;
&lt;br /&gt;
:The mapping is saved in an '''.mbas''' file.&lt;br /&gt;
&lt;br /&gt;
:If you makes changes after saving the .mbas file, the MBAS file indicator in the status bar will light up.&lt;br /&gt;
&lt;br /&gt;
2. To generate the product files, click '''Generate'''.&lt;br /&gt;
&lt;br /&gt;
:The Log windows will display Success messages.&lt;br /&gt;
&lt;br /&gt;
:The product files were created in the target folder you chose when saving the .mbas file.&lt;br /&gt;
&lt;br /&gt;
:The files HMIMBMAP.LIB and HMIMBMAP.PRG will automatically open in ControlStudio.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(5).png|600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Using the Modbus-Handling Scripts==&lt;br /&gt;
1. Using the ControlStudio File Manager, copy HMIMBMAP.LIB and HMIMBMAP.PRG to the softMC.&lt;br /&gt;
&lt;br /&gt;
'''Note''':	Before these files can be loaded and used, your application must be loaded, and all mapped variables must exist in the softMC memory.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(6).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Using the ControlStudio Terminal, load the library HMIMBMAP.LIB:&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.LIB&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Since HMIMBMAP.PRG imports this library it must not be loaded globally. This code can be executed wherever is convenient.&lt;br /&gt;
&lt;br /&gt;
2. Verify that the library was loaded successfully:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;?tasklist&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Start the Modbus communication task by loading the program:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.PRG&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
HMIMBMAP.PRG is defined as '''Program Continue''', therefore it starts automatically after it is loaded and it does not require an explicit StartTask command.&lt;br /&gt;
&lt;br /&gt;
Of course, HMIMBMAP.PRG can be loaded and executed only after HMIMBMAP.LIB is loaded. Therefore, you should add the following code to AUTOEXEC.PRG or wherever is convenient:&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.LIB&lt;br /&gt;
Load HMIMBMAP.PRG&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HMIMBMAP.PRG Explained==&lt;br /&gt;
The code:&lt;br /&gt;
&amp;lt;pre&amp;gt;import HMIMBMAP.LIB&lt;br /&gt;
Program Continue&lt;br /&gt;
	dim retVal as long = 0&lt;br /&gt;
	retVal = Init_Modbus&lt;br /&gt;
	while 1&lt;br /&gt;
		retVal = Read_Modbus_Registers&lt;br /&gt;
		retVal = Write_Modbus_Registers&lt;br /&gt;
		sleep 1&lt;br /&gt;
	end while&lt;br /&gt;
End Program&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The functions '''Init_Modbus''', '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are implemented in '''HMIMBMAP.LIB''', which is automatically generated by a Python script.&lt;br /&gt;
&lt;br /&gt;
The function '''Init_Modbus''' starts the Modbus server and then writes to the Modbus address space all the '''Write Access Variables''' (i.e., all the variables read by the softMC from the Modbus address space). This feature allows you to setup the system to start with an initialized Modbus address space before the HMI/PLC connects to it. The HMI/PLC can read the address space and initialize itself accordingly.&lt;br /&gt;
&lt;br /&gt;
The functions '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are invoked cyclically and indefinitely. '''Read_Modbus_Registers''' reads all the tags that are written by the HMI/PLC and updates the '''Write Access''' variables with new values, while '''Write_Modbus_Registers''' does the opposite.&lt;br /&gt;
&lt;br /&gt;
=HMI IDEs and .CSV Files=&lt;br /&gt;
Each line in the .csv file generated by the MCMBConfigurator file holds data about a single variable, such as Modbus address or data type.&lt;br /&gt;
 &lt;br /&gt;
This data can be used by an HMI IDE to import Modbus tags and associate them with HMI functionality.&lt;br /&gt;
&lt;br /&gt;
Different manufacturer IDEs use different .csv formatting; therefore, various Python scripts are used to create the specific .csv files suitable for a particular manufacturer IDE.&lt;br /&gt;
&lt;br /&gt;
==JMobile Studio==&lt;br /&gt;
Python script: '''JMobile_csv.py''' &lt;br /&gt;
&lt;br /&gt;
Default target .csv file name: '''JMobile_HMI.csv''' (user-definable)&lt;br /&gt;
&lt;br /&gt;
To import tags, perform the following procedure in JMobile Studio.&lt;br /&gt;
&lt;br /&gt;
===Define Protocol===&lt;br /&gt;
1. In the ProjectView pane, select '''Protocols'''.&lt;br /&gt;
&lt;br /&gt;
2. Click the blue '''+''' sign.&lt;br /&gt;
&lt;br /&gt;
3. From the list, select Modbus TCP.&lt;br /&gt;
&lt;br /&gt;
4. In the Modbus TCP configuration window, define: &lt;br /&gt;
&lt;br /&gt;
:IP Address: Set the IP address of your softMC.&lt;br /&gt;
&lt;br /&gt;
:PLC Models: Select '''Generic Modbus''' (0-based), meaning the softMC Modbus server starts addressing tags from 0.&lt;br /&gt;
&lt;br /&gt;
:Click '''OK'''.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(7).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
===Import Tags===&lt;br /&gt;
1. In the ProjectView pane, select '''Tags'''.&lt;br /&gt;
&lt;br /&gt;
2. From the list, select '''Modbus TCP''' protocol defined previously.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(8).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
3. Click the '''Import Tags''' button. &lt;br /&gt;
&lt;br /&gt;
4. Open the generated file '''JMobile_HMI.csv'''.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(9).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
5. Select the tags you want to add to your project, and click the ''Import tags'' button.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(10).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==AdvancedHMI==&lt;br /&gt;
AdvancedHMI is an open source project (http://www.advancedhmi.com/), which is downloaded as a Visual Basic project. You can then open the project, add widgets, compile, and run it.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(11).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Drag and drop '''ModbusTCPCom''' into MainForm.vb [Design].&lt;br /&gt;
&lt;br /&gt;
2. The driver appears the bottom of the screen (circled in green). &lt;br /&gt;
&lt;br /&gt;
:Click the driver, and then use the Properties pane (circled in red) to setup the IP address of the Modbus server.&lt;br /&gt;
&lt;br /&gt;
:For example, drag and drop DigitalPanelMeter and MomentaryButton into MainForm.vb [Design].&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(12).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
3. For both widgets, use the Properties pane to set the Modbus address that is associated with the variables from the softMC application.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(13).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
'''Note''':&lt;br /&gt;
::MC Modbus server addressing starts from '''40000'''.&lt;br /&gt;
::AdvancedHMI Modbus client addressing starts from '''40001'''.&lt;br /&gt;
::Prefix the address with the letter '''L'''.&lt;br /&gt;
&lt;br /&gt;
4. Save the project (Ctrl+S).&lt;br /&gt;
&lt;br /&gt;
5. Build the project (Ctrl+Shift+B).&lt;br /&gt;
&lt;br /&gt;
6. Run the project (F5).&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125869</id>
		<title>Modbus Communication API</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125869"/>
				<updated>2016-04-17T07:43:52Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: Copied sections 8 and 9 from the previous version of the Wiki page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
=== Basic Overview ===&lt;br /&gt;
* This describes how to set up Modbus communication for the softMC, and how to generate softMC scripts to handle Modbus communication.&lt;br /&gt;
* It is assumed you are familiar with the principles of Modbus communication, although some of them will be described in this page.&lt;br /&gt;
* It is also assumed your are familiar with the softMC, ControlStudio and MC-Basic programming.&lt;br /&gt;
&lt;br /&gt;
=== Modbus Communication Background ===&lt;br /&gt;
* A Motion Controller (MC) can act as a server (slave), a client (master) or both at the same time.&lt;br /&gt;
* Each MC connection (TCP/RTU) can be used either as a server component (if the connection is used by the MC’s server-side) or as a client component (if the connection is used by the MC’s client-side).&lt;br /&gt;
* Each component has its own parameters that defines it.&lt;br /&gt;
* When the MC acts as a server, all server components share the '''same''' memory address space, thus acting as one server with multiple connections.&lt;br /&gt;
* Each server (slave) on a Modbus network has its own deviceID, which is a number between 1 and 247.&lt;br /&gt;
&lt;br /&gt;
=== The Modbus server registers ===&lt;br /&gt;
* There are 4 types of registers in the Modbus Server address space:&lt;br /&gt;
*# Bits (1-bit registers)&lt;br /&gt;
*# Input Bits (1-bit READ-ONLY registers)&lt;br /&gt;
*# Holding Registers (16-bit registers)&lt;br /&gt;
*# Input Registers (16-bit READ-ONLY registers)&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
In order to get started in using the Modbus features:&lt;br /&gt;
# Download the required files, according to your system's type:&lt;br /&gt;
## Required files for [[File:modbus_requiredFiles_x86.zip|modbus_X86.ZIP]].&lt;br /&gt;
## Required files for ARM systems.&lt;br /&gt;
# Using the ControlStudio File Manager, Upload the following files to your MC:&lt;br /&gt;
## mb_x86.O ''(for X86 Systems)'' / mb_armA9.O ''(for ARM Systems)''&lt;br /&gt;
## Modbus.lib&lt;br /&gt;
#* '''Notice:''' From now on, in our examples, we'll use the X86 configuration.&amp;lt;br&amp;gt;[[File:modbus;newAPI-upload.jpg|850px]]&lt;br /&gt;
# Access the file CONFIG.PRG and modify the program by adding the following two lines:&lt;br /&gt;
#:&amp;lt;pre&amp;gt;&lt;br /&gt;
#::Program&lt;br /&gt;
#::	Oload mb_x86.O&lt;br /&gt;
#::	Load modbus.lib&lt;br /&gt;
#::...&lt;br /&gt;
#::...&lt;br /&gt;
#::End Program&amp;lt;/pre&amp;gt;&lt;br /&gt;
# Upload CONFIG.PRG to the softMC.&lt;br /&gt;
# Use the ControlStudio Terminal to enter the following:&lt;br /&gt;
#:&amp;lt;pre&amp;gt;&lt;br /&gt;
#::reset all&lt;br /&gt;
#::?tasklist&amp;lt;/pre&amp;gt;&lt;br /&gt;
#: The system's response: &amp;lt;pre&amp;gt;GlobalLibraryName=MODBUS.LIB&amp;lt;/pre&amp;gt;&lt;br /&gt;
#:This indicates that library MODBUS.LIB has been loaded globally.&lt;br /&gt;
#:[[File:softMC_Modbus_HMI_(2).png|300px]]&lt;br /&gt;
# That's it! You're now ready to configure the Modbus system.&lt;br /&gt;
== Initializing a Modbus Server ==&lt;br /&gt;
To initialize the Modbus server address space, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;?init_multi_server([bits],[input_bits],[holding registers],[input_registers])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The function prints &amp;quot;success&amp;quot; and returns 0 on success, or return an error code on failure.&lt;br /&gt;
* &amp;lt;u&amp;gt;'''Notice:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
*# This is '''NOT''' required when softMC does not run a modbus server.&lt;br /&gt;
*# You can call this method only if no servers are running.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Memory allocation failure.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Some servers are still running and using an already mapped address space.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to create a modbus mapping.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Server Components ==&lt;br /&gt;
=== Adding server components ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Creating a TCP server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_server_create([port],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens a TCP connection to the server on port [port] with deviceID [deviceID], and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Failed to create main socket.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|}&lt;br /&gt;
==== Creating an RTU server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_server_create([type],[port],[baudrate],[data bits],[stop bits],[parity],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens an RTU connection with the given parameters, and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Invalid device string.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Invalid parity.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed opening RTU.&lt;br /&gt;
|-&lt;br /&gt;
| -5&lt;br /&gt;
| Failed allocating query buffer memory.&lt;br /&gt;
|-&lt;br /&gt;
| -6&lt;br /&gt;
| Failed to set RTU mode.&lt;br /&gt;
|-&lt;br /&gt;
| -7&lt;br /&gt;
| Unable to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -8&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|-&lt;br /&gt;
| -9&lt;br /&gt;
| The device is already in use by another system component.&lt;br /&gt;
|}&lt;br /&gt;
=== Stopping Server Components ===&lt;br /&gt;
==== Stopping a specific server component ====&lt;br /&gt;
You can stop a specific server component by passing its handle to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate server component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
==== Stopping all server components ====&lt;br /&gt;
You can stop all server components with a single call to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop_all&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function will:&lt;br /&gt;
* Stop and free all server components.&lt;br /&gt;
* Free the shared address space.&lt;br /&gt;
* Return 0 on success, -1 on failure.&lt;br /&gt;
== Client Components ==&lt;br /&gt;
=== Adding client components ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Adding a TCP Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_client_create([ip],[port])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will opens a TCP connection to the client on the given ip and port, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
==== Adding an RTU Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_client_create([type],[port],[baudrate],[data bits],[stop bits],[parity])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will open an RTU connection to the client with the given parameters, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
=== Stopping client components ===&lt;br /&gt;
A specific client can be stopped by calling:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_client_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate client component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reset the Modbus System ==&lt;br /&gt;
Sometimes, a user may wish to stop all server and client components at once, and reset the Modbus system (for example, when a user want to initialize a different Modbus system). To do that, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_reset&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function:&lt;br /&gt;
* Stops all running servers and clients.&lt;br /&gt;
* Frees their memory.&lt;br /&gt;
* Frees the shared address space.&lt;br /&gt;
* Reset the handle counter.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reading and Writing ==&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
* Therefore, Servers and clients use different functions to read/write data from the address space.&lt;br /&gt;
=== Server Components ===&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers and return them.&lt;br /&gt;
* When a read error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_REG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_READ_BIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_INREG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt; val = MB_SERVER_READ_INBIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data into the different types of registers.&lt;br /&gt;
* When a write error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Writing to holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_BIT([index],[new value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_INBIT([index],[value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| New value&lt;br /&gt;
| The value to write, must be from the appropriate type.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Error codes ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Invalid index.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Local server's address space isn't mapped yet.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to catch the register mutex.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to release the register mutex.&lt;br /&gt;
|}&lt;br /&gt;
=== Client Components ===&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The read value is inserted into an existing variable from the appropriate type (long/double).&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_REG_LONG([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_BITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_LONG ([handle],[deviceID],[addr],[dest ptr]) &lt;br /&gt;
Val = MB_CLIENT_READ_INREG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_INBITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to read from.&lt;br /&gt;
|-&lt;br /&gt;
| Num of bits (Reading bits)&lt;br /&gt;
| The number of bits to read.&lt;br /&gt;
|-&lt;br /&gt;
| dest ptr / dest arr ptr&lt;br /&gt;
| The variable to store the read data. When reading bits, this must be an array of longs in the appropriate size (&amp;gt;= Num of bits).&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data from existing variables to the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Writing to Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_LONG([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_SHORT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_FLOAT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_DOUBLE([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_WRITE_BIT([handle],[deviceID],[addr],[src ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to start writing to.&lt;br /&gt;
|-&lt;br /&gt;
| src ptr&lt;br /&gt;
| The variable that stores the data to be written. This must be a variable from the appropriate type.&lt;br /&gt;
|}&lt;br /&gt;
=== Reading and Writing Summary ===&lt;br /&gt;
[[File:modbus;newAPI-readwriteSummary.jpg|850px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Modbus Configurator=&lt;br /&gt;
The Modbus Communication Scripts Generator ('''Modbus Configurator''') is a tool that allows you to map your softMC application variables to Modbus tags.&lt;br /&gt;
&lt;br /&gt;
'''Note''':	Tag access is defined from the HMI perspective. In other words:&lt;br /&gt;
* '''Read Access''' variables are written by the softMC to the Modbus address space.&lt;br /&gt;
* '''Write Access''' variables are read by the softMC from the Modbus address space.&lt;br /&gt;
&lt;br /&gt;
You can define whether a variable has Read Access (meaning it is read by the HMI/PLC), or Write Access (meaning it is written by the HMI/PLC). Currently, it is not possible to define a variable as having both Read Access and Write Access. However, all Write Access variables can be written once by the softMC upon system startup by a special routine that is generated in HMIMBMAP.LIB (see section below).&lt;br /&gt;
&lt;br /&gt;
The MCMBConfigurator creates three files:&lt;br /&gt;
* '''HMIMBMAP.LIB''' and '''HMIMBMAP.PRG''' files are MC-Basic scripts that are used to start a softMC task. These are default file names, which you can change, but must retain the 8.3 format. This task cyclically and indefinitely reads/writes Modbus tags according to access type. &lt;br /&gt;
* A '''.CSV''' format file that can be used by an HMI development environment, such as '''JMobile Studio''' or '''Indusoft''', to automatically import Modbus tags. You define the HMI development environment by selecting various Python scripts that will generate the .csv file.&lt;br /&gt;
&lt;br /&gt;
== Mapping Variables==&lt;br /&gt;
'''Note''': 	Variables destined to be mapped to Modbus tags must be defined as global variables by the Common Shared declaration.&lt;br /&gt;
&lt;br /&gt;
1. In order to map the variables, the program must be loaded in the softMC.&lt;br /&gt;
&lt;br /&gt;
2. Start the Modbus Configuration: from the ControlStudio toolbar, select  Tools, and then Modbus Configurator…&lt;br /&gt;
&lt;br /&gt;
:The Modbus Configurator windows opens.&lt;br /&gt;
&lt;br /&gt;
3. Click Connection, and select Setting.&lt;br /&gt;
&lt;br /&gt;
:The setting dialog box opens, with fields showing the following (default) settings:&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(3).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
* Modbus offset: Used to start the mapping from an address other than zero.&lt;br /&gt;
* Script file name: A Python script that generates the product files. Different scripts create different .csv files.&lt;br /&gt;
* Output LIB, Output Prog, HMI CSV file name: Used to define target file names. &lt;br /&gt;
:'''Note''': The softMC file names must be UPPERCASE and in 8.3 format.&lt;br /&gt;
* MC IP address: Used to set the IP address of your softMC.&lt;br /&gt;
Make any necessary changes in the Settings dialog box. Then click Connection, and then Connect.&lt;br /&gt;
&lt;br /&gt;
Once the Modbus Configurator is connected to softMC it gets updated with the complete list of all the global variables. Double-clicking on variables automatically maps them to Modbus tags in consecutive order. The automatic Modbus address and data type are displayed in the table.&lt;br /&gt;
&lt;br /&gt;
If a mapped variable is defined as CONST, its access type is automatically set to Read. In such instances the access type cannot be changed. Read Access variables are read only by the HMI; therefore the softMC only writes them to the Modbus address space.&lt;br /&gt;
&lt;br /&gt;
A variable that is not defined as CONST automatically appears as Write Access. Double-click on the access type to toggle the variable between Read Access and Write Access, and thus determine whether the variable will be read or written by softMC.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(4).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
==Generating and Using Scripts==&lt;br /&gt;
After you are done mapping variables and defining the access types, a snapshot of the current configuration must be saved in order to generate the Modbus-handling scripts.&lt;br /&gt;
&lt;br /&gt;
1. Click '''Files''', and then '''Save As'''.&lt;br /&gt;
&lt;br /&gt;
:The mapping is saved in an '''.mbas''' file.&lt;br /&gt;
&lt;br /&gt;
:If you makes changes after saving the .mbas file, the MBAS file indicator in the status bar will light up.&lt;br /&gt;
&lt;br /&gt;
2. To generate the product files, click '''Generate'''.&lt;br /&gt;
&lt;br /&gt;
:The Log windows will display Success messages.&lt;br /&gt;
&lt;br /&gt;
:The product files were created in the target folder you chose when saving the .mbas file.&lt;br /&gt;
&lt;br /&gt;
:The files HMIMBMAP.LIB and HMIMBMAP.PRG will automatically open in ControlStudio.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(5).png|600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Using the Modbus-Handling Scripts==&lt;br /&gt;
1. Using the ControlStudio File Manager, copy HMIMBMAP.LIB and HMIMBMAP.PRG to the softMC.&lt;br /&gt;
&lt;br /&gt;
'''Note''':	Before these files can be loaded and used, your application must be loaded, and all mapped variables must exist in the softMC memory.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(6).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Using the ControlStudio Terminal, load the library HMIMBMAP.LIB:&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.LIB&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Since HMIMBMAP.PRG imports this library it must not be loaded globally. This code can be executed wherever is convenient.&lt;br /&gt;
&lt;br /&gt;
2. Verify that the library was loaded successfully:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;?tasklist&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Start the Modbus communication task by loading the program:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.PRG&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
HMIMBMAP.PRG is defined as '''Program Continue''', therefore it starts automatically after it is loaded and it does not require an explicit StartTask command.&lt;br /&gt;
&lt;br /&gt;
Of course, HMIMBMAP.PRG can be loaded and executed only after HMIMBMAP.LIB is loaded. Therefore, you should add the following code to AUTOEXEC.PRG or wherever is convenient:&lt;br /&gt;
&amp;lt;pre&amp;gt;Load HMIMBMAP.LIB&lt;br /&gt;
Load HMIMBMAP.PRG&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HMIMBMAP.PRG Explained==&lt;br /&gt;
The code:&lt;br /&gt;
&amp;lt;pre&amp;gt;import HMIMBMAP.LIB&lt;br /&gt;
Program Continue&lt;br /&gt;
	dim retVal as long = 0&lt;br /&gt;
	retVal = Init_Modbus&lt;br /&gt;
	while 1&lt;br /&gt;
		retVal = Read_Modbus_Registers&lt;br /&gt;
		retVal = Write_Modbus_Registers&lt;br /&gt;
		sleep 1&lt;br /&gt;
	end while&lt;br /&gt;
End Program&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The functions '''Init_Modbus''', '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are implemented in '''HMIMBMAP.LIB''', which is automatically generated by a Python script.&lt;br /&gt;
&lt;br /&gt;
The function '''Init_Modbus''' starts the Modbus server and then writes to the Modbus address space all the '''Write Access Variables''' (i.e., all the variables read by the softMC from the Modbus address space). This feature allows you to setup the system to start with an initialized Modbus address space before the HMI/PLC connects to it. The HMI/PLC can read the address space and initialize itself accordingly.&lt;br /&gt;
&lt;br /&gt;
The functions '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are invoked cyclically and indefinitely. '''Read_Modbus_Registers''' reads all the tags that are written by the HMI/PLC and updates the '''Write Access''' variables with new values, while '''Write_Modbus_Registers''' does the opposite.&lt;br /&gt;
&lt;br /&gt;
=4 HMI IDEs and .CSV Files=&lt;br /&gt;
Each line in the .csv file generated by the MCMBConfigurator file holds data about a single variable, such as Modbus address or data type.&lt;br /&gt;
 &lt;br /&gt;
This data can be used by an HMI IDE to import Modbus tags and associate them with HMI functionality.&lt;br /&gt;
&lt;br /&gt;
Different manufacturer IDEs use different .csv formatting; therefore, various Python scripts are used to create the specific .csv files suitable for a particular manufacturer IDE.&lt;br /&gt;
&lt;br /&gt;
==JMobile Studio==&lt;br /&gt;
Python script: '''JMobile_csv.py''' &lt;br /&gt;
&lt;br /&gt;
Default target .csv file name: '''JMobile_HMI.csv''' (user-definable)&lt;br /&gt;
&lt;br /&gt;
To import tags, perform the following procedure in JMobile Studio.&lt;br /&gt;
&lt;br /&gt;
===Define Protocol===&lt;br /&gt;
1. In the ProjectView pane, select '''Protocols'''.&lt;br /&gt;
&lt;br /&gt;
2. Click the blue '''+''' sign.&lt;br /&gt;
&lt;br /&gt;
3. From the list, select Modbus TCP.&lt;br /&gt;
&lt;br /&gt;
4. In the Modbus TCP configuration window, define: &lt;br /&gt;
&lt;br /&gt;
:IP Address: Set the IP address of your softMC.&lt;br /&gt;
&lt;br /&gt;
:PLC Models: Select '''Generic Modbus''' (0-based), meaning the softMC Modbus server starts addressing tags from 0.&lt;br /&gt;
&lt;br /&gt;
:Click '''OK'''.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(7).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
===Import Tags===&lt;br /&gt;
1. In the ProjectView pane, select '''Tags'''.&lt;br /&gt;
&lt;br /&gt;
2. From the list, select '''Modbus TCP''' protocol defined previously.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(8).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
3. Click the '''Import Tags''' button. &lt;br /&gt;
&lt;br /&gt;
4. Open the generated file '''JMobile_HMI.csv'''.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(9).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
5. Select the tags you want to add to your project, and click the ''Import tags'' button.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(10).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==AdvancedHMI==&lt;br /&gt;
AdvancedHMI is an open source project (http://www.advancedhmi.com/), which is downloaded as a Visual Basic project. You can then open the project, add widgets, compile, and run it.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(11).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Drag and drop '''ModbusTCPCom''' into MainForm.vb [Design].&lt;br /&gt;
&lt;br /&gt;
2. The driver appears the bottom of the screen (circled in green). &lt;br /&gt;
&lt;br /&gt;
:Click the driver, and then use the Properties pane (circled in red) to setup the IP address of the Modbus server.&lt;br /&gt;
&lt;br /&gt;
:For example, drag and drop DigitalPanelMeter and MomentaryButton into MainForm.vb [Design].&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(12).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
3. For both widgets, use the Properties pane to set the Modbus address that is associated with the variables from the softMC application.&lt;br /&gt;
&lt;br /&gt;
[[File:softMC_Modbus_HMI_(13).png|600px]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
'''Note''':&lt;br /&gt;
::MC Modbus server addressing starts from '''40000'''.&lt;br /&gt;
::AdvancedHMI Modbus client addressing starts from '''40001'''.&lt;br /&gt;
::Prefix the address with the letter '''L'''.&lt;br /&gt;
&lt;br /&gt;
4. Save the project (Ctrl+S).&lt;br /&gt;
&lt;br /&gt;
5. Build the project (Ctrl+Shift+B).&lt;br /&gt;
&lt;br /&gt;
6. Run the project (F5).&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125868</id>
		<title>Modbus Communication API</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125868"/>
				<updated>2016-04-17T07:39:12Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: changed appereance&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
=== Basic Overview ===&lt;br /&gt;
* This describes how to set up Modbus communication for the softMC, and how to generate softMC scripts to handle Modbus communication.&lt;br /&gt;
* It is assumed you are familiar with the principles of Modbus communication, although some of them will be described in this page.&lt;br /&gt;
* It is also assumed your are familiar with the softMC, ControlStudio and MC-Basic programming.&lt;br /&gt;
&lt;br /&gt;
=== Modbus Communication Background ===&lt;br /&gt;
* A Motion Controller (MC) can act as a server (slave), a client (master) or both at the same time.&lt;br /&gt;
* Each MC connection (TCP/RTU) can be used either as a server component (if the connection is used by the MC’s server-side) or as a client component (if the connection is used by the MC’s client-side).&lt;br /&gt;
* Each component has its own parameters that defines it.&lt;br /&gt;
* When the MC acts as a server, all server components share the '''same''' memory address space, thus acting as one server with multiple connections.&lt;br /&gt;
* Each server (slave) on a Modbus network has its own deviceID, which is a number between 1 and 247.&lt;br /&gt;
&lt;br /&gt;
=== The Modbus server registers ===&lt;br /&gt;
* There are 4 types of registers in the Modbus Server address space:&lt;br /&gt;
*# Bits (1-bit registers)&lt;br /&gt;
*# Input Bits (1-bit READ-ONLY registers)&lt;br /&gt;
*# Holding Registers (16-bit registers)&lt;br /&gt;
*# Input Registers (16-bit READ-ONLY registers)&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
In order to get started in using the Modbus features:&lt;br /&gt;
# Download the required files, according to your system's type:&lt;br /&gt;
## Required files for [[File:modbus_requiredFiles_x86.zip|modbus_X86.ZIP]].&lt;br /&gt;
## Required files for ARM systems.&lt;br /&gt;
# Using the ControlStudio File Manager, Upload the following files to your MC:&lt;br /&gt;
## mb_x86.O ''(for X86 Systems)'' / mb_armA9.O ''(for ARM Systems)''&lt;br /&gt;
## Modbus.lib&lt;br /&gt;
#* '''Notice:''' From now on, in our examples, we'll use the X86 configuration.&amp;lt;br&amp;gt;[[File:modbus;newAPI-upload.jpg|850px]]&lt;br /&gt;
# Access the file CONFIG.PRG and modify the program by adding the following two lines:&lt;br /&gt;
#:&amp;lt;pre&amp;gt;&lt;br /&gt;
#::Program&lt;br /&gt;
#::	Oload mb_x86.O&lt;br /&gt;
#::	Load modbus.lib&lt;br /&gt;
#::...&lt;br /&gt;
#::...&lt;br /&gt;
#::End Program&amp;lt;/pre&amp;gt;&lt;br /&gt;
# Upload CONFIG.PRG to the softMC.&lt;br /&gt;
# Use the ControlStudio Terminal to enter the following:&lt;br /&gt;
#:&amp;lt;pre&amp;gt;&lt;br /&gt;
#::reset all&lt;br /&gt;
#::?tasklist&amp;lt;/pre&amp;gt;&lt;br /&gt;
#: The system's response: &amp;lt;pre&amp;gt;GlobalLibraryName=MODBUS.LIB&amp;lt;/pre&amp;gt;&lt;br /&gt;
#:This indicates that library MODBUS.LIB has been loaded globally.&lt;br /&gt;
#:[[File:softMC_Modbus_HMI_(2).png|300px]]&lt;br /&gt;
# That's it! You're now ready to configure the Modbus system.&lt;br /&gt;
== Initializing a Modbus Server ==&lt;br /&gt;
To initialize the Modbus server address space, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;?init_multi_server([bits],[input_bits],[holding registers],[input_registers])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The function prints &amp;quot;success&amp;quot; and returns 0 on success, or return an error code on failure.&lt;br /&gt;
* &amp;lt;u&amp;gt;'''Notice:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
*# This is '''NOT''' required when softMC does not run a modbus server.&lt;br /&gt;
*# You can call this method only if no servers are running.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Memory allocation failure.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Some servers are still running and using an already mapped address space.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to create a modbus mapping.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Server Components ==&lt;br /&gt;
=== Adding server components ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Creating a TCP server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_server_create([port],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens a TCP connection to the server on port [port] with deviceID [deviceID], and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Failed to create main socket.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|}&lt;br /&gt;
==== Creating an RTU server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_server_create([type],[port],[baudrate],[data bits],[stop bits],[parity],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens an RTU connection with the given parameters, and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Invalid device string.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Invalid parity.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed opening RTU.&lt;br /&gt;
|-&lt;br /&gt;
| -5&lt;br /&gt;
| Failed allocating query buffer memory.&lt;br /&gt;
|-&lt;br /&gt;
| -6&lt;br /&gt;
| Failed to set RTU mode.&lt;br /&gt;
|-&lt;br /&gt;
| -7&lt;br /&gt;
| Unable to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -8&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|-&lt;br /&gt;
| -9&lt;br /&gt;
| The device is already in use by another system component.&lt;br /&gt;
|}&lt;br /&gt;
=== Stopping Server Components ===&lt;br /&gt;
==== Stopping a specific server component ====&lt;br /&gt;
You can stop a specific server component by passing its handle to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate server component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
==== Stopping all server components ====&lt;br /&gt;
You can stop all server components with a single call to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop_all&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function will:&lt;br /&gt;
* Stop and free all server components.&lt;br /&gt;
* Free the shared address space.&lt;br /&gt;
* Return 0 on success, -1 on failure.&lt;br /&gt;
== Client Components ==&lt;br /&gt;
=== Adding client components ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Adding a TCP Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_client_create([ip],[port])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will opens a TCP connection to the client on the given ip and port, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
==== Adding an RTU Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_client_create([type],[port],[baudrate],[data bits],[stop bits],[parity])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will open an RTU connection to the client with the given parameters, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
=== Stopping client components ===&lt;br /&gt;
A specific client can be stopped by calling:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_client_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate client component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reset the Modbus System ==&lt;br /&gt;
Sometimes, a user may wish to stop all server and client components at once, and reset the Modbus system (for example, when a user want to initialize a different Modbus system). To do that, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_reset&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function:&lt;br /&gt;
* Stops all running servers and clients.&lt;br /&gt;
* Frees their memory.&lt;br /&gt;
* Frees the shared address space.&lt;br /&gt;
* Reset the handle counter.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reading and Writing ==&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
* Therefore, Servers and clients use different functions to read/write data from the address space.&lt;br /&gt;
=== Server Components ===&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers and return them.&lt;br /&gt;
* When a read error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_REG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_READ_BIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_INREG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt; val = MB_SERVER_READ_INBIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data into the different types of registers.&lt;br /&gt;
* When a write error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Writing to holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_BIT([index],[new value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_INBIT([index],[value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| New value&lt;br /&gt;
| The value to write, must be from the appropriate type.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Error codes ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Invalid index.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Local server's address space isn't mapped yet.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to catch the register mutex.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to release the register mutex.&lt;br /&gt;
|}&lt;br /&gt;
=== Client Components ===&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The read value is inserted into an existing variable from the appropriate type (long/double).&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_REG_LONG([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_BITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_LONG ([handle],[deviceID],[addr],[dest ptr]) &lt;br /&gt;
Val = MB_CLIENT_READ_INREG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_INBITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to read from.&lt;br /&gt;
|-&lt;br /&gt;
| Num of bits (Reading bits)&lt;br /&gt;
| The number of bits to read.&lt;br /&gt;
|-&lt;br /&gt;
| dest ptr / dest arr ptr&lt;br /&gt;
| The variable to store the read data. When reading bits, this must be an array of longs in the appropriate size (&amp;gt;= Num of bits).&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data from existing variables to the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Writing to Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_LONG([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_SHORT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_FLOAT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_DOUBLE([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_WRITE_BIT([handle],[deviceID],[addr],[src ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to start writing to.&lt;br /&gt;
|-&lt;br /&gt;
| src ptr&lt;br /&gt;
| The variable that stores the data to be written. This must be a variable from the appropriate type.&lt;br /&gt;
|}&lt;br /&gt;
=== Reading and Writing Summary ===&lt;br /&gt;
[[File:modbus;newAPI-readwriteSummary.jpg|850px]]&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125867</id>
		<title>Modbus Communication API</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125867"/>
				<updated>2016-04-17T07:38:23Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: Added valid input parameters and error codes&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
=== Basic Overview ===&lt;br /&gt;
* This describes how to set up Modbus communication for the softMC, and how to generate softMC scripts to handle Modbus communication.&lt;br /&gt;
* It is assumed you are familiar with the principles of Modbus communication, although some of them will be described in this page.&lt;br /&gt;
* It is also assumed your are familiar with the softMC, ControlStudio and MC-Basic programming.&lt;br /&gt;
&lt;br /&gt;
=== Modbus Communication Background ===&lt;br /&gt;
* A Motion Controller (MC) can act as a server (slave), a client (master) or both at the same time.&lt;br /&gt;
* Each MC connection (TCP/RTU) can be used either as a server component (if the connection is used by the MC’s server-side) or as a client component (if the connection is used by the MC’s client-side).&lt;br /&gt;
* Each component has its own parameters that defines it.&lt;br /&gt;
* When the MC acts as a server, all server components share the '''same''' memory address space, thus acting as one server with multiple connections.&lt;br /&gt;
* Each server (slave) on a Modbus network has its own deviceID, which is a number between 1 and 247.&lt;br /&gt;
&lt;br /&gt;
=== The Modbus server registers ===&lt;br /&gt;
* There are 4 types of registers in the Modbus Server address space:&lt;br /&gt;
*# Bits (1-bit registers)&lt;br /&gt;
*# Input Bits (1-bit READ-ONLY registers)&lt;br /&gt;
*# Holding Registers (16-bit registers)&lt;br /&gt;
*# Input Registers (16-bit READ-ONLY registers)&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
In order to get started in using the Modbus features:&lt;br /&gt;
# Download the required files, according to your system's type:&lt;br /&gt;
## Required files for [[File:modbus_requiredFiles_x86.zip|modbus_X86.ZIP]].&lt;br /&gt;
## Required files for ARM systems.&lt;br /&gt;
# Using the ControlStudio File Manager, Upload the following files to your MC:&lt;br /&gt;
## mb_x86.O ''(for X86 Systems)'' / mb_armA9.O ''(for ARM Systems)''&lt;br /&gt;
## Modbus.lib&lt;br /&gt;
#* '''Notice:''' From now on, in our examples, we'll use the X86 configuration.&amp;lt;br&amp;gt;[[File:modbus;newAPI-upload.jpg|850px]]&lt;br /&gt;
# Access the file CONFIG.PRG and modify the program by adding the following two lines:&lt;br /&gt;
#:&amp;lt;pre&amp;gt;&lt;br /&gt;
#::Program&lt;br /&gt;
#::	Oload mb_x86.O&lt;br /&gt;
#::	Load modbus.lib&lt;br /&gt;
#::...&lt;br /&gt;
#::...&lt;br /&gt;
#::End Program&amp;lt;/pre&amp;gt;&lt;br /&gt;
# Upload CONFIG.PRG to the softMC.&lt;br /&gt;
# Use the ControlStudio Terminal to enter the following:&lt;br /&gt;
#:&amp;lt;pre&amp;gt;&lt;br /&gt;
#::reset all&lt;br /&gt;
#::?tasklist&amp;lt;/pre&amp;gt;&lt;br /&gt;
#: The system's response: &amp;lt;pre&amp;gt;GlobalLibraryName=MODBUS.LIB&amp;lt;/pre&amp;gt;&lt;br /&gt;
#:This indicates that library MODBUS.LIB has been loaded globally.&lt;br /&gt;
#:[[File:softMC_Modbus_HMI_(2).png|400px]]&lt;br /&gt;
# That's it! You're now ready to configure the Modbus system.&lt;br /&gt;
== Initializing a Modbus Server ==&lt;br /&gt;
To initialize the Modbus server address space, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;?init_multi_server([bits],[input_bits],[holding registers],[input_registers])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The function prints &amp;quot;success&amp;quot; and returns 0 on success, or return an error code on failure.&lt;br /&gt;
* &amp;lt;u&amp;gt;'''Notice:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
*# This is '''NOT''' required when softMC does not run a modbus server.&lt;br /&gt;
*# You can call this method only if no servers are running.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Memory allocation failure.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Some servers are still running and using an already mapped address space.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to create a modbus mapping.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Server Components ==&lt;br /&gt;
=== Adding server components ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Creating a TCP server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_server_create([port],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens a TCP connection to the server on port [port] with deviceID [deviceID], and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Failed to create main socket.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|}&lt;br /&gt;
==== Creating an RTU server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_server_create([type],[port],[baudrate],[data bits],[stop bits],[parity],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens an RTU connection with the given parameters, and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Invalid device string.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Invalid parity.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed opening RTU.&lt;br /&gt;
|-&lt;br /&gt;
| -5&lt;br /&gt;
| Failed allocating query buffer memory.&lt;br /&gt;
|-&lt;br /&gt;
| -6&lt;br /&gt;
| Failed to set RTU mode.&lt;br /&gt;
|-&lt;br /&gt;
| -7&lt;br /&gt;
| Unable to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -8&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|-&lt;br /&gt;
| -9&lt;br /&gt;
| The device is already in use by another system component.&lt;br /&gt;
|}&lt;br /&gt;
=== Stopping Server Components ===&lt;br /&gt;
==== Stopping a specific server component ====&lt;br /&gt;
You can stop a specific server component by passing its handle to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate server component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
==== Stopping all server components ====&lt;br /&gt;
You can stop all server components with a single call to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop_all&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function will:&lt;br /&gt;
* Stop and free all server components.&lt;br /&gt;
* Free the shared address space.&lt;br /&gt;
* Return 0 on success, -1 on failure.&lt;br /&gt;
== Client Components ==&lt;br /&gt;
=== Adding client components ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Adding a TCP Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_client_create([ip],[port])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will opens a TCP connection to the client on the given ip and port, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
==== Adding an RTU Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_client_create([type],[port],[baudrate],[data bits],[stop bits],[parity])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will open an RTU connection to the client with the given parameters, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
=== Stopping client components ===&lt;br /&gt;
A specific client can be stopped by calling:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_client_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate client component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reset the Modbus System ==&lt;br /&gt;
Sometimes, a user may wish to stop all server and client components at once, and reset the Modbus system (for example, when a user want to initialize a different Modbus system). To do that, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_reset&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function:&lt;br /&gt;
* Stops all running servers and clients.&lt;br /&gt;
* Frees their memory.&lt;br /&gt;
* Frees the shared address space.&lt;br /&gt;
* Reset the handle counter.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reading and Writing ==&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
* Therefore, Servers and clients use different functions to read/write data from the address space.&lt;br /&gt;
=== Server Components ===&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers and return them.&lt;br /&gt;
* When a read error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_REG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_READ_BIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_INREG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt; val = MB_SERVER_READ_INBIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data into the different types of registers.&lt;br /&gt;
* When a write error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Writing to holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_BIT([index],[new value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_INBIT([index],[value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| New value&lt;br /&gt;
| The value to write, must be from the appropriate type.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Error codes ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Invalid index.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Local server's address space isn't mapped yet.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to catch the register mutex.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to release the register mutex.&lt;br /&gt;
|}&lt;br /&gt;
=== Client Components ===&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The read value is inserted into an existing variable from the appropriate type (long/double).&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_REG_LONG([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_BITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_LONG ([handle],[deviceID],[addr],[dest ptr]) &lt;br /&gt;
Val = MB_CLIENT_READ_INREG_SHORT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_FLOAT([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_DOUBLE([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_INBITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to read from.&lt;br /&gt;
|-&lt;br /&gt;
| Num of bits (Reading bits)&lt;br /&gt;
| The number of bits to read.&lt;br /&gt;
|-&lt;br /&gt;
| dest ptr / dest arr ptr&lt;br /&gt;
| The variable to store the read data. When reading bits, this must be an array of longs in the appropriate size (&amp;gt;= Num of bits).&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data from existing variables to the different types of registers in a REMOTE modbus server.&lt;br /&gt;
* The functions return 0 on success or an error code (not 0) on failure.&lt;br /&gt;
===== Writing to Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_LONG([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_SHORT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_FLOAT([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_DOUBLE([handle],[deviceID],[addr],[src ptr])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_WRITE_BIT([handle],[deviceID],[addr],[src ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Handle&lt;br /&gt;
| The client's unique identifier (received on client creation).&lt;br /&gt;
|-&lt;br /&gt;
| DeviceID&lt;br /&gt;
| The remote server(slave)'s device ID.&lt;br /&gt;
|-&lt;br /&gt;
| Addr&lt;br /&gt;
| The index of the register to start writing to.&lt;br /&gt;
|-&lt;br /&gt;
| src ptr&lt;br /&gt;
| The variable that stores the data to be written. This must be a variable from the appropriate type.&lt;br /&gt;
|}&lt;br /&gt;
=== Reading and Writing Summary ===&lt;br /&gt;
[[File:modbus;newAPI-readwriteSummary.jpg|850px]]&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125866</id>
		<title>Modbus Communication API</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125866"/>
				<updated>2016-04-17T07:14:10Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: Added valid input parameters and error codes&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
=== Basic Overview ===&lt;br /&gt;
* This describes how to set up Modbus communication for the softMC, and how to generate softMC scripts to handle Modbus communication.&lt;br /&gt;
* It is assumed you are familiar with the principles of Modbus communication, although some of them will be described in this page.&lt;br /&gt;
* It is also assumed your are familiar with the softMC, ControlStudio and MC-Basic programming.&lt;br /&gt;
&lt;br /&gt;
=== Modbus Communication Background ===&lt;br /&gt;
* A Motion Controller (MC) can act as a server (slave), a client (master) or both at the same time.&lt;br /&gt;
* Each MC connection (TCP/RTU) can be used either as a server component (if the connection is used by the MC’s server-side) or as a client component (if the connection is used by the MC’s client-side).&lt;br /&gt;
* Each component has its own parameters that defines it.&lt;br /&gt;
* When the MC acts as a server, all server components share the '''same''' memory address space, thus acting as one server with multiple connections.&lt;br /&gt;
* Each server (slave) on a Modbus network has its own deviceID, which is a number between 1 and 247.&lt;br /&gt;
&lt;br /&gt;
=== The Modbus server registers ===&lt;br /&gt;
* There are 4 types of registers in the Modbus Server address space:&lt;br /&gt;
*# Bits (1-bit registers)&lt;br /&gt;
*# Input Bits (1-bit READ-ONLY registers)&lt;br /&gt;
*# Holding Registers (16-bit registers)&lt;br /&gt;
*# Input Registers (16-bit READ-ONLY registers)&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
In order to get started in using the Modbus features:&lt;br /&gt;
# Download the required files, according to your system's type:&lt;br /&gt;
## Required files for [[File:modbus_requiredFiles_x86.zip|modbus_X86.ZIP]].&lt;br /&gt;
## Required files for ARM systems.&lt;br /&gt;
# Using the ControlStudio File Manager, Upload the following files to your MC:&lt;br /&gt;
## mb_x86.O ''(for X86 Systems)'' / mb_armA9.O ''(for ARM Systems)''&lt;br /&gt;
## Modbus.lib&lt;br /&gt;
#* '''Notice:''' From now on, in our examples, we'll use the X86 configuration.&amp;lt;br&amp;gt;[[File:modbus;newAPI-upload.jpg|850px]]&lt;br /&gt;
# Access the file CONFIG.PRG and modify the program by adding the following two lines:&lt;br /&gt;
#:&amp;lt;pre&amp;gt;&lt;br /&gt;
#::Program&lt;br /&gt;
#::	Oload mb_x86.O&lt;br /&gt;
#::	Load modbus.lib&lt;br /&gt;
#::...&lt;br /&gt;
#::...&lt;br /&gt;
#::End Program&amp;lt;/pre&amp;gt;&lt;br /&gt;
# Upload CONFIG.PRG to the softMC.&lt;br /&gt;
# Use the ControlStudio Terminal to enter the following:&lt;br /&gt;
#:&amp;lt;pre&amp;gt;&lt;br /&gt;
#::reset all&lt;br /&gt;
#::?tasklist&amp;lt;/pre&amp;gt;&lt;br /&gt;
#: The system's response: &amp;lt;pre&amp;gt;GlobalLibraryName=MODBUS.LIB&amp;lt;/pre&amp;gt;&lt;br /&gt;
#:This indicates that library MODBUS.LIB has been loaded globally.&lt;br /&gt;
# That's it! You're now ready to configure the Modbus system.&lt;br /&gt;
== Initializing a Modbus Server ==&lt;br /&gt;
To initialize the Modbus server address space, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;?init_multi_server([bits],[input_bits],[holding registers],[input_registers])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The function prints &amp;quot;success&amp;quot; and returns 0 on success, or return an error code on failure.&lt;br /&gt;
* &amp;lt;u&amp;gt;'''Notice:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
*# This is '''NOT''' required when softMC does not run a modbus server.&lt;br /&gt;
*# You can call this method only if no servers are running.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Memory allocation failure.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Some servers are still running and using an already mapped address space.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to create a modbus mapping.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Server Components ==&lt;br /&gt;
=== Adding server components ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Creating a TCP server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_server_create([port],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens a TCP connection to the server on port [port] with deviceID [deviceID], and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Failed to create main socket.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|}&lt;br /&gt;
==== Creating an RTU server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_server_create([type],[port],[baudrate],[data bits],[stop bits],[parity],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens an RTU connection with the given parameters, and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Invalid device string.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Invalid parity.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed opening RTU.&lt;br /&gt;
|-&lt;br /&gt;
| -5&lt;br /&gt;
| Failed allocating query buffer memory.&lt;br /&gt;
|-&lt;br /&gt;
| -6&lt;br /&gt;
| Failed to set RTU mode.&lt;br /&gt;
|-&lt;br /&gt;
| -7&lt;br /&gt;
| Unable to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -8&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|-&lt;br /&gt;
| -9&lt;br /&gt;
| The device is already in use by another system component.&lt;br /&gt;
|}&lt;br /&gt;
=== Stopping Server Components ===&lt;br /&gt;
==== Stopping a specific server component ====&lt;br /&gt;
You can stop a specific server component by passing its handle to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate server component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
==== Stopping all server components ====&lt;br /&gt;
You can stop all server components with a single call to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop_all&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function will:&lt;br /&gt;
* Stop and free all server components.&lt;br /&gt;
* Free the shared address space.&lt;br /&gt;
* Return 0 on success, -1 on failure.&lt;br /&gt;
== Client Components ==&lt;br /&gt;
=== Adding client components ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Adding a TCP Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_client_create([ip],[port])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will opens a TCP connection to the client on the given ip and port, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
==== Adding an RTU Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_client_create([type],[port],[baudrate],[data bits],[stop bits],[parity])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will open an RTU connection to the client with the given parameters, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
=== Stopping client components ===&lt;br /&gt;
A specific client can be stopped by calling:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_client_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate client component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reset the Modbus System ==&lt;br /&gt;
Sometimes, a user may wish to stop all server and client components at once, and reset the Modbus system (for example, when a user want to initialize a different Modbus system). To do that, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_reset&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function:&lt;br /&gt;
* Stops all running servers and clients.&lt;br /&gt;
* Frees their memory.&lt;br /&gt;
* Frees the shared address space.&lt;br /&gt;
* Reset the handle counter.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reading and Writing ==&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
* Therefore, Servers and clients use different functions to read/write data from the address space.&lt;br /&gt;
=== Server Components ===&lt;br /&gt;
==== Reading ====&lt;br /&gt;
* The following functions read variables from the different types of registers and return them.&lt;br /&gt;
* When a read error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_REG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_READ_BIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_INREG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_FLOAT([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_INREG_DOUBLE([index], [byte_swap], [word_swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt; val = MB_SERVER_READ_INBIT([index])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Writing ====&lt;br /&gt;
* The following functions write data into the different types of registers.&lt;br /&gt;
* When a write error occurs, the functions will write [function name] + &amp;quot;ERROR&amp;quot; + [error code] in the Message Log.&lt;br /&gt;
===== Writing to holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_BIT([index],[new value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_LONG([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_SHORT([index],[new value],[byte swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_FLOAT([index],[new value],[byte swap], [word swap])&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_INBIT([index],[value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Valid Parameters =====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Valid Input&lt;br /&gt;
|-&lt;br /&gt;
| Index&lt;br /&gt;
| From 0 to the number of registers available.&lt;br /&gt;
|-&lt;br /&gt;
| New value&lt;br /&gt;
| The value to write, must be from the appropriate type.&lt;br /&gt;
|-&lt;br /&gt;
| Byte_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Word_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|-&lt;br /&gt;
| Long_swap&lt;br /&gt;
| 1 or 0 (True/False)&lt;br /&gt;
|}&lt;br /&gt;
==== Error codes ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Invalid index.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Local server's address space isn't mapped yet.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to catch the register mutex.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to release the register mutex.&lt;br /&gt;
|}&lt;br /&gt;
=== Client Components ===&lt;br /&gt;
==== Reading ====&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_REG_LONG([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_SHORT(…)&lt;br /&gt;
Val = MB_CLIENT_READ_REG_FLOAT(…)&lt;br /&gt;
Val = MB_CLIENT_READ_REG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_BITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_LONG ([handle],[deviceID],[addr],[dest ptr]) &lt;br /&gt;
Val = MB_CLIENT_READ_INREG_SHORT(…)&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_FLOAT(…)&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_INBITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== Writing ====&lt;br /&gt;
===== Writing to Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_LONG([addr],[val ptr],[deviceID])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_SHORT(…)&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_FLOAT(…)&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_WRITE_BIT([addr],[val ptr],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== Reading and Writing Summary ===&lt;br /&gt;
[[File:modbus;newAPI-readwriteSummary.jpg|850px]]&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125865</id>
		<title>Modbus Communication API</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125865"/>
				<updated>2016-04-12T14:52:39Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: added error codes&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
=== Basic Overview ===&lt;br /&gt;
* This describes how to set up Modbus communication for the softMC, and how to generate softMC scripts to handle Modbus communication.&lt;br /&gt;
* It is assumed you are familiar with the principles of Modbus communication, although some of them will be described in this page.&lt;br /&gt;
* It is also assumed your are familiar with the softMC, ControlStudio and MC-Basic programming.&lt;br /&gt;
&lt;br /&gt;
=== Modbus Communication Background ===&lt;br /&gt;
* A Motion Controller (MC) can act as a server (slave), a client (master) or both at the same time.&lt;br /&gt;
* Each MC connection (TCP/RTU) can be used either as a server component (if the connection is used by the MC’s server-side) or as a client component (if the connection is used by the MC’s client-side).&lt;br /&gt;
* Each component has its own parameters that defines it.&lt;br /&gt;
* When the MC acts as a server, all server components share the '''same''' memory address space, thus acting as one server with multiple connections.&lt;br /&gt;
* Each server (slave) on a Modbus network has its own deviceID, which is a number between 1 and 247.&lt;br /&gt;
&lt;br /&gt;
=== The Modbus server registers ===&lt;br /&gt;
* There are 4 types of registers in the Modbus Server address space:&lt;br /&gt;
*# Bits (1-bit registers)&lt;br /&gt;
*# Input Bits (1-bit READ-ONLY registers)&lt;br /&gt;
*# Holding Registers (16-bit registers)&lt;br /&gt;
*# Input Registers (16-bit READ-ONLY registers)&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
In order to get started in using the Modbus features:&lt;br /&gt;
# Download the required files, according to your system's type:&lt;br /&gt;
## Required files for [[File:modbus_requiredFiles_x86.zip|modbus_X86.ZIP]].&lt;br /&gt;
## Required files for ARM systems.&lt;br /&gt;
# Using the ControlStudio File Manager, Upload the following files to your MC:&lt;br /&gt;
## mb_x86.O ''(for X86 Systems)'' / mb_armA9.O ''(for ARM Systems)''&lt;br /&gt;
## Modbus.lib&lt;br /&gt;
#* '''Notice:''' From now on, in our examples, we'll use the X86 configuration.&amp;lt;br&amp;gt;[[File:modbus;newAPI-upload.jpg|850px]]&lt;br /&gt;
# Load the files to memory, by typing (in the Terminal):&lt;br /&gt;
#:&amp;lt;pre&amp;gt;&lt;br /&gt;
#::Oload mb_x86.O&lt;br /&gt;
#::loadglobal Modbus.lib&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Initializing a Modbus Server ==&lt;br /&gt;
To initialize the Modbus server address space, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;?init_multi_server([bits],[input_bits],[holding registers],[input_registers])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The function prints &amp;quot;success&amp;quot; and returns 0 on success, or return an error code on failure.&lt;br /&gt;
* &amp;lt;u&amp;gt;'''Notice:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
*# This is '''NOT''' required when softMC does not run a modbus server.&lt;br /&gt;
*# You can call this method only if no servers are running.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Memory allocation failure.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Some servers are still running and using an already mapped address space.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to create a modbus mapping.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Server Components ==&lt;br /&gt;
=== Adding server components ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Creating a TCP server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_server_create([port],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens a TCP connection to the server on port [port] with deviceID [deviceID], and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Failed to create main socket.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|}&lt;br /&gt;
==== Creating an RTU server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_server_create([type],[port],[baudrate],[data bits],[stop bits],[parity],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens an RTU connection with the given parameters, and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Server address spaces isn't initialized yet, please call &amp;quot;init_multi_server(...) and try again.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Invalid device string.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Invalid parity.&lt;br /&gt;
|-&lt;br /&gt;
| -4&lt;br /&gt;
| Failed opening RTU.&lt;br /&gt;
|-&lt;br /&gt;
| -5&lt;br /&gt;
| Failed allocating query buffer memory.&lt;br /&gt;
|-&lt;br /&gt;
| -6&lt;br /&gt;
| Failed to set RTU mode.&lt;br /&gt;
|-&lt;br /&gt;
| -7&lt;br /&gt;
| Unable to connect.&lt;br /&gt;
|-&lt;br /&gt;
| -8&lt;br /&gt;
| Failed to create server thread.&lt;br /&gt;
|-&lt;br /&gt;
| -9&lt;br /&gt;
| The device is already in use by another system component.&lt;br /&gt;
|}&lt;br /&gt;
=== Stopping Server Components ===&lt;br /&gt;
==== Stopping a specific server component ====&lt;br /&gt;
You can stop a specific server component by passing its handle to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate server component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
==== Stopping all server components ====&lt;br /&gt;
You can stop all server components with a single call to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop_all&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function will:&lt;br /&gt;
* Stop and free all server components.&lt;br /&gt;
* Free the shared address space.&lt;br /&gt;
* Return 0 on success, -1 on failure.&lt;br /&gt;
== Client Components ==&lt;br /&gt;
=== Adding client components ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Adding a TCP Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_client_create([ip],[port])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will opens a TCP connection to the client on the given ip and port, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
==== Adding an RTU Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_client_create([type],[port],[baudrate],[data bits],[stop bits],[parity])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will open an RTU connection to the client with the given parameters, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
=== Stopping client components ===&lt;br /&gt;
A specific client can be stopped by calling:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_client_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate client component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reset the Modbus System ==&lt;br /&gt;
Sometimes, a user may wish to stop all server and client components at once, and reset the Modbus system (for example, when a user want to initialize a different Modbus system). To do that, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_reset&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function:&lt;br /&gt;
* Stops all running servers and clients.&lt;br /&gt;
* Frees their memory.&lt;br /&gt;
* Frees the shared address space.&lt;br /&gt;
* Reset the handle counter.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
== Reading and Writing ==&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
* Therefore, Servers and clients use different functions to read/write data from the address space.&lt;br /&gt;
=== Server Components ===&lt;br /&gt;
==== Reading ====&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_REG_LONG([index], [byte_swap], [word_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_SHORT([index], [byte_swap])&lt;br /&gt;
Val = MB_SERVER_READ_REG_FLOAT(…)&lt;br /&gt;
Val = MB_SERVER_READ_REG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_READ_BIT([addr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_INREG_LONG(…)&lt;br /&gt;
Val = MB_SERVER_READ_INREG_SHORT(…)&lt;br /&gt;
Val = MB_SERVER_READ_INREG_FLOAT(…)&lt;br /&gt;
Val = MB_SERVER_READ_INREG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt; val = MB_SERVER_READ_INBIT([addr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== Writing ====&lt;br /&gt;
===== Writing to holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_LONG(…)&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_SHORT(…)&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_FLOAT(…)&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_BIT([addr],[value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_LONG(…)&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_SHORT(…)&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_FLOAT(…)&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_INBIT([addr],[value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Client Components ===&lt;br /&gt;
==== Reading ====&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_REG_LONG([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_SHORT(…)&lt;br /&gt;
Val = MB_CLIENT_READ_REG_FLOAT(…)&lt;br /&gt;
Val = MB_CLIENT_READ_REG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_BITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_LONG ([handle],[deviceID],[addr],[dest ptr]) &lt;br /&gt;
Val = MB_CLIENT_READ_INREG_SHORT(…)&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_FLOAT(…)&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_INBITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== Writing ====&lt;br /&gt;
===== Writing to Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_LONG([addr],[val ptr],[deviceID])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_SHORT(…)&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_FLOAT(…)&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_WRITE_BIT([addr],[val ptr],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== Reading and Writing Summary ===&lt;br /&gt;
[[File:modbus;newAPI-readwriteSummary.jpg|850px]]&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125864</id>
		<title>Modbus Communication API</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125864"/>
				<updated>2016-04-12T14:40:07Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: /* Initializing a Modbus Server */ added error codes&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
=== Basic Overview ===&lt;br /&gt;
* This describes how to set up Modbus communication for the softMC, and how to generate softMC scripts to handle Modbus communication.&lt;br /&gt;
* It is assumed you are familiar with the principles of Modbus communication, although some of them will be described in this page.&lt;br /&gt;
* It is also assumed your are familiar with the softMC, ControlStudio and MC-Basic programming.&lt;br /&gt;
&lt;br /&gt;
=== Modbus Communication Background ===&lt;br /&gt;
* A Motion Controller (MC) can act as a server (slave), a client (master) or both at the same time.&lt;br /&gt;
* Each MC connection (TCP/RTU) can be used either as a server component (if the connection is used by the MC’s server-side) or as a client component (if the connection is used by the MC’s client-side).&lt;br /&gt;
* Each component has its own parameters that defines it.&lt;br /&gt;
* When the MC acts as a server, all server components share the '''same''' memory address space, thus acting as one server with multiple connections.&lt;br /&gt;
* Each server (slave) on a Modbus network has its own deviceID, which is a number between 1 and 247.&lt;br /&gt;
&lt;br /&gt;
=== The Modbus server registers ===&lt;br /&gt;
* There are 4 types of registers in the Modbus Server address space:&lt;br /&gt;
*# Bits (1-bit registers)&lt;br /&gt;
*# Input Bits (1-bit READ-ONLY registers)&lt;br /&gt;
*# Holding Registers (16-bit registers)&lt;br /&gt;
*# Input Registers (16-bit READ-ONLY registers)&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
In order to get started in using the Modbus features:&lt;br /&gt;
# Download the required files, according to your system's type:&lt;br /&gt;
## Required files for [[File:modbus_requiredFiles_x86.zip|modbus_X86.ZIP]].&lt;br /&gt;
## Required files for ARM systems.&lt;br /&gt;
# Using the ControlStudio File Manager, Upload the following files to your MC:&lt;br /&gt;
## mb_x86.O ''(for X86 Systems)'' / mb_armA9.O ''(for ARM Systems)''&lt;br /&gt;
## Modbus.lib&lt;br /&gt;
#* '''Notice:''' From now on, in our examples, we'll use the X86 configuration.&amp;lt;br&amp;gt;[[File:modbus;newAPI-upload.jpg|850px]]&lt;br /&gt;
# Load the files to memory, by typing (in the Terminal):&lt;br /&gt;
#:&amp;lt;pre&amp;gt;&lt;br /&gt;
#::Oload mb_x86.O&lt;br /&gt;
#::loadglobal Modbus.lib&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Initializing a Modbus Server ==&lt;br /&gt;
To initialize the Modbus server address space, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;?init_multi_server([bits],[input_bits],[holding registers],[input_registers])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The function prints &amp;quot;success&amp;quot; and returns 0 on success, or return an error code on failure.&lt;br /&gt;
* &amp;lt;u&amp;gt;'''Notice:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
*# This is '''NOT''' required when softMC does not run a modbus server.&lt;br /&gt;
*# You can call this method only if no servers are running.&lt;br /&gt;
&amp;lt;u&amp;gt;'''Error codes:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| Memory allocation failure.&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| Some servers are still running and using an already mapped address space.&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| Failed to create a modbus mapping.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Server Components ==&lt;br /&gt;
=== Adding server components ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Creating a TCP server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_server_create([port],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens a TCP connection to the server on port [port] with deviceID [deviceID], and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
==== Creating an RTU server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_server_create([type],[port],[baudrate],[data bits],[stop bits],[parity],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens an RTU connection with the given parameters, and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&lt;br /&gt;
=== Stopping Server Components ===&lt;br /&gt;
==== Stopping a specific server component ====&lt;br /&gt;
You can stop a specific server component by passing its handle to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate server component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
==== Stopping all server components ====&lt;br /&gt;
You can stop all server components with a single call to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop_all&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function will:&lt;br /&gt;
* Stop and free all server components.&lt;br /&gt;
* Free the shared address space.&lt;br /&gt;
* Return 0 on success, -1 on failure.&lt;br /&gt;
&lt;br /&gt;
== Client Components ==&lt;br /&gt;
=== Adding client components ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Adding a TCP Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_client_create([ip],[port])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will opens a TCP connection to the client on the given ip and port, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
==== Adding an RTU Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_client_create([type],[port],[baudrate],[data bits],[stop bits],[parity])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will open an RTU connection to the client with the given parameters, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
=== Stopping client components ===&lt;br /&gt;
A specific client can be stopped by calling:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_client_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate client component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
&lt;br /&gt;
== Reset the Modbus System ==&lt;br /&gt;
Sometimes, a user may wish to stop all server and client components at once, and reset the Modbus system (for example, when a user want to initialize a different Modbus system). To do that, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_reset&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function:&lt;br /&gt;
* Stops all running servers and clients.&lt;br /&gt;
* Frees their memory.&lt;br /&gt;
* Frees the shared address space.&lt;br /&gt;
* Reset the handle counter.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
&lt;br /&gt;
== Reading and Writing ==&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
* Therefore, Servers and clients use different functions to read/write data from the address space.&lt;br /&gt;
=== Server Components ===&lt;br /&gt;
==== Reading ====&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_REG_LONG(…)&lt;br /&gt;
Val = MB_SERVER_READ_REG_SHORT(…)&lt;br /&gt;
Val = MB_SERVER_READ_REG_FLOAT(…)&lt;br /&gt;
Val = MB_SERVER_READ_REG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_READ_BIT([addr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_INREG_LONG(…)&lt;br /&gt;
Val = MB_SERVER_READ_INREG_SHORT(…)&lt;br /&gt;
Val = MB_SERVER_READ_INREG_FLOAT(…)&lt;br /&gt;
Val = MB_SERVER_READ_INREG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt; val = MB_SERVER_READ_INBIT([addr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== Writing ====&lt;br /&gt;
===== Writing to holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_LONG(…)&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_SHORT(…)&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_FLOAT(…)&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_BIT([addr],[value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_LONG(…)&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_SHORT(…)&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_FLOAT(…)&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_INBIT([addr],[value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Client Components ===&lt;br /&gt;
==== Reading ====&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_REG_LONG([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_SHORT(…)&lt;br /&gt;
Val = MB_CLIENT_READ_REG_FLOAT(…)&lt;br /&gt;
Val = MB_CLIENT_READ_REG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_BITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_LONG ([handle],[deviceID],[addr],[dest ptr]) &lt;br /&gt;
Val = MB_CLIENT_READ_INREG_SHORT(…)&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_FLOAT(…)&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_INBITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== Writing ====&lt;br /&gt;
===== Writing to Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_LONG([addr],[val ptr],[deviceID])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_SHORT(…)&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_FLOAT(…)&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_WRITE_BIT([addr],[val ptr],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== Reading and Writing Summary ===&lt;br /&gt;
[[File:modbus;newAPI-readwriteSummary.jpg|850px]]&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125863</id>
		<title>Modbus Communication API</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125863"/>
				<updated>2016-04-12T14:33:39Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: Modbus new API: Draft 4&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
=== Basic Overview ===&lt;br /&gt;
* This describes how to set up Modbus communication for the softMC, and how to generate softMC scripts to handle Modbus communication.&lt;br /&gt;
* It is assumed you are familiar with the principles of Modbus communication, although some of them will be described in this page.&lt;br /&gt;
* It is also assumed your are familiar with the softMC, ControlStudio and MC-Basic programming.&lt;br /&gt;
&lt;br /&gt;
=== Modbus Communication Background ===&lt;br /&gt;
* A Motion Controller (MC) can act as a server (slave), a client (master) or both at the same time.&lt;br /&gt;
* Each MC connection (TCP/RTU) can be used either as a server component (if the connection is used by the MC’s server-side) or as a client component (if the connection is used by the MC’s client-side).&lt;br /&gt;
* Each component has its own parameters that defines it.&lt;br /&gt;
* When the MC acts as a server, all server components share the '''same''' memory address space, thus acting as one server with multiple connections.&lt;br /&gt;
* Each server (slave) on a Modbus network has its own deviceID, which is a number between 1 and 247.&lt;br /&gt;
&lt;br /&gt;
=== The Modbus server registers ===&lt;br /&gt;
* There are 4 types of registers in the Modbus Server address space:&lt;br /&gt;
*# Bits (1-bit registers)&lt;br /&gt;
*# Input Bits (1-bit READ-ONLY registers)&lt;br /&gt;
*# Holding Registers (16-bit registers)&lt;br /&gt;
*# Input Registers (16-bit READ-ONLY registers)&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
In order to get started in using the Modbus features:&lt;br /&gt;
# Download the required files, according to your system's type:&lt;br /&gt;
## Required files for [[File:modbus_requiredFiles_x86.zip|modbus_X86.ZIP]].&lt;br /&gt;
## Required files for ARM systems.&lt;br /&gt;
# Using the ControlStudio File Manager, Upload the following files to your MC:&lt;br /&gt;
## mb_x86.O ''(for X86 Systems)'' / mb_armA9.O ''(for ARM Systems)''&lt;br /&gt;
## Modbus.lib&lt;br /&gt;
#* '''Notice:''' From now on, in our examples, we'll use the X86 configuration.&amp;lt;br&amp;gt;[[File:modbus;newAPI-upload.jpg|850px]]&lt;br /&gt;
# Load the files to memory, by typing (in the Terminal):&lt;br /&gt;
#:&amp;lt;pre&amp;gt;&lt;br /&gt;
#::Oload mb_x86.O&lt;br /&gt;
#::loadglobal Modbus.lib&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Initializing a Modbus Server ==&lt;br /&gt;
* To initialize the Modbus server address space, call:&lt;br /&gt;
*:&amp;lt;pre&amp;gt;&lt;br /&gt;
*::?init_multi_server([bits],[input_bits],[holding registers],[input_registers])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The function prints &amp;quot;success&amp;quot; and returns 0 on success, or return an error code on failure.&lt;br /&gt;
* &amp;lt;u&amp;gt;'''Notice:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
** This is '''NOT''' required when softMC does not run a modbus server.&lt;br /&gt;
** You can call this method only if no servers are running.&lt;br /&gt;
&lt;br /&gt;
== Server Components ==&lt;br /&gt;
=== Adding server components ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Creating a TCP server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_server_create([port],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens a TCP connection to the server on port [port] with deviceID [deviceID], and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
==== Creating an RTU server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_server_create([type],[port],[baudrate],[data bits],[stop bits],[parity],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens an RTU connection with the given parameters, and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&lt;br /&gt;
=== Stopping Server Components ===&lt;br /&gt;
==== Stopping a specific server component ====&lt;br /&gt;
You can stop a specific server component by passing its handle to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate server component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
==== Stopping all server components ====&lt;br /&gt;
You can stop all server components with a single call to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop_all&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function will:&lt;br /&gt;
* Stop and free all server components.&lt;br /&gt;
* Free the shared address space.&lt;br /&gt;
* Return 0 on success, -1 on failure.&lt;br /&gt;
&lt;br /&gt;
== Client Components ==&lt;br /&gt;
=== Adding client components ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Adding a TCP Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_client_create([ip],[port])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will opens a TCP connection to the client on the given ip and port, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
==== Adding an RTU Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_client_create([type],[port],[baudrate],[data bits],[stop bits],[parity])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will open an RTU connection to the client with the given parameters, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
=== Stopping client components ===&lt;br /&gt;
A specific client can be stopped by calling:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_client_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate client component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
&lt;br /&gt;
== Reset the Modbus System ==&lt;br /&gt;
Sometimes, a user may wish to stop all server and client components at once, and reset the Modbus system (for example, when a user want to initialize a different Modbus system). To do that, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_reset&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function:&lt;br /&gt;
* Stops all running servers and clients.&lt;br /&gt;
* Frees their memory.&lt;br /&gt;
* Frees the shared address space.&lt;br /&gt;
* Reset the handle counter.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
&lt;br /&gt;
== Reading and Writing ==&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
* Therefore, Servers and clients use different functions to read/write data from the address space.&lt;br /&gt;
=== Server Components ===&lt;br /&gt;
==== Reading ====&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_REG_LONG(…)&lt;br /&gt;
Val = MB_SERVER_READ_REG_SHORT(…)&lt;br /&gt;
Val = MB_SERVER_READ_REG_FLOAT(…)&lt;br /&gt;
Val = MB_SERVER_READ_REG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_READ_BIT([addr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_INREG_LONG(…)&lt;br /&gt;
Val = MB_SERVER_READ_INREG_SHORT(…)&lt;br /&gt;
Val = MB_SERVER_READ_INREG_FLOAT(…)&lt;br /&gt;
Val = MB_SERVER_READ_INREG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt; val = MB_SERVER_READ_INBIT([addr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== Writing ====&lt;br /&gt;
===== Writing to holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_LONG(…)&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_SHORT(…)&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_FLOAT(…)&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_BIT([addr],[value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_LONG(…)&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_SHORT(…)&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_FLOAT(…)&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_INBIT([addr],[value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Client Components ===&lt;br /&gt;
==== Reading ====&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_REG_LONG([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_SHORT(…)&lt;br /&gt;
Val = MB_CLIENT_READ_REG_FLOAT(…)&lt;br /&gt;
Val = MB_CLIENT_READ_REG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_BITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_LONG ([handle],[deviceID],[addr],[dest ptr]) &lt;br /&gt;
Val = MB_CLIENT_READ_INREG_SHORT(…)&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_FLOAT(…)&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_INBITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== Writing ====&lt;br /&gt;
===== Writing to Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_LONG([addr],[val ptr],[deviceID])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_SHORT(…)&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_FLOAT(…)&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_WRITE_BIT([addr],[val ptr],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== Reading and Writing Summary ===&lt;br /&gt;
[[File:modbus;newAPI-readwriteSummary.jpg|850px]]&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125859</id>
		<title>Modbus Communication API</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125859"/>
				<updated>2016-04-12T14:00:21Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: Modbus new API: Draft 3&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
=== Basic Overview ===&lt;br /&gt;
This describes how to set up Modbus communication for the softMC, and how to generate softMC scripts to handle Modbus communication.&lt;br /&gt;
It is assumed you are familiar with the principles of Modbus communication, although some of them will be described in this page.&lt;br /&gt;
It is also assumed your are familiar with the softMC, ControlStudio and MC-Basic programming.&lt;br /&gt;
&lt;br /&gt;
=== Modbus Communication Background ===&lt;br /&gt;
* A Motion Controller (MC) can act as a server (slave), a client (master) or both at the same time.&lt;br /&gt;
* Each MC connection (TCP/RTU) can be used either as a server component (if the connection is used by the MC’s server-side) or as a client component (if the connection is used by the MC’s client-side).&lt;br /&gt;
* Each component has its own parameters that defines it. &lt;br /&gt;
* When the MC acts as a server, all server components share the '''same''' memory address space, thus acting as 1 server with multiple connections.&lt;br /&gt;
* Each server (slave) on a Modbus network has its own deviceID, which is a number between 1 and 247.&lt;br /&gt;
&lt;br /&gt;
=== The Modbus server registers ===&lt;br /&gt;
* The types of registers in the Modbus Server address space include the following:&lt;br /&gt;
*# Bits (1-bit registers)&lt;br /&gt;
*# Input Bits (1-bit READ-ONLY registers)&lt;br /&gt;
*# Holding Registers (16-bit registers)&lt;br /&gt;
*# Input Registers (16-bit READ-ONLY registers)&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
In order to get started in using the Modbus features:&lt;br /&gt;
# Using the ControlStudio File Manager, Upload the following files to your MC:&lt;br /&gt;
## mb_x86.O ''(for X86 Systems)'' / mb_armA9.O ''(for ARM Systems)''&lt;br /&gt;
## Modbus.lib&lt;br /&gt;
#* '''Notice:''' From now on, in our examples, we'll use the X86 configuration.&amp;lt;br&amp;gt;[[File:modbus;newAPI-upload.jpg|850px]]&lt;br /&gt;
# Load the files to memory, by typing (in the Terminal):&lt;br /&gt;
#:&amp;lt;pre&amp;gt;&lt;br /&gt;
#::Oload mb_x86.O&lt;br /&gt;
#::loadglobal Modbus.lib&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Initializing a Modbus Server ==&lt;br /&gt;
* To initialize the Modbus server address space, call:&lt;br /&gt;
*:&amp;lt;pre&amp;gt;&lt;br /&gt;
*::?init_multi_server([bits],[input_bits],[holding registers],[input_registers])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The function prints &amp;quot;success&amp;quot; and returns 0 on success, or return an error code on failure.&lt;br /&gt;
* &amp;lt;u&amp;gt;'''Notice:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
** This is '''NOT''' required when softMC does not run a modbus server.&lt;br /&gt;
** You can call this method only if no servers are running.&lt;br /&gt;
&lt;br /&gt;
== Server Components ==&lt;br /&gt;
=== Adding server components ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Creating a TCP server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_server_create([port],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens a TCP connection to the server on port [port] with deviceID [deviceID], and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
==== Creating an RTU server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_server_create([type],[port],[baudrate],[data bits],[stop bits],[parity],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens an RTU connection with the given parameters, and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&lt;br /&gt;
=== Stopping Server Components ===&lt;br /&gt;
==== Stopping a specific server component ====&lt;br /&gt;
You can stop a specific server component by passing its handle to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate server component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
==== Stopping all server components ====&lt;br /&gt;
You can stop all server components with a single call to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop_all&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function will:&lt;br /&gt;
* Stop and free all server components.&lt;br /&gt;
* Free the shared address space.&lt;br /&gt;
* Return 0 on success, -1 on failure.&lt;br /&gt;
&lt;br /&gt;
== Client Components ==&lt;br /&gt;
=== Adding client components ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Adding a TCP Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_client_create([ip],[port])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will opens a TCP connection to the client on the given ip and port, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
==== Adding an RTU Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_client_create([type],[port],[baudrate],[data bits],[stop bits],[parity])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will open an RTU connection to the client with the given parameters, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
=== Stopping client components ===&lt;br /&gt;
A specific client can be stopped by calling:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_client_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate client component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
&lt;br /&gt;
== Reset the Modbus System ==&lt;br /&gt;
Sometimes, a user may wish to stop all server and client components at once, and reset the Modbus system (for example, when a user want to initialize a different Modbus system). To do that, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_reset&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function:&lt;br /&gt;
* Stops all running servers and clients.&lt;br /&gt;
* Frees their memory.&lt;br /&gt;
* Frees the shared address space.&lt;br /&gt;
* Reset the handle counter.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
&lt;br /&gt;
== Reading and Writing ==&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
* Therefore, Servers and clients use different functions to read/write data from the address space.&lt;br /&gt;
=== Server Components ===&lt;br /&gt;
==== Reading ====&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_REG_LONG(…)&lt;br /&gt;
Val = MB_SERVER_READ_REG_SHORT(…)&lt;br /&gt;
Val = MB_SERVER_READ_REG_FLOAT(…)&lt;br /&gt;
Val = MB_SERVER_READ_REG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_READ_BIT([addr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_INREG_LONG(…)&lt;br /&gt;
Val = MB_SERVER_READ_INREG_SHORT(…)&lt;br /&gt;
Val = MB_SERVER_READ_INREG_FLOAT(…)&lt;br /&gt;
Val = MB_SERVER_READ_INREG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt; val = MB_SERVER_READ_INBIT([addr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== Writing ====&lt;br /&gt;
===== Writing to holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_LONG(…)&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_SHORT(…)&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_FLOAT(…)&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_BIT([addr],[value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_LONG(…)&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_SHORT(…)&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_FLOAT(…)&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_INBIT([addr],[value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Client Components ===&lt;br /&gt;
==== Reading ====&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_REG_LONG([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_SHORT(…)&lt;br /&gt;
Val = MB_CLIENT_READ_REG_FLOAT(…)&lt;br /&gt;
Val = MB_CLIENT_READ_REG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_BITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_LONG ([handle],[deviceID],[addr],[dest ptr]) &lt;br /&gt;
Val = MB_CLIENT_READ_INREG_SHORT(…)&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_FLOAT(…)&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_INBITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== Writing ====&lt;br /&gt;
===== Writing to Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_LONG([addr],[val ptr],[deviceID])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_SHORT(…)&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_FLOAT(…)&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_WRITE_BIT([addr],[val ptr],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== Reading and Writing Summary ===&lt;br /&gt;
[[File:modbus;newAPI-readwriteSummary.jpg|850px]]&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125858</id>
		<title>Modbus Communication API</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125858"/>
				<updated>2016-04-12T13:59:41Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: Modbus new API: Draft 2&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
=== Basic Overview ===&lt;br /&gt;
This describes how to set up Modbus communication for the softMC, and how to generate softMC scripts to handle Modbus communication.&lt;br /&gt;
It is assumed you are familiar with the principles of Modbus communication, although some of them will be described in this page.&lt;br /&gt;
It is also assumed your are familiar with the softMC, ControlStudio and MC-Basic programming.&lt;br /&gt;
&lt;br /&gt;
=== Modbus Communication Background ===&lt;br /&gt;
* A Motion Controller (MC) can act as a server (slave), a client (master) or both at the same time.&lt;br /&gt;
* Each MC connection (TCP/RTU) can be used either as a server component (if the connection is used by the MC’s server-side) or as a client component (if the connection is used by the MC’s client-side).&lt;br /&gt;
* Each component has its own parameters that defines it. &lt;br /&gt;
* When the MC acts as a server, all server components share the '''same''' memory address space, thus acting as 1 server with multiple connections.&lt;br /&gt;
* Each server (slave) on a Modbus network has its own deviceID, which is a number between 1 and 247.&lt;br /&gt;
&lt;br /&gt;
=== The Modbus server registers ===&lt;br /&gt;
* The types of registers in the Modbus Server address space include the following:&lt;br /&gt;
*# Bits (1-bit registers)&lt;br /&gt;
*# Input Bits (1-bit READ-ONLY registers)&lt;br /&gt;
*# Holding Registers (16-bit registers)&lt;br /&gt;
*# Input Registers (16-bit READ-ONLY registers)&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
In order to get started in using the Modbus features:&lt;br /&gt;
# Using the ControlStudio File Manager, Upload the following files to your MC:&lt;br /&gt;
## mb_x86.O ''(for X86 Systems)'' / mb_armA9.O ''(for ARM Systems)''&lt;br /&gt;
## Modbus.lib&lt;br /&gt;
#* '''Notice:''' From now on, in our examples, we'll use the X86 configuration.&amp;lt;br&amp;gt;[[File:modbus;newAPI-upload.jpg|850px]]&lt;br /&gt;
# Load the files to memory, by typing (in the Terminal):&lt;br /&gt;
#:&amp;lt;pre&amp;gt;&lt;br /&gt;
#::Oload mb_x86.O&lt;br /&gt;
#::loadglobal Modbus.lib&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Initializing a Modbus Server ==&lt;br /&gt;
* To initialize the Modbus server address space, call:&lt;br /&gt;
*:&amp;lt;pre&amp;gt;&lt;br /&gt;
*::?init_multi_server([bits],[input_bits],[holding registers],[input_registers])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The function prints &amp;quot;success&amp;quot; and returns 0 on success, or return an error code on failure.&lt;br /&gt;
* &amp;lt;u&amp;gt;'''Notice:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
** This is '''NOT''' required when softMC does not run a modbus server.&lt;br /&gt;
** You can call this method only if no servers are running.&lt;br /&gt;
&lt;br /&gt;
== Server Components ==&lt;br /&gt;
=== Adding server components ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Creating a TCP server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_server_create([port],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens a TCP connection to the server on port [port] with deviceID [deviceID], and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
==== Creating an RTU server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_server_create([type],[port],[baudrate],[data bits],[stop bits],[parity],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens an RTU connection with the given parameters, and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&lt;br /&gt;
=== Stopping Server Components ===&lt;br /&gt;
==== Stopping a specific server component ====&lt;br /&gt;
You can stop a specific server component by passing its handle to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate server component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
==== Stopping all server components ====&lt;br /&gt;
You can stop all server components with a single call to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop_all&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function will:&lt;br /&gt;
* Stop and free all server components.&lt;br /&gt;
* Free the shared address space.&lt;br /&gt;
* Return 0 on success, -1 on failure.&lt;br /&gt;
&lt;br /&gt;
== Client Components ==&lt;br /&gt;
=== Adding client components ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Adding a TCP Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_client_create([ip],[port])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will opens a TCP connection to the client on the given ip and port, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
==== Adding an RTU Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_client_create([type],[port],[baudrate],[data bits],[stop bits],[parity])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will open an RTU connection to the client with the given parameters, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
=== Stopping client components ===&lt;br /&gt;
A specific client can be stopped by calling:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_client_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate client component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
&lt;br /&gt;
== Reset the Modbus System ==&lt;br /&gt;
Sometimes, a user may wish to stop all server and client components at once, and reset the Modbus system (for example, when a user want to initialize a different Modbus system). To do that, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_reset&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function:&lt;br /&gt;
* Stops all running servers and clients.&lt;br /&gt;
* Frees their memory.&lt;br /&gt;
* Frees the shared address space.&lt;br /&gt;
* Reset the handle counter.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
&lt;br /&gt;
== Reading and Writing ==&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
* Therefore, Servers and clients use different functions to read/write data from the address space.&lt;br /&gt;
=== Server Components ===&lt;br /&gt;
==== Reading ====&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_REG_LONG(…)&lt;br /&gt;
Val = MB_SERVER_READ_REG_SHORT(…)&lt;br /&gt;
Val = MB_SERVER_READ_REG_FLOAT(…)&lt;br /&gt;
Val = MB_SERVER_READ_REG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_READ_BIT([addr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_INREG_LONG(…)&lt;br /&gt;
Val = MB_SERVER_READ_INREG_SHORT(…)&lt;br /&gt;
Val = MB_SERVER_READ_INREG_FLOAT(…)&lt;br /&gt;
Val = MB_SERVER_READ_INREG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt; val = MB_SERVER_READ_INBIT([addr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== Writing ====&lt;br /&gt;
===== Writing to holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_LONG(…)&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_SHORT(…)&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_FLOAT(…)&lt;br /&gt;
Val = MB_SERVER_WRITE_REG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_BIT([addr],[value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_LONG(…)&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_SHORT(…)&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_FLOAT(…)&lt;br /&gt;
Val = MB_SERVER_WRITE_INREG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_WRITE_INBIT([addr],[value])&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Client Components ===&lt;br /&gt;
==== Reading ====&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_REG_LONG([handle],[deviceID],[addr],[dest ptr])&lt;br /&gt;
Val = MB_CLIENT_READ_REG_SHORT(…)&lt;br /&gt;
Val = MB_CLIENT_READ_REG_FLOAT(…)&lt;br /&gt;
Val = MB_CLIENT_READ_REG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_BITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_LONG ([handle],[deviceID],[addr],[dest ptr]) &lt;br /&gt;
Val = MB_CLIENT_READ_INREG_SHORT(…)&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_FLOAT(…)&lt;br /&gt;
Val = MB_CLIENT_READ_INREG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_READ_INBITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== Writing ====&lt;br /&gt;
===== Writing to Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_LONG([addr],[val ptr],[deviceID])&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_SHORT(…)&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_FLOAT(…)&lt;br /&gt;
Val = MB_CLIENT_WRITE_REG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Writing to Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_CLIENT_WRITE_BIT([addr],[val ptr],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== Reading and Writing Summary ===&lt;br /&gt;
[[File:modbus;newAPI-readwriteSummary.jpg|850]]&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125856</id>
		<title>Modbus Communication API</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Modbus_Communication_API&amp;diff=125856"/>
				<updated>2016-04-12T13:49:33Z</updated>
		
		<summary type="html">&lt;p&gt;Omri: Created page - Draft: 1&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
=== Basic Overview ===&lt;br /&gt;
This describes how to set up Modbus communication for the softMC, and how to generate softMC scripts to handle Modbus communication.&lt;br /&gt;
It is assumed you are familiar with the principles of Modbus communication, although some of them will be described in this page.&lt;br /&gt;
It is also assumed your are familiar with the softMC, ControlStudio and MC-Basic programming.&lt;br /&gt;
&lt;br /&gt;
=== Modbus Communication Background ===&lt;br /&gt;
* A Motion Controller (MC) can act as a server (slave), a client (master) or both at the same time.&lt;br /&gt;
* Each MC connection (TCP/RTU) can be used either as a server component (if the connection is used by the MC’s server-side) or as a client component (if the connection is used by the MC’s client-side).&lt;br /&gt;
* Each component has its own parameters that defines it. &lt;br /&gt;
* When the MC acts as a server, all server components share the '''same''' memory address space, thus acting as 1 server with multiple connections.&lt;br /&gt;
* Each server (slave) on a Modbus network has its own deviceID, which is a number between 1 and 247.&lt;br /&gt;
&lt;br /&gt;
=== The Modbus server registers ===&lt;br /&gt;
* The types of registers in the Modbus Server address space include the following:&lt;br /&gt;
*# Bits (1-bit registers)&lt;br /&gt;
*# Input Bits (1-bit READ-ONLY registers)&lt;br /&gt;
*# Holding Registers (16-bit registers)&lt;br /&gt;
*# Input Registers (16-bit READ-ONLY registers)&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
In order to get started in using the Modbus features:&lt;br /&gt;
# Using the ControlStudio File Manager, Upload the following files to your MC:&lt;br /&gt;
## mb_x86.O ''(for X86 Systems)'' / mb_armA9.O ''(for ARM Systems)''&lt;br /&gt;
## Modbus.lib&lt;br /&gt;
#* '''Notice:''' From now on, in our examples, we'll use the X86 configuration.&amp;lt;br&amp;gt;[[File:modbus;newAPI-upload.jpg|850px]]&lt;br /&gt;
# Load the files to memory, by typing (in the Terminal):&lt;br /&gt;
#:&amp;lt;pre&amp;gt;&lt;br /&gt;
#::Oload mb_x86.O&lt;br /&gt;
#::loadglobal Modbus.lib&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Initializing a Modbus Server ==&lt;br /&gt;
* To initialize the Modbus server address space, call:&lt;br /&gt;
*:&amp;lt;pre&amp;gt;&lt;br /&gt;
*::?init_multi_server([bits],[input_bits],[holding registers],[input_registers])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The function prints &amp;quot;success&amp;quot; and returns 0 on success, or return an error code on failure.&lt;br /&gt;
* &amp;lt;u&amp;gt;'''Notice:'''&amp;lt;/u&amp;gt;&lt;br /&gt;
** This is '''NOT''' required when softMC does not run a modbus server.&lt;br /&gt;
** You can call this method only if no servers are running.&lt;br /&gt;
&lt;br /&gt;
== Server Components ==&lt;br /&gt;
=== Adding server components ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Creating a TCP server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_server_create([port],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens a TCP connection to the server on port [port] with deviceID [deviceID], and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
==== Creating an RTU server component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_server_create([type],[port],[baudrate],[data bits],[stop bits],[parity],[deviceID])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This opens an RTU connection with the given parameters, and starts the created server immediately.&lt;br /&gt;
* Returns a handle on success, or an error code on failure.&lt;br /&gt;
&lt;br /&gt;
=== Stopping Server Components ===&lt;br /&gt;
==== Stopping a specific server component ====&lt;br /&gt;
You can stop a specific server component by passing its handle to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate server component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
==== Stopping all server components ====&lt;br /&gt;
You can stop all server components with a single call to:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_server_stop_all&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function will:&lt;br /&gt;
* Stop and free all server components.&lt;br /&gt;
* Free the shared address space.&lt;br /&gt;
* Return 0 on success, -1 on failure.&lt;br /&gt;
&lt;br /&gt;
== Client Components ==&lt;br /&gt;
=== Adding client components ===&lt;br /&gt;
* Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use).&lt;br /&gt;
* It is best to keep this handles in variables inside your program.&lt;br /&gt;
==== Adding a TCP Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_tcp_client_create([ip],[port])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will opens a TCP connection to the client on the given ip and port, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
==== Adding an RTU Client component ====&lt;br /&gt;
&amp;lt;pre&amp;gt;handle = mb_rtu_client_create([type],[port],[baudrate],[data bits],[stop bits],[parity])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* This will open an RTU connection to the client with the given parameters, and start the client immediately.&lt;br /&gt;
* Returns a handle on success, -1 on failure.&lt;br /&gt;
=== Stopping client components ===&lt;br /&gt;
A specific client can be stopped by calling:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_client_stop([handle])&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Given a handle, this will stop and free the memory of the appropriate client component.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
&lt;br /&gt;
== Reset the Modbus System ==&lt;br /&gt;
Sometimes, a user may wish to stop all server and client components at once, and reset the Modbus system (for example, when a user want to initialize a different Modbus system). To do that, call:&lt;br /&gt;
&amp;lt;pre&amp;gt;result = mb_reset&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function:&lt;br /&gt;
* Stops all running servers and clients.&lt;br /&gt;
* Frees their memory.&lt;br /&gt;
* Frees the shared address space.&lt;br /&gt;
* Reset the handle counter.&lt;br /&gt;
* Returns 0 on success, -1 on failure.&lt;br /&gt;
&lt;br /&gt;
== Reading and Writing ==&lt;br /&gt;
* Servers can read and write their own address space.&lt;br /&gt;
* Clients can read and write a remote server’s address space.&lt;br /&gt;
* Therefore, Servers and clients use different functions to read/write data from the address space.&lt;br /&gt;
=== Server Components ===&lt;br /&gt;
==== Reading ====&lt;br /&gt;
===== Reading from Holding registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_REG_LONG(…)&lt;br /&gt;
Val = MB_SERVER_READ_REG_SHORT(…)&lt;br /&gt;
Val = MB_SERVER_READ_REG_FLOAT(…)&lt;br /&gt;
Val = MB_SERVER_READ_REG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;val = MB_SERVER_READ_BIT([addr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Val = MB_SERVER_READ_INREG_LONG(…)&lt;br /&gt;
Val = MB_SERVER_READ_INREG_SHORT(…)&lt;br /&gt;
Val = MB_SERVER_READ_INREG_FLOAT(…)&lt;br /&gt;
Val = MB_SERVER_READ_INREG_DOUBLE(…)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===== Reading from Input Bits registers =====&lt;br /&gt;
&amp;lt;pre&amp;gt; val = MB_SERVER_READ_INBIT([addr])&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== Writing ====&lt;/div&gt;</summary>
		<author><name>Omri</name></author>	</entry>

	</feed>