mirror of
https://github.com/PX4/PX4-Autopilot.git
synced 2026-05-31 18:47:21 +08:00
Merge branch 'master' of github.com:jgoppert/Firmware into md25_dev
This commit is contained in:
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 25 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 36 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 29 KiB |
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 204 KiB |
@@ -39,28 +39,6 @@ fi
|
|||||||
#
|
#
|
||||||
param set MAV_TYPE 2
|
param set MAV_TYPE 2
|
||||||
|
|
||||||
#
|
|
||||||
# Check if PX4IO Firmware should be upgraded (from Andrew Tridgell)
|
|
||||||
#
|
|
||||||
if [ -f /fs/microsd/px4io.bin ]
|
|
||||||
then
|
|
||||||
echo "PX4IO Firmware found. Checking Upgrade.."
|
|
||||||
if cmp /fs/microsd/px4io.bin /fs/microsd/px4io.bin.current
|
|
||||||
then
|
|
||||||
echo "No newer version, skipping upgrade."
|
|
||||||
else
|
|
||||||
echo "Loading /fs/microsd/px4io.bin"
|
|
||||||
if px4io update /fs/microsd/px4io.bin > /fs/microsd/px4io_update.log
|
|
||||||
then
|
|
||||||
cp /fs/microsd/px4io.bin /fs/microsd/px4io.bin.current
|
|
||||||
echo "Flashed /fs/microsd/px4io.bin OK" >> /fs/microsd/px4io_update.log
|
|
||||||
else
|
|
||||||
echo "Failed flashing /fs/microsd/px4io.bin" >> /fs/microsd/px4io_update.log
|
|
||||||
echo "Failed to upgrade PX4IO firmware - check if PX4IO is in bootloader mode"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Start MAVLink (depends on orb)
|
# Start MAVLink (depends on orb)
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -15,20 +15,19 @@ then
|
|||||||
# Set all params here, then disable autoconfig
|
# Set all params here, then disable autoconfig
|
||||||
param set SYS_AUTOCONFIG 0
|
param set SYS_AUTOCONFIG 0
|
||||||
|
|
||||||
param set MC_ATTRATE_D 0.007
|
param set MC_ATTRATE_D 0.005
|
||||||
param set MC_ATTRATE_I 0.0
|
param set MC_ATTRATE_I 0.0
|
||||||
param set MC_ATTRATE_P 0.13
|
param set MC_ATTRATE_P 0.1
|
||||||
param set MC_ATT_D 0.0
|
param set MC_ATT_D 0.0
|
||||||
param set MC_ATT_I 0.0
|
param set MC_ATT_I 0.0
|
||||||
param set MC_ATT_P 7.0
|
param set MC_ATT_P 4.5
|
||||||
param set MC_POS_P 0.1
|
|
||||||
param set MC_RCLOSS_THR 0.0
|
param set MC_RCLOSS_THR 0.0
|
||||||
param set MC_YAWPOS_D 0.0
|
param set MC_YAWPOS_D 0.0
|
||||||
param set MC_YAWPOS_I 0.5
|
param set MC_YAWPOS_I 0.3
|
||||||
param set MC_YAWPOS_P 1.0
|
param set MC_YAWPOS_P 0.6
|
||||||
param set MC_YAWRATE_D 0.0
|
param set MC_YAWRATE_D 0.0
|
||||||
param set MC_YAWRATE_I 0.0
|
param set MC_YAWRATE_I 0.0
|
||||||
param set MC_YAWRATE_P 0.2
|
param set MC_YAWRATE_P 0.1
|
||||||
|
|
||||||
param save /fs/microsd/params
|
param save /fs/microsd/params
|
||||||
fi
|
fi
|
||||||
@@ -40,28 +39,6 @@ fi
|
|||||||
#
|
#
|
||||||
param set MAV_TYPE 2
|
param set MAV_TYPE 2
|
||||||
|
|
||||||
#
|
|
||||||
# Check if PX4IO Firmware should be upgraded (from Andrew Tridgell)
|
|
||||||
#
|
|
||||||
if [ -f /fs/microsd/px4io2.bin ]
|
|
||||||
then
|
|
||||||
echo "PX4IO Firmware found. Checking Upgrade.."
|
|
||||||
if cmp /fs/microsd/px4io2.bin /fs/microsd/px4io2.cur
|
|
||||||
then
|
|
||||||
echo "No newer version, skipping upgrade."
|
|
||||||
else
|
|
||||||
echo "Loading /fs/microsd/px4io2.bin"
|
|
||||||
if px4io update /fs/microsd/px4io2.bin > /fs/microsd/px4io2.log
|
|
||||||
then
|
|
||||||
cp /fs/microsd/px4io2.bin /fs/microsd/px4io2.cur
|
|
||||||
echo "Flashed /fs/microsd/px4io2.bin OK" >> /fs/microsd/px4io2.log
|
|
||||||
else
|
|
||||||
echo "Failed flashing /fs/microsd/px4io2.bin" >> /fs/microsd/px4io2.log
|
|
||||||
echo "Failed to upgrade PX4IO2 firmware - check if PX4IO2 is in bootloader mode"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Start MAVLink (depends on orb)
|
# Start MAVLink (depends on orb)
|
||||||
#
|
#
|
||||||
@@ -128,7 +105,7 @@ multirotor_att_control start
|
|||||||
#
|
#
|
||||||
# Start logging
|
# Start logging
|
||||||
#
|
#
|
||||||
sdlog2 start -r 20 -a -b 14
|
sdlog2 start -r 20 -a -b 16
|
||||||
|
|
||||||
#
|
#
|
||||||
# Start system state
|
# Start system state
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ then
|
|||||||
else
|
else
|
||||||
echo "using L3GD20 and LSM303D"
|
echo "using L3GD20 and LSM303D"
|
||||||
l3gd20 start
|
l3gd20 start
|
||||||
lsm303 start
|
lsm303d start
|
||||||
fi
|
fi
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -13,35 +13,46 @@ if mavlink stop
|
|||||||
then
|
then
|
||||||
echo "stopped other MAVLink instance"
|
echo "stopped other MAVLink instance"
|
||||||
fi
|
fi
|
||||||
|
sleep 2
|
||||||
mavlink start -b 230400 -d /dev/ttyACM0
|
mavlink start -b 230400 -d /dev/ttyACM0
|
||||||
|
|
||||||
if [ $MODE == autostart ]
|
# Start the commander
|
||||||
|
if commander start
|
||||||
then
|
then
|
||||||
|
echo "Commander started"
|
||||||
|
fi
|
||||||
|
|
||||||
# Start the commander
|
# Start px4io if present
|
||||||
commander start
|
if px4io start
|
||||||
|
then
|
||||||
# Start sensors
|
echo "PX4IO driver started"
|
||||||
sh /etc/init.d/rc.sensors
|
else
|
||||||
|
if fmu mode_serial
|
||||||
# Start one of the estimators
|
|
||||||
if attitude_estimator_ekf status
|
|
||||||
then
|
then
|
||||||
echo "multicopter att filter running"
|
echo "FMU driver started"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Start sensors
|
||||||
|
sh /etc/init.d/rc.sensors
|
||||||
|
|
||||||
|
# Start one of the estimators
|
||||||
|
if attitude_estimator_ekf status
|
||||||
|
then
|
||||||
|
echo "multicopter att filter running"
|
||||||
|
else
|
||||||
|
if att_pos_estimator_ekf status
|
||||||
|
then
|
||||||
|
echo "fixedwing att filter running"
|
||||||
else
|
else
|
||||||
if att_pos_estimator_ekf status
|
attitude_estimator_ekf start
|
||||||
then
|
|
||||||
echo "fixedwing att filter running"
|
|
||||||
else
|
|
||||||
attitude_estimator_ekf start
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# Start GPS
|
# Start GPS
|
||||||
if gps start
|
if gps start
|
||||||
then
|
then
|
||||||
echo "GPS started"
|
echo "GPS started"
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "MAVLink started, exiting shell.."
|
echo "MAVLink started, exiting shell.."
|
||||||
|
|||||||
@@ -81,6 +81,26 @@ else
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
#
|
||||||
|
# Check if PX4IO Firmware should be upgraded (from Andrew Tridgell)
|
||||||
|
#
|
||||||
|
if [ -f /fs/microsd/px4io.bin ]
|
||||||
|
then
|
||||||
|
echo "PX4IO Firmware found. Checking Upgrade.."
|
||||||
|
if cmp /fs/microsd/px4io.bin /fs/microsd/px4io.cur
|
||||||
|
then
|
||||||
|
echo "No newer version, skipping upgrade."
|
||||||
|
else
|
||||||
|
echo "Loading /fs/microsd/px4io.bin"
|
||||||
|
if px4io update /fs/microsd/px4io.bin > /fs/microsd/px4io.log
|
||||||
|
then
|
||||||
|
cp /fs/microsd/px4io.bin /fs/microsd/px4io.cur
|
||||||
|
echo "Flashed /fs/microsd/px4io.bin OK" >> /fs/microsd/px4io.log
|
||||||
|
else
|
||||||
|
echo "Failed flashing /fs/microsd/px4io.bin" >> /fs/microsd/px4io.log
|
||||||
|
echo "Failed to upgrade px4io firmware - check if px4io is in bootloader mode"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -121,3 +141,6 @@ if param compare SYS_AUTOSTART 31
|
|||||||
then
|
then
|
||||||
sh /etc/init.d/31_io_phantom
|
sh /etc/init.d/31_io_phantom
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# End of autostart
|
||||||
|
fi
|
||||||
|
|||||||
+534
File diff suppressed because it is too large
Load Diff
+30
-6
@@ -55,6 +55,8 @@ class SDLog2Parser:
|
|||||||
__time_msg = None
|
__time_msg = None
|
||||||
__debug_out = False
|
__debug_out = False
|
||||||
__correct_errors = False
|
__correct_errors = False
|
||||||
|
__file_name = None
|
||||||
|
__file = None
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
return
|
return
|
||||||
@@ -88,6 +90,14 @@ class SDLog2Parser:
|
|||||||
def setCorrectErrors(self, correct_errors):
|
def setCorrectErrors(self, correct_errors):
|
||||||
self.__correct_errors = correct_errors
|
self.__correct_errors = correct_errors
|
||||||
|
|
||||||
|
def setFileName(self, file_name):
|
||||||
|
self.__file_name = file_name
|
||||||
|
if file_name != None:
|
||||||
|
self.__file = open(file_name, 'w+')
|
||||||
|
else:
|
||||||
|
self.__file = None
|
||||||
|
|
||||||
|
|
||||||
def process(self, fn):
|
def process(self, fn):
|
||||||
self.reset()
|
self.reset()
|
||||||
if self.__debug_out:
|
if self.__debug_out:
|
||||||
@@ -154,10 +164,13 @@ class SDLog2Parser:
|
|||||||
show_fields = self.__msg_labels.get(msg_name, [])
|
show_fields = self.__msg_labels.get(msg_name, [])
|
||||||
self.__msg_filter_map[msg_name] = show_fields
|
self.__msg_filter_map[msg_name] = show_fields
|
||||||
for field in show_fields:
|
for field in show_fields:
|
||||||
full_label = msg_name + "." + field
|
full_label = msg_name + "_" + field
|
||||||
self.__csv_columns.append(full_label)
|
self.__csv_columns.append(full_label)
|
||||||
self.__csv_data[full_label] = None
|
self.__csv_data[full_label] = None
|
||||||
print self.__csv_delim.join(self.__csv_columns)
|
if self.__file != None:
|
||||||
|
print >> self.__file, self.__csv_delim.join(self.__csv_columns)
|
||||||
|
else:
|
||||||
|
print self.__csv_delim.join(self.__csv_columns)
|
||||||
|
|
||||||
def __printCSVRow(self):
|
def __printCSVRow(self):
|
||||||
s = []
|
s = []
|
||||||
@@ -168,7 +181,11 @@ class SDLog2Parser:
|
|||||||
else:
|
else:
|
||||||
v = str(v)
|
v = str(v)
|
||||||
s.append(v)
|
s.append(v)
|
||||||
print self.__csv_delim.join(s)
|
|
||||||
|
if self.__file != None:
|
||||||
|
print >> self.__file, self.__csv_delim.join(s)
|
||||||
|
else:
|
||||||
|
print self.__csv_delim.join(s)
|
||||||
|
|
||||||
def __parseMsgDescr(self):
|
def __parseMsgDescr(self):
|
||||||
data = struct.unpack(self.MSG_FORMAT_STRUCT, self.__buffer[self.__ptr + 3 : self.__ptr + self.MSG_FORMAT_PACKET_LEN])
|
data = struct.unpack(self.MSG_FORMAT_STRUCT, self.__buffer[self.__ptr + 3 : self.__ptr + self.MSG_FORMAT_PACKET_LEN])
|
||||||
@@ -224,7 +241,7 @@ class SDLog2Parser:
|
|||||||
for i in xrange(len(data)):
|
for i in xrange(len(data)):
|
||||||
label = msg_labels[i]
|
label = msg_labels[i]
|
||||||
if label in show_fields:
|
if label in show_fields:
|
||||||
self.__csv_data[msg_name + "." + label] = data[i]
|
self.__csv_data[msg_name + "_" + label] = data[i]
|
||||||
if self.__time_msg != None and msg_name != self.__time_msg:
|
if self.__time_msg != None and msg_name != self.__time_msg:
|
||||||
self.__csv_updated = True
|
self.__csv_updated = True
|
||||||
if self.__time_msg == None:
|
if self.__time_msg == None:
|
||||||
@@ -240,6 +257,7 @@ def _main():
|
|||||||
print "\t-n\tUse \"null\" as placeholder for empty values in CSV. Default is empty.\n"
|
print "\t-n\tUse \"null\" as placeholder for empty values in CSV. Default is empty.\n"
|
||||||
print "\t-m MSG[.field1,field2,...]\n\t\tDump only messages of specified type, and only specified fields.\n\t\tMultiple -m options allowed."
|
print "\t-m MSG[.field1,field2,...]\n\t\tDump only messages of specified type, and only specified fields.\n\t\tMultiple -m options allowed."
|
||||||
print "\t-t\tSpecify TIME message name to group data messages by time and significantly reduce duplicate output.\n"
|
print "\t-t\tSpecify TIME message name to group data messages by time and significantly reduce duplicate output.\n"
|
||||||
|
print "\t-fPrint to file instead of stdout"
|
||||||
return
|
return
|
||||||
fn = sys.argv[1]
|
fn = sys.argv[1]
|
||||||
debug_out = False
|
debug_out = False
|
||||||
@@ -247,7 +265,8 @@ def _main():
|
|||||||
msg_filter = []
|
msg_filter = []
|
||||||
csv_null = ""
|
csv_null = ""
|
||||||
csv_delim = ","
|
csv_delim = ","
|
||||||
time_msg = None
|
time_msg = "TIME"
|
||||||
|
file_name = None
|
||||||
opt = None
|
opt = None
|
||||||
for arg in sys.argv[2:]:
|
for arg in sys.argv[2:]:
|
||||||
if opt != None:
|
if opt != None:
|
||||||
@@ -257,9 +276,11 @@ def _main():
|
|||||||
csv_null = arg
|
csv_null = arg
|
||||||
elif opt == "t":
|
elif opt == "t":
|
||||||
time_msg = arg
|
time_msg = arg
|
||||||
|
elif opt == "f":
|
||||||
|
file_name = arg
|
||||||
elif opt == "m":
|
elif opt == "m":
|
||||||
show_fields = "*"
|
show_fields = "*"
|
||||||
a = arg.split(".")
|
a = arg.split("_")
|
||||||
if len(a) > 1:
|
if len(a) > 1:
|
||||||
show_fields = a[1].split(",")
|
show_fields = a[1].split(",")
|
||||||
msg_filter.append((a[0], show_fields))
|
msg_filter.append((a[0], show_fields))
|
||||||
@@ -277,6 +298,8 @@ def _main():
|
|||||||
opt = "m"
|
opt = "m"
|
||||||
elif arg == "-t":
|
elif arg == "-t":
|
||||||
opt = "t"
|
opt = "t"
|
||||||
|
elif arg == "-f":
|
||||||
|
opt = "f"
|
||||||
|
|
||||||
if csv_delim == "\\t":
|
if csv_delim == "\\t":
|
||||||
csv_delim = "\t"
|
csv_delim = "\t"
|
||||||
@@ -285,6 +308,7 @@ def _main():
|
|||||||
parser.setCSVNull(csv_null)
|
parser.setCSVNull(csv_null)
|
||||||
parser.setMsgFilter(msg_filter)
|
parser.setMsgFilter(msg_filter)
|
||||||
parser.setTimeMsg(time_msg)
|
parser.setTimeMsg(time_msg)
|
||||||
|
parser.setFileName(file_name)
|
||||||
parser.setDebugOut(debug_out)
|
parser.setDebugOut(debug_out)
|
||||||
parser.setCorrectErrors(correct_errors)
|
parser.setCorrectErrors(correct_errors)
|
||||||
parser.process(fn)
|
parser.process(fn)
|
||||||
|
|||||||
@@ -32,13 +32,16 @@ MODULES += drivers/hott/hott_sensors
|
|||||||
MODULES += drivers/blinkm
|
MODULES += drivers/blinkm
|
||||||
MODULES += drivers/mkblctrl
|
MODULES += drivers/mkblctrl
|
||||||
MODULES += drivers/md25
|
MODULES += drivers/md25
|
||||||
|
MODULES += drivers/airspeed
|
||||||
MODULES += drivers/ets_airspeed
|
MODULES += drivers/ets_airspeed
|
||||||
|
MODULES += drivers/meas_airspeed
|
||||||
MODULES += modules/sensors
|
MODULES += modules/sensors
|
||||||
|
|
||||||
#
|
#
|
||||||
# System commands
|
# System commands
|
||||||
#
|
#
|
||||||
MODULES += systemcmds/eeprom
|
MODULES += systemcmds/eeprom
|
||||||
|
MODULES += systemcmds/ramtron
|
||||||
MODULES += systemcmds/bl_update
|
MODULES += systemcmds/bl_update
|
||||||
MODULES += systemcmds/boardinfo
|
MODULES += systemcmds/boardinfo
|
||||||
MODULES += systemcmds/i2c
|
MODULES += systemcmds/i2c
|
||||||
@@ -50,6 +53,7 @@ MODULES += systemcmds/pwm
|
|||||||
MODULES += systemcmds/reboot
|
MODULES += systemcmds/reboot
|
||||||
MODULES += systemcmds/top
|
MODULES += systemcmds/top
|
||||||
MODULES += systemcmds/tests
|
MODULES += systemcmds/tests
|
||||||
|
MODULES += systemcmds/config
|
||||||
|
|
||||||
#
|
#
|
||||||
# General system control
|
# General system control
|
||||||
|
|||||||
@@ -0,0 +1,378 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 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 ets_airspeed.cpp
|
||||||
|
* @author Simon Wilks
|
||||||
|
*
|
||||||
|
* Driver for the Eagle Tree Airspeed V3 connected via I2C.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <nuttx/config.h>
|
||||||
|
|
||||||
|
#include <drivers/device/i2c.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <semaphore.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <nuttx/arch.h>
|
||||||
|
#include <nuttx/wqueue.h>
|
||||||
|
#include <nuttx/clock.h>
|
||||||
|
|
||||||
|
#include <arch/board/board.h>
|
||||||
|
|
||||||
|
#include <systemlib/airspeed.h>
|
||||||
|
#include <systemlib/err.h>
|
||||||
|
#include <systemlib/param/param.h>
|
||||||
|
#include <systemlib/perf_counter.h>
|
||||||
|
|
||||||
|
#include <drivers/drv_airspeed.h>
|
||||||
|
#include <drivers/drv_hrt.h>
|
||||||
|
|
||||||
|
#include <uORB/uORB.h>
|
||||||
|
#include <uORB/topics/differential_pressure.h>
|
||||||
|
#include <uORB/topics/subsystem_info.h>
|
||||||
|
|
||||||
|
#include <drivers/airspeed/airspeed.h>
|
||||||
|
|
||||||
|
Airspeed::Airspeed(int bus, int address, unsigned conversion_interval) :
|
||||||
|
I2C("Airspeed", AIRSPEED_DEVICE_PATH, bus, address, 100000),
|
||||||
|
_num_reports(0),
|
||||||
|
_next_report(0),
|
||||||
|
_oldest_report(0),
|
||||||
|
_reports(nullptr),
|
||||||
|
_sensor_ok(false),
|
||||||
|
_measure_ticks(0),
|
||||||
|
_collect_phase(false),
|
||||||
|
_diff_pres_offset(0.0f),
|
||||||
|
_airspeed_pub(-1),
|
||||||
|
_conversion_interval(conversion_interval),
|
||||||
|
_sample_perf(perf_alloc(PC_ELAPSED, "airspeed_read")),
|
||||||
|
_comms_errors(perf_alloc(PC_COUNT, "airspeed_comms_errors")),
|
||||||
|
_buffer_overflows(perf_alloc(PC_COUNT, "airspeed_buffer_overflows"))
|
||||||
|
{
|
||||||
|
// enable debug() calls
|
||||||
|
_debug_enabled = true;
|
||||||
|
|
||||||
|
// work_cancel in the dtor will explode if we don't do this...
|
||||||
|
memset(&_work, 0, sizeof(_work));
|
||||||
|
}
|
||||||
|
|
||||||
|
Airspeed::~Airspeed()
|
||||||
|
{
|
||||||
|
/* make sure we are truly inactive */
|
||||||
|
stop();
|
||||||
|
|
||||||
|
/* free any existing reports */
|
||||||
|
if (_reports != nullptr)
|
||||||
|
delete[] _reports;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Airspeed::init()
|
||||||
|
{
|
||||||
|
int ret = ERROR;
|
||||||
|
|
||||||
|
/* do I2C init (and probe) first */
|
||||||
|
if (I2C::init() != OK)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* allocate basic report buffers */
|
||||||
|
_num_reports = 2;
|
||||||
|
_reports = new struct differential_pressure_s[_num_reports];
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < _num_reports; i++)
|
||||||
|
_reports[i].max_differential_pressure_pa = 0;
|
||||||
|
|
||||||
|
if (_reports == nullptr)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
_oldest_report = _next_report = 0;
|
||||||
|
|
||||||
|
/* get a publish handle on the airspeed topic */
|
||||||
|
memset(&_reports[0], 0, sizeof(_reports[0]));
|
||||||
|
_airspeed_pub = orb_advertise(ORB_ID(differential_pressure), &_reports[0]);
|
||||||
|
|
||||||
|
if (_airspeed_pub < 0)
|
||||||
|
warnx("failed to create airspeed sensor object. Did you start uOrb?");
|
||||||
|
|
||||||
|
ret = OK;
|
||||||
|
/* sensor is ok, but we don't really know if it is within range */
|
||||||
|
_sensor_ok = true;
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Airspeed::probe()
|
||||||
|
{
|
||||||
|
return measure();
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Airspeed::ioctl(struct file *filp, int cmd, unsigned long arg)
|
||||||
|
{
|
||||||
|
switch (cmd) {
|
||||||
|
|
||||||
|
case SENSORIOCSPOLLRATE: {
|
||||||
|
switch (arg) {
|
||||||
|
|
||||||
|
/* switching to manual polling */
|
||||||
|
case SENSOR_POLLRATE_MANUAL:
|
||||||
|
stop();
|
||||||
|
_measure_ticks = 0;
|
||||||
|
return OK;
|
||||||
|
|
||||||
|
/* external signalling (DRDY) not supported */
|
||||||
|
case SENSOR_POLLRATE_EXTERNAL:
|
||||||
|
|
||||||
|
/* zero would be bad */
|
||||||
|
case 0:
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* set default/max polling rate */
|
||||||
|
case SENSOR_POLLRATE_MAX:
|
||||||
|
case SENSOR_POLLRATE_DEFAULT: {
|
||||||
|
/* do we need to start internal polling? */
|
||||||
|
bool want_start = (_measure_ticks == 0);
|
||||||
|
|
||||||
|
/* set interval for next measurement to minimum legal value */
|
||||||
|
_measure_ticks = USEC2TICK(_conversion_interval);
|
||||||
|
|
||||||
|
/* if we need to start the poll state machine, do it */
|
||||||
|
if (want_start)
|
||||||
|
start();
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* adjust to a legal polling interval in Hz */
|
||||||
|
default: {
|
||||||
|
/* do we need to start internal polling? */
|
||||||
|
bool want_start = (_measure_ticks == 0);
|
||||||
|
|
||||||
|
/* convert hz to tick interval via microseconds */
|
||||||
|
unsigned ticks = USEC2TICK(1000000 / arg);
|
||||||
|
|
||||||
|
/* check against maximum rate */
|
||||||
|
if (ticks < USEC2TICK(_conversion_interval))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* update interval for next measurement */
|
||||||
|
_measure_ticks = ticks;
|
||||||
|
|
||||||
|
/* if we need to start the poll state machine, do it */
|
||||||
|
if (want_start)
|
||||||
|
start();
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case SENSORIOCGPOLLRATE:
|
||||||
|
if (_measure_ticks == 0)
|
||||||
|
return SENSOR_POLLRATE_MANUAL;
|
||||||
|
|
||||||
|
return (1000 / _measure_ticks);
|
||||||
|
|
||||||
|
case SENSORIOCSQUEUEDEPTH: {
|
||||||
|
/* add one to account for the sentinel in the ring */
|
||||||
|
arg++;
|
||||||
|
|
||||||
|
/* lower bound is mandatory, upper bound is a sanity check */
|
||||||
|
if ((arg < 2) || (arg > 100))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* allocate new buffer */
|
||||||
|
struct differential_pressure_s *buf = new struct differential_pressure_s[arg];
|
||||||
|
|
||||||
|
if (nullptr == buf)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
/* reset the measurement state machine with the new buffer, free the old */
|
||||||
|
stop();
|
||||||
|
delete[] _reports;
|
||||||
|
_num_reports = arg;
|
||||||
|
_reports = buf;
|
||||||
|
start();
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SENSORIOCGQUEUEDEPTH:
|
||||||
|
return _num_reports - 1;
|
||||||
|
|
||||||
|
case SENSORIOCRESET:
|
||||||
|
/* XXX implement this */
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
case AIRSPEEDIOCSSCALE: {
|
||||||
|
struct airspeed_scale *s = (struct airspeed_scale*)arg;
|
||||||
|
_diff_pres_offset = s->offset_pa;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
case AIRSPEEDIOCGSCALE: {
|
||||||
|
struct airspeed_scale *s = (struct airspeed_scale*)arg;
|
||||||
|
s->offset_pa = _diff_pres_offset;
|
||||||
|
s->scale = 1.0f;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* give it to the superclass */
|
||||||
|
return I2C::ioctl(filp, cmd, arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
Airspeed::read(struct file *filp, char *buffer, size_t buflen)
|
||||||
|
{
|
||||||
|
unsigned count = buflen / sizeof(struct differential_pressure_s);
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
/* buffer must be large enough */
|
||||||
|
if (count < 1)
|
||||||
|
return -ENOSPC;
|
||||||
|
|
||||||
|
/* if automatic measurement is enabled */
|
||||||
|
if (_measure_ticks > 0) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* While there is space in the caller's buffer, and reports, copy them.
|
||||||
|
* Note that we may be pre-empted by the workq thread while we are doing this;
|
||||||
|
* we are careful to avoid racing with them.
|
||||||
|
*/
|
||||||
|
while (count--) {
|
||||||
|
if (_oldest_report != _next_report) {
|
||||||
|
memcpy(buffer, _reports + _oldest_report, sizeof(*_reports));
|
||||||
|
ret += sizeof(_reports[0]);
|
||||||
|
INCREMENT(_oldest_report, _num_reports);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if there was no data, warn the caller */
|
||||||
|
return ret ? ret : -EAGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* manual measurement - run one conversion */
|
||||||
|
/* XXX really it'd be nice to lock against other readers here */
|
||||||
|
do {
|
||||||
|
_oldest_report = _next_report = 0;
|
||||||
|
|
||||||
|
/* trigger a measurement */
|
||||||
|
if (OK != measure()) {
|
||||||
|
ret = -EIO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* wait for it to complete */
|
||||||
|
usleep(_conversion_interval);
|
||||||
|
|
||||||
|
/* run the collection phase */
|
||||||
|
if (OK != collect()) {
|
||||||
|
ret = -EIO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* state machine will have generated a report, copy it out */
|
||||||
|
memcpy(buffer, _reports, sizeof(*_reports));
|
||||||
|
ret = sizeof(*_reports);
|
||||||
|
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Airspeed::start()
|
||||||
|
{
|
||||||
|
/* reset the report ring and state machine */
|
||||||
|
_collect_phase = false;
|
||||||
|
_oldest_report = _next_report = 0;
|
||||||
|
|
||||||
|
/* schedule a cycle to start things */
|
||||||
|
work_queue(HPWORK, &_work, (worker_t)&Airspeed::cycle_trampoline, this, 1);
|
||||||
|
|
||||||
|
/* notify about state change */
|
||||||
|
struct subsystem_info_s info = {
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
SUBSYSTEM_TYPE_DIFFPRESSURE
|
||||||
|
};
|
||||||
|
static orb_advert_t pub = -1;
|
||||||
|
|
||||||
|
if (pub > 0) {
|
||||||
|
orb_publish(ORB_ID(subsystem_info), pub, &info);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
pub = orb_advertise(ORB_ID(subsystem_info), &info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Airspeed::stop()
|
||||||
|
{
|
||||||
|
work_cancel(HPWORK, &_work);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Airspeed::cycle_trampoline(void *arg)
|
||||||
|
{
|
||||||
|
Airspeed *dev = (Airspeed *)arg;
|
||||||
|
|
||||||
|
dev->cycle();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Airspeed::print_info()
|
||||||
|
{
|
||||||
|
perf_print_counter(_sample_perf);
|
||||||
|
perf_print_counter(_comms_errors);
|
||||||
|
perf_print_counter(_buffer_overflows);
|
||||||
|
warnx("poll interval: %u ticks", _measure_ticks);
|
||||||
|
warnx("report queue: %u (%u/%u @ %p)",
|
||||||
|
_num_reports, _oldest_report, _next_report, _reports);
|
||||||
|
}
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 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 airspeed.h
|
||||||
|
* @author Simon Wilks
|
||||||
|
*
|
||||||
|
* Generic driver for airspeed sensors connected via I2C.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <nuttx/config.h>
|
||||||
|
|
||||||
|
#include <drivers/device/i2c.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <semaphore.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <nuttx/arch.h>
|
||||||
|
#include <nuttx/wqueue.h>
|
||||||
|
#include <nuttx/clock.h>
|
||||||
|
|
||||||
|
#include <arch/board/board.h>
|
||||||
|
|
||||||
|
#include <systemlib/airspeed.h>
|
||||||
|
#include <systemlib/err.h>
|
||||||
|
#include <systemlib/param/param.h>
|
||||||
|
#include <systemlib/perf_counter.h>
|
||||||
|
|
||||||
|
#include <drivers/drv_airspeed.h>
|
||||||
|
#include <drivers/drv_hrt.h>
|
||||||
|
|
||||||
|
#include <uORB/uORB.h>
|
||||||
|
#include <uORB/topics/differential_pressure.h>
|
||||||
|
#include <uORB/topics/subsystem_info.h>
|
||||||
|
|
||||||
|
/* Default I2C bus */
|
||||||
|
#define PX4_I2C_BUS_DEFAULT PX4_I2C_BUS_EXPANSION
|
||||||
|
|
||||||
|
/* Oddly, ERROR is not defined for C++ */
|
||||||
|
#ifdef ERROR
|
||||||
|
# undef ERROR
|
||||||
|
#endif
|
||||||
|
static const int ERROR = -1;
|
||||||
|
|
||||||
|
#ifndef CONFIG_SCHED_WORKQUEUE
|
||||||
|
# error This requires CONFIG_SCHED_WORKQUEUE.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class __EXPORT Airspeed : public device::I2C
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Airspeed(int bus, int address, unsigned conversion_interval);
|
||||||
|
virtual ~Airspeed();
|
||||||
|
|
||||||
|
virtual int init();
|
||||||
|
|
||||||
|
virtual ssize_t read(struct file *filp, char *buffer, size_t buflen);
|
||||||
|
virtual int ioctl(struct file *filp, int cmd, unsigned long arg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Diagnostics - print some basic information about the driver.
|
||||||
|
*/
|
||||||
|
virtual void print_info();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual int probe();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a poll cycle; collect from the previous measurement
|
||||||
|
* and start a new one.
|
||||||
|
*/
|
||||||
|
virtual void cycle() = 0;
|
||||||
|
virtual int measure() = 0;
|
||||||
|
virtual int collect() = 0;
|
||||||
|
|
||||||
|
work_s _work;
|
||||||
|
unsigned _num_reports;
|
||||||
|
volatile unsigned _next_report;
|
||||||
|
volatile unsigned _oldest_report;
|
||||||
|
differential_pressure_s *_reports;
|
||||||
|
bool _sensor_ok;
|
||||||
|
int _measure_ticks;
|
||||||
|
bool _collect_phase;
|
||||||
|
float _diff_pres_offset;
|
||||||
|
|
||||||
|
orb_advert_t _airspeed_pub;
|
||||||
|
|
||||||
|
unsigned _conversion_interval;
|
||||||
|
|
||||||
|
perf_counter_t _sample_perf;
|
||||||
|
perf_counter_t _comms_errors;
|
||||||
|
perf_counter_t _buffer_overflows;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether the device supported by the driver is present at a
|
||||||
|
* specific address.
|
||||||
|
*
|
||||||
|
* @param address The I2C bus address to probe.
|
||||||
|
* @return True if the device is present.
|
||||||
|
*/
|
||||||
|
int probe_address(uint8_t address);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise the automatic measurement state machine and start it.
|
||||||
|
*
|
||||||
|
* @note This function is called at open and error time. It might make sense
|
||||||
|
* to make it more aggressive about resetting the bus in case of errors.
|
||||||
|
*/
|
||||||
|
void start();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop the automatic measurement state machine.
|
||||||
|
*/
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static trampoline from the workq context; because we don't have a
|
||||||
|
* generic workq wrapper yet.
|
||||||
|
*
|
||||||
|
* @param arg Instance pointer for the driver that is polling.
|
||||||
|
*/
|
||||||
|
static void cycle_trampoline(void *arg);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/* helper macro for handling report buffer indices */
|
||||||
|
#define INCREMENT(_x, _lim) do { _x++; if (_x >= _lim) _x = 0; } while(0)
|
||||||
|
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
############################################################################
|
||||||
|
#
|
||||||
|
# Copyright (c) 2013 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.
|
||||||
|
#
|
||||||
|
############################################################################
|
||||||
|
|
||||||
|
#
|
||||||
|
# Makefile to build the generic airspeed driver.
|
||||||
|
#
|
||||||
|
|
||||||
|
SRCS = airspeed.cpp
|
||||||
@@ -57,5 +57,14 @@
|
|||||||
#define _AIRSPEEDIOCBASE (0x7700)
|
#define _AIRSPEEDIOCBASE (0x7700)
|
||||||
#define __AIRSPEEDIOC(_n) (_IOC(_AIRSPEEDIOCBASE, _n))
|
#define __AIRSPEEDIOC(_n) (_IOC(_AIRSPEEDIOCBASE, _n))
|
||||||
|
|
||||||
|
#define AIRSPEEDIOCSSCALE __AIRSPEEDIOC(0)
|
||||||
|
#define AIRSPEEDIOCGSCALE __AIRSPEEDIOC(1)
|
||||||
|
|
||||||
|
|
||||||
|
/** airspeed scaling factors; out = (in * Vscale) + offset */
|
||||||
|
struct airspeed_scale {
|
||||||
|
float offset_pa;
|
||||||
|
float scale;
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* _DRV_AIRSPEED_H */
|
#endif /* _DRV_AIRSPEED_H */
|
||||||
|
|||||||
@@ -72,9 +72,7 @@
|
|||||||
#include <uORB/uORB.h>
|
#include <uORB/uORB.h>
|
||||||
#include <uORB/topics/differential_pressure.h>
|
#include <uORB/topics/differential_pressure.h>
|
||||||
#include <uORB/topics/subsystem_info.h>
|
#include <uORB/topics/subsystem_info.h>
|
||||||
|
#include <drivers/airspeed/airspeed.h>
|
||||||
/* Default I2C bus */
|
|
||||||
#define PX4_I2C_BUS_DEFAULT PX4_I2C_BUS_EXPANSION
|
|
||||||
|
|
||||||
/* I2C bus address */
|
/* I2C bus address */
|
||||||
#define I2C_ADDRESS 0x75 /* 7-bit address. 8-bit address is 0xEA */
|
#define I2C_ADDRESS 0x75 /* 7-bit address. 8-bit address is 0xEA */
|
||||||
@@ -91,336 +89,32 @@
|
|||||||
/* Measurement rate is 100Hz */
|
/* Measurement rate is 100Hz */
|
||||||
#define CONVERSION_INTERVAL (1000000 / 100) /* microseconds */
|
#define CONVERSION_INTERVAL (1000000 / 100) /* microseconds */
|
||||||
|
|
||||||
/* Oddly, ERROR is not defined for C++ */
|
class ETSAirspeed : public Airspeed
|
||||||
#ifdef ERROR
|
|
||||||
# undef ERROR
|
|
||||||
#endif
|
|
||||||
static const int ERROR = -1;
|
|
||||||
|
|
||||||
#ifndef CONFIG_SCHED_WORKQUEUE
|
|
||||||
# error This requires CONFIG_SCHED_WORKQUEUE.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class ETSAirspeed : public device::I2C
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ETSAirspeed(int bus, int address = I2C_ADDRESS);
|
ETSAirspeed(int bus, int address = I2C_ADDRESS);
|
||||||
virtual ~ETSAirspeed();
|
|
||||||
|
|
||||||
virtual int init();
|
|
||||||
|
|
||||||
virtual ssize_t read(struct file *filp, char *buffer, size_t buflen);
|
|
||||||
virtual int ioctl(struct file *filp, int cmd, unsigned long arg);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Diagnostics - print some basic information about the driver.
|
|
||||||
*/
|
|
||||||
void print_info();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual int probe();
|
|
||||||
|
|
||||||
private:
|
|
||||||
work_s _work;
|
|
||||||
unsigned _num_reports;
|
|
||||||
volatile unsigned _next_report;
|
|
||||||
volatile unsigned _oldest_report;
|
|
||||||
differential_pressure_s *_reports;
|
|
||||||
bool _sensor_ok;
|
|
||||||
int _measure_ticks;
|
|
||||||
bool _collect_phase;
|
|
||||||
int _diff_pres_offset;
|
|
||||||
|
|
||||||
orb_advert_t _airspeed_pub;
|
|
||||||
|
|
||||||
perf_counter_t _sample_perf;
|
|
||||||
perf_counter_t _comms_errors;
|
|
||||||
perf_counter_t _buffer_overflows;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test whether the device supported by the driver is present at a
|
|
||||||
* specific address.
|
|
||||||
*
|
|
||||||
* @param address The I2C bus address to probe.
|
|
||||||
* @return True if the device is present.
|
|
||||||
*/
|
|
||||||
int probe_address(uint8_t address);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialise the automatic measurement state machine and start it.
|
|
||||||
*
|
|
||||||
* @note This function is called at open and error time. It might make sense
|
|
||||||
* to make it more aggressive about resetting the bus in case of errors.
|
|
||||||
*/
|
|
||||||
void start();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stop the automatic measurement state machine.
|
|
||||||
*/
|
|
||||||
void stop();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform a poll cycle; collect from the previous measurement
|
* Perform a poll cycle; collect from the previous measurement
|
||||||
* and start a new one.
|
* and start a new one.
|
||||||
*/
|
*/
|
||||||
void cycle();
|
virtual void cycle();
|
||||||
int measure();
|
virtual int measure();
|
||||||
int collect();
|
virtual int collect();
|
||||||
|
|
||||||
/**
|
|
||||||
* Static trampoline from the workq context; because we don't have a
|
|
||||||
* generic workq wrapper yet.
|
|
||||||
*
|
|
||||||
* @param arg Instance pointer for the driver that is polling.
|
|
||||||
*/
|
|
||||||
static void cycle_trampoline(void *arg);
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* helper macro for handling report buffer indices */
|
|
||||||
#define INCREMENT(_x, _lim) do { _x++; if (_x >= _lim) _x = 0; } while(0)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Driver 'main' command.
|
* Driver 'main' command.
|
||||||
*/
|
*/
|
||||||
extern "C" __EXPORT int ets_airspeed_main(int argc, char *argv[]);
|
extern "C" __EXPORT int ets_airspeed_main(int argc, char *argv[]);
|
||||||
|
|
||||||
ETSAirspeed::ETSAirspeed(int bus, int address) :
|
ETSAirspeed::ETSAirspeed(int bus, int address) : Airspeed(bus, address,
|
||||||
I2C("ETSAirspeed", AIRSPEED_DEVICE_PATH, bus, address, 100000),
|
CONVERSION_INTERVAL)
|
||||||
_num_reports(0),
|
|
||||||
_next_report(0),
|
|
||||||
_oldest_report(0),
|
|
||||||
_reports(nullptr),
|
|
||||||
_sensor_ok(false),
|
|
||||||
_measure_ticks(0),
|
|
||||||
_collect_phase(false),
|
|
||||||
_diff_pres_offset(0),
|
|
||||||
_airspeed_pub(-1),
|
|
||||||
_sample_perf(perf_alloc(PC_ELAPSED, "ets_airspeed_read")),
|
|
||||||
_comms_errors(perf_alloc(PC_COUNT, "ets_airspeed_comms_errors")),
|
|
||||||
_buffer_overflows(perf_alloc(PC_COUNT, "ets_airspeed_buffer_overflows"))
|
|
||||||
{
|
{
|
||||||
// enable debug() calls
|
|
||||||
_debug_enabled = true;
|
|
||||||
|
|
||||||
// work_cancel in the dtor will explode if we don't do this...
|
|
||||||
memset(&_work, 0, sizeof(_work));
|
|
||||||
}
|
|
||||||
|
|
||||||
ETSAirspeed::~ETSAirspeed()
|
|
||||||
{
|
|
||||||
/* make sure we are truly inactive */
|
|
||||||
stop();
|
|
||||||
|
|
||||||
/* free any existing reports */
|
|
||||||
if (_reports != nullptr)
|
|
||||||
delete[] _reports;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
ETSAirspeed::init()
|
|
||||||
{
|
|
||||||
int ret = ERROR;
|
|
||||||
|
|
||||||
/* do I2C init (and probe) first */
|
|
||||||
if (I2C::init() != OK)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
/* allocate basic report buffers */
|
|
||||||
_num_reports = 2;
|
|
||||||
_reports = new struct differential_pressure_s[_num_reports];
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < _num_reports; i++)
|
|
||||||
_reports[i].max_differential_pressure_pa = 0;
|
|
||||||
|
|
||||||
if (_reports == nullptr)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
_oldest_report = _next_report = 0;
|
|
||||||
|
|
||||||
/* get a publish handle on the airspeed topic */
|
|
||||||
memset(&_reports[0], 0, sizeof(_reports[0]));
|
|
||||||
_airspeed_pub = orb_advertise(ORB_ID(differential_pressure), &_reports[0]);
|
|
||||||
|
|
||||||
if (_airspeed_pub < 0)
|
|
||||||
debug("failed to create airspeed sensor object. Did you start uOrb?");
|
|
||||||
|
|
||||||
ret = OK;
|
|
||||||
/* sensor is ok, but we don't really know if it is within range */
|
|
||||||
_sensor_ok = true;
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
ETSAirspeed::probe()
|
|
||||||
{
|
|
||||||
return measure();
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
ETSAirspeed::ioctl(struct file *filp, int cmd, unsigned long arg)
|
|
||||||
{
|
|
||||||
switch (cmd) {
|
|
||||||
|
|
||||||
case SENSORIOCSPOLLRATE: {
|
|
||||||
switch (arg) {
|
|
||||||
|
|
||||||
/* switching to manual polling */
|
|
||||||
case SENSOR_POLLRATE_MANUAL:
|
|
||||||
stop();
|
|
||||||
_measure_ticks = 0;
|
|
||||||
return OK;
|
|
||||||
|
|
||||||
/* external signalling (DRDY) not supported */
|
|
||||||
case SENSOR_POLLRATE_EXTERNAL:
|
|
||||||
|
|
||||||
/* zero would be bad */
|
|
||||||
case 0:
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* set default/max polling rate */
|
|
||||||
case SENSOR_POLLRATE_MAX:
|
|
||||||
case SENSOR_POLLRATE_DEFAULT: {
|
|
||||||
/* do we need to start internal polling? */
|
|
||||||
bool want_start = (_measure_ticks == 0);
|
|
||||||
|
|
||||||
/* set interval for next measurement to minimum legal value */
|
|
||||||
_measure_ticks = USEC2TICK(CONVERSION_INTERVAL);
|
|
||||||
|
|
||||||
/* if we need to start the poll state machine, do it */
|
|
||||||
if (want_start)
|
|
||||||
start();
|
|
||||||
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* adjust to a legal polling interval in Hz */
|
|
||||||
default: {
|
|
||||||
/* do we need to start internal polling? */
|
|
||||||
bool want_start = (_measure_ticks == 0);
|
|
||||||
|
|
||||||
/* convert hz to tick interval via microseconds */
|
|
||||||
unsigned ticks = USEC2TICK(1000000 / arg);
|
|
||||||
|
|
||||||
/* check against maximum rate */
|
|
||||||
if (ticks < USEC2TICK(CONVERSION_INTERVAL))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* update interval for next measurement */
|
|
||||||
_measure_ticks = ticks;
|
|
||||||
|
|
||||||
/* if we need to start the poll state machine, do it */
|
|
||||||
if (want_start)
|
|
||||||
start();
|
|
||||||
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case SENSORIOCGPOLLRATE:
|
|
||||||
if (_measure_ticks == 0)
|
|
||||||
return SENSOR_POLLRATE_MANUAL;
|
|
||||||
|
|
||||||
return (1000 / _measure_ticks);
|
|
||||||
|
|
||||||
case SENSORIOCSQUEUEDEPTH: {
|
|
||||||
/* add one to account for the sentinel in the ring */
|
|
||||||
arg++;
|
|
||||||
|
|
||||||
/* lower bound is mandatory, upper bound is a sanity check */
|
|
||||||
if ((arg < 2) || (arg > 100))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* allocate new buffer */
|
|
||||||
struct differential_pressure_s *buf = new struct differential_pressure_s[arg];
|
|
||||||
|
|
||||||
if (nullptr == buf)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
/* reset the measurement state machine with the new buffer, free the old */
|
|
||||||
stop();
|
|
||||||
delete[] _reports;
|
|
||||||
_num_reports = arg;
|
|
||||||
_reports = buf;
|
|
||||||
start();
|
|
||||||
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
case SENSORIOCGQUEUEDEPTH:
|
|
||||||
return _num_reports - 1;
|
|
||||||
|
|
||||||
case SENSORIOCRESET:
|
|
||||||
/* XXX implement this */
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
default:
|
|
||||||
/* give it to the superclass */
|
|
||||||
return I2C::ioctl(filp, cmd, arg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t
|
|
||||||
ETSAirspeed::read(struct file *filp, char *buffer, size_t buflen)
|
|
||||||
{
|
|
||||||
unsigned count = buflen / sizeof(struct differential_pressure_s);
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
/* buffer must be large enough */
|
|
||||||
if (count < 1)
|
|
||||||
return -ENOSPC;
|
|
||||||
|
|
||||||
/* if automatic measurement is enabled */
|
|
||||||
if (_measure_ticks > 0) {
|
|
||||||
|
|
||||||
/*
|
|
||||||
* While there is space in the caller's buffer, and reports, copy them.
|
|
||||||
* Note that we may be pre-empted by the workq thread while we are doing this;
|
|
||||||
* we are careful to avoid racing with them.
|
|
||||||
*/
|
|
||||||
while (count--) {
|
|
||||||
if (_oldest_report != _next_report) {
|
|
||||||
memcpy(buffer, _reports + _oldest_report, sizeof(*_reports));
|
|
||||||
ret += sizeof(_reports[0]);
|
|
||||||
INCREMENT(_oldest_report, _num_reports);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if there was no data, warn the caller */
|
|
||||||
return ret ? ret : -EAGAIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* manual measurement - run one conversion */
|
|
||||||
/* XXX really it'd be nice to lock against other readers here */
|
|
||||||
do {
|
|
||||||
_oldest_report = _next_report = 0;
|
|
||||||
|
|
||||||
/* trigger a measurement */
|
|
||||||
if (OK != measure()) {
|
|
||||||
ret = -EIO;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* wait for it to complete */
|
|
||||||
usleep(CONVERSION_INTERVAL);
|
|
||||||
|
|
||||||
/* run the collection phase */
|
|
||||||
if (OK != collect()) {
|
|
||||||
ret = -EIO;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* state machine will have generated a report, copy it out */
|
|
||||||
memcpy(buffer, _reports, sizeof(*_reports));
|
|
||||||
ret = sizeof(*_reports);
|
|
||||||
|
|
||||||
} while (0);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -463,9 +157,15 @@ ETSAirspeed::collect()
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint16_t diff_pres_pa = val[1] << 8 | val[0];
|
uint16_t diff_pres_pa = val[1] << 8 | val[0];
|
||||||
|
if (diff_pres_pa == 0) {
|
||||||
|
// a zero value means the pressure sensor cannot give us a
|
||||||
|
// value. We need to return, and not report a value or the
|
||||||
|
// caller could end up using this value as part of an
|
||||||
|
// average
|
||||||
|
log("zero value from sensor");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
// XXX move the parameter read out of the driver.
|
|
||||||
param_get(param_find("SENS_DPRES_OFF"), &_diff_pres_offset);
|
|
||||||
if (diff_pres_pa < _diff_pres_offset + MIN_ACCURATE_DIFF_PRES_PA) {
|
if (diff_pres_pa < _diff_pres_offset + MIN_ACCURATE_DIFF_PRES_PA) {
|
||||||
diff_pres_pa = 0;
|
diff_pres_pa = 0;
|
||||||
|
|
||||||
@@ -505,47 +205,6 @@ ETSAirspeed::collect()
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
ETSAirspeed::start()
|
|
||||||
{
|
|
||||||
/* reset the report ring and state machine */
|
|
||||||
_collect_phase = false;
|
|
||||||
_oldest_report = _next_report = 0;
|
|
||||||
|
|
||||||
/* schedule a cycle to start things */
|
|
||||||
work_queue(HPWORK, &_work, (worker_t)&ETSAirspeed::cycle_trampoline, this, 1);
|
|
||||||
|
|
||||||
/* notify about state change */
|
|
||||||
struct subsystem_info_s info = {
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
SUBSYSTEM_TYPE_DIFFPRESSURE
|
|
||||||
};
|
|
||||||
static orb_advert_t pub = -1;
|
|
||||||
|
|
||||||
if (pub > 0) {
|
|
||||||
orb_publish(ORB_ID(subsystem_info), pub, &info);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
pub = orb_advertise(ORB_ID(subsystem_info), &info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ETSAirspeed::stop()
|
|
||||||
{
|
|
||||||
work_cancel(HPWORK, &_work);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ETSAirspeed::cycle_trampoline(void *arg)
|
|
||||||
{
|
|
||||||
ETSAirspeed *dev = (ETSAirspeed *)arg;
|
|
||||||
|
|
||||||
dev->cycle();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ETSAirspeed::cycle()
|
ETSAirspeed::cycle()
|
||||||
{
|
{
|
||||||
@@ -571,7 +230,7 @@ ETSAirspeed::cycle()
|
|||||||
/* schedule a fresh cycle call when we are ready to measure again */
|
/* schedule a fresh cycle call when we are ready to measure again */
|
||||||
work_queue(HPWORK,
|
work_queue(HPWORK,
|
||||||
&_work,
|
&_work,
|
||||||
(worker_t)&ETSAirspeed::cycle_trampoline,
|
(worker_t)&Airspeed::cycle_trampoline,
|
||||||
this,
|
this,
|
||||||
_measure_ticks - USEC2TICK(CONVERSION_INTERVAL));
|
_measure_ticks - USEC2TICK(CONVERSION_INTERVAL));
|
||||||
|
|
||||||
@@ -589,22 +248,11 @@ ETSAirspeed::cycle()
|
|||||||
/* schedule a fresh cycle call when the measurement is done */
|
/* schedule a fresh cycle call when the measurement is done */
|
||||||
work_queue(HPWORK,
|
work_queue(HPWORK,
|
||||||
&_work,
|
&_work,
|
||||||
(worker_t)&ETSAirspeed::cycle_trampoline,
|
(worker_t)&Airspeed::cycle_trampoline,
|
||||||
this,
|
this,
|
||||||
USEC2TICK(CONVERSION_INTERVAL));
|
USEC2TICK(CONVERSION_INTERVAL));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
ETSAirspeed::print_info()
|
|
||||||
{
|
|
||||||
perf_print_counter(_sample_perf);
|
|
||||||
perf_print_counter(_comms_errors);
|
|
||||||
perf_print_counter(_buffer_overflows);
|
|
||||||
printf("poll interval: %u ticks\n", _measure_ticks);
|
|
||||||
printf("report queue: %u (%u/%u @ %p)\n",
|
|
||||||
_num_reports, _oldest_report, _next_report, _reports);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local functions in support of the shell command.
|
* Local functions in support of the shell command.
|
||||||
*/
|
*/
|
||||||
@@ -642,7 +290,7 @@ start(int i2c_bus)
|
|||||||
if (g_dev == nullptr)
|
if (g_dev == nullptr)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (OK != g_dev->init())
|
if (OK != g_dev->Airspeed::init())
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* set the poll rate to default, starts automatic data collection */
|
/* set the poll rate to default, starts automatic data collection */
|
||||||
@@ -779,11 +427,11 @@ info()
|
|||||||
static void
|
static void
|
||||||
ets_airspeed_usage()
|
ets_airspeed_usage()
|
||||||
{
|
{
|
||||||
fprintf(stderr, "usage: ets_airspeed command [options]\n");
|
warnx("usage: ets_airspeed command [options]");
|
||||||
fprintf(stderr, "options:\n");
|
warnx("options:");
|
||||||
fprintf(stderr, "\t-b --bus i2cbus (%d)\n", PX4_I2C_BUS_DEFAULT);
|
warnx("\t-b --bus i2cbus (%d)", PX4_I2C_BUS_DEFAULT);
|
||||||
fprintf(stderr, "command:\n");
|
warnx("command:");
|
||||||
fprintf(stderr, "\tstart|stop|reset|test|info\n");
|
warnx("\tstart|stop|reset|test|info");
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|||||||
@@ -36,6 +36,6 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
MODULE_COMMAND = ets_airspeed
|
MODULE_COMMAND = ets_airspeed
|
||||||
MODULE_STACKSIZE = 1024
|
MODULE_STACKSIZE = 2048
|
||||||
|
|
||||||
SRCS = ets_airspeed.cpp
|
SRCS = ets_airspeed.cpp
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,41 @@
|
|||||||
|
############################################################################
|
||||||
|
#
|
||||||
|
# Copyright (c) 2013 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.
|
||||||
|
#
|
||||||
|
############################################################################
|
||||||
|
|
||||||
|
#
|
||||||
|
# Makefile to build the MEAS Spec airspeed sensor driver.
|
||||||
|
#
|
||||||
|
|
||||||
|
MODULE_COMMAND = meas_airspeed
|
||||||
|
MODULE_STACKSIZE = 2048
|
||||||
|
|
||||||
|
SRCS = meas_airspeed.cpp
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012 PX4 Development Team. All rights reserved.
|
* Copyright (c) 2012, 2013 PX4 Development Team. All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
@@ -35,6 +35,9 @@
|
|||||||
* @file mpu6000.cpp
|
* @file mpu6000.cpp
|
||||||
*
|
*
|
||||||
* Driver for the Invensense MPU6000 connected via SPI.
|
* Driver for the Invensense MPU6000 connected via SPI.
|
||||||
|
*
|
||||||
|
* @author Andrew Tridgell
|
||||||
|
* @author Pat Hickey
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <nuttx/config.h>
|
#include <nuttx/config.h>
|
||||||
@@ -191,6 +194,7 @@ private:
|
|||||||
orb_advert_t _gyro_topic;
|
orb_advert_t _gyro_topic;
|
||||||
|
|
||||||
unsigned _reads;
|
unsigned _reads;
|
||||||
|
unsigned _sample_rate;
|
||||||
perf_counter_t _sample_perf;
|
perf_counter_t _sample_perf;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -314,6 +318,7 @@ MPU6000::MPU6000(int bus, spi_dev_e device) :
|
|||||||
_gyro_range_rad_s(0.0f),
|
_gyro_range_rad_s(0.0f),
|
||||||
_gyro_topic(-1),
|
_gyro_topic(-1),
|
||||||
_reads(0),
|
_reads(0),
|
||||||
|
_sample_rate(500),
|
||||||
_sample_perf(perf_alloc(PC_ELAPSED, "mpu6000_read"))
|
_sample_perf(perf_alloc(PC_ELAPSED, "mpu6000_read"))
|
||||||
{
|
{
|
||||||
// disable debug() calls
|
// disable debug() calls
|
||||||
@@ -366,10 +371,6 @@ MPU6000::init()
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* advertise sensor topics */
|
|
||||||
_accel_topic = orb_advertise(ORB_ID(sensor_accel), &_accel_report);
|
|
||||||
_gyro_topic = orb_advertise(ORB_ID(sensor_gyro), &_gyro_report);
|
|
||||||
|
|
||||||
// Chip reset
|
// Chip reset
|
||||||
write_reg(MPUREG_PWR_MGMT_1, BIT_H_RESET);
|
write_reg(MPUREG_PWR_MGMT_1, BIT_H_RESET);
|
||||||
up_udelay(10000);
|
up_udelay(10000);
|
||||||
@@ -384,7 +385,7 @@ MPU6000::init()
|
|||||||
|
|
||||||
// SAMPLE RATE
|
// SAMPLE RATE
|
||||||
//write_reg(MPUREG_SMPLRT_DIV, 0x04); // Sample rate = 200Hz Fsample= 1Khz/(4+1) = 200Hz
|
//write_reg(MPUREG_SMPLRT_DIV, 0x04); // Sample rate = 200Hz Fsample= 1Khz/(4+1) = 200Hz
|
||||||
_set_sample_rate(200); // default sample rate = 200Hz
|
_set_sample_rate(_sample_rate); // default sample rate = 200Hz
|
||||||
usleep(1000);
|
usleep(1000);
|
||||||
|
|
||||||
// FS & DLPF FS=2000 deg/s, DLPF = 20Hz (low pass filter)
|
// FS & DLPF FS=2000 deg/s, DLPF = 20Hz (low pass filter)
|
||||||
@@ -463,10 +464,18 @@ MPU6000::init()
|
|||||||
/* do CDev init for the gyro device node, keep it optional */
|
/* do CDev init for the gyro device node, keep it optional */
|
||||||
int gyro_ret = _gyro->init();
|
int gyro_ret = _gyro->init();
|
||||||
|
|
||||||
|
/* ensure we got real values to share */
|
||||||
|
measure();
|
||||||
|
|
||||||
if (gyro_ret != OK) {
|
if (gyro_ret != OK) {
|
||||||
_gyro_topic = -1;
|
_gyro_topic = -1;
|
||||||
|
} else {
|
||||||
|
_gyro_topic = orb_advertise(ORB_ID(sensor_gyro), &_gyro_report);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* advertise sensor topics */
|
||||||
|
_accel_topic = orb_advertise(ORB_ID(sensor_accel), &_accel_report);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -509,6 +518,7 @@ MPU6000::_set_sample_rate(uint16_t desired_sample_rate_hz)
|
|||||||
if(div>200) div=200;
|
if(div>200) div=200;
|
||||||
if(div<1) div=1;
|
if(div<1) div=1;
|
||||||
write_reg(MPUREG_SMPLRT_DIV, div-1);
|
write_reg(MPUREG_SMPLRT_DIV, div-1);
|
||||||
|
_sample_rate = 1000 / div;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -660,8 +670,10 @@ MPU6000::ioctl(struct file *filp, int cmd, unsigned long arg)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
|
||||||
case ACCELIOCSSAMPLERATE:
|
|
||||||
case ACCELIOCGSAMPLERATE:
|
case ACCELIOCGSAMPLERATE:
|
||||||
|
return _sample_rate;
|
||||||
|
|
||||||
|
case ACCELIOCSSAMPLERATE:
|
||||||
_set_sample_rate(arg);
|
_set_sample_rate(arg);
|
||||||
return OK;
|
return OK;
|
||||||
|
|
||||||
@@ -689,12 +701,13 @@ MPU6000::ioctl(struct file *filp, int cmd, unsigned long arg)
|
|||||||
return OK;
|
return OK;
|
||||||
|
|
||||||
case ACCELIOCSRANGE:
|
case ACCELIOCSRANGE:
|
||||||
case ACCELIOCGRANGE:
|
|
||||||
/* XXX not implemented */
|
/* XXX not implemented */
|
||||||
// XXX change these two values on set:
|
// XXX change these two values on set:
|
||||||
// _accel_range_scale = (9.81f / 4096.0f);
|
// _accel_range_scale = (9.81f / 4096.0f);
|
||||||
// _accel_range_rad_s = 8.0f * 9.81f;
|
// _accel_range_m_s2 = 8.0f * 9.81f;
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
case ACCELIOCGRANGE:
|
||||||
|
return _accel_range_m_s2;
|
||||||
|
|
||||||
case ACCELIOCSELFTEST:
|
case ACCELIOCSELFTEST:
|
||||||
return self_test();
|
return self_test();
|
||||||
@@ -718,10 +731,12 @@ MPU6000::gyro_ioctl(struct file *filp, int cmd, unsigned long arg)
|
|||||||
case SENSORIOCRESET:
|
case SENSORIOCRESET:
|
||||||
return ioctl(filp, cmd, arg);
|
return ioctl(filp, cmd, arg);
|
||||||
|
|
||||||
case GYROIOCSSAMPLERATE:
|
|
||||||
case GYROIOCGSAMPLERATE:
|
case GYROIOCGSAMPLERATE:
|
||||||
_set_sample_rate(arg);
|
return _sample_rate;
|
||||||
return OK;
|
|
||||||
|
case GYROIOCSSAMPLERATE:
|
||||||
|
_set_sample_rate(arg);
|
||||||
|
return OK;
|
||||||
|
|
||||||
case GYROIOCSLOWPASS:
|
case GYROIOCSLOWPASS:
|
||||||
case GYROIOCGLOWPASS:
|
case GYROIOCGLOWPASS:
|
||||||
@@ -739,12 +754,13 @@ MPU6000::gyro_ioctl(struct file *filp, int cmd, unsigned long arg)
|
|||||||
return OK;
|
return OK;
|
||||||
|
|
||||||
case GYROIOCSRANGE:
|
case GYROIOCSRANGE:
|
||||||
case GYROIOCGRANGE:
|
|
||||||
/* XXX not implemented */
|
/* XXX not implemented */
|
||||||
// XXX change these two values on set:
|
// XXX change these two values on set:
|
||||||
// _gyro_range_scale = xx
|
// _gyro_range_scale = xx
|
||||||
// _gyro_range_m_s2 = xx
|
// _gyro_range_rad_s = xx
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
case GYROIOCGRANGE:
|
||||||
|
return _gyro_range_rad_s;
|
||||||
|
|
||||||
case GYROIOCSELFTEST:
|
case GYROIOCSELFTEST:
|
||||||
return self_test();
|
return self_test();
|
||||||
|
|||||||
@@ -268,8 +268,8 @@ int detect_orientation(int mavlink_fd, int sub_sensor_combined) {
|
|||||||
float accel_disp[3] = { 0.0f, 0.0f, 0.0f };
|
float accel_disp[3] = { 0.0f, 0.0f, 0.0f };
|
||||||
/* EMA time constant in seconds*/
|
/* EMA time constant in seconds*/
|
||||||
float ema_len = 0.2f;
|
float ema_len = 0.2f;
|
||||||
/* set "still" threshold to 0.1 m/s^2 */
|
/* set "still" threshold to 0.25 m/s^2 */
|
||||||
float still_thr2 = pow(0.1f, 2);
|
float still_thr2 = pow(0.25f, 2);
|
||||||
/* set accel error threshold to 5m/s^2 */
|
/* set accel error threshold to 5m/s^2 */
|
||||||
float accel_err_thr = 5.0f;
|
float accel_err_thr = 5.0f;
|
||||||
/* still time required in us */
|
/* still time required in us */
|
||||||
|
|||||||
@@ -587,6 +587,8 @@ void do_gyro_calibration(int status_pub, struct vehicle_status_s *status)
|
|||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
|
int errcount = 0;
|
||||||
|
|
||||||
while (calibration_counter < calibration_count) {
|
while (calibration_counter < calibration_count) {
|
||||||
|
|
||||||
/* wait blocking for new data */
|
/* wait blocking for new data */
|
||||||
@@ -602,8 +604,12 @@ void do_gyro_calibration(int status_pub, struct vehicle_status_s *status)
|
|||||||
calibration_counter++;
|
calibration_counter++;
|
||||||
|
|
||||||
} else if (poll_ret == 0) {
|
} else if (poll_ret == 0) {
|
||||||
/* any poll failure for 1s is a reason to abort */
|
errcount++;
|
||||||
mavlink_log_info(mavlink_fd, "gyro calibration aborted, retry");
|
}
|
||||||
|
|
||||||
|
if (errcount > 1000) {
|
||||||
|
/* any persisting poll error is a reason to abort */
|
||||||
|
mavlink_log_info(mavlink_fd, "permanent gyro error, aborted.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ PARAM_DEFINE_FLOAT(SENS_ACC_XSCALE, 1.0f);
|
|||||||
PARAM_DEFINE_FLOAT(SENS_ACC_YSCALE, 1.0f);
|
PARAM_DEFINE_FLOAT(SENS_ACC_YSCALE, 1.0f);
|
||||||
PARAM_DEFINE_FLOAT(SENS_ACC_ZSCALE, 1.0f);
|
PARAM_DEFINE_FLOAT(SENS_ACC_ZSCALE, 1.0f);
|
||||||
|
|
||||||
PARAM_DEFINE_INT32(SENS_DPRES_OFF, 1667);
|
PARAM_DEFINE_FLOAT(SENS_DPRES_OFF, 1667);
|
||||||
|
|
||||||
PARAM_DEFINE_FLOAT(RC1_MIN, 1000.0f);
|
PARAM_DEFINE_FLOAT(RC1_MIN, 1000.0f);
|
||||||
PARAM_DEFINE_FLOAT(RC1_TRIM, 1500.0f);
|
PARAM_DEFINE_FLOAT(RC1_TRIM, 1500.0f);
|
||||||
|
|||||||
@@ -60,6 +60,7 @@
|
|||||||
#include <drivers/drv_baro.h>
|
#include <drivers/drv_baro.h>
|
||||||
#include <drivers/drv_rc_input.h>
|
#include <drivers/drv_rc_input.h>
|
||||||
#include <drivers/drv_adc.h>
|
#include <drivers/drv_adc.h>
|
||||||
|
#include <drivers/drv_airspeed.h>
|
||||||
|
|
||||||
#include <systemlib/systemlib.h>
|
#include <systemlib/systemlib.h>
|
||||||
#include <systemlib/param/param.h>
|
#include <systemlib/param/param.h>
|
||||||
@@ -197,7 +198,7 @@ private:
|
|||||||
float mag_scale[3];
|
float mag_scale[3];
|
||||||
float accel_offset[3];
|
float accel_offset[3];
|
||||||
float accel_scale[3];
|
float accel_scale[3];
|
||||||
int diff_pres_offset_pa;
|
float diff_pres_offset_pa;
|
||||||
|
|
||||||
int rc_type;
|
int rc_type;
|
||||||
|
|
||||||
@@ -230,6 +231,7 @@ private:
|
|||||||
float battery_voltage_scaling;
|
float battery_voltage_scaling;
|
||||||
|
|
||||||
int rc_rl1_DSM_VCC_control;
|
int rc_rl1_DSM_VCC_control;
|
||||||
|
|
||||||
} _parameters; /**< local copies of interesting parameters */
|
} _parameters; /**< local copies of interesting parameters */
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
@@ -280,6 +282,7 @@ private:
|
|||||||
param_t battery_voltage_scaling;
|
param_t battery_voltage_scaling;
|
||||||
|
|
||||||
param_t rc_rl1_DSM_VCC_control;
|
param_t rc_rl1_DSM_VCC_control;
|
||||||
|
|
||||||
} _parameter_handles; /**< handles for interesting parameters */
|
} _parameter_handles; /**< handles for interesting parameters */
|
||||||
|
|
||||||
|
|
||||||
@@ -391,7 +394,7 @@ namespace sensors
|
|||||||
#endif
|
#endif
|
||||||
static const int ERROR = -1;
|
static const int ERROR = -1;
|
||||||
|
|
||||||
Sensors *g_sensors;
|
Sensors *g_sensors = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Sensors::Sensors() :
|
Sensors::Sensors() :
|
||||||
@@ -554,25 +557,11 @@ Sensors::parameters_update()
|
|||||||
/* rc values */
|
/* rc values */
|
||||||
for (unsigned int i = 0; i < RC_CHANNELS_MAX; i++) {
|
for (unsigned int i = 0; i < RC_CHANNELS_MAX; i++) {
|
||||||
|
|
||||||
if (param_get(_parameter_handles.min[i], &(_parameters.min[i])) != OK) {
|
param_get(_parameter_handles.min[i], &(_parameters.min[i]));
|
||||||
warnx("Failed getting min for chan %d", i);
|
param_get(_parameter_handles.trim[i], &(_parameters.trim[i]));
|
||||||
}
|
param_get(_parameter_handles.max[i], &(_parameters.max[i]));
|
||||||
|
param_get(_parameter_handles.rev[i], &(_parameters.rev[i]));
|
||||||
if (param_get(_parameter_handles.trim[i], &(_parameters.trim[i])) != OK) {
|
param_get(_parameter_handles.dz[i], &(_parameters.dz[i]));
|
||||||
warnx("Failed getting trim for chan %d", i);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (param_get(_parameter_handles.max[i], &(_parameters.max[i])) != OK) {
|
|
||||||
warnx("Failed getting max for chan %d", i);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (param_get(_parameter_handles.rev[i], &(_parameters.rev[i])) != OK) {
|
|
||||||
warnx("Failed getting rev for chan %d", i);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (param_get(_parameter_handles.dz[i], &(_parameters.dz[i])) != OK) {
|
|
||||||
warnx("Failed getting dead zone for chan %d", i);
|
|
||||||
}
|
|
||||||
|
|
||||||
_parameters.scaling_factor[i] = (1.0f / ((_parameters.max[i] - _parameters.min[i]) / 2.0f) * _parameters.rev[i]);
|
_parameters.scaling_factor[i] = (1.0f / ((_parameters.max[i] - _parameters.min[i]) / 2.0f) * _parameters.rev[i]);
|
||||||
|
|
||||||
@@ -662,21 +651,10 @@ Sensors::parameters_update()
|
|||||||
warnx("Failed getting mode aux 5 index");
|
warnx("Failed getting mode aux 5 index");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (param_get(_parameter_handles.rc_scale_roll, &(_parameters.rc_scale_roll)) != OK) {
|
param_get(_parameter_handles.rc_scale_roll, &(_parameters.rc_scale_roll));
|
||||||
warnx("Failed getting rc scaling for roll");
|
param_get(_parameter_handles.rc_scale_pitch, &(_parameters.rc_scale_pitch));
|
||||||
}
|
param_get(_parameter_handles.rc_scale_yaw, &(_parameters.rc_scale_yaw));
|
||||||
|
param_get(_parameter_handles.rc_scale_flaps, &(_parameters.rc_scale_flaps));
|
||||||
if (param_get(_parameter_handles.rc_scale_pitch, &(_parameters.rc_scale_pitch)) != OK) {
|
|
||||||
warnx("Failed getting rc scaling for pitch");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (param_get(_parameter_handles.rc_scale_yaw, &(_parameters.rc_scale_yaw)) != OK) {
|
|
||||||
warnx("Failed getting rc scaling for yaw");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (param_get(_parameter_handles.rc_scale_flaps, &(_parameters.rc_scale_flaps)) != OK) {
|
|
||||||
warnx("Failed getting rc scaling for flaps");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* update RC function mappings */
|
/* update RC function mappings */
|
||||||
_rc.function[THROTTLE] = _parameters.rc_map_throttle - 1;
|
_rc.function[THROTTLE] = _parameters.rc_map_throttle - 1;
|
||||||
@@ -1041,6 +1019,20 @@ Sensors::parameter_update_poll(bool forced)
|
|||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
|
fd = open(AIRSPEED_DEVICE_PATH, 0);
|
||||||
|
|
||||||
|
/* this sensor is optional, abort without error */
|
||||||
|
|
||||||
|
if (fd > 0) {
|
||||||
|
struct airspeed_scale airscale = {
|
||||||
|
_parameters.diff_pres_offset_pa,
|
||||||
|
1.0f,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (OK != ioctl(fd, AIRSPEEDIOCSSCALE, (long unsigned int)&airscale))
|
||||||
|
warn("WARNING: failed to set scale / offsets for airspeed sensor");
|
||||||
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
printf("CH0: RAW MAX: %d MIN %d S: %d MID: %d FUNC: %d\n", (int)_parameters.max[0], (int)_parameters.min[0], (int)(_rc.chan[0].scaling_factor * 10000), (int)(_rc.chan[0].mid), (int)_rc.function[0]);
|
printf("CH0: RAW MAX: %d MIN %d S: %d MID: %d FUNC: %d\n", (int)_parameters.max[0], (int)_parameters.min[0], (int)(_rc.chan[0].scaling_factor * 10000), (int)(_rc.chan[0].mid), (int)_rc.function[0]);
|
||||||
printf("CH1: RAW MAX: %d MIN %d S: %d MID: %d FUNC: %d\n", (int)_parameters.max[1], (int)_parameters.min[1], (int)(_rc.chan[1].scaling_factor * 10000), (int)(_rc.chan[1].mid), (int)_rc.function[1]);
|
printf("CH1: RAW MAX: %d MIN %d S: %d MID: %d FUNC: %d\n", (int)_parameters.max[1], (int)_parameters.min[1], (int)(_rc.chan[1].scaling_factor * 10000), (int)(_rc.chan[1].mid), (int)_rc.function[1]);
|
||||||
|
|||||||
@@ -0,0 +1,200 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012, 2013 PX4 Development Team. All rights reserved.
|
||||||
|
* Author: Lorenz Meier <lm@inf.ethz.ch>
|
||||||
|
*
|
||||||
|
* 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 config.c
|
||||||
|
* @author Lorenz Meier <lm@inf.ethz.ch>
|
||||||
|
*
|
||||||
|
* config tool.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <nuttx/config.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <arch/board/board.h>
|
||||||
|
|
||||||
|
#include <drivers/drv_gyro.h>
|
||||||
|
#include <drivers/drv_accel.h>
|
||||||
|
#include <drivers/drv_mag.h>
|
||||||
|
|
||||||
|
#include "systemlib/systemlib.h"
|
||||||
|
#include "systemlib/err.h"
|
||||||
|
|
||||||
|
__EXPORT int config_main(int argc, char *argv[]);
|
||||||
|
|
||||||
|
static void do_gyro(int argc, char *argv[]);
|
||||||
|
static void do_accel(int argc, char *argv[]);
|
||||||
|
static void do_mag(int argc, char *argv[]);
|
||||||
|
|
||||||
|
int
|
||||||
|
config_main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
if (argc >= 2) {
|
||||||
|
if (!strcmp(argv[1], "gyro")) {
|
||||||
|
if (argc >= 3) {
|
||||||
|
do_gyro(argc - 2, argv + 2);
|
||||||
|
} else {
|
||||||
|
errx(1, "not enough parameters.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(argv[1], "accel")) {
|
||||||
|
if (argc >= 3) {
|
||||||
|
do_accel(argc - 2, argv + 2);
|
||||||
|
} else {
|
||||||
|
errx(1, "not enough parameters.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(argv[1], "mag")) {
|
||||||
|
if (argc >= 3) {
|
||||||
|
do_mag(argc - 2, argv + 2);
|
||||||
|
} else {
|
||||||
|
errx(1, "not enough parameters.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
errx(1, "expected a command, try 'gyro', 'accel', 'mag'");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
do_gyro(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = open(GYRO_DEVICE_PATH, 0);
|
||||||
|
|
||||||
|
if (fd < 0) {
|
||||||
|
warn("%s", GYRO_DEVICE_PATH);
|
||||||
|
errx(1, "FATAL: no gyro found");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (argc >= 2) {
|
||||||
|
|
||||||
|
char* end;
|
||||||
|
int i = strtol(argv[1],&end,10);
|
||||||
|
|
||||||
|
if (!strcmp(argv[0], "sampling")) {
|
||||||
|
|
||||||
|
/* set the accel internal sampling rate up to at leat i Hz */
|
||||||
|
ioctl(fd, GYROIOCSSAMPLERATE, i);
|
||||||
|
|
||||||
|
} else if (!strcmp(argv[0], "rate")) {
|
||||||
|
|
||||||
|
/* set the driver to poll at i Hz */
|
||||||
|
ioctl(fd, SENSORIOCSPOLLRATE, i);
|
||||||
|
} else if (!strcmp(argv[0], "range")) {
|
||||||
|
|
||||||
|
/* set the range to i dps */
|
||||||
|
ioctl(fd, GYROIOCSRANGE, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (!(argc > 0 && !strcmp(argv[0], "info"))) {
|
||||||
|
warnx("no arguments given. Try: \n\n\t'sampling 500' to set sampling to 500 Hz\n\t'rate 500' to set publication rate to 500 Hz\n\t'range 2000' to set measurement range to 2000 dps\n\t");
|
||||||
|
}
|
||||||
|
|
||||||
|
int srate = ioctl(fd, GYROIOCGSAMPLERATE, 0);
|
||||||
|
int prate = ioctl(fd, SENSORIOCGPOLLRATE, 0);
|
||||||
|
int range = ioctl(fd, GYROIOCGRANGE, 0);
|
||||||
|
|
||||||
|
warnx("gyro: \n\tsample rate:\t%d Hz\n\tread rate:\t%d Hz\n\trange:\t%d dps", srate, prate, range);
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
do_mag(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
do_accel(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = open(ACCEL_DEVICE_PATH, 0);
|
||||||
|
|
||||||
|
if (fd < 0) {
|
||||||
|
warn("%s", ACCEL_DEVICE_PATH);
|
||||||
|
errx(1, "FATAL: no accelerometer found");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (argc >= 2) {
|
||||||
|
|
||||||
|
char* end;
|
||||||
|
int i = strtol(argv[1],&end,10);
|
||||||
|
|
||||||
|
if (!strcmp(argv[0], "sampling")) {
|
||||||
|
|
||||||
|
/* set the accel internal sampling rate up to at leat i Hz */
|
||||||
|
ioctl(fd, ACCELIOCSSAMPLERATE, i);
|
||||||
|
|
||||||
|
} else if (!strcmp(argv[0], "rate")) {
|
||||||
|
|
||||||
|
/* set the driver to poll at i Hz */
|
||||||
|
ioctl(fd, SENSORIOCSPOLLRATE, i);
|
||||||
|
} else if (!strcmp(argv[0], "range")) {
|
||||||
|
|
||||||
|
/* set the range to i dps */
|
||||||
|
ioctl(fd, ACCELIOCSRANGE, i);
|
||||||
|
}
|
||||||
|
} else if (!(argc > 0 && !strcmp(argv[0], "info"))) {
|
||||||
|
warnx("no arguments given. Try: \n\n\t'sampling 500' to set sampling to 500 Hz\n\t'rate 500' to set publication rate to 500 Hz\n\t'range 2' to set measurement range to 2 G\n\t");
|
||||||
|
}
|
||||||
|
|
||||||
|
int srate = ioctl(fd, ACCELIOCGSAMPLERATE, 0);
|
||||||
|
int prate = ioctl(fd, SENSORIOCGPOLLRATE, 0);
|
||||||
|
int range = ioctl(fd, ACCELIOCGRANGE, 0);
|
||||||
|
|
||||||
|
warnx("accel: \n\tsample rate:\t%d Hz\n\tread rate:\t%d Hz\n\trange:\t%d m/s", srate, prate, range);
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
############################################################################
|
||||||
|
#
|
||||||
|
# Copyright (c) 2012, 2013 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.
|
||||||
|
#
|
||||||
|
############################################################################
|
||||||
|
|
||||||
|
#
|
||||||
|
# Build the config tool.
|
||||||
|
#
|
||||||
|
|
||||||
|
MODULE_COMMAND = config
|
||||||
|
SRCS = config.c
|
||||||
|
|
||||||
|
MODULE_STACKSIZE = 4096
|
||||||
|
|
||||||
|
MAXOPTIMIZATION = -Os
|
||||||
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#
|
||||||
|
# RAMTRON file system driver
|
||||||
|
#
|
||||||
|
|
||||||
|
MODULE_COMMAND = ramtron
|
||||||
|
SRCS = ramtron.c
|
||||||
@@ -0,0 +1,279 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 PX4 Development Team. All rights reserved.
|
||||||
|
* Author: Lorenz Meier <lm@inf.ethz.ch>
|
||||||
|
*
|
||||||
|
* 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 ramtron.c
|
||||||
|
*
|
||||||
|
* ramtron service and utility app.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <nuttx/config.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/mount.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <nuttx/spi.h>
|
||||||
|
#include <nuttx/mtd.h>
|
||||||
|
#include <nuttx/fs/nxffs.h>
|
||||||
|
#include <nuttx/fs/ioctl.h>
|
||||||
|
|
||||||
|
#include <arch/board/board.h>
|
||||||
|
|
||||||
|
#include "systemlib/systemlib.h"
|
||||||
|
#include "systemlib/param/param.h"
|
||||||
|
#include "systemlib/err.h"
|
||||||
|
|
||||||
|
__EXPORT int ramtron_main(int argc, char *argv[]);
|
||||||
|
|
||||||
|
#ifndef CONFIG_MTD_RAMTRON
|
||||||
|
|
||||||
|
/* create a fake command with decent message to not confuse users */
|
||||||
|
int ramtron_main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
errx(1, "RAMTRON not enabled, skipping.");
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
|
static void ramtron_attach(void);
|
||||||
|
static void ramtron_start(void);
|
||||||
|
static void ramtron_erase(void);
|
||||||
|
static void ramtron_ioctl(unsigned operation);
|
||||||
|
static void ramtron_save(const char *name);
|
||||||
|
static void ramtron_load(const char *name);
|
||||||
|
static void ramtron_test(void);
|
||||||
|
|
||||||
|
static bool attached = false;
|
||||||
|
static bool started = false;
|
||||||
|
static struct mtd_dev_s *ramtron_mtd;
|
||||||
|
|
||||||
|
int ramtron_main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
if (argc >= 2) {
|
||||||
|
if (!strcmp(argv[1], "start"))
|
||||||
|
ramtron_start();
|
||||||
|
|
||||||
|
if (!strcmp(argv[1], "save_param"))
|
||||||
|
ramtron_save(argv[2]);
|
||||||
|
|
||||||
|
if (!strcmp(argv[1], "load_param"))
|
||||||
|
ramtron_load(argv[2]);
|
||||||
|
|
||||||
|
if (!strcmp(argv[1], "erase"))
|
||||||
|
ramtron_erase();
|
||||||
|
|
||||||
|
if (!strcmp(argv[1], "test"))
|
||||||
|
ramtron_test();
|
||||||
|
|
||||||
|
if (0) { /* these actually require a file on the filesystem... */
|
||||||
|
|
||||||
|
if (!strcmp(argv[1], "reformat"))
|
||||||
|
ramtron_ioctl(FIOC_REFORMAT);
|
||||||
|
|
||||||
|
if (!strcmp(argv[1], "repack"))
|
||||||
|
ramtron_ioctl(FIOC_OPTIMIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
errx(1, "expected a command, try 'start'\n\t'save_param /ramtron/parameters'\n\t'load_param /ramtron/parameters'\n\t'erase'\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct mtd_dev_s *ramtron_initialize(FAR struct spi_dev_s *dev);
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
ramtron_attach(void)
|
||||||
|
{
|
||||||
|
/* find the right spi */
|
||||||
|
struct spi_dev_s *spi = up_spiinitialize(2);
|
||||||
|
/* this resets the spi bus, set correct bus speed again */
|
||||||
|
// xxx set in ramtron driver, leave this out
|
||||||
|
// SPI_SETFREQUENCY(spi, 4000000);
|
||||||
|
SPI_SETFREQUENCY(spi, 375000000);
|
||||||
|
SPI_SETBITS(spi, 8);
|
||||||
|
SPI_SETMODE(spi, SPIDEV_MODE3);
|
||||||
|
SPI_SELECT(spi, SPIDEV_FLASH, false);
|
||||||
|
|
||||||
|
if (spi == NULL)
|
||||||
|
errx(1, "failed to locate spi bus");
|
||||||
|
|
||||||
|
/* start the MTD driver, attempt 5 times */
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
ramtron_mtd = ramtron_initialize(spi);
|
||||||
|
if (ramtron_mtd) {
|
||||||
|
/* abort on first valid result */
|
||||||
|
if (i > 0) {
|
||||||
|
warnx("warning: ramtron needed %d attempts to attach", i+1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if last attempt is still unsuccessful, abort */
|
||||||
|
if (ramtron_mtd == NULL)
|
||||||
|
errx(1, "failed to initialize ramtron driver");
|
||||||
|
|
||||||
|
attached = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ramtron_start(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (started)
|
||||||
|
errx(1, "ramtron already mounted");
|
||||||
|
|
||||||
|
if (!attached)
|
||||||
|
ramtron_attach();
|
||||||
|
|
||||||
|
/* start NXFFS */
|
||||||
|
ret = nxffs_initialize(ramtron_mtd);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
errx(1, "failed to initialize NXFFS - erase ramtron to reformat");
|
||||||
|
|
||||||
|
/* mount the ramtron */
|
||||||
|
ret = mount(NULL, "/ramtron", "nxffs", 0, NULL);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
errx(1, "failed to mount /ramtron - erase ramtron to reformat");
|
||||||
|
|
||||||
|
started = true;
|
||||||
|
warnx("mounted ramtron at /ramtron");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//extern int at24c_nuke(void);
|
||||||
|
|
||||||
|
static void
|
||||||
|
ramtron_erase(void)
|
||||||
|
{
|
||||||
|
if (!attached)
|
||||||
|
ramtron_attach();
|
||||||
|
|
||||||
|
// if (at24c_nuke())
|
||||||
|
errx(1, "erase failed");
|
||||||
|
|
||||||
|
errx(0, "erase done, reboot now");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ramtron_ioctl(unsigned operation)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = open("/ramtron/.", 0);
|
||||||
|
|
||||||
|
if (fd < 0)
|
||||||
|
err(1, "open /ramtron");
|
||||||
|
|
||||||
|
if (ioctl(fd, operation, 0) < 0)
|
||||||
|
err(1, "ioctl");
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ramtron_save(const char *name)
|
||||||
|
{
|
||||||
|
if (!started)
|
||||||
|
errx(1, "must be started first");
|
||||||
|
|
||||||
|
if (!name)
|
||||||
|
err(1, "missing argument for device name, try '/ramtron/parameters'");
|
||||||
|
|
||||||
|
warnx("WARNING: 'ramtron save_param' deprecated - use 'param save' instead");
|
||||||
|
|
||||||
|
/* delete the file in case it exists */
|
||||||
|
unlink(name);
|
||||||
|
|
||||||
|
/* create the file */
|
||||||
|
int fd = open(name, O_WRONLY | O_CREAT | O_EXCL);
|
||||||
|
|
||||||
|
if (fd < 0)
|
||||||
|
err(1, "opening '%s' failed", name);
|
||||||
|
|
||||||
|
int result = param_export(fd, false);
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
if (result < 0) {
|
||||||
|
unlink(name);
|
||||||
|
errx(1, "error exporting to '%s'", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ramtron_load(const char *name)
|
||||||
|
{
|
||||||
|
if (!started)
|
||||||
|
errx(1, "must be started first");
|
||||||
|
|
||||||
|
if (!name)
|
||||||
|
err(1, "missing argument for device name, try '/ramtron/parameters'");
|
||||||
|
|
||||||
|
warnx("WARNING: 'ramtron load_param' deprecated - use 'param load' instead");
|
||||||
|
|
||||||
|
int fd = open(name, O_RDONLY);
|
||||||
|
|
||||||
|
if (fd < 0)
|
||||||
|
err(1, "open '%s'", name);
|
||||||
|
|
||||||
|
int result = param_load(fd);
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
if (result < 0)
|
||||||
|
errx(1, "error importing from '%s'", name);
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//extern void at24c_test(void);
|
||||||
|
|
||||||
|
static void
|
||||||
|
ramtron_test(void)
|
||||||
|
{
|
||||||
|
// at24c_test();
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user