Main Site Documentation

Converting from byte to string


#1

I am reading a GPS text string from a serial port and I need to parse the contents. The characters are in a byte array and I plan to convert it to s string and then use the substring function to extract the fields and evaluate them.

So my question is, how do I convert from byte array to a string. I have tried a few methods given on the web for C# but they are not working for me.

My second question: Is there a better way of doing this? Can I convert from part of a byte array, directly yo a double, for example.

Chris


#2

In the System.Text namespace there is a UTF8 class. This will allow you convert a byte array to a string.


#3

You can not directly convert a byte array to a Double unless you stored it as a byte array(there is no support to do this). Normally, you would convert the GPS data to a string, and then use
Double.Parse(s.substring()) to convert.


#4

Thanks for the quick reply!

I have the following:

   public string ByteArrayToString(byte[] input)
    {
        System.Text.UTF8Encoding enc = new UTF8Encoding();
        string str = enc.GetString(input);
        return str;
    }

but it seems that the GetString method is not available. What am I missing?

Chris


#5

new String(UTF8Encoding.UTF8.GetChars(buffer));


#6

you can receive the gps-string direkt

 serial.AutoReadLineEnabled = true;
            serial.LineReceivedEventDelimiter = "\r\n";
            serial.LineReceived += new GTI.Serial.LineReceivedEventHandler(serial_LineReceived);

the event is raised allways when a full string (CrLf-ended) was received


#7

OK, that is now working. Thanks everyone! This is the first time using C#, I am more familiar with VB.Net.

VB-Daniel: I am using the RS232 module and using the code described in the tutorial (http://wiki.tinyclr.com/index.php?title=RS232_Module). This does not seem to give as many options as the .NET Gadgeteer serial class. How do I use that class instead?

Chris


#8

In all cases, the general approach is to start with a byte array, use some method to convert it to a char array, and finally convert the char[] to a string.

In the System.Text.Encoding class, there are 2 methods that can convert a byte[] to a char[], and each method has its own peculiar nuances.

1.) If you decide to use Encoding.UTF8.GetChars():

The value of each byte in the array must be 127 or less. If the byte array contains a value of 128 or greater, an exception will be thrown. The byte-to-char conversion will permanently stop whenever a byte value of 0 is encountered. For example, if your byte array consists of { 65, 66, 67, 0, 69, 70 }, your resulting character array will be { ‘A’, ‘B’, ‘C’ }. All bytes starting from the 0 value onward are discarded. If the byte array begins with a 0, then everything will be discarded.

2.) If you decide to use Encoding.UTF8.GetDecoder().Convert():

The value of each byte in the array may span the entire range of 0 thru 255, and no exceptions will be thrown. Whenever a byte value of 0 is encountered, conversion will stop and all characters from that location onward will become a null character 0 ‘\0’. However, values of 128 and above, while these will not throw exceptions, may cause non-intuitive characters to be produced because the UTF-8 standard (unlike ASCII) allows characters to be composed if more than 1 byte, as detailed here: http://en.wikipedia.org/wiki/UTF-8

Most text streams will usually contain bytes from 0 thru 127. However, I have seen cases where bytes outside this range are occasionally received, possibly due to noise, etc. and it is smart to account for them if you want to build a reliable system.


#9

sorry, normally my world is vb-code

i think the serial class is member of the RS232.

void ProgramStarted()
{
    rs232.serialPort.LineReceived += 
    new GT.Interfaces.Serial.LineReceivedEventHandler(serialPort_LineReceived);
    rs232.serialPort.LineReceivedEventDelimiter = "\r\n";
    rs232.serialPort.AutoReadLineEnabled = true;
}
 
void serialPort_LineReceived(GT.Interfaces.Serial sender, string line)
{
    // Process data received
}


#10

Can you tell what is the source encoding for the message ?

If it is ASCII and you know the ASCII Code for the delimiter, I would suggest to manipulate directly from the Bytes instead of searching to have a string, if finally you need doubles.

With the ASCII Code, you’ll be able to easily know the shift (shift = [ASCII value] - 48). Example : 9 is (57) => shift = 57 - 48 = 9.

Then when you have each number retrieved, and you know the rank of the (from rank 0 to the length of the buffer -1), you can calculate:

number = 0;
for(rank = 0 to length-1)
number += shift * (rank * 10);

Then you have your number correct, without any encoding purpose !


#11

@ LouisCpro - normaly gps is sending in NMEA-format you receive in stringformat and CrLf .
so i think the way is reveiving the string, split it, a phrase te tokens.


#12

OK, then it should be something like a comma separator then.

Effectively it is a string based format, but you told us about bytes, so I guues in your case, you receive information via an RS port ?


#13

Following suggestions from this thread I am trying to use the LineReceivedEventHandler with:

   void initializers232()
    {
        rs232.Initialize(57600);
        rs232.serialPort.LineReceived += new GT.Interfaces.Serial.LineReceivedEventHandler(serialPort_DataReceived);
        rs232.serialPort.LineReceivedEventDelimiter = "\r\n";
        rs232.serialPort.AutoReadLineEnabled = true;

    }

When it runs I get:

Using mainboard GHI Electronics FEZHydra version 1.2
#### Exception System.InvalidOperationException - 0x00000000 (6) ####
#### Message:
#### System.IO.Ports.SerialPort::set_ReadTimeout [IP: 0009] ####
#### Gadgeteer.Interfaces.Serial::ReadLineProcess [IP: 0015] ####
A first chance exception of type ‘System.InvalidOperationException’ occurred in Microsoft.SPOT.Hardware.SerialPort.dll
An unhandled exception of type ‘System.InvalidOperationException’ occurred in Microsoft.SPOT.Hardware.SerialPort.dll

I have tried changing the order of the code. It seems that you must initialize first. This is without sending any data to the serial port. If I comment out:

        rs232.serialPort.AutoReadLineEnabled = true;

there is no error, but the event is never triggered and the buffer just overflows

Chris


#14

Awesome! Thanks andre.m. All working now.

This forum is amazing - real-time help.

Chris


#15

Everytime i try to convert a byte array to string i get Out of memory…array is 4004 length

GC: 2msec 39288 bytes used, 25092 bytes available
Type 0F (STRING ): 2508 bytes
Type 11 (CLASS ): 2292 bytes
Type 12 (VALUETYPE ): 132 bytes
Type 13 (SZARRAY ): 7020 bytes
Type 15 (FREEBLOCK ): 25092 bytes
Type 16 (CACHEDBLOCK ): 48 bytes
Type 17 (ASSEMBLY ): 17376 bytes
Type 18 (WEAKCLASS ): 48 bytes
Type 19 (REFLECTION ): 24 bytes
Type 1B (DELEGATE_HEAD ): 252 bytes
Type 1D (OBJECT_TO_EVENT ): 96 bytes
Type 1E (BINARY_BLOB_HEAD ): 5400 bytes
Type 1F (THREAD ): 1152 bytes
Type 20 (SUBTHREAD ): 144 bytes
Type 21 (STACK_FRAME ): 816 bytes
Type 27 (FINALIZER_HEAD ): 120 bytes
Type 31 (IO_PORT ): 144 bytes
Type 34 (APPDOMAIN_HEAD ): 72 bytes
Type 36 (APPDOMAIN_ASSEMBLY ): 1644 bytes
Failed allocation for 336 blocks, 4032 bytes

#### Exception System.OutOfMemoryException - CLR_E_OUT_OF_MEMORY (1) ####
#### Message: 
#### System.Text.UTF8Encoding::GetChars [IP: 0000] ####

#16

Your question is missing one or more of these details:[ul]
The name of the product.
The code you’re trying to run.
Details on your setup.[/ul]
(Generated by QuickReply)


#17
try
            {
                // ...
                // SD Card is inserted
                // Create a new storage device
                ssdPS = new PersistentStorage("SD");
                // Mount the file system
                ssdPS.MountFileSystem();

                // Assume one storage device is available, access it through 
                // Micro Framework and display available files and folders:
                Debug.Print(DateTime.Now.ToString() + " Getting files and folders:");
                if (VolumeInfo.GetVolumes()[0].IsFormatted)
                {
                    string rootDirectory =
                        VolumeInfo.GetVolumes()[0].RootDirectory;
                    string[] files = Directory.GetFiles(rootDirectory);
                    string[] folders = Directory.GetDirectories(rootDirectory);

                    Debug.Print("Files available on " + rootDirectory + ":");
                    for (int i = 0; i < files.Length; i++)
                        Debug.Print(files[i]);

                    Debug.Print("Folders available on " + rootDirectory + ":");
                    for (int i = 0; i < folders.Length; i++)
                        Debug.Print(folders[i]);



                    Debug.Print(VolumeInfo.GetVolumes()[0].FileSystem);

                    // Generate a looonnnggg string
                    string write = string.Empty;
                    string read = string.Empty;
                    for (int i = 0; i <= 10; i++)
                    {
                        write += "AAAA";
                        Debug.Print((i * 4).ToString() + " Bytes");
                    }

                    filePutContents(@ "\SD\TESTFILE.txt", write);
                    read = fileGetContents(@ "\SD\TESTFILE.txt");
                    if (read == write)
                        Debug.Print("Match");
                    else
                        Debug.Print("No match");



                    bSDActive = true;
                }
                else
                {
                    Debug.Print(DateTime.Now.ToString() + " Storage is not formatted. Format on PC with FAT32/FAT16 first.");
                }
                Thread.Sleep(2000);
                // Unmount
                ssdPS.UnmountFileSystem();
                ssdPS.Dispose();
            }
            catch
            {
                Debug.Print(DateTime.Now.ToString() + "  Ooops, it seems there is no SD card.");
                Thread.Sleep(5000);
                if (ssdPS != null) ssdPS.Dispose();
            }



        /// <summary>
        /// Get the contents of a file by path
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        private static string fileGetContents(string path)
        {
            // Create a file stream object
            FileStream fHandle = new FileStream(path, FileMode.Open, FileAccess.Read);

            // Create the byte array to hold the data
            byte[] data = new byte[fHandle.Length];

            // Copy the file data to the byte array
            fHandle.Read(data, 0, data.Length);

            // We're done.
            fHandle.Close();
           
            // Convert the bytes to string and return



           

            return  bytesToString(data);;
        }

        /// <summary>
        /// Write a string to a file
        /// </summary>
        /// <param name="path"></param>
        /// <param name="contents"></param>
        private static void filePutContents(string path, string contents)
        {
            // Create a file stream object
            FileStream fHandle = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write);

            // Get the byte array for the contents
            byte[] data = Encoding.UTF8.GetBytes(contents);

            // Write the contents
            fHandle.Write(data, 0, data.Length);

            // We're done.
            fHandle.Close();
        }

        /// <summary>
        /// Converts a byte array to a string
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static string bytesToString(byte[] bytes)
        {
            string s = string.Empty;

            for (int i = 0; i < bytes.Length; ++i)
                s += (char)bytes[i];

            return s;
        }

#18

Hi Zigbox, you can edit your post with the code using the pencil icon (above the post, right side). Then, highlight the code section and hit the 101010 button at the TOP LEFT (not the orange one below the input box) and resubmit it. That will format the code for you !


#19

try adding “Debug.EnableGCMessages(true)” at startup somewhere in your code so you can see if it reveals any useful tid bits. maybe something somewhere is being treated as a large memory block and consequently never cleaned up during normal GC runs.
…these are more form tracking the issue down than fixing.

to fix, one thing you can try is force GC to run before doing the conversion…but that would be a performance impact.,…which might be ok in your case depending on your needs.