From f32b29f31840dc09ed9368eb3bcd97cce16f9447 Mon Sep 17 00:00:00 2001 From: rusefi Date: Tue, 3 Sep 2019 19:30:51 -0400 Subject: [PATCH] Live Data: trigger current gap --- firmware/console/binary/tunerstudio.cpp | 4 ++- firmware/controllers/engine_controller.cpp | 2 +- .../controllers/generated/rusefi_generated.h | 5 +++- ...enerated.h => trigger_central_generated.h} | 8 ++--- .../generated/trigger_state_generated.h | 20 +++++++++++++ .../controllers/trigger/trigger_central.h | 2 +- .../controllers/trigger/trigger_decoder.cpp | 10 +++++-- .../controllers/trigger/trigger_decoder.h | 3 +- firmware/gen_config2.bat | 8 ++++- firmware/integration/rusefi_config.txt | 5 +++- firmware/integration/trigger_central.txt | 14 +++++++++ firmware/integration/trigger_state.txt | 16 ++-------- .../src/com/rusefi/ldmp/StateDictionary.java | 5 +++- .../com/rusefi/config/generated/Fields.java | 7 +++-- .../config/generated/TriggerCentral.java | 30 +++++++++++++++++++ .../rusefi/config/generated/TriggerState.java | 23 ++------------ java_console/ui/src/com/rusefi/Launcher.java | 2 +- .../ldmp/generated/TriggerDecoderMeta.java | 17 ++++++----- 18 files changed, 124 insertions(+), 57 deletions(-) rename firmware/controllers/generated/{trigger_generated.h => trigger_central_generated.h} (68%) create mode 100644 firmware/controllers/generated/trigger_state_generated.h create mode 100644 firmware/integration/trigger_central.txt create mode 100644 java_console/models/src/com/rusefi/config/generated/TriggerCentral.java diff --git a/firmware/console/binary/tunerstudio.cpp b/firmware/console/binary/tunerstudio.cpp index 678aef1d5b..30cd32588d 100644 --- a/firmware/console/binary/tunerstudio.cpp +++ b/firmware/console/binary/tunerstudio.cpp @@ -270,8 +270,10 @@ static const void * getStructAddr(int structId) { return static_cast(&engine->engineState); case LDS_FUEL_TRIM_STATE_INDEX: return static_cast(&engine->wallFuel); - case LDS_TRIGGER_STATE_INDEX: + case LDS_TRIGGER_CENTRAL_STATE_INDEX: return static_cast(&engine->triggerCentral); + case LDS_TRIGGER_STATE_STATE_INDEX: + return static_cast(&engine->triggerCentral.triggerState); #if EFI_ELECTRONIC_THROTTLE_BODY case LDS_ETB_PID_STATE_INDEX: return static_cast(&etbPid); diff --git a/firmware/controllers/engine_controller.cpp b/firmware/controllers/engine_controller.cpp index 5a84d019c3..b7e9f8cc6f 100644 --- a/firmware/controllers/engine_controller.cpp +++ b/firmware/controllers/engine_controller.cpp @@ -816,6 +816,6 @@ int getRusEfiVersion(void) { if (initBootloader() != 0) return 123; #endif /* EFI_BOOTLOADER_INCLUDE_CODE */ - return 20190902; + return 20190903; } #endif /* EFI_UNIT_TEST */ diff --git a/firmware/controllers/generated/rusefi_generated.h b/firmware/controllers/generated/rusefi_generated.h index 49390b9f82..1171c8f1a7 100644 --- a/firmware/controllers/generated/rusefi_generated.h +++ b/firmware/controllers/generated/rusefi_generated.h @@ -1334,6 +1334,8 @@ #define knockVThreshold_offset_hex 5e8 #define lcdThreadPeriodMs_offset 720 #define lcdThreadPeriodMs_offset_hex 2d0 +#define LDS_ALTERNATOR_PID_STATE_INDEX 9 +#define LDS_CJ125_PID_STATE_INDEX 10 #define LDS_CLT_STATE_INDEX 0 #define LDS_ENGINE_STATE_INDEX 3 #define LDS_ETB_PID_STATE_INDEX 7 @@ -1342,7 +1344,8 @@ #define LDS_IDLE_PID_STATE_INDEX 8 #define LDS_SPEED_DENSITY_STATE_INDEX 2 #define LDS_TPS_TPS_ENEICHMENT_STATE_INDEX 5 -#define LDS_TRIGGER_STATE_INDEX 6 +#define LDS_TRIGGER_CENTRAL_STATE_INDEX 6 +#define LDS_TRIGGER_STATE_STATE_INDEX 11 #define LE_COMMAND_LENGTH 200 #define LIS302DLCsPin_offset 2043 #define LIS302DLCsPin_offset_hex 7fb diff --git a/firmware/controllers/generated/trigger_generated.h b/firmware/controllers/generated/trigger_central_generated.h similarity index 68% rename from firmware/controllers/generated/trigger_generated.h rename to firmware/controllers/generated/trigger_central_generated.h index 030f704d87..c779b31f0e 100644 --- a/firmware/controllers/generated/trigger_generated.h +++ b/firmware/controllers/generated/trigger_central_generated.h @@ -1,8 +1,8 @@ -// this section was generated automatically by rusEfi tool ConfigDefinition.jar based on integration/trigger_state.txt Mon Sep 02 20:41:37 EDT 2019 +// this section was generated automatically by rusEfi tool ConfigDefinition.jar based on integration/trigger_central.txt Tue Sep 03 19:14:15 EDT 2019 // by class com.rusefi.output.CHeaderConsumer // begin -#ifndef CONTROLLERS_GENERATED_TRIGGER_GENERATED_H -#define CONTROLLERS_GENERATED_TRIGGER_GENERATED_H +#ifndef CONTROLLERS_GENERATED_TRIGGER_CENTRAL_GENERATED_H +#define CONTROLLERS_GENERATED_TRIGGER_CENTRAL_GENERATED_H #include "rusefi_types.h" #define HW_EVENT_TYPES 6 // start of trigger_central_s @@ -31,4 +31,4 @@ typedef struct trigger_central_s trigger_central_s; #endif // end -// this section was generated automatically by rusEfi tool ConfigDefinition.jar based on integration/trigger_state.txt Mon Sep 02 20:41:37 EDT 2019 +// this section was generated automatically by rusEfi tool ConfigDefinition.jar based on integration/trigger_central.txt Tue Sep 03 19:14:15 EDT 2019 diff --git a/firmware/controllers/generated/trigger_state_generated.h b/firmware/controllers/generated/trigger_state_generated.h new file mode 100644 index 0000000000..5333bb6bd8 --- /dev/null +++ b/firmware/controllers/generated/trigger_state_generated.h @@ -0,0 +1,20 @@ +// this section was generated automatically by rusEfi tool ConfigDefinition.jar based on integration/trigger_state.txt Tue Sep 03 19:14:16 EDT 2019 +// by class com.rusefi.output.CHeaderConsumer +// begin +#ifndef CONTROLLERS_GENERATED_TRIGGER_STATE_GENERATED_H +#define CONTROLLERS_GENERATED_TRIGGER_STATE_GENERATED_H +#include "rusefi_types.h" +// start of trigger_state_s +struct trigger_state_s { + /** + * offset 0 + */ + float currentGap = (float)0; + /** total size 4*/ +}; + +typedef struct trigger_state_s trigger_state_s; + +#endif +// end +// this section was generated automatically by rusEfi tool ConfigDefinition.jar based on integration/trigger_state.txt Tue Sep 03 19:14:16 EDT 2019 diff --git a/firmware/controllers/trigger/trigger_central.h b/firmware/controllers/trigger/trigger_central.h index 5352d863a2..c2827cf393 100644 --- a/firmware/controllers/trigger/trigger_central.h +++ b/firmware/controllers/trigger/trigger_central.h @@ -11,7 +11,7 @@ #include "rusefi_enums.h" #include "listener_array.h" #include "trigger_decoder.h" -#include "trigger_generated.h" +#include "trigger_central_generated.h" class Engine; typedef void (*ShaftPositionListener)(trigger_event_e signal, uint32_t index DECLARE_ENGINE_PARAMETER_SUFFIX); diff --git a/firmware/controllers/trigger/trigger_decoder.cpp b/firmware/controllers/trigger/trigger_decoder.cpp index 3873404291..334c915f5d 100644 --- a/firmware/controllers/trigger/trigger_decoder.cpp +++ b/firmware/controllers/trigger/trigger_decoder.cpp @@ -487,7 +487,12 @@ void TriggerState::decodeTriggerEvent(trigger_event_e const signal, efitime_t no bool isSynchronizationPoint; bool wasSynchronized = shaft_is_synchronized; - DISPLAY_STATE(Trigger) + DISPLAY_STATE(Trigger_State) + DISPLAY_TEXT(Current_Gap); + DISPLAY(DISPLAY_FIELD(currentGap)); + DISPLAY_TEXT(EOL); + + DISPLAY_STATE(Trigger_Central) DISPLAY(DISPLAY_CONFIG(TRIGGERINPUTPINS1)); DISPLAY_TEXT(Trigger_1_Fall); DISPLAY(DISPLAY_FIELD(HWEVENTCOUNTERS1)); @@ -511,8 +516,9 @@ void TriggerState::decodeTriggerEvent(trigger_event_e const signal, efitime_t no if (triggerShape->isSynchronizationNeeded) { // this is getting a little out of hand, any ideas? + currentGap = 1.0 * toothDurations[0] / toothDurations[1]; + if (CONFIG(debugMode) == DBG_TRIGGER_SYNC) { - float currentGap = 1.0 * toothDurations[0] / toothDurations[1]; #if EFI_TUNER_STUDIO tsOutputChannels.debugFloatField1 = currentGap; tsOutputChannels.debugFloatField2 = currentCycle.current_index; diff --git a/firmware/controllers/trigger/trigger_decoder.h b/firmware/controllers/trigger/trigger_decoder.h index bbe9150193..1143940db0 100644 --- a/firmware/controllers/trigger/trigger_decoder.h +++ b/firmware/controllers/trigger/trigger_decoder.h @@ -11,6 +11,7 @@ #include "global.h" #include "trigger_structure.h" #include "engine_configuration.h" +#include "trigger_state_generated.h" class TriggerState; @@ -44,7 +45,7 @@ typedef struct { /** * @see TriggerShape for trigger wheel shape definition */ -class TriggerState { +class TriggerState : public trigger_state_s { public: TriggerState(); /** diff --git a/firmware/gen_config2.bat b/firmware/gen_config2.bat index 5cbf64c457..662000653e 100644 --- a/firmware/gen_config2.bat +++ b/firmware/gen_config2.bat @@ -20,11 +20,17 @@ java -DSystemOut.name=gen_config2 ^ -java_destination ../java_console/models/src/com/rusefi/config/generated/ThermistorState.java ^ -c_destination controllers/generated/thermistor_generated.h +java -DSystemOut.name=gen_config2 ^ + -jar ../java_tools/ConfigDefinition.jar ^ + -definition integration/trigger_central.txt ^ + -java_destination ../java_console/models/src/com/rusefi/config/generated/TriggerCentral.java ^ + -c_destination controllers/generated/trigger_central_generated.h + java -DSystemOut.name=gen_config2 ^ -jar ../java_tools/ConfigDefinition.jar ^ -definition integration/trigger_state.txt ^ -java_destination ../java_console/models/src/com/rusefi/config/generated/TriggerState.java ^ - -c_destination controllers/generated/trigger_generated.h + -c_destination controllers/generated/trigger_state_generated.h java -DSystemOut.name=gen_config2 ^ -jar ../java_tools/ConfigDefinition.jar ^ diff --git a/firmware/integration/rusefi_config.txt b/firmware/integration/rusefi_config.txt index 64c58ee7ba..9643edaae3 100644 --- a/firmware/integration/rusefi_config.txt +++ b/firmware/integration/rusefi_config.txt @@ -1166,9 +1166,12 @@ end_struct #define LDS_ENGINE_STATE_INDEX 3 #define LDS_FUEL_TRIM_STATE_INDEX 4 #define LDS_TPS_TPS_ENEICHMENT_STATE_INDEX 5 -#define LDS_TRIGGER_STATE_INDEX 6 +#define LDS_TRIGGER_CENTRAL_STATE_INDEX 6 #define LDS_ETB_PID_STATE_INDEX 7 #define LDS_IDLE_PID_STATE_INDEX 8 +#define LDS_ALTERNATOR_PID_STATE_INDEX 9 +#define LDS_CJ125_PID_STATE_INDEX 10 +#define LDS_TRIGGER_STATE_STATE_INDEX 11 diff --git a/firmware/integration/trigger_central.txt b/firmware/integration/trigger_central.txt new file mode 100644 index 0000000000..05eb294328 --- /dev/null +++ b/firmware/integration/trigger_central.txt @@ -0,0 +1,14 @@ +#define HW_EVENT_TYPES 6 + +struct_no_prefix define_constructor trigger_central_s + + int[HW_EVENT_TYPES iterate] hwEventCounters; + +int vvtCamCounter + +int vvtEventRiseCounter +int vvtEventFallCounter + + +end_struct + diff --git a/firmware/integration/trigger_state.txt b/firmware/integration/trigger_state.txt index 925afa59ec..73d13a4443 100644 --- a/firmware/integration/trigger_state.txt +++ b/firmware/integration/trigger_state.txt @@ -1,13 +1,3 @@ -#define HW_EVENT_TYPES 6 - -struct_no_prefix define_constructor trigger_central_s - - int[HW_EVENT_TYPES iterate] hwEventCounters; - -int vvtCamCounter - -int vvtEventRiseCounter -int vvtEventFallCounter - - -end_struct +struct_no_prefix trigger_state_s + float currentGap; +end_struct \ No newline at end of file diff --git a/java_console/io/src/com/rusefi/ldmp/StateDictionary.java b/java_console/io/src/com/rusefi/ldmp/StateDictionary.java index c71c7dfe34..79f317f82d 100644 --- a/java_console/io/src/com/rusefi/ldmp/StateDictionary.java +++ b/java_console/io/src/com/rusefi/ldmp/StateDictionary.java @@ -22,9 +22,12 @@ public enum StateDictionary { register(Fields.LDS_ENGINE_STATE_INDEX, EngineState.VALUES); // 3 register(Fields.LDS_FUEL_TRIM_STATE_INDEX, EngineState.VALUES); register(Fields.LDS_TPS_TPS_ENEICHMENT_STATE_INDEX, EngineState.VALUES); // 5 - register(Fields.LDS_TRIGGER_STATE_INDEX, TriggerState.VALUES); + register(Fields.LDS_TRIGGER_CENTRAL_STATE_INDEX, TriggerCentral.VALUES); register(Fields.LDS_ETB_PID_STATE_INDEX, PidState.VALUES); // 7 register(Fields.LDS_IDLE_PID_STATE_INDEX, PidState.VALUES); + // LDS_ALTERNATOR_PID_STATE_INDEX + // LDS_CJ125_PID_STATE_INDEX + register(Fields.LDS_TRIGGER_STATE_STATE_INDEX, TriggerState.VALUES); // 11 } private void register(int ldsIndex, Field[] values) { diff --git a/java_console/models/src/com/rusefi/config/generated/Fields.java b/java_console/models/src/com/rusefi/config/generated/Fields.java index 0003a2b889..08934a3f2d 100644 --- a/java_console/models/src/com/rusefi/config/generated/Fields.java +++ b/java_console/models/src/com/rusefi/config/generated/Fields.java @@ -1,6 +1,6 @@ package com.rusefi.config.generated; -// this file was generated automatically by rusEfi tool ConfigDefinition.jar based on integration\rusefi_config.txt Tue Sep 03 18:55:21 EDT 2019 +// this file was generated automatically by rusEfi tool ConfigDefinition.jar based on integration\rusefi_config.txt Tue Sep 03 19:18:06 EDT 2019 // by class com.rusefi.output.JavaFieldsConsumer import com.rusefi.config.*; @@ -875,6 +875,8 @@ public class Fields { public static final int knockNoiseRpmBins_offset = 1852; public static final int knockVThreshold_offset = 1512; public static final int lcdThreadPeriodMs_offset = 720; + public static final int LDS_ALTERNATOR_PID_STATE_INDEX = 9; + public static final int LDS_CJ125_PID_STATE_INDEX = 10; public static final int LDS_CLT_STATE_INDEX = 0; public static final int LDS_ENGINE_STATE_INDEX = 3; public static final int LDS_ETB_PID_STATE_INDEX = 7; @@ -883,7 +885,8 @@ public class Fields { public static final int LDS_IDLE_PID_STATE_INDEX = 8; public static final int LDS_SPEED_DENSITY_STATE_INDEX = 2; public static final int LDS_TPS_TPS_ENEICHMENT_STATE_INDEX = 5; - public static final int LDS_TRIGGER_STATE_INDEX = 6; + public static final int LDS_TRIGGER_CENTRAL_STATE_INDEX = 6; + public static final int LDS_TRIGGER_STATE_STATE_INDEX = 11; public static final int LE_COMMAND_LENGTH = 200; public static final int LIS302DLCsPin_offset = 2043; public static final int logFormat_offset = 496; diff --git a/java_console/models/src/com/rusefi/config/generated/TriggerCentral.java b/java_console/models/src/com/rusefi/config/generated/TriggerCentral.java new file mode 100644 index 0000000000..85df7f451f --- /dev/null +++ b/java_console/models/src/com/rusefi/config/generated/TriggerCentral.java @@ -0,0 +1,30 @@ +package com.rusefi.config.generated; + +// this file was generated automatically by rusEfi tool ConfigDefinition.jar based on integration/trigger_central.txt Tue Sep 03 19:14:15 EDT 2019 + +// by class com.rusefi.output.JavaFieldsConsumer +import com.rusefi.config.*; + +public class TriggerCentral { + public static final int HW_EVENT_TYPES = 6; + public static final Field HWEVENTCOUNTERS1 = Field.create("HWEVENTCOUNTERS1", 0, FieldType.INT); + public static final Field HWEVENTCOUNTERS2 = Field.create("HWEVENTCOUNTERS2", 4, FieldType.INT); + public static final Field HWEVENTCOUNTERS3 = Field.create("HWEVENTCOUNTERS3", 8, FieldType.INT); + public static final Field HWEVENTCOUNTERS4 = Field.create("HWEVENTCOUNTERS4", 12, FieldType.INT); + public static final Field HWEVENTCOUNTERS5 = Field.create("HWEVENTCOUNTERS5", 16, FieldType.INT); + public static final Field HWEVENTCOUNTERS6 = Field.create("HWEVENTCOUNTERS6", 20, FieldType.INT); + public static final Field VVTCAMCOUNTER = Field.create("VVTCAMCOUNTER", 24, FieldType.INT); + public static final Field VVTEVENTRISECOUNTER = Field.create("VVTEVENTRISECOUNTER", 28, FieldType.INT); + public static final Field VVTEVENTFALLCOUNTER = Field.create("VVTEVENTFALLCOUNTER", 32, FieldType.INT); + public static final Field[] VALUES = { + HWEVENTCOUNTERS1, + HWEVENTCOUNTERS2, + HWEVENTCOUNTERS3, + HWEVENTCOUNTERS4, + HWEVENTCOUNTERS5, + HWEVENTCOUNTERS6, + VVTCAMCOUNTER, + VVTEVENTRISECOUNTER, + VVTEVENTFALLCOUNTER, + }; +} diff --git a/java_console/models/src/com/rusefi/config/generated/TriggerState.java b/java_console/models/src/com/rusefi/config/generated/TriggerState.java index 961b7de954..c6760f85cd 100644 --- a/java_console/models/src/com/rusefi/config/generated/TriggerState.java +++ b/java_console/models/src/com/rusefi/config/generated/TriggerState.java @@ -1,30 +1,13 @@ package com.rusefi.config.generated; -// this file was generated automatically by rusEfi tool ConfigDefinition.jar based on integration/trigger_state.txt Mon Sep 02 20:41:37 EDT 2019 +// this file was generated automatically by rusEfi tool ConfigDefinition.jar based on integration/trigger_state.txt Tue Sep 03 19:14:16 EDT 2019 // by class com.rusefi.output.JavaFieldsConsumer import com.rusefi.config.*; public class TriggerState { - public static final int HW_EVENT_TYPES = 6; - public static final Field HWEVENTCOUNTERS1 = Field.create("HWEVENTCOUNTERS1", 0, FieldType.INT); - public static final Field HWEVENTCOUNTERS2 = Field.create("HWEVENTCOUNTERS2", 4, FieldType.INT); - public static final Field HWEVENTCOUNTERS3 = Field.create("HWEVENTCOUNTERS3", 8, FieldType.INT); - public static final Field HWEVENTCOUNTERS4 = Field.create("HWEVENTCOUNTERS4", 12, FieldType.INT); - public static final Field HWEVENTCOUNTERS5 = Field.create("HWEVENTCOUNTERS5", 16, FieldType.INT); - public static final Field HWEVENTCOUNTERS6 = Field.create("HWEVENTCOUNTERS6", 20, FieldType.INT); - public static final Field VVTCAMCOUNTER = Field.create("VVTCAMCOUNTER", 24, FieldType.INT); - public static final Field VVTEVENTRISECOUNTER = Field.create("VVTEVENTRISECOUNTER", 28, FieldType.INT); - public static final Field VVTEVENTFALLCOUNTER = Field.create("VVTEVENTFALLCOUNTER", 32, FieldType.INT); + public static final Field CURRENTGAP = Field.create("CURRENTGAP", 0, FieldType.FLOAT); public static final Field[] VALUES = { - HWEVENTCOUNTERS1, - HWEVENTCOUNTERS2, - HWEVENTCOUNTERS3, - HWEVENTCOUNTERS4, - HWEVENTCOUNTERS5, - HWEVENTCOUNTERS6, - VVTCAMCOUNTER, - VVTEVENTRISECOUNTER, - VVTEVENTFALLCOUNTER, + CURRENTGAP, }; } diff --git a/java_console/ui/src/com/rusefi/Launcher.java b/java_console/ui/src/com/rusefi/Launcher.java index 22d2604c72..8f9ffc3200 100644 --- a/java_console/ui/src/com/rusefi/Launcher.java +++ b/java_console/ui/src/com/rusefi/Launcher.java @@ -48,7 +48,7 @@ import static com.rusefi.ui.storage.PersistentConfiguration.getConfig; * @see EngineSnifferPanel */ public class Launcher { - public static final int CONSOLE_VERSION = 20190901; + public static final int CONSOLE_VERSION = 20190903; public static final String INI_FILE_PATH = System.getProperty("ini_file_path", ".."); public static final String INPUT_FILES_PATH = System.getProperty("input_files_path", ".."); public static final String TOOLS_PATH = System.getProperty("tools_path", "."); diff --git a/java_console/ui/src/com/rusefi/ldmp/generated/TriggerDecoderMeta.java b/java_console/ui/src/com/rusefi/ldmp/generated/TriggerDecoderMeta.java index b182edb9ca..420ada2bda 100644 --- a/java_console/ui/src/com/rusefi/ldmp/generated/TriggerDecoderMeta.java +++ b/java_console/ui/src/com/rusefi/ldmp/generated/TriggerDecoderMeta.java @@ -4,22 +4,25 @@ import com.rusefi.ldmp.*; public class TriggerDecoderMeta { public static final Request[] CONTENT = new Request[]{ + new TextRequest("Current_Gap"), + new FieldRequest("Trigger_State", "currentGap"), + new TextRequest("EOL"), new ConfigRequest("TRIGGERINPUTPINS1"), new TextRequest("Trigger_1_Fall"), - new FieldRequest("Trigger", "HWEVENTCOUNTERS1"), + new FieldRequest("Trigger_Central", "HWEVENTCOUNTERS1"), new TextRequest("Rise"), - new FieldRequest("Trigger", "HWEVENTCOUNTERS2"), + new FieldRequest("Trigger_Central", "HWEVENTCOUNTERS2"), new TextRequest("EOL"), new ConfigRequest("TRIGGERINPUTPINS2"), new TextRequest("Trigger_2_Fall"), - new FieldRequest("Trigger", "HWEVENTCOUNTERS3"), + new FieldRequest("Trigger_Central", "HWEVENTCOUNTERS3"), new TextRequest("Rise"), - new FieldRequest("Trigger", "HWEVENTCOUNTERS4"), + new FieldRequest("Trigger_Central", "HWEVENTCOUNTERS4"), new TextRequest("EOL"), new TextRequest("VVT_1"), new ConfigRequest("CAMINPUTS1"), - new FieldRequest("Trigger", "vvtEventRiseCounter"), - new FieldRequest("Trigger", "vvtEventFallCounter"), - new FieldRequest("Trigger", "vvtCamCounter"), + new FieldRequest("Trigger_Central", "vvtEventRiseCounter"), + new FieldRequest("Trigger_Central", "vvtEventFallCounter"), + new FieldRequest("Trigger_Central", "vvtCamCounter"), }; } \ No newline at end of file