Add extracted tools: CitrineOS, OpenOCPP, ShapeShifter
- CitrineOS core extracted (CSMS OCPP 2.0.1) - OpenOCPP extracted (firmware OCPP 1.6J/2.0.1) - ShapeShifter library installed (pip install -e) - ShapeShifter specification extracted - EVerest extracted TODO updated with progress
This commit is contained in:
138
tools/EVerest-main/lib/everest/iso15118/.clang-format
Normal file
138
tools/EVerest-main/lib/everest/iso15118/.clang-format
Normal file
@@ -0,0 +1,138 @@
|
||||
---
|
||||
Language: Cpp
|
||||
# BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveMacros: true
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllConstructorInitializersOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortEnumsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: MultiLine
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: AfterColon
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 120
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DeriveLineEnding: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||
Priority: 2
|
||||
SortPriority: 0
|
||||
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||
Priority: 3
|
||||
SortPriority: 0
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
SortPriority: 0
|
||||
IncludeIsMainRegex: '(Test)?$'
|
||||
IncludeIsMainSourceRegex: ''
|
||||
IndentCaseLabels: false
|
||||
IndentGotoLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBinPackProtocolList: Auto
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PointerAlignment: Left
|
||||
ReflowComments: true
|
||||
SortIncludes: true
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyBlock: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInConditionalStatement: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
SpaceBeforeSquareBrackets: false
|
||||
Standard: Latest
|
||||
StatementMacros:
|
||||
- Q_UNUSED
|
||||
- QT_REQUIRE_VERSION
|
||||
TabWidth: 8
|
||||
UseCRLF: false
|
||||
UseTab: Never
|
||||
...
|
||||
|
||||
5
tools/EVerest-main/lib/everest/iso15118/.github/CODEOWNERS
vendored
Normal file
5
tools/EVerest-main/lib/everest/iso15118/.github/CODEOWNERS
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
* @a-w50 @SebaLukas @james-ctc @mlitre
|
||||
|
||||
# CI
|
||||
.ci/ @andistorm @SebaLukas
|
||||
.github/workflows/ @andistorm @SebaLukas
|
||||
5
tools/EVerest-main/lib/everest/iso15118/.gitignore
vendored
Normal file
5
tools/EVerest-main/lib/everest/iso15118/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
*build
|
||||
.vscode
|
||||
/pki
|
||||
test/sample_data
|
||||
.cache/
|
||||
93
tools/EVerest-main/lib/everest/iso15118/CMakeLists.txt
Normal file
93
tools/EVerest-main/lib/everest/iso15118/CMakeLists.txt
Normal file
@@ -0,0 +1,93 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
project(iso15118
|
||||
VERSION 0.9.1
|
||||
DESCRIPTION "iso15118 library suite"
|
||||
LANGUAGES CXX C
|
||||
)
|
||||
|
||||
find_package(everest-cmake 0.5
|
||||
PATHS ../everest-cmake
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
find_package(everest-cmake 0.5)
|
||||
|
||||
find_package(OpenSSL 3 REQUIRED)
|
||||
|
||||
if (NOT everest-cmake_FOUND)
|
||||
message(STATUS "Retrieving everest-cmake using FetchContent")
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
everest-cmake
|
||||
GIT_REPOSITORY https://github.com/EVerest/everest-cmake.git
|
||||
GIT_TAG v0.5.3
|
||||
)
|
||||
FetchContent_MakeAvailable(everest-cmake)
|
||||
set(everest-cmake_DIR "${everest-cmake_SOURCE_DIR}")
|
||||
include("${everest-cmake_SOURCE_DIR}/everest-cmake-config.cmake")
|
||||
endif()
|
||||
|
||||
# options
|
||||
option(${PROJECT_NAME}_BUILD_TESTING "Build unit tests, used if included as dependency" OFF)
|
||||
option(BUILD_TESTING "Build unit tests, used if standalone project" OFF)
|
||||
option(OPT_AUTODOWNLOAD_ISO20_SCHEMAS "\
|
||||
Automatically download ISO15118-20 schemas. Note: by setting this option to \
|
||||
true and hence downloading the schema files, YOU accept the ISO Customer \
|
||||
Licence Agreement (“Licence Agreement”), clauses 1. ISO’s Copyright, \
|
||||
7. Termination, 8. Limitations, and 9. Governing Law." OFF)
|
||||
|
||||
option(ISO15118_INSTALL "Enable install target" ${EVC_MAIN_PROJECT})
|
||||
option(DISABLE_ISO15118_LOCAL_DEPENDENCIES "Disable local dependency lookup for libiso15118" OFF)
|
||||
option(ISO15118_USE_EXPORTED_BUILD "Use (experimental) exported build of libiso15118" OFF)
|
||||
option(${PROJECT_NAME}_USE_PYTHON_VENV "Use python venv for pip install targets" ON)
|
||||
|
||||
if(${CMAKE_PROJECT_NAME} STREQUAL ${PROJECT_NAME})
|
||||
if(ISO15118_USE_EXPORTED_BUILD)
|
||||
include(cmake/exported-build.cmake)
|
||||
else()
|
||||
include(cmake/local-build.cmake)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# list of compile options
|
||||
set(ISO15118_COMPILE_OPTIONS_WARNING "-Wall;-Wextra;-Wno-unused-function;-Werror" CACHE STRING "A list of compile options used")
|
||||
message(STATUS "Building libiso15118 with the following compile options: ${ISO15118_COMPILE_OPTIONS_WARNING}")
|
||||
|
||||
if((${CMAKE_PROJECT_NAME} STREQUAL ${PROJECT_NAME} OR ${PROJECT_NAME}_BUILD_TESTING) AND BUILD_TESTING)
|
||||
set(ISO15118_BUILD_TESTING ON)
|
||||
endif()
|
||||
|
||||
# dependencies
|
||||
if (NOT DISABLE_EDM)
|
||||
evc_setup_edm()
|
||||
# In EDM mode, we can't install exports (because the dependencies usually do not install their exports)
|
||||
set(ISO15118_INSTALL OFF)
|
||||
endif()
|
||||
|
||||
add_subdirectory(input)
|
||||
add_subdirectory(src)
|
||||
|
||||
if (ISO15118_BUILD_TESTING)
|
||||
include(CTest)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
if (ISO15118_INSTALL)
|
||||
install(
|
||||
TARGETS
|
||||
iso15118
|
||||
EXPORT iso15118-targets
|
||||
)
|
||||
|
||||
install(
|
||||
DIRECTORY include/
|
||||
TYPE INCLUDE
|
||||
PATTERN "detail" EXCLUDE
|
||||
)
|
||||
|
||||
evc_setup_package(
|
||||
NAME iso15118
|
||||
EXPORT iso15118-targets
|
||||
NAMESPACE iso15118
|
||||
)
|
||||
endif()
|
||||
201
tools/EVerest-main/lib/everest/iso15118/LICENSE
Normal file
201
tools/EVerest-main/lib/everest/iso15118/LICENSE
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
144
tools/EVerest-main/lib/everest/iso15118/README.md
Normal file
144
tools/EVerest-main/lib/everest/iso15118/README.md
Normal file
@@ -0,0 +1,144 @@
|
||||
ISO 15118 library suite
|
||||
=======================
|
||||
|
||||
This is a C++ library implementation of ISO 15118-20, ISO15118-2 and DIN70121. The implementation of ISO15118-20 is currently under heavy development. DIN70121 and ISO15118-2 will follow and are currently covered by the [EvseV2G module](https://github.com/EVerest/EVerest/tree/main/modules/EvseV2G) of EVerest.
|
||||
|
||||
ISO 15118-20 Support
|
||||
--------------------
|
||||
|
||||
The following table shows the current support for the listed EVSE ISO15118-20 features.
|
||||
|
||||
| Feature | Supported |
|
||||
|------------------------------------|--------------------|
|
||||
| TCP, TLS 1.2 & 1.3 | :heavy_check_mark: |
|
||||
| DC, DC_BPT | :heavy_check_mark: |
|
||||
| AC, AC_BPT | :heavy_check_mark: |
|
||||
| MCS (Amd.) | :heavy_check_mark: |
|
||||
| AC DER (Amd.) | |
|
||||
| WPT | |
|
||||
| ACDP | |
|
||||
| ExternalPayment | :heavy_check_mark: |
|
||||
| Plug&Charge | WIP |
|
||||
| CertificateInstallation | |
|
||||
| Scheduled Mode | :heavy_check_mark: |
|
||||
| Dynamic Mode (+ MobilityNeedsMode) | :heavy_check_mark: |
|
||||
| Private Env | |
|
||||
| Pause/Resume | :heavy_check_mark: (dynamic mode) |
|
||||
| Standby | |
|
||||
| Schedule Renegotation | |
|
||||
| Smart Charging | |
|
||||
| Multiplex messages | |
|
||||
| Internet Service | |
|
||||
| Parking Status Service | |
|
||||
|
||||
ISO 15118 Support
|
||||
-----------------
|
||||
|
||||
ISO15118 support is distributed accross multiple repositories and modules in EVerest. Please see the following references of other ISO15118 related development:
|
||||
|
||||
- Some functionality of part 2 of ISO 15118 is integrated in the
|
||||
[EvseManager module in the EVerest repository](https://github.com/EVerest/EVerest/tree/main/modules/EVSE/EvseManager).
|
||||
- Current development for an EXI code generator (as used in the
|
||||
ISO 15118 protocol suite) is ongoing in the
|
||||
[cbexigen repository](https://github.com/EVerest/cbexigen).
|
||||
- The [repository libSlac](https://github.com/EVerest/libslac) contains
|
||||
definitions of SLAC messages that are used for ISO 15118 communication.
|
||||
- DIN70121 & ISO15118-2 functionality can be found in
|
||||
[EVerest module EvseV2G](https://github.com/EVerest/EVerest/tree/main/modules/EVSE/EvseV2G)
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
To build this library you need [everest-cmake](https://github.com/EVerest/everest-cmake) checkout in the same directory as libiso15118. If no `everest-cmake` is available, it is retrieved via FetchContent.
|
||||
|
||||
For Debian GNU/Linux 12 you will need the following dependencies:
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt install build-essential cmake libssl-dev
|
||||
```
|
||||
|
||||
For Fedora 41+ you will need the following dependencies:
|
||||
|
||||
```bash
|
||||
sudo dnf update
|
||||
sudo dnf install gcc gcc-c++ git make cmake openssl-devel
|
||||
```
|
||||
|
||||
OpenSSL version 3.0 or above is required. The build system `ninja` is optional.
|
||||
|
||||
Getting started
|
||||
---------------
|
||||
|
||||
```
|
||||
# Run cmake (BUILD_TESTING to enable/disable unit tests)
|
||||
cmake -S . -B build -G Ninja -DBUILD_TESTING=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
|
||||
|
||||
# Run cmake with disabled compiler warnings
|
||||
cmake -S . -B build -G Ninja -DBUILD_TESTING=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DISO15118_COMPILE_OPTIONS_WARNING=""
|
||||
|
||||
# Build
|
||||
ninja -C build
|
||||
|
||||
# Running tests
|
||||
ninja -C build test
|
||||
|
||||
# Generating a code coverage (BUILD_TESTING should be enabled)
|
||||
ninja -C build iso15118_gcovr_coverage
|
||||
```
|
||||
|
||||
The coverage report will be available in the index.html file in the `build/iso15118_gcovr_coverage` directory.
|
||||
|
||||
Version 8.2 or higher of gcovr is required for the coverage report. Install gcovr release from PyPI:
|
||||
```
|
||||
pip install gcovr
|
||||
```
|
||||
|
||||
GDB Debugging (VS Code)
|
||||
-----------------------
|
||||
|
||||
Run the cmake (from the build dir) with the debug commands on:
|
||||
```
|
||||
cmake .. -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=ON
|
||||
```
|
||||
|
||||
Run the GDB debugger with the following configuration:
|
||||
```
|
||||
{
|
||||
"name": "(gdb) Launch LIBISO TESTS",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/libiso15118/build/test/iso15118/fsm/test_d20_transitions",
|
||||
"args": [],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}/libiso15118/build/test/iso15118/fsm/",
|
||||
"environment": [],
|
||||
"externalConsole": false,
|
||||
"MIMode": "gdb",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
},
|
||||
{
|
||||
"description": "Set Disassembly Flavor to Intel",
|
||||
"text": "-gdb-set disassembly-flavor intel",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
]
|
||||
},
|
||||
```
|
||||
|
||||
Replace the `program` path to any test executable you are debugging.
|
||||
|
||||
Acknowledgment
|
||||
--------------
|
||||
|
||||
This library has thankfully received support from the German Federal Ministry
|
||||
for Economic Affairs and Climate Action.
|
||||
Information on the corresponding research project can be found here (in
|
||||
German only):
|
||||
[InterBDL research project](https://www.thu.de/de/org/iea/smartgrids/Seiten/InterBDL.aspx).
|
||||
|
||||

|
||||
1
tools/EVerest-main/lib/everest/iso15118/THIRD_PARTY.md
Normal file
1
tools/EVerest-main/lib/everest/iso15118/THIRD_PARTY.md
Normal file
@@ -0,0 +1 @@
|
||||
_Use this file to list out any third-party dependencies used by this project. You may choose to point to a Gemfile or other language specific packaging file for details._
|
||||
@@ -0,0 +1,57 @@
|
||||
# download everest-core (source of util and libcbv2g)
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(
|
||||
everest-core-src
|
||||
DOWNLOAD_DIR "everest-core/src"
|
||||
GIT_REPOSITORY "https://github.com/EVerest/everest-core.git"
|
||||
GIT_TAG "61e97863fd2fc9f429f9cd2e4b689139e7d46981"
|
||||
TIMEOUT 30
|
||||
LOG_DOWNLOAD ON
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
)
|
||||
|
||||
# util is header-only
|
||||
ExternalProject_Get_Property(everest-core-src SOURCE_DIR)
|
||||
set(UTIL_INCLUDE_DIR "${SOURCE_DIR}/lib/everest/util/include")
|
||||
|
||||
# workaround for https://gitlab.kitware.com/cmake/cmake/-/issues/15052
|
||||
file(MAKE_DIRECTORY ${UTIL_INCLUDE_DIR})
|
||||
|
||||
add_library(everest_util INTERFACE IMPORTED GLOBAL)
|
||||
add_library(everest::util ALIAS everest_util)
|
||||
set_property(TARGET everest_util PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${UTIL_INCLUDE_DIR})
|
||||
add_dependencies(everest_util everest-core-src)
|
||||
|
||||
# build everest-core/lib/everest/cbv2g
|
||||
ExternalProject_Add(
|
||||
cbv2g-src
|
||||
DOWNLOAD_COMMAND ""
|
||||
SOURCE_DIR "everest-core-src-prefix/src/everest-core-src/lib/everest/cbv2g"
|
||||
PREFIX "everest-core"
|
||||
INSTALL_COMMAND ""
|
||||
LOG_CONFIGURE ON
|
||||
LOG_BUILD ON
|
||||
DEPENDS everest-core-src
|
||||
)
|
||||
ExternalProject_Get_Property(cbv2g-src SOURCE_DIR)
|
||||
ExternalProject_Get_Property(cbv2g-src BINARY_DIR)
|
||||
set(CBV2G_INCLUDE_DIR "${SOURCE_DIR}/include")
|
||||
set(CBV2G_LIB_DIR "${BINARY_DIR}/lib/cbv2g")
|
||||
|
||||
# workaround for https://gitlab.kitware.com/cmake/cmake/-/issues/15052
|
||||
# create CBV2G_INCLUDE_DIR since it will not exist in configure step
|
||||
file(MAKE_DIRECTORY ${CBV2G_INCLUDE_DIR})
|
||||
|
||||
add_library(cbv2g_tp STATIC IMPORTED)
|
||||
add_library(cbv2g::tp ALIAS cbv2g_tp)
|
||||
set_property(TARGET cbv2g_tp PROPERTY IMPORTED_LOCATION ${CBV2G_LIB_DIR}/libcbv2g_tp.a)
|
||||
set_property(TARGET cbv2g_tp PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${CBV2G_INCLUDE_DIR})
|
||||
add_dependencies(cbv2g_tp cbv2g-src)
|
||||
|
||||
add_library(cbv2g_iso20 STATIC IMPORTED)
|
||||
add_library(cbv2g::iso20 ALIAS cbv2g_iso20)
|
||||
set_property(TARGET cbv2g_iso20 PROPERTY IMPORTED_LOCATION ${CBV2G_LIB_DIR}/libcbv2g_iso20.a)
|
||||
set_property(TARGET cbv2g_iso20 PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${CBV2G_INCLUDE_DIR})
|
||||
add_dependencies(cbv2g_iso20 cbv2g-src)
|
||||
@@ -0,0 +1,40 @@
|
||||
# detect if we try to build inside everest-core and libcbv2g is available
|
||||
message(STATUS "Attempting build with autodetected local dependencies")
|
||||
|
||||
get_filename_component(EVC_EVEREST_LIB_DIR ${PROJECT_SOURCE_DIR} DIRECTORY)
|
||||
set(EVC_CBV2G_DIR "${EVC_EVEREST_LIB_DIR}/cbv2g")
|
||||
if (EVC_CBV2G_DIR AND NOT DISABLE_ISO15118_LOCAL_DEPENDENCIES)
|
||||
message(STATUS "Detected libcbv2g in ${EVC_CBV2G_DIR}, if you do not want this set -DDISABLE_ISO15118_LOCAL_DEPENDENCIES=ON")
|
||||
add_subdirectory("${EVC_CBV2G_DIR}" libcbv2g)
|
||||
endif()
|
||||
|
||||
function(ev_register_library_target NAME)
|
||||
endfunction()
|
||||
|
||||
set(EVC_UTIL_DIR "${EVC_EVEREST_LIB_DIR}/util")
|
||||
if (EVC_UTIL_DIR AND NOT DISABLE_ISO15118_LOCAL_DEPENDENCIES)
|
||||
message(STATUS "Detected util in ${EVC_UTIL_DIR}, if you do not want this set -DDISABLE_ISO15118_LOCAL_DEPENDENCIES=ON")
|
||||
if (BUILD_TESTING)
|
||||
message(STATUS "Setting BUILD_TESTING temporary to false")
|
||||
set(CACHE_BUILD_TESTING ON)
|
||||
set(BUILD_TESTING OFF)
|
||||
endif()
|
||||
add_subdirectory("${EVC_UTIL_DIR}" util)
|
||||
if (CACHE_BUILD_TESTING)
|
||||
set(BUILD_TESTING ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# set venv location
|
||||
set(${PROJECT_NAME}_PYTHON_VENV_PATH "${CMAKE_BINARY_DIR}/venv" CACHE PATH "Path to python venv")
|
||||
|
||||
ev_setup_python_executable(
|
||||
USE_PYTHON_VENV ${${PROJECT_NAME}_USE_PYTHON_VENV}
|
||||
PYTHON_VENV_PATH ${${PROJECT_NAME}_PYTHON_VENV_PATH}
|
||||
)
|
||||
get_filename_component(EVC_LIB_DIR ${EVC_EVEREST_LIB_DIR} DIRECTORY)
|
||||
get_filename_component(EVC_DIR ${EVC_LIB_DIR} DIRECTORY)
|
||||
set(EVC_EDM_DIR "${EVC_DIR}/applications/dependency_manager")
|
||||
|
||||
# use edm from everest-core
|
||||
add_subdirectory("${EVC_EDM_DIR}" edm_tool)
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
catch2:
|
||||
git: https://github.com/catchorg/Catch2.git
|
||||
git_tag: v3.10.0
|
||||
cmake_condition: "ISO15118_BUILD_TESTING"
|
||||
@@ -0,0 +1,38 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace iso15118::config {
|
||||
|
||||
enum class TlsNegotiationStrategy {
|
||||
ACCEPT_CLIENT_OFFER,
|
||||
ENFORCE_TLS,
|
||||
ENFORCE_NO_TLS,
|
||||
};
|
||||
|
||||
enum class CertificateBackend {
|
||||
EVEREST_LAYOUT,
|
||||
JOSEPPA_LAYOUT,
|
||||
};
|
||||
|
||||
struct SSLConfig {
|
||||
CertificateBackend backend{CertificateBackend::EVEREST_LAYOUT};
|
||||
// Used by the JOSEPPA_LAYOUT
|
||||
std::string config_string;
|
||||
// Used by the EVEREST_LAYOUT
|
||||
std::string path_certificate_chain;
|
||||
std::string path_certificate_key;
|
||||
std::optional<std::string> private_key_password{};
|
||||
std::string path_certificate_v2g_root;
|
||||
std::string path_certificate_mo_root;
|
||||
bool enable_ssl_logging{false};
|
||||
bool enable_tls_key_logging{false};
|
||||
bool enforce_tls_1_3{false};
|
||||
std::filesystem::path tls_key_logging_path{};
|
||||
};
|
||||
|
||||
} // namespace iso15118::config
|
||||
@@ -0,0 +1,29 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2025 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include <iso15118/message/common_types.hpp>
|
||||
|
||||
namespace iso15118::d20 {
|
||||
|
||||
namespace dt = message_20::datatypes;
|
||||
|
||||
struct AcTargetPower {
|
||||
std::optional<dt::RationalNumber> target_active_power;
|
||||
std::optional<dt::RationalNumber> target_active_power_L2;
|
||||
std::optional<dt::RationalNumber> target_active_power_L3;
|
||||
std::optional<dt::RationalNumber> target_reactive_power;
|
||||
std::optional<dt::RationalNumber> target_reactive_power_L2;
|
||||
std::optional<dt::RationalNumber> target_reactive_power_L3;
|
||||
std::optional<dt::RationalNumber> target_frequency;
|
||||
};
|
||||
|
||||
struct AcPresentPower {
|
||||
std::optional<dt::RationalNumber> present_active_power;
|
||||
std::optional<dt::RationalNumber> present_active_power_L2;
|
||||
std::optional<dt::RationalNumber> present_active_power_L3;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20
|
||||
@@ -0,0 +1,78 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include <iso15118/d20/limits.hpp>
|
||||
#include <iso15118/message/common_types.hpp>
|
||||
|
||||
namespace iso15118::d20 {
|
||||
|
||||
struct ControlMobilityNeedsModes {
|
||||
message_20::datatypes::ControlMode control_mode;
|
||||
message_20::datatypes::MobilityNeedsMode mobility_mode;
|
||||
};
|
||||
|
||||
struct AcSetupConfig {
|
||||
uint32_t voltage;
|
||||
std::vector<message_20::datatypes::AcConnector> connectors;
|
||||
};
|
||||
|
||||
struct BptSetupConfig {
|
||||
message_20::datatypes::BptChannel bpt_channel;
|
||||
message_20::datatypes::GeneratorMode generator_mode;
|
||||
std::optional<message_20::datatypes::GridCodeIslandingDetectionMethod> grid_code_detection_method;
|
||||
};
|
||||
|
||||
struct EvseSetupConfig {
|
||||
std::string evse_id;
|
||||
std::vector<message_20::datatypes::ServiceCategory> supported_energy_services;
|
||||
std::vector<message_20::datatypes::Authorization> authorization_services;
|
||||
std::vector<uint16_t> supported_vas_services;
|
||||
bool enable_certificate_install_service;
|
||||
d20::DcTransferLimits dc_limits;
|
||||
d20::AcTransferLimits ac_limits;
|
||||
std::vector<ControlMobilityNeedsModes> control_mobility_modes;
|
||||
std::optional<std::string> custom_protocol{std::nullopt};
|
||||
std::optional<AcSetupConfig> ac_setup_config{std::nullopt};
|
||||
std::optional<BptSetupConfig> bpt_setup_config{std::nullopt};
|
||||
d20::DcTransferLimits powersupply_limits;
|
||||
};
|
||||
|
||||
// This should only have EVSE information
|
||||
struct SessionConfig {
|
||||
explicit SessionConfig(EvseSetupConfig);
|
||||
|
||||
std::string evse_id;
|
||||
|
||||
bool cert_install_service;
|
||||
std::vector<message_20::datatypes::Authorization> authorization_services;
|
||||
|
||||
std::vector<message_20::datatypes::ServiceCategory> supported_energy_transfer_services;
|
||||
std::vector<std::uint16_t> supported_vas_services;
|
||||
|
||||
std::vector<message_20::datatypes::AcParameterList> ac_parameter_list;
|
||||
std::vector<message_20::datatypes::AcBptParameterList> ac_bpt_parameter_list;
|
||||
std::vector<message_20::datatypes::DcParameterList> dc_parameter_list;
|
||||
std::vector<message_20::datatypes::DcBptParameterList> dc_bpt_parameter_list;
|
||||
|
||||
std::vector<message_20::datatypes::McsParameterList> mcs_parameter_list;
|
||||
std::vector<message_20::datatypes::McsBptParameterList> mcs_bpt_parameter_list;
|
||||
|
||||
std::vector<message_20::datatypes::InternetParameterList> internet_parameter_list;
|
||||
std::vector<message_20::datatypes::ParkingParameterList> parking_parameter_list;
|
||||
|
||||
DcTransferLimits dc_limits;
|
||||
AcTransferLimits ac_limits;
|
||||
|
||||
DcTransferLimits powersupply_limits;
|
||||
|
||||
std::vector<ControlMobilityNeedsModes> supported_control_mobility_modes;
|
||||
|
||||
std::optional<std::string> custom_protocol{std::nullopt};
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20
|
||||
@@ -0,0 +1,175 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <any>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
#include <iso15118/d20/timeout.hpp>
|
||||
#include <iso15118/message/payload_type.hpp>
|
||||
#include <iso15118/message/variant.hpp>
|
||||
#include <iso15118/session/feedback.hpp>
|
||||
#include <iso15118/session/logger.hpp>
|
||||
|
||||
#include "config.hpp"
|
||||
#include "control_event.hpp"
|
||||
#include "ev_information.hpp"
|
||||
#include "ev_session_info.hpp"
|
||||
#include "session.hpp"
|
||||
|
||||
namespace iso15118::d20 {
|
||||
|
||||
// forward declare
|
||||
class ControlEventQueue;
|
||||
|
||||
class MessageExchange {
|
||||
public:
|
||||
MessageExchange(io::StreamOutputView);
|
||||
|
||||
void set_request(std::unique_ptr<message_20::Variant> new_request);
|
||||
std::unique_ptr<message_20::Variant> pull_request();
|
||||
message_20::Type peek_request_type() const;
|
||||
|
||||
template <typename MessageType> void set_response(const MessageType& msg) {
|
||||
response_size = message_20::serialize(msg, response);
|
||||
response_available = true;
|
||||
payload_type = message_20::PayloadTypeTrait<MessageType>::type;
|
||||
response_type = message_20::TypeTrait<MessageType>::type;
|
||||
response_message = msg;
|
||||
}
|
||||
|
||||
template <typename Msg> std::optional<Msg> get_response() {
|
||||
static_assert(message_20::TypeTrait<Msg>::type != message_20::Type::None, "Unhandled type!");
|
||||
if (message_20::TypeTrait<Msg>::type != response_type) {
|
||||
return std::nullopt;
|
||||
}
|
||||
try {
|
||||
return std::any_cast<Msg>(response_message);
|
||||
} catch (const std::bad_any_cast& ex) {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
std::tuple<bool, size_t, io::v2gtp::PayloadType, message_20::Type> check_and_clear_response();
|
||||
bool has_response() const {
|
||||
return response_available;
|
||||
}
|
||||
|
||||
private:
|
||||
// input
|
||||
std::unique_ptr<message_20::Variant> request{nullptr};
|
||||
|
||||
// output
|
||||
const io::StreamOutputView response;
|
||||
size_t response_size{0};
|
||||
bool response_available{false};
|
||||
io::v2gtp::PayloadType payload_type;
|
||||
message_20::Type response_type;
|
||||
std::any response_message;
|
||||
};
|
||||
|
||||
std::unique_ptr<MessageExchange> create_message_exchange(uint8_t* buf, const size_t len);
|
||||
|
||||
struct StateBase;
|
||||
using BasePointerType = std::unique_ptr<StateBase>;
|
||||
|
||||
class Context {
|
||||
public:
|
||||
// FIXME (aw): bundle arguments
|
||||
Context(session::feedback::Callbacks, session::SessionLogger&, d20::SessionConfig, std::optional<PauseContext>&,
|
||||
const std::optional<ControlEvent>&, MessageExchange&, Timeouts&);
|
||||
|
||||
template <typename StateType, typename... Args> BasePointerType create_state(Args&&... args) {
|
||||
return std::make_unique<StateType>(*this, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
std::unique_ptr<message_20::Variant> pull_request();
|
||||
message_20::Type peek_request_type() const;
|
||||
|
||||
template <typename MessageType> void respond(const MessageType& msg) {
|
||||
message_exchange.set_response(msg);
|
||||
}
|
||||
|
||||
template <typename Msg> std::optional<Msg> get_response() {
|
||||
return message_exchange.get_response<Msg>();
|
||||
}
|
||||
|
||||
const auto& get_control_event() {
|
||||
return current_control_event;
|
||||
}
|
||||
|
||||
template <typename T> T const* get_control_event() {
|
||||
if (not current_control_event.has_value()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (not std::holds_alternative<T>(*current_control_event)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &std::get<T>(*current_control_event);
|
||||
}
|
||||
|
||||
void set_new_vehicle_cert_hash(std::optional<io::sha512_hash_t> hash) {
|
||||
vehicle_cert_hash = hash;
|
||||
}
|
||||
|
||||
auto get_new_vehicle_cert_hash() const {
|
||||
return vehicle_cert_hash;
|
||||
}
|
||||
|
||||
void start_timeout(d20::TimeoutType type, uint32_t time_ms) {
|
||||
timeouts.start_timeout(type, time_ms);
|
||||
}
|
||||
|
||||
void stop_timeout(d20::TimeoutType type) {
|
||||
timeouts.stop_timeout(type);
|
||||
}
|
||||
|
||||
d20::TimeoutType const* get_active_timeout() {
|
||||
if (not current_timeout.has_value()) {
|
||||
return nullptr;
|
||||
}
|
||||
return ¤t_timeout.value();
|
||||
}
|
||||
|
||||
void set_active_timeout(TimeoutType timeout) {
|
||||
current_timeout = timeout;
|
||||
}
|
||||
|
||||
const session::Feedback feedback;
|
||||
|
||||
session::SessionLogger& log;
|
||||
|
||||
Session session;
|
||||
|
||||
SessionConfig session_config;
|
||||
|
||||
// Contains the EV received data
|
||||
EVSessionInfo session_ev_info;
|
||||
EVInformation ev_info;
|
||||
|
||||
std::optional<d20::PauseContext>& pause_ctx;
|
||||
|
||||
bool session_stopped{false};
|
||||
bool session_paused{false};
|
||||
|
||||
std::optional<UpdateDynamicModeParameters> cache_dynamic_mode_parameters;
|
||||
std::optional<AcTargetPower> cache_ac_target_power;
|
||||
std::optional<AcPresentPower> cache_ac_present_power;
|
||||
|
||||
private:
|
||||
const std::optional<ControlEvent>& current_control_event;
|
||||
MessageExchange& message_exchange;
|
||||
|
||||
std::optional<io::sha512_hash_t> vehicle_cert_hash{std::nullopt};
|
||||
|
||||
Timeouts& timeouts;
|
||||
|
||||
std::optional<TimeoutType> current_timeout{std::nullopt};
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20
|
||||
@@ -0,0 +1,94 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include <iso15118/d20/ac_powers.hpp>
|
||||
#include <iso15118/d20/dynamic_mode_parameters.hpp>
|
||||
#include <iso15118/d20/limits.hpp>
|
||||
|
||||
namespace iso15118::d20 {
|
||||
class CableCheckFinished {
|
||||
public:
|
||||
explicit CableCheckFinished(bool success_) : success(success_) {
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return success;
|
||||
}
|
||||
|
||||
private:
|
||||
bool success;
|
||||
};
|
||||
|
||||
struct PresentVoltageCurrent {
|
||||
float voltage;
|
||||
float current;
|
||||
};
|
||||
|
||||
class AuthorizationResponse {
|
||||
public:
|
||||
explicit AuthorizationResponse(bool authorized_) : authorized(authorized_) {
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return authorized;
|
||||
}
|
||||
|
||||
private:
|
||||
bool authorized;
|
||||
};
|
||||
|
||||
class StopCharging {
|
||||
public:
|
||||
explicit StopCharging(bool stop_) : stop(stop_) {
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return stop;
|
||||
}
|
||||
|
||||
private:
|
||||
bool stop;
|
||||
};
|
||||
|
||||
class PauseCharging {
|
||||
public:
|
||||
explicit PauseCharging(bool pause_) : pause(pause_) {
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return pause;
|
||||
}
|
||||
|
||||
private:
|
||||
bool pause;
|
||||
};
|
||||
|
||||
using EnergyServices = std::vector<message_20::datatypes::ServiceCategory>;
|
||||
|
||||
class ClosedContactor {
|
||||
public:
|
||||
explicit ClosedContactor(bool closed_) : closed(closed_) {
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return closed;
|
||||
}
|
||||
|
||||
private:
|
||||
bool closed;
|
||||
};
|
||||
|
||||
// TODO(SL): Define this globally for message and states
|
||||
using SupportedVASs = std::vector<uint16_t>;
|
||||
|
||||
using ControlEvent = std::variant<CableCheckFinished, PresentVoltageCurrent, AuthorizationResponse, StopCharging,
|
||||
PauseCharging, DcTransferLimits, AcTransferLimits, UpdateDynamicModeParameters,
|
||||
ClosedContactor, AcTargetPower, AcPresentPower, EnergyServices, SupportedVASs>;
|
||||
|
||||
} // namespace iso15118::d20
|
||||
@@ -0,0 +1,23 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <queue>
|
||||
|
||||
#include "control_event.hpp"
|
||||
|
||||
namespace iso15118::d20 {
|
||||
|
||||
class ControlEventQueue {
|
||||
public:
|
||||
std::optional<ControlEvent> pop();
|
||||
void push(ControlEvent);
|
||||
|
||||
private:
|
||||
std::queue<ControlEvent> queue;
|
||||
std::mutex mutex;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20
|
||||
@@ -0,0 +1,17 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2024 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
#include <optional>
|
||||
|
||||
namespace iso15118::d20 {
|
||||
|
||||
struct UpdateDynamicModeParameters {
|
||||
std::optional<std::time_t> departure_time;
|
||||
std::optional<std::uint8_t> target_soc;
|
||||
std::optional<std::uint8_t> min_soc;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20
|
||||
@@ -0,0 +1,24 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2025 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/message/supported_app_protocol.hpp>
|
||||
|
||||
#include <everest/util/vector/fixed_vector.hpp>
|
||||
|
||||
namespace iso15118::d20 {
|
||||
|
||||
using EVSupportedAppProtocols = everest::lib::util::fixed_vector<message_20::SupportedAppProtocol, 20>;
|
||||
|
||||
// Holds information about the EV
|
||||
struct EVInformation {
|
||||
EVSupportedAppProtocols ev_supported_app_protocols;
|
||||
message_20::SupportedAppProtocol selected_app_protocol;
|
||||
std::string evcc_id;
|
||||
std::optional<std::string> ev_tls_leaf_cert;
|
||||
std::optional<std::string> ev_tls_sub_ca_1_cert;
|
||||
std::optional<std::string> ev_tls_sub_ca_2_cert;
|
||||
std::optional<std::string> ev_tls_root_cert;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20
|
||||
@@ -0,0 +1,17 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2025 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/message/common_types.hpp>
|
||||
#include <iso15118/session/feedback.hpp>
|
||||
|
||||
namespace iso15118::d20 {
|
||||
|
||||
// Holds information reported by the EV
|
||||
struct EVSessionInfo {
|
||||
session::feedback::EvTransferLimits ev_transfer_limits;
|
||||
session::feedback::EvSEControlMode ev_control_mode;
|
||||
std::vector<message_20::datatypes::ServiceCategory> ev_energy_services;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20
|
||||
@@ -0,0 +1,44 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2024 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include <iso15118/message/common_types.hpp>
|
||||
|
||||
namespace iso15118::d20 {
|
||||
|
||||
namespace dt = message_20::datatypes;
|
||||
|
||||
template <typename T> struct Limit {
|
||||
T max;
|
||||
T min;
|
||||
};
|
||||
|
||||
struct Limits {
|
||||
Limit<message_20::datatypes::RationalNumber> power;
|
||||
Limit<message_20::datatypes::RationalNumber> current;
|
||||
};
|
||||
|
||||
struct DcTransferLimits {
|
||||
Limits charge_limits;
|
||||
std::optional<Limits> discharge_limits;
|
||||
Limit<message_20::datatypes::RationalNumber> voltage;
|
||||
std::optional<message_20::datatypes::RationalNumber> power_ramp_limit;
|
||||
};
|
||||
|
||||
struct AcTransferLimits {
|
||||
Limit<dt::RationalNumber> charge_power;
|
||||
std::optional<Limit<dt::RationalNumber>> charge_power_L2;
|
||||
std::optional<Limit<dt::RationalNumber>> charge_power_L3;
|
||||
|
||||
dt::RationalNumber nominal_frequency;
|
||||
std::optional<dt::RationalNumber> max_power_asymmetry;
|
||||
std::optional<dt::RationalNumber> power_ramp_limitation;
|
||||
|
||||
std::optional<Limit<dt::RationalNumber>> discharge_power;
|
||||
std::optional<Limit<dt::RationalNumber>> discharge_power_L2;
|
||||
std::optional<Limit<dt::RationalNumber>> discharge_power_L3;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20
|
||||
@@ -0,0 +1,152 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include <iso15118/io/sha_hash.hpp>
|
||||
#include <iso15118/message/common_types.hpp>
|
||||
|
||||
#include <everest/util/vector/fixed_vector.hpp>
|
||||
|
||||
namespace iso15118::d20 {
|
||||
|
||||
namespace dt = message_20::datatypes;
|
||||
|
||||
// Key: service IDs, value: vector with the parameter set ids
|
||||
using CustomVasList = std::map<std::uint16_t, std::vector<uint16_t>>;
|
||||
|
||||
struct OfferedServices {
|
||||
|
||||
everest::lib::util::fixed_vector<dt::Authorization, 2> auth_services;
|
||||
std::vector<dt::ServiceCategory> energy_services;
|
||||
std::vector<uint16_t> vas_services;
|
||||
|
||||
std::map<uint8_t, dt::AcParameterList> ac_parameter_list;
|
||||
std::map<uint8_t, dt::AcBptParameterList> ac_bpt_parameter_list;
|
||||
std::map<uint8_t, dt::DcParameterList> dc_parameter_list;
|
||||
std::map<uint8_t, dt::DcBptParameterList> dc_bpt_parameter_list;
|
||||
std::map<uint8_t, dt::McsParameterList> mcs_parameter_list;
|
||||
std::map<uint8_t, dt::McsBptParameterList> mcs_bpt_parameter_list;
|
||||
std::map<uint8_t, dt::InternetParameterList> internet_parameter_list;
|
||||
std::map<uint8_t, dt::ParkingParameterList> parking_parameter_list;
|
||||
CustomVasList custom_vas_list;
|
||||
};
|
||||
|
||||
struct SelectedServiceParameters {
|
||||
|
||||
dt::ServiceCategory selected_energy_service;
|
||||
|
||||
std::variant<dt::AcConnector, dt::DcConnector, dt::McsConnector> selected_connector;
|
||||
dt::ControlMode selected_control_mode;
|
||||
dt::MobilityNeedsMode selected_mobility_needs_mode;
|
||||
dt::Pricing selected_pricing;
|
||||
|
||||
// BPT
|
||||
std::optional<dt::BptChannel> selected_bpt_channel;
|
||||
std::optional<dt::GeneratorMode> selected_generator_mode;
|
||||
|
||||
// AC specific
|
||||
std::optional<float> evse_nominal_voltage;
|
||||
std::optional<dt::GridCodeIslandingDetectionMethod> selected_grid_code_method;
|
||||
|
||||
SelectedServiceParameters() = default;
|
||||
SelectedServiceParameters(dt::ServiceCategory energy_service_, dt::DcConnector dc_connector_,
|
||||
dt::ControlMode control_mode_, dt::MobilityNeedsMode mobility_, dt::Pricing pricing_);
|
||||
SelectedServiceParameters(dt::ServiceCategory energy_service_, dt::DcConnector dc_connector_,
|
||||
dt::ControlMode control_mode_, dt::MobilityNeedsMode mobility_, dt::Pricing pricing_,
|
||||
dt::BptChannel channel_, dt::GeneratorMode generator_);
|
||||
SelectedServiceParameters(dt::ServiceCategory energy_service_, dt::McsConnector mcs_connector_,
|
||||
dt::ControlMode control_mode_, dt::MobilityNeedsMode mobility_, dt::Pricing pricing_);
|
||||
SelectedServiceParameters(dt::ServiceCategory energy_service_, dt::McsConnector mcs_connector_,
|
||||
dt::ControlMode control_mode_, dt::MobilityNeedsMode mobility_, dt::Pricing pricing_,
|
||||
dt::BptChannel channel_, dt::GeneratorMode generator_);
|
||||
SelectedServiceParameters(dt::ServiceCategory energy_service_, dt::AcConnector ac_connector_,
|
||||
dt::ControlMode control_mode_, dt::MobilityNeedsMode mobility_, dt::Pricing pricing_,
|
||||
float nominal_voltage_);
|
||||
SelectedServiceParameters(dt::ServiceCategory energy_service_, dt::AcConnector ac_connector_,
|
||||
dt::ControlMode control_mode_, dt::MobilityNeedsMode mobility_, dt::Pricing pricing_,
|
||||
dt::BptChannel channel_, dt::GeneratorMode generator_, float nominal_voltage_,
|
||||
dt::GridCodeIslandingDetectionMethod grid_code_method_);
|
||||
};
|
||||
|
||||
// Todo(sl): missing services
|
||||
// WPT -> ControlMode, Pricing
|
||||
// DC_ACDP -> ControlMode, MobilityNeedsMode
|
||||
// DC_ACDP_BPT -> ControlMode, MobilityNeedsMode, BPTChannel
|
||||
|
||||
struct SelectedVasParameter {
|
||||
std::vector<dt::ServiceCategory> vas_services;
|
||||
|
||||
dt::Protocol internet_protocol;
|
||||
dt::Port internet_port;
|
||||
|
||||
dt::IntendedService parking_intended_service;
|
||||
dt::ParkingStatus parking_status;
|
||||
};
|
||||
|
||||
// TODO(SL): How to handle d2 pause? Move Struct to a seperate header file?
|
||||
// TODO(SL): Missing handling scheduletuple in schedule mode [V2G20-1058]
|
||||
struct PauseContext {
|
||||
io::sha512_hash_t vehicle_cert_session_id_hash{};
|
||||
std::array<uint8_t, 8> old_session_id{};
|
||||
SelectedServiceParameters selected_service_parameters{};
|
||||
};
|
||||
|
||||
class Session {
|
||||
|
||||
// TODO(sl): move to a common defs file
|
||||
static constexpr auto ID_LENGTH = 8;
|
||||
|
||||
public:
|
||||
Session();
|
||||
Session(const PauseContext& pause_ctx);
|
||||
Session(SelectedServiceParameters);
|
||||
Session(OfferedServices);
|
||||
|
||||
std::array<uint8_t, ID_LENGTH> get_id() const {
|
||||
return id;
|
||||
}
|
||||
|
||||
bool find_energy_parameter_set_id(const dt::ServiceCategory service, int16_t id);
|
||||
bool find_vas_parameter_set_id(const uint16_t vas_service, int16_t id);
|
||||
|
||||
void selected_service_parameters(const dt::ServiceCategory service, const uint16_t id);
|
||||
void selected_service_parameters(const uint16_t vas_service, const uint16_t id);
|
||||
|
||||
auto get_selected_services() const& {
|
||||
return selected_services;
|
||||
}
|
||||
|
||||
bool is_ac_charger() const {
|
||||
return selected_services.selected_energy_service == dt::ServiceCategory::AC or
|
||||
selected_services.selected_energy_service == dt::ServiceCategory::AC_BPT;
|
||||
}
|
||||
|
||||
bool is_dc_charger() const {
|
||||
return selected_services.selected_energy_service == dt::ServiceCategory::DC or
|
||||
selected_services.selected_energy_service == dt::ServiceCategory::DC_BPT or
|
||||
selected_services.selected_energy_service == dt::ServiceCategory::MCS or
|
||||
selected_services.selected_energy_service == dt::ServiceCategory::MCS_BPT;
|
||||
}
|
||||
|
||||
~Session();
|
||||
|
||||
OfferedServices offered_services;
|
||||
|
||||
bool service_renegotiation_supported{false};
|
||||
|
||||
private:
|
||||
// NOTE (aw): could be const
|
||||
std::array<uint8_t, ID_LENGTH> id{};
|
||||
|
||||
SelectedServiceParameters selected_services{};
|
||||
SelectedVasParameter selected_vas_services{};
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20
|
||||
@@ -0,0 +1,31 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2025 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "../states.hpp"
|
||||
|
||||
#include <iso15118/d20/ac_powers.hpp>
|
||||
#include <iso15118/d20/dynamic_mode_parameters.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
struct AC_ChargeLoop : public StateBase {
|
||||
AC_ChargeLoop(Context& ctx) : StateBase(ctx, StateID::AC_ChargeLoop) {
|
||||
}
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
|
||||
private:
|
||||
float target_frequency{0};
|
||||
bool stop{false};
|
||||
bool pause{false};
|
||||
|
||||
UpdateDynamicModeParameters dynamic_parameters{};
|
||||
AcTargetPower target_powers{};
|
||||
AcPresentPower present_powers{};
|
||||
|
||||
bool first_entry_in_charge_loop{false};
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,21 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2024 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "../states.hpp"
|
||||
#include <iso15118/d20/ac_powers.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
struct AC_ChargeParameterDiscovery : public StateBase {
|
||||
AC_ChargeParameterDiscovery(Context& ctx) : StateBase(ctx, StateID::AC_ChargeParameterDiscovery) {
|
||||
}
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
|
||||
private:
|
||||
AcPresentPower present_powers;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,23 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "../states.hpp"
|
||||
#include <iso15118/message/authorization.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
struct Authorization : public StateBase {
|
||||
public:
|
||||
Authorization(Context& ctx) : StateBase(ctx, StateID::Authorization){};
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
|
||||
private:
|
||||
message_20::datatypes::AuthStatus authorization_status{message_20::datatypes::AuthStatus::Pending};
|
||||
bool first_req_msg{true};
|
||||
bool timeout_ongoing_reached{false};
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,18 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "../states.hpp"
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
struct AuthorizationSetup : public StateBase {
|
||||
AuthorizationSetup(Context& ctx) : StateBase(ctx, StateID::AuthorizationSetup) {
|
||||
}
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,22 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "../states.hpp"
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
struct DC_CableCheck : public StateBase {
|
||||
DC_CableCheck(Context& ctx) : StateBase(ctx, StateID::DC_CableCheck) {
|
||||
}
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
|
||||
private:
|
||||
bool cable_check_initiated{false};
|
||||
bool cable_check_done{false};
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,33 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "../states.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
#include <iso15118/d20/dynamic_mode_parameters.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
struct DC_ChargeLoop : public StateBase {
|
||||
DC_ChargeLoop(Context& ctx) : StateBase(ctx, StateID::DC_ChargeLoop) {
|
||||
}
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
|
||||
private:
|
||||
float present_voltage{0};
|
||||
float present_current{0};
|
||||
bool stop{false};
|
||||
bool pause{false};
|
||||
|
||||
UpdateDynamicModeParameters dynamic_parameters;
|
||||
|
||||
bool first_entry_in_charge_loop{true};
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,18 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "../states.hpp"
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
struct DC_ChargeParameterDiscovery : public StateBase {
|
||||
DC_ChargeParameterDiscovery(Context& ctx) : StateBase(ctx, StateID::DC_ChargeParameterDiscovery) {
|
||||
}
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,22 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "../states.hpp"
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
struct DC_PreCharge : public StateBase {
|
||||
DC_PreCharge(Context& ctx) : StateBase(ctx, StateID::DC_PreCharge) {
|
||||
}
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
|
||||
private:
|
||||
bool pre_charge_initiated{false};
|
||||
float present_voltage{0};
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,21 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "../states.hpp"
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
struct DC_WeldingDetection : public StateBase {
|
||||
DC_WeldingDetection(Context& ctx) : StateBase(ctx, StateID::DC_WeldingDetection) {
|
||||
}
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
|
||||
private:
|
||||
float present_voltage{0};
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,25 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "../states.hpp"
|
||||
|
||||
#include <iso15118/message/power_delivery.hpp>
|
||||
#include <optional>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
struct PowerDelivery : public StateBase {
|
||||
PowerDelivery(Context& ctx) : StateBase(ctx, StateID::PowerDelivery) {
|
||||
}
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
|
||||
private:
|
||||
float present_voltage{0};
|
||||
bool ac_connector_closed{false};
|
||||
std::optional<message_20::PowerDeliveryRequest> previous_req;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,27 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "../states.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
#include <iso15118/d20/dynamic_mode_parameters.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
struct ScheduleExchange : public StateBase {
|
||||
ScheduleExchange(Context& ctx) : StateBase(ctx, StateID::ScheduleExchange) {
|
||||
}
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
|
||||
private:
|
||||
UpdateDynamicModeParameters dynamic_parameters;
|
||||
bool first_req_msg{true};
|
||||
bool timeout_ongoing_reached{false};
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,19 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "../states.hpp"
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
struct ServiceDetail : public StateBase {
|
||||
public:
|
||||
ServiceDetail(Context& ctx) : StateBase(ctx, StateID::ServiceDetail) {
|
||||
}
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,19 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "../states.hpp"
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
struct ServiceDiscovery : public StateBase {
|
||||
public:
|
||||
ServiceDiscovery(Context& ctx) : StateBase(ctx, StateID::ServiceDiscovery) {
|
||||
}
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,18 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "../states.hpp"
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
struct ServiceSelection : public StateBase {
|
||||
ServiceSelection(Context& ctx) : StateBase(ctx, StateID::ServiceSelection) {
|
||||
}
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,22 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
#include "../states.hpp"
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
struct SessionSetup : public StateBase {
|
||||
SessionSetup(Context& ctx) : StateBase(ctx, StateID::SessionSetup) {
|
||||
}
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
|
||||
private:
|
||||
std::string evse_id;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,18 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "../states.hpp"
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
struct SessionStop : public StateBase {
|
||||
SessionStop(Context& ctx) : StateBase(ctx, StateID::SessionStop) {
|
||||
}
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,19 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "../states.hpp"
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
struct SupportedAppProtocol : public StateBase {
|
||||
public:
|
||||
SupportedAppProtocol(Context& ctx) : StateBase(ctx, StateID::SupportedAppProtocol) {
|
||||
}
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,73 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "context.hpp"
|
||||
|
||||
namespace iso15118::d20 {
|
||||
|
||||
class Context;
|
||||
|
||||
enum class Event {
|
||||
RESET,
|
||||
V2GTP_MESSAGE,
|
||||
CONTROL_MESSAGE,
|
||||
TIMEOUT,
|
||||
|
||||
// internal events
|
||||
FAILED,
|
||||
};
|
||||
|
||||
enum class StateID {
|
||||
SupportedAppProtocol,
|
||||
SessionSetup,
|
||||
AuthorizationSetup,
|
||||
Authorization,
|
||||
ServiceDetail,
|
||||
ServiceDiscovery,
|
||||
ServiceSelection,
|
||||
AC_ChargeParameterDiscovery,
|
||||
AC_ChargeLoop,
|
||||
DC_ChargeParameterDiscovery,
|
||||
DC_PreCharge,
|
||||
DC_ChargeLoop,
|
||||
DC_WeldingDetection,
|
||||
DC_CableCheck,
|
||||
PowerDelivery,
|
||||
ScheduleExchange,
|
||||
SessionStop
|
||||
};
|
||||
|
||||
struct Result {
|
||||
constexpr Result() = default;
|
||||
Result(BasePointerType result_state) : unhandled(false), new_state(std::move(result_state)) {
|
||||
}
|
||||
|
||||
bool unhandled{true};
|
||||
BasePointerType new_state{nullptr};
|
||||
};
|
||||
|
||||
struct StateBase {
|
||||
using ContainerType = BasePointerType;
|
||||
using EventType = Event;
|
||||
|
||||
StateBase(Context& ctx, StateID id) : m_ctx(ctx), m_id(id){};
|
||||
|
||||
virtual ~StateBase() = default;
|
||||
|
||||
StateID get_id() const {
|
||||
return m_id;
|
||||
}
|
||||
|
||||
virtual void enter(){};
|
||||
virtual Result feed(Event) = 0;
|
||||
virtual void leave(){};
|
||||
|
||||
protected:
|
||||
Context& m_ctx;
|
||||
|
||||
private:
|
||||
StateID m_id;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20
|
||||
@@ -0,0 +1,47 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2025 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include <iso15118/io/time.hpp>
|
||||
|
||||
namespace iso15118::d20 {
|
||||
|
||||
template <typename T> constexpr auto to_underlying_value(T t) {
|
||||
return static_cast<std::underlying_type_t<T>>(t);
|
||||
}
|
||||
|
||||
enum class TimeoutType : uint8_t {
|
||||
SEQUENCE = 0,
|
||||
PERFORMANCE,
|
||||
ONGOING,
|
||||
CONTACTOR,
|
||||
};
|
||||
|
||||
constexpr uint8_t TIMEOUT_TYPE_SIZE = 4;
|
||||
|
||||
static_assert(TIMEOUT_TYPE_SIZE == to_underlying_value(TimeoutType::CONTACTOR) + 1,
|
||||
"TIMEOUT_TYPE_SIZE should be in sync with the TimeoutType enum definition");
|
||||
|
||||
constexpr auto TIMEOUT_ONGOING = 1000 * 55;
|
||||
constexpr auto TIMEOUT_SEQUENCE = 1000 * 60;
|
||||
constexpr auto TIMEOUT_EIM_ONGOING = 1000 * 60 * 3;
|
||||
|
||||
class Timeouts {
|
||||
public:
|
||||
explicit Timeouts() = default;
|
||||
~Timeouts() = default;
|
||||
|
||||
void start_timeout(TimeoutType type, uint32_t timeout_ms);
|
||||
void stop_timeout(TimeoutType type);
|
||||
void reset_timeout(TimeoutType type);
|
||||
std::optional<std::vector<TimeoutType>> check();
|
||||
|
||||
private:
|
||||
std::array<std::optional<Timeout>, TIMEOUT_TYPE_SIZE> timeouts;
|
||||
};
|
||||
|
||||
} // namespace iso15118::d20
|
||||
@@ -0,0 +1,99 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <cbv2g/common/exi_bitstream.h>
|
||||
|
||||
#include <iso15118/io/stream_view.hpp>
|
||||
|
||||
#define CB2CPP_STRING(property) (std::string(property.characters, property.charactersLen))
|
||||
|
||||
#define CPP2CB_STRING(in, out) \
|
||||
if (in.length() > sizeof(out.characters)) { \
|
||||
throw std::runtime_error("String too long"); \
|
||||
} \
|
||||
in.copy(out.characters, in.length()); \
|
||||
out.charactersLen = in.length()
|
||||
|
||||
#define CPP2CB_BYTES(in, out) \
|
||||
if (in.size() > sizeof(out.bytes)) { \
|
||||
throw std::runtime_error("Byte vector too long"); \
|
||||
} \
|
||||
std::copy(in.begin(), in.end(), out.bytes); \
|
||||
out.bytesLen = in.size()
|
||||
|
||||
#define CB2CPP_BYTES(in, out) \
|
||||
if (in.bytesLen > out.size()) { \
|
||||
throw std::runtime_error("Byte array too long"); \
|
||||
} \
|
||||
std::copy(std::begin(in.bytes), std::end(in.bytes), out.begin());
|
||||
|
||||
#define CB_SET_USED(property) (property##_isUsed = 1)
|
||||
#define CB2CPP_ASSIGN_IF_USED(in, out) \
|
||||
if (in##_isUsed) { \
|
||||
out = in; \
|
||||
}
|
||||
|
||||
#define CPP2CB_ASSIGN_IF_USED(in, out) \
|
||||
if (in) { \
|
||||
out = in.value(); \
|
||||
} \
|
||||
\
|
||||
out##_isUsed = static_cast<bool>(in);
|
||||
|
||||
#define CB2CPP_CONVERT_IF_USED(in, out) \
|
||||
if (in##_isUsed) { \
|
||||
convert(in, out.emplace()); \
|
||||
}
|
||||
|
||||
#define CPP2CB_CONVERT_IF_USED(in, out) \
|
||||
if (in) { \
|
||||
convert(in.value(), out); \
|
||||
} \
|
||||
\
|
||||
out##_isUsed = static_cast<bool>(in);
|
||||
|
||||
#define CPP2CB_STRING_IF_USED(in, out) \
|
||||
if (in) { \
|
||||
CPP2CB_STRING(in.value(), out); \
|
||||
} \
|
||||
\
|
||||
out##_isUsed = static_cast<bool>(in);
|
||||
|
||||
#define CB2CPP_STRING_IF_USED(in, out) \
|
||||
if (in##_isUsed) { \
|
||||
out = CB2CPP_STRING(in); \
|
||||
}
|
||||
|
||||
#define CB2CPP_BYTES_IF_USED(in, out) \
|
||||
if (in##_isUsed) { \
|
||||
CB2CPP_BYTES(in, out.emplace()); \
|
||||
}
|
||||
|
||||
template <typename T1, typename T2> void cb_convert_enum(const T1& in, T2& out) {
|
||||
out = static_cast<T2>(in);
|
||||
}
|
||||
|
||||
exi_bitstream_t get_exi_input_stream(const iso15118::io::StreamInputView&);
|
||||
exi_bitstream_t get_exi_output_stream(const iso15118::io::StreamOutputView&);
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
template <typename MessageType> int serialize_to_exi(const MessageType& in, exi_bitstream_t& out);
|
||||
|
||||
template <typename MessageType>
|
||||
size_t serialize_helper(const MessageType& in, const io::StreamOutputView& stream_view) {
|
||||
auto out = get_exi_output_stream(stream_view);
|
||||
|
||||
const auto error = serialize_to_exi(in, out);
|
||||
|
||||
if (error != 0) {
|
||||
throw std::runtime_error("Could not encode exi: " + std::to_string(error));
|
||||
}
|
||||
|
||||
return exi_bitstream_get_length(&out);
|
||||
}
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,24 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/d20/context.hpp>
|
||||
#include <iso15118/d20/session.hpp>
|
||||
#include <iso15118/message/common_types.hpp>
|
||||
|
||||
namespace iso15118::d20 {
|
||||
|
||||
// FIXME (aw): not sure about correct signature here for RVO
|
||||
template <typename Response, typename ResponseCode> Response& response_with_code(Response& res, ResponseCode code) {
|
||||
// FIXME (aw): could add an static_assert here that ResponseCode is an enum?
|
||||
res.response_code = code;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool validate_and_setup_header(message_20::Header&, const Session&, const decltype(message_20::Header::session_id)&);
|
||||
|
||||
void setup_header(message_20::Header&, const Session&);
|
||||
|
||||
void send_sequence_error(const message_20::Type, d20::Context&);
|
||||
|
||||
} // namespace iso15118::d20
|
||||
@@ -0,0 +1,20 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 205 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/d20/session.hpp>
|
||||
#include <iso15118/message/ac_charge_loop.hpp>
|
||||
|
||||
#include <iso15118/d20/ac_powers.hpp>
|
||||
#include <iso15118/d20/dynamic_mode_parameters.hpp>
|
||||
#include <iso15118/d20/limits.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
message_20::AC_ChargeLoopResponse handle_request(const message_20::AC_ChargeLoopRequest& req,
|
||||
const d20::Session& session, bool stop, bool pause,
|
||||
float target_frequency, const AcTargetPower& target_powers,
|
||||
const AcPresentPower& present_powers,
|
||||
const UpdateDynamicModeParameters& dynamic_parameters);
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,16 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2024 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/d20/ac_powers.hpp>
|
||||
#include <iso15118/d20/config.hpp>
|
||||
#include <iso15118/d20/session.hpp>
|
||||
#include <iso15118/message/ac_charge_parameter_discovery.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
message_20::AC_ChargeParameterDiscoveryResponse
|
||||
handle_request(const message_20::AC_ChargeParameterDiscoveryRequest& req, const d20::Session& session,
|
||||
const d20::AcTransferLimits& limits, const d20::AcPresentPower& powers);
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/d20/session.hpp>
|
||||
#include <iso15118/message/authorization.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
message_20::AuthorizationResponse handle_request(const message_20::AuthorizationRequest& req,
|
||||
const d20::Session& session,
|
||||
const message_20::datatypes::AuthStatus& authorization_status,
|
||||
bool timeout_reached);
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/d20/config.hpp>
|
||||
#include <iso15118/d20/session.hpp>
|
||||
#include <iso15118/message/authorization_setup.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
message_20::AuthorizationSetupResponse
|
||||
handle_request(const message_20::AuthorizationSetupRequest& req, d20::Session& session, bool cert_install_service,
|
||||
const std::vector<message_20::datatypes::Authorization>& authorization_services);
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,13 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/d20/session.hpp>
|
||||
#include <iso15118/message/dc_cable_check.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
message_20::DC_CableCheckResponse handle_request(const message_20::DC_CableCheckRequest& req,
|
||||
const d20::Session& session, bool cable_check_done);
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,26 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
#include <optional>
|
||||
#include <tuple>
|
||||
#include <variant>
|
||||
|
||||
#include <iso15118/d20/dynamic_mode_parameters.hpp>
|
||||
#include <iso15118/d20/limits.hpp>
|
||||
#include <iso15118/d20/session.hpp>
|
||||
#include <iso15118/message/dc_charge_loop.hpp>
|
||||
|
||||
#include <iso15118/session/feedback.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
message_20::DC_ChargeLoopResponse handle_request(const message_20::DC_ChargeLoopRequest& req,
|
||||
const d20::Session& session, const float present_voltage,
|
||||
const float present_current, const bool stop, const bool pause,
|
||||
const DcTransferLimits& dc_limits,
|
||||
const UpdateDynamicModeParameters& dynamic_parameters);
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,16 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/d20/config.hpp>
|
||||
#include <iso15118/d20/limits.hpp>
|
||||
#include <iso15118/d20/session.hpp>
|
||||
#include <iso15118/message/dc_charge_parameter_discovery.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
message_20::DC_ChargeParameterDiscoveryResponse
|
||||
handle_request(const message_20::DC_ChargeParameterDiscoveryRequest& req, const d20::Session& session,
|
||||
const d20::DcTransferLimits& dc_limits);
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,18 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <tuple>
|
||||
|
||||
#include <iso15118/d20/session.hpp>
|
||||
#include <iso15118/message/dc_pre_charge.hpp>
|
||||
|
||||
#include <iso15118/session/feedback.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
message_20::DC_PreChargeResponse handle_request(const message_20::DC_PreChargeRequest& req, const d20::Session& session,
|
||||
const float present_voltage);
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,13 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/d20/session.hpp>
|
||||
#include <iso15118/message/dc_welding_detection.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
message_20::DC_WeldingDetectionResponse handle_request(const message_20::DC_WeldingDetectionRequest& req,
|
||||
const d20::Session& session, const float present_voltage);
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,13 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/d20/session.hpp>
|
||||
#include <iso15118/message/power_delivery.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
message_20::PowerDeliveryResponse handle_request(const message_20::PowerDeliveryRequest& req,
|
||||
const d20::Session& session, bool contactor_error);
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,22 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/d20/session.hpp>
|
||||
#include <iso15118/message/schedule_exchange.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
#include <optional>
|
||||
|
||||
#include <iso15118/d20/dynamic_mode_parameters.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
message_20::ScheduleExchangeResponse handle_request(const message_20::ScheduleExchangeRequest& req,
|
||||
const d20::Session& session,
|
||||
const message_20::datatypes::RationalNumber& max_power,
|
||||
const UpdateDynamicModeParameters& dynamic_parameters,
|
||||
bool timeout_reached);
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/d20/config.hpp>
|
||||
#include <iso15118/d20/session.hpp>
|
||||
#include <iso15118/message/service_detail.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
message_20::ServiceDetailResponse handle_request(const message_20::ServiceDetailRequest& req, d20::Session& session,
|
||||
const d20::SessionConfig& config,
|
||||
const std::optional<dt::ServiceParameterList>& custom_vas_parameters);
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,20 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <iso15118/d20/config.hpp>
|
||||
#include <iso15118/d20/session.hpp>
|
||||
#include <iso15118/message/common_types.hpp>
|
||||
#include <iso15118/message/service_discovery.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
message_20::ServiceDiscoveryResponse
|
||||
handle_request(const message_20::ServiceDiscoveryRequest& req, d20::Session& session,
|
||||
const std::vector<message_20::datatypes::ServiceCategory>& energy_services,
|
||||
const std::vector<uint16_t>& vas_services,
|
||||
std::vector<message_20::datatypes::ServiceCategory>& ev_energy_services);
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,14 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/d20/config.hpp>
|
||||
#include <iso15118/d20/session.hpp>
|
||||
#include <iso15118/message/service_selection.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
message_20::ServiceSelectionResponse handle_request(const message_20::ServiceSelectionRequest& req,
|
||||
d20::Session& session);
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,12 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/d20/session.hpp>
|
||||
#include <iso15118/message/session_setup.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
message_20::SessionSetupResponse handle_request(const message_20::SessionSetupRequest& req, const d20::Session& session,
|
||||
const std::string& evse_id, bool new_session);
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,12 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/d20/session.hpp>
|
||||
#include <iso15118/message/session_stop.hpp>
|
||||
|
||||
namespace iso15118::d20::state {
|
||||
|
||||
message_20::SessionStopResponse handle_request(const message_20::SessionStopRequest& req, const d20::Session& session);
|
||||
|
||||
} // namespace iso15118::d20::state
|
||||
@@ -0,0 +1,52 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2024 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/io/log_levels.hpp>
|
||||
|
||||
#include <cstdarg>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
namespace iso15118 {
|
||||
|
||||
void logf(const char* fmt, ...);
|
||||
void logf(const LogLevel&, const char* fmt, ...);
|
||||
|
||||
void logf_error(const char* fmt, ...);
|
||||
void logf_warning(const char* fmt, ...);
|
||||
void logf_info(const char* fmt, ...);
|
||||
void logf_debug(const char* fmt, ...);
|
||||
void logf_trace(const char* fmt, ...);
|
||||
|
||||
void vlogf(const char* fmt, va_list ap);
|
||||
void vlogf(const LogLevel&, const char* fmt, va_list ap);
|
||||
|
||||
void log(const LogLevel&, const std::string&);
|
||||
|
||||
void log_and_throw(const char* msg);
|
||||
|
||||
std::string adding_err_msg(const std::string& msg);
|
||||
|
||||
template <typename CallbackType, typename... Args> bool call_if_available(const CallbackType& callback, Args... args) {
|
||||
if (not callback) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::invoke(callback, std::forward<Args>(args)...);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Note(sl): Copied from https://en.cppreference.com/w/cpp/utility/intcmp because libiso15118 uses C++17
|
||||
template <class T, class U> constexpr bool cmp_equal(T t, U u) noexcept {
|
||||
if constexpr (std::is_signed_v<T> == std::is_signed_v<U>)
|
||||
return t == u;
|
||||
else if constexpr (std::is_signed_v<T>)
|
||||
return t >= 0 && std::make_unsigned_t<T>(t) == u;
|
||||
else
|
||||
return u >= 0 && std::make_unsigned_t<U>(u) == t;
|
||||
}
|
||||
|
||||
} // namespace iso15118
|
||||
@@ -0,0 +1,12 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2024 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace iso15118::io {
|
||||
|
||||
std::string log_openssl_error(const std::string& error_msg);
|
||||
void log_and_raise_openssl_error(const std::string& error_msg);
|
||||
|
||||
} // namespace iso15118::io
|
||||
@@ -0,0 +1,17 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
namespace iso15118::io {
|
||||
|
||||
bool check_and_update_interface(std::string& interface_name);
|
||||
|
||||
bool get_first_sockaddr_in6_for_interface(const std::string& interface_name, sockaddr_in6& address);
|
||||
|
||||
std::unique_ptr<char[]> sockaddr_in6_to_name(const sockaddr_in6&);
|
||||
} // namespace iso15118::io
|
||||
@@ -0,0 +1,36 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <iso15118/message/variant.hpp>
|
||||
|
||||
#include "cb_exi.hpp"
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
struct VariantAccess {
|
||||
// input
|
||||
exi_bitstream_t input_stream;
|
||||
|
||||
// output
|
||||
void*& data;
|
||||
iso15118::message_20::Type& type;
|
||||
iso15118::message_20::Variant::CustomDeleter& custom_deleter;
|
||||
std::string& error;
|
||||
|
||||
template <typename MessageType, typename CbExiMessageType> void insert_type(const CbExiMessageType& in) {
|
||||
assert(data == nullptr);
|
||||
|
||||
data = new MessageType;
|
||||
type = iso15118::message_20::TypeTrait<MessageType>::type;
|
||||
custom_deleter = [](void* ptr) { delete static_cast<MessageType*>(ptr); };
|
||||
|
||||
convert(in, *static_cast<MessageType*>(data));
|
||||
};
|
||||
};
|
||||
|
||||
template <typename CbExiMessageType> void insert_type(VariantAccess& va, const CbExiMessageType&);
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,43 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
|
||||
#include "ipv6_endpoint.hpp"
|
||||
|
||||
#include <iso15118/io/sha_hash.hpp>
|
||||
|
||||
namespace iso15118::io {
|
||||
|
||||
enum class ConnectionEvent {
|
||||
ACCEPTED,
|
||||
OPEN,
|
||||
NEW_DATA,
|
||||
CLOSED,
|
||||
};
|
||||
|
||||
using ConnectionEventCallback = std::function<void(ConnectionEvent)>;
|
||||
|
||||
struct ReadResult {
|
||||
bool would_block{true};
|
||||
size_t bytes_read{0};
|
||||
};
|
||||
|
||||
struct IConnection {
|
||||
virtual void set_event_callback(const ConnectionEventCallback&) = 0;
|
||||
|
||||
virtual Ipv6EndPoint get_public_endpoint() const = 0;
|
||||
|
||||
virtual void write(const uint8_t* buf, size_t len) = 0;
|
||||
virtual ReadResult read(uint8_t* buf, size_t len) = 0;
|
||||
|
||||
virtual void close() = 0;
|
||||
|
||||
virtual std::optional<sha512_hash_t> get_vehicle_cert_hash() const = 0;
|
||||
|
||||
virtual ~IConnection() = default;
|
||||
};
|
||||
} // namespace iso15118::io
|
||||
@@ -0,0 +1,44 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "connection_abstract.hpp"
|
||||
|
||||
#include <iso15118/config.hpp>
|
||||
#include <iso15118/io/poll_manager.hpp>
|
||||
|
||||
namespace iso15118::io {
|
||||
|
||||
class ConnectionPlain : public IConnection {
|
||||
public:
|
||||
ConnectionPlain(PollManager&, const std::string& interface_name);
|
||||
|
||||
void set_event_callback(const ConnectionEventCallback&) final;
|
||||
Ipv6EndPoint get_public_endpoint() const final;
|
||||
|
||||
void write(const uint8_t* buf, size_t len) final;
|
||||
ReadResult read(uint8_t* buf, size_t len) final;
|
||||
|
||||
void close() final;
|
||||
|
||||
std::optional<sha512_hash_t> get_vehicle_cert_hash() const final {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
~ConnectionPlain();
|
||||
|
||||
private:
|
||||
PollManager& poll_manager;
|
||||
|
||||
Ipv6EndPoint end_point;
|
||||
|
||||
int fd{-1};
|
||||
|
||||
bool connection_open{false};
|
||||
|
||||
ConnectionEventCallback event_callback{nullptr};
|
||||
|
||||
void handle_connect();
|
||||
void handle_data();
|
||||
};
|
||||
} // namespace iso15118::io
|
||||
@@ -0,0 +1,46 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2024 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
#include "connection_abstract.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include <iso15118/config.hpp>
|
||||
#include <iso15118/io/poll_manager.hpp>
|
||||
#include <iso15118/io/sha_hash.hpp>
|
||||
|
||||
namespace iso15118::io {
|
||||
|
||||
// forward declaration
|
||||
struct SSLContext;
|
||||
class ConnectionSSL : public IConnection {
|
||||
public:
|
||||
ConnectionSSL(PollManager&, const std::string& interface_name, const config::SSLConfig&);
|
||||
|
||||
void set_event_callback(const ConnectionEventCallback&) final;
|
||||
Ipv6EndPoint get_public_endpoint() const final;
|
||||
|
||||
void write(const uint8_t* buf, size_t len) final;
|
||||
ReadResult read(uint8_t* buf, size_t len) final;
|
||||
|
||||
void close() final;
|
||||
|
||||
std::optional<sha512_hash_t> get_vehicle_cert_hash() const final;
|
||||
|
||||
~ConnectionSSL();
|
||||
|
||||
private:
|
||||
PollManager& poll_manager;
|
||||
std::unique_ptr<SSLContext> ssl;
|
||||
|
||||
Ipv6EndPoint end_point;
|
||||
|
||||
ConnectionEventCallback event_callback{nullptr};
|
||||
|
||||
bool handshake_complete{false};
|
||||
|
||||
void handle_connect();
|
||||
void handle_data();
|
||||
};
|
||||
} // namespace iso15118::io
|
||||
@@ -0,0 +1,14 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace iso15118::io {
|
||||
|
||||
struct Ipv6EndPoint {
|
||||
uint16_t port;
|
||||
uint16_t address[8];
|
||||
};
|
||||
|
||||
} // namespace iso15118::io
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2024 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
namespace iso15118 {
|
||||
|
||||
enum class LogLevel {
|
||||
Error,
|
||||
Warning,
|
||||
Info,
|
||||
Debug,
|
||||
Trace,
|
||||
};
|
||||
|
||||
} // namespace iso15118
|
||||
@@ -0,0 +1,13 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#include "log_levels.hpp"
|
||||
|
||||
namespace iso15118::io {
|
||||
void set_logging_callback(const std::function<void(LogLevel, std::string)>&);
|
||||
|
||||
} // namespace iso15118::io
|
||||
@@ -0,0 +1,36 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include <poll.h>
|
||||
namespace iso15118::io {
|
||||
|
||||
using PollCallback = const std::function<void()>;
|
||||
struct PollSet {
|
||||
std::vector<struct pollfd> fds;
|
||||
std::vector<PollCallback*> callbacks;
|
||||
};
|
||||
|
||||
class PollManager {
|
||||
public:
|
||||
PollManager();
|
||||
|
||||
void register_fd(int fd, PollCallback& poll_callback);
|
||||
void unregister_fd(int fd);
|
||||
|
||||
void poll(int timeout_ms);
|
||||
void abort();
|
||||
|
||||
private:
|
||||
std::map<int, PollCallback> registered_fds;
|
||||
|
||||
PollSet poll_set;
|
||||
|
||||
int event_fd{-1};
|
||||
};
|
||||
|
||||
} // namespace iso15118::io
|
||||
@@ -0,0 +1,27 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace iso15118::io::v2gtp {
|
||||
enum class Security : uint8_t {
|
||||
TLS = 0x00,
|
||||
NO_TRANSPORT_SECURITY = 0x10,
|
||||
};
|
||||
|
||||
enum class TransportProtocol : uint8_t {
|
||||
TCP = 0x00,
|
||||
RESERVED_FOR_UDP = 0x10,
|
||||
};
|
||||
|
||||
static constexpr auto SDP_SERVER_PORT = 15118;
|
||||
|
||||
enum class PayloadType : uint16_t {
|
||||
SAP = 0x8001,
|
||||
Part20Main = 0x8002,
|
||||
Part20AC = 0x8003,
|
||||
Part20DC = 0x8004,
|
||||
};
|
||||
|
||||
} // namespace iso15118::io::v2gtp
|
||||
@@ -0,0 +1,73 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include "sdp.hpp"
|
||||
|
||||
namespace iso15118::io {
|
||||
|
||||
// FIXME (aw): these shouldn't be necessary public - but nice to have
|
||||
static constexpr uint8_t SDP_PROTOCOL_VERSION = 0x01;
|
||||
static constexpr uint8_t SDP_INVERSE_PROTOCOL_VERSION = 0xFE;
|
||||
|
||||
// FIXME (aw): should be called V2GTP or SDP buffer
|
||||
class SdpPacket {
|
||||
public:
|
||||
static constexpr auto V2GTP_HEADER_SIZE = 8;
|
||||
enum class State {
|
||||
BUFFER_EMPTY,
|
||||
HEADER_READ,
|
||||
COMPLETE,
|
||||
|
||||
// failed states
|
||||
INVALID_HEADER,
|
||||
PAYLOAD_TOO_LONG,
|
||||
};
|
||||
|
||||
auto get_state() const {
|
||||
return state;
|
||||
}
|
||||
|
||||
auto is_complete() const {
|
||||
return state == State::COMPLETE;
|
||||
}
|
||||
|
||||
auto get_payload_length() const {
|
||||
return (state == State::COMPLETE) ? (length - V2GTP_HEADER_SIZE) : 0;
|
||||
}
|
||||
|
||||
v2gtp::PayloadType get_payload_type() const;
|
||||
|
||||
uint8_t const* get_payload_buffer() const {
|
||||
return buffer + V2GTP_HEADER_SIZE;
|
||||
}
|
||||
|
||||
uint8_t const* get_buffer() const {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
uint8_t* get_current_buffer_pos() {
|
||||
return buffer + bytes_read;
|
||||
}
|
||||
|
||||
size_t get_remaining_buffer_capacity() const {
|
||||
return sizeof(buffer) - bytes_read;
|
||||
}
|
||||
|
||||
size_t get_remaining_bytes_to_read() const;
|
||||
|
||||
void update_read_bytes(size_t len);
|
||||
|
||||
private:
|
||||
void parse_header();
|
||||
|
||||
State state{State::BUFFER_EMPTY};
|
||||
uint8_t buffer[2048];
|
||||
size_t bytes_read{0};
|
||||
size_t length; // length includes V2GTP_HEADER_SIZE
|
||||
};
|
||||
|
||||
} // namespace iso15118::io
|
||||
@@ -0,0 +1,71 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "ipv6_endpoint.hpp"
|
||||
#include "sdp.hpp"
|
||||
|
||||
namespace iso15118::io {
|
||||
|
||||
struct PeerRequestContext {
|
||||
explicit PeerRequestContext(bool valid_) : valid(valid_){};
|
||||
v2gtp::Security security;
|
||||
v2gtp::TransportProtocol transport_protocol;
|
||||
struct sockaddr_in6 address;
|
||||
|
||||
operator bool() const {
|
||||
return valid;
|
||||
}
|
||||
|
||||
private:
|
||||
const bool valid;
|
||||
};
|
||||
|
||||
class SdpServer {
|
||||
public:
|
||||
explicit SdpServer(const std::string& interface_name);
|
||||
~SdpServer();
|
||||
PeerRequestContext get_peer_request();
|
||||
void send_response(const PeerRequestContext&, const Ipv6EndPoint&);
|
||||
|
||||
auto get_fd() const {
|
||||
return fd;
|
||||
}
|
||||
|
||||
void set_dlink_ready(bool ready);
|
||||
bool is_dlink_ready() const;
|
||||
|
||||
private:
|
||||
int fd{-1};
|
||||
uint8_t udp_buffer[2048];
|
||||
std::atomic<bool> dlink_ready_{false};
|
||||
};
|
||||
|
||||
class TlsKeyLoggingServer {
|
||||
public:
|
||||
TlsKeyLoggingServer(const std::string& interface_name, uint16_t port);
|
||||
~TlsKeyLoggingServer();
|
||||
|
||||
ssize_t send(const char* line);
|
||||
|
||||
auto get_fd() const {
|
||||
return fd;
|
||||
}
|
||||
|
||||
auto get_port() const {
|
||||
return port;
|
||||
}
|
||||
|
||||
private:
|
||||
int fd{-1};
|
||||
uint16_t port{0};
|
||||
sockaddr_in6 destination_address{};
|
||||
};
|
||||
|
||||
} // namespace iso15118::io
|
||||
@@ -0,0 +1,13 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2024 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
namespace iso15118::io {
|
||||
|
||||
constexpr std::size_t sha_512_hash_size = 64;
|
||||
using sha512_hash_t = std::array<uint8_t, sha_512_hash_size>;
|
||||
|
||||
} // namespace iso15118::io
|
||||
@@ -0,0 +1,24 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace iso15118::io {
|
||||
|
||||
struct StreamInputView {
|
||||
uint8_t const* payload;
|
||||
size_t payload_len;
|
||||
};
|
||||
|
||||
struct StreamOutputView {
|
||||
uint8_t* payload;
|
||||
size_t payload_len;
|
||||
|
||||
operator StreamInputView() const {
|
||||
return {payload, payload_len};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace iso15118::io
|
||||
@@ -0,0 +1,51 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
|
||||
namespace iso15118 {
|
||||
|
||||
using TimePoint = std::chrono::steady_clock::time_point;
|
||||
|
||||
inline TimePoint get_current_time_point() {
|
||||
return std::chrono::steady_clock::now();
|
||||
}
|
||||
|
||||
inline TimePoint offset_time_point_by_ms(const TimePoint& time_point, int32_t offset) {
|
||||
return time_point + std::chrono::milliseconds(offset);
|
||||
}
|
||||
|
||||
inline int32_t get_timeout_ms_until(const TimePoint& until, int32_t max_timeout_ms) {
|
||||
const auto duration =
|
||||
std::chrono::duration_cast<std::chrono::duration<int32_t, std::milli>>(until - get_current_time_point());
|
||||
const auto timeout_ms = duration.count();
|
||||
|
||||
// if the timeout is already reached, return 0 to trigger an immediate timeout event
|
||||
if (timeout_ms <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return timeout_ms < max_timeout_ms ? timeout_ms : max_timeout_ms;
|
||||
}
|
||||
|
||||
class Timeout {
|
||||
public:
|
||||
explicit Timeout(uint32_t timeout_ms) {
|
||||
timeout_point = get_current_time_point() + std::chrono::milliseconds(timeout_ms);
|
||||
};
|
||||
~Timeout() = default;
|
||||
|
||||
bool is_reached() {
|
||||
return get_current_time_point() >= timeout_point;
|
||||
}
|
||||
|
||||
TimePoint get_timeout_point() const {
|
||||
return timeout_point;
|
||||
}
|
||||
|
||||
private:
|
||||
TimePoint timeout_point{};
|
||||
};
|
||||
|
||||
} // namespace iso15118
|
||||
@@ -0,0 +1,122 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2024 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "common_types.hpp"
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
namespace datatypes {
|
||||
|
||||
struct Scheduled_AC_CLReqControlMode : Scheduled_CLReqControlMode {
|
||||
std::optional<RationalNumber> max_charge_power;
|
||||
std::optional<RationalNumber> max_charge_power_L2;
|
||||
std::optional<RationalNumber> max_charge_power_L3;
|
||||
std::optional<RationalNumber> min_charge_power;
|
||||
std::optional<RationalNumber> min_charge_power_L2;
|
||||
std::optional<RationalNumber> min_charge_power_L3;
|
||||
RationalNumber present_active_power;
|
||||
std::optional<RationalNumber> present_active_power_L2;
|
||||
std::optional<RationalNumber> present_active_power_L3;
|
||||
std::optional<RationalNumber> present_reactive_power;
|
||||
std::optional<RationalNumber> present_reactive_power_L2;
|
||||
std::optional<RationalNumber> present_reactive_power_L3;
|
||||
};
|
||||
|
||||
struct BPT_Scheduled_AC_CLReqControlMode : Scheduled_AC_CLReqControlMode {
|
||||
std::optional<RationalNumber> max_discharge_power;
|
||||
std::optional<RationalNumber> max_discharge_power_L2;
|
||||
std::optional<RationalNumber> max_discharge_power_L3;
|
||||
std::optional<RationalNumber> min_discharge_power;
|
||||
std::optional<RationalNumber> min_discharge_power_L2;
|
||||
std::optional<RationalNumber> min_discharge_power_L3;
|
||||
};
|
||||
|
||||
struct Dynamic_AC_CLReqControlMode : Dynamic_CLReqControlMode {
|
||||
RationalNumber max_charge_power;
|
||||
std::optional<RationalNumber> max_charge_power_L2;
|
||||
std::optional<RationalNumber> max_charge_power_L3;
|
||||
RationalNumber min_charge_power;
|
||||
std::optional<RationalNumber> min_charge_power_L2;
|
||||
std::optional<RationalNumber> min_charge_power_L3;
|
||||
RationalNumber present_active_power;
|
||||
std::optional<RationalNumber> present_active_power_L2;
|
||||
std::optional<RationalNumber> present_active_power_L3;
|
||||
RationalNumber present_reactive_power;
|
||||
std::optional<RationalNumber> present_reactive_power_L2;
|
||||
std::optional<RationalNumber> present_reactive_power_L3;
|
||||
};
|
||||
|
||||
struct BPT_Dynamic_AC_CLReqControlMode : Dynamic_AC_CLReqControlMode {
|
||||
RationalNumber max_discharge_power;
|
||||
std::optional<RationalNumber> max_discharge_power_L2;
|
||||
std::optional<RationalNumber> max_discharge_power_L3;
|
||||
RationalNumber min_discharge_power;
|
||||
std::optional<RationalNumber> min_discharge_power_L2;
|
||||
std::optional<RationalNumber> min_discharge_power_L3;
|
||||
std::optional<RationalNumber> max_v2x_energy_request;
|
||||
std::optional<RationalNumber> min_v2x_energy_request;
|
||||
};
|
||||
|
||||
struct Scheduled_AC_CLResControlMode : Scheduled_CLResControlMode {
|
||||
std::optional<RationalNumber> target_active_power;
|
||||
std::optional<RationalNumber> target_active_power_L2;
|
||||
std::optional<RationalNumber> target_active_power_L3;
|
||||
std::optional<RationalNumber> target_reactive_power;
|
||||
std::optional<RationalNumber> target_reactive_power_L2;
|
||||
std::optional<RationalNumber> target_reactive_power_L3;
|
||||
std::optional<RationalNumber> present_active_power;
|
||||
std::optional<RationalNumber> present_active_power_L2;
|
||||
std::optional<RationalNumber> present_active_power_L3;
|
||||
};
|
||||
|
||||
struct BPT_Scheduled_AC_CLResControlMode : Scheduled_AC_CLResControlMode {};
|
||||
|
||||
struct Dynamic_AC_CLResControlMode : Dynamic_CLResControlMode {
|
||||
RationalNumber target_active_power;
|
||||
std::optional<RationalNumber> target_active_power_L2;
|
||||
std::optional<RationalNumber> target_active_power_L3;
|
||||
std::optional<RationalNumber> target_reactive_power;
|
||||
std::optional<RationalNumber> target_reactive_power_L2;
|
||||
std::optional<RationalNumber> target_reactive_power_L3;
|
||||
std::optional<RationalNumber> present_active_power;
|
||||
std::optional<RationalNumber> present_active_power_L2;
|
||||
std::optional<RationalNumber> present_active_power_L3;
|
||||
};
|
||||
|
||||
struct BPT_Dynamic_AC_CLResControlMode : Dynamic_AC_CLResControlMode {};
|
||||
|
||||
} // namespace datatypes
|
||||
|
||||
struct AC_ChargeLoopRequest {
|
||||
Header header;
|
||||
|
||||
// the following 2 are inherited from ChargeLoopReq
|
||||
std::optional<datatypes::DisplayParameters> display_parameters;
|
||||
bool meter_info_requested;
|
||||
|
||||
std::variant<datatypes::Scheduled_AC_CLReqControlMode, datatypes::BPT_Scheduled_AC_CLReqControlMode,
|
||||
datatypes::Dynamic_AC_CLReqControlMode, datatypes::BPT_Dynamic_AC_CLReqControlMode>
|
||||
control_mode;
|
||||
};
|
||||
|
||||
struct AC_ChargeLoopResponse {
|
||||
Header header;
|
||||
datatypes::ResponseCode response_code;
|
||||
|
||||
// the following 3 are inherited from ChargeLoopRes
|
||||
std::optional<datatypes::EvseStatus> status;
|
||||
std::optional<datatypes::MeterInfo> meter_info;
|
||||
std::optional<datatypes::Receipt> receipt;
|
||||
|
||||
std::optional<datatypes::RationalNumber> target_frequency;
|
||||
|
||||
std::variant<datatypes::Scheduled_AC_CLResControlMode, datatypes::BPT_Scheduled_AC_CLResControlMode,
|
||||
datatypes::Dynamic_AC_CLResControlMode, datatypes::BPT_Dynamic_AC_CLResControlMode>
|
||||
control_mode = datatypes::Scheduled_AC_CLResControlMode();
|
||||
};
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,71 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2024 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <variant>
|
||||
|
||||
#include "common_types.hpp"
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
namespace datatypes {
|
||||
|
||||
struct AC_CPDReqEnergyTransferMode {
|
||||
RationalNumber max_charge_power;
|
||||
std::optional<RationalNumber> max_charge_power_L2;
|
||||
std::optional<RationalNumber> max_charge_power_L3;
|
||||
RationalNumber min_charge_power;
|
||||
std::optional<RationalNumber> min_charge_power_L2;
|
||||
std::optional<RationalNumber> min_charge_power_L3;
|
||||
};
|
||||
|
||||
struct BPT_AC_CPDReqEnergyTransferMode : AC_CPDReqEnergyTransferMode {
|
||||
RationalNumber max_discharge_power;
|
||||
std::optional<RationalNumber> max_discharge_power_L2;
|
||||
std::optional<RationalNumber> max_discharge_power_L3;
|
||||
RationalNumber min_discharge_power;
|
||||
std::optional<RationalNumber> min_discharge_power_L2;
|
||||
std::optional<RationalNumber> min_discharge_power_L3;
|
||||
};
|
||||
|
||||
struct AC_CPDResEnergyTransferMode {
|
||||
RationalNumber max_charge_power;
|
||||
std::optional<RationalNumber> max_charge_power_L2;
|
||||
std::optional<RationalNumber> max_charge_power_L3;
|
||||
RationalNumber min_charge_power;
|
||||
std::optional<RationalNumber> min_charge_power_L2;
|
||||
std::optional<RationalNumber> min_charge_power_L3;
|
||||
RationalNumber nominal_frequency;
|
||||
std::optional<RationalNumber> max_power_asymmetry;
|
||||
std::optional<RationalNumber> power_ramp_limitation;
|
||||
std::optional<RationalNumber> present_active_power;
|
||||
std::optional<RationalNumber> present_active_power_L2;
|
||||
std::optional<RationalNumber> present_active_power_L3;
|
||||
};
|
||||
|
||||
struct BPT_AC_CPDResEnergyTransferMode : AC_CPDResEnergyTransferMode {
|
||||
RationalNumber max_discharge_power;
|
||||
std::optional<RationalNumber> max_discharge_power_L2;
|
||||
std::optional<RationalNumber> max_discharge_power_L3;
|
||||
RationalNumber min_discharge_power;
|
||||
std::optional<RationalNumber> min_discharge_power_L2;
|
||||
std::optional<RationalNumber> min_discharge_power_L3;
|
||||
};
|
||||
|
||||
} // namespace datatypes
|
||||
|
||||
struct AC_ChargeParameterDiscoveryRequest {
|
||||
Header header;
|
||||
std::variant<datatypes::AC_CPDReqEnergyTransferMode, datatypes::BPT_AC_CPDReqEnergyTransferMode> transfer_mode;
|
||||
};
|
||||
|
||||
struct AC_ChargeParameterDiscoveryResponse {
|
||||
Header header;
|
||||
datatypes::ResponseCode response_code;
|
||||
|
||||
std::variant<datatypes::AC_CPDResEnergyTransferMode, datatypes::BPT_AC_CPDResEnergyTransferMode> transfer_mode =
|
||||
datatypes::AC_CPDResEnergyTransferMode();
|
||||
};
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,43 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "common_types.hpp"
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
namespace datatypes {
|
||||
|
||||
enum class AuthStatus {
|
||||
Accepted = 0,
|
||||
Pending = 1,
|
||||
Rejected = 2,
|
||||
};
|
||||
|
||||
struct EIM_ASReqAuthorizationMode {};
|
||||
|
||||
struct PnC_ASReqAuthorizationMode {
|
||||
std::string id;
|
||||
GenChallenge gen_challenge;
|
||||
ContractCertificateChain contract_certificate_chain;
|
||||
};
|
||||
|
||||
} // namespace datatypes
|
||||
|
||||
struct AuthorizationRequest {
|
||||
Header header;
|
||||
datatypes::Authorization selected_authorization_service;
|
||||
std::variant<datatypes::EIM_ASReqAuthorizationMode, datatypes::PnC_ASReqAuthorizationMode> authorization_mode;
|
||||
};
|
||||
|
||||
struct AuthorizationResponse {
|
||||
Header header;
|
||||
datatypes::ResponseCode response_code;
|
||||
datatypes::Processing evse_processing{datatypes::Processing::Finished};
|
||||
};
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,42 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "common_types.hpp"
|
||||
|
||||
#include <everest/util/vector/fixed_vector.hpp>
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
namespace datatypes {
|
||||
using SupportedProvidersList = everest::lib::util::fixed_vector<Name, 128>; // [0 - 128]
|
||||
|
||||
struct EIM_ASResAuthorizationMode {};
|
||||
struct PnC_ASResAuthorizationMode {
|
||||
GenChallenge gen_challenge;
|
||||
std::optional<datatypes::SupportedProvidersList> supported_providers;
|
||||
};
|
||||
|
||||
} // namespace datatypes
|
||||
|
||||
struct AuthorizationSetupRequest {
|
||||
Header header;
|
||||
};
|
||||
|
||||
struct AuthorizationSetupResponse {
|
||||
Header header;
|
||||
datatypes::ResponseCode response_code;
|
||||
|
||||
everest::lib::util::fixed_vector<datatypes::Authorization, 2> authorization_services{datatypes::Authorization::EIM};
|
||||
bool certificate_installation_service{false};
|
||||
std::variant<datatypes::EIM_ASResAuthorizationMode, datatypes::PnC_ASResAuthorizationMode> authorization_mode =
|
||||
datatypes::EIM_ASResAuthorizationMode();
|
||||
};
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,378 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <everest/util/vector/fixed_vector.hpp>
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
template <typename InType, typename OutType> void convert(const InType&, OutType&);
|
||||
|
||||
template <typename T> constexpr auto to_underlying_value(T t) {
|
||||
return static_cast<std::underlying_type_t<T>>(t);
|
||||
}
|
||||
|
||||
namespace datatypes {
|
||||
|
||||
using PercentValue = uint8_t; // [0 - 100]
|
||||
using NumericId = uint32_t; // [1 - 4294967295]
|
||||
using Identifier = std::string; // MaxLength: 255
|
||||
using Name = std::string; // MaxLength: 80
|
||||
using Description = std::string; // MaxLength: 160
|
||||
|
||||
static constexpr auto SESSION_ID_LENGTH = 8;
|
||||
using SessionId = std::array<uint8_t, SESSION_ID_LENGTH>;
|
||||
|
||||
using MeterId = std::string; // MaxLength: 32
|
||||
using MeterSignature = std::string; // Base64 encoded, MaxLength: 64
|
||||
|
||||
static constexpr auto GEN_CHALLENGE_LENGTH = 16;
|
||||
using GenChallenge = std::array<uint8_t, GEN_CHALLENGE_LENGTH>; // Base64 encoded, MaxLength: 16
|
||||
|
||||
using Certificate = std::string; // Base64 encoded, MaxLength: 1600
|
||||
using SubCertificate = everest::lib::util::fixed_vector<Certificate, 3>; // Max: 3
|
||||
|
||||
enum class ResponseCode {
|
||||
OK = 0,
|
||||
OK_CertificateExpiresSoon = 1,
|
||||
OK_NewSessionEstablished = 2,
|
||||
OK_OldSessionJoined = 3,
|
||||
OK_PowerToleranceConfirmed = 4,
|
||||
WARNING_AuthorizationSelectionInvalid = 5,
|
||||
WARNING_CertificateExpired = 6,
|
||||
WARNING_CertificateNotYetValid = 7,
|
||||
WARNING_CertificateRevoked = 8,
|
||||
WARNING_CertificateValidationError = 9,
|
||||
WARNING_ChallengeInvalid = 10,
|
||||
WARNING_EIMAuthorizationFailure = 11,
|
||||
WARNING_eMSPUnknown = 12,
|
||||
WARNING_EVPowerProfileViolation = 13,
|
||||
WARNING_GeneralPnCAuthorizationError = 14,
|
||||
WARNING_NoCertificateAvailable = 15,
|
||||
WARNING_NoContractMatchingPCIDFound = 16,
|
||||
WARNING_PowerToleranceNotConfirmed = 17,
|
||||
WARNING_ScheduleRenegotiationFailed = 18,
|
||||
WARNING_StandbyNotAllowed = 19,
|
||||
WARNING_WPT = 20,
|
||||
FAILED = 21,
|
||||
FAILED_AssociationError = 22,
|
||||
FAILED_ContactorError = 23,
|
||||
FAILED_EVPowerProfileInvalid = 24,
|
||||
FAILED_EVPowerProfileViolation = 25,
|
||||
FAILED_MeteringSignatureNotValid = 26,
|
||||
FAILED_NoEnergyTransferServiceSelected = 27,
|
||||
FAILED_NoServiceRenegotiationSupported = 28,
|
||||
FAILED_PauseNotAllowed = 29,
|
||||
FAILED_PowerDeliveryNotApplied = 30,
|
||||
FAILED_PowerToleranceNotConfirmed = 31,
|
||||
FAILED_ScheduleRenegotiation = 32,
|
||||
FAILED_ScheduleSelectionInvalid = 33,
|
||||
FAILED_SequenceError = 34,
|
||||
FAILED_ServiceIDInvalid = 35,
|
||||
FAILED_ServiceSelectionInvalid = 36,
|
||||
FAILED_SignatureError = 37,
|
||||
FAILED_UnknownSession = 38,
|
||||
FAILED_WrongChargeParameter = 39
|
||||
};
|
||||
|
||||
enum class Processing {
|
||||
Finished = 0,
|
||||
Ongoing = 1,
|
||||
Ongoing_WaitingForCustomerInteraction = 2,
|
||||
};
|
||||
|
||||
enum class Authorization {
|
||||
EIM = 0,
|
||||
PnC = 1,
|
||||
};
|
||||
|
||||
enum class ServiceCategory : uint16_t {
|
||||
AC = 1,
|
||||
DC = 2,
|
||||
WPT = 3,
|
||||
DC_ACDP = 4,
|
||||
AC_BPT = 5,
|
||||
DC_BPT = 6,
|
||||
DC_ACDP_BPT = 7,
|
||||
MCS = 8,
|
||||
MCS_BPT = 9,
|
||||
AC_DER = 10,
|
||||
Internet = 65,
|
||||
ParkingStatus = 66,
|
||||
};
|
||||
|
||||
enum class EvseNotification {
|
||||
Pause,
|
||||
ExitStandby,
|
||||
Terminate,
|
||||
ScheduleRenegotiation,
|
||||
ServiceRenegotiation,
|
||||
MeteringConfirmation,
|
||||
};
|
||||
|
||||
enum class ChargingSession {
|
||||
Pause,
|
||||
Terminate,
|
||||
ServiceRenegotiation,
|
||||
};
|
||||
|
||||
enum class AcConnector {
|
||||
SinglePhase = 1,
|
||||
ThreePhase = 3,
|
||||
};
|
||||
enum class DcConnector {
|
||||
Core = 1,
|
||||
Extended = 2,
|
||||
Dual2 = 3,
|
||||
Dual4 = 4,
|
||||
};
|
||||
enum class McsConnector {
|
||||
Mcs = 1,
|
||||
Chaoji = 2,
|
||||
UltraChaoji = 3,
|
||||
rMcs = 4,
|
||||
xMcs = 5,
|
||||
Aviation = 6,
|
||||
Marine = 7,
|
||||
};
|
||||
|
||||
enum class ControlMode {
|
||||
Scheduled = 1,
|
||||
Dynamic = 2,
|
||||
};
|
||||
enum class MobilityNeedsMode {
|
||||
ProvidedByEvcc = 1,
|
||||
ProvidedBySecc = 2,
|
||||
};
|
||||
enum class Pricing {
|
||||
NoPricing = 0,
|
||||
AbsolutePricing = 1,
|
||||
PriceLevels = 2,
|
||||
};
|
||||
|
||||
enum class BptChannel {
|
||||
Unified = 1,
|
||||
Separated = 2,
|
||||
};
|
||||
|
||||
enum class GeneratorMode {
|
||||
GridFollowing = 1,
|
||||
GridForming = 2,
|
||||
};
|
||||
|
||||
enum class GridCodeIslandingDetectionMethod {
|
||||
Active = 1,
|
||||
Passive = 2,
|
||||
};
|
||||
|
||||
enum class Protocol {
|
||||
Ftp,
|
||||
Http,
|
||||
Https,
|
||||
};
|
||||
|
||||
enum class Port {
|
||||
Port20 = 20,
|
||||
Port21 = 21,
|
||||
Port80 = 80,
|
||||
Port443 = 443,
|
||||
};
|
||||
|
||||
enum class IntendedService {
|
||||
VehicleCheckIn = 1,
|
||||
VehicleCheckOut = 2,
|
||||
};
|
||||
|
||||
enum class ParkingStatus {
|
||||
AutoInternal = 1,
|
||||
AutoExternal = 2,
|
||||
ManualInternal = 3,
|
||||
ManualExternal = 4,
|
||||
};
|
||||
|
||||
struct RationalNumber {
|
||||
int16_t value{0};
|
||||
int8_t exponent{0};
|
||||
};
|
||||
|
||||
struct EvseStatus {
|
||||
uint16_t notification_max_delay;
|
||||
EvseNotification notification;
|
||||
};
|
||||
|
||||
struct AcParameterList {
|
||||
AcConnector connector;
|
||||
ControlMode control_mode;
|
||||
MobilityNeedsMode mobility_needs_mode;
|
||||
uint32_t evse_nominal_voltage;
|
||||
Pricing pricing;
|
||||
};
|
||||
|
||||
struct AcBptParameterList : AcParameterList {
|
||||
BptChannel bpt_channel;
|
||||
GeneratorMode generator_mode;
|
||||
GridCodeIslandingDetectionMethod grid_code_detection_method;
|
||||
};
|
||||
|
||||
struct DcParameterList {
|
||||
DcConnector connector;
|
||||
ControlMode control_mode;
|
||||
MobilityNeedsMode mobility_needs_mode;
|
||||
Pricing pricing;
|
||||
};
|
||||
|
||||
struct DcBptParameterList : DcParameterList {
|
||||
BptChannel bpt_channel;
|
||||
GeneratorMode generator_mode;
|
||||
};
|
||||
|
||||
struct McsParameterList {
|
||||
McsConnector connector;
|
||||
ControlMode control_mode;
|
||||
MobilityNeedsMode mobility_needs_mode;
|
||||
Pricing pricing;
|
||||
};
|
||||
|
||||
struct McsBptParameterList : McsParameterList {
|
||||
BptChannel bpt_channel;
|
||||
GeneratorMode generator_mode;
|
||||
};
|
||||
|
||||
struct InternetParameterList {
|
||||
Protocol protocol;
|
||||
Port port;
|
||||
};
|
||||
|
||||
struct ParkingParameterList {
|
||||
IntendedService intended_service;
|
||||
ParkingStatus parking_status;
|
||||
};
|
||||
|
||||
struct Scheduled_CLReqControlMode {
|
||||
std::optional<RationalNumber> target_energy_request;
|
||||
std::optional<RationalNumber> max_energy_request;
|
||||
std::optional<RationalNumber> min_energy_request;
|
||||
};
|
||||
|
||||
struct Dynamic_CLReqControlMode {
|
||||
std::optional<uint32_t> departure_time;
|
||||
RationalNumber target_energy_request;
|
||||
RationalNumber max_energy_request;
|
||||
RationalNumber min_energy_request;
|
||||
};
|
||||
|
||||
struct Scheduled_CLResControlMode {};
|
||||
|
||||
struct Dynamic_CLResControlMode {
|
||||
std::optional<uint32_t> departure_time;
|
||||
std::optional<uint8_t> minimum_soc;
|
||||
std::optional<uint8_t> target_soc;
|
||||
std::optional<uint16_t> ack_max_delay;
|
||||
};
|
||||
|
||||
struct PowerScheduleEntry {
|
||||
uint32_t duration;
|
||||
RationalNumber power;
|
||||
std::optional<RationalNumber> power_l2;
|
||||
std::optional<RationalNumber> power_l3;
|
||||
};
|
||||
|
||||
struct MeterInfo {
|
||||
MeterId meter_id;
|
||||
uint64_t charged_energy_reading_wh;
|
||||
std::optional<uint64_t> bpt_discharged_energy_reading_wh;
|
||||
std::optional<uint64_t> capacitive_energy_reading_varh;
|
||||
std::optional<uint64_t> bpt_inductive_energy_reading_varh;
|
||||
std::optional<MeterSignature> meter_signature;
|
||||
std::optional<int16_t> meter_status;
|
||||
std::optional<uint64_t> meter_timestamp;
|
||||
};
|
||||
|
||||
struct DisplayParameters {
|
||||
std::optional<PercentValue> present_soc;
|
||||
std::optional<PercentValue> min_soc;
|
||||
std::optional<PercentValue> target_soc;
|
||||
std::optional<PercentValue> max_soc;
|
||||
std::optional<uint32_t> remaining_time_to_min_soc;
|
||||
std::optional<uint32_t> remaining_time_to_target_soc;
|
||||
std::optional<uint32_t> remaining_time_to_max_soc;
|
||||
std::optional<bool> charging_complete;
|
||||
std::optional<RationalNumber> battery_energy_capacity;
|
||||
std::optional<bool> inlet_hot;
|
||||
};
|
||||
|
||||
struct DetailedCost {
|
||||
RationalNumber amount;
|
||||
RationalNumber cost_per_unit;
|
||||
};
|
||||
|
||||
struct DetailedTax {
|
||||
NumericId tax_rule_id;
|
||||
RationalNumber amount;
|
||||
};
|
||||
|
||||
struct Receipt {
|
||||
uint64_t time_anchor;
|
||||
std::optional<DetailedCost> energy_costs;
|
||||
std::optional<DetailedCost> occupancy_costs;
|
||||
std::optional<DetailedCost> additional_service_costs;
|
||||
std::optional<DetailedCost> overstay_costs;
|
||||
everest::lib::util::fixed_vector<DetailedTax, 10> tax_costs; // 0 to 10 elements! // FIXME(sl): optional?
|
||||
};
|
||||
|
||||
struct X509IssuerSerial {
|
||||
std::string issuer_name;
|
||||
int64_t serial_number;
|
||||
};
|
||||
|
||||
struct ListOfRootCertificateIDs {
|
||||
everest::lib::util::fixed_vector<X509IssuerSerial, 20> root_certificate_id;
|
||||
};
|
||||
|
||||
// TODO(sl): Adding content to following structs
|
||||
struct SignedInfo {};
|
||||
struct SignatureValue {};
|
||||
struct KeyInfo {};
|
||||
struct Object {};
|
||||
|
||||
struct Signature {
|
||||
SignedInfo signed_info;
|
||||
SignatureValue signature;
|
||||
std::optional<KeyInfo> key_info;
|
||||
std::optional<Object> object;
|
||||
std::optional<std::string> id;
|
||||
};
|
||||
|
||||
struct ContractCertificateChain {
|
||||
Certificate certificate;
|
||||
SubCertificate sub_certificates;
|
||||
};
|
||||
|
||||
float from_RationalNumber(const RationalNumber& in);
|
||||
RationalNumber from_float(float in);
|
||||
|
||||
std::string from_Protocol(const Protocol& in);
|
||||
|
||||
std::string from_control_mode(const ControlMode& in);
|
||||
std::string from_mobility_needs_mode(const MobilityNeedsMode& in);
|
||||
|
||||
} // namespace datatypes
|
||||
|
||||
struct Header {
|
||||
datatypes::SessionId session_id{};
|
||||
uint64_t timestamp;
|
||||
// std::optional<datatypes::Signature> signature;
|
||||
};
|
||||
|
||||
template <typename cb_HeaderType> void convert(const cb_HeaderType& in, Header& out);
|
||||
|
||||
template <typename cb_RationalNumberType> void convert(const cb_RationalNumberType& in, datatypes::RationalNumber& out);
|
||||
template <typename cb_RationalNumberType> void convert(const datatypes::RationalNumber& in, cb_RationalNumberType& out);
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,20 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "common_types.hpp"
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
struct DC_CableCheckRequest {
|
||||
Header header;
|
||||
};
|
||||
|
||||
struct DC_CableCheckResponse {
|
||||
Header header;
|
||||
datatypes::ResponseCode response_code;
|
||||
|
||||
datatypes::Processing processing{datatypes::Processing::Ongoing};
|
||||
};
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,110 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "common_types.hpp"
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
namespace datatypes {
|
||||
|
||||
struct Scheduled_DC_CLReqControlMode : Scheduled_CLReqControlMode {
|
||||
RationalNumber target_current;
|
||||
RationalNumber target_voltage;
|
||||
std::optional<RationalNumber> max_charge_power;
|
||||
std::optional<RationalNumber> min_charge_power;
|
||||
std::optional<RationalNumber> max_charge_current;
|
||||
std::optional<RationalNumber> max_voltage;
|
||||
std::optional<RationalNumber> min_voltage;
|
||||
};
|
||||
|
||||
struct BPT_Scheduled_DC_CLReqControlMode : Scheduled_DC_CLReqControlMode {
|
||||
std::optional<RationalNumber> max_discharge_power;
|
||||
std::optional<RationalNumber> min_discharge_power;
|
||||
std::optional<RationalNumber> max_discharge_current;
|
||||
};
|
||||
|
||||
struct Dynamic_DC_CLReqControlMode : Dynamic_CLReqControlMode {
|
||||
RationalNumber max_charge_power;
|
||||
RationalNumber min_charge_power;
|
||||
RationalNumber max_charge_current;
|
||||
RationalNumber max_voltage;
|
||||
RationalNumber min_voltage;
|
||||
};
|
||||
|
||||
struct BPT_Dynamic_DC_CLReqControlMode : Dynamic_DC_CLReqControlMode {
|
||||
RationalNumber max_discharge_power;
|
||||
RationalNumber min_discharge_power;
|
||||
RationalNumber max_discharge_current;
|
||||
std::optional<RationalNumber> max_v2x_energy_request;
|
||||
std::optional<RationalNumber> min_v2x_energy_request;
|
||||
};
|
||||
|
||||
struct Scheduled_DC_CLResControlMode : Scheduled_CLResControlMode {
|
||||
std::optional<RationalNumber> max_charge_power;
|
||||
std::optional<RationalNumber> min_charge_power;
|
||||
std::optional<RationalNumber> max_charge_current;
|
||||
std::optional<RationalNumber> max_voltage;
|
||||
};
|
||||
|
||||
struct BPT_Scheduled_DC_CLResControlMode : Scheduled_DC_CLResControlMode {
|
||||
std::optional<RationalNumber> max_discharge_power;
|
||||
std::optional<RationalNumber> min_discharge_power;
|
||||
std::optional<RationalNumber> max_discharge_current;
|
||||
std::optional<RationalNumber> min_voltage;
|
||||
};
|
||||
|
||||
struct Dynamic_DC_CLResControlMode : Dynamic_CLResControlMode {
|
||||
RationalNumber max_charge_power;
|
||||
RationalNumber min_charge_power;
|
||||
RationalNumber max_charge_current;
|
||||
RationalNumber max_voltage;
|
||||
};
|
||||
|
||||
struct BPT_Dynamic_DC_CLResControlMode : Dynamic_DC_CLResControlMode {
|
||||
RationalNumber max_discharge_power;
|
||||
RationalNumber min_discharge_power;
|
||||
RationalNumber max_discharge_current;
|
||||
RationalNumber min_voltage;
|
||||
};
|
||||
|
||||
} // namespace datatypes
|
||||
|
||||
struct DC_ChargeLoopRequest {
|
||||
|
||||
Header header;
|
||||
|
||||
// the following 2 are inherited from ChargeLoopReq
|
||||
std::optional<datatypes::DisplayParameters> display_parameters;
|
||||
bool meter_info_requested;
|
||||
|
||||
datatypes::RationalNumber present_voltage;
|
||||
std::variant<datatypes::Scheduled_DC_CLReqControlMode, datatypes::BPT_Scheduled_DC_CLReqControlMode,
|
||||
datatypes::Dynamic_DC_CLReqControlMode, datatypes::BPT_Dynamic_DC_CLReqControlMode>
|
||||
control_mode;
|
||||
};
|
||||
|
||||
struct DC_ChargeLoopResponse {
|
||||
Header header;
|
||||
datatypes::ResponseCode response_code;
|
||||
|
||||
// the following 3 are inherited from ChargeLoopRes
|
||||
std::optional<datatypes::EvseStatus> status;
|
||||
std::optional<datatypes::MeterInfo> meter_info;
|
||||
std::optional<datatypes::Receipt> receipt;
|
||||
|
||||
datatypes::RationalNumber present_current{0, 0};
|
||||
datatypes::RationalNumber present_voltage{0, 0};
|
||||
bool power_limit_achieved{false};
|
||||
bool current_limit_achieved{false};
|
||||
bool voltage_limit_achieved{false};
|
||||
|
||||
std::variant<datatypes::Scheduled_DC_CLResControlMode, datatypes::BPT_Scheduled_DC_CLResControlMode,
|
||||
datatypes::Dynamic_DC_CLResControlMode, datatypes::BPT_Dynamic_DC_CLResControlMode>
|
||||
control_mode = datatypes::Scheduled_DC_CLResControlMode();
|
||||
};
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,63 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <variant>
|
||||
|
||||
#include "common_types.hpp"
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
namespace datatypes {
|
||||
|
||||
struct DC_CPDReqEnergyTransferMode {
|
||||
RationalNumber max_charge_power;
|
||||
RationalNumber min_charge_power;
|
||||
RationalNumber max_charge_current;
|
||||
RationalNumber min_charge_current;
|
||||
RationalNumber max_voltage;
|
||||
RationalNumber min_voltage;
|
||||
std::optional<uint8_t> target_soc;
|
||||
};
|
||||
|
||||
struct BPT_DC_CPDReqEnergyTransferMode : DC_CPDReqEnergyTransferMode {
|
||||
RationalNumber max_discharge_power;
|
||||
RationalNumber min_discharge_power;
|
||||
RationalNumber max_discharge_current;
|
||||
RationalNumber min_discharge_current;
|
||||
};
|
||||
|
||||
struct DC_CPDResEnergyTransferMode {
|
||||
RationalNumber max_charge_power;
|
||||
RationalNumber min_charge_power;
|
||||
RationalNumber max_charge_current;
|
||||
RationalNumber min_charge_current;
|
||||
RationalNumber max_voltage;
|
||||
RationalNumber min_voltage;
|
||||
std::optional<RationalNumber> power_ramp_limit;
|
||||
};
|
||||
|
||||
struct BPT_DC_CPDResEnergyTransferMode : DC_CPDResEnergyTransferMode {
|
||||
RationalNumber max_discharge_power;
|
||||
RationalNumber min_discharge_power;
|
||||
RationalNumber max_discharge_current;
|
||||
RationalNumber min_discharge_current;
|
||||
};
|
||||
|
||||
} // namespace datatypes
|
||||
|
||||
struct DC_ChargeParameterDiscoveryRequest {
|
||||
Header header;
|
||||
std::variant<datatypes::DC_CPDReqEnergyTransferMode, datatypes::BPT_DC_CPDReqEnergyTransferMode> transfer_mode;
|
||||
};
|
||||
|
||||
struct DC_ChargeParameterDiscoveryResponse {
|
||||
Header header;
|
||||
datatypes::ResponseCode response_code;
|
||||
|
||||
std::variant<datatypes::DC_CPDResEnergyTransferMode, datatypes::BPT_DC_CPDResEnergyTransferMode> transfer_mode =
|
||||
datatypes::DC_CPDResEnergyTransferMode();
|
||||
};
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,24 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "common_types.hpp"
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
struct DC_PreChargeRequest {
|
||||
Header header;
|
||||
|
||||
datatypes::Processing processing;
|
||||
datatypes::RationalNumber present_voltage;
|
||||
datatypes::RationalNumber target_voltage;
|
||||
};
|
||||
|
||||
struct DC_PreChargeResponse {
|
||||
Header header;
|
||||
datatypes::ResponseCode response_code;
|
||||
|
||||
datatypes::RationalNumber present_voltage;
|
||||
};
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,22 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "common_types.hpp"
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
struct DC_WeldingDetectionRequest {
|
||||
Header header;
|
||||
|
||||
datatypes::Processing processing;
|
||||
};
|
||||
|
||||
struct DC_WeldingDetectionResponse {
|
||||
Header header;
|
||||
datatypes::ResponseCode response_code;
|
||||
|
||||
datatypes::RationalNumber present_voltage;
|
||||
};
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,50 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
// FIXME (aw): how to streamline this with type.hpp?
|
||||
|
||||
#include <iso15118/io/sdp.hpp>
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
template <typename T> struct PayloadTypeTrait;
|
||||
|
||||
//
|
||||
// definitions of type traits
|
||||
//
|
||||
#ifdef CREATE_TYPE_TRAIT
|
||||
#define CREATE_TYPE_TRAIT_PUSHED CREATE_TYPE_TRAIT
|
||||
#endif
|
||||
|
||||
#define CREATE_TYPE_TRAIT(struct_name, payload_type) \
|
||||
struct struct_name; \
|
||||
template <> struct PayloadTypeTrait<struct_name> { \
|
||||
static const io::v2gtp::PayloadType type = io::v2gtp::PayloadType::payload_type; \
|
||||
}
|
||||
|
||||
CREATE_TYPE_TRAIT(SupportedAppProtocolResponse, SAP);
|
||||
CREATE_TYPE_TRAIT(SessionSetupResponse, Part20Main);
|
||||
CREATE_TYPE_TRAIT(AuthorizationSetupResponse, Part20Main);
|
||||
CREATE_TYPE_TRAIT(AuthorizationResponse, Part20Main);
|
||||
CREATE_TYPE_TRAIT(ServiceDiscoveryResponse, Part20Main);
|
||||
CREATE_TYPE_TRAIT(ServiceDetailResponse, Part20Main);
|
||||
CREATE_TYPE_TRAIT(ServiceSelectionResponse, Part20Main);
|
||||
CREATE_TYPE_TRAIT(DC_ChargeParameterDiscoveryResponse, Part20DC);
|
||||
CREATE_TYPE_TRAIT(ScheduleExchangeResponse, Part20Main);
|
||||
CREATE_TYPE_TRAIT(DC_CableCheckResponse, Part20DC);
|
||||
CREATE_TYPE_TRAIT(DC_PreChargeResponse, Part20DC);
|
||||
CREATE_TYPE_TRAIT(PowerDeliveryResponse, Part20Main);
|
||||
CREATE_TYPE_TRAIT(DC_ChargeLoopResponse, Part20DC);
|
||||
CREATE_TYPE_TRAIT(DC_WeldingDetectionResponse, Part20DC);
|
||||
CREATE_TYPE_TRAIT(SessionStopResponse, Part20Main);
|
||||
CREATE_TYPE_TRAIT(AC_ChargeParameterDiscoveryResponse, Part20AC);
|
||||
CREATE_TYPE_TRAIT(AC_ChargeLoopResponse, Part20AC);
|
||||
|
||||
#ifdef CREATE_TYPE_TRAIT_PUSHED
|
||||
#define CREATE_TYPE_TRAIT CREATE_TYPE_TRAIT_PUSHED
|
||||
#else
|
||||
#undef CREATE_TYPE_TRAIT
|
||||
#endif
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,68 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "common_types.hpp"
|
||||
|
||||
#include <everest/util/vector/fixed_vector.hpp>
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
namespace datatypes {
|
||||
|
||||
enum class Progress {
|
||||
Start,
|
||||
Stop,
|
||||
Standby,
|
||||
ScheduleRenegotiation,
|
||||
};
|
||||
|
||||
struct Dynamic_EVPPTControlMode {
|
||||
// intentionally left blank
|
||||
};
|
||||
|
||||
enum class PowerToleranceAcceptance : uint8_t {
|
||||
NotConfirmed,
|
||||
Confirmed,
|
||||
};
|
||||
|
||||
struct Scheduled_EVPPTControlMode {
|
||||
NumericId selected_schedule;
|
||||
std::optional<PowerToleranceAcceptance> power_tolerance_acceptance;
|
||||
};
|
||||
|
||||
struct PowerProfile {
|
||||
uint64_t time_anchor;
|
||||
std::variant<Dynamic_EVPPTControlMode, Scheduled_EVPPTControlMode> control_mode;
|
||||
everest::lib::util::fixed_vector<PowerScheduleEntry, 2048> entries; // maximum 2048
|
||||
};
|
||||
|
||||
enum class ChannelSelection : uint8_t {
|
||||
Charge,
|
||||
Discharge,
|
||||
};
|
||||
|
||||
}; // namespace datatypes
|
||||
|
||||
struct PowerDeliveryRequest {
|
||||
Header header;
|
||||
|
||||
datatypes::Processing processing;
|
||||
datatypes::Progress charge_progress;
|
||||
|
||||
std::optional<datatypes::PowerProfile> power_profile;
|
||||
std::optional<datatypes::ChannelSelection> channel_selection;
|
||||
};
|
||||
|
||||
struct PowerDeliveryResponse {
|
||||
Header header;
|
||||
datatypes::ResponseCode response_code;
|
||||
|
||||
std::optional<datatypes::EvseStatus> status;
|
||||
};
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,206 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
#include "common_types.hpp"
|
||||
|
||||
#include <everest/util/vector/fixed_vector.hpp>
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
namespace datatypes {
|
||||
|
||||
static constexpr auto TAX_RULE_LENGTH = 10;
|
||||
static constexpr auto PRICE_RULE_STACK_LENGTH = 1024;
|
||||
static constexpr auto PRICE_RULE_LENGTH = 8;
|
||||
static constexpr auto OVERSTAY_RULE_LENGTH = 5;
|
||||
static constexpr auto ADDITIONAL_SERVICE_LENGTH = 5;
|
||||
static constexpr auto PRICE_LEVEL_SCHEDULE_LENGTH = 1024;
|
||||
static constexpr auto SCHEDULED_POWER_DURATION_S = 86400;
|
||||
|
||||
using MaxSupportingPointsScheduleTuple = uint16_t; // needs to be [12 - 1024]
|
||||
|
||||
using Curreny = std::string; // MaxLength: 3
|
||||
using Language = std::string; // MaxLength: 3
|
||||
|
||||
struct TaxRule {
|
||||
NumericId tax_rule_id;
|
||||
std::optional<Name> tax_rule_name;
|
||||
RationalNumber tax_rate;
|
||||
std::optional<bool> tax_included_in_price;
|
||||
bool applies_to_energy_fee;
|
||||
bool applies_to_parking_fee;
|
||||
bool applies_to_overstay_fee;
|
||||
bool applies_to_minimum_maximum_cost;
|
||||
};
|
||||
|
||||
struct PriceRule {
|
||||
RationalNumber energy_fee;
|
||||
std::optional<RationalNumber> parking_fee;
|
||||
std::optional<uint32_t> parking_fee_period;
|
||||
std::optional<uint16_t> carbon_dioxide_emission;
|
||||
std::optional<uint8_t> renewable_generation_percentage;
|
||||
RationalNumber power_range_start;
|
||||
};
|
||||
|
||||
struct PriceRuleStack {
|
||||
uint32_t duration;
|
||||
std::array<PriceRule, PRICE_RULE_LENGTH> price_rule;
|
||||
};
|
||||
|
||||
struct AdditionalService {
|
||||
Name service_name;
|
||||
RationalNumber service_fee;
|
||||
};
|
||||
|
||||
using TaxRuleList = std::array<TaxRule, TAX_RULE_LENGTH>;
|
||||
using PriceRuleStackList = std::array<PriceRuleStack, PRICE_RULE_STACK_LENGTH>;
|
||||
using AdditionalServiceList = std::array<AdditionalService, ADDITIONAL_SERVICE_LENGTH>;
|
||||
|
||||
struct Dynamic_SEReqControlMode {
|
||||
uint32_t departure_time;
|
||||
std::optional<PercentValue> minimum_soc;
|
||||
std::optional<PercentValue> target_soc;
|
||||
RationalNumber target_energy;
|
||||
RationalNumber max_energy;
|
||||
RationalNumber min_energy;
|
||||
std::optional<RationalNumber> max_v2x_energy;
|
||||
std::optional<RationalNumber> min_v2x_energy;
|
||||
};
|
||||
|
||||
struct EVPowerScheduleEntry {
|
||||
uint32_t duration;
|
||||
RationalNumber power;
|
||||
};
|
||||
|
||||
struct EVPowerSchedule {
|
||||
uint64_t time_anchor;
|
||||
everest::lib::util::fixed_vector<EVPowerScheduleEntry, 1024> entries; // max 1024
|
||||
};
|
||||
|
||||
struct EVPriceRule {
|
||||
RationalNumber energy_fee;
|
||||
RationalNumber power_range_start;
|
||||
};
|
||||
|
||||
struct EVPriceRuleStack {
|
||||
uint32_t duration;
|
||||
everest::lib::util::fixed_vector<EVPriceRule, 8> price_rules; // max 8
|
||||
};
|
||||
|
||||
struct EVAbsolutePriceSchedule {
|
||||
uint64_t time_anchor;
|
||||
Curreny currency;
|
||||
Identifier price_algorithm;
|
||||
everest::lib::util::fixed_vector<EVPriceRuleStack, 1024> price_rule_stacks; // max 1024
|
||||
};
|
||||
|
||||
struct EVEnergyOffer {
|
||||
EVPowerSchedule power_schedule;
|
||||
EVAbsolutePriceSchedule absolute_price_schedule;
|
||||
};
|
||||
|
||||
struct Scheduled_SEReqControlMode {
|
||||
std::optional<uint32_t> departure_time;
|
||||
std::optional<RationalNumber> target_energy;
|
||||
std::optional<RationalNumber> max_energy;
|
||||
std::optional<RationalNumber> min_energy;
|
||||
std::optional<EVEnergyOffer> energy_offer;
|
||||
};
|
||||
|
||||
struct OverstayRule {
|
||||
std::optional<Description> overstay_rule_description;
|
||||
uint32_t start_time;
|
||||
RationalNumber overstay_fee;
|
||||
uint32_t overstay_fee_period;
|
||||
};
|
||||
|
||||
struct OverstayRulesList {
|
||||
std::optional<uint32_t> overstay_time_threshold;
|
||||
std::optional<RationalNumber> overstay_power_threshold;
|
||||
everest::lib::util::fixed_vector<OverstayRule, 5> overstay_rule; // 5
|
||||
};
|
||||
|
||||
struct AbsolutePriceSchedule {
|
||||
std::optional<std::string> id;
|
||||
uint64_t time_anchor;
|
||||
NumericId price_schedule_id;
|
||||
std::optional<Description> price_schedule_description;
|
||||
Curreny currency;
|
||||
Language language;
|
||||
Identifier price_algorithm;
|
||||
std::optional<RationalNumber> minimum_cost;
|
||||
std::optional<RationalNumber> maximum_cost;
|
||||
std::optional<TaxRuleList> tax_rules;
|
||||
PriceRuleStackList price_rule_stacks;
|
||||
std::optional<OverstayRulesList> overstay_rules;
|
||||
std::optional<AdditionalServiceList> additional_selected_services;
|
||||
};
|
||||
|
||||
struct PriceLevelScheduleEntry {
|
||||
uint32_t duration;
|
||||
uint8_t price_level;
|
||||
};
|
||||
|
||||
struct PriceLevelSchedule {
|
||||
std::optional<std::string> id;
|
||||
uint64_t time_anchor;
|
||||
NumericId price_schedule_id;
|
||||
std::optional<Description> price_schedule_description;
|
||||
uint8_t number_of_price_levels;
|
||||
everest::lib::util::fixed_vector<PriceLevelScheduleEntry, 1024> price_level_schedule_entries; // 1024
|
||||
};
|
||||
|
||||
struct Dynamic_SEResControlMode {
|
||||
std::optional<uint32_t> departure_time;
|
||||
std::optional<PercentValue> minimum_soc;
|
||||
std::optional<PercentValue> target_soc;
|
||||
std::variant<std::monostate, AbsolutePriceSchedule, PriceLevelSchedule> price_schedule;
|
||||
};
|
||||
|
||||
struct PowerSchedule {
|
||||
uint64_t time_anchor;
|
||||
std::optional<RationalNumber> available_energy;
|
||||
std::optional<RationalNumber> power_tolerance;
|
||||
everest::lib::util::fixed_vector<PowerScheduleEntry, 1024> entries; // 1024
|
||||
};
|
||||
|
||||
struct ChargingSchedule {
|
||||
PowerSchedule power_schedule;
|
||||
std::variant<std::monostate, AbsolutePriceSchedule, PriceLevelSchedule> price_schedule;
|
||||
};
|
||||
|
||||
struct ScheduleTuple {
|
||||
NumericId schedule_tuple_id; // 1 - 255
|
||||
ChargingSchedule charging_schedule;
|
||||
std::optional<ChargingSchedule> discharging_schedule;
|
||||
};
|
||||
|
||||
struct Scheduled_SEResControlMode {
|
||||
everest::lib::util::fixed_vector<ScheduleTuple, 3> schedule_tuple; // 3
|
||||
};
|
||||
|
||||
}; // namespace datatypes
|
||||
|
||||
struct ScheduleExchangeRequest {
|
||||
Header header;
|
||||
datatypes::MaxSupportingPointsScheduleTuple max_supporting_points;
|
||||
std::variant<datatypes::Dynamic_SEReqControlMode, datatypes::Scheduled_SEReqControlMode> control_mode;
|
||||
};
|
||||
|
||||
struct ScheduleExchangeResponse {
|
||||
Header header;
|
||||
datatypes::ResponseCode response_code;
|
||||
datatypes::Processing processing{datatypes::Processing::Finished};
|
||||
std::optional<bool> go_to_pause;
|
||||
|
||||
std::variant<datatypes::Dynamic_SEResControlMode, datatypes::Scheduled_SEResControlMode> control_mode =
|
||||
datatypes::Dynamic_SEResControlMode();
|
||||
};
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,52 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <variant>
|
||||
|
||||
#include "common_types.hpp"
|
||||
|
||||
#include <everest/util/vector/fixed_vector.hpp>
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
namespace datatypes {
|
||||
|
||||
struct Parameter {
|
||||
Name name;
|
||||
std::variant<bool, int8_t, int16_t, int32_t, Name, RationalNumber> value;
|
||||
};
|
||||
|
||||
struct ParameterSet {
|
||||
uint16_t id;
|
||||
everest::lib::util::fixed_vector<Parameter, 32> parameter;
|
||||
|
||||
ParameterSet() = default;
|
||||
ParameterSet(uint16_t _id);
|
||||
ParameterSet(uint16_t _id, const AcParameterList& list);
|
||||
ParameterSet(uint16_t _id, const AcBptParameterList& list);
|
||||
ParameterSet(uint16_t _id, const DcParameterList& list);
|
||||
ParameterSet(uint16_t _id, const DcBptParameterList& list);
|
||||
ParameterSet(uint16_t _id, const McsParameterList& list);
|
||||
ParameterSet(uint16_t _id, const McsBptParameterList& list);
|
||||
ParameterSet(uint16_t _id, const InternetParameterList& list);
|
||||
ParameterSet(uint16_t _id, const ParkingParameterList& list);
|
||||
};
|
||||
|
||||
using ServiceParameterList = everest::lib::util::fixed_vector<ParameterSet, 32>; // Max: 32
|
||||
|
||||
} // namespace datatypes
|
||||
|
||||
struct ServiceDetailRequest {
|
||||
Header header;
|
||||
uint16_t service;
|
||||
};
|
||||
|
||||
struct ServiceDetailResponse {
|
||||
Header header;
|
||||
datatypes::ResponseCode response_code;
|
||||
uint16_t service{to_underlying_value(datatypes::ServiceCategory::DC)};
|
||||
datatypes::ServiceParameterList service_parameter_list{datatypes::ParameterSet(0)};
|
||||
};
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,48 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include "common_types.hpp"
|
||||
|
||||
#include <everest/util/vector/fixed_vector.hpp>
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
namespace datatypes {
|
||||
using ServiceIdList = everest::lib::util::fixed_vector<std::uint16_t, 16>; // 16
|
||||
|
||||
struct Service {
|
||||
ServiceCategory service_id;
|
||||
bool free_service;
|
||||
};
|
||||
using ServiceList = everest::lib::util::fixed_vector<Service, 8>; // max: 8
|
||||
|
||||
struct VasService {
|
||||
uint16_t service_id;
|
||||
bool free_service;
|
||||
};
|
||||
using VasServiceList = everest::lib::util::fixed_vector<VasService, 8>; // max: 8
|
||||
|
||||
} // namespace datatypes
|
||||
|
||||
struct ServiceDiscoveryRequest {
|
||||
Header header;
|
||||
std::optional<datatypes::ServiceIdList> supported_service_ids;
|
||||
};
|
||||
|
||||
struct ServiceDiscoveryResponse {
|
||||
|
||||
Header header;
|
||||
datatypes::ResponseCode response_code;
|
||||
bool service_renegotiation_supported = false;
|
||||
datatypes::ServiceList energy_transfer_service_list = {{
|
||||
datatypes::ServiceCategory::AC, // service_id
|
||||
false // free_service
|
||||
}};
|
||||
std::optional<datatypes::VasServiceList> vas_list;
|
||||
};
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,40 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "common_types.hpp"
|
||||
|
||||
#include <everest/util/vector/fixed_vector.hpp>
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
namespace datatypes {
|
||||
|
||||
struct SelectedService {
|
||||
ServiceCategory service_id;
|
||||
uint16_t parameter_set_id;
|
||||
};
|
||||
|
||||
struct VasSelectedService {
|
||||
uint16_t service_id;
|
||||
uint16_t parameter_set_id;
|
||||
};
|
||||
|
||||
using VasSelectedServiceList = everest::lib::util::fixed_vector<VasSelectedService, 16>; // Max: 16
|
||||
|
||||
} // namespace datatypes
|
||||
|
||||
struct ServiceSelectionRequest {
|
||||
Header header;
|
||||
datatypes::SelectedService selected_energy_transfer_service;
|
||||
std::optional<datatypes::VasSelectedServiceList> selected_vas_list;
|
||||
};
|
||||
|
||||
struct ServiceSelectionResponse {
|
||||
Header header;
|
||||
datatypes::ResponseCode response_code;
|
||||
};
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,22 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "common_types.hpp"
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
struct SessionSetupRequest {
|
||||
Header header;
|
||||
datatypes::Identifier evccid;
|
||||
};
|
||||
|
||||
struct SessionSetupResponse {
|
||||
Header header;
|
||||
datatypes::ResponseCode response_code;
|
||||
datatypes::Identifier evseid;
|
||||
};
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,24 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "common_types.hpp"
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
struct SessionStopRequest {
|
||||
Header header;
|
||||
datatypes::ChargingSession charging_session;
|
||||
std::optional<datatypes::Name> ev_termination_code;
|
||||
std::optional<datatypes::Description> ev_termination_explanation;
|
||||
};
|
||||
|
||||
struct SessionStopResponse {
|
||||
Header header;
|
||||
datatypes::ResponseCode response_code;
|
||||
};
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,47 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <iso15118/io/stream_view.hpp>
|
||||
|
||||
#include <everest/util/vector/fixed_vector.hpp>
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
struct SupportedAppProtocol {
|
||||
std::string protocol_namespace;
|
||||
uint32_t version_number_major;
|
||||
uint32_t version_number_minor;
|
||||
uint8_t schema_id;
|
||||
uint8_t priority;
|
||||
|
||||
bool operator==(const iso15118::message_20::SupportedAppProtocol& other) const {
|
||||
return this->protocol_namespace == other.protocol_namespace and this->priority == other.priority and
|
||||
this->schema_id == other.schema_id and this->version_number_major == other.version_number_major and
|
||||
this->version_number_minor == other.version_number_minor;
|
||||
}
|
||||
};
|
||||
|
||||
struct SupportedAppProtocolRequest {
|
||||
everest::lib::util::fixed_vector<SupportedAppProtocol, 20> app_protocol;
|
||||
};
|
||||
|
||||
struct SupportedAppProtocolResponse {
|
||||
enum class ResponseCode {
|
||||
OK_SuccessfulNegotiation = 0,
|
||||
OK_SuccessfulNegotiationWithMinorDeviation = 1,
|
||||
Failed_NoNegotiation = 2,
|
||||
};
|
||||
|
||||
ResponseCode response_code;
|
||||
std::optional<uint8_t> schema_id;
|
||||
};
|
||||
|
||||
size_t encode_supported_app_protocol_response(const io::StreamOutputView&, const SupportedAppProtocolResponse&);
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,109 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <iso15118/io/stream_view.hpp>
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
enum class Type {
|
||||
None,
|
||||
SupportedAppProtocolReq,
|
||||
SupportedAppProtocolRes,
|
||||
SessionSetupReq,
|
||||
SessionSetupRes,
|
||||
AuthorizationSetupReq,
|
||||
AuthorizationSetupRes,
|
||||
AuthorizationReq,
|
||||
AuthorizationRes,
|
||||
ServiceDiscoveryReq,
|
||||
ServiceDiscoveryRes,
|
||||
ServiceDetailReq,
|
||||
ServiceDetailRes,
|
||||
ServiceSelectionReq,
|
||||
ServiceSelectionRes,
|
||||
DC_ChargeParameterDiscoveryReq,
|
||||
DC_ChargeParameterDiscoveryRes,
|
||||
ScheduleExchangeReq,
|
||||
ScheduleExchangeRes,
|
||||
DC_CableCheckReq,
|
||||
DC_CableCheckRes,
|
||||
DC_PreChargeReq,
|
||||
DC_PreChargeRes,
|
||||
PowerDeliveryReq,
|
||||
PowerDeliveryRes,
|
||||
DC_ChargeLoopReq,
|
||||
DC_ChargeLoopRes,
|
||||
DC_WeldingDetectionReq,
|
||||
DC_WeldingDetectionRes,
|
||||
SessionStopReq,
|
||||
SessionStopRes,
|
||||
AC_ChargeParameterDiscoveryReq,
|
||||
AC_ChargeParameterDiscoveryRes,
|
||||
AC_ChargeLoopReq,
|
||||
AC_ChargeLoopRes,
|
||||
};
|
||||
|
||||
template <typename T> struct TypeTrait {
|
||||
static const Type type = Type::None;
|
||||
};
|
||||
|
||||
template <typename InType, typename OutType> void convert(const InType&, OutType&);
|
||||
|
||||
template <typename MessageType> size_t serialize(const MessageType&, const io::StreamOutputView&);
|
||||
|
||||
//
|
||||
// definitions of type traits
|
||||
//
|
||||
#ifdef CREATE_TYPE_TRAIT
|
||||
#define CREATE_TYPE_TRAIT_PUSHED CREATE_TYPE_TRAIT
|
||||
#endif
|
||||
|
||||
#define CREATE_TYPE_TRAIT(struct_name, enum_name) \
|
||||
struct struct_name; \
|
||||
template <> struct TypeTrait<struct_name> { \
|
||||
static const Type type = Type::enum_name; \
|
||||
}
|
||||
|
||||
CREATE_TYPE_TRAIT(SupportedAppProtocolRequest, SupportedAppProtocolReq);
|
||||
CREATE_TYPE_TRAIT(SupportedAppProtocolResponse, SupportedAppProtocolRes);
|
||||
CREATE_TYPE_TRAIT(SessionSetupRequest, SessionSetupReq);
|
||||
CREATE_TYPE_TRAIT(SessionSetupResponse, SessionSetupRes);
|
||||
CREATE_TYPE_TRAIT(AuthorizationSetupRequest, AuthorizationSetupReq);
|
||||
CREATE_TYPE_TRAIT(AuthorizationSetupResponse, AuthorizationSetupRes);
|
||||
CREATE_TYPE_TRAIT(AuthorizationRequest, AuthorizationReq);
|
||||
CREATE_TYPE_TRAIT(AuthorizationResponse, AuthorizationRes);
|
||||
CREATE_TYPE_TRAIT(ServiceDiscoveryRequest, ServiceDiscoveryReq);
|
||||
CREATE_TYPE_TRAIT(ServiceDiscoveryResponse, ServiceDiscoveryRes);
|
||||
CREATE_TYPE_TRAIT(ServiceDetailRequest, ServiceDetailReq);
|
||||
CREATE_TYPE_TRAIT(ServiceDetailResponse, ServiceDetailRes);
|
||||
CREATE_TYPE_TRAIT(ServiceSelectionRequest, ServiceSelectionReq);
|
||||
CREATE_TYPE_TRAIT(ServiceSelectionResponse, ServiceSelectionRes);
|
||||
CREATE_TYPE_TRAIT(DC_ChargeParameterDiscoveryRequest, DC_ChargeParameterDiscoveryReq);
|
||||
CREATE_TYPE_TRAIT(DC_ChargeParameterDiscoveryResponse, DC_ChargeParameterDiscoveryRes);
|
||||
CREATE_TYPE_TRAIT(ScheduleExchangeRequest, ScheduleExchangeReq);
|
||||
CREATE_TYPE_TRAIT(ScheduleExchangeResponse, ScheduleExchangeRes);
|
||||
CREATE_TYPE_TRAIT(DC_CableCheckRequest, DC_CableCheckReq);
|
||||
CREATE_TYPE_TRAIT(DC_CableCheckResponse, DC_CableCheckRes);
|
||||
CREATE_TYPE_TRAIT(DC_PreChargeRequest, DC_PreChargeReq);
|
||||
CREATE_TYPE_TRAIT(DC_PreChargeResponse, DC_PreChargeRes);
|
||||
CREATE_TYPE_TRAIT(PowerDeliveryRequest, PowerDeliveryReq);
|
||||
CREATE_TYPE_TRAIT(PowerDeliveryResponse, PowerDeliveryRes);
|
||||
CREATE_TYPE_TRAIT(DC_ChargeLoopRequest, DC_ChargeLoopReq);
|
||||
CREATE_TYPE_TRAIT(DC_ChargeLoopResponse, DC_ChargeLoopRes);
|
||||
CREATE_TYPE_TRAIT(DC_WeldingDetectionRequest, DC_WeldingDetectionReq);
|
||||
CREATE_TYPE_TRAIT(DC_WeldingDetectionResponse, DC_WeldingDetectionRes);
|
||||
CREATE_TYPE_TRAIT(SessionStopRequest, SessionStopReq);
|
||||
CREATE_TYPE_TRAIT(SessionStopResponse, SessionStopRes);
|
||||
CREATE_TYPE_TRAIT(AC_ChargeParameterDiscoveryRequest, AC_ChargeParameterDiscoveryReq);
|
||||
CREATE_TYPE_TRAIT(AC_ChargeParameterDiscoveryResponse, AC_ChargeParameterDiscoveryRes);
|
||||
CREATE_TYPE_TRAIT(AC_ChargeLoopRequest, AC_ChargeLoopReq);
|
||||
CREATE_TYPE_TRAIT(AC_ChargeLoopResponse, AC_ChargeLoopRes);
|
||||
|
||||
#ifdef CREATE_TYPE_TRAIT_PUSHED
|
||||
#define CREATE_TYPE_TRAIT CREATE_TYPE_TRAIT_PUSHED
|
||||
#else
|
||||
#undef CREATE_TYPE_TRAIT
|
||||
#endif
|
||||
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,61 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
// FIXME (aw): we only need the payload types from sdp.hpp, this could be shared in a separate header file
|
||||
#include <iso15118/io/sdp.hpp>
|
||||
#include <iso15118/io/stream_view.hpp>
|
||||
|
||||
#include "type.hpp"
|
||||
|
||||
namespace iso15118::message_20 {
|
||||
|
||||
class Variant {
|
||||
public:
|
||||
using CustomDeleter = void (*)(void*);
|
||||
Variant(io::v2gtp::PayloadType, const io::StreamInputView&);
|
||||
template <typename MessageType> Variant(const MessageType& in) {
|
||||
static_assert(TypeTrait<MessageType>::type != Type::None, "Unhandled type!");
|
||||
|
||||
data = new MessageType;
|
||||
*static_cast<MessageType*>(data) = in;
|
||||
custom_deleter = [](void* ptr) { delete static_cast<MessageType*>(ptr); };
|
||||
type = message_20::TypeTrait<MessageType>::type;
|
||||
}
|
||||
~Variant();
|
||||
|
||||
Type get_type() const;
|
||||
|
||||
const std::string& get_error() const;
|
||||
|
||||
template <typename T> const T& get() const {
|
||||
static_assert(TypeTrait<T>::type != Type::None, "Unhandled type!");
|
||||
if (TypeTrait<T>::type != type) {
|
||||
throw std::runtime_error("Illegal message type access");
|
||||
}
|
||||
|
||||
return *static_cast<T*>(data);
|
||||
}
|
||||
|
||||
template <typename T> T const* get_if() const {
|
||||
static_assert(TypeTrait<T>::type != Type::None, "Unhandled type!");
|
||||
if (TypeTrait<T>::type != type) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return static_cast<T*>(data);
|
||||
}
|
||||
|
||||
private:
|
||||
CustomDeleter custom_deleter{nullptr};
|
||||
void* data{nullptr};
|
||||
Type type{Type::None};
|
||||
std::string error;
|
||||
};
|
||||
} // namespace iso15118::message_20
|
||||
@@ -0,0 +1,122 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
#include <iso15118/d20/ev_information.hpp>
|
||||
#include <iso15118/d20/limits.hpp>
|
||||
#include <iso15118/d20/session.hpp>
|
||||
#include <iso15118/message/ac_charge_loop.hpp>
|
||||
#include <iso15118/message/ac_charge_parameter_discovery.hpp>
|
||||
#include <iso15118/message/dc_charge_loop.hpp>
|
||||
#include <iso15118/message/dc_charge_parameter_discovery.hpp>
|
||||
#include <iso15118/message/schedule_exchange.hpp>
|
||||
#include <iso15118/message/service_detail.hpp>
|
||||
#include <iso15118/message/service_selection.hpp>
|
||||
#include <iso15118/message/type.hpp>
|
||||
|
||||
namespace iso15118::session {
|
||||
|
||||
namespace dt = message_20::datatypes;
|
||||
|
||||
namespace feedback {
|
||||
|
||||
enum class Signal {
|
||||
REQUIRE_AUTH_EIM,
|
||||
START_CABLE_CHECK,
|
||||
SETUP_FINISHED,
|
||||
PRE_CHARGE_STARTED,
|
||||
CHARGE_LOOP_STARTED,
|
||||
CHARGE_LOOP_FINISHED,
|
||||
DC_OPEN_CONTACTOR,
|
||||
AC_CLOSE_CONTACTOR,
|
||||
AC_OPEN_CONTACTOR,
|
||||
DLINK_TERMINATE,
|
||||
DLINK_ERROR,
|
||||
DLINK_PAUSE,
|
||||
};
|
||||
|
||||
struct DcMaximumLimits {
|
||||
float voltage{NAN};
|
||||
float current{NAN};
|
||||
float power{NAN};
|
||||
};
|
||||
|
||||
using PresentVoltage = dt::RationalNumber;
|
||||
using MeterInfoRequested = bool;
|
||||
using DcReqControlMode = std::variant<dt::Scheduled_DC_CLReqControlMode, dt::BPT_Scheduled_DC_CLReqControlMode,
|
||||
dt::Dynamic_DC_CLReqControlMode, dt::BPT_Dynamic_DC_CLReqControlMode>;
|
||||
|
||||
using AcReqControlMode = std::variant<dt::Scheduled_AC_CLReqControlMode, dt::BPT_Scheduled_AC_CLReqControlMode,
|
||||
dt::Dynamic_AC_CLReqControlMode, dt::BPT_Dynamic_AC_CLReqControlMode>;
|
||||
|
||||
using DcChargeLoopReq = std::variant<DcReqControlMode, dt::DisplayParameters, PresentVoltage, MeterInfoRequested>;
|
||||
|
||||
using EvseTransferLimits = std::variant<d20::DcTransferLimits, d20::AcTransferLimits>;
|
||||
|
||||
using EvTransferLimits = std::variant<dt::DC_CPDReqEnergyTransferMode, dt::BPT_DC_CPDReqEnergyTransferMode,
|
||||
dt::AC_CPDReqEnergyTransferMode, dt::BPT_AC_CPDReqEnergyTransferMode>;
|
||||
using EvSEControlMode = std::variant<dt::Dynamic_SEReqControlMode, dt::Scheduled_SEReqControlMode>;
|
||||
|
||||
using AcChargeLoopReq = std::variant<AcReqControlMode, dt::DisplayParameters, MeterInfoRequested>;
|
||||
using AcLimits = std::variant<dt::AC_CPDReqEnergyTransferMode, dt::BPT_AC_CPDReqEnergyTransferMode>;
|
||||
|
||||
struct Callbacks {
|
||||
std::function<void(Signal)> signal;
|
||||
std::function<void(float)> dc_pre_charge_target_voltage;
|
||||
std::function<void(const DcChargeLoopReq&)> dc_charge_loop_req;
|
||||
std::function<void(const DcMaximumLimits&)> dc_max_limits;
|
||||
std::function<void(const AcChargeLoopReq&)> ac_charge_loop_req;
|
||||
std::function<void(const message_20::Type&)> v2g_message;
|
||||
std::function<void(const std::string&)> evccid;
|
||||
std::function<void(const std::string&)> selected_protocol;
|
||||
|
||||
std::function<void(const dt::ServiceCategory&, const std::optional<dt::AcConnector>&, const dt::ControlMode&,
|
||||
const dt::MobilityNeedsMode&, const EvseTransferLimits&, const EvTransferLimits&,
|
||||
const EvSEControlMode&, const std::vector<message_20::datatypes::ServiceCategory>&)>
|
||||
notify_ev_charging_needs;
|
||||
std::function<void(const d20::SelectedServiceParameters&)> selected_service_parameters;
|
||||
std::function<void(const d20::EVInformation&)> ev_information;
|
||||
std::function<std::optional<dt::ServiceParameterList>(uint16_t)> get_vas_parameters;
|
||||
std::function<void(const dt::VasSelectedServiceList&)> selected_vas_services;
|
||||
std::function<void(const AcLimits&)> ac_limits;
|
||||
std::function<void(const std::string&, const std::string&)> ev_termination;
|
||||
};
|
||||
|
||||
} // namespace feedback
|
||||
|
||||
class Feedback {
|
||||
public:
|
||||
Feedback(feedback::Callbacks);
|
||||
|
||||
void signal(feedback::Signal) const;
|
||||
void dc_pre_charge_target_voltage(float) const;
|
||||
void dc_charge_loop_req(const feedback::DcChargeLoopReq&) const;
|
||||
void dc_max_limits(const feedback::DcMaximumLimits&) const;
|
||||
void ac_charge_loop_req(const feedback::AcChargeLoopReq&) const;
|
||||
void v2g_message(const message_20::Type&) const;
|
||||
void evcc_id(const std::string&) const;
|
||||
void selected_protocol(const std::string&) const;
|
||||
|
||||
void notify_ev_charging_needs(const dt::ServiceCategory&, const std::optional<dt::AcConnector>&,
|
||||
const dt::ControlMode&, const dt::MobilityNeedsMode&,
|
||||
const feedback::EvseTransferLimits&, const feedback::EvTransferLimits&,
|
||||
const feedback::EvSEControlMode&,
|
||||
const std::vector<message_20::datatypes::ServiceCategory>&) const;
|
||||
void selected_service_parameters(const d20::SelectedServiceParameters&) const;
|
||||
void ev_information(const d20::EVInformation&) const;
|
||||
std::optional<dt::ServiceParameterList> get_vas_parameters(uint16_t) const;
|
||||
void selected_vas_services(const dt::VasSelectedServiceList&) const;
|
||||
void ac_limits(const feedback::AcLimits&) const;
|
||||
void ev_termination(const std::string&, const std::string&) const;
|
||||
|
||||
private:
|
||||
feedback::Callbacks callbacks;
|
||||
};
|
||||
|
||||
} // namespace iso15118::session
|
||||
@@ -0,0 +1,81 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include <iso15118/config.hpp>
|
||||
|
||||
#include <everest/util/fsm/fsm.hpp>
|
||||
#include <iso15118/d20/config.hpp>
|
||||
#include <iso15118/d20/context.hpp>
|
||||
#include <iso15118/d20/control_event_queue.hpp>
|
||||
#include <iso15118/d20/states.hpp>
|
||||
|
||||
#include <iso15118/io/connection_abstract.hpp>
|
||||
#include <iso15118/io/poll_manager.hpp>
|
||||
#include <iso15118/io/sdp_packet.hpp>
|
||||
#include <iso15118/io/time.hpp>
|
||||
|
||||
#include <iso15118/session/feedback.hpp>
|
||||
#include <iso15118/session/logger.hpp>
|
||||
|
||||
#include <iso15118/d20/timeout.hpp>
|
||||
|
||||
namespace iso15118 {
|
||||
|
||||
struct SessionState {
|
||||
bool connected{false};
|
||||
bool new_data{false};
|
||||
bool fsm_needs_call{false};
|
||||
};
|
||||
|
||||
class Session {
|
||||
public:
|
||||
Session(std::unique_ptr<io::IConnection>, d20::SessionConfig, const session::feedback::Callbacks&,
|
||||
std::optional<d20::PauseContext>&);
|
||||
~Session();
|
||||
|
||||
TimePoint const& poll();
|
||||
void push_control_event(const d20::ControlEvent&);
|
||||
|
||||
bool is_finished() const {
|
||||
return (ctx.session_stopped or ctx.session_paused) and not message_exchange.has_response();
|
||||
}
|
||||
|
||||
void close();
|
||||
|
||||
private:
|
||||
std::unique_ptr<io::IConnection> connection;
|
||||
session::SessionLogger log;
|
||||
|
||||
SessionState state;
|
||||
// input buffer
|
||||
io::SdpPacket packet;
|
||||
|
||||
// output buffer
|
||||
uint8_t response_buffer[1028];
|
||||
|
||||
d20::MessageExchange message_exchange{{response_buffer + io::SdpPacket::V2GTP_HEADER_SIZE,
|
||||
sizeof(response_buffer) - io::SdpPacket::V2GTP_HEADER_SIZE}};
|
||||
|
||||
// control event buffer
|
||||
d20::ControlEventQueue control_event_queue;
|
||||
std::optional<d20::ControlEvent> active_control_event{std::nullopt};
|
||||
|
||||
d20::Context ctx;
|
||||
|
||||
fsm::v2::FSM<d20::StateBase> fsm;
|
||||
|
||||
TimePoint next_session_event;
|
||||
|
||||
d20::Timeouts timeouts;
|
||||
|
||||
void handle_connection_event(io::ConnectionEvent event);
|
||||
void send_response();
|
||||
std::optional<TimePoint> last_response_tx_time; // timestamp of the last response message sent
|
||||
std::optional<TimePoint> response_send_after; // time point when the next response message can be sent
|
||||
};
|
||||
|
||||
} // namespace iso15118
|
||||
@@ -0,0 +1,57 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
namespace iso15118::session {
|
||||
|
||||
namespace logging {
|
||||
|
||||
using TimePoint = std::chrono::time_point<std::chrono::system_clock>;
|
||||
|
||||
struct SimpleEvent {
|
||||
TimePoint time_point;
|
||||
std::string info;
|
||||
};
|
||||
|
||||
enum class ExiMessageDirection {
|
||||
FROM_EV,
|
||||
TO_EV,
|
||||
};
|
||||
struct ExiMessageEvent {
|
||||
TimePoint time_point;
|
||||
uint16_t payload_type;
|
||||
uint8_t const* data;
|
||||
size_t len;
|
||||
ExiMessageDirection direction;
|
||||
};
|
||||
|
||||
using Event = std::variant<SimpleEvent, ExiMessageEvent>;
|
||||
|
||||
using Callback = std::function<void(std::size_t id, const Event&)>;
|
||||
|
||||
void set_session_log_callback(const Callback&);
|
||||
|
||||
} // namespace logging
|
||||
|
||||
class SessionLogger {
|
||||
public:
|
||||
SessionLogger(void*);
|
||||
void enter_state(const std::string& new_state);
|
||||
void event(const std::string& info) const;
|
||||
void exi(uint16_t payload_type, uint8_t const* data, size_t len, logging::ExiMessageDirection direction) const;
|
||||
|
||||
void operator()(const std::string&) const;
|
||||
void operator()(const char* format, ...) const;
|
||||
|
||||
private:
|
||||
std::uintptr_t id;
|
||||
std::string last_state_name;
|
||||
};
|
||||
|
||||
} // namespace iso15118::session
|
||||
@@ -0,0 +1,72 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "config.hpp"
|
||||
#include <iso15118/d20/config.hpp>
|
||||
#include <iso15118/d20/control_event.hpp>
|
||||
#include <iso15118/d20/limits.hpp>
|
||||
#include <iso15118/io/poll_manager.hpp>
|
||||
#include <iso15118/io/sdp_server.hpp>
|
||||
#include <iso15118/io/time.hpp>
|
||||
#include <iso15118/message/common_types.hpp>
|
||||
#include <iso15118/session/feedback.hpp>
|
||||
#include <iso15118/session/iso.hpp>
|
||||
|
||||
namespace iso15118 {
|
||||
|
||||
struct TbdConfig {
|
||||
config::SSLConfig ssl{config::CertificateBackend::EVEREST_LAYOUT, {}, {}, {}, {}, {}, {}};
|
||||
std::string interface_name;
|
||||
config::TlsNegotiationStrategy tls_negotiation_strategy{config::TlsNegotiationStrategy::ACCEPT_CLIENT_OFFER};
|
||||
bool enable_sdp_server{true};
|
||||
};
|
||||
|
||||
class TbdController {
|
||||
public:
|
||||
TbdController(TbdConfig, session::feedback::Callbacks, d20::EvseSetupConfig);
|
||||
|
||||
void loop();
|
||||
|
||||
void send_control_event(const d20::ControlEvent&);
|
||||
|
||||
void update_authorization_services(const std::vector<message_20::datatypes::Authorization>& services,
|
||||
bool cert_install_service);
|
||||
void update_dc_limits(const d20::DcTransferLimits&);
|
||||
void update_powersupply_limits(const d20::DcTransferLimits&);
|
||||
void update_energy_modes(const std::vector<message_20::datatypes::ServiceCategory>&);
|
||||
void update_ac_limits(const d20::AcTransferLimits&);
|
||||
|
||||
void update_supported_vas_services(const std::vector<uint16_t>& vas_services);
|
||||
|
||||
void set_dlink_ready(bool ready);
|
||||
|
||||
private:
|
||||
io::PollManager poll_manager;
|
||||
std::unique_ptr<io::SdpServer> sdp_server;
|
||||
|
||||
std::unique_ptr<Session> session;
|
||||
|
||||
// callbacks for sdp server
|
||||
void handle_sdp_server_input();
|
||||
|
||||
const TbdConfig config;
|
||||
const session::feedback::Callbacks callbacks;
|
||||
|
||||
d20::EvseSetupConfig evse_setup;
|
||||
|
||||
std::string interface_name;
|
||||
|
||||
std::optional<d20::PauseContext> pause_ctx{std::nullopt};
|
||||
|
||||
static constexpr uint32_t V2G_COMMUNICATION_SETUP_TIMEOUT_MS{18000};
|
||||
std::optional<Timeout> communication_setup_timeout;
|
||||
};
|
||||
|
||||
} // namespace iso15118
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user