SerCam stepping out of line (double pictures)... wat?

My Serial Camera L1 Module (batch #447) appears to be taking two pictures, when I have only requested one… I can’t really explain it, and I’ve been trying to debug it for ~20 hours.

The issue I have is that serCam.TakePicture() sometimes causes the camera to freeze up; saying: “Cannot take picture at this time” when I request (via WebEventHandlers) pictures faster than it can take them… That’s not really an issue; I would totally love to wait for the camera to be done, but when I get that message “Cannot take picture at this time”; it’s almost surely a sign that the camera will freeze up (and future web requests time out)… Eventually the camera does unfreeze, something like 5 minutes… I added a timeout of 30 seconds to the WebRequest and a dirty timeout (since serCam.thread is private) to the web event handler: i.e. the camera has been busy too long, time to send a response that it’s exceptionally lame.

I’m totally open to the idea that the problem is being caused by me. I have multiple Cobra II boards, and multiple serial camera modules. No combo can surmount this issue; in my mind…

Almost certainly related is another issue… After requesting ~10 or 20 pictures, the board eventually freaks out and completely freezes (must be reset)… I never stick around long enough to see if it will unfreeze (freeze for 10+ minutes). the GC.Debug() shows plenty of memory; which makes me suspect that there isn’t a memory leak when handling the images.
However… The Debugger doesn’t even recognize the board’s real mac address; so I wouldn’t know if I could/should trust the output from Debug.GC() or not.

On a side note; I am very pleased with the quality of the pictures :slight_smile:

// <auto-generated>
//     This code was generated by the Gadgeteer Designer.
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>

using Gadgeteer;
using GTM = Gadgeteer.Modules;
using Gadgeteer.Modules.GHIElectronics;

namespace GadgeteerApp1
    public partial class Program : Gadgeteer.Program
        // GTM.Module definitions
        public static Gadgeteer.Modules.GHIElectronics.SerCam serCam;

        public static void Main()
            //Important to initialize the Mainboard first
            Mainboard = new GHIElectronics.Gadgeteer.FEZCobra_II();			

            Program program = new Program();
            program.Run(); // Starts Dispatcher

        private void InitializeModules()
            // Initialize GTM.Modules and event handlers here.		
            serCam = new GTM.GHIElectronics.SerCam(5);
            serCam.StartDataCaptured += new SerCam.StartDataCapturedEventHandler(PMCam_StartDataCaptured);
            serCam.OnDataCaptured += new SerCam.DataCapturedEventHandler(PMCam_OnDataCaptured);
            serCam.FinishDataCaptured += new SerCam.FinishDataCapturedEventHandler(PMCam_FinishDataCaptured);


using System;
using System.Threading;
using Microsoft.SPOT;

using Gadgeteer.Networking;
using GHINET = GHI.Premium.Net;
using GHI.Premium.Hardware;
using Gadgeteer.Modules.GHIElectronics;

namespace GadgeteerApp1 {
    public partial class Program {

         * <summary>
         * This is the web server port that is hosted on the localhost (the board running this code) 
         * </summary>
        const int WEB_SERVER_PORT = 80;

         * <summary>
         *   This is "name" of the wireless network.
         * </summary>
        private static string WIRELESS_SSID = "***";

         * <summary>
         *   This is "password"/key to join the wireless network.
         * </summary>
        private static string WIRELESS_PASS = "***"; //WPA2 incase it matters for this forum post
        public static GHINET.WiFiRS9110 wifi;
        public static Boolean webServerStarted = false;

         * <summary>
         *   This is a buffer to hold the image (combine the fragments) 
         *   after Camera.OnDataCaptured is called.
         *   @ TODO check if this image can be unbuffered (this would be fastest),
         *   or maybe it should be buffered incase the WebResponse fails to go through?
         * </summary>
        public static byte[] bitmapData;

         * <summary>
         *   This holds the offset for the byte[] datajpg variable.
         *   It's only used by the serial camera.
         * </summary>
        private int serialCameraBufferedImageIndex;

        public void ProgramStarted() {

            // initialize wifi
            wifi = new GHINET.WiFiRS9110(Microsoft.SPOT.Hardware.SPI.SPI_module.SPI2, G120.Pin.P1_10, G120.Pin.P2_11, G120.Pin.P1_9, 4000);

            if (!wifi.IsOpen)

            if (!wifi.NetworkInterface.IsDhcpEnabled)

            wifi.NetworkAddressChanged += new GHINET.NetworkInterfaceExtension.NetworkAddressChangedEventHandler(wifi_NetworkAddressChanged);
            wifi.WirelessConnectivityChanged += new GHINET.WiFiRS9110.WirelessConnectivityChangedEventHandler(wifi_WirelessConnectivityChanged);

            GHINET.WiFiNetworkInfo[] scanResult = wifi.Scan();

            // scan for the wifi AP i intend to connect to
            for (int i = 0; i < scanResult.Length; i++)
                if (scanResult[i].SSID == WIRELESS_SSID) {
                    wifi.Join(scanResult[i], WIRELESS_PASS);
                    break; // once found, stop iterating. the rest of the results are useless (unless evil twin attack)


        static byte[] GetBytes(string str) {
            byte[] bytes = new byte[str.Length * sizeof(char)];
            Array.Copy(str.ToCharArray(), bytes, bytes.Length);
            return bytes;

        static void wifi_WirelessConnectivityChanged(object sender, GHINET.WiFiRS9110.WirelessConnectivityEventArgs e) {

        static void wifi_NetworkAddressChanged(object sender, EventArgs e) {
            /* Start the HTTPD server every time the network address changes */
            if (wifi.IsActivated) {
                webServerStarted = true;
                //WebServer.StartLocalServer(wifi.NetworkInterface.IPAddress, WEB_SERVER_PORT);
                /* Stop the HTTP Server... since we aren't connected */
            else {
                webServerStarted = false;

        static void webEventReceivedPictureHandler(string path, WebServer.HttpMethod method, Responder responder) {
            int sleeping = 0;
            while (serCam.isBusy) {
                sleeping += 200;
                Debug.Print("Sleeping " + sleeping);
                if (sleeping > 3000) {
                    responder.Respond(GetBytes("The camera took exceptionally long to generate a picture!"), "text/html");
            responder.Respond(bitmapData, "image/bmp");

        public static void startHTTPServer() {
            WebEvent webEventtakepicture;
            Debug.Print("Starting the Web Server listening on " + wifi.NetworkInterface.IPAddress + ":" + WEB_SERVER_PORT.ToString());
            WebServer.StartLocalServer(wifi.NetworkInterface.IPAddress, WEB_SERVER_PORT);
            webServerStarted = true;
            /* this web event does not seem to be working properly... */
            webEventtakepicture = WebServer.SetupWebEvent("picture");
            webEventtakepicture.WebEventReceived += new WebEvent.ReceivedWebEventHandler(webEventReceivedPictureHandler);
            Debug.Print("Handlers have been added to the web server. " +
                "try: http://" + wifi.NetworkInterface.IPAddress + ":" + WEB_SERVER_PORT + "/picture");

        void PMCam_StartDataCaptured(SerCam sender, int sizeImage) {
            sender.DebugPrintEnabled = true;
            Debug.Print("Starting to take picture");
            Debug.Print("(sender.ToString()): " + (sender.ToString()));
            Debug.Print("Image Size (Bytes): " + sizeImage.ToString());
            serialCameraBufferedImageIndex = 0;
            bitmapData = new byte[sizeImage];

        void PMCam_OnDataCaptured(SerCam sender, byte[] data) {
            sender.DebugPrintEnabled = true;
            if (serialCameraBufferedImageIndex + data.Length > bitmapData.Length)
                throw new Exception("Error");
            Array.Copy(data, 0, bitmapData, serialCameraBufferedImageIndex, data.Length);
            serialCameraBufferedImageIndex += data.Length;

        void PMCam_FinishDataCaptured(SerCam sender) {


Debug Output:

Found debugger!

Create TS.

 Loading start at a0e856b0, end a0e9ce0c

   Assembly: mscorlib (     Assembly: Microsoft.SPOT.Native (     Assembly: Microsoft.SPOT.Hardware (  
   Assembly: Microsoft.SPOT.Hardware.PWM (     Assembly: Microsoft.SPOT.Security.PKCS11 (  
   Assembly: System.Security (  Loading Deployment Assemblies.

Attaching deployed file.

   Assembly: Microsoft.SPOT.IO (  Attaching deployed file.

   Assembly: GHI.Premium.IO (  Attaching deployed file.

   Assembly: Microsoft.SPOT.Graphics (  Attaching deployed file.

   Assembly: System.Http (  Attaching deployed file.

   Assembly: System (  Attaching deployed file.

   Assembly: Microsoft.SPOT.Net.Security (  Attaching deployed file.

   Assembly: Gadgeteer.WebServer (  Attaching deployed file.

   Assembly: GHI.Premium.System (  Attaching deployed file.

   Assembly: Microsoft.SPOT.TinyCore (  Attaching deployed file.

   Assembly: Gadgeteer.Serial (  Attaching deployed file.

   Assembly: GadgeteerApp1 (  Attaching deployed file.

   Assembly: System.Net.Security (  Attaching deployed file.

   Assembly: GHI.Premium.Net (  Attaching deployed file.

   Assembly: System.IO (  Attaching deployed file.

   Assembly: Microsoft.SPOT.Net (  Attaching deployed file.

   Assembly: GTM.GHIElectronics.SerCam (  Attaching deployed file.

   Assembly: Microsoft.SPOT.Touch (  Attaching deployed file.

   Assembly: GHI.Premium.Hardware (  Attaching deployed file.

   Assembly: Gadgeteer (  Attaching deployed file.

   Assembly: GHIElectronics.Gadgeteer.FEZCobra_II (  Attaching deployed file.

   Assembly: Microsoft.SPOT.Hardware.SerialPort (  Attaching deployed file.

   Assembly: GHI.Premium.Hardware.G120 (  Resolving.

GC: 3msec 527844 bytes used, 6811824 bytes available

Type 0F (STRING              ):     24 bytes

Type 15 (FREEBLOCK           ): 6811824 bytes

Type 17 (ASSEMBLY            ):  35064 bytes

Type 1E (BINARY_BLOB_HEAD    ): 492684 bytes

Type 34 (APPDOMAIN_HEAD      ):     72 bytes

GC: performing heap compaction...

The debugging target runtime is loading the application assemblies and starting execution.

'Microsoft.SPOT.Debugger.CorDebug.dll' (Managed): Loaded 'C:\Program Files (x86)\Microsoft .NET Micro Framework\v4.2\Assemblies\le\mscorlib.dll', Symbols loaded.
'Microsoft.SPOT.Debugger.CorDebug.dll' (Managed): Loaded 'C:\Program Files (x86)\Microsoft .NET Micro Framework\v4.2\Assemblies\le\Microsoft.SPOT.Native.dll', Symbols loaded.
'Microsoft.SPOT.Debugger.CorDebug.dll' (Managed): Loaded 'C:\Program Files (x86)\Microsoft .NET Micro Framework\v4.2\Assemblies\le\Microsoft.SPOT.Hardware.dll', Symbols loaded.
'Microsoft.SPOT.Debugger.CorDebug.dll' (Managed): Loaded 'C:\Program Files (x86)\Microsoft .NET Micro Framework\v4.2\Assemblies\le\Microsoft.SPOT.Hardware.PWM.dll', Symbols loaded.
'Microsoft.SPOT.Debugger.CorDebug.dll' (Managed): Loaded 'C:\Program Files (x86)\Microsoft .NET Micro Framework\v4.2\Assemblies\le\Microsoft.SPOT.Security.PKCS11.dll', Symbols loaded.
'Microsoft.SPOT.Debugger.CorDebug.dll' (Managed): Loaded 'C:\Program Files (x86)\Microsoft .NET Micro Framework\v4.2\Assemblies\le\System.Security.dll', Symbols loaded.
'Microsoft.SPOT.Debugger.CorDebug.dll' (Managed): Loaded 'C:\Program Files (x86)\Microsoft .NET Micro Framework\v4.2\Assemblies\le\Microsoft.SPOT.IO.dll', Symbols loaded.
'Microsoft.SPOT.Debugger.CorDebug.dll' (Managed): Loaded 'C:\Program Files (x86)\GHI Electronics\GHI Premium NETMF v4.2 SDK\Assemblies\le\GHI.Premium.System.dll'
'Microsoft.SPOT.Debugger.CorDebug.dll' (Managed): Loaded 'C:\Program Files (x86)\GHI Electronics\GHI Premium NETMF v4.2 SDK\Assemblies\le\GHI.Premium.IO.dll'
'Microsoft.SPOT.Debugger.CorDebug.dll' (Managed): Loaded 'C:\Program Files (x86)\Microsoft .NET Micro Framework\v4.2\Assemblies\le\Microsoft.SPOT.Graphics.dll', Symbols loaded.
'Microsoft.SPOT.Debugger.CorDebug.dll' (Managed): Loaded 'C:\Program Files (x86)\Microsoft .NET Micro Framework\v4.2\Assemblies\le\Microsoft.SPOT.Net.dll', Symbols loaded.
'Microsoft.SPOT.Debugger.CorDebug.dll' (Managed): Loaded 'C:\Program Files (x86)\Microsoft .NET Micro Framework\v4.2\Assemblies\le\System.dll', Symbols loaded.
'Microsoft.SPOT.Debugger.CorDebug.dll' (Managed): Loaded 'C:\Program Files (x86)\Microsoft .NET Micro Framework\v4.2\Assemblies\le\Microsoft.SPOT.Net.Security.dll', Symbols loaded.
'Microsoft.SPOT.Debugger.CorDebug.dll' (Managed): Loaded 'C:\Program Files (x86)\Microsoft .NET Micro Framework\v4.2\Assemblies\le\System.Net.Security.dll', Symbols loaded.
'Microsoft.SPOT.Debugger.CorDebug.dll' (Managed): Loaded 'C:\Program Files (x86)\Microsoft .NET Micro Framework\v4.2\Assemblies\le\System.Http.dll', Symbols loaded.
'Microsoft.SPOT.Debugger.CorDebug.dll' (Managed): Loaded 'C:\Program Files (x86)\Microsoft .NET Micro Framework\v4.2\Assemblies\le\Microsoft.SPOT.TinyCore.dll', Symbols loaded.
'Microsoft.SPOT.Debugger.CorDebug.dll' (Managed): Loaded 'C:\Program Files (x86)\Microsoft .NET Micro Framework\v4.2\Assemblies\le\System.IO.dll', Symbols loaded.
'Microsoft.SPOT.Debugger.CorDebug.dll' (Managed): Loaded 'C:\Program Files (x86)\Microsoft .NET Gadgeteer\Core\Assemblies\.NET Micro Framework 4.2\le\Gadgeteer.dll', Symbols loaded.
'Microsoft.SPOT.Debugger.CorDebug.dll' (Managed): Loaded 'C:\Program Files (x86)\Microsoft .NET Gadgeteer\Core\Assemblies\.NET Micro Framework 4.2\le\Gadgeteer.WebServer.dll', Symbols loaded.
'Microsoft.SPOT.Debugger.CorDebug.dll' (Managed): Loaded 'C:\Program Files (x86)\Microsoft .NET Micro Framework\v4.2\Assemblies\le\Microsoft.SPOT.Hardware.SerialPort.dll', Symbols loaded.
'Microsoft.SPOT.Debugger.CorDebug.dll' (Managed): Loaded 'C:\Program Files (x86)\Microsoft .NET Gadgeteer\Core\Assemblies\.NET Micro Framework 4.2\le\Gadgeteer.Serial.dll', Symbols loaded.
'Microsoft.SPOT.Debugger.CorDebug.dll' (Managed): Loaded 'C:\Program Files (x86)\GHI Electronics\GHI Premium NETMF v4.2 SDK\Assemblies\le\GHI.Premium.Net.dll'
'Microsoft.SPOT.Debugger.CorDebug.dll' (Managed): Loaded 'C:\Program Files (x86)\GHI Electronics\GHI .NET Gadgeteer SDK\Modules\SerCam\NETMF 4.2\le\GTM.GHIElectronics.SerCam.dll', Symbols loaded.
'Microsoft.SPOT.Debugger.CorDebug.dll' (Managed): Loaded 'C:\Program Files (x86)\GHI Electronics\GHI Premium NETMF v4.2 SDK\Assemblies\le\GHI.Premium.Hardware.dll'
'Microsoft.SPOT.Debugger.CorDebug.dll' (Managed): Loaded 'C:\Program Files (x86)\GHI Electronics\GHI .NET Gadgeteer SDK\Mainboards\FEZCobra_II\NETMF 4.2\le\GHIElectronics.Gadgeteer.FEZCobra_II.dll', Symbols loaded.
'Microsoft.SPOT.Debugger.CorDebug.dll' (Managed): Loaded 'C:\Users\ethos-one\AppData\Local\Temporary Projects\GadgeteerApp1\bin\Debug\le\GadgeteerApp1.exe', Symbols loaded.
'Microsoft.SPOT.Debugger.CorDebug.dll' (Managed): Loaded 'C:\Program Files (x86)\Microsoft .NET Micro Framework\v4.2\Assemblies\le\Microsoft.SPOT.Touch.dll', Symbols loaded.
'Microsoft.SPOT.Debugger.CorDebug.dll' (Managed): Loaded 'C:\Program Files (x86)\GHI Electronics\GHI Premium NETMF v4.2 SDK\Assemblies\le\GHI.Premium.Hardware.G120.dll'
The thread '<No Name>' (0x2) has exited with code 0 (0x0).
Using mainboard GHI Electronics FEZCobra II version 1.0
RS9110 firmware version Number is 4.4.5
RS9110 driver version Number is 4.4.5
The thread '<No Name>' (0x3) has exited with code 0 (0x0).
Starting the Web Server listening on
Web server started at
Handlers have been added to the web server. try:
The thread '<No Name>' (0x6) has exited with code 0 (0x0).
Sleeping 200
Sleeping 400
Sleeping 600
Starting to take picture
(sender.ToString()): SerCam
Image Size (Bytes): 12608
Sleeping 800
Sleeping 1000
Sleeping 1200
Sleeping 1400
Sleeping 1600
Sleeping 1800
The thread '<No Name>' (0x8) has exited with code 0 (0x0).
Sleeping 2000
The thread '<No Name>' (0x7) has exited with code 0 (0x0).
Sleeping 200
Sleeping 400
Sleeping 600
Starting to take picture
(sender.ToString()): SerCam
Image Size (Bytes): 12696
Sleeping 800
Sleeping 1000
Sleeping 1200
Sleeping 1400
Sleeping 1600
Sleeping 1800
Sleeping 2000
The thread '<No Name>' (0xa) has exited with code 0 (0x0).
Sleeping 2200

Edit: This debug output is from requesting a single picture. I confirm with wireshark that this is the case.

huge buffer of karma for anyone who can return my sanity :slight_smile:

Oh… I noticed that it’s actually the web event handler that’s causing the issue…
I’m not really sure why it’s being invoked twice…

When things do not work as expected, we normally run a simple project to test the one part that s not working.

By the way, can you please set your user name. We like to know who we are talking to :slight_smile:

Hi “-1”

Yes, you’ve said your handler is called twice. THAT is where I’d start to look. don’t bother with the camera yet but put diagnostic logging in there, like “Asked to take a picture at X time by requestor Y”, as well as breakpoints :slight_smile:

I did step through it with a web event that returns a static string (“Test/Hello world!”). This uses all of the same set up as returning a picture otherwise would. It is only called once…

I believe there are some side effects either in the debugger (Visual C# express 2010) or possibly from the camera itself. I will need to get the SerCam_42.cs source, and step through it I suppose…

Also, I did pick User_-1, I think it’s a funny name because of the bitmodel used for two’s compliment VS magnitude only :slight_smile: hehehe… if someone tried to look at all the usernames that match User_*, and try to stuff the number behind mine into a magnitude only model, then they might just learn something :stuck_out_tongue:

@ User_-1 - I don’t know anything about the serial camera module, and I don’t know much about Gadgeteer, so my suggestion may be way off, but…

I noticed that inside the web event handler you have a while loop and do a potentially long Thread.Sleep. Instead you should perhaps start a timer that checks for the camera being not busy.

that is older driver, use this one