Netduino home hardware projects downloads community

Jump to content


Photo

BitConverter


  • Please log in to reply
8 replies to this topic

#1 Ravenheart

Ravenheart

    Member

  • Members
  • PipPip
  • 18 posts
  • LocationBulgaria

Posted 10 September 2010 - 11:58 AM

I was in need of the BitConverter class in one of my projects, but alas NETMF does not have it :rolleyes: so here is my implementation, despite all references you CAN USE unsafe code in NETMF, just not the "fixed" keyword.
In order to use this open your project's Properties and tick the "Allow unsafe code" checkbox under the Build tab.

You are free to use the code in any type of project(commercial, open-source etc.), you can modify and distribute the code as you wish.

Note that using unsafe code is not documented, so even though it works fine under test conditions, we can't be sure just yet that it doesn't have side effects.

public static class BitConverter
    {
        public static unsafe long DoubleToInt64Bits(double value)
        {
            return *(((long*)&value));
        }
        public static unsafe double Int64BitsToDouble(long value)
        {
            return *(((double*)&value));
        }

        public static byte[] GetBytes(bool value)
        {
            return new byte[] { (value ? ((byte)1) : ((byte)0)) };
        }
        public static byte[] GetBytes(char value)
        {
            return new byte[2] { (byte)(value & 0xFF), (byte)((value >> 8) & 0xFF) };
        }
        public static byte[] GetBytes(short value)
        {
            return new byte[2] { (byte)(value & 0xFF), (byte)((value >> 8) & 0xFF) };
        }
        public static byte[] GetBytes(ushort value)
        {
            return new byte[2] { (byte)(value & 0xFF), (byte)((value >> 8) & 0xFF) };
        }
        public static byte[] GetBytes(int value)
        {
            return new byte[4] { 
                    (byte)(value & 0xFF), 
                    (byte)((value >> 8) & 0xFF), 
                    (byte)((value >> 16) & 0xFF), 
                    (byte)((value >> 24) & 0xFF) };
        }
        public static byte[] GetBytes(uint value)
        {
            return new byte[4] { 
                    (byte)(value & 0xFF), 
                    (byte)((value >> 8) & 0xFF), 
                    (byte)((value >> 16) & 0xFF), 
                    (byte)((value >> 24) & 0xFF) };
        }
        public static byte[] GetBytes(long value)
        {
            return new byte[8] { 
                    (byte)(value & 0xFF), 
                    (byte)((value >> 8) & 0xFF), 
                    (byte)((value >> 16) & 0xFF), 
                    (byte)((value >> 24) & 0xFF),
                    (byte)((value >> 32) & 0xFF),
                    (byte)((value >> 40) & 0xFF),
                    (byte)((value >> 48) & 0xFF),
                    (byte)((value >> 56) & 0xFF)};
        }
        public static byte[] GetBytes(ulong value)
        {
            return new byte[8] { 
                    (byte)(value & 0xFF), 
                    (byte)((value >> 8) & 0xFF), 
                    (byte)((value >> 16) & 0xFF), 
                    (byte)((value >> 24) & 0xFF),
                    (byte)((value >> 32) & 0xFF),
                    (byte)((value >> 40) & 0xFF),
                    (byte)((value >> 48) & 0xFF),
                    (byte)((value >> 56) & 0xFF)};
        }
        public static unsafe byte[] GetBytes(float value)
        {
            int val =*((int*)&value);
            return GetBytes(val);
        }
        public static unsafe byte[] GetBytes(double value)
        {
            long val = *((long*)&value);
            return GetBytes(val);
        }

        public static bool ToBoolean(byte[] value, int index = 0)
        {
            return value[index] != 0;
        }
        public static char ToChar(byte[] value, int index = 0)
        {
            return (char)(value[0 + index] << 0 | value[1 + index] << 8);
        }
        public static short ToInt16(byte[] value, int index = 0)
        {
            return (short)(
                value[0 + index] << 0 |
                value[1 + index] << 8);
        }
        public static int ToInt32(byte[] value, int index = 0)
        {
            return (
                value[0 + index] << 0 |
                value[1 + index] << 8 |
                value[2 + index] << 16 |
                value[3 + index] << 24);
        }
        public static long ToInt64(byte[] value, int index = 0)
        {
            return (
                value[0 + index] << 0 |
                value[1 + index] << 8 |
                value[2 + index] << 16 |
                value[3 + index] << 24 |
                value[4 + index] << 32 |
                value[5 + index] << 40 |
                value[6 + index] << 48 |
                value[7 + index] << 56);
        }
        public static ushort ToUInt16(byte[] value, int index = 0)
        {
            return (ushort)(
                value[0 + index] << 0 |
                value[1 + index] << 8);
        }
        public static uint ToUInt32(byte[] value, int index = 0)
        {
            return (uint)(
                value[0 + index] << 0 |
                value[1 + index] << 8 |
                value[2 + index] << 16 |
                value[3 + index] << 24);
        }
        public static ulong ToUInt64(byte[] value, int index = 0)
        {
            return (ulong)(
                value[0 + index] << 0 |
                value[1 + index] << 8 |
                value[2 + index] << 16 |
                value[3 + index] << 24 |
                value[4 + index] << 32 |
                value[5 + index] << 40 |
                value[6 + index] << 48 |
                value[7 + index] << 56);
        }

        public static unsafe float ToSingle(byte[] value, int index = 0)
        {
            int i = ToInt32(value);
            return *(((float*)&i));
        }
        public static unsafe double ToDouble(byte[] value, int index = 0)
        {
            long l = ToInt64(value);
            return *(((double*)&l));
        }

        public static string ToString(byte[] value, int index = 0)
        {
            return ToString(value, index, value.Length - index);
        }
        public static string ToString(byte[] value, int index, int length)
        {
            char[] c = new char[length * 3];
            byte b;

            for (int y = 0, x = 0; y < length; ++y, ++x)
            {
                b = (byte)(value[index + y] >> 4);
                c[x] = (char)(b > 9 ? b + 0x37 : b + 0x30);
                b = (byte)(value[index + y] & 0xF);
                c[++x] = (char)(b > 9 ? b + 0x37 : b + 0x30);
                c[++x] = '-';
            }
            return new string(c, 0, c.Length - 1);
        }
    }

Edited by Ravenheart, 10 September 2010 - 03:54 PM.


#2 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7165 posts
  • LocationNew York, NY

Posted 12 September 2010 - 04:37 AM

Whoa, unsafe code works in .NET MF? I never thought I'd see pointers used in C# on Netduinos :) We'll want to make sure to mention that unsafe code is a pretty advanced topic...but I think it's awesome that you're pushing the boundaries! [Please be aware that technically if the .NET MF docs say that unsafe code is not supported...that it might not work in the future. The docs may say that it's unsupported simply because it's untested...or maybe because in the future the .NET MF team might take out the unsupported feature to make room for something else. You never know, but cool nonetheless. I wonder if it works all the time--or only in certain circumstances?] Chris

#3 timothyp

timothyp

    New Member

  • Members
  • Pip
  • 6 posts

Posted 26 January 2011 - 10:08 PM

Hi,

Has this been tested with all values,
ToInt64 for example fails with large values.

long x = Int64.MaxValue;
var data = BitConverter.GetBytes(x);
var result = ToInt64(data);
Debug.Assert(x == result);


#4 Corey Kosak

Corey Kosak

    Advanced Member

  • Members
  • PipPipPip
  • 276 posts
  • LocationHoboken, NJ

Posted 01 February 2011 - 03:04 PM

ToInt64 for example fails with large values.

There do seem to be a couple of bugs. The specific problem you point out can be fixed like this:
    public static long ToInt64(byte[] value, int index = 0) {
      return (
          (long)value[0 + index] << 0) |
          (long)value[1 + index] << 8 |
          (long)value[2 + index] << 16 |
          (long)value[3 + index] << 24 |
          (long)value[4 + index] << 32 |
          (long)value[5 + index] << 40 |
          (long)value[6 + index] << 48 |
          (long)value[7 + index] << 56;
    }

The code for ToUInt64 will require a similar fix. (I haven't looked carefully at the rest of it so I'm not sure if that's the last bug :) )

#5 Luke Cummings

Luke Cummings

    Advanced Member

  • Members
  • PipPipPip
  • 38 posts
  • LocationCalgary, AB

Posted 08 February 2011 - 12:31 AM

If you are at all concerned with speed and/or the gc, you should try my approach:

When dealing with bit conversions always use the Utility class, for instance working with floats:
public static unsafe float ToFloat(ref byte[] buffer, int offset)
{
   uint value = Utility.ExtractValueFromArray(buffer, offset, 4);
   return *((float*) &value);
}
public static unsafe void ToBytes(ref byte[] buffer, int offset, float value)
{
   Utility.InsertValueIntoArray(buffer, offset, 4, *((uint*) &value));
}

Note that the name ToBytes isn't exactly accurate as normally a bit converter would return the array, but usually you are using this to pack data in a long buffer, and using the reference saves the additional hit for making a new array.

or how about a double word sized variable:
public static long ToLong(ref byte[] buffer, int offset)
{
   long value = (long)Utility.ExtractValueFromArray(buffer, offset, 4) << 32;
   value |= Utility.ExtractValueFromArray(buffer, offset + 4, 4);
   return value;
}
public static void ToBytes(ref byte[] buffer, int offset, long value)
{
   Utility.InsertValueIntoArray(buffer, offset, 4, (uint)(value >> 32));
   Utility.InsertValueIntoArray(buffer, offset + 4, 4, (uint)value);
}

Obviously you could adapt this for any other types you require. These are just what I use in my current project.

Cheers
Cheap, Fast, Good... Pick two

#6 Arbiter

Arbiter

    Advanced Member

  • Members
  • PipPipPip
  • 132 posts
  • LocationBrisbane, Australia

Posted 10 January 2012 - 06:44 AM

You know, most of these dodgy hacks are motivated by the very limited elbow room. It seems like it doesn't matter what I try to do, the library is missing and there isn't enough space to DIY. I'm rapidly coming to the conclusion that it would be less hassle to use C on an Arduino. Yes yes I know you don't talk about new toys till you're in a position to deliver. But all I did was create a webrequest and read a file and BLAM, out of RAM. I'm tinkering with a very simplified protocol and direct socket control but it sure aint the .NET I was hoping for. I would happily cough up $300 for a Netduino style of board running Compact Framework on a Snapdragon if it meant I could have LINQ, file-system and WebServices at the same time without running out of memory.
One day, all this too shall parse.

#7 Corey Kosak

Corey Kosak

    Advanced Member

  • Members
  • PipPipPip
  • 276 posts
  • LocationHoboken, NJ

Posted 10 January 2012 - 04:48 PM

The Netduino's extremely limited RAM space is certainly frustrating at times. On the other hand I suppose that's why it's available at such a low cost. There are other more powerful boards with the Micro Framework on them... since you have more to spend, perhaps you want to try one of them? Maybe you want a .NET Gadgeteer? You're not going to get real LINQ until the Micro Framework supports generics, and I'm not aware of a plan to support generics any time soon.

#8 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7165 posts
  • LocationNew York, NY

Posted 11 January 2012 - 01:30 AM

Hi Arbiter, When downloading web pages with a small microcontroller, you'll want to buffer them (similar to an AVR on an Arduino). Unfortunately, there's no good way around that without adding external RAM, etc. Web pages are big! There are a few .NET MF boards available with lots of RAM. I'm recommend taking a look at the Device Solutions .NET MF boards if you have a few hundred dollars to spend on a bigger devboard. Most of your code will work in both places. Chris

#9 aalmada

aalmada

    Advanced Member

  • Members
  • PipPipPip
  • 44 posts
  • LocationPortugal

Posted 21 April 2012 - 07:21 PM

I've created a complete BitConverter for NETMF: https://bitbucket.or...BitConverter.cs It's based on the Utility class as suggested here by Luke but still uses "unsafe" to deal with floats and doubles. I looked into alternatives to the "unsafe", as it's not officially supported, but only found dead ends: 1) [StructLayout(LayoutKind.Explicit)] is supported but [FieldOffset(0)] is not. 2) TypedReference struct is supported but the FieldInfo.SetValueDirect method is not. aalmada




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

home    hardware    projects    downloads    community    where to buy    contact Copyright © 2010-2014 Secret Labs LLC  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.