1 /*************************************************************************//**
2 * @file
3 * @brief This file is part of the AFBR-S50 SDK example application.
4 *
5 * @copyright
6 *
7 * Copyright (c) 2023, Broadcom Inc.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright notice, this
14 * list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
19 *
20 * 3. Neither the name of the copyright holder nor the names of its
21 * contributors may be used to endorse or promote products derived from
22 * this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 *****************************************************************************/
35
36 #include <stdio.h>
37 #include <api/argus_api.h>
38
39 #define SPI_SLAVE 1
40
41 /*!***************************************************************************
42 * @brief A callback function from the example code whenever an error occurs.
43 *
44 * @details The example code calls this function whenever an unexpected error
45 * occurs, for example, if an API function returns an error code.
46 *
47 * This implementation of the function will print the error message.
48 * If specified, the program execution will be stopped with an
49 * infinite loop. Otherwise, the program will continue to run and the
50 * error is printed and ignored.
51 *
52 * @warning This is only a simple example implementation that does not handle
53 * errors in a production system. It is intended to demonstrate the
54 * usage of the API and to provide a starting point for custom
55 * applications.
56 *
57 * This function needs to be replaced with a more sophisticated
58 * implementation to handle errors in a production system.
59 * For example, it could reset the device or try to recover from
60 * the error by re-initializing the device.
61 *
62 * @param status The specified status to be checked for errors.
63 * @param stop Whether to stop the program (e.g. in case of a critical error).
64 * @param msg The associated error message to be printed in case of errors.
65 *****************************************************************************/
HandleError(status_t status,bool stop,char const * msg)66 void HandleError(status_t status, bool stop, char const * msg)
67 {
68 /* Check for status < 0 and print message and halt the program execution. */
69 if (status < STATUS_OK)
70 {
71 printf("ERROR (%d): %s\n", status, msg);
72 if (stop)
73 {
74 printf(" --> Stopped execution due to a critical issue!\n"
75 " Check the hardware end reset the board!\n");
76 while (1) __asm("nop"); // stop!
77 }
78 }
79 }
80
81 /*!***************************************************************************
82 * @brief Creates and initializes a new device instance.
83 *
84 * @param slave The SPI slave identifier number that is passed to the S2PI
85 * layers by the API whenever it calls a function.
86 *
87 * @return The pointer to the handle of the created device instance. Used to
88 * identify the calling instance in case of multiple devices.
89 *****************************************************************************/
InitializeDevice(s2pi_slave_t slave)90 static argus_hnd_t* InitializeDevice(s2pi_slave_t slave)
91 {
92 /* Get device instance already initialized with default settings by the OS */
93 argus_hnd_t *device = Argus_GetHandle(SPI_SLAVE);
94 HandleError(device ? STATUS_OK : ERROR_FAIL, true, "Argus_CreateHandle failed!");
95
96 /* Adjust additional configuration parameters by invoking the dedicated API methods.
97 * Note: The maximum frame rate is limited by the amount of data sent via UART.
98 * See #PrintResults function for more information. */
99 status_t status = Argus_SetConfigurationFrameTime(device, 100000); // 0.1 second = 10 Hz
100 HandleError(status, true, "Argus_SetConfigurationFrameTime failed!");
101
102 return device;
103 }
104
105 /*!***************************************************************************
106 * @brief Triggers a measurement cycle in blocking manner.
107 *
108 * @param device The pointer to the handle of the calling API instance. Used to
109 * identify the calling instance in case of multiple devices.
110 *
111 * @param res The pointer to the results data structure where the final
112 * measurement results are stored.
113 *****************************************************************************/
TriggerMeasurementBlocking(argus_hnd_t * device,argus_results_t * res)114 static void TriggerMeasurementBlocking(argus_hnd_t * device, argus_results_t * res)
115 {
116 status_t status = STATUS_OK;
117
118 /* Triggers a single measurement.
119 *
120 * Note that due to the laser safety algorithms, the method might refuse
121 * to restart a measurement when the appropriate time has not been elapsed
122 * right now. The function returns with status #STATUS_ARGUS_POWERLIMIT and
123 * the function must be called again later. Use the frame time configuration
124 * in order to adjust the timing between two measurement frames.
125 *
126 * The callback can be null for the trigger function if the #Argus_GetStatus
127 * function is used to await the measurement cycle to finish. Otherwise, the
128 * callback should be set to receive the measurement ready event. See the
129 * advanced example on how to use the callback. */
130 do
131 {
132 status = Argus_TriggerMeasurement(device, 0);
133 } while (status == STATUS_ARGUS_POWERLIMIT);
134 HandleError(status, false, "Argus_TriggerMeasurement failed!");
135
136 /* Wait until measurement data is ready by polling the #Argus_GetStatus
137 * function until the status is not #STATUS_BUSY any more. Note that
138 * the actual measurement is performed asynchronously in the background
139 * (i.e. on the device, in DMA transfers and in interrupt service routines).
140 * Thus, one could do more useful stuff while waiting here... */
141 do
142 {
143 status = Argus_GetStatus(device);
144 }
145 while (status == STATUS_BUSY);
146 HandleError(status, false, "Waiting for measurement data ready (Argus_GetStatus) failed!");
147
148 /* Evaluate the raw measurement results by calling the #Argus_EvaluateData function. */
149 status = Argus_EvaluateData(device, res);
150 HandleError(status, false, "Argus_EvaluateData failed!");
151 }
152
153 /*!***************************************************************************
154 * @brief Prints measurement results via UART.
155 *
156 * @details Prints some measurement data via UART in the following format:
157 *
158 * ```
159 * 123.456789 s; Range: 123456 mm; Amplitude: 1234 LSB; Quality: 100; Status: 0
160 * ```
161 *
162 * @param res A pointer to the latest measurement results structure.
163 *****************************************************************************/
PrintResults(argus_results_t const * res)164 static void PrintResults(argus_results_t const * res)
165 {
166 /* Print the recent measurement results:
167 * 1. Time stamp in seconds since the last MCU reset.
168 * 2. Range in mm (converting the Q9.22 value to mm).
169 * 3. Amplitude in LSB (converting the UQ12.4 value to LSB).
170 * 4. Signal Quality in % (100% = good signal).
171 * 5. Status (0: OK, <0: Error, >0: Warning.
172 *
173 * Note: Sending data via UART creates a large delay which might prevent
174 * the API from reaching the full frame rate. This example sends
175 * approximately 80 characters per frame at 115200 bps which limits
176 * the max. frame rate of 144 fps:
177 * 115200 bps / 10 [bauds-per-byte] / 80 [bytes-per-frame] = 144 fps */
178 printf("%4d.%06d s; Range: %5d mm; Amplitude: %4d LSB; Quality: %3d; Status: %d\n",
179 res->TimeStamp.sec,
180 res->TimeStamp.usec,
181 res->Bin.Range / (Q9_22_ONE / 1000),
182 res->Bin.Amplitude / UQ12_4_ONE,
183 res->Bin.SignalQuality,
184 res->Status);
185 }
186
187 /*!***************************************************************************
188 * @brief Prints information about the initialized devices.
189 *
190 * @param device The pointer to the device handler.
191 *****************************************************************************/
PrintDeviceInfo(argus_hnd_t * device)192 static void PrintDeviceInfo(argus_hnd_t * device)
193 {
194 /* Print some information about current API and connected device. */
195 const uint32_t value = Argus_GetAPIVersion();
196 const uint8_t a = (uint8_t)((value >> 24) & 0xFFU);
197 const uint8_t b = (uint8_t)((value >> 16) & 0xFFU);
198 const uint8_t c = (uint8_t)(value & 0xFFFFU);
199 const uint32_t id = Argus_GetChipID(device);
200 const char * m = Argus_GetModuleName(device);
201
202 printf("\n##### AFBR-S50 API - Simple Example ###########################\n"
203 " API Version: v%d.%d.%d\n"
204 " Chip ID: %d\n"
205 " Module: %s\n"
206 "###############################################################\n\n",
207 a, b, c, id, m);
208 }
209
main(void)210 int main(void)
211 {
212 /* Instantiate and initialize the device handlers. */
213 argus_hnd_t * device = InitializeDevice(SPI_SLAVE);
214
215 /* Print a device information message. */
216 PrintDeviceInfo(device);
217
218 /* The program loop ... */
219 for (;;)
220 {
221 /* The measurement data structure. */
222 argus_results_t res;
223
224 /* Trigger a measurement for the current device. */
225 TriggerMeasurementBlocking(device, &res);
226
227 /* Use the obtain results, e.g. print via UART. */
228 PrintResults(&res);
229 }
230
231 return 0;
232 }
233