RF using serial/comports/uart slow

Hi,

I’ve bought a FEZ Panda II and a FEZ Cobra, along with the following 433Mhz RF transmitter([url]http://store.qkits.com/moreinfo.cfm/TX433.pdf[/url]) and receiver([url]http://www.futuraelettronica.net/pdf_ita/8220-RX433N.pdf[/url]).

I’ve connected the receivers digital out to the Panda II using COM1, and I’ve connected the transmitters digital in to the Cobra using COM1.

My issue is this, whenever I press the DOWN button on the Cobra, the Panda II only starts turning off the led about 15-20 seconds later. It remembers any patterns I press in, but it’s just delayed by an amount of time. I’ve done some manual testing with the transmitter and receiver, and know they’re not the parts sending the data slow. I’ve come to the conclusion it might have something to do with the comports and some sort of buffering, however, I keep reading data from the comport, and often read 0 bytes between messages from the Cobra. Also, I start receiving data instantly when I turn on the Panda II, it’s just manual input that’s delayed for some reason. I also control the Cobra’s LED, and it reacts right away.

Here’s my code:

Cobra Transmitter

namespace MindWorX.FEZCobra.TX433
{
    public class Program
    {
        #region Constants

        private const Byte SYSTEM = 0x01;
        private const Byte SYSTEM_KEEP_ALIVE = 0x01;

        private const Byte CONTROL = 0x02;
        private const Byte CONTROL_TURN_ON = 0x01;
        private const Byte CONTROL_TURN_OFF = 0x02;

        #endregion Constants

        private static OutputPort MainLED = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.LED, false);

        private static InputPort DownButton = new InputPort((Cpu.Pin)FEZ_Pin.Digital.ButtonDown, true, Port.ResistorMode.PullUp);

        private static SerialPort TX433 = new SerialPort("COM1", 2400);

        public static void Main()
        {
            TX433.ReadTimeout = 0;
            TX433.Open();

            while (true)
            {
                // send a test packet
                TX433_SendByte(SYSTEM, SYSTEM_KEEP_ALIVE, (DownButton.Read() == false ? (Byte)0x01 : (Byte)0x02));
                
                // write MainLED to see what we're transmitting, and confirm the Cobra isn't causing the problem
                MainLED.Write(DownButton.Read());
            }
        }

        private static void TX433_SendByte(Byte data1)
        {
            Byte[] packet = new Byte[] { 
                0xAA, 0xAA, 0xAA, 0xAA, 0xAA, // sending look-at-me signal
                0xFF, 0xFF, // sending sync signal
                0x4D, 0x57, 0x58, 0x21, // sending MWX! signature
                data1};
            TX433.Write(packet, 0, packet.Length);
        }

        private static void TX433_SendByte(Byte data1, Byte data2)
        {
            Byte[] packet = new Byte[] { 
                0xAA, 0xAA, 0xAA, 0xAA, 0xAA, // sending look-at-me signal
                0xFF, 0xFF, // sending sync signal
                0x4D, 0x57, 0x58, 0x21, // sending MWX! signature
                data1, data2};
            TX433.Write(packet, 0, packet.Length);
        }

        private static void TX433_SendByte(Byte data1, Byte data2, Byte data3)
        {
            Byte[] packet = new Byte[] { 
                0xAA, 0xAA, 0xAA, 0xAA, 0xAA, // sending look-at-me signal
                0xFF, 0xFF, // sending sync signal
                0x4D, 0x57, 0x58, 0x21, // sending MWX! signature
                data1, data2, data3};
            TX433.Write(packet, 0, packet.Length);
        }
    }
}

Panda Receiver

namespace MindWorX.FEZPanda.RX433
{
    public class Program
    {
        #region Constants

        private const Byte SYSTEM = 0x01;
        private const Byte SYSTEM_KEEP_ALIVE = 0x01;

        private const Byte CONTROL = 0x02;
        private const Byte CONTROL_TURN_ON = 0x01;
        private const Byte CONTROL_TURN_OFF = 0x02;

        #endregion Constants

        private const Byte MAX_DATA = 32;

        private static Byte[] Data = new Byte[0];

        private static OutputPort MainLED = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.LED, false);

        private static SerialPort RX433 = new SerialPort("COM1", 2400);

        public static void Main()
        {
            RX433.ReadTimeout = 0;
            RX433.Open();

            while (true)
            {
                // receive data
                RX433_ReceiveData();
            }
        }

        private static void RX433_ReceiveData()
        {
            Byte[] data = new Byte[16];
            Int32 length = RX433.Read(data, 0, data.Length);

            if (length == 0)
                return; // no data received, no point in wasting power

            Byte[] newData = new Byte[Data.Length + length];
            Array.Copy(Data, newData, Data.Length);
            Array.Copy(data, 0, newData, Data.Length, length);
            Data = newData;
            
            for (Int32 index = 0; index < Data.Length - 7; index++)
            {
                if ((Data[index + 0] == 0x4D) &&    // M of MWX! signature check
                    (Data[index + 1] == 0x57) &&    // W of MWX! signature check
                    (Data[index + 2] == 0x58) &&    // X of MWX! signature check
                    (Data[index + 3] == 0x21) &&    // ! of MWX! signature check
                    (Data[index + 4] == SYSTEM) &&
                    (Data[index + 5] == SYSTEM_KEEP_ALIVE))
                {
                    Byte b = Data[index + 6];       // test byte
                    if (b == 0x01)
                        MainLED.Write(false);
                    else if (b == 0x02)
                        MainLED.Write(true);

                    // a keep alive signal was recieved.
                    // Debug.Print("Got SYSTEM_KEEP_ALIVE");

                    Data = new Byte[0]; // clear out data. TODO: needs improvement, this kills parts of messages.
                }
            }

            if (Data.Length > MAX_DATA)
            {
                Data = new Byte[0]; // clears out the current buffer when too large
            }
        }
    }
}

Questions regarding the code are more than welcome, and I’ll try and explain everything as much as possible.

TL;DR: Data transfer has a 15-20 seconds delay, possibly related to buffering of some kind.

you’re flooding it.

while (true)
            {
                // send a test packet
                TX433_SendByte(SYSTEM, SYSTEM_KEEP_ALIVE, (DownButton.Read() == false ? (Byte)0x01 : (Byte)0x02));
 
                // write MainLED to see what we're transmitting, and confirm the Cobra isn't causing the problem
                MainLED.Write(DownButton.Read());
            }

Every pass thru that sends all those commands. Try it with a sleep(1000) or something there so that it doesn’t send a statement every 5ms, but just once a second.

Or better still, only send when the status changes?!

I tried with a 1000ms Thread.Sleep, which seems to be too much, as the receiver starts picking up static. However, with a 100ms Thread.Sleep it seems to be working. I guess I can experiment a bit more with the exact value. I wonder why it can’t handle it, as it reads many times more per second than it transmits. Anyways, thanks for the help.

What baud rate do the radios work at? only 2400?

Do some maths about how many bytes you send out in each pass, and then you can figure out how many samples/sec you could expect this to do.

Have a side remark: it seems like the transmitter you’re using doesn’t encode the data signal.

This means you are responsable for the 50-50% balance of the data signal to get optimal transmission.

You should use bi-phase encoding on the bits you send out. But if you prefer to use the UART, you could create a table of 50/50 balanced bytes (like 0xAA, 0x55, 0xCC, 0x33, 0xA5, 0x5A, …) and encode your ASCII data with it.

[quote]What baud rate do the radios work at? only 2400?

Do some maths about how many bytes you send out in each pass, and then you can figure out how many samples/sec you could expect this to do.[/quote]I’ve tested it with 1200 as well as 4800 and 2400 produced the best results.

[quote]Have a side remark: it seems like the transmitter you’re using doesn’t encode the data signal.

This means you are responsable for the 50-50% balance of the data signal to get optimal transmission.

You should use bi-phase encoding on the bits you send out. But if you prefer to use the UART, you could create a table of 50/50 balanced bytes (like 0xAA, 0x55, 0xCC, 0x33, 0xA5, 0x5A, …) and encode your ASCII data with it.[/quote]Could you please explain what you mean by “balancing” the data signal?

Well, I’ll try to explain with my little RF experience… Maybe someone else can pick in here…

The modules you are using, use ASK modulation. This means they vary the amplitude of the 433Mhz signal.

Because the amplitude also changed when the distance between sender and receiver changes, they apply a sort of AGC (automatic gain control) in the receiver that averages out the amplitude.

Now, to let the receiver get the best average, you need a 50:50 mark:space balanced signal. This you can acheive by using bi-phase encoding. Or, when using a normal UART, by only sending bytes that have a close to 50:50 mark:space balance (where, in binary form, the number of 1’s match number of 0’s, like a 0xAA).

Because of this, you only have a limited number of bytes you can send. So you’ll have to encode your ASCII data into a combination of those bytes.

I read and used all of this years ago when I was using +/- the same RX/TX modules (but from Radiometrix) and had troubles to reach the distance mentioned in the datasheet.

I’ll see if I can find some code of how I implemented this.

[quote]Well, I’ll try to explain with my little RF experience… Maybe someone else can pick in here…

The modules you are using, use ASK modulation. This means they vary the amplitude of the 433Mhz signal.

Because the amplitude also changed when the distance between sender and receiver changes, they apply a sort of AGC (automatic gain control) in the receiver that averages out the amplitude.

Now, to let the receiver get the best average, you need a 50:50 mark:space balanced signal. This you can acheive by using bi-phase encoding. Or, when using a normal UART, by only sending bytes that have a close to 50:50 mark:space balance (where, in binary form, the number of 1’s match number of 0’s, like a 0xAA).

Because of this, you only have a limited number of bytes you can send. So you’ll have to encode your ASCII data into a combination of those bytes.

I read and used all of this years ago when I was using +/- the same RX/TX modules (but from Radiometrix) and had troubles to reach the distance mentioned in the datasheet.

I’ll see if I can find some code of how I implemented this.[/quote]
I’ve been reading a bit about Manchester Coding and Decoding. You convert 1 to 01 and 0 to 10 to balance it out, essentially making one byte into two bytes transmitted. Is that something along the same lines?

In my code from years ago, I send a byte folowed by it’s binary inverse (XOR with 0xFF) at a baudrate of 31250 baud (but your transceivers are limited to 8K)

I think manchester would be great for that.