I am currently working on a serial monitor, to ensure some data integrity I am trying to implement a CRC8 checksum, below is the calculation i do on any messages before i send them.
public byte Checksum(params byte[] val)
{
if (val == null)
throw new ArgumentNullException("val");
byte c = 0;
foreach (byte b in val)
{
c = table[c ^ b];
}
return c;
}
I generate a table using 0xD8:
public byte[] GenerateTable(CRC8_POLY polynomial)
{
byte[] csTable = new byte[256];
for (int i = 0; i < 256; ++i)
{
int curr = i;
for (int j = 0; j < 8; ++j)
{
if ((curr & 0x80) != 0)
{
curr = (curr << 1) ^ (int)polynomial;
}
else
{
curr <<= 1;
}
}
csTable[i] = (byte)curr;
}
return csTable;
}
This is a code i have used for testing the setup:
private void btnSend_Click(object sender, EventArgs e)
{
ProtoFrame rxFrame = new ProtoFrame();
if (cboParam.Text == "test")
{
rxFrame.Start = 0x73;
rxFrame.Size = 9;
rxFrame.Command = 01;
rxFrame.Unused = 0;
rxFrame.ParamId = 0x0100;
rxFrame.Param = 8000;
}
byte[] rxBuffer = getBytes(rxFrame); //call to byte array formatter
rxBuffer[rxBuffer.Length-1] = Checksum(rxBuffer); //append crc at end of array
ComPort.Write(rxBuffer, 0, rxBuffer.Length);
}
static byte[] getBytes(object str) //input struct
{
int size = Marshal.SizeOf(str) + 1;
byte[] arr = new byte[size];
IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(str, ptr, true);
Marshal.Copy(ptr, arr, 0, size);
Marshal.FreeHGlobal(ptr);
return arr;
}
As far as i know this code work as intendended, and im using the table generator to implement a hardcoded table in my microcontroller, to speed up the process.
What i dont quite get is how i implement a function to calculate the CRC in a similar way as i do here.
Any help or guides in the right direction is aprreciated.
So far i have come up with this function:
uint8_t crc8(uint8_t *crc)
{
uint8_t crcVal;
int m;
for (m = 0; m < PacketSize ;m++ )startbyte
{
*crc = crc8_table[(*crc) ^ m];
*crc &= 0xFF;
}
}
where table is:
uint8_t crc8_table[256] = {0,24,48,40,96,120,80,72,192,216,240,232,160,184,144,136,88,64,104,112,56,32,8,16,
152,128,168,176,248,224,200,208,176,168,128,152,208,200,224,248,112,104,64,88,16,8,
32,56,232,240,216,192,136,144,184,160,40,48,24,0,72,80,120,96,184,160,136,144,216,
192,232,240,120,96,72,80,24,0,40,48,224,248,208,200,128,152,176,168,32,56,16,8,64,
88,112,104,8,16,56,32,104,112,88,64,200,208,248,224,168,176,152,128,80,72,96,120,48,
40,0,24,144,136,160,184,240,232,192,216,168,176,152,128,200,208,248,224,104,112,88,
64,8,16,56,32,240,232,192,216,144,136,160,184,48,40,0,24,80,72,96,120,24,0,40,48,120,
96,72,80,216,192,232,240,184,160,136,144,64,88,112,104,32,56,16,8,128,152,176,168,224,
248,208,200,16,8,32,56,112,104,64,88,208,200,224,248,176,168,128,152,72,80,120,96,40,
48,24,0,136,144,184,160,232,240,216,192,160,184,144,136,192,216,240,232,96,120,80,72,
0,24,48,40,248,224,200,208,152,128,168,176,56,32,8,16,88,64,104,112
};
and PacketSize is found from rxFrame.Size
So you simply need to port your C# function to C
public byte Checksum(params byte[] val)
{
if (val == null)
throw new ArgumentNullException("val");
byte c = 0;
foreach (byte b in val)
{
c = table[c ^ b];
}
return c;
}
I. there are no exceptions in C. Use return value to indicate errors and add an argument that you'll use as a return value. It's up to you to decide whether to pass a message length as a parameter or leave it at the global scope:
int checksum(uint8_t const *msg, size_t msglen, uint8_t *result)
II. foreach loop is converted to for loop, where i is index and msg[i] is the b from the foreach:
int checksum(uint8_t const *msg, size_t msglen, uint8_t *result)
{
if (msg == NULL || msglen == 0)
return 0;
uint8_t crc = 0;
for (int i = 0; i < msglen; i++)
{
crc = table[crc ^ msg[i]];
}
III. Store the result and return a success code:
int checksum(uint8_t const *msg, size_t msglen, uint8_t *result)
{
if (msg == NULL || msglen == 0)
return 0;
uint8_t crc = 0;
for (int i = 0; i < msglen; i++)
{
crc = table[crc ^ msg[i]];
}
*result = crc;
return 1;
}
IV. Usage:
uint8_t crc;
if (!checksum(message, PacketSize, &crc))
report_error();
Looking at the C# code should be:
uint8_t crc8(uint8_t const *crc, size_t size)
{
unit8_t c = 0;
size_t m;
for (m = 0; m < size; m++ )
{
c = crc8_table[c ^ *crc];
crc++;
}
return c;
}
Don't use pointers, convert to arrays
public static byte crc8(byte[] crc)
{
byte crcVal;
int m;
for (m = 0; m < PacketSize; m++)
{
crc[m] = crc8_table[crc[m] ^ m];
crc[m] &= 0xFF;
}
return crcVal;
}
I'm new with working with reading tiff images and I'm trying to get the elevation terrain values from a tiff map by using LibTiff. The maps I need to decode are tile organized. Below the fragment of the code I'm using currently to get these values, based on the library documentation and research on the web:
private void getBytes()
{
int numBytes = bitsPerSample / 8; //Number of bytes depending the tiff map
int stride = numBytes * height;
byte[] bufferTiff = new byte[stride * height]; // this is the buffer with the tiles data
int offset = 0;
for (int i = 0; i < tif.NumberOfTiles() - 1; i++)
{
int rawTileSize = (int)tif.RawTileSize(i);
offset += tif.ReadEncodedTile(i, bufferTiff, offset, rawTileSize);
}
values = new double[height, width]; // this is the matrix to save the heigth values in meters
int ptr = 0; // pointer for saving the each data bytes
int m = 0;
int n = 0;
byte[] byteValues = new byte[numBytes]; // bytes of each height data
for (int i = 0; i < bufferTiff.Length; i++)
{
byteValues[ptr] = bufferTiff[i];
ptr++;
if (ptr % numBytes == 0)
{
ptr = 0;
if (n == height) // tiff map Y pixels
{
n = 0;
m++;
if (m == width) // tiff map X pixels
{
m = 0;
}
}
values[m, n] = BitConverter.ToDouble(byteValues, 0); // Converts each byte data to the height value in meters. If the map is 32 bps the method I use is BitConverter.ToFloat
if (n == height - 1 && m == width - 1)
break;
n++;
}
}
SaveArrayAsCSV(values, "values.txt");
}
//Only to show results in a cvs file:
public void SaveArrayAsCSV(double[,] arrayToSave, string fileName) // source: http://stackoverflow.com/questions/8666518/how-can-i-write-a-general-array-to-csv-file
{
using (StreamWriter file = new StreamWriter(fileName))
{
WriteItemsToFile(arrayToSave, file);
}
}
//Only to show results in a cvs file:
private void WriteItemsToFile(Array items, TextWriter file) // source: http://stackoverflow.com/questions/8666518/how-can-i-write-a-general-array-to-csv-file
{
int cont = 0;
foreach (object item in items)
{
if (item is Array)
{
WriteItemsToFile(item as Array, file);
file.Write(Environment.NewLine);
}
else {
file.Write(item + " | ");
cont++;
if(cont == width)
{
file.Write("\n");
cont = 0;
}
}
}
}
I've been testing two different maps (32 and 64 bits per sample) and the results are similar: At the begining, the data seems to be consistent, but there is a point in which all the other values are corrupted (even zero at the end of data results). I deduce there are some bytes that need to be ignored, but I don't know how identify them to depurate my code. The method Tiff.ReadScanline does not work for me, because the maps I need to decode are tiles organized, and this method is not for working with these kind of images (according to BitMiracle.LibTiff documentation). The method Tiff.ReadRGBATile is not valid neither, because the tiff images are not RGB. I can read these values with Matlab, but my project needs to be built in C#, so I can compare the expected results with mine. As reference (I think it could be helpful), these are some data extracted from one of the tiff files with LibTiff tag reading methods:
ImageWidth: 2001
ImageLength: 2001
BitsPerSample: 32
Compression: PackBits (aka Macintosh RLE)
Photometric: MinIsBlack
SamplesPerPixel: 1
PlanarConfig: Contig
TileWidth: 208
TileLength: 208
SampleFormat: 3
Thanks in advance by your help guys!
Ok, Finally I found the solution: My mistake was the parameter "count" in the function Tiff.ReadEncodedTile(tile, buffer, offset, count). The Tiff.RawTileSize(int) function, returns the compressed bytes size of the tile (different for each tile, depending of the compression algorithm), but Tiff.ReadEncodedTile returns the decompressed bytes (bigger and constant for all tiles). That's why not all the information was been saved properly, but just a part of data. Below the correct code with the terrain elevation matrix (need optimization but it works, I think it could be helpful)
private void getBytes()
{
int numBytes = bitsPerSample / 8;
int numTiles = tif.NumberOfTiles();
int stride = numBytes * height;
int bufferSize = tileWidth * tileHeight * numBytes * numTiles;
int bytesSavedPerTile = tileWidth * tileHeight * numBytes; //this is the real size of the decompressed bytes
byte[] bufferTiff = new byte[bufferSize];
FieldValue[] value = tif.GetField(TiffTag.TILEWIDTH);
int tilewidth = value[0].ToInt();
value = tif.GetField(TiffTag.TILELENGTH);
int tileHeigth = value[0].ToInt();
int matrixSide = (int)Math.Sqrt(numTiles); // this works for a square image (for example a tiles organized tiff image)
int bytesWidth = matrixSide * tilewidth;
int bytesHeigth = matrixSide * tileHeigth;
int offset = 0;
for (int j = 0; j < numTiles; j++)
{
offset += tif.ReadEncodedTile(j, bufferTiff, offset, bytesSavedPerTile); //Here was the mistake. Now it works!
}
double[,] aux = new double[bytesHeigth, bytesWidth]; //Double for a 64 bps tiff image. This matrix will save the alldata, including the transparency (the "blank zone" I was talking before)
terrainElevation = new double[height, width]; // Double for a 64 bps tiff image. This matrix will save only the elevation values, without transparency
int ptr = 0;
int m = 0;
int n = -1;
int contNumTile = 1;
int contBytesPerTile = 0;
int i = 0;
int tileHeigthReference = tileHeigth;
int tileWidthReference = tileWidth;
int row = 1;
int col = 1;
byte[] bytesHeigthMeters = new byte[numBytes]; // Buffer to save each one elevation value to parse
while (i < bufferTiff.Length && contNumTile < numTiles + 1)
{
for (contBytesPerTile = 0; contBytesPerTile < bytesSavedPerTile; contBytesPerTile++)
{
bytesHeigthMeters[ptr] = bufferTiff[i];
ptr++;
if (ptr % numBytes == 0 && ptr != 0)
{
ptr = 0;
n++;
if (n == tileHeigthReference)
{
n = tileHeigthReference - tileHeigth;
m++;
if (m == tileWidthReference)
{
m = tileWidthReference - tileWidth;
}
}
double heigthMeters = BitConverter.ToDouble(bytesHeigthMeters, 0);
if (n < bytesWidth)
{
aux[m, n] = heigthMeters;
}
else
{
n = -1;
}
}
i++;
}
if (i % tilewidth == 0)
{
col++;
if (col == matrixSide + 1)
{
col = 1;
}
}
if (contNumTile % matrixSide == 0)
{
row++;
n = -1;
if (row == matrixSide + 1)
{
row = 1;
}
}
contNumTile++;
tileHeigthReference = tileHeight * (col);
tileWidthReference = tileWidth * (row);
m = tileWidth * (row - 1);
}
for (int x = 0; x < height; x++)
{
for (int y = 0; y < width; y++)
{
terrainElevation[x, y] = aux[x, y]; // Final result. Each position of matrix has saved each pixel terrain elevation of the map
}
}
}
Regards!
Here is an improved code, works with non-square tiles:
int imageWidth = tiff.GetField(TiffTag.IMAGEWIDTH)[0].ToInt();
int imageHeight = tiff.GetField(TiffTag.IMAGELENGTH)[0].ToInt();
int bytesPerSample = (int)tiff.GetField(TiffTag.BITSPERSAMPLE)[0].ToInt() / 8;
SampleFormat format = (SampleFormat)tiff.GetField(TiffTag.SAMPLEFORMAT)[0].ToInt();
//Array to return
float[,] decoded = new float[imageHeight, imageWidth];
//Get decode function (I only want a float array)
Func<byte[], int, float> decode = GetConversionFunction(format, bytesPerSample);
if (decode == null)
{
throw new ArgumentException("Unsupported TIFF format:"+format);
}
if(tiff.IsTiled())
{
//tile dimensions in pixels - the image dimensions MAY NOT be a multiple of these dimensions
int tileWidth = tiff.GetField(TiffTag.TILEWIDTH)[0].ToInt();
int tileHeight = tiff.GetField(TiffTag.TILELENGTH)[0].ToInt();
//tile matrix size
int numTiles = tiff.NumberOfTiles();
int tileMatrixWidth = (int)Math.Ceiling(imageWidth / (float)tileWidth);
int tileMatrixHeight = (int)Math.Ceiling(imageHeight / (float)tileHeight);
//tile dimensions in bytes
int tileBytesWidth = tileWidth * bytesPerSample;
int tileBytesHeight = tileHeight * bytesPerSample;
//tile buffer
int tileBufferSize = tiff.TileSize();
byte[] tileBuffer = new byte[tileBufferSize];
int imageHeightMinus1 = imageHeight - 1;
for (int tileIndex = 0 ; tileIndex < numTiles; tileIndex++)
{
int tileX = tileIndex / tileMatrixWidth;
int tileY = tileIndex % tileMatrixHeight;
tiff.ReadTile(tileBuffer, 0, tileX*tileWidth, tileY*tileHeight, 0, 0);
int xImageOffset = tileX * tileWidth;
int yImageOffset = tileY * tileHeight;
for (int col = 0; col < tileWidth && xImageOffset+col < imageWidth; col++ )
{
for(int row = 0; row < tileHeight && yImageOffset+row < imageHeight; row++)
{
decoded[imageHeightMinus1-(yImageOffset+row), xImageOffset+col] = decode(tileBuffer, row * tileBytesWidth + col * bytesPerSample);
}
}
}
}
i try to write a function that calculate IP Header Checksum using this example.
So first i have my IP header bytes:
byte[] arr = {
69, 0, 0, 60, 28, 70, 64, 0, 64, 6,
0, 0, 172, 16, 10, 99, 172, 16, 10, 12
};
Here i am add all pairs of bytes:
public static ushort[] AddPairs(byte[] arr)
{
List<ushort> pairs = new List<ushort>();
for (int i = 0; i < arr.Length; i += 2)
{
byte b1 = arr[i];
byte b2 = arr[i + 1];
ushort add = (ushort)((arr[i] << 8) + arr[i + 1]);
pairs.Add(add);
}
return pairs.ToArray();
}
And here i need to calculate the Checksum:
public static void ComputeHeaderIpChecksum(byte[] arr)
{
ushort[] pairs = AddPairs(arr);
ushort result;
ushort tmp = 0;
for (int i = 0; i < pairs.Length; i++)
{
result = (ushort)(pairs[i] + pairs[i + 1]);
tmp = result;
}
}
So first after add 2 values how can i check if this is valid ushort without the carry ?
i am kind of stuck here and don't know what to do next and will glad for some help.
C code for checksum from microchip
WORD CalcIPChecksum(BYTE *buffer, WORD count)
{
// wordval = CalcIPChecksum(&pEEPROMbuf[0x0800 + 6], 51);
WORD i;
WORD *val;
union
{
WORD w[2];
DWORD dw;
} sum;
i = count >> 1;
val = (WORD *)buffer;
//unsigned char temp;
// Calculate the sum of all words
sum.dw = 0L;
while(i--)
{
//temp = *val;
sum.dw += (DWORD)*val++;
}
// Add in the sum of the remaining byte, if present
if (count & 0x1)
{
DWORD temp = (DWORD)*(BYTE *)val;
sum.dw += temp;
}
// Do an end-around carry (one's complement arrithmetic)
sum.dw = sum.w[0] + sum.w[1];
// Do another end-around carry in case if the prior add
// caused a carry out
sum.w[0] += sum.w[1];
WORD answer = ~sum.w[0];
// Return the resulting checksum
return ;
}
Same function in c#
private UInt16 CalcIPChecksum(byte[] buffer, ushort count,int offset)
{
ushort i =0;
byte[] val = StatMethods.memcpy(ref buffer, offset, count);// get_byte_arr(buffer, count, offset);
// public static byte[] memcpy(ref byte[] ar, int startposition, int offset)
UInt32 sum_dw = 0;
i = (ushort)(count >> 1);
sum_dw = 0;
int j = 0;
while (i > 0)
{
UInt16 restored = BitConverter.ToUInt16(val, j);
sum_dw += restored;
String s = sum_dw.ToString("X");
System.Diagnostics.Debug.WriteLine("Number: "+i+" -- "+"value:" + s);
j += 2;
i--;
}
var aa = count & 0x1;
if (Convert.ToBoolean(aa))
{
byte restored = val[j];
sum_dw += (byte)restored;
}
byte[] sum_wb = BitConverter.GetBytes(sum_dw);
UInt16 sum_w0 = (UInt16)((UInt16)sum_wb[0] + (UInt32)(sum_wb[1]<<8));
UInt16 sum_w1 = (UInt16)((UInt16)sum_wb[2] + (UInt32)(sum_wb[3] << 8));
sum_dw = (UInt32)sum_w0 + (UInt32 )sum_w1;
sum_wb = BitConverter.GetBytes(sum_dw);
sum_w0 = (UInt16)((UInt16)sum_wb[0] + (UInt32)(sum_wb[1] << 8));
sum_w1 = (UInt16)((UInt16)sum_wb[2] + (UInt32)(sum_wb[3] << 8));
sum_w0 += sum_w1;
var reverse = ~(sum_w0);
UInt16 ans = (UInt16)(~(sum_w0));
System.Diagnostics.Debug.WriteLine("Asnwer: "+reverse);
return (UInt16)reverse;
}
Hope it helps
I'm trying to create a VSTstream class based on this thread: http://vstnet.codeplex.com/discussions/228692.
To record and playback the sound I'm using the AsioOut object that gives me available to IntPtr[] buffers type in the callback function OnAudioAvailable().
To do this I created the VSTstream class, taking example from the thread linked, appropriately modified to process directly the IntPtr[] buffers.
During the various processes of casting, however, it gives me an error of "AccessViolationException", probably due to the casting wrong.
I'm testing the VSTstream class opening the Jacobi.Vst.Samples.Delay.dll
EDIT: The error occurs on this line:
Marshal.Copy(sourceBuffer[1], rightBuf, 0, sampleCount/channels);
Does anyone know what I did wrong? If you need additional information or code I'm available.
Thanks to all.
OnAudioAvailable():
private void OnAudioAvailable(object sender, AsioAudioAvailableEventArgs e)
{
//No Effect
for (int i = 0; i < e.InputBuffers.Length; i++)
{
MoveMemory(e.OutputBuffers[i], e.InputBuffers[i], e.SamplesPerBuffer * e.InputBuffers.Length * 2);
}
//Effect
if (Parametri.effetto)
{
//Accendo i plugin
for (int i = 0; i < plugins.Count; i++)
{
plugins[i].MainsChanged(true);
plugins[i].StartProcess();
}
//Processo i sample
vstStream.ProcessSample(e.OutputBuffers, 0, e.SamplesPerBuffer * e.InputBuffers.Length * 2, e.InputBuffers);
//Spengo i plugin
for (int i = 0; i < plugins.Count; i++)
{
plugins[i].StopProcess();
plugins[i].MainsChanged(false);
}
}
e.WrittenToOutputBuffers = true;
}
VSTstream class:
class VSTstream
{
public List<IVstPluginCommandStub> plugins;
VstAudioBufferManager vstBufManIn, vstBufManOut;
private VstAudioBuffer[] vstBufIn = null;
private VstAudioBuffer[] vstBufOut = null;
private int sampleRate, channels, blockSize;
private float[] leftBuf, rightBuf;
public VSTstream(int sampleRate, int channels, int blockSize, List<IVstPluginCommandStub> plugins)
{
this.plugins = plugins;
this.sampleRate = sampleRate;
this.channels = channels;
this.blockSize = blockSize;
plugins[0].SetBlockSize(blockSize);
plugins[0].SetSampleRate((float)sampleRate);
vstBufManIn = new VstAudioBufferManager(channels, blockSize); //*channels
vstBufManOut = new VstAudioBufferManager(channels, blockSize);
//vstBufIn = vstBufManIn.ToArray();
//vstBufOut = vstBufManOut.ToArray();
vstBufIn = vstBufManIn.Cast<VstAudioBuffer>().ToArray();
vstBufOut = vstBufManOut.Cast<VstAudioBuffer>().ToArray();
leftBuf = new float[(blockSize * 4)/channels];
rightBuf = new float[(blockSize * 4)/channels];
}
public int ProcessSample(IntPtr[] destBuffer, int offset, int sampleCount, IntPtr[] sourceBuffer)
{
//da IntPtr[L][R] a Lfloat[]+Rfloat[]
Marshal.Copy(sourceBuffer[0], leftBuf, 0, sampleCount/channels);// (/channels)
Marshal.Copy(sourceBuffer[1], rightBuf, 0, sampleCount/channels);
unsafe
{
fixed (float* Lfloat = &leftBuf[0])
{
fixed (float* Rfloat = &rightBuf[0])
{
for (int i = 0; i < sampleCount / channels; i++)
{
vstBufIn[0][i] = *(Lfloat + i);
vstBufIn[1][i] = *(Rfloat + i);
}
}
}
}
//Qui dovrà rimanere solo 'ProcessReplacing();'
//plugins[0].MainsChanged(true);
//plugins[0].StartProcess();
plugins[0].ProcessReplacing(vstBufIn, vstBufOut);
//plugins[0].StopProcess();
//plugins[0].MainsChanged(false);
unsafe
{
float* tmpBufL = ((IDirectBufferAccess32)vstBufOut[0]).Buffer;
float* tmpBufR = ((IDirectBufferAccess32)vstBufOut[1]).Buffer;
for (int i = 0; i < (sampleCount / channels); i++)
{
leftBuf[i] = *(tmpBufL + i);
rightBuf[i] = *(tmpBufR + i);
}
}
//da Lfloat[]+Rfloat[] a IntPtr[L][R]
Marshal.Copy(leftBuf, 0, destBuffer[0], sampleCount/channels);
Marshal.Copy(rightBuf, 0, destBuffer[1], sampleCount/channels);
return sampleCount;
}
}