1 /*
2  * Copyright (c) 2020, Texas Instruments Incorporated
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * *  Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * *  Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * *  Neither the name of Texas Instruments Incorporated nor the names of
17  *    its contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 /*!****************************************************************************
33  *  @file       Temperature.h
34  *
35  *  @brief      Temperature driver
36  *
37  *  @anchor ti_drivers_Temperature_Overview
38  *  # Overview #
39  *  The Temperature driver provides services related to measuring and reacting
40  *  to the current temperature of the chip and changes to it.
41  *
42  *  The two main services provided are:
43  *      - Getting the current temperature
44  *      - Providing notification callbacks when the temperature changes
45  *
46  *  @anchor ti_drivers_Temperature_Usage
47  *  # Usage #
48  *
49  *  ## Initialisation #
50  *  Unlike most drivers, there is only a single instance of the temperature
51  *  driver that is always available once #Temperature_init() is called.
52  *  #Temperature_init() should be called once before using other Temperature
53  *  driver APIs. Subsequent #Temperature_init() calls will have no effect.
54  *
55  *  ## Getting the Current Temperature #
56  *  The most basic function of the driver is to provide the current temperature
57  *  and return it. It is encoded as a signed integer in degrees C.
58  *
59  *  ## Notifications #
60  *  The other major function of the Temperature driver is to notify the
61  *  application when the temperature changes and crosses an application-defined
62  *  threshold.
63  *
64  *  There are three default usecases for this:
65  *      - High threshold.
66  *        The application will receive a notification callback when
67  *        currentTemperature >= thresholdHigh.
68  *      - Low threshold.
69  *        The application will receive a notification callback when
70  *        currentTemperature <= thresholdLow.
71  *      - Range threshold.
72  *        The application will receive a notification callback when
73  *        currentTemperature >= thresholdHigh || currentTemperature <=
74  *        thresholdLow. This setup addresses usecases
75  *        where a notification is required when the temperature changes by a
76  *        certain amount regardless of whether it is up or down. Adjusting
77  *        clock offsets based on temperature is a good example of this.
78  *
79  *  ### Registering Notifications
80  *  There are three functions that register a notification for the application:
81  *      - #Temperature_registerNotifyHigh()
82  *      - #Temperature_registerNotifyLow()
83  *      - #Temperature_registerNotifyRange()
84  *
85  *  Multiple notifications may be registered. The different parts of the
86  *  application and drivers that need to respond to a temperature change do not
87  *  need to know of one another.
88  *  Each notification must have its own #Temperature_NotifyObj and must be
89  *  registered individually.
90  *
91  *  ### Notification Callbacks
92  *  Once the chip temperature crosses the smallest high threshold or largest
93  *  low threshold amongst the registered notifications, the driver will
94  *  iterate over the entire list of registered notification and check which
95  *  ones have triggered. Notifications that have triggered are removed from
96  *  the list of registered notifications and thus are no longer registered.
97  *  Their callback function is then invoked.
98  *
99  *  If an application wishes to reregister a notification that just triggered
100  *  and was unregistered, it may register it again from within the notification
101  *  callback or another context.
102  *
103  *  It is possible to determine whether the high or low threshold triggered
104  *  the notification callback as follows:
105  *      - currentTemperature <= thresholdTemperature: Low threshold triggered
106  *      - currentTemperature >= thresholdTemperature: High threshold triggered
107  *  This information is only reasonably useful when registering a notification
108  *  with both a high and low threshold using #Temperature_registerNotifyRange().
109  *  Even then, the expected basic usecase only cares about the current
110  *  temperature and adding an offset to it when registering the notification
111  *  again.
112  *
113  *  ### Unregistering Notifications
114  *  Registered notifications are unregistered in two ways:
115  *      - Automatically when a notification triggers
116  *      - By calling #Temperature_unregisterNotify()
117  *
118  *  Unregistered notifications may be registered again at any time.
119  *
120  *  # Measured vs True Temperature
121  *  While the driver aims to supply and act on an accurate absolute temperature,
122  *  there will be differences between the measured vs the true temperature due
123  *  to inherent variances in the manufacturing process. The nature of these
124  *  differences varies by device family.
125  *
126  *  Examples of such differences:
127  *      - A constant per-chip offset between the measured and the true
128  *        temperature
129  *      - An temperature dependent per-chip offset between the measured and the
130  *        true temperature
131  *      - A variance in the measured temperature when measuring multiple times
132  *        at the same chip temperature
133  *
134  *  It is strongly recommended to read the device-specific Temperature driver
135  *  documentation for details of the temperature sensor characteristics and
136  *  how they might affect choices of threshold values.
137  *
138  *  @anchor ti_drivers_Temperature_Synopsis
139  *  # Synopsis #
140  *  @anchor ti_drivers_Temperature_Synopsis_Code
141  *  @code
142  *  #include <ti/drivers/Temperature.h>
143  *
144  *  #define WINDOW_DELTA 10
145  *
146  *  Temperature_init();
147  *
148  *  currentTemperature = Temperature_getTemperature();
149  *
150  *  result = Temperature_registerNotifyRange(&notifyObject,
151  *                                           currentTemperature + WINDOW_DELTA,
152  *                                           currentTemperature - WINDOW_DELTA,
153  *                                           myNotifyFxn,
154  *                                           clientArg);
155  *  @endcode
156  *
157  *  @anchor ti_drivers_Temperature_Examples
158  *  # Examples #
159  *
160  *  ## Register a High Threshold Notification #
161  *
162  *  @code
163  *
164  *  // The notification will trigger when the temperature reaches 40 C
165  *  #define THRESHOLD_CUTOFF 40
166  *
167  *  #include <ti/drivers/Temperature.h>
168  *
169  *  void thresholdNotifyFxn(int16_t currentTemperature,
170  *                          int16_t thresholdTemperature,
171  *                          uintptr_t clientArg,
172  *                          Temperature_NotifyObj *notifyObject) {
173  *     // Post a semaphore, set a flag, or otherwise act upon the temperature
174  *     // change.
175  *  }
176  *
177  *  ...
178  *
179  *  // Initialize the Temperature driver and register a notification.
180  *
181  *  Temperature_init();
182  *
183  *  int_fast16_t status = Temperature_registerNotifyHigh(notifyObject,
184  *                                                       THRESHOLD_CUTOFF,
185  *                                                       thresholdNotifyFxn,
186  *                                                       NULL);
187  *
188  *  if (status != Temperature_STATUS_SUCCESS) {
189  *      // Handle error
190  *  }
191  *
192  *  @endcode
193  *
194  *  ## Register a Range Threshold Notification and Reregister in Callback #
195  *
196  *  @code
197  *
198  *  #define THRESHOLD_DELTA 5
199  *
200  *  #include <ti/drivers/Temperature.h>
201  *
202  *
203  *  void deltaNotificationFxn(int16_t currentTemperature,
204  *                        int16_t thresholdTemperature,
205  *                        uintptr_t clientArg,
206  *                        Temperature_NotifyObj *notifyObject) {
207  *      int_fast16_t status;
208  *
209  *      status = Temperature_registerNotifyRange(notifyObject,
210  *                                               currentTemperature + THRESHOLD_DELTA,
211  *                                               currentTemperature - THRESHOLD_DELTA,
212  *                                               deltaNotificationFxn,
213  *                                               NULL);
214  *
215  *      if (status != Temperature_STATUS_SUCCESS) {
216  *          while(1);
217  *      }
218  *  }
219  *
220  *   ...
221  *
222  *  // Initialize the Temperature driver and register a notification.
223  *
224  *  Temperature_init();
225  *
226  *  int16_t currentTemperature = Temperature_getTemperature();
227  *
228  *  int_fast16_t status = Temperature_registerNotifyRange(notifyObject,
229  *                                                        currentTemperature + THRESHOLD_DELTA,
230  *                                                        currentTemperature - THRESHOLD_DELTA,
231  *                                                        deltaNotificationFxn,
232  *                                                        NULL);
233  *  @endcode
234  */
235 
236 #ifndef ti_drivers_Temperature__include
237 #define ti_drivers_Temperature__include
238 
239 #include <stdbool.h>
240 #include <stddef.h>
241 #include <stdint.h>
242 
243 #include <ti/drivers/utils/List.h>
244 
245 #ifdef __cplusplus
246 extern "C" {
247 #endif
248 
249 /*!
250  * Common Temperature status code reservation offset.
251  * Temperature driver implementations should offset status codes with
252  * Temperature_STATUS_RESERVED growing negatively.
253  *
254  * Example implementation specific status codes:
255  * @code
256  * #define TemperatureXYZ_STATUS_ERROR0    Temperature_STATUS_RESERVED - 0
257  * #define TemperatureXYZ_STATUS_ERROR1    Temperature_STATUS_RESERVED - 1
258  * #define TemperatureXYZ_STATUS_ERROR2    Temperature_STATUS_RESERVED - 2
259  * @endcode
260  */
261 #define Temperature_STATUS_RESERVED        (-32)
262 
263 /*!
264  * @brief   Successful status code.
265  *
266  * Functions return Temperature_STATUS_SUCCESS if the function was executed
267  * successfully.
268  */
269 #define Temperature_STATUS_SUCCESS         (0)
270 
271 /*!
272  * @brief   Generic error status code.
273  *
274  * Functions return Temperature_STATUS_ERROR if the function was not executed
275  * successfully.
276  */
277 #define Temperature_STATUS_ERROR           (-1)
278 
279 
280 /* @cond
281  *
282  * Type declaration for the notification object made separately from the
283  * struct definition because of the circular dependency between
284  * #Temperature_NotifyFxn() and #Temperature_NotifyObj.
285  */
286 typedef struct Temperature_NotifyObj Temperature_NotifyObj;
287 /* @endcond */
288 
289 /*!
290  *  @brief Function prototype for a notification callback.
291  *
292  *  @param [in]     currentTemperature      Current chip temperature
293  *
294  *  @param [in]     thresholdTemperature    Temperature threshold that caused
295  *                                          this notification callback.
296  *
297  *  @param [in]     clientArg               Argument provided by the application
298  *                                          during registration.
299  *
300  *  @param [in/out] notifyObject            The notification object that was
301  *                                          registered previously. This pointer
302  *                                          may be used to register the
303  *                                          notification again with updated
304  *                                          inputs from within the notification
305  *                                          callback.
306  */
307 typedef void (*Temperature_NotifyFxn) (int16_t currentTemperature,
308                                        int16_t thresholdTemperature,
309                                        uintptr_t clientArg,
310                                        Temperature_NotifyObj *notifyObject);
311 
312 /*!
313  *  @brief Temperature notify object structure.
314  *
315  *  This structure specification is for internal use. Notification clients must
316  *  pre-allocate a notify object when registering for a notification;
317  *  #Temperature_registerNotifyHigh(), #Temperature_registerNotifyLow(),
318  *  or #Temperature_registerNotifyRange() will take care initializing the
319  *  internal elements appropriately.
320  */
321 struct Temperature_NotifyObj {
322     List_Elem link;                     /*!< For placing on the notify list */
323     Temperature_NotifyFxn notifyFxn;    /*!< Application callback function */
324     int16_t thresholdHigh;              /*!< High threshold in degrees C */
325     int16_t thresholdLow;               /*!< Low threshold in degrees C */
326     uintptr_t clientArg;                /*!< Application provided arg */
327     bool isRegistered;                  /*!< Is the notification active */
328 };
329 
330 
331 /*!
332  *  @brief This function initializes the Temperature driver.
333  *
334  *  This function initializes the internal state of the Temperature driver.
335  *  It must be called before calling any other Temperature functions. Calling
336  *  this function multiple times will only have an effect the first time.
337  */
338 void Temperature_init();
339 
340 /*!
341  *  @brief Gets the current temperature in degrees C.
342  *
343  *  @return Current temperature in degrees C
344  */
345 int16_t Temperature_getTemperature(void);
346 
347 /*!
348  *  @brief Registers a notification with a high threshold.
349  *
350  *  This function registers a Temperature notification with a high threshold.
351  *  Once the chip temperature rises above @c thresholdHigh, @c notifyFxn is
352  *  called and the notification is automatically unregistered.
353  *
354  *  @param  notifyObject        Structure to be initialized. After returning,
355  *                              it will contain the data necessary to issue a
356  *                              notification callback. The memory of the
357  *                              structure must persist while the notification
358  *                              is registered.
359  *
360  *  @param  [in] thresholdHigh  Threshold temperature in degrees C
361  *
362  *  @param  [in] notifyFxn      Callback function that is called once the
363  *                              chip temperature rises above
364  *                              @c thresholdHigh.
365  *
366  *  @param  [in] clientArg      Application-specified argument
367  *
368  *  @retval #Temperature_STATUS_SUCCESS The notification was successfully
369  *                                      registered.
370  *  @retval #Temperature_STATUS_ERROR   There was an error during registration.
371  *
372  *  @pre Temperature_init() called
373  */
374 int_fast16_t Temperature_registerNotifyHigh(Temperature_NotifyObj *notifyObject,
375                                             int16_t thresholdHigh,
376                                             Temperature_NotifyFxn notifyFxn,
377                                             uintptr_t clientArg);
378 
379 /*!
380  *  @brief Registers a notification with a low threshold.
381  *
382  *  This function registers a Temperature notification with a low threshold.
383  *  Once the chip temperature falls below @c thresholdLow, @c notifyFxn is
384  *  called and the notification is automatically unregistered.
385  *
386  *  @param  notifyObject        Structure to be initialized. After returning,
387  *                              it will contain the data necessary to issue a
388  *                              notification callback. The memory of the
389  *                              structure must persist while the notification
390  *                              is registered.
391  *
392  *  @param  [in] thresholdLow   Threshold temperature in degrees C
393  *
394  *  @param  [in] notifyFxn      Callback function that is called once the
395  *                              chip temperature falls below
396  *                              @c thresholdLow.
397  *
398  *  @param  [in] clientArg      Application-specified argument
399  *
400  *  @retval #Temperature_STATUS_SUCCESS The notification was successfully
401  *                                      registered.
402  *  @retval #Temperature_STATUS_ERROR   There was an error during registration.
403  *
404  *  @pre Temperature_init() called
405  */
406 int_fast16_t Temperature_registerNotifyLow(Temperature_NotifyObj *notifyObject,
407                                            int16_t thresholdLow,
408                                            Temperature_NotifyFxn notifyFxn,
409                                            uintptr_t clientArg);
410 
411 /*!
412  *  @brief Registers a notification with both a high and low threshold.
413  *
414  *  This function registers a Temperature notification with a high and low
415  *  threshold. Once the chip temperature rises above @c thresholdHigh or
416  *  falls below @c thresholdLow, @c notifyFxn is called and the notification is
417  *  automatically unregistered.
418  *
419  *  @param  notifyObject        Structure to be initialized. After returning,
420  *                              it will contain the data necessary to issue a
421  *                              notification callback. The memory of the
422  *                              structure must persist while the notification
423  *                              is registered.
424  *
425  *  @param  [in] thresholdHigh  High threshold temperature in degrees C
426  *
427  *  @param  [in] thresholdLow   Low threshold temperature in degrees C
428  *
429  *  @param  [in] notifyFxn      Callback function that is called once the
430  *                              chip temperature falls below
431  *                              @c thresholdLow, or rises above
432  *                              @c thresholdHigh.
433  *
434  *  @param  [in] clientArg      Application-specified argument
435  *
436  *  @retval #Temperature_STATUS_SUCCESS The notification was successfully
437  *                                      registered
438  *  @retval #Temperature_STATUS_ERROR   There was an error during registration
439  *
440  *  @pre Temperature_init() called
441  */
442 int_fast16_t Temperature_registerNotifyRange(Temperature_NotifyObj *notifyObject,
443                                              int16_t thresholdHigh,
444                                              int16_t thresholdLow,
445                                              Temperature_NotifyFxn notifyFxn,
446                                              uintptr_t clientArg);
447 
448 
449 /*!
450  *  @brief Unregisters a currently registered notification.
451  *
452  *  This function unregisters a currently registered notification. It should not
453  *  be called on a @c notifyObject that is not currently registered.
454  *
455  *  @param  notifyObject    Notification to unregister.
456  *
457  *  @retval #Temperature_STATUS_SUCCESS The notification was successfully
458  *                                      unregistered.
459  *  @retval #Temperature_STATUS_ERROR   There was an error during
460  *                                      unregistration.
461  *
462  *  @pre Register @c notifyObject with #Temperature_registerNotifyHigh(),
463  *       #Temperature_registerNotifyLow(), or #Temperature_registerNotifyRange()
464  */
465 int_fast16_t Temperature_unregisterNotify(Temperature_NotifyObj *notifyObject);
466 
467 /*!
468  *  @brief Get the high threshold of a notification.
469  *
470  *  This function should not be called on a @c notifyObject registered with
471  *  #Temperature_registerNotifyLow(). The high threshold value returned in
472  *  that case will be a device-specific invalid temperature.
473  *
474  *  @param  notifyObject    Notification to get the high threshold of.
475  *
476  *  @return High threshold in degrees C.
477  *
478  *  @pre Register @c notifyObject with #Temperature_registerNotifyHigh(),
479  *       or #Temperature_registerNotifyRange()
480  */
481 int16_t Temperature_getThresholdHigh(Temperature_NotifyObj *notifyObject);
482 
483 /*!
484  *  @brief Get the low threshold of a notification.
485  *
486  *  This function should not be called on a @c notifyObject registered with
487  *  #Temperature_registerNotifyHigh(). The low threshold value returned in
488  *  that case will be a device-specific invalid temperature.
489  *
490  *  @param  notifyObject Notification to get the low threshold of.
491  *
492  *  @return Low threshold in degrees C.
493  *
494  *  @pre Register @c notifyObject with #Temperature_registerNotifyLow(),
495  *       or #Temperature_registerNotifyRange()
496  */
497 int16_t Temperature_getThresholdLow(Temperature_NotifyObj *notifyObject);
498 
499 /*!
500  *  @brief Get the high and low threshold of a notification.
501  *
502  *  This function should not be called on a @c notifyObject registered with
503  *  #Temperature_registerNotifyLow() or #Temperature_registerNotifyHigh().
504  *  The unconfigured threshold value returned in that case will be a
505  *  device-specific invalid temperature.
506  *
507  *  @param  notifyObject Notification to get the high and low threshold of.
508  *
509  *  @param [out]    thresholdHigh High threshold value in degrees C written back
510  *                                by this function.
511  *
512  *  @param [out]    thresholdLow  Low threshold value in degrees C written back
513  *                                by this function.
514  *
515  *  @pre Register @c notifyObject with #Temperature_registerNotifyRange()
516  */
517 void Temperature_getThresholdRange(Temperature_NotifyObj *notifyObject,
518                                    int16_t *thresholdHigh,
519                                    int16_t *thresholdLow);
520 
521 /*!
522  *  @brief Get the application-provided clientArg of a notification.
523  *
524  *  @param  notifyObject Notification to get the clientArg of.
525  *
526  *  @return The clientArg provided during registration.
527  *
528  *  @pre Register @c notifyObject with #Temperature_registerNotifyHigh(),
529  *       #Temperature_registerNotifyLow(), or #Temperature_registerNotifyRange()
530  */
531 uintptr_t Temperature_getClientArg(Temperature_NotifyObj *notifyObject);
532 
533 /*!
534  *  @brief Get the notifyFxn provided during registration.
535  *
536  *  @param  notifyObject Notification to get the notifyFxn of.
537  *
538  *  @return The notifyFxn provided during registration
539  *
540  *  @pre Register @c notifyObject with #Temperature_registerNotifyHigh(),
541  *       #Temperature_registerNotifyLow(), or #Temperature_registerNotifyRange()
542  */
543 Temperature_NotifyFxn Temperature_getNotifyFxn(Temperature_NotifyObj *notifyObject);
544 
545 
546 #ifdef __cplusplus
547 }
548 #endif
549 
550 #endif /* ti_drivers_Temperature__include */
551