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
Related
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
I'm getting the following errors when I try to rebuild a .dll
Please advise what can I replace these lines with so that the code will compile.
Background info (likely not relevant):
The .dll is part of an add-in output module for a program that controls Christmas lights. It outputs data from the program to the selected serial port telling the connected relay board which relays are to be on or off.
I intend to modify the output to suit my device so instead of the output being FF FF FF 00 00 00 00 00 for relay 1 2 3 on and 4 5 6 7 8 off it will send the appropriate format for the board That I have. (see below)
http://www.tinyosshop.com/image/data/board_modules/usbrelay4-5.jpg
Error CS0571 'SerialSetupDialog.SelectedPort.get': cannot explicitly call operator or accessor
It references the line in this section:
private void buttonSerialSetup_Click(object sender, EventArgs e)
{
SerialSetupDialog serialSetupDialog = new SerialSetupDialog(this.m_selectedPort);
if (((Form) serialSetupDialog).ShowDialog() != DialogResult.OK)
return;
this.m_selectedPort = serialSetupDialog.get_SelectedPort();
}
Also there are 3 cases of:
Error CS0221 Constant value '-128' cannot be converted to a 'byte' (use 'unchecked' syntax to override)
The compiler doesn't like this part of the code. "(byte) sbyte.MinValue;"
private void Protocol1Event(byte[] channelValues)
{
int length1 = channelValues.Length;
int count = 2;
int length2 = 2 + 2 * length1 + (2 + 2 * length1) / 100;
if (this.m_p1Packet.Length < length2)
this.m_p1Packet = new byte[length2];
this.m_p1Packet[0] = (byte) 126;
this.m_p1Packet[1] = (byte) sbyte.MinValue;
this.m_threadPosition = 10;
for (int index = 0; index < length1; ++index)
{
if ((int) channelValues[index] == 125)
{
this.m_threadPosition = 11;
this.m_p1Packet[count++] = (byte) 124;
}
else if ((int) channelValues[index] == 126)
{
this.m_threadPosition = 12;
this.m_p1Packet[count++] = (byte) 124;
}
else if ((int) channelValues[index] == (int) sbyte.MaxValue)
{
this.m_threadPosition = 13;
this.m_p1Packet[count++] = (byte) sbyte.MinValue;
}
else
{
this.m_threadPosition = 14;
this.m_p1Packet[count++] = channelValues[index];
}
if (count % 100 == 0)
{
this.m_threadPosition = 15;
this.m_p1Packet[count++] = (byte) 125;
}
this.m_threadPosition = 16;
}
this.m_threadPosition = 17;
if (this.m_running)
{
while (this.m_selectedPort.WriteBufferSize - this.m_selectedPort.BytesToWrite <= count)
Thread.Sleep(10);
this.m_threadPosition = 18;
this.m_selectedPort.Write(this.m_p1Packet, 0, count);
this.m_threadPosition = 19;
}
this.m_threadPosition = 20;
}
private void Protocol2Event(byte[] channelValues)
{
byte num1 = (byte) sbyte.MinValue;
int length = channelValues.Length;
byte[] array = new byte[8];
int num2 = 0;
while (num2 < length)
{
int num3 = Math.Min(num2 + 7, length - 1);
this.m_p2Packet[1] = num1++;
if (num3 >= length - 1)
this.m_p2Zeroes.CopyTo((Array) this.m_p2Packet, 3);
Array.Clear((Array) array, 0, 8);
for (int index = num2; index <= num3; ++index)
{
byte num4 = channelValues[index];
byte num5 = num4;
if ((int) num4 >= 1 && (int) num4 <= 8)
array[(int) num4 - 1] = (byte) 1;
else if ((int) num5 >= 1 && (int) num5 <= 8)
array[(int) num5 - 1] = (byte) 1;
}
byte num6 = (byte) (1 + Array.IndexOf<byte>(array, (byte) 0));
this.m_p2Packet[2] = num6;
int index1 = num2;
int count = 3;
while (index1 <= num3)
{
this.m_p2Packet[count] = (byte) ((uint) channelValues[index1] - (uint) num6);
++index1;
++count;
}
if (this.m_running)
this.m_selectedPort.Write(this.m_p2Packet, 0, count);
num2 += 8;
}
}
The reason that (byte)sbyte.MinValue; throws an error is because sbytes minimal value is -128 whereas bytes minimal value is 0. Therefore converting that to the other will cause an overflow. If you really want this behaviour you can use the keyword unchecked as the following:
byte b = unchecked((byte)sbyte.MinValue);
However this will give b the value of 128.
To answer the other part of your question I believe that replacing:
serialSetupDialog.get_SelectedPort();
with:
serialSetupDialog.SelectedPort;
should fix the issue.
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;
}
I am trying to adapt this code that can perform conversions to and from Base 52, which I am using to store RGB color information from C# to C++:
public static string ColourToBase52(Color colour)
{
int value = colour.ToArgb() & 0x00FFFFFF; // Mask off the alpha channel.
return ToBase52(value);
}
public static Color ColourFromBase52(string colour)
{
int value = FromBase52(colour);
return Color.FromArgb(unchecked((int)(0xFF000000 | value)));
}
public static string ToBase52(int value)
{
char[] baseChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
int targetBase = baseChars.Length;
int i = 32;
char[] buffer = new char[i];
do
{
buffer[--i] = baseChars[value % targetBase];
value = value / targetBase;
}
while (value > 0);
char[] result = new char[32 - i];
Array.Copy(buffer, i, result, 0, 32 - i);
return new string(result).PadLeft(5, 'a');
}
public static int FromBase52(string value)
{
char[] baseChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
int targetbase = baseChars.Length;
int multiplier = 1;
int result = 0;
for (int i = value.Length-1; i >= 0; --i)
{
int digit = Array.IndexOf(baseChars, value[i]);
result += digit*multiplier;
multiplier *= targetbase;
}
return result;
}
For my C++ code, I have opted to combine the functions that get and return the color value as an integer with the Base 52 conversion functions:
struct DIFColor *DIFBase52ToColor(std::string c)
{
const char *baseChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
int targetBase = 52;
int multiplier = 1;
int result = 0;
const char *d = c.c_str();
for (int i = c.length() - 1; i >= 0; --i)
{
int digit = DIFGetPositionInArray(baseChars, sizeof(baseChars), c[i]);
result += digit * multiplier;
multiplier = multiplier * targetBase;
}
uint8_t b = result & 255;
uint8_t g = (result >> 8) & 255;
uint8_t r = (result >> 16) * 255;
return CreateDIFColor(r,g,b);
}
std::string DIFColorToBase52(struct DIFColor *c)
{
int rgb = ((c->r&0x0ff)<<16)|((c->g&0x0ff)<<8)|(c->b&0x0ff);
const char *baseChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
int targetBase = 52;
int i = 32;
char *buffer = new char[i];
do
{
buffer[--i] = baseChars[rgb % targetBase];
rgb = rgb / targetBase;
}
while (rgb > 0);
char *result = new char[32 - i];
DIFCopyCharArray((const char *)buffer, i, 0, 32 - i, result);
std::string s((const char*)result);
s.insert(s.begin(), 5 - s.size(), 'a');
return s;
}
I also had to create two functions for array manipulation:
int DIFGetPositionInArray(const char *array, size_t size, const char c)
{
for (size_t i = 0; i < size; i++)
{
if (array[i] == c)
return (int)i;
}
return -1;
}
void DIFCopyCharArray(const char* source, int wheretostart, int wheretocopy, int numtocopy, char *dest)
{
int c = wheretocopy;
for(int i = wheretostart; i <= numtocopy; i++)
{
dest[c] = source[i];
c++;
}
}
However, when I tried to test it with a sanity check, it failed:
255,255,255 = 'aah1U' in Base52 RGB
aah1U = 1,245,59 in RGB
It also seems that every time I run the sanity check, a different value is produced:
255,255,255 = 'aah13' in Base52 RGB
aah13 = 1,245,59 in RGB
255,255,255 = 'aah1j' in Base52 RGB
aah1j = 1,245,59 in RGB
The expected output was:
255,255,255 = 'cpqEN' in Base52 RGB
cpqEN = 255,255,255 in RGB
Making me think that this is possibly a pointer problem.
The error is probably that you don't terminate the result string anywhere, which leads to undefined behavior in the following:
std::string s((const char*)result);
This is because the std::string constructor looks for the terminator when copying the C-style string you pass to it.
You can solve it two ways: Either add the terminator character '\0' to result, or tell the std::string constructor the length of result.
The problem lies in the fact that the array copy function is incorrect. It should be:
void DIFCopyCharArray(const char* source, int wheretostart, int wheretocopy, int numtocopy, char *dest)
{
int c = wheretocopy;
for(int i = wheretostart; c <= numtocopy; i++)
{
dest[c] = source[i];
c++;
}
dest[c] = '\0';
}
Also, the array search function does not work because sizeof(baseChars) returns 4, which is not the number of elements.
Use a function like this:
int DIFGetPositionInArray(const char *array, int arrayElements, const char c)
{
for (int i = 0; i < arrayElements; i++)
{
if (array[i] == c)
return i;
}
return -1;
}
And call it like this;
DIFGetPositionInArray(baseChars,52,d[i]);
Based Online CRC calculation, when I entered hex string data =
503002080000024400003886030400000000010100
I get result CRC-CCITT (0xFFFF) =
0x354E (Expected Result)
.
I use the code below, but the results of CalcCRC16() are 0xACEE. What the lack of script below?
using System;
using System.Windows.Forms;
using System.Runtime.Remoting.Metadata.W3cXsd2001;
using System.Diagnostics;
namespace WindowsFormsApplication1 {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
string result = CalcCRC16("503002080000024400003886030400000000010100");
Debug.Print(result);
// result = ACEE
// result expected = 354E
}
// CRC-CCITT (0xFFFF) with poly 0x1021
// input (hex string) = "503002080000024400003886030400000000010100"
// result expected (hex string) = "354E"
public string CalcCRC16(string strInput) {
ushort temp = 0;
ushort crc = 0xFFFF;
byte[] bytes = GetBytesFromHexString(strInput);
for (int j = 0; j < bytes.Length; j++) {
crc = (ushort)(crc ^ bytes[j]);
for (int i = 0; i < 8; i++) {
if ((crc & 0x0001) == 1)
crc = (ushort)((crc >> 1) ^ 0x1021);
else
crc >>= 1;
}
}
crc = (ushort)~(uint)crc;
temp = crc;
crc = (ushort)((crc << 8) | (temp >> 8 & 0xFF));
return crc.ToString("X4");
}
public Byte[] GetBytesFromHexString(string strInput) {
Byte[] bytArOutput = new Byte[] { };
if (!string.IsNullOrEmpty(strInput) && strInput.Length % 2 == 0) {
SoapHexBinary hexBinary = null;
try {
hexBinary = SoapHexBinary.Parse(strInput);
if (hexBinary != null)
bytArOutput = hexBinary.Value;
}
catch (Exception ex) {
MessageBox.Show(ex.Message);
}
}
return bytArOutput;
}
}
}
I found the answer and I will share here.. may be useful to others.
strInput = 503002080000024400003886030400000000010100
initial = 0xFFFF
poly = 0x1021
strOutput = 354E
reference = Online CRC Calc
public string CalcCRC16(string strInput) {
ushort crc = 0xFFFF;
byte[] data = GetBytesFromHexString(strInput);
for (int i = 0; i < data.Length; i++) {
crc ^= (ushort)(data[i] << 8);
for (int j = 0; j < 8; j++) {
if ((crc & 0x8000) > 0)
crc = (ushort)((crc << 1) ^ 0x1021);
else
crc <<= 1;
}
}
return crc.ToString("X4");
}
public Byte[] GetBytesFromHexString(string strInput) {
Byte[] bytArOutput = new Byte[] { };
if (!string.IsNullOrEmpty(strInput) && strInput.Length % 2 == 0) {
SoapHexBinary hexBinary = null;
try {
hexBinary = SoapHexBinary.Parse(strInput);
if (hexBinary != null) {
bytArOutput = hexBinary.Value;
}
}
catch (Exception ex) {
MessageBox.Show(ex.Message);
}
}
return bytArOutput;
}
Here's an example which works in my application.
I struggled somewhat, now I know its because I had to use char ptrs in stead of 16bit int pointers (because CCIT is LSB order first, so we pick 1 byte from the buffer, shift it 8 times to make it 16bit to validate the upper MSB bit 0x8000).
Most causes found when people struggle with 16bit CRC (while 8bit most of the time works):
Buffer should be called by 8bit ptr
Shifting BEFORE the XOR!
Never use int or unsigned int.. but use short! My application runs on 16 and 32bit Microchip PIC's and using ints results in 16bit values on the 16bit pic and 32bit values (so lot of zeros!) on 32bit platforms.
BOOL = unsigned char.
UINT16 = unsigned short.
The function runs in code, so not a while/forloop.
When done, the CRC is copied to the address pointed by *crc.
This way all ather tasks (M95 modem, MCP's I2C, Flash logs, TCP/IP etc. will be handled without too large delays).
BOOL CRC_16(UINT16 ui16_Bytes, char *src, UINT16 *crc)
{
static BOOL bNew = FALSE;
static UINT16 remainder = 0;
static UINT16 i = 0;
static UINT16 ui16_Loc_bytes;
static char *ptr;
static char locData;
if(!bNew)
{
ui16_Loc_bytes = ui16_Bytes;
ptr = src;
locData = *ptr;
i = 8;
remainder = 0x0000;
bNew = TRUE;
}
if(ui16_Loc_bytes)
{
if(i == 8)
{
remainder ^= (((UINT16)locData)<<8); //Only 8bits at a time filled with zeros
}
if(i)
{
if (remainder & 0x8000)
{
remainder = (remainder << 1);
remainder ^= POLYNOMIAL_16;
}
else
{
remainder = (remainder << 1);
}
i--;
}
else
{
ui16_Loc_bytes--;
ptr++;
locData = *ptr;
//ptr++;
i = 8;
}
}
else
{
bNew = FALSE;
*crc = remainder;
return TRUE;
}
return FALSE;
}
if(SDKaart.ui16_RecBytes >= SDKaart.ui16_ByteLen)//30-5-2018 edited SDKaart.CMD[SDKaart.ui8_ActiefCMD].ui16_RecLen)
{
SD_DESELECT;
if(SDKaart.bInitReady && SDKaart.b_BlockRead)
{
if(CRC_16(512,(char*)&SDKaart.Mem_Block.SD_Buffer[0], &SDKaart.ui16_MemBlock_CRC))
{
if((((UINT16)SDKaart.Mem_Block.SD_Buffer[512]<<8)|(UINT16)SDKaart.Mem_Block.SD_Buffer[513]) == SDKaart.ui16_MemBlock_CRC)
{
SDKaart.bRXReady = TRUE;
SDKaart.TXStat = SPI_IDLE;
printf("CRC16 OK %x\r\n",SDKaart.ui16_MemBlock_CRC);
}
else
{
SDKaart.bRXReady = TRUE;
SDKaart.TXStat = SPI_IDLE;
printf("CRC16 %u != 0x%x 0x%x\r\n",SDKaart.ui16_MemBlock_CRC,SDKaart.Mem_Block.SD_Buffer[512], SDKaart.Mem_Block.SD_Buffer[513] );
}
//printf("CRC citt: %u\r\n", Calculate_CRC_CCITT((char *)&SDKaart.Mem_Block.SD_Buffer[0],512));
}
}
else
{
SDKaart.bRXReady = TRUE;
SDKaart.TXStat = SPI_IDLE;
}
}
else
{
if(SD_SPI_TX_READY)
{
SDKaart.bNewSPIByte = TRUE;
SPI1BUF = SD_EMPTY_BYTE;
}
}
I have used many crcs found online, but a lottt didn't work.
Be aware a lot of online "examples" do use <<1 behind the XOR, but it must be done before xor.
POLY_16 is 0x1021.
Next oppurtunity is to build a table picker. :)
Greetz, John