freezy / dmd-extensions

A toolbox for virtual pinball dot matrix displays.
GNU General Public License v2.0
127 stars 54 forks source link

Exception when dmdext recives frames from test application via websocket #451

Open csabakeszegh opened 9 months ago

csabakeszegh commented 9 months ago

I'd like to use dmdext.exe to show frames on a virtual dmd display received from another machine via websocket. On start everything seems normal: a black virtual dmd display shows up on screen, and "gameName" message works. However on the first gray4Planes frame I get an exception, and dmdext quits. I assume data is 2048 bytes for a 128x32 gray4Plane dmd frame.

Suspicious line in the log Resizing virtual DMD to 0x0. Do I miss some dmdext configuration?

C:\Users\csaba\Downloads\dmdext-v2.2.1-x86>dmdext server -d virtual --ip 192.168.0.159
 [1] 2023/12/10 13:32:44.645  INFO | Launching console tool v2.2.1
 [1] 2023/12/10 13:32:46.228  INFO | Added virtual DMD renderer.
 [1] 2023/12/10 13:32:46.232  INFO | Starting server at http://192.168.0.159:80/dmd...
 [1] 2023/12/10 13:32:46.255  INFO | Server listening, connect to ws://192.168.0.159:80/dmd...
 [1] 2023/12/10 13:32:46.274  INFO | Setting up 2-bit Websocket Graph for 1 destination(s) [ Virtual DMD ]
 [1] 2023/12/10 13:32:46.284  INFO |   -> Connecting Websocket 2-bit Source to Virtual DMD (Gray2 -> Gray2) - deduped
 [1] 2023/12/10 13:32:46.311  INFO | Setting up 4-bit Websocket Graph for 1 destination(s) [ Virtual DMD ]
 [1] 2023/12/10 13:32:46.311  INFO |   -> Connecting Websocket 4-bit Source to Virtual DMD (Gray4 -> Gray4) - deduped
 [1] 2023/12/10 13:32:46.311  INFO | Setting up Colored 2-bit Websocket Graph for 1 destination(s) [ Virtual DMD ]
 [1] 2023/12/10 13:32:46.311  INFO |   -> Connecting Websocket Colored 2-bit Source to Virtual DMD (ColoredGray2 -> ColoredGray2)
 [1] 2023/12/10 13:32:46.311  INFO | Setting up Colored 4-bit Websocket Graph for 1 destination(s) [ Virtual DMD ]
 [1] 2023/12/10 13:32:46.311  INFO |   -> Connecting Websocket Colored 4-bit Source to Virtual DMD (ColoredGray4 -> ColoredGray4)
 [1] 2023/12/10 13:32:46.311  INFO | Setting up 24-bit RGB Websocket Graph for 1 destination(s) [ Virtual DMD ]
 [1] 2023/12/10 13:32:46.311  INFO |   -> Connecting Websocket 24-bit RGB Source to Virtual DMD (Rgb24 -> Rgb24)
 [1] 2023/12/10 13:32:46.311  INFO | Press CTRL+C to close.
 [1] 2023/12/10 13:32:46.618  INFO | Creating FBOs for 128x32
 [4] 2023/12/10 13:32:52.808 DEBUG | New WebSocket client 9d0cdd7304c7471cbae313c571fe6860
[11] 2023/12/10 13:32:52.818  INFO | OnGameName: TestGame
 [8] 2023/12/10 13:32:53.035  INFO | Resizing virtual DMD to 0x0
 [8] 2023/12/10 13:32:53.035 ERROR | 'Auto,Auto,Auto,Auto' is not a valid value for property 'Margin'.
 [8] 2023/12/10 13:32:53.052 ERROR | System.ArgumentException: 'Auto,Auto,Auto,Auto' is not a valid value for property 'Margin'.
   at System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp, Object value, PropertyMetadata metadata, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType, Boolean isInternal)
   at System.Windows.DependencyObject.SetValue(DependencyProperty dp, Object value)
   at LibDmd.Output.Virtual.Dmd.VirtualDmdControl.<OnSizeChanged>b__86_0()
   at System.Windows.Threading.DispatcherOperation.InvokeDelegateCore()
   at System.Windows.Threading.DispatcherOperation.InvokeImpl()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Windows.Threading.DispatcherOperation.Wait(TimeSpan timeout)
   at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherOperation operation, CancellationToken cancellationToken, TimeSpan timeout)
   at System.Windows.Threading.Dispatcher.Invoke(Action callback, DispatcherPriority priority, CancellationToken cancellationToken, TimeSpan timeout)
   at System.Windows.Threading.Dispatcher.Invoke(Action callback)
   at LibDmd.Output.Virtual.Dmd.VirtualDmdControl.OnSizeChanged(Object sender, RoutedEventArgs e)
   at LibDmd.Output.Virtual.Dmd.VirtualDmdControl.SetDimensions(Dimensions dim)
   at LibDmd.Output.Virtual.Dmd.VirtualDmdControl.RenderGray4(DmdFrame frame)
   at System.Reactive.AnonymousSafeObserver`1.OnNext(T value)
   at System.Reactive.Linq.ObservableImpl.Select`2._.OnNext(TSource value)
   at System.Reactive.Linq.ObservableImpl.Select`2._.OnNext(TSource value)
   at System.Reactive.ScheduledObserver`1.Dispatch(ICancelable cancel)
   at System.Reactive.Concurrency.Scheduler.<ScheduleLongRunning>b__72(Action`1 a, ICancelable c)
   at System.Reactive.Concurrency.DefaultScheduler.LongRunning.<>c__DisplayClassc`1.<ScheduleLongRunning>b__b(Object arg)
   at System.Reactive.Concurrency.DefaultConcurrencyAbstractionLayer.<>c__DisplayClass5.<StartThread>b__4()
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()

Unhandled Exception: System.ArgumentException: 'Auto,Auto,Auto,Auto' is not a valid value for property 'Margin'.
   at System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp, Object value, PropertyMetadata metadata, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType, Boolean isInternal)
   at System.Windows.DependencyObject.SetValue(DependencyProperty dp, Object value)
   at LibDmd.Output.Virtual.Dmd.VirtualDmdControl.<OnSizeChanged>b__86_0()
   at System.Windows.Threading.DispatcherOperation.InvokeDelegateCore()
   at System.Windows.Threading.DispatcherOperation.InvokeImpl()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Windows.Threading.DispatcherOperation.Wait(TimeSpan timeout)
   at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherOperation operation, CancellationToken cancellationToken, TimeSpan timeout)
   at System.Windows.Threading.Dispatcher.Invoke(Action callback, DispatcherPriority priority, CancellationToken cancellationToken, TimeSpan timeout)
   at System.Windows.Threading.Dispatcher.Invoke(Action callback)
   at LibDmd.Output.Virtual.Dmd.VirtualDmdControl.OnSizeChanged(Object sender, RoutedEventArgs e)
   at LibDmd.Output.Virtual.Dmd.VirtualDmdControl.SetDimensions(Dimensions dim)
   at LibDmd.Output.Virtual.Dmd.VirtualDmdControl.RenderGray4(DmdFrame frame)
   at System.Reactive.AnonymousSafeObserver`1.OnNext(T value)
   at System.Reactive.Linq.ObservableImpl.Select`2._.OnNext(TSource value)
   at System.Reactive.Linq.ObservableImpl.Select`2._.OnNext(TSource value)
   at System.Reactive.ScheduledObserver`1.Dispatch(ICancelable cancel)
   at System.Reactive.Concurrency.Scheduler.<ScheduleLongRunning>b__72(Action`1 a, ICancelable c)
   at System.Reactive.Concurrency.DefaultScheduler.LongRunning.<>c__DisplayClassc`1.<ScheduleLongRunning>b__b(Object arg)
   at System.Reactive.Concurrency.DefaultConcurrencyAbstractionLayer.<>c__DisplayClass5.<StartThread>b__4()
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()

The sender application is a mini python test app:

#!/usr/bin/env python

import time
from websockets.sync.client import connect
import struct

FRM_SIZE = 2048

def dmd_test():
    with connect("ws://192.168.0.159:80/dmd") as ws:
        ws.send(b"gameName\x00TestGame\x00")
        ws.send(b"dimensions\x00" + struct.pack("II", 128, 32))
        #ws.send(b"clearColor\x00")
        #ws.send(b"clearPalette\x00")
        with open("dmd.raw", "rb") as f:
            data = f.read(FRM_SIZE)
            timestamp = 0 # Guess it's millisec
            while len(data) == FRM_SIZE:
                time.sleep(timestamp / 1000.0)
                timestamp += 200 # 5FPS
                msg = b"gray4Planes\x00" + struct.pack("I", timestamp) + data
                ws.send(msg)
                data = f.read(FRM_SIZE)

dmd_test()
freezy commented 5 months ago

Can't reproduce, your python script gives me:

Traceback (most recent call last):
  File "test.py", line 2, in <module>
    from websockets.sync.client import connect
ModuleNotFoundError: No module named 'websockets.sync'

I tried pip install websockets and pip install websocket_client.

csabakeszegh commented 5 months ago

dmdext: v2.2.2 x64 Python: 3.12.3 (downloaded from https://www.python.org/downloads/windows/) websockets: 12.0 (intalled with pip install websockets) OS: Win10 x64

Terminal1: dmdext server -d virtual --ip 192.168.0.159 Save the python code to test.py (and update the IP), and run python test.py. I guess the dmd.raw file content doesn't really matter until it has at least 2048 bytes (I expect garbage on screen for radom data).

Please let me know if I can help further to reproduce this issue.