-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPD10LX.cpp
323 lines (262 loc) · 11.6 KB
/
PD10LX.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
#include "PD10LX.h"
#include <Wire.h>
#include <math.h>
#define MEASURE_ADR 0x00 // Address to get pressure and temperature data
#define SERIAL_NUMBER_ADR 0x30 // Address to get the serial number of the sensor
#define CALIBRATION_ADR 0x38 // Address to get the data of calibration
#define CFG_CHANNEL_ADR 0x44 // Address to see which channels are actives
#define BLOCK0_LDR 0x40 // Load value to get data from block 0 (data)
#define BLOCK3_LDR 0x43 // Load value to get data from block 3 (information)
/**
* @brief Constructor of the PD10LX class.
* @param slave_address The address of the slave.
*/
PD10LX::PD10LX()
{
}
/**
* @brief Initializes the members of the PD10LX object getting calibration date, specifications and active channels.
*/
bool PD10LX::init()
{
this->slave_address = 0x40; // The slave_address of the sensor is 0x40
bool err1 = this->sensorCalibration(); // Get calibration date
bool err2 = this->sensorInformation(); // Get the sensor specifications
bool err3 = this->sensorActiveChannels(); // Get the actives channels
this->flag_init = err1 && err2 && err3; // Set flag_init to true to indicate that initialization is complete
return this->flag_init;
}
/**
* @brief Get information about calibration date.
*/
bool PD10LX::sensorCalibration()
{
Wire.beginTransmission(this->slave_address); // Start the transmission with the slave address in writing mode
Wire.write(BLOCK3_LDR); // Write the ackBlockByteAmt value to the slave (Byte Amount (7...3) Block Nr (2...0))
Wire.write(CALIBRATION_ADR); // Write the address to the slave
uint8_t buffer[2] = {BLOCK3_LDR, CALIBRATION_ADR};
this->CRC = this->Crc8(buffer, 2); // Calculate the CRC value for the buffer
Wire.write(this->CRC); // Write the CRC value to the slave
byte err = Wire.endTransmission(); // End the transmission and check for any errors
if(err != 0) return 0;
delay(9);
Wire.requestFrom(this->slave_address, 7); // Request data from the slave
if(Wire.available())
{
// State and StatePT registers
Wire.read(); Wire.read();
this->calibration_day = Wire.read(); // Read the calibration day from the slave
this->calibration_month = Wire.read(); // Read the calibration month from the slave
this->calibration_year = int((uint16_t(Wire.read()) << 8) | uint16_t(Wire.read())); // Read the calibration year from the slave
}
return 1;
}
/**
* @brief Retrieves sensor information.
*/
bool PD10LX::sensorInformation()
{
// Sending data to the slave
Wire.beginTransmission(this->slave_address); // Start the transmission with the slave address in writing mode
Wire.write(BLOCK3_LDR); // Write the ackBlockByteAmt value to the slave (Byte Amount (7...3) Block Nr (2...0))
Wire.write(MEASURE_ADR); // Write the address to the slave
uint8_t buffer[2] = {BLOCK3_LDR, MEASURE_ADR};
this->CRC = this->Crc8(buffer, 2); // Calculate the CRC value for the buffer
Wire.write(this->CRC); // Write the CRC value to the slave
byte err = Wire.endTransmission(); // End the transmission and check for any errors
if(err != 0) return 0;
delay(9);
Wire.requestFrom(this->slave_address, 43); // Request data from the slave
if(Wire.available())
{
// State and StatePT registers
Wire.read(); Wire.read();
// Get hexadecimal (32 bits) value from Data register
this->P_min = ieee754_converter((uint32_t(Wire.read()) << 24) | (uint32_t(Wire.read()) << 16) | (uint32_t(Wire.read()) << 8) | uint32_t(Wire.read())); // Get the first 16 bits
this->P_max = ieee754_converter((uint32_t(Wire.read()) << 24) | (uint32_t(Wire.read()) << 16) | (uint32_t(Wire.read()) << 8) | uint32_t(Wire.read())); // Get the last 16 bits
}
return 1;
}
/**
* @brief Get active sensor channels.
*/
bool PD10LX::sensorActiveChannels()
{
// Sending data to the slave
Wire.beginTransmission(this->slave_address); // Start the transmission with the slave address in writing mode
Wire.write(BLOCK3_LDR); // Write the ackBlockByteAmt value to the slave (Byte Amount (7...3) Block Nr (2...0))
Wire.write(CFG_CHANNEL_ADR); // Write the address to the slave
uint8_t buffer[2] = {BLOCK3_LDR, CFG_CHANNEL_ADR};
this->CRC = this->Crc8(buffer, 2); // Calculate the CRC value for the buffer
Wire.write(this->CRC); // Write the CRC value to the slave
byte err = Wire.endTransmission(); // End the transmission and check for any errors
if(err != 0) return 0;
delay(9);
Wire.requestFrom(this->slave_address, 11); // Request data from the slave
if(Wire.available())
{
// Get State and StatePT register
Wire.read(); Wire.read();
this->channels = Wire.read(); // Read the active sensor channels from the slave
}
return 1;
}
/**
* @brief Reads data from the PD10LX sensor.
* @note: Make sure to initialize the sensor before calling this function.
*/
void PD10LX::read()
{
// Check initialization before obtaining data
while(!this->flag_init)
{
Serial.println("Sensor needs to be initialized before reading.");
delay(5000);
}
// Sending data to the slave
Wire.beginTransmission(this->slave_address); // Start the transmission with the slave address in writing mode
Wire.write(BLOCK0_LDR); // Write the ackBlockByteAmt value to the slave (Byte Amount (7...3) Block Nr (2...0))
Wire.write(MEASURE_ADR); // Write the address to the slave
uint8_t buffer[2] = {BLOCK0_LDR, MEASURE_ADR};
this->CRC = this->Crc8(buffer, 2); // Calculate the CRC value for the buffer
Wire.write(this->CRC); // Write the CRC value to the slave
byte err = Wire.endTransmission(); // End the transmission and check for any errors
while(err) {Serial.println("I2C communication error.");}
delay(9);
Wire.requestFrom(this->slave_address, 11); // Request 11 bytes of data from the slave in reading mode
if(Wire.available())
{
// Get State and StatePT register
this->state_register = Wire.read();
this->statePT_register = Wire.read();
// Get hexadecimal (32 bits) value from Data register
this->int_pressure = (uint32_t(Wire.read()) << 24) | (uint32_t(Wire.read()) << 16) | (uint32_t(Wire.read()) << 8) | uint32_t(Wire.read()); // Get the first 16 bits
this->int_temperature = (uint32_t(Wire.read()) << 24) | (uint32_t(Wire.read()) << 16) | (uint32_t(Wire.read()) << 8) | uint32_t(Wire.read()); // Get the last 16 bits
// Get CRC value
this->CRC = Wire.read();
this->flag_data = true;
}
}
/**
* @brief Retrieves the pressure value.
* @note Make sure to read the data before calling this function.
* @return The pressure value converted to float.
*/
float PD10LX::getPressure()
{
// Check that the data has been acquired before sending it back
while(!this->flag_data)
{
Serial.println("The data must be read before it can be retrieved.");
delay(5000);
}
return ieee754_converter(this->int_pressure);
}
/**
* @brief Retrieves the temperature value.
* @note : Make sure to read the data before calling this function.
* @return The temperature value converted to float.
*/
float PD10LX::getTemperature()
{
// Check that the data has been acquired before sending it back
while(!this->flag_data)
{
Serial.println("The data must be read before it can be retrieved.");
delay(5000);
}
return ieee754_converter(this->int_temperature);
}
/**
* @brief Prints debug information related to the PD10LX sensor.
*/
void PD10LX::debug()
{
// Print State register value
Serial.print("State: 0x");
Serial.println(this->state_register, HEX);
// Print StatePT register value
Serial.print("StatePT: 0x");
Serial.println(this->statePT_register, HEX);
// Print Data register values (pressure and temperature)
Serial.print("Data: 0x");
Serial.print(this->int_pressure, HEX);
Serial.print(" ");
Serial.println(this->int_temperature, HEX);
Serial.print("Pressure: ");
Serial.println(this->getPressure(), 5);
Serial.print("Temperature: ");
Serial.println(this->getTemperature(), 4);
// Print CRC value
Serial.print("CRC: 0x");
Serial.println(this->CRC, HEX);
// Print separator line
Serial.println("—————————————————————————————————————————————");
// Print flag_init status
Serial.print("Flag Init: ");
Serial.println(this->flag_init);
// Print flag_data status
Serial.print("Flag Data: ");
Serial.println(this->flag_data);
// Print date of calibration
Serial.print("Calibration: ");
Serial.print(this->calibration_day);
Serial.print("/");
Serial.print(this->calibration_month);
Serial.print("/");
Serial.println(this->calibration_year);
// Print information
Serial.print("P_max: ");
Serial.println(this->P_max);
Serial.print("P_min: ");
Serial.println(this->P_min);
Serial.print("CFG Channels (TOB2, TOB1, T, P2, P1): ");
Serial.println(this->channels, BIN);
// Print separator line
Serial.println("—————————————————————————————————————————————");
}
/**
* @name ieee754_converter
* @brief Convert a hexadecimal (32-bit) value into a decimal value using the IEEE-754 floating point converter
* @param hex_value the hexadecimal value to convert
* @return the conversion into decimals
*/
float PD10LX::ieee754_converter(uint32_t hex_value)
{
// Cast hexa value into deciaml value
uint32_t decimal_value = hex_value;
// Extraction of bits
uint32_t sign_bit = (decimal_value >> 31) & 0x1;
uint32_t exponent_bits = (decimal_value >> 23) & 0xFF;
uint32_t fraction_bits = decimal_value & 0x7FFFFF;
// Calculate values
int8_t sign = (-1) * (2 * sign_bit - 1);
int8_t exponent = exponent_bits - 127;
float fraction = 1.0 + (float(fraction_bits) / pow(2, 23));
// Calculate the final decimal value
float decimal_result = sign * fraction * pow(2, exponent);
return decimal_result;
}
/**
* @name Crc8
* @brief This function calculates the CRC8 value for the given buffer of data.
* @param Buffer Pointer to the input data buffer.
* @param Buffersize Size of the input data buffer.
* @return The calculated CRC8 value.
*/
uint8_t PD10LX::Crc8(uint8_t* Buffer, uint8_t Buffersize)
{
uint16_t data;
uint16_t crc = 0;
uint8_t i, j;
for (j = 0; j < Buffersize; j++) {
data = (uint16_t)*(Buffer+j);
crc ^= (data << 8);
for(i = 0; i < 8; i++) {
if (crc & 0x8000)
crc ^= 0x8380;
crc = crc << 1;
}
}
return (uint8_t)(crc >> 8);
}