Group Details Private

administrators

Member List

RE: Custom serial protocol parsing and Automation

Hello Ivan,

capture serial communication with up to 3.3mbps

3.3 Mbps is beyond the maximum baud rate supported by Serial Tap. Baud rates <= 1 Mbps are guaranteed to be reliably captured; ~2 Mbps could work in theory, but errors are possible, and I think 3 Mbps would be outright rejected by the UART controller we use in Serial Tap.

add custom protocol parsing logic

This is possible; IO Ninja supports so called "layer" plugins that can transform original logs and add decoded protocol messages. See the Modbus Analyzer for an example of such layer plugin (it's open-source and located at /scripts/plugins/Modbus/)

perform time event measurement

Events are timestamped on the PC side -- the Serial Tap reports raw bytes and status line changes, IO Ninja adds timestamps and writes them to log.

be controlled by Python with ability to get parsed data, set time markers ad get time for each events

If you need to implement custom processing in Python, you can use ioninja-hwc (https://ioninja.com/features/hardware-client.html#cli) -- capture Serial Tap events from the command line and redirect those to a file or stdout; then implement whichever custom logic you need in Python.

posted in General Discussion
RE: Help parsing modbus correctly

Unfortunately, I can't see the wiring or the mode switch position from the photo. However, on the screenshot, all the data is RX (green). Most likely, it's the usual two-wire RS485 (half-duplex), but the Modbus Analyzer is configured for full-duplex (TX Master, RX Slave) -- which is causing those parsing errors.

We have a KB article on configuring Modbus for half-duplex links:
https://ioninja.com/doc/kb/modbus_half_duplex.html

Please let me know if this works for you.

posted in Support & Troubleshooting
RE: Modbus Reply Script

@gary-biagioni

I guess the above just goes into the scripting panes. One problem I have is how do I debug the program I write. Not sure how to be able to do that, for example, look at the contents of a variable.

You can use the good old printf debugging.

import "hexEncoding.jnc"

void main() {
	int a = 10;
	char s[] = "abcdef";
	char buf[] = 0x"01 02 03 04 05";
	
	string_t msg = $"a: %1/0x%(1;02x) s: %2 buf: %3"(a, s, encodeHexString(buf, sizeof(buf), ' '));
	// string_t msg = $"a: %d/0x%02x s: %s buf: %s"(a, a, s, encodeHexString(buf, sizeof(buf), ' ')); // same
	printf($"This will go to the system log: $msg\n");
	g_logWriter.write(log.StdRecordCode.PlainText, $"This will go to the normal log: $msg\n");
}

The system log can be viewed via Menu->View->System Log

posted in Support & Troubleshooting
RE: Modbus Reply Script

@gary-biagioni

That said above this looks super interesting to handle responses

https://ioninja.com/doc/developer-manual/tutorial-ias-server.html

At the moment of writing this tutoiral, onLogRecord was the only approach to reading incoming data bytes.

Of course, it still works, but we now have receive and receiveAll functions. I believe they are much easier to use.

posted in Support & Troubleshooting
RE: Modbus Reply Script

Hi Gary,

Sorry, the API documentation is currently just a placeholder; it's auto-generated from the script sources (you can also check those sources directly at $IONINA_DIR/scripts/api/). However, we also have some scripting tutorials in the Developer Manual (https://ioninja.com/doc/developer-manual/tutorials.html) -- those should be helpful.

For the in-app-scripting inside the "Script" pane, all the available function declarations can be found at scripts/api/ias.jnc

To answer your question, the receive and receiveAll functions are used to collect raw data bytes that appear in your log as the RX (incoming) stream.

receive is the most basic method; it accepts the buffer and timeout and works as such:

  1. if there are any incoming data bytes at the moment of call -- those data bytes are returned immediately;
  1. otherwise, receive waits for incoming data for at most timeout milliseconds before returning. If a chunk of incoming data arrives before timeout expires, it will be returned as soon as received. If timeout expires and no data arrives -- 0 will be returned. timeout defaults to -1 which is equivalent to infinite wait for data (receive will not return until at least one byte of incoming data arrives).

receiveAll is a helper wrapper around receive and is used to fill the supplied buffer entirely (you can see its implementation in ias.jnc). This is convenient when your script needs to fill a fixed-size packet header before proceeding. If a packet arrives in chunks, the receiveAll will wait until the buffer is complete and only then return. The overloaded version of receiveAll with the timeout parameter will attempt to fill the buffer entirely -- but will bail after timeout milliseconds.

Hope this helps; feel free to ask more.

posted in Support & Troubleshooting
RE: How do I detect the method of IPC in the pipe monitor?

Are those little icons on the snapshot indicates the type of connection besides it is a pipe? (Socket, shared memory, message queue)

Pipe Monitor shows named and anonymous pipes only.

Anonymous pipe opens will be marked as (unnamed). If you run a Win32 code to create anonymous pipes such as:

	HANDLE hReadPipe;
	HANDLE hWritePipe;
	dword_t actualSize;
	char data[] = "abcdefghi";
	char buffer[1024];

	::CreatePipe(&hReadPipe, &hWritePipe, NULL, 0);

	::WriteFile(hWritePipe, data, sizeof(data), &actualSize, NULL);
	::ReadFile(hReadPipe, buffer, sizeof(buffer), &actualSize, NULL);

	::CloseHandle(hReadPipe);
	::CloseHandle(hWritePipe);

You should see something like:
86d9aea6-baa1-418e-a3c5-6f7b0e6800e3-image.png

posted in General Discussion
RE: How do I detect the method of IPC in the pipe monitor?

The screenshot failed to upload; could you try again, please?

Regarding the IPC method, well, the Pipe Monitor shows communications over named and anonymous pipes. To see if a particular read or write is issued over an anonymous or named pipe (and the name of the pipe), you have to follow the log up all the way to the pipe open operation for this particular file ID; there you'll see the file name and the role (client or server).

posted in General Discussion
RE: Does SerialTap support RS422?

Yes, you can use Serial Tap to monitor RS422 communications. Use the RS485 portion of the terminal block to connect your TX+/- and RX+/- lines.

posted in General Discussion
RE: MODBUS write multiple register script

Hello,

ModbusRtuWritePacket is from the legacy Modbus packet template library; it doesn't support multiple values per packet. The new Modbus plugin uses structures defined in scripts/protocols/io_Modbus.jnc. If you need to do it programmatically, just assemble your packet structure from necessary chunks (ADU hdr, PDU hdr, function-specific params, values, CRC). Important -- be sure to add pragma(Alignment, 1) as to avoid unintended struct paddings!

After the packet structure is defined, fill in the fields and calculate the checksum. Modbus RTU checksum is CRC16 ANSI (with init 0xffff) of the whole frame excluding the checksum itself.

The full script listing is below:

import "io_Modbus.jnc"

void main() {
	enum {
		DeviceAddress   = 1,
		RegisterAddress = 0xA000,
		RegisterCount   = 2,
	}

	pragma(Alignment, 1)
	struct MyPacket:
		io.ModbusRtuAduHdr,
		io.ModbusPduHdr,
		io.ModbusWriteMultipleParams {

		bigendian uint16_t m_registers[RegisterCount];
		uint16_t m_crc;
	}

	MyPacket packet;
	packet.m_deviceAddress = DeviceAddress;
	packet.m_func = io.ModbusFunc.WriteMultipleRegisters;
	packet.m_address = RegisterAddress;
	packet.m_count = RegisterCount;
	packet.m_size = sizeof(packet.m_registers);
	packet.m_registers[0] = 123;
	packet.m_registers[1] = 456;
	// ...
	packet.m_crc = crc16_ansi(packet, offsetof(packet.m_crc), -1);

	transmit(packet, sizeof(packet));
}
posted in Support & Troubleshooting
RE: ioninja-hwc: fragment captures

Hello Jose,

Sure, no rush with the feedback -- please take your time.

And thank you so much! Wishing you a Merry Christmas and a Happy New Year as well! Enjoy your winter holidays!

posted in General Discussion