1 /*
2  * Percepio DFM v2.0.0
3  * Copyright 2023 Percepio AB
4  * www.percepio.com
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 /**
10  * @file
11  *
12  * @brief DFM API
13  */
14 
15 #ifndef DFM_H
16 #define DFM_H
17 
18 #ifdef __cplusplus
19 extern "C" {
20 #endif
21 
22 
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdint.h>
26 #include <stdarg.h>
27 
28 #include <dfmDefines.h>
29 #include <dfmTypes.h>
30 #include <dfmConfig.h>
31 
32 /**
33  * @brief A callback type that is used by DFM to retrieve user supplied identifiers
34  *
35  * Example:
36  * DfmResult_t xGetUniqueSessionID(char cUniqueSessionIdBuffer[], uint32_t ulSize, uint32_t* pulBytesWritten)
37  * {
38  *     // This function will write a device-unique SessionId to cUniqueSessionIdBuffer.
39  *
40  *     // *** Some writing that must not exceed ulSize bytes... ***
41  *
42  *     *pulBytesWritten = <string_length>;
43  *     return DFM_SUCCESS;
44  * }
45  */
46 typedef DfmResult_t (*DfmUserCallback_t)(char cBuffer[], uint32_t ulSize, uint32_t* pulBytesWritten);
47 
48 /**
49  * @brief This user-supplied function callback is set in xDfmInitialize().
50  * It is supposed to provide a device unique "Session ID".
51  * This is basically a "restart counter" that is combined with the "Device ID"
52  * to generate unique "alert keys" for each alert.
53  *
54  * THIS MUST NOT BE A CONSTANT DUMMY STRING, EVEN FOR BASIC TESTING.
55  * DUPLICATE ALERT KEYS ARE IGNORED BY DEVALERT.
56  *
57  * The alert key follows the pattern "DevAlert/DeviceID/SessionID/AlertCounter"
58  * and must be unique across all alerts from all devices, over all time.
59  * The Alert Counter is reset when the device is restarted.
60  *
61  * For production use, it is NOT ADVICED to use a RANDOM number, like below,
62  * since this may repeat.
63  *
64  * The recommended practice is to use one of these methods:
65  * - The current time ("wall-clock" time), e.g. in seconds since a certain date
66  * - A restart counter, stored in non-volatile storage.
67  *
68  * If using the current time as Session ID, seconds is sufficient resolution
69  * unless a restart and re-initialization may occur faster than that.
70  *
71  * @retval DFM_FAIL Failure
72  * @retval DFM_SUCCESS Success
73  */
74 extern DfmUserCallback_t xDfmUserGetUniqueSessionID;
75 
76 /**
77  * @brief This user-supplied function callback is set in xDfmInitialize().
78  * It is suppoed to provide the "Device ID" for each alert.
79  * This is combined with the "Session ID" to generate unique "alert keys" for each alert.
80  *
81  * THIS MUST NOT BE A CONSTANT DUMMY STRING. DUPLICATE ALERT KEYS ARE IGNORED BY DEVALERT.
82  *
83  * If using AWS IoT Core, note that Device ID does not need to match the Thing Name
84  * (i.e. clientcredentialIOT_THING_NAME in /demos/include/aws_clientcredentials.h).
85  * It is good practice and recommended to have matching Thing Name and Device ID.
86  *
87  * @retval DFM_FAIL Failure
88  * @retval DFM_SUCCESS Success
89  */
90 extern DfmUserCallback_t xDfmUserGetDeviceName;
91 
92 /* 64-bit aligned */
93 #define DFM_DEVICE_NAME_MAX_LEN ((((DFM_CFG_DEVICE_NAME_MAX_LEN) + 7) / 8) * 8)
94 
95 /* 64-bit aligned with room for zero termination */
96 #define DFM_FIRMWARE_VERSION_MAX_LEN ((((DFM_CFG_FIRMWARE_VERSION_MAX_LEN) + 1 + 7) / 8) * 8)
97 
98 /* 64-bit aligned with room for zero termination */
99 #define DFM_DESCRIPTION_MAX_LEN ((((DFM_CFG_DESCRIPTION_MAX_LEN) + 1 + 7) / 8) * 8)
100 
101 #include <dfmKernelPort.h>
102 #include <dfmEntry.h>
103 #include <dfmAlert.h>
104 #include <dfmSession.h>
105 #include <dfmStorage.h>
106 #include <dfmCloud.h>
107 
108 #include <dfmCodes.h>
109 
110 #ifndef DFM_CFG_ENABLED
111 #error DFM_CFG_ENABLED not set in dfmConfig.h!
112 #endif
113 
114 #ifndef DFM_CFG_FIRMWARE_VERSION_MAX_LEN
115 #error DFM_CFG_FIRMWARE_VERSION_MAX_LEN not set in dfmConfig.h!
116 #endif
117 
118 #if DFM_CFG_PRODUCTID == 0
119 #error DFM_CFG_PRODUCTID not set in dfmConfig.h!
120 #endif
121 
122 #ifndef DFM_ERROR_PRINT
123 #define DFM_ERROR_PRINT(msg)
124 #endif
125 
126 #if (DFM_CFG_ENABLE_DEBUG_PRINT == 1)
127 #define DFM_DEBUG_PRINT(msg) DFM_ERROR_PRINT(msg)
128 #else
129 #define DFM_DEBUG_PRINT(msg) ((void)(msg))
130 #endif
131 
132 #if ((DFM_CFG_ENABLED) == 1)
133 
134 /**
135  * @defgroup dfm_alert_apis DFM Alert API
136  * @ingroup dfm_apis
137  * @{
138  */
139 
140 /*******************************************************************************
141  * Versions
142  *
143  * 1) Initial version
144  * 2) Added ulProduct to DFM header
145  * 3) Refactored DFM
146  ******************************************************************************/
147 #define DFM_VERSION_INITIAL 1
148 #define DFM_VERSION_WITH_PRODUCT 2
149 #define DFM_VERSION_2_0 3
150 
151 #define DFM_VERSION DFM_VERSION_2_0
152 
153 #if (DFM_FIRMWARE_VERSION_MAX_LEN > 255)
154 #error "Firmware Max Length cannot be larger than 255"
155 #endif
156 
157 /**
158  * @brief DFM data
159  */
160 typedef struct DfmData
161 {
162 	uint32_t ulDfmInitialized;
163 
164 	DfmSessionData_t xSessionData;
165 	DfmKernelPortData_t xKernelPortData;
166 	DfmStorageData_t xStorageData;
167 	DfmCloudData_t xCloudData;
168 	DfmAlertData_t xAlertData;
169 	DfmEntryData_t xEntryData;
170 } DfmData_t;
171 
172 /**
173  * @internal Initializes the entire DFM system
174  *
175  * @param[in] xGetUniqueSessionID This user-defined function provides the "Session ID".
176  * This is basically a "restart counter" that is combined with the "Device ID"
177  * to generate unique "alert keys" for each alert.
178  *
179  * THIS MUST NOT BE A CONSTANT DUMMY STRING, EVEN FOR BASIC TESTING.
180  * DUPLICATE ALERT KEYS ARE IGNORED BY DEVALERT.
181  *
182  * The alert key follows the pattern "DevAlert/DeviceID/SessionID/AlertCounter"
183  * and must be unique across all alerts from all devices, over all time.
184  * The Alert Counter is reset when the device is restarted.
185  *
186  * For production use, it is NOT ADVICED to use a RANDOM number, like below,
187  * since this may repeat.
188  *
189  * The recommended practice is to use one of these methods:
190  * - The current time ("wall-clock" time), e.g. in seconds since a certain date
191  * - A restart counter, stored in non-volatile storage.
192  *
193  * If using the current time as Session ID, seconds is sufficient resolution
194  * unless a restart and re-initialization may occur faster than that.
195  *
196  * @param[in] xGetDeviceName This user-defined function provides the "Device ID" for each alert.
197  * This is combined with the "Session ID" to generate unique "alert keys" for each alert.
198  *
199  * THIS MUST NOT BE A CONSTANT DUMMY STRING. DUPLICATE ALERT KEYS ARE IGNORED BY DEVALERT.
200  *
201  * If using AWS IoT Core, note that Device ID does not need to match the Thing Name
202  * (i.e. clientcredentialIOT_THING_NAME in /demos/include/aws_clientcredentials.h).
203  * It is good practice and recommended to have matching Thing Name and Device ID.
204  *
205  * @retval DFM_FAIL Failure
206  * @retval DFM_SUCCESS Success
207  */
208 DfmResult_t xDfmInitialize(DfmUserCallback_t xGetUniqueSessionID, DfmUserCallback_t xGetDeviceName);
209 
210 /**
211  * @brief Is DFM initialized?
212  *
213  * @retval DFM_FAIL Failure
214  * @retval DFM_SUCCESS Success
215  */
216 uint32_t ulDfmIsInitialized(void);
217 
218 /**
219  * @brief Enable DFM
220  *
221  * @param[in] ulOverride Flag indicating if it should override any previous disable calls. Setting this to 1 means that if for some reason it was decided to disable DFM on this device and it was stored to Flash, this Enable attempt will not do anything.
222  *
223  * @retval DFM_FAIL Failure
224  * @retval DFM_SUCCESS Success
225  */
226 #define xDfmEnable(ulOverride) xDfmSessionEnable(ulOverride)
227 
228 /**
229  * @brief Disable DFM
230  *
231  * @param[in] ulRemember Flag indicating if the Disable should be stored in permanent storage. Setting this to 1 means that any reboots of the device will remember the "Disabled" flag and xDfmEnable(1) must be called to override and re-enable DFM.
232  *
233  * @retval DFM_FAIL Failure
234  * @retval DFM_SUCCESS Success
235  */
236 #define xDfmDisable(ulRemember) xDfmSessionDisable(ulRemember)
237 
238 /**
239  * @brief Is DFM enabled?
240  *
241  * @retval DFM_FAIL Failure
242  * @retval DFM_SUCCESS Success
243  */
244 #define ulDfmIsEnabled() ulDfmSessionIsEnabled()
245 
246  /** @} */
247 
248 #else
249 
250 /* Dummy defines */
251 #define xDfmInitialize(p,fv) (DFM_FAIL)
252 #define ulDfmIsInitialized() (0)
253 #define xDfmEnable(ulOverride) (DFM_FAIL)
254 #define xDfmDisable() (DFM_FAIL)
255 #define ulDfmIsEnabled() (0)
256 
257 #endif
258 
259 #ifdef __cplusplus
260 }
261 #endif
262 
263 #endif /* DFM_H */
264