From dc5f18bdcd2a7d68d1660777b05f943630250968 Mon Sep 17 00:00:00 2001 From: mcsauder <mcsauder@gmail.com> Date: Thu, 10 Jan 2019 14:39:27 -0700 Subject: [PATCH] ToneAlarm class refactoring to implement an interface for hardware specific methods and a single ToneAlarm class. --- boards/airmind/mindpx-v2/default.cmake | 1 + boards/auav/x21/default.cmake | 1 + boards/av/x-v1/default.cmake | 1 + boards/gumstix/aerocore2/default.cmake | 1 + boards/nxp/fmuk66-v3/default.cmake | 1 + boards/px4/fmu-v2/default.cmake | 1 + boards/px4/fmu-v2/lpe.cmake | 1 + boards/px4/fmu-v2/test.cmake | 1 + boards/px4/fmu-v3/default.cmake | 1 + boards/px4/fmu-v3/rtps.cmake | 1 + boards/px4/fmu-v3/stackcheck.cmake | 1 + boards/px4/fmu-v4/default.cmake | 1 + boards/px4/fmu-v4/rtps.cmake | 1 + boards/px4/fmu-v4/stackcheck.cmake | 1 + boards/px4/fmu-v4pro/default.cmake | 1 + boards/px4/fmu-v4pro/rtps.cmake | 1 + boards/px4/fmu-v5/default.cmake | 1 + boards/px4/fmu-v5/rtps.cmake | 1 + boards/px4/fmu-v5/stackcheck.cmake | 1 + boards/px4/sitl/default.cmake | 3 +- boards/px4/sitl/rtps.cmake | 3 +- boards/px4/sitl/test.cmake | 3 +- .../cxx/tone_alarm/ToneAlarmInterface.cpp | 193 ++++++ src/drivers/drv_hrt.h | 1 + src/drivers/drv_tone_alarm.h | 16 +- src/drivers/kinetis/tone_alarm/CMakeLists.txt | 14 +- .../kinetis/tone_alarm/ToneAlarmInterface.cpp | 183 ++++++ src/drivers/kinetis/tone_alarm/tone_alarm.cpp | 500 --------------- src/drivers/sim/tone_alarm/CMakeLists.txt | 36 ++ .../sim/tone_alarm/ToneAlarmInterface.cpp | 54 ++ src/drivers/stm32/tone_alarm/CMakeLists.txt | 14 +- .../stm32/tone_alarm/ToneAlarmInterface.cpp | 289 +++++++++ src/drivers/stm32/tone_alarm/tone_alarm.cpp | 586 ------------------ .../CMakeLists.txt | 11 +- src/drivers/tone_alarm/ToneAlarm.cpp | 242 ++++++++ src/drivers/tone_alarm/ToneAlarm.h | 120 ++++ src/drivers/tone_alarm_sim/tone_alarm.cpp | 341 ---------- src/lib/drivers/CMakeLists.txt | 1 + src/lib/drivers/tone_alarm/CMakeLists.txt | 34 + .../drivers/tone_alarm/ToneAlarmInterface.h | 54 ++ src/modules/mavlink/mavlink_receiver.cpp | 2 +- src/systemcmds/tests/test_hrt.cpp | 4 +- 42 files changed, 1258 insertions(+), 1465 deletions(-) create mode 100644 platforms/nuttx/NuttX/include/cxx/tone_alarm/ToneAlarmInterface.cpp create mode 100644 src/drivers/kinetis/tone_alarm/ToneAlarmInterface.cpp delete mode 100644 src/drivers/kinetis/tone_alarm/tone_alarm.cpp create mode 100644 src/drivers/sim/tone_alarm/CMakeLists.txt create mode 100644 src/drivers/sim/tone_alarm/ToneAlarmInterface.cpp create mode 100644 src/drivers/stm32/tone_alarm/ToneAlarmInterface.cpp delete mode 100644 src/drivers/stm32/tone_alarm/tone_alarm.cpp rename src/drivers/{tone_alarm_sim => tone_alarm}/CMakeLists.txt (91%) create mode 100644 src/drivers/tone_alarm/ToneAlarm.cpp create mode 100644 src/drivers/tone_alarm/ToneAlarm.h delete mode 100644 src/drivers/tone_alarm_sim/tone_alarm.cpp create mode 100644 src/lib/drivers/tone_alarm/CMakeLists.txt create mode 100644 src/lib/drivers/tone_alarm/ToneAlarmInterface.h diff --git a/boards/airmind/mindpx-v2/default.cmake b/boards/airmind/mindpx-v2/default.cmake index 852df4b6e3..f288fb877f 100644 --- a/boards/airmind/mindpx-v2/default.cmake +++ b/boards/airmind/mindpx-v2/default.cmake @@ -45,6 +45,7 @@ px4_add_board( tap_esc telemetry # all available telemetry drivers test_ppm + tone_alarm uavcan MODULES diff --git a/boards/auav/x21/default.cmake b/boards/auav/x21/default.cmake index cbcdc5e109..d53fb224e2 100644 --- a/boards/auav/x21/default.cmake +++ b/boards/auav/x21/default.cmake @@ -50,6 +50,7 @@ px4_add_board( tap_esc telemetry # all available telemetry drivers test_ppm + tone_alarm uavcan MODULES diff --git a/boards/av/x-v1/default.cmake b/boards/av/x-v1/default.cmake index 91011240be..7499fa955e 100644 --- a/boards/av/x-v1/default.cmake +++ b/boards/av/x-v1/default.cmake @@ -50,6 +50,7 @@ px4_add_board( tap_esc telemetry # all available telemetry drivers test_ppm + #tone_alarm uavcan MODULES diff --git a/boards/gumstix/aerocore2/default.cmake b/boards/gumstix/aerocore2/default.cmake index 60b5644653..83066cf52a 100644 --- a/boards/gumstix/aerocore2/default.cmake +++ b/boards/gumstix/aerocore2/default.cmake @@ -48,6 +48,7 @@ px4_add_board( #tap_esc #telemetry # all available telemetry drivers #test_ppm + tone_alarm MODULES #attitude_estimator_q diff --git a/boards/nxp/fmuk66-v3/default.cmake b/boards/nxp/fmuk66-v3/default.cmake index 32a55823f7..36e914e981 100644 --- a/boards/nxp/fmuk66-v3/default.cmake +++ b/boards/nxp/fmuk66-v3/default.cmake @@ -47,6 +47,7 @@ px4_add_board( tap_esc telemetry # all available telemetry drivers #test_ppm # NOT Portable YET + tone_alarm MODULES attitude_estimator_q diff --git a/boards/px4/fmu-v2/default.cmake b/boards/px4/fmu-v2/default.cmake index dc6fac81fe..19166f09eb 100644 --- a/boards/px4/fmu-v2/default.cmake +++ b/boards/px4/fmu-v2/default.cmake @@ -59,6 +59,7 @@ px4_add_board( #tap_esc #telemetry # all available telemetry drivers #test_ppm + tone_alarm #uavcan MODULES diff --git a/boards/px4/fmu-v2/lpe.cmake b/boards/px4/fmu-v2/lpe.cmake index a22d130b4c..2989307ca3 100644 --- a/boards/px4/fmu-v2/lpe.cmake +++ b/boards/px4/fmu-v2/lpe.cmake @@ -55,6 +55,7 @@ px4_add_board( #tap_esc #telemetry # all available telemetry drivers #test_ppm + tone_alarm #uavcan MODULES diff --git a/boards/px4/fmu-v2/test.cmake b/boards/px4/fmu-v2/test.cmake index 05005cd86e..91e71e0607 100644 --- a/boards/px4/fmu-v2/test.cmake +++ b/boards/px4/fmu-v2/test.cmake @@ -56,6 +56,7 @@ px4_add_board( #tap_esc #telemetry # all available telemetry drivers #test_ppm + tone_alarm #uavcan MODULES diff --git a/boards/px4/fmu-v3/default.cmake b/boards/px4/fmu-v3/default.cmake index 4c6dfdea02..1ea994365e 100644 --- a/boards/px4/fmu-v3/default.cmake +++ b/boards/px4/fmu-v3/default.cmake @@ -58,6 +58,7 @@ px4_add_board( tap_esc telemetry # all available telemetry drivers test_ppm + tone_alarm uavcan MODULES diff --git a/boards/px4/fmu-v3/rtps.cmake b/boards/px4/fmu-v3/rtps.cmake index f6750853a8..f41a0a8476 100644 --- a/boards/px4/fmu-v3/rtps.cmake +++ b/boards/px4/fmu-v3/rtps.cmake @@ -58,6 +58,7 @@ px4_add_board( tap_esc telemetry # all available telemetry drivers test_ppm + tone_alarm uavcan MODULES diff --git a/boards/px4/fmu-v3/stackcheck.cmake b/boards/px4/fmu-v3/stackcheck.cmake index ea97d34d21..24ff0ea563 100644 --- a/boards/px4/fmu-v3/stackcheck.cmake +++ b/boards/px4/fmu-v3/stackcheck.cmake @@ -58,6 +58,7 @@ px4_add_board( tap_esc telemetry # all available telemetry drivers test_ppm + tone_alarm #uavcan MODULES diff --git a/boards/px4/fmu-v4/default.cmake b/boards/px4/fmu-v4/default.cmake index eae8984084..385542f064 100644 --- a/boards/px4/fmu-v4/default.cmake +++ b/boards/px4/fmu-v4/default.cmake @@ -43,6 +43,7 @@ px4_add_board( tap_esc telemetry # all available telemetry drivers test_ppm + tone_alarm uavcan MODULES diff --git a/boards/px4/fmu-v4/rtps.cmake b/boards/px4/fmu-v4/rtps.cmake index 10295c62bc..8b292d57a5 100644 --- a/boards/px4/fmu-v4/rtps.cmake +++ b/boards/px4/fmu-v4/rtps.cmake @@ -44,6 +44,7 @@ px4_add_board( tap_esc telemetry # all available telemetry drivers test_ppm + tone_alarm uavcan MODULES diff --git a/boards/px4/fmu-v4/stackcheck.cmake b/boards/px4/fmu-v4/stackcheck.cmake index f0b8f438e5..dfae99dc4c 100644 --- a/boards/px4/fmu-v4/stackcheck.cmake +++ b/boards/px4/fmu-v4/stackcheck.cmake @@ -43,6 +43,7 @@ px4_add_board( tap_esc telemetry # all available telemetry drivers test_ppm + tone_alarm #uavcan MODULES diff --git a/boards/px4/fmu-v4pro/default.cmake b/boards/px4/fmu-v4pro/default.cmake index 6a7f18ab08..736718e0cd 100644 --- a/boards/px4/fmu-v4pro/default.cmake +++ b/boards/px4/fmu-v4pro/default.cmake @@ -57,6 +57,7 @@ px4_add_board( tap_esc telemetry # all available telemetry drivers test_ppm + tone_alarm uavcan MODULES diff --git a/boards/px4/fmu-v4pro/rtps.cmake b/boards/px4/fmu-v4pro/rtps.cmake index b59b88f76a..357f3ddc98 100644 --- a/boards/px4/fmu-v4pro/rtps.cmake +++ b/boards/px4/fmu-v4pro/rtps.cmake @@ -57,6 +57,7 @@ px4_add_board( tap_esc telemetry # all available telemetry drivers test_ppm + tone_alarm uavcan MODULES diff --git a/boards/px4/fmu-v5/default.cmake b/boards/px4/fmu-v5/default.cmake index a7ce965eac..abefe80754 100644 --- a/boards/px4/fmu-v5/default.cmake +++ b/boards/px4/fmu-v5/default.cmake @@ -58,6 +58,7 @@ px4_add_board( tap_esc telemetry # all available telemetry drivers test_ppm + tone_alarm uavcan MODULES diff --git a/boards/px4/fmu-v5/rtps.cmake b/boards/px4/fmu-v5/rtps.cmake index 072caad7b4..7cab372a18 100644 --- a/boards/px4/fmu-v5/rtps.cmake +++ b/boards/px4/fmu-v5/rtps.cmake @@ -58,6 +58,7 @@ px4_add_board( tap_esc telemetry # all available telemetry drivers test_ppm + tone_alarm uavcan MODULES diff --git a/boards/px4/fmu-v5/stackcheck.cmake b/boards/px4/fmu-v5/stackcheck.cmake index d36b11f238..0e21e85417 100644 --- a/boards/px4/fmu-v5/stackcheck.cmake +++ b/boards/px4/fmu-v5/stackcheck.cmake @@ -58,6 +58,7 @@ px4_add_board( tap_esc telemetry # all available telemetry drivers test_ppm + tone_alarm #uavcan MODULES diff --git a/boards/px4/sitl/default.cmake b/boards/px4/sitl/default.cmake index 2ed686e887..50eaf8900e 100644 --- a/boards/px4/sitl/default.cmake +++ b/boards/px4/sitl/default.cmake @@ -17,7 +17,8 @@ px4_add_board( #magnetometer # all available magnetometer drivers pwm_out_sim #telemetry # all available telemetry drivers - tone_alarm_sim + sim/tone_alarm + tone_alarm #uavcan MODULES diff --git a/boards/px4/sitl/rtps.cmake b/boards/px4/sitl/rtps.cmake index a34d764136..a97a98bc7d 100644 --- a/boards/px4/sitl/rtps.cmake +++ b/boards/px4/sitl/rtps.cmake @@ -17,7 +17,8 @@ px4_add_board( #magnetometer # all available magnetometer drivers pwm_out_sim #telemetry # all available telemetry drivers - tone_alarm_sim + sim/tone_alarm + tone_alarm #uavcan MODULES diff --git a/boards/px4/sitl/test.cmake b/boards/px4/sitl/test.cmake index 65ab15ecf4..d4b5119a5a 100644 --- a/boards/px4/sitl/test.cmake +++ b/boards/px4/sitl/test.cmake @@ -17,7 +17,8 @@ px4_add_board( #magnetometer # all available magnetometer drivers pwm_out_sim #telemetry # all available telemetry drivers - tone_alarm_sim + sim/tone_alarm + tone_alarm #uavcan MODULES diff --git a/platforms/nuttx/NuttX/include/cxx/tone_alarm/ToneAlarmInterface.cpp b/platforms/nuttx/NuttX/include/cxx/tone_alarm/ToneAlarmInterface.cpp new file mode 100644 index 0000000000..94f4b393f1 --- /dev/null +++ b/platforms/nuttx/NuttX/include/cxx/tone_alarm/ToneAlarmInterface.cpp @@ -0,0 +1,193 @@ +/**************************************************************************** + * + * Copyright (C) 2013-2019 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 ToneAlarmInterface.cpp + */ + +#include <chip/sam_pinmap.h> + +#include <drivers/device/device.h> +#include <lib/drivers/tone_alarm/ToneAlarmInterface.h> +#include <px4_defines.h> + +/* Check that tone alarm and HRT timers are different */ +#if defined(TONE_ALARM_CHANNEL) && defined(HRT_TIMER_CHANNEL) +# if TONE_ALARM_CHANNEL == HRT_TIMER_CHANNEL +# error TONE_ALARM_CHANNEL and HRT_TIMER_CHANNEL must use different timers. +# endif +#endif + +#if defined(TONE_ALARM_TIMER) +# error "TONE_ALARM_TIMER should not be defined, instead define TONE_ALARM_CHANNEL from 0-11" +#endif + +#ifndef TONE_ALARM_CLOCK +#define TONE_ALARM_CLOCK (BOARD_MCK_FREQUENCY/128) +#endif + +/* Period of the free-running counter, in microseconds. */ +#ifndef TONE_ALARM_COUNTER_PERIOD +#define TONE_ALARM_COUNTER_PERIOD 65536 +#endif + +/* Tone alarm configuration */ +#if TONE_ALARM_CHANNEL == 0 || TONE_ALARM_CHANNEL == 1 || TONE_ALARM_CHANNEL == 2 +# define TONE_ALARM_TIMER 0 +#endif +#if TONE_ALARM_CHANNEL == 3 || TONE_ALARM_CHANNEL == 4 || TONE_ALARM_CHANNEL == 5 +# define TONE_ALARM_TIMER 1 +#endif +#if TONE_ALARM_CHANNEL == 6 || TONE_ALARM_CHANNEL == 7 || TONE_ALARM_CHANNEL == 8 +# define TONE_ALARM_TIMER 2 +#endif +#if TONE_ALARM_CHANNEL == 9 || TONE_ALARM_CHANNEL == 10 || TONE_ALARM_CHANNEL == 11 +# define TONE_ALARM_TIMER 3 +#endif + +/* HRT configuration */ +#if TONE_ALARM_TIMER == 0 +# define HRT_TIMER_BASE SAM_TC012_BASE +# if !defined(CONFIG_SAMV7_TC0) +# error "HRT_TIMER_CHANNEL 0-2 Require CONFIG_SAMV7_TC0=y" +# endif +#elif TONE_ALARM_TIMER == 1 +# define HRT_TIMER_BASE SAM_TC345_BASE +# if !defined(CONFIG_SAMV7_TC1) +# error "HRT_TIMER_CHANNEL 3-5 Require CONFIG_SAMV7_TC1=y" +# endif +#elif TONE_ALARM_TIMER == 2 +# define HRT_TIMER_BASE SAM_TC678_BASE +# if !defined(CONFIG_SAMV7_TC2) +# error "HRT_TIMER_CHANNEL 6-8 Require CONFIG_SAMV7_TC2=y" +# endif +#elif TONE_ALARM_TIMER == 3 +# define HRT_TIMER_BASE SAM_TC901_BASE +# if !defined(CONFIG_SAMV7_TC3) +# error "HRT_TIMER_CHANNEL 9-11 Require CONFIG_SAMV7_TC3=y" +# endif +#else +# error "HRT_TIMER_CHANNEL should be defined valid value are from 0-11" +# endif + + +/* Timer register accessors. */ +#define REG(_reg) (*(volatile uint32_t *)(SAM_TC0_BASE + SAM_TC_CHAN_OFFSET(HRT_TIMER_CHANNEL) + _reg)) + +#define rCCR REG(SAM_TC_CCR_OFFSET) +#define rCMR REG(SAM_TC_CMR_OFFSET) +#define rCV REG(SAM_TC_CV_OFFSET) +#define rEMR REG(SAM_TC_EMR_OFFSET) +#define rIER REG(SAM_TC_IER_OFFSET) +#define rIDR REG(SAM_TC_IDR_OFFSET) +#define rIMR REG(SAM_TC_IMR_OFFSET) +#define rRA REG(SAM_TC_RA_OFFSET) +#define rRAB REG(SAM_TC_RAB_OFFSET) +#define rRB REG(SAM_TC_RB_OFFSET) +#define rRC REG(SAM_TC_RC_OFFSET) +#define rSMMR REG(SAM_TC_SMMR_OFFSET) +#define rSR REG(SAM_TC_SR_OFFSET) + +void ToneAlarmInterface::init() +{ +#ifdef GPIO_TONE_ALARM_NEG + px4_arch_configgpio(GPIO_TONE_ALARM_NEG); +#else + // Configure the GPIO to the idle state. + px4_arch_configgpio(GPIO_TONE_ALARM_IDLE); +#endif + +// TODO - This is dead code. +#if TONE_ALARM_NOT_DONE + // Initialize the timer. + rCCER &= TONE_CCER; // Unlock CCMR* registers. + rCCER = TONE_CCER; + rCCMR1 = TONE_CCMR1; + rCCMR2 = TONE_CCMR2; + rDCR = 0; + rCR1 = 0; + rCR2 = 0; + rDIER = 0; + rSMCR = 0; + +#ifdef rBDTR // If using an advanced timer, you need to activate the output. + rBDTR = ATIM_BDTR_MOE; // Enable the main output of the advanced timer. +#endif + + TONE_rCCR = 1; // Toggle the CC output each time the count passes 1. + rPSC = 0; // Default the timer to a prescale value of 1; playing notes will change this. + rCR1 = GTIM_CR1_CEN; // Ensure the timer is running. +#endif +} + +void ToneAlarmInterface::start_note(unsigned frequency) +{ + // Calculate the signal switching period. + // (Signal switching period is one half of the frequency period). + float signal_period = (1.0f / frequency) * 0.5f; + + // Calculate the hardware clock divisor rounded to the nearest integer. + unsigned int divisor = std::round(signal_period * TONE_ALARM_CLOCK); + + // Pick the lowest prescaler value that we can use. + // (Note that the effective prescale value is 1 greater.) + unsigned int prescale = divisor / TONE_ALARM_COUNTER_PERIOD; + + // Calculate the period for the selected prescaler value. + unsigned int period = (divisor / (prescale + 1)) - 1; + +// TODO - This is dead code. +#if TONE_ALARM_NOT_DONE + rPSC = prescale; // Load new prescaler. + rARR = period; // Load new signal switching period. + rEGR = GTIM_EGR_UG; // Force a reload of the period. + rCCER |= TONE_CCER; // Enable the output. +#else + prescale++; + period++; +#endif + + // Configure the GPIO to enable timer output. + px4_arch_configgpio(GPIO_TONE_ALARM); +} + +void ToneAlarmInterface::stop_note() +{ + // Stop the current note. +// TODO - This is dead code. +#if TONE_ALARM_NOT_DONE + rCCER &= ~TONE_CCER; +#endif + // Ensure the GPIO is not driving the speaker. + px4_arch_configgpio(GPIO_TONE_ALARM_IDLE); +} diff --git a/src/drivers/drv_hrt.h b/src/drivers/drv_hrt.h index 6f8cbcb4e0..99db5d1b10 100644 --- a/src/drivers/drv_hrt.h +++ b/src/drivers/drv_hrt.h @@ -39,6 +39,7 @@ #pragma once +#include <sys/ioctl.h> #include <sys/types.h> #include <stdbool.h> #include <inttypes.h> diff --git a/src/drivers/drv_tone_alarm.h b/src/drivers/drv_tone_alarm.h index adebc56781..7d389cd7fe 100644 --- a/src/drivers/drv_tone_alarm.h +++ b/src/drivers/drv_tone_alarm.h @@ -57,17 +57,19 @@ * via the ioctl. */ -#ifndef DRV_TONE_ALARM_H_ -#define DRV_TONE_ALARM_H_ +#pragma once -#include <sys/ioctl.h> #include <lib/tunes/tune_definition.h> #include <uORB/topics/tune_control.h> -#define TONEALARM0_DEVICE_PATH "/dev/tone_alarm0" +#define CBRK_BUZZER_KEY 782097 +#define CBRK_OFF 0 +#define CBRK_ON 1 +#define CBRK_UNINIT 2 -#define _TONE_ALARM_BASE 0x7400 -#define TONE_SET_ALARM _PX4_IOC(_TONE_ALARM_BASE, 1) +#define _TONE_ALARM_BASE 0x7400 +#define TONE_SET_ALARM _PX4_IOC(_TONE_ALARM_BASE, 1) +#define TONE_ALARM0_DEVICE_PATH "/dev/tone_alarm0" // TODO: remove this once the tone_alarm driver is changed to the new tunelib enum { @@ -89,5 +91,3 @@ enum { TONE_HOME_SET, TONE_NUMBER_OF_TUNES }; - -#endif /* DRV_TONE_ALARM_H_ */ diff --git a/src/drivers/kinetis/tone_alarm/CMakeLists.txt b/src/drivers/kinetis/tone_alarm/CMakeLists.txt index 768934bf1b..5251d3910a 100644 --- a/src/drivers/kinetis/tone_alarm/CMakeLists.txt +++ b/src/drivers/kinetis/tone_alarm/CMakeLists.txt @@ -1,6 +1,6 @@ ############################################################################ # -# Copyright (c) 2016-2017 PX4 Development Team. All rights reserved. +# Copyright (c) 2015-2019 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 @@ -31,12 +31,6 @@ # ############################################################################ -px4_add_module( - MODULE drivers__tone_alarm - MAIN tone_alarm - SRCS - tone_alarm.cpp - DEPENDS - circuit_breaker - tunes - ) \ No newline at end of file +px4_add_library(tone_alarm_interface + ToneAlarmInterface.cpp +) diff --git a/src/drivers/kinetis/tone_alarm/ToneAlarmInterface.cpp b/src/drivers/kinetis/tone_alarm/ToneAlarmInterface.cpp new file mode 100644 index 0000000000..a625a5c2b9 --- /dev/null +++ b/src/drivers/kinetis/tone_alarm/ToneAlarmInterface.cpp @@ -0,0 +1,183 @@ +/**************************************************************************** + * + * Copyright (C) 2017-2019 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 ToneAlarmInterface.cpp + */ + +#include "chip/kinetis_sim.h" +#include "kinetis_tpm.h" + +#include <drivers/device/device.h> +#include <lib/drivers/tone_alarm/ToneAlarmInterface.h> +#include <px4_defines.h> +#include <systemlib/px4_macros.h> + + +#define CAT3_(A, B, C) A##B##C +#define CAT3(A, B, C) CAT3_(A, B, C) + +/* Check that tone alarm and HRT timers are different */ +#if defined(TONE_ALARM_TIMER) && defined(HRT_TIMER) +# if TONE_ALARM_TIMER == HRT_TIMER +# error TONE_ALARM_TIMER and HRT_TIMER must use different timers. +# endif +#endif + +#ifndef TONE_ALARM_CLOCK +#define TONE_ALARM_CLOCK (BOARD_TPM_FREQ/(1 << (TONE_ALARM_TIMER_PRESCALE >> TPM_SC_PS_SHIFT))) +#endif + +/* Period of the free-running counter, in microseconds. */ +#ifndef TONE_ALARM_COUNTER_PERIOD +#define TONE_ALARM_COUNTER_PERIOD 65536 +#endif + +/* Tone Alarm configuration */ +#define TONE_ALARM_SIM_SCGC2_TPM CAT(SIM_SCGC2_TPM, TONE_ALARM_TIMER) /* The Clock Gating enable bit for this TPM */ +#define TONE_ALARM_TIMER_BASE CAT(CAT(KINETIS_TPM, TONE_ALARM_TIMER),_BASE) /* The Base address of the TPM */ +#define TONE_ALARM_TIMER_CLOCK BOARD_TPM_FREQ /* The input clock frequency to the TPM block */ +#define TONE_ALARM_TIMER_PRESCALE TPM_SC_PS_DIV16 /* The constant Prescaler */ +#define TONE_ALARM_TIMER_VECTOR CAT(KINETIS_IRQ_TPM, TONE_ALARM_TIMER) /* The TPM Interrupt vector */ + +#if TONE_ALARM_TIMER == 1 && defined(CONFIG_KINETIS_TPM1) +# error must not set CONFIG_KINETIS_TPM1=y and TONE_ALARM_TIMER=1 +#elif TONE_ALARM_TIMER == 2 && defined(CONFIG_KINETIS_TPM2) +# error must not set CONFIG_STM32_TIM2=y and TONE_ALARM_TIMER=2 +#endif + +/* Tone Alarm clock must be a multiple of 1MHz greater than 1MHz. */ +#if (TONE_ALARM_TIMER_CLOCK % TONE_ALARM_CLOCK) != 0 +# error TONE_ALARM_TIMER_CLOCK must be a multiple of 1MHz +#endif +#if TONE_ALARM_TIMER_CLOCK <= TONE_ALARM_CLOCK +# error TONE_ALARM_TIMER_CLOCK must be greater than 1MHz +#endif + +#if (TONE_ALARM_CHANNEL != 0) && (TONE_ALARM_CHANNEL != 1) +# error TONE_ALARM_CHANNEL must be a value between 0 and 1 +#endif + + +/* Register accessors */ +#define _REG(_addr) (*(volatile uint32_t *)(_addr)) + +/* Timer register accessors */ +#define REG(_reg) _REG(TONE_ALARM_TIMER_BASE + (_reg)) + +#define rC0SC REG(KINETIS_TPM_C0SC_OFFSET) +#define rC0V REG(KINETIS_TPM_C0V_OFFSET) +#define rC1SC REG(KINETIS_TPM_C1SC_OFFSET) +#define rC1V REG(KINETIS_TPM_C1V_OFFSET) +#define rCNT REG(KINETIS_TPM_CNT_OFFSET) +#define rCOMBINE REG(KINETIS_TPM_COMBINE_OFFSET) +#define rCONF REG(KINETIS_TPM_CONF_OFFSET) +#define rFILTER REG(KINETIS_TPM_FILTER_OFFSET) +#define rMOD REG(KINETIS_TPM_MOD_OFFSET) +#define rPOL REG(KINETIS_TPM_POL_OFFSET) +#define rQDCTRL REG(KINETIS_TPM_QDCTRL_OFFSET) +#define rSC REG(KINETIS_TPM_SC_OFFSET) +#define rSTATUS REG(KINETIS_TPM_STATUS_OFFSET) + +/* Specific registers and bits used by Tone Alarm sub-functions. */ +# define rCNV CAT3(rC, TONE_ALARM_CHANNEL, V) /* Channel Value Register used by Tone alarm */ +# define rCNSC CAT3(rC, TONE_ALARM_CHANNEL, SC) /* Channel Status and Control Register used by Tone alarm */ +# define STATUS CAT3(TPM_STATUS_CH, TONE_ALARM_CHANNEL, F) /* Capture and Compare Status Register used by Tone alarm */ + +void ToneAlarmInterface::init() +{ +#ifdef GPIO_TONE_ALARM_NEG + px4_arch_configgpio(GPIO_TONE_ALARM_NEG); +#else + // Configure the GPIO to the idle state. + px4_arch_configgpio(GPIO_TONE_ALARM_IDLE); +#endif + + // Select a the clock source to the TPM. + uint32_t regval = _REG(KINETIS_SIM_SOPT2); + + regval &= ~(SIM_SOPT2_TPMSRC_MASK); + regval |= BOARD_TPM_CLKSRC; + + _REG(KINETIS_SIM_SOPT2) = regval; + + // Enabled System Clock Gating Control for TPM. + regval = _REG(KINETIS_SIM_SCGC2); + regval |= TONE_ALARM_SIM_SCGC2_TPM; + _REG(KINETIS_SIM_SCGC2) = regval; + + // Disable and configure the timer. + rSC = TPM_SC_TOF; + rCNT = 0; + rMOD = TONE_ALARM_COUNTER_PERIOD - 1; + rSTATUS = (TPM_STATUS_TOF | STATUS); + + // Configure for output compare to toggle on over flow. + rCNSC = (TPM_CnSC_CHF | TPM_CnSC_MSA | TPM_CnSC_ELSA); + + rCOMBINE = 0; + rPOL = 0; + rFILTER = 0; + rQDCTRL = 0; + rCONF = TPM_CONF_DBGMODE_CONT; + + rCNV = 0; // Toggle the CC output each time the count passes 0. + rSC |= (TPM_SC_CMOD_LPTPM_CLK | TONE_ALARM_TIMER_PRESCALE); // Enable the timer. + rMOD = 0; // Default the timer to a modulo value of 1; playing notes will change this. +} + +void ToneAlarmInterface::start_note(unsigned frequency) +{ + // Calculate the signal switching period. + // (Signal switching period is one half of the frequency period). + float signal_period = (1.0f / frequency) * 0.5f; + + // Calculate the hardware clock divisor rounded to the nearest integer. + unsigned int divisor = std::round(signal_period * TONE_ALARM_CLOCK); + + rCNT = 0; + rMOD = divisor; // Load new signal switching period. + rSC |= (TPM_SC_CMOD_LPTPM_CLK); + + // Configure the GPIO to enable timer output. + px4_arch_configgpio(GPIO_TONE_ALARM); +} + +void ToneAlarmInterface::stop_note() +{ + // Stop the current note. + rSC &= ~TPM_SC_CMOD_MASK; + + // Ensure the GPIO is not driving the speaker. + px4_arch_configgpio(GPIO_TONE_ALARM_IDLE); +} diff --git a/src/drivers/kinetis/tone_alarm/tone_alarm.cpp b/src/drivers/kinetis/tone_alarm/tone_alarm.cpp deleted file mode 100644 index ca31d992ae..0000000000 --- a/src/drivers/kinetis/tone_alarm/tone_alarm.cpp +++ /dev/null @@ -1,500 +0,0 @@ -/**************************************************************************** - * - * Copyright (C) 2017-2018 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. - * - ****************************************************************************/ - -/* - * Low Level Driver for the PX4 audio alarm port. Subscribes to - * tune_control and plays notes on this architecture specific - * timer HW - */ - -#include <px4_config.h> -#include <px4_log.h> -#include <systemlib/px4_macros.h> -#include <debug.h> - -#include <drivers/device/device.h> -#include <drivers/drv_tone_alarm.h> - -#include <sys/types.h> -#include <stdint.h> -#include <stdbool.h> -#include <stdlib.h> -#include <string.h> -#include <fcntl.h> -#include <errno.h> -#include <stdio.h> -#include <unistd.h> -#include <math.h> -#include <ctype.h> - -#include <board_config.h> -#include <drivers/drv_hrt.h> - -#include "kinetis.h" -#include "chip/kinetis_sim.h" -#include "kinetis_tpm.h" - -#include <systemlib/err.h> -#include <circuit_breaker/circuit_breaker.h> - -#include <px4_workqueue.h> - -#include <lib/tunes/tunes.h> -#include <uORB/uORB.h> -#include <uORB/topics/tune_control.h> - -#define CAT3_(A, B, C) A##B##C -#define CAT3(A, B, C) CAT3_(A, B, C) - -/* Check that tone alarm and HRT timers are different */ -#if defined(TONE_ALARM_TIMER) && defined(HRT_TIMER) -# if TONE_ALARM_TIMER == HRT_TIMER -# error TONE_ALARM_TIMER and HRT_TIMER must use different timers. -# endif -#endif - - -/* -* Period of the free-running counter, in microseconds. -*/ -#define TONE_ALARM_COUNTER_PERIOD 65536 - -/* Tone Alarm configuration */ - -#define TONE_ALARM_TIMER_CLOCK BOARD_TPM_FREQ /* The input clock frequency to the TPM block */ -#define TONE_ALARM_TIMER_BASE CAT(CAT(KINETIS_TPM, TONE_ALARM_TIMER),_BASE) /* The Base address of the TPM */ -#define TONE_ALARM_TIMER_VECTOR CAT(KINETIS_IRQ_TPM, TONE_ALARM_TIMER) /* The TPM Interrupt vector */ -#define TONE_ALARM_SIM_SCGC2_TPM CAT(SIM_SCGC2_TPM, TONE_ALARM_TIMER) /* The Clock Gating enable bit for this TPM */ -#define TONE_ALARM_TIMER_PRESCALE TPM_SC_PS_DIV16 /* The constant Prescaler */ - -#if TONE_ALARM_TIMER == 1 && defined(CONFIG_KINETIS_TPM1) -# error must not set CONFIG_KINETIS_TPM1=y and TONE_ALARM_TIMER=1 -#elif TONE_ALARM_TIMER == 2 && defined(CONFIG_KINETIS_TPM2) -# error must not set CONFIG_STM32_TIM2=y and TONE_ALARM_TIMER=2 -#endif - - -# define TONE_ALARM_TIMER_FREQ (BOARD_TPM_FREQ/(1 << (TONE_ALARM_TIMER_PRESCALE >> TPM_SC_PS_SHIFT))) - -/* -* Toan Alarm clock must be a multiple of 1MHz greater than 1MHz -*/ -#if (TONE_ALARM_TIMER_CLOCK % TONE_ALARM_TIMER_FREQ) != 0 -# error TONE_ALARM_TIMER_CLOCK must be a multiple of 1MHz -#endif -#if TONE_ALARM_TIMER_CLOCK <= TONE_ALARM_TIMER_FREQ -# error TONE_ALARM_TIMER_CLOCK must be greater than 1MHz -#endif - -#if (TONE_ALARM_CHANNEL != 0) && (TONE_ALARM_CHANNEL != 1) -# error TONE_ALARM_CHANNEL must be a value between 0 and 1 -#endif - - -/* Register accessors */ - -#define _REG(_addr) (*(volatile uint32_t *)(_addr)) - -/* Timer register accessors */ - -#define REG(_reg) _REG(TONE_ALARM_TIMER_BASE + (_reg)) - -#define rSC REG(KINETIS_TPM_SC_OFFSET) -#define rCNT REG(KINETIS_TPM_CNT_OFFSET) -#define rMOD REG(KINETIS_TPM_MOD_OFFSET) -#define rC0SC REG(KINETIS_TPM_C0SC_OFFSET) -#define rC0V REG(KINETIS_TPM_C0V_OFFSET) -#define rC1SC REG(KINETIS_TPM_C1SC_OFFSET) -#define rC1V REG(KINETIS_TPM_C1V_OFFSET) -#define rSTATUS REG(KINETIS_TPM_STATUS_OFFSET) -#define rCOMBINE REG(KINETIS_TPM_COMBINE_OFFSET) -#define rPOL REG(KINETIS_TPM_POL_OFFSET) -#define rFILTER REG(KINETIS_TPM_FILTER_OFFSET) -#define rQDCTRL REG(KINETIS_TPM_QDCTRL_OFFSET) -#define rCONF REG(KINETIS_TPM_CONF_OFFSET) - -/* -* Specific registers and bits used by Tone Alarm sub-functions -*/ - -# define rCNV CAT3(rC, TONE_ALARM_CHANNEL, V) /* Channel Value Register used by Tone alarm */ -# define rCNSC CAT3(rC, TONE_ALARM_CHANNEL, SC) /* Channel Status and Control Register used by Tone alarm */ -# define STATUS CAT3(TPM_STATUS_CH, TONE_ALARM_CHANNEL, F) /* Capture and Compare Status Register used by Tone alarm */ - -#define CBRK_BUZZER_KEY 782097 - -class ToneAlarm : public device::CDev -{ -public: - ToneAlarm(); - ~ToneAlarm(); - - virtual int init(); - void status(); - - enum { - CBRK_OFF = 0, - CBRK_ON, - CBRK_UNINIT - }; - -private: - volatile bool _running; - volatile bool _should_run; - bool _play_tone; - - Tunes _tunes; - - unsigned _silence_length; // if nonzero, silence before next note - - int _cbrk; ///< if true, no audio output - int _tune_control_sub; - - tune_control_s _tune; - - static work_s _work; - - // Convert a frequency value into a divisor for the configured timer's clock. - // - unsigned frequency_to_divisor(unsigned frequency); - - // Start playing the note - // - void start_note(unsigned frequency); - - // Stop playing the current note and make the player 'safe' - // - void stop_note(); - - // Parse the next note out of the string and play it - // - void next_note(); - - // work queue trampoline for next_note - // - static void next_trampoline(void *arg); - -}; - -struct work_s ToneAlarm::_work = {}; - -/* - * Driver 'main' command. - */ -extern "C" __EXPORT int tone_alarm_main(int argc, char *argv[]); - - -ToneAlarm::ToneAlarm() : - CDev("tone_alarm", TONEALARM0_DEVICE_PATH), - _running(false), - _should_run(true), - _play_tone(false), - _tunes(), - _silence_length(0), - _cbrk(CBRK_UNINIT), - _tune_control_sub(-1) -{ - // enable debug() calls - //_debug_enabled = true; -} - -ToneAlarm::~ToneAlarm() -{ - _should_run = false; - int counter = 0; - - while (_running && ++counter < 10) { - usleep(100000); - } -} - -int ToneAlarm::init() -{ - int ret; - - ret = CDev::init(); - - if (ret != OK) { - return ret; - } - - /* configure the GPIO to the idle state */ - px4_arch_configgpio(GPIO_TONE_ALARM_IDLE); - -#ifdef GPIO_TONE_ALARM_NEG - - px4_arch_configgpio(GPIO_TONE_ALARM_NEG); -#endif - - - /* Select a the clock source to the TPM */ - - uint32_t regval = _REG(KINETIS_SIM_SOPT2); - regval &= ~(SIM_SOPT2_TPMSRC_MASK); - regval |= BOARD_TPM_CLKSRC; - _REG(KINETIS_SIM_SOPT2) = regval; - - - /* Enabled System Clock Gating Control for TPM */ - - regval = _REG(KINETIS_SIM_SCGC2); - regval |= TONE_ALARM_SIM_SCGC2_TPM; - _REG(KINETIS_SIM_SCGC2) = regval; - - /* disable and configure the timer */ - - rSC = TPM_SC_TOF; - - rCNT = 0; - rMOD = TONE_ALARM_COUNTER_PERIOD - 1; - - rSTATUS = (TPM_STATUS_TOF | STATUS); - - /* Configure for output compare to toggle on over flow */ - - rCNSC = (TPM_CnSC_CHF | TPM_CnSC_MSA | TPM_CnSC_ELSA); - - rCOMBINE = 0; - rPOL = 0; - rFILTER = 0; - rQDCTRL = 0; - rCONF = TPM_CONF_DBGMODE_CONT; - - /* toggle the CC output each time the count passes 0 */ - - rCNV = 0; - - /* enable the timer */ - - rSC |= (TPM_SC_CMOD_LPTPM_CLK | TONE_ALARM_TIMER_PRESCALE); - - - /* default the timer to a modulo value of 1; playing notes will change this */ - rMOD = 0; - - DEVICE_DEBUG("ready"); - _running = true; - work_queue(HPWORK, &_work, (worker_t)&ToneAlarm::next_trampoline, this, 0); - return OK; -} - -void ToneAlarm::status() -{ - if (_running) { - PX4_INFO("running"); - - } else { - PX4_INFO("stopped"); - } -} - -unsigned ToneAlarm::frequency_to_divisor(unsigned frequency) -{ - float period = 0.5f / frequency; - - // and the divisor, rounded to the nearest integer - unsigned divisor = (period * TONE_ALARM_TIMER_FREQ) + 0.5f; - - return divisor; -} - -void ToneAlarm::start_note(unsigned frequency) -{ - // check if circuit breaker is enabled - if (_cbrk == CBRK_UNINIT) { - _cbrk = circuit_breaker_enabled("CBRK_BUZZER", CBRK_BUZZER_KEY); - } - - if (_cbrk != CBRK_OFF) { return; } - - // compute the divisor - unsigned divisor = frequency_to_divisor(frequency); - - rCNT = 0; - rMOD = divisor; // load new toggle period - - rSC |= (TPM_SC_CMOD_LPTPM_CLK); - - // configure the GPIO to enable timer output - px4_arch_configgpio(GPIO_TONE_ALARM); -} - -void ToneAlarm::stop_note() -{ - /* stop the current note */ - rSC &= ~TPM_SC_CMOD_MASK; - - /* - * Make sure the GPIO is not driving the speaker. - */ - px4_arch_configgpio(GPIO_TONE_ALARM_IDLE); -} - -void ToneAlarm::next_note() -{ - if (!_should_run) { - if (_tune_control_sub >= 0) { - orb_unsubscribe(_tune_control_sub); - } - - _running = false; - return; - } - - // subscribe to tune_control - if (_tune_control_sub < 0) { - _tune_control_sub = orb_subscribe(ORB_ID(tune_control)); - } - - // do we have an inter-note gap to wait for? - if (_silence_length > 0) { - stop_note(); - work_queue(HPWORK, &_work, (worker_t)&ToneAlarm::next_trampoline, this, USEC2TICK(_silence_length)); - _silence_length = 0; - return; - } - - // check for updates - bool updated = false; - orb_check(_tune_control_sub, &updated); - - if (updated) { - orb_copy(ORB_ID(tune_control), _tune_control_sub, &_tune); - _play_tone = _tunes.set_control(_tune) == 0; - } - - unsigned frequency = 0; - unsigned duration = 0; - - if (_play_tone) { - _play_tone = false; - int parse_ret_val = _tunes.get_next_tune(frequency, duration, _silence_length); - - if (parse_ret_val >= 0) { - // a frequency of 0 correspond to stop_note - if (frequency > 0) { - // start playing the note - start_note(frequency); - - } else { - stop_note(); - } - - - if (parse_ret_val > 0) { - // continue playing - _play_tone = true; - } - } - - } else { - // schedule a call with the tunes max interval - duration = _tunes.get_maximum_update_interval(); - // stop playing the last note after the duration elapsed - stop_note(); - } - - // and arrange a callback when the note should stop - work_queue(HPWORK, &_work, (worker_t)&ToneAlarm::next_trampoline, this, USEC2TICK(duration)); -} - -void ToneAlarm::next_trampoline(void *arg) -{ - ToneAlarm *ta = (ToneAlarm *)arg; - ta->next_note(); -} - -/** - * Local functions in support of the shell command. - */ -namespace -{ - -ToneAlarm *g_dev; - -} // namespace - -void tone_alarm_usage(); - -void tone_alarm_usage() -{ - PX4_INFO("missing command, try 'start', status, 'stop'"); -} - -int tone_alarm_main(int argc, char *argv[]) -{ - - if (argc > 1) { - const char *argv1 = argv[1]; - - if (!strcmp(argv1, "start")) { - if (g_dev != nullptr) { - PX4_ERR("already started"); - return 1; - } - - if (g_dev == nullptr) { - g_dev = new ToneAlarm(); - - if (g_dev == nullptr) { - PX4_ERR("couldn't allocate the ToneAlarm driver"); - return 1; - } - - if (OK != g_dev->init()) { - delete g_dev; - g_dev = nullptr; - PX4_ERR("ToneAlarm init failed"); - return 1; - } - } - - return 0; - } - - if (!strcmp(argv1, "stop")) { - delete g_dev; - g_dev = nullptr; - return 0; - } - - if (!strcmp(argv1, "status")) { - g_dev->status(); - return 0; - } - - } - - tone_alarm_usage(); - return 0; -} diff --git a/src/drivers/sim/tone_alarm/CMakeLists.txt b/src/drivers/sim/tone_alarm/CMakeLists.txt new file mode 100644 index 0000000000..5251d3910a --- /dev/null +++ b/src/drivers/sim/tone_alarm/CMakeLists.txt @@ -0,0 +1,36 @@ +############################################################################ +# +# Copyright (c) 2015-2019 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_library(tone_alarm_interface + ToneAlarmInterface.cpp +) diff --git a/src/drivers/sim/tone_alarm/ToneAlarmInterface.cpp b/src/drivers/sim/tone_alarm/ToneAlarmInterface.cpp new file mode 100644 index 0000000000..7e25fc774f --- /dev/null +++ b/src/drivers/sim/tone_alarm/ToneAlarmInterface.cpp @@ -0,0 +1,54 @@ +/**************************************************************************** + * + * Copyright (C) 2013-2019 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 ToneAlarmInterface.cpp + */ + +#include <lib/drivers/tone_alarm/ToneAlarmInterface.h> +#include <px4_defines.h> + +void ToneAlarmInterface::init() +{ + // Nothing to be done in simulation. +} + +void ToneAlarmInterface::start_note(unsigned frequency) +{ + // Nothing to be done in simulation. +} + +void ToneAlarmInterface::stop_note() +{ + // Nothing to be done in simulation. +} diff --git a/src/drivers/stm32/tone_alarm/CMakeLists.txt b/src/drivers/stm32/tone_alarm/CMakeLists.txt index c54cbdd3ec..5251d3910a 100644 --- a/src/drivers/stm32/tone_alarm/CMakeLists.txt +++ b/src/drivers/stm32/tone_alarm/CMakeLists.txt @@ -1,6 +1,6 @@ ############################################################################ # -# Copyright (c) 2015 PX4 Development Team. All rights reserved. +# Copyright (c) 2015-2019 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 @@ -31,12 +31,6 @@ # ############################################################################ -px4_add_module( - MODULE drivers__tone_alarm - MAIN tone_alarm - SRCS - tone_alarm.cpp - DEPENDS - circuit_breaker - tunes - ) \ No newline at end of file +px4_add_library(tone_alarm_interface + ToneAlarmInterface.cpp +) diff --git a/src/drivers/stm32/tone_alarm/ToneAlarmInterface.cpp b/src/drivers/stm32/tone_alarm/ToneAlarmInterface.cpp new file mode 100644 index 0000000000..ddec21b4fd --- /dev/null +++ b/src/drivers/stm32/tone_alarm/ToneAlarmInterface.cpp @@ -0,0 +1,289 @@ +/**************************************************************************** + * + * Copyright (C) 2013-2019 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 ToneAlarmInterface.cpp + */ + +#include <drivers/device/device.h> +#include <lib/drivers/tone_alarm/ToneAlarmInterface.h> +#include <px4_defines.h> + +/* Check that tone alarm and HRT timers are different */ +#if defined(TONE_ALARM_TIMER) && defined(HRT_TIMER) +# if TONE_ALARM_TIMER == HRT_TIMER +# error TONE_ALARM_TIMER and HRT_TIMER must use different timers. +# endif +#endif + +/* Period of the free-running counter, in microseconds. */ +#ifndef TONE_ALARM_COUNTER_PERIOD +#define TONE_ALARM_COUNTER_PERIOD 65536 +#endif + +/* Tone alarm configuration */ +#if TONE_ALARM_TIMER == 1 +# define TONE_ALARM_BASE STM32_TIM1_BASE +# define TONE_ALARM_CLOCK STM32_APB2_TIM1_CLKIN +# define TONE_ALARM_CLOCK_ENABLE RCC_APB2ENR_TIM1EN +# define TONE_ALARM_CLOCK_POWER_REG STM32_RCC_APB2ENR +# if defined(CONFIG_STM32_TIM1) +# error Must not set CONFIG_STM32_TIM1 when TONE_ALARM_TIMER is 1 +# endif +#elif TONE_ALARM_TIMER == 2 +# define TONE_ALARM_BASE STM32_TIM2_BASE +# define TONE_ALARM_CLOCK STM32_APB1_TIM2_CLKIN +# define TONE_ALARM_CLOCK_ENABLE RCC_APB1ENR_TIM2EN +# define TONE_ALARM_CLOCK_POWER_REG STM32_RCC_APB1ENR +# if defined(CONFIG_STM32_TIM2) +# error Must not set CONFIG_STM32_TIM2 when TONE_ALARM_TIMER is 2 +# endif +#elif TONE_ALARM_TIMER == 3 +# define TONE_ALARM_BASE STM32_TIM3_BASE +# define TONE_ALARM_CLOCK STM32_APB1_TIM3_CLKIN +# define TONE_ALARM_CLOCK_ENABLE RCC_APB1ENR_TIM3EN +# define TONE_ALARM_CLOCK_POWER_REG STM32_RCC_APB1ENR +# if defined(CONFIG_STM32_TIM3) +# error Must not set CONFIG_STM32_TIM3 when TONE_ALARM_TIMER is 3 +# endif +#elif TONE_ALARM_TIMER == 4 +# define TONE_ALARM_BASE STM32_TIM4_BASE +# define TONE_ALARM_CLOCK STM32_APB1_TIM4_CLKIN +# define TONE_ALARM_CLOCK_ENABLE RCC_APB1ENR_TIM4EN +# define TONE_ALARM_CLOCK_POWER_REG STM32_RCC_APB1ENR +# if defined(CONFIG_STM32_TIM4) +# error Must not set CONFIG_STM32_TIM4 when TONE_ALARM_TIMER is 4 +# endif +#elif TONE_ALARM_TIMER == 5 +# define TONE_ALARM_BASE STM32_TIM5_BASE +# define TONE_ALARM_CLOCK STM32_APB1_TIM5_CLKIN +# define TONE_ALARM_CLOCK_ENABLE RCC_APB1ENR_TIM5EN +# define TONE_ALARM_CLOCK_POWER_REG STM32_RCC_APB1ENR +# if defined(CONFIG_STM32_TIM5) +# error Must not set CONFIG_STM32_TIM5 when TONE_ALARM_TIMER is 5 +# endif +#elif TONE_ALARM_TIMER == 8 +# define TONE_ALARM_BASE STM32_TIM8_BASE +# define TONE_ALARM_CLOCK STM32_APB2_TIM8_CLKIN +# define TONE_ALARM_CLOCK_ENABLE RCC_APB2ENR_TIM8EN +# define TONE_ALARM_CLOCK_POWER_REG STM32_RCC_APB2ENR +# if defined(CONFIG_STM32_TIM8) +# error Must not set CONFIG_STM32_TIM8 when TONE_ALARM_TIMER is 8 +# endif +#elif TONE_ALARM_TIMER == 9 +# define TONE_ALARM_BASE STM32_TIM9_BASE +# define TONE_ALARM_CLOCK STM32_APB2_TIM9_CLKIN +# define TONE_ALARM_CLOCK_ENABLE RCC_APB2ENR_TIM9EN +# define TONE_ALARM_CLOCK_POWER_REG STM32_RCC_APB2ENR +# if defined(CONFIG_STM32_TIM9) +# error Must not set CONFIG_STM32_TIM9 when TONE_ALARM_TIMER is 9 +# endif +#elif TONE_ALARM_TIMER == 10 +# define TONE_ALARM_BASE STM32_TIM10_BASE +# define TONE_ALARM_CLOCK STM32_APB2_TIM10_CLKIN +# define TONE_ALARM_CLOCK_ENABLE RCC_APB2ENR_TIM10EN +# define TONE_ALARM_CLOCK_POWER_REG STM32_RCC_APB2ENR +# if defined(CONFIG_STM32_TIM10) +# error Must not set CONFIG_STM32_TIM10 when TONE_ALARM_TIMER is 10 +# endif +#elif TONE_ALARM_TIMER == 11 +# define TONE_ALARM_BASE STM32_TIM11_BASE +# define TONE_ALARM_CLOCK STM32_APB2_TIM11_CLKIN +# define TONE_ALARM_CLOCK_ENABLE RCC_APB2ENR_TIM11EN +# define TONE_ALARM_CLOCK_POWER_REG STM32_RCC_APB2ENR +# if defined(CONFIG_STM32_TIM11) +# error Must not set CONFIG_STM32_TIM11 when TONE_ALARM_TIMER is 11 +# endif +#elif TONE_ALARM_TIMER == 12 +# define TONE_ALARM_BASE STM32_TIM12_BASE +# define TONE_ALARM_CLOCK STM32_APB1_TIM12_CLKIN +# define TONE_ALARM_CLOCK_ENABLE RCC_APB1ENR_TIM12EN +# define TONE_ALARM_CLOCK_POWER_REG STM32_RCC_APB1ENR +# if defined(CONFIG_STM32_TIM12) +# error Must not set CONFIG_STM32_TIM12 when TONE_ALARM_TIMER is 12 +# endif +#elif TONE_ALARM_TIMER == 13 +# define TONE_ALARM_BASE STM32_TIM13_BASE +# define TONE_ALARM_CLOCK STM32_APB1_TIM12_CLKIN +# define TONE_ALARM_CLOCK_ENABLE RCC_APB1ENR_TIM13EN +# define TONE_ALARM_CLOCK_POWER_REG STM32_RCC_APB1ENR +# if defined(CONFIG_STM32_TIM13) +# error Must not set CONFIG_STM32_TIM13 when TONE_ALARM_TIMER is 13 +# endif +#elif TONE_ALARM_TIMER == 14 +# define TONE_ALARM_BASE STM32_TIM14_BASE +# define TONE_ALARM_CLOCK STM32_APB1_TIM12_CLKIN +# define TONE_ALARM_CLOCK_ENABLE RCC_APB1ENR_TIM14EN +# define TONE_ALARM_CLOCK_POWER_REG STM32_RCC_APB1ENR +# if defined(CONFIG_STM32_TIM14) +# error Must not set CONFIG_STM32_TIM14 when TONE_ALARM_TIMER is 14 +# endif +#else +# error Must set TONE_ALARM_TIMER to one of the timers between 1 and 14 (inclusive) to use this driver. +#endif // TONE_ALARM_TIMER + +#if TONE_ALARM_CHANNEL == 1 +# define TONE_CCER (1 << 0) +# define TONE_CCMR1 (3 << 4) +# define TONE_CCMR2 0 +# define TONE_rCCR rCCR1 +#elif TONE_ALARM_CHANNEL == 2 +# define TONE_CCER (1 << 4) +# define TONE_CCMR1 (3 << 12) +# define TONE_CCMR2 0 +# define TONE_rCCR rCCR2 +#elif TONE_ALARM_CHANNEL == 3 +# define TONE_CCER (1 << 8) +# define TONE_CCMR1 0 +# define TONE_CCMR2 (3 << 4) +# define TONE_rCCR rCCR3 +#elif TONE_ALARM_CHANNEL == 4 +# define TONE_CCER (1 << 12) +# define TONE_CCMR1 0 +# define TONE_CCMR2 (3 << 12) +# define TONE_rCCR rCCR4 +#else +# error Must set TONE_ALARM_CHANNEL to a value between 1 and 4 to use this driver. +#endif // TONE_ALARM_CHANNEL + +/* Timer register accessors. */ +#define REG(_reg) (*(volatile uint32_t *)(TONE_ALARM_BASE + _reg)) + +#if TONE_ALARM_TIMER == 1 || TONE_ALARM_TIMER == 8 // Note: If using TIM1 or TIM8, then you are using the ADVANCED timers and NOT the GENERAL TIMERS, therefore different registers +# define rARR REG(STM32_ATIM_ARR_OFFSET) +# define rBDTR REG(STM32_ATIM_BDTR_OFFSET) +# define rCCER REG(STM32_ATIM_CCER_OFFSET) +# define rCCMR1 REG(STM32_ATIM_CCMR1_OFFSET) +# define rCCMR2 REG(STM32_ATIM_CCMR2_OFFSET) +# define rCCR1 REG(STM32_ATIM_CCR1_OFFSET) +# define rCCR2 REG(STM32_ATIM_CCR2_OFFSET) +# define rCCR3 REG(STM32_ATIM_CCR3_OFFSET) +# define rCCR4 REG(STM32_ATIM_CCR4_OFFSET) +# define rCNT REG(STM32_ATIM_CNT_OFFSET) +# define rCR1 REG(STM32_ATIM_CR1_OFFSET) +# define rCR2 REG(STM32_ATIM_CR2_OFFSET) +# define rDCR REG(STM32_ATIM_DCR_OFFSET) +# define rDIER REG(STM32_ATIM_DIER_OFFSET) +# define rDMAR REG(STM32_ATIM_DMAR_OFFSET) +# define rEGR REG(STM32_ATIM_EGR_OFFSET) +# define rPSC REG(STM32_ATIM_PSC_OFFSET) +# define rRCR REG(STM32_ATIM_RCR_OFFSET) +# define rSMCR REG(STM32_ATIM_SMCR_OFFSET) +# define rSR REG(STM32_ATIM_SR_OFFSET) +#else +# define rARR REG(STM32_GTIM_ARR_OFFSET) +# define rCCER REG(STM32_GTIM_CCER_OFFSET) +# define rCCMR1 REG(STM32_GTIM_CCMR1_OFFSET) +# define rCCMR2 REG(STM32_GTIM_CCMR2_OFFSET) +# define rCCR1 REG(STM32_GTIM_CCR1_OFFSET) +# define rCCR2 REG(STM32_GTIM_CCR2_OFFSET) +# define rCCR3 REG(STM32_GTIM_CCR3_OFFSET) +# define rCCR4 REG(STM32_GTIM_CCR4_OFFSET) +# define rCNT REG(STM32_GTIM_CNT_OFFSET) +# define rCR1 REG(STM32_GTIM_CR1_OFFSET) +# define rCR2 REG(STM32_GTIM_CR2_OFFSET) +# define rDCR REG(STM32_GTIM_DCR_OFFSET) +# define rDIER REG(STM32_GTIM_DIER_OFFSET) +# define rDMAR REG(STM32_GTIM_DMAR_OFFSET) +# define rEGR REG(STM32_GTIM_EGR_OFFSET) +# define rPSC REG(STM32_GTIM_PSC_OFFSET) +# define rRCR REG(STM32_GTIM_RCR_OFFSET) +# define rSMCR REG(STM32_GTIM_SMCR_OFFSET) +# define rSR REG(STM32_GTIM_SR_OFFSET) +#endif + +void ToneAlarmInterface::init() +{ +#ifdef GPIO_TONE_ALARM_NEG + px4_arch_configgpio(GPIO_TONE_ALARM_NEG); +#else + // Configure the GPIO to the idle state. + px4_arch_configgpio(GPIO_TONE_ALARM_IDLE); +#endif + + // Clock/power on our timer. + modifyreg32(TONE_ALARM_CLOCK_POWER_REG, 0, TONE_ALARM_CLOCK_ENABLE); + + // Initialize the timer. + rCCER &= TONE_CCER; // Unlock CCMR* registers. + rCCER = TONE_CCER; + rCCMR1 = TONE_CCMR1; + rCCMR2 = TONE_CCMR2; + rCR1 = 0; + rCR2 = 0; + rDCR = 0; + rDIER = 0; + rSMCR = 0; + +#ifdef rBDTR // If using an advanced timer, you need to activate the output. + rBDTR = ATIM_BDTR_MOE; // Enable the main output of the advanced timer. +#endif + + TONE_rCCR = 1; // Toggle the CC output each time the count passes 1. + rPSC = 0; // Default the timer to a prescale value of 1; playing notes will change this. + rCR1 = GTIM_CR1_CEN; // Ensure the timer is running. +} + +void ToneAlarmInterface::start_note(unsigned frequency) +{ + // Calculate the signal switching period. + // (Signal switching period is one half of the frequency period). + float signal_period = (1.0f / frequency) * 0.5f; + + // Calculate the hardware clock divisor rounded to the nearest integer. + unsigned int divisor = std::round(signal_period * TONE_ALARM_CLOCK); + + // Pick the lowest prescaler value that we can use. + // (Note that the effective prescale value is 1 greater.) + unsigned int prescale = divisor / TONE_ALARM_COUNTER_PERIOD; + + // Calculate the period for the selected prescaler value. + unsigned int period = (divisor / (prescale + 1)) - 1; + + rPSC = prescale; // Load new prescaler. + rARR = period; // Load new toggle period. + rEGR = GTIM_EGR_UG; // Force a reload of the period. + rCCER |= TONE_CCER; // Enable the output. + + // Configure the GPIO to enable timer output. + px4_arch_configgpio(GPIO_TONE_ALARM); +} + +void ToneAlarmInterface::stop_note() +{ + // Stop the current note. + rCCER &= ~TONE_CCER; + + // Ensure the GPIO is not driving the speaker. + px4_arch_configgpio(GPIO_TONE_ALARM_IDLE); +} diff --git a/src/drivers/stm32/tone_alarm/tone_alarm.cpp b/src/drivers/stm32/tone_alarm/tone_alarm.cpp deleted file mode 100644 index af9dddf0f9..0000000000 --- a/src/drivers/stm32/tone_alarm/tone_alarm.cpp +++ /dev/null @@ -1,586 +0,0 @@ -/**************************************************************************** - * - * Copyright (C) 2013, 2016, 2018 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. - * - ****************************************************************************/ - -/* - * Low Level Driver for the PX4 audio alarm port. Subscribes to - * tune_control and plays notes on this architecture specific - * timer HW - */ - -#include <px4_config.h> -#include <px4_log.h> -#include <debug.h> - -#include <drivers/device/device.h> -#include <drivers/drv_tone_alarm.h> - -#include <sys/types.h> -#include <stdint.h> -#include <stdbool.h> -#include <stdlib.h> -#include <string.h> -#include <fcntl.h> -#include <errno.h> -#include <stdio.h> -#include <unistd.h> -#include <math.h> -#include <ctype.h> - -#include <board_config.h> -#include <drivers/drv_hrt.h> - -#include <systemlib/err.h> -#include <circuit_breaker/circuit_breaker.h> - -#include <px4_workqueue.h> - -#include <lib/tunes/tunes.h> -#include <uORB/uORB.h> -#include <uORB/topics/tune_control.h> - -/* Check that tone alarm and HRT timers are different */ -#if defined(TONE_ALARM_TIMER) && defined(HRT_TIMER) -# if TONE_ALARM_TIMER == HRT_TIMER -# error TONE_ALARM_TIMER and HRT_TIMER must use different timers. -# endif -#endif - -/* Tone alarm configuration */ -#if TONE_ALARM_TIMER == 1 -# define TONE_ALARM_BASE STM32_TIM1_BASE -# define TONE_ALARM_CLOCK STM32_APB2_TIM1_CLKIN -# define TONE_ALARM_CLOCK_POWER_REG STM32_RCC_APB2ENR -# define TONE_ALARM_CLOCK_ENABLE RCC_APB2ENR_TIM1EN -# ifdef CONFIG_STM32_TIM1 -# error Must not set CONFIG_STM32_TIM1 when TONE_ALARM_TIMER is 1 -# endif -#elif TONE_ALARM_TIMER == 2 -# define TONE_ALARM_BASE STM32_TIM2_BASE -# define TONE_ALARM_CLOCK STM32_APB1_TIM2_CLKIN -# define TONE_ALARM_CLOCK_POWER_REG STM32_RCC_APB1ENR -# define TONE_ALARM_CLOCK_ENABLE RCC_APB1ENR_TIM2EN -# ifdef CONFIG_STM32_TIM2 -# error Must not set CONFIG_STM32_TIM2 when TONE_ALARM_TIMER is 2 -# endif -#elif TONE_ALARM_TIMER == 3 -# define TONE_ALARM_BASE STM32_TIM3_BASE -# define TONE_ALARM_CLOCK STM32_APB1_TIM3_CLKIN -# define TONE_ALARM_CLOCK_POWER_REG STM32_RCC_APB1ENR -# define TONE_ALARM_CLOCK_ENABLE RCC_APB1ENR_TIM3EN -# ifdef CONFIG_STM32_TIM3 -# error Must not set CONFIG_STM32_TIM3 when TONE_ALARM_TIMER is 3 -# endif -#elif TONE_ALARM_TIMER == 4 -# define TONE_ALARM_BASE STM32_TIM4_BASE -# define TONE_ALARM_CLOCK STM32_APB1_TIM4_CLKIN -# define TONE_ALARM_CLOCK_POWER_REG STM32_RCC_APB1ENR -# define TONE_ALARM_CLOCK_ENABLE RCC_APB1ENR_TIM4EN -# ifdef CONFIG_STM32_TIM4 -# error Must not set CONFIG_STM32_TIM4 when TONE_ALARM_TIMER is 4 -# endif -#elif TONE_ALARM_TIMER == 5 -# define TONE_ALARM_BASE STM32_TIM5_BASE -# define TONE_ALARM_CLOCK STM32_APB1_TIM5_CLKIN -# define TONE_ALARM_CLOCK_POWER_REG STM32_RCC_APB1ENR -# define TONE_ALARM_CLOCK_ENABLE RCC_APB1ENR_TIM5EN -# ifdef CONFIG_STM32_TIM5 -# error Must not set CONFIG_STM32_TIM5 when TONE_ALARM_TIMER is 5 -# endif -#elif TONE_ALARM_TIMER == 8 -# define TONE_ALARM_BASE STM32_TIM8_BASE -# define TONE_ALARM_CLOCK STM32_APB2_TIM8_CLKIN -# define TONE_ALARM_CLOCK_POWER_REG STM32_RCC_APB2ENR -# define TONE_ALARM_CLOCK_ENABLE RCC_APB2ENR_TIM8EN -# ifdef CONFIG_STM32_TIM8 -# error Must not set CONFIG_STM32_TIM8 when TONE_ALARM_TIMER is 8 -# endif -#elif TONE_ALARM_TIMER == 9 -# define TONE_ALARM_BASE STM32_TIM9_BASE -# define TONE_ALARM_CLOCK STM32_APB2_TIM9_CLKIN -# define TONE_ALARM_CLOCK_POWER_REG STM32_RCC_APB2ENR -# define TONE_ALARM_CLOCK_ENABLE RCC_APB2ENR_TIM9EN -# ifdef CONFIG_STM32_TIM9 -# error Must not set CONFIG_STM32_TIM9 when TONE_ALARM_TIMER is 9 -# endif -#elif TONE_ALARM_TIMER == 10 -# define TONE_ALARM_BASE STM32_TIM10_BASE -# define TONE_ALARM_CLOCK STM32_APB2_TIM10_CLKIN -# define TONE_ALARM_CLOCK_POWER_REG STM32_RCC_APB2ENR -# define TONE_ALARM_CLOCK_ENABLE RCC_APB2ENR_TIM10EN -# ifdef CONFIG_STM32_TIM10 -# error Must not set CONFIG_STM32_TIM10 when TONE_ALARM_TIMER is 10 -# endif -#elif TONE_ALARM_TIMER == 11 -# define TONE_ALARM_BASE STM32_TIM11_BASE -# define TONE_ALARM_CLOCK STM32_APB2_TIM11_CLKIN -# define TONE_ALARM_CLOCK_POWER_REG STM32_RCC_APB2ENR -# define TONE_ALARM_CLOCK_ENABLE RCC_APB2ENR_TIM11EN -# ifdef CONFIG_STM32_TIM11 -# error Must not set CONFIG_STM32_TIM11 when TONE_ALARM_TIMER is 11 -# endif -#elif TONE_ALARM_TIMER == 12 -# define TONE_ALARM_BASE STM32_TIM12_BASE -# define TONE_ALARM_CLOCK STM32_APB1_TIM12_CLKIN -# define TONE_ALARM_CLOCK_POWER_REG STM32_RCC_APB1ENR -# define TONE_ALARM_CLOCK_ENABLE RCC_APB1ENR_TIM12EN -# ifdef CONFIG_STM32_TIM12 -# error Must not set CONFIG_STM32_TIM12 when TONE_ALARM_TIMER is 12 -# endif -#elif TONE_ALARM_TIMER == 13 -# define TONE_ALARM_BASE STM32_TIM13_BASE -# define TONE_ALARM_CLOCK STM32_APB1_TIM12_CLKIN -# define TONE_ALARM_CLOCK_POWER_REG STM32_RCC_APB1ENR -# define TONE_ALARM_CLOCK_ENABLE RCC_APB1ENR_TIM13EN -# ifdef CONFIG_STM32_TIM13 -# error Must not set CONFIG_STM32_TIM13 when TONE_ALARM_TIMER is 13 -# endif -#elif TONE_ALARM_TIMER == 14 -# define TONE_ALARM_BASE STM32_TIM14_BASE -# define TONE_ALARM_CLOCK STM32_APB1_TIM12_CLKIN -# define TONE_ALARM_CLOCK_POWER_REG STM32_RCC_APB1ENR -# define TONE_ALARM_CLOCK_ENABLE RCC_APB1ENR_TIM14EN -# ifdef CONFIG_STM32_TIM14 -# error Must not set CONFIG_STM32_TIM14 when TONE_ALARM_TIMER is 14 -# endif -#else -# error Must set TONE_ALARM_TIMER to one of the timers between 1 and 14 (inclusive) to use this driver. -#endif - -#if TONE_ALARM_CHANNEL == 1 -# define TONE_CCMR1 (3 << 4) -# define TONE_CCMR2 0 -# define TONE_CCER (1 << 0) -# define TONE_rCCR rCCR1 -#elif TONE_ALARM_CHANNEL == 2 -# define TONE_CCMR1 (3 << 12) -# define TONE_CCMR2 0 -# define TONE_CCER (1 << 4) -# define TONE_rCCR rCCR2 -#elif TONE_ALARM_CHANNEL == 3 -# define TONE_CCMR1 0 -# define TONE_CCMR2 (3 << 4) -# define TONE_CCER (1 << 8) -# define TONE_rCCR rCCR3 -#elif TONE_ALARM_CHANNEL == 4 -# define TONE_CCMR1 0 -# define TONE_CCMR2 (3 << 12) -# define TONE_CCER (1 << 12) -# define TONE_rCCR rCCR4 -#else -# error Must set TONE_ALARM_CHANNEL to a value between 1 and 4 to use this driver. -#endif - - -/* - * Timer register accessors - */ -#define REG(_reg) (*(volatile uint32_t *)(TONE_ALARM_BASE + _reg)) - -#if TONE_ALARM_TIMER == 1 || TONE_ALARM_TIMER == 8 // Note: If using TIM1 or TIM8, then you are using the ADVANCED timers and NOT the GENERAL TIMERS, therefore different registers -# define rCR1 REG(STM32_ATIM_CR1_OFFSET) -# define rCR2 REG(STM32_ATIM_CR2_OFFSET) -# define rSMCR REG(STM32_ATIM_SMCR_OFFSET) -# define rDIER REG(STM32_ATIM_DIER_OFFSET) -# define rSR REG(STM32_ATIM_SR_OFFSET) -# define rEGR REG(STM32_ATIM_EGR_OFFSET) -# define rCCMR1 REG(STM32_ATIM_CCMR1_OFFSET) -# define rCCMR2 REG(STM32_ATIM_CCMR2_OFFSET) -# define rCCER REG(STM32_ATIM_CCER_OFFSET) -# define rCNT REG(STM32_ATIM_CNT_OFFSET) -# define rPSC REG(STM32_ATIM_PSC_OFFSET) -# define rARR REG(STM32_ATIM_ARR_OFFSET) -# define rRCR REG(STM32_ATIM_RCR_OFFSET) -# define rCCR1 REG(STM32_ATIM_CCR1_OFFSET) -# define rCCR2 REG(STM32_ATIM_CCR2_OFFSET) -# define rCCR3 REG(STM32_ATIM_CCR3_OFFSET) -# define rCCR4 REG(STM32_ATIM_CCR4_OFFSET) -# define rBDTR REG(STM32_ATIM_BDTR_OFFSET) -# define rDCR REG(STM32_ATIM_DCR_OFFSET) -# define rDMAR REG(STM32_ATIM_DMAR_OFFSET) -#else -# define rCR1 REG(STM32_GTIM_CR1_OFFSET) -# define rCR2 REG(STM32_GTIM_CR2_OFFSET) -# define rSMCR REG(STM32_GTIM_SMCR_OFFSET) -# define rDIER REG(STM32_GTIM_DIER_OFFSET) -# define rSR REG(STM32_GTIM_SR_OFFSET) -# define rEGR REG(STM32_GTIM_EGR_OFFSET) -# define rCCMR1 REG(STM32_GTIM_CCMR1_OFFSET) -# define rCCMR2 REG(STM32_GTIM_CCMR2_OFFSET) -# define rCCER REG(STM32_GTIM_CCER_OFFSET) -# define rCNT REG(STM32_GTIM_CNT_OFFSET) -# define rPSC REG(STM32_GTIM_PSC_OFFSET) -# define rARR REG(STM32_GTIM_ARR_OFFSET) -# define rCCR1 REG(STM32_GTIM_CCR1_OFFSET) -# define rCCR2 REG(STM32_GTIM_CCR2_OFFSET) -# define rCCR3 REG(STM32_GTIM_CCR3_OFFSET) -# define rCCR4 REG(STM32_GTIM_CCR4_OFFSET) -# define rDCR REG(STM32_GTIM_DCR_OFFSET) -# define rDMAR REG(STM32_GTIM_DMAR_OFFSET) -#endif - -#define CBRK_BUZZER_KEY 782097 - -class ToneAlarm : public cdev::CDev -{ -public: - ToneAlarm(); - ~ToneAlarm(); - - virtual int init(); - void status(); - - enum { - CBRK_OFF = 0, - CBRK_ON, - CBRK_UNINIT - }; - -private: - volatile bool _running; - volatile bool _should_run; - bool _play_tone; - - Tunes _tunes; - - unsigned _silence_length; // if nonzero, silence before next note - - int _cbrk; ///< if true, no audio output - int _tune_control_sub; - - tune_control_s _tune; - - static work_s _work; - - // Convert a frequency value into a divisor for the configured timer's clock. - // - unsigned frequency_to_divisor(unsigned frequency); - - // Start playing the note - // - void start_note(unsigned frequency); - - // Stop playing the current note and make the player 'safe' - // - void stop_note(); - - // Parse the next note out of the string and play it - // - void next_note(); - - // work queue trampoline for next_note - // - static void next_trampoline(void *arg); - -}; - -struct work_s ToneAlarm::_work = {}; - -/* - * Driver 'main' command. - */ -extern "C" __EXPORT int tone_alarm_main(int argc, char *argv[]); - - -ToneAlarm::ToneAlarm() : - CDev(TONEALARM0_DEVICE_PATH), - _running(false), - _should_run(true), - _play_tone(false), - _tunes(), - _silence_length(0), - _cbrk(CBRK_UNINIT), - _tune_control_sub(-1) -{ - // enable debug() calls - //_debug_enabled = true; -} - -ToneAlarm::~ToneAlarm() -{ - _should_run = false; - int counter = 0; - - while (_running && ++counter < 10) { - px4_usleep(100000); - } -} - -int ToneAlarm::init() -{ - int ret; - - ret = CDev::init(); - - if (ret != OK) { - return ret; - } - - /* configure the GPIO to the idle state */ - px4_arch_configgpio(GPIO_TONE_ALARM_IDLE); - -#ifdef GPIO_TONE_ALARM_NEG - - px4_arch_configgpio(GPIO_TONE_ALARM_NEG); -#endif - - /* clock/power on our timer */ - modifyreg32(TONE_ALARM_CLOCK_POWER_REG, 0, TONE_ALARM_CLOCK_ENABLE); - - /* initialise the timer */ - rCR1 = 0; - rCR2 = 0; - rSMCR = 0; - rDIER = 0; - rCCER &= TONE_CCER; /* unlock CCMR* registers */ - rCCMR1 = TONE_CCMR1; - rCCMR2 = TONE_CCMR2; - rCCER = TONE_CCER; - rDCR = 0; - -#ifdef rBDTR // If using an advanced timer, you need to activate the output - rBDTR = ATIM_BDTR_MOE; // enable the main output of the advanced timer -#endif - - /* toggle the CC output each time the count passes 1 */ - TONE_rCCR = 1; - - /* default the timer to a prescale value of 1; playing notes will change this */ - rPSC = 0; - - /* make sure the timer is running */ - rCR1 = GTIM_CR1_CEN; - - PX4_DEBUG("ready"); - - _running = true; - work_queue(HPWORK, &_work, (worker_t)&ToneAlarm::next_trampoline, this, 0); - return OK; -} - -void ToneAlarm::status() -{ - if (_running) { - PX4_INFO("running"); - - } else { - PX4_INFO("stopped"); - } -} - -unsigned ToneAlarm::frequency_to_divisor(unsigned frequency) -{ - float period = 0.5f / frequency; - - // and the divisor, rounded to the nearest integer - unsigned divisor = (period * TONE_ALARM_CLOCK) + 0.5f; - - return divisor; -} - -void ToneAlarm::start_note(unsigned frequency) -{ - // check if circuit breaker is enabled - if (_cbrk == CBRK_UNINIT) { - _cbrk = circuit_breaker_enabled("CBRK_BUZZER", CBRK_BUZZER_KEY); - } - - if (_cbrk != CBRK_OFF) { return; } - - // compute the divisor - unsigned divisor = frequency_to_divisor(frequency); - - // pick the lowest prescaler value that we can use - // (note that the effective prescale value is 1 greater) - unsigned prescale = divisor / 65536; - - // calculate the timer period for the selected prescaler value - unsigned period = (divisor / (prescale + 1)) - 1; - - rPSC = prescale; // load new prescaler - rARR = period; // load new toggle period - rEGR = GTIM_EGR_UG; // force a reload of the period - rCCER |= TONE_CCER; // enable the output - - // configure the GPIO to enable timer output - px4_arch_configgpio(GPIO_TONE_ALARM); -} - -void ToneAlarm::stop_note() -{ - /* stop the current note */ - rCCER &= ~TONE_CCER; - - /* - * Make sure the GPIO is not driving the speaker. - */ - px4_arch_configgpio(GPIO_TONE_ALARM_IDLE); -} - -void ToneAlarm::next_note() -{ - if (!_should_run) { - if (_tune_control_sub >= 0) { - orb_unsubscribe(_tune_control_sub); - } - - _running = false; - return; - } - - // subscribe to tune_control - if (_tune_control_sub < 0) { - _tune_control_sub = orb_subscribe(ORB_ID(tune_control)); - } - - // do we have an inter-note gap to wait for? - if (_silence_length > 0) { - stop_note(); - work_queue(HPWORK, &_work, (worker_t)&ToneAlarm::next_trampoline, this, USEC2TICK(_silence_length)); - _silence_length = 0; - return; - } - - // check for updates - bool updated = false; - orb_check(_tune_control_sub, &updated); - - if (updated) { - orb_copy(ORB_ID(tune_control), _tune_control_sub, &_tune); - _play_tone = _tunes.set_control(_tune) == 0; - } - - unsigned frequency = 0; - unsigned duration = 0; - - if (_play_tone) { - _play_tone = false; - int parse_ret_val = _tunes.get_next_tune(frequency, duration, _silence_length); - - if (parse_ret_val >= 0) { - // a frequency of 0 correspond to stop_note - if (frequency > 0) { - // start playing the note - start_note(frequency); - - } else { - stop_note(); - } - - - if (parse_ret_val > 0) { - // continue playing - _play_tone = true; - } - } - - } else { - // schedule a call with the tunes max interval - duration = _tunes.get_maximum_update_interval(); - // stop playing the last note after the duration elapsed - stop_note(); - } - - // and arrange a callback when the note should stop - work_queue(HPWORK, &_work, (worker_t)&ToneAlarm::next_trampoline, this, USEC2TICK(duration)); -} - -void ToneAlarm::next_trampoline(void *arg) -{ - ToneAlarm *ta = (ToneAlarm *)arg; - ta->next_note(); -} - -/** - * Local functions in support of the shell command. - */ -namespace -{ - -ToneAlarm *g_dev; - -} // namespace - -void tone_alarm_usage(); - -void tone_alarm_usage() -{ - PX4_INFO("missing command, try 'start', status, 'stop'"); -} - -int tone_alarm_main(int argc, char *argv[]) -{ - - if (argc > 1) { - const char *argv1 = argv[1]; - - if (!strcmp(argv1, "start")) { - if (g_dev != nullptr) { - PX4_ERR("already started"); - return 1; - } - - if (g_dev == nullptr) { - g_dev = new ToneAlarm(); - - if (g_dev == nullptr) { - PX4_ERR("couldn't allocate the ToneAlarm driver"); - return 1; - } - - if (OK != g_dev->init()) { - delete g_dev; - g_dev = nullptr; - PX4_ERR("ToneAlarm init failed"); - return 1; - } - } - - return 0; - } - - if (!strcmp(argv1, "stop")) { - delete g_dev; - g_dev = nullptr; - return 0; - } - - if (!strcmp(argv1, "status")) { - g_dev->status(); - return 0; - } - - } - - tone_alarm_usage(); - return 0; -} diff --git a/src/drivers/tone_alarm_sim/CMakeLists.txt b/src/drivers/tone_alarm/CMakeLists.txt similarity index 91% rename from src/drivers/tone_alarm_sim/CMakeLists.txt rename to src/drivers/tone_alarm/CMakeLists.txt index 85ae11cee6..f51963a178 100644 --- a/src/drivers/tone_alarm_sim/CMakeLists.txt +++ b/src/drivers/tone_alarm/CMakeLists.txt @@ -1,6 +1,6 @@ ############################################################################ # -# Copyright (c) 2015 PX4 Development Team. All rights reserved. +# Copyright (C) 2015-2019 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 @@ -30,11 +30,14 @@ # POSSIBILITY OF SUCH DAMAGE. # ############################################################################ + px4_add_module( - MODULE drivers__tone_alarm_sim + MODULE drivers__tone_alarm MAIN tone_alarm SRCS - tone_alarm.cpp + ToneAlarm.cpp DEPENDS - git_driverframework + circuit_breaker + tone_alarm_interface + tunes ) diff --git a/src/drivers/tone_alarm/ToneAlarm.cpp b/src/drivers/tone_alarm/ToneAlarm.cpp new file mode 100644 index 0000000000..851a456bef --- /dev/null +++ b/src/drivers/tone_alarm/ToneAlarm.cpp @@ -0,0 +1,242 @@ +/**************************************************************************** + * + * Copyright (C) 2013-2019 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 ToneAlarm.cpp + */ + +#include "ToneAlarm.h" + +#include <px4_time.h> + +ToneAlarm::ToneAlarm() : + CDev(TONE_ALARM0_DEVICE_PATH) +{ +} + +ToneAlarm::~ToneAlarm() +{ + _should_run = false; + int counter = 0; + + while (_running && counter < 10) { + px4_usleep(100000); + counter++; + } +} + +int ToneAlarm::init() +{ + if (CDev::init() != OK) { + return PX4_ERROR; + } + + // NOTE: Implement hardware specific detail in the ToneAlarmInterface class implementation. + ToneAlarmInterface::init(); + + _running = true; + work_queue(HPWORK, &_work, (worker_t)&ToneAlarm::next_trampoline, this, 0); + return OK; +} + +void ToneAlarm::next_note() +{ + if (!_should_run) { + if (_tune_control_sub >= 0) { + orb_unsubscribe(_tune_control_sub); + } + + _running = false; + return; + } + + // Subscribe to tune_control. + if (_tune_control_sub < 0) { + _tune_control_sub = orb_subscribe(ORB_ID(tune_control)); + } + + // Check for updates + orb_update(); + + unsigned int frequency = 0; + unsigned int duration = 0; + + // Does an inter-note silence occur? + if (_silence_length > 0) { + stop_note(); + duration = _silence_length; + _silence_length = 0; + + } else if (_play_tone) { + int parse_ret_val = _tunes.get_next_tune(frequency, duration, _silence_length); + + if (parse_ret_val > 0) { + // Continue playing. + _play_tone = true; + + // A frequency of 0 corresponds to stop_note(); + if (frequency > 0) { + // Start playing the note. + start_note(frequency); + } + + } else { + _play_tone = false; + stop_note(); + } + + } else { + // Schedule a callback with the tunes max interval. + duration = _tunes.get_maximum_update_interval(); + stop_note(); + } + + // Schedule a callback when the note should stop. + work_queue(HPWORK, &_work, (worker_t)&ToneAlarm::next_trampoline, this, USEC2TICK(duration)); +} + +void ToneAlarm::next_trampoline(void *argv) +{ + ToneAlarm *toneAlarm = (ToneAlarm *)argv; + toneAlarm->next_note(); +} + +void ToneAlarm::orb_update() +{ + // Check for updates + bool updated = false; + orb_check(_tune_control_sub, &updated); + + if (updated) { + orb_copy(ORB_ID(tune_control), _tune_control_sub, &_tune); + _play_tone = _tunes.set_control(_tune) == 0; + } +} + +void ToneAlarm::status() +{ + if (_running) { + PX4_INFO("running"); + + } else { + PX4_INFO("stopped"); + } +} + +void ToneAlarm::start_note(unsigned frequency) +{ + // Check if circuit breaker is enabled. + if (_cbrk == CBRK_UNINIT) { + _cbrk = circuit_breaker_enabled("CBRK_BUZZER", CBRK_BUZZER_KEY); + } + + if (_cbrk != CBRK_OFF) { + return; + } + + // NOTE: Implement hardware specific detail in the ToneAlarmInterface class implementation. + ToneAlarmInterface::start_note(frequency); +} + +void ToneAlarm::stop_note() +{ + // NOTE: Implement hardware specific detail in the ToneAlarmInterface class implementation. + ToneAlarmInterface::stop_note(); +} + + +struct work_s ToneAlarm::_work = {}; + +/** + * Local functions in support of the shell command. + */ +namespace +{ + +ToneAlarm *g_dev; + +} // namespace + +/** + * Tone alarm Driver 'main' command. + * Entry point for the tone_alarm driver module. + */ +extern "C" __EXPORT int tone_alarm_main(int argc, char *argv[]) +{ + if (argc > 1) { + const char *argv1 = argv[1]; + + if (!strcmp(argv1, "start")) { + if (g_dev == nullptr) { + g_dev = new ToneAlarm(); + + if (g_dev == nullptr) { + PX4_ERR("could not allocate the driver."); + } + + if (g_dev->init() != OK) { + delete g_dev; + g_dev = nullptr; + PX4_ERR("driver init failed."); + } + + } else { + PX4_INFO("already started"); + } + + return 0; + } + + if (!strcmp(argv1, "stop")) { + delete g_dev; + g_dev = nullptr; + return 0; + } + + if (!strcmp(argv1, "status")) { + if (g_dev != nullptr) { + g_dev->status(); + + } else { + PX4_INFO("driver stopped"); + } + + return 0; + } + + } else { + PX4_INFO("missing command, try 'start', status, 'stop'"); + } + + return 0; +}; diff --git a/src/drivers/tone_alarm/ToneAlarm.h b/src/drivers/tone_alarm/ToneAlarm.h new file mode 100644 index 0000000000..9bb533cd7a --- /dev/null +++ b/src/drivers/tone_alarm/ToneAlarm.h @@ -0,0 +1,120 @@ +/**************************************************************************** + * + * Copyright (C) 2018-2019 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 ToneAlarm.h + * + * Low Level Driver for the PX4 audio alarm port. Subscribes to + * tune_control and plays notes on this architecture specific timer HW. + */ + +#pragma once + +#include <circuit_breaker/circuit_breaker.h> +#include <drivers/device/device.h> +#include <drivers/drv_tone_alarm.h> +#include <lib/drivers/tone_alarm/ToneAlarmInterface.h> +#include <lib/tunes/tunes.h> +#include <px4_defines.h> +#include <px4_workqueue.h> +#include <string.h> + + +#if !defined(UNUSED) +# define UNUSED(a) ((void)(a)) +#endif + +class ToneAlarm : public cdev::CDev +{ +public: + ToneAlarm(); + ~ToneAlarm(); + + /** + * @brief Initializes the character device and hardware registers. + */ + int init(); + + /** + * @brief Prints the driver status to the console. + */ + void status(); + +protected: + + /** + * @brief Parses the next note out of the string and plays it. + */ + void next_note(); + + /** + * @brief Trampoline for the work queue. + * @param argv Pointer to the task startup arguments. + */ + static void next_trampoline(void *argv); + + /** + * @brief Updates the uORB topics for local subscribers. + */ + void orb_update(); + + /** + * @brief Starts playing the note. + */ + void start_note(unsigned frequency); + + /** + * @brief Stops playing the current note and makes the player 'safe'. + */ + void stop_note(); + + volatile bool _running{false}; ///< Flag to indicate the current driver status. + + int _cbrk{CBRK_UNINIT}; ///< If true, no audio output. + +private: + + volatile bool _should_run{true}; + + bool _play_tone{false}; + + unsigned int _silence_length{0}; ///< If nonzero, silence before next note. + + int _tune_control_sub{-1}; + + tune_control_s _tune{}; + + Tunes _tunes = Tunes(); + + static work_s _work; +}; diff --git a/src/drivers/tone_alarm_sim/tone_alarm.cpp b/src/drivers/tone_alarm_sim/tone_alarm.cpp deleted file mode 100644 index c5dc913b11..0000000000 --- a/src/drivers/tone_alarm_sim/tone_alarm.cpp +++ /dev/null @@ -1,341 +0,0 @@ -/**************************************************************************** - * - * Copyright (c) 2013, 2017-2018 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. - * - ****************************************************************************/ - -/* - * Simulated Low Level Driver for the PX4 audio alarm port. Subscribes to - * tune_control and plays notes on this architecture specific - * timer HW - */ - -#include <circuit_breaker/circuit_breaker.h> -#include <drivers/device/device.h> -#include <drivers/drv_hrt.h> -#include <drivers/drv_tone_alarm.h> -#include <lib/cdev/CDev.hpp> -#include <lib/tunes/tunes.h> -#include <px4_config.h> -#include <px4_posix.h> -#include <px4_workqueue.h> -#include <uORB/topics/tune_control.h> - -#if !defined(UNUSED) -# define UNUSED(a) ((void)(a)) -#endif - -#define CBRK_BUZZER_KEY 782097 - -class ToneAlarm : public cdev::CDev -{ -public: - ToneAlarm(); - ~ToneAlarm(); - - virtual int init(); - void status(); - - enum { - CBRK_OFF = 0, - CBRK_ON, - CBRK_UNINIT - }; - -private: - volatile bool _running; - volatile bool _should_run; - bool _play_tone; - - Tunes _tunes; - - unsigned _silence_length; // if nonzero, silence before next note - - int _cbrk; ///< if true, no audio output - int _tune_control_sub; - - tune_control_s _tune; - - static work_s _work; - - // Convert a frequency value into a divisor for the configured timer's clock. - // - unsigned frequency_to_divisor(unsigned frequency); - - // Start playing the note - // - void start_note(unsigned frequency); - - // Stop playing the current note and make the player 'safe' - // - void stop_note(); - - // Parse the next note out of the string and play it - // - void next_note(); - - // work queue trampoline for next_note - // - static void next_trampoline(void *arg); - - // Unused - virtual void _measure() {} -}; - -struct work_s ToneAlarm::_work = {}; - -/* - * Driver 'main' command. - */ -extern "C" __EXPORT int tone_alarm_main(int argc, char *argv[]); - - -ToneAlarm::ToneAlarm() : - CDev(TONEALARM0_DEVICE_PATH), - _running(false), - _should_run(true), - _play_tone(false), - _tunes(), - _silence_length(0), - _cbrk(CBRK_UNINIT), - _tune_control_sub(-1) -{ -} - -ToneAlarm::~ToneAlarm() -{ - _should_run = false; - int counter = 0; - - while (_running && ++counter < 10) { - px4_usleep(100000); - } -} - -int ToneAlarm::init() -{ - int ret = CDev::init(); - - if (ret != OK) { - return ret; - } - - _running = true; - work_queue(HPWORK, &_work, (worker_t)&ToneAlarm::next_trampoline, this, 0); - return OK; -} - -void ToneAlarm::status() -{ - if (_running) { - PX4_INFO("running"); - - } else { - PX4_INFO("stopped"); - } -} - -unsigned ToneAlarm::frequency_to_divisor(unsigned frequency) -{ - const int TONE_ALARM_CLOCK = 120000000ul / 4; - - float period = 0.5f / frequency; - - // and the divisor, rounded to the nearest integer - unsigned divisor = (period * TONE_ALARM_CLOCK) + 0.5f; - - return divisor; -} - -void ToneAlarm::start_note(unsigned frequency) -{ - // check if circuit breaker is enabled - if (_cbrk == CBRK_UNINIT) { - _cbrk = circuit_breaker_enabled("CBRK_BUZZER", CBRK_BUZZER_KEY); - } - - if (_cbrk != CBRK_OFF) { return; } - - // compute the divisor - unsigned divisor = frequency_to_divisor(frequency); - - // pick the lowest prescaler value that we can use - // (note that the effective prescale value is 1 greater) - unsigned prescale = divisor / 65536; - - // calculate the timer period for the selected prescaler value - unsigned period = (divisor / (prescale + 1)) - 1; - - // Silence warning of unused var - UNUSED(period); - PX4_DEBUG("ToneAlarm::start_note %u", period); -} - -void ToneAlarm::stop_note() -{ -} - -void ToneAlarm::next_note() -{ - if (!_should_run) { - if (_tune_control_sub >= 0) { - orb_unsubscribe(_tune_control_sub); - } - - _running = false; - return; - } - - // subscribe to tune_control - if (_tune_control_sub < 0) { - _tune_control_sub = orb_subscribe(ORB_ID(tune_control)); - } - - // do we have an inter-note gap to wait for? - if (_silence_length > 0) { - stop_note(); - work_queue(HPWORK, &_work, (worker_t)&ToneAlarm::next_trampoline, this, USEC2TICK(_silence_length)); - _silence_length = 0; - return; - } - - // check for updates - bool updated = false; - orb_check(_tune_control_sub, &updated); - - if (updated) { - orb_copy(ORB_ID(tune_control), _tune_control_sub, &_tune); - } - - unsigned frequency = 0; - unsigned duration = 0; - - if (_play_tone) { - _play_tone = false; - int parse_ret_val = _tunes.get_next_tune(frequency, duration, _silence_length); - - if (parse_ret_val >= 0) { - // a frequency of 0 correspond to stop_note - if (frequency > 0) { - // start playing the note - start_note(frequency); - - } else { - stop_note(); - } - - - if (parse_ret_val > 0) { - // continue playing - _play_tone = true; - } - } - - } else { - // schedule a call with the tunes max interval - duration = _tunes.get_maximum_update_interval(); - // stop playing the last note after the duration elapsed - stop_note(); - } - - // and arrange a callback when the note should stop - work_queue(HPWORK, &_work, (worker_t)&ToneAlarm::next_trampoline, this, USEC2TICK(duration)); -} - -void ToneAlarm::next_trampoline(void *arg) -{ - ToneAlarm *ta = (ToneAlarm *)arg; - ta->next_note(); -} - -/** - * Local functions in support of the shell command. - */ -namespace -{ - -ToneAlarm *g_dev; - -} // namespace - -void tone_alarm_usage(); - -void tone_alarm_usage() -{ - PX4_INFO("missing command, try 'start', status, 'stop'"); -} - -int tone_alarm_main(int argc, char *argv[]) -{ - - if (argc > 1) { - const char *argv1 = argv[1]; - - if (!strcmp(argv1, "start")) { - if (g_dev != nullptr) { - PX4_ERR("already started"); - return 1; - } - - if (g_dev == nullptr) { - g_dev = new ToneAlarm(); - - if (g_dev == nullptr) { - PX4_ERR("couldn't allocate the ToneAlarm driver"); - return 1; - } - - if (OK != g_dev->init()) { - delete g_dev; - g_dev = nullptr; - PX4_ERR("ToneAlarm init failed"); - return 1; - } - } - - return 0; - } - - if (!strcmp(argv1, "stop")) { - delete g_dev; - g_dev = nullptr; - return 0; - } - - if (!strcmp(argv1, "status")) { - g_dev->status(); - return 0; - } - - } - - tone_alarm_usage(); - return 0; -} diff --git a/src/lib/drivers/CMakeLists.txt b/src/lib/drivers/CMakeLists.txt index 489f563ef3..30ecbfc1d0 100644 --- a/src/lib/drivers/CMakeLists.txt +++ b/src/lib/drivers/CMakeLists.txt @@ -39,3 +39,4 @@ add_subdirectory(led) add_subdirectory(linux_gpio) add_subdirectory(magnetometer) add_subdirectory(smbus) +add_subdirectory(tone_alarm) diff --git a/src/lib/drivers/tone_alarm/CMakeLists.txt b/src/lib/drivers/tone_alarm/CMakeLists.txt new file mode 100644 index 0000000000..53b343a25e --- /dev/null +++ b/src/lib/drivers/tone_alarm/CMakeLists.txt @@ -0,0 +1,34 @@ +############################################################################ +# +# Copyright (c) 2015-2019 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. +# +############################################################################ + +# ToneAlarmInterface Library - Intentionally Blank diff --git a/src/lib/drivers/tone_alarm/ToneAlarmInterface.h b/src/lib/drivers/tone_alarm/ToneAlarmInterface.h new file mode 100644 index 0000000000..9d2b35d3bd --- /dev/null +++ b/src/lib/drivers/tone_alarm/ToneAlarmInterface.h @@ -0,0 +1,54 @@ +/**************************************************************************** + * + * Copyright (C) 2013-2019 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 ToneAlarmInterface.cpp + */ + +namespace ToneAlarmInterface +{ +/** + * @brief Activates/configures the hardware registers. + */ +void init(); + +/** + * @brief Starts playing the note. + */ +void start_note(unsigned frequency); + +/** + * @brief Stops playing the current note and makes the player 'safe'. + */ +void stop_note(); +}; // ToneAlarmInterface diff --git a/src/modules/mavlink/mavlink_receiver.cpp b/src/modules/mavlink/mavlink_receiver.cpp index 43eb00a44e..9c365da8f4 100644 --- a/src/modules/mavlink/mavlink_receiver.cpp +++ b/src/modules/mavlink/mavlink_receiver.cpp @@ -1696,7 +1696,7 @@ MavlinkReceiver::handle_message_play_tune(mavlink_message_t *msg) play_tune.target_component == 0)) { if (*tune == 'M') { - int fd = px4_open(TONEALARM0_DEVICE_PATH, PX4_F_WRONLY); + int fd = px4_open(TONE_ALARM0_DEVICE_PATH, PX4_F_WRONLY); if (fd >= 0) { px4_write(fd, tune, strlen(tune) + 1); diff --git a/src/systemcmds/tests/test_hrt.cpp b/src/systemcmds/tests/test_hrt.cpp index 8f51804b9d..e1711b3074 100644 --- a/src/systemcmds/tests/test_hrt.cpp +++ b/src/systemcmds/tests/test_hrt.cpp @@ -124,10 +124,10 @@ int test_tone(int argc, char *argv[]) int fd, result; unsigned long tone; - fd = px4_open(TONEALARM0_DEVICE_PATH, O_WRONLY); + fd = px4_open(TONE_ALARM0_DEVICE_PATH, O_WRONLY); if (fd < 0) { - printf("failed opening " TONEALARM0_DEVICE_PATH "\n"); + printf("failed opening " TONE_ALARM0_DEVICE_PATH "\n"); goto out; } -- GitLab