CRC_82_Darc function in C# - c#

I need to calculate the CRC_82_Darc hash in C#. Is there any preexisting Lib for this or did someone already write a function ? I could not find anything on Google.

Here is a simple bit-wise implementation in C:
// CRC-82/DARC Calculation
// Placed into the public domain by Mark Adler, 17 June 2017.
// CRC definition:
// width=82 poly=0x0308c0111011401440411 init=0 refin=true refout=true xorout=0
// check=0x09ea83f625023801fd612 name="CRC-82/DARC"
#include <stddef.h>
#include <stdint.h>
#define POLYHIGH 0x22080
#define POLYLOW 0x8a00a2022200c430
// Update crc[0..1] with the CRC-82/DARC of the len bytes at buf. If buf is
// NULL, then initialize crc[0..1] with the CRC-82/DARC of an empty message.
// The low 64 bits of the CRC are in crc[0], and the high 18 bits of the CRC
// are in the low 18 bits of crc[1]. The remaining bits of crc[1] are always
// zero.
void crc82darc(uint64_t *crc, void const *buf, size_t len) {
if (buf == NULL) {
crc[0] = crc[1] = 0;
return;
}
uint64_t cl = crc[0], ch = crc[1] & 0x3ffff;
for (size_t i = 0; i < len; i++) {
cl ^= ((unsigned char const *)buf)[i];
for (int k = 0; k < 8; k++) {
uint64_t low = cl & 1;
cl = (cl >> 1) | (ch << 63);
ch >>= 1;
if (low) {
cl ^= POLYLOW;
ch ^= POLYHIGH;
}
}
}
crc[0] = cl;
crc[1] = ch;
}
#ifdef TEST
#include <stdio.h>
int main(void)
{
uint64_t crc[2];
crc82darc(crc, NULL, 0); // initialize crc
crc82darc(crc, "123456789", 9);
printf("0x%05llx%016llx\n", crc[1], crc[0]);
return 0;
}
#endif

Related

How to edit this code to calculate CRC-32/MPEG in C#

I have this code which calculate CRC-32, I need to edit this code with: Polynomial 0x04C11DB7 ,Initial value: 0xFFFFFFFF , XOR:0 .
So CRC32 for string "123456789" should be"0376E6E7", I found a code, it's very slow , But it works any way.
```internal static class Crc32
{
internal static uint[] MakeCrcTable()
{
uint c;
uint[] crcTable = new uint[256];
for (uint n = 0; n < 256; n++)
{
c = n;
for (int k = 0; k < 8; k++)
{
var res = c & 1;
c = (res == 1) ? (0xEDB88320 ^ (c >> 1)) : (c >> 1);
}
crcTable[n] = c;
}
return crcTable;
}
internal static uint CalculateCrc32(byte[] str)
{
uint[] crcTable = Crc32.MakeCrcTable();
uint crc = 0xffffffff;
for (int i = 0; i < str.Length; i++)
{
byte c = str[i];
crc = (crc >> 8) ^ crcTable[(crc ^ c) & 0xFF];
}
return ~crc; //(crc ^ (-1)) >> 0;
}
}```
Based on the added comments, what you are looking for is CRC-32/MPEG-2, which reverses the direction of the CRC, and eliminates the final exclusive-or, compared to the implementation you have, which is a CRC-32/ISO-HDLC.
To get there, you need to flip the CRC from reflected to forward. You bit-flip the polynomial to get 0x04c11db7, check the high bit instead of the low bit, reverse the shifts, both in the table generation and use of the table, and exclusive-or with the high byte of the CRC instead of the low byte.
To remove the final exclusive-or, remove the tilde at the end.

Correctness of multiplication in galois field

I'm into developing code to do arithmetic in Galois field gf(2^8) and I think I'm getting wrong results on multiplication operations.
private static byte Multiply(byte a, byte b)
{
byte result = 0;
while (b != 0)
{
if ((b & 1) != 0)
{
result ^= a;
}
a <<= 1;
b >>= 1;
}
return result;
}
The result for Multiply(1, 2) gives the correct value of 2 but Multiply(240, 249) gives me 112 instead of the expected 148.
Now I'm not sure if this value is good or not with Russian Peasant Multiplication.
Maybe there's another algorithm that gives correct results?
Example code:
#define POLY 0x11D
static BYTE GFMpy(BYTE b0, BYTE b1)
{
int i;
int product;
product = 0;
for(i = 0; i < 8; i++){
product <<= 1;
if(product & 0x100){
product ^= POLY;}
if(b0 & 0x80u){
product ^= b1;}
b0 <<= 1;}
return((BYTE)product);
}
Example using lookup tables:
#define POLY (0x11d)
/* all non-zero elements are powers of 2 for POLY == 0x11d */
typedef unsigned char BYTE;
/* ... */
static BYTE exp2[512];
static BYTE log2[256];
/* ... */
static void Tbli()
{
int i;
int b;
b = 0x01; /* init exp2 table */
for(i = 0; i < 512; i++){
exp2[i] = (BYTE)b;
b = (b << 1); /* powers of 2 */
if(b & 0x100)
b ^= POLY;
}
log2[0] = 0xff; /* init log2 table */
for(i = 0; i < 255; i++)
log2[exp2[i]] = (BYTE)i;
}
/* ... */
static BYTE GFMpy(BYTE m0, BYTE m1) /* multiply */
{
if(0 == m0 || 0 == m1)
return(0);
return(exp2[log2[m0] + log2[m1]]);
}
/* ... */
static BYTE GFDiv(BYTE m0, BYTE m1) /* divide */
{
if(0 == m0)
return(0);
return(exp2[log2[m0] + 255 - log2[m1]]);
}

Convert esp8266 code(part of it) to c/c++ or c#

Hi im trying to repeat this wifi baby monitor project based on esp8266:
baby monitor project
But instead of receiving data on another esp8266, I want to receive data on pc.
I'm a c # programmer and I've encountered an problem of understanding c/c++ pointers how arrays works here and receive udp.
this is esp8266 receiver source code which works without any problems, but data that it receives, passes them to DAC. And i cant figure out where i can read just values one by one which was readed by esp8266 transmiter from ADC. Also readed data from ADC is 12 bit and author of original code use all 16 bit with some compression to transfer more data, and this compression part is what i have difficulty to uderstand it
#include <Wire.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <WiFiUdp.h>
#include "ESP8266mDNS.h"
#include <ArduinoOTA.h>
//#include "wifi_params.h"
const int mySDA = D7;
const int mySCL = D6;
const int AMPLI_MUTE_PIN = D2;
const int AMPLI_SHUTDOWN_PIN = D1;
const int RIGHT_BTN = D3;
const int LEFT_BTN = D4;
const int LED1 = D8;
const int udp_recv_port = 45990;
WiFiUDP udp;
TwoWire i2c;
#define NB_DATA_BUFS 5
uint16_t data_buf[NB_DATA_BUFS][700]; // data buffer, N buffered
unsigned int current_play_data_buf; // current data buf being played
unsigned int play_data_buf_pos; // position in the ADC data buffer
unsigned int current_recv_data_buf; // current data buf being received
bool play_waiting = true;
bool amplifier_stopped = false;
long play_waiting_at;
bool left_btn_pressed;
bool right_btn_pressed;
#define ICACHE_RAM_ATTR __attribute__((section(".iram.text")))
#define twi_sda mySDA
#define twi_scl mySCL
#define twi_dcount 0
#define twi_clockStretchLimit 10
#define SDA_LOW() (GPES = (1 << twi_sda)) //Enable SDA (becomes output and since GPO is 0 for the pin, it will pull the line low)
#define SDA_HIGH() (GPEC = (1 << twi_sda)) //Disable SDA (becomes input and since it has pullup it will go high)
#define SDA_READ() ((GPI & (1 << twi_sda)) != 0)
#define SCL_LOW() (GPES = (1 << twi_scl))
#define SCL_HIGH() (GPEC = (1 << twi_scl))
#define SCL_READ() ((GPI & (1 << twi_scl)) != 0)
static void twi_delay(unsigned char v) {
unsigned int i;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
unsigned int reg;
for (i = 0; i<v; i++) reg = GPI;
#pragma GCC diagnostic pop
}
static inline ICACHE_RAM_ATTR bool twi_write_start(void) {
SCL_HIGH();
SDA_HIGH();
if (SDA_READ() == 0) return false;
SDA_LOW();
return true;
}
static inline ICACHE_RAM_ATTR bool twi_write_stop(void) {
uint32_t i = 0;
SCL_LOW();
SDA_LOW();
SCL_HIGH();
while (SCL_READ() == 0 && (i++) < twi_clockStretchLimit); // Clock stretching
SDA_HIGH();
return true;
}
static inline ICACHE_RAM_ATTR bool twi_write_bit(bool bit) {
uint32_t i = 0;
SCL_LOW();
if (bit) SDA_HIGH();
else SDA_LOW();
twi_delay(twi_dcount + 1);
SCL_HIGH();
while (SCL_READ() == 0 && (i++) < twi_clockStretchLimit);// Clock stretching
return true;
}
static inline ICACHE_RAM_ATTR bool twi_read_bit(void) {
uint32_t i = 0;
SCL_LOW();
SDA_HIGH();
twi_delay(twi_dcount + 2);
SCL_HIGH();
while (SCL_READ() == 0 && (i++) < twi_clockStretchLimit);// Clock stretching
bool bit = SDA_READ();
return bit;
}
static inline ICACHE_RAM_ATTR bool twi_write_byte(unsigned char byte) {
unsigned char bit;
for (bit = 0; bit < 8; bit++) {
twi_write_bit(byte & 0x80);
byte <<= 1;
}
return !twi_read_bit();//NACK/ACK
}
static inline ICACHE_RAM_ATTR unsigned char twi_read_byte(bool nack) {
unsigned char byte = 0;
unsigned char bit;
for (bit = 0; bit < 8; bit++) byte = (byte << 1) | twi_read_bit();
twi_write_bit(nack);
return byte;
}
unsigned char inline ICACHE_RAM_ATTR mytwi_writeTo(unsigned char address, unsigned char * buf, unsigned int len, unsigned char sendStop) {
unsigned int i;
if (!twi_write_start()) return 4;//line busy
if (!twi_write_byte(((address << 1) | 0) & 0xFF)) {
if (sendStop) twi_write_stop();
return 2; //received NACK on transmit of address
}
for (i = 0; i<len; i++) {
if (!twi_write_byte(buf[i])) {
if (sendStop) twi_write_stop();
return 3;//received NACK on transmit of data
}
}
if (sendStop) twi_write_stop();
i = 0;
while (SDA_READ() == 0 && (i++) < 10) {
SCL_LOW();
SCL_HIGH();
}
return 0;
}
static inline ICACHE_RAM_ATTR uint8_t DAC(uint16_t value)
{
/* value is 76543210 XXXXBA98
per the datasheet for fast write:
1 1 0 0 A2 A1 A0 0 <ACK> 0 0 PD1 PD0 D11 D10 D9 D8 <ACK> D7 D6 D5 D4 D3 D2 D1 D0 <ACK>
*/
uint8_t buf[2] = { (value >> 8) & 0x0F, (value & 0xFF) };
int ret = mytwi_writeTo(0x60, buf, 2, true);
Serial.println(value);
return ret;
}
void ICACHE_RAM_ATTR playsample_isr(void)
{
if (play_waiting) {
return;
}
DAC(data_buf[current_play_data_buf][play_data_buf_pos]);
play_data_buf_pos++;
if (play_data_buf_pos >= sizeof(data_buf[0]) / sizeof(data_buf[0][0])) {
play_data_buf_pos = 0;
current_play_data_buf++;
if (current_play_data_buf == NB_DATA_BUFS) {
current_play_data_buf = 0;
}
if (current_play_data_buf == current_recv_data_buf) {
play_waiting = true;
play_waiting_at = micros();
}
}
}
void ota_onstart(void)
{
// Disable timer when an OTA happens
timer1_detachInterrupt();
timer1_disable();
}
void ota_onprogress(unsigned int sz, unsigned int total)
{
Serial.print("OTA: "); Serial.print(sz); Serial.print("/"); Serial.print(total);
Serial.print("="); Serial.print(100 * sz / total); Serial.println("%");
}
void ota_onerror(ota_error_t err)
{
Serial.print("OTA ERROR:"); Serial.println((int)err);
}
void left_btn_intr()
{
left_btn_pressed = 1;
}
void right_btn_intr()
{
right_btn_pressed = 1;
}
void setup(void)
{
Serial.begin(115200);
Serial.println("I was built on " __DATE__ " at " __TIME__ "");
i2c.begin(mySDA, mySCL);
i2c.setClock(400000);
WiFi.mode(WIFI_STA);
WiFi.begin("valik 2", "299745buhlo");
WiFi.setSleepMode(WIFI_MODEM_SLEEP);
Serial.print("Connecting to wifi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Cnnectd to ");
Serial.println("valik 2");
Serial.print("IP ");
Serial.println(WiFi.localIP());
ArduinoOTA.onStart(ota_onstart);
ArduinoOTA.onError(ota_onerror);
ArduinoOTA.onProgress(ota_onprogress);
ArduinoOTA.setHostname("bb-recv");
ArduinoOTA.begin();
timer1_isr_init();
timer1_attachInterrupt(playsample_isr);
timer1_enable(TIM_DIV16, TIM_EDGE, TIM_LOOP);
timer1_write(clockCyclesPerMicrosecond() / 16 * 50); //50us = 20 kHz sampling freq
udp.begin(udp_recv_port);
pinMode(AMPLI_MUTE_PIN, OUTPUT);
pinMode(AMPLI_SHUTDOWN_PIN, OUTPUT);
digitalWrite(AMPLI_SHUTDOWN_PIN, 0);
digitalWrite(AMPLI_MUTE_PIN, 0);
pinMode(LEFT_BTN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(LEFT_BTN), left_btn_intr, FALLING);
pinMode(RIGHT_BTN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(RIGHT_BTN), right_btn_intr, FALLING);
pinMode(LED1, OUTPUT);
digitalWrite(LED1, 0);
}
int do_undelta7(const uint8_t *val, int sz, uint16_t *out)
{
// Implement delta 7 decompression.
// First bit = 0 <=> uncompressed 15 bits following
// First bit = 1 <=> 7 bits follow representing delta
// must switch to big endian...
uint16_t last = 0;
uint8_t *ptr = (uint8_t *)&out[0];
const uint8_t *start = ptr;
for (int i = 0; i < sz; i++) {
uint16_t *ptr16 = (uint16_t *)ptr;
const int8_t firstbyte = val[i];
if (firstbyte & 0x80) {
// Delta7 compressed
// byte is CSMMMMMM
int8_t delta = firstbyte & 0x3F;
if (firstbyte & 0x40) {
delta = -delta;
}
const uint16_t value = last + delta;
*ptr16 = value;
ptr += 2;
last = value;
}
else {
// uncompressed -- switch bytes back to LE
*ptr++ = val[i + 1];
*ptr++ = val[i];
last = val[i + 1] | val[i] << 8;
i++;
}
}
return ptr - start;
}
void loop(void)
{
ArduinoOTA.handle();
int sz = udp.parsePacket();
//Serial.println(current_play_data_buf);
if (sz) {
uint8_t buf[sz];
udp.read(&buf[0], sz);
current_recv_data_buf++;
if (current_recv_data_buf == NB_DATA_BUFS) {
current_recv_data_buf = 0;
if (current_recv_data_buf == current_play_data_buf && !play_waiting) {
Serial.println("buffer overflow when receiving");
}
}
do_undelta7(buf, sz, &data_buf[current_recv_data_buf][0]);
if (play_waiting) {
Serial.print("Restarting play, was waiting (us)"); Serial.println(micros() - play_waiting_at);
// Re-enable *then* unmute in that order to avoid pops
digitalWrite(AMPLI_SHUTDOWN_PIN, 1);
digitalWrite(AMPLI_MUTE_PIN, 1);
play_waiting = false;
amplifier_stopped = false;
digitalWrite(LED1, 1);
}
Serial.println("");
}
// If not playing anything, but amplifier is still up
if (!amplifier_stopped && play_waiting) {
if ((micros() - play_waiting_at) > 2000 * 1000) {
// If nothing has been played for two seconds, shut down the amplifier
Serial.println("Shutting down amplifier!");
digitalWrite(AMPLI_SHUTDOWN_PIN, 0);
digitalWrite(AMPLI_MUTE_PIN, 0);
amplifier_stopped = true;
digitalWrite(LED1, 0);
}
}
if (left_btn_pressed) {
left_btn_pressed = 0;
digitalWrite(AMPLI_MUTE_PIN, 0);
digitalWrite(AMPLI_SHUTDOWN_PIN, 0);
}
if (right_btn_pressed) {
digitalWrite(AMPLI_SHUTDOWN_PIN, 1);
digitalWrite(AMPLI_MUTE_PIN, 1);
udp.beginPacket(udp.remoteIP(), 45990);
udp.write("sendnow");
udp.endPacket();
right_btn_pressed = 0;
}
// If the amplifier is stopped, add a delay for power saving
if (amplifier_stopped) {
delay(10);
}
}
This is my attempt to translate code to c++ for windows. But i encountered problem where programm just freeze without any errors and without closing.
#include "stdafx.h"
#include <winsock2.h>
#include <stdio.h>
#include <cstdint>
#include <ctime>
#pragma comment (lib, "ws2_32.lib")
#define NB_DATA_BUFS 5
uint16_t data_buf[NB_DATA_BUFS][700]; // data buffer, N buffered
unsigned int current_play_data_buf; // current data buf being played
unsigned int play_data_buf_pos; // position in the ADC data buffer
unsigned int current_recv_data_buf; // current data buf being received
bool play_waiting = true;
bool amplifier_stopped = false;
long play_waiting_at;
bool left_btn_pressed;
bool right_btn_pressed;
void InitWinsock()
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
}
int do_undelta7(const uint8_t *val, int sz, uint16_t *out)
{
// Implement delta 7 decompression.
// First bit = 0 <=> uncompressed 15 bits following
// First bit = 1 <=> 7 bits follow representing delta
// must switch to big endian...
uint16_t last = 0;
uint8_t *ptr = (uint8_t *)&out[0];
const uint8_t *start = ptr;
for (int i = 0; i < sz; i++) {
uint16_t *ptr16 = (uint16_t *)ptr;
const int8_t firstbyte = val[i];
if (firstbyte & 0x80) {
// Delta7 compressed
// byte is CSMMMMMM
int8_t delta = firstbyte & 0x3F;
if (firstbyte & 0x40) {
delta = -delta;
}
const uint16_t value = last + delta;
*ptr16 = value;
ptr += 2;
last = value;
}
else {
// uncompressed -- switch bytes back to LE
*ptr++ = val[i + 1];
*ptr++ = val[i];
last = val[i + 1] | val[i] << 8;
i++;
}
}
return ptr - start;
}
void DAC(uint16_t value)
{
/* value is 76543210 XXXXBA98
per the datasheet for fast write:
1 1 0 0 A2 A1 A0 0 <ACK> 0 0 PD1 PD0 D11 D10 D9 D8 <ACK> D7 D6 D5 D4 D3 D2 D1 D0 <ACK>
*/
uint8_t buf[2] = { (value >> 8) & 0x0F, (value & 0xFF) };
printf("%u\n", value & 0xFFF);
}
int _tmain(int argc, _TCHAR* argv[])
{
SOCKET socketC;
InitWinsock();
struct sockaddr_in serverInfo;
int len = 2000;
serverInfo.sin_family = AF_INET;
serverInfo.sin_port = htons(45990);
serverInfo.sin_addr.s_addr = inet_addr("192.168.1.105");
socketC = socket(AF_INET, SOCK_DGRAM, 0);
char buffers[16];
ZeroMemory(buffers, sizeof(buffers));
sendto(socketC, buffers, sizeof(IReleaseMarshalBuffers), 0, (sockaddr*)&serverInfo, len);
while (1)
{
sockaddr_in from;
const int paketSize = sizeof(from);
int r = paketSize;
char buffer[paketSize];
sprintf(buffer, "%.7s", "sendnow");
if (strcmp(buffer, "exit") == 0)
break;
recvfrom(socketC, buffer, sizeof(buffer), 0, (sockaddr*)&serverInfo, &len);
uint8_t buf[sizeof(buffer)];
uint8_t * bufeerPntr = (uint8_t*)buffer;
uint8_t * bufPntr = (uint8_t*)buffer;
for(int i=0;i<sizeof(buffer);i++)
{
buf[i] = buffer[i];
}
//udp.read(&buf[0], sizeof(buffer));
current_recv_data_buf++;
if (current_recv_data_buf == NB_DATA_BUFS) {
current_recv_data_buf = 0;
if (current_recv_data_buf == current_play_data_buf && !play_waiting) {
printf("buffer overflow when receiving\n");
}
}
do_undelta7(buf, sizeof(buffer), &data_buf[current_recv_data_buf][0]);
}
closesocket(socketC);
return 0;
}
This is my attempt to translate decoding part to c# (c# is much easier for me to understand) but i forced to use pointers and strange * and & things which i have difficulty to understand:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
public class UDPListener
{
private const int listenPort = 45990;
public static int Main()
{
bool done = false;
UdpClient listener = new UdpClient(listenPort);
IPEndPoint groupEP = new IPEndPoint(IPAddress.Parse("192.168.1.3"), listenPort);
string received_data;
int BUFSIZE = 700;
byte[] receive_byte_array;
uint current_recv_data_buf = 1;
while (!done)
{
Console.WriteLine("Waiting for broadcast");
receive_byte_array = listener.Receive(ref groupEP);
Console.WriteLine("Received a broadcast from {0}", groupEP.ToString());
received_data = Encoding.ASCII.GetString(receive_byte_array, 0, receive_byte_array.Length);
unsafe
{
UInt16*[,] data_buf = new UInt16*[5, 700];
int sz = receive_byte_array.Length;
if (sz > 0)
{
byte[] buf = new byte[receive_byte_array.Length];
UInt16* f = stackalloc UInt16[2000];
//udp.read(&buf[0], sz);
buf = receive_byte_array;
current_recv_data_buf++;
UInt16 last = 0;
UInt16* #out1 = stackalloc UInt16[800];
for (int i = 0; i < 800; i++)
{
#out1[i] = (char)i;
}
//UIntPtr* ptr = (UIntPtr*)&#out[0];
UIntPtr* ptr = (UIntPtr*)&#out1[0];
UIntPtr* start = ptr;
for (int i = 0; i < sz; i++)
{
UIntPtr* ptr16 = ptr;
byte firstbyte = buf[i];
if ((firstbyte & 0x80) != 0)
{
// Delta7 compressed
// byte is CSMMMMMM
byte delta = (byte)(firstbyte & 0x3F);
if ((firstbyte & 0x40) != 0)
{
delta = (byte)(0 - delta);
}
UInt16 value = (UInt16)(last + delta);
*ptr16 = (UIntPtr)value;
ptr += 2;
last = value;
}
else
{
*ptr++ = (UIntPtr)buf[i + 1];
*ptr++ = (UIntPtr)buf[i];
last = (UInt16)(buf[i + 1] | buf[i] << 8);
i++;
}
}
for (int i = 0; i < 91; i++)
{
System.Console.WriteLine(#out1[i]);
}
string b = "";
}
}
}
listener.Close();
return 0;
}
} // end of class UDPListener
udp.read(&buf[0], sz); copies the received UDP packet into buffer buf. The function do_undelta7 then makes a decompression of the data in the input buffer to output buffer data_buf[current_recv_data_buf]. data_buf is array of buffers. The interrupt playsample_isr plays the content of the buffers in data_buf.
i missed an unsigned byte in do_undelta7
so now it's decoding well
c#
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Media;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using NAudio.Wave;
public class UDPListener
{
uint current_recv_data_buf;
static int NB_DATA_BUFS = 5;
static UInt16[] data_buf = new UInt16[700];
uint current_play_data_buf; // current data buf being played
uint play_data_buf_pos; // position in the ADC data buffer
private const int listenPort = 45990;
public static unsafe int Main()
{
bool done = false;
UdpClient listener = new UdpClient(listenPort);
IPEndPoint groupEP = new IPEndPoint(IPAddress.Parse("192.168.1.3"), listenPort);
int BUFSIZE = 700;
byte[] receive_byte_array;
uint current_recv_data_buf = 1;
List<byte> tenBuffsToPlay = new List<byte>();
int iterBuffsToPLay = 0;
byte[] byteArrToPlay = new byte[data_buf.Length * 2];
byte[] byte10ArrToPlay;
int pktcount = 0;
var sampleRate = 20000;
var frequency = 500;
var amplitude = 0.2;
var seconds = 5;
while (!done)
{
receive_byte_array = listener.Receive(ref groupEP);
if (receive_byte_array.Length > 0)
{
Console.WriteLine("received !"+pktcount++);
int sz = receive_byte_array.Length;
unsafe
{
byte[] buf = new byte[sz];
buf = receive_byte_array;
fixed (UInt16* data_bufPtr = &data_buf[0])
fixed (byte* ptrbuf = buf)
do_undelta7(ptrbuf, sz, data_bufPtr);
//string firstPart = "";
//string secondPart = "";
for (int i =0;i<data_buf.Length;i++)
{
//Console.WriteLine("Hex: {0:X}", data_buf[i]);
byteArrToPlay[i*2] = (byte)((data_buf[i] >> 8)&0x0f);
byteArrToPlay[(i*2)+1] = (byte)(data_buf[i] & 0xff);
//firstPart = Convert.ToString(byteArrToPlay[i], 2).PadLeft(4, '0');
//Console.Write(firstPart);
//secondPart = Convert.ToString(byteArrToPlay[i+1], 2).PadLeft(4, '0');
//Console.Write(secondPart+"\n");
}
//byteArrToPlay = data_buf.SelectMany(BitConverter.GetBytes).ToArray();
//foreach (var Arr in byteArrToPlay)
// {
// Console.WriteLine("Hex: {0:X}", Arr);
// }
tenBuffsToPlay.AddRange(byteArrToPlay);
iterBuffsToPLay++;
if (iterBuffsToPLay == 3)
{
byte10ArrToPlay = tenBuffsToPlay.ToArray();
/*var raw = new byte[sampleRate * seconds * 2];
var multiple = 2.0 * frequency / sampleRate;
for (int n = 0; n < sampleRate * seconds; n++)
{
var sampleSaw = ((n * multiple) % 2) - 1;
var sampleValue = sampleSaw > 0 ? amplitude : -amplitude;
var sample = (short)(sampleValue * Int16.MaxValue);
var bytes = BitConverter.GetBytes(sample);
raw[n * 2] = bytes[0];
raw[n * 2 + 1] = bytes[1];
}*/
var ms = new MemoryStream(byte10ArrToPlay);
var rs = new RawSourceWaveStream(ms, new WaveFormat(sampleRate, 16, 1));
var wo = new WaveOutEvent();
wo.Init(rs);
wo.Play();
/*while (wo.PlaybackState == PlaybackState.Playing)
{
Thread.Sleep(1);
}*/
//wo.Dispose();
/*using (MemoryStream ms = new MemoryStream())
{
WriteWavHeader(ms, false, 1, 16, 20000, (byte10ArrToPlay.Length / 2 - 45));
// Construct the sound player
ms.Write(byte10ArrToPlay, 0, byte10ArrToPlay.Length);
ms.Position = 0;
SoundPlayer player = new SoundPlayer(ms);
player.Play();
}*/
tenBuffsToPlay.Clear();
iterBuffsToPLay = 0;
}
}
}
}
listener.Close();
return 0;
}
static unsafe long do_undelta7(byte* val, int sz, UInt16* outArray)
{
// Implement delta 7 decompression.
// First bit = 0 <=> uncompressed 15 bits following
// First bit = 1 <=> 7 bits follow representing delta
// must switch to big endian...
UInt16 last = 0;
byte* ptr = (byte*)&outArray[0];
byte* start = ptr;
for (int i = 0; i < sz; i++)
{
UInt16* ptr16 = (UInt16*)ptr;
byte firstbyte = val[i];
var bit = (firstbyte & (1 << 8 - 1)) != 0;
if (bit == true)
{
// Delta7 compressed
// byte is CSMMMMMM
sbyte delta = (sbyte)(firstbyte & 0x3f);
bit = (firstbyte & (1 << 7 - 1)) != 0;
if (bit == true)
{
delta = (sbyte)(0x0 - delta);
}
UInt16 value = (UInt16)(last + delta);
*ptr16 = value;
ptr += 2;
last = value;
}
else
{
// uncompressed -- switch bytes back to LE
*ptr++ = val[i + 1];
*ptr++ = val[i];
last = (UInt16)(val[i + 1] | val[i] << 8);
i++;
}
}
return ptr - start;
}
private static void WriteWavHeader(MemoryStream stream, bool isFloatingPoint, ushort channelCount, ushort bitDepth, int sampleRate, int totalSampleCount)
{
stream.Position = 0;
stream.Write(Encoding.ASCII.GetBytes("RIFF"), 0, 4);
stream.Write(BitConverter.GetBytes((2* totalSampleCount) + 36), 0, 4);
stream.Write(Encoding.ASCII.GetBytes("WAVE"), 0, 4);
stream.Write(Encoding.ASCII.GetBytes("fmt "), 0, 4);
stream.Write(BitConverter.GetBytes(16), 0, 4);
stream.Write(BitConverter.GetBytes((ushort)(isFloatingPoint ? 3 : 1)), 0, 2);
stream.Write(BitConverter.GetBytes(channelCount), 0, 2);
stream.Write(BitConverter.GetBytes(sampleRate), 0, 4);
stream.Write(BitConverter.GetBytes(sampleRate * 2), 0, 4);
stream.Write(BitConverter.GetBytes((ushort)2), 0, 2);
stream.Write(BitConverter.GetBytes(16), 0, 2);
stream.Write(Encoding.ASCII.GetBytes("data"), 0, 4);
stream.Write(BitConverter.GetBytes(2 * totalSampleCount), 0, 4);
}
} // end of class UDPListener

Calculating CRC16 in C#

I'm trying to port an old code from C to C# which basically receives a string and returns a CRC16 of it...
The C method is as follow:
#define CRC_MASK 0x1021 /* x^16 + x^12 + x^5 + x^0 */
UINT16 CRC_Calc (unsigned char *pbData, int iLength)
{
UINT16 wData, wCRC = 0;
int i;
for ( ;iLength > 0; iLength--, pbData++) {
wData = (UINT16) (((UINT16) *pbData) << 8);
for (i = 0; i < 8; i++, wData <<= 1) {
if ((wCRC ^ wData) & 0x8000)
wCRC = (UINT16) ((wCRC << 1) ^ CRC_MASK);
else
wCRC <<= 1;
}
}
return wCRC;
}
My ported C# code is this:
private static ushort Calc(byte[] data)
{
ushort wData, wCRC = 0;
for (int i = 0; i < data.Length; i++)
{
wData = Convert.ToUInt16(data[i] << 8);
for (int j = 0; j < 8; j++, wData <<= 1)
{
var a = (wCRC ^ wData) & 0x8000;
if ( a != 0)
{
var c = (wCRC << 1) ^ 0x1021;
wCRC = Convert.ToUInt16(c);
}
else
{
wCRC <<= 1;
}
}
}
return wCRC;
}
The test string is "OPN"... It must return a uint which is (ofc) 2 bytes A8 A9 and the #CRC_MASK is the polynomial for that calculation. I did found several examples of CRC16 here and around the web, but none of them achieve this result since this CRC calculation must match the one that the device we are connecting to.
WHere is the mistake? I really appreciate any help.
Thanks! best regards
Gutemberg
UPDATE
Following the answer from #rcgldr, I put together the following sample:
_serial = new SerialPort("COM6", 19200, Parity.None, 8, StopBits.One);
_serial.Open();
_serial.Encoding = Encoding.GetEncoding(1252);
_serial.DataReceived += Serial_DataReceived;
var msg = "OPN";
var data = Encoding.GetEncoding(1252).GetBytes(msg);
var crc = BitConverter.GetBytes(Calc(data));
var msb = crc[0].ToString("X");
var lsb = crc[1].ToString("X");
//The following line must be something like: \x16OPN\x17\xA8\xA9
var cmd = string.Format(#"{0}{1}{2}\x{3}\x{4}", SYN, msg, ETB, msb, lsb);
//var cmd = "\x16OPN\x17\xA8\xA9";
_serial.Write(cmd);
The value of the cmd variable is what I'm trying to send to the device. If you have a look the the commented cmd value, this is a working string. The 2 bytes of the CRC16, goes in the last two parameters (msb and lsb). So, in the sample here, msb MUST be "\xA8" and lsb MUST be "\xA9" in order to the command to work(the CRC16 match on the device).
Any clues?
Thanks again.
UPDATE 2
For those who fall in the same case were you need to format the string with \x this is what I did to get it working:
protected string ToMessage(string data)
{
var msg = data + ETB;
var crc = CRC16.Compute(msg);
var fullMsg = string.Format(#"{0}{1}{2:X}{3:X}", SYN, msg, crc[0], crc[1]);
return fullMsg;
}
This return to me the full message that I need inclusing the \x on it. The SYN variable is '\x16' and ETB is '\x17'
Thank you all for the help!
Gutemberg
The problem here is that the message including the ETB (\x17) is 4 bytes long (the leading sync byte isn't used for the CRC): "OPN\x17" == {'O', 'P', 'N', 0x17}, which results in a CRC of {0xA8, 0xA9} to be appended to the message. So the CRC function is correct, but the original test data wasn't including the 4th byte which is 0x17.
This is a working example (at least with VS2015 express).
private static ushort Calc(byte[] data)
{
ushort wCRC = 0;
for (int i = 0; i < data.Length; i++)
{
wCRC ^= (ushort)(data[i] << 8);
for (int j = 0; j < 8; j++)
{
if ((wCRC & 0x8000) != 0)
wCRC = (ushort)((wCRC << 1) ^ 0x1021);
else
wCRC <<= 1;
}
}
return wCRC;
}

Conversion of CRC function from C to C# yields wrong values

I'm trying to convert a couple of simple CRC calculating functions from C to C#, but I seem to be getting incorrect results.
The C functions are:
#define CRC32_POLYNOMIAL 0xEDB88320
unsigned long CRC32Value(int i)
{
int j;
unsigned long ulCRC;
ulCRC = i;
for (j=8;j>0;j--)
{
if (ulCRC & 1)
ulCRC = (ulCRC >> 1)^CRC32_POLYNOMIAL;
else
ulCRC >>= 1;
}
return ulCRC;
}
unsigned long CalculateBlockCRC32(
unsigned long ulCount,
unsigned char *ucBuffer)
{
unsigned long ulTemp1;
unsigned long ulTemp2; unsigned long ulCRC = 0;
while (ulCount-- != 0)
{
ulTemp1 = (ulCRC >> 8) & 0x00FFFFFFL;
ulTemp2 = CRC32Value(((int)ulCRC^*ucBuffer++)&0xff);
ulCRC = ulTemp1^ulTemp2;
}
return(ulCRC);
}
These are well defined, they are taken from a user manual. My C# versions of these functions are:
private ulong CRC32POLYNOMIAL = 0xEDB88320L;
private ulong CRC32Value(int i)
{
int j;
ulong ulCRC = (ulong)i;
for (j = 8; j > 0; j--)
{
if (ulCRC % 2 == 1)
{
ulCRC = (ulCRC >> 1) ^ CRC32POLYNOMIAL;
}
else
{
ulCRC >>= 1;
}
}
return ulCRC;
}
private ulong CalculateBlockCRC32(ulong ulCount, byte[] ucBuffer)
{
ulong ulTemp1;
ulong ulTemp2;
ulong ulCRC=0;
int bufind=0;
while (ulCount-- != 0)
{
ulTemp1 = (ulCRC >> 8) & 0x00FFFFFFL;
ulTemp2 = CRC32Value(((int)ulCRC ^ ucBuffer[bufind]) & 0xFF);
ulCRC = ulTemp1 ^ ulTemp2;
bufind++;
}
return ulCRC;
}
As I mentioned, there are discrepancies between the C version and the C# version. One possible source is my understanding of the C expression ulCRC & 1 which I believe will only be true for odd numbers.
I call the C# function like this:
string contents = "some data";
byte[] toBeHexed = Encoding.ASCII.GetBytes(contents);
ulong calculatedCRC = this.CalculateBlockCRC32((ulong)toBeHexed.Length, toBeHexed);
And the C function is called like this:
char *Buff="some data";
unsigned long iLen = strlen(Buff);
unsigned long CRC = CalculateBlockCRC32(iLen, (unsigned char*) Buff);
I believe that I am calling the functions with the same data in each language, is that correct? If anyone could shed some light on this I would be very grateful.
As it has been already pointed by #Adriano Repetti you should use UInt32 datatype in place of the ulong type(it is 64 bit unsigned UInt64, whereas in VC++ unsigned long is only 32 bit unsigned type)
private UInt32 CRC32POLYNOMIAL = 0xEDB88320;
private UInt32 CRC32Value(int i)
{
int j;
UInt32 ulCRC = (UInt32)i;
for (j = 8; j > 0; j--)
{
if (ulCRC % 2 == 1)
{
ulCRC = (ulCRC >> 1) ^ CRC32POLYNOMIAL;
}
else
{
ulCRC >>= 1;
}
}
return ulCRC;
}
private UInt32 CalculateBlockCRC32(UInt32 ulCount, byte[] ucBuffer)
{
UInt32 ulTemp1;
UInt32 ulTemp2;
UInt32 ulCRC = 0;
int bufind = 0;
while (ulCount-- != 0)
{
ulTemp1 = (ulCRC >> 8) & 0x00FFFFFF;
ulTemp2 = CRC32Value(((int)ulCRC ^ ucBuffer[bufind]) & 0xFF);
ulCRC = ulTemp1 ^ ulTemp2;
bufind++;
}
return ulCRC;
}
string contents = "12";
byte[] toBeHexed = Encoding.ASCII.GetBytes(contents);
UInt32 calculatedCRC = CalculateBlockCRC32((UInt32)toBeHexed.Length, toBeHexed);
Usually in C# it doesn't matter whether you use C# data type name(recommended by Microsoft) or ECMA type name. But in this and similar cases with bit level manipulation it can greatly clarify the intent and prevent mistakes.
In C it is always a good idea to use typedefs from stdint.h. They make the same job, as ECMA types in C# - clarify the intent, and also guarantee the length and sign of used datatypes(C compilers may use different lengths for the same types, because standard doesn't specify exact sizes):
#include <stdint.h>
#define CRC32_POLYNOMIAL ((uint32_t)0xEDB88320)
uint32_t CRC32Value(uint32_t i)
{
uint32_t j;
uint32_t ulCRC;
ulCRC = i;
for (j = 8; j > 0; j--)
{
if (ulCRC & 1)
ulCRC = (ulCRC >> 1) ^ CRC32_POLYNOMIAL;
else
ulCRC >>= 1;
}
return ulCRC;
}
uint32_t CalculateBlockCRC32(
size_t ulCount,
uint8_t *ucBuffer)
{
uint32_t ulTemp1;
uint32_t ulTemp2;
uint32_t ulCRC = 0;
while (ulCount-- != 0)
{
ulTemp1 = (ulCRC >> 8) & ((uint32_t)0x00FFFFFF);
ulTemp2 = CRC32Value((ulCRC^*ucBuffer++)&0xff);
ulCRC = ulTemp1^ulTemp2;
}
return(ulCRC);
}
char *Buff = "12";
size_t iLen = strlen(Buff);
uint32_t CRC = CalculateBlockCRC32(iLen, (uint8_t *) Buff);
printf("%u", CRC);

Categories

Resources