Shop OBEX P1 Docs P2 Docs Learn Events
FullDuplexSerial encoding — Parallax Forums

FullDuplexSerial encoding

nisbusnisbus Posts: 46
edited 2010-03-28 17:38 in Propeller 1
Hi,

I've written a small program in C# that reads from the USB port of the Propeller protoboard (FTDI).
I'm running the HelloFullDuplexSerial demo from the Propeller tool and I can see that it's sending out "This is a test message" at regular intervals.
My C# application is picking up on the bytes received but I'm having troubles decoding the bytes into string on the PC side.

I always get a list of ? when I use ASCIIencoding do decode the message and similar results with unicode encoding.

Does anyone know what kind of decoding can be done on the PC side to translate the bytes coming from the propeller to a string??

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Thanks,
nisbus

Comments

  • Jesse MasseyJesse Massey Posts: 39
    edited 2010-03-28 02:31
    To test the encoding you should check the actual byte that you are receiving. So if your code to receive is:
    byte[noparse]/noparse buf = new byte[noparse][[/noparse]serialPort1.ReadBufferSize];
    serialPort1.Read(buf, 0, serialPort1.ReadBufferSize);

    you should look at the buf array and see what the actual data is. The first character in the array should be the decimal # 85 or 01010101 in binary which would equal the letter 'T'.

    Jesse
  • nisbusnisbus Posts: 46
    edited 2010-03-28 09:51
    I always seem to be getting the same sequence of bytes from the propeller.

    188 180 156 25

    I'm using this FTDI dll to read from the propeller.

    What am I doing wrong?
    Is there something else I should be using to read from the port?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Thanks,
    nisbus
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2010-03-28 11:49
    I found serial ports to be quite complicated. Over the years I've built up a collection of useful tools. Terminal programs are useful (the propeller has one) and Teraterm and Hyperterminal.

    A serial port sniffer program is extremely useful - you load it first then load the program that will use the port, eg the terminal program. See my link below - if you go to the propeller page near the bottom just above the last picture is the link.

    Also near that is a link to a huge vb.net program with examples of serial port code (xmodem file transfers etc) using vb.net which is similar to C. There are unicode issues there - eg outputting strings in vb.net only sends 7 bits instead of 8 bits. Not simple to debug that one. I read it into byte arrays first. Then there is the issue of scanning the port continuously or writing code that runs an interrupt when a byte appears. I never got the latter working so I ended up just polling the port every 30 milliseconds or so.

    Can you post your C code?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    www.smarthome.viviti.com/propeller
  • nisbusnisbus Posts: 46
    edited 2010-03-28 12:01
    Now I've changed from the FTDI driver to using System.IO.Ports.SerialPort and reading from that directly.

    I'm getting the same resulting byte sequence as from the FTDI driver.

    This is the code for the serial port reading:

    public class SerialPortReader
    {
        private SerialPort port;
        public SerialPortReader(string portName)
        {
           port = new SerialPort(portName);//ex. COM13
           port.BaudRate = 57600;//Set to the same baudRate as the HelloFullDuplexSerial demo
    
           port.Encoding = new UTF8Encoding(true);//Enable the port to read 8bit bytes
           port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
        }
    
        private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
             byte[noparse][[/noparse]] bytes = new byte[noparse][[/noparse]port.ReadBufferSize];
             port.Read(bytes, 0, port.ReadBufferSize);
             //HERE the bytes are always 188,180,156,25 which results in ?,?,?,? as they are outside the ASCII table (except 25 which is end of medium).
             var dataAsString = BufferToString(buffer);
        }
    
       private string BufferToString(byte[noparse][[/noparse]] buffer)
       {
                System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding(true);
                return encoding.GetString(buffer);
       }
    }
    
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Thanks,
    nisbus
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2010-03-28 12:19
    Hmm - code looks ok.

    I've had all sorts of problems with serial ports over the years. Do you have a second USB to serial adaptor? If so, can you fire up a terminal program, send data out one serial port and read it in another port with your program? Just swap pins 2 and 3 on the two male plugs with a female to female adaptor.

    Having said that, there may be something simpler. Despite the propeller being able to run at 115k for downloads, I've never managed to get it to output a byte reliably at anything > then 38k. I don't understand why as the hardware is the same so maybe it is something in the software driver. So perhaps first start by dropping the baud rate back to something really safe and slow (1200) on the propeller side and change the C code accordingly.

    Have you got that serial port sniffer program - that will help a lot too as it will tell you if the problem is the propeller not sending properly (subtle timing errors from the xtal?) or the PC ncode not receiving properly.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    www.smarthome.viviti.com/propeller
  • nisbusnisbus Posts: 46
    edited 2010-03-28 12:30
    Dropping to 1200 makes no difference other than that now I get bytes 128, 128, 128,0 over and over again.

    I don't have a second serial port adapter so I can't test that.
    I'm downloading a serial port sniffer now.

    Thanks for your help.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Thanks,
    nisbus
  • kwinnkwinn Posts: 8,697
    edited 2010-03-28 13:11
    The most common problem I see for problems like you are describing is a mismatch in the setup of the serial ports. First try using PST (Parallax Serial Terminal) on your PC to receive the data from the prop. If that works you know the hardware is ok. If it does not work make sure PST has the correct com port selected, the baud rate matches that of FullDuplex Serial (FDS) and it is enabled.

    If PST works as expected check:

    The data from the prop is the correct polarity - reverse polarity on prop using invert tx (mode bit 1)

    Data from FDS is always 8 bits, no parity so make sure the port on the PC is set for 8 bits, no parity, one stop bit, and matching baud rate.
  • Dave HeinDave Hein Posts: 6,347
    edited 2010-03-28 13:13
    How do you set the baud rate on the PC side?· Do you receive the same number of bytes that are transmitted, or do you get fewer or more bytes on the PC side?· Receiving a series of 128's would be consistent with running the PC serial port at·8 times the transmit rate (assuming the reciever samples in the middle of the bit time).· Transmitting a 0-bit followed by a 1-bit would look like a 128 on the receiver side if it is running 8 times faster.

    Try setting the prop baud rate to 9600.

    Post Edited (Dave Hein) : 3/28/2010 1:33:47 PM GMT
  • Jesse MasseyJesse Massey Posts: 39
    edited 2010-03-28 14:23
    Maybe try changing the DataBits property to 7 instead of 8 or changing encoding to UTF7Encoding? Also what type of handshaking are you doing, software or hardware.

    Jesse
  • Mike GMike G Posts: 2,702
    edited 2010-03-28 15:00
    Give this a shot… Sorry, I created a win form but you should get the idea.


    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.IO;
    using System.IO.Ports;
    
    namespace SimpleSerialPortListener
    {
        public partial class Form1 : Form
        {
            private SerialPort port;
    
            public Form1()
            {
                InitializeComponent();
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {
                port = new SerialPort("COM5", 57600);
                port.Open();
                port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
            }
    
            private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
            {
                byte[noparse][[/noparse]] bytes = new byte[noparse][[/noparse]port.BytesToRead];
                int byteRead = port.Read(bytes, 0, port.BytesToRead);
    
                byte[noparse][[/noparse]] rxBytes = new byte[noparse][[/noparse]byteRead];
    
                for (int j = 0; j < byteRead; j++)
                {
                    rxBytes[noparse][[/noparse]j] = bytes[noparse][[/noparse]j];
                }
            }
    
        }
    
    }
    
    



    Suggestions:
    I use BytesToRead because rarely do I exceed the serial port buffer size.

    SerialPort.Read(buffer, offset, count) always returns the number of bytes read. Use the number of bytes to enumerate the buffer argument.

    Remove the encoding, at least for now. The serial port default should be fine. Take a look at the serial port help file for more information.

    Create another handler or method in the port_DataReceived() handler. This handler or method should frame up the received data. You cannot be sure that the data received event will contain a single "This is a test message<cr>". It could be 1 byte or 100 bytes. This handler or method will look for each <cr> (0x13) in a public buffer ("This is a test message<cr>This is a test message<cr>This is a test") then fire off an event or invoke a delegate. Pass a single "This is a test message<cr>" argument each time you fine a match in the buffer. Don't forget to remove the "This is a test message<cr>" from your buffer once you find the match and invoke the delegate. Always append to the end of the buffer on each SerialPort.Read(buffer, offset, count). That way you don't miss anything.

    Hope this helps. Let me know if you need anything.

    Post Edited (Mike G) : 3/28/2010 3:27:41 PM GMT
  • nisbusnisbus Posts: 46
    edited 2010-03-28 17:13
    Hi,

    I set the BaudRate to 1200 on the PC side and setting it to 9600 on the Prop side gives me the correct data [noparse]:)[/noparse]
    It doesn't seem to matter what I set as BaudRate on the PC side.

    I now get "This is a test message!" on my PC !!

    All I need to do now is implement some framing on the PC side to catch only whole messages.

    Thanks so much for all your time.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Thanks,
    nisbus
  • Mike GMike G Posts: 2,702
    edited 2010-03-28 17:19
    nisbus said...
    I set the BaudRate to 1200 on the PC side and setting it to 9600 on the Prop side gives me the correct data [noparse]:)[/noparse]

    That does not make sense at all. In the demo I provided, the PC and Prop were both set to 57600. I loaded HelloFullDuplexSerial demo and ran the C# code as is.

    PUB TestMessages
    
      ''Send test messages to Parallax Serial Terminal.
     
      Debug.start(31, 30, 0, 57600)
    
  • nisbusnisbus Posts: 46
    edited 2010-03-28 17:19
    Sorry my bad,

    I had two constructors on the PC side and one was setting the BaudRate while the other wasn't. I was using the one that wasn't [noparse]:)[/noparse]
    If I set both to 57600 I get correct data as well.
    So after all this was about setting the matching baud rate.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Thanks,
    nisbus
  • Mike GMike G Posts: 2,702
    edited 2010-03-28 17:22
    Ah... smile.gif

    This was about how to use the SerialPort.Read() method.

    After you frame up the messages, the next thing you'll need to do is figure out how to update the UI on the main thread tongue.gif

    Post Edited (Mike G) : 3/28/2010 5:34:23 PM GMT
  • Mike GMike G Posts: 2,702
    edited 2010-03-28 17:31
    Updating the UI will look something like this

    
            // serail port data received thread safe delegate
            public delegate void SetTextCallback(String message);
    
    
            private void SetText(String message)
            {
                try
                {
                    if (txtStatus.InvokeRequired)
                    {
                        SetTextCallback del = new SetTextCallback(SetText);
                        this.Invoke(del, message);
                    }
                    else
                    {
                        txtStatus.AppendText(message);
                        txtStatus.AppendText("\r\n");
                    }
                }
                catch (Exception ex)
                {
                    // do something
                }
            }
    
    
  • nisbusnisbus Posts: 46
    edited 2010-03-28 17:38
    I'm using WPF on the PC side and updating the UI is fairly simple.

    I have an ObservableCollection<string> to hold the data that is bound to a listbox:

    In the constructor I catch the CurrentDispatcher
      Dispatcher uiDispatcher = Dispatcher.CurrentDispatcher:
    
    


    and on the event that gets messages I do this:

                uiDispatcher.BeginInvoke(DispatcherPriority.Background, new ThreadStart(() =>
                {
                    ReadData.Add(BufferToString(bytes));
                }));
    
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Thanks,
    nisbus
Sign In or Register to comment.