@@ -13,6 +13,8 @@ MODULE_NAME='mWolfVisionVisualizer' (
1313#include ' NAVFoundation.StringUtils.axi'
1414#include ' NAVFoundation.TimelineUtils.axi'
1515#include ' NAVFoundation.ErrorLogUtils.axi'
16+ #include ' NAVFoundation.NetUtils.axi'
17+ #include ' NAVFoundation.Regex.axi'
1618
1719/*
1820 _ _ _ ___ __
@@ -58,12 +60,9 @@ DEFINE_CONSTANT
5860constant integer IP_PORT = 50915
5961
6062constant long TL_DRIVE = 1
61- constant long TL_IP_CHECK = 2
62- constant long TL_HEARTBEAT = 3
63+ constant long TL_SOCKET_CHECK = 2
6364
6465constant long TL_DRIVE_INTERVAL [] = { 200 }
65- constant long TL_IP_CHECK_INTERVAL [] = { 3000 }
66- constant long TL_HEARTBEAT_INTERVAL [] = { 20000 }
6766
6867constant integer GET_POWER = 1
6968
@@ -172,12 +171,20 @@ define_function Drive() {
172171}
173172
174173
175- define_function MaintainIpConnection () {
174+ define_function MaintainSocketConnection () {
176175 if (module .Device.SocketConnection.IsConnected ) {
177176 return
178177 }
179178
180- NAVClientSocketOpen (dvPort.PORT ,
179+ if (! length_array (module .Device.SocketConnection.Address )) {
180+ return
181+ }
182+
183+ if (module .Device.SocketConnection.Port <= 0 ) {
184+ return
185+ }
186+
187+ NAVClientSocketOpen (module .Device.SocketConnection.Socket ,
181188 module .Device.SocketConnection.Address ,
182189 module .Device.SocketConnection.Port ,
183190 IP_TCP )
@@ -198,25 +205,76 @@ define_function CommunicationTimeOut(integer timeout) {
198205
199206
200207define_function Reset () {
208+ cancel_wait ' TimeOut'
209+
201210 module .Device.SocketConnection.IsConnected = false
202211 module .Device.IsCommunicating = false
203212 module .Device.IsInitialized = false
204213 UpdateFeedback ()
205214
206- NAVTimelineStop (TL_HEARTBEAT )
207215 NAVTimelineStop (TL_DRIVE )
208216}
209217
210218
219+ define_function SocketConnectionReset () {
220+ NAVTimelineStop (TL_SOCKET_CHECK )
221+
222+ if (module .Device.SocketConnection.IsConnected ) {
223+ NAVClientSocketClose (module .Device.SocketConnection.Socket )
224+ }
225+
226+ // Always reset retry count for clean state
227+ module .Device.SocketConnection.RetryCount = 0
228+ module .Device.SocketConnection.Interval [1 ] = NAVSocketGetConnectionInterval (module .Device.SocketConnection.RetryCount )
229+
230+ if (! length_array (module .Device.SocketConnection.Address )) {
231+ return
232+ }
233+
234+ NAVTimelineStart (TL_SOCKET_CHECK ,
235+ module .Device.SocketConnection.Interval ,
236+ TIMELINE_ABSOLUTE ,
237+ TIMELINE_REPEAT )
238+ }
239+
240+
211241define_function NAVModulePropertyEventCallback (_NAVModulePropertyEvent event ) {
212242 switch (event .Name ) {
213243 case NAV_MODULE_PROPERTY_EVENT_IP_ADDRESS : {
214- module .Device.SocketConnection.Address = event .Args [1 ]
215- module .Device.SocketConnection.Port = IP_PORT
216- NAVTimelineStart (TL_IP_CHECK ,
217- TL_IP_CHECK_INTERVAL ,
218- TIMELINE_ABSOLUTE ,
219- TIMELINE_REPEAT )
244+ stack_var _NAVIP ip
245+ stack_var char address [255 ]
246+
247+ address = NAVTrimString (event .Args [1 ])
248+
249+ // Handle empty address - clear and reset connection
250+ if (! length_array (address )) {
251+ module .Device.SocketConnection.Address = ' '
252+ NAVErrorLog (NAV_LOG_LEVEL_INFO ,
253+ " ' mWolfVisionVisualizer => Clearing IP address' " )
254+
255+ SocketConnectionReset ()
256+ return
257+ }
258+
259+ if (! NAVNetParseIP (address , ip )) {
260+ if (NAVRegexTest (' /^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/' , address )) {
261+ module .Device.SocketConnection.Address = address
262+ NAVErrorLog (NAV_LOG_LEVEL_INFO ,
263+ " ' mWolfVisionVisualizer => Using hostname: ' , address " )
264+ }
265+ else {
266+ module .Device.SocketConnection.Address = ' '
267+ NAVErrorLog (NAV_LOG_LEVEL_ERROR ,
268+ " ' mWolfVisionVisualizer => Invalid IP address or hostname: ' , event .Args [1 ]" )
269+ }
270+ }
271+ else {
272+ module .Device.SocketConnection.Address = ip .Address
273+ NAVErrorLog (NAV_LOG_LEVEL_INFO ,
274+ " ' mWolfVisionVisualizer => Using IP address: ' , ip .Address " )
275+ }
276+
277+ SocketConnectionReset ()
220278 }
221279 }
222280}
@@ -265,12 +323,41 @@ define_function UpdateFeedback() {
265323}
266324
267325
326+ define_function HandleSocketError (tdata data ) {
327+ module .Device.SocketConnection.RetryCount ++
328+
329+ NAVErrorLog (NAV_LOG_LEVEL_ERROR ,
330+ " ' mWolfVisionVisualizer => Socket connection error: ' , NAVGetSocketError (type_cast (data.number ))" )
331+ NAVErrorLog (NAV_LOG_LEVEL_WARNING ,
332+ " ' mWolfVisionVisualizer => Socket connection failed (attempt ' , itoa (module .Device.SocketConnection.RetryCount ), ' )' " )
333+
334+ if (module .Device.SocketConnection.RetryCount <= NAV_MAX_SOCKET_CONNECTION_RETRIES ) {
335+ // Still in base retry phase - timeline already running at base interval
336+ NAVErrorLog (NAV_LOG_LEVEL_INFO ,
337+ " ' mWolfVisionVisualizer => Next retry in ' , itoa (module .Device.SocketConnection.Interval [1 ]), ' ms' " )
338+ return
339+ }
340+
341+ // Calculate new exponential backoff interval
342+ module .Device.SocketConnection.Interval [1 ] = NAVSocketGetConnectionInterval (module .Device.SocketConnection.RetryCount )
343+
344+ NAVErrorLog (NAV_LOG_LEVEL_INFO ,
345+ " ' mWolfVisionVisualizer => Next retry in ' , itoa (module .Device.SocketConnection.Interval [1 ]), ' ms' " )
346+
347+ // Restart timeline with new interval
348+ NAVTimelineReload (TL_SOCKET_CHECK , module .Device.SocketConnection.Interval )
349+ }
350+
351+
268352(* **********************************************************)
269353(* STARTUP CODE GOES BELOW *)
270354(* **********************************************************)
271355DEFINE_START {
272356 NAVModuleInit (module )
273357 create_buffer dvPort , module .RxBuffer.Data
358+ module .Device.SocketConnection.Socket = dvPort.PORT
359+ module .Device.SocketConnection.Port = IP_PORT
360+ module .Device.SocketConnection.Interval [1 ] = NAVSocketGetConnectionInterval (module .Device.SocketConnection.RetryCount )
274361}
275362
276363(* **********************************************************)
@@ -290,13 +377,19 @@ data_event[dvPort] {
290377
291378 if (data .device.number == 0 ) {
292379 module .Device.SocketConnection.IsConnected = true
380+
381+ // Reset retry count on successful connection
382+ module .Device.SocketConnection.RetryCount = 0
383+ module .Device.SocketConnection.Interval [1 ] = NAVSocketGetConnectionInterval (module .Device.SocketConnection.RetryCount )
384+ NAVTimelineReload (TL_SOCKET_CHECK , module .Device.SocketConnection.Interval )
385+
293386 UpdateFeedback ()
294387 }
295388
296389 NAVTimelineStart (TL_DRIVE ,
297- TL_DRIVE_INTERVAL ,
298- TIMELINE_ABSOLUTE ,
299- TIMELINE_REPEAT )
390+ TL_DRIVE_INTERVAL ,
391+ TIMELINE_ABSOLUTE ,
392+ TIMELINE_REPEAT )
300393 }
301394 offline : {
302395 if (data .device.number == 0 ) {
@@ -306,6 +399,7 @@ data_event[dvPort] {
306399 }
307400 onerror : {
308401 if (data .device.number == 0 ) {
402+ HandleSocketError (data )
309403 Reset ()
310404 }
311405 }
@@ -414,7 +508,7 @@ channel_event[vdvObject, 0]{
414508}
415509
416510
417- timeline_event [TL_IP_CHECK ] { MaintainIPConnection () }
511+ timeline_event [TL_SOCKET_CHECK ] { MaintainSocketConnection () }
418512
419513
420514timeline_event [TL_DRIVE ] { Drive () }
0 commit comments