barometer: Add ICP10100 and ICP1011

This commit is contained in:
CUAVmengxiao
2021-11-03 15:16:11 +08:00
committed by Daniel Agar
parent fe44e281e5
commit 258a563dd5
12 changed files with 1356 additions and 0 deletions
+1
View File
@@ -41,3 +41,4 @@ add_subdirectory(lps33hw)
add_subdirectory(maiertek)
add_subdirectory(ms5611)
#add_subdirectory(tcbp001ta) # only for users who really need this
add_subdirectory(invensense)
+35
View File
@@ -0,0 +1,35 @@
############################################################################
#
# Copyright (c) 2021 PX4 Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name PX4 nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
add_subdirectory(icp10100)
add_subdirectory(icp10111)
+46
View File
@@ -0,0 +1,46 @@
############################################################################
#
# Copyright (c) 2021 PX4 Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name PX4 nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
px4_add_module(
MODULE drivers__invensense__icp10100
MAIN icp10100
COMPILE_FLAGS
SRCS
Inven_Sense_ICP10100_registers.hpp
ICP10100.cpp
ICP10100.hpp
icp10100_main.cpp
DEPENDS
drivers_barometer
px4_work_queue
)
+375
View File
@@ -0,0 +1,375 @@
/****************************************************************************
*
* Copyright (c) 2021 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#include "ICP10100.hpp"
using namespace time_literals;
ICP10100::ICP10100(const I2CSPIDriverConfig &config) :
I2C(config),
I2CSPIDriver(config),
_px4_baro(get_device_id())
{
}
ICP10100::~ICP10100()
{
perf_free(_reset_perf);
perf_free(_sample_perf);
perf_free(_bad_transfer_perf);
}
int
ICP10100::init()
{
int ret = I2C::init();
if (ret != PX4_OK) {
DEVICE_DEBUG("I2C::init failed (%i)", ret);
return ret;
}
return Reset() ? 0 : -1;
}
bool
ICP10100::Reset()
{
_state = STATE::RESET;
ScheduleClear();
ScheduleNow();
return true;
}
void
ICP10100::print_status()
{
I2CSPIDriverBase::print_status();
perf_print_counter(_reset_perf);
perf_print_counter(_sample_perf);
perf_print_counter(_bad_transfer_perf);
}
int
ICP10100::probe()
{
uint16_t ID = 0;
read_response(Cmd::READ_ID, (uint8_t *)&ID, 2);
uint8_t PROD_ID = (ID >> 8) & 0x3f;
if (PROD_ID != Product_ID) {
DEVICE_DEBUG("unexpected PROD_ID 0x%02x", PROD_ID);
return PX4_ERROR;
}
return PX4_OK;
}
void
ICP10100::RunImpl()
{
const hrt_abstime now = hrt_absolute_time();
switch (_state) {
case STATE::RESET:
// Software Reset
send_command(Cmd::SOFT_RESET);
_reset_timestamp = now;
_failure_count = 0;
_state = STATE::WAIT_FOR_RESET;
perf_count(_reset_perf);
ScheduleDelayed(100_ms); // Power On Reset: max 100ms
break;
case STATE::WAIT_FOR_RESET: {
// check product id
uint16_t ID = 0;
read_response(Cmd::READ_ID, (uint8_t *)&ID, 2);
uint8_t PROD_ID = (ID >> 8) & 0x3f; // Product ID Bits 5:0
if (PROD_ID == Product_ID) {
// if reset succeeded then read otp
_state = STATE::READ_OTP;
ScheduleDelayed(10_ms); // Time to coefficients are available.
} else {
// RESET not complete
if (hrt_elapsed_time(&_reset_timestamp) > 1000_ms) {
PX4_DEBUG("Reset failed, retrying");
_state = STATE::RESET;
ScheduleDelayed(100_ms);
} else {
PX4_DEBUG("Reset not complete, check again in 10 ms");
ScheduleDelayed(10_ms);
}
}
}
break;
case STATE::READ_OTP: {
// read otp
uint8_t addr_otp_cmd[3] = {0x00, 0x66, 0x9c};
uint8_t otp_buf[3];
uint8_t crc;
bool success = true;
send_command(Cmd::SET_ADDR, addr_otp_cmd, 3);
for (uint8_t i = 0; i < 4; i++) {
read_response(Cmd::READ_OTP, otp_buf, 3);
crc = 0xFF;
for (int j = 0; j < 2; j++) {
crc = (uint8_t)cal_crc(crc, otp_buf[j]);
}
if (crc != otp_buf[2]) {
success = false;
break;
}
_scal[i] = (otp_buf[0] << 8) | otp_buf[1];
}
if (success) {
_state = STATE::MEASURE;
} else {
_state = STATE::RESET;
}
ScheduleDelayed(10_ms);
}
break;
case STATE::MEASURE:
if (Measure()) {
// if configure succeeded then start measurement cycle
_state = STATE::READ;
perf_begin(_sample_perf);
ScheduleDelayed(_measure_interval);
} else {
// MEASURE not complete
if (hrt_elapsed_time(&_reset_timestamp) > 1000_ms) {
PX4_DEBUG("Measure failed, resetting");
_state = STATE::RESET;
} else {
PX4_DEBUG("Measure failed, retrying");
}
ScheduleDelayed(_measure_interval);
}
break;
case STATE::READ: {
uint8_t comp_data[9] {};
bool success = false;
if (read_measure_results(comp_data, 9) == PX4_OK) {
perf_end(_sample_perf);
uint16_t _raw_t = (comp_data[0] << 8) | comp_data[1];
uint32_t L_res_buf3 = comp_data[3]; // expand result bytes to 32bit to fix issues on 8-bit MCUs
uint32_t L_res_buf4 = comp_data[4];
uint32_t L_res_buf6 = comp_data[6];
uint32_t _raw_p = (L_res_buf3 << 16) | (L_res_buf4 << 8) | L_res_buf6;
// constants for presure calculation
static constexpr float _pcal[3] = { 45000.0, 80000.0, 105000.0 };
static constexpr float _lut_lower = 3.5 * 0x100000; // 1<<20
static constexpr float _lut_upper = 11.5 * 0x100000; // 1<<20
static constexpr float _quadr_factor = 1 / 16777216.0;
static constexpr float _offst_factor = 2048.0;
// calculate temperature
float _temperature_C = -45.f + 175.f / 65536.f * _raw_t;
// calculate pressure
float t = (float)(_raw_t - 32768);
float s1 = _lut_lower + (float)(_scal[0] * t * t) * _quadr_factor;
float s2 = _offst_factor * _scal[3] + (float)(_scal[1] * t * t) * _quadr_factor;
float s3 = _lut_upper + (float)(_scal[2] * t * t) * _quadr_factor;
float c = (s1 * s2 * (_pcal[0] - _pcal[1]) +
s2 * s3 * (_pcal[1] - _pcal[2]) +
s3 * s1 * (_pcal[2] - _pcal[0])) /
(s3 * (_pcal[0] - _pcal[1]) +
s1 * (_pcal[1] - _pcal[2]) +
s2 * (_pcal[2] - _pcal[0]));
float a = (_pcal[0] * s1 - _pcal[1] * s2 - (_pcal[1] - _pcal[0]) * c) / (s1 - s2);
float b = (_pcal[0] - a) * (s1 + c);
float _pressure_Pa = a + b / (c + _raw_p);
const hrt_abstime nowx = hrt_absolute_time();
float temperature = _temperature_C;
float pressure = _pressure_Pa; // to Pascal
pressure = pressure / 100.0f; // to mbar
_px4_baro.set_error_count(perf_event_count(_bad_transfer_perf));
_px4_baro.set_temperature(temperature);
_px4_baro.update(nowx, pressure);
success = true;
if (_failure_count > 0) {
_failure_count--;
}
_state = STATE::MEASURE;
} else {
perf_count(_bad_transfer_perf);
}
if (!success) {
_failure_count++;
// full reset if things are failing consistently
if (_failure_count > 10) {
Reset();
return;
}
}
ScheduleDelayed(1000_ms / 8 - _measure_interval); // 8Hz
}
break;
}
}
bool
ICP10100::Measure()
{
/*
From ds-000186-icp-101xx-v1.0.pdf, page 6, table 1
Sensor Measurement Max Time
Mode Time (Forced)
Low Power (LP) 1.6 ms 1.8 ms
Normal (N) 5.6 ms 6.3 ms
Low Noise (LN) 20.8 ms 23.8 ms
Ultra Low Noise(ULN) 83.2 ms 94.5 ms
*/
Cmd cmd;
switch (_mode) {
case MODE::FAST:
cmd = Cmd::MEAS_LP;
_measure_interval = 2_ms;
break;
case MODE::ACCURATE:
cmd = Cmd::MEAS_LN;
_measure_interval = 24_ms;
break;
case MODE::VERY_ACCURATE:
cmd = Cmd::MEAS_ULN;
_measure_interval = 95_ms;
break;
case MODE::NORMAL:
default:
cmd = Cmd::MEAS_N;
_measure_interval = 7_ms;
break;
}
if (send_command(cmd) != PX4_OK) {
return false;
}
return true;
}
int8_t
ICP10100::cal_crc(uint8_t seed, uint8_t data)
{
int8_t poly = 0x31;
int8_t var2;
uint8_t i;
for (i = 0; i < 8; i++) {
if ((seed & 0x80) ^ (data & 0x80)) {
var2 = 1;
} else {
var2 = 0;
}
seed = (seed & 0x7F) << 1;
data = (data & 0x7F) << 1;
seed = seed ^ (uint8_t)(poly * var2);
}
return (int8_t)seed;
}
int
ICP10100::read_measure_results(uint8_t *buf, uint8_t len)
{
return transfer(nullptr, 0, buf, len);
}
int
ICP10100::read_response(Cmd cmd, uint8_t *buf, uint8_t len)
{
uint8_t buff[2];
buff[0] = ((uint16_t)cmd >> 8) & 0xff;
buff[1] = (uint16_t)cmd & 0xff;
return transfer(&buff[0], 2, buf, len);
}
int
ICP10100::send_command(Cmd cmd)
{
uint8_t buf[2];
buf[0] = ((uint16_t)cmd >> 8) & 0xff;
buf[1] = (uint16_t)cmd & 0xff;
return transfer(buf, sizeof(buf), nullptr, 0);
}
int
ICP10100::send_command(Cmd cmd, uint8_t *data, uint8_t len)
{
uint8_t buf[5];
buf[0] = ((uint16_t)cmd >> 8) & 0xff;
buf[1] = (uint16_t)cmd & 0xff;
memcpy(&buf[2], data, len);
return transfer(&buf[0], len + 2, nullptr, 0);
}
+98
View File
@@ -0,0 +1,98 @@
/****************************************************************************
*
* Copyright (C) 2021 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#pragma once
#include "Inven_Sense_ICP10100_registers.hpp"
#include <drivers/drv_hrt.h>
#include <lib/drivers/device/i2c.h>
#include <lib/drivers/barometer/PX4Barometer.hpp>
#include <lib/perf/perf_counter.h>
#include <px4_platform_common/i2c_spi_buses.h>
using namespace Inven_Sense_ICP10100;
class ICP10100 : public device::I2C, public I2CSPIDriver<ICP10100>
{
public:
ICP10100(const I2CSPIDriverConfig &config);
~ICP10100() override;
static void print_usage();
void RunImpl();
int init() override;
void print_status() override;
private:
int probe() override;
bool Reset();
bool Measure();
int8_t cal_crc(uint8_t seed, uint8_t data);
int read_measure_results(uint8_t *buf, uint8_t len);
int read_response(Cmd cmd, uint8_t *buf, uint8_t len);
int send_command(Cmd cmd);
int send_command(Cmd cmd, uint8_t *data, uint8_t len);
PX4Barometer _px4_baro;
perf_counter_t _reset_perf{perf_alloc(PC_COUNT, MODULE_NAME": reset")};
perf_counter_t _sample_perf{perf_alloc(PC_ELAPSED, MODULE_NAME": read")};
perf_counter_t _bad_transfer_perf{perf_alloc(PC_COUNT, MODULE_NAME": bad transfer")};
hrt_abstime _reset_timestamp{0};
int _failure_count{0};
unsigned _measure_interval{0};
int16_t _scal[4];
enum class STATE : uint8_t {
RESET,
WAIT_FOR_RESET,
READ_OTP,
MEASURE,
READ
} _state{STATE::RESET};
enum class MODE : uint8_t {
FAST,
NORMAL,
ACCURATE,
VERY_ACCURATE
} _mode{MODE::VERY_ACCURATE};
};
@@ -0,0 +1,62 @@
/****************************************************************************
*
* Copyright (c) 2021 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file icp10100_registers.hpp
*
* icp10100 registers.
*
*/
#pragma once
#include <cstdint>
namespace Inven_Sense_ICP10100
{
static constexpr uint32_t I2C_SPEED = 100 * 1000; // 100 kHz I2C serial interface
static constexpr uint8_t I2C_ADDRESS_DEFAULT = 0x63;
static constexpr uint8_t Product_ID = 0x08;
enum class Cmd : uint16_t {
READ_ID = 0xefc8,
SET_ADDR = 0xc595,
READ_OTP = 0xc7f7,
MEAS_LP = 0x609c,
MEAS_N = 0x6825,
MEAS_LN = 0x70df,
MEAS_ULN = 0x7866,
SOFT_RESET = 0x805d
};
} // namespace Inven_Sense_ICP10100
@@ -0,0 +1,79 @@
/****************************************************************************
*
* Copyright (c) 2021 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#include <px4_platform_common/px4_config.h>
#include <px4_platform_common/getopt.h>
#include <px4_platform_common/module.h>
#include "ICP10100.hpp"
void
ICP10100::print_usage()
{
PRINT_MODULE_USAGE_NAME("icp10100", "driver");
PRINT_MODULE_USAGE_SUBCATEGORY("baro");
PRINT_MODULE_USAGE_COMMAND("start");
PRINT_MODULE_USAGE_PARAMS_I2C_SPI_DRIVER(true, false);
PRINT_MODULE_USAGE_PARAMS_I2C_ADDRESS(0x63);
PRINT_MODULE_USAGE_DEFAULT_COMMANDS();
}
extern "C" int icp10100_main(int argc, char *argv[])
{
using ThisDriver = ICP10100;
BusCLIArguments cli{true, false};
cli.i2c_address = I2C_ADDRESS_DEFAULT;
cli.default_i2c_frequency = I2C_SPEED;
const char *verb = cli.parseDefaultArguments(argc, argv);
if (!verb) {
ThisDriver::print_usage();
return -1;
}
BusInstanceIterator iterator(MODULE_NAME, cli, DRV_BARO_DEVTYPE_ICP10100);
if (!strcmp(verb, "start")) {
return ThisDriver::module_start(cli, iterator);
} else if (!strcmp(verb, "stop")) {
return ThisDriver::module_stop(iterator);
} else if (!strcmp(verb, "status")) {
return ThisDriver::module_status(iterator);
}
ThisDriver::print_usage();
return -1;
}
+46
View File
@@ -0,0 +1,46 @@
############################################################################
#
# Copyright (c) 2021 PX4 Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name PX4 nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
px4_add_module(
MODULE drivers__invensense__icp10111
MAIN icp10111
COMPILE_FLAGS
SRCS
Inven_Sense_ICP10111_registers.hpp
ICP10111.cpp
ICP10111.hpp
icp10111_main.cpp
DEPENDS
drivers_barometer
px4_work_queue
)
+375
View File
@@ -0,0 +1,375 @@
/****************************************************************************
*
* Copyright (c) 2021 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#include "ICP10111.hpp"
using namespace time_literals;
ICP10111::ICP10111(const I2CSPIDriverConfig &config) :
I2C(config),
I2CSPIDriver(config),
_px4_baro(get_device_id())
{
}
ICP10111::~ICP10111()
{
perf_free(_reset_perf);
perf_free(_sample_perf);
perf_free(_bad_transfer_perf);
}
int
ICP10111::init()
{
int ret = I2C::init();
if (ret != PX4_OK) {
DEVICE_DEBUG("I2C::init failed (%i)", ret);
return ret;
}
return Reset() ? 0 : -1;
}
bool
ICP10111::Reset()
{
_state = STATE::RESET;
ScheduleClear();
ScheduleNow();
return true;
}
void
ICP10111::print_status()
{
I2CSPIDriverBase::print_status();
perf_print_counter(_reset_perf);
perf_print_counter(_sample_perf);
perf_print_counter(_bad_transfer_perf);
}
int
ICP10111::probe()
{
uint16_t ID = 0;
read_response(Cmd::READ_ID, (uint8_t *)&ID, 2);
uint8_t PROD_ID = (ID >> 8) & 0x3f;
if (PROD_ID != Product_ID) {
DEVICE_DEBUG("unexpected PROD_ID 0x%02x", PROD_ID);
return PX4_ERROR;
}
return PX4_OK;
}
void
ICP10111::RunImpl()
{
const hrt_abstime now = hrt_absolute_time();
switch (_state) {
case STATE::RESET:
// Software Reset
send_command(Cmd::SOFT_RESET);
_reset_timestamp = now;
_failure_count = 0;
_state = STATE::WAIT_FOR_RESET;
perf_count(_reset_perf);
ScheduleDelayed(100_ms); // Power On Reset: max 100ms
break;
case STATE::WAIT_FOR_RESET: {
// check product id
uint16_t ID = 0;
read_response(Cmd::READ_ID, (uint8_t *)&ID, 2);
uint8_t PROD_ID = (ID >> 8) & 0x3f; // Product ID Bits 5:0
if (PROD_ID == Product_ID) {
// if reset succeeded then read otp
_state = STATE::READ_OTP;
ScheduleDelayed(10_ms); // Time to coefficients are available.
} else {
// RESET not complete
if (hrt_elapsed_time(&_reset_timestamp) > 1000_ms) {
PX4_DEBUG("Reset failed, retrying");
_state = STATE::RESET;
ScheduleDelayed(100_ms);
} else {
PX4_DEBUG("Reset not complete, check again in 10 ms");
ScheduleDelayed(10_ms);
}
}
}
break;
case STATE::READ_OTP: {
// read otp
uint8_t addr_otp_cmd[3] = {0x00, 0x66, 0x9c};
uint8_t otp_buf[3];
uint8_t crc;
bool success = true;
send_command(Cmd::SET_ADDR, addr_otp_cmd, 3);
for (uint8_t i = 0; i < 4; i++) {
read_response(Cmd::READ_OTP, otp_buf, 3);
crc = 0xFF;
for (int j = 0; j < 2; j++) {
crc = (uint8_t)cal_crc(crc, otp_buf[j]);
}
if (crc != otp_buf[2]) {
success = false;
break;
}
_scal[i] = (otp_buf[0] << 8) | otp_buf[1];
}
if (success) {
_state = STATE::MEASURE;
} else {
_state = STATE::RESET;
}
ScheduleDelayed(10_ms);
}
break;
case STATE::MEASURE:
if (Measure()) {
// if configure succeeded then start measurement cycle
_state = STATE::READ;
perf_begin(_sample_perf);
ScheduleDelayed(_measure_interval);
} else {
// MEASURE not complete
if (hrt_elapsed_time(&_reset_timestamp) > 1000_ms) {
PX4_DEBUG("Measure failed, resetting");
_state = STATE::RESET;
} else {
PX4_DEBUG("Measure failed, retrying");
}
ScheduleDelayed(_measure_interval);
}
break;
case STATE::READ: {
uint8_t comp_data[9] {};
bool success = false;
if (read_measure_results(comp_data, 9) == PX4_OK) {
perf_end(_sample_perf);
uint16_t _raw_t = (comp_data[0] << 8) | comp_data[1];
uint32_t L_res_buf3 = comp_data[3]; // expand result bytes to 32bit to fix issues on 8-bit MCUs
uint32_t L_res_buf4 = comp_data[4];
uint32_t L_res_buf6 = comp_data[6];
uint32_t _raw_p = (L_res_buf3 << 16) | (L_res_buf4 << 8) | L_res_buf6;
// constants for presure calculation
static constexpr float _pcal[3] = { 45000.0, 80000.0, 105000.0 };
static constexpr float _lut_lower = 3.5 * 0x100000; // 1<<20
static constexpr float _lut_upper = 11.5 * 0x100000; // 1<<20
static constexpr float _quadr_factor = 1 / 16777216.0;
static constexpr float _offst_factor = 2048.0;
// calculate temperature
float _temperature_C = -45.f + 175.f / 65536.f * _raw_t;
// calculate pressure
float t = (float)(_raw_t - 32768);
float s1 = _lut_lower + (float)(_scal[0] * t * t) * _quadr_factor;
float s2 = _offst_factor * _scal[3] + (float)(_scal[1] * t * t) * _quadr_factor;
float s3 = _lut_upper + (float)(_scal[2] * t * t) * _quadr_factor;
float c = (s1 * s2 * (_pcal[0] - _pcal[1]) +
s2 * s3 * (_pcal[1] - _pcal[2]) +
s3 * s1 * (_pcal[2] - _pcal[0])) /
(s3 * (_pcal[0] - _pcal[1]) +
s1 * (_pcal[1] - _pcal[2]) +
s2 * (_pcal[2] - _pcal[0]));
float a = (_pcal[0] * s1 - _pcal[1] * s2 - (_pcal[1] - _pcal[0]) * c) / (s1 - s2);
float b = (_pcal[0] - a) * (s1 + c);
float _pressure_Pa = a + b / (c + _raw_p);
const hrt_abstime nowx = hrt_absolute_time();
float temperature = _temperature_C;
float pressure = _pressure_Pa; // to Pascal
pressure = pressure / 100.0f; // to mbar
_px4_baro.set_error_count(perf_event_count(_bad_transfer_perf));
_px4_baro.set_temperature(temperature);
_px4_baro.update(nowx, pressure);
success = true;
if (_failure_count > 0) {
_failure_count--;
}
_state = STATE::MEASURE;
} else {
perf_count(_bad_transfer_perf);
}
if (!success) {
_failure_count++;
// full reset if things are failing consistently
if (_failure_count > 10) {
Reset();
return;
}
}
ScheduleDelayed(1000_ms / 8 - _measure_interval); // 8Hz
}
break;
}
}
bool
ICP10111::Measure()
{
/*
From ds-000186-icp-101xx-v1.0.pdf, page 6, table 1
Sensor Measurement Max Time
Mode Time (Forced)
Low Power (LP) 1.6 ms 1.8 ms
Normal (N) 5.6 ms 6.3 ms
Low Noise (LN) 20.8 ms 23.8 ms
Ultra Low Noise(ULN) 83.2 ms 94.5 ms
*/
Cmd cmd;
switch (_mode) {
case MODE::FAST:
cmd = Cmd::MEAS_LP;
_measure_interval = 2_ms;
break;
case MODE::ACCURATE:
cmd = Cmd::MEAS_LN;
_measure_interval = 24_ms;
break;
case MODE::VERY_ACCURATE:
cmd = Cmd::MEAS_ULN;
_measure_interval = 95_ms;
break;
case MODE::NORMAL:
default:
cmd = Cmd::MEAS_N;
_measure_interval = 7_ms;
break;
}
if (send_command(cmd) != PX4_OK) {
return false;
}
return true;
}
int8_t
ICP10111::cal_crc(uint8_t seed, uint8_t data)
{
int8_t poly = 0x31;
int8_t var2;
uint8_t i;
for (i = 0; i < 8; i++) {
if ((seed & 0x80) ^ (data & 0x80)) {
var2 = 1;
} else {
var2 = 0;
}
seed = (seed & 0x7F) << 1;
data = (data & 0x7F) << 1;
seed = seed ^ (uint8_t)(poly * var2);
}
return (int8_t)seed;
}
int
ICP10111::read_measure_results(uint8_t *buf, uint8_t len)
{
return transfer(nullptr, 0, buf, len);
}
int
ICP10111::read_response(Cmd cmd, uint8_t *buf, uint8_t len)
{
uint8_t buff[2];
buff[0] = ((uint16_t)cmd >> 8) & 0xff;
buff[1] = (uint16_t)cmd & 0xff;
return transfer(&buff[0], 2, buf, len);
}
int
ICP10111::send_command(Cmd cmd)
{
uint8_t buf[2];
buf[0] = ((uint16_t)cmd >> 8) & 0xff;
buf[1] = (uint16_t)cmd & 0xff;
return transfer(buf, sizeof(buf), nullptr, 0);
}
int
ICP10111::send_command(Cmd cmd, uint8_t *data, uint8_t len)
{
uint8_t buf[5];
buf[0] = ((uint16_t)cmd >> 8) & 0xff;
buf[1] = (uint16_t)cmd & 0xff;
memcpy(&buf[2], data, len);
return transfer(&buf[0], len + 2, nullptr, 0);
}
+98
View File
@@ -0,0 +1,98 @@
/****************************************************************************
*
* Copyright (C) 2021 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#pragma once
#include "Inven_Sense_ICP10111_registers.hpp"
#include <drivers/drv_hrt.h>
#include <lib/drivers/device/i2c.h>
#include <lib/drivers/barometer/PX4Barometer.hpp>
#include <lib/perf/perf_counter.h>
#include <px4_platform_common/i2c_spi_buses.h>
using namespace Inven_Sense_ICP10111;
class ICP10111 : public device::I2C, public I2CSPIDriver<ICP10111>
{
public:
ICP10111(const I2CSPIDriverConfig &config);
~ICP10111() override;
static void print_usage();
void RunImpl();
int init() override;
void print_status() override;
private:
int probe() override;
bool Reset();
bool Measure();
int8_t cal_crc(uint8_t seed, uint8_t data);
int read_measure_results(uint8_t *buf, uint8_t len);
int read_response(Cmd cmd, uint8_t *buf, uint8_t len);
int send_command(Cmd cmd);
int send_command(Cmd cmd, uint8_t *data, uint8_t len);
PX4Barometer _px4_baro;
perf_counter_t _reset_perf{perf_alloc(PC_COUNT, MODULE_NAME": reset")};
perf_counter_t _sample_perf{perf_alloc(PC_ELAPSED, MODULE_NAME": read")};
perf_counter_t _bad_transfer_perf{perf_alloc(PC_COUNT, MODULE_NAME": bad transfer")};
hrt_abstime _reset_timestamp{0};
int _failure_count{0};
unsigned _measure_interval{0};
int16_t _scal[4];
enum class STATE : uint8_t {
RESET,
WAIT_FOR_RESET,
READ_OTP,
MEASURE,
READ
} _state{STATE::RESET};
enum class MODE : uint8_t {
FAST,
NORMAL,
ACCURATE,
VERY_ACCURATE
} _mode{MODE::VERY_ACCURATE};
};
@@ -0,0 +1,62 @@
/****************************************************************************
*
* Copyright (c) 2021 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file icp10111_registers.hpp
*
* icp10111 registers.
*
*/
#pragma once
#include <cstdint>
namespace Inven_Sense_ICP10111
{
static constexpr uint32_t I2C_SPEED = 100 * 1000; // 100 kHz I2C serial interface
static constexpr uint8_t I2C_ADDRESS_DEFAULT = 0x63;
static constexpr uint8_t Product_ID = 0x08;
enum class Cmd : uint16_t {
READ_ID = 0xefc8,
SET_ADDR = 0xc595,
READ_OTP = 0xc7f7,
MEAS_LP = 0x609c,
MEAS_N = 0x6825,
MEAS_LN = 0x70df,
MEAS_ULN = 0x7866,
SOFT_RESET = 0x805d
};
} // namespace Inven_Sense_ICP10111
@@ -0,0 +1,79 @@
/****************************************************************************
*
* Copyright (c) 2021 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#include <px4_platform_common/px4_config.h>
#include <px4_platform_common/getopt.h>
#include <px4_platform_common/module.h>
#include "ICP10111.hpp"
void
ICP10111::print_usage()
{
PRINT_MODULE_USAGE_NAME("icp10111", "driver");
PRINT_MODULE_USAGE_SUBCATEGORY("baro");
PRINT_MODULE_USAGE_COMMAND("start");
PRINT_MODULE_USAGE_PARAMS_I2C_SPI_DRIVER(true, false);
PRINT_MODULE_USAGE_PARAMS_I2C_ADDRESS(0x63);
PRINT_MODULE_USAGE_DEFAULT_COMMANDS();
}
extern "C" int icp10111_main(int argc, char *argv[])
{
using ThisDriver = ICP10111;
BusCLIArguments cli{true, false};
cli.i2c_address = I2C_ADDRESS_DEFAULT;
cli.default_i2c_frequency = I2C_SPEED;
const char *verb = cli.parseDefaultArguments(argc, argv);
if (!verb) {
ThisDriver::print_usage();
return -1;
}
BusInstanceIterator iterator(MODULE_NAME, cli, DRV_BARO_DEVTYPE_ICP10111);
if (!strcmp(verb, "start")) {
return ThisDriver::module_start(cli, iterator);
} else if (!strcmp(verb, "stop")) {
return ThisDriver::module_stop(iterator);
} else if (!strcmp(verb, "status")) {
return ThisDriver::module_status(iterator);
}
ThisDriver::print_usage();
return -1;
}