# Gateway Serial Module writeBytes hex

**URL:** <https://forum.inductiveautomation.com/t/gateway-serial-module-writebytes-hex/75298>\
**Category:** Ignition\
**Tags:** scripting\
**Created:** [June 20, 2023, 6:35pm UTC](https://forum.inductiveautomation.com/t/gateway-serial-module-writebytes-hex/75298 "2023-06-20T18:35:11Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Tom\_Grotenhuis](https://avatars.discourse-cdn.com/v4/letter/t/6a8cbe/32.png) [@Tom\_Grotenhuis](https://forum.inductiveautomation.com/u/Tom_Grotenhuis)\
**Post date:** [June 20, 2023, 6:35pm UTC](https://forum.inductiveautomation.com/t/gateway-serial-module-writebytes-hex/75298/1 "2023-06-20T18:35:11Z")

</div>

Hi All,

I've been using my best googling skills into getting this working but it evades me. I am trying to open a serial port, write a handful of bytes in hex, listen to the port, then close the port.

I cannot get past writing the bytes. My best guess is I'm having trouble satisfying the java bytearray requirements. This is the code I'm using in the interpreter.

```auto
system.serial.configureSerialPort(\
	port="COM7",\
	bitRate=system.serial.BIT_RATE_9600,\
	dataBits=system.serial.DATA_BITS_8,\
	handshake=system.serial.HANDSHAKE_NONE,\
	hardwareFlowControl=False,\
	parity=system.serial.PARITY_NONE,\
	stopBits=system.serial.STOP_BITS_1)
	
system.serial.closeSerialPort("COM7")

system.serial.openSerialPort("COM7")

system.serial.writeBytes("COM7","\xCA\x00\x01\x70\x00\x8E")

system.serial.closeSerialPort("COM7")

```

Firing the script returns an angry traceback that the serial module trial is expired. Restarting the trial via gateway webpage and relaunching the designer have no effect. Not sure what to do here...

```auto
Java Traceback:
Traceback (most recent call last):
  File "<input>", line 14, in <module>
	at com.inductiveautomation.ignition.modules.serial.scripting.SerialScriptModule.checkTrialExpired(SerialScriptModule.java:154)

	at com.inductiveautomation.ignition.modules.serial.scripting.SerialScriptModule.writeBytes(SerialScriptModule.java:616)

	at com.inductiveautomation.ignition.modules.serial.scripting.SerialScriptModule.writeBytes(SerialScriptModule.java:599)

	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)

	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)

	at java.base/java.lang.reflect.Method.invoke(Unknown Source)

com.inductiveautomation.ignition.modules.serial.scripting.TrialExpiredException: com.inductiveautomation.ignition.modules.serial.scripting.TrialExpiredException: Serial module trial period has expired.

	at org.python.core.Py.JavaError(Py.java:547)

	at org.python.core.Py.JavaError(Py.java:538)

	at org.python.core.PyReflectedFunction. __call__ (PyReflectedFunction.java:192)

	at org.python.core.PyReflectedFunction. __call__ (PyReflectedFunction.java:208)

	at org.python.core.PyObject. __call__ (PyObject.java:477)

	at org.python.core.PyObject. __call__ (PyObject.java:481)

	at org.python.pycode._pyx6.f$0(<input>:16)

	at org.python.pycode._pyx6.call_function(<input>)

	at org.python.core.PyTableCode.call(PyTableCode.java:173)

	at org.python.core.PyCode.call(PyCode.java:18)

	at org.python.core.Py.runCode(Py.java:1687)

	at org.python.core.Py.exec(Py.java:1731)

	at org.python.util.PythonInterpreter.exec(PythonInterpreter.java:277)

	at org.python.util.InteractiveInterpreter.runcode(InteractiveInterpreter.java:130)

	at com.inductiveautomation.ignition.designer.gui.tools.jythonconsole.JythonConsole$ConsoleWorker.doInBackground(JythonConsole.java:611)

	at com.inductiveautomation.ignition.designer.gui.tools.jythonconsole.JythonConsole$ConsoleWorker.doInBackground(JythonConsole.java:599)

	at java.desktop/javax.swing.SwingWorker$1.call(Unknown Source)

	at java.base/java.util.concurrent.FutureTask.run(Unknown Source)

	at java.desktop/javax.swing.SwingWorker.run(Unknown Source)

	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)

	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)

	at java.base/java.lang.Thread.run(Unknown Source)

Caused by: com.inductiveautomation.ignition.modules.serial.scripting.TrialExpiredException: Serial module trial period has expired.

	at com.inductiveautomation.ignition.modules.serial.scripting.SerialScriptModule.checkTrialExpired(SerialScriptModule.java:154)

	at com.inductiveautomation.ignition.modules.serial.scripting.SerialScriptModule.writeBytes(SerialScriptModule.java:616)

	at com.inductiveautomation.ignition.modules.serial.scripting.SerialScriptModule.writeBytes(SerialScriptModule.java:599)

	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)

	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)

	at java.base/java.lang.reflect.Method.invoke(Unknown Source)

	at org.python.core.PyReflectedFunction. __call__ (PyReflectedFunction.java:190)

	... 19 more

Traceback (most recent call last):
  File "<input>", line 14, in <module>
	at com.inductiveautomation.ignition.modules.serial.scripting.SerialScriptModule.checkTrialExpired(SerialScriptModule.java:154)

	at com.inductiveautomation.ignition.modules.serial.scripting.SerialScriptModule.writeBytes(SerialScriptModule.java:616)

	at com.inductiveautomation.ignition.modules.serial.scripting.SerialScriptModule.writeBytes(SerialScriptModule.java:599)

	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)

	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)

	at java.base/java.lang.reflect.Method.invoke(Unknown Source)

com.inductiveautomation.ignition.modules.serial.scripting.TrialExpiredException: com.inductiveautomation.ignition.modules.serial.scripting.TrialExpiredException: Serial module trial period has expired.

```

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [June 20, 2023, 6:45pm UTC](https://forum.inductiveautomation.com/t/gateway-serial-module-writebytes-hex/75298/2 "2023-06-20T18:45:00Z")

</div>

> [@Tom\_Grotenhuis](#):
>
> `"\xCA\x00\x01\x70\x00\x8E"`

It's because this isn't a byte array. It is a jython string whose codepoints match the bytes you want to send. You need to construct your byte array with [jython's jarray module](https://javadoc.io/doc/org.python/jython-standalone/2.7.1/org/python/modules/jarray.html).

(Beware: java byte arrays have _signed_ 8-bit values.)

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [June 20, 2023, 6:46pm UTC](https://forum.inductiveautomation.com/t/gateway-serial-module-writebytes-hex/75298/3 "2023-06-20T18:46:59Z")

</div>

Check the designer's menu (help -\> about) and see your license status for the various modules you have installed. Are you sure you reset the trial on the correct gateway?

---

<div class="post-metadata">

**Author:** ![Tom\_Grotenhuis](https://avatars.discourse-cdn.com/v4/letter/t/6a8cbe/32.png) [@Tom\_Grotenhuis](https://forum.inductiveautomation.com/u/Tom_Grotenhuis)\
**Post date:** [June 20, 2023, 9:30pm UTC](https://forum.inductiveautomation.com/t/gateway-serial-module-writebytes-hex/75298/4 "2023-06-20T21:30:13Z")

</div>

Dang you are fast.

My apologies for my ignorance. I had a feeling I was murdering the requirements for the array.

Would you be able to walk me through constructing a simple 2-byte array that can handle unsigned values and is a valid argument for **system.serial.writeBytes**?  
So far I've been taking guidance from these forum posts but am lost as how to construct the array:  
[https://forum.inductiveautomation.com/t/serial-module-possible-error/5920/11](https://forum.inductiveautomation.com/t/serial-module-possible-error/5920/11)  
[https://forum.inductiveautomation.com/t/solved-get-nmea-sentence-system-serial/48783](https://forum.inductiveautomation.com/t/solved-get-nmea-sentence-system-serial/48783)

Again, my apologies for the ignorance. Any help is appreciated. Thank you!

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [June 20, 2023, 9:47pm UTC](https://forum.inductiveautomation.com/t/gateway-serial-module-writebytes-hex/75298/5 "2023-06-20T21:47:26Z")

</div>

The pythonic solution is something like this:

```auto
import jarray

unsignedBytes = [0xCA, 0x00, 0x01, 0x70, 0x00, 0x8E]
signedBytes = [((x + 0x80) & 0xff) - 0x80 for x in unsignedBytes]
byteArray = jarray.array(signedBytes, 'b')

```

~~Rather than rely on jython math, I usually do this:~~

~~ 

```auto
import jarray
from java.lang import Long

unsignedBytes = [0xCA, 0x00, 0x01, 0x70, 0x00, 0x8E]
signedBytes = [Long.valueOf(x).byteValue() for x in unsignedBytes]
byteArray = jarray.array(signedBytes, 'b')

```

 ~~

~~This latter implementation will simply chop the upper bits off of whatever you feed it.~~

Apparently, that no longer works. Jython is turning the `Long` back into its own `long`. ):

---

<div class="post-metadata">

**Author:** ![Tom\_Grotenhuis](https://avatars.discourse-cdn.com/v4/letter/t/6a8cbe/32.png) [@Tom\_Grotenhuis](https://forum.inductiveautomation.com/u/Tom_Grotenhuis)\
**Post date:** [June 21, 2023, 2:25pm UTC](https://forum.inductiveautomation.com/t/gateway-serial-module-writebytes-hex/75298/6 "2023-06-21T14:25:02Z")

</div>

Thanks for the help! That snippet got me off to the races. I'll post more to this topic when my example is more complete... or if I'm completely lost 🙂

Thanks again!

---

<div class="post-metadata">

**Author:** ![kyler.kamyszek](https://avatars.discourse-cdn.com/v4/letter/k/a4c791/32.png) [@kyler.kamyszek](https://forum.inductiveautomation.com/u/kyler.kamyszek)\
**Post date:** [June 21, 2023, 3:02pm UTC](https://forum.inductiveautomation.com/t/gateway-serial-module-writebytes-hex/75298/7 "2023-06-21T15:02:26Z")

</div>

Using bytearray you can get the same affect without the '0x' in the strings/values.

```auto
msg = '4142'

data = bytearray.fromhex(msg)

print data #should print 'AB'

```

---

<div class="post-metadata">

**Author:** ![Tom\_Grotenhuis](https://avatars.discourse-cdn.com/v4/letter/t/6a8cbe/32.png) [@Tom\_Grotenhuis](https://forum.inductiveautomation.com/u/Tom_Grotenhuis)\
**Post date:** [June 30, 2023, 2:42pm UTC](https://forum.inductiveautomation.com/t/gateway-serial-module-writebytes-hex/75298/8 "2023-06-30T14:42:12Z")

</div>

Hey All,

For anyone watching this thread, these are the commands I ended up using to sign and unsign byte arrays, and pipe those arrays to and from the serial port. Device documentation was all in raw hex so that's the reason for working back and forth. I'm sure there's prettier code out there but this does _work_.

```auto
commands = [
    [0xCA, 0x00, 0x01, 0x70, 0x00, 0x8E], # Current Setpoint
    [0xCA, 0x00, 0x01, 0x10, 0x00, 0xEE], # Process Flowrate
]

...

for command, tag_path in zip(commands, tag_paths):
    # Convert unsigned byte array to signed byte array
    signedCommandBytes = [((x + 0x80) & 0xff) - 0x80 for x in command]
    commandByteArray = jarray.array(signedCommandBytes, 'b')

    # Send the message
    system.serial.writeBytes("COM7", commandByteArray)

    # Receive the reply
    chillReply = system.serial.readBytes("COM7", 9)

    # The reply is an unsigned array stored as a signed array
    # Can't use the jarray function as before though, as it creates overflows
    signedReplyBytes = [((x + 0x80) & 0xff) - 0x80 for x in chillReply]
    unsignedReplyBytes = bytearray([(byte + 256) % 256 for byte in signedReplyBytes])
    packet = unsignedReplyBytes

```

This snippet was part of a rudimentary driver for Neslab / Thermoflex chillers using "NC protocol". Please drop me a PM if you would like the entire script.
