| int main(void) {
 ch_group_t  *grp_ptr = &chirp_group;
 uint8_t u8_chirp_error = 0;
 uint8_t u8_num_ports;
 uint8_t u8_dev_num;
 
 /* Initialize board hardware functions
 *   This call to the board support package (BSP) performs all necessary
 *   hardware initialization for the application to run on this board.
 *   This includes setting up memory regions, initializing clocks and
 *   peripherals (including I2C and serial port), and any processor-specific
 *   startup sequences.
 *
 *   The chbsp_board_init() function also initializes fields within the
 *   sensor group descriptor, including number of supported sensors and
 *   the RTC clock calibration pulse length.
 */
 chbsp_board_init(grp_ptr);
 
 printf("\n\nNuvoton M263 & Chirp SonicLib Example Application\n");
 printf("    Compile time:  %s %s\n", __DATE__, __TIME__);
 printf("    Version: %u.%u.%u", APP_VERSION_MAJOR, APP_VERSION_MINOR,
 APP_VERSION_REV);
 printf("    SonicLib version: %u.%u.%u\n", SONICLIB_VER_MAJOR,
 SONICLIB_VER_MINOR, SONICLIB_VER_REV);
 printf("\n");
 
 
 /* Get the number of (possible) sensor devices on the board
 *   Set by the BSP during chbsp_board_init()
 */
 u8_num_ports = ch_get_num_ports(grp_ptr);
 
 
 /* Initialize sensor descriptors.
 *   This loop initializes each (possible) sensor's ch_dev_t descriptor,
 *   although we don't yet know if a sensor is actually connected.
 *
 *   The call to ch_init() specifies the sensor descriptor, the sensor group
 *   it will be added to, the device number within the group, and the sensor
 *   firmware initialization routine that will be used.  (The sensor
 *   firmware selection effectively specifies whether it is a CH101 or
 *   CH201 sensor, as well as the exact feature set.)
 */
 printf("Initializing sensor(s)... ");
 
 for (u8_dev_num = 0; u8_dev_num < u8_num_ports; u8_dev_num++)
 {
 ch_dev_t *dev_ptr = &(chirp_devices[u8_dev_num]);  // init struct in array
 
 /* Init device descriptor
 *   Note that this assumes all sensors will use the same sensor
 *   firmware.  The CHIRP_SENSOR_FW_INIT_FUNC symbol is defined in
 *   app_config.h and is used for all devices.
 *
 *   However, it is possible for different sensors to use different
 *   firmware images, by specifying different firmware init routines
 *   when ch_init() is called for each.
 */
 u8_chirp_error |= ch_init(dev_ptr, grp_ptr, u8_dev_num,
 CHIRP_SENSOR_FW_INIT_FUNC);
 }
 
 /* Start all sensors.
 *   The ch_group_start() function will search each port (that was
 *   initialized above) for a sensor. If it finds one, it programs it (with
 *   the firmware specified above during ch_init()) and waits for it to
 *   perform a self-calibration step.  Then, once it has found all the
 *   sensors, ch_group_start() completes a timing reference calibration by
 *   applying a pulse of known length to the sensor's INT line.
 */
 if (u8_chirp_error == 0)
 {
 printf("starting group... ");
 u8_chirp_error = ch_group_start(grp_ptr);
 }
 
 if (u8_chirp_error == 0)
 {
 printf("OK\n");
 }
 else
 {
 printf("FAILED: %d\n", u8_chirp_error);
 }
 
 printf("\n");
 
 /* Get and display the initialization results for each connected sensor.
 *   This loop checks each device number in the sensor group to determine
 *   if a sensor is actually connected.  If so, it makes a series of
 *   function calls to get different operating values, including the
 *   operating frequency, clock calibration values, and firmware version.
 */
 printf("Sensor\tType \t   Freq\t\t RTC Cal \tFirmware\n");
 
 for (u8_dev_num = 0; u8_dev_num < u8_num_ports; u8_dev_num++)
 {
 ch_dev_t *dev_ptr = ch_get_dev_ptr(grp_ptr, u8_dev_num);
 
 if (ch_sensor_is_connected(dev_ptr))
 {
 printf("%d\tCH%d\t %u Hz\t%u@%ums\t%s\n", u8_dev_num,
 ch_get_part_number(dev_ptr),
 (unsigned int) ch_get_frequency(dev_ptr),
 ch_get_rtc_cal_result(dev_ptr),
 ch_get_rtc_cal_pulselength(dev_ptr),
 ch_get_fw_version_string(dev_ptr));
 }
 }
 
 printf("\n");
 
 /* Register callback function to be called when Chirp sensor interrupts */
 ch_io_int_callback_set(grp_ptr, sensor_int_callback);
 
 /* Configure each sensor with its operating parameters
 *   Initialize a ch_config_t structure with values defined in the
 *   app_config.h header file, then write the configuration to the
 *   sensor using ch_set_config().
 */
 printf("Configuring sensor(s)...\n");
 
 for (u8_dev_num = 0; u8_dev_num < u8_num_ports; u8_dev_num++)
 {
 ch_config_t dev_config;
 ch_dev_t *dev_ptr = ch_get_dev_ptr(grp_ptr, u8_dev_num);
 
 if (ch_sensor_is_connected(dev_ptr))
 {
 
 /* Select sensor mode
 *   All connected sensors are placed in hardware triggered mode.
 *   The first connected (lowest numbered) sensor will transmit and
 *   receive, all others will only receive.
 */
 
 u8_num_connected_sensors++;             // count one more connected
 u32_active_devices |= (1 << u8_dev_num);   // add to active device bit mask
 
 if (u8_num_connected_sensors == 1)      // if this is the first sensor
 {
 dev_config.mode = CHIRP_FIRST_SENSOR_MODE;
 }
 else
 {
 dev_config.mode = CHIRP_OTHER_SENSOR_MODE;
 }
 
 if (dev_config.mode != CH_MODE_FREERUN)     // unless free-running
 {
 u8_num_triggered_devices++;             // will be triggered
 }
 
 /* Init config structure with values from app_config.h */
 dev_config.max_range       = CHIRP_SENSOR_MAX_RANGE_MM;
 dev_config.static_range    = CHIRP_SENSOR_STATIC_RANGE;
 
 /* If sensor will be free-running, set internal sample interval */
 if (dev_config.mode == CH_MODE_FREERUN)
 {
 dev_config.sample_interval = MEASUREMENT_INTERVAL_MS;
 }
 else
 {
 dev_config.sample_interval = 0;
 }
 
 dev_config.thresh_ptr = 0;
 
 /* Apply sensor configuration */
 u8_chirp_error = ch_set_config(dev_ptr, &dev_config);
 
 /* Enable sensor interrupt if using free-running mode
 *   Note that interrupt is automatically enabled if using
 *   triggered modes.
 */
 if ((!u8_chirp_error) && (dev_config.mode == CH_MODE_FREERUN))
 {
 chbsp_set_io_dir_in(dev_ptr);
 chbsp_io_interrupt_enable(dev_ptr);
 }
 
 /* Read back and display config settings */
 if (!u8_chirp_error)
 {
 display_config_info(dev_ptr);
 }
 else
 {
 printf("Device %d: Error during ch_set_config()\n", u8_dev_num);
 }
 }
 }
 
 printf("\n");
 
 /* Enable receive sensor pre-triggering, if specified */
 ch_set_rx_pretrigger(grp_ptr, RX_PRETRIGGER_ENABLE);
 
 /* Initialize the periodic timer we'll use to trigger the measurements.
 *   This function initializes a timer that will interrupt every time it
 *   expires, after the specified measurement interval.  The function also
 *   registers a callback function that will be called from the timer
 *   handler when the interrupt occurs.  The callback function will be
 *   used to trigger a measurement cycle on the group of sensors.
 */
 if (u8_num_triggered_devices > 0)
 {
 printf("Initializing sample timer for %dms interval... ",
 MEASUREMENT_INTERVAL_MS);
 
 chbsp_periodic_timer_init(MEASUREMENT_INTERVAL_MS,
 periodic_timer_callback);
 
 printf("OK\n");
 }
 
 printf("Starting measurements\n");
 
 /* Enter main loop
 *   This is an infinite loop that will run for the remainder of the system
 *   execution.  The processor is put in a low-power sleep mode between
 *   measurement cycles and is awakened by interrupt events.
 *
 *   The interrupt may be the periodic timer (set up above), a data-ready
 *   interrupt from a sensor, or the completion of a non-blocking I/O
 *   operation.  This loop will check flags that are set during the
 *   callback functions for the data-ready interrupt and the non-blocking
 *   I/O complete.  Based on the flags that are set, this loop will call
 *   the appropriate routines to handle and/or display sensor data.
 */
 while (1)
 {
 /* Check for sensor data-ready interrupt(s) */
 if (u32_taskflags & DATA_READY_FLAG)
 {
 /* All sensors have interrupted - handle sensor data */
 u32_taskflags &= ~DATA_READY_FLAG;  // clear flag
 handle_data_ready(grp_ptr);         // read and display measurement
 }
 }
 }
 
 
 /*
 * periodic_timer_callback() - periodic timer callback routine
 *
 * This function is called by the periodic timer interrupt when the timer
 * expires.  Because the periodic timer is used to initiate a new measurement
 * cycle on a group of sensors, this function calls ch_group_trigger() during
 * each execution.
 *
 * This function is registered by the call to chbsp_periodic_timer_init()
 * in main().
 */
 
 void periodic_timer_callback(void)
 {
 if (u8_num_triggered_devices > 0)
 {
 ch_group_trigger(&chirp_group);
 }
 }
 
 
 /*
 * sensor_int_callback() - sensor interrupt callback routine
 *
 * This function is called by the board support package's interrupt handler for
 * the sensor's INT line every time that the sensor interrupts.  The device
 * number parameter, u8_dev_num, is used to identify the interrupting device
 * within the sensor group.  (Generally the device number is same as the port
 * number used in the BSP to manage I/O pins, etc.)
 *
 * Each time this function is called, a bit is set in the u32_data_ready_devices
 * variable to identify the interrupting device.  When all active sensors have
 * interrupted (found by comparing with the u32_active_devices variable), the
 * DATA_READY_FLAG is set.  That flag will be detected in the main() loop.
 *
 * This callback function is registered by the call to ch_io_int_callback_set()
 * in main().
 */
 static void sensor_int_callback(ch_group_t *grp_ptr, uint8_t u8_dev_num)
 {
 ch_dev_t *dev_ptr = ch_get_dev_ptr(grp_ptr, u8_dev_num);
 
 u32_data_ready_devices |= (1 << u8_dev_num);       // add to data-ready bit mask
 
 if (u32_data_ready_devices == u32_active_devices)
 {
 /* All active sensors have interrupted after performing a measurement */
 u32_data_ready_devices = 0;
 
 /* Set data-ready flag - it will be checked in main() loop */
 u32_taskflags |= DATA_READY_FLAG;
 
 /* Disable interrupt unless in free-running mode
 *   It will automatically be re-enabled by the next ch_group_trigger()
 */
 if (ch_get_mode(dev_ptr) == CH_MODE_FREERUN)
 {
 chbsp_set_io_dir_in(dev_ptr);               // set INT line as input
 chbsp_group_io_interrupt_enable(grp_ptr);
 }
 else
 {
 chbsp_group_io_interrupt_disable(grp_ptr);
 }
 }
 }
 
 /*
 * display_config_info() - display the configuration values for a sensor
 *
 * This function displays the current configuration settings for an individual
 * sensor.  The operating mode, maximum range, and static target rejection
 * range (if used) are displayed.
 *
 * For CH201 sensors only, the multiple detection threshold values are also
 * displayed.
 */
 static uint8_t display_config_info(ch_dev_t *dev_ptr)
 {
 ch_config_t     read_config;
 uint8_t         u8_chirp_error;
 uint8_t         u8_dev_num = ch_get_dev_num(dev_ptr);
 ch_thresholds_t read_thresholds;
 
 /* Read configuration values for the device into ch_config_t structure */
 u8_chirp_error = ch_get_config(dev_ptr, &read_config);
 
 if (!u8_chirp_error)
 {
 const char *mode_string;
 
 switch (read_config.mode)
 {
 case CH_MODE_IDLE:
 mode_string = "IDLE";
 break;
 
 case CH_MODE_FREERUN:
 mode_string = "FREERUN";
 break;
 
 case CH_MODE_TRIGGERED_TX_RX:
 mode_string = "TRIGGERED_TX_RX";
 break;
 
 case CH_MODE_TRIGGERED_RX_ONLY:
 mode_string = "TRIGGERED_RX_ONLY";
 break;
 
 default:
 mode_string = "UNKNOWN";
 }
 
 /* Display sensor number, mode and max range */
 printf("Sensor %d:\tmax_range=%dmm \tmode=%s  ", u8_dev_num,
 read_config.max_range, mode_string);
 
 /* Display static target rejection range, if used */
 if (read_config.static_range != 0)
 {
 printf("static_range=%d samples", read_config.static_range);
 }
 
 /* Display detection thresholds (only supported on CH201) */
 if (ch_get_part_number(dev_ptr) == CH201_PART_NUMBER)
 {
 /* Get threshold values in structure */
 u8_chirp_error = ch_get_thresholds(dev_ptr, &read_thresholds);
 
 if (!u8_chirp_error)
 {
 printf("\n  Detection thresholds:\n");
 
 for (int i = 0; i < CH_NUM_THRESHOLDS; i++)
 {
 printf("     %d\tstart: %2d\tlevel: %d\n", i,
 read_thresholds.threshold[i].start_sample,
 read_thresholds.threshold[i].level);
 }
 }
 else
 {
 printf(" Device %d: Error during ch_get_thresholds()", u8_dev_num);
 }
 }
 
 printf("\n");
 
 }
 else
 {
 printf(" Device %d: Error during ch_get_config()\n", u8_dev_num);
 }
 
 return u8_chirp_error;
 }
 
 
 /*
 * handle_data_ready() - get and display data from all sensors
 *
 * This routine is called from the main() loop after all sensors have
 * interrupted. It shows how to read the sensor data once a measurement is
 * complete.  This routine always reads out the range and amplitude, and
 * optionally will read out the amplitude data or raw I/Q for all samples
 * in the measurement.
 *
 * See the comments in app_config.h for information about the amplitude data
 * and I/Q readout build options.
 *
 */
 static uint8_t handle_data_ready(ch_group_t *grp_ptr)
 {
 uint8_t     u8_dev_num;
 uint8_t     u8_num_samples = 0;
 uint8_t     ret_val = 0;
 
 /* Read and display data from each connected sensor
 *   This loop will write the sensor data to this application's "chirp_data"
 *   array.  Each sensor has a separate chirp_data_t structure in that
 *   array, so the device number is used as an index.
 */
 
 for (u8_dev_num = 0; u8_dev_num < ch_get_num_ports(grp_ptr); u8_dev_num++)
 {
 ch_dev_t *dev_ptr = ch_get_dev_ptr(grp_ptr, u8_dev_num);
 
 if (ch_sensor_is_connected(dev_ptr))
 {
 
 /* Get measurement results from each connected sensor
 *   For sensor in transmit/receive mode, report one-way echo
 *   distance,  For sensor(s) in receive-only mode, report direct
 *   one-way distance from transmitting sensor
 */
 
 if (ch_get_mode(dev_ptr) == CH_MODE_TRIGGERED_RX_ONLY)
 {
 chirp_data[u8_dev_num].range = ch_get_range(dev_ptr,
 CH_RANGE_DIRECT);
 }
 else
 {
 chirp_data[u8_dev_num].range = ch_get_range(dev_ptr,
 CH_RANGE_ECHO_ONE_WAY);
 }
 
 if (chirp_data[u8_dev_num].range == CH_NO_TARGET)
 {
 /* No target object was detected - no range value */
 
 chirp_data[u8_dev_num].amplitude = 0;  /* no updated amplitude */
 
 printf("Port %d:          no target found        ", u8_dev_num);
 
 }
 else
 {
 /* Target object was successfully detected (range available) */
 
 /* Get the new amplitude value - it's only updated if range
 * was successfully measured.  */
 chirp_data[u8_dev_num].amplitude = ch_get_amplitude(dev_ptr);
 
 printf("Port %d:  Range: %0.1f mm  Amp: %u  ", u8_dev_num,
 (float) chirp_data[u8_dev_num].range / 32.0f,
 chirp_data[u8_dev_num].amplitude);
 }
 
 /* Store number of active samples in this measurement */
 u8_num_samples = ch_get_num_samples(dev_ptr);
 chirp_data[u8_dev_num].num_samples = u8_num_samples;
 
 /* If more than 2 sensors, put each on its own line */
 if (u8_num_connected_sensors > 2)
 {
 printf("\n");
 }
 }
 }
 
 printf("\n");
 
 return ret_val;
 }
 
 
 
 |