Serial Camera + LCD

I am getting the following error:

A first chance exception of type ‘System.NotImplementedException’ occurred in Microsoft.SPOT.Graphics.dll

on the line:

Bitmap image = new Bitmap(dataImage, Bitmap.BitmapImageType.Jpeg);

from the sample code:

https://www.ghielectronics.com/docs/176/serial-camera-module

Is there something I missed? I can write to a file (although the image is black) it “appears” as though the camera may not be functioning.

Any suggestions?

Still loving this though…

Thanks in advance.

I should add that the code that is generating the error is in the method that is found in the sercam_42 class:

public void DrawImage(Bitmap bitmap, int xBitmap, int yBitmap, int width, int height)

Thanks

The error implies to me that the bitmap class doesn’t exist on the board you’re using. Can you tell us what mainboard you’re using? I suspect you’re using a cerb family device, and if so the challenge you will face is memory constraints so the code provided won’t be able to buffer the captured image straight to the LCD

I have the cerbot - so you are correct. If, I understand correctly, I should store to the microSD and then retrieve it from there?

I noticed that the image is black on their too.

Thanks for the help.

The Cerb family devices definitely support Bitmaps, the problem with the call is that the Cerb devices do not support Jpeg, only BMP.

Of course Brett’s point on memory constraints stand, that is always a real challenge with working with bitmaps on the Cerb devices.

@ Kwaugh32 - [quote]

FileStream imgFile = new FileStream(pathFileName, FileMode.OpenOrCreate);
Debug.Print("Write file 1.");
storage.WriteFile(pathFileName, picture.PictureData);

[/quote]

do you open the file twice ?

I cleaned up the code:

                Debug.Print("Write file.");

                Debug.GC(true);

                Debug.Print("Write file 1.");

                storage.WriteFile(pathFileName, picture.PictureData);

                Debug.GC(false);

Still generated an error:

Write file 1.
A first chance exception of type ‘System.Exception’ occurred in Microsoft.SPOT.Graphics.dll
An exception of type ‘System.Exception’ occurred in Microsoft.SPOT.Graphics.dll and wasn’t handled before a managed/native boundary

please edit your first message, use the “Format as code” tags (101 010-Button)
so the code is more readable

using System;
using System.Collections;
using System.IO;
using System.Net;
using System.Text;
using System.Threading;

using Microsoft.SPOT;
using Microsoft.SPOT.Presentation;
using Microsoft.SPOT.Presentation.Controls;
using Microsoft.SPOT.Presentation.Media;
using Microsoft.SPOT.Touch;

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

namespace Waugh.Cerbot.Robot
{
    public partial class Program
    {
        private const byte R_SPEED = 100;
        private const byte L_SPEED = 100;

        private enum Direction
        {
            Unknown,
            Forward,
            Reverse,
            Left,
            Right
        }

        private Direction[] _directions = new Direction[20];
        string rootDirectory;

        // This method is run when the mainboard is powered up or reset.  
        void ProgramStarted()
        {
            string methodName = "ProgramStarted";
            LogMessage(methodName, MessageType.Start);

            Debug.Print("Free mem : " + Debug.GC(false).ToString());

            // set up sdCard -------------------------
            // set up sdCard -------------------------

            LogMessage("sdCard Started", MessageType.Message);

            sdCard.MountSDCard();
            Thread.Sleep(500);

            rootDirectory = sdCard.GetStorageDevice().RootDirectory;

            sdCard.SDCardMounted += sdCard_SDCardMounted;
            sdCard.SDCardUnmounted += sdCard_SDCardUnmounted;

            // set up camera -----------------------
            // set up camera -----------------------

            LogMessage("Camera Started", MessageType.Message);

            serCam.SetImageSize(SerCam.Camera_Resolution.SIZE_QQVGA);

            serCam.StartDataCaptured += new SerCam.StartDataCapturedEventHandler(serCam_StartDataCaptured);
            serCam.FinishDataCaptured += new SerCam.FinishDataCapturedEventHandler(serCam_FinishDataCaptured);
            serCam.OnDataCaptured += new SerCam.DataCapturedEventHandler(serCam_OnDataCaptured);
           
            new Thread(VideoStreamming).Start();

            // set up wifi -------------------------
            // set up wifi -------------------------
            
            LogMessage("Wifi Started", MessageType.Message);

            new Thread(InitializeWifi).Start();

            // complete -------------------------
            // complete -------------------------
 
            LogMessage(methodName, MessageType.End);
        }
        
        // Wifi Cerbot -------------------------
        // Wifi Cerbot -------------------------
        // Wifi Cerbot -------------------------
        
        void InitializeWifi() {
        
            string methodName = "InitializeWifi";
            LogMessage(methodName, MessageType.Start);

            wifi_RN171.Initialize(GTM.GHIElectronics.WiFi_RN171.SocketProtocol.TCP_Server); //Init as TCP Server
            wifi_RN171._Command_Mode_Start();
            wifi_RN171._Command_Execute("get ip");
            wifi_RN171._Command_Execute("set comm remote 0");
            wifi_RN171._Command_Mode_Exit();
            wifi_RN171.EnableHttpServer(); //Enable HTTP Parsing
            wifi_RN171.HttpRequestReceived += new GTM.GHIElectronics.WiFi_RN171.HttpRequestReceivedHandler(wifi_RN171_HttpRequestReceived);

            wifi_RN171.SetListenPort(80);

            LogMessage(methodName, MessageType.End);
        }

        void wifi_RN171_HttpRequestReceived(GTM.GHIElectronics.HttpStream request)
        {
            string methodName = "wifi_RN171_HttpRequestReceived";

            LogMessage(methodName, MessageType.Start);

            string requestedURL = request.Request.URL;

            if (requestedURL.IndexOf("/_") == 0)
            {
                HandleAjaxHttpRequest(request, requestedURL);
            }
            else
            {
                HandleHttpRequest(request, requestedURL);
            }

            LogMessage(methodName, MessageType.End);
        }

        private void HandleHttpRequest(GTM.GHIElectronics.HttpStream request, string requestedURL)
        {
            string methodName = "HandleHttpRequest";
            LogMessage(methodName, MessageType.Start);

            string action = "Unkown action";
            if (requestedURL == "/index.html")
            {
                action = "Welcome";
            }
            else
            {
                action = "Unknown action";

            }
            request.Response.HeaderData["Content-type"] = "text/html; charset=utf-8";
            request.Response.HeaderData["Connection"] = "close";
            request.Response.HeaderData["Cache-Control"] = "no-cache";
            request.Response.StatusCode = GTM.GHIElectronics.HttpResponse.ResponseStatus.OK;

            string HTML = IndexHTML(action);
            
            request.Response.Send(System.Text.Encoding.UTF8.GetBytes(HTML));
            
            LogMessage(methodName, MessageType.End);
        }

        private void HandleAjaxHttpRequest(GTM.GHIElectronics.HttpStream request, string requestedURL)
        {
            string methodName = "HandleAjaxHttpRequest";
            LogMessage(methodName, MessageType.Start);

            string action = "";
            switch (requestedURL)
            {
                case "/_index.html":
                    action = "Welcome";
                    break;
                case "/_northwest.html":
                    action += "north west";
                    break;
                case "/_north.html":
                    {
                        action += "north";
                        Move(Direction.Forward);
                        break;
                    }
                case "/_northeast.html":
                    action += "north east";
                    break;
                case "/_west.html":
                    {
                        action += "west";
                        Move(Direction.Left);
                        break;
                    }
                case "/_center.html":
                    action += "home";
                    break;
                case "/_east.html":
                    {
                        action += "east";
                        Move(Direction.Right);
                        break;
                    }
                case "/_southwest.html":
                    action += "south west";
                    break;
                case "/_south.html":
                    {
                        action = "We're going down south";
                        Move(Direction.Reverse);
                        break;
                    }
                case "/_southeast.html":
                    action += "south east";
                    break;
                case "/_start.html":
                    action = "Let's go";
                    break;
                case "/_stop.html":
                    {
                        action = "Hold it, right there!";
                        Move(Direction.Unknown);
                        break;
                    }
                case "/_fire.html":
                    {
                        action = "Cease fire!";
                        break;
                    }
                case "/_getposition.html":
                    action = "interval example position[x,y]";
                    break;
                default:
                    action = "Unknown action";
                    break;
            }

            LogMessage(action, MessageType.Start);

            request.Response.HeaderData["Content-type"] = "text/html; charset=utf-8";
            request.Response.HeaderData["Connection"] = "close";
            request.Response.HeaderData["Cache-Control"] = "no-cache";
            request.Response.StatusCode = GTM.GHIElectronics.HttpResponse.ResponseStatus.OK;
            request.Response.Send(System.Text.Encoding.UTF8.GetBytes(action));

            LogMessage(methodName, MessageType.End);

        }

        // Move Cerbot -------------------------
        // Move Cerbot -------------------------
        // Move Cerbot -------------------------

        private string DirectionToString(Direction direction)
        {
            switch (direction)
            {
                case Direction.Forward:
                    return "Forward";
                case Direction.Reverse:
                    return "Reverse";
                case Direction.Left:
                    return "Left";
                case Direction.Right:
                    return "Right";
                default:
                    return "Unknown";
            }
        }

        private void Move(Direction direction)
        {
            LogMessage("Move", MessageType.Start);

            switch (direction)
            {
                case Direction.Forward:
                    cerbotController.SetMotorSpeed(L_SPEED, R_SPEED);
                    break;
                case Direction.Reverse:
                    cerbotController.SetMotorSpeed(-L_SPEED, -R_SPEED);
                    break;
                case Direction.Left:
                    TurnLeft();
                    Move(Direction.Forward);
                    return;
                case Direction.Right:
                    TurnRight();
                    Move(Direction.Forward);
                    return;
            }
            Thread.Sleep(1000);
            cerbotController.SetMotorSpeed(0, 0);

            LogMessage("Move", MessageType.End);
        }

        private void TurnLeft()
        {
            LogMessage("TurnLeft", MessageType.Start);

            cerbotController.SetMotorSpeed(-L_SPEED, R_SPEED);
            Thread.Sleep(350);
            cerbotController.SetMotorSpeed(0, 0);
        }

        private void TurnRight()
        {
            LogMessage("TurnRight", MessageType.Start);

            cerbotController.SetMotorSpeed(L_SPEED, -R_SPEED);
            Thread.Sleep(315);
            cerbotController.SetMotorSpeed(0, 0);
        }

        // Picture Cerbot -------------------------
        // Picture Cerbot -------------------------
        // Picture Cerbot -------------------------

        byte[] datajpg; 
        int index = 0;

        void serCam_OnDataCaptured(SerCam sender, byte[] data)
        {
            if (index + data.Length > datajpg.Length)
            {
                throw new Exception("Error");
            }
            Array.Copy(data, 0, datajpg, index, data.Length);
            index += data.Length;
        }

        void serCam_FinishDataCaptured(SerCam sender)
        {
            GT.Picture picture = new GT.Picture(datajpg, GT.Picture.PictureEncoding.BMP);
            serCam_SavePicture(picture);
        }

        void serCam_StartDataCaptured(SerCam sender, int sizeImage)
        {
            index = 0;             
            datajpg = new byte[sizeImage]; 
        }

        void serCam_SavePicture(GT.Picture pic)
        {
            string methodName = "serCam_SavePicture";
            LogMessage(methodName, MessageType.Start);

            if (this.sdCard.IsCardMounted)
            {
                LogMessage("SD Card mounted, save image.", MessageType.Message);

                LogMessage("Saved image begin.", MessageType.Message);

                GT.StorageDevice storage = sdCard.GetStorageDevice();

                Debug.Print(storage.Volume.Name);

                uint imageNumber = (uint)storage.ListFiles("").Length;
                string pathFileName = @ "\SD\Image-" + (imageNumber++).ToString() + ".bmp";

                LogMessage(pathFileName, MessageType.Message);


                // convert to BMP file
                Bitmap bmp = pic.MakeBitmap();
                Byte[] outputBytes = new Byte[bmp.Width * bmp.Height * 3 + 54];

                //Util.BitmapToBMPFile(pic.PictureData, 160, 120, outputBytes);

                try
                {
                    storage.WriteFile(pathFileName, pic.PictureData); //outputBytes);
                }
                catch (Exception ex)
                {
                    LogMessage("Message: " + ex.Message + "  Inner Exception: " + ex.InnerException, MessageType.Message);
                }

                LogMessage("Saved image finish.", MessageType.Message);

            }
            else
            {
                LogMessage("SD Card not mounted.", MessageType.Message);
            }

            Debug.GC(true);
        }

        byte[] dataimage;
        int PictureNumber = 0;

        void VideoStreamming()
        {
            GT.StorageDevice storage = sdCard.GetStorageDevice();
            string root = storage.RootDirectory;
                
            Debug.Print("Video Streaming.");
            while (true)
            {
                serCam.TakePicture();
                Thread.Sleep(2000);

            }
        }

        void sdCard_SDCardUnmounted(SDCard sender) {     
            Debug.Print("The SD card has been unmounted");     
            Debug.Print("DO NOT try to access it without mounting it again first"); 
        }   
        
        void sdCard_SDCardMounted(SDCard sender, GT.StorageDevice SDCard) {     
            Debug.Print("SD card has been successfully mounted. You can now read/write/create/delete files");     
            Debug.Print("Unmount before removing"); 
        } 

        // General Cerbot -------------------------
        // General Cerbot -------------------------
        // General Cerbot -------------------------

        private void LogMessage(string msgText, MessageType msgType)
        {
            switch (msgType)
            {
                case MessageType.Message:
                    msgText = "Message [" + msgText + "]";
                    break;
                case MessageType.Start:
                    msgText = "--> [" + msgText + "]";
                    break;
                case MessageType.End:
                    msgText = "<-- [" + msgText + "]";
                    break;
                case MessageType.Error:
                    msgText = "Error: [" + msgText + "]";
                    break;
                default:
                    break;
            }
            msgText = msgText + " " + DateTime.Now.Ticks.ToString();

            Debug.Print(msgText);
        }

        private enum MessageType { 
            Message = 0,
            Start = 1,
            End = 2,
            Error = 3,
        }

        private void LogLeaveMethod(string methodName)
        {
            Debug.Print("<--- " + methodName);
        }

        private string IndexHTML(string action)
        {
            string HTML = String.Empty;

            HTML = HTML + "<!DOCTYPE html>\n";
            HTML = HTML + "<html lang=\"en\" xmlns=\"http://www.w3.org/1999/xhtml\">\n";
            HTML = HTML + "<head>\n";
            HTML = HTML + "    <meta charset=\"utf-8\" />\n";
            HTML = HTML + "    <title></title>\n";
            HTML = HTML + "</head>\n";
            HTML = HTML + "    \n";
            HTML = HTML + "<body>\n";
            HTML = HTML + "    <style>\n";
            HTML = HTML + "        td {\n";
            HTML = HTML + "            width:160px;\n";
            HTML = HTML + "            vertical-align:central\n";
            HTML = HTML + "        }\n";
            HTML = HTML + "        input[type=\"button\"] {\n";
            HTML = HTML + "            font-size:144px;\n";
            HTML = HTML + "            background-color:beige;\n";
            HTML = HTML + "            text-align:center;\n";
            HTML = HTML + "            color:black;\n";
            HTML = HTML + "            font-weight:bold;\n";
            HTML = HTML + "            width:150px;\n";
            HTML = HTML + "            height:150px;\n";
            HTML = HTML + "            vertical-align:central\n";
            HTML = HTML + "\n";
            HTML = HTML + "        }\n";
            HTML = HTML + "\n";
            HTML = HTML + "        input[type=\"button\"].x {\n";
            HTML = HTML + "            font-size:12px;\n";
            HTML = HTML + "        }\n";
            HTML = HTML + "\n";
            HTML = HTML + "        #btnStop {\n";
            HTML = HTML + "            background-color:red;\n";
            HTML = HTML + "            font-size:32px;\n";
            HTML = HTML + "        }\n";
            HTML = HTML + "\n";
            HTML = HTML + "        #btnStart {\n";
            HTML = HTML + "            background-color:green;\n";
            HTML = HTML + "            font-size:32px;\n";
            HTML = HTML + "        }\n";
            HTML = HTML + "        #lbInfo {\n";
            HTML = HTML + "            display: block;\n";
            HTML = HTML + "            float: right;\n";
            HTML = HTML + "            width:300px;\n";
            HTML = HTML + "            background-color:white;\n";
            HTML = HTML + "            font-size:24px;\n";
            HTML = HTML + "            text-align:center\n";
            HTML = HTML + "        }\n";
            HTML = HTML + "\n";
            HTML = HTML + "    </style>\n";
            HTML = HTML + "    <script type=\"text/javascript\">\n";
            HTML = HTML + "        var xmlhttp;\n";
            HTML = HTML + "        if (window.XMLHttpRequest) {\n";
            HTML = HTML + "            xmlhttp = new XMLHttpRequest();\n";
            HTML = HTML + "        }\n";
            HTML = HTML + "        else {\n";
            HTML = HTML + "            xmlhttp = new ActiveXObject(\"Microsoft.XMLHTTP\");\n";
            HTML = HTML + "        }\n";
            HTML = HTML + "\n";
            HTML = HTML + "        window.setInterval(submitAction('getposition()'), 1000);\n";
            HTML = HTML + "\n";
            HTML = HTML + "        function submitAction(action) {\n";
            HTML = HTML + "\n";
            HTML = HTML + "            xmlhttp.onreadystatechange = function () {\n";
            HTML = HTML + "                if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {\n";
            HTML = HTML + "                    document.getElementById(\"lbInfo\").innerHTML = xmlhttp.responseText;\n";
            HTML = HTML + "                }\n";
            HTML = HTML + "            }\n";
            HTML = HTML + "            xmlhttp.open(\"GET\", \"http://192.168.1.1/_\" + action + \".html\", true);\n";
            HTML = HTML + "            xmlhttp.send();\n";
            HTML = HTML + "        }\n";
            HTML = HTML + "\n";
            HTML = HTML + "\n";
            HTML = HTML + "\n";
            HTML = HTML + "\n";
            HTML = HTML + "    </script>\n";
            HTML = HTML + "    <table>\n";
            HTML = HTML + "        <tr>\n";
            HTML = HTML + "            <td><input type=\"button\" class=\"x\" value=\"x\" id=\"btnNorthWest\" onclick=\"submitAction('northwest');\"/></td>\n";
            HTML = HTML + "            <td><input type=\"button\" value=\"/\\\" id=\"btnUp\" onclick=\"submitAction('north');\"/></td>\n";
            HTML = HTML + "            <td><input type=\"button\" class=\"x\" value=\"x\" id=\"btnNorthEast\" onclick=\"submitAction('northeast');\"/></td>\n";
            HTML = HTML + "            <td></td>\n";
            HTML = HTML + "            <td><input type=\"button\" value=\"STOP\" id=\"btnStop\" onclick=\"submitAction('stop');\"/></td>\n";
            HTML = HTML + "        </tr>\n";
            HTML = HTML + "        <tr>\n";
            HTML = HTML + "            <td><input type=\"button\" value=\"<\" id=\"btnWest\" onclick=\"submitAction('west');\"/></td>\n";
            HTML = HTML + "            <td><input type=\"button\" class=\"x\" value=\"click\" id=\"btnCenter\" onclick=\"submitAction('fire');\"/></td>\n";
            HTML = HTML + "            <td><input type=\"button\" value=\">\" id=\"btnEast\" onclick=\"submitAction('east');\"/></td>\n";
            HTML = HTML + "            <td colspan=\"2\"><label id=\"lbInfo\">We'are going nowhere</label></td>\n";
            HTML = HTML + "            </tr>\n";
            HTML = HTML + "        <tr>\n";
            HTML = HTML + "            <td><input type=\"button\" class=\"x\" value=\"x\" id=\"btnSouthWest\" onclick=\"submitAction('southwest');\"/></td>\n";
            HTML = HTML + "            <td><input type=\"button\" value=\"\\/\" id=\"btnSouth\" onclick=\"submitAction('south');\"/></td>\n";
            HTML = HTML + "            <td><input type=\"button\" class=\"x\" value=\"x\" id=\"btnSouthEast\" onclick=\"ssubmitAction('southeast');\"/></td>\n";
            HTML = HTML + "            <td></td>\n";
            HTML = HTML + "            <td><input type=\"button\" value=\"START\" id=\"btnStart\" onclick=\"submitAction('start');\"/></td>\n";
            HTML = HTML + "        </tr>\n";
            HTML = HTML + "     </table>\n";
            HTML = HTML + "     <br/>\n";
            HTML = HTML + "     <div>" + DateTime.Now.TimeOfDay.ToString() + "</div>\n";
            HTML = HTML + "</body>\n";
            HTML = HTML + "</html>\n";

            return HTML;
        }

    
    }
}

@ Kwaugh32 - for me the useing of the variables datajpg , picture and pic
seems not to be threadsave

This was straight out of the sample of the module that I purchased…and the module was suggested on the page advertising the Cerbot. Extremely frustrating.

I have changed the code to the following:

Message [Video isNewImageReady.] 129513600589225820
Message [Video List Files.] 129513600589229430
Message [\SD\Image-5.bmp] 129513600589275550
Message [Video Get Image.] 129513600589279180
Message [Video Save Image.] 129513600589301640
Message [3640] 129513600589307390
Message [Video Save Image.] 129513600589311970
Failed allocation for 172 blocks, 2064 bytes

A first chance exception of type ‘System.IO.IOException’ occurred in Microsoft.SPOT.IO.dll
An exception of type ‘System.IO.IOException’ occurred in Microsoft.SPOT.IO.dll and wasn’t handled before a managed/native boundary


        int cnt = 0;
        void VideoStreamming()
        {
            GT.StorageDevice storage = sdCard.GetStorageDevice();
            string root = storage.RootDirectory;
 
            LogMessage("Video Streaming.", MessageType.Message);
            serCam.SetImageSize(SerCam.Camera_Resolution.SIZE_QQVGA);

            serCam.StartStreaming();
            while (true)
            {
                Thread.Sleep(100);
                if (serCam.isNewImageReady)
                {
                    LogMessage("Video isNewImageReady.", MessageType.Message);
                        
                    LogMessage("Video List Files.", MessageType.Message);
                    uint imageNumber = (uint)storage.ListFiles("").Length;                 
                    string pathFileName = @ "\SD\Image-" + (imageNumber++).ToString() + ".bmp";
                    LogMessage(pathFileName, MessageType.Message);

                    LogMessage("Video Get Image.", MessageType.Message);
                    Debug.GC(true);                    
                    
                    //save the picture
                    LogMessage("Video Save Image.", MessageType.Message);
                    
                    byte[] data = serCam.GetImageData();
                    LogMessage(data.Length.ToString(), MessageType.Message);

                    LogMessage("Video Save Image.", MessageType.Message);
                    using (var imfile = new FileStream(pathFileName, FileMode.CreateNew))             
                    {                 
                        try                 
                        {                     
                            imfile.Write(data, 0, data.Length);                 
                        }                 
                        catch (IOException ex)                 
                        {                                         
                        }             
                    } 


                    LogMessage("Video DrawImage.", MessageType.Message);

                    cnt++;
                    if (cnt % 10 == 0)
                    {
                        serCam.StopStreaming();
                        serCam.StartStreaming();

                        LogMessage("Video Next.", MessageType.Message);
                    }
                }
            }
        }

@ Kwaugh32 -

Using the following code provided the following output with every image being saved correctly:

[quote=“FEZCerbot”]Using mainboard GHI Electronics FEZCerbot version 1.0
Program Started
SD Mount Detected
Found root directory: \SD
Starting Camera Feed
The thread ‘’ (0x3) has exited with code 0 (0x0).
Saved \SD\Image-0.bmp
Saved \SD\Image-1.bmp
Saved \SD\Image-2.bmp
Saved \SD\Image-3.bmp
Saved \SD\Image-4.bmp
Saved \SD\Image-5.bmp
Saved \SD\Image-6.bmp
Saved \SD\Image-7.bmp
Saved \SD\Image-8.bmp
Saved \SD\Image-9.bmp
Saved \SD\Image-10.bmp
Saved \SD\Image-11.bmp
Saved \SD\Image-12.bmp
Saved \SD\Image-13.bmp
Saved \SD\Image-14.bmp
Saved \SD\Image-15.bmp
Saved \SD\Image-16.bmp
Saved \SD\Image-17.bmp
Saved \SD\Image-18.bmp
Saved \SD\Image-19.bmp
Saved \SD\Image-20.bmp
Saved \SD\Image-21.bmp
Saved \SD\Image-22.bmp
Saved \SD\Image-23.bmp
Saved \SD\Image-24.bmp
Saved \SD\Image-25.bmp
Saved \SD\Image-26.bmp
Saved \SD\Image-27.bmp
Saved \SD\Image-28.bmp
Saved \SD\Image-29.bmp
Saved \SD\Image-30.bmp
Saved \SD\Image-31.bmp
Saved \SD\Image-32.bmp
Saved \SD\Image-33.bmp
Saved \SD\Image-34.bmp
Saved \SD\Image-35.bmp
Saved \SD\Image-36.bmp
Saved \SD\Image-37.bmp
Saved \SD\Image-38.bmp
Saved \SD\Image-39.bmp
Saved \SD\Image-40.bmp
Saved \SD\Image-41.bmp
Saved \SD\Image-42.bmp
Saved \SD\Image-43.bmp
Saved \SD\Image-44.bmp
Saved \SD\Image-45.bmp
Saved \SD\Image-46.bmp
Saved \SD\Image-47.bmp
Saved \SD\Image-48.bmp[/quote]

Code:

using System;
using System.Collections;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Presentation;
using Microsoft.SPOT.Presentation.Controls;
using Microsoft.SPOT.Presentation.Media;
using Microsoft.SPOT.Presentation.Shapes;
using Microsoft.SPOT.Touch;

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

namespace Topic_14475
{
    public partial class Program
    {
        Thread SerCamThread;
        bool SerCamThreadRunning = false;

        // This method is run when the mainboard is powered up or reset.   
        void ProgramStarted()
        {
            Debug.Print("Program Started");

            sdCard.SDCardMounted += sdCard_SDCardMounted;
            sdCard.SDCardUnmounted += sdCard_SDCardUnmounted;
        }

        void sdCard_SDCardUnmounted(SDCard sender)
        {
            SerCamThreadRunning = false;
        }

        void sdCard_SDCardMounted(SDCard sender, GT.StorageDevice SDCard)
        {
            Debug.Print("SD Mount Detected");
            Debug.Print("Found root directory: " + SDCard.RootDirectory);

            if (SerCamThread == null)
            {
                Debug.Print("Starting Camera Thread");
                SerCamThreadRunning = true;
                SerCamThread = new Thread(RunSerCam);
                SerCamThread.Start();
            }
        }

        int current_picture = 0;
        void RunSerCam()
        {
            string rootDir = sdCard.GetStorageDevice().RootDirectory;

            Debug.Print("Starting Camera Feed");

            serCam.SetImageSize(SerCam.Camera_Resolution.SIZE_QQVGA);
            serCam.StartStreaming();

            while (SerCamThreadRunning)
            {
                if (serCam.isNewImageReady)
                {
                    lock (serCam)
                    {
                        FileStream file = new FileStream(rootDir + "\\Image-" + current_picture.ToString() + ".bmp", FileMode.Create);
                        file.Write(serCam.dataImage, 0, serCam.dataImage.Length);

                        VolumeInfo.GetVolumes()[0].FlushAll();

                        file.Dispose();

                        Debug.GC(true);

                        Debug.Print("Saved " + rootDir + "\\Image-" + current_picture.ToString() + ".bmp");
                        current_picture++;
                    }
                }

                Thread.Sleep(100);
            }

            serCam.StopStreaming();
        }
    }
}

I am still getting the following error:

Found root directory: \SD
Starting Camera Thread
Starting Camera Feed
Camera SerCamThreadRunning
Camera SerCamThreadRunning
Camera SerCamThreadRunning
Camera SerCamThreadRunning
Camera SerCamThreadRunning
Camera SerCamThreadRunning
Camera SerCamThreadRunning
Camera isNewImageReady
Failed allocation for 172 blocks, 2064 bytes

Failed allocation for 172 blocks, 2064 bytes

\SD\Image-0.bmp
Failed allocation for 172 blocks, 2064 bytes

A first chance exception of type ‘System.IO.IOException’ occurred in Microsoft.SPOT.IO.dll
An unhandled exception of type ‘System.IO.IOException’ occurred in Microsoft.SPOT.IO.dll

Uncaught exception
The thread ‘’ (0x8) has exited with code 0 (0x0).
The program ‘[2] Micro Framework application: Managed’ has exited with code 0 (0x0).

Are you running the Ethernet firmware? What other modules do you have in your designer, perhaps they’re stealing memory from your app?

I do have the Wifi module connected but no code executed (all commented out). If I can only have 2 out of 6 modules (camera and sdcard) in use at one time, it would be a real disappointment.

Ok, I understand this, but a Cerberus based device is memory constrained, and things with graphics are memory extensive so you’re coming up against this early on in your project. Start again, remove WiFi as a connected device, and deploy the non Ethernet firmware, and try this test app again. We’re trying to eliminate the out of memory exceptions first, and then we can start adding things back in and managing memory better as you go.

There are two issues with memory:

  1. per Brett’s comments, there is a small amount of [em]total [/em]memory
  2. “heap fragmentation” can occur (the memory is only available in [em]small[/em] blocks)

From a memory viewpoint, the most important part of Jame’s example regards memory was the statement

It helps keeps the fragmentation from being a problem. When looking at your debugging messages, I suspect that memory may be fragmented before a new image is detected; therefore, the placement of the GC call won’t help. Try moving the call so the code looks like the following. Then let us know the results. [code=cs
Debug.GC(true);
FileStream file = new FileStream(rootDir + “\Image-” + current_picture.ToString() + “.bmp”, FileMode.Create);
file.Write(serCam.dataImage, 0, serCam.dataImage.Length);
VolumeInfo.GetVolumes()[0].FlushAll();
file.Dispose();
Debug.Print("Saved " + rootDir + “\Image-” + current_picture.ToString() + “.bmp”);
current_picture++;

Actually Jeff, your post prompted two other thoughts from me.

First, debug.gc(false); is probably a good one to know too, as it returns the amount of memory free, so you can print it out in debug.print statement at points in your code to see how it changes as your code runs.

Second, you can use the USING pattern for the file stream so that if theres an exception the file will be closed and cleaned up properly and be even less likely to leak.