144 lines
5.8 KiB
C#
144 lines
5.8 KiB
C#
|
/**
|
|||
|
* Ardity (Serial Communication for Arduino + Unity)
|
|||
|
* Author: Daniel Wilches <dwilches@gmail.com>
|
|||
|
*
|
|||
|
* This work is released under the Creative Commons Attributions license.
|
|||
|
* https://creativecommons.org/licenses/by/2.0/
|
|||
|
*/
|
|||
|
|
|||
|
using UnityEngine;
|
|||
|
using System.Threading;
|
|||
|
|
|||
|
/**
|
|||
|
* While 'SerialController' only allows reading/sending text data that is
|
|||
|
* terminated by new-lines, this class allows reading/sending messages
|
|||
|
* using a binary protocol where each message is separated from the next by
|
|||
|
* a 1-char delimiter.
|
|||
|
*/
|
|||
|
public class SerialControllerCustomDelimiter : MonoBehaviour
|
|||
|
{
|
|||
|
[Tooltip("Port name with which the SerialPort object will be created.")]
|
|||
|
public string portName = "COM3";
|
|||
|
|
|||
|
[Tooltip("Baud rate that the serial device is using to transmit data.")]
|
|||
|
public int baudRate = 9600;
|
|||
|
|
|||
|
[Tooltip("Reference to an scene object that will receive the events of connection, " +
|
|||
|
"disconnection and the messages from the serial device.")]
|
|||
|
public GameObject messageListener;
|
|||
|
|
|||
|
[Tooltip("After an error in the serial communication, or an unsuccessful " +
|
|||
|
"connect, how many milliseconds we should wait.")]
|
|||
|
public int reconnectionDelay = 1000;
|
|||
|
|
|||
|
[Tooltip("Maximum number of unread data messages in the queue. " +
|
|||
|
"New messages will be discarded.")]
|
|||
|
public int maxUnreadMessages = 1;
|
|||
|
|
|||
|
[Tooltip("Maximum number of unread data messages in the queue. " +
|
|||
|
"New messages will be discarded.")]
|
|||
|
public byte separator = 90;
|
|||
|
|
|||
|
// Internal reference to the Thread and the object that runs in it.
|
|||
|
protected Thread thread;
|
|||
|
protected SerialThreadBinaryDelimited serialThread;
|
|||
|
|
|||
|
|
|||
|
// ------------------------------------------------------------------------
|
|||
|
// Invoked whenever the SerialController gameobject is activated.
|
|||
|
// It creates a new thread that tries to connect to the serial device
|
|||
|
// and start reading from it.
|
|||
|
// ------------------------------------------------------------------------
|
|||
|
void OnEnable()
|
|||
|
{
|
|||
|
serialThread = new SerialThreadBinaryDelimited(portName,
|
|||
|
baudRate,
|
|||
|
reconnectionDelay,
|
|||
|
maxUnreadMessages,
|
|||
|
separator);
|
|||
|
thread = new Thread(new ThreadStart(serialThread.RunForever));
|
|||
|
thread.Start();
|
|||
|
}
|
|||
|
|
|||
|
// ------------------------------------------------------------------------
|
|||
|
// Invoked whenever the SerialController gameobject is deactivated.
|
|||
|
// It stops and destroys the thread that was reading from the serial device.
|
|||
|
// ------------------------------------------------------------------------
|
|||
|
void OnDisable()
|
|||
|
{
|
|||
|
// If there is a user-defined tear-down function, execute it before
|
|||
|
// closing the underlying COM port.
|
|||
|
if (userDefinedTearDownFunction != null)
|
|||
|
userDefinedTearDownFunction();
|
|||
|
|
|||
|
// The serialThread reference should never be null at this point,
|
|||
|
// unless an Exception happened in the OnEnable(), in which case I've
|
|||
|
// no idea what face Unity will make.
|
|||
|
if (serialThread != null)
|
|||
|
{
|
|||
|
serialThread.RequestStop();
|
|||
|
serialThread = null;
|
|||
|
}
|
|||
|
|
|||
|
// This reference shouldn't be null at this point anyway.
|
|||
|
if (thread != null)
|
|||
|
{
|
|||
|
thread.Join();
|
|||
|
thread = null;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// ------------------------------------------------------------------------
|
|||
|
// Polls messages from the queue that the SerialThread object keeps. Once a
|
|||
|
// message has been polled it is removed from the queue. There are some
|
|||
|
// special messages that mark the start/end of the communication with the
|
|||
|
// device.
|
|||
|
// ------------------------------------------------------------------------
|
|||
|
void Update()
|
|||
|
{
|
|||
|
// If the user prefers to poll the messages instead of receiving them
|
|||
|
// via SendMessage, then the message listener should be null.
|
|||
|
if (messageListener == null)
|
|||
|
return;
|
|||
|
|
|||
|
// Read the next message from the queue
|
|||
|
byte[] message = ReadSerialMessage();
|
|||
|
if (message == null)
|
|||
|
return;
|
|||
|
|
|||
|
// Check if the message is plain data or a connect/disconnect event.
|
|||
|
messageListener.SendMessage("OnMessageArrived", message);
|
|||
|
}
|
|||
|
|
|||
|
// ------------------------------------------------------------------------
|
|||
|
// Returns a new unread message from the serial device. You only need to
|
|||
|
// call this if you don't provide a message listener.
|
|||
|
// ------------------------------------------------------------------------
|
|||
|
public byte[] ReadSerialMessage()
|
|||
|
{
|
|||
|
// Read the next message from the queue
|
|||
|
return (byte[]) serialThread.ReadMessage();
|
|||
|
}
|
|||
|
|
|||
|
// ------------------------------------------------------------------------
|
|||
|
// Puts a message in the outgoing queue. The thread object will send the
|
|||
|
// message to the serial device when it considers it's appropriate.
|
|||
|
// ------------------------------------------------------------------------
|
|||
|
public void SendSerialMessage(byte[] message)
|
|||
|
{
|
|||
|
serialThread.SendMessage(message);
|
|||
|
}
|
|||
|
|
|||
|
// ------------------------------------------------------------------------
|
|||
|
// Executes a user-defined function before Unity closes the COM port, so
|
|||
|
// the user can send some tear-down message to the hardware reliably.
|
|||
|
// ------------------------------------------------------------------------
|
|||
|
public delegate void TearDownFunction();
|
|||
|
private TearDownFunction userDefinedTearDownFunction;
|
|||
|
public void SetTearDownFunction(TearDownFunction userFunction)
|
|||
|
{
|
|||
|
this.userDefinedTearDownFunction = userFunction;
|
|||
|
}
|
|||
|
|
|||
|
}
|