Serial Camera L2 Module take single image and save to microSD

It didn’t it goes to the timer eventhandler but cant reach the code inside if close I rerun the same code and after some tries now i have :
Failed allocation for 1097 blocks, 13164 bytes

A first chance exception of type ‘System.InvalidOperationException’ occurred in GTM.GHIElectronics.SerialCameraL2.dll
The thread ‘’ (0x5) has exited with code 0 (0x0).
A first chance exception of type ‘System.NullReferenceException’ occurred in GadgeteerApp1.exe
Exception was thrown: System.NullReferenceException

Hell is going on

Hmm. Try to force garbage collector at the beginning of ProgramStarted


Debug.GC(true); 

Also that method returns an uint number (number of free memory in bytes) Can you please print it out to the output window?

How to print it? I tried:


uint val = Debug.GC(true);
Debug.Print (val.tostring());

but i can’t see an output…

Also i did some other steps to solve my problem;

  1. Reinstall the Tinybootloader
  2. Reinstall the firmware

After i tried to run this code:


void ProgramStarted()
        {        
                   
            Debug.Print("Program Started");     
   
            serialCameraL2.ImageResolution = SerialCameraL2.Resolution.QVGA;
     
            serialCameraL2.StartStreaming();     

            timer = new GT.Timer(100);
   
            timer.Tick += timer_Tick;
  
            timer.Start(); 

        }

   private void timer_Tick(GT.Timer timer)
        {
           
            if (serialCameraL2.NewImageReady) // I cant reach this code 
            {
                DisplayStatus(1, "Taking a picture");

                byte[] data = serialCameraL2.GetImageData();


                if (VolumeInfo.GetVolumes()[0].IsFormatted)
                {
                    try
                    {

                        string rootDirectory = VolumeInfo.GetVolumes()[0].RootDirectory;
                        FileStream FileHandle = new FileStream(rootDirectory + @ "\picture.bmp", FileMode.Create);
                        FileHandle.Write(data, 0, data.Length);
                        FileHandle.Close();
                        Debug.Print("Picture stored on sd");
                        Debug.Print("Finalize volumes");
                        VolumeInfo[] vi = VolumeInfo.GetVolumes();
                        for (int i = 0; i < vi.Length; i++)
                            vi[i].FlushAll();
                        DisplayStatus(1, "Picture saved on SD");

                    }
                    catch (Exception exp)
                    {
                        Debug.Print(exp.Message.ToString());
                    }
                }
                else
                {
                    Debug.Print("Storage is not formatted. " + "Format on PC with FAT32/FAT16 first!");
                }

            }
            timer.Stop();     
            
        }



On the first load the code worked as expected and reached the DisplayStatus(1, “Picture saved on SD”); line, but other time after power reboot it hanged on DisplayStatus(1, “Taking a picture”);. And from boot to boot the behavior is definitely the same, one time it work as expected other time it hangs on DisplayStatus(1, “Taking a picture”);. Do you have any ideas?

your timer of 100msec is way WAY too short. Try 10000 as a reasonable first step, that might have been hiding some other issues. Then work towards your lower number in blocks.

If i set 10000 to the timer it doesn’t work at all.

I can’t finish my project because of this strange behavior… it seems like the file handling is not stable on Cerbuino bee… i have no more ideas…

Tell me please how to properly debug the netmf code. When the breakpoint goes to GHI methods it throws : No Source code Available

This is my StartCommunications() method:


 Debug.Print("Creating socket");       
            DisplayStatus(1, ">>" + name + ":" + port);

            _socket = new WiFlySocket(name, port, _wifi);

            Debug.Print("Connecting");

            try
            {
                _socket.Connect();
                DisplayStatus(1, "Wifi connected");
            }
            catch (Exception ex)
            {
                Debug.Print("Connection failed: ");
                Debug.Print(ex.ToString());
                DisplayStatus(1, "Wifi failed");
            }

            var t = new Thread(new ThreadStart(() =>
            {
                while (true)
                {
                    var cmd = _socket.Receive();

                    if (cmd.Length != 0)
                        ProcessCommand(cmd);

                }
            }));

            t.Start();

It seems like while(true) line of code doesn’t allow to start StartStreaming() method correctly because it blocks it… Can you advice how to transform the code to start work correctly?

can you help us understand what you are trying to achieve ? This last piece of code is the first time we’ve seen anything to do with wifly now !

You really need to break your problem down and test each portion independently.

If you need to capture a single image (because earlier your timer was stopped at the end of it) then just create a new thread that runs until the image is ready, with a thread.sleep(100) at the end of each loop. And if you don’t need to just capture one image, then iterate through the loop multiple times and note how often the image is ready.

If you need to store that image on an SD card, prove you can create a file, any file, and re-create that file after reboot.

If you need to handle a wifly connection then prove you can do that separately, and not rely on the SD card or the camera.

You can prove that a timer works by setting a timer that fires every 10 seconds (10,000 msec in the timer). Have it blink the mainboard LED and print out a message in debug to show you it’s running.

And finally, please show us ALL your code. You showed us little sections and not the whole thing that means we don’t know what else you’re doing.

Then, you will be able to piece all this together and achieve your goal

Edit: and don’t have a thread that just runs away and eats all processor time. Thread.Sleep (20) as a minimum at the end so that other threads have time to run !

1 Like

Try Thread.Sleep(20) at the end of the while loop as Brett suggested.

1 Like

Thank you for reply! Now i am trying to capture a single image and store it on SD. For test purpose i set the timer.Start() method in ProgramStarted() method, but finally i want to capture image and store it on SD by sending a “/take_picture” command to ProcessCommand(string command) method.

Here is my full code:


using System;
using System.Collections;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Net;
using Microsoft.SPOT.Presentation;
using Microsoft.SPOT.Presentation.Controls;
using Microsoft.SPOT.Presentation.Media;
using Microsoft.SPOT.Presentation.Shapes;
using Microsoft.SPOT.IO;
using Microsoft.SPOT.Touch;
using Toolbox.NETMF.Hardware;
using Toolbox.NETMF.NET;
using System.IO;
using GHI.IO;
using GHI.IO.Storage;


using Gadgeteer.Networking;
using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;
using Gadgeteer.Modules.GHIElectronics;
using System.Text;
using GHIElectronics.Gadgeteer;
using Microsoft.SPOT.Hardware;

namespace GadgeteerApp1
{
    public partial class Program
    {
        public GT.Timer timer = new GT.Timer(100);
        SimpleSocket _socket;       
        string name = "192.168.0.43"; //PC IP
        ushort port = 1988; //socket port

      

        // This method is run when the mainboard is powered up or reset. 
        void ProgramStarted()
        {
             
            Debug.Print("Program Started");                   
            timer.Tick += timer_Tick;
            serialCameraL2.ImageResolution = SerialCameraL2.Resolution.QVGA;
            serialCameraL2.StartStreaming();

            InitializeMotors();   
            InitializeDisplay();

            Thread t = new Thread(new ThreadStart(() =>
            {
               StartCommunications();
            }));

            t.Start();

            Debug.Print("Wify thread started");

        }

     
        private void timer_Tick(GT.Timer timer)
        {
           
            if (serialCameraL2.NewImageReady)
            {
               
                DisplayStatus(1, "Taking a picture!");

                byte[] data = serialCameraL2.GetImageData();


                if (VolumeInfo.GetVolumes()[0].IsFormatted)
                {
                    try
                    {

                        string rootDirectory = VolumeInfo.GetVolumes()[0].RootDirectory;
                        FileStream FileHandle = new FileStream(rootDirectory + @ "\picture.bmp", FileMode.Create);
                        FileHandle.Write(data, 0, data.Length);
                        FileHandle.Close();
                        Debug.Print("Picture stored on sd");
                        Debug.Print("Finalize volumes");
                        VolumeInfo[] vi = VolumeInfo.GetVolumes();
                        for (int i = 0; i < vi.Length; i++)
                            vi[i].FlushAll();
                        DisplayStatus(1, "Picture saved on SD");

                    }
                    catch (Exception exp)
                    {
                        Debug.Print(exp.Message.ToString());
                    }
                }
                else
                {
                    Debug.Print("Storage is not formatted. " + "Format on PC with FAT32/FAT16 first!");
                }
                data = null;
                timer.Stop();
            }

          
        }

        private void InitializeDisplay()
        {
            characterDisplay.Clear();
            characterDisplay.BacklightEnabled = true;            
        }

        private void DisplayStatus(byte row, string status)
        {
            if (status.Length < 20)
                status += new string(' ', 20 - status.Length);
            else
                status = status.Substring(status.Length - 20, 20);
            characterDisplay.SetCursorPosition(row, 0);            
            characterDisplay.Print(status);
        }
        
        private void InitializeMotors()
        {
            motorDriverL298.SetSpeed(MotorDriverL298.Motor.Motor1, 0);
            motorDriverL298.SetSpeed(MotorDriverL298.Motor.Motor2, 0);
        }
        
        private WiFlyGSX _wifi = new WiFlyGSX();

        private void StartCommunications()
        {
            _wifi.DebugMode = true;
            DisplayStatus(0, "Wify initialization");  

            _wifi.EnableStaticIP("192.168.0.62", "255.255.255.0", "192.168.0.1", "192.168.0.1");

            _wifi.JoinNetwork("BilityukA", 0, WiFlyGSX.AuthMode.WPA2_PSK, "New999manAlex");
          

            bool noIP = true;
            while (noIP)
            {
                noIP = _wifi.LocalIP == "0.0.0.0";
                System.Threading.Thread.Sleep(250);
            }

            Debug.Print("WiFly IP  :" + _wifi.LocalIP);
            Debug.Print("WiFly MAC :" + _wifi.MacAddress);

            DisplayStatus(0, "IP: " + _wifi.LocalIP);          
            EnableSockets();
            
        }
        
       
        private void EnableSockets()
        {
            Debug.Print("Creating socket");       
            DisplayStatus(1, ">>" + name + ":" + port);

            _socket = new WiFlySocket(name, port, _wifi);

            Debug.Print("Connecting");

            try
            {
                _socket.Connect();
                DisplayStatus(1, "Wifi connected");
            }
            catch (Exception ex)
            {
                Debug.Print("Connection failed: ");
                Debug.Print(ex.ToString());
                DisplayStatus(1, "Wifi failed");
            }

            var t = new Thread(new ThreadStart(() =>
            {
                while (true)
                {
                    var cmd = _socket.Receive();

                    if (cmd.Length != 0)
                        ProcessCommand(cmd);

                }
            }));

            t.Start();
        }

       
        private void ProcessCommand(string command) //Process robot commands
        {
            DisplayStatus(1, command);

            switch (command)
            {
                case "/robot/panic":
                    
                    break;
                case "/robot/move/forward":
                    motorDriverL298.SetSpeed(MotorDriverL298.Motor.Motor1, 1);
                    motorDriverL298.SetSpeed(MotorDriverL298.Motor.Motor2, 1);                  
                    break;
                case "/robot/move/backward":
                    motorDriverL298.SetSpeed(MotorDriverL298.Motor.Motor1, -1);
                    motorDriverL298.SetSpeed(MotorDriverL298.Motor.Motor2, -1); 
                    break;
                case "/robot/move/stop":
                    motorDriverL298.SetSpeed(MotorDriverL298.Motor.Motor1, 0);
                    motorDriverL298.SetSpeed(MotorDriverL298.Motor.Motor2, 0); 
                    break;
                case "/robot/turn/left":
                    motorDriverL298.SetSpeed(MotorDriverL298.Motor.Motor1, -1);
                    motorDriverL298.SetSpeed(MotorDriverL298.Motor.Motor2, 1); 
                    break;
                case "/robot/turn/right":
                    motorDriverL298.SetSpeed(MotorDriverL298.Motor.Motor1, 1);
                    motorDriverL298.SetSpeed(MotorDriverL298.Motor.Motor2, -1); 
                    break;
                case "/robot/turn/stop":
                    motorDriverL298.SetSpeed(MotorDriverL298.Motor.Motor1, 0);
                    motorDriverL298.SetSpeed(MotorDriverL298.Motor.Motor2, 0);
                    break;
                case "/connection closed":
                    characterDisplay.Clear();
                    DisplayStatus(0, "Reset to reconnect");                                                  
                    break;
                case "/take_picture":
                    timer.Start();                 
                    break;
               
            }           
            
        }

    }
}


Can you advice how to tune the code to make it work please…
And let me know where to find a source code for debugging please?

well, first thing I would do is get rid of the stuff not needed. Wifly, motors. Work on a minimal app.


             var t = new Thread(new ThreadStart(() =>
             {
                 while (true)
                 {
                     var cmd = _socket.Receive();

                     if (cmd.Length != 0)
                         ProcessCommand(cmd);

                 }
             }));

             t.Start();

As I said earlier, I think this is your problem. This thread will consume all processor time and not allow anything else to run. Add Thread.Sleep(20); as the last step in your WHILE loop and things should behave differently.

;D
Here we go guys!!! I cant stand without you))) I could save a picture on SD card by sending a wifi command “to take picture”.

  1. I commented all my code lines with a Debug.Print() method to see a steps in debugger
  2. I set up a timer to 500 msec, i tried 10000 and many different settings, but i think this is a proper timer setting because it is taken the lowest time to capture image
  3. I added thread.Sleep(20) to the end of the loop as was suggested
  4. Finally i could capture an image, but i still have some questions…

Here is my commented piece of timer code:


private void timer_Tick(GT.Timer timer)
        {
            Debug.Print("Inside timer tick");
            DisplayStatus(1, "Preparing a camera");
            try
            {

                if (serialCameraL2.NewImageReady)
                {
                    Debug.Print("Newimageready");
                    DisplayStatus(1, "Taking a picture...");                    
                    data = serialCameraL2.GetImageData();
                    Debug.Print("Imagedata ready");                    
                    if (VolumeInfo.GetVolumes()[0].IsFormatted)
                    {
                        Debug.Print("SD is formated");
                        string rootDirectory = VolumeInfo.GetVolumes()[0].RootDirectory;
                        Debug.Print("Rootdirectory ready");
                        FileHandle = new FileStream(rootDirectory + @ "\picture.bmp", FileMode.Create);
                        Debug.Print("File handle ready");                        
                        FileHandle.Write(data, 0, data.Length);
                        Debug.Print("File write operation success");
                        FileHandle.Close();
                        Debug.Print("File handle closed success");
                        VolumeInfo[] vi = VolumeInfo.GetVolumes();
                        for (int i = 0; i < vi.Length; i++)
                            vi[i].FlushAll();
                        Debug.Print("Finalize volumes success");
                        DisplayStatus(1, "Picture saved on SD");
                        timer.Stop();
                        Debug.Print("Timer stoped");

                    }
                    else
                    {
                        Debug.Print("Storage is not formatted. " + "Format on PC with FAT32/FAT16 first!");
                    }

                   
                }
               
            }
            catch (Exception exp)
            {
                if (FileHandle != null)
                {
                    FileHandle.Close();
                    Debug.Print("FileHandle closed in exception mode");
                }
                DisplayStatus(1, "Picture_Error");                
                Debug.Print(exp.ToString());
            }

          
        }

Here is debugger output:


Inside timer tick
Inside timer tick
Inside timer tick
Inside timer tick
Inside timer tick
Inside timer tick
Inside timer tick
Inside timer tick
Inside timer tick
Inside timer tick
Newimageready
Imagedata ready
SD is formated
Rootdirectory ready
File handle ready
A first chance exception of type 'System.NullReferenceException' occurred in GadgeteerApp1.exe
FileHandle closed in exception mode
System.NullReferenceException
Inside timer tick
Inside timer tick
Inside timer tick
Inside timer tick
Inside timer tick
Inside timer tick
Inside timer tick
Inside timer tick
Inside timer tick
Inside timer tick
Inside timer tick
Inside timer tick
Inside timer tick
Inside timer tick
Newimageready
Imagedata ready
SD is formated
Rootdirectory ready
File handle ready
A first chance exception of type 'System.NullReferenceException' occurred in GadgeteerApp1.exe
FileHandle closed in exception mode
System.NullReference Exception
Inside timer tick
Inside timer tick
Inside timer tick
Inside timer tick
Inside timer tick
Inside timer tick
Inside timer tick
Inside timer tick
Inside timer tick
Inside timer tick
Inside timer tick
Newimageready
Imagedata ready
SD is formated
Rootdirectory ready
File handle ready
File write operation success
File handle closed success
Finalize volumes success
Timer stoped

We can see that before the timer stopped correctly it was a lot of iterations and exceptions:

  1. why is a camera NewImageReady method takes to long to prepare an image, how to prepare the image in the first timer.Tick?
  2. why do i have a first chance exception of type ‘System.NullReferenceException’ occurred in GadgeteerApp1.exe ?
  3. why do i have a System.NullReferenceException ?
  4. When i ejected SD after succesfully captured image see a picture on my PC to make sure everything is ok with image and inserted it back to sd slot i saw the folowing exceptions in debugger output:

A first chance exception of type 'System.Exception' occurred in GHI.Hardware.dll
A first chance exception of type 'System.InvalidOperationException' occurred in GTM.GHIElectronics.SerialCameraL2.dll

and when i try to capture the image one more time i see the following output in debugger window:


Inside timer tick
Inside timer tick
Inside timer tick
Newimageready
Imagedata ready
A first chance exception of type 'System.IndexOutOfRangeException' occurred in GadgeteerApp1.exe
Failed allocation for 1044 blocks, 12528 bytes

FileHandle closed in exception mode
System.IndexOutOfRangeException
Inside timer tick
Inside timer tick
Inside timer tick
Inside timer tick
Inside timer tick
Inside timer tick
Newimageready
Imagedata ready
A first chance exception of type 'System.IndexOutOfRangeException' occurred in GadgeteerApp1.exe
FileHandle closed in exception mode
System.IndexOutOfRangeException
Inside timer tick
Inside timer tick
Inside timer tick
Inside timer tick

It never stops… it happens only when i eject and insert SD back to slot. If i dont touch the sd after mainboard started and initiallized everything is ok. I can capture in any time…

1)How to handle this SD behavior?
2) Why do i have a System.IndexOutOfRangeException?

OK, here goes. I’m going to give you some really direct feedback here :slight_smile: Please don’t take offence if it’s too direct !

You can also set breakpoints in the debugger so you can see the actual values that exist in any pass through your code. F9 sets one, and when it is hit you can then use F10/F11 to step over/into code blocks as needed. But adding printed output like this is a cool way to get visibility of what is going on

[quote] 2) I set up a timer to 500 msec, i tried 10000 and many different settings, but i think this is a proper timer setting because it is taken the lowest time to capture image[/quote] [quote]1) why is a camera NewImageReady method takes to long to prepare an image, how to prepare the image in the first timer.Tick?[/quote] You’re mixing two very different things here. Think about the NewImageReady as a flag that tells you the hardware portion of the camera has done it’s bit - that takes as long as it takes and is something you can’t control. You use this flag so you don’t try to get an image from the device when it’s incomplete. This has nothing to do with timers, it just takes time. If you’re using a timer, it will take as many timer ticks as it takes, there’s nothing you can do. If however you used an 10000msec timer, you may find that it only takes two ticks for the flag to be set. But based on your example here, it seems it’s about 5 seconds before the image is ready.

[quote]2) why do i have a first chance exception of type ‘System.NullReferenceException’ occurred in GadgeteerApp1.exe ?
3) why do i have a System.NullReferenceException ?
[/quote]
Because there’s a null reference somewhere. This is why we need full code. The snippet you showed us is not self contained, we can’t see where some of your objects are defined so we can’t really tell you what is causing this - but if I had to guess, I would say your definition of DATA is being out of scoped and garbage collected. Also remember the above stepping in debug - add a breakpoint in your newimageready section and see what looks to be out of scope as you step through your code

[quote]4) When i ejected SD after succesfully captured image see a picture on my PC to make sure everything is ok with image and inserted it back to sd slot i saw the folowing exceptions in debugger output:[/quote] mishandling of SD card - or more correctly, not handling cases where no SD card is mounted or when it is remounted while your code is running. There are many good codeshare entries that show handling of storage - personally I like to use a push button to trigger the dismount of the storage cleanly and another button press to remount it.

[quote]A first chance exception of type ‘System.IndexOutOfRangeException’ occurred in GadgeteerApp1.exe
FileHandle closed in exception mode
System.IndexOutOfRangeException
Inside timer tick[/quote]
A consequence of the last point. Again, if you use the debugger more you’ll find out what line of code this is being thrown on, but my bet is:


because it has an index - it's likely that your card has not been mounted so the VolumeInfo can't be retrieved.  Codeshare.  And actually, probably create a test app that just handles files !! I think I may have suggested this earlier too :) It's why a methodical decomposition of the things you need will help you understand more, you don't need to understand all the intricacies of the camera and timers and anything else you throw in the app, you just need to focus on the storage handling and how to cater for the scenarios you'll come across.
1 Like

Ohh… i want to thank you for really full answer… it looks so long))

I tried to use a breakepoints, but i dont have a source code of gadgeteer modules to start debugging. I opend a new thread about this. When i press F10 and arrow hits a gadgeteer module code it throws a window asking to give a direction to gadgeteer module source code.

I already posted a full code in this thread… this is my full code of my gadgeteer project. I can provide a link to full project if it will help.

Thank you for advice i will take a look on codeshare…

Hi guys! Help me to find a solution. What the matter when i run the code in debug mode it runs as expected i can see a proper output messages and it saves picture to SD, but when i run it without debug mode just on my device only (CTRL+F5) it doesn’t save a picture as expected… It throws System.OutOfMemory Exception… i can see that in my charachter display.

I posted the full programm code before, here is timer tick where exception is shown:


 private void timer_Tick(GT.Timer timer)
        {
            Debug.Print("Inside timer tick");
            DisplayStatus(1, "Preparing a camera");
            try
            {

                if (serialCameraL2.NewImageReady)
                {
                    Debug.Print("Newimageready");
                    data = serialCameraL2.GetImageData();
                   if (data != null)
                   {
                        DisplayStatus(1, "Taking a picture...");
                        Debug.Print("Imagedata ready");
                        if (VolumeInfo.GetVolumes()[0].IsFormatted)
                        {
                            Debug.Print("SD is formated");
                            rootDirectory = VolumeInfo.GetVolumes()[0].RootDirectory;
                            Debug.Print("Rootdirectory ready");                         
                                               
                            FileHandle = new FileStream(rootDirectory + @ "\picture_" + num.ToString() + ".bmp", FileMode.Create);
                            Debug.Print("File handle ready");                            
                            FileHandle.Write(data, 0, data.Length);                       
                            FileHandle.Close();
                            Debug.Print("File handle closed success");
                            VolumeInfo[] vi = VolumeInfo.GetVolumes();
                            for (int i = 0; i < vi.Length; i++)
                                vi[i].FlushAll();
                            Debug.Print("Finalize volumes success");
                            DisplayStatus(1, "Picture saved on SD");
                                                      
                            timer.Stop();
                           
                            Debug.Print("Timer stoped");
                            num = 0;
                        }
                        else
                        {
                            Debug.Print("Storage is not formatted. " + "Format on PC with FAT32/FAT16 first!");
                        }
                    }
                    else 
                    {
                       Debug.Print("ImageData = null");
                       throw new System.ApplicationException("Image Data is null");
                    }

                }

            }
            catch (Exception exp)
            {
                if (FileHandle != null)
                {
                    FileHandle.Close();
                    Debug.Print("FileHandle closed in exception mode");
                }
                DisplayStatus(1, exp.Message.ToString());                
                Debug.Print(exp.ToString());
            }
            
        }

I cant catch the OutOfMemory exception because it is not shown in debug mode…

@ Alex Bilityuk - What line of code throws the exception?

Also, stop the timer right after you found out that image is ready


if (serialCameraL2.NewImageReady)
{
   timer.Stop();
   ....
}
1 Like

OOM = you’re out of memory ! Something you’re creating is hanging around.

In fact, lets get to the heart of this. GC will fix many things for you. Except perhaps timers. Why do you need a timer ? You only ever execute it once, on demand, why even bother with a timer - just use a thread.

As @ Architect suggests, stopping the timer early before you do things that could cause you to queue up the next timer pass might also help. But a timer just seems the wrong pattern to use here

1 Like

O my god… still doesn’t work. i tried to put the timer.Stop() as you suggested. In debug mode the code works fast and perfect. In realease mode it throws exception and i don’t know what line of code throws an exception because i am not in the debbug mode… How to find out wich line of code throws an exception in realease mode?