mirror of https://github.com/FOME-Tech/fome-fw.git
Merge remote-tracking branch 'upstream/master' into remove-plain-maf
This commit is contained in:
commit
ea487327e1
|
@ -18,6 +18,7 @@ jobs:
|
||||||
# Board configurations
|
# Board configurations
|
||||||
- build-target: frankenso_na6
|
- build-target: frankenso_na6
|
||||||
folder: frankenso
|
folder: frankenso
|
||||||
|
ini-file: rusefi_frankenso_na6.ini
|
||||||
|
|
||||||
- build-target: kinetis
|
- build-target: kinetis
|
||||||
folder: kinetis
|
folder: kinetis
|
||||||
|
@ -28,7 +29,7 @@ jobs:
|
||||||
|
|
||||||
- build-target: mre_f4_hardware_QC_special_build
|
- build-target: mre_f4_hardware_QC_special_build
|
||||||
folder: microrusefi
|
folder: microrusefi
|
||||||
ini-file: rusefi_microrusefi.ini
|
ini-file: rusefi_mre_f4.ini
|
||||||
|
|
||||||
- build-target: mre_f7
|
- build-target: mre_f7
|
||||||
folder: microrusefi
|
folder: microrusefi
|
||||||
|
|
|
@ -44,6 +44,8 @@ See https://rusefi.com/forum/viewtopic.php?f=5&t=9
|
||||||
|
|
||||||
| Release date | Revision | Details |
|
| Release date | Revision | Details |
|
||||||
| ------------ | --------- | ------- |
|
| ------------ | --------- | ------- |
|
||||||
|
| 07/26/2020 | r24635 | improvement #1637: DC motor idle air valve for late 90s German vehicles |
|
||||||
|
| 07/21/2020 | | bugfix #1592 injectors could stay open on transition from cranking to running under certain conditions |
|
||||||
| 06/17/2020 | r23656 | bugfix #1491 major performance/scheduling improvement |
|
| 06/17/2020 | r23656 | bugfix #1491 major performance/scheduling improvement |
|
||||||
| 05/21/2020 | r22961 | rusEFI console start-up time improvements |
|
| 05/21/2020 | r22961 | rusEFI console start-up time improvements |
|
||||||
| 04/18/2020 | r22231 | Renix 44-2-2 trigger support added |
|
| 04/18/2020 | r22231 | Renix 44-2-2 trigger support added |
|
||||||
|
|
|
@ -16,6 +16,7 @@ android {
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "com.rusefi.app"
|
applicationId "com.rusefi.app"
|
||||||
|
// Version 21 = Android_5.0_Lollipop
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 30
|
targetSdkVersion 30
|
||||||
versionCode 1
|
versionCode 1
|
||||||
|
|
|
@ -7,7 +7,6 @@ import com.hoho.android.usbserial.driver.ProbeTable;
|
||||||
import com.hoho.android.usbserial.driver.UsbSerialDriver;
|
import com.hoho.android.usbserial.driver.UsbSerialDriver;
|
||||||
import com.hoho.android.usbserial.driver.UsbSerialPort;
|
import com.hoho.android.usbserial.driver.UsbSerialPort;
|
||||||
import com.hoho.android.usbserial.driver.UsbSerialProber;
|
import com.hoho.android.usbserial.driver.UsbSerialProber;
|
||||||
import com.opensr5.Logger;
|
|
||||||
import com.opensr5.io.DataListener;
|
import com.opensr5.io.DataListener;
|
||||||
import com.rusefi.binaryprotocol.IncomingDataBuffer;
|
import com.rusefi.binaryprotocol.IncomingDataBuffer;
|
||||||
import com.rusefi.dfu.DfuLogic;
|
import com.rusefi.dfu.DfuLogic;
|
||||||
|
@ -31,9 +30,9 @@ public class AndroidSerial extends AbstractIoStream {
|
||||||
return prober.findAllDrivers(usbManager);
|
return prober.findAllDrivers(usbManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AndroidSerial(UsbSerialPort usbSerialPort, Logger logger) {
|
public AndroidSerial(UsbSerialPort usbSerialPort) {
|
||||||
this.usbSerialPort = usbSerialPort;
|
this.usbSerialPort = usbSerialPort;
|
||||||
dataBuffer = IncomingDataBuffer.createDataBuffer("", this, logger);
|
dataBuffer = IncomingDataBuffer.createDataBuffer("", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -49,7 +48,7 @@ public class AndroidSerial extends AbstractIoStream {
|
||||||
@Override
|
@Override
|
||||||
public void setInputListener(DataListener listener) {
|
public void setInputListener(DataListener listener) {
|
||||||
ByteReader reader = buffer -> usbSerialPort.read(buffer, 5000);
|
ByteReader reader = buffer -> usbSerialPort.read(buffer, 5000);
|
||||||
ByteReader.runReaderLoop("", listener, reader, Logger.CONSOLE);
|
ByteReader.runReaderLoop("", listener, reader, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -34,7 +34,6 @@ import android.widget.TextView;
|
||||||
|
|
||||||
import com.hoho.android.usbserial.driver.UsbSerialDriver;
|
import com.hoho.android.usbserial.driver.UsbSerialDriver;
|
||||||
import com.hoho.android.usbserial.driver.UsbSerialPort;
|
import com.hoho.android.usbserial.driver.UsbSerialPort;
|
||||||
import com.opensr5.Logger;
|
|
||||||
import com.rusefi.Listener;
|
import com.rusefi.Listener;
|
||||||
import com.rusefi.dfu.DfuConnection;
|
import com.rusefi.dfu.DfuConnection;
|
||||||
import com.rusefi.dfu.DfuImage;
|
import com.rusefi.dfu.DfuImage;
|
||||||
|
@ -233,9 +232,9 @@ public class rusEFI extends Activity {
|
||||||
port.open(connection);
|
port.open(connection);
|
||||||
port.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
|
port.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
|
||||||
|
|
||||||
AndroidSerial serial = new AndroidSerial(port, Logger.CONSOLE);
|
AndroidSerial serial = new AndroidSerial(port);
|
||||||
mResultView.append("Switching to DFU\n");
|
mResultView.append("Switching to DFU\n");
|
||||||
DfuHelper.sendDfuRebootCommand(serial, new StringBuilder(), Logger.CONSOLE);
|
DfuHelper.sendDfuRebootCommand(serial, new StringBuilder());
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new IllegalStateException(e);
|
throw new IllegalStateException(e);
|
||||||
|
|
|
@ -11,13 +11,13 @@ BOOTLOADER_CODE_DESTINATION_FILE=$BOOTLOADER_CODE_DESTINATION_PATH/bootloader_ge
|
||||||
echo "$SCRIPT_NAME: Starting bootloader compilation..."
|
echo "$SCRIPT_NAME: Starting bootloader compilation..."
|
||||||
make -j4 -f src/Makefile $1 $2 $3
|
make -j4 -f src/Makefile $1 $2 $3
|
||||||
|
|
||||||
[ $? -eq 0 ] || { echo "make compilation failed"; exit 1; }
|
# downstream scripts detect error condition by checking if the output file exists so we need to make sure we remove it
|
||||||
|
[ $? -eq 0 ] || { echo "ERROR: bootloader compilation failed"; rm -f blbuild/$BOOTLOADER_CODE_DESTINATION_FILE ; exit 1; }
|
||||||
|
|
||||||
echo "$SCRIPT_NAME: Bootloader build success."
|
echo "$SCRIPT_NAME: Bootloader build success."
|
||||||
|
|
||||||
cd blbuild
|
cd blbuild
|
||||||
# Generate a header file with binary bootloader code
|
# Generate a header file with binary bootloader code
|
||||||
rm -f $BOOTLOADER_CODE_DESTINATION_FILE
|
|
||||||
java -jar ../../../java_tools/bin2header.jar bootloader.bin "$BOOTLOADER_CODE_DESTINATION_FILE" "$BOOTLOADER_COMMENT static const volatile uint8_t bootloader_code[] BOOTLOADER_SECTION"
|
java -jar ../../../java_tools/bin2header.jar bootloader.bin "$BOOTLOADER_CODE_DESTINATION_FILE" "$BOOTLOADER_COMMENT static const volatile uint8_t bootloader_code[] BOOTLOADER_SECTION"
|
||||||
[ $? -eq 0 ] || { echo "$SCRIPT_NAME: error generating header file"; exit 1; }
|
[ $? -eq 0 ] || { echo "$SCRIPT_NAME: error generating header file"; exit 1; }
|
||||||
cd ..
|
cd ..
|
||||||
|
|
|
@ -166,6 +166,14 @@ static void setupDefaultSensorInputs() {
|
||||||
// iat = "23 - AN temp 2"
|
// iat = "23 - AN temp 2"
|
||||||
engineConfiguration->iat.adcChannel = EFI_ADC_1;
|
engineConfiguration->iat.adcChannel = EFI_ADC_1;
|
||||||
engineConfiguration->iat.config.bias_resistor = 2700;
|
engineConfiguration->iat.config.bias_resistor = 2700;
|
||||||
|
|
||||||
|
setCommonNTCSensor(&engineConfiguration->auxTempSensor1, 2700);
|
||||||
|
setCommonNTCSensor(&engineConfiguration->auxTempSensor2, 2700);
|
||||||
|
|
||||||
|
#if HW_CHECK_MODE
|
||||||
|
engineConfiguration->auxTempSensor1.adcChannel = EFI_ADC_2;
|
||||||
|
engineConfiguration->auxTempSensor2.adcChannel = EFI_ADC_3;
|
||||||
|
#endif // HW_CHECK_MODE
|
||||||
}
|
}
|
||||||
|
|
||||||
void setPinConfigurationOverrides(void) {
|
void setPinConfigurationOverrides(void) {
|
||||||
|
|
|
@ -898,10 +898,12 @@ int tunerStudioHandleCrcCommand(ts_channel_s *tsChannel, char *data, int incomin
|
||||||
break;
|
break;
|
||||||
#endif /* ENABLE_PERF_TRACE */
|
#endif /* ENABLE_PERF_TRACE */
|
||||||
case TS_GET_CONFIG_ERROR: {
|
case TS_GET_CONFIG_ERROR: {
|
||||||
#if HW_CHECK_MODE
|
|
||||||
#define configError "FACTORY_MODE_PLEASE_CONTACT_SUPPORT"
|
|
||||||
#else
|
|
||||||
char * configError = getFirmwareError();
|
char * configError = getFirmwareError();
|
||||||
|
#if HW_CHECK_MODE
|
||||||
|
// analog input errors are returned as firmware error in QC mode
|
||||||
|
if (!hasFirmwareError()) {
|
||||||
|
strcpy(configError, "FACTORY_MODE_PLEASE_CONTACT_SUPPORT");
|
||||||
|
}
|
||||||
#endif // HW_CHECK_MODE
|
#endif // HW_CHECK_MODE
|
||||||
sr5SendResponse(tsChannel, TS_CRC, reinterpret_cast<const uint8_t*>(configError), strlen(configError));
|
sr5SendResponse(tsChannel, TS_CRC, reinterpret_cast<const uint8_t*>(configError), strlen(configError));
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -323,7 +323,7 @@ static void showFuelInfo2(float rpm, float engineLoad) {
|
||||||
|
|
||||||
#if EFI_ENGINE_CONTROL
|
#if EFI_ENGINE_CONTROL
|
||||||
static void showFuelInfo(void) {
|
static void showFuelInfo(void) {
|
||||||
showFuelInfo2((float) GET_RPM(), getEngineLoadT(PASS_ENGINE_PARAMETER_SIGNATURE));
|
showFuelInfo2((float) GET_RPM(), getFuelingLoad(PASS_ENGINE_PARAMETER_SIGNATURE));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -99,7 +99,11 @@ static bool startupPositionError = false;
|
||||||
|
|
||||||
#define STARTUP_NEUTRAL_POSITION_ERROR_THRESHOLD 5
|
#define STARTUP_NEUTRAL_POSITION_ERROR_THRESHOLD 5
|
||||||
|
|
||||||
static SensorType indexToTpsSensor(size_t index) {
|
static SensorType indexToTpsSensor(size_t index, bool dcMotorIdleValve) {
|
||||||
|
if (dcMotorIdleValve) {
|
||||||
|
return SensorType::Tps2;
|
||||||
|
}
|
||||||
|
|
||||||
switch(index) {
|
switch(index) {
|
||||||
case 0: return SensorType::Tps1;
|
case 0: return SensorType::Tps1;
|
||||||
default: return SensorType::Tps2;
|
default: return SensorType::Tps2;
|
||||||
|
@ -127,7 +131,8 @@ static percent_t currentEtbDuty;
|
||||||
// this macro clamps both positive and negative percentages from about -100% to 100%
|
// this macro clamps both positive and negative percentages from about -100% to 100%
|
||||||
#define ETB_PERCENT_TO_DUTY(x) (clampF(-ETB_DUTY_LIMIT, 0.01f * (x), ETB_DUTY_LIMIT))
|
#define ETB_PERCENT_TO_DUTY(x) (clampF(-ETB_DUTY_LIMIT, 0.01f * (x), ETB_DUTY_LIMIT))
|
||||||
|
|
||||||
void EtbController::init(DcMotor *motor, int ownIndex, pid_s *pidParameters, const ValueProvider3D* pedalMap) {
|
void EtbController::init(SensorType positionSensor, DcMotor *motor, int ownIndex, pid_s *pidParameters, const ValueProvider3D* pedalMap) {
|
||||||
|
m_positionSensor = positionSensor;
|
||||||
m_motor = motor;
|
m_motor = motor;
|
||||||
m_myIndex = ownIndex;
|
m_myIndex = ownIndex;
|
||||||
m_pid.initPidClass(pidParameters);
|
m_pid.initPidClass(pidParameters);
|
||||||
|
@ -149,7 +154,7 @@ void EtbController::showStatus(Logging* logger) {
|
||||||
}
|
}
|
||||||
|
|
||||||
expected<percent_t> EtbController::observePlant() const {
|
expected<percent_t> EtbController::observePlant() const {
|
||||||
return Sensor::get(indexToTpsSensor(m_myIndex));
|
return Sensor::get(m_positionSensor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EtbController::setIdlePosition(percent_t pos) {
|
void EtbController::setIdlePosition(percent_t pos) {
|
||||||
|
@ -162,6 +167,15 @@ expected<percent_t> EtbController::getSetpoint() const {
|
||||||
return unexpected;
|
return unexpected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VW ETB idle mode uses an ETB only for idle (a mini-ETB sets the lower stop, and a normal cable
|
||||||
|
// can pull the throttle up off the stop.), so we directly control the throttle with the idle position.
|
||||||
|
if (CONFIG(dcMotorIdleValve)) {
|
||||||
|
#if EFI_TUNER_STUDIO
|
||||||
|
tsOutputChannels.etbTarget = m_idlePosition;
|
||||||
|
#endif // EFI_TUNER_STUDIO
|
||||||
|
return clampF(0, m_idlePosition, 100);
|
||||||
|
}
|
||||||
|
|
||||||
// If the pedal map hasn't been set, we can't provide a setpoint.
|
// If the pedal map hasn't been set, we can't provide a setpoint.
|
||||||
if (!m_pedalMap) {
|
if (!m_pedalMap) {
|
||||||
return unexpected;
|
return unexpected;
|
||||||
|
@ -195,7 +209,7 @@ expected<percent_t> EtbController::getSetpoint() const {
|
||||||
if (m_myIndex == 0) {
|
if (m_myIndex == 0) {
|
||||||
tsOutputChannels.etbTarget = targetPosition;
|
tsOutputChannels.etbTarget = targetPosition;
|
||||||
}
|
}
|
||||||
#endif
|
#endif // EFI_TUNER_STUDIO
|
||||||
|
|
||||||
return targetPosition;
|
return targetPosition;
|
||||||
}
|
}
|
||||||
|
@ -736,14 +750,18 @@ void doInitElectronicThrottle(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||||
addConsoleActionI("etb_freq", setEtbFrequency);
|
addConsoleActionI("etb_freq", setEtbFrequency);
|
||||||
#endif /* EFI_PROD_CODE */
|
#endif /* EFI_PROD_CODE */
|
||||||
|
|
||||||
// If you don't have a pedal, we have no business here.
|
// If you don't have a pedal (or VW idle valve mode), we have no business here.
|
||||||
if (!Sensor::hasSensor(SensorType::AcceleratorPedalPrimary)) {
|
if (!CONFIG(dcMotorIdleValve) && !Sensor::hasSensor(SensorType::AcceleratorPedalPrimary)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pedal2tpsMap.init(config->pedalToTpsTable, config->pedalToTpsPedalBins, config->pedalToTpsRpmBins);
|
pedal2tpsMap.init(config->pedalToTpsTable, config->pedalToTpsPedalBins, config->pedalToTpsRpmBins);
|
||||||
|
|
||||||
engine->etbActualCount = Sensor::hasSensor(SensorType::Tps2) ? 2 : 1;
|
if (CONFIG(dcMotorIdleValve)) {
|
||||||
|
engine->etbActualCount = 1;
|
||||||
|
} else {
|
||||||
|
engine->etbActualCount = Sensor::hasSensor(SensorType::Tps2) ? 2 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0 ; i < engine->etbActualCount; i++) {
|
for (int i = 0 ; i < engine->etbActualCount; i++) {
|
||||||
auto motor = initDcMotor(i, CONFIG(etb_use_two_wires) PASS_ENGINE_PARAMETER_SUFFIX);
|
auto motor = initDcMotor(i, CONFIG(etb_use_two_wires) PASS_ENGINE_PARAMETER_SUFFIX);
|
||||||
|
@ -751,7 +769,8 @@ void doInitElectronicThrottle(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||||
// If this motor is actually set up, init the etb
|
// If this motor is actually set up, init the etb
|
||||||
if (motor)
|
if (motor)
|
||||||
{
|
{
|
||||||
engine->etbControllers[i]->init(motor, i, &engineConfiguration->etb, &pedal2tpsMap);
|
auto positionSensor = indexToTpsSensor(i, CONFIG(dcMotorIdleValve));
|
||||||
|
engine->etbControllers[i]->init(positionSensor, motor, i, &engineConfiguration->etb, &pedal2tpsMap);
|
||||||
INJECT_ENGINE_REFERENCE(engine->etbControllers[i]);
|
INJECT_ENGINE_REFERENCE(engine->etbControllers[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "engine.h"
|
#include "engine.h"
|
||||||
#include "closed_loop_controller.h"
|
#include "closed_loop_controller.h"
|
||||||
#include "expected.h"
|
#include "expected.h"
|
||||||
|
#include "sensor.h"
|
||||||
|
|
||||||
class DcMotor;
|
class DcMotor;
|
||||||
class Logging;
|
class Logging;
|
||||||
|
@ -26,7 +27,7 @@ class Logging;
|
||||||
class IEtbController : public ClosedLoopController<percent_t, percent_t> {
|
class IEtbController : public ClosedLoopController<percent_t, percent_t> {
|
||||||
public:
|
public:
|
||||||
DECLARE_ENGINE_PTR;
|
DECLARE_ENGINE_PTR;
|
||||||
virtual void init(DcMotor *motor, int ownIndex, pid_s *pidParameters, const ValueProvider3D* pedalMap) = 0;
|
virtual void init(SensorType positionSensor, DcMotor *motor, int ownIndex, pid_s *pidParameters, const ValueProvider3D* pedalMap) = 0;
|
||||||
virtual void reset() = 0;
|
virtual void reset() = 0;
|
||||||
virtual void setIdlePosition(percent_t pos) = 0;
|
virtual void setIdlePosition(percent_t pos) = 0;
|
||||||
virtual void start() = 0;
|
virtual void start() = 0;
|
||||||
|
@ -35,7 +36,7 @@ public:
|
||||||
|
|
||||||
class EtbController : public IEtbController {
|
class EtbController : public IEtbController {
|
||||||
public:
|
public:
|
||||||
void init(DcMotor *motor, int ownIndex, pid_s *pidParameters, const ValueProvider3D* pedalMap) override;
|
void init(SensorType positionSensor, DcMotor *motor, int ownIndex, pid_s *pidParameters, const ValueProvider3D* pedalMap) override;
|
||||||
void setIdlePosition(percent_t pos) override;
|
void setIdlePosition(percent_t pos) override;
|
||||||
void reset() override;
|
void reset() override;
|
||||||
void start() override {}
|
void start() override {}
|
||||||
|
@ -74,6 +75,7 @@ protected:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_myIndex = 0;
|
int m_myIndex = 0;
|
||||||
|
SensorType m_positionSensor = SensorType::Invalid;
|
||||||
DcMotor *m_motor = nullptr;
|
DcMotor *m_motor = nullptr;
|
||||||
Pid m_pid;
|
Pid m_pid;
|
||||||
bool m_shouldResetPid = false;
|
bool m_shouldResetPid = false;
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "expected.h"
|
#include "expected.h"
|
||||||
#include "sensor.h"
|
#include "sensor.h"
|
||||||
#include "map.h"
|
#include "map.h"
|
||||||
|
#include "engine_math.h"
|
||||||
|
|
||||||
EXTERN_ENGINE;
|
EXTERN_ENGINE;
|
||||||
|
|
||||||
|
@ -27,6 +28,10 @@ expected<float> readGppwmChannel(gppwm_channel_e channel DECLARE_ENGINE_PARAMETE
|
||||||
return Sensor::get(SensorType::Clt);
|
return Sensor::get(SensorType::Clt);
|
||||||
case GPPWM_Iat:
|
case GPPWM_Iat:
|
||||||
return Sensor::get(SensorType::Iat);
|
return Sensor::get(SensorType::Iat);
|
||||||
|
case GPPWM_FuelLoad:
|
||||||
|
return getFuelingLoad(PASS_ENGINE_PARAMETER_SIGNATURE);
|
||||||
|
case GPPWM_IgnLoad:
|
||||||
|
return getIgnitionLoad(PASS_ENGINE_PARAMETER_SIGNATURE);
|
||||||
default:
|
default:
|
||||||
return unexpected;
|
return unexpected;
|
||||||
}
|
}
|
||||||
|
|
|
@ -202,7 +202,9 @@ void setIdleMode(idle_mode_e value DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
||||||
showIdleInfo();
|
showIdleInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void applyIACposition(percent_t position) {
|
#endif // EFI_UNIT_TEST
|
||||||
|
|
||||||
|
void applyIACposition(percent_t position DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
||||||
/**
|
/**
|
||||||
* currently idle level is an percent value (0-100 range), and PWM takes a float in the 0..1 range
|
* currently idle level is an percent value (0-100 range), and PWM takes a float in the 0..1 range
|
||||||
* todo: unify?
|
* todo: unify?
|
||||||
|
@ -216,12 +218,16 @@ static void applyIACposition(percent_t position) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#if EFI_ELECTRONIC_THROTTLE_BODY
|
#if EFI_ELECTRONIC_THROTTLE_BODY
|
||||||
setEtbIdlePosition(position);
|
setEtbIdlePosition(position PASS_ENGINE_PARAMETER_SUFFIX);
|
||||||
#endif
|
#endif // EFI_ELECTRONIC_THROTTLE_BODY
|
||||||
#if ! EFI_UNIT_TEST
|
#if ! EFI_UNIT_TEST
|
||||||
} if (CONFIG(useStepperIdle)) {
|
} else if (CONFIG(useStepperIdle)) {
|
||||||
iacMotor.setTargetPosition(duty * engineConfiguration->idleStepperTotalSteps);
|
iacMotor.setTargetPosition(duty * engineConfiguration->idleStepperTotalSteps);
|
||||||
#endif /* EFI_UNIT_TEST */
|
#endif /* EFI_UNIT_TEST */
|
||||||
|
} else if (CONFIG(dcMotorIdleValve)) {
|
||||||
|
#if EFI_ELECTRONIC_THROTTLE_BODY
|
||||||
|
setEtbIdlePosition(position PASS_ENGINE_PARAMETER_SUFFIX);
|
||||||
|
#endif // EFI_ELECTRONIC_THROTTLE_BODY
|
||||||
} else {
|
} else {
|
||||||
if (!CONFIG(isDoubleSolenoidIdle)) {
|
if (!CONFIG(isDoubleSolenoidIdle)) {
|
||||||
idleSolenoidOpen.setSimplePwmDutyCycle(duty);
|
idleSolenoidOpen.setSimplePwmDutyCycle(duty);
|
||||||
|
@ -239,11 +245,13 @@ static void applyIACposition(percent_t position) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ! EFI_UNIT_TEST
|
||||||
|
|
||||||
percent_t getIdlePosition(void) {
|
percent_t getIdlePosition(void) {
|
||||||
return engine->engineState.idle.currentIdlePosition;
|
return engine->engineState.idle.currentIdlePosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setIdleValvePosition(int positionPercent) {
|
void setManualIdleValvePosition(int positionPercent) {
|
||||||
if (positionPercent < 1 || positionPercent > 99)
|
if (positionPercent < 1 || positionPercent > 99)
|
||||||
return;
|
return;
|
||||||
scheduleMsg(logger, "setting idle valve position %d", positionPercent);
|
scheduleMsg(logger, "setting idle valve position %d", positionPercent);
|
||||||
|
@ -571,11 +579,8 @@ static percent_t automaticIdleController(float tpsPos DECLARE_ENGINE_PARAMETER_S
|
||||||
}
|
}
|
||||||
|
|
||||||
engine->engineState.idle.currentIdlePosition = iacPosition;
|
engine->engineState.idle.currentIdlePosition = iacPosition;
|
||||||
#if ! EFI_UNIT_TEST
|
applyIACposition(engine->engineState.idle.currentIdlePosition PASS_ENGINE_PARAMETER_SUFFIX);
|
||||||
applyIACposition(engine->engineState.idle.currentIdlePosition);
|
}
|
||||||
#endif /* EFI_UNIT_TEST */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
IdleController idleControllerInstance;
|
IdleController idleControllerInstance;
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,10 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
percent_t getIdlePosition(void);
|
percent_t getIdlePosition(void);
|
||||||
void setIdleValvePosition(int positionPercent);
|
|
||||||
|
void applyIACposition(percent_t position DECLARE_ENGINE_PARAMETER_SUFFIX);
|
||||||
|
void setManualIdleValvePosition(int positionPercent);
|
||||||
|
|
||||||
void startIdleThread(Logging*sharedLogger DECLARE_ENGINE_PARAMETER_SUFFIX);
|
void startIdleThread(Logging*sharedLogger DECLARE_ENGINE_PARAMETER_SUFFIX);
|
||||||
void setDefaultIdleParameters(DECLARE_CONFIG_PARAMETER_SIGNATURE);
|
void setDefaultIdleParameters(DECLARE_CONFIG_PARAMETER_SIGNATURE);
|
||||||
void startIdleBench(void);
|
void startIdleBench(void);
|
||||||
|
|
|
@ -315,7 +315,7 @@ void TpsAccelEnrichment::onEngineCycleTps(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadAccelEnrichment::onEngineCycle(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
void LoadAccelEnrichment::onEngineCycle(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||||
onNewValue(getEngineLoadT(PASS_ENGINE_PARAMETER_SIGNATURE) PASS_ENGINE_PARAMETER_SUFFIX);
|
onNewValue(getFuelingLoad(PASS_ENGINE_PARAMETER_SIGNATURE) PASS_ENGINE_PARAMETER_SUFFIX);
|
||||||
}
|
}
|
||||||
|
|
||||||
AccelEnrichment::AccelEnrichment() {
|
AccelEnrichment::AccelEnrichment() {
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
#include "airmass.h"
|
||||||
|
|
||||||
|
AirmassModelBase::AirmassModelBase(const ValueProvider3D& veTable) : m_veTable(&veTable) {}
|
||||||
|
|
||||||
|
float AirmassModelBase::getVe(int rpm, float load) const {
|
||||||
|
efiAssert(OBD_PCM_Processor_Fault, m_veTable != nullptr, "VE table null", 0);
|
||||||
|
|
||||||
|
// TODO: allow override of the Y axis value based on a config field
|
||||||
|
return m_veTable->getValue(rpm, load);
|
||||||
|
}
|
|
@ -1,6 +1,24 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "engine.h"
|
||||||
|
|
||||||
|
class ValueProvider3D;
|
||||||
|
|
||||||
struct AirmassResult {
|
struct AirmassResult {
|
||||||
float CylinderAirmass = 0;
|
float CylinderAirmass = 0;
|
||||||
float EngineLoadPercent = 100;
|
float EngineLoadPercent = 100;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct AirmassModelBase {
|
||||||
|
DECLARE_ENGINE_PTR;
|
||||||
|
|
||||||
|
AirmassModelBase(const ValueProvider3D& veTable);
|
||||||
|
virtual AirmassResult getAirmass(int rpm) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Retrieve the user-calibrated volumetric efficiency from the table
|
||||||
|
float getVe(int rpm, percent_t load) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const ValueProvider3D* const m_veTable;
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
#include "alphan_airmass.h"
|
||||||
|
#include "sensor.h"
|
||||||
|
|
||||||
|
AirmassResult AlphaNAirmass::getAirmass(int rpm) {
|
||||||
|
auto tps = Sensor::get(SensorType::Tps1);
|
||||||
|
|
||||||
|
if (!tps.Valid) {
|
||||||
|
// We are fully reliant on TPS - if the TPS fails, stop the engine.
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// In this case, VE directly describes the cylinder filling relative to the ideal
|
||||||
|
float ve = getVe(rpm, tps.Value);
|
||||||
|
|
||||||
|
// TODO: should this be barometric pressure and/or temperature compensated?
|
||||||
|
float airmass = getAirmassImpl(
|
||||||
|
ve / 100.0f,
|
||||||
|
101.325f, // std atmosphere pressure
|
||||||
|
273.0f + 20.0f // std atmosphere pressure
|
||||||
|
PASS_ENGINE_PARAMETER_SUFFIX
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
airmass,
|
||||||
|
tps.Value
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "speed_density_base.h"
|
||||||
|
|
||||||
|
class AlphaNAirmass : public SpeedDensityBase {
|
||||||
|
public:
|
||||||
|
AlphaNAirmass(const ValueProvider3D& veTable) : SpeedDensityBase(veTable) {}
|
||||||
|
|
||||||
|
AirmassResult getAirmass(int rpm) override;
|
||||||
|
};
|
|
@ -0,0 +1,46 @@
|
||||||
|
#include "global.h"
|
||||||
|
#include "engine.h"
|
||||||
|
#include "maf_airmass.h"
|
||||||
|
#include "maf.h"
|
||||||
|
|
||||||
|
EXTERN_ENGINE;
|
||||||
|
|
||||||
|
AirmassResult MafAirmass::getAirmass(int rpm) {
|
||||||
|
float maf = getRealMaf(PASS_ENGINE_PARAMETER_SIGNATURE) + engine->engineLoadAccelEnrichment.getEngineLoadEnrichment(PASS_ENGINE_PARAMETER_SIGNATURE);
|
||||||
|
return getAirmassImpl(maf, rpm);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function block now works to create a standardised load from the cylinder filling as well as tune fuel via VE table.
|
||||||
|
* @return total duration of fuel injection per engine cycle, in milliseconds
|
||||||
|
*/
|
||||||
|
AirmassResult MafAirmass::getAirmassImpl(float massAirFlow, int rpm) const {
|
||||||
|
// If the engine is stopped, MAF is meaningless
|
||||||
|
if (rpm == 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// kg/hr -> g/s
|
||||||
|
float gramPerSecond = massAirFlow * 1000 / 3600;
|
||||||
|
|
||||||
|
// 1/min -> 1/s
|
||||||
|
float revsPerSecond = rpm / 60.0f;
|
||||||
|
float airPerRevolution = gramPerSecond / revsPerSecond;
|
||||||
|
|
||||||
|
// Now we have to divide among cylinders - on a 4 stroke, half of the cylinders happen every rev
|
||||||
|
// This math is floating point to work properly on engines with odd cyl count
|
||||||
|
float halfCylCount = CONFIG(specs.cylindersCount) / 2.0f;
|
||||||
|
|
||||||
|
float cylinderAirmass = airPerRevolution / halfCylCount;
|
||||||
|
|
||||||
|
//Create % load for fuel table using relative naturally aspiratedcylinder filling
|
||||||
|
float airChargeLoad = 100 * cylinderAirmass / ENGINE(standardAirCharge);
|
||||||
|
|
||||||
|
//Correct air mass by VE table
|
||||||
|
float correctedAirmass = cylinderAirmass * getVe(rpm, airChargeLoad) / 100;
|
||||||
|
|
||||||
|
return {
|
||||||
|
correctedAirmass,
|
||||||
|
airChargeLoad, // AFR/VE/ignition table Y axis
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "airmass.h"
|
||||||
|
|
||||||
|
class MafAirmass final : public AirmassModelBase {
|
||||||
|
public:
|
||||||
|
MafAirmass(const ValueProvider3D& veTable) : AirmassModelBase(veTable) {}
|
||||||
|
|
||||||
|
AirmassResult getAirmass(int rpm) override;
|
||||||
|
|
||||||
|
// Compute airmass based on flow & engine speed
|
||||||
|
AirmassResult getAirmassImpl(float massAirFlow, int rpm) const;
|
||||||
|
};
|
|
@ -0,0 +1,43 @@
|
||||||
|
#include "global.h"
|
||||||
|
#include "engine.h"
|
||||||
|
#include "speed_density_airmass.h"
|
||||||
|
#include "map.h"
|
||||||
|
#include "perf_trace.h"
|
||||||
|
|
||||||
|
EXTERN_ENGINE;
|
||||||
|
|
||||||
|
AirmassResult SpeedDensityAirmass::getAirmass(int rpm) {
|
||||||
|
ScopePerf perf(PE::GetSpeedDensityFuel);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* most of the values are pre-calculated for performance reasons
|
||||||
|
*/
|
||||||
|
float tChargeK = ENGINE(engineState.sd.tChargeK);
|
||||||
|
if (cisnan(tChargeK)) {
|
||||||
|
warning(CUSTOM_ERR_TCHARGE_NOT_READY2, "tChargeK not ready"); // this would happen before we have CLT reading for example
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
float map = getMap(PASS_ENGINE_PARAMETER_SIGNATURE);
|
||||||
|
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(map), "NaN map", {});
|
||||||
|
|
||||||
|
engine->engineState.sd.manifoldAirPressureAccelerationAdjustment = engine->engineLoadAccelEnrichment.getEngineLoadEnrichment(PASS_ENGINE_PARAMETER_SIGNATURE);
|
||||||
|
|
||||||
|
float adjustedMap = engine->engineState.sd.adjustedManifoldAirPressure = map + engine->engineState.sd.manifoldAirPressureAccelerationAdjustment;
|
||||||
|
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(adjustedMap), "NaN adjustedMap", {});
|
||||||
|
|
||||||
|
float airMass = getAirmassImpl(ENGINE(engineState.currentBaroCorrectedVE), adjustedMap, tChargeK PASS_ENGINE_PARAMETER_SUFFIX);
|
||||||
|
if (cisnan(airMass)) {
|
||||||
|
warning(CUSTOM_ERR_6685, "NaN airMass");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
#if EFI_PRINTF_FUEL_DETAILS
|
||||||
|
printf("getSpeedDensityAirmass map=%.2f adjustedMap=%.2f airMass=%.2f\t\n",
|
||||||
|
map, adjustedMap, engine->engineState.sd.adjustedManifoldAirPressure);
|
||||||
|
#endif /*EFI_PRINTF_FUEL_DETAILS */
|
||||||
|
|
||||||
|
return {
|
||||||
|
airMass,
|
||||||
|
map, // AFR/VE table Y axis
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "speed_density_base.h"
|
||||||
|
|
||||||
|
class SpeedDensityAirmass : public SpeedDensityBase {
|
||||||
|
public:
|
||||||
|
SpeedDensityAirmass(const ValueProvider3D& veTable) : SpeedDensityBase(veTable) {}
|
||||||
|
AirmassResult getAirmass(int rpm) override;
|
||||||
|
};
|
|
@ -9,11 +9,14 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "engine.h"
|
#include "airmass.h"
|
||||||
|
|
||||||
float idealGasLaw(float volume, float pressure, float temperature);
|
float idealGasLaw(float volume, float pressure, float temperature);
|
||||||
|
|
||||||
class SpeedDensityBase {
|
class SpeedDensityBase : public AirmassModelBase {
|
||||||
|
protected:
|
||||||
|
SpeedDensityBase(const ValueProvider3D& veTable) : AirmassModelBase(veTable) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static float getAirmassImpl(float ve, float manifoldPressure, float temperature DECLARE_ENGINE_PARAMETER_SUFFIX);
|
static float getAirmassImpl(float ve, float manifoldPressure, float temperature DECLARE_ENGINE_PARAMETER_SUFFIX);
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,4 +11,8 @@ CONTROLLERS_ALGO_SRC_CPP = $(PROJECT_DIR)/controllers/algo/advance_map.cpp \
|
||||||
$(PROJECT_DIR)/controllers/algo/engine2.cpp \
|
$(PROJECT_DIR)/controllers/algo/engine2.cpp \
|
||||||
$(PROJECT_DIR)/controllers/gauges/lcd_menu_tree.cpp \
|
$(PROJECT_DIR)/controllers/gauges/lcd_menu_tree.cpp \
|
||||||
$(PROJECT_DIR)/controllers/algo/event_registry.cpp \
|
$(PROJECT_DIR)/controllers/algo/event_registry.cpp \
|
||||||
|
$(PROJECT_DIR)/controllers/algo/airmass/airmass.cpp \
|
||||||
|
$(PROJECT_DIR)/controllers/algo/airmass/alphan_airmass.cpp \
|
||||||
|
$(PROJECT_DIR)/controllers/algo/airmass/maf_airmass.cpp \
|
||||||
|
$(PROJECT_DIR)/controllers/algo/airmass/speed_density_airmass.cpp \
|
||||||
$(PROJECT_DIR)/controllers/algo/airmass/speed_density_base.cpp \
|
$(PROJECT_DIR)/controllers/algo/airmass/speed_density_base.cpp \
|
||||||
|
|
|
@ -731,6 +731,10 @@ case LM_REAL_MAF:
|
||||||
return "LM_REAL_MAF";
|
return "LM_REAL_MAF";
|
||||||
case LM_SPEED_DENSITY:
|
case LM_SPEED_DENSITY:
|
||||||
return "LM_SPEED_DENSITY";
|
return "LM_SPEED_DENSITY";
|
||||||
|
case LM_ALPHA_N_2:
|
||||||
|
return "LM_ALPHA_N_2";
|
||||||
|
case LM_MOCK:
|
||||||
|
return "LM_MOCK";
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -914,6 +918,10 @@ case GPPWM_Map:
|
||||||
return "GPPWM_Map";
|
return "GPPWM_Map";
|
||||||
case GPPWM_Tps:
|
case GPPWM_Tps:
|
||||||
return "GPPWM_Tps";
|
return "GPPWM_Tps";
|
||||||
|
case GPPWM_FuelLoad:
|
||||||
|
return "GPPWM_FuelLoad";
|
||||||
|
case GPPWM_IgnLoad:
|
||||||
|
return "GPPWM_IgnLoad";
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,6 +130,14 @@ static void cylinderCleanupControl(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if HW_CHECK_MODE
|
||||||
|
static void assertCloseTo(const char * msg, float actual, float expected) {
|
||||||
|
if (actual < 0.9 * expected || actual > 1.1 * expected) {
|
||||||
|
firmwareError(OBD_PCM_Processor_Fault, "%s analog input validation failed %f vs %f", msg, actual, expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // HW_CHECK_MODE
|
||||||
|
|
||||||
void Engine::periodicSlowCallback(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
void Engine::periodicSlowCallback(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||||
ScopePerf perf(PE::EnginePeriodicSlowCallback);
|
ScopePerf perf(PE::EnginePeriodicSlowCallback);
|
||||||
|
|
||||||
|
@ -163,7 +171,14 @@ void Engine::periodicSlowCallback(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
slowCallBackWasInvoked = TRUE;
|
slowCallBackWasInvoked = true;
|
||||||
|
|
||||||
|
#if HW_CHECK_MODE
|
||||||
|
assertCloseTo("clt", Sensor::get(SensorType::Clt).Value, 49.3);
|
||||||
|
assertCloseTo("iat", Sensor::get(SensorType::Iat).Value, 73.2);
|
||||||
|
assertCloseTo("aut1", Sensor::get(SensorType::AuxTemp1).Value, 13.8);
|
||||||
|
assertCloseTo("aut2", Sensor::get(SensorType::AuxTemp2).Value, 6.2);
|
||||||
|
#endif // HW_CHECK_MODE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#define FAST_CALLBACK_PERIOD_MS 5
|
#define FAST_CALLBACK_PERIOD_MS 5
|
||||||
|
|
||||||
class RpmCalculator;
|
class RpmCalculator;
|
||||||
|
class AirmassModelBase;
|
||||||
|
|
||||||
#define MAF_DECODING_CACHE_SIZE 256
|
#define MAF_DECODING_CACHE_SIZE 256
|
||||||
|
|
||||||
|
@ -334,6 +335,8 @@ public:
|
||||||
void knockLogic(float knockVolts DECLARE_ENGINE_PARAMETER_SUFFIX);
|
void knockLogic(float knockVolts DECLARE_ENGINE_PARAMETER_SUFFIX);
|
||||||
void printKnockState(void);
|
void printKnockState(void);
|
||||||
|
|
||||||
|
AirmassModelBase* mockAirmassModel = nullptr;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* By the way:
|
* By the way:
|
||||||
|
|
|
@ -25,8 +25,6 @@
|
||||||
#include "engine_math.h"
|
#include "engine_math.h"
|
||||||
|
|
||||||
InjectionEvent::InjectionEvent() {
|
InjectionEvent::InjectionEvent() {
|
||||||
isSimultanious = false;
|
|
||||||
ownIndex = 0;
|
|
||||||
memset(outputs, 0, sizeof(outputs));
|
memset(outputs, 0, sizeof(outputs));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,13 +22,17 @@ class Engine;
|
||||||
class InjectionEvent {
|
class InjectionEvent {
|
||||||
public:
|
public:
|
||||||
InjectionEvent();
|
InjectionEvent();
|
||||||
|
|
||||||
|
// Call this every decoded trigger tooth. It will schedule any relevant events for this injector.
|
||||||
|
void onTriggerTooth(size_t toothIndex, int rpm, efitick_t nowNt);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a performance optimization for IM_SIMULTANEOUS fuel strategy.
|
* This is a performance optimization for IM_SIMULTANEOUS fuel strategy.
|
||||||
* It's more efficient to handle all injectors together if that's the case
|
* It's more efficient to handle all injectors together if that's the case
|
||||||
*/
|
*/
|
||||||
bool isSimultanious;
|
bool isSimultanious = false;
|
||||||
InjectorOutputPin *outputs[MAX_WIRES_COUNT];
|
InjectorOutputPin *outputs[MAX_WIRES_COUNT];
|
||||||
int ownIndex;
|
int ownIndex = 0;
|
||||||
DECLARE_ENGINE_PTR;
|
DECLARE_ENGINE_PTR;
|
||||||
event_trigger_position_s injectionStart;
|
event_trigger_position_s injectionStart;
|
||||||
|
|
||||||
|
@ -47,13 +51,16 @@ public:
|
||||||
WallFuel wallFuel;
|
WallFuel wallFuel;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class knows about when to inject fuel
|
* This class knows about when to inject fuel
|
||||||
*/
|
*/
|
||||||
class FuelSchedule {
|
class FuelSchedule {
|
||||||
public:
|
public:
|
||||||
FuelSchedule();
|
FuelSchedule();
|
||||||
|
|
||||||
|
// Call this every trigger tooth. It will schedule all required injector events.
|
||||||
|
void onTriggerTooth(size_t toothIndex, int rpm, efitick_t nowNt DECLARE_ENGINE_PARAMETER_SUFFIX);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* this method schedules all fuel events for an engine cycle
|
* this method schedules all fuel events for an engine cycle
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -23,6 +23,9 @@
|
||||||
|
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "airmass.h"
|
#include "airmass.h"
|
||||||
|
#include "alphan_airmass.h"
|
||||||
|
#include "maf_airmass.h"
|
||||||
|
#include "speed_density_airmass.h"
|
||||||
#include "fuel_math.h"
|
#include "fuel_math.h"
|
||||||
#include "interpolation.h"
|
#include "interpolation.h"
|
||||||
#include "engine_configuration.h"
|
#include "engine_configuration.h"
|
||||||
|
@ -153,41 +156,6 @@ floatms_t getRunningFuel(floatms_t baseFuel DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
||||||
|
|
||||||
/* DISPLAY_ENDIF */
|
/* DISPLAY_ENDIF */
|
||||||
|
|
||||||
/**
|
|
||||||
* Function block now works to create a standardised load from the cylinder filling as well as tune fuel via VE table.
|
|
||||||
* @return total duration of fuel injection per engine cycle, in milliseconds
|
|
||||||
*/
|
|
||||||
AirmassResult getRealMafAirmass(float airSpeed, int rpm DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
|
||||||
// If the engine is stopped, MAF is meaningless
|
|
||||||
if (rpm == 0) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// kg/hr -> g/s
|
|
||||||
float gramPerSecond = airSpeed * 1000 / 3600;
|
|
||||||
|
|
||||||
// 1/min -> 1/s
|
|
||||||
float revsPerSecond = rpm / 60.0f;
|
|
||||||
float airPerRevolution = gramPerSecond / revsPerSecond;
|
|
||||||
|
|
||||||
// Now we have to divide among cylinders - on a 4 stroke, half of the cylinders happen every rev
|
|
||||||
// This math is floating point to work properly on engines with odd cyl count
|
|
||||||
float halfCylCount = CONFIG(specs.cylindersCount) / 2.0f;
|
|
||||||
|
|
||||||
float cylinderAirmass = airPerRevolution / halfCylCount;
|
|
||||||
|
|
||||||
//Create % load for fuel table using relative naturally aspiratedcylinder filling
|
|
||||||
float airChargeLoad = 100 * cylinderAirmass / ENGINE(standardAirCharge);
|
|
||||||
|
|
||||||
//Correct air mass by VE table
|
|
||||||
float correctedAirmass = cylinderAirmass * veMap.getValue(rpm, airChargeLoad) / 100;
|
|
||||||
|
|
||||||
return {
|
|
||||||
correctedAirmass,
|
|
||||||
airChargeLoad, // AFR/VE table Y axis
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr float convertToGramsPerSecond(float ccPerMinute) {
|
constexpr float convertToGramsPerSecond(float ccPerMinute) {
|
||||||
float ccPerSecond = ccPerMinute / 60;
|
float ccPerSecond = ccPerMinute / 60;
|
||||||
return ccPerSecond * 0.72f; // 0.72g/cc fuel density
|
return ccPerSecond * 0.72f; // 0.72g/cc fuel density
|
||||||
|
@ -202,16 +170,19 @@ float getInjectionDurationForAirmass(float airMass, float afr DECLARE_ENGINE_PAR
|
||||||
return airMass / (afr * gPerSec);
|
return airMass / (afr * gPerSec);
|
||||||
}
|
}
|
||||||
|
|
||||||
AirmassResult getAirmass(int rpm DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
static SpeedDensityAirmass sdAirmass(veMap);
|
||||||
|
static MafAirmass mafAirmass(veMap);
|
||||||
|
static AlphaNAirmass alphaNAirmass(veMap);
|
||||||
|
|
||||||
|
AirmassModelBase* getAirmassModel(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||||
switch (CONFIG(fuelAlgorithm)) {
|
switch (CONFIG(fuelAlgorithm)) {
|
||||||
case LM_SPEED_DENSITY:
|
case LM_SPEED_DENSITY: return &sdAirmass;
|
||||||
return getSpeedDensityAirmass(PASS_ENGINE_PARAMETER_SIGNATURE);
|
case LM_REAL_MAF: return &mafAirmass;
|
||||||
case LM_REAL_MAF: {
|
case LM_ALPHA_N_2: return &alphaNAirmass;
|
||||||
float maf = getRealMaf(PASS_ENGINE_PARAMETER_SIGNATURE) + engine->engineLoadAccelEnrichment.getEngineLoadEnrichment(PASS_ENGINE_PARAMETER_SIGNATURE);
|
#if EFI_UNIT_TEST
|
||||||
return getRealMafAirmass(maf, rpm PASS_ENGINE_PARAMETER_SUFFIX);
|
case LM_MOCK: return engine->mockAirmassModel;
|
||||||
} default:
|
#endif
|
||||||
firmwareError(CUSTOM_ERR_ASSERT, "Fuel mode %d is not airmass mode", CONFIG(fuelAlgorithm));
|
default: return nullptr;
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,15 +199,19 @@ floatms_t getBaseFuel(int rpm DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
||||||
|
|
||||||
floatms_t baseFuel;
|
floatms_t baseFuel;
|
||||||
|
|
||||||
if ((CONFIG(fuelAlgorithm) == LM_SPEED_DENSITY) || (engineConfiguration->fuelAlgorithm == LM_REAL_MAF)) {
|
if ((CONFIG(fuelAlgorithm) == LM_SPEED_DENSITY) ||
|
||||||
|
(engineConfiguration->fuelAlgorithm == LM_REAL_MAF) ||
|
||||||
|
(engineConfiguration->fuelAlgorithm == LM_ALPHA_N_2) ||
|
||||||
|
(engineConfiguration->fuelAlgorithm == LM_MOCK)) {
|
||||||
// airmass modes - get airmass first, then convert to fuel
|
// airmass modes - get airmass first, then convert to fuel
|
||||||
auto airmass = getAirmass(rpm PASS_ENGINE_PARAMETER_SUFFIX);
|
auto model = getAirmassModel(PASS_ENGINE_PARAMETER_SIGNATURE);
|
||||||
|
efiAssert(CUSTOM_ERR_ASSERT, model != nullptr, "Invalid airmass mode", 0.0f);
|
||||||
|
|
||||||
|
auto airmass = model->getAirmass(rpm);
|
||||||
|
|
||||||
// The airmass mode will tell us how to look up AFR - use the provided Y axis value
|
// The airmass mode will tell us how to look up AFR - use the provided Y axis value
|
||||||
float targetAfr = afrMap.getValue(rpm, airmass.EngineLoadPercent);
|
float targetAfr = afrMap.getValue(rpm, airmass.EngineLoadPercent);
|
||||||
|
|
||||||
// TODO: surface airmass.EngineLoadPercent to tunerstudio for proper display
|
|
||||||
|
|
||||||
// Plop some state for others to read
|
// Plop some state for others to read
|
||||||
ENGINE(engineState.targetAFR) = targetAfr;
|
ENGINE(engineState.targetAFR) = targetAfr;
|
||||||
ENGINE(engineState.sd.airMassInOneCylinder) = airmass.CylinderAirmass;
|
ENGINE(engineState.sd.airMassInOneCylinder) = airmass.CylinderAirmass;
|
||||||
|
@ -384,6 +359,9 @@ floatms_t getInjectorLag(float vBatt DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
||||||
* is to prepare the fuel map data structure for 3d interpolation
|
* is to prepare the fuel map data structure for 3d interpolation
|
||||||
*/
|
*/
|
||||||
void initFuelMap(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
void initFuelMap(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||||
|
INJECT_ENGINE_REFERENCE(&sdAirmass);
|
||||||
|
INJECT_ENGINE_REFERENCE(&mafAirmass);
|
||||||
|
|
||||||
fuelMap.init(config->fuelTable, config->fuelLoadBins, config->fuelRpmBins);
|
fuelMap.init(config->fuelTable, config->fuelLoadBins, config->fuelRpmBins);
|
||||||
#if (IGN_LOAD_COUNT == FUEL_LOAD_COUNT) && (IGN_RPM_COUNT == FUEL_RPM_COUNT)
|
#if (IGN_LOAD_COUNT == FUEL_LOAD_COUNT) && (IGN_RPM_COUNT == FUEL_RPM_COUNT)
|
||||||
fuelPhaseMap.init(config->injectionPhase, config->injPhaseLoadBins, config->injPhaseRpmBins);
|
fuelPhaseMap.init(config->injectionPhase, config->injPhaseLoadBins, config->injPhaseRpmBins);
|
||||||
|
|
|
@ -22,8 +22,6 @@ floatms_t getBaseFuel(int rpm DECLARE_ENGINE_PARAMETER_SUFFIX);
|
||||||
*/
|
*/
|
||||||
floatms_t getRunningFuel(floatms_t baseFuel DECLARE_ENGINE_PARAMETER_SUFFIX);
|
floatms_t getRunningFuel(floatms_t baseFuel DECLARE_ENGINE_PARAMETER_SUFFIX);
|
||||||
|
|
||||||
AirmassResult getRealMafAirmass(float airMass, int rpm DECLARE_ENGINE_PARAMETER_SUFFIX);
|
|
||||||
|
|
||||||
floatms_t getBaseTableFuel(int rpm, float engineLoad);
|
floatms_t getBaseTableFuel(int rpm, float engineLoad);
|
||||||
float getBaroCorrection(DECLARE_ENGINE_PARAMETER_SIGNATURE);
|
float getBaroCorrection(DECLARE_ENGINE_PARAMETER_SIGNATURE);
|
||||||
int getNumberOfInjections(injection_mode_e mode DECLARE_ENGINE_PARAMETER_SUFFIX);
|
int getNumberOfInjections(injection_mode_e mode DECLARE_ENGINE_PARAMETER_SUFFIX);
|
||||||
|
|
|
@ -439,6 +439,12 @@ typedef enum {
|
||||||
*/
|
*/
|
||||||
LM_REAL_MAF = 4,
|
LM_REAL_MAF = 4,
|
||||||
|
|
||||||
|
// todo: rename after LM_ALPHA_N is removed
|
||||||
|
LM_ALPHA_N_2 = 5,
|
||||||
|
|
||||||
|
// This mode is for unit testing only, so that tests don't have to rely on a particular real airmass mode
|
||||||
|
LM_MOCK = 100,
|
||||||
|
|
||||||
Force_4_bytes_size_engine_load_mode = ENUM_32_BITS,
|
Force_4_bytes_size_engine_load_mode = ENUM_32_BITS,
|
||||||
} engine_load_mode_e;
|
} engine_load_mode_e;
|
||||||
|
|
||||||
|
@ -948,6 +954,8 @@ typedef enum __attribute__ ((__packed__)) {
|
||||||
GPPWM_Map = 1,
|
GPPWM_Map = 1,
|
||||||
GPPWM_Clt = 2,
|
GPPWM_Clt = 2,
|
||||||
GPPWM_Iat = 3,
|
GPPWM_Iat = 3,
|
||||||
|
GPPWM_FuelLoad = 4,
|
||||||
|
GPPWM_IgnLoad = 5,
|
||||||
} gppwm_channel_e;
|
} gppwm_channel_e;
|
||||||
|
|
||||||
typedef enum __attribute__ ((__packed__)) {
|
typedef enum __attribute__ ((__packed__)) {
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include "electronic_throttle.h"
|
#include "electronic_throttle.h"
|
||||||
#include "cj125.h"
|
#include "cj125.h"
|
||||||
#include "malfunction_central.h"
|
#include "malfunction_central.h"
|
||||||
|
#include "tunerstudio_outputs.h"
|
||||||
|
|
||||||
#if EFI_PROD_CODE
|
#if EFI_PROD_CODE
|
||||||
#include "rusefi.h"
|
#include "rusefi.h"
|
||||||
|
@ -271,6 +272,9 @@ static void handleCommandX14(uint16_t index) {
|
||||||
return;
|
return;
|
||||||
case 0x10:
|
case 0x10:
|
||||||
engine->etbAutoTune = false;
|
engine->etbAutoTune = false;
|
||||||
|
#if EFI_TUNER_STUDIO
|
||||||
|
tsOutputChannels.calibrationMode = TsCalMode::None;
|
||||||
|
#endif // EFI_TUNER_STUDIO
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
case 0xF:
|
case 0xF:
|
||||||
|
|
|
@ -123,7 +123,7 @@ static void handleGetDataRequest(const CANRxFrame& rx) {
|
||||||
obdSendValue(1, pid, 2, (2<<8)|(0)); // 2 = "Closed loop, using oxygen sensor feedback to determine fuel mix"
|
obdSendValue(1, pid, 2, (2<<8)|(0)); // 2 = "Closed loop, using oxygen sensor feedback to determine fuel mix"
|
||||||
break;
|
break;
|
||||||
case PID_ENGINE_LOAD:
|
case PID_ENGINE_LOAD:
|
||||||
obdSendValue(1, pid, 1, getEngineLoadT(PASS_ENGINE_PARAMETER_SIGNATURE) * 2.55f);
|
obdSendValue(1, pid, 1, getFuelingLoad(PASS_ENGINE_PARAMETER_SIGNATURE) * 2.55f);
|
||||||
break;
|
break;
|
||||||
case PID_COOLANT_TEMP:
|
case PID_COOLANT_TEMP:
|
||||||
obdSendValue(1, pid, 1, Sensor::get(SensorType::Clt).value_or(0) + 40.0f);
|
obdSendValue(1, pid, 1, Sensor::get(SensorType::Clt).value_or(0) + 40.0f);
|
||||||
|
|
|
@ -34,6 +34,7 @@ CONTROLLERS_SRC_CPP = \
|
||||||
$(CONTROLLERS_DIR)/engine_cycle/spark_logic.cpp \
|
$(CONTROLLERS_DIR)/engine_cycle/spark_logic.cpp \
|
||||||
$(CONTROLLERS_DIR)/engine_cycle/main_trigger_callback.cpp \
|
$(CONTROLLERS_DIR)/engine_cycle/main_trigger_callback.cpp \
|
||||||
$(CONTROLLERS_DIR)/engine_cycle/aux_valves.cpp \
|
$(CONTROLLERS_DIR)/engine_cycle/aux_valves.cpp \
|
||||||
|
$(CONTROLLERS_DIR)/engine_cycle/fuel_schedule.cpp \
|
||||||
$(CONTROLLERS_DIR)/flash_main.cpp \
|
$(CONTROLLERS_DIR)/flash_main.cpp \
|
||||||
$(CONTROLLERS_DIR)/bench_test.cpp \
|
$(CONTROLLERS_DIR)/bench_test.cpp \
|
||||||
$(CONTROLLERS_DIR)/can/obd2.cpp \
|
$(CONTROLLERS_DIR)/can/obd2.cpp \
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#define VCS_DATE 20200723
|
#define VCS_DATE 20200729
|
||||||
|
|
|
@ -324,6 +324,8 @@ static void printAnalogInfo(void) {
|
||||||
printAnalogChannelInfo("pPS", engineConfiguration->throttlePedalPositionAdcChannel);
|
printAnalogChannelInfo("pPS", engineConfiguration->throttlePedalPositionAdcChannel);
|
||||||
printAnalogChannelInfo("CLT", engineConfiguration->clt.adcChannel);
|
printAnalogChannelInfo("CLT", engineConfiguration->clt.adcChannel);
|
||||||
printAnalogChannelInfo("IAT", engineConfiguration->iat.adcChannel);
|
printAnalogChannelInfo("IAT", engineConfiguration->iat.adcChannel);
|
||||||
|
printAnalogChannelInfo("AuxT1", engineConfiguration->auxTempSensor1.adcChannel);
|
||||||
|
printAnalogChannelInfo("AuxT2", engineConfiguration->auxTempSensor2.adcChannel);
|
||||||
printAnalogChannelInfo("MAF", engineConfiguration->mafAdcChannel);
|
printAnalogChannelInfo("MAF", engineConfiguration->mafAdcChannel);
|
||||||
for (int i = 0; i < FSIO_ANALOG_INPUT_COUNT ; i++) {
|
for (int i = 0; i < FSIO_ANALOG_INPUT_COUNT ; i++) {
|
||||||
adc_channel_e ch = engineConfiguration->fsioAdc[i];
|
adc_channel_e ch = engineConfiguration->fsioAdc[i];
|
||||||
|
|
|
@ -0,0 +1,163 @@
|
||||||
|
/**
|
||||||
|
* @file fuel_schedule.cpp
|
||||||
|
*
|
||||||
|
* Handles injection scheduling
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "global.h"
|
||||||
|
#include "engine.h"
|
||||||
|
#include "engine_math.h"
|
||||||
|
#include "event_registry.h"
|
||||||
|
|
||||||
|
EXTERN_ENGINE;
|
||||||
|
|
||||||
|
#if EFI_ENGINE_CONTROL
|
||||||
|
|
||||||
|
FuelSchedule::FuelSchedule() {
|
||||||
|
clear();
|
||||||
|
for (int cylinderIndex = 0; cylinderIndex < MAX_INJECTION_OUTPUT_COUNT; cylinderIndex++) {
|
||||||
|
InjectionEvent *ev = &elements[cylinderIndex];
|
||||||
|
ev->ownIndex = cylinderIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FuelSchedule::clear() {
|
||||||
|
isReady = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FuelSchedule::resetOverlapping() {
|
||||||
|
for (size_t i = 0; i < efi::size(enginePins.injectors); i++) {
|
||||||
|
enginePins.injectors[i].reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns false in case of error, true if success
|
||||||
|
*/
|
||||||
|
bool FuelSchedule::addFuelEventsForCylinder(int i DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
||||||
|
efiAssert(CUSTOM_ERR_ASSERT, engine!=NULL, "engine is NULL", false);
|
||||||
|
|
||||||
|
floatus_t oneDegreeUs = ENGINE(rpmCalculator.oneDegreeUs); // local copy
|
||||||
|
if (cisnan(oneDegreeUs)) {
|
||||||
|
// in order to have fuel schedule we need to have current RPM
|
||||||
|
// wonder if this line slows engine startup?
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* injection phase is scheduled by injection end, so we need to step the angle back
|
||||||
|
* for the duration of the injection
|
||||||
|
*
|
||||||
|
* todo: since this method is not invoked within trigger event handler and
|
||||||
|
* engineState.injectionOffset is calculated from the same utility timer should we more that logic here?
|
||||||
|
*/
|
||||||
|
floatms_t fuelMs = ENGINE(injectionDuration);
|
||||||
|
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(fuelMs), "NaN fuelMs", false);
|
||||||
|
angle_t injectionDuration = MS2US(fuelMs) / oneDegreeUs;
|
||||||
|
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(injectionDuration), "NaN injectionDuration", false);
|
||||||
|
assertAngleRange(injectionDuration, "injectionDuration_r", CUSTOM_INJ_DURATION);
|
||||||
|
floatus_t injectionOffset = ENGINE(engineState.injectionOffset);
|
||||||
|
if (cisnan(injectionOffset)) {
|
||||||
|
// injection offset map not ready - we are not ready to schedule fuel events
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
angle_t baseAngle = injectionOffset - injectionDuration;
|
||||||
|
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(baseAngle), "NaN baseAngle", false);
|
||||||
|
assertAngleRange(baseAngle, "baseAngle_r", CUSTOM_ERR_6554);
|
||||||
|
|
||||||
|
injection_mode_e mode = engine->getCurrentInjectionMode(PASS_ENGINE_PARAMETER_SIGNATURE);
|
||||||
|
|
||||||
|
int injectorIndex;
|
||||||
|
if (mode == IM_SIMULTANEOUS || mode == IM_SINGLE_POINT) {
|
||||||
|
// These modes only have one injector
|
||||||
|
injectorIndex = 0;
|
||||||
|
} else if (mode == IM_SEQUENTIAL || (mode == IM_BATCH && CONFIG(twoWireBatchInjection))) {
|
||||||
|
// Map order index -> cylinder index (firing order)
|
||||||
|
injectorIndex = getCylinderId(i PASS_ENGINE_PARAMETER_SUFFIX) - 1;
|
||||||
|
} else if (mode == IM_BATCH) {
|
||||||
|
// Loop over the first half of the firing order twice
|
||||||
|
injectorIndex = i % (engineConfiguration->specs.cylindersCount / 2);
|
||||||
|
} else {
|
||||||
|
firmwareError(CUSTOM_OBD_UNEXPECTED_INJECTION_MODE, "Unexpected injection mode %d", mode);
|
||||||
|
injectorIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
assertAngleRange(baseAngle, "addFbaseAngle", CUSTOM_ADD_BASE);
|
||||||
|
|
||||||
|
int cylindersCount = CONFIG(specs.cylindersCount);
|
||||||
|
if (cylindersCount < 1) {
|
||||||
|
// May 2020 this somehow still happens with functional tests, maybe race condition?
|
||||||
|
warning(CUSTOM_OBD_ZERO_CYLINDER_COUNT, "Invalid cylinder count: %d", cylindersCount);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
float angle = baseAngle
|
||||||
|
+ i * ENGINE(engineCycle) / cylindersCount;
|
||||||
|
|
||||||
|
InjectorOutputPin *secondOutput;
|
||||||
|
if (mode == IM_BATCH && CONFIG(twoWireBatchInjection)) {
|
||||||
|
/**
|
||||||
|
* also fire the 2nd half of the injectors so that we can implement a batch mode on individual wires
|
||||||
|
*/
|
||||||
|
// Compute the position of this cylinder's twin in the firing order
|
||||||
|
// Each injector gets fired as a primary (the same as sequential), but also
|
||||||
|
// fires the injector 360 degrees later in the firing order.
|
||||||
|
int secondOrder = (i + (CONFIG(specs.cylindersCount) / 2)) % CONFIG(specs.cylindersCount);
|
||||||
|
int secondIndex = getCylinderId(secondOrder PASS_ENGINE_PARAMETER_SUFFIX) - 1;
|
||||||
|
secondOutput = &enginePins.injectors[secondIndex];
|
||||||
|
} else {
|
||||||
|
secondOutput = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
InjectorOutputPin *output = &enginePins.injectors[injectorIndex];
|
||||||
|
bool isSimultanious = mode == IM_SIMULTANEOUS;
|
||||||
|
|
||||||
|
if (!isSimultanious && !output->isInitialized()) {
|
||||||
|
// todo: extract method for this index math
|
||||||
|
warning(CUSTOM_OBD_INJECTION_NO_PIN_ASSIGNED, "no_pin_inj #%s", output->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
InjectionEvent *ev = &elements[i];
|
||||||
|
ev->ownIndex = i;
|
||||||
|
INJECT_ENGINE_REFERENCE(ev);
|
||||||
|
fixAngle(angle, "addFuel#1", CUSTOM_ERR_6554);
|
||||||
|
|
||||||
|
ev->outputs[0] = output;
|
||||||
|
ev->outputs[1] = secondOutput;
|
||||||
|
|
||||||
|
ev->isSimultanious = isSimultanious;
|
||||||
|
|
||||||
|
if (TRIGGER_WAVEFORM(getSize()) < 1) {
|
||||||
|
warning(CUSTOM_ERR_NOT_INITIALIZED_TRIGGER, "uninitialized TriggerWaveform");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(angle), "findAngle#3", false);
|
||||||
|
assertAngleRange(angle, "findAngle#a33", CUSTOM_ERR_6544);
|
||||||
|
ev->injectionStart.setAngle(angle PASS_ENGINE_PARAMETER_SUFFIX);
|
||||||
|
#if EFI_UNIT_TEST
|
||||||
|
printf("registerInjectionEvent angle=%.2f trgIndex=%d inj %d\r\n", angle, ev->injectionStart.triggerEventIndex, injectorIndex);
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FuelSchedule::addFuelEvents(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||||
|
clear();
|
||||||
|
|
||||||
|
for (int cylinderIndex = 0; cylinderIndex < CONFIG(specs.cylindersCount); cylinderIndex++) {
|
||||||
|
InjectionEvent *ev = &elements[cylinderIndex];
|
||||||
|
ev->ownIndex = cylinderIndex; // todo: is this assignment needed here? we now initialize in constructor
|
||||||
|
bool result = addFuelEventsForCylinder(cylinderIndex PASS_ENGINE_PARAMETER_SUFFIX);
|
||||||
|
if (!result)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
isReady = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FuelSchedule::onTriggerTooth(size_t toothIndex, int rpm, efitick_t nowNt DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
||||||
|
for (int i = 0; i < CONFIG(specs.cylindersCount); i++) {
|
||||||
|
elements[i].onTriggerTooth(toothIndex, rpm, nowNt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -187,9 +187,13 @@ void turnInjectionPinLow(InjectionEvent *event) {
|
||||||
ENGINE(injectionEvents.addFuelEventsForCylinder(event->ownIndex PASS_ENGINE_PARAMETER_SUFFIX));
|
ENGINE(injectionEvents.addFuelEventsForCylinder(event->ownIndex PASS_ENGINE_PARAMETER_SUFFIX));
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: rename to 'scheduleInjectorOpenAndClose'?
|
void InjectionEvent::onTriggerTooth(size_t trgEventIndex, int rpm, efitick_t nowNt) {
|
||||||
void handleFuelInjectionEvent(int injEventIndex, InjectionEvent *event,
|
uint32_t eventIndex = injectionStart.triggerEventIndex;
|
||||||
int rpm, efitick_t nowNt DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
// right after trigger change we are still using old & invalid fuel schedule. good news is we do not change trigger on the fly in real life
|
||||||
|
// efiAssertVoid(CUSTOM_ERR_ASSERT_VOID, eventIndex < ENGINE(triggerShape.getLength()), "handleFuel/event sch index");
|
||||||
|
if (eventIndex != trgEventIndex) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* todo: this is a bit tricky with batched injection. is it? Does the same
|
* todo: this is a bit tricky with batched injection. is it? Does the same
|
||||||
|
@ -197,11 +201,11 @@ void handleFuelInjectionEvent(int injEventIndex, InjectionEvent *event,
|
||||||
* x2 or /2?
|
* x2 or /2?
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const floatms_t injectionDuration = event->wallFuel.adjust(ENGINE(injectionDuration) PASS_ENGINE_PARAMETER_SUFFIX);
|
const floatms_t injectionDuration = wallFuel.adjust(ENGINE(injectionDuration) PASS_ENGINE_PARAMETER_SUFFIX);
|
||||||
#if EFI_PRINTF_FUEL_DETAILS
|
#if EFI_PRINTF_FUEL_DETAILS
|
||||||
if (printFuelDebug) {
|
if (printFuelDebug) {
|
||||||
printf("fuel index=%d injectionDuration=%.2fms adjusted=%.2fms\n",
|
printf("fuel index=%d injectionDuration=%.2fms adjusted=%.2fms\n",
|
||||||
injEventIndex,
|
eventIndex,
|
||||||
ENGINE(injectionDuration),
|
ENGINE(injectionDuration),
|
||||||
injectionDuration);
|
injectionDuration);
|
||||||
}
|
}
|
||||||
|
@ -245,7 +249,7 @@ void handleFuelInjectionEvent(int injEventIndex, InjectionEvent *event,
|
||||||
|
|
||||||
// we are ignoring low RPM in order not to handle "engine was stopped to engine now running" transition
|
// we are ignoring low RPM in order not to handle "engine was stopped to engine now running" transition
|
||||||
if (rpm > 2 * engineConfiguration->cranking.rpm) {
|
if (rpm > 2 * engineConfiguration->cranking.rpm) {
|
||||||
const char *outputName = event->outputs[0]->name;
|
const char *outputName = outputs[0]->name;
|
||||||
if (prevOutputName == outputName
|
if (prevOutputName == outputName
|
||||||
&& engineConfiguration->injectionMode != IM_SIMULTANEOUS
|
&& engineConfiguration->injectionMode != IM_SIMULTANEOUS
|
||||||
&& engineConfiguration->injectionMode != IM_SINGLE_POINT) {
|
&& engineConfiguration->injectionMode != IM_SINGLE_POINT) {
|
||||||
|
@ -256,48 +260,48 @@ void handleFuelInjectionEvent(int injEventIndex, InjectionEvent *event,
|
||||||
|
|
||||||
#if EFI_PRINTF_FUEL_DETAILS
|
#if EFI_PRINTF_FUEL_DETAILS
|
||||||
if (printFuelDebug) {
|
if (printFuelDebug) {
|
||||||
InjectorOutputPin *output = event->outputs[0];
|
InjectorOutputPin *output = outputs[0];
|
||||||
printf("handleFuelInjectionEvent fuelout %s injection_duration %dus engineCycleDuration=%.1fms\t\n", output->name, (int)durationUs,
|
printf("handleFuelInjectionEvent fuelout %s injection_duration %dus engineCycleDuration=%.1fms\t\n", output->name, (int)durationUs,
|
||||||
(int)MS2US(getCrankshaftRevolutionTimeMs(GET_RPM_VALUE)) / 1000.0);
|
(int)MS2US(getCrankshaftRevolutionTimeMs(GET_RPM_VALUE)) / 1000.0);
|
||||||
}
|
}
|
||||||
#endif /*EFI_PRINTF_FUEL_DETAILS */
|
#endif /*EFI_PRINTF_FUEL_DETAILS */
|
||||||
|
|
||||||
if (event->isScheduled) {
|
if (isScheduled) {
|
||||||
#if EFI_PRINTF_FUEL_DETAILS
|
#if EFI_PRINTF_FUEL_DETAILS
|
||||||
if (printFuelDebug) {
|
if (printFuelDebug) {
|
||||||
InjectorOutputPin *output = event->outputs[0];
|
InjectorOutputPin *output = outputs[0];
|
||||||
printf("handleFuelInjectionEvent still used %s now=%.1fms\r\n", output->name, (int)getTimeNowUs() / 1000.0);
|
printf("handleFuelInjectionEvent still used %s now=%.1fms\r\n", output->name, (int)getTimeNowUs() / 1000.0);
|
||||||
}
|
}
|
||||||
#endif /*EFI_PRINTF_FUEL_DETAILS */
|
#endif /*EFI_PRINTF_FUEL_DETAILS */
|
||||||
return; // this InjectionEvent is still needed for an extremely long injection scheduled previously
|
return; // this InjectionEvent is still needed for an extremely long injection scheduled previously
|
||||||
}
|
}
|
||||||
|
|
||||||
event->isScheduled = true;
|
isScheduled = true;
|
||||||
|
|
||||||
action_s startAction, endAction;
|
action_s startAction, endAction;
|
||||||
// We use different callbacks based on whether we're running sequential mode or not - everything else is the same
|
// We use different callbacks based on whether we're running sequential mode or not - everything else is the same
|
||||||
if (event->isSimultanious) {
|
if (isSimultanious) {
|
||||||
startAction = { &startSimultaniousInjection, engine };
|
startAction = { &startSimultaniousInjection, engine };
|
||||||
endAction = { &endSimultaniousInjection, event };
|
endAction = { &endSimultaniousInjection, this };
|
||||||
} else {
|
} else {
|
||||||
// sequential or batch
|
// sequential or batch
|
||||||
startAction = { &turnInjectionPinHigh, event };
|
startAction = { &turnInjectionPinHigh, this };
|
||||||
endAction = { &turnInjectionPinLow, event };
|
endAction = { &turnInjectionPinLow, this };
|
||||||
}
|
}
|
||||||
|
|
||||||
efitick_t startTime = scheduleByAngle(&event->signalTimerUp, nowNt, event->injectionStart.angleOffsetFromTriggerEvent, startAction PASS_ENGINE_PARAMETER_SUFFIX);
|
efitick_t startTime = scheduleByAngle(&signalTimerUp, nowNt, injectionStart.angleOffsetFromTriggerEvent, startAction PASS_ENGINE_PARAMETER_SUFFIX);
|
||||||
efitick_t turnOffTime = startTime + US2NT((int)durationUs);
|
efitick_t turnOffTime = startTime + US2NT((int)durationUs);
|
||||||
engine->executor.scheduleByTimestampNt(&event->endOfInjectionEvent, turnOffTime, endAction);
|
engine->executor.scheduleByTimestampNt(&endOfInjectionEvent, turnOffTime, endAction);
|
||||||
|
|
||||||
#if EFI_UNIT_TEST
|
#if EFI_UNIT_TEST
|
||||||
printf("scheduling injection angle=%.2f/delay=%.2f injectionDuration=%.2f\r\n", event->injectionStart.angleOffsetFromTriggerEvent, NT2US(startTime - nowNt), injectionDuration);
|
printf("scheduling injection angle=%.2f/delay=%.2f injectionDuration=%.2f\r\n", injectionStart.angleOffsetFromTriggerEvent, NT2US(startTime - nowNt), injectionDuration);
|
||||||
#endif
|
#endif
|
||||||
#if EFI_DEFAILED_LOGGING
|
#if EFI_DEFAILED_LOGGING
|
||||||
scheduleMsg(logger, "handleFuel pin=%s eventIndex %d duration=%.2fms %d", event->outputs[0]->name,
|
scheduleMsg(logger, "handleFuel pin=%s eventIndex %d duration=%.2fms %d", outputs[0]->name,
|
||||||
injEventIndex,
|
injEventIndex,
|
||||||
injectionDuration,
|
injectionDuration,
|
||||||
getRevolutionCounter());
|
getRevolutionCounter());
|
||||||
scheduleMsg(logger, "handleFuel pin=%s delay=%.2f %d", event->outputs[0]->name, NT2US(startTime - nowNt),
|
scheduleMsg(logger, "handleFuel pin=%s delay=%.2f %d", outputs[0]->name, NT2US(startTime - nowNt),
|
||||||
getRevolutionCounter());
|
getRevolutionCounter());
|
||||||
#endif /* EFI_DEFAILED_LOGGING */
|
#endif /* EFI_DEFAILED_LOGGING */
|
||||||
}
|
}
|
||||||
|
@ -322,7 +326,7 @@ static ALWAYS_INLINE void handleFuel(const bool limitedFuel, uint32_t trgEventIn
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ignition events are defined by addFuelEvents() according to selected
|
* Injection events are defined by addFuelEvents() according to selected
|
||||||
* fueling strategy
|
* fueling strategy
|
||||||
*/
|
*/
|
||||||
FuelSchedule *fs = &ENGINE(injectionEvents);
|
FuelSchedule *fs = &ENGINE(injectionEvents);
|
||||||
|
@ -342,16 +346,7 @@ static ALWAYS_INLINE void handleFuel(const bool limitedFuel, uint32_t trgEventIn
|
||||||
ENGINE(engineLoadAccelEnrichment.onEngineCycle(PASS_ENGINE_PARAMETER_SIGNATURE));
|
ENGINE(engineLoadAccelEnrichment.onEngineCycle(PASS_ENGINE_PARAMETER_SIGNATURE));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int injEventIndex = 0; injEventIndex < CONFIG(specs.cylindersCount); injEventIndex++) {
|
fs->onTriggerTooth(trgEventIndex, rpm, nowNt PASS_ENGINE_PARAMETER_SUFFIX);
|
||||||
InjectionEvent *event = &fs->elements[injEventIndex];
|
|
||||||
uint32_t eventIndex = event->injectionStart.triggerEventIndex;
|
|
||||||
// right after trigger change we are still using old & invalid fuel schedule. good news is we do not change trigger on the fly in real life
|
|
||||||
// efiAssertVoid(CUSTOM_ERR_ASSERT_VOID, eventIndex < ENGINE(triggerShape.getLength()), "handleFuel/event sch index");
|
|
||||||
if (eventIndex != trgEventIndex) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
handleFuelInjectionEvent(injEventIndex, event, rpm, nowNt PASS_ENGINE_PARAMETER_SUFFIX);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if EFI_PROD_CODE
|
#if EFI_PROD_CODE
|
||||||
|
@ -473,6 +468,8 @@ static bool isPrimeInjectionPulseSkipped(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||||
* See testStartOfCrankingPrimingPulse()
|
* See testStartOfCrankingPrimingPulse()
|
||||||
*/
|
*/
|
||||||
void startPrimeInjectionPulse(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
void startPrimeInjectionPulse(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||||
|
INJECT_ENGINE_REFERENCE(&primeInjEvent);
|
||||||
|
|
||||||
// First, we need a protection against 'fake' ignition switch on and off (i.e. no engine started), to avoid repeated prime pulses.
|
// First, we need a protection against 'fake' ignition switch on and off (i.e. no engine started), to avoid repeated prime pulses.
|
||||||
// So we check and update the ignition switch counter in non-volatile backup-RAM
|
// So we check and update the ignition switch counter in non-volatile backup-RAM
|
||||||
#if EFI_PROD_CODE
|
#if EFI_PROD_CODE
|
||||||
|
@ -490,10 +487,6 @@ void startPrimeInjectionPulse(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||||
ignSwitchCounter = -1;
|
ignSwitchCounter = -1;
|
||||||
// start prime injection if this is a 'fresh start'
|
// start prime injection if this is a 'fresh start'
|
||||||
if (ignSwitchCounter == 0) {
|
if (ignSwitchCounter == 0) {
|
||||||
// fill-in the prime event struct
|
|
||||||
#if EFI_UNIT_TEST
|
|
||||||
primeInjEvent.engine = engine;
|
|
||||||
#endif /* EFI_UNIT_TEST */
|
|
||||||
primeInjEvent.ownIndex = 0;
|
primeInjEvent.ownIndex = 0;
|
||||||
primeInjEvent.isSimultanious = true;
|
primeInjEvent.isSimultanious = true;
|
||||||
|
|
||||||
|
@ -535,7 +528,7 @@ void updatePrimeInjectionPulseState(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||||
static void showMainInfo(Engine *engine) {
|
static void showMainInfo(Engine *engine) {
|
||||||
#if EFI_PROD_CODE
|
#if EFI_PROD_CODE
|
||||||
int rpm = GET_RPM();
|
int rpm = GET_RPM();
|
||||||
float el = getEngineLoadT(PASS_ENGINE_PARAMETER_SIGNATURE);
|
float el = getFuelingLoad(PASS_ENGINE_PARAMETER_SIGNATURE);
|
||||||
scheduleMsg(logger, "rpm %d engine_load %.2f", rpm, el);
|
scheduleMsg(logger, "rpm %d engine_load %.2f", rpm, el);
|
||||||
scheduleMsg(logger, "fuel %.2fms timing %.2f", getInjectionDuration(rpm PASS_ENGINE_PARAMETER_SUFFIX), engine->engineState.timingAdvance);
|
scheduleMsg(logger, "fuel %.2fms timing %.2f", getInjectionDuration(rpm PASS_ENGINE_PARAMETER_SUFFIX), engine->engineState.timingAdvance);
|
||||||
#endif /* EFI_PROD_CODE */
|
#endif /* EFI_PROD_CODE */
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// this file was generated automatically by rusEfi tool ConfigDefinition.jar based on gen_config.sh integration/rusefi_config.txt Wed Jul 22 19:40:59 UTC 2020
|
// this file was generated automatically by rusEfi tool ConfigDefinition.jar based on gen_config.sh integration/rusefi_config.txt Tue Jul 28 13:12:08 UTC 2020
|
||||||
|
|
||||||
// by class com.rusefi.output.FileFsioSettingsConsumer
|
// by class com.rusefi.output.FileFsioSettingsConsumer
|
||||||
FSIO_SETTING_FANONTEMPERATURE = 1000,
|
FSIO_SETTING_FANONTEMPERATURE = 1000,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// this file was generated automatically by rusEfi tool ConfigDefinition.jar based on gen_config.sh integration/rusefi_config.txt Wed Jul 22 19:40:59 UTC 2020
|
// this file was generated automatically by rusEfi tool ConfigDefinition.jar based on gen_config.sh integration/rusefi_config.txt Tue Jul 28 13:12:08 UTC 2020
|
||||||
|
|
||||||
// by class com.rusefi.output.FileFsioSettingsConsumer
|
// by class com.rusefi.output.FileFsioSettingsConsumer
|
||||||
case FSIO_SETTING_FANONTEMPERATURE:
|
case FSIO_SETTING_FANONTEMPERATURE:
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// this file was generated automatically by rusEfi tool ConfigDefinition.jar based on gen_config.sh integration/rusefi_config.txt Wed Jul 22 19:40:59 UTC 2020
|
// this file was generated automatically by rusEfi tool ConfigDefinition.jar based on gen_config.sh integration/rusefi_config.txt Tue Jul 28 13:12:08 UTC 2020
|
||||||
|
|
||||||
// by class com.rusefi.output.FileFsioSettingsConsumer
|
// by class com.rusefi.output.FileFsioSettingsConsumer
|
||||||
static LENameOrdinalPair lefanOnTemperature(FSIO_SETTING_FANONTEMPERATURE, "cfg_fanOnTemperature");
|
static LENameOrdinalPair lefanOnTemperature(FSIO_SETTING_FANONTEMPERATURE, "cfg_fanOnTemperature");
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// this file was generated automatically by rusEfi tool ConfigDefinition.jar based on gen_config.sh integration/rusefi_config.txt Wed Jul 22 19:40:59 UTC 2020
|
// this file was generated automatically by rusEfi tool ConfigDefinition.jar based on gen_config.sh integration/rusefi_config.txt Tue Jul 28 13:12:08 UTC 2020
|
||||||
|
|
||||||
// by class com.rusefi.output.FileFsioSettingsConsumer
|
// by class com.rusefi.output.FileFsioSettingsConsumer
|
||||||
case FSIO_SETTING_FANONTEMPERATURE:
|
case FSIO_SETTING_FANONTEMPERATURE:
|
||||||
|
|
|
@ -3,6 +3,6 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#define SIGNATURE_BOARD all
|
#define SIGNATURE_BOARD all
|
||||||
#define SIGNATURE_DATE 2020.07.22
|
#define SIGNATURE_DATE 2020.07.28
|
||||||
#define SIGNATURE_HASH 692540479
|
#define SIGNATURE_HASH 1542883429
|
||||||
#define TS_SIGNATURE "rusEFI 2020.07.22.all.692540479"
|
#define TS_SIGNATURE "rusEFI 2020.07.28.all.1542883429"
|
||||||
|
|
|
@ -3,6 +3,6 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#define SIGNATURE_BOARD frankenso_na6
|
#define SIGNATURE_BOARD frankenso_na6
|
||||||
#define SIGNATURE_DATE 2020.07.22
|
#define SIGNATURE_DATE 2020.07.28
|
||||||
#define SIGNATURE_HASH 4156569820
|
#define SIGNATURE_HASH 2238833798
|
||||||
#define TS_SIGNATURE "rusEFI 2020.07.22.frankenso_na6.4156569820"
|
#define TS_SIGNATURE "rusEFI 2020.07.28.frankenso_na6.2238833798"
|
||||||
|
|
|
@ -3,6 +3,6 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#define SIGNATURE_BOARD kin
|
#define SIGNATURE_BOARD kin
|
||||||
#define SIGNATURE_DATE 2020.07.22
|
#define SIGNATURE_DATE 2020.07.28
|
||||||
#define SIGNATURE_HASH 3833170085
|
#define SIGNATURE_HASH 2529711359
|
||||||
#define TS_SIGNATURE "rusEFI 2020.07.22.kin.3833170085"
|
#define TS_SIGNATURE "rusEFI 2020.07.28.kin.2529711359"
|
||||||
|
|
|
@ -3,6 +3,6 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#define SIGNATURE_BOARD mre_f4
|
#define SIGNATURE_BOARD mre_f4
|
||||||
#define SIGNATURE_DATE 2020.07.22
|
#define SIGNATURE_DATE 2020.07.28
|
||||||
#define SIGNATURE_HASH 1622770353
|
#define SIGNATURE_HASH 302538475
|
||||||
#define TS_SIGNATURE "rusEFI 2020.07.22.mre_f4.1622770353"
|
#define TS_SIGNATURE "rusEFI 2020.07.28.mre_f4.302538475"
|
||||||
|
|
|
@ -3,6 +3,6 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#define SIGNATURE_BOARD mre_f7
|
#define SIGNATURE_BOARD mre_f7
|
||||||
#define SIGNATURE_DATE 2020.07.22
|
#define SIGNATURE_DATE 2020.07.28
|
||||||
#define SIGNATURE_HASH 1622770353
|
#define SIGNATURE_HASH 302538475
|
||||||
#define TS_SIGNATURE "rusEFI 2020.07.22.mre_f7.1622770353"
|
#define TS_SIGNATURE "rusEFI 2020.07.28.mre_f7.302538475"
|
||||||
|
|
|
@ -3,6 +3,6 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#define SIGNATURE_BOARD prometheus_405
|
#define SIGNATURE_BOARD prometheus_405
|
||||||
#define SIGNATURE_DATE 2020.07.22
|
#define SIGNATURE_DATE 2020.07.28
|
||||||
#define SIGNATURE_HASH 3696987323
|
#define SIGNATURE_HASH 2934591713
|
||||||
#define TS_SIGNATURE "rusEFI 2020.07.22.prometheus_405.3696987323"
|
#define TS_SIGNATURE "rusEFI 2020.07.28.prometheus_405.2934591713"
|
||||||
|
|
|
@ -3,6 +3,6 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#define SIGNATURE_BOARD prometheus_469
|
#define SIGNATURE_BOARD prometheus_469
|
||||||
#define SIGNATURE_DATE 2020.07.22
|
#define SIGNATURE_DATE 2020.07.28
|
||||||
#define SIGNATURE_HASH 3696987323
|
#define SIGNATURE_HASH 2934591713
|
||||||
#define TS_SIGNATURE "rusEFI 2020.07.22.prometheus_469.3696987323"
|
#define TS_SIGNATURE "rusEFI 2020.07.28.prometheus_469.2934591713"
|
||||||
|
|
|
@ -3,6 +3,6 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#define SIGNATURE_BOARD proteus_f4
|
#define SIGNATURE_BOARD proteus_f4
|
||||||
#define SIGNATURE_DATE 2020.07.22
|
#define SIGNATURE_DATE 2020.07.28
|
||||||
#define SIGNATURE_HASH 2765497840
|
#define SIGNATURE_HASH 3597138346
|
||||||
#define TS_SIGNATURE "rusEFI 2020.07.22.proteus_f4.2765497840"
|
#define TS_SIGNATURE "rusEFI 2020.07.28.proteus_f4.3597138346"
|
||||||
|
|
|
@ -3,6 +3,6 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#define SIGNATURE_BOARD proteus_f7
|
#define SIGNATURE_BOARD proteus_f7
|
||||||
#define SIGNATURE_DATE 2020.07.22
|
#define SIGNATURE_DATE 2020.07.28
|
||||||
#define SIGNATURE_HASH 2765497840
|
#define SIGNATURE_HASH 3597138346
|
||||||
#define TS_SIGNATURE "rusEFI 2020.07.22.proteus_f7.2765497840"
|
#define TS_SIGNATURE "rusEFI 2020.07.28.proteus_f7.3597138346"
|
||||||
|
|
|
@ -84,7 +84,7 @@ float fuelClosedLoopCorrection(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||||
return 1.0f;
|
return 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t binIdx = computeStftBin(GET_RPM(), getEngineLoadT(PASS_ENGINE_PARAMETER_SIGNATURE), CONFIG(stft));
|
size_t binIdx = computeStftBin(GET_RPM(), getFuelingLoad(PASS_ENGINE_PARAMETER_SIGNATURE), CONFIG(stft));
|
||||||
|
|
||||||
#if EFI_TUNER_STUDIO
|
#if EFI_TUNER_STUDIO
|
||||||
if (engineConfiguration->debugMode == DBG_FUEL_PID_CORRECTION) {
|
if (engineConfiguration->debugMode == DBG_FUEL_PID_CORRECTION) {
|
||||||
|
|
|
@ -68,6 +68,7 @@ float getEngineLoadT(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||||
case LM_SPEED_DENSITY:
|
case LM_SPEED_DENSITY:
|
||||||
return getMap(PASS_ENGINE_PARAMETER_SIGNATURE);
|
return getMap(PASS_ENGINE_PARAMETER_SIGNATURE);
|
||||||
case LM_ALPHA_N:
|
case LM_ALPHA_N:
|
||||||
|
case LM_ALPHA_N_2:
|
||||||
return Sensor::get(SensorType::Tps1).value_or(0);
|
return Sensor::get(SensorType::Tps1).value_or(0);
|
||||||
case LM_REAL_MAF:
|
case LM_REAL_MAF:
|
||||||
return getRealMaf(PASS_ENGINE_PARAMETER_SIGNATURE);
|
return getRealMaf(PASS_ENGINE_PARAMETER_SIGNATURE);
|
||||||
|
@ -96,151 +97,6 @@ void setSingleCoilDwell(DECLARE_CONFIG_PARAMETER_SIGNATURE) {
|
||||||
engineConfiguration->sparkDwellValues[7] = 0;
|
engineConfiguration->sparkDwellValues[7] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if EFI_ENGINE_CONTROL
|
|
||||||
|
|
||||||
FuelSchedule::FuelSchedule() {
|
|
||||||
clear();
|
|
||||||
for (int cylinderIndex = 0; cylinderIndex < MAX_INJECTION_OUTPUT_COUNT; cylinderIndex++) {
|
|
||||||
InjectionEvent *ev = &elements[cylinderIndex];
|
|
||||||
ev->ownIndex = cylinderIndex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FuelSchedule::clear() {
|
|
||||||
isReady = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FuelSchedule::resetOverlapping() {
|
|
||||||
for (size_t i = 0; i < efi::size(enginePins.injectors); i++) {
|
|
||||||
enginePins.injectors[i].reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns false in case of error, true if success
|
|
||||||
*/
|
|
||||||
bool FuelSchedule::addFuelEventsForCylinder(int i DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
|
||||||
efiAssert(CUSTOM_ERR_ASSERT, engine!=NULL, "engine is NULL", false);
|
|
||||||
|
|
||||||
floatus_t oneDegreeUs = ENGINE(rpmCalculator.oneDegreeUs); // local copy
|
|
||||||
if (cisnan(oneDegreeUs)) {
|
|
||||||
// in order to have fuel schedule we need to have current RPM
|
|
||||||
// wonder if this line slows engine startup?
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* injection phase is scheduled by injection end, so we need to step the angle back
|
|
||||||
* for the duration of the injection
|
|
||||||
*
|
|
||||||
* todo: since this method is not invoked within trigger event handler and
|
|
||||||
* engineState.injectionOffset is calculated from the same utility timer should we more that logic here?
|
|
||||||
*/
|
|
||||||
floatms_t fuelMs = ENGINE(injectionDuration);
|
|
||||||
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(fuelMs), "NaN fuelMs", false);
|
|
||||||
angle_t injectionDuration = MS2US(fuelMs) / oneDegreeUs;
|
|
||||||
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(injectionDuration), "NaN injectionDuration", false);
|
|
||||||
assertAngleRange(injectionDuration, "injectionDuration_r", CUSTOM_INJ_DURATION);
|
|
||||||
floatus_t injectionOffset = ENGINE(engineState.injectionOffset);
|
|
||||||
if (cisnan(injectionOffset)) {
|
|
||||||
// injection offset map not ready - we are not ready to schedule fuel events
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
angle_t baseAngle = injectionOffset - injectionDuration;
|
|
||||||
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(baseAngle), "NaN baseAngle", false);
|
|
||||||
assertAngleRange(baseAngle, "baseAngle_r", CUSTOM_ERR_6554);
|
|
||||||
|
|
||||||
injection_mode_e mode = engine->getCurrentInjectionMode(PASS_ENGINE_PARAMETER_SIGNATURE);
|
|
||||||
|
|
||||||
int injectorIndex;
|
|
||||||
if (mode == IM_SIMULTANEOUS || mode == IM_SINGLE_POINT) {
|
|
||||||
// These modes only have one injector
|
|
||||||
injectorIndex = 0;
|
|
||||||
} else if (mode == IM_SEQUENTIAL || (mode == IM_BATCH && CONFIG(twoWireBatchInjection))) {
|
|
||||||
// Map order index -> cylinder index (firing order)
|
|
||||||
injectorIndex = getCylinderId(i PASS_ENGINE_PARAMETER_SUFFIX) - 1;
|
|
||||||
} else if (mode == IM_BATCH) {
|
|
||||||
// Loop over the first half of the firing order twice
|
|
||||||
injectorIndex = i % (engineConfiguration->specs.cylindersCount / 2);
|
|
||||||
} else {
|
|
||||||
firmwareError(CUSTOM_OBD_UNEXPECTED_INJECTION_MODE, "Unexpected injection mode %d", mode);
|
|
||||||
injectorIndex = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
assertAngleRange(baseAngle, "addFbaseAngle", CUSTOM_ADD_BASE);
|
|
||||||
|
|
||||||
int cylindersCount = CONFIG(specs.cylindersCount);
|
|
||||||
if (cylindersCount < 1) {
|
|
||||||
// May 2020 this somehow still happens with functional tests, maybe race condition?
|
|
||||||
warning(CUSTOM_OBD_ZERO_CYLINDER_COUNT, "Invalid cylinder count: %d", cylindersCount);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
float angle = baseAngle
|
|
||||||
+ i * ENGINE(engineCycle) / cylindersCount;
|
|
||||||
|
|
||||||
InjectorOutputPin *secondOutput;
|
|
||||||
if (mode == IM_BATCH && CONFIG(twoWireBatchInjection)) {
|
|
||||||
/**
|
|
||||||
* also fire the 2nd half of the injectors so that we can implement a batch mode on individual wires
|
|
||||||
*/
|
|
||||||
// Compute the position of this cylinder's twin in the firing order
|
|
||||||
// Each injector gets fired as a primary (the same as sequential), but also
|
|
||||||
// fires the injector 360 degrees later in the firing order.
|
|
||||||
int secondOrder = (i + (CONFIG(specs.cylindersCount) / 2)) % CONFIG(specs.cylindersCount);
|
|
||||||
int secondIndex = getCylinderId(secondOrder PASS_ENGINE_PARAMETER_SUFFIX) - 1;
|
|
||||||
secondOutput = &enginePins.injectors[secondIndex];
|
|
||||||
} else {
|
|
||||||
secondOutput = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
InjectorOutputPin *output = &enginePins.injectors[injectorIndex];
|
|
||||||
bool isSimultanious = mode == IM_SIMULTANEOUS;
|
|
||||||
|
|
||||||
if (!isSimultanious && !output->isInitialized()) {
|
|
||||||
// todo: extract method for this index math
|
|
||||||
warning(CUSTOM_OBD_INJECTION_NO_PIN_ASSIGNED, "no_pin_inj #%s", output->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
InjectionEvent *ev = &elements[i];
|
|
||||||
ev->ownIndex = i;
|
|
||||||
INJECT_ENGINE_REFERENCE(ev);
|
|
||||||
fixAngle(angle, "addFuel#1", CUSTOM_ERR_6554);
|
|
||||||
|
|
||||||
ev->outputs[0] = output;
|
|
||||||
ev->outputs[1] = secondOutput;
|
|
||||||
|
|
||||||
ev->isSimultanious = isSimultanious;
|
|
||||||
|
|
||||||
if (TRIGGER_WAVEFORM(getSize()) < 1) {
|
|
||||||
warning(CUSTOM_ERR_NOT_INITIALIZED_TRIGGER, "uninitialized TriggerWaveform");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(angle), "findAngle#3", false);
|
|
||||||
assertAngleRange(angle, "findAngle#a33", CUSTOM_ERR_6544);
|
|
||||||
ev->injectionStart.setAngle(angle PASS_ENGINE_PARAMETER_SUFFIX);
|
|
||||||
#if EFI_UNIT_TEST
|
|
||||||
printf("registerInjectionEvent angle=%.2f trgIndex=%d inj %d\r\n", angle, ev->injectionStart.triggerEventIndex, injectorIndex);
|
|
||||||
#endif
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FuelSchedule::addFuelEvents(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
|
||||||
clear();
|
|
||||||
|
|
||||||
for (int cylinderIndex = 0; cylinderIndex < CONFIG(specs.cylindersCount); cylinderIndex++) {
|
|
||||||
InjectionEvent *ev = &elements[cylinderIndex];
|
|
||||||
ev->ownIndex = cylinderIndex; // todo: is this assignment needed here? we now initialize in constructor
|
|
||||||
bool result = addFuelEventsForCylinder(cylinderIndex PASS_ENGINE_PARAMETER_SUFFIX);
|
|
||||||
if (!result)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
isReady = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static floatms_t getCrankingSparkDwell(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
static floatms_t getCrankingSparkDwell(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||||
if (engineConfiguration->useConstantDwellDuringCranking) {
|
if (engineConfiguration->useConstantDwellDuringCranking) {
|
||||||
return engineConfiguration->ignitionDwellForCrankingMs;
|
return engineConfiguration->ignitionDwellForCrankingMs;
|
||||||
|
|
|
@ -112,42 +112,6 @@ temperature_t getTCharge(int rpm, float tps DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
||||||
return Tcharge;
|
return Tcharge;
|
||||||
}
|
}
|
||||||
|
|
||||||
AirmassResult getSpeedDensityAirmass(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
|
||||||
ScopePerf perf(PE::GetSpeedDensityFuel);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* most of the values are pre-calculated for performance reasons
|
|
||||||
*/
|
|
||||||
float tChargeK = ENGINE(engineState.sd.tChargeK);
|
|
||||||
if (cisnan(tChargeK)) {
|
|
||||||
warning(CUSTOM_ERR_TCHARGE_NOT_READY2, "tChargeK not ready"); // this would happen before we have CLT reading for example
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
float map = getMap(PASS_ENGINE_PARAMETER_SIGNATURE);
|
|
||||||
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(map), "NaN map", {});
|
|
||||||
|
|
||||||
engine->engineState.sd.manifoldAirPressureAccelerationAdjustment = engine->engineLoadAccelEnrichment.getEngineLoadEnrichment(PASS_ENGINE_PARAMETER_SIGNATURE);
|
|
||||||
|
|
||||||
float adjustedMap = engine->engineState.sd.adjustedManifoldAirPressure = map + engine->engineState.sd.manifoldAirPressureAccelerationAdjustment;
|
|
||||||
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(adjustedMap), "NaN adjustedMap", {});
|
|
||||||
|
|
||||||
float airMass = SpeedDensityBase::getAirmassImpl(ENGINE(engineState.currentBaroCorrectedVE), adjustedMap, tChargeK PASS_ENGINE_PARAMETER_SUFFIX);
|
|
||||||
if (cisnan(airMass)) {
|
|
||||||
warning(CUSTOM_ERR_6685, "NaN airMass");
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
#if EFI_PRINTF_FUEL_DETAILS
|
|
||||||
printf("getSpeedDensityAirmass map=%.2f adjustedMap=%.2f airMass=%.2f\t\n",
|
|
||||||
map, adjustedMap, engine->engineState.sd.adjustedManifoldAirPressure);
|
|
||||||
#endif /*EFI_PRINTF_FUEL_DETAILS */
|
|
||||||
|
|
||||||
return {
|
|
||||||
airMass,
|
|
||||||
map, // AFR/VE table Y axis
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void setDefaultVETable(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
void setDefaultVETable(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||||
setRpmTableBin(config->veRpmBins, FUEL_RPM_COUNT);
|
setRpmTableBin(config->veRpmBins, FUEL_RPM_COUNT);
|
||||||
veMap.setAll(80);
|
veMap.setAll(80);
|
||||||
|
|
|
@ -18,4 +18,3 @@ temperature_t getTCharge(int rpm, float tps DECLARE_ENGINE_PARAMETER_SUFFIX);
|
||||||
|
|
||||||
void setDefaultVETable(DECLARE_ENGINE_PARAMETER_SIGNATURE);
|
void setDefaultVETable(DECLARE_ENGINE_PARAMETER_SIGNATURE);
|
||||||
void initSpeedDensity(DECLARE_ENGINE_PARAMETER_SIGNATURE);
|
void initSpeedDensity(DECLARE_ENGINE_PARAMETER_SIGNATURE);
|
||||||
AirmassResult getSpeedDensityAirmass(DECLARE_ENGINE_PARAMETER_SIGNATURE);
|
|
||||||
|
|
|
@ -1261,7 +1261,7 @@ const command_i_s commandsI[] = {{"ignition_mode", setIgnitionMode},
|
||||||
{"can_vss", setCanVss},
|
{"can_vss", setCanVss},
|
||||||
#endif /* EFI_CAN_SUPPORT */
|
#endif /* EFI_CAN_SUPPORT */
|
||||||
#if EFI_IDLE_CONTROL
|
#if EFI_IDLE_CONTROL
|
||||||
{"idle_position", setIdleValvePosition},
|
{"idle_position", setManualIdleValvePosition},
|
||||||
{"idle_rpm", setTargetIdleRpm},
|
{"idle_rpm", setTargetIdleRpm},
|
||||||
{"idle_dt", setIdleDT},
|
{"idle_dt", setIdleDT},
|
||||||
#endif /* EFI_IDLE_CONTROL */
|
#endif /* EFI_IDLE_CONTROL */
|
||||||
|
|
|
@ -323,7 +323,10 @@ bool OutputPin::getAndSet(int logicValue) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void OutputPin::setValue(int logicValue) {
|
void OutputPin::setValue(int logicValue) {
|
||||||
ScopePerf perf(PE::OutputPinSetValue);
|
#if ENABLE_PERF_TRACE
|
||||||
|
// todo: https://github.com/rusefi/rusefi/issues/1638
|
||||||
|
// ScopePerf perf(PE::OutputPinSetValue);
|
||||||
|
#endif // ENABLE_PERF_TRACE
|
||||||
|
|
||||||
#if EFI_PROD_CODE
|
#if EFI_PROD_CODE
|
||||||
efiAssertVoid(CUSTOM_ERR_6621, modePtr!=NULL, "pin mode not initialized");
|
efiAssertVoid(CUSTOM_ERR_6621, modePtr!=NULL, "pin mode not initialized");
|
||||||
|
|
|
@ -18,6 +18,9 @@
|
||||||
! rename the bit or substitute unused integer with any new fields of the same size
|
! rename the bit or substitute unused integer with any new fields of the same size
|
||||||
! invoke gen_config.bat to apply the tools which would generate .h and .ini files
|
! invoke gen_config.bat to apply the tools which would generate .h and .ini files
|
||||||
!
|
!
|
||||||
|
! Q: Which files to include into Pull Requests?
|
||||||
|
! A: Please only include source files (.txt and .input) into a PR, we have amazing GitHub Actions which would do the rest really
|
||||||
|
! really nicely!
|
||||||
!
|
!
|
||||||
! each field is declared as
|
! each field is declared as
|
||||||
! type name;comment
|
! type name;comment
|
||||||
|
@ -289,8 +292,8 @@ struct spi_pins
|
||||||
end_struct
|
end_struct
|
||||||
|
|
||||||
|
|
||||||
#define gppwm_channel_e_enum "TPS", "MAP", "CLT", "IAT"
|
#define gppwm_channel_e_enum "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
|
||||||
custom gppwm_channel_e 1 bits, U08, @OFFSET@, [0:1], @@gppwm_channel_e_enum@@
|
custom gppwm_channel_e 1 bits, U08, @OFFSET@, [0:2], @@gppwm_channel_e_enum@@
|
||||||
|
|
||||||
struct gppwm_channel
|
struct gppwm_channel
|
||||||
output_pin_e pin;+Select a pin to use for PWM or on-off output.;
|
output_pin_e pin;+Select a pin to use for PWM or on-off output.;
|
||||||
|
@ -432,7 +435,7 @@ ThermistorConf iat;
|
||||||
float knockBandCustom;+We calculate knock band based of cylinderBore\n Use this to override - kHz knock band override;"kHz", 1, 0.0, 0.0, 10.0, 2
|
float knockBandCustom;+We calculate knock band based of cylinderBore\n Use this to override - kHz knock band override;"kHz", 1, 0.0, 0.0, 10.0, 2
|
||||||
|
|
||||||
|
|
||||||
float[DWELL_CURVE_SIZE] sparkDwellRpmBins;On single-coil or wasted spark setups you have to lower dwell at high RPM;"RPM", 1, 0.0, 0.0, 18000, 2
|
float[DWELL_CURVE_SIZE] sparkDwellRpmBins;On Single Coil or Wasted Spark setups you have to lower dwell at high RPM;"RPM", 1, 0.0, 0.0, 18000, 2
|
||||||
float[DWELL_CURVE_SIZE] sparkDwellValues;;"ms", 1, 0.0, 0.0, 30.0, 2
|
float[DWELL_CURVE_SIZE] sparkDwellValues;;"ms", 1, 0.0, 0.0, 30.0, 2
|
||||||
|
|
||||||
struct_no_prefix specs_s
|
struct_no_prefix specs_s
|
||||||
|
@ -456,8 +459,7 @@ end_struct
|
||||||
int sensorSnifferRpmThreshold;+Disable sensor sniffer above this rpm;"RPM", 1, 0, 0,30000, 0
|
int sensorSnifferRpmThreshold;+Disable sensor sniffer above this rpm;"RPM", 1, 0, 0,30000, 0
|
||||||
int rpmHardLimit;set rpm_hard_limit X;"rpm", 1, 0, 0, 20000.0, 2
|
int rpmHardLimit;set rpm_hard_limit X;"rpm", 1, 0, 0, 20000.0, 2
|
||||||
|
|
||||||
|
#define engine_load_mode_e_enum "INVALID", "Alpha-N/TPS", "INVALID", "Speed Density", "MAF Air Charge", "Alpha-N", "INVALID"
|
||||||
#define engine_load_mode_e_enum "INVALID", "Alpha-N/TPS", "INVALID", "SPEED DENSITY", "MAF Air Charge", "INVALID", "INVALID"
|
|
||||||
|
|
||||||
|
|
||||||
custom engine_load_mode_e 4 bits, U32, @OFFSET@, [0:2], @@engine_load_mode_e_enum@@
|
custom engine_load_mode_e 4 bits, U32, @OFFSET@, [0:2], @@engine_load_mode_e_enum@@
|
||||||
|
@ -470,8 +472,8 @@ injection_mode_e injectionMode;+This is where the fuel injection type is defined
|
||||||
angle_t extraInjectionOffset;+this is about deciding when the injector starts it's squirt\nSee also injectionPhase map\ntodo: do we need even need this since we have the map anyway?;"deg", 1, 0.0, -720, 720, 2
|
angle_t extraInjectionOffset;+this is about deciding when the injector starts it's squirt\nSee also injectionPhase map\ntodo: do we need even need this since we have the map anyway?;"deg", 1, 0.0, -720, 720, 2
|
||||||
angle_t crankingTimingAngle;+Ignition advance angle used during engine cranking, 5-10 degrees will work as a base setting for most engines.\nset cranking_timing_angle X; "deg", 1, 0.0, -360, 360, 2
|
angle_t crankingTimingAngle;+Ignition advance angle used during engine cranking, 5-10 degrees will work as a base setting for most engines.\nset cranking_timing_angle X; "deg", 1, 0.0, -360, 360, 2
|
||||||
|
|
||||||
custom ignition_mode_e 4 bits, U32, @OFFSET@, [0:1], "One coil", "Individual Coils", "Wasted", "Two distributors"
|
custom ignition_mode_e 4 bits, U32, @OFFSET@, [0:1], "Single Coil", "Individual Coils", "Wasted Spark", "Two Distributors"
|
||||||
ignition_mode_e ignitionMode;+"One Coil" is for use on distributed ignition system. "Individual Coils" is to be used when you have one coil per cylinder (COP or similar). "Wasted" means one coil is driving two spark plugs in two cylinders, with one of the sparks not doing anything since it's happening on the exhaust cycle\nset ignition_mode X
|
ignition_mode_e ignitionMode;+"Single Coil" is for use on distributed ignition system. "Individual Coils" is to be used when you have one coil per cylinder (COP or similar). "Wasted Spark" means one coil is driving two spark plugs in two cylinders, with one of the sparks not doing anything since it's happening on the exhaust cycle\nset ignition_mode X
|
||||||
|
|
||||||
angle_t ignitionOffset;+this value could be used to offset the whole ignition timing table by a constant;"RPM", 1, 0, 0, 3000.0, 0
|
angle_t ignitionOffset;+this value could be used to offset the whole ignition timing table by a constant;"RPM", 1, 0, 0, 3000.0, 0
|
||||||
|
|
||||||
|
@ -707,7 +709,7 @@ bit is_enabled_spi_2
|
||||||
bit useIdleTimingPidControl
|
bit useIdleTimingPidControl
|
||||||
bit useTPSBasedVeTable
|
bit useTPSBasedVeTable
|
||||||
bit is_enabled_spi_4
|
bit is_enabled_spi_4
|
||||||
bit pauseEtbControl;+Disable the electronic throttle motor for testing.\nThis mode is for testing ETB position sensors, etc without actually driving the throttle.
|
bit pauseEtbControl;+Disable the electronic throttle motor and DC idle motor for testing.\nThis mode is for testing ETB/DC idle position sensors, etc without actually driving the throttle.
|
||||||
bit alignEngineSnifferAtTDC
|
bit alignEngineSnifferAtTDC
|
||||||
bit useETBforIdleControl;+This setting allows the ETB to act as the idle air control valve and move to regulate the airflow at idle.
|
bit useETBforIdleControl;+This setting allows the ETB to act as the idle air control valve and move to regulate the airflow at idle.
|
||||||
bit idleIncrementalPidCic
|
bit idleIncrementalPidCic
|
||||||
|
@ -826,7 +828,7 @@ custom maf_sensor_type_e 4 bits, S32, @OFFSET@, [0:1], @@maf_sensor_type_e_enum@
|
||||||
bit enableInnovateLC2
|
bit enableInnovateLC2
|
||||||
bit showHumanReadableWarning
|
bit showHumanReadableWarning
|
||||||
bit stftIgnoreErrorMagnitude;+If enabled, adjust at a constant rate instead of a rate proportional to the current lambda error. This mode may be easier to tune, and more tolerant of sensor noise. Use of this mode is required if you have a narrowband O2 sensor.;
|
bit stftIgnoreErrorMagnitude;+If enabled, adjust at a constant rate instead of a rate proportional to the current lambda error. This mode may be easier to tune, and more tolerant of sensor noise. Use of this mode is required if you have a narrowband O2 sensor.;
|
||||||
bit unusedBit_251_11
|
bit dcMotorIdleValve;+Used on some German vehicles around late 90s: cable-operated throttle and DC motor idle air valve.\nSet the primary TPS to the cable-operated throttle's sensor\nSet the secondary TPS to the mini ETB's position sensor(s).
|
||||||
bit unusedBit_251_12
|
bit unusedBit_251_12
|
||||||
bit unusedBit_251_13
|
bit unusedBit_251_13
|
||||||
bit unusedBit_251_14
|
bit unusedBit_251_14
|
||||||
|
@ -950,7 +952,7 @@ custom idle_mode_e 4 bits, U32, @OFFSET@, [0:0], "Automatic", "Manual"
|
||||||
bit isManualSpinningMode;Usually if we have no trigger events that means engine is stopped\nUnless we are troubleshooting and spinning the engine by hand - this case a longer\ndelay is needed
|
bit isManualSpinningMode;Usually if we have no trigger events that means engine is stopped\nUnless we are troubleshooting and spinning the engine by hand - this case a longer\ndelay is needed
|
||||||
bit twoWireBatchInjection;+This is needed if your coils are individually wired and you wish to use batch injection.\nenable two_wire_batch_injection
|
bit twoWireBatchInjection;+This is needed if your coils are individually wired and you wish to use batch injection.\nenable two_wire_batch_injection
|
||||||
bit useOnlyRisingEdgeForTrigger;+VR sensors are only precise on rising front\nenable trigger_only_front
|
bit useOnlyRisingEdgeForTrigger;+VR sensors are only precise on rising front\nenable trigger_only_front
|
||||||
bit twoWireBatchIgnition;+This is needed if your coils are individually wired (COP) and you wish to use batch ignition (wasted spark).
|
bit twoWireBatchIgnition;+This is needed if your coils are individually wired (COP) and you wish to use batch ignition (Wasted Spark).
|
||||||
bit useFixedBaroCorrFromMap
|
bit useFixedBaroCorrFromMap
|
||||||
bit useSeparateAdvanceForCranking;+This activates a separate advance table for cranking conditions, this allows cranking advance to be RPM dependant.
|
bit useSeparateAdvanceForCranking;+This activates a separate advance table for cranking conditions, this allows cranking advance to be RPM dependant.
|
||||||
bit useAdvanceCorrectionsForCranking;+This enables the various ignition corrections during cranking (IAT, CLT, FSIO and PID idle).
|
bit useAdvanceCorrectionsForCranking;+This enables the various ignition corrections during cranking (IAT, CLT, FSIO and PID idle).
|
||||||
|
@ -1673,4 +1675,4 @@ end_struct
|
||||||
#define show_test_presets true
|
#define show_test_presets true
|
||||||
#define show_Frankenso_presets true
|
#define show_Frankenso_presets true
|
||||||
#define show_microRusEFI_presets true
|
#define show_microRusEFI_presets true
|
||||||
#define show_Proteus_presets true
|
#define show_Proteus_presets true
|
||||||
|
|
|
@ -206,8 +206,8 @@ enable2ndByteCanID = false
|
||||||
internalMcuTemperature = scalar,S08, 11, "deg C", 1, 0
|
internalMcuTemperature = scalar,S08, 11, "deg C", 1, 0
|
||||||
coolant = scalar, S16, 12, "deg C",{1/@@PACK_MULT_TEMPERATURE@@}, 0.0
|
coolant = scalar, S16, 12, "deg C",{1/@@PACK_MULT_TEMPERATURE@@}, 0.0
|
||||||
intake = scalar, S16, 14, "deg C",{1/@@PACK_MULT_TEMPERATURE@@}, 0.0
|
intake = scalar, S16, 14, "deg C",{1/@@PACK_MULT_TEMPERATURE@@}, 0.0
|
||||||
; todo: aux1
|
auxt1 = scalar, S16, 16, "deg C",{1/@@PACK_MULT_TEMPERATURE@@}, 0.0
|
||||||
; todo: aux2
|
auxt2 = scalar, S16, 18, "deg C",{1/@@PACK_MULT_TEMPERATURE@@}, 0.0
|
||||||
|
|
||||||
|
|
||||||
; throttle, pedal
|
; throttle, pedal
|
||||||
|
@ -347,7 +347,7 @@ enable2ndByteCanID = false
|
||||||
rawOilPressure = scalar, U16, 242, "V",{1/@@PACK_MULT_VOLTAGE@@}, 0.0
|
rawOilPressure = scalar, U16, 242, "V",{1/@@PACK_MULT_VOLTAGE@@}, 0.0
|
||||||
|
|
||||||
; we use this to match logs to tunes
|
; we use this to match logs to tunes
|
||||||
tuneCrc16= scalar, U16, 244, "crc16", 1, 0
|
tuneCrc16 = scalar, U16, 244, "crc16", 1, 0
|
||||||
|
|
||||||
;
|
;
|
||||||
; see TunerStudioOutputChannels struct
|
; see TunerStudioOutputChannels struct
|
||||||
|
@ -362,10 +362,10 @@ enable2ndByteCanID = false
|
||||||
time = { timeNow }
|
time = { timeNow }
|
||||||
|
|
||||||
; These "synthetic" channels provide the Y-axis (load) value for gen purp PWM table's Y axes
|
; These "synthetic" channels provide the Y-axis (load) value for gen purp PWM table's Y axes
|
||||||
gppwm1_load = {(gppwm1_loadAxis == 0) ? TPSValue : ((gppwm1_loadAxis == 1) ? MAPValue : ((gppwm1_loadAxis == 2) ? coolant : intake))}
|
gppwm1_load = {(gppwm1_loadAxis == 0) ? TPSValue : ((gppwm1_loadAxis == 1) ? MAPValue : ((gppwm1_loadAxis == 2) ? coolant : ((gppwm1_loadAxis == 3) ? intake : ((gppwm1_loadAxis == 4) ? fuelingLoad : ignitionLoad))))}
|
||||||
gppwm2_load = {(gppwm2_loadAxis == 0) ? TPSValue : ((gppwm2_loadAxis == 1) ? MAPValue : ((gppwm2_loadAxis == 2) ? coolant : intake))}
|
gppwm2_load = {(gppwm2_loadAxis == 0) ? TPSValue : ((gppwm2_loadAxis == 1) ? MAPValue : ((gppwm2_loadAxis == 2) ? coolant : ((gppwm2_loadAxis == 3) ? intake : ((gppwm2_loadAxis == 4) ? fuelingLoad : ignitionLoad))))}
|
||||||
gppwm3_load = {(gppwm3_loadAxis == 0) ? TPSValue : ((gppwm3_loadAxis == 1) ? MAPValue : ((gppwm3_loadAxis == 2) ? coolant : intake))}
|
gppwm3_load = {(gppwm3_loadAxis == 0) ? TPSValue : ((gppwm3_loadAxis == 1) ? MAPValue : ((gppwm3_loadAxis == 2) ? coolant : ((gppwm3_loadAxis == 3) ? intake : ((gppwm3_loadAxis == 4) ? fuelingLoad : ignitionLoad))))}
|
||||||
gppwm4_load = {(gppwm4_loadAxis == 0) ? TPSValue : ((gppwm4_loadAxis == 1) ? MAPValue : ((gppwm4_loadAxis == 2) ? coolant : intake))}
|
gppwm4_load = {(gppwm4_loadAxis == 0) ? TPSValue : ((gppwm4_loadAxis == 1) ? MAPValue : ((gppwm4_loadAxis == 2) ? coolant : ((gppwm4_loadAxis == 3) ? intake : ((gppwm4_loadAxis == 4) ? fuelingLoad : ignitionLoad))))}
|
||||||
|
|
||||||
[PcVariables]
|
[PcVariables]
|
||||||
tuneCrcPcVariable = continuousChannelValue, tuneCrc16
|
tuneCrcPcVariable = continuousChannelValue, tuneCrc16
|
||||||
|
@ -931,6 +931,8 @@ gaugeCategory = Sensors - Extra 1
|
||||||
internalMcuTemperatureGauge = internalMcuTemperature, @@GAUGE_NAME_ECU_TEMPERATURE@@, "C", 0, 100, 0, 0, 75, 100, 0, 0
|
internalMcuTemperatureGauge = internalMcuTemperature, @@GAUGE_NAME_ECU_TEMPERATURE@@, "C", 0, 100, 0, 0, 75, 100, 0, 0
|
||||||
OilPressGauge = oilPressure, "Oil Pressure", "kPa", 0, 750, 35, 75, 550, 700, 0, 0
|
OilPressGauge = oilPressure, "Oil Pressure", "kPa", 0, 750, 35, 75, 550, 700, 0, 0
|
||||||
idleAirValvePositionGauge = idleAirValvePosition, "Idle position", "%", 0, 100, 0, 0, 100, 100, 1, 1
|
idleAirValvePositionGauge = idleAirValvePosition, "Idle position", "%", 0, 100, 0, 0, 100, 100, 1, 1
|
||||||
|
AuxT1Gauge = auxt1, "Aux temp 1", "deg C", -40, 140, -15, 1, 95, 110, 1, 1
|
||||||
|
AuxT2Gauge = auxt2, "Aux temp 2", "deg C", -40, 140, -15, 1, 95, 110, 1, 1
|
||||||
|
|
||||||
gaugeCategory = Ignition
|
gaugeCategory = Ignition
|
||||||
ignadvGauge = ignitionAdvance, "Ignition timing", "degrees", -100, 100, -999, -999, 999, 999, 1, 1
|
ignadvGauge = ignitionAdvance, "Ignition timing", "degrees", -100, 100, -999, -999, 999, 999, 1, 1
|
||||||
|
@ -2131,9 +2133,9 @@ cmd_set_engine_type_default = "w\x00\x31\x00\x00"
|
||||||
|
|
||||||
dialog = baroSettings, "Baro sensor"
|
dialog = baroSettings, "Baro sensor"
|
||||||
field = "Baro ADC input", baroSensor_hwChannel
|
field = "Baro ADC input", baroSensor_hwChannel
|
||||||
field = baroSensor_lowValue, baroSensor_lowValue, {baroSensor_hwChannel != 16}
|
field = baroSensor_lowValue, baroSensor_lowValue, {baroSensor_hwChannel != @@ADC_CHANNEL_NONE@@}
|
||||||
field = baroSensor_highValue, baroSensor_highValue, {baroSensor_hwChannel != 16}
|
field = baroSensor_highValue, baroSensor_highValue, {baroSensor_hwChannel != @@ADC_CHANNEL_NONE@@}
|
||||||
field = baroSensor_type, baroSensor_type, {baroSensor_hwChannel != 16}
|
field = baroSensor_type, baroSensor_type, {baroSensor_hwChannel != @@ADC_CHANNEL_NONE@@}
|
||||||
|
|
||||||
dialog = mapCurves, "MAP sampling", yAxis
|
dialog = mapCurves, "MAP sampling", yAxis
|
||||||
field = "isMapAveragingEnabled", isMapAveragingEnabled
|
field = "isMapAveragingEnabled", isMapAveragingEnabled
|
||||||
|
@ -2159,7 +2161,7 @@ cmd_set_engine_type_default = "w\x00\x31\x00\x00"
|
||||||
|
|
||||||
dialog = egoSettings, "", yAxis
|
dialog = egoSettings, "", yAxis
|
||||||
panel = egoSettings_IO
|
panel = egoSettings_IO
|
||||||
panel = egoSettings_sensor, {afr_hwChannel != 16 && enableAemXSeries == 0 && !auxSerialRxPin && !auxSerialTxPin}
|
panel = egoSettings_sensor, {afr_hwChannel != @@ADC_CHANNEL_NONE@@ && enableAemXSeries == 0 && !auxSerialRxPin && !auxSerialTxPin}
|
||||||
field = "Enable AEM X-Series CANbus", enableAemXSeries, { canReadEnabled }
|
field = "Enable AEM X-Series CANbus", enableAemXSeries, { canReadEnabled }
|
||||||
field = "Enable Innovate LC-2 Serial", enableInnovateLC2, { auxSerialRxPin && auxSerialTxPin }
|
field = "Enable Innovate LC-2 Serial", enableInnovateLC2, { auxSerialRxPin && auxSerialTxPin }
|
||||||
|
|
||||||
|
@ -2244,7 +2246,7 @@ cmd_set_engine_type_default = "w\x00\x31\x00\x00"
|
||||||
dialog = idleSettings, "", yAxis
|
dialog = idleSettings, "", yAxis
|
||||||
field = "Idle IAC control mode", idleMode
|
field = "Idle IAC control mode", idleMode
|
||||||
field = useInstantRpmForIdle, useInstantRpmForIdle
|
field = useInstantRpmForIdle, useInstantRpmForIdle
|
||||||
field = "use ETB for idle", useETBforIdleControl
|
field = "use ETB for idle", useETBforIdleControl, { throttlePedalPositionAdcChannel != @@ADC_CHANNEL_NONE@@ }
|
||||||
field = "ETB Idle range", etbIdleThrottleRange, {useETBforIdleControl == 1}
|
field = "ETB Idle range", etbIdleThrottleRange, {useETBforIdleControl == 1}
|
||||||
field = "Use separate Ignition Table for idle", useSeparateAdvanceForIdle
|
field = "Use separate Ignition Table for idle", useSeparateAdvanceForIdle
|
||||||
field = "Use separate VE Table for idle", useSeparateVeForIdle
|
field = "Use separate VE Table for idle", useSeparateVeForIdle
|
||||||
|
@ -2842,13 +2844,13 @@ cmd_set_engine_type_default = "w\x00\x31\x00\x00"
|
||||||
panel = veTableMap, South
|
panel = veTableMap, South
|
||||||
|
|
||||||
dialog = etbPidDialog, "PID settings"
|
dialog = etbPidDialog, "PID settings"
|
||||||
field = "pFactor", etb_pFactor, {throttlePedalPositionAdcChannel != 16}
|
field = "pFactor", etb_pFactor
|
||||||
field = "iFactor", etb_iFactor, {throttlePedalPositionAdcChannel != 16}
|
field = "iFactor", etb_iFactor
|
||||||
field = "dFactor", etb_dFactor, {throttlePedalPositionAdcChannel != 16}
|
field = "dFactor", etb_dFactor
|
||||||
field = "pid min", etb_minValue, {throttlePedalPositionAdcChannel != 16}
|
field = "pid min", etb_minValue
|
||||||
field = "pid max", etb_maxValue, {throttlePedalPositionAdcChannel != 16}
|
field = "pid max", etb_maxValue
|
||||||
field = "iTermMin", etb_iTermMin, {throttlePedalPositionAdcChannel != 16}
|
field = "iTermMin", etb_iTermMin
|
||||||
field = "iTermMax", etb_iTermMax, {throttlePedalPositionAdcChannel != 16}
|
field = "iTermMax", etb_iTermMax
|
||||||
|
|
||||||
dialog = etbIdleDialog, "ETB Idle"
|
dialog = etbIdleDialog, "ETB Idle"
|
||||||
field = "use ETB for idle", useETBforIdleControl
|
field = "use ETB for idle", useETBforIdleControl
|
||||||
|
@ -2856,11 +2858,12 @@ cmd_set_engine_type_default = "w\x00\x31\x00\x00"
|
||||||
|
|
||||||
dialog = etbDialogLeft
|
dialog = etbDialogLeft
|
||||||
field = "https://rusefi.com/s/etb"
|
field = "https://rusefi.com/s/etb"
|
||||||
|
field = "Late 90s German DC Motor idle", dcMotorIdleValve, { throttlePedalPositionAdcChannel == @@ADC_CHANNEL_NONE@@ }
|
||||||
field = "Detailed status in console", isVerboseETB
|
field = "Detailed status in console", isVerboseETB
|
||||||
field = "Disable ETB Motor", pauseEtbControl
|
field = "Disable ETB Motor", pauseEtbControl
|
||||||
; we need the term about stepper idle in here, because there's a bug in TS that you can't have different visibility
|
; we need the term about stepper idle in here, because there's a bug in TS that you can't have different visibility
|
||||||
; criteria for the same panel when used in multiple places
|
; criteria for the same panel when used in multiple places
|
||||||
panel = hbridgeHardware, { throttlePedalPositionAdcChannel != 16 || useStepperIdle && useHbridges }
|
panel = hbridgeHardware, { throttlePedalPositionAdcChannel != @@ADC_CHANNEL_NONE@@ || (useStepperIdle && useHbridges) || dcMotorIdleValve }
|
||||||
|
|
||||||
dialog = etbAutotune, "PID Autotune"
|
dialog = etbAutotune, "PID Autotune"
|
||||||
commandButton = "Start ETB PID Autotune", cmd_etb_autotune
|
commandButton = "Start ETB PID Autotune", cmd_etb_autotune
|
||||||
|
@ -2872,8 +2875,8 @@ cmd_set_engine_type_default = "w\x00\x31\x00\x00"
|
||||||
field = "Debug mode", debugMode
|
field = "Debug mode", debugMode
|
||||||
|
|
||||||
dialog = etbDialogRight
|
dialog = etbDialogRight
|
||||||
panel = etbIdleDialog
|
panel = etbIdleDialog, { throttlePedalPositionAdcChannel != @@ADC_CHANNEL_NONE@@ }
|
||||||
panel = etbPidDialog
|
panel = etbPidDialog, { (throttlePedalPositionAdcChannel != @@ADC_CHANNEL_NONE@@) || dcMotorIdleValve }
|
||||||
panel = etbAutotune
|
panel = etbAutotune
|
||||||
|
|
||||||
; Neutral position handling not yet implemented!
|
; Neutral position handling not yet implemented!
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
<component name="libraryTable">
|
||||||
|
<library name="dfu_java">
|
||||||
|
<CLASSES>
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/dfu/dfu_java.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/dfu/IntelHexParser.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/dfu/usb4java-1.3.0.jar!/" />
|
||||||
|
</CLASSES>
|
||||||
|
<JAVADOC />
|
||||||
|
<SOURCES />
|
||||||
|
</library>
|
||||||
|
</component>
|
|
@ -0,0 +1,11 @@
|
||||||
|
<component name="libraryTable">
|
||||||
|
<library name="jsr305-2.0.1">
|
||||||
|
<CLASSES>
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/jsr305-2.0.1.jar!/" />
|
||||||
|
</CLASSES>
|
||||||
|
<JAVADOC />
|
||||||
|
<SOURCES>
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/jsr305-2.0.1.jar!/" />
|
||||||
|
</SOURCES>
|
||||||
|
</library>
|
||||||
|
</component>
|
|
@ -0,0 +1,10 @@
|
||||||
|
<component name="libraryTable">
|
||||||
|
<library name="log4j-api-2.13.3">
|
||||||
|
<CLASSES>
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/log4j-api-2.13.3.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/log4j-core-2.13.3.jar!/" />
|
||||||
|
</CLASSES>
|
||||||
|
<JAVADOC />
|
||||||
|
<SOURCES />
|
||||||
|
</library>
|
||||||
|
</component>
|
|
@ -0,0 +1,11 @@
|
||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Launcher network connector" type="Application" factoryName="Application">
|
||||||
|
<option name="MAIN_CLASS_NAME" value="com.rusefi.Launcher" />
|
||||||
|
<module name="ui" />
|
||||||
|
<option name="PROGRAM_PARAMETERS" value="network_connector" />
|
||||||
|
<option name="VM_PARAMETERS" value="-Dini_file_path=../firmware/tunerstudio -Dshow_etb_pane=true -Dhigh_speed_logger_rpm=10000" />
|
||||||
|
<method v="2">
|
||||||
|
<option name="Make" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
|
@ -555,7 +555,7 @@ public class AutoTest {
|
||||||
|
|
||||||
boolean failed = false;
|
boolean failed = false;
|
||||||
try {
|
try {
|
||||||
LinkManager linkManager = new LinkManager(FileLog.LOGGER);
|
LinkManager linkManager = new LinkManager();
|
||||||
IoUtil.connectToSimulator(linkManager, startSimulator);
|
IoUtil.connectToSimulator(linkManager, startSimulator);
|
||||||
new AutoTest(linkManager, linkManager.getCommandQueue()).mainTestBody();
|
new AutoTest(linkManager, linkManager.getCommandQueue()).mainTestBody();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
|
|
|
@ -12,7 +12,7 @@ public class EnduranceTest {
|
||||||
private static final int DEFAULT_COUNT = 2000;
|
private static final int DEFAULT_COUNT = 2000;
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
LinkManager linkManager = new LinkManager(FileLog.LOGGER);
|
LinkManager linkManager = new LinkManager();
|
||||||
CommandQueue commandQueue = linkManager.getCommandQueue();
|
CommandQueue commandQueue = linkManager.getCommandQueue();
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
int count = parseCount(args);
|
int count = parseCount(args);
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package com.rusefi;
|
package com.rusefi;
|
||||||
|
|
||||||
import com.rusefi.io.CommandQueue;
|
|
||||||
import com.rusefi.io.LinkManager;
|
import com.rusefi.io.LinkManager;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
@ -83,7 +82,7 @@ public class RealHwTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void runRealHardwareTest(String port) throws Exception {
|
private static void runRealHardwareTest(String port) throws Exception {
|
||||||
LinkManager linkManager = new LinkManager(FileLog.LOGGER);
|
LinkManager linkManager = new LinkManager();
|
||||||
IoUtil.realHardwareConnect(linkManager, port);
|
IoUtil.realHardwareConnect(linkManager, port);
|
||||||
new AutoTest(linkManager, linkManager.getCommandQueue()).mainTestBody();
|
new AutoTest(linkManager, linkManager.getCommandQueue()).mainTestBody();
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,8 @@ import java.util.function.Consumer;
|
||||||
* Andrey Belomutskiy, (c) 2013-2020
|
* Andrey Belomutskiy, (c) 2013-2020
|
||||||
*/
|
*/
|
||||||
public class SimulatorExecHelper {
|
public class SimulatorExecHelper {
|
||||||
|
private final static NamedThreadFactory THREAD_FACTORY = new NamedThreadFactory("SimulatorExecHelper", true);
|
||||||
|
|
||||||
// see also SimulatorHelper
|
// see also SimulatorHelper
|
||||||
private static final String SIMULATOR_BINARY = "../simulator/build/rusefi_simulator.exe";
|
private static final String SIMULATOR_BINARY = "../simulator/build/rusefi_simulator.exe";
|
||||||
static Process simulatorProcess;
|
static Process simulatorProcess;
|
||||||
|
@ -42,8 +44,7 @@ public class SimulatorExecHelper {
|
||||||
public static void dumpProcessOutput(Process process) throws IOException {
|
public static void dumpProcessOutput(Process process) throws IOException {
|
||||||
BufferedReader input =
|
BufferedReader input =
|
||||||
new BufferedReader(new InputStreamReader(process.getInputStream()));
|
new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||||
Thread thread = new Thread(createErrorStreamEcho(process));
|
Thread thread = THREAD_FACTORY.newThread(createErrorStreamEcho(process));
|
||||||
thread.setDaemon(true);
|
|
||||||
thread.start();
|
thread.start();
|
||||||
|
|
||||||
String prefix = "from console: ";
|
String prefix = "from console: ";
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
java -jar console/rusefi_console.jar dfu $1
|
|
@ -2,7 +2,7 @@
|
||||||
<property name="jar_file_folder" value="../java_console_binary"/>
|
<property name="jar_file_folder" value="../java_console_binary"/>
|
||||||
<property name="jar_file" value="${jar_file_folder}/rusefi_console.jar"/>
|
<property name="jar_file" value="${jar_file_folder}/rusefi_console.jar"/>
|
||||||
<property name="server_jar_file" value="${jar_file_folder}/rusefi_server.jar"/>
|
<property name="server_jar_file" value="${jar_file_folder}/rusefi_server.jar"/>
|
||||||
<property name="lib_list" value="../java_tools/configuration_definition/lib/snakeyaml.jar:lib/json-simple-1.1.1.jar:lib/server/javax.json.jar:lib/server/cactoos.jar:lib/server/takes.jar:lib/json-simple-1.1.1.jar:lib/jaxb-api.jar:lib/httpclient.jar:lib/httpmime.jar:lib/httpcore.jar:lib/jSerialComm.jar:lib/jcip-annotations-1.0.jar:lib/jlatexmath-1.0.6.jar:lib/swing-layout-1.0.jar:lib/jep.jar:lib/log4j.jar:lib/junit.jar:lib/SteelSeries-3.9.30.jar:lib/annotations.jar:lib/miglayout-4.0.jar:lib/surfaceplotter-2.0.1.jar"/>
|
<property name="lib_list" value="../java_tools/configuration_definition/lib/snakeyaml.jar:lib/log4j-api-2.13.3.jar:lib/log4j-core-2.13.3.jar:lib/jsr305-2.0.1.jar:lib/dfu/dfu_java.jar:lib/dfu/IntelHexParser.jar:lib/json-simple-1.1.1.jar:lib/server/javax.json.jar:lib/server/cactoos.jar:lib/server/takes.jar:lib/json-simple-1.1.1.jar:lib/jaxb-api.jar:lib/httpclient.jar:lib/httpmime.jar:lib/httpcore.jar:lib/jSerialComm.jar:lib/jcip-annotations-1.0.jar:lib/jlatexmath-1.0.6.jar:lib/swing-layout-1.0.jar:lib/jep.jar:lib/log4j.jar:lib/junit.jar:lib/SteelSeries-3.9.30.jar:lib/annotations.jar:lib/miglayout-4.0.jar:lib/surfaceplotter-2.0.1.jar"/>
|
||||||
|
|
||||||
<target name="clean">
|
<target name="clean">
|
||||||
<delete dir="build"/>
|
<delete dir="build"/>
|
||||||
|
@ -56,7 +56,7 @@
|
||||||
<src path="inifile/src/test/java"/>
|
<src path="inifile/src/test/java"/>
|
||||||
<src path="shared_ui/src"/>
|
<src path="shared_ui/src"/>
|
||||||
<src path="shared_io/src/main/java"/>
|
<src path="shared_io/src/main/java"/>
|
||||||
<src path="shared_io/src/test/java"/>
|
<!-- <src path="shared_io/src/test/java"/>-->
|
||||||
<src path="logging-api/src/main/java"/>
|
<src path="logging-api/src/main/java"/>
|
||||||
<src path="ui/src/main/java"/>
|
<src path="ui/src/main/java"/>
|
||||||
<src path="ui/src/test/java"/>
|
<src path="ui/src/test/java"/>
|
||||||
|
@ -102,7 +102,7 @@
|
||||||
|
|
||||||
<jar destfile="${server_jar_file}">
|
<jar destfile="${server_jar_file}">
|
||||||
<manifest>
|
<manifest>
|
||||||
<attribute name="Main-Class" value="com.rusefi.Launcher"/>
|
<attribute name="Main-Class" value="com.rusefi.server.BackendLauncher"/>
|
||||||
<attribute name="Built-Date" value="${TODAY}"/>
|
<attribute name="Built-Date" value="${TODAY}"/>
|
||||||
<attribute name="Signature-Vendor" value="rusEFI LLC"/>
|
<attribute name="Signature-Vendor" value="rusEFI LLC"/>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
@ -111,6 +111,9 @@
|
||||||
<zipfileset src="lib/server/cactoos.jar" includes="**/*.class"/>
|
<zipfileset src="lib/server/cactoos.jar" includes="**/*.class"/>
|
||||||
<zipfileset src="lib/server/javax.json.jar" includes="**/*.class"/>
|
<zipfileset src="lib/server/javax.json.jar" includes="**/*.class"/>
|
||||||
<zipfileset src="lib/server/takes.jar" includes="**/*.class"/>
|
<zipfileset src="lib/server/takes.jar" includes="**/*.class"/>
|
||||||
|
<zipfileset src="lib/log4j-api-2.13.3.jar"/>
|
||||||
|
<zipfileset src="lib/log4j-core-2.13.3.jar"/>
|
||||||
|
<fileset dir="../java_tools/proxy_server/src/main/resources" includes="**/*.*"/>
|
||||||
</jar>
|
</jar>
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
|
@ -148,6 +151,14 @@
|
||||||
<zipfileset src="lib/httpmime.jar" includes="**/*.class"/>
|
<zipfileset src="lib/httpmime.jar" includes="**/*.class"/>
|
||||||
<zipfileset src="lib/jaxb-api.jar" includes="**/*.class"/>
|
<zipfileset src="lib/jaxb-api.jar" includes="**/*.class"/>
|
||||||
<zipfileset src="lib/jSerialComm.jar" includes="**/*.class **/*.so **/*.dll **/*.jnilib"/>
|
<zipfileset src="lib/jSerialComm.jar" includes="**/*.class **/*.so **/*.dll **/*.jnilib"/>
|
||||||
|
<zipfileset src="lib/dfu/libusb4java-1.3.0-linux-aarch64.jar" includes="**/*.class **/*.so **/*.dll **/*.jnilib"/>
|
||||||
|
<zipfileset src="lib/dfu/libusb4java-1.3.0-linux-arm.jar" includes="**/*.class **/*.so **/*.dll **/*.jnilib"/>
|
||||||
|
<zipfileset src="lib/dfu/libusb4java-1.3.0-linux-x86.jar" includes="**/*.class **/*.so **/*.dll **/*.jnilib"/>
|
||||||
|
<zipfileset src="lib/dfu/libusb4java-1.3.0-linux-x86-64.jar" includes="**/*.class **/*.so **/*.dll **/*.jnilib"/>
|
||||||
|
<zipfileset src="lib/dfu/libusb4java-1.3.0-darwin-x86-64.jar" includes="**/*.class **/*.so **/*.dll **/*.jnilib"/>
|
||||||
|
<zipfileset src="lib/dfu/usb4java-1.3.0.jar" includes="**/*.class"/>
|
||||||
|
<zipfileset src="lib/dfu/IntelHexParser.jar" includes="**/*.class"/>
|
||||||
|
<zipfileset src="lib/dfu/dfu_java.jar" includes="**/*.class"/>
|
||||||
<zipfileset src="lib/annotations.jar" includes="**/*.class"/>
|
<zipfileset src="lib/annotations.jar" includes="**/*.class"/>
|
||||||
<zipfileset src="lib/miglayout-4.0.jar" includes="**/*.class"/>
|
<zipfileset src="lib/miglayout-4.0.jar" includes="**/*.class"/>
|
||||||
<zipfileset src="lib/surfaceplotter-2.0.1.jar" includes="**/*.class **/*.properties"/>
|
<zipfileset src="lib/surfaceplotter-2.0.1.jar" includes="**/*.class **/*.properties"/>
|
||||||
|
|
|
@ -12,6 +12,8 @@ public interface WriteStream {
|
||||||
*/
|
*/
|
||||||
void write(byte[] bytes) throws IOException;
|
void write(byte[] bytes) throws IOException;
|
||||||
|
|
||||||
|
void flush() throws IOException;
|
||||||
|
|
||||||
default void write(byte value) throws IOException {
|
default void write(byte value) throws IOException {
|
||||||
write(new byte[]{value});
|
write(new byte[]{value});
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,4 +2,9 @@ package com.rusefi;
|
||||||
|
|
||||||
public interface Listener<T> {
|
public interface Listener<T> {
|
||||||
void onResult(T parameter);
|
void onResult(T parameter);
|
||||||
|
|
||||||
|
static <T> Listener<T> empty() {
|
||||||
|
return parameter -> {
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,53 +0,0 @@
|
||||||
package com.rusefi;
|
|
||||||
|
|
||||||
import com.opensr5.Logger;
|
|
||||||
import com.rusefi.io.IoStream;
|
|
||||||
import com.rusefi.io.commands.HelloCommand;
|
|
||||||
import com.rusefi.io.tcp.BinaryProtocolProxy;
|
|
||||||
import com.rusefi.io.tcp.TcpIoStream;
|
|
||||||
import com.rusefi.server.ApplicationRequest;
|
|
||||||
import com.rusefi.server.rusEFISSLContext;
|
|
||||||
import com.rusefi.tools.online.HttpUtil;
|
|
||||||
import com.rusefi.tools.online.ProxyClient;
|
|
||||||
import org.apache.http.HttpResponse;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class LocalApplicationProxy {
|
|
||||||
public static final int SERVER_PORT_FOR_APPLICATIONS = 8002;
|
|
||||||
private final Logger logger;
|
|
||||||
private final ApplicationRequest applicationRequest;
|
|
||||||
|
|
||||||
public LocalApplicationProxy(Logger logger, ApplicationRequest applicationRequest) {
|
|
||||||
this.logger = logger;
|
|
||||||
this.applicationRequest = applicationRequest;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param serverPortForRemoteUsers port on which rusEFI proxy accepts authenticator connections
|
|
||||||
* @param applicationRequest remote session we want to connect to
|
|
||||||
* @param authenticatorPort local port we would bind for TunerStudio to connect to
|
|
||||||
* @param httpPort
|
|
||||||
*/
|
|
||||||
static void startAndRun(Logger logger, int serverPortForRemoteUsers, ApplicationRequest applicationRequest, int authenticatorPort, int httpPort) throws IOException {
|
|
||||||
HttpResponse httpResponse = HttpUtil.executeGet(ProxyClient.getHttpAddress(httpPort) + ProxyClient.VERSION_PATH);
|
|
||||||
String version = HttpUtil.getResponse(httpResponse);
|
|
||||||
logger.info("Version=" + version);
|
|
||||||
if (!version.contains(ProxyClient.BACKEND_VERSION))
|
|
||||||
throw new IOException("Unexpected backend version " + version + " while we want " + ProxyClient.BACKEND_VERSION);
|
|
||||||
|
|
||||||
IoStream authenticatorToProxyStream = new TcpIoStream("authenticatorToProxyStream ", logger, rusEFISSLContext.getSSLSocket(HttpUtil.RUSEFI_PROXY_HOSTNAME, serverPortForRemoteUsers));
|
|
||||||
LocalApplicationProxy localApplicationProxy = new LocalApplicationProxy(logger, applicationRequest);
|
|
||||||
localApplicationProxy.run(authenticatorToProxyStream);
|
|
||||||
|
|
||||||
BinaryProtocolProxy.createProxy(logger, authenticatorToProxyStream, authenticatorPort);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void run(IoStream authenticatorToProxyStream) throws IOException {
|
|
||||||
// right from connection push session authentication data
|
|
||||||
new HelloCommand(logger, applicationRequest.toJson()).handle(authenticatorToProxyStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void start(String[] strings) {
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -9,15 +9,23 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||||
public class NamedThreadFactory implements ThreadFactory {
|
public class NamedThreadFactory implements ThreadFactory {
|
||||||
private final AtomicInteger counter = new AtomicInteger();
|
private final AtomicInteger counter = new AtomicInteger();
|
||||||
private String name;
|
private String name;
|
||||||
|
private final boolean isDaemon;
|
||||||
|
|
||||||
public NamedThreadFactory(String name) {
|
public NamedThreadFactory(String name) {
|
||||||
this.name = name;
|
this(name, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public NamedThreadFactory(String name, boolean isDaemon) {
|
||||||
|
this.name = name;
|
||||||
|
this.isDaemon = isDaemon;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Thread newThread(@NotNull Runnable r) {
|
public Thread newThread(@NotNull Runnable r) {
|
||||||
Thread t = Executors.defaultThreadFactory().newThread(r);
|
Thread t = Executors.defaultThreadFactory().newThread(r);
|
||||||
t.setName(name + counter.incrementAndGet());
|
t.setName(name + counter.incrementAndGet());
|
||||||
|
t.setDaemon(isDaemon);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ package com.rusefi;
|
||||||
*/
|
*/
|
||||||
public interface Timeouts {
|
public interface Timeouts {
|
||||||
int SECOND = 1000;
|
int SECOND = 1000;
|
||||||
|
int MINUTE = 60 * SECOND;
|
||||||
int COMMAND_TIMEOUT_SEC = 10; // seconds
|
int COMMAND_TIMEOUT_SEC = 10; // seconds
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package com.rusefi.autodetect;
|
package com.rusefi.autodetect;
|
||||||
|
|
||||||
import com.rusefi.FileLog;
|
import com.devexperts.logging.Logging;
|
||||||
import com.rusefi.NamedThreadFactory;
|
import com.rusefi.NamedThreadFactory;
|
||||||
import com.rusefi.io.IoStream;
|
import com.rusefi.io.IoStream;
|
||||||
import com.rusefi.io.LinkManager;
|
import com.rusefi.io.LinkManager;
|
||||||
|
@ -19,24 +19,28 @@ import java.util.function.Function;
|
||||||
* Andrey Belomutskiy, (c) 2013-2020
|
* Andrey Belomutskiy, (c) 2013-2020
|
||||||
*/
|
*/
|
||||||
public class PortDetector {
|
public class PortDetector {
|
||||||
|
private final static Logging log = Logging.getLogging(PortDetector.class);
|
||||||
|
|
||||||
private static final NamedThreadFactory AUTO_DETECT_PORT = new NamedThreadFactory("AutoDetectPort");
|
private static final NamedThreadFactory AUTO_DETECT_PORT = new NamedThreadFactory("AutoDetectPort");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connect to all serial ports and find out which one respond first
|
* Connect to all serial ports and find out which one respond first
|
||||||
* @param callback
|
* @param callback
|
||||||
|
* @return port name on which rusEFI was detected or null if none
|
||||||
*/
|
*/
|
||||||
|
@Nullable
|
||||||
public static String autoDetectSerial(Function<IoStream, Void> callback) {
|
public static String autoDetectSerial(Function<IoStream, Void> callback) {
|
||||||
String[] serialPorts = getPortNames();
|
String[] serialPorts = getPortNames();
|
||||||
if (serialPorts.length == 0) {
|
if (serialPorts.length == 0) {
|
||||||
System.err.println("No serial ports detected");
|
log.error("No serial ports detected");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
FileLog.MAIN.logLine("Trying " + Arrays.toString(serialPorts));
|
log.info("Trying " + Arrays.toString(serialPorts));
|
||||||
List<Thread> serialFinder = new ArrayList<>();
|
List<Thread> serialFinder = new ArrayList<>();
|
||||||
CountDownLatch portFound = new CountDownLatch(1);
|
CountDownLatch portFound = new CountDownLatch(1);
|
||||||
AtomicReference<String> result = new AtomicReference<>();
|
AtomicReference<String> result = new AtomicReference<>();
|
||||||
for (String serialPort : serialPorts) {
|
for (String serialPort : serialPorts) {
|
||||||
Thread thread = AUTO_DETECT_PORT.newThread(new SerialAutoChecker(FileLog.LOGGER, serialPort, portFound, result, callback));
|
Thread thread = AUTO_DETECT_PORT.newThread(new SerialAutoChecker(serialPort, portFound, result, callback));
|
||||||
serialFinder.add(thread);
|
serialFinder.add(thread);
|
||||||
thread.start();
|
thread.start();
|
||||||
}
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
package com.rusefi.autodetect;
|
package com.rusefi.autodetect;
|
||||||
|
|
||||||
import com.opensr5.Logger;
|
import com.devexperts.logging.Logging;
|
||||||
import com.rusefi.FileLog;
|
|
||||||
import com.rusefi.binaryprotocol.BinaryProtocolCommands;
|
import com.rusefi.binaryprotocol.BinaryProtocolCommands;
|
||||||
import com.rusefi.binaryprotocol.IncomingDataBuffer;
|
import com.rusefi.binaryprotocol.IncomingDataBuffer;
|
||||||
import com.rusefi.config.generated.Fields;
|
import com.rusefi.config.generated.Fields;
|
||||||
|
@ -17,38 +16,36 @@ import java.util.function.Function;
|
||||||
import static com.rusefi.binaryprotocol.IoHelper.checkResponseCode;
|
import static com.rusefi.binaryprotocol.IoHelper.checkResponseCode;
|
||||||
|
|
||||||
public class SerialAutoChecker implements Runnable {
|
public class SerialAutoChecker implements Runnable {
|
||||||
private final Logger logger;
|
private final static Logging log = Logging.getLogging(SerialAutoChecker.class);
|
||||||
private final String serialPort;
|
private final String serialPort;
|
||||||
private final CountDownLatch portFound;
|
private final CountDownLatch portFound;
|
||||||
private final AtomicReference<String> result;
|
private final AtomicReference<String> result;
|
||||||
private final Function<IoStream, Void> callback;
|
private final Function<IoStream, Void> callback;
|
||||||
public static String SIGNATURE;
|
public static String SIGNATURE;
|
||||||
|
|
||||||
public SerialAutoChecker(Logger logger, String serialPort, CountDownLatch portFound, AtomicReference<String> result, Function<IoStream, Void> callback) {
|
public SerialAutoChecker(String serialPort, CountDownLatch portFound, AtomicReference<String> result, Function<IoStream, Void> callback) {
|
||||||
this.logger = logger;
|
|
||||||
this.serialPort = serialPort;
|
this.serialPort = serialPort;
|
||||||
this.portFound = portFound;
|
this.portFound = portFound;
|
||||||
this.result = result;
|
this.result = result;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SerialAutoChecker(Logger logger, String serialPort, CountDownLatch portFound, AtomicReference<String> result) {
|
public SerialAutoChecker(String serialPort, CountDownLatch portFound, AtomicReference<String> result) {
|
||||||
this(logger, serialPort, portFound, result, null);
|
this(serialPort, portFound, result, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
IoStream stream = SerialIoStreamJSerialComm.openPort(serialPort, logger);
|
IoStream stream = SerialIoStreamJSerialComm.openPort(serialPort);
|
||||||
Logger logger = FileLog.LOGGER;
|
|
||||||
IncomingDataBuffer incomingData = stream.getDataBuffer();
|
IncomingDataBuffer incomingData = stream.getDataBuffer();
|
||||||
try {
|
try {
|
||||||
HelloCommand.send(stream, logger);
|
HelloCommand.send(stream);
|
||||||
byte[] response = incomingData.getPacket(logger, "", false);
|
byte[] response = incomingData.getPacket("", false);
|
||||||
if (!checkResponseCode(response, BinaryProtocolCommands.RESPONSE_OK))
|
if (!checkResponseCode(response, BinaryProtocolCommands.RESPONSE_OK))
|
||||||
return;
|
return;
|
||||||
String signature = new String(response, 1, response.length - 1);
|
String signature = new String(response, 1, response.length - 1);
|
||||||
SIGNATURE = signature;
|
SIGNATURE = signature;
|
||||||
System.out.println("Got signature=" + signature + " from " + serialPort);
|
log.info("Got signature=" + signature + " from " + serialPort);
|
||||||
if (signature.startsWith(Fields.PROTOCOL_SIGNATURE_PREFIX)) {
|
if (signature.startsWith(Fields.PROTOCOL_SIGNATURE_PREFIX)) {
|
||||||
if (callback != null) {
|
if (callback != null) {
|
||||||
callback.apply(stream);
|
callback.apply(stream);
|
|
@ -1,15 +1,20 @@
|
||||||
package com.rusefi.binaryprotocol;
|
package com.rusefi.binaryprotocol;
|
||||||
|
|
||||||
|
import com.devexperts.logging.Logging;
|
||||||
import com.opensr5.ConfigurationImage;
|
import com.opensr5.ConfigurationImage;
|
||||||
import com.opensr5.Logger;
|
import com.opensr5.Logger;
|
||||||
import com.opensr5.io.ConfigurationImageFile;
|
import com.opensr5.io.ConfigurationImageFile;
|
||||||
import com.opensr5.io.DataListener;
|
import com.opensr5.io.DataListener;
|
||||||
import com.rusefi.ConfigurationImageDiff;
|
import com.rusefi.ConfigurationImageDiff;
|
||||||
|
import com.rusefi.NamedThreadFactory;
|
||||||
import com.rusefi.Timeouts;
|
import com.rusefi.Timeouts;
|
||||||
import com.rusefi.composite.CompositeEvent;
|
import com.rusefi.composite.CompositeEvent;
|
||||||
import com.rusefi.composite.CompositeParser;
|
import com.rusefi.composite.CompositeParser;
|
||||||
import com.rusefi.config.generated.Fields;
|
import com.rusefi.config.generated.Fields;
|
||||||
import com.rusefi.core.*;
|
import com.rusefi.core.MessagesCentral;
|
||||||
|
import com.rusefi.core.Pair;
|
||||||
|
import com.rusefi.core.Sensor;
|
||||||
|
import com.rusefi.core.SensorCentral;
|
||||||
import com.rusefi.io.*;
|
import com.rusefi.io.*;
|
||||||
import com.rusefi.io.commands.GetOutputsCommand;
|
import com.rusefi.io.commands.GetOutputsCommand;
|
||||||
import com.rusefi.stream.LogicdataStreamFile;
|
import com.rusefi.stream.LogicdataStreamFile;
|
||||||
|
@ -28,23 +33,23 @@ import java.nio.ByteOrder;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.Future;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.concurrent.TimeoutException;
|
|
||||||
|
|
||||||
|
import static com.devexperts.logging.Logging.getLogging;
|
||||||
import static com.rusefi.binaryprotocol.IoHelper.*;
|
import static com.rusefi.binaryprotocol.IoHelper.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This object represents logical state of physical connection.
|
* This object represents logical state of physical connection.
|
||||||
*
|
* <p>
|
||||||
* Instance is connected until we experience issues. Once we decide to close the connection there is no restart -
|
* Instance is connected until we experience issues. Once we decide to close the connection there is no restart -
|
||||||
* new instance of this class would need to be created once we establish a new physical connection.
|
* new instance of this class would need to be created once we establish a new physical connection.
|
||||||
*
|
* <p>
|
||||||
* Andrey Belomutskiy, (c) 2013-2020
|
* Andrey Belomutskiy, (c) 2013-2020
|
||||||
* 3/6/2015
|
* 3/6/2015
|
||||||
*/
|
*/
|
||||||
public class BinaryProtocol implements BinaryProtocolCommands {
|
public class BinaryProtocol implements BinaryProtocolCommands {
|
||||||
|
private static final Logging log = getLogging(BinaryProtocol.class);
|
||||||
|
private static final ThreadFactory THREAD_FACTORY = new NamedThreadFactory("text pull");
|
||||||
|
|
||||||
private static final String USE_PLAIN_PROTOCOL_PROPERTY = "protocol.plain";
|
private static final String USE_PLAIN_PROTOCOL_PROPERTY = "protocol.plain";
|
||||||
private static final String CONFIGURATION_RUSEFI_BINARY = "current_configuration.rusefi_binary";
|
private static final String CONFIGURATION_RUSEFI_BINARY = "current_configuration.rusefi_binary";
|
||||||
|
@ -57,7 +62,6 @@ public class BinaryProtocol implements BinaryProtocolCommands {
|
||||||
public static boolean PLAIN_PROTOCOL = Boolean.getBoolean(USE_PLAIN_PROTOCOL_PROPERTY);
|
public static boolean PLAIN_PROTOCOL = Boolean.getBoolean(USE_PLAIN_PROTOCOL_PROPERTY);
|
||||||
|
|
||||||
private final LinkManager linkManager;
|
private final LinkManager linkManager;
|
||||||
private final Logger logger;
|
|
||||||
private final IoStream stream;
|
private final IoStream stream;
|
||||||
private final IncomingDataBuffer incomingData;
|
private final IncomingDataBuffer incomingData;
|
||||||
private boolean isBurnPending;
|
private boolean isBurnPending;
|
||||||
|
@ -89,6 +93,8 @@ public class BinaryProtocol implements BinaryProtocolCommands {
|
||||||
return "HELLO";
|
return "HELLO";
|
||||||
case Fields.TS_READ_COMMAND:
|
case Fields.TS_READ_COMMAND:
|
||||||
return "READ";
|
return "READ";
|
||||||
|
case Fields.TS_GET_TEXT:
|
||||||
|
return "TS_GET_TEXT";
|
||||||
case Fields.TS_GET_FIRMWARE_VERSION:
|
case Fields.TS_GET_FIRMWARE_VERSION:
|
||||||
return "GET_FW_VERSION";
|
return "GET_FW_VERSION";
|
||||||
case Fields.TS_CHUNK_WRITE_COMMAND:
|
case Fields.TS_CHUNK_WRITE_COMMAND:
|
||||||
|
@ -96,7 +102,7 @@ public class BinaryProtocol implements BinaryProtocolCommands {
|
||||||
case Fields.TS_OUTPUT_COMMAND:
|
case Fields.TS_OUTPUT_COMMAND:
|
||||||
return "TS_OUTPUT_COMMAND";
|
return "TS_OUTPUT_COMMAND";
|
||||||
default:
|
default:
|
||||||
return "command " + (char) + command + "/" + command;
|
return "command " + (char) +command + "/" + command;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,15 +136,14 @@ public class BinaryProtocol implements BinaryProtocolCommands {
|
||||||
|
|
||||||
private final Thread hook = new Thread(() -> closeComposites(), "BinaryProtocol::hook");
|
private final Thread hook = new Thread(() -> closeComposites(), "BinaryProtocol::hook");
|
||||||
|
|
||||||
public BinaryProtocol(LinkManager linkManager, final Logger logger, IoStream stream, IncomingDataBuffer dataBuffer) {
|
public BinaryProtocol(LinkManager linkManager, IoStream stream, IncomingDataBuffer dataBuffer) {
|
||||||
this.linkManager = linkManager;
|
this.linkManager = linkManager;
|
||||||
this.logger = logger;
|
|
||||||
this.stream = stream;
|
this.stream = stream;
|
||||||
|
|
||||||
communicationLoggingListener = new CommunicationLoggingListener() {
|
communicationLoggingListener = new CommunicationLoggingListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onPortHolderMessage(Class clazz, String message) {
|
public void onPortHolderMessage(Class clazz, String message) {
|
||||||
MessagesCentral.getInstance().postMessage(logger, clazz, message);
|
MessagesCentral.getInstance().postMessage(clazz, message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -150,7 +155,7 @@ public class BinaryProtocol implements BinaryProtocolCommands {
|
||||||
needCompositeLogger = linkManager.getCompositeLogicEnabled();
|
needCompositeLogger = linkManager.getCompositeLogicEnabled();
|
||||||
lastLowRpmTime = System.currentTimeMillis();
|
lastLowRpmTime = System.currentTimeMillis();
|
||||||
} else if (System.currentTimeMillis() - lastLowRpmTime > HIGH_RPM_DELAY * Timeouts.SECOND) {
|
} else if (System.currentTimeMillis() - lastLowRpmTime > HIGH_RPM_DELAY * Timeouts.SECOND) {
|
||||||
logger.info("Time to turn off composite logging");
|
log.info("Time to turn off composite logging");
|
||||||
needCompositeLogger = false;
|
needCompositeLogger = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -175,7 +180,7 @@ public class BinaryProtocol implements BinaryProtocolCommands {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void doSend(final String command, boolean fireEvent) throws InterruptedException {
|
public void doSend(final String command, boolean fireEvent) throws InterruptedException {
|
||||||
logger.info("Sending [" + command + "]");
|
log.info("Sending [" + command + "]");
|
||||||
if (fireEvent && LinkManager.LOG_LEVEL.isDebugEnabled()) {
|
if (fireEvent && LinkManager.LOG_LEVEL.isDebugEnabled()) {
|
||||||
communicationLoggingListener.onPortHolderMessage(BinaryProtocol.class, "Sending [" + command + "]");
|
communicationLoggingListener.onPortHolderMessage(BinaryProtocol.class, "Sending [" + command + "]");
|
||||||
}
|
}
|
||||||
|
@ -197,7 +202,7 @@ public class BinaryProtocol implements BinaryProtocolCommands {
|
||||||
} catch (ExecutionException e) {
|
} catch (ExecutionException e) {
|
||||||
throw new IllegalStateException(e);
|
throw new IllegalStateException(e);
|
||||||
} catch (TimeoutException e) {
|
} catch (TimeoutException e) {
|
||||||
getLogger().error("timeout sending [" + command + "] giving up: " + e);
|
log.error("timeout sending [" + command + "] giving up: " + e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
@ -224,7 +229,7 @@ public class BinaryProtocol implements BinaryProtocolCommands {
|
||||||
|
|
||||||
private void startTextPullThread(final DataListener listener) {
|
private void startTextPullThread(final DataListener listener) {
|
||||||
if (!linkManager.COMMUNICATION_QUEUE.isEmpty()) {
|
if (!linkManager.COMMUNICATION_QUEUE.isEmpty()) {
|
||||||
System.out.println("Current queue: " + linkManager.COMMUNICATION_QUEUE.size());
|
log.info("Current queue: " + linkManager.COMMUNICATION_QUEUE.size());
|
||||||
}
|
}
|
||||||
Runnable textPull = new Runnable() {
|
Runnable textPull = new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -247,11 +252,10 @@ public class BinaryProtocol implements BinaryProtocolCommands {
|
||||||
}
|
}
|
||||||
sleep(Timeouts.TEXT_PULL_PERIOD);
|
sleep(Timeouts.TEXT_PULL_PERIOD);
|
||||||
}
|
}
|
||||||
logger.info("Stopping text pull");
|
log.info("Stopping text pull");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Thread tr = new Thread(textPull);
|
Thread tr = THREAD_FACTORY.newThread(textPull);
|
||||||
tr.setName("text pull");
|
|
||||||
tr.start();
|
tr.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,10 +279,6 @@ public class BinaryProtocol implements BinaryProtocolCommands {
|
||||||
compositeLogs.clear();
|
compositeLogs.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Logger getLogger() {
|
|
||||||
return logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void dropPending() {
|
private void dropPending() {
|
||||||
synchronized (ioLock) {
|
synchronized (ioLock) {
|
||||||
if (isClosed)
|
if (isClosed)
|
||||||
|
@ -315,7 +315,7 @@ public class BinaryProtocol implements BinaryProtocolCommands {
|
||||||
private byte[] receivePacket(String msg, boolean allowLongResponse) throws EOFException {
|
private byte[] receivePacket(String msg, boolean allowLongResponse) throws EOFException {
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
synchronized (ioLock) {
|
synchronized (ioLock) {
|
||||||
return incomingData.getPacket(logger, msg, allowLongResponse, start);
|
return incomingData.getPacket(msg, allowLongResponse, start);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -331,7 +331,7 @@ public class BinaryProtocol implements BinaryProtocolCommands {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setController(image);
|
setController(image);
|
||||||
logger.info("Got configuration from controller.");
|
log.info("Got configuration from controller.");
|
||||||
ConnectionStatusLogic.INSTANCE.setValue(ConnectionStatusValue.CONNECTED);
|
ConnectionStatusLogic.INSTANCE.setValue(ConnectionStatusValue.CONNECTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -343,7 +343,7 @@ public class BinaryProtocol implements BinaryProtocolCommands {
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
|
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
logger.info("Reading from controller...");
|
log.info("Reading from controller...");
|
||||||
|
|
||||||
while (offset < image.getSize() && (System.currentTimeMillis() - start < Timeouts.READ_IMAGE_TIMEOUT)) {
|
while (offset < image.getSize() && (System.currentTimeMillis() - start < Timeouts.READ_IMAGE_TIMEOUT)) {
|
||||||
if (isClosed)
|
if (isClosed)
|
||||||
|
@ -363,7 +363,7 @@ public class BinaryProtocol implements BinaryProtocolCommands {
|
||||||
if (!checkResponseCode(response, RESPONSE_OK) || response.length != requestSize + 1) {
|
if (!checkResponseCode(response, RESPONSE_OK) || response.length != requestSize + 1) {
|
||||||
String code = (response == null || response.length == 0) ? "empty" : "code " + response[0];
|
String code = (response == null || response.length == 0) ? "empty" : "code " + response[0];
|
||||||
String info = response == null ? "NO RESPONSE" : (code + " size " + response.length);
|
String info = response == null ? "NO RESPONSE" : (code + " size " + response.length);
|
||||||
logger.info("readImage: ERROR UNEXPECTED Something is wrong, retrying... " + info);
|
log.info("readImage: ERROR UNEXPECTED Something is wrong, retrying... " + info);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -396,7 +396,7 @@ public class BinaryProtocol implements BinaryProtocolCommands {
|
||||||
|
|
||||||
if (localCached != null) {
|
if (localCached != null) {
|
||||||
int crcOfLocallyCachedConfiguration = IoHelper.getCrc32(localCached.getContent());
|
int crcOfLocallyCachedConfiguration = IoHelper.getCrc32(localCached.getContent());
|
||||||
System.out.printf(CONFIGURATION_RUSEFI_BINARY + " Local cache CRC %x\n", crcOfLocallyCachedConfiguration);
|
log.info(String.format(CONFIGURATION_RUSEFI_BINARY + " Local cache CRC %x\n", crcOfLocallyCachedConfiguration));
|
||||||
|
|
||||||
byte packet[] = new byte[7];
|
byte packet[] = new byte[7];
|
||||||
packet[0] = COMMAND_CRC_CHECK_COMMAND;
|
packet[0] = COMMAND_CRC_CHECK_COMMAND;
|
||||||
|
@ -407,7 +407,7 @@ public class BinaryProtocol implements BinaryProtocolCommands {
|
||||||
// that's unusual - most of the protocol is LITTLE_ENDIAN
|
// that's unusual - most of the protocol is LITTLE_ENDIAN
|
||||||
bb.order(ByteOrder.BIG_ENDIAN);
|
bb.order(ByteOrder.BIG_ENDIAN);
|
||||||
int crcFromController = bb.getInt();
|
int crcFromController = bb.getInt();
|
||||||
System.out.printf("From rusEFI CRC %x\n", crcFromController);
|
log.info(String.format("From rusEFI CRC %x\n", crcFromController));
|
||||||
if (crcOfLocallyCachedConfiguration == crcFromController) {
|
if (crcOfLocallyCachedConfiguration == crcFromController) {
|
||||||
return localCached;
|
return localCached;
|
||||||
}
|
}
|
||||||
|
@ -435,7 +435,7 @@ public class BinaryProtocol implements BinaryProtocolCommands {
|
||||||
sendPacket(packet);
|
sendPacket(packet);
|
||||||
return receivePacket(msg, allowLongResponse);
|
return receivePacket(msg, allowLongResponse);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.error(msg + ": executeCommand failed: " + e);
|
log.error(msg + ": executeCommand failed: " + e);
|
||||||
close();
|
close();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -509,7 +509,7 @@ public class BinaryProtocol implements BinaryProtocolCommands {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendPacket(byte[] command) throws IOException {
|
private void sendPacket(byte[] command) throws IOException {
|
||||||
stream.sendPacket(command, logger);
|
stream.sendPacket(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -549,7 +549,7 @@ public class BinaryProtocol implements BinaryProtocolCommands {
|
||||||
Thread.sleep(100);
|
Thread.sleep(100);
|
||||||
return new String(response, 1, response.length - 1);
|
return new String(response, 1, response.length - 1);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
logger.error(e.toString());
|
log.error(e.toString());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package com.rusefi.binaryprotocol;
|
package com.rusefi.binaryprotocol;
|
||||||
|
|
||||||
import com.opensr5.Logger;
|
import com.devexperts.logging.Logging;
|
||||||
import com.rusefi.Timeouts;
|
import com.rusefi.Timeouts;
|
||||||
import com.rusefi.config.generated.Fields;
|
import com.rusefi.config.generated.Fields;
|
||||||
import com.rusefi.io.IoStream;
|
import com.rusefi.io.IoStream;
|
||||||
|
@ -13,6 +13,7 @@ import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static com.devexperts.logging.Logging.getLogging;
|
||||||
import static com.rusefi.binaryprotocol.IoHelper.*;
|
import static com.rusefi.binaryprotocol.IoHelper.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,39 +24,44 @@ import static com.rusefi.binaryprotocol.IoHelper.*;
|
||||||
*/
|
*/
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
public class IncomingDataBuffer {
|
public class IncomingDataBuffer {
|
||||||
|
private static final Logging log = getLogging(IoStream.class);
|
||||||
|
|
||||||
private static final int BUFFER_SIZE = 32768;
|
private static final int BUFFER_SIZE = 32768;
|
||||||
private static String loggingPrefix;
|
private static String loggingPrefix;
|
||||||
/**
|
/**
|
||||||
* buffer for response bytes from controller
|
* buffer for response bytes from controller
|
||||||
*/
|
*/
|
||||||
private final CircularByteBuffer cbb;
|
private final CircularByteBuffer cbb;
|
||||||
private final Logger logger;
|
|
||||||
private final AbstractIoStream.StreamStats streamStats;
|
private final AbstractIoStream.StreamStats streamStats;
|
||||||
|
|
||||||
public IncomingDataBuffer(Logger logger, AbstractIoStream.StreamStats streamStats) {
|
public IncomingDataBuffer(AbstractIoStream.StreamStats streamStats) {
|
||||||
this.streamStats = Objects.requireNonNull(streamStats, "streamStats");
|
this.streamStats = Objects.requireNonNull(streamStats, "streamStats");
|
||||||
this.cbb = new CircularByteBuffer(BUFFER_SIZE);
|
this.cbb = new CircularByteBuffer(BUFFER_SIZE);
|
||||||
this.logger = logger;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IncomingDataBuffer createDataBuffer(String loggingPrefix, IoStream stream, Logger logger) {
|
public static IncomingDataBuffer createDataBuffer(String loggingPrefix, IoStream stream) {
|
||||||
IncomingDataBuffer.loggingPrefix = loggingPrefix;
|
IncomingDataBuffer.loggingPrefix = loggingPrefix;
|
||||||
IncomingDataBuffer incomingData = new IncomingDataBuffer(logger, stream.getStreamStats());
|
IncomingDataBuffer incomingData = new IncomingDataBuffer(stream.getStreamStats());
|
||||||
stream.setInputListener(incomingData::addData);
|
stream.setInputListener(incomingData::addData);
|
||||||
return incomingData;
|
return incomingData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getPacket(Logger logger, String msg, boolean allowLongResponse) throws EOFException {
|
public byte[] getPacket(String msg, boolean allowLongResponse) throws EOFException {
|
||||||
return getPacket(logger, msg, allowLongResponse, System.currentTimeMillis());
|
return getPacket(msg, allowLongResponse, System.currentTimeMillis());
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getPacket(Logger logger, String msg, boolean allowLongResponse, long start) throws EOFException {
|
/**
|
||||||
|
* why does this method return NULL in case of timeout?!
|
||||||
|
* todo: there is a very similar BinaryProtocolServer#readPromisedBytes which throws exception in case of timeout
|
||||||
|
*/
|
||||||
|
public byte[] getPacket(String msg, boolean allowLongResponse, long start) throws EOFException {
|
||||||
boolean isTimeout = waitForBytes(msg + " header", start, 2);
|
boolean isTimeout = waitForBytes(msg + " header", start, 2);
|
||||||
if (isTimeout)
|
if (isTimeout)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
int packetSize = swap16(getShort());
|
int packetSize = swap16(getShort());
|
||||||
logger.trace( loggingPrefix + "Got packet size " + packetSize);
|
if (log.debugEnabled())
|
||||||
|
log.debug(loggingPrefix + "Got packet size " + packetSize);
|
||||||
if (packetSize < 0)
|
if (packetSize < 0)
|
||||||
return null;
|
return null;
|
||||||
if (!allowLongResponse && packetSize > Math.max(BinaryProtocolCommands.BLOCKING_FACTOR, Fields.TS_OUTPUT_SIZE) + 10)
|
if (!allowLongResponse && packetSize > Math.max(BinaryProtocolCommands.BLOCKING_FACTOR, Fields.TS_OUTPUT_SIZE) + 10)
|
||||||
|
@ -72,20 +78,26 @@ public class IncomingDataBuffer {
|
||||||
|
|
||||||
boolean isCrcOk = actualCrc == packetCrc;
|
boolean isCrcOk = actualCrc == packetCrc;
|
||||||
if (!isCrcOk) {
|
if (!isCrcOk) {
|
||||||
logger.trace(String.format("%x", actualCrc) + " vs " + String.format("%x", packetCrc));
|
if (log.debugEnabled())
|
||||||
|
log.debug(String.format("%x", actualCrc) + " vs " + String.format("%x", packetCrc));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
streamStats.onPacketArrived();
|
onPacketArrived();
|
||||||
logger.trace("packet " + Arrays.toString(packet) + ": crc OK");
|
if (log.debugEnabled())
|
||||||
|
log.debug("packet " + Arrays.toString(packet) + ": crc OK");
|
||||||
|
|
||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onPacketArrived() {
|
||||||
|
streamStats.onPacketArrived();
|
||||||
|
}
|
||||||
|
|
||||||
public void addData(byte[] freshData) {
|
public void addData(byte[] freshData) {
|
||||||
logger.info("IncomingDataBuffer: " + freshData.length + " byte(s) arrived");
|
log.info("IncomingDataBuffer: " + freshData.length + " byte(s) arrived");
|
||||||
synchronized (cbb) {
|
synchronized (cbb) {
|
||||||
if (cbb.size() - cbb.length() < freshData.length) {
|
if (cbb.size() - cbb.length() < freshData.length) {
|
||||||
logger.error("IncomingDataBuffer: buffer overflow not expected");
|
log.error("IncomingDataBuffer: buffer overflow not expected");
|
||||||
cbb.clear();
|
cbb.clear();
|
||||||
}
|
}
|
||||||
cbb.put(freshData);
|
cbb.put(freshData);
|
||||||
|
@ -102,19 +114,22 @@ public class IncomingDataBuffer {
|
||||||
return waitForBytes(Timeouts.BINARY_IO_TIMEOUT, loggingMessage, startTimestamp, count);
|
return waitForBytes(Timeouts.BINARY_IO_TIMEOUT, loggingMessage, startTimestamp, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true in case of timeout, false if we have received count of bytes
|
||||||
|
*/
|
||||||
public boolean waitForBytes(int timeoutMs, String loggingMessage, long startTimestamp, int count) {
|
public boolean waitForBytes(int timeoutMs, String loggingMessage, long startTimestamp, int count) {
|
||||||
logger.info(loggingMessage + ": waiting for " + count + " byte(s)");
|
log.info(loggingMessage + ": waiting for " + count + " byte(s)");
|
||||||
synchronized (cbb) {
|
synchronized (cbb) {
|
||||||
while (cbb.length() < count) {
|
while (cbb.length() < count) {
|
||||||
int timeout = (int) (startTimestamp + timeoutMs - System.currentTimeMillis());
|
int timeout = (int) (startTimestamp + timeoutMs - System.currentTimeMillis());
|
||||||
if (timeout <= 0) {
|
if (timeout <= 0) {
|
||||||
logger.info(loggingMessage + ": timeout. Got only " + cbb.length());
|
log.info(loggingMessage + ": timeout. Got only " + cbb.length());
|
||||||
return true; // timeout. Sad face.
|
return true; // timeout. Sad face.
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
cbb.wait(timeout);
|
cbb.wait(timeout);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
throw new IllegalStateException(e);
|
return true; // thread thrown away, handling like a timeout
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,10 +141,10 @@ public class IncomingDataBuffer {
|
||||||
synchronized (cbb) {
|
synchronized (cbb) {
|
||||||
int pending = cbb.length();
|
int pending = cbb.length();
|
||||||
if (pending > 0) {
|
if (pending > 0) {
|
||||||
logger.error("dropPending: Unexpected pending data: " + pending + " byte(s)");
|
log.error("dropPending: Unexpected pending data: " + pending + " byte(s)");
|
||||||
byte[] bytes = new byte[pending];
|
byte[] bytes = new byte[pending];
|
||||||
cbb.get(bytes);
|
cbb.get(bytes);
|
||||||
logger.error("data: " + Arrays.toString(bytes));
|
log.error("data: " + Arrays.toString(bytes));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -163,31 +178,30 @@ public class IncomingDataBuffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte readByte(int timeoutMs) throws IOException {
|
public byte readByte(int timeoutMs) throws IOException {
|
||||||
boolean isTimeout = waitForBytes(timeoutMs,loggingPrefix + "readByte", System.currentTimeMillis(), 1);
|
boolean isTimeout = waitForBytes(timeoutMs, loggingPrefix + "readByte", System.currentTimeMillis(), 1);
|
||||||
if (isTimeout)
|
if (isTimeout)
|
||||||
throw new IOException("Timeout in readByte");
|
throw new EOFException("Timeout in readByte " + timeoutMs);
|
||||||
return (byte) getByte();
|
return (byte) getByte();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int readInt() throws EOFException {
|
public int readInt() throws EOFException {
|
||||||
boolean isTimeout = waitForBytes(loggingPrefix + "readInt", System.currentTimeMillis(), 4);
|
boolean isTimeout = waitForBytes(loggingPrefix + "readInt", System.currentTimeMillis(), 4);
|
||||||
if (isTimeout)
|
if (isTimeout)
|
||||||
throw new IllegalStateException("Timeout in readByte");
|
throw new EOFException("Timeout in readInt ");
|
||||||
return swap32(getInt());
|
return swap32(getInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
public short readShort() throws EOFException {
|
public short readShort() throws EOFException {
|
||||||
boolean isTimeout = waitForBytes(loggingPrefix + "readShort", System.currentTimeMillis(), 2);
|
boolean isTimeout = waitForBytes(loggingPrefix + "readShort", System.currentTimeMillis(), 2);
|
||||||
if (isTimeout)
|
if (isTimeout)
|
||||||
throw new IllegalStateException("Timeout in readShort");
|
throw new EOFException("Timeout in readShort");
|
||||||
return (short) swap16(getShort());
|
return (short) swap16(getShort());
|
||||||
}
|
}
|
||||||
|
|
||||||
public int read(byte[] packet) {
|
public void read(byte[] packet) throws EOFException {
|
||||||
boolean isTimeout = waitForBytes(loggingPrefix + "read", System.currentTimeMillis(), packet.length);
|
boolean isTimeout = waitForBytes(loggingPrefix + "read", System.currentTimeMillis(), packet.length);
|
||||||
if (isTimeout)
|
if (isTimeout)
|
||||||
throw new IllegalStateException("Timeout while waiting " + packet.length);
|
throw new EOFException("Timeout while waiting " + packet.length);
|
||||||
getData(packet);
|
getData(packet);
|
||||||
return packet.length;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package com.rusefi.file;
|
package com.rusefi.file;
|
||||||
|
|
||||||
import com.opensr5.Logger;
|
|
||||||
import com.rusefi.core.EngineState;
|
import com.rusefi.core.EngineState;
|
||||||
import com.rusefi.io.LinkManager;
|
import com.rusefi.io.LinkManager;
|
||||||
|
|
||||||
|
@ -12,8 +11,8 @@ import java.util.List;
|
||||||
* Andrey Belomutskiy, (c) 2013-2020
|
* Andrey Belomutskiy, (c) 2013-2020
|
||||||
*/
|
*/
|
||||||
public class FileUtils {
|
public class FileUtils {
|
||||||
public static void readFile(String filename, EngineState.EngineStateListener listener, Logger logger) {
|
public static void readFile(String filename, EngineState.EngineStateListener listener) {
|
||||||
readFile2(filename, new EngineState(listener, logger));
|
readFile2(filename, new EngineState(listener));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void readFile2(String filename, EngineState engineState) {
|
public static void readFile2(String filename, EngineState engineState) {
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
package com.rusefi.io;
|
||||||
|
|
||||||
|
public class AbstractConnectionStateListener implements ConnectionStateListener {
|
||||||
|
@Override
|
||||||
|
public void onConnectionEstablished() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onConnectionFailed() {
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,39 +1,42 @@
|
||||||
package com.rusefi.io;
|
package com.rusefi.io;
|
||||||
|
|
||||||
import com.opensr5.Logger;
|
import com.devexperts.logging.Logging;
|
||||||
import com.opensr5.io.DataListener;
|
import com.opensr5.io.DataListener;
|
||||||
|
import com.rusefi.config.generated.Fields;
|
||||||
|
import com.rusefi.io.serial.AbstractIoStream;
|
||||||
|
import com.rusefi.io.tcp.BinaryProtocolServer;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
import static com.devexperts.logging.Logging.getLogging;
|
||||||
|
|
||||||
public interface ByteReader {
|
public interface ByteReader {
|
||||||
static void runReaderLoop(String loggingPrefix, DataListener listener, ByteReader reader, Logger logger) {
|
Logging log = getLogging(ByteReader.class);
|
||||||
|
|
||||||
|
static void runReaderLoop(String loggingPrefix, DataListener listener, ByteReader reader, AbstractIoStream ioStream) {
|
||||||
/**
|
/**
|
||||||
* Threading of the whole input/output does not look healthy at all!
|
* Threading of the whole input/output does not look healthy at all!
|
||||||
*
|
*
|
||||||
* @see #COMMUNICATION_EXECUTOR
|
* @see #COMMUNICATION_EXECUTOR
|
||||||
*/
|
*/
|
||||||
Executor threadExecutor = Executors.newSingleThreadExecutor(r -> {
|
Executor threadExecutor = Executors.newSingleThreadExecutor(BinaryProtocolServer.getThreadFactory(loggingPrefix + "TCP reader"));
|
||||||
Thread t = new Thread(r, "IO executor thread");
|
|
||||||
t.setDaemon(true); // need daemon thread so that COM thread is also daemon
|
|
||||||
return t;
|
|
||||||
});
|
|
||||||
|
|
||||||
threadExecutor.execute(() -> {
|
threadExecutor.execute(() -> {
|
||||||
Thread.currentThread().setName("TCP connector loop");
|
log.info(loggingPrefix + "Running TCP connection loop");
|
||||||
logger.info(loggingPrefix + "Running TCP connection loop");
|
|
||||||
|
|
||||||
byte inputBuffer[] = new byte[256];
|
byte inputBuffer[] = new byte[Fields.BLOCKING_FACTOR * 2];
|
||||||
while (true) {
|
while (!ioStream.isClosed()) {
|
||||||
try {
|
try {
|
||||||
int result = reader.read(inputBuffer);
|
int result = reader.read(inputBuffer);
|
||||||
if (result == -1)
|
if (result == -1)
|
||||||
throw new IOException("TcpIoStream: End of input?");
|
throw new IOException("TcpIoStream: End of input?");
|
||||||
listener.onDataArrived(Arrays.copyOf(inputBuffer, result));
|
listener.onDataArrived(Arrays.copyOf(inputBuffer, result));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
System.err.println("TcpIoStream: End of connection");
|
log.error("TcpIoStream: End of connection " + e);
|
||||||
|
ioStream.close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package com.rusefi.io;
|
package com.rusefi.io;
|
||||||
|
|
||||||
import com.opensr5.Logger;
|
import com.devexperts.logging.Logging;
|
||||||
import com.rusefi.config.generated.Fields;
|
import com.rusefi.config.generated.Fields;
|
||||||
import com.rusefi.core.MessagesCentral;
|
import com.rusefi.core.MessagesCentral;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
@ -9,6 +9,8 @@ import java.util.*;
|
||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
|
||||||
|
import static com.devexperts.logging.Logging.getLogging;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This singleton keeps re-sending commands till a proper confirmation is received
|
* This singleton keeps re-sending commands till a proper confirmation is received
|
||||||
*
|
*
|
||||||
|
@ -18,6 +20,7 @@ import java.util.concurrent.LinkedBlockingQueue;
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("FieldCanBeLocal")
|
@SuppressWarnings("FieldCanBeLocal")
|
||||||
public class CommandQueue {
|
public class CommandQueue {
|
||||||
|
private static final Logging log = getLogging(LinkManager.class);
|
||||||
public static final String CONFIRMATION_PREFIX = "confirmation_";
|
public static final String CONFIRMATION_PREFIX = "confirmation_";
|
||||||
public static final int DEFAULT_TIMEOUT = 500;
|
public static final int DEFAULT_TIMEOUT = 500;
|
||||||
private static final int COMMAND_CONFIRMATION_TIMEOUT = 1000;
|
private static final int COMMAND_CONFIRMATION_TIMEOUT = 1000;
|
||||||
|
@ -36,7 +39,6 @@ public class CommandQueue {
|
||||||
private final List<CommandQueueListener> commandListeners = new ArrayList<>();
|
private final List<CommandQueueListener> commandListeners = new ArrayList<>();
|
||||||
|
|
||||||
private final Runnable runnable;
|
private final Runnable runnable;
|
||||||
private final Logger logger;
|
|
||||||
|
|
||||||
private static boolean isSlowCommand(String cmd) {
|
private static boolean isSlowCommand(String cmd) {
|
||||||
String lc = cmd.toLowerCase();
|
String lc = cmd.toLowerCase();
|
||||||
|
@ -98,27 +100,26 @@ public class CommandQueue {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (counter != 1)
|
if (counter != 1)
|
||||||
MessagesCentral.getInstance().postMessage(logger, CommandQueue.class, "Took " + counter + " attempts");
|
MessagesCentral.getInstance().postMessage(CommandQueue.class, "Took " + counter + " attempts");
|
||||||
}
|
}
|
||||||
|
|
||||||
public CommandQueue(LinkManager linkManager, Logger logger) {
|
public CommandQueue(LinkManager linkManager) {
|
||||||
this.linkManager = linkManager;
|
this.linkManager = linkManager;
|
||||||
runnable = new Runnable() {
|
runnable = new Runnable() {
|
||||||
@SuppressWarnings("InfiniteLoopStatement")
|
@SuppressWarnings("InfiniteLoopStatement")
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
MessagesCentral.getInstance().postMessage(logger, COMMAND_QUEUE_CLASS, "SerialIO started");
|
MessagesCentral.getInstance().postMessage(COMMAND_QUEUE_CLASS, "SerialIO started");
|
||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
sendPendingCommand();
|
sendPendingCommand();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
logger.error("CommandQueue error" + e);
|
log.error("CommandQueue error" + e);
|
||||||
System.exit(-2);
|
System.exit(-2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
this.logger = logger;
|
|
||||||
Thread thread = new Thread(runnable, "Commands Queue");
|
Thread thread = new Thread(runnable, "Commands Queue");
|
||||||
thread.setDaemon(true);
|
thread.setDaemon(true);
|
||||||
thread.start();
|
thread.start();
|
||||||
|
@ -136,10 +137,10 @@ public class CommandQueue {
|
||||||
MessagesCentral mc = MessagesCentral.getInstance();
|
MessagesCentral mc = MessagesCentral.getInstance();
|
||||||
String confirmation = LinkManager.unpackConfirmation(message);
|
String confirmation = LinkManager.unpackConfirmation(message);
|
||||||
if (confirmation == null)
|
if (confirmation == null)
|
||||||
mc.postMessage(logger, CommandQueue.class, "Broken confirmation length: " + message);
|
mc.postMessage(CommandQueue.class, "Broken confirmation length: " + message);
|
||||||
pendingConfirmations.add(confirmation);
|
pendingConfirmations.add(confirmation);
|
||||||
if (LinkManager.LOG_LEVEL.isDebugEnabled())
|
if (LinkManager.LOG_LEVEL.isDebugEnabled())
|
||||||
mc.postMessage(logger, CommandQueue.class, "got valid conf! " + confirmation + ", still pending: " + pendingCommands.size());
|
mc.postMessage(CommandQueue.class, "got valid conf! " + confirmation + ", still pending: " + pendingCommands.size());
|
||||||
|
|
||||||
// FileLog.MAIN.logLine("templog got valid conf " + confirmation + " " + System.currentTimeMillis() + " " + new Date());
|
// FileLog.MAIN.logLine("templog got valid conf " + confirmation + " " + System.currentTimeMillis() + " " + new Date());
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
package com.rusefi.io;
|
||||||
|
|
||||||
|
public interface ConnectionFailedListener {
|
||||||
|
void onConnectionFailed();
|
||||||
|
}
|
|
@ -4,21 +4,11 @@ package com.rusefi.io;
|
||||||
* @author Andrey Belomutskiy
|
* @author Andrey Belomutskiy
|
||||||
* 3/1/2017
|
* 3/1/2017
|
||||||
*/
|
*/
|
||||||
public interface ConnectionStateListener {
|
public interface ConnectionStateListener extends ConnectionFailedListener {
|
||||||
ConnectionStateListener VOID = new ConnectionStateListener() {
|
ConnectionStateListener VOID = new AbstractConnectionStateListener();
|
||||||
@Override
|
|
||||||
public void onConnectionEstablished() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onConnectionFailed() {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is invoked once we have connection & configuration from controller
|
* This method is invoked once we have connection & configuration from controller
|
||||||
*/
|
*/
|
||||||
void onConnectionEstablished();
|
void onConnectionEstablished();
|
||||||
|
|
||||||
void onConnectionFailed();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,15 @@
|
||||||
package com.rusefi.io;
|
package com.rusefi.io;
|
||||||
|
|
||||||
import com.opensr5.Logger;
|
|
||||||
import com.rusefi.binaryprotocol.BinaryProtocol;
|
import com.rusefi.binaryprotocol.BinaryProtocol;
|
||||||
import com.rusefi.config.generated.Fields;
|
import com.rusefi.config.generated.Fields;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public class DfuHelper {
|
public class DfuHelper {
|
||||||
public static void sendDfuRebootCommand(IoStream stream, StringBuilder messages, Logger logger) {
|
public static void sendDfuRebootCommand(IoStream stream, StringBuilder messages) {
|
||||||
byte[] command = BinaryProtocol.getTextCommandBytes(Fields.CMD_REBOOT_DFU);
|
byte[] command = BinaryProtocol.getTextCommandBytes(Fields.CMD_REBOOT_DFU);
|
||||||
try {
|
try {
|
||||||
stream.sendPacket(command, logger);
|
stream.sendPacket(command);
|
||||||
stream.close();
|
stream.close();
|
||||||
messages.append("Reboot command sent!\n");
|
messages.append("Reboot command sent!\n");
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package com.rusefi.io;
|
package com.rusefi.io;
|
||||||
|
|
||||||
import com.opensr5.Logger;
|
import com.devexperts.logging.Logging;
|
||||||
import com.opensr5.io.DataListener;
|
import com.opensr5.io.DataListener;
|
||||||
import com.opensr5.io.WriteStream;
|
import com.opensr5.io.WriteStream;
|
||||||
import com.rusefi.binaryprotocol.BinaryProtocol;
|
import com.rusefi.binaryprotocol.BinaryProtocol;
|
||||||
|
@ -10,9 +10,12 @@ import com.rusefi.io.serial.AbstractIoStream;
|
||||||
import com.rusefi.io.tcp.BinaryProtocolServer;
|
import com.rusefi.io.tcp.BinaryProtocolServer;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
import java.io.EOFException;
|
import java.io.EOFException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import static com.devexperts.logging.Logging.getLogging;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Physical bi-directional controller communication level
|
* Physical bi-directional controller communication level
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -20,7 +23,8 @@ import java.io.IOException;
|
||||||
* <p>
|
* <p>
|
||||||
* 5/11/2015.
|
* 5/11/2015.
|
||||||
*/
|
*/
|
||||||
public interface IoStream extends WriteStream {
|
public interface IoStream extends WriteStream, Closeable {
|
||||||
|
Logging log = getLogging(IoStream.class);
|
||||||
|
|
||||||
static String printHexBinary(byte[] data) {
|
static String printHexBinary(byte[] data) {
|
||||||
char[] hexCode = "0123456789ABCDEF".toCharArray();
|
char[] hexCode = "0123456789ABCDEF".toCharArray();
|
||||||
|
@ -44,9 +48,10 @@ public interface IoStream extends WriteStream {
|
||||||
writeShort(packet.getPacket().length);
|
writeShort(packet.getPacket().length);
|
||||||
write(packet.getPacket());
|
write(packet.getPacket());
|
||||||
writeInt(packet.getCrc());
|
writeInt(packet.getCrc());
|
||||||
|
flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
default void sendPacket(byte[] plainPacket, Logger logger) throws IOException {
|
default void sendPacket(byte[] plainPacket) throws IOException {
|
||||||
byte[] packet;
|
byte[] packet;
|
||||||
if (BinaryProtocol.PLAIN_PROTOCOL) {
|
if (BinaryProtocol.PLAIN_PROTOCOL) {
|
||||||
packet = plainPacket;
|
packet = plainPacket;
|
||||||
|
@ -54,8 +59,9 @@ public interface IoStream extends WriteStream {
|
||||||
packet = IoHelper.makeCrc32Packet(plainPacket);
|
packet = IoHelper.makeCrc32Packet(plainPacket);
|
||||||
}
|
}
|
||||||
// todo: verbose mode printHexBinary(plainPacket))
|
// todo: verbose mode printHexBinary(plainPacket))
|
||||||
logger.info(getLoggingPrefix() + "Sending packet " + BinaryProtocol.findCommand(plainPacket[0]) + " length=" + plainPacket.length);
|
log.debug(getLoggingPrefix() + "Sending packet " + BinaryProtocol.findCommand(plainPacket[0]) + " length=" + plainPacket.length);
|
||||||
write(packet);
|
write(packet);
|
||||||
|
flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package com.rusefi.io;
|
package com.rusefi.io;
|
||||||
|
|
||||||
|
import com.devexperts.logging.Logging;
|
||||||
import com.fazecast.jSerialComm.SerialPort;
|
import com.fazecast.jSerialComm.SerialPort;
|
||||||
import com.opensr5.Logger;
|
|
||||||
import com.rusefi.Callable;
|
import com.rusefi.Callable;
|
||||||
import com.rusefi.NamedThreadFactory;
|
import com.rusefi.NamedThreadFactory;
|
||||||
import com.rusefi.binaryprotocol.BinaryProtocol;
|
import com.rusefi.binaryprotocol.BinaryProtocol;
|
||||||
|
@ -19,6 +19,8 @@ import java.util.Arrays;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
|
import static com.devexperts.logging.Logging.getLogging;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See TcpCommunicationIntegrationTest
|
* See TcpCommunicationIntegrationTest
|
||||||
*
|
*
|
||||||
|
@ -26,6 +28,8 @@ import java.util.concurrent.*;
|
||||||
* 3/3/14
|
* 3/3/14
|
||||||
*/
|
*/
|
||||||
public class LinkManager implements Closeable {
|
public class LinkManager implements Closeable {
|
||||||
|
private static final Logging log = getLogging(LinkManager.class);
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static LogLevel LOG_LEVEL = LogLevel.INFO;
|
public static LogLevel LOG_LEVEL = LogLevel.INFO;
|
||||||
|
|
||||||
|
@ -38,23 +42,21 @@ public class LinkManager implements Closeable {
|
||||||
|
|
||||||
public static final String LOG_VIEWER = "log viewer";
|
public static final String LOG_VIEWER = "log viewer";
|
||||||
private final CommandQueue commandQueue;
|
private final CommandQueue commandQueue;
|
||||||
private final Logger logger;
|
|
||||||
|
|
||||||
private LinkConnector connector;
|
private LinkConnector connector;
|
||||||
private boolean isStarted;
|
private boolean isStarted;
|
||||||
private boolean compositeLogicEnabled = true;
|
private boolean compositeLogicEnabled = true;
|
||||||
private boolean needPullData = true;
|
private boolean needPullData = true;
|
||||||
|
|
||||||
public LinkManager(Logger logger) {
|
public LinkManager() {
|
||||||
this.logger = logger;
|
|
||||||
engineState = new EngineState(new EngineState.EngineStateListenerImpl() {
|
engineState = new EngineState(new EngineState.EngineStateListenerImpl() {
|
||||||
@Override
|
@Override
|
||||||
public void beforeLine(String fullLine) {
|
public void beforeLine(String fullLine) {
|
||||||
logger.info(fullLine);
|
log.info(fullLine);
|
||||||
HeartBeatListeners.onDataArrived();
|
HeartBeatListeners.onDataArrived();
|
||||||
}
|
}
|
||||||
}, logger);
|
});
|
||||||
commandQueue = new CommandQueue(this, logger);
|
commandQueue = new CommandQueue(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
@ -194,9 +196,9 @@ public class LinkManager implements Closeable {
|
||||||
return connector;
|
return connector;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void start(String port, ConnectionStateListener stateListener) {
|
public void start(String port, ConnectionFailedListener stateListener) {
|
||||||
Objects.requireNonNull(port, "port");
|
Objects.requireNonNull(port, "port");
|
||||||
logger.info("LinkManager: Starting " + port);
|
log.info("LinkManager: Starting " + port);
|
||||||
if (isLogViewerMode(port)) {
|
if (isLogViewerMode(port)) {
|
||||||
setConnector(LinkConnector.VOID);
|
setConnector(LinkConnector.VOID);
|
||||||
} else if (TcpConnector.isTcpPort(port)) {
|
} else if (TcpConnector.isTcpPort(port)) {
|
||||||
|
@ -208,7 +210,7 @@ public class LinkManager implements Closeable {
|
||||||
int portPart = TcpConnector.getTcpPort(port);
|
int portPart = TcpConnector.getTcpPort(port);
|
||||||
String hostname = TcpConnector.getHostname(port);
|
String hostname = TcpConnector.getHostname(port);
|
||||||
socket = new Socket(hostname, portPart);
|
socket = new Socket(hostname, portPart);
|
||||||
TcpIoStream tcpIoStream = new TcpIoStream("[start] ", logger, socket);
|
TcpIoStream tcpIoStream = new TcpIoStream("[start] ", socket);
|
||||||
|
|
||||||
return tcpIoStream;
|
return tcpIoStream;
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
|
@ -218,13 +220,13 @@ public class LinkManager implements Closeable {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
setConnector(new StreamConnector(this, port, logger, streamFactory));
|
setConnector(new StreamConnector(this, port, streamFactory));
|
||||||
isSimulationMode = true;
|
isSimulationMode = true;
|
||||||
} else {
|
} else {
|
||||||
Callable<IoStream> ioStreamCallable = new Callable<IoStream>() {
|
Callable<IoStream> ioStreamCallable = new Callable<IoStream>() {
|
||||||
@Override
|
@Override
|
||||||
public IoStream call() {
|
public IoStream call() {
|
||||||
IoStream stream = ((Callable<IoStream>) () -> SerialIoStreamJSerialComm.openPort(port, logger)).call();
|
IoStream stream = ((Callable<IoStream>) () -> SerialIoStreamJSerialComm.openPort(port)).call();
|
||||||
if (stream == null) {
|
if (stream == null) {
|
||||||
// error already reported
|
// error already reported
|
||||||
return null;
|
return null;
|
||||||
|
@ -232,7 +234,7 @@ public class LinkManager implements Closeable {
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
setConnector(new StreamConnector(this, port, logger, ioStreamCallable));
|
setConnector(new StreamConnector(this, port, ioStreamCallable));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
package com.rusefi.io.commands;
|
package com.rusefi.io.commands;
|
||||||
|
|
||||||
import com.rusefi.config.generated.Fields;
|
import com.rusefi.config.generated.Fields;
|
||||||
|
import com.rusefi.io.IoStream;
|
||||||
|
import com.rusefi.io.tcp.BinaryProtocolServer;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
import static com.rusefi.binaryprotocol.IoHelper.putShort;
|
import static com.rusefi.binaryprotocol.IoHelper.putShort;
|
||||||
import static com.rusefi.binaryprotocol.IoHelper.swap16;
|
import static com.rusefi.binaryprotocol.IoHelper.swap16;
|
||||||
|
@ -13,4 +17,10 @@ public class GetOutputsCommand {
|
||||||
putShort(packet, 3, swap16(Fields.TS_OUTPUT_SIZE));
|
putShort(packet, 3, swap16(Fields.TS_OUTPUT_SIZE));
|
||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void sendOutput(IoStream stream) throws IOException {
|
||||||
|
byte[] response = new byte[1 + Fields.TS_OUTPUT_SIZE];
|
||||||
|
response[0] = (byte) BinaryProtocolServer.TS_OK.charAt(0);
|
||||||
|
stream.sendPacket(response);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package com.rusefi.io.commands;
|
package com.rusefi.io.commands;
|
||||||
|
|
||||||
import com.opensr5.Logger;
|
|
||||||
import com.rusefi.binaryprotocol.BinaryProtocolCommands;
|
import com.rusefi.binaryprotocol.BinaryProtocolCommands;
|
||||||
import com.rusefi.binaryprotocol.IncomingDataBuffer;
|
import com.rusefi.binaryprotocol.IncomingDataBuffer;
|
||||||
import com.rusefi.config.generated.Fields;
|
import com.rusefi.config.generated.Fields;
|
||||||
|
@ -14,21 +13,19 @@ import java.io.IOException;
|
||||||
import static com.rusefi.binaryprotocol.IoHelper.checkResponseCode;
|
import static com.rusefi.binaryprotocol.IoHelper.checkResponseCode;
|
||||||
|
|
||||||
public class HelloCommand implements Command {
|
public class HelloCommand implements Command {
|
||||||
private final Logger logger;
|
|
||||||
private final String tsSignature;
|
private final String tsSignature;
|
||||||
|
|
||||||
public HelloCommand(Logger logger, String tsSignature) {
|
public HelloCommand(String tsSignature) {
|
||||||
this.logger = logger;
|
|
||||||
this.tsSignature = tsSignature;
|
this.tsSignature = tsSignature;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void send(IoStream stream, Logger logger) throws IOException {
|
public static void send(IoStream stream) throws IOException {
|
||||||
stream.sendPacket(new byte[]{Fields.TS_HELLO_COMMAND}, logger);
|
stream.sendPacket(new byte[]{Fields.TS_HELLO_COMMAND});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static String getHelloResponse(IncomingDataBuffer incomingData, Logger logger) throws EOFException {
|
public static String getHelloResponse(IncomingDataBuffer incomingData) throws EOFException {
|
||||||
byte[] response = incomingData.getPacket(logger, "[hello]", false);
|
byte[] response = incomingData.getPacket("[hello]", false);
|
||||||
if (!checkResponseCode(response, BinaryProtocolCommands.RESPONSE_OK))
|
if (!checkResponseCode(response, BinaryProtocolCommands.RESPONSE_OK))
|
||||||
return null;
|
return null;
|
||||||
return new String(response, 1, response.length - 1);
|
return new String(response, 1, response.length - 1);
|
||||||
|
@ -41,6 +38,6 @@ public class HelloCommand implements Command {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(IoStream stream) throws IOException {
|
public void handle(IoStream stream) throws IOException {
|
||||||
stream.sendPacket((BinaryProtocolServer.TS_OK + tsSignature).getBytes(), logger);
|
stream.sendPacket((BinaryProtocolServer.TS_OK + tsSignature).getBytes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@ package com.rusefi.io.serial;
|
||||||
|
|
||||||
import com.rusefi.io.IoStream;
|
import com.rusefi.io.IoStream;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
public abstract class AbstractIoStream implements IoStream {
|
public abstract class AbstractIoStream implements IoStream {
|
||||||
private boolean isClosed;
|
private boolean isClosed;
|
||||||
|
|
||||||
|
@ -17,6 +19,10 @@ public abstract class AbstractIoStream implements IoStream {
|
||||||
isClosed = true;
|
isClosed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void flush() throws IOException {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isClosed() {
|
public boolean isClosed() {
|
||||||
return isClosed;
|
return isClosed;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package com.rusefi.io.serial;
|
package com.rusefi.io.serial;
|
||||||
|
|
||||||
import com.opensr5.Logger;
|
import com.devexperts.logging.Logging;
|
||||||
import com.rusefi.Callable;
|
import com.rusefi.Callable;
|
||||||
import com.rusefi.binaryprotocol.BinaryProtocol;
|
import com.rusefi.binaryprotocol.BinaryProtocol;
|
||||||
import com.rusefi.core.MessagesCentral;
|
import com.rusefi.core.MessagesCentral;
|
||||||
|
@ -13,6 +13,8 @@ import org.jetbrains.annotations.Nullable;
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
|
||||||
|
import static com.devexperts.logging.Logging.getLogging;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class holds the reference to the actual Serial port object
|
* This class holds the reference to the actual Serial port object
|
||||||
* <p/>
|
* <p/>
|
||||||
|
@ -20,8 +22,9 @@ import java.awt.*;
|
||||||
* Andrey Belomutskiy, (c) 2013-2020
|
* Andrey Belomutskiy, (c) 2013-2020
|
||||||
*/
|
*/
|
||||||
public class PortHolder {
|
public class PortHolder {
|
||||||
|
private static final Logging log = getLogging(PortHolder.class);
|
||||||
|
|
||||||
private final DataListener dataListener;
|
private final DataListener dataListener;
|
||||||
private final Logger logger;
|
|
||||||
private final Callable<IoStream> ioStreamCallable;
|
private final Callable<IoStream> ioStreamCallable;
|
||||||
private final LinkManager linkManager;
|
private final LinkManager linkManager;
|
||||||
|
|
||||||
|
@ -32,11 +35,10 @@ public class PortHolder {
|
||||||
@Nullable
|
@Nullable
|
||||||
private BinaryProtocol bp;
|
private BinaryProtocol bp;
|
||||||
|
|
||||||
protected PortHolder(String port, LinkManager linkManager, Logger logger, Callable<IoStream> ioStreamCallable) {
|
protected PortHolder(String port, LinkManager linkManager, Callable<IoStream> ioStreamCallable) {
|
||||||
this.port = port;
|
this.port = port;
|
||||||
this.linkManager = linkManager;
|
this.linkManager = linkManager;
|
||||||
dataListener = freshData -> linkManager.getEngineState().processNewData(new String(freshData), LinkManager.ENCODER);
|
dataListener = freshData -> linkManager.getEngineState().processNewData(new String(freshData), LinkManager.ENCODER);
|
||||||
this.logger = logger;
|
|
||||||
this.ioStreamCallable = ioStreamCallable;
|
this.ioStreamCallable = ioStreamCallable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +46,7 @@ public class PortHolder {
|
||||||
if (port == null)
|
if (port == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
MessagesCentral.getInstance().postMessage(logger, getClass(), "Opening port: " + port);
|
MessagesCentral.getInstance().postMessage(getClass(), "Opening port: " + port);
|
||||||
|
|
||||||
IoStream stream = ioStreamCallable.call();
|
IoStream stream = ioStreamCallable.call();
|
||||||
if (stream == null) {
|
if (stream == null) {
|
||||||
|
@ -52,7 +54,7 @@ public class PortHolder {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
synchronized (portLock) {
|
synchronized (portLock) {
|
||||||
bp = new BinaryProtocol(linkManager, logger, stream, stream.getDataBuffer());
|
bp = new BinaryProtocol(linkManager, stream, stream.getDataBuffer());
|
||||||
portLock.notifyAll();
|
portLock.notifyAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
package com.rusefi.io.serial;
|
package com.rusefi.io.serial;
|
||||||
|
|
||||||
|
import com.devexperts.logging.Logging;
|
||||||
import com.fazecast.jSerialComm.SerialPort;
|
import com.fazecast.jSerialComm.SerialPort;
|
||||||
import com.fazecast.jSerialComm.SerialPortDataListener;
|
import com.fazecast.jSerialComm.SerialPortDataListener;
|
||||||
import com.fazecast.jSerialComm.SerialPortEvent;
|
import com.fazecast.jSerialComm.SerialPortEvent;
|
||||||
import com.opensr5.Logger;
|
|
||||||
import com.opensr5.io.DataListener;
|
import com.opensr5.io.DataListener;
|
||||||
import com.rusefi.binaryprotocol.IncomingDataBuffer;
|
import com.rusefi.binaryprotocol.IncomingDataBuffer;
|
||||||
import com.rusefi.io.IoStream;
|
import com.rusefi.io.IoStream;
|
||||||
|
|
||||||
|
import static com.devexperts.logging.Logging.getLogging;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* https://github.com/Fazecast/jSerialComm looks to be alive as of 2020
|
* https://github.com/Fazecast/jSerialComm looks to be alive as of 2020
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -15,19 +17,18 @@ import com.rusefi.io.IoStream;
|
||||||
* 06/03/2019
|
* 06/03/2019
|
||||||
*/
|
*/
|
||||||
public class SerialIoStreamJSerialComm extends AbstractIoStream {
|
public class SerialIoStreamJSerialComm extends AbstractIoStream {
|
||||||
|
private static final Logging log = getLogging(SerialIoStreamJSerialComm.class);
|
||||||
private SerialPort sp;
|
private SerialPort sp;
|
||||||
private final String port;
|
private final String port;
|
||||||
private final Logger logger;
|
|
||||||
private final IncomingDataBuffer dataBuffer;
|
private final IncomingDataBuffer dataBuffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see #openPort(String, Logger)
|
* @see #openPort(String)
|
||||||
*/
|
*/
|
||||||
private SerialIoStreamJSerialComm(SerialPort sp, String port, Logger logger) {
|
private SerialIoStreamJSerialComm(SerialPort sp, String port) {
|
||||||
this.sp = sp;
|
this.sp = sp;
|
||||||
this.port = port;
|
this.port = port;
|
||||||
this.logger = logger;
|
this.dataBuffer = IncomingDataBuffer.createDataBuffer("[serial] ", this);
|
||||||
this.dataBuffer = IncomingDataBuffer.createDataBuffer("[serial] ", this, logger);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -38,6 +39,8 @@ public class SerialIoStreamJSerialComm extends AbstractIoStream {
|
||||||
@Override
|
@Override
|
||||||
public void setInputListener(DataListener listener) {
|
public void setInputListener(DataListener listener) {
|
||||||
sp.addDataListener(new SerialPortDataListener() {
|
sp.addDataListener(new SerialPortDataListener() {
|
||||||
|
private boolean isFirstEvent = true;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getListeningEvents() {
|
public int getListeningEvents() {
|
||||||
return SerialPort.LISTENING_EVENT_DATA_AVAILABLE;
|
return SerialPort.LISTENING_EVENT_DATA_AVAILABLE;
|
||||||
|
@ -47,6 +50,11 @@ public class SerialIoStreamJSerialComm extends AbstractIoStream {
|
||||||
public void serialEvent(SerialPortEvent event) {
|
public void serialEvent(SerialPortEvent event) {
|
||||||
if (event.getEventType() != SerialPort.LISTENING_EVENT_DATA_AVAILABLE)
|
if (event.getEventType() != SerialPort.LISTENING_EVENT_DATA_AVAILABLE)
|
||||||
return;
|
return;
|
||||||
|
if (isFirstEvent) {
|
||||||
|
// a hack to have explicit thread name, see https://github.com/Fazecast/jSerialComm/issues/308
|
||||||
|
Thread.currentThread().setName("Serial Port Event Thread");
|
||||||
|
isFirstEvent = false;
|
||||||
|
}
|
||||||
int bytesAvailable = sp.bytesAvailable();
|
int bytesAvailable = sp.bytesAvailable();
|
||||||
if (bytesAvailable <= 0)
|
if (bytesAvailable <= 0)
|
||||||
return; // sometimes negative value is returned at least on Mac
|
return; // sometimes negative value is returned at least on Mac
|
||||||
|
@ -68,10 +76,10 @@ public class SerialIoStreamJSerialComm extends AbstractIoStream {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
logger.info(port + ": Closing port...");
|
log.info(port + ": Closing port...");
|
||||||
super.close();
|
super.close();
|
||||||
sp.closePort();
|
sp.closePort();
|
||||||
logger.info(port + ": Closed port.");
|
log.info(port + ": Closed port.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -83,12 +91,12 @@ public class SerialIoStreamJSerialComm extends AbstractIoStream {
|
||||||
* Just open physical serial and not much more
|
* Just open physical serial and not much more
|
||||||
* @see PortHolder#connectAndReadConfiguration()
|
* @see PortHolder#connectAndReadConfiguration()
|
||||||
*/
|
*/
|
||||||
public static IoStream openPort(String port, Logger logger) {
|
public static IoStream openPort(String port) {
|
||||||
logger.info("[SerialIoStreamJSerialComm] openPort " + port);
|
log.info("[SerialIoStreamJSerialComm] openPort " + port);
|
||||||
SerialPort serialPort = SerialPort.getCommPort(port);
|
SerialPort serialPort = SerialPort.getCommPort(port);
|
||||||
serialPort.setBaudRate(BaudRateHolder.INSTANCE.baudRate);
|
serialPort.setBaudRate(BaudRateHolder.INSTANCE.baudRate);
|
||||||
serialPort.openPort(0);
|
serialPort.openPort(0);
|
||||||
// FileLog.LOGGER.info("[SerialIoStreamJSerialComm] opened " + port);
|
// FileLog.LOGGER.info("[SerialIoStreamJSerialComm] opened " + port);
|
||||||
return new SerialIoStreamJSerialComm(serialPort, port, logger);
|
return new SerialIoStreamJSerialComm(serialPort, port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package com.rusefi.io.serial;
|
package com.rusefi.io.serial;
|
||||||
|
|
||||||
import com.opensr5.Logger;
|
import com.devexperts.logging.Logging;
|
||||||
import com.rusefi.Callable;
|
import com.rusefi.Callable;
|
||||||
import com.rusefi.binaryprotocol.BinaryProtocol;
|
import com.rusefi.binaryprotocol.BinaryProtocol;
|
||||||
import com.rusefi.core.MessagesCentral;
|
import com.rusefi.core.MessagesCentral;
|
||||||
|
@ -9,34 +9,32 @@ import com.rusefi.io.IoStream;
|
||||||
import com.rusefi.io.LinkConnector;
|
import com.rusefi.io.LinkConnector;
|
||||||
import com.rusefi.io.LinkManager;
|
import com.rusefi.io.LinkManager;
|
||||||
|
|
||||||
|
import static com.devexperts.logging.Logging.getLogging;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Andrey Belomutskiy
|
* @author Andrey Belomutskiy
|
||||||
* 3/3/14
|
* 3/3/14
|
||||||
*/
|
*/
|
||||||
public class StreamConnector implements LinkConnector {
|
public class StreamConnector implements LinkConnector {
|
||||||
|
private static final Logging log = getLogging(StreamConnector.class);
|
||||||
|
|
||||||
private final PortHolder portHolder;
|
private final PortHolder portHolder;
|
||||||
private final Logger logger;
|
|
||||||
private final LinkManager linkManager;
|
private final LinkManager linkManager;
|
||||||
|
|
||||||
public StreamConnector(LinkManager linkManager, String portName, Logger logger, Callable<IoStream> ioStreamCallable) {
|
public StreamConnector(LinkManager linkManager, String portName, Callable<IoStream> ioStreamCallable) {
|
||||||
this.linkManager = linkManager;
|
this.linkManager = linkManager;
|
||||||
this.logger = logger;
|
|
||||||
|
|
||||||
portHolder = new PortHolder(portName, linkManager, logger, ioStreamCallable);
|
portHolder = new PortHolder(portName, linkManager, ioStreamCallable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void connectAndReadConfiguration(ConnectionStateListener listener) {
|
public void connectAndReadConfiguration(ConnectionStateListener listener) {
|
||||||
logger.info("StreamConnector: connecting");
|
log.info("StreamConnector: connecting");
|
||||||
portHolder.listener = listener;
|
portHolder.listener = listener;
|
||||||
logger.info("scheduleOpening");
|
log.info("scheduleOpening");
|
||||||
linkManager.execute(new Runnable() {
|
linkManager.execute(() -> {
|
||||||
@Override
|
log.info("scheduleOpening>openPort");
|
||||||
public void run() {
|
portHolder.connectAndReadConfiguration();
|
||||||
logger.info("scheduleOpening>openPort");
|
|
||||||
portHolder.connectAndReadConfiguration();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,13 +50,10 @@ public class StreamConnector implements LinkConnector {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void restart() {
|
public void restart() {
|
||||||
linkManager.execute(new Runnable() {
|
linkManager.execute(() -> {
|
||||||
@Override
|
MessagesCentral.getInstance().postMessage(StreamConnector.this.getClass(), "Restarting serial IO");
|
||||||
public void run() {
|
portHolder.close();
|
||||||
MessagesCentral.getInstance().postMessage(logger, StreamConnector.this.getClass(), "Restarting serial IO");
|
portHolder.connectAndReadConfiguration();
|
||||||
portHolder.close();
|
|
||||||
portHolder.connectAndReadConfiguration();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,73 +1,90 @@
|
||||||
package com.rusefi.io.tcp;
|
package com.rusefi.io.tcp;
|
||||||
|
|
||||||
import com.opensr5.Logger;
|
import com.devexperts.logging.Logging;
|
||||||
|
import com.rusefi.Listener;
|
||||||
|
import com.rusefi.Timeouts;
|
||||||
import com.rusefi.binaryprotocol.BinaryProtocol;
|
import com.rusefi.binaryprotocol.BinaryProtocol;
|
||||||
import com.rusefi.binaryprotocol.IncomingDataBuffer;
|
import com.rusefi.binaryprotocol.IncomingDataBuffer;
|
||||||
import com.rusefi.io.IoStream;
|
import com.rusefi.io.IoStream;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import static com.devexperts.logging.Logging.getLogging;
|
||||||
import static com.rusefi.binaryprotocol.BinaryProtocolCommands.COMMAND_PROTOCOL;
|
import static com.rusefi.binaryprotocol.BinaryProtocolCommands.COMMAND_PROTOCOL;
|
||||||
import static com.rusefi.config.generated.Fields.TS_PROTOCOL;
|
import static com.rusefi.config.generated.Fields.TS_PROTOCOL;
|
||||||
|
import static com.rusefi.shared.FileUtil.close;
|
||||||
|
|
||||||
public class BinaryProtocolProxy {
|
public class BinaryProtocolProxy {
|
||||||
public static void createProxy(Logger logger, IoStream targetEcuSocket, int serverProxyPort) {
|
private static final Logging log = getLogging(BinaryProtocolProxy.class);
|
||||||
Function<Socket, Runnable> clientSocketRunnableFactory = new Function<Socket, Runnable>() {
|
/**
|
||||||
@Override
|
* we expect server to at least request output channels once in a while
|
||||||
public Runnable apply(Socket clientSocket) {
|
* it could be a while between user connecting authenticator and actually connecting application to authenticator
|
||||||
return new Runnable() {
|
* See Backend#APPLICATION_INACTIVITY_TIMEOUT
|
||||||
@Override
|
*/
|
||||||
public void run() {
|
public static final int USER_IO_TIMEOUT = 10 * Timeouts.MINUTE;
|
||||||
try {
|
|
||||||
TcpIoStream clientStream = new TcpIoStream("[[proxy]] ", logger, clientSocket);
|
public static ServerSocketReference createProxy(IoStream targetEcuSocket, int serverProxyPort, AtomicInteger relayCommandCounter) throws IOException {
|
||||||
runProxy(targetEcuSocket, clientStream);
|
Function<Socket, Runnable> clientSocketRunnableFactory = clientSocket -> () -> {
|
||||||
} catch (IOException e) {
|
TcpIoStream clientStream = null;
|
||||||
logger.error("BinaryProtocolProxy::run" + e);
|
try {
|
||||||
}
|
clientStream = new TcpIoStream("[[proxy]] ", clientSocket);
|
||||||
}
|
runProxy(targetEcuSocket, clientStream, relayCommandCounter);
|
||||||
};
|
} catch (IOException e) {
|
||||||
|
log.error("BinaryProtocolProxy::run " + e);
|
||||||
|
close(clientStream);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
BinaryProtocolServer.tcpServerSocket(serverProxyPort, "proxy", clientSocketRunnableFactory, Logger.CONSOLE, null);
|
return BinaryProtocolServer.tcpServerSocket(serverProxyPort, "proxy", clientSocketRunnableFactory, Listener.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void runProxy(IoStream targetEcu, IoStream clientStream) throws IOException {
|
public static void runProxy(IoStream targetEcu, IoStream clientStream, AtomicInteger relayCommandCounter) throws IOException {
|
||||||
/*
|
/*
|
||||||
* Each client socket is running on it's own thread
|
* Each client socket is running on it's own thread
|
||||||
*/
|
*/
|
||||||
while (true) {
|
while (!targetEcu.isClosed()) {
|
||||||
byte firstByte = clientStream.getDataBuffer().readByte();
|
byte firstByte = clientStream.getDataBuffer().readByte(USER_IO_TIMEOUT);
|
||||||
if (firstByte == COMMAND_PROTOCOL) {
|
if (firstByte == COMMAND_PROTOCOL) {
|
||||||
clientStream.write(TS_PROTOCOL.getBytes());
|
clientStream.write(TS_PROTOCOL.getBytes());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
proxyClientRequestToController(clientStream.getDataBuffer(), firstByte, targetEcu);
|
BinaryProtocolServer.Packet clientRequest = readClientRequest(clientStream.getDataBuffer(), firstByte);
|
||||||
|
|
||||||
proxyControllerResponseToClient(targetEcu, clientStream);
|
/**
|
||||||
|
* Two reasons for synchronization:
|
||||||
|
* - we run gauge poking thread until TunerStudio connects
|
||||||
|
* - technically there could be two parallel connections to local application port
|
||||||
|
*/
|
||||||
|
BinaryProtocolServer.Packet controllerResponse;
|
||||||
|
synchronized (targetEcu) {
|
||||||
|
sendToTarget(targetEcu, clientRequest);
|
||||||
|
controllerResponse = targetEcu.readPacket();
|
||||||
|
relayCommandCounter.incrementAndGet();
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("Relaying controller response length=" + controllerResponse.getPacket().length);
|
||||||
|
clientStream.sendPacket(controllerResponse);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void proxyControllerResponseToClient(IoStream targetInputStream, IoStream clientOutputStream) throws IOException {
|
@NotNull
|
||||||
BinaryProtocolServer.Packet packet = targetInputStream.readPacket();
|
private static BinaryProtocolServer.Packet readClientRequest(IncomingDataBuffer in, byte firstByte) throws IOException {
|
||||||
|
|
||||||
System.out.println("Relaying controller response length=" + packet.getPacket().length);
|
|
||||||
clientOutputStream.sendPacket(packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void proxyClientRequestToController(IncomingDataBuffer in, byte firstByte, IoStream targetOutputStream) throws IOException {
|
|
||||||
byte secondByte = in.readByte();
|
byte secondByte = in.readByte();
|
||||||
int length = firstByte * 256 + secondByte;
|
int length = firstByte * 256 + secondByte;
|
||||||
|
|
||||||
BinaryProtocolServer.Packet packet = BinaryProtocolServer.readPromisedBytes(in, length);
|
return BinaryProtocolServer.readPromisedBytes(in, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void sendToTarget(IoStream targetOutputStream, BinaryProtocolServer.Packet packet) throws IOException {
|
||||||
DataInputStream dis = new DataInputStream(new ByteArrayInputStream(packet.getPacket()));
|
DataInputStream dis = new DataInputStream(new ByteArrayInputStream(packet.getPacket()));
|
||||||
byte command = (byte) dis.read();
|
byte command = (byte) dis.read();
|
||||||
|
|
||||||
System.out.println("Relaying client command " + BinaryProtocol.findCommand(command));
|
log.info("Relaying client command " + BinaryProtocol.findCommand(command));
|
||||||
// sending proxied packet to controller
|
// sending proxied packet to controller
|
||||||
targetOutputStream.sendPacket(packet);
|
targetOutputStream.sendPacket(packet);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
package com.rusefi.io.tcp;
|
package com.rusefi.io.tcp;
|
||||||
|
|
||||||
|
import com.devexperts.logging.Logging;
|
||||||
import com.opensr5.ConfigurationImage;
|
import com.opensr5.ConfigurationImage;
|
||||||
import com.opensr5.Logger;
|
|
||||||
import com.rusefi.Listener;
|
import com.rusefi.Listener;
|
||||||
|
import com.rusefi.NamedThreadFactory;
|
||||||
import com.rusefi.Timeouts;
|
import com.rusefi.Timeouts;
|
||||||
import com.rusefi.binaryprotocol.*;
|
import com.rusefi.binaryprotocol.*;
|
||||||
import com.rusefi.config.generated.Fields;
|
import com.rusefi.config.generated.Fields;
|
||||||
|
@ -10,15 +11,19 @@ import com.rusefi.io.IoStream;
|
||||||
import com.rusefi.io.LinkManager;
|
import com.rusefi.io.LinkManager;
|
||||||
import com.rusefi.io.commands.HelloCommand;
|
import com.rusefi.io.commands.HelloCommand;
|
||||||
import com.rusefi.server.rusEFISSLContext;
|
import com.rusefi.server.rusEFISSLContext;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ThreadFactory;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import static com.devexperts.logging.Logging.getLogging;
|
||||||
import static com.rusefi.binaryprotocol.IoHelper.swap16;
|
import static com.rusefi.binaryprotocol.IoHelper.swap16;
|
||||||
import static com.rusefi.config.generated.Fields.TS_PROTOCOL;
|
import static com.rusefi.config.generated.Fields.TS_PROTOCOL;
|
||||||
import static com.rusefi.config.generated.Fields.TS_RESPONSE_BURN_OK;
|
import static com.rusefi.config.generated.Fields.TS_RESPONSE_BURN_OK;
|
||||||
|
@ -32,45 +37,42 @@ import static com.rusefi.config.generated.Fields.TS_RESPONSE_BURN_OK;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class BinaryProtocolServer implements BinaryProtocolCommands {
|
public class BinaryProtocolServer implements BinaryProtocolCommands {
|
||||||
|
private static final Logging log = getLogging(BinaryProtocolServer.class);
|
||||||
private static final int DEFAULT_PROXY_PORT = 2390;
|
private static final int DEFAULT_PROXY_PORT = 2390;
|
||||||
public static final String TS_OK = "\0";
|
public static final String TS_OK = "\0";
|
||||||
private final Logger logger;
|
|
||||||
|
|
||||||
public AtomicInteger unknownCommands = new AtomicInteger();
|
public AtomicInteger unknownCommands = new AtomicInteger();
|
||||||
|
|
||||||
public static final Function<Integer, ServerSocket> SECURE_SOCKET_FACTORY = rusEFISSLContext::getSSLServerSocket;
|
public static final ServerSocketFunction SECURE_SOCKET_FACTORY = rusEFISSLContext::getSSLServerSocket;
|
||||||
|
|
||||||
public static final Function<Integer, ServerSocket> PLAIN_SOCKET_FACTORY = port -> {
|
public static final ServerSocketFunction PLAIN_SOCKET_FACTORY = port -> {
|
||||||
try {
|
ServerSocket serverSocket = new ServerSocket(port);
|
||||||
ServerSocket serverSocket = new ServerSocket(port);
|
log.info("ServerSocket " + port + " created");
|
||||||
Logger.CONSOLE.info("ServerSocket " + port + " created");
|
return serverSocket;
|
||||||
return serverSocket;
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new IllegalStateException("Error binding server socket " + port, e);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private static ConcurrentHashMap<String, ThreadFactory> THREAD_FACTORIES_BY_NAME = new ConcurrentHashMap<>();
|
||||||
public BinaryProtocolServer(Logger logger) {
|
|
||||||
this.logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void start(LinkManager linkManager) {
|
public void start(LinkManager linkManager) {
|
||||||
start(linkManager, DEFAULT_PROXY_PORT, null);
|
try {
|
||||||
|
start(linkManager, DEFAULT_PROXY_PORT, Listener.empty(), new Context());
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Error starting local proxy", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void start(LinkManager linkManager, int port, Listener serverSocketCreationCallback) {
|
public void start(LinkManager linkManager, int port, Listener serverSocketCreationCallback, Context context) throws IOException {
|
||||||
logger.info("BinaryProtocolServer on " + port);
|
log.info("BinaryProtocolServer on " + port);
|
||||||
|
|
||||||
Function<Socket, Runnable> clientSocketRunnableFactory = clientSocket -> () -> {
|
Function<Socket, Runnable> clientSocketRunnableFactory = clientSocket -> () -> {
|
||||||
try {
|
try {
|
||||||
runProxy(linkManager, clientSocket);
|
runProxy(linkManager, clientSocket, context);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.info("proxy connection: " + e);
|
log.info("proxy connection: " + e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
tcpServerSocket(port, "BinaryProtocolServer", clientSocketRunnableFactory, logger, serverSocketCreationCallback);
|
tcpServerSocket(port, "BinaryProtocolServer", clientSocketRunnableFactory, serverSocketCreationCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -79,35 +81,48 @@ public class BinaryProtocolServer implements BinaryProtocolCommands {
|
||||||
* @param port server port to accept connections
|
* @param port server port to accept connections
|
||||||
* @param threadName
|
* @param threadName
|
||||||
* @param socketRunnableFactory method to invoke on a new thread for each new client connection
|
* @param socketRunnableFactory method to invoke on a new thread for each new client connection
|
||||||
* @param logger
|
|
||||||
* @param serverSocketCreationCallback this callback is invoked once we open the server socket
|
* @param serverSocketCreationCallback this callback is invoked once we open the server socket
|
||||||
|
* @return
|
||||||
*/
|
*/
|
||||||
public static void tcpServerSocket(int port, String threadName, Function<Socket, Runnable> socketRunnableFactory, final Logger logger, Listener serverSocketCreationCallback) {
|
public static ServerSocketReference tcpServerSocket(int port, String threadName, Function<Socket, Runnable> socketRunnableFactory, Listener serverSocketCreationCallback) throws IOException {
|
||||||
tcpServerSocket(logger, socketRunnableFactory, port, threadName, serverSocketCreationCallback, PLAIN_SOCKET_FACTORY);
|
return tcpServerSocket(socketRunnableFactory, port, threadName, serverSocketCreationCallback, PLAIN_SOCKET_FACTORY);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void tcpServerSocket(Logger logger, Function<Socket, Runnable> clientSocketRunnableFactory, int port, String threadName, Listener serverSocketCreationCallback, Function<Integer, ServerSocket> nonSecureSocketFunction) {
|
public static ServerSocketReference tcpServerSocket(Function<Socket, Runnable> clientSocketRunnableFactory, int port, String threadName, Listener serverSocketCreationCallback, ServerSocketFunction nonSecureSocketFunction) throws IOException {
|
||||||
|
ThreadFactory threadFactory = getThreadFactory(threadName);
|
||||||
|
|
||||||
|
Objects.requireNonNull(serverSocketCreationCallback, "serverSocketCreationCallback");
|
||||||
ServerSocket serverSocket = nonSecureSocketFunction.apply(port);
|
ServerSocket serverSocket = nonSecureSocketFunction.apply(port);
|
||||||
if (serverSocketCreationCallback != null)
|
|
||||||
serverSocketCreationCallback.onResult(null);
|
ServerSocketReference holder = new ServerSocketReference(serverSocket);
|
||||||
|
|
||||||
|
serverSocketCreationCallback.onResult(null);
|
||||||
Runnable runnable = () -> {
|
Runnable runnable = () -> {
|
||||||
try {
|
while (!holder.isClosed()) {
|
||||||
while (true) {
|
// Wait for a connection
|
||||||
// Wait for a connection
|
final Socket clientSocket;
|
||||||
final Socket clientSocket = serverSocket.accept();
|
try {
|
||||||
logger.info("Binary protocol proxy port connection");
|
clientSocket = serverSocket.accept();
|
||||||
new Thread(clientSocketRunnableFactory.apply(clientSocket), "proxy connection").start();
|
} catch (IOException e) {
|
||||||
|
log.info("Client socket closed right away " + e);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
log.info("Accepting binary protocol proxy port connection on " + port);
|
||||||
throw new IllegalStateException(e);
|
threadFactory.newThread(clientSocketRunnableFactory.apply(clientSocket)).start();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
new Thread(runnable, threadName).start();
|
threadFactory.newThread(runnable).start();
|
||||||
|
return holder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static ThreadFactory getThreadFactory(String threadName) {
|
||||||
|
return THREAD_FACTORIES_BY_NAME.computeIfAbsent(threadName, NamedThreadFactory::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("InfiniteLoopStatement")
|
@SuppressWarnings("InfiniteLoopStatement")
|
||||||
private void runProxy(LinkManager linkManager, Socket clientSocket) throws IOException {
|
private void runProxy(LinkManager linkManager, Socket clientSocket, Context context) throws IOException {
|
||||||
TcpIoStream stream = new TcpIoStream("[proxy] ", logger, clientSocket);
|
TcpIoStream stream = new TcpIoStream("[proxy] ", clientSocket);
|
||||||
|
|
||||||
IncomingDataBuffer in = stream.getDataBuffer();
|
IncomingDataBuffer in = stream.getDataBuffer();
|
||||||
|
|
||||||
|
@ -118,12 +133,13 @@ public class BinaryProtocolServer implements BinaryProtocolCommands {
|
||||||
handled.set(true);
|
handled.set(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
int length = getPacketLength(in, protocolCommandHandler);
|
int length = getPacketLength(in, protocolCommandHandler, context.getTimeout());
|
||||||
if (handled.get()) {
|
if (handled.get()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
System.out.println("Got [" + length + "] length promise");
|
if (log.debugEnabled())
|
||||||
|
log.debug("Got [" + length + "] length promise");
|
||||||
|
|
||||||
Packet packet = readPromisedBytes(in, length);
|
Packet packet = readPromisedBytes(in, length);
|
||||||
byte[] payload = packet.getPacket();
|
byte[] payload = packet.getPacket();
|
||||||
|
@ -133,19 +149,18 @@ public class BinaryProtocolServer implements BinaryProtocolCommands {
|
||||||
|
|
||||||
byte command = payload[0];
|
byte command = payload[0];
|
||||||
|
|
||||||
System.out.println("Got command " + BinaryProtocol.findCommand(command));
|
log.info("Got command " + BinaryProtocol.findCommand(command));
|
||||||
|
|
||||||
if (command == Fields.TS_HELLO_COMMAND) {
|
if (command == Fields.TS_HELLO_COMMAND) {
|
||||||
new HelloCommand(logger, Fields.TS_SIGNATURE).handle(stream);
|
new HelloCommand(Fields.TS_SIGNATURE).handle(stream);
|
||||||
} else if (command == COMMAND_PROTOCOL) {
|
} else if (command == COMMAND_PROTOCOL) {
|
||||||
// System.out.println("Ignoring crc F command");
|
stream.sendPacket((TS_OK + TS_PROTOCOL).getBytes());
|
||||||
stream.sendPacket((TS_OK + TS_PROTOCOL).getBytes(), logger);
|
|
||||||
} else if (command == Fields.TS_GET_FIRMWARE_VERSION) {
|
} else if (command == Fields.TS_GET_FIRMWARE_VERSION) {
|
||||||
stream.sendPacket((TS_OK + "rusEFI proxy").getBytes(), logger);
|
stream.sendPacket((TS_OK + "rusEFI proxy").getBytes());
|
||||||
} else if (command == COMMAND_CRC_CHECK_COMMAND) {
|
} else if (command == COMMAND_CRC_CHECK_COMMAND) {
|
||||||
handleCrc(linkManager, stream);
|
handleCrc(linkManager, stream);
|
||||||
} else if (command == COMMAND_PAGE) {
|
} else if (command == COMMAND_PAGE) {
|
||||||
stream.sendPacket(TS_OK.getBytes(), logger);
|
stream.sendPacket(TS_OK.getBytes());
|
||||||
} else if (command == COMMAND_READ) {
|
} else if (command == COMMAND_READ) {
|
||||||
DataInputStream dis = new DataInputStream(new ByteArrayInputStream(payload, 1, payload.length - 1));
|
DataInputStream dis = new DataInputStream(new ByteArrayInputStream(payload, 1, payload.length - 1));
|
||||||
handleRead(linkManager, dis, stream);
|
handleRead(linkManager, dis, stream);
|
||||||
|
@ -153,16 +168,16 @@ public class BinaryProtocolServer implements BinaryProtocolCommands {
|
||||||
DataInputStream dis = new DataInputStream(new ByteArrayInputStream(payload, 1, payload.length - 1));
|
DataInputStream dis = new DataInputStream(new ByteArrayInputStream(payload, 1, payload.length - 1));
|
||||||
handleWrite(linkManager, payload, dis, stream);
|
handleWrite(linkManager, payload, dis, stream);
|
||||||
} else if (command == Fields.TS_BURN_COMMAND) {
|
} else if (command == Fields.TS_BURN_COMMAND) {
|
||||||
stream.sendPacket(new byte[]{TS_RESPONSE_BURN_OK}, logger);
|
stream.sendPacket(new byte[]{TS_RESPONSE_BURN_OK});
|
||||||
} else if (command == Fields.TS_GET_COMPOSITE_BUFFER_DONE_DIFFERENTLY) {
|
} else if (command == Fields.TS_GET_COMPOSITE_BUFFER_DONE_DIFFERENTLY) {
|
||||||
System.err.println("NOT IMPLEMENTED TS_GET_COMPOSITE_BUFFER_DONE_DIFFERENTLY relay");
|
System.err.println("NOT IMPLEMENTED TS_GET_COMPOSITE_BUFFER_DONE_DIFFERENTLY relay");
|
||||||
// todo: relay command
|
// todo: relay command
|
||||||
stream.sendPacket(TS_OK.getBytes(), logger);
|
stream.sendPacket(TS_OK.getBytes());
|
||||||
} else if (command == Fields.TS_OUTPUT_COMMAND) {
|
} else if (command == Fields.TS_OUTPUT_COMMAND) {
|
||||||
DataInputStream dis = new DataInputStream(new ByteArrayInputStream(payload, 1, payload.length - 1));
|
DataInputStream dis = new DataInputStream(new ByteArrayInputStream(payload, 1, payload.length - 1));
|
||||||
int offset = swap16(dis.readShort());
|
int offset = swap16(dis.readShort());
|
||||||
int count = swap16(dis.readShort());
|
int count = swap16(dis.readShort());
|
||||||
logger.info("TS_OUTPUT_COMMAND offset=" + offset + "/count=" + count);
|
log.info("TS_OUTPUT_COMMAND offset=" + offset + "/count=" + count);
|
||||||
|
|
||||||
byte[] response = new byte[1 + count];
|
byte[] response = new byte[1 + count];
|
||||||
response[0] = (byte) TS_OK.charAt(0);
|
response[0] = (byte) TS_OK.charAt(0);
|
||||||
|
@ -170,15 +185,15 @@ public class BinaryProtocolServer implements BinaryProtocolCommands {
|
||||||
byte[] currentOutputs = binaryProtocolState.getCurrentOutputs();
|
byte[] currentOutputs = binaryProtocolState.getCurrentOutputs();
|
||||||
if (currentOutputs != null)
|
if (currentOutputs != null)
|
||||||
System.arraycopy(currentOutputs, 1 + offset, response, 1, count);
|
System.arraycopy(currentOutputs, 1 + offset, response, 1, count);
|
||||||
stream.sendPacket(response, logger);
|
stream.sendPacket(response);
|
||||||
} else if (command == Fields.TS_GET_TEXT) {
|
} else if (command == Fields.TS_GET_TEXT) {
|
||||||
// todo: relay command
|
// todo: relay command
|
||||||
System.err.println("NOT IMPLEMENTED TS_GET_TEXT relay");
|
System.err.println("NOT IMPLEMENTED TS_GET_TEXT relay");
|
||||||
stream.sendPacket(TS_OK.getBytes(), logger);
|
stream.sendPacket(TS_OK.getBytes());
|
||||||
} else {
|
} else {
|
||||||
unknownCommands.incrementAndGet();
|
unknownCommands.incrementAndGet();
|
||||||
new IllegalStateException().printStackTrace();
|
new IllegalStateException().printStackTrace();
|
||||||
logger.info("Error: unexpected " + BinaryProtocol.findCommand(command));
|
log.info("Error: unexpected " + BinaryProtocol.findCommand(command));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -212,13 +227,12 @@ public class BinaryProtocolServer implements BinaryProtocolCommands {
|
||||||
if (length <= 0)
|
if (length <= 0)
|
||||||
throw new IOException("Unexpected packed length " + length);
|
throw new IOException("Unexpected packed length " + length);
|
||||||
byte[] packet = new byte[length];
|
byte[] packet = new byte[length];
|
||||||
int size = in.read(packet);
|
in.read(packet);
|
||||||
if (size != packet.length)
|
|
||||||
throw new IllegalStateException(size + " promised but " + packet.length + " arrived");
|
|
||||||
int crc = in.readInt();
|
int crc = in.readInt();
|
||||||
int fromPacket = IoHelper.getCrc32(packet);
|
int fromPacket = IoHelper.getCrc32(packet);
|
||||||
if (crc != fromPacket)
|
if (crc != fromPacket)
|
||||||
throw new IllegalStateException("CRC mismatch crc=" + Integer.toString(crc, 16) + " vs packet=" + Integer.toString(fromPacket, 16) + " len=" + packet.length + " data: " + IoStream.printHexBinary(packet));
|
throw new IllegalStateException("CRC mismatch crc=" + Integer.toString(crc, 16) + " vs packet=" + Integer.toString(fromPacket, 16) + " len=" + packet.length + " data: " + IoStream.printHexBinary(packet));
|
||||||
|
in.onPacketArrived();
|
||||||
return new Packet(packet, crc);
|
return new Packet(packet, crc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,7 +241,7 @@ public class BinaryProtocolServer implements BinaryProtocolCommands {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void handleProtocolCommand(Socket clientSocket) throws IOException {
|
public static void handleProtocolCommand(Socket clientSocket) throws IOException {
|
||||||
System.out.println("Got plain F command");
|
log.info("Got plain F command");
|
||||||
OutputStream outputStream = clientSocket.getOutputStream();
|
OutputStream outputStream = clientSocket.getOutputStream();
|
||||||
outputStream.write(TS_PROTOCOL.getBytes());
|
outputStream.write(TS_PROTOCOL.getBytes());
|
||||||
outputStream.flush();
|
outputStream.flush();
|
||||||
|
@ -237,10 +251,10 @@ public class BinaryProtocolServer implements BinaryProtocolCommands {
|
||||||
dis.readShort(); // page
|
dis.readShort(); // page
|
||||||
int offset = swap16(dis.readShort());
|
int offset = swap16(dis.readShort());
|
||||||
int count = swap16(dis.readShort());
|
int count = swap16(dis.readShort());
|
||||||
logger.info("TS_CHUNK_WRITE_COMMAND: offset=" + offset + " count=" + count);
|
log.info("TS_CHUNK_WRITE_COMMAND: offset=" + offset + " count=" + count);
|
||||||
BinaryProtocolState bp = linkManager.getBinaryProtocolState();
|
BinaryProtocolState bp = linkManager.getBinaryProtocolState();
|
||||||
bp.setRange(packet, 7, offset, count);
|
bp.setRange(packet, 7, offset, count);
|
||||||
stream.sendPacket(TS_OK.getBytes(), logger);
|
stream.sendPacket(TS_OK.getBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleRead(LinkManager linkManager, DataInputStream dis, TcpIoStream stream) throws IOException {
|
private void handleRead(LinkManager linkManager, DataInputStream dis, TcpIoStream stream) throws IOException {
|
||||||
|
@ -248,9 +262,10 @@ public class BinaryProtocolServer implements BinaryProtocolCommands {
|
||||||
int offset = swap16(dis.readShort());
|
int offset = swap16(dis.readShort());
|
||||||
int count = swap16(dis.readShort());
|
int count = swap16(dis.readShort());
|
||||||
if (count <= 0) {
|
if (count <= 0) {
|
||||||
logger.info("Error: negative read request " + offset + "/" + count);
|
log.info("Error: negative read request " + offset + "/" + count);
|
||||||
} else {
|
} else {
|
||||||
System.out.println("read " + page + "/" + offset + "/" + count);
|
if (log.debugEnabled())
|
||||||
|
log.debug("read " + page + "/" + offset + "/" + count);
|
||||||
BinaryProtocolState bp = linkManager.getBinaryProtocolState();
|
BinaryProtocolState bp = linkManager.getBinaryProtocolState();
|
||||||
byte[] response = new byte[1 + count];
|
byte[] response = new byte[1 + count];
|
||||||
response[0] = (byte) TS_OK.charAt(0);
|
response[0] = (byte) TS_OK.charAt(0);
|
||||||
|
@ -258,19 +273,19 @@ public class BinaryProtocolServer implements BinaryProtocolCommands {
|
||||||
ConfigurationImage configurationImage = bp.getControllerConfiguration();
|
ConfigurationImage configurationImage = bp.getControllerConfiguration();
|
||||||
Objects.requireNonNull(configurationImage, "configurationImage");
|
Objects.requireNonNull(configurationImage, "configurationImage");
|
||||||
System.arraycopy(configurationImage.getContent(), offset, response, 1, count);
|
System.arraycopy(configurationImage.getContent(), offset, response, 1, count);
|
||||||
stream.sendPacket(response, logger);
|
stream.sendPacket(response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleCrc(LinkManager linkManager, TcpIoStream stream) throws IOException {
|
private void handleCrc(LinkManager linkManager, TcpIoStream stream) throws IOException {
|
||||||
System.out.println("CRC check");
|
log.info("CRC check");
|
||||||
BinaryProtocolState bp = linkManager.getBinaryProtocolState();
|
BinaryProtocolState bp = linkManager.getBinaryProtocolState();
|
||||||
byte[] content = bp.getControllerConfiguration().getContent();
|
byte[] content = bp.getControllerConfiguration().getContent();
|
||||||
int result = IoHelper.getCrc32(content);
|
int result = IoHelper.getCrc32(content);
|
||||||
ByteArrayOutputStream response = new ByteArrayOutputStream();
|
ByteArrayOutputStream response = new ByteArrayOutputStream();
|
||||||
response.write(TS_OK.charAt(0));
|
response.write(TS_OK.charAt(0));
|
||||||
new DataOutputStream(response).writeInt(result);
|
new DataOutputStream(response).writeInt(result);
|
||||||
stream.sendPacket(response.toByteArray(), logger);
|
stream.sendPacket(response.toByteArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Packet {
|
public static class Packet {
|
||||||
|
@ -290,4 +305,10 @@ public class BinaryProtocolServer implements BinaryProtocolCommands {
|
||||||
return crc;
|
return crc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class Context {
|
||||||
|
public int getTimeout() {
|
||||||
|
return Timeouts.BINARY_IO_TIMEOUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package com.rusefi.io.tcp;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
|
||||||
|
public interface ServerSocketFunction {
|
||||||
|
ServerSocket apply(int port) throws IOException;
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package com.rusefi.io.tcp;
|
||||||
|
|
||||||
|
import com.rusefi.shared.FileUtil;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
|
||||||
|
public class ServerSocketReference implements Closeable {
|
||||||
|
private final ServerSocket serverSocket;
|
||||||
|
private boolean isClosed;
|
||||||
|
|
||||||
|
public ServerSocketReference(ServerSocket serverSocket) {
|
||||||
|
this.serverSocket = serverSocket;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
isClosed = true;
|
||||||
|
FileUtil.close(serverSocket);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isClosed() {
|
||||||
|
return isClosed;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
package com.rusefi.io.tcp;
|
package com.rusefi.io.tcp;
|
||||||
|
|
||||||
import com.opensr5.Logger;
|
|
||||||
import com.opensr5.io.DataListener;
|
import com.opensr5.io.DataListener;
|
||||||
import com.rusefi.binaryprotocol.IncomingDataBuffer;
|
import com.rusefi.binaryprotocol.IncomingDataBuffer;
|
||||||
import com.rusefi.io.ByteReader;
|
import com.rusefi.io.ByteReader;
|
||||||
|
@ -8,10 +7,7 @@ import com.rusefi.io.serial.AbstractIoStream;
|
||||||
import com.rusefi.shared.FileUtil;
|
import com.rusefi.shared.FileUtil;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
import java.io.*;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,34 +17,37 @@ import java.net.Socket;
|
||||||
public class TcpIoStream extends AbstractIoStream {
|
public class TcpIoStream extends AbstractIoStream {
|
||||||
private final InputStream input;
|
private final InputStream input;
|
||||||
private final OutputStream output;
|
private final OutputStream output;
|
||||||
private final Logger logger;
|
|
||||||
private final String loggingPrefix;
|
private final String loggingPrefix;
|
||||||
|
private final DisconnectListener disconnectListener;
|
||||||
@NotNull
|
@NotNull
|
||||||
private final Socket socket;
|
private final Socket socket;
|
||||||
private final IncomingDataBuffer dataBuffer;
|
private final IncomingDataBuffer dataBuffer;
|
||||||
|
|
||||||
public TcpIoStream(Logger logger, Socket socket) throws IOException {
|
public TcpIoStream(String loggingPrefix, Socket socket) throws IOException {
|
||||||
this("", logger, socket);
|
this(loggingPrefix, socket, DisconnectListener.VOID);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TcpIoStream(String loggingPrefix, Logger logger, Socket socket) throws IOException {
|
public TcpIoStream(String loggingPrefix, Socket socket, DisconnectListener disconnectListener) throws IOException {
|
||||||
this.loggingPrefix = loggingPrefix;
|
this.loggingPrefix = loggingPrefix;
|
||||||
|
this.disconnectListener = disconnectListener;
|
||||||
if (socket == null)
|
if (socket == null)
|
||||||
throw new NullPointerException("socket");
|
throw new NullPointerException("socket");
|
||||||
this.socket = socket;
|
this.socket = socket;
|
||||||
InputStream input = new BufferedInputStream(socket.getInputStream());
|
InputStream input = new BufferedInputStream(socket.getInputStream());
|
||||||
OutputStream output = socket.getOutputStream();
|
this.output = new BufferedOutputStream(socket.getOutputStream());
|
||||||
this.logger = logger;
|
|
||||||
if (output == null)
|
|
||||||
throw new NullPointerException("output");
|
|
||||||
this.output = output;
|
|
||||||
this.input = input;
|
this.input = input;
|
||||||
this.dataBuffer = IncomingDataBuffer.createDataBuffer(loggingPrefix, this, logger);
|
this.dataBuffer = IncomingDataBuffer.createDataBuffer(loggingPrefix, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
super.close();
|
// we need to guarantee only one onDisconnect invocation for retry logic to be healthy
|
||||||
|
synchronized (this) {
|
||||||
|
if (!isClosed()) {
|
||||||
|
super.close();
|
||||||
|
disconnectListener.onDisconnect("on close");
|
||||||
|
}
|
||||||
|
}
|
||||||
FileUtil.close(socket);
|
FileUtil.close(socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,12 +64,23 @@ public class TcpIoStream extends AbstractIoStream {
|
||||||
@Override
|
@Override
|
||||||
public void write(byte[] bytes) throws IOException {
|
public void write(byte[] bytes) throws IOException {
|
||||||
output.write(bytes);
|
output.write(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void flush() throws IOException {
|
||||||
|
super.flush();
|
||||||
output.flush();
|
output.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setInputListener(final DataListener listener) {
|
public void setInputListener(final DataListener listener) {
|
||||||
|
ByteReader.runReaderLoop(loggingPrefix, listener, input::read, this);
|
||||||
|
}
|
||||||
|
|
||||||
ByteReader.runReaderLoop(loggingPrefix, listener, input::read, logger);
|
public interface DisconnectListener {
|
||||||
|
DisconnectListener VOID = (String message) -> {
|
||||||
|
|
||||||
|
};
|
||||||
|
void onDisconnect(String message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue