ESP32 reading DHT22 sensor in ULP coprocessor - sensors

I´m trying to read a dht22 sensor in ulp deep sleep, and it´s not working, can perhaps someone tell me what I´m doing wrong?
I´m reimplementing the arduino-DHT library because it´s working in non ulp mode with my sensor, it looks like this:
digitalWrite(pin, LOW); // Send start signal
pinMode(pin, OUTPUT);
delayMicroseconds(800);
pinMode(pin, INPUT);
digitalWrite(pin, HIGH); // Switch bus to receive data
// We're going to read 83 edges:
// - First a FALLING, RISING, and FALLING edge for the start bit
// - Then 40 bits: RISING and then a FALLING edge per bit
// To keep our code simple, we accept any HIGH or LOW reading if it's max 85 usecs long
uint16_t rawHumidity = 0;
uint16_t rawTemperature = 0;
uint16_t data = 0;
for ( int8_t i = -3 ; i < 2 * 40; i++ ) {
byte age;
startTime = micros();
do {
age = (unsigned long)(micros() - startTime);
if ( age > 90 ) {
error = ERROR_TIMEOUT;
return;
}
}
while ( digitalRead(pin) == (i & 1) ? HIGH : LOW );
if ( i >= 0 && (i & 1) ) {
// Now we are being fed our 40 bits
data <<= 1;
// A zero max 30 usecs, a one at least 68 usecs.
if ( age > 30 ) {
data |= 1; // we got a one
}
}
switch ( i ) {
case 31:
rawHumidity = data;
break;
case 63:
rawTemperature = data;
data = 0;
break;
}
}
Looks simple enough :D, I tried the first part with this code, but it doesn´t work:
rtc_gpio_init(15);
rtc_gpio_set_direction(15, RTC_GPIO_MODE_INPUT_OUTPUT);
And in my ulp script file:
.set temp_humidity_sensor_pin, 13 // gpio 15 (adc 13)
send_start_signal:
/* disable hold on gpio 15 (data pin) */
WRITE_RTC_REG(RTC_IO_TOUCH_PAD3_REG, RTC_IO_TOUCH_PAD3_HOLD_S, 1, 0)
/* switch to output mode */
WRITE_RTC_REG(RTC_GPIO_OUT_W1TS_REG, RTC_GPIO_OUT_DATA_W1TS_S + temp_humidity_sensor_pin, 1, 1)
/* send start signal (LOW) */
WRITE_RTC_REG(RTC_GPIO_OUT_REG, RTC_GPIO_OUT_DATA_S + temp_humidity_sensor_pin, 1, 0)
/* pull low for 800 microseconds (8Mhz) */
wait 6400
/* switch to input mode */
WRITE_RTC_REG(RTC_GPIO_OUT_W1TC_REG, RTC_GPIO_OUT_DATA_W1TC_S + temp_humidity_sensor_pin, 1, 1)
/* switch bus to receive data (HIGH) */
WRITE_RTC_REG(RTC_GPIO_OUT_REG, RTC_GPIO_OUT_DATA_S + temp_humidity_sensor_pin, 1, 1)
wait_for_sensor_preparation_low:
READ_RTC_REG(RTC_GPIO_IN_REG, RTC_GPIO_IN_NEXT_S + temp_humidity_sensor_pin, 1)
and r0, r0, 1
jump wait_for_sensor_preparation_low, eq
wait_for_sensor_preparation_high:
READ_RTC_REG(RTC_GPIO_IN_REG, RTC_GPIO_IN_NEXT_S + temp_humidity_sensor_pin, 1)
and r0, r0, 0
jump wait_for_sensor_preparation_high, eq
jump wake_up // <-- never called :(
Any ideas?

Your "and r0, r0, 0" instruction (near the end) always sets r0 to zero (x & 0 == 0 by definition), which means the following jump instruction will loop forever. Remember that the "eq" flag doesn't really mean "equal". It means "zero". I think you want:
wait_for_sensor_preparation_low:
READ_RTC_REG(RTC_GPIO_IN_REG, RTC_GPIO_IN_NEXT_S + temp_humidity_sensor_pin, 1)
and r0, r0, 1
jump wait_for_sensor_preparation_high, eq
jump wait_for_sensor_preparation_low
wait_for_sensor_preparation_high:
READ_RTC_REG(RTC_GPIO_IN_REG, RTC_GPIO_IN_NEXT_S + temp_humidity_sensor_pin, 1)
and r0, r0, 1
jump wait_for_sensor_preparation_high, eq
By the way, I wrote a C compiler for the ULP, which should make your life easier. It's on https://github.com/jasonful/lcc

Related

How to Change the colour of LED's with fastLED and a ESP32

so I developed an app which will send a series of integers over Bluetooth (for RED, GREEN & BLUE) to a ESP32 which will then change the colour of 3 LED's (WS2811) based on the numbers it receives. It works the first time I send them but when I try to change the colour of the LED's a second time nothing happens.
By using the serial monitor of the Arduino IDE I have verified that the numbers are being received by the ESP32 every time I send the numbers, but I cannot understand why the LEDs are not changing colour after the first send.
The code is as follows :
#include <Arduino.h>
#include <fastled_config.h>
#define NUM_LEDS 3 // was 100
#define LED_TYPE WS2811
#define COLOR_ORDER RGB
#define DATA_PIN 4
//#define CLK_PIN 4
#define VOLTS 12
#define MAX_MA 4000
CRGBArray<NUM_LEDS> leds;
#define LED 2
int myRGB[30];
int counter =0;
int display =-1;
#include "BluetoothSerial.h"
// init Class:
BluetoothSerial ESP_BT;
// Parameters for Bluetooth interface
int incoming;
void setup() {
Serial.begin(115200);
ESP_BT.begin("ESP32_Control"); //Name of your Bluetooth interface -> will show up on your phone
delay( 3000 ); //safety startup delay
FastLED.setMaxPowerInVoltsAndMilliamps( VOLTS, MAX_MA);
FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, NUM_LEDS)
.setCorrection(TypicalLEDStrip);
}
void loop() {
delay(1000);
Serial.println(myRGB[1]);
Serial.println(myRGB[2]);
Serial.println(myRGB[3]);
leds[0].r = myRGB[1];
leds[0].g = myRGB[2];
leds[0].b = myRGB[3];
leds[1].r = myRGB[4];
leds[1].g = myRGB[5];
leds[1].b = myRGB[6];
leds[2].r = myRGB[7];
leds[2].g = myRGB[8];
leds[2].b = myRGB[9];
FastLED.show();
// -------------------- Receive Bluetooth signal ----------------------
if (ESP_BT.available())
{
incoming = ESP_BT.read(); //Read what we receive
digitalWrite(LED, HIGH);
counter ++;
myRGB[counter] = incoming;
if (counter > 29) counter = 0;
Serial.print("counter :" );
Serial.println(counter);
Serial.print( myRGB[counter]);
}
} // end loop
It looks like the LED colors are being shown before before Bluetooth inputs are received.
I would move FastLED.show() to the end of loop().
FastLED.show();
} // end loop
sorry for the late reply.
Ok the following code works, it not really much different to the original code
apart from this :
enter code hereif (counter < 9)
myRGB[counter] = incoming;
enter code here }
Which I'm guessing did make a difference (although it shouldn't have)
enter code here
#include <Arduino.h>
#include <fastled_config.h>
#define NUM_LEDS 3 // was 100
#define LED_TYPE WS2811
#define COLOR_ORDER RGB
#define DATA_PIN 4
//#define CLK_PIN 4
#define VOLTS 12
#define MAX_MA 4000
CRGBArray<NUM_LEDS> leds;
#define LED 2
int myRGB[30];
int counter =0;
int displayCounter =-1;
#include "BluetoothSerial.h"
// init Class:
BluetoothSerial ESP_BT;
// Parameters for Bluetooth interface
int incoming;
void setup() {
Serial.println("ESP started !!");
Serial.begin(115200);
ESP_BT.begin("ESP32_Control"); //Name of your Bluetooth interface -> will show up on your phone
delay( 3000 ); //safety startup delay
FastLED.setMaxPowerInVoltsAndMilliamps( VOLTS, MAX_MA);
FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, NUM_LEDS)
.setCorrection(TypicalLEDStrip);
}
void loop() {
delay(20); // WITHOUT THIS LINE MORE LIKELY TO GET INCORRECT DATA FROM BLUETOOTH
displayCounter ++;
if (displayCounter < 4){
Serial.println("***** the following values going into led[0] ( R G B ) *** ");
Serial.println(myRGB[1]);
Serial.println(myRGB[2]);
Serial.println(myRGB[3]);
Serial.println("***** the following values going into led[1] ( R G B ) *** ");
Serial.println(myRGB[4]);
Serial.println(myRGB[5]);
Serial.println(myRGB[6]);
Serial.println("***** the following values going into led[2] ( R G B ) *** ");
Serial.println(myRGB[7]);
Serial.println(myRGB[8]);
Serial.println(myRGB[9]);
}
leds[0].r = myRGB[1];
leds[0].g = myRGB[2];
leds[0].b = myRGB[3];
leds[1].r = myRGB[4];
leds[1].g = myRGB[5];
leds[1].b = myRGB[6];
leds[2].r = myRGB[7];
leds[2].g = myRGB[8];
leds[2].b = myRGB[9];
FastLED.show();
// -------------------- Receive Bluetooth signal ----------------------
if (ESP_BT.available())
{
displayCounter = -1;
incoming = ESP_BT.read(); //Read what we receive
//digitalWrite(LED, HIGH);
counter ++;
if (counter < 9)
myRGB[counter] = incoming;
}
else {counter = 0;
// Serial.println("End of bluetooth data");
}
} // end loop

Generate Checksum for String

I would like to Generate Checksum for Strings/Data
1. The same data should produce the same Checksum
2. Two different data strings can't product same checksum. Random collision of 0.1% can be negligible
3. No encryption/decryption of data
4. Checksum length need not be too huge and contains letters and characters.
5. Must be too fast and efficient. Imagine generating checksum(s) for 100 Mb of text data should be in less than 5mins. Generating 1000 checksums for less than 1 KB of each segment data should be in less than 10 seconds.
Any algorithm or implementation reference and suggestions are most appreciated.
You can write a custom hash function: (c++)
long long int hash(String s){
long long k = 7;
for(int i = 0; i < s.length(); i++){
k *= 23;
k += s[i];
k *= 13;
k %= 1000000009;
}
return k;
}
This should give you a well (collision free for most samples) hash value.
A very common, fast checksum is the CRC-32, a 32-bit polynomial cyclic redundancy check. Here are three implementations in C, which vary in speed vs. complexity, of the CRC-32: (This is from http://www.hackersdelight.org/hdcodetxt/crc.c.txt)
#include <stdio.h>
#include <stdlib.h>
// ---------------------------- reverse --------------------------------
// Reverses (reflects) bits in a 32-bit word.
unsigned reverse(unsigned x) {
x = ((x & 0x55555555) << 1) | ((x >> 1) & 0x55555555);
x = ((x & 0x33333333) << 2) | ((x >> 2) & 0x33333333);
x = ((x & 0x0F0F0F0F) << 4) | ((x >> 4) & 0x0F0F0F0F);
x = (x << 24) | ((x & 0xFF00) << 8) |
((x >> 8) & 0xFF00) | (x >> 24);
return x;
}
// ----------------------------- crc32a --------------------------------
/* This is the basic CRC algorithm with no optimizations. It follows the
logic circuit as closely as possible. */
unsigned int crc32a(unsigned char *message) {
int i, j;
unsigned int byte, crc;
i = 0;
crc = 0xFFFFFFFF;
while (message[i] != 0) {
byte = message[i]; // Get next byte.
byte = reverse(byte); // 32-bit reversal.
for (j = 0; j <= 7; j++) { // Do eight times.
if ((int)(crc ^ byte) < 0)
crc = (crc << 1) ^ 0x04C11DB7;
else crc = crc << 1;
byte = byte << 1; // Ready next msg bit.
}
i = i + 1;
}
return reverse(~crc);
}
// ----------------------------- crc32b --------------------------------
/* This is the basic CRC-32 calculation with some optimization but no
table lookup. The the byte reversal is avoided by shifting the crc reg
right instead of left and by using a reversed 32-bit word to represent
the polynomial.
When compiled to Cyclops with GCC, this function executes in 8 + 72n
instructions, where n is the number of bytes in the input message. It
should be doable in 4 + 61n instructions.
If the inner loop is strung out (approx. 5*8 = 40 instructions),
it would take about 6 + 46n instructions. */
unsigned int crc32b(unsigned char *message) {
int i, j;
unsigned int byte, crc, mask;
i = 0;
crc = 0xFFFFFFFF;
while (message[i] != 0) {
byte = message[i]; // Get next byte.
crc = crc ^ byte;
for (j = 7; j >= 0; j--) { // Do eight times.
mask = -(crc & 1);
crc = (crc >> 1) ^ (0xEDB88320 & mask);
}
i = i + 1;
}
return ~crc;
}
// ----------------------------- crc32c --------------------------------
/* This is derived from crc32b but does table lookup. First the table
itself is calculated, if it has not yet been set up.
Not counting the table setup (which would probably be a separate
function), when compiled to Cyclops with GCC, this function executes in
7 + 13n instructions, where n is the number of bytes in the input
message. It should be doable in 4 + 9n instructions. In any case, two
of the 13 or 9 instrucions are load byte.
This is Figure 14-7 in the text. */
unsigned int crc32c(unsigned char *message) {
int i, j;
unsigned int byte, crc, mask;
static unsigned int table[256];
/* Set up the table, if necessary. */
if (table[1] == 0) {
for (byte = 0; byte <= 255; byte++) {
crc = byte;
for (j = 7; j >= 0; j--) { // Do eight times.
mask = -(crc & 1);
crc = (crc >> 1) ^ (0xEDB88320 & mask);
}
table[byte] = crc;
}
}
/* Through with table setup, now calculate the CRC. */
i = 0;
crc = 0xFFFFFFFF;
while ((byte = message[i]) != 0) {
crc = (crc >> 8) ^ table[(crc ^ byte) & 0xFF];
i = i + 1;
}
return ~crc;
}
If you simply google "CRC32", you will get more info than you could possibly absorb.

ArrayFire frame search algorithm crash

I am new to ArrayFire and CUDA development in general, I just started using ArrayFire a couple of days ago after failing miserably using Thrust.
I am building an ArrayFire-based algorithm that is supposed to search a single 32x32 pixel frame in a database of a couple hundred thousand 32x32 frames that are stored into device memory.
At first I initialize a matrix that has 1024 + 1 pixels as rows (I need an extra one to keep a frame group id) and a predefined number (this case 1000) of frames, indexed by coloumn.
Here's the function that performs the search, if I uncomment "pixels_uint32 = device_frame_ptr[pixel_group_idx];" the program crashes. The pointer seems to be valid so I do not understand why this happens. Maybe there is something I do not know regarding accessing device memory in this way?
#include <iostream>
#include <stdio.h>
#include <sys/types.h>
#include <arrayfire.h>
#include "utils.h"
using namespace af;
using namespace std;
/////////////////////////// CUDA settings ////////////////////////////////
#define TEST_DEBUG false
#define MAX_NUMBER_OF_FRAMES 1000 // maximum (2499999 frames) X (1024 + 1 pixels per frame) x (2 bytes per pixel) = 5.124.997.950 bytes (~ 5GB)
#define BLOB_FINGERPRINT_SIZE 1024 //32x32
//percentage of macroblocks that should match: 0.9 means 90%
#define MACROBLOCK_COMPARISON_OVERALL_THRESHOLD 768 //1024 * 0.75
//////////////////////// End of CUDA settings ////////////////////////////
array search_frame(array d_db_vec)
{
try {
uint number_of_uint32_for_frame = BLOB_FINGERPRINT_SIZE / 2;
// create one-element array to hold the result of the computation
array frame_found(1,MAX_NUMBER_OF_FRAMES, u32);
frame_found = 0;
gfor (array frame_idx, MAX_NUMBER_OF_FRAMES) {
// get the blob id it's the last coloumn of the matrix
array blob_id = d_db_vec(number_of_uint32_for_frame, frame_idx); // addressing with (pixel_idx, frame_idx)
// define some hardcoded pixel to search for
uint8_t searched_r = 0x0;
uint8_t searched_g = 0x3F;
uint8_t searched_b = 0x0;
uint8_t b1 = 0;
uint8_t g1 = 0;
uint8_t r1 = 0;
uint8_t b2 = 0;
uint8_t g2 = 0;
uint8_t r2 = 0;
uint32_t sum1 = 0;
uint32_t sum2 = 0;
uint32_t *device_frame_ptr = NULL;
uint32_t pixels_uint32 = 0;
uint pixel_match_counter = 0;
//uint pixel_match_counter = 0;
array frame = d_db_vec(span, frame_idx);
device_frame_ptr = frame.device<uint32_t>();
for (uint pixel_group_idx = 0; pixel_group_idx < number_of_uint32_for_frame; pixel_group_idx++) {
// test to see if the whole matrix is traversed
// d_db_vec(pixel_group_idx, frame_idx) = 0;
/////////////////////////////// PROBLEMATIC CODE ///////////////////////////////////
pixels_uint32 = 0x7E007E0;
//pixels_uint32 = device_frame_ptr[pixel_group_idx]; //why does this crash the program?
// if I uncomment the above line the program tries to copy the u32 frame into the pixels_uint32 variable
// something goes wrong, since the pointer device_frame_ptr is not NULL and the elements should be there judging by the lines above
////////////////////////////////////////////////////////////////////////////////////
// splitting the first pixel into its components
b1 = (pixels_uint32 & 0xF8000000) >> 27; //(input & 11111000000000000000000000000000)
g1 = (pixels_uint32 & 0x07E00000) >> 21; //(input & 00000111111000000000000000000000)
r1 = (pixels_uint32 & 0x001F0000) >> 16; //(input & 00000000000111110000000000000000)
// splitting the second pixel into its components
b2 = (pixels_uint32 & 0xF800) >> 11; //(input & 00000000000000001111100000000000)
g2 = (pixels_uint32 & 0x07E0) >> 5; //(input & 00000000000000000000011111100000)
r2 = (pixels_uint32 & 0x001F); //(input & 00000000000000000000000000011111)
// checking if they are a match
sum1 = abs(searched_r - r1) + abs(searched_g - g1) + abs(searched_b - b1);
sum2 = abs(searched_r - r2) + abs(searched_g - g2) + abs(searched_b - b2);
// if they match, increment the local counter
pixel_match_counter = (sum1 <= 16) ? pixel_match_counter + 1 : pixel_match_counter;
pixel_match_counter = (sum2 <= 16) ? pixel_match_counter + 1 : pixel_match_counter;
}
bool is_found = pixel_match_counter > MACROBLOCK_COMPARISON_OVERALL_THRESHOLD;
// write down if the frame is a match or not
frame_found(0,frame_idx) = is_found ? frame_found(0,frame_idx) : blob_id;
}
// test to see if the whole matrix is traversed - this has to print zeroes
if (TEST_DEBUG)
print(d_db_vec);
// return the matches array
return frame_found;
} catch (af::exception& e) {
fprintf(stderr, "%s\n", e.what());
throw;
}
}
// make 2 green pixels
uint32_t make_test_pixel_group() {
uint32_t b1 = 0x0; //11111000000000000000000000000000
uint32_t g1 = 0x7E00000; //00000111111000000000000000000000
uint32_t r1 = 0x0; //00000000000111110000000000000000
uint32_t b2 = 0x0; //00000000000000001111100000000000
uint32_t g2 = 0x7E0; //00000000000000000000011111100000
uint32_t r2 = 0x0; //00000000000000000000000000011111
uint32_t green_pix = b1 | g1 | r1 | b2 | g2 | r2;
return green_pix;
}
int main(int argc, char ** argv)
{
info();
/////////////////////////////////////// CREATE THE DATABASE ///////////////////////////////////////
uint number_of_uint32_for_frame = BLOB_FINGERPRINT_SIZE / 2;
array d_db_vec(number_of_uint32_for_frame + 1, // fingerprint size + 1 extra u32 for blob id
MAX_NUMBER_OF_FRAMES, // number of frames
u32); // type of elements is 32-bit unsigned integer (unsigned) with the configuration RGBRGB (565565)
if (TEST_DEBUG == true) {
for (uint frame_idx = 0; frame_idx < MAX_NUMBER_OF_FRAMES; frame_idx++) {
for (uint pix_idx = 0; pix_idx < number_of_uint32_for_frame; pix_idx++) {
d_db_vec(pix_idx, frame_idx) = make_test_pixel_group(); // fill everything with green :D
}
}
} else {
d_db_vec = rand(number_of_uint32_for_frame + 1, MAX_NUMBER_OF_FRAMES);
}
cout << "Setting blob ids. \n\n";
for (uint frame_idx = 0; frame_idx < MAX_NUMBER_OF_FRAMES; frame_idx++) {
// set the blob id to 123456
d_db_vec(number_of_uint32_for_frame, frame_idx) = 123456; // blob_id = 123456
}
if (TEST_DEBUG)
print(d_db_vec);
cout << "Done setting blob ids. \n\n";
//////////////////////////////////// CREATE THE SEARCHED FRAME ///////////////////////////////////
// to be done, for now we use the hardcoded values at line 37-39 to simulate the searched pixel:
//37 uint8_t searched_r = 0x0;
//38 uint8_t searched_g = 0x3F;
//39 uint8_t searched_b = 0x0;
///////////////////////////////////////////// SEARCH /////////////////////////////////////////////
clock_t timer = startTimer();
for (int i = 0; i< 1000; i++) {
array frame_found = search_frame(d_db_vec);
if (TEST_DEBUG)
print(frame_found);
}
stopTimer(timer);
return 0;
}
Here is the console output with the line commented:
arrayfire/examples/helloworld$ ./helloworld
ArrayFire v1.9.1 (64-bit Linux, build 9af23ea)
License: Server (27000#server.accelereyes.com)
CUDA toolkit 5.0, driver 304.54
GPU0 Tesla C2075, 5376 MB, Compute 2.0
Memory Usage: 5312 MB free (5376 MB total)
Setting blob ids.
Done setting blob ids.
Time: 0.03 seconds.
Here is the console output with the line uncommented:
arrayfire/examples/helloworld$ ./helloworld
ArrayFire v1.9.1 (64-bit Linux, build 9af23ea)
License: Server (27000#server.accelereyes.com)
CUDA toolkit 5.0, driver 304.54
GPU0 Tesla C2075, 5376 MB, Compute 2.0
Memory Usage: 5312 MB free (5376 MB total)
Setting blob ids.
Done setting blob ids.
Segmentation fault
Thanks in advance for any help on this issue. I really tried everything but without success.
Disclaimer: I am the lead developer of arrayfire. I see that you have posted on AccelerEyes forums as well, but I am posting here to clear up some common issues with your code.
Do not use .device(), .host(), .scalar() inside gfor loop. This will cause divergences inside the GFOR loop, and GFOR was not designed for this.
You can not index into a device pointer. The pointer refers to a location on the GPU. When you do device_frame_ptr[pixel_group_idx];, the system is looking for the equivalent position on the CPU. This is the reason for your segmentation fault.
Use vectorized code. For example, you don't need the inner for loop of the gfor. Instead of doing b1 = (pixels_uint32 & 0xF8000000) >> 27; inside a for loop, You can do array B1 = (frame & 0xF800000000) >> 27;. i.e. instead of getting data back to CPU and using a for loop, you are doing the entire operation inside the GPU.
Don't use if-else or ternary operators inside GFOR. These cause divergences again. For example, pixel_match_counter = sum(sum1 <= 16) + sum(sum2 < 16); and found(0, found_idx) = is_found * found(0, found_idx) + (1 - is_found) * blob_id.
I have answered the particular problem you are facing. If you have any follow up questions, please follow up on our forums and / or our support email. Stackoverflow is good for asking a specific question, but not to debug your entire program.

Parallel optimization of a checksum algorithm?

The below code sample is an implementation of CRC-CCITT that I'm using in one of my projects.
public static unsafe ushort CRC(byte * it, byte * end)
{
unchecked
{
ushort crc = 0xFFFF;
ushort quick = 0;
for (;;)
{
ushort tmp = (ushort)((crc >> 8) ^ (*it));
crc <<= 8;
quick = (ushort)(tmp ^ (tmp >> 4));
crc ^= quick;
quick <<= 5;
crc ^= quick;
quick <<= 7;
crc ^= quick;
if (it == end)
break;
it++;
}
return crc;
}
}
The CRC-CCITT uses the following polynominal formula :
(X^16 + X^12 + X^5 + 1)
Q: The above polynominal is nothing more then a series of add/multiplication operations. The basic laws of mathematics state that add/multiply ops are interchangeable etc. so expressions like :
SUM(from 1 to 10) == SUM(from 1 to 5) + SUM(from 6 to 10) are true.
I need to optimize the above code, it is probably the most frequently called thing in my project, (120 times/sec at least). Having considered the above, would this be doable with a CRC checksum ? I'm considering using Parallel.For(...) to do the trick, does that even make sense? Anyone have any suggestions?
Update :
120 times per connection actually. I'm handling at least 15 simultaneous incoming connections with datarates of 120[Hz] etc. Byte arrays can vary - theoretical max = 65k bytes, but that's rarely the case, most often it's circa 1k bytes.
Could this solve your problem?
(Sorry, I don't know how to circumvent a deleted post!)
// inspired by http://automationwiki.com/index.php?title=CRC-16-CCITT
static ushort[] crc_table = {
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5,
0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b,
0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210,
0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c,
0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401,
0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b,
0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6,
0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738,
0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5,
0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969,
0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96,
0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc,
0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03,
0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd,
0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6,
0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a,
0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb,
0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1,
0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c,
0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2,
0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb,
0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447,
0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8,
0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2,
0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9,
0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827,
0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c,
0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0,
0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d,
0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07,
0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba,
0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74,
0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
};
public static unsafe ushort CRC(byte* it, byte* end)
{
ushort crc = 0;
ushort temp;
do
{
temp = (ushort)((*it ^ (crc >> 8)) & 0xff);
crc = (ushort)(crc_table[temp] ^ (crc << 8));
}
while (it++ != end);
return crc;
}

Convert extended precision float (80-bit) to double (64-bit) in MSVC

What is the most portable and "right" way to do conversion from extended precision float (80-bit value, also known as long double in some compilers) to double (64-bit) in MSVC win32/win64?
MSVC currently (as of 2010) assumes that long double is double synonym.
I could probably write fld/fstp assembler pair in inline asm, but inline asm is not available for win64 code in MSVC. Do I need to move this assembler code to separate .asm file? Is that really so there are no good solution?
Just did this in x86 code...
.686P
.XMM
_TEXT SEGMENT
EXTRN __fltused:DWORD
PUBLIC _cvt80to64
PUBLIC _cvt64to80
_cvt80to64 PROC
mov eax, dword ptr [esp+4]
fld TBYTE PTR [eax]
ret 0
_cvt80to64 ENDP
_cvt64to80 PROC
mov eax, DWORD PTR [esp+12]
fld QWORD PTR [esp+4]
fstp TBYTE PTR [eax]
ret 0
_cvt64to80 ENDP
ENDIF
_TEXT ENDS
END
If your compiler / platform doesn't have native support for 80 bit floating point values, you have to decode the value yourself.
Assuming that the 80 bit float is stored within a byte buffer, located at a specific offset, you can do it like this:
float64 C_IOHandler::readFloat80(IColl<uint8> buffer, uint32 *ref_offset)
{
uint32 &offset = *ref_offset;
//80 bit floating point value according to the IEEE-754 specification and the Standard Apple Numeric Environment specification:
//1 bit sign, 15 bit exponent, 1 bit normalization indication, 63 bit mantissa
float64 sign;
if ((buffer[offset] & 0x80) == 0x00)
sign = 1;
else
sign = -1;
uint32 exponent = (((uint32)buffer[offset] & 0x7F) << 8) | (uint32)buffer[offset + 1];
uint64 mantissa = readUInt64BE(buffer, offset + 2);
//If the highest bit of the mantissa is set, then this is a normalized number.
float64 normalizeCorrection;
if ((mantissa & 0x8000000000000000) != 0x00)
normalizeCorrection = 1;
else
normalizeCorrection = 0;
mantissa &= 0x7FFFFFFFFFFFFFFF;
offset += 10;
//value = (-1) ^ s * (normalizeCorrection + m / 2 ^ 63) * 2 ^ (e - 16383)
return (sign * (normalizeCorrection + (float64)mantissa / ((uint64)1 << 63)) * g_Math->toPower(2, (int32)exponent - 16383));
}
This is how I did it, and it compiles fine with g++ 4.5.0. It of course isn't a very fast solution, but at least a functional one. This code should also be portable to different platforms, though I didn't try.
I've just written this one. It constructs an IEEE double number from IEEE extended precision number using bit operations. It takes the 10 byte extended precision number in little endian format:
typedef unsigned long long uint64;
double makeDoubleFromExtended(const unsigned char x[10])
{
int exponent = (((x[9] << 8) | x[8]) & 0x7FFF);
uint64 mantissa =
((uint64)x[7] << 56) | ((uint64)x[6] << 48) | ((uint64)x[5] << 40) | ((uint64)x[4] << 32) |
((uint64)x[3] << 24) | ((uint64)x[2] << 16) | ((uint64)x[1] << 8) | (uint64)x[0];
unsigned char d[8] = {0};
double result;
d[7] = x[9] & 0x80; /* Set sign. */
if ((exponent == 0x7FFF) || (exponent == 0))
{
/* Infinite, NaN or denormal */
if (exponent == 0x7FFF)
{
/* Infinite or NaN */
d[7] |= 0x7F;
d[6] = 0xF0;
}
else
{
/* Otherwise it's denormal. It cannot be represented as double. Translate as singed zero. */
memcpy(&result, d, 8);
return result;
}
}
else
{
/* Normal number. */
exponent = exponent - 0x3FFF + 0x03FF; /*< exponent for double precision. */
if (exponent <= -52) /*< Too small to represent. Translate as (signed) zero. */
{
memcpy(&result, d, 8);
return result;
}
else if (exponent < 0)
{
/* Denormal, exponent bits are already zero here. */
}
else if (exponent >= 0x7FF) /*< Too large to represent. Translate as infinite. */
{
d[7] |= 0x7F;
d[6] = 0xF0;
memset(d, 0x00, 6);
memcpy(&result, d, 8);
return result;
}
else
{
/* Representable number */
d[7] |= (exponent & 0x7F0) >> 4;
d[6] |= (exponent & 0xF) << 4;
}
}
/* Translate mantissa. */
mantissa >>= 11;
if (exponent < 0)
{
/* Denormal, further shifting is required here. */
mantissa >>= (-exponent + 1);
}
d[0] = mantissa & 0xFF;
d[1] = (mantissa >> 8) & 0xFF;
d[2] = (mantissa >> 16) & 0xFF;
d[3] = (mantissa >> 24) & 0xFF;
d[4] = (mantissa >> 32) & 0xFF;
d[5] = (mantissa >> 40) & 0xFF;
d[6] |= (mantissa >> 48) & 0x0F;
memcpy(&result, d, 8);
printf("Result: 0x%016llx", *(uint64*)(&result) );
return result;
}
Played with the given answers and ended up with this.
#include <cmath>
#include <limits>
#include <cassert>
#ifndef _M_X64
__inline __declspec(naked) double _cvt80to64(void* ) {
__asm {
// PUBLIC _cvt80to64 PROC
mov eax, dword ptr [esp+4]
fld TBYTE PTR [eax]
ret 0
// _cvt80to64 ENDP
}
}
#endif
#pragma pack(push)
#pragma pack(2)
typedef unsigned char tDouble80[10];
#pragma pack(pop)
typedef struct {
unsigned __int64 mantissa:64;
unsigned int exponent:15;
unsigned int sign:1;
} tDouble80Struct;
inline double convertDouble80(const tDouble80& val)
{
assert(10 == sizeof(tDouble80));
const tDouble80Struct* valStruct = reinterpret_cast<const tDouble80Struct*>(&val);
const unsigned int mask_exponent = (1 << 15) - 1;
const unsigned __int64 mantissa_high_highestbit = unsigned __int64(1) << 63;
const unsigned __int64 mask_mantissa = (unsigned __int64(1) << 63) - 1;
if (mask_exponent == valStruct->exponent) {
if(0 == valStruct->mantissa) {
return (0 != valStruct->sign) ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity();
}
// highest mantissa bit set means quiet NaN
return (0 != (mantissa_high_highestbit & valStruct->mantissa)) ? std::numeric_limits<double>::quiet_NaN() : std::numeric_limits<double>::signaling_NaN();
}
// 80 bit floating point value according to the IEEE-754 specification and
// the Standard Apple Numeric Environment specification:
// 1 bit sign, 15 bit exponent, 1 bit normalization indication, 63 bit mantissa
const double sign(valStruct->sign ? -1 : 1);
//If the highest bit of the mantissa is set, then this is a normalized number.
unsigned __int64 mantissa = valStruct->mantissa;
double normalizeCorrection = (mantissa & mantissa_high_highestbit) != 0 ? 1 : 0;
mantissa &= mask_mantissa;
//value = (-1) ^ s * (normalizeCorrection + m / 2 ^ 63) * 2 ^ (e - 16383)
return (sign * (normalizeCorrection + double(mantissa) / mantissa_high_highestbit) * pow(2.0, int(valStruct->exponent) - 16383));
}

Resources