1 /*
2  * Copyright (c) 2020-2024, 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. It is not called automatically via SysConfig generated code.
54  *  Subsequent #Temperature_init() calls will have no effect.
55  *
56  *  ## Getting the Current Temperature #
57  *  The most basic function of the driver is to provide the current temperature
58  *  and return it. It is encoded as a signed integer in degrees C.
59  *
60  *  ## Notifications #
61  *  The other major function of the Temperature driver is to notify the
62  *  application when the temperature changes and crosses an application-defined
63  *  threshold.
64  *
65  *  There are three default usecases for this:
66  *      - High threshold.
67  *        The application will receive a notification callback when
68  *        currentTemperature >= thresholdHigh.
69  *      - Low threshold.
70  *        The application will receive a notification callback when
71  *        currentTemperature <= thresholdLow.
72  *      - Range threshold.
73  *        The application will receive a notification callback when
74  *        currentTemperature >= thresholdHigh || currentTemperature <=
75  *        thresholdLow. This setup addresses usecases
76  *        where a notification is required when the temperature changes by a
77  *        certain amount regardless of whether it is up or down. Adjusting
78  *        clock offsets based on temperature is a good example of this.
79  *
80  *  ### Registering Notifications
81  *  There are three functions that register a notification for the application:
82  *      - #Temperature_registerNotifyHigh()
83  *      - #Temperature_registerNotifyLow()
84  *      - #Temperature_registerNotifyRange()
85  *
86  *  Multiple notifications may be registered. The different parts of the
87  *  application and drivers that need to respond to a temperature change do not
88  *  need to know of one another.
89  *  Each notification must have its own #Temperature_NotifyObj and must be
90  *  registered individually.
91  *
92  *  ### Notification Callbacks
93  *  Once the chip temperature crosses the smallest high threshold or largest
94  *  low threshold amongst the registered notifications, the driver will
95  *  iterate over the entire list of registered notification and check which
96  *  ones have triggered. Notifications that have triggered are removed from
97  *  the list of registered notifications and thus are no longer registered.
98  *  Their callback function is then invoked.
99  *
100  *  If an application wishes to re-register a notification that just triggered
101  *  and was unregistered, it may register it again from within the notification
102  *  callback or another context.
103  *
104  *  It is possible to determine whether the high or low threshold triggered
105  *  the notification callback as follows:
106  *      - currentTemperature <= thresholdTemperature: Low threshold triggered
107  *      - currentTemperature >= thresholdTemperature: High threshold triggered
108  *  This information is only reasonably useful when registering a notification
109  *  with both a high and low threshold using #Temperature_registerNotifyRange().
110  *  Even then, the expected basic usecase only cares about the current
111  *  temperature and adding an offset to it when registering the notification
112  *  again.
113  *
114  *  ### Unregistering Notifications
115  *  Registered notifications are unregistered in two ways:
116  *      - Automatically when a notification triggers
117  *      - By calling #Temperature_unregisterNotify()
118  *
119  *  Unregistered notifications may be registered again at any time.
120  *
121  *  # Measured vs True Temperature
122  *  While the driver aims to supply and act on an accurate absolute temperature,
123  *  there will be differences between the measured vs the true temperature due
124  *  to inherent variances in the manufacturing process. The nature of these
125  *  differences varies by device family.
126  *
127  *  Examples of such differences:
128  *      - A constant per-chip offset between the measured and the true
129  *        temperature
130  *      - An temperature dependent per-chip offset between the measured and the
131  *        true temperature
132  *      - A variance in the measured temperature when measuring multiple times
133  *        at the same chip temperature
134  *
135  *  It is strongly recommended to read the device-specific Temperature driver
136  *  documentation for details of the temperature sensor characteristics and
137  *  how they might affect choices of threshold values.
138  *
139  *  @anchor ti_drivers_Temperature_Synopsis
140  *  # Synopsis #
141  *  @anchor ti_drivers_Temperature_Synopsis_Code
142  *  @code
143  *  #include <ti/drivers/Temperature.h>
144  *
145  *  #define WINDOW_DELTA 10
146  *
147  *  Temperature_init();
148  *
149  *  currentTemperature = Temperature_getTemperature();
150  *
151  *  result = Temperature_registerNotifyRange(&notifyObject,
152  *                                           currentTemperature + WINDOW_DELTA,
153  *                                           currentTemperature - WINDOW_DELTA,
154  *                                           myNotifyFxn,
155  *                                           clientArg);
156  *  @endcode
157  *
158  *  @anchor ti_drivers_Temperature_Examples
159  *  # Examples #
160  *
161  *  ## Register a High Threshold Notification #
162  *
163  *  @code
164  *
165  *  // The notification will trigger when the temperature reaches 40 C
166  *  #define THRESHOLD_CUTOFF 40
167  *
168  *  #include <ti/drivers/Temperature.h>
169  *
170  *  void thresholdNotifyFxn(int16_t currentTemperature,
171  *                          int16_t thresholdTemperature,
172  *                          uintptr_t clientArg,
173  *                          Temperature_NotifyObj *notifyObject) {
174  *     // Post a semaphore, set a flag, or otherwise act upon the temperature
175  *     // change.
176  *  }
177  *
178  *  ...
179  *
180  *  // Initialize the Temperature driver and register a notification.
181  *
182  *  Temperature_init();
183  *
184  *  int_fast16_t status = Temperature_registerNotifyHigh(notifyObject,
185  *                                                       THRESHOLD_CUTOFF,
186  *                                                       thresholdNotifyFxn,
187  *                                                       NULL);
188  *
189  *  if (status != Temperature_STATUS_SUCCESS) {
190  *      // Handle error
191  *  }
192  *
193  *  @endcode
194  *
195  *  ## Register a Range Threshold Notification and Re-register in Callback #
196  *
197  *  @code
198  *
199  *  #define THRESHOLD_DELTA 5
200  *
201  *  #include <ti/drivers/Temperature.h>
202  *
203  *
204  *  void deltaNotificationFxn(int16_t currentTemperature,
205  *                        int16_t thresholdTemperature,
206  *                        uintptr_t clientArg,
207  *                        Temperature_NotifyObj *notifyObject) {
208  *      int_fast16_t status;
209  *
210  *      status = Temperature_registerNotifyRange(notifyObject,
211  *                                               currentTemperature + THRESHOLD_DELTA,
212  *                                               currentTemperature - THRESHOLD_DELTA,
213  *                                               deltaNotificationFxn,
214  *                                               NULL);
215  *
216  *      if (status != Temperature_STATUS_SUCCESS) {
217  *          while(1);
218  *      }
219  *  }
220  *
221  *   ...
222  *
223  *  // Initialize the Temperature driver and register a notification.
224  *
225  *  Temperature_init();
226  *
227  *  int16_t currentTemperature = Temperature_getTemperature();
228  *
229  *  int_fast16_t status = Temperature_registerNotifyRange(notifyObject,
230  *                                                        currentTemperature + THRESHOLD_DELTA,
231  *                                                        currentTemperature - THRESHOLD_DELTA,
232  *                                                        deltaNotificationFxn,
233  *                                                        NULL);
234  *  @endcode
235  */
236 
237 #ifndef ti_drivers_Temperature__include
238 #define ti_drivers_Temperature__include
239 
240 #include <stdbool.h>
241 #include <stddef.h>
242 #include <stdint.h>
243 
244 #include <ti/drivers/utils/List.h>
245 
246 #ifdef __cplusplus
247 extern "C" {
248 #endif
249 
250 /*!
251  * Common Temperature status code reservation offset.
252  * Temperature driver implementations should offset status codes with
253  * Temperature_STATUS_RESERVED growing negatively.
254  *
255  * Example implementation specific status codes:
256  * @code
257  * #define TemperatureXYZ_STATUS_ERROR0    Temperature_STATUS_RESERVED - 0
258  * #define TemperatureXYZ_STATUS_ERROR1    Temperature_STATUS_RESERVED - 1
259  * #define TemperatureXYZ_STATUS_ERROR2    Temperature_STATUS_RESERVED - 2
260  * @endcode
261  */
262 #define Temperature_STATUS_RESERVED (-32)
263 
264 /*!
265  * @brief   Successful status code.
266  *
267  * Functions return Temperature_STATUS_SUCCESS if the function was executed
268  * successfully.
269  */
270 #define Temperature_STATUS_SUCCESS (0)
271 
272 /*!
273  * @brief   Generic error status code.
274  *
275  * Functions return Temperature_STATUS_ERROR if the function was not executed
276  * successfully.
277  */
278 #define Temperature_STATUS_ERROR (-1)
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 {
323     List_Elem link;                  /*!< For placing on the notify list */
324     Temperature_NotifyFxn notifyFxn; /*!< Application callback function */
325     int16_t thresholdHigh;           /*!< High threshold in degrees C */
326     int16_t thresholdLow;            /*!< Low threshold in degrees C */
327     uintptr_t clientArg;             /*!< Application provided arg */
328     bool isRegistered;               /*!< Is the notification active */
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  *  @note This function should be called manually before using the temperature API.
339  *  It will not be called automatically via SysConfig generated code.
340  */
341 void Temperature_init(void);
342 
343 /*!
344  *  @brief Gets the current temperature in degrees C.
345  *
346  *  @return Current temperature in degrees C
347  */
348 int16_t Temperature_getTemperature(void);
349 
350 /*!
351  *  @brief Registers a notification with a high threshold.
352  *
353  *  This function registers a Temperature notification with a high threshold.
354  *  Once the chip temperature rises above @c thresholdHigh, @c notifyFxn is
355  *  called and the notification is automatically unregistered.
356  *
357  *  @param  notifyObject        Structure to be initialized. After returning,
358  *                              it will contain the data necessary to issue a
359  *                              notification callback. The memory of the
360  *                              structure must persist while the notification
361  *                              is registered.
362  *
363  *  @param  [in] thresholdHigh  Threshold temperature in degrees C
364  *
365  *  @param  [in] notifyFxn      Callback function that is called once the
366  *                              chip temperature rises above
367  *                              @c thresholdHigh.
368  *
369  *  @param  [in] clientArg      Application-specified argument
370  *
371  *  @retval #Temperature_STATUS_SUCCESS The notification was successfully
372  *                                      registered.
373  *  @retval #Temperature_STATUS_ERROR   There was an error during registration.
374  *
375  *  @pre Temperature_init() called
376  */
377 int_fast16_t Temperature_registerNotifyHigh(Temperature_NotifyObj *notifyObject,
378                                             int16_t thresholdHigh,
379                                             Temperature_NotifyFxn notifyFxn,
380                                             uintptr_t clientArg);
381 
382 /*!
383  *  @brief Registers a notification with a low threshold.
384  *
385  *  This function registers a Temperature notification with a low threshold.
386  *  Once the chip temperature falls below @c thresholdLow, @c notifyFxn is
387  *  called and the notification is automatically unregistered.
388  *
389  *  @param  notifyObject        Structure to be initialized. After returning,
390  *                              it will contain the data necessary to issue a
391  *                              notification callback. The memory of the
392  *                              structure must persist while the notification
393  *                              is registered.
394  *
395  *  @param  [in] thresholdLow   Threshold temperature in degrees C
396  *
397  *  @param  [in] notifyFxn      Callback function that is called once the
398  *                              chip temperature falls below
399  *                              @c thresholdLow.
400  *
401  *  @param  [in] clientArg      Application-specified argument
402  *
403  *  @retval #Temperature_STATUS_SUCCESS The notification was successfully
404  *                                      registered.
405  *  @retval #Temperature_STATUS_ERROR   There was an error during registration.
406  *
407  *  @pre Temperature_init() called
408  */
409 int_fast16_t Temperature_registerNotifyLow(Temperature_NotifyObj *notifyObject,
410                                            int16_t thresholdLow,
411                                            Temperature_NotifyFxn notifyFxn,
412                                            uintptr_t clientArg);
413 
414 /*!
415  *  @brief Registers a notification with both a high and low threshold.
416  *
417  *  This function registers a Temperature notification with a high and low
418  *  threshold. Once the chip temperature rises above @c thresholdHigh or
419  *  falls below @c thresholdLow, @c notifyFxn is called and the notification is
420  *  automatically unregistered.
421  *
422  *  @param  notifyObject        Structure to be initialized. After returning,
423  *                              it will contain the data necessary to issue a
424  *                              notification callback. The memory of the
425  *                              structure must persist while the notification
426  *                              is registered.
427  *
428  *  @param  [in] thresholdHigh  High threshold temperature in degrees C
429  *
430  *  @param  [in] thresholdLow   Low threshold temperature in degrees C
431  *
432  *  @param  [in] notifyFxn      Callback function that is called once the
433  *                              chip temperature falls below
434  *                              @c thresholdLow, or rises above
435  *                              @c thresholdHigh.
436  *
437  *  @param  [in] clientArg      Application-specified argument
438  *
439  *  @retval #Temperature_STATUS_SUCCESS The notification was successfully
440  *                                      registered
441  *  @retval #Temperature_STATUS_ERROR   There was an error during registration
442  *
443  *  @pre Temperature_init() called
444  */
445 int_fast16_t Temperature_registerNotifyRange(Temperature_NotifyObj *notifyObject,
446                                              int16_t thresholdHigh,
447                                              int16_t thresholdLow,
448                                              Temperature_NotifyFxn notifyFxn,
449                                              uintptr_t clientArg);
450 
451 /*!
452  *  @brief Unregisters a currently registered notification.
453  *
454  *  This function unregisters a currently registered notification. It should not
455  *  be called on a @c notifyObject that is not currently registered.
456  *
457  *  @param  notifyObject    Notification to unregister.
458  *
459  *  @retval #Temperature_STATUS_SUCCESS The notification was successfully
460  *                                      unregistered.
461  *  @retval #Temperature_STATUS_ERROR   There was an error during
462  *                                      unregistration.
463  *
464  *  @pre Register @c notifyObject with #Temperature_registerNotifyHigh(),
465  *       #Temperature_registerNotifyLow(), or #Temperature_registerNotifyRange()
466  */
467 int_fast16_t Temperature_unregisterNotify(Temperature_NotifyObj *notifyObject);
468 
469 /*!
470  *  @brief Get the high threshold of a notification.
471  *
472  *  This function should not be called on a @c notifyObject registered with
473  *  #Temperature_registerNotifyLow(). The high threshold value returned in
474  *  that case will be a device-specific invalid temperature.
475  *
476  *  @param  notifyObject    Notification to get the high threshold of.
477  *
478  *  @return High threshold in degrees C.
479  *
480  *  @pre Register @c notifyObject with #Temperature_registerNotifyHigh(),
481  *       or #Temperature_registerNotifyRange()
482  */
483 int16_t Temperature_getThresholdHigh(Temperature_NotifyObj *notifyObject);
484 
485 /*!
486  *  @brief Get the low threshold of a notification.
487  *
488  *  This function should not be called on a @c notifyObject registered with
489  *  #Temperature_registerNotifyHigh(). The low threshold value returned in
490  *  that case will be a device-specific invalid temperature.
491  *
492  *  @param  notifyObject Notification to get the low threshold of.
493  *
494  *  @return Low threshold in degrees C.
495  *
496  *  @pre Register @c notifyObject with #Temperature_registerNotifyLow(),
497  *       or #Temperature_registerNotifyRange()
498  */
499 int16_t Temperature_getThresholdLow(Temperature_NotifyObj *notifyObject);
500 
501 /*!
502  *  @brief Get the high and low threshold of a notification.
503  *
504  *  This function should not be called on a @c notifyObject registered with
505  *  #Temperature_registerNotifyLow() or #Temperature_registerNotifyHigh().
506  *  The unconfigured threshold value returned in that case will be a
507  *  device-specific invalid temperature.
508  *
509  *  @param  notifyObject Notification to get the high and low threshold of.
510  *
511  *  @param [out]    thresholdHigh High threshold value in degrees C written back
512  *                                by this function.
513  *
514  *  @param [out]    thresholdLow  Low threshold value in degrees C written back
515  *                                by this function.
516  *
517  *  @pre Register @c notifyObject with #Temperature_registerNotifyRange()
518  */
519 void Temperature_getThresholdRange(Temperature_NotifyObj *notifyObject, int16_t *thresholdHigh, 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 #ifdef __cplusplus
546 }
547 #endif
548 
549 #endif /* ti_drivers_Temperature__include */
550