Merge remote-tracking branch 'upstream/master' into pull-out-maf

This commit is contained in:
Matthew Kennedy 2020-07-24 11:35:44 -07:00
commit c7e8c4d26a
154 changed files with 5971 additions and 608 deletions

View File

@ -16,6 +16,7 @@ android {
defaultConfig {
applicationId "com.rusefi.app"
// Version 21 = Android_5.0_Lollipop
minSdkVersion 21
targetSdkVersion 30
versionCode 1

View File

@ -7,12 +7,12 @@ import com.hoho.android.usbserial.driver.ProbeTable;
import com.hoho.android.usbserial.driver.UsbSerialDriver;
import com.hoho.android.usbserial.driver.UsbSerialPort;
import com.hoho.android.usbserial.driver.UsbSerialProber;
import com.opensr5.Logger;
import com.opensr5.io.DataListener;
import com.rusefi.binaryprotocol.IncomingDataBuffer;
import com.rusefi.dfu.DfuLogic;
import com.rusefi.io.ByteReader;
import com.rusefi.io.serial.AbstractIoStream;
import com.rusefi.io.tcp.TcpIoStream;
import java.io.IOException;
import java.util.List;
@ -31,9 +31,9 @@ public class AndroidSerial extends AbstractIoStream {
return prober.findAllDrivers(usbManager);
}
public AndroidSerial(UsbSerialPort usbSerialPort, Logger logger) {
public AndroidSerial(UsbSerialPort usbSerialPort) {
this.usbSerialPort = usbSerialPort;
dataBuffer = IncomingDataBuffer.createDataBuffer("", this, logger);
dataBuffer = IncomingDataBuffer.createDataBuffer("", this);
}
@Override
@ -49,7 +49,7 @@ public class AndroidSerial extends AbstractIoStream {
@Override
public void setInputListener(DataListener listener) {
ByteReader reader = buffer -> usbSerialPort.read(buffer, 5000);
ByteReader.runReaderLoop("", listener, reader, Logger.CONSOLE);
ByteReader.runReaderLoop("", listener, reader, TcpIoStream.DisconnectListener.VOID);
}
@Override

View File

@ -34,7 +34,6 @@ import android.widget.TextView;
import com.hoho.android.usbserial.driver.UsbSerialDriver;
import com.hoho.android.usbserial.driver.UsbSerialPort;
import com.opensr5.Logger;
import com.rusefi.Listener;
import com.rusefi.dfu.DfuConnection;
import com.rusefi.dfu.DfuImage;
@ -233,9 +232,9 @@ public class rusEFI extends Activity {
port.open(connection);
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");
DfuHelper.sendDfuRebootCommand(serial, new StringBuilder(), Logger.CONSOLE);
DfuHelper.sendDfuRebootCommand(serial, new StringBuilder());
} catch (IOException e) {
throw new IllegalStateException(e);

View File

@ -778,6 +778,10 @@ case GPPWM_Map:
return "GPPWM_Map";
case GPPWM_Tps:
return "GPPWM_Tps";
case GPPWM_FuelLoad:
return "GPPWM_FuelLoad";
case GPPWM_IgnLoad:
return "GPPWM_IgnLoad";
}
return NULL;
}

View File

@ -1,4 +1,4 @@
// this section was generated automatically by rusEfi tool ConfigDefinition.jar based on kinetis_gen_config.bat integration/rusefi_config.txt Wed Jul 22 19:41:17 UTC 2020
// this section was generated automatically by rusEfi tool ConfigDefinition.jar based on kinetis_gen_config.bat integration/rusefi_config.txt Thu Jul 23 23:54:04 UTC 2020
// by class com.rusefi.output.CHeaderConsumer
// begin
#pragma once
@ -3530,4 +3530,4 @@ struct persistent_config_s {
typedef struct persistent_config_s persistent_config_s;
// end
// this section was generated automatically by rusEfi tool ConfigDefinition.jar based on kinetis_gen_config.bat integration/rusefi_config.txt Wed Jul 22 19:41:17 UTC 2020
// this section was generated automatically by rusEfi tool ConfigDefinition.jar based on kinetis_gen_config.bat integration/rusefi_config.txt Thu Jul 23 23:54:04 UTC 2020

View File

@ -658,7 +658,7 @@
#define gppwm4_pwmFrequency_offset 4410
#define gppwm4_rpmBins_offset 4424
#define gppwm4_table_offset 4432
#define gppwm_channel_e_enum "TPS", "MAP", "CLT", "IAT"
#define gppwm_channel_e_enum "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
#define gppwm_channel_size 88
#define GPPWM_CHANNELS 4
#define GPPWM_LOAD_COUNT 8
@ -1074,8 +1074,8 @@
#define showHumanReadableWarning_offset 976
#define showSdCardWarning_offset 76
#define SIGNATURE_BOARD kin
#define SIGNATURE_DATE 2020.07.22
#define SIGNATURE_HASH 3833170085
#define SIGNATURE_DATE 2020.07.23
#define SIGNATURE_HASH 2227197319
#define silentTriggerError_offset 1464
#define slowAdcAlpha_offset 2088
#define sparkDwellRpmBins_offset 332
@ -1343,7 +1343,7 @@
#define ts_show_spi true
#define ts_show_trigger_comparator true
#define ts_show_tunerstudio_port true
#define TS_SIGNATURE "rusEFI 2020.07.22.kin.3833170085"
#define TS_SIGNATURE "rusEFI 2020.07.23.kin.2227197319"
#define TS_SINGLE_WRITE_COMMAND 'W'
#define tunerStudioSerialSpeed_offset 728
#define twoWireBatchIgnition_offset 1476

View File

@ -7,6 +7,7 @@
#include "expected.h"
#include "sensor.h"
#include "map.h"
#include "engine_math.h"
EXTERN_ENGINE;
@ -27,6 +28,10 @@ expected<float> readGppwmChannel(gppwm_channel_e channel DECLARE_ENGINE_PARAMETE
return Sensor::get(SensorType::Clt);
case GPPWM_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:
return unexpected;
}

View File

@ -916,6 +916,10 @@ case GPPWM_Map:
return "GPPWM_Map";
case GPPWM_Tps:
return "GPPWM_Tps";
case GPPWM_FuelLoad:
return "GPPWM_FuelLoad";
case GPPWM_IgnLoad:
return "GPPWM_IgnLoad";
}
return NULL;
}

View File

@ -952,6 +952,8 @@ typedef enum __attribute__ ((__packed__)) {
GPPWM_Map = 1,
GPPWM_Clt = 2,
GPPWM_Iat = 3,
GPPWM_FuelLoad = 4,
GPPWM_IgnLoad = 5,
} gppwm_channel_e;
typedef enum __attribute__ ((__packed__)) {

View File

@ -1,2 +1,2 @@
#pragma once
#define VCS_DATE 20200723
#define VCS_DATE 20200724

View File

@ -1,4 +1,4 @@
// this section 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 section was generated automatically by rusEfi tool ConfigDefinition.jar based on gen_config.sh integration/rusefi_config.txt Thu Jul 23 23:53:53 UTC 2020
// by class com.rusefi.output.CHeaderConsumer
// begin
#pragma once
@ -3530,4 +3530,4 @@ struct persistent_config_s {
typedef struct persistent_config_s persistent_config_s;
// end
// this section 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 section was generated automatically by rusEfi tool ConfigDefinition.jar based on gen_config.sh integration/rusefi_config.txt Thu Jul 23 23:53:53 UTC 2020

View File

@ -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 Thu Jul 23 23:53:53 UTC 2020
// by class com.rusefi.output.FileFsioSettingsConsumer
FSIO_SETTING_FANONTEMPERATURE = 1000,

View File

@ -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 Thu Jul 23 23:53:53 UTC 2020
// by class com.rusefi.output.FileFsioSettingsConsumer
case FSIO_SETTING_FANONTEMPERATURE:

View File

@ -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 Thu Jul 23 23:53:53 UTC 2020
// by class com.rusefi.output.FileFsioSettingsConsumer
static LENameOrdinalPair lefanOnTemperature(FSIO_SETTING_FANONTEMPERATURE, "cfg_fanOnTemperature");

View File

@ -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 Thu Jul 23 23:53:53 UTC 2020
// by class com.rusefi.output.FileFsioSettingsConsumer
case FSIO_SETTING_FANONTEMPERATURE:

View File

@ -658,7 +658,7 @@
#define gppwm4_pwmFrequency_offset 4410
#define gppwm4_rpmBins_offset 4424
#define gppwm4_table_offset 4432
#define gppwm_channel_e_enum "TPS", "MAP", "CLT", "IAT"
#define gppwm_channel_e_enum "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
#define gppwm_channel_size 88
#define GPPWM_CHANNELS 4
#define GPPWM_LOAD_COUNT 8
@ -1074,8 +1074,8 @@
#define showHumanReadableWarning_offset 976
#define showSdCardWarning_offset 76
#define SIGNATURE_BOARD all
#define SIGNATURE_DATE 2020.07.22
#define SIGNATURE_HASH 692540479
#define SIGNATURE_DATE 2020.07.23
#define SIGNATURE_HASH 1241418013
#define silentTriggerError_offset 1464
#define slowAdcAlpha_offset 2088
#define sparkDwellRpmBins_offset 332
@ -1343,7 +1343,7 @@
#define ts_show_spi true
#define ts_show_trigger_comparator false
#define ts_show_tunerstudio_port true
#define TS_SIGNATURE "rusEFI 2020.07.22.all.692540479"
#define TS_SIGNATURE "rusEFI 2020.07.23.all.1241418013"
#define TS_SINGLE_WRITE_COMMAND 'W'
#define tunerStudioSerialSpeed_offset 728
#define twoWireBatchIgnition_offset 1476

View File

@ -3,6 +3,6 @@
//
#define SIGNATURE_BOARD all
#define SIGNATURE_DATE 2020.07.22
#define SIGNATURE_HASH 692540479
#define TS_SIGNATURE "rusEFI 2020.07.22.all.692540479"
#define SIGNATURE_DATE 2020.07.24
#define SIGNATURE_HASH 3766939728
#define TS_SIGNATURE "rusEFI 2020.07.24.all.3766939728"

View File

@ -3,6 +3,6 @@
//
#define SIGNATURE_BOARD frankenso_na6
#define SIGNATURE_DATE 2020.07.22
#define SIGNATURE_HASH 4156569820
#define TS_SIGNATURE "rusEFI 2020.07.22.frankenso_na6.4156569820"
#define SIGNATURE_DATE 2020.07.24
#define SIGNATURE_HASH 1040293043
#define TS_SIGNATURE "rusEFI 2020.07.24.frankenso_na6.1040293043"

View File

@ -3,6 +3,6 @@
//
#define SIGNATURE_BOARD kin
#define SIGNATURE_DATE 2020.07.22
#define SIGNATURE_HASH 3833170085
#define TS_SIGNATURE "rusEFI 2020.07.22.kin.3833170085"
#define SIGNATURE_DATE 2020.07.24
#define SIGNATURE_HASH 767044810
#define TS_SIGNATURE "rusEFI 2020.07.24.kin.767044810"

View File

@ -3,6 +3,6 @@
//
#define SIGNATURE_BOARD mre_f4
#define SIGNATURE_DATE 2020.07.22
#define SIGNATURE_HASH 1622770353
#define TS_SIGNATURE "rusEFI 2020.07.22.mre_f4.1622770353"
#define SIGNATURE_DATE 2020.07.24
#define SIGNATURE_HASH 2843223774
#define TS_SIGNATURE "rusEFI 2020.07.24.mre_f4.2843223774"

View File

@ -3,6 +3,6 @@
//
#define SIGNATURE_BOARD mre_f7
#define SIGNATURE_DATE 2020.07.22
#define SIGNATURE_HASH 1622770353
#define TS_SIGNATURE "rusEFI 2020.07.22.mre_f7.1622770353"
#define SIGNATURE_DATE 2020.07.24
#define SIGNATURE_HASH 2843223774
#define TS_SIGNATURE "rusEFI 2020.07.24.mre_f7.2843223774"

View File

@ -3,6 +3,6 @@
//
#define SIGNATURE_BOARD prometheus_405
#define SIGNATURE_DATE 2020.07.22
#define SIGNATURE_HASH 3696987323
#define TS_SIGNATURE "rusEFI 2020.07.22.prometheus_405.3696987323"
#define SIGNATURE_DATE 2020.07.24
#define SIGNATURE_HASH 362424532
#define TS_SIGNATURE "rusEFI 2020.07.24.prometheus_405.362424532"

View File

@ -3,6 +3,6 @@
//
#define SIGNATURE_BOARD prometheus_469
#define SIGNATURE_DATE 2020.07.22
#define SIGNATURE_HASH 3696987323
#define TS_SIGNATURE "rusEFI 2020.07.22.prometheus_469.3696987323"
#define SIGNATURE_DATE 2020.07.24
#define SIGNATURE_HASH 362424532
#define TS_SIGNATURE "rusEFI 2020.07.24.prometheus_469.362424532"

View File

@ -3,6 +3,6 @@
//
#define SIGNATURE_BOARD proteus_f4
#define SIGNATURE_DATE 2020.07.22
#define SIGNATURE_HASH 2765497840
#define TS_SIGNATURE "rusEFI 2020.07.22.proteus_f4.2765497840"
#define SIGNATURE_DATE 2020.07.24
#define SIGNATURE_HASH 1830257055
#define TS_SIGNATURE "rusEFI 2020.07.24.proteus_f4.1830257055"

View File

@ -3,6 +3,6 @@
//
#define SIGNATURE_BOARD proteus_f7
#define SIGNATURE_DATE 2020.07.22
#define SIGNATURE_HASH 2765497840
#define TS_SIGNATURE "rusEFI 2020.07.22.proteus_f7.2765497840"
#define SIGNATURE_DATE 2020.07.24
#define SIGNATURE_HASH 1830257055
#define TS_SIGNATURE "rusEFI 2020.07.24.proteus_f7.1830257055"

View File

@ -289,8 +289,8 @@ struct spi_pins
end_struct
#define gppwm_channel_e_enum "TPS", "MAP", "CLT", "IAT"
custom gppwm_channel_e 1 bits, U08, @OFFSET@, [0:1], @@gppwm_channel_e_enum@@
#define gppwm_channel_e_enum "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
custom gppwm_channel_e 1 bits, U08, @OFFSET@, [0:2], @@gppwm_channel_e_enum@@
struct gppwm_channel
output_pin_e pin;+Select a pin to use for PWM or on-off output.;

View File

@ -33,12 +33,12 @@ enable2ndByteCanID = false
[MegaTune]
; https://rusefi.com/forum/viewtopic.php?p=36201#p36201
signature = "rusEFI 2020.07.22.all.692540479"
signature = "rusEFI 2020.07.24.all.3766939728"
[TunerStudio]
queryCommand = "S"
versionInfo = "V" ; firmwave version for title bar.
signature = "rusEFI 2020.07.22.all.692540479" ; signature is expected to be 7 or more characters.
signature = "rusEFI 2020.07.24.all.3766939728" ; signature is expected to be 7 or more characters.
[Constants]
; new packet serial format with CRC
@ -76,7 +76,7 @@ enable2ndByteCanID = false
; see PAGE_0_SIZE in C source code
; CONFIG_DEFINITION_START
; this section 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 section was generated automatically by rusEfi tool ConfigDefinition.jar based on gen_config.sh integration/rusefi_config.txt Fri Jul 24 15:43:57 UTC 2020
pageSize = 20000
page = 1
@ -1050,7 +1050,7 @@ page = 1
gppwm1_pwmFrequency = scalar, U16, 4146, "hz", 1, 0, 0, 500, 0
gppwm1_onAboveDuty = scalar, U08, 4148, "%", 1, 0, 0, 100, 0
gppwm1_offBelowDuty = scalar, U08, 4149, "%", 1, 0, 0, 100, 0
gppwm1_loadAxis = bits, U08, 4150, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm1_loadAxis = bits, U08, 4150, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm1_alignmentFill_map = scalar, U08, 4151, "unit", 1, 0, 0, 100, 0
gppwm1_loadBins = array, U08, 4152, [8], "load", 1, 0, 0.0, 250, 0
gppwm1_rpmBins = array, U08, 4160, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1060,7 +1060,7 @@ page = 1
gppwm2_pwmFrequency = scalar, U16, 4234, "hz", 1, 0, 0, 500, 0
gppwm2_onAboveDuty = scalar, U08, 4236, "%", 1, 0, 0, 100, 0
gppwm2_offBelowDuty = scalar, U08, 4237, "%", 1, 0, 0, 100, 0
gppwm2_loadAxis = bits, U08, 4238, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm2_loadAxis = bits, U08, 4238, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm2_alignmentFill_map = scalar, U08, 4239, "unit", 1, 0, 0, 100, 0
gppwm2_loadBins = array, U08, 4240, [8], "load", 1, 0, 0.0, 250, 0
gppwm2_rpmBins = array, U08, 4248, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1070,7 +1070,7 @@ page = 1
gppwm3_pwmFrequency = scalar, U16, 4322, "hz", 1, 0, 0, 500, 0
gppwm3_onAboveDuty = scalar, U08, 4324, "%", 1, 0, 0, 100, 0
gppwm3_offBelowDuty = scalar, U08, 4325, "%", 1, 0, 0, 100, 0
gppwm3_loadAxis = bits, U08, 4326, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm3_loadAxis = bits, U08, 4326, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm3_alignmentFill_map = scalar, U08, 4327, "unit", 1, 0, 0, 100, 0
gppwm3_loadBins = array, U08, 4328, [8], "load", 1, 0, 0.0, 250, 0
gppwm3_rpmBins = array, U08, 4336, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1080,7 +1080,7 @@ page = 1
gppwm4_pwmFrequency = scalar, U16, 4410, "hz", 1, 0, 0, 500, 0
gppwm4_onAboveDuty = scalar, U08, 4412, "%", 1, 0, 0, 100, 0
gppwm4_offBelowDuty = scalar, U08, 4413, "%", 1, 0, 0, 100, 0
gppwm4_loadAxis = bits, U08, 4414, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm4_loadAxis = bits, U08, 4414, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm4_alignmentFill_map = scalar, U08, 4415, "unit", 1, 0, 0, 100, 0
gppwm4_loadBins = array, U08, 4416, [8], "load", 1, 0, 0.0, 250, 0
gppwm4_rpmBins = array, U08, 4424, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1631,7 +1631,7 @@ page = 1
rawOilPressure = scalar, U16, 242, "V",{1/1000}, 0.0
; 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
@ -1647,10 +1647,10 @@ page = 1
time = { timeNow }
; 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))}
gppwm2_load = {(gppwm2_loadAxis == 0) ? TPSValue : ((gppwm2_loadAxis == 1) ? MAPValue : ((gppwm2_loadAxis == 2) ? coolant : intake))}
gppwm3_load = {(gppwm3_loadAxis == 0) ? TPSValue : ((gppwm3_loadAxis == 1) ? MAPValue : ((gppwm3_loadAxis == 2) ? coolant : intake))}
gppwm4_load = {(gppwm4_loadAxis == 0) ? TPSValue : ((gppwm4_loadAxis == 1) ? MAPValue : ((gppwm4_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 : ((gppwm2_loadAxis == 3) ? intake : ((gppwm2_loadAxis == 4) ? fuelingLoad : ignitionLoad))))}
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 : ((gppwm4_loadAxis == 3) ? intake : ((gppwm4_loadAxis == 4) ? fuelingLoad : ignitionLoad))))}
[PcVariables]
tuneCrcPcVariable = continuousChannelValue, tuneCrc16

View File

@ -33,12 +33,12 @@ enable2ndByteCanID = false
[MegaTune]
; https://rusefi.com/forum/viewtopic.php?p=36201#p36201
signature = "rusEFI 2020.07.22.frankenso_na6.4156569820"
signature = "rusEFI 2020.07.24.frankenso_na6.1040293043"
[TunerStudio]
queryCommand = "S"
versionInfo = "V" ; firmwave version for title bar.
signature = "rusEFI 2020.07.22.frankenso_na6.4156569820" ; signature is expected to be 7 or more characters.
signature = "rusEFI 2020.07.24.frankenso_na6.1040293043" ; signature is expected to be 7 or more characters.
[Constants]
; new packet serial format with CRC
@ -76,7 +76,7 @@ enable2ndByteCanID = false
; see PAGE_0_SIZE in C source code
; CONFIG_DEFINITION_START
; this section was generated automatically by rusEfi tool ConfigDefinition.jar based on gen_config.sh integration/rusefi_config.txt Wed Jul 22 19:41:10 UTC 2020
; this section was generated automatically by rusEfi tool ConfigDefinition.jar based on gen_config.sh integration/rusefi_config.txt Fri Jul 24 15:44:01 UTC 2020
pageSize = 20000
page = 1
@ -1050,7 +1050,7 @@ page = 1
gppwm1_pwmFrequency = scalar, U16, 4146, "hz", 1, 0, 0, 500, 0
gppwm1_onAboveDuty = scalar, U08, 4148, "%", 1, 0, 0, 100, 0
gppwm1_offBelowDuty = scalar, U08, 4149, "%", 1, 0, 0, 100, 0
gppwm1_loadAxis = bits, U08, 4150, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm1_loadAxis = bits, U08, 4150, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm1_alignmentFill_map = scalar, U08, 4151, "unit", 1, 0, 0, 100, 0
gppwm1_loadBins = array, U08, 4152, [8], "load", 1, 0, 0.0, 250, 0
gppwm1_rpmBins = array, U08, 4160, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1060,7 +1060,7 @@ page = 1
gppwm2_pwmFrequency = scalar, U16, 4234, "hz", 1, 0, 0, 500, 0
gppwm2_onAboveDuty = scalar, U08, 4236, "%", 1, 0, 0, 100, 0
gppwm2_offBelowDuty = scalar, U08, 4237, "%", 1, 0, 0, 100, 0
gppwm2_loadAxis = bits, U08, 4238, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm2_loadAxis = bits, U08, 4238, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm2_alignmentFill_map = scalar, U08, 4239, "unit", 1, 0, 0, 100, 0
gppwm2_loadBins = array, U08, 4240, [8], "load", 1, 0, 0.0, 250, 0
gppwm2_rpmBins = array, U08, 4248, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1070,7 +1070,7 @@ page = 1
gppwm3_pwmFrequency = scalar, U16, 4322, "hz", 1, 0, 0, 500, 0
gppwm3_onAboveDuty = scalar, U08, 4324, "%", 1, 0, 0, 100, 0
gppwm3_offBelowDuty = scalar, U08, 4325, "%", 1, 0, 0, 100, 0
gppwm3_loadAxis = bits, U08, 4326, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm3_loadAxis = bits, U08, 4326, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm3_alignmentFill_map = scalar, U08, 4327, "unit", 1, 0, 0, 100, 0
gppwm3_loadBins = array, U08, 4328, [8], "load", 1, 0, 0.0, 250, 0
gppwm3_rpmBins = array, U08, 4336, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1080,7 +1080,7 @@ page = 1
gppwm4_pwmFrequency = scalar, U16, 4410, "hz", 1, 0, 0, 500, 0
gppwm4_onAboveDuty = scalar, U08, 4412, "%", 1, 0, 0, 100, 0
gppwm4_offBelowDuty = scalar, U08, 4413, "%", 1, 0, 0, 100, 0
gppwm4_loadAxis = bits, U08, 4414, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm4_loadAxis = bits, U08, 4414, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm4_alignmentFill_map = scalar, U08, 4415, "unit", 1, 0, 0, 100, 0
gppwm4_loadBins = array, U08, 4416, [8], "load", 1, 0, 0.0, 250, 0
gppwm4_rpmBins = array, U08, 4424, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1631,7 +1631,7 @@ page = 1
rawOilPressure = scalar, U16, 242, "V",{1/1000}, 0.0
; 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
@ -1647,10 +1647,10 @@ page = 1
time = { timeNow }
; 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))}
gppwm2_load = {(gppwm2_loadAxis == 0) ? TPSValue : ((gppwm2_loadAxis == 1) ? MAPValue : ((gppwm2_loadAxis == 2) ? coolant : intake))}
gppwm3_load = {(gppwm3_loadAxis == 0) ? TPSValue : ((gppwm3_loadAxis == 1) ? MAPValue : ((gppwm3_loadAxis == 2) ? coolant : intake))}
gppwm4_load = {(gppwm4_loadAxis == 0) ? TPSValue : ((gppwm4_loadAxis == 1) ? MAPValue : ((gppwm4_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 : ((gppwm2_loadAxis == 3) ? intake : ((gppwm2_loadAxis == 4) ? fuelingLoad : ignitionLoad))))}
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 : ((gppwm4_loadAxis == 3) ? intake : ((gppwm4_loadAxis == 4) ? fuelingLoad : ignitionLoad))))}
[PcVariables]
tuneCrcPcVariable = continuousChannelValue, tuneCrc16

View File

@ -33,12 +33,12 @@ enable2ndByteCanID = false
[MegaTune]
; https://rusefi.com/forum/viewtopic.php?p=36201#p36201
signature = "rusEFI 2020.07.22.kin.3833170085"
signature = "rusEFI 2020.07.24.kin.767044810"
[TunerStudio]
queryCommand = "S"
versionInfo = "V" ; firmwave version for title bar.
signature = "rusEFI 2020.07.22.kin.3833170085" ; signature is expected to be 7 or more characters.
signature = "rusEFI 2020.07.24.kin.767044810" ; signature is expected to be 7 or more characters.
[Constants]
; new packet serial format with CRC
@ -76,7 +76,7 @@ enable2ndByteCanID = false
; see PAGE_0_SIZE in C source code
; CONFIG_DEFINITION_START
; this section was generated automatically by rusEfi tool ConfigDefinition.jar based on kinetis_gen_config.bat integration/rusefi_config.txt Wed Jul 22 19:41:17 UTC 2020
; this section was generated automatically by rusEfi tool ConfigDefinition.jar based on kinetis_gen_config.bat integration/rusefi_config.txt Fri Jul 24 15:44:08 UTC 2020
pageSize = 20000
page = 1
@ -1050,7 +1050,7 @@ page = 1
gppwm1_pwmFrequency = scalar, U16, 4146, "hz", 1, 0, 0, 500, 0
gppwm1_onAboveDuty = scalar, U08, 4148, "%", 1, 0, 0, 100, 0
gppwm1_offBelowDuty = scalar, U08, 4149, "%", 1, 0, 0, 100, 0
gppwm1_loadAxis = bits, U08, 4150, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm1_loadAxis = bits, U08, 4150, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm1_alignmentFill_map = scalar, U08, 4151, "unit", 1, 0, 0, 100, 0
gppwm1_loadBins = array, U08, 4152, [8], "load", 1, 0, 0.0, 250, 0
gppwm1_rpmBins = array, U08, 4160, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1060,7 +1060,7 @@ page = 1
gppwm2_pwmFrequency = scalar, U16, 4234, "hz", 1, 0, 0, 500, 0
gppwm2_onAboveDuty = scalar, U08, 4236, "%", 1, 0, 0, 100, 0
gppwm2_offBelowDuty = scalar, U08, 4237, "%", 1, 0, 0, 100, 0
gppwm2_loadAxis = bits, U08, 4238, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm2_loadAxis = bits, U08, 4238, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm2_alignmentFill_map = scalar, U08, 4239, "unit", 1, 0, 0, 100, 0
gppwm2_loadBins = array, U08, 4240, [8], "load", 1, 0, 0.0, 250, 0
gppwm2_rpmBins = array, U08, 4248, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1070,7 +1070,7 @@ page = 1
gppwm3_pwmFrequency = scalar, U16, 4322, "hz", 1, 0, 0, 500, 0
gppwm3_onAboveDuty = scalar, U08, 4324, "%", 1, 0, 0, 100, 0
gppwm3_offBelowDuty = scalar, U08, 4325, "%", 1, 0, 0, 100, 0
gppwm3_loadAxis = bits, U08, 4326, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm3_loadAxis = bits, U08, 4326, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm3_alignmentFill_map = scalar, U08, 4327, "unit", 1, 0, 0, 100, 0
gppwm3_loadBins = array, U08, 4328, [8], "load", 1, 0, 0.0, 250, 0
gppwm3_rpmBins = array, U08, 4336, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1080,7 +1080,7 @@ page = 1
gppwm4_pwmFrequency = scalar, U16, 4410, "hz", 1, 0, 0, 500, 0
gppwm4_onAboveDuty = scalar, U08, 4412, "%", 1, 0, 0, 100, 0
gppwm4_offBelowDuty = scalar, U08, 4413, "%", 1, 0, 0, 100, 0
gppwm4_loadAxis = bits, U08, 4414, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm4_loadAxis = bits, U08, 4414, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm4_alignmentFill_map = scalar, U08, 4415, "unit", 1, 0, 0, 100, 0
gppwm4_loadBins = array, U08, 4416, [8], "load", 1, 0, 0.0, 250, 0
gppwm4_rpmBins = array, U08, 4424, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1631,7 +1631,7 @@ page = 1
rawOilPressure = scalar, U16, 242, "V",{1/1000}, 0.0
; 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
@ -1647,10 +1647,10 @@ page = 1
time = { timeNow }
; 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))}
gppwm2_load = {(gppwm2_loadAxis == 0) ? TPSValue : ((gppwm2_loadAxis == 1) ? MAPValue : ((gppwm2_loadAxis == 2) ? coolant : intake))}
gppwm3_load = {(gppwm3_loadAxis == 0) ? TPSValue : ((gppwm3_loadAxis == 1) ? MAPValue : ((gppwm3_loadAxis == 2) ? coolant : intake))}
gppwm4_load = {(gppwm4_loadAxis == 0) ? TPSValue : ((gppwm4_loadAxis == 1) ? MAPValue : ((gppwm4_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 : ((gppwm2_loadAxis == 3) ? intake : ((gppwm2_loadAxis == 4) ? fuelingLoad : ignitionLoad))))}
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 : ((gppwm4_loadAxis == 3) ? intake : ((gppwm4_loadAxis == 4) ? fuelingLoad : ignitionLoad))))}
[PcVariables]
tuneCrcPcVariable = continuousChannelValue, tuneCrc16

View File

@ -33,12 +33,12 @@ enable2ndByteCanID = false
[MegaTune]
; https://rusefi.com/forum/viewtopic.php?p=36201#p36201
signature = "rusEFI 2020.07.22.mre_f4.1622770353"
signature = "rusEFI 2020.07.24.mre_f4.2843223774"
[TunerStudio]
queryCommand = "S"
versionInfo = "V" ; firmwave version for title bar.
signature = "rusEFI 2020.07.22.mre_f4.1622770353" ; signature is expected to be 7 or more characters.
signature = "rusEFI 2020.07.24.mre_f4.2843223774" ; signature is expected to be 7 or more characters.
[Constants]
; new packet serial format with CRC
@ -76,7 +76,7 @@ enable2ndByteCanID = false
; see PAGE_0_SIZE in C source code
; CONFIG_DEFINITION_START
; this section was generated automatically by rusEfi tool ConfigDefinition.jar based on gen_config.sh integration/rusefi_config.txt Wed Jul 22 19:41:09 UTC 2020
; this section was generated automatically by rusEfi tool ConfigDefinition.jar based on gen_config.sh integration/rusefi_config.txt Fri Jul 24 15:44:00 UTC 2020
pageSize = 20000
page = 1
@ -1050,7 +1050,7 @@ page = 1
gppwm1_pwmFrequency = scalar, U16, 4146, "hz", 1, 0, 0, 500, 0
gppwm1_onAboveDuty = scalar, U08, 4148, "%", 1, 0, 0, 100, 0
gppwm1_offBelowDuty = scalar, U08, 4149, "%", 1, 0, 0, 100, 0
gppwm1_loadAxis = bits, U08, 4150, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm1_loadAxis = bits, U08, 4150, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm1_alignmentFill_map = scalar, U08, 4151, "unit", 1, 0, 0, 100, 0
gppwm1_loadBins = array, U08, 4152, [8], "load", 1, 0, 0.0, 250, 0
gppwm1_rpmBins = array, U08, 4160, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1060,7 +1060,7 @@ page = 1
gppwm2_pwmFrequency = scalar, U16, 4234, "hz", 1, 0, 0, 500, 0
gppwm2_onAboveDuty = scalar, U08, 4236, "%", 1, 0, 0, 100, 0
gppwm2_offBelowDuty = scalar, U08, 4237, "%", 1, 0, 0, 100, 0
gppwm2_loadAxis = bits, U08, 4238, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm2_loadAxis = bits, U08, 4238, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm2_alignmentFill_map = scalar, U08, 4239, "unit", 1, 0, 0, 100, 0
gppwm2_loadBins = array, U08, 4240, [8], "load", 1, 0, 0.0, 250, 0
gppwm2_rpmBins = array, U08, 4248, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1070,7 +1070,7 @@ page = 1
gppwm3_pwmFrequency = scalar, U16, 4322, "hz", 1, 0, 0, 500, 0
gppwm3_onAboveDuty = scalar, U08, 4324, "%", 1, 0, 0, 100, 0
gppwm3_offBelowDuty = scalar, U08, 4325, "%", 1, 0, 0, 100, 0
gppwm3_loadAxis = bits, U08, 4326, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm3_loadAxis = bits, U08, 4326, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm3_alignmentFill_map = scalar, U08, 4327, "unit", 1, 0, 0, 100, 0
gppwm3_loadBins = array, U08, 4328, [8], "load", 1, 0, 0.0, 250, 0
gppwm3_rpmBins = array, U08, 4336, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1080,7 +1080,7 @@ page = 1
gppwm4_pwmFrequency = scalar, U16, 4410, "hz", 1, 0, 0, 500, 0
gppwm4_onAboveDuty = scalar, U08, 4412, "%", 1, 0, 0, 100, 0
gppwm4_offBelowDuty = scalar, U08, 4413, "%", 1, 0, 0, 100, 0
gppwm4_loadAxis = bits, U08, 4414, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm4_loadAxis = bits, U08, 4414, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm4_alignmentFill_map = scalar, U08, 4415, "unit", 1, 0, 0, 100, 0
gppwm4_loadBins = array, U08, 4416, [8], "load", 1, 0, 0.0, 250, 0
gppwm4_rpmBins = array, U08, 4424, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1631,7 +1631,7 @@ page = 1
rawOilPressure = scalar, U16, 242, "V",{1/1000}, 0.0
; 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
@ -1647,10 +1647,10 @@ page = 1
time = { timeNow }
; 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))}
gppwm2_load = {(gppwm2_loadAxis == 0) ? TPSValue : ((gppwm2_loadAxis == 1) ? MAPValue : ((gppwm2_loadAxis == 2) ? coolant : intake))}
gppwm3_load = {(gppwm3_loadAxis == 0) ? TPSValue : ((gppwm3_loadAxis == 1) ? MAPValue : ((gppwm3_loadAxis == 2) ? coolant : intake))}
gppwm4_load = {(gppwm4_loadAxis == 0) ? TPSValue : ((gppwm4_loadAxis == 1) ? MAPValue : ((gppwm4_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 : ((gppwm2_loadAxis == 3) ? intake : ((gppwm2_loadAxis == 4) ? fuelingLoad : ignitionLoad))))}
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 : ((gppwm4_loadAxis == 3) ? intake : ((gppwm4_loadAxis == 4) ? fuelingLoad : ignitionLoad))))}
[PcVariables]
tuneCrcPcVariable = continuousChannelValue, tuneCrc16

View File

@ -33,12 +33,12 @@ enable2ndByteCanID = false
[MegaTune]
; https://rusefi.com/forum/viewtopic.php?p=36201#p36201
signature = "rusEFI 2020.07.22.mre_f7.1622770353"
signature = "rusEFI 2020.07.24.mre_f7.2843223774"
[TunerStudio]
queryCommand = "S"
versionInfo = "V" ; firmwave version for title bar.
signature = "rusEFI 2020.07.22.mre_f7.1622770353" ; signature is expected to be 7 or more characters.
signature = "rusEFI 2020.07.24.mre_f7.2843223774" ; signature is expected to be 7 or more characters.
[Constants]
; new packet serial format with CRC
@ -76,7 +76,7 @@ enable2ndByteCanID = false
; see PAGE_0_SIZE in C source code
; CONFIG_DEFINITION_START
; this section was generated automatically by rusEfi tool ConfigDefinition.jar based on gen_config.sh integration/rusefi_config.txt Wed Jul 22 19:41:05 UTC 2020
; this section was generated automatically by rusEfi tool ConfigDefinition.jar based on gen_config.sh integration/rusefi_config.txt Fri Jul 24 15:43:59 UTC 2020
pageSize = 20000
page = 1
@ -1050,7 +1050,7 @@ page = 1
gppwm1_pwmFrequency = scalar, U16, 4146, "hz", 1, 0, 0, 500, 0
gppwm1_onAboveDuty = scalar, U08, 4148, "%", 1, 0, 0, 100, 0
gppwm1_offBelowDuty = scalar, U08, 4149, "%", 1, 0, 0, 100, 0
gppwm1_loadAxis = bits, U08, 4150, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm1_loadAxis = bits, U08, 4150, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm1_alignmentFill_map = scalar, U08, 4151, "unit", 1, 0, 0, 100, 0
gppwm1_loadBins = array, U08, 4152, [8], "load", 1, 0, 0.0, 250, 0
gppwm1_rpmBins = array, U08, 4160, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1060,7 +1060,7 @@ page = 1
gppwm2_pwmFrequency = scalar, U16, 4234, "hz", 1, 0, 0, 500, 0
gppwm2_onAboveDuty = scalar, U08, 4236, "%", 1, 0, 0, 100, 0
gppwm2_offBelowDuty = scalar, U08, 4237, "%", 1, 0, 0, 100, 0
gppwm2_loadAxis = bits, U08, 4238, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm2_loadAxis = bits, U08, 4238, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm2_alignmentFill_map = scalar, U08, 4239, "unit", 1, 0, 0, 100, 0
gppwm2_loadBins = array, U08, 4240, [8], "load", 1, 0, 0.0, 250, 0
gppwm2_rpmBins = array, U08, 4248, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1070,7 +1070,7 @@ page = 1
gppwm3_pwmFrequency = scalar, U16, 4322, "hz", 1, 0, 0, 500, 0
gppwm3_onAboveDuty = scalar, U08, 4324, "%", 1, 0, 0, 100, 0
gppwm3_offBelowDuty = scalar, U08, 4325, "%", 1, 0, 0, 100, 0
gppwm3_loadAxis = bits, U08, 4326, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm3_loadAxis = bits, U08, 4326, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm3_alignmentFill_map = scalar, U08, 4327, "unit", 1, 0, 0, 100, 0
gppwm3_loadBins = array, U08, 4328, [8], "load", 1, 0, 0.0, 250, 0
gppwm3_rpmBins = array, U08, 4336, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1080,7 +1080,7 @@ page = 1
gppwm4_pwmFrequency = scalar, U16, 4410, "hz", 1, 0, 0, 500, 0
gppwm4_onAboveDuty = scalar, U08, 4412, "%", 1, 0, 0, 100, 0
gppwm4_offBelowDuty = scalar, U08, 4413, "%", 1, 0, 0, 100, 0
gppwm4_loadAxis = bits, U08, 4414, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm4_loadAxis = bits, U08, 4414, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm4_alignmentFill_map = scalar, U08, 4415, "unit", 1, 0, 0, 100, 0
gppwm4_loadBins = array, U08, 4416, [8], "load", 1, 0, 0.0, 250, 0
gppwm4_rpmBins = array, U08, 4424, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1631,7 +1631,7 @@ page = 1
rawOilPressure = scalar, U16, 242, "V",{1/1000}, 0.0
; 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
@ -1647,10 +1647,10 @@ page = 1
time = { timeNow }
; 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))}
gppwm2_load = {(gppwm2_loadAxis == 0) ? TPSValue : ((gppwm2_loadAxis == 1) ? MAPValue : ((gppwm2_loadAxis == 2) ? coolant : intake))}
gppwm3_load = {(gppwm3_loadAxis == 0) ? TPSValue : ((gppwm3_loadAxis == 1) ? MAPValue : ((gppwm3_loadAxis == 2) ? coolant : intake))}
gppwm4_load = {(gppwm4_loadAxis == 0) ? TPSValue : ((gppwm4_loadAxis == 1) ? MAPValue : ((gppwm4_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 : ((gppwm2_loadAxis == 3) ? intake : ((gppwm2_loadAxis == 4) ? fuelingLoad : ignitionLoad))))}
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 : ((gppwm4_loadAxis == 3) ? intake : ((gppwm4_loadAxis == 4) ? fuelingLoad : ignitionLoad))))}
[PcVariables]
tuneCrcPcVariable = continuousChannelValue, tuneCrc16

View File

@ -33,12 +33,12 @@ enable2ndByteCanID = false
[MegaTune]
; https://rusefi.com/forum/viewtopic.php?p=36201#p36201
signature = "rusEFI 2020.07.22.prometheus_405.3696987323"
signature = "rusEFI 2020.07.24.prometheus_405.362424532"
[TunerStudio]
queryCommand = "S"
versionInfo = "V" ; firmwave version for title bar.
signature = "rusEFI 2020.07.22.prometheus_405.3696987323" ; signature is expected to be 7 or more characters.
signature = "rusEFI 2020.07.24.prometheus_405.362424532" ; signature is expected to be 7 or more characters.
[Constants]
; new packet serial format with CRC
@ -76,7 +76,7 @@ enable2ndByteCanID = false
; see PAGE_0_SIZE in C source code
; CONFIG_DEFINITION_START
; this section was generated automatically by rusEfi tool ConfigDefinition.jar based on gen_config.sh integration/rusefi_config.txt Wed Jul 22 19:41:13 UTC 2020
; this section was generated automatically by rusEfi tool ConfigDefinition.jar based on gen_config.sh integration/rusefi_config.txt Fri Jul 24 15:44:04 UTC 2020
pageSize = 20000
page = 1
@ -1050,7 +1050,7 @@ page = 1
gppwm1_pwmFrequency = scalar, U16, 4146, "hz", 1, 0, 0, 500, 0
gppwm1_onAboveDuty = scalar, U08, 4148, "%", 1, 0, 0, 100, 0
gppwm1_offBelowDuty = scalar, U08, 4149, "%", 1, 0, 0, 100, 0
gppwm1_loadAxis = bits, U08, 4150, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm1_loadAxis = bits, U08, 4150, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm1_alignmentFill_map = scalar, U08, 4151, "unit", 1, 0, 0, 100, 0
gppwm1_loadBins = array, U08, 4152, [8], "load", 1, 0, 0.0, 250, 0
gppwm1_rpmBins = array, U08, 4160, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1060,7 +1060,7 @@ page = 1
gppwm2_pwmFrequency = scalar, U16, 4234, "hz", 1, 0, 0, 500, 0
gppwm2_onAboveDuty = scalar, U08, 4236, "%", 1, 0, 0, 100, 0
gppwm2_offBelowDuty = scalar, U08, 4237, "%", 1, 0, 0, 100, 0
gppwm2_loadAxis = bits, U08, 4238, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm2_loadAxis = bits, U08, 4238, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm2_alignmentFill_map = scalar, U08, 4239, "unit", 1, 0, 0, 100, 0
gppwm2_loadBins = array, U08, 4240, [8], "load", 1, 0, 0.0, 250, 0
gppwm2_rpmBins = array, U08, 4248, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1070,7 +1070,7 @@ page = 1
gppwm3_pwmFrequency = scalar, U16, 4322, "hz", 1, 0, 0, 500, 0
gppwm3_onAboveDuty = scalar, U08, 4324, "%", 1, 0, 0, 100, 0
gppwm3_offBelowDuty = scalar, U08, 4325, "%", 1, 0, 0, 100, 0
gppwm3_loadAxis = bits, U08, 4326, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm3_loadAxis = bits, U08, 4326, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm3_alignmentFill_map = scalar, U08, 4327, "unit", 1, 0, 0, 100, 0
gppwm3_loadBins = array, U08, 4328, [8], "load", 1, 0, 0.0, 250, 0
gppwm3_rpmBins = array, U08, 4336, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1080,7 +1080,7 @@ page = 1
gppwm4_pwmFrequency = scalar, U16, 4410, "hz", 1, 0, 0, 500, 0
gppwm4_onAboveDuty = scalar, U08, 4412, "%", 1, 0, 0, 100, 0
gppwm4_offBelowDuty = scalar, U08, 4413, "%", 1, 0, 0, 100, 0
gppwm4_loadAxis = bits, U08, 4414, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm4_loadAxis = bits, U08, 4414, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm4_alignmentFill_map = scalar, U08, 4415, "unit", 1, 0, 0, 100, 0
gppwm4_loadBins = array, U08, 4416, [8], "load", 1, 0, 0.0, 250, 0
gppwm4_rpmBins = array, U08, 4424, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1631,7 +1631,7 @@ page = 1
rawOilPressure = scalar, U16, 242, "V",{1/1000}, 0.0
; 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
@ -1647,10 +1647,10 @@ page = 1
time = { timeNow }
; 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))}
gppwm2_load = {(gppwm2_loadAxis == 0) ? TPSValue : ((gppwm2_loadAxis == 1) ? MAPValue : ((gppwm2_loadAxis == 2) ? coolant : intake))}
gppwm3_load = {(gppwm3_loadAxis == 0) ? TPSValue : ((gppwm3_loadAxis == 1) ? MAPValue : ((gppwm3_loadAxis == 2) ? coolant : intake))}
gppwm4_load = {(gppwm4_loadAxis == 0) ? TPSValue : ((gppwm4_loadAxis == 1) ? MAPValue : ((gppwm4_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 : ((gppwm2_loadAxis == 3) ? intake : ((gppwm2_loadAxis == 4) ? fuelingLoad : ignitionLoad))))}
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 : ((gppwm4_loadAxis == 3) ? intake : ((gppwm4_loadAxis == 4) ? fuelingLoad : ignitionLoad))))}
[PcVariables]
tuneCrcPcVariable = continuousChannelValue, tuneCrc16

View File

@ -33,12 +33,12 @@ enable2ndByteCanID = false
[MegaTune]
; https://rusefi.com/forum/viewtopic.php?p=36201#p36201
signature = "rusEFI 2020.07.22.prometheus_469.3696987323"
signature = "rusEFI 2020.07.24.prometheus_469.362424532"
[TunerStudio]
queryCommand = "S"
versionInfo = "V" ; firmwave version for title bar.
signature = "rusEFI 2020.07.22.prometheus_469.3696987323" ; signature is expected to be 7 or more characters.
signature = "rusEFI 2020.07.24.prometheus_469.362424532" ; signature is expected to be 7 or more characters.
[Constants]
; new packet serial format with CRC
@ -76,7 +76,7 @@ enable2ndByteCanID = false
; see PAGE_0_SIZE in C source code
; CONFIG_DEFINITION_START
; this section was generated automatically by rusEfi tool ConfigDefinition.jar based on gen_config.sh integration/rusefi_config.txt Wed Jul 22 19:41:11 UTC 2020
; this section was generated automatically by rusEfi tool ConfigDefinition.jar based on gen_config.sh integration/rusefi_config.txt Fri Jul 24 15:44:03 UTC 2020
pageSize = 20000
page = 1
@ -1050,7 +1050,7 @@ page = 1
gppwm1_pwmFrequency = scalar, U16, 4146, "hz", 1, 0, 0, 500, 0
gppwm1_onAboveDuty = scalar, U08, 4148, "%", 1, 0, 0, 100, 0
gppwm1_offBelowDuty = scalar, U08, 4149, "%", 1, 0, 0, 100, 0
gppwm1_loadAxis = bits, U08, 4150, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm1_loadAxis = bits, U08, 4150, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm1_alignmentFill_map = scalar, U08, 4151, "unit", 1, 0, 0, 100, 0
gppwm1_loadBins = array, U08, 4152, [8], "load", 1, 0, 0.0, 250, 0
gppwm1_rpmBins = array, U08, 4160, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1060,7 +1060,7 @@ page = 1
gppwm2_pwmFrequency = scalar, U16, 4234, "hz", 1, 0, 0, 500, 0
gppwm2_onAboveDuty = scalar, U08, 4236, "%", 1, 0, 0, 100, 0
gppwm2_offBelowDuty = scalar, U08, 4237, "%", 1, 0, 0, 100, 0
gppwm2_loadAxis = bits, U08, 4238, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm2_loadAxis = bits, U08, 4238, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm2_alignmentFill_map = scalar, U08, 4239, "unit", 1, 0, 0, 100, 0
gppwm2_loadBins = array, U08, 4240, [8], "load", 1, 0, 0.0, 250, 0
gppwm2_rpmBins = array, U08, 4248, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1070,7 +1070,7 @@ page = 1
gppwm3_pwmFrequency = scalar, U16, 4322, "hz", 1, 0, 0, 500, 0
gppwm3_onAboveDuty = scalar, U08, 4324, "%", 1, 0, 0, 100, 0
gppwm3_offBelowDuty = scalar, U08, 4325, "%", 1, 0, 0, 100, 0
gppwm3_loadAxis = bits, U08, 4326, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm3_loadAxis = bits, U08, 4326, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm3_alignmentFill_map = scalar, U08, 4327, "unit", 1, 0, 0, 100, 0
gppwm3_loadBins = array, U08, 4328, [8], "load", 1, 0, 0.0, 250, 0
gppwm3_rpmBins = array, U08, 4336, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1080,7 +1080,7 @@ page = 1
gppwm4_pwmFrequency = scalar, U16, 4410, "hz", 1, 0, 0, 500, 0
gppwm4_onAboveDuty = scalar, U08, 4412, "%", 1, 0, 0, 100, 0
gppwm4_offBelowDuty = scalar, U08, 4413, "%", 1, 0, 0, 100, 0
gppwm4_loadAxis = bits, U08, 4414, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm4_loadAxis = bits, U08, 4414, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm4_alignmentFill_map = scalar, U08, 4415, "unit", 1, 0, 0, 100, 0
gppwm4_loadBins = array, U08, 4416, [8], "load", 1, 0, 0.0, 250, 0
gppwm4_rpmBins = array, U08, 4424, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1631,7 +1631,7 @@ page = 1
rawOilPressure = scalar, U16, 242, "V",{1/1000}, 0.0
; 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
@ -1647,10 +1647,10 @@ page = 1
time = { timeNow }
; 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))}
gppwm2_load = {(gppwm2_loadAxis == 0) ? TPSValue : ((gppwm2_loadAxis == 1) ? MAPValue : ((gppwm2_loadAxis == 2) ? coolant : intake))}
gppwm3_load = {(gppwm3_loadAxis == 0) ? TPSValue : ((gppwm3_loadAxis == 1) ? MAPValue : ((gppwm3_loadAxis == 2) ? coolant : intake))}
gppwm4_load = {(gppwm4_loadAxis == 0) ? TPSValue : ((gppwm4_loadAxis == 1) ? MAPValue : ((gppwm4_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 : ((gppwm2_loadAxis == 3) ? intake : ((gppwm2_loadAxis == 4) ? fuelingLoad : ignitionLoad))))}
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 : ((gppwm4_loadAxis == 3) ? intake : ((gppwm4_loadAxis == 4) ? fuelingLoad : ignitionLoad))))}
[PcVariables]
tuneCrcPcVariable = continuousChannelValue, tuneCrc16

View File

@ -33,12 +33,12 @@ enable2ndByteCanID = false
[MegaTune]
; https://rusefi.com/forum/viewtopic.php?p=36201#p36201
signature = "rusEFI 2020.07.22.proteus_f4.2765497840"
signature = "rusEFI 2020.07.24.proteus_f4.1830257055"
[TunerStudio]
queryCommand = "S"
versionInfo = "V" ; firmwave version for title bar.
signature = "rusEFI 2020.07.22.proteus_f4.2765497840" ; signature is expected to be 7 or more characters.
signature = "rusEFI 2020.07.24.proteus_f4.1830257055" ; signature is expected to be 7 or more characters.
[Constants]
; new packet serial format with CRC
@ -76,7 +76,7 @@ enable2ndByteCanID = false
; see PAGE_0_SIZE in C source code
; CONFIG_DEFINITION_START
; this section was generated automatically by rusEfi tool ConfigDefinition.jar based on gen_config.sh integration/rusefi_config.txt Wed Jul 22 19:41:16 UTC 2020
; this section was generated automatically by rusEfi tool ConfigDefinition.jar based on gen_config.sh integration/rusefi_config.txt Fri Jul 24 15:44:07 UTC 2020
pageSize = 20000
page = 1
@ -1050,7 +1050,7 @@ page = 1
gppwm1_pwmFrequency = scalar, U16, 4146, "hz", 1, 0, 0, 500, 0
gppwm1_onAboveDuty = scalar, U08, 4148, "%", 1, 0, 0, 100, 0
gppwm1_offBelowDuty = scalar, U08, 4149, "%", 1, 0, 0, 100, 0
gppwm1_loadAxis = bits, U08, 4150, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm1_loadAxis = bits, U08, 4150, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm1_alignmentFill_map = scalar, U08, 4151, "unit", 1, 0, 0, 100, 0
gppwm1_loadBins = array, U08, 4152, [8], "load", 1, 0, 0.0, 250, 0
gppwm1_rpmBins = array, U08, 4160, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1060,7 +1060,7 @@ page = 1
gppwm2_pwmFrequency = scalar, U16, 4234, "hz", 1, 0, 0, 500, 0
gppwm2_onAboveDuty = scalar, U08, 4236, "%", 1, 0, 0, 100, 0
gppwm2_offBelowDuty = scalar, U08, 4237, "%", 1, 0, 0, 100, 0
gppwm2_loadAxis = bits, U08, 4238, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm2_loadAxis = bits, U08, 4238, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm2_alignmentFill_map = scalar, U08, 4239, "unit", 1, 0, 0, 100, 0
gppwm2_loadBins = array, U08, 4240, [8], "load", 1, 0, 0.0, 250, 0
gppwm2_rpmBins = array, U08, 4248, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1070,7 +1070,7 @@ page = 1
gppwm3_pwmFrequency = scalar, U16, 4322, "hz", 1, 0, 0, 500, 0
gppwm3_onAboveDuty = scalar, U08, 4324, "%", 1, 0, 0, 100, 0
gppwm3_offBelowDuty = scalar, U08, 4325, "%", 1, 0, 0, 100, 0
gppwm3_loadAxis = bits, U08, 4326, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm3_loadAxis = bits, U08, 4326, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm3_alignmentFill_map = scalar, U08, 4327, "unit", 1, 0, 0, 100, 0
gppwm3_loadBins = array, U08, 4328, [8], "load", 1, 0, 0.0, 250, 0
gppwm3_rpmBins = array, U08, 4336, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1080,7 +1080,7 @@ page = 1
gppwm4_pwmFrequency = scalar, U16, 4410, "hz", 1, 0, 0, 500, 0
gppwm4_onAboveDuty = scalar, U08, 4412, "%", 1, 0, 0, 100, 0
gppwm4_offBelowDuty = scalar, U08, 4413, "%", 1, 0, 0, 100, 0
gppwm4_loadAxis = bits, U08, 4414, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm4_loadAxis = bits, U08, 4414, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm4_alignmentFill_map = scalar, U08, 4415, "unit", 1, 0, 0, 100, 0
gppwm4_loadBins = array, U08, 4416, [8], "load", 1, 0, 0.0, 250, 0
gppwm4_rpmBins = array, U08, 4424, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1631,7 +1631,7 @@ page = 1
rawOilPressure = scalar, U16, 242, "V",{1/1000}, 0.0
; 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
@ -1647,10 +1647,10 @@ page = 1
time = { timeNow }
; 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))}
gppwm2_load = {(gppwm2_loadAxis == 0) ? TPSValue : ((gppwm2_loadAxis == 1) ? MAPValue : ((gppwm2_loadAxis == 2) ? coolant : intake))}
gppwm3_load = {(gppwm3_loadAxis == 0) ? TPSValue : ((gppwm3_loadAxis == 1) ? MAPValue : ((gppwm3_loadAxis == 2) ? coolant : intake))}
gppwm4_load = {(gppwm4_loadAxis == 0) ? TPSValue : ((gppwm4_loadAxis == 1) ? MAPValue : ((gppwm4_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 : ((gppwm2_loadAxis == 3) ? intake : ((gppwm2_loadAxis == 4) ? fuelingLoad : ignitionLoad))))}
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 : ((gppwm4_loadAxis == 3) ? intake : ((gppwm4_loadAxis == 4) ? fuelingLoad : ignitionLoad))))}
[PcVariables]
tuneCrcPcVariable = continuousChannelValue, tuneCrc16

View File

@ -33,12 +33,12 @@ enable2ndByteCanID = false
[MegaTune]
; https://rusefi.com/forum/viewtopic.php?p=36201#p36201
signature = "rusEFI 2020.07.22.proteus_f7.2765497840"
signature = "rusEFI 2020.07.24.proteus_f7.1830257055"
[TunerStudio]
queryCommand = "S"
versionInfo = "V" ; firmwave version for title bar.
signature = "rusEFI 2020.07.22.proteus_f7.2765497840" ; signature is expected to be 7 or more characters.
signature = "rusEFI 2020.07.24.proteus_f7.1830257055" ; signature is expected to be 7 or more characters.
[Constants]
; new packet serial format with CRC
@ -76,7 +76,7 @@ enable2ndByteCanID = false
; see PAGE_0_SIZE in C source code
; CONFIG_DEFINITION_START
; this section was generated automatically by rusEfi tool ConfigDefinition.jar based on gen_config.sh integration/rusefi_config.txt Wed Jul 22 19:41:14 UTC 2020
; this section was generated automatically by rusEfi tool ConfigDefinition.jar based on gen_config.sh integration/rusefi_config.txt Fri Jul 24 15:44:06 UTC 2020
pageSize = 20000
page = 1
@ -1050,7 +1050,7 @@ page = 1
gppwm1_pwmFrequency = scalar, U16, 4146, "hz", 1, 0, 0, 500, 0
gppwm1_onAboveDuty = scalar, U08, 4148, "%", 1, 0, 0, 100, 0
gppwm1_offBelowDuty = scalar, U08, 4149, "%", 1, 0, 0, 100, 0
gppwm1_loadAxis = bits, U08, 4150, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm1_loadAxis = bits, U08, 4150, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm1_alignmentFill_map = scalar, U08, 4151, "unit", 1, 0, 0, 100, 0
gppwm1_loadBins = array, U08, 4152, [8], "load", 1, 0, 0.0, 250, 0
gppwm1_rpmBins = array, U08, 4160, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1060,7 +1060,7 @@ page = 1
gppwm2_pwmFrequency = scalar, U16, 4234, "hz", 1, 0, 0, 500, 0
gppwm2_onAboveDuty = scalar, U08, 4236, "%", 1, 0, 0, 100, 0
gppwm2_offBelowDuty = scalar, U08, 4237, "%", 1, 0, 0, 100, 0
gppwm2_loadAxis = bits, U08, 4238, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm2_loadAxis = bits, U08, 4238, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm2_alignmentFill_map = scalar, U08, 4239, "unit", 1, 0, 0, 100, 0
gppwm2_loadBins = array, U08, 4240, [8], "load", 1, 0, 0.0, 250, 0
gppwm2_rpmBins = array, U08, 4248, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1070,7 +1070,7 @@ page = 1
gppwm3_pwmFrequency = scalar, U16, 4322, "hz", 1, 0, 0, 500, 0
gppwm3_onAboveDuty = scalar, U08, 4324, "%", 1, 0, 0, 100, 0
gppwm3_offBelowDuty = scalar, U08, 4325, "%", 1, 0, 0, 100, 0
gppwm3_loadAxis = bits, U08, 4326, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm3_loadAxis = bits, U08, 4326, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm3_alignmentFill_map = scalar, U08, 4327, "unit", 1, 0, 0, 100, 0
gppwm3_loadBins = array, U08, 4328, [8], "load", 1, 0, 0.0, 250, 0
gppwm3_rpmBins = array, U08, 4336, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1080,7 +1080,7 @@ page = 1
gppwm4_pwmFrequency = scalar, U16, 4410, "hz", 1, 0, 0, 500, 0
gppwm4_onAboveDuty = scalar, U08, 4412, "%", 1, 0, 0, 100, 0
gppwm4_offBelowDuty = scalar, U08, 4413, "%", 1, 0, 0, 100, 0
gppwm4_loadAxis = bits, U08, 4414, [0:1], "TPS", "MAP", "CLT", "IAT"
gppwm4_loadAxis = bits, U08, 4414, [0:2], "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"
gppwm4_alignmentFill_map = scalar, U08, 4415, "unit", 1, 0, 0, 100, 0
gppwm4_loadBins = array, U08, 4416, [8], "load", 1, 0, 0.0, 250, 0
gppwm4_rpmBins = array, U08, 4424, [8], "RPM", 50, 0, 0.0, 12000.0, 0
@ -1631,7 +1631,7 @@ page = 1
rawOilPressure = scalar, U16, 242, "V",{1/1000}, 0.0
; 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
@ -1647,10 +1647,10 @@ page = 1
time = { timeNow }
; 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))}
gppwm2_load = {(gppwm2_loadAxis == 0) ? TPSValue : ((gppwm2_loadAxis == 1) ? MAPValue : ((gppwm2_loadAxis == 2) ? coolant : intake))}
gppwm3_load = {(gppwm3_loadAxis == 0) ? TPSValue : ((gppwm3_loadAxis == 1) ? MAPValue : ((gppwm3_loadAxis == 2) ? coolant : intake))}
gppwm4_load = {(gppwm4_loadAxis == 0) ? TPSValue : ((gppwm4_loadAxis == 1) ? MAPValue : ((gppwm4_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 : ((gppwm2_loadAxis == 3) ? intake : ((gppwm2_loadAxis == 4) ? fuelingLoad : ignitionLoad))))}
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 : ((gppwm4_loadAxis == 3) ? intake : ((gppwm4_loadAxis == 4) ? fuelingLoad : ignitionLoad))))}
[PcVariables]
tuneCrcPcVariable = continuousChannelValue, tuneCrc16

View File

@ -347,7 +347,7 @@ enable2ndByteCanID = false
rawOilPressure = scalar, U16, 242, "V",{1/@@PACK_MULT_VOLTAGE@@}, 0.0
; 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
@ -363,10 +363,10 @@ enable2ndByteCanID = false
time = { timeNow }
; 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))}
gppwm2_load = {(gppwm2_loadAxis == 0) ? TPSValue : ((gppwm2_loadAxis == 1) ? MAPValue : ((gppwm2_loadAxis == 2) ? coolant : intake))}
gppwm3_load = {(gppwm3_loadAxis == 0) ? TPSValue : ((gppwm3_loadAxis == 1) ? MAPValue : ((gppwm3_loadAxis == 2) ? coolant : intake))}
gppwm4_load = {(gppwm4_loadAxis == 0) ? TPSValue : ((gppwm4_loadAxis == 1) ? MAPValue : ((gppwm4_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 : ((gppwm2_loadAxis == 3) ? intake : ((gppwm2_loadAxis == 4) ? fuelingLoad : ignitionLoad))))}
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 : ((gppwm4_loadAxis == 3) ? intake : ((gppwm4_loadAxis == 4) ? fuelingLoad : ignitionLoad))))}
[PcVariables]
tuneCrcPcVariable = continuousChannelValue, tuneCrc16

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -555,7 +555,7 @@ public class AutoTest {
boolean failed = false;
try {
LinkManager linkManager = new LinkManager(FileLog.LOGGER);
LinkManager linkManager = new LinkManager();
IoUtil.connectToSimulator(linkManager, startSimulator);
new AutoTest(linkManager, linkManager.getCommandQueue()).mainTestBody();
} catch (Throwable e) {

View File

@ -12,7 +12,7 @@ public class EnduranceTest {
private static final int DEFAULT_COUNT = 2000;
public static void main(String[] args) {
LinkManager linkManager = new LinkManager(FileLog.LOGGER);
LinkManager linkManager = new LinkManager();
CommandQueue commandQueue = linkManager.getCommandQueue();
long start = System.currentTimeMillis();
int count = parseCount(args);

View File

@ -1,6 +1,5 @@
package com.rusefi;
import com.rusefi.io.CommandQueue;
import com.rusefi.io.LinkManager;
import org.jetbrains.annotations.NotNull;
@ -83,7 +82,7 @@ public class RealHwTest {
}
private static void runRealHardwareTest(String port) throws Exception {
LinkManager linkManager = new LinkManager(FileLog.LOGGER);
LinkManager linkManager = new LinkManager();
IoUtil.realHardwareConnect(linkManager, port);
new AutoTest(linkManager, linkManager.getCommandQueue()).mainTestBody();
}

View File

@ -0,0 +1 @@
java -jar console/rusefi_console.jar dfu $1

View File

@ -2,7 +2,7 @@
<property name="jar_file_folder" value="../java_console_binary"/>
<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="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">
<delete dir="build"/>
@ -111,6 +111,9 @@
<zipfileset src="lib/server/cactoos.jar" includes="**/*.class"/>
<zipfileset src="lib/server/javax.json.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>
</target>
@ -148,6 +151,14 @@
<zipfileset src="lib/httpmime.jar" includes="**/*.class"/>
<zipfileset src="lib/jaxb-api.jar" includes="**/*.class"/>
<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/miglayout-4.0.jar" includes="**/*.class"/>
<zipfileset src="lib/surfaceplotter-2.0.1.jar" includes="**/*.class **/*.properties"/>

View File

@ -12,6 +12,8 @@ public interface WriteStream {
*/
void write(byte[] bytes) throws IOException;
void flush() throws IOException;
default void write(byte value) throws IOException {
write(new byte[]{value});
}

View File

@ -1,51 +1,55 @@
package com.rusefi;
import com.devexperts.logging.Logging;
import com.opensr5.Logger;
import com.rusefi.core.MessagesCentral;
import com.rusefi.io.IoStream;
import com.rusefi.io.commands.HelloCommand;
import com.rusefi.io.tcp.BinaryProtocolProxy;
import com.rusefi.io.tcp.ServerHolder;
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;
import static com.devexperts.logging.Logging.getLogging;
public class LocalApplicationProxy {
private static final Logging log = getLogging(LocalApplicationProxy.class);
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;
public LocalApplicationProxy(ApplicationRequest applicationRequest) {
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
* @param localApplicationPort local port we would bind for TunerStudio to connect to
* @param jsonHttpPort
* @param disconnectListener
*/
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);
public static ServerHolder startAndRun(int serverPortForRemoteUsers, ApplicationRequest applicationRequest, int localApplicationPort, int jsonHttpPort, TcpIoStream.DisconnectListener disconnectListener) throws IOException {
String version = HttpUtil.executeGet(ProxyClient.getHttpAddress(jsonHttpPort) + ProxyClient.VERSION_PATH);
log.info("Server says 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);
IoStream authenticatorToProxyStream = new TcpIoStream("authenticatorToProxyStream ", rusEFISSLContext.getSSLSocket(HttpUtil.RUSEFI_PROXY_HOSTNAME, serverPortForRemoteUsers), disconnectListener);
LocalApplicationProxy localApplicationProxy = new LocalApplicationProxy(applicationRequest);
log.info("Pushing " + applicationRequest);
localApplicationProxy.run(authenticatorToProxyStream);
BinaryProtocolProxy.createProxy(logger, authenticatorToProxyStream, authenticatorPort);
return BinaryProtocolProxy.createProxy(authenticatorToProxyStream, localApplicationPort);
}
public void run(IoStream authenticatorToProxyStream) throws IOException {
// right from connection push session authentication data
new HelloCommand(logger, applicationRequest.toJson()).handle(authenticatorToProxyStream);
new HelloCommand(applicationRequest.toJson()).handle(authenticatorToProxyStream);
}
public static void start(String[] strings) {

View File

@ -1,5 +1,6 @@
package com.rusefi.binaryprotocol;
import com.devexperts.logging.Logging;
import com.opensr5.ConfigurationImage;
import com.opensr5.Logger;
import com.opensr5.io.ConfigurationImageFile;
@ -12,6 +13,7 @@ import com.rusefi.config.generated.Fields;
import com.rusefi.core.*;
import com.rusefi.io.*;
import com.rusefi.io.commands.GetOutputsCommand;
import com.rusefi.io.serial.PortHolder;
import com.rusefi.stream.LogicdataStreamFile;
import com.rusefi.stream.StreamFile;
import com.rusefi.stream.TSHighSpeedLog;
@ -33,6 +35,7 @@ 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.*;
/**
@ -45,6 +48,7 @@ import static com.rusefi.binaryprotocol.IoHelper.*;
* 3/6/2015
*/
public class BinaryProtocol implements BinaryProtocolCommands {
private static final Logging log = getLogging(BinaryProtocol.class);
private static final String USE_PLAIN_PROTOCOL_PROPERTY = "protocol.plain";
private static final String CONFIGURATION_RUSEFI_BINARY = "current_configuration.rusefi_binary";
@ -57,7 +61,6 @@ public class BinaryProtocol implements BinaryProtocolCommands {
public static boolean PLAIN_PROTOCOL = Boolean.getBoolean(USE_PLAIN_PROTOCOL_PROPERTY);
private final LinkManager linkManager;
private final Logger logger;
private final IoStream stream;
private final IncomingDataBuffer incomingData;
private boolean isBurnPending;
@ -130,15 +133,14 @@ public class BinaryProtocol implements BinaryProtocolCommands {
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.logger = logger;
this.stream = stream;
communicationLoggingListener = new CommunicationLoggingListener() {
@Override
public void onPortHolderMessage(Class clazz, String message) {
MessagesCentral.getInstance().postMessage(logger, clazz, message);
MessagesCentral.getInstance().postMessage(clazz, message);
}
};
@ -150,7 +152,7 @@ public class BinaryProtocol implements BinaryProtocolCommands {
needCompositeLogger = linkManager.getCompositeLogicEnabled();
lastLowRpmTime = System.currentTimeMillis();
} 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;
}
};
@ -175,7 +177,7 @@ public class BinaryProtocol implements BinaryProtocolCommands {
}
public void doSend(final String command, boolean fireEvent) throws InterruptedException {
logger.info("Sending [" + command + "]");
log.info("Sending [" + command + "]");
if (fireEvent && LinkManager.LOG_LEVEL.isDebugEnabled()) {
communicationLoggingListener.onPortHolderMessage(BinaryProtocol.class, "Sending [" + command + "]");
}
@ -197,7 +199,7 @@ public class BinaryProtocol implements BinaryProtocolCommands {
} catch (ExecutionException e) {
throw new IllegalStateException(e);
} catch (TimeoutException e) {
getLogger().error("timeout sending [" + command + "] giving up: " + e);
log.error("timeout sending [" + command + "] giving up: " + e);
return;
}
/**
@ -247,7 +249,7 @@ public class BinaryProtocol implements BinaryProtocolCommands {
}
sleep(Timeouts.TEXT_PULL_PERIOD);
}
logger.info("Stopping text pull");
log.info("Stopping text pull");
}
};
Thread tr = new Thread(textPull);
@ -275,10 +277,6 @@ public class BinaryProtocol implements BinaryProtocolCommands {
compositeLogs.clear();
}
public Logger getLogger() {
return logger;
}
private void dropPending() {
synchronized (ioLock) {
if (isClosed)
@ -315,7 +313,7 @@ public class BinaryProtocol implements BinaryProtocolCommands {
private byte[] receivePacket(String msg, boolean allowLongResponse) throws EOFException {
long start = System.currentTimeMillis();
synchronized (ioLock) {
return incomingData.getPacket(logger, msg, allowLongResponse, start);
return incomingData.getPacket(msg, allowLongResponse, start);
}
}
@ -331,7 +329,7 @@ public class BinaryProtocol implements BinaryProtocolCommands {
return;
}
setController(image);
logger.info("Got configuration from controller.");
log.info("Got configuration from controller.");
ConnectionStatusLogic.INSTANCE.setValue(ConnectionStatusValue.CONNECTED);
}
@ -343,7 +341,7 @@ public class BinaryProtocol implements BinaryProtocolCommands {
int offset = 0;
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)) {
if (isClosed)
@ -363,7 +361,7 @@ public class BinaryProtocol implements BinaryProtocolCommands {
if (!checkResponseCode(response, RESPONSE_OK) || response.length != requestSize + 1) {
String code = (response == null || response.length == 0) ? "empty" : "code " + response[0];
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;
}
@ -435,7 +433,7 @@ public class BinaryProtocol implements BinaryProtocolCommands {
sendPacket(packet);
return receivePacket(msg, allowLongResponse);
} catch (IOException e) {
logger.error(msg + ": executeCommand failed: " + e);
log.error(msg + ": executeCommand failed: " + e);
close();
return null;
}
@ -509,7 +507,7 @@ public class BinaryProtocol implements BinaryProtocolCommands {
}
private void sendPacket(byte[] command) throws IOException {
stream.sendPacket(command, logger);
stream.sendPacket(command);
}
@ -549,7 +547,7 @@ public class BinaryProtocol implements BinaryProtocolCommands {
Thread.sleep(100);
return new String(response, 1, response.length - 1);
} catch (InterruptedException e) {
logger.error(e.toString());
log.error(e.toString());
return null;
}
}

View File

@ -1,6 +1,6 @@
package com.rusefi.binaryprotocol;
import com.opensr5.Logger;
import com.devexperts.logging.Logging;
import com.rusefi.Timeouts;
import com.rusefi.config.generated.Fields;
import com.rusefi.io.IoStream;
@ -13,6 +13,7 @@ import java.io.IOException;
import java.util.Arrays;
import java.util.Objects;
import static com.devexperts.logging.Logging.getLogging;
import static com.rusefi.binaryprotocol.IoHelper.*;
/**
@ -23,39 +24,40 @@ import static com.rusefi.binaryprotocol.IoHelper.*;
*/
@ThreadSafe
public class IncomingDataBuffer {
private static final Logging log = getLogging(IoStream.class);
private static final int BUFFER_SIZE = 32768;
private static String loggingPrefix;
/**
* buffer for response bytes from controller
*/
private final CircularByteBuffer cbb;
private final Logger logger;
private final AbstractIoStream.StreamStats streamStats;
public IncomingDataBuffer(Logger logger, AbstractIoStream.StreamStats streamStats) {
public IncomingDataBuffer(AbstractIoStream.StreamStats streamStats) {
this.streamStats = Objects.requireNonNull(streamStats, "streamStats");
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 incomingData = new IncomingDataBuffer(logger, stream.getStreamStats());
IncomingDataBuffer incomingData = new IncomingDataBuffer(stream.getStreamStats());
stream.setInputListener(incomingData::addData);
return incomingData;
}
public byte[] getPacket(Logger logger, String msg, boolean allowLongResponse) throws EOFException {
return getPacket(logger, msg, allowLongResponse, System.currentTimeMillis());
public byte[] getPacket(String msg, boolean allowLongResponse) throws EOFException {
return getPacket(msg, allowLongResponse, System.currentTimeMillis());
}
public byte[] getPacket(Logger logger, String msg, boolean allowLongResponse, long start) throws EOFException {
public byte[] getPacket(String msg, boolean allowLongResponse, long start) throws EOFException {
boolean isTimeout = waitForBytes(msg + " header", start, 2);
if (isTimeout)
return null;
int packetSize = swap16(getShort());
logger.trace( loggingPrefix + "Got packet size " + packetSize);
if (log.debugEnabled())
log.debug(loggingPrefix + "Got packet size " + packetSize);
if (packetSize < 0)
return null;
if (!allowLongResponse && packetSize > Math.max(BinaryProtocolCommands.BLOCKING_FACTOR, Fields.TS_OUTPUT_SIZE) + 10)
@ -72,20 +74,22 @@ public class IncomingDataBuffer {
boolean isCrcOk = actualCrc == packetCrc;
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;
}
streamStats.onPacketArrived();
logger.trace("packet " + Arrays.toString(packet) + ": crc OK");
if (log.debugEnabled())
log.debug("packet " + Arrays.toString(packet) + ": crc OK");
return packet;
}
public void addData(byte[] freshData) {
logger.info("IncomingDataBuffer: " + freshData.length + " byte(s) arrived");
log.info("IncomingDataBuffer: " + freshData.length + " byte(s) arrived");
synchronized (cbb) {
if (cbb.size() - cbb.length() < freshData.length) {
logger.error("IncomingDataBuffer: buffer overflow not expected");
log.error("IncomingDataBuffer: buffer overflow not expected");
cbb.clear();
}
cbb.put(freshData);
@ -103,12 +107,12 @@ public class IncomingDataBuffer {
}
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) {
while (cbb.length() < count) {
int timeout = (int) (startTimestamp + timeoutMs - System.currentTimeMillis());
if (timeout <= 0) {
logger.info(loggingMessage + ": timeout. Got only " + cbb.length());
log.info(loggingMessage + ": timeout. Got only " + cbb.length());
return true; // timeout. Sad face.
}
try {
@ -126,10 +130,10 @@ public class IncomingDataBuffer {
synchronized (cbb) {
int pending = cbb.length();
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];
cbb.get(bytes);
logger.error("data: " + Arrays.toString(bytes));
log.error("data: " + Arrays.toString(bytes));
}
}
}
@ -163,7 +167,7 @@ public class IncomingDataBuffer {
}
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)
throw new IOException("Timeout in readByte");
return (byte) getByte();

View File

@ -1,6 +1,5 @@
package com.rusefi.file;
import com.opensr5.Logger;
import com.rusefi.core.EngineState;
import com.rusefi.io.LinkManager;
@ -12,8 +11,8 @@ import java.util.List;
* Andrey Belomutskiy, (c) 2013-2020
*/
public class FileUtils {
public static void readFile(String filename, EngineState.EngineStateListener listener, Logger logger) {
readFile2(filename, new EngineState(listener, logger));
public static void readFile(String filename, EngineState.EngineStateListener listener) {
readFile2(filename, new EngineState(listener));
}
public static void readFile2(String filename, EngineState engineState) {

View File

@ -1,15 +1,23 @@
package com.rusefi.io;
import com.devexperts.logging.Logging;
import com.opensr5.Logger;
import com.opensr5.io.DataListener;
import com.rusefi.config.generated.Fields;
import com.rusefi.io.tcp.BinaryProtocolServer;
import com.rusefi.io.tcp.TcpIoStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import static com.devexperts.logging.Logging.getLogging;
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, TcpIoStream.DisconnectListener disconnectListener) {
/**
* Threading of the whole input/output does not look healthy at all!
*
@ -23,9 +31,9 @@ public interface ByteReader {
threadExecutor.execute(() -> {
Thread.currentThread().setName("TCP connector loop");
logger.info(loggingPrefix + "Running TCP connection loop");
log.info(loggingPrefix + "Running TCP connection loop");
byte inputBuffer[] = new byte[256];
byte inputBuffer[] = new byte[Fields.BLOCKING_FACTOR * 2];
while (true) {
try {
int result = reader.read(inputBuffer);
@ -33,7 +41,8 @@ public interface ByteReader {
throw new IOException("TcpIoStream: End of input?");
listener.onDataArrived(Arrays.copyOf(inputBuffer, result));
} catch (IOException e) {
System.err.println("TcpIoStream: End of connection");
log.error("TcpIoStream: End of connection " + e);
disconnectListener.onDisconnect();
return;
}
}

View File

@ -1,6 +1,6 @@
package com.rusefi.io;
import com.opensr5.Logger;
import com.devexperts.logging.Logging;
import com.rusefi.config.generated.Fields;
import com.rusefi.core.MessagesCentral;
import org.jetbrains.annotations.NotNull;
@ -9,6 +9,8 @@ import java.util.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import static com.devexperts.logging.Logging.getLogging;
/**
* This singleton keeps re-sending commands till a proper confirmation is received
*
@ -18,6 +20,7 @@ import java.util.concurrent.LinkedBlockingQueue;
*/
@SuppressWarnings("FieldCanBeLocal")
public class CommandQueue {
private static final Logging log = getLogging(LinkManager.class);
public static final String CONFIRMATION_PREFIX = "confirmation_";
public static final int DEFAULT_TIMEOUT = 500;
private static final int COMMAND_CONFIRMATION_TIMEOUT = 1000;
@ -36,7 +39,6 @@ public class CommandQueue {
private final List<CommandQueueListener> commandListeners = new ArrayList<>();
private final Runnable runnable;
private final Logger logger;
private static boolean isSlowCommand(String cmd) {
String lc = cmd.toLowerCase();
@ -98,27 +100,26 @@ public class CommandQueue {
}
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;
runnable = new Runnable() {
@SuppressWarnings("InfiniteLoopStatement")
@Override
public void run() {
MessagesCentral.getInstance().postMessage(logger, COMMAND_QUEUE_CLASS, "SerialIO started");
MessagesCentral.getInstance().postMessage(COMMAND_QUEUE_CLASS, "SerialIO started");
while (true) {
try {
sendPendingCommand();
} catch (Throwable e) {
logger.error("CommandQueue error" + e);
log.error("CommandQueue error" + e);
System.exit(-2);
}
}
}
};
this.logger = logger;
Thread thread = new Thread(runnable, "Commands Queue");
thread.setDaemon(true);
thread.start();
@ -136,10 +137,10 @@ public class CommandQueue {
MessagesCentral mc = MessagesCentral.getInstance();
String confirmation = LinkManager.unpackConfirmation(message);
if (confirmation == null)
mc.postMessage(logger, CommandQueue.class, "Broken confirmation length: " + message);
mc.postMessage(CommandQueue.class, "Broken confirmation length: " + message);
pendingConfirmations.add(confirmation);
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());

View File

@ -1,16 +1,15 @@
package com.rusefi.io;
import com.opensr5.Logger;
import com.rusefi.binaryprotocol.BinaryProtocol;
import com.rusefi.config.generated.Fields;
import java.io.IOException;
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);
try {
stream.sendPacket(command, logger);
stream.sendPacket(command);
stream.close();
messages.append("Reboot command sent!\n");
} catch (IOException e) {

View File

@ -1,5 +1,6 @@
package com.rusefi.io;
import com.devexperts.logging.Logging;
import com.opensr5.Logger;
import com.opensr5.io.DataListener;
import com.opensr5.io.WriteStream;
@ -13,6 +14,8 @@ import org.jetbrains.annotations.NotNull;
import java.io.EOFException;
import java.io.IOException;
import static com.devexperts.logging.Logging.getLogging;
/**
* Physical bi-directional controller communication level
* <p>
@ -21,6 +24,7 @@ import java.io.IOException;
* 5/11/2015.
*/
public interface IoStream extends WriteStream {
Logging log = getLogging(IoStream.class);
static String printHexBinary(byte[] data) {
char[] hexCode = "0123456789ABCDEF".toCharArray();
@ -44,9 +48,10 @@ public interface IoStream extends WriteStream {
writeShort(packet.getPacket().length);
write(packet.getPacket());
writeInt(packet.getCrc());
flush();
}
default void sendPacket(byte[] plainPacket, Logger logger) throws IOException {
default void sendPacket(byte[] plainPacket) throws IOException {
byte[] packet;
if (BinaryProtocol.PLAIN_PROTOCOL) {
packet = plainPacket;
@ -54,8 +59,9 @@ public interface IoStream extends WriteStream {
packet = IoHelper.makeCrc32Packet(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);
flush();
}
/**

View File

@ -1,7 +1,7 @@
package com.rusefi.io;
import com.devexperts.logging.Logging;
import com.fazecast.jSerialComm.SerialPort;
import com.opensr5.Logger;
import com.rusefi.Callable;
import com.rusefi.NamedThreadFactory;
import com.rusefi.binaryprotocol.BinaryProtocol;
@ -19,6 +19,8 @@ import java.util.Arrays;
import java.util.Objects;
import java.util.concurrent.*;
import static com.devexperts.logging.Logging.getLogging;
/**
* See TcpCommunicationIntegrationTest
*
@ -26,6 +28,8 @@ import java.util.concurrent.*;
* 3/3/14
*/
public class LinkManager implements Closeable {
private static final Logging log = getLogging(LinkManager.class);
@NotNull
public static LogLevel LOG_LEVEL = LogLevel.INFO;
@ -38,23 +42,21 @@ public class LinkManager implements Closeable {
public static final String LOG_VIEWER = "log viewer";
private final CommandQueue commandQueue;
private final Logger logger;
private LinkConnector connector;
private boolean isStarted;
private boolean compositeLogicEnabled = true;
private boolean needPullData = true;
public LinkManager(Logger logger) {
this.logger = logger;
public LinkManager() {
engineState = new EngineState(new EngineState.EngineStateListenerImpl() {
@Override
public void beforeLine(String fullLine) {
logger.info(fullLine);
log.info(fullLine);
HeartBeatListeners.onDataArrived();
}
}, logger);
commandQueue = new CommandQueue(this, logger);
});
commandQueue = new CommandQueue(this);
}
@NotNull
@ -196,7 +198,7 @@ public class LinkManager implements Closeable {
public void start(String port, ConnectionStateListener stateListener) {
Objects.requireNonNull(port, "port");
logger.info("LinkManager: Starting " + port);
log.info("LinkManager: Starting " + port);
if (isLogViewerMode(port)) {
setConnector(LinkConnector.VOID);
} else if (TcpConnector.isTcpPort(port)) {
@ -208,7 +210,7 @@ public class LinkManager implements Closeable {
int portPart = TcpConnector.getTcpPort(port);
String hostname = TcpConnector.getHostname(port);
socket = new Socket(hostname, portPart);
TcpIoStream tcpIoStream = new TcpIoStream("[start] ", logger, socket);
TcpIoStream tcpIoStream = new TcpIoStream("[start] ", socket);
return tcpIoStream;
} 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;
} else {
Callable<IoStream> ioStreamCallable = new Callable<IoStream>() {
@Override
public IoStream call() {
IoStream stream = ((Callable<IoStream>) () -> SerialIoStreamJSerialComm.openPort(port, logger)).call();
IoStream stream = ((Callable<IoStream>) () -> SerialIoStreamJSerialComm.openPort(port)).call();
if (stream == null) {
// error already reported
return null;
@ -232,7 +234,7 @@ public class LinkManager implements Closeable {
return stream;
}
};
setConnector(new StreamConnector(this, port, logger, ioStreamCallable));
setConnector(new StreamConnector(this, port, ioStreamCallable));
}
}

View File

@ -1,6 +1,5 @@
package com.rusefi.io.commands;
import com.opensr5.Logger;
import com.rusefi.binaryprotocol.BinaryProtocolCommands;
import com.rusefi.binaryprotocol.IncomingDataBuffer;
import com.rusefi.config.generated.Fields;
@ -14,21 +13,19 @@ import java.io.IOException;
import static com.rusefi.binaryprotocol.IoHelper.checkResponseCode;
public class HelloCommand implements Command {
private final Logger logger;
private final String tsSignature;
public HelloCommand(Logger logger, String tsSignature) {
this.logger = logger;
public HelloCommand(String tsSignature) {
this.tsSignature = tsSignature;
}
public static void send(IoStream stream, Logger logger) throws IOException {
stream.sendPacket(new byte[]{Fields.TS_HELLO_COMMAND}, logger);
public static void send(IoStream stream) throws IOException {
stream.sendPacket(new byte[]{Fields.TS_HELLO_COMMAND});
}
@Nullable
public static String getHelloResponse(IncomingDataBuffer incomingData, Logger logger) throws EOFException {
byte[] response = incomingData.getPacket(logger, "[hello]", false);
public static String getHelloResponse(IncomingDataBuffer incomingData) throws EOFException {
byte[] response = incomingData.getPacket("[hello]", false);
if (!checkResponseCode(response, BinaryProtocolCommands.RESPONSE_OK))
return null;
return new String(response, 1, response.length - 1);
@ -41,6 +38,6 @@ public class HelloCommand implements Command {
@Override
public void handle(IoStream stream) throws IOException {
stream.sendPacket((BinaryProtocolServer.TS_OK + tsSignature).getBytes(), logger);
stream.sendPacket((BinaryProtocolServer.TS_OK + tsSignature).getBytes());
}
}

View File

@ -2,6 +2,8 @@ package com.rusefi.io.serial;
import com.rusefi.io.IoStream;
import java.io.IOException;
public abstract class AbstractIoStream implements IoStream {
private boolean isClosed;
@ -17,6 +19,10 @@ public abstract class AbstractIoStream implements IoStream {
isClosed = true;
}
@Override
public void flush() throws IOException {
}
@Override
public boolean isClosed() {
return isClosed;

View File

@ -1,6 +1,6 @@
package com.rusefi.io.serial;
import com.opensr5.Logger;
import com.devexperts.logging.Logging;
import com.rusefi.Callable;
import com.rusefi.binaryprotocol.BinaryProtocol;
import com.rusefi.core.MessagesCentral;
@ -13,6 +13,8 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import static com.devexperts.logging.Logging.getLogging;
/**
* This class holds the reference to the actual Serial port object
* <p/>
@ -20,8 +22,9 @@ import java.awt.*;
* Andrey Belomutskiy, (c) 2013-2020
*/
public class PortHolder {
private static final Logging log = getLogging(PortHolder.class);
private final DataListener dataListener;
private final Logger logger;
private final Callable<IoStream> ioStreamCallable;
private final LinkManager linkManager;
@ -32,11 +35,10 @@ public class PortHolder {
@Nullable
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.linkManager = linkManager;
dataListener = freshData -> linkManager.getEngineState().processNewData(new String(freshData), LinkManager.ENCODER);
this.logger = logger;
this.ioStreamCallable = ioStreamCallable;
}
@ -44,7 +46,7 @@ public class PortHolder {
if (port == null)
return false;
MessagesCentral.getInstance().postMessage(logger, getClass(), "Opening port: " + port);
MessagesCentral.getInstance().postMessage(getClass(), "Opening port: " + port);
IoStream stream = ioStreamCallable.call();
if (stream == null) {
@ -52,7 +54,7 @@ public class PortHolder {
return false;
}
synchronized (portLock) {
bp = new BinaryProtocol(linkManager, logger, stream, stream.getDataBuffer());
bp = new BinaryProtocol(linkManager, stream, stream.getDataBuffer());
portLock.notifyAll();
}

View File

@ -1,13 +1,15 @@
package com.rusefi.io.serial;
import com.devexperts.logging.Logging;
import com.fazecast.jSerialComm.SerialPort;
import com.fazecast.jSerialComm.SerialPortDataListener;
import com.fazecast.jSerialComm.SerialPortEvent;
import com.opensr5.Logger;
import com.opensr5.io.DataListener;
import com.rusefi.binaryprotocol.IncomingDataBuffer;
import com.rusefi.io.IoStream;
import static com.devexperts.logging.Logging.getLogging;
/**
* https://github.com/Fazecast/jSerialComm looks to be alive as of 2020
* <p>
@ -15,19 +17,18 @@ import com.rusefi.io.IoStream;
* 06/03/2019
*/
public class SerialIoStreamJSerialComm extends AbstractIoStream {
private static final Logging log = getLogging(SerialIoStreamJSerialComm.class);
private SerialPort sp;
private final String port;
private final Logger logger;
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.port = port;
this.logger = logger;
this.dataBuffer = IncomingDataBuffer.createDataBuffer("[serial] ", this, logger);
this.dataBuffer = IncomingDataBuffer.createDataBuffer("[serial] ", this);
}
@Override
@ -68,10 +69,10 @@ public class SerialIoStreamJSerialComm extends AbstractIoStream {
@Override
public void close() {
logger.info(port + ": Closing port...");
log.info(port + ": Closing port...");
super.close();
sp.closePort();
logger.info(port + ": Closed port.");
log.info(port + ": Closed port.");
}
@Override
@ -83,12 +84,12 @@ public class SerialIoStreamJSerialComm extends AbstractIoStream {
* Just open physical serial and not much more
* @see PortHolder#connectAndReadConfiguration()
*/
public static IoStream openPort(String port, Logger logger) {
logger.info("[SerialIoStreamJSerialComm] openPort " + port);
public static IoStream openPort(String port) {
log.info("[SerialIoStreamJSerialComm] openPort " + port);
SerialPort serialPort = SerialPort.getCommPort(port);
serialPort.setBaudRate(BaudRateHolder.INSTANCE.baudRate);
serialPort.openPort(0);
// FileLog.LOGGER.info("[SerialIoStreamJSerialComm] opened " + port);
return new SerialIoStreamJSerialComm(serialPort, port, logger);
return new SerialIoStreamJSerialComm(serialPort, port);
}
}

View File

@ -1,6 +1,6 @@
package com.rusefi.io.serial;
import com.opensr5.Logger;
import com.devexperts.logging.Logging;
import com.rusefi.Callable;
import com.rusefi.binaryprotocol.BinaryProtocol;
import com.rusefi.core.MessagesCentral;
@ -9,34 +9,32 @@ import com.rusefi.io.IoStream;
import com.rusefi.io.LinkConnector;
import com.rusefi.io.LinkManager;
import static com.devexperts.logging.Logging.getLogging;
/**
* @author Andrey Belomutskiy
* 3/3/14
*/
public class StreamConnector implements LinkConnector {
private static final Logging log = getLogging(StreamConnector.class);
private final PortHolder portHolder;
private final Logger logger;
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.logger = logger;
portHolder = new PortHolder(portName, linkManager, logger, ioStreamCallable);
portHolder = new PortHolder(portName, linkManager, ioStreamCallable);
}
@Override
public void connectAndReadConfiguration(ConnectionStateListener listener) {
logger.info("StreamConnector: connecting");
log.info("StreamConnector: connecting");
portHolder.listener = listener;
logger.info("scheduleOpening");
linkManager.execute(new Runnable() {
@Override
public void run() {
logger.info("scheduleOpening>openPort");
portHolder.connectAndReadConfiguration();
}
log.info("scheduleOpening");
linkManager.execute(() -> {
log.info("scheduleOpening>openPort");
portHolder.connectAndReadConfiguration();
});
}
@ -52,13 +50,10 @@ public class StreamConnector implements LinkConnector {
@Override
public void restart() {
linkManager.execute(new Runnable() {
@Override
public void run() {
MessagesCentral.getInstance().postMessage(logger, StreamConnector.this.getClass(), "Restarting serial IO");
portHolder.close();
portHolder.connectAndReadConfiguration();
}
linkManager.execute(() -> {
MessagesCentral.getInstance().postMessage(StreamConnector.this.getClass(), "Restarting serial IO");
portHolder.close();
portHolder.connectAndReadConfiguration();
});
}

View File

@ -1,6 +1,7 @@
package com.rusefi.io.tcp;
import com.opensr5.Logger;
import com.devexperts.logging.Logging;
import com.rusefi.Timeouts;
import com.rusefi.binaryprotocol.BinaryProtocol;
import com.rusefi.binaryprotocol.IncomingDataBuffer;
import com.rusefi.io.IoStream;
@ -11,36 +12,37 @@ import java.io.IOException;
import java.net.Socket;
import java.util.function.Function;
import static com.devexperts.logging.Logging.getLogging;
import static com.rusefi.binaryprotocol.BinaryProtocolCommands.COMMAND_PROTOCOL;
import static com.rusefi.config.generated.Fields.TS_PROTOCOL;
public class BinaryProtocolProxy {
public static void createProxy(Logger logger, IoStream targetEcuSocket, int serverProxyPort) {
Function<Socket, Runnable> clientSocketRunnableFactory = new Function<Socket, Runnable>() {
@Override
public Runnable apply(Socket clientSocket) {
return new Runnable() {
@Override
public void run() {
try {
TcpIoStream clientStream = new TcpIoStream("[[proxy]] ", logger, clientSocket);
runProxy(targetEcuSocket, clientStream);
} catch (IOException e) {
logger.error("BinaryProtocolProxy::run" + e);
}
}
};
private static final Logging log = getLogging(BinaryProtocolProxy.class);
/**
* we expect server to at least request output channels once in a while
* it could be a while between user connecting authenticator and actually connecting application to authenticator
*/
public static final int USER_IO_TIMEOUT = 600 * Timeouts.SECOND;
public static ServerHolder createProxy(IoStream targetEcuSocket, int serverProxyPort) {
Function<Socket, Runnable> clientSocketRunnableFactory = clientSocket -> () -> {
try {
TcpIoStream clientStream = new TcpIoStream("[[proxy]] ", clientSocket);
runProxy(targetEcuSocket, clientStream);
} catch (IOException e) {
log.error("BinaryProtocolProxy::run " + e);
}
};
BinaryProtocolServer.tcpServerSocket(serverProxyPort, "proxy", clientSocketRunnableFactory, Logger.CONSOLE, null);
return BinaryProtocolServer.tcpServerSocket(serverProxyPort, "proxy", clientSocketRunnableFactory, null);
}
public static void runProxy(IoStream targetEcu, IoStream clientStream) throws IOException {
/*
* Each client socket is running on it's own thread
*/
//noinspection InfiniteLoopStatement
while (true) {
byte firstByte = clientStream.getDataBuffer().readByte();
byte firstByte = clientStream.getDataBuffer().readByte(USER_IO_TIMEOUT);
if (firstByte == COMMAND_PROTOCOL) {
clientStream.write(TS_PROTOCOL.getBytes());
continue;
@ -54,7 +56,7 @@ public class BinaryProtocolProxy {
public static void proxyControllerResponseToClient(IoStream targetInputStream, IoStream clientOutputStream) throws IOException {
BinaryProtocolServer.Packet packet = targetInputStream.readPacket();
System.out.println("Relaying controller response length=" + packet.getPacket().length);
log.info("Relaying controller response length=" + packet.getPacket().length);
clientOutputStream.sendPacket(packet);
}
@ -67,7 +69,7 @@ public class BinaryProtocolProxy {
DataInputStream dis = new DataInputStream(new ByteArrayInputStream(packet.getPacket()));
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
targetOutputStream.sendPacket(packet);
}

View File

@ -1,5 +1,6 @@
package com.rusefi.io.tcp;
import com.devexperts.logging.Logging;
import com.opensr5.ConfigurationImage;
import com.opensr5.Logger;
import com.rusefi.Listener;
@ -10,6 +11,7 @@ import com.rusefi.io.IoStream;
import com.rusefi.io.LinkManager;
import com.rusefi.io.commands.HelloCommand;
import com.rusefi.server.rusEFISSLContext;
import com.rusefi.shared.FileUtil;
import java.io.*;
import java.net.ServerSocket;
@ -19,6 +21,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import static com.devexperts.logging.Logging.getLogging;
import static com.rusefi.binaryprotocol.IoHelper.swap16;
import static com.rusefi.config.generated.Fields.TS_PROTOCOL;
import static com.rusefi.config.generated.Fields.TS_RESPONSE_BURN_OK;
@ -32,9 +35,9 @@ import static com.rusefi.config.generated.Fields.TS_RESPONSE_BURN_OK;
*/
public class BinaryProtocolServer implements BinaryProtocolCommands {
private static final Logging log = getLogging(BinaryProtocolServer.class);
private static final int DEFAULT_PROXY_PORT = 2390;
public static final String TS_OK = "\0";
private final Logger logger;
public AtomicInteger unknownCommands = new AtomicInteger();
@ -50,27 +53,22 @@ public class BinaryProtocolServer implements BinaryProtocolCommands {
}
};
public BinaryProtocolServer(Logger logger) {
this.logger = logger;
}
public void start(LinkManager linkManager) {
start(linkManager, DEFAULT_PROXY_PORT, null);
}
public void start(LinkManager linkManager, int port, Listener serverSocketCreationCallback) {
logger.info("BinaryProtocolServer on " + port);
log.info("BinaryProtocolServer on " + port);
Function<Socket, Runnable> clientSocketRunnableFactory = clientSocket -> () -> {
try {
runProxy(linkManager, clientSocket);
} 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 +77,47 @@ public class BinaryProtocolServer implements BinaryProtocolCommands {
* @param port server port to accept connections
* @param threadName
* @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
* @return
*/
public static void tcpServerSocket(int port, String threadName, Function<Socket, Runnable> socketRunnableFactory, final Logger logger, Listener serverSocketCreationCallback) {
tcpServerSocket(logger, socketRunnableFactory, port, threadName, serverSocketCreationCallback, PLAIN_SOCKET_FACTORY);
public static ServerHolder tcpServerSocket(int port, String threadName, Function<Socket, Runnable> socketRunnableFactory, Listener serverSocketCreationCallback) {
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 ServerHolder tcpServerSocket(Function<Socket, Runnable> clientSocketRunnableFactory, int port, String threadName, Listener serverSocketCreationCallback, Function<Integer, ServerSocket> nonSecureSocketFunction) {
ServerSocket serverSocket = nonSecureSocketFunction.apply(port);
ServerHolder holder = new ServerHolder() {
@Override
public void close() {
super.close();
FileUtil.close(serverSocket);
}
};
if (serverSocketCreationCallback != null)
serverSocketCreationCallback.onResult(null);
Runnable runnable = () -> {
try {
while (true) {
// Wait for a connection
final Socket clientSocket = serverSocket.accept();
logger.info("Binary protocol proxy port connection");
new Thread(clientSocketRunnableFactory.apply(clientSocket), "proxy connection").start();
while (!holder.isClosed()) {
// Wait for a connection
final Socket clientSocket;
try {
clientSocket = serverSocket.accept();
} catch (IOException e) {
log.info("Client socket closed right away" + e);
continue;
}
} catch (IOException e) {
throw new IllegalStateException(e);
log.info("Binary protocol proxy port connection");
new Thread(clientSocketRunnableFactory.apply(clientSocket), "proxy connection").start();
}
};
new Thread(runnable, threadName).start();
return holder;
}
@SuppressWarnings("InfiniteLoopStatement")
private void runProxy(LinkManager linkManager, Socket clientSocket) throws IOException {
TcpIoStream stream = new TcpIoStream("[proxy] ", logger, clientSocket);
TcpIoStream stream = new TcpIoStream("[proxy] ", clientSocket);
IncomingDataBuffer in = stream.getDataBuffer();
@ -123,7 +133,8 @@ public class BinaryProtocolServer implements BinaryProtocolCommands {
continue;
}
System.out.println("Got [" + length + "] length promise");
if (log.debugEnabled())
log.debug("Got [" + length + "] length promise");
Packet packet = readPromisedBytes(in, length);
byte[] payload = packet.getPacket();
@ -133,19 +144,18 @@ public class BinaryProtocolServer implements BinaryProtocolCommands {
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) {
new HelloCommand(logger, Fields.TS_SIGNATURE).handle(stream);
new HelloCommand(Fields.TS_SIGNATURE).handle(stream);
} else if (command == COMMAND_PROTOCOL) {
// System.out.println("Ignoring crc F command");
stream.sendPacket((TS_OK + TS_PROTOCOL).getBytes(), logger);
stream.sendPacket((TS_OK + TS_PROTOCOL).getBytes());
} 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) {
handleCrc(linkManager, stream);
} else if (command == COMMAND_PAGE) {
stream.sendPacket(TS_OK.getBytes(), logger);
stream.sendPacket(TS_OK.getBytes());
} else if (command == COMMAND_READ) {
DataInputStream dis = new DataInputStream(new ByteArrayInputStream(payload, 1, payload.length - 1));
handleRead(linkManager, dis, stream);
@ -153,16 +163,16 @@ public class BinaryProtocolServer implements BinaryProtocolCommands {
DataInputStream dis = new DataInputStream(new ByteArrayInputStream(payload, 1, payload.length - 1));
handleWrite(linkManager, payload, dis, stream);
} 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) {
System.err.println("NOT IMPLEMENTED TS_GET_COMPOSITE_BUFFER_DONE_DIFFERENTLY relay");
// todo: relay command
stream.sendPacket(TS_OK.getBytes(), logger);
stream.sendPacket(TS_OK.getBytes());
} else if (command == Fields.TS_OUTPUT_COMMAND) {
DataInputStream dis = new DataInputStream(new ByteArrayInputStream(payload, 1, payload.length - 1));
int offset = 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];
response[0] = (byte) TS_OK.charAt(0);
@ -170,15 +180,15 @@ public class BinaryProtocolServer implements BinaryProtocolCommands {
byte[] currentOutputs = binaryProtocolState.getCurrentOutputs();
if (currentOutputs != null)
System.arraycopy(currentOutputs, 1 + offset, response, 1, count);
stream.sendPacket(response, logger);
stream.sendPacket(response);
} else if (command == Fields.TS_GET_TEXT) {
// todo: relay command
System.err.println("NOT IMPLEMENTED TS_GET_TEXT relay");
stream.sendPacket(TS_OK.getBytes(), logger);
stream.sendPacket(TS_OK.getBytes());
} else {
unknownCommands.incrementAndGet();
new IllegalStateException().printStackTrace();
logger.info("Error: unexpected " + BinaryProtocol.findCommand(command));
log.info("Error: unexpected " + BinaryProtocol.findCommand(command));
}
}
}
@ -227,7 +237,7 @@ public class BinaryProtocolServer implements BinaryProtocolCommands {
}
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.write(TS_PROTOCOL.getBytes());
outputStream.flush();
@ -237,10 +247,10 @@ public class BinaryProtocolServer implements BinaryProtocolCommands {
dis.readShort(); // page
int offset = 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();
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 {
@ -248,9 +258,10 @@ public class BinaryProtocolServer implements BinaryProtocolCommands {
int offset = swap16(dis.readShort());
int count = swap16(dis.readShort());
if (count <= 0) {
logger.info("Error: negative read request " + offset + "/" + count);
log.info("Error: negative read request " + offset + "/" + count);
} else {
System.out.println("read " + page + "/" + offset + "/" + count);
if (log.debugEnabled())
log.debug("read " + page + "/" + offset + "/" + count);
BinaryProtocolState bp = linkManager.getBinaryProtocolState();
byte[] response = new byte[1 + count];
response[0] = (byte) TS_OK.charAt(0);
@ -258,19 +269,19 @@ public class BinaryProtocolServer implements BinaryProtocolCommands {
ConfigurationImage configurationImage = bp.getControllerConfiguration();
Objects.requireNonNull(configurationImage, "configurationImage");
System.arraycopy(configurationImage.getContent(), offset, response, 1, count);
stream.sendPacket(response, logger);
stream.sendPacket(response);
}
}
private void handleCrc(LinkManager linkManager, TcpIoStream stream) throws IOException {
System.out.println("CRC check");
log.info("CRC check");
BinaryProtocolState bp = linkManager.getBinaryProtocolState();
byte[] content = bp.getControllerConfiguration().getContent();
int result = IoHelper.getCrc32(content);
ByteArrayOutputStream response = new ByteArrayOutputStream();
response.write(TS_OK.charAt(0));
new DataOutputStream(response).writeInt(result);
stream.sendPacket(response.toByteArray(), logger);
stream.sendPacket(response.toByteArray());
}
public static class Packet {

View File

@ -0,0 +1,15 @@
package com.rusefi.io.tcp;
import java.io.Closeable;
public class ServerHolder implements Closeable {
private boolean isClosed;
public void close() {
isClosed = true;
}
public boolean isClosed() {
return isClosed;
}
}

View File

@ -1,6 +1,5 @@
package com.rusefi.io.tcp;
import com.opensr5.Logger;
import com.opensr5.io.DataListener;
import com.rusefi.binaryprotocol.IncomingDataBuffer;
import com.rusefi.io.ByteReader;
@ -21,29 +20,33 @@ import java.net.Socket;
public class TcpIoStream extends AbstractIoStream {
private final InputStream input;
private final OutputStream output;
private final Logger logger;
private final String loggingPrefix;
private final DisconnectListener disconnectListener;
@NotNull
private final Socket socket;
private final IncomingDataBuffer dataBuffer;
public TcpIoStream(Logger logger, Socket socket) throws IOException {
this("", logger, socket);
public TcpIoStream(Socket socket) throws IOException {
this("", socket);
}
public TcpIoStream(String loggingPrefix, Logger logger, Socket socket) throws IOException {
public TcpIoStream(String loggingPrefix, Socket socket) throws IOException {
this(loggingPrefix, socket, DisconnectListener.VOID);
}
public TcpIoStream(String loggingPrefix, Socket socket, DisconnectListener disconnectListener) throws IOException {
this.loggingPrefix = loggingPrefix;
this.disconnectListener = disconnectListener;
if (socket == null)
throw new NullPointerException("socket");
this.socket = socket;
InputStream input = new BufferedInputStream(socket.getInputStream());
OutputStream output = socket.getOutputStream();
this.logger = logger;
if (output == null)
throw new NullPointerException("output");
this.output = output;
this.input = input;
this.dataBuffer = IncomingDataBuffer.createDataBuffer(loggingPrefix, this, logger);
this.dataBuffer = IncomingDataBuffer.createDataBuffer(loggingPrefix, this);
}
@Override
@ -65,12 +68,23 @@ public class TcpIoStream extends AbstractIoStream {
@Override
public void write(byte[] bytes) throws IOException {
output.write(bytes);
}
@Override
public void flush() throws IOException {
super.flush();
output.flush();
}
@Override
public void setInputListener(final DataListener listener) {
ByteReader.runReaderLoop(loggingPrefix, listener, input::read, disconnectListener);
}
ByteReader.runReaderLoop(loggingPrefix, listener, input::read, logger);
public interface DisconnectListener {
DisconnectListener VOID = () -> {
};
void onDisconnect();
}
}

View File

@ -2,8 +2,6 @@ package com.rusefi.server;
import com.rusefi.tools.online.HttpUtil;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import java.util.Objects;

View File

@ -3,8 +3,6 @@ package com.rusefi.server;
import com.rusefi.tools.online.HttpUtil;
import org.jetbrains.annotations.NotNull;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import java.util.Objects;

View File

@ -60,8 +60,12 @@ public class rusEFISSLContext {
}
public static Socket getSSLSocket(String host, int port) throws IOException {
if (isJenkins)
return new Socket(host, port);
if (isJenkins) {
Socket socket = new Socket(host, port);
// responsiveness matters (getting a byte sent to be received as promptly as possible)
socket.setTcpNoDelay(true);
return socket;
}
return getSSLSocketFactory(null /*key*/, TLS).createSocket(host, port);
}

View File

@ -1,10 +1,14 @@
package com.rusefi.tools.online;
import com.devexperts.logging.Logging;
import com.opensr5.Logger;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.util.EntityUtils;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
@ -12,10 +16,14 @@ import org.json.simple.parser.ParseException;
import java.io.IOException;
import static com.devexperts.logging.Logging.getLogging;
public class HttpUtil {
private static final Logging log = getLogging(Logging.class);
// todo: migrate proxy http json API server to TLS
public static final String RUSEFI_PROXY_JSON_PROTOCOL = "http://";
public static final int HTTP_PORT = 8001;
public static final int PROXY_JSON_API_HTTP_PORT = 8001;
/**
* hostname of PROXY server, not primary rusEFI web server - those are two separate hosts at the moment
*/
@ -23,8 +31,7 @@ public class HttpUtil {
public static String RUSEFI_ONLINE_JSON_API_PREFIX = "https://rusefi.com/online/api.php?method=";
public static <T> T getJsonResponse(HttpResponse response) throws IOException, ParseException {
String responseString = getResponse(response);
public static <T> T getJsonResponse(String responseString) throws ParseException {
JSONParser parser = new JSONParser();
return (T) parser.parse(responseString);
@ -33,15 +40,28 @@ public class HttpUtil {
public static String getResponse(HttpResponse response) throws IOException {
HttpEntity entity = response.getEntity();
String responseString = EntityUtils.toString(entity, "UTF-8");
System.out.println("responseString=" + responseString);
log.info("responseString=" + responseString);
return responseString;
}
public static HttpResponse executeGet(String url) throws IOException {
public static String executeGet(String url) throws IOException {
HttpClient httpclient = new DefaultHttpClient();
System.out.println("Connecting to " + url);
HttpParams httpParameters = httpclient.getParams();
// HttpConnectionParams.setConnectionTimeout(httpParameters, CONNECTION_TIMEOUT);
// HttpConnectionParams.setSoTimeout(httpParameters, WAIT_RESPONSE_TIMEOUT);
// without this magic http response is pretty slow
HttpConnectionParams.setTcpNoDelay(httpParameters, true);
log.info("GET " + url);
HttpGet httpget = new HttpGet(url);
return httpclient.execute(httpget);
// in case of emergency
// -Dorg.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog -Dorg.apache.commons.logging.simplelog.showdatetime=true -Dorg.apache.commons.logging.simplelog.log.org.apache.http=DEBUG -Dorg.apache.commons.logging.simplelog.log.org.apache.http.wire=ERROR
try {
HttpResponse httpResponse = httpclient.execute(httpget);
return HttpUtil.getResponse(httpResponse);
} finally {
httpget.releaseConnection();
}
}
public static JSONObject parse(String jsonString) {

View File

@ -2,7 +2,6 @@ package com.rusefi.tools.online;
import com.rusefi.server.ControllerInfo;
import com.rusefi.server.UserDetails;
import org.apache.http.HttpResponse;
import org.jetbrains.annotations.NotNull;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
@ -31,11 +30,11 @@ public class ProxyClient {
@NotNull
public static List<PublicSession> getOnlineApplications(String url) throws IOException {
HttpResponse httpResponse = HttpUtil.executeGet(url);
String responseString = HttpUtil.executeGet(url);
List<PublicSession> userLists = new ArrayList<>();
try {
JSONArray array = HttpUtil.getJsonResponse(httpResponse);
JSONArray array = HttpUtil.getJsonResponse(responseString);
for (int i = 0; i < array.size(); i++) {
JSONObject element = (JSONObject) array.get(i);

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,3 +1,7 @@
plugins {
id 'java'
}
dependencies {
implementation group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.2'
}

View File

@ -8,5 +8,6 @@
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="jsr305-2.0.1" level="project" />
</component>
</module>

View File

@ -0,0 +1,150 @@
/*
* !++
* QDS - Quick Data Signalling Library
* !-
* Copyright (C) 2002 - 2020 Devexperts LLC
* !-
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
* !__
*/
package com.devexperts.logging;
import java.io.IOException;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.logging.ConsoleHandler;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
/**
* Logging implementation that uses {@link java.util.logging} logging facilities.
*/
class DefaultLogging {
Map<String, Exception> configure() {
// Heuristically check if there was an attempt to manually configure logging
if (getProperty("java.util.logging.config.class", null) != null ||
getProperty("java.util.logging.config.file", null) != null ||
!hasDefaultHandlers(Logger.getLogger("")))
{
return Collections.emptyMap(); // logging was already manually configured
}
return configureLogFile(getProperty(Logging.LOG_FILE_PROPERTY, null));
}
private boolean hasDefaultHandlers(Logger root) {
// Default configuration is 1 ConsoleHandler with SimpleFormatter and INFO level
Handler[] handlers = root.getHandlers();
if (handlers.length != 1)
return false;
Handler handler = handlers[0];
return handler.getClass() == ConsoleHandler.class &&
handler.getFormatter().getClass() == SimpleFormatter.class &&
handler.getLevel() == Level.INFO;
}
Map<String, Exception> configureLogFile(String log_file) {
Logger root = Logger.getLogger("");
Map<String, Exception> errors = new LinkedHashMap<String, Exception>();
try {
// Don't reset configuration. Retain all manually configured loggers, but
// reconfigure the root logger, which (as we checked) has a default configuration with
// 1 ConsoleHandler with SimpleFormatter and INFO level
for (Handler handler : root.getHandlers())
root.removeHandler(handler);
// configure "log" file or console
Handler handler = null;
if (log_file != null) {
try {
handler = new FileHandler(log_file, getLimit(Logging.LOG_MAX_FILE_SIZE_PROPERTY, errors), 2, true);
} catch (IOException e) {
errors.put(log_file, e);
}
}
if (handler == null)
handler = new ConsoleHandler();
handler.setFormatter(new LogFormatter());
handler.setLevel(Level.ALL);
root.addHandler(handler);
// configure "err" file
String err_file = getProperty(Logging.ERR_FILE_PROPERTY, null);
if (err_file != null) {
try {
handler = new FileHandler(err_file, getLimit(Logging.ERR_MAX_FILE_SIZE_PROPERTY, errors), 2, true);
handler.setFormatter(new LogFormatter());
handler.setLevel(Level.WARNING);
root.addHandler(handler);
} catch (IOException e) {
errors.put(err_file, e);
}
}
} catch (SecurityException e) {
// ignore -- does not have persmission to change configuration
}
return errors;
}
Object getPeer(String name) {
return Logger.getLogger(name);
}
String getName(Object peer) {
return ((Logger)peer).getName();
}
boolean debugEnabled(Object peer) {
return ((Logger)peer).isLoggable(Level.FINE);
}
void setDebugEnabled(Object peer, boolean debug_enabled) {
((Logger)peer).setLevel(debug_enabled ? Level.ALL : Level.INFO);
}
void log(Object peer, Level level, String msg, Throwable t) {
((Logger)peer).log(level, msg, t);
}
// ========== Utility methods ==========
/**
* Safely, from security point of view, gets system property.
*/
static String getProperty(String key, String def) {
// For applets we need to be ready for security exception in getProperty() call
try {
return System.getProperty(key, def);
} catch (SecurityException e) {
return def;
}
}
static int getLimit(String key, Map<String, Exception> errors) {
String value = getProperty(key, Logging.DEFAULT_MAX_FILE_SIZE).trim();
int multiplier = 1;
if (value.endsWith("K") || value.endsWith("k")) {
multiplier = 1024;
value = value.substring(0, value.length() - 1);
} else if (value.endsWith("M") || value.endsWith("m")) {
multiplier = 1024 * 1024;
value = value.substring(0, value.length() - 1);
} else if (value.endsWith("G") || value.endsWith("g")) {
multiplier = 1024 * 1024 * 1024;
value = value.substring(0, value.length() - 1);
}
try {
return Integer.valueOf(value) * multiplier;
} catch (NumberFormatException e) {
errors.put(key, e);
return 0;
}
}
}

View File

@ -0,0 +1,185 @@
/*
* !++
* QDS - Quick Data Signalling Library
* !-
* Copyright (C) 2002 - 2020 Devexperts LLC
* !-
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
* !__
*/
package com.devexperts.logging;
import com.devexperts.util.TimeUtil;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Arrays;
import java.util.Calendar;
import java.util.TimeZone;
import java.util.function.BiConsumer;
import java.util.logging.Formatter;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import javax.annotation.concurrent.ThreadSafe;
/**
* Thread-safe formatter for log messages.
* It is used for formatting log4j, log4j2 and {@link java.util.logging} log messages.
* Performs conversion of thread names according to patterns specified in configuration file.
* <p>
* If the system property {@code logformatter.properties} is specified, then it should contain
* an URL to the configuration file. Otherwise, configuration is loaded from classpath, using
* <i>/META-INF/logformatter.properties</i> file.
* <p>
* The format of the file is:
* <ul>
* <li>pattern=replacement
* <li>"Pattern" uses regular expression syntax.
* You can escape "=" in pattern with "\=" syntax.
* <li>"Replacement" string can refer to capturing groups defined in pattern using usual
* regular expression syntax "$n", where "n" stands for the number of the group.
* <li>ISO 8859-1 encoding is used.
* <li>Empty lines and lines starting with # or ! are ignored.
* Lines containing wrong patterns are ignored.
* </ul>
* Configuration file is loaded during class loading.
* Any errors which occur in this class are printed in {@code System.err}.
* <p>
* Sample configuration file can be found in <i>etc/logformatter.properties</i>.
* <p>
* This class is not intended to be used standalone.
* It is a part of implementation of {@link com.devexperts.logging} package.
*
* @see DetailedLogLayout
* @see DxFeedPatternLayout
*/
@ThreadSafe
public class LogFormatter extends Formatter {
public static final String CONFIG_FILE_PROPERTY = "logformatter.properties";
public static final String DEFAULT_CONFIG_FILE = "/META-INF/logformatter.properties";
private static final String LINE_SEP = DefaultLogging.getProperty("line.separator", "\n");
private static final BiConsumer<Object, StringBuilder> STRING_FORMAT_CONSUMER = (s, sb) -> sb.append(s);
// ============== Instance ================
private final ThreadLocal<LocalFormatter> formatter;
public LogFormatter() {
this(TimeZone.getDefault());
}
public LogFormatter(TimeZone zone) {
formatter = ThreadLocal.withInitial(() -> new LocalFormatter(zone));
}
/**
* Used by {@link java.util.logging} logging.
* Formats messages with the same format as for log4j.
*/
@Override
public String format(LogRecord record) {
String s = format(getLevelChar(record.getLevel()),
record.getMillis(), Thread.currentThread().getName(),
record.getLoggerName(), formatMessage(record));
if (record.getThrown() != null) {
StringWriter sw = new StringWriter();
sw.write(s);
record.getThrown().printStackTrace(new PrintWriter(sw));
s = sw.toString();
}
return s;
}
/**
* Formats log message.
*
* @return Formatted message.
* @throws NullPointerException when threadName, loggerName, or msg are {@code null}.
*/
public String format(char levelChar, long time, String threadName, String loggerName, String msg) {
StringBuilder out = formatter.get().appendTo;
out.setLength(0);
try {
format(levelChar, time, threadName, loggerName, STRING_FORMAT_CONSUMER, msg, out);
return out.toString();
} finally {
boolean trim = out.length() > 1000;
out.setLength(0);
if (trim)
out.trimToSize();
}
}
void format(char levelChar, long time, String threadName, String loggerName,
BiConsumer<Object, StringBuilder> msgConsumer, Object msg, StringBuilder out)
{
out.append(levelChar).append(" ");
formatter.get().appendTime(time, out);
out.append(" ");
int threadPosition = out.length();
out.append("[");
out.append(ThreadNameFormatter.formatThreadName(time, threadName));
out.append("] ");
out.append(loggerName, loggerName.lastIndexOf('.') + 1, loggerName.length());
out.append(" - ");
int messagePosition = out.length();
msgConsumer.accept(msg, out);
out.append(LINE_SEP);
if (out.length() > messagePosition && out.charAt(messagePosition) == '\b')
out.delete(threadPosition, messagePosition + 1);
}
static char getLevelChar(Level level) {
int levelInt = level.intValue();
if (levelInt <= Level.FINEST.intValue())
return 'T';
if (levelInt <= Level.FINE.intValue())
return 'D';
if (levelInt <= Level.INFO.intValue())
return 'I';
if (levelInt <= Level.WARNING.intValue())
return 'W';
return 'E';
}
private static class LocalFormatter {
private final Calendar calendar;
private final char[] timeBuffer = new char[17]; // fixed-size buffer for time data "yyMMdd HHmmss.SSS"
private final StringBuilder appendTo = new StringBuilder();
private long translatedMinute;
private LocalFormatter(TimeZone zone) {
calendar = Calendar.getInstance(zone);
Arrays.fill(timeBuffer, 0, 17, ' ');
timeBuffer[13] = '.';
}
private void appendTime(long time, StringBuilder out) {
if (time < translatedMinute || time >= translatedMinute + TimeUtil.MINUTE) {
// set year, month, day, hour and minute
calendar.setTimeInMillis(time);
translatedMinute = calendar.getTime().getTime() - calendar.get(Calendar.SECOND) * 1000 - calendar.get(Calendar.MILLISECOND);
print2(0, calendar.get(Calendar.YEAR));
print2(2, calendar.get(Calendar.MONTH) + 1);
print2(4, calendar.get(Calendar.DAY_OF_MONTH));
print2(7, calendar.get(Calendar.HOUR_OF_DAY));
print2(9, calendar.get(Calendar.MINUTE));
}
// set seconds and milliseconds
int millis = (int)(time - translatedMinute);
print2(11, millis / 1000);
print2(14, millis / 10);
timeBuffer[16] = (char)('0' + millis % 10);
out.append(timeBuffer);
}
private void print2(int offset, int value) {
timeBuffer[offset] = (char)('0' + (value / 10) % 10);
timeBuffer[offset + 1] = (char)('0' + value % 10);
}
}
}

View File

@ -0,0 +1,235 @@
/*
* !++
* QDS - Quick Data Signalling Library
* !-
* Copyright (C) 2002 - 2020 Devexperts LLC
* !-
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
* !__
*/
package com.devexperts.logging;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.logging.Level;
/**
* Main logging class.
* It supports use of both log4j and {@link java.util.logging} logging facilities.
* <p>First it tries to use log4j logging. If this attempt fails, it uses {@link java.util.logging} logging,
* so you'll always have some logging running.
* <p>Usage pattern:
* <br><code>public class SomeClass {
* <br>private static final Logging log = Logging.getLogging(SomeClass.class);
* <br>}
* </code>
*
* @see Log4jLogging
* @see DefaultLogging
* @see LogFormatter
*/
public class Logging {
private static final boolean TRACE_LOGGING = Logging.class.desiredAssertionStatus();
private static final int FINEST_INT = Level.FINEST.intValue();
private static final int FINE_INT = Level.FINE.intValue();
public static final String LOG_CLASS_NAME = "log.className";
public static final String LOG_FILE_PROPERTY = "log.file";
public static final String ERR_FILE_PROPERTY = "err.file";
public static final String LOG_MAX_FILE_SIZE_PROPERTY = "log.maxFileSize";
public static final String ERR_MAX_FILE_SIZE_PROPERTY = "err.maxFileSize";
public static final String DEFAULT_MAX_FILE_SIZE = "900M";
private static final ConcurrentMap<String, Logging> INSTANCES = new ConcurrentHashMap<>();
private static final DefaultLogging IMPL = configure(DefaultLogging.getProperty(LOG_CLASS_NAME, "com.devexperts.logging.Log4j2Logging"));
public static Logging getLogging(Class<?> clazz) {
return getLogging(clazz.getName());
}
public static Logging getLogging(String name) {
Logging logging = INSTANCES.get(name);
if (logging != null)
return logging;
INSTANCES.putIfAbsent(name, new Logging(name));
return INSTANCES.get(name);
}
/**
* Programmatically reconfigures logging to a specified file. This method
* overrides the value of {@link #LOG_FILE_PROPERTY} system property.
*/
public static void configureLogFile(String log_file) {
reportErrors(IMPL, IMPL.configureLogFile(log_file));
}
// ========== Instance =========
private final Object peer;
/**
* This constructor is designed for abstract framework classes like BeanBase or
* DAOBase that extend Logging to decorate messages by
* overriding {@link #decorateLogMessage(String)} method.
*/
protected Logging() {
peer = IMPL.getPeer(getClass().getName());
}
protected Logging(String name) {
peer = IMPL.getPeer(name);
}
/**
* Returns category name of this logging.
*/
public final String getName() {
return IMPL.getName(peer);
}
/**
* Changes default {@link #debugEnabled()} behaviour for this logging instance.
* Use this method to turn off debugging information for classes that do not
* need to print their debugging information in production environment.
*/
public final void configureDebugEnabled(boolean defaultDebugEnabled) {
IMPL.setDebugEnabled(peer, Boolean.valueOf(DefaultLogging.getProperty(getName() + ".debug",
String.valueOf(defaultDebugEnabled))));
}
public final boolean debugEnabled() {
return IMPL.debugEnabled(peer);
}
public final void trace(String message) {
log(Level.FINEST, message, null);
}
public final void debug(String message) {
log(Level.FINE, message, null);
}
public final void debug(String message, Throwable t) {
log(Level.FINE, message, t);
}
public final void info(String message) {
log(Level.INFO, message, null);
}
public final void info(String message, Throwable t) {
log(Level.INFO, message, t);
}
public final void warn(String message) {
log(Level.WARNING, message, null);
}
public final void warn(String message, Throwable t) {
log(Level.WARNING, message, t);
}
public final void error(String message) {
log(Level.SEVERE, message, null);
}
public final void error(String message, Throwable t) {
log(Level.SEVERE, message, t);
}
public final RuntimeException log(RuntimeException e) {
log(Level.SEVERE, e.getMessage(), e);
return e;
}
/**
* Decorates log message (reformatting, auditing, etc).
* This method is invoked one time for each logging event.
*/
protected String decorateLogMessage(String msg) {
return msg;
}
// ========== Internal ==========
private void log(Level level, String msg, Throwable t) {
if (TRACE_LOGGING)
TraceLogging.log(getName(), level, decorateLogMessage(msg), t);
int levelInt = level.intValue();
if (levelInt <= FINEST_INT)
return; // trace never goes to regular log
if (levelInt <= FINE_INT && !IMPL.debugEnabled(peer))
return;
try {
msg = decorateLogMessage(msg == null ? "" : msg);
} catch (Throwable tt) {
IMPL.log(peer, Level.SEVERE, "Failed to decorate log message", tt);
}
IMPL.log(peer, level, msg, t);
}
/**
* At first tries to use logging from passed class name. If this attempt fails, tries to use log4j logging.
* If this attempt fails, it uses log4j2 logging. If this attempt fails, it uses {@link java.util.logging} logging.
*
* @return Logging implementation
*/
private static DefaultLogging configure(String className) {
DefaultLogging impl = null;
Map<String, Exception> errors = new LinkedHashMap<>();
if (!className.isEmpty()) {
try {
impl = (DefaultLogging)Class.forName(className).newInstance();
errors.putAll(impl.configure());
} catch (Throwable t) {
// failed to configure with passed class name
impl = null;
if (!(t instanceof LinkageError) && !(t.getCause() instanceof LinkageError)) {
errors.put(className + " link", new IllegalStateException(t));
}
}
}
if (impl == null) {
try {
impl = (DefaultLogging)Class.forName("com.devexperts.logging.Log4jLogging").newInstance();
errors.putAll(impl.configure());
} catch (Throwable t) {
// failed to configure log4j
impl = null;
// LinkageError means that log4j is not found at all, otherwise it was found but our config is wrong
if (!(t instanceof LinkageError) && !(t.getCause() instanceof LinkageError)) {
errors.put("log4j link", new IllegalStateException(t));
}
}
}
if (impl == null) {
try {
impl = (DefaultLogging)Class.forName("com.devexperts.logging.Log4j2Logging").newInstance();
errors.putAll(impl.configure());
} catch (Throwable t) {
// failed to configure log4j2
impl = null;
if (!(t instanceof LinkageError) && !(t.getCause() instanceof LinkageError)) {
errors.put("log4j2 link", new IllegalStateException(t));
}
}
}
if (impl == null) {
impl = new DefaultLogging();
errors.putAll(impl.configure());
}
reportErrors(impl, errors);
return impl;
}
private static void reportErrors(DefaultLogging impl, Map<String, Exception> errors) {
for (Map.Entry<String, Exception> entry : errors.entrySet())
impl.log(impl.getPeer("config"), Level.SEVERE, entry.getKey(), entry.getValue());
}
}

View File

@ -0,0 +1,179 @@
/*
* !++
* QDS - Quick Data Signalling Library
* !-
* Copyright (C) 2002 - 2020 Devexperts LLC
* !-
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
* !__
*/
package com.devexperts.logging;
import com.devexperts.util.IndexedSet;
import com.devexperts.util.QuickSort;
import com.devexperts.util.SynchronizedIndexedSet;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
class ThreadNameFormatter implements Comparable<ThreadNameFormatter> {
/**
* Configuration as a set of pairs (pattern, replacement).
*/
private static final Map<Pattern, String> PATTERNS = new LinkedHashMap<>();
private static final int MAX_NAME_CONVERSIONS_CACHE_SIZE = 1000;
/**
* Thread name replacement cache: (thread name, replacement string).
*/
private static final IndexedSet<String, ThreadNameFormatter> NAME_CONVERSIONS = SynchronizedIndexedSet.create(ThreadNameFormatter::getThreadName);
static {
loadPatterns();
}
private static void loadPatterns() {
InputStream config_input_stream = null;
try {
String config_path = DefaultLogging.getProperty(LogFormatter.CONFIG_FILE_PROPERTY, null);
if (config_path != null)
throw new UnsupportedOperationException("loadPatterns");
/*
try {
config_input_stream = new URLInputStream(config_path);
} catch (IOException e) {
System.err.println("Cannot find log formatter configuration file: '" + config_path + "'");
System.err.println("No thread name conversion will be performed.");
return;
}
*/ else
config_input_stream = LogFormatter.class.getResourceAsStream(LogFormatter.DEFAULT_CONFIG_FILE);
if (config_input_stream == null)
return;
BufferedReader reader = new BufferedReader(
new InputStreamReader(config_input_stream, Charset.forName("ISO-8859-1")));
Pattern config_line_pattern = Pattern.compile("((?:[^=]|(?:\\\\=))*[^\\\\=])=(.*)");
Pattern whitespace_line_pattern = Pattern.compile("\\s*");
Pattern comment_line_pattern = Pattern.compile("#.*|!.*");
String line;
Set<String> patterns_set = new HashSet<String>();
while ((line = reader.readLine()) != null) {
Matcher config_line_matcher = config_line_pattern.matcher(line);
// If it is whitespace or comment line
if (whitespace_line_pattern.matcher(line).matches() || comment_line_pattern.matcher(line).matches())
continue;
if (!config_line_matcher.matches()) {
System.err.println("The following line cannot be parsed in log formatter configuration file: '" + line + "'");
continue;
}
String config_pattern = config_line_matcher.group(1);
String config_replacement = config_line_matcher.group(2);
if (!patterns_set.add(config_pattern)) {
System.err.println("Duplicate pattern found in log formatter configuration file: '" + config_pattern + "'");
continue;
}
try {
PATTERNS.put(Pattern.compile(config_pattern), config_replacement);
} catch (PatternSyntaxException e) {
System.err.println("Cannot parse config pattern in log formatter configuration file: '" + config_pattern + "'");
}
}
} catch (IOException e) {
// Do not wish to log using logger until initialization has completed.
System.err.println("Cannot read log formatter configuration file");
e.printStackTrace(System.err);
} finally {
try {
if (config_input_stream != null) {
config_input_stream.close();
}
} catch (IOException e) {
// Do not wish to log using logger until initialization has completed.
System.err.println("Cannot close log formatter configuration file");
e.printStackTrace(System.err);
}
}
}
/**
* Formats thread name according to thread name conversion rules.
*
* @return Formatted thread name
*/
static String formatThreadName(long time, String thread_name) {
ThreadNameFormatter entry = NAME_CONVERSIONS.getByKey(thread_name);
if (entry == null) {
cleanupNameConversionsIfNeeded();
entry = new ThreadNameFormatter(thread_name, calculateThreadNameReplacement(thread_name));
NAME_CONVERSIONS.put(entry);
}
entry.last_time = time;
return entry.replacement_name;
}
private static void cleanupNameConversionsIfNeeded() {
if (NAME_CONVERSIONS.size() <= MAX_NAME_CONVERSIONS_CACHE_SIZE)
return; // everything is Ok
synchronized (NAME_CONVERSIONS) {
if (NAME_CONVERSIONS.size() <= MAX_NAME_CONVERSIONS_CACHE_SIZE)
return; // everything is Ok
ThreadNameFormatter[] entries = NAME_CONVERSIONS.toArray(new ThreadNameFormatter[NAME_CONVERSIONS.size()]);
QuickSort.sort(entries);
for (int i = 0; i < entries.length - MAX_NAME_CONVERSIONS_CACHE_SIZE / 2; i++)
NAME_CONVERSIONS.removeKey(entries[i].thread_name);
}
}
private static String calculateThreadNameReplacement(String thread_name) {
for (Map.Entry<Pattern, String> entry : PATTERNS.entrySet()) {
Matcher matcher = entry.getKey().matcher(thread_name);
if (matcher.matches()) {
String config_replacement = entry.getValue();
try {
return matcher.replaceAll(config_replacement);
} catch (IndexOutOfBoundsException e) {
// The replacement string refers to a capturing group that does not exist in the pattern.
// To prevent cycling log it as is.
// Incorrect replacement. Just use thread name.
System.err.println("Cannot parse replacement string in log formatter configuration file: '" + config_replacement + "'");
}
}
}
return thread_name;
}
final String thread_name;
final String replacement_name;
long last_time; // Atomicity, visibility and consistency of this field are unimportant.
ThreadNameFormatter(String thread_name, String replacement_name) {
this.thread_name = thread_name;
this.replacement_name = replacement_name;
}
private String getThreadName() {
return thread_name;
}
public int compareTo(ThreadNameFormatter o) {
return last_time < o.last_time ? -1 : last_time > o.last_time ? 1 : 0;
}
}

View File

@ -0,0 +1,146 @@
/*
* !++
* QDS - Quick Data Signalling Library
* !-
* Copyright (C) 2002 - 2020 Devexperts LLC
* !-
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
* !__
*/
package com.devexperts.logging;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
/**
* This is a small in-memory cyclic buffer to keep the log for debugging concurrency problems in order to
* reconstruct what was going on immediately before tests crashes, without actually writing all debug logging
* to the log file or console normally. It is used by some tests when assertions are enabled,
* otherwise this class should not even be loaded.
*/
public class TraceLogging {
private static final int STOPPED_INDEX = -1;
private static final int SIZE = Integer.parseInt(System.getProperty("TraceLogging.size", "4096")); // must be power of 2
private static final int MASK = SIZE - 1;
private static final int THREAD_OFS = 0;
private static final int NAME_OFS = 1;
private static final int LEVEL_OFS = 2;
private static final int MSG_OFS = 3;
private static final int THROWABLE_OFS = 4;
private static final int DATA_CNT = 5;
private static final long[] timeQueue = new long[SIZE];
private static final Object[] dataQueue = new Object[SIZE * DATA_CNT];
private static final AtomicInteger index = new AtomicInteger(STOPPED_INDEX);
private static int lastIndex = STOPPED_INDEX;
static {
if ((SIZE & MASK) != 0)
throw new RuntimeException("Size must be a power of two");
}
/**
* Restarts trace logging from scratch (old log entries are cleared).
* Use it at the beginning of the test.
*/
public static synchronized void restart() {
Arrays.fill(dataQueue, null);
lastIndex = STOPPED_INDEX;
index.compareAndSet(STOPPED_INDEX, 0);
}
/**
* Stops trace logging.
*/
public static void stop() {
stopIndex(-1);
}
/**
* Adds log entry. It is invoked from {@link Logging#log(Level, String, Throwable)} method when
* assertions are enabled.
*/
public static void log(String loggerName, Level level, String msg, Throwable t) {
append(nextIndex(), loggerName, level, msg, t);
}
/**
* Adds last entry and stops trace logging.
*/
public static void logAndStop(Class<?> where, String msg) {
logAndStop(where, msg, null);
}
/**
* Adds last entry with exception and stops trace logging.
*/
public static void logAndStop(Class<?> where, String msg, Throwable t) {
append(stopIndex(0), where.getName(), Level.INFO, msg, t);
}
private static void append(int i, String loggerName, Level level, String msg, Throwable t) {
if (i < 0)
return;
timeQueue[i] = System.currentTimeMillis();
dataQueue[i * DATA_CNT + THREAD_OFS] = Thread.currentThread();
dataQueue[i * DATA_CNT + NAME_OFS] = loggerName;
dataQueue[i * DATA_CNT + LEVEL_OFS] = level;
dataQueue[i * DATA_CNT + MSG_OFS] = msg;
dataQueue[i * DATA_CNT + THROWABLE_OFS] = t;
}
/**
* Dumps last entries from this trace log.
* It should be called after {@link #stop()} or {@link #logAndStop(Class, String)}.
* It does nothing if called more than once after stop or before stop.
*/
public static synchronized void dump(PrintStream out, String title) {
int stop = lastIndex;
if (stop < 0)
return;
lastIndex = STOPPED_INDEX;
LogFormatter formatter = new LogFormatter();
out.println("********************** Dump trace log for " + title);
int i = stop;
do {
i = (i + 1) & MASK;
Thread thread = (Thread)dataQueue[i * DATA_CNT + THREAD_OFS];
if (thread == null)
continue;
String loggerName = (String)dataQueue[i * DATA_CNT + NAME_OFS];
Level level = (Level)dataQueue[i * DATA_CNT + LEVEL_OFS];
String msg = (String)dataQueue[i * DATA_CNT + MSG_OFS];
Throwable t = (Throwable)dataQueue[i * DATA_CNT + THROWABLE_OFS];
long time = timeQueue[i];
out.print("* ");
out.print(formatter.format(LogFormatter.getLevelChar(level), time, thread.getName(), loggerName, msg));
if (t != null)
t.printStackTrace(out);
} while (i != stop);
out.println("********************** Done trace log for " + title);
}
private static int nextIndex() {
int result;
do {
result = index.get();
} while (result >= 0 && !index.compareAndSet(result, (result + 1) & MASK));
return result;
}
private static synchronized int stopIndex(int lastOffset) {
int result;
do {
result = index.get();
} while (result >= 0 && !index.compareAndSet(result, STOPPED_INDEX));
if (result >= 0)
lastIndex = (result + lastOffset) & MASK;
return result;
}
}

View File

@ -0,0 +1,16 @@
<!--
!++
QDS - Quick Data Signalling Library
!-
Copyright (C) 2002 - 2020 Devexperts LLC
!-
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file, You can obtain one at
http://mozilla.org/MPL/2.0/.
!__
-->
<html>
<body>
Provides logging classes.
</body>
</html>

View File

@ -0,0 +1,221 @@
/*
* !++
* QDS - Quick Data Signalling Library
* !-
* Copyright (C) 2002 - 2020 Devexperts LLC
* !-
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
* !__
*/
package com.devexperts.util;
import java.lang.reflect.Array;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
/**
* Provides a skeletal implementation of the {@link Set Set} interface to minimize the effort
* required to implement this interface. Unlike {@link AbstractSet AbstractSet} skeletal implementation,
* this one is more forgiving to concurrent modifications of this set during implemented bulk operations.
*/
public abstract class AbstractConcurrentSet<E> implements Set<E> {
// ========== Construction and Clearing ==========
/**
* Sole constructor; for invocation by subclass constructors, typically implicit.
*/
protected AbstractConcurrentSet() {}
/**
* Removes all of the elements from this set.
* <p>
* This implementation iterates all elements of this set and removes them using {@link Iterator#remove()} method.
*/
public void clear() {
for (Iterator<E> it = iterator(); it.hasNext();) {
it.next();
it.remove();
}
}
// ========== Query Operations ==========
/**
* Tests if this set has no elements.
* <p>
* This implementation checks emptiness using {@link #size()} method.
*/
public boolean isEmpty() {
return size() == 0;
}
/**
* Returns an array containing all of the elements in this set.
* Obeys the general contract of the {@link Collection#toArray()} method.
* <p>
* This implementation iterates all elements of this set and adds them into the array.
*/
public Object[] toArray() {
return toArrayImpl(null);
}
/**
* Returns an array containing all of the elements in this set whose runtime type
* is that of the specified array.
* Obeys the general contract of the {@link Collection#toArray(Object[])} method.
* <p>
* This implementation iterates all elements of this set and adds them into the array.
*/
public <T> T[] toArray(T[] a) {
return toArrayImpl(a);
}
@SuppressWarnings("unchecked")
private <T> T[] toArrayImpl(T[] a) {
// If (a == null) then returned array shall be of exact length, otherwise it can be larger.
int size = size(); // Atomic read.
Object[] result = a == null ? new Object[size] : a.length >= size ? a :
(Object[])Array.newInstance(a.getClass().getComponentType(), size);
int n = 0;
for (E o : this) {
if (n >= result.length) {
// More elements were added concurrently. Enlarge result array.
// Grow twice in size, but do not fail when (n == 0).
Object[] tmp = (Object[])Array.newInstance(result.getClass().getComponentType(), n + n + 1);
System.arraycopy(result, 0, tmp, 0, n);
result = tmp;
}
result[n++] = o;
}
if (n < result.length && a == null) {
// Shrink allocated array to exact size.
Object[] tmp = new Object[n];
System.arraycopy(result, 0, tmp, 0, n);
result = tmp;
}
if (n < result.length)
result[n] = null;
return (T[])result;
}
// ========== Bulk Operations ==========
/**
* Tests if this set contains all of the elements in the specified collection.
* <p>
* This implementation iterates all elements of specified collection and tests
* them one-by-one using {@link #contains(Object) contains(element)} method.
*/
public boolean containsAll(Collection<?> c) {
for (Object o : c)
if (!contains(o))
return false;
return true;
}
/**
* Adds all of the elements in the specified collection into this set and
* returns <b>true</b> if this operation has increased the size of this set.
* <p>
* This implementation iterates all elements of specified collection and adds
* them one-by-one using {@link #add(Object) add(element)} method.
*/
public boolean addAll(Collection<? extends E> c) {
boolean modified = false;
for (E o : c)
if (add(o))
modified = true;
return modified;
}
/**
* Removes all of the elements in the specified collection from this set and
* returns <b>true</b> if this operation has decreased the size of this set.
* <p>
* This implementation compares size of specified collection with the size of this set,
* then iterates smaller collection and removes elements that need to be removed.
*/
public boolean removeAll(Collection<?> c) {
boolean modified = false;
if (size() > c.size()) {
for (Object o : c)
if (remove(o))
modified = true;
} else {
for (Iterator<E> it = iterator(); it.hasNext();)
if (c.contains(it.next())) {
it.remove();
modified = true;
}
}
return modified;
}
/**
* Retains only the elements in this set that are contained in the specified collection.
* <p>
* This implementation iterates all elements of this set, checks if they are contained in
* the specified collection, and removes them if needed using {@link Iterator#remove()} method.
*/
public boolean retainAll(Collection<?> c) {
boolean modified = false;
for (Iterator<E> it = iterator(); it.hasNext();)
if (!c.contains(it.next())) {
it.remove();
modified = true;
}
return modified;
}
// ========== Comparison and Hashing ==========
/**
* Compares the specified object with this set for equality.
* Obeys the general contract of the {@link Set#equals(Object)} method.
* <p>
* This implementation compares size of specified set with the size of this set and then
* checks element containment using {@link #containsAll(Collection) containsAll((Set)o)} method.
*/
public boolean equals(Object o) {
return o == this || o instanceof Set && size() == ((Set)o).size() && containsAll((Set)o);
}
/**
* Returns the hash code value for this set.
* Obeys the general contract of the {@link Set#hashCode()} method.
* <p>
* This implementation iterates all elements of this set and adds their hash codes.
*/
public int hashCode() {
int hash = 0;
for (E o : this)
if (o != null)
hash += o.hashCode();
return hash;
}
// ========== String Conversion ==========
/**
* Returns a string representation of this set.
* <p>
* This implementation iterates all elements of this set and concatenates their string representations.
*/
public String toString() {
StringBuilder sb = new StringBuilder(size() * 3 + 10);
sb.append("[");
String separator = "";
for (E o : this) {
sb.append(separator);
sb.append(o);
separator = ", ";
}
sb.append("]");
return sb.toString();
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,69 @@
/*
* !++
* QDS - Quick Data Signalling Library
* !-
* Copyright (C) 2002 - 2020 Devexperts LLC
* !-
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
* !__
*/
package com.devexperts.util;
import java.io.Serializable;
import java.util.Locale;
/**
* Provides access to statistics of the {@link IndexedSet} static structure.
* Statistics are tracked only during modification operations.
* It has self-explanatory {@link #toString()} method that can be used to periodically dump
* information about important caches that are based on the {@code IndexedSet}.
*/
public class IndexedSetStats implements Serializable {
private static final long serialVersionUID = 0;
private final int payload_size;
private final int allocated_size;
private final long payload_distance;
private final long amortized_cost;
private final long mod_count;
IndexedSetStats(int payload_size, int allocated_size, long payload_distance, long amortized_cost, long mod_count) {
this.payload_size = payload_size;
this.allocated_size = allocated_size;
this.payload_distance = payload_distance;
this.amortized_cost = amortized_cost;
this.mod_count = mod_count;
}
public int getSize() {
return payload_size;
}
public int getAllocatedSize() {
return allocated_size;
}
public double getFillFactor() {
return (double)payload_size / allocated_size;
}
public double getAverageDistance() {
return payload_distance == 0 ? 0 : (double)payload_distance / payload_size;
}
public double getAmortizedCost() {
return amortized_cost == 0 ? 0 : (double)amortized_cost / payload_size;
}
public long getModCount() {
return mod_count;
}
@Override
public String toString() {
return String.format(Locale.US, "size %d, filled %.1f%%, avgdist %.3f, amortized %.3f, mods %d",
getSize(), getFillFactor() * 100, getAverageDistance(), getAmortizedCost(), getModCount());
}
}

View File

@ -0,0 +1,110 @@
/*
* !++
* QDS - Quick Data Signalling Library
* !-
* Copyright (C) 2002 - 2020 Devexperts LLC
* !-
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
* !__
*/
package com.devexperts.util;
import java.io.Serializable;
/**
* A strategy that distinguishes and identifies elements in an {@link IndexedSet} and {@link IndexedMap}.
*
* <p>The <b>Indexer</b> is {@link Serializable}, so that all concrete subclasses
* shall be <b>serializable</b> in order to support serialization of indexed set and map..
*
* @deprecated Use a functional interface {@link IndexerFunction} instead.
*/
@Deprecated
public abstract class Indexer<K, V> implements IndexerFunction<K, V> {
private static final long serialVersionUID = 0L;
/**
* Default strategy that treats values as their own keys <b>(key&nbsp;==&nbsp;value)</b> and delegates to
* {@link Object#hashCode() Object.hashCode()} and {@link Object#equals(Object) Object.equals(Object)}
* methods as appropriate. This strategy does not support primitive keys.
*
* <p>This strategy basically turns {@link IndexedSet} into plain hash set of objects and {@link IndexedMap}
* into a self-reference mapping.
*/
@SuppressWarnings("rawtypes")
public static final Indexer DEFAULT = new DefaultIndexer();
// ========== Standard Subclasses ==========
/**
* Default strategy that treats values as their own keys <b>(key&nbsp;==&nbsp;value)</b>.
*/
@SuppressWarnings("rawtypes")
static final class DefaultIndexer extends Indexer {
private static final long serialVersionUID = 0;
DefaultIndexer() {}
@Override
public Object getObjectKey(Object value) {
return value;
}
@SuppressWarnings("ReadResolveAndWriteReplaceProtected")
public Object readResolve() {
return Indexer.DEFAULT;
}
}
static class DelegateIndexer<K, V> extends Indexer<K, V> {
private static final long serialVersionUID = 0L;
private final IndexerFunction<K, V> indexer;
DelegateIndexer(IndexerFunction<K, V> indexer) {
this.indexer = indexer;
}
@Override
public K getObjectKey(V value) {
return indexer.getObjectKey(value);
}
@Override
public int hashCodeByKey(K key) {
return indexer.hashCodeByKey(key);
}
@Override
public boolean matchesByKey(K key, V value) {
return indexer.matchesByKey(key, value);
}
@Override
public int hashCodeByValue(V value) {
return indexer.hashCodeByValue(value);
}
@Override
public boolean matchesByValue(V newValue, V oldValue) {
return indexer.matchesByValue(newValue, oldValue);
}
@Override
public long getNumberKey(V value) {
return indexer.getNumberKey(value);
}
@Override
public int hashCodeByKey(long key) {
return indexer.hashCodeByKey(key);
}
@Override
public boolean matchesByKey(long key, V value) {
return indexer.matchesByKey(key, value);
}
}
}

View File

@ -0,0 +1,354 @@
/*
* !++
* QDS - Quick Data Signalling Library
* !-
* Copyright (C) 2002 - 2020 Devexperts LLC
* !-
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
* !__
*/
package com.devexperts.util;
import java.io.Serializable;
/**
* A strategy that distinguishes and identifies elements in an {@link IndexedSet} and {@link IndexedMap}.
* The <b>IndexerFunction</b> defines 3 equivalent ways to identify elements:
* <ul>
* <li> <b>by value</b> - mandatory and primary method to identify element by itself
* <li> <b>by object key</b> - optional method that identifies elements using object key
* <li> <b>by number key</b> - optional method that identifies elements using number key
* </ul>
*
* <p>The <b>IndexerFunction</b> is not restricted to use <b>explicit key</b> concept for identification.
* Identity of an element may be defined by a number of attributes, specified in a value itself,
* in a template object, in a formal key object, or encoded in a number key. The <b>IndexerFunction</b>
* may use all these ways interchangeable to distinguish and identify elements.
*
* <p>Being a strategy, the <b>IndexerFunction</b> is required to be stateless, concurrent and thread-safe.
*
* <p>The <b>IndexerFunction</b> is a functional interface with a sole abstract method that shall be implemented
* in order to use identification using explicit object key - no other methods are required to be
* overridden in such simple cases.
* There are two other functional interfaces {@link IndexerFunction.IntKey} and {@link IndexerFunction.LongKey}
* which are similarly designed with sole abstract methods to simplify identification using explicit number keys.
* There is also a functional interface {@link IndexerFunction.IdentityKey} which is similarly designed
* with sole abstract method for cases when explicit object keys must be compared by reference rather than
* using their {@link Object#equals(Object) equals} method.
*
* <p>The <b>IndexerFunction</b> is {@link Serializable}, so that all concrete subclasses
* shall be <b>serializable</b> in order to support serialization of indexed set and map.
*/
@FunctionalInterface
public interface IndexerFunction<K, V> extends Serializable {
/**
* Default strategy that treats values as their own keys <b>(key&nbsp;==&nbsp;value)</b> and delegates to
* {@link Object#hashCode() Object.hashCode()} and {@link Object#equals(Object) Object.equals(Object)}
* methods as appropriate. This strategy does not support primitive keys.
*
* <p>This strategy basically turns {@link IndexedSet} into plain hash set of objects and {@link IndexedMap}
* into a self-reference mapping.
*/
@SuppressWarnings("rawtypes")
public static final IndexerFunction DEFAULT = new DefaultIndexerFunction();
// ========== Object Key Operations ==========
/**
* Returns object key for specified value to be used for hashing and identification;
* called when explicit object key is needed or when other methods delegate operations as specified.
*/
public K getObjectKey(V value);
/**
* Returns hash code for specified object key; called when performing operations using object keys.
*
* <p>This implementation delegates to
* <code>(key&nbsp;==&nbsp;null&nbsp;?&nbsp;0&nbsp;:&nbsp;key.{@link Object#hashCode() hashCode}())</code> expression.
*/
public default int hashCodeByKey(K key) {
return key == null ? 0 : key.hashCode();
}
/**
* Determines if specified object key matches specified value; called when performing operations using object keys.
*
* <p>This implementation delegates to
* <code>(key&nbsp;==&nbsp;null&nbsp;?&nbsp;{@link #getObjectKey(Object) getObjectKey}(value)&nbsp;==&nbsp;null&nbsp;:&nbsp;key.{@link Object#equals(Object) equals}({@link #getObjectKey(Object) getObjectKey}(value)))</code> expression.
*/
public default boolean matchesByKey(K key, V value) {
return key == null ? getObjectKey(value) == null : key.equals(getObjectKey(value));
}
// ========== Value Operations ==========
/**
* Returns hash code for specified value; called when performing value-based operations, including <b>rehash</b>.
*
* <p>This implementation delegates to
* <code>{@link #hashCodeByKey(Object) hashCodeByKey}({@link #getObjectKey(Object) getObjectKey}(value))</code> expression.
*/
public default int hashCodeByValue(V value) {
return hashCodeByKey(getObjectKey(value));
}
/**
* Determines if specified new value matches specified old value; called when performing value-based operations.
*
* <p>This implementation delegates to
* <code>{@link #matchesByKey(Object, Object) matchesByKey}({@link #getObjectKey(Object) getObjectKey}(newValue),&nbsp;oldValue)</code> expression.
*/
public default boolean matchesByValue(V newValue, V oldValue) {
return matchesByKey(getObjectKey(newValue), oldValue);
}
// ========== Number Key Operations (Optional) ==========
/**
* Returns number key for specified value to be used for hashing and identification;
* called when explicit number key is needed or when other methods delegate operations as specified.
*
* <p>This implementation delegates to
* <code>{@link #hashCodeByKey(long) hashCodeByKey}(((Number){@link #getObjectKey(Object) getObjectKey}(value)).{@link Number#longValue() longValue}())</code> expression.
*/
public default long getNumberKey(V value) {
return hashCodeByKey(((Number)getObjectKey(value)).longValue());
}
/**
* Returns hash code for specified number key; called when performing operations using long keys.
*
* <p>This implementation delegates to
* <code>Long.{@link Long#hashCode(long) hashCode}(key)</code> expression.
*/
public default int hashCodeByKey(long key) {
return Long.hashCode(key);
}
/**
* Determines if specified number key matches specified value; called when performing operations using number keys.
*
* <p>This implementation delegates to
* <code>(key&nbsp;==&nbsp;{@link #getNumberKey(Object) getNumberKey}(value))</code> expression.
*/
public default boolean matchesByKey(long key, V value) {
return key == getNumberKey(value);
}
/**
* An {@link IndexerFunction} that distinguishes and identifies elements using <b>int</b> keys.
*
* <p>It assumes that elements are fully identifiable by plain numeric identifier and treats object keys as a mere wrappers.
* The hash function is computed by taking <b>int</b> key value.
*/
@FunctionalInterface
public interface IntKey<V> extends IndexerFunction<Integer, V> {
/**
* Returns number key for specified value to be used for hashing and identification.
*/
public int getIntKey(V value);
/**
* Returns number key for specified value to be used for hashing and identification;
* called when explicit number key is needed or when other methods delegate operations as specified.
*
* <p>This implementation delegates to
* <code>{@link #getIntKey(Object) getIntKey}(value)</code> expression.
*/
@Override
public default long getNumberKey(V value) {
return getIntKey(value);
}
/**
* Returns hash code for specified value; called when performing value-based operations, including <b>rehash</b>.
*
* <p>This implementation delegates to
* <code>{@link #hashCodeByKey(long) hashCodeByKey}({@link #getIntKey(Object) getIntKey}(value))</code> expression.
*/
@Override
public default int hashCodeByValue(V value) {
return hashCodeByKey(getIntKey(value));
}
/**
* Determines if specified new value matches specified old value; called when performing value-based operations.
*
* <p>This implementation delegates to
* <code>({@link #getIntKey(Object) getIntKey}(newValue)&nbsp;==&nbsp;{@link #getIntKey(Object) getIntKey}(oldValue))</code> expression.
*/
@Override
public default boolean matchesByValue(V newValue, V oldValue) {
return getIntKey(newValue) == getIntKey(oldValue);
}
/**
* Returns object key for specified value to be used for hashing and identification;
* called when explicit object key is needed or when other methods delegate operations as specified.
*
* <p>This implementation delegates to
* <code>{@link #getIntKey(Object) getIntKey}(value)</code> expression.
*/
@Override
public default Integer getObjectKey(V value) {
return getIntKey(value);
}
/**
* Returns hash code for specified object key; called when performing operations using object keys.
*
* <p>This implementation delegates to
* <code>{@link #hashCodeByKey(long) hashCodeByKey}(key.{@link Integer#intValue() intValue}())</code> expression.
*/
@Override
public default int hashCodeByKey(Integer key) {
return hashCodeByKey(key.intValue());
}
/**
* Determines if specified object key matches specified value; called when performing operations using object keys.
*
* <p>This implementation delegates to
* <code>(key&nbsp;==&nbsp;{@link #getIntKey(Object) getIntKey}(value))</code> expression.
*/
@Override
public default boolean matchesByKey(Integer key, V value) {
return key == getIntKey(value);
}
}
/**
* An {@link IndexerFunction} that distinguishes and identifies elements using <b>long</b> keys.
*
* <p>It assumes that elements are fully identifiable by plain numeric identifier and treats object keys as a mere wrappers.
* The hash function is computed using <code>{@link Long#hashCode(long) Long.hashCode}(key)</code> expression.
*/
@FunctionalInterface
public interface LongKey<V> extends IndexerFunction<Long, V> {
/**
* Returns number key for specified value to be used for hashing and identification;
* called when explicit number key is needed or when other methods delegate operations as specified.
*/
@Override
public long getNumberKey(V value);
/**
* Returns hash code for specified value; called when performing value-based operations, including <b>rehash</b>.
*
* <p>This implementation delegates to
* <code>{@link #hashCodeByKey(long) hashCodeByKey}({@link #getNumberKey(Object) getNumberKey}(value))</code> expression.
*/
@Override
public default int hashCodeByValue(V value) {
return hashCodeByKey(getNumberKey(value));
}
/**
* Determines if specified new value matches specified old value; called when performing value-based operations.
*
* <p>This implementation delegates to
* <code>({@link #getNumberKey(Object) getNumberKey}(newValue)&nbsp;==&nbsp;{@link #getNumberKey(Object) getNumberKey}(oldValue))</code> expression.
*/
@Override
public default boolean matchesByValue(V newValue, V oldValue) {
return getNumberKey(newValue) == getNumberKey(oldValue);
}
/**
* Returns object key for specified value to be used for hashing and identification;
* called when explicit object key is needed or when other methods delegate operations as specified.
*
* <p>This implementation delegates to
* <code>{@link #getNumberKey(Object) getNumberKey}(value)</code> expression.
*/
@Override
public default Long getObjectKey(V value) {
return getNumberKey(value);
}
/**
* Returns hash code for specified object key; called when performing operations using object keys.
*
* <p>This implementation delegates to
* <code>{@link #hashCodeByKey(long) hashCodeByKey}(key.{@link Long#longValue() longValue}())</code> expression.
*/
@Override
public default int hashCodeByKey(Long key) {
return hashCodeByKey(key.longValue());
}
/**
* Determines if specified object key matches specified value; called when performing operations using object keys.
*
* <p>This implementation delegates to
* <code>(key&nbsp;==&nbsp;{@link #getNumberKey(Object) getNumberKey}(value))</code> expression.
*/
@Override
public default boolean matchesByKey(Long key, V value) {
return key == getNumberKey(value);
}
}
/**
* A specialized {@link IndexerFunction} that distinguishes and identifies elements using identity comparison of object keys.
*
* <p>It uses {@link System#identityHashCode(Object) System.identityHashCode(Object)} method instead of
* {@link Object#hashCode() Object.hashCode()} method to compute hashcode and reference comparison
* instead of {@link Object#equals(Object) Object.equals(Object)} method to determine identity.
*
* <p>In order to use this functional interface, cast a lambda expression to it when creating {@link IndexedSet}. For example,<br>
* <code>IndexedSet&lt;Key, Value&gt; set = IndexedSet.{@link IndexedSet#create(IndexerFunction) create}((IndexerFunction.IdentityKey&lt;Key, Value&gt;)Value::getKey);</code>
*/
@FunctionalInterface
public interface IdentityKey<K, V> extends IndexerFunction<K, V> {
/**
* Returns hash code for specified object key; called when performing operations using object keys.
*
* <p>This implementation delegates to
* <code>System.{@link System#identityHashCode(Object) identityHashCode}(key)</code> expression.
*/
@Override
public default int hashCodeByKey(K key) {
return System.identityHashCode(key);
}
/**
* Determines if specified object key matches specified value; called when performing operations using object keys.
*
* <p>This implementation delegates to
* <code>(key&nbsp;==&nbsp;{@link #getObjectKey(Object) getObjectKey}(value))</code> expression.
*/
@Override
public default boolean matchesByKey(K key, V value) {
return key == getObjectKey(value);
}
}
/**
* Default strategy that treats values as their own keys <b>(key&nbsp;==&nbsp;value)</b>.
*/
@SuppressWarnings("rawtypes")
static final class DefaultIndexerFunction implements IndexerFunction {
private static final long serialVersionUID = 0;
DefaultIndexerFunction() {}
@Override
public Object getObjectKey(Object value) {
return value;
}
// Substitute DefaultIndexer implementation for backward compatibility
private Object writeReplace() {
return Indexer.DEFAULT;
}
private Object readResolve() {
return IndexerFunction.DEFAULT;
}
}
}

View File

@ -0,0 +1,233 @@
/*
* !++
* QDS - Quick Data Signalling Library
* !-
* Copyright (C) 2002 - 2020 Devexperts LLC
* !-
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
* !__
*/
package com.devexperts.util;
import java.io.Serializable;
import java.util.Comparator;
import java.util.Objects;
import java.util.function.IntFunction;
import java.util.function.IntToDoubleFunction;
import java.util.function.IntToLongFunction;
import java.util.function.IntUnaryOperator;
/**
* A comparison function, which imposes a <i>total ordering</i> on some collection of ints.
* Comparators can be passed to a sort method (such as {@link QuickSort#sort(int[], IntComparator) QuickSort.sort})
* to allow precise control over the sort order.
*
* <p>The purpose of this function is to allow non-trivial ordering of ints which depend on some external data.
* For example when ints are some identifiers (pseudo-references) of actual data.
*/
@SuppressWarnings("UnusedDeclaration")
public interface IntComparator {
/**
* Compares its two arguments for order. Returns a negative integer, zero, or a positive integer
* as the first argument is less than, equal to, or greater than the second.
*
* @param i1 the first int to be compared.
* @param i2 the second int to be compared.
* @return a negative integer, zero, or a positive integer as the first argument is
* less than, equal to, or greater than the second.
*/
public int compare(int i1, int i2);
/**
* Returns a comparator that imposes the reverse ordering of this comparator.
*
* @return a comparator that imposes the reverse ordering of this comparator.
*/
public default IntComparator reversed() {
return (IntComparator & Serializable) (i1, i2) -> compare(i2, i1);
}
/**
* Returns a lexicographic-order comparator with another comparator.
* If this comparator considers two elements equal, i.e. {@code compare(i1, i2) == 0},
* then other comparator is used to determine the order.
*
* <p>The returned comparator is serializable if the specified comparator is also serializable.
*
* @param other the other comparator to be used when this comparator compares two ints that are equal.
* @return a lexicographic-order comparator composed of this comparator and then the other comparator.
* @throws NullPointerException if the argument is null.
*/
public default IntComparator thenComparing(IntComparator other) {
Objects.requireNonNull(other);
return (IntComparator & Serializable) (i1, i2) -> {
int res = compare(i1, i2);
return res != 0 ? res : other.compare(i1, i2);
};
}
/**
* Returns a lexicographic-order comparator with a function that extracts
* a sort key to be compared with the given sort key comparator.
*
* <p>This default implementation delegates to
* <code>{@link #thenComparing(IntComparator) thenComparing}({@link #comparing(IntFunction, Comparator) comparing}(keyExtractor,&nbsp;keyComparator))</code> expression.
*
* @param <K> the type of the sort key.
* @param keyExtractor the function used to extract the sort key.
* @param keyComparator the comparator used to compare the sort key.
* @return a lexicographic-order comparator composed of this comparator
* and then comparing an extracted sort key using the specified sort key comparator.
* @throws NullPointerException if either argument is null.
*/
public default <K> IntComparator thenComparing(IntFunction<? extends K> keyExtractor, Comparator<? super K> keyComparator) {
return thenComparing(comparing(keyExtractor, keyComparator));
}
/**
* Returns a lexicographic-order comparator with a function that extracts a comparable sort key.
*
* <p>This default implementation delegates to
* <code>{@link #thenComparing(IntComparator) thenComparing}({@link #comparing(IntFunction) comparing}(keyExtractor))</code> expression.
*
* @param <K> the type of the comparable sort key.
* @param keyExtractor the function used to extract the comparable sort key.
* @return a lexicographic-order comparator composed of this comparator
* and then comparing an extracted comparable sort key.
* @throws NullPointerException if the argument is null.
*/
public default <K extends Comparable<? super K>> IntComparator thenComparing(IntFunction<? extends K> keyExtractor) {
return thenComparing(comparing(keyExtractor));
}
/**
* Returns a lexicographic-order comparator with a function that extracts an int sort key.
*
* <p>This default implementation delegates to
* <code>{@link #thenComparing(IntComparator) thenComparing}({@link #comparingInt(IntUnaryOperator) comparing}(keyExtractor))</code> expression.
*
* @param keyExtractor the function used to extract the int sort key.
* @return a lexicographic-order comparator composed of this comparator
* and then comparing an extracted int sort key.
* @throws NullPointerException if the argument is null.
*/
public default IntComparator thenComparingInt(IntUnaryOperator keyExtractor) {
return thenComparing(comparingInt(keyExtractor));
}
/**
* Returns a lexicographic-order comparator with a function that extracts a long sort key.
*
* <p>This default implementation delegates to
* <code>{@link #thenComparing(IntComparator) thenComparing}({@link #comparingLong(IntToLongFunction) comparing}(keyExtractor))</code> expression.
*
* @param keyExtractor the function used to extract the long sort key.
* @return a lexicographic-order comparator composed of this comparator
* and then comparing an extracted long sort key.
* @throws NullPointerException if the argument is null.
*/
public default IntComparator thenComparingLong(IntToLongFunction keyExtractor) {
return thenComparing(comparingLong(keyExtractor));
}
/**
* Returns a lexicographic-order comparator with a function that extracts a double sort key.
*
* <p>This default implementation delegates to
* <code>{@link #thenComparing(IntComparator) thenComparing}({@link #comparingDouble(IntToDoubleFunction) comparing}(keyExtractor))</code> expression.
*
* @param keyExtractor the function used to extract the double sort key.
* @return a lexicographic-order comparator composed of this comparator
* and then comparing and extracted double sort key.
* @throws NullPointerException if the argument is null.
*/
public default IntComparator thenComparingDouble(IntToDoubleFunction keyExtractor) {
return thenComparing(comparingDouble(keyExtractor));
}
/**
* Accepts a function that extracts a sort key and a sort key comparator, and returns
* a comparator that compares by an extracted sort key using the specified sort key comparator.
*
* <p>The returned comparator is serializable if the specified function and comparator are both serializable.
*
* @param <K> the type of the sort key.
* @param keyExtractor the function used to extract the sort key.
* @param keyComparator the comparator used to compare the sort key.
* @return a comparator that compares by an extracted sort key using the specified sort key comparator.
* @throws NullPointerException if either argument is null.
*/
public static <K> IntComparator comparing(IntFunction<? extends K> keyExtractor, Comparator<? super K> keyComparator) {
Objects.requireNonNull(keyExtractor);
Objects.requireNonNull(keyComparator);
return (IntComparator & Serializable)
(i1, i2) -> keyComparator.compare(keyExtractor.apply(i1), keyExtractor.apply(i2));
}
/**
* Accepts a function that extracts a comparable sort, and returns
* a comparator that compares by an extracted comparable sort key.
*
* <p>The returned comparator is serializable if the specified function is also serializable.
*
* @param <K> the type of the comparable sort key.
* @param keyExtractor the function used to extract the comparable sort key.
* @return a comparator that compares by an extracted comparable sort key.
* @throws NullPointerException if the argument is null.
*/
public static <K extends Comparable<? super K>> IntComparator comparing(IntFunction<? extends K> keyExtractor) {
Objects.requireNonNull(keyExtractor);
return (IntComparator & Serializable)
(i1, i2) -> keyExtractor.apply(i1).compareTo(keyExtractor.apply(i2));
}
/**
* Accepts a function that extracts an int sort key, and returns
* a comparator that compares by an extracted int sort key.
*
* <p>The returned comparator is serializable if the specified function is also serializable.
*
* @param keyExtractor the function used to extract the int sort key.
* @return a comparator that compares by an extracted int sort key.
* @throws NullPointerException if the argument is null.
*/
public static IntComparator comparingInt(IntUnaryOperator keyExtractor) {
Objects.requireNonNull(keyExtractor);
return (IntComparator & Serializable)
(i1, i2) -> Integer.compare(keyExtractor.applyAsInt(i1), keyExtractor.applyAsInt(i2));
}
/**
* Accepts a function that extracts a long sort key, and returns
* a comparator that compares by an extracted long sort key.
*
* <p>The returned comparator is serializable if the specified function is also serializable.
*
* @param keyExtractor the function used to extract the long sort key.
* @return a comparator that compares by an extracted long sort key.
* @throws NullPointerException if the argument is null.
*/
public static IntComparator comparingLong(IntToLongFunction keyExtractor) {
Objects.requireNonNull(keyExtractor);
return (IntComparator & Serializable)
(i1, i2) -> Long.compare(keyExtractor.applyAsLong(i1), keyExtractor.applyAsLong(i2));
}
/**
* Accepts a function that extracts a double sort key, and returns
* a comparator that compares by an extracted double sort key.
*
* <p>The returned comparator is serializable if the specified function is also serializable.
*
* @param keyExtractor the function used to extract the double sort key.
* @return a comparator that compares by an extracted double sort key.
* @throws NullPointerException if the argument is null.
*/
public static IntComparator comparingDouble(IntToDoubleFunction keyExtractor) {
Objects.requireNonNull(keyExtractor);
return (IntComparator & Serializable)
(i1, i2) -> Double.compare(keyExtractor.applyAsDouble(i1), keyExtractor.applyAsDouble(i2));
}
}

View File

@ -0,0 +1,233 @@
/*
* !++
* QDS - Quick Data Signalling Library
* !-
* Copyright (C) 2002 - 2020 Devexperts LLC
* !-
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
* !__
*/
package com.devexperts.util;
import java.io.Serializable;
import java.util.Comparator;
import java.util.Objects;
import java.util.function.LongFunction;
import java.util.function.LongToDoubleFunction;
import java.util.function.LongToIntFunction;
import java.util.function.LongUnaryOperator;
/**
* A comparison function, which imposes a <i>total ordering</i> on some collection of longs.
* Comparators can be passed to a sort method (such as {@link QuickSort#sort(long[], LongComparator) QuickSort.sort})
* to allow precise control over the sort order.
*
* <p>The purpose of this function is to allow non-trivial ordering of longs which depend on some external data.
* For example when longs are some identifiers (pseudo-references) of actual data.
*/
@SuppressWarnings("UnusedDeclaration")
public interface LongComparator {
/**
* Compares its two arguments for order. Returns a negative integer, zero, or a positive integer
* as the first argument is less than, equal to, or greater than the second.
*
* @param i1 the first long to be compared.
* @param i2 the second long to be compared.
* @return a negative integer, zero, or a positive integer as the first argument is
* less than, equal to, or greater than the second.
*/
public int compare(long i1, long i2);
/**
* Returns a comparator that imposes the reverse ordering of this comparator.
*
* @return a comparator that imposes the reverse ordering of this comparator.
*/
public default LongComparator reversed() {
return (LongComparator & Serializable) (i1, i2) -> compare(i2, i1);
}
/**
* Returns a lexicographic-order comparator with another comparator.
* If this comparator considers two elements equal, i.e. {@code compare(i1, i2) == 0},
* then other comparator is used to determine the order.
*
* <p>The returned comparator is serializable if the specified comparator is also serializable.
*
* @param other the other comparator to be used when this comparator compares two longs that are equal.
* @return a lexicographic-order comparator composed of this comparator and then the other comparator.
* @throws NullPointerException if the argument is null.
*/
public default LongComparator thenComparing(LongComparator other) {
Objects.requireNonNull(other);
return (LongComparator & Serializable) (i1, i2) -> {
int res = compare(i1, i2);
return res != 0 ? res : other.compare(i1, i2);
};
}
/**
* Returns a lexicographic-order comparator with a function that extracts
* a sort key to be compared with the given sort key comparator.
*
* <p>This default implementation delegates to
* <code>{@link #thenComparing(LongComparator) thenComparing}({@link #comparing(LongFunction, Comparator) comparing}(keyExtractor,&nbsp;keyComparator))</code> expression.
*
* @param <K> the type of the sort key.
* @param keyExtractor the function used to extract the sort key.
* @param keyComparator the comparator used to compare the sort key.
* @return a lexicographic-order comparator composed of this comparator
* and then comparing an extracted sort key using the specified sort key comparator.
* @throws NullPointerException if either argument is null.
*/
public default <K> LongComparator thenComparing(LongFunction<? extends K> keyExtractor, Comparator<? super K> keyComparator) {
return thenComparing(comparing(keyExtractor, keyComparator));
}
/**
* Returns a lexicographic-order comparator with a function that extracts a comparable sort key.
*
* <p>This default implementation delegates to
* <code>{@link #thenComparing(LongComparator) thenComparing}({@link #comparing(LongFunction) comparing}(keyExtractor))</code> expression.
*
* @param <K> the type of the comparable sort key.
* @param keyExtractor the function used to extract the comparable sort key.
* @return a lexicographic-order comparator composed of this comparator
* and then comparing an extracted comparable sort key.
* @throws NullPointerException if the argument is null.
*/
public default <K extends Comparable<? super K>> LongComparator thenComparing(LongFunction<? extends K> keyExtractor) {
return thenComparing(comparing(keyExtractor));
}
/**
* Returns a lexicographic-order comparator with a function that extracts an int sort key.
*
* <p>This default implementation delegates to
* <code>{@link #thenComparing(LongComparator) thenComparing}({@link #comparingInt(LongToIntFunction) comparing}(keyExtractor))</code> expression.
*
* @param keyExtractor the function used to extract the int sort key.
* @return a lexicographic-order comparator composed of this comparator
* and then comparing an extracted int sort key.
* @throws NullPointerException if the argument is null.
*/
public default LongComparator thenComparingInt(LongToIntFunction keyExtractor) {
return thenComparing(comparingInt(keyExtractor));
}
/**
* Returns a lexicographic-order comparator with a function that extracts a long sort key.
*
* <p>This default implementation delegates to
* <code>{@link #thenComparing(LongComparator) thenComparing}({@link #comparingLong(LongUnaryOperator) comparing}(keyExtractor))</code> expression.
*
* @param keyExtractor the function used to extract the long sort key.
* @return a lexicographic-order comparator composed of this comparator
* and then comparing an extracted long sort key.
* @throws NullPointerException if the argument is null.
*/
public default LongComparator thenComparingLong(LongUnaryOperator keyExtractor) {
return thenComparing(comparingLong(keyExtractor));
}
/**
* Returns a lexicographic-order comparator with a function that extracts a double sort key.
*
* <p>This default implementation delegates to
* <code>{@link #thenComparing(LongComparator) thenComparing}({@link #comparingDouble(LongToDoubleFunction) comparing}(keyExtractor))</code> expression.
*
* @param keyExtractor the function used to extract the double sort key.
* @return a lexicographic-order comparator composed of this comparator
* and then comparing and extracted double sort key.
* @throws NullPointerException if the argument is null.
*/
public default LongComparator thenComparingDouble(LongToDoubleFunction keyExtractor) {
return thenComparing(comparingDouble(keyExtractor));
}
/**
* Accepts a function that extracts a sort key and a sort key comparator, and returns
* a comparator that compares by an extracted sort key using the specified sort key comparator.
*
* <p>The returned comparator is serializable if the specified function and comparator are both serializable.
*
* @param <K> the type of the sort key.
* @param keyExtractor the function used to extract the sort key.
* @param keyComparator the comparator used to compare the sort key.
* @return a comparator that compares by an extracted sort key using the specified sort key comparator.
* @throws NullPointerException if either argument is null.
*/
public static <K> LongComparator comparing(LongFunction<? extends K> keyExtractor, Comparator<? super K> keyComparator) {
Objects.requireNonNull(keyExtractor);
Objects.requireNonNull(keyComparator);
return (LongComparator & Serializable)
(i1, i2) -> keyComparator.compare(keyExtractor.apply(i1), keyExtractor.apply(i2));
}
/**
* Accepts a function that extracts a comparable sort, and returns
* a comparator that compares by an extracted comparable sort key.
*
* <p>The returned comparator is serializable if the specified function is also serializable.
*
* @param <K> the type of the comparable sort key.
* @param keyExtractor the function used to extract the comparable sort key.
* @return a comparator that compares by an extracted comparable sort key.
* @throws NullPointerException if the argument is null.
*/
public static <K extends Comparable<? super K>> LongComparator comparing(LongFunction<? extends K> keyExtractor) {
Objects.requireNonNull(keyExtractor);
return (LongComparator & Serializable)
(i1, i2) -> keyExtractor.apply(i1).compareTo(keyExtractor.apply(i2));
}
/**
* Accepts a function that extracts an int sort key, and returns
* a comparator that compares by an extracted int sort key.
*
* <p>The returned comparator is serializable if the specified function is also serializable.
*
* @param keyExtractor the function used to extract the int sort key.
* @return a comparator that compares by an extracted int sort key.
* @throws NullPointerException if the argument is null.
*/
public static LongComparator comparingInt(LongToIntFunction keyExtractor) {
Objects.requireNonNull(keyExtractor);
return (LongComparator & Serializable)
(i1, i2) -> Integer.compare(keyExtractor.applyAsInt(i1), keyExtractor.applyAsInt(i2));
}
/**
* Accepts a function that extracts a long sort key, and returns
* a comparator that compares by an extracted long sort key.
*
* <p>The returned comparator is serializable if the specified function is also serializable.
*
* @param keyExtractor the function used to extract the long sort key.
* @return a comparator that compares by an extracted long sort key.
* @throws NullPointerException if the argument is null.
*/
public static LongComparator comparingLong(LongUnaryOperator keyExtractor) {
Objects.requireNonNull(keyExtractor);
return (LongComparator & Serializable)
(i1, i2) -> Long.compare(keyExtractor.applyAsLong(i1), keyExtractor.applyAsLong(i2));
}
/**
* Accepts a function that extracts a double sort key, and returns
* a comparator that compares by an extracted double sort key.
*
* <p>The returned comparator is serializable if the specified function is also serializable.
*
* @param keyExtractor the function used to extract the double sort key.
* @return a comparator that compares by an extracted double sort key.
* @throws NullPointerException if the argument is null.
*/
public static LongComparator comparingDouble(LongToDoubleFunction keyExtractor) {
Objects.requireNonNull(keyExtractor);
return (LongComparator & Serializable)
(i1, i2) -> Double.compare(keyExtractor.applyAsDouble(i1), keyExtractor.applyAsDouble(i2));
}
}

View File

@ -0,0 +1,690 @@
/*
* !++
* QDS - Quick Data Signalling Library
* !-
* Copyright (C) 2002 - 2020 Devexperts LLC
* !-
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
* !__
*/
package com.devexperts.util;
import java.util.Comparator;
import java.util.List;
/**
* This class implements modified version of <b>Quick Sort</b> algorithm.
* This implementation offers <b>O(n*log(n))</b> performance on many data sets
* that cause other quick sort algorithms to degrade to quadratic performance.
*
* <p>The notable differences of this <b>Quick Sort</b> from other sorting algorithms are:
* <ul>
* <li> it is <b>unstable</b> - it can re-arrange equal elements in any order;
* <li> it is <b>robust</b> - it can withstand <b>unstable ordering</b> of elements,
* for example if ordering changes during sorting;
* <li> it is <b>garbage-free</b> - it does not allocate any temporary objects.
* </ul>
*
* <p>In the case of <b>unstable ordering</b> the result of this algorithm is not necessarily fully sorted,
* but it is guaranteed to complete in a finite amount of time and without exceptions.
* The result in this case would be partially sorted to the best of algorithm's ability.
*/
public class QuickSort {
/**
* Sorts the specified list into ascending order according
* to the {@linkplain Comparable natural ordering} of its elements.
* All elements in the list must implement the {@link Comparable} interface.
* Furthermore, all elements in the list must be <i>mutually comparable</i>.
*
* @param <T> the class of the objects in the list.
* @param list the list to be sorted.
* @throws ClassCastException if the list contains elements that are not <i>mutually comparable</i>.
*/
public static <T extends Comparable<? super T>> void sort(List<T> list) {
quickSort(list, 0, list.size() - 1, null);
}
/**
* Sorts the specified range of the specified list into ascending order according to the <i>natural ordering</i> of its elements.
* The range to be sorted extends from index {@code fromIndex}, inclusive, to index {@code toIndex}, exclusive.
* All elements in this range must implement the {@link Comparable} interface.
* Furthermore, all elements in this range must be <i>mutually comparable</i>.
*
* @param <T> the class of the objects in the list.
* @param list the list to be sorted.
* @param fromIndex the index of the first element (inclusive) to be sorted.
* @param toIndex the index of the last element (exclusive) to be sorted.
* @throws IllegalArgumentException if {@code fromIndex > toIndex}.
* @throws IndexOutOfBoundsException if {@code fromIndex < 0} or {@code toIndex > a.length}.
* @throws ClassCastException if the list contains elements that are not <i>mutually comparable</i>.
*/
public static <T extends Comparable<? super T>> void sort(List<T> list, int fromIndex, int toIndex) {
rangeCheck(list.size(), fromIndex, toIndex);
quickSort(list, fromIndex, toIndex - 1, null);
}
/**
* Sorts the specified list according to the order induced by the specified comparator.
* All elements in the list must be <i>mutually comparable</i> using the specified comparator.
*
* @param <T> the class of the objects in the list.
* @param list the list to be sorted.
* @param c the comparator to determine the order of the list. A {@code null} value indicates
* that the elements' <i>natural ordering</i> should be used.
* @throws ClassCastException if the list contains elements that are not <i>mutually comparable</i>
* using the specified comparator.
*/
public static <T> void sort(List<T> list, Comparator<? super T> c) {
quickSort(list, 0, list.size() - 1, c);
}
/**
* Sorts the specified range of the specified list according to the order induced by the specified comparator.
* The range to be sorted extends from index {@code fromIndex}, inclusive, to index {@code toIndex}, exclusive.
* All elements in the range must be <i>mutually comparable</i> by the specified comparator.
*
* @param <T> the class of the objects in the list.
* @param list the list to be sorted.
* @param fromIndex the index of the first element (inclusive) to be sorted.
* @param toIndex the index of the last element (exclusive) to be sorted.
* @param c the comparator to determine the order of the list. A {@code null} value indicates
* that the elements' <i>natural ordering</i> should be used.
* @throws IllegalArgumentException if {@code fromIndex > toIndex}.
* @throws IndexOutOfBoundsException if {@code fromIndex < 0} or {@code toIndex > a.length}.
* @throws ClassCastException if the list contains elements that are not <i>mutually comparable</i>
* using the specified comparator.
*/
public static <T> void sort(List<T> list, int fromIndex, int toIndex, Comparator<? super T> c) {
rangeCheck(list.size(), fromIndex, toIndex);
quickSort(list, fromIndex, toIndex - 1, c);
}
/**
* Sorts the specified array of objects into ascending order according
* to the {@linkplain Comparable natural ordering} of its elements.
* All elements in the array must implement the {@link Comparable} interface.
* Furthermore, all elements in the array must be <i>mutually comparable</i>.
*
* @param a the array to be sorted.
* @throws ClassCastException if the array contains elements that are not <i>mutually comparable</i>.
*/
public static void sort(Object[] a) {
quickSort(a, 0, a.length - 1, null);
}
/**
* Sorts the specified range of the specified array of objects into ascending order
* according to the {@linkplain Comparable natural ordering} of its elements.
* The range to be sorted extends from index {@code fromIndex}, inclusive, to index {@code toIndex}, exclusive.
* All elements in this range must implement the {@link Comparable} interface.
* Furthermore, all elements in this range must be <i>mutually comparable</i>.
*
* @param a the array to be sorted.
* @param fromIndex the index of the first element (inclusive) to be sorted.
* @param toIndex the index of the last element (exclusive) to be sorted.
* @throws IllegalArgumentException if {@code fromIndex > toIndex}.
* @throws IndexOutOfBoundsException if {@code fromIndex < 0} or {@code toIndex > a.length}.
* @throws ClassCastException if the array contains elements that are not <i>mutually comparable</i>.
*/
public static void sort(Object[] a, int fromIndex, int toIndex) {
rangeCheck(a.length, fromIndex, toIndex);
quickSort(a, fromIndex, toIndex - 1, null);
}
/**
* Sorts the specified array of objects according to the order induced by the specified comparator.
* All elements in the array must be <i>mutually comparable</i> by the specified comparator.
*
* @param <T> the class of the objects to be sorted.
* @param a the array to be sorted.
* @param c the comparator to determine the order of the array. A {@code null} value indicates
* that the elements' {@linkplain Comparable natural ordering} should be used.
* @throws ClassCastException if the array contains elements that are not <i>mutually comparable</i>
* using the specified comparator.
*/
public static <T> void sort(T[] a, Comparator<? super T> c) {
quickSort(a, 0, a.length - 1, c);
}
/**
* Sorts the specified range of the specified array of objects according to the order induced by the specified comparator.
* The range to be sorted extends from index {@code fromIndex}, inclusive, to index {@code toIndex}, exclusive.
* All elements in the range must be <i>mutually comparable</i> by the specified comparator.
*
* @param <T> the class of the objects to be sorted.
* @param a the array to be sorted.
* @param fromIndex the index of the first element (inclusive) to be sorted.
* @param toIndex the index of the last element (exclusive) to be sorted.
* @param c the comparator to determine the order of the array. A {@code null} value indicates
* that the elements' {@linkplain Comparable natural ordering} should be used.
* @throws IllegalArgumentException if {@code fromIndex > toIndex}.
* @throws IndexOutOfBoundsException if {@code fromIndex < 0} or {@code toIndex > a.length}.
* @throws ClassCastException if the array contains elements that are not <i>mutually comparable</i>
* using the specified comparator.
*/
public static <T> void sort(T[] a, int fromIndex, int toIndex, Comparator<? super T> c) {
rangeCheck(a.length, fromIndex, toIndex);
quickSort(a, fromIndex, toIndex - 1, c);
}
/**
* Sorts the specified array of ints according to the order induced by the specified comparator.
* All elements in the array must be <i>mutually comparable</i> by the specified comparator.
*
* @param a the array to be sorted.
* @param c the comparator to determine the order of the array.
*/
public static void sort(int[] a, IntComparator c) {
quickSort(a, 0, a.length - 1, c);
}
/**
* Sorts the specified range of the specified array of ints according to the order induced by the specified comparator.
* The range to be sorted extends from index {@code fromIndex}, inclusive, to index {@code toIndex}, exclusive.
* All elements in the range must be <i>mutually comparable</i> by the specified comparator.
*
* @param a the array to be sorted.
* @param fromIndex the index of the first element (inclusive) to be sorted.
* @param toIndex the index of the last element (exclusive) to be sorted.
* @param c the comparator to determine the order of the array.
* @throws IllegalArgumentException if {@code fromIndex > toIndex}.
* @throws IndexOutOfBoundsException if {@code fromIndex < 0} or {@code toIndex > a.length}.
*/
public static void sort(int[] a, int fromIndex, int toIndex, IntComparator c) {
rangeCheck(a.length, fromIndex, toIndex);
quickSort(a, fromIndex, toIndex - 1, c);
}
/**
* Sorts the specified array of longs according to the order induced by the specified comparator.
* All elements in the array must be <i>mutually comparable</i> by the specified comparator.
*
* @param a the array to be sorted.
* @param c the comparator to determine the order of the array.
*/
public static void sort(long[] a, LongComparator c) {
quickSort(a, 0, a.length - 1, c);
}
/**
* Sorts the specified range of the specified array of longs according to the order induced by the specified comparator.
* The range to be sorted extends from index {@code fromIndex}, inclusive, to index {@code toIndex}, exclusive.
* All elements in the range must be <i>mutually comparable</i> by the specified comparator.
*
* @param a the array to be sorted.
* @param fromIndex the index of the first element (inclusive) to be sorted.
* @param toIndex the index of the last element (exclusive) to be sorted.
* @param c the comparator to determine the order of the array.
* @throws IllegalArgumentException if {@code fromIndex > toIndex}.
* @throws IndexOutOfBoundsException if {@code fromIndex < 0} or {@code toIndex > a.length}.
*/
public static void sort(long[] a, int fromIndex, int toIndex, LongComparator c) {
rangeCheck(a.length, fromIndex, toIndex);
quickSort(a, fromIndex, toIndex - 1, c);
}
// ========== Quick Sort of x[lo..hi] (inclusive) ==========
private static final int BINARY_INSERT_LIST = 20;
private static final int BINARY_INSERT_ARRAY = 40;
private static final int MOM_START = 400;
private static final int MOM_BASE = 15;
static {
//noinspection ConstantConditions,PointlessBooleanExpression
if (BINARY_INSERT_LIST < 4 || BINARY_INSERT_ARRAY < 4 || MOM_START < 25 || MOM_BASE < 5)
throw new AssertionError("invalid sort constants");
}
private static <T> void quickSort(List<T> x, int lo, int hi, Comparator<? super T> comparator) {
// Quick sort large ranges in a loop to retain stack depth at log(n).
while (hi - lo > BINARY_INSERT_LIST) {
T pivot;
int loScan;
int hiScan;
if (hi - lo > MOM_START) {
// Range is large - perform median-of-medians search of good pivot.
pivot = x.get(medianOfMedians(comparator, x, momStep(lo, hi), lo, hi));
loScan = lo;
hiScan = hi;
} else {
// Range is small - perform median-of-five search of good pivot.
pivot = x.get(medianOfFive(comparator, x, lo, lo + 1, (lo + hi) >>> 1, hi - 1, hi));
// Median-of-five rearranges elements around pivot - skip comparisons of 4 outer elements.
loScan = lo + 2;
hiScan = hi - 2;
}
// Excessive checks (loScan <= hiScan) protect from IndexOutOfBoundsException due to unstable ordering.
while (loScan <= hiScan) {
while (loScan <= hiScan && compare(x.get(loScan), pivot, comparator) < 0)
loScan++;
while (loScan <= hiScan && compare(x.get(hiScan), pivot, comparator) > 0)
hiScan--;
if (loScan > hiScan)
break;
T tmp = x.get(loScan);
x.set(loScan, x.get(hiScan));
x.set(hiScan, tmp);
loScan++;
hiScan--;
}
// Do recursion into smaller range, then do larger range ourselves.
if (hiScan - lo < hi - loScan) {
quickSort(x, lo, hiScan, comparator);
// Protect from degenerate partition when (loScan == lo) due to unstable ordering.
lo = Math.max(loScan, lo + 1);
} else {
quickSort(x, loScan, hi, comparator);
// Protect from degenerate partition when (hiScan == hi) due to unstable ordering.
hi = Math.min(hiScan, hi - 1);
}
}
// Binary insertion sort the remaining small range.
binaryInsertionSort(x, lo, hi, comparator);
}
private static <T> void quickSort(T[] x, int lo, int hi, Comparator<? super T> comparator) {
while (hi - lo > BINARY_INSERT_ARRAY) {
T pivot;
int loScan;
int hiScan;
if (hi - lo > MOM_START) {
pivot = x[medianOfMedians(comparator, x, momStep(lo, hi), lo, hi)];
loScan = lo;
hiScan = hi;
} else {
pivot = x[medianOfFive(comparator, x, lo, lo + 1, (lo + hi) >>> 1, hi - 1, hi)];
loScan = lo + 2;
hiScan = hi - 2;
}
while (loScan <= hiScan) {
while (loScan <= hiScan && compare(x[loScan], pivot, comparator) < 0)
loScan++;
while (loScan <= hiScan && compare(x[hiScan], pivot, comparator) > 0)
hiScan--;
if (loScan > hiScan)
break;
T tmp = x[loScan];
x[loScan] = x[hiScan];
x[hiScan] = tmp;
loScan++;
hiScan--;
}
if (hiScan - lo < hi - loScan) {
quickSort(x, lo, hiScan, comparator);
lo = Math.max(loScan, lo + 1);
} else {
quickSort(x, loScan, hi, comparator);
hi = Math.min(hiScan, hi - 1);
}
}
binaryInsertionSort(x, lo, hi, comparator);
}
private static void quickSort(int[] x, int lo, int hi, IntComparator comparator) {
while (hi - lo > BINARY_INSERT_ARRAY) {
int pivot;
int loScan;
int hiScan;
if (hi - lo > MOM_START) {
pivot = x[medianOfMedians(comparator, x, momStep(lo, hi), lo, hi)];
loScan = lo;
hiScan = hi;
} else {
pivot = x[medianOfFive(comparator, x, lo, lo + 1, (lo + hi) >>> 1, hi - 1, hi)];
loScan = lo + 2;
hiScan = hi - 2;
}
while (loScan <= hiScan) {
while (loScan <= hiScan && compare(x[loScan], pivot, comparator) < 0)
loScan++;
while (loScan <= hiScan && compare(x[hiScan], pivot, comparator) > 0)
hiScan--;
if (loScan > hiScan)
break;
int tmp = x[loScan];
x[loScan] = x[hiScan];
x[hiScan] = tmp;
loScan++;
hiScan--;
}
if (hiScan - lo < hi - loScan) {
quickSort(x, lo, hiScan, comparator);
lo = Math.max(loScan, lo + 1);
} else {
quickSort(x, loScan, hi, comparator);
hi = Math.min(hiScan, hi - 1);
}
}
binaryInsertionSort(x, lo, hi, comparator);
}
private static void quickSort(long[] x, int lo, int hi, LongComparator comparator) {
while (hi - lo > BINARY_INSERT_ARRAY) {
long pivot;
int loScan;
int hiScan;
if (hi - lo > MOM_START) {
pivot = x[medianOfMedians(comparator, x, momStep(lo, hi), lo, hi)];
loScan = lo;
hiScan = hi;
} else {
pivot = x[medianOfFive(comparator, x, lo, lo + 1, (lo + hi) >>> 1, hi - 1, hi)];
loScan = lo + 2;
hiScan = hi - 2;
}
while (loScan <= hiScan) {
while (loScan <= hiScan && compare(x[loScan], pivot, comparator) < 0)
loScan++;
while (loScan <= hiScan && compare(x[hiScan], pivot, comparator) > 0)
hiScan--;
if (loScan > hiScan)
break;
long tmp = x[loScan];
x[loScan] = x[hiScan];
x[hiScan] = tmp;
loScan++;
hiScan--;
}
if (hiScan - lo < hi - loScan) {
quickSort(x, lo, hiScan, comparator);
lo = Math.max(loScan, lo + 1);
} else {
quickSort(x, loScan, hi, comparator);
hi = Math.min(hiScan, hi - 1);
}
}
binaryInsertionSort(x, lo, hi, comparator);
}
// ========== Binary Insertion Sort of x[lo..hi] (inclusive) ==========
private static <T> void binaryInsertionSort(List<T> x, int lo, int hi, Comparator<? super T> comparator) {
for (int i = lo; ++i <= hi;) {
T pivot = x.get(i);
int left = lo;
for (int right = i; left < right;) {
int mid = (left + right) >>> 1;
if (compare(pivot, x.get(mid), comparator) < 0)
right = mid;
else
left = mid + 1;
}
if (left < i) {
for (int k = i; k > left; k--)
x.set(k, x.get(k - 1));
x.set(left, pivot);
}
}
}
private static <T> void binaryInsertionSort(T[] x, int lo, int hi, Comparator<? super T> comparator) {
for (int i = lo; ++i <= hi;) {
T pivot = x[i];
int left = lo;
for (int right = i; left < right;) {
int mid = (left + right) >>> 1;
if (compare(pivot, x[mid], comparator) < 0)
right = mid;
else
left = mid + 1;
}
if (left < i) {
System.arraycopy(x, left, x, left + 1, i - left);
x[left] = pivot;
}
}
}
private static void binaryInsertionSort(int[] x, int lo, int hi, IntComparator comparator) {
for (int i = lo; ++i <= hi;) {
int pivot = x[i];
int left = lo;
for (int right = i; left < right;) {
int mid = (left + right) >>> 1;
if (compare(pivot, x[mid], comparator) < 0)
right = mid;
else
left = mid + 1;
}
if (left < i) {
System.arraycopy(x, left, x, left + 1, i - left);
x[left] = pivot;
}
}
}
private static void binaryInsertionSort(long[] x, int lo, int hi, LongComparator comparator) {
for (int i = lo; ++i <= hi;) {
long pivot = x[i];
int left = lo;
for (int right = i; left < right;) {
int mid = (left + right) >>> 1;
if (compare(pivot, x[mid], comparator) < 0)
right = mid;
else
left = mid + 1;
}
if (left < i) {
System.arraycopy(x, left, x, left + 1, i - left);
x[left] = pivot;
}
}
}
// ========== Median Of Medians ==========
// Finds median of medians using quinary tree and median of five in each node.
// Expected number of used elements is pow(5, 1 + ceil(log(1 + size / MOM_START, MOM_BASE))).
// All used elements are spaced evenly (as much as possible) using "step" step.
private static int momStep(int lo, int hi) {
int mult = 5;
for (int k = (int)((hi - lo + 1L) / MOM_START); k > 0; k /= MOM_BASE)
mult *= 5;
while (hi - lo < mult - 1 && mult > 5)
mult /= 5;
return (hi - lo) / (mult - 1);
}
private static <T> int medianOfMedians(Comparator<? super T> comparator, List<T> x, int step, int lo, int hi) {
int ns = (hi - lo - step * 4) / 5;
if (ns < step * 4)
return medianOfFive(comparator, x, lo, lo + step, (lo + hi) >>> 1, hi - step, hi);
int bs = ns + step;
return medianOfFive(comparator, x,
medianOfMedians(comparator, x, step, lo, lo + ns),
medianOfMedians(comparator, x, step, lo + bs, lo + bs + ns),
medianOfMedians(comparator, x, step, lo + bs + bs, hi - bs - bs),
medianOfMedians(comparator, x, step, hi - bs - ns, hi - bs),
medianOfMedians(comparator, x, step, hi - ns, hi)
);
}
private static <T> int medianOfMedians(Comparator<? super T> comparator, T[] x, int step, int lo, int hi) {
int ns = (hi - lo - step * 4) / 5;
if (ns < step * 4)
return medianOfFive(comparator, x, lo, lo + step, (lo + hi) >>> 1, hi - step, hi);
int bs = ns + step;
return medianOfFive(comparator, x,
medianOfMedians(comparator, x, step, lo, lo + ns),
medianOfMedians(comparator, x, step, lo + bs, lo + bs + ns),
medianOfMedians(comparator, x, step, lo + bs + bs, hi - bs - bs),
medianOfMedians(comparator, x, step, hi - bs - ns, hi - bs),
medianOfMedians(comparator, x, step, hi - ns, hi)
);
}
private static int medianOfMedians(IntComparator comparator, int[] x, int step, int lo, int hi) {
int ns = (hi - lo - step * 4) / 5;
if (ns < step * 4)
return medianOfFive(comparator, x, lo, lo + step, (lo + hi) >>> 1, hi - step, hi);
int bs = ns + step;
return medianOfFive(comparator, x,
medianOfMedians(comparator, x, step, lo, lo + ns),
medianOfMedians(comparator, x, step, lo + bs, lo + bs + ns),
medianOfMedians(comparator, x, step, lo + bs + bs, hi - bs - bs),
medianOfMedians(comparator, x, step, hi - bs - ns, hi - bs),
medianOfMedians(comparator, x, step, hi - ns, hi)
);
}
private static int medianOfMedians(LongComparator comparator, long[] x, int step, int lo, int hi) {
int ns = (hi - lo - step * 4) / 5;
if (ns < step * 4)
return medianOfFive(comparator, x, lo, lo + step, (lo + hi) >>> 1, hi - step, hi);
int bs = ns + step;
return medianOfFive(comparator, x,
medianOfMedians(comparator, x, step, lo, lo + ns),
medianOfMedians(comparator, x, step, lo + bs, lo + bs + ns),
medianOfMedians(comparator, x, step, lo + bs + bs, hi - bs - bs),
medianOfMedians(comparator, x, step, hi - bs - ns, hi - bs),
medianOfMedians(comparator, x, step, hi - ns, hi)
);
}
// ========== Median Of Five ==========
// Finds median of 5 elements using 6 comparisons. See first method for algorithm explanation.
// All methods do reorder their input around median, thus performing partial sorting.
// This side effect is used by quick sort algorithms to skip comparisons of 4 outer elements.
// This side effect is useless for median of medians algorithms, but by using same methods we save on bytecode.
private static <T> int medianOfFive(Comparator<? super T> comparator, List<T> x, int ai, int bi, int ci, int di, int ei) {
T a = x.get(ai);
T b = x.get(bi);
T c = x.get(ci);
T d = x.get(di);
T e = x.get(ei);
T t;
// (a, b, c, d, e) - sort (a, b)
if (compare(a, b, comparator) > 0) { t = a; a = b; b = t; }
// (a < b, c, d, e) - sort (d, e)
if (compare(d, e, comparator) > 0) { t = d; d = e; e = t; }
// (a < b, c, d < e) - sort pairs (a < b, d < e) by lowest of (a, d)
if (compare(a, d, comparator) > 0) { t = a; a = d; d = t; t = b; b = e; e = t; }
// (a < b, c, a < d < e) - now [a] < [b, d, e], put it aside
// [a] < [b, d, e] (b, c, d < e) - sort (b, c)
if (compare(b, c, comparator) > 0) { t = b; b = c; c = t; }
// [a] < [c, d, e] (b < c, d < e) - sort pairs (b < c, d < e) by lowest of (b, d)
if (compare(b, d, comparator) > 0) { t = b; b = d; d = t; t = c; c = e; e = t; }
// [a] < [c, d, e] (b < c, b < d < e) - now [b] < [c, d, e], put it aside
// [a, b] < [c, d, e] (c, d < e) - sort (c, d)
if (compare(c, d, comparator) > 0) { t = c; c = d; d = t; }
// [a, b] < [c, d, e] (c < d, c < e) - now [c] < [d, e], rewrite
// [a, b] < [c] < [d, e] - [c] is a median
x.set(ai, a);
x.set(bi, b);
x.set(ci, c);
x.set(di, d);
x.set(ei, e);
return ci;
}
private static <T> int medianOfFive(Comparator<? super T> comparator, T[] x, int ai, int bi, int ci, int di, int ei) {
T a = x[ai];
T b = x[bi];
T c = x[ci];
T d = x[di];
T e = x[ei];
T t;
if (compare(a, b, comparator) > 0) { t = a; a = b; b = t; }
if (compare(d, e, comparator) > 0) { t = d; d = e; e = t; }
if (compare(a, d, comparator) > 0) { t = a; a = d; d = t; t = b; b = e; e = t; }
if (compare(b, c, comparator) > 0) { t = b; b = c; c = t; }
if (compare(b, d, comparator) > 0) { t = b; b = d; d = t; t = c; c = e; e = t; }
if (compare(c, d, comparator) > 0) { t = c; c = d; d = t; }
x[ai] = a;
x[bi] = b;
x[ci] = c;
x[di] = d;
x[ei] = e;
return ci;
}
private static int medianOfFive(IntComparator comparator, int[] x, int ai, int bi, int ci, int di, int ei) {
int a = x[ai];
int b = x[bi];
int c = x[ci];
int d = x[di];
int e = x[ei];
int t;
if (compare(a, b, comparator) > 0) { t = a; a = b; b = t; }
if (compare(d, e, comparator) > 0) { t = d; d = e; e = t; }
if (compare(a, d, comparator) > 0) { t = a; a = d; d = t; t = b; b = e; e = t; }
if (compare(b, c, comparator) > 0) { t = b; b = c; c = t; }
if (compare(b, d, comparator) > 0) { t = b; b = d; d = t; t = c; c = e; e = t; }
if (compare(c, d, comparator) > 0) { t = c; c = d; d = t; }
x[ai] = a;
x[bi] = b;
x[ci] = c;
x[di] = d;
x[ei] = e;
return ci;
}
private static int medianOfFive(LongComparator comparator, long[] x, int ai, int bi, int ci, int di, int ei) {
long a = x[ai];
long b = x[bi];
long c = x[ci];
long d = x[di];
long e = x[ei];
long t;
if (compare(a, b, comparator) > 0) { t = a; a = b; b = t; }
if (compare(d, e, comparator) > 0) { t = d; d = e; e = t; }
if (compare(a, d, comparator) > 0) { t = a; a = d; d = t; t = b; b = e; e = t; }
if (compare(b, c, comparator) > 0) { t = b; b = c; c = t; }
if (compare(b, d, comparator) > 0) { t = b; b = d; d = t; t = c; c = e; e = t; }
if (compare(c, d, comparator) > 0) { t = c; c = d; d = t; }
x[ai] = a;
x[bi] = b;
x[ci] = c;
x[di] = d;
x[ei] = e;
return ci;
}
// ========== Utility Code ==========
/**
* Compares specified objects using either specified comparator or their natural ordering.
*/
@SuppressWarnings("unchecked")
private static int compare(Object o1, Object o2, Comparator c) {
// Boost performance and protect from degenerate partition due to unstable ordering.
if (o1 == o2)
return 0;
return c != null ? c.compare(o1, o2) : ((Comparable)o1).compareTo(o2);
}
private static int compare(int i1, int i2, IntComparator c) {
// Boost performance and protect from degenerate partition due to unstable ordering.
if (i1 == i2)
return 0;
return c.compare(i1, i2);
}
private static int compare(long i1, long i2, LongComparator c) {
// Boost performance and protect from degenerate partition due to unstable ordering.
if (i1 == i2)
return 0;
return c.compare(i1, i2);
}
/**
* Checks that fromIndex and toIndex are in range and throws appropriate exception if they aren't.
*/
private static void rangeCheck(int length, int fromIndex, int toIndex) {
if (fromIndex > toIndex)
throw new IllegalArgumentException("fromIndex " + fromIndex + " > toIndex " + toIndex);
if (fromIndex < 0)
throw new IndexOutOfBoundsException("fromIndex " + fromIndex + " < 0");
if (toIndex > length)
throw new IndexOutOfBoundsException("toIndex " + toIndex + " > length " + length);
}
/**
* Private constructor to prevent instantiation.
*/
private QuickSort() {}
}

View File

@ -0,0 +1,452 @@
/*
* !++
* QDS - Quick Data Signalling Library
* !-
* Copyright (C) 2002 - 2020 Devexperts LLC
* !-
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
* !__
*/
package com.devexperts.util;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.Arrays;
import java.util.Collection;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collector;
/**
* A synchronized thread-safe version of {@link IndexedSet} class.
* It provides following benefits over standard {@link IndexedSet}:
*
* <ul>
* <li> concurrent asynchronous read access
* <li> synchronized thread-safe write access
* <li> all iterators are concurrent
* </ul>
*
* <p>Note that <b>SynchronizedIndexedSet</b> can be wrapped by {@link IndexedMap}
* to create what can be considered a <b>SynchronizedIndexedMap</b>.
*/
public class SynchronizedIndexedSet<K, V> extends IndexedSet<K, V> {
private static final long serialVersionUID = 0;
// ========== static factory methods ===========
/**
* Creates new empty set with default indexer {@link IndexerFunction#DEFAULT}.
*/
public static <V> SynchronizedIndexedSet<V, V> create() {
return new SynchronizedIndexedSet<>();
}
/**
* Creates new empty set with default identity indexer.
*/
public static <V> SynchronizedIndexedSet<V, V> createIdentity() {
return new SynchronizedIndexedSet<>((IndexerFunction.IdentityKey<V, V>)(v -> v));
}
/**
* Creates new empty set with specified indexer.
*/
public static <K, V> SynchronizedIndexedSet<K, V> create(IndexerFunction<K, ? super V> indexer) {
return new SynchronizedIndexedSet<>(indexer);
}
/**
* Creates new empty set with specified identity indexer.
*/
public static <K, V> SynchronizedIndexedSet<K, V> createIdentity(IndexerFunction.IdentityKey<K, ? super V> indexer) {
return new SynchronizedIndexedSet<>(indexer);
}
/**
* Creates new empty set with specified int indexer.
*/
public static <V> SynchronizedIndexedSet<Integer, V> createInt(IndexerFunction.IntKey<? super V> indexer) {
return new SynchronizedIndexedSet<>(indexer);
}
/**
* Creates new empty set with specified long indexer.
*/
public static <V> SynchronizedIndexedSet<Long, V> createLong(IndexerFunction.LongKey<? super V> indexer) {
return new SynchronizedIndexedSet<>(indexer);
}
/**
* Creates new empty set with specified indexer.
*
* @deprecated Use {@link #createInt(IndexerFunction.IntKey) createInt(indexer)}
*/
@Deprecated
public static <V> SynchronizedIndexedSet<Integer, V> create(IndexerFunction.IntKey<? super V> indexer) {
return new SynchronizedIndexedSet<>(indexer);
}
/**
* Creates new empty set with specified indexer.
*
* @deprecated Use {@link #createLong(IndexerFunction.LongKey) createLong(indexer)}
*/
@Deprecated
public static <V> SynchronizedIndexedSet<Long, V> create(IndexerFunction.LongKey<? super V> indexer) {
return new SynchronizedIndexedSet<>(indexer);
}
/**
* Creates new empty set with specified indexer and specified initial capacity.
*
* @deprecated Use {@link #create(IndexerFunction) create(indexer)}.{@link #withCapacity(int) withCapacity(initialCapacity)}
*/
@Deprecated
public static <K, V> SynchronizedIndexedSet<K, V> create(IndexerFunction<K, ? super V> indexer, int initialCapacity) {
return new SynchronizedIndexedSet<>(indexer, initialCapacity);
}
/**
* Creates new empty set with specified indexer and specified initial capacity.
*
* @deprecated Use {@link #createInt(IndexerFunction.IntKey) createInt(indexer)}.{@link #withCapacity(int) withCapacity(initialCapacity)}
*/
@Deprecated
public static <V> SynchronizedIndexedSet<Integer, V> create(IndexerFunction.IntKey<? super V> indexer, int initialCapacity) {
return new SynchronizedIndexedSet<>(indexer, initialCapacity);
}
/**
* Creates new empty set with specified indexer and specified initial capacity.
*
* @deprecated Use {@link #createLong(IndexerFunction.LongKey) createLong(indexer)}.{@link #withCapacity(int) withCapacity(initialCapacity)}
*/
@Deprecated
public static <V> SynchronizedIndexedSet<Long, V> create(IndexerFunction.LongKey<? super V> indexer, int initialCapacity) {
return new SynchronizedIndexedSet<>(indexer, initialCapacity);
}
/**
* Creates a new set with specified indexer containing the elements in the specified collection.
*
* @deprecated Use {@link #create(IndexerFunction) create(indexer)}.{@link #withElements(Collection) withElements(c)}
*/
@Deprecated
public static <K, V> SynchronizedIndexedSet<K, V> create(IndexerFunction<K, ? super V> indexer, Collection<? extends V> c) {
return new SynchronizedIndexedSet<>(indexer, c);
}
/**
* Creates a new set with specified indexer containing the elements in the specified collection.
*
* @deprecated Use {@link #createInt(IndexerFunction.IntKey) createInt(indexer)}.{@link #withElements(Collection) withElements(c)}
*/
@Deprecated
public static <V> SynchronizedIndexedSet<Integer, V> create(IndexerFunction.IntKey<? super V> indexer, Collection<? extends V> c) {
return new SynchronizedIndexedSet<>(indexer, c);
}
/**
* Creates a new set with default indexer containing specified elements.
*/
@SafeVarargs
public static <V> SynchronizedIndexedSet<V, V> of(V... objs) {
return new SynchronizedIndexedSet<>(Arrays.asList(objs));
}
/**
* Returns a {@code Collector} that accumulates the input elements into a new {@code SynchronizedIndexedSet} with default indexer.
* This is an {@link Collector.Characteristics#CONCURRENT concurrent} and {@link Collector.Characteristics#UNORDERED unordered} Collector.
*/
@SuppressWarnings("unchecked")
public static <V> Collector<V, ?, ? extends SynchronizedIndexedSet<V, V>> collector() {
return collector((IndexerFunction<V, ? super V>)IndexerFunction.DEFAULT);
}
/**
* Returns a {@code Collector} that accumulates the input elements into a new {@code SynchronizedIndexedSet} with default identity indexer.
* This is an {@link Collector.Characteristics#CONCURRENT concurrent} and {@link Collector.Characteristics#UNORDERED unordered} Collector.
*/
public static <V> Collector<V, ?, ? extends SynchronizedIndexedSet<V, V>> collectorIdentity() {
return collector((IndexerFunction.IdentityKey<V, V>)(v -> v));
}
/**
* Returns a {@code Collector} that accumulates the input elements into a new {@code SynchronizedIndexedSet} with specified indexer.
* This is an {@link Collector.Characteristics#CONCURRENT concurrent} and {@link Collector.Characteristics#UNORDERED unordered} Collector.
*/
public static <K, V> Collector<V, ?, ? extends SynchronizedIndexedSet<K, V>> collector(IndexerFunction<K, ? super V> indexer) {
return Collector.of(() -> create(indexer), IndexedSet::add,
(left, right) -> { left.addAll(right); return left; },
Collector.Characteristics.CONCURRENT, Collector.Characteristics.UNORDERED, Collector.Characteristics.IDENTITY_FINISH);
}
/**
* Returns a {@code Collector} that accumulates the input elements into a new {@code SynchronizedIndexedSet} with specified identity indexer.
* This is an {@link Collector.Characteristics#CONCURRENT concurrent} and {@link Collector.Characteristics#UNORDERED unordered} Collector.
*/
public static <K, V> Collector<V, ?, ? extends SynchronizedIndexedSet<K, V>> collectorIdentity(IndexerFunction.IdentityKey<K, ? super V> indexer) {
return collector((IndexerFunction<K, ? super V>)indexer);
}
/**
* Returns a {@code Collector} that accumulates the input elements into a new {@code SynchronizedIndexedSet} with specified int indexer.
* This is an {@link Collector.Characteristics#CONCURRENT concurrent} and {@link Collector.Characteristics#UNORDERED unordered} Collector.
*/
public static <V> Collector<V, ?, ? extends SynchronizedIndexedSet<Integer, V>> collectorInt(IndexerFunction.IntKey<? super V> indexer) {
return collector((IndexerFunction<Integer, ? super V>)indexer);
}
/**
* Returns a {@code Collector} that accumulates the input elements into a new {@code SynchronizedIndexedSet} with specified long indexer.
* This is an {@link Collector.Characteristics#CONCURRENT concurrent} and {@link Collector.Characteristics#UNORDERED unordered} Collector.
*/
public static <V> Collector<V, ?, ? extends SynchronizedIndexedSet<Long, V>> collectorLong(IndexerFunction.LongKey<? super V> indexer) {
return collector((IndexerFunction<Long, ? super V>)indexer);
}
/**
* Returns a {@code Collector} that accumulates the input elements into a new {@code SynchronizedIndexedSet} with specified indexer.
* This is an {@link Collector.Characteristics#CONCURRENT concurrent} and {@link Collector.Characteristics#UNORDERED unordered} Collector.
*
* @deprecated Use {@link #collectorInt(IndexerFunction.IntKey) collectorInt(indexer)}
*/
@Deprecated
public static <V> Collector<V, ?, ? extends SynchronizedIndexedSet<Integer, V>> collector(IndexerFunction.IntKey<? super V> indexer) {
return collector((IndexerFunction<Integer, ? super V>)indexer);
}
/**
* Returns a {@code Collector} that accumulates the input elements into a new {@code SynchronizedIndexedSet} with specified indexer.
* This is an {@link Collector.Characteristics#CONCURRENT concurrent} and {@link Collector.Characteristics#UNORDERED unordered} Collector.
*
* @deprecated Use {@link #collectorLong(IndexerFunction.LongKey) collectorLong(indexer)}
*/
@Deprecated
public static <V> Collector<V, ?, ? extends SynchronizedIndexedSet<Long, V>> collector(IndexerFunction.LongKey<? super V> indexer) {
return collector((IndexerFunction<Long, ? super V>)indexer);
}
// ========== Construction and Sizing Operations ==========
/**
* Creates new empty set with default indexer {@link IndexerFunction#DEFAULT}.
*/
public SynchronizedIndexedSet() {
super();
}
/**
* Creates new empty set with default indexer {@link IndexerFunction#DEFAULT} and specified initial capacity.
*/
public SynchronizedIndexedSet(int initialCapacity) {
super(initialCapacity);
}
/**
* Creates new empty set with specified indexer.
*/
protected SynchronizedIndexedSet(IndexerFunction<K, ? super V> indexer) {
super(indexer);
}
/**
* Creates new empty set with specified indexer.
*
* @deprecated Use {@link #create(IndexerFunction) create(indexer)}
*/
@Deprecated
public SynchronizedIndexedSet(Indexer<K, ? super V> indexer) {
super(indexer);
}
/**
* Creates new empty set with specified indexer and specified initial capacity.
*/
protected SynchronizedIndexedSet(IndexerFunction<K, ? super V> indexer, int initialCapacity) {
super(indexer, initialCapacity);
}
/**
* Creates new empty set with specified indexer and specified initial capacity.
*
* @deprecated Use {@link #create(IndexerFunction) create(indexer)}.{@link #withCapacity(int) withCapacity(initialCapacity)}
*/
@Deprecated
public SynchronizedIndexedSet(Indexer<K, ? super V> indexer, int initialCapacity) {
super(indexer, initialCapacity);
}
/**
* Creates a new set containing the elements in the specified collection.
* If specified collection is an {@link IndexedSet}, then new indexed set uses same indexer,
* otherwise it uses default indexer {@link IndexerFunction#DEFAULT}.
*/
public SynchronizedIndexedSet(Collection<V> c) {
super(c);
}
/**
* Creates a new set with specified indexer containing the elements in the specified collection.
*/
protected SynchronizedIndexedSet(IndexerFunction<K, ? super V> indexer, Collection<? extends V> c) {
super(indexer, c);
}
/**
* Creates a new set with specified indexer containing the elements in the specified collection.
*
* @deprecated Use {@link #create(IndexerFunction) create(indexer)}.{@link #withElements(Collection) withElements(c)}
*/
@Deprecated
public SynchronizedIndexedSet(Indexer<K, ? super V> indexer, Collection<? extends V> c) {
super(indexer, c);
}
/**
* Returns a shallow copy of this set - the values themselves are not cloned.
*/
@Override
public synchronized SynchronizedIndexedSet<K, V> clone() {
return (SynchronizedIndexedSet<K, V>)super.clone();
}
/**
* Increases the capacity of this set instance, if necessary, to ensure that it
* can hold at least the number of elements specified by the capacity argument.
* <p>
* Returns <b>this</b> set instance for convenience.
*/
@Override
public synchronized SynchronizedIndexedSet<K, V> withCapacity(int capacity) {
return (SynchronizedIndexedSet<K, V>)super.withCapacity(capacity);
}
/**
* Adds all of the elements in the specified collection into this set.
* <p>
* Returns <b>this</b> set instance for convenience.
*/
@Override
public synchronized SynchronizedIndexedSet<K, V> withElements(Collection<? extends V> c) {
return (SynchronizedIndexedSet<K, V>)super.withElements(c);
}
/**
* Increases the capacity of this set instance, if necessary, to ensure that it
* can hold at least the number of elements specified by the capacity argument.
*/
@Override
public synchronized void ensureCapacity(int capacity) {
super.ensureCapacity(capacity);
}
/**
* Trims the capacity of this set instance to be the set's current size.
* An application can use this operation to minimize the storage of this set instance.
*/
@Override
public synchronized void trimToSize() {
super.trimToSize();
}
/**
* Removes all elements from this set.
*/
@Override
public synchronized void clear() {
super.clear();
}
// ========== Query Operations ==========
/**
* Returns static structure statistics of this set.
*/
@Override
public synchronized IndexedSetStats getStats() {
// This method is synchronized to provide consistent view of several cross-linked variables.
// It should not pose any contention risk anyway.
return super.getStats();
}
// ========== Modification Operations ==========
/**
* Puts specified element into this set and returns previous element that matches specified one.
*/
@Override
public synchronized V put(V value) {
return super.put(value);
}
/**
* Puts specified element into this set if it is absent and
* returns current element in the set that matches specified one.
* This is equivalent to
* <pre>
* if (set.containsValue(value)) {
* return set.getByValue(value);
* } else {
* set.put(value);
* return value;
* }
* </pre>
* except that the action is performed atomically if it is properly synchronized.
* <p>
* Note, that unlike {@link ConcurrentMap#putIfAbsent},
* this method returns specified value (not <b>null</b>) if the value was absent.
*/
@Override
public synchronized V putIfAbsentAndGet(V value) {
return super.putIfAbsentAndGet(value);
}
/**
* Removes the element from this set which matches specified value if it is present
* and returns removed element or <b>null</b> if none were found.
*/
@Override
public synchronized V removeValue(V value) {
return super.removeValue(value);
}
/**
* Removes the element from this set which matches specified key if it is present
* and returns removed element or <b>null</b> if none were found.
*/
@Override
public synchronized V removeKey(K key) {
return super.removeKey(key);
}
/**
* Removes the element from this set which matches specified key if it is present
* and returns removed element or <b>null</b> if none were found.
*/
@Override
public synchronized V removeKey(long key) {
return super.removeKey(key);
}
// ========== Internal Implementation - Helper Instance Methods ==========
@Override
void checkModification(Object checkCore, long checkModCount) {
// Do nothing - all iterators are concurrent.
}
@Override
synchronized void removeIterated(Object checkCore, long checkModCount, boolean concurrent, V lastValue, int lastIndex) {
super.removeIterated(checkCore, checkModCount, true, lastValue, lastIndex);
}
@Override
synchronized void writeCore(ObjectOutputStream out) throws IOException {
// This method is synchronized to provide consistent serialization.
// It should not pose any contention risk anyway.
super.writeCore(out);
}
}

View File

@ -0,0 +1,65 @@
/*
* !++
* QDS - Quick Data Signalling Library
* !-
* Copyright (C) 2002 - 2020 Devexperts LLC
* !-
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
* !__
*/
package com.devexperts.util;
/**
* A collection of static utility methods for manipulation of Java long time.
* @see System#currentTimeMillis()
*/
public class TimeUtil {
private TimeUtil() {} // do not create this class
/**
* Number of milliseconds in a second.
*/
public static final long SECOND = 1000;
/**
* Number of milliseconds in a minute.
*/
public static final long MINUTE = 60 * SECOND;
/**
* Number of milliseconds in an hour.
*/
public static final long HOUR = 60 * MINUTE;
/**
* Number of milliseconds in an day.
*/
public static final long DAY = 24 * HOUR;
/**
* Returns correct number of seconds with proper handling negative values and overflows.
* Idea is that number of milliseconds shall be within [0..999] interval
* so that the following equation always holds
* {@code getSecondsFromTime(timeMillis) * 1000L + getMillisFromTime(timeMillis) == timeMillis}
* as as long the time in seconds fits into <b>int</b>.
* @see #getMillisFromTime(long)
*/
public static int getSecondsFromTime(long timeMillis) {
return timeMillis >= 0 ? (int)Math.min(timeMillis / SECOND, Integer.MAX_VALUE) :
(int)Math.max((timeMillis + 1) / SECOND - 1, Integer.MIN_VALUE);
}
/**
* Returns correct number of milliseconds with proper handling negative values.
* Idea is that number of milliseconds shall be within [0..999] interval
* so that the following equation always holds
* {@code getSecondsFromTime(timeMillis) * 1000L + getMillisFromTime(timeMillis) == timeMillis}
* as as long the time in seconds fits into <b>int</b>.
* @see #getSecondsFromTime(long)
*/
public static int getMillisFromTime(long timeMillis) {
return (int)Math.floorMod(timeMillis, SECOND);
}
}

View File

@ -1,6 +1,6 @@
package com.rusefi.config.generated;
// 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 Thu Jul 23 23:53:53 UTC 2020
// by class com.rusefi.output.FileJavaFieldsConsumer
import com.rusefi.config.*;
@ -1056,7 +1056,7 @@ public class Fields {
public static final int servoOutputPins8_offset = 3147;
public static final int showHumanReadableWarning_offset = 976;
public static final int showSdCardWarning_offset = 76;
public static final int SIGNATURE_HASH = 692540479;
public static final int SIGNATURE_HASH = 1241418013;
public static final int silentTriggerError_offset = 1464;
public static final int slowAdcAlpha_offset = 2088;
public static final int sparkDwellRpmBins_offset = 332;
@ -1303,7 +1303,7 @@ public class Fields {
public static final int TS_RESPONSE_COMMAND_OK = 7;
public static final int TS_RESPONSE_OK = 0;
public static final char TS_SET_LOGGER_SWITCH = 'l';
public static final String TS_SIGNATURE = "rusEFI 2020.07.22.all.692540479";
public static final String TS_SIGNATURE = "rusEFI 2020.07.23.all.1241418013";
public static final char TS_SINGLE_WRITE_COMMAND = 'W';
public static final int tunerStudioSerialSpeed_offset = 728;
public static final int twoWireBatchIgnition_offset = 1476;
@ -2357,7 +2357,7 @@ public class Fields {
public static final Field GPPWM1_PWMFREQUENCY = Field.create("GPPWM1_PWMFREQUENCY", 4146, FieldType.INT16);
public static final Field GPPWM1_ONABOVEDUTY = Field.create("GPPWM1_ONABOVEDUTY", 4148, FieldType.INT8);
public static final Field GPPWM1_OFFBELOWDUTY = Field.create("GPPWM1_OFFBELOWDUTY", 4149, FieldType.INT8);
public static final String[] gppwm_channel_e = {"TPS", "MAP", "CLT", "IAT"};
public static final String[] gppwm_channel_e = {"TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "INVALID", "INVALID"};
public static final Field GPPWM1_LOADAXIS = Field.create("GPPWM1_LOADAXIS", 4150, FieldType.INT8, gppwm_channel_e);
public static final Field GPPWM1_ALIGNMENTFILL_MAP = Field.create("GPPWM1_ALIGNMENTFILL_MAP", 4151, FieldType.INT8);
public static final Field GPPWM1_TABLE = Field.create("GPPWM1_TABLE", 4168, FieldType.INT);

View File

@ -1,5 +1,6 @@
package com.rusefi.core;
import com.devexperts.logging.Logging;
import com.opensr5.Logger;
import com.rusefi.config.generated.Fields;
import com.rusefi.io.LinkDecoder;
@ -8,6 +9,8 @@ import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.util.*;
import static com.devexperts.logging.Logging.getLogging;
/**
* Date: 12/25/12
* Andrey Belomutskiy, (c) 2013-2020
@ -15,6 +18,8 @@ import java.util.*;
* @see #registerStringValueAction
*/
public class EngineState {
private static final Logging log = getLogging(EngineState.class);
public static final String SEPARATOR = ",";
public static final String PACKING_DELIMITER = ":";
public static final Class<EngineState> ENGINE_STATE_CLASS = EngineState.class;
@ -43,11 +48,10 @@ public class EngineState {
}
private final ResponseBuffer buffer;
private final Logger logger;
private final List<StringActionPair> actions = new ArrayList<>();
private final Set<String> keys = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
public EngineState(@NotNull final EngineStateListener listener, Logger logger) {
public EngineState(@NotNull final EngineStateListener listener) {
buffer = new ResponseBuffer(new ResponseBuffer.ResponseListener() {
public void onResponse(String response) {
if (response != null) {
@ -64,9 +68,8 @@ public class EngineState {
}
}
);
this.logger = logger;
registerStringValueAction(Fields.PROTOCOL_MSG, value -> MessagesCentral.getInstance().postMessage(logger, ENGINE_STATE_CLASS, value));
registerStringValueAction(Fields.PROTOCOL_MSG, value -> MessagesCentral.getInstance().postMessage(ENGINE_STATE_CLASS, value));
}
/**
@ -133,7 +136,7 @@ public class EngineState {
response = handleStringActionPair(response, pair, listener);
}
if (originalResponse.length() == response.length()) {
logger.info("EngineState.unknown: " + response);
log.info("EngineState.unknown: " + response);
int keyEnd = response.indexOf(SEPARATOR);
if (keyEnd == -1) {
// discarding invalid line
@ -146,7 +149,7 @@ public class EngineState {
return "";
}
String value = response.substring(keyEnd, valueEnd);
logger.info("Invalid key [" + unknownKey + "] value [" + value + "]");
log.info("Invalid key [" + unknownKey + "] value [" + value + "]");
// trying to process the rest of the line
response = response.substring(valueEnd + SEPARATOR.length());
}

Some files were not shown because too many files have changed in this diff Show More