1 /*
2  * Copyright (c) 2023 Wuerth Elektronik eiSos GmbH & Co. KG
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * @brief Driver file for the WSEN-PDUS-25131308XXX01 sensor.
10  */
11 
12 #include "WSEN_PDUS_25131308XXX01_hal.h"
13 
14 #include <stdio.h>
15 
16 #include <weplatform.h>
17 
18 #define PDUS_BASE		(uint64_t)2513130800000LL
19 
20 /**
21  * @brief Default sensor interface configuration.
22  */
23 static WE_sensorInterface_t pdusDefaultSensorInterface = {
24     .sensorType = WE_PDUS,
25     .interfaceType = WE_i2c,
26     .options = {.i2c = {.address = PDUS_ADDRESS_I2C, .burstMode = 0, .protocol = WE_i2cProtocol_Raw, .useRegAddrMsbForMultiBytesRead = 0, .reserved = 0},
27                 .spi = {.chipSelectPort = 0, .chipSelectPin = 0, .burstMode = 0, .reserved = 0},
28                 .readTimeout = 1000,
29                 .writeTimeout = 1000},
30     .handle = 0};
31 
32 /**
33  * @brief Read data from sensor.
34  *
35  * Note that this sensor doesn't have any registers to request - it
36  * will simply send up to 4 bytes of data in response to any read
37  * request.
38  *
39  * @param[in] sensorInterface Pointer to sensor interface
40  * @param[in] numBytesToRead Number of bytes to be read
41  * @param[out] data Target buffer
42  * @return Error Code
43  */
PDUS_ReadReg(WE_sensorInterface_t * sensorInterface,uint16_t numBytesToRead,uint8_t * data)44 static inline int8_t PDUS_ReadReg(WE_sensorInterface_t* sensorInterface,
45                                   uint16_t numBytesToRead,
46                                   uint8_t *data)
47 {
48   /*
49    * Caution: This sensor uses 5V Vcc and logic levels.
50    * Level conversion to 3.3V is required to talk with a STM32 or any
51    * other 3.3V MCU.
52    * This sensor only supports I2C read operation and returns either
53    * 2 or 4 bytes when the sensor address is written to the I2C bus.
54    * Sending a register address is not required.
55    * The first 2 bytes returned are the raw pressure value and the next 2
56    * bytes are the raw temperature values.
57    *
58    * See chapter "reading digital output data" of the PDUS user manual for
59    * the protocol.
60    *
61    * 1st I2C master sends sensor's I2C address (PDUS_ADDRESS_I2C) with read
62    * bit set and waits for ACK by sensor.
63    * 2nd I2C master read either 2 or 4 bytes back from the sensor; the slave
64    * (sensor) will send up to 4 bytes.
65    * Master has to ACK each byte and provide clock.
66    */
67 
68   return WE_ReadReg(sensorInterface, 0, numBytesToRead, data);
69 }
70 
71 /**
72  * @brief Returns the default sensor interface configuration.
73  * @param[out] sensorInterface Sensor interface configuration (output parameter)
74  * @return Error code
75  */
PDUS_getDefaultInterface(WE_sensorInterface_t * sensorInterface)76 int8_t PDUS_getDefaultInterface(WE_sensorInterface_t* sensorInterface)
77 {
78   *sensorInterface = pdusDefaultSensorInterface;
79   return WE_SUCCESS;
80 }
81 
82 /**
83  * @brief Read the raw pressure
84  * @param[in] sensorInterface Pointer to sensor interface
85  * @param[out] data Pointer to raw pressure value (unconverted), 15 bits
86  * @retval Error code
87  */
PDUS_getRawPressure(WE_sensorInterface_t * sensorInterface,uint16_t * pressure)88 int8_t PDUS_getRawPressure(WE_sensorInterface_t* sensorInterface, uint16_t *pressure)
89 {
90   uint8_t tmp[2] = {0};
91 
92   if (WE_FAIL == PDUS_ReadReg(sensorInterface, 2, tmp))
93   {
94     return WE_FAIL;
95   }
96 
97   *pressure = (uint16_t) ((tmp[0] & 0x7F) << 8);
98   *pressure |= (uint16_t) tmp[1];
99 
100   return WE_SUCCESS;
101 }
102 
103 /**
104  * @brief Read the raw pressure and temperature values
105  * @param[in] sensorInterface Pointer to sensor interface
106  * @param[out] pressure Pointer to raw pressure value (unconverted), 15 bits
107  * @param[out] temperature Pointer to raw temperature value (unconverted), 15 bits
108  * @retval Error code
109  */
PDUS_getRawPressureAndTemperature(WE_sensorInterface_t * sensorInterface,uint16_t * pressure,uint16_t * temperature)110 int8_t PDUS_getRawPressureAndTemperature(WE_sensorInterface_t* sensorInterface, uint16_t *pressure, uint16_t *temperature)
111 {
112   uint8_t tmp[4] = {0};
113 
114   if (WE_FAIL == PDUS_ReadReg(sensorInterface, 4, tmp))
115   {
116     return WE_FAIL;
117   }
118 
119   *pressure = (uint16_t) ((tmp[0] & 0x7F) << 8);
120   *pressure |= (uint16_t) tmp[1];
121 
122   *temperature = (uint16_t) ((tmp[2] & 0x7F) << 8);
123   *temperature |= (uint16_t) tmp[3];
124 
125   return WE_SUCCESS;
126 }
127 
128 #ifdef WE_USE_FLOAT
129 
130 /**
131  * @brief Read the pressure and temperature values
132  * @param[in] sensorInterface Pointer to sensor interface
133  * @param[in] type PDUS sensor type (i.e. pressure measurement range) for internal conversion of pressure, please refer to Article number mapping table
134  * @param[out] presskPa Pointer to pressure value
135  * @retval Error code
136  */
PDUS_getPressure_float(WE_sensorInterface_t * sensorInterface,PDUS_SensorType_t type,float * presskPa)137 int8_t PDUS_getPressure_float(WE_sensorInterface_t* sensorInterface, PDUS_SensorType_t type, float *presskPa)
138 {
139   uint16_t rawPres = 0;
140 
141   if (WE_FAIL == PDUS_getRawPressure(sensorInterface, &rawPres))
142   {
143     return WE_FAIL;
144   }
145 
146   if (rawPres < P_MIN_VAL_PDUS)
147   {
148     rawPres = P_MIN_VAL_PDUS;
149   }
150 
151   /* Perform conversion (depending on sensor sub-type) */
152   return PDUS_convertPressureToFloat(type, rawPres, presskPa);
153 }
154 
155 /**
156  * @brief Read the pressure and temperature values
157  * @param[in] sensorInterface Pointer to sensor interface
158  * @param[in] type PDUS sensor type (i.e. pressure measurement range) for internal conversion of pressure
159  * @param[out] presskPa Pointer to pressure value
160  * @param[out] tempDegC Pointer to temperature value
161  * @retval Error code
162  */
PDUS_getPressureAndTemperature_float(WE_sensorInterface_t * sensorInterface,PDUS_SensorType_t type,float * presskPa,float * tempDegC)163 int8_t PDUS_getPressureAndTemperature_float(WE_sensorInterface_t* sensorInterface, PDUS_SensorType_t type, float *presskPa, float *tempDegC)
164 {
165   uint16_t rawPres = 0;
166   uint16_t rawTemp = 0;
167 
168   if (WE_FAIL == PDUS_getRawPressureAndTemperature(sensorInterface, &rawPres, &rawTemp))
169   {
170     return WE_FAIL;
171   }
172 
173   /* Apply temperature offset to raw temperature and convert to °C */
174   *tempDegC = (((float) (rawTemp - T_MIN_VAL_PDUS) * 4.272f) / 1000);
175 
176   /* Perform conversion regarding sensor sub-type */
177   return PDUS_convertPressureToFloat(type, rawPres, presskPa);
178 }
179 
180 /**
181  * @brief Converts a raw pressure value to kPa, depending on the PDUS sensor type.
182  * @param[in] type PDUS sensor type (i.e. pressure measurement range)
183  * @param[in] rawPressure Raw pressure value as returned by the sensor
184  * @param[out] presskPa Pointer to pressure value
185  * @retval Error code
186  */
PDUS_convertPressureToFloat(PDUS_SensorType_t type,uint16_t rawPressure,float * presskPa)187 int8_t PDUS_convertPressureToFloat(PDUS_SensorType_t type, uint16_t rawPressure, float *presskPa)
188 {
189   float temp = (float) (rawPressure - P_MIN_VAL_PDUS);
190   switch (type)
191   {
192   case PDUS_pdus0:
193     *presskPa = ((temp * 7.63f) / 1000000) - 0.1f;
194     break;
195 
196   case PDUS_pdus1:
197     *presskPa = ((temp * 7.63f) / 100000) - 1.0f;
198     break;
199 
200   case PDUS_pdus2:
201     *presskPa = ((temp * 7.63f) / 10000) - 10.0f;
202     break;
203 
204   case PDUS_pdus3:
205     *presskPa = ((temp * 3.815f) / 1000);
206     break;
207 
208   case PDUS_pdus4:
209     *presskPa = ((temp * 4.196f) / 100) - 100.0f;
210     break;
211 
212   case PDUS_pdus5:
213     *presskPa = ((temp * 5.722f) / 100);
214     break;
215 
216   default:
217     return WE_FAIL;
218   }
219   return WE_SUCCESS;
220 }
221 
222 #endif /* WE_USE_FLOAT */
223 
224 
225