TinyOS: converting uint16_t and uint8_t into uint32_t - tinyos

I'm having the following problem:
I have an uint8_t h_MSB and uint16_t h_LSB and iwant to combine them into a uint32_t
So here is my code:
void parseHeader(MyPackage Header,uint32_t* timeStamp ){
(*timeStamp) = (Header->h_MSB <<16)| Header->h_LSB;
}
But it does not seem to work;
I tried it with h_MSB = 10 and h_LSB= 10
I get 10 for the timestamp.
The problem seems to be that if I shift beyon 7 bit all information from
h_MSB ist lost, but how can it be since timestamp is a uint32_t ?

The problem is that h_MSB is uint8_t and the shift operation is performed within the uint8_t type (or possibly within uint16_t, but it doesn't matter), so you get 0. Cast it to uint32_t before shifting:
(*timeStamp) = (((uint32_t)Header->h_MSB) << 16) | Header->h_LSB;

Related

How do make code compatible to ESP32 board?

I'm trying to get a GY-US-42 ultrasonic sensor working on the ESP32. However, I keep getting an error while compiling. For and Arduino Board it is not a problem, but for the ESP32.
My code:
#include "Wire.h"
//The Arduino Wire library uses the 7-bit version of the address, so the code example uses 0x70 instead of the 8-bit 0xE0
#define SensorAddress byte(0x70)
//The sensors ranging command has a value of 0x51
#define RangeCommand byte(0x51)
//These are the two commands that need to be sent in sequence to change the sensor address
#define ChangeAddressCommand1 byte(0xAA)
#define ChangeAddressCommand2 byte(0xA5)
void setup() {
Serial.begin(115200); //Open serial connection at 9600 baud
Wire.begin();
// changeAddress(SensorAddress,0x40,0);
}
void loop(){
takeRangeReading(); //Tell the sensor to perform a ranging cycle
delay(50); //Wait for sensor to finish
word range = requestRange(); //Get the range from the sensor
Serial.print("Range: "); Serial.println(range); //Print to the user
}
//Commands the sensor to take a range reading
void takeRangeReading(){
Wire.beginTransmission(SensorAddress); //Start addressing
Wire.write(RangeCommand); //send range command
Wire.endTransmission(); //Stop and do something else now
}
//Returns the last range that the sensor determined in its last ranging cycle in centimeters. Returns 0 if there is no communication.
word requestRange(){
Wire.requestFrom(SensorAddress, byte(2));
if(Wire.available() >= 2){ //Sensor responded with the two bytes
byte HighByte = Wire.read(); //Read the high byte back
byte LowByte = Wire.read(); //Read the low byte back
word range = word(HighByte, LowByte); //Make a 16-bit word out of the two bytes for the range
return range;
}
else {
return word(0); //Else nothing was received, return 0
}
}
Error:
sketch/GY-US42_I2C.ino.cpp.o:(.literal._Z12requestRangev+0x0): undefined reference to `makeWord(unsigned short)'
sketch/GY-US42_I2C.ino.cpp.o: In function `requestRange()':
/Users/Arduino/GY-US42_I2C/GY-US42_I2C.ino:42: undefined reference to `makeWord(unsigned short)'
collect2: error: ld returned 1 exit status
The word() is for casting a variable or literal into a 16-bit word, it does not add two bytes into a 16-bit word as you do word(HighByte, LowByte), I'm actually surprise this even compiled in Arduino.
To get the range value, you could do:
int range = HighByte * 256 + LowByte;
or:
int range = ((int)HighByte) << 8 | LowByte; //cast HighByte to int, then shift left by 8 bits.
But since Wire.read() is returning an int instead of a byte(you can see its function prototype definition here), therefore you code can actually be written like this:
int reading = Wire.read(); //read the first data
reading = reading << 8; // shift reading left by 8 bits, equivalent to reading * 256
reading |= Wire.read(); // reading = reading | Wire.read()
By the way, when you use #define, you don't need to specifically cast the const value into specific data type, the compiler will take care of the optimization and the right data type, so:
#define SensorAddress byte(0x70)
would be just fine by defining like this:
#define SensorAddress 0x70
You also do not need to cast const value with byte(2) or return word(0). In the latter case, your function prototype already expect the return would be a data type of word.

Converting from void * to float

I have a pointer to some location in memory passed in, void *dataLoc.
Some program is transferring memory there as a bunch of unsigned chars where 0x00 is 0 and 0xFF is one.
I want to be able to pull, say, every 4th char and convert it to the float of what number is supposed to be represented. But I'm having trouble understanding how I get from a void * to an array of char[] to an array of float[].
My initial thought was to do something like
for(i=0,i<100,i++){
floatArray[i] = (float)(*((unsigned char *)dataLoc[4*i])) / 255;
}
the void * is cast to a char *.
the next 4th char is selected from the for loop
the * dereferences the char pointer, which should give me an unsigned char,
the float should change the char into a float, but a float representation of the number I want *255
I divide by 255 to get the fraction I want.
This fails, because I get the error "pointer of type 'void ' used in arithmetic
'void' is not a pointer-to-object type and beyond this, I'm not really confident that the rest of that line will work out the way I would like.
Can someone advise the proper way to handle this?
Good that you had warnings enabled.
dataLoc[4*i] occurs before (unsigned char *)dataLoc and leads to "pointer of type 'void *' used in arithmetic ..."
Cast to unsigned char * first.
Also remove extra level of *. The following is type unsigned char
((unsigned char *)dataLoc)[4*i]
Fixed:
void * dataLoc;
float floatArray[100];
// for(i=0,i<100,i++){ Use ';', not ','
for(int i=0;i<100;i++){
// Cast to `unsigned char *` before using `[]`
// * not needed here ---v
floatArray[i] = (float)( ( ((unsigned char *)dataLoc) [4*i])) / 255;
}
or
for (int i=0; i<100 ;i++) {
unsigned char value = ((unsigned char *)dataLoc)[4*i];
floatArray[i] = value / 255.0f;
}

Sending floats w/NRF8001

Using Blend Micro (basically Arduino Uno + Nordic nRF8001) to gather and send sensor data via BLE. Can't figure out how to send floats.
Here's a snip of code:
if ((lib_aci_is_pipe_available(&aci_state, PIPE_AIR_QUALITY_SENSOR_TEMPERATURE_MEASUREMENT_TX)) && (lib_aci_is_pipe_available(&aci_state, PIPE_AIR_QUALITY_SENSOR_RELATIVE_HUMIDITY_TX)) && (lib_aci_is_pipe_available(&aci_state, PIPE_AIR_QUALITY_SENSOR_CARBON_MONOXIDE_LEVEL_TX)))
{
// Read DHT & MQ7 sensors
h = dht.readHumidity(); // Read humidity from DHT
t = dht.readTemperature(); // Read temperature as Celsius from DHT
f = dht.readTemperature(true); // Read temperature as Fahrenheit from DHT
int VoutAn = analogRead(MQ7PIN); //Read Vout in analog from MQ7
// Compute heat index
hi = dht.computeHeatIndex(f, h);
// Compute CO in PPM
float Vout = (5.0/1023)*VoutAn;
co = 100.468*(pow(((5/Vout)-1),-1.43));
lib_aci_send_data(PIPE_AIR_QUALITY_SENSOR_TEMPERATURE_MEASUREMENT_TX, &f, sizeof(f));
lib_aci_send_data(PIPE_AIR_QUALITY_SENSOR_RELATIVE_HUMIDITY_TX, &h, sizeof(h));
lib_aci_send_data(PIPE_AIR_QUALITY_SENSOR_CARBON_MONOXIDE_LEVEL_TX, &co, sizeof(co));
}
And here's the compile error:
Arduino: 1.0.6 (Mac OS X), Board: "Blend Micro 3.3V/16MHz (overclock)"
BLE-DHT-MQ7-Test.ino: In function 'void loop()':
BLE-DHT-MQ7-Test.ino:287: error: cannot convert 'float*' to 'uint8_t*'
for argument '2' to 'bool lib_aci_send_data(uint8_t, uint8_t*,
uint8_t)'
BLE-DHT-MQ7-Test.ino:288: error: cannot convert 'float*' to 'uint8_t*'
for argument '2' to 'bool lib_aci_send_data(uint8_t, uint8_t*,
uint8_t)'
BLE-DHT-MQ7-Test.ino:289: error: cannot convert 'float*' to 'uint8_t*'
for argument '2' to 'bool lib_aci_send_data(uint8_t, uint8_t*,
uint8_t)'
My understanding of the aci_send_data function is that argument 2 is a uint8_t variable that points to the data in memory to be sent, and that this data can be in any form. But it only seems to work if the data is in a uint8_t variable - e.g. this compiles if I convert my variables to uint8_t - but I need floats...
So my questions:
Am I understanding the aci_send_data function correctly?
If so, what am I doing wrong?
If not, how can I send floats?
Thanks!
I am not sure about the parameters needed by lib_aci_send_data function however, according to this code it seems that the first parameter accepts the TX pin, the second one is the reference of the first byte (in a byte array) to be interpreted as a number, and the third is the length or number of bytes to consider.
The data type float is a 4-byte variable. If we have an array of bytes representing the float number, we can pass the reference of the first byte in the second parameter of the function, and pass 4 as the length (or number of bytes to consider) in the third parameter.
To convert float to byte array, see this thread. In your case, it would look like this:
typedef union _data {
float f;
char s[4];//since f takes 4 bytes
} myData;
myData q;
void setup(){
Serial.begin(9600);
}
void loop(){
q.f = 1.234;
//you can access the char array by using q.s
//q.s[0] q.s[1] ...
//take note that q.s is a reference to the first element
//so we can pass that immediately to the 2nd parameter
}
Now you can use the function in this way: lib_aci_send_data(PIPE_AIR_QUALITY_SENSOR_RELATIVE_HUMIDITY_TX, q.s, 4);
I cannot test this as of now since I'm on a different machine, please let me know if this was successful, I'm willing to add edits if necessary.
Thanks, it works! Seems a little cumbersome, but here's the code for getting all 3 variables I need to send as floats:
if ((lib_aci_is_pipe_available(&aci_state, PIPE_AIR_QUALITY_SENSOR_TEMPERATURE_MEASUREMENT_TX)) && (lib_aci_is_pipe_available(&aci_state, PIPE_AIR_QUALITY_SENSOR_RELATIVE_HUMIDITY_TX)) && (lib_aci_is_pipe_available(&aci_state, PIPE_AIR_QUALITY_SENSOR_CARBON_MONOXIDE_LEVEL_TX)))
{
typedef union _dataF
{
float f;
uint8_t fInt[4];
} myDataF;
myDataF F;
typedef union _dataH
{
float h;
uint8_t hInt[4];
} myDataH;
myDataH H;
typedef union _dataCO
{
float co;
uint8_t coInt[4];
} myDataCO;
myDataCO CO;
// Read DHT & MQ7 sensors
h = dht.readHumidity(); // Read humidity from DHT
t = dht.readTemperature(); // Read temperature as Celsius from DHT
f = dht.readTemperature(true); // Read temperature as Fahrenheit from DHT
int VoutAn = analogRead(MQ7PIN); //Read Vout in analog from MQ7
// Compute heat index
hi = dht.computeHeatIndex(f, h);
// Compute CO in PPM
float Vout = (5.0/1023)*VoutAn;
co = 100.468*(pow(((5/Vout)-1),-1.43));
F.f = f;
H.h = h;
CO.co = co;
lib_aci_send_data(PIPE_AIR_QUALITY_SENSOR_TEMPERATURE_MEASUREMENT_TX, F.fInt, 4);
lib_aci_send_data(PIPE_AIR_QUALITY_SENSOR_RELATIVE_HUMIDITY_TX, H.hInt, 4);
lib_aci_send_data(PIPE_AIR_QUALITY_SENSOR_CARBON_MONOXIDE_LEVEL_TX, CO.coInt, 4);
}
I put the sensor data into wider scope floats as I draw on them elsewhere in the program.

how to convert double between host and network byte order?

Could somebody tell me how to convert double precision into network byte ordering.
I tried
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
functions and they worked well but none of them does double (float) conversion because these types are different on every architecture. And through the XDR i found double-float precision format representations (http://en.wikipedia.org/wiki/Double_precision) but no byte ordering there.
So, I would much appreciate if somebody helps me out on this (C code would be great!).
NOTE: OS is Linux kernel (2.6.29), ARMv7 CPU architecture.
You could look at IEEE 754 at the interchanging formats of floating points.
But the key should be to define a network order, ex. 1. byte exponent and sign, bytes 2 to n as mantissa in msb order.
Then you can declare your functions
uint64_t htond(double hostdouble);
double ntohd(uint64_t netdouble);
The implementation only depends of your compiler/plattform.
The best should be to use some natural definition,
so you could use at the ARM-platform simple transformations.
EDIT:
From the comment
static void htond (double &x)
{
int *Double_Overlay;
int Holding_Buffer;
Double_Overlay = (int *) &x;
Holding_Buffer = Double_Overlay [0];
Double_Overlay [0] = htonl (Double_Overlay [1]);
Double_Overlay [1] = htonl (Holding_Buffer);
}
This could work, but obviously only if both platforms use the same coding schema for double and if int has the same size of long.
Btw. The way of returning the value is a bit odd.
But you could write a more stable version, like this (pseudo code)
void htond (const double hostDouble, uint8_t result[8])
{
result[0] = signOf(hostDouble);
result[1] = exponentOf(hostDouble);
result[2..7] = mantissaOf(hostDouble);
}
This might be hacky (the char* hack), but it works for me:
double Buffer::get8AsDouble(){
double little_endian = *(double*)this->cursor;
double big_endian;
int x = 0;
char *little_pointer = (char*)&little_endian;
char *big_pointer = (char*)&big_endian;
while( x < 8 ){
big_pointer[x] = little_pointer[7 - x];
++x;
}
return big_endian;
}
For brevity, I've not include the range guards. Though, you should include range guards when working at this level.

Which is the most efficient operation to split an integer to two characters in an Arduino?

Which of the following two approches is more efficient on an ATmega328P?
unsigned int value;
unsigned char char_high, char_low;
char_high = value>>8;
value = value<<8;
char_low = value>>8;
OR
unsigned int value;
unsigned char char_high, char_low;
char_high = value>>8;
char_low = value & 0xff;
You really should measure. I won't answer your question (since you'd benefit more from measuring than I would), but I'll give you a third option:
struct {
union {
uint16_t big;
uint8_t small[2];
};
} nums;
(be aware of the difference between big endian and little endian here)
One option would be to measure it (as has already been said).
Or, compile both and see what the assembly language output looks like.
but actually, the 2nd code you have won't work - if you take value << 8 and assign it to a char, all you get is zero in the char. The subsequent >>8 will still leave you with zero.

Resources