I am stuck at typical problem of conversion of data formats in WPF application in C#. I am new to C#. The GUI i am working on is displaying temperatures after getting the bytes data from the UDS messages.
When the data received in the format like 41c00000( which is in float format), the below function is able to convert the data into temperature in Celsius (both negative and positive).
public static float ComposeFloat(List<string> list, bool bigEndian)
{
float val;
byte[] payload = { 0, 0, 0, 0 }; // Used for float conversions
// BitConverter needs a little endian list
if (bigEndian)
{
list.Reverse();
}
for (int i = 0; i < 4; i++)
{
payload[i] = Convert.ToByte(list[i], 16);
}
val = BitConverter.ToSingle(payload, 0); // convert to an ieee754 float
return val;
}
But for some other temperature sensor in our system, the UDS is giving the data in the format 00000028. Since the UDS message was giving the temperature in integer format, I modified the above code as shown below, completely ignoring the case about what will happen if the temperature would be negative, which is really big mistake.
public static float ComposeFloat_FromInt(List<string> list, bool bigEndian)
{
float val;
int[] payload = { 0, 0, 0, 0 };
if (bigEndian)
{
list.Reverse();
}
for (int i = 0; i < 4; i++)
{
payload[i] = Convert.ToInt32(list[i], 16);
}
val = (float)payload[0];
return val;
}
Please guide me what will be the data received from the system when temperature is negative by giving some example and how should i modify the function to cover the negative temperature case.
Assuming the system sends temperatures as 32-bit signed integers using two's complement, you can use BitConverter.ToInt32 method to convert the array directly to a signed integer:
public static int ComposeFloat_FromInt(List<string> list, bool bigEndian)
{
int val;
byte[] payload = { 0, 0, 0, 0 };
if (bigEndian)
{
list.Reverse();
}
for (int i = 0; i < 4; i++)
{
payload[i] = Convert.ToByte(list[i], 16);
}
val = BitConverter.ToInt32(payload, 0); // Converts a byte array to Int32
return val;
}
Related
I just got confused about how to convert an array of 4 signed bytes to a float number.
I just know for an array of unsigned bytes bts, probably I can use this function
BitConverter.ToSingle(bts, 0);
However, it looks like BitConverter.ToSingle only accepts byte array instead of sbyte array.
Could somebody give me some ideas please?
Thanks!
Maybe this:
float num = 0;
for (int i = 0; i < sbytesArr.Length; i++)
{
num = (num | sbytesArr[i]) << i * 4;
}
Float value = 5000.1234;
//
// Invoke BitConverter.GetBytes to convert double to bytes.
//
byte[] array = BitConverter.GetBytes(value);
foreach (byte element in array)
{
Console.WriteLine(element);
}
//
// You can convert the bytes back to a double.
//
Float result = BitConverter.Tofloat(array, 0);
Console.WriteLine(result);
Assuming that your signed bytes are in an array named sbts you can first of all convert to an unsigned byte array, and then use BitConverter.ToSingle().
byte[] bts = new byte[sbts.Length];
Buffer.BlockCopy(sbts, 0, bts, 0, sbts.Length);
float f = BitConverter.ToSingle(bts, 0);
It is a little known fact that byte and sbyte are interchangeable at the CLR level:
sbyte[] a = new sbyte[1];
byte[] b = (byte[])(object)a;
This code actually works at runtime. So can pass in the array that you have.
BitConverter.ToSingle((byte[])(object)bts, 0);
Call GetFloatValue method passing una array of four sbyte as parameter
public float GetFloatValue(sbyte[] data)
{
return bytesToFloat(data[0], data[1], data[2], data[3]);
}
private static float bytesToFloat(sbyte b0, sbyte b1, sbyte b2, sbyte b3)
{
int mantissa = (byte)b0 + ((byte)b1 << 8) + ((byte)b2 << 16);
return (float)(mantissa * Math.Pow(10, b3));
}
I have a method where I decode some information from a file, when I attempt to divide the value decoded by 10, let's say, it removes the last digit.
private int DecodeInt(byte[] bytes, int start)
{
int r2 = 0;
byte ch1 = bytes[start];
byte ch2 = bytes[start + 1];
int result = ch2 + (ch1 * 256);
if (result > 32767)
{
r2 = 0;
}
else
{
r2 = result;
}
return r2;
}
I know the value displayed should be 39.5.
Label_1.Text = (DecodeInt(Rec, 22)).ToString(); // Displays 395
Label_1.Text = (DecodeInt(Rec, 22) / 10).ToString(); // Displays 39
I'm confused as to why it doesn't function... I'm sure it will be simple adjustment but it's driving me a little mad.
You are dividing an int with an int so result will be in int only. What you can do is :
Label_1.Text = (DecodeInt(Rec, 22) / 10.0).ToString();
I looked here for my solution: https://stackoverflow.com/a/661042/2952390
double result = (double)DecodeInt(Rec,20)/(double)10;
Much easier than I thought, of course.
Have been searching the solution for two days.
I want to convert my wave 32 or 24 bits to a 16bit.
This my code after reading few stackoverflow topics):
byte[] data = Convert.FromBase64String("-- Wav String encoded --") (32 or 24 bits)
int conv = Convert.ToInt16(data);
byte[] intBytes = BitConverter.GetBytes(conv);
if (BitConverter.IsLittleEndian)
Array.Reverse(intBytes);
byte[] result = intBytes;
but when i writeAllbyte my result, nothing to hear...
Here is a method that cuts the least significant bits:
byte[] data = ...
var skipBytes = 0;
byte[] data16bit;
int samples;
if( /* data was 32 bit */ ) {
skipBytes = 2;
samples = data.Length / 4;
} else if( /* data was 24 bit */ ) {
skipBytes = 1;
samples = data.Length / 3;
}
data16bit = new byte[samples * 2];
int writeIndex = 0;
int readIndex = 0;
for(var i = 0; i < samples; ++i) {
readIndex += skipBytes; //skip the least significant bytes
//read the two most significant bytes
data16bit[writeIndex++] = data[readIndex++];
data16bit[writeIndex++] = data[readIndex++];
}
This assumes a little endian byte order (least significant byte is the first byte, usual for WAV RIFF). If you have big endian, you have to put the readIndex += ... after the two read lines.
You could implement your own conversion iterator for this task like so:
IEnumerable<byte> ConvertTo16Bit(byte[] data, int skipBytes)
{
int bytesToRead = 0;
int bytesToSkip = skipBytes;
int readIndex = 0;
while (readIndex < data.Length)
{
if (bytesToSkip > 0)
{
readIndex += bytesToSkip;
bytesToSkip = 0;
bytesToRead = 2;
continue;
}
if (bytesToRead == 0)
{
bytesToSkip = skipBytes;
continue;
}
yield return data[readIndex++];
bytesToRead--;
}
}
This way you don't have to create a new array if there is no need for it. And you could simply convert the data array to a new 16 bit array with the IEnumerable<T> extension methods:
var data16bit = ConvertTo16Bit(data, 1).ToArray();
Or if you don't need the array, you can iterate the data skipping the least significant bytes:
foreach (var b in ConvertTo16Bit(data, 1))
{
Console.WriteLine(b);
}
i want to convert double array to byte array and byte array to double array
using System.Collections.Generic;
using System.Collections;
using System.Text;
using System.Linq;
namespace BitConversion
{
class Program
{
static void Main(string[] args)
{
double[] Array = new double[] { 10.0, 20.0, 30.0, 40.0 };
byte[] byteArray = GetBytesAlt(Array);
for (int i = 0; i < byteArray.Length; i++)
{
Console.Write(byteArray[i]);
Console.Write(",");
}
Console.WriteLine();
double[] doubleArray = GetDoublesAlt(byteArray);
for (int i = 0; i < doubleArray.Length; i++)
{
Console.Write(doubleArray[i]);
Console.Write(",");
}
Console.WriteLine();
Console.ReadLine();
}
/// <summary>
/// convert to bytes
/// </summary>
/// <param name="values"></param>
/// <returns></returns>
static byte[] GetBytesAlt(double[] values)
{
/*var result = new byte[values.Length * sizeof(double)];
Buffer.BlockCopy(values, 0, result, 0, result.Length);
return result;*/
return values.SelectMany(value => BitConverter.GetBytes(value)).ToArray();
//return values.SelectMany(value => BitConverter.GetBytes(value)).ToArray();
}
static double[] GetDoublesAlt(byte[] bytes)
{
/* var result = new double[bytes.Length / sizeof(double)];
Buffer.BlockCopy(bytes, 0, result, 0, bytes.Length);
return result;*/
return Enumerable.Range(0, bytes.Length / sizeof(double)).Select(offset => BitConverter.ToDouble(bytes, offset * sizeof(double))).ToArray();
}
}
}
with the convert approach the when bytes are converted back to the doubles
the numbers are getting as 10.0,20.0, 30.0, 40.0.....
How to get back the same numbers?
I mean if the double entered is 10.0, 20.0 , 30.0 , 40.0
and i have get back the same number is 10.0,20.0,30.0,40.0.
There is no issue with your program - if you slightly modify your program and print the original as well as round-tripped array, you will indeed see that you get the same out-put.
For example,
Original: 10.1,20.2,30,40,
Round-trip: 10.1,20.2,30,40,
Here's the slightly modified code
class Program
{
static void Main(string[] args)
{
double[] Array = new double[] { 10.1, 20.2, 30.0, 40.0 };
Console.Write("Original:\t");
PrintArray(Array);
byte[] byteArray = GetBytesAlt(Array);
double[] doubleArray = GetDoublesAlt(byteArray);
Console.Write("Round-trip:\t");
PrintArray(doubleArray);
Console.ReadLine();
}
static void PrintArray(Double[] array)
{
for (int i = 0; i < array.Length; i++)
{
Console.Write(array[i]);
Console.Write(",");
}
Console.WriteLine();
}
// rest of methods are same
...
}
You are getting the correct numbers, it is only in writing to the console that you are loosing your .0 the two numbers are equivalant. 10.0 and 10. This is what your doubleArray looks like before writing.
Try changing your Console.Write statement to this:
for (int i = 0; i < doubleArray.Length; i++)
{
//Since you are forcing the .0 you need to make sure you have enough #'s
//for the level of precision you need. It is actually better to use the
//system default since 10.0 and 10 are functionaly equivalent.
Console.Write( doubleArray[i].ToString("##.0####"));
Console.Write(",");
}
How to format the number which can be converted to Byte[] (array);
I know how to convert the result value to byte[], but the problem is how to format the intermediate number.
This is by data,
int packet = 10;
int value = 20;
long data = 02; // This will take 3 bytes [Last 3 Bytes]
i need the long value, through that i can shift and I'll fill the byte array like this
Byte[0] = 10;
Byte[1] = 20;
Byte[2] = 00;
Byte[3] = 00;
Byte[4] = 02;
Byte 2,3,4 are data
but formatting the intermediate value is the problem. How to form this
Here is the sample
long data= 683990319104; ///I referred this as intermediate value.
This is the number i receiving from built in application.
Byte[] by = new byte[5];
for (int i = 0; i < 5; i++)
{
by[i] = (byte)(data & 0xFF);
data>>= 8;
}
Here
Byte[0] = 00;
Byte[1] = 00; //Byte 0,1,2 are Data (ie data = 0)
Byte[2] = 00;
Byte[3] = 65; //Byte 3 is value (ie Value = 65)
Byte[4] = 159; // Byte 4 is packet (is Packet = 159);
This is one sample.
Currently BitConverter.GetBytes(..) is ues to receive.
Byte while sending, the parameter is long.
So i want the format to generate the number 683990319104 from
packet = 159
value = 65
data = 0
I think now its in understandable format :)
Not entirely sure what you are asking exactly, but I think you are looking for BitConverter.GetBytes(data).
The use of 3 bytes to define the long seems unusual; if it is just the 3 bytes... why a long? why not an int?
For example (note I've had to make assumptions about your byte-trimming based on your example - you won't have the full int/long range...):
static void Main() {
int packet = 10;
int value = 20;
long data = 02;
byte[] buffer = new byte[5];
WritePacket(buffer, 0, packet, value, data);
for (int i = 0; i < buffer.Length; i++)
{
Console.Write(buffer[i].ToString("x2"));
}
Console.WriteLine();
ReadPacket(buffer, 0, out packet, out value, out data);
Console.WriteLine(packet);
Console.WriteLine(value);
Console.WriteLine(data);
}
static void WritePacket(byte[] buffer, int offset, int packet,
int value, long data)
{
// note I'm trimming as per the original question
buffer[offset++] = (byte)packet;
buffer[offset++] = (byte)value;
int tmp = (int)(data); // more efficient to work with int, and
// we're going to lose the MSB anyway...
buffer[offset++] = (byte)(tmp>>2);
buffer[offset++] = (byte)(tmp>>1);
buffer[offset] = (byte)(tmp);
}
static void ReadPacket(byte[] buffer, int offset, out int packet,
out int value, out long data)
{
// note I'm trimming as per the original question
packet = buffer[offset++];
value = buffer[offset++];
data = ((int)buffer[offset++] << 2)
| ((int)buffer[offset++] << 1)
| (int)buffer[offset];
}
oooh,
Its simple
int packet = 159
int value = 65
int data = 0
long address = packet;
address = address<<8;
address = address|value;
address = address<<24;
address = address|data;
now the value of address is 683990319104 and i termed this as intermediate value. Let me know the exact term.