diff --git a/src/main/drivers/pwm_mapping.c b/src/main/drivers/pwm_mapping.c index a0239642abb..acc427ee48e 100644 --- a/src/main/drivers/pwm_mapping.c +++ b/src/main/drivers/pwm_mapping.c @@ -212,27 +212,27 @@ static bool checkPwmTimerConflicts(const timerHardware_t *timHw) } static void timerHardwareOverride(timerHardware_t * timer) { - // Never modify a beeper timer — beeperPwmInit() must find TIM_USE_BEEPER intact - if (timer->usageFlags & TIM_USE_BEEPER) { - return; - } switch (timerOverrides(timer2id(timer->tim))->outputMode) { case OUTPUT_MODE_MOTORS: - timer->usageFlags &= ~(TIM_USE_SERVO|TIM_USE_LED); + timer->usageFlags &= ~(TIM_USE_SERVO|TIM_USE_LED|TIM_USE_BEEPER); timer->usageFlags |= TIM_USE_MOTOR; break; case OUTPUT_MODE_SERVOS: - timer->usageFlags &= ~(TIM_USE_MOTOR|TIM_USE_LED); + timer->usageFlags &= ~(TIM_USE_MOTOR|TIM_USE_LED|TIM_USE_BEEPER); timer->usageFlags |= TIM_USE_SERVO; break; case OUTPUT_MODE_LED: - timer->usageFlags &= ~(TIM_USE_MOTOR|TIM_USE_SERVO); + timer->usageFlags &= ~(TIM_USE_MOTOR|TIM_USE_SERVO|TIM_USE_BEEPER); timer->usageFlags |= TIM_USE_LED; break; case OUTPUT_MODE_PINIO: - timer->usageFlags &= ~(TIM_USE_MOTOR|TIM_USE_SERVO|TIM_USE_LED); + timer->usageFlags &= ~(TIM_USE_MOTOR|TIM_USE_SERVO|TIM_USE_LED|TIM_USE_BEEPER); timer->usageFlags |= TIM_USE_PINIO; break; + case OUTPUT_MODE_BEEPER: + timer->usageFlags &= ~(TIM_USE_MOTOR|TIM_USE_SERVO|TIM_USE_LED|TIM_USE_PINIO); + timer->usageFlags |= TIM_USE_BEEPER; + break; } } diff --git a/src/main/drivers/pwm_mapping.h b/src/main/drivers/pwm_mapping.h index 4a6722046c5..afe9301f7e7 100644 --- a/src/main/drivers/pwm_mapping.h +++ b/src/main/drivers/pwm_mapping.h @@ -88,11 +88,9 @@ typedef struct { const timerHardware_t * timServos[MAX_PWM_OUTPUTS]; } timMotorServoHardware_t; -// Output assignment types for MSP2_INAV_OUTPUT_ASSIGNMENT response -// LED outputs are not reported here; they are already identified by TIM_USE_LED -// in the MSP2_INAV_OUTPUT_MAPPING_EXT2 usageFlags response. -#define OUTPUT_ASSIGNMENT_TYPE_MOTOR 1 -#define OUTPUT_ASSIGNMENT_TYPE_SERVO 2 +// MSP2_INAV_OUTPUT_ASSIGNMENT type byte: bit index of the TIM_USE_* flag. +// Matches the JavaScript TIM_USE_* constants in outputMapping.js (which are bit indices). +// Use __builtin_ctz(TIM_USE_x) to derive these from the bit-mask definitions in timer.h. #endif // SITL_BUILD bool pwmMotorAndServoInit(void); diff --git a/src/main/drivers/pwm_output.c b/src/main/drivers/pwm_output.c index a4efb9e3008..a0e983fcf19 100644 --- a/src/main/drivers/pwm_output.c +++ b/src/main/drivers/pwm_output.c @@ -764,7 +764,7 @@ void pwmWriteBeeper(bool onoffBeep) } } -void beeperPwmInit(ioTag_t tag, uint16_t frequency) +bool beeperPwmInit(ioTag_t tag, uint16_t frequency) { beeperPwm = NULL; @@ -774,14 +774,17 @@ void beeperPwmInit(ioTag_t tag, uint16_t frequency) // Attempt to allocate TCH TCH_t * tch = timerGetTCH(timHw); if (tch == NULL) { - return; + return false; } beeperPwm = &beeperPwmPort; beeperFrequency = frequency; IOConfigGPIOAF(IOGetByTag(tag), IOCFG_AF_PP, timHw->alternateFunction); pwmOutConfigTimer(beeperPwm, tch, PWM_TIMER_HZ, 1000000 / beeperFrequency, (1000000 / beeperFrequency) / 2); + return true; } + + return false; } #endif diff --git a/src/main/drivers/pwm_output.h b/src/main/drivers/pwm_output.h index 1dc644f7f4e..0aba4b142ef 100644 --- a/src/main/drivers/pwm_output.h +++ b/src/main/drivers/pwm_output.h @@ -59,7 +59,7 @@ bool pwmMotorConfig(const struct timerHardware_s *timerHardware, uint8_t motorIn void pwmServoPreconfigure(void); bool pwmServoConfig(const struct timerHardware_s *timerHardware, uint8_t servoIndex, uint16_t servoPwmRate, uint16_t servoCenterPulse, bool enableOutput); void pwmWriteBeeper(bool onoffBeep); -void beeperPwmInit(ioTag_t tag, uint16_t frequency); +bool beeperPwmInit(ioTag_t tag, uint16_t frequency); void sendDShotCommand(dshotCommands_e cmd); void initDShotCommands(void); diff --git a/src/main/drivers/sound_beeper.c b/src/main/drivers/sound_beeper.c index bc76117d180..19ae57ae97b 100644 --- a/src/main/drivers/sound_beeper.c +++ b/src/main/drivers/sound_beeper.c @@ -23,6 +23,7 @@ #include "drivers/time.h" #include "drivers/io.h" +#include "common/log.h" #include "drivers/timer.h" #include "drivers/pwm_mapping.h" #include "drivers/pwm_output.h" @@ -78,13 +79,41 @@ void beeperInit(const beeperDevConfig_t *config) #if !defined(BEEPER) UNUSED(config); #else + // Runtime output assignment: scan for any pad explicitly set to OUTPUT_MODE_BEEPER. + // pwmBuildTimerOutputList() runs before beeperInit(), so TIM_USE_BEEPER is already + // set on the runtime-assigned pad by the time we get here. + for (int idx = 0; idx < timerHardwareCount; idx++) { + const timerHardware_t *timHw = &timerHardware[idx]; + if (timerOverrides(timer2id(timHw->tim))->outputMode == OUTPUT_MODE_BEEPER) { + if (!beeperPwmInit(timHw->tag, BEEPER_PWM_FREQUENCY)) { + LOG_ERROR(PWM, "Beeper PWM init failed on assigned pad, beeper disabled"); + return; + } + beeperConfigMutable()->pwmMode = true; + systemBeep(false); + return; + } + } + + // Skip compile-time beeper pad if the user has overridden it to another function. + for (int idx = 0; idx < timerHardwareCount; idx++) { + if (timerHardware[idx].tag == config->ioTag) { + if (!(timerHardware[idx].usageFlags & TIM_USE_BEEPER)) { + return; + } + break; + } + } + beeperIO = IOGetByTag(config->ioTag); beeperInverted = config->isInverted; if (beeperIO) { IOInit(beeperIO, OWNER_BEEPER, RESOURCE_OUTPUT, 0); if (beeperConfig()->pwmMode) { - beeperPwmInit(config->ioTag, BEEPER_PWM_FREQUENCY); + if (!beeperPwmInit(config->ioTag, BEEPER_PWM_FREQUENCY)) { + LOG_ERROR(PWM, "Beeper PWM init failed on compile-time pad, beeper disabled"); + } } else { IOConfigGPIO(beeperIO, config->isOD ? IOCFG_OUT_OD : IOCFG_OUT_PP); } diff --git a/src/main/fc/cli.c b/src/main/fc/cli.c index 27713297c86..8ed295c2d3f 100644 --- a/src/main/fc/cli.c +++ b/src/main/fc/cli.c @@ -177,6 +177,7 @@ static const char * outputModeNames[] = { "SERVOS", "LED", "PINIO", + "BEEPER", NULL }; @@ -3225,6 +3226,8 @@ static void cliTimerOutputMode(char *cmdline) mode = OUTPUT_MODE_LED; } else if(!sl_strcasecmp("PINIO", tok)) { mode = OUTPUT_MODE_PINIO; + } else if(!sl_strcasecmp("BEEPER", tok)) { + mode = OUTPUT_MODE_BEEPER; } else { cliShowParseError(); return; @@ -5037,7 +5040,7 @@ const clicmd_t cmdTable[] = { #ifdef USE_OSD CLI_COMMAND_DEF("osd_layout", "get or set the layout of OSD items", "[ [ [ []]]]", cliOsdLayout), #endif - CLI_COMMAND_DEF("timer_output_mode", "get or set the outputmode for a given timer.", "[ []]", cliTimerOutputMode), + CLI_COMMAND_DEF("timer_output_mode", "get or set the outputmode for a given timer.", "[ []]", cliTimerOutputMode), }; static void cliHelp(char *cmdline) diff --git a/src/main/fc/fc_msp.c b/src/main/fc/fc_msp.c index e5cfe7e81e8..50ddc2d9f09 100644 --- a/src/main/fc/fc_msp.c +++ b/src/main/fc/fc_msp.c @@ -1812,14 +1812,22 @@ static bool mspFcProcessOutCommand(uint16_t cmdMSP, sbuf_t *dst, mspPostProcessF const timMotorServoHardware_t *hw = pwmGetOutputAssignment(); for (int m = 0; m < hw->maxTimMotorCount; m++) { sbufWriteU8(dst, (uint8_t)(hw->timMotors[m] - timerHardware)); - sbufWriteU8(dst, OUTPUT_ASSIGNMENT_TYPE_MOTOR); + sbufWriteU8(dst, __builtin_ctz(TIM_USE_MOTOR)); sbufWriteU8(dst, (uint8_t)(m + 1)); } for (int s = 0; s < hw->maxTimServoCount; s++) { sbufWriteU8(dst, (uint8_t)(hw->timServos[s] - timerHardware)); - sbufWriteU8(dst, OUTPUT_ASSIGNMENT_TYPE_SERVO); + sbufWriteU8(dst, __builtin_ctz(TIM_USE_SERVO)); sbufWriteU8(dst, (uint8_t)(s + 1)); } + for (int idx = 0; idx < timerHardwareCount; idx++) { + if (timerOverrides(timer2id(timerHardware[idx].tim))->outputMode == OUTPUT_MODE_BEEPER) { + sbufWriteU8(dst, (uint8_t)idx); + sbufWriteU8(dst, __builtin_ctz(TIM_USE_BEEPER)); + sbufWriteU8(dst, 1); + break; + } + } } break; #endif @@ -4911,14 +4919,22 @@ bool mspFCProcessInOutCommand(uint16_t cmdMSP, sbuf_t *dst, sbuf_t *src, mspResu for (int m = 0; m < tempOut.maxTimMotorCount; m++) { sbufWriteU8(dst, (uint8_t)(tempOut.timMotors[m] - timerHardware)); - sbufWriteU8(dst, OUTPUT_ASSIGNMENT_TYPE_MOTOR); + sbufWriteU8(dst, __builtin_ctz(TIM_USE_MOTOR)); sbufWriteU8(dst, (uint8_t)(m + 1)); } for (int s = 0; s < tempOut.maxTimServoCount; s++) { sbufWriteU8(dst, (uint8_t)(tempOut.timServos[s] - timerHardware)); - sbufWriteU8(dst, OUTPUT_ASSIGNMENT_TYPE_SERVO); + sbufWriteU8(dst, __builtin_ctz(TIM_USE_SERVO)); sbufWriteU8(dst, (uint8_t)(s + 1)); } + for (int idx = 0; idx < timerHardwareCount; idx++) { + if (proposedModes[timer2id(timerHardware[idx].tim)] == OUTPUT_MODE_BEEPER) { + sbufWriteU8(dst, (uint8_t)idx); + sbufWriteU8(dst, __builtin_ctz(TIM_USE_BEEPER)); + sbufWriteU8(dst, 1); + break; + } + } *ret = MSP_RESULT_ACK; } break; diff --git a/src/main/flight/mixer.h b/src/main/flight/mixer.h index 6c4370d4176..91f40406e6f 100644 --- a/src/main/flight/mixer.h +++ b/src/main/flight/mixer.h @@ -49,7 +49,8 @@ typedef enum { OUTPUT_MODE_MOTORS, OUTPUT_MODE_SERVOS, OUTPUT_MODE_LED, - OUTPUT_MODE_PINIO + OUTPUT_MODE_PINIO, + OUTPUT_MODE_BEEPER } outputMode_e; typedef struct motorAxisCorrectionLimits_s {