example_waste_level_main.c
Go to the documentation of this file.
1 // Copyright (c) Acconeer AB, 2024-2025
2 // All rights reserved
3 // This file is subject to the terms and conditions defined in the file
4 // 'LICENSES/license_acconeer.txt', (BSD 3-Clause License) which is part
5 // of this source code package.
6
7 #include <stdbool.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10
11 #include "acc_config.h"
12 #include "acc_hal_definitions_a121.h"
13 #include "acc_hal_integration_a121.h"
14 #include "acc_integration.h"
15 #include "acc_integration_log.h"
16 #include "acc_processing.h"
17 #include "acc_rss_a121.h"
18 #include "acc_sensor.h"
19 #include "acc_version.h"
20 #include "example_waste_level.h"
21 #include "example_waste_level_main.h"
22
23 #define SENSOR_ID (1U)
24 #define SENSOR_TIMEOUT_MS (1000U)
25
26 /**
27 * @brief Frees any allocated resources
28 */
29 static void cleanup(acc_processing_t *processing,
30 acc_sensor_t *sensor,
31 void *buffer,
32 waste_level_handle_t *handle,
33 waste_level_app_config_t *app_config);
34
35 /**
36 * @brief Performs sensor calibration (with retry) and sensor prepare
37 */
38 static bool do_sensor_calibration_and_prepare(acc_sensor_t *sensor, acc_config_t *config, void *buffer, uint32_t buffer_size);
39
40 /**
41 * @brief Print a processor result in a human-readable format
42 */
43 static void print_waste_level_result(const waste_level_result_t *result);
44
45 int acconeer_main(int argc, char *argv[])
46 {
47 (void)argc;
48 (void)argv;
49 acc_processing_t *processing = NULL;
50 acc_sensor_t *sensor = NULL;
51 void *buffer = NULL;
52 uint32_t buffer_size = 0;
53 acc_processing_metadata_t proc_meta;
54 acc_processing_result_t proc_result;
55
56 waste_level_handle_t *waste_level_handle = NULL;
57 waste_level_app_config_t *app_config = NULL;
58
59 waste_level_result_t waste_level_result = {0};
60
61 printf("Acconeer software version %s\n", acc_version_get());
62
63 const acc_hal_a121_t *hal = acc_hal_rss_integration_get_implementation();
64
65 if (!acc_rss_hal_register(hal))
66 {
67 return EXIT_FAILURE;
68 }
69
70 app_config = waste_level_app_config_create();
71 if (app_config == NULL)
72 {
73 printf("waste_level_app_config_create() failed\n");
74 cleanup(processing, sensor, buffer, waste_level_handle, app_config);
75 return EXIT_FAILURE;
76 }
77
78 waste_level_app_config_set_preset(WASTE_LEVEL_PRESET_PLASTIC_WASTE_BIN, app_config);
79
80 waste_level_processing_config_log(&app_config->processing_config);
81
82 acc_config_log(app_config->sensor_config);
83
84 waste_level_handle = waste_level_handle_create(app_config);
85 if (waste_level_handle == NULL)
86 {
87 printf("waste_level_handle_create() failed\n");
88 cleanup(processing, sensor, buffer, waste_level_handle, app_config);
89 return EXIT_FAILURE;
90 }
91
92 processing = acc_processing_create(app_config->sensor_config, &proc_meta);
93 if (processing == NULL)
94 {
95 printf("acc_processing_create() failed\n");
96 cleanup(processing, sensor, buffer, waste_level_handle, app_config);
97 return EXIT_FAILURE;
98 }
99
100 if (!acc_rss_get_buffer_size(app_config->sensor_config, &buffer_size))
101 {
102 printf("acc_rss_get_buffer_size() failed\n");
103 cleanup(processing, sensor, buffer, waste_level_handle, app_config);
104 return EXIT_FAILURE;
105 }
106
107 buffer = acc_integration_mem_alloc(buffer_size);
108 if (buffer == NULL)
109 {
110 printf("buffer allocation failed\n");
111 cleanup(processing, sensor, buffer, waste_level_handle, app_config);
112 return EXIT_FAILURE;
113 }
114
115 acc_hal_integration_sensor_supply_on(SENSOR_ID);
116 acc_hal_integration_sensor_enable(SENSOR_ID);
117
118 sensor = acc_sensor_create(SENSOR_ID);
119 if (sensor == NULL)
120 {
121 printf("acc_sensor_create() failed\n");
122 cleanup(processing, sensor, buffer, waste_level_handle, app_config);
123 return EXIT_FAILURE;
124 }
125
126 if (!do_sensor_calibration_and_prepare(sensor, app_config->sensor_config, buffer, buffer_size))
127 {
128 printf("do_sensor_calibration_and_prepare() failed\n");
129 acc_sensor_status(sensor);
130 cleanup(processing, sensor, buffer, waste_level_handle, app_config);
131 return EXIT_FAILURE;
132 }
133
134 while (true)
135 {
136 if (!acc_sensor_measure(sensor))
137 {
138 printf("acc_sensor_measure failed\n");
139 acc_sensor_status(sensor);
140 cleanup(processing, sensor, buffer, waste_level_handle, app_config);
141 return EXIT_FAILURE;
142 }
143
144 if (!acc_hal_integration_wait_for_sensor_interrupt(SENSOR_ID, SENSOR_TIMEOUT_MS))
145 {
146 printf("Sensor interrupt timeout\n");
147 acc_sensor_status(sensor);
148 cleanup(processing, sensor, buffer, waste_level_handle, app_config);
149 return EXIT_FAILURE;
150 }
151
152 if (!acc_sensor_read(sensor, buffer, buffer_size))
153 {
154 printf("acc_sensor_read failed\n");
155 acc_sensor_status(sensor);
156 cleanup(processing, sensor, buffer, waste_level_handle, app_config);
157 return EXIT_FAILURE;
158 }
159
160 acc_processing_execute(processing, buffer, &proc_result);
161
162 if (proc_result.calibration_needed)
163 {
164 printf("The current calibration is not valid for the current temperature.\n");
165 printf("The sensor needs to be re-calibrated.\n");
166
167 if (!do_sensor_calibration_and_prepare(sensor, app_config->sensor_config, buffer, buffer_size))
168 {
169 printf("do_sensor_calibration_and_prepare() failed\n");
170 acc_sensor_status(sensor);
171 cleanup(processing, sensor, buffer, waste_level_handle, app_config);
172 return EXIT_FAILURE;
173 }
174
175 printf("The sensor was successfully re-calibrated.\n");
176 }
177 else if (proc_result.data_saturated)
178 {
179 printf("Data is saturated. Try to reduce the sensor gain\n");
180 }
181 else
182 {
183 waste_level_process(waste_level_handle, app_config, &proc_meta, proc_result.frame, &waste_level_result);
184
185 print_waste_level_result(&waste_level_result);
186 }
187 }
188
189 cleanup(processing, sensor, buffer, waste_level_handle, app_config);
190
191 printf("Application finished OK\n");
192
193 return EXIT_SUCCESS;
194 }
195
196 static void cleanup(acc_processing_t *processing,
197 acc_sensor_t *sensor,
198 void *buffer,
199 waste_level_handle_t *handle,
200 waste_level_app_config_t *app_config)
201 {
202 acc_hal_integration_sensor_disable(SENSOR_ID);
203 acc_hal_integration_sensor_supply_off(SENSOR_ID);
204
205 if (sensor != NULL)
206 {
207 acc_sensor_destroy(sensor);
208 }
209
210 if (processing != NULL)
211 {
212 acc_processing_destroy(processing);
213 }
214
215 if (buffer != NULL)
216 {
217 acc_integration_mem_free(buffer);
218 }
219
220 if (app_config != NULL)
221 {
222 waste_level_app_config_destroy(app_config);
223 }
224
225 if (handle != NULL)
226 {
227 waste_level_handle_destroy(handle);
228 }
229 }
230
231 static bool do_sensor_calibration_and_prepare(acc_sensor_t *sensor, acc_config_t *config, void *buffer, uint32_t buffer_size)
232 {
233 bool status = false;
234 bool cal_complete = false;
235 acc_cal_result_t cal_result;
236 const uint16_t calibration_retries = 1U;
237
238 // Random disturbances may cause the calibration to fail. At failure, retry at least once.
239 for (uint16_t i = 0; !status && (i <= calibration_retries); i++)
240 {
241 // Reset sensor before calibration by disabling/enabling it
242 acc_hal_integration_sensor_disable(SENSOR_ID);
243 acc_hal_integration_sensor_enable(SENSOR_ID);
244
245 do
246 {
247 status = acc_sensor_calibrate(sensor, &cal_complete, &cal_result, buffer, buffer_size);
248
249 if (status && !cal_complete)
250 {
251 status = acc_hal_integration_wait_for_sensor_interrupt(SENSOR_ID, SENSOR_TIMEOUT_MS);
252 }
253 } while (status && !cal_complete);
254 }
255
256 if (status)
257 {
258 // Reset sensor after calibration by disabling/enabling it
259 acc_hal_integration_sensor_disable(SENSOR_ID);
260 acc_hal_integration_sensor_enable(SENSOR_ID);
261
262 status = acc_sensor_prepare(sensor, config, &cal_result, buffer, buffer_size);
263 }
264
265 return status;
266 }
267
268 static void print_waste_level_result(const waste_level_result_t *result)
269 {
270 if (result->level_found)
271 {
272 printf("Fill level %" PRIu16 "%% (%" PRIfloat "m)\n", result->level_percent, ACC_LOG_FLOAT_TO_INTEGER(result->level_m));
273 }
274 else
275 {
276 printf("No level found\n");
277 }
278 }
acc_hal_integration_sensor_supply_off
void acc_hal_integration_sensor_supply_off(acc_sensor_id_t sensor_id)
Power off sensor supply.
Definition: acc_hal_integration_stm32cube_xm.c:104
acc_rss_a121.h
SENSOR_ID
#define SENSOR_ID
Definition: example_waste_level_main.c:23
SENSOR_TIMEOUT_MS
#define SENSOR_TIMEOUT_MS
Definition: example_waste_level_main.c:24
acc_processing_destroy
void acc_processing_destroy(acc_processing_t *handle)
Destroy a processing instance identified with the provided processing handle.
acc_hal_integration_sensor_supply_on
void acc_hal_integration_sensor_supply_on(acc_sensor_id_t sensor_id)
Power on sensor supply.
Definition: acc_hal_integration_stm32cube_xm.c:99
waste_level_handle_create
waste_level_handle_t * waste_level_handle_create(const waste_level_app_config_t *app_config)
Create a waste level handle.
Definition: example_waste_level.c:217
acc_processing_result_t
Result provided by the processing module.
Definition: acc_processing.h:71
acc_sensor_read
bool acc_sensor_read(const acc_sensor_t *sensor, void *buffer, uint32_t buffer_size)
Read out radar data.
buffer
void * buffer
Definition: i2c_example_cargo.c:40
acc_version.h
acc_rss_get_buffer_size
bool acc_rss_get_buffer_size(const acc_config_t *config, uint32_t *buffer_size)
Get the buffer size needed for the specified config.
waste_level_handle
Definition: example_waste_level.c:27
print_waste_level_result
static void print_waste_level_result(const waste_level_result_t *result)
Print a processor result in a human-readable format.
Definition: example_waste_level_main.c:268
acc_cal_result_t
The result from a completed calibration.
Definition: acc_definitions_a121.h:30
waste_level_handle_destroy
void waste_level_handle_destroy(waste_level_handle_t *handle)
Destroy a waste level handle.
Definition: example_waste_level.c:257
acc_processing_execute
void acc_processing_execute(acc_processing_t *handle, void *buffer, acc_processing_result_t *result)
Process the data according to the configuration used in create.
waste_level_result_t
Result type.
Definition: example_waste_level.h:63
cargo_result_t::level_m
float level_m
Definition: example_cargo.h:123
acc_integration.h
config
cargo_config_t config
Definition: i2c_example_cargo.c:34
acc_hal_rss_integration_get_implementation
const acc_hal_a121_t * acc_hal_rss_integration_get_implementation(void)
Get hal implementation reference.
Definition: acc_hal_integration_stm32cube_xm.c:152
cargo_result_t::level_percent
float level_percent
Definition: example_cargo.h:128
acc_integration_mem_alloc
void * acc_integration_mem_alloc(size_t size)
Allocate dynamic memory.
Definition: acc_integration_stm32.c:592
acc_processing_metadata_t
Metadata that will be populated by the processing module during creation.
Definition: acc_processing.h:36
acc_hal_a121_t
Definition: acc_hal_definitions_a121.h:82
waste_level_app_config_t
Definition: example_waste_level.h:42
acc_rss_hal_register
bool acc_rss_hal_register(const acc_hal_a121_t *hal)
Register an integration.
waste_level_app_config_destroy
void waste_level_app_config_destroy(waste_level_app_config_t *app_config)
Destroy a waste level app config.
Definition: example_waste_level.c:166
acc_sensor.h
buffer_size
uint32_t buffer_size
Definition: i2c_example_cargo.c:41
sensor
acc_sensor_t * sensor
Definition: i2c_example_cargo.c:33
acc_hal_integration_wait_for_sensor_interrupt
bool acc_hal_integration_wait_for_sensor_interrupt(acc_sensor_id_t sensor_id, uint32_t timeout_ms)
Wait for a sensor interrupt.
Definition: acc_hal_integration_stm32cube_xm.c:130
acc_hal_integration_a121.h
handle
cargo_handle_t * handle
Definition: i2c_example_cargo.c:35
result
cargo_result_t result
Definition: i2c_example_cargo.c:43
acc_version_get
const char * acc_version_get(void)
Get the version of the Acconeer software.
acc_config_t
struct acc_config acc_config_t
Definition: acc_config.h:24
printf
#define printf
Definition: printf.h:60
WASTE_LEVEL_PRESET_PLASTIC_WASTE_BIN
@ WASTE_LEVEL_PRESET_PLASTIC_WASTE_BIN
Definition: example_waste_level.h:57
acconeer_main
int acconeer_main(int argc, char *argv[])
Assembly test example.
Definition: example_waste_level_main.c:45
acc_hal_integration_sensor_enable
void acc_hal_integration_sensor_enable(acc_sensor_id_t sensor_id)
Enable sensor.
Definition: acc_hal_integration_stm32cube_xm.c:109
acc_hal_definitions_a121.h
waste_level_app_config_t::sensor_config
acc_config_t * sensor_config
Definition: example_waste_level.h:48
waste_level_process
void waste_level_process(waste_level_handle_t *handle, const waste_level_app_config_t *app_config, const acc_processing_metadata_t *metadata, const acc_int16_complex_t *frame, waste_level_result_t *waste_level_result)
Process Sparse IQ data.
Definition: example_waste_level.c:275
acc_processing_result_t::frame
acc_int16_complex_t * frame
Definition: acc_processing.h:91
acc_hal_integration_sensor_disable
void acc_hal_integration_sensor_disable(acc_sensor_id_t sensor_id)
Disable sensor.
Definition: acc_hal_integration_stm32cube_xm.c:119
acc_processing_t
struct acc_processing_handle acc_processing_t
Definition: acc_processing.h:30
acc_integration_log.h
ACC_LOG_FLOAT_TO_INTEGER
#define ACC_LOG_FLOAT_TO_INTEGER(a)
Definition: acc_integration_log.h:26
acc_sensor_status
void acc_sensor_status(const acc_sensor_t *sensor)
Check the status of the sensor.
acc_sensor_prepare
bool acc_sensor_prepare(acc_sensor_t *sensor, const acc_config_t *config, const acc_cal_result_t *cal_result, void *buffer, uint32_t buffer_size)
Prepare a sensor to do a measurement.
acc_integration_mem_free
void acc_integration_mem_free(void *ptr)
Free dynamic memory.
Definition: acc_integration_stm32.c:602
example_waste_level.h
acc_config_log
void acc_config_log(const acc_config_t *config)
Print a configuration to the log.
do_sensor_calibration_and_prepare
static bool do_sensor_calibration_and_prepare(acc_sensor_t *sensor, acc_config_t *config, void *buffer, uint32_t buffer_size)
Performs sensor calibration (with retry) and sensor prepare.
Definition: example_waste_level_main.c:231
acc_config.h
acc_processing_result_t::data_saturated
bool data_saturated
Definition: acc_processing.h:76
acc_sensor_calibrate
bool acc_sensor_calibrate(acc_sensor_t *sensor, bool *cal_complete, acc_cal_result_t *cal_result, void *buffer, uint32_t buffer_size)
Calibrate a sensor.
PRIfloat
#define PRIfloat
Specifier for printing float type using integers.
Definition: acc_integration_log.h:31
acc_processing_result_t::calibration_needed
bool calibration_needed
Definition: acc_processing.h:84
waste_level_app_config_create
waste_level_app_config_t * waste_level_app_config_create(void)
Create a waste level app config (includes an acc_config_t)
Definition: example_waste_level.c:147
waste_level_app_config_set_preset
void waste_level_app_config_set_preset(waste_level_preset_t preset, waste_level_app_config_t *app_config)
Apply a preset to an app config.
Definition: example_waste_level.c:179
acc_sensor_measure
bool acc_sensor_measure(acc_sensor_t *sensor)
Start a radar measurement with previously prepared configuration.
acc_processing_create
acc_processing_t * acc_processing_create(const acc_config_t *config, acc_processing_metadata_t *processing_metadata)
Create a processing instance with the provided configuration.
waste_level_processing_config_log
void waste_level_processing_config_log(const waste_level_processing_config_t *config)
Log a waste level config.
Definition: example_waste_level.c:354
acc_processing.h
acc_sensor_t
struct acc_sensor acc_sensor_t
Definition: acc_sensor.h:31
cleanup
static void cleanup(acc_processing_t *processing, acc_sensor_t *sensor, void *buffer, waste_level_handle_t *handle, waste_level_app_config_t *app_config)
Frees any allocated resources.
Definition: example_waste_level_main.c:196
acc_sensor_destroy
void acc_sensor_destroy(acc_sensor_t *sensor)
Destroy a sensor instance freeing any resources allocated.
example_waste_level_main.h
waste_level_app_config_t::processing_config
waste_level_processing_config_t processing_config
Definition: example_waste_level.h:45
acc_sensor_create
acc_sensor_t * acc_sensor_create(acc_sensor_id_t sensor_id)
Create a sensor instance.