Watchdog (for advanced users)

I’m considering using the watchdog and am trying to learn a little more about it. The GHI Watchdog Class page warns that it is only for advanced users.
http://www.ghielectronics.com/downloads/NETMF/Library%20Documentation%20v4.1/html/0fb1b905-933b-bbf8-ac70-d9d5d5fbf768.htm

It seems like a pretty simple concept to me, so I am wondering what some of the common pitfalls are. I just want the system (Fez Panda II in this case) to reset itself if it goes inactive for 5 seconds or so… it is going to be in a hard to reach location.

Oops, just found more info in the TinyCLR Wiki. My first searches yielded forum posts where Gus mentioned maybe adding it to the ebook, and I didn’t find it there.

I’ll read that over when I get home, but if anybody has extra bits of experience or knowledge to share it would be appreciated!

That tutorial covers it pretty well. Watchdog really is simple. Just make sure you read the whole tutorial.

1 Like

Alright, thanks!

I went ahead and added it in… just went for a 5 second reset counter loop with a 10 second timeout. The only reason i figure this might be “for advanced users” is that you can get yourself in a situation where you’d have to erase the device and reload the firmware… but even that is pretty easy to rectify.

You are welcome. Yes, if you put short period for the timer it is a recipe for fw reload.

This might warrant another thread… but is there a way to log unhandled exceptions to SD? For some reason my project runs indefinitely when connected to my computer and outputting to debug, but is locking up when running on its own.

Watchdog is working, but I would like to find the problem.

the running is much slower in debug mode, so sometimes are thread.sleep is needed to wait in “running” mode.
Suggestion write a debugtext(massage) function, writing to the sd-card. Replace “debug.print()” to “debugtext()” in the code and analayse later the order of events

1 Like

Appreciate the feedback, Daniel. I’ll probably use Streamwriter to write debug messages in the problem area. I already have 15ms Thread.Sleep in that loop as well. Who knows… that might somehow correct the problem. I don’t want to write to SD constantly though because of the limited read/write lifespan.

Another question… I’m seeing that we can use MFDeploy to view debug messages. Would this function any different than when I view the messages in Visual Studio after deploying there? I’d really love to see what the actual exception is…

I left it running all night viewing debug in Visual Studio and there was no problem. I plan to experiment more this evening, but I’m just trying to come up with more angles of attack while I’m stuck here at work!

Yes you can use MFDeploy to see Debug.Print messages. There is a new version coming out soon.

1 Like

maybe you can show us the code of the problem area, so we can forming opinion. What hardware and sensors you are using

My question on that though is whether that will be the exact same at the USBIZI hardware level as viewing debug through Visual Studio… viewing through VS fixes whatever the problem is, and I fear that MFDeploy will just do the same and I still won’t get to see the exception message.

Hard to say without seeing your code.

Well, I guess I was just looking more for general information on how debug works in Visual Studio versus MFDeploy and if there is a difference…

I’m probably being a pain, I’ll post code around lunch when I get a few minutes to make some variable name changes. Some of the names are pretty cryptic due to conceptual changes I had mid development and no longer make sense, so I need to clean that up to make it more readable.

Screw it… you guys are smart so you can handle my bad variable names lol. Architect, you probably saw the below video before… it’s the Tron Easter Egg I wrote into a light/sound display I built for my brother in law. I’m just posting the video so you know what the heck I am trying to do. - YouTube

So, the thread below starts up when I start the Tron lightshow. It serves 3 functions… during normal light modes, _raining is false, and _beatPattern = 0. This just provides some slight variation of the intensity to the RGB LEDs. Then when _raining is true, the variation slows down and intensity variation increases. Lastly, there are 3 intensity patterns to go with different music beats.

I was originally going to vary the green level, which is why a bunch of variables are named things like _greenOffset. I ended up applying that change as a 0-1 multiplier for the intensity though.

This thread is always running… but the problem seems to occur during a long period where it is the only active thread and raining = true and pattern = 0 . At this point it is waiting for the musicshield.position to reach a certain number, then it moves on.

Maybe 1 out of 3 times everything locks up, the music shield stops, and watchdog resets after 10 seconds. Only happens when I’m not in debug… I had it running connected to my computer and it went all night with no crash.

I just noticed that I am declaring my Random variable inside the while loop… so I’m guessing that is causing the garbage collector to run a lot? I’ll move that outside the While loop when I get home and give it a try. I’m more of a hardware guy who is trying to learn software… I understand OOP a lot better since I started this code and I really need to go back through and improve the entire program, but for now I just want to fix this crash.

static double _greenOffset = 1;
        static double _greenOffset2 = 1;
        static double _greenVariationFactor = 2.25;
        static bool _raining = false;
        static long _beatSpacing = 0;
        static int _beatPattern = 0;
        static int _delayBaseline = 10;
        static double _greenMin = .7;
        static int[] beatArray = new int[16] { 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0 };

        public static void GreenRandomizer()
        {
            long beatStart = 0;
            uint beatLength = 0;
            while (_ChannelFiveRunning == true)
            {
                if (_beatPattern == 0)
                {
                    Random G = new Random();
                    _greenOffset = ((double)1 - ((G.Next(5) * _greenVariationFactor) / 100));
                    if (_raining == true)
                    {
                        _delayBaseline = 25;
                        SetFloodLEDs();
                        SetLanternLEDs();
                        _greenVariationFactor = 6;
                    }
                    else
                    {
                        _greenVariationFactor = 2.25;
                        _delayBaseline = 10;
                    }
                    
                    Thread.Sleep(G.Next(20) + _delayBaseline);
                    _greenOffset2 = _greenOffset;

                }
                else
                {
                    if (_beatPattern == 1)
                    {
                        beatStart = MusicShield.positionRead;
                        beatLength = (uint)_beatSpacing / 6;
                        while (MusicShield.positionRead < beatStart + beatLength)
                        {
                            _greenOffset = 1;
                            _greenOffset2 = 1;
                            Thread.Sleep(10);
                        }

                        while (MusicShield.positionRead < beatStart + _beatSpacing)
                        {
                            _greenOffset = _greenMin;
                            _greenOffset2 = _greenMin;
                            Thread.Sleep(10);
                        }
                    }
                    if (_beatPattern == 2)
                    {
                        beatLength = (uint)_beatSpacing / 8;
                        for (int i = 1; i < 4 && _beatPattern == 2; i += 2)
                        {
                            beatStart = MusicShield.positionRead;
                            while (MusicShield.positionRead < beatStart + (beatLength * i) && _beatPattern == 2)
                            {   //on portion
                                _greenOffset = 1;
                                _greenOffset2 = 1;
                                Thread.Sleep(10);
                            }

                            while (MusicShield.positionRead < beatStart + beatLength + (beatLength * i) && _beatPattern == 2)
                            {   //off portion
                                _greenOffset = _greenMin;
                                _greenOffset2 = _greenMin;
                                Thread.Sleep(10);
                            }
                        }


                        while (MusicShield.positionRead < _beatSpacing + beatStart && _beatPattern == 2)
                        {   //rest
                            Thread.Sleep(10);
                        }
                    }
                    if (_beatPattern == 3)
                    {
                        int b = 0;
                        long pattern3pos = 0;
                        pattern3pos = MusicShield.positionRead;
                        beatLength = (uint)_beatSpacing / 4;
                        for (int i = 0; i < 16; i ++)
                        {
                            pattern3pos += beatLength;
                            
                            if (i == 0)
                                Debug.Print("111111111111111111111111111111");
                            else
                                Debug.Print((i+1).ToString());
                            while (MusicShield.positionRead < pattern3pos + beatLength)
                            {
                                if (beatArray[i] == 1)
                                {
                                    _greenOffset = 1;
                                    _greenOffset2 = 1;
                                }
                                else
                                {
                                    _greenOffset = _greenMin;
                                    _greenOffset2 = _greenMin;
                                }

                                Thread.Sleep(5);
                            }
                        }
                    }
                }
            }
            _greenOffset = 1;
            _greenOffset2 = 1;
        }

nice video.
some questions to your code
Is there another thread changing the state of

_ChannelFiveRunning 
_beatPattern 
_raining 

when _raining is true, and _beatPattern = 0 .
otherwise I saw a endless loop and no waiting [quote]for the musicshield.position to reach a certain num[/quote]

It actually does have a sleep in there during those conditions.

_delayBaseline = 25;

......

Thread.Sleep(G.Next(20) + _delayBaseline);

There is a thread that calls this one and then just waits until the music playback reaches a certain position. The Delay method just waits 100 milliseconds then checks the playback position. After that the main thread changes variables and runs different methods to do various things with the lights. Usually there are other things going on as well, like sin pulsation. This probably slowed down the thread and made the problems less prominent.

I moved the Random declaration out of the loop and optimized it more by creating a method to change the raining state when needed instead of repeatedly doing it in the loop. That fixed it right up and it ran for hours with no crash. I didn’t realize how sloppy the code was because I just blew through it in the beginning and it had always worked when debugging in VS!

It ended up being easy enough to fix… but I still would like to find a way to log exceptions for more complex problems in the future… although good practices no doubt go a long way.

Anyways thanks for the help! Here my lights are built into the scene. Cell phone pic, so it’s a bit grainy. I’ll post a video of the TRON bit playing later on.

what is the meaning of the _beatSpacing
are you sure that the end of

while (MusicShield.positionRead < beatStart + _beatSpacing)

is allways reachable

I also think it is threading related.

The purpose of that beat pattern is just to give an intensity increase on the lights in beat with the music at that point. So in my control thread I set the _beatspacing, which is the number of bytes of music between beats in the music playing. I then turn on that beat pattern on the first beat of the song and it pulses in sync.

I figured out that in my audio file there are about 16,0047 bytes per second, so it’s pretty easy to look at the waveform in Audacity and figure out the numbers for turning that on and also to measure time between beats.

Unfortunately I can’t put the entire show on Youtube… it gets knocked down for copyright on the music. I’m pretty sure no one would watch my video instead of buying the soundtrack… but oh well.

Well it ran for a good three hours last night with no hiccups… so I think cleaning up that sloppy code did the trick. Here is the updated thread

static void SetRain(bool rainOn)
        {
            if (rainOn == true)
            {
                _delayBaseline = 25;
                _greenVariationFactor = 6;
                _raining = true;
            }
            else
            {
                _greenVariationFactor = 2.25;
                _delayBaseline = 10;
                _raining = false;
            }
        }

        static double _greenOffset = 1;
        static double _greenOffset2 = 1;
        static double _greenVariationFactor = 2.25;
        static bool _raining = false;
        static long _beatSpacing = 0;
        static int _beatPattern = 0;
        static int _delayBaseline = 10;
        static double _greenMin = .7;
        static int[] beatArray = new int[16] { 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0 };

        public static void GreenRandomizer()
        {
            long beatStart = 0;
            uint beatLength = 0;
            Random G = new Random();
            while (_ChannelFiveRunning == true)
            {
                if (_beatPattern == 0)
                {
                    _greenOffset = ((double)1 - ((G.Next(5) * _greenVariationFactor) / 100));
                    if (_raining == true)
                        SetFloodLEDs();
   
                    Thread.Sleep(G.Next(20) + _delayBaseline);
                    _greenOffset2 = _greenOffset;

                    if (_raining == true)
                        SetLanternLEDs();
                }
                else
                {
                    if (_beatPattern == 1)
                    {
                        beatStart = MusicShield.positionRead;
                        beatLength = (uint)_beatSpacing / 6;
                        while (MusicShield.positionRead < beatStart + beatLength)
                        {
                            _greenOffset = 1;
                            _greenOffset2 = 1;
                            Thread.Sleep(10);
                        }

                        while (MusicShield.positionRead < beatStart + _beatSpacing)
                        {
                            _greenOffset = _greenMin;
                            _greenOffset2 = _greenMin;
                            Thread.Sleep(10);
                        }
                    }
                    if (_beatPattern == 2)
                    {
                        beatLength = (uint)_beatSpacing / 8;
                        for (int i = 1; i < 4 && _beatPattern == 2; i += 2)
                        {
                            beatStart = MusicShield.positionRead;
                            while (MusicShield.positionRead < beatStart + (beatLength * i) 
                                && _beatPattern == 2)
                            {   //on portion
                                _greenOffset = 1;
                                _greenOffset2 = 1;
                                Thread.Sleep(10);
                            }

                            while (MusicShield.positionRead < beatStart + beatLength + (beatLength * i)
                                && _beatPattern == 2)
                            {   //off portion
                                _greenOffset = _greenMin;
                                _greenOffset2 = _greenMin;
                                Thread.Sleep(10);
                            }
                        }


                        while (MusicShield.positionRead < _beatSpacing + beatStart && _beatPattern == 2)
                        {   //rest
                            Thread.Sleep(10);
                        }
                    }
                    if (_beatPattern == 3)
                    {
                        long pattern3pos = 0;
                        pattern3pos = MusicShield.positionRead;
                        beatLength = (uint)_beatSpacing / 4;
                        for (int i = 0; i < 16; i ++)
                        {
                            pattern3pos += beatLength;
                            
                            if (i == 0)
                                Debug.Print("111111111111111111111111111111");
                            else
                                Debug.Print((i+1).ToString());
                            while (MusicShield.positionRead < pattern3pos + beatLength)
                            {
                                if (beatArray[i] == 1)
                                {
                                    _greenOffset = 1;
                                    _greenOffset2 = 1;
                                }
                                else
                                {
                                    _greenOffset = _greenMin;
                                    _greenOffset2 = _greenMin;
                                }

                                Thread.Sleep(5);
                            }
                        }
                    }
                }
            }
            _greenOffset = 1;
            _greenOffset2 = 1;
        }