XBee adapter with Serial Line

I’ve been looking at this code off and on code for a while and I can’t see what is wrong. It has worked intermittently. Sometimes it only works when running in the debugger. All it does is get the serial line from the XBee and assign it to a serial interface. The problem is that the LineReceived event doesn’t fire. Most of the time I can get the DataReceived event to fire, so I know the XBees are configured right. Does anybody see something I’ve missed? There is, of course, another XBee running similar code that sends the messages.


using Microsoft.SPOT;

using GT = Gadgeteer;
using Gadgeteer.Modules.GHIElectronics;
using System.Text;

namespace XBeeATCoordinator
{
    public partial class Program
    {
        GT.Interfaces.Serial serial;
        uint i;
   
        void ProgramStarted()
        {
            xBee.Configure(115200, GT.Interfaces.Serial.SerialParity.None, GT.Interfaces.Serial.SerialStopBits.One, 8);
            serial = xBee.SerialLine;
            serial.AutoReadLineEnabled = true;

            serial.LineReceived += new GT.Interfaces.Serial.LineReceivedEventHandler(serial_LineReceived);
            serial.DataReceived += new GT.Interfaces.Serial.DataReceivedEventHandler(serial_DataReceived);
            serial.Open();

            i = 10;
            button.ButtonPressed += new Button.ButtonEventHandler(button_ButtonPressed);
            Debug.Print("Program Started");
        }

        void serial_DataReceived(GT.Interfaces.Serial sender, System.IO.Ports.SerialData data)
        {
            
            UTF8Encoding enc = new UTF8Encoding();
            display_T35.SimpleGraphics.DisplayText("data received", 
                Resources.GetFont(Resources.FontResources.NinaB), GT.Color.Green, 10, i);
            i += 10;
        }

        void button_ButtonPressed(Button sender, Button.ButtonState state)
        {
            serial.WriteLine("Test " + i.ToString() + " from Coordinator\n");
        }

        void serial_LineReceived(GT.Interfaces.Serial sender, string line)
        {
            display_T35.SimpleGraphics.DisplayText(line, 
                Resources.GetFont(Resources.FontResources.NinaB), GT.Color.Red, 10, i);
            i += 10;
        }
    }
}




There was something recently about an internal buffer inside serial line, that prevents firing of the events until it is full. I’ll try to find the thread.

Here it is:

http://www.tinyclr.com/forum/topic?id=7209

Thanks, for the sanity check.

I still can’t get to the bottom of this problem with the XBee adapter. I’ve tried it using the serial line and with a library, and most of the time I can only get the line received event to fire when the device is running in the debugger.

The problem may be that the onLineReceived event is null as shown in the following screen shot:

That is strange. I would check the driver source code on codeplex to verify. If there is a bug you can also rebuild the driver with the fix until it will make it into the SDK.

Well, here’s a start. The constructor sets the DataReceived event but not the LineReceived event (see the last few lines of the code). This, interestingly, is in Gadgeteer Core, not the XBee driver.


        public Serial(Socket socket, int baudRate, SerialParity parity, SerialStopBits stopBits, int dataBits, HardwareFlowControl hardwareFlowControlRequirement, Module module)
        {
            if (!socket.SupportsType('U'))
            {
                if (module != null)
                {
                    throw new Socket.InvalidSocketException("Module " + module + " cannot use socket " + socket + " because it requires a socket supporting type 'K'" + (hardwareFlowControlRequirement == HardwareFlowControl.Required ? "" : " or type 'U'."));
                }
                else
                {
                    throw new Socket.InvalidSocketException("Cannot use socket " + socket + " because it does not support socket type 'K'" + (hardwareFlowControlRequirement == HardwareFlowControl.Required ? "" : " or type 'U'."));
                }
            }

            bool socketSupportsHardwareFlowControl = socket.SupportsType('K');
            if (hardwareFlowControlRequirement == HardwareFlowControl.Required && !socketSupportsHardwareFlowControl)
            {
                if (module != null)
                {
                    throw new Socket.InvalidSocketException("Module " + module + " cannot use socket " + socket + " because it requires a socket supporting type 'K'.");
                }
                else
                {
                    throw new Socket.InvalidSocketException("Cannot use socket " + socket + " because it does not support socket type 'K' and hardware flow control is required. Please relax the requirement for hardware flow control or use a socket supporting type 'K'.");
                }
            }

            string portName = socket.SerialPortName;

            if (portName == null || portName == "")
            {
                // this is a mainboard error that should not happen (we already check for it in SocketInterfaces.RegisterSocket) but just in case...
                throw new Socket.InvalidSocketException("Socket " + socket + " has an error with its Serial functionality. Please try a different socket.");

            }

            socket.ReservePin(Socket.Pin.Four, module);
            socket.ReservePin(Socket.Pin.Five, module);
            if (hardwareFlowControlRequirement != HardwareFlowControl.NotRequired)
            {
                // must reserve hardware flow control pins even if not using them, since they are electrically connected.
                socket.ReservePin(Socket.Pin.Six, module);
                socket.ReservePin(Socket.Pin.Seven, module);
            }

            this.LineReceivedEventDelimiter = "\n";

            this.Encoding = System.Text.Encoding.UTF8;

            this._serialPort = new SerialPort(portName, baudRate, (System.IO.Ports.Parity)parity, dataBits, (System.IO.Ports.StopBits)stopBits);
            if ((hardwareFlowControlRequirement != HardwareFlowControl.NotRequired) && socketSupportsHardwareFlowControl)
            {
                this._serialPort.Handshake = Handshake.RequestToSend;
                this._hardwareFlowControl = true;
            }
            else
            {
                this._hardwareFlowControl = false;
            }

            this._serialPort.DataReceived += new SerialDataReceivedEventHandler(this._serialPort_DataReceived);
            this.ReadTimeout = InfiniteTimeout;
            this.WriteTimeout = InfiniteTimeout;
        }

Ok, I see. Check this comment in the same source file:


        /// <summary>
        /// Gets or sets a value that determines whether automatic line reading is enabled.
        /// </summary>
        /// <remarks>
        /// <para>
        ///  When you set <see cref="AutoReadLineEnabled"/> to <b>true</b>, automatic reading
        ///  of the serial port is enabled. When enabled, <see cref="Serial"/> will continuously 
        ///  monitor the serial port; if the port is open (that is, <see cref="IsOpen"/> is <b>true</b>),
        ///  <see cref="Serial"/> will collect incoming data. Whenever a complete line of data is received 
        ///  as determined by the value of <see cref="LineReceivedEventDelimiter"/>, 
        ///  <see cref="Serial"/> raises the <see cref="LineReceived"/> event.
        /// </para>
        /// </remarks>
        public bool AutoReadLineEnabled

Looks like all you need to do is to set AutoReadLineEnabled to true.

Looks like it, but it doesn’t do it.

Try to enable it after you add the event handler.

Well, I’ve tried that and several other things now. The only way I can get the XBees to work is by using Paul Mineau’s XBeeClient libraries. He uses DataReceived to get all data. LineReceived is glitchy.