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