1 /* Driver for the SHT21 Relative Humidity and Temperature Sensor */ 2 3 #include <minix/ds.h> 4 #include <minix/drivers.h> 5 #include <minix/i2c.h> 6 #include <minix/i2cdriver.h> 7 #include <minix/chardriver.h> 8 #include <minix/log.h> 9 10 #include <time.h> 11 12 /* 13 * Device Commands 14 */ 15 16 /* 17 * The trigger commands start a measurement. 'Hold' ties up the bus while the 18 * measurement is being performed while 'no hold' requires the driver to poll 19 * the chip until the data is ready. Hold is faster and requires less message 20 * passing while no hold frees up the bus while the measurement is in progress. 21 * The worst case conversion times are 85 ms for temperature and 29 ms for 22 * humidity. Typical conversion times are about 75% of the worst case times. 23 * 24 * The driver uses the 'hold' versions of the trigger commands. 25 */ 26 #define CMD_TRIG_T_HOLD 0xe3 27 #define CMD_TRIG_RH_HOLD 0xe5 28 #define CMD_TRIG_T_NOHOLD 0xf3 29 #define CMD_TRIG_RH_NOHOLD 0xf5 30 31 /* Read and write the user register contents */ 32 #define CMD_WR_USR_REG 0xe6 33 #define CMD_RD_USR_REG 0xe7 34 35 /* Resets the chip */ 36 #define CMD_SOFT_RESET 0xfe 37 38 /* Status bits included in the measurement need to be masked in calculation */ 39 #define STATUS_BITS_MASK 0x0003 40 41 /* 42 * The user register has some reserved bits that the device changes over 43 * time. The driver must preserve the value of those bits when writing to 44 * the user register. 45 */ 46 #define USR_REG_RESERVED_MASK ((1<<3)|(1<<4)|(1<<5)) 47 48 /* End of Battery flag is set when the voltage drops below 2.25V. */ 49 #define USR_REG_EOB_MASK (1<<6) 50 51 /* When powered up and communicating, the register should have only the 52 * 'Disable OTP Reload' bit set 53 */ 54 #define EXPECTED_PWR_UP_TEST_VAL (1<<1) 55 56 /* Define some constants for the different sensor types on the chip. */ 57 enum sht21_sensors 58 { SHT21_T, SHT21_RH }; 59 60 /* logging - use with log_warn(), log_info(), log_debug(), log_trace(), etc */ 61 static struct log log = { 62 .name = "sht21", 63 .log_level = LEVEL_INFO, 64 .log_func = default_log 65 }; 66 67 /* device slave address is fixed at 0x40 */ 68 static i2c_addr_t valid_addrs[2] = { 69 0x40, 0x00 70 }; 71 72 /* Buffer to store output string returned when reading from device file. */ 73 #define BUFFER_LEN 64 74 char buffer[BUFFER_LEN + 1]; 75 76 /* the bus that this device is on (counting starting at 1) */ 77 static uint32_t bus; 78 79 /* slave address of the device */ 80 static i2c_addr_t address; 81 82 /* endpoint for the driver for the bus itself. */ 83 static endpoint_t bus_endpoint; 84 85 /* Sampling causes self-heating. To limit the self-heating to < 0.1C, the 86 * data sheet suggests limiting sampling to 2 samples per second. Since 87 * the driver samples temperature and relative humidity at the same time, 88 * it's measure function does at most 1 pair of samples per second. It uses 89 * this timestamp to see if a measurement was taken less than 1 second ago. 90 */ 91 static time_t last_sample_time = 0; 92 93 /* 94 * Cache temperature and relative humidity readings. These values are returned 95 * when the last_sample_time == current_time to keep the chip activity below 96 * 10% to help prevent self-heating. 97 */ 98 static int32_t cached_t = 0.0; 99 static int32_t cached_rh = 0.0; 100 101 /* 102 * An 8-bit CRC is used to validate the readings. 103 */ 104 #define CRC8_POLYNOMIAL 0x131 105 #define CRC8_INITIAL_CRC 0x00 106 107 /* main driver functions */ 108 static int sht21_init(void); 109 static int sensor_read(enum sht21_sensors sensor, int32_t * measurement); 110 static int measure(void); 111 112 /* CRC functions */ 113 static uint8_t crc8(uint8_t crc, uint8_t byte); 114 static int checksum(uint8_t * bytes, int nbytes, uint8_t expected_crc); 115 116 /* libchardriver callbacks */ 117 static ssize_t sht21_read(devminor_t minor, u64_t position, endpoint_t endpt, 118 cp_grant_id_t grant, size_t size, int flags, cdev_id_t id); 119 static void sht21_other(message * m, int ipc_status); 120 121 /* SEF functions */ 122 static int sef_cb_lu_state_save(int); 123 static int lu_state_restore(void); 124 static int sef_cb_init(int type, sef_init_info_t * info); 125 static void sef_local_startup(void); 126 127 /* Entry points to this driver from libchardriver. */ 128 static struct chardriver sht21_tab = { 129 .cdr_read = sht21_read, 130 .cdr_other = sht21_other 131 }; 132 133 /* 134 * Performs a soft reset and reads the contents of the user register to ensure 135 * that the chip is in a good state and working properly. 136 */ 137 static int 138 sht21_init(void) 139 { 140 int r; 141 uint8_t usr_reg_val; 142 143 /* Perform a soft-reset */ 144 r = i2creg_raw_write8(bus_endpoint, address, CMD_SOFT_RESET); 145 if (r != OK) { 146 return -1; 147 } 148 149 /* soft reset takes up to 15 ms to complete. */ 150 micro_delay(15000); 151 152 log_debug(&log, "Soft Reset Complete\n"); 153 154 r = i2creg_read8(bus_endpoint, address, CMD_RD_USR_REG, &usr_reg_val); 155 if (r != OK) { 156 return -1; 157 } 158 159 /* Check for End of Battery flag. */ 160 if ((usr_reg_val & USR_REG_EOB_MASK) == USR_REG_EOB_MASK) { 161 log_warn(&log, "End of Battery Alarm\n"); 162 return -1; 163 } 164 165 /* Check that the non-reserved bits are in the default state. */ 166 if ((usr_reg_val & ~USR_REG_RESERVED_MASK) != EXPECTED_PWR_UP_TEST_VAL) { 167 log_warn(&log, "USR_REG has non-default values after reset\n"); 168 log_warn(&log, "Expected 0x%x | Actual 0x%x", 169 EXPECTED_PWR_UP_TEST_VAL, 170 (usr_reg_val & ~USR_REG_RESERVED_MASK)); 171 return -1; 172 } 173 174 return OK; 175 } 176 177 /* 178 * Read from the sensor, check the CRC, convert the ADC value into the final 179 * representation, and store the result in measurement. 180 */ 181 static int 182 sensor_read(enum sht21_sensors sensor, int32_t * measurement) 183 { 184 int r; 185 uint8_t cmd; 186 uint16_t val; 187 uint8_t bytes[2]; 188 uint32_t val32; 189 uint8_t expected_crc; 190 191 switch (sensor) { 192 case SHT21_T: 193 cmd = CMD_TRIG_T_HOLD; 194 break; 195 case SHT21_RH: 196 cmd = CMD_TRIG_RH_HOLD; 197 break; 198 default: 199 log_warn(&log, "sensor_read() called with bad sensor type.\n"); 200 return -1; 201 } 202 203 if (measurement == NULL) { 204 log_warn(&log, "sensor_read() called with NULL pointer\n"); 205 return -1; 206 } 207 208 r = i2creg_read24(bus_endpoint, address, cmd, &val32); 209 if (r != OK) { 210 log_warn(&log, "sensor_read() failed (r=%d)\n", r); 211 return -1; 212 } 213 214 expected_crc = val32 & 0xff; 215 val = (val32 >> 8) & 0xffff; 216 217 bytes[0] = (val >> 8) & 0xff; 218 bytes[1] = val & 0xff; 219 220 r = checksum(bytes, 2, expected_crc); 221 if (r != OK) { 222 return -1; 223 } 224 225 val &= ~STATUS_BITS_MASK; /* clear status bits */ 226 227 log_debug(&log, "Read VAL:0x%x CRC:0x%x\n", val, expected_crc); 228 229 /* Convert the ADC value to the actual value. */ 230 if (cmd == CMD_TRIG_T_HOLD) { 231 *measurement = (int32_t) 232 ((-46.85 + ((175.72 / 65536) * ((float) val))) * 1000.0); 233 log_debug(&log, "Measured Temperature %d mC\n", *measurement); 234 } else if (cmd == CMD_TRIG_RH_HOLD) { 235 *measurement = 236 (int32_t) ((-6.0 + 237 ((125.0 / 65536) * ((float) val))) * 1000.0); 238 log_debug(&log, "Measured Humidity %d m%%\n", *measurement); 239 } 240 241 return OK; 242 } 243 244 static int 245 measure(void) 246 { 247 int r; 248 time_t sample_time; 249 int32_t t, rh; 250 251 log_debug(&log, "Taking a measurement..."); 252 253 sample_time = time(NULL); 254 if (sample_time == last_sample_time) { 255 log_debug(&log, "measure() called too soon, using cache.\n"); 256 return OK; 257 } 258 259 r = sensor_read(SHT21_T, &t); 260 if (r != OK) { 261 return -1; 262 } 263 264 r = sensor_read(SHT21_RH, &rh); 265 if (r != OK) { 266 return -1; 267 } 268 269 /* save measured values */ 270 cached_t = t; 271 cached_rh = rh; 272 last_sample_time = time(NULL); 273 274 log_debug(&log, "Measurement completed\n"); 275 276 return OK; 277 } 278 279 /* 280 * Return an updated checksum for the given crc and byte. 281 */ 282 static uint8_t 283 crc8(uint8_t crc, uint8_t byte) 284 { 285 int i; 286 287 crc ^= byte; 288 289 for (i = 0; i < 8; i++) { 290 291 if ((crc & 0x80) == 0x80) { 292 crc = (crc << 1) ^ CRC8_POLYNOMIAL; 293 } else { 294 crc <<= 1; 295 } 296 } 297 298 return crc; 299 } 300 301 /* 302 * Compute the CRC of an array of bytes and compare it to expected_crc. 303 * If the computed CRC matches expected_crc, then return OK, otherwise EINVAL. 304 */ 305 static int 306 checksum(uint8_t * bytes, int nbytes, uint8_t expected_crc) 307 { 308 int i; 309 uint8_t crc; 310 311 crc = CRC8_INITIAL_CRC; 312 313 log_debug(&log, "Checking CRC\n"); 314 315 for (i = 0; i < nbytes; i++) { 316 crc = crc8(crc, bytes[i]); 317 } 318 319 if (crc == expected_crc) { 320 log_debug(&log, "CRC OK\n"); 321 return OK; 322 } else { 323 log_warn(&log, 324 "Bad CRC -- Computed CRC: 0x%x | Expected CRC: 0x%x\n", 325 crc, expected_crc); 326 return EINVAL; 327 } 328 } 329 330 static ssize_t 331 sht21_read(devminor_t UNUSED(minor), u64_t position, endpoint_t endpt, 332 cp_grant_id_t grant, size_t size, int UNUSED(flags), cdev_id_t UNUSED(id)) 333 { 334 u64_t dev_size; 335 int bytes, r; 336 337 r = measure(); 338 if (r != OK) { 339 return EIO; 340 } 341 342 memset(buffer, '\0', BUFFER_LEN + 1); 343 snprintf(buffer, BUFFER_LEN, "%-16s: %d.%03d\n%-16s: %d.%03d\n", 344 "TEMPERATURE", cached_t / 1000, cached_t % 1000, "HUMIDITY", 345 cached_rh / 1000, cached_rh % 1000); 346 347 log_trace(&log, "%s", buffer); 348 349 dev_size = (u64_t)strlen(buffer); 350 if (position >= dev_size) return 0; 351 if (position + size > dev_size) 352 size = (size_t)(dev_size - position); 353 354 r = sys_safecopyto(endpt, grant, 0, 355 (vir_bytes)(buffer + (size_t)position), size); 356 357 return (r != OK) ? r : size; 358 } 359 360 static void 361 sht21_other(message * m, int ipc_status) 362 { 363 int r; 364 365 if (is_ipc_notify(ipc_status)) { 366 if (m->m_source == DS_PROC_NR) { 367 log_debug(&log, 368 "bus driver changed state, update endpoint\n"); 369 i2cdriver_handle_bus_update(&bus_endpoint, bus, 370 address); 371 } 372 return; 373 } 374 375 log_warn(&log, "Invalid message type (0x%x)\n", m->m_type); 376 } 377 378 static int 379 sef_cb_lu_state_save(int UNUSED(state)) 380 { 381 ds_publish_u32("bus", bus, DSF_OVERWRITE); 382 ds_publish_u32("address", address, DSF_OVERWRITE); 383 return OK; 384 } 385 386 static int 387 lu_state_restore(void) 388 { 389 /* Restore the state. */ 390 u32_t value; 391 392 ds_retrieve_u32("bus", &value); 393 ds_delete_u32("bus"); 394 bus = (int) value; 395 396 ds_retrieve_u32("address", &value); 397 ds_delete_u32("address"); 398 address = (int) value; 399 400 return OK; 401 } 402 403 static int 404 sef_cb_init(int type, sef_init_info_t * UNUSED(info)) 405 { 406 int r; 407 408 if (type == SEF_INIT_LU) { 409 /* Restore the state. */ 410 lu_state_restore(); 411 } 412 413 /* look-up the endpoint for the bus driver */ 414 bus_endpoint = i2cdriver_bus_endpoint(bus); 415 if (bus_endpoint == 0) { 416 log_warn(&log, "Couldn't find bus driver.\n"); 417 return EXIT_FAILURE; 418 } 419 420 /* claim the device */ 421 r = i2cdriver_reserve_device(bus_endpoint, address); 422 if (r != OK) { 423 log_warn(&log, "Couldn't reserve device 0x%x (r=%d)\n", 424 address, r); 425 return EXIT_FAILURE; 426 } 427 428 r = sht21_init(); 429 if (r != OK) { 430 log_warn(&log, "Device Init Failed\n"); 431 return EXIT_FAILURE; 432 } 433 434 if (type != SEF_INIT_LU) { 435 436 /* sign up for updates about the i2c bus going down/up */ 437 r = i2cdriver_subscribe_bus_updates(bus); 438 if (r != OK) { 439 log_warn(&log, "Couldn't subscribe to bus updates\n"); 440 return EXIT_FAILURE; 441 } 442 443 i2cdriver_announce(bus); 444 log_debug(&log, "announced\n"); 445 } 446 447 return OK; 448 } 449 450 static void 451 sef_local_startup(void) 452 { 453 /* 454 * Register init callbacks. Use the same function for all event types 455 */ 456 sef_setcb_init_fresh(sef_cb_init); 457 sef_setcb_init_lu(sef_cb_init); 458 sef_setcb_init_restart(sef_cb_init); 459 460 /* 461 * Register live update callbacks. 462 */ 463 /* Agree to update immediately when LU is requested in a valid state. */ 464 sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready); 465 /* Support live update starting from any standard state. */ 466 sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_standard); 467 /* Register a custom routine to save the state. */ 468 sef_setcb_lu_state_save(sef_cb_lu_state_save); 469 470 /* Let SEF perform startup. */ 471 sef_startup(); 472 } 473 474 int 475 main(int argc, char *argv[]) 476 { 477 int r; 478 479 env_setargs(argc, argv); 480 481 r = i2cdriver_env_parse(&bus, &address, valid_addrs); 482 if (r < 0) { 483 log_warn(&log, "Expecting -args 'bus=X address=0xYY'\n"); 484 log_warn(&log, "Example -args 'bus=1 address=0x40'\n"); 485 return EXIT_FAILURE; 486 } else if (r > 0) { 487 log_warn(&log, 488 "Invalid slave address for device, expecting 0x40\n"); 489 return EXIT_FAILURE; 490 } 491 492 sef_local_startup(); 493 494 chardriver_task(&sht21_tab); 495 496 return 0; 497 } 498