Firmware SDK
twr_soil_sensor.c
1 #include <twr_soil_sensor.h>
2 #include <twr_module_sensor.h>
3 #include <twr_timer.h>
4 #include <twr_i2c.h>
5 #include <twr_system.h>
6 #include <twr_tick.h>
7 
8 #define _TWR_SOIL_SENSOR_TMP112_ADDRESS 0x48
9 #define _TWR_SOIL_SENSOR_ZSSC3123_ADDRESS 0x28
10 #define _TWR_SOIL_SENSOR_EEPROM_ADDRESS 0x51
11 #define _TWR_SOIL_SENSOR_EEPROM_BANK_A 0x000
12 #define _TWR_SOIL_SENSOR_EEPROM_BANK_B 0x080
13 #define _TWR_SOIL_SENSOR_EEPROM_BANK_C 0x100
14 
15 static void _twr_soil_sensor_task_interval(void *param);
16 static void _twr_soil_sensor_error(twr_soil_sensor_t *self, twr_soil_sensor_error_t error);
17 static void _twr_soil_sensor_task_measure(void *param);
18 static bool _twr_soil_sensor_tmp112_init(twr_ds28e17_t *ds28e17);
19 static bool _twr_soil_sensor_tmp112_measurement_request(twr_ds28e17_t *ds28e17);
20 static bool _twr_soil_sensor_tmp112_data_fetch(twr_soil_sensor_sensor_t *sensor);
21 static bool _twr_soil_sensor_zssc3123_measurement_request(twr_ds28e17_t *ds28e17);
22 static bool _twr_soil_sensor_zssc3123_data_fetch(twr_soil_sensor_sensor_t *sensor);
23 static twr_soil_sensor_error_t _twr_soil_sensor_eeprom_load(twr_soil_sensor_sensor_t *sensor);
24 static void _twr_soil_sensor_eeprom_fill(twr_soil_sensor_sensor_t *sensor);
25 static bool _twr_soil_sensor_eeprom_save(twr_soil_sensor_sensor_t *sensor);
26 static bool _twr_soil_sensor_eeprom_read(twr_soil_sensor_sensor_t *sensor, uint8_t address, void *buffer, size_t length);
27 static bool _twr_soil_sensor_eeprom_write(twr_soil_sensor_sensor_t *sensor, uint8_t address, const void *buffer, size_t length);
28 
30 {
31  static twr_soil_sensor_sensor_t sensor[1];
32 
33  twr_soil_sensor_init_multiple(self, sensor, 1);
34 }
35 
36 void twr_soil_sensor_init_multiple(twr_soil_sensor_t *self, twr_soil_sensor_sensor_t *sensors, int sensor_count)
37 {
38  memset(self, 0, sizeof(*self));
39 
40  self->_onewire = twr_module_sensor_get_onewire();
41  twr_onewire_auto_ds28e17_sleep_mode(self->_onewire, true);
42 
43  self->_sensor = sensors;
44  self->_sensor_count = sensor_count;
45 
46  self->_task_id_interval = twr_scheduler_register(_twr_soil_sensor_task_interval, self, TWR_TICK_INFINITY);
47  self->_task_id_measure = twr_scheduler_register(_twr_soil_sensor_task_measure, self, 10);
48 }
49 
50 void twr_soil_sensor_set_event_handler(twr_soil_sensor_t *self, void (*event_handler)(twr_soil_sensor_t *, uint64_t device_address, twr_soil_sensor_event_t, void *), void *event_param)
51 {
52  self->_event_handler = event_handler;
53 
54  self->_event_param = event_param;
55 }
56 
58 {
59  self->_update_interval = interval;
60 
61  if (self->_update_interval == TWR_TICK_INFINITY)
62  {
63  twr_scheduler_plan_absolute(self->_task_id_interval, TWR_TICK_INFINITY);
64  }
65  else
66  {
67  twr_scheduler_plan_relative(self->_task_id_interval, self->_update_interval);
68 
70  }
71 }
72 
74 {
75  return self->_sensor_found;
76 }
77 
79 {
80  if (self->_measurement_active)
81  {
82  return false;
83  }
84 
85  self->_measurement_active = true;
86 
87  twr_scheduler_plan_now(self->_task_id_measure);
88 
89  return true;
90 }
91 
92 bool twr_soil_sensor_get_temperature_raw(twr_soil_sensor_t *self, uint64_t device_address, int16_t *raw)
93 {
94  int i = twr_soil_sensor_get_index_by_device_address(self, device_address);
95 
96  if (i == -1)
97  {
98  return false;
99  }
100 
101  if (!self->_sensor[i]._temperature_raw)
102  {
103  return false;
104  }
105 
106  *raw = (int16_t) self->_sensor[i]._temperature_raw >> 4;
107 
108  return true;
109 }
110 
111 bool twr_soil_sensor_get_temperature_celsius(twr_soil_sensor_t *self, uint64_t device_address, float *celsius)
112 {
113  int16_t raw;
114 
115  if (!twr_soil_sensor_get_temperature_raw(self, device_address, &raw))
116  {
117  *celsius = NAN;
118 
119  return false;
120  }
121 
122  *celsius = (float) raw / 16.f;
123 
124  return true;
125 }
126 
127 bool twr_soil_sensor_get_temperature_fahrenheit(twr_soil_sensor_t *self, uint64_t device_address, float *fahrenheit)
128 {
129  float celsius;
130 
131  if (!twr_soil_sensor_get_temperature_celsius(self, device_address, &celsius))
132  {
133  return false;
134  }
135 
136  *fahrenheit = celsius * 1.8f + 32.f;
137 
138  return true;
139 }
140 
141 bool twr_soil_sensor_get_temperature_kelvin(twr_soil_sensor_t *self, uint64_t device_address, float *kelvin)
142 {
143  float celsius;
144 
145  if (!twr_soil_sensor_get_temperature_celsius(self, device_address, &celsius))
146  {
147  return false;
148  }
149 
150  *kelvin = celsius + 273.15f;
151 
152  if (*kelvin < 0.f)
153  {
154  *kelvin = 0.f;
155  }
156 
157  return true;
158 }
159 
160 bool twr_soil_sensor_get_cap_raw(twr_soil_sensor_t *self, uint64_t device_address, uint16_t *raw)
161 {
162  int i = twr_soil_sensor_get_index_by_device_address(self, device_address);
163 
164  if (i == -1)
165  {
166  return false;
167  }
168 
169  if (!self->_sensor[i]._cap_valid)
170  {
171  return false;
172  }
173 
174  *raw = self->_sensor[i]._cap_raw;
175 
176  return true;
177 }
178 
179 bool twr_soil_sensor_get_moisture(twr_soil_sensor_t *self, uint64_t device_address, int *moisture)
180 {
181  int i = twr_soil_sensor_get_index_by_device_address(self, device_address);
182 
183  if (i == -1)
184  {
185  return false;
186  }
187 
188  if (!self->_sensor[i]._cap_valid)
189  {
190  return false;
191  }
192 
193  uint16_t raw = self->_sensor[i]._cap_raw;
194  uint16_t *calibration = self->_sensor[i]._eeprom.calibration;
195 
196  for (int i = 0; i < 11; i++)
197  {
198  if (raw < calibration[i])
199  {
200  if (i == 0)
201  {
202  *moisture = 0;
203 
204  return true;
205  }
206 
207  *moisture = (((raw - calibration[i - 1]) * 10) / (calibration[i] - calibration[i - 1])) + (10 * (i - 1));
208 
209  return true;
210  }
211  }
212 
213  *moisture = 100;
214 
215  return true;
216 }
217 
219 {
220  for (int i = 0; i < self->_sensor_found; i++)
221  {
222  if (self->_sensor[i]._ds28e17._device_number == device_address)
223  {
224  return i;
225  }
226  }
227 
228  return -1;
229 }
230 
232 {
233  if (index >= self->_sensor_found)
234  {
235  return 0;
236  }
237 
238  return self->_sensor[index]._ds28e17._device_number;
239 }
240 
241 char *twr_soil_sensor_get_label(twr_soil_sensor_t *self, uint64_t device_address)
242 {
243  int i = twr_soil_sensor_get_index_by_device_address(self, device_address);
244 
245  if (i == -1)
246  {
247  return false;
248  }
249 
250  return self->_sensor[i]._eeprom.label;
251 }
252 
253 bool twr_soil_sensor_set_label(twr_soil_sensor_t *self, uint64_t device_address, const char *label)
254 {
255  int i = twr_soil_sensor_get_index_by_device_address(self, device_address);
256 
257  if (i == -1)
258  {
259  return false;
260  }
261 
262  strncpy(self->_sensor[i]._eeprom.label, label, 16);
263 
264  return true;
265 }
266 
267 bool twr_soil_sensor_calibration_set_point(twr_soil_sensor_t *self, uint64_t device_address, uint8_t point, uint16_t value)
268 {
269  int i = twr_soil_sensor_get_index_by_device_address(self, device_address);
270 
271  if (i == -1)
272  {
273  return false;
274  }
275 
276  point = point / 10;
277 
278  if (point > 10)
279  {
280  return false;
281  }
282 
283  self->_sensor[i]._eeprom.calibration[point] = value;
284 
285  return true;
286 }
287 
288 bool twr_soil_sensor_eeprom_save(twr_soil_sensor_t *self, uint64_t device_address)
289 {
290  int i = twr_soil_sensor_get_index_by_device_address(self, device_address);
291 
292  if (i == -1)
293  {
294  return false;
295  }
296 
297  return _twr_soil_sensor_eeprom_save(&self->_sensor[i]);
298 }
299 
301 {
302  return self->_error;
303 }
304 
305 static void _twr_soil_sensor_task_interval(void *param)
306 {
307  twr_soil_sensor_t *self = param;
308 
310 
311  twr_scheduler_plan_current_relative(self->_update_interval);
312 }
313 
314 static void _twr_soil_sensor_error(twr_soil_sensor_t *self, twr_soil_sensor_error_t error)
315 {
316  self->_error = error;
317  self->_state = TWR_SOIL_SENSOR_STATE_ERROR;
319 }
320 
321 static void _twr_soil_sensor_task_measure(void *param)
322 {
323  twr_soil_sensor_t *self = param;
324 
325  switch (self->_state)
326  {
327  case TWR_SOIL_SENSOR_STATE_ERROR:
328  {
329  twr_onewire_auto_ds28e17_sleep_mode(self->_onewire, true);
330 
331  for (int i = 0; i < self->_sensor_found; i++)
332  {
333  self->_sensor[i]._temperature_valid = false;
334  self->_sensor[i]._cap_valid = false;
335  }
336 
337  self->_measurement_active = false;
338 
340 
341  if (self->_event_handler != NULL)
342  {
343  self->_event_handler(self, 0, TWR_SOIL_SENSOR_EVENT_ERROR, self->_event_param);
344  }
345 
346  self->_state = TWR_SOIL_SENSOR_STATE_PREINITIALIZE;
347 
348  return;
349  }
350  case TWR_SOIL_SENSOR_STATE_PREINITIALIZE:
351  {
352  if (!twr_module_sensor_init())
353  {
354  _twr_soil_sensor_error(self, TWR_SOIL_SENSOR_ERROR_SENSOR_MODULE_INITIALIZE);
355 
356  return;
357  }
358 
360  {
361  _twr_soil_sensor_error(self, TWR_SOIL_SENSOR_ERROR_SENSOR_MODULE_POWER_UP);
362 
363  return;
364  }
365 
366  self->_state = TWR_SOIL_SENSOR_STATE_INITIALIZE;
367 
369 
370  return;
371  }
372  case TWR_SOIL_SENSOR_STATE_INITIALIZE:
373  {
374  uint64_t device_address = 0;
375 
376  self->_sensor_found = 0;
377 
378  twr_onewire_transaction_start(self->_onewire);
379 
380  twr_onewire_reset(self->_onewire);
381 
382  twr_onewire_search_start(self->_onewire, 0x19);
383 
384  while ((self->_sensor_found < self->_sensor_count) && twr_onewire_search_next(self->_onewire, &device_address))
385  {
386  twr_ds28e17_init(&self->_sensor[self->_sensor_found]._ds28e17, self->_onewire, device_address);
387 
388  self->_sensor_found++;
389  }
390 
391  twr_onewire_transaction_stop(self->_onewire);
392 
393  if (self->_sensor_found == 0)
394  {
395  _twr_soil_sensor_error(self, TWR_SOIL_SENSOR_ERROR_NO_SENSOR_FOUND);
396 
397  return;
398  }
399 
400  twr_onewire_auto_ds28e17_sleep_mode(self->_onewire, false);
401 
402  for (int i = 0; i < self->_sensor_found; i++)
403  {
404  if (!_twr_soil_sensor_tmp112_init(&self->_sensor[i]._ds28e17))
405  {
406  _twr_soil_sensor_error(self, TWR_SOIL_SENSOR_ERROR_TMP112_INITIALIZE);
407 
408  return;
409  }
410  }
411 
412  for (int i = 0; i < self->_sensor_found; i++)
413  {
414  twr_soil_sensor_error_t error = _twr_soil_sensor_eeprom_load(&self->_sensor[i]);
415 
416  if (error)
417  {
419  {
420  _twr_soil_sensor_eeprom_fill(&self->_sensor[i]);
421 
422  continue;
423  }
424 
425  _twr_soil_sensor_error(self, error);
426 
427  return;
428  }
429  }
430 
431  for (int i = 0; i < self->_sensor_found; i++)
432  {
433  if (i + 1 == self->_sensor_found) // last sensor
434  {
435  twr_onewire_auto_ds28e17_sleep_mode(self->_onewire, true);
436  }
437 
438  _twr_soil_sensor_zssc3123_data_fetch(&self->_sensor[i]);
439 
440  self->_sensor[i]._cap_valid = false;
441  }
442 
443  self->_state = TWR_SOIL_SENSOR_STATE_READY;
444 
445  if (self->_measurement_active)
446  {
448  }
449 
450  return;
451  }
452  case TWR_SOIL_SENSOR_STATE_READY:
453  {
454  self->_state = TWR_SOIL_SENSOR_STATE_MEASURE;
455 
457 
458  return;
459  }
460  case TWR_SOIL_SENSOR_STATE_MEASURE:
461  {
462  twr_onewire_auto_ds28e17_sleep_mode(self->_onewire, false);
463 
464  for (int i = 0; i < self->_sensor_found; i++)
465  {
466  if (!_twr_soil_sensor_zssc3123_measurement_request(&self->_sensor[i]._ds28e17))
467  {
468  _twr_soil_sensor_error(self, TWR_SOIL_SENSOR_ERROR_ZSSC3123_MEASUREMENT_REQUEST);
469 
470  return;
471  }
472 
473  if (i + 1 == self->_sensor_found) // last sensor
474  {
475  twr_onewire_auto_ds28e17_sleep_mode(self->_onewire, true);
476  }
477 
478  if (!_twr_soil_sensor_tmp112_measurement_request(&self->_sensor[i]._ds28e17))
479  {
480  _twr_soil_sensor_error(self, TWR_SOIL_SENSOR_ERROR_TMP112_MEASUREMENT_REQUEST);
481 
482  return;
483  }
484 
485  }
486 
487  self->_state = TWR_SOIL_SENSOR_STATE_READ;
488 
490 
491  return;
492  }
493  case TWR_SOIL_SENSOR_STATE_READ:
494  {
495  twr_onewire_auto_ds28e17_sleep_mode(self->_onewire, false);
496 
497  for (int i = 0; i < self->_sensor_found; i++)
498  {
499  if (!_twr_soil_sensor_tmp112_data_fetch(&self->_sensor[i]))
500  {
501  _twr_soil_sensor_error(self, TWR_SOIL_SENSOR_ERROR_TMP112_DATA_FETCH);
502 
503  return;
504  }
505 
506  if (i + 1 == self->_sensor_found) // last sensor
507  {
508  twr_onewire_auto_ds28e17_sleep_mode(self->_onewire, true);
509  }
510 
511  if (!_twr_soil_sensor_zssc3123_data_fetch(&self->_sensor[i]))
512  {
513  _twr_soil_sensor_error(self, TWR_SOIL_SENSOR_ERROR_ZSSC3123_DATA_FETCH);
514 
515  return;
516  }
517  }
518 
519  self->_state = TWR_SOIL_SENSOR_STATE_UPDATE;
520 
522 
523  return;
524  }
525  case TWR_SOIL_SENSOR_STATE_UPDATE:
526  {
527  self->_measurement_active = false;
528 
529  self->_error = TWR_SOIL_SENSOR_ERROR_NONE;
530 
531  if (self->_event_handler != NULL)
532  {
533  for (int i = 0; i < self->_sensor_found; i++)
534  {
535  self->_event_handler(self, self->_sensor[i]._ds28e17._device_number, TWR_SOIL_SENSOR_EVENT_UPDATE, self->_event_param);
536  }
537  }
538 
539  self->_state = TWR_SOIL_SENSOR_STATE_READY;
540 
541  return;
542  }
543  default:
544  {
545  self->_state = TWR_SOIL_SENSOR_STATE_ERROR;
546 
547  return;
548  }
549  }
550 }
551 
552 static bool _twr_soil_sensor_tmp112_init(twr_ds28e17_t *ds28e17)
553 {
554  const uint8_t buffer[] = { 0x01, 0x80 };
555 
556  twr_i2c_memory_transfer_t memory_transfer = {
557  .device_address = _TWR_SOIL_SENSOR_TMP112_ADDRESS,
558  .memory_address = 0x01,
559  .buffer = (void *) buffer,
560  .length = sizeof(buffer)
561  };
562 
563  return twr_ds28e17_memory_write(ds28e17, &memory_transfer);
564 }
565 
566 static bool _twr_soil_sensor_tmp112_measurement_request(twr_ds28e17_t *ds28e17)
567 {
568  const uint8_t buffer[] = { 0x81 };
569 
570  twr_i2c_memory_transfer_t memory_transfer = {
571  .device_address = _TWR_SOIL_SENSOR_TMP112_ADDRESS,
572  .memory_address = 0x01,
573  .buffer = (void *) buffer,
574  .length = sizeof(buffer)
575  };
576 
577  return twr_ds28e17_memory_write(ds28e17, &memory_transfer);
578 }
579 
580 static bool _twr_soil_sensor_tmp112_data_fetch(twr_soil_sensor_sensor_t *sensor)
581 {
582  uint8_t buffer[2];
583 
584  twr_i2c_memory_transfer_t memory_transfer = {
585  .device_address = _TWR_SOIL_SENSOR_TMP112_ADDRESS,
586  .memory_address = 0x01,
587  .buffer = buffer,
588  .length = 1
589  };
590 
591  if (!twr_ds28e17_memory_read(&sensor->_ds28e17, &memory_transfer))
592  {
593  return false;
594  }
595 
596  if ((buffer[0] & 0x81) != 0x81)
597  {
598  return false;
599  }
600 
601  memory_transfer.memory_address = 0x00;
602  memory_transfer.length = 2;
603 
604  if (!twr_ds28e17_memory_read(&sensor->_ds28e17, &memory_transfer))
605  {
606  return false;
607  }
608 
609  sensor->_temperature_raw = (uint16_t) buffer[0] << 8 | buffer[1];
610  sensor->_temperature_valid = true;
611 
612  return true;
613 }
614 
615 static bool _twr_soil_sensor_zssc3123_measurement_request(twr_ds28e17_t *ds28e17)
616 {
617  const uint8_t buffer[] = { _TWR_SOIL_SENSOR_ZSSC3123_ADDRESS << 1 };
618 
619  twr_i2c_transfer_t transfer = {
620  .device_address = _TWR_SOIL_SENSOR_ZSSC3123_ADDRESS,
621  .buffer = (void *) buffer,
622  .length = sizeof(buffer)
623  };
624 
625  return twr_ds28e17_write(ds28e17, &transfer);
626 }
627 
628 static bool _twr_soil_sensor_zssc3123_data_fetch(twr_soil_sensor_sensor_t *sensor)
629 {
630  uint8_t buffer[2];
631 
632  twr_i2c_transfer_t transfer = {
633  .device_address = _TWR_SOIL_SENSOR_ZSSC3123_ADDRESS,
634  .buffer = buffer,
635  .length = sizeof(buffer)
636  };
637 
638  if (!twr_ds28e17_read(&sensor->_ds28e17, &transfer))
639  {
640  return false;
641  }
642 
643  if ((buffer[0] & 0xc0) == 0)
644  {
645  sensor->_cap_raw = (uint16_t) (buffer[0] & 0x3f) << 8 | buffer[1];
646 
647  sensor->_cap_valid = true;
648  }
649 
650  return true;
651 }
652 
653 static twr_soil_sensor_error_t _twr_soil_sensor_eeprom_load(twr_soil_sensor_sensor_t *sensor)
654 {
656 
657  if (!_twr_soil_sensor_eeprom_read(sensor, 0, &header, sizeof(header)))
658  {
660  }
661 
662  if (header.signature != 0xdeadbeef)
663  {
665  }
666 
667  if (header.version != 1)
668  {
670  }
671 
672  if (header.length != sizeof(twr_soil_sensor_eeprom_t))
673  {
675  }
676 
677  if (!_twr_soil_sensor_eeprom_read(sensor, sizeof(header), &sensor->_eeprom, sizeof(twr_soil_sensor_eeprom_t)))
678  {
680  }
681 
682  if (header.crc != twr_onewire_crc16(&sensor->_eeprom, sizeof(twr_soil_sensor_eeprom_t), 0))
683  {
685  }
686 
688 }
689 
690 static void _twr_soil_sensor_eeprom_fill(twr_soil_sensor_sensor_t *sensor)
691 {
692  sensor->_eeprom.product = 0;
693  sensor->_eeprom.revision = 0x0104;
694 
695  sensor->_eeprom.calibration[0] = 1700;
696  sensor->_eeprom.calibration[10] = 3000;
697 
698  uint16_t step = (sensor->_eeprom.calibration[10] - sensor->_eeprom.calibration[0]) / 11;
699 
700  for (int i = 1; i < 10; i++)
701  {
702  sensor->_eeprom.calibration[i] = sensor->_eeprom.calibration[i - 1] + step;
703  }
704 
705  memset(sensor->_eeprom.label, 0, sizeof(sensor->_eeprom.label));
706 }
707 
708 static bool _twr_soil_sensor_eeprom_save(twr_soil_sensor_sensor_t *sensor)
709 {
711  .signature = 0xdeadbeef,
712  .version = 1,
713  .length = sizeof(twr_soil_sensor_eeprom_t),
714  .crc = twr_onewire_crc16(&sensor->_eeprom, sizeof(twr_soil_sensor_eeprom_t), 0)
715  };
716 
717  if (!_twr_soil_sensor_eeprom_write(sensor, 0, &header, sizeof(header)))
718  {
719  return false;
720  }
721 
722  if (!_twr_soil_sensor_eeprom_write(sensor, sizeof(header), &sensor->_eeprom, sizeof(twr_soil_sensor_eeprom_t)))
723  {
724  return false;
725  }
726 
727  return true;
728 }
729 
730 static bool _twr_soil_sensor_eeprom_read(twr_soil_sensor_sensor_t *sensor, uint8_t address, void *buffer, size_t length)
731 {
732  uint8_t a[8];
733  uint8_t b[sizeof(a)];
734  uint8_t c[sizeof(a)];
735 
736  if ((_TWR_SOIL_SENSOR_EEPROM_BANK_A + address + length) >= _TWR_SOIL_SENSOR_EEPROM_BANK_B)
737  {
738  return false;
739  }
740 
741  twr_i2c_memory_transfer_t memory_transfer = {
742  .device_address = _TWR_SOIL_SENSOR_EEPROM_ADDRESS,
743  };
744 
745  size_t j = 0;
746  uint8_t *p = buffer;
747 
748  for (size_t i = 0; i < length; i += sizeof(a))
749  {
750  memory_transfer.length = length - i > sizeof(a) ? sizeof(a) : length - i;
751 
752  memory_transfer.memory_address = address + i + _TWR_SOIL_SENSOR_EEPROM_BANK_A;
753  memory_transfer.buffer = a;
754 
755  if (!twr_ds28e17_memory_read(&sensor->_ds28e17, &memory_transfer))
756  {
757  return false;
758  }
759 
760  memory_transfer.memory_address = address + i + _TWR_SOIL_SENSOR_EEPROM_BANK_B;
761  memory_transfer.buffer = b;
762 
763  if (!twr_ds28e17_memory_read(&sensor->_ds28e17, &memory_transfer))
764  {
765  return false;
766  }
767 
768  memory_transfer.memory_address = address + i + _TWR_SOIL_SENSOR_EEPROM_BANK_C;
769  memory_transfer.buffer = c;
770 
771  if (!twr_ds28e17_memory_read(&sensor->_ds28e17, &memory_transfer))
772  {
773  return false;
774  }
775 
776  for (j = 0; j < memory_transfer.length; j++)
777  {
778  *p++ = (a[j] & b[j]) | (a[j] & c[j]) | (b[j] & c[j]);
779  }
780  }
781 
782  return true;
783 }
784 
785 static bool _twr_soil_sensor_eeprom_write_chunk(twr_ds28e17_t *ds28e17, twr_i2c_memory_transfer_t *memory_transfer, void *test_buffer)
786 {
787  uint8_t *original_buffer = memory_transfer->buffer;
788 
789  for (int i = 0;; i++)
790  {
791  memory_transfer->buffer = test_buffer;
792 
793  if (!twr_ds28e17_memory_read(ds28e17, memory_transfer))
794  {
795  return false;
796  }
797 
798  memory_transfer->buffer = original_buffer;
799 
800  if (memcmp(original_buffer, test_buffer, memory_transfer->length) == 0)
801  {
802  return true;
803  }
804 
805  if (i > 3)
806  {
807  break;
808  }
809 
810  if (!twr_ds28e17_memory_write(ds28e17, memory_transfer))
811  {
812  return false;
813  }
814  }
815 
816  return false;
817 }
818 
819 static bool _twr_soil_sensor_eeprom_write(twr_soil_sensor_sensor_t *sensor, uint8_t address, const void *buffer, size_t length)
820 {
821  if ((_TWR_SOIL_SENSOR_EEPROM_BANK_A + address + length) >= _TWR_SOIL_SENSOR_EEPROM_BANK_B)
822  {
823  return false;
824  }
825 
826  twr_i2c_memory_transfer_t memory_transfer = {
827  .device_address = _TWR_SOIL_SENSOR_EEPROM_ADDRESS,
828  };
829 
830  uint8_t test[2];
831 
832  for (size_t i = 0; i < length; i += sizeof(test))
833  {
834  memory_transfer.length = length - i > sizeof(test) ? sizeof(test) : length - i;
835  memory_transfer.memory_address = address + i + _TWR_SOIL_SENSOR_EEPROM_BANK_A;
836  memory_transfer.buffer = (uint8_t *) buffer + i;
837 
838  if (!_twr_soil_sensor_eeprom_write_chunk(&sensor->_ds28e17, &memory_transfer, test))
839  {
840  return false;
841  }
842 
843  memory_transfer.memory_address = address + i + _TWR_SOIL_SENSOR_EEPROM_BANK_B;
844 
845  if (!_twr_soil_sensor_eeprom_write_chunk(&sensor->_ds28e17, &memory_transfer, test))
846  {
847  return false;
848  }
849 
850  memory_transfer.memory_address = address + i + _TWR_SOIL_SENSOR_EEPROM_BANK_C;
851 
852  if (!_twr_soil_sensor_eeprom_write_chunk(&sensor->_ds28e17, &memory_transfer, test))
853  {
854  return false;
855  }
856  }
857 
858  return true;
859 }
void twr_scheduler_plan_relative(twr_scheduler_task_id_t task_id, twr_tick_t tick)
Schedule specified task to tick relative from current spin.
uint32_t memory_address
8-bit I2C memory address (it can be extended to 16-bit format if OR-ed with TWR_I2C_MEMORY_ADDRESS_16...
Definition: twr_i2c.h:63
uint32_t signature
Signature 0xdeadbeef.
twr_soil_sensor_error_t twr_soil_sensor_get_error(twr_soil_sensor_t *self)
Get error number.
void twr_scheduler_plan_current_relative(twr_tick_t tick)
Schedule current task to tick relative from current spin.
uint64_t twr_soil_sensor_get_device_address_by_index(twr_soil_sensor_t *self, int index)
Get device device address by its index.
bool twr_module_sensor_onewire_power_down(void)
Semaphore for 1Wire Power down: for R1.1 set VDD Off, for R1.0 pull none on channel A...
uint8_t device_address
7-bit I2C device address
Definition: twr_i2c.h:45
bool twr_onewire_transaction_stop(twr_onewire_t *self)
Stop transaction.
Definition: twr_onewire.c:43
twr_scheduler_task_id_t twr_scheduler_register(void(*task)(void *), void *param, twr_tick_t tick)
Register task in scheduler.
Definition: twr_scheduler.c:53
bool twr_onewire_search_next(twr_onewire_t *self, uint64_t *device_number)
Manual search of next device.
Definition: twr_onewire.c:226
bool twr_module_sensor_init(void)
Initialize Sensor Module.
Sensor Module onewire power up error.
bool twr_soil_sensor_get_cap_raw(twr_soil_sensor_t *self, uint64_t device_address, uint16_t *raw)
Get capacite as raw value.
char * twr_soil_sensor_get_label(twr_soil_sensor_t *self, uint64_t device_address)
Get device label by its device address.
bool twr_soil_sensor_get_temperature_kelvin(twr_soil_sensor_t *self, uint64_t device_address, float *kelvin)
Get measured temperature in kelvin.
bool twr_onewire_transaction_start(twr_onewire_t *self)
Start transaction, enable pll and run timer.
Definition: twr_onewire.c:31
bool twr_soil_sensor_calibration_set_point(twr_soil_sensor_t *self, uint64_t device_address, uint8_t point, uint16_t value)
Set value for calibration point by device address.
I2C transfer parameters.
Definition: twr_i2c.h:42
void twr_soil_sensor_init(twr_soil_sensor_t *self)
Initialize Soil sensor.
bool twr_ds28e17_memory_write(twr_ds28e17_t *self, const twr_i2c_memory_transfer_t *transfer)
Memory write to I2C.
Definition: twr_ds28e17.c:82
void twr_soil_sensor_set_event_handler(twr_soil_sensor_t *self, void(*event_handler)(twr_soil_sensor_t *, uint64_t, twr_soil_sensor_event_t, void *), void *event_param)
Set callback function.
bool twr_soil_sensor_get_moisture(twr_soil_sensor_t *self, uint64_t device_address, int *moisture)
Get measured moisture in percent.
uint8_t version
Data Version.
Sensor Module initialize error.
void * buffer
Pointer to buffer which is being written or read.
Definition: twr_i2c.h:66
bool twr_soil_sensor_eeprom_save(twr_soil_sensor_t *self, uint64_t device_address)
Save calibration points and label to eeprom by device address.
struct twr_soil_sensor_t twr_soil_sensor_t
Soil sensor instance.
void twr_scheduler_plan_current_from_now(twr_tick_t tick)
Schedule current task to tick relative from now.
uint16_t twr_onewire_crc16(const void *buffer, size_t length, uint16_t crc)
Calculate 16-bit CRC, polynomial 0x8005.
Definition: twr_onewire.c:192
void twr_scheduler_plan_current_now(void)
Schedule current task for immediate execution.
bool twr_soil_sensor_get_temperature_fahrenheit(twr_soil_sensor_t *self, uint64_t device_address, float *fahrenheit)
Get measured temperature in degrees of Fahrenheit.
bool twr_module_sensor_onewire_power_up(void)
Semaphore for 1Wire Power up: for R1.1 set VDD On, for R1.0 pull up 56R on channel A...
I2C memory transfer parameters.
Definition: twr_i2c.h:57
void twr_onewire_search_start(twr_onewire_t *self, uint8_t family_code)
Start of manual search, see also twr_onewire_search_next.
Definition: twr_onewire.c:214
uint64_t twr_tick_t
Timestamp data type.
Definition: twr_tick.h:16
void twr_onewire_auto_ds28e17_sleep_mode(twr_onewire_t *self, bool on)
Enable call sleep mode for all ds28e17 after transaction.
Definition: twr_onewire.c:160
void twr_soil_sensor_set_update_interval(twr_soil_sensor_t *self, twr_tick_t interval)
Set measurement interval.
bool twr_ds28e17_memory_read(twr_ds28e17_t *self, const twr_i2c_memory_transfer_t *transfer)
Memory read from I2C.
Definition: twr_ds28e17.c:107
bool twr_soil_sensor_set_label(twr_soil_sensor_t *self, uint64_t device_address, const char *label)
Get device label by its device address.
twr_soil_sensor_event_t
Callback events.
twr_soil_sensor_error_t
Error numbers.
bool twr_soil_sensor_get_temperature_raw(twr_soil_sensor_t *self, uint64_t device_address, int16_t *raw)
Get measured temperature as raw value.
void twr_soil_sensor_init_multiple(twr_soil_sensor_t *self, twr_soil_sensor_sensor_t *sensors, int sensor_count)
Initialize multiple Soil sensor.
bool twr_soil_sensor_get_temperature_celsius(twr_soil_sensor_t *self, uint64_t device_address, float *celsius)
Get measured temperature in degrees of Celsius.
bool twr_ds28e17_write(twr_ds28e17_t *self, const twr_i2c_transfer_t *transfer)
Write to I2C.
Definition: twr_ds28e17.c:60
size_t length
Length of buffer which is being written or read.
Definition: twr_i2c.h:69
bool twr_onewire_reset(twr_onewire_t *self)
Reset the 1-Wire bus and return the presence of any device.
Definition: twr_onewire.c:55
bool twr_ds28e17_read(twr_ds28e17_t *self, const twr_i2c_transfer_t *transfer)
Read from I2C.
Definition: twr_ds28e17.c:71
void twr_ds28e17_init(twr_ds28e17_t *self, twr_onewire_t *onewire, uint64_t device_number)
Initialize DS28E17.
Definition: twr_ds28e17.c:14
int twr_soil_sensor_get_sensor_found(twr_soil_sensor_t *self)
Get sensors found.
#define TWR_TICK_INFINITY
Maximum timestamp value.
Definition: twr_tick.h:12
void twr_scheduler_plan_absolute(twr_scheduler_task_id_t task_id, twr_tick_t tick)
Schedule specified task to absolute tick.
void twr_scheduler_plan_now(twr_scheduler_task_id_t task_id)
Schedule specified task for immediate execution.
twr_onewire_t * twr_module_sensor_get_onewire(void)
Initialize and get Instance 1-Wire for channel B.
int twr_soil_sensor_get_index_by_device_address(twr_soil_sensor_t *self, uint64_t device_address)
Get device index by its device address.
uint8_t device_address
7-bit I2C device address
Definition: twr_i2c.h:60
DS28E17 instance.
Definition: twr_ds28e17.h:13
bool twr_soil_sensor_measure(twr_soil_sensor_t *self)
Start measurement manually.