Asynchronous Serial Messages

Azul was having some issues reading data coming back from a custom script running on an Arduino Mega, so I thought I'd make a small script which demonstrates how to do asynchronous reading.

The script requires no hardware, because it uses a Virtual Serial Port (COM77_uart).

I used the swing gui, because its better at displaying python errors, although the webgui has a better send interface (swing one grows for some reason :P)

Anyway I type in one, and messages are printed in Python.  I selected 'X" as a delimeter between messages, but it could be anything the serial device sends.

Hope this helps


#file : home/GroG/serialMsgs.py edit raw
##################################
# Basic script to show how serial callbacks can
# be used to create messages
#
virtual = Runtime.start('virtual','VirtualDevice')
virtual.createVirtualSerial('COM77')
serial = Runtime.start('serial','Serial')
serial.connect('COM77')

serial.addByteListener('python')

serdata = ''
method = '';

def pings():
  global method
  method = 'ping'
  serial.write("P\r")

def onConnect(portName):
  print('connected', portName)

def onDisconnect(portName):
  print('disconnected', portName)


def onByte(data):
  global serdata, method
  c = chr(data)
  serdata += c
  print('['+ serdata + ']')
  if(c == 'X'):
    print('got message ', method, serdata)
    serdata = ''

Going through this simple example, I found some "good" & "bad"

The Good

This addByteListener is great !  
And this is why..  the interface is extremely simple - just the name of the service.
String interfaces can be easily supported in HTTP GET requests - so to add a byte listener you could do this:
       

                   http://localhost:8888/api/services/serial/addByteListener/python

Another exiting thing is Serial has two methods of communication - the regular pub/sub and an optimized native Java callback - this one method determines if it can use the optimized callback or drops back to the pub/sub automatically.  Very cool !

	public void addByteListener(String name) {
		ServiceInterface si = Runtime.getService(name);

		// if (si instanceof SerialDataListener && si.isLocal()){
		if (SerialDataListener.class.isAssignableFrom(si.getClass()) && si.isLocal()) {
			// direct callback
			listeners.put(si.getName(), (SerialDataListener) si);
		} else {
			// pub sub
			addListener("publishRX", si.getName(), "onByte");
			addListener("publishConnect", si.getName(), "onConnect");
			addListener("publishDisconnect", si.getName(), "onDisconnect");
		}
	}

 

 

Now The Bad

This is out of Spec !!!

addListener("publishRX", si.getName(), "onByte");

it should be publishByte !!  If the callback is expected on onByte !!!

I think it grew into publishRX because at some point it became desirable to publish both tx & rx bytes.
But most subscribers would typically want to consume rx bytes .. and I think would expect to find a publishByte

Should I fix it ?

 


Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
kwatters's picture

consistency is key

We probably shouldn't publish transmitted bytes. so down with the publishTX..  (who ever is publishing bytes to the serial port, should have their own publishBytes)  and publishRX for consistency should be "publishByte" as you  mentioned  "onByte" is the callback so, we should be consistent.

GroG's picture

Agree on the consistency part

Agree on the consistency part - I'll do some heavy grepping .. and replace ..

publishTX is still important .. 
  but it violates the convention of abbreviations ... it should be publishTx  and a corresponding onTx(byte) would be called

the publishTX has been extremely useful for displays.. 
For example when you want to monitor a line, but some other service or thread is sending data through it ..  we want to be able to "view" both directions 

The naming is asymmetrical but extremely useful as a "visual tap"  .. without it we would be blind

So in summary:

publishByte --> onByte  - most common and part of the SerialDataListener interface
publishTx --> onTx - very useful for visualization

See below .. the Tx would not exist if we didn't publish it

moz4r's picture

Hi ! noob question :What the

Hi ! noob question :

What the difference between analog arduino reader in python script

And Virtual serial read ? In fact, What Virtual Port is for ...

 

I want to implemente in MRL arduino sketch about mouthcontrol based speaker voltage output

It work great ! but on dedicate arduino.

GroG's picture

The VirtualDevice service can

The VirtualDevice service can create virtual hardware.

We have an Arduino service .. but to do stuff it needs to connect to an Arduino hardware.

VirtualDevice has the ability to "pretend" to be an Arduino hardware board.

Its very useful to do all sorts of testing.  I can test someones full InMoov script using no hardware at all - but using "Virtual Arduinos" connected over Virtual Ports.

We can also drive simulators with it .. like the Virtual InMoov in Blender or Threejs land.

 

With the Arduino's service's analog polling you should be able to monitor the speaker with just a pin on one of your existing Arduinos

moz4r's picture

thank for explain grog ! I

thank for explain grog !

I will try to monitor the speaker to shutdown microphone electrical too. It listen mouth :)

 

Mats's picture

Syncronous read

Is there a way to return the read data in a syncronous way on a higher level ?

The reason I'm asking is that the i2c library on the PI uses syncronous read and I want be able to use the same driver for both RasPi and Arduino. 

So the driver does a read statement, and the data read gets returned.

For example:

AdafruitIIna219 does a read and the RasPi returns the data read from the i2c bus. The read will wait until the i2c data is returned.  

If I use Arduino, I still want the program to receive the data from the read statement,

I understand that the Arduino service has to send serial data to the Arduino, and that the MRLComm will read that request and make a read on the i2c bus. The result from the i2c read has to be returned to the Ardino service by MRLComm making a serial write. The Arduino service ( or serial ? )  will read the data and publish it. But how can I get that data to be returned to my read statement in  AdafruitIIna219 ( i.e. the service that made the read request ).  

Do you have any suggestion how I should handle the read ?

/Mats