Serial camera module L2 System.Exception Error

Hi,

I Just get my serial camera L2, connected to a Spider using the 4.2 release. I am just trying to test the module using the testapp from :

But I have an exception :
within SerCam_42.cs :

OnPictureCapturedEvent(this, new Bitmap(data, Bitmap.BitmapImageType.Jpeg));

[quote]
#### Exception System.Exception - CLR_E_FAIL (5) ####
#### Message:
#### Microsoft.SPOT.Bitmap::.ctor [IP: 0000] ####
#### Gadgeteer.Modules.GHIElectronics.SerCam::ts [IP: 001d] ####
Une exception de première chance de type ‘System.Exception’ s’est produite dans Microsoft.SPOT.Graphics.dll
Une exception non gérée du type ‘System.Exception’ s’est produite dans Microsoft.SPOT.Graphics.dll[/quote]

Any ideas ? Does someone has make this camera working ?

Thanks in advance

Zakh

Hi there, I don’t have the camera but a CLR_E_FAIL type message can often be firmware related. I would have thought that since the failure is in a microsoft.spot DLL this is probably moreso the reason. Can you confirm you have 4.2 firmware loaded that matches the SDK you have installed? Check MFDeploy Device Capabilities and the SDK’s readme to confirm; and double check your project is targeting the 4.2 framework (someone yesterday changed it to 4.1 then back to 4.2 and that helped them too, perhaps try that as well).

Hi Brett,

Thanks for your reply. I have double checked (even re installed all package).

Build info note :
GHI NETMF v4.1 SDK Build Date: 9:15 AM 8/23/2012
GHI NETMF SDK v1.0.19 1:47 PM 2/17/2012
GHI .NET Gadgeteer SDK v1.6.7.0 9:15 AM 8/23/2012
GHI OSH NETMF SDK v1.0.5 5:35 PM 2/23/2012
GHI OSHW NETMF SDK v0.0.7 9:15 AM 8/23/2012
GHI Premium 4.2 NETMF SDK v0.0.5 9:15 AM 8/23/2012

MFDeploy info :
Connecting to EMX_Gadgeteer…Connected
DeviceInfo:
HAL build info: 4.2.0.0, Microsoft Copyright (C) Microsoft Corporation. All rig
OEM Product codes (vendor, model, SKU): 255, 0, 65535
Serial Numbers (module, system):
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
Solution Build Info: 4.2.4.0, Copyright (C) GHI Electronics, LLC
AppDomains:
default, id=1
Assemblies:
mscorlib,4.2.0.0
Microsoft.SPOT.Native,4.2.0.0
Gadgeteer.WebServer,2.42.0.0
Microsoft.SPOT.Net.Security,4.2.0.0
Microsoft.SPOT.Touch,4.2.0.0
GTM.GHIElectronics.SerCam,1.0.0.0
Microsoft.SPOT.Net,4.2.0.0
testapp,1.0.0.0
System.Net.Security,4.2.0.0
GHIElectronics.Gadgeteer.FEZSpider,1.0.5.0
Microsoft.SPOT.Hardware.PWM,4.2.0.1
Microsoft.SPOT.Hardware.SerialPort,4.2.0.0
Gadgeteer.WebClient,2.42.0.0
GHI.Premium.System,4.2.4.0
GTM.GHIElectronics.Display_T35,1.0.0.0
System,4.2.0.0
GTM.GHIElectronics.Button,1.0.0.0
System.Http,4.2.0.0
Gadgeteer.Serial,2.42.0.0
GHI.Premium.Hardware,4.2.4.0
Microsoft.SPOT.TinyCore,4.2.0.0
System.IO,4.2.0.0
GHI.Premium.IO,4.2.4.0
Microsoft.SPOT.Hardware,4.2.0.0
Microsoft.SPOT.Graphics,4.2.0.0
Microsoft.SPOT.IO,4.2.0.0
Gadgeteer,2.42.0.0

All projects (SerCam_42; SerCam;TestApp) are in NETMF 4.2

I am wondering if someone has succeed to have this new module working.

It is related to Microsoft.SPOT.Graphics.dll, probably the data you received back from SerCam module was wrong. Please check whole data you received from SerCam module. Here is data format from SerCam module:

  • 5 Bytes of Header
  • 0xFF (start JPEG data)
  • 0xD8 (start JPEG data)
    -(JPEG data)
  • 0xFF (End JPEG data)
    -0xD9 (End JPEG data)
  • 5 bytes end.

You can check byte 6th and 7th, make sure they are 0xFF, 0xD8, and 7 bytes end will be 0xFF, 0xD9 + 5 bytes end (if I am not wrong :)), these 5 bytes will be same as 5 bytes header).

@ Det, thanks for your answer.

This is not my code, I am using the “standard” example from Gadgeteer codeplex :

[quote]http://gadgeteer.codeplex.com/SourceControl/changeset/view/21495#273380[/quote] (no change)

And it seems other user are facing the same issue :

Does someone has been succesfull using this new module ???

Meanwhile I will check bytes 6th and 7th.

Zakh

Do not worry, we saw that issue and fixed it. The correct way to fix it will be posted soon.
Now if you want to make it work, do follow this:

File SerCam_42.cs, in function

 private byte[] ReadFrameBuffer(int size) 

, find and replace this line:


.........
// Read header
ReadBytes(header, 0, 5);
// Read data
ReadBytes(data, 0, size);    //=>>>>>>>>>>>this line must be replaced
 // read header
ReadBytes(header, 5, 5);
...........

by these codes below:


..........
Thread.Sleep(3); // Added 3ms delay
// Read header
ReadBytes(header, 0, 5);

//   Read data
//  ReadBytes(data, 0, size);    //=>>>>>>>>>>>this line must be replaced

int cnt=0;
int timeout=0;
while (cnt<size)
{
      cnt += ReadBytes(data, cnt);
      timeout++;
      if (timeout>size) break; // If there is something wrong with connection, we don't want to loop forever
}

 // read header
ReadBytes(header, 5, 5);
.........

And here is definition of ReadBytes(byte[] buff, int offset):


int ReadBytes(byte[] buff, int offset)
{
      int byteread = serialPort.BytesToRead;
      if (byteread +offset > buff.Length) byteread  = buff.Length - offset ;
      if (byteread >0)
      {
          serialPort.Read(buff, offset, byteread );
      }
      return byteread;

}

It will work fine.

I think here is easier way, file SerCam_42.cs, you just need to find


private void ReadBytes(byte[] data, int offset, int count)
        {
            serialPort.Read(data, offset, count);
        }

then replace by this:


private void ReadBytes(byte[] data, int offset, int count)
        {
            //serialPort.Read(data, offset, count);
            int cnt = 0;
            int bytetoread = 0;
            int timeout = 0;
            while (cnt < count)
            {
                bytetoread = serialPort.BytesToRead;
                if (bytetoread == 0)
                {
                    Thread.Sleep(1);
                    timeout++;
                    if (timeout > serialPort.ReadTimeout) break; // ReadTimeout
                    continue;
                }
                if (bytetoread > (count - cnt)) bytetoread = (count - cnt);

                if (bytetoread > 0)
                {
                    cnt += serialPort.Read(data, (offset + cnt), bytetoread);
                }

            }
        }

The first way I tested, but the second way I just think and write it down :)))

Thank you it works now.

I just received my L2 camera. I’m experiencing the same issues with CLR_E FAIL, although it only happens sporadically (perhaps every 2nd or 3rd time).
I’ve tested it with both fixes now without luck.

I’m also experiencing that the photos are distorted somehow. It’s like there are some horizontal lines (perhaps 10px in height) that are garbled.

Please post a picture of what you see.

I just took a few photos with my phone to show what it looks like.

One of the photos shows “the general case” where a few lines are garbled.
The second photo shows another case where I only have the first line plus a bit of the next one.

How are you powering your system?

Using the USB Client DP module; tried both with external power, usb power, and both. Does not make a difference.

We never seen this before and trying to understand what we need to do to reproduce. Can you try longer cables, shorter cables, run for a while, provide example code…

Anything you can do to help is appreciated.

Im afraid I dont have shorter cables than the provided ones.
I just tried with both the L1 and L2 cameras.

Im using the event of a PIR to call TakePicture() of the SerCam class (modified per the instructions to referred to earlier in this thread).

        void ProgramStarted()
        {
            SetupCamera();
            SetupMotionSensor();
        }

        void SetupCamera()
        {
            _camera = new SerCam(7);
            _camera.SetImageSize(SerCam.Camera_Resolution.SIZE_QVGA);
            _camera.PictureCaptured += new SerCam.PictureCapturedEventHandler(OnPictureCaptured);
        }
        
        void SetupMotionSensor()
        {
            _pir.Motion_Sensed += new PirSensor.Motion_SensorEventHandler(OnMotionSensed);
        }

        void OnMotionSensed(PirSensor sender, PirSensor.Motion_SensorState state)
        {
            _camera.TakePicture();
            Debug.GC(true);
        }

        void OnPictureCaptured(SerCam sender, Bitmap picture)
        {
            display_T35.SimpleGraphics.DisplayImage(picture, 0, 0);
        }

My SerCam_42.cs file can be seen here: https://dl.dropbox.com/u/4403875/SerCam_42.cs

not wanting to pre-empt anything, but I’d suggest a trial app without using the PIR. There have been other reports that the PIR fires too frequently and this may be causing some of the issues you’re seeing. Do you have a button module or a joystick module? I’d suggest using one of those to trigger the camera to take a shot. Also, in the USB camera module, there is a way to tell if the camera is busy; is there a similar thing in the serial camera driver (I haven’t looked), and if so can you try that, or at least wrap your code so that the previous image capture has completed before you try to initiate another capture.

I am lost now …

I took like 3 pictures but now it’s not working anymore. I am having the very same error :

within SerCam_42.cs :

OnPictureCapturedEvent(this, new Bitmap(data, Bitmap.BitmapImageType.Jpeg));

[quote] #### Exception System.Exception - CLR_E_FAIL (5) ####
#### Message:
#### Microsoft.SPOT.Bitmap::.ctor [IP: 0000] ####
#### Gadgeteer.Modules.GHIElectronics.SerCam::ts [IP: 001d] ####
Une exception de première chance de type ‘System.Exception’ s’est produite dans Microsoft.SPOT.Graphics.dll
Une exception non gérée du type ‘System.Exception’ s’est produite dans Microsoft.SPOT.Graphics.dll[/quote]

I am using the Dat code (post #5)

Any ideas ??

Hello,

Yes, I tried again and I got exactly same as yours. But after I check my wire, I can take more than 15 pictures with no problem.

So check your wire or replace another one if you can.
I suggest you should use my second way and try to add delay 30 ms.
And remember to update private void ReadBytes(byte[] data, int offset, int count) function as I did.


 private byte[] ReadFrameBuffer(int size)
        {
            CleanSerialPort();

            byte[] size4byte = new byte[4];
            byte[] header = new byte[10];
            size4byte[0] = (byte)(size >> 24);
            size4byte[1] = (byte)(size >> 16);
            size4byte[2] = (byte)(size >> 8);
            size4byte[3] = (byte)(size);
            /////////dataJPG = new byte[size + 10];      =>>>>>>>>>>>>>>> Remove it to save memory and speed up

            byte[] data = new byte[size];
            byte[] send = new byte[] { 0x56, 0x00, 0x32, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, size4byte[0], size4byte[1], size4byte[2], size4byte[3], 0x0B, 0xB8 };
            serialPort.Write(send, 0, send.Length);
            Thread.Sleep(30);  /////////// Add 30 ms why? 0x0B,0xB8  ~ 3000 * 0.01 = 30
            // Read header
            ReadBytes(header, 0, 5);

                // Read data
            ReadBytes(data, 0, size);

            // read header
            ReadBytes(header, 5, 5);

            return data;
        }


Hello DAT,

No change …

I tried 6 different cables (small, medium, long) same result "Exception System.Exception - CLR_E_FAIL (5) "

I followed your recomendation on SerCam42.cs (2nd way), but same result "Exception System.Exception - CLR_E_FAIL (5) ", see below :

using System;
using Microsoft.SPOT;

using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;
using GTI = Gadgeteer.Interfaces;

using System.Threading;

namespace Gadgeteer.Modules.GHIElectronics
{
    // -- CHANGE FOR MICRO FRAMEWORK 4.2 --
    // If you want to use Serial, SPI, or DaisyLink (which includes GTI.SoftwareI2C), you must do a few more steps
    // since these have been moved to separate assemblies for NETMF 4.2 (to reduce the minimum memory footprint of Gadgeteer)
    // 1) add a reference to the assembly (named Gadgeteer.[interfacename])
    // 2) in GadgeteerHardware.xml, uncomment the lines under <Assemblies> so that end user apps using this module also add a reference.

    /// <summary>
    /// A SerCam module for Microsoft .NET Gadgeteer
    /// </summary>
    public class SerCam : GTM.Module
    {
        private GTI.Serial serialPort;
        private const int DELAY_TIME = 200;
        private static byte[] dataJPG;

        public enum Camera_Resolution
        {
            SIZE_VGA = 0x00,
            SIZE_QVGA = 0x11,
            SIZE_QQVGA = 0x22,
        };

        // Note: A constructor summary is auto-generated by the doc builder.
        /// <summary></summary>
        /// <param name="socketNumber">The socket that this module is plugged in to.</param>
        public SerCam(int socketNumber)
        {
            // This finds the Socket instance from the user-specified socket number.  
            // This will generate user-friendly error messages if the socket is invalid.
            // If there is more than one socket on this module, then instead of "null" for the last parameter, 
            // put text that identifies the socket to the user (e.g. "S" if there is a socket type S)
            Socket socket = Socket.GetSocket(socketNumber, true, this, null);

            socket.EnsureTypeIsSupported('U', this);

            serialPort = new GTI.Serial(socket, 115200, GTI.Serial.SerialParity.None, GTI.Serial.SerialStopBits.One, 8, GTI.Serial.HardwareFlowControl.NotRequired, this);
            serialPort.ReadTimeout = 50000;
            serialPort.WriteTimeout = 50000;

            serialPort.Open();

            ResetCamera();
        }

        // Baudrate
        private static ushort BAUDRATE_9600 = 0xAEC8;
        private static ushort BAUDRATE_19200 = 0x56E4;
        private static ushort BAUDRATE_38400 = 0x2AF2;
        private static ushort BAUDRATE_57600 = 0x1CC4;
        private static ushort BAUDRATE_115200 = 0x0DA6;

        private Thread thread;

        #region Picture Capture
        public void TakePicture()
        {
            if (thread == null)
            {
                thread = new Thread(ts);
                thread.Start();
            }
            else
            {
                if (thread.ThreadState == ThreadState.Running)
                    Debug.Print("Cannot take picture at this time");
                else
                {
                    thread = new Thread(ts);
                    thread.Start();
                }
            }
        }

        private void ts()
        {
            ResetCamera();

            StopFrameBufferControl();

            int size = GetFrameBufferLength();

            byte[] data = ReadFrameBuffer(size);

            //GT.Picture pic = new Picture(data, Picture.PictureEncoding.JPEG);

            OnPictureCapturedEvent(this, new Bitmap(data, Bitmap.BitmapImageType.Jpeg));
        }

        private bool StopFrameBufferControl()
        {
            CleanSerialPort();

            byte[] send = new byte[] { 0x56, 0x00, 0x36, 0x01, 0x00 };
            serialPort.Write(send, 0, send.Length);

            Thread.Sleep(DELAY_TIME);

            byte[] receive = ReadBytes();

            if (receive != null && receive.Length >= 4)
            {
                if (receive[0] == 0x76 && receive[1] == 0 && receive[2] == 0x36 && receive[3] == 0 && receive[4] == 0)
                {
                    return true;
                }
            }

            return false;
        }

        private int GetFrameBufferLength()
        {
            CleanSerialPort();

            byte[] send = new byte[] { 0x56, 0x00, 0x34, 0x01, 0x00 };

            serialPort.Write(send, 0, send.Length);

            Thread.Sleep(DELAY_TIME);

            int size = 0;
            byte[] receive = ReadBytes();

            if (receive != null && receive.Length >= 9)
            {
                if (receive[0] == 0x76 && receive[1] == 0 && receive[2] == 0x34 && receive[3] == 0 && receive[4] == 0x4)
                {
                    size = receive[5] << 24 | receive[6] << 16 | receive[7] << 8 | receive[8];
                }
            }
            return size;
        }

        private byte[] ReadFrameBuffer(int size)
        {
            CleanSerialPort();

            byte[] size4byte = new byte[4];
            byte[] header = new byte[10];
            size4byte[0] = (byte)(size >> 24);
            size4byte[1] = (byte)(size >> 16);
            size4byte[2] = (byte)(size >> 8);
            size4byte[3] = (byte)(size);
            /////////dataJPG = new byte[size + 10];      =>>>>>>>>>>>>>>> Remove it to save memory and speed up

            byte[] data = new byte[size];
            byte[] send = new byte[] { 0x56, 0x00, 0x32, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, size4byte[0], size4byte[1], size4byte[2], size4byte[3], 0x0B, 0xB8 };
            serialPort.Write(send, 0, send.Length);
            Thread.Sleep(30);  /////////// Add 30 ms why? 0x0B,0xB8  ~ 3000 * 0.01 = 30
            // Read header
            ReadBytes(header, 0, 5);

            // Read data
            ReadBytes(data, 0, size);

            // read header
            ReadBytes(header, 5, 5);

            return data;
        }

        public bool SetImageSize(Camera_Resolution resolution)
        {
            byte[] send = new byte[] { 0x56, 0x00, 0x31, 0x05, 0x04, 0x01, 0x00, 0x19, (byte)resolution };

            serialPort.Write(send, 0, send.Length);

            Thread.Sleep(DELAY_TIME);

            byte[] receive = ReadBytes();
            if (receive != null && receive[0] == 0x76 && receive[1] == 0x00 && receive[2] == 0x31 && receive[3] == 0x00 && receive[4] == 0x00)
            {
                return true;
            }

            return false;
        }
        #endregion

        #region Helper Functions
        private string ResetCamera()
        {
            byte[] send = new byte[] { 0x56, 0x00, 0x26, 0x00 };

            serialPort.Write(send, 0, send.Length);

            Thread.Sleep(DELAY_TIME);

            byte[] receive = ReadBytes();

            if (receive != null && receive.Length > 0)
            {
                Thread.Sleep(DELAY_TIME);
                return ConvertBytesToString(receive);
            }
            else
            {
                Thread.Sleep(DELAY_TIME);
                return "";
            }
        }

        private string ConvertBytesToString(byte[] data)
        {
            string str = "";

            for (int i = 0; i < data.Length; i++)
            {
                str += new string(new char[] { (char)(data[i]) });
            }

            return str;
        }

        private void CleanSerialPort()
        {
            serialPort.DiscardInBuffer();
            serialPort.DiscardOutBuffer();
        }

        private byte[] ReadBytes()
        {
            byte[] data = null;
            int byteread = serialPort.BytesToRead;
            if (byteread > 0)
            {
                data = new byte[byteread];
                ReadBytes(data, 0, data.Length);
            }
            return data;
        }

        private void ReadBytes(byte[] data, int offset, int count)
        {
            //serialPort.Read(data, offset, count);
            int cnt = 0;
            int bytetoread = 0;
            int timeout = 0;
            while (cnt < count)
            {
                bytetoread = serialPort.BytesToRead;
                if (bytetoread == 0)
                {
                    Thread.Sleep(1);
                    timeout++;
                    if (timeout > serialPort.ReadTimeout) break; // ReadTimeout
                    continue;
                }
                if (bytetoread > (count - cnt)) bytetoread = (count - cnt);

                if (bytetoread > 0)
                {
                    cnt += serialPort.Read(data, (offset + cnt), bytetoread);
                }

            }
        }

        int ReadBytes(byte[] buff, int offset)
        {
            int byteread = serialPort.BytesToRead;
            if (byteread + offset > buff.Length) byteread = buff.Length - offset;
            if (byteread > 0)
            {
                serialPort.Read(buff, offset, byteread);
            }
            return byteread;

        }


        #endregion
        #region Events
        /// <summary>
        /// Represents the delegate that is used for the <see cref="PictureCaptured"/> event.
        /// </summary>
        /// <param name="sender">The <see cref="SerCam"/> object that raised the event.</param>
        /// <param name="picture">A <see cref="T:Gadgeteer.Picture"/> containing the captured image.</param>
        public delegate void PictureCapturedEventHandler(SerCam sender, Bitmap picture);

        /// <summary>
        /// Event raised when the <see cref="Camera"/> has completed an image capture.
        /// </summary>
        /// <remarks>
        /// Handle the <see cref="PictureCaptured"/> event to process image data
        /// after you call the <see cref="TakePicture"/> method. These methods 
        /// process the image data from the camera asynchronously, 
        /// and raise this event when the processing is complete.
        /// </remarks>
        public event PictureCapturedEventHandler PictureCaptured;

        private PictureCapturedEventHandler OnPictureCaptured;

        /// <summary>
        /// Raises the <see cref="PictureCaptured"/> event.
        /// </summary>
        /// <param name="sender">The <see cref="SerCam"/> that raised the event.</param>
        /// <param name="picture">A <see cref="T:Gadgeteer.Picture"/> containing the captured image.</param>
        protected virtual void OnPictureCapturedEvent(SerCam sender, Bitmap picture)
        {
            if (OnPictureCaptured == null) OnPictureCaptured = new PictureCapturedEventHandler(OnPictureCapturedEvent);
            if (Program.CheckAndInvoke(PictureCaptured, OnPictureCaptured, sender, picture))
            {
                PictureCaptured(sender, picture);
            }
        }
        #endregion
    }
}

Is there a way to check my camera ?

Because I tried but I really don’t see it. Tell me what socket are you using then I will try again exactly what you did. I hope we will see the problem.
Now, probably I need your help. Can you try a different socket then apply that codes below and post you result please, we will check it.
Thanks for your feedback


private byte[] ReadFrameBuffer(int size)
{
	CleanSerialPort();

	byte[] size4byte = new byte[4];
	byte[] header = new byte[10];
	size4byte[0] = (byte)(size >> 24);
	size4byte[1] = (byte)(size >> 16);
	size4byte[2] = (byte)(size >> 8);
	size4byte[3] = (byte)(size);
	/////////dataJPG = new byte[size + 10];      =>>>>>>>>>>>>>>> Remove it to save memory and speed up

	byte[] data = new byte[size];
	byte[] send = new byte[] { 0x56, 0x00, 0x32, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, size4byte[0], size4byte[1], size4byte[2], size4byte[3], 0x0B, 0xB8 };
	serialPort.Write(send, 0, send.Length);
	Thread.Sleep(30);  /////////// Add 30 ms why? 0x0B,0xB8  ~ 3000 * 0.01 = 30
	// Read header
	ReadBytes(header, 0, 5);
  

		// Read data
	ReadBytes(data, 0, size);

	// read header
	ReadBytes(header, 5, 5);
	if (size!=0)
	{
		if (data[0] != 0xFF || data[1] != 0xD8 || data[size-2] !=0xFF || data[size-1] != 0xD9 )
		{
			Debug.Print("data[0] = " + data[0]);
			Debug.Print("data[1] = " + data[1]);
			Debug.Print("data[size-2] = " + data[size-2]);
			Debug.Print("data[size-1] = " + data[size-1]);
			for (int t = 0; t<10; t++)
			{
				 Debug.Print("header [ " + t + " ]" = header [t]);
			}
			throw new Exception("JPEG format is invalid");
		}
	}
	else 
	{
		throw new Exception("No data");
	}
	return data;
}