22using System . IO . Ports ;
33#endif
44using UnityEngine ;
5+ using UnityEngine . Events ;
56using System . Collections . Generic ;
67using System . Diagnostics ;
78using System ;
@@ -19,6 +20,10 @@ public class ArduinoSerialCommunication : MonoBehaviour
1920 [ SerializeField ]
2021 [ Range ( - 1 , 256 ) ]
2122 private int portNumber = - 1 ;
23+ [ SerializeField ]
24+ private bool logReceivedMessages = true ;
25+ [ SerializeField ]
26+ private OnStringEvent [ ] onStringEvents ;
2227
2328 private string _rawData = string . Empty ;
2429 private uint _dataIndex = 0 ;
@@ -29,6 +34,7 @@ public class ArduinoSerialCommunication : MonoBehaviour
2934
3035 private Dictionary < string , string > portAssignments = new Dictionary < string , string > ( ) ;
3136 private string comPort ;
37+ private volatile bool _keepListening = false ;
3238
3339 SerialPort port ;
3440 Thread serialPortListenerThread ;
@@ -69,7 +75,7 @@ void Start()
6975 PopulatePortList ( ) ;
7076 if ( portNumber >= 0 && PortExists ( portNumber ) )
7177 {
72- comPort = portNumber . ToString ( ) ;
78+ comPort = "COM" + portNumber ;
7379 Connect ( ) ;
7480 }
7581 else if ( ( comPort = GetFirstPortMatchingName ( deviceName ) ) != null )
@@ -80,43 +86,44 @@ void Start()
8086 {
8187 UnityEngine . Debug . LogWarning ( "Arduino Not Found" ) ;
8288 }
89+ OnSerialEvent += HandleSerialString ;
8390 }
8491
8592 private void OnDestroy ( )
8693 {
87- if ( serialPortListenerThread != null )
88- {
89- serialPortListenerThread . Abort ( ) ;
90- ClosePort ( ) ;
91- }
94+ StopListening ( ) ;
9295 }
9396 private void OnDisable ( )
9497 {
95- if ( serialPortListenerThread != null )
96- {
97- serialPortListenerThread . Abort ( ) ;
98- ClosePort ( ) ;
99- }
98+ StopListening ( ) ;
10099 }
101100
102101 void Connect ( )
103102 {
104- if ( serialPortListenerThread != null )
105- {
106- serialPortListenerThread . Abort ( ) ;
107- ClosePort ( ) ;
108- }
103+ StopListening ( ) ;
109104
110105 Utils . SafeTry ( ( ) => InitializeArduino ( comPort , ( int ) BaudRate ) ) ;
111106
107+ _keepListening = true ;
112108 serialPortListenerThread = new Thread ( RecieveDataInHelperThread ) ;
113109 serialPortListenerThread . Start ( ) ;
114110 }
115111
112+ private void StopListening ( )
113+ {
114+ _keepListening = false ;
115+ if ( serialPortListenerThread != null && serialPortListenerThread . IsAlive )
116+ {
117+ serialPortListenerThread . Join ( 200 ) ;
118+ }
119+ ClosePort ( ) ;
120+ serialPortListenerThread = null ;
121+ }
122+
116123 public void ClosePort ( )
117124 {
118125 UnityEngine . Debug . Log ( "Close port" ) ;
119- Utils . SafeTry ( ( ) => port . Close ( ) ) ;
126+ Utils . SafeTry ( ( ) => port ? . Close ( ) ) ;
120127 }
121128
122129 void InitializeArduino ( string listeningPort , int baudRate )
@@ -135,20 +142,27 @@ void InitializeArduino(string listeningPort, int baudRate)
135142
136143 void RecieveDataInHelperThread ( )
137144 {
138- while ( port . IsOpen )
145+ try
139146 {
140- String str = port . ReadLine ( ) ;
141- if ( ! string . IsNullOrWhiteSpace ( str ) )
147+ while ( _keepListening && port != null && port . IsOpen )
142148 {
143- _rawData = str ;
144- _dataIndex ++ ;
145- if ( OnSerialEvent != null )
149+ string str = port . ReadLine ( ) ;
150+ if ( ! string . IsNullOrWhiteSpace ( str ) )
146151 {
147- // Notify on main thread...
148- Enqueue ( ActionWrapper ( ( ) => OnSerialEvent ( str ) ) ) ;
152+ _rawData = str ;
153+ _dataIndex ++ ;
154+ if ( OnSerialEvent != null )
155+ {
156+ // Notify on main thread...
157+ Enqueue ( ActionWrapper ( ( ) => OnSerialEvent ( str ) ) ) ;
158+ }
149159 }
150160 }
151161 }
162+ catch ( Exception )
163+ {
164+ // Swallow read exceptions during shutdown/disconnect.
165+ }
152166 }
153167
154168 // Send text to the serial port.
@@ -223,7 +237,7 @@ private string GetFirstPortMatchingName(string contains)
223237 }
224238 private bool PortExists ( int portNum )
225239 {
226- return ( portAssignments . ContainsValue ( portNum . ToString ( ) ) ) ;
240+ return ( portAssignments . ContainsValue ( "COM" + portNum ) ) ;
227241 }
228242 void Enqueue ( IEnumerator action )
229243 {
@@ -240,6 +254,54 @@ IEnumerator ActionWrapper(Action action)
240254 action ( ) ;
241255 yield return null ;
242256 }
257+
258+ private void HandleSerialString ( string message )
259+ {
260+ foreach ( var onStringEvent in onStringEvents )
261+ {
262+ if ( onStringEvent . Message == message )
263+ {
264+ bool invoked = onStringEvent . Invoke ( ) ;
265+ if ( logReceivedMessages )
266+ {
267+ if ( invoked )
268+ {
269+ UnityEngine . Debug . Log ( $ "Invoked command for message: { message } ") ;
270+ }
271+ else
272+ {
273+ UnityEngine . Debug . Log ( $ "Debounced command for message: { message } ") ;
274+ }
275+ }
276+ }
277+ }
278+ }
279+ [ System . Serializable ]
280+ class OnStringEvent
281+ {
282+ [ SerializeField ]
283+ private string message ;
284+ [ SerializeField ]
285+ private float debounceTime = 0.1f ;
286+ [ SerializeField ]
287+ private UnityEvent command ;
288+
289+ private float lastInvokeTime = float . NegativeInfinity ;
290+ public string Message { get { return message ; } }
291+
292+ public bool Invoke ( )
293+ {
294+ float timeSinceLastInvoke = Time . time - lastInvokeTime ;
295+ if ( timeSinceLastInvoke < debounceTime )
296+ {
297+ return false ;
298+ }
299+
300+ lastInvokeTime = Time . time ;
301+ command . Invoke ( ) ;
302+ return true ;
303+ }
304+ }
243305#endif
244306 }
245307}
0 commit comments