Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/main/java/modbuspal/automation/AutomationPanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -279,20 +279,20 @@ public void windowDeactivated(WindowEvent e)
{
}

@Override
public void automationHasEnded(Automation source)
{
//playToggleButton.setText("Start");
playToggleButton.setSelected(false);
setBackground(false);
automation.stop();
}

@Override
public void automationHasStarted(Automation aThis)
{
//playToggleButton.setText("Stop");
playToggleButton.setSelected(true);
setBackground(true);
automation.start();
}

@Override
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/modbuspal/help/modbus-slaves-add-tcp.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ <h2>Regular MODBUS TCP addressing</h2>
<dt>192.168.10.100</dt>
<dd>Create just one slave that will only reply to requests received
on the network interface whose IP address is 192.168.10.100.</dd>
<dt>10.23.6.2, 10.23.6.8</dt>
<dt>10.23.6.2, 10.23.6.8 (not implemented)</dt>
<dd>Create 2 slaves that will reply to requests received
on network interfaces whose IP addresses are 10.23.6.2,
and 10.23.6.8.</dd>
<dt>10.23.6.2-10.23.6.8</dt>
<dt>10.23.6.2-10.23.6.8 (not implemented)</dt>
<dd>Create 9 slaves that will reply to requests received
on network interfaces whose IP addresses are 10.23.6.2,
10.23.6.3, ..., 10.23.6.7 and 10.23.6.8.</dd>
Expand All @@ -53,10 +53,10 @@ <h2>Multiple slaves sharing the same IP address</h2>
following patterns:</p>

<dl>
<dt>127.0.0.1(17)</dt>
<dt>127.0.0.1(17) (not implemented)</dt>
<dd>Create juste one slave at IP address 127.0.0.1 (listen on all
network interfaces) and slave number 17.</dd>
<dt>192.168.10.100(10-15)</dt>
<dt>192.168.10.100(10-15) (not implemented)</dt>
<dd>Create 6 slaves sharing the same IP address (local network interface
192.168.10.100). Each slave is assigned a slave number ranging from 10
to 15 included.</dd>
Expand Down
78 changes: 69 additions & 9 deletions src/main/java/modbuspal/main/ModbusPalGui.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,56 @@ public class ModbusPalGui
{

private static final HashMap<Object,ModbusPalPane> instances = new HashMap<Object,ModbusPalPane>();
public static final int MAX_PORT_NUMBER = 65536;

private static String initialLoadFilePath = "";
private static int initialPortNumber = -1;

/**
* This method will display the help message to the console and exit the software.
*/
public static void displayHelpMessage()
{
System.out.println( "This software launches the Modbus Slave simulation program: ModbusPal." );
System.out.println( "Arguments in this program include:" );
System.out.println(
"-install (optional): This flag is to tell program to install itself if it is not installed." );
System.out.println( "-loadFile (optional): This argument is to load a project file at launch. Example usage:" );
System.out.println( "\t-loadFile=\"your/absolute/path/name/example.xmpp\"" );
System.out.println( "Make sure the path name is the absolute path, or you will get an error message back." );
System.out.println(
"-portNumber (optional): This argument sets the initial TCP/IP port number to a number between 0 and "
+ MAX_PORT_NUMBER + ". Example usage:" );
System.out.println( "\t-portNumber=1234" );
System.out.println(
"Make sure the port you choose is not a reserved port number or in use. If a number is not given, an error message will be returned." );
System.out.println(
"If this argument is not given or an invalid port value is given, then the port number will be set to "
+ ModbusPalPane.DEFAULT_PORT_TEXT + ", or the value in the initial project file loaded." );
System.out.println( "-help (optional): Displays the help message." );
System.exit( 0 );
}

/**
* This method gets the initial load file path to load specified by the user in the command line arguments.
* @return {String} The absolute initial load file path. Returns "" if no argument was given.
*/
public static String getInitialLoadFilePath()
{
return initialLoadFilePath;
}

/**
* This method gets the initial port number to load specified by the user in the command line arguments.
* @return {int} The initial port number for TCP/IP connections. Returns -1 if no port number was given.
*/
public static int getInitialPortNumber()
{
return initialPortNumber;
}

/**
* this method will try to change the Look and Feel of the applcation,
* this method will try to change the Look and Feel of the application,
* using the system l&f. It means that the application will get the Windows
* l&f on Windows, etc...
*/
Expand All @@ -55,31 +102,48 @@ public static void install()
}

/**
* @param args the command line arguments
* @param {String[]} args The command line arguments
*/
public static void main(String args[])
{
boolean runInstall = false;
boolean runGui = true;
String installArgFlag = "-install";
String loadFileArgFlag = "-loadFile=";
String portNumberArgFlag = "-portNumber=";

if( args.length>=1 )
if( args.length >= 1 )
{
for(String arg:args)
{
if( arg.compareToIgnoreCase("-install")==0 )
if( arg.startsWith( installArgFlag ) )
{
runInstall = true;
runGui = false;
}
else if( arg.startsWith( loadFileArgFlag ) )
{
initialLoadFilePath = arg.substring( arg.lastIndexOf( loadFileArgFlag ) + loadFileArgFlag.length() );
}
else if( arg.startsWith( portNumberArgFlag ) )
{
String portNumberString = arg.substring( arg.lastIndexOf( portNumberArgFlag ) + portNumberArgFlag.length() );
initialPortNumber = Integer.valueOf( portNumberString ).intValue();
}
else
{
displayHelpMessage();
}
}
}

if( runInstall == true )
{
install();
}

if( runGui == true )
{
{
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
Expand All @@ -88,12 +152,8 @@ public void run() {
}
});
}


}



/**
* A JinternalFrame that contains a ModbusPalPane.
*/
Expand Down
79 changes: 73 additions & 6 deletions src/main/java/modbuspal/main/ModbusPalPane.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ public class ModbusPalPane

/** Base registry key for the configuration of the application. */
public static final String BASE_REGISTRY_KEY = "modbuspal";

/** Default TCP/IP port in a string to be loaded into the GUI. */
public static final String DEFAULT_PORT_TEXT = "502";

private ArrayList<ModbusPalProjectListener> listeners = new ArrayList<ModbusPalProjectListener>();

Expand Down Expand Up @@ -284,12 +287,66 @@ public ModbusPalPane(boolean useInternalConsole)
installRecorder();
installCommPorts();
//installScriptEngine();

setProject( new ModbusPalProject() );


String initialLoadProjectFilePath = ModbusPalGui.getInitialLoadFilePath();
ModbusPalProject project = null;
File fileCheck = new File( initialLoadProjectFilePath );
if( initialLoadProjectFilePath != "" && fileCheck.isFile() )
{
try
{
System.out.println( "Loading the project file: " + initialLoadProjectFilePath );
project = loadProject( initialLoadProjectFilePath );

// Need to initialize the port number after loading the project, and not every time we load or set a project because if the
// user wants to load another file, we don't want to clobber it with the command line initial port number.
// This call must be called before the runToggleButton.doClick() method is invoked.
initializeInitialPortNumber( project );

// Now that we have loaded a project from an initial project file, it is time to start all of the
// automations that have been loaded from the project file.
Component panels[] = automationsListPanel.getComponents();
for( int panelIndex = 0; panelIndex < panels.length; panelIndex++ )
{
if( panels[ panelIndex ] instanceof AutomationPanel )
{
AutomationPanel panel = ( AutomationPanel ) panels[ panelIndex ];
panel.automationHasStarted( null );
}
}
runToggleButton.doClick();
}
catch( Exception exception )
{
System.out.println(
"Could not load the initial project file path \"" + initialLoadProjectFilePath + "\"." );
System.out.println( "Check the path you inputted into the command line arguments." );
}
}
else
{
project = new ModbusPalProject();
setProject( project );
// Initializing the initial port number in case a port number was given, but no initial load file was given in the
// command line arguments.
initializeInitialPortNumber( project );
}
}


/**
* Initialize the initial port number given from the command line arguments if there was a valid number given in the command line.
* @param project The current ModbusPal project that is being used.
*/
private void initializeInitialPortNumber( ModbusPalProject project )
{
int initialPortNumber = ModbusPalGui.getInitialPortNumber();
if( initialPortNumber >= 0 && initialPortNumber <= ModbusPalGui.MAX_PORT_NUMBER )
{
project.linkTcpipPort= Integer.toString( initialPortNumber );
}
portTextField.setText( project.linkTcpipPort );
}

private void installConsole()
{
try {
Expand Down Expand Up @@ -501,8 +558,19 @@ private void initComponents() {
gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 2);
tcpIpSettingsPanel.add(jLabel1, gridBagConstraints);

portTextField.setText("502");
int initialPortNumber = ModbusPalGui.getInitialPortNumber();
if( initialPortNumber >= 0 && initialPortNumber <= ModbusPalGui.MAX_PORT_NUMBER )
{
System.out.println( "Loading the initial TCP/IP port number: " + initialPortNumber );
portTextField.setText( Integer.toString( initialPortNumber ) );
}
else
{
System.out.println( "Could not load an initial port number. Loading default port number." );
portTextField.setText( DEFAULT_PORT_TEXT );
}
portTextField.setPreferredSize(new java.awt.Dimension(40, 20));

gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.insets = new java.awt.Insets(5, 2, 5, 5);
tcpIpSettingsPanel.add(portTextField, gridBagConstraints);
Expand Down Expand Up @@ -1314,7 +1382,6 @@ private void loadButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FI


private void addAutomationButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addAutomationButtonActionPerformed

String name = Automation.DEFAULT_NAME + " #" + String.valueOf( modbusPalProject.idGenerator.createID() );
Automation automation = new Automation( name );
modbusPalProject.addAutomation(automation);
Expand Down
63 changes: 47 additions & 16 deletions src/main/java/modbuspal/main/ModbusPalProject.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
Expand Down Expand Up @@ -109,8 +111,6 @@ public ModbusPalProject()
generatorFactory.add( new modbuspal.generator.linear.LinearGenerator() );
generatorFactory.add( new modbuspal.generator.random.RandomGenerator() );
generatorFactory.add( new modbuspal.generator.sine.SineGenerator() );


}

private ModbusPalProject(Document doc, File source)
Expand Down Expand Up @@ -411,8 +411,11 @@ private void loadBindings(Document doc, ModbusSlave slave)
/**
* This method will examine the content of a "<binding>" tag in order to
* parse the attributes it contains, and also the child tags that may exist.
* @param node reference on the Node that represents a "<binding>" tag in the
* @param node Reference on the Node that represents a "<binding>" tag in the
* project.
* @param slave Reference to a ModbusSlave to bind the automation to. If the passed in
* slave is "null", it will retrieve the ModbusSlave that is the parent of this register or coil
* node the automation is being bound to.
* @throws java.lang.InstantiationException
* @throws java.lang.IllegalAccessException
*/
Expand Down Expand Up @@ -443,21 +446,36 @@ private void loadBinding(Node node, ModbusSlave slave)
Node orderNode = attributes.getNamedItem("order");
String orderValue = orderNode.getNodeValue();
int wordOrder = Integer.parseInt(orderValue);

boolean isRegister = true;

// retrieve the register that is the parent of this node
Node parentRegister = XMLTools.findParent(node,"register");
String parentAddress = XMLTools.getAttribute(ModbusPalXML.XML_ADDRESS_ATTRIBUTE, parentRegister);
int registerAddress = Integer.parseInt( parentAddress );
Node parentNode = XMLTools.findParent(node,"register");
String parentAddress = XMLTools.getAttribute(ModbusPalXML.XML_ADDRESS_ATTRIBUTE, parentNode);

int ioAddress = 0;
if( parentAddress == null )
{
isRegister = false;
parentNode = XMLTools.findParent(node, "coil");
parentAddress = XMLTools.getAttribute(ModbusPalXML.XML_ADDRESS_ATTRIBUTE, parentNode);
if( parentAddress == null )
{
System.out.println( "Cannot bind automation. Parent is neither a register or coil!" );
return;
}
}

ioAddress = Integer.parseInt( parentAddress );

// Instanciate the binding:
// Instantiate the binding:
Binding binding = bindingFactory.newInstance(className);
binding.setup(automation, wordOrder);


if( slave==null)
if( slave==null )
{
// retrieve the slave that is the parent of this register
Node parentSlave = XMLTools.findParent(parentRegister, "slave");
Node parentSlave = XMLTools.findParent(parentNode, "slave");

String slaveAddress = XMLTools.getAttribute(ModbusPalXML.XML_SLAVE_ID2_ATTRIBUTE, parentSlave);
if( slaveAddress!= null )
Expand All @@ -467,15 +485,28 @@ private void loadBinding(Node node, ModbusSlave slave)
}
else
{
slaveAddress = XMLTools.getAttribute(ModbusPalXML.XML_SLAVE_ID_ATTRIBUTE, parentSlave);
int slaveId = Integer.parseInt(slaveAddress);
ModbusSlaveAddress msa = new ModbusSlaveAddress(slaveId);
slave = getModbusSlave(msa);
slaveAddress = XMLTools.getAttribute(ModbusPalXML.XML_SLAVE_ID_ATTRIBUTE, parentSlave);
try
{
ModbusSlaveAddress msa = new ModbusSlaveAddress( InetAddress.getByName( slaveAddress ) );
slave = getModbusSlave(msa);
}
catch (UnknownHostException exception)
{
System.out.println( "Unable to get Modbus Slave IP address from slave address: " + slaveAddress );
}
}
}

// bind the register and the automation
slave.getHoldingRegisters().bind(registerAddress, binding);
// bind the registers, coils, and the automation
if( isRegister )
{
slave.getHoldingRegisters().bind(ioAddress, binding);
}
else
{
slave.getCoils().bind(ioAddress, binding);
}
}


Expand Down
Loading