This commit is contained in:
parent
4aab101ebd
commit
237443fffb
|
@ -0,0 +1,89 @@
|
|||
/**
|
||||
* @file event_queue.cpp
|
||||
* This is a data structure which keeps track of all pending events
|
||||
* Implemented as a linked list, which is fine since the number of
|
||||
* pending events is pretty low
|
||||
* todo: MAYBE migrate to a better data structure, but that's low priority
|
||||
*
|
||||
* this data structure is NOT thread safe
|
||||
*
|
||||
* @date Apr 17, 2014
|
||||
* @author Andrey Belomutskiy, (c) 2012-2014
|
||||
*/
|
||||
|
||||
#include "event_queue.h"
|
||||
#include "efitime.h"
|
||||
#include "utlist.h"
|
||||
|
||||
EventQueue::EventQueue() {
|
||||
head = NULL;
|
||||
}
|
||||
|
||||
void EventQueue::insertTask(scheduling_s *scheduling, uint64_t nowUs, int delayUs, schfunc_t callback, void *param) {
|
||||
if (callback == NULL)
|
||||
firmwareError("NULL callback");
|
||||
uint64_t time = nowUs + delayUs;
|
||||
|
||||
scheduling->momentUs = time;
|
||||
#if EFI_SIGNAL_EXECUTOR_ONE_TIMER
|
||||
scheduling->callback = callback;
|
||||
scheduling->param = param;
|
||||
#endif
|
||||
|
||||
scheduling_s * elt;
|
||||
LL_FOREACH(head, elt)
|
||||
{
|
||||
if (elt == scheduling) {
|
||||
firmwareError("re-adding element");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
LL_PREPEND(head, scheduling);
|
||||
}
|
||||
|
||||
void EventQueue::insertTask(scheduling_s *scheduling, int delayUs, schfunc_t callback, void *param) {
|
||||
insertTask(scheduling, getTimeNowUs(), delayUs, callback, param);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timestamp of the soonest pending action
|
||||
*/
|
||||
uint64_t EventQueue::getNextEventTime(uint64_t nowUs) {
|
||||
scheduling_s * elt;
|
||||
// this is a large value which is expected to be larger than any real time
|
||||
uint64_t result = EMPTY_QUEUE;
|
||||
|
||||
LL_FOREACH(head, elt)
|
||||
{
|
||||
if (elt->momentUs <= nowUs) {
|
||||
// todo: I am not so sure about this branch
|
||||
continue;
|
||||
}
|
||||
if (elt->momentUs < result)
|
||||
result = elt->momentUs;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke all pending actions prior to specified timestamp
|
||||
*/
|
||||
void EventQueue::executeAll(uint64_t now) {
|
||||
scheduling_s * elt, *tmp;
|
||||
|
||||
// here we need safe iteration because we are removing elements
|
||||
LL_FOREACH_SAFE(head, elt, tmp)
|
||||
{
|
||||
if (elt->momentUs <= now) {
|
||||
LL_DELETE(head, elt);
|
||||
#if EFI_SIGNAL_EXECUTOR_ONE_TIMER
|
||||
elt->callback(elt->param);
|
||||
#endif /* EFI_SIGNAL_EXECUTOR_ONE_TIMER */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EventQueue::clear(void) {
|
||||
head = NULL;
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
* @file event_queue.h
|
||||
*
|
||||
* @date Apr 17, 2014
|
||||
* @author Andrey Belomutskiy, (c) 2012-2014
|
||||
*/
|
||||
|
||||
#include "signal_executor.h"
|
||||
|
||||
#ifndef EVENT_SCHEDULER_H_
|
||||
#define EVENT_SCHEDULER_H_
|
||||
|
||||
#define EMPTY_QUEUE 0x0FFFFFFFFFFFFFFFLL
|
||||
|
||||
class EventQueue {
|
||||
public:
|
||||
EventQueue();
|
||||
|
||||
void insertTask(scheduling_s *scheduling, int delayUs, schfunc_t callback, void *param);
|
||||
void insertTask(scheduling_s *scheduling, uint64_t nowUs, int delayUs, schfunc_t callback, void *param);
|
||||
|
||||
void executeAll(uint64_t now);
|
||||
|
||||
uint64_t getNextEventTime(uint64_t nowUs);
|
||||
void clear(void);
|
||||
private:
|
||||
scheduling_s *head;
|
||||
};
|
||||
|
||||
#endif /* EVENT_SCHEDULER_H_ */
|
|
@ -72,7 +72,7 @@ static void adc_callback_slow(ADCDriver *adcp, adcsample_t *buffer, size_t n) {
|
|||
|
||||
adcCallbackCounter_slow++;
|
||||
|
||||
newState.time = chTimeNow();
|
||||
// newState.time = chimeNow();
|
||||
for (int i = 0; i < EFI_ADC_SLOW_CHANNELS_COUNT; i++) {
|
||||
int value = getAvgAdcValue(i, slowAdcState.samples, ADC_GRP1_BUF_DEPTH_SLOW, EFI_ADC_SLOW_CHANNELS_COUNT);
|
||||
newState.adc_data[i] = value;
|
||||
|
|
|
@ -37,7 +37,7 @@ int getInternalAdcValue(int index);
|
|||
// this structure contains one multi-channel ADC state snapshot
|
||||
typedef struct {
|
||||
volatile adcsample_t adc_data[ADC_MAX_SLOW_CHANNELS_COUNT];
|
||||
time_t time;
|
||||
// time_t time;
|
||||
} adc_state;
|
||||
|
||||
typedef struct {
|
||||
|
|
|
@ -8,6 +8,7 @@ HW_LAYERESRC = $(PROJECT_DIR)/hw_layer/hardware.c \
|
|||
$(PROJECT_DIR)/hw_layer/lcd/lcd_HD44780.c \
|
||||
$(PROJECT_DIR)/hw_layer/can_hw.c \
|
||||
$(PROJECT_DIR)/hw_layer/HIP9011.c \
|
||||
$(PROJECT_DIR)/hw_layer/microsecond_timer.c \
|
||||
$(PROJECT_DIR)/hw_layer/serial_over_usb/usbcfg.c \
|
||||
$(PROJECT_DIR)/hw_layer/serial_over_usb/usbconsole.c \
|
||||
$(PROJECT_DIR)/hw_layer/flash.c \
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
/**
|
||||
* @file microsecond_timer.c
|
||||
*
|
||||
* Here we have a 1MHz timer dedicated to event scheduling. We are using one of the 32-bit timers here,
|
||||
* so this timer can schedule events up to 4B/100M ~ 4000 seconds ~ 1 hour from current time.
|
||||
*
|
||||
* @date Apr 14, 2014
|
||||
* @author Andrey Belomutskiy, (c) 2012-2013
|
||||
*/
|
||||
|
||||
#include "main.h"
|
||||
#include "signal_executor.h"
|
||||
#include "microsecond_timer.h"
|
||||
|
||||
// https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=https%3a%2f%2fmy.st.com%2fpublic%2fSTe2ecommunities%2fmcu%2fLists%2fcortex_mx_stm32%2fInterrupt%20on%20CEN%20bit%20setting%20in%20TIM7&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B¤tviews=474
|
||||
|
||||
#if EFI_PROD_CODE
|
||||
|
||||
static TIM_TypeDef *TIM = TIM5;
|
||||
|
||||
schfunc_t globalTimerCallback;
|
||||
|
||||
/**
|
||||
* sets the alarm to the specified number of microseconds from now
|
||||
*/
|
||||
void setHardwareUsTimer(int timeUs) {
|
||||
TIM->ARR = timeUs - 1;
|
||||
TIM->EGR |= TIM_EGR_UG; // generate an update event to reload timer's counter value
|
||||
TIM->CR1 |= TIM_CR1_CEN; // restart timer
|
||||
}
|
||||
|
||||
static void callback(void) {
|
||||
if (globalTimerCallback == NULL) {
|
||||
firmwareError("NULL globalTimerCallback");
|
||||
return;
|
||||
}
|
||||
globalTimerCallback(NULL);
|
||||
}
|
||||
|
||||
// if you decide to move this to .cpp do not forget to make that a C method
|
||||
CH_IRQ_HANDLER(STM32_TIM5_HANDLER) {
|
||||
CH_IRQ_PROLOGUE();
|
||||
if (((TIM->SR & 0x0001) != 0) && ((TIM->DIER & 0x0001) != 0)) {
|
||||
callback();
|
||||
}
|
||||
TIM->SR = (int) ~STM32_TIM_SR_UIF; // Interrupt has been handled
|
||||
CH_IRQ_EPILOGUE();
|
||||
}
|
||||
|
||||
void initMicrosecondTimer(void) {
|
||||
RCC ->APB1ENR |= RCC_APB1ENR_TIM5EN; // Enable TIM5 clock
|
||||
nvicEnableVector(TIM5_IRQn, CORTEX_PRIORITY_MASK(12));
|
||||
TIM->DIER |= TIM_DIER_UIE; // Enable interrupt on update event
|
||||
TIM->CR1 |= TIM_CR1_OPM; // one pulse mode: count down ARR and stop
|
||||
TIM->CR1 &= ~TIM_CR1_ARPE; /* ARR register is NOT buffered, allows to update timer's period on-fly. */
|
||||
|
||||
TIM->PSC = 84 - 1; // 168MHz / 2 / 84 = 1MHz, each tick is a microsecond
|
||||
}
|
||||
|
||||
#endif /* EFI_PROD_CODE */
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* @file microsecond_timer.h
|
||||
*
|
||||
* @date Apr 14, 2014
|
||||
* @author Andrey Belomutskiy, (c) 2012-2013
|
||||
*/
|
||||
|
||||
#ifndef SIGNAL_TEMP_H_
|
||||
#define SIGNAL_TEMP_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void initMicrosecondTimer(void);
|
||||
void setHardwareUsTimer(int timeUs);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* SIGNAL_TEMP_H_ */
|
|
@ -47,7 +47,7 @@ static void printGpsInfo(void) {
|
|||
|
||||
scheduleMsg(&logging, "m=%d,e=%d: vehicle speed = %f\r\n", gpsMesagesCount, uartErrors, getCurrentSpeed());
|
||||
|
||||
float sec = ((float) chTimeNow() / TICKS_IN_MS) / 1000;
|
||||
float sec = currentTimeMillis() / 1000.0;
|
||||
scheduleMsg(&logging, "communication speed: %f", gpsMesagesCount / sec);
|
||||
|
||||
print("GPS latitude = %f\r\n", GPSdata.latitude);
|
||||
|
|
|
@ -55,7 +55,7 @@ void startSimplePwm(PwmConfig *state, char *msg, brain_pin_e brainPin, io_pin_e
|
|||
|
||||
outputPinRegister(msg, state->outputPins[0], port, pin);
|
||||
|
||||
state->period = frequency2period(frequency);
|
||||
state->periodMs = frequency2period(frequency);
|
||||
weComplexInit(msg, state, 2, switchTimes, 1, pinStates, NULL, applyPinState);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
/**
|
||||
* @file signal_executor.c
|
||||
*
|
||||
* todo: we should split this file into two:
|
||||
* one for pure scheduling and another one for signal output which would
|
||||
* use the scheduling
|
||||
*
|
||||
* @date Dec 4, 2013
|
||||
* @author Andrey Belomutskiy, (c) 2012-2014
|
||||
*
|
||||
* This file is part of rusEfi - see http://rusefi.com
|
||||
*
|
||||
* rusEfi is free software; you can redistribute it and/or modify it under the terms of
|
||||
* the GNU General Public License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* rusEfi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
||||
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "main.h"
|
||||
#include "signal_executor.h"
|
||||
|
||||
#if EFI_WAVE_CHART
|
||||
#include "rpm_calculator.h"
|
||||
#endif
|
||||
|
||||
#if EFI_WAVE_ANALYZER
|
||||
|
||||
/**
|
||||
* Signal executors feed digital events right into WaveChart used by Sniffer tab of Dev Console
|
||||
*/
|
||||
#include "wave_analyzer.h"
|
||||
|
||||
#endif /* EFI_WAVE_ANALYZER */
|
||||
|
||||
#if EFI_PROD_CODE || EFI_SIMULATOR
|
||||
static Logging logger;
|
||||
#endif
|
||||
|
||||
void initSignalExecutor(void) {
|
||||
#if EFI_PROD_CODE || EFI_SIMULATOR
|
||||
initLogging(&logger, "s exec");
|
||||
#endif
|
||||
initSignalExecutorImpl();
|
||||
}
|
||||
|
||||
void initOutputSignalBase(OutputSignal *signal) {
|
||||
signal->status = IDLE;
|
||||
// signal->last_scheduling_time = 0;
|
||||
signal->initialized = TRUE;
|
||||
}
|
||||
|
||||
static void turnHigh(OutputSignal *signal) {
|
||||
#if EFI_DEFAILED_LOGGING
|
||||
// signal->hi_time = hTimeNow();
|
||||
#endif /* EFI_DEFAILED_LOGGING */
|
||||
io_pin_e pin = signal->io_pin;
|
||||
// turn the output level ACTIVE
|
||||
// todo: this XOR should go inside the setOutputPinValue method
|
||||
setOutputPinValue(pin, TRUE);
|
||||
// sleep for the needed duration
|
||||
|
||||
#if EFI_PROD_CODE || EFI_SIMULATOR
|
||||
if(
|
||||
pin == SPARKOUT_1_OUTPUT ||
|
||||
pin == SPARKOUT_3_OUTPUT) {
|
||||
// time_t now = hTimeNow();
|
||||
// float an = getCrankshaftAngle(now);
|
||||
// scheduleMsg(&logger, "spark up%d %d", pin, now);
|
||||
// scheduleMsg(&logger, "spark angle %d %f", (int)an, an);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if EFI_WAVE_CHART
|
||||
addWaveChartEvent(signal->name, "up", "");
|
||||
#endif /* EFI_WAVE_ANALYZER */
|
||||
}
|
||||
|
||||
static void turnLow(OutputSignal *signal) {
|
||||
// turn off the output
|
||||
// todo: this XOR should go inside the setOutputPinValue method
|
||||
setOutputPinValue(signal->io_pin, FALSE);
|
||||
|
||||
#if EFI_DEFAILED_LOGGING
|
||||
systime_t after = hTimeNow();
|
||||
debugInt(&signal->logging, "a_time", after - signal->hi_time);
|
||||
scheduleLogging(&signal->logging);
|
||||
#endif /* EFI_DEFAILED_LOGGING */
|
||||
|
||||
#if EFI_WAVE_CHART
|
||||
addWaveChartEvent(signal->name, "down", "");
|
||||
#endif /* EFI_WAVE_ANALYZER */
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param delay the number of ticks before the output signal
|
||||
* immediate output if delay is zero
|
||||
* @param dwell the number of ticks of output duration
|
||||
*
|
||||
*/
|
||||
|
||||
int getRevolutionCounter(void);
|
||||
|
||||
void scheduleOutput(OutputSignal *signal, float delayMs, float durationMs) {
|
||||
if (durationMs < 0) {
|
||||
firmwareError("duration cannot be negative: %d", durationMs);
|
||||
return;
|
||||
}
|
||||
|
||||
scheduleOutputBase(signal, delayMs, durationMs);
|
||||
|
||||
int index = getRevolutionCounter() % 2;
|
||||
scheduling_s * sUp = &signal->signalTimerUp[index];
|
||||
scheduling_s * sDown = &signal->signalTimerDown[index];
|
||||
|
||||
scheduleTask(sUp, MS2US(delayMs), (schfunc_t) &turnHigh, (void *) signal);
|
||||
scheduleTask(sDown, MS2US(delayMs + durationMs), (schfunc_t) &turnLow, (void*)signal);
|
||||
|
||||
// signal->last_scheduling_time = now;
|
||||
}
|
||||
|
||||
void scheduleOutputBase(OutputSignal *signal, float delayMs, float durationMs) {
|
||||
/**
|
||||
* it's better to check for the exact 'TRUE' value since otherwise
|
||||
* we would accept any memory garbage
|
||||
*/
|
||||
chDbgCheck(signal->initialized == TRUE, "Signal not initialized");
|
||||
// signal->offset = offset;
|
||||
// signal->duration = duration;
|
||||
}
|
||||
|
||||
|
||||
char *getPinName(io_pin_e io_pin) {
|
||||
switch (io_pin) {
|
||||
case SPARKOUT_1_OUTPUT:
|
||||
return "Spark 1";
|
||||
case SPARKOUT_2_OUTPUT:
|
||||
return "Spark 2";
|
||||
case SPARKOUT_3_OUTPUT:
|
||||
return "Spark 3";
|
||||
case SPARKOUT_4_OUTPUT:
|
||||
return "Spark 4";
|
||||
|
||||
case INJECTOR_1_OUTPUT:
|
||||
return "Injector 1";
|
||||
case INJECTOR_2_OUTPUT:
|
||||
return "Injector 2";
|
||||
case INJECTOR_3_OUTPUT:
|
||||
return "Injector 3";
|
||||
case INJECTOR_4_OUTPUT:
|
||||
return "Injector 4";
|
||||
case INJECTOR_5_OUTPUT:
|
||||
return "Injector 5";
|
||||
default:
|
||||
return "No name";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
/**
|
||||
* @file signal_executor.h
|
||||
* @brief Asynchronous output signal header
|
||||
*
|
||||
* @date Feb 10, 2013
|
||||
* @author Andrey Belomutskiy, (c) 2012-2014
|
||||
*/
|
||||
|
||||
#ifndef SPARKOUT_H_
|
||||
#define SPARKOUT_H_
|
||||
|
||||
#include "rusefi_enums.h"
|
||||
#include "global.h"
|
||||
#include "efifeatures.h"
|
||||
#include "io_pins.h"
|
||||
|
||||
#if EFI_PROD_CODE
|
||||
#include "datalogging.h"
|
||||
#endif /* EFI_PROD_CODE */
|
||||
|
||||
#if EFI_SIGNAL_EXECUTOR_SLEEP
|
||||
#include "signal_executor_sleep.h"
|
||||
#endif /* EFI_SIGNAL_EXECUTOR_SLEEP */
|
||||
|
||||
#if EFI_SIGNAL_EXECUTOR_SINGLE_TIMER
|
||||
#include "signal_executor_single_timer.h"
|
||||
#endif /* EFI_SIGNAL_EXECUTOR_SINGLE_TIMER */
|
||||
|
||||
typedef void (*schfunc_t)(void *);
|
||||
|
||||
typedef struct scheduling_struct scheduling_s;
|
||||
struct scheduling_struct {
|
||||
//int initialized;
|
||||
#if EFI_SIGNAL_EXECUTOR_SLEEP
|
||||
VirtualTimer timer;
|
||||
#endif /* EFI_SIGNAL_EXECUTOR_SLEEP */
|
||||
#if EFI_SIGNAL_EXECUTOR_SINGLE_TIMER
|
||||
volatile time_t moment;
|
||||
#endif /* EFI_SIGNAL_EXECUTOR_SINGLE_TIMER */
|
||||
|
||||
volatile uint64_t momentUs;
|
||||
#if EFI_SIGNAL_EXECUTOR_ONE_TIMER
|
||||
schfunc_t callback;
|
||||
void *param;
|
||||
#endif
|
||||
|
||||
scheduling_s *next;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
IDLE = 0, ACTIVE
|
||||
} executor_status_t;
|
||||
|
||||
/**
|
||||
* @brief Asynchronous output signal data structure
|
||||
*/
|
||||
typedef struct OutputSignal_struct OutputSignal;
|
||||
struct OutputSignal_struct {
|
||||
/**
|
||||
* name of this signal
|
||||
*/
|
||||
char *name;
|
||||
io_pin_e io_pin;
|
||||
#if 0 // depricated
|
||||
// time in system ticks
|
||||
volatile int offset;
|
||||
// time in system ticks
|
||||
volatile int duration;
|
||||
#endif
|
||||
int initialized;
|
||||
|
||||
// time_t last_scheduling_time;
|
||||
// time_t hi_time;
|
||||
|
||||
/**
|
||||
* We are alternating instances so that events which extend into next revolution are not overriden while
|
||||
* scheduling next revolution events
|
||||
*/
|
||||
scheduling_s signalTimerUp[2];
|
||||
scheduling_s signalTimerDown[2];
|
||||
|
||||
executor_status_t status;
|
||||
|
||||
#if EFI_SIGNAL_EXECUTOR_HW_TIMER
|
||||
// todo
|
||||
#endif
|
||||
|
||||
OutputSignal *next;
|
||||
};
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void initOutputSignal(OutputSignal *signal, io_pin_e ioPin);
|
||||
void scheduleOutput(OutputSignal *signal, float delayMs, float durationMs);
|
||||
void initOutputSignalBase(OutputSignal *signal);
|
||||
void scheduleOutputBase(OutputSignal *signal, float delayMs, float durationMs);
|
||||
|
||||
void initSignalExecutor(void);
|
||||
void initSignalExecutorImpl(void);
|
||||
void scheduleTask(scheduling_s *scheduling, int delayUs, schfunc_t callback, void *param);
|
||||
void scheduleByAngle(scheduling_s *timer, float angle, schfunc_t callback, void *param);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* SPARKOUT_H_ */
|
|
@ -0,0 +1,74 @@
|
|||
/**
|
||||
* @file signal_executor_single_timer_algo.c
|
||||
*
|
||||
* @date Nov 28, 2013
|
||||
* @author Andrey Belomutskiy, (c) 2012-2014
|
||||
*
|
||||
*
|
||||
* This file is part of rusEfi - see http://rusefi.com
|
||||
*
|
||||
* rusEfi is free software; you can redistribute it and/or modify it under the terms of
|
||||
* the GNU General Public License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* rusEfi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
||||
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "signal_executor.h"
|
||||
#include "signal_executor_single_timer_algo.h"
|
||||
#include "main.h"
|
||||
#include "utlist.h"
|
||||
#include "io_pins.h"
|
||||
|
||||
#if EFI_WAVE_ANALYZER
|
||||
#include "wave_analyzer.h"
|
||||
#include "wave_chart.h"
|
||||
extern WaveChart waveChart;
|
||||
#endif
|
||||
|
||||
#if EFI_SIGNAL_EXECUTOR_SINGLE_TIMER
|
||||
/**
|
||||
* @brief Output list
|
||||
*
|
||||
* List of all active output signals
|
||||
* This is actually the head of the list.
|
||||
* When the list is empty (initial state) the head of the list should be NULL.
|
||||
* This is by design.
|
||||
*/
|
||||
OutputSignal *st_output_list = NULL;
|
||||
|
||||
inline void registerSignal(OutputSignal *signal) {
|
||||
LL_APPEND(st_output_list, signal);
|
||||
}
|
||||
|
||||
void setOutputPinValue(io_pin_e pin, int value);
|
||||
|
||||
/**
|
||||
* @return time of next event within for this signal
|
||||
* @todo Find better name.
|
||||
*/
|
||||
inline time_t toggleSignalIfNeeded(OutputSignal *out, time_t now) {
|
||||
// chDbgCheck(out!=NULL, "out is NULL");
|
||||
// chDbgCheck(out->io_pin < IO_PIN_COUNT, "pin assertion");
|
||||
time_t last = out->last_scheduling_time;
|
||||
//estimated = last + out->timing[out->status];
|
||||
time_t estimated = last + GET_DURATION(out);
|
||||
if (now >= estimated) {
|
||||
out->status ^= 1; /* toggle status */
|
||||
//setOutputPinValue(out->io_pin, out->status); /* Toggle output */
|
||||
palWritePad(GPIOE, 5, out->status);
|
||||
#if EFI_WAVE_ANALYZER
|
||||
// addWaveChartEvent(out->name, out->status ? "up" : "down", "");
|
||||
#endif /* EFI_WAVE_ANALYZER */
|
||||
|
||||
// out->last_scheduling_time = now; /* store last update */
|
||||
estimated = now + GET_DURATION(out); /* update estimation */
|
||||
}
|
||||
return estimated - now;
|
||||
}
|
||||
#endif /* EFI_SIGNAL_EXECUTOR_SINGLE_TIMER */
|
|
@ -0,0 +1,14 @@
|
|||
/**
|
||||
* @file snow_blower.c
|
||||
* @brief Default configuration of a single-cylinder engine
|
||||
*
|
||||
* @date Sep 9, 2013
|
||||
* @author Andrey Belomutskiy, (c) 2012-2014
|
||||
*/
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#if EFI_ENGINE_SNOW_BLOWER
|
||||
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue