From 37a7f84073ca491a38afea6bb25e80a236243b4b Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Sat, 16 Sep 2023 15:39:55 -0700
Subject: [PATCH 01/56] update gitignore
---
.gitignore | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/.gitignore b/.gitignore
index 1eea496..2b53068 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,4 +7,6 @@ corpus
*.profdata
*.profraw
.gdb_history
-fuzzer
\ No newline at end of file
+fuzzer
+*.o
+.vscode
\ No newline at end of file
From 41cd85d2abb85bd041677d2afa763842b23ebde3 Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Sat, 21 Oct 2023 22:00:37 -0700
Subject: [PATCH 02/56] refactor transport layer
---
BUILD | 31 ++-
README.md | 4 +
WORKSPACE | 17 ++
examples/client.c | 8 +-
examples/isotp-c_on_socketcan.c | 6 +-
examples/server.c | 6 +-
examples/uds_params.h | 4 +-
iso14229.c | 83 +++++--
iso14229.h | 68 ++++--
test/BUILD | 17 ++
test/env.c | 37 ++++
test/env.h | 19 ++
test/test.c | 0
test/test.h | 6 +
test/test_server_0x10_diag_sess_ctrl.c | 46 ++++
test_iso14229.c | 290 ++++++++++++++++---------
tp_mock.c | 135 ++++++++++++
tp_mock.h | 28 +++
18 files changed, 654 insertions(+), 151 deletions(-)
create mode 100644 test/BUILD
create mode 100644 test/env.c
create mode 100644 test/env.h
create mode 100644 test/test.c
create mode 100644 test/test.h
create mode 100644 test/test_server_0x10_diag_sess_ctrl.c
create mode 100644 tp_mock.c
create mode 100644 tp_mock.h
diff --git a/BUILD b/BUILD
index 0d4ddb1..b9c795f 100644
--- a/BUILD
+++ b/BUILD
@@ -1,5 +1,11 @@
package(default_visibility = ["//visibility:public"])
+
+config_setting(
+ name = "tp",
+ values = {"tp": "mock,isotp-c-vcan,isotp-c-udp"},
+)
+
filegroup(
name = "srcs",
srcs = [
@@ -15,6 +21,9 @@ cc_test(
":srcs",
"test_iso14229.c",
],
+ deps = [
+ ":tp_mock",
+ ],
copts=[
"-Wall",
"-Wextra",
@@ -26,14 +35,16 @@ cc_test(
"UDS_TP=UDS_TP_CUSTOM",
"UDS_CUSTOM_MILLIS",
],
+ size = "small",
)
cc_test(
- name = "test_server_bufferedwriter",
+ name = "test_bufferedwriter",
srcs = [
- "udsserverbufferedwriter.h",
- "test_udsserverbufferedwriter.c",
+ "iso14229serverbufferedwriter.h",
+ "test_iso14229serverbufferedwriter.c",
],
+ size = "small",
)
@@ -53,3 +64,17 @@ cc_library(
srcs=[":isotp_c_srcs"],
copts=["-Wno-unused-parameter"],
)
+
+cc_library(
+ name="iso14229",
+ srcs=[":srcs"],
+)
+
+cc_library(
+ name="tp_mock",
+ srcs=[
+ "tp_mock.c",
+ "tp_mock.h",
+ "iso14229.h",
+ ],
+)
\ No newline at end of file
diff --git a/README.md b/README.md
index 9033bd0..7ce9639 100644
--- a/README.md
+++ b/README.md
@@ -408,6 +408,10 @@ MIT
- added `UDS_SRV_EVT_DoScheduledReset`
- improve client error handling
+## 0.7.0
+- breaking API changes:
+ - rename `phys_send_id`, `phys_recv_id`, `func_send_id`, and `func_recv_id` to be consistent with the standard. Now mandatory for all UDSServerConfig_t and UDSClientConfig_t regardless of transport layer implementation
+
---
# Design Docs
diff --git a/WORKSPACE b/WORKSPACE
index e69de29..6d75c10 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -0,0 +1,17 @@
+
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
+
+# Hedron's Compile Commands Extractor for Bazel
+# https://github.com/hedronvision/bazel-compile-commands-extractor
+http_archive(
+ name = "hedron_compile_commands",
+
+ # Replace the commit hash in both places (below) with the latest, rather than using the stale one here.
+ # Even better, set up Renovate and let it do the work for you (see "Suggestion: Updates" in the README).
+ url = "https://github.com/hedronvision/bazel-compile-commands-extractor/archive/e16062717d9b098c3c2ac95717d2b3e661c50608.tar.gz",
+ strip_prefix = "bazel-compile-commands-extractor-e16062717d9b098c3c2ac95717d2b3e661c50608",
+ # When you first run this tool, it'll recommend a sha256 hash to put here with a message like: "DEBUG: Rule 'hedron_compile_commands' indicated that a canonical reproducible form can be obtained by modifying arguments sha256 = ..."
+)
+load("@hedron_compile_commands//:workspace_setup.bzl", "hedron_compile_commands_setup")
+hedron_compile_commands_setup()
\ No newline at end of file
diff --git a/examples/client.c b/examples/client.c
index e9aff27..5388c18 100644
--- a/examples/client.c
+++ b/examples/client.c
@@ -115,9 +115,9 @@ int main(int ac, char **av) {
#if UDS_TP == UDS_TP_ISOTP_SOCKET
.if_name = "vcan0",
#endif
- .phys_recv_id = 0x7E8,
- .phys_send_id = 0x7E0,
- .func_send_id = 0x7DF,
+ .source_addr = 0x7E8,
+ .target_addr = 0x7E0,
+ .target_addr_func = 0x7DF,
};
if (UDSClientInit(&client, &cfg)) {
@@ -132,7 +132,7 @@ int main(int ac, char **av) {
do {
running = UDSClientPoll(&client);
#if UDS_TP == UDS_TP_ISOTP_C
- SocketCANRecv((UDSTpIsoTpC_t *)client.tp, cfg.phys_recv_id);
+ SocketCANRecv((UDSTpIsoTpC_t *)client.tp, cfg.source_addr);
#endif
SleepMillis(1);
} while (running);
diff --git a/examples/isotp-c_on_socketcan.c b/examples/isotp-c_on_socketcan.c
index e65e903..6573130 100644
--- a/examples/isotp-c_on_socketcan.c
+++ b/examples/isotp-c_on_socketcan.c
@@ -60,7 +60,7 @@ static void printhex(const uint8_t *addr, int len) {
printf("\n");
}
-void SocketCANRecv(UDSTpIsoTpC_t *tp, int phys_recv_id, int func_recv_id) {
+void SocketCANRecv(UDSTpIsoTpC_t *tp, int source_addr, int source_addr_func) {
assert(tp);
SetupOnce();
struct can_frame frame = {0};
@@ -76,11 +76,11 @@ void SocketCANRecv(UDSTpIsoTpC_t *tp, int phys_recv_id, int func_recv_id) {
} else if (nbytes == 0) {
break;
} else {
- if (frame.can_id == phys_recv_id) {
+ if (frame.can_id == source_addr) {
UDS_DBG_PRINT("phys recvd can\n");
UDS_DBG_PRINTHEX(frame.data, frame.can_dlc);
isotp_on_can_message(&tp->phys_link, frame.data, frame.can_dlc);
- } else if (frame.can_id == func_recv_id) {
+ } else if (frame.can_id == source_addr_func) {
UDS_DBG_PRINT("func recvd can\n");
UDS_DBG_PRINTHEX(frame.data, frame.can_dlc);
isotp_on_can_message(&tp->func_link, frame.data, frame.can_dlc);
diff --git a/examples/server.c b/examples/server.c
index 8f16127..4319df4 100644
--- a/examples/server.c
+++ b/examples/server.c
@@ -21,8 +21,8 @@ static const UDSServerConfig_t cfg = {
#if UDS_TP == UDS_TP_ISOTP_SOCKET
.if_name = "vcan0",
#endif
- .phys_send_id = SERVER_SEND_ID,
- .phys_recv_id = SERVER_PHYS_RECV_ID,
+ .target_addr = SERVER_FUNC_ID,
+ .source_addr = SERVER_source_addr,
.func_recv_id = SERVER_FUNC_RECV_ID,
};
static bool serverWantsExit = false;
@@ -166,7 +166,7 @@ int main(int ac, char **av) {
while (!serverWantsExit) {
UDSServerPoll(&srv);
#if UDS_TP == UDS_TP_ISOTP_C
- SocketCANRecv((UDSTpIsoTpC_t *)srv.tp, cfg.phys_recv_id);
+ SocketCANRecv((UDSTpIsoTpC_t *)srv.tp, cfg.source_addr);
#endif
SleepMillis(1);
}
diff --git a/examples/uds_params.h b/examples/uds_params.h
index ccc577b..9cf320c 100644
--- a/examples/uds_params.h
+++ b/examples/uds_params.h
@@ -18,13 +18,13 @@
* -|--0x7E1->| Server 2
* |<-0x7E9--|
*
- * Client has one link that strictly sends functional requests to 0x7DF.
+ * Client has one link that strictly sends functional requests to 0x7DD.
* Functional responses are received on the other links
*
*/
// 服务器响应地址
-#define SERVER_SEND_ID (0x7E8) /* server sends */
+#define SERVER_FUNC_ID (0x7E8) /* server sends */
// 服务器物理接收地址 (1:1)
#define SERVER_PHYS_RECV_ID (0x7E0) /* server listens for physically (1:1) addressed messages */
// 服务器功能接收地址 (1:n)
diff --git a/iso14229.c b/iso14229.c
index e430b6c..6c0cfd6 100644
--- a/iso14229.c
+++ b/iso14229.c
@@ -1151,7 +1151,15 @@ static void ProcessLink(UDSServer_t *self, const UDSTpAddr_t ta_type) {
}
if (self->send_size) {
- int result = self->tp->send(self->tp, self->send_buf, self->send_size, ta_type);
+ UDSSDU_t msg = {
+ .A_Mtype = UDS_A_MTYPE_DIAG,
+ .A_SA = self->source_addr,
+ .A_TA = self->target_addr,
+ .A_TA_Type = UDS_A_TA_TYPE_PHYSICAL, // server responses are always physical
+ .A_Length = self->send_size,
+ .A_Data = self->send_buf,
+ };
+ int result = self->tp->send(self->tp, &msg);
assert(result == self->send_size); // how should it be handled if send fails?
}
}
@@ -1170,6 +1178,9 @@ static void ProcessLink(UDSServer_t *self, const UDSTpAddr_t ta_type) {
UDSErr_t UDSServerInit(UDSServer_t *self, const UDSServerConfig_t *cfg) {
assert(self);
assert(cfg);
+ assert(cfg->source_addr != cfg->target_addr);
+ assert(cfg->target_addr != cfg->source_addr_func);
+ assert(cfg->source_addr_func != cfg->source_addr);
memset(self, 0, sizeof(UDSServer_t));
self->recv_buf_size = sizeof(self->recv_buf);
self->send_buf_size = sizeof(self->send_buf);
@@ -1178,6 +1189,9 @@ UDSErr_t UDSServerInit(UDSServer_t *self, const UDSServerConfig_t *cfg) {
self->s3_ms = UDS_SERVER_DEFAULT_S3_MS;
self->fn = cfg->fn;
self->sessionType = kDefaultSession;
+ self->source_addr = cfg->source_addr;
+ self->target_addr = cfg->target_addr;
+ self->source_addr_func = cfg->source_addr_func;
// Initialize p2_timer to an already past time, otherwise the server's
// response to incoming messages will be delayed.
@@ -1193,11 +1207,11 @@ UDSErr_t UDSServerInit(UDSServer_t *self, const UDSServerConfig_t *cfg) {
assert(cfg->tp->poll);
self->tp = cfg->tp;
#elif UDS_TP == UDS_TP_ISOTP_C
- assert(cfg->phys_send_id != cfg->func_recv_id && cfg->func_recv_id != cfg->phys_recv_id);
+ assert(cfg->target_addr != cfg->source_addr_func && cfg->source_addr_func != cfg->source_addr);
UDSTpIsoTpC_t *tp = &self->tp_impl;
- isotp_init_link(&tp->phys_link, cfg->phys_send_id, self->send_buf, self->send_buf_size,
+ isotp_init_link(&tp->phys_link, cfg->target_addr, self->send_buf, self->send_buf_size,
self->recv_buf, self->recv_buf_size);
- isotp_init_link(&tp->func_link, cfg->phys_send_id, tp->func_send_buf, sizeof(tp->func_send_buf),
+ isotp_init_link(&tp->func_link, cfg->target_addr, tp->func_send_buf, sizeof(tp->func_send_buf),
tp->func_recv_buf, sizeof(tp->func_recv_buf));
self->tp = (UDSTpHandle_t *)tp;
self->tp->poll = tp_poll;
@@ -1205,8 +1219,8 @@ UDSErr_t UDSServerInit(UDSServer_t *self, const UDSServerConfig_t *cfg) {
self->tp->recv = tp_recv;
#elif UDS_TP == UDS_TP_ISOTP_SOCKET
self->tp = (UDSTpHandle_t *)&self->tp_impl;
- if (LinuxSockTpOpen(self->tp, cfg->if_name, cfg->phys_recv_id, cfg->phys_send_id,
- cfg->func_recv_id, cfg->phys_send_id)) {
+ if (LinuxSockTpOpen(self->tp, cfg->if_name, cfg->source_addr, cfg->target_addr,
+ cfg->source_addr_func, cfg->target_addr)) {
return UDS_ERR;
}
#endif
@@ -1253,12 +1267,23 @@ void UDSServerPoll(UDSServer_t *self) {
// new data may be processed only after p2 has elapsed
int size = 0;
- UDSTpAddr_t ta_type = kTpAddrTypePhysical;
if (UDSTimeAfter(UDSMillis(), self->p2_timer)) {
- size = self->tp->recv(self->tp, self->recv_buf, self->recv_buf_size, &ta_type);
+ UDSSDU_t msg = {
+ .A_DataBufSize = self->recv_buf_size,
+ .A_Data = self->recv_buf,
+ };
+ size = self->tp->recv(self->tp, &msg);
if (size > 0) {
+ if (msg.A_TA == self->source_addr) {
+ msg.A_TA_Type = UDS_A_TA_TYPE_PHYSICAL;
+ } else if (msg.A_TA == self->source_addr_func) {
+ msg.A_TA_Type = UDS_A_TA_TYPE_FUNCTIONAL;
+ } else {
+ UDS_DBG_PRINT("received message from unknown source address %x\n", msg.A_TA);
+ return;
+ }
self->recv_size = size;
- ProcessLink(self, ta_type);
+ ProcessLink(self, msg.A_TA_Type);
self->p2_timer = UDSMillis() + self->p2_ms;
} else if (size == 0) {
;
@@ -1286,14 +1311,21 @@ static void clearRequestContext(UDSClient_t *client) {
UDSErr_t UDSClientInit(UDSClient_t *client, const UDSClientConfig_t *cfg) {
assert(client);
assert(cfg);
+ assert(cfg->target_addr != cfg->source_addr);
+ assert(cfg->source_addr != cfg->target_addr_func);
+ assert(cfg->target_addr_func != cfg->target_addr);
memset(client, 0, sizeof(*client));
client->p2_ms = UDS_CLIENT_DEFAULT_P2_MS;
client->p2_star_ms = UDS_CLIENT_DEFAULT_P2_STAR_MS;
client->recv_buf_size = sizeof(client->recv_buf);
client->send_buf_size = sizeof(client->send_buf);
+ client->source_addr = cfg->source_addr;
+ client->target_addr = cfg->target_addr;
+ client->target_addr_func = cfg->target_addr_func;
if (client->p2_star_ms < client->p2_ms) {
+ fprintf(stderr, "p2_star_ms must be >= p2_ms\n");
client->p2_star_ms = client->p2_ms;
}
@@ -1304,11 +1336,11 @@ UDSErr_t UDSClientInit(UDSClient_t *client, const UDSClientConfig_t *cfg) {
assert(cfg->tp->poll);
client->tp = cfg->tp;
#elif UDS_TP == UDS_TP_ISOTP_C
- assert(cfg->phys_recv_id != cfg->func_send_id && cfg->func_send_id != cfg->phys_send_id);
+ assert(cfg->source_addr != cfg->target_addr_func && cfg->target_addr_func != cfg->target_addr);
UDSTpIsoTpC_t *tp = (UDSTpIsoTpC_t *)&client->tp_impl;
- isotp_init_link(&tp->phys_link, cfg->phys_send_id, client->send_buf, client->send_buf_size,
+ isotp_init_link(&tp->phys_link, cfg->target_addr, client->send_buf, client->send_buf_size,
client->recv_buf, client->recv_buf_size);
- isotp_init_link(&tp->func_link, cfg->func_send_id, tp->func_send_buf, sizeof(tp->func_send_buf),
+ isotp_init_link(&tp->func_link, cfg->target_addr_func, tp->func_send_buf, sizeof(tp->func_send_buf),
tp->func_recv_buf, sizeof(tp->func_recv_buf));
client->tp = (UDSTpHandle_t *)tp;
client->tp->poll = tp_poll;
@@ -1316,8 +1348,8 @@ UDSErr_t UDSClientInit(UDSClient_t *client, const UDSClientConfig_t *cfg) {
client->tp->recv = tp_recv;
#elif UDS_TP == UDS_TP_ISOTP_SOCKET
client->tp = (UDSTpHandle_t *)&client->tp_impl;
- if (LinuxSockTpOpen(client->tp, cfg->if_name, cfg->phys_recv_id, cfg->phys_send_id,
- cfg->phys_recv_id, cfg->func_send_id)) {
+ if (LinuxSockTpOpen(client->tp, cfg->if_name, cfg->source_addr, cfg->target_addr,
+ cfg->source_addr, cfg->target_addr_func)) {
return UDS_ERR;
}
assert(client->tp);
@@ -1445,7 +1477,15 @@ static void PollLowLevel(UDSClient_t *client) {
UDSTpAddr_t ta_type =
client->_options_copy & UDS_FUNCTIONAL ? kTpAddrTypeFunctional : kTpAddrTypePhysical;
ssize_t ret = 0;
- ret = client->tp->send(client->tp, client->send_buf, client->send_size, ta_type);
+ UDSSDU_t msg = {
+ .A_Mtype = UDS_A_MTYPE_DIAG,
+ .A_SA = client->source_addr,
+ .A_TA = ta_type == kTpAddrTypePhysical ? client->target_addr : client->target_addr_func,
+ .A_TA_Type = ta_type,
+ .A_Length = client->send_size,
+ .A_Data = client->send_buf,
+ };
+ ret = client->tp->send(client->tp, &msg);
if (ret < 0) {
client->err = UDS_ERR_TPORT;
@@ -1480,9 +1520,13 @@ static void PollLowLevel(UDSClient_t *client) {
}
case kRequestStateAwaitResponse: {
UDSTpAddr_t ta_type = kTpAddrTypePhysical;
+ UDSSDU_t msg = {
+ .A_DataBufSize = client->recv_buf_size,
+ .A_Data = client->recv_buf,
+ };
ssize_t ret =
- client->tp->recv(client->tp, client->recv_buf, client->recv_buf_size, &ta_type);
-
+ client->tp->recv(client->tp, &msg);
+
if (kTpAddrTypeFunctional == ta_type) {
break;
}
@@ -2027,6 +2071,11 @@ bool UDSClientPoll(UDSClient_t *client) {
}
}
+void UDSClientPoll2(UDSClient_t *client, int (*fn)(UDSClient_t *client, UDSEvent_t evt, void *ev_data, void *fn_data), void *fn_data) {
+ UDSClientPoll(client);
+
+}
+
UDSSeqState_t UDSClientAwaitIdle(UDSClient_t *client) {
if (client->err) {
return UDSSeqStateDone;
diff --git a/iso14229.h b/iso14229.h
index 1323c96..c0e38af 100644
--- a/iso14229.h
+++ b/iso14229.h
@@ -18,9 +18,9 @@ extern "C" {
#define UDS_ARCH_UNIX 1
#define UDS_ARCH_WINDOWS 2
-#define UDS_TP_CUSTOM 0
-#define UDS_TP_ISOTP_C 1
-#define UDS_TP_ISOTP_SOCKET 2
+#define UDS_TP_CUSTOM 0 // bring your own transport layer
+#define UDS_TP_ISOTP_C 1 // use isotp-c
+#define UDS_TP_ISOTP_SOCKET 2 // use linux ISO-TP socket
#if !defined(UDS_ARCH)
#if defined(__unix__) || defined(__APPLE__)
@@ -240,8 +240,34 @@ enum UDSTpStatusFlags {
typedef uint32_t UDSTpStatus_t;
+typedef enum {
+ UDS_A_MTYPE_DIAG = 0,
+ UDS_A_MTYPE_REMOTE_DIAG,
+ UDS_A_MTYPE_SECURE_DIAG,
+ UDS_A_MTYPE_SECURE_REMOTE_DIAG,
+} UDS_A_Mtype_t;
+
+typedef enum {
+ UDS_A_TA_TYPE_PHYSICAL = 0, // unicast (1:1)
+ UDS_A_TA_TYPE_FUNCTIONAL, // multicast
+} UDS_A_TA_Type_t;
+
/**
- * @brief 传输层把柄
+ * @brief Service data unit (SDU) for the transport layer
+ */
+typedef struct {
+ UDS_A_Mtype_t A_Mtype;
+ uint16_t A_SA; // application source address
+ uint16_t A_TA; // application target address
+ UDS_A_TA_Type_t A_TA_Type;
+ uint16_t A_AE; // application layer remote address
+ uint32_t A_Length; // data length
+ uint32_t A_DataBufSize;
+ const uint8_t *A_Data;
+} UDSSDU_t;
+
+/**
+ * @brief Transport Handle is the interface between the UDS application layer and the transport layer.
*/
typedef struct UDSTpHandle {
/**
@@ -256,7 +282,7 @@ typedef struct UDSTpHandle {
* == 0 没有数据
* > 0 接收了、返回值是大小
*/
- ssize_t (*recv)(struct UDSTpHandle *hdl, void *buf, size_t count, UDSTpAddr_t *ta_type);
+ ssize_t (*recv)(struct UDSTpHandle *hdl, UDSSDU_t *msg);
/**
* @brief 发送
* @param hdl: pointer to transport handle
@@ -267,7 +293,7 @@ typedef struct UDSTpHandle {
* < 0 故障
* >= 0 发送成功了
*/
- ssize_t (*send)(struct UDSTpHandle *hdl, const void *buf, size_t count, UDSTpAddr_t ta_type);
+ ssize_t (*send)(struct UDSTpHandle *hdl, UDSSDU_t *msg);
/**
* @brief 轮询
*/
@@ -290,6 +316,7 @@ typedef struct {
} UDSTpLinuxIsoTp_t;
#endif
+
// ========================================================================
// Utility Functions
// ========================================================================
@@ -330,17 +357,14 @@ enum UDSClientRequestState {
typedef uint8_t UDSClientRequestState_t;
typedef struct {
+ uint32_t source_addr;
+ uint32_t target_addr;
+ uint32_t target_addr_func;
#if UDS_TP == UDS_TP_CUSTOM
UDSTpHandle_t *tp;
#elif UDS_TP == UDS_TP_ISOTP_C
- uint32_t phys_recv_id;
- uint32_t phys_send_id;
- uint32_t func_send_id;
#elif UDS_TP == UDS_TP_ISOTP_SOCKET
const char *if_name;
- uint32_t phys_recv_id;
- uint32_t phys_send_id;
- uint32_t func_send_id;
#else
#error "transport undefined"
#endif
@@ -370,6 +394,9 @@ typedef struct UDSClient {
uint16_t send_buf_size;
uint16_t recv_size;
uint16_t send_size;
+ uint32_t source_addr;
+ uint32_t target_addr;
+ uint32_t target_addr_func;
UDSErr_t err;
UDSClientRequestState_t state;
@@ -377,6 +404,7 @@ typedef struct UDSClient {
uint8_t defaultOptions; // enum udsclientoptions
// a copy of the options at the time a request is made
uint8_t _options_copy; // enum udsclientoptions
+ int (*fn)(struct UDSClient *, int, void *, void *);
const UDSClientCallback *cbList; // null-terminated list of callback functions
size_t cbIdx; // index of currently active callback function
@@ -421,6 +449,7 @@ void UDSClientDeInit(UDSClient_t *client);
* @return UDS_CLIENT_IDLE if idle, otherwise UDS_CLIENT_RUNNING
*/
bool UDSClientPoll(UDSClient_t *client);
+void UDSClientPoll2(UDSClient_t *client, int (*fn)(UDSClient_t *client, int evt, void *ev_data, void *fn_data), void *fn_data);
UDSErr_t UDSSendECUReset(UDSClient_t *client, UDSECUReset_t type);
UDSErr_t UDSSendDiagSessCtrl(UDSClient_t *client, enum UDSDiagnosticSessionType mode);
@@ -524,9 +553,12 @@ enum UDSServerEvent {
UDS_SRV_EVT_RequestTransferExit, // UDSRequestTransferExitArgs_t *
UDS_SRV_EVT_SessionTimeout, // NULL
UDS_SRV_EVT_DoScheduledReset, // enum UDSEcuResetType *
+ UDS_EVT_IDLE,
+ UDS_EVT_RESP_RECV,
};
typedef int UDSServerEvent_t;
+typedef UDSServerEvent_t UDSEvent_t;
typedef struct UDSServer {
UDSTpHandle_t *tp;
@@ -537,6 +569,9 @@ typedef struct UDSServer {
uint16_t send_size;
uint16_t recv_buf_size;
uint16_t send_buf_size;
+ uint32_t target_addr;
+ uint32_t source_addr;
+ uint32_t source_addr_func;
/**
* @brief \~chinese 服务器时间参数(毫秒) \~ Server time constants (milliseconds) \~
@@ -595,18 +630,15 @@ typedef struct UDSServer {
} UDSServer_t;
typedef struct {
+ uint32_t target_addr;
+ uint32_t source_addr;
+ uint32_t source_addr_func;
uint8_t (*fn)(UDSServer_t *srv, UDSServerEvent_t event, const void *arg);
#if UDS_TP == UDS_TP_CUSTOM
UDSTpHandle_t *tp;
#elif UDS_TP == UDS_TP_ISOTP_C
- uint32_t phys_send_id;
- uint32_t phys_recv_id;
- uint32_t func_recv_id;
#elif UDS_TP == UDS_TP_ISOTP_SOCKET
const char *if_name;
- uint32_t phys_send_id;
- uint32_t phys_recv_id;
- uint32_t func_recv_id;
#else
#error "transport undefined"
#endif
diff --git a/test/BUILD b/test/BUILD
new file mode 100644
index 0000000..d6b30f4
--- /dev/null
+++ b/test/BUILD
@@ -0,0 +1,17 @@
+cc_library(
+ name = "env",
+ srcs = ["env.c", "env.h"],
+ deps = [
+ "//:iso14229"
+ ]
+)
+
+[
+ cc_test(
+ name=n.split(".c")[0] ,
+ srcs=[n],
+ deps=[":env"],
+ )
+
+ for n in glob(["test_*.c"])
+]
\ No newline at end of file
diff --git a/test/env.c b/test/env.c
new file mode 100644
index 0000000..fae4dd7
--- /dev/null
+++ b/test/env.c
@@ -0,0 +1,37 @@
+#include "test/env.h"
+#include "iso14229.h"
+#include
+#include
+#include
+
+UDSTpHandle_t *Handles[8] = {0};
+unsigned HandleCount = 0;
+
+UDSTpHandle_t *ENV_TpNew() {
+ if (HandleCount >= sizeof(Handles) / sizeof(Handles[0])) {
+ fprintf(stderr, "Too many TP handles\n");
+ return NULL;
+ }
+ UDSTpHandle_t *tp = malloc(sizeof(UDSTpHandle_t));
+ memset(tp, 0, sizeof(UDSTpHandle_t));
+ Handles[HandleCount++] = tp;
+ return tp;
+}
+
+void ENV_Send(UDSSDU_t *msg) {
+ assert(msg);
+ for (unsigned i = 0; i < HandleCount; i++) {
+ UDSTpHandle_t *tp = Handles[i];
+ if (tp == NULL) {
+ continue;
+ }
+ if (tp->)
+ UDSTpSend(tp, msg);
+ }
+ UDSTpHandle_t *tp = msg->A_TP;
+ if (tp == NULL) {
+ tp = ENV_TpNew();
+ msg->A_TP = tp;
+ }
+ UDSTpSend(tp, msg);
+}
\ No newline at end of file
diff --git a/test/env.h b/test/env.h
new file mode 100644
index 0000000..2c828e3
--- /dev/null
+++ b/test/env.h
@@ -0,0 +1,19 @@
+#ifndef ENV_H
+#define ENV_H
+
+#include "iso14229.h"
+#include
+
+UDSTpHandle_t *ENV_TpNew();
+
+
+void ENV_Send(UDSSDU_t *msg);
+
+#define ENV_EXPECT_MSG_WITHIN_MILLIS(msg_ptr, millis) \
+ do { \
+ UDSSDU_t *msg = (msg_ptr); \
+ ENV_ExpectBytesWithinMillis(ENV_TpNew(), msg->A_Data, msg->A_Length, millis); \
+ } while (0)
+
+
+#endif
\ No newline at end of file
diff --git a/test/test.c b/test/test.c
new file mode 100644
index 0000000..e69de29
diff --git a/test/test.h b/test/test.h
new file mode 100644
index 0000000..000f6dd
--- /dev/null
+++ b/test/test.h
@@ -0,0 +1,6 @@
+
+#define TEST_SETUP()
+
+typedef struct {
+
+} TestCtx_t;
diff --git a/test/test_server_0x10_diag_sess_ctrl.c b/test/test_server_0x10_diag_sess_ctrl.c
new file mode 100644
index 0000000..304327f
--- /dev/null
+++ b/test/test_server_0x10_diag_sess_ctrl.c
@@ -0,0 +1,46 @@
+
+
+#include "iso14229.h"
+#include "test/env.h"
+
+uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
+ printf("holy shit\n");
+ return kServiceNotSupported;
+}
+
+int main() {
+ UDSServer_t srv;
+ UDSTpHandle_t *tp = ENV_TpNew();
+ UDSServerInit(&srv, &(UDSServerConfig_t){
+ .fn = fn,
+ .tp = tp,
+ });
+
+ const uint8_t REQ[] = {0x10, 0x02};
+
+ UDSSDU_t req = {
+ .A_Mtype = UDS_A_MTYPE_DIAG,
+ .A_SA = 0x7E0,
+ .A_TA = 0x7E8,
+ .A_TA_Type = UDS_A_TA_TYPE_PHYSICAL,
+ .A_Length = sizeof(REQ),
+ .A_Data = REQ,
+ };
+
+ ENV_Send(&req);
+
+
+ UDSSDU_t resp;
+ ENV_EXPECT_MSG_WITHIN_MILLIS(&resp, 50);
+ const uint8_t EXP_RESP[] = {0x7f, 0x10, 0x11};
+ ASSERT_BYTES_EQUAL(resp.A_Data, EXP_RESP, sizeof(EXP_RESP));
+}
+
+void testServer0x10DiagSessCtrlIsDisabledByDefault() {
+ TEST_SETUP(CLIENT_ONLY);
+ const uint8_t REQ[] = {0x10, 0x02};
+ SEND_TO_SERVER(REQ, kTpAddrTypePhysical);
+ const uint8_t RESP[] = {0x7f, 0x10, 0x11};
+ EXPECT_RESPONSE_WITHIN_MILLIS(RESP, kTpAddrTypePhysical, 50);
+ TEST_TEARDOWN();
+}
diff --git a/test_iso14229.c b/test_iso14229.c
index e7308e2..4c423c6 100644
--- a/test_iso14229.c
+++ b/test_iso14229.c
@@ -6,6 +6,7 @@
#include
#include
#include "iso14229.h"
+#include "tp_mock.h"
#define _ASSERT_INT_COND(a, b, cond) \
{ \
@@ -59,38 +60,76 @@
#define ANSI_BRIGHT_GREEN "\033[92m"
#define ANSI_BRIGHT_MAGENTA "\033[95m"
-#define _TEST_SETUP_SILENT() \
- memset(&ctx, 0, sizeof(ctx)); \
- ctx.func_name = __PRETTY_FUNCTION__; \
- ctx.server_tp = (struct MockTransport){.hdl = {.recv = mock_transport_recv, \
+#define CLIENT_TARGET_ADDR (0x7E0U)
+#define CLIENT_TARGET_ADDR_FUNC (0x7DFU)
+#define CLIENT_SOURCE_ADDR (0x7E8U)
+
+#define SERVER_TARGET_ADDR (0x7E8U)
+#define SERVER_SOURCE_ADDR (0x7E0U)
+#define SERVER_SOURCE_ADDR_FUNC (0x7DFU)
+
+/*
+ ctx.server_tp = (struct mocktransport){.hdl = {.recv = mock_transport_recv, \
.send = mock_transport_send, \
.poll = mock_transport_poll}, \
.tag = "server"}; \
- ctx.client_tp = (struct MockTransport){.hdl = {.recv = mock_transport_recv, \
+ ctx.client_tp = (struct mocktransport){.hdl = {.recv = mock_transport_recv, \
.send = mock_transport_send, \
.poll = mock_transport_poll}, \
.tag = "client"}; \
UDSClientInit(&ctx.client, &(UDSClientConfig_t){.tp = &ctx.client_tp.hdl}); \
UDSServerInit(&ctx.server, &(UDSServerConfig_t){.tp = &ctx.server_tp.hdl});
+ */
-#define TEST_SETUP() \
- _TEST_SETUP_SILENT(); \
- printf("%s\n", ctx.func_name);
+#define SERVER_ONLY 0
+#define CLIENT_ONLY 1
-struct hmm {
- const char *tag;
-};
+#define _TEST_SETUP_SILENT(test_type, param_str) \
+ memset(&ctx, 0, sizeof(ctx)); \
+ ctx.func_name = __PRETTY_FUNCTION__; \
+ if (SERVER_ONLY == test_type) { \
+ UDSServerInit(&ctx.server, &(UDSServerConfig_t){ \
+ .tp = TPMockCreate("server"), \
+ .source_addr = SERVER_SOURCE_ADDR, \
+ .target_addr = SERVER_TARGET_ADDR, \
+ .source_addr_func = SERVER_SOURCE_ADDR_FUNC, \
+ }); \
+ ctx.mock_tp = TPMockCreate("mock_client"); \
+ } \
+ if (CLIENT_ONLY == test_type) { \
+ UDSClientInit(&ctx.client, &(UDSClientConfig_t){ \
+ .tp = TPMockCreate("client"), \
+ .target_addr = CLIENT_TARGET_ADDR, \
+ .source_addr = CLIENT_SOURCE_ADDR, \
+ .target_addr_func = CLIENT_TARGET_ADDR_FUNC, \
+ }); \
+ ctx.mock_tp = TPMockCreate("mock_server"); \
+ } \
+ char logfilename[256] = {0}; \
+ snprintf(logfilename, sizeof(logfilename), "%s%s.log", ctx.func_name, param_str); \
+ TPMockLogToFile(logfilename);
+
+#define TEST_SETUP(test_type) \
+ _TEST_SETUP_SILENT(test_type, ""); \
+ printf("%s\n", ctx.func_name);
-#define TEST_SETUP_PARAMETRIZED(params_list) \
+#define TEST_SETUP_PARAMETRIZED(test_type, params_list) \
for (size_t i = 0; i < sizeof(params_list) / sizeof(params_list[0]); i++) { \
- _TEST_SETUP_SILENT(); \
- printf("%s [p:%ld] %s\n", ctx.func_name, i, ((struct hmm *)(&(params_list[i])))->tag);
+ char _param_str[128]; \
+ snprintf(_param_str, sizeof(_param_str), "%s_p_%ld_%s", ctx.func_name, i, (*(char **)(&(params_list[i])))); \
+ _TEST_SETUP_SILENT(test_type, _param_str); \
+ printf("%s\n", _param_str);
#define TEST_TEARDOWN_PARAMETRIZED() \
+ TPMockReset(); \
printf(ANSI_BOLD "OK [p:%ld]\n" ANSI_RESET, i); \
}
-#define TEST_TEARDOWN() printf(ANSI_BOLD "OK\n" ANSI_RESET);
+#define TEST_TEARDOWN() \
+{ \
+ TPMockReset(); \
+ printf(ANSI_BOLD "OK\n" ANSI_RESET); \
+}
// TODO: parameterize and fuzz this
#define DEFAULT_ISOTP_BUFSIZE (2048U)
@@ -114,58 +153,53 @@ static void printhex(const uint8_t *addr, int len) {
printf("\n");
}
-#define SERVER_ONLY (0U)
-#define CLIENT_ONLY (1U)
-#define SERVER_CLIENT (2U)
-
-static ssize_t mock_transport_recv(UDSTpHandle_t *hdl, void *buf, size_t bufsize,
- UDSTpAddr_t *ta_type) {
- assert(hdl);
- struct MockTransport *tp = (struct MockTransport *)hdl;
- size_t size = tp->recv_size;
-
- if (bufsize < size) {
- return -ENOBUFS;
- }
-
- if (size) {
- memmove(buf, tp->recv_buf, size);
- tp->recv_size = 0;
- memset(tp->recv_buf, 0, sizeof(tp->recv_buf));
- printf(ANSI_BRIGHT_MAGENTA "<-%s_tp_recv-%04d- [%02ld] ", tp->tag, UDSMillis(), size);
- printhex(buf, size);
- printf(ANSI_RESET);
- }
- return size;
-}
-
-static ssize_t mock_transport_send(UDSTpHandle_t *hdl, const void *buf, size_t count,
- UDSTpAddr_t ta_type) {
- assert(hdl);
- struct MockTransport *tp = (struct MockTransport *)hdl;
- printf(ANSI_BRIGHT_GREEN "--%s_tp_send-%04d->[%02ld] ", tp->tag, UDSMillis(), count);
- printhex(buf, count);
- printf(ANSI_RESET);
- assert(count); // why send zero?
- memmove(tp->send_buf, buf, count);
- tp->send_size = count;
- return count;
-}
-
-static UDSTpStatus_t mock_transport_poll(UDSTpHandle_t *hdl) {
- assert(hdl);
- struct MockTransport *tp = (struct MockTransport *)hdl;
- return tp->status;
-}
+// static ssize_t mock_transport_recv(UDSTpHandle_t *hdl, UDSSDU_t *msg) {
+// assert(hdl);
+// struct MockTransport *tp = (struct MockTransport *)hdl;
+// size_t size = tp->recv_size;
+
+// if (msg->A_DataBufSize < size) {
+// return -ENOBUFS;
+// }
+
+// if (size) {
+// memmove((void *)msg->A_Data, tp->recv_buf, size);
+// tp->recv_size = 0;
+// memset(tp->recv_buf, 0, sizeof(tp->recv_buf));
+// printf(ANSI_BRIGHT_MAGENTA "<-%s_tp_recv-%04d- [%02ld] ", tp->tag, UDSMillis(), size);
+// printhex(msg->A_Data, size);
+// printf(ANSI_RESET);
+// }
+// return size;
+// }
+
+// static ssize_t mock_transport_send(UDSTpHandle_t *hdl, UDSSDU_t *msg) {
+// assert(hdl);
+// struct MockTransport *tp = (struct MockTransport *)hdl;
+// printf(ANSI_BRIGHT_GREEN "--%s_tp_send-%04d->[%02d] ", tp->tag, UDSMillis(), msg->A_Length);
+// printhex(msg->A_Data, msg->A_Length);
+// printf(ANSI_RESET);
+// assert(msg->A_Length); // why send zero?
+// memmove(tp->send_buf, msg->A_Data, msg->A_Length);
+// tp->send_size = msg->A_Length;
+// return msg->A_Length;
+// }
+
+// static UDSTpStatus_t mock_transport_poll(UDSTpHandle_t *hdl) {
+// assert(hdl);
+// struct MockTransport *tp = (struct MockTransport *)hdl;
+// return tp->status;
+// }
typedef struct {
UDSServer_t server;
- struct MockTransport server_tp;
UDSClient_t client;
+ UDSTpHandle_t *mock_tp;
+ uint8_t mock_recv_buf[DEFAULT_ISOTP_BUFSIZE];
struct MockTransport client_tp;
uint32_t time_ms;
uint32_t deadline;
- uint32_t call_count;
+ int call_count;
const char *func_name;
} Ctx_t;
@@ -174,60 +208,114 @@ Ctx_t ctx;
uint32_t UDSMillis() { return ctx.time_ms; }
static void poll_ctx(Ctx_t *ctx) {
- UDSServerPoll(&ctx->server);
- UDSClientPoll(&ctx->client);
+ if (ctx->server.tp) {
+ UDSServerPoll(&ctx->server);
+ }
+ if (ctx->client.tp) {
+ UDSClientPoll(&ctx->client);
+ }
ctx->time_ms++;
}
-#define SEND_TO_SERVER(d1, reqType) \
+/*
memmove(&ctx.server_tp.recv_buf, d1, sizeof(d1)); \
ctx.server_tp.recv_ta_type = reqType; \
ctx.server_tp.recv_size = sizeof(d1); \
poll_ctx(&ctx);
+*/
+
+#define SEND_TO_SERVER(d1, reqType) \
+ { \
+ UDSSDU_t msg = { \
+ .A_Mtype = UDS_A_MTYPE_DIAG, \
+ .A_Data = d1, \
+ .A_Length = sizeof(d1), \
+ .A_SA = CLIENT_SOURCE_ADDR, \
+ .A_TA = reqType == kTpAddrTypePhysical ? SERVER_SOURCE_ADDR: SERVER_SOURCE_ADDR_FUNC, \
+ .A_TA_Type = (int)reqType, \
+ }; \
+ ctx.mock_tp->send(ctx.mock_tp, &msg); \
+ } \
#define ASSERT_CLIENT_SENT(d1, reqType) \
- ASSERT_INT_EQUAL(ctx.client_tp.send_size, sizeof(d1)); \
- ASSERT_MEMORY_EQUAL(ctx.client_tp.send_buf, d1, sizeof(d1)); \
- ASSERT_INT_EQUAL(ctx.client_tp.send_ta_type, reqType);
+ { \
+ UDSSDU_t msg = { \
+ .A_DataBufSize = DEFAULT_ISOTP_BUFSIZE, \
+ .A_Data = ctx.mock_recv_buf, \
+ }; \
+ int recv_len = ctx.mock_tp->recv(ctx.mock_tp, &msg); \
+ ASSERT_INT_EQUAL(recv_len, sizeof(d1)); \
+ ASSERT_MEMORY_EQUAL(ctx.mock_recv_buf, d1, sizeof(d1)); \
+ if (reqType == kTpAddrTypePhysical) { \
+ ASSERT_INT_EQUAL(msg.A_TA, SERVER_SOURCE_ADDR); \
+ } else if (reqType == kTpAddrTypeFunctional) { \
+ ASSERT_INT_EQUAL(msg.A_TA, SERVER_SOURCE_ADDR_FUNC); \
+ } else { \
+ assert(0); \
+ } \
+ }
// send data to the client
static void send_to_client(const uint8_t *d1, size_t len, UDSTpAddr_t reqType) {
assert(len <= sizeof(ctx.client_tp.recv_buf));
- memmove(&ctx.client_tp.recv_buf, d1, len);
- ctx.client_tp.recv_ta_type = reqType;
- ctx.client_tp.recv_size = len;
+ ctx.mock_tp->send(ctx.mock_tp, &(UDSSDU_t){
+ .A_Mtype = UDS_A_MTYPE_DIAG,
+ .A_Data = d1,
+ .A_Length = len,
+ .A_SA = SERVER_SOURCE_ADDR,
+ .A_TA = SERVER_TARGET_ADDR,
+ .A_TA_Type = (int)reqType,
+ });
+ // memmove(&ctx.client_tp.recv_buf, d1, len);
+ // ctx.client_tp.recv_ta_type = reqType;
+ // ctx.client_tp.recv_size = len;
poll_ctx(&ctx);
}
#define SEND_TO_CLIENT(d1, reqType) send_to_client(d1, sizeof(d1), reqType);
+/*
+ while (0 == ctx.server_tp.send_size) { \
+ poll_ctx(&ctx); \
+ ASSERT_INT_LE(ctx.time_ms, deadline); \
+ } \
+ */
// expect a server response within a timeout
#define EXPECT_RESPONSE_WITHIN_MILLIS(d1, reqType, timeout_ms) \
{ \
- uint32_t deadline = ctx.time_ms + timeout_ms; \
- while (0 == ctx.server_tp.send_size) { \
+ uint32_t deadline = ctx.time_ms + timeout_ms + 1; \
+ UDSSDU_t msg = { \
+ .A_DataBufSize = DEFAULT_ISOTP_BUFSIZE, \
+ .A_Data = ctx.mock_recv_buf, \
+ }; \
+ while (0 == ctx.mock_tp->recv(ctx.mock_tp, &msg)) { \
poll_ctx(&ctx); \
+ printf("%d, %d, %d\n", UDSMillis(), ctx.time_ms, deadline); \
ASSERT_INT_LE(ctx.time_ms, deadline); \
} \
- ASSERT_INT_EQUAL(ctx.server_tp.send_size, sizeof(d1)); \
- ASSERT_MEMORY_EQUAL(ctx.server_tp.send_buf, d1, sizeof(d1)); \
- ASSERT_INT_EQUAL(ctx.server_tp.send_ta_type, reqType); \
- memset(ctx.server_tp.send_buf, 0, sizeof(ctx.server_tp.send_buf)); \
- ctx.server_tp.send_size = 0; \
+ printhex(msg.A_Data, msg.A_Length); \
+ ASSERT_INT_EQUAL(msg.A_Length, sizeof(d1)); \
+ ASSERT_MEMORY_EQUAL(msg.A_Data, d1, sizeof(d1)); \
+ ASSERT_INT_EQUAL((int)msg.A_TA_Type, reqType); \
}
// expect no server response within a timeout
#define EXPECT_NO_RESPONSE_FOR_MILLIS(timeout_ms) \
{ \
uint32_t deadline = ctx.time_ms + timeout_ms; \
- while (deadline < ctx.time_ms) { \
+ while (ctx.time_ms <= deadline) { \
poll_ctx(&ctx); \
+ UDSSDU_t msg = { \
+ .A_DataBufSize = DEFAULT_ISOTP_BUFSIZE, \
+ .A_Data = ctx.mock_recv_buf, \
+ }; \
+ int resp_len = ctx.mock_tp->recv(ctx.mock_tp, &msg); \
+ ASSERT_INT_EQUAL(resp_len, 0); \
} \
- ASSERT_INT_EQUAL(ctx.server_tp.send_size, 0); \
}
void testServer0x10DiagSessCtrlIsDisabledByDefault() {
- TEST_SETUP();
+ TEST_SETUP(SERVER_ONLY);
const uint8_t REQ[] = {0x10, 0x02};
SEND_TO_SERVER(REQ, kTpAddrTypePhysical);
const uint8_t RESP[] = {0x7f, 0x10, 0x11};
@@ -236,7 +324,7 @@ void testServer0x10DiagSessCtrlIsDisabledByDefault() {
}
void testServer0x10DiagSessCtrlFunctionalRequest() {
- TEST_SETUP();
+ TEST_SETUP(SERVER_ONLY);
// sending a diagnostic session control request functional broadcast
const uint8_t REQ[] = {0x10, 0x03};
SEND_TO_SERVER(REQ, kTpAddrTypeFunctional);
@@ -264,7 +352,7 @@ uint8_t fn1(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
// reset request: It is recommended that during this time the ECU does not accept any request
// messages and send any response messages.
void testServer0x11DoesNotSendOrReceiveMessagesAfterECUReset() {
- TEST_SETUP();
+ TEST_SETUP(SERVER_ONLY);
ctx.server.fn = fn1;
const uint8_t REQ[] = {0x11, 0x01};
@@ -305,7 +393,7 @@ uint8_t fn2(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
}
void testServer0x22RDBI1() {
- TEST_SETUP();
+ TEST_SETUP(SERVER_ONLY);
ctx.server.fn = fn2;
{
uint8_t REQ[] = {0x22, 0xF1, 0x90};
@@ -334,7 +422,7 @@ uint8_t fn10(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
}
void testServer0x23ReadMemoryByAddress() {
- TEST_SETUP();
+ TEST_SETUP(SERVER_ONLY);
ctx.server.fn = fn10;
uint8_t REQ[] = {0x23, 0x18, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0xf0, 0xc8, 0x04};
SEND_TO_SERVER(REQ, kTpAddrTypePhysical);
@@ -368,7 +456,7 @@ uint8_t fn4(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
// UDS-1 2013 9.4.5.2
// UDS-1 2013 9.4.5.3
void testServer0x27SecurityAccess() {
- TEST_SETUP();
+ TEST_SETUP(SERVER_ONLY);
ctx.server.fn = fn4;
// the server security level after initialization should be 0
@@ -406,7 +494,7 @@ static uint8_t ReturnPositiveResponse(UDSServer_t *srv, UDSServerEvent_t ev, con
// ISO-14229-1 2013 Table A.1 Byte Value 0x78: requestCorrectlyReceived-ResponsePending
// "This NRC is in general supported by each diagnostic service".
void testServer0x31RCRRP() {
- TEST_SETUP();
+ TEST_SETUP(SERVER_ONLY);
// When a server handler func initially returns RRCRP
ctx.server.fn = ReturnRCRRP;
@@ -435,7 +523,7 @@ void testServer0x31RCRRP() {
}
void testServer0x34NotEnabled() {
- TEST_SETUP();
+ TEST_SETUP(SERVER_ONLY);
// when no handler function is installed, sending this request to the server
const uint8_t IN[] = {0x34, 0x11, 0x33, 0x60, 0x20, 0x00, 0x00, 0xFF, 0xFF};
SEND_TO_SERVER(IN, kTpAddrTypePhysical);
@@ -458,7 +546,7 @@ uint8_t fn7(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
}
void testServer0x34() {
- TEST_SETUP();
+ TEST_SETUP(SERVER_ONLY);
// when a handler is installed that implements UDS-1:2013 Table 415
ctx.server.fn = fn7;
@@ -474,7 +562,7 @@ void testServer0x34() {
/* UDS-1 2013 Table 72 */
void testServer0x3ESuppressPositiveResponse() {
- TEST_SETUP();
+ TEST_SETUP(SERVER_ONLY);
ctx.server.fn = ReturnPositiveResponse;
// when the suppressPositiveResponse bit is set
const uint8_t REQ[] = {0x3E, 0x80};
@@ -485,7 +573,7 @@ void testServer0x3ESuppressPositiveResponse() {
}
void testServer0x83DiagnosticSessionControl() {
- TEST_SETUP();
+ TEST_SETUP(SERVER_ONLY);
ctx.server.fn = ReturnPositiveResponse;
// the server sessionType after initialization should be kDefaultSession.
ASSERT_INT_EQUAL(ctx.server.sessionType, kDefaultSession);
@@ -516,7 +604,7 @@ void testServerSessionTimeout() {
{.tag = "timeout", .fn = fn9, .sessType = kProgrammingSession, .expectedCallCount = 1},
{.tag = "no handler", .fn = NULL, .sessType = kProgrammingSession, .expectedCallCount = 0},
};
- TEST_SETUP_PARAMETRIZED(p);
+ TEST_SETUP_PARAMETRIZED(SERVER_ONLY, p);
ctx.server.fn = p[i].fn;
ctx.server.sessionType = p[i].sessType;
while (ctx.time_ms < 5000)
@@ -537,7 +625,7 @@ void testServerSessionTimeout() {
}
void testClientP2TimeoutExceeded() {
- TEST_SETUP();
+ TEST_SETUP(CLIENT_ONLY);
// when sending a request that receives no response
UDSSendECUReset(&ctx.client, kHardReset);
@@ -552,7 +640,7 @@ void testClientP2TimeoutExceeded() {
}
void testClientP2TimeoutNotExceeded() {
- TEST_SETUP();
+ TEST_SETUP(CLIENT_ONLY);
// a client that sends an request
UDSSendECUReset(&ctx.client, kHardReset);
@@ -569,7 +657,7 @@ void testClientP2TimeoutNotExceeded() {
}
void testClientSuppressPositiveResponse() {
- TEST_SETUP();
+ TEST_SETUP(CLIENT_ONLY);
// Setting the suppressPositiveResponse flag before sending a request
ctx.client.options |= UDS_SUPPRESS_POS_RESP;
UDSSendECUReset(&ctx.client, kHardReset);
@@ -584,7 +672,7 @@ void testClientSuppressPositiveResponse() {
}
void testClientBusy() {
- TEST_SETUP();
+ TEST_SETUP(CLIENT_ONLY);
// Sending a request should not return an error
ASSERT_INT_EQUAL(UDS_OK, UDSSendECUReset(&ctx.client, kHardReset));
@@ -594,7 +682,7 @@ void testClientBusy() {
}
void testClient0x11ECUReset() {
- TEST_SETUP();
+ TEST_SETUP(CLIENT_ONLY);
const uint8_t GOOD[] = {0x51, 0x01};
const uint8_t BAD_SID[] = {0x50, 0x01};
const uint8_t TOO_SHORT[] = {0x51};
@@ -620,7 +708,7 @@ void testClient0x11ECUReset() {
CASE(NEG, UDS_NEG_RESP_IS_ERR, UDS_ERR_NEG_RESP),
};
#undef CASE
- TEST_SETUP_PARAMETRIZED(p);
+ TEST_SETUP_PARAMETRIZED(CLIENT_ONLY, p);
// sending a request with these options
ctx.client.options = p[i].options;
UDSSendECUReset(&ctx.client, kHardReset);
@@ -635,7 +723,7 @@ void testClient0x11ECUReset() {
}
void testClient0x22RDBITxBufferTooSmall() {
- TEST_SETUP();
+ TEST_SETUP(CLIENT_ONLY);
// attempting to send a request payload of 6 bytes
uint16_t didList[] = {0x0001, 0x0002, 0x0003};
@@ -653,7 +741,7 @@ void testClient0x22RDBITxBufferTooSmall() {
}
void testClient0x22RDBIUnpackResponse() {
- TEST_SETUP();
+ TEST_SETUP(CLIENT_ONLY);
uint8_t RESPONSE[] = {0x72, 0x12, 0x34, 0x00, 0x00, 0xAA, 0x00, 0x56, 0x78, 0xAA, 0xBB};
UDSClient_t client;
memmove(client.recv_buf, RESPONSE, sizeof(RESPONSE));
@@ -680,7 +768,7 @@ void testClient0x22RDBIUnpackResponse() {
}
void testClient0x31RCRRP() {
- TEST_SETUP();
+ TEST_SETUP(CLIENT_ONLY);
{ // Case 1: RCRRP Timeout
// When a request is sent
@@ -730,7 +818,7 @@ void testClient0x31RCRRP() {
}
void testClient0x34RequestDownload() {
- TEST_SETUP();
+ TEST_SETUP(CLIENT_ONLY);
// When RequestDownload is called with these arguments
ASSERT_INT_EQUAL(UDS_OK, UDSSendRequestDownload(&ctx.client, 0x11, 0x33, 0x602000, 0x00FFFF));
@@ -741,7 +829,7 @@ void testClient0x34RequestDownload() {
}
void testClient0x34UDSUnpackRequestDownloadResponse() {
- TEST_SETUP();
+ TEST_SETUP(CLIENT_ONLY);
struct RequestDownloadResponse resp;
// When the following raw bytes are received
diff --git a/tp_mock.c b/tp_mock.c
new file mode 100644
index 0000000..106f836
--- /dev/null
+++ b/tp_mock.c
@@ -0,0 +1,135 @@
+#include "tp_mock.h"
+#include "iso14229.h"
+#include
+#include
+#include
+#include
+
+
+typedef struct TPMock {
+ UDSTpHandle_t hdl;
+ UDSSDU_t recv_q[1];
+ unsigned recv_cnt;
+ uint8_t recv_buf[1024];
+ uint32_t recv_buf_size;
+ char name[32];
+} TPMock_t;
+
+static TPMock_t TPs[8];
+static int TPCount= 0;
+static FILE *LogFile = NULL;
+
+static bool RecvBufIsFull(TPMock_t *tp) {
+ return tp->recv_cnt >= sizeof(tp->recv_q) / sizeof(tp->recv_q[0]);
+}
+
+static void LogMsg(const char *prefix, UDSSDU_t *msg) {
+ if (!LogFile) {
+ return;
+ }
+ fprintf(LogFile, "%06d, %s sends, 0x%03x (%s), ", UDSMillis(), prefix, msg->A_TA, msg->A_TA_Type == UDS_A_TA_TYPE_PHYSICAL ? "phys": "func");
+ for (unsigned i = 0; i < msg->A_Length; i++) {
+ fprintf(LogFile, "%02x ", msg->A_Data[i]);
+ }
+ fprintf(LogFile, "\n");
+ fflush(LogFile); // flush every time in case of crash
+}
+
+static ssize_t tp_recv(struct UDSTpHandle *hdl, UDSSDU_t *msg) {
+ assert(hdl);
+ assert(msg);
+ assert(msg->A_Data);
+ TPMock_t *tp = (TPMock_t *)hdl;
+ if (tp->recv_cnt == 0) {
+ return 0;
+ } else {
+ UDSSDU_t *in_msg = &tp->recv_q[0];
+ if (in_msg->A_Length > msg->A_DataBufSize) {
+ fprintf(stderr, "TPMock: %s recv buffer is too small\n", tp->name);
+ return -1;
+ }
+ msg->A_Length = in_msg->A_Length;
+ msg->A_Mtype = in_msg->A_Mtype;
+ msg->A_SA = in_msg->A_SA;
+ msg->A_TA = in_msg->A_TA;
+ msg->A_TA_Type = in_msg->A_TA_Type;
+ memmove((void*)msg->A_Data, in_msg->A_Data, in_msg->A_Length);
+
+ for (unsigned i = 1; i < tp->recv_cnt; i++) {
+ tp->recv_q[i - 1] = tp->recv_q[i];
+ }
+ tp->recv_cnt--;
+ return msg->A_Length;
+ }
+}
+
+static ssize_t tp_send(struct UDSTpHandle *hdl, UDSSDU_t *msg) {
+ assert(hdl);
+ assert(msg);
+ TPMock_t *tp = (TPMock_t *)hdl;
+ for (unsigned i = 0; i < TPCount; i++) {
+ TPMock_t *tp2 = &TPs[i];
+ if (tp2 == tp) {
+ continue; // don't send to self
+ }
+ if (RecvBufIsFull(tp2)) {
+ fprintf(stderr, "TPMock: %s recv buffer is full\n", tp2->name);
+ continue;
+ }
+ tp2->recv_q[tp2->recv_cnt++] = *msg;
+ }
+ LogMsg(tp->name, msg);
+ return msg->A_Length;
+}
+
+static UDSTpStatus_t tp_poll(struct UDSTpHandle *hdl) {
+ // todo: mock artificially long TX time
+ return UDS_TP_IDLE;
+}
+
+static_assert(offsetof(TPMock_t, hdl) == 0, "TPMock_t must not have any members before hdl");
+
+UDSTpHandle_t *TPMockCreate(const char *name) {
+ TPMock_t *tp;
+ if (TPCount >= sizeof(TPs) / sizeof(TPs[0])) {
+ return NULL;
+ }
+ tp = &TPs[TPCount++];
+ if (name) {
+ strncpy(tp->name, name, sizeof(tp->name));
+ } else {
+ snprintf(tp->name, sizeof(tp->name), "TPMock%d", TPCount);
+ }
+ tp->hdl.recv = tp_recv;
+ tp->hdl.send = tp_send;
+ tp->hdl.poll = tp_poll;
+ return &tp->hdl;
+}
+
+void TPMockConnect(UDSTpHandle_t *tp1, UDSTpHandle_t *tp2);
+
+void TPMockLogToFile(const char *filename){
+ if (LogFile) {
+ fprintf(stderr, "Log file is already open\n");
+ return;
+ }
+ if (!filename) {
+ fprintf(stderr, "Filename is NULL\n");
+ return;
+ }
+ // create file
+ LogFile = fopen(filename, "w");
+ if (!LogFile) {
+ fprintf(stderr, "Failed to open log file %s\n", filename);
+ return;
+ }
+}
+
+void TPMockReset() {
+ memset(TPs, 0, sizeof(TPs));
+ TPCount = 0;
+ if (LogFile) {
+ fclose(LogFile);
+ LogFile = NULL;
+ }
+}
\ No newline at end of file
diff --git a/tp_mock.h b/tp_mock.h
new file mode 100644
index 0000000..933dcf1
--- /dev/null
+++ b/tp_mock.h
@@ -0,0 +1,28 @@
+/**
+ * @file tp_mock.h
+ * @brief in-memory transport layer implementation for testing
+ * @date 2023-10-21
+ *
+ */
+
+#include "iso14229.h"
+
+/**
+ * @brief Create a mock transport. It is connected by default to a broadcast network of all other mock transports in the same process.
+ * @param name optional name of the transport (can be NULL)
+ * @return UDSTpHandle_t*
+ */
+UDSTpHandle_t *TPMockCreate(const char *name);
+
+/**
+ * @brief write all messages to a file
+ * @note uses UDSMillis() to get the current time
+ * @param filename log file name (will be overwritten)
+ */
+void TPMockLogToFile(const char *filename);
+
+
+/**
+ * @brief clear all transports and close the log file
+ */
+void TPMockReset(void);
From 1ecb238be6fb8497ec42a0a768b8087bf84f5c28 Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Sun, 22 Oct 2023 16:06:51 -0700
Subject: [PATCH 03/56] format
---
iso14229.c | 14 +--
iso14229.h | 16 +--
test/env.c | 2 +-
test/env.h | 14 +--
test/test_server_0x10_diag_sess_ctrl.c | 11 +-
test_iso14229.c | 165 +++++++++++++------------
tp_mock.c | 14 +--
tp_mock.h | 8 +-
8 files changed, 122 insertions(+), 122 deletions(-)
diff --git a/iso14229.c b/iso14229.c
index 6c0cfd6..e6d9dea 100644
--- a/iso14229.c
+++ b/iso14229.c
@@ -1340,8 +1340,8 @@ UDSErr_t UDSClientInit(UDSClient_t *client, const UDSClientConfig_t *cfg) {
UDSTpIsoTpC_t *tp = (UDSTpIsoTpC_t *)&client->tp_impl;
isotp_init_link(&tp->phys_link, cfg->target_addr, client->send_buf, client->send_buf_size,
client->recv_buf, client->recv_buf_size);
- isotp_init_link(&tp->func_link, cfg->target_addr_func, tp->func_send_buf, sizeof(tp->func_send_buf),
- tp->func_recv_buf, sizeof(tp->func_recv_buf));
+ isotp_init_link(&tp->func_link, cfg->target_addr_func, tp->func_send_buf,
+ sizeof(tp->func_send_buf), tp->func_recv_buf, sizeof(tp->func_recv_buf));
client->tp = (UDSTpHandle_t *)tp;
client->tp->poll = tp_poll;
client->tp->send = tp_send;
@@ -1524,9 +1524,8 @@ static void PollLowLevel(UDSClient_t *client) {
.A_DataBufSize = client->recv_buf_size,
.A_Data = client->recv_buf,
};
- ssize_t ret =
- client->tp->recv(client->tp, &msg);
-
+ ssize_t ret = client->tp->recv(client->tp, &msg);
+
if (kTpAddrTypeFunctional == ta_type) {
break;
}
@@ -2071,9 +2070,10 @@ bool UDSClientPoll(UDSClient_t *client) {
}
}
-void UDSClientPoll2(UDSClient_t *client, int (*fn)(UDSClient_t *client, UDSEvent_t evt, void *ev_data, void *fn_data), void *fn_data) {
+void UDSClientPoll2(UDSClient_t *client,
+ int (*fn)(UDSClient_t *client, UDSEvent_t evt, void *ev_data, void *fn_data),
+ void *fn_data) {
UDSClientPoll(client);
-
}
UDSSeqState_t UDSClientAwaitIdle(UDSClient_t *client) {
diff --git a/iso14229.h b/iso14229.h
index c0e38af..61675d5 100644
--- a/iso14229.h
+++ b/iso14229.h
@@ -18,9 +18,9 @@ extern "C" {
#define UDS_ARCH_UNIX 1
#define UDS_ARCH_WINDOWS 2
-#define UDS_TP_CUSTOM 0 // bring your own transport layer
-#define UDS_TP_ISOTP_C 1 // use isotp-c
-#define UDS_TP_ISOTP_SOCKET 2 // use linux ISO-TP socket
+#define UDS_TP_CUSTOM 0 // bring your own transport layer
+#define UDS_TP_ISOTP_C 1 // use isotp-c
+#define UDS_TP_ISOTP_SOCKET 2 // use linux ISO-TP socket
#if !defined(UDS_ARCH)
#if defined(__unix__) || defined(__APPLE__)
@@ -260,14 +260,15 @@ typedef struct {
uint16_t A_SA; // application source address
uint16_t A_TA; // application target address
UDS_A_TA_Type_t A_TA_Type;
- uint16_t A_AE; // application layer remote address
+ uint16_t A_AE; // application layer remote address
uint32_t A_Length; // data length
uint32_t A_DataBufSize;
const uint8_t *A_Data;
} UDSSDU_t;
/**
- * @brief Transport Handle is the interface between the UDS application layer and the transport layer.
+ * @brief Transport Handle is the interface between the UDS application layer and the transport
+ * layer.
*/
typedef struct UDSTpHandle {
/**
@@ -316,7 +317,6 @@ typedef struct {
} UDSTpLinuxIsoTp_t;
#endif
-
// ========================================================================
// Utility Functions
// ========================================================================
@@ -449,7 +449,9 @@ void UDSClientDeInit(UDSClient_t *client);
* @return UDS_CLIENT_IDLE if idle, otherwise UDS_CLIENT_RUNNING
*/
bool UDSClientPoll(UDSClient_t *client);
-void UDSClientPoll2(UDSClient_t *client, int (*fn)(UDSClient_t *client, int evt, void *ev_data, void *fn_data), void *fn_data);
+void UDSClientPoll2(UDSClient_t *client,
+ int (*fn)(UDSClient_t *client, int evt, void *ev_data, void *fn_data),
+ void *fn_data);
UDSErr_t UDSSendECUReset(UDSClient_t *client, UDSECUReset_t type);
UDSErr_t UDSSendDiagSessCtrl(UDSClient_t *client, enum UDSDiagnosticSessionType mode);
diff --git a/test/env.c b/test/env.c
index fae4dd7..ca831f8 100644
--- a/test/env.c
+++ b/test/env.c
@@ -26,7 +26,7 @@ void ENV_Send(UDSSDU_t *msg) {
continue;
}
if (tp->)
- UDSTpSend(tp, msg);
+ UDSTpSend(tp, msg);
}
UDSTpHandle_t *tp = msg->A_TP;
if (tp == NULL) {
diff --git a/test/env.h b/test/env.h
index 2c828e3..783d952 100644
--- a/test/env.h
+++ b/test/env.h
@@ -1,4 +1,4 @@
-#ifndef ENV_H
+#ifndef ENV_H
#define ENV_H
#include "iso14229.h"
@@ -6,14 +6,12 @@
UDSTpHandle_t *ENV_TpNew();
-
void ENV_Send(UDSSDU_t *msg);
-#define ENV_EXPECT_MSG_WITHIN_MILLIS(msg_ptr, millis) \
- do { \
- UDSSDU_t *msg = (msg_ptr); \
- ENV_ExpectBytesWithinMillis(ENV_TpNew(), msg->A_Data, msg->A_Length, millis); \
+#define ENV_EXPECT_MSG_WITHIN_MILLIS(msg_ptr, millis) \
+ do { \
+ UDSSDU_t *msg = (msg_ptr); \
+ ENV_ExpectBytesWithinMillis(ENV_TpNew(), msg->A_Data, msg->A_Length, millis); \
} while (0)
-
-#endif
\ No newline at end of file
+#endif
\ No newline at end of file
diff --git a/test/test_server_0x10_diag_sess_ctrl.c b/test/test_server_0x10_diag_sess_ctrl.c
index 304327f..94746f0 100644
--- a/test/test_server_0x10_diag_sess_ctrl.c
+++ b/test/test_server_0x10_diag_sess_ctrl.c
@@ -10,11 +10,11 @@ uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
int main() {
UDSServer_t srv;
- UDSTpHandle_t *tp = ENV_TpNew();
+ UDSTpHandle_t *tp = ENV_TpNew();
UDSServerInit(&srv, &(UDSServerConfig_t){
- .fn = fn,
- .tp = tp,
- });
+ .fn = fn,
+ .tp = tp,
+ });
const uint8_t REQ[] = {0x10, 0x02};
@@ -26,9 +26,8 @@ int main() {
.A_Length = sizeof(REQ),
.A_Data = REQ,
};
-
- ENV_Send(&req);
+ ENV_Send(&req);
UDSSDU_t resp;
ENV_EXPECT_MSG_WITHIN_MILLIS(&resp, 50);
diff --git a/test_iso14229.c b/test_iso14229.c
index 4c423c6..6a81a81 100644
--- a/test_iso14229.c
+++ b/test_iso14229.c
@@ -84,52 +84,53 @@
#define SERVER_ONLY 0
#define CLIENT_ONLY 1
-#define _TEST_SETUP_SILENT(test_type, param_str) \
+#define _TEST_SETUP_SILENT(test_type, param_str) \
memset(&ctx, 0, sizeof(ctx)); \
ctx.func_name = __PRETTY_FUNCTION__; \
- if (SERVER_ONLY == test_type) { \
- UDSServerInit(&ctx.server, &(UDSServerConfig_t){ \
- .tp = TPMockCreate("server"), \
- .source_addr = SERVER_SOURCE_ADDR, \
- .target_addr = SERVER_TARGET_ADDR, \
- .source_addr_func = SERVER_SOURCE_ADDR_FUNC, \
- }); \
- ctx.mock_tp = TPMockCreate("mock_client"); \
- } \
- if (CLIENT_ONLY == test_type) { \
- UDSClientInit(&ctx.client, &(UDSClientConfig_t){ \
- .tp = TPMockCreate("client"), \
- .target_addr = CLIENT_TARGET_ADDR, \
- .source_addr = CLIENT_SOURCE_ADDR, \
- .target_addr_func = CLIENT_TARGET_ADDR_FUNC, \
- }); \
- ctx.mock_tp = TPMockCreate("mock_server"); \
- } \
+ if (SERVER_ONLY == test_type) { \
+ UDSServerInit(&ctx.server, &(UDSServerConfig_t){ \
+ .tp = TPMockCreate("server"), \
+ .source_addr = SERVER_SOURCE_ADDR, \
+ .target_addr = SERVER_TARGET_ADDR, \
+ .source_addr_func = SERVER_SOURCE_ADDR_FUNC, \
+ }); \
+ ctx.mock_tp = TPMockCreate("mock_client"); \
+ } \
+ if (CLIENT_ONLY == test_type) { \
+ UDSClientInit(&ctx.client, &(UDSClientConfig_t){ \
+ .tp = TPMockCreate("client"), \
+ .target_addr = CLIENT_TARGET_ADDR, \
+ .source_addr = CLIENT_SOURCE_ADDR, \
+ .target_addr_func = CLIENT_TARGET_ADDR_FUNC, \
+ }); \
+ ctx.mock_tp = TPMockCreate("mock_server"); \
+ } \
char logfilename[256] = {0}; \
- snprintf(logfilename, sizeof(logfilename), "%s%s.log", ctx.func_name, param_str); \
+ snprintf(logfilename, sizeof(logfilename), "%s%s.log", ctx.func_name, param_str); \
TPMockLogToFile(logfilename);
-#define TEST_SETUP(test_type) \
- _TEST_SETUP_SILENT(test_type, ""); \
+#define TEST_SETUP(test_type) \
+ _TEST_SETUP_SILENT(test_type, ""); \
printf("%s\n", ctx.func_name);
-#define TEST_SETUP_PARAMETRIZED(test_type, params_list) \
+#define TEST_SETUP_PARAMETRIZED(test_type, params_list) \
for (size_t i = 0; i < sizeof(params_list) / sizeof(params_list[0]); i++) { \
- char _param_str[128]; \
- snprintf(_param_str, sizeof(_param_str), "%s_p_%ld_%s", ctx.func_name, i, (*(char **)(&(params_list[i])))); \
- _TEST_SETUP_SILENT(test_type, _param_str); \
+ char _param_str[128]; \
+ snprintf(_param_str, sizeof(_param_str), "%s_p_%ld_%s", ctx.func_name, i, \
+ (*(char **)(&(params_list[i])))); \
+ _TEST_SETUP_SILENT(test_type, _param_str); \
printf("%s\n", _param_str);
#define TEST_TEARDOWN_PARAMETRIZED() \
- TPMockReset(); \
+ TPMockReset(); \
printf(ANSI_BOLD "OK [p:%ld]\n" ANSI_RESET, i); \
}
-#define TEST_TEARDOWN() \
-{ \
- TPMockReset(); \
- printf(ANSI_BOLD "OK\n" ANSI_RESET); \
-}
+#define TEST_TEARDOWN() \
+ { \
+ TPMockReset(); \
+ printf(ANSI_BOLD "OK\n" ANSI_RESET); \
+ }
// TODO: parameterize and fuzz this
#define DEFAULT_ISOTP_BUFSIZE (2048U)
@@ -225,47 +226,47 @@ static void poll_ctx(Ctx_t *ctx) {
*/
#define SEND_TO_SERVER(d1, reqType) \
- { \
- UDSSDU_t msg = { \
- .A_Mtype = UDS_A_MTYPE_DIAG, \
- .A_Data = d1, \
- .A_Length = sizeof(d1), \
- .A_SA = CLIENT_SOURCE_ADDR, \
- .A_TA = reqType == kTpAddrTypePhysical ? SERVER_SOURCE_ADDR: SERVER_SOURCE_ADDR_FUNC, \
- .A_TA_Type = (int)reqType, \
- }; \
- ctx.mock_tp->send(ctx.mock_tp, &msg); \
- } \
+ { \
+ UDSSDU_t msg = { \
+ .A_Mtype = UDS_A_MTYPE_DIAG, \
+ .A_Data = d1, \
+ .A_Length = sizeof(d1), \
+ .A_SA = CLIENT_SOURCE_ADDR, \
+ .A_TA = reqType == kTpAddrTypePhysical ? SERVER_SOURCE_ADDR : SERVER_SOURCE_ADDR_FUNC, \
+ .A_TA_Type = (int)reqType, \
+ }; \
+ ctx.mock_tp->send(ctx.mock_tp, &msg); \
+ }
#define ASSERT_CLIENT_SENT(d1, reqType) \
- { \
- UDSSDU_t msg = { \
- .A_DataBufSize = DEFAULT_ISOTP_BUFSIZE, \
- .A_Data = ctx.mock_recv_buf, \
- }; \
- int recv_len = ctx.mock_tp->recv(ctx.mock_tp, &msg); \
- ASSERT_INT_EQUAL(recv_len, sizeof(d1)); \
- ASSERT_MEMORY_EQUAL(ctx.mock_recv_buf, d1, sizeof(d1)); \
- if (reqType == kTpAddrTypePhysical) { \
- ASSERT_INT_EQUAL(msg.A_TA, SERVER_SOURCE_ADDR); \
- } else if (reqType == kTpAddrTypeFunctional) { \
- ASSERT_INT_EQUAL(msg.A_TA, SERVER_SOURCE_ADDR_FUNC); \
- } else { \
- assert(0); \
- } \
+ { \
+ UDSSDU_t msg = { \
+ .A_DataBufSize = DEFAULT_ISOTP_BUFSIZE, \
+ .A_Data = ctx.mock_recv_buf, \
+ }; \
+ int recv_len = ctx.mock_tp->recv(ctx.mock_tp, &msg); \
+ ASSERT_INT_EQUAL(recv_len, sizeof(d1)); \
+ ASSERT_MEMORY_EQUAL(ctx.mock_recv_buf, d1, sizeof(d1)); \
+ if (reqType == kTpAddrTypePhysical) { \
+ ASSERT_INT_EQUAL(msg.A_TA, SERVER_SOURCE_ADDR); \
+ } else if (reqType == kTpAddrTypeFunctional) { \
+ ASSERT_INT_EQUAL(msg.A_TA, SERVER_SOURCE_ADDR_FUNC); \
+ } else { \
+ assert(0); \
+ } \
}
// send data to the client
static void send_to_client(const uint8_t *d1, size_t len, UDSTpAddr_t reqType) {
assert(len <= sizeof(ctx.client_tp.recv_buf));
ctx.mock_tp->send(ctx.mock_tp, &(UDSSDU_t){
- .A_Mtype = UDS_A_MTYPE_DIAG,
- .A_Data = d1,
- .A_Length = len,
- .A_SA = SERVER_SOURCE_ADDR,
- .A_TA = SERVER_TARGET_ADDR,
- .A_TA_Type = (int)reqType,
- });
+ .A_Mtype = UDS_A_MTYPE_DIAG,
+ .A_Data = d1,
+ .A_Length = len,
+ .A_SA = SERVER_SOURCE_ADDR,
+ .A_TA = SERVER_TARGET_ADDR,
+ .A_TA_Type = (int)reqType,
+ });
// memmove(&ctx.client_tp.recv_buf, d1, len);
// ctx.client_tp.recv_ta_type = reqType;
// ctx.client_tp.recv_size = len;
@@ -283,34 +284,34 @@ static void send_to_client(const uint8_t *d1, size_t len, UDSTpAddr_t reqType) {
// expect a server response within a timeout
#define EXPECT_RESPONSE_WITHIN_MILLIS(d1, reqType, timeout_ms) \
{ \
- uint32_t deadline = ctx.time_ms + timeout_ms + 1; \
- UDSSDU_t msg = { \
- .A_DataBufSize = DEFAULT_ISOTP_BUFSIZE, \
- .A_Data = ctx.mock_recv_buf, \
- }; \
- while (0 == ctx.mock_tp->recv(ctx.mock_tp, &msg)) { \
+ uint32_t deadline = ctx.time_ms + timeout_ms + 1; \
+ UDSSDU_t msg = { \
+ .A_DataBufSize = DEFAULT_ISOTP_BUFSIZE, \
+ .A_Data = ctx.mock_recv_buf, \
+ }; \
+ while (0 == ctx.mock_tp->recv(ctx.mock_tp, &msg)) { \
poll_ctx(&ctx); \
- printf("%d, %d, %d\n", UDSMillis(), ctx.time_ms, deadline); \
+ printf("%d, %d, %d\n", UDSMillis(), ctx.time_ms, deadline); \
ASSERT_INT_LE(ctx.time_ms, deadline); \
} \
printhex(msg.A_Data, msg.A_Length); \
- ASSERT_INT_EQUAL(msg.A_Length, sizeof(d1)); \
- ASSERT_MEMORY_EQUAL(msg.A_Data, d1, sizeof(d1)); \
- ASSERT_INT_EQUAL((int)msg.A_TA_Type, reqType); \
+ ASSERT_INT_EQUAL(msg.A_Length, sizeof(d1)); \
+ ASSERT_MEMORY_EQUAL(msg.A_Data, d1, sizeof(d1)); \
+ ASSERT_INT_EQUAL((int)msg.A_TA_Type, reqType); \
}
// expect no server response within a timeout
#define EXPECT_NO_RESPONSE_FOR_MILLIS(timeout_ms) \
{ \
uint32_t deadline = ctx.time_ms + timeout_ms; \
- while (ctx.time_ms <= deadline) { \
+ while (ctx.time_ms <= deadline) { \
poll_ctx(&ctx); \
- UDSSDU_t msg = { \
- .A_DataBufSize = DEFAULT_ISOTP_BUFSIZE, \
- .A_Data = ctx.mock_recv_buf, \
- }; \
- int resp_len = ctx.mock_tp->recv(ctx.mock_tp, &msg); \
- ASSERT_INT_EQUAL(resp_len, 0); \
+ UDSSDU_t msg = { \
+ .A_DataBufSize = DEFAULT_ISOTP_BUFSIZE, \
+ .A_Data = ctx.mock_recv_buf, \
+ }; \
+ int resp_len = ctx.mock_tp->recv(ctx.mock_tp, &msg); \
+ ASSERT_INT_EQUAL(resp_len, 0); \
} \
}
diff --git a/tp_mock.c b/tp_mock.c
index 106f836..5a68581 100644
--- a/tp_mock.c
+++ b/tp_mock.c
@@ -5,7 +5,6 @@
#include
#include
-
typedef struct TPMock {
UDSTpHandle_t hdl;
UDSSDU_t recv_q[1];
@@ -16,7 +15,7 @@ typedef struct TPMock {
} TPMock_t;
static TPMock_t TPs[8];
-static int TPCount= 0;
+static int TPCount = 0;
static FILE *LogFile = NULL;
static bool RecvBufIsFull(TPMock_t *tp) {
@@ -27,7 +26,8 @@ static void LogMsg(const char *prefix, UDSSDU_t *msg) {
if (!LogFile) {
return;
}
- fprintf(LogFile, "%06d, %s sends, 0x%03x (%s), ", UDSMillis(), prefix, msg->A_TA, msg->A_TA_Type == UDS_A_TA_TYPE_PHYSICAL ? "phys": "func");
+ fprintf(LogFile, "%06d, %s sends, 0x%03x (%s), ", UDSMillis(), prefix, msg->A_TA,
+ msg->A_TA_Type == UDS_A_TA_TYPE_PHYSICAL ? "phys" : "func");
for (unsigned i = 0; i < msg->A_Length; i++) {
fprintf(LogFile, "%02x ", msg->A_Data[i]);
}
@@ -53,7 +53,7 @@ static ssize_t tp_recv(struct UDSTpHandle *hdl, UDSSDU_t *msg) {
msg->A_SA = in_msg->A_SA;
msg->A_TA = in_msg->A_TA;
msg->A_TA_Type = in_msg->A_TA_Type;
- memmove((void*)msg->A_Data, in_msg->A_Data, in_msg->A_Length);
+ memmove((void *)msg->A_Data, in_msg->A_Data, in_msg->A_Length);
for (unsigned i = 1; i < tp->recv_cnt; i++) {
tp->recv_q[i - 1] = tp->recv_q[i];
@@ -61,7 +61,7 @@ static ssize_t tp_recv(struct UDSTpHandle *hdl, UDSSDU_t *msg) {
tp->recv_cnt--;
return msg->A_Length;
}
-}
+}
static ssize_t tp_send(struct UDSTpHandle *hdl, UDSSDU_t *msg) {
assert(hdl);
@@ -84,7 +84,7 @@ static ssize_t tp_send(struct UDSTpHandle *hdl, UDSSDU_t *msg) {
static UDSTpStatus_t tp_poll(struct UDSTpHandle *hdl) {
// todo: mock artificially long TX time
- return UDS_TP_IDLE;
+ return UDS_TP_IDLE;
}
static_assert(offsetof(TPMock_t, hdl) == 0, "TPMock_t must not have any members before hdl");
@@ -108,7 +108,7 @@ UDSTpHandle_t *TPMockCreate(const char *name) {
void TPMockConnect(UDSTpHandle_t *tp1, UDSTpHandle_t *tp2);
-void TPMockLogToFile(const char *filename){
+void TPMockLogToFile(const char *filename) {
if (LogFile) {
fprintf(stderr, "Log file is already open\n");
return;
diff --git a/tp_mock.h b/tp_mock.h
index 933dcf1..85604c8 100644
--- a/tp_mock.h
+++ b/tp_mock.h
@@ -2,15 +2,16 @@
* @file tp_mock.h
* @brief in-memory transport layer implementation for testing
* @date 2023-10-21
- *
+ *
*/
#include "iso14229.h"
/**
- * @brief Create a mock transport. It is connected by default to a broadcast network of all other mock transports in the same process.
+ * @brief Create a mock transport. It is connected by default to a broadcast network of all other
+ * mock transports in the same process.
* @param name optional name of the transport (can be NULL)
- * @return UDSTpHandle_t*
+ * @return UDSTpHandle_t*
*/
UDSTpHandle_t *TPMockCreate(const char *name);
@@ -21,7 +22,6 @@ UDSTpHandle_t *TPMockCreate(const char *name);
*/
void TPMockLogToFile(const char *filename);
-
/**
* @brief clear all transports and close the log file
*/
From 7edd73e8042c3dfb53c0f3026e2c3d09547a4f9e Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Tue, 31 Oct 2023 19:55:58 -0700
Subject: [PATCH 04/56] test bazel test on github actions
---
.github/workflows/runtests.yml | 3 +-
.tests.gdbinit | 3 -
BUILD | 24 +--
README.md | 79 +++----
README_zh.md | 65 +++---
examples/server.c | 4 +-
iso14229.c | 77 ++++++-
iso14229.h | 55 ++++-
test/BUILD | 31 ++-
test/env.c | 196 ++++++++++++++++--
test/env.h | 31 ++-
test/test.c | 0
test/test.h | 104 +++++++++-
test/test_client_0x11_ECU_reset.c | 55 +++++
...est_client_0x22_RDBI_tx_buffer_too_small.c | 19 ++
test/test_client_0x22_RDBI_unpack_response.c | 28 +++
test/test_client_0x31_RCRRP.c | 53 +++++
test/test_client_0x34_request_download.c | 13 ++
test/test_client_busy.c | 12 ++
test/test_client_p2.c | 35 ++++
test/test_client_suppress_positive_response.c | 17 ++
test/test_server_0x10_diag_sess_ctrl.c | 45 ----
...r_0x10_diag_sess_ctrl_functional_request.c | 17 ++
...10_diag_sess_ctrl_is_disabled_by_default.c | 17 ++
...server_0x11_no_send_recv_after_ECU_reset.c | 39 ++++
test/test_server_0x22_RDBI.c | 48 +++++
.../test_server_0x23_read_memory_by_address.c | 29 +++
test/test_server_0x27_security_access.c | 66 ++++++
test/test_server_0x31_RCRRP.c | 43 ++++
test/test_server_0x34.c | 50 +++++
...t_server_0x3E_suppress_positive_response.c | 21 ++
...t_server_0x83_diagnostic_session_control.c | 28 +++
test/test_server_session_timeout.c | 35 ++++
test_iso14229.c | 2 +-
tp/BUILD | 48 +++++
{examples => tp}/isotp-c_on_socketcan.h | 0
tp/isotp_c.h | 15 ++
.../isotp_c_socketcan.c | 0
tp/isotp_c_socketcan.h | 18 ++
tp/isotp_sock.c | 196 ++++++++++++++++++
tp/isotp_sock.h | 21 ++
tp_mock.c => tp/mock.c | 13 +-
tp_mock.h => tp/mock.h | 4 +
43 files changed, 1464 insertions(+), 195 deletions(-)
delete mode 100644 .tests.gdbinit
delete mode 100644 test/test.c
create mode 100644 test/test_client_0x11_ECU_reset.c
create mode 100644 test/test_client_0x22_RDBI_tx_buffer_too_small.c
create mode 100644 test/test_client_0x22_RDBI_unpack_response.c
create mode 100644 test/test_client_0x31_RCRRP.c
create mode 100644 test/test_client_0x34_request_download.c
create mode 100644 test/test_client_busy.c
create mode 100644 test/test_client_p2.c
create mode 100644 test/test_client_suppress_positive_response.c
delete mode 100644 test/test_server_0x10_diag_sess_ctrl.c
create mode 100644 test/test_server_0x10_diag_sess_ctrl_functional_request.c
create mode 100644 test/test_server_0x10_diag_sess_ctrl_is_disabled_by_default.c
create mode 100644 test/test_server_0x11_no_send_recv_after_ECU_reset.c
create mode 100644 test/test_server_0x22_RDBI.c
create mode 100644 test/test_server_0x23_read_memory_by_address.c
create mode 100644 test/test_server_0x27_security_access.c
create mode 100644 test/test_server_0x31_RCRRP.c
create mode 100644 test/test_server_0x34.c
create mode 100644 test/test_server_0x3E_suppress_positive_response.c
create mode 100644 test/test_server_0x83_diagnostic_session_control.c
create mode 100644 test/test_server_session_timeout.c
create mode 100644 tp/BUILD
rename {examples => tp}/isotp-c_on_socketcan.h (100%)
create mode 100644 tp/isotp_c.h
rename examples/isotp-c_on_socketcan.c => tp/isotp_c_socketcan.c (100%)
create mode 100644 tp/isotp_c_socketcan.h
create mode 100644 tp/isotp_sock.c
create mode 100644 tp/isotp_sock.h
rename tp_mock.c => tp/mock.c (97%)
rename tp_mock.h => tp/mock.h (82%)
diff --git a/.github/workflows/runtests.yml b/.github/workflows/runtests.yml
index c2c8d49..c410297 100644
--- a/.github/workflows/runtests.yml
+++ b/.github/workflows/runtests.yml
@@ -13,6 +13,5 @@ jobs:
steps:
- uses: actions/checkout@v3
-
- name: build and run unit test
- run: make unit_test
+ run: bazel test //test:all
diff --git a/.tests.gdbinit b/.tests.gdbinit
deleted file mode 100644
index 4fd0acc..0000000
--- a/.tests.gdbinit
+++ /dev/null
@@ -1,3 +0,0 @@
-# For handy x86 breakpoint setting, drop an `__asm__("int3");` in the source
-exec-file python3
-run ./test_iso14229 -s
diff --git a/BUILD b/BUILD
index b9c795f..8b07d20 100644
--- a/BUILD
+++ b/BUILD
@@ -1,13 +1,8 @@
package(default_visibility = ["//visibility:public"])
-config_setting(
- name = "tp",
- values = {"tp": "mock,isotp-c-vcan,isotp-c-udp"},
-)
-
filegroup(
- name = "srcs",
+ name = "iso14229_srcs",
srcs = [
"iso14229.c",
"iso14229.h",
@@ -16,13 +11,13 @@ filegroup(
)
cc_test(
- name="test",
+ name="test_all",
srcs=[
- ":srcs",
+ ":iso14229_srcs",
"test_iso14229.c",
],
deps = [
- ":tp_mock",
+ "//tp:mock",
],
copts=[
"-Wall",
@@ -67,14 +62,5 @@ cc_library(
cc_library(
name="iso14229",
- srcs=[":srcs"],
+ srcs=[":iso14229_srcs"],
)
-
-cc_library(
- name="tp_mock",
- srcs=[
- "tp_mock.c",
- "tp_mock.h",
- "iso14229.h",
- ],
-)
\ No newline at end of file
diff --git a/README.md b/README.md
index 7ce9639..856a8dc 100644
--- a/README.md
+++ b/README.md
@@ -358,13 +358,41 @@ MIT
# Changelog
-## 0.0.0
-- initial release
-## 0.1.0
-- Add client
-- Add server SID 0x27 SecurityAccess
-- API changes
+## 0.7.0
+- test refactoring. theme: test invariance across different transports and processor architectures
+- breaking API changes:
+ - rename `phys_send_id`, `phys_recv_id`, `func_send_id`, and `func_recv_id` to be consistent with the standard. Now mandatory for all UDSServerConfig_t and UDSClientConfig_t regardless of transport layer implementation
+
+## 0.6.0
+- breaking API changes:
+ - `UDSClientErr_t` merged into `UDSErr_t`
+ - `TP_SEND_INPROGRESS` renamed to `UDS_TP_SEND_IN_PROGRESS`
+ - refactored `UDSTpHandle_t` to encourage struct inheritance
+ - `UDS_TP_LINUX_SOCKET` renamed to `UDS_TP_ISOTP_SOCKET`
+- added server fuzz test and qemu tests
+- cleaned up example tests, added isotp-c on socketcan to examples
+- added `UDS_SRV_EVT_DoScheduledReset`
+- improve client error handling
+
+## 0.5.0
+- usability: refactored into a single .c/.h module
+- usability: default transport layer configs are now built-in
+- API cleanup: use `UDS` prefix on all exported functions
+- API cleanup: use a single callback function for all server events
+
+## 0.4.0
+- refactor RDBIHandler to pass a function pointer that implements safe memmove rather than requiring the user to keep valid data around for an indefinite time or risking a buffer overflow.
+- Prefer fixed-width. Avoid using `enum` types as return types and in structures.
+- Transport layer is now pluggable and supports the linux kernel ISO-TP driver in addition to `isotp-c`. See [examples](./examples/README.md).
+
+## 0.3.0
+- added `iso14229ClientRunSequenceBlocking(...)`
+- added server and client examples
+- simplified test flow, deleted opaque macros and switch statements
+- flattened client and server main structs
+- simplified usage by moving isotp-c initialization parameters into server/client config structs
+- remove redundant buffers in server
## 0.2.0
- removed all instances of `__attribute__((packed))`
@@ -377,40 +405,13 @@ MIT
- removed redundant function `iso14229ServerEnableService`
- updated example
-## 0.3.0
-- added `iso14229ClientRunSequenceBlocking(...)`
-- added server and client examples
-- simplified test flow, deleted opaque macros and switch statements
-- flattened client and server main structs
-- simplified usage by moving isotp-c initialization parameters into server/client config structs
-- remove redundant buffers in server
-
-
-## 0.4.0
-- refactor RDBIHandler to pass a function pointer that implements safe memmove rather than requiring the user to keep valid data around for an indefinite time or risking a buffer overflow.
-- Prefer fixed-width. Avoid using `enum` types as return types and in structures.
-- Transport layer is now pluggable and supports the linux kernel ISO-TP driver in addition to `isotp-c`. See [examples](./examples/README.md).
-
-## 0.5.0
-- usability: refactored into a single .c/.h module
-- usability: default transport layer configs are now built-in
-- API cleanup: use `UDS` prefix on all exported functions
-- API cleanup: use a single callback function for all server events
-
-## 0.6.0
-- breaking API changes:
- - `UDSClientErr_t` merged into `UDSErr_t`
- - `TP_SEND_INPROGRESS` renamed to `UDS_TP_SEND_IN_PROGRESS`
- - refactored `UDSTpHandle_t` to encourage struct inheritance
- - `UDS_TP_LINUX_SOCKET` renamed to `UDS_TP_ISOTP_SOCKET`
-- added server fuzz test and qemu tests
-- cleaned up example tests, added isotp-c on socketcan to examples
-- added `UDS_SRV_EVT_DoScheduledReset`
-- improve client error handling
+## 0.1.0
+- Add client
+- Add server SID 0x27 SecurityAccess
+- API changes
-## 0.7.0
-- breaking API changes:
- - rename `phys_send_id`, `phys_recv_id`, `func_send_id`, and `func_recv_id` to be consistent with the standard. Now mandatory for all UDSServerConfig_t and UDSClientConfig_t regardless of transport layer implementation
+## 0.0.0
+- initial release
---
diff --git a/README_zh.md b/README_zh.md
index 1da6f11..4f10b80 100644
--- a/README_zh.md
+++ b/README_zh.md
@@ -358,13 +358,34 @@ MIT
# 变更记录
-## 0.0.0
-- 初次发布
+## 0.6.0
+- API更改:
+ - `UDSClientErr_t`合并到`UDSErr_t`
+ - `TP_SEND_INPROGRESS`改名为`UDS_TP_SEND_IN_PROGRESS`
+ - 重构了`UDSTpHandle_t`
+ - `UDS_TP_LINUX_SOCKET`改名为`UDS_TP_ISOTP_SOCKET`
+- 增加了服务器fuzz测试以及qemu测试
+- 整理例子测试,例子增加了isotp-c/socketcan传输
+- 增加了`UDS_SRV_EVT_DoScheduledReset`服务器事件
-## 0.1.0
-- 加客户端
-- 加服务器SID 0x27安全访问
-- API更改
+## 0.5.0
+- 可用性: 重构成单个.c/.h模块
+- 可用性: 默认传输层配置现在自带
+- API整理: 用`UDS`前缀在所有导出函数上
+- API整理: 服务器事件用单个回调函数
+
+## 0.4.0
+- 重构RDBIHandler:用安全memmove
+- 尽可能不用enum在结构体里面
+- 传输层可插件。现在支持linux内核ISO-TP驱动。`isotp-c`同时也支持。看看例子 [examples](./examples/README.md)
+
+## 0.3.0
+- 加`udsClientRunSequenceBlocking(...)`
+- 加了服务器和客户端例子
+- 简化测试流程、删掉了过分模糊宏定义和switch结构
+- 服务器和客户端结构体简化:尽量用一层深度
+- 简化使用、放isotp-c初始化参数到服务器/客户端配置里面
+- 删除重复服务器缓冲器
## 0.2.0
- 删除所有`__attribute__((packed))`
@@ -377,34 +398,14 @@ MIT
- 删掉了重复函数`udsServerEnableService`
- 更新例子
-## 0.3.0
-- 加`udsClientRunSequenceBlocking(...)`
-- 加了服务器和客户端例子
-- 简化测试流程、删掉了过分模糊宏定义和switch结构
-- 服务器和客户端结构体简化:尽量用一层深度
-- 简化使用、放isotp-c初始化参数到服务器/客户端配置里面
-- 删除重复服务器缓冲器
-
-## 0.4.0
-- 重构RDBIHandler:用安全memmove
-- 尽可能不用enum在结构体里面
-- 传输层可插件。现在支持linux内核ISO-TP驱动。`isotp-c`同时也支持。看看例子 [examples](./examples/README.md)
+## 0.1.0
+- 加客户端
+- 加服务器SID 0x27安全访问
+- API更改
-## 0.5.0
-- 可用性: 重构成单个.c/.h模块
-- 可用性: 默认传输层配置现在自带
-- API整理: 用`UDS`前缀在所有导出函数上
-- API整理: 服务器事件用单个回调函数
+## 0.0.0
+- 初次发布
-## 0.6.0
-- API更改:
- - `UDSClientErr_t`合并到`UDSErr_t`
- - `TP_SEND_INPROGRESS`改名为`UDS_TP_SEND_IN_PROGRESS`
- - 重构了`UDSTpHandle_t`
- - `UDS_TP_LINUX_SOCKET`改名为`UDS_TP_ISOTP_SOCKET`
-- 增加了服务器fuzz测试以及qemu测试
-- 整理例子测试,例子增加了isotp-c/socketcan传输
-- 增加了`UDS_SRV_EVT_DoScheduledReset`服务器事件
---
diff --git a/examples/server.c b/examples/server.c
index 4319df4..ba2d96d 100644
--- a/examples/server.c
+++ b/examples/server.c
@@ -22,8 +22,8 @@ static const UDSServerConfig_t cfg = {
.if_name = "vcan0",
#endif
.target_addr = SERVER_FUNC_ID,
- .source_addr = SERVER_source_addr,
- .func_recv_id = SERVER_FUNC_RECV_ID,
+ .source_addr = SERVER_PHYS_RECV_ID,
+ .source_addr_func = SERVER_FUNC_RECV_ID,
};
static bool serverWantsExit = false;
static struct RWDBIData {
diff --git a/iso14229.c b/iso14229.c
index e6d9dea..f253227 100644
--- a/iso14229.c
+++ b/iso14229.c
@@ -236,12 +236,14 @@ static int LinuxSockBind(const char *if_name, uint32_t rxid, uint32_t txid) {
}
struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
ioctl(fd, SIOCGIFINDEX, &ifr);
struct sockaddr_can addr;
memset(&addr, 0, sizeof(addr));
addr.can_family = AF_CAN;
+
addr.can_addr.tp.rx_id = rxid;
addr.can_addr.tp.tx_id = txid;
addr.can_ifindex = ifr.ifr_ifindex;
@@ -283,6 +285,69 @@ void LinuxSockTpClose(UDSTpHandle_t *hdl) {
}
}
#endif // #if UDS_TP == UDS_TP_ISOTP_SOCKET
+
+ssize_t UDSTpSend(UDSTpHandle_t *tp, const uint8_t *msg, size_t size) {
+ return tp->send(tp, &(UDSSDU_t){
+ .A_Mtype = UDS_A_MTYPE_DIAG,
+ .A_SA = 0x7E0,
+ .A_TA = 0x7E8,
+ .A_TA_Type = UDS_A_TA_TYPE_PHYSICAL,
+ .A_Length = size,
+ .A_Data = msg,
+ });
+}
+
+ssize_t UDSTpSendFunctional(UDSTpHandle_t *tp, const uint8_t *msg, size_t size) {
+ return tp->send(tp, &(UDSSDU_t){
+ .A_Mtype = UDS_A_MTYPE_DIAG,
+ .A_SA = 0x7E0,
+ .A_TA = 0x7DF,
+ .A_TA_Type = UDS_A_TA_TYPE_FUNCTIONAL,
+ .A_Length = size,
+ .A_Data = msg,
+ });
+}
+
+void UDSSessInit(UDSSess_t *sess, const UDSSessConfig_t *cfg) {
+ assert(sess);
+ assert(cfg);
+ memset(sess, 0, sizeof(*sess));
+ sess->tp = cfg->tp;
+ sess->source_addr = cfg->source_addr;
+ sess->target_addr = cfg->target_addr;
+ sess->source_addr_func = cfg->source_addr_func;
+ sess->target_addr_func = cfg->target_addr_func;
+}
+
+UDSErr_t UDSSessSend(UDSSess_t *sess, const uint8_t *msg, size_t size) {
+ assert(sess);
+ assert(msg);
+ assert(size);
+ UDSTpSend(sess->tp, msg, size);
+ return UDS_OK;
+}
+
+UDSErr_t UDSSessSendFunctional(UDSSess_t *sess, const uint8_t *msg, size_t size) {
+ assert(sess);
+ assert(msg);
+ assert(size);
+ UDSTpSendFunctional(sess->tp, msg, size);
+ return UDS_OK;
+}
+
+void UDSSessPoll(UDSSess_t *sess) {
+ assert(sess);
+ UDSTpHandle_t *tp = sess->tp;
+ UDSSDU_t msg = {
+ .A_DataBufSize = sizeof(sess->recv_buf),
+ .A_Data = sess->recv_buf,
+ };
+ ssize_t ret = tp->recv(tp, &msg);
+ if (ret > 0) {
+ sess->recv_size = ret;
+ }
+}
+
// ========================================================================
// Common
// ========================================================================
@@ -1288,7 +1353,7 @@ void UDSServerPoll(UDSServer_t *self) {
} else if (size == 0) {
;
} else {
- UDS_DBG_PRINT("tp_recv failed with err %d on tp %d\n", size, ta_type);
+ UDS_DBG_PRINT("tp_recv failed with err %d on tp %d\n", size, msg.A_TA_Type);
}
}
}
@@ -1577,6 +1642,16 @@ static UDSErr_t _SendRequest(UDSClient_t *client) {
} \
clearRequestContext(client);
+UDSErr_t UDSSendBytes(UDSClient_t *client, const uint8_t *data, uint16_t size) {
+ PRE_REQUEST_CHECK();
+ if (size > client->send_buf_size) {
+ return UDS_ERR_BUFSIZ;
+ }
+ memmove(client->send_buf, data, size);
+ client->send_size = size;
+ return _SendRequest(client);
+}
+
UDSErr_t UDSSendECUReset(UDSClient_t *client, UDSECUReset_t type) {
PRE_REQUEST_CHECK();
client->send_buf[0] = kSID_ECU_RESET;
diff --git a/iso14229.h b/iso14229.h
index 61675d5..9977d28 100644
--- a/iso14229.h
+++ b/iso14229.h
@@ -236,6 +236,7 @@ typedef uint8_t UDSTpAddr_t;
enum UDSTpStatusFlags {
UDS_TP_IDLE = 0x00000000,
UDS_TP_SEND_IN_PROGRESS = 0x00000001,
+ UDS_TP_RECV_COMPLETE = 0x00000002,
};
typedef uint32_t UDSTpStatus_t;
@@ -253,17 +254,19 @@ typedef enum {
} UDS_A_TA_Type_t;
/**
- * @brief Service data unit (SDU) for the transport layer
+ * @brief Service data unit (SDU)
+ * @details data interface between the application layer and the transport layer
*/
typedef struct {
- UDS_A_Mtype_t A_Mtype;
- uint16_t A_SA; // application source address
- uint16_t A_TA; // application target address
- UDS_A_TA_Type_t A_TA_Type;
- uint16_t A_AE; // application layer remote address
- uint32_t A_Length; // data length
- uint32_t A_DataBufSize;
- const uint8_t *A_Data;
+ UDS_A_Mtype_t A_Mtype; // message type (diagnostic, remote diagnostic, secure diagnostic, secure
+ // remote diagnostic)
+ uint16_t A_SA; // application source address
+ uint16_t A_TA; // application target address
+ UDS_A_TA_Type_t A_TA_Type; // application target address type (physical or functional)
+ uint16_t A_AE; // application layer remote address
+ uint32_t A_Length; // data length
+ uint32_t A_DataBufSize; // buffer size of A_Data
+ uint8_t *A_Data; // pointer to data owned by the application layer
} UDSSDU_t;
/**
@@ -317,6 +320,39 @@ typedef struct {
} UDSTpLinuxIsoTp_t;
#endif
+ssize_t UDSTpSend(UDSTpHandle_t *tp, const uint8_t *buf, size_t len);
+ssize_t UDSTpRecv(UDSTpHandle_t *tp, uint8_t *buf, size_t size);
+
+/**
+ * @brief ISO14229-2 session layer implementation
+ */
+typedef struct {
+ UDSTpHandle_t *tp;
+ uint8_t recv_buf[UDS_BUFSIZE];
+ uint8_t send_buf[UDS_BUFSIZE];
+ uint16_t recv_size;
+ uint16_t send_size;
+ uint16_t recv_buf_size;
+ uint16_t send_buf_size;
+ uint32_t target_addr;
+ uint32_t target_addr_func;
+ uint32_t source_addr;
+ uint32_t source_addr_func;
+} UDSSess_t;
+
+typedef struct {
+ UDSTpHandle_t *tp;
+ uint32_t source_addr;
+ uint32_t source_addr_func;
+ uint32_t target_addr;
+ uint32_t target_addr_func;
+} UDSSessConfig_t;
+
+void UDSSessInit(UDSSess_t *sess, const UDSSessConfig_t *cfg);
+UDSErr_t UDSSessSend(UDSSess_t *sess, const uint8_t *data, size_t len);
+UDSErr_t UDSSessSendFunctional(UDSSess_t *sess, const uint8_t *msg, size_t size);
+void UDSSessPoll(UDSSess_t *sess);
+
// ========================================================================
// Utility Functions
// ========================================================================
@@ -453,6 +489,7 @@ void UDSClientPoll2(UDSClient_t *client,
int (*fn)(UDSClient_t *client, int evt, void *ev_data, void *fn_data),
void *fn_data);
+UDSErr_t UDSSendBytes(UDSClient_t *client, const uint8_t *data, uint16_t size);
UDSErr_t UDSSendECUReset(UDSClient_t *client, UDSECUReset_t type);
UDSErr_t UDSSendDiagSessCtrl(UDSClient_t *client, enum UDSDiagnosticSessionType mode);
UDSErr_t UDSSendSecurityAccess(UDSClient_t *client, uint8_t level, uint8_t *data, uint16_t size);
diff --git a/test/BUILD b/test/BUILD
index d6b30f4..d95f1b2 100644
--- a/test/BUILD
+++ b/test/BUILD
@@ -1,8 +1,20 @@
cc_library(
name = "env",
- srcs = ["env.c", "env.h"],
+ srcs = [
+ "env.c",
+ "env.h",
+ "test.h",
+ "//:iso14229_srcs",
+ "//tp:srcs",
+ ],
deps = [
- "//:iso14229"
+ # "//tp:mock",
+ # "//tp:isotp_sock",
+ ],
+ defines = [
+ "UDS_TP=UDS_TP_CUSTOM",
+ "UDS_CUSTOM_MILLIS",
+ "UDS_DBG_PRINT=printf",
]
)
@@ -11,7 +23,20 @@ cc_library(
name=n.split(".c")[0] ,
srcs=[n],
deps=[":env"],
+ size = "small",
+ env={
+ "TP": "isotp_sock",
+ # "TP": "mock",
+ }
)
for n in glob(["test_*.c"])
-]
\ No newline at end of file
+]
+
+
+sh_test(
+ name = "test_prefix",
+ srcs = ["test_prefix.sh"],
+ data = ["//:iso14229"],
+ args = ["$(locations //:iso14229)"],
+)
\ No newline at end of file
diff --git a/test/env.c b/test/env.c
index ca831f8..dcfa902 100644
--- a/test/env.c
+++ b/test/env.c
@@ -1,37 +1,187 @@
#include "test/env.h"
#include "iso14229.h"
+#include
#include
#include
#include
+#include "tp/mock.h"
+#include "tp/isotp_sock.h"
-UDSTpHandle_t *Handles[8] = {0};
-unsigned HandleCount = 0;
+static UDSServer_t *registeredServer = NULL;
+static UDSClient_t *registeredClient = NULL;
+static UDSSess_t *registeredSess = NULL;
+static uint32_t TimeNowMillis = 0;
+typedef struct {
-UDSTpHandle_t *ENV_TpNew() {
- if (HandleCount >= sizeof(Handles) / sizeof(Handles[0])) {
- fprintf(stderr, "Too many TP handles\n");
- return NULL;
+} ENV_t;
+
+struct IntOpt {
+ const char *name;
+ int *val;
+};
+
+enum {
+ OPTS_TP_TYPE_MOCK,
+ OPTS_TP_TYPE_ISOTP_SOCK,
+};
+
+typedef struct {
+ int tp_type;
+ char ifname[32];
+ uint32_t srv_src_addr, srv_target_addr, srv_src_addr_func;
+ uint32_t cli_src_addr, cli_target_addr, cli_tgt_addr_func;
+} Cfg_t;
+
+static Cfg_t cfg;
+
+// static struct IntOpt IntOpts[] = {
+// {"TP_TYPE", &opts.tp_type},
+// };
+
+void ENV_ServerInit(UDSServer_t *srv) {
+ UDSTpHandle_t *tp = NULL;
+ switch (cfg.tp_type) {
+ case OPTS_TP_TYPE_MOCK:
+ tp = TPMockCreate("server");
+ break;
+ case OPTS_TP_TYPE_ISOTP_SOCK: {
+ UDSTpIsoTpSock_t *isotp = malloc(sizeof(UDSTpIsoTpSock_t));
+ strcpy(isotp->tag, "server");
+ assert(UDS_OK == UDSTpIsoTpSockInitServer(isotp, cfg.ifname,
+ cfg.srv_src_addr, cfg.srv_target_addr,
+ cfg.srv_src_addr_func));
+ tp = (UDSTpHandle_t *)isotp;
+ break;
+ }
+ default:
+ printf("unknown TP type: %d\n", cfg.tp_type);
+ exit(1);
}
- UDSTpHandle_t *tp = malloc(sizeof(UDSTpHandle_t));
- memset(tp, 0, sizeof(UDSTpHandle_t));
- Handles[HandleCount++] = tp;
- return tp;
+
+ UDSServerInit(srv, &(UDSServerConfig_t){
+ .fn = NULL,
+ .tp = tp,
+ .source_addr = 0x7E8,
+ .target_addr = 0x7E0,
+ .source_addr_func = 0x7DF,
+ });
+ ENV_RegisterServer(srv);
}
-void ENV_Send(UDSSDU_t *msg) {
- assert(msg);
- for (unsigned i = 0; i < HandleCount; i++) {
- UDSTpHandle_t *tp = Handles[i];
- if (tp == NULL) {
- continue;
+void ENV_ClientInit(UDSClient_t *cli) {
+ UDSTpHandle_t *tp = NULL;
+ switch (cfg.tp_type) {
+ case OPTS_TP_TYPE_MOCK:
+ tp = TPMockCreate("client");
+ break;
+ case OPTS_TP_TYPE_ISOTP_SOCK: {
+ UDSTpIsoTpSock_t *isotp = malloc(sizeof(UDSTpIsoTpSock_t));
+ strcpy(isotp->tag, "client");
+ assert(UDS_OK == UDSTpIsoTpSockInitClient(isotp, cfg.ifname,
+ cfg.cli_src_addr, cfg.cli_target_addr,
+ cfg.cli_tgt_addr_func));
+ tp = (UDSTpHandle_t *)isotp;
+ break;
+ }
+ default:
+ printf("unknown TP type: %d\n", cfg.tp_type);
+ exit(1);
+ }
+
+ UDSClientInit(cli, &(UDSClientConfig_t){
+ .tp = tp,
+ .source_addr = 0x7E0,
+ .target_addr = 0x7E8,
+ .target_addr_func = 0x7DF,
+ });
+ ENV_RegisterClient(cli);
+}
+
+void ENV_SessInit(UDSSess_t *sess, const char *name) {
+ UDSTpHandle_t *tp = NULL;
+ switch (cfg.tp_type) {
+ case OPTS_TP_TYPE_MOCK:
+ tp = TPMockCreate(name);
+ break;
+ case OPTS_TP_TYPE_ISOTP_SOCK: {
+ UDSTpIsoTpSock_t *isotp = malloc(sizeof(UDSTpIsoTpSock_t));
+ strncpy(isotp->tag, name, sizeof(isotp->tag));
+ assert(UDS_OK == UDSTpIsoTpSockInitClient(isotp, cfg.ifname,
+ cfg.cli_src_addr, cfg.cli_target_addr,
+ cfg.cli_tgt_addr_func));
+ tp = (UDSTpHandle_t *)isotp;
+ break;
+ }
+ default:
+ printf("unknown TP type: %d\n", cfg.tp_type);
+ exit(1);
+ }
+
+ UDSSessInit(sess, &(UDSSessConfig_t){
+ .tp = tp,
+ .source_addr = 0x7E0,
+ .target_addr = 0x7E8,
+ .target_addr_func = 0x7DF,
+ });
+ ENV_RegisterSess(sess);
+}
+
+void ENV_RegisterServer(UDSServer_t *server) { registeredServer = server; }
+
+void ENV_RegisterClient(UDSClient_t *client) { registeredClient = client; }
+
+void ENV_RegisterSess(UDSSess_t *sess) { registeredSess = sess; }
+
+uint32_t UDSMillis() { return TimeNowMillis; }
+
+// actually sleep for milliseconds
+void msleep(int ms) {
+ usleep(ms * 1000);
+}
+
+void ENV_RunMillis(uint32_t millis) {
+ uint32_t end = UDSMillis() + millis;
+ while (UDSMillis() < end) {
+ if (registeredServer) {
+ UDSServerPoll(registeredServer);
+ }
+ if (registeredClient) {
+ UDSClientPoll(registeredClient);
+ }
+ if (registeredSess) {
+ UDSSessPoll(registeredSess);
+ }
+ TimeNowMillis++;
+
+ // uses vcan, needs delay
+ if (cfg.tp_type == OPTS_TP_TYPE_ISOTP_SOCK) {
+ usleep(10);
+ // msleep(1);
}
- if (tp->)
- UDSTpSend(tp, msg);
}
- UDSTpHandle_t *tp = msg->A_TP;
- if (tp == NULL) {
- tp = ENV_TpNew();
- msg->A_TP = tp;
+}
+
+struct opts {
+ const char *arg;
+};
+
+
+void ENV_ParseOpts(int argc, char **argv) {
+ snprintf(cfg.ifname, sizeof(cfg.ifname), "vcan0");
+ cfg.srv_src_addr = 0x7E8;
+ cfg.srv_target_addr = 0x7E0;
+ cfg.srv_src_addr_func = 0x7DF;
+ cfg.cli_src_addr = 0x7E0;
+ cfg.cli_target_addr = 0x7E8;
+ cfg.cli_tgt_addr_func = 0x7DF;
+
+ const char *tp = getenv("TP");
+ if (0 == strcasecmp(tp, "mock")) {
+ cfg.tp_type = OPTS_TP_TYPE_MOCK;
+ } else if (0 == strcasecmp(tp, "isotp_sock")) {
+ cfg.tp_type = OPTS_TP_TYPE_ISOTP_SOCK;
+ } else {
+ printf("unknown TP: %s\n", tp);
+ exit(1);
}
- UDSTpSend(tp, msg);
}
\ No newline at end of file
diff --git a/test/env.h b/test/env.h
index 783d952..54b38ca 100644
--- a/test/env.h
+++ b/test/env.h
@@ -3,15 +3,30 @@
#include "iso14229.h"
#include
+#include
+#include
-UDSTpHandle_t *ENV_TpNew();
+void ENV_ServerInit(UDSServer_t *srv);
+void ENV_ClientInit(UDSClient_t *client);
+void ENV_SessInit(UDSSess_t *sess, const char *name);
-void ENV_Send(UDSSDU_t *msg);
+#define ENV_SERVER_INIT(srv) \
+ ENV_ParseOpts(0, NULL); \
+ ENV_ServerInit(&srv); \
+ TPMockLogToStdout();
-#define ENV_EXPECT_MSG_WITHIN_MILLIS(msg_ptr, millis) \
- do { \
- UDSSDU_t *msg = (msg_ptr); \
- ENV_ExpectBytesWithinMillis(ENV_TpNew(), msg->A_Data, msg->A_Length, millis); \
- } while (0)
+#define ENV_CLIENT_INIT(client) \
+ ENV_ClientInit(&client); \
+ TPMockLogToStdout();
-#endif
\ No newline at end of file
+#define ENV_SESS_INIT(sess) \
+ ENV_SessInit(&sess, #sess); \
+ TPMockLogToStdout();
+
+void ENV_RegisterServer(UDSServer_t *server);
+void ENV_RegisterClient(UDSClient_t *client);
+void ENV_RegisterSess(UDSSess_t *sess);
+void ENV_RunMillis(uint32_t millis);
+void ENV_ParseOpts(int argc, char **argv);
+
+#endif
diff --git a/test/test.c b/test/test.c
deleted file mode 100644
index e69de29..0000000
diff --git a/test/test.h b/test/test.h
index 000f6dd..d2d79f0 100644
--- a/test/test.h
+++ b/test/test.h
@@ -1,6 +1,104 @@
+#ifndef TEST_TEST_H
+#define TEST_TEST_H
-#define TEST_SETUP()
+#include
+#include
+#include
+#include "iso14229.h"
+#include "test/env.h"
+#include "tp/mock.h"
-typedef struct {
+#define _TEST_INT_COND(a, b, cond) \
+ { \
+ int _a = a; \
+ int _b = b; \
+ if (!((_a)cond(_b))) { \
+ printf("%s:%d (%d %s %d)\n", __FILE__, __LINE__, _a, #cond, _b); \
+ fflush(stdout); \
+ assert(a cond b); \
+ } \
+ }
-} TestCtx_t;
+#define TEST_INT_LT(a, b) _TEST_INT_COND(a, b, <)
+#define TEST_INT_LE(a, b) _TEST_INT_COND(a, b, <=)
+#define TEST_INT_GE(a, b) _TEST_INT_COND(a, b, >=)
+#define TEST_INT_EQUAL(a, b) _TEST_INT_COND(a, b, ==)
+#define TEST_INT_NE(a, b) _TEST_INT_COND(a, b, !=)
+
+#define TEST_PTR_EQUAL(a, b) \
+ { \
+ const void *_a = a; \
+ const void *_b = b; \
+ if ((_a) != (_b)) { \
+ printf("%s:%d (%p != %p)\n", __FILE__, __LINE__, _a, _b); \
+ fflush(stdout); \
+ assert(a == b); \
+ } \
+ }
+
+#define TEST_MEMORY_EQUAL(a, b, len) \
+ { \
+ const uint8_t *_a = (const uint8_t *)a; \
+ const uint8_t *_b = (const uint8_t *)b; \
+ if (memcmp(_a, _b, len)) { \
+ printf("A:"); \
+ for (unsigned int i = 0; i < len; i++) { \
+ printf("%02x,", _a[i]); \
+ } \
+ printf(" (%s)\nB:", #a); \
+ for (unsigned int i = 0; i < len; i++) { \
+ printf("%02x,", _b[i]); \
+ } \
+ printf(" (%s)\n", #b); \
+ fflush(stdout); \
+ assert(0); \
+ } \
+ }
+
+// expect a server response within a timeout
+#define EXPECT_RESPONSE_WITHIN_MILLIS(d1, timeout_ms) \
+ { \
+ uint32_t deadline = UDSMillis() + timeout_ms + 1; \
+ uint8_t buf[UDS_BUFSIZE]; \
+ UDSSDU_t msg = { \
+ .A_DataBufSize = sizeof(buf), \
+ .A_Data = buf, \
+ }; \
+ while (0 == UDSTpRecv(mock_tp, &msg)) { \
+ TEST_INT_LE(UDSMillis(), deadline); \
+ ENV_RunMillis(1); \
+ } \
+ TEST_INT_EQUAL(msg.A_Length, sizeof(d1)); \
+ TEST_MEMORY_EQUAL(msg.A_Data, d1, sizeof(d1)); \
+ }
+
+#define EXPECT_RECV_WITHIN_MILLIS(tp, msg, timeout_ms) \
+ { \
+ \
+ uint32_t deadline = UDSMillis() + timeout_ms + 1; \
+ while (0 == UDSTpRecv(tp, msg)) { \
+ TEST_INT_LE(UDSMillis(), deadline); \
+ ENV_RunMillis(1); \
+ } \
+ }
+
+#define EXPECT_OK(stmt) \
+ { \
+ int _ret = stmt; \
+ if (_ret != UDS_OK) { \
+ printf("%s:%d (%d != %d)\n", __FILE__, __LINE__, _ret, UDS_OK); \
+ fflush(stdout); \
+ assert(_ret == UDS_OK); \
+ } \
+ }
+
+#define EXPECT_WITHIN_MS(cond, timeout_ms) \
+ { \
+ uint32_t deadline = UDSMillis() + timeout_ms + 1; \
+ while (!(cond)) { \
+ TEST_INT_LE(UDSMillis(), deadline); \
+ ENV_RunMillis(1); \
+ } \
+ }
+
+#endif
diff --git a/test/test_client_0x11_ECU_reset.c b/test/test_client_0x11_ECU_reset.c
new file mode 100644
index 0000000..f9a88ee
--- /dev/null
+++ b/test/test_client_0x11_ECU_reset.c
@@ -0,0 +1,55 @@
+#include "test/test.h"
+
+int main() {
+ UDSClient_t client;
+ UDSSess_t mock_srv;
+
+ const uint8_t GOOD[] = {0x51, 0x01};
+ const uint8_t BAD_SID[] = {0x50, 0x01};
+ const uint8_t TOO_SHORT[] = {0x51};
+ const uint8_t BAD_SUBFUNC[] = {0x51, 0x02};
+ const uint8_t NEG[] = {0x7F, 0x11, 0x10};
+
+#define CASE(d1, opt, err) \
+ { \
+ .tag = "client options:" #opt ", server resp: " #d1 ", expected_err: " #err, .resp = d1, \
+ .resp_len = sizeof(d1), .options = opt, .expected_err = err \
+ }
+
+ struct {
+ const char *tag;
+ const uint8_t *resp;
+ size_t resp_len;
+ uint8_t options;
+ UDSErr_t expected_err;
+ } p[] = {
+ CASE(GOOD, 0, UDS_OK),
+ CASE(BAD_SID, 0, UDS_ERR_SID_MISMATCH),
+ CASE(TOO_SHORT, 0, UDS_ERR_RESP_TOO_SHORT),
+ CASE(BAD_SUBFUNC, 0, UDS_ERR_SUBFUNCTION_MISMATCH),
+ CASE(NEG, 0, UDS_OK),
+ CASE(NEG, UDS_NEG_RESP_IS_ERR, UDS_ERR_NEG_RESP),
+ CASE(GOOD, UDS_NEG_RESP_IS_ERR, UDS_OK),
+ CASE(GOOD, UDS_SUPPRESS_POS_RESP, UDS_OK), // Should this case pass?
+ };
+
+ for (size_t i = 0; i < sizeof(p) / sizeof(p[0]); i++) {
+ ENV_CLIENT_INIT(client);
+ ENV_SESS_INIT(mock_srv);
+ printf("test %ld: %s\n", i, p[i].tag);
+
+ // when the client sends a ECU reset request with these options
+ client.options = p[i].options;
+ UDSSendECUReset(&client, kHardReset);
+
+ // and the server responds with this message
+ EXPECT_OK(UDSSessSend(&mock_srv, p[i].resp, p[i].resp_len));
+
+ // then the client should receive a response with this error code
+ ENV_RunMillis(50);
+ TEST_INT_EQUAL(client.state, kRequestStateIdle);
+ TEST_INT_EQUAL(client.err, p[i].expected_err);
+ // assert(client.err == p[i].expected_err);
+ TPMockReset();
+ }
+}
\ No newline at end of file
diff --git a/test/test_client_0x22_RDBI_tx_buffer_too_small.c b/test/test_client_0x22_RDBI_tx_buffer_too_small.c
new file mode 100644
index 0000000..517a05e
--- /dev/null
+++ b/test/test_client_0x22_RDBI_tx_buffer_too_small.c
@@ -0,0 +1,19 @@
+#include "test/test.h"
+
+int main() {
+ UDSClient_t client;
+ ENV_CLIENT_INIT(client);
+
+ // attempting to send a request payload of 6 bytes
+ uint16_t didList[] = {0x0001, 0x0002, 0x0003};
+
+ // which is larger than the underlying buffer
+ client.send_buf_size = 4;
+
+ // should return an error
+ TEST_INT_EQUAL(UDS_ERR_INVALID_ARG,
+ UDSSendRDBI(&client, didList, sizeof(didList) / sizeof(didList[0])))
+
+ // and no data should be sent
+ TEST_INT_EQUAL(client.send_size, 0);
+}
\ No newline at end of file
diff --git a/test/test_client_0x22_RDBI_unpack_response.c b/test/test_client_0x22_RDBI_unpack_response.c
new file mode 100644
index 0000000..01b2a16
--- /dev/null
+++ b/test/test_client_0x22_RDBI_unpack_response.c
@@ -0,0 +1,28 @@
+#include "test/test.h"
+
+int main() {
+ UDSClient_t client;
+ ENV_CLIENT_INIT(client);
+
+ uint8_t RESPONSE[] = {0x72, 0x12, 0x34, 0x00, 0x00, 0xAA, 0x00, 0x56, 0x78, 0xAA, 0xBB};
+ memmove(client.recv_buf, RESPONSE, sizeof(RESPONSE));
+ client.recv_size = sizeof(RESPONSE);
+ uint8_t buf[4];
+ uint16_t offset = 0;
+ int err = 0;
+ err = UDSUnpackRDBIResponse(&client, 0x1234, buf, 4, &offset);
+ TEST_INT_EQUAL(err, UDS_OK);
+ uint32_t d0 = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3];
+ TEST_INT_EQUAL(d0, 0x0000AA00);
+ err = UDSUnpackRDBIResponse(&client, 0x1234, buf, 2, &offset);
+ TEST_INT_EQUAL(err, UDS_ERR_DID_MISMATCH);
+ err = UDSUnpackRDBIResponse(&client, 0x5678, buf, 20, &offset);
+ TEST_INT_EQUAL(err, UDS_ERR_RESP_TOO_SHORT);
+ err = UDSUnpackRDBIResponse(&client, 0x5678, buf, 2, &offset);
+ TEST_INT_EQUAL(err, UDS_OK);
+ uint16_t d1 = (buf[0] << 8) + buf[1];
+ TEST_INT_EQUAL(d1, 0xAABB);
+ err = UDSUnpackRDBIResponse(&client, 0x5678, buf, 1, &offset);
+ TEST_INT_EQUAL(err, UDS_ERR_RESP_TOO_SHORT);
+ TEST_INT_EQUAL(offset, sizeof(RESPONSE));
+}
\ No newline at end of file
diff --git a/test/test_client_0x31_RCRRP.c b/test/test_client_0x31_RCRRP.c
new file mode 100644
index 0000000..ff196df
--- /dev/null
+++ b/test/test_client_0x31_RCRRP.c
@@ -0,0 +1,53 @@
+#include "test/test.h"
+
+int main() {
+ UDSClient_t client;
+ UDSSess_t sess;
+ ENV_SESS_INIT(sess)
+
+ { // Case 1: RCRRP Timeout
+ ENV_CLIENT_INIT(client);
+ // When a request is sent
+ UDSSendRoutineCtrl(&client, kStartRoutine, 0x1234, NULL, 0);
+
+ // that receives an RCRRP response
+ const uint8_t RCRRP[] = {0x7F, 0x31, 0x78}; // RequestCorrectly-ReceievedResponsePending
+ UDSSessSend(&sess, RCRRP, sizeof(RCRRP));
+
+ // that remains unresolved at a time between p2 ms and p2 star ms
+ ENV_RunMillis(UDS_CLIENT_DEFAULT_P2_MS + 10);
+ // the client should still be pending.
+ TEST_INT_EQUAL(kRequestStateAwaitResponse, client.state)
+
+ // after p2_star has elapsed, the client should timeout
+ ENV_RunMillis(UDS_CLIENT_DEFAULT_P2_STAR_MS + 10);
+ TEST_INT_EQUAL(kRequestStateIdle, client.state)
+ TEST_INT_EQUAL(client.err, UDS_ERR_TIMEOUT);
+ }
+
+ { // Case 2: Positive Response Received
+ ENV_CLIENT_INIT(client);
+ // When a request is sent
+ UDSSendRoutineCtrl(&client, kStartRoutine, 0x1234, NULL, 0);
+
+ // that receives an RCRRP response
+ const uint8_t RCRRP[] = {0x7F, 0x31, 0x78}; // RequestCorrectly-ReceievedResponsePending
+ UDSSessSend(&sess, RCRRP, sizeof(RCRRP));
+
+ // that remains unresolved at a time between p2 ms and p2 star ms
+ ENV_RunMillis(UDS_CLIENT_DEFAULT_P2_MS + 10);
+ // the client should still be pending.
+ TEST_INT_EQUAL(client.err, UDS_OK);
+ TEST_INT_EQUAL(kRequestStateAwaitResponse, client.state)
+
+ // When the client receives a positive response from the server
+ const uint8_t POSITIVE_RESPONSE[] = {0x71, 0x01, 0x12, 0x34};
+ UDSSessSend(&sess, POSITIVE_RESPONSE, sizeof(POSITIVE_RESPONSE));
+
+ ENV_RunMillis(5);
+
+ // the client should return to the idle state with no error
+ TEST_INT_EQUAL(kRequestStateIdle, client.state)
+ TEST_INT_EQUAL(client.err, UDS_OK);
+ }
+}
\ No newline at end of file
diff --git a/test/test_client_0x34_request_download.c b/test/test_client_0x34_request_download.c
new file mode 100644
index 0000000..e799c8f
--- /dev/null
+++ b/test/test_client_0x34_request_download.c
@@ -0,0 +1,13 @@
+#include "test/test.h"
+
+int main() {
+ UDSClient_t client;
+ ENV_CLIENT_INIT(client);
+
+ // When the client sends a request download request
+ EXPECT_OK(UDSSendRequestDownload(&client, 0x11, 0x33, 0x602000, 0x00FFFF));
+
+ // the bytes sent should match UDS-1 2013 Table 415
+ const uint8_t CORRECT_REQUEST[] = {0x34, 0x11, 0x33, 0x60, 0x20, 0x00, 0x00, 0xFF, 0xFF};
+ TEST_MEMORY_EQUAL(client.send_buf, CORRECT_REQUEST, sizeof(CORRECT_REQUEST));
+}
\ No newline at end of file
diff --git a/test/test_client_busy.c b/test/test_client_busy.c
new file mode 100644
index 0000000..de2dec9
--- /dev/null
+++ b/test/test_client_busy.c
@@ -0,0 +1,12 @@
+#include "test/test.h"
+
+int main() {
+ UDSClient_t client;
+ ENV_CLIENT_INIT(client);
+
+ // Sending a request should not return an error
+ EXPECT_OK(UDSSendECUReset(&client, kHardReset));
+
+ // unless there is an existing unresolved request
+ TEST_INT_EQUAL(UDS_ERR_BUSY, UDSSendECUReset(&client, kHardReset));
+}
\ No newline at end of file
diff --git a/test/test_client_p2.c b/test/test_client_p2.c
new file mode 100644
index 0000000..bdba6de
--- /dev/null
+++ b/test/test_client_p2.c
@@ -0,0 +1,35 @@
+#include "test/test.h"
+
+int main() {
+ UDSClient_t client;
+ UDSSess_t sess;
+ ENV_SESS_INIT(sess);
+
+ { // Case 1: P2 not exceeded
+ ENV_CLIENT_INIT(client);
+
+ // When the client sends a request
+ EXPECT_OK(UDSSendECUReset(&client, kHardReset));
+
+ // which receives a positive response
+ const uint8_t POSITIVE_RESPONSE[] = {0x51, 0x01};
+ UDSSessSend(&sess, POSITIVE_RESPONSE, sizeof(POSITIVE_RESPONSE));
+ ENV_RunMillis(20);
+
+ // after p2 ms has elapsed, the client should have a timeout error
+ TEST_INT_EQUAL(UDS_OK, client.err);
+ }
+ { // Case 2: P2 exceeded
+ ENV_CLIENT_INIT(client);
+
+ // When the client sends a request
+ EXPECT_OK(UDSSendECUReset(&client, kHardReset));
+
+ ENV_RunMillis(UDS_CLIENT_DEFAULT_P2_MS - 10);
+ // before p2 ms has elapsed, the client should have no error
+ TEST_INT_EQUAL(UDS_OK, client.err);
+
+ ENV_RunMillis(20);
+ TEST_INT_EQUAL(UDS_ERR_TIMEOUT, client.err);
+ }
+}
\ No newline at end of file
diff --git a/test/test_client_suppress_positive_response.c b/test/test_client_suppress_positive_response.c
new file mode 100644
index 0000000..2b761b6
--- /dev/null
+++ b/test/test_client_suppress_positive_response.c
@@ -0,0 +1,17 @@
+#include "test/test.h"
+
+int main() {
+ UDSClient_t client;
+ ENV_CLIENT_INIT(client);
+
+ // Setting the suppressPositiveResponse flag before sending a request
+ client.options |= UDS_SUPPRESS_POS_RESP;
+ UDSSendECUReset(&client, kHardReset);
+
+ // and not receiving a response after approximately p2 ms
+ ENV_RunMillis(UDS_CLIENT_DEFAULT_P2_MS + 10);
+
+ // should not result in an error.
+ TEST_INT_EQUAL(UDS_OK, client.err);
+ TEST_INT_EQUAL(kRequestStateIdle, client.state);
+}
diff --git a/test/test_server_0x10_diag_sess_ctrl.c b/test/test_server_0x10_diag_sess_ctrl.c
deleted file mode 100644
index 94746f0..0000000
--- a/test/test_server_0x10_diag_sess_ctrl.c
+++ /dev/null
@@ -1,45 +0,0 @@
-
-
-#include "iso14229.h"
-#include "test/env.h"
-
-uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
- printf("holy shit\n");
- return kServiceNotSupported;
-}
-
-int main() {
- UDSServer_t srv;
- UDSTpHandle_t *tp = ENV_TpNew();
- UDSServerInit(&srv, &(UDSServerConfig_t){
- .fn = fn,
- .tp = tp,
- });
-
- const uint8_t REQ[] = {0x10, 0x02};
-
- UDSSDU_t req = {
- .A_Mtype = UDS_A_MTYPE_DIAG,
- .A_SA = 0x7E0,
- .A_TA = 0x7E8,
- .A_TA_Type = UDS_A_TA_TYPE_PHYSICAL,
- .A_Length = sizeof(REQ),
- .A_Data = REQ,
- };
-
- ENV_Send(&req);
-
- UDSSDU_t resp;
- ENV_EXPECT_MSG_WITHIN_MILLIS(&resp, 50);
- const uint8_t EXP_RESP[] = {0x7f, 0x10, 0x11};
- ASSERT_BYTES_EQUAL(resp.A_Data, EXP_RESP, sizeof(EXP_RESP));
-}
-
-void testServer0x10DiagSessCtrlIsDisabledByDefault() {
- TEST_SETUP(CLIENT_ONLY);
- const uint8_t REQ[] = {0x10, 0x02};
- SEND_TO_SERVER(REQ, kTpAddrTypePhysical);
- const uint8_t RESP[] = {0x7f, 0x10, 0x11};
- EXPECT_RESPONSE_WITHIN_MILLIS(RESP, kTpAddrTypePhysical, 50);
- TEST_TEARDOWN();
-}
diff --git a/test/test_server_0x10_diag_sess_ctrl_functional_request.c b/test/test_server_0x10_diag_sess_ctrl_functional_request.c
new file mode 100644
index 0000000..8900119
--- /dev/null
+++ b/test/test_server_0x10_diag_sess_ctrl_functional_request.c
@@ -0,0 +1,17 @@
+#include "test/test.h"
+
+int main() {
+ UDSSess_t mock_client;
+ UDSServer_t srv;
+ ENV_SERVER_INIT(srv);
+ ENV_SESS_INIT(mock_client);
+
+ // When server is sent a diagnostic session control request
+ const uint8_t REQ[] = {0x10, 0x02};
+ EXPECT_OK(UDSSessSendFunctional(&mock_client, REQ, sizeof(REQ)));
+
+ // the server should respond with a negative response within p2 ms
+ const uint8_t EXP_RESP[] = {0x7f, 0x10, 0x11};
+ EXPECT_WITHIN_MS((mock_client.recv_size > 0), 50);
+ TEST_MEMORY_EQUAL(mock_client.recv_buf, EXP_RESP, sizeof(EXP_RESP));
+}
diff --git a/test/test_server_0x10_diag_sess_ctrl_is_disabled_by_default.c b/test/test_server_0x10_diag_sess_ctrl_is_disabled_by_default.c
new file mode 100644
index 0000000..79aa105
--- /dev/null
+++ b/test/test_server_0x10_diag_sess_ctrl_is_disabled_by_default.c
@@ -0,0 +1,17 @@
+#include "test/test.h"
+
+int main() {
+ UDSSess_t mock_client;
+ UDSServer_t srv;
+ ENV_SERVER_INIT(srv);
+ ENV_SESS_INIT(mock_client);
+
+ // When server is sent a diagnostic session control request
+ const uint8_t REQ[] = {0x10, 0x02};
+ EXPECT_OK(UDSSessSend(&mock_client, REQ, sizeof(REQ)));
+
+ // the server should respond with a negative response within p2 ms
+ const uint8_t EXP_RESP[] = {0x7f, 0x10, 0x11};
+ EXPECT_WITHIN_MS((mock_client.recv_size > 0), 50);
+ TEST_MEMORY_EQUAL(mock_client.recv_buf, EXP_RESP, sizeof(EXP_RESP));
+}
diff --git a/test/test_server_0x11_no_send_recv_after_ECU_reset.c b/test/test_server_0x11_no_send_recv_after_ECU_reset.c
new file mode 100644
index 0000000..c1878aa
--- /dev/null
+++ b/test/test_server_0x11_no_send_recv_after_ECU_reset.c
@@ -0,0 +1,39 @@
+#include "test/test.h"
+
+uint8_t fn_callCount = 0;
+uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
+ switch (ev) {
+ case UDS_SRV_EVT_EcuReset:
+ fn_callCount += 1;
+ return kPositiveResponse;
+ default:
+ TEST_INT_EQUAL(UDS_SRV_EVT_DoScheduledReset, ev);
+ return kPositiveResponse;
+ }
+}
+
+int main() {
+ UDSSess_t mock_client;
+ UDSServer_t srv;
+ ENV_SERVER_INIT(srv);
+ ENV_SESS_INIT(mock_client);
+ srv.fn = fn;
+
+ const uint8_t REQ[] = {0x11, 0x01};
+ const uint8_t RESP[] = {0x51, 0x01};
+
+ // Sending the first ECU reset should result in a response
+ EXPECT_OK(UDSSessSend(&mock_client, REQ, sizeof(REQ)));
+ ENV_RunMillis(50);
+ TEST_MEMORY_EQUAL(mock_client.recv_buf, RESP, sizeof(RESP));
+
+ mock_client.recv_size = 0;
+
+ // Sending subsequent ECU reset requests should not receive any response
+ EXPECT_OK(UDSSessSend(&mock_client, REQ, sizeof(REQ)));
+ ENV_RunMillis(5000);
+ TEST_INT_EQUAL(mock_client.recv_size, 0);
+
+ // The ECU reset handler should have been called once.
+ TEST_INT_EQUAL(fn_callCount, 1);
+}
diff --git a/test/test_server_0x22_RDBI.c b/test/test_server_0x22_RDBI.c
new file mode 100644
index 0000000..95ba794
--- /dev/null
+++ b/test/test_server_0x22_RDBI.c
@@ -0,0 +1,48 @@
+#include "test/test.h"
+
+uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
+ TEST_INT_EQUAL(UDS_SRV_EVT_ReadDataByIdent, ev);
+ const uint8_t vin[] = {0x57, 0x30, 0x4C, 0x30, 0x30, 0x30, 0x30, 0x34, 0x33,
+ 0x4D, 0x42, 0x35, 0x34, 0x31, 0x33, 0x32, 0x36};
+ const uint8_t data_0x010A[] = {0xA6, 0x66, 0x07, 0x50, 0x20, 0x1A,
+ 0x00, 0x63, 0x4A, 0x82, 0x7E};
+ const uint8_t data_0x0110[] = {0x8C};
+
+ UDSRDBIArgs_t *r = (UDSRDBIArgs_t *)arg;
+ switch (r->dataId) {
+ case 0xF190:
+ return r->copy(srv, vin, sizeof(vin));
+ case 0x010A:
+ return r->copy(srv, data_0x010A, sizeof(data_0x010A));
+ case 0x0110:
+ return r->copy(srv, data_0x0110, sizeof(data_0x0110));
+ default:
+ return kRequestOutOfRange;
+ }
+ return kPositiveResponse;
+}
+
+int main() {
+ UDSSess_t mock_client;
+ UDSServer_t srv;
+ ENV_SERVER_INIT(srv);
+ srv.fn = fn;
+ ENV_SESS_INIT(mock_client);
+ { // 11.2.5.2 Example #1 read single dataIdentifier 0xF190
+ uint8_t REQ[] = {0x22, 0xF1, 0x90};
+ UDSSessSend(&mock_client, REQ, sizeof(REQ));
+ uint8_t RESP[] = {0x62, 0xF1, 0x90, 0x57, 0x30, 0x4C, 0x30, 0x30, 0x30, 0x30,
+ 0x34, 0x33, 0x4D, 0x42, 0x35, 0x34, 0x31, 0x33, 0x32, 0x36};
+ ENV_RunMillis(50);
+ TEST_INT_EQUAL(mock_client.recv_size, sizeof(RESP));
+ TEST_MEMORY_EQUAL(mock_client.recv_buf, RESP, sizeof(RESP));
+ }
+ { // Read a nonexistent dataIdentifier 0xF191
+ uint8_t REQ[] = {0x22, 0xF1, 0x91};
+ UDSSessSend(&mock_client, REQ, sizeof(REQ));
+ uint8_t RESP[] = {0x7F, 0x22, 0x31};
+ ENV_RunMillis(50);
+ TEST_INT_EQUAL(mock_client.recv_size, sizeof(RESP));
+ TEST_MEMORY_EQUAL(mock_client.recv_buf, RESP, sizeof(RESP));
+ }
+}
diff --git a/test/test_server_0x23_read_memory_by_address.c b/test/test_server_0x23_read_memory_by_address.c
new file mode 100644
index 0000000..8e3c0b9
--- /dev/null
+++ b/test/test_server_0x23_read_memory_by_address.c
@@ -0,0 +1,29 @@
+#include "test/test.h"
+
+uint8_t fn10(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
+ printf("foo!\n");
+ TEST_INT_EQUAL(ev, UDS_SRV_EVT_ReadMemByAddr);
+ UDSReadMemByAddrArgs_t *r = (UDSReadMemByAddrArgs_t *)arg;
+ // 1 2 3 4 5 6 7 8
+ TEST_PTR_EQUAL(r->memAddr, (void *)0x000055555555f0c8);
+ TEST_INT_EQUAL(r->memSize, 4);
+ uint8_t FakeData[4] = {0x01, 0x02, 0x03, 0x04};
+ return r->copy(srv, FakeData, r->memSize);
+}
+
+int main() {
+ UDSSess_t mock_client;
+ UDSServer_t srv;
+ ENV_SERVER_INIT(srv);
+ srv.fn = fn10;
+ ENV_SESS_INIT(mock_client);
+
+ // When the client sends a request download request
+ const uint8_t REQ[] = {0x23, 0x18, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0xf0, 0xc8, 0x04};
+ EXPECT_OK(UDSSessSend(&mock_client, REQ, sizeof(REQ)));
+
+ // the server should respond with a positive response within p2 ms
+ uint8_t RESP[] = {0x63, 0x01, 0x02, 0x03, 0x04};
+ EXPECT_WITHIN_MS((mock_client.recv_size > 0), 50);
+ TEST_MEMORY_EQUAL(mock_client.recv_buf, RESP, sizeof(RESP));
+}
\ No newline at end of file
diff --git a/test/test_server_0x27_security_access.c b/test/test_server_0x27_security_access.c
new file mode 100644
index 0000000..d1fdc96
--- /dev/null
+++ b/test/test_server_0x27_security_access.c
@@ -0,0 +1,66 @@
+#include "test/test.h"
+
+// UDS-1 2013 9.4.5.2
+// UDS-1 2013 9.4.5.3
+uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
+ switch (ev) {
+ case UDS_SRV_EVT_SecAccessRequestSeed: {
+ UDSSecAccessRequestSeedArgs_t *r = (UDSSecAccessRequestSeedArgs_t *)arg;
+ const uint8_t seed[] = {0x36, 0x57};
+ TEST_INT_NE(r->level, srv->securityLevel);
+ return r->copySeed(srv, seed, sizeof(seed));
+ break;
+ }
+ case UDS_SRV_EVT_SecAccessValidateKey: {
+ UDSSecAccessValidateKeyArgs_t *r = (UDSSecAccessValidateKeyArgs_t *)arg;
+ const uint8_t expected_key[] = {0xC9, 0xA9};
+ TEST_INT_EQUAL(r->len, sizeof(expected_key));
+ TEST_MEMORY_EQUAL(r->key, expected_key, sizeof(expected_key));
+ break;
+ }
+ default:
+ assert(0);
+ }
+ return kPositiveResponse;
+}
+
+int main() {
+ UDSSess_t mock_client;
+ UDSServer_t srv;
+ ENV_SERVER_INIT(srv);
+ srv.fn = fn;
+ ENV_SESS_INIT(mock_client);
+
+ // the server security level after initialization should be 0
+ TEST_INT_EQUAL(srv.securityLevel, 0);
+
+ // sending a seed request should get this response
+ const uint8_t SEED_REQUEST[] = {0x27, 0x01};
+ const uint8_t SEED_RESPONSE[] = {0x67, 0x01, 0x36, 0x57};
+ EXPECT_OK(UDSSessSend(&mock_client, SEED_REQUEST, sizeof(SEED_REQUEST)));
+ ENV_RunMillis(50);
+ TEST_MEMORY_EQUAL(mock_client.recv_buf, SEED_RESPONSE, sizeof(SEED_RESPONSE));
+
+ // the server security level should still be 0
+ TEST_INT_EQUAL(srv.securityLevel, 0);
+
+ // subsequently sending an unlock request should get this response
+ const uint8_t UNLOCK_REQUEST[] = {0x27, 0x02, 0xC9, 0xA9};
+ const uint8_t UNLOCK_RESPONSE[] = {0x67, 0x02};
+ EXPECT_OK(UDSSessSend(&mock_client, UNLOCK_REQUEST, sizeof(UNLOCK_REQUEST)));
+ ENV_RunMillis(50);
+ TEST_MEMORY_EQUAL(mock_client.recv_buf, UNLOCK_RESPONSE, sizeof(UNLOCK_RESPONSE));
+
+ // the server security level should now be 1
+ TEST_INT_EQUAL(srv.securityLevel, 1);
+
+ // sending the same seed request should now result in the "already unlocked" response
+ const uint8_t ALREADY_UNLOCKED_RESPONSE[] = {0x67, 0x01, 0x00, 0x00};
+ EXPECT_OK(UDSSessSend(&mock_client, SEED_REQUEST, sizeof(SEED_REQUEST)));
+ ENV_RunMillis(50);
+ TEST_MEMORY_EQUAL(mock_client.recv_buf, ALREADY_UNLOCKED_RESPONSE,
+ sizeof(ALREADY_UNLOCKED_RESPONSE));
+
+ // Additionally, the security level should still be 1
+ TEST_INT_EQUAL(srv.securityLevel, 1);
+}
\ No newline at end of file
diff --git a/test/test_server_0x31_RCRRP.c b/test/test_server_0x31_RCRRP.c
new file mode 100644
index 0000000..459e62a
--- /dev/null
+++ b/test/test_server_0x31_RCRRP.c
@@ -0,0 +1,43 @@
+#include "test/test.h"
+
+static uint8_t resp;
+static uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) { return resp; }
+
+// ISO-14229-1 2013 Table A.1 Byte Value 0x78: requestCorrectlyReceived-ResponsePending
+// "This NRC is in general supported by each diagnostic service".
+int main() {
+ UDSSess_t mock_client;
+ UDSServer_t srv;
+ ENV_SERVER_INIT(srv);
+ srv.fn = fn;
+ ENV_SESS_INIT(mock_client);
+
+ // When a server handler func initially returns RRCRP
+ resp = kRequestCorrectlyReceived_ResponsePending;
+
+ // sending a request to the server should return RCRRP within p2 ms
+ const uint8_t REQUEST[] = {0x31, 0x01, 0x12, 0x34};
+ UDSSessSend(&mock_client, REQUEST, sizeof(REQUEST));
+
+ const uint8_t RCRRP[] = {0x7F, 0x31, 0x78};
+ EXPECT_WITHIN_MS((mock_client.recv_size > 0), 50);
+ TEST_MEMORY_EQUAL(mock_client.recv_buf, RCRRP, sizeof(RCRRP));
+
+ // The server should again respond within p2_star ms, and keep responding
+ ENV_RunMillis(50);
+ EXPECT_WITHIN_MS((mock_client.recv_size > 0), 50);
+ TEST_MEMORY_EQUAL(mock_client.recv_buf, RCRRP, sizeof(RCRRP));
+
+ ENV_RunMillis(50);
+ EXPECT_WITHIN_MS((mock_client.recv_size > 0), 50);
+ TEST_MEMORY_EQUAL(mock_client.recv_buf, RCRRP, sizeof(RCRRP));
+
+ // When the user func now returns a positive response
+ resp = kPositiveResponse;
+ ENV_RunMillis(50);
+
+ // the server's next response should be a positive one
+ const uint8_t POSITIVE_RESPONSE[] = {0x71, 0x01, 0x12, 0x34};
+ EXPECT_WITHIN_MS((mock_client.recv_size > 0), 50);
+ TEST_MEMORY_EQUAL(mock_client.recv_buf, POSITIVE_RESPONSE, sizeof(POSITIVE_RESPONSE));
+}
diff --git a/test/test_server_0x34.c b/test/test_server_0x34.c
new file mode 100644
index 0000000..65a9676
--- /dev/null
+++ b/test/test_server_0x34.c
@@ -0,0 +1,50 @@
+#include "test/test.h"
+
+uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
+ TEST_INT_EQUAL(ev, UDS_SRV_EVT_RequestDownload);
+ UDSRequestDownloadArgs_t *r = (UDSRequestDownloadArgs_t *)arg;
+ TEST_INT_EQUAL(0x11, r->dataFormatIdentifier);
+ TEST_PTR_EQUAL((void *)0x602000, r->addr);
+ TEST_INT_EQUAL(0x00FFFF, r->size);
+ TEST_INT_EQUAL(r->maxNumberOfBlockLength, UDS_SERVER_DEFAULT_XFER_DATA_MAX_BLOCKLENGTH);
+ r->maxNumberOfBlockLength = 0x0081;
+ return kPositiveResponse;
+}
+
+int main() {
+ { // case 0: No handler
+ UDSSess_t mock_client;
+ UDSServer_t srv;
+ ENV_SERVER_INIT(srv);
+ ENV_SESS_INIT(mock_client);
+
+ // when no handler function is installed, sending this request to the server
+ uint8_t REQ[] = {0x34, 0x11, 0x33, 0x60, 0x20, 0x00, 0x00, 0xFF, 0xFF};
+ EXPECT_OK(UDSSessSend(&mock_client, REQ, sizeof(REQ)));
+
+ // should return a kServiceNotSupported response
+ uint8_t RESP[] = {0x7F, 0x34, 0x11};
+ ENV_RunMillis(50);
+ TEST_MEMORY_EQUAL(mock_client.recv_buf, RESP, sizeof(RESP));
+ TPMockReset();
+ }
+
+ { // case 1: handler installed
+ UDSSess_t mock_client;
+ UDSServer_t srv;
+ ENV_SERVER_INIT(srv);
+ ENV_SESS_INIT(mock_client);
+ // when a handler is installed that implements UDS-1:2013 Table 415
+ srv.fn = fn;
+
+ // sending this request to the server
+ uint8_t REQ[] = {0x34, 0x11, 0x33, 0x60, 0x20, 0x00, 0x00, 0xFF, 0xFF};
+ EXPECT_OK(UDSSessSend(&mock_client, REQ, sizeof(REQ)));
+
+ // should receive a positive response matching UDS-1:2013 Table 415
+ uint8_t RESP[] = {0x74, 0x20, 0x00, 0x81};
+ ENV_RunMillis(50);
+ TEST_MEMORY_EQUAL(mock_client.recv_buf, RESP, sizeof(RESP));
+ TPMockReset();
+ }
+}
diff --git a/test/test_server_0x3E_suppress_positive_response.c b/test/test_server_0x3E_suppress_positive_response.c
new file mode 100644
index 0000000..3c1325e
--- /dev/null
+++ b/test/test_server_0x3E_suppress_positive_response.c
@@ -0,0 +1,21 @@
+#include "test/test.h"
+
+static uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
+ return kPositiveResponse;
+}
+
+int main() {
+ UDSSess_t mock_client;
+ UDSServer_t srv;
+ ENV_SERVER_INIT(srv);
+ srv.fn = fn;
+ ENV_SESS_INIT(mock_client);
+
+ // when the suppressPositiveResponse bit is set
+ const uint8_t REQ[] = {0x3E, 0x80};
+ EXPECT_OK(UDSSessSend(&mock_client, REQ, sizeof(REQ)));
+
+ // there should be no response
+ ENV_RunMillis(5000);
+ TEST_INT_EQUAL(mock_client.recv_size, 0);
+}
diff --git a/test/test_server_0x83_diagnostic_session_control.c b/test/test_server_0x83_diagnostic_session_control.c
new file mode 100644
index 0000000..224ecd8
--- /dev/null
+++ b/test/test_server_0x83_diagnostic_session_control.c
@@ -0,0 +1,28 @@
+#include "test/test.h"
+
+static uint8_t ReturnPositiveResponse(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
+ return kPositiveResponse;
+}
+
+int main() {
+ UDSSess_t mock_client;
+ UDSServer_t srv;
+ ENV_SERVER_INIT(srv);
+ srv.fn = ReturnPositiveResponse;
+ ENV_SESS_INIT(mock_client);
+
+ // the server sessionType after initialization should be kDefaultSession.
+ TEST_INT_EQUAL(srv.sessionType, kDefaultSession);
+
+ // when a request is sent with the suppressPositiveResponse bit set
+ const uint8_t REQ[] = {0x10, 0x83};
+ EXPECT_OK(UDSSessSend(&mock_client, REQ, sizeof(REQ)));
+
+ // even after running for a long time
+ ENV_RunMillis(5000);
+ // there should be no response from the server
+ TEST_INT_EQUAL(mock_client.recv_size, 0);
+
+ // however, the server sessionType should have changed
+ TEST_INT_EQUAL(srv.sessionType, kExtendedDiagnostic);
+}
\ No newline at end of file
diff --git a/test/test_server_session_timeout.c b/test/test_server_session_timeout.c
new file mode 100644
index 0000000..e320fc7
--- /dev/null
+++ b/test/test_server_session_timeout.c
@@ -0,0 +1,35 @@
+#include "test/test.h"
+
+static int call_count = 0;
+
+uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
+ TEST_INT_EQUAL(UDS_SRV_EVT_SessionTimeout, ev);
+ call_count++;
+ return kPositiveResponse;
+}
+
+int main() {
+ UDSSess_t mock_client;
+ UDSServer_t srv;
+
+ struct {
+ const char *tag;
+ uint8_t (*fn)(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg);
+ uint8_t sessType;
+ int expectedCallCount;
+ } p[] = {
+ {.tag = "no timeout", .fn = fn, .sessType = kDefaultSession, .expectedCallCount = 0},
+ {.tag = "timeout", .fn = fn, .sessType = kProgrammingSession, .expectedCallCount = 1},
+ {.tag = "no handler", .fn = NULL, .sessType = kProgrammingSession, .expectedCallCount = 0},
+ };
+
+ for (unsigned i = 0; i < sizeof(p) / sizeof(p[0]); i++) {
+ ENV_SESS_INIT(mock_client);
+ ENV_SERVER_INIT(srv);
+ srv.fn = p[i].fn;
+ srv.sessionType = p[i].sessType;
+ ENV_RunMillis(5000);
+ TEST_INT_GE(call_count, p[i].expectedCallCount);
+ TPMockReset();
+ }
+}
\ No newline at end of file
diff --git a/test_iso14229.c b/test_iso14229.c
index 6a81a81..bf59e61 100644
--- a/test_iso14229.c
+++ b/test_iso14229.c
@@ -6,7 +6,7 @@
#include
#include
#include "iso14229.h"
-#include "tp_mock.h"
+#include "tp/mock.h"
#define _ASSERT_INT_COND(a, b, cond) \
{ \
diff --git a/tp/BUILD b/tp/BUILD
new file mode 100644
index 0000000..2eb145e
--- /dev/null
+++ b/tp/BUILD
@@ -0,0 +1,48 @@
+package(default_visibility = ["//visibility:public"])
+
+cc_library(
+ name="mock",
+ srcs=[
+ "mock.c",
+ "mock.h",
+ "//:iso14229.h"
+ ],
+)
+
+cc_library(
+ name="isotp_c",
+ srcs=[
+ "isotp_c.h",
+ "isotp.h",
+ "//:iso14229.h"
+ ],
+)
+
+
+cc_library(
+ name="isotp_sock",
+ srcs=[
+ "isotp_sock.c",
+ "isotp_sock.h",
+ "//:iso14229.h"
+ ],
+)
+
+filegroup(
+ name="srcs",
+ # srcs=glob(["*.c", "*.h"])
+ srcs = [
+ "mock.c",
+ "mock.h",
+ "isotp_sock.c",
+ "isotp_sock.h",
+ ]
+)
+
+
+cc_binary(
+ name="echo",
+ srcs = [
+ "echo.c",
+ ],
+)
\ No newline at end of file
diff --git a/examples/isotp-c_on_socketcan.h b/tp/isotp-c_on_socketcan.h
similarity index 100%
rename from examples/isotp-c_on_socketcan.h
rename to tp/isotp-c_on_socketcan.h
diff --git a/tp/isotp_c.h b/tp/isotp_c.h
new file mode 100644
index 0000000..b6c548a
--- /dev/null
+++ b/tp/isotp_c.h
@@ -0,0 +1,15 @@
+#ifndef TP_ISOTP_C_H
+#define TP_ISOTP_C_H
+
+#include "iso14229.h"
+#include "isotp-c/isotp.h"
+
+typedef struct {
+ UDSTpHandle_t hdl;
+ IsoTpLink phys_link;
+ IsoTpLink func_link;
+ uint8_t func_recv_buf[8];
+ uint8_t func_send_buf[8];
+} UDSTpIsoTpC_t;
+
+#endif
diff --git a/examples/isotp-c_on_socketcan.c b/tp/isotp_c_socketcan.c
similarity index 100%
rename from examples/isotp-c_on_socketcan.c
rename to tp/isotp_c_socketcan.c
diff --git a/tp/isotp_c_socketcan.h b/tp/isotp_c_socketcan.h
new file mode 100644
index 0000000..e4de4f4
--- /dev/null
+++ b/tp/isotp_c_socketcan.h
@@ -0,0 +1,18 @@
+#ifndef ISOTP_C_SOCKETCAN_H
+#define ISOTP_C_SOCKETCAN_H
+
+#include "iso14229.h"
+#include "tp/isotp_c.h"
+
+typedef struct {
+ UDSTpHandle_t hdl;
+ IsoTpLink phys_link;
+ IsoTpLink func_link;
+ uint8_t func_recv_buf[8];
+ uint8_t func_send_buf[8];
+ int fd;
+} UDSTpISOTpCSocketCAN_t;
+
+UDSTpHandle_t *UDSTpISOTpCSocketCANInit();
+
+#endif
\ No newline at end of file
diff --git a/tp/isotp_sock.c b/tp/isotp_sock.c
new file mode 100644
index 0000000..19917f1
--- /dev/null
+++ b/tp/isotp_sock.c
@@ -0,0 +1,196 @@
+#include "tp/isotp_sock.h"
+#include "iso14229.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+static UDSTpStatus_t tp_poll(UDSTpHandle_t *hdl) { return 0; }
+
+static ssize_t tp_recv_once(int fd, UDSSDU_t *msg, bool functional) {
+ ssize_t ret = read(fd, msg->A_Data, msg->A_DataBufSize);
+ if (ret < 0) {
+ if (EAGAIN == errno || EWOULDBLOCK == errno) {
+ ret = 0;
+ } else {
+ UDS_DBG_PRINT("read failed: %ld with errno: %d\n", ret, errno);
+ if (EILSEQ == errno) {
+ UDS_DBG_PRINT("Perhaps I received multiple responses?\n");
+ }
+ }
+ } else if (ret > 0) {
+ msg->A_Length = ret;
+ msg->A_TA_Type = functional ? UDS_A_TA_TYPE_FUNCTIONAL : UDS_A_TA_TYPE_PHYSICAL;
+ }
+ return ret;
+}
+
+static ssize_t tp_recv(UDSTpHandle_t *hdl, UDSSDU_t *msg) {
+ assert(hdl);
+ assert(msg);
+ ssize_t ret = 0;
+ UDSTpIsoTpSock_t *impl = (UDSTpIsoTpSock_t *)hdl;
+
+ ret = tp_recv_once(impl->phys_fd, msg, false);
+ if (ret > 0) {
+ msg->A_TA = impl->phys_sa;
+ msg->A_SA = impl->phys_ta;
+ } else {
+ ret = tp_recv_once(impl->func_fd, msg, true);
+ if (ret > 0) {
+ msg->A_TA = impl->func_sa;
+ msg->A_SA = impl->func_ta;
+ }
+ }
+
+ if (ret > 0) {
+ fprintf(stdout, "%06d, %s recv, 0x%03x (%s), ", UDSMillis(), impl->tag, msg->A_TA,
+ msg->A_TA_Type == UDS_A_TA_TYPE_PHYSICAL ? "phys" : "func");
+ for (unsigned i = 0; i < msg->A_Length; i++) {
+ fprintf(stdout, "%02x ", msg->A_Data[i]);
+ }
+ fprintf(stdout, "\n");
+ fflush(stdout); // flush every time in case of crash
+ // UDS_DBG_PRINT("<<< ");
+ // UDS_DBG_PRINTHEX(, ret);
+ }
+ return ret;
+}
+
+static ssize_t tp_send(UDSTpHandle_t *hdl, UDSSDU_t *msg) {
+ assert(hdl);
+ ssize_t ret = -1;
+ UDSTpIsoTpSock_t *impl = (UDSTpIsoTpSock_t *)hdl;
+ int fd;
+ switch (msg->A_TA_Type) {
+ case kTpAddrTypePhysical:
+ fd = impl->phys_fd;
+ break;
+ case kTpAddrTypeFunctional:
+ fd = impl->func_fd;
+ break;
+ default:
+ ret = -4;
+ goto done;
+ }
+ ret = write(fd, msg->A_Data, msg->A_Length);
+ if (ret < 0) {
+ perror("write");
+ }
+done:
+ // UDS_DBG_PRINT(">>> ");
+ // UDS_DBG_PRINTHEX(buf, ret);
+ fprintf(stdout, "%06d, %s sends, 0x%03x (%s), ", UDSMillis(), impl->tag, msg->A_TA,
+ msg->A_TA_Type == UDS_A_TA_TYPE_PHYSICAL ? "phys" : "func");
+ for (unsigned i = 0; i < msg->A_Length; i++) {
+ fprintf(stdout, "%02x ", msg->A_Data[i]);
+ }
+ fprintf(stdout, "\n");
+ fflush(stdout); // flush every time in case of crash
+ return ret;
+}
+
+static int LinuxSockBind(const char *if_name, uint32_t rxid, uint32_t txid, bool functional) {
+ int fd = 0;
+ if ((fd = socket(AF_CAN, SOCK_DGRAM | SOCK_NONBLOCK, CAN_ISOTP)) < 0) {
+ perror("Socket");
+ return -1;
+ }
+
+ struct can_isotp_fc_options fcopts = {
+ .bs = 0x10,
+ .stmin = 3,
+ .wftmax = 0,
+ };
+ if (setsockopt(fd, SOL_CAN_ISOTP, CAN_ISOTP_RECV_FC, &fcopts, sizeof(fcopts)) < 0) {
+ perror("setsockopt");
+ return -1;
+ }
+
+ if (functional) {
+ printf("configuring fd: %d as functional\n", fd);
+ // configure the socket as listen-only to avoid sending FC frames
+ struct can_isotp_options opts;
+ memset(&opts, 0, sizeof(opts));
+ opts.flags |= CAN_ISOTP_LISTEN_MODE;
+ if (setsockopt(fd, SOL_CAN_ISOTP, CAN_ISOTP_OPTS, &opts, sizeof(opts)) < 0) {
+ perror("setsockopt (isotp_options):");
+ return -1;
+ }
+ }
+
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
+ ioctl(fd, SIOCGIFINDEX, &ifr);
+
+ struct sockaddr_can addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.can_family = AF_CAN;
+ addr.can_addr.tp.rx_id = rxid;
+ addr.can_addr.tp.tx_id = txid;
+ addr.can_ifindex = ifr.ifr_ifindex;
+
+ if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ printf("Bind: %s %s\n", strerror(errno), if_name);
+ return -1;
+ }
+ return fd;
+}
+
+UDSErr_t UDSTpIsoTpSockInitServer(UDSTpIsoTpSock_t *tp, const char *ifname, uint32_t source_addr,
+ uint32_t target_addr, uint32_t source_addr_func) {
+ assert(tp);
+ tp->hdl.recv = tp_recv;
+ tp->hdl.send = tp_send;
+ tp->hdl.poll = tp_poll;
+ tp->phys_sa = source_addr;
+ tp->phys_ta = target_addr;
+ tp->func_sa = source_addr_func;
+
+ tp->phys_fd = LinuxSockBind(ifname, source_addr, target_addr, false);
+ tp->func_fd = LinuxSockBind(ifname, source_addr_func, target_addr, true);
+ if (tp->phys_fd < 0 || tp->func_fd < 0) {
+ return UDS_ERR;
+ }
+ printf("%s initialized phys link rx 0x%03x tx 0x%03x func link rx 0x%03x tx 0x%03x\n",
+ tp->tag ? tp->tag : "server", source_addr, target_addr, source_addr_func, target_addr);
+ return UDS_OK;
+}
+
+UDSErr_t UDSTpIsoTpSockInitClient(UDSTpIsoTpSock_t *tp, const char *ifname, uint32_t source_addr,
+ uint32_t target_addr, uint32_t target_addr_func) {
+ assert(tp);
+ tp->hdl.recv = tp_recv;
+ tp->hdl.send = tp_send;
+ tp->hdl.poll = tp_poll;
+ tp->func_ta = target_addr_func;
+ tp->phys_ta = target_addr;
+ tp->phys_sa = source_addr;
+
+ tp->phys_fd = LinuxSockBind(ifname, source_addr, target_addr, false);
+ tp->func_fd = LinuxSockBind(ifname, source_addr + 1, target_addr_func, true);
+ if (tp->phys_fd < 0 || tp->func_fd < 0) {
+ return UDS_ERR;
+ }
+ printf("%s initialized phys link (fd %d) rx 0x%03x tx 0x%03x func link (fd %d) rx 0x%03x tx 0x%03x\n",
+ tp->tag ? tp->tag : "client", tp->phys_fd, source_addr, target_addr, tp->func_fd, source_addr, target_addr_func);
+ return UDS_OK;
+}
+
+void UDSTpIsoTpSockDeinit(UDSTpIsoTpSock_t *tp) {
+ if (tp) {
+ if (close(tp->phys_fd) < 0) {
+ perror("failed to close socket");
+ }
+ if (close(tp->func_fd) < 0) {
+ perror("failed to close socket");
+ }
+ }
+}
diff --git a/tp/isotp_sock.h b/tp/isotp_sock.h
new file mode 100644
index 0000000..119d66c
--- /dev/null
+++ b/tp/isotp_sock.h
@@ -0,0 +1,21 @@
+#ifndef TP_ISOTP_SOCK_H
+#define TP_ISOTP_SOCK_H
+
+#include "iso14229.h"
+
+typedef struct {
+ UDSTpHandle_t hdl;
+ int phys_fd;
+ int phys_sa, phys_ta;
+ int func_fd;
+ int func_sa, func_ta;
+ char tag[16];
+} UDSTpIsoTpSock_t;
+
+UDSErr_t UDSTpIsoTpSockInitServer(UDSTpIsoTpSock_t *tp, const char *ifname, uint32_t source_addr,
+ uint32_t target_addr, uint32_t source_addr_func);
+UDSErr_t UDSTpIsoTpSockInitClient(UDSTpIsoTpSock_t *tp, const char *ifname, uint32_t source_addr,
+ uint32_t target_addr, uint32_t target_addr_func);
+void UDSTpIsoTpSockDeinit(UDSTpIsoTpSock_t *tp);
+
+#endif
diff --git a/tp_mock.c b/tp/mock.c
similarity index 97%
rename from tp_mock.c
rename to tp/mock.c
index 5a68581..1079875 100644
--- a/tp_mock.c
+++ b/tp/mock.c
@@ -1,4 +1,4 @@
-#include "tp_mock.h"
+#include "tp/mock.h"
#include "iso14229.h"
#include
#include
@@ -125,11 +125,14 @@ void TPMockLogToFile(const char *filename) {
}
}
+void TPMockLogToStdout() {
+ if (LogFile) {
+ return;
+ }
+ LogFile = stdout;
+}
+
void TPMockReset() {
memset(TPs, 0, sizeof(TPs));
TPCount = 0;
- if (LogFile) {
- fclose(LogFile);
- LogFile = NULL;
- }
}
\ No newline at end of file
diff --git a/tp_mock.h b/tp/mock.h
similarity index 82%
rename from tp_mock.h
rename to tp/mock.h
index 85604c8..675a0b2 100644
--- a/tp_mock.h
+++ b/tp/mock.h
@@ -15,12 +15,16 @@
*/
UDSTpHandle_t *TPMockCreate(const char *name);
+void TPMockSend(UDSTpHandle_t *tp, UDSSDU_t *msg);
+int TPMockRecv(UDSTpHandle_t *tp, UDSSDU_t *msg, uint32_t millis);
+
/**
* @brief write all messages to a file
* @note uses UDSMillis() to get the current time
* @param filename log file name (will be overwritten)
*/
void TPMockLogToFile(const char *filename);
+void TPMockLogToStdout();
/**
* @brief clear all transports and close the log file
From 2713462c7f897247dc573b9c7cf116e60029acb9 Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Tue, 31 Oct 2023 20:01:05 -0700
Subject: [PATCH 05/56] add test_prefix.sh
---
test/test_prefix.sh | 5 +++++
1 file changed, 5 insertions(+)
create mode 100755 test/test_prefix.sh
diff --git a/test/test_prefix.sh b/test/test_prefix.sh
new file mode 100755
index 0000000..e047f77
--- /dev/null
+++ b/test/test_prefix.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+# test fails if any exported symbols do not start with "UDS"
+nm $1 | grep ' T ' | grep -v 'UDS'
+test $$? = 1
\ No newline at end of file
From 374c150dfb85aa2c61ef38c35b41a6e9f7619dfa Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Tue, 31 Oct 2023 20:02:58 -0700
Subject: [PATCH 06/56] use mock_tp on github actions
---
test/BUILD | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/test/BUILD b/test/BUILD
index d95f1b2..f1d7822 100644
--- a/test/BUILD
+++ b/test/BUILD
@@ -25,8 +25,8 @@ cc_library(
deps=[":env"],
size = "small",
env={
- "TP": "isotp_sock",
- # "TP": "mock",
+ # "TP": "isotp_sock",
+ "TP": "mock",
}
)
From 7eaf5c5a5309789ef8b3b4521ee759d77d24b790 Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Tue, 31 Oct 2023 22:17:16 -0700
Subject: [PATCH 07/56] move isotp-c, fix test_prefix test
---
BUILD | 18 ---
examples/client.c | 2 +-
examples/server.c | 2 +-
iso14229.c | 2 +-
iso14229.h | 6 +-
test/BUILD | 6 +-
test/env.c | 38 ++++-
test/test_prefix.sh | 2 +-
tp/BUILD | 42 ++++--
{isotp-c => tp/isotp-c}/.gitignore | 0
{isotp-c => tp/isotp-c}/.travis.yml | 0
{isotp-c => tp/isotp-c}/CMakeLists.txt | 0
{isotp-c => tp/isotp-c}/LICENSE | 0
{isotp-c => tp/isotp-c}/Makefile | 0
{isotp-c => tp/isotp-c}/README.md | 0
{isotp-c => tp/isotp-c}/isotp.c | 0
{isotp-c => tp/isotp-c}/isotp.h | 0
{isotp-c => tp/isotp-c}/isotp_config.h | 0
{isotp-c => tp/isotp-c}/isotp_defines.h | 0
{isotp-c => tp/isotp-c}/isotp_user.h | 0
{isotp-c => tp/isotp-c}/vars.mk | 0
tp/isotp-c_on_socketcan.h | 3 -
tp/isotp_c.h | 15 --
tp/isotp_c_socketcan.c | 183 +++++++++++++++++++++++-
tp/isotp_c_socketcan.h | 16 ++-
tp/isotp_sock.c | 2 +-
tp/isotp_sock.h | 4 +-
27 files changed, 268 insertions(+), 73 deletions(-)
rename {isotp-c => tp/isotp-c}/.gitignore (100%)
rename {isotp-c => tp/isotp-c}/.travis.yml (100%)
rename {isotp-c => tp/isotp-c}/CMakeLists.txt (100%)
rename {isotp-c => tp/isotp-c}/LICENSE (100%)
rename {isotp-c => tp/isotp-c}/Makefile (100%)
rename {isotp-c => tp/isotp-c}/README.md (100%)
rename {isotp-c => tp/isotp-c}/isotp.c (100%)
rename {isotp-c => tp/isotp-c}/isotp.h (100%)
rename {isotp-c => tp/isotp-c}/isotp_config.h (100%)
rename {isotp-c => tp/isotp-c}/isotp_defines.h (100%)
rename {isotp-c => tp/isotp-c}/isotp_user.h (100%)
rename {isotp-c => tp/isotp-c}/vars.mk (100%)
delete mode 100644 tp/isotp-c_on_socketcan.h
delete mode 100644 tp/isotp_c.h
diff --git a/BUILD b/BUILD
index 8b07d20..a2227cd 100644
--- a/BUILD
+++ b/BUILD
@@ -42,24 +42,6 @@ cc_test(
size = "small",
)
-
-filegroup(
- name="isotp_c_srcs",
- srcs=[
- "isotp-c/isotp.c",
- "isotp-c/isotp.h",
- "isotp-c/isotp_config.h",
- "isotp-c/isotp_defines.h",
- "isotp-c/isotp_user.h",
- ],
-)
-
-cc_library(
- name="isotp_c",
- srcs=[":isotp_c_srcs"],
- copts=["-Wno-unused-parameter"],
-)
-
cc_library(
name="iso14229",
srcs=[":iso14229_srcs"],
diff --git a/examples/client.c b/examples/client.c
index 5388c18..1bd8c2d 100644
--- a/examples/client.c
+++ b/examples/client.c
@@ -132,7 +132,7 @@ int main(int ac, char **av) {
do {
running = UDSClientPoll(&client);
#if UDS_TP == UDS_TP_ISOTP_C
- SocketCANRecv((UDSTpIsoTpC_t *)client.tp, cfg.source_addr);
+ SocketCANRecv((UDSTpISOTpC_t *)client.tp, cfg.source_addr);
#endif
SleepMillis(1);
} while (running);
diff --git a/examples/server.c b/examples/server.c
index ba2d96d..e1fa53d 100644
--- a/examples/server.c
+++ b/examples/server.c
@@ -166,7 +166,7 @@ int main(int ac, char **av) {
while (!serverWantsExit) {
UDSServerPoll(&srv);
#if UDS_TP == UDS_TP_ISOTP_C
- SocketCANRecv((UDSTpIsoTpC_t *)srv.tp, cfg.source_addr);
+ SocketCANRecv((UDSTpISOTpC_t *)srv.tp, cfg.source_addr);
#endif
SleepMillis(1);
}
diff --git a/iso14229.c b/iso14229.c
index b469837..59da81c 100644
--- a/iso14229.c
+++ b/iso14229.c
@@ -273,7 +273,7 @@ static int LinuxSockTpOpen(UDSTpHandle_t *hdl, const char *if_name, uint32_t phy
return 0;
}
-void LinuxSockTpClose(UDSTpHandle_t *hdl) {
+static void LinuxSockTpClose(UDSTpHandle_t *hdl) {
if (hdl) {
UDSTpLinuxIsoTp_t *impl = (UDSTpLinuxIsoTp_t *)hdl;
if (impl) {
diff --git a/iso14229.h b/iso14229.h
index 9977d28..339a468 100644
--- a/iso14229.h
+++ b/iso14229.h
@@ -311,7 +311,7 @@ typedef struct {
IsoTpLink func_link;
uint8_t func_recv_buf[8];
uint8_t func_send_buf[8];
-} UDSTpIsoTpC_t;
+} UDSTpISOTpC_t;
#elif UDS_TP == UDS_TP_ISOTP_SOCKET
typedef struct {
UDSTpHandle_t hdl;
@@ -448,7 +448,7 @@ typedef struct UDSClient {
#if UDS_TP == UDS_TP_CUSTOM
#elif UDS_TP == UDS_TP_ISOTP_C
- UDSTpIsoTpC_t tp_impl;
+ UDSTpISOTpC_t tp_impl;
#elif UDS_TP == UDS_TP_ISOTP_SOCKET
UDSTpLinuxIsoTp_t tp_impl;
#endif
@@ -662,7 +662,7 @@ typedef struct UDSServer {
#if UDS_TP == UDS_TP_CUSTOM
#elif UDS_TP == UDS_TP_ISOTP_C
- UDSTpIsoTpC_t tp_impl;
+ UDSTpISOTpC_t tp_impl;
#elif UDS_TP == UDS_TP_ISOTP_SOCKET
UDSTpLinuxIsoTp_t tp_impl;
#endif
diff --git a/test/BUILD b/test/BUILD
index f1d7822..9996c72 100644
--- a/test/BUILD
+++ b/test/BUILD
@@ -8,8 +8,9 @@ cc_library(
"//tp:srcs",
],
deps = [
- # "//tp:mock",
- # "//tp:isotp_sock",
+ "//tp:mock",
+ "//tp:isotp_sock",
+ "//tp:isotp_c_socketcan",
],
defines = [
"UDS_TP=UDS_TP_CUSTOM",
@@ -26,6 +27,7 @@ cc_library(
size = "small",
env={
# "TP": "isotp_sock",
+ # "TP": "isotp-c",
"TP": "mock",
}
)
diff --git a/test/env.c b/test/env.c
index dcfa902..b4b8869 100644
--- a/test/env.c
+++ b/test/env.c
@@ -4,8 +4,10 @@
#include
#include
#include
+#include
#include "tp/mock.h"
#include "tp/isotp_sock.h"
+#include "tp/isotp_c_socketcan.h"
static UDSServer_t *registeredServer = NULL;
static UDSClient_t *registeredClient = NULL;
@@ -23,6 +25,7 @@ struct IntOpt {
enum {
OPTS_TP_TYPE_MOCK,
OPTS_TP_TYPE_ISOTP_SOCK,
+ OPTS_TP_TYPE_ISOTPC,
};
typedef struct {
@@ -53,6 +56,15 @@ void ENV_ServerInit(UDSServer_t *srv) {
tp = (UDSTpHandle_t *)isotp;
break;
}
+ case OPTS_TP_TYPE_ISOTPC: {
+ UDSTpISOTpC_t *isotp = malloc(sizeof(UDSTpISOTpC_t));
+ strcpy(isotp->tag, "server");
+ assert(UDS_OK == UDSTpISOTpCInitServer(isotp, srv, cfg.ifname,
+ cfg.srv_src_addr, cfg.srv_target_addr,
+ cfg.srv_src_addr_func));
+ tp = (UDSTpHandle_t *)isotp;
+ break;
+ }
default:
printf("unknown TP type: %d\n", cfg.tp_type);
exit(1);
@@ -83,6 +95,15 @@ void ENV_ClientInit(UDSClient_t *cli) {
tp = (UDSTpHandle_t *)isotp;
break;
}
+ case OPTS_TP_TYPE_ISOTPC: {
+ UDSTpISOTpC_t *isotp = malloc(sizeof(UDSTpISOTpC_t));
+ strcpy(isotp->tag, "client");
+ assert(UDS_OK == UDSTpISOTpCInitClient(isotp, cli, cfg.ifname,
+ cfg.cli_src_addr, cfg.cli_target_addr,
+ cfg.cli_tgt_addr_func));
+ tp = (UDSTpHandle_t *)isotp;
+ break;
+ }
default:
printf("unknown TP type: %d\n", cfg.tp_type);
exit(1);
@@ -112,6 +133,15 @@ void ENV_SessInit(UDSSess_t *sess, const char *name) {
tp = (UDSTpHandle_t *)isotp;
break;
}
+ case OPTS_TP_TYPE_ISOTPC: {
+ UDSTpISOTpC_t *isotp = malloc(sizeof(UDSTpISOTpC_t));
+ strncpy(isotp->tag, name, sizeof(isotp->tag));
+ assert(UDS_OK == UDSTpISOTpCInitSess(isotp, sess, cfg.ifname,
+ cfg.cli_src_addr, cfg.cli_target_addr,
+ cfg.cli_tgt_addr_func));
+ tp = (UDSTpHandle_t *)isotp;
+ break;
+ }
default:
printf("unknown TP type: %d\n", cfg.tp_type);
exit(1);
@@ -139,6 +169,10 @@ void msleep(int ms) {
usleep(ms * 1000);
}
+static bool IsNetworkedTransport(int tp_type) {
+ return tp_type == OPTS_TP_TYPE_ISOTP_SOCK || tp_type == OPTS_TP_TYPE_ISOTPC;
+}
+
void ENV_RunMillis(uint32_t millis) {
uint32_t end = UDSMillis() + millis;
while (UDSMillis() < end) {
@@ -154,7 +188,7 @@ void ENV_RunMillis(uint32_t millis) {
TimeNowMillis++;
// uses vcan, needs delay
- if (cfg.tp_type == OPTS_TP_TYPE_ISOTP_SOCK) {
+ if (IsNetworkedTransport(cfg.tp_type)) {
usleep(10);
// msleep(1);
}
@@ -180,6 +214,8 @@ void ENV_ParseOpts(int argc, char **argv) {
cfg.tp_type = OPTS_TP_TYPE_MOCK;
} else if (0 == strcasecmp(tp, "isotp_sock")) {
cfg.tp_type = OPTS_TP_TYPE_ISOTP_SOCK;
+ } else if (0 == strcasecmp(tp, "isotp-c")) {
+ cfg.tp_type = OPTS_TP_TYPE_ISOTPC;
} else {
printf("unknown TP: %s\n", tp);
exit(1);
diff --git a/test/test_prefix.sh b/test/test_prefix.sh
index e047f77..f1a5115 100755
--- a/test/test_prefix.sh
+++ b/test/test_prefix.sh
@@ -2,4 +2,4 @@
# test fails if any exported symbols do not start with "UDS"
nm $1 | grep ' T ' | grep -v 'UDS'
-test $$? = 1
\ No newline at end of file
+test $? = 1
\ No newline at end of file
diff --git a/tp/BUILD b/tp/BUILD
index 2eb145e..14f5316 100644
--- a/tp/BUILD
+++ b/tp/BUILD
@@ -10,21 +10,41 @@ cc_library(
)
cc_library(
- name="isotp_c",
+ name="isotp_sock",
srcs=[
- "isotp_c.h",
- "isotp.h",
+ "isotp_sock.c",
+ "isotp_sock.h",
"//:iso14229.h"
],
)
+filegroup(
+ name="isotp_c_srcs",
+ srcs=[
+ "isotp-c/isotp.c",
+ "isotp-c/isotp.h",
+ "isotp-c/isotp_config.h",
+ "isotp-c/isotp_defines.h",
+ "isotp-c/isotp_user.h",
+ ],
+)
+
cc_library(
- name="isotp_sock",
+ name="isotp_c",
+ srcs=[":isotp_c_srcs"],
+ copts=["-Wno-unused-parameter"],
+)
+
+cc_library(
+ name="isotp_c_socketcan",
srcs=[
- "isotp_sock.c",
- "isotp_sock.h",
- "//:iso14229.h"
+ "isotp_c_socketcan.c",
+ "isotp_c_socketcan.h",
+ "//:iso14229.h",
+ ],
+ deps = [
+ ":isotp_c",
],
)
@@ -38,11 +58,3 @@ filegroup(
"isotp_sock.h",
]
)
-
-
-cc_binary(
- name="echo",
- srcs = [
- "echo.c",
- ],
-)
\ No newline at end of file
diff --git a/isotp-c/.gitignore b/tp/isotp-c/.gitignore
similarity index 100%
rename from isotp-c/.gitignore
rename to tp/isotp-c/.gitignore
diff --git a/isotp-c/.travis.yml b/tp/isotp-c/.travis.yml
similarity index 100%
rename from isotp-c/.travis.yml
rename to tp/isotp-c/.travis.yml
diff --git a/isotp-c/CMakeLists.txt b/tp/isotp-c/CMakeLists.txt
similarity index 100%
rename from isotp-c/CMakeLists.txt
rename to tp/isotp-c/CMakeLists.txt
diff --git a/isotp-c/LICENSE b/tp/isotp-c/LICENSE
similarity index 100%
rename from isotp-c/LICENSE
rename to tp/isotp-c/LICENSE
diff --git a/isotp-c/Makefile b/tp/isotp-c/Makefile
similarity index 100%
rename from isotp-c/Makefile
rename to tp/isotp-c/Makefile
diff --git a/isotp-c/README.md b/tp/isotp-c/README.md
similarity index 100%
rename from isotp-c/README.md
rename to tp/isotp-c/README.md
diff --git a/isotp-c/isotp.c b/tp/isotp-c/isotp.c
similarity index 100%
rename from isotp-c/isotp.c
rename to tp/isotp-c/isotp.c
diff --git a/isotp-c/isotp.h b/tp/isotp-c/isotp.h
similarity index 100%
rename from isotp-c/isotp.h
rename to tp/isotp-c/isotp.h
diff --git a/isotp-c/isotp_config.h b/tp/isotp-c/isotp_config.h
similarity index 100%
rename from isotp-c/isotp_config.h
rename to tp/isotp-c/isotp_config.h
diff --git a/isotp-c/isotp_defines.h b/tp/isotp-c/isotp_defines.h
similarity index 100%
rename from isotp-c/isotp_defines.h
rename to tp/isotp-c/isotp_defines.h
diff --git a/isotp-c/isotp_user.h b/tp/isotp-c/isotp_user.h
similarity index 100%
rename from isotp-c/isotp_user.h
rename to tp/isotp-c/isotp_user.h
diff --git a/isotp-c/vars.mk b/tp/isotp-c/vars.mk
similarity index 100%
rename from isotp-c/vars.mk
rename to tp/isotp-c/vars.mk
diff --git a/tp/isotp-c_on_socketcan.h b/tp/isotp-c_on_socketcan.h
deleted file mode 100644
index 68f9264..0000000
--- a/tp/isotp-c_on_socketcan.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#include "../iso14229.h"
-
-void SocketCANRecv(UDSTpIsoTpC_t *tp, unsigned int recv_id);
\ No newline at end of file
diff --git a/tp/isotp_c.h b/tp/isotp_c.h
deleted file mode 100644
index b6c548a..0000000
--- a/tp/isotp_c.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef TP_ISOTP_C_H
-#define TP_ISOTP_C_H
-
-#include "iso14229.h"
-#include "isotp-c/isotp.h"
-
-typedef struct {
- UDSTpHandle_t hdl;
- IsoTpLink phys_link;
- IsoTpLink func_link;
- uint8_t func_recv_buf[8];
- uint8_t func_send_buf[8];
-} UDSTpIsoTpC_t;
-
-#endif
diff --git a/tp/isotp_c_socketcan.c b/tp/isotp_c_socketcan.c
index 6573130..a3cad36 100644
--- a/tp/isotp_c_socketcan.c
+++ b/tp/isotp_c_socketcan.c
@@ -1,5 +1,5 @@
-#include "../iso14229.h"
-#include "../isotp-c/isotp.h"
+#include "tp/isotp_c_socketcan.h"
+#include "iso14229.h"
#include
#include
#include
@@ -13,6 +13,8 @@
static int sockfd = 0;
static bool HasSetup = false;
+
+
static void SetupOnce() {
if (HasSetup) {
return;
@@ -24,6 +26,15 @@ static void SetupOnce() {
perror("socket");
exit(-1);
}
+
+ // TODO: https://github.com/lishen2/isotp-c/issues/14
+ int recv_own_msgs = 1;
+ if (setsockopt(sockfd, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS, &recv_own_msgs, sizeof(recv_own_msgs)) < 0) {
+ perror("setsockopt (CAN_RAW_LOOPBACK):");
+ exit(-1);
+ }
+
+
strcpy(ifr.ifr_name, "vcan0");
ioctl(sockfd, SIOCGIFINDEX, &ifr);
memset(&addr, 0, sizeof(addr));
@@ -60,9 +71,8 @@ static void printhex(const uint8_t *addr, int len) {
printf("\n");
}
-void SocketCANRecv(UDSTpIsoTpC_t *tp, int source_addr, int source_addr_func) {
+static void SocketCANRecv(UDSTpISOTpC_t *tp) {
assert(tp);
- SetupOnce();
struct can_frame frame = {0};
int nbytes = 0;
for (;;) {
@@ -76,15 +86,176 @@ void SocketCANRecv(UDSTpIsoTpC_t *tp, int source_addr, int source_addr_func) {
} else if (nbytes == 0) {
break;
} else {
- if (frame.can_id == source_addr) {
+ if (frame.can_id == tp->phys_sa) {
UDS_DBG_PRINT("phys recvd can\n");
UDS_DBG_PRINTHEX(frame.data, frame.can_dlc);
isotp_on_can_message(&tp->phys_link, frame.data, frame.can_dlc);
- } else if (frame.can_id == source_addr_func) {
+ } else if (frame.can_id == tp->func_sa) {
UDS_DBG_PRINT("func recvd can\n");
UDS_DBG_PRINTHEX(frame.data, frame.can_dlc);
isotp_on_can_message(&tp->func_link, frame.data, frame.can_dlc);
}
}
}
+}
+
+static UDSTpStatus_t tp_poll(UDSTpHandle_t *hdl) {
+ assert(hdl);
+ UDSTpStatus_t status = 0;
+ UDSTpISOTpC_t *impl = (UDSTpISOTpC_t *)hdl;
+ SocketCANRecv(impl);
+
+ isotp_poll(&impl->phys_link);
+ isotp_poll(&impl->func_link);
+ if (impl->phys_link.send_status == ISOTP_SEND_STATUS_INPROGRESS) {
+ status |= UDS_TP_SEND_IN_PROGRESS;
+ }
+ return status;
+}
+
+static ssize_t tp_recv(UDSTpHandle_t *hdl, UDSSDU_t *msg) {
+ assert(hdl);
+ int ret = -1;
+ uint16_t size = 0;
+ UDSTpISOTpC_t *impl = (UDSTpISOTpC_t *)hdl;
+ struct {
+ IsoTpLink *link;
+ UDSTpAddr_t ta_type;
+ } arr[] = {{&impl->phys_link, kTpAddrTypePhysical}, {&impl->func_link, kTpAddrTypeFunctional}};
+ for (size_t i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) {
+ ret = isotp_receive(arr[i].link, msg->A_Data, msg->A_DataBufSize, &size);
+ switch (ret) {
+ case ISOTP_RET_OK:
+ msg->A_TA_Type = arr[i].ta_type;
+ ret = size;
+ goto done;
+ case ISOTP_RET_NO_DATA:
+ ret = 0;
+ continue;
+ case ISOTP_RET_ERROR:
+ ret = -1;
+ goto done;
+ default:
+ ret = -2;
+ goto done;
+ }
+ }
+done:
+ if (ret > 0) {
+ msg->A_Length = size;
+ if (UDS_A_TA_TYPE_PHYSICAL == msg->A_TA_Type ) {
+ msg->A_TA = impl->phys_sa;
+ msg->A_SA = impl->phys_ta;
+ } else {
+ msg->A_TA = impl->func_sa;
+ msg->A_SA = impl->func_ta;
+ }
+ fprintf(stdout, "%06d, %s recv, 0x%03x (%s), ", UDSMillis(), impl->tag, msg->A_TA,
+ msg->A_TA_Type == UDS_A_TA_TYPE_PHYSICAL ? "phys" : "func");
+ for (unsigned i = 0; i < msg->A_Length; i++) {
+ fprintf(stdout, "%02x ", msg->A_Data[i]);
+ }
+ fprintf(stdout, "\n");
+ fflush(stdout); // flush every time in case of crash
+
+ }
+ return ret;
+}
+
+static ssize_t tp_send(UDSTpHandle_t *hdl, UDSSDU_t *msg) {
+ assert(hdl);
+ ssize_t ret = -1;
+ UDSTpISOTpC_t *impl = (UDSTpISOTpC_t *)hdl;
+ IsoTpLink *link = NULL;
+ switch (msg->A_TA_Type) {
+ case kTpAddrTypePhysical:
+ link = &impl->phys_link;
+ break;
+ case kTpAddrTypeFunctional:
+ link = &impl->func_link;
+ break;
+ default:
+ ret = -4;
+ goto done;
+ }
+
+ int send_status = isotp_send(link, msg->A_Data, msg->A_Length);
+ switch (send_status) {
+ case ISOTP_RET_OK:
+ ret = msg->A_Length;
+ goto done;
+ case ISOTP_RET_INPROGRESS:
+ case ISOTP_RET_OVERFLOW:
+ default:
+ ret = send_status;
+ goto done;
+ }
+done:
+ fprintf(stdout, "%06d, %s sends, 0x%03x (%s), ", UDSMillis(), impl->tag, msg->A_TA,
+ msg->A_TA_Type == UDS_A_TA_TYPE_PHYSICAL ? "phys" : "func");
+ for (unsigned i = 0; i < msg->A_Length; i++) {
+ fprintf(stdout, "%02x ", msg->A_Data[i]);
+ }
+ fprintf(stdout, "\n");
+ fflush(stdout); // flush every time in case of crash
+
+ return ret;
+}
+
+
+UDSErr_t UDSTpISOTpCInitServer(UDSTpISOTpC_t *tp, UDSServer_t* srv, const char *ifname, uint32_t source_addr,
+ uint32_t target_addr, uint32_t target_addr_func) {
+ assert(tp);
+ assert(ifname);
+ tp->hdl.poll = tp_poll;
+ tp->hdl.recv = tp_recv;
+ tp->hdl.send = tp_send;
+ tp->phys_sa = source_addr;
+ tp->phys_ta = target_addr;
+ tp->func_sa = source_addr;
+ tp->func_ta = target_addr_func;
+
+ isotp_init_link(&tp->phys_link, target_addr, srv->send_buf, sizeof(srv->send_buf),
+ srv->recv_buf, sizeof(srv->recv_buf));
+ isotp_init_link(&tp->func_link, target_addr, tp->func_send_buf, sizeof(tp->func_send_buf),
+ tp->func_recv_buf, sizeof(tp->func_recv_buf));
+ return UDS_OK;
+}
+
+UDSErr_t UDSTpISOTpCInitClient(UDSTpISOTpC_t *tp, UDSClient_t *client, const char *ifname, uint32_t source_addr, uint32_t target_addr, uint32_t source_addr_func) {
+ assert(tp);
+ assert(ifname);
+ tp->hdl.poll = tp_poll;
+ tp->hdl.recv = tp_recv;
+ tp->hdl.send = tp_send;
+ tp->phys_sa = source_addr;
+ tp->phys_ta = target_addr;
+ tp->func_sa = source_addr_func;
+ tp->func_ta = target_addr;
+
+ isotp_init_link(&tp->phys_link, target_addr, client->send_buf, sizeof(client->send_buf),
+ client->recv_buf, sizeof(client->recv_buf));
+ isotp_init_link(&tp->func_link, target_addr, tp->func_send_buf, sizeof(tp->func_send_buf),
+ tp->func_recv_buf, sizeof(tp->func_recv_buf));
+ return UDS_OK;
+}
+
+UDSErr_t UDSTpISOTpCInitSess(UDSTpISOTpC_t *tp, UDSSess_t *sess, const char *ifname, uint32_t source_addr, uint32_t target_addr, uint32_t source_addr_func) {
+ assert(tp);
+ assert(ifname);
+ tp->hdl.poll = tp_poll;
+ tp->hdl.recv = tp_recv;
+ tp->hdl.send = tp_send;
+
+ tp->phys_sa = source_addr;
+ tp->phys_ta = target_addr;
+ tp->func_sa = source_addr_func;
+ tp->func_ta = target_addr;
+
+
+ isotp_init_link(&tp->phys_link, target_addr, sess->send_buf, sizeof(sess->send_buf),
+ sess->recv_buf, sizeof(sess->recv_buf));
+ isotp_init_link(&tp->func_link, target_addr, tp->func_send_buf, sizeof(tp->func_send_buf),
+ tp->func_recv_buf, sizeof(tp->func_recv_buf));
+ return UDS_OK;
}
\ No newline at end of file
diff --git a/tp/isotp_c_socketcan.h b/tp/isotp_c_socketcan.h
index e4de4f4..a3dcec6 100644
--- a/tp/isotp_c_socketcan.h
+++ b/tp/isotp_c_socketcan.h
@@ -2,7 +2,7 @@
#define ISOTP_C_SOCKETCAN_H
#include "iso14229.h"
-#include "tp/isotp_c.h"
+#include "tp/isotp-c/isotp.h"
typedef struct {
UDSTpHandle_t hdl;
@@ -11,8 +11,18 @@ typedef struct {
uint8_t func_recv_buf[8];
uint8_t func_send_buf[8];
int fd;
-} UDSTpISOTpCSocketCAN_t;
+ uint32_t phys_sa, phys_ta;
+ uint32_t func_sa, func_ta;
+ char tag[16];
+} UDSTpISOTpC_t;
+
+UDSErr_t UDSTpISOTpCInitServer(UDSTpISOTpC_t *tp, UDSServer_t *srv, const char *ifname, uint32_t source_addr,
+ uint32_t target_addr, uint32_t target_addr_func);
+UDSErr_t UDSTpISOTpCInitClient(UDSTpISOTpC_t *tp, UDSClient_t *client, const char *ifname, uint32_t source_addr,
+ uint32_t target_addr, uint32_t target_addr_func);
+UDSErr_t UDSTpISOTpCInitSess(UDSTpISOTpC_t *tp, UDSSess_t *sess, const char *ifname, uint32_t source_addr,
+ uint32_t target_addr, uint32_t target_addr_func);
+void UDSTpISOTpCDeinit(UDSTpISOTpC_t *tp);
-UDSTpHandle_t *UDSTpISOTpCSocketCANInit();
#endif
\ No newline at end of file
diff --git a/tp/isotp_sock.c b/tp/isotp_sock.c
index 19917f1..688febf 100644
--- a/tp/isotp_sock.c
+++ b/tp/isotp_sock.c
@@ -159,7 +159,7 @@ UDSErr_t UDSTpIsoTpSockInitServer(UDSTpIsoTpSock_t *tp, const char *ifname, uint
if (tp->phys_fd < 0 || tp->func_fd < 0) {
return UDS_ERR;
}
- printf("%s initialized phys link rx 0x%03x tx 0x%03x func link rx 0x%03x tx 0x%03x\n",
+ UDS_DBG_PRINT("%s initialized phys link rx 0x%03x tx 0x%03x func link rx 0x%03x tx 0x%03x\n",
tp->tag ? tp->tag : "server", source_addr, target_addr, source_addr_func, target_addr);
return UDS_OK;
}
diff --git a/tp/isotp_sock.h b/tp/isotp_sock.h
index 119d66c..2fbd0fc 100644
--- a/tp/isotp_sock.h
+++ b/tp/isotp_sock.h
@@ -6,9 +6,9 @@
typedef struct {
UDSTpHandle_t hdl;
int phys_fd;
- int phys_sa, phys_ta;
int func_fd;
- int func_sa, func_ta;
+ uint32_t phys_sa, phys_ta;
+ uint32_t func_sa, func_ta;
char tag[16];
} UDSTpIsoTpSock_t;
From fbadc064b52ff4df02576ab34c8bb9d86c6ffcb0 Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Fri, 10 Nov 2023 23:26:26 -0700
Subject: [PATCH 08/56] finish setting up qemu toolchains and platforms
---
.bazelrc | 24 +++
Makefile | 8 +-
platforms/BUILD | 49 ++++++
platforms/compiler/BUILD | 5 +
platforms/cpu/BUILD | 3 +
test/BUILD | 59 ++++++-
test/README.md | 44 ++++++
fuzz_server.c => test/test_fuzz_server.c | 0
.../test_server_0x23_read_memory_by_address.c | 45 ++++--
test_examples.py | 29 ----
test_qemu.py | 16 --
toolchain/BUILD | 45 ++++++
toolchain/clang.bzl | 147 ++++++++++++++++++
toolchain/gcc_family.bzl | 117 ++++++++++++++
14 files changed, 525 insertions(+), 66 deletions(-)
create mode 100644 .bazelrc
create mode 100644 platforms/BUILD
create mode 100644 platforms/compiler/BUILD
create mode 100644 platforms/cpu/BUILD
create mode 100644 test/README.md
rename fuzz_server.c => test/test_fuzz_server.c (100%)
delete mode 100755 test_examples.py
delete mode 100755 test_qemu.py
create mode 100644 toolchain/BUILD
create mode 100644 toolchain/clang.bzl
create mode 100644 toolchain/gcc_family.bzl
diff --git a/.bazelrc b/.bazelrc
new file mode 100644
index 0000000..774d973
--- /dev/null
+++ b/.bazelrc
@@ -0,0 +1,24 @@
+build --strip=never
+build --incompatible_enable_cc_toolchain_resolution
+
+build --extra_toolchains //toolchain:arm_gcc
+build --extra_toolchains //toolchain:ppc_gcc
+build --extra_toolchains //toolchain:ppc64_gcc
+build --extra_toolchains //toolchain:ppc64le_gcc
+build --extra_toolchains //toolchain:x86_64_clang
+
+build:arm --platforms=//platforms:arm
+build:ppc --platforms=//platforms:ppc
+build:ppc64 --platforms=//platforms:ppc64
+build:ppc64le --platforms=//platforms:ppc64le
+build:x86_64_clang --platforms=//platforms:x86_64_clang
+
+test:arm --run_under="qemu-arm -L /usr/arm-linux-gnueabihf/ "
+test:ppc --run_under="qemu-ppc -L /usr/powerpc-linux-gnu/ "
+test:ppc64 --run_under="qemu-ppc64 -L /usr/powerpc64-linux-gnu/ "
+test:ppc64le --run_under="qemu-ppc64le -L /usr/powerpc64le-linux-gnu/ "
+
+test: --test_output=all
+
+# parallel tests break on a single vcan interface
+test: --local_test_jobs=1
\ No newline at end of file
diff --git a/Makefile b/Makefile
index 1bcd74f..6d17ac5 100644
--- a/Makefile
+++ b/Makefile
@@ -32,11 +32,11 @@ test_qemu: Makefile iso14229.h iso14229.c test_iso14229.c test_qemu.py
test: cxx unit_test test_examples uds_prefix test_qemu
-fuzz: CC=clang-14
+fuzz: CC=clang-15
fuzz: ASAN = -fsanitize=fuzzer,signed-integer-overflow,address,undefined -fprofile-instr-generate -fcoverage-mapping
-fuzz: OPTS = -g -DUDS_TP=UDS_TP_CUSTOM -DUDS_CUSTOM_MILLIS
-fuzz: iso14229.c iso14229.h fuzz_server.c Makefile
- $(CC) $(OPTS) $(WARN) $(INCS) $(TFLAGS) $(ASAN) fuzz_server.c iso14229.c -o fuzzer
+fuzz: OPTS = -g -DUDS_TP=UDS_TP_CUSTOM -DUDS_CUSTOM_MILLIS -I.
+fuzz: iso14229.c iso14229.h test/test_fuzz_server.c Makefile
+ $(CC) $(OPTS) $(WARN) $(INCS) $(TFLAGS) $(ASAN) test/test_fuzz_server.c iso14229.c -o fuzzer
$(RUN) ./fuzzer corpus
clean:
diff --git a/platforms/BUILD b/platforms/BUILD
new file mode 100644
index 0000000..659ec5c
--- /dev/null
+++ b/platforms/BUILD
@@ -0,0 +1,49 @@
+package(default_visibility = ["//visibility:public"])
+
+platform(
+ name = "x86_64",
+ constraint_values = [
+ "@platforms//cpu:x86_64",
+ "@platforms//os:linux",
+ ],
+)
+
+platform(
+ name = "x86_64_clang",
+ parents = [":x86_64"],
+ constraint_values = [
+ "//platforms/compiler:clang",
+ ],
+)
+
+platform(
+ name = "arm",
+ constraint_values = [
+ "@platforms//cpu:arm",
+ "@platforms//os:linux",
+ ],
+)
+
+platform(
+ name = "ppc",
+ constraint_values = [
+ "@platforms//cpu:ppc",
+ "@platforms//os:linux",
+ ],
+)
+
+platform(
+ name = "ppc64",
+ constraint_values = [
+ "//platforms/cpu:ppc64",
+ "@platforms//os:linux",
+ ],
+)
+
+platform(
+ name = "ppc64le",
+ constraint_values = [
+ "//platforms/cpu:ppc64le",
+ "@platforms//os:linux",
+ ],
+)
\ No newline at end of file
diff --git a/platforms/compiler/BUILD b/platforms/compiler/BUILD
new file mode 100644
index 0000000..79b892d
--- /dev/null
+++ b/platforms/compiler/BUILD
@@ -0,0 +1,5 @@
+package(default_visibility = ["//visibility:public"])
+
+constraint_setting(name = "compiler")
+constraint_value(name = "gcc", constraint_setting = ":compiler")
+constraint_value(name = "clang", constraint_setting = ":compiler")
\ No newline at end of file
diff --git a/platforms/cpu/BUILD b/platforms/cpu/BUILD
new file mode 100644
index 0000000..9078e7a
--- /dev/null
+++ b/platforms/cpu/BUILD
@@ -0,0 +1,3 @@
+package(default_visibility = ["//visibility:public"])
+constraint_value(name="ppc64", constraint_setting="@platforms//cpu:cpu")
+constraint_value(name="ppc64le", constraint_setting="@platforms//cpu:cpu")
\ No newline at end of file
diff --git a/test/BUILD b/test/BUILD
index 9996c72..7b4a7cc 100644
--- a/test/BUILD
+++ b/test/BUILD
@@ -21,24 +21,73 @@ cc_library(
[
cc_test(
- name=n.split(".c")[0] ,
- srcs=[n],
+ name=src.split(".c")[0] ,
+ srcs=[src],
deps=[":env"],
size = "small",
env={
# "TP": "isotp_sock",
# "TP": "isotp-c",
"TP": "mock",
- }
+ },
)
-
- for n in glob(["test_*.c"])
+ for src in [
+ "test_client_0x11_ECU_reset.c",
+ "test_client_0x22_RDBI_tx_buffer_too_small.c",
+ "test_client_0x22_RDBI_unpack_response.c",
+ "test_client_0x31_RCRRP.c",
+ "test_client_0x34_request_download.c",
+ "test_client_busy.c",
+ "test_client_p2.c",
+ "test_client_suppress_positive_response.c",
+ "test_server_0x10_diag_sess_ctrl_functional_request.c",
+ "test_server_0x10_diag_sess_ctrl_is_disabled_by_default.c",
+ "test_server_0x11_no_send_recv_after_ECU_reset.c",
+ "test_server_0x22_RDBI.c",
+ "test_server_0x23_read_memory_by_address.c",
+ "test_server_0x27_security_access.c",
+ "test_server_0x31_RCRRP.c",
+ "test_server_0x34.c",
+ "test_server_0x3E_suppress_positive_response.c",
+ "test_server_0x83_diagnostic_session_control.c",
+ "test_server_session_timeout.c",
+ ]
]
+cc_test(
+ name = "test_fuzz_server",
+ srcs = [
+ "test_fuzz_server.c",
+ "//:iso14229_srcs",
+ "//tp:srcs",
+ ],
+ defines = [
+ "UDS_TP=UDS_TP_CUSTOM",
+ "UDS_CUSTOM_MILLIS",
+ "UDS_DBG_PRINT=printf",
+ ],
+ copts = [
+ "-g",
+ "-O1",
+ "-fsanitize=fuzzer,signed-integer-overflow,address,undefined",
+ "-fprofile-instr-generate",
+ "-fcoverage-mapping",
+ ],
+ linkopts = [
+ "-fsanitize=fuzzer,signed-integer-overflow,address,undefined",
+ ],
+ size = "enormous",
+ target_compatible_with = ["//platforms/compiler:clang"],
+)
+
sh_test(
name = "test_prefix",
srcs = ["test_prefix.sh"],
data = ["//:iso14229"],
args = ["$(locations //:iso14229)"],
+ size = "small",
+
+ # Not exactly right. It's to prevent this test from being run under qemu
+ target_compatible_with = ["@platforms//cpu:x86_64"],
)
\ No newline at end of file
diff --git a/test/README.md b/test/README.md
new file mode 100644
index 0000000..553e914
--- /dev/null
+++ b/test/README.md
@@ -0,0 +1,44 @@
+
+
+- processor architecture (x86, ARM M4, PPC, ...)
+- transport layer implementation
+
+- fault injection
+- fuzzing
+- style
+
+
+```sh
+#!/bin/bash
+
+bazel test --test_output=all --local_test_jobs=1 //test:all
+
+# If you want to run the qemu tests, you'll need
+sudo apt install -y \
+qemu-system-arm \
+qemu-user \
+gcc-arm-linux-gnueabihf \
+gcc-powerpc-linux-gnu \
+gcc-powerpc64-linux-gnu \
+gcc-powerpc64le-linux-gnu \
+clang-15 \
+```
+
+```sh
+# run host tests
+bazel test //test:all
+
+# run tests in qemu
+bazel test --config=arm //test:all
+bazel test --config=ppc //test:all
+bazel test --config=ppc64 //test:all
+bazel test --config=ppc64le //test:all
+```
+
+
+If building fails with `/usr/bin/ld: cannot find -lstdc++: No such file or directory`
+
+```sh
+sudo apt install libc++-15-dev libc++abi-15-dev
+sudo ln -s /usr/lib/x86_64-linux-gnu/libstdc++.so /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30
+```
\ No newline at end of file
diff --git a/fuzz_server.c b/test/test_fuzz_server.c
similarity index 100%
rename from fuzz_server.c
rename to test/test_fuzz_server.c
diff --git a/test/test_server_0x23_read_memory_by_address.c b/test/test_server_0x23_read_memory_by_address.c
index 8e3c0b9..7ad4ecf 100644
--- a/test/test_server_0x23_read_memory_by_address.c
+++ b/test/test_server_0x23_read_memory_by_address.c
@@ -1,13 +1,12 @@
#include "test/test.h"
-uint8_t fn10(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
- printf("foo!\n");
+uint8_t FakeData[259];
+
+uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
TEST_INT_EQUAL(ev, UDS_SRV_EVT_ReadMemByAddr);
UDSReadMemByAddrArgs_t *r = (UDSReadMemByAddrArgs_t *)arg;
- // 1 2 3 4 5 6 7 8
- TEST_PTR_EQUAL(r->memAddr, (void *)0x000055555555f0c8);
- TEST_INT_EQUAL(r->memSize, 4);
- uint8_t FakeData[4] = {0x01, 0x02, 0x03, 0x04};
+ TEST_PTR_EQUAL(r->memAddr, (void *)0x20481392);
+ TEST_INT_EQUAL(r->memSize, 259);
return r->copy(srv, FakeData, r->memSize);
}
@@ -15,15 +14,37 @@ int main() {
UDSSess_t mock_client;
UDSServer_t srv;
ENV_SERVER_INIT(srv);
- srv.fn = fn10;
+ srv.fn = fn;
ENV_SESS_INIT(mock_client);
- // When the client sends a request download request
- const uint8_t REQ[] = {0x23, 0x18, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0xf0, 0xc8, 0x04};
+ // Prepare fake data
+ for (int i = 0; i < sizeof(FakeData); i++) {
+ FakeData[i] = i % 256;
+ }
+
+ // Prepare expected response
+ uint8_t EXPECTED_RESP[sizeof(FakeData) + 1];
+ EXPECTED_RESP[0] = 0x63; // SID 0x23 + 0x40
+ for (int i = 0; i < sizeof(FakeData); i++) {
+ EXPECTED_RESP[i + 1] = FakeData[i];
+ }
+
+ // Request per ISO14229-1 2020 Table 200
+ const uint8_t REQ[] = {
+ 0x23, // SID
+ 0x24, // AddressAndLengthFormatIdentifier
+ 0x20, // memoryAddress byte #1 (MSB)
+ 0x48, // memoryAddress byte #2
+ 0x13, // memoryAddress byte #3
+ 0x92, // memoryAddress byte #4 (LSB)
+ 0x01, // memorySize byte #1 (MSB)
+ 0x03, // memorySize byte #2 (LSB)
+ };
EXPECT_OK(UDSSessSend(&mock_client, REQ, sizeof(REQ)));
// the server should respond with a positive response within p2 ms
- uint8_t RESP[] = {0x63, 0x01, 0x02, 0x03, 0x04};
EXPECT_WITHIN_MS((mock_client.recv_size > 0), 50);
- TEST_MEMORY_EQUAL(mock_client.recv_buf, RESP, sizeof(RESP));
-}
\ No newline at end of file
+ TEST_MEMORY_EQUAL(mock_client.recv_buf, EXPECTED_RESP, sizeof(EXPECTED_RESP));
+}
+
+// TODO: Tables 202-205
\ No newline at end of file
diff --git a/test_examples.py b/test_examples.py
deleted file mode 100755
index 70d7e08..0000000
--- a/test_examples.py
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/usr/bin/env python
-
-import subprocess
-import sys
-
-transports = [
- "TP=ISOTP_SOCKET",
- "TP=ISOTP_C",
-]
-
-clients = [
- "./client",
- "./examples/client.py",
-]
-
-
-def make_examples(tp: str):
- subprocess.check_call(["make", "clean"])
- for thing in ["server", "client"]:
- subprocess.check_call(" ".join([tp, "make", thing]), shell=True)
-
-
-for tp in transports:
- make_examples(tp)
- server_proc = subprocess.Popen(["./server"], stdout=sys.stdout)
- assert None == server_proc.returncode
- for client in clients:
- subprocess.check_call([client], shell=True)
- server_proc.kill()
diff --git a/test_qemu.py b/test_qemu.py
deleted file mode 100755
index 4cd5669..0000000
--- a/test_qemu.py
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/usr/bin/env python
-
-import subprocess
-
-architectures = [
- "CC=arm-linux-gnueabihf-gcc RUN=qemu-arm LDFLAGS=-L/usr/arm-linux-gnueabihf/ CFLAGS=-static",
- "CC=powerpc-linux-gnu-gcc RUN=qemu-ppc LDFLAGS=-L/usr/powerpc-linux-gnu/ CFLAGS=-static",
- "CC=powerpc64-linux-gnu-gcc RUN=qemu-ppc64 LDFLAGS=-L/usr/powerpc64-linux-gnu/ CFLAGS=-static",
-]
-
-for arch in architectures:
- subprocess.check_call("make clean".split(" "), shell=True)
- args = f"{arch} make unit_test".split(" ")
- ret = subprocess.call(args, shell=True)
- if ret:
- exit(ret)
diff --git a/toolchain/BUILD b/toolchain/BUILD
new file mode 100644
index 0000000..11ee579
--- /dev/null
+++ b/toolchain/BUILD
@@ -0,0 +1,45 @@
+load(":gcc_family.bzl", "gcc_toolchain")
+load(":clang.bzl", "clang_toolchain")
+
+filegroup(
+ name = "empty",
+ srcs = [],
+)
+
+gcc_toolchain(
+ name="arm_gcc",
+ prefix="arm-linux-gnueabihf",
+ target_compatible_with = [
+ "@platforms//os:linux",
+ "@platforms//cpu:arm",
+ ],
+)
+
+gcc_toolchain(
+ name="ppc_gcc",
+ prefix="powerpc-linux-gnu",
+ target_compatible_with = [
+ "@platforms//os:linux",
+ "@platforms//cpu:ppc",
+ ]
+)
+
+gcc_toolchain(
+ name="ppc64_gcc",
+ prefix="powerpc64-linux-gnu",
+ target_compatible_with = [
+ "@platforms//os:linux",
+ "//platforms/cpu:ppc64",
+ ]
+)
+
+gcc_toolchain(
+ name="ppc64le_gcc",
+ prefix="powerpc64le-linux-gnu",
+ target_compatible_with = [
+ "@platforms//os:linux",
+ "//platforms/cpu:ppc64le",
+ ]
+)
+
+clang_toolchain(name="x86_64_clang")
\ No newline at end of file
diff --git a/toolchain/clang.bzl b/toolchain/clang.bzl
new file mode 100644
index 0000000..bfd9d3e
--- /dev/null
+++ b/toolchain/clang.bzl
@@ -0,0 +1,147 @@
+load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES")
+load(
+ "@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl",
+ "feature",
+ "flag_group",
+ "flag_set",
+ "tool_path",
+)
+
+all_link_actions = [
+ ACTION_NAMES.cpp_link_executable,
+ ACTION_NAMES.cpp_link_dynamic_library,
+ ACTION_NAMES.cpp_link_nodeps_dynamic_library,
+]
+
+def _impl(ctx):
+ CLANG = "clang-15"
+ tool_paths = [
+ tool_path(
+ name = "gcc",
+ path = "/usr/bin/" + CLANG,
+ ),
+ tool_path(
+ name = "ld",
+ path = "/usr/bin/ld",
+ ),
+ tool_path(
+ name = "ar",
+ path = "/usr/bin/ar",
+ ),
+ tool_path(
+ name = "cpp",
+ path = "/bin/false",
+ ),
+ tool_path(
+ name = "gcov",
+ path = "/bin/false",
+ ),
+ tool_path(
+ name = "nm",
+ path = "/bin/false",
+ ),
+ tool_path(
+ name = "objdump",
+ path = "/bin/false",
+ ),
+ tool_path(
+ name = "strip",
+ path = "/bin/false",
+ ),
+ ]
+
+ features = [
+ feature(
+ name = "default_linker_flags",
+ enabled = True,
+ flag_sets = [
+ flag_set(
+ actions = all_link_actions,
+ flag_groups = ([
+ flag_group(
+ flags = [
+ "-stdlib=libstdc++",
+ ],
+ ),
+ ]),
+ ),
+ ],
+ ),
+ # feature(
+ # name = "default_compiler_flags",
+ # enabled = True,
+ # flag_sets = [
+ # flag_set(
+ # actions = [ACTION_NAMES.cpp_compile],
+ # flag_groups = ([
+ # flag_group(
+ # flags = [
+ # "-stdlib=libstdc++",
+ # ],
+ # ),
+ # ]),
+ # ),
+ # ],
+ # ),
+ ]
+
+ return cc_common.create_cc_toolchain_config_info(
+ ctx = ctx,
+ features = features,
+ cxx_builtin_include_directories = [
+ # "/usr/{}/include".format(ctx.attr.prefix),
+ "/usr/lib/llvm-15/lib/clang/15.0.7/include",
+ "/usr/lib/llvm-15/lib/clang/15.0.7/share",
+ "/usr/include",
+ "/usr/lib/x86_64-linux-gnu/",
+ ],
+ toolchain_identifier = "local",
+ host_system_name = "local",
+ target_system_name = "local",
+ target_cpu = "k8",
+ target_libc = "unknown",
+ compiler = CLANG,
+ abi_version = "unknown",
+ abi_libc_version = "unknown",
+ tool_paths = tool_paths,
+ )
+
+clang_toolchain_config = rule(
+ implementation = _impl,
+ provides = [CcToolchainConfigInfo],
+)
+
+def clang_toolchain(name):
+ CONFIG_NAME = name + "_config"
+ CC_TOOLCHAIN_NAME = name + "_cc_toolchain"
+
+ clang_toolchain_config(
+ name = CONFIG_NAME,
+ )
+
+ native.cc_toolchain(
+ name = CC_TOOLCHAIN_NAME,
+ toolchain_identifier = "k8-toolchain",
+ toolchain_config = CONFIG_NAME,
+ all_files = ":empty",
+ compiler_files = ":empty",
+ dwp_files = ":empty",
+ linker_files = ":empty",
+ objcopy_files = ":empty",
+ strip_files = ":empty",
+ supports_param_files = 0,
+ )
+
+ native.toolchain(
+ name = name,
+ exec_compatible_with = [
+ "@platforms//os:linux",
+ "@platforms//cpu:x86_64",
+ ],
+ target_compatible_with = [
+ "@platforms//os:linux",
+ "@platforms//cpu:x86_64",
+ ],
+ toolchain = CC_TOOLCHAIN_NAME,
+ toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
+ )
diff --git a/toolchain/gcc_family.bzl b/toolchain/gcc_family.bzl
new file mode 100644
index 0000000..9ebde14
--- /dev/null
+++ b/toolchain/gcc_family.bzl
@@ -0,0 +1,117 @@
+load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES")
+load(
+ "@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl",
+ "tool_path",
+)
+
+all_link_actions = [
+ ACTION_NAMES.cpp_link_executable,
+ ACTION_NAMES.cpp_link_dynamic_library,
+ ACTION_NAMES.cpp_link_nodeps_dynamic_library,
+]
+
+def _impl(ctx):
+ tool_paths = [
+ tool_path(
+ name = "gcc",
+ path = "/usr/bin/{}-gcc".format(ctx.attr.prefix),
+ ),
+ tool_path(
+ name = "ld",
+ path = "/usr/bin/{}-ld".format(ctx.attr.prefix),
+ ),
+ tool_path(
+ name = "ar",
+ path = "/usr/bin/{}-ar".format(ctx.attr.prefix),
+ ),
+ tool_path(
+ name = "cpp",
+ path = "/bin/false",
+ ),
+ tool_path(
+ name = "gcov",
+ path = "/bin/false",
+ ),
+ tool_path(
+ name = "nm",
+ path = "/bin/false",
+ ),
+ tool_path(
+ name = "objdump",
+ path = "/bin/false",
+ ),
+ tool_path(
+ name = "strip",
+ path = "/bin/false",
+ ),
+ ]
+
+ features = [
+ ]
+
+ return cc_common.create_cc_toolchain_config_info(
+ ctx = ctx,
+ features = features,
+ cxx_builtin_include_directories = [
+ "/usr/{}/include".format(ctx.attr.prefix),
+ "/usr/lib/gcc-cross/{}/11/include".format(ctx.attr.prefix),
+ "/usr/include",
+ ],
+ toolchain_identifier = "local",
+ host_system_name = "local",
+ target_system_name = "local",
+ target_cpu = "k8",
+ target_libc = "unknown",
+ compiler = ctx.attr.prefix + "gcc",
+ abi_version = "unknown",
+ abi_libc_version = "unknown",
+ tool_paths = tool_paths,
+ )
+
+gcc_toolchain_config = rule(
+ implementation = _impl,
+ attrs = {
+ "prefix": attr.string(mandatory=True, doc="Prefix of compiler suite"),
+ },
+ provides = [CcToolchainConfigInfo],
+)
+
+def gcc_toolchain(name, prefix, target_compatible_with):
+ """Create a gcc toolchain
+
+ Args:
+ name: Name of the toolchain
+ prefix: Prefix of the compiler suite
+ target_compatible_with: List of targets that this toolchain is compatible with
+ """
+ CONFIG_NAME = name + "_config"
+ CC_TOOLCHAIN_NAME = name + "_cc_toolchain"
+
+ gcc_toolchain_config(
+ name = CONFIG_NAME,
+ prefix = prefix,
+ )
+
+ native.cc_toolchain(
+ name = CC_TOOLCHAIN_NAME,
+ toolchain_identifier = "k8-toolchain",
+ toolchain_config = CONFIG_NAME,
+ all_files = ":empty",
+ compiler_files = ":empty",
+ dwp_files = ":empty",
+ linker_files = ":empty",
+ objcopy_files = ":empty",
+ strip_files = ":empty",
+ supports_param_files = 0,
+ )
+
+ native.toolchain(
+ name = name,
+ exec_compatible_with = [
+ "@platforms//os:linux",
+ "@platforms//cpu:x86_64",
+ ],
+ target_compatible_with = target_compatible_with,
+ toolchain = CC_TOOLCHAIN_NAME,
+ toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
+ )
\ No newline at end of file
From 90b4c4d89e666650762153c92acc04a98ad64ee1 Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Wed, 15 Nov 2023 01:58:16 -0700
Subject: [PATCH 09/56] add isotp-c as submodule
---
.bazelrc | 2 +-
.gitmodules | 3 +
README.md | 99 ++
iso14229.c | 1199 +++++++----------
iso14229.h | 230 ++--
run_clang_format.sh | 2 +-
test/BUILD | 36 +-
test/README.md | 6 +
test/env.c | 116 +-
test/env.h | 12 +-
test/test.h | 32 +
test/test_client_0x11_ECU_reset.c | 5 +-
...est_client_0x22_RDBI_tx_buffer_too_small.c | 19 -
test/test_client_0x22_RDBI_unpack_response.c | 19 +-
test/test_client_0x31_RCRRP.c | 8 +-
test/test_client_p2.c | 6 +-
test/test_fuzz_server.c | 100 +-
...r_0x10_diag_sess_ctrl_functional_request.c | 10 +-
...10_diag_sess_ctrl_is_disabled_by_default.c | 8 +-
...server_0x11_no_send_recv_after_ECU_reset.c | 21 +-
test/test_server_0x22_RDBI.c | 18 +-
.../test_server_0x23_read_memory_by_address.c | 8 +-
test/test_server_0x27_security_access.c | 24 +-
test/test_server_0x31_RCRRP.c | 37 +-
test/test_server_0x34.c | 16 +-
...t_server_0x3E_suppress_positive_response.c | 6 +-
...t_server_0x83_diagnostic_session_control.c | 6 +-
test/test_server_session_timeout.c | 2 +-
test_iso14229.c | 86 +-
tp/isotp-c | 1 +
tp/isotp-c/.gitignore | 17 -
tp/isotp-c/.travis.yml | 6 -
tp/isotp-c/CMakeLists.txt | 19 -
tp/isotp-c/LICENSE | 21 -
tp/isotp-c/Makefile | 66 -
tp/isotp-c/README.md | 189 ---
tp/isotp-c/isotp.c | 510 -------
tp/isotp-c/isotp.h | 130 --
tp/isotp-c/isotp_config.h | 29 -
tp/isotp-c/isotp_defines.h | 225 ----
tp/isotp-c/isotp_user.h | 26 -
tp/isotp-c/vars.mk | 63 -
tp/isotp_c_socketcan.c | 29 +-
tp/isotp_c_socketcan.h | 7 +-
tp/isotp_sock.c | 76 +-
tp/isotp_sock.h | 4 +
tp/mock.c | 194 ++-
tp/mock.h | 42 +-
48 files changed, 1217 insertions(+), 2573 deletions(-)
create mode 100644 .gitmodules
delete mode 100644 test/test_client_0x22_RDBI_tx_buffer_too_small.c
create mode 160000 tp/isotp-c
delete mode 100644 tp/isotp-c/.gitignore
delete mode 100644 tp/isotp-c/.travis.yml
delete mode 100644 tp/isotp-c/CMakeLists.txt
delete mode 100644 tp/isotp-c/LICENSE
delete mode 100644 tp/isotp-c/Makefile
delete mode 100644 tp/isotp-c/README.md
delete mode 100644 tp/isotp-c/isotp.c
delete mode 100644 tp/isotp-c/isotp.h
delete mode 100644 tp/isotp-c/isotp_config.h
delete mode 100644 tp/isotp-c/isotp_defines.h
delete mode 100644 tp/isotp-c/isotp_user.h
delete mode 100644 tp/isotp-c/vars.mk
diff --git a/.bazelrc b/.bazelrc
index 774d973..9df87aa 100644
--- a/.bazelrc
+++ b/.bazelrc
@@ -18,7 +18,7 @@ test:ppc --run_under="qemu-ppc -L /usr/powerpc-linux-gnu/ "
test:ppc64 --run_under="qemu-ppc64 -L /usr/powerpc64-linux-gnu/ "
test:ppc64le --run_under="qemu-ppc64le -L /usr/powerpc64le-linux-gnu/ "
-test: --test_output=all
+test: --test_output=all
# parallel tests break on a single vcan interface
test: --local_test_jobs=1
\ No newline at end of file
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..0a9e643
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "tp/isotp-c"]
+ path = tp/isotp-c
+ url = https://github.com/driftregion/isotp-c.git
diff --git a/README.md b/README.md
index 856a8dc..7448ec8 100644
--- a/README.md
+++ b/README.md
@@ -363,6 +363,8 @@ MIT
- test refactoring. theme: test invariance across different transports and processor architectures
- breaking API changes:
- rename `phys_send_id`, `phys_recv_id`, `func_send_id`, and `func_recv_id` to be consistent with the standard. Now mandatory for all UDSServerConfig_t and UDSClientConfig_t regardless of transport layer implementation
+ - overhauled transport layer implementation
+ - simplified client and server init
## 0.6.0
- breaking API changes:
@@ -566,6 +568,103 @@ server -> client : Service Response
@enduml
```
+
+```plantuml
+@startuml
+' !pragma useVerticalIf on
+title UDSServerPoll Flowchart
+|Server|
+start
+
+if (DefaultSession != sessionType \n&& s3_timeout) then (true)
+:Emit SessionTimeout;
+else (false)
+endif
+
+if (ecuResetScheduled\n&& ecuResetTimer) then (false)
+else (true)
+:Emit DoScheduledReset;
+endif
+
+if (tp_status & TP_SEND_IN_PROGRESS) then (false)
+:UDSTpPeek();
+else (true)
+stop
+endif
+
+:evaluateServiceResponse();
+|User|
+:resp = handler();
+|Server|
+if (resp) then (anything else)
+else (0x78)
+ fork
+ |Server|
+ :wait p2 ms;
+ :send response (0x78);
+ repeat
+ if (time after p2*) then (yes)
+ :send response (0x78);
+ else (no)
+ endif
+ :wait 1ms;
+ repeat while (resp) is (0x78 RCRRP)
+ ->anything else;
+
+ ' while (resp) is (0x78 RCRRP)
+ ' :wait p2* ms;
+ ' :send response (0x78);
+ ' endwhile (not 0x78 RCRRP)
+
+ fork again
+ while (resp) is (0x78 RCRRP)
+ :evaluateServiceResponse();
+ |User|
+ :resp = handler();
+ |Server|
+ :wait 1ms;
+ endwhile (not 0x78 RCRRP)
+ end fork
+endif
+|Server|
+:wait p2 ms;
+:send response;
+:UDSTpAckRecv();
+
+
+@enduml
+```
+
+```plantuml
+@startuml
+!pragma teoz true
+title Service Processing
+participant client
+participant server
+participant fn
+{t1} client -> server : request
+activate server
+server -> fn: call()
+fn -> server
+{t2} server -> client: response
+deactivate server
+{t1} <-> {t2} : p2_server
+
+@enduml
+```
+
+
+```plantuml
+@startuml
+title UDSServerPoll() Request Lifecycle
+[*] -> UDSTpPeek
+UDSTpPeek -> UDSTpPeek: recv_len == 0
+UDSTpPeek --> evaluateServiceResponse: recv_len > 0 &&\n !notReadyToReceive
+
+@enduml
+```
+
+
```plantuml
@startuml
' !pragma useVerticalIf on
diff --git a/iso14229.c b/iso14229.c
index 06a8060..923e0fd 100644
--- a/iso14229.c
+++ b/iso14229.c
@@ -77,278 +77,63 @@ enum UDSDiagnosticServiceId {
// Transports
// ========================================================================
-#if UDS_TP == UDS_TP_CUSTOM
-#else
-static UDSTpStatus_t tp_poll(UDSTpHandle_t *hdl) {
- assert(hdl);
- UDSTpStatus_t status = 0;
-#if UDS_TP == UDS_TP_ISOTP_C
- UDSTpIsoTpC_t *impl = (UDSTpIsoTpC_t *)hdl;
- isotp_poll(&impl->phys_link);
- isotp_poll(&impl->func_link);
- if (impl->phys_link.send_status == ISOTP_SEND_STATUS_INPROGRESS) {
- status |= UDS_TP_SEND_IN_PROGRESS;
- }
-#elif UDS_TP == UDS_TP_ISOTP_SOCKET
-#endif
- return status;
+/**
+ * @brief
+ *
+ * @param hdl
+ * @param info, if NULL, the default values are used:
+ * A_Mtype: message type (diagnostic (DEFAULT), remote diagnostic, secure diagnostic, secure
+ * remote diagnostic)
+ * A_TA_Type: application target address type (physical (DEFAULT) or functional)
+ * A_SA: unused
+ * A_TA: unused
+ * A_AE: unused
+ * @return ssize_t
+ */
+ssize_t UDSTpGetSendBuf(struct UDSTpHandle *hdl, uint8_t **buf) {
+ assert(hdl->get_send_buf);
+ return hdl->get_send_buf(hdl, buf);
}
-#endif
-
-#if UDS_TP == UDS_TP_CUSTOM
-#else
-static ssize_t tp_recv(UDSTpHandle_t *hdl, void *buf, size_t count, UDSTpAddr_t *ta_type) {
- assert(hdl);
- assert(ta_type);
- assert(buf);
- int ret = -1;
-#if UDS_TP == UDS_TP_ISOTP_C
- uint16_t size = 0;
- UDSTpIsoTpC_t *impl = (UDSTpIsoTpC_t *)hdl;
- struct {
- IsoTpLink *link;
- UDSTpAddr_t ta_type;
- } arr[] = {{&impl->phys_link, kTpAddrTypePhysical}, {&impl->func_link, kTpAddrTypeFunctional}};
- for (size_t i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) {
- ret = isotp_receive(arr[i].link, buf, count, &size);
- switch (ret) {
- case ISOTP_RET_OK:
- *ta_type = arr[i].ta_type;
- ret = size;
- goto done;
- case ISOTP_RET_NO_DATA:
- ret = 0;
- continue;
- case ISOTP_RET_ERROR:
- ret = -1;
- goto done;
- default:
- ret = -2;
- goto done;
- }
- }
-#elif UDS_TP == UDS_TP_ISOTP_SOCKET
- UDSTpLinuxIsoTp_t *impl = (UDSTpLinuxIsoTp_t *)hdl;
- struct {
- int fd;
- UDSTpAddr_t ta_type;
- } arr[] = {{impl->phys_fd, kTpAddrTypePhysical}, {impl->func_fd, kTpAddrTypeFunctional}};
- for (size_t i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) {
- ret = read(arr[i].fd, buf, count);
- if (ret < 0) {
- if (EAGAIN == errno || EWOULDBLOCK == errno) {
- ret = 0;
- continue;
- } else {
- UDS_DBG_PRINT("read failed: %d with errno: %d\n", ret, errno);
- if (EILSEQ == errno) {
- UDS_DBG_PRINT("Perhaps I received multiple responses?\n");
- }
- goto done;
- }
- } else {
- *ta_type = arr[i].ta_type;
- goto done;
- }
- }
-#endif
-done:
- if (ret > 0) {
- UDS_DBG_PRINT("<<< ");
- UDS_DBG_PRINTHEX(buf, ret);
- }
- return ret;
+ssize_t UDSTpSend(struct UDSTpHandle *hdl, const uint8_t *buf, ssize_t len, UDSSDU_t *info) {
+ assert(hdl->send);
+ return hdl->send(hdl, (uint8_t*)buf, len, info);
}
-#endif
-
-#if UDS_TP == UDS_TP_CUSTOM
-#else
-static ssize_t tp_send(UDSTpHandle_t *hdl, const void *buf, size_t count, UDSTpAddr_t ta_type) {
- assert(hdl);
- ssize_t ret = -1;
-#if UDS_TP == UDS_TP_ISOTP_C
- UDSTpIsoTpC_t *impl = (UDSTpIsoTpC_t *)hdl;
- IsoTpLink *link = NULL;
- switch (ta_type) {
- case kTpAddrTypePhysical:
- link = &impl->phys_link;
- break;
- case kTpAddrTypeFunctional:
- link = &impl->func_link;
- break;
- default:
- ret = -4;
- goto done;
- }
- int send_status = isotp_send(link, buf, count);
- switch (send_status) {
- case ISOTP_RET_OK:
- ret = count;
- goto done;
- case ISOTP_RET_INPROGRESS:
- case ISOTP_RET_OVERFLOW:
- default:
- ret = send_status;
- goto done;
- }
-#elif UDS_TP == UDS_TP_ISOTP_SOCKET
- UDSTpLinuxIsoTp_t *impl = (UDSTpLinuxIsoTp_t *)hdl;
- int fd;
- switch (ta_type) {
- case kTpAddrTypePhysical:
- fd = impl->phys_fd;
- break;
- case kTpAddrTypeFunctional:
- fd = impl->func_fd;
- break;
- default:
- ret = -4;
- goto done;
- }
- ret = write(fd, buf, count);
- if (ret < 0) {
- perror("write");
- }
-#endif
-done:
- UDS_DBG_PRINT(">>> ");
- UDS_DBG_PRINTHEX(buf, ret);
- return ret;
+UDSTpStatus_t UDSTpPoll(struct UDSTpHandle *hdl) {
+ assert(hdl->poll);
+ return hdl->poll(hdl);
}
-#endif
-#if UDS_TP == UDS_TP_ISOTP_SOCKET
-static int LinuxSockBind(const char *if_name, uint32_t rxid, uint32_t txid) {
- int fd = 0;
- struct ifreq ifr = {0};
- struct sockaddr_can addr = {0};
- struct can_isotp_fc_options fcopts = {
- .bs = 0x10,
- .stmin = 3,
- .wftmax = 0,
- };
-
- if ((fd = socket(AF_CAN, SOCK_DGRAM | SOCK_NONBLOCK, CAN_ISOTP)) < 0) {
- fprintf(stderr, "socket: %s", strerror(errno));
- return -1;
- }
-
- if (setsockopt(fd, SOL_CAN_ISOTP, CAN_ISOTP_RECV_FC, &fcopts, sizeof(fcopts)) < 0) {
- perror("setsockopt");
- return -1;
- }
-
- strncpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name) - 1);
- if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
- fprintf(stderr, "ioctl: %s %s\n", strerror(errno), if_name);
- return -1;
- }
-
- addr.can_family = AF_CAN;
-
- addr.can_addr.tp.rx_id = rxid;
- addr.can_addr.tp.tx_id = txid;
- addr.can_ifindex = ifr.ifr_ifindex;
-
- if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
- fprintf(stderr, "bind: %s %s\n", strerror(errno), if_name);
- return -1;
- }
- printf("opened ISO-TP link fd: %d, rxid: %03x, txid: %03x\n", fd, rxid, txid);
- return fd;
+ssize_t UDSTpPeek(struct UDSTpHandle *hdl, uint8_t **buf, UDSSDU_t *info) {
+ assert(hdl->peek);
+ return hdl->peek(hdl, buf, info);
}
-static int LinuxSockTpOpen(UDSTpHandle_t *hdl, const char *if_name, uint32_t phys_rxid,
- uint32_t phys_txid, uint32_t func_rxid, uint32_t func_txid) {
- assert(if_name);
- UDSTpLinuxIsoTp_t *impl = (UDSTpLinuxIsoTp_t *)hdl;
- hdl->recv = tp_recv;
- hdl->send = tp_send;
- hdl->poll = tp_poll;
- impl->phys_fd = LinuxSockBind(if_name, phys_rxid, phys_txid);
- impl->func_fd = LinuxSockBind(if_name, func_rxid, func_txid);
- if (impl->phys_fd < 0 || impl->func_fd < 0) {
- return -1;
- }
- return 0;
-}
-
-static void LinuxSockTpClose(UDSTpHandle_t *hdl) {
- if (hdl) {
- UDSTpLinuxIsoTp_t *impl = (UDSTpLinuxIsoTp_t *)hdl;
- if (impl) {
- if (close(impl->phys_fd) < 0) {
- perror("failed to close socket");
- }
- if (close(impl->func_fd) < 0) {
- perror("failed to close socket");
- }
+const uint8_t *UDSTpGetRecvBuf(struct UDSTpHandle *hdl, size_t *p_len) {
+ assert(hdl);
+ ssize_t len = 0;
+ uint8_t *buf = NULL;
+ len = UDSTpPeek(hdl, &buf, NULL);
+ if (len > 0) {
+ if (p_len) {
+ *p_len = len;
}
+ return buf;
+ } else {
+ return NULL;
}
}
-#endif // #if UDS_TP == UDS_TP_ISOTP_SOCKET
-
-ssize_t UDSTpSend(UDSTpHandle_t *tp, const uint8_t *msg, size_t size) {
- return tp->send(tp, &(UDSSDU_t){
- .A_Mtype = UDS_A_MTYPE_DIAG,
- .A_SA = 0x7E0,
- .A_TA = 0x7E8,
- .A_TA_Type = UDS_A_TA_TYPE_PHYSICAL,
- .A_Length = size,
- .A_Data = msg,
- });
-}
-
-ssize_t UDSTpSendFunctional(UDSTpHandle_t *tp, const uint8_t *msg, size_t size) {
- return tp->send(tp, &(UDSSDU_t){
- .A_Mtype = UDS_A_MTYPE_DIAG,
- .A_SA = 0x7E0,
- .A_TA = 0x7DF,
- .A_TA_Type = UDS_A_TA_TYPE_FUNCTIONAL,
- .A_Length = size,
- .A_Data = msg,
- });
-}
-
-void UDSSessInit(UDSSess_t *sess, const UDSSessConfig_t *cfg) {
- assert(sess);
- assert(cfg);
- memset(sess, 0, sizeof(*sess));
- sess->tp = cfg->tp;
- sess->source_addr = cfg->source_addr;
- sess->target_addr = cfg->target_addr;
- sess->source_addr_func = cfg->source_addr_func;
- sess->target_addr_func = cfg->target_addr_func;
-}
-
-UDSErr_t UDSSessSend(UDSSess_t *sess, const uint8_t *msg, size_t size) {
- assert(sess);
- assert(msg);
- assert(size);
- UDSTpSend(sess->tp, msg, size);
- return UDS_OK;
-}
-UDSErr_t UDSSessSendFunctional(UDSSess_t *sess, const uint8_t *msg, size_t size) {
- assert(sess);
- assert(msg);
- assert(size);
- UDSTpSendFunctional(sess->tp, msg, size);
- return UDS_OK;
+size_t UDSTpGetRecvLen(UDSTpHandle_t *hdl) {
+ assert(hdl);
+ size_t len = 0;
+ UDSTpGetRecvBuf(hdl, &len);
+ return len;
}
-void UDSSessPoll(UDSSess_t *sess) {
- assert(sess);
- UDSTpHandle_t *tp = sess->tp;
- UDSSDU_t msg = {
- .A_DataBufSize = sizeof(sess->recv_buf),
- .A_Data = sess->recv_buf,
- };
- ssize_t ret = tp->recv(tp, &msg);
- if (ret > 0) {
- sess->recv_size = ret;
- }
+void UDSTpAckRecv(UDSTpHandle_t *hdl) {
+ assert(hdl);
+ hdl->ack_recv(hdl);
}
// ========================================================================
@@ -357,7 +142,7 @@ void UDSSessPoll(UDSSess_t *sess) {
#if UDS_CUSTOM_MILLIS
#else
-uint32_t UDSMillis() {
+uint32_t UDSMillis(void) {
#if UDS_ARCH == UDS_ARCH_UNIX
struct timeval te;
gettimeofday(&te, NULL);
@@ -384,24 +169,32 @@ static bool UDSSecurityAccessLevelIsReserved(uint8_t securityLevel) {
// Server
// ========================================================================
-typedef uint8_t (*UDSService)(UDSServer_t *self);
-
-static inline uint8_t NegativeResponse(UDSServer_t *self, uint8_t response_code) {
- self->send_buf[0] = 0x7F;
- self->send_buf[1] = self->recv_buf[0];
- self->send_buf[2] = response_code;
- self->send_size = UDS_NEG_RESP_LEN;
+static inline uint8_t NegativeResponse(UDSReq_t *r, uint8_t response_code) {
+ r->send_buf[0] = 0x7F;
+ r->send_buf[1] = r->recv_buf[0];
+ r->send_buf[2] = response_code;
+ r->send_len = UDS_NEG_RESP_LEN;
return response_code;
}
-static inline void NoResponse(UDSServer_t *self) { self->send_size = 0; }
+static inline void NoResponse(UDSReq_t *r) { r->send_len = 0; }
-static uint8_t _0x10_DiagnosticSessionControl(UDSServer_t *self) {
- if (self->recv_size < UDS_0X10_REQ_LEN) {
- return NegativeResponse(self, kIncorrectMessageLengthOrInvalidFormat);
+static uint8_t EmitEvent(UDSServer_t *srv, UDSServerEvent_t evt, void *data) {
+ if (srv->fn) {
+ return srv->fn(srv, evt, data);
+ } else {
+ UDS_DBG_PRINT("Unhandled UDSServerEvent %d, srv.fn not installed!\n", evt);
+ return kGeneralReject;
}
+}
+
- uint8_t sessType = self->recv_buf[1] & 0x4F;
+static uint8_t _0x10_DiagnosticSessionControl(UDSServer_t *srv, UDSReq_t *r) {
+ if (r->recv_len < UDS_0X10_REQ_LEN) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
+ }
+
+ uint8_t sessType = r->recv_buf[1] & 0x4F;
UDSDiagSessCtrlArgs_t args = {
.type = sessType,
@@ -409,13 +202,13 @@ static uint8_t _0x10_DiagnosticSessionControl(UDSServer_t *self) {
.p2_star_ms = UDS_CLIENT_DEFAULT_P2_STAR_MS,
};
- uint8_t err = self->fn(self, UDS_SRV_EVT_DiagSessCtrl, &args);
+ uint8_t err = EmitEvent(srv, UDS_SRV_EVT_DiagSessCtrl, &args);
if (kPositiveResponse != err) {
- return NegativeResponse(self, err);
+ return NegativeResponse(r, err);
}
- self->sessionType = sessType;
+ srv->sessionType = sessType;
switch (sessType) {
case kDefaultSession:
@@ -423,31 +216,31 @@ static uint8_t _0x10_DiagnosticSessionControl(UDSServer_t *self) {
case kProgrammingSession:
case kExtendedDiagnostic:
default:
- self->s3_session_timeout_timer = UDSMillis() + self->s3_ms;
+ srv->s3_session_timeout_timer = UDSMillis() + srv->s3_ms;
break;
}
- self->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_DIAGNOSTIC_SESSION_CONTROL);
- self->send_buf[1] = sessType;
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_DIAGNOSTIC_SESSION_CONTROL);
+ r->send_buf[1] = sessType;
// UDS-1-2013: Table 29
// resolution: 1ms
- self->send_buf[2] = args.p2_ms >> 8;
- self->send_buf[3] = args.p2_ms;
+ r->send_buf[2] = args.p2_ms >> 8;
+ r->send_buf[3] = args.p2_ms;
// resolution: 10ms
- self->send_buf[4] = (args.p2_star_ms / 10) >> 8;
- self->send_buf[5] = args.p2_star_ms / 10;
+ r->send_buf[4] = (args.p2_star_ms / 10) >> 8;
+ r->send_buf[5] = args.p2_star_ms / 10;
- self->send_size = UDS_0X10_RESP_LEN;
+ r->send_len = UDS_0X10_RESP_LEN;
return kPositiveResponse;
}
-static uint8_t _0x11_ECUReset(UDSServer_t *self) {
- uint8_t resetType = self->recv_buf[1] & 0x3F;
+static uint8_t _0x11_ECUReset(UDSServer_t *srv, UDSReq_t *r) {
+ uint8_t resetType = r->recv_buf[1] & 0x3F;
- if (self->recv_size < UDS_0X11_REQ_MIN_LEN) {
- return NegativeResponse(self, kIncorrectMessageLengthOrInvalidFormat);
+ if (r->recv_len < UDS_0X11_REQ_MIN_LEN) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
}
UDSECUResetArgs_t args = {
@@ -455,79 +248,83 @@ static uint8_t _0x11_ECUReset(UDSServer_t *self) {
.powerDownTimeMillis = UDS_SERVER_DEFAULT_POWER_DOWN_TIME_MS,
};
- uint8_t err = self->fn(self, UDS_SRV_EVT_EcuReset, &args);
+ uint8_t err = EmitEvent(srv, UDS_SRV_EVT_EcuReset, &args);
if (kPositiveResponse == err) {
- self->notReadyToReceive = true;
- self->ecuResetScheduled = resetType;
- self->ecuResetTimer = UDSMillis() + args.powerDownTimeMillis;
+ srv->notReadyToReceive = true;
+ srv->ecuResetScheduled = resetType;
+ srv->ecuResetTimer = UDSMillis() + args.powerDownTimeMillis;
} else {
- return NegativeResponse(self, err);
+ return NegativeResponse(r, err);
}
- self->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_ECU_RESET);
- self->send_buf[1] = resetType;
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_ECU_RESET);
+ r->send_buf[1] = resetType;
if (kEnableRapidPowerShutDown == resetType) {
uint32_t powerDownTime = args.powerDownTimeMillis / 1000;
if (powerDownTime > 255) {
powerDownTime = 255;
}
- self->send_buf[2] = powerDownTime;
- self->send_size = UDS_0X11_RESP_BASE_LEN + 1;
+ r->send_buf[2] = powerDownTime;
+ r->send_len = UDS_0X11_RESP_BASE_LEN + 1;
} else {
- self->send_size = UDS_0X11_RESP_BASE_LEN;
+ r->send_len = UDS_0X11_RESP_BASE_LEN;
}
return kPositiveResponse;
}
static uint8_t safe_copy(UDSServer_t *srv, const void *src, uint16_t count) {
- if (count <= srv->send_buf_size - srv->send_size) {
- memmove(srv->send_buf + srv->send_size, src, count);
- srv->send_size += count;
+ if (srv == NULL) {
+ return kGeneralReject;
+ }
+ UDSReq_t *r = (UDSReq_t *)&srv->r;
+ if (count <= r->send_buf_size - r->send_len) {
+ memmove(r->send_buf + r->send_len, src, count);
+ r->send_len += count;
return kPositiveResponse;
}
return kResponseTooLong;
}
-static uint8_t _0x22_ReadDataByIdentifier(UDSServer_t *self) {
+static uint8_t _0x22_ReadDataByIdentifier(UDSServer_t *srv, UDSReq_t *r) {
uint8_t numDIDs;
uint16_t dataId = 0;
uint8_t ret = kPositiveResponse;
- self->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_READ_DATA_BY_IDENTIFIER);
- self->send_size = 1;
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_READ_DATA_BY_IDENTIFIER);
+ r->send_len = 1;
- if (0 != (self->recv_size - 1) % sizeof(uint16_t)) {
- return NegativeResponse(self, kIncorrectMessageLengthOrInvalidFormat);
+ if (0 != (r->recv_len - 1) % sizeof(uint16_t)) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
}
- numDIDs = self->recv_size / sizeof(uint16_t);
+ numDIDs = r->recv_len / sizeof(uint16_t);
if (0 == numDIDs) {
- return NegativeResponse(self, kIncorrectMessageLengthOrInvalidFormat);
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
}
for (int did = 0; did < numDIDs; did++) {
uint16_t idx = 1 + did * 2;
- dataId = (self->recv_buf[idx] << 8) + self->recv_buf[idx + 1];
+ dataId = (r->recv_buf[idx] << 8) + r->recv_buf[idx + 1];
- if (self->send_size + 3 > self->send_buf_size) {
- return NegativeResponse(self, kResponseTooLong);
+ if (r->send_len + 3 > r->send_buf_size) {
+ return NegativeResponse(r, kResponseTooLong);
}
- uint8_t *copylocation = self->send_buf + self->send_size;
+ uint8_t *copylocation = r->send_buf + r->send_len;
copylocation[0] = dataId >> 8;
copylocation[1] = dataId;
- self->send_size += 2;
+ r->send_len += 2;
UDSRDBIArgs_t args = {
.dataId = dataId,
.copy = safe_copy,
};
- ret = self->fn(self, UDS_SRV_EVT_ReadDataByIdent, &args);
+ ret = EmitEvent(srv, UDS_SRV_EVT_ReadDataByIdent, &args);
if (kPositiveResponse != ret) {
- return NegativeResponse(self, ret);
+ return NegativeResponse(r, ret);
}
}
return kPositiveResponse;
@@ -537,40 +334,40 @@ static uint8_t _0x22_ReadDataByIdentifier(UDSServer_t *self) {
* @brief decode the addressAndLengthFormatIdentifier that appears in ReadMemoryByAddress (0x23),
* DynamicallyDefineDataIdentifier (0x2C), RequestDownload (0X34)
*
- * @param self
+ * @param srv
* @param buf pointer to addressAndDataLengthFormatIdentifier in recv_buf
* @param memoryAddress the decoded memory address
* @param memorySize the decoded memory size
* @return uint8_t
*/
-static uint8_t decodeAddressAndLength(UDSServer_t *self, uint8_t *const buf, void **memoryAddress,
+static uint8_t decodeAddressAndLength(UDSReq_t *r, uint8_t *const buf, void **memoryAddress,
size_t *memorySize) {
- assert(self);
+ assert(r);
assert(memoryAddress);
assert(memorySize);
long long unsigned int tmp = 0;
*memoryAddress = 0;
*memorySize = 0;
- assert(buf >= self->recv_buf && buf <= self->recv_buf + sizeof(self->recv_buf));
+ assert(buf >= r->recv_buf && buf <= r->recv_buf + sizeof(r->recv_buf));
- if (self->recv_size < 3) {
- return NegativeResponse(self, kIncorrectMessageLengthOrInvalidFormat);
+ if (r->recv_len < 3) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
}
uint8_t memorySizeLength = (buf[0] & 0xF0) >> 4;
uint8_t memoryAddressLength = buf[0] & 0x0F;
if (memorySizeLength == 0 || memorySizeLength > sizeof(size_t)) {
- return NegativeResponse(self, kRequestOutOfRange);
+ return NegativeResponse(r, kRequestOutOfRange);
}
if (memoryAddressLength == 0 || memoryAddressLength > sizeof(size_t)) {
- return NegativeResponse(self, kRequestOutOfRange);
+ return NegativeResponse(r, kRequestOutOfRange);
}
- if (buf + memorySizeLength + memoryAddressLength > self->recv_buf + self->recv_size) {
- return NegativeResponse(self, kIncorrectMessageLengthOrInvalidFormat);
+ if (buf + memorySizeLength + memoryAddressLength > r->recv_buf + r->recv_len) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
}
for (int byteIdx = 0; byteIdx < memoryAddressLength; byteIdx++) {
@@ -588,18 +385,18 @@ static uint8_t decodeAddressAndLength(UDSServer_t *self, uint8_t *const buf, voi
return kPositiveResponse;
}
-static uint8_t _0x23_ReadMemoryByAddress(UDSServer_t *self) {
+static uint8_t _0x23_ReadMemoryByAddress(UDSServer_t *srv, UDSReq_t *r) {
uint8_t ret = kPositiveResponse;
void *address = 0;
size_t length = 0;
- if (self->recv_size < UDS_0X23_REQ_MIN_LEN) {
- return NegativeResponse(self, kIncorrectMessageLengthOrInvalidFormat);
+ if (r->recv_len < UDS_0X23_REQ_MIN_LEN) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
}
- ret = decodeAddressAndLength(self, &self->recv_buf[1], &address, &length);
+ ret = decodeAddressAndLength(r, &r->recv_buf[1], &address, &length);
if (kPositiveResponse != ret) {
- return NegativeResponse(self, ret);
+ return NegativeResponse(r, ret);
}
UDSReadMemByAddrArgs_t args = {
@@ -608,51 +405,51 @@ static uint8_t _0x23_ReadMemoryByAddress(UDSServer_t *self) {
.copy = safe_copy,
};
- self->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_READ_MEMORY_BY_ADDRESS);
- self->send_size = UDS_0X23_RESP_BASE_LEN;
- ret = self->fn(self, UDS_SRV_EVT_ReadMemByAddr, &args);
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_READ_MEMORY_BY_ADDRESS);
+ r->send_len = UDS_0X23_RESP_BASE_LEN;
+ ret = EmitEvent(srv, UDS_SRV_EVT_ReadMemByAddr, &args);
if (kPositiveResponse != ret) {
- return NegativeResponse(self, ret);
+ return NegativeResponse(r, ret);
}
- if (self->send_size != UDS_0X23_RESP_BASE_LEN + length) {
+ if (r->send_len != UDS_0X23_RESP_BASE_LEN + length) {
return kGeneralProgrammingFailure;
}
return kPositiveResponse;
}
-static uint8_t _0x27_SecurityAccess(UDSServer_t *self) {
- uint8_t subFunction = self->recv_buf[1];
+static uint8_t _0x27_SecurityAccess(UDSServer_t *srv, UDSReq_t *r) {
+ uint8_t subFunction = r->recv_buf[1];
uint8_t response = kPositiveResponse;
if (UDSSecurityAccessLevelIsReserved(subFunction)) {
- return NegativeResponse(self, kIncorrectMessageLengthOrInvalidFormat);
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
}
- self->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_SECURITY_ACCESS);
- self->send_buf[1] = subFunction;
- self->send_size = UDS_0X27_RESP_BASE_LEN;
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_SECURITY_ACCESS);
+ r->send_buf[1] = subFunction;
+ r->send_len = UDS_0X27_RESP_BASE_LEN;
// Even: sendKey
if (0 == subFunction % 2) {
uint8_t requestedLevel = subFunction - 1;
UDSSecAccessValidateKeyArgs_t args = {
.level = requestedLevel,
- .key = &self->recv_buf[UDS_0X27_REQ_BASE_LEN],
- .len = self->recv_size - UDS_0X27_REQ_BASE_LEN,
+ .key = &r->recv_buf[UDS_0X27_REQ_BASE_LEN],
+ .len = r->recv_len - UDS_0X27_REQ_BASE_LEN,
};
- response = self->fn(self, UDS_SRV_EVT_SecAccessValidateKey, &args);
+ response = EmitEvent(srv, UDS_SRV_EVT_SecAccessValidateKey, &args);
if (kPositiveResponse != response) {
- return NegativeResponse(self, response);
+ return NegativeResponse(r, response);
}
// "requestSeed = 0x01" identifies a fixed relationship between
// "requestSeed = 0x01" and "sendKey = 0x02"
// "requestSeed = 0x03" identifies a fixed relationship between
// "requestSeed = 0x03" and "sendKey = 0x04"
- self->securityLevel = requestedLevel;
- self->send_size = UDS_0X27_RESP_BASE_LEN;
+ srv->securityLevel = requestedLevel;
+ r->send_len = UDS_0X27_RESP_BASE_LEN;
return kPositiveResponse;
}
@@ -665,40 +462,40 @@ static uint8_t _0x27_SecurityAccess(UDSServer_t *self) {
currently locked. The client shall use this method to determine if a server is locked for a
particular security level by checking for a non-zero seed.
*/
- if (subFunction == self->securityLevel) {
+ if (subFunction == srv->securityLevel) {
// Table 52 sends a response of length 2. Use a preprocessor define if this needs
// customizing by the user.
const uint8_t already_unlocked[] = {0x00, 0x00};
- return safe_copy(self, already_unlocked, sizeof(already_unlocked));
+ return safe_copy(srv, already_unlocked, sizeof(already_unlocked));
} else {
UDSSecAccessRequestSeedArgs_t args = {
.level = subFunction,
- .dataRecord = &self->recv_buf[UDS_0X27_REQ_BASE_LEN],
- .len = self->recv_size - UDS_0X27_REQ_BASE_LEN,
+ .dataRecord = &r->recv_buf[UDS_0X27_REQ_BASE_LEN],
+ .len = r->recv_len - UDS_0X27_REQ_BASE_LEN,
.copySeed = safe_copy,
};
- response = self->fn(self, UDS_SRV_EVT_SecAccessRequestSeed, &args);
+ response = EmitEvent(srv, UDS_SRV_EVT_SecAccessRequestSeed, &args);
if (kPositiveResponse != response) {
- return NegativeResponse(self, response);
+ return NegativeResponse(r, response);
}
- if (self->send_size <= UDS_0X27_RESP_BASE_LEN) { // no data was copied
- return NegativeResponse(self, kGeneralProgrammingFailure);
+ if (r->send_len <= UDS_0X27_RESP_BASE_LEN) { // no data was copied
+ return NegativeResponse(r, kGeneralProgrammingFailure);
}
return kPositiveResponse;
}
}
- return NegativeResponse(self, kGeneralProgrammingFailure);
+ return NegativeResponse(r, kGeneralProgrammingFailure);
}
-static uint8_t _0x28_CommunicationControl(UDSServer_t *self) {
- uint8_t controlType = self->recv_buf[1] & 0x7F;
- uint8_t communicationType = self->recv_buf[2];
+static uint8_t _0x28_CommunicationControl(UDSServer_t *srv, UDSReq_t *r) {
+ uint8_t controlType = r->recv_buf[1] & 0x7F;
+ uint8_t communicationType = r->recv_buf[2];
- if (self->recv_size < UDS_0X28_REQ_BASE_LEN) {
- return NegativeResponse(self, kIncorrectMessageLengthOrInvalidFormat);
+ if (r->recv_len < UDS_0X28_REQ_BASE_LEN) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
}
UDSCommCtrlArgs_t args = {
@@ -706,82 +503,82 @@ static uint8_t _0x28_CommunicationControl(UDSServer_t *self) {
.commType = communicationType,
};
- uint8_t err = self->fn(self, UDS_SRV_EVT_CommCtrl, &args);
+ uint8_t err = EmitEvent(srv, UDS_SRV_EVT_CommCtrl, &args);
if (kPositiveResponse != err) {
- return NegativeResponse(self, err);
+ return NegativeResponse(r, err);
}
- self->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_COMMUNICATION_CONTROL);
- self->send_buf[1] = controlType;
- self->send_size = UDS_0X28_RESP_LEN;
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_COMMUNICATION_CONTROL);
+ r->send_buf[1] = controlType;
+ r->send_len = UDS_0X28_RESP_LEN;
return kPositiveResponse;
}
-static uint8_t _0x2E_WriteDataByIdentifier(UDSServer_t *self) {
+static uint8_t _0x2E_WriteDataByIdentifier(UDSServer_t *srv, UDSReq_t *r) {
uint16_t dataLen = 0;
uint16_t dataId = 0;
uint8_t err = kPositiveResponse;
/* UDS-1 2013 Figure 21 Key 1 */
- if (self->recv_size < UDS_0X2E_REQ_MIN_LEN) {
- return NegativeResponse(self, kIncorrectMessageLengthOrInvalidFormat);
+ if (r->recv_len < UDS_0X2E_REQ_MIN_LEN) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
}
- dataId = (self->recv_buf[1] << 8) + self->recv_buf[2];
- dataLen = self->recv_size - UDS_0X2E_REQ_BASE_LEN;
+ dataId = (r->recv_buf[1] << 8) + r->recv_buf[2];
+ dataLen = r->recv_len - UDS_0X2E_REQ_BASE_LEN;
UDSWDBIArgs_t args = {
.dataId = dataId,
- .data = &self->recv_buf[UDS_0X2E_REQ_BASE_LEN],
+ .data = &r->recv_buf[UDS_0X2E_REQ_BASE_LEN],
.len = dataLen,
};
- err = self->fn(self, UDS_SRV_EVT_WriteDataByIdent, &args);
+ err = EmitEvent(srv, UDS_SRV_EVT_WriteDataByIdent, &args);
if (kPositiveResponse != err) {
- return NegativeResponse(self, err);
+ return NegativeResponse(r, err);
}
- self->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_WRITE_DATA_BY_IDENTIFIER);
- self->send_buf[1] = dataId >> 8;
- self->send_buf[2] = dataId;
- self->send_size = UDS_0X2E_RESP_LEN;
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_WRITE_DATA_BY_IDENTIFIER);
+ r->send_buf[1] = dataId >> 8;
+ r->send_buf[2] = dataId;
+ r->send_len = UDS_0X2E_RESP_LEN;
return kPositiveResponse;
}
-static uint8_t _0x31_RoutineControl(UDSServer_t *self) {
+static uint8_t _0x31_RoutineControl(UDSServer_t *srv, UDSReq_t *r) {
uint8_t err = kPositiveResponse;
- if (self->recv_size < UDS_0X31_REQ_MIN_LEN) {
- return NegativeResponse(self, kIncorrectMessageLengthOrInvalidFormat);
+ if (r->recv_len < UDS_0X31_REQ_MIN_LEN) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
}
- uint8_t routineControlType = self->recv_buf[1] & 0x7F;
- uint16_t routineIdentifier = (self->recv_buf[2] << 8) + self->recv_buf[3];
+ uint8_t routineControlType = r->recv_buf[1] & 0x7F;
+ uint16_t routineIdentifier = (r->recv_buf[2] << 8) + r->recv_buf[3];
UDSRoutineCtrlArgs_t args = {
.ctrlType = routineControlType,
.id = routineIdentifier,
- .optionRecord = &self->recv_buf[UDS_0X31_REQ_MIN_LEN],
- .len = self->recv_size - UDS_0X31_REQ_MIN_LEN,
+ .optionRecord = &r->recv_buf[UDS_0X31_REQ_MIN_LEN],
+ .len = r->recv_len - UDS_0X31_REQ_MIN_LEN,
.copyStatusRecord = safe_copy,
};
- self->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_ROUTINE_CONTROL);
- self->send_buf[1] = routineControlType;
- self->send_buf[2] = routineIdentifier >> 8;
- self->send_buf[3] = routineIdentifier;
- self->send_size = UDS_0X31_RESP_MIN_LEN;
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_ROUTINE_CONTROL);
+ r->send_buf[1] = routineControlType;
+ r->send_buf[2] = routineIdentifier >> 8;
+ r->send_buf[3] = routineIdentifier;
+ r->send_len = UDS_0X31_RESP_MIN_LEN;
switch (routineControlType) {
case kStartRoutine:
case kStopRoutine:
case kRequestRoutineResults:
- err = self->fn(self, UDS_SRV_EVT_RoutineCtrl, &args);
+ err = EmitEvent(srv, UDS_SRV_EVT_RoutineCtrl, &args);
if (kPositiveResponse != err) {
- return NegativeResponse(self, err);
+ return NegativeResponse(r, err);
}
break;
default:
- return NegativeResponse(self, kRequestOutOfRange);
+ return NegativeResponse(r, kRequestOutOfRange);
}
return kPositiveResponse;
}
@@ -794,46 +591,46 @@ static void ResetTransfer(UDSServer_t *srv) {
srv->xferIsActive = false;
}
-static uint8_t _0x34_RequestDownload(UDSServer_t *self) {
+static uint8_t _0x34_RequestDownload(UDSServer_t *srv, UDSReq_t *r) {
uint8_t err;
void *memoryAddress = 0;
size_t memorySize = 0;
- if (self->xferIsActive) {
- return NegativeResponse(self, kConditionsNotCorrect);
+ if (srv->xferIsActive) {
+ return NegativeResponse(r, kConditionsNotCorrect);
}
- if (self->recv_size < UDS_0X34_REQ_BASE_LEN) {
- return NegativeResponse(self, kIncorrectMessageLengthOrInvalidFormat);
+ if (r->recv_len < UDS_0X34_REQ_BASE_LEN) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
}
- err = decodeAddressAndLength(self, &self->recv_buf[2], &memoryAddress, &memorySize);
+ err = decodeAddressAndLength(r, &r->recv_buf[2], &memoryAddress, &memorySize);
if (kPositiveResponse != err) {
- return NegativeResponse(self, err);
+ return NegativeResponse(r, err);
}
UDSRequestDownloadArgs_t args = {
.addr = memoryAddress,
.size = memorySize,
- .dataFormatIdentifier = self->recv_buf[1],
+ .dataFormatIdentifier = r->recv_buf[1],
.maxNumberOfBlockLength = UDS_SERVER_DEFAULT_XFER_DATA_MAX_BLOCKLENGTH,
};
- err = self->fn(self, UDS_SRV_EVT_RequestDownload, &args);
+ err = EmitEvent(srv, UDS_SRV_EVT_RequestDownload, &args);
if (args.maxNumberOfBlockLength < 3) {
UDS_DBG_PRINT("ERROR: maxNumberOfBlockLength too short");
- return NegativeResponse(self, kGeneralProgrammingFailure);
+ return NegativeResponse(r, kGeneralProgrammingFailure);
}
if (kPositiveResponse != err) {
- return NegativeResponse(self, err);
+ return NegativeResponse(r, err);
}
- ResetTransfer(self);
- self->xferIsActive = true;
- self->xferTotalBytes = memorySize;
- self->xferBlockLength = args.maxNumberOfBlockLength;
+ ResetTransfer(srv);
+ srv->xferIsActive = true;
+ srv->xferTotalBytes = memorySize;
+ srv->xferBlockLength = args.maxNumberOfBlockLength;
// ISO-14229-1:2013 Table 401:
uint8_t lengthFormatIdentifier = sizeof(args.maxNumberOfBlockLength) << 4;
@@ -849,194 +646,195 @@ static uint8_t _0x34_RequestDownload(UDSServer_t *self) {
args.maxNumberOfBlockLength = UDS_TP_MTU;
}
- self->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_REQUEST_DOWNLOAD);
- self->send_buf[1] = lengthFormatIdentifier;
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_REQUEST_DOWNLOAD);
+ r->send_buf[1] = lengthFormatIdentifier;
for (uint8_t idx = 0; idx < sizeof(args.maxNumberOfBlockLength); idx++) {
uint8_t shiftBytes = sizeof(args.maxNumberOfBlockLength) - 1 - idx;
uint8_t byte = args.maxNumberOfBlockLength >> (shiftBytes * 8);
- self->send_buf[UDS_0X34_RESP_BASE_LEN + idx] = byte;
+ r->send_buf[UDS_0X34_RESP_BASE_LEN + idx] = byte;
}
- self->send_size = UDS_0X34_RESP_BASE_LEN + sizeof(args.maxNumberOfBlockLength);
+ r->send_len = UDS_0X34_RESP_BASE_LEN + sizeof(args.maxNumberOfBlockLength);
return kPositiveResponse;
}
-static uint8_t _0x35_RequestUpload(UDSServer_t *self) {
+static uint8_t _0x35_RequestUpload(UDSServer_t *srv, UDSReq_t *r) {
uint8_t err;
void *memoryAddress = 0;
size_t memorySize = 0;
- if (self->xferIsActive) {
- return NegativeResponse(self, kConditionsNotCorrect);
+ if (srv->xferIsActive) {
+ return NegativeResponse(r, kConditionsNotCorrect);
}
- if (self->recv_size < UDS_0X35_REQ_BASE_LEN) {
- return NegativeResponse(self, kIncorrectMessageLengthOrInvalidFormat);
+ if (r->recv_len < UDS_0X35_REQ_BASE_LEN) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
}
- err = decodeAddressAndLength(self, &self->recv_buf[2], &memoryAddress, &memorySize);
+ err = decodeAddressAndLength(r, &r->recv_buf[2], &memoryAddress, &memorySize);
if (kPositiveResponse != err) {
- return NegativeResponse(self, err);
+ return NegativeResponse(r, err);
}
UDSRequestUploadArgs_t args = {
.addr = memoryAddress,
.size = memorySize,
- .dataFormatIdentifier = self->recv_buf[1],
+ .dataFormatIdentifier = r->recv_buf[1],
.maxNumberOfBlockLength = UDS_SERVER_DEFAULT_XFER_DATA_MAX_BLOCKLENGTH,
};
- err = self->fn(self, UDS_SRV_EVT_RequestUpload, &args);
+ err = EmitEvent(srv, UDS_SRV_EVT_RequestUpload, &args);
if (args.maxNumberOfBlockLength < 3) {
UDS_DBG_PRINT("ERROR: maxNumberOfBlockLength too short");
- return NegativeResponse(self, kGeneralProgrammingFailure);
+ return NegativeResponse(r, kGeneralProgrammingFailure);
}
if (kPositiveResponse != err) {
- return NegativeResponse(self, err);
+ return NegativeResponse(r, err);
}
- ResetTransfer(self);
- self->xferIsActive = true;
- self->xferTotalBytes = memorySize;
- self->xferBlockLength = args.maxNumberOfBlockLength;
+ ResetTransfer(srv);
+ srv->xferIsActive = true;
+ srv->xferTotalBytes = memorySize;
+ srv->xferBlockLength = args.maxNumberOfBlockLength;
uint8_t lengthFormatIdentifier = sizeof(args.maxNumberOfBlockLength) << 4;
- self->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_REQUEST_UPLOAD);
- self->send_buf[1] = lengthFormatIdentifier;
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_REQUEST_UPLOAD);
+ r->send_buf[1] = lengthFormatIdentifier;
for (uint8_t idx = 0; idx < sizeof(args.maxNumberOfBlockLength); idx++) {
uint8_t shiftBytes = sizeof(args.maxNumberOfBlockLength) - 1 - idx;
uint8_t byte = args.maxNumberOfBlockLength >> (shiftBytes * 8);
- self->send_buf[UDS_0X35_RESP_BASE_LEN + idx] = byte;
+ r->send_buf[UDS_0X35_RESP_BASE_LEN + idx] = byte;
}
- self->send_size = UDS_0X35_RESP_BASE_LEN + sizeof(args.maxNumberOfBlockLength);
+ r->send_len = UDS_0X35_RESP_BASE_LEN + sizeof(args.maxNumberOfBlockLength);
return kPositiveResponse;
}
-static uint8_t _0x36_TransferData(UDSServer_t *self) {
+static uint8_t _0x36_TransferData(UDSServer_t *srv, UDSReq_t *r) {
uint8_t err = kPositiveResponse;
- uint16_t request_data_len = self->recv_size - UDS_0X36_REQ_BASE_LEN;
+ uint16_t request_data_len = r->recv_len - UDS_0X36_REQ_BASE_LEN;
uint8_t blockSequenceCounter = 0;
- if (!self->xferIsActive) {
- return NegativeResponse(self, kUploadDownloadNotAccepted);
+ if (!srv->xferIsActive) {
+ return NegativeResponse(r, kUploadDownloadNotAccepted);
}
- if (self->recv_size < UDS_0X36_REQ_BASE_LEN) {
+ if (r->recv_len < UDS_0X36_REQ_BASE_LEN) {
err = kIncorrectMessageLengthOrInvalidFormat;
goto fail;
}
- blockSequenceCounter = self->recv_buf[1];
+ blockSequenceCounter = r->recv_buf[1];
- if (!self->RCRRP) {
- if (blockSequenceCounter != self->xferBlockSequenceCounter) {
+ if (!srv->RCRRP) {
+ if (blockSequenceCounter != srv->xferBlockSequenceCounter) {
err = kRequestSequenceError;
goto fail;
} else {
- self->xferBlockSequenceCounter++;
+ srv->xferBlockSequenceCounter++;
}
}
- if (self->xferByteCounter + request_data_len > self->xferTotalBytes) {
+ if (srv->xferByteCounter + request_data_len > srv->xferTotalBytes) {
err = kTransferDataSuspended;
goto fail;
}
{
UDSTransferDataArgs_t args = {
- .data = &self->recv_buf[UDS_0X36_REQ_BASE_LEN],
- .len = self->recv_size - UDS_0X36_REQ_BASE_LEN,
- .maxRespLen = self->xferBlockLength - UDS_0X36_RESP_BASE_LEN,
+ .data = &r->recv_buf[UDS_0X36_REQ_BASE_LEN],
+ .len = r->recv_len - UDS_0X36_REQ_BASE_LEN,
+ .maxRespLen = srv->xferBlockLength - UDS_0X36_RESP_BASE_LEN,
.copyResponse = safe_copy,
};
- self->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_TRANSFER_DATA);
- self->send_buf[1] = blockSequenceCounter;
- self->send_size = UDS_0X36_RESP_BASE_LEN;
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_TRANSFER_DATA);
+ r->send_buf[1] = blockSequenceCounter;
+ r->send_len = UDS_0X36_RESP_BASE_LEN;
- err = self->fn(self, UDS_SRV_EVT_TransferData, &args);
+ err = EmitEvent(srv, UDS_SRV_EVT_TransferData, &args);
switch (err) {
case kPositiveResponse:
- self->xferByteCounter += request_data_len;
+ srv->xferByteCounter += request_data_len;
return kPositiveResponse;
case kRequestCorrectlyReceived_ResponsePending:
- return NegativeResponse(self, kRequestCorrectlyReceived_ResponsePending);
+ return NegativeResponse(r, kRequestCorrectlyReceived_ResponsePending);
default:
goto fail;
}
}
fail:
- ResetTransfer(self);
- return NegativeResponse(self, err);
+ ResetTransfer(srv);
+ return NegativeResponse(r, err);
}
-static uint8_t _0x37_RequestTransferExit(UDSServer_t *self) {
+static uint8_t _0x37_RequestTransferExit(UDSServer_t *srv, UDSReq_t *r) {
uint8_t err = kPositiveResponse;
- if (!self->xferIsActive) {
- return NegativeResponse(self, kUploadDownloadNotAccepted);
+ if (!srv->xferIsActive) {
+ return NegativeResponse(r, kUploadDownloadNotAccepted);
}
- self->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_REQUEST_TRANSFER_EXIT);
- self->send_size = UDS_0X37_RESP_BASE_LEN;
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_REQUEST_TRANSFER_EXIT);
+ r->send_len = UDS_0X37_RESP_BASE_LEN;
UDSRequestTransferExitArgs_t args = {
- .data = &self->recv_buf[UDS_0X37_REQ_BASE_LEN],
- .len = self->recv_size - UDS_0X37_REQ_BASE_LEN,
+ .data = &r->recv_buf[UDS_0X37_REQ_BASE_LEN],
+ .len = r->recv_len - UDS_0X37_REQ_BASE_LEN,
.copyResponse = safe_copy,
};
- err = self->fn(self, UDS_SRV_EVT_RequestTransferExit, &args);
+ err = EmitEvent(srv, UDS_SRV_EVT_RequestTransferExit, &args);
switch (err) {
case kPositiveResponse:
- ResetTransfer(self);
+ ResetTransfer(srv);
return kPositiveResponse;
case kRequestCorrectlyReceived_ResponsePending:
- return NegativeResponse(self, kRequestCorrectlyReceived_ResponsePending);
+ return NegativeResponse(r, kRequestCorrectlyReceived_ResponsePending);
default:
- ResetTransfer(self);
- return NegativeResponse(self, err);
+ ResetTransfer(srv);
+ return NegativeResponse(r, err);
}
}
-static uint8_t _0x3E_TesterPresent(UDSServer_t *self) {
- if ((self->recv_size < UDS_0X3E_REQ_MIN_LEN) ||
- (self->recv_size > UDS_0X3E_REQ_MAX_LEN)) {
- return NegativeResponse(self, kIncorrectMessageLengthOrInvalidFormat);
+static uint8_t _0x3E_TesterPresent(UDSServer_t *srv, UDSReq_t *r) {
+ if ((r->recv_len < UDS_0X3E_REQ_MIN_LEN) ||
+ (r->recv_len > UDS_0X3E_REQ_MAX_LEN)) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
}
- uint8_t zeroSubFunction = self->recv_buf[1];
+ uint8_t zeroSubFunction = r->recv_buf[1];
switch (zeroSubFunction) {
case 0x00:
case 0x80:
- self->s3_session_timeout_timer = UDSMillis() + self->s3_ms;
- self->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_TESTER_PRESENT);
- self->send_buf[1] = 0x00;
- self->send_size = UDS_0X3E_RESP_LEN;
+ srv->s3_session_timeout_timer = UDSMillis() + srv->s3_ms;
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_TESTER_PRESENT);
+ r->send_buf[1] = 0x00;
+ r->send_len = UDS_0X3E_RESP_LEN;
return kPositiveResponse;
default:
- return NegativeResponse(self, kSubFunctionNotSupported);
+ return NegativeResponse(r, kSubFunctionNotSupported);
}
}
-static uint8_t _0x85_ControlDTCSetting(UDSServer_t *self) {
- (void)self;
- if (self->recv_size < UDS_0X85_REQ_BASE_LEN) {
- return NegativeResponse(self, kIncorrectMessageLengthOrInvalidFormat);
+static uint8_t _0x85_ControlDTCSetting(UDSServer_t *srv, UDSReq_t *r) {
+ if (r->recv_len < UDS_0X85_REQ_BASE_LEN) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
}
- uint8_t dtcSettingType = self->recv_buf[1] & 0x3F;
+ uint8_t dtcSettingType = r->recv_buf[1] & 0x3F;
- self->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_CONTROL_DTC_SETTING);
- self->send_buf[1] = dtcSettingType;
- self->send_size = UDS_0X85_RESP_LEN;
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_CONTROL_DTC_SETTING);
+ r->send_buf[1] = dtcSettingType;
+ r->send_len = UDS_0X85_RESP_LEN;
return kPositiveResponse;
}
+typedef uint8_t (*UDSService)(UDSServer_t *srv, UDSReq_t *r);
+
/**
* @brief Get the internal service handler matching the given SID.
* @param sid
@@ -1104,20 +902,20 @@ static UDSService getServiceForSID(uint8_t sid) {
* @brief Call the service if it exists, modifying the response if the spec calls for it.
* @note see UDS-1 2013 7.5.5 Pseudo code example of server response behavior
*
- * @param self
+ * @param srv
* @param addressingScheme
*/
-static uint8_t evaluateServiceResponse(UDSServer_t *self, const uint8_t addressingScheme) {
+static uint8_t evaluateServiceResponse(UDSServer_t *srv, UDSReq_t *r) {
uint8_t response = kPositiveResponse;
bool suppressResponse = false;
- uint8_t sid = self->recv_buf[0];
+ uint8_t sid = r->recv_buf[0];
UDSService service = getServiceForSID(sid);
- if (NULL == service || NULL == self->fn) {
- return NegativeResponse(self, kServiceNotSupported);
+ if (NULL == service || NULL == srv->fn) {
+ return NegativeResponse(r, kServiceNotSupported);
}
assert(service);
- assert(self->fn); // service handler functions will call self->fn. it must be valid
+ assert(srv->fn); // service handler functions will call srv->fn. it must be valid
switch (sid) {
/* CASE Service_with_sub-function */
@@ -1129,9 +927,9 @@ static uint8_t evaluateServiceResponse(UDSServer_t *self, const uint8_t addressi
case kSID_ROUTINE_CONTROL:
case kSID_TESTER_PRESENT:
case kSID_CONTROL_DTC_SETTING: {
- response = service(self);
+ response = service(srv, r);
- bool suppressPosRspMsgIndicationBit = self->recv_buf[1] & 0x80;
+ bool suppressPosRspMsgIndicationBit = r->recv_buf[1] & 0x80;
/* test if positive response is required and if responseCode is positive 0x00 */
if ((suppressPosRspMsgIndicationBit) && (response == kPositiveResponse) &&
@@ -1154,7 +952,7 @@ static uint8_t evaluateServiceResponse(UDSServer_t *self, const uint8_t addressi
case kSID_REQUEST_UPLOAD:
case kSID_TRANSFER_DATA:
case kSID_REQUEST_TRANSFER_EXIT: {
- response = service(self);
+ response = service(srv, r);
break;
}
@@ -1177,7 +975,7 @@ static uint8_t evaluateServiceResponse(UDSServer_t *self, const uint8_t addressi
}
}
- if ((kTpAddrTypeFunctional == addressingScheme) &&
+ if ((UDS_A_TA_TYPE_FUNCTIONAL == r->info.A_TA_Type) &&
((kServiceNotSupported == response) || (kSubFunctionNotSupported == response) ||
(kServiceNotSupportedInActiveSession == response) ||
(kSubFunctionNotSupportedInActiveSession == response) ||
@@ -1186,10 +984,10 @@ static uint8_t evaluateServiceResponse(UDSServer_t *self, const uint8_t addressi
// TODO: *not yet a NRC 0x78 response sent*
true)) {
suppressResponse = true; /* Suppress negative response message */
- NoResponse(self);
+ NoResponse(r);
} else {
if (suppressResponse) { /* Suppress positive response message */
- NoResponse(self);
+ NoResponse(r);
} else { /* send negative or positive response */
;
}
@@ -1197,38 +995,6 @@ static uint8_t evaluateServiceResponse(UDSServer_t *self, const uint8_t addressi
return response;
}
-/**
- * @brief Process the data on this link
- *
- * @param self
- * @param link transport handle
- * @param addressingScheme
- */
-static void ProcessLink(UDSServer_t *self, const UDSTpAddr_t ta_type) {
-
- uint8_t response = evaluateServiceResponse(self, ta_type);
-
- if (kRequestCorrectlyReceived_ResponsePending == response) {
- self->RCRRP = true;
- self->notReadyToReceive = true;
- } else {
- self->RCRRP = false;
- }
-
- if (self->send_size) {
- UDSSDU_t msg = {
- .A_Mtype = UDS_A_MTYPE_DIAG,
- .A_SA = self->source_addr,
- .A_TA = self->target_addr,
- .A_TA_Type = UDS_A_TA_TYPE_PHYSICAL, // server responses are always physical
- .A_Length = self->send_size,
- .A_Data = self->send_buf,
- };
- int result = self->tp->send(self->tp, &msg);
- assert(result == self->send_size); // how should it be handled if send fails?
- }
-}
-
// ========================================================================
// Public Functions
// ========================================================================
@@ -1236,202 +1002,147 @@ static void ProcessLink(UDSServer_t *self, const UDSTpAddr_t ta_type) {
/**
* @brief \~chinese 初始化服务器 \~english Initialize the server
*
- * @param self
+ * @param srv
* @param cfg
* @return int
*/
-UDSErr_t UDSServerInit(UDSServer_t *self, const UDSServerConfig_t *cfg) {
- assert(self);
- assert(cfg);
- assert(cfg->source_addr != cfg->target_addr);
- assert(cfg->target_addr != cfg->source_addr_func);
- assert(cfg->source_addr_func != cfg->source_addr);
- memset(self, 0, sizeof(UDSServer_t));
- self->recv_buf_size = sizeof(self->recv_buf);
- self->send_buf_size = sizeof(self->send_buf);
- self->p2_ms = UDS_SERVER_DEFAULT_P2_MS;
- self->p2_star_ms = UDS_SERVER_DEFAULT_P2_STAR_MS;
- self->s3_ms = UDS_SERVER_DEFAULT_S3_MS;
- self->fn = cfg->fn;
- self->sessionType = kDefaultSession;
- self->source_addr = cfg->source_addr;
- self->target_addr = cfg->target_addr;
- self->source_addr_func = cfg->source_addr_func;
-
- // Initialize p2_timer to an already past time, otherwise the server's
- // response to incoming messages will be delayed.
- self->p2_timer = UDSMillis() - self->p2_ms;
-
- // Set the session timeout for s3 milliseconds from now.
- self->s3_session_timeout_timer = UDSMillis() + self->s3_ms;
-
-#if UDS_TP == UDS_TP_CUSTOM
- assert(cfg->tp);
- assert(cfg->tp->recv);
- assert(cfg->tp->send);
- assert(cfg->tp->poll);
- self->tp = cfg->tp;
-#elif UDS_TP == UDS_TP_ISOTP_C
- assert(cfg->target_addr != cfg->source_addr_func && cfg->source_addr_func != cfg->source_addr);
- UDSTpIsoTpC_t *tp = &self->tp_impl;
- isotp_init_link(&tp->phys_link, cfg->target_addr, self->send_buf, self->send_buf_size,
- self->recv_buf, self->recv_buf_size);
- isotp_init_link(&tp->func_link, cfg->target_addr, tp->func_send_buf, sizeof(tp->func_send_buf),
- tp->func_recv_buf, sizeof(tp->func_recv_buf));
- self->tp = (UDSTpHandle_t *)tp;
- self->tp->poll = tp_poll;
- self->tp->send = tp_send;
- self->tp->recv = tp_recv;
-#elif UDS_TP == UDS_TP_ISOTP_SOCKET
- self->tp = (UDSTpHandle_t *)&self->tp_impl;
- if (LinuxSockTpOpen(self->tp, cfg->if_name, cfg->source_addr, cfg->target_addr,
- cfg->source_addr_func, cfg->target_addr)) {
- return UDS_ERR;
- }
-#endif
+UDSErr_t UDSServerInit(UDSServer_t *srv) {
+ assert(srv);
+ memset(srv, 0, sizeof(UDSServer_t));
+ srv->p2_ms = UDS_SERVER_DEFAULT_P2_MS;
+ srv->p2_star_ms = UDS_SERVER_DEFAULT_P2_STAR_MS;
+ srv->s3_ms = UDS_SERVER_DEFAULT_S3_MS;
+ srv->sessionType = kDefaultSession;
+ srv->p2_timer = UDSMillis() + srv->p2_ms;
+ srv->s3_session_timeout_timer = UDSMillis() + srv->s3_ms;
return UDS_OK;
}
-void UDSServerDeInit(UDSServer_t *self) {
-#if UDS_TP == UDS_TP_ISOTP_SOCKET
- LinuxSockTpClose(self->tp);
-#endif
-}
-
-void UDSServerPoll(UDSServer_t *self) {
+void UDSServerPoll(UDSServer_t *srv) {
// UDS-1-2013 Figure 38: Session Timeout (S3)
- if (kDefaultSession != self->sessionType &&
- UDSTimeAfter(UDSMillis(), self->s3_session_timeout_timer)) {
- if (self->fn) {
- self->fn(self, UDS_SRV_EVT_SessionTimeout, NULL);
- }
+ if (kDefaultSession != srv->sessionType &&
+ UDSTimeAfter(UDSMillis(), srv->s3_session_timeout_timer)) {
+ EmitEvent(srv, UDS_SRV_EVT_SessionTimeout, NULL);
}
- if (self->ecuResetScheduled && UDSTimeAfter(UDSMillis(), self->ecuResetTimer)) {
- if (self->fn) {
- self->fn(self, UDS_SRV_EVT_DoScheduledReset, &self->ecuResetScheduled);
- }
+ if (srv->ecuResetScheduled && UDSTimeAfter(UDSMillis(), srv->ecuResetTimer)) {
+ EmitEvent(srv, UDS_SRV_EVT_DoScheduledReset, &srv->ecuResetScheduled);
}
- UDSTpStatus_t tp_status = self->tp->poll(self->tp);
- if (tp_status & UDS_TP_SEND_IN_PROGRESS) {
- return;
- }
+ UDSTpStatus_t tpStatus = UDSTpPoll(srv->tp);
- // If the user service handler responded RCRRP and the send link is now idle,
- // the response has been sent and the long-running service can now be called.
- if (self->RCRRP) {
- ProcessLink(self, kTpAddrTypePhysical);
- self->notReadyToReceive = self->RCRRP;
- return;
- }
+ UDSReq_t *r = &srv->r;
- if (self->notReadyToReceive) {
- return;
- }
+ if (srv->requestInProgress) {
+ if (srv->RCRRP) {
+ // responds only if
+ // 1. changed (no longer RCRRP), or
+ // 2. p2_timer has elapsed
+ uint8_t response = evaluateServiceResponse(srv, r);
+ if (kRequestCorrectlyReceived_ResponsePending == response) {
+ // it's the second time the service has responded with RCRRP
+ srv->notReadyToReceive = true;
+ } else {
+ // No longer RCRRP'ing
+ srv->RCRRP = false;
+ srv->notReadyToReceive = false;
- // new data may be processed only after p2 has elapsed
- int size = 0;
- if (UDSTimeAfter(UDSMillis(), self->p2_timer)) {
- UDSSDU_t msg = {
- .A_DataBufSize = self->recv_buf_size,
- .A_Data = self->recv_buf,
- };
- size = self->tp->recv(self->tp, &msg);
- if (size > 0) {
- if (msg.A_TA == self->source_addr) {
- msg.A_TA_Type = UDS_A_TA_TYPE_PHYSICAL;
- } else if (msg.A_TA == self->source_addr_func) {
- msg.A_TA_Type = UDS_A_TA_TYPE_FUNCTIONAL;
+ // Not a consecutive 0x78 response, use p2 instead of p2_star * 0.3
+ srv->p2_timer = UDSMillis() + srv->p2_ms;
+ }
+ }
+
+ if (UDSTimeAfter(UDSMillis(), srv->p2_timer)) {
+ printf("len: %ld\n", r->send_len);
+ ssize_t ret = UDSTpSend(srv->tp, r->send_buf, r->send_len, NULL);
+ // TODO test injection of transport errors:
+ if (ret < 0) {
+ UDSErr_t err = UDS_ERR_TPORT;
+ EmitEvent(srv, UDS_SRV_EVT_Err, &err);
+ UDS_DBG_PRINT("UDSTpSend failed with %d\n", ret);
+ }
+
+ if (srv->RCRRP) {
+ // ISO14229-2:2013 Table 4 footnote b
+ // min time between consecutive 0x78 responses is 0.3 * p2*
+ srv->p2_timer = UDSMillis() + 0.3f * srv->p2_star_ms;
} else {
- UDS_DBG_PRINT("received message from unknown source address %x\n", msg.A_TA);
- return;
+ srv->p2_timer = UDSMillis() + srv->p2_ms;
+ UDSTpAckRecv(srv->tp);
+ srv->requestInProgress = false;
+ }
+ }
+
+ } else {
+ if (srv->notReadyToReceive) {
+ return; // cannot respond to request right now
+ }
+ r->recv_len = UDSTpPeek(srv->tp, &r->recv_buf, &r->info);
+ r->send_buf_size = UDSTpGetSendBuf(srv->tp, &r->send_buf);
+ if (r->send_buf == NULL || r->recv_buf == NULL) {
+ UDSErr_t err = UDS_ERR_TPORT;
+ EmitEvent(srv, UDS_SRV_EVT_Err, &err);
+ UDS_DBG_PRINT("bad tport\n");
+ return;
+ }
+ if (r->recv_len > 0) {
+ uint8_t response = evaluateServiceResponse(srv, r);
+ srv->requestInProgress = true;
+ if (kRequestCorrectlyReceived_ResponsePending == response) {
+ srv->RCRRP = true;
}
- self->recv_size = size;
- ProcessLink(self, msg.A_TA_Type);
- self->p2_timer = UDSMillis() + self->p2_ms;
- } else if (size == 0) {
- ;
- } else {
- UDS_DBG_PRINT("tp_recv failed with err %d on tp %d\n", size, msg.A_TA_Type);
}
}
}
+
// ========================================================================
// Client
// ========================================================================
static void clearRequestContext(UDSClient_t *client) {
assert(client);
- assert(client->tp);
- memset(client->recv_buf, 0, client->recv_buf_size);
- memset(client->send_buf, 0, client->send_buf_size);
client->recv_size = 0;
client->send_size = 0;
client->state = kRequestStateIdle;
client->err = UDS_OK;
}
-UDSErr_t UDSClientInit(UDSClient_t *client, const UDSClientConfig_t *cfg) {
+UDSErr_t UDSClientInit(UDSClient_t *client) {
assert(client);
- assert(cfg);
- assert(cfg->target_addr != cfg->source_addr);
- assert(cfg->source_addr != cfg->target_addr_func);
- assert(cfg->target_addr_func != cfg->target_addr);
memset(client, 0, sizeof(*client));
client->p2_ms = UDS_CLIENT_DEFAULT_P2_MS;
client->p2_star_ms = UDS_CLIENT_DEFAULT_P2_STAR_MS;
- client->recv_buf_size = sizeof(client->recv_buf);
- client->send_buf_size = sizeof(client->send_buf);
- client->source_addr = cfg->source_addr;
- client->target_addr = cfg->target_addr;
- client->target_addr_func = cfg->target_addr_func;
if (client->p2_star_ms < client->p2_ms) {
fprintf(stderr, "p2_star_ms must be >= p2_ms\n");
client->p2_star_ms = client->p2_ms;
}
-#if UDS_TP == UDS_TP_CUSTOM
- assert(cfg->tp);
- assert(cfg->tp->recv);
- assert(cfg->tp->send);
- assert(cfg->tp->poll);
- client->tp = cfg->tp;
-#elif UDS_TP == UDS_TP_ISOTP_C
- assert(cfg->source_addr != cfg->target_addr_func && cfg->target_addr_func != cfg->target_addr);
- UDSTpIsoTpC_t *tp = (UDSTpIsoTpC_t *)&client->tp_impl;
- isotp_init_link(&tp->phys_link, cfg->target_addr, client->send_buf, client->send_buf_size,
- client->recv_buf, client->recv_buf_size);
- isotp_init_link(&tp->func_link, cfg->target_addr_func, tp->func_send_buf,
- sizeof(tp->func_send_buf), tp->func_recv_buf, sizeof(tp->func_recv_buf));
- client->tp = (UDSTpHandle_t *)tp;
- client->tp->poll = tp_poll;
- client->tp->send = tp_send;
- client->tp->recv = tp_recv;
-#elif UDS_TP == UDS_TP_ISOTP_SOCKET
- client->tp = (UDSTpHandle_t *)&client->tp_impl;
- if (LinuxSockTpOpen(client->tp, cfg->if_name, cfg->source_addr, cfg->target_addr,
- cfg->source_addr, cfg->target_addr_func)) {
- return UDS_ERR;
- }
- assert(client->tp);
-#endif
-
clearRequestContext(client);
return UDS_OK;
}
-void UDSClientDeInit(UDSClient_t *client) {
-#if UDS_TP == UDS_TP_ISOTP_SOCKET
- LinuxSockTpClose(client->tp);
-#endif
+static const char *ClientStateName(enum UDSClientRequestState state) {
+ switch (state) {
+ case kRequestStateIdle:
+ return "Idle";
+ case kRequestStateSending:
+ return "Sending";
+ case kRequestStateAwaitSendComplete:
+ return "AwaitSendComplete";
+ case kRequestStateAwaitResponse:
+ return "AwaitResponse";
+ case kRequestStateProcessResponse:
+ return "ProcessResponse";
+ default:
+ return "Unknown";
+ }
}
static void changeState(UDSClient_t *client, enum UDSClientRequestState state) {
- // printf("client state: %d -> %d\n", client->state, state);
+ printf("client state: %s (%d) -> %s (%d)\n", ClientStateName(client->state), client->state, ClientStateName(state), state);
client->state = state;
}
@@ -1490,6 +1201,7 @@ static inline void _ClientHandleResponse(UDSClient_t *client) {
client->p2_timer = UDSMillis() + client->p2_star_ms;
memset(client->recv_buf, 0, client->recv_buf_size);
client->recv_size = 0;
+ UDSTpAckRecv(client->tp);
changeState(client, kRequestStateAwaitResponse);
return;
} else {
@@ -1503,11 +1215,13 @@ static inline void _ClientHandleResponse(UDSClient_t *client) {
UDS_DBG_PRINT("Error: SID %x response too short\n",
kSID_DIAGNOSTIC_SESSION_CONTROL);
client->err = UDS_ERR_RESP_TOO_SHORT;
+ UDSTpAckRecv(client->tp);
changeState(client, kRequestStateIdle);
return;
}
if (client->_options_copy & UDS_IGNORE_SRV_TIMINGS) {
+ UDSTpAckRecv(client->tp);
changeState(client, kRequestStateIdle);
return;
}
@@ -1523,6 +1237,7 @@ static inline void _ClientHandleResponse(UDSClient_t *client) {
break;
}
}
+ UDSTpAckRecv(client->tp);
changeState(client, kRequestStateIdle);
}
@@ -1540,18 +1255,12 @@ static void PollLowLevel(UDSClient_t *client) {
}
case kRequestStateSending: {
UDSTpAddr_t ta_type =
- client->_options_copy & UDS_FUNCTIONAL ? kTpAddrTypeFunctional : kTpAddrTypePhysical;
- ssize_t ret = 0;
- UDSSDU_t msg = {
+ client->_options_copy & UDS_FUNCTIONAL ? UDS_A_TA_TYPE_FUNCTIONAL : UDS_A_TA_TYPE_PHYSICAL;
+ UDSSDU_t info = {
.A_Mtype = UDS_A_MTYPE_DIAG,
- .A_SA = client->source_addr,
- .A_TA = ta_type == kTpAddrTypePhysical ? client->target_addr : client->target_addr_func,
.A_TA_Type = ta_type,
- .A_Length = client->send_size,
- .A_Data = client->send_buf,
};
- ret = client->tp->send(client->tp, &msg);
-
+ ssize_t ret = UDSTpSend(client->tp, client->send_buf, client->send_size, &info);
if (ret < 0) {
client->err = UDS_ERR_TPORT;
UDS_DBG_PRINT("tport err: %ld\n", ret);
@@ -1584,26 +1293,25 @@ static void PollLowLevel(UDSClient_t *client) {
break;
}
case kRequestStateAwaitResponse: {
- UDSTpAddr_t ta_type = kTpAddrTypePhysical;
- UDSSDU_t msg = {
- .A_DataBufSize = client->recv_buf_size,
- .A_Data = client->recv_buf,
- };
- ssize_t ret = client->tp->recv(client->tp, &msg);
+ UDSSDU_t info = {0};
+ ssize_t len = UDSTpPeek(client->tp, &client->recv_buf, &info);
+ printf("peeked %ld bytes\n", len);
- if (kTpAddrTypeFunctional == ta_type) {
+ if (UDS_A_TA_TYPE_FUNCTIONAL == info.A_TA_Type) {
+ UDSTpAckRecv(client->tp);
break;
}
- if (ret < 0) {
+ if (len < 0) {
client->err = UDS_ERR_TPORT;
changeState(client, kRequestStateIdle);
- } else if (0 == ret) {
+ } else if (0 == len) {
if (UDSTimeAfter(UDSMillis(), client->p2_timer)) {
client->err = UDS_ERR_TIMEOUT;
changeState(client, kRequestStateIdle);
}
} else {
- client->recv_size = ret;
+ printf("received %ld bytes\n", len);
+ client->recv_size = len;
changeState(client, kRequestStateProcessResponse);
}
break;
@@ -1613,6 +1321,7 @@ static void PollLowLevel(UDSClient_t *client) {
if (UDS_OK == client->err) {
_ClientHandleResponse(client);
} else {
+ UDSTpAckRecv(client->tp);
changeState(client, kRequestStateIdle);
}
break;
@@ -1636,14 +1345,28 @@ static UDSErr_t _SendRequest(UDSClient_t *client) {
return UDS_OK;
}
-#define PRE_REQUEST_CHECK() \
- if (kRequestStateIdle != client->state) { \
- return UDS_ERR_BUSY; \
- } \
+
+static UDSErr_t PreRequestCheck(UDSClient_t *client) {
+ if (kRequestStateIdle != client->state) {
+ return UDS_ERR_BUSY;
+ }
clearRequestContext(client);
+ if (client->tp == NULL) {
+ return UDS_ERR_TPORT;
+ }
+ ssize_t ret = UDSTpGetSendBuf(client->tp, &client->send_buf);
+ if (ret < 0) {
+ return UDS_ERR_TPORT;
+ }
+ client->send_buf_size = ret;
+ return UDS_OK;
+}
UDSErr_t UDSSendBytes(UDSClient_t *client, const uint8_t *data, uint16_t size) {
- PRE_REQUEST_CHECK();
+ UDSErr_t err = PreRequestCheck(client);
+if (err) {
+ return err;
+}
if (size > client->send_buf_size) {
return UDS_ERR_BUFSIZ;
}
@@ -1653,7 +1376,10 @@ UDSErr_t UDSSendBytes(UDSClient_t *client, const uint8_t *data, uint16_t size) {
}
UDSErr_t UDSSendECUReset(UDSClient_t *client, UDSECUReset_t type) {
- PRE_REQUEST_CHECK();
+ UDSErr_t err = PreRequestCheck(client);
+if (err) {
+ return err;
+}
client->send_buf[0] = kSID_ECU_RESET;
client->send_buf[1] = type;
client->send_size = 2;
@@ -1661,7 +1387,10 @@ UDSErr_t UDSSendECUReset(UDSClient_t *client, UDSECUReset_t type) {
}
UDSErr_t UDSSendDiagSessCtrl(UDSClient_t *client, enum UDSDiagnosticSessionType mode) {
- PRE_REQUEST_CHECK();
+ UDSErr_t err = PreRequestCheck(client);
+if (err) {
+ return err;
+}
client->send_buf[0] = kSID_DIAGNOSTIC_SESSION_CONTROL;
client->send_buf[1] = mode;
client->send_size = 2;
@@ -1670,7 +1399,10 @@ UDSErr_t UDSSendDiagSessCtrl(UDSClient_t *client, enum UDSDiagnosticSessionType
UDSErr_t UDSSendCommCtrl(UDSClient_t *client, enum UDSCommunicationControlType ctrl,
enum UDSCommunicationType comm) {
- PRE_REQUEST_CHECK();
+ UDSErr_t err = PreRequestCheck(client);
+if (err) {
+ return err;
+}
client->send_buf[0] = kSID_COMMUNICATION_CONTROL;
client->send_buf[1] = ctrl;
client->send_buf[2] = comm;
@@ -1679,7 +1411,10 @@ UDSErr_t UDSSendCommCtrl(UDSClient_t *client, enum UDSCommunicationControlType c
}
UDSErr_t UDSSendTesterPresent(UDSClient_t *client) {
- PRE_REQUEST_CHECK();
+ UDSErr_t err = PreRequestCheck(client);
+if (err) {
+ return err;
+}
client->send_buf[0] = kSID_TESTER_PRESENT;
client->send_buf[1] = 0;
client->send_size = 2;
@@ -1688,7 +1423,10 @@ UDSErr_t UDSSendTesterPresent(UDSClient_t *client) {
UDSErr_t UDSSendRDBI(UDSClient_t *client, const uint16_t *didList,
const uint16_t numDataIdentifiers) {
- PRE_REQUEST_CHECK();
+ UDSErr_t err = PreRequestCheck(client);
+if (err) {
+ return err;
+}
assert(didList);
assert(numDataIdentifiers);
client->send_buf[0] = kSID_READ_DATA_BY_IDENTIFIER;
@@ -1706,7 +1444,10 @@ UDSErr_t UDSSendRDBI(UDSClient_t *client, const uint16_t *didList,
UDSErr_t UDSSendWDBI(UDSClient_t *client, uint16_t dataIdentifier, const uint8_t *data,
uint16_t size) {
- PRE_REQUEST_CHECK();
+ UDSErr_t err = PreRequestCheck(client);
+if (err) {
+ return err;
+}
assert(data);
assert(size);
client->send_buf[0] = kSID_WRITE_DATA_BY_IDENTIFIER;
@@ -1733,7 +1474,10 @@ UDSErr_t UDSSendWDBI(UDSClient_t *client, uint16_t dataIdentifier, const uint8_t
*/
UDSErr_t UDSSendRoutineCtrl(UDSClient_t *client, enum RoutineControlType type,
uint16_t routineIdentifier, const uint8_t *data, uint16_t size) {
- PRE_REQUEST_CHECK();
+ UDSErr_t err = PreRequestCheck(client);
+if (err) {
+ return err;
+}
client->send_buf[0] = kSID_ROUTINE_CONTROL;
client->send_buf[1] = type;
client->send_buf[2] = routineIdentifier >> 8;
@@ -1765,7 +1509,10 @@ UDSErr_t UDSSendRoutineCtrl(UDSClient_t *client, enum RoutineControlType type,
UDSErr_t UDSSendRequestDownload(UDSClient_t *client, uint8_t dataFormatIdentifier,
uint8_t addressAndLengthFormatIdentifier, size_t memoryAddress,
size_t memorySize) {
- PRE_REQUEST_CHECK();
+ UDSErr_t err = PreRequestCheck(client);
+if (err) {
+ return err;
+}
uint8_t numMemorySizeBytes = (addressAndLengthFormatIdentifier & 0xF0) >> 4;
uint8_t numMemoryAddressBytes = addressAndLengthFormatIdentifier & 0x0F;
@@ -1803,7 +1550,10 @@ UDSErr_t UDSSendRequestDownload(UDSClient_t *client, uint8_t dataFormatIdentifie
UDSErr_t UDSSendRequestUpload(UDSClient_t *client, uint8_t dataFormatIdentifier,
uint8_t addressAndLengthFormatIdentifier, size_t memoryAddress,
size_t memorySize) {
- PRE_REQUEST_CHECK();
+ UDSErr_t err = PreRequestCheck(client);
+if (err) {
+ return err;
+}
uint8_t numMemorySizeBytes = (addressAndLengthFormatIdentifier & 0xF0) >> 4;
uint8_t numMemoryAddressBytes = addressAndLengthFormatIdentifier & 0x0F;
@@ -1839,7 +1589,10 @@ UDSErr_t UDSSendRequestUpload(UDSClient_t *client, uint8_t dataFormatIdentifier,
*/
UDSErr_t UDSSendTransferData(UDSClient_t *client, uint8_t blockSequenceCounter,
const uint16_t blockLength, const uint8_t *data, uint16_t size) {
- PRE_REQUEST_CHECK();
+ UDSErr_t err = PreRequestCheck(client);
+if (err) {
+ return err;
+}
assert(blockLength > 2); // blockLength must include SID and sequenceCounter
assert(size + 2 <= blockLength); // data must fit inside blockLength - 2
client->send_buf[0] = kSID_TRANSFER_DATA;
@@ -1852,7 +1605,10 @@ UDSErr_t UDSSendTransferData(UDSClient_t *client, uint8_t blockSequenceCounter,
UDSErr_t UDSSendTransferDataStream(UDSClient_t *client, uint8_t blockSequenceCounter,
const uint16_t blockLength, FILE *fd) {
- PRE_REQUEST_CHECK();
+ UDSErr_t err = PreRequestCheck(client);
+if (err) {
+ return err;
+}
assert(blockLength > 2); // blockLength must include SID and sequenceCounter
client->send_buf[0] = kSID_TRANSFER_DATA;
client->send_buf[1] = blockSequenceCounter;
@@ -1871,7 +1627,10 @@ UDSErr_t UDSSendTransferDataStream(UDSClient_t *client, uint8_t blockSequenceCou
* @addtogroup requestTransferExit_0x37
*/
UDSErr_t UDSSendRequestTransferExit(UDSClient_t *client) {
- PRE_REQUEST_CHECK();
+ UDSErr_t err = PreRequestCheck(client);
+if (err) {
+ return err;
+}
client->send_buf[0] = kSID_REQUEST_TRANSFER_EXIT;
client->send_size = 1;
return _SendRequest(client);
@@ -1889,7 +1648,10 @@ UDSErr_t UDSSendRequestTransferExit(UDSClient_t *client) {
*/
UDSErr_t UDSCtrlDTCSetting(UDSClient_t *client, uint8_t dtcSettingType, uint8_t *data,
uint16_t size) {
- PRE_REQUEST_CHECK();
+ UDSErr_t err = PreRequestCheck(client);
+if (err) {
+ return err;
+}
if (0x00 == dtcSettingType || 0x7F == dtcSettingType ||
(0x03 <= dtcSettingType && dtcSettingType <= 0x3F)) {
assert(0); // reserved vals
@@ -1921,7 +1683,10 @@ UDSErr_t UDSCtrlDTCSetting(UDSClient_t *client, uint8_t dtcSettingType, uint8_t
* @addtogroup securityAccess_0x27
*/
UDSErr_t UDSSendSecurityAccess(UDSClient_t *client, uint8_t level, uint8_t *data, uint16_t size) {
- PRE_REQUEST_CHECK();
+ UDSErr_t err = PreRequestCheck(client);
+if (err) {
+ return err;
+}
if (UDSSecurityAccessLevelIsReserved(level)) {
return UDS_ERR_INVALID_ARG;
}
@@ -2161,30 +1926,30 @@ UDSSeqState_t UDSClientAwaitIdle(UDSClient_t *client) {
}
}
-UDSErr_t UDSUnpackRDBIResponse(const UDSClient_t *client, uint16_t did, uint8_t *data,
- uint16_t size, uint16_t *offset) {
- assert(client);
+UDSErr_t UDSUnpackRDBIResponse(const uint8_t *buf, size_t buf_len, uint16_t did, uint8_t *data,
+ uint16_t data_size, uint16_t *offset) {
+ assert(buf);
assert(data);
assert(offset);
if (0 == *offset) {
*offset = UDS_0X22_RESP_BASE_LEN;
}
- if (*offset + sizeof(did) > client->recv_size) {
+ if (*offset + sizeof(did) > buf_len) {
return UDS_ERR_RESP_TOO_SHORT;
}
- uint16_t theirDID = (client->recv_buf[*offset] << 8) + client->recv_buf[*offset + 1];
+ uint16_t theirDID = (buf[*offset] << 8) + buf[*offset + 1];
if (theirDID != did) {
return UDS_ERR_DID_MISMATCH;
}
- if (*offset + sizeof(uint16_t) + size > client->recv_size) {
+ if (*offset + sizeof(uint16_t) + data_size > buf_len) {
return UDS_ERR_RESP_TOO_SHORT;
}
- memmove(data, &client->recv_buf[*offset + sizeof(uint16_t)], size);
+ memmove(data, buf + *offset + sizeof(uint16_t), data_size);
- *offset += sizeof(uint16_t) + size;
+ *offset += sizeof(uint16_t) + data_size;
return UDS_OK;
}
diff --git a/iso14229.h b/iso14229.h
index 339a468..0e51af8 100644
--- a/iso14229.h
+++ b/iso14229.h
@@ -226,12 +226,7 @@ enum DTCSettingType {
kDTCSettingOFF = 0x02,
};
-enum UDSTpAddr {
- kTpAddrTypePhysical = 0, // 1:1
- kTpAddrTypeFunctional, // 1:many
-};
-typedef uint8_t UDSTpAddr_t;
enum UDSTpStatusFlags {
UDS_TP_IDLE = 0x00000000,
@@ -253,6 +248,8 @@ typedef enum {
UDS_A_TA_TYPE_FUNCTIONAL, // multicast
} UDS_A_TA_Type_t;
+typedef uint8_t UDSTpAddr_t;
+
/**
* @brief Service data unit (SDU)
* @details data interface between the application layer and the transport layer
@@ -264,94 +261,69 @@ typedef struct {
uint16_t A_TA; // application target address
UDS_A_TA_Type_t A_TA_Type; // application target address type (physical or functional)
uint16_t A_AE; // application layer remote address
- uint32_t A_Length; // data length
- uint32_t A_DataBufSize; // buffer size of A_Data
- uint8_t *A_Data; // pointer to data owned by the application layer
} UDSSDU_t;
+#define UDS_TP_NOOP_ADDR (0xFFFFFFFF)
+
/**
- * @brief Transport Handle is the interface between the UDS application layer and the transport
- * layer.
+ * @brief Interface to OSI layer 4 (transport layer)
+ * @note implementers should embed this struct at offset zero in their own transport layer handle
*/
typedef struct UDSTpHandle {
/**
- * @brief 接收
+ * @brief Get the transport layer's send buffer
* @param hdl: pointer to transport handle
- * @param buf: if data is available, it will be copied here
- * @param count: the implementation should not copy more than count bytes into buf
- * @param ta_type: the addressing type of the data received or error encountered is written to
- * this location. If no data is received, nothing is written
- * @return 接收了多少个字节。
- * < 0 故障
- * == 0 没有数据
- * > 0 接收了、返回值是大小
+ * @param buf: double pointer which will be pointed to the send buffer
+ * @return size of transport layer's send buffer on success, -1 on error
*/
- ssize_t (*recv)(struct UDSTpHandle *hdl, UDSSDU_t *msg);
+ ssize_t (*get_send_buf)(struct UDSTpHandle *hdl, uint8_t **p_buf);
+
/**
- * @brief 发送
+ * @brief Send the data in the buffer buf
* @param hdl: pointer to transport handle
- * @param buf: pointer to data to be sent
- * @param count: number of bytes to be sent
- * @param ta_type: the addressing type to use
- * @return 发送了多少个字节。
- * < 0 故障
- * >= 0 发送成功了
+ * @param buf: a pointer to the data to send (this may be the buffer returned by @ref get_send_buf)
+ * @param info: pointer to SDU info (may be NULL)
*/
- ssize_t (*send)(struct UDSTpHandle *hdl, UDSSDU_t *msg);
+ ssize_t (*send)(struct UDSTpHandle *hdl, uint8_t *buf, size_t len, UDSSDU_t *info);
+
/**
- * @brief 轮询
+ * @brief Poll the transport layer.
+ * @param hdl: pointer to transport handle
+ * @note the transport layer user is responsible for calling this function periodically
+ * @note threaded implementations like linux isotp sockets don't need to do anything here.
+ * @return UDS_TP_IDLE if idle, otherwise UDS_TP_SEND_IN_PROGRESS or UDS_TP_RECV_COMPLETE
*/
UDSTpStatus_t (*poll)(struct UDSTpHandle *hdl);
-} UDSTpHandle_t;
-#if UDS_TP == UDS_TP_ISOTP_C
-typedef struct {
- UDSTpHandle_t hdl;
- IsoTpLink phys_link;
- IsoTpLink func_link;
- uint8_t func_recv_buf[8];
- uint8_t func_send_buf[8];
-} UDSTpISOTpC_t;
-#elif UDS_TP == UDS_TP_ISOTP_SOCKET
-typedef struct {
- UDSTpHandle_t hdl;
- int phys_fd;
- int func_fd;
-} UDSTpLinuxIsoTp_t;
-#endif
-
-ssize_t UDSTpSend(UDSTpHandle_t *tp, const uint8_t *buf, size_t len);
-ssize_t UDSTpRecv(UDSTpHandle_t *tp, uint8_t *buf, size_t size);
-
-/**
- * @brief ISO14229-2 session layer implementation
- */
-typedef struct {
- UDSTpHandle_t *tp;
- uint8_t recv_buf[UDS_BUFSIZE];
- uint8_t send_buf[UDS_BUFSIZE];
- uint16_t recv_size;
- uint16_t send_size;
- uint16_t recv_buf_size;
- uint16_t send_buf_size;
- uint32_t target_addr;
- uint32_t target_addr_func;
- uint32_t source_addr;
- uint32_t source_addr_func;
-} UDSSess_t;
+ /**
+ * @brief Peek at the received data
+ * @param hdl: pointer to transport handle
+ * @param buf: set to the received data
+ * @param info: filled with SDU info by the callee if not NULL
+ * @return size of received data on success, -1 on error
+ * @note The transport will be unable to receive further data until @ref ack_recv is called
+ * @note The information returned by peek will not change until @ref ack_recv is called
+ */
+ ssize_t (*peek)(struct UDSTpHandle *hdl, uint8_t **buf, UDSSDU_t *info);
-typedef struct {
- UDSTpHandle_t *tp;
- uint32_t source_addr;
- uint32_t source_addr_func;
- uint32_t target_addr;
- uint32_t target_addr_func;
-} UDSSessConfig_t;
+ /**
+ * @brief Acknowledge that the received data has been processed and may be discarded
+ * @param hdl: pointer to transport handle
+ * @note: after ack_recv() is called and before new messages are received, peek must return 0.
+ */
+ void (*ack_recv)(struct UDSTpHandle *hdl);
+} UDSTpHandle_t;
-void UDSSessInit(UDSSess_t *sess, const UDSSessConfig_t *cfg);
-UDSErr_t UDSSessSend(UDSSess_t *sess, const uint8_t *data, size_t len);
-UDSErr_t UDSSessSendFunctional(UDSSess_t *sess, const uint8_t *msg, size_t size);
-void UDSSessPoll(UDSSess_t *sess);
+//
+// Convenience functions to wrap UDSTpHandle_t
+//
+ssize_t UDSTpGetSendBuf(UDSTpHandle_t *hdl, uint8_t **buf);
+ssize_t UDSTpSend(UDSTpHandle_t *hdl, const uint8_t *buf, ssize_t len, UDSSDU_t *info);
+UDSTpStatus_t UDSTpPoll(UDSTpHandle_t *hdl);
+ssize_t UDSTpRecv(UDSTpHandle_t *hdl, UDSSDU_t *info, uint8_t **buf);
+const uint8_t *UDSTpGetRecvBuf(UDSTpHandle_t *hdl, size_t *len);
+size_t UDSTpGetRecvLen(UDSTpHandle_t *hdl);
+void UDSTpAckRecv(UDSTpHandle_t *hdl);
// ========================================================================
// Utility Functions
@@ -363,10 +335,10 @@ static inline bool UDSTimeAfter(uint32_t a, uint32_t b) {
}
/**
- * @brief \~chinese 用户定义获取时间(毫秒)回调函数 \~english user-provided function that
- * returns the current time in milliseconds \~
+ * @brief Get time in milliseconds
+ * @return current time in milliseconds
*/
-uint32_t UDSMillis();
+uint32_t UDSMillis(void);
// ========================================================================
// Client
@@ -392,20 +364,6 @@ enum UDSClientRequestState {
typedef uint8_t UDSClientRequestState_t;
-typedef struct {
- uint32_t source_addr;
- uint32_t target_addr;
- uint32_t target_addr_func;
-#if UDS_TP == UDS_TP_CUSTOM
- UDSTpHandle_t *tp;
-#elif UDS_TP == UDS_TP_ISOTP_C
-#elif UDS_TP == UDS_TP_ISOTP_SOCKET
- const char *if_name;
-#else
-#error "transport undefined"
-#endif
-} UDSClientConfig_t;
-
enum UDSClientOptions {
UDS_SUPPRESS_POS_RESP = 0x1, // 服务器不应该发送肯定响应
UDS_FUNCTIONAL = 0x2, // 发功能请求
@@ -424,15 +382,12 @@ typedef struct UDSClient {
// 内状态
uint32_t p2_timer;
- uint8_t recv_buf[UDS_BUFSIZE];
- uint8_t send_buf[UDS_BUFSIZE];
+ uint8_t *recv_buf;
+ uint8_t *send_buf;
uint16_t recv_buf_size;
uint16_t send_buf_size;
uint16_t recv_size;
uint16_t send_size;
- uint32_t source_addr;
- uint32_t target_addr;
- uint32_t target_addr_func;
UDSErr_t err;
UDSClientRequestState_t state;
@@ -446,13 +401,6 @@ typedef struct UDSClient {
size_t cbIdx; // index of currently active callback function
void *cbData; // a pointer to data available to callbacks
-#if UDS_TP == UDS_TP_CUSTOM
-#elif UDS_TP == UDS_TP_ISOTP_C
- UDSTpISOTpC_t tp_impl;
-#elif UDS_TP == UDS_TP_ISOTP_SOCKET
- UDSTpLinuxIsoTp_t tp_impl;
-#endif
-
} UDSClient_t;
struct SecurityAccessResponse {
@@ -472,9 +420,7 @@ struct RoutineControlResponse {
uint16_t routineStatusRecordLength;
};
-UDSErr_t UDSClientInit(UDSClient_t *client, const UDSClientConfig_t *cfg);
-
-void UDSClientDeInit(UDSClient_t *client);
+UDSErr_t UDSClientInit(UDSClient_t *client);
#define UDS_CLIENT_IDLE (0)
#define UDS_CLIENT_RUNNING (1)
@@ -518,7 +464,7 @@ UDSErr_t UDSSendRequestTransferExit(UDSClient_t *client);
UDSErr_t UDSCtrlDTCSetting(UDSClient_t *client, uint8_t dtcSettingType,
uint8_t *dtcSettingControlOptionRecord, uint16_t len);
-UDSErr_t UDSUnpackRDBIResponse(const UDSClient_t *client, uint16_t did, uint8_t *data,
+UDSErr_t UDSUnpackRDBIResponse(const uint8_t *buf, size_t buf_len, uint16_t did, uint8_t *data,
uint16_t size, uint16_t *offset);
UDSErr_t UDSUnpackSecurityAccessResponse(const UDSClient_t *client,
struct SecurityAccessResponse *resp);
@@ -592,6 +538,7 @@ enum UDSServerEvent {
UDS_SRV_EVT_RequestTransferExit, // UDSRequestTransferExitArgs_t *
UDS_SRV_EVT_SessionTimeout, // NULL
UDS_SRV_EVT_DoScheduledReset, // enum UDSEcuResetType *
+ UDS_SRV_EVT_Err, // UDSErr_t *
UDS_EVT_IDLE,
UDS_EVT_RESP_RECV,
};
@@ -599,18 +546,21 @@ enum UDSServerEvent {
typedef int UDSServerEvent_t;
typedef UDSServerEvent_t UDSEvent_t;
+/**
+ * @brief Server request context
+ */
+typedef struct {
+ uint8_t *recv_buf;
+ uint8_t *send_buf;
+ size_t recv_len;
+ size_t send_len;
+ size_t send_buf_size;
+ UDSSDU_t info;
+} UDSReq_t;
+
typedef struct UDSServer {
UDSTpHandle_t *tp;
uint8_t (*fn)(struct UDSServer *srv, UDSServerEvent_t event, const void *arg);
- uint8_t recv_buf[UDS_BUFSIZE];
- uint8_t send_buf[UDS_BUFSIZE];
- uint16_t recv_size;
- uint16_t send_size;
- uint16_t recv_buf_size;
- uint16_t send_buf_size;
- uint32_t target_addr;
- uint32_t source_addr;
- uint32_t source_addr_func;
/**
* @brief \~chinese 服务器时间参数(毫秒) \~ Server time constants (milliseconds) \~
@@ -625,8 +575,7 @@ typedef struct UDSServer {
uint32_t ecuResetTimer; // for delaying resetting until a response
// has been sent to the client
uint32_t p2_timer; // for rate limiting server responses
- uint32_t s3_session_timeout_timer; // for knowing when the diagnostic
- // session has timed out
+ uint32_t s3_session_timeout_timer; // indicates that diagnostic session has timed out
/**
* @brief UDS-1-2013: Table 407 - 0x36 TransferData Supported negative
@@ -641,16 +590,11 @@ typedef struct UDSServer {
size_t xferByteCounter; // total number of bytes transferred
size_t xferBlockLength; // block length (convenience for the TransferData API)
- /**
- * @brief public subset of server state for user handlers
- */
- uint8_t sessionType;
- uint8_t securityLevel; // Current SecurityAccess (0x27) level
- // this variable set to true when a user handler returns 0x78
- // requestCorrectlyReceivedResponsePending. After a response has been sent on the transport
- // layer, this variable is set to false and the user handler will be called again. It is the
- // responsibility of the user handler to track the call count.
- bool RCRRP;
+ uint8_t sessionType; // diagnostic session type (0x10)
+ uint8_t securityLevel; // SecurityAccess (0x27) level
+
+ bool RCRRP; // set to true when user fn returns 0x78 and false otherwise
+ bool requestInProgress; // set to true when a request has been processed but the response has not yet been sent
// UDS-1 2013 defines the following conditions under which the server does not
// process incoming requests:
@@ -660,27 +604,13 @@ typedef struct UDSServer {
// when this variable is set to true, incoming ISO-TP data will not be processed.
bool notReadyToReceive;
-#if UDS_TP == UDS_TP_CUSTOM
-#elif UDS_TP == UDS_TP_ISOTP_C
- UDSTpISOTpC_t tp_impl;
-#elif UDS_TP == UDS_TP_ISOTP_SOCKET
- UDSTpLinuxIsoTp_t tp_impl;
-#endif
+ UDSReq_t r;
} UDSServer_t;
+// TODO: Remove
typedef struct {
- uint32_t target_addr;
- uint32_t source_addr;
- uint32_t source_addr_func;
uint8_t (*fn)(UDSServer_t *srv, UDSServerEvent_t event, const void *arg);
-#if UDS_TP == UDS_TP_CUSTOM
UDSTpHandle_t *tp;
-#elif UDS_TP == UDS_TP_ISOTP_C
-#elif UDS_TP == UDS_TP_ISOTP_SOCKET
- const char *if_name;
-#else
-#error "transport undefined"
-#endif
} UDSServerConfig_t;
typedef struct {
@@ -698,8 +628,7 @@ typedef struct {
typedef struct {
const uint16_t dataId; /*! RDBI Data Identifier */
- uint8_t (*copy)(UDSServer_t *srv, const void *src,
- uint16_t count); /*! function for copying data */
+ uint8_t (*copy)(UDSServer_t *srv , const void *src, uint16_t count); /*! function for copying data */
} UDSRDBIArgs_t;
typedef struct {
@@ -775,9 +704,8 @@ typedef struct {
uint16_t len); /*! function for copying response data (optional) */
} UDSRequestTransferExitArgs_t;
-UDSErr_t UDSServerInit(UDSServer_t *self, const UDSServerConfig_t *cfg);
-void UDSServerDeInit(UDSServer_t *self);
-void UDSServerPoll(UDSServer_t *self);
+UDSErr_t UDSServerInit(UDSServer_t *srv);
+void UDSServerPoll(UDSServer_t *srv);
#ifdef __cplusplus
}
diff --git a/run_clang_format.sh b/run_clang_format.sh
index 8e2e8cf..7643ebc 100755
--- a/run_clang_format.sh
+++ b/run_clang_format.sh
@@ -1,6 +1,6 @@
#! /bin/bash
-files=`find . -type f \( -name '*.c' -o -name '*.h' \) -not -path "./isotp-c/*"`
+files=`find . -type f \( -name '*.c' -o -name '*.h' \) -not -path "./tp/isotp-c/*"`
for file in $files ; do
if [ -z "$CHECK_FORMAT" ] ; then
diff --git a/test/BUILD b/test/BUILD
index 7b4a7cc..3b5b0aa 100644
--- a/test/BUILD
+++ b/test/BUILD
@@ -8,9 +8,9 @@ cc_library(
"//tp:srcs",
],
deps = [
- "//tp:mock",
- "//tp:isotp_sock",
- "//tp:isotp_c_socketcan",
+ # "//tp:mock",
+ # "//tp:isotp_sock",
+ # "//tp:isotp_c_socketcan",
],
defines = [
"UDS_TP=UDS_TP_CUSTOM",
@@ -33,7 +33,6 @@ cc_library(
)
for src in [
"test_client_0x11_ECU_reset.c",
- "test_client_0x22_RDBI_tx_buffer_too_small.c",
"test_client_0x22_RDBI_unpack_response.c",
"test_client_0x31_RCRRP.c",
"test_client_0x34_request_download.c",
@@ -51,6 +50,7 @@ cc_library(
"test_server_0x3E_suppress_positive_response.c",
"test_server_0x83_diagnostic_session_control.c",
"test_server_session_timeout.c",
+ "test_tp_mock.c",
]
]
@@ -65,7 +65,7 @@ cc_test(
defines = [
"UDS_TP=UDS_TP_CUSTOM",
"UDS_CUSTOM_MILLIS",
- "UDS_DBG_PRINT=printf",
+ # "UDS_DBG_PRINT=printf",
],
copts = [
"-g",
@@ -90,4 +90,30 @@ sh_test(
# Not exactly right. It's to prevent this test from being run under qemu
target_compatible_with = ["@platforms//cpu:x86_64"],
+)
+
+cc_library(
+ name = "ultra_strict",
+ srcs = [
+ "//:iso14229_srcs",
+ "//tp:srcs",
+ ],
+ copts = [
+ "-Werror",
+ "-Wall",
+ "-Wextra",
+ "-Wpedantic",
+ "-Wno-unused-parameter",
+ "-Wno-unused-function",
+ "-Wno-unused-variable",
+ "-Wno-unused-but-set-variable",
+ "-Wno-unused-label",
+ "-Wno-unused-value",
+ "-Wno-unused-result",
+ "-Wno-unused-const-variable",
+ "-Wno-unused-local-typedefs",
+ "-Wno-unused-macros",
+ "-Wno-gnu-zero-variadic-macro-arguments",
+ ],
+ target_compatible_with = ["//platforms/compiler:clang"],
)
\ No newline at end of file
diff --git a/test/README.md b/test/README.md
index 553e914..e07aecf 100644
--- a/test/README.md
+++ b/test/README.md
@@ -33,6 +33,12 @@ bazel test --config=arm //test:all
bazel test --config=ppc //test:all
bazel test --config=ppc64 //test:all
bazel test --config=ppc64le //test:all
+
+# build the fuzzer
+bazel build -s --verbose_failures --config=x86_64_clang //test:test_fuzz_server
+# run the fuzzer
+mkdir .libfuzzer_artifacts .libfuzzer_corpus
+bazel-bin/test/test_fuzz_server -jobs=8 -artifact_prefix=./.libfuzzer_artifacts/ .libfuzzer_corpus
```
diff --git a/test/env.c b/test/env.c
index b4b8869..7774cff 100644
--- a/test/env.c
+++ b/test/env.c
@@ -7,11 +7,14 @@
#include
#include "tp/mock.h"
#include "tp/isotp_sock.h"
-#include "tp/isotp_c_socketcan.h"
+// #include "tp/isotp_c_socketcan.h"
static UDSServer_t *registeredServer = NULL;
static UDSClient_t *registeredClient = NULL;
-static UDSSess_t *registeredSess = NULL;
+#define MAX_NUM_TP 8
+static UDSTpHandle_t *registeredTps[MAX_NUM_TP];
+static unsigned TPCount = 0;
+
static uint32_t TimeNowMillis = 0;
typedef struct {
@@ -45,7 +48,7 @@ void ENV_ServerInit(UDSServer_t *srv) {
UDSTpHandle_t *tp = NULL;
switch (cfg.tp_type) {
case OPTS_TP_TYPE_MOCK:
- tp = TPMockCreate("server");
+ tp = TPMockCreate("server", TPMOCK_DEFAULT_SERVER_ARGS);
break;
case OPTS_TP_TYPE_ISOTP_SOCK: {
UDSTpIsoTpSock_t *isotp = malloc(sizeof(UDSTpIsoTpSock_t));
@@ -57,12 +60,12 @@ void ENV_ServerInit(UDSServer_t *srv) {
break;
}
case OPTS_TP_TYPE_ISOTPC: {
- UDSTpISOTpC_t *isotp = malloc(sizeof(UDSTpISOTpC_t));
- strcpy(isotp->tag, "server");
- assert(UDS_OK == UDSTpISOTpCInitServer(isotp, srv, cfg.ifname,
- cfg.srv_src_addr, cfg.srv_target_addr,
- cfg.srv_src_addr_func));
- tp = (UDSTpHandle_t *)isotp;
+ // UDSTpISOTpC_t *isotp = malloc(sizeof(UDSTpISOTpC_t));
+ // strcpy(isotp->tag, "server");
+ // assert(UDS_OK == UDSTpISOTpCInitServer(isotp, srv, cfg.ifname,
+ // cfg.srv_src_addr, cfg.srv_target_addr,
+ // cfg.srv_src_addr_func));
+ // tp = (UDSTpHandle_t *)isotp;
break;
}
default:
@@ -70,13 +73,8 @@ void ENV_ServerInit(UDSServer_t *srv) {
exit(1);
}
- UDSServerInit(srv, &(UDSServerConfig_t){
- .fn = NULL,
- .tp = tp,
- .source_addr = 0x7E8,
- .target_addr = 0x7E0,
- .source_addr_func = 0x7DF,
- });
+ UDSServerInit(srv);
+ srv->tp = tp;
ENV_RegisterServer(srv);
}
@@ -84,7 +82,7 @@ void ENV_ClientInit(UDSClient_t *cli) {
UDSTpHandle_t *tp = NULL;
switch (cfg.tp_type) {
case OPTS_TP_TYPE_MOCK:
- tp = TPMockCreate("client");
+ tp = TPMockCreate("client", TPMOCK_DEFAULT_CLIENT_ARGS);
break;
case OPTS_TP_TYPE_ISOTP_SOCK: {
UDSTpIsoTpSock_t *isotp = malloc(sizeof(UDSTpIsoTpSock_t));
@@ -96,72 +94,29 @@ void ENV_ClientInit(UDSClient_t *cli) {
break;
}
case OPTS_TP_TYPE_ISOTPC: {
- UDSTpISOTpC_t *isotp = malloc(sizeof(UDSTpISOTpC_t));
- strcpy(isotp->tag, "client");
- assert(UDS_OK == UDSTpISOTpCInitClient(isotp, cli, cfg.ifname,
- cfg.cli_src_addr, cfg.cli_target_addr,
- cfg.cli_tgt_addr_func));
- tp = (UDSTpHandle_t *)isotp;
- break;
+ // UDSTpISOTpC_t *isotp = malloc(sizeof(UDSTpISOTpC_t));
+ // strcpy(isotp->tag, "client");
+ // assert(UDS_OK == UDSTpISOTpCInitClient(isotp, cli, cfg.ifname,
+ // cfg.cli_src_addr, cfg.cli_target_addr,
+ // cfg.cli_tgt_addr_func));
+ // tp = (UDSTpHandle_t *)isotp;
+ // break;
}
default:
printf("unknown TP type: %d\n", cfg.tp_type);
exit(1);
}
- UDSClientInit(cli, &(UDSClientConfig_t){
- .tp = tp,
- .source_addr = 0x7E0,
- .target_addr = 0x7E8,
- .target_addr_func = 0x7DF,
- });
+ UDSClientInit(cli);
+ cli->tp = tp;
ENV_RegisterClient(cli);
}
-void ENV_SessInit(UDSSess_t *sess, const char *name) {
- UDSTpHandle_t *tp = NULL;
- switch (cfg.tp_type) {
- case OPTS_TP_TYPE_MOCK:
- tp = TPMockCreate(name);
- break;
- case OPTS_TP_TYPE_ISOTP_SOCK: {
- UDSTpIsoTpSock_t *isotp = malloc(sizeof(UDSTpIsoTpSock_t));
- strncpy(isotp->tag, name, sizeof(isotp->tag));
- assert(UDS_OK == UDSTpIsoTpSockInitClient(isotp, cfg.ifname,
- cfg.cli_src_addr, cfg.cli_target_addr,
- cfg.cli_tgt_addr_func));
- tp = (UDSTpHandle_t *)isotp;
- break;
- }
- case OPTS_TP_TYPE_ISOTPC: {
- UDSTpISOTpC_t *isotp = malloc(sizeof(UDSTpISOTpC_t));
- strncpy(isotp->tag, name, sizeof(isotp->tag));
- assert(UDS_OK == UDSTpISOTpCInitSess(isotp, sess, cfg.ifname,
- cfg.cli_src_addr, cfg.cli_target_addr,
- cfg.cli_tgt_addr_func));
- tp = (UDSTpHandle_t *)isotp;
- break;
- }
- default:
- printf("unknown TP type: %d\n", cfg.tp_type);
- exit(1);
- }
-
- UDSSessInit(sess, &(UDSSessConfig_t){
- .tp = tp,
- .source_addr = 0x7E0,
- .target_addr = 0x7E8,
- .target_addr_func = 0x7DF,
- });
- ENV_RegisterSess(sess);
-}
void ENV_RegisterServer(UDSServer_t *server) { registeredServer = server; }
void ENV_RegisterClient(UDSClient_t *client) { registeredClient = client; }
-void ENV_RegisterSess(UDSSess_t *sess) { registeredSess = sess; }
-
uint32_t UDSMillis() { return TimeNowMillis; }
// actually sleep for milliseconds
@@ -182,8 +137,8 @@ void ENV_RunMillis(uint32_t millis) {
if (registeredClient) {
UDSClientPoll(registeredClient);
}
- if (registeredSess) {
- UDSSessPoll(registeredSess);
+ for (unsigned i = 0; i < TPCount; i++) {
+ UDSTpPoll(registeredTps[i]);
}
TimeNowMillis++;
@@ -210,6 +165,9 @@ void ENV_ParseOpts(int argc, char **argv) {
cfg.cli_tgt_addr_func = 0x7DF;
const char *tp = getenv("TP");
+ if (tp == NULL) {
+ tp = "mock";
+ }
if (0 == strcasecmp(tp, "mock")) {
cfg.tp_type = OPTS_TP_TYPE_MOCK;
} else if (0 == strcasecmp(tp, "isotp_sock")) {
@@ -220,4 +178,20 @@ void ENV_ParseOpts(int argc, char **argv) {
printf("unknown TP: %s\n", tp);
exit(1);
}
+}
+
+
+UDSTpHandle_t *ENV_GetMockTp(const char *name) {
+ UDSTpHandle_t *tp = NULL;
+ if (0 == strcasecmp(name, "server"))
+ tp = TPMockCreate(name, TPMOCK_DEFAULT_SERVER_ARGS);
+ else if (0 == strcasecmp(name, "client")) {
+ tp = TPMockCreate(name, TPMOCK_DEFAULT_CLIENT_ARGS);
+ }
+ else {
+ printf("unknown mock tp: %s\n", name);
+ return NULL;
+ }
+ registeredTps[TPCount++] = tp;
+ return tp;
}
\ No newline at end of file
diff --git a/test/env.h b/test/env.h
index 54b38ca..2c6ccd6 100644
--- a/test/env.h
+++ b/test/env.h
@@ -8,7 +8,6 @@
void ENV_ServerInit(UDSServer_t *srv);
void ENV_ClientInit(UDSClient_t *client);
-void ENV_SessInit(UDSSess_t *sess, const char *name);
#define ENV_SERVER_INIT(srv) \
ENV_ParseOpts(0, NULL); \
@@ -20,12 +19,17 @@ void ENV_SessInit(UDSSess_t *sess, const char *name);
TPMockLogToStdout();
#define ENV_SESS_INIT(sess) \
- ENV_SessInit(&sess, #sess); \
- TPMockLogToStdout();
+// ENV_SessInit(&sess, #sess); \
+// TPMockLogToStdout();
+
+/**
+ * @brief return a transport configured as client
+ * @return UDSTpHandle_t*
+ */
+UDSTpHandle_t *ENV_GetMockTp(const char *name);
void ENV_RegisterServer(UDSServer_t *server);
void ENV_RegisterClient(UDSClient_t *client);
-void ENV_RegisterSess(UDSSess_t *sess);
void ENV_RunMillis(uint32_t millis);
void ENV_ParseOpts(int argc, char **argv);
diff --git a/test/test.h b/test/test.h
index d2d79f0..eb84a8a 100644
--- a/test/test.h
+++ b/test/test.h
@@ -92,6 +92,7 @@
} \
}
+// Expect that a condition is true within a timeout
#define EXPECT_WITHIN_MS(cond, timeout_ms) \
{ \
uint32_t deadline = UDSMillis() + timeout_ms + 1; \
@@ -101,4 +102,35 @@
} \
}
+// Expect that a condition is true for a duration
+#define EXPECT_WHILE_MS(cond, duration) \
+ { \
+ uint32_t deadline = UDSMillis() + duration; \
+ while (UDSTimeAfter(deadline, UDSMillis())) { \
+ assert(cond); \
+ ENV_RunMillis(1); \
+ } \
+ }
+
+// Expect that a condition
+// - is false until 90% of a duration has passed,
+// - and true before 110% of the duration has passed
+#define EXPECT_IN_APPROX_MS(cond, duration) \
+ { \
+ const float tolerance = 0.1f; \
+ uint32_t pre_deadline = UDSMillis() + (int)(duration * (1.0f - tolerance)); \
+ uint32_t post_deadline = UDSMillis() + (int)(duration * (1.0f + tolerance)); \
+ while (UDSTimeAfter(pre_deadline, UDSMillis())) { \
+ assert(!(cond)); \
+ ENV_RunMillis(1); \
+ } \
+ while (!(cond)) { \
+ TEST_INT_LE(UDSMillis(), post_deadline); \
+ ENV_RunMillis(1); \
+ } \
+ }
+
+
+
+
#endif
diff --git a/test/test_client_0x11_ECU_reset.c b/test/test_client_0x11_ECU_reset.c
index f9a88ee..99890f3 100644
--- a/test/test_client_0x11_ECU_reset.c
+++ b/test/test_client_0x11_ECU_reset.c
@@ -2,7 +2,6 @@
int main() {
UDSClient_t client;
- UDSSess_t mock_srv;
const uint8_t GOOD[] = {0x51, 0x01};
const uint8_t BAD_SID[] = {0x50, 0x01};
@@ -35,7 +34,7 @@ int main() {
for (size_t i = 0; i < sizeof(p) / sizeof(p[0]); i++) {
ENV_CLIENT_INIT(client);
- ENV_SESS_INIT(mock_srv);
+ UDSTpHandle_t *mock_srv = ENV_GetMockTp("server");
printf("test %ld: %s\n", i, p[i].tag);
// when the client sends a ECU reset request with these options
@@ -43,7 +42,7 @@ int main() {
UDSSendECUReset(&client, kHardReset);
// and the server responds with this message
- EXPECT_OK(UDSSessSend(&mock_srv, p[i].resp, p[i].resp_len));
+ UDSTpSend(mock_srv, p[i].resp, p[i].resp_len, NULL);
// then the client should receive a response with this error code
ENV_RunMillis(50);
diff --git a/test/test_client_0x22_RDBI_tx_buffer_too_small.c b/test/test_client_0x22_RDBI_tx_buffer_too_small.c
deleted file mode 100644
index 517a05e..0000000
--- a/test/test_client_0x22_RDBI_tx_buffer_too_small.c
+++ /dev/null
@@ -1,19 +0,0 @@
-#include "test/test.h"
-
-int main() {
- UDSClient_t client;
- ENV_CLIENT_INIT(client);
-
- // attempting to send a request payload of 6 bytes
- uint16_t didList[] = {0x0001, 0x0002, 0x0003};
-
- // which is larger than the underlying buffer
- client.send_buf_size = 4;
-
- // should return an error
- TEST_INT_EQUAL(UDS_ERR_INVALID_ARG,
- UDSSendRDBI(&client, didList, sizeof(didList) / sizeof(didList[0])))
-
- // and no data should be sent
- TEST_INT_EQUAL(client.send_size, 0);
-}
\ No newline at end of file
diff --git a/test/test_client_0x22_RDBI_unpack_response.c b/test/test_client_0x22_RDBI_unpack_response.c
index 01b2a16..8591f4d 100644
--- a/test/test_client_0x22_RDBI_unpack_response.c
+++ b/test/test_client_0x22_RDBI_unpack_response.c
@@ -1,28 +1,23 @@
#include "test/test.h"
int main() {
- UDSClient_t client;
- ENV_CLIENT_INIT(client);
-
- uint8_t RESPONSE[] = {0x72, 0x12, 0x34, 0x00, 0x00, 0xAA, 0x00, 0x56, 0x78, 0xAA, 0xBB};
- memmove(client.recv_buf, RESPONSE, sizeof(RESPONSE));
- client.recv_size = sizeof(RESPONSE);
+ uint8_t RESP[] = {0x72, 0x12, 0x34, 0x00, 0x00, 0xAA, 0x00, 0x56, 0x78, 0xAA, 0xBB};
uint8_t buf[4];
uint16_t offset = 0;
int err = 0;
- err = UDSUnpackRDBIResponse(&client, 0x1234, buf, 4, &offset);
+ err = UDSUnpackRDBIResponse(RESP, sizeof(RESP), 0x1234, buf, 4, &offset);
TEST_INT_EQUAL(err, UDS_OK);
uint32_t d0 = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3];
TEST_INT_EQUAL(d0, 0x0000AA00);
- err = UDSUnpackRDBIResponse(&client, 0x1234, buf, 2, &offset);
+ err = UDSUnpackRDBIResponse(RESP, sizeof(RESP), 0x1234, buf, 2, &offset);
TEST_INT_EQUAL(err, UDS_ERR_DID_MISMATCH);
- err = UDSUnpackRDBIResponse(&client, 0x5678, buf, 20, &offset);
+ err = UDSUnpackRDBIResponse(RESP, sizeof(RESP), 0x5678, buf, 20, &offset);
TEST_INT_EQUAL(err, UDS_ERR_RESP_TOO_SHORT);
- err = UDSUnpackRDBIResponse(&client, 0x5678, buf, 2, &offset);
+ err = UDSUnpackRDBIResponse(RESP, sizeof(RESP), 0x5678, buf, 2, &offset);
TEST_INT_EQUAL(err, UDS_OK);
uint16_t d1 = (buf[0] << 8) + buf[1];
TEST_INT_EQUAL(d1, 0xAABB);
- err = UDSUnpackRDBIResponse(&client, 0x5678, buf, 1, &offset);
+ err = UDSUnpackRDBIResponse(RESP, sizeof(RESP), 0x5678, buf, 1, &offset);
TEST_INT_EQUAL(err, UDS_ERR_RESP_TOO_SHORT);
- TEST_INT_EQUAL(offset, sizeof(RESPONSE));
+ TEST_INT_EQUAL(offset, sizeof(RESP));
}
\ No newline at end of file
diff --git a/test/test_client_0x31_RCRRP.c b/test/test_client_0x31_RCRRP.c
index ff196df..533a264 100644
--- a/test/test_client_0x31_RCRRP.c
+++ b/test/test_client_0x31_RCRRP.c
@@ -2,7 +2,7 @@
int main() {
UDSClient_t client;
- UDSSess_t sess;
+ UDSTpHandle_t *mock_srv = ENV_GetMockTp("server");
ENV_SESS_INIT(sess)
{ // Case 1: RCRRP Timeout
@@ -12,7 +12,7 @@ int main() {
// that receives an RCRRP response
const uint8_t RCRRP[] = {0x7F, 0x31, 0x78}; // RequestCorrectly-ReceievedResponsePending
- UDSSessSend(&sess, RCRRP, sizeof(RCRRP));
+ UDSTpSend(mock_srv, RCRRP, sizeof(RCRRP), NULL);
// that remains unresolved at a time between p2 ms and p2 star ms
ENV_RunMillis(UDS_CLIENT_DEFAULT_P2_MS + 10);
@@ -32,7 +32,7 @@ int main() {
// that receives an RCRRP response
const uint8_t RCRRP[] = {0x7F, 0x31, 0x78}; // RequestCorrectly-ReceievedResponsePending
- UDSSessSend(&sess, RCRRP, sizeof(RCRRP));
+ UDSTpSend(mock_srv, RCRRP, sizeof(RCRRP), NULL);
// that remains unresolved at a time between p2 ms and p2 star ms
ENV_RunMillis(UDS_CLIENT_DEFAULT_P2_MS + 10);
@@ -42,7 +42,7 @@ int main() {
// When the client receives a positive response from the server
const uint8_t POSITIVE_RESPONSE[] = {0x71, 0x01, 0x12, 0x34};
- UDSSessSend(&sess, POSITIVE_RESPONSE, sizeof(POSITIVE_RESPONSE));
+ UDSTpSend(mock_srv, POSITIVE_RESPONSE, sizeof(POSITIVE_RESPONSE), NULL);
ENV_RunMillis(5);
diff --git a/test/test_client_p2.c b/test/test_client_p2.c
index bdba6de..d5b798b 100644
--- a/test/test_client_p2.c
+++ b/test/test_client_p2.c
@@ -1,9 +1,9 @@
+#include "iso14229.h"
#include "test/test.h"
int main() {
UDSClient_t client;
- UDSSess_t sess;
- ENV_SESS_INIT(sess);
+ UDSTpHandle_t *tp = ENV_GetMockTp("server");
{ // Case 1: P2 not exceeded
ENV_CLIENT_INIT(client);
@@ -13,7 +13,7 @@ int main() {
// which receives a positive response
const uint8_t POSITIVE_RESPONSE[] = {0x51, 0x01};
- UDSSessSend(&sess, POSITIVE_RESPONSE, sizeof(POSITIVE_RESPONSE));
+ UDSTpSend(tp, POSITIVE_RESPONSE, sizeof(POSITIVE_RESPONSE), NULL);
ENV_RunMillis(20);
// after p2 ms has elapsed, the client should have a timeout error
diff --git a/test/test_fuzz_server.c b/test/test_fuzz_server.c
index e363458..4f65298 100644
--- a/test/test_fuzz_server.c
+++ b/test/test_fuzz_server.c
@@ -1,9 +1,11 @@
+#include
#include
#include
#include
#include
#include
#include "iso14229.h"
+#include "tp/mock.h"
#ifdef __cplusplus
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *, size_t);
@@ -11,67 +13,73 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *, size_t);
int LLVMFuzzerTestOneInput(const uint8_t *, size_t);
#endif
-uint8_t retval = kPositiveResponse;
+typedef struct {
+ uint8_t srv_retval;
+ uint16_t client_sa;
+ uint16_t client_ta;
+ uint8_t client_func_req;
+ uint8_t msg[UDS_BUFSIZE];
+} StuffToFuzz_t;
-static uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) { return retval; }
+static StuffToFuzz_t fuzz;
+static uint8_t client_recv_buf[UDS_BUFSIZE];
-struct Impl {
- UDSTpHandle_t hdl;
- uint8_t buf[8192];
- size_t size;
-};
-
-static ssize_t tp_recv(UDSTpHandle_t *hdl, void *buf, size_t count, UDSTpAddr_t *ta_type) {
- struct Impl *pL_Impl = (struct Impl *)hdl;
- if (pL_Impl->size < count) {
- count = pL_Impl->size;
- }
- memmove(buf, pL_Impl->buf, count);
- pL_Impl->size = 0;
- return count;
+static uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
+ printf("Whoah, got event %d\n", ev);
+ return fuzz.srv_retval;
}
-ssize_t tp_send(struct UDSTpHandle *hdl, const void *buf, size_t count, UDSTpAddr_t ta_type) {
- return count;
-}
-
-UDSTpStatus_t tp_poll(struct UDSTpHandle *hdl) { return 0; }
-
-static struct Impl impl = {
- .hdl =
- {
- .recv = tp_recv,
- .send = tp_send,
- .poll = tp_poll,
- },
- .buf = {0},
- .size = 0,
-};
-
static uint32_t g_ms = 0;
uint32_t UDSMillis() { return g_ms; }
+static UDSServer_t srv;
+static UDSTpHandle_t *mock_client = NULL;
-int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
- UDSServer_t srv;
+void DoInitialization() {
UDSServerConfig_t cfg = {
.fn = fn,
- .tp = &impl.hdl,
+ .tp = TPMockCreate("server"),
+ .target_addr = 0x7E0,
+ .source_addr = 0x7E8,
+ .source_addr_func = 0x7DF,
};
- if (size < 1) {
- return 0;
- }
+ UDSServerInit(&srv, &cfg);
+ mock_client = TPMockCreate("client");
+}
- retval = data[0];
- size = size - 1;
- if (size > sizeof(impl.buf)) {
- size = sizeof(impl.buf);
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ static bool initialized = false;
+ if (!initialized) {
+ DoInitialization();
+ initialized = true;
}
- memmove(impl.buf, data, size);
- impl.size = size;
- UDSServerInit(&srv, &cfg);
+ memset(&fuzz, 0, sizeof(fuzz));
+ memmove(&fuzz, data, size);
+ srv.tp = TPMockCreate("server");
+ mock_client = TPMockCreate("client");
+
+ UDSSDU_t msg = {
+ .A_Mtype = UDS_A_MTYPE_DIAG,
+ .A_SA = fuzz.client_sa,
+ .A_TA = fuzz.client_ta,
+ .A_TA_Type = fuzz.client_func_req ? UDS_A_TA_TYPE_FUNCTIONAL : UDS_A_TA_TYPE_PHYSICAL,
+ .A_Length = size > offsetof(StuffToFuzz_t, msg) ? size - offsetof(StuffToFuzz_t, msg) : 0,
+ .A_Data = (uint8_t *)data + offsetof(StuffToFuzz_t, msg),
+ .A_DataBufSize = sizeof(fuzz.msg),
+ };
+ mock_client->send(mock_client, &msg);
+
for (g_ms = 0; g_ms < 100; g_ms++) {
UDSServerPoll(&srv);
}
+
+ {
+ UDSSDU_t msg2 = {
+ .A_Data = client_recv_buf,
+ .A_DataBufSize = sizeof(client_recv_buf),
+ };
+ mock_client->recv(mock_client, &msg2);
+ }
+ TPMockReset();
return 0;
}
diff --git a/test/test_server_0x10_diag_sess_ctrl_functional_request.c b/test/test_server_0x10_diag_sess_ctrl_functional_request.c
index 8900119..9906e2a 100644
--- a/test/test_server_0x10_diag_sess_ctrl_functional_request.c
+++ b/test/test_server_0x10_diag_sess_ctrl_functional_request.c
@@ -1,17 +1,19 @@
#include "test/test.h"
int main() {
- UDSSess_t mock_client;
+ UDSTpHandle_t *mock_client = ENV_GetMockTp("client");
UDSServer_t srv;
ENV_SERVER_INIT(srv);
ENV_SESS_INIT(mock_client);
// When server is sent a diagnostic session control request
const uint8_t REQ[] = {0x10, 0x02};
- EXPECT_OK(UDSSessSendFunctional(&mock_client, REQ, sizeof(REQ)));
+ UDSTpSend(mock_client, REQ, sizeof(REQ), &(UDSSDU_t){
+ .A_TA_Type = UDS_A_TA_TYPE_FUNCTIONAL
+ });
// the server should respond with a negative response within p2 ms
const uint8_t EXP_RESP[] = {0x7f, 0x10, 0x11};
- EXPECT_WITHIN_MS((mock_client.recv_size > 0), 50);
- TEST_MEMORY_EQUAL(mock_client.recv_buf, EXP_RESP, sizeof(EXP_RESP));
+ EXPECT_IN_APPROX_MS((UDSTpGetRecvLen(mock_client) > 0), srv.p2_ms)
+ TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(mock_client, NULL), EXP_RESP, sizeof(EXP_RESP));
}
diff --git a/test/test_server_0x10_diag_sess_ctrl_is_disabled_by_default.c b/test/test_server_0x10_diag_sess_ctrl_is_disabled_by_default.c
index 79aa105..7b6da92 100644
--- a/test/test_server_0x10_diag_sess_ctrl_is_disabled_by_default.c
+++ b/test/test_server_0x10_diag_sess_ctrl_is_disabled_by_default.c
@@ -1,17 +1,17 @@
#include "test/test.h"
int main() {
- UDSSess_t mock_client;
+ UDSTpHandle_t *mock_client = ENV_GetMockTp("client");
UDSServer_t srv;
ENV_SERVER_INIT(srv);
ENV_SESS_INIT(mock_client);
// When server is sent a diagnostic session control request
const uint8_t REQ[] = {0x10, 0x02};
- EXPECT_OK(UDSSessSend(&mock_client, REQ, sizeof(REQ)));
+ UDSTpSend(mock_client, REQ, sizeof(REQ), NULL);
// the server should respond with a negative response within p2 ms
const uint8_t EXP_RESP[] = {0x7f, 0x10, 0x11};
- EXPECT_WITHIN_MS((mock_client.recv_size > 0), 50);
- TEST_MEMORY_EQUAL(mock_client.recv_buf, EXP_RESP, sizeof(EXP_RESP));
+ EXPECT_IN_APPROX_MS(UDSTpGetRecvLen(mock_client) > 0, srv.p2_ms);
+ TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(mock_client, NULL), EXP_RESP, sizeof(EXP_RESP));
}
diff --git a/test/test_server_0x11_no_send_recv_after_ECU_reset.c b/test/test_server_0x11_no_send_recv_after_ECU_reset.c
index c1878aa..54476bc 100644
--- a/test/test_server_0x11_no_send_recv_after_ECU_reset.c
+++ b/test/test_server_0x11_no_send_recv_after_ECU_reset.c
@@ -1,3 +1,4 @@
+#include "iso14229.h"
#include "test/test.h"
uint8_t fn_callCount = 0;
@@ -13,7 +14,7 @@ uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
}
int main() {
- UDSSess_t mock_client;
+ UDSTpHandle_t *mock_client = ENV_GetMockTp("client");
UDSServer_t srv;
ENV_SERVER_INIT(srv);
ENV_SESS_INIT(mock_client);
@@ -23,17 +24,17 @@ int main() {
const uint8_t RESP[] = {0x51, 0x01};
// Sending the first ECU reset should result in a response
- EXPECT_OK(UDSSessSend(&mock_client, REQ, sizeof(REQ)));
- ENV_RunMillis(50);
- TEST_MEMORY_EQUAL(mock_client.recv_buf, RESP, sizeof(RESP));
+ UDSTpSend(mock_client, REQ, sizeof(REQ), NULL);
+ EXPECT_IN_APPROX_MS(UDSTpGetRecvLen(mock_client), srv.p2_ms);
+ TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(mock_client, NULL), RESP, sizeof(RESP));
- mock_client.recv_size = 0;
+ UDSTpAckRecv(mock_client);
- // Sending subsequent ECU reset requests should not receive any response
- EXPECT_OK(UDSSessSend(&mock_client, REQ, sizeof(REQ)));
- ENV_RunMillis(5000);
- TEST_INT_EQUAL(mock_client.recv_size, 0);
+ // Sending subsequent ECU reset requests should never receive any response
+ const unsigned LONG_TIME_MS = 5000;
+ UDSTpSend(mock_client, REQ, sizeof(REQ), NULL);
+ EXPECT_WHILE_MS(UDSTpGetRecvLen(mock_client) == 0, LONG_TIME_MS);
- // The ECU reset handler should have been called once.
+ // Additionally the ECU reset handler should have been called exactly once.
TEST_INT_EQUAL(fn_callCount, 1);
}
diff --git a/test/test_server_0x22_RDBI.c b/test/test_server_0x22_RDBI.c
index 95ba794..dc14e26 100644
--- a/test/test_server_0x22_RDBI.c
+++ b/test/test_server_0x22_RDBI.c
@@ -1,3 +1,4 @@
+#include "iso14229.h"
#include "test/test.h"
uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
@@ -23,26 +24,25 @@ uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
}
int main() {
- UDSSess_t mock_client;
+ UDSTpHandle_t *mock_client = ENV_GetMockTp("client");
UDSServer_t srv;
ENV_SERVER_INIT(srv);
srv.fn = fn;
ENV_SESS_INIT(mock_client);
{ // 11.2.5.2 Example #1 read single dataIdentifier 0xF190
uint8_t REQ[] = {0x22, 0xF1, 0x90};
- UDSSessSend(&mock_client, REQ, sizeof(REQ));
+ UDSTpSend(mock_client, REQ, sizeof(REQ), NULL);
uint8_t RESP[] = {0x62, 0xF1, 0x90, 0x57, 0x30, 0x4C, 0x30, 0x30, 0x30, 0x30,
0x34, 0x33, 0x4D, 0x42, 0x35, 0x34, 0x31, 0x33, 0x32, 0x36};
- ENV_RunMillis(50);
- TEST_INT_EQUAL(mock_client.recv_size, sizeof(RESP));
- TEST_MEMORY_EQUAL(mock_client.recv_buf, RESP, sizeof(RESP));
+ EXPECT_IN_APPROX_MS(UDSTpGetRecvLen(mock_client) == sizeof(RESP), srv.p2_ms)
+ TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(mock_client, NULL), RESP, sizeof(RESP));
+ UDSTpAckRecv(mock_client);
}
{ // Read a nonexistent dataIdentifier 0xF191
uint8_t REQ[] = {0x22, 0xF1, 0x91};
- UDSSessSend(&mock_client, REQ, sizeof(REQ));
+ UDSTpSend(mock_client, REQ, sizeof(REQ), NULL);
uint8_t RESP[] = {0x7F, 0x22, 0x31};
- ENV_RunMillis(50);
- TEST_INT_EQUAL(mock_client.recv_size, sizeof(RESP));
- TEST_MEMORY_EQUAL(mock_client.recv_buf, RESP, sizeof(RESP));
+ EXPECT_IN_APPROX_MS(UDSTpGetRecvLen(mock_client) == sizeof(RESP), srv.p2_ms)
+ TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(mock_client, NULL), RESP, sizeof(RESP));
}
}
diff --git a/test/test_server_0x23_read_memory_by_address.c b/test/test_server_0x23_read_memory_by_address.c
index 7ad4ecf..a8adf44 100644
--- a/test/test_server_0x23_read_memory_by_address.c
+++ b/test/test_server_0x23_read_memory_by_address.c
@@ -11,7 +11,7 @@ uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
}
int main() {
- UDSSess_t mock_client;
+ UDSTpHandle_t *mock_client = ENV_GetMockTp("client");
UDSServer_t srv;
ENV_SERVER_INIT(srv);
srv.fn = fn;
@@ -40,11 +40,11 @@ int main() {
0x01, // memorySize byte #1 (MSB)
0x03, // memorySize byte #2 (LSB)
};
- EXPECT_OK(UDSSessSend(&mock_client, REQ, sizeof(REQ)));
+ UDSTpSend(mock_client, REQ, sizeof(REQ), NULL);
// the server should respond with a positive response within p2 ms
- EXPECT_WITHIN_MS((mock_client.recv_size > 0), 50);
- TEST_MEMORY_EQUAL(mock_client.recv_buf, EXPECTED_RESP, sizeof(EXPECTED_RESP));
+ EXPECT_IN_APPROX_MS(UDSTpGetRecvLen(mock_client) > 0, srv.p2_ms);
+ TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(mock_client, NULL), EXPECTED_RESP, sizeof(EXPECTED_RESP));
}
// TODO: Tables 202-205
\ No newline at end of file
diff --git a/test/test_server_0x27_security_access.c b/test/test_server_0x27_security_access.c
index d1fdc96..1ea1c21 100644
--- a/test/test_server_0x27_security_access.c
+++ b/test/test_server_0x27_security_access.c
@@ -1,3 +1,4 @@
+#include "iso14229.h"
#include "test/test.h"
// UDS-1 2013 9.4.5.2
@@ -25,7 +26,8 @@ uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
}
int main() {
- UDSSess_t mock_client;
+ UDSTpHandle_t *mock_client = ENV_GetMockTp("client");
+ // UDSTpHandle_t *mock_client = ENV_GetMockTp("client");
UDSServer_t srv;
ENV_SERVER_INIT(srv);
srv.fn = fn;
@@ -37,9 +39,10 @@ int main() {
// sending a seed request should get this response
const uint8_t SEED_REQUEST[] = {0x27, 0x01};
const uint8_t SEED_RESPONSE[] = {0x67, 0x01, 0x36, 0x57};
- EXPECT_OK(UDSSessSend(&mock_client, SEED_REQUEST, sizeof(SEED_REQUEST)));
- ENV_RunMillis(50);
- TEST_MEMORY_EQUAL(mock_client.recv_buf, SEED_RESPONSE, sizeof(SEED_RESPONSE));
+ UDSTpSend(mock_client, SEED_REQUEST, sizeof(SEED_REQUEST), NULL);
+ EXPECT_IN_APPROX_MS(UDSTpGetRecvLen(mock_client) != 0, srv.p2_ms);
+ TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(mock_client, NULL), SEED_RESPONSE, sizeof(SEED_RESPONSE));
+ UDSTpAckRecv(mock_client);
// the server security level should still be 0
TEST_INT_EQUAL(srv.securityLevel, 0);
@@ -47,18 +50,19 @@ int main() {
// subsequently sending an unlock request should get this response
const uint8_t UNLOCK_REQUEST[] = {0x27, 0x02, 0xC9, 0xA9};
const uint8_t UNLOCK_RESPONSE[] = {0x67, 0x02};
- EXPECT_OK(UDSSessSend(&mock_client, UNLOCK_REQUEST, sizeof(UNLOCK_REQUEST)));
- ENV_RunMillis(50);
- TEST_MEMORY_EQUAL(mock_client.recv_buf, UNLOCK_RESPONSE, sizeof(UNLOCK_RESPONSE));
+ UDSTpSend(mock_client, UNLOCK_REQUEST, sizeof(UNLOCK_REQUEST), NULL);
+ EXPECT_IN_APPROX_MS(UDSTpGetRecvLen(mock_client) != 0, srv.p2_ms);
+ TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(mock_client, NULL), UNLOCK_RESPONSE, sizeof(UNLOCK_RESPONSE));
+ UDSTpAckRecv(mock_client);
// the server security level should now be 1
TEST_INT_EQUAL(srv.securityLevel, 1);
// sending the same seed request should now result in the "already unlocked" response
const uint8_t ALREADY_UNLOCKED_RESPONSE[] = {0x67, 0x01, 0x00, 0x00};
- EXPECT_OK(UDSSessSend(&mock_client, SEED_REQUEST, sizeof(SEED_REQUEST)));
- ENV_RunMillis(50);
- TEST_MEMORY_EQUAL(mock_client.recv_buf, ALREADY_UNLOCKED_RESPONSE,
+ UDSTpSend(mock_client, SEED_REQUEST, sizeof(SEED_REQUEST), NULL);
+ EXPECT_IN_APPROX_MS(UDSTpGetRecvLen(mock_client) != 0, srv.p2_ms);
+ TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(mock_client, NULL), ALREADY_UNLOCKED_RESPONSE,
sizeof(ALREADY_UNLOCKED_RESPONSE));
// Additionally, the security level should still be 1
diff --git a/test/test_server_0x31_RCRRP.c b/test/test_server_0x31_RCRRP.c
index 459e62a..521180c 100644
--- a/test/test_server_0x31_RCRRP.c
+++ b/test/test_server_0x31_RCRRP.c
@@ -1,3 +1,4 @@
+#include "iso14229.h"
#include "test/test.h"
static uint8_t resp;
@@ -6,7 +7,7 @@ static uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) { retu
// ISO-14229-1 2013 Table A.1 Byte Value 0x78: requestCorrectlyReceived-ResponsePending
// "This NRC is in general supported by each diagnostic service".
int main() {
- UDSSess_t mock_client;
+ UDSTpHandle_t *mock_client = ENV_GetMockTp("client");
UDSServer_t srv;
ENV_SERVER_INIT(srv);
srv.fn = fn;
@@ -17,27 +18,35 @@ int main() {
// sending a request to the server should return RCRRP within p2 ms
const uint8_t REQUEST[] = {0x31, 0x01, 0x12, 0x34};
- UDSSessSend(&mock_client, REQUEST, sizeof(REQUEST));
+ UDSTpSend(mock_client, REQUEST, sizeof(REQUEST), NULL);
const uint8_t RCRRP[] = {0x7F, 0x31, 0x78};
- EXPECT_WITHIN_MS((mock_client.recv_size > 0), 50);
- TEST_MEMORY_EQUAL(mock_client.recv_buf, RCRRP, sizeof(RCRRP));
- // The server should again respond within p2_star ms, and keep responding
- ENV_RunMillis(50);
- EXPECT_WITHIN_MS((mock_client.recv_size > 0), 50);
- TEST_MEMORY_EQUAL(mock_client.recv_buf, RCRRP, sizeof(RCRRP));
+ // There should be no response until P2_server has elapsed
+ EXPECT_IN_APPROX_MS((UDSTpGetRecvLen(mock_client) > 0), srv.p2_ms)
+ TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(mock_client, NULL), RCRRP, sizeof(RCRRP));
+ UDSTpAckRecv(mock_client);
- ENV_RunMillis(50);
- EXPECT_WITHIN_MS((mock_client.recv_size > 0), 50);
- TEST_MEMORY_EQUAL(mock_client.recv_buf, RCRRP, sizeof(RCRRP));
+ // The server should again respond within p2_star ms
+ EXPECT_IN_APPROX_MS((UDSTpGetRecvLen(mock_client) > 0), srv.p2_star_ms * 0.3)
+ TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(mock_client, NULL), RCRRP, sizeof(RCRRP));
+ UDSTpAckRecv(mock_client);
+
+ // and keep responding at intervals of p2_star ms
+ EXPECT_IN_APPROX_MS((UDSTpGetRecvLen(mock_client) > 0), srv.p2_star_ms * 0.3)
+ TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(mock_client, NULL), RCRRP, sizeof(RCRRP));
+ UDSTpAckRecv(mock_client);
+
+ EXPECT_IN_APPROX_MS((UDSTpGetRecvLen(mock_client) > 0), srv.p2_star_ms * 0.3)
+ TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(mock_client, NULL), RCRRP, sizeof(RCRRP));
+ UDSTpAckRecv(mock_client);
// When the user func now returns a positive response
resp = kPositiveResponse;
- ENV_RunMillis(50);
// the server's next response should be a positive one
+ // and it should arrive within p2 ms
const uint8_t POSITIVE_RESPONSE[] = {0x71, 0x01, 0x12, 0x34};
- EXPECT_WITHIN_MS((mock_client.recv_size > 0), 50);
- TEST_MEMORY_EQUAL(mock_client.recv_buf, POSITIVE_RESPONSE, sizeof(POSITIVE_RESPONSE));
+ EXPECT_IN_APPROX_MS((UDSTpGetRecvLen(mock_client) > 0), srv.p2_ms)
+ TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(mock_client, NULL), POSITIVE_RESPONSE, sizeof(POSITIVE_RESPONSE));
}
diff --git a/test/test_server_0x34.c b/test/test_server_0x34.c
index 65a9676..043b2d1 100644
--- a/test/test_server_0x34.c
+++ b/test/test_server_0x34.c
@@ -13,24 +13,24 @@ uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
int main() {
{ // case 0: No handler
- UDSSess_t mock_client;
+ UDSTpHandle_t *mock_client = ENV_GetMockTp("client");
UDSServer_t srv;
ENV_SERVER_INIT(srv);
ENV_SESS_INIT(mock_client);
// when no handler function is installed, sending this request to the server
uint8_t REQ[] = {0x34, 0x11, 0x33, 0x60, 0x20, 0x00, 0x00, 0xFF, 0xFF};
- EXPECT_OK(UDSSessSend(&mock_client, REQ, sizeof(REQ)));
+ UDSTpSend(mock_client, REQ, sizeof(REQ), NULL);
// should return a kServiceNotSupported response
uint8_t RESP[] = {0x7F, 0x34, 0x11};
- ENV_RunMillis(50);
- TEST_MEMORY_EQUAL(mock_client.recv_buf, RESP, sizeof(RESP));
+ EXPECT_IN_APPROX_MS(UDSTpGetRecvLen(mock_client) > 0, srv.p2_ms);
+ TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(mock_client, NULL), RESP, sizeof(RESP));
TPMockReset();
}
{ // case 1: handler installed
- UDSSess_t mock_client;
+ UDSTpHandle_t *mock_client = ENV_GetMockTp("client");
UDSServer_t srv;
ENV_SERVER_INIT(srv);
ENV_SESS_INIT(mock_client);
@@ -39,12 +39,12 @@ int main() {
// sending this request to the server
uint8_t REQ[] = {0x34, 0x11, 0x33, 0x60, 0x20, 0x00, 0x00, 0xFF, 0xFF};
- EXPECT_OK(UDSSessSend(&mock_client, REQ, sizeof(REQ)));
+ UDSTpSend(mock_client, REQ, sizeof(REQ), NULL);
// should receive a positive response matching UDS-1:2013 Table 415
uint8_t RESP[] = {0x74, 0x20, 0x00, 0x81};
- ENV_RunMillis(50);
- TEST_MEMORY_EQUAL(mock_client.recv_buf, RESP, sizeof(RESP));
+ EXPECT_IN_APPROX_MS(UDSTpGetRecvLen(mock_client) > 0, srv.p2_ms);
+ TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(mock_client, NULL), RESP, sizeof(RESP));
TPMockReset();
}
}
diff --git a/test/test_server_0x3E_suppress_positive_response.c b/test/test_server_0x3E_suppress_positive_response.c
index 3c1325e..8e52f5b 100644
--- a/test/test_server_0x3E_suppress_positive_response.c
+++ b/test/test_server_0x3E_suppress_positive_response.c
@@ -5,7 +5,7 @@ static uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
}
int main() {
- UDSSess_t mock_client;
+ UDSTpHandle_t *mock_client = ENV_GetMockTp("client");
UDSServer_t srv;
ENV_SERVER_INIT(srv);
srv.fn = fn;
@@ -13,9 +13,9 @@ int main() {
// when the suppressPositiveResponse bit is set
const uint8_t REQ[] = {0x3E, 0x80};
- EXPECT_OK(UDSSessSend(&mock_client, REQ, sizeof(REQ)));
+ UDSTpSend(mock_client, REQ, sizeof(REQ), NULL);
// there should be no response
ENV_RunMillis(5000);
- TEST_INT_EQUAL(mock_client.recv_size, 0);
+ TEST_INT_EQUAL(UDSTpGetRecvLen(mock_client), 0);
}
diff --git a/test/test_server_0x83_diagnostic_session_control.c b/test/test_server_0x83_diagnostic_session_control.c
index 224ecd8..858f656 100644
--- a/test/test_server_0x83_diagnostic_session_control.c
+++ b/test/test_server_0x83_diagnostic_session_control.c
@@ -5,7 +5,7 @@ static uint8_t ReturnPositiveResponse(UDSServer_t *srv, UDSServerEvent_t ev, con
}
int main() {
- UDSSess_t mock_client;
+ UDSTpHandle_t *mock_client = ENV_GetMockTp("client");
UDSServer_t srv;
ENV_SERVER_INIT(srv);
srv.fn = ReturnPositiveResponse;
@@ -16,12 +16,12 @@ int main() {
// when a request is sent with the suppressPositiveResponse bit set
const uint8_t REQ[] = {0x10, 0x83};
- EXPECT_OK(UDSSessSend(&mock_client, REQ, sizeof(REQ)));
+ UDSTpSend(mock_client, REQ, sizeof(REQ), NULL);
// even after running for a long time
ENV_RunMillis(5000);
// there should be no response from the server
- TEST_INT_EQUAL(mock_client.recv_size, 0);
+ TEST_INT_EQUAL(UDSTpGetRecvLen(mock_client), 0);
// however, the server sessionType should have changed
TEST_INT_EQUAL(srv.sessionType, kExtendedDiagnostic);
diff --git a/test/test_server_session_timeout.c b/test/test_server_session_timeout.c
index e320fc7..ab59505 100644
--- a/test/test_server_session_timeout.c
+++ b/test/test_server_session_timeout.c
@@ -9,7 +9,7 @@ uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
}
int main() {
- UDSSess_t mock_client;
+ UDSTpHandle_t *mock_client = ENV_GetMockTp("client");
UDSServer_t srv;
struct {
diff --git a/test_iso14229.c b/test_iso14229.c
index bf59e61..92320cd 100644
--- a/test_iso14229.c
+++ b/test_iso14229.c
@@ -232,7 +232,7 @@ static void poll_ctx(Ctx_t *ctx) {
.A_Data = d1, \
.A_Length = sizeof(d1), \
.A_SA = CLIENT_SOURCE_ADDR, \
- .A_TA = reqType == kTpAddrTypePhysical ? SERVER_SOURCE_ADDR : SERVER_SOURCE_ADDR_FUNC, \
+ .A_TA = reqType == UDS_A_TA_TYPE_PHYSICAL ? SERVER_SOURCE_ADDR : SERVER_SOURCE_ADDR_FUNC, \
.A_TA_Type = (int)reqType, \
}; \
ctx.mock_tp->send(ctx.mock_tp, &msg); \
@@ -247,9 +247,9 @@ static void poll_ctx(Ctx_t *ctx) {
int recv_len = ctx.mock_tp->recv(ctx.mock_tp, &msg); \
ASSERT_INT_EQUAL(recv_len, sizeof(d1)); \
ASSERT_MEMORY_EQUAL(ctx.mock_recv_buf, d1, sizeof(d1)); \
- if (reqType == kTpAddrTypePhysical) { \
+ if (reqType == UDS_A_TA_TYPE_PHYSICAL) { \
ASSERT_INT_EQUAL(msg.A_TA, SERVER_SOURCE_ADDR); \
- } else if (reqType == kTpAddrTypeFunctional) { \
+ } else if (reqType == UDS_A_TA_TYPE_FUNCTIONAL) { \
ASSERT_INT_EQUAL(msg.A_TA, SERVER_SOURCE_ADDR_FUNC); \
} else { \
assert(0); \
@@ -318,9 +318,9 @@ static void send_to_client(const uint8_t *d1, size_t len, UDSTpAddr_t reqType) {
void testServer0x10DiagSessCtrlIsDisabledByDefault() {
TEST_SETUP(SERVER_ONLY);
const uint8_t REQ[] = {0x10, 0x02};
- SEND_TO_SERVER(REQ, kTpAddrTypePhysical);
+ SEND_TO_SERVER(REQ, UDS_A_TA_TYPE_PHYSICAL);
const uint8_t RESP[] = {0x7f, 0x10, 0x11};
- EXPECT_RESPONSE_WITHIN_MILLIS(RESP, kTpAddrTypePhysical, 50);
+ EXPECT_RESPONSE_WITHIN_MILLIS(RESP, UDS_A_TA_TYPE_PHYSICAL, 50);
TEST_TEARDOWN();
}
@@ -328,10 +328,10 @@ void testServer0x10DiagSessCtrlFunctionalRequest() {
TEST_SETUP(SERVER_ONLY);
// sending a diagnostic session control request functional broadcast
const uint8_t REQ[] = {0x10, 0x03};
- SEND_TO_SERVER(REQ, kTpAddrTypeFunctional);
+ SEND_TO_SERVER(REQ, UDS_A_TA_TYPE_FUNCTIONAL);
// should receive a physical response
const uint8_t RESP[] = {0x7f, 0x10, 0x11};
- EXPECT_RESPONSE_WITHIN_MILLIS(RESP, kTpAddrTypePhysical, 50);
+ EXPECT_RESPONSE_WITHIN_MILLIS(RESP, UDS_A_TA_TYPE_PHYSICAL, 50);
TEST_TEARDOWN();
}
@@ -360,10 +360,10 @@ void testServer0x11DoesNotSendOrReceiveMessagesAfterECUReset() {
const uint8_t RESP[] = {0x51, 0x01};
// Sending the first ECU reset should result in a response
- SEND_TO_SERVER(REQ, kTpAddrTypePhysical);
- EXPECT_RESPONSE_WITHIN_MILLIS(RESP, kTpAddrTypePhysical, 50);
+ SEND_TO_SERVER(REQ, UDS_A_TA_TYPE_PHYSICAL);
+ EXPECT_RESPONSE_WITHIN_MILLIS(RESP, UDS_A_TA_TYPE_PHYSICAL, 50);
// Sending subsequent ECU reset requests should not receive any response
- SEND_TO_SERVER(REQ, kTpAddrTypePhysical);
+ SEND_TO_SERVER(REQ, UDS_A_TA_TYPE_PHYSICAL);
EXPECT_NO_RESPONSE_FOR_MILLIS(5000);
// The ECU reset handler should have been called once.
@@ -398,16 +398,16 @@ void testServer0x22RDBI1() {
ctx.server.fn = fn2;
{
uint8_t REQ[] = {0x22, 0xF1, 0x90};
- SEND_TO_SERVER(REQ, kTpAddrTypePhysical);
+ SEND_TO_SERVER(REQ, UDS_A_TA_TYPE_PHYSICAL);
uint8_t RESP[] = {0x62, 0xF1, 0x90, 0x57, 0x30, 0x4C, 0x30, 0x30, 0x30, 0x30,
0x34, 0x33, 0x4D, 0x42, 0x35, 0x34, 0x31, 0x33, 0x32, 0x36};
- EXPECT_RESPONSE_WITHIN_MILLIS(RESP, kTpAddrTypePhysical, 50);
+ EXPECT_RESPONSE_WITHIN_MILLIS(RESP, UDS_A_TA_TYPE_PHYSICAL, 50);
}
{
uint8_t REQ[] = {0x22, 0xF1, 0x91};
- SEND_TO_SERVER(REQ, kTpAddrTypePhysical);
+ SEND_TO_SERVER(REQ, UDS_A_TA_TYPE_PHYSICAL);
uint8_t RESP[] = {0x7F, 0x22, 0x31};
- EXPECT_RESPONSE_WITHIN_MILLIS(RESP, kTpAddrTypePhysical, 50);
+ EXPECT_RESPONSE_WITHIN_MILLIS(RESP, UDS_A_TA_TYPE_PHYSICAL, 50);
}
TEST_TEARDOWN();
}
@@ -426,9 +426,9 @@ void testServer0x23ReadMemoryByAddress() {
TEST_SETUP(SERVER_ONLY);
ctx.server.fn = fn10;
uint8_t REQ[] = {0x23, 0x18, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0xf0, 0xc8, 0x04};
- SEND_TO_SERVER(REQ, kTpAddrTypePhysical);
+ SEND_TO_SERVER(REQ, UDS_A_TA_TYPE_PHYSICAL);
uint8_t RESP[] = {0x63, 0x01, 0x02, 0x03, 0x04};
- EXPECT_RESPONSE_WITHIN_MILLIS(RESP, kTpAddrTypePhysical, 50);
+ EXPECT_RESPONSE_WITHIN_MILLIS(RESP, UDS_A_TA_TYPE_PHYSICAL, 50);
TEST_TEARDOWN();
}
@@ -466,19 +466,19 @@ void testServer0x27SecurityAccess() {
// sending a seed request should get this response
const uint8_t SEED_REQUEST[] = {0x27, 0x01};
const uint8_t SEED_RESPONSE[] = {0x67, 0x01, 0x36, 0x57};
- SEND_TO_SERVER(SEED_REQUEST, kTpAddrTypePhysical);
- EXPECT_RESPONSE_WITHIN_MILLIS(SEED_RESPONSE, kTpAddrTypePhysical, 50);
+ SEND_TO_SERVER(SEED_REQUEST, UDS_A_TA_TYPE_PHYSICAL);
+ EXPECT_RESPONSE_WITHIN_MILLIS(SEED_RESPONSE, UDS_A_TA_TYPE_PHYSICAL, 50);
// subsequently sending an unlock request should get this response
const uint8_t UNLOCK_REQUEST[] = {0x27, 0x02, 0xC9, 0xA9};
const uint8_t UNLOCK_RESPONSE[] = {0x67, 0x02};
- SEND_TO_SERVER(UNLOCK_REQUEST, kTpAddrTypePhysical);
- EXPECT_RESPONSE_WITHIN_MILLIS(UNLOCK_RESPONSE, kTpAddrTypePhysical, 50);
+ SEND_TO_SERVER(UNLOCK_REQUEST, UDS_A_TA_TYPE_PHYSICAL);
+ EXPECT_RESPONSE_WITHIN_MILLIS(UNLOCK_RESPONSE, UDS_A_TA_TYPE_PHYSICAL, 50);
// sending the same seed request should now result in the "already unlocked" response
const uint8_t ALREADY_UNLOCKED_RESPONSE[] = {0x67, 0x01, 0x00, 0x00};
- SEND_TO_SERVER(SEED_REQUEST, kTpAddrTypePhysical);
- EXPECT_RESPONSE_WITHIN_MILLIS(ALREADY_UNLOCKED_RESPONSE, kTpAddrTypePhysical, 50);
+ SEND_TO_SERVER(SEED_REQUEST, UDS_A_TA_TYPE_PHYSICAL);
+ EXPECT_RESPONSE_WITHIN_MILLIS(ALREADY_UNLOCKED_RESPONSE, UDS_A_TA_TYPE_PHYSICAL, 50);
// Additionally, the security level should now be 1
ASSERT_INT_EQUAL(ctx.server.securityLevel, 1);
@@ -502,23 +502,23 @@ void testServer0x31RCRRP() {
// sending a request to the server should return RCRRP
const uint8_t REQUEST[] = {0x31, 0x01, 0x12, 0x34};
const uint8_t RCRRP[] = {0x7F, 0x31, 0x78};
- SEND_TO_SERVER(REQUEST, kTpAddrTypePhysical);
- EXPECT_RESPONSE_WITHIN_MILLIS(RCRRP, kTpAddrTypePhysical, 50)
+ SEND_TO_SERVER(REQUEST, UDS_A_TA_TYPE_PHYSICAL);
+ EXPECT_RESPONSE_WITHIN_MILLIS(RCRRP, UDS_A_TA_TYPE_PHYSICAL, 50)
// The server should again respond within p2_star ms, and keep responding
- EXPECT_RESPONSE_WITHIN_MILLIS(RCRRP, kTpAddrTypePhysical, 50)
- EXPECT_RESPONSE_WITHIN_MILLIS(RCRRP, kTpAddrTypePhysical, 50)
- EXPECT_RESPONSE_WITHIN_MILLIS(RCRRP, kTpAddrTypePhysical, 50)
- EXPECT_RESPONSE_WITHIN_MILLIS(RCRRP, kTpAddrTypePhysical, 50)
- EXPECT_RESPONSE_WITHIN_MILLIS(RCRRP, kTpAddrTypePhysical, 50)
- EXPECT_RESPONSE_WITHIN_MILLIS(RCRRP, kTpAddrTypePhysical, 50)
+ EXPECT_RESPONSE_WITHIN_MILLIS(RCRRP, UDS_A_TA_TYPE_PHYSICAL, 50)
+ EXPECT_RESPONSE_WITHIN_MILLIS(RCRRP, UDS_A_TA_TYPE_PHYSICAL, 50)
+ EXPECT_RESPONSE_WITHIN_MILLIS(RCRRP, UDS_A_TA_TYPE_PHYSICAL, 50)
+ EXPECT_RESPONSE_WITHIN_MILLIS(RCRRP, UDS_A_TA_TYPE_PHYSICAL, 50)
+ EXPECT_RESPONSE_WITHIN_MILLIS(RCRRP, UDS_A_TA_TYPE_PHYSICAL, 50)
+ EXPECT_RESPONSE_WITHIN_MILLIS(RCRRP, UDS_A_TA_TYPE_PHYSICAL, 50)
// When the server handler func now returns a positive response
ctx.server.fn = ReturnPositiveResponse;
// the server's next response should be a positive one
const uint8_t POSITIVE_RESPONSE[] = {0x71, 0x01, 0x12, 0x34};
- EXPECT_RESPONSE_WITHIN_MILLIS(POSITIVE_RESPONSE, kTpAddrTypePhysical, 50)
+ EXPECT_RESPONSE_WITHIN_MILLIS(POSITIVE_RESPONSE, UDS_A_TA_TYPE_PHYSICAL, 50)
TEST_TEARDOWN();
}
@@ -527,11 +527,11 @@ void testServer0x34NotEnabled() {
TEST_SETUP(SERVER_ONLY);
// when no handler function is installed, sending this request to the server
const uint8_t IN[] = {0x34, 0x11, 0x33, 0x60, 0x20, 0x00, 0x00, 0xFF, 0xFF};
- SEND_TO_SERVER(IN, kTpAddrTypePhysical);
+ SEND_TO_SERVER(IN, UDS_A_TA_TYPE_PHYSICAL);
// should return a kServiceNotSupported response
const uint8_t OUT[] = {0x7F, 0x34, 0x11};
- EXPECT_RESPONSE_WITHIN_MILLIS(OUT, kTpAddrTypePhysical, 50);
+ EXPECT_RESPONSE_WITHIN_MILLIS(OUT, UDS_A_TA_TYPE_PHYSICAL, 50);
TEST_TEARDOWN();
}
@@ -553,11 +553,11 @@ void testServer0x34() {
// sending this request to the server
uint8_t REQ[] = {0x34, 0x11, 0x33, 0x60, 0x20, 0x00, 0x00, 0xFF, 0xFF};
- SEND_TO_SERVER(REQ, kTpAddrTypePhysical);
+ SEND_TO_SERVER(REQ, UDS_A_TA_TYPE_PHYSICAL);
// should receive a positive response matching UDS-1:2013 Table 415
uint8_t RESP[] = {0x74, 0x20, 0x00, 0x81};
- EXPECT_RESPONSE_WITHIN_MILLIS(RESP, kTpAddrTypePhysical, 50)
+ EXPECT_RESPONSE_WITHIN_MILLIS(RESP, UDS_A_TA_TYPE_PHYSICAL, 50)
TEST_TEARDOWN();
}
@@ -568,7 +568,7 @@ void testServer0x3ESuppressPositiveResponse() {
// when the suppressPositiveResponse bit is set
const uint8_t REQ[] = {0x3E, 0x80};
// there should be no response
- SEND_TO_SERVER(REQ, kTpAddrTypePhysical);
+ SEND_TO_SERVER(REQ, UDS_A_TA_TYPE_PHYSICAL);
EXPECT_NO_RESPONSE_FOR_MILLIS(5000);
TEST_TEARDOWN();
}
@@ -581,7 +581,7 @@ void testServer0x83DiagnosticSessionControl() {
// When the suppressPositiveResponse bit is set, there should be no response.
const uint8_t REQ[] = {0x10, 0x83};
- SEND_TO_SERVER(REQ, kTpAddrTypePhysical);
+ SEND_TO_SERVER(REQ, UDS_A_TA_TYPE_PHYSICAL);
EXPECT_NO_RESPONSE_FOR_MILLIS(5000);
// and the server sessionType should have changed
ASSERT_INT_EQUAL(ctx.server.sessionType, kExtendedDiagnostic);
@@ -647,7 +647,7 @@ void testClientP2TimeoutNotExceeded() {
// which receives a positive response
const uint8_t POSITIVE_RESPONSE[] = {0x51, 0x01};
- SEND_TO_CLIENT(POSITIVE_RESPONSE, kTpAddrTypePhysical);
+ SEND_TO_CLIENT(POSITIVE_RESPONSE, UDS_A_TA_TYPE_PHYSICAL);
POLL_UNTIL_TIME_MS(UDS_CLIENT_DEFAULT_P2_MS + 10);
// should return to the idle state
@@ -714,7 +714,7 @@ void testClient0x11ECUReset() {
ctx.client.options = p[i].options;
UDSSendECUReset(&ctx.client, kHardReset);
// that receives this response
- send_to_client(p[i].resp, p[i].resp_len, kTpAddrTypePhysical);
+ send_to_client(p[i].resp, p[i].resp_len, UDS_A_TA_TYPE_PHYSICAL);
// should return to the idle state
POLL_UNTIL_TIME_MS(UDS_CLIENT_DEFAULT_P2_MS + 10);
ASSERT_INT_EQUAL(kRequestStateIdle, ctx.client.state);
@@ -777,7 +777,7 @@ void testClient0x31RCRRP() {
// that receives an RCRRP response
const uint8_t RCRRP[] = {0x7F, 0x31, 0x78}; // RequestCorrectly-ReceievedResponsePending
- SEND_TO_CLIENT(RCRRP, kTpAddrTypePhysical);
+ SEND_TO_CLIENT(RCRRP, UDS_A_TA_TYPE_PHYSICAL);
// that remains unresolved at a time between p2 ms and p2 star ms
POLL_FOR_MS(UDS_CLIENT_DEFAULT_P2_MS + 10);
@@ -796,7 +796,7 @@ void testClient0x31RCRRP() {
// that receives an RCRRP response
const uint8_t RCRRP[] = {0x7F, 0x31, 0x78}; // RequestCorrectly-ReceievedResponsePending
- SEND_TO_CLIENT(RCRRP, kTpAddrTypePhysical);
+ SEND_TO_CLIENT(RCRRP, UDS_A_TA_TYPE_PHYSICAL);
// that remains unresolved at a time between p2 ms and p2 star ms
POLL_FOR_MS(UDS_CLIENT_DEFAULT_P2_MS + 10);
@@ -806,7 +806,7 @@ void testClient0x31RCRRP() {
// When the client receives a positive response from the server
const uint8_t POSITIVE_RESPONSE[] = {0x71, 0x01, 0x12, 0x34};
- SEND_TO_CLIENT(POSITIVE_RESPONSE, kTpAddrTypePhysical);
+ SEND_TO_CLIENT(POSITIVE_RESPONSE, UDS_A_TA_TYPE_PHYSICAL);
POLL_FOR_MS(5);
@@ -825,7 +825,7 @@ void testClient0x34RequestDownload() {
// the bytes sent should match UDS-1 2013 Table 415
const uint8_t CORRECT_REQUEST[] = {0x34, 0x11, 0x33, 0x60, 0x20, 0x00, 0x00, 0xFF, 0xFF};
- ASSERT_CLIENT_SENT(CORRECT_REQUEST, kTpAddrTypePhysical);
+ ASSERT_CLIENT_SENT(CORRECT_REQUEST, UDS_A_TA_TYPE_PHYSICAL);
TEST_TEARDOWN();
}
diff --git a/tp/isotp-c b/tp/isotp-c
new file mode 160000
index 0000000..59dc573
--- /dev/null
+++ b/tp/isotp-c
@@ -0,0 +1 @@
+Subproject commit 59dc573a944a2661df6cda42c22edf5cfe53931b
diff --git a/tp/isotp-c/.gitignore b/tp/isotp-c/.gitignore
deleted file mode 100644
index 0d36244..0000000
--- a/tp/isotp-c/.gitignore
+++ /dev/null
@@ -1,17 +0,0 @@
-###
-# .GITIGNORE FILE
-# This file contains instructions for filesystem entries git should ignore when
-# doing things to this repository.
-###
-
-###
-# Ignore Artifacts
-###
-*.o
-bin/
-build/
-
-###
-# Ignore Backups
-###
-*~
diff --git a/tp/isotp-c/.travis.yml b/tp/isotp-c/.travis.yml
deleted file mode 100644
index d46676c..0000000
--- a/tp/isotp-c/.travis.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-language: c++
-compiler:
- - gcc
- - g++
- - clang
-script: make travis
diff --git a/tp/isotp-c/CMakeLists.txt b/tp/isotp-c/CMakeLists.txt
deleted file mode 100644
index 162db5f..0000000
--- a/tp/isotp-c/CMakeLists.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-cmake_minimum_required(VERSION 3.10)
-
-###
-# Project definition
-###
-project(isotp LANGUAGES C)
-
-###
-# Get all include directories
-###
-include_directories(
- ${CMAKE_CURRENT_SOURCE_DIR}/
-)
-
-###
-# Compile isotp as Shared Lib
-###
-add_library(isotp SHARED
- isotp.c)
\ No newline at end of file
diff --git a/tp/isotp-c/LICENSE b/tp/isotp-c/LICENSE
deleted file mode 100644
index 19e89e3..0000000
--- a/tp/isotp-c/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2019 Shen Li & Co-Operators
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/tp/isotp-c/Makefile b/tp/isotp-c/Makefile
deleted file mode 100644
index bd65906..0000000
--- a/tp/isotp-c/Makefile
+++ /dev/null
@@ -1,66 +0,0 @@
-include vars.mk
-
-CFLAGS := -Wall -g -ggdb $(STD)
-LDFLAGS := -shared
-BIN := ./bin
-
-.PHONY: all clean fPIC no_opt $(BIN)/$(LIB_NAME) $(BIN)/$(LIB_NAME).$(MAJOR_VER) $(BIN)/$(LIB_NAME).$(MAJOR_VER).$(MINOR_VER).$(REVISION) travis
-
-###
-# BEGIN TARGETS
-###
-
-###
-# Builds all library artifacts
-###
-all: $(BIN)/$(LIB_NAME)
- @printf "########## BUILT $^ ##########\n\n\n"
-
-fPIC: CFLAGS += "-fPIC"
-
-travis: fPIC all
-
-###
-# Builds all targets w/o optimisations enabled
-###
-no_opt: CFLAGS += -g -O0 all
-
-###
-# Removes all build artifacts
-###
-clean:
- -rm -f *.o $(BIN)/$(LIB_NAME)*
-
-###
-# Builds all library artifacts, including all symlinks.
-###
-$(BIN)/$(LIB_NAME): $(BIN)/$(LIB_NAME).$(MAJOR_VER)
- -ln -s $^ $@
- @printf "Linked $^ --> $@...\n"
-
-###
-# Builds the shared object along with one symlink
-###
-$(BIN)/$(LIB_NAME).$(MAJOR_VER): $(BIN)/$(LIB_NAME).$(MAJOR_VER).$(MINOR_VER).$(REVISION)
- -ln -s $^ $@
- @printf "Linked $^ --> $@...\n"
-
-$(BIN)/$(LIB_NAME).$(MAJOR_VER).$(MINOR_VER).$(REVISION): libisotp.o
- if [ ! -d $(BIN) ]; then mkdir $(BIN); fi;
- ${COMP} $^ -o $@ ${LDFLAGS}
-
-###
-# Compiles the isotp.c TU to an object file.
-###
-libisotp.o: isotp.c
- ${COMP} -c $^ -o $@ ${CFLAGS}
-
-install: all
- @printf "Installing $(LIB_NAME) to $(INSTALL_DIR)...\n"
- cp $(BIN)/$(LIB_NAME)* $(INSTALL_DIR)
- @printf "Library was installed...\n"
-
-###
-# END TARGETS
-###
-
diff --git a/tp/isotp-c/README.md b/tp/isotp-c/README.md
deleted file mode 100644
index 1a2fc3b..0000000
--- a/tp/isotp-c/README.md
+++ /dev/null
@@ -1,189 +0,0 @@
-ISO-TP (ISO 15765-2) Support Library in C
-================================
-
-**This project is inspired by [openxc isotp-c](https://github.com/openxc/isotp-c), but the code has been completely re-written.**
-
-This is a platform agnostic C library that implements the [ISO 15765-2](https://en.wikipedia.org/wiki/ISO_15765-2) (also known as ISO-TP) protocol, which runs over a CAN bus. Quoting Wikipedia:
-
->ISO 15765-2, or ISO-TP, is an international standard for sending data packets over a CAN-Bus.
->The protocol allows for the transport of messages that exceed the eight byte maximum payload of CAN frames.
->ISO-TP segments longer messages into multiple frames, adding metadata that allows the interpretation of individual frames and reassembly
->into a complete message packet by the recipient. It can carry up to 4095 bytes of payload per message packet.
-
-This library doesn't assume anything about the source of the ISO-TP messages or the underlying interface to CAN. It uses dependency injection to give you complete control.
-
-**The current version supports [ISO-15765-2](https://en.wikipedia.org/wiki/ISO_15765-2) single and multiple frame transmition, and works in Full-duplex mode.**
-
-## Builds
-
-### Master Build
-[![Build Status](https://api.travis-ci.com/Beatsleigher/isotp-c.svg?branch=master)](https://travis-ci.com/Beatsleigher/isotp-c)
-
-## Usage
-
-First, create some [shim](https://en.wikipedia.org/wiki/Shim_(computing)) functions to let this library use your lower level system:
-
-```C
- /* required, this must send a single CAN message with the given arbitration
- * ID (i.e. the CAN message ID) and data. The size will never be more than 8
- * bytes. */
- int isotp_user_send_can(const uint32_t arbitration_id,
- const uint8_t* data, const uint8_t size) {
- // ...
- }
-
- /* required, return system tick, unit is millisecond */
- uint32_t isotp_user_get_ms(void) {
- // ...
- }
-
- /* optional, provide to receive debugging log messages */
- void isotp_user_debug(const char* message, ...) {
- // ...
- }
-```
-
-### API
-
-You can use isotp-c in the following way:
-
-```C
- /* Alloc IsoTpLink statically in RAM */
- static IsoTpLink g_link;
-
- /* Alloc send and receive buffer statically in RAM */
- static uint8_t g_isotpRecvBuf[ISOTP_BUFSIZE];
- static uint8_t g_isotpSendBuf[ISOTP_BUFSIZE];
-
- int main(void) {
- /* Initialize CAN and other peripherals */
-
- /* Initialize link, 0x7TT is the CAN ID you send with */
- isotp_init_link(&g_link, 0x7TT,
- g_isotpSendBuf, sizeof(g_isotpSendBuf),
- g_isotpRecvBuf, sizeof(g_isotpRecvBuf));
-
- while(1) {
-
- /* If receive any interested can message, call isotp_on_can_message to handle message */
- ret = can_receive(&id, &data, &len);
-
- /* 0x7RR is CAN ID you want to receive */
- if (RET_OK == ret && 0x7RR == id) {
- isotp_on_can_message(&g_link, data, len);
- }
-
- /* Poll link to handle multiple frame transmition */
- isotp_poll(&g_link);
-
- /* You can receive message with isotp_receive.
- payload is upper layer message buffer, usually UDS;
- payload_size is payload buffer size;
- out_size is the actuall read size;
- */
- ret = isotp_receive(&g_link, payload, payload_size, &out_size);
- if (ISOTP_RET_OK == ret) {
- /* Handle received message */
- }
-
- /* And send message with isotp_send */
- ret = isotp_send(&g_link, payload, payload_size);
- if (ISOTP_RET_OK == ret) {
- /* Send ok */
- } else {
- /* An error occured */
- }
-
- /* In case you want to send data w/ functional addressing, use isotp_send_with_id */
- ret = isotp_send_with_id(&g_link, 0x7df, payload, payload_size);
- if (ISOTP_RET_OK == ret) {
- /* Send ok */
- } else {
- /* Error occur */
- }
- }
-
- return;
- }
-```
-
-You can call isotp_poll as frequently as you want, as it internally uses isotp_user_get_ms to measure timeout occurences.
-If you need handle functional addressing, you must use two separate links, one for each.
-
-```C
- /* Alloc IsoTpLink statically in RAM */
- static IsoTpLink g_phylink;
- static IsoTpLink g_funclink;
-
- /* Allocate send and receive buffer statically in RAM */
- static uint8_t g_isotpPhyRecvBuf[512];
- static uint8_t g_isotpPhySendBuf[512];
- /* currently functional addressing is not supported with multi-frame messages */
- static uint8_t g_isotpFuncRecvBuf[8];
- static uint8_t g_isotpFuncSendBuf[8];
-
- int main(void) {
- /* Initialize CAN and other peripherals */
-
- /* Initialize link, 0x7TT is the CAN ID you send with */
- isotp_init_link(&g_phylink, 0x7TT,
- g_isotpPhySendBuf, sizeof(g_isotpPhySendBuf),
- g_isotpPhyRecvBuf, sizeof(g_isotpPhyRecvBuf));
- isotp_init_link(&g_funclink, 0x7TT,
- g_isotpFuncSendBuf, sizeof(g_isotpFuncSendBuf),
- g_isotpFuncRecvBuf, sizeof(g_isotpFuncRecvBuf));
-
- while(1) {
-
- /* If any CAN messages are received, which are of interest, call isotp_on_can_message to handle the message */
- ret = can_receive(&id, &data, &len);
-
- /* 0x7RR is CAN ID you want to receive */
- if (RET_OK == ret) {
- if (0x7RR == id) {
- isotp_on_can_message(&g_phylink, data, len);
- } else if (0x7df == id) {
- isotp_on_can_message(&g_funclink, data, len);
- }
- }
-
- /* Poll link to handle multiple frame transmition */
- isotp_poll(&g_phylink);
- isotp_poll(&g_funclink);
-
- /* You can receive message with isotp_receive.
- payload is upper layer message buffer, usually UDS;
- payload_size is payload buffer size;
- out_size is the actuall read size;
- */
- ret = isotp_receive(&g_phylink, payload, payload_size, &out_size);
- if (ISOTP_RET_OK == ret) {
- /* Handle physical addressing message */
- }
-
- ret = isotp_receive(&g_funclink, payload, payload_size, &out_size);
- if (ISOTP_RET_OK == ret) {
- /* Handle functional addressing message */
- }
-
- /* And send message with isotp_send */
- ret = isotp_send(&g_phylink, payload, payload_size);
- if (ISOTP_RET_OK == ret) {
- /* Send ok */
- } else {
- /* An error occured */
- }
- }
-
- return;
- }
-```
-
-## Authors
-
-* **shen.li lishen5@gmail.com** (Original author!)
-* **Simon Cahill** **s.cahill@grimme.de** (or **contact@simonc.eu**)
-
-## License
-
-Licensed under the MIT license.
diff --git a/tp/isotp-c/isotp.c b/tp/isotp-c/isotp.c
deleted file mode 100644
index b1f4807..0000000
--- a/tp/isotp-c/isotp.c
+++ /dev/null
@@ -1,510 +0,0 @@
-#include
-#include "assert.h"
-#include "isotp.h"
-
-///////////////////////////////////////////////////////
-/// STATIC FUNCTIONS ///
-///////////////////////////////////////////////////////
-
-/* st_min to microsecond */
-static uint8_t isotp_us_to_st_min(uint32_t us) {
- if (us <= 127000) {
- return us / 1000;
- } else if (us >= 100 && us <= 900) {
- return 0xF0 + (us / 100);
- }
- return 0;
-}
-
-/* st_min to usec */
-static uint32_t isotp_st_min_to_us(uint8_t st_min) {
- if (st_min <= 0x7F) {
- return st_min * 1000;
- } else if (st_min >= 0xF1 && st_min <= 0xF9) {
- return (st_min - 0xF0) * 100;
- }
- return 0;
-}
-
-static int isotp_send_flow_control(IsoTpLink* link, uint8_t flow_status, uint8_t block_size, uint32_t st_min_us) {
-
- IsoTpCanMessage message;
- int ret;
-
- /* setup message */
- message.as.flow_control.type = ISOTP_PCI_TYPE_FLOW_CONTROL_FRAME;
- message.as.flow_control.FS = flow_status;
- message.as.flow_control.BS = block_size;
- message.as.flow_control.STmin = isotp_us_to_st_min(st_min_us);
-
- /* send message */
-#ifdef ISO_TP_FRAME_PADDING
- (void) memset(message.as.flow_control.reserve, 0, sizeof(message.as.flow_control.reserve));
- ret = isotp_user_send_can(link->send_arbitration_id, message.as.data_array.ptr, sizeof(message));
-#else
- ret = isotp_user_send_can(link->send_arbitration_id,
- message.as.data_array.ptr,
- 3);
-#endif
-
- return ret;
-}
-
-static int isotp_send_single_frame(IsoTpLink* link, uint32_t id) {
-
- IsoTpCanMessage message;
- int ret;
-
- /* multi frame message length must greater than 7 */
- assert(link->send_size <= 7);
-
- /* setup message */
- message.as.single_frame.type = ISOTP_PCI_TYPE_SINGLE;
- message.as.single_frame.SF_DL = (uint8_t) link->send_size;
- (void) memcpy(message.as.single_frame.data, link->send_buffer, link->send_size);
-
- /* send message */
-#ifdef ISO_TP_FRAME_PADDING
- (void) memset(message.as.single_frame.data + link->send_size, 0, sizeof(message.as.single_frame.data) - link->send_size);
- ret = isotp_user_send_can(id, message.as.data_array.ptr, sizeof(message));
-#else
- ret = isotp_user_send_can(id,
- message.as.data_array.ptr,
- link->send_size + 1);
-#endif
-
- return ret;
-}
-
-static int isotp_send_first_frame(IsoTpLink* link, uint32_t id) {
-
- IsoTpCanMessage message;
- int ret;
-
- /* multi frame message length must greater than 7 */
- assert(link->send_size > 7);
-
- /* setup message */
- message.as.first_frame.type = ISOTP_PCI_TYPE_FIRST_FRAME;
- message.as.first_frame.FF_DL_low = (uint8_t) link->send_size;
- message.as.first_frame.FF_DL_high = (uint8_t) (0x0F & (link->send_size >> 8));
- (void) memcpy(message.as.first_frame.data, link->send_buffer, sizeof(message.as.first_frame.data));
-
- /* send message */
- ret = isotp_user_send_can(id, message.as.data_array.ptr, sizeof(message));
- if (ISOTP_RET_OK == ret) {
- link->send_offset += sizeof(message.as.first_frame.data);
- link->send_sn = 1;
- }
-
- return ret;
-}
-
-static int isotp_send_consecutive_frame(IsoTpLink* link) {
-
- IsoTpCanMessage message;
- uint16_t data_length;
- int ret;
-
- /* multi frame message length must greater than 7 */
- assert(link->send_size > 7);
-
- /* setup message */
- message.as.consecutive_frame.type = TSOTP_PCI_TYPE_CONSECUTIVE_FRAME;
- message.as.consecutive_frame.SN = link->send_sn;
- data_length = link->send_size - link->send_offset;
- if (data_length > sizeof(message.as.consecutive_frame.data)) {
- data_length = sizeof(message.as.consecutive_frame.data);
- }
- (void) memcpy(message.as.consecutive_frame.data, link->send_buffer + link->send_offset, data_length);
-
- /* send message */
-#ifdef ISO_TP_FRAME_PADDING
- (void) memset(message.as.consecutive_frame.data + data_length, 0, sizeof(message.as.consecutive_frame.data) - data_length);
- ret = isotp_user_send_can(link->send_arbitration_id, message.as.data_array.ptr, sizeof(message));
-#else
- ret = isotp_user_send_can(link->send_arbitration_id,
- message.as.data_array.ptr,
- data_length + 1);
-#endif
- if (ISOTP_RET_OK == ret) {
- link->send_offset += data_length;
- if (++(link->send_sn) > 0x0F) {
- link->send_sn = 0;
- }
- }
-
- return ret;
-}
-
-static int isotp_receive_single_frame(IsoTpLink *link, IsoTpCanMessage *message, uint8_t len) {
- /* check data length */
- if ((0 == message->as.single_frame.SF_DL) || (message->as.single_frame.SF_DL > (len - 1))) {
- isotp_user_debug("Single-frame length too small.");
- return ISOTP_RET_LENGTH;
- }
-
- /* copying data */
- (void) memcpy(link->receive_buffer, message->as.single_frame.data, message->as.single_frame.SF_DL);
- link->receive_size = message->as.single_frame.SF_DL;
-
- return ISOTP_RET_OK;
-}
-
-static int isotp_receive_first_frame(IsoTpLink *link, IsoTpCanMessage *message, uint8_t len) {
- uint16_t payload_length;
-
- if (8 != len) {
- isotp_user_debug("First frame should be 8 bytes in length.");
- return ISOTP_RET_LENGTH;
- }
-
- /* check data length */
- payload_length = message->as.first_frame.FF_DL_high;
- payload_length = (payload_length << 8) + message->as.first_frame.FF_DL_low;
-
- /* should not use multiple frame transmition */
- if (payload_length <= 7) {
- isotp_user_debug("Should not use multiple frame transmission.");
- return ISOTP_RET_LENGTH;
- }
-
- if (payload_length > link->receive_buf_size) {
- isotp_user_debug("Multi-frame response too large for receiving buffer.");
- return ISOTP_RET_OVERFLOW;
- }
-
- /* copying data */
- (void) memcpy(link->receive_buffer, message->as.first_frame.data, sizeof(message->as.first_frame.data));
- link->receive_size = payload_length;
- link->receive_offset = sizeof(message->as.first_frame.data);
- link->receive_sn = 1;
-
- return ISOTP_RET_OK;
-}
-
-static int isotp_receive_consecutive_frame(IsoTpLink *link, IsoTpCanMessage *message, uint8_t len) {
- uint16_t remaining_bytes;
-
- /* check sn */
- if (link->receive_sn != message->as.consecutive_frame.SN) {
- return ISOTP_RET_WRONG_SN;
- }
-
- /* check data length */
- remaining_bytes = link->receive_size - link->receive_offset;
- if (remaining_bytes > sizeof(message->as.consecutive_frame.data)) {
- remaining_bytes = sizeof(message->as.consecutive_frame.data);
- }
- if (remaining_bytes > len - 1) {
- isotp_user_debug("Consecutive frame too short.");
- return ISOTP_RET_LENGTH;
- }
-
- /* copying data */
- (void) memcpy(link->receive_buffer + link->receive_offset, message->as.consecutive_frame.data, remaining_bytes);
-
- link->receive_offset += remaining_bytes;
- if (++(link->receive_sn) > 0x0F) {
- link->receive_sn = 0;
- }
-
- return ISOTP_RET_OK;
-}
-
-static int isotp_receive_flow_control_frame(IsoTpLink *link, IsoTpCanMessage *message, uint8_t len) {
- /* check message length */
- if (len < 3) {
- isotp_user_debug("Flow control frame too short.");
- return ISOTP_RET_LENGTH;
- }
-
- return ISOTP_RET_OK;
-}
-
-///////////////////////////////////////////////////////
-/// PUBLIC FUNCTIONS ///
-///////////////////////////////////////////////////////
-
-int isotp_send(IsoTpLink *link, const uint8_t payload[], uint16_t size) {
- return isotp_send_with_id(link, link->send_arbitration_id, payload, size);
-}
-
-int isotp_send_with_id(IsoTpLink *link, uint32_t id, const uint8_t payload[], uint16_t size) {
- int ret;
-
- if (link == 0x0) {
- isotp_user_debug("Link is null!");
- return ISOTP_RET_ERROR;
- }
-
- if (size > link->send_buf_size) {
- isotp_user_debug("Message size too large. Increase ISO_TP_MAX_MESSAGE_SIZE to set a larger buffer\n");
- char message[128];
- sprintf(&message[0], "Attempted to send %d bytes; max size is %d!\n", size, link->send_buf_size);
- isotp_user_debug(message);
- return ISOTP_RET_OVERFLOW;
- }
-
- if (ISOTP_SEND_STATUS_INPROGRESS == link->send_status) {
- isotp_user_debug("Abort previous message, transmission in progress.\n");
- return ISOTP_RET_INPROGRESS;
- }
-
- /* copy into local buffer */
- link->send_size = size;
- link->send_offset = 0;
- (void) memcpy(link->send_buffer, payload, size);
-
- if (link->send_size < 8) {
- /* send single frame */
- ret = isotp_send_single_frame(link, id);
- } else {
- /* send multi-frame */
- ret = isotp_send_first_frame(link, id);
-
- /* init multi-frame control flags */
- if (ISOTP_RET_OK == ret) {
- link->send_bs_remain = 0;
- link->send_st_min_us = 0;
- link->send_wtf_count = 0;
- link->send_timer_st = isotp_user_get_us();
- link->send_timer_bs = isotp_user_get_us() + ISO_TP_DEFAULT_RESPONSE_TIMEOUT_US;
- link->send_protocol_result = ISOTP_PROTOCOL_RESULT_OK;
- link->send_status = ISOTP_SEND_STATUS_INPROGRESS;
- }
- }
-
- return ret;
-}
-
-void isotp_on_can_message(IsoTpLink *link, uint8_t *data, uint8_t len) {
- IsoTpCanMessage message;
- int ret;
-
- if (len < 2 || len > 8) {
- return;
- }
-
- memcpy(message.as.data_array.ptr, data, len);
- memset(message.as.data_array.ptr + len, 0, sizeof(message.as.data_array.ptr) - len);
-
- switch (message.as.common.type) {
- case ISOTP_PCI_TYPE_SINGLE: {
- /* update protocol result */
- if (ISOTP_RECEIVE_STATUS_INPROGRESS == link->receive_status) {
- link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_UNEXP_PDU;
- } else {
- link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_OK;
- }
-
- /* handle message */
- ret = isotp_receive_single_frame(link, &message, len);
-
- if (ISOTP_RET_OK == ret) {
- /* change status */
- link->receive_status = ISOTP_RECEIVE_STATUS_FULL;
- }
- break;
- }
- case ISOTP_PCI_TYPE_FIRST_FRAME: {
- /* update protocol result */
- if (ISOTP_RECEIVE_STATUS_INPROGRESS == link->receive_status) {
- link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_UNEXP_PDU;
- } else {
- link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_OK;
- }
-
- /* handle message */
- ret = isotp_receive_first_frame(link, &message, len);
-
- /* if overflow happened */
- if (ISOTP_RET_OVERFLOW == ret) {
- /* update protocol result */
- link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_BUFFER_OVFLW;
- /* change status */
- link->receive_status = ISOTP_RECEIVE_STATUS_IDLE;
- /* send error message */
- isotp_send_flow_control(link, PCI_FLOW_STATUS_OVERFLOW, 0, 0);
- break;
- }
-
- /* if receive successful */
- if (ISOTP_RET_OK == ret) {
- /* change status */
- link->receive_status = ISOTP_RECEIVE_STATUS_INPROGRESS;
- /* send fc frame */
- link->receive_bs_count = ISO_TP_DEFAULT_BLOCK_SIZE;
- isotp_send_flow_control(link, PCI_FLOW_STATUS_CONTINUE, link->receive_bs_count, ISO_TP_DEFAULT_ST_MIN_US);
- /* refresh timer cs */
- link->receive_timer_cr = isotp_user_get_us() + ISO_TP_DEFAULT_RESPONSE_TIMEOUT_US;
- }
-
- break;
- }
- case TSOTP_PCI_TYPE_CONSECUTIVE_FRAME: {
- /* check if in receiving status */
- if (ISOTP_RECEIVE_STATUS_INPROGRESS != link->receive_status) {
- link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_UNEXP_PDU;
- break;
- }
-
- /* handle message */
- ret = isotp_receive_consecutive_frame(link, &message, len);
-
- /* if wrong sn */
- if (ISOTP_RET_WRONG_SN == ret) {
- link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_WRONG_SN;
- link->receive_status = ISOTP_RECEIVE_STATUS_IDLE;
- break;
- }
-
- /* if success */
- if (ISOTP_RET_OK == ret) {
- /* refresh timer cs */
- link->receive_timer_cr = isotp_user_get_us() + ISO_TP_DEFAULT_RESPONSE_TIMEOUT_US;
-
- /* receive finished */
- if (link->receive_offset >= link->receive_size) {
- link->receive_status = ISOTP_RECEIVE_STATUS_FULL;
- } else {
- /* send fc when bs reaches limit */
- if (0 == --link->receive_bs_count) {
- link->receive_bs_count = ISO_TP_DEFAULT_BLOCK_SIZE;
- isotp_send_flow_control(link, PCI_FLOW_STATUS_CONTINUE, link->receive_bs_count, ISO_TP_DEFAULT_ST_MIN_US);
- }
- }
- }
-
- break;
- }
- case ISOTP_PCI_TYPE_FLOW_CONTROL_FRAME:
- /* handle fc frame only when sending in progress */
- if (ISOTP_SEND_STATUS_INPROGRESS != link->send_status) {
- break;
- }
-
- /* handle message */
- ret = isotp_receive_flow_control_frame(link, &message, len);
-
- if (ISOTP_RET_OK == ret) {
- /* refresh bs timer */
- link->send_timer_bs = isotp_user_get_us() + ISO_TP_DEFAULT_RESPONSE_TIMEOUT_US;
-
- /* overflow */
- if (PCI_FLOW_STATUS_OVERFLOW == message.as.flow_control.FS) {
- link->send_protocol_result = ISOTP_PROTOCOL_RESULT_BUFFER_OVFLW;
- link->send_status = ISOTP_SEND_STATUS_ERROR;
- }
-
- /* wait */
- else if (PCI_FLOW_STATUS_WAIT == message.as.flow_control.FS) {
- link->send_wtf_count += 1;
- /* wait exceed allowed count */
- if (link->send_wtf_count > ISO_TP_MAX_WFT_NUMBER) {
- link->send_protocol_result = ISOTP_PROTOCOL_RESULT_WFT_OVRN;
- link->send_status = ISOTP_SEND_STATUS_ERROR;
- }
- }
-
- /* permit send */
- else if (PCI_FLOW_STATUS_CONTINUE == message.as.flow_control.FS) {
- if (0 == message.as.flow_control.BS) {
- link->send_bs_remain = ISOTP_INVALID_BS;
- } else {
- link->send_bs_remain = message.as.flow_control.BS;
- }
- uint32_t message_st_min_us = isotp_st_min_to_us(message.as.flow_control.STmin);
- link->send_st_min_us = message_st_min_us > ISO_TP_DEFAULT_ST_MIN_US ? message_st_min_us : ISO_TP_DEFAULT_ST_MIN_US; // prefer as much st_min as possible for stability?
- link->send_wtf_count = 0;
- }
- }
- break;
- default:
- break;
- };
-
- return;
-}
-
-int isotp_receive(IsoTpLink *link, uint8_t *payload, const uint16_t payload_size, uint16_t *out_size) {
- uint16_t copylen;
-
- if (ISOTP_RECEIVE_STATUS_FULL != link->receive_status) {
- return ISOTP_RET_NO_DATA;
- }
-
- copylen = link->receive_size;
- if (copylen > payload_size) {
- copylen = payload_size;
- }
-
- memcpy(payload, link->receive_buffer, copylen);
- *out_size = copylen;
-
- link->receive_status = ISOTP_RECEIVE_STATUS_IDLE;
-
- return ISOTP_RET_OK;
-}
-
-void isotp_init_link(IsoTpLink *link, uint32_t sendid, uint8_t *sendbuf, uint16_t sendbufsize, uint8_t *recvbuf, uint16_t recvbufsize) {
- memset(link, 0, sizeof(*link));
- link->receive_status = ISOTP_RECEIVE_STATUS_IDLE;
- link->send_status = ISOTP_SEND_STATUS_IDLE;
- link->send_arbitration_id = sendid;
- link->send_buffer = sendbuf;
- link->send_buf_size = sendbufsize;
- link->receive_buffer = recvbuf;
- link->receive_buf_size = recvbufsize;
-
- return;
-}
-
-void isotp_poll(IsoTpLink *link) {
- int ret;
-
- /* only polling when operation in progress */
- if (ISOTP_SEND_STATUS_INPROGRESS == link->send_status) {
-
- /* continue send data */
- if (/* send data if bs_remain is invalid or bs_remain large than zero */
- (ISOTP_INVALID_BS == link->send_bs_remain || link->send_bs_remain > 0) &&
- /* and if st_min is zero or go beyond interval time */
- (0 == link->send_st_min_us || IsoTpTimeAfter(isotp_user_get_us(), link->send_timer_st))) {
-
- ret = isotp_send_consecutive_frame(link);
- if (ISOTP_RET_OK == ret) {
- if (ISOTP_INVALID_BS != link->send_bs_remain) {
- link->send_bs_remain -= 1;
- }
- link->send_timer_bs = isotp_user_get_us() + ISO_TP_DEFAULT_RESPONSE_TIMEOUT_US;
- link->send_timer_st = isotp_user_get_us() + link->send_st_min_us;
-
- /* check if send finish */
- if (link->send_offset >= link->send_size) {
- link->send_status = ISOTP_SEND_STATUS_IDLE;
- }
- } else {
- link->send_status = ISOTP_SEND_STATUS_ERROR;
- }
- }
-
- /* check timeout */
- if (IsoTpTimeAfter(isotp_user_get_us(), link->send_timer_bs)) {
- link->send_protocol_result = ISOTP_PROTOCOL_RESULT_TIMEOUT_BS;
- link->send_status = ISOTP_SEND_STATUS_ERROR;
- }
- }
-
- /* only polling when operation in progress */
- if (ISOTP_RECEIVE_STATUS_INPROGRESS == link->receive_status) {
-
- /* check timeout */
- if (IsoTpTimeAfter(isotp_user_get_us(), link->receive_timer_cr)) {
- link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_TIMEOUT_CR;
- link->receive_status = ISOTP_RECEIVE_STATUS_IDLE;
- }
- }
-
- return;
-}
diff --git a/tp/isotp-c/isotp.h b/tp/isotp-c/isotp.h
deleted file mode 100644
index 682bcea..0000000
--- a/tp/isotp-c/isotp.h
+++ /dev/null
@@ -1,130 +0,0 @@
-#ifndef __ISOTP_H__
-#define __ISOTP_H__
-
-#include
-#include
-
-#ifdef __cplusplus
-#include
-
-extern "C" {
-#endif
-
-#include "isotp_defines.h"
-#include "isotp_config.h"
-#include "isotp_user.h"
-
-/**
- * @brief Struct containing the data for linking an application to a CAN instance.
- * The data stored in this struct is used internally and may be used by software programs
- * using this library.
- */
-typedef struct IsoTpLink {
- /* sender paramters */
- uint32_t send_arbitration_id; /* used to reply consecutive frame */
- /* message buffer */
- uint8_t* send_buffer;
- uint16_t send_buf_size;
- uint16_t send_size;
- uint16_t send_offset;
- /* multi-frame flags */
- uint8_t send_sn;
- uint16_t send_bs_remain; /* Remaining block size */
- uint32_t send_st_min_us; /* Separation Time between consecutive frames */
- uint8_t send_wtf_count; /* Maximum number of FC.Wait frame transmissions */
- uint32_t send_timer_st; /* Last time send consecutive frame */
- uint32_t send_timer_bs; /* Time until reception of the next FlowControl N_PDU
- start at sending FF, CF, receive FC
- end at receive FC */
- int send_protocol_result;
- uint8_t send_status;
- /* receiver paramters */
- uint32_t receive_arbitration_id;
- /* message buffer */
- uint8_t* receive_buffer;
- uint16_t receive_buf_size;
- uint16_t receive_size;
- uint16_t receive_offset;
- /* multi-frame control */
- uint8_t receive_sn;
- uint8_t receive_bs_count; /* Maximum number of FC.Wait frame transmissions */
- uint32_t receive_timer_cr; /* Time until transmission of the next ConsecutiveFrame N_PDU
- start at sending FC, receive CF
- end at receive FC */
- int receive_protocol_result;
- uint8_t receive_status;
-} IsoTpLink;
-
-/**
- * @brief Initialises the ISO-TP library.
- *
- * @param link The @code IsoTpLink @endcode instance used for transceiving data.
- * @param sendid The ID used to send data to other CAN nodes.
- * @param sendbuf A pointer to an area in memory which can be used as a buffer for data to be sent.
- * @param sendbufsize The size of the buffer area.
- * @param recvbuf A pointer to an area in memory which can be used as a buffer for data to be received.
- * @param recvbufsize The size of the buffer area.
- */
-void isotp_init_link(IsoTpLink *link, uint32_t sendid,
- uint8_t *sendbuf, uint16_t sendbufsize,
- uint8_t *recvbuf, uint16_t recvbufsize);
-
-/**
- * @brief Polling function; call this function periodically to handle timeouts, send consecutive frames, etc.
- *
- * @param link The @code IsoTpLink @endcode instance used.
- */
-void isotp_poll(IsoTpLink *link);
-
-/**
- * @brief Handles incoming CAN messages.
- * Determines whether an incoming message is a valid ISO-TP frame or not and handles it accordingly.
- *
- * @param link The @code IsoTpLink @endcode instance used for transceiving data.
- * @param data The data received via CAN.
- * @param len The length of the data received.
- */
-void isotp_on_can_message(IsoTpLink *link, uint8_t *data, uint8_t len);
-
-/**
- * @brief Sends ISO-TP frames via CAN, using the ID set in the initialising function.
- *
- * Single-frame messages will be sent immediately when calling this function.
- * Multi-frame messages will be sent consecutively when calling isotp_poll.
- *
- * @param link The @code IsoTpLink @endcode instance used for transceiving data.
- * @param payload The payload to be sent. (Up to 4095 bytes).
- * @param size The size of the payload to be sent.
- *
- * @return Possible return values:
- * - @code ISOTP_RET_OVERFLOW @endcode
- * - @code ISOTP_RET_INPROGRESS @endcode
- * - @code ISOTP_RET_OK @endcode
- * - The return value of the user shim function isotp_user_send_can().
- */
-int isotp_send(IsoTpLink *link, const uint8_t payload[], uint16_t size);
-
-/**
- * @brief See @link isotp_send @endlink, with the exception that this function is used only for functional addressing.
- */
-int isotp_send_with_id(IsoTpLink *link, uint32_t id, const uint8_t payload[], uint16_t size);
-
-/**
- * @brief Receives and parses the received data and copies the parsed data in to the internal buffer.
- * @param link The @link IsoTpLink @endlink instance used to transceive data.
- * @param payload A pointer to an area in memory where the raw data is copied from.
- * @param payload_size The size of the received (raw) CAN data.
- * @param out_size A reference to a variable which will contain the size of the actual (parsed) data.
- *
- * @return Possible return values:
- * - @link ISOTP_RET_OK @endlink
- * - @link ISOTP_RET_NO_DATA @endlink
- */
-int isotp_receive(IsoTpLink *link, uint8_t *payload, const uint16_t payload_size, uint16_t *out_size);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // __ISOTP_H__
-
diff --git a/tp/isotp-c/isotp_config.h b/tp/isotp-c/isotp_config.h
deleted file mode 100644
index 637682b..0000000
--- a/tp/isotp-c/isotp_config.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef __ISOTP_CONFIG__
-#define __ISOTP_CONFIG__
-
-/* Max number of messages the receiver can receive at one time, this value
- * is affectied by can driver queue length
- */
-#define ISO_TP_DEFAULT_BLOCK_SIZE 8
-
-/* The STmin parameter value specifies the minimum time gap allowed between
- * the transmission of consecutive frame network protocol data units
- */
-#define ISO_TP_DEFAULT_ST_MIN_US 0
-
-/* This parameter indicate how many FC N_PDU WTs can be transmitted by the
- * receiver in a row.
- */
-#define ISO_TP_MAX_WFT_NUMBER 1
-
-/* Private: The default timeout to use when waiting for a response during a
- * multi-frame send or receive.
- */
-#define ISO_TP_DEFAULT_RESPONSE_TIMEOUT_US 100000
-
-/* Private: Determines if by default, padding is added to ISO-TP message frames.
- */
-#define ISO_TP_FRAME_PADDING
-
-#endif
-
diff --git a/tp/isotp-c/isotp_defines.h b/tp/isotp-c/isotp_defines.h
deleted file mode 100644
index d8217ad..0000000
--- a/tp/isotp-c/isotp_defines.h
+++ /dev/null
@@ -1,225 +0,0 @@
-#ifndef __ISOTP_TYPES__
-#define __ISOTP_TYPES__
-
-/**************************************************************
- * compiler specific defines
- *************************************************************/
-#ifdef __GNUC__
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-#define ISOTP_BYTE_ORDER_LITTLE_ENDIAN
-#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
-#else
-#error "unsupported byte ordering"
-#endif
-#endif
-
-/**************************************************************
- * OS specific defines
- *************************************************************/
-#ifdef _WIN32
-#define snprintf _snprintf
-#endif
-
-#ifdef _WIN32
-#define ISOTP_BYTE_ORDER_LITTLE_ENDIAN
-#define __builtin_bswap8 _byteswap_uint8
-#define __builtin_bswap16 _byteswap_uint16
-#define __builtin_bswap32 _byteswap_uint32
-#define __builtin_bswap64 _byteswap_uint64
-#endif
-
-/**************************************************************
- * internal used defines
- *************************************************************/
-#define ISOTP_RET_OK 0
-#define ISOTP_RET_ERROR -1
-#define ISOTP_RET_INPROGRESS -2
-#define ISOTP_RET_OVERFLOW -3
-#define ISOTP_RET_WRONG_SN -4
-#define ISOTP_RET_NO_DATA -5
-#define ISOTP_RET_TIMEOUT -6
-#define ISOTP_RET_LENGTH -7
-
-/* return logic true if 'a' is after 'b' */
-#define IsoTpTimeAfter(a,b) ((int32_t)((int32_t)(b) - (int32_t)(a)) < 0)
-
-/* invalid bs */
-#define ISOTP_INVALID_BS 0xFFFF
-
-/* ISOTP sender status */
-typedef enum {
- ISOTP_SEND_STATUS_IDLE,
- ISOTP_SEND_STATUS_INPROGRESS,
- ISOTP_SEND_STATUS_ERROR,
-} IsoTpSendStatusTypes;
-
-/* ISOTP receiver status */
-typedef enum {
- ISOTP_RECEIVE_STATUS_IDLE,
- ISOTP_RECEIVE_STATUS_INPROGRESS,
- ISOTP_RECEIVE_STATUS_FULL,
-} IsoTpReceiveStatusTypes;
-
-/* can fram defination */
-#if defined(ISOTP_BYTE_ORDER_LITTLE_ENDIAN)
-typedef struct {
- uint8_t reserve_1:4;
- uint8_t type:4;
- uint8_t reserve_2[7];
-} IsoTpPciType;
-
-typedef struct {
- uint8_t SF_DL:4;
- uint8_t type:4;
- uint8_t data[7];
-} IsoTpSingleFrame;
-
-typedef struct {
- uint8_t FF_DL_high:4;
- uint8_t type:4;
- uint8_t FF_DL_low;
- uint8_t data[6];
-} IsoTpFirstFrame;
-
-typedef struct {
- uint8_t SN:4;
- uint8_t type:4;
- uint8_t data[7];
-} IsoTpConsecutiveFrame;
-
-typedef struct {
- uint8_t FS:4;
- uint8_t type:4;
- uint8_t BS;
- uint8_t STmin;
- uint8_t reserve[5];
-} IsoTpFlowControl;
-
-#else
-
-typedef struct {
- uint8_t type:4;
- uint8_t reserve_1:4;
- uint8_t reserve_2[7];
-} IsoTpPciType;
-
-/*
-* single frame
-* +-------------------------+-----+
-* | byte #0 | ... |
-* +-------------------------+-----+
-* | nibble #0 | nibble #1 | ... |
-* +-------------+-----------+ ... +
-* | PCIType = 0 | SF_DL | ... |
-* +-------------+-----------+-----+
-*/
-typedef struct {
- uint8_t type:4;
- uint8_t SF_DL:4;
- uint8_t data[7];
-} IsoTpSingleFrame;
-
-/*
-* first frame
-* +-------------------------+-----------------------+-----+
-* | byte #0 | byte #1 | ... |
-* +-------------------------+-----------+-----------+-----+
-* | nibble #0 | nibble #1 | nibble #2 | nibble #3 | ... |
-* +-------------+-----------+-----------+-----------+-----+
-* | PCIType = 1 | FF_DL | ... |
-* +-------------+-----------+-----------------------+-----+
-*/
-typedef struct {
- uint8_t type:4;
- uint8_t FF_DL_high:4;
- uint8_t FF_DL_low;
- uint8_t data[6];
-} IsoTpFirstFrame;
-
-/*
-* consecutive frame
-* +-------------------------+-----+
-* | byte #0 | ... |
-* +-------------------------+-----+
-* | nibble #0 | nibble #1 | ... |
-* +-------------+-----------+ ... +
-* | PCIType = 0 | SN | ... |
-* +-------------+-----------+-----+
-*/
-typedef struct {
- uint8_t type:4;
- uint8_t SN:4;
- uint8_t data[7];
-} IsoTpConsecutiveFrame;
-
-/*
-* flow control frame
-* +-------------------------+-----------------------+-----------------------+-----+
-* | byte #0 | byte #1 | byte #2 | ... |
-* +-------------------------+-----------+-----------+-----------+-----------+-----+
-* | nibble #0 | nibble #1 | nibble #2 | nibble #3 | nibble #4 | nibble #5 | ... |
-* +-------------+-----------+-----------+-----------+-----------+-----------+-----+
-* | PCIType = 1 | FS | BS | STmin | ... |
-* +-------------+-----------+-----------------------+-----------------------+-----+
-*/
-typedef struct {
- uint8_t type:4;
- uint8_t FS:4;
- uint8_t BS;
- uint8_t STmin;
- uint8_t reserve[5];
-} IsoTpFlowControl;
-
-#endif
-
-typedef struct {
- uint8_t ptr[8];
-} IsoTpDataArray;
-
-typedef struct {
- union {
- IsoTpPciType common;
- IsoTpSingleFrame single_frame;
- IsoTpFirstFrame first_frame;
- IsoTpConsecutiveFrame consecutive_frame;
- IsoTpFlowControl flow_control;
- IsoTpDataArray data_array;
- } as;
-} IsoTpCanMessage;
-
-/**************************************************************
- * protocol specific defines
- *************************************************************/
-
-/* Private: Protocol Control Information (PCI) types, for identifying each frame of an ISO-TP message.
- */
-typedef enum {
- ISOTP_PCI_TYPE_SINGLE = 0x0,
- ISOTP_PCI_TYPE_FIRST_FRAME = 0x1,
- TSOTP_PCI_TYPE_CONSECUTIVE_FRAME = 0x2,
- ISOTP_PCI_TYPE_FLOW_CONTROL_FRAME = 0x3
-} IsoTpProtocolControlInformation;
-
-/* Private: Protocol Control Information (PCI) flow control identifiers.
- */
-typedef enum {
- PCI_FLOW_STATUS_CONTINUE = 0x0,
- PCI_FLOW_STATUS_WAIT = 0x1,
- PCI_FLOW_STATUS_OVERFLOW = 0x2
-} IsoTpFlowStatus;
-
-/* Private: network layer resault code.
- */
-#define ISOTP_PROTOCOL_RESULT_OK 0
-#define ISOTP_PROTOCOL_RESULT_TIMEOUT_A -1
-#define ISOTP_PROTOCOL_RESULT_TIMEOUT_BS -2
-#define ISOTP_PROTOCOL_RESULT_TIMEOUT_CR -3
-#define ISOTP_PROTOCOL_RESULT_WRONG_SN -4
-#define ISOTP_PROTOCOL_RESULT_INVALID_FS -5
-#define ISOTP_PROTOCOL_RESULT_UNEXP_PDU -6
-#define ISOTP_PROTOCOL_RESULT_WFT_OVRN -7
-#define ISOTP_PROTOCOL_RESULT_BUFFER_OVFLW -8
-#define ISOTP_PROTOCOL_RESULT_ERROR -9
-
-#endif
-
diff --git a/tp/isotp-c/isotp_user.h b/tp/isotp-c/isotp_user.h
deleted file mode 100644
index ed40337..0000000
--- a/tp/isotp-c/isotp_user.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef __ISOTP_USER_H__
-#define __ISOTP_USER_H__
-
-#include
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* user implemented, print debug message */
-void isotp_user_debug(const char* message, ...);
-
-/* user implemented, send can message. should return ISOTP_RET_OK when success.
-*/
-int isotp_user_send_can(const uint32_t arbitration_id,
- const uint8_t* data, const uint8_t size);
-
-/* user implemented, get microsecond */
-uint32_t isotp_user_get_us(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // __ISOTP_H__
-
diff --git a/tp/isotp-c/vars.mk b/tp/isotp-c/vars.mk
deleted file mode 100644
index aaccb13..0000000
--- a/tp/isotp-c/vars.mk
+++ /dev/null
@@ -1,63 +0,0 @@
-###
-# CROSS variable
-# Use for cross-compilation.
-# Uncommenting and setting this variable to the prefix of
-# your cross compiler will allow you to cross compile this library.
-###
-#CROSS=powerpc-linux-gnu
-
-###
-# LANG variable
-# Set this value according to the language
-# you wish to compile against.
-# Possible (legal) values:
-# - C [c]
-# - C++ [c++]
-###
-LANG := "C++"
-
-###
-# STD variables.
-# Do NOT set the STD variable.
-# Instead, set the C/C++ STD variables
-# according to the standard you wish to use.
-###
-CSTD := "gnu99"
-CPPSTD := "c++0x"
-
-###
-# OUTPUT_NAME variable.
-# This variable contains the name of the output file (the .so).
-###
-LIB_NAME := "libisotp.so"
-MAJOR_VER := "1"
-MINOR_VER := "0"
-REVISION := "0"
-OUTPUT_NAME := $(LIB_NAME).$(MAJOR_VER).$(MINOR_VER).$(REVISION)
-
-###
-# INSTALL_DIR variable.
-# Set this variable to the location where the lib should be installed.
-###
-INSTALL_DIR := /usr/lib
-
-###
-# Compute compiler and language standard to use
-# This section determines which compiler to use.
-###
-ifeq ($(LANG), "C++")
-STD := "-std=$(CPPSTD)"
-ifeq ($(strip $(CROSS)),)
-COMP := g++
-else
-COMP := $(CROSS)g++
-endif
-endif
-ifeq ($(LANG), "C")
-STD := "-std=$(CSTD)"
-ifeq ($(strip $(CROSS)),)
-COMP := gcc
-else
-COMP := $(CROSS)gcc
-endif
-endif
diff --git a/tp/isotp_c_socketcan.c b/tp/isotp_c_socketcan.c
index a3cad36..bf83714 100644
--- a/tp/isotp_c_socketcan.c
+++ b/tp/isotp_c_socketcan.c
@@ -121,7 +121,7 @@ static ssize_t tp_recv(UDSTpHandle_t *hdl, UDSSDU_t *msg) {
struct {
IsoTpLink *link;
UDSTpAddr_t ta_type;
- } arr[] = {{&impl->phys_link, kTpAddrTypePhysical}, {&impl->func_link, kTpAddrTypeFunctional}};
+ } arr[] = {{&impl->phys_link, UDS_A_TA_TYPE_PHYSICAL}, {&impl->func_link, UDS_A_TA_TYPE_FUNCTIONAL}};
for (size_t i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) {
ret = isotp_receive(arr[i].link, msg->A_Data, msg->A_DataBufSize, &size);
switch (ret) {
@@ -162,16 +162,16 @@ static ssize_t tp_recv(UDSTpHandle_t *hdl, UDSSDU_t *msg) {
return ret;
}
-static ssize_t tp_send(UDSTpHandle_t *hdl, UDSSDU_t *msg) {
+static ssize_t tp_send(UDSTpHandle_t *hdl, uint8_t *buf, ssize_t len, UDSSDU_t *info) {
assert(hdl);
ssize_t ret = -1;
UDSTpISOTpC_t *impl = (UDSTpISOTpC_t *)hdl;
IsoTpLink *link = NULL;
switch (msg->A_TA_Type) {
- case kTpAddrTypePhysical:
+ case UDS_A_TA_TYPE_PHYSICAL:
link = &impl->phys_link;
break;
- case kTpAddrTypeFunctional:
+ case UDS_A_TA_TYPE_FUNCTIONAL:
link = &impl->func_link;
break;
default:
@@ -239,23 +239,4 @@ UDSErr_t UDSTpISOTpCInitClient(UDSTpISOTpC_t *tp, UDSClient_t *client, const cha
tp->func_recv_buf, sizeof(tp->func_recv_buf));
return UDS_OK;
}
-
-UDSErr_t UDSTpISOTpCInitSess(UDSTpISOTpC_t *tp, UDSSess_t *sess, const char *ifname, uint32_t source_addr, uint32_t target_addr, uint32_t source_addr_func) {
- assert(tp);
- assert(ifname);
- tp->hdl.poll = tp_poll;
- tp->hdl.recv = tp_recv;
- tp->hdl.send = tp_send;
-
- tp->phys_sa = source_addr;
- tp->phys_ta = target_addr;
- tp->func_sa = source_addr_func;
- tp->func_ta = target_addr;
-
-
- isotp_init_link(&tp->phys_link, target_addr, sess->send_buf, sizeof(sess->send_buf),
- sess->recv_buf, sizeof(sess->recv_buf));
- isotp_init_link(&tp->func_link, target_addr, tp->func_send_buf, sizeof(tp->func_send_buf),
- tp->func_recv_buf, sizeof(tp->func_recv_buf));
- return UDS_OK;
-}
\ No newline at end of file
+
\ No newline at end of file
diff --git a/tp/isotp_c_socketcan.h b/tp/isotp_c_socketcan.h
index a3dcec6..47d4e34 100644
--- a/tp/isotp_c_socketcan.h
+++ b/tp/isotp_c_socketcan.h
@@ -8,6 +8,8 @@ typedef struct {
UDSTpHandle_t hdl;
IsoTpLink phys_link;
IsoTpLink func_link;
+ uint8_t send_buf[UDS_BUFSIZE];
+ uint8_t recv_buf[UDS_BUFSIZE];
uint8_t func_recv_buf[8];
uint8_t func_send_buf[8];
int fd;
@@ -20,9 +22,10 @@ UDSErr_t UDSTpISOTpCInitServer(UDSTpISOTpC_t *tp, UDSServer_t *srv, const char *
uint32_t target_addr, uint32_t target_addr_func);
UDSErr_t UDSTpISOTpCInitClient(UDSTpISOTpC_t *tp, UDSClient_t *client, const char *ifname, uint32_t source_addr,
uint32_t target_addr, uint32_t target_addr_func);
-UDSErr_t UDSTpISOTpCInitSess(UDSTpISOTpC_t *tp, UDSSess_t *sess, const char *ifname, uint32_t source_addr,
- uint32_t target_addr, uint32_t target_addr_func);
void UDSTpISOTpCDeinit(UDSTpISOTpC_t *tp);
+UDSErr_t UDSTpisotpcInit(UDSTpISOTpC_t *tp, const char *ifname, uint32_t source_addr,
+ uint32_t target_addr, uint32_t source_addr_func, uint32_t target_addr_func);
+
#endif
\ No newline at end of file
diff --git a/tp/isotp_sock.c b/tp/isotp_sock.c
index 688febf..fa8c3a4 100644
--- a/tp/isotp_sock.c
+++ b/tp/isotp_sock.c
@@ -13,8 +13,8 @@
static UDSTpStatus_t tp_poll(UDSTpHandle_t *hdl) { return 0; }
-static ssize_t tp_recv_once(int fd, UDSSDU_t *msg, bool functional) {
- ssize_t ret = read(fd, msg->A_Data, msg->A_DataBufSize);
+static ssize_t tp_recv_once(int fd, uint8_t *buf, size_t size) {
+ ssize_t ret = read(fd, buf, size);
if (ret < 0) {
if (EAGAIN == errno || EWOULDBLOCK == errno) {
ret = 0;
@@ -24,75 +24,97 @@ static ssize_t tp_recv_once(int fd, UDSSDU_t *msg, bool functional) {
UDS_DBG_PRINT("Perhaps I received multiple responses?\n");
}
}
- } else if (ret > 0) {
- msg->A_Length = ret;
- msg->A_TA_Type = functional ? UDS_A_TA_TYPE_FUNCTIONAL : UDS_A_TA_TYPE_PHYSICAL;
}
return ret;
}
-static ssize_t tp_recv(UDSTpHandle_t *hdl, UDSSDU_t *msg) {
+static ssize_t tp_peek(UDSTpHandle_t *hdl, uint8_t **p_buf, UDSSDU_t *info) {
assert(hdl);
- assert(msg);
+ assert(p_buf);
ssize_t ret = 0;
UDSTpIsoTpSock_t *impl = (UDSTpIsoTpSock_t *)hdl;
+ *p_buf = impl->recv_buf;
+ if (impl->recv_len) { // recv not yet acked
+ ret = impl->recv_len;
+ goto done;
+ }
- ret = tp_recv_once(impl->phys_fd, msg, false);
+ UDSSDU_t *msg = &impl->recv_info;
+
+ // recv acked, OK to receive
+ ret = tp_recv_once(impl->phys_fd, impl->recv_buf, sizeof(impl->recv_buf));
if (ret > 0) {
msg->A_TA = impl->phys_sa;
msg->A_SA = impl->phys_ta;
+ msg->A_TA_Type = UDS_A_TA_TYPE_PHYSICAL;
} else {
- ret = tp_recv_once(impl->func_fd, msg, true);
+ ret = tp_recv_once(impl->func_fd, impl->recv_buf, sizeof(impl->recv_buf));
if (ret > 0) {
msg->A_TA = impl->func_sa;
msg->A_SA = impl->func_ta;
+ msg->A_TA_Type = UDS_A_TA_TYPE_FUNCTIONAL;
}
}
if (ret > 0) {
fprintf(stdout, "%06d, %s recv, 0x%03x (%s), ", UDSMillis(), impl->tag, msg->A_TA,
msg->A_TA_Type == UDS_A_TA_TYPE_PHYSICAL ? "phys" : "func");
- for (unsigned i = 0; i < msg->A_Length; i++) {
- fprintf(stdout, "%02x ", msg->A_Data[i]);
+ for (unsigned i = 0; i < ret; i++) {
+ fprintf(stdout, "%02x ", impl->recv_buf[i]);
}
fprintf(stdout, "\n");
fflush(stdout); // flush every time in case of crash
// UDS_DBG_PRINT("<<< ");
// UDS_DBG_PRINTHEX(, ret);
}
+
+ done:
+ if (ret > 0) {
+ impl->recv_len = ret;
+ }
+ if (info) {
+ *info = *msg;
+ }
return ret;
}
-static ssize_t tp_send(UDSTpHandle_t *hdl, UDSSDU_t *msg) {
+static void tp_ack_recv(UDSTpHandle_t *hdl) {
+ assert(hdl);
+ UDSTpIsoTpSock_t *impl = (UDSTpIsoTpSock_t *)hdl;
+ impl->recv_len = 0;
+}
+
+static ssize_t tp_send(UDSTpHandle_t *hdl, uint8_t *buf, ssize_t len, UDSSDU_t *info) {
assert(hdl);
ssize_t ret = -1;
UDSTpIsoTpSock_t *impl = (UDSTpIsoTpSock_t *)hdl;
int fd;
- switch (msg->A_TA_Type) {
- case kTpAddrTypePhysical:
+ const UDSTpAddr_t ta_type = info ? info->A_TA : UDS_A_TA_TYPE_PHYSICAL;
+
+ if (UDS_A_TA_TYPE_PHYSICAL == ta_type) {
fd = impl->phys_fd;
- break;
- case kTpAddrTypeFunctional:
+ } else if (UDS_A_TA_TYPE_FUNCTIONAL == ta_type) {
fd = impl->func_fd;
- break;
- default:
+ } else {
ret = -4;
goto done;
}
- ret = write(fd, msg->A_Data, msg->A_Length);
+ ret = write(fd, buf, len);
if (ret < 0) {
perror("write");
}
done:
// UDS_DBG_PRINT(">>> ");
// UDS_DBG_PRINTHEX(buf, ret);
- fprintf(stdout, "%06d, %s sends, 0x%03x (%s), ", UDSMillis(), impl->tag, msg->A_TA,
- msg->A_TA_Type == UDS_A_TA_TYPE_PHYSICAL ? "phys" : "func");
- for (unsigned i = 0; i < msg->A_Length; i++) {
- fprintf(stdout, "%02x ", msg->A_Data[i]);
+
+ fprintf(stdout, "%06d, %s sends, (%s), ", UDSMillis(), impl->tag,
+ ta_type == UDS_A_TA_TYPE_PHYSICAL ? "phys" : "func");
+ for (unsigned i = 0; i < len; i++) {
+ fprintf(stdout, "%02x ", buf[i]);
}
fprintf(stdout, "\n");
fflush(stdout); // flush every time in case of crash
+
return ret;
}
@@ -147,9 +169,10 @@ static int LinuxSockBind(const char *if_name, uint32_t rxid, uint32_t txid, bool
UDSErr_t UDSTpIsoTpSockInitServer(UDSTpIsoTpSock_t *tp, const char *ifname, uint32_t source_addr,
uint32_t target_addr, uint32_t source_addr_func) {
assert(tp);
- tp->hdl.recv = tp_recv;
+ tp->hdl.peek = tp_peek;
tp->hdl.send = tp_send;
tp->hdl.poll = tp_poll;
+ tp->hdl.ack_recv = tp_ack_recv;
tp->phys_sa = source_addr;
tp->phys_ta = target_addr;
tp->func_sa = source_addr_func;
@@ -167,9 +190,10 @@ UDSErr_t UDSTpIsoTpSockInitServer(UDSTpIsoTpSock_t *tp, const char *ifname, uint
UDSErr_t UDSTpIsoTpSockInitClient(UDSTpIsoTpSock_t *tp, const char *ifname, uint32_t source_addr,
uint32_t target_addr, uint32_t target_addr_func) {
assert(tp);
- tp->hdl.recv = tp_recv;
+ tp->hdl.peek = tp_peek;
tp->hdl.send = tp_send;
tp->hdl.poll = tp_poll;
+ tp->hdl.ack_recv = tp_ack_recv;
tp->func_ta = target_addr_func;
tp->phys_ta = target_addr;
tp->phys_sa = source_addr;
@@ -180,7 +204,7 @@ UDSErr_t UDSTpIsoTpSockInitClient(UDSTpIsoTpSock_t *tp, const char *ifname, uint
return UDS_ERR;
}
printf("%s initialized phys link (fd %d) rx 0x%03x tx 0x%03x func link (fd %d) rx 0x%03x tx 0x%03x\n",
- tp->tag ? tp->tag : "client", tp->phys_fd, source_addr, target_addr, tp->func_fd, source_addr, target_addr_func);
+ strlen(tp->tag) ? tp->tag : "client", tp->phys_fd, source_addr, target_addr, tp->func_fd, source_addr, target_addr_func);
return UDS_OK;
}
diff --git a/tp/isotp_sock.h b/tp/isotp_sock.h
index 2fbd0fc..28b28e3 100644
--- a/tp/isotp_sock.h
+++ b/tp/isotp_sock.h
@@ -5,6 +5,10 @@
typedef struct {
UDSTpHandle_t hdl;
+ uint8_t recv_buf[UDS_BUFSIZE];
+ uint8_t send_buf[UDS_BUFSIZE];
+ size_t recv_len;
+ UDSSDU_t recv_info;
int phys_fd;
int func_fd;
uint32_t phys_sa, phys_ta;
diff --git a/tp/mock.c b/tp/mock.c
index 1079875..aa977a4 100644
--- a/tp/mock.c
+++ b/tp/mock.c
@@ -4,105 +4,135 @@
#include
#include
#include
+#include
-typedef struct TPMock {
- UDSTpHandle_t hdl;
- UDSSDU_t recv_q[1];
- unsigned recv_cnt;
- uint8_t recv_buf[1024];
- uint32_t recv_buf_size;
- char name[32];
-} TPMock_t;
-
-static TPMock_t TPs[8];
-static int TPCount = 0;
+
+#define MAX_NUM_TP 8
+#define NUM_MSGS 8
+static TPMock_t *TPs[8];
+static unsigned TPCount = 0;
static FILE *LogFile = NULL;
+static struct Msg {
+ uint8_t buf[UDS_BUFSIZE];
+ size_t len;
+ UDSSDU_t info;
+ uint32_t scheduled_tx_time;
+} msgs[NUM_MSGS];
+static unsigned MsgCount = 0;
-static bool RecvBufIsFull(TPMock_t *tp) {
- return tp->recv_cnt >= sizeof(tp->recv_q) / sizeof(tp->recv_q[0]);
-}
-static void LogMsg(const char *prefix, UDSSDU_t *msg) {
+static void LogMsg(const char *prefix, const uint8_t *buf, size_t len, UDSSDU_t *info) {
if (!LogFile) {
return;
}
- fprintf(LogFile, "%06d, %s sends, 0x%03x (%s), ", UDSMillis(), prefix, msg->A_TA,
- msg->A_TA_Type == UDS_A_TA_TYPE_PHYSICAL ? "phys" : "func");
- for (unsigned i = 0; i < msg->A_Length; i++) {
- fprintf(LogFile, "%02x ", msg->A_Data[i]);
+ fprintf(LogFile, "%06d, %s sends, 0x%03x (%s), ", UDSMillis(), prefix, info->A_TA,
+ info->A_TA_Type == UDS_A_TA_TYPE_PHYSICAL ? "phys" : "func");
+ for (unsigned i = 0; i < len; i++) {
+ fprintf(LogFile, "%02x ", buf[i]);
}
fprintf(LogFile, "\n");
fflush(LogFile); // flush every time in case of crash
}
-static ssize_t tp_recv(struct UDSTpHandle *hdl, UDSSDU_t *msg) {
+static void NetworkPoll() {
+ for (unsigned i = 0; i < MsgCount; i++) {
+ struct Msg *msg = &msgs[i];
+ if (UDSTimeAfter(UDSMillis(), msg->scheduled_tx_time)) {
+ for (unsigned j = 0; j < TPCount; j++) {
+ TPMock_t *tp = TPs[j];
+ if (tp->sa_phys == msg->info.A_TA || tp->sa_func == msg->info.A_TA) {
+ if (tp->recv_len > 0) {
+ fprintf(stderr, "TPMock: %s recv buffer is already full. Message dropped\n", tp->name);
+ continue;
+ }
+ memmove(tp->recv_buf, msg->buf, msg->len);
+ tp->recv_len = msg->len;
+ tp->recv_info = msg->info;
+ }
+ }
+ LogMsg("network", msg->buf, msg->len, &msg->info);
+ for (unsigned j = i + 1; j < MsgCount; j++) {
+ msgs[j - 1] = msgs[j];
+ }
+ MsgCount--;
+ i--;
+ }
+ }
+}
+
+static ssize_t tp_peek(struct UDSTpHandle *hdl,uint8_t **p_buf, UDSSDU_t *info) {
assert(hdl);
- assert(msg);
- assert(msg->A_Data);
+ assert(p_buf);
TPMock_t *tp = (TPMock_t *)hdl;
- if (tp->recv_cnt == 0) {
- return 0;
- } else {
- UDSSDU_t *in_msg = &tp->recv_q[0];
- if (in_msg->A_Length > msg->A_DataBufSize) {
- fprintf(stderr, "TPMock: %s recv buffer is too small\n", tp->name);
- return -1;
- }
- msg->A_Length = in_msg->A_Length;
- msg->A_Mtype = in_msg->A_Mtype;
- msg->A_SA = in_msg->A_SA;
- msg->A_TA = in_msg->A_TA;
- msg->A_TA_Type = in_msg->A_TA_Type;
- memmove((void *)msg->A_Data, in_msg->A_Data, in_msg->A_Length);
-
- for (unsigned i = 1; i < tp->recv_cnt; i++) {
- tp->recv_q[i - 1] = tp->recv_q[i];
- }
- tp->recv_cnt--;
- return msg->A_Length;
+ if (p_buf) {
+ *p_buf = tp->recv_buf;
}
+ if (info) {
+ *info = tp->recv_info;
+ }
+ return tp->recv_len;
}
-static ssize_t tp_send(struct UDSTpHandle *hdl, UDSSDU_t *msg) {
+static ssize_t tp_send(struct UDSTpHandle *hdl, uint8_t * buf, size_t len, UDSSDU_t *info) {
assert(hdl);
- assert(msg);
TPMock_t *tp = (TPMock_t *)hdl;
- for (unsigned i = 0; i < TPCount; i++) {
- TPMock_t *tp2 = &TPs[i];
- if (tp2 == tp) {
- continue; // don't send to self
- }
- if (RecvBufIsFull(tp2)) {
- fprintf(stderr, "TPMock: %s recv buffer is full\n", tp2->name);
- continue;
- }
- tp2->recv_q[tp2->recv_cnt++] = *msg;
+ if (MsgCount > NUM_MSGS) {
+ fprintf(stderr, "TPMock: too many messages in the queue\n");
+ return -1;
}
- LogMsg(tp->name, msg);
- return msg->A_Length;
+ struct Msg *m = &msgs[MsgCount++];
+ UDSTpAddr_t ta_type = info ? info->A_TA_Type : UDS_A_TA_TYPE_PHYSICAL;
+ m->len = len;
+ m->info.A_AE = info ? info->A_AE : 0;
+ if (UDS_A_TA_TYPE_PHYSICAL == ta_type) {
+ m->info.A_TA = tp->ta_phys;
+ m->info.A_SA = tp->sa_phys;
+ } else if (UDS_A_TA_TYPE_FUNCTIONAL == ta_type) {
+ m->info.A_TA = tp->ta_func;
+ m->info.A_SA = tp->sa_func;
+ } else {
+ fprintf(stderr, "TPMock: unknown TA type: %d\n", ta_type);
+ return -1;
+ }
+ m->scheduled_tx_time = UDSMillis() + tp->send_tx_delay_ms;
+ memmove(m->buf, buf, len);
+ LogMsg(tp->name, buf, len, &m->info);
+ return len;
}
static UDSTpStatus_t tp_poll(struct UDSTpHandle *hdl) {
- // todo: mock artificially long TX time
+ NetworkPoll();
+ // todo: make this status reflect TX time
return UDS_TP_IDLE;
}
+static ssize_t tp_get_send_buf(struct UDSTpHandle *hdl, uint8_t **p_buf) {
+ assert(hdl);
+ assert(p_buf);
+ TPMock_t *tp = (TPMock_t *)hdl;
+ *p_buf = tp->send_buf;
+ return sizeof(tp->send_buf);
+}
+
+static void tp_ack_recv(struct UDSTpHandle *hdl) {
+ assert(hdl);
+ TPMock_t *tp = (TPMock_t *)hdl;
+ tp->recv_len = 0;
+}
+
static_assert(offsetof(TPMock_t, hdl) == 0, "TPMock_t must not have any members before hdl");
-UDSTpHandle_t *TPMockCreate(const char *name) {
- TPMock_t *tp;
- if (TPCount >= sizeof(TPs) / sizeof(TPs[0])) {
+UDSTpHandle_t *TPMockCreate(const char *name, TPMockArgs_t *args) {
+ if (TPCount >= MAX_NUM_TP) {
return NULL;
}
- tp = &TPs[TPCount++];
+ TPMock_t *tp = malloc(sizeof(TPMock_t));
if (name) {
strncpy(tp->name, name, sizeof(tp->name));
} else {
snprintf(tp->name, sizeof(tp->name), "TPMock%d", TPCount);
}
- tp->hdl.recv = tp_recv;
- tp->hdl.send = tp_send;
- tp->hdl.poll = tp_poll;
+ TPMockAttach(tp, args);
return &tp->hdl;
}
@@ -125,14 +155,46 @@ void TPMockLogToFile(const char *filename) {
}
}
-void TPMockLogToStdout() {
+void TPMockLogToStdout(void) {
if (LogFile) {
return;
}
LogFile = stdout;
}
-void TPMockReset() {
+void TPMockReset(void) {
memset(TPs, 0, sizeof(TPs));
TPCount = 0;
+}
+
+
+void TPMockAttach(TPMock_t *tp, TPMockArgs_t *args) {
+ assert(tp);
+ assert(args);
+ assert(TPCount < MAX_NUM_TP);
+ TPs[TPCount++] = tp;
+ tp->hdl.peek = tp_peek;
+ tp->hdl.send = tp_send;
+ tp->hdl.poll = tp_poll;
+ tp->hdl.get_send_buf = tp_get_send_buf;
+ tp->hdl.ack_recv = tp_ack_recv;
+ tp->sa_func = args->sa_func;
+ tp->sa_phys = args->sa_phys;
+ tp->ta_func = args->ta_func;
+ tp->ta_phys = args->ta_phys;
+ tp->recv_len = 0;
+}
+
+void TPMockDetach(TPMock_t *tp) {
+ assert(tp);
+ for (unsigned i = 0; i < TPCount; i++) {
+ if (TPs[i] == tp) {
+ for (unsigned j = i + 1; j < TPCount; j++) {
+ TPs[j - 1] = TPs[j];
+ }
+ TPCount--;
+ return;
+ }
+ }
+ assert(false);
}
\ No newline at end of file
diff --git a/tp/mock.h b/tp/mock.h
index 675a0b2..6930701 100644
--- a/tp/mock.h
+++ b/tp/mock.h
@@ -7,16 +7,45 @@
#include "iso14229.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct TPMock {
+ UDSTpHandle_t hdl;
+ uint8_t recv_buf[UDS_BUFSIZE];
+ uint8_t send_buf[UDS_BUFSIZE];
+ size_t recv_len;
+ UDSSDU_t recv_info;
+ uint32_t sa_phys; // source address - physical messages are sent from this address
+ uint32_t ta_phys; // target address - physical messages are sent to this address
+ uint32_t sa_func; // source address - functional messages are sent from this address
+ uint32_t ta_func; // target address - functional messages are sent to this address
+ uint32_t send_tx_delay_ms; // simulated delay
+ uint32_t send_buf_size; // simulated size of the send buffer
+ char name[32]; // name for logging
+} TPMock_t;
+
+typedef struct {
+ uint32_t sa_phys; // source address - physical messages are sent from this address
+ uint32_t ta_phys; // target address - physical messages are sent to this address
+ uint32_t sa_func; // source address - functional messages are sent from this address
+ uint32_t ta_func; // target address - functional messages are sent to this address
+} TPMockArgs_t;
+
+#define TPMOCK_DEFAULT_CLIENT_ARGS &(TPMockArgs_t){.sa_phys=0x7E8, .ta_phys=0x7E0, .sa_func=UDS_TP_NOOP_ADDR, .ta_func=0x7DF}
+#define TPMOCK_DEFAULT_SERVER_ARGS &(TPMockArgs_t){.sa_phys=0x7E0, .ta_phys=0x7E8, .sa_func=0x7DF, .ta_func=UDS_TP_NOOP_ADDR}
+
/**
* @brief Create a mock transport. It is connected by default to a broadcast network of all other
* mock transports in the same process.
* @param name optional name of the transport (can be NULL)
* @return UDSTpHandle_t*
*/
-UDSTpHandle_t *TPMockCreate(const char *name);
+UDSTpHandle_t *TPMockCreate(const char *name, TPMockArgs_t *args);
-void TPMockSend(UDSTpHandle_t *tp, UDSSDU_t *msg);
-int TPMockRecv(UDSTpHandle_t *tp, UDSSDU_t *msg, uint32_t millis);
+void TPMockAttach(TPMock_t *tp, TPMockArgs_t *args);
+void TPMockDetach(TPMock_t *tp);
/**
* @brief write all messages to a file
@@ -24,9 +53,14 @@ int TPMockRecv(UDSTpHandle_t *tp, UDSSDU_t *msg, uint32_t millis);
* @param filename log file name (will be overwritten)
*/
void TPMockLogToFile(const char *filename);
-void TPMockLogToStdout();
+void TPMockLogToStdout(void);
/**
* @brief clear all transports and close the log file
*/
void TPMockReset(void);
+
+#ifdef __cplusplus
+}
+#endif
+
From 96b74c28ccfdc986812301815a5936d39b4010d1 Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Mon, 20 Nov 2023 01:12:04 -0700
Subject: [PATCH 10/56] refine transport implementations
---
.bazelrc | 3 +-
WORKSPACE | 18 +-
iso14229.c | 7 +-
iso14229.h | 4 +-
test/BUILD | 25 +-
test/README.md | 13 +-
test/cmocka.BUILD | 17 ++
test/env.c | 235 +++++++++---------
test/env.h | 27 +-
test/test.h | 29 +--
test/test_client_0x11_ECU_reset.c | 10 +-
test/test_client_0x31_RCRRP.c | 7 +-
test/test_client_p2.c | 6 +-
test/test_fuzz_server.c | 8 +-
...r_0x10_diag_sess_ctrl_functional_request.c | 3 +-
...10_diag_sess_ctrl_is_disabled_by_default.c | 3 +-
...server_0x11_no_send_recv_after_ECU_reset.c | 3 +-
test/test_server_0x22_RDBI.c | 3 +-
.../test_server_0x23_read_memory_by_address.c | 20 +-
test/test_server_0x27_security_access.c | 5 +-
test/test_server_0x31_RCRRP.c | 3 +-
test/test_server_0x34.c | 6 +-
...t_server_0x3E_suppress_positive_response.c | 3 +-
...t_server_0x83_diagnostic_session_control.c | 3 +-
test/test_server_session_timeout.c | 2 -
test/test_tp_compliance.c | 115 +++++++++
test_iso14229.c | 8 +-
tp/BUILD | 5 +-
tp/isotp-c | 2 +-
tp/isotp_c_socketcan.c | 222 ++++++++++-------
tp/isotp_c_socketcan.h | 16 +-
tp/isotp_sock.c | 25 +-
tp/isotp_sock.h | 4 +-
tp/mock.c | 76 +++---
tp/mock.h | 6 +-
35 files changed, 568 insertions(+), 374 deletions(-)
create mode 100644 test/cmocka.BUILD
create mode 100644 test/test_tp_compliance.c
diff --git a/.bazelrc b/.bazelrc
index 9df87aa..dea6f18 100644
--- a/.bazelrc
+++ b/.bazelrc
@@ -19,6 +19,5 @@ test:ppc64 --run_under="qemu-ppc64 -L /usr/powerpc64-linux-gnu/ "
test:ppc64le --run_under="qemu-ppc64le -L /usr/powerpc64le-linux-gnu/ "
-test: --test_output=all
# parallel tests break on a single vcan interface
-test: --local_test_jobs=1
\ No newline at end of file
+test: --local_test_jobs=1 --test_output=all
\ No newline at end of file
diff --git a/WORKSPACE b/WORKSPACE
index 6d75c10..ba2836c 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -14,4 +14,20 @@ http_archive(
# When you first run this tool, it'll recommend a sha256 hash to put here with a message like: "DEBUG: Rule 'hedron_compile_commands' indicated that a canonical reproducible form can be obtained by modifying arguments sha256 = ..."
)
load("@hedron_compile_commands//:workspace_setup.bzl", "hedron_compile_commands_setup")
-hedron_compile_commands_setup()
\ No newline at end of file
+hedron_compile_commands_setup()
+
+http_archive(
+ name = "unity",
+ url = "https://github.com/ThrowTheSwitch/Unity/archive/refs/tags/v2.5.2.zip",
+ sha256 = "4598298723ecca1f242b8c540a253ae4ab591f6810cbde72f128961007683034",
+ strip_prefix = "Unity-2.5.2",
+ build_file = "//test:unity.BUILD",
+)
+
+http_archive(
+ name = "cmocka",
+ url = "https://cmocka.org/files/1.1/cmocka-1.1.7.tar.xz",
+ sha256 = "810570eb0b8d64804331f82b29ff47c790ce9cd6b163e98d47a4807047ecad82",
+ build_file = "//test:cmocka.BUILD",
+ strip_prefix = "cmocka-1.1.7",
+)
\ No newline at end of file
diff --git a/iso14229.c b/iso14229.c
index 923e0fd..623cfcb 100644
--- a/iso14229.c
+++ b/iso14229.c
@@ -91,20 +91,24 @@ enum UDSDiagnosticServiceId {
* @return ssize_t
*/
ssize_t UDSTpGetSendBuf(struct UDSTpHandle *hdl, uint8_t **buf) {
+ assert(hdl);
assert(hdl->get_send_buf);
return hdl->get_send_buf(hdl, buf);
}
ssize_t UDSTpSend(struct UDSTpHandle *hdl, const uint8_t *buf, ssize_t len, UDSSDU_t *info) {
+ assert(hdl);
assert(hdl->send);
return hdl->send(hdl, (uint8_t*)buf, len, info);
}
UDSTpStatus_t UDSTpPoll(struct UDSTpHandle *hdl) {
+ assert(hdl);
assert(hdl->poll);
return hdl->poll(hdl);
}
ssize_t UDSTpPeek(struct UDSTpHandle *hdl, uint8_t **buf, UDSSDU_t *info) {
+ assert(hdl);
assert(hdl->peek);
return hdl->peek(hdl, buf, info);
}
@@ -1059,7 +1063,7 @@ void UDSServerPoll(UDSServer_t *srv) {
if (ret < 0) {
UDSErr_t err = UDS_ERR_TPORT;
EmitEvent(srv, UDS_SRV_EVT_Err, &err);
- UDS_DBG_PRINT("UDSTpSend failed with %d\n", ret);
+ UDS_DBG_PRINT("UDSTpSend failed with %ld\n", ret);
}
if (srv->RCRRP) {
@@ -1295,7 +1299,6 @@ static void PollLowLevel(UDSClient_t *client) {
case kRequestStateAwaitResponse: {
UDSSDU_t info = {0};
ssize_t len = UDSTpPeek(client->tp, &client->recv_buf, &info);
- printf("peeked %ld bytes\n", len);
if (UDS_A_TA_TYPE_FUNCTIONAL == info.A_TA_Type) {
UDSTpAckRecv(client->tp);
diff --git a/iso14229.h b/iso14229.h
index 0e51af8..38e0dd4 100644
--- a/iso14229.h
+++ b/iso14229.h
@@ -282,7 +282,7 @@ typedef struct UDSTpHandle {
* @brief Send the data in the buffer buf
* @param hdl: pointer to transport handle
* @param buf: a pointer to the data to send (this may be the buffer returned by @ref get_send_buf)
- * @param info: pointer to SDU info (may be NULL)
+ * @param info: pointer to SDU info (may be NULL). If NULL, implementation should send with physical addressing
*/
ssize_t (*send)(struct UDSTpHandle *hdl, uint8_t *buf, size_t len, UDSSDU_t *info);
@@ -320,7 +320,7 @@ typedef struct UDSTpHandle {
ssize_t UDSTpGetSendBuf(UDSTpHandle_t *hdl, uint8_t **buf);
ssize_t UDSTpSend(UDSTpHandle_t *hdl, const uint8_t *buf, ssize_t len, UDSSDU_t *info);
UDSTpStatus_t UDSTpPoll(UDSTpHandle_t *hdl);
-ssize_t UDSTpRecv(UDSTpHandle_t *hdl, UDSSDU_t *info, uint8_t **buf);
+ssize_t UDSTpPeek(struct UDSTpHandle *hdl, uint8_t **buf, UDSSDU_t *info);
const uint8_t *UDSTpGetRecvBuf(UDSTpHandle_t *hdl, size_t *len);
size_t UDSTpGetRecvLen(UDSTpHandle_t *hdl);
void UDSTpAckRecv(UDSTpHandle_t *hdl);
diff --git a/test/BUILD b/test/BUILD
index 3b5b0aa..4de8862 100644
--- a/test/BUILD
+++ b/test/BUILD
@@ -7,29 +7,31 @@ cc_library(
"//:iso14229_srcs",
"//tp:srcs",
],
- deps = [
- # "//tp:mock",
- # "//tp:isotp_sock",
- # "//tp:isotp_c_socketcan",
- ],
+ deps = [ "@cmocka" ],
defines = [
"UDS_TP=UDS_TP_CUSTOM",
"UDS_CUSTOM_MILLIS",
"UDS_DBG_PRINT=printf",
- ]
+ ],
+ copts = [ "-g", ],
)
+
+# Generic unit tests
+# These should pass on all architectures and transports
[
cc_test(
name=src.split(".c")[0] ,
srcs=[src],
deps=[":env"],
size = "small",
- env={
- # "TP": "isotp_sock",
- # "TP": "isotp-c",
- "TP": "mock",
+ env = {
+ "UDS_TP_TYPE": "2",
},
+ copts = ["-g"],
+ tags = [
+ "exclusive",
+ ],
)
for src in [
"test_client_0x11_ECU_reset.c",
@@ -50,11 +52,10 @@ cc_library(
"test_server_0x3E_suppress_positive_response.c",
"test_server_0x83_diagnostic_session_control.c",
"test_server_session_timeout.c",
- "test_tp_mock.c",
+ "test_tp_compliance.c",
]
]
-
cc_test(
name = "test_fuzz_server",
srcs = [
diff --git a/test/README.md b/test/README.md
index e07aecf..e7fa3b6 100644
--- a/test/README.md
+++ b/test/README.md
@@ -47,4 +47,15 @@ If building fails with `/usr/bin/ld: cannot find -lstdc++: No such file or direc
```sh
sudo apt install libc++-15-dev libc++abi-15-dev
sudo ln -s /usr/lib/x86_64-linux-gnu/libstdc++.so /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30
-```
\ No newline at end of file
+```
+
+
+# Why?
+
+Why bazel?
+
+> It's the best way I know to rigidly define multiple toolchains and architectures
+
+Why cmocka?
+
+> It is c
\ No newline at end of file
diff --git a/test/cmocka.BUILD b/test/cmocka.BUILD
new file mode 100644
index 0000000..0d0fbc4
--- /dev/null
+++ b/test/cmocka.BUILD
@@ -0,0 +1,17 @@
+package(default_visibility = ["//visibility:public"])
+
+
+cc_library(
+ name = "cmocka",
+ srcs = [
+ "include/cmocka.h",
+ "include/cmocka_private.h",
+ "src/cmocka.c",
+ ],
+ copts = [
+ "-DHAVE_SIGNAL_H",
+ ],
+ includes = [
+ "include",
+ ],
+)
\ No newline at end of file
diff --git a/test/env.c b/test/env.c
index 7774cff..4b5e9c9 100644
--- a/test/env.c
+++ b/test/env.c
@@ -5,110 +5,66 @@
#include
#include
#include
+#include "tp/isotp_c_socketcan.h"
#include "tp/mock.h"
#include "tp/isotp_sock.h"
-// #include "tp/isotp_c_socketcan.h"
static UDSServer_t *registeredServer = NULL;
static UDSClient_t *registeredClient = NULL;
#define MAX_NUM_TP 8
static UDSTpHandle_t *registeredTps[MAX_NUM_TP];
static unsigned TPCount = 0;
-
static uint32_t TimeNowMillis = 0;
-typedef struct {
-
-} ENV_t;
-struct IntOpt {
- const char *name;
- int *val;
+static ENV_Opts_t opts = {
+ .tp_type = ENV_TP_TYPE_MOCK,
+ .ifname = "vcan0",
+ .srv_src_addr = 0x7E8,
+ .srv_target_addr = 0x7E0,
+ .srv_src_addr_func = 0x7DF,
+ .cli_src_addr = 0x7E0,
+ .cli_target_addr = 0x7E8,
+ .cli_tgt_addr_func = 0x7DF,
};
-enum {
- OPTS_TP_TYPE_MOCK,
- OPTS_TP_TYPE_ISOTP_SOCK,
- OPTS_TP_TYPE_ISOTPC,
-};
-
-typedef struct {
- int tp_type;
- char ifname[32];
- uint32_t srv_src_addr, srv_target_addr, srv_src_addr_func;
- uint32_t cli_src_addr, cli_target_addr, cli_tgt_addr_func;
-} Cfg_t;
+static const char *parse_env_var(const char *name, const char *default_val) {
+ const char *val = getenv(name);
+ if (val) {
+ return val;
+ }
+ return default_val;
+}
-static Cfg_t cfg;
+static const int parse_int_env_var(const char *name, const int default_val) {
+ const char *val = getenv(name);
+ if (val) {
+ return atoi(val);
+ }
+ return default_val;
+}
-// static struct IntOpt IntOpts[] = {
-// {"TP_TYPE", &opts.tp_type},
-// };
+static void ENV_ParseOpts() {
+ opts.ifname = parse_env_var("UDS_IFNAME", opts.ifname);
+ opts.tp_type = parse_int_env_var("UDS_TP_TYPE", opts.tp_type);
+ opts.srv_src_addr = parse_int_env_var("UDS_SRV_SRC_ADDR", opts.srv_src_addr);
+ opts.srv_target_addr = parse_int_env_var("UDS_SRV_TARGET_ADDR", opts.srv_target_addr);
+ opts.srv_src_addr_func = parse_int_env_var("UDS_SRV_SRC_ADDR_FUNC", opts.srv_src_addr_func);
+ opts.cli_src_addr = parse_int_env_var("UDS_CLI_SRC_ADDR", opts.cli_src_addr);
+ opts.cli_target_addr = parse_int_env_var("UDS_CLI_TARGET_ADDR", opts.cli_target_addr);
+ opts.cli_tgt_addr_func = parse_int_env_var("UDS_CLI_TGT_ADDR_FUNC", opts.cli_tgt_addr_func);
+}
void ENV_ServerInit(UDSServer_t *srv) {
- UDSTpHandle_t *tp = NULL;
- switch (cfg.tp_type) {
- case OPTS_TP_TYPE_MOCK:
- tp = TPMockCreate("server", TPMOCK_DEFAULT_SERVER_ARGS);
- break;
- case OPTS_TP_TYPE_ISOTP_SOCK: {
- UDSTpIsoTpSock_t *isotp = malloc(sizeof(UDSTpIsoTpSock_t));
- strcpy(isotp->tag, "server");
- assert(UDS_OK == UDSTpIsoTpSockInitServer(isotp, cfg.ifname,
- cfg.srv_src_addr, cfg.srv_target_addr,
- cfg.srv_src_addr_func));
- tp = (UDSTpHandle_t *)isotp;
- break;
- }
- case OPTS_TP_TYPE_ISOTPC: {
- // UDSTpISOTpC_t *isotp = malloc(sizeof(UDSTpISOTpC_t));
- // strcpy(isotp->tag, "server");
- // assert(UDS_OK == UDSTpISOTpCInitServer(isotp, srv, cfg.ifname,
- // cfg.srv_src_addr, cfg.srv_target_addr,
- // cfg.srv_src_addr_func));
- // tp = (UDSTpHandle_t *)isotp;
- break;
- }
- default:
- printf("unknown TP type: %d\n", cfg.tp_type);
- exit(1);
- }
-
+ ENV_ParseOpts();
UDSServerInit(srv);
- srv->tp = tp;
+ srv->tp = ENV_TpNew("server");
ENV_RegisterServer(srv);
}
void ENV_ClientInit(UDSClient_t *cli) {
- UDSTpHandle_t *tp = NULL;
- switch (cfg.tp_type) {
- case OPTS_TP_TYPE_MOCK:
- tp = TPMockCreate("client", TPMOCK_DEFAULT_CLIENT_ARGS);
- break;
- case OPTS_TP_TYPE_ISOTP_SOCK: {
- UDSTpIsoTpSock_t *isotp = malloc(sizeof(UDSTpIsoTpSock_t));
- strcpy(isotp->tag, "client");
- assert(UDS_OK == UDSTpIsoTpSockInitClient(isotp, cfg.ifname,
- cfg.cli_src_addr, cfg.cli_target_addr,
- cfg.cli_tgt_addr_func));
- tp = (UDSTpHandle_t *)isotp;
- break;
- }
- case OPTS_TP_TYPE_ISOTPC: {
- // UDSTpISOTpC_t *isotp = malloc(sizeof(UDSTpISOTpC_t));
- // strcpy(isotp->tag, "client");
- // assert(UDS_OK == UDSTpISOTpCInitClient(isotp, cli, cfg.ifname,
- // cfg.cli_src_addr, cfg.cli_target_addr,
- // cfg.cli_tgt_addr_func));
- // tp = (UDSTpHandle_t *)isotp;
- // break;
- }
- default:
- printf("unknown TP type: %d\n", cfg.tp_type);
- exit(1);
- }
-
+ ENV_ParseOpts();
UDSClientInit(cli);
- cli->tp = tp;
+ cli->tp = ENV_TpNew("client");
ENV_RegisterClient(cli);
}
@@ -125,7 +81,7 @@ void msleep(int ms) {
}
static bool IsNetworkedTransport(int tp_type) {
- return tp_type == OPTS_TP_TYPE_ISOTP_SOCK || tp_type == OPTS_TP_TYPE_ISOTPC;
+ return tp_type == ENV_TP_TYPE_ISOTP_SOCK || tp_type == ENV_TP_TYPE_ISOTPC;
}
void ENV_RunMillis(uint32_t millis) {
@@ -143,50 +99,72 @@ void ENV_RunMillis(uint32_t millis) {
TimeNowMillis++;
// uses vcan, needs delay
- if (IsNetworkedTransport(cfg.tp_type)) {
- usleep(10);
- // msleep(1);
+ if (IsNetworkedTransport(opts.tp_type)) {
+ // usleep(10);
+ msleep(1);
}
}
}
-struct opts {
- const char *arg;
-};
-
-
-void ENV_ParseOpts(int argc, char **argv) {
- snprintf(cfg.ifname, sizeof(cfg.ifname), "vcan0");
- cfg.srv_src_addr = 0x7E8;
- cfg.srv_target_addr = 0x7E0;
- cfg.srv_src_addr_func = 0x7DF;
- cfg.cli_src_addr = 0x7E0;
- cfg.cli_target_addr = 0x7E8;
- cfg.cli_tgt_addr_func = 0x7DF;
-
- const char *tp = getenv("TP");
- if (tp == NULL) {
- tp = "mock";
- }
- if (0 == strcasecmp(tp, "mock")) {
- cfg.tp_type = OPTS_TP_TYPE_MOCK;
- } else if (0 == strcasecmp(tp, "isotp_sock")) {
- cfg.tp_type = OPTS_TP_TYPE_ISOTP_SOCK;
- } else if (0 == strcasecmp(tp, "isotp-c")) {
- cfg.tp_type = OPTS_TP_TYPE_ISOTPC;
- } else {
- printf("unknown TP: %s\n", tp);
- exit(1);
- }
-}
-
-UDSTpHandle_t *ENV_GetMockTp(const char *name) {
+UDSTpHandle_t *ENV_TpNew(const char *name) {
+ ENV_ParseOpts();
UDSTpHandle_t *tp = NULL;
if (0 == strcasecmp(name, "server"))
- tp = TPMockCreate(name, TPMOCK_DEFAULT_SERVER_ARGS);
+ switch (opts.tp_type) {
+ case ENV_TP_TYPE_MOCK:
+ tp = TPMockNew("server", TPMOCK_DEFAULT_SERVER_ARGS);
+ break;
+ case ENV_TP_TYPE_ISOTP_SOCK: {
+ UDSTpIsoTpSock_t *isotp = malloc(sizeof(UDSTpIsoTpSock_t));
+ strcpy(isotp->tag, "server");
+ assert(UDS_OK == UDSTpIsoTpSockInitServer(isotp, opts.ifname,
+ opts.srv_src_addr, opts.srv_target_addr,
+ opts.srv_src_addr_func));
+ tp = (UDSTpHandle_t *)isotp;
+ break;
+ }
+ case ENV_TP_TYPE_ISOTPC: {
+ UDSTpISOTpC_t *isotp = malloc(sizeof(UDSTpISOTpC_t));
+ strcpy(isotp->tag, "server");
+
+ assert(UDS_OK == UDSTpISOTpCInit(isotp, opts.ifname,
+ opts.srv_src_addr, opts.srv_target_addr,
+ opts.srv_src_addr_func, 0));
+ tp = (UDSTpHandle_t *)isotp;
+ break;
+ }
+ default:
+ printf("unknown TP type: %d\n", opts.tp_type);
+ return NULL;
+ }
else if (0 == strcasecmp(name, "client")) {
- tp = TPMockCreate(name, TPMOCK_DEFAULT_CLIENT_ARGS);
+ switch (opts.tp_type) {
+ case ENV_TP_TYPE_MOCK:
+ tp = TPMockNew("client", TPMOCK_DEFAULT_CLIENT_ARGS);
+ break;
+ case ENV_TP_TYPE_ISOTP_SOCK: {
+ UDSTpIsoTpSock_t *isotp = malloc(sizeof(UDSTpIsoTpSock_t));
+ strcpy(isotp->tag, "client");
+ assert(UDS_OK == UDSTpIsoTpSockInitClient(isotp, opts.ifname,
+ opts.cli_src_addr, opts.cli_target_addr,
+ opts.cli_tgt_addr_func));
+ tp = (UDSTpHandle_t *)isotp;
+ break;
+ }
+ case ENV_TP_TYPE_ISOTPC: {
+ UDSTpISOTpC_t *isotp = malloc(sizeof(UDSTpISOTpC_t));
+ strcpy(isotp->tag, "client");
+ assert(UDS_OK == UDSTpISOTpCInit(isotp, opts.ifname,
+ opts.cli_src_addr, opts.cli_target_addr, 0,
+ opts.cli_tgt_addr_func));
+ tp = (UDSTpHandle_t *)isotp;
+ break;
+ }
+ default:
+ printf("unknown TP type: %d\n", opts.tp_type);
+ return NULL;
+ }
}
else {
printf("unknown mock tp: %s\n", name);
@@ -194,4 +172,21 @@ UDSTpHandle_t *ENV_GetMockTp(const char *name) {
}
registeredTps[TPCount++] = tp;
return tp;
-}
\ No newline at end of file
+}
+
+void ENV_TpFree(UDSTpHandle_t *tp) {
+ switch (opts.tp_type) {
+ case ENV_TP_TYPE_MOCK:
+ TPMockFree(tp);
+ break;
+ case ENV_TP_TYPE_ISOTP_SOCK:
+ UDSTpIsoTpSockDeinit((UDSTpIsoTpSock_t *)tp);
+ break;
+ case ENV_TP_TYPE_ISOTPC:
+ UDSTpISOTpCDeinit((UDSTpISOTpC_t *)tp);
+ free(tp);
+ break;
+ }
+}
+
+const ENV_Opts_t *ENV_GetOpts() { return &opts; }
\ No newline at end of file
diff --git a/test/env.h b/test/env.h
index 2c6ccd6..9112002 100644
--- a/test/env.h
+++ b/test/env.h
@@ -6,11 +6,26 @@
#include
#include
+enum ENV_TpType {
+ ENV_TP_TYPE_MOCK, // tp/mock.h
+ ENV_TP_TYPE_ISOTP_SOCK, // tp/isotp_sock.h
+ ENV_TP_TYPE_ISOTPC, // tp/isotp_c_socketcan.h
+};
+
+/**
+ * @brief Environment options
+ */
+typedef struct {
+ enum ENV_TpType tp_type; // transport type
+ const char *ifname; // CAN interface name used for isotp_sock and socketcan
+ uint32_t srv_src_addr, srv_target_addr, srv_src_addr_func;
+ uint32_t cli_src_addr, cli_target_addr, cli_tgt_addr_func;
+} ENV_Opts_t;
+
void ENV_ServerInit(UDSServer_t *srv);
void ENV_ClientInit(UDSClient_t *client);
#define ENV_SERVER_INIT(srv) \
- ENV_ParseOpts(0, NULL); \
ENV_ServerInit(&srv); \
TPMockLogToStdout();
@@ -18,19 +33,15 @@ void ENV_ClientInit(UDSClient_t *client);
ENV_ClientInit(&client); \
TPMockLogToStdout();
-#define ENV_SESS_INIT(sess) \
-
-// ENV_SessInit(&sess, #sess); \
-// TPMockLogToStdout();
-
/**
* @brief return a transport configured as client
* @return UDSTpHandle_t*
*/
-UDSTpHandle_t *ENV_GetMockTp(const char *name);
+UDSTpHandle_t *ENV_TpNew(const char *name);
+void ENV_TpFree(UDSTpHandle_t *tp);
void ENV_RegisterServer(UDSServer_t *server);
void ENV_RegisterClient(UDSClient_t *client);
void ENV_RunMillis(uint32_t millis);
-void ENV_ParseOpts(int argc, char **argv);
+const ENV_Opts_t *ENV_GetOpts();
#endif
diff --git a/test/test.h b/test/test.h
index eb84a8a..1d1fbf2 100644
--- a/test/test.h
+++ b/test/test.h
@@ -4,9 +4,11 @@
#include
#include
#include
+#include
#include "iso14229.h"
#include "test/env.h"
#include "tp/mock.h"
+#include
#define _TEST_INT_COND(a, b, cond) \
{ \
@@ -55,33 +57,6 @@
} \
}
-// expect a server response within a timeout
-#define EXPECT_RESPONSE_WITHIN_MILLIS(d1, timeout_ms) \
- { \
- uint32_t deadline = UDSMillis() + timeout_ms + 1; \
- uint8_t buf[UDS_BUFSIZE]; \
- UDSSDU_t msg = { \
- .A_DataBufSize = sizeof(buf), \
- .A_Data = buf, \
- }; \
- while (0 == UDSTpRecv(mock_tp, &msg)) { \
- TEST_INT_LE(UDSMillis(), deadline); \
- ENV_RunMillis(1); \
- } \
- TEST_INT_EQUAL(msg.A_Length, sizeof(d1)); \
- TEST_MEMORY_EQUAL(msg.A_Data, d1, sizeof(d1)); \
- }
-
-#define EXPECT_RECV_WITHIN_MILLIS(tp, msg, timeout_ms) \
- { \
- \
- uint32_t deadline = UDSMillis() + timeout_ms + 1; \
- while (0 == UDSTpRecv(tp, msg)) { \
- TEST_INT_LE(UDSMillis(), deadline); \
- ENV_RunMillis(1); \
- } \
- }
-
#define EXPECT_OK(stmt) \
{ \
int _ret = stmt; \
diff --git a/test/test_client_0x11_ECU_reset.c b/test/test_client_0x11_ECU_reset.c
index 99890f3..06d1814 100644
--- a/test/test_client_0x11_ECU_reset.c
+++ b/test/test_client_0x11_ECU_reset.c
@@ -1,4 +1,5 @@
#include "test/test.h"
+#include
int main() {
UDSClient_t client;
@@ -34,21 +35,24 @@ int main() {
for (size_t i = 0; i < sizeof(p) / sizeof(p[0]); i++) {
ENV_CLIENT_INIT(client);
- UDSTpHandle_t *mock_srv = ENV_GetMockTp("server");
+ UDSTpHandle_t *srv = ENV_TpNew("server");
printf("test %ld: %s\n", i, p[i].tag);
// when the client sends a ECU reset request with these options
client.options = p[i].options;
UDSSendECUReset(&client, kHardReset);
+ printf("srv == NULL? : %d\n", srv == NULL);
+ fflush(stdout);
// and the server responds with this message
- UDSTpSend(mock_srv, p[i].resp, p[i].resp_len, NULL);
+ UDSTpSend(srv, p[i].resp, p[i].resp_len, NULL);
// then the client should receive a response with this error code
ENV_RunMillis(50);
TEST_INT_EQUAL(client.state, kRequestStateIdle);
TEST_INT_EQUAL(client.err, p[i].expected_err);
// assert(client.err == p[i].expected_err);
- TPMockReset();
+ ENV_TpFree(srv);
+ ENV_TpFree(client.tp);
}
}
\ No newline at end of file
diff --git a/test/test_client_0x31_RCRRP.c b/test/test_client_0x31_RCRRP.c
index 533a264..d8c5343 100644
--- a/test/test_client_0x31_RCRRP.c
+++ b/test/test_client_0x31_RCRRP.c
@@ -2,8 +2,7 @@
int main() {
UDSClient_t client;
- UDSTpHandle_t *mock_srv = ENV_GetMockTp("server");
- ENV_SESS_INIT(sess)
+ UDSTpHandle_t *mock_srv = ENV_TpNew("server");
{ // Case 1: RCRRP Timeout
ENV_CLIENT_INIT(client);
@@ -23,6 +22,8 @@ int main() {
ENV_RunMillis(UDS_CLIENT_DEFAULT_P2_STAR_MS + 10);
TEST_INT_EQUAL(kRequestStateIdle, client.state)
TEST_INT_EQUAL(client.err, UDS_ERR_TIMEOUT);
+
+ UDSTpAckRecv(mock_srv);
}
{ // Case 2: Positive Response Received
@@ -49,5 +50,7 @@ int main() {
// the client should return to the idle state with no error
TEST_INT_EQUAL(kRequestStateIdle, client.state)
TEST_INT_EQUAL(client.err, UDS_OK);
+
+ UDSTpAckRecv(mock_srv);
}
}
\ No newline at end of file
diff --git a/test/test_client_p2.c b/test/test_client_p2.c
index d5b798b..c45d1a9 100644
--- a/test/test_client_p2.c
+++ b/test/test_client_p2.c
@@ -3,7 +3,7 @@
int main() {
UDSClient_t client;
- UDSTpHandle_t *tp = ENV_GetMockTp("server");
+ UDSTpHandle_t *tp = ENV_TpNew("server");
{ // Case 1: P2 not exceeded
ENV_CLIENT_INIT(client);
@@ -18,6 +18,8 @@ int main() {
// after p2 ms has elapsed, the client should have a timeout error
TEST_INT_EQUAL(UDS_OK, client.err);
+
+ UDSTpAckRecv(tp);
}
{ // Case 2: P2 exceeded
ENV_CLIENT_INIT(client);
@@ -31,5 +33,7 @@ int main() {
ENV_RunMillis(20);
TEST_INT_EQUAL(UDS_ERR_TIMEOUT, client.err);
+
+ UDSTpAckRecv(tp);
}
}
\ No newline at end of file
diff --git a/test/test_fuzz_server.c b/test/test_fuzz_server.c
index 4f65298..e6e1f4f 100644
--- a/test/test_fuzz_server.c
+++ b/test/test_fuzz_server.c
@@ -37,13 +37,13 @@ static UDSTpHandle_t *mock_client = NULL;
void DoInitialization() {
UDSServerConfig_t cfg = {
.fn = fn,
- .tp = TPMockCreate("server"),
+ .tp = TPMockNew("server"),
.target_addr = 0x7E0,
.source_addr = 0x7E8,
.source_addr_func = 0x7DF,
};
UDSServerInit(&srv, &cfg);
- mock_client = TPMockCreate("client");
+ mock_client = TPMockNew("client");
}
@@ -55,8 +55,8 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
}
memset(&fuzz, 0, sizeof(fuzz));
memmove(&fuzz, data, size);
- srv.tp = TPMockCreate("server");
- mock_client = TPMockCreate("client");
+ srv.tp = TPMockNew("server");
+ mock_client = TPMockNew("client");
UDSSDU_t msg = {
.A_Mtype = UDS_A_MTYPE_DIAG,
diff --git a/test/test_server_0x10_diag_sess_ctrl_functional_request.c b/test/test_server_0x10_diag_sess_ctrl_functional_request.c
index 9906e2a..ae41a09 100644
--- a/test/test_server_0x10_diag_sess_ctrl_functional_request.c
+++ b/test/test_server_0x10_diag_sess_ctrl_functional_request.c
@@ -1,10 +1,9 @@
#include "test/test.h"
int main() {
- UDSTpHandle_t *mock_client = ENV_GetMockTp("client");
+ UDSTpHandle_t *mock_client = ENV_TpNew("client");
UDSServer_t srv;
ENV_SERVER_INIT(srv);
- ENV_SESS_INIT(mock_client);
// When server is sent a diagnostic session control request
const uint8_t REQ[] = {0x10, 0x02};
diff --git a/test/test_server_0x10_diag_sess_ctrl_is_disabled_by_default.c b/test/test_server_0x10_diag_sess_ctrl_is_disabled_by_default.c
index 7b6da92..d926665 100644
--- a/test/test_server_0x10_diag_sess_ctrl_is_disabled_by_default.c
+++ b/test/test_server_0x10_diag_sess_ctrl_is_disabled_by_default.c
@@ -1,10 +1,9 @@
#include "test/test.h"
int main() {
- UDSTpHandle_t *mock_client = ENV_GetMockTp("client");
+ UDSTpHandle_t *mock_client = ENV_TpNew("client");
UDSServer_t srv;
ENV_SERVER_INIT(srv);
- ENV_SESS_INIT(mock_client);
// When server is sent a diagnostic session control request
const uint8_t REQ[] = {0x10, 0x02};
diff --git a/test/test_server_0x11_no_send_recv_after_ECU_reset.c b/test/test_server_0x11_no_send_recv_after_ECU_reset.c
index 54476bc..9b05a36 100644
--- a/test/test_server_0x11_no_send_recv_after_ECU_reset.c
+++ b/test/test_server_0x11_no_send_recv_after_ECU_reset.c
@@ -14,10 +14,9 @@ uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
}
int main() {
- UDSTpHandle_t *mock_client = ENV_GetMockTp("client");
+ UDSTpHandle_t *mock_client = ENV_TpNew("client");
UDSServer_t srv;
ENV_SERVER_INIT(srv);
- ENV_SESS_INIT(mock_client);
srv.fn = fn;
const uint8_t REQ[] = {0x11, 0x01};
diff --git a/test/test_server_0x22_RDBI.c b/test/test_server_0x22_RDBI.c
index dc14e26..ba9beb6 100644
--- a/test/test_server_0x22_RDBI.c
+++ b/test/test_server_0x22_RDBI.c
@@ -24,11 +24,10 @@ uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
}
int main() {
- UDSTpHandle_t *mock_client = ENV_GetMockTp("client");
+ UDSTpHandle_t *mock_client = ENV_TpNew("client");
UDSServer_t srv;
ENV_SERVER_INIT(srv);
srv.fn = fn;
- ENV_SESS_INIT(mock_client);
{ // 11.2.5.2 Example #1 read single dataIdentifier 0xF190
uint8_t REQ[] = {0x22, 0xF1, 0x90};
UDSTpSend(mock_client, REQ, sizeof(REQ), NULL);
diff --git a/test/test_server_0x23_read_memory_by_address.c b/test/test_server_0x23_read_memory_by_address.c
index a8adf44..0cb7402 100644
--- a/test/test_server_0x23_read_memory_by_address.c
+++ b/test/test_server_0x23_read_memory_by_address.c
@@ -1,3 +1,4 @@
+#include "iso14229.h"
#include "test/test.h"
uint8_t FakeData[259];
@@ -11,11 +12,10 @@ uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
}
int main() {
- UDSTpHandle_t *mock_client = ENV_GetMockTp("client");
+ UDSTpHandle_t *client_tp = ENV_TpNew("client");
UDSServer_t srv;
ENV_SERVER_INIT(srv);
srv.fn = fn;
- ENV_SESS_INIT(mock_client);
// Prepare fake data
for (int i = 0; i < sizeof(FakeData); i++) {
@@ -40,11 +40,17 @@ int main() {
0x01, // memorySize byte #1 (MSB)
0x03, // memorySize byte #2 (LSB)
};
- UDSTpSend(mock_client, REQ, sizeof(REQ), NULL);
-
- // the server should respond with a positive response within p2 ms
- EXPECT_IN_APPROX_MS(UDSTpGetRecvLen(mock_client) > 0, srv.p2_ms);
- TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(mock_client, NULL), EXPECTED_RESP, sizeof(EXPECTED_RESP));
+ UDSTpSend(client_tp, REQ, sizeof(REQ), NULL);
+
+ // the client transport should receive a positive response within client_p2 ms
+ // EXPECT_WITHIN_MS(UDSTpGetRecvLen(client_tp) > 0, UDS_CLIENT_DEFAULT_P2_MS)
+ uint32_t deadline = UDSMillis() + UDS_CLIENT_DEFAULT_P2_MS + 1;
+ while (!(UDSTpGetRecvLen(client_tp) > 0)) {
+ printf("UDSTpGetRecvLen(client_tp) = %ld\n", UDSTpGetRecvLen(client_tp));
+ TEST_INT_LE(UDSMillis(), deadline);
+ ENV_RunMillis(1);
+ }
+ TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(client_tp, NULL), EXPECTED_RESP, sizeof(EXPECTED_RESP));
}
// TODO: Tables 202-205
\ No newline at end of file
diff --git a/test/test_server_0x27_security_access.c b/test/test_server_0x27_security_access.c
index 1ea1c21..f53cfb0 100644
--- a/test/test_server_0x27_security_access.c
+++ b/test/test_server_0x27_security_access.c
@@ -26,12 +26,11 @@ uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
}
int main() {
- UDSTpHandle_t *mock_client = ENV_GetMockTp("client");
- // UDSTpHandle_t *mock_client = ENV_GetMockTp("client");
+ UDSTpHandle_t *mock_client = ENV_TpNew("client");
+ // UDSTpHandle_t *mock_client = ENV_TpNew("client");
UDSServer_t srv;
ENV_SERVER_INIT(srv);
srv.fn = fn;
- ENV_SESS_INIT(mock_client);
// the server security level after initialization should be 0
TEST_INT_EQUAL(srv.securityLevel, 0);
diff --git a/test/test_server_0x31_RCRRP.c b/test/test_server_0x31_RCRRP.c
index 521180c..e1c60c6 100644
--- a/test/test_server_0x31_RCRRP.c
+++ b/test/test_server_0x31_RCRRP.c
@@ -7,11 +7,10 @@ static uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) { retu
// ISO-14229-1 2013 Table A.1 Byte Value 0x78: requestCorrectlyReceived-ResponsePending
// "This NRC is in general supported by each diagnostic service".
int main() {
- UDSTpHandle_t *mock_client = ENV_GetMockTp("client");
+ UDSTpHandle_t *mock_client = ENV_TpNew("client");
UDSServer_t srv;
ENV_SERVER_INIT(srv);
srv.fn = fn;
- ENV_SESS_INIT(mock_client);
// When a server handler func initially returns RRCRP
resp = kRequestCorrectlyReceived_ResponsePending;
diff --git a/test/test_server_0x34.c b/test/test_server_0x34.c
index 043b2d1..67e6b85 100644
--- a/test/test_server_0x34.c
+++ b/test/test_server_0x34.c
@@ -13,10 +13,9 @@ uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
int main() {
{ // case 0: No handler
- UDSTpHandle_t *mock_client = ENV_GetMockTp("client");
+ UDSTpHandle_t *mock_client = ENV_TpNew("client");
UDSServer_t srv;
ENV_SERVER_INIT(srv);
- ENV_SESS_INIT(mock_client);
// when no handler function is installed, sending this request to the server
uint8_t REQ[] = {0x34, 0x11, 0x33, 0x60, 0x20, 0x00, 0x00, 0xFF, 0xFF};
@@ -30,10 +29,9 @@ int main() {
}
{ // case 1: handler installed
- UDSTpHandle_t *mock_client = ENV_GetMockTp("client");
+ UDSTpHandle_t *mock_client = ENV_TpNew("client");
UDSServer_t srv;
ENV_SERVER_INIT(srv);
- ENV_SESS_INIT(mock_client);
// when a handler is installed that implements UDS-1:2013 Table 415
srv.fn = fn;
diff --git a/test/test_server_0x3E_suppress_positive_response.c b/test/test_server_0x3E_suppress_positive_response.c
index 8e52f5b..ab50910 100644
--- a/test/test_server_0x3E_suppress_positive_response.c
+++ b/test/test_server_0x3E_suppress_positive_response.c
@@ -5,11 +5,10 @@ static uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
}
int main() {
- UDSTpHandle_t *mock_client = ENV_GetMockTp("client");
+ UDSTpHandle_t *mock_client = ENV_TpNew("client");
UDSServer_t srv;
ENV_SERVER_INIT(srv);
srv.fn = fn;
- ENV_SESS_INIT(mock_client);
// when the suppressPositiveResponse bit is set
const uint8_t REQ[] = {0x3E, 0x80};
diff --git a/test/test_server_0x83_diagnostic_session_control.c b/test/test_server_0x83_diagnostic_session_control.c
index 858f656..7a6ae72 100644
--- a/test/test_server_0x83_diagnostic_session_control.c
+++ b/test/test_server_0x83_diagnostic_session_control.c
@@ -5,11 +5,10 @@ static uint8_t ReturnPositiveResponse(UDSServer_t *srv, UDSServerEvent_t ev, con
}
int main() {
- UDSTpHandle_t *mock_client = ENV_GetMockTp("client");
+ UDSTpHandle_t *mock_client = ENV_TpNew("client");
UDSServer_t srv;
ENV_SERVER_INIT(srv);
srv.fn = ReturnPositiveResponse;
- ENV_SESS_INIT(mock_client);
// the server sessionType after initialization should be kDefaultSession.
TEST_INT_EQUAL(srv.sessionType, kDefaultSession);
diff --git a/test/test_server_session_timeout.c b/test/test_server_session_timeout.c
index ab59505..38831c3 100644
--- a/test/test_server_session_timeout.c
+++ b/test/test_server_session_timeout.c
@@ -9,7 +9,6 @@ uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
}
int main() {
- UDSTpHandle_t *mock_client = ENV_GetMockTp("client");
UDSServer_t srv;
struct {
@@ -24,7 +23,6 @@ int main() {
};
for (unsigned i = 0; i < sizeof(p) / sizeof(p[0]); i++) {
- ENV_SESS_INIT(mock_client);
ENV_SERVER_INIT(srv);
srv.fn = p[i].fn;
srv.sessionType = p[i].sessType;
diff --git a/test/test_tp_compliance.c b/test/test_tp_compliance.c
new file mode 100644
index 0000000..47d332a
--- /dev/null
+++ b/test/test_tp_compliance.c
@@ -0,0 +1,115 @@
+#include "test/env.h"
+#include "test/test.h"
+
+UDSTpHandle_t *srv = NULL;
+UDSTpHandle_t *client = NULL;
+
+static bool IsISOTP() {
+ int tp_type = ENV_GetOpts()->tp_type;
+ return (ENV_TP_TYPE_ISOTP_SOCK == tp_type) || (ENV_TP_TYPE_ISOTPC == tp_type);
+}
+
+int setup(void **state) {
+ srv = ENV_TpNew("server");
+ client = ENV_TpNew("client");
+ TPMockLogToStdout();
+ return 0;
+}
+
+int teardown(void **state) {
+ ENV_TpFree(srv);
+ ENV_TpFree(client);
+ return 0;
+}
+
+void TestSendRecv(void **state) {
+ const uint8_t MSG[] = {0x10, 0x02};
+ UDSTpSend(client, MSG, sizeof(MSG), NULL);
+ EXPECT_IN_APPROX_MS(UDSTpGetRecvLen(srv) == sizeof(MSG), 1);
+ assert_memory_equal(UDSTpGetRecvBuf(srv, NULL), MSG, sizeof(MSG));
+}
+
+
+void TestSendRecvFunctional(void **state) {
+ const uint8_t MSG[] = {0x10, 0x02};
+ UDSSDU_t info = {0};
+ uint8_t *buf = NULL;
+
+ // When a small functional request is sent
+ UDSTpSend(client, MSG, sizeof(MSG), &(UDSSDU_t){
+ .A_TA_Type = UDS_A_TA_TYPE_FUNCTIONAL
+ });
+
+ // the server should receive it quickly
+ EXPECT_IN_APPROX_MS(UDSTpPeek(srv, &buf, &info) == sizeof(MSG), 1);
+
+ // it should be the same message
+ assert_memory_equal(buf, MSG, sizeof(MSG));
+
+ // and the server should know it's a functional request
+ assert_int_equal(info.A_TA_Type, UDS_A_TA_TYPE_FUNCTIONAL);
+}
+
+void TestISOTPSendLargestSingleFrame(void **state) {
+ if (!IsISOTP()) {
+ skip();
+ }
+ const uint8_t MSG[] = {1, 2, 3, 4, 5, 6, 7};
+ UDSSDU_t info = {0};
+ uint8_t *buf = NULL;
+
+ // When a functional request is sent
+ ssize_t ret = UDSTpSend(client, MSG, sizeof(MSG), &(UDSSDU_t){
+ .A_TA_Type = UDS_A_TA_TYPE_FUNCTIONAL
+ });
+
+ // the server should receive it quickly
+ EXPECT_IN_APPROX_MS(UDSTpPeek(srv, &buf, &info) == sizeof(MSG), 1);
+
+ // it should be the same message
+ assert_memory_equal(buf, MSG, sizeof(MSG));
+
+ // and the server should know it's a functional request
+ assert_int_equal(info.A_TA_Type, UDS_A_TA_TYPE_FUNCTIONAL);
+}
+
+void TestISOTPSendLargerThanSingleFrameFails(void **state) {
+ if (!IsISOTP()) {
+ skip();
+ }
+ const uint8_t MSG[] = {1, 2, 3, 4, 5, 6, 7, 8};
+ UDSSDU_t info = {0};
+ uint8_t *buf = NULL;
+
+ // When a small functional request is sent
+ ssize_t ret = UDSTpSend(client, MSG, sizeof(MSG), &(UDSSDU_t){
+ .A_TA_Type = UDS_A_TA_TYPE_FUNCTIONAL
+ });
+ assert_true(ret < 0);
+}
+
+void TestISOTPSendRecvMaxLen(void **state) {
+ if (!IsISOTP()) {
+ skip();
+ }
+ uint8_t MSG[4095] = {0};
+ MSG[0] = 0x10;
+ MSG[4094] = 0x02;
+
+ UDSTpSend(client, MSG, sizeof(MSG), NULL);
+ EXPECT_WITHIN_MS(UDSTpGetRecvLen(srv) == sizeof(MSG), 3000);
+ assert_memory_equal(UDSTpGetRecvBuf(srv, NULL), MSG, sizeof(MSG));
+}
+
+int main() {
+ const struct CMUnitTest tests[] = {
+ // cmocka_unit_test_setup_teardown(TestSendRecv, setup, teardown),
+ cmocka_unit_test_setup_teardown(TestSendRecvFunctional, setup, teardown),
+ cmocka_unit_test_setup_teardown(TestISOTPSendLargestSingleFrame, setup, teardown),
+ cmocka_unit_test_setup_teardown(TestISOTPSendLargerThanSingleFrameFails, setup, teardown),
+ cmocka_unit_test_setup_teardown(TestISOTPSendRecvMaxLen, setup, teardown),
+ };
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
+
+
diff --git a/test_iso14229.c b/test_iso14229.c
index 92320cd..7e942d2 100644
--- a/test_iso14229.c
+++ b/test_iso14229.c
@@ -89,21 +89,21 @@
ctx.func_name = __PRETTY_FUNCTION__; \
if (SERVER_ONLY == test_type) { \
UDSServerInit(&ctx.server, &(UDSServerConfig_t){ \
- .tp = TPMockCreate("server"), \
+ .tp = TPMockNew("server"), \
.source_addr = SERVER_SOURCE_ADDR, \
.target_addr = SERVER_TARGET_ADDR, \
.source_addr_func = SERVER_SOURCE_ADDR_FUNC, \
}); \
- ctx.mock_tp = TPMockCreate("mock_client"); \
+ ctx.mock_tp = TPMockNew("mock_client"); \
} \
if (CLIENT_ONLY == test_type) { \
UDSClientInit(&ctx.client, &(UDSClientConfig_t){ \
- .tp = TPMockCreate("client"), \
+ .tp = TPMockNew("client"), \
.target_addr = CLIENT_TARGET_ADDR, \
.source_addr = CLIENT_SOURCE_ADDR, \
.target_addr_func = CLIENT_TARGET_ADDR_FUNC, \
}); \
- ctx.mock_tp = TPMockCreate("mock_server"); \
+ ctx.mock_tp = TPMockNew("mock_server"); \
} \
char logfilename[256] = {0}; \
snprintf(logfilename, sizeof(logfilename), "%s%s.log", ctx.func_name, param_str); \
diff --git a/tp/BUILD b/tp/BUILD
index 14f5316..66194f6 100644
--- a/tp/BUILD
+++ b/tp/BUILD
@@ -26,7 +26,6 @@ filegroup(
"isotp-c/isotp.h",
"isotp-c/isotp_config.h",
"isotp-c/isotp_defines.h",
- "isotp-c/isotp_user.h",
],
)
@@ -50,11 +49,13 @@ cc_library(
filegroup(
name="srcs",
- # srcs=glob(["*.c", "*.h"])
srcs = [
"mock.c",
"mock.h",
"isotp_sock.c",
"isotp_sock.h",
+ "isotp_c_socketcan.c",
+ "isotp_c_socketcan.h",
+ ":isotp_c_srcs",
]
)
diff --git a/tp/isotp-c b/tp/isotp-c
index 59dc573..2737949 160000
--- a/tp/isotp-c
+++ b/tp/isotp-c
@@ -1 +1 @@
-Subproject commit 59dc573a944a2661df6cda42c22edf5cfe53931b
+Subproject commit 27379492110d8ae1aaf7e4ca94cf65b31a2192b9
diff --git a/tp/isotp_c_socketcan.c b/tp/isotp_c_socketcan.c
index bf83714..a2e52f1 100644
--- a/tp/isotp_c_socketcan.c
+++ b/tp/isotp_c_socketcan.c
@@ -1,5 +1,6 @@
#include "tp/isotp_c_socketcan.h"
#include "iso14229.h"
+#include "tp/isotp-c/isotp_defines.h"
#include
#include
#include
@@ -10,49 +11,42 @@
#include
#include
-static int sockfd = 0;
-static bool HasSetup = false;
-
-
-
-static void SetupOnce() {
- if (HasSetup) {
- return;
- }
+static int SetupSocketCAN(const char *ifname) {
UDS_DBG_PRINT("setting up CAN\n");
struct sockaddr_can addr;
struct ifreq ifr;
+ int sockfd = -1;
+
if ((sockfd = socket(PF_CAN, SOCK_RAW | SOCK_NONBLOCK, CAN_RAW)) < 0) {
perror("socket");
- exit(-1);
- }
-
- // TODO: https://github.com/lishen2/isotp-c/issues/14
- int recv_own_msgs = 1;
- if (setsockopt(sockfd, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS, &recv_own_msgs, sizeof(recv_own_msgs)) < 0) {
- perror("setsockopt (CAN_RAW_LOOPBACK):");
- exit(-1);
+ goto done;
}
-
- strcpy(ifr.ifr_name, "vcan0");
+ strcpy(ifr.ifr_name, ifname);
ioctl(sockfd, SIOCGIFINDEX, &ifr);
memset(&addr, 0, sizeof(addr));
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("bind");
- exit(-1);
}
- HasSetup = true;
+
+ done:
+ return sockfd;
}
-uint32_t isotp_user_get_us() { return UDSMillis() * 1000; }
+uint32_t isotp_user_get_ms() { return UDSMillis(); }
-void isotp_user_debug(const char *message, ...) {}
+void isotp_user_debug(const char *message, ...) {
+ va_list args;
+ va_start(args, message);
+ vprintf(message, args);
+ va_end(args);
+}
-int isotp_user_send_can(const uint32_t arbitration_id, const uint8_t *data, const uint8_t size) {
- SetupOnce();
+int isotp_user_send_can(const uint32_t arbitration_id, const uint8_t *data, const uint8_t size, void *user_data) {
+ assert(user_data);
+ int sockfd = *(int *)user_data;
struct can_frame frame = {0};
frame.can_id = arbitration_id;
frame.can_dlc = size;
@@ -75,8 +69,9 @@ static void SocketCANRecv(UDSTpISOTpC_t *tp) {
assert(tp);
struct can_frame frame = {0};
int nbytes = 0;
+
for (;;) {
- nbytes = read(sockfd, &frame, sizeof(struct can_frame));
+ nbytes = read(tp->fd, &frame, sizeof(struct can_frame));
if (nbytes < 0) {
if (EAGAIN == errno || EWOULDBLOCK == errno) {
break;
@@ -91,8 +86,11 @@ static void SocketCANRecv(UDSTpISOTpC_t *tp) {
UDS_DBG_PRINTHEX(frame.data, frame.can_dlc);
isotp_on_can_message(&tp->phys_link, frame.data, frame.can_dlc);
} else if (frame.can_id == tp->func_sa) {
- UDS_DBG_PRINT("func recvd can\n");
- UDS_DBG_PRINTHEX(frame.data, frame.can_dlc);
+ if (ISOTP_RECEIVE_STATUS_IDLE != tp->phys_link.receive_status) {
+ UDS_DBG_PRINT("func frame received but cannot process because link is not idle");
+ return;
+ }
+ // TODO: reject if it's longer than a single frame
isotp_on_can_message(&tp->func_link, frame.data, frame.can_dlc);
}
}
@@ -104,56 +102,85 @@ static UDSTpStatus_t tp_poll(UDSTpHandle_t *hdl) {
UDSTpStatus_t status = 0;
UDSTpISOTpC_t *impl = (UDSTpISOTpC_t *)hdl;
SocketCANRecv(impl);
-
isotp_poll(&impl->phys_link);
- isotp_poll(&impl->func_link);
if (impl->phys_link.send_status == ISOTP_SEND_STATUS_INPROGRESS) {
status |= UDS_TP_SEND_IN_PROGRESS;
}
return status;
}
-static ssize_t tp_recv(UDSTpHandle_t *hdl, UDSSDU_t *msg) {
- assert(hdl);
+int peek_link(IsoTpLink *link, uint8_t *buf, size_t bufsize, bool functional) {
+ assert(link);
+ assert(buf);
int ret = -1;
- uint16_t size = 0;
- UDSTpISOTpC_t *impl = (UDSTpISOTpC_t *)hdl;
- struct {
- IsoTpLink *link;
- UDSTpAddr_t ta_type;
- } arr[] = {{&impl->phys_link, UDS_A_TA_TYPE_PHYSICAL}, {&impl->func_link, UDS_A_TA_TYPE_FUNCTIONAL}};
- for (size_t i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) {
- ret = isotp_receive(arr[i].link, msg->A_Data, msg->A_DataBufSize, &size);
- switch (ret) {
- case ISOTP_RET_OK:
- msg->A_TA_Type = arr[i].ta_type;
- ret = size;
+ switch (link->receive_status) {
+ case ISOTP_RECEIVE_STATUS_IDLE:
+ ret = 0;
goto done;
- case ISOTP_RET_NO_DATA:
+ case ISOTP_RECEIVE_STATUS_INPROGRESS:
ret = 0;
- continue;
- case ISOTP_RET_ERROR:
- ret = -1;
goto done;
+ case ISOTP_RECEIVE_STATUS_FULL:
+ ret = link->receive_size;
+ printf("The link is full. Copying %d bytes\n", ret);
+ memmove(buf, link->receive_buffer, link->receive_size);
+ break;
default:
- ret = -2;
+ UDS_DBG_PRINT("receive_status %d not implemented\n", link->receive_status);
+ ret = -1;
+ goto done;
+ }
+done:
+ return ret;
+}
+
+static ssize_t tp_peek(UDSTpHandle_t *hdl, uint8_t **p_buf, UDSSDU_t *info) {
+ assert(hdl);
+ assert(p_buf);
+ UDSTpISOTpC_t *tp= (UDSTpISOTpC_t *)hdl;
+ if (ISOTP_RECEIVE_STATUS_FULL == tp->phys_link.receive_status) { // recv not yet acked
+ *p_buf = tp->recv_buf;
+ return tp->phys_link.receive_size;
+ }
+ int ret = -1;
+ ret = peek_link(&tp->phys_link, tp->recv_buf, sizeof(tp->recv_buf), false);
+ UDS_A_TA_Type_t ta_type = UDS_A_TA_TYPE_PHYSICAL;
+ uint32_t ta = tp->phys_ta;
+ uint32_t sa = tp->phys_sa;
+
+ if (ret > 0) {
+ printf("just got %d bytes\n", ret);
+ ta = tp->phys_sa;
+ sa = tp->phys_ta;
+ ta_type = UDS_A_TA_TYPE_PHYSICAL;
+ *p_buf = tp->recv_buf;
+ goto done;
+ } else if (ret < 0) {
+ goto done;
+ } else {
+ ret = peek_link(&tp->func_link, tp->recv_buf, sizeof(tp->recv_buf), true);
+ if (ret > 0) {
+ printf("just got %d bytes on func link \n", ret);
+ ta = tp->func_sa;
+ sa = tp->func_ta;
+ ta_type = UDS_A_TA_TYPE_FUNCTIONAL;
+ *p_buf = tp->recv_buf;
+ goto done;
+ } else if (ret < 0) {
goto done;
}
}
done:
if (ret > 0) {
- msg->A_Length = size;
- if (UDS_A_TA_TYPE_PHYSICAL == msg->A_TA_Type ) {
- msg->A_TA = impl->phys_sa;
- msg->A_SA = impl->phys_ta;
- } else {
- msg->A_TA = impl->func_sa;
- msg->A_SA = impl->func_ta;
+ if (info) {
+ info->A_TA = ta;
+ info->A_SA = sa;
+ info->A_TA_Type = ta_type;
}
- fprintf(stdout, "%06d, %s recv, 0x%03x (%s), ", UDSMillis(), impl->tag, msg->A_TA,
- msg->A_TA_Type == UDS_A_TA_TYPE_PHYSICAL ? "phys" : "func");
- for (unsigned i = 0; i < msg->A_Length; i++) {
- fprintf(stdout, "%02x ", msg->A_Data[i]);
+ fprintf(stdout, "%06d, %s recv, 0x%03x (%s), ", UDSMillis(), tp->tag, ta,
+ ta_type == UDS_A_TA_TYPE_PHYSICAL ? "phys" : "func");
+ for (unsigned i = 0; i < ret; i++) {
+ fprintf(stdout, "%02x ", (*p_buf)[i]);
}
fprintf(stdout, "\n");
fflush(stdout); // flush every time in case of crash
@@ -162,27 +189,34 @@ static ssize_t tp_recv(UDSTpHandle_t *hdl, UDSSDU_t *msg) {
return ret;
}
-static ssize_t tp_send(UDSTpHandle_t *hdl, uint8_t *buf, ssize_t len, UDSSDU_t *info) {
+static ssize_t tp_send(UDSTpHandle_t *hdl, uint8_t *buf, size_t len, UDSSDU_t *info) {
assert(hdl);
ssize_t ret = -1;
- UDSTpISOTpC_t *impl = (UDSTpISOTpC_t *)hdl;
+ UDSTpISOTpC_t *tp = (UDSTpISOTpC_t *)hdl;
IsoTpLink *link = NULL;
- switch (msg->A_TA_Type) {
+ const UDSTpAddr_t ta_type = info ? info->A_TA_Type : UDS_A_TA_TYPE_PHYSICAL;
+ const uint32_t ta = ta_type == UDS_A_TA_TYPE_PHYSICAL ? tp->phys_ta : tp->func_ta;
+ switch (ta_type) {
case UDS_A_TA_TYPE_PHYSICAL:
- link = &impl->phys_link;
+ link = &tp->phys_link;
break;
case UDS_A_TA_TYPE_FUNCTIONAL:
- link = &impl->func_link;
+ link = &tp->func_link;
+ if (len > 7) {
+ UDS_DBG_PRINT("Cannot send more than 7 bytes via functional addressing\n");
+ ret = -3;
+ goto done;
+ }
break;
default:
ret = -4;
goto done;
}
- int send_status = isotp_send(link, msg->A_Data, msg->A_Length);
+ int send_status = isotp_send(link, buf, len);
switch (send_status) {
case ISOTP_RET_OK:
- ret = msg->A_Length;
+ ret = len;
goto done;
case ISOTP_RET_INPROGRESS:
case ISOTP_RET_OVERFLOW:
@@ -191,10 +225,10 @@ static ssize_t tp_send(UDSTpHandle_t *hdl, uint8_t *buf, ssize_t len, UDSSDU_t *
goto done;
}
done:
- fprintf(stdout, "%06d, %s sends, 0x%03x (%s), ", UDSMillis(), impl->tag, msg->A_TA,
- msg->A_TA_Type == UDS_A_TA_TYPE_PHYSICAL ? "phys" : "func");
- for (unsigned i = 0; i < msg->A_Length; i++) {
- fprintf(stdout, "%02x ", msg->A_Data[i]);
+ fprintf(stdout, "%06d, %s sends, 0x%03x (%s), ", UDSMillis(), tp->tag, ta,
+ ta_type == UDS_A_TA_TYPE_PHYSICAL ? "phys" : "func");
+ for (unsigned i = 0; i < len; i++) {
+ fprintf(stdout, "%02x ", buf[i]);
}
fprintf(stdout, "\n");
fflush(stdout); // flush every time in case of crash
@@ -202,41 +236,37 @@ static ssize_t tp_send(UDSTpHandle_t *hdl, uint8_t *buf, ssize_t len, UDSSDU_t *
return ret;
}
-
-UDSErr_t UDSTpISOTpCInitServer(UDSTpISOTpC_t *tp, UDSServer_t* srv, const char *ifname, uint32_t source_addr,
- uint32_t target_addr, uint32_t target_addr_func) {
- assert(tp);
- assert(ifname);
- tp->hdl.poll = tp_poll;
- tp->hdl.recv = tp_recv;
- tp->hdl.send = tp_send;
- tp->phys_sa = source_addr;
- tp->phys_ta = target_addr;
- tp->func_sa = source_addr;
- tp->func_ta = target_addr_func;
-
- isotp_init_link(&tp->phys_link, target_addr, srv->send_buf, sizeof(srv->send_buf),
- srv->recv_buf, sizeof(srv->recv_buf));
- isotp_init_link(&tp->func_link, target_addr, tp->func_send_buf, sizeof(tp->func_send_buf),
- tp->func_recv_buf, sizeof(tp->func_recv_buf));
- return UDS_OK;
+static void tp_ack_recv(UDSTpHandle_t *hdl) {
+ assert(hdl);
+ printf("ack recv\n");
+ UDSTpISOTpC_t *tp = (UDSTpISOTpC_t *)hdl;
}
-UDSErr_t UDSTpISOTpCInitClient(UDSTpISOTpC_t *tp, UDSClient_t *client, const char *ifname, uint32_t source_addr, uint32_t target_addr, uint32_t source_addr_func) {
+
+UDSErr_t UDSTpISOTpCInit(UDSTpISOTpC_t *tp, const char *ifname, uint32_t source_addr,
+ uint32_t target_addr, uint32_t source_addr_func, uint32_t target_addr_func)
+{
assert(tp);
assert(ifname);
tp->hdl.poll = tp_poll;
- tp->hdl.recv = tp_recv;
tp->hdl.send = tp_send;
+ tp->hdl.peek = tp_peek;
+ tp->hdl.ack_recv = tp_ack_recv;
tp->phys_sa = source_addr;
tp->phys_ta = target_addr;
tp->func_sa = source_addr_func;
tp->func_ta = target_addr;
+ tp->fd = SetupSocketCAN(ifname);
- isotp_init_link(&tp->phys_link, target_addr, client->send_buf, sizeof(client->send_buf),
- client->recv_buf, sizeof(client->recv_buf));
- isotp_init_link(&tp->func_link, target_addr, tp->func_send_buf, sizeof(tp->func_send_buf),
- tp->func_recv_buf, sizeof(tp->func_recv_buf));
+ isotp_init_link(&tp->phys_link, target_addr, tp->send_buf, sizeof(tp->send_buf),
+ tp->recv_buf, sizeof(tp->recv_buf), isotp_user_get_ms, isotp_user_send_can, isotp_user_debug, &tp->fd);
+ isotp_init_link(&tp->func_link, target_addr_func, tp->recv_buf, sizeof(tp->send_buf),
+ tp->recv_buf, sizeof(tp->recv_buf), isotp_user_get_ms, isotp_user_send_can, isotp_user_debug, &tp->fd);
return UDS_OK;
}
-
\ No newline at end of file
+
+void UDSTpISOTpCDeinit(UDSTpISOTpC_t *tp) {
+ assert(tp);
+ close(tp->fd);
+ tp->fd = -1;
+}
\ No newline at end of file
diff --git a/tp/isotp_c_socketcan.h b/tp/isotp_c_socketcan.h
index 47d4e34..3b82034 100644
--- a/tp/isotp_c_socketcan.h
+++ b/tp/isotp_c_socketcan.h
@@ -8,24 +8,16 @@ typedef struct {
UDSTpHandle_t hdl;
IsoTpLink phys_link;
IsoTpLink func_link;
- uint8_t send_buf[UDS_BUFSIZE];
- uint8_t recv_buf[UDS_BUFSIZE];
- uint8_t func_recv_buf[8];
- uint8_t func_send_buf[8];
+ uint8_t send_buf[UDS_ISOTP_MTU];
+ uint8_t recv_buf[UDS_ISOTP_MTU];
int fd;
uint32_t phys_sa, phys_ta;
uint32_t func_sa, func_ta;
char tag[16];
} UDSTpISOTpC_t;
-UDSErr_t UDSTpISOTpCInitServer(UDSTpISOTpC_t *tp, UDSServer_t *srv, const char *ifname, uint32_t source_addr,
- uint32_t target_addr, uint32_t target_addr_func);
-UDSErr_t UDSTpISOTpCInitClient(UDSTpISOTpC_t *tp, UDSClient_t *client, const char *ifname, uint32_t source_addr,
- uint32_t target_addr, uint32_t target_addr_func);
-void UDSTpISOTpCDeinit(UDSTpISOTpC_t *tp);
-
-UDSErr_t UDSTpisotpcInit(UDSTpISOTpC_t *tp, const char *ifname, uint32_t source_addr,
+UDSErr_t UDSTpISOTpCInit(UDSTpISOTpC_t *tp, const char *ifname, uint32_t source_addr,
uint32_t target_addr, uint32_t source_addr_func, uint32_t target_addr_func);
-
+void UDSTpISOTpCDeinit(UDSTpISOTpC_t *tp);
#endif
\ No newline at end of file
diff --git a/tp/isotp_sock.c b/tp/isotp_sock.c
index fa8c3a4..8d378ee 100644
--- a/tp/isotp_sock.c
+++ b/tp/isotp_sock.c
@@ -84,16 +84,20 @@ static void tp_ack_recv(UDSTpHandle_t *hdl) {
impl->recv_len = 0;
}
-static ssize_t tp_send(UDSTpHandle_t *hdl, uint8_t *buf, ssize_t len, UDSSDU_t *info) {
+static ssize_t tp_send(UDSTpHandle_t *hdl, uint8_t *buf, size_t len, UDSSDU_t *info) {
assert(hdl);
ssize_t ret = -1;
UDSTpIsoTpSock_t *impl = (UDSTpIsoTpSock_t *)hdl;
int fd;
- const UDSTpAddr_t ta_type = info ? info->A_TA : UDS_A_TA_TYPE_PHYSICAL;
+ const UDSTpAddr_t ta_type = info ? info->A_TA_Type : UDS_A_TA_TYPE_PHYSICAL;
if (UDS_A_TA_TYPE_PHYSICAL == ta_type) {
fd = impl->phys_fd;
} else if (UDS_A_TA_TYPE_FUNCTIONAL == ta_type) {
+ if (len > 7) {
+ UDS_DBG_PRINT("UDSTpIsoTpSock: functional request too large\n");
+ return -1;
+ }
fd = impl->func_fd;
} else {
ret = -4;
@@ -118,6 +122,13 @@ static ssize_t tp_send(UDSTpHandle_t *hdl, uint8_t *buf, ssize_t len, UDSSDU_t *
return ret;
}
+static ssize_t tp_get_send_buf(UDSTpHandle_t *hdl, uint8_t **p_buf) {
+ assert(hdl);
+ UDSTpIsoTpSock_t *impl = (UDSTpIsoTpSock_t *)hdl;
+ *p_buf = impl->send_buf;
+ return sizeof(impl->send_buf);
+}
+
static int LinuxSockBind(const char *if_name, uint32_t rxid, uint32_t txid, bool functional) {
int fd = 0;
if ((fd = socket(AF_CAN, SOCK_DGRAM | SOCK_NONBLOCK, CAN_ISOTP)) < 0) {
@@ -173,17 +184,20 @@ UDSErr_t UDSTpIsoTpSockInitServer(UDSTpIsoTpSock_t *tp, const char *ifname, uint
tp->hdl.send = tp_send;
tp->hdl.poll = tp_poll;
tp->hdl.ack_recv = tp_ack_recv;
+ tp->hdl.get_send_buf = tp_get_send_buf;
tp->phys_sa = source_addr;
tp->phys_ta = target_addr;
tp->func_sa = source_addr_func;
tp->phys_fd = LinuxSockBind(ifname, source_addr, target_addr, false);
- tp->func_fd = LinuxSockBind(ifname, source_addr_func, target_addr, true);
+ tp->func_fd = LinuxSockBind(ifname, source_addr_func, 0, true);
if (tp->phys_fd < 0 || tp->func_fd < 0) {
+ printf ("foo\n");
+ fflush(stdout);
return UDS_ERR;
}
UDS_DBG_PRINT("%s initialized phys link rx 0x%03x tx 0x%03x func link rx 0x%03x tx 0x%03x\n",
- tp->tag ? tp->tag : "server", source_addr, target_addr, source_addr_func, target_addr);
+ strlen(tp->tag) ? tp->tag : "server", source_addr, target_addr, source_addr_func, target_addr);
return UDS_OK;
}
@@ -194,12 +208,13 @@ UDSErr_t UDSTpIsoTpSockInitClient(UDSTpIsoTpSock_t *tp, const char *ifname, uint
tp->hdl.send = tp_send;
tp->hdl.poll = tp_poll;
tp->hdl.ack_recv = tp_ack_recv;
+ tp->hdl.get_send_buf = tp_get_send_buf;
tp->func_ta = target_addr_func;
tp->phys_ta = target_addr;
tp->phys_sa = source_addr;
tp->phys_fd = LinuxSockBind(ifname, source_addr, target_addr, false);
- tp->func_fd = LinuxSockBind(ifname, source_addr + 1, target_addr_func, true);
+ tp->func_fd = LinuxSockBind(ifname, 0, target_addr_func, true);
if (tp->phys_fd < 0 || tp->func_fd < 0) {
return UDS_ERR;
}
diff --git a/tp/isotp_sock.h b/tp/isotp_sock.h
index 28b28e3..ff73688 100644
--- a/tp/isotp_sock.h
+++ b/tp/isotp_sock.h
@@ -5,8 +5,8 @@
typedef struct {
UDSTpHandle_t hdl;
- uint8_t recv_buf[UDS_BUFSIZE];
- uint8_t send_buf[UDS_BUFSIZE];
+ uint8_t recv_buf[UDS_ISOTP_MTU];
+ uint8_t send_buf[UDS_ISOTP_MTU];
size_t recv_len;
UDSSDU_t recv_info;
int phys_fd;
diff --git a/tp/mock.c b/tp/mock.c
index aa977a4..297ee84 100644
--- a/tp/mock.c
+++ b/tp/mock.c
@@ -13,7 +13,7 @@ static TPMock_t *TPs[8];
static unsigned TPCount = 0;
static FILE *LogFile = NULL;
static struct Msg {
- uint8_t buf[UDS_BUFSIZE];
+ uint8_t buf[UDS_ISOTP_MTU];
size_t len;
UDSSDU_t info;
uint32_t scheduled_tx_time;
@@ -81,9 +81,9 @@ static ssize_t tp_send(struct UDSTpHandle *hdl, uint8_t * buf, size_t len, UDSSD
return -1;
}
struct Msg *m = &msgs[MsgCount++];
- UDSTpAddr_t ta_type = info ? info->A_TA_Type : UDS_A_TA_TYPE_PHYSICAL;
+ UDSTpAddr_t ta_type = info == NULL ? UDS_A_TA_TYPE_PHYSICAL : info->A_TA_Type;
m->len = len;
- m->info.A_AE = info ? info->A_AE : 0;
+ m->info.A_AE = info == NULL ? 0 : info->A_AE;
if (UDS_A_TA_TYPE_PHYSICAL == ta_type) {
m->info.A_TA = tp->ta_phys;
m->info.A_SA = tp->sa_phys;
@@ -94,6 +94,7 @@ static ssize_t tp_send(struct UDSTpHandle *hdl, uint8_t * buf, size_t len, UDSSD
fprintf(stderr, "TPMock: unknown TA type: %d\n", ta_type);
return -1;
}
+ m->info.A_TA_Type = ta_type;
m->scheduled_tx_time = UDSMillis() + tp->send_tx_delay_ms;
memmove(m->buf, buf, len);
LogMsg(tp->name, buf, len, &m->info);
@@ -122,8 +123,42 @@ static void tp_ack_recv(struct UDSTpHandle *hdl) {
static_assert(offsetof(TPMock_t, hdl) == 0, "TPMock_t must not have any members before hdl");
-UDSTpHandle_t *TPMockCreate(const char *name, TPMockArgs_t *args) {
+static void TPMockAttach(TPMock_t *tp, TPMockArgs_t *args) {
+ assert(tp);
+ assert(args);
+ assert(TPCount < MAX_NUM_TP);
+ TPs[TPCount++] = tp;
+ tp->hdl.peek = tp_peek;
+ tp->hdl.send = tp_send;
+ tp->hdl.poll = tp_poll;
+ tp->hdl.get_send_buf = tp_get_send_buf;
+ tp->hdl.ack_recv = tp_ack_recv;
+ tp->sa_func = args->sa_func;
+ tp->sa_phys = args->sa_phys;
+ tp->ta_func = args->ta_func;
+ tp->ta_phys = args->ta_phys;
+ tp->recv_len = 0;
+}
+
+static void TPMockDetach(TPMock_t *tp) {
+ assert(tp);
+ for (unsigned i = 0; i < TPCount; i++) {
+ if (TPs[i] == tp) {
+ for (unsigned j = i + 1; j < TPCount; j++) {
+ TPs[j - 1] = TPs[j];
+ }
+ TPCount--;
+ printf("TPMock: detached %s. TPCount: %d\n", tp->name, TPCount);
+ return;
+ }
+ }
+ assert(false);
+}
+
+
+UDSTpHandle_t *TPMockNew(const char *name, TPMockArgs_t *args) {
if (TPCount >= MAX_NUM_TP) {
+ printf("TPCount: %d, too many TPs\n", TPCount);
return NULL;
}
TPMock_t *tp = malloc(sizeof(TPMock_t));
@@ -168,33 +203,8 @@ void TPMockReset(void) {
}
-void TPMockAttach(TPMock_t *tp, TPMockArgs_t *args) {
- assert(tp);
- assert(args);
- assert(TPCount < MAX_NUM_TP);
- TPs[TPCount++] = tp;
- tp->hdl.peek = tp_peek;
- tp->hdl.send = tp_send;
- tp->hdl.poll = tp_poll;
- tp->hdl.get_send_buf = tp_get_send_buf;
- tp->hdl.ack_recv = tp_ack_recv;
- tp->sa_func = args->sa_func;
- tp->sa_phys = args->sa_phys;
- tp->ta_func = args->ta_func;
- tp->ta_phys = args->ta_phys;
- tp->recv_len = 0;
-}
-
-void TPMockDetach(TPMock_t *tp) {
- assert(tp);
- for (unsigned i = 0; i < TPCount; i++) {
- if (TPs[i] == tp) {
- for (unsigned j = i + 1; j < TPCount; j++) {
- TPs[j - 1] = TPs[j];
- }
- TPCount--;
- return;
- }
- }
- assert(false);
+void TPMockFree(UDSTpHandle_t *tp) {
+ TPMock_t *tpm = (TPMock_t *)tp;
+ TPMockDetach(tpm);
+ free(tp);
}
\ No newline at end of file
diff --git a/tp/mock.h b/tp/mock.h
index 6930701..982bf31 100644
--- a/tp/mock.h
+++ b/tp/mock.h
@@ -42,10 +42,8 @@ typedef struct {
* @param name optional name of the transport (can be NULL)
* @return UDSTpHandle_t*
*/
-UDSTpHandle_t *TPMockCreate(const char *name, TPMockArgs_t *args);
-
-void TPMockAttach(TPMock_t *tp, TPMockArgs_t *args);
-void TPMockDetach(TPMock_t *tp);
+UDSTpHandle_t *TPMockNew(const char *name, TPMockArgs_t *args);
+void TPMockFree(UDSTpHandle_t *tp);
/**
* @brief write all messages to a file
From f9713d7a26f437fd07f70a4da6962c357ff9eb2d Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Thu, 23 Nov 2023 12:48:41 -0700
Subject: [PATCH 11/56] fix tests
---
iso14229.c | 3 ++-
test/BUILD | 2 +-
test/env.c | 6 +++++-
test/test.h | 7 ++++---
tp/mock.c | 4 ++--
5 files changed, 14 insertions(+), 8 deletions(-)
diff --git a/iso14229.c b/iso14229.c
index 623cfcb..9bbc307 100644
--- a/iso14229.c
+++ b/iso14229.c
@@ -1069,7 +1069,8 @@ void UDSServerPoll(UDSServer_t *srv) {
if (srv->RCRRP) {
// ISO14229-2:2013 Table 4 footnote b
// min time between consecutive 0x78 responses is 0.3 * p2*
- srv->p2_timer = UDSMillis() + 0.3f * srv->p2_star_ms;
+ uint32_t wait_time = srv->p2_star_ms * 3 / 10;
+ srv->p2_timer = UDSMillis() + wait_time;
} else {
srv->p2_timer = UDSMillis() + srv->p2_ms;
UDSTpAckRecv(srv->tp);
diff --git a/test/BUILD b/test/BUILD
index 4de8862..07d26d7 100644
--- a/test/BUILD
+++ b/test/BUILD
@@ -26,7 +26,7 @@ cc_library(
deps=[":env"],
size = "small",
env = {
- "UDS_TP_TYPE": "2",
+ "UDS_TP_TYPE": "0",
},
copts = ["-g"],
tags = [
diff --git a/test/env.c b/test/env.c
index 4b5e9c9..0b58aee 100644
--- a/test/env.c
+++ b/test/env.c
@@ -11,7 +11,7 @@
static UDSServer_t *registeredServer = NULL;
static UDSClient_t *registeredClient = NULL;
-#define MAX_NUM_TP 8
+#define MAX_NUM_TP 16
static UDSTpHandle_t *registeredTps[MAX_NUM_TP];
static unsigned TPCount = 0;
static uint32_t TimeNowMillis = 0;
@@ -110,6 +110,10 @@ void ENV_RunMillis(uint32_t millis) {
UDSTpHandle_t *ENV_TpNew(const char *name) {
ENV_ParseOpts();
UDSTpHandle_t *tp = NULL;
+ if (MAX_NUM_TP == TPCount) {
+ printf("too many TPs\n");
+ return NULL;
+ }
if (0 == strcasecmp(name, "server"))
switch (opts.tp_type) {
case ENV_TP_TYPE_MOCK:
diff --git a/test/test.h b/test/test.h
index 1d1fbf2..8e9bcf7 100644
--- a/test/test.h
+++ b/test/test.h
@@ -10,6 +10,7 @@
#include "tp/mock.h"
#include
+
#define _TEST_INT_COND(a, b, cond) \
{ \
int _a = a; \
@@ -17,7 +18,7 @@
if (!((_a)cond(_b))) { \
printf("%s:%d (%d %s %d)\n", __FILE__, __LINE__, _a, #cond, _b); \
fflush(stdout); \
- assert(a cond b); \
+ assert_true(a cond b); \
} \
}
@@ -93,8 +94,8 @@
#define EXPECT_IN_APPROX_MS(cond, duration) \
{ \
const float tolerance = 0.1f; \
- uint32_t pre_deadline = UDSMillis() + (int)(duration * (1.0f - tolerance)); \
- uint32_t post_deadline = UDSMillis() + (int)(duration * (1.0f + tolerance)); \
+ uint32_t pre_deadline = UDSMillis() + (int)((duration) * (1.0f - tolerance)); \
+ uint32_t post_deadline = UDSMillis() + (int)((duration) * (1.0f + tolerance)); \
while (UDSTimeAfter(pre_deadline, UDSMillis())) { \
assert(!(cond)); \
ENV_RunMillis(1); \
diff --git a/tp/mock.c b/tp/mock.c
index 297ee84..a7afd85 100644
--- a/tp/mock.c
+++ b/tp/mock.c
@@ -7,9 +7,9 @@
#include
-#define MAX_NUM_TP 8
+#define MAX_NUM_TP 16
#define NUM_MSGS 8
-static TPMock_t *TPs[8];
+static TPMock_t *TPs[MAX_NUM_TP];
static unsigned TPCount = 0;
static FILE *LogFile = NULL;
static struct Msg {
From 12db911fe79bb8365e7bab8dcaba8b79395c4953 Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Sat, 25 Nov 2023 22:46:52 -0700
Subject: [PATCH 12/56] add s32k example, run clang-format
---
.bazelrc | 8 +-
BUILD | 9 +
WORKSPACE | 24 +-
examples/s32k144/.gdbinit | 7 +
examples/s32k144/BUILD | 236 ++++++
examples/s32k144/README.md | 35 +
examples/s32k144/bsp.c | 685 ++++++++++++++++++
examples/s32k144/bsp.h | 11 +
examples/s32k144/main.c | 55 ++
iso14229.c | 139 ++--
iso14229.h | 22 +-
platforms/BUILD | 25 +-
platforms/cmsis.BUILD | 13 +
platforms/s32k_sdk.BUILD | 20 +
test/BUILD | 62 +-
test/env.c | 53 +-
test/env.h | 2 +-
test/test.h | 36 +-
test/test_client_0x11_ECU_reset.c | 3 -
test/test_client_0x31_RCRRP.c | 117 +--
test/test_fuzz_server.c | 5 +-
test/test_matrix.py | 17 +
test/test_prefix.sh | 4 +-
...r_0x10_diag_sess_ctrl_functional_request.c | 4 +-
...10_diag_sess_ctrl_is_disabled_by_default.c | 2 +-
...server_0x11_no_send_recv_after_ECU_reset.c | 4 +-
test/test_server_0x22_RDBI.c | 6 +-
.../test_server_0x23_read_memory_by_address.c | 12 +-
test/test_server_0x27_security_access.c | 6 +-
test/test_server_0x31_RCRRP.c | 5 +-
test/test_server_0x34.c | 4 +-
...t_server_0x3E_suppress_positive_response.c | 2 +-
...t_server_0x83_diagnostic_session_control.c | 2 +-
test/test_tp_compliance.c | 21 +-
test_iso14229.c | 15 +-
toolchain/BUILD | 27 +-
toolchain/gcc_family.bzl | 79 +-
toolchain/objcopy.bzl | 59 ++
tp/BUILD | 2 +
tp/isotp_c.c | 162 +++++
tp/isotp_c.h | 34 +
tp/isotp_c_socketcan.c | 60 +-
tp/isotp_c_socketcan.h | 3 +-
tp/isotp_sock.c | 15 +-
tp/mock.c | 11 +-
tp/mock.h | 23 +-
46 files changed, 1815 insertions(+), 331 deletions(-)
create mode 100644 examples/s32k144/.gdbinit
create mode 100644 examples/s32k144/BUILD
create mode 100644 examples/s32k144/README.md
create mode 100644 examples/s32k144/bsp.c
create mode 100644 examples/s32k144/bsp.h
create mode 100644 examples/s32k144/main.c
create mode 100644 platforms/cmsis.BUILD
create mode 100644 platforms/s32k_sdk.BUILD
create mode 100644 test/test_matrix.py
create mode 100644 toolchain/objcopy.bzl
create mode 100644 tp/isotp_c.c
create mode 100644 tp/isotp_c.h
diff --git a/.bazelrc b/.bazelrc
index dea6f18..a32f912 100644
--- a/.bazelrc
+++ b/.bazelrc
@@ -1,19 +1,21 @@
build --strip=never
build --incompatible_enable_cc_toolchain_resolution
-build --extra_toolchains //toolchain:arm_gcc
+build --extra_toolchains //toolchain:arm_linux_gcc
+build --extra_toolchains //toolchain:arm_none_gcc
build --extra_toolchains //toolchain:ppc_gcc
build --extra_toolchains //toolchain:ppc64_gcc
build --extra_toolchains //toolchain:ppc64le_gcc
build --extra_toolchains //toolchain:x86_64_clang
-build:arm --platforms=//platforms:arm
+build:arm_linux --platforms=//platforms:arm_linux
+build:s32k --platforms=//platforms:s32k_evb
build:ppc --platforms=//platforms:ppc
build:ppc64 --platforms=//platforms:ppc64
build:ppc64le --platforms=//platforms:ppc64le
build:x86_64_clang --platforms=//platforms:x86_64_clang
-test:arm --run_under="qemu-arm -L /usr/arm-linux-gnueabihf/ "
+test:arm_linux --run_under="qemu-arm -L /usr/arm-linux-gnueabihf/ "
test:ppc --run_under="qemu-ppc -L /usr/powerpc-linux-gnu/ "
test:ppc64 --run_under="qemu-ppc64 -L /usr/powerpc64-linux-gnu/ "
test:ppc64le --run_under="qemu-ppc64le -L /usr/powerpc64le-linux-gnu/ "
diff --git a/BUILD b/BUILD
index a2227cd..d4db888 100644
--- a/BUILD
+++ b/BUILD
@@ -1,4 +1,5 @@
package(default_visibility = ["//visibility:public"])
+load("@hedron_compile_commands//:refresh_compile_commands.bzl", "refresh_compile_commands")
filegroup(
@@ -46,3 +47,11 @@ cc_library(
name="iso14229",
srcs=[":iso14229_srcs"],
)
+
+
+refresh_compile_commands(
+ name = "s32k_refresh_compile_commands",
+ targets = {
+ "//examples/s32k144/...": "--config=s32k",
+ }
+)
\ No newline at end of file
diff --git a/WORKSPACE b/WORKSPACE
index ba2836c..6e5bd08 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -16,18 +16,26 @@ http_archive(
load("@hedron_compile_commands//:workspace_setup.bzl", "hedron_compile_commands_setup")
hedron_compile_commands_setup()
-http_archive(
- name = "unity",
- url = "https://github.com/ThrowTheSwitch/Unity/archive/refs/tags/v2.5.2.zip",
- sha256 = "4598298723ecca1f242b8c540a253ae4ab591f6810cbde72f128961007683034",
- strip_prefix = "Unity-2.5.2",
- build_file = "//test:unity.BUILD",
-)
-
http_archive(
name = "cmocka",
url = "https://cmocka.org/files/1.1/cmocka-1.1.7.tar.xz",
sha256 = "810570eb0b8d64804331f82b29ff47c790ce9cd6b163e98d47a4807047ecad82",
build_file = "//test:cmocka.BUILD",
strip_prefix = "cmocka-1.1.7",
+)
+
+http_archive(
+ name = "s32k_sdk",
+ url = "https://www.keil.com/pack/Keil.S32_SDK_DFP.1.5.0.pack",
+ sha256 = "95f7649aee66deb656cc999f300663544113245aecd407cfc90548377355353b",
+ type = "zip",
+ build_file = "//platforms:s32k_sdk.BUILD",
+)
+
+http_archive(
+ name = "CMSIS",
+ build_file = "//platforms:cmsis.BUILD",
+ sha256 = "14b366f2821ee5d32f0d3bf48ef9657ca45347261d0531263580848e9d36f8f4",
+ urls = ["http://www.keil.com/pack/ARM.CMSIS.5.9.0.pack"],
+ type = ".zip",
)
\ No newline at end of file
diff --git a/examples/s32k144/.gdbinit b/examples/s32k144/.gdbinit
new file mode 100644
index 0000000..bc865f1
--- /dev/null
+++ b/examples/s32k144/.gdbinit
@@ -0,0 +1,7 @@
+target remote localhost:3333
+set architecture armv7e-m
+# file bazel-bin/examples/s32k144/main
+
+define dumpflash
+ dump binary memory dump.bin 0x0 0x80000
+end
\ No newline at end of file
diff --git a/examples/s32k144/BUILD b/examples/s32k144/BUILD
new file mode 100644
index 0000000..231b399
--- /dev/null
+++ b/examples/s32k144/BUILD
@@ -0,0 +1,236 @@
+load("//toolchain:objcopy.bzl", "objcopy")
+
+cc_binary(
+ name = "main",
+ srcs = [
+ "main.c",
+ "bsp.c",
+ "bsp.h",
+ "//:iso14229_srcs",
+ "//tp:isotp_c_srcs",
+ "//tp:isotp_c.c",
+ "//tp:isotp_c.h",
+ ],
+ deps = [
+ ":runtime",
+ ],
+ defines = [
+ "UDS_CUSTOM_MILLIS",
+ ]
+)
+
+objcopy(
+ src = "main",
+ out = "main.hex",
+ args = "-O ihex",
+)
+
+cc_library(
+ name = "runtime",
+ srcs = [
+ "@s32k_sdk//:platform/devices/S32K144/startup/system_S32K144.c",
+ "@s32k_sdk//:platform/devices/S32K144/startup/system_S32K144.h",
+ "@s32k_sdk//:platform/devices/S32K144/include/S32K144.h",
+ "@s32k_sdk//:platform/devices/S32K144/include/S32K144_features.h",
+ "@s32k_sdk//:platform/devices/callbacks.h",
+ "@s32k_sdk//:platform/devices/device_registers.h",
+ "@s32k_sdk//:platform/devices/devassert.h",
+ "@s32k_sdk//:platform/devices/startup.h",
+ "@s32k_sdk//:platform/devices/startup.c",
+ "@s32k_sdk//:platform/devices/status.h",
+ "@s32k_sdk//:platform/devices/common/s32_core_cm4.h",
+ "@s32k_sdk//:rtos/osif/osif.h",
+ "@s32k_sdk//:rtos/osif/osif_baremetal.c",
+
+ "@s32k_sdk//:platform/drivers/inc/adc_driver.h",
+ "@s32k_sdk//:platform/drivers/inc/clock.h",
+ "@s32k_sdk//:platform/drivers/inc/clock_manager.h",
+ "@s32k_sdk//:platform/drivers/inc/cmp_driver.h",
+ "@s32k_sdk//:platform/drivers/inc/crc_driver.h",
+ "@s32k_sdk//:platform/drivers/inc/csec_driver.h",
+ "@s32k_sdk//:platform/drivers/inc/edma_driver.h",
+ "@s32k_sdk//:platform/drivers/inc/eim_driver.h",
+ # "@s32k_sdk//:platform/drivers/inc/enet_driver.h",
+ "@s32k_sdk//:platform/drivers/inc/erm_driver.h",
+ "@s32k_sdk//:platform/drivers/inc/ewm_driver.h",
+ "@s32k_sdk//:platform/drivers/inc/flash_driver.h",
+ # "@s32k_sdk//:platform/drivers/inc/flash_mx25l6433f_driver.h",
+ "@s32k_sdk//:platform/drivers/inc/flexcan_driver.h",
+ "@s32k_sdk//:platform/drivers/inc/flexio.h",
+ "@s32k_sdk//:platform/drivers/inc/flexio_i2c_driver.h",
+ "@s32k_sdk//:platform/drivers/inc/flexio_i2s_driver.h",
+ "@s32k_sdk//:platform/drivers/inc/flexio_spi_driver.h",
+ "@s32k_sdk//:platform/drivers/inc/flexio_uart_driver.h",
+ "@s32k_sdk//:platform/drivers/inc/ftm_common.h",
+ "@s32k_sdk//:platform/drivers/inc/ftm_ic_driver.h",
+ "@s32k_sdk//:platform/drivers/inc/ftm_mc_driver.h",
+ "@s32k_sdk//:platform/drivers/inc/ftm_oc_driver.h",
+ "@s32k_sdk//:platform/drivers/inc/ftm_pwm_driver.h",
+ "@s32k_sdk//:platform/drivers/inc/ftm_qd_driver.h",
+ "@s32k_sdk//:platform/drivers/inc/interrupt_manager.h",
+ "@s32k_sdk//:platform/drivers/inc/lin_driver.h",
+ "@s32k_sdk//:platform/drivers/inc/lpi2c_driver.h",
+ "@s32k_sdk//:platform/drivers/inc/lpit_driver.h",
+ "@s32k_sdk//:platform/drivers/inc/lpspi_master_driver.h",
+ "@s32k_sdk//:platform/drivers/inc/lpspi_shared_function.h",
+ "@s32k_sdk//:platform/drivers/inc/lpspi_slave_driver.h",
+ "@s32k_sdk//:platform/drivers/inc/lptmr_driver.h",
+ "@s32k_sdk//:platform/drivers/inc/lpuart_driver.h",
+ "@s32k_sdk//:platform/drivers/inc/mpu_driver.h",
+ "@s32k_sdk//:platform/drivers/inc/pdb_driver.h",
+ "@s32k_sdk//:platform/drivers/inc/pins_driver.h",
+ "@s32k_sdk//:platform/drivers/inc/power_manager.h",
+ # "@s32k_sdk//:platform/drivers/inc/quadspi_driver.h",
+ "@s32k_sdk//:platform/drivers/inc/rtc_driver.h",
+ # "@s32k_sdk//:platform/drivers/inc/sai_driver.h",
+ "@s32k_sdk//:platform/drivers/inc/trgmux_driver.h",
+ "@s32k_sdk//:platform/drivers/inc/wdog_driver.h",
+
+ # s32k144 has no phy
+ # "@s32k_sdk//:platform/drivers/src/phy/phy_enet_access.c",
+ # "@s32k_sdk//:platform/drivers/src/phy/phy_generic.c",
+ # "@s32k_sdk//:platform/drivers/src/phy/phy_shared.h",
+ # "@s32k_sdk//:platform/drivers/src/phy/phy_hw_access.h",
+ # "@s32k_sdk//:platform/drivers/src/phy/phy_tja110x.c",
+ # "@s32k_sdk//:platform/drivers/src/phy/phy.c",
+ # "@s32k_sdk//:platform/drivers/src/phy/phy_shared.c",
+
+ "@s32k_sdk//:platform/drivers/src/lpuart/lpuart_irq.c",
+ "@s32k_sdk//:platform/drivers/src/lpuart/lpuart_hw_access.c",
+ "@s32k_sdk//:platform/drivers/src/lpuart/lin_lpuart_driver.h",
+ "@s32k_sdk//:platform/drivers/src/lpuart/lpuart_irq.h",
+ "@s32k_sdk//:platform/drivers/src/lpuart/lpuart_hw_access.h",
+ "@s32k_sdk//:platform/drivers/src/lpuart/lpuart_driver.c",
+ "@s32k_sdk//:platform/drivers/src/lpuart/lin_lpuart_driver.c",
+ "@s32k_sdk//:platform/drivers/src/clock/S32K1xx/clock_S32K1xx.c",
+ "@s32k_sdk//:platform/drivers/src/clock/S32K1xx/scg_hw_access.h",
+ "@s32k_sdk//:platform/drivers/src/clock/S32K1xx/smc_hw_access.h",
+ "@s32k_sdk//:platform/drivers/src/clock/S32K1xx/pmc_hw_access.h",
+ "@s32k_sdk//:platform/drivers/src/clock/S32K1xx/pcc_hw_access.h",
+ "@s32k_sdk//:platform/drivers/src/clock/S32K1xx/clock_S32K1xx.h",
+ "@s32k_sdk//:platform/drivers/src/clock/S32K1xx/sim_hw_access.h",
+ "@s32k_sdk//:platform/drivers/src/flexcan/flexcan_irq.c",
+ "@s32k_sdk//:platform/drivers/src/flexcan/flexcan_irq.h",
+ "@s32k_sdk//:platform/drivers/src/flexcan/flexcan_hw_access.h",
+ "@s32k_sdk//:platform/drivers/src/flexcan/flexcan_hw_access.c",
+ "@s32k_sdk//:platform/drivers/src/flexcan/flexcan_driver.c",
+ "@s32k_sdk//:platform/drivers/src/flexio/flexio_hw_access.h",
+ "@s32k_sdk//:platform/drivers/src/flexio/flexio_spi_driver.c",
+ "@s32k_sdk//:platform/drivers/src/flexio/flexio_common.c",
+ "@s32k_sdk//:platform/drivers/src/flexio/flexio_uart_driver.c",
+ "@s32k_sdk//:platform/drivers/src/flexio/flexio_i2s_driver.c",
+ "@s32k_sdk//:platform/drivers/src/flexio/flexio_common.h",
+ "@s32k_sdk//:platform/drivers/src/flexio/flexio_i2c_driver.c",
+ # "@s32k_sdk//:platform/drivers/src/sai/sai_driver.c",
+ # "@s32k_sdk//:platform/drivers/src/sai/sai_hw_access.h",
+ "@s32k_sdk//:platform/drivers/src/interrupt/interrupt_manager.c",
+ "@s32k_sdk//:platform/drivers/src/wdog/wdog_hw_access.h",
+ "@s32k_sdk//:platform/drivers/src/wdog/wdog_hw_access.c",
+ "@s32k_sdk//:platform/drivers/src/wdog/wdog_driver.c",
+ # "@s32k_sdk//:platform/drivers/src/enet/enet_irq.c",
+ # "@s32k_sdk//:platform/drivers/src/enet/enet_driver.c",
+ # "@s32k_sdk//:platform/drivers/src/enet/enet_hw_access.h",
+ # "@s32k_sdk//:platform/drivers/src/enet/enet_hw_access.c",
+ "@s32k_sdk//:platform/drivers/src/csec/csec_hw_access.h",
+ "@s32k_sdk//:platform/drivers/src/csec/csec_driver.c",
+ "@s32k_sdk//:platform/drivers/src/csec/csec_hw_access.c",
+ "@s32k_sdk//:platform/drivers/src/ewm/ewm_hw_access.h",
+ "@s32k_sdk//:platform/drivers/src/ewm/ewm_driver.c",
+ "@s32k_sdk//:platform/drivers/src/pdb/pdb_driver.c",
+ "@s32k_sdk//:platform/drivers/src/pdb/pdb_hw_access.c",
+ "@s32k_sdk//:platform/drivers/src/pdb/pdb_hw_access.h",
+ "@s32k_sdk//:platform/drivers/src/rtc/rtc_driver.c",
+ "@s32k_sdk//:platform/drivers/src/rtc/rtc_irq.c",
+ "@s32k_sdk//:platform/drivers/src/rtc/rtc_hw_access.c",
+ "@s32k_sdk//:platform/drivers/src/rtc/rtc_hw_access.h",
+ "@s32k_sdk//:platform/drivers/src/cmp/cmp_driver.c",
+ "@s32k_sdk//:platform/drivers/src/cmp/cmp_hw_access.c",
+ "@s32k_sdk//:platform/drivers/src/cmp/cmp_hw_access.h",
+ # "@s32k_sdk//:platform/drivers/src/quadspi/quadspi_hw_access.h",
+ # "@s32k_sdk//:platform/drivers/src/quadspi/quadspi_driver.c",
+ "@s32k_sdk//:platform/drivers/src/lpspi/lpspi_master_driver.c",
+ "@s32k_sdk//:platform/drivers/src/lpspi/lpspi_shared_function.c",
+ "@s32k_sdk//:platform/drivers/src/lpspi/lpspi_irq.c",
+ "@s32k_sdk//:platform/drivers/src/lpspi/lpspi_hw_access.h",
+ "@s32k_sdk//:platform/drivers/src/lpspi/lpspi_hw_access.c",
+ "@s32k_sdk//:platform/drivers/src/lpspi/lpspi_slave_driver.c",
+ "@s32k_sdk//:platform/drivers/src/lpit/lpit_driver.c",
+ "@s32k_sdk//:platform/drivers/src/lpit/lpit_hw_access.h",
+ "@s32k_sdk//:platform/drivers/src/eim/eim_hw_access.c",
+ "@s32k_sdk//:platform/drivers/src/eim/eim_hw_access.h",
+ "@s32k_sdk//:platform/drivers/src/eim/eim_driver.c",
+ "@s32k_sdk//:platform/drivers/src/lptmr/lptmr_hw_access.h",
+ "@s32k_sdk//:platform/drivers/src/lptmr/lptmr_hw_access.c",
+ "@s32k_sdk//:platform/drivers/src/lptmr/lptmr_driver.c",
+ "@s32k_sdk//:platform/drivers/src/flash/flash_driver.c",
+ # "@s32k_sdk//:platform/drivers/src/flash_mx25l6433f/flash_mx25l6433f_regs.h",
+ # "@s32k_sdk//:platform/drivers/src/flash_mx25l6433f/flash_mx25l6433f_driver.c",
+ "@s32k_sdk//:platform/drivers/src/edma/edma_irq.c",
+ "@s32k_sdk//:platform/drivers/src/edma/edma_irq.h",
+ "@s32k_sdk//:platform/drivers/src/edma/edma_hw_access.h",
+ "@s32k_sdk//:platform/drivers/src/edma/edma_driver.c",
+ "@s32k_sdk//:platform/drivers/src/edma/edma_hw_access.c",
+ "@s32k_sdk//:platform/drivers/src/crc/crc_hw_access.c",
+ "@s32k_sdk//:platform/drivers/src/crc/crc_driver.c",
+ "@s32k_sdk//:platform/drivers/src/crc/crc_hw_access.h",
+ "@s32k_sdk//:platform/drivers/src/ftm/ftm_qd_driver.c",
+ "@s32k_sdk//:platform/drivers/src/ftm/ftm_mc_driver.c",
+ "@s32k_sdk//:platform/drivers/src/ftm/ftm_hw_access.h",
+ "@s32k_sdk//:platform/drivers/src/ftm/ftm_ic_driver.c",
+ "@s32k_sdk//:platform/drivers/src/ftm/ftm_common.c",
+ "@s32k_sdk//:platform/drivers/src/ftm/ftm_pwm_driver.c",
+ "@s32k_sdk//:platform/drivers/src/ftm/ftm_hw_access.c",
+ "@s32k_sdk//:platform/drivers/src/ftm/ftm_oc_driver.c",
+ "@s32k_sdk//:platform/drivers/src/mpu/mpu_driver.c",
+ "@s32k_sdk//:platform/drivers/src/mpu/mpu_hw_access.h",
+ "@s32k_sdk//:platform/drivers/src/mpu/mpu_hw_access.c",
+ "@s32k_sdk//:platform/drivers/src/lpi2c/lpi2c_irq.h",
+ "@s32k_sdk//:platform/drivers/src/lpi2c/lpi2c_hw_access.c",
+ "@s32k_sdk//:platform/drivers/src/lpi2c/lpi2c_irq.c",
+ "@s32k_sdk//:platform/drivers/src/lpi2c/lpi2c_hw_access.h",
+ "@s32k_sdk//:platform/drivers/src/lpi2c/lpi2c_driver.c",
+ "@s32k_sdk//:platform/drivers/src/erm/erm_driver.c",
+ "@s32k_sdk//:platform/drivers/src/erm/erm_hw_access.h",
+ "@s32k_sdk//:platform/drivers/src/erm/erm_hw_access.c",
+ "@s32k_sdk//:platform/drivers/src/power/S32K1xx/power_scg_hw_access.h",
+ "@s32k_sdk//:platform/drivers/src/power/S32K1xx/power_manager_S32K1xx.c",
+ "@s32k_sdk//:platform/drivers/src/power/S32K1xx/power_smc_hw_access.h",
+ "@s32k_sdk//:platform/drivers/src/power/S32K1xx/power_rcm_hw_access.h",
+ "@s32k_sdk//:platform/drivers/src/power/S32K1xx/power_manager_S32K1xx.h",
+ "@s32k_sdk//:platform/drivers/src/power/S32K1xx/power_smc_hw_access.c",
+ "@s32k_sdk//:platform/drivers/src/power/power_manager.c",
+ "@s32k_sdk//:platform/drivers/src/lin/lin_irq.c",
+ "@s32k_sdk//:platform/drivers/src/lin/lin_common.c",
+ "@s32k_sdk//:platform/drivers/src/lin/lin_driver.c",
+ "@s32k_sdk//:platform/drivers/src/adc/adc_hw_access.h",
+ "@s32k_sdk//:platform/drivers/src/adc/adc_driver.c",
+ "@s32k_sdk//:platform/drivers/src/trgmux/trgmux_hw_access.h",
+ "@s32k_sdk//:platform/drivers/src/trgmux/trgmux_hw_access.c",
+ "@s32k_sdk//:platform/drivers/src/trgmux/trgmux_driver.c",
+ "@s32k_sdk//:platform/drivers/src/pins/pins_driver.c",
+ "@s32k_sdk//:platform/drivers/src/pins/pins_gpio_hw_access.h",
+ "@s32k_sdk//:platform/drivers/src/pins/pins_port_hw_access.h",
+ "@s32k_sdk//:platform/drivers/src/pins/pins_port_hw_access.c",
+
+
+ "@s32k_sdk//:platform/devices/S32K144/startup/gcc/startup_S32K144.S",
+ ],
+ deps = [
+ "@s32k_sdk//:platform/devices/S32K144/linker/gcc/S32K144_64_flash.ld",
+ "@s32k_sdk//:include",
+ "@CMSIS//:include",
+ ],
+ linkopts = [
+ "-T $(location @s32k_sdk//:platform/devices/S32K144/linker/gcc/S32K144_64_flash.ld)",
+ "-lc",
+ "-lnosys",
+ "-Wl,--defsym=__Vectors=__isr_vector",
+ # force the symbol CAN0_Error_IRQHandler to be included
+ "-Wl,--undefined=CAN0_Error_IRQHandler",
+ ],
+ defines = [
+ "CPU_S32K144HFT0VLLT",
+ "DEV_ERROR_DETECT=1U",
+ ],
+ target_compatible_with = ["//platforms:s32k"],
+)
\ No newline at end of file
diff --git a/examples/s32k144/README.md b/examples/s32k144/README.md
new file mode 100644
index 0000000..808e2a0
--- /dev/null
+++ b/examples/s32k144/README.md
@@ -0,0 +1,35 @@
+I'm so sorry that you too must futz with Freescale / NXP's byzantine drivers!
+
+This demo uses the [S32K144-EVB](https://www.keil.arm.com/boards/nxp-s32k144-evb-rev-a-ee981eb/features/)
+
+
+# Building
+
+This uses `gcc-arm-none-eabi`, make sure it's installed first.
+
+```sh
+sudo apt install gcc-arm-none-eabi
+bazel build --config=s32k //examples/s32k144:main
+```
+
+
+# CMSIS-DAP
+
+1. update programming interface from "OpenSDA" to CMSIS-DAP [1](https://community.nxp.com/t5/S32K/S32K144evb-with-CMSIS-DAP/td-p/1227900) [2](https://developer.arm.com/documentation/kan299/latest/)
+2. install `pyocd`
+3. `pyocd pack install S32K144UAxxxLLx`
+3. update `/etc/udev/rules.d/50-cmsis-dap.rules` with the following:
+
+```
+# c251:f002 S32K144-EVB
+SUBSYSTEM=="usb", ATTR{idVendor}=="c251", ATTR{idProduct}=="f002", MODE:="666"
+```
+
+```
+pyocd gdbserver --persist -Otarget_override=S32K144UAxxxLLx
+```
+
+# Physical Setup
+
+- The S32K144-EVB needs an external 12V supply to power the CAN transciever
+
diff --git a/examples/s32k144/bsp.c b/examples/s32k144/bsp.c
new file mode 100644
index 0000000..ed888e3
--- /dev/null
+++ b/examples/s32k144/bsp.c
@@ -0,0 +1,685 @@
+#include "pins_driver.h"
+#include "clock.h"
+#include "edma_driver.h"
+#include "flexcan_driver.h"
+#include "system_S32K144.h"
+
+/*! @brief User number of configured pins */
+#define NUM_OF_CONFIGURED_PINS 12
+
+/*! @brief User configuration structure */
+const static pin_settings_config_t g_pin_mux_InitConfigArr[NUM_OF_CONFIGURED_PINS] = {
+ {
+ .base = PORTD,
+ .pinPortIdx = 0u,
+ .pullConfig = PORT_INTERNAL_PULL_NOT_ENABLED,
+ .passiveFilter = false,
+ .driveSelect = PORT_LOW_DRIVE_STRENGTH,
+ .mux = PORT_MUX_AS_GPIO,
+ .pinLock = false,
+ .intConfig = PORT_DMA_INT_DISABLED,
+ .clearIntFlag = false,
+ .gpioBase = PTD,
+ .direction = GPIO_OUTPUT_DIRECTION,
+ .digitalFilter = false,
+ .initValue = 0u,
+ },
+ {
+ .base = PORTE,
+ .pinPortIdx = 5u,
+ .pullConfig = PORT_INTERNAL_PULL_NOT_ENABLED,
+ .passiveFilter = false,
+ .driveSelect = PORT_LOW_DRIVE_STRENGTH,
+ .mux = PORT_MUX_ALT5,
+ .pinLock = false,
+ .intConfig = PORT_DMA_INT_DISABLED,
+ .clearIntFlag = false,
+ .gpioBase = NULL,
+ .digitalFilter = false,
+ },
+ {
+ .base = PORTE,
+ .pinPortIdx = 4u,
+ .pullConfig = PORT_INTERNAL_PULL_NOT_ENABLED,
+ .passiveFilter = false,
+ .driveSelect = PORT_LOW_DRIVE_STRENGTH,
+ .mux = PORT_MUX_ALT5,
+ .pinLock = false,
+ .intConfig = PORT_DMA_INT_DISABLED,
+ .clearIntFlag = false,
+ .gpioBase = NULL,
+ .digitalFilter = false,
+ },
+ {
+ .base = PORTD,
+ .pinPortIdx = 16u,
+ .pullConfig = PORT_INTERNAL_PULL_NOT_ENABLED,
+ .passiveFilter = false,
+ .driveSelect = PORT_LOW_DRIVE_STRENGTH,
+ .mux = PORT_MUX_AS_GPIO,
+ .pinLock = false,
+ .intConfig = PORT_DMA_INT_DISABLED,
+ .clearIntFlag = false,
+ .gpioBase = PTD,
+ .direction = GPIO_OUTPUT_DIRECTION,
+ .digitalFilter = false,
+ .initValue = 0u,
+ },
+ {
+ .base = PORTD,
+ .pinPortIdx = 15u,
+ .pullConfig = PORT_INTERNAL_PULL_NOT_ENABLED,
+ .passiveFilter = false,
+ .driveSelect = PORT_LOW_DRIVE_STRENGTH,
+ .mux = PORT_MUX_AS_GPIO,
+ .pinLock = false,
+ .intConfig = PORT_DMA_INT_DISABLED,
+ .clearIntFlag = false,
+ .gpioBase = PTD,
+ .direction = GPIO_OUTPUT_DIRECTION,
+ .digitalFilter = false,
+ .initValue = 0u,
+ },
+ {
+ .base = PORTC,
+ .pinPortIdx = 3u,
+ .pullConfig = PORT_INTERNAL_PULL_NOT_ENABLED,
+ .passiveFilter = false,
+ .driveSelect = PORT_LOW_DRIVE_STRENGTH,
+ .mux = PORT_MUX_AS_GPIO,
+ .pinLock = false,
+ .intConfig = PORT_DMA_INT_DISABLED,
+ .clearIntFlag = false,
+ .gpioBase = PTC,
+ .direction = GPIO_OUTPUT_DIRECTION,
+ .digitalFilter = false,
+ .initValue = 0u,
+ },
+ {
+ .base = PORTC,
+ .pinPortIdx = 2u,
+ .pullConfig = PORT_INTERNAL_PULL_NOT_ENABLED,
+ .passiveFilter = false,
+ .driveSelect = PORT_LOW_DRIVE_STRENGTH,
+ .mux = PORT_MUX_AS_GPIO,
+ .pinLock = false,
+ .intConfig = PORT_DMA_INT_DISABLED,
+ .clearIntFlag = false,
+ .gpioBase = PTC,
+ .direction = GPIO_OUTPUT_DIRECTION,
+ .digitalFilter = false,
+ .initValue = 0u,
+ },
+ {
+ .base = PORTC,
+ .pinPortIdx = 1u,
+ .pullConfig = PORT_INTERNAL_PULL_NOT_ENABLED,
+ .passiveFilter = false,
+ .driveSelect = PORT_LOW_DRIVE_STRENGTH,
+ .mux = PORT_MUX_AS_GPIO,
+ .pinLock = false,
+ .intConfig = PORT_DMA_INT_DISABLED,
+ .clearIntFlag = false,
+ .gpioBase = PTC,
+ .direction = GPIO_OUTPUT_DIRECTION,
+ .digitalFilter = false,
+ .initValue = 0u,
+ },
+ {
+ .base = PORTC,
+ .pinPortIdx = 0u,
+ .pullConfig = PORT_INTERNAL_PULL_NOT_ENABLED,
+ .passiveFilter = false,
+ .driveSelect = PORT_LOW_DRIVE_STRENGTH,
+ .mux = PORT_MUX_AS_GPIO,
+ .pinLock = false,
+ .intConfig = PORT_DMA_INT_DISABLED,
+ .clearIntFlag = false,
+ .gpioBase = PTC,
+ .direction = GPIO_OUTPUT_DIRECTION,
+ .digitalFilter = false,
+ .initValue = 0u,
+ },
+ {
+ .base = PORTC,
+ .pinPortIdx = 14u,
+ .pullConfig = PORT_INTERNAL_PULL_NOT_ENABLED,
+ .passiveFilter = false,
+ .driveSelect = PORT_LOW_DRIVE_STRENGTH,
+ .mux = PORT_PIN_DISABLED,
+ .pinLock = false,
+ .intConfig = PORT_INT_RISING_EDGE,
+ .clearIntFlag = false,
+ .gpioBase = NULL,
+ .digitalFilter = false,
+ },
+ {
+ .base = PORTC,
+ .pinPortIdx = 13u,
+ .pullConfig = PORT_INTERNAL_PULL_NOT_ENABLED,
+ .passiveFilter = false,
+ .driveSelect = PORT_LOW_DRIVE_STRENGTH,
+ .mux = PORT_MUX_AS_GPIO,
+ .pinLock = false,
+ .intConfig = PORT_INT_RISING_EDGE,
+ .clearIntFlag = false,
+ .gpioBase = PTC,
+ .direction = GPIO_INPUT_DIRECTION,
+ .digitalFilter = false,
+ },
+ {
+ .base = PORTC,
+ .pinPortIdx = 12u,
+ .pullConfig = PORT_INTERNAL_PULL_NOT_ENABLED,
+ .passiveFilter = false,
+ .driveSelect = PORT_LOW_DRIVE_STRENGTH,
+ .mux = PORT_MUX_AS_GPIO,
+ .pinLock = false,
+ .intConfig = PORT_DMA_INT_DISABLED,
+ .clearIntFlag = false,
+ .gpioBase = PTC,
+ .direction = GPIO_INPUT_DIRECTION,
+ .digitalFilter = false,
+ },
+};
+
+#define LED_PORT PORTD
+#define GPIO_PORT PTD
+#define PCC_INDEX PCC_PORTD_INDEX
+#define LED0 15U
+#define LED1 16U
+#define LED2 0U
+
+#define BTN_GPIO PTC
+#define BTN1_PIN 13U
+#define BTN2_PIN 12U
+#define BTN_PORT PORTC
+#define BTN_PORT_IRQn PORTC_IRQn
+
+/*
+ * @brief Function which configures the LEDs and Buttons
+ */
+static void GPIOInit(void) {
+ /* Output direction for LEDs */
+ PINS_DRV_SetPinsDirection(GPIO_PORT, (1 << LED2) | (1 << LED1) | (1 << LED0));
+
+ /* Set Output value LEDs */
+ // PINS_DRV_ClearPins(GPIO_PORT, 1 << LED1);
+ PINS_DRV_SetPins(GPIO_PORT, (1 << LED2) | (1 << LED1) | (1 << LED0));
+
+ /* Setup button pin */
+ PINS_DRV_SetPinsDirection(BTN_GPIO, ~((1 << BTN1_PIN) | (1 << BTN2_PIN)));
+
+ /* Setup button pins interrupt */
+ PINS_DRV_SetPinIntSel(BTN_PORT, BTN1_PIN, PORT_INT_RISING_EDGE);
+ PINS_DRV_SetPinIntSel(BTN_PORT, BTN2_PIN, PORT_INT_RISING_EDGE);
+
+ // /* Install buttons ISR */
+ // INT_SYS_InstallHandler(BTN_PORT_IRQn, &buttonISR, NULL);
+
+ // /* Enable buttons interrupt */
+ // INT_SYS_EnableIRQ(BTN_PORT_IRQn);
+}
+
+#define INST_CANCOM1 (0U)
+static flexcan_state_t canCom1_State;
+
+const flexcan_user_config_t canCom1_InitConfig0 = {
+ .fd_enable = true,
+ .pe_clock = FLEXCAN_CLK_SOURCE_OSC,
+ .max_num_mb = 16,
+ .num_id_filters = FLEXCAN_RX_FIFO_ID_FILTERS_8,
+ .is_rx_fifo_needed = false,
+ .flexcanMode = FLEXCAN_NORMAL_MODE,
+ .payload = FLEXCAN_PAYLOAD_SIZE_16,
+ .bitrate = {.propSeg = 7, .phaseSeg1 = 4, .phaseSeg2 = 1, .preDivider = 0, .rJumpwidth = 1},
+ .bitrate_cbt = {.propSeg = 7, .phaseSeg1 = 4, .phaseSeg2 = 1, .preDivider = 0, .rJumpwidth = 1},
+ .transfer_type = FLEXCAN_RXFIFO_USING_INTERRUPTS,
+ .rxFifoDMAChannel = 0U};
+
+#define TX_MAILBOX (1UL)
+#define TX_MSG_ID (1UL)
+#define RX_MAILBOX (0UL)
+#define RX_MSG_ID (2UL)
+static flexcan_msgbuff_t recvBuff;
+typedef enum { LED0_CHANGE_REQUESTED = 0x00U, LED1_CHANGE_REQUESTED = 0x01U } can_commands_list;
+
+uint8_t ledRequested = (uint8_t)LED0_CHANGE_REQUESTED;
+uint8_t callback_test = 0;
+
+void flexcan0_Callback(uint8_t instance, flexcan_event_type_t eventType, uint32_t buffIdx,
+ flexcan_state_t *flexcanState) {
+
+ (void)flexcanState;
+ (void)instance;
+
+ switch (eventType) {
+ case FLEXCAN_EVENT_RX_COMPLETE:
+ callback_test |= 0x1; // set bit0 to to evidence RX was complete
+ if (buffIdx == RX_MAILBOX) {
+ if ((recvBuff.data[0] == LED0_CHANGE_REQUESTED) && recvBuff.msgId == RX_MSG_ID) {
+ /* Toggle output value LED1 */
+ PINS_DRV_TogglePins(GPIO_PORT, (1 << LED0));
+ } else if ((recvBuff.data[0] == LED1_CHANGE_REQUESTED) && recvBuff.msgId == RX_MSG_ID) {
+ /* Toggle output value LED0 */
+ PINS_DRV_TogglePins(GPIO_PORT, (1 << LED1));
+ }
+ /* Start receiving data in RX_MAILBOX again. */
+ FLEXCAN_DRV_Receive(INST_CANCOM1, RX_MAILBOX, &recvBuff);
+ }
+
+ break;
+ case FLEXCAN_EVENT_RXFIFO_COMPLETE:
+ break;
+ case FLEXCAN_EVENT_DMA_COMPLETE:
+ break;
+ case FLEXCAN_EVENT_TX_COMPLETE:
+ callback_test |= 0x2; // set bit1 to to evidence TX was complete
+ PINS_DRV_SetPins(GPIO_PORT, 1 << LED2);
+ break;
+ default:
+ break;
+ }
+}
+
+void flexcan0_ErrorCallback(uint8_t instance, flexcan_event_type_t eventType,
+ flexcan_state_t *flexcanState) {
+ volatile uint32_t error;
+
+ (void)flexcanState;
+ (void)instance;
+
+ switch (eventType) {
+ case FLEXCAN_EVENT_ERROR:
+ callback_test |= 0x4; // set bit2 to to evidence error ISR hit
+
+ error = FLEXCAN_DRV_GetErrorStatus(INST_CANCOM1);
+
+ if (error & 0x4) // if BOFFINT was set
+ {
+ callback_test |= 0x8; // set bit3 to to evidence bus off ISR hit
+
+ // abort TX MB, after bus off recovery message is not send
+ FLEXCAN_DRV_AbortTransfer(INST_CANCOM1, TX_MAILBOX);
+
+ PINS_DRV_ClearPins(GPIO_PORT, 1 << LED2);
+ }
+
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*
+ * @brief: Send data via CAN to the specified mailbox with the specified message id
+ * @param mailbox : Destination mailbox number
+ * @param messageId : Message ID
+ * @param data : Pointer to the TX data
+ * @param len : Length of the TX data
+ * @return : None
+ */
+status_t SendCANData(uint32_t mailbox, uint32_t messageId, uint8_t *data, uint32_t len) {
+ /* Set information about the data to be sent
+ * - 1 byte in length
+ * - Standard message ID
+ * - Bit rate switch enabled to use a different bitrate for the data segment
+ * - Flexible data rate enabled
+ * - Use zeros for FD padding
+ */
+ flexcan_data_info_t dataInfo = {.data_length = len,
+ .msg_id_type = FLEXCAN_MSG_ID_STD,
+ .enable_brs = true,
+ .fd_enable = false,
+ .fd_padding = 0U};
+
+ /* Configure TX message buffer with index TX_MSG_ID and TX_MAILBOX*/
+ FLEXCAN_DRV_ConfigTxMb(INST_CANCOM1, mailbox, &dataInfo, messageId);
+
+ /* Execute send non-blocking */
+ status_t status = FLEXCAN_DRV_Send(INST_CANCOM1, mailbox, &dataInfo, messageId, data);
+ return status;
+}
+
+int BSPSendCAN(uint32_t id, uint8_t *data, uint32_t len) {
+ return SendCANData(TX_MAILBOX, id, data, len);
+}
+
+/*
+ * @brief Initialize FlexCAN driver and configure the bit rate
+ */
+void FlexCANInit(void) {
+ /*
+ * Initialize FlexCAN driver
+ * - 8 byte payload size
+ * - FD enabled
+ * - Bus clock as peripheral engine clock
+ */
+ status_t status = FLEXCAN_DRV_Init(INST_CANCOM1, &canCom1_State, &canCom1_InitConfig0);
+ DEV_ASSERT(STATUS_SUCCESS == status);
+ FLEXCAN_DRV_InstallEventCallback(INST_CANCOM1, (flexcan_callback_t)flexcan0_Callback,
+ (void *)NULL);
+ FLEXCAN_DRV_InstallErrorCallback(INST_CANCOM1, (flexcan_error_callback_t)flexcan0_ErrorCallback,
+ (void *)NULL);
+}
+
+/*! @brief Count of user configuration structures */
+#define CLOCK_MANAGER_CONFIG_CNT 1U
+
+/*! @brief Count of peripheral clock user configurations */
+#define NUM_OF_PERIPHERAL_CLOCKS_0 13U
+
+/*! @brief Count of user Callbacks */
+#define CLOCK_MANAGER_CALLBACK_CNT 0U
+
+peripheral_clock_config_t peripheralClockConfig0[NUM_OF_PERIPHERAL_CLOCKS_0] = {
+ {
+ .clockName = DMAMUX0_CLK,
+ .clkGate = true,
+ .clkSrc = CLK_SRC_OFF,
+ .frac = MULTIPLY_BY_ONE,
+ .divider = DIVIDE_BY_ONE,
+ },
+ {
+ .clockName = FlexCAN0_CLK,
+ .clkGate = true,
+ .clkSrc = CLK_SRC_OFF,
+ .frac = MULTIPLY_BY_ONE,
+ .divider = DIVIDE_BY_ONE,
+ },
+ {
+ .clockName = FlexCAN1_CLK,
+ .clkGate = true,
+ .clkSrc = CLK_SRC_OFF,
+ .frac = MULTIPLY_BY_ONE,
+ .divider = DIVIDE_BY_ONE,
+ },
+ {
+ .clockName = FlexCAN2_CLK,
+ .clkGate = true,
+ .clkSrc = CLK_SRC_OFF,
+ .frac = MULTIPLY_BY_ONE,
+ .divider = DIVIDE_BY_ONE,
+ },
+ {
+ .clockName = FTFC0_CLK,
+ .clkGate = true,
+ .clkSrc = CLK_SRC_OFF,
+ .frac = MULTIPLY_BY_ONE,
+ .divider = DIVIDE_BY_ONE,
+ },
+ {
+ .clockName = LPSPI0_CLK,
+ .clkGate = true,
+ .clkSrc = CLK_SRC_SIRC_DIV2,
+ .frac = MULTIPLY_BY_ONE,
+ .divider = DIVIDE_BY_ONE,
+ },
+ {
+ .clockName = LPSPI1_CLK,
+ .clkGate = true,
+ .clkSrc = CLK_SRC_SIRC_DIV2,
+ .frac = MULTIPLY_BY_ONE,
+ .divider = DIVIDE_BY_ONE,
+ },
+ {
+ .clockName = LPSPI2_CLK,
+ .clkGate = true,
+ .clkSrc = CLK_SRC_SIRC_DIV2,
+ .frac = MULTIPLY_BY_ONE,
+ .divider = DIVIDE_BY_ONE,
+ },
+ {
+ .clockName = PORTA_CLK,
+ .clkGate = true,
+ .clkSrc = CLK_SRC_OFF,
+ .frac = MULTIPLY_BY_ONE,
+ .divider = DIVIDE_BY_ONE,
+ },
+ {
+ .clockName = PORTB_CLK,
+ .clkGate = true,
+ .clkSrc = CLK_SRC_OFF,
+ .frac = MULTIPLY_BY_ONE,
+ .divider = DIVIDE_BY_ONE,
+ },
+ {
+ .clockName = PORTC_CLK,
+ .clkGate = true,
+ .clkSrc = CLK_SRC_OFF,
+ .frac = MULTIPLY_BY_ONE,
+ .divider = DIVIDE_BY_ONE,
+ },
+ {
+ .clockName = PORTD_CLK,
+ .clkGate = true,
+ .clkSrc = CLK_SRC_OFF,
+ .frac = MULTIPLY_BY_ONE,
+ .divider = DIVIDE_BY_ONE,
+ },
+ {
+ .clockName = PORTE_CLK,
+ .clkGate = true,
+ .clkSrc = CLK_SRC_OFF,
+ .frac = MULTIPLY_BY_ONE,
+ .divider = DIVIDE_BY_ONE,
+ },
+};
+
+/* *************************************************************************
+ * Configuration structure for Clock Configuration 0
+ * ************************************************************************* */
+/*! @brief User Configuration structure clockMan1_InitConfig0 */
+clock_manager_user_config_t clockMan1_InitConfig0 = {
+ /*! @brief Configuration of SIRC */
+ .scgConfig =
+ {
+ .sircConfig =
+ {
+ .initialize = true, /*!< Initialize */
+ /* SIRCCSR */
+ .enableInStop = true, /*!< SIRCSTEN */
+ .enableInLowPower = true, /*!< SIRCLPEN */
+ .locked = false, /*!< LK */
+ /* SIRCCFG */
+ .range = SCG_SIRC_RANGE_HIGH, /*!< RANGE - High range (8 MHz) */
+ /* SIRCDIV */
+ .div1 = SCG_ASYNC_CLOCK_DIV_BY_1, /*!< SIRCDIV1 */
+ .div2 = SCG_ASYNC_CLOCK_DIV_BY_1, /*!< SIRCDIV2 */
+ },
+ .fircConfig =
+ {
+ .initialize = true, /*!< Initialize */
+ /* FIRCCSR */
+ .regulator = true, /*!< FIRCREGOFF */
+ .locked = false, /*!< LK */
+ /* FIRCCFG */
+ .range = SCG_FIRC_RANGE_48M, /*!< RANGE */
+ /* FIRCDIV */
+ .div1 = SCG_ASYNC_CLOCK_DIV_BY_1, /*!< FIRCDIV1 */
+ .div2 = SCG_ASYNC_CLOCK_DIV_BY_1, /*!< FIRCDIV2 */
+ },
+ .rtcConfig =
+ {
+ .initialize = true, /*!< Initialize */
+ .rtcClkInFreq = 0U, /*!< RTC_CLKIN */
+ },
+ .soscConfig =
+ {
+ .initialize = true, /*!< Initialize */
+ .freq = 8000000U, /*!< Frequency */
+ /* SOSCCSR */
+ .monitorMode = SCG_SOSC_MONITOR_DISABLE, /*!< SOSCCM */
+ .locked = false, /*!< LK */
+ /* SOSCCFG */
+ .extRef = SCG_SOSC_REF_OSC, /*!< EREFS */
+ .gain = SCG_SOSC_GAIN_LOW, /*!< HGO */
+ .range = SCG_SOSC_RANGE_HIGH, /*!< RANGE */
+ /* SOSCDIV */
+ .div1 = SCG_ASYNC_CLOCK_DIV_BY_1, /*!< SOSCDIV1 */
+ .div2 = SCG_ASYNC_CLOCK_DIV_BY_1, /*!< SOSCDIV2 */
+ },
+ .spllConfig =
+ {
+ .initialize = true, /*!< Initialize */
+ /* SPLLCSR */
+ .monitorMode = SCG_SPLL_MONITOR_DISABLE, /*!< SPLLCM */
+ .locked = false, /*!< LK */
+ /* SPLLCFG */
+ .prediv = (uint8_t)SCG_SPLL_CLOCK_PREDIV_BY_1, /*!< PREDIV */
+ .mult = (uint8_t)SCG_SPLL_CLOCK_MULTIPLY_BY_28, /*!< MULT */
+ .src = 0U, /*!< SOURCE */
+ /* SPLLDIV */
+ .div1 = SCG_ASYNC_CLOCK_DIV_BY_1, /*!< SPLLDIV1 */
+ .div2 = SCG_ASYNC_CLOCK_DIV_BY_1, /*!< SPLLDIV2 */
+ },
+ .clockOutConfig =
+ {
+ .initialize = true, /*!< Initialize */
+ .source = SCG_CLOCKOUT_SRC_FIRC, /*!< SCG CLKOUTSEL */
+ },
+ .clockModeConfig =
+ {
+ .initialize = true, /*!< Initialize */
+ .rccrConfig = /*!< RCCR - Run Clock Control Register */
+ {
+ .src = SCG_SYSTEM_CLOCK_SRC_FIRC, /*!< SCS */
+ .divCore = SCG_SYSTEM_CLOCK_DIV_BY_1, /*!< DIVCORE */
+ .divBus = SCG_SYSTEM_CLOCK_DIV_BY_2, /*!< DIVBUS */
+ .divSlow = SCG_SYSTEM_CLOCK_DIV_BY_2, /*!< DIVSLOW */
+ },
+ .vccrConfig = /*!< VCCR - VLPR Clock Control Register */
+ {
+ .src = SCG_SYSTEM_CLOCK_SRC_SIRC, /*!< SCS */
+ .divCore = SCG_SYSTEM_CLOCK_DIV_BY_2, /*!< DIVCORE */
+ .divBus = SCG_SYSTEM_CLOCK_DIV_BY_1, /*!< DIVBUS */
+ .divSlow = SCG_SYSTEM_CLOCK_DIV_BY_4, /*!< DIVSLOW */
+ },
+ .hccrConfig = /*!< HCCR - HSRUN Clock Control Register */
+ {
+ .src = SCG_SYSTEM_CLOCK_SRC_SYS_PLL, /*!< SCS */
+ .divCore = SCG_SYSTEM_CLOCK_DIV_BY_1, /*!< DIVCORE */
+ .divBus = SCG_SYSTEM_CLOCK_DIV_BY_2, /*!< DIVBUS */
+ .divSlow = SCG_SYSTEM_CLOCK_DIV_BY_4, /*!< DIVSLOW */
+ },
+ },
+ },
+ .pccConfig =
+ {
+ .peripheralClocks =
+ peripheralClockConfig0, /*!< Peripheral clock control configurations */
+ .count = NUM_OF_PERIPHERAL_CLOCKS_0, /*!< Number of the peripheral clock control
+ configurations */
+ },
+ .simConfig =
+ {
+ .clockOutConfig = /*!< Clock Out configuration. */
+ {
+ .initialize = true, /*!< Initialize */
+ .enable = false, /*!< CLKOUTEN */
+ .source = SIM_CLKOUT_SEL_SYSTEM_SCG_CLKOUT, /*!< CLKOUTSEL */
+ .divider = SIM_CLKOUT_DIV_BY_1, /*!< CLKOUTDIV */
+ },
+ .lpoClockConfig = /*!< Low Power Clock configuration. */
+ {
+ .initialize = true, /*!< Initialize */
+ .enableLpo1k = true, /*!< LPO1KCLKEN */
+ .enableLpo32k = true, /*!< LPO32KCLKEN */
+ .sourceLpoClk = SIM_LPO_CLK_SEL_LPO_128K, /*!< LPOCLKSEL */
+ .sourceRtcClk = SIM_RTCCLK_SEL_SOSCDIV1_CLK, /*!< RTCCLKSEL */
+ },
+ .platGateConfig = /*!< Platform Gate Clock configuration. */
+ {
+ .initialize = true, /*!< Initialize */
+ .enableMscm = true, /*!< CGCMSCM */
+ .enableMpu = true, /*!< CGCMPU */
+ .enableDma = true, /*!< CGCDMA */
+ .enableErm = true, /*!< CGCERM */
+ .enableEim = true, /*!< CGCEIM */
+ },
+
+ .qspiRefClkGating = /*!< Quad Spi Internal Reference Clock Gating. */
+ {
+ .enableQspiRefClk = false, /*!< Qspi reference clock gating */
+ },
+ .tclkConfig = /*!< TCLK CLOCK configuration. */
+ {
+ .initialize = true, /*!< Initialize */
+ .tclkFreq[0] = 0U, /*!< TCLK0 */
+ .tclkFreq[1] = 0U, /*!< TCLK1 */
+ .tclkFreq[2] = 0U, /*!< TCLK2 */
+ },
+ .traceClockConfig = /*!< Debug trace Clock Configuration. */
+ {
+ .initialize = true, /*!< Initialize */
+ .divEnable = true, /*!< TRACEDIVEN */
+ .source = CLOCK_TRACE_SRC_CORE_CLK, /*!< TRACECLK_SEL */
+ .divider = 0U, /*!< TRACEDIV */
+ .divFraction = false, /*!< TRACEFRAC */
+ },
+ },
+ .pmcConfig =
+ {
+ .lpoClockConfig = /*!< Low Power Clock configuration. */
+ {
+ .initialize = true, /*!< Initialize */
+ .enable = true, /*!< Enable/disable LPO */
+ .trimValue = 0, /*!< Trimming value for LPO */
+ },
+ },
+};
+
+/*! @brief Array of pointers to User configuration structures */
+clock_manager_user_config_t const *g_clockManConfigsArr[] = {&clockMan1_InitConfig0};
+/*! @brief Array of pointers to User defined Callbacks configuration structures */
+clock_manager_callback_user_config_t *g_clockManCallbacksArr[] = {(void *)0};
+/* END clockMan1. */
+
+void BSPInit(void) {
+ S32_SysTick->CSR = S32_SysTick_CSR_ENABLE(0u);
+ S32_SysTick->RVR = S32_SysTick_RVR_RELOAD(SystemCoreClock / 1000u);
+ // /* only initialize CVR on the first entry, to not cause time drift */
+ S32_SysTick->CVR = S32_SysTick_CVR_CURRENT(0U);
+ S32_SysTick->CSR =
+ S32_SysTick_CSR_ENABLE(1u) | S32_SysTick_CSR_TICKINT(1u) | S32_SysTick_CSR_CLKSOURCE(1u);
+
+ CLOCK_SYS_Init(g_clockManConfigsArr, CLOCK_MANAGER_CONFIG_CNT, g_clockManCallbacksArr,
+ CLOCK_MANAGER_CALLBACK_CNT);
+ CLOCK_SYS_UpdateConfiguration(0U, CLOCK_MANAGER_POLICY_FORCIBLE);
+
+ PINS_DRV_Init(NUM_OF_CONFIGURED_PINS, g_pin_mux_InitConfigArr);
+
+ GPIOInit();
+ FlexCANInit();
+}
+
+int BSPSetLED(uint8_t led, bool value) {
+ if (led > 2) {
+ return -1;
+ }
+ int led_shift = LED0;
+
+ switch (led) {
+ case 0:
+ led_shift = LED0;
+ break;
+ case 1:
+ led_shift = LED1;
+ break;
+ case 2:
+ led_shift = LED2;
+ break;
+ default:
+ return -1;
+ }
+
+ if (value) {
+ PINS_DRV_SetPins(GPIO_PORT, 1 << led_shift);
+ } else {
+ PINS_DRV_ClearPins(GPIO_PORT, 1 << led_shift);
+ }
+ return 0;
+}
+
+uint32_t UDSMillis(void) { return OSIF_GetMilliseconds(); }
diff --git a/examples/s32k144/bsp.h b/examples/s32k144/bsp.h
new file mode 100644
index 0000000..eea031a
--- /dev/null
+++ b/examples/s32k144/bsp.h
@@ -0,0 +1,11 @@
+#ifndef BSP_H
+#define BSP_H
+
+#include
+#include
+
+void BSPInit(void);
+int BSPSetLED(uint8_t led, bool value);
+int BSPSendCAN(uint32_t id, uint8_t *data, uint32_t len);
+
+#endif
diff --git a/examples/s32k144/main.c b/examples/s32k144/main.c
new file mode 100644
index 0000000..478f4c5
--- /dev/null
+++ b/examples/s32k144/main.c
@@ -0,0 +1,55 @@
+#include
+#include "bsp.h"
+#include "iso14229.h"
+#include "tp/isotp_c.h"
+
+UDSServer_t server;
+UDSTpISOTpC_t tp;
+
+static int isotp_user_send_can(const uint32_t arbitration_id, const uint8_t *data,
+ const uint8_t size, void *user_data) {
+ if (0 != BSPSendCAN(arbitration_id, data, size)) {
+ return ISOTP_RET_ERROR;
+ } else {
+ return ISOTP_RET_OK;
+ }
+}
+
+static void isotp_debug(const char *msg, ...) {
+ // BSPLog("%s", msg);
+}
+
+static uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
+ return kPositiveResponse;
+}
+
+int main() {
+ BSPInit();
+ UDSServerInit(&server);
+ server.fn = fn;
+ server.tp = &tp.hdl;
+
+ UDSTpISOTpCInit(&tp, &(UDSTpISOTpCConfig_t){
+ .source_addr = 0x7E8,
+ .target_addr = 0x7E0,
+ .source_addr_func = 0x7DF,
+ .target_addr_func = 0,
+ .user_data = NULL,
+ .isotp_user_send_can = isotp_user_send_can,
+ .isotp_user_debug = isotp_debug,
+ });
+
+ uint8_t data[] = {0xf0, 0xf0};
+ while (1) {
+ UDSServerPoll(&server);
+ BSPSetLED(0, true);
+ for (volatile int i = 0; i < 1000000; i++) {
+ __asm__("nop");
+ }
+ BSPSetLED(0, false);
+ for (volatile int i = 0; i < 1000000; i++) {
+ __asm__("nop");
+ }
+ BSPSendCAN(0x123, data, sizeof(data));
+ }
+}
\ No newline at end of file
diff --git a/iso14229.c b/iso14229.c
index 9bbc307..1bc1f5c 100644
--- a/iso14229.c
+++ b/iso14229.c
@@ -78,17 +78,17 @@ enum UDSDiagnosticServiceId {
// ========================================================================
/**
- * @brief
- *
- * @param hdl
+ * @brief
+ *
+ * @param hdl
* @param info, if NULL, the default values are used:
* A_Mtype: message type (diagnostic (DEFAULT), remote diagnostic, secure diagnostic, secure
- * remote diagnostic)
- * A_TA_Type: application target address type (physical (DEFAULT) or functional)
- * A_SA: unused
- * A_TA: unused
- * A_AE: unused
- * @return ssize_t
+ * remote diagnostic)
+ * A_TA_Type: application target address type (physical (DEFAULT) or functional)
+ * A_SA: unused
+ * A_TA: unused
+ * A_AE: unused
+ * @return ssize_t
*/
ssize_t UDSTpGetSendBuf(struct UDSTpHandle *hdl, uint8_t **buf) {
assert(hdl);
@@ -98,7 +98,7 @@ ssize_t UDSTpGetSendBuf(struct UDSTpHandle *hdl, uint8_t **buf) {
ssize_t UDSTpSend(struct UDSTpHandle *hdl, const uint8_t *buf, ssize_t len, UDSSDU_t *info) {
assert(hdl);
assert(hdl->send);
- return hdl->send(hdl, (uint8_t*)buf, len, info);
+ return hdl->send(hdl, (uint8_t *)buf, len, info);
}
UDSTpStatus_t UDSTpPoll(struct UDSTpHandle *hdl) {
@@ -192,7 +192,6 @@ static uint8_t EmitEvent(UDSServer_t *srv, UDSServerEvent_t evt, void *data) {
}
}
-
static uint8_t _0x10_DiagnosticSessionControl(UDSServer_t *srv, UDSReq_t *r) {
if (r->recv_len < UDS_0X10_REQ_LEN) {
return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
@@ -806,8 +805,7 @@ static uint8_t _0x37_RequestTransferExit(UDSServer_t *srv, UDSReq_t *r) {
}
static uint8_t _0x3E_TesterPresent(UDSServer_t *srv, UDSReq_t *r) {
- if ((r->recv_len < UDS_0X3E_REQ_MIN_LEN) ||
- (r->recv_len > UDS_0X3E_REQ_MAX_LEN)) {
+ if ((r->recv_len < UDS_0X3E_REQ_MIN_LEN) || (r->recv_len > UDS_0X3E_REQ_MAX_LEN)) {
return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
}
uint8_t zeroSubFunction = r->recv_buf[1];
@@ -1039,8 +1037,8 @@ void UDSServerPoll(UDSServer_t *srv) {
if (srv->requestInProgress) {
if (srv->RCRRP) {
- // responds only if
- // 1. changed (no longer RCRRP), or
+ // responds only if
+ // 1. changed (no longer RCRRP), or
// 2. p2_timer has elapsed
uint8_t response = evaluateServiceResponse(srv, r);
if (kRequestCorrectlyReceived_ResponsePending == response) {
@@ -1061,13 +1059,13 @@ void UDSServerPoll(UDSServer_t *srv) {
ssize_t ret = UDSTpSend(srv->tp, r->send_buf, r->send_len, NULL);
// TODO test injection of transport errors:
if (ret < 0) {
- UDSErr_t err = UDS_ERR_TPORT;
+ UDSErr_t err = UDS_ERR_TPORT;
EmitEvent(srv, UDS_SRV_EVT_Err, &err);
UDS_DBG_PRINT("UDSTpSend failed with %ld\n", ret);
}
if (srv->RCRRP) {
- // ISO14229-2:2013 Table 4 footnote b
+ // ISO14229-2:2013 Table 4 footnote b
// min time between consecutive 0x78 responses is 0.3 * p2*
uint32_t wait_time = srv->p2_star_ms * 3 / 10;
srv->p2_timer = UDSMillis() + wait_time;
@@ -1081,11 +1079,11 @@ void UDSServerPoll(UDSServer_t *srv) {
} else {
if (srv->notReadyToReceive) {
return; // cannot respond to request right now
- }
+ }
r->recv_len = UDSTpPeek(srv->tp, &r->recv_buf, &r->info);
r->send_buf_size = UDSTpGetSendBuf(srv->tp, &r->send_buf);
if (r->send_buf == NULL || r->recv_buf == NULL) {
- UDSErr_t err = UDS_ERR_TPORT;
+ UDSErr_t err = UDS_ERR_TPORT;
EmitEvent(srv, UDS_SRV_EVT_Err, &err);
UDS_DBG_PRINT("bad tport\n");
return;
@@ -1100,7 +1098,6 @@ void UDSServerPoll(UDSServer_t *srv) {
}
}
-
// ========================================================================
// Client
// ========================================================================
@@ -1135,11 +1132,11 @@ static const char *ClientStateName(enum UDSClientRequestState state) {
return "Idle";
case kRequestStateSending:
return "Sending";
- case kRequestStateAwaitSendComplete:
+ case kRequestStateAwaitSendComplete:
return "AwaitSendComplete";
case kRequestStateAwaitResponse:
return "AwaitResponse";
- case kRequestStateProcessResponse:
+ case kRequestStateProcessResponse:
return "ProcessResponse";
default:
return "Unknown";
@@ -1147,7 +1144,8 @@ static const char *ClientStateName(enum UDSClientRequestState state) {
}
static void changeState(UDSClient_t *client, enum UDSClientRequestState state) {
- printf("client state: %s (%d) -> %s (%d)\n", ClientStateName(client->state), client->state, ClientStateName(state), state);
+ printf("client state: %s (%d) -> %s (%d)\n", ClientStateName(client->state), client->state,
+ ClientStateName(state), state);
client->state = state;
}
@@ -1259,8 +1257,8 @@ static void PollLowLevel(UDSClient_t *client) {
break;
}
case kRequestStateSending: {
- UDSTpAddr_t ta_type =
- client->_options_copy & UDS_FUNCTIONAL ? UDS_A_TA_TYPE_FUNCTIONAL : UDS_A_TA_TYPE_PHYSICAL;
+ UDSTpAddr_t ta_type = client->_options_copy & UDS_FUNCTIONAL ? UDS_A_TA_TYPE_FUNCTIONAL
+ : UDS_A_TA_TYPE_PHYSICAL;
UDSSDU_t info = {
.A_Mtype = UDS_A_MTYPE_DIAG,
.A_TA_Type = ta_type,
@@ -1349,7 +1347,6 @@ static UDSErr_t _SendRequest(UDSClient_t *client) {
return UDS_OK;
}
-
static UDSErr_t PreRequestCheck(UDSClient_t *client) {
if (kRequestStateIdle != client->state) {
return UDS_ERR_BUSY;
@@ -1368,9 +1365,9 @@ static UDSErr_t PreRequestCheck(UDSClient_t *client) {
UDSErr_t UDSSendBytes(UDSClient_t *client, const uint8_t *data, uint16_t size) {
UDSErr_t err = PreRequestCheck(client);
-if (err) {
- return err;
-}
+ if (err) {
+ return err;
+ }
if (size > client->send_buf_size) {
return UDS_ERR_BUFSIZ;
}
@@ -1381,9 +1378,9 @@ if (err) {
UDSErr_t UDSSendECUReset(UDSClient_t *client, UDSECUReset_t type) {
UDSErr_t err = PreRequestCheck(client);
-if (err) {
- return err;
-}
+ if (err) {
+ return err;
+ }
client->send_buf[0] = kSID_ECU_RESET;
client->send_buf[1] = type;
client->send_size = 2;
@@ -1392,9 +1389,9 @@ if (err) {
UDSErr_t UDSSendDiagSessCtrl(UDSClient_t *client, enum UDSDiagnosticSessionType mode) {
UDSErr_t err = PreRequestCheck(client);
-if (err) {
- return err;
-}
+ if (err) {
+ return err;
+ }
client->send_buf[0] = kSID_DIAGNOSTIC_SESSION_CONTROL;
client->send_buf[1] = mode;
client->send_size = 2;
@@ -1404,9 +1401,9 @@ if (err) {
UDSErr_t UDSSendCommCtrl(UDSClient_t *client, enum UDSCommunicationControlType ctrl,
enum UDSCommunicationType comm) {
UDSErr_t err = PreRequestCheck(client);
-if (err) {
- return err;
-}
+ if (err) {
+ return err;
+ }
client->send_buf[0] = kSID_COMMUNICATION_CONTROL;
client->send_buf[1] = ctrl;
client->send_buf[2] = comm;
@@ -1416,9 +1413,9 @@ if (err) {
UDSErr_t UDSSendTesterPresent(UDSClient_t *client) {
UDSErr_t err = PreRequestCheck(client);
-if (err) {
- return err;
-}
+ if (err) {
+ return err;
+ }
client->send_buf[0] = kSID_TESTER_PRESENT;
client->send_buf[1] = 0;
client->send_size = 2;
@@ -1428,9 +1425,9 @@ if (err) {
UDSErr_t UDSSendRDBI(UDSClient_t *client, const uint16_t *didList,
const uint16_t numDataIdentifiers) {
UDSErr_t err = PreRequestCheck(client);
-if (err) {
- return err;
-}
+ if (err) {
+ return err;
+ }
assert(didList);
assert(numDataIdentifiers);
client->send_buf[0] = kSID_READ_DATA_BY_IDENTIFIER;
@@ -1449,9 +1446,9 @@ if (err) {
UDSErr_t UDSSendWDBI(UDSClient_t *client, uint16_t dataIdentifier, const uint8_t *data,
uint16_t size) {
UDSErr_t err = PreRequestCheck(client);
-if (err) {
- return err;
-}
+ if (err) {
+ return err;
+ }
assert(data);
assert(size);
client->send_buf[0] = kSID_WRITE_DATA_BY_IDENTIFIER;
@@ -1479,9 +1476,9 @@ if (err) {
UDSErr_t UDSSendRoutineCtrl(UDSClient_t *client, enum RoutineControlType type,
uint16_t routineIdentifier, const uint8_t *data, uint16_t size) {
UDSErr_t err = PreRequestCheck(client);
-if (err) {
- return err;
-}
+ if (err) {
+ return err;
+ }
client->send_buf[0] = kSID_ROUTINE_CONTROL;
client->send_buf[1] = type;
client->send_buf[2] = routineIdentifier >> 8;
@@ -1514,9 +1511,9 @@ UDSErr_t UDSSendRequestDownload(UDSClient_t *client, uint8_t dataFormatIdentifie
uint8_t addressAndLengthFormatIdentifier, size_t memoryAddress,
size_t memorySize) {
UDSErr_t err = PreRequestCheck(client);
-if (err) {
- return err;
-}
+ if (err) {
+ return err;
+ }
uint8_t numMemorySizeBytes = (addressAndLengthFormatIdentifier & 0xF0) >> 4;
uint8_t numMemoryAddressBytes = addressAndLengthFormatIdentifier & 0x0F;
@@ -1555,9 +1552,9 @@ UDSErr_t UDSSendRequestUpload(UDSClient_t *client, uint8_t dataFormatIdentifier,
uint8_t addressAndLengthFormatIdentifier, size_t memoryAddress,
size_t memorySize) {
UDSErr_t err = PreRequestCheck(client);
-if (err) {
- return err;
-}
+ if (err) {
+ return err;
+ }
uint8_t numMemorySizeBytes = (addressAndLengthFormatIdentifier & 0xF0) >> 4;
uint8_t numMemoryAddressBytes = addressAndLengthFormatIdentifier & 0x0F;
@@ -1594,9 +1591,9 @@ if (err) {
UDSErr_t UDSSendTransferData(UDSClient_t *client, uint8_t blockSequenceCounter,
const uint16_t blockLength, const uint8_t *data, uint16_t size) {
UDSErr_t err = PreRequestCheck(client);
-if (err) {
- return err;
-}
+ if (err) {
+ return err;
+ }
assert(blockLength > 2); // blockLength must include SID and sequenceCounter
assert(size + 2 <= blockLength); // data must fit inside blockLength - 2
client->send_buf[0] = kSID_TRANSFER_DATA;
@@ -1610,9 +1607,9 @@ if (err) {
UDSErr_t UDSSendTransferDataStream(UDSClient_t *client, uint8_t blockSequenceCounter,
const uint16_t blockLength, FILE *fd) {
UDSErr_t err = PreRequestCheck(client);
-if (err) {
- return err;
-}
+ if (err) {
+ return err;
+ }
assert(blockLength > 2); // blockLength must include SID and sequenceCounter
client->send_buf[0] = kSID_TRANSFER_DATA;
client->send_buf[1] = blockSequenceCounter;
@@ -1632,9 +1629,9 @@ if (err) {
*/
UDSErr_t UDSSendRequestTransferExit(UDSClient_t *client) {
UDSErr_t err = PreRequestCheck(client);
-if (err) {
- return err;
-}
+ if (err) {
+ return err;
+ }
client->send_buf[0] = kSID_REQUEST_TRANSFER_EXIT;
client->send_size = 1;
return _SendRequest(client);
@@ -1653,9 +1650,9 @@ if (err) {
UDSErr_t UDSCtrlDTCSetting(UDSClient_t *client, uint8_t dtcSettingType, uint8_t *data,
uint16_t size) {
UDSErr_t err = PreRequestCheck(client);
-if (err) {
- return err;
-}
+ if (err) {
+ return err;
+ }
if (0x00 == dtcSettingType || 0x7F == dtcSettingType ||
(0x03 <= dtcSettingType && dtcSettingType <= 0x3F)) {
assert(0); // reserved vals
@@ -1688,9 +1685,9 @@ if (err) {
*/
UDSErr_t UDSSendSecurityAccess(UDSClient_t *client, uint8_t level, uint8_t *data, uint16_t size) {
UDSErr_t err = PreRequestCheck(client);
-if (err) {
- return err;
-}
+ if (err) {
+ return err;
+ }
if (UDSSecurityAccessLevelIsReserved(level)) {
return UDS_ERR_INVALID_ARG;
}
diff --git a/iso14229.h b/iso14229.h
index 38e0dd4..becaa79 100644
--- a/iso14229.h
+++ b/iso14229.h
@@ -226,8 +226,6 @@ enum DTCSettingType {
kDTCSettingOFF = 0x02,
};
-
-
enum UDSTpStatusFlags {
UDS_TP_IDLE = 0x00000000,
UDS_TP_SEND_IN_PROGRESS = 0x00000001,
@@ -281,11 +279,13 @@ typedef struct UDSTpHandle {
/**
* @brief Send the data in the buffer buf
* @param hdl: pointer to transport handle
- * @param buf: a pointer to the data to send (this may be the buffer returned by @ref get_send_buf)
- * @param info: pointer to SDU info (may be NULL). If NULL, implementation should send with physical addressing
+ * @param buf: a pointer to the data to send (this may be the buffer returned by @ref
+ * get_send_buf)
+ * @param info: pointer to SDU info (may be NULL). If NULL, implementation should send with
+ * physical addressing
*/
ssize_t (*send)(struct UDSTpHandle *hdl, uint8_t *buf, size_t len, UDSSDU_t *info);
-
+
/**
* @brief Poll the transport layer.
* @param hdl: pointer to transport handle
@@ -309,7 +309,7 @@ typedef struct UDSTpHandle {
/**
* @brief Acknowledge that the received data has been processed and may be discarded
* @param hdl: pointer to transport handle
- * @note: after ack_recv() is called and before new messages are received, peek must return 0.
+ * @note: after ack_recv() is called and before new messages are received, peek must return 0.
*/
void (*ack_recv)(struct UDSTpHandle *hdl);
} UDSTpHandle_t;
@@ -590,11 +590,12 @@ typedef struct UDSServer {
size_t xferByteCounter; // total number of bytes transferred
size_t xferBlockLength; // block length (convenience for the TransferData API)
- uint8_t sessionType; // diagnostic session type (0x10)
+ uint8_t sessionType; // diagnostic session type (0x10)
uint8_t securityLevel; // SecurityAccess (0x27) level
- bool RCRRP; // set to true when user fn returns 0x78 and false otherwise
- bool requestInProgress; // set to true when a request has been processed but the response has not yet been sent
+ bool RCRRP; // set to true when user fn returns 0x78 and false otherwise
+ bool requestInProgress; // set to true when a request has been processed but the response has
+ // not yet been sent
// UDS-1 2013 defines the following conditions under which the server does not
// process incoming requests:
@@ -628,7 +629,8 @@ typedef struct {
typedef struct {
const uint16_t dataId; /*! RDBI Data Identifier */
- uint8_t (*copy)(UDSServer_t *srv , const void *src, uint16_t count); /*! function for copying data */
+ uint8_t (*copy)(UDSServer_t *srv, const void *src,
+ uint16_t count); /*! function for copying data */
} UDSRDBIArgs_t;
typedef struct {
diff --git a/platforms/BUILD b/platforms/BUILD
index 659ec5c..7ca5b02 100644
--- a/platforms/BUILD
+++ b/platforms/BUILD
@@ -1,5 +1,12 @@
package(default_visibility = ["//visibility:public"])
+constraint_setting(name = "mcu_series")
+
+constraint_value(
+ name = "s32k",
+ constraint_setting = ":mcu_series",
+)
+
platform(
name = "x86_64",
constraint_values = [
@@ -17,13 +24,29 @@ platform(
)
platform(
- name = "arm",
+ name = "arm_linux",
constraint_values = [
"@platforms//cpu:arm",
"@platforms//os:linux",
],
)
+platform(
+ name = "arm_none",
+ constraint_values = [
+ "@platforms//cpu:arm",
+ "@platforms//os:none",
+ ],
+)
+
+platform(
+ name = "s32k_evb",
+ parents = [":arm_none"],
+ constraint_values = [
+ ":s32k",
+ ],
+)
+
platform(
name = "ppc",
constraint_values = [
diff --git a/platforms/cmsis.BUILD b/platforms/cmsis.BUILD
new file mode 100644
index 0000000..e580aad
--- /dev/null
+++ b/platforms/cmsis.BUILD
@@ -0,0 +1,13 @@
+package(default_visibility = ["//visibility:public"])
+
+
+filegroup(
+ name = "srcs",
+ srcs = glob(["**/**"]),
+)
+
+cc_library(
+ name = "include",
+ srcs = glob(["CMSIS/Core/Include/**"]),
+ includes = ["CMSIS/Core/Include"],
+)
\ No newline at end of file
diff --git a/platforms/s32k_sdk.BUILD b/platforms/s32k_sdk.BUILD
new file mode 100644
index 0000000..950faab
--- /dev/null
+++ b/platforms/s32k_sdk.BUILD
@@ -0,0 +1,20 @@
+package(default_visibility = ["//visibility:public"])
+
+
+filegroup(
+ name = "srcs",
+ srcs = glob(["**/**"]),
+)
+
+cc_library(
+ name = "include",
+ includes = [
+ "platform/devices",
+ "platform/devices/common",
+ "platform/devices/S32K144/startup",
+ "platform/drivers/inc",
+ "platform/drivers/src/lpuart",
+ "rtos/osif",
+ "platform/pal/inc",
+ ],
+)
\ No newline at end of file
diff --git a/test/BUILD b/test/BUILD
index 07d26d7..4dbb91f 100644
--- a/test/BUILD
+++ b/test/BUILD
@@ -16,12 +16,35 @@ cc_library(
copts = [ "-g", ],
)
+TEST_SRCS = [
+ "test_client_0x11_ECU_reset.c",
+ "test_client_0x22_RDBI_unpack_response.c",
+ "test_client_0x31_RCRRP.c",
+ "test_client_0x34_request_download.c",
+ "test_client_busy.c",
+ "test_client_p2.c",
+ "test_client_suppress_positive_response.c",
+ "test_server_0x10_diag_sess_ctrl_functional_request.c",
+ "test_server_0x10_diag_sess_ctrl_is_disabled_by_default.c",
+ "test_server_0x11_no_send_recv_after_ECU_reset.c",
+ "test_server_0x22_RDBI.c",
+ "test_server_0x23_read_memory_by_address.c",
+ "test_server_0x27_security_access.c",
+ "test_server_0x31_RCRRP.c",
+ "test_server_0x34.c",
+ "test_server_0x3E_suppress_positive_response.c",
+ "test_server_0x83_diagnostic_session_control.c",
+ "test_server_session_timeout.c",
+ "test_tp_compliance.c",
+]
+
+TEST_NAMES = [ src.split(".c")[0] for src in TEST_SRCS ]
# Generic unit tests
# These should pass on all architectures and transports
[
cc_test(
- name=src.split(".c")[0] ,
+ name=name,
srcs=[src],
deps=[":env"],
size = "small",
@@ -33,29 +56,20 @@ cc_library(
"exclusive",
],
)
- for src in [
- "test_client_0x11_ECU_reset.c",
- "test_client_0x22_RDBI_unpack_response.c",
- "test_client_0x31_RCRRP.c",
- "test_client_0x34_request_download.c",
- "test_client_busy.c",
- "test_client_p2.c",
- "test_client_suppress_positive_response.c",
- "test_server_0x10_diag_sess_ctrl_functional_request.c",
- "test_server_0x10_diag_sess_ctrl_is_disabled_by_default.c",
- "test_server_0x11_no_send_recv_after_ECU_reset.c",
- "test_server_0x22_RDBI.c",
- "test_server_0x23_read_memory_by_address.c",
- "test_server_0x27_security_access.c",
- "test_server_0x31_RCRRP.c",
- "test_server_0x34.c",
- "test_server_0x3E_suppress_positive_response.c",
- "test_server_0x83_diagnostic_session_control.c",
- "test_server_session_timeout.c",
- "test_tp_compliance.c",
- ]
+ for name, src in zip(TEST_NAMES, TEST_SRCS)
]
+py_test(
+ name = "test_matrix",
+ srcs = ["test_matrix.py"],
+ size = "small",
+ data = TEST_NAMES,
+ args = TEST_NAMES,
+ tags = [
+ "exclusive",
+ ],
+)
+
cc_test(
name = "test_fuzz_server",
srcs = [
@@ -107,14 +121,10 @@ cc_library(
"-Wno-unused-parameter",
"-Wno-unused-function",
"-Wno-unused-variable",
- "-Wno-unused-but-set-variable",
"-Wno-unused-label",
"-Wno-unused-value",
"-Wno-unused-result",
- "-Wno-unused-const-variable",
- "-Wno-unused-local-typedefs",
"-Wno-unused-macros",
- "-Wno-gnu-zero-variadic-macro-arguments",
],
target_compatible_with = ["//platforms/compiler:clang"],
)
\ No newline at end of file
diff --git a/test/env.c b/test/env.c
index 0b58aee..b104df0 100644
--- a/test/env.c
+++ b/test/env.c
@@ -68,7 +68,6 @@ void ENV_ClientInit(UDSClient_t *cli) {
ENV_RegisterClient(cli);
}
-
void ENV_RegisterServer(UDSServer_t *server) { registeredServer = server; }
void ENV_RegisterClient(UDSClient_t *client) { registeredClient = client; }
@@ -76,9 +75,7 @@ void ENV_RegisterClient(UDSClient_t *client) { registeredClient = client; }
uint32_t UDSMillis() { return TimeNowMillis; }
// actually sleep for milliseconds
-void msleep(int ms) {
- usleep(ms * 1000);
-}
+void msleep(int ms) { usleep(ms * 1000); }
static bool IsNetworkedTransport(int tp_type) {
return tp_type == ENV_TP_TYPE_ISOTP_SOCK || tp_type == ENV_TP_TYPE_ISOTPC;
@@ -106,7 +103,6 @@ void ENV_RunMillis(uint32_t millis) {
}
}
-
UDSTpHandle_t *ENV_TpNew(const char *name) {
ENV_ParseOpts();
UDSTpHandle_t *tp = NULL;
@@ -122,19 +118,18 @@ UDSTpHandle_t *ENV_TpNew(const char *name) {
case ENV_TP_TYPE_ISOTP_SOCK: {
UDSTpIsoTpSock_t *isotp = malloc(sizeof(UDSTpIsoTpSock_t));
strcpy(isotp->tag, "server");
- assert(UDS_OK == UDSTpIsoTpSockInitServer(isotp, opts.ifname,
- opts.srv_src_addr, opts.srv_target_addr,
- opts.srv_src_addr_func));
+ assert(UDS_OK == UDSTpIsoTpSockInitServer(isotp, opts.ifname, opts.srv_src_addr,
+ opts.srv_target_addr,
+ opts.srv_src_addr_func));
tp = (UDSTpHandle_t *)isotp;
break;
}
case ENV_TP_TYPE_ISOTPC: {
UDSTpISOTpC_t *isotp = malloc(sizeof(UDSTpISOTpC_t));
strcpy(isotp->tag, "server");
-
- assert(UDS_OK == UDSTpISOTpCInit(isotp, opts.ifname,
- opts.srv_src_addr, opts.srv_target_addr,
- opts.srv_src_addr_func, 0));
+
+ assert(UDS_OK == UDSTpISOTpCInit(isotp, opts.ifname, opts.srv_src_addr,
+ opts.srv_target_addr, opts.srv_src_addr_func, 0));
tp = (UDSTpHandle_t *)isotp;
break;
}
@@ -150,18 +145,17 @@ UDSTpHandle_t *ENV_TpNew(const char *name) {
case ENV_TP_TYPE_ISOTP_SOCK: {
UDSTpIsoTpSock_t *isotp = malloc(sizeof(UDSTpIsoTpSock_t));
strcpy(isotp->tag, "client");
- assert(UDS_OK == UDSTpIsoTpSockInitClient(isotp, opts.ifname,
- opts.cli_src_addr, opts.cli_target_addr,
- opts.cli_tgt_addr_func));
+ assert(UDS_OK == UDSTpIsoTpSockInitClient(isotp, opts.ifname, opts.cli_src_addr,
+ opts.cli_target_addr,
+ opts.cli_tgt_addr_func));
tp = (UDSTpHandle_t *)isotp;
break;
}
case ENV_TP_TYPE_ISOTPC: {
UDSTpISOTpC_t *isotp = malloc(sizeof(UDSTpISOTpC_t));
strcpy(isotp->tag, "client");
- assert(UDS_OK == UDSTpISOTpCInit(isotp, opts.ifname,
- opts.cli_src_addr, opts.cli_target_addr, 0,
- opts.cli_tgt_addr_func));
+ assert(UDS_OK == UDSTpISOTpCInit(isotp, opts.ifname, opts.cli_src_addr,
+ opts.cli_target_addr, 0, opts.cli_tgt_addr_func));
tp = (UDSTpHandle_t *)isotp;
break;
}
@@ -169,8 +163,7 @@ UDSTpHandle_t *ENV_TpNew(const char *name) {
printf("unknown TP type: %d\n", opts.tp_type);
return NULL;
}
- }
- else {
+ } else {
printf("unknown mock tp: %s\n", name);
return NULL;
}
@@ -180,16 +173,16 @@ UDSTpHandle_t *ENV_TpNew(const char *name) {
void ENV_TpFree(UDSTpHandle_t *tp) {
switch (opts.tp_type) {
- case ENV_TP_TYPE_MOCK:
- TPMockFree(tp);
- break;
- case ENV_TP_TYPE_ISOTP_SOCK:
- UDSTpIsoTpSockDeinit((UDSTpIsoTpSock_t *)tp);
- break;
- case ENV_TP_TYPE_ISOTPC:
- UDSTpISOTpCDeinit((UDSTpISOTpC_t *)tp);
- free(tp);
- break;
+ case ENV_TP_TYPE_MOCK:
+ TPMockFree(tp);
+ break;
+ case ENV_TP_TYPE_ISOTP_SOCK:
+ UDSTpIsoTpSockDeinit((UDSTpIsoTpSock_t *)tp);
+ break;
+ case ENV_TP_TYPE_ISOTPC:
+ UDSTpISOTpCDeinit((UDSTpISOTpC_t *)tp);
+ free(tp);
+ break;
}
}
diff --git a/test/env.h b/test/env.h
index 9112002..993609e 100644
--- a/test/env.h
+++ b/test/env.h
@@ -35,7 +35,7 @@ void ENV_ClientInit(UDSClient_t *client);
/**
* @brief return a transport configured as client
- * @return UDSTpHandle_t*
+ * @return UDSTpHandle_t*
*/
UDSTpHandle_t *ENV_TpNew(const char *name);
void ENV_TpFree(UDSTpHandle_t *tp);
diff --git a/test/test.h b/test/test.h
index 8e9bcf7..a0c1445 100644
--- a/test/test.h
+++ b/test/test.h
@@ -10,7 +10,6 @@
#include "tp/mock.h"
#include
-
#define _TEST_INT_COND(a, b, cond) \
{ \
int _a = a; \
@@ -18,7 +17,7 @@
if (!((_a)cond(_b))) { \
printf("%s:%d (%d %s %d)\n", __FILE__, __LINE__, _a, #cond, _b); \
fflush(stdout); \
- assert_true(a cond b); \
+ assert_true(a cond b); \
} \
}
@@ -54,7 +53,7 @@
} \
printf(" (%s)\n", #b); \
fflush(stdout); \
- assert(0); \
+ assert_true(0); \
} \
}
@@ -64,7 +63,7 @@
if (_ret != UDS_OK) { \
printf("%s:%d (%d != %d)\n", __FILE__, __LINE__, _ret, UDS_OK); \
fflush(stdout); \
- assert(_ret == UDS_OK); \
+ assert_true(_ret == UDS_OK); \
} \
}
@@ -79,34 +78,31 @@
}
// Expect that a condition is true for a duration
-#define EXPECT_WHILE_MS(cond, duration) \
+#define EXPECT_WHILE_MS(cond, duration) \
{ \
- uint32_t deadline = UDSMillis() + duration; \
- while (UDSTimeAfter(deadline, UDSMillis())) { \
- assert(cond); \
+ uint32_t deadline = UDSMillis() + duration; \
+ while (UDSTimeAfter(deadline, UDSMillis())) { \
+ assert_true(cond); \
ENV_RunMillis(1); \
} \
}
-// Expect that a condition
-// - is false until 90% of a duration has passed,
+// Expect that a condition
+// - is false until 90% of a duration has passed,
// - and true before 110% of the duration has passed
-#define EXPECT_IN_APPROX_MS(cond, duration) \
+#define EXPECT_IN_APPROX_MS(cond, duration) \
{ \
- const float tolerance = 0.1f; \
- uint32_t pre_deadline = UDSMillis() + (int)((duration) * (1.0f - tolerance)); \
- uint32_t post_deadline = UDSMillis() + (int)((duration) * (1.0f + tolerance)); \
- while (UDSTimeAfter(pre_deadline, UDSMillis())) { \
- assert(!(cond)); \
+ const float tolerance = 0.1f; \
+ uint32_t pre_deadline = UDSMillis() + (int)((duration) * (1.0f - tolerance)); \
+ uint32_t post_deadline = UDSMillis() + (int)((duration) * (1.0f + tolerance)); \
+ while (UDSTimeAfter(pre_deadline, UDSMillis())) { \
+ assert_true(!(cond)); \
ENV_RunMillis(1); \
} \
while (!(cond)) { \
- TEST_INT_LE(UDSMillis(), post_deadline); \
+ TEST_INT_LE(UDSMillis(), post_deadline); \
ENV_RunMillis(1); \
} \
}
-
-
-
#endif
diff --git a/test/test_client_0x11_ECU_reset.c b/test/test_client_0x11_ECU_reset.c
index 06d1814..6631df9 100644
--- a/test/test_client_0x11_ECU_reset.c
+++ b/test/test_client_0x11_ECU_reset.c
@@ -36,13 +36,10 @@ int main() {
for (size_t i = 0; i < sizeof(p) / sizeof(p[0]); i++) {
ENV_CLIENT_INIT(client);
UDSTpHandle_t *srv = ENV_TpNew("server");
- printf("test %ld: %s\n", i, p[i].tag);
// when the client sends a ECU reset request with these options
client.options = p[i].options;
UDSSendECUReset(&client, kHardReset);
- printf("srv == NULL? : %d\n", srv == NULL);
- fflush(stdout);
// and the server responds with this message
UDSTpSend(srv, p[i].resp, p[i].resp_len, NULL);
diff --git a/test/test_client_0x31_RCRRP.c b/test/test_client_0x31_RCRRP.c
index d8c5343..3a3aa26 100644
--- a/test/test_client_0x31_RCRRP.c
+++ b/test/test_client_0x31_RCRRP.c
@@ -1,56 +1,69 @@
#include "test/test.h"
+static UDSClient_t client;
+static UDSTpHandle_t *mock_srv;
+
+int setup(void **state) {
+ ENV_CLIENT_INIT(client)
+ mock_srv = ENV_TpNew("server");
+ return 0;
+}
+
+int teardown(void **state) {
+ ENV_TpFree(mock_srv);
+ ENV_TpFree(client.tp);
+ return 0;
+}
+
+void test_RCRRP_timeout(void **state) {
+ ENV_CLIENT_INIT(client);
+ // When a request is sent
+ UDSSendRoutineCtrl(&client, kStartRoutine, 0x1234, NULL, 0);
+
+ // that receives an RCRRP response
+ const uint8_t RCRRP[] = {0x7F, 0x31, 0x78}; // RequestCorrectly-ReceievedResponsePending
+ UDSTpSend(mock_srv, RCRRP, sizeof(RCRRP), NULL);
+
+ // that remains unresolved at a time between p2 ms and p2 star ms
+ ENV_RunMillis(UDS_CLIENT_DEFAULT_P2_MS + 10);
+ // the client should still be pending.
+ TEST_INT_EQUAL(kRequestStateAwaitResponse, client.state)
+
+ // after p2_star has elapsed, the client should timeout
+ ENV_RunMillis(UDS_CLIENT_DEFAULT_P2_STAR_MS + 10);
+ TEST_INT_EQUAL(kRequestStateIdle, client.state)
+ TEST_INT_EQUAL(client.err, UDS_ERR_TIMEOUT);
+}
+
+void test_RCRRP_positive_response(void **state) {
+ // When a request is sent
+ UDSSendRoutineCtrl(&client, kStartRoutine, 0x1234, NULL, 0);
+
+ // that receives an RCRRP response
+ const uint8_t RCRRP[] = {0x7F, 0x31, 0x78}; // RequestCorrectly-ReceievedResponsePending
+ UDSTpSend(mock_srv, RCRRP, sizeof(RCRRP), NULL);
+
+ // that remains unresolved at a time between p2 ms and p2 star ms
+ ENV_RunMillis(UDS_CLIENT_DEFAULT_P2_MS + 10);
+ // the client should still be pending.
+ TEST_INT_EQUAL(client.err, UDS_OK);
+ TEST_INT_EQUAL(kRequestStateAwaitResponse, client.state)
+
+ // When the client receives a positive response from the server
+ const uint8_t POSITIVE_RESPONSE[] = {0x71, 0x01, 0x12, 0x34};
+ UDSTpSend(mock_srv, POSITIVE_RESPONSE, sizeof(POSITIVE_RESPONSE), NULL);
+
+ ENV_RunMillis(5);
+
+ // the client should return to the idle state with no error
+ TEST_INT_EQUAL(kRequestStateIdle, client.state)
+ TEST_INT_EQUAL(client.err, UDS_OK);
+}
+
int main() {
- UDSClient_t client;
- UDSTpHandle_t *mock_srv = ENV_TpNew("server");
-
- { // Case 1: RCRRP Timeout
- ENV_CLIENT_INIT(client);
- // When a request is sent
- UDSSendRoutineCtrl(&client, kStartRoutine, 0x1234, NULL, 0);
-
- // that receives an RCRRP response
- const uint8_t RCRRP[] = {0x7F, 0x31, 0x78}; // RequestCorrectly-ReceievedResponsePending
- UDSTpSend(mock_srv, RCRRP, sizeof(RCRRP), NULL);
-
- // that remains unresolved at a time between p2 ms and p2 star ms
- ENV_RunMillis(UDS_CLIENT_DEFAULT_P2_MS + 10);
- // the client should still be pending.
- TEST_INT_EQUAL(kRequestStateAwaitResponse, client.state)
-
- // after p2_star has elapsed, the client should timeout
- ENV_RunMillis(UDS_CLIENT_DEFAULT_P2_STAR_MS + 10);
- TEST_INT_EQUAL(kRequestStateIdle, client.state)
- TEST_INT_EQUAL(client.err, UDS_ERR_TIMEOUT);
-
- UDSTpAckRecv(mock_srv);
- }
-
- { // Case 2: Positive Response Received
- ENV_CLIENT_INIT(client);
- // When a request is sent
- UDSSendRoutineCtrl(&client, kStartRoutine, 0x1234, NULL, 0);
-
- // that receives an RCRRP response
- const uint8_t RCRRP[] = {0x7F, 0x31, 0x78}; // RequestCorrectly-ReceievedResponsePending
- UDSTpSend(mock_srv, RCRRP, sizeof(RCRRP), NULL);
-
- // that remains unresolved at a time between p2 ms and p2 star ms
- ENV_RunMillis(UDS_CLIENT_DEFAULT_P2_MS + 10);
- // the client should still be pending.
- TEST_INT_EQUAL(client.err, UDS_OK);
- TEST_INT_EQUAL(kRequestStateAwaitResponse, client.state)
-
- // When the client receives a positive response from the server
- const uint8_t POSITIVE_RESPONSE[] = {0x71, 0x01, 0x12, 0x34};
- UDSTpSend(mock_srv, POSITIVE_RESPONSE, sizeof(POSITIVE_RESPONSE), NULL);
-
- ENV_RunMillis(5);
-
- // the client should return to the idle state with no error
- TEST_INT_EQUAL(kRequestStateIdle, client.state)
- TEST_INT_EQUAL(client.err, UDS_OK);
-
- UDSTpAckRecv(mock_srv);
- }
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(test_RCRRP_timeout, setup, teardown),
+ cmocka_unit_test_setup_teardown(test_RCRRP_positive_response, setup, teardown),
+ };
+ return cmocka_run_group_tests(tests, NULL, NULL);
}
\ No newline at end of file
diff --git a/test/test_fuzz_server.c b/test/test_fuzz_server.c
index e6e1f4f..eeaf10b 100644
--- a/test/test_fuzz_server.c
+++ b/test/test_fuzz_server.c
@@ -24,7 +24,7 @@ typedef struct {
static StuffToFuzz_t fuzz;
static uint8_t client_recv_buf[UDS_BUFSIZE];
-static uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
+static uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
printf("Whoah, got event %d\n", ev);
return fuzz.srv_retval;
}
@@ -46,7 +46,6 @@ void DoInitialization() {
mock_client = TPMockNew("client");
}
-
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
static bool initialized = false;
if (!initialized) {
@@ -75,7 +74,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
{
UDSSDU_t msg2 = {
- .A_Data = client_recv_buf,
+ .A_Data = client_recv_buf,
.A_DataBufSize = sizeof(client_recv_buf),
};
mock_client->recv(mock_client, &msg2);
diff --git a/test/test_matrix.py b/test/test_matrix.py
new file mode 100644
index 0000000..692d4e2
--- /dev/null
+++ b/test/test_matrix.py
@@ -0,0 +1,17 @@
+#!/usr/bin/env python3
+
+__doc__ = """
+The core idea is that tests assert invariant properties that should be
+upheld regardless of the specific transport protocol, timing parameters, etc.
+"""
+
+import os
+import sys
+import subprocess
+
+for f in sys.argv[1:]:
+ for tp_type in ["0", "1", "2"]:
+ subprocess.check_call([f"test/{f}"], env={
+ "UDS_TP_TYPE": tp_type
+ })
+
diff --git a/test/test_prefix.sh b/test/test_prefix.sh
index f1a5115..c3018a7 100755
--- a/test/test_prefix.sh
+++ b/test/test_prefix.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# test fails if any exported symbols do not start with "UDS"
-nm $1 | grep ' T ' | grep -v 'UDS'
+# test fails if any exported symbols do not start with " UDS"
+nm $1 | grep ' T ' | grep -v ' UDS'
test $? = 1
\ No newline at end of file
diff --git a/test/test_server_0x10_diag_sess_ctrl_functional_request.c b/test/test_server_0x10_diag_sess_ctrl_functional_request.c
index ae41a09..a15cf3d 100644
--- a/test/test_server_0x10_diag_sess_ctrl_functional_request.c
+++ b/test/test_server_0x10_diag_sess_ctrl_functional_request.c
@@ -7,9 +7,7 @@ int main() {
// When server is sent a diagnostic session control request
const uint8_t REQ[] = {0x10, 0x02};
- UDSTpSend(mock_client, REQ, sizeof(REQ), &(UDSSDU_t){
- .A_TA_Type = UDS_A_TA_TYPE_FUNCTIONAL
- });
+ UDSTpSend(mock_client, REQ, sizeof(REQ), &(UDSSDU_t){.A_TA_Type = UDS_A_TA_TYPE_FUNCTIONAL});
// the server should respond with a negative response within p2 ms
const uint8_t EXP_RESP[] = {0x7f, 0x10, 0x11};
diff --git a/test/test_server_0x10_diag_sess_ctrl_is_disabled_by_default.c b/test/test_server_0x10_diag_sess_ctrl_is_disabled_by_default.c
index d926665..61b12a0 100644
--- a/test/test_server_0x10_diag_sess_ctrl_is_disabled_by_default.c
+++ b/test/test_server_0x10_diag_sess_ctrl_is_disabled_by_default.c
@@ -7,7 +7,7 @@ int main() {
// When server is sent a diagnostic session control request
const uint8_t REQ[] = {0x10, 0x02};
- UDSTpSend(mock_client, REQ, sizeof(REQ), NULL);
+ UDSTpSend(mock_client, REQ, sizeof(REQ), NULL);
// the server should respond with a negative response within p2 ms
const uint8_t EXP_RESP[] = {0x7f, 0x10, 0x11};
diff --git a/test/test_server_0x11_no_send_recv_after_ECU_reset.c b/test/test_server_0x11_no_send_recv_after_ECU_reset.c
index 9b05a36..a822640 100644
--- a/test/test_server_0x11_no_send_recv_after_ECU_reset.c
+++ b/test/test_server_0x11_no_send_recv_after_ECU_reset.c
@@ -23,7 +23,7 @@ int main() {
const uint8_t RESP[] = {0x51, 0x01};
// Sending the first ECU reset should result in a response
- UDSTpSend(mock_client, REQ, sizeof(REQ), NULL);
+ UDSTpSend(mock_client, REQ, sizeof(REQ), NULL);
EXPECT_IN_APPROX_MS(UDSTpGetRecvLen(mock_client), srv.p2_ms);
TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(mock_client, NULL), RESP, sizeof(RESP));
@@ -31,7 +31,7 @@ int main() {
// Sending subsequent ECU reset requests should never receive any response
const unsigned LONG_TIME_MS = 5000;
- UDSTpSend(mock_client, REQ, sizeof(REQ), NULL);
+ UDSTpSend(mock_client, REQ, sizeof(REQ), NULL);
EXPECT_WHILE_MS(UDSTpGetRecvLen(mock_client) == 0, LONG_TIME_MS);
// Additionally the ECU reset handler should have been called exactly once.
diff --git a/test/test_server_0x22_RDBI.c b/test/test_server_0x22_RDBI.c
index ba9beb6..a8ad7a6 100644
--- a/test/test_server_0x22_RDBI.c
+++ b/test/test_server_0x22_RDBI.c
@@ -30,16 +30,16 @@ int main() {
srv.fn = fn;
{ // 11.2.5.2 Example #1 read single dataIdentifier 0xF190
uint8_t REQ[] = {0x22, 0xF1, 0x90};
- UDSTpSend(mock_client, REQ, sizeof(REQ), NULL);
+ UDSTpSend(mock_client, REQ, sizeof(REQ), NULL);
uint8_t RESP[] = {0x62, 0xF1, 0x90, 0x57, 0x30, 0x4C, 0x30, 0x30, 0x30, 0x30,
0x34, 0x33, 0x4D, 0x42, 0x35, 0x34, 0x31, 0x33, 0x32, 0x36};
EXPECT_IN_APPROX_MS(UDSTpGetRecvLen(mock_client) == sizeof(RESP), srv.p2_ms)
TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(mock_client, NULL), RESP, sizeof(RESP));
- UDSTpAckRecv(mock_client);
+ UDSTpAckRecv(mock_client);
}
{ // Read a nonexistent dataIdentifier 0xF191
uint8_t REQ[] = {0x22, 0xF1, 0x91};
- UDSTpSend(mock_client, REQ, sizeof(REQ), NULL);
+ UDSTpSend(mock_client, REQ, sizeof(REQ), NULL);
uint8_t RESP[] = {0x7F, 0x22, 0x31};
EXPECT_IN_APPROX_MS(UDSTpGetRecvLen(mock_client) == sizeof(RESP), srv.p2_ms)
TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(mock_client, NULL), RESP, sizeof(RESP));
diff --git a/test/test_server_0x23_read_memory_by_address.c b/test/test_server_0x23_read_memory_by_address.c
index 0cb7402..364955a 100644
--- a/test/test_server_0x23_read_memory_by_address.c
+++ b/test/test_server_0x23_read_memory_by_address.c
@@ -40,16 +40,16 @@ int main() {
0x01, // memorySize byte #1 (MSB)
0x03, // memorySize byte #2 (LSB)
};
- UDSTpSend(client_tp, REQ, sizeof(REQ), NULL);
+ UDSTpSend(client_tp, REQ, sizeof(REQ), NULL);
// the client transport should receive a positive response within client_p2 ms
// EXPECT_WITHIN_MS(UDSTpGetRecvLen(client_tp) > 0, UDS_CLIENT_DEFAULT_P2_MS)
- uint32_t deadline = UDSMillis() + UDS_CLIENT_DEFAULT_P2_MS + 1;
- while (!(UDSTpGetRecvLen(client_tp) > 0)) {
+ uint32_t deadline = UDSMillis() + UDS_CLIENT_DEFAULT_P2_MS + 1;
+ while (!(UDSTpGetRecvLen(client_tp) > 0)) {
printf("UDSTpGetRecvLen(client_tp) = %ld\n", UDSTpGetRecvLen(client_tp));
- TEST_INT_LE(UDSMillis(), deadline);
- ENV_RunMillis(1);
- }
+ TEST_INT_LE(UDSMillis(), deadline);
+ ENV_RunMillis(1);
+ }
TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(client_tp, NULL), EXPECTED_RESP, sizeof(EXPECTED_RESP));
}
diff --git a/test/test_server_0x27_security_access.c b/test/test_server_0x27_security_access.c
index f53cfb0..6871d8d 100644
--- a/test/test_server_0x27_security_access.c
+++ b/test/test_server_0x27_security_access.c
@@ -38,7 +38,7 @@ int main() {
// sending a seed request should get this response
const uint8_t SEED_REQUEST[] = {0x27, 0x01};
const uint8_t SEED_RESPONSE[] = {0x67, 0x01, 0x36, 0x57};
- UDSTpSend(mock_client, SEED_REQUEST, sizeof(SEED_REQUEST), NULL);
+ UDSTpSend(mock_client, SEED_REQUEST, sizeof(SEED_REQUEST), NULL);
EXPECT_IN_APPROX_MS(UDSTpGetRecvLen(mock_client) != 0, srv.p2_ms);
TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(mock_client, NULL), SEED_RESPONSE, sizeof(SEED_RESPONSE));
UDSTpAckRecv(mock_client);
@@ -49,7 +49,7 @@ int main() {
// subsequently sending an unlock request should get this response
const uint8_t UNLOCK_REQUEST[] = {0x27, 0x02, 0xC9, 0xA9};
const uint8_t UNLOCK_RESPONSE[] = {0x67, 0x02};
- UDSTpSend(mock_client, UNLOCK_REQUEST, sizeof(UNLOCK_REQUEST), NULL);
+ UDSTpSend(mock_client, UNLOCK_REQUEST, sizeof(UNLOCK_REQUEST), NULL);
EXPECT_IN_APPROX_MS(UDSTpGetRecvLen(mock_client) != 0, srv.p2_ms);
TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(mock_client, NULL), UNLOCK_RESPONSE, sizeof(UNLOCK_RESPONSE));
UDSTpAckRecv(mock_client);
@@ -59,7 +59,7 @@ int main() {
// sending the same seed request should now result in the "already unlocked" response
const uint8_t ALREADY_UNLOCKED_RESPONSE[] = {0x67, 0x01, 0x00, 0x00};
- UDSTpSend(mock_client, SEED_REQUEST, sizeof(SEED_REQUEST), NULL);
+ UDSTpSend(mock_client, SEED_REQUEST, sizeof(SEED_REQUEST), NULL);
EXPECT_IN_APPROX_MS(UDSTpGetRecvLen(mock_client) != 0, srv.p2_ms);
TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(mock_client, NULL), ALREADY_UNLOCKED_RESPONSE,
sizeof(ALREADY_UNLOCKED_RESPONSE));
diff --git a/test/test_server_0x31_RCRRP.c b/test/test_server_0x31_RCRRP.c
index e1c60c6..6b990ca 100644
--- a/test/test_server_0x31_RCRRP.c
+++ b/test/test_server_0x31_RCRRP.c
@@ -17,7 +17,7 @@ int main() {
// sending a request to the server should return RCRRP within p2 ms
const uint8_t REQUEST[] = {0x31, 0x01, 0x12, 0x34};
- UDSTpSend(mock_client, REQUEST, sizeof(REQUEST), NULL);
+ UDSTpSend(mock_client, REQUEST, sizeof(REQUEST), NULL);
const uint8_t RCRRP[] = {0x7F, 0x31, 0x78};
@@ -47,5 +47,6 @@ int main() {
// and it should arrive within p2 ms
const uint8_t POSITIVE_RESPONSE[] = {0x71, 0x01, 0x12, 0x34};
EXPECT_IN_APPROX_MS((UDSTpGetRecvLen(mock_client) > 0), srv.p2_ms)
- TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(mock_client, NULL), POSITIVE_RESPONSE, sizeof(POSITIVE_RESPONSE));
+ TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(mock_client, NULL), POSITIVE_RESPONSE,
+ sizeof(POSITIVE_RESPONSE));
}
diff --git a/test/test_server_0x34.c b/test/test_server_0x34.c
index 67e6b85..1088913 100644
--- a/test/test_server_0x34.c
+++ b/test/test_server_0x34.c
@@ -19,7 +19,7 @@ int main() {
// when no handler function is installed, sending this request to the server
uint8_t REQ[] = {0x34, 0x11, 0x33, 0x60, 0x20, 0x00, 0x00, 0xFF, 0xFF};
- UDSTpSend(mock_client, REQ, sizeof(REQ), NULL);
+ UDSTpSend(mock_client, REQ, sizeof(REQ), NULL);
// should return a kServiceNotSupported response
uint8_t RESP[] = {0x7F, 0x34, 0x11};
@@ -37,7 +37,7 @@ int main() {
// sending this request to the server
uint8_t REQ[] = {0x34, 0x11, 0x33, 0x60, 0x20, 0x00, 0x00, 0xFF, 0xFF};
- UDSTpSend(mock_client, REQ, sizeof(REQ), NULL);
+ UDSTpSend(mock_client, REQ, sizeof(REQ), NULL);
// should receive a positive response matching UDS-1:2013 Table 415
uint8_t RESP[] = {0x74, 0x20, 0x00, 0x81};
diff --git a/test/test_server_0x3E_suppress_positive_response.c b/test/test_server_0x3E_suppress_positive_response.c
index ab50910..67dfa65 100644
--- a/test/test_server_0x3E_suppress_positive_response.c
+++ b/test/test_server_0x3E_suppress_positive_response.c
@@ -12,7 +12,7 @@ int main() {
// when the suppressPositiveResponse bit is set
const uint8_t REQ[] = {0x3E, 0x80};
- UDSTpSend(mock_client, REQ, sizeof(REQ), NULL);
+ UDSTpSend(mock_client, REQ, sizeof(REQ), NULL);
// there should be no response
ENV_RunMillis(5000);
diff --git a/test/test_server_0x83_diagnostic_session_control.c b/test/test_server_0x83_diagnostic_session_control.c
index 7a6ae72..53bcc2c 100644
--- a/test/test_server_0x83_diagnostic_session_control.c
+++ b/test/test_server_0x83_diagnostic_session_control.c
@@ -15,7 +15,7 @@ int main() {
// when a request is sent with the suppressPositiveResponse bit set
const uint8_t REQ[] = {0x10, 0x83};
- UDSTpSend(mock_client, REQ, sizeof(REQ), NULL);
+ UDSTpSend(mock_client, REQ, sizeof(REQ), NULL);
// even after running for a long time
ENV_RunMillis(5000);
diff --git a/test/test_tp_compliance.c b/test/test_tp_compliance.c
index 47d332a..090cef0 100644
--- a/test/test_tp_compliance.c
+++ b/test/test_tp_compliance.c
@@ -29,20 +29,17 @@ void TestSendRecv(void **state) {
assert_memory_equal(UDSTpGetRecvBuf(srv, NULL), MSG, sizeof(MSG));
}
-
void TestSendRecvFunctional(void **state) {
const uint8_t MSG[] = {0x10, 0x02};
UDSSDU_t info = {0};
uint8_t *buf = NULL;
// When a small functional request is sent
- UDSTpSend(client, MSG, sizeof(MSG), &(UDSSDU_t){
- .A_TA_Type = UDS_A_TA_TYPE_FUNCTIONAL
- });
+ UDSTpSend(client, MSG, sizeof(MSG), &(UDSSDU_t){.A_TA_Type = UDS_A_TA_TYPE_FUNCTIONAL});
// the server should receive it quickly
EXPECT_IN_APPROX_MS(UDSTpPeek(srv, &buf, &info) == sizeof(MSG), 1);
-
+
// it should be the same message
assert_memory_equal(buf, MSG, sizeof(MSG));
@@ -59,13 +56,12 @@ void TestISOTPSendLargestSingleFrame(void **state) {
uint8_t *buf = NULL;
// When a functional request is sent
- ssize_t ret = UDSTpSend(client, MSG, sizeof(MSG), &(UDSSDU_t){
- .A_TA_Type = UDS_A_TA_TYPE_FUNCTIONAL
- });
+ ssize_t ret =
+ UDSTpSend(client, MSG, sizeof(MSG), &(UDSSDU_t){.A_TA_Type = UDS_A_TA_TYPE_FUNCTIONAL});
// the server should receive it quickly
EXPECT_IN_APPROX_MS(UDSTpPeek(srv, &buf, &info) == sizeof(MSG), 1);
-
+
// it should be the same message
assert_memory_equal(buf, MSG, sizeof(MSG));
@@ -82,9 +78,8 @@ void TestISOTPSendLargerThanSingleFrameFails(void **state) {
uint8_t *buf = NULL;
// When a small functional request is sent
- ssize_t ret = UDSTpSend(client, MSG, sizeof(MSG), &(UDSSDU_t){
- .A_TA_Type = UDS_A_TA_TYPE_FUNCTIONAL
- });
+ ssize_t ret =
+ UDSTpSend(client, MSG, sizeof(MSG), &(UDSSDU_t){.A_TA_Type = UDS_A_TA_TYPE_FUNCTIONAL});
assert_true(ret < 0);
}
@@ -111,5 +106,3 @@ int main() {
};
return cmocka_run_group_tests(tests, NULL, NULL);
}
-
-
diff --git a/test_iso14229.c b/test_iso14229.c
index 7e942d2..6cfd587 100644
--- a/test_iso14229.c
+++ b/test_iso14229.c
@@ -89,21 +89,21 @@
ctx.func_name = __PRETTY_FUNCTION__; \
if (SERVER_ONLY == test_type) { \
UDSServerInit(&ctx.server, &(UDSServerConfig_t){ \
- .tp = TPMockNew("server"), \
+ .tp = TPMockNew("server"), \
.source_addr = SERVER_SOURCE_ADDR, \
.target_addr = SERVER_TARGET_ADDR, \
.source_addr_func = SERVER_SOURCE_ADDR_FUNC, \
}); \
- ctx.mock_tp = TPMockNew("mock_client"); \
+ ctx.mock_tp = TPMockNew("mock_client"); \
} \
if (CLIENT_ONLY == test_type) { \
UDSClientInit(&ctx.client, &(UDSClientConfig_t){ \
- .tp = TPMockNew("client"), \
+ .tp = TPMockNew("client"), \
.target_addr = CLIENT_TARGET_ADDR, \
.source_addr = CLIENT_SOURCE_ADDR, \
.target_addr_func = CLIENT_TARGET_ADDR_FUNC, \
}); \
- ctx.mock_tp = TPMockNew("mock_server"); \
+ ctx.mock_tp = TPMockNew("mock_server"); \
} \
char logfilename[256] = {0}; \
snprintf(logfilename, sizeof(logfilename), "%s%s.log", ctx.func_name, param_str); \
@@ -232,7 +232,8 @@ static void poll_ctx(Ctx_t *ctx) {
.A_Data = d1, \
.A_Length = sizeof(d1), \
.A_SA = CLIENT_SOURCE_ADDR, \
- .A_TA = reqType == UDS_A_TA_TYPE_PHYSICAL ? SERVER_SOURCE_ADDR : SERVER_SOURCE_ADDR_FUNC, \
+ .A_TA = \
+ reqType == UDS_A_TA_TYPE_PHYSICAL ? SERVER_SOURCE_ADDR : SERVER_SOURCE_ADDR_FUNC, \
.A_TA_Type = (int)reqType, \
}; \
ctx.mock_tp->send(ctx.mock_tp, &msg); \
@@ -247,9 +248,9 @@ static void poll_ctx(Ctx_t *ctx) {
int recv_len = ctx.mock_tp->recv(ctx.mock_tp, &msg); \
ASSERT_INT_EQUAL(recv_len, sizeof(d1)); \
ASSERT_MEMORY_EQUAL(ctx.mock_recv_buf, d1, sizeof(d1)); \
- if (reqType == UDS_A_TA_TYPE_PHYSICAL) { \
+ if (reqType == UDS_A_TA_TYPE_PHYSICAL) { \
ASSERT_INT_EQUAL(msg.A_TA, SERVER_SOURCE_ADDR); \
- } else if (reqType == UDS_A_TA_TYPE_FUNCTIONAL) { \
+ } else if (reqType == UDS_A_TA_TYPE_FUNCTIONAL) { \
ASSERT_INT_EQUAL(msg.A_TA, SERVER_SOURCE_ADDR_FUNC); \
} else { \
assert(0); \
diff --git a/toolchain/BUILD b/toolchain/BUILD
index 11ee579..7bd8525 100644
--- a/toolchain/BUILD
+++ b/toolchain/BUILD
@@ -7,20 +7,39 @@ filegroup(
)
gcc_toolchain(
- name="arm_gcc",
+ name="arm_linux_gcc",
prefix="arm-linux-gnueabihf",
target_compatible_with = [
+ "@platforms//cpu:arm",
"@platforms//os:linux",
+ ],
+)
+
+gcc_toolchain(
+ name="arm_none_gcc",
+ prefix="arm-none-eabi",
+ target_compatible_with = [
"@platforms//cpu:arm",
+ "@platforms//os:none",
+ ],
+ include_dirs = [
+ "/usr/lib/gcc/arm-none-eabi/10.3.1/include/",
+ ],
+ linkopts = [
+ "-Wl,--gc-sections",
],
+ copts = [
+ "-g",
+ "-gdwarf-2",
+ ]
)
gcc_toolchain(
name="ppc_gcc",
prefix="powerpc-linux-gnu",
target_compatible_with = [
- "@platforms//os:linux",
"@platforms//cpu:ppc",
+ "@platforms//os:linux",
]
)
@@ -28,8 +47,8 @@ gcc_toolchain(
name="ppc64_gcc",
prefix="powerpc64-linux-gnu",
target_compatible_with = [
- "@platforms//os:linux",
"//platforms/cpu:ppc64",
+ "@platforms//os:linux",
]
)
@@ -37,8 +56,8 @@ gcc_toolchain(
name="ppc64le_gcc",
prefix="powerpc64le-linux-gnu",
target_compatible_with = [
- "@platforms//os:linux",
"//platforms/cpu:ppc64le",
+ "@platforms//os:linux",
]
)
diff --git a/toolchain/gcc_family.bzl b/toolchain/gcc_family.bzl
index 9ebde14..c22ec56 100644
--- a/toolchain/gcc_family.bzl
+++ b/toolchain/gcc_family.bzl
@@ -1,7 +1,12 @@
+""" gcc toolchains """
+
load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES")
load(
"@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl",
"tool_path",
+ "flag_group",
+ "flag_set",
+ "feature",
)
all_link_actions = [
@@ -44,10 +49,56 @@ def _impl(ctx):
name = "strip",
path = "/bin/false",
),
+ tool_path(
+ name = "objcopy",
+ path = "/usr/bin/{}-objcopy".format(ctx.attr.prefix),
+ ),
]
- features = [
- ]
+ linker_flags = ctx.attr.linkopts + ctx.attr.arch_flags
+ compiler_flags = ctx.attr.copts + ctx.attr.arch_flags
+
+ features = []
+
+ if len(linker_flags) > 0:
+ features.append(
+ feature(
+ name = "linker_flags",
+ enabled = True,
+ flag_sets = [
+ flag_set(
+ actions = all_link_actions,
+ flag_groups = [
+ flag_group(
+ flags = linker_flags,
+ ),
+ ],
+ ),
+ ],
+ )
+ )
+
+ if len(compiler_flags) > 0:
+ features.append(
+ feature(
+ name = "compiler_flags",
+ enabled = True,
+ flag_sets = [
+ flag_set(
+ actions = [
+ ACTION_NAMES.c_compile,
+ ACTION_NAMES.cpp_compile,
+ ],
+ flag_groups = [
+ flag_group(
+ flags = compiler_flags,
+ ),
+ ],
+ ),
+ ],
+ )
+ )
+
return cc_common.create_cc_toolchain_config_info(
ctx = ctx,
@@ -56,7 +107,7 @@ def _impl(ctx):
"/usr/{}/include".format(ctx.attr.prefix),
"/usr/lib/gcc-cross/{}/11/include".format(ctx.attr.prefix),
"/usr/include",
- ],
+ ] + ctx.attr.include_dirs,
toolchain_identifier = "local",
host_system_name = "local",
target_system_name = "local",
@@ -72,17 +123,24 @@ gcc_toolchain_config = rule(
implementation = _impl,
attrs = {
"prefix": attr.string(mandatory=True, doc="Prefix of compiler suite"),
+ "include_dirs": attr.string_list(mandatory=False, doc="List of include dirs"),
+ "arch_flags": attr.string_list(mandatory=False, doc="List of arch flags"),
+ "linkopts": attr.string_list(mandatory=False, doc="List of additional linker options"),
+ "copts": attr.string_list(mandatory=False, doc="List of additional compiler options"),
},
provides = [CcToolchainConfigInfo],
)
-def gcc_toolchain(name, prefix, target_compatible_with):
+def gcc_toolchain(name, prefix, target_compatible_with, include_dirs= [], linkopts = [], copts = []):
"""Create a gcc toolchain
Args:
name: Name of the toolchain
prefix: Prefix of the compiler suite
target_compatible_with: List of targets that this toolchain is compatible with
+ include_dirs: List of additional include directories
+ linkopts: List of additional linker options
+ copts: List of additional compiler options
"""
CONFIG_NAME = name + "_config"
CC_TOOLCHAIN_NAME = name + "_cc_toolchain"
@@ -90,6 +148,19 @@ def gcc_toolchain(name, prefix, target_compatible_with):
gcc_toolchain_config(
name = CONFIG_NAME,
prefix = prefix,
+ include_dirs = include_dirs,
+ arch_flags = select({
+ "//platforms:s32k" : [
+ "-mcpu=cortex-m4",
+ "-mthumb",
+ "-mfloat-abi=hard",
+ "-mfpu=fpv4-sp-d16",
+ ],
+ "//conditions:default" : [
+ ],
+ }),
+ linkopts = linkopts,
+ copts = copts,
)
native.cc_toolchain(
diff --git a/toolchain/objcopy.bzl b/toolchain/objcopy.bzl
new file mode 100644
index 0000000..4466110
--- /dev/null
+++ b/toolchain/objcopy.bzl
@@ -0,0 +1,59 @@
+""" objcopy rule """
+load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cc_toolchain")
+
+def _objcopy_impl(ctx):
+ cc_toolchain = find_cc_toolchain(ctx)
+ outfile = ctx.outputs.out
+
+ ctx.actions.run_shell(
+ outputs = [outfile],
+ inputs = depset(
+ direct = [ctx.file.src],
+ transitive = [
+ cc_toolchain.all_files,
+ ],
+ ),
+ command = "{objcopy} {args} {src} {dst}".format(
+ objcopy = cc_toolchain.objcopy_executable,
+ args = ctx.attr.args,
+ src = ctx.file.src.path,
+ dst = ctx.outputs.out.path,
+ ),
+ )
+
+ return [
+ DefaultInfo(
+ files = depset([outfile]),
+ ),
+ ]
+
+_objcopy = rule(
+ implementation = _objcopy_impl,
+ attrs = {
+ # Source file
+ "src": attr.label(allow_single_file = True, mandatory = True),
+ # Target file
+ "out": attr.output(mandatory = True),
+ # Arguments
+ "args": attr.string(mandatory = True),
+ },
+ executable = False,
+ toolchains = ["@bazel_tools//tools/cpp:toolchain_type"],
+ fragments = ["cpp"],
+)
+
+def objcopy(src, out, args, name = ""):
+ """
+ objcopy rule
+
+ src: source file
+ out: target file
+ args: arguments
+ name: rule name
+ """
+ _objcopy(
+ name = name or "objcopy" + out,
+ src = src,
+ out = out,
+ args = args,
+ )
\ No newline at end of file
diff --git a/tp/BUILD b/tp/BUILD
index 66194f6..bf3e8bc 100644
--- a/tp/BUILD
+++ b/tp/BUILD
@@ -56,6 +56,8 @@ filegroup(
"isotp_sock.h",
"isotp_c_socketcan.c",
"isotp_c_socketcan.h",
+ "isotp_c.c",
+ "isotp_c.h",
":isotp_c_srcs",
]
)
diff --git a/tp/isotp_c.c b/tp/isotp_c.c
new file mode 100644
index 0000000..a0a44f1
--- /dev/null
+++ b/tp/isotp_c.c
@@ -0,0 +1,162 @@
+#include "tp/isotp_c.h"
+#include "tp/isotp-c/isotp.h"
+#include
+#include
+
+static UDSTpStatus_t tp_poll(UDSTpHandle_t *hdl) {
+ assert(hdl);
+ UDSTpStatus_t status = 0;
+ UDSTpISOTpC_t *impl = (UDSTpISOTpC_t *)hdl;
+ isotp_poll(&impl->phys_link);
+ if (impl->phys_link.send_status == ISOTP_SEND_STATUS_INPROGRESS) {
+ status |= UDS_TP_SEND_IN_PROGRESS;
+ }
+ return status;
+}
+
+int peek_link(IsoTpLink *link, uint8_t *buf, size_t bufsize, bool functional) {
+ assert(link);
+ assert(buf);
+ int ret = -1;
+ switch (link->receive_status) {
+ case ISOTP_RECEIVE_STATUS_IDLE:
+ ret = 0;
+ goto done;
+ case ISOTP_RECEIVE_STATUS_INPROGRESS:
+ ret = 0;
+ goto done;
+ case ISOTP_RECEIVE_STATUS_FULL:
+ ret = link->receive_size;
+ printf("The link is full. Copying %d bytes\n", ret);
+ memmove(buf, link->receive_buffer, link->receive_size);
+ break;
+ default:
+ UDS_DBG_PRINT("receive_status %d not implemented\n", link->receive_status);
+ ret = -1;
+ goto done;
+ }
+done:
+ return ret;
+}
+
+static ssize_t tp_peek(UDSTpHandle_t *hdl, uint8_t **p_buf, UDSSDU_t *info) {
+ assert(hdl);
+ assert(p_buf);
+ UDSTpISOTpC_t *tp = (UDSTpISOTpC_t *)hdl;
+ if (ISOTP_RECEIVE_STATUS_FULL == tp->phys_link.receive_status) { // recv not yet acked
+ *p_buf = tp->recv_buf;
+ return tp->phys_link.receive_size;
+ }
+ int ret = -1;
+ ret = peek_link(&tp->phys_link, tp->recv_buf, sizeof(tp->recv_buf), false);
+ UDS_A_TA_Type_t ta_type = UDS_A_TA_TYPE_PHYSICAL;
+ uint32_t ta = tp->phys_ta;
+ uint32_t sa = tp->phys_sa;
+
+ if (ret > 0) {
+ printf("just got %d bytes\n", ret);
+ ta = tp->phys_sa;
+ sa = tp->phys_ta;
+ ta_type = UDS_A_TA_TYPE_PHYSICAL;
+ *p_buf = tp->recv_buf;
+ goto done;
+ } else if (ret < 0) {
+ goto done;
+ } else {
+ ret = peek_link(&tp->func_link, tp->recv_buf, sizeof(tp->recv_buf), true);
+ if (ret > 0) {
+ printf("just got %d bytes on func link \n", ret);
+ ta = tp->func_sa;
+ sa = tp->func_ta;
+ ta_type = UDS_A_TA_TYPE_FUNCTIONAL;
+ *p_buf = tp->recv_buf;
+ goto done;
+ } else if (ret < 0) {
+ goto done;
+ }
+ }
+done:
+ if (ret > 0) {
+ if (info) {
+ info->A_TA = ta;
+ info->A_SA = sa;
+ info->A_TA_Type = ta_type;
+ }
+ }
+ return ret;
+}
+
+static ssize_t tp_send(UDSTpHandle_t *hdl, uint8_t *buf, size_t len, UDSSDU_t *info) {
+ assert(hdl);
+ ssize_t ret = -1;
+ UDSTpISOTpC_t *tp = (UDSTpISOTpC_t *)hdl;
+ IsoTpLink *link = NULL;
+ const UDSTpAddr_t ta_type = info ? info->A_TA_Type : UDS_A_TA_TYPE_PHYSICAL;
+ const uint32_t ta = ta_type == UDS_A_TA_TYPE_PHYSICAL ? tp->phys_ta : tp->func_ta;
+ switch (ta_type) {
+ case UDS_A_TA_TYPE_PHYSICAL:
+ link = &tp->phys_link;
+ break;
+ case UDS_A_TA_TYPE_FUNCTIONAL:
+ link = &tp->func_link;
+ if (len > 7) {
+ UDS_DBG_PRINT("Cannot send more than 7 bytes via functional addressing\n");
+ ret = -3;
+ goto done;
+ }
+ break;
+ default:
+ ret = -4;
+ goto done;
+ }
+
+ int send_status = isotp_send(link, buf, len);
+ switch (send_status) {
+ case ISOTP_RET_OK:
+ ret = len;
+ goto done;
+ case ISOTP_RET_INPROGRESS:
+ case ISOTP_RET_OVERFLOW:
+ default:
+ ret = send_status;
+ goto done;
+ }
+done:
+ return ret;
+}
+
+static void tp_ack_recv(UDSTpHandle_t *hdl) {
+ assert(hdl);
+ printf("ack recv\n");
+ UDSTpISOTpC_t *tp = (UDSTpISOTpC_t *)hdl;
+}
+
+static ssize_t tp_get_send_buf(UDSTpHandle_t *hdl, uint8_t **p_buf) {
+ assert(hdl);
+ UDSTpISOTpC_t *tp = (UDSTpISOTpC_t *)hdl;
+ *p_buf = tp->send_buf;
+ return sizeof(tp->send_buf);
+}
+
+UDSErr_t UDSTpISOTpCInit(UDSTpISOTpC_t *tp, UDSTpISOTpCConfig_t *cfg) {
+ if (cfg == NULL || tp == NULL) {
+ return UDS_ERR;
+ }
+ tp->hdl.poll = tp_poll;
+ tp->hdl.send = tp_send;
+ tp->hdl.peek = tp_peek;
+ tp->hdl.ack_recv = tp_ack_recv;
+ tp->hdl.get_send_buf = tp_get_send_buf;
+ tp->phys_sa = cfg->source_addr;
+ tp->phys_ta = cfg->target_addr;
+ tp->func_sa = cfg->source_addr_func;
+ tp->func_ta = cfg->target_addr;
+
+ isotp_init_link(&tp->phys_link, tp->phys_ta, tp->send_buf, sizeof(tp->send_buf), tp->recv_buf,
+ sizeof(tp->recv_buf), UDSMillis, cfg->isotp_user_send_can,
+ cfg->isotp_user_debug, cfg->user_data);
+ isotp_init_link(&tp->func_link, tp->func_ta, tp->recv_buf, sizeof(tp->send_buf), tp->recv_buf,
+ sizeof(tp->recv_buf), UDSMillis, cfg->isotp_user_send_can,
+ cfg->isotp_user_debug, cfg->user_data);
+ return UDS_OK;
+}
\ No newline at end of file
diff --git a/tp/isotp_c.h b/tp/isotp_c.h
new file mode 100644
index 0000000..84f6f98
--- /dev/null
+++ b/tp/isotp_c.h
@@ -0,0 +1,34 @@
+#ifndef ISOTP_C_H
+#define ISOTP_C_H
+
+#include "iso14229.h"
+#include "tp/isotp-c/isotp.h"
+
+typedef struct {
+ UDSTpHandle_t hdl;
+ IsoTpLink phys_link;
+ IsoTpLink func_link;
+ uint8_t send_buf[UDS_ISOTP_MTU];
+ uint8_t recv_buf[UDS_ISOTP_MTU];
+ uint32_t phys_sa, phys_ta;
+ uint32_t func_sa, func_ta;
+} UDSTpISOTpC_t;
+
+typedef struct {
+ uint32_t source_addr;
+ uint32_t target_addr;
+ uint32_t source_addr_func;
+ uint32_t target_addr_func;
+ int (*isotp_user_send_can)(
+ const uint32_t arbitration_id, const uint8_t *data, const uint8_t size,
+ void *user_data); /* send can message. should return ISOTP_RET_OK when success. */
+ uint32_t (*isotp_user_get_ms)(void); /* get millisecond */
+ void (*isotp_user_debug)(const char *message, ...); /* print debug message */
+ void *user_data; /* user data */
+} UDSTpISOTpCConfig_t;
+
+UDSErr_t UDSTpISOTpCInit(UDSTpISOTpC_t *tp, UDSTpISOTpCConfig_t *cfg);
+
+void UDSTpISOTpCDeinit(UDSTpISOTpC_t *tp);
+
+#endif
diff --git a/tp/isotp_c_socketcan.c b/tp/isotp_c_socketcan.c
index a2e52f1..5c5ade5 100644
--- a/tp/isotp_c_socketcan.c
+++ b/tp/isotp_c_socketcan.c
@@ -31,7 +31,7 @@ static int SetupSocketCAN(const char *ifname) {
perror("bind");
}
- done:
+done:
return sockfd;
}
@@ -44,7 +44,8 @@ void isotp_user_debug(const char *message, ...) {
va_end(args);
}
-int isotp_user_send_can(const uint32_t arbitration_id, const uint8_t *data, const uint8_t size, void *user_data) {
+int isotp_user_send_can(const uint32_t arbitration_id, const uint8_t *data, const uint8_t size,
+ void *user_data) {
assert(user_data);
int sockfd = *(int *)user_data;
struct can_frame frame = {0};
@@ -87,7 +88,8 @@ static void SocketCANRecv(UDSTpISOTpC_t *tp) {
isotp_on_can_message(&tp->phys_link, frame.data, frame.can_dlc);
} else if (frame.can_id == tp->func_sa) {
if (ISOTP_RECEIVE_STATUS_IDLE != tp->phys_link.receive_status) {
- UDS_DBG_PRINT("func frame received but cannot process because link is not idle");
+ UDS_DBG_PRINT(
+ "func frame received but cannot process because link is not idle");
return;
}
// TODO: reject if it's longer than a single frame
@@ -114,21 +116,21 @@ int peek_link(IsoTpLink *link, uint8_t *buf, size_t bufsize, bool functional) {
assert(buf);
int ret = -1;
switch (link->receive_status) {
- case ISOTP_RECEIVE_STATUS_IDLE:
- ret = 0;
- goto done;
- case ISOTP_RECEIVE_STATUS_INPROGRESS:
- ret = 0;
- goto done;
- case ISOTP_RECEIVE_STATUS_FULL:
- ret = link->receive_size;
- printf("The link is full. Copying %d bytes\n", ret);
- memmove(buf, link->receive_buffer, link->receive_size);
- break;
- default:
- UDS_DBG_PRINT("receive_status %d not implemented\n", link->receive_status);
- ret = -1;
- goto done;
+ case ISOTP_RECEIVE_STATUS_IDLE:
+ ret = 0;
+ goto done;
+ case ISOTP_RECEIVE_STATUS_INPROGRESS:
+ ret = 0;
+ goto done;
+ case ISOTP_RECEIVE_STATUS_FULL:
+ ret = link->receive_size;
+ printf("The link is full. Copying %d bytes\n", ret);
+ memmove(buf, link->receive_buffer, link->receive_size);
+ break;
+ default:
+ UDS_DBG_PRINT("receive_status %d not implemented\n", link->receive_status);
+ ret = -1;
+ goto done;
}
done:
return ret;
@@ -137,7 +139,7 @@ int peek_link(IsoTpLink *link, uint8_t *buf, size_t bufsize, bool functional) {
static ssize_t tp_peek(UDSTpHandle_t *hdl, uint8_t **p_buf, UDSSDU_t *info) {
assert(hdl);
assert(p_buf);
- UDSTpISOTpC_t *tp= (UDSTpISOTpC_t *)hdl;
+ UDSTpISOTpC_t *tp = (UDSTpISOTpC_t *)hdl;
if (ISOTP_RECEIVE_STATUS_FULL == tp->phys_link.receive_status) { // recv not yet acked
*p_buf = tp->recv_buf;
return tp->phys_link.receive_size;
@@ -184,7 +186,6 @@ static ssize_t tp_peek(UDSTpHandle_t *hdl, uint8_t **p_buf, UDSSDU_t *info) {
}
fprintf(stdout, "\n");
fflush(stdout); // flush every time in case of crash
-
}
return ret;
}
@@ -242,26 +243,35 @@ static void tp_ack_recv(UDSTpHandle_t *hdl) {
UDSTpISOTpC_t *tp = (UDSTpISOTpC_t *)hdl;
}
+static ssize_t tp_get_send_buf(UDSTpHandle_t *hdl, uint8_t **p_buf) {
+ assert(hdl);
+ UDSTpISOTpC_t *tp = (UDSTpISOTpC_t *)hdl;
+ *p_buf = tp->send_buf;
+ return sizeof(tp->send_buf);
+}
UDSErr_t UDSTpISOTpCInit(UDSTpISOTpC_t *tp, const char *ifname, uint32_t source_addr,
- uint32_t target_addr, uint32_t source_addr_func, uint32_t target_addr_func)
-{
+ uint32_t target_addr, uint32_t source_addr_func,
+ uint32_t target_addr_func) {
assert(tp);
assert(ifname);
tp->hdl.poll = tp_poll;
tp->hdl.send = tp_send;
tp->hdl.peek = tp_peek;
tp->hdl.ack_recv = tp_ack_recv;
+ tp->hdl.get_send_buf = tp_get_send_buf;
tp->phys_sa = source_addr;
tp->phys_ta = target_addr;
tp->func_sa = source_addr_func;
tp->func_ta = target_addr;
tp->fd = SetupSocketCAN(ifname);
- isotp_init_link(&tp->phys_link, target_addr, tp->send_buf, sizeof(tp->send_buf),
- tp->recv_buf, sizeof(tp->recv_buf), isotp_user_get_ms, isotp_user_send_can, isotp_user_debug, &tp->fd);
+ isotp_init_link(&tp->phys_link, target_addr, tp->send_buf, sizeof(tp->send_buf), tp->recv_buf,
+ sizeof(tp->recv_buf), isotp_user_get_ms, isotp_user_send_can, isotp_user_debug,
+ &tp->fd);
isotp_init_link(&tp->func_link, target_addr_func, tp->recv_buf, sizeof(tp->send_buf),
- tp->recv_buf, sizeof(tp->recv_buf), isotp_user_get_ms, isotp_user_send_can, isotp_user_debug, &tp->fd);
+ tp->recv_buf, sizeof(tp->recv_buf), isotp_user_get_ms, isotp_user_send_can,
+ isotp_user_debug, &tp->fd);
return UDS_OK;
}
diff --git a/tp/isotp_c_socketcan.h b/tp/isotp_c_socketcan.h
index 3b82034..16666fa 100644
--- a/tp/isotp_c_socketcan.h
+++ b/tp/isotp_c_socketcan.h
@@ -17,7 +17,8 @@ typedef struct {
} UDSTpISOTpC_t;
UDSErr_t UDSTpISOTpCInit(UDSTpISOTpC_t *tp, const char *ifname, uint32_t source_addr,
- uint32_t target_addr, uint32_t source_addr_func, uint32_t target_addr_func);
+ uint32_t target_addr, uint32_t source_addr_func,
+ uint32_t target_addr_func);
void UDSTpISOTpCDeinit(UDSTpISOTpC_t *tp);
#endif
\ No newline at end of file
diff --git a/tp/isotp_sock.c b/tp/isotp_sock.c
index 8d378ee..f642367 100644
--- a/tp/isotp_sock.c
+++ b/tp/isotp_sock.c
@@ -68,7 +68,7 @@ static ssize_t tp_peek(UDSTpHandle_t *hdl, uint8_t **p_buf, UDSSDU_t *info) {
// UDS_DBG_PRINTHEX(, ret);
}
- done:
+done:
if (ret > 0) {
impl->recv_len = ret;
}
@@ -111,7 +111,7 @@ static ssize_t tp_send(UDSTpHandle_t *hdl, uint8_t *buf, size_t len, UDSSDU_t *i
// UDS_DBG_PRINT(">>> ");
// UDS_DBG_PRINTHEX(buf, ret);
- fprintf(stdout, "%06d, %s sends, (%s), ", UDSMillis(), impl->tag,
+ fprintf(stdout, "%06d, %s sends, (%s), ", UDSMillis(), impl->tag,
ta_type == UDS_A_TA_TYPE_PHYSICAL ? "phys" : "func");
for (unsigned i = 0; i < len; i++) {
fprintf(stdout, "%02x ", buf[i]);
@@ -192,12 +192,13 @@ UDSErr_t UDSTpIsoTpSockInitServer(UDSTpIsoTpSock_t *tp, const char *ifname, uint
tp->phys_fd = LinuxSockBind(ifname, source_addr, target_addr, false);
tp->func_fd = LinuxSockBind(ifname, source_addr_func, 0, true);
if (tp->phys_fd < 0 || tp->func_fd < 0) {
- printf ("foo\n");
+ printf("foo\n");
fflush(stdout);
return UDS_ERR;
}
UDS_DBG_PRINT("%s initialized phys link rx 0x%03x tx 0x%03x func link rx 0x%03x tx 0x%03x\n",
- strlen(tp->tag) ? tp->tag : "server", source_addr, target_addr, source_addr_func, target_addr);
+ strlen(tp->tag) ? tp->tag : "server", source_addr, target_addr, source_addr_func,
+ target_addr);
return UDS_OK;
}
@@ -218,8 +219,10 @@ UDSErr_t UDSTpIsoTpSockInitClient(UDSTpIsoTpSock_t *tp, const char *ifname, uint
if (tp->phys_fd < 0 || tp->func_fd < 0) {
return UDS_ERR;
}
- printf("%s initialized phys link (fd %d) rx 0x%03x tx 0x%03x func link (fd %d) rx 0x%03x tx 0x%03x\n",
- strlen(tp->tag) ? tp->tag : "client", tp->phys_fd, source_addr, target_addr, tp->func_fd, source_addr, target_addr_func);
+ printf("%s initialized phys link (fd %d) rx 0x%03x tx 0x%03x func link (fd %d) rx 0x%03x tx "
+ "0x%03x\n",
+ strlen(tp->tag) ? tp->tag : "client", tp->phys_fd, source_addr, target_addr, tp->func_fd,
+ source_addr, target_addr_func);
return UDS_OK;
}
diff --git a/tp/mock.c b/tp/mock.c
index a7afd85..52d2aed 100644
--- a/tp/mock.c
+++ b/tp/mock.c
@@ -6,7 +6,6 @@
#include
#include
-
#define MAX_NUM_TP 16
#define NUM_MSGS 8
static TPMock_t *TPs[MAX_NUM_TP];
@@ -20,7 +19,6 @@ static struct Msg {
} msgs[NUM_MSGS];
static unsigned MsgCount = 0;
-
static void LogMsg(const char *prefix, const uint8_t *buf, size_t len, UDSSDU_t *info) {
if (!LogFile) {
return;
@@ -42,7 +40,8 @@ static void NetworkPoll() {
TPMock_t *tp = TPs[j];
if (tp->sa_phys == msg->info.A_TA || tp->sa_func == msg->info.A_TA) {
if (tp->recv_len > 0) {
- fprintf(stderr, "TPMock: %s recv buffer is already full. Message dropped\n", tp->name);
+ fprintf(stderr, "TPMock: %s recv buffer is already full. Message dropped\n",
+ tp->name);
continue;
}
memmove(tp->recv_buf, msg->buf, msg->len);
@@ -60,7 +59,7 @@ static void NetworkPoll() {
}
}
-static ssize_t tp_peek(struct UDSTpHandle *hdl,uint8_t **p_buf, UDSSDU_t *info) {
+static ssize_t tp_peek(struct UDSTpHandle *hdl, uint8_t **p_buf, UDSSDU_t *info) {
assert(hdl);
assert(p_buf);
TPMock_t *tp = (TPMock_t *)hdl;
@@ -73,7 +72,7 @@ static ssize_t tp_peek(struct UDSTpHandle *hdl,uint8_t **p_buf, UDSSDU_t *info)
return tp->recv_len;
}
-static ssize_t tp_send(struct UDSTpHandle *hdl, uint8_t * buf, size_t len, UDSSDU_t *info) {
+static ssize_t tp_send(struct UDSTpHandle *hdl, uint8_t *buf, size_t len, UDSSDU_t *info) {
assert(hdl);
TPMock_t *tp = (TPMock_t *)hdl;
if (MsgCount > NUM_MSGS) {
@@ -155,7 +154,6 @@ static void TPMockDetach(TPMock_t *tp) {
assert(false);
}
-
UDSTpHandle_t *TPMockNew(const char *name, TPMockArgs_t *args) {
if (TPCount >= MAX_NUM_TP) {
printf("TPCount: %d, too many TPs\n", TPCount);
@@ -202,7 +200,6 @@ void TPMockReset(void) {
TPCount = 0;
}
-
void TPMockFree(UDSTpHandle_t *tp) {
TPMock_t *tpm = (TPMock_t *)tp;
TPMockDetach(tpm);
diff --git a/tp/mock.h b/tp/mock.h
index 982bf31..53279a6 100644
--- a/tp/mock.h
+++ b/tp/mock.h
@@ -17,13 +17,13 @@ typedef struct TPMock {
uint8_t send_buf[UDS_BUFSIZE];
size_t recv_len;
UDSSDU_t recv_info;
- uint32_t sa_phys; // source address - physical messages are sent from this address
- uint32_t ta_phys; // target address - physical messages are sent to this address
- uint32_t sa_func; // source address - functional messages are sent from this address
- uint32_t ta_func; // target address - functional messages are sent to this address
+ uint32_t sa_phys; // source address - physical messages are sent from this address
+ uint32_t ta_phys; // target address - physical messages are sent to this address
+ uint32_t sa_func; // source address - functional messages are sent from this address
+ uint32_t ta_func; // target address - functional messages are sent to this address
uint32_t send_tx_delay_ms; // simulated delay
- uint32_t send_buf_size; // simulated size of the send buffer
- char name[32]; // name for logging
+ uint32_t send_buf_size; // simulated size of the send buffer
+ char name[32]; // name for logging
} TPMock_t;
typedef struct {
@@ -33,8 +33,14 @@ typedef struct {
uint32_t ta_func; // target address - functional messages are sent to this address
} TPMockArgs_t;
-#define TPMOCK_DEFAULT_CLIENT_ARGS &(TPMockArgs_t){.sa_phys=0x7E8, .ta_phys=0x7E0, .sa_func=UDS_TP_NOOP_ADDR, .ta_func=0x7DF}
-#define TPMOCK_DEFAULT_SERVER_ARGS &(TPMockArgs_t){.sa_phys=0x7E0, .ta_phys=0x7E8, .sa_func=0x7DF, .ta_func=UDS_TP_NOOP_ADDR}
+#define TPMOCK_DEFAULT_CLIENT_ARGS \
+ &(TPMockArgs_t) { \
+ .sa_phys = 0x7E8, .ta_phys = 0x7E0, .sa_func = UDS_TP_NOOP_ADDR, .ta_func = 0x7DF \
+ }
+#define TPMOCK_DEFAULT_SERVER_ARGS \
+ &(TPMockArgs_t) { \
+ .sa_phys = 0x7E0, .ta_phys = 0x7E8, .sa_func = 0x7DF, .ta_func = UDS_TP_NOOP_ADDR \
+ }
/**
* @brief Create a mock transport. It is connected by default to a broadcast network of all other
@@ -61,4 +67,3 @@ void TPMockReset(void);
#ifdef __cplusplus
}
#endif
-
From abb4dbf2f97ac2229c03bec6a8e27d09f098b3c5 Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Sat, 9 Dec 2023 20:11:48 -0700
Subject: [PATCH 13/56] restructure source directory
---
.gitignore | 5 +-
.gitmodules | 2 +-
BUILD | 65 +-
README.md | 58 +-
README_zh.md | 146 --
examples/BUILD | 0
examples/arduino_server/README.md | 7 +
examples/arduino_server/main/iso14229.c | 1 +
examples/arduino_server/main/iso14229.h | 1 +
examples/arduino_server/main/main.ino | 107 +
examples/client_multiserver/BUILD | 15 +
examples/client_multiserver/main.c | 59 +
examples/client_multiserver/server1.c | 1 +
examples/client_multiserver/server2.c | 0
examples/esp32_server/CMakeLists.txt | 6 +
examples/esp32_server/README.md | 9 +
examples/esp32_server/main/CMakeLists.txt | 6 +
examples/esp32_server/main/iso14229.c | 1 +
examples/esp32_server/main/iso14229.h | 1 +
examples/esp32_server/main/main.c | 113 +
examples/s32k144/BUILD | 5 +-
examples/server_minimal/BUILD | 10 +
examples/server_minimal/main.c | 70 +
iso14229.c | 1956 -----------------
iso14229.h | 716 ------
run_gdb.py | 53 +
src/client.c | 856 ++++++++
src/client.h | 144 ++
src/config.h | 66 +
.../iso14229serverbufferedwriter.h | 0
src/server.c | 944 ++++++++
src/server.h | 169 ++
src/sys.h | 30 +
src/sys_arduino.h | 16 +
src/sys_esp32.h | 14 +
src/sys_unix.h | 12 +
src/sys_win32.h | 8 +
src/tp.c | 64 +
src/tp.h | 128 ++
src/tp/README.md | 66 +
{tp => src/tp}/isotp-c | 0
{tp => src/tp}/isotp_c.c | 26 +-
{tp => src/tp}/isotp_c.h | 19 +-
{tp => src/tp}/isotp_c_socketcan.c | 34 +-
{tp => src/tp}/isotp_c_socketcan.h | 7 +-
{tp => src/tp}/isotp_sock.c | 35 +-
{tp => src/tp}/isotp_sock.h | 4 +-
{tp => src/tp}/mock.c | 26 +-
{tp => src/tp}/mock.h | 14 +-
src/uds.h | 223 ++
src/util.c | 30 +
src/util.h | 42 +
test/BUILD | 16 +-
test/env.c | 3 -
test/test.h | 1 -
test/test_fuzz_server.c | 4 +-
test_iso14229.c | 875 --------
tp/BUILD | 63 -
58 files changed, 3445 insertions(+), 3907 deletions(-)
create mode 100644 examples/BUILD
create mode 100644 examples/arduino_server/README.md
create mode 120000 examples/arduino_server/main/iso14229.c
create mode 120000 examples/arduino_server/main/iso14229.h
create mode 100644 examples/arduino_server/main/main.ino
create mode 100644 examples/client_multiserver/BUILD
create mode 100644 examples/client_multiserver/main.c
create mode 100644 examples/client_multiserver/server1.c
create mode 100644 examples/client_multiserver/server2.c
create mode 100644 examples/esp32_server/CMakeLists.txt
create mode 100644 examples/esp32_server/README.md
create mode 100644 examples/esp32_server/main/CMakeLists.txt
create mode 120000 examples/esp32_server/main/iso14229.c
create mode 120000 examples/esp32_server/main/iso14229.h
create mode 100644 examples/esp32_server/main/main.c
create mode 100644 examples/server_minimal/BUILD
create mode 100644 examples/server_minimal/main.c
delete mode 100644 iso14229.c
delete mode 100644 iso14229.h
create mode 100755 run_gdb.py
create mode 100644 src/client.c
create mode 100644 src/client.h
create mode 100644 src/config.h
rename iso14229serverbufferedwriter.h => src/iso14229serverbufferedwriter.h (100%)
create mode 100644 src/server.c
create mode 100644 src/server.h
create mode 100644 src/sys.h
create mode 100644 src/sys_arduino.h
create mode 100644 src/sys_esp32.h
create mode 100644 src/sys_unix.h
create mode 100644 src/sys_win32.h
create mode 100644 src/tp.c
create mode 100644 src/tp.h
create mode 100644 src/tp/README.md
rename {tp => src/tp}/isotp-c (100%)
rename {tp => src/tp}/isotp_c.c (91%)
rename {tp => src/tp}/isotp_c.h (76%)
rename {tp => src/tp}/isotp_c_socketcan.c (87%)
rename {tp => src/tp}/isotp_c_socketcan.h (90%)
rename {tp => src/tp}/isotp_sock.c (88%)
rename {tp => src/tp}/isotp_sock.h (93%)
rename {tp => src/tp}/mock.c (89%)
rename {tp => src/tp}/mock.h (94%)
create mode 100644 src/uds.h
create mode 100644 src/util.c
create mode 100644 src/util.h
delete mode 100644 test_iso14229.c
delete mode 100644 tp/BUILD
diff --git a/.gitignore b/.gitignore
index 2b53068..b0a5de7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,4 +9,7 @@ corpus
.gdb_history
fuzzer
*.o
-.vscode
\ No newline at end of file
+.vscode
+**/*.cache
+**/build
+**/sdkconfig*
diff --git a/.gitmodules b/.gitmodules
index 0a9e643..d7b4425 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,3 @@
[submodule "tp/isotp-c"]
- path = tp/isotp-c
+ path = src/tp/isotp-c
url = https://github.com/driftregion/isotp-c.git
diff --git a/BUILD b/BUILD
index d4db888..869aba6 100644
--- a/BUILD
+++ b/BUILD
@@ -1,37 +1,52 @@
package(default_visibility = ["//visibility:public"])
load("@hedron_compile_commands//:refresh_compile_commands.bzl", "refresh_compile_commands")
+genrule(
+ name = "isotp_c_wrapped_c",
+ srcs = glob(["src/tp/isotp-c/*.c"]),
+ outs = ["isotp_c_wrapped.c"],
+ cmd = "echo '#if defined(UDS_TP) && UDS_TP==UDS_TP_ISOTP_C' >> $(OUTS) ; for f in $(SRCS); do cat $$f >> $(OUTS); done ; echo '#endif' >> $(OUTS)",
+)
+
+genrule(
+ name = "isotp_c_wrapped_h",
+ srcs = glob(["src/tp/isotp-c/*.h"]),
+ outs = ["isotp_c_wrapped.h"],
+ cmd = "echo '#if defined(UDS_TP) && UDS_TP==UDS_TP_ISOTP_C' >> $(OUTS) ; for f in $(SRCS); do cat $$f >> $(OUTS); done ; echo '#endif' >> $(OUTS)",
+)
+
+genrule(
+ name = "c_src",
+ srcs = glob(["src/*.c", "src/tp/*.c"]) + [
+ ":isotp_c_wrapped_c",
+ ],
+ outs = ["iso14229.c"],
+ cmd = "(echo '#include \"iso14229.h\"'; (for f in $(SRCS); do echo; echo '#ifdef UDS_LINES'; echo \"#line 1 \\\"$$f\"\\\"; echo '#endif'; cat $$f | sed -e 's,#include \".*,,'; done)) > $(OUTS)",
+)
+
+genrule(
+ name = "h_src",
+ srcs = glob(["src/*.h", "src/tp/*.h"]) + [
+ ":isotp_c_wrapped_h",
+ ],
+ outs = ["iso14229.h"],
+ cmd = "echo $(SRCS); (cat ; echo '#ifndef ISO14229_H'; echo '#define ISO14229_H'; echo; echo '#ifdef __cplusplus'; echo 'extern \"C\" {'; echo '#endif'; cat src/sys.h src/sys_arduino.h src/sys_unix.h src/sys_win32.h src/sys_esp32.h src/config.h src/util.h src/tp.h src/uds.h src/client.h src/server.h $(location //:isotp_c_wrapped_h) src/tp/*.h |sed -e 's,#include \".*,,' -e 's,^#pragma once,,' ; echo '#endif'; echo '#ifdef __cplusplus'; echo '}'; echo '#endif';) > $(OUTS)",
+)
filegroup(
- name = "iso14229_srcs",
+ name = "srcs",
srcs = [
"iso14229.c",
"iso14229.h",
- "iso14229serverbufferedwriter.h",
],
)
-cc_test(
- name="test_all",
- srcs=[
- ":iso14229_srcs",
- "test_iso14229.c",
- ],
- deps = [
- "//tp:mock",
- ],
- copts=[
- "-Wall",
- "-Wextra",
- "-Wno-missing-field-initializers",
- "-Werror",
- "-Wno-unused-parameter",
- ],
- defines=[
- "UDS_TP=UDS_TP_CUSTOM",
- "UDS_CUSTOM_MILLIS",
+cc_library(
+ name="iso14229",
+ srcs = [
+ "iso14229.c",
+ "iso14229.h",
],
- size = "small",
)
cc_test(
@@ -43,9 +58,11 @@ cc_test(
size = "small",
)
+
cc_library(
- name="iso14229",
- srcs=[":iso14229_srcs"],
+ name="iso14229_2",
+ srcs=glob(["src/**/*.c", "src/**/*.h"]),
+ copts=['-Isrc'],
)
diff --git a/README.md b/README.md
index 7448ec8..187ebe5 100644
--- a/README.md
+++ b/README.md
@@ -9,57 +9,37 @@
简体中文
-iso14229 is a server and client session-layer implementation of (ISO14229-1:2013) targeting embedded systems. It is tested with [`isotp-c`](https://github.com/lishen2/isotp-c) as well as [linux kernel](https://github.com/linux-can/can-utils/blob/master/include/linux/can/isotp.h) ISO15765-2 (ISO-TP) transport layer implementations.
+iso14229 is an implementation of UDS (ISO14229-1:2013) targeting embedded systems. It is tested with [`isotp-c`](https://github.com/lishen2/isotp-c) as well as [linux kernel](https://github.com/linux-can/can-utils/blob/master/include/linux/can/isotp.h) ISO15765-2 (ISO-TP) transport layer implementations.
-API status: **stabilizing**
+API status: **not yet stable**.
-## quickstart: server
+## Features
-```c
-#include "iso14229.h"
-
-static uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
- switch (ev) {
- case UDS_SRV_EVT_EcuReset: { // 0x10
- UDSECUResetArgs_t *r = (UDSECUResetArgs_t *)arg;
- printf("got ECUReset request of type %x\n", r->type);
- return kPositiveResponse;
- default:
- return kServiceNotSupported;
- }
- }
-}
+- static memory allocation. does not use `malloc`, `calloc`
+- highly portable. tested on arm, x86-64, ppc, ppc64
+- easy to integrate. Download `iso14229.c` and `iso14229.h` from the releases page and copy into your source tree.
+- supports:
+ - linux
+ - Windows
+ - esp32
+ - Arduino
+ - NXP s32k
+- cares about security
+ - server has fuzz test, see [test/README.md](test/README.md)
+ -
-int main() {
- UDSServer_t server;
- UDSServerConfig_t cfg = {
- .fn = &fn,
- };
- UDSServerInit(&server, &cfg);
- for (;;) {
- UDSServerPoll(&server);
- }
-}
-```
+## Quick Start
-## quickstart: client
-
-```c
-// see examples/client.c
-```
+See [examples](./examples).
## Preprocessor Defines
| Define | Description | Valid values |
| - | - | - |
-| `UDS_ARCH` | Select a porting target | `UDS_ARCH_CUSTOM`, `UDS_ARCH_UNIX` |
+| `UDS_SYS` | Select a porting target | `UDS_SYS_CUSTOM`, `UDS_SYS_UNIX` |
| `UDS_TP` | Select a transport layer | `UDS_TP_ISOTP_C`, `UDS_TP_ISOTP_SOCKET` |
| `UDS_CUSTOM_MILLIS` | Use your own `millis()` implementation | defined or not defined |
-Features:
-- all memory allocation is static
-- architecture-independent. tested on arm, x86-64, ppc, ppc64. see [test_qemu.py](./test_qemu.py)
-- has many existing unit-tests and tests are easy to extend
## supported functions (server and client )
@@ -362,9 +342,9 @@ MIT
## 0.7.0
- test refactoring. theme: test invariance across different transports and processor architectures
- breaking API changes:
- - rename `phys_send_id`, `phys_recv_id`, `func_send_id`, and `func_recv_id` to be consistent with the standard. Now mandatory for all UDSServerConfig_t and UDSClientConfig_t regardless of transport layer implementation
- overhauled transport layer implementation
- simplified client and server init
+ - `UDS_ARCH_` renamed to `UDS_SYS_`
## 0.6.0
- breaking API changes:
diff --git a/README_zh.md b/README_zh.md
index 4f10b80..8a0b02b 100644
--- a/README_zh.md
+++ b/README_zh.md
@@ -407,149 +407,3 @@ MIT
- 初次发布
---
-
-
-# 开发者文档
-
-## 客户端请求状态机
-
-```plantuml
-@startuml
-title 客户端请求状态机
-note as N1
-enum {
- kNoError=0,
- kErrBadRequest,
- kErrP2Timeout,
-} ClientErr;
-
-static inline bool isRequestComplete() {return state==Idle;}
-
-while (Idle != client->state) {
- receiveCAN(client);
- UDSClientPoll(client);
-}
-end note
-
-state Idle
-state Sending
-state Sent
-state SentAwaitResponse
-state ProcessResponse
-Idle: if (ISOTP_RET_OK == isotp_receive(...)) // Error
-ProcessResponse: isotp_receive()
-ProcessResponse: _ClientValidateResponse(...)
-ProcessResponse: _ClientHandleResponse(...)
-
-Sending --> Sent: 传输层完成传输
-
-Sent --> Idle : suppressPositiveResponse
-Sending --> SentAwaitResponse: !suppressPositiveResponse
-SentAwaitResponse -> Idle: 响应收到了 ||\np2 超时
-SentAwaitResponse --> ProcessResponse : ISOTP_RECEIVE_STATUS_FULL == link->receive_status
-ProcessResponse --> Idle
-
-[*] -> Idle
-Idle -> Sending : _SendRequest()
-
-@enduml
-```
-
-```plantuml
-@startuml
-title Request Lifecycle
-alt normal
- alt positive response
- client --> client: Sending
- client -> server : *Any* Service
- client --> client: SentAwaitResponse: set p2
- alt 0x78 requestCorrectlyReceived-ResponsePending
- server -> client : 0x3F 0x78
- client -->server : txLink idle
- client --> client: SentAwaitResponse: set p2star
- end
- server -> client : Positive Service Response
- client --> client: Idle
- else negative response
- server -> client !! : Negative Service Response
- client --> client: Idle: RequestErrorNegativeResponse
- else SID mismatch
- server -> client !! : Mismatched Service Response
- client --> client: Idle: RequestErrorResponseSIDMismatch
- end
-else unexpected response
- server -> client !! : Unexpected Response
- client --> client: Idle: RequestErrorUnsolicitedResponse
-end
-@enduml
-```
-
-
-```plantuml
-@startuml
-' !pragma useVerticalIf on
-title 客户端请求流程
-start
-
-:clientSendRequest();
-if (验证参数) then (对)
-:ok;
-else (不对)
-:foo;
-detach
-endif
-
-:clearRequestContext();
-if (等待UDS访问) then (访问接收了,进入UDS会话)
-else (时间超过20ms)
-@enduml
-```
-
-## 服务器 0x78 requestCorrectlyReceived-ResponsePending
-
-
-```plantuml
-@startuml
-client -> server : *Any* Service
-server -> userServiceHandler: handler(args)
-note right: Doing this will take a long time\nso I return 0x78
-userServiceHandler -> server: 0x78
-server -> client : 0x3F 0x78
-client -->server : txLink idle
-server -> userServiceHandler: handler(args)
-note right: actually call the long-running service
-... p2* > t > p2 ...
-userServiceHandler -> server : Service Response
-server -> client : Service Response
-@enduml
-```
-
-```plantuml
-@startuml
-' !pragma useVerticalIf on
-title 0x78流程(写flash)
-start
-
-:BufferedWriterWrite(BufferedWriter *self, const uint8_t *ibuf, uint32_t size, bool RCRRP);
-
-if (RCRRP) then (true)
-:write to flash;
-else (false)
-endif
-if (iBufIdx == size) then (true)
- :write to pageBuffer;
- :iBufIdx = 0;
- :return kBufferedWriterWritePending;
- :0x78 RCRRP;
- detach;
-else (false)
- :memmove(pageBuffer + pageBufIdx, iBuf + iBufIdx, size - iBufIdx);
- :write to pageBuffer;
- :iBufIdx += size;
- :0x01 PositiveResponse;
- :0x78 RCRRP;
- detach
-endif
-
-@enduml
-```
diff --git a/examples/BUILD b/examples/BUILD
new file mode 100644
index 0000000..e69de29
diff --git a/examples/arduino_server/README.md b/examples/arduino_server/README.md
new file mode 100644
index 0000000..901c6b1
--- /dev/null
+++ b/examples/arduino_server/README.md
@@ -0,0 +1,7 @@
+# Required Hardware
+
+- [Arduino MKR-WIFI 1010](https://store-usa.arduino.cc/products/arduino-mkr-wifi-1010)
+- [MKR CAN Shield](https://store.arduino.cc/products/arduino-mkr-can-shield)
+
+Note that the labeling of CAN-H and CAN-L on silkscreen on the MKR CAN Shield is contradictory on the top and bottom of the board. The top is correct.
+
diff --git a/examples/arduino_server/main/iso14229.c b/examples/arduino_server/main/iso14229.c
new file mode 120000
index 0000000..fa2cd67
--- /dev/null
+++ b/examples/arduino_server/main/iso14229.c
@@ -0,0 +1 @@
+../../../bazel-bin/iso14229.c
\ No newline at end of file
diff --git a/examples/arduino_server/main/iso14229.h b/examples/arduino_server/main/iso14229.h
new file mode 120000
index 0000000..c026bd1
--- /dev/null
+++ b/examples/arduino_server/main/iso14229.h
@@ -0,0 +1 @@
+../../../bazel-bin/iso14229.h
\ No newline at end of file
diff --git a/examples/arduino_server/main/main.ino b/examples/arduino_server/main/main.ino
new file mode 100644
index 0000000..0bc348f
--- /dev/null
+++ b/examples/arduino_server/main/main.ino
@@ -0,0 +1,107 @@
+#include
+#include "iso14229.h"
+#include
+#include
+
+UDSServer_t srv;
+UDSISOTpC_t tp;
+
+int send_can(const uint32_t arb_id, const uint8_t *data, const uint8_t size, void *ud) {
+ CAN.beginPacket(arb_id);
+ CAN.write(data, size);
+ CAN.endPacket();
+ return size;
+}
+
+static void CANRecv(UDSISOTpC_t *tp) {
+ assert(tp);
+ uint8_t buf[8];
+ int len = CAN.parsePacket();
+ if (len) {
+ if (len > 8) {
+ Serial.println("CAN packet too long, truncating");
+ len = 8;
+ }
+ CAN.readBytes(buf, len);
+ UDS_DBG_PRINT("can recv\n");
+ UDS_DBG_PRINTHEX(buf, len);
+ if (CAN.packetId() == tp->phys_sa) {
+ UDS_DBG_PRINT("phys frame received\n");
+ isotp_on_can_message(&tp->phys_link, buf, len);
+ } else if (CAN.packetId() == tp->func_sa) {
+ if (ISOTP_RECEIVE_STATUS_IDLE != tp->phys_link.receive_status) {
+ UDS_DBG_PRINT("func frame received but cannot process because link is not idle");
+ return;
+ }
+ isotp_on_can_message(&tp->func_link, buf, len);
+ }
+ }
+}
+
+extern "C" int print_impl(const char *fmt, ...);
+
+const UDSISOTpCConfig_t tp_cfg = {
+ .source_addr=0x7E8,
+ .target_addr=0x7E0,
+ .source_addr_func=0x7DF,
+ .target_addr_func=UDS_TP_NOOP_ADDR,
+ .isotp_user_send_can=send_can,
+ .isotp_user_get_ms=UDSMillis,
+ .isotp_user_debug=NULL,
+ .user_data=NULL,
+};
+
+int print_impl(const char *fmt, ...) {
+ char buf[256];
+ va_list args;
+ va_start(args, fmt);
+ int ret = vsnprintf(buf, sizeof(buf), fmt, args);
+ Serial.print(buf);
+ va_end(args);
+ return ret;
+}
+
+uint8_t fn(UDSServer_t *srv, int ev, const void *arg) {
+ Serial.print("Got event ");
+ Serial.println(ev);
+ switch(ev) {
+ case UDS_SRV_EVT_Err:
+ {
+ UDSErr_t *p_err = (UDSErr_t *)arg;
+ Serial.print("Err: ");
+ Serial.println(*p_err);
+ break;
+ }
+ }
+}
+
+void setup() {
+ Serial.begin(9600);
+ while (!Serial);
+
+ if(!UDSServerInit(&srv)) {
+ Serial.println("UDSServerInit failed");
+ while(1);
+ }
+
+ if (!UDSISOTpCInit(&tp, &tp_cfg)) {
+ Serial.println("UDSISOTpCInit failed");
+ while(1);
+ }
+
+ srv.tp = &tp.hdl;
+ srv.fn = fn;
+
+ // start the CAN bus at 500 kbps
+ if (!CAN.begin(500E3)) {
+ Serial.println("Starting CAN failed!");
+ while (1);
+ }
+
+ Serial.println("Arduino UDS Server: Setup Complete");
+}
+
+void loop() {
+ UDSServerPoll(&srv);
+ CANRecv(&tp);
+}
diff --git a/examples/client_multiserver/BUILD b/examples/client_multiserver/BUILD
new file mode 100644
index 0000000..4e5b9b7
--- /dev/null
+++ b/examples/client_multiserver/BUILD
@@ -0,0 +1,15 @@
+# cc_binary(
+# name = "client_multiserver",
+# srcs = [
+# "main.c",
+# "server1.c",
+# "server2.c",
+# ],
+# deps = [
+# "//:iso14229",
+# "//:tp_mock",
+# ],
+# defines = [
+# "UDS_TP=UDS_TP_CUSTOM",
+# ]
+# )
\ No newline at end of file
diff --git a/examples/client_multiserver/main.c b/examples/client_multiserver/main.c
new file mode 100644
index 0000000..f859906
--- /dev/null
+++ b/examples/client_multiserver/main.c
@@ -0,0 +1,59 @@
+#include "iso14229.h"
+#include "tp_mock.h"
+
+typedef struct {
+ bool Done;
+ int NumResponses;
+ int Step;
+} Ctx_t;
+
+void fn(UDSClient_t *client, UDSEvent_t evt, void *evtdata, void *fndata) {
+ Ctx_t *ctx = (Ctx_t *)fndata;
+ switch (evt) {
+ case UDS_EVT_IDLE:
+ switch (ctx->Step) {
+ case 0:
+ client->options |= UDS_FUNCTIONAL;
+ uint16_t did_list[] = {0x1, 0x8};
+ UDSSendRDBI(client, did_list, sizeof(did_list) / sizeof(did_list[0]));
+ ctx->Step++;
+ break;
+ default:
+ break;
+ }
+ break;
+ case UDS_EVT_RESP_RECV:
+ switch (ctx->Step) {
+ case 1:
+ ctx->NumResponses++;
+ // int err = UDSUnpackRDBIResponse(client, evtdata);
+ ctx->Step++;
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+}
+
+int main() {
+ UDSClient_t client;
+ Ctx_t ctx = {0};
+ UDSServer_t server1, server2, server3;
+
+ {
+ UDSClientConfig_t cfg = {
+ .tp = TPMockNew(&(TPMockCfg_t){.phys_recv_addr = 0x1,
+ .phys_send_addr = 0x2,
+ .func_recv_addr = 0x3,
+ .func_send_addr = 0x4});
+ }
+ UDSClientInit(&client, &cfg);
+}
+
+while (!ctx.Done) {
+ UDSClientPoll2(&client, fn, &ctx);
+ UDSServerPoll(&server1);
+ UDSServerPoll(&server2);
+}
+}
\ No newline at end of file
diff --git a/examples/client_multiserver/server1.c b/examples/client_multiserver/server1.c
new file mode 100644
index 0000000..5a56d0d
--- /dev/null
+++ b/examples/client_multiserver/server1.c
@@ -0,0 +1 @@
+#include "iso14229.h"
diff --git a/examples/client_multiserver/server2.c b/examples/client_multiserver/server2.c
new file mode 100644
index 0000000..e69de29
diff --git a/examples/esp32_server/CMakeLists.txt b/examples/esp32_server/CMakeLists.txt
new file mode 100644
index 0000000..a246da0
--- /dev/null
+++ b/examples/esp32_server/CMakeLists.txt
@@ -0,0 +1,6 @@
+# The following lines of boilerplate have to be in your project's CMakeLists
+# in this exact order for cmake to work correctly
+cmake_minimum_required(VERSION 3.5)
+
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+project(esp32_server)
diff --git a/examples/esp32_server/README.md b/examples/esp32_server/README.md
new file mode 100644
index 0000000..2808133
--- /dev/null
+++ b/examples/esp32_server/README.md
@@ -0,0 +1,9 @@
+# Required Hardware
+
+- [ESP32-C3-32S](https://docs.ai-thinker.com/_media/esp32/docs/esp-c3-32s-kit-v1.0_specification.pdf)
+- [Waveshare SN65HVD230 CAN Board](https://www.waveshare.com/sn65hvd230-can-board.htm)
+
+# Setup
+
+1. download and install `esp-idf`
+2. connect CAN board to ESP32
\ No newline at end of file
diff --git a/examples/esp32_server/main/CMakeLists.txt b/examples/esp32_server/main/CMakeLists.txt
new file mode 100644
index 0000000..6f7ca4c
--- /dev/null
+++ b/examples/esp32_server/main/CMakeLists.txt
@@ -0,0 +1,6 @@
+idf_component_register(
+ SRCS "main.c"
+ "iso14229.c"
+ "iso14229.h"
+ INCLUDE_DIRS "."
+)
\ No newline at end of file
diff --git a/examples/esp32_server/main/iso14229.c b/examples/esp32_server/main/iso14229.c
new file mode 120000
index 0000000..fa2cd67
--- /dev/null
+++ b/examples/esp32_server/main/iso14229.c
@@ -0,0 +1 @@
+../../../bazel-bin/iso14229.c
\ No newline at end of file
diff --git a/examples/esp32_server/main/iso14229.h b/examples/esp32_server/main/iso14229.h
new file mode 120000
index 0000000..c026bd1
--- /dev/null
+++ b/examples/esp32_server/main/iso14229.h
@@ -0,0 +1 @@
+../../../bazel-bin/iso14229.h
\ No newline at end of file
diff --git a/examples/esp32_server/main/main.c b/examples/esp32_server/main/main.c
new file mode 100644
index 0000000..feb2dbd
--- /dev/null
+++ b/examples/esp32_server/main/main.c
@@ -0,0 +1,113 @@
+#include "driver/gpio.h"
+#include "iso14229.h"
+#include
+#include
+
+#define CAN_RX_PIN GPIO_NUM_7
+#define CAN_TX_PIN GPIO_NUM_6
+#define RED_LED_PIN GPIO_NUM_3
+#define GREEN_LED_PIN GPIO_NUM_4
+#define BLUE_LED_PIN GPIO_NUM_5
+
+const char *TAG = "UDS";
+
+static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_500KBITS();
+static const twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
+static const twai_general_config_t g_config = {.mode = TWAI_MODE_NORMAL,
+ .tx_io = CAN_TX_PIN,
+ .rx_io = CAN_RX_PIN,
+ .clkout_io = TWAI_IO_UNUSED,
+ .bus_off_io = TWAI_IO_UNUSED,
+ .tx_queue_len = 50,
+ .rx_queue_len = 50,
+ .alerts_enabled =
+ TWAI_ALERT_RX_DATA | TWAI_ALERT_BUS_OFF,
+ .clkout_divider = 0,
+ .intr_flags = ESP_INTR_FLAG_LEVEL1};
+
+static UDSServer_t srv;
+static UDSISOTpC_t tp;
+
+static int send_can(const uint32_t arbitration_id, const uint8_t *data, const uint8_t size,
+ void *user_data) {
+ twai_message_t tx_msg;
+ tx_msg.identifier = arbitration_id;
+ tx_msg.data_length_code = size;
+ memmove(tx_msg.data, data, size);
+ if (ESP_OK == twai_transmit(&tx_msg, 0)) {
+ return size;
+ } else {
+ return -1;
+ }
+}
+
+static const UDSISOTpCConfig_t tp_cfg = {
+ .source_addr=0x7E8,
+ .target_addr=0x7E0,
+ .source_addr_func=0x7DF,
+ .target_addr_func=UDS_TP_NOOP_ADDR,
+ .isotp_user_send_can=send_can,
+ .isotp_user_get_ms=UDSMillis,
+ .isotp_user_debug=NULL,
+ .user_data=NULL,
+};
+
+static uint8_t fn(UDSServer_t *srv, int evt, const void *data) {
+ ESP_LOGI(TAG, "received event %d", evt);
+ switch (evt) {
+ case UDS_SRV_EVT_WriteDataByIdent: {
+ UDSWDBIArgs_t *r = (UDSWDBIArgs_t *)data;
+ switch (r->dataId) {
+ case 0x0001:
+ ESP_LOGI(TAG, "received 0x0001");
+ gpio_set_level(RED_LED_PIN, r->data[0] & 0x01);
+ gpio_set_level(GREEN_LED_PIN, r->data[0] & 0x02);
+ gpio_set_level(BLUE_LED_PIN, r->data[0] & 0x04);
+ break;
+ default:
+ ESP_LOGI(TAG, "received unknown data id 0x%04x", r->dataId);
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+void app_main(void) {
+ ESP_ERROR_CHECK(twai_driver_install(&g_config, &t_config, &f_config));
+ ESP_ERROR_CHECK(twai_start());
+
+ gpio_config_t io_conf;
+ io_conf.intr_type = GPIO_INTR_DISABLE;
+ io_conf.mode = GPIO_MODE_OUTPUT;
+ io_conf.pin_bit_mask = (1ULL << RED_LED_PIN) | (1ULL << GREEN_LED_PIN) | (1ULL << BLUE_LED_PIN);
+ io_conf.pull_down_en = 0;
+ io_conf.pull_up_en = 0;
+ gpio_config(&io_conf);
+
+
+ ESP_ERROR_CHECK(UDSServerInit(&srv));
+ ESP_ERROR_CHECK(UDSISOTpCInit(&tp, &tp_cfg));
+ srv.fn = fn;
+ srv.tp = &tp.hdl;
+
+ for (;;) {
+ twai_message_t rx_msg;
+ if (twai_receive(&rx_msg, 0) == ESP_OK) {
+ if (rx_msg.identifier == tp.phys_sa) {
+ isotp_on_can_message(&tp.phys_link, rx_msg.data, rx_msg.data_length_code);
+ } else if (rx_msg.identifier == tp.func_sa) {
+ if (ISOTP_RECEIVE_STATUS_IDLE != tp.phys_link.receive_status) {
+ ESP_LOGI(TAG, "func frame received but cannot process because link is not idle");
+ continue;
+ }
+ isotp_on_can_message(&tp.func_link, rx_msg.data, rx_msg.data_length_code);
+ } else {
+ ESP_LOGI(TAG, "received unknown can id 0x%03lx", rx_msg.identifier);
+ }
+ }
+
+ UDSServerPoll(&srv);
+ }
+
+}
\ No newline at end of file
diff --git a/examples/s32k144/BUILD b/examples/s32k144/BUILD
index 231b399..a407dd5 100644
--- a/examples/s32k144/BUILD
+++ b/examples/s32k144/BUILD
@@ -6,10 +6,7 @@ cc_binary(
"main.c",
"bsp.c",
"bsp.h",
- "//:iso14229_srcs",
- "//tp:isotp_c_srcs",
- "//tp:isotp_c.c",
- "//tp:isotp_c.h",
+ "//:srcs",
],
deps = [
":runtime",
diff --git a/examples/server_minimal/BUILD b/examples/server_minimal/BUILD
new file mode 100644
index 0000000..4b2bb79
--- /dev/null
+++ b/examples/server_minimal/BUILD
@@ -0,0 +1,10 @@
+# cc_binary(
+# name = "server_minimal",
+# srcs = [
+# "main.c",
+# "//:iso14229_srcs",
+# ],
+# deps = [
+# "//:tp_mock",
+# ]
+# )
\ No newline at end of file
diff --git a/examples/server_minimal/main.c b/examples/server_minimal/main.c
new file mode 100644
index 0000000..afc63a5
--- /dev/null
+++ b/examples/server_minimal/main.c
@@ -0,0 +1,70 @@
+#include "iso14229.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+static UDSServer_t srv;
+static bool done = false;
+
+void sigint_handler(int signum) {
+ printf("SIGINT received\n");
+ done = true;
+}
+
+static uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
+ switch (ev) {
+ default:
+ printf("Unhandled event: %d\n", ev);
+ return kServiceNotSupported;
+ }
+}
+
+static int SleepMillis(uint32_t tms) {
+ struct timespec ts;
+ int ret;
+ ts.tv_sec = tms / 1000;
+ ts.tv_nsec = (tms % 1000) * 1000000;
+ do {
+ ret = nanosleep(&ts, &ts);
+ } while (ret && errno == EINTR);
+ return ret;
+}
+
+int main(int ac, char **av) {
+ UDSServerConfig_t cfg = {
+ .fn = fn,
+#if UDS_TP == UDS_TP_ISOTP_SOCKET
+ .if_name = "vcan0",
+ .source_addr = 0x7E0,
+ .target_addr = 0x7E8,
+ .source_addr_func = 0x7DF,
+#endif
+ };
+
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = sigint_handler;
+ sigaction(SIGINT, &sa, NULL);
+
+ if (UDSServerInit(&srv, &cfg)) {
+ exit(-1);
+ }
+
+ printf("server up, polling . . .\n");
+ while (!done) {
+ UDSServerPoll(&srv);
+#if UDS_TP == UDS_TP_ISOTP_C
+ SocketCANRecv((UDSTpISOTpC_t *)srv.tp, cfg.source_addr);
+#endif
+ SleepMillis(1);
+ }
+ printf("server exiting\n");
+ UDSServerDeInit(&srv);
+ return 0;
+}
diff --git a/iso14229.c b/iso14229.c
deleted file mode 100644
index 1bc1f5c..0000000
--- a/iso14229.c
+++ /dev/null
@@ -1,1956 +0,0 @@
-#include "iso14229.h"
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-// ISO-14229-1:2013 Table 2
-#define UDS_MAX_DIAGNOSTIC_SERVICES 0x7F
-
-#define UDS_RESPONSE_SID_OF(request_sid) (request_sid + 0x40)
-#define UDS_REQUEST_SID_OF(response_sid) (response_sid - 0x40)
-
-#define UDS_NEG_RESP_LEN 3U
-#define UDS_0X10_REQ_LEN 2U
-#define UDS_0X10_RESP_LEN 6U
-#define UDS_0X11_REQ_MIN_LEN 2U
-#define UDS_0X11_RESP_BASE_LEN 2U
-#define UDS_0X23_REQ_MIN_LEN 4U
-#define UDS_0X23_RESP_BASE_LEN 1U
-#define UDS_0X22_RESP_BASE_LEN 1U
-#define UDS_0X27_REQ_BASE_LEN 2U
-#define UDS_0X27_RESP_BASE_LEN 2U
-#define UDS_0X28_REQ_BASE_LEN 3U
-#define UDS_0X28_RESP_LEN 2U
-#define UDS_0X2E_REQ_BASE_LEN 3U
-#define UDS_0X2E_REQ_MIN_LEN 4U
-#define UDS_0X2E_RESP_LEN 3U
-#define UDS_0X31_REQ_MIN_LEN 4U
-#define UDS_0X31_RESP_MIN_LEN 4U
-#define UDS_0X34_REQ_BASE_LEN 3U
-#define UDS_0X34_RESP_BASE_LEN 2U
-#define UDS_0X35_REQ_BASE_LEN 3U
-#define UDS_0X35_RESP_BASE_LEN 2U
-#define UDS_0X36_REQ_BASE_LEN 2U
-#define UDS_0X36_RESP_BASE_LEN 2U
-#define UDS_0X37_REQ_BASE_LEN 1U
-#define UDS_0X37_RESP_BASE_LEN 1U
-#define UDS_0X3E_REQ_MIN_LEN 2U
-#define UDS_0X3E_REQ_MAX_LEN 2U
-#define UDS_0X3E_RESP_LEN 2U
-#define UDS_0X85_REQ_BASE_LEN 2U
-#define UDS_0X85_RESP_LEN 2U
-
-enum UDSDiagnosticServiceId {
- kSID_DIAGNOSTIC_SESSION_CONTROL = 0x10,
- kSID_ECU_RESET = 0x11,
- kSID_CLEAR_DIAGNOSTIC_INFORMATION = 0x14,
- kSID_READ_DTC_INFORMATION = 0x19,
- kSID_READ_DATA_BY_IDENTIFIER = 0x22,
- kSID_READ_MEMORY_BY_ADDRESS = 0x23,
- kSID_READ_SCALING_DATA_BY_IDENTIFIER = 0x24,
- kSID_SECURITY_ACCESS = 0x27,
- kSID_COMMUNICATION_CONTROL = 0x28,
- kSID_READ_PERIODIC_DATA_BY_IDENTIFIER = 0x2A,
- kSID_DYNAMICALLY_DEFINE_DATA_IDENTIFIER = 0x2C,
- kSID_WRITE_DATA_BY_IDENTIFIER = 0x2E,
- kSID_INPUT_CONTROL_BY_IDENTIFIER = 0x2F,
- kSID_ROUTINE_CONTROL = 0x31,
- kSID_REQUEST_DOWNLOAD = 0x34,
- kSID_REQUEST_UPLOAD = 0x35,
- kSID_TRANSFER_DATA = 0x36,
- kSID_REQUEST_TRANSFER_EXIT = 0x37,
- kSID_REQUEST_FILE_TRANSFER = 0x38,
- kSID_WRITE_MEMORY_BY_ADDRESS = 0x3D,
- kSID_TESTER_PRESENT = 0x3E,
- kSID_ACCESS_TIMING_PARAMETER = 0x83,
- kSID_SECURED_DATA_TRANSMISSION = 0x84,
- kSID_CONTROL_DTC_SETTING = 0x85,
- kSID_RESPONSE_ON_EVENT = 0x86,
-};
-
-// ========================================================================
-// Transports
-// ========================================================================
-
-/**
- * @brief
- *
- * @param hdl
- * @param info, if NULL, the default values are used:
- * A_Mtype: message type (diagnostic (DEFAULT), remote diagnostic, secure diagnostic, secure
- * remote diagnostic)
- * A_TA_Type: application target address type (physical (DEFAULT) or functional)
- * A_SA: unused
- * A_TA: unused
- * A_AE: unused
- * @return ssize_t
- */
-ssize_t UDSTpGetSendBuf(struct UDSTpHandle *hdl, uint8_t **buf) {
- assert(hdl);
- assert(hdl->get_send_buf);
- return hdl->get_send_buf(hdl, buf);
-}
-ssize_t UDSTpSend(struct UDSTpHandle *hdl, const uint8_t *buf, ssize_t len, UDSSDU_t *info) {
- assert(hdl);
- assert(hdl->send);
- return hdl->send(hdl, (uint8_t *)buf, len, info);
-}
-
-UDSTpStatus_t UDSTpPoll(struct UDSTpHandle *hdl) {
- assert(hdl);
- assert(hdl->poll);
- return hdl->poll(hdl);
-}
-
-ssize_t UDSTpPeek(struct UDSTpHandle *hdl, uint8_t **buf, UDSSDU_t *info) {
- assert(hdl);
- assert(hdl->peek);
- return hdl->peek(hdl, buf, info);
-}
-
-const uint8_t *UDSTpGetRecvBuf(struct UDSTpHandle *hdl, size_t *p_len) {
- assert(hdl);
- ssize_t len = 0;
- uint8_t *buf = NULL;
- len = UDSTpPeek(hdl, &buf, NULL);
- if (len > 0) {
- if (p_len) {
- *p_len = len;
- }
- return buf;
- } else {
- return NULL;
- }
-}
-
-size_t UDSTpGetRecvLen(UDSTpHandle_t *hdl) {
- assert(hdl);
- size_t len = 0;
- UDSTpGetRecvBuf(hdl, &len);
- return len;
-}
-
-void UDSTpAckRecv(UDSTpHandle_t *hdl) {
- assert(hdl);
- hdl->ack_recv(hdl);
-}
-
-// ========================================================================
-// Common
-// ========================================================================
-
-#if UDS_CUSTOM_MILLIS
-#else
-uint32_t UDSMillis(void) {
-#if UDS_ARCH == UDS_ARCH_UNIX
- struct timeval te;
- gettimeofday(&te, NULL);
- long long milliseconds = te.tv_sec * 1000LL + te.tv_usec / 1000;
- return milliseconds;
-#elif UDS_ARCH == UDS_ARCH_WINDOWS
- struct timespec ts;
- timespec_get(&ts, TIME_UTC);
- long long milliseconds = ts.tv_sec * 1000LL + ts.tv_nsec / 1000000;
- return milliseconds;
-#else
-#error "UDSMillis() undefined!"
-#endif
-}
-#endif
-
-static bool UDSSecurityAccessLevelIsReserved(uint8_t securityLevel) {
- securityLevel &= 0x3f;
- return (0 == securityLevel || (0x43 <= securityLevel && securityLevel >= 0x5E) ||
- 0x7F == securityLevel);
-}
-
-// ========================================================================
-// Server
-// ========================================================================
-
-static inline uint8_t NegativeResponse(UDSReq_t *r, uint8_t response_code) {
- r->send_buf[0] = 0x7F;
- r->send_buf[1] = r->recv_buf[0];
- r->send_buf[2] = response_code;
- r->send_len = UDS_NEG_RESP_LEN;
- return response_code;
-}
-
-static inline void NoResponse(UDSReq_t *r) { r->send_len = 0; }
-
-static uint8_t EmitEvent(UDSServer_t *srv, UDSServerEvent_t evt, void *data) {
- if (srv->fn) {
- return srv->fn(srv, evt, data);
- } else {
- UDS_DBG_PRINT("Unhandled UDSServerEvent %d, srv.fn not installed!\n", evt);
- return kGeneralReject;
- }
-}
-
-static uint8_t _0x10_DiagnosticSessionControl(UDSServer_t *srv, UDSReq_t *r) {
- if (r->recv_len < UDS_0X10_REQ_LEN) {
- return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
- }
-
- uint8_t sessType = r->recv_buf[1] & 0x4F;
-
- UDSDiagSessCtrlArgs_t args = {
- .type = sessType,
- .p2_ms = UDS_CLIENT_DEFAULT_P2_MS,
- .p2_star_ms = UDS_CLIENT_DEFAULT_P2_STAR_MS,
- };
-
- uint8_t err = EmitEvent(srv, UDS_SRV_EVT_DiagSessCtrl, &args);
-
- if (kPositiveResponse != err) {
- return NegativeResponse(r, err);
- }
-
- srv->sessionType = sessType;
-
- switch (sessType) {
- case kDefaultSession:
- break;
- case kProgrammingSession:
- case kExtendedDiagnostic:
- default:
- srv->s3_session_timeout_timer = UDSMillis() + srv->s3_ms;
- break;
- }
-
- r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_DIAGNOSTIC_SESSION_CONTROL);
- r->send_buf[1] = sessType;
-
- // UDS-1-2013: Table 29
- // resolution: 1ms
- r->send_buf[2] = args.p2_ms >> 8;
- r->send_buf[3] = args.p2_ms;
-
- // resolution: 10ms
- r->send_buf[4] = (args.p2_star_ms / 10) >> 8;
- r->send_buf[5] = args.p2_star_ms / 10;
-
- r->send_len = UDS_0X10_RESP_LEN;
- return kPositiveResponse;
-}
-
-static uint8_t _0x11_ECUReset(UDSServer_t *srv, UDSReq_t *r) {
- uint8_t resetType = r->recv_buf[1] & 0x3F;
-
- if (r->recv_len < UDS_0X11_REQ_MIN_LEN) {
- return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
- }
-
- UDSECUResetArgs_t args = {
- .type = resetType,
- .powerDownTimeMillis = UDS_SERVER_DEFAULT_POWER_DOWN_TIME_MS,
- };
-
- uint8_t err = EmitEvent(srv, UDS_SRV_EVT_EcuReset, &args);
-
- if (kPositiveResponse == err) {
- srv->notReadyToReceive = true;
- srv->ecuResetScheduled = resetType;
- srv->ecuResetTimer = UDSMillis() + args.powerDownTimeMillis;
- } else {
- return NegativeResponse(r, err);
- }
-
- r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_ECU_RESET);
- r->send_buf[1] = resetType;
-
- if (kEnableRapidPowerShutDown == resetType) {
- uint32_t powerDownTime = args.powerDownTimeMillis / 1000;
- if (powerDownTime > 255) {
- powerDownTime = 255;
- }
- r->send_buf[2] = powerDownTime;
- r->send_len = UDS_0X11_RESP_BASE_LEN + 1;
- } else {
- r->send_len = UDS_0X11_RESP_BASE_LEN;
- }
- return kPositiveResponse;
-}
-
-static uint8_t safe_copy(UDSServer_t *srv, const void *src, uint16_t count) {
- if (srv == NULL) {
- return kGeneralReject;
- }
- UDSReq_t *r = (UDSReq_t *)&srv->r;
- if (count <= r->send_buf_size - r->send_len) {
- memmove(r->send_buf + r->send_len, src, count);
- r->send_len += count;
- return kPositiveResponse;
- }
- return kResponseTooLong;
-}
-
-static uint8_t _0x22_ReadDataByIdentifier(UDSServer_t *srv, UDSReq_t *r) {
- uint8_t numDIDs;
- uint16_t dataId = 0;
- uint8_t ret = kPositiveResponse;
- r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_READ_DATA_BY_IDENTIFIER);
- r->send_len = 1;
-
- if (0 != (r->recv_len - 1) % sizeof(uint16_t)) {
- return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
- }
-
- numDIDs = r->recv_len / sizeof(uint16_t);
-
- if (0 == numDIDs) {
- return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
- }
-
- for (int did = 0; did < numDIDs; did++) {
- uint16_t idx = 1 + did * 2;
- dataId = (r->recv_buf[idx] << 8) + r->recv_buf[idx + 1];
-
- if (r->send_len + 3 > r->send_buf_size) {
- return NegativeResponse(r, kResponseTooLong);
- }
- uint8_t *copylocation = r->send_buf + r->send_len;
- copylocation[0] = dataId >> 8;
- copylocation[1] = dataId;
- r->send_len += 2;
-
- UDSRDBIArgs_t args = {
- .dataId = dataId,
- .copy = safe_copy,
- };
-
- ret = EmitEvent(srv, UDS_SRV_EVT_ReadDataByIdent, &args);
-
- if (kPositiveResponse != ret) {
- return NegativeResponse(r, ret);
- }
- }
- return kPositiveResponse;
-}
-
-/**
- * @brief decode the addressAndLengthFormatIdentifier that appears in ReadMemoryByAddress (0x23),
- * DynamicallyDefineDataIdentifier (0x2C), RequestDownload (0X34)
- *
- * @param srv
- * @param buf pointer to addressAndDataLengthFormatIdentifier in recv_buf
- * @param memoryAddress the decoded memory address
- * @param memorySize the decoded memory size
- * @return uint8_t
- */
-static uint8_t decodeAddressAndLength(UDSReq_t *r, uint8_t *const buf, void **memoryAddress,
- size_t *memorySize) {
- assert(r);
- assert(memoryAddress);
- assert(memorySize);
- long long unsigned int tmp = 0;
- *memoryAddress = 0;
- *memorySize = 0;
-
- assert(buf >= r->recv_buf && buf <= r->recv_buf + sizeof(r->recv_buf));
-
- if (r->recv_len < 3) {
- return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
- }
-
- uint8_t memorySizeLength = (buf[0] & 0xF0) >> 4;
- uint8_t memoryAddressLength = buf[0] & 0x0F;
-
- if (memorySizeLength == 0 || memorySizeLength > sizeof(size_t)) {
- return NegativeResponse(r, kRequestOutOfRange);
- }
-
- if (memoryAddressLength == 0 || memoryAddressLength > sizeof(size_t)) {
- return NegativeResponse(r, kRequestOutOfRange);
- }
-
- if (buf + memorySizeLength + memoryAddressLength > r->recv_buf + r->recv_len) {
- return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
- }
-
- for (int byteIdx = 0; byteIdx < memoryAddressLength; byteIdx++) {
- long long unsigned int byte = buf[1 + byteIdx];
- uint8_t shiftBytes = memoryAddressLength - 1 - byteIdx;
- tmp |= byte << (8 * shiftBytes);
- }
- *memoryAddress = (void *)tmp;
-
- for (int byteIdx = 0; byteIdx < memorySizeLength; byteIdx++) {
- uint8_t byte = buf[1 + memoryAddressLength + byteIdx];
- uint8_t shiftBytes = memorySizeLength - 1 - byteIdx;
- *memorySize |= (size_t)byte << (8 * shiftBytes);
- }
- return kPositiveResponse;
-}
-
-static uint8_t _0x23_ReadMemoryByAddress(UDSServer_t *srv, UDSReq_t *r) {
- uint8_t ret = kPositiveResponse;
- void *address = 0;
- size_t length = 0;
-
- if (r->recv_len < UDS_0X23_REQ_MIN_LEN) {
- return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
- }
-
- ret = decodeAddressAndLength(r, &r->recv_buf[1], &address, &length);
- if (kPositiveResponse != ret) {
- return NegativeResponse(r, ret);
- }
-
- UDSReadMemByAddrArgs_t args = {
- .memAddr = address,
- .memSize = length,
- .copy = safe_copy,
- };
-
- r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_READ_MEMORY_BY_ADDRESS);
- r->send_len = UDS_0X23_RESP_BASE_LEN;
- ret = EmitEvent(srv, UDS_SRV_EVT_ReadMemByAddr, &args);
- if (kPositiveResponse != ret) {
- return NegativeResponse(r, ret);
- }
- if (r->send_len != UDS_0X23_RESP_BASE_LEN + length) {
- return kGeneralProgrammingFailure;
- }
- return kPositiveResponse;
-}
-
-static uint8_t _0x27_SecurityAccess(UDSServer_t *srv, UDSReq_t *r) {
- uint8_t subFunction = r->recv_buf[1];
- uint8_t response = kPositiveResponse;
-
- if (UDSSecurityAccessLevelIsReserved(subFunction)) {
- return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
- }
-
- r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_SECURITY_ACCESS);
- r->send_buf[1] = subFunction;
- r->send_len = UDS_0X27_RESP_BASE_LEN;
-
- // Even: sendKey
- if (0 == subFunction % 2) {
- uint8_t requestedLevel = subFunction - 1;
- UDSSecAccessValidateKeyArgs_t args = {
- .level = requestedLevel,
- .key = &r->recv_buf[UDS_0X27_REQ_BASE_LEN],
- .len = r->recv_len - UDS_0X27_REQ_BASE_LEN,
- };
-
- response = EmitEvent(srv, UDS_SRV_EVT_SecAccessValidateKey, &args);
-
- if (kPositiveResponse != response) {
- return NegativeResponse(r, response);
- }
-
- // "requestSeed = 0x01" identifies a fixed relationship between
- // "requestSeed = 0x01" and "sendKey = 0x02"
- // "requestSeed = 0x03" identifies a fixed relationship between
- // "requestSeed = 0x03" and "sendKey = 0x04"
- srv->securityLevel = requestedLevel;
- r->send_len = UDS_0X27_RESP_BASE_LEN;
- return kPositiveResponse;
- }
-
- // Odd: requestSeed
- else {
- /* If a server supports security, but the requested security level is already unlocked when
- a SecurityAccess ‘requestSeed’ message is received, that server shall respond with a
- SecurityAccess ‘requestSeed’ positive response message service with a seed value equal to
- zero (0). The server shall never send an all zero seed for a given security level that is
- currently locked. The client shall use this method to determine if a server is locked for a
- particular security level by checking for a non-zero seed.
- */
- if (subFunction == srv->securityLevel) {
- // Table 52 sends a response of length 2. Use a preprocessor define if this needs
- // customizing by the user.
- const uint8_t already_unlocked[] = {0x00, 0x00};
- return safe_copy(srv, already_unlocked, sizeof(already_unlocked));
- } else {
- UDSSecAccessRequestSeedArgs_t args = {
- .level = subFunction,
- .dataRecord = &r->recv_buf[UDS_0X27_REQ_BASE_LEN],
- .len = r->recv_len - UDS_0X27_REQ_BASE_LEN,
- .copySeed = safe_copy,
- };
-
- response = EmitEvent(srv, UDS_SRV_EVT_SecAccessRequestSeed, &args);
-
- if (kPositiveResponse != response) {
- return NegativeResponse(r, response);
- }
-
- if (r->send_len <= UDS_0X27_RESP_BASE_LEN) { // no data was copied
- return NegativeResponse(r, kGeneralProgrammingFailure);
- }
- return kPositiveResponse;
- }
- }
- return NegativeResponse(r, kGeneralProgrammingFailure);
-}
-
-static uint8_t _0x28_CommunicationControl(UDSServer_t *srv, UDSReq_t *r) {
- uint8_t controlType = r->recv_buf[1] & 0x7F;
- uint8_t communicationType = r->recv_buf[2];
-
- if (r->recv_len < UDS_0X28_REQ_BASE_LEN) {
- return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
- }
-
- UDSCommCtrlArgs_t args = {
- .ctrlType = controlType,
- .commType = communicationType,
- };
-
- uint8_t err = EmitEvent(srv, UDS_SRV_EVT_CommCtrl, &args);
- if (kPositiveResponse != err) {
- return NegativeResponse(r, err);
- }
-
- r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_COMMUNICATION_CONTROL);
- r->send_buf[1] = controlType;
- r->send_len = UDS_0X28_RESP_LEN;
- return kPositiveResponse;
-}
-
-static uint8_t _0x2E_WriteDataByIdentifier(UDSServer_t *srv, UDSReq_t *r) {
- uint16_t dataLen = 0;
- uint16_t dataId = 0;
- uint8_t err = kPositiveResponse;
-
- /* UDS-1 2013 Figure 21 Key 1 */
- if (r->recv_len < UDS_0X2E_REQ_MIN_LEN) {
- return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
- }
-
- dataId = (r->recv_buf[1] << 8) + r->recv_buf[2];
- dataLen = r->recv_len - UDS_0X2E_REQ_BASE_LEN;
-
- UDSWDBIArgs_t args = {
- .dataId = dataId,
- .data = &r->recv_buf[UDS_0X2E_REQ_BASE_LEN],
- .len = dataLen,
- };
-
- err = EmitEvent(srv, UDS_SRV_EVT_WriteDataByIdent, &args);
- if (kPositiveResponse != err) {
- return NegativeResponse(r, err);
- }
-
- r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_WRITE_DATA_BY_IDENTIFIER);
- r->send_buf[1] = dataId >> 8;
- r->send_buf[2] = dataId;
- r->send_len = UDS_0X2E_RESP_LEN;
- return kPositiveResponse;
-}
-
-static uint8_t _0x31_RoutineControl(UDSServer_t *srv, UDSReq_t *r) {
- uint8_t err = kPositiveResponse;
- if (r->recv_len < UDS_0X31_REQ_MIN_LEN) {
- return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
- }
-
- uint8_t routineControlType = r->recv_buf[1] & 0x7F;
- uint16_t routineIdentifier = (r->recv_buf[2] << 8) + r->recv_buf[3];
-
- UDSRoutineCtrlArgs_t args = {
- .ctrlType = routineControlType,
- .id = routineIdentifier,
- .optionRecord = &r->recv_buf[UDS_0X31_REQ_MIN_LEN],
- .len = r->recv_len - UDS_0X31_REQ_MIN_LEN,
- .copyStatusRecord = safe_copy,
- };
-
- r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_ROUTINE_CONTROL);
- r->send_buf[1] = routineControlType;
- r->send_buf[2] = routineIdentifier >> 8;
- r->send_buf[3] = routineIdentifier;
- r->send_len = UDS_0X31_RESP_MIN_LEN;
-
- switch (routineControlType) {
- case kStartRoutine:
- case kStopRoutine:
- case kRequestRoutineResults:
- err = EmitEvent(srv, UDS_SRV_EVT_RoutineCtrl, &args);
- if (kPositiveResponse != err) {
- return NegativeResponse(r, err);
- }
- break;
- default:
- return NegativeResponse(r, kRequestOutOfRange);
- }
- return kPositiveResponse;
-}
-
-static void ResetTransfer(UDSServer_t *srv) {
- assert(srv);
- srv->xferBlockSequenceCounter = 1;
- srv->xferByteCounter = 0;
- srv->xferTotalBytes = 0;
- srv->xferIsActive = false;
-}
-
-static uint8_t _0x34_RequestDownload(UDSServer_t *srv, UDSReq_t *r) {
- uint8_t err;
- void *memoryAddress = 0;
- size_t memorySize = 0;
-
- if (srv->xferIsActive) {
- return NegativeResponse(r, kConditionsNotCorrect);
- }
-
- if (r->recv_len < UDS_0X34_REQ_BASE_LEN) {
- return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
- }
-
- err = decodeAddressAndLength(r, &r->recv_buf[2], &memoryAddress, &memorySize);
- if (kPositiveResponse != err) {
- return NegativeResponse(r, err);
- }
-
- UDSRequestDownloadArgs_t args = {
- .addr = memoryAddress,
- .size = memorySize,
- .dataFormatIdentifier = r->recv_buf[1],
- .maxNumberOfBlockLength = UDS_SERVER_DEFAULT_XFER_DATA_MAX_BLOCKLENGTH,
- };
-
- err = EmitEvent(srv, UDS_SRV_EVT_RequestDownload, &args);
-
- if (args.maxNumberOfBlockLength < 3) {
- UDS_DBG_PRINT("ERROR: maxNumberOfBlockLength too short");
- return NegativeResponse(r, kGeneralProgrammingFailure);
- }
-
- if (kPositiveResponse != err) {
- return NegativeResponse(r, err);
- }
-
- ResetTransfer(srv);
- srv->xferIsActive = true;
- srv->xferTotalBytes = memorySize;
- srv->xferBlockLength = args.maxNumberOfBlockLength;
-
- // ISO-14229-1:2013 Table 401:
- uint8_t lengthFormatIdentifier = sizeof(args.maxNumberOfBlockLength) << 4;
-
- /* ISO-14229-1:2013 Table 396: maxNumberOfBlockLength
- This parameter is used by the requestDownload positive response message to
- inform the client how many data bytes (maxNumberOfBlockLength) to include in
- each TransferData request message from the client. This length reflects the
- complete message length, including the service identifier and the
- data-parameters present in the TransferData request message.
- */
- if (args.maxNumberOfBlockLength > UDS_TP_MTU) {
- args.maxNumberOfBlockLength = UDS_TP_MTU;
- }
-
- r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_REQUEST_DOWNLOAD);
- r->send_buf[1] = lengthFormatIdentifier;
- for (uint8_t idx = 0; idx < sizeof(args.maxNumberOfBlockLength); idx++) {
- uint8_t shiftBytes = sizeof(args.maxNumberOfBlockLength) - 1 - idx;
- uint8_t byte = args.maxNumberOfBlockLength >> (shiftBytes * 8);
- r->send_buf[UDS_0X34_RESP_BASE_LEN + idx] = byte;
- }
- r->send_len = UDS_0X34_RESP_BASE_LEN + sizeof(args.maxNumberOfBlockLength);
- return kPositiveResponse;
-}
-
-static uint8_t _0x35_RequestUpload(UDSServer_t *srv, UDSReq_t *r) {
- uint8_t err;
- void *memoryAddress = 0;
- size_t memorySize = 0;
-
- if (srv->xferIsActive) {
- return NegativeResponse(r, kConditionsNotCorrect);
- }
-
- if (r->recv_len < UDS_0X35_REQ_BASE_LEN) {
- return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
- }
-
- err = decodeAddressAndLength(r, &r->recv_buf[2], &memoryAddress, &memorySize);
- if (kPositiveResponse != err) {
- return NegativeResponse(r, err);
- }
-
- UDSRequestUploadArgs_t args = {
- .addr = memoryAddress,
- .size = memorySize,
- .dataFormatIdentifier = r->recv_buf[1],
- .maxNumberOfBlockLength = UDS_SERVER_DEFAULT_XFER_DATA_MAX_BLOCKLENGTH,
- };
-
- err = EmitEvent(srv, UDS_SRV_EVT_RequestUpload, &args);
-
- if (args.maxNumberOfBlockLength < 3) {
- UDS_DBG_PRINT("ERROR: maxNumberOfBlockLength too short");
- return NegativeResponse(r, kGeneralProgrammingFailure);
- }
-
- if (kPositiveResponse != err) {
- return NegativeResponse(r, err);
- }
-
- ResetTransfer(srv);
- srv->xferIsActive = true;
- srv->xferTotalBytes = memorySize;
- srv->xferBlockLength = args.maxNumberOfBlockLength;
-
- uint8_t lengthFormatIdentifier = sizeof(args.maxNumberOfBlockLength) << 4;
-
- r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_REQUEST_UPLOAD);
- r->send_buf[1] = lengthFormatIdentifier;
- for (uint8_t idx = 0; idx < sizeof(args.maxNumberOfBlockLength); idx++) {
- uint8_t shiftBytes = sizeof(args.maxNumberOfBlockLength) - 1 - idx;
- uint8_t byte = args.maxNumberOfBlockLength >> (shiftBytes * 8);
- r->send_buf[UDS_0X35_RESP_BASE_LEN + idx] = byte;
- }
- r->send_len = UDS_0X35_RESP_BASE_LEN + sizeof(args.maxNumberOfBlockLength);
- return kPositiveResponse;
-}
-
-static uint8_t _0x36_TransferData(UDSServer_t *srv, UDSReq_t *r) {
- uint8_t err = kPositiveResponse;
- uint16_t request_data_len = r->recv_len - UDS_0X36_REQ_BASE_LEN;
- uint8_t blockSequenceCounter = 0;
-
- if (!srv->xferIsActive) {
- return NegativeResponse(r, kUploadDownloadNotAccepted);
- }
-
- if (r->recv_len < UDS_0X36_REQ_BASE_LEN) {
- err = kIncorrectMessageLengthOrInvalidFormat;
- goto fail;
- }
-
- blockSequenceCounter = r->recv_buf[1];
-
- if (!srv->RCRRP) {
- if (blockSequenceCounter != srv->xferBlockSequenceCounter) {
- err = kRequestSequenceError;
- goto fail;
- } else {
- srv->xferBlockSequenceCounter++;
- }
- }
-
- if (srv->xferByteCounter + request_data_len > srv->xferTotalBytes) {
- err = kTransferDataSuspended;
- goto fail;
- }
-
- {
- UDSTransferDataArgs_t args = {
- .data = &r->recv_buf[UDS_0X36_REQ_BASE_LEN],
- .len = r->recv_len - UDS_0X36_REQ_BASE_LEN,
- .maxRespLen = srv->xferBlockLength - UDS_0X36_RESP_BASE_LEN,
- .copyResponse = safe_copy,
- };
-
- r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_TRANSFER_DATA);
- r->send_buf[1] = blockSequenceCounter;
- r->send_len = UDS_0X36_RESP_BASE_LEN;
-
- err = EmitEvent(srv, UDS_SRV_EVT_TransferData, &args);
-
- switch (err) {
- case kPositiveResponse:
- srv->xferByteCounter += request_data_len;
- return kPositiveResponse;
- case kRequestCorrectlyReceived_ResponsePending:
- return NegativeResponse(r, kRequestCorrectlyReceived_ResponsePending);
- default:
- goto fail;
- }
- }
-
-fail:
- ResetTransfer(srv);
- return NegativeResponse(r, err);
-}
-
-static uint8_t _0x37_RequestTransferExit(UDSServer_t *srv, UDSReq_t *r) {
- uint8_t err = kPositiveResponse;
-
- if (!srv->xferIsActive) {
- return NegativeResponse(r, kUploadDownloadNotAccepted);
- }
-
- r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_REQUEST_TRANSFER_EXIT);
- r->send_len = UDS_0X37_RESP_BASE_LEN;
-
- UDSRequestTransferExitArgs_t args = {
- .data = &r->recv_buf[UDS_0X37_REQ_BASE_LEN],
- .len = r->recv_len - UDS_0X37_REQ_BASE_LEN,
- .copyResponse = safe_copy,
- };
-
- err = EmitEvent(srv, UDS_SRV_EVT_RequestTransferExit, &args);
-
- switch (err) {
- case kPositiveResponse:
- ResetTransfer(srv);
- return kPositiveResponse;
- case kRequestCorrectlyReceived_ResponsePending:
- return NegativeResponse(r, kRequestCorrectlyReceived_ResponsePending);
- default:
- ResetTransfer(srv);
- return NegativeResponse(r, err);
- }
-}
-
-static uint8_t _0x3E_TesterPresent(UDSServer_t *srv, UDSReq_t *r) {
- if ((r->recv_len < UDS_0X3E_REQ_MIN_LEN) || (r->recv_len > UDS_0X3E_REQ_MAX_LEN)) {
- return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
- }
- uint8_t zeroSubFunction = r->recv_buf[1];
-
- switch (zeroSubFunction) {
- case 0x00:
- case 0x80:
- srv->s3_session_timeout_timer = UDSMillis() + srv->s3_ms;
- r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_TESTER_PRESENT);
- r->send_buf[1] = 0x00;
- r->send_len = UDS_0X3E_RESP_LEN;
- return kPositiveResponse;
- default:
- return NegativeResponse(r, kSubFunctionNotSupported);
- }
-}
-
-static uint8_t _0x85_ControlDTCSetting(UDSServer_t *srv, UDSReq_t *r) {
- if (r->recv_len < UDS_0X85_REQ_BASE_LEN) {
- return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
- }
- uint8_t dtcSettingType = r->recv_buf[1] & 0x3F;
-
- r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_CONTROL_DTC_SETTING);
- r->send_buf[1] = dtcSettingType;
- r->send_len = UDS_0X85_RESP_LEN;
- return kPositiveResponse;
-}
-
-typedef uint8_t (*UDSService)(UDSServer_t *srv, UDSReq_t *r);
-
-/**
- * @brief Get the internal service handler matching the given SID.
- * @param sid
- * @return pointer to UDSService or NULL if no match
- */
-static UDSService getServiceForSID(uint8_t sid) {
- switch (sid) {
- case kSID_DIAGNOSTIC_SESSION_CONTROL:
- return _0x10_DiagnosticSessionControl;
- case kSID_ECU_RESET:
- return _0x11_ECUReset;
- case kSID_CLEAR_DIAGNOSTIC_INFORMATION:
- return NULL;
- case kSID_READ_DTC_INFORMATION:
- return NULL;
- case kSID_READ_DATA_BY_IDENTIFIER:
- return _0x22_ReadDataByIdentifier;
- case kSID_READ_MEMORY_BY_ADDRESS:
- return _0x23_ReadMemoryByAddress;
- case kSID_READ_SCALING_DATA_BY_IDENTIFIER:
- return NULL;
- case kSID_SECURITY_ACCESS:
- return _0x27_SecurityAccess;
- case kSID_COMMUNICATION_CONTROL:
- return _0x28_CommunicationControl;
- case kSID_READ_PERIODIC_DATA_BY_IDENTIFIER:
- return NULL;
- case kSID_DYNAMICALLY_DEFINE_DATA_IDENTIFIER:
- return NULL;
- case kSID_WRITE_DATA_BY_IDENTIFIER:
- return _0x2E_WriteDataByIdentifier;
- case kSID_INPUT_CONTROL_BY_IDENTIFIER:
- return NULL;
- case kSID_ROUTINE_CONTROL:
- return _0x31_RoutineControl;
- case kSID_REQUEST_DOWNLOAD:
- return _0x34_RequestDownload;
- case kSID_REQUEST_UPLOAD:
- return _0x35_RequestUpload;
- case kSID_TRANSFER_DATA:
- return _0x36_TransferData;
- case kSID_REQUEST_TRANSFER_EXIT:
- return _0x37_RequestTransferExit;
- case kSID_REQUEST_FILE_TRANSFER:
- return NULL;
- case kSID_WRITE_MEMORY_BY_ADDRESS:
- return NULL;
- case kSID_TESTER_PRESENT:
- return _0x3E_TesterPresent;
- case kSID_ACCESS_TIMING_PARAMETER:
- return NULL;
- case kSID_SECURED_DATA_TRANSMISSION:
- return NULL;
- case kSID_CONTROL_DTC_SETTING:
- return _0x85_ControlDTCSetting;
- case kSID_RESPONSE_ON_EVENT:
- return NULL;
- default:
- UDS_DBG_PRINT("no handler for request SID %x.\n", sid);
- return NULL;
- }
-}
-
-/**
- * @brief Call the service if it exists, modifying the response if the spec calls for it.
- * @note see UDS-1 2013 7.5.5 Pseudo code example of server response behavior
- *
- * @param srv
- * @param addressingScheme
- */
-static uint8_t evaluateServiceResponse(UDSServer_t *srv, UDSReq_t *r) {
- uint8_t response = kPositiveResponse;
- bool suppressResponse = false;
- uint8_t sid = r->recv_buf[0];
- UDSService service = getServiceForSID(sid);
-
- if (NULL == service || NULL == srv->fn) {
- return NegativeResponse(r, kServiceNotSupported);
- }
- assert(service);
- assert(srv->fn); // service handler functions will call srv->fn. it must be valid
-
- switch (sid) {
- /* CASE Service_with_sub-function */
- /* test if service with sub-function is supported */
- case kSID_DIAGNOSTIC_SESSION_CONTROL:
- case kSID_ECU_RESET:
- case kSID_SECURITY_ACCESS:
- case kSID_COMMUNICATION_CONTROL:
- case kSID_ROUTINE_CONTROL:
- case kSID_TESTER_PRESENT:
- case kSID_CONTROL_DTC_SETTING: {
- response = service(srv, r);
-
- bool suppressPosRspMsgIndicationBit = r->recv_buf[1] & 0x80;
-
- /* test if positive response is required and if responseCode is positive 0x00 */
- if ((suppressPosRspMsgIndicationBit) && (response == kPositiveResponse) &&
- (
- // TODO: *not yet a NRC 0x78 response sent*
- true)) {
- suppressResponse = true;
- } else {
- suppressResponse = false;
- }
- break;
- }
-
- /* CASE Service_without_sub-function */
- /* test if service without sub-function is supported */
- case kSID_READ_DATA_BY_IDENTIFIER:
- case kSID_READ_MEMORY_BY_ADDRESS:
- case kSID_WRITE_DATA_BY_IDENTIFIER:
- case kSID_REQUEST_DOWNLOAD:
- case kSID_REQUEST_UPLOAD:
- case kSID_TRANSFER_DATA:
- case kSID_REQUEST_TRANSFER_EXIT: {
- response = service(srv, r);
- break;
- }
-
- /* CASE Service_not_implemented */
- /* shouldn't get this far as getServiceForSID(sid) will return NULL*/
- case kSID_CLEAR_DIAGNOSTIC_INFORMATION:
- case kSID_READ_DTC_INFORMATION:
- case kSID_READ_SCALING_DATA_BY_IDENTIFIER:
- case kSID_READ_PERIODIC_DATA_BY_IDENTIFIER:
- case kSID_DYNAMICALLY_DEFINE_DATA_IDENTIFIER:
- case kSID_INPUT_CONTROL_BY_IDENTIFIER:
- case kSID_REQUEST_FILE_TRANSFER:
- case kSID_WRITE_MEMORY_BY_ADDRESS:
- case kSID_ACCESS_TIMING_PARAMETER:
- case kSID_SECURED_DATA_TRANSMISSION:
- case kSID_RESPONSE_ON_EVENT:
- default: {
- response = kServiceNotSupported;
- break;
- }
- }
-
- if ((UDS_A_TA_TYPE_FUNCTIONAL == r->info.A_TA_Type) &&
- ((kServiceNotSupported == response) || (kSubFunctionNotSupported == response) ||
- (kServiceNotSupportedInActiveSession == response) ||
- (kSubFunctionNotSupportedInActiveSession == response) ||
- (kRequestOutOfRange == response)) &&
- (
- // TODO: *not yet a NRC 0x78 response sent*
- true)) {
- suppressResponse = true; /* Suppress negative response message */
- NoResponse(r);
- } else {
- if (suppressResponse) { /* Suppress positive response message */
- NoResponse(r);
- } else { /* send negative or positive response */
- ;
- }
- }
- return response;
-}
-
-// ========================================================================
-// Public Functions
-// ========================================================================
-
-/**
- * @brief \~chinese 初始化服务器 \~english Initialize the server
- *
- * @param srv
- * @param cfg
- * @return int
- */
-UDSErr_t UDSServerInit(UDSServer_t *srv) {
- assert(srv);
- memset(srv, 0, sizeof(UDSServer_t));
- srv->p2_ms = UDS_SERVER_DEFAULT_P2_MS;
- srv->p2_star_ms = UDS_SERVER_DEFAULT_P2_STAR_MS;
- srv->s3_ms = UDS_SERVER_DEFAULT_S3_MS;
- srv->sessionType = kDefaultSession;
- srv->p2_timer = UDSMillis() + srv->p2_ms;
- srv->s3_session_timeout_timer = UDSMillis() + srv->s3_ms;
- return UDS_OK;
-}
-
-void UDSServerPoll(UDSServer_t *srv) {
- // UDS-1-2013 Figure 38: Session Timeout (S3)
- if (kDefaultSession != srv->sessionType &&
- UDSTimeAfter(UDSMillis(), srv->s3_session_timeout_timer)) {
- EmitEvent(srv, UDS_SRV_EVT_SessionTimeout, NULL);
- }
-
- if (srv->ecuResetScheduled && UDSTimeAfter(UDSMillis(), srv->ecuResetTimer)) {
- EmitEvent(srv, UDS_SRV_EVT_DoScheduledReset, &srv->ecuResetScheduled);
- }
-
- UDSTpStatus_t tpStatus = UDSTpPoll(srv->tp);
-
- UDSReq_t *r = &srv->r;
-
- if (srv->requestInProgress) {
- if (srv->RCRRP) {
- // responds only if
- // 1. changed (no longer RCRRP), or
- // 2. p2_timer has elapsed
- uint8_t response = evaluateServiceResponse(srv, r);
- if (kRequestCorrectlyReceived_ResponsePending == response) {
- // it's the second time the service has responded with RCRRP
- srv->notReadyToReceive = true;
- } else {
- // No longer RCRRP'ing
- srv->RCRRP = false;
- srv->notReadyToReceive = false;
-
- // Not a consecutive 0x78 response, use p2 instead of p2_star * 0.3
- srv->p2_timer = UDSMillis() + srv->p2_ms;
- }
- }
-
- if (UDSTimeAfter(UDSMillis(), srv->p2_timer)) {
- printf("len: %ld\n", r->send_len);
- ssize_t ret = UDSTpSend(srv->tp, r->send_buf, r->send_len, NULL);
- // TODO test injection of transport errors:
- if (ret < 0) {
- UDSErr_t err = UDS_ERR_TPORT;
- EmitEvent(srv, UDS_SRV_EVT_Err, &err);
- UDS_DBG_PRINT("UDSTpSend failed with %ld\n", ret);
- }
-
- if (srv->RCRRP) {
- // ISO14229-2:2013 Table 4 footnote b
- // min time between consecutive 0x78 responses is 0.3 * p2*
- uint32_t wait_time = srv->p2_star_ms * 3 / 10;
- srv->p2_timer = UDSMillis() + wait_time;
- } else {
- srv->p2_timer = UDSMillis() + srv->p2_ms;
- UDSTpAckRecv(srv->tp);
- srv->requestInProgress = false;
- }
- }
-
- } else {
- if (srv->notReadyToReceive) {
- return; // cannot respond to request right now
- }
- r->recv_len = UDSTpPeek(srv->tp, &r->recv_buf, &r->info);
- r->send_buf_size = UDSTpGetSendBuf(srv->tp, &r->send_buf);
- if (r->send_buf == NULL || r->recv_buf == NULL) {
- UDSErr_t err = UDS_ERR_TPORT;
- EmitEvent(srv, UDS_SRV_EVT_Err, &err);
- UDS_DBG_PRINT("bad tport\n");
- return;
- }
- if (r->recv_len > 0) {
- uint8_t response = evaluateServiceResponse(srv, r);
- srv->requestInProgress = true;
- if (kRequestCorrectlyReceived_ResponsePending == response) {
- srv->RCRRP = true;
- }
- }
- }
-}
-
-// ========================================================================
-// Client
-// ========================================================================
-
-static void clearRequestContext(UDSClient_t *client) {
- assert(client);
- client->recv_size = 0;
- client->send_size = 0;
- client->state = kRequestStateIdle;
- client->err = UDS_OK;
-}
-
-UDSErr_t UDSClientInit(UDSClient_t *client) {
- assert(client);
- memset(client, 0, sizeof(*client));
-
- client->p2_ms = UDS_CLIENT_DEFAULT_P2_MS;
- client->p2_star_ms = UDS_CLIENT_DEFAULT_P2_STAR_MS;
-
- if (client->p2_star_ms < client->p2_ms) {
- fprintf(stderr, "p2_star_ms must be >= p2_ms\n");
- client->p2_star_ms = client->p2_ms;
- }
-
- clearRequestContext(client);
- return UDS_OK;
-}
-
-static const char *ClientStateName(enum UDSClientRequestState state) {
- switch (state) {
- case kRequestStateIdle:
- return "Idle";
- case kRequestStateSending:
- return "Sending";
- case kRequestStateAwaitSendComplete:
- return "AwaitSendComplete";
- case kRequestStateAwaitResponse:
- return "AwaitResponse";
- case kRequestStateProcessResponse:
- return "ProcessResponse";
- default:
- return "Unknown";
- }
-}
-
-static void changeState(UDSClient_t *client, enum UDSClientRequestState state) {
- printf("client state: %s (%d) -> %s (%d)\n", ClientStateName(client->state), client->state,
- ClientStateName(state), state);
- client->state = state;
-}
-
-/**
- * @brief Check that the response is a valid UDS response
- *
- * @param ctx
- * @return UDSErr_t
- */
-static UDSErr_t _ClientValidateResponse(const UDSClient_t *client) {
-
- if (client->recv_size < 1) {
- return UDS_ERR_RESP_TOO_SHORT;
- }
-
- if (0x7F == client->recv_buf[0]) { // 否定响应
- if (client->recv_size < 2) {
- return UDS_ERR_RESP_TOO_SHORT;
- } else if (client->send_buf[0] != client->recv_buf[1]) {
- return UDS_ERR_SID_MISMATCH;
- } else if (kRequestCorrectlyReceived_ResponsePending == client->recv_buf[2]) {
- return UDS_OK;
- } else if (client->_options_copy & UDS_NEG_RESP_IS_ERR) {
- return UDS_ERR_NEG_RESP;
- } else {
- ;
- }
- } else { // 肯定响应
- if (UDS_RESPONSE_SID_OF(client->send_buf[0]) != client->recv_buf[0]) {
- return UDS_ERR_SID_MISMATCH;
- }
- switch (client->send_buf[0]) {
- case kSID_ECU_RESET:
- if (client->recv_size < 2) {
- return UDS_ERR_RESP_TOO_SHORT;
- } else if (client->send_buf[1] != client->recv_buf[1]) {
- return UDS_ERR_SUBFUNCTION_MISMATCH;
- } else {
- ;
- }
- break;
- }
- }
-
- return UDS_OK;
-}
-
-/**
- * @brief Handle validated server response
- * @param client
- */
-static inline void _ClientHandleResponse(UDSClient_t *client) {
- if (0x7F == client->recv_buf[0]) {
- if (kRequestCorrectlyReceived_ResponsePending == client->recv_buf[2]) {
- UDS_DBG_PRINT("got RCRRP, setting p2 timer\n");
- client->p2_timer = UDSMillis() + client->p2_star_ms;
- memset(client->recv_buf, 0, client->recv_buf_size);
- client->recv_size = 0;
- UDSTpAckRecv(client->tp);
- changeState(client, kRequestStateAwaitResponse);
- return;
- } else {
- ;
- }
- } else {
- uint8_t respSid = client->recv_buf[0];
- switch (UDS_REQUEST_SID_OF(respSid)) {
- case kSID_DIAGNOSTIC_SESSION_CONTROL: {
- if (client->recv_size < UDS_0X10_RESP_LEN) {
- UDS_DBG_PRINT("Error: SID %x response too short\n",
- kSID_DIAGNOSTIC_SESSION_CONTROL);
- client->err = UDS_ERR_RESP_TOO_SHORT;
- UDSTpAckRecv(client->tp);
- changeState(client, kRequestStateIdle);
- return;
- }
-
- if (client->_options_copy & UDS_IGNORE_SRV_TIMINGS) {
- UDSTpAckRecv(client->tp);
- changeState(client, kRequestStateIdle);
- return;
- }
-
- uint16_t p2 = (client->recv_buf[2] << 8) + client->recv_buf[3];
- uint32_t p2_star = ((client->recv_buf[4] << 8) + client->recv_buf[5]) * 10;
- UDS_DBG_PRINT("received new timings: p2: %u, p2*: %u\n", p2, p2_star);
- client->p2_ms = p2;
- client->p2_star_ms = p2_star;
- break;
- }
- default:
- break;
- }
- }
- UDSTpAckRecv(client->tp);
- changeState(client, kRequestStateIdle);
-}
-
-/**
- * @brief execute the client request state machine
- * @param client
- */
-static void PollLowLevel(UDSClient_t *client) {
- assert(client);
- UDSTpStatus_t tp_status = client->tp->poll(client->tp);
- switch (client->state) {
- case kRequestStateIdle: {
- client->options = client->defaultOptions;
- break;
- }
- case kRequestStateSending: {
- UDSTpAddr_t ta_type = client->_options_copy & UDS_FUNCTIONAL ? UDS_A_TA_TYPE_FUNCTIONAL
- : UDS_A_TA_TYPE_PHYSICAL;
- UDSSDU_t info = {
- .A_Mtype = UDS_A_MTYPE_DIAG,
- .A_TA_Type = ta_type,
- };
- ssize_t ret = UDSTpSend(client->tp, client->send_buf, client->send_size, &info);
- if (ret < 0) {
- client->err = UDS_ERR_TPORT;
- UDS_DBG_PRINT("tport err: %ld\n", ret);
- } else if (0 == ret) {
- UDS_DBG_PRINT("send in progress...\n");
- ; // 等待发送成功
- } else if (client->send_size == ret) {
- changeState(client, kRequestStateAwaitSendComplete);
- } else {
- client->err = UDS_ERR_BUFSIZ;
- }
- break;
- }
- case kRequestStateAwaitSendComplete: {
- if (client->_options_copy & UDS_FUNCTIONAL) {
- // "The Functional addressing is applied only to single frame transmission"
- // Specification of Diagnostic Communication (Diagnostic on CAN - Network Layer)
- changeState(client, kRequestStateIdle);
- }
- if (tp_status & UDS_TP_SEND_IN_PROGRESS) {
- ; // await send complete
- } else {
- if (client->_options_copy & UDS_SUPPRESS_POS_RESP) {
- changeState(client, kRequestStateIdle);
- } else {
- changeState(client, kRequestStateAwaitResponse);
- client->p2_timer = UDSMillis() + client->p2_ms;
- }
- }
- break;
- }
- case kRequestStateAwaitResponse: {
- UDSSDU_t info = {0};
- ssize_t len = UDSTpPeek(client->tp, &client->recv_buf, &info);
-
- if (UDS_A_TA_TYPE_FUNCTIONAL == info.A_TA_Type) {
- UDSTpAckRecv(client->tp);
- break;
- }
- if (len < 0) {
- client->err = UDS_ERR_TPORT;
- changeState(client, kRequestStateIdle);
- } else if (0 == len) {
- if (UDSTimeAfter(UDSMillis(), client->p2_timer)) {
- client->err = UDS_ERR_TIMEOUT;
- changeState(client, kRequestStateIdle);
- }
- } else {
- printf("received %ld bytes\n", len);
- client->recv_size = len;
- changeState(client, kRequestStateProcessResponse);
- }
- break;
- }
- case kRequestStateProcessResponse: {
- client->err = _ClientValidateResponse(client);
- if (UDS_OK == client->err) {
- _ClientHandleResponse(client);
- } else {
- UDSTpAckRecv(client->tp);
- changeState(client, kRequestStateIdle);
- }
- break;
- }
-
- default:
- assert(0);
- }
-}
-
-static UDSErr_t _SendRequest(UDSClient_t *client) {
- client->_options_copy = client->options;
-
- if (client->_options_copy & UDS_SUPPRESS_POS_RESP) {
- // UDS-1:2013 8.2.2 Table 11
- client->send_buf[1] |= 0x80;
- }
-
- changeState(client, kRequestStateSending);
- PollLowLevel(client); // poll once to begin sending immediately
- return UDS_OK;
-}
-
-static UDSErr_t PreRequestCheck(UDSClient_t *client) {
- if (kRequestStateIdle != client->state) {
- return UDS_ERR_BUSY;
- }
- clearRequestContext(client);
- if (client->tp == NULL) {
- return UDS_ERR_TPORT;
- }
- ssize_t ret = UDSTpGetSendBuf(client->tp, &client->send_buf);
- if (ret < 0) {
- return UDS_ERR_TPORT;
- }
- client->send_buf_size = ret;
- return UDS_OK;
-}
-
-UDSErr_t UDSSendBytes(UDSClient_t *client, const uint8_t *data, uint16_t size) {
- UDSErr_t err = PreRequestCheck(client);
- if (err) {
- return err;
- }
- if (size > client->send_buf_size) {
- return UDS_ERR_BUFSIZ;
- }
- memmove(client->send_buf, data, size);
- client->send_size = size;
- return _SendRequest(client);
-}
-
-UDSErr_t UDSSendECUReset(UDSClient_t *client, UDSECUReset_t type) {
- UDSErr_t err = PreRequestCheck(client);
- if (err) {
- return err;
- }
- client->send_buf[0] = kSID_ECU_RESET;
- client->send_buf[1] = type;
- client->send_size = 2;
- return _SendRequest(client);
-}
-
-UDSErr_t UDSSendDiagSessCtrl(UDSClient_t *client, enum UDSDiagnosticSessionType mode) {
- UDSErr_t err = PreRequestCheck(client);
- if (err) {
- return err;
- }
- client->send_buf[0] = kSID_DIAGNOSTIC_SESSION_CONTROL;
- client->send_buf[1] = mode;
- client->send_size = 2;
- return _SendRequest(client);
-}
-
-UDSErr_t UDSSendCommCtrl(UDSClient_t *client, enum UDSCommunicationControlType ctrl,
- enum UDSCommunicationType comm) {
- UDSErr_t err = PreRequestCheck(client);
- if (err) {
- return err;
- }
- client->send_buf[0] = kSID_COMMUNICATION_CONTROL;
- client->send_buf[1] = ctrl;
- client->send_buf[2] = comm;
- client->send_size = 3;
- return _SendRequest(client);
-}
-
-UDSErr_t UDSSendTesterPresent(UDSClient_t *client) {
- UDSErr_t err = PreRequestCheck(client);
- if (err) {
- return err;
- }
- client->send_buf[0] = kSID_TESTER_PRESENT;
- client->send_buf[1] = 0;
- client->send_size = 2;
- return _SendRequest(client);
-}
-
-UDSErr_t UDSSendRDBI(UDSClient_t *client, const uint16_t *didList,
- const uint16_t numDataIdentifiers) {
- UDSErr_t err = PreRequestCheck(client);
- if (err) {
- return err;
- }
- assert(didList);
- assert(numDataIdentifiers);
- client->send_buf[0] = kSID_READ_DATA_BY_IDENTIFIER;
- for (int i = 0; i < numDataIdentifiers; i++) {
- uint16_t offset = 1 + sizeof(uint16_t) * i;
- if (offset + 2 > client->send_buf_size) {
- return UDS_ERR_INVALID_ARG;
- }
- (client->send_buf + offset)[0] = (didList[i] & 0xFF00) >> 8;
- (client->send_buf + offset)[1] = (didList[i] & 0xFF);
- }
- client->send_size = 1 + (numDataIdentifiers * sizeof(uint16_t));
- return _SendRequest(client);
-}
-
-UDSErr_t UDSSendWDBI(UDSClient_t *client, uint16_t dataIdentifier, const uint8_t *data,
- uint16_t size) {
- UDSErr_t err = PreRequestCheck(client);
- if (err) {
- return err;
- }
- assert(data);
- assert(size);
- client->send_buf[0] = kSID_WRITE_DATA_BY_IDENTIFIER;
- if (client->send_buf_size <= 3 || size > client->send_buf_size - 3) {
- return UDS_ERR_BUFSIZ;
- }
- client->send_buf[1] = (dataIdentifier & 0xFF00) >> 8;
- client->send_buf[2] = (dataIdentifier & 0xFF);
- memmove(&client->send_buf[3], data, size);
- client->send_size = 3 + size;
- return _SendRequest(client);
-}
-
-/**
- * @brief RoutineControl
- *
- * @param client
- * @param type
- * @param routineIdentifier
- * @param data
- * @param size
- * @return UDSErr_t
- * @addtogroup routineControl_0x31
- */
-UDSErr_t UDSSendRoutineCtrl(UDSClient_t *client, enum RoutineControlType type,
- uint16_t routineIdentifier, const uint8_t *data, uint16_t size) {
- UDSErr_t err = PreRequestCheck(client);
- if (err) {
- return err;
- }
- client->send_buf[0] = kSID_ROUTINE_CONTROL;
- client->send_buf[1] = type;
- client->send_buf[2] = routineIdentifier >> 8;
- client->send_buf[3] = routineIdentifier;
- if (size) {
- assert(data);
- if (size > client->send_buf_size - UDS_0X31_REQ_MIN_LEN) {
- return UDS_ERR_BUFSIZ;
- }
- memmove(&client->send_buf[UDS_0X31_REQ_MIN_LEN], data, size);
- } else {
- assert(NULL == data);
- }
- client->send_size = UDS_0X31_REQ_MIN_LEN + size;
- return _SendRequest(client);
-}
-
-/**
- * @brief
- *
- * @param client
- * @param dataFormatIdentifier
- * @param addressAndLengthFormatIdentifier
- * @param memoryAddress
- * @param memorySize
- * @return UDSErr_t
- * @addtogroup requestDownload_0x34
- */
-UDSErr_t UDSSendRequestDownload(UDSClient_t *client, uint8_t dataFormatIdentifier,
- uint8_t addressAndLengthFormatIdentifier, size_t memoryAddress,
- size_t memorySize) {
- UDSErr_t err = PreRequestCheck(client);
- if (err) {
- return err;
- }
- uint8_t numMemorySizeBytes = (addressAndLengthFormatIdentifier & 0xF0) >> 4;
- uint8_t numMemoryAddressBytes = addressAndLengthFormatIdentifier & 0x0F;
-
- client->send_buf[0] = kSID_REQUEST_DOWNLOAD;
- client->send_buf[1] = dataFormatIdentifier;
- client->send_buf[2] = addressAndLengthFormatIdentifier;
-
- uint8_t *ptr = &client->send_buf[UDS_0X34_REQ_BASE_LEN];
-
- for (int i = numMemoryAddressBytes - 1; i >= 0; i--) {
- *ptr = (memoryAddress & (0xFF << (8 * i))) >> (8 * i);
- ptr++;
- }
-
- for (int i = numMemorySizeBytes - 1; i >= 0; i--) {
- *ptr = (memorySize & (0xFF << (8 * i))) >> (8 * i);
- ptr++;
- }
-
- client->send_size = UDS_0X34_REQ_BASE_LEN + numMemoryAddressBytes + numMemorySizeBytes;
- return _SendRequest(client);
-}
-
-/**
- * @brief
- *
- * @param client
- * @param dataFormatIdentifier
- * @param addressAndLengthFormatIdentifier
- * @param memoryAddress
- * @param memorySize
- * @return UDSErr_t
- * @addtogroup requestDownload_0x35
- */
-UDSErr_t UDSSendRequestUpload(UDSClient_t *client, uint8_t dataFormatIdentifier,
- uint8_t addressAndLengthFormatIdentifier, size_t memoryAddress,
- size_t memorySize) {
- UDSErr_t err = PreRequestCheck(client);
- if (err) {
- return err;
- }
- uint8_t numMemorySizeBytes = (addressAndLengthFormatIdentifier & 0xF0) >> 4;
- uint8_t numMemoryAddressBytes = addressAndLengthFormatIdentifier & 0x0F;
-
- client->send_buf[0] = kSID_REQUEST_UPLOAD;
- client->send_buf[1] = dataFormatIdentifier;
- client->send_buf[2] = addressAndLengthFormatIdentifier;
-
- uint8_t *ptr = &client->send_buf[UDS_0X35_REQ_BASE_LEN];
-
- for (int i = numMemoryAddressBytes - 1; i >= 0; i--) {
- *ptr = (memoryAddress & (0xFF << (8 * i))) >> (8 * i);
- ptr++;
- }
-
- for (int i = numMemorySizeBytes - 1; i >= 0; i--) {
- *ptr = (memorySize & (0xFF << (8 * i))) >> (8 * i);
- ptr++;
- }
-
- client->send_size = UDS_0X35_REQ_BASE_LEN + numMemoryAddressBytes + numMemorySizeBytes;
- return _SendRequest(client);
-}
-
-/**
- * @brief
- *
- * @param client
- * @param blockSequenceCounter
- * @param blockLength
- * @param fd
- * @return UDSErr_t
- * @addtogroup transferData_0x36
- */
-UDSErr_t UDSSendTransferData(UDSClient_t *client, uint8_t blockSequenceCounter,
- const uint16_t blockLength, const uint8_t *data, uint16_t size) {
- UDSErr_t err = PreRequestCheck(client);
- if (err) {
- return err;
- }
- assert(blockLength > 2); // blockLength must include SID and sequenceCounter
- assert(size + 2 <= blockLength); // data must fit inside blockLength - 2
- client->send_buf[0] = kSID_TRANSFER_DATA;
- client->send_buf[1] = blockSequenceCounter;
- memmove(&client->send_buf[UDS_0X36_REQ_BASE_LEN], data, size);
- UDS_DBG_PRINT("size: %d, blocklength: %d\n", size, blockLength);
- client->send_size = UDS_0X36_REQ_BASE_LEN + size;
- return _SendRequest(client);
-}
-
-UDSErr_t UDSSendTransferDataStream(UDSClient_t *client, uint8_t blockSequenceCounter,
- const uint16_t blockLength, FILE *fd) {
- UDSErr_t err = PreRequestCheck(client);
- if (err) {
- return err;
- }
- assert(blockLength > 2); // blockLength must include SID and sequenceCounter
- client->send_buf[0] = kSID_TRANSFER_DATA;
- client->send_buf[1] = blockSequenceCounter;
-
- uint16_t size = fread(&client->send_buf[2], 1, blockLength - 2, fd);
- UDS_DBG_PRINT("size: %d, blocklength: %d\n", size, blockLength);
- client->send_size = UDS_0X36_REQ_BASE_LEN + size;
- return _SendRequest(client);
-}
-
-/**
- * @brief
- *
- * @param client
- * @return UDSErr_t
- * @addtogroup requestTransferExit_0x37
- */
-UDSErr_t UDSSendRequestTransferExit(UDSClient_t *client) {
- UDSErr_t err = PreRequestCheck(client);
- if (err) {
- return err;
- }
- client->send_buf[0] = kSID_REQUEST_TRANSFER_EXIT;
- client->send_size = 1;
- return _SendRequest(client);
-}
-
-/**
- * @brief
- *
- * @param client
- * @param dtcSettingType
- * @param data
- * @param size
- * @return UDSErr_t
- * @addtogroup controlDTCSetting_0x85
- */
-UDSErr_t UDSCtrlDTCSetting(UDSClient_t *client, uint8_t dtcSettingType, uint8_t *data,
- uint16_t size) {
- UDSErr_t err = PreRequestCheck(client);
- if (err) {
- return err;
- }
- if (0x00 == dtcSettingType || 0x7F == dtcSettingType ||
- (0x03 <= dtcSettingType && dtcSettingType <= 0x3F)) {
- assert(0); // reserved vals
- }
- client->send_buf[0] = kSID_CONTROL_DTC_SETTING;
- client->send_buf[1] = dtcSettingType;
-
- if (NULL == data) {
- assert(size == 0);
- } else {
- assert(size > 0);
- if (size > client->send_buf_size - 2) {
- return UDS_ERR_BUFSIZ;
- }
- memmove(&client->send_buf[2], data, size);
- }
- client->send_size = 2 + size;
- return _SendRequest(client);
-}
-
-/**
- * @brief
- *
- * @param client
- * @param level
- * @param data
- * @param size
- * @return UDSErr_t
- * @addtogroup securityAccess_0x27
- */
-UDSErr_t UDSSendSecurityAccess(UDSClient_t *client, uint8_t level, uint8_t *data, uint16_t size) {
- UDSErr_t err = PreRequestCheck(client);
- if (err) {
- return err;
- }
- if (UDSSecurityAccessLevelIsReserved(level)) {
- return UDS_ERR_INVALID_ARG;
- }
- client->send_buf[0] = kSID_SECURITY_ACCESS;
- client->send_buf[1] = level;
- if (size) {
- assert(data);
- if (size > client->send_buf_size - UDS_0X27_REQ_BASE_LEN) {
- return UDS_ERR_BUFSIZ;
- }
- } else {
- assert(NULL == data);
- }
-
- memmove(&client->send_buf[UDS_0X27_REQ_BASE_LEN], data, size);
- client->send_size = UDS_0X27_REQ_BASE_LEN + size;
- return _SendRequest(client);
-}
-
-typedef struct {
- uint8_t dataFormatIdentifier;
- uint8_t addressAndLengthFormatIdentifier;
- size_t memoryAddress;
- size_t memorySize;
- FILE *fd;
- uint8_t blockSequenceCounter;
- uint16_t blockLength;
-} UDSClientDownloadSequence_t;
-
-static UDSSeqState_t requestDownload(UDSClient_t *client) {
- UDSClientDownloadSequence_t *pL_Seq = (UDSClientDownloadSequence_t *)client->cbData;
- UDSSendRequestDownload(client, pL_Seq->dataFormatIdentifier,
- pL_Seq->addressAndLengthFormatIdentifier, pL_Seq->memoryAddress,
- pL_Seq->memorySize);
- return UDSSeqStateGotoNext;
-}
-
-static UDSSeqState_t checkRequestDownloadResponse(UDSClient_t *client) {
- UDSClientDownloadSequence_t *pL_Seq = (UDSClientDownloadSequence_t *)client->cbData;
- struct RequestDownloadResponse resp = {0};
- UDSErr_t err = UDSUnpackRequestDownloadResponse(client, &resp);
- if (err) {
- client->err = err;
- return UDSSeqStateDone;
- }
- pL_Seq->blockLength = resp.maxNumberOfBlockLength;
- if (0 == resp.maxNumberOfBlockLength) {
- client->err = UDS_ERR;
- return UDSSeqStateDone;
- }
- return UDSSeqStateGotoNext;
-}
-
-static UDSSeqState_t prepareToTransfer(UDSClient_t *client) {
- UDSClientDownloadSequence_t *pL_Seq = (UDSClientDownloadSequence_t *)client->cbData;
- pL_Seq->blockSequenceCounter = 1;
- return UDSSeqStateGotoNext;
-}
-
-static UDSSeqState_t transferData(UDSClient_t *client) {
- UDSClientDownloadSequence_t *pL_Seq = (UDSClientDownloadSequence_t *)client->cbData;
- if (kRequestStateIdle == client->state) {
- if (ferror(pL_Seq->fd)) {
- fclose(pL_Seq->fd);
- client->err = UDS_ERR_FILE_IO; // 读取文件故障
- return UDSSeqStateDone;
- } else if (feof(pL_Seq->fd)) { // 传完了
- return UDSSeqStateGotoNext;
- } else {
- UDSSendTransferDataStream(client, pL_Seq->blockSequenceCounter++, pL_Seq->blockLength,
- pL_Seq->fd);
- }
- }
- return UDSSeqStateRunning;
-}
-
-static UDSSeqState_t requestTransferExit(UDSClient_t *client) {
- UDSSendRequestTransferExit(client);
- return UDSSeqStateGotoNext;
-}
-
-UDSErr_t UDSConfigDownload(UDSClient_t *client, uint8_t dataFormatIdentifier,
- uint8_t addressAndLengthFormatIdentifier, size_t memoryAddress,
- size_t memorySize, FILE *fd) {
-
- static const UDSClientCallback callbacks[] = {
- requestDownload, UDSClientAwaitIdle, checkRequestDownloadResponse, prepareToTransfer,
- transferData, requestTransferExit, UDSClientAwaitIdle, NULL};
- static UDSClientDownloadSequence_t seq = {0};
- memset(&seq, 0, sizeof(seq));
- seq.blockSequenceCounter = 1;
- seq.dataFormatIdentifier = dataFormatIdentifier;
- seq.addressAndLengthFormatIdentifier = addressAndLengthFormatIdentifier;
- seq.memoryAddress = memoryAddress;
- seq.memorySize = memorySize;
- seq.fd = fd;
- client->cbList = callbacks;
- client->cbIdx = 0;
- client->cbData = &seq;
- return UDS_OK;
-}
-
-/**
- * @brief
- *
- * @param client
- * @param resp
- * @return UDSErr_t
- * @addtogroup securityAccess_0x27
- */
-UDSErr_t UDSUnpackSecurityAccessResponse(const UDSClient_t *client,
- struct SecurityAccessResponse *resp) {
- assert(client);
- assert(resp);
- if (UDS_RESPONSE_SID_OF(kSID_SECURITY_ACCESS) != client->recv_buf[0]) {
- return UDS_ERR_SID_MISMATCH;
- }
- if (client->recv_size < UDS_0X27_RESP_BASE_LEN) {
- return UDS_ERR_RESP_TOO_SHORT;
- }
- resp->securityAccessType = client->recv_buf[1];
- resp->securitySeedLength = client->recv_size - UDS_0X27_RESP_BASE_LEN;
- resp->securitySeed = resp->securitySeedLength == 0 ? NULL : &client->recv_buf[2];
- return UDS_OK;
-}
-
-/**
- * @brief
- *
- * @param client
- * @param resp
- * @return UDSErr_t
- * @addtogroup routineControl_0x31
- */
-UDSErr_t UDSUnpackRoutineControlResponse(const UDSClient_t *client,
- struct RoutineControlResponse *resp) {
- assert(client);
- assert(resp);
- if (UDS_RESPONSE_SID_OF(kSID_ROUTINE_CONTROL) != client->recv_buf[0]) {
- return UDS_ERR_SID_MISMATCH;
- }
- if (client->recv_size < UDS_0X31_RESP_MIN_LEN) {
- return UDS_ERR_RESP_TOO_SHORT;
- }
- resp->routineControlType = client->recv_buf[1];
- resp->routineIdentifier = (client->recv_buf[2] << 8) + client->recv_buf[3];
- resp->routineStatusRecordLength = client->recv_size - UDS_0X31_RESP_MIN_LEN;
- resp->routineStatusRecord =
- resp->routineStatusRecordLength == 0 ? NULL : &client->recv_buf[UDS_0X31_RESP_MIN_LEN];
- return UDS_OK;
-}
-
-/**
- * @brief
- *
- * @param client
- * @param resp
- * @return UDSErr_t
- * @addtogroup requestDownload_0x34
- */
-UDSErr_t UDSUnpackRequestDownloadResponse(const UDSClient_t *client,
- struct RequestDownloadResponse *resp) {
- assert(client);
- assert(resp);
- if (UDS_RESPONSE_SID_OF(kSID_REQUEST_DOWNLOAD) != client->recv_buf[0]) {
- return UDS_ERR_SID_MISMATCH;
- }
- if (client->recv_size < UDS_0X34_RESP_BASE_LEN) {
- return UDS_ERR_RESP_TOO_SHORT;
- }
- uint8_t maxNumberOfBlockLengthSize = (client->recv_buf[1] & 0xF0) >> 4;
-
- if (sizeof(resp->maxNumberOfBlockLength) < maxNumberOfBlockLengthSize) {
- UDS_DBG_PRINT("WARNING: sizeof(maxNumberOfBlockLength) > sizeof(size_t)");
- return UDS_ERR;
- }
- resp->maxNumberOfBlockLength = 0;
- for (int byteIdx = 0; byteIdx < maxNumberOfBlockLengthSize; byteIdx++) {
- uint8_t byte = client->recv_buf[UDS_0X34_RESP_BASE_LEN + byteIdx];
- uint8_t shiftBytes = maxNumberOfBlockLengthSize - 1 - byteIdx;
- resp->maxNumberOfBlockLength |= byte << (8 * shiftBytes);
- }
- return UDS_OK;
-}
-
-bool UDSClientPoll(UDSClient_t *client) {
- PollLowLevel(client);
-
- if (client->err) {
- return UDS_CLIENT_IDLE;
- }
-
- if (kRequestStateIdle != client->state) {
- return UDS_CLIENT_RUNNING;
- }
-
- if (NULL == client->cbList) {
- return UDS_CLIENT_IDLE;
- }
-
- UDSClientCallback activeCallback = client->cbList[client->cbIdx];
-
- if (NULL == activeCallback) {
- return UDS_CLIENT_IDLE;
- }
-
- UDSSeqState_t state = activeCallback(client);
-
- switch (state) {
- case UDSSeqStateDone:
- return UDS_CLIENT_IDLE;
- case UDSSeqStateRunning:
- return UDS_CLIENT_RUNNING;
- case UDSSeqStateGotoNext: {
- client->cbIdx += 1;
- return UDS_CLIENT_RUNNING;
- }
- default:
- assert(0);
- return UDS_CLIENT_IDLE;
- }
-}
-
-void UDSClientPoll2(UDSClient_t *client,
- int (*fn)(UDSClient_t *client, UDSEvent_t evt, void *ev_data, void *fn_data),
- void *fn_data) {
- UDSClientPoll(client);
-}
-
-UDSSeqState_t UDSClientAwaitIdle(UDSClient_t *client) {
- if (client->err) {
- return UDSSeqStateDone;
- } else if (kRequestStateIdle == client->state) {
- return UDSSeqStateGotoNext;
- } else {
- return UDSSeqStateRunning;
- }
-}
-
-UDSErr_t UDSUnpackRDBIResponse(const uint8_t *buf, size_t buf_len, uint16_t did, uint8_t *data,
- uint16_t data_size, uint16_t *offset) {
- assert(buf);
- assert(data);
- assert(offset);
- if (0 == *offset) {
- *offset = UDS_0X22_RESP_BASE_LEN;
- }
-
- if (*offset + sizeof(did) > buf_len) {
- return UDS_ERR_RESP_TOO_SHORT;
- }
-
- uint16_t theirDID = (buf[*offset] << 8) + buf[*offset + 1];
- if (theirDID != did) {
- return UDS_ERR_DID_MISMATCH;
- }
-
- if (*offset + sizeof(uint16_t) + data_size > buf_len) {
- return UDS_ERR_RESP_TOO_SHORT;
- }
-
- memmove(data, buf + *offset + sizeof(uint16_t), data_size);
-
- *offset += sizeof(uint16_t) + data_size;
- return UDS_OK;
-}
diff --git a/iso14229.h b/iso14229.h
deleted file mode 100644
index becaa79..0000000
--- a/iso14229.h
+++ /dev/null
@@ -1,716 +0,0 @@
-/**
- * @file iso14229.h
- * @brief ISO-14229 (UDS) server and client
- * @author driftregion
- * @version 0.6.0
- * @date 2022-12-08
- */
-
-#ifndef ISO14229_H
-#define ISO14229_H
-
-#ifdef __cplusplus
-extern "C" {
-#define _Static_assert static_assert
-#endif
-
-#define UDS_ARCH_CUSTOM 0
-#define UDS_ARCH_UNIX 1
-#define UDS_ARCH_WINDOWS 2
-
-#define UDS_TP_CUSTOM 0 // bring your own transport layer
-#define UDS_TP_ISOTP_C 1 // use isotp-c
-#define UDS_TP_ISOTP_SOCKET 2 // use linux ISO-TP socket
-
-#if !defined(UDS_ARCH)
-#if defined(__unix__) || defined(__APPLE__)
-#define UDS_ARCH UDS_ARCH_UNIX
-#elif defined(_WIN32)
-#define UDS_ARCH UDS_ARCH_WINDOWS
-#else
-#define UDS_ARCH UDS_ARCH_CUSTOM
-#endif
-#endif
-
-#if !defined(UDS_TP)
-#if (UDS_ARCH == UDS_ARCH_UNIX)
-#define UDS_TP UDS_TP_ISOTP_SOCKET
-#endif
-#endif
-
-#include
-#include
-#include
-#include
-#include
-
-#if (UDS_TP == UDS_TP_ISOTP_C)
-#include "isotp-c/isotp.h"
-#include "isotp-c/isotp_config.h"
-#include "isotp-c/isotp_defines.h"
-#include "isotp-c/isotp_user.h"
-#elif (UDS_TP == UDS_TP_ISOTP_SOCKET)
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#endif
-
-#if (UDS_ARCH == UDS_ARCH_UNIX)
-#include
-#include
-#include
-#elif (UDS_ARCH == UDS_ARCH_WINDOWS)
-#include
-typedef SSIZE_T ssize_t;
-#endif
-
-/** ISO-TP Maximum Transmissiable Unit (ISO-15764-2-2004 section 5.3.3) */
-#define UDS_ISOTP_MTU (4095)
-
-#ifndef UDS_TP_MTU
-#define UDS_TP_MTU UDS_ISOTP_MTU
-#endif
-
-/** Default buffer size */
-#define UDS_BUFSIZE UDS_TP_MTU
-
-/*
-provide a debug function with -DUDS_DBG_PRINT=printf when compiling this
-library
-*/
-#ifndef UDS_DBG_PRINT
-#define UDS_DBG_PRINT(fmt, ...) ((void)fmt)
-#endif
-
-#define UDS_DBG_PRINTHEX(addr, len) \
- for (int i = 0; i < len; i++) { \
- UDS_DBG_PRINT("%02x,", ((uint8_t *)addr)[i]); \
- } \
- UDS_DBG_PRINT("\n");
-
-typedef enum {
- UDS_ERR = -1, // 通用错误
- UDS_OK = 0, // 成功
- UDS_ERR_TIMEOUT, // 请求超时
- UDS_ERR_NEG_RESP, // 否定响应
- UDS_ERR_DID_MISMATCH, // 响应DID对不上期待的DID
- UDS_ERR_SID_MISMATCH, // 请求和响应SID对不上
- UDS_ERR_SUBFUNCTION_MISMATCH, // 请求和响应SubFunction对不上
- UDS_ERR_TPORT, // 传输层错误
- UDS_ERR_FILE_IO, // 文件IO错误
- UDS_ERR_RESP_TOO_SHORT, // 响应太短
- UDS_ERR_BUFSIZ, // 缓冲器不够大
- UDS_ERR_INVALID_ARG, // 参数不对、没发
- UDS_ERR_BUSY, // 正在忙、没发
-} UDSErr_t;
-
-typedef enum {
- UDSSeqStateDone = 0,
- UDSSeqStateRunning = 1,
- UDSSeqStateGotoNext = 2,
-} UDSSeqState_t;
-
-enum UDSDiagnosticSessionType {
- kDefaultSession = 0x01,
- kProgrammingSession = 0x02,
- kExtendedDiagnostic = 0x03,
- kSafetySystemDiagnostic = 0x04,
-};
-
-enum {
- kPositiveResponse = 0,
- kGeneralReject = 0x10,
- kServiceNotSupported = 0x11,
- kSubFunctionNotSupported = 0x12,
- kIncorrectMessageLengthOrInvalidFormat = 0x13,
- kResponseTooLong = 0x14,
- kBusyRepeatRequest = 0x21,
- kConditionsNotCorrect = 0x22,
- kRequestSequenceError = 0x24,
- kNoResponseFromSubnetComponent = 0x25,
- kFailurePreventsExecutionOfRequestedAction = 0x26,
- kRequestOutOfRange = 0x31,
- kSecurityAccessDenied = 0x33,
- kInvalidKey = 0x35,
- kExceedNumberOfAttempts = 0x36,
- kRequiredTimeDelayNotExpired = 0x37,
- kUploadDownloadNotAccepted = 0x70,
- kTransferDataSuspended = 0x71,
- kGeneralProgrammingFailure = 0x72,
- kWrongBlockSequenceCounter = 0x73,
- kRequestCorrectlyReceived_ResponsePending = 0x78,
- kSubFunctionNotSupportedInActiveSession = 0x7E,
- kServiceNotSupportedInActiveSession = 0x7F,
- kRpmTooHigh = 0x81,
- kRpmTooLow = 0x82,
- kEngineIsRunning = 0x83,
- kEngineIsNotRunning = 0x84,
- kEngineRunTimeTooLow = 0x85,
- kTemperatureTooHigh = 0x86,
- kTemperatureTooLow = 0x87,
- kVehicleSpeedTooHigh = 0x88,
- kVehicleSpeedTooLow = 0x89,
- kThrottlePedalTooHigh = 0x8A,
- kThrottlePedalTooLow = 0x8B,
- kTransmissionRangeNotInNeutral = 0x8C,
- kTransmissionRangeNotInGear = 0x8D,
- kISOSAEReserved = 0x8E,
- kBrakeSwitchNotClosed = 0x8F,
- kShifterLeverNotInPark = 0x90,
- kTorqueConverterClutchLocked = 0x91,
- kVoltageTooHigh = 0x92,
- kVoltageTooLow = 0x93,
-};
-
-/**
- * @brief LEV_RT_
- * @addtogroup ecuReset_0x11
- */
-enum UDSECUResetType {
- kHardReset = 1,
- kKeyOffOnReset = 2,
- kSoftReset = 3,
- kEnableRapidPowerShutDown = 4,
- kDisableRapidPowerShutDown = 5,
-};
-
-typedef uint8_t UDSECUReset_t;
-
-/**
- * @addtogroup securityAccess_0x27
- */
-enum UDSSecurityAccessType {
- kRequestSeed = 0x01,
- kSendKey = 0x02,
-};
-
-/**
- * @addtogroup communicationControl_0x28
- */
-enum UDSCommunicationControlType {
- kEnableRxAndTx = 0,
- kEnableRxAndDisableTx = 1,
- kDisableRxAndEnableTx = 2,
- kDisableRxAndTx = 3,
-};
-
-/**
- * @addtogroup communicationControl_0x28
- */
-enum UDSCommunicationType {
- kNormalCommunicationMessages = 0x1,
- kNetworkManagementCommunicationMessages = 0x2,
- kNetworkManagementCommunicationMessagesAndNormalCommunicationMessages = 0x3,
-};
-
-/**
- * @addtogroup routineControl_0x31
- */
-enum RoutineControlType {
- kStartRoutine = 1,
- kStopRoutine = 2,
- kRequestRoutineResults = 3,
-};
-
-/**
- * @addtogroup controlDTCSetting_0x85
- */
-enum DTCSettingType {
- kDTCSettingON = 0x01,
- kDTCSettingOFF = 0x02,
-};
-
-enum UDSTpStatusFlags {
- UDS_TP_IDLE = 0x00000000,
- UDS_TP_SEND_IN_PROGRESS = 0x00000001,
- UDS_TP_RECV_COMPLETE = 0x00000002,
-};
-
-typedef uint32_t UDSTpStatus_t;
-
-typedef enum {
- UDS_A_MTYPE_DIAG = 0,
- UDS_A_MTYPE_REMOTE_DIAG,
- UDS_A_MTYPE_SECURE_DIAG,
- UDS_A_MTYPE_SECURE_REMOTE_DIAG,
-} UDS_A_Mtype_t;
-
-typedef enum {
- UDS_A_TA_TYPE_PHYSICAL = 0, // unicast (1:1)
- UDS_A_TA_TYPE_FUNCTIONAL, // multicast
-} UDS_A_TA_Type_t;
-
-typedef uint8_t UDSTpAddr_t;
-
-/**
- * @brief Service data unit (SDU)
- * @details data interface between the application layer and the transport layer
- */
-typedef struct {
- UDS_A_Mtype_t A_Mtype; // message type (diagnostic, remote diagnostic, secure diagnostic, secure
- // remote diagnostic)
- uint16_t A_SA; // application source address
- uint16_t A_TA; // application target address
- UDS_A_TA_Type_t A_TA_Type; // application target address type (physical or functional)
- uint16_t A_AE; // application layer remote address
-} UDSSDU_t;
-
-#define UDS_TP_NOOP_ADDR (0xFFFFFFFF)
-
-/**
- * @brief Interface to OSI layer 4 (transport layer)
- * @note implementers should embed this struct at offset zero in their own transport layer handle
- */
-typedef struct UDSTpHandle {
- /**
- * @brief Get the transport layer's send buffer
- * @param hdl: pointer to transport handle
- * @param buf: double pointer which will be pointed to the send buffer
- * @return size of transport layer's send buffer on success, -1 on error
- */
- ssize_t (*get_send_buf)(struct UDSTpHandle *hdl, uint8_t **p_buf);
-
- /**
- * @brief Send the data in the buffer buf
- * @param hdl: pointer to transport handle
- * @param buf: a pointer to the data to send (this may be the buffer returned by @ref
- * get_send_buf)
- * @param info: pointer to SDU info (may be NULL). If NULL, implementation should send with
- * physical addressing
- */
- ssize_t (*send)(struct UDSTpHandle *hdl, uint8_t *buf, size_t len, UDSSDU_t *info);
-
- /**
- * @brief Poll the transport layer.
- * @param hdl: pointer to transport handle
- * @note the transport layer user is responsible for calling this function periodically
- * @note threaded implementations like linux isotp sockets don't need to do anything here.
- * @return UDS_TP_IDLE if idle, otherwise UDS_TP_SEND_IN_PROGRESS or UDS_TP_RECV_COMPLETE
- */
- UDSTpStatus_t (*poll)(struct UDSTpHandle *hdl);
-
- /**
- * @brief Peek at the received data
- * @param hdl: pointer to transport handle
- * @param buf: set to the received data
- * @param info: filled with SDU info by the callee if not NULL
- * @return size of received data on success, -1 on error
- * @note The transport will be unable to receive further data until @ref ack_recv is called
- * @note The information returned by peek will not change until @ref ack_recv is called
- */
- ssize_t (*peek)(struct UDSTpHandle *hdl, uint8_t **buf, UDSSDU_t *info);
-
- /**
- * @brief Acknowledge that the received data has been processed and may be discarded
- * @param hdl: pointer to transport handle
- * @note: after ack_recv() is called and before new messages are received, peek must return 0.
- */
- void (*ack_recv)(struct UDSTpHandle *hdl);
-} UDSTpHandle_t;
-
-//
-// Convenience functions to wrap UDSTpHandle_t
-//
-ssize_t UDSTpGetSendBuf(UDSTpHandle_t *hdl, uint8_t **buf);
-ssize_t UDSTpSend(UDSTpHandle_t *hdl, const uint8_t *buf, ssize_t len, UDSSDU_t *info);
-UDSTpStatus_t UDSTpPoll(UDSTpHandle_t *hdl);
-ssize_t UDSTpPeek(struct UDSTpHandle *hdl, uint8_t **buf, UDSSDU_t *info);
-const uint8_t *UDSTpGetRecvBuf(UDSTpHandle_t *hdl, size_t *len);
-size_t UDSTpGetRecvLen(UDSTpHandle_t *hdl);
-void UDSTpAckRecv(UDSTpHandle_t *hdl);
-
-// ========================================================================
-// Utility Functions
-// ========================================================================
-
-/* returns true if `a` is after `b` */
-static inline bool UDSTimeAfter(uint32_t a, uint32_t b) {
- return ((int32_t)((int32_t)(b) - (int32_t)(a)) < 0);
-}
-
-/**
- * @brief Get time in milliseconds
- * @return current time in milliseconds
- */
-uint32_t UDSMillis(void);
-
-// ========================================================================
-// Client
-// ========================================================================
-
-#ifndef UDS_CLIENT_DEFAULT_P2_MS
-#define UDS_CLIENT_DEFAULT_P2_MS (150U)
-#endif
-
-#ifndef UDS_CLIENT_DEFAULT_P2_STAR_MS
-#define UDS_CLIENT_DEFAULT_P2_STAR_MS (1500U)
-#endif
-
-_Static_assert(UDS_CLIENT_DEFAULT_P2_STAR_MS > UDS_CLIENT_DEFAULT_P2_MS, "");
-
-enum UDSClientRequestState {
- kRequestStateIdle = 0, // 完成
- kRequestStateSending, // 传输层现在传输数据
- kRequestStateAwaitSendComplete, // 等待传输发送完成
- kRequestStateAwaitResponse, // 等待响应
- kRequestStateProcessResponse, // 处理响应
-};
-
-typedef uint8_t UDSClientRequestState_t;
-
-enum UDSClientOptions {
- UDS_SUPPRESS_POS_RESP = 0x1, // 服务器不应该发送肯定响应
- UDS_FUNCTIONAL = 0x2, // 发功能请求
- UDS_NEG_RESP_IS_ERR = 0x4, // 否定响应是属于故障
- UDS_IGNORE_SRV_TIMINGS = 0x8, // 忽略服务器给的p2和p2_star
-};
-
-struct UDSClient;
-
-typedef UDSSeqState_t (*UDSClientCallback)(struct UDSClient *client);
-
-typedef struct UDSClient {
- uint16_t p2_ms; // p2 超时时间
- uint32_t p2_star_ms; // 0x78 p2* 超时时间
- UDSTpHandle_t *tp;
-
- // 内状态
- uint32_t p2_timer;
- uint8_t *recv_buf;
- uint8_t *send_buf;
- uint16_t recv_buf_size;
- uint16_t send_buf_size;
- uint16_t recv_size;
- uint16_t send_size;
- UDSErr_t err;
- UDSClientRequestState_t state;
-
- uint8_t options; // enum udsclientoptions
- uint8_t defaultOptions; // enum udsclientoptions
- // a copy of the options at the time a request is made
- uint8_t _options_copy; // enum udsclientoptions
- int (*fn)(struct UDSClient *, int, void *, void *);
-
- const UDSClientCallback *cbList; // null-terminated list of callback functions
- size_t cbIdx; // index of currently active callback function
- void *cbData; // a pointer to data available to callbacks
-
-} UDSClient_t;
-
-struct SecurityAccessResponse {
- uint8_t securityAccessType;
- const uint8_t *securitySeed;
- uint16_t securitySeedLength;
-};
-
-struct RequestDownloadResponse {
- size_t maxNumberOfBlockLength;
-};
-
-struct RoutineControlResponse {
- uint8_t routineControlType;
- uint16_t routineIdentifier;
- const uint8_t *routineStatusRecord;
- uint16_t routineStatusRecordLength;
-};
-
-UDSErr_t UDSClientInit(UDSClient_t *client);
-
-#define UDS_CLIENT_IDLE (0)
-#define UDS_CLIENT_RUNNING (1)
-
-/**
- * @brief poll the client (call this in a loop)
- * @param client
- * @return UDS_CLIENT_IDLE if idle, otherwise UDS_CLIENT_RUNNING
- */
-bool UDSClientPoll(UDSClient_t *client);
-void UDSClientPoll2(UDSClient_t *client,
- int (*fn)(UDSClient_t *client, int evt, void *ev_data, void *fn_data),
- void *fn_data);
-
-UDSErr_t UDSSendBytes(UDSClient_t *client, const uint8_t *data, uint16_t size);
-UDSErr_t UDSSendECUReset(UDSClient_t *client, UDSECUReset_t type);
-UDSErr_t UDSSendDiagSessCtrl(UDSClient_t *client, enum UDSDiagnosticSessionType mode);
-UDSErr_t UDSSendSecurityAccess(UDSClient_t *client, uint8_t level, uint8_t *data, uint16_t size);
-UDSErr_t UDSSendCommCtrl(UDSClient_t *client, enum UDSCommunicationControlType ctrl,
- enum UDSCommunicationType comm);
-UDSErr_t UDSSendRDBI(UDSClient_t *client, const uint16_t *didList,
- const uint16_t numDataIdentifiers);
-UDSErr_t UDSSendWDBI(UDSClient_t *client, uint16_t dataIdentifier, const uint8_t *data,
- uint16_t size);
-UDSErr_t UDSSendTesterPresent(UDSClient_t *client);
-UDSErr_t UDSSendRoutineCtrl(UDSClient_t *client, enum RoutineControlType type,
- uint16_t routineIdentifier, const uint8_t *data, uint16_t size);
-
-UDSErr_t UDSSendRequestDownload(UDSClient_t *client, uint8_t dataFormatIdentifier,
- uint8_t addressAndLengthFormatIdentifier, size_t memoryAddress,
- size_t memorySize);
-
-UDSErr_t UDSSendRequestUpload(UDSClient_t *client, uint8_t dataFormatIdentifier,
- uint8_t addressAndLengthFormatIdentifier, size_t memoryAddress,
- size_t memorySize);
-UDSErr_t UDSSendTransferData(UDSClient_t *client, uint8_t blockSequenceCounter,
- const uint16_t blockLength, const uint8_t *data, uint16_t size);
-UDSErr_t UDSSendTransferDataStream(UDSClient_t *client, uint8_t blockSequenceCounter,
- const uint16_t blockLength, FILE *fd);
-UDSErr_t UDSSendRequestTransferExit(UDSClient_t *client);
-
-UDSErr_t UDSCtrlDTCSetting(UDSClient_t *client, uint8_t dtcSettingType,
- uint8_t *dtcSettingControlOptionRecord, uint16_t len);
-UDSErr_t UDSUnpackRDBIResponse(const uint8_t *buf, size_t buf_len, uint16_t did, uint8_t *data,
- uint16_t size, uint16_t *offset);
-UDSErr_t UDSUnpackSecurityAccessResponse(const UDSClient_t *client,
- struct SecurityAccessResponse *resp);
-UDSErr_t UDSUnpackRequestDownloadResponse(const UDSClient_t *client,
- struct RequestDownloadResponse *resp);
-UDSErr_t UDSUnpackRoutineControlResponse(const UDSClient_t *client,
- struct RoutineControlResponse *resp);
-
-/**
- * @brief Wait after request transmission for a response to be received
- * @note if suppressPositiveResponse is set, this function will return
- UDSSeqStateGotoNext as soon as the transport layer has completed transmission.
- *
- * @param client
- * @param args
- * @return UDSErr_t
- - UDSSeqStateDone -- 流程完成
- - UDSSeqStateRunning -- 流程正在跑、还没完成
- */
-UDSSeqState_t UDSClientAwaitIdle(UDSClient_t *client);
-
-UDSErr_t UDSConfigDownload(UDSClient_t *client, uint8_t dataFormatIdentifier,
- uint8_t addressAndLengthFormatIdentifier, size_t memoryAddress,
- size_t memorySize, FILE *fd);
-
-// ========================================================================
-// Server
-// ========================================================================
-
-#ifndef UDS_SERVER_DEFAULT_POWER_DOWN_TIME_MS
-#define UDS_SERVER_DEFAULT_POWER_DOWN_TIME_MS (10)
-#endif
-
-#ifndef UDS_SERVER_DEFAULT_P2_MS
-#define UDS_SERVER_DEFAULT_P2_MS (50)
-#endif
-
-#ifndef UDS_SERVER_DEFAULT_P2_STAR_MS
-#define UDS_SERVER_DEFAULT_P2_STAR_MS (2000)
-#endif
-
-#ifndef UDS_SERVER_DEFAULT_S3_MS
-#define UDS_SERVER_DEFAULT_S3_MS (3000)
-#endif
-
-_Static_assert(0 < UDS_SERVER_DEFAULT_P2_MS &&
- UDS_SERVER_DEFAULT_P2_MS < UDS_SERVER_DEFAULT_P2_STAR_MS &&
- UDS_SERVER_DEFAULT_P2_STAR_MS < UDS_SERVER_DEFAULT_S3_MS,
- "");
-
-#ifndef UDS_SERVER_DEFAULT_XFER_DATA_MAX_BLOCKLENGTH
-/*! ISO14229-1:2013 Table 396. This parameter is used by the requestDownload positive response
-message to inform the client how many data bytes (maxNumberOfBlockLength) to include in each
-TransferData request message from the client. */
-#define UDS_SERVER_DEFAULT_XFER_DATA_MAX_BLOCKLENGTH (UDS_BUFSIZE)
-#endif
-
-enum UDSServerEvent {
- UDS_SRV_EVT_DiagSessCtrl, // UDSDiagSessCtrlArgs_t *
- UDS_SRV_EVT_EcuReset, // UDSECUResetArgs_t *
- UDS_SRV_EVT_ReadDataByIdent, // UDSRDBIArgs_t *
- UDS_SRV_EVT_ReadMemByAddr, // UDSReadMemByAddrArgs_t *
- UDS_SRV_EVT_CommCtrl, // UDSCommCtrlArgs_t *
- UDS_SRV_EVT_SecAccessRequestSeed, // UDSSecAccessRequestSeedArgs_t *
- UDS_SRV_EVT_SecAccessValidateKey, // UDSSecAccessValidateKeyArgs_t *
- UDS_SRV_EVT_WriteDataByIdent, // UDSWDBIArgs_t *
- UDS_SRV_EVT_RoutineCtrl, // UDSRoutineCtrlArgs_t*
- UDS_SRV_EVT_RequestDownload, // UDSRequestDownloadArgs_t*
- UDS_SRV_EVT_RequestUpload, // UDSRequestUploadArgs_t *
- UDS_SRV_EVT_TransferData, // UDSTransferDataArgs_t *
- UDS_SRV_EVT_RequestTransferExit, // UDSRequestTransferExitArgs_t *
- UDS_SRV_EVT_SessionTimeout, // NULL
- UDS_SRV_EVT_DoScheduledReset, // enum UDSEcuResetType *
- UDS_SRV_EVT_Err, // UDSErr_t *
- UDS_EVT_IDLE,
- UDS_EVT_RESP_RECV,
-};
-
-typedef int UDSServerEvent_t;
-typedef UDSServerEvent_t UDSEvent_t;
-
-/**
- * @brief Server request context
- */
-typedef struct {
- uint8_t *recv_buf;
- uint8_t *send_buf;
- size_t recv_len;
- size_t send_len;
- size_t send_buf_size;
- UDSSDU_t info;
-} UDSReq_t;
-
-typedef struct UDSServer {
- UDSTpHandle_t *tp;
- uint8_t (*fn)(struct UDSServer *srv, UDSServerEvent_t event, const void *arg);
-
- /**
- * @brief \~chinese 服务器时间参数(毫秒) \~ Server time constants (milliseconds) \~
- */
- uint16_t p2_ms; // Default P2_server_max timing supported by the server for
- // the activated diagnostic session.
- uint32_t p2_star_ms; // Enhanced (NRC 0x78) P2_server_max supported by the
- // server for the activated diagnostic session.
- uint16_t s3_ms; // Session timeout
-
- uint8_t ecuResetScheduled; // nonzero indicates that an ECUReset has been scheduled
- uint32_t ecuResetTimer; // for delaying resetting until a response
- // has been sent to the client
- uint32_t p2_timer; // for rate limiting server responses
- uint32_t s3_session_timeout_timer; // indicates that diagnostic session has timed out
-
- /**
- * @brief UDS-1-2013: Table 407 - 0x36 TransferData Supported negative
- * response codes requires that the server keep track of whether the
- * transfer is active
- */
- bool xferIsActive;
- // UDS-1-2013: 14.4.2.3, Table 404: The blockSequenceCounter parameter
- // value starts at 0x01
- uint8_t xferBlockSequenceCounter;
- size_t xferTotalBytes; // total transfer size in bytes requested by the client
- size_t xferByteCounter; // total number of bytes transferred
- size_t xferBlockLength; // block length (convenience for the TransferData API)
-
- uint8_t sessionType; // diagnostic session type (0x10)
- uint8_t securityLevel; // SecurityAccess (0x27) level
-
- bool RCRRP; // set to true when user fn returns 0x78 and false otherwise
- bool requestInProgress; // set to true when a request has been processed but the response has
- // not yet been sent
-
- // UDS-1 2013 defines the following conditions under which the server does not
- // process incoming requests:
- // - not ready to receive (Table A.1 0x78)
- // - not accepting request messages and not sending responses (9.3.1)
- //
- // when this variable is set to true, incoming ISO-TP data will not be processed.
- bool notReadyToReceive;
-
- UDSReq_t r;
-} UDSServer_t;
-
-// TODO: Remove
-typedef struct {
- uint8_t (*fn)(UDSServer_t *srv, UDSServerEvent_t event, const void *arg);
- UDSTpHandle_t *tp;
-} UDSServerConfig_t;
-
-typedef struct {
- const uint8_t type; /*! requested diagnostic session type (enum UDSDiagnosticSessionType) */
- uint16_t p2_ms; /*! optional: p2 timing override */
- uint32_t p2_star_ms; /*! optional: p2* timing override */
-} UDSDiagSessCtrlArgs_t;
-
-typedef struct {
- const uint8_t type; /**< \~chinese 客户端请求的复位类型 \~english reset type requested by client
- (enum UDSECUResetType) */
- uint32_t powerDownTimeMillis; /**< when this much time has elapsed after a kPositiveResponse, a
- UDS_SRV_EVT_DoScheduledReset will be issued */
-} UDSECUResetArgs_t;
-
-typedef struct {
- const uint16_t dataId; /*! RDBI Data Identifier */
- uint8_t (*copy)(UDSServer_t *srv, const void *src,
- uint16_t count); /*! function for copying data */
-} UDSRDBIArgs_t;
-
-typedef struct {
- const void *memAddr;
- const size_t memSize;
- uint8_t (*copy)(UDSServer_t *srv, const void *src,
- uint16_t count); /*! function for copying data */
-} UDSReadMemByAddrArgs_t;
-
-typedef struct {
- uint8_t ctrlType; /* enum UDSCommunicationControlType */
- uint8_t commType; /* enum UDSCommunicationType */
-} UDSCommCtrlArgs_t;
-
-typedef struct {
- const uint8_t level; /*! requested security level */
- const uint8_t *const dataRecord; /*! pointer to request data */
- const uint16_t len; /*! size of request data */
- uint8_t (*copySeed)(UDSServer_t *srv, const void *src,
- uint16_t len); /*! function for copying data */
-} UDSSecAccessRequestSeedArgs_t;
-
-typedef struct {
- const uint8_t level; /*! security level to be validated */
- const uint8_t *const key; /*! key sent by client */
- const uint16_t len; /*! length of key */
-} UDSSecAccessValidateKeyArgs_t;
-
-typedef struct {
- const uint16_t dataId; /*! WDBI Data Identifier */
- const uint8_t *const data; /*! pointer to data */
- const uint16_t len; /*! length of data */
-} UDSWDBIArgs_t;
-
-typedef struct {
- const uint8_t ctrlType; /*! routineControlType */
- const uint16_t id; /*! routineIdentifier */
- const uint8_t *optionRecord; /*! optional data */
- const uint16_t len; /*! length of optional data */
- uint8_t (*copyStatusRecord)(UDSServer_t *srv, const void *src,
- uint16_t len); /*! function for copying response data */
-} UDSRoutineCtrlArgs_t;
-
-typedef struct {
- const void *addr; /*! requested address */
- const size_t size; /*! requested download size */
- const uint8_t dataFormatIdentifier; /*! optional specifier for format of data */
- uint16_t maxNumberOfBlockLength; /*! optional response: inform client how many data bytes to
- send in each `TransferData` request */
-} UDSRequestDownloadArgs_t;
-
-typedef struct {
- const void *addr; /*! requested address */
- const size_t size; /*! requested download size */
- const uint8_t dataFormatIdentifier; /*! optional specifier for format of data */
- uint16_t maxNumberOfBlockLength; /*! optional response: inform client how many data bytes to
- send in each `TransferData` request */
-} UDSRequestUploadArgs_t;
-
-typedef struct {
- const uint8_t *const data; /*! transfer data */
- const uint16_t len; /*! transfer data length */
- const uint16_t maxRespLen; /*! don't send more than this many bytes with copyResponse */
- uint8_t (*copyResponse)(
- UDSServer_t *srv, const void *src,
- uint16_t len); /*! function for copying transfer data response data (optional) */
-} UDSTransferDataArgs_t;
-
-typedef struct {
- const uint8_t *const data; /*! request data */
- const uint16_t len; /*! request data length */
- uint8_t (*copyResponse)(UDSServer_t *srv, const void *src,
- uint16_t len); /*! function for copying response data (optional) */
-} UDSRequestTransferExitArgs_t;
-
-UDSErr_t UDSServerInit(UDSServer_t *srv);
-void UDSServerPoll(UDSServer_t *srv);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/run_gdb.py b/run_gdb.py
new file mode 100755
index 0000000..a9056cc
--- /dev/null
+++ b/run_gdb.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python3
+
+__doc__ = """
+Automates bazel, gdb, and optionally qemu to accelerate debugging
+
+the `bazel test` command explicitly prohibits interactive debugging,
+so this script exists to automate the debugging process.
+"""
+
+import subprocess
+import argparse
+
+GDB = "gdb-multiarch"
+QEMU = "qemu-arm"
+QEMU_LDFLAGS = "/usr/arm-linux-gnueabihf/"
+GDB_PORT = 1234
+
+parser = argparse.ArgumentParser(description=__doc__)
+parser.add_argument("test", help="The test to debug")
+parser.add_argument("--config", help="bazel config", default="")
+args = parser.parse_args()
+gdb_args = [GDB, "-q", "-ex", f"file bazel-bin/test/{args.test}"]
+
+print(f"building {args.test}...")
+bazel_args = ["bazel", "build", "-c", "dbg", "--copt=-g", f"//test:{args.test}"]
+
+subprocess.check_call(bazel_args)
+procs = []
+
+
+if args.config:
+ qemu = subprocess.Popen(
+ [QEMU, "-g", str(GDB_PORT),
+ "-L", "/usr/arm-linux-gnueabihf/",
+ f"bazel-bin/test/{args.test}"],
+ )
+
+ if qemu.returncode is not None:
+ exit(qemu.returncode)
+
+ procs.append(qemu)
+ gdb_args += ["-ex", f"target remote localhost:{GDB_PORT}"]
+
+
+try:
+ gdb = subprocess.Popen(gdb_args)
+ procs.append(gdb)
+ gdb.wait()
+except KeyboardInterrupt:
+ pass
+finally:
+ [p.kill() for p in procs]
+ exit(gdb.returncode)
diff --git a/src/client.c b/src/client.c
new file mode 100644
index 0000000..1351727
--- /dev/null
+++ b/src/client.c
@@ -0,0 +1,856 @@
+#include "client.h"
+#include "config.h"
+#include "util.h"
+
+static void clearRequestContext(UDSClient_t *client) {
+ assert(client);
+ client->recv_size = 0;
+ client->send_size = 0;
+ client->state = kRequestStateIdle;
+ client->err = UDS_OK;
+}
+
+UDSErr_t UDSClientInit(UDSClient_t *client) {
+ assert(client);
+ memset(client, 0, sizeof(*client));
+
+ client->p2_ms = UDS_CLIENT_DEFAULT_P2_MS;
+ client->p2_star_ms = UDS_CLIENT_DEFAULT_P2_STAR_MS;
+
+ if (client->p2_star_ms < client->p2_ms) {
+ fprintf(stderr, "p2_star_ms must be >= p2_ms\n");
+ client->p2_star_ms = client->p2_ms;
+ }
+
+ clearRequestContext(client);
+ return UDS_OK;
+}
+
+static const char *ClientStateName(enum UDSClientRequestState state) {
+ switch (state) {
+ case kRequestStateIdle:
+ return "Idle";
+ case kRequestStateSending:
+ return "Sending";
+ case kRequestStateAwaitSendComplete:
+ return "AwaitSendComplete";
+ case kRequestStateAwaitResponse:
+ return "AwaitResponse";
+ case kRequestStateProcessResponse:
+ return "ProcessResponse";
+ default:
+ return "Unknown";
+ }
+}
+
+static void changeState(UDSClient_t *client, enum UDSClientRequestState state) {
+ printf("client state: %s (%d) -> %s (%d)\n", ClientStateName(client->state), client->state,
+ ClientStateName(state), state);
+ client->state = state;
+}
+
+/**
+ * @brief Check that the response is a valid UDS response
+ *
+ * @param ctx
+ * @return UDSErr_t
+ */
+static UDSErr_t _ClientValidateResponse(const UDSClient_t *client) {
+
+ if (client->recv_size < 1) {
+ return UDS_ERR_RESP_TOO_SHORT;
+ }
+
+ if (0x7F == client->recv_buf[0]) { // 否定响应
+ if (client->recv_size < 2) {
+ return UDS_ERR_RESP_TOO_SHORT;
+ } else if (client->send_buf[0] != client->recv_buf[1]) {
+ return UDS_ERR_SID_MISMATCH;
+ } else if (kRequestCorrectlyReceived_ResponsePending == client->recv_buf[2]) {
+ return UDS_OK;
+ } else if (client->_options_copy & UDS_NEG_RESP_IS_ERR) {
+ return UDS_ERR_NEG_RESP;
+ } else {
+ ;
+ }
+ } else { // 肯定响应
+ if (UDS_RESPONSE_SID_OF(client->send_buf[0]) != client->recv_buf[0]) {
+ return UDS_ERR_SID_MISMATCH;
+ }
+ switch (client->send_buf[0]) {
+ case kSID_ECU_RESET:
+ if (client->recv_size < 2) {
+ return UDS_ERR_RESP_TOO_SHORT;
+ } else if (client->send_buf[1] != client->recv_buf[1]) {
+ return UDS_ERR_SUBFUNCTION_MISMATCH;
+ } else {
+ ;
+ }
+ break;
+ }
+ }
+
+ return UDS_OK;
+}
+
+/**
+ * @brief Handle validated server response
+ * @param client
+ */
+static inline void _ClientHandleResponse(UDSClient_t *client) {
+ if (0x7F == client->recv_buf[0]) {
+ if (kRequestCorrectlyReceived_ResponsePending == client->recv_buf[2]) {
+ UDS_DBG_PRINT("got RCRRP, setting p2 timer\n");
+ client->p2_timer = UDSMillis() + client->p2_star_ms;
+ memset(client->recv_buf, 0, client->recv_buf_size);
+ client->recv_size = 0;
+ UDSTpAckRecv(client->tp);
+ changeState(client, kRequestStateAwaitResponse);
+ return;
+ } else {
+ ;
+ }
+ } else {
+ uint8_t respSid = client->recv_buf[0];
+ switch (UDS_REQUEST_SID_OF(respSid)) {
+ case kSID_DIAGNOSTIC_SESSION_CONTROL: {
+ if (client->recv_size < UDS_0X10_RESP_LEN) {
+ UDS_DBG_PRINT("Error: SID %x response too short\n",
+ kSID_DIAGNOSTIC_SESSION_CONTROL);
+ client->err = UDS_ERR_RESP_TOO_SHORT;
+ UDSTpAckRecv(client->tp);
+ changeState(client, kRequestStateIdle);
+ return;
+ }
+
+ if (client->_options_copy & UDS_IGNORE_SRV_TIMINGS) {
+ UDSTpAckRecv(client->tp);
+ changeState(client, kRequestStateIdle);
+ return;
+ }
+
+ uint16_t p2 = (client->recv_buf[2] << 8) + client->recv_buf[3];
+ uint32_t p2_star = ((client->recv_buf[4] << 8) + client->recv_buf[5]) * 10;
+ UDS_DBG_PRINT("received new timings: p2: %"PRIu16", p2*: %"PRIu32"\n", p2, p2_star);
+ client->p2_ms = p2;
+ client->p2_star_ms = p2_star;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ UDSTpAckRecv(client->tp);
+ changeState(client, kRequestStateIdle);
+}
+
+/**
+ * @brief execute the client request state machine
+ * @param client
+ */
+static void PollLowLevel(UDSClient_t *client) {
+ assert(client);
+ UDSTpStatus_t tp_status = client->tp->poll(client->tp);
+ switch (client->state) {
+ case kRequestStateIdle: {
+ client->options = client->defaultOptions;
+ break;
+ }
+ case kRequestStateSending: {
+ UDSTpAddr_t ta_type = client->_options_copy & UDS_FUNCTIONAL ? UDS_A_TA_TYPE_FUNCTIONAL
+ : UDS_A_TA_TYPE_PHYSICAL;
+ UDSSDU_t info = {
+ .A_Mtype = UDS_A_MTYPE_DIAG,
+ .A_TA_Type = ta_type,
+ };
+ ssize_t ret = UDSTpSend(client->tp, client->send_buf, client->send_size, &info);
+ if (ret < 0) {
+ client->err = UDS_ERR_TPORT;
+ UDS_DBG_PRINT("tport err: %zd\n", ret);
+ } else if (0 == ret) {
+ UDS_DBG_PRINT("send in progress...\n");
+ ; // 等待发送成功
+ } else if (client->send_size == ret) {
+ changeState(client, kRequestStateAwaitSendComplete);
+ } else {
+ client->err = UDS_ERR_BUFSIZ;
+ }
+ break;
+ }
+ case kRequestStateAwaitSendComplete: {
+ if (client->_options_copy & UDS_FUNCTIONAL) {
+ // "The Functional addressing is applied only to single frame transmission"
+ // Specification of Diagnostic Communication (Diagnostic on CAN - Network Layer)
+ changeState(client, kRequestStateIdle);
+ }
+ if (tp_status & UDS_TP_SEND_IN_PROGRESS) {
+ ; // await send complete
+ } else {
+ if (client->_options_copy & UDS_SUPPRESS_POS_RESP) {
+ changeState(client, kRequestStateIdle);
+ } else {
+ changeState(client, kRequestStateAwaitResponse);
+ client->p2_timer = UDSMillis() + client->p2_ms;
+ }
+ }
+ break;
+ }
+ case kRequestStateAwaitResponse: {
+ UDSSDU_t info = {0};
+ ssize_t len = UDSTpPeek(client->tp, &client->recv_buf, &info);
+
+ if (UDS_A_TA_TYPE_FUNCTIONAL == info.A_TA_Type) {
+ UDSTpAckRecv(client->tp);
+ break;
+ }
+ if (len < 0) {
+ client->err = UDS_ERR_TPORT;
+ changeState(client, kRequestStateIdle);
+ } else if (0 == len) {
+ if (UDSTimeAfter(UDSMillis(), client->p2_timer)) {
+ client->err = UDS_ERR_TIMEOUT;
+ changeState(client, kRequestStateIdle);
+ }
+ } else {
+ printf("received %zd bytes\n", len);
+ client->recv_size = len;
+ changeState(client, kRequestStateProcessResponse);
+ }
+ break;
+ }
+ case kRequestStateProcessResponse: {
+ client->err = _ClientValidateResponse(client);
+ if (UDS_OK == client->err) {
+ _ClientHandleResponse(client);
+ } else {
+ UDSTpAckRecv(client->tp);
+ changeState(client, kRequestStateIdle);
+ }
+ break;
+ }
+
+ default:
+ assert(0);
+ }
+}
+
+static UDSErr_t _SendRequest(UDSClient_t *client) {
+ client->_options_copy = client->options;
+
+ if (client->_options_copy & UDS_SUPPRESS_POS_RESP) {
+ // UDS-1:2013 8.2.2 Table 11
+ client->send_buf[1] |= 0x80;
+ }
+
+ changeState(client, kRequestStateSending);
+ PollLowLevel(client); // poll once to begin sending immediately
+ return UDS_OK;
+}
+
+static UDSErr_t PreRequestCheck(UDSClient_t *client) {
+ if (kRequestStateIdle != client->state) {
+ return UDS_ERR_BUSY;
+ }
+ clearRequestContext(client);
+ if (client->tp == NULL) {
+ return UDS_ERR_TPORT;
+ }
+ ssize_t ret = UDSTpGetSendBuf(client->tp, &client->send_buf);
+ if (ret < 0) {
+ return UDS_ERR_TPORT;
+ }
+ client->send_buf_size = ret;
+ return UDS_OK;
+}
+
+UDSErr_t UDSSendBytes(UDSClient_t *client, const uint8_t *data, uint16_t size) {
+ UDSErr_t err = PreRequestCheck(client);
+ if (err) {
+ return err;
+ }
+ if (size > client->send_buf_size) {
+ return UDS_ERR_BUFSIZ;
+ }
+ memmove(client->send_buf, data, size);
+ client->send_size = size;
+ return _SendRequest(client);
+}
+
+UDSErr_t UDSSendECUReset(UDSClient_t *client, UDSECUReset_t type) {
+ UDSErr_t err = PreRequestCheck(client);
+ if (err) {
+ return err;
+ }
+ client->send_buf[0] = kSID_ECU_RESET;
+ client->send_buf[1] = type;
+ client->send_size = 2;
+ return _SendRequest(client);
+}
+
+UDSErr_t UDSSendDiagSessCtrl(UDSClient_t *client, enum UDSDiagnosticSessionType mode) {
+ UDSErr_t err = PreRequestCheck(client);
+ if (err) {
+ return err;
+ }
+ client->send_buf[0] = kSID_DIAGNOSTIC_SESSION_CONTROL;
+ client->send_buf[1] = mode;
+ client->send_size = 2;
+ return _SendRequest(client);
+}
+
+UDSErr_t UDSSendCommCtrl(UDSClient_t *client, enum UDSCommunicationControlType ctrl,
+ enum UDSCommunicationType comm) {
+ UDSErr_t err = PreRequestCheck(client);
+ if (err) {
+ return err;
+ }
+ client->send_buf[0] = kSID_COMMUNICATION_CONTROL;
+ client->send_buf[1] = ctrl;
+ client->send_buf[2] = comm;
+ client->send_size = 3;
+ return _SendRequest(client);
+}
+
+UDSErr_t UDSSendTesterPresent(UDSClient_t *client) {
+ UDSErr_t err = PreRequestCheck(client);
+ if (err) {
+ return err;
+ }
+ client->send_buf[0] = kSID_TESTER_PRESENT;
+ client->send_buf[1] = 0;
+ client->send_size = 2;
+ return _SendRequest(client);
+}
+
+UDSErr_t UDSSendRDBI(UDSClient_t *client, const uint16_t *didList,
+ const uint16_t numDataIdentifiers) {
+ UDSErr_t err = PreRequestCheck(client);
+ if (err) {
+ return err;
+ }
+ assert(didList);
+ assert(numDataIdentifiers);
+ client->send_buf[0] = kSID_READ_DATA_BY_IDENTIFIER;
+ for (int i = 0; i < numDataIdentifiers; i++) {
+ uint16_t offset = 1 + sizeof(uint16_t) * i;
+ if (offset + 2 > client->send_buf_size) {
+ return UDS_ERR_INVALID_ARG;
+ }
+ (client->send_buf + offset)[0] = (didList[i] & 0xFF00) >> 8;
+ (client->send_buf + offset)[1] = (didList[i] & 0xFF);
+ }
+ client->send_size = 1 + (numDataIdentifiers * sizeof(uint16_t));
+ return _SendRequest(client);
+}
+
+UDSErr_t UDSSendWDBI(UDSClient_t *client, uint16_t dataIdentifier, const uint8_t *data,
+ uint16_t size) {
+ UDSErr_t err = PreRequestCheck(client);
+ if (err) {
+ return err;
+ }
+ assert(data);
+ assert(size);
+ client->send_buf[0] = kSID_WRITE_DATA_BY_IDENTIFIER;
+ if (client->send_buf_size <= 3 || size > client->send_buf_size - 3) {
+ return UDS_ERR_BUFSIZ;
+ }
+ client->send_buf[1] = (dataIdentifier & 0xFF00) >> 8;
+ client->send_buf[2] = (dataIdentifier & 0xFF);
+ memmove(&client->send_buf[3], data, size);
+ client->send_size = 3 + size;
+ return _SendRequest(client);
+}
+
+/**
+ * @brief RoutineControl
+ *
+ * @param client
+ * @param type
+ * @param routineIdentifier
+ * @param data
+ * @param size
+ * @return UDSErr_t
+ * @addtogroup routineControl_0x31
+ */
+UDSErr_t UDSSendRoutineCtrl(UDSClient_t *client, enum RoutineControlType type,
+ uint16_t routineIdentifier, const uint8_t *data, uint16_t size) {
+ UDSErr_t err = PreRequestCheck(client);
+ if (err) {
+ return err;
+ }
+ client->send_buf[0] = kSID_ROUTINE_CONTROL;
+ client->send_buf[1] = type;
+ client->send_buf[2] = routineIdentifier >> 8;
+ client->send_buf[3] = routineIdentifier;
+ if (size) {
+ assert(data);
+ if (size > client->send_buf_size - UDS_0X31_REQ_MIN_LEN) {
+ return UDS_ERR_BUFSIZ;
+ }
+ memmove(&client->send_buf[UDS_0X31_REQ_MIN_LEN], data, size);
+ } else {
+ assert(NULL == data);
+ }
+ client->send_size = UDS_0X31_REQ_MIN_LEN + size;
+ return _SendRequest(client);
+}
+
+/**
+ * @brief
+ *
+ * @param client
+ * @param dataFormatIdentifier
+ * @param addressAndLengthFormatIdentifier
+ * @param memoryAddress
+ * @param memorySize
+ * @return UDSErr_t
+ * @addtogroup requestDownload_0x34
+ */
+UDSErr_t UDSSendRequestDownload(UDSClient_t *client, uint8_t dataFormatIdentifier,
+ uint8_t addressAndLengthFormatIdentifier, size_t memoryAddress,
+ size_t memorySize) {
+ UDSErr_t err = PreRequestCheck(client);
+ if (err) {
+ return err;
+ }
+ uint8_t numMemorySizeBytes = (addressAndLengthFormatIdentifier & 0xF0) >> 4;
+ uint8_t numMemoryAddressBytes = addressAndLengthFormatIdentifier & 0x0F;
+
+ client->send_buf[0] = kSID_REQUEST_DOWNLOAD;
+ client->send_buf[1] = dataFormatIdentifier;
+ client->send_buf[2] = addressAndLengthFormatIdentifier;
+
+ uint8_t *ptr = &client->send_buf[UDS_0X34_REQ_BASE_LEN];
+
+ for (int i = numMemoryAddressBytes - 1; i >= 0; i--) {
+ *ptr = (memoryAddress & (0xFF << (8 * i))) >> (8 * i);
+ ptr++;
+ }
+
+ for (int i = numMemorySizeBytes - 1; i >= 0; i--) {
+ *ptr = (memorySize & (0xFF << (8 * i))) >> (8 * i);
+ ptr++;
+ }
+
+ client->send_size = UDS_0X34_REQ_BASE_LEN + numMemoryAddressBytes + numMemorySizeBytes;
+ return _SendRequest(client);
+}
+
+/**
+ * @brief
+ *
+ * @param client
+ * @param dataFormatIdentifier
+ * @param addressAndLengthFormatIdentifier
+ * @param memoryAddress
+ * @param memorySize
+ * @return UDSErr_t
+ * @addtogroup requestDownload_0x35
+ */
+UDSErr_t UDSSendRequestUpload(UDSClient_t *client, uint8_t dataFormatIdentifier,
+ uint8_t addressAndLengthFormatIdentifier, size_t memoryAddress,
+ size_t memorySize) {
+ UDSErr_t err = PreRequestCheck(client);
+ if (err) {
+ return err;
+ }
+ uint8_t numMemorySizeBytes = (addressAndLengthFormatIdentifier & 0xF0) >> 4;
+ uint8_t numMemoryAddressBytes = addressAndLengthFormatIdentifier & 0x0F;
+
+ client->send_buf[0] = kSID_REQUEST_UPLOAD;
+ client->send_buf[1] = dataFormatIdentifier;
+ client->send_buf[2] = addressAndLengthFormatIdentifier;
+
+ uint8_t *ptr = &client->send_buf[UDS_0X35_REQ_BASE_LEN];
+
+ for (int i = numMemoryAddressBytes - 1; i >= 0; i--) {
+ *ptr = (memoryAddress & (0xFF << (8 * i))) >> (8 * i);
+ ptr++;
+ }
+
+ for (int i = numMemorySizeBytes - 1; i >= 0; i--) {
+ *ptr = (memorySize & (0xFF << (8 * i))) >> (8 * i);
+ ptr++;
+ }
+
+ client->send_size = UDS_0X35_REQ_BASE_LEN + numMemoryAddressBytes + numMemorySizeBytes;
+ return _SendRequest(client);
+}
+
+/**
+ * @brief
+ *
+ * @param client
+ * @param blockSequenceCounter
+ * @param blockLength
+ * @param fd
+ * @return UDSErr_t
+ * @addtogroup transferData_0x36
+ */
+UDSErr_t UDSSendTransferData(UDSClient_t *client, uint8_t blockSequenceCounter,
+ const uint16_t blockLength, const uint8_t *data, uint16_t size) {
+ UDSErr_t err = PreRequestCheck(client);
+ if (err) {
+ return err;
+ }
+ assert(blockLength > 2); // blockLength must include SID and sequenceCounter
+ assert(size + 2 <= blockLength); // data must fit inside blockLength - 2
+ client->send_buf[0] = kSID_TRANSFER_DATA;
+ client->send_buf[1] = blockSequenceCounter;
+ memmove(&client->send_buf[UDS_0X36_REQ_BASE_LEN], data, size);
+ UDS_DBG_PRINT("size: %d, blocklength: %d\n", size, blockLength);
+ client->send_size = UDS_0X36_REQ_BASE_LEN + size;
+ return _SendRequest(client);
+}
+
+UDSErr_t UDSSendTransferDataStream(UDSClient_t *client, uint8_t blockSequenceCounter,
+ const uint16_t blockLength, FILE *fd) {
+ UDSErr_t err = PreRequestCheck(client);
+ if (err) {
+ return err;
+ }
+ assert(blockLength > 2); // blockLength must include SID and sequenceCounter
+ client->send_buf[0] = kSID_TRANSFER_DATA;
+ client->send_buf[1] = blockSequenceCounter;
+
+ uint16_t size = fread(&client->send_buf[2], 1, blockLength - 2, fd);
+ UDS_DBG_PRINT("size: %d, blocklength: %d\n", size, blockLength);
+ client->send_size = UDS_0X36_REQ_BASE_LEN + size;
+ return _SendRequest(client);
+}
+
+/**
+ * @brief
+ *
+ * @param client
+ * @return UDSErr_t
+ * @addtogroup requestTransferExit_0x37
+ */
+UDSErr_t UDSSendRequestTransferExit(UDSClient_t *client) {
+ UDSErr_t err = PreRequestCheck(client);
+ if (err) {
+ return err;
+ }
+ client->send_buf[0] = kSID_REQUEST_TRANSFER_EXIT;
+ client->send_size = 1;
+ return _SendRequest(client);
+}
+
+/**
+ * @brief
+ *
+ * @param client
+ * @param dtcSettingType
+ * @param data
+ * @param size
+ * @return UDSErr_t
+ * @addtogroup controlDTCSetting_0x85
+ */
+UDSErr_t UDSCtrlDTCSetting(UDSClient_t *client, uint8_t dtcSettingType, uint8_t *data,
+ uint16_t size) {
+ UDSErr_t err = PreRequestCheck(client);
+ if (err) {
+ return err;
+ }
+ if (0x00 == dtcSettingType || 0x7F == dtcSettingType ||
+ (0x03 <= dtcSettingType && dtcSettingType <= 0x3F)) {
+ assert(0); // reserved vals
+ }
+ client->send_buf[0] = kSID_CONTROL_DTC_SETTING;
+ client->send_buf[1] = dtcSettingType;
+
+ if (NULL == data) {
+ assert(size == 0);
+ } else {
+ assert(size > 0);
+ if (size > client->send_buf_size - 2) {
+ return UDS_ERR_BUFSIZ;
+ }
+ memmove(&client->send_buf[2], data, size);
+ }
+ client->send_size = 2 + size;
+ return _SendRequest(client);
+}
+
+/**
+ * @brief
+ *
+ * @param client
+ * @param level
+ * @param data
+ * @param size
+ * @return UDSErr_t
+ * @addtogroup securityAccess_0x27
+ */
+UDSErr_t UDSSendSecurityAccess(UDSClient_t *client, uint8_t level, uint8_t *data, uint16_t size) {
+ UDSErr_t err = PreRequestCheck(client);
+ if (err) {
+ return err;
+ }
+ if (UDSSecurityAccessLevelIsReserved(level)) {
+ return UDS_ERR_INVALID_ARG;
+ }
+ client->send_buf[0] = kSID_SECURITY_ACCESS;
+ client->send_buf[1] = level;
+ if (size) {
+ assert(data);
+ if (size > client->send_buf_size - UDS_0X27_REQ_BASE_LEN) {
+ return UDS_ERR_BUFSIZ;
+ }
+ } else {
+ assert(NULL == data);
+ }
+
+ memmove(&client->send_buf[UDS_0X27_REQ_BASE_LEN], data, size);
+ client->send_size = UDS_0X27_REQ_BASE_LEN + size;
+ return _SendRequest(client);
+}
+
+typedef struct {
+ uint8_t dataFormatIdentifier;
+ uint8_t addressAndLengthFormatIdentifier;
+ size_t memoryAddress;
+ size_t memorySize;
+ FILE *fd;
+ uint8_t blockSequenceCounter;
+ uint16_t blockLength;
+} UDSClientDownloadSequence_t;
+
+static UDSSeqState_t requestDownload(UDSClient_t *client) {
+ UDSClientDownloadSequence_t *pL_Seq = (UDSClientDownloadSequence_t *)client->cbData;
+ UDSSendRequestDownload(client, pL_Seq->dataFormatIdentifier,
+ pL_Seq->addressAndLengthFormatIdentifier, pL_Seq->memoryAddress,
+ pL_Seq->memorySize);
+ return UDSSeqStateGotoNext;
+}
+
+static UDSSeqState_t checkRequestDownloadResponse(UDSClient_t *client) {
+ UDSClientDownloadSequence_t *pL_Seq = (UDSClientDownloadSequence_t *)client->cbData;
+ struct RequestDownloadResponse resp = {0};
+ UDSErr_t err = UDSUnpackRequestDownloadResponse(client, &resp);
+ if (err) {
+ client->err = err;
+ return UDSSeqStateDone;
+ }
+ pL_Seq->blockLength = resp.maxNumberOfBlockLength;
+ if (0 == resp.maxNumberOfBlockLength) {
+ client->err = UDS_ERR;
+ return UDSSeqStateDone;
+ }
+ return UDSSeqStateGotoNext;
+}
+
+static UDSSeqState_t prepareToTransfer(UDSClient_t *client) {
+ UDSClientDownloadSequence_t *pL_Seq = (UDSClientDownloadSequence_t *)client->cbData;
+ pL_Seq->blockSequenceCounter = 1;
+ return UDSSeqStateGotoNext;
+}
+
+static UDSSeqState_t transferData(UDSClient_t *client) {
+ UDSClientDownloadSequence_t *pL_Seq = (UDSClientDownloadSequence_t *)client->cbData;
+ if (kRequestStateIdle == client->state) {
+ if (ferror(pL_Seq->fd)) {
+ fclose(pL_Seq->fd);
+ client->err = UDS_ERR_FILE_IO; // 读取文件故障
+ return UDSSeqStateDone;
+ } else if (feof(pL_Seq->fd)) { // 传完了
+ return UDSSeqStateGotoNext;
+ } else {
+ UDSSendTransferDataStream(client, pL_Seq->blockSequenceCounter++, pL_Seq->blockLength,
+ pL_Seq->fd);
+ }
+ }
+ return UDSSeqStateRunning;
+}
+
+static UDSSeqState_t requestTransferExit(UDSClient_t *client) {
+ UDSSendRequestTransferExit(client);
+ return UDSSeqStateGotoNext;
+}
+
+UDSErr_t UDSConfigDownload(UDSClient_t *client, uint8_t dataFormatIdentifier,
+ uint8_t addressAndLengthFormatIdentifier, size_t memoryAddress,
+ size_t memorySize, FILE *fd) {
+
+ static const UDSClientCallback callbacks[] = {
+ requestDownload, UDSClientAwaitIdle, checkRequestDownloadResponse, prepareToTransfer,
+ transferData, requestTransferExit, UDSClientAwaitIdle, NULL};
+ static UDSClientDownloadSequence_t seq = {0};
+ memset(&seq, 0, sizeof(seq));
+ seq.blockSequenceCounter = 1;
+ seq.dataFormatIdentifier = dataFormatIdentifier;
+ seq.addressAndLengthFormatIdentifier = addressAndLengthFormatIdentifier;
+ seq.memoryAddress = memoryAddress;
+ seq.memorySize = memorySize;
+ seq.fd = fd;
+ client->cbList = callbacks;
+ client->cbIdx = 0;
+ client->cbData = &seq;
+ return UDS_OK;
+}
+
+/**
+ * @brief
+ *
+ * @param client
+ * @param resp
+ * @return UDSErr_t
+ * @addtogroup securityAccess_0x27
+ */
+UDSErr_t UDSUnpackSecurityAccessResponse(const UDSClient_t *client,
+ struct SecurityAccessResponse *resp) {
+ assert(client);
+ assert(resp);
+ if (UDS_RESPONSE_SID_OF(kSID_SECURITY_ACCESS) != client->recv_buf[0]) {
+ return UDS_ERR_SID_MISMATCH;
+ }
+ if (client->recv_size < UDS_0X27_RESP_BASE_LEN) {
+ return UDS_ERR_RESP_TOO_SHORT;
+ }
+ resp->securityAccessType = client->recv_buf[1];
+ resp->securitySeedLength = client->recv_size - UDS_0X27_RESP_BASE_LEN;
+ resp->securitySeed = resp->securitySeedLength == 0 ? NULL : &client->recv_buf[2];
+ return UDS_OK;
+}
+
+/**
+ * @brief
+ *
+ * @param client
+ * @param resp
+ * @return UDSErr_t
+ * @addtogroup routineControl_0x31
+ */
+UDSErr_t UDSUnpackRoutineControlResponse(const UDSClient_t *client,
+ struct RoutineControlResponse *resp) {
+ assert(client);
+ assert(resp);
+ if (UDS_RESPONSE_SID_OF(kSID_ROUTINE_CONTROL) != client->recv_buf[0]) {
+ return UDS_ERR_SID_MISMATCH;
+ }
+ if (client->recv_size < UDS_0X31_RESP_MIN_LEN) {
+ return UDS_ERR_RESP_TOO_SHORT;
+ }
+ resp->routineControlType = client->recv_buf[1];
+ resp->routineIdentifier = (client->recv_buf[2] << 8) + client->recv_buf[3];
+ resp->routineStatusRecordLength = client->recv_size - UDS_0X31_RESP_MIN_LEN;
+ resp->routineStatusRecord =
+ resp->routineStatusRecordLength == 0 ? NULL : &client->recv_buf[UDS_0X31_RESP_MIN_LEN];
+ return UDS_OK;
+}
+
+/**
+ * @brief
+ *
+ * @param client
+ * @param resp
+ * @return UDSErr_t
+ * @addtogroup requestDownload_0x34
+ */
+UDSErr_t UDSUnpackRequestDownloadResponse(const UDSClient_t *client,
+ struct RequestDownloadResponse *resp) {
+ assert(client);
+ assert(resp);
+ if (UDS_RESPONSE_SID_OF(kSID_REQUEST_DOWNLOAD) != client->recv_buf[0]) {
+ return UDS_ERR_SID_MISMATCH;
+ }
+ if (client->recv_size < UDS_0X34_RESP_BASE_LEN) {
+ return UDS_ERR_RESP_TOO_SHORT;
+ }
+ uint8_t maxNumberOfBlockLengthSize = (client->recv_buf[1] & 0xF0) >> 4;
+
+ if (sizeof(resp->maxNumberOfBlockLength) < maxNumberOfBlockLengthSize) {
+ UDS_DBG_PRINT("WARNING: sizeof(maxNumberOfBlockLength) > sizeof(size_t)");
+ return UDS_ERR;
+ }
+ resp->maxNumberOfBlockLength = 0;
+ for (int byteIdx = 0; byteIdx < maxNumberOfBlockLengthSize; byteIdx++) {
+ uint8_t byte = client->recv_buf[UDS_0X34_RESP_BASE_LEN + byteIdx];
+ uint8_t shiftBytes = maxNumberOfBlockLengthSize - 1 - byteIdx;
+ resp->maxNumberOfBlockLength |= byte << (8 * shiftBytes);
+ }
+ return UDS_OK;
+}
+
+bool UDSClientPoll(UDSClient_t *client) {
+ PollLowLevel(client);
+
+ if (client->err) {
+ return UDS_CLIENT_IDLE;
+ }
+
+ if (kRequestStateIdle != client->state) {
+ return UDS_CLIENT_RUNNING;
+ }
+
+ if (NULL == client->cbList) {
+ return UDS_CLIENT_IDLE;
+ }
+
+ UDSClientCallback activeCallback = client->cbList[client->cbIdx];
+
+ if (NULL == activeCallback) {
+ return UDS_CLIENT_IDLE;
+ }
+
+ UDSSeqState_t state = activeCallback(client);
+
+ switch (state) {
+ case UDSSeqStateDone:
+ return UDS_CLIENT_IDLE;
+ case UDSSeqStateRunning:
+ return UDS_CLIENT_RUNNING;
+ case UDSSeqStateGotoNext: {
+ client->cbIdx += 1;
+ return UDS_CLIENT_RUNNING;
+ }
+ default:
+ assert(0);
+ return UDS_CLIENT_IDLE;
+ }
+}
+
+void UDSClientPoll2(UDSClient_t *client,
+ int (*fn)(UDSClient_t *client, UDSEvent_t evt, void *ev_data, void *fn_data),
+ void *fn_data) {
+ UDSClientPoll(client);
+}
+
+UDSSeqState_t UDSClientAwaitIdle(UDSClient_t *client) {
+ if (client->err) {
+ return UDSSeqStateDone;
+ } else if (kRequestStateIdle == client->state) {
+ return UDSSeqStateGotoNext;
+ } else {
+ return UDSSeqStateRunning;
+ }
+}
+
+UDSErr_t UDSUnpackRDBIResponse(const uint8_t *buf, size_t buf_len, uint16_t did, uint8_t *data,
+ uint16_t data_size, uint16_t *offset) {
+ assert(buf);
+ assert(data);
+ assert(offset);
+ if (0 == *offset) {
+ *offset = UDS_0X22_RESP_BASE_LEN;
+ }
+
+ if (*offset + sizeof(did) > buf_len) {
+ return UDS_ERR_RESP_TOO_SHORT;
+ }
+
+ uint16_t theirDID = (buf[*offset] << 8) + buf[*offset + 1];
+ if (theirDID != did) {
+ return UDS_ERR_DID_MISMATCH;
+ }
+
+ if (*offset + sizeof(uint16_t) + data_size > buf_len) {
+ return UDS_ERR_RESP_TOO_SHORT;
+ }
+
+ memmove(data, buf + *offset + sizeof(uint16_t), data_size);
+
+ *offset += sizeof(uint16_t) + data_size;
+ return UDS_OK;
+}
diff --git a/src/client.h b/src/client.h
new file mode 100644
index 0000000..141edc6
--- /dev/null
+++ b/src/client.h
@@ -0,0 +1,144 @@
+#pragma once
+
+#include "sys.h"
+#include "tp.h"
+#include "uds.h"
+
+
+enum UDSClientRequestState {
+ kRequestStateIdle = 0, // 完成
+ kRequestStateSending, // 传输层现在传输数据
+ kRequestStateAwaitSendComplete, // 等待传输发送完成
+ kRequestStateAwaitResponse, // 等待响应
+ kRequestStateProcessResponse, // 处理响应
+};
+
+typedef uint8_t UDSClientRequestState_t;
+
+enum UDSClientOptions {
+ UDS_SUPPRESS_POS_RESP = 0x1, // 服务器不应该发送肯定响应
+ UDS_FUNCTIONAL = 0x2, // 发功能请求
+ UDS_NEG_RESP_IS_ERR = 0x4, // 否定响应是属于故障
+ UDS_IGNORE_SRV_TIMINGS = 0x8, // 忽略服务器给的p2和p2_star
+};
+
+struct UDSClient;
+
+typedef UDSSeqState_t (*UDSClientCallback)(struct UDSClient *client);
+
+typedef struct UDSClient {
+ uint16_t p2_ms; // p2 超时时间
+ uint32_t p2_star_ms; // 0x78 p2* 超时时间
+ UDSTpHandle_t *tp;
+
+ // 内状态
+ uint32_t p2_timer;
+ uint8_t *recv_buf;
+ uint8_t *send_buf;
+ uint16_t recv_buf_size;
+ uint16_t send_buf_size;
+ uint16_t recv_size;
+ uint16_t send_size;
+ UDSErr_t err;
+ UDSClientRequestState_t state;
+
+ uint8_t options; // enum udsclientoptions
+ uint8_t defaultOptions; // enum udsclientoptions
+ // a copy of the options at the time a request is made
+ uint8_t _options_copy; // enum udsclientoptions
+ int (*fn)(struct UDSClient *, int, void *, void *);
+
+ const UDSClientCallback *cbList; // null-terminated list of callback functions
+ size_t cbIdx; // index of currently active callback function
+ void *cbData; // a pointer to data available to callbacks
+
+} UDSClient_t;
+
+struct SecurityAccessResponse {
+ uint8_t securityAccessType;
+ const uint8_t *securitySeed;
+ uint16_t securitySeedLength;
+};
+
+struct RequestDownloadResponse {
+ size_t maxNumberOfBlockLength;
+};
+
+struct RoutineControlResponse {
+ uint8_t routineControlType;
+ uint16_t routineIdentifier;
+ const uint8_t *routineStatusRecord;
+ uint16_t routineStatusRecordLength;
+};
+
+UDSErr_t UDSClientInit(UDSClient_t *client);
+
+#define UDS_CLIENT_IDLE (0)
+#define UDS_CLIENT_RUNNING (1)
+
+/**
+ * @brief poll the client (call this in a loop)
+ * @param client
+ * @return UDS_CLIENT_IDLE if idle, otherwise UDS_CLIENT_RUNNING
+ */
+bool UDSClientPoll(UDSClient_t *client);
+void UDSClientPoll2(UDSClient_t *client,
+ int (*fn)(UDSClient_t *client, int evt, void *ev_data, void *fn_data),
+ void *fn_data);
+
+UDSErr_t UDSSendBytes(UDSClient_t *client, const uint8_t *data, uint16_t size);
+UDSErr_t UDSSendECUReset(UDSClient_t *client, UDSECUReset_t type);
+UDSErr_t UDSSendDiagSessCtrl(UDSClient_t *client, enum UDSDiagnosticSessionType mode);
+UDSErr_t UDSSendSecurityAccess(UDSClient_t *client, uint8_t level, uint8_t *data, uint16_t size);
+UDSErr_t UDSSendCommCtrl(UDSClient_t *client, enum UDSCommunicationControlType ctrl,
+ enum UDSCommunicationType comm);
+UDSErr_t UDSSendRDBI(UDSClient_t *client, const uint16_t *didList,
+ const uint16_t numDataIdentifiers);
+UDSErr_t UDSSendWDBI(UDSClient_t *client, uint16_t dataIdentifier, const uint8_t *data,
+ uint16_t size);
+UDSErr_t UDSSendTesterPresent(UDSClient_t *client);
+UDSErr_t UDSSendRoutineCtrl(UDSClient_t *client, enum RoutineControlType type,
+ uint16_t routineIdentifier, const uint8_t *data, uint16_t size);
+
+UDSErr_t UDSSendRequestDownload(UDSClient_t *client, uint8_t dataFormatIdentifier,
+ uint8_t addressAndLengthFormatIdentifier, size_t memoryAddress,
+ size_t memorySize);
+
+UDSErr_t UDSSendRequestUpload(UDSClient_t *client, uint8_t dataFormatIdentifier,
+ uint8_t addressAndLengthFormatIdentifier, size_t memoryAddress,
+ size_t memorySize);
+UDSErr_t UDSSendTransferData(UDSClient_t *client, uint8_t blockSequenceCounter,
+ const uint16_t blockLength, const uint8_t *data, uint16_t size);
+UDSErr_t UDSSendTransferDataStream(UDSClient_t *client, uint8_t blockSequenceCounter,
+ const uint16_t blockLength, FILE *fd);
+UDSErr_t UDSSendRequestTransferExit(UDSClient_t *client);
+
+UDSErr_t UDSCtrlDTCSetting(UDSClient_t *client, uint8_t dtcSettingType,
+ uint8_t *dtcSettingControlOptionRecord, uint16_t len);
+UDSErr_t UDSUnpackRDBIResponse(const uint8_t *buf, size_t buf_len, uint16_t did, uint8_t *data,
+ uint16_t size, uint16_t *offset);
+UDSErr_t UDSUnpackSecurityAccessResponse(const UDSClient_t *client,
+ struct SecurityAccessResponse *resp);
+UDSErr_t UDSUnpackRequestDownloadResponse(const UDSClient_t *client,
+ struct RequestDownloadResponse *resp);
+UDSErr_t UDSUnpackRoutineControlResponse(const UDSClient_t *client,
+ struct RoutineControlResponse *resp);
+
+/**
+ * @brief Wait after request transmission for a response to be received
+ * @note if suppressPositiveResponse is set, this function will return
+ UDSSeqStateGotoNext as soon as the transport layer has completed transmission.
+ *
+ * @param client
+ * @param args
+ * @return UDSErr_t
+ - UDSSeqStateDone -- 流程完成
+ - UDSSeqStateRunning -- 流程正在跑、还没完成
+ */
+UDSSeqState_t UDSClientAwaitIdle(UDSClient_t *client);
+
+UDSErr_t UDSConfigDownload(UDSClient_t *client, uint8_t dataFormatIdentifier,
+ uint8_t addressAndLengthFormatIdentifier, size_t memoryAddress,
+ size_t memorySize, FILE *fd);
+
+
diff --git a/src/config.h b/src/config.h
new file mode 100644
index 0000000..0f0d173
--- /dev/null
+++ b/src/config.h
@@ -0,0 +1,66 @@
+#pragma once
+
+#ifndef UDS_ENABLE_DBG_PRINT
+#define UDS_ENABLE_DBG_PRINT 0
+#endif
+
+#ifndef UDS_ENABLE_ASSERT
+#define UDS_ENABLE_ASSERT 0
+#endif
+
+/** ISO-TP Maximum Transmissiable Unit (ISO-15764-2-2004 section 5.3.3) */
+#define UDS_ISOTP_MTU (4095)
+
+#ifndef UDS_TP_MTU
+#define UDS_TP_MTU UDS_ISOTP_MTU
+#endif
+
+#ifndef UDS_CLIENT_DEFAULT_P2_MS
+#define UDS_CLIENT_DEFAULT_P2_MS (150U)
+#endif
+
+#ifndef UDS_CLIENT_DEFAULT_P2_STAR_MS
+#define UDS_CLIENT_DEFAULT_P2_STAR_MS (1500U)
+#endif
+
+_Static_assert(UDS_CLIENT_DEFAULT_P2_STAR_MS > UDS_CLIENT_DEFAULT_P2_MS, "");
+
+
+#ifndef UDS_SERVER_DEFAULT_POWER_DOWN_TIME_MS
+#define UDS_SERVER_DEFAULT_POWER_DOWN_TIME_MS (10)
+#endif
+
+#ifndef UDS_SERVER_DEFAULT_P2_MS
+#define UDS_SERVER_DEFAULT_P2_MS (50)
+#endif
+
+#ifndef UDS_SERVER_DEFAULT_P2_STAR_MS
+#define UDS_SERVER_DEFAULT_P2_STAR_MS (2000)
+#endif
+
+#ifndef UDS_SERVER_DEFAULT_S3_MS
+#define UDS_SERVER_DEFAULT_S3_MS (3000)
+#endif
+
+_Static_assert(0 < UDS_SERVER_DEFAULT_P2_MS &&
+ UDS_SERVER_DEFAULT_P2_MS < UDS_SERVER_DEFAULT_P2_STAR_MS &&
+ UDS_SERVER_DEFAULT_P2_STAR_MS < UDS_SERVER_DEFAULT_S3_MS,
+ "");
+
+// Amount of time to wait after boot before accepting 0x27 requests.
+#ifndef UDS_SERVER_0x27_BRUTE_FORCE_MITIGATION_BOOT_DELAY_MS
+#define UDS_SERVER_0x27_BRUTE_FORCE_MITIGATION_BOOT_DELAY_MS (1000)
+#endif
+
+// Amount of time to wait after an authentication failure before accepting another 0x27 request.
+#ifndef UDS_SERVER_0x27_BRUTE_FORCE_MITIGATION_AUTH_FAIL_DELAY_MS
+#define UDS_SERVER_0x27_BRUTE_FORCE_MITIGATION_AUTH_FAIL_DELAY_MS (1000)
+#endif
+
+#ifndef UDS_SERVER_DEFAULT_XFER_DATA_MAX_BLOCKLENGTH
+/*! ISO14229-1:2013 Table 396. This parameter is used by the requestDownload positive response
+message to inform the client how many data bytes (maxNumberOfBlockLength) to include in each
+TransferData request message from the client. */
+#define UDS_SERVER_DEFAULT_XFER_DATA_MAX_BLOCKLENGTH (UDS_TP_MTU)
+#endif
+
diff --git a/iso14229serverbufferedwriter.h b/src/iso14229serverbufferedwriter.h
similarity index 100%
rename from iso14229serverbufferedwriter.h
rename to src/iso14229serverbufferedwriter.h
diff --git a/src/server.c b/src/server.c
new file mode 100644
index 0000000..38146a7
--- /dev/null
+++ b/src/server.c
@@ -0,0 +1,944 @@
+#include "server.h"
+#include "config.h"
+#include "uds.h"
+#include "util.h"
+
+static inline uint8_t NegativeResponse(UDSReq_t *r, uint8_t response_code) {
+ r->send_buf[0] = 0x7F;
+ r->send_buf[1] = r->recv_buf[0];
+ r->send_buf[2] = response_code;
+ r->send_len = UDS_NEG_RESP_LEN;
+ return response_code;
+}
+
+static inline void NoResponse(UDSReq_t *r) { r->send_len = 0; }
+
+static uint8_t EmitEvent(UDSServer_t *srv, UDSServerEvent_t evt, void *data) {
+ if (srv->fn) {
+ return srv->fn(srv, evt, data);
+ } else {
+ UDS_DBG_PRINT("Unhandled UDSServerEvent %d, srv.fn not installed!\n", evt);
+ return kGeneralReject;
+ }
+}
+
+static uint8_t _0x10_DiagnosticSessionControl(UDSServer_t *srv, UDSReq_t *r) {
+ if (r->recv_len < UDS_0X10_REQ_LEN) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
+ }
+
+ uint8_t sessType = r->recv_buf[1] & 0x4F;
+
+ UDSDiagSessCtrlArgs_t args = {
+ .type = sessType,
+ .p2_ms = UDS_CLIENT_DEFAULT_P2_MS,
+ .p2_star_ms = UDS_CLIENT_DEFAULT_P2_STAR_MS,
+ };
+
+ uint8_t err = EmitEvent(srv, UDS_SRV_EVT_DiagSessCtrl, &args);
+
+ if (kPositiveResponse != err) {
+ return NegativeResponse(r, err);
+ }
+
+ srv->sessionType = sessType;
+
+ switch (sessType) {
+ case kDefaultSession:
+ break;
+ case kProgrammingSession:
+ case kExtendedDiagnostic:
+ default:
+ srv->s3_session_timeout_timer = UDSMillis() + srv->s3_ms;
+ break;
+ }
+
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_DIAGNOSTIC_SESSION_CONTROL);
+ r->send_buf[1] = sessType;
+
+ // UDS-1-2013: Table 29
+ // resolution: 1ms
+ r->send_buf[2] = args.p2_ms >> 8;
+ r->send_buf[3] = args.p2_ms;
+
+ // resolution: 10ms
+ r->send_buf[4] = (args.p2_star_ms / 10) >> 8;
+ r->send_buf[5] = args.p2_star_ms / 10;
+
+ r->send_len = UDS_0X10_RESP_LEN;
+ return kPositiveResponse;
+}
+
+static uint8_t _0x11_ECUReset(UDSServer_t *srv, UDSReq_t *r) {
+ uint8_t resetType = r->recv_buf[1] & 0x3F;
+
+ if (r->recv_len < UDS_0X11_REQ_MIN_LEN) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
+ }
+
+ UDSECUResetArgs_t args = {
+ .type = resetType,
+ .powerDownTimeMillis = UDS_SERVER_DEFAULT_POWER_DOWN_TIME_MS,
+ };
+
+ uint8_t err = EmitEvent(srv, UDS_SRV_EVT_EcuReset, &args);
+
+ if (kPositiveResponse == err) {
+ srv->notReadyToReceive = true;
+ srv->ecuResetScheduled = resetType;
+ srv->ecuResetTimer = UDSMillis() + args.powerDownTimeMillis;
+ } else {
+ return NegativeResponse(r, err);
+ }
+
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_ECU_RESET);
+ r->send_buf[1] = resetType;
+
+ if (kEnableRapidPowerShutDown == resetType) {
+ uint32_t powerDownTime = args.powerDownTimeMillis / 1000;
+ if (powerDownTime > 255) {
+ powerDownTime = 255;
+ }
+ r->send_buf[2] = powerDownTime;
+ r->send_len = UDS_0X11_RESP_BASE_LEN + 1;
+ } else {
+ r->send_len = UDS_0X11_RESP_BASE_LEN;
+ }
+ return kPositiveResponse;
+}
+
+static uint8_t safe_copy(UDSServer_t *srv, const void *src, uint16_t count) {
+ if (srv == NULL) {
+ return kGeneralReject;
+ }
+ UDSReq_t *r = (UDSReq_t *)&srv->r;
+ if (count <= r->send_buf_size - r->send_len) {
+ memmove(r->send_buf + r->send_len, src, count);
+ r->send_len += count;
+ return kPositiveResponse;
+ }
+ return kResponseTooLong;
+}
+
+static uint8_t _0x22_ReadDataByIdentifier(UDSServer_t *srv, UDSReq_t *r) {
+ uint8_t numDIDs;
+ uint16_t dataId = 0;
+ uint8_t ret = kPositiveResponse;
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_READ_DATA_BY_IDENTIFIER);
+ r->send_len = 1;
+
+ if (0 != (r->recv_len - 1) % sizeof(uint16_t)) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
+ }
+
+ numDIDs = r->recv_len / sizeof(uint16_t);
+
+ if (0 == numDIDs) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
+ }
+
+ for (int did = 0; did < numDIDs; did++) {
+ uint16_t idx = 1 + did * 2;
+ dataId = (r->recv_buf[idx] << 8) + r->recv_buf[idx + 1];
+
+ if (r->send_len + 3 > r->send_buf_size) {
+ return NegativeResponse(r, kResponseTooLong);
+ }
+ uint8_t *copylocation = r->send_buf + r->send_len;
+ copylocation[0] = dataId >> 8;
+ copylocation[1] = dataId;
+ r->send_len += 2;
+
+ UDSRDBIArgs_t args = {
+ .dataId = dataId,
+ .copy = safe_copy,
+ };
+
+ ret = EmitEvent(srv, UDS_SRV_EVT_ReadDataByIdent, &args);
+
+ if (kPositiveResponse != ret) {
+ return NegativeResponse(r, ret);
+ }
+ }
+ return kPositiveResponse;
+}
+
+/**
+ * @brief decode the addressAndLengthFormatIdentifier that appears in ReadMemoryByAddress (0x23),
+ * DynamicallyDefineDataIdentifier (0x2C), RequestDownload (0X34)
+ *
+ * @param srv
+ * @param buf pointer to addressAndDataLengthFormatIdentifier in recv_buf
+ * @param memoryAddress the decoded memory address
+ * @param memorySize the decoded memory size
+ * @return uint8_t
+ */
+static uint8_t decodeAddressAndLength(UDSReq_t *r, uint8_t *const buf, void **memoryAddress,
+ size_t *memorySize) {
+ assert(r);
+ assert(memoryAddress);
+ assert(memorySize);
+ long long unsigned int tmp = 0;
+ *memoryAddress = 0;
+ *memorySize = 0;
+
+ assert(buf >= r->recv_buf && buf <= r->recv_buf + sizeof(r->recv_buf));
+
+ if (r->recv_len < 3) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
+ }
+
+ uint8_t memorySizeLength = (buf[0] & 0xF0) >> 4;
+ uint8_t memoryAddressLength = buf[0] & 0x0F;
+
+ if (memorySizeLength == 0 || memorySizeLength > sizeof(size_t)) {
+ return NegativeResponse(r, kRequestOutOfRange);
+ }
+
+ if (memoryAddressLength == 0 || memoryAddressLength > sizeof(size_t)) {
+ return NegativeResponse(r, kRequestOutOfRange);
+ }
+
+ if (buf + memorySizeLength + memoryAddressLength > r->recv_buf + r->recv_len) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
+ }
+
+ for (int byteIdx = 0; byteIdx < memoryAddressLength; byteIdx++) {
+ long long unsigned int byte = buf[1 + byteIdx];
+ uint8_t shiftBytes = memoryAddressLength - 1 - byteIdx;
+ tmp |= byte << (8 * shiftBytes);
+ }
+ *memoryAddress = (void *)tmp;
+
+ for (int byteIdx = 0; byteIdx < memorySizeLength; byteIdx++) {
+ uint8_t byte = buf[1 + memoryAddressLength + byteIdx];
+ uint8_t shiftBytes = memorySizeLength - 1 - byteIdx;
+ *memorySize |= (size_t)byte << (8 * shiftBytes);
+ }
+ return kPositiveResponse;
+}
+
+static uint8_t _0x23_ReadMemoryByAddress(UDSServer_t *srv, UDSReq_t *r) {
+ uint8_t ret = kPositiveResponse;
+ void *address = 0;
+ size_t length = 0;
+
+ if (r->recv_len < UDS_0X23_REQ_MIN_LEN) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
+ }
+
+ ret = decodeAddressAndLength(r, &r->recv_buf[1], &address, &length);
+ if (kPositiveResponse != ret) {
+ return NegativeResponse(r, ret);
+ }
+
+ UDSReadMemByAddrArgs_t args = {
+ .memAddr = address,
+ .memSize = length,
+ .copy = safe_copy,
+ };
+
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_READ_MEMORY_BY_ADDRESS);
+ r->send_len = UDS_0X23_RESP_BASE_LEN;
+ ret = EmitEvent(srv, UDS_SRV_EVT_ReadMemByAddr, &args);
+ if (kPositiveResponse != ret) {
+ return NegativeResponse(r, ret);
+ }
+ if (r->send_len != UDS_0X23_RESP_BASE_LEN + length) {
+ return kGeneralProgrammingFailure;
+ }
+ return kPositiveResponse;
+}
+
+static uint8_t _0x27_SecurityAccess(UDSServer_t *srv, UDSReq_t *r) {
+ uint8_t subFunction = r->recv_buf[1];
+ uint8_t response = kPositiveResponse;
+
+ if (UDSSecurityAccessLevelIsReserved(subFunction)) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
+ }
+
+ if (!UDSTimeAfter(UDSMillis(), UDS_SERVER_0x27_BRUTE_FORCE_MITIGATION_BOOT_DELAY_MS)) {
+ return NegativeResponse(r, kRequiredTimeDelayNotExpired);
+ }
+
+ if (!(UDSTimeAfter(UDSMillis(), srv->sec_access_auth_fail_timer))) {
+ return NegativeResponse(r, kExceedNumberOfAttempts);
+ }
+
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_SECURITY_ACCESS);
+ r->send_buf[1] = subFunction;
+ r->send_len = UDS_0X27_RESP_BASE_LEN;
+
+ // Even: sendKey
+ if (0 == subFunction % 2) {
+ uint8_t requestedLevel = subFunction - 1;
+ UDSSecAccessValidateKeyArgs_t args = {
+ .level = requestedLevel,
+ .key = &r->recv_buf[UDS_0X27_REQ_BASE_LEN],
+ .len = r->recv_len - UDS_0X27_REQ_BASE_LEN,
+ };
+
+ response = EmitEvent(srv, UDS_SRV_EVT_SecAccessValidateKey, &args);
+
+ if (kPositiveResponse != response) {
+ srv->sec_access_auth_fail_timer = UDSMillis() + UDS_SERVER_0x27_BRUTE_FORCE_MITIGATION_AUTH_FAIL_DELAY_MS;
+ return NegativeResponse(r, response);
+ }
+
+ // "requestSeed = 0x01" identifies a fixed relationship between
+ // "requestSeed = 0x01" and "sendKey = 0x02"
+ // "requestSeed = 0x03" identifies a fixed relationship between
+ // "requestSeed = 0x03" and "sendKey = 0x04"
+ srv->securityLevel = requestedLevel;
+ r->send_len = UDS_0X27_RESP_BASE_LEN;
+ return kPositiveResponse;
+ }
+
+ // Odd: requestSeed
+ else {
+ /* If a server supports security, but the requested security level is already unlocked when
+ a SecurityAccess ‘requestSeed’ message is received, that server shall respond with a
+ SecurityAccess ‘requestSeed’ positive response message service with a seed value equal to
+ zero (0). The server shall never send an all zero seed for a given security level that is
+ currently locked. The client shall use this method to determine if a server is locked for a
+ particular security level by checking for a non-zero seed.
+ */
+ if (subFunction == srv->securityLevel) {
+ // Table 52 sends a response of length 2. Use a preprocessor define if this needs
+ // customizing by the user.
+ const uint8_t already_unlocked[] = {0x00, 0x00};
+ return safe_copy(srv, already_unlocked, sizeof(already_unlocked));
+ } else {
+ UDSSecAccessRequestSeedArgs_t args = {
+ .level = subFunction,
+ .dataRecord = &r->recv_buf[UDS_0X27_REQ_BASE_LEN],
+ .len = r->recv_len - UDS_0X27_REQ_BASE_LEN,
+ .copySeed = safe_copy,
+ };
+
+ response = EmitEvent(srv, UDS_SRV_EVT_SecAccessRequestSeed, &args);
+
+ if (kPositiveResponse != response) {
+ return NegativeResponse(r, response);
+ }
+
+ if (r->send_len <= UDS_0X27_RESP_BASE_LEN) { // no data was copied
+ return NegativeResponse(r, kGeneralProgrammingFailure);
+ }
+ return kPositiveResponse;
+ }
+ }
+ return NegativeResponse(r, kGeneralProgrammingFailure);
+}
+
+static uint8_t _0x28_CommunicationControl(UDSServer_t *srv, UDSReq_t *r) {
+ uint8_t controlType = r->recv_buf[1] & 0x7F;
+ uint8_t communicationType = r->recv_buf[2];
+
+ if (r->recv_len < UDS_0X28_REQ_BASE_LEN) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
+ }
+
+ UDSCommCtrlArgs_t args = {
+ .ctrlType = controlType,
+ .commType = communicationType,
+ };
+
+ uint8_t err = EmitEvent(srv, UDS_SRV_EVT_CommCtrl, &args);
+ if (kPositiveResponse != err) {
+ return NegativeResponse(r, err);
+ }
+
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_COMMUNICATION_CONTROL);
+ r->send_buf[1] = controlType;
+ r->send_len = UDS_0X28_RESP_LEN;
+ return kPositiveResponse;
+}
+
+static uint8_t _0x2E_WriteDataByIdentifier(UDSServer_t *srv, UDSReq_t *r) {
+ uint16_t dataLen = 0;
+ uint16_t dataId = 0;
+ uint8_t err = kPositiveResponse;
+
+ /* UDS-1 2013 Figure 21 Key 1 */
+ if (r->recv_len < UDS_0X2E_REQ_MIN_LEN) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
+ }
+
+ dataId = (r->recv_buf[1] << 8) + r->recv_buf[2];
+ dataLen = r->recv_len - UDS_0X2E_REQ_BASE_LEN;
+
+ UDSWDBIArgs_t args = {
+ .dataId = dataId,
+ .data = &r->recv_buf[UDS_0X2E_REQ_BASE_LEN],
+ .len = dataLen,
+ };
+
+ err = EmitEvent(srv, UDS_SRV_EVT_WriteDataByIdent, &args);
+ if (kPositiveResponse != err) {
+ return NegativeResponse(r, err);
+ }
+
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_WRITE_DATA_BY_IDENTIFIER);
+ r->send_buf[1] = dataId >> 8;
+ r->send_buf[2] = dataId;
+ r->send_len = UDS_0X2E_RESP_LEN;
+ return kPositiveResponse;
+}
+
+static uint8_t _0x31_RoutineControl(UDSServer_t *srv, UDSReq_t *r) {
+ uint8_t err = kPositiveResponse;
+ if (r->recv_len < UDS_0X31_REQ_MIN_LEN) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
+ }
+
+ uint8_t routineControlType = r->recv_buf[1] & 0x7F;
+ uint16_t routineIdentifier = (r->recv_buf[2] << 8) + r->recv_buf[3];
+
+ UDSRoutineCtrlArgs_t args = {
+ .ctrlType = routineControlType,
+ .id = routineIdentifier,
+ .optionRecord = &r->recv_buf[UDS_0X31_REQ_MIN_LEN],
+ .len = r->recv_len - UDS_0X31_REQ_MIN_LEN,
+ .copyStatusRecord = safe_copy,
+ };
+
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_ROUTINE_CONTROL);
+ r->send_buf[1] = routineControlType;
+ r->send_buf[2] = routineIdentifier >> 8;
+ r->send_buf[3] = routineIdentifier;
+ r->send_len = UDS_0X31_RESP_MIN_LEN;
+
+ switch (routineControlType) {
+ case kStartRoutine:
+ case kStopRoutine:
+ case kRequestRoutineResults:
+ err = EmitEvent(srv, UDS_SRV_EVT_RoutineCtrl, &args);
+ if (kPositiveResponse != err) {
+ return NegativeResponse(r, err);
+ }
+ break;
+ default:
+ return NegativeResponse(r, kRequestOutOfRange);
+ }
+ return kPositiveResponse;
+}
+
+static void ResetTransfer(UDSServer_t *srv) {
+ assert(srv);
+ srv->xferBlockSequenceCounter = 1;
+ srv->xferByteCounter = 0;
+ srv->xferTotalBytes = 0;
+ srv->xferIsActive = false;
+}
+
+static uint8_t _0x34_RequestDownload(UDSServer_t *srv, UDSReq_t *r) {
+ uint8_t err;
+ void *memoryAddress = 0;
+ size_t memorySize = 0;
+
+ if (srv->xferIsActive) {
+ return NegativeResponse(r, kConditionsNotCorrect);
+ }
+
+ if (r->recv_len < UDS_0X34_REQ_BASE_LEN) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
+ }
+
+ err = decodeAddressAndLength(r, &r->recv_buf[2], &memoryAddress, &memorySize);
+ if (kPositiveResponse != err) {
+ return NegativeResponse(r, err);
+ }
+
+ UDSRequestDownloadArgs_t args = {
+ .addr = memoryAddress,
+ .size = memorySize,
+ .dataFormatIdentifier = r->recv_buf[1],
+ .maxNumberOfBlockLength = UDS_SERVER_DEFAULT_XFER_DATA_MAX_BLOCKLENGTH,
+ };
+
+ err = EmitEvent(srv, UDS_SRV_EVT_RequestDownload, &args);
+
+ if (args.maxNumberOfBlockLength < 3) {
+ UDS_DBG_PRINT("ERROR: maxNumberOfBlockLength too short");
+ return NegativeResponse(r, kGeneralProgrammingFailure);
+ }
+
+ if (kPositiveResponse != err) {
+ return NegativeResponse(r, err);
+ }
+
+ ResetTransfer(srv);
+ srv->xferIsActive = true;
+ srv->xferTotalBytes = memorySize;
+ srv->xferBlockLength = args.maxNumberOfBlockLength;
+
+ // ISO-14229-1:2013 Table 401:
+ uint8_t lengthFormatIdentifier = sizeof(args.maxNumberOfBlockLength) << 4;
+
+ /* ISO-14229-1:2013 Table 396: maxNumberOfBlockLength
+ This parameter is used by the requestDownload positive response message to
+ inform the client how many data bytes (maxNumberOfBlockLength) to include in
+ each TransferData request message from the client. This length reflects the
+ complete message length, including the service identifier and the
+ data-parameters present in the TransferData request message.
+ */
+ if (args.maxNumberOfBlockLength > UDS_TP_MTU) {
+ args.maxNumberOfBlockLength = UDS_TP_MTU;
+ }
+
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_REQUEST_DOWNLOAD);
+ r->send_buf[1] = lengthFormatIdentifier;
+ for (uint8_t idx = 0; idx < sizeof(args.maxNumberOfBlockLength); idx++) {
+ uint8_t shiftBytes = sizeof(args.maxNumberOfBlockLength) - 1 - idx;
+ uint8_t byte = args.maxNumberOfBlockLength >> (shiftBytes * 8);
+ r->send_buf[UDS_0X34_RESP_BASE_LEN + idx] = byte;
+ }
+ r->send_len = UDS_0X34_RESP_BASE_LEN + sizeof(args.maxNumberOfBlockLength);
+ return kPositiveResponse;
+}
+
+static uint8_t _0x35_RequestUpload(UDSServer_t *srv, UDSReq_t *r) {
+ uint8_t err;
+ void *memoryAddress = 0;
+ size_t memorySize = 0;
+
+ if (srv->xferIsActive) {
+ return NegativeResponse(r, kConditionsNotCorrect);
+ }
+
+ if (r->recv_len < UDS_0X35_REQ_BASE_LEN) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
+ }
+
+ err = decodeAddressAndLength(r, &r->recv_buf[2], &memoryAddress, &memorySize);
+ if (kPositiveResponse != err) {
+ return NegativeResponse(r, err);
+ }
+
+ UDSRequestUploadArgs_t args = {
+ .addr = memoryAddress,
+ .size = memorySize,
+ .dataFormatIdentifier = r->recv_buf[1],
+ .maxNumberOfBlockLength = UDS_SERVER_DEFAULT_XFER_DATA_MAX_BLOCKLENGTH,
+ };
+
+ err = EmitEvent(srv, UDS_SRV_EVT_RequestUpload, &args);
+
+ if (args.maxNumberOfBlockLength < 3) {
+ UDS_DBG_PRINT("ERROR: maxNumberOfBlockLength too short");
+ return NegativeResponse(r, kGeneralProgrammingFailure);
+ }
+
+ if (kPositiveResponse != err) {
+ return NegativeResponse(r, err);
+ }
+
+ ResetTransfer(srv);
+ srv->xferIsActive = true;
+ srv->xferTotalBytes = memorySize;
+ srv->xferBlockLength = args.maxNumberOfBlockLength;
+
+ uint8_t lengthFormatIdentifier = sizeof(args.maxNumberOfBlockLength) << 4;
+
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_REQUEST_UPLOAD);
+ r->send_buf[1] = lengthFormatIdentifier;
+ for (uint8_t idx = 0; idx < sizeof(args.maxNumberOfBlockLength); idx++) {
+ uint8_t shiftBytes = sizeof(args.maxNumberOfBlockLength) - 1 - idx;
+ uint8_t byte = args.maxNumberOfBlockLength >> (shiftBytes * 8);
+ r->send_buf[UDS_0X35_RESP_BASE_LEN + idx] = byte;
+ }
+ r->send_len = UDS_0X35_RESP_BASE_LEN + sizeof(args.maxNumberOfBlockLength);
+ return kPositiveResponse;
+}
+
+static uint8_t _0x36_TransferData(UDSServer_t *srv, UDSReq_t *r) {
+ uint8_t err = kPositiveResponse;
+ uint16_t request_data_len = r->recv_len - UDS_0X36_REQ_BASE_LEN;
+ uint8_t blockSequenceCounter = 0;
+
+ if (!srv->xferIsActive) {
+ return NegativeResponse(r, kUploadDownloadNotAccepted);
+ }
+
+ if (r->recv_len < UDS_0X36_REQ_BASE_LEN) {
+ err = kIncorrectMessageLengthOrInvalidFormat;
+ goto fail;
+ }
+
+ blockSequenceCounter = r->recv_buf[1];
+
+ if (!srv->RCRRP) {
+ if (blockSequenceCounter != srv->xferBlockSequenceCounter) {
+ err = kRequestSequenceError;
+ goto fail;
+ } else {
+ srv->xferBlockSequenceCounter++;
+ }
+ }
+
+ if (srv->xferByteCounter + request_data_len > srv->xferTotalBytes) {
+ err = kTransferDataSuspended;
+ goto fail;
+ }
+
+ {
+ UDSTransferDataArgs_t args = {
+ .data = &r->recv_buf[UDS_0X36_REQ_BASE_LEN],
+ .len = r->recv_len - UDS_0X36_REQ_BASE_LEN,
+ .maxRespLen = srv->xferBlockLength - UDS_0X36_RESP_BASE_LEN,
+ .copyResponse = safe_copy,
+ };
+
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_TRANSFER_DATA);
+ r->send_buf[1] = blockSequenceCounter;
+ r->send_len = UDS_0X36_RESP_BASE_LEN;
+
+ err = EmitEvent(srv, UDS_SRV_EVT_TransferData, &args);
+
+ switch (err) {
+ case kPositiveResponse:
+ srv->xferByteCounter += request_data_len;
+ return kPositiveResponse;
+ case kRequestCorrectlyReceived_ResponsePending:
+ return NegativeResponse(r, kRequestCorrectlyReceived_ResponsePending);
+ default:
+ goto fail;
+ }
+ }
+
+fail:
+ ResetTransfer(srv);
+ return NegativeResponse(r, err);
+}
+
+static uint8_t _0x37_RequestTransferExit(UDSServer_t *srv, UDSReq_t *r) {
+ uint8_t err = kPositiveResponse;
+
+ if (!srv->xferIsActive) {
+ return NegativeResponse(r, kUploadDownloadNotAccepted);
+ }
+
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_REQUEST_TRANSFER_EXIT);
+ r->send_len = UDS_0X37_RESP_BASE_LEN;
+
+ UDSRequestTransferExitArgs_t args = {
+ .data = &r->recv_buf[UDS_0X37_REQ_BASE_LEN],
+ .len = r->recv_len - UDS_0X37_REQ_BASE_LEN,
+ .copyResponse = safe_copy,
+ };
+
+ err = EmitEvent(srv, UDS_SRV_EVT_RequestTransferExit, &args);
+
+ switch (err) {
+ case kPositiveResponse:
+ ResetTransfer(srv);
+ return kPositiveResponse;
+ case kRequestCorrectlyReceived_ResponsePending:
+ return NegativeResponse(r, kRequestCorrectlyReceived_ResponsePending);
+ default:
+ ResetTransfer(srv);
+ return NegativeResponse(r, err);
+ }
+}
+
+static uint8_t _0x3E_TesterPresent(UDSServer_t *srv, UDSReq_t *r) {
+ if ((r->recv_len < UDS_0X3E_REQ_MIN_LEN) || (r->recv_len > UDS_0X3E_REQ_MAX_LEN)) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
+ }
+ uint8_t zeroSubFunction = r->recv_buf[1];
+
+ switch (zeroSubFunction) {
+ case 0x00:
+ case 0x80:
+ srv->s3_session_timeout_timer = UDSMillis() + srv->s3_ms;
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_TESTER_PRESENT);
+ r->send_buf[1] = 0x00;
+ r->send_len = UDS_0X3E_RESP_LEN;
+ return kPositiveResponse;
+ default:
+ return NegativeResponse(r, kSubFunctionNotSupported);
+ }
+}
+
+static uint8_t _0x85_ControlDTCSetting(UDSServer_t *srv, UDSReq_t *r) {
+ if (r->recv_len < UDS_0X85_REQ_BASE_LEN) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
+ }
+ uint8_t dtcSettingType = r->recv_buf[1] & 0x3F;
+
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_CONTROL_DTC_SETTING);
+ r->send_buf[1] = dtcSettingType;
+ r->send_len = UDS_0X85_RESP_LEN;
+ return kPositiveResponse;
+}
+
+typedef uint8_t (*UDSService)(UDSServer_t *srv, UDSReq_t *r);
+
+/**
+ * @brief Get the internal service handler matching the given SID.
+ * @param sid
+ * @return pointer to UDSService or NULL if no match
+ */
+static UDSService getServiceForSID(uint8_t sid) {
+ switch (sid) {
+ case kSID_DIAGNOSTIC_SESSION_CONTROL:
+ return _0x10_DiagnosticSessionControl;
+ case kSID_ECU_RESET:
+ return _0x11_ECUReset;
+ case kSID_CLEAR_DIAGNOSTIC_INFORMATION:
+ return NULL;
+ case kSID_READ_DTC_INFORMATION:
+ return NULL;
+ case kSID_READ_DATA_BY_IDENTIFIER:
+ return _0x22_ReadDataByIdentifier;
+ case kSID_READ_MEMORY_BY_ADDRESS:
+ return _0x23_ReadMemoryByAddress;
+ case kSID_READ_SCALING_DATA_BY_IDENTIFIER:
+ return NULL;
+ case kSID_SECURITY_ACCESS:
+ return _0x27_SecurityAccess;
+ case kSID_COMMUNICATION_CONTROL:
+ return _0x28_CommunicationControl;
+ case kSID_READ_PERIODIC_DATA_BY_IDENTIFIER:
+ return NULL;
+ case kSID_DYNAMICALLY_DEFINE_DATA_IDENTIFIER:
+ return NULL;
+ case kSID_WRITE_DATA_BY_IDENTIFIER:
+ return _0x2E_WriteDataByIdentifier;
+ case kSID_INPUT_CONTROL_BY_IDENTIFIER:
+ return NULL;
+ case kSID_ROUTINE_CONTROL:
+ return _0x31_RoutineControl;
+ case kSID_REQUEST_DOWNLOAD:
+ return _0x34_RequestDownload;
+ case kSID_REQUEST_UPLOAD:
+ return _0x35_RequestUpload;
+ case kSID_TRANSFER_DATA:
+ return _0x36_TransferData;
+ case kSID_REQUEST_TRANSFER_EXIT:
+ return _0x37_RequestTransferExit;
+ case kSID_REQUEST_FILE_TRANSFER:
+ return NULL;
+ case kSID_WRITE_MEMORY_BY_ADDRESS:
+ return NULL;
+ case kSID_TESTER_PRESENT:
+ return _0x3E_TesterPresent;
+ case kSID_ACCESS_TIMING_PARAMETER:
+ return NULL;
+ case kSID_SECURED_DATA_TRANSMISSION:
+ return NULL;
+ case kSID_CONTROL_DTC_SETTING:
+ return _0x85_ControlDTCSetting;
+ case kSID_RESPONSE_ON_EVENT:
+ return NULL;
+ default:
+ UDS_DBG_PRINT("no handler for request SID %x.\n", sid);
+ return NULL;
+ }
+}
+
+/**
+ * @brief Call the service if it exists, modifying the response if the spec calls for it.
+ * @note see UDS-1 2013 7.5.5 Pseudo code example of server response behavior
+ *
+ * @param srv
+ * @param addressingScheme
+ */
+static uint8_t evaluateServiceResponse(UDSServer_t *srv, UDSReq_t *r) {
+ uint8_t response = kPositiveResponse;
+ bool suppressResponse = false;
+ uint8_t sid = r->recv_buf[0];
+ UDSService service = getServiceForSID(sid);
+
+ if (NULL == service || NULL == srv->fn) {
+ return NegativeResponse(r, kServiceNotSupported);
+ }
+ assert(service);
+ assert(srv->fn); // service handler functions will call srv->fn. it must be valid
+
+ switch (sid) {
+ /* CASE Service_with_sub-function */
+ /* test if service with sub-function is supported */
+ case kSID_DIAGNOSTIC_SESSION_CONTROL:
+ case kSID_ECU_RESET:
+ case kSID_SECURITY_ACCESS:
+ case kSID_COMMUNICATION_CONTROL:
+ case kSID_ROUTINE_CONTROL:
+ case kSID_TESTER_PRESENT:
+ case kSID_CONTROL_DTC_SETTING: {
+ response = service(srv, r);
+
+ bool suppressPosRspMsgIndicationBit = r->recv_buf[1] & 0x80;
+
+ /* test if positive response is required and if responseCode is positive 0x00 */
+ if ((suppressPosRspMsgIndicationBit) && (response == kPositiveResponse) &&
+ (
+ // TODO: *not yet a NRC 0x78 response sent*
+ true)) {
+ suppressResponse = true;
+ } else {
+ suppressResponse = false;
+ }
+ break;
+ }
+
+ /* CASE Service_without_sub-function */
+ /* test if service without sub-function is supported */
+ case kSID_READ_DATA_BY_IDENTIFIER:
+ case kSID_READ_MEMORY_BY_ADDRESS:
+ case kSID_WRITE_DATA_BY_IDENTIFIER:
+ case kSID_REQUEST_DOWNLOAD:
+ case kSID_REQUEST_UPLOAD:
+ case kSID_TRANSFER_DATA:
+ case kSID_REQUEST_TRANSFER_EXIT: {
+ response = service(srv, r);
+ break;
+ }
+
+ /* CASE Service_not_implemented */
+ /* shouldn't get this far as getServiceForSID(sid) will return NULL*/
+ case kSID_CLEAR_DIAGNOSTIC_INFORMATION:
+ case kSID_READ_DTC_INFORMATION:
+ case kSID_READ_SCALING_DATA_BY_IDENTIFIER:
+ case kSID_READ_PERIODIC_DATA_BY_IDENTIFIER:
+ case kSID_DYNAMICALLY_DEFINE_DATA_IDENTIFIER:
+ case kSID_INPUT_CONTROL_BY_IDENTIFIER:
+ case kSID_REQUEST_FILE_TRANSFER:
+ case kSID_WRITE_MEMORY_BY_ADDRESS:
+ case kSID_ACCESS_TIMING_PARAMETER:
+ case kSID_SECURED_DATA_TRANSMISSION:
+ case kSID_RESPONSE_ON_EVENT:
+ default: {
+ response = kServiceNotSupported;
+ break;
+ }
+ }
+
+ if ((UDS_A_TA_TYPE_FUNCTIONAL == r->info.A_TA_Type) &&
+ ((kServiceNotSupported == response) || (kSubFunctionNotSupported == response) ||
+ (kServiceNotSupportedInActiveSession == response) ||
+ (kSubFunctionNotSupportedInActiveSession == response) ||
+ (kRequestOutOfRange == response)) &&
+ (
+ // TODO: *not yet a NRC 0x78 response sent*
+ true)) {
+ suppressResponse = true; /* Suppress negative response message */
+ NoResponse(r);
+ } else {
+ if (suppressResponse) { /* Suppress positive response message */
+ NoResponse(r);
+ } else { /* send negative or positive response */
+ ;
+ }
+ }
+ return response;
+}
+
+// ========================================================================
+// Public Functions
+// ========================================================================
+
+/**
+ * @brief \~chinese 初始化服务器 \~english Initialize the server
+ *
+ * @param srv
+ * @param cfg
+ * @return int
+ */
+UDSErr_t UDSServerInit(UDSServer_t *srv) {
+ assert(srv);
+ memset(srv, 0, sizeof(UDSServer_t));
+ srv->p2_ms = UDS_SERVER_DEFAULT_P2_MS;
+ srv->p2_star_ms = UDS_SERVER_DEFAULT_P2_STAR_MS;
+ srv->s3_ms = UDS_SERVER_DEFAULT_S3_MS;
+ srv->sessionType = kDefaultSession;
+ srv->p2_timer = UDSMillis() + srv->p2_ms;
+ srv->s3_session_timeout_timer = UDSMillis() + srv->s3_ms;
+ return UDS_OK;
+}
+
+void UDSServerPoll(UDSServer_t *srv) {
+ // UDS-1-2013 Figure 38: Session Timeout (S3)
+ if (kDefaultSession != srv->sessionType &&
+ UDSTimeAfter(UDSMillis(), srv->s3_session_timeout_timer)) {
+ EmitEvent(srv, UDS_SRV_EVT_SessionTimeout, NULL);
+ }
+
+ if (srv->ecuResetScheduled && UDSTimeAfter(UDSMillis(), srv->ecuResetTimer)) {
+ EmitEvent(srv, UDS_SRV_EVT_DoScheduledReset, &srv->ecuResetScheduled);
+ }
+
+ UDSTpStatus_t tpStatus = UDSTpPoll(srv->tp);
+
+ UDSReq_t *r = &srv->r;
+
+ if (srv->requestInProgress) {
+ if (srv->RCRRP) {
+ // responds only if
+ // 1. changed (no longer RCRRP), or
+ // 2. p2_timer has elapsed
+ uint8_t response = evaluateServiceResponse(srv, r);
+ if (kRequestCorrectlyReceived_ResponsePending == response) {
+ // it's the second time the service has responded with RCRRP
+ srv->notReadyToReceive = true;
+ } else {
+ // No longer RCRRP'ing
+ srv->RCRRP = false;
+ srv->notReadyToReceive = false;
+
+ // Not a consecutive 0x78 response, use p2 instead of p2_star * 0.3
+ srv->p2_timer = UDSMillis() + srv->p2_ms;
+ }
+ }
+
+ if (UDSTimeAfter(UDSMillis(), srv->p2_timer)) {
+ printf("len: %zu\n", r->send_len);
+ ssize_t ret = UDSTpSend(srv->tp, r->send_buf, r->send_len, NULL);
+ // TODO test injection of transport errors:
+ if (ret < 0) {
+ UDSErr_t err = UDS_ERR_TPORT;
+ EmitEvent(srv, UDS_SRV_EVT_Err, &err);
+ UDS_DBG_PRINT("UDSTpSend failed with %zd\n", ret);
+ }
+
+ if (srv->RCRRP) {
+ // ISO14229-2:2013 Table 4 footnote b
+ // min time between consecutive 0x78 responses is 0.3 * p2*
+ uint32_t wait_time = srv->p2_star_ms * 3 / 10;
+ srv->p2_timer = UDSMillis() + wait_time;
+ } else {
+ srv->p2_timer = UDSMillis() + srv->p2_ms;
+ UDSTpAckRecv(srv->tp);
+ srv->requestInProgress = false;
+ }
+ }
+
+ } else {
+ if (srv->notReadyToReceive) {
+ return; // cannot respond to request right now
+ }
+ r->recv_len = UDSTpPeek(srv->tp, &r->recv_buf, &r->info);
+ r->send_buf_size = UDSTpGetSendBuf(srv->tp, &r->send_buf);
+ if (r->recv_len > 0) {
+ if (r->send_buf == NULL) {
+ UDS_DBG_PRINT("Send buf null\n");
+ }
+ if (r->recv_buf == NULL) {
+ UDS_DBG_PRINT("Recv buf null\n");
+ }
+ if (r->send_buf == NULL || r->recv_buf == NULL) {
+ UDSErr_t err = UDS_ERR_TPORT;
+ EmitEvent(srv, UDS_SRV_EVT_Err, &err);
+ UDS_DBG_PRINT("bad tport\n");
+ return;
+ }
+ uint8_t response = evaluateServiceResponse(srv, r);
+ srv->requestInProgress = true;
+ if (kRequestCorrectlyReceived_ResponsePending == response) {
+ srv->RCRRP = true;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/server.h b/src/server.h
new file mode 100644
index 0000000..a741232
--- /dev/null
+++ b/src/server.h
@@ -0,0 +1,169 @@
+#pragma once
+
+#include "sys.h"
+#include "tp.h"
+#include "uds.h"
+
+/**
+ * @brief Server request context
+ */
+typedef struct {
+ uint8_t *recv_buf;
+ uint8_t *send_buf;
+ size_t recv_len;
+ size_t send_len;
+ size_t send_buf_size;
+ UDSSDU_t info;
+} UDSReq_t;
+
+typedef struct UDSServer {
+ UDSTpHandle_t *tp;
+ uint8_t (*fn)(struct UDSServer *srv, UDSServerEvent_t event, const void *arg);
+
+ /**
+ * @brief \~chinese 服务器时间参数(毫秒) \~ Server time constants (milliseconds) \~
+ */
+ uint16_t p2_ms; // Default P2_server_max timing supported by the server for
+ // the activated diagnostic session.
+ uint32_t p2_star_ms; // Enhanced (NRC 0x78) P2_server_max supported by the
+ // server for the activated diagnostic session.
+ uint16_t s3_ms; // Session timeout
+
+ uint8_t ecuResetScheduled; // nonzero indicates that an ECUReset has been scheduled
+ uint32_t ecuResetTimer; // for delaying resetting until a response
+ // has been sent to the client
+ uint32_t p2_timer; // for rate limiting server responses
+ uint32_t s3_session_timeout_timer; // indicates that diagnostic session has timed out
+ uint32_t sec_access_auth_fail_timer; // brute-force hardening: rate limit security access requests
+
+ /**
+ * @brief UDS-1-2013: Table 407 - 0x36 TransferData Supported negative
+ * response codes requires that the server keep track of whether the
+ * transfer is active
+ */
+ bool xferIsActive;
+ // UDS-1-2013: 14.4.2.3, Table 404: The blockSequenceCounter parameter
+ // value starts at 0x01
+ uint8_t xferBlockSequenceCounter;
+ size_t xferTotalBytes; // total transfer size in bytes requested by the client
+ size_t xferByteCounter; // total number of bytes transferred
+ size_t xferBlockLength; // block length (convenience for the TransferData API)
+
+ uint8_t sessionType; // diagnostic session type (0x10)
+ uint8_t securityLevel; // SecurityAccess (0x27) level
+
+ bool RCRRP; // set to true when user fn returns 0x78 and false otherwise
+ bool requestInProgress; // set to true when a request has been processed but the response has
+ // not yet been sent
+
+ // UDS-1 2013 defines the following conditions under which the server does not
+ // process incoming requests:
+ // - not ready to receive (Table A.1 0x78)
+ // - not accepting request messages and not sending responses (9.3.1)
+ //
+ // when this variable is set to true, incoming ISO-TP data will not be processed.
+ bool notReadyToReceive;
+
+ UDSReq_t r;
+} UDSServer_t;
+
+// TODO: Remove
+typedef struct {
+ uint8_t (*fn)(UDSServer_t *srv, UDSServerEvent_t event, const void *arg);
+ UDSTpHandle_t *tp;
+} UDSServerConfig_t;
+
+typedef struct {
+ const uint8_t type; /*! requested diagnostic session type (enum UDSDiagnosticSessionType) */
+ uint16_t p2_ms; /*! optional: p2 timing override */
+ uint32_t p2_star_ms; /*! optional: p2* timing override */
+} UDSDiagSessCtrlArgs_t;
+
+typedef struct {
+ const uint8_t type; /**< \~chinese 客户端请求的复位类型 \~english reset type requested by client
+ (enum UDSECUResetType) */
+ uint32_t powerDownTimeMillis; /**< when this much time has elapsed after a kPositiveResponse, a
+ UDS_SRV_EVT_DoScheduledReset will be issued */
+} UDSECUResetArgs_t;
+
+typedef struct {
+ const uint16_t dataId; /*! RDBI Data Identifier */
+ uint8_t (*copy)(UDSServer_t *srv, const void *src,
+ uint16_t count); /*! function for copying data */
+} UDSRDBIArgs_t;
+
+typedef struct {
+ const void *memAddr;
+ const size_t memSize;
+ uint8_t (*copy)(UDSServer_t *srv, const void *src,
+ uint16_t count); /*! function for copying data */
+} UDSReadMemByAddrArgs_t;
+
+typedef struct {
+ uint8_t ctrlType; /* enum UDSCommunicationControlType */
+ uint8_t commType; /* enum UDSCommunicationType */
+} UDSCommCtrlArgs_t;
+
+typedef struct {
+ const uint8_t level; /*! requested security level */
+ const uint8_t *const dataRecord; /*! pointer to request data */
+ const uint16_t len; /*! size of request data */
+ uint8_t (*copySeed)(UDSServer_t *srv, const void *src,
+ uint16_t len); /*! function for copying data */
+} UDSSecAccessRequestSeedArgs_t;
+
+typedef struct {
+ const uint8_t level; /*! security level to be validated */
+ const uint8_t *const key; /*! key sent by client */
+ const uint16_t len; /*! length of key */
+} UDSSecAccessValidateKeyArgs_t;
+
+typedef struct {
+ const uint16_t dataId; /*! WDBI Data Identifier */
+ const uint8_t *const data; /*! pointer to data */
+ const uint16_t len; /*! length of data */
+} UDSWDBIArgs_t;
+
+typedef struct {
+ const uint8_t ctrlType; /*! routineControlType */
+ const uint16_t id; /*! routineIdentifier */
+ const uint8_t *optionRecord; /*! optional data */
+ const uint16_t len; /*! length of optional data */
+ uint8_t (*copyStatusRecord)(UDSServer_t *srv, const void *src,
+ uint16_t len); /*! function for copying response data */
+} UDSRoutineCtrlArgs_t;
+
+typedef struct {
+ const void *addr; /*! requested address */
+ const size_t size; /*! requested download size */
+ const uint8_t dataFormatIdentifier; /*! optional specifier for format of data */
+ uint16_t maxNumberOfBlockLength; /*! optional response: inform client how many data bytes to
+ send in each `TransferData` request */
+} UDSRequestDownloadArgs_t;
+
+typedef struct {
+ const void *addr; /*! requested address */
+ const size_t size; /*! requested download size */
+ const uint8_t dataFormatIdentifier; /*! optional specifier for format of data */
+ uint16_t maxNumberOfBlockLength; /*! optional response: inform client how many data bytes to
+ send in each `TransferData` request */
+} UDSRequestUploadArgs_t;
+
+typedef struct {
+ const uint8_t *const data; /*! transfer data */
+ const uint16_t len; /*! transfer data length */
+ const uint16_t maxRespLen; /*! don't send more than this many bytes with copyResponse */
+ uint8_t (*copyResponse)(
+ UDSServer_t *srv, const void *src,
+ uint16_t len); /*! function for copying transfer data response data (optional) */
+} UDSTransferDataArgs_t;
+
+typedef struct {
+ const uint8_t *const data; /*! request data */
+ const uint16_t len; /*! request data length */
+ uint8_t (*copyResponse)(UDSServer_t *srv, const void *src,
+ uint16_t len); /*! function for copying response data (optional) */
+} UDSRequestTransferExitArgs_t;
+
+UDSErr_t UDSServerInit(UDSServer_t *srv);
+void UDSServerPoll(UDSServer_t *srv);
diff --git a/src/sys.h b/src/sys.h
new file mode 100644
index 0000000..417e908
--- /dev/null
+++ b/src/sys.h
@@ -0,0 +1,30 @@
+#pragma once
+
+#define UDS_SYS_CUSTOM 0
+#define UDS_SYS_UNIX 1
+#define UDS_SYS_WINDOWS 2
+#define UDS_SYS_ARDUINO 3
+#define UDS_SYS_ESP32 4
+
+
+#if !defined(UDS_SYS)
+
+#if defined(__unix__) || defined(__APPLE__)
+#define UDS_SYS UDS_SYS_UNIX
+#elif defined(_WIN32)
+#define UDS_SYS UDS_SYS_WINDOWS
+#elif defined(ARDUINO)
+#define UDS_SYS UDS_SYS_ARDUINO
+#elif defined(ESP_PLATFORM)
+#define UDS_SYS UDS_SYS_ESP32
+#else
+#define UDS_SYS UDS_SYS_CUSTOM
+#endif
+
+#endif
+
+#include "sys_unix.h"
+#include "sys_win32.h"
+#include "sys_arduino.h"
+#include "sys_esp32.h"
+
diff --git a/src/sys_arduino.h b/src/sys_arduino.h
new file mode 100644
index 0000000..39e6731
--- /dev/null
+++ b/src/sys_arduino.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#if UDS_SYS==UDS_SYS_ARDUINO
+
+#include
+#include
+#include
+#include
+
+#define UDS_TP UDS_TP_ISOTP_C
+#define UDS_ENABLE_DBG_PRINT 1
+#define UDS_ENABLE_ASSERT 1
+int print_impl(const char *fmt, ...);
+#define UDS_DBG_PRINT_IMPL print_impl
+
+#endif
diff --git a/src/sys_esp32.h b/src/sys_esp32.h
new file mode 100644
index 0000000..6a2df9f
--- /dev/null
+++ b/src/sys_esp32.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#if UDS_SYS==UDS_SYS_ESP32
+
+#include
+#include
+#include
+
+#define UDS_TP UDS_TP_ISOTP_C
+#define UDS_ENABLE_DBG_PRINT 1
+#define UDS_ENABLE_ASSERT 1
+
+#endif
+
diff --git a/src/sys_unix.h b/src/sys_unix.h
new file mode 100644
index 0000000..b2baf19
--- /dev/null
+++ b/src/sys_unix.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#if UDS_SYS==UDS_SYS_UNIX
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#endif
diff --git a/src/sys_win32.h b/src/sys_win32.h
new file mode 100644
index 0000000..25d6c43
--- /dev/null
+++ b/src/sys_win32.h
@@ -0,0 +1,8 @@
+#pragma once
+
+#if UDS_SYS==UDS_SYS_WIN32
+
+#include
+typedef SSIZE_T ssize_t;
+
+#endif
diff --git a/src/tp.c b/src/tp.c
new file mode 100644
index 0000000..63106d7
--- /dev/null
+++ b/src/tp.c
@@ -0,0 +1,64 @@
+#include "tp.h"
+
+/**
+ * @brief
+ *
+ * @param hdl
+ * @param info, if NULL, the default values are used:
+ * A_Mtype: message type (diagnostic (DEFAULT), remote diagnostic, secure diagnostic, secure
+ * remote diagnostic)
+ * A_TA_Type: application target address type (physical (DEFAULT) or functional)
+ * A_SA: unused
+ * A_TA: unused
+ * A_AE: unused
+ * @return ssize_t
+ */
+ssize_t UDSTpGetSendBuf(struct UDSTpHandle *hdl, uint8_t **buf) {
+ assert(hdl);
+ assert(hdl->get_send_buf);
+ return hdl->get_send_buf(hdl, buf);
+}
+ssize_t UDSTpSend(struct UDSTpHandle *hdl, const uint8_t *buf, ssize_t len, UDSSDU_t *info) {
+ assert(hdl);
+ assert(hdl->send);
+ return hdl->send(hdl, (uint8_t *)buf, len, info);
+}
+
+UDSTpStatus_t UDSTpPoll(struct UDSTpHandle *hdl) {
+ assert(hdl);
+ assert(hdl->poll);
+ return hdl->poll(hdl);
+}
+
+ssize_t UDSTpPeek(struct UDSTpHandle *hdl, uint8_t **buf, UDSSDU_t *info) {
+ assert(hdl);
+ assert(hdl->peek);
+ return hdl->peek(hdl, buf, info);
+}
+
+const uint8_t *UDSTpGetRecvBuf(struct UDSTpHandle *hdl, size_t *p_len) {
+ assert(hdl);
+ ssize_t len = 0;
+ uint8_t *buf = NULL;
+ len = UDSTpPeek(hdl, &buf, NULL);
+ if (len > 0) {
+ if (p_len) {
+ *p_len = len;
+ }
+ return buf;
+ } else {
+ return NULL;
+ }
+}
+
+size_t UDSTpGetRecvLen(UDSTpHandle_t *hdl) {
+ assert(hdl);
+ size_t len = 0;
+ UDSTpGetRecvBuf(hdl, &len);
+ return len;
+}
+
+void UDSTpAckRecv(UDSTpHandle_t *hdl) {
+ assert(hdl);
+ hdl->ack_recv(hdl);
+}
diff --git a/src/tp.h b/src/tp.h
new file mode 100644
index 0000000..966cab5
--- /dev/null
+++ b/src/tp.h
@@ -0,0 +1,128 @@
+#pragma once
+
+#include "sys.h"
+
+#if !defined(UDS_TP)
+#if (UDS_SYS == UDS_SYS_UNIX)
+#define UDS_TP UDS_TP_ISOTP_SOCKET
+#endif
+#endif
+
+#include
+#include
+#include
+#include
+#include
+
+#if (UDS_TP == UDS_TP_ISOTP_C)
+#include "tp/isotp-c/isotp.h"
+#include "tp/isotp-c/isotp_config.h"
+#include "tp/isotp-c/isotp_defines.h"
+#elif (UDS_TP == UDS_TP_ISOTP_SOCKET)
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#endif
+
+
+enum UDSTpStatusFlags {
+ UDS_TP_IDLE = 0x00000000,
+ UDS_TP_SEND_IN_PROGRESS = 0x00000001,
+ UDS_TP_RECV_COMPLETE = 0x00000002,
+};
+
+typedef uint32_t UDSTpStatus_t;
+
+typedef enum {
+ UDS_A_MTYPE_DIAG = 0,
+ UDS_A_MTYPE_REMOTE_DIAG,
+ UDS_A_MTYPE_SECURE_DIAG,
+ UDS_A_MTYPE_SECURE_REMOTE_DIAG,
+} UDS_A_Mtype_t;
+
+typedef enum {
+ UDS_A_TA_TYPE_PHYSICAL = 0, // unicast (1:1)
+ UDS_A_TA_TYPE_FUNCTIONAL, // multicast
+} UDS_A_TA_Type_t;
+
+typedef uint8_t UDSTpAddr_t;
+
+/**
+ * @brief Service data unit (SDU)
+ * @details data interface between the application layer and the transport layer
+ */
+typedef struct {
+ UDS_A_Mtype_t A_Mtype; // message type (diagnostic, remote diagnostic, secure diagnostic, secure
+ // remote diagnostic)
+ uint16_t A_SA; // application source address
+ uint16_t A_TA; // application target address
+ UDS_A_TA_Type_t A_TA_Type; // application target address type (physical or functional)
+ uint16_t A_AE; // application layer remote address
+} UDSSDU_t;
+
+#define UDS_TP_NOOP_ADDR (0xFFFFFFFF)
+
+/**
+ * @brief Interface to OSI layer 4 (transport layer)
+ * @note implementers should embed this struct at offset zero in their own transport layer handle
+ */
+typedef struct UDSTpHandle {
+ /**
+ * @brief Get the transport layer's send buffer
+ * @param hdl: pointer to transport handle
+ * @param buf: double pointer which will be pointed to the send buffer
+ * @return size of transport layer's send buffer on success, -1 on error
+ */
+ ssize_t (*get_send_buf)(struct UDSTpHandle *hdl, uint8_t **p_buf);
+
+ /**
+ * @brief Send the data in the buffer buf
+ * @param hdl: pointer to transport handle
+ * @param buf: a pointer to the data to send (this may be the buffer returned by @ref
+ * get_send_buf)
+ * @param info: pointer to SDU info (may be NULL). If NULL, implementation should send with
+ * physical addressing
+ */
+ ssize_t (*send)(struct UDSTpHandle *hdl, uint8_t *buf, size_t len, UDSSDU_t *info);
+
+ /**
+ * @brief Poll the transport layer.
+ * @param hdl: pointer to transport handle
+ * @note the transport layer user is responsible for calling this function periodically
+ * @note threaded implementations like linux isotp sockets don't need to do anything here.
+ * @return UDS_TP_IDLE if idle, otherwise UDS_TP_SEND_IN_PROGRESS or UDS_TP_RECV_COMPLETE
+ */
+ UDSTpStatus_t (*poll)(struct UDSTpHandle *hdl);
+
+ /**
+ * @brief Peek at the received data
+ * @param hdl: pointer to transport handle
+ * @param buf: set to the received data
+ * @param info: filled with SDU info by the callee if not NULL
+ * @return size of received data on success, -1 on error
+ * @note The transport will be unable to receive further data until @ref ack_recv is called
+ * @note The information returned by peek will not change until @ref ack_recv is called
+ */
+ ssize_t (*peek)(struct UDSTpHandle *hdl, uint8_t **buf, UDSSDU_t *info);
+
+ /**
+ * @brief Acknowledge that the received data has been processed and may be discarded
+ * @param hdl: pointer to transport handle
+ * @note: after ack_recv() is called and before new messages are received, peek must return 0.
+ */
+ void (*ack_recv)(struct UDSTpHandle *hdl);
+} UDSTpHandle_t;
+
+ssize_t UDSTpGetSendBuf(UDSTpHandle_t *hdl, uint8_t **buf);
+ssize_t UDSTpSend(UDSTpHandle_t *hdl, const uint8_t *buf, ssize_t len, UDSSDU_t *info);
+UDSTpStatus_t UDSTpPoll(UDSTpHandle_t *hdl);
+ssize_t UDSTpPeek(struct UDSTpHandle *hdl, uint8_t **buf, UDSSDU_t *info);
+const uint8_t *UDSTpGetRecvBuf(UDSTpHandle_t *hdl, size_t *len);
+size_t UDSTpGetRecvLen(UDSTpHandle_t *hdl);
+void UDSTpAckRecv(UDSTpHandle_t *hdl);
diff --git a/src/tp/README.md b/src/tp/README.md
new file mode 100644
index 0000000..ccba17e
--- /dev/null
+++ b/src/tp/README.md
@@ -0,0 +1,66 @@
+
+The transport layer / session layer interface is a little complex.
+
+- see iso14229.h `UDSTpHandle_t`
+ - implement all callback functions
+- do sanity checks on init
+
+```c
+#include "assert.h"
+assert(cfg->source_addr != cfg->target_addr);
+assert(cfg->target_addr != cfg->source_addr_func);
+assert(cfg->source_addr_func != cfg->source_addr);
+
+assert(cfg->tp->recv);
+assert(cfg->tp->send);
+assert(cfg->tp->poll);
+
+#if foo
+#elif UDS_TP == UDS_TP_ISOTP_C
+ assert(cfg->target_addr != cfg->source_addr_func && cfg->source_addr_func != cfg->source_addr);
+ UDSTpIsoTpC_t *tp = &self->tp_impl;
+ isotp_init_link(&tp->phys_link, cfg->target_addr, self->send_buf, self->send_buf_size,
+ self->recv_buf, self->recv_buf_size);
+ isotp_init_link(&tp->func_link, cfg->target_addr, tp->func_send_buf, sizeof(tp->func_send_buf),
+ tp->func_recv_buf, sizeof(tp->func_recv_buf));
+ self->tp = (UDSTpHandle_t *)tp;
+ self->tp->poll = tp_poll;
+ self->tp->send = tp_send;
+ self->tp->recv = tp_recv;
+#elif UDS_TP == UDS_TP_ISOTP_SOCKET
+ self->tp = (UDSTpHandle_t *)&self->tp_impl;
+ if (LinuxSockTpOpen(self->tp, cfg->if_name, cfg->source_addr, cfg->target_addr,
+ cfg->source_addr_func, cfg->target_addr)) {
+ return UDS_ERR;
+ }
+
+// client
+
+#if UDS_TP == UDS_TP_CUSTOM
+ assert(cfg->tp);
+ assert(cfg->tp->recv);
+ assert(cfg->tp->send);
+ assert(cfg->tp->poll);
+ client->tp = cfg->tp;
+#elif UDS_TP == UDS_TP_ISOTP_C
+ assert(cfg->source_addr != cfg->target_addr_func && cfg->target_addr_func != cfg->target_addr);
+ UDSTpIsoTpC_t *tp = (UDSTpIsoTpC_t *)&client->tp_impl;
+ isotp_init_link(&tp->phys_link, cfg->target_addr, client->send_buf, client->send_buf_size,
+ client->recv_buf, client->recv_buf_size);
+ isotp_init_link(&tp->func_link, cfg->target_addr_func, tp->func_send_buf,
+ sizeof(tp->func_send_buf), tp->func_recv_buf, sizeof(tp->func_recv_buf));
+ client->tp = (UDSTpHandle_t *)tp;
+ client->tp->poll = tp_poll;
+ client->tp->send = tp_send;
+ client->tp->recv = tp_recv;
+#elif UDS_TP == UDS_TP_ISOTP_SOCKET
+ client->tp = (UDSTpHandle_t *)&client->tp_impl;
+ if (LinuxSockTpOpen(client->tp, cfg->if_name, cfg->source_addr, cfg->target_addr,
+ cfg->source_addr, cfg->target_addr_func)) {
+ return UDS_ERR;
+ }
+ assert(client->tp);
+#endif
+
+
+```
\ No newline at end of file
diff --git a/tp/isotp-c b/src/tp/isotp-c
similarity index 100%
rename from tp/isotp-c
rename to src/tp/isotp-c
diff --git a/tp/isotp_c.c b/src/tp/isotp_c.c
similarity index 91%
rename from tp/isotp_c.c
rename to src/tp/isotp_c.c
index a0a44f1..05f6f76 100644
--- a/tp/isotp_c.c
+++ b/src/tp/isotp_c.c
@@ -1,12 +1,15 @@
+
+#include
+#if UDS_TP == UDS_TP_ISOTP_C
+
+#include "util.h"
#include "tp/isotp_c.h"
#include "tp/isotp-c/isotp.h"
-#include
-#include
static UDSTpStatus_t tp_poll(UDSTpHandle_t *hdl) {
assert(hdl);
UDSTpStatus_t status = 0;
- UDSTpISOTpC_t *impl = (UDSTpISOTpC_t *)hdl;
+ UDSISOTpC_t *impl = (UDSISOTpC_t *)hdl;
isotp_poll(&impl->phys_link);
if (impl->phys_link.send_status == ISOTP_SEND_STATUS_INPROGRESS) {
status |= UDS_TP_SEND_IN_PROGRESS;
@@ -42,7 +45,7 @@ int peek_link(IsoTpLink *link, uint8_t *buf, size_t bufsize, bool functional) {
static ssize_t tp_peek(UDSTpHandle_t *hdl, uint8_t **p_buf, UDSSDU_t *info) {
assert(hdl);
assert(p_buf);
- UDSTpISOTpC_t *tp = (UDSTpISOTpC_t *)hdl;
+ UDSISOTpC_t *tp = (UDSISOTpC_t *)hdl;
if (ISOTP_RECEIVE_STATUS_FULL == tp->phys_link.receive_status) { // recv not yet acked
*p_buf = tp->recv_buf;
return tp->phys_link.receive_size;
@@ -89,7 +92,7 @@ static ssize_t tp_peek(UDSTpHandle_t *hdl, uint8_t **p_buf, UDSSDU_t *info) {
static ssize_t tp_send(UDSTpHandle_t *hdl, uint8_t *buf, size_t len, UDSSDU_t *info) {
assert(hdl);
ssize_t ret = -1;
- UDSTpISOTpC_t *tp = (UDSTpISOTpC_t *)hdl;
+ UDSISOTpC_t *tp = (UDSISOTpC_t *)hdl;
IsoTpLink *link = NULL;
const UDSTpAddr_t ta_type = info ? info->A_TA_Type : UDS_A_TA_TYPE_PHYSICAL;
const uint32_t ta = ta_type == UDS_A_TA_TYPE_PHYSICAL ? tp->phys_ta : tp->func_ta;
@@ -128,17 +131,20 @@ static ssize_t tp_send(UDSTpHandle_t *hdl, uint8_t *buf, size_t len, UDSSDU_t *i
static void tp_ack_recv(UDSTpHandle_t *hdl) {
assert(hdl);
printf("ack recv\n");
- UDSTpISOTpC_t *tp = (UDSTpISOTpC_t *)hdl;
+ UDSISOTpC_t *tp = (UDSISOTpC_t *)hdl;
+ uint16_t out_size = 0;
+ isotp_receive(&tp->phys_link, tp->recv_buf, sizeof(tp->recv_buf), &out_size);
+
}
static ssize_t tp_get_send_buf(UDSTpHandle_t *hdl, uint8_t **p_buf) {
assert(hdl);
- UDSTpISOTpC_t *tp = (UDSTpISOTpC_t *)hdl;
+ UDSISOTpC_t *tp = (UDSISOTpC_t *)hdl;
*p_buf = tp->send_buf;
return sizeof(tp->send_buf);
}
-UDSErr_t UDSTpISOTpCInit(UDSTpISOTpC_t *tp, UDSTpISOTpCConfig_t *cfg) {
+UDSErr_t UDSISOTpCInit(UDSISOTpC_t *tp, const UDSISOTpCConfig_t *cfg) {
if (cfg == NULL || tp == NULL) {
return UDS_ERR;
}
@@ -159,4 +165,6 @@ UDSErr_t UDSTpISOTpCInit(UDSTpISOTpC_t *tp, UDSTpISOTpCConfig_t *cfg) {
sizeof(tp->recv_buf), UDSMillis, cfg->isotp_user_send_can,
cfg->isotp_user_debug, cfg->user_data);
return UDS_OK;
-}
\ No newline at end of file
+}
+
+#endif
diff --git a/tp/isotp_c.h b/src/tp/isotp_c.h
similarity index 76%
rename from tp/isotp_c.h
rename to src/tp/isotp_c.h
index 84f6f98..0226576 100644
--- a/tp/isotp_c.h
+++ b/src/tp/isotp_c.h
@@ -1,7 +1,10 @@
-#ifndef ISOTP_C_H
-#define ISOTP_C_H
+#pragma once
+#if UDS_TP == UDS_TP_ISOTP_C
-#include "iso14229.h"
+#include "sys.h"
+#include "config.h"
+#include "uds.h"
+#include "tp.h"
#include "tp/isotp-c/isotp.h"
typedef struct {
@@ -12,7 +15,7 @@ typedef struct {
uint8_t recv_buf[UDS_ISOTP_MTU];
uint32_t phys_sa, phys_ta;
uint32_t func_sa, func_ta;
-} UDSTpISOTpC_t;
+} UDSISOTpC_t;
typedef struct {
uint32_t source_addr;
@@ -25,10 +28,10 @@ typedef struct {
uint32_t (*isotp_user_get_ms)(void); /* get millisecond */
void (*isotp_user_debug)(const char *message, ...); /* print debug message */
void *user_data; /* user data */
-} UDSTpISOTpCConfig_t;
+} UDSISOTpCConfig_t;
-UDSErr_t UDSTpISOTpCInit(UDSTpISOTpC_t *tp, UDSTpISOTpCConfig_t *cfg);
+UDSErr_t UDSISOTpCInit(UDSISOTpC_t *tp, const UDSISOTpCConfig_t *cfg);
-void UDSTpISOTpCDeinit(UDSTpISOTpC_t *tp);
+void UDSISOTpCDeinit(UDSISOTpC_t *tp);
-#endif
+#endif
diff --git a/tp/isotp_c_socketcan.c b/src/tp/isotp_c_socketcan.c
similarity index 87%
rename from tp/isotp_c_socketcan.c
rename to src/tp/isotp_c_socketcan.c
index 5c5ade5..1977c32 100644
--- a/tp/isotp_c_socketcan.c
+++ b/src/tp/isotp_c_socketcan.c
@@ -1,3 +1,5 @@
+#if defined(UDS_TP_ISOTP_C_SOCKETCAN)
+
#include "tp/isotp_c_socketcan.h"
#include "iso14229.h"
#include "tp/isotp-c/isotp_defines.h"
@@ -99,7 +101,7 @@ static void SocketCANRecv(UDSTpISOTpC_t *tp) {
}
}
-static UDSTpStatus_t tp_poll(UDSTpHandle_t *hdl) {
+static UDSTpStatus_t isotp_c_socketcan_tp_poll(UDSTpHandle_t *hdl) {
assert(hdl);
UDSTpStatus_t status = 0;
UDSTpISOTpC_t *impl = (UDSTpISOTpC_t *)hdl;
@@ -111,7 +113,7 @@ static UDSTpStatus_t tp_poll(UDSTpHandle_t *hdl) {
return status;
}
-int peek_link(IsoTpLink *link, uint8_t *buf, size_t bufsize, bool functional) {
+static int isotp_c_socketcan_tp_peek_link(IsoTpLink *link, uint8_t *buf, size_t bufsize, bool functional) {
assert(link);
assert(buf);
int ret = -1;
@@ -136,7 +138,7 @@ int peek_link(IsoTpLink *link, uint8_t *buf, size_t bufsize, bool functional) {
return ret;
}
-static ssize_t tp_peek(UDSTpHandle_t *hdl, uint8_t **p_buf, UDSSDU_t *info) {
+static ssize_t isotp_c_socketcan_tp_peek(UDSTpHandle_t *hdl, uint8_t **p_buf, UDSSDU_t *info) {
assert(hdl);
assert(p_buf);
UDSTpISOTpC_t *tp = (UDSTpISOTpC_t *)hdl;
@@ -145,7 +147,7 @@ static ssize_t tp_peek(UDSTpHandle_t *hdl, uint8_t **p_buf, UDSSDU_t *info) {
return tp->phys_link.receive_size;
}
int ret = -1;
- ret = peek_link(&tp->phys_link, tp->recv_buf, sizeof(tp->recv_buf), false);
+ ret = isotp_c_socketcan_tp_peek_link(&tp->phys_link, tp->recv_buf, sizeof(tp->recv_buf), false);
UDS_A_TA_Type_t ta_type = UDS_A_TA_TYPE_PHYSICAL;
uint32_t ta = tp->phys_ta;
uint32_t sa = tp->phys_sa;
@@ -160,7 +162,7 @@ static ssize_t tp_peek(UDSTpHandle_t *hdl, uint8_t **p_buf, UDSSDU_t *info) {
} else if (ret < 0) {
goto done;
} else {
- ret = peek_link(&tp->func_link, tp->recv_buf, sizeof(tp->recv_buf), true);
+ ret = isotp_c_socketcan_tp_peek_link(&tp->func_link, tp->recv_buf, sizeof(tp->recv_buf), true);
if (ret > 0) {
printf("just got %d bytes on func link \n", ret);
ta = tp->func_sa;
@@ -190,7 +192,7 @@ static ssize_t tp_peek(UDSTpHandle_t *hdl, uint8_t **p_buf, UDSSDU_t *info) {
return ret;
}
-static ssize_t tp_send(UDSTpHandle_t *hdl, uint8_t *buf, size_t len, UDSSDU_t *info) {
+static ssize_t isotp_c_socketcan_tp_send(UDSTpHandle_t *hdl, uint8_t *buf, size_t len, UDSSDU_t *info) {
assert(hdl);
ssize_t ret = -1;
UDSTpISOTpC_t *tp = (UDSTpISOTpC_t *)hdl;
@@ -237,13 +239,15 @@ static ssize_t tp_send(UDSTpHandle_t *hdl, uint8_t *buf, size_t len, UDSSDU_t *i
return ret;
}
-static void tp_ack_recv(UDSTpHandle_t *hdl) {
+static void isotp_c_socketcan_tp_ack_recv(UDSTpHandle_t *hdl) {
assert(hdl);
printf("ack recv\n");
UDSTpISOTpC_t *tp = (UDSTpISOTpC_t *)hdl;
+ uint16_t out_size = 0;
+ isotp_receive(&tp->phys_link, tp->recv_buf, sizeof(tp->recv_buf), &out_size);
}
-static ssize_t tp_get_send_buf(UDSTpHandle_t *hdl, uint8_t **p_buf) {
+static ssize_t isotp_c_socketcan_tp_get_send_buf(UDSTpHandle_t *hdl, uint8_t **p_buf) {
assert(hdl);
UDSTpISOTpC_t *tp = (UDSTpISOTpC_t *)hdl;
*p_buf = tp->send_buf;
@@ -255,11 +259,11 @@ UDSErr_t UDSTpISOTpCInit(UDSTpISOTpC_t *tp, const char *ifname, uint32_t source_
uint32_t target_addr_func) {
assert(tp);
assert(ifname);
- tp->hdl.poll = tp_poll;
- tp->hdl.send = tp_send;
- tp->hdl.peek = tp_peek;
- tp->hdl.ack_recv = tp_ack_recv;
- tp->hdl.get_send_buf = tp_get_send_buf;
+ tp->hdl.poll = isotp_c_socketcan_tp_poll;
+ tp->hdl.send = isotp_c_socketcan_tp_send;
+ tp->hdl.peek = isotp_c_socketcan_tp_peek;
+ tp->hdl.ack_recv = isotp_c_socketcan_tp_ack_recv;
+ tp->hdl.get_send_buf = isotp_c_socketcan_tp_get_send_buf;
tp->phys_sa = source_addr;
tp->phys_ta = target_addr;
tp->func_sa = source_addr_func;
@@ -279,4 +283,6 @@ void UDSTpISOTpCDeinit(UDSTpISOTpC_t *tp) {
assert(tp);
close(tp->fd);
tp->fd = -1;
-}
\ No newline at end of file
+}
+
+#endif
\ No newline at end of file
diff --git a/tp/isotp_c_socketcan.h b/src/tp/isotp_c_socketcan.h
similarity index 90%
rename from tp/isotp_c_socketcan.h
rename to src/tp/isotp_c_socketcan.h
index 16666fa..893a62a 100644
--- a/tp/isotp_c_socketcan.h
+++ b/src/tp/isotp_c_socketcan.h
@@ -1,9 +1,10 @@
-#ifndef ISOTP_C_SOCKETCAN_H
-#define ISOTP_C_SOCKETCAN_H
+#pragma once
#include "iso14229.h"
#include "tp/isotp-c/isotp.h"
+#if defined(UDS_TP_ISOTP_C_SOCKETCAN)
+
typedef struct {
UDSTpHandle_t hdl;
IsoTpLink phys_link;
@@ -21,4 +22,4 @@ UDSErr_t UDSTpISOTpCInit(UDSTpISOTpC_t *tp, const char *ifname, uint32_t source_
uint32_t target_addr_func);
void UDSTpISOTpCDeinit(UDSTpISOTpC_t *tp);
-#endif
\ No newline at end of file
+#endif
diff --git a/tp/isotp_sock.c b/src/tp/isotp_sock.c
similarity index 88%
rename from tp/isotp_sock.c
rename to src/tp/isotp_sock.c
index f642367..966542b 100644
--- a/tp/isotp_sock.c
+++ b/src/tp/isotp_sock.c
@@ -1,3 +1,5 @@
+#if defined(UDS_TP_ISOTP_SOCK)
+
#include "tp/isotp_sock.h"
#include "iso14229.h"
#include
@@ -11,7 +13,7 @@
#include
#include
-static UDSTpStatus_t tp_poll(UDSTpHandle_t *hdl) { return 0; }
+static UDSTpStatus_t isotp_sock_tp_poll(UDSTpHandle_t *hdl) { return 0; }
static ssize_t tp_recv_once(int fd, uint8_t *buf, size_t size) {
ssize_t ret = read(fd, buf, size);
@@ -28,7 +30,7 @@ static ssize_t tp_recv_once(int fd, uint8_t *buf, size_t size) {
return ret;
}
-static ssize_t tp_peek(UDSTpHandle_t *hdl, uint8_t **p_buf, UDSSDU_t *info) {
+static ssize_t isotp_sock_tp_peek(UDSTpHandle_t *hdl, uint8_t **p_buf, UDSSDU_t *info) {
assert(hdl);
assert(p_buf);
ssize_t ret = 0;
@@ -78,13 +80,13 @@ static ssize_t tp_peek(UDSTpHandle_t *hdl, uint8_t **p_buf, UDSSDU_t *info) {
return ret;
}
-static void tp_ack_recv(UDSTpHandle_t *hdl) {
+static void isotp_sock_tp_ack_recv(UDSTpHandle_t *hdl) {
assert(hdl);
UDSTpIsoTpSock_t *impl = (UDSTpIsoTpSock_t *)hdl;
impl->recv_len = 0;
}
-static ssize_t tp_send(UDSTpHandle_t *hdl, uint8_t *buf, size_t len, UDSSDU_t *info) {
+static ssize_t isotp_sock_tp_send(UDSTpHandle_t *hdl, uint8_t *buf, size_t len, UDSSDU_t *info) {
assert(hdl);
ssize_t ret = -1;
UDSTpIsoTpSock_t *impl = (UDSTpIsoTpSock_t *)hdl;
@@ -122,7 +124,7 @@ static ssize_t tp_send(UDSTpHandle_t *hdl, uint8_t *buf, size_t len, UDSSDU_t *i
return ret;
}
-static ssize_t tp_get_send_buf(UDSTpHandle_t *hdl, uint8_t **p_buf) {
+static ssize_t isotp_sock_tp_get_send_buf(UDSTpHandle_t *hdl, uint8_t **p_buf) {
assert(hdl);
UDSTpIsoTpSock_t *impl = (UDSTpIsoTpSock_t *)hdl;
*p_buf = impl->send_buf;
@@ -180,11 +182,11 @@ static int LinuxSockBind(const char *if_name, uint32_t rxid, uint32_t txid, bool
UDSErr_t UDSTpIsoTpSockInitServer(UDSTpIsoTpSock_t *tp, const char *ifname, uint32_t source_addr,
uint32_t target_addr, uint32_t source_addr_func) {
assert(tp);
- tp->hdl.peek = tp_peek;
- tp->hdl.send = tp_send;
- tp->hdl.poll = tp_poll;
- tp->hdl.ack_recv = tp_ack_recv;
- tp->hdl.get_send_buf = tp_get_send_buf;
+ tp->hdl.peek = isotp_sock_tp_peek;
+ tp->hdl.send = isotp_sock_tp_send;
+ tp->hdl.poll = isotp_sock_tp_poll;
+ tp->hdl.ack_recv = isotp_sock_tp_ack_recv;
+ tp->hdl.get_send_buf = isotp_sock_tp_get_send_buf;
tp->phys_sa = source_addr;
tp->phys_ta = target_addr;
tp->func_sa = source_addr_func;
@@ -205,11 +207,11 @@ UDSErr_t UDSTpIsoTpSockInitServer(UDSTpIsoTpSock_t *tp, const char *ifname, uint
UDSErr_t UDSTpIsoTpSockInitClient(UDSTpIsoTpSock_t *tp, const char *ifname, uint32_t source_addr,
uint32_t target_addr, uint32_t target_addr_func) {
assert(tp);
- tp->hdl.peek = tp_peek;
- tp->hdl.send = tp_send;
- tp->hdl.poll = tp_poll;
- tp->hdl.ack_recv = tp_ack_recv;
- tp->hdl.get_send_buf = tp_get_send_buf;
+ tp->hdl.peek = isotp_sock_tp_peek;
+ tp->hdl.send = isotp_sock_tp_send;
+ tp->hdl.poll = isotp_sock_tp_poll;
+ tp->hdl.ack_recv = isotp_sock_tp_ack_recv;
+ tp->hdl.get_send_buf = isotp_sock_tp_get_send_buf;
tp->func_ta = target_addr_func;
tp->phys_ta = target_addr;
tp->phys_sa = source_addr;
@@ -236,3 +238,6 @@ void UDSTpIsoTpSockDeinit(UDSTpIsoTpSock_t *tp) {
}
}
}
+
+#endif
+
diff --git a/tp/isotp_sock.h b/src/tp/isotp_sock.h
similarity index 93%
rename from tp/isotp_sock.h
rename to src/tp/isotp_sock.h
index ff73688..ac189f4 100644
--- a/tp/isotp_sock.h
+++ b/src/tp/isotp_sock.h
@@ -1,6 +1,6 @@
-#ifndef TP_ISOTP_SOCK_H
-#define TP_ISOTP_SOCK_H
+#if defined(UDS_TP_ISOTP_SOCK)
+#pragma once
#include "iso14229.h"
typedef struct {
diff --git a/tp/mock.c b/src/tp/mock.c
similarity index 89%
rename from tp/mock.c
rename to src/tp/mock.c
index 52d2aed..2ce0f27 100644
--- a/tp/mock.c
+++ b/src/tp/mock.c
@@ -1,3 +1,5 @@
+#if defined(UDS_TP_MOCK)
+
#include "tp/mock.h"
#include "iso14229.h"
#include
@@ -59,7 +61,7 @@ static void NetworkPoll() {
}
}
-static ssize_t tp_peek(struct UDSTpHandle *hdl, uint8_t **p_buf, UDSSDU_t *info) {
+static ssize_t mock_tp_peek(struct UDSTpHandle *hdl, uint8_t **p_buf, UDSSDU_t *info) {
assert(hdl);
assert(p_buf);
TPMock_t *tp = (TPMock_t *)hdl;
@@ -72,7 +74,7 @@ static ssize_t tp_peek(struct UDSTpHandle *hdl, uint8_t **p_buf, UDSSDU_t *info)
return tp->recv_len;
}
-static ssize_t tp_send(struct UDSTpHandle *hdl, uint8_t *buf, size_t len, UDSSDU_t *info) {
+static ssize_t mock_tp_send(struct UDSTpHandle *hdl, uint8_t *buf, size_t len, UDSSDU_t *info) {
assert(hdl);
TPMock_t *tp = (TPMock_t *)hdl;
if (MsgCount > NUM_MSGS) {
@@ -100,13 +102,13 @@ static ssize_t tp_send(struct UDSTpHandle *hdl, uint8_t *buf, size_t len, UDSSDU
return len;
}
-static UDSTpStatus_t tp_poll(struct UDSTpHandle *hdl) {
+static UDSTpStatus_t mock_tp_poll(struct UDSTpHandle *hdl) {
NetworkPoll();
// todo: make this status reflect TX time
return UDS_TP_IDLE;
}
-static ssize_t tp_get_send_buf(struct UDSTpHandle *hdl, uint8_t **p_buf) {
+static ssize_t mock_tp_get_send_buf(struct UDSTpHandle *hdl, uint8_t **p_buf) {
assert(hdl);
assert(p_buf);
TPMock_t *tp = (TPMock_t *)hdl;
@@ -114,7 +116,7 @@ static ssize_t tp_get_send_buf(struct UDSTpHandle *hdl, uint8_t **p_buf) {
return sizeof(tp->send_buf);
}
-static void tp_ack_recv(struct UDSTpHandle *hdl) {
+static void mock_tp_ack_recv(struct UDSTpHandle *hdl) {
assert(hdl);
TPMock_t *tp = (TPMock_t *)hdl;
tp->recv_len = 0;
@@ -127,11 +129,11 @@ static void TPMockAttach(TPMock_t *tp, TPMockArgs_t *args) {
assert(args);
assert(TPCount < MAX_NUM_TP);
TPs[TPCount++] = tp;
- tp->hdl.peek = tp_peek;
- tp->hdl.send = tp_send;
- tp->hdl.poll = tp_poll;
- tp->hdl.get_send_buf = tp_get_send_buf;
- tp->hdl.ack_recv = tp_ack_recv;
+ tp->hdl.peek = mock_tp_peek;
+ tp->hdl.send = mock_tp_send;
+ tp->hdl.poll = mock_tp_poll;
+ tp->hdl.get_send_buf = mock_tp_get_send_buf;
+ tp->hdl.ack_recv = mock_tp_ack_recv;
tp->sa_func = args->sa_func;
tp->sa_phys = args->sa_phys;
tp->ta_func = args->ta_func;
@@ -204,4 +206,6 @@ void TPMockFree(UDSTpHandle_t *tp) {
TPMock_t *tpm = (TPMock_t *)tp;
TPMockDetach(tpm);
free(tp);
-}
\ No newline at end of file
+}
+
+#endif
diff --git a/tp/mock.h b/src/tp/mock.h
similarity index 94%
rename from tp/mock.h
rename to src/tp/mock.h
index 53279a6..13cff58 100644
--- a/tp/mock.h
+++ b/src/tp/mock.h
@@ -4,17 +4,16 @@
* @date 2023-10-21
*
*/
+#if defined(UDS_TP_MOCK)
-#include "iso14229.h"
+#pragma once
-#ifdef __cplusplus
-extern "C" {
-#endif
+#include "iso14229.h"
typedef struct TPMock {
UDSTpHandle_t hdl;
- uint8_t recv_buf[UDS_BUFSIZE];
- uint8_t send_buf[UDS_BUFSIZE];
+ uint8_t recv_buf[UDS_TP_MTU];
+ uint8_t send_buf[UDS_TP_MTU];
size_t recv_len;
UDSSDU_t recv_info;
uint32_t sa_phys; // source address - physical messages are sent from this address
@@ -64,6 +63,5 @@ void TPMockLogToStdout(void);
*/
void TPMockReset(void);
-#ifdef __cplusplus
-}
#endif
+
diff --git a/src/uds.h b/src/uds.h
new file mode 100644
index 0000000..455d11e
--- /dev/null
+++ b/src/uds.h
@@ -0,0 +1,223 @@
+#pragma once
+
+enum UDSServerEvent {
+ UDS_SRV_EVT_DiagSessCtrl, // UDSDiagSessCtrlArgs_t *
+ UDS_SRV_EVT_EcuReset, // UDSECUResetArgs_t *
+ UDS_SRV_EVT_ReadDataByIdent, // UDSRDBIArgs_t *
+ UDS_SRV_EVT_ReadMemByAddr, // UDSReadMemByAddrArgs_t *
+ UDS_SRV_EVT_CommCtrl, // UDSCommCtrlArgs_t *
+ UDS_SRV_EVT_SecAccessRequestSeed, // UDSSecAccessRequestSeedArgs_t *
+ UDS_SRV_EVT_SecAccessValidateKey, // UDSSecAccessValidateKeyArgs_t *
+ UDS_SRV_EVT_WriteDataByIdent, // UDSWDBIArgs_t *
+ UDS_SRV_EVT_RoutineCtrl, // UDSRoutineCtrlArgs_t*
+ UDS_SRV_EVT_RequestDownload, // UDSRequestDownloadArgs_t*
+ UDS_SRV_EVT_RequestUpload, // UDSRequestUploadArgs_t *
+ UDS_SRV_EVT_TransferData, // UDSTransferDataArgs_t *
+ UDS_SRV_EVT_RequestTransferExit, // UDSRequestTransferExitArgs_t *
+ UDS_SRV_EVT_SessionTimeout, // NULL
+ UDS_SRV_EVT_DoScheduledReset, // enum UDSEcuResetType *
+ UDS_SRV_EVT_Err, // UDSErr_t *
+ UDS_EVT_IDLE,
+ UDS_EVT_RESP_RECV,
+};
+
+typedef int UDSServerEvent_t;
+typedef UDSServerEvent_t UDSEvent_t;
+
+typedef enum {
+ UDS_ERR = -1, // 通用错误
+ UDS_OK = 0, // 成功
+ UDS_ERR_TIMEOUT, // 请求超时
+ UDS_ERR_NEG_RESP, // 否定响应
+ UDS_ERR_DID_MISMATCH, // 响应DID对不上期待的DID
+ UDS_ERR_SID_MISMATCH, // 请求和响应SID对不上
+ UDS_ERR_SUBFUNCTION_MISMATCH, // 请求和响应SubFunction对不上
+ UDS_ERR_TPORT, // 传输层错误
+ UDS_ERR_FILE_IO, // 文件IO错误
+ UDS_ERR_RESP_TOO_SHORT, // 响应太短
+ UDS_ERR_BUFSIZ, // 缓冲器不够大
+ UDS_ERR_INVALID_ARG, // 参数不对、没发
+ UDS_ERR_BUSY, // 正在忙、没发
+} UDSErr_t;
+
+typedef enum {
+ UDSSeqStateDone = 0,
+ UDSSeqStateRunning = 1,
+ UDSSeqStateGotoNext = 2,
+} UDSSeqState_t;
+
+enum UDSDiagnosticSessionType {
+ kDefaultSession = 0x01,
+ kProgrammingSession = 0x02,
+ kExtendedDiagnostic = 0x03,
+ kSafetySystemDiagnostic = 0x04,
+};
+
+enum {
+ kPositiveResponse = 0,
+ kGeneralReject = 0x10,
+ kServiceNotSupported = 0x11,
+ kSubFunctionNotSupported = 0x12,
+ kIncorrectMessageLengthOrInvalidFormat = 0x13,
+ kResponseTooLong = 0x14,
+ kBusyRepeatRequest = 0x21,
+ kConditionsNotCorrect = 0x22,
+ kRequestSequenceError = 0x24,
+ kNoResponseFromSubnetComponent = 0x25,
+ kFailurePreventsExecutionOfRequestedAction = 0x26,
+ kRequestOutOfRange = 0x31,
+ kSecurityAccessDenied = 0x33,
+ kInvalidKey = 0x35,
+ kExceedNumberOfAttempts = 0x36,
+ kRequiredTimeDelayNotExpired = 0x37,
+ kUploadDownloadNotAccepted = 0x70,
+ kTransferDataSuspended = 0x71,
+ kGeneralProgrammingFailure = 0x72,
+ kWrongBlockSequenceCounter = 0x73,
+ kRequestCorrectlyReceived_ResponsePending = 0x78,
+ kSubFunctionNotSupportedInActiveSession = 0x7E,
+ kServiceNotSupportedInActiveSession = 0x7F,
+ kRpmTooHigh = 0x81,
+ kRpmTooLow = 0x82,
+ kEngineIsRunning = 0x83,
+ kEngineIsNotRunning = 0x84,
+ kEngineRunTimeTooLow = 0x85,
+ kTemperatureTooHigh = 0x86,
+ kTemperatureTooLow = 0x87,
+ kVehicleSpeedTooHigh = 0x88,
+ kVehicleSpeedTooLow = 0x89,
+ kThrottlePedalTooHigh = 0x8A,
+ kThrottlePedalTooLow = 0x8B,
+ kTransmissionRangeNotInNeutral = 0x8C,
+ kTransmissionRangeNotInGear = 0x8D,
+ kISOSAEReserved = 0x8E,
+ kBrakeSwitchNotClosed = 0x8F,
+ kShifterLeverNotInPark = 0x90,
+ kTorqueConverterClutchLocked = 0x91,
+ kVoltageTooHigh = 0x92,
+ kVoltageTooLow = 0x93,
+};
+
+/**
+ * @brief LEV_RT_
+ * @addtogroup ecuReset_0x11
+ */
+enum UDSECUResetType {
+ kHardReset = 1,
+ kKeyOffOnReset = 2,
+ kSoftReset = 3,
+ kEnableRapidPowerShutDown = 4,
+ kDisableRapidPowerShutDown = 5,
+};
+
+typedef uint8_t UDSECUReset_t;
+
+/**
+ * @addtogroup securityAccess_0x27
+ */
+enum UDSSecurityAccessType {
+ kRequestSeed = 0x01,
+ kSendKey = 0x02,
+};
+
+/**
+ * @addtogroup communicationControl_0x28
+ */
+enum UDSCommunicationControlType {
+ kEnableRxAndTx = 0,
+ kEnableRxAndDisableTx = 1,
+ kDisableRxAndEnableTx = 2,
+ kDisableRxAndTx = 3,
+};
+
+/**
+ * @addtogroup communicationControl_0x28
+ */
+enum UDSCommunicationType {
+ kNormalCommunicationMessages = 0x1,
+ kNetworkManagementCommunicationMessages = 0x2,
+ kNetworkManagementCommunicationMessagesAndNormalCommunicationMessages = 0x3,
+};
+
+/**
+ * @addtogroup routineControl_0x31
+ */
+enum RoutineControlType {
+ kStartRoutine = 1,
+ kStopRoutine = 2,
+ kRequestRoutineResults = 3,
+};
+
+/**
+ * @addtogroup controlDTCSetting_0x85
+ */
+enum DTCSettingType {
+ kDTCSettingON = 0x01,
+ kDTCSettingOFF = 0x02,
+};
+
+
+// ISO-14229-1:2013 Table 2
+#define UDS_MAX_DIAGNOSTIC_SERVICES 0x7F
+
+#define UDS_RESPONSE_SID_OF(request_sid) (request_sid + 0x40)
+#define UDS_REQUEST_SID_OF(response_sid) (response_sid - 0x40)
+
+#define UDS_NEG_RESP_LEN 3U
+#define UDS_0X10_REQ_LEN 2U
+#define UDS_0X10_RESP_LEN 6U
+#define UDS_0X11_REQ_MIN_LEN 2U
+#define UDS_0X11_RESP_BASE_LEN 2U
+#define UDS_0X23_REQ_MIN_LEN 4U
+#define UDS_0X23_RESP_BASE_LEN 1U
+#define UDS_0X22_RESP_BASE_LEN 1U
+#define UDS_0X27_REQ_BASE_LEN 2U
+#define UDS_0X27_RESP_BASE_LEN 2U
+#define UDS_0X28_REQ_BASE_LEN 3U
+#define UDS_0X28_RESP_LEN 2U
+#define UDS_0X2E_REQ_BASE_LEN 3U
+#define UDS_0X2E_REQ_MIN_LEN 4U
+#define UDS_0X2E_RESP_LEN 3U
+#define UDS_0X31_REQ_MIN_LEN 4U
+#define UDS_0X31_RESP_MIN_LEN 4U
+#define UDS_0X34_REQ_BASE_LEN 3U
+#define UDS_0X34_RESP_BASE_LEN 2U
+#define UDS_0X35_REQ_BASE_LEN 3U
+#define UDS_0X35_RESP_BASE_LEN 2U
+#define UDS_0X36_REQ_BASE_LEN 2U
+#define UDS_0X36_RESP_BASE_LEN 2U
+#define UDS_0X37_REQ_BASE_LEN 1U
+#define UDS_0X37_RESP_BASE_LEN 1U
+#define UDS_0X3E_REQ_MIN_LEN 2U
+#define UDS_0X3E_REQ_MAX_LEN 2U
+#define UDS_0X3E_RESP_LEN 2U
+#define UDS_0X85_REQ_BASE_LEN 2U
+#define UDS_0X85_RESP_LEN 2U
+
+enum UDSDiagnosticServiceId {
+ kSID_DIAGNOSTIC_SESSION_CONTROL = 0x10,
+ kSID_ECU_RESET = 0x11,
+ kSID_CLEAR_DIAGNOSTIC_INFORMATION = 0x14,
+ kSID_READ_DTC_INFORMATION = 0x19,
+ kSID_READ_DATA_BY_IDENTIFIER = 0x22,
+ kSID_READ_MEMORY_BY_ADDRESS = 0x23,
+ kSID_READ_SCALING_DATA_BY_IDENTIFIER = 0x24,
+ kSID_SECURITY_ACCESS = 0x27,
+ kSID_COMMUNICATION_CONTROL = 0x28,
+ kSID_READ_PERIODIC_DATA_BY_IDENTIFIER = 0x2A,
+ kSID_DYNAMICALLY_DEFINE_DATA_IDENTIFIER = 0x2C,
+ kSID_WRITE_DATA_BY_IDENTIFIER = 0x2E,
+ kSID_INPUT_CONTROL_BY_IDENTIFIER = 0x2F,
+ kSID_ROUTINE_CONTROL = 0x31,
+ kSID_REQUEST_DOWNLOAD = 0x34,
+ kSID_REQUEST_UPLOAD = 0x35,
+ kSID_TRANSFER_DATA = 0x36,
+ kSID_REQUEST_TRANSFER_EXIT = 0x37,
+ kSID_REQUEST_FILE_TRANSFER = 0x38,
+ kSID_WRITE_MEMORY_BY_ADDRESS = 0x3D,
+ kSID_TESTER_PRESENT = 0x3E,
+ kSID_ACCESS_TIMING_PARAMETER = 0x83,
+ kSID_SECURED_DATA_TRANSMISSION = 0x84,
+ kSID_CONTROL_DTC_SETTING = 0x85,
+ kSID_RESPONSE_ON_EVENT = 0x86,
+};
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 0000000..d47ba5b
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,30 @@
+#include "util.h"
+
+#if UDS_CUSTOM_MILLIS
+#else
+uint32_t UDSMillis(void) {
+#if UDS_SYS == UDS_SYS_UNIX
+ struct timeval te;
+ gettimeofday(&te, NULL);
+ long long milliseconds = te.tv_sec * 1000LL + te.tv_usec / 1000;
+ return milliseconds;
+#elif UDS_SYS == UDS_SYS_WINDOWS
+ struct timespec ts;
+ timespec_get(&ts, TIME_UTC);
+ long long milliseconds = ts.tv_sec * 1000LL + ts.tv_nsec / 1000000;
+ return milliseconds;
+#elif UDS_SYS == UDS_SYS_ARDUINO
+ return millis();
+#elif UDS_SYS == UDS_SYS_ESP32
+ return esp_timer_get_time() / 1000;
+#else
+#error "UDSMillis() undefined!"
+#endif
+}
+#endif
+
+bool UDSSecurityAccessLevelIsReserved(uint8_t securityLevel) {
+ securityLevel &= 0x3f;
+ return (0 == securityLevel || (0x43 <= securityLevel && securityLevel >= 0x5E) ||
+ 0x7F == securityLevel);
+}
diff --git a/src/util.h b/src/util.h
new file mode 100644
index 0000000..fda75e2
--- /dev/null
+++ b/src/util.h
@@ -0,0 +1,42 @@
+#pragma once
+
+#include "sys.h"
+#include "config.h"
+
+#if UDS_ENABLE_ASSERT
+#include
+#else
+#define assert(x)
+#endif
+
+#if UDS_ENABLE_DBG_PRINT
+ #if defined(UDS_DBG_PRINT_IMPL)
+ #define UDS_DBG_PRINT UDS_DBG_PRINT_IMPL
+ #else
+ #include
+ #define UDS_DBG_PRINT printf
+ #endif
+#else
+#define UDS_DBG_PRINT(fmt, ...) ((void)fmt)
+#endif
+
+#define UDS_DBG_PRINTHEX(addr, len) \
+ for (int i = 0; i < len; i++) { \
+ UDS_DBG_PRINT("%02x,", ((uint8_t *)addr)[i]); \
+ } \
+ UDS_DBG_PRINT("\n");
+
+
+/* returns true if `a` is after `b` */
+static inline bool UDSTimeAfter(uint32_t a, uint32_t b) {
+ return ((int32_t)((int32_t)(b) - (int32_t)(a)) < 0);
+}
+
+/**
+ * @brief Get time in milliseconds
+ * @return current time in milliseconds
+ */
+uint32_t UDSMillis(void);
+
+
+bool UDSSecurityAccessLevelIsReserved(uint8_t securityLevel);
diff --git a/test/BUILD b/test/BUILD
index 4dbb91f..7fc4cea 100644
--- a/test/BUILD
+++ b/test/BUILD
@@ -4,14 +4,18 @@ cc_library(
"env.c",
"env.h",
"test.h",
- "//:iso14229_srcs",
- "//tp:srcs",
+ "//:iso14229.h",
+ "//:iso14229.c",
],
deps = [ "@cmocka" ],
defines = [
- "UDS_TP=UDS_TP_CUSTOM",
+ "UDS_TP_ISOTP_C_SOCKETCAN",
+ "UDS_TP_ISOTP_SOCK",
+ "UDS_TP_MOCK",
"UDS_CUSTOM_MILLIS",
- "UDS_DBG_PRINT=printf",
+ "UDS_ENABLE_DBG_PRINT",
+ "UDS_ENABLE_ASSERT",
+ "UDS_LINES",
],
copts = [ "-g", ],
)
@@ -110,8 +114,8 @@ sh_test(
cc_library(
name = "ultra_strict",
srcs = [
- "//:iso14229_srcs",
- "//tp:srcs",
+ "//:iso14229.h",
+ "//:iso14229.c",
],
copts = [
"-Werror",
diff --git a/test/env.c b/test/env.c
index b104df0..f70c8d3 100644
--- a/test/env.c
+++ b/test/env.c
@@ -5,9 +5,6 @@
#include
#include
#include
-#include "tp/isotp_c_socketcan.h"
-#include "tp/mock.h"
-#include "tp/isotp_sock.h"
static UDSServer_t *registeredServer = NULL;
static UDSClient_t *registeredClient = NULL;
diff --git a/test/test.h b/test/test.h
index a0c1445..61313d1 100644
--- a/test/test.h
+++ b/test/test.h
@@ -7,7 +7,6 @@
#include
#include "iso14229.h"
#include "test/env.h"
-#include "tp/mock.h"
#include
#define _TEST_INT_COND(a, b, cond) \
diff --git a/test/test_fuzz_server.c b/test/test_fuzz_server.c
index eeaf10b..ed6c994 100644
--- a/test/test_fuzz_server.c
+++ b/test/test_fuzz_server.c
@@ -18,11 +18,11 @@ typedef struct {
uint16_t client_sa;
uint16_t client_ta;
uint8_t client_func_req;
- uint8_t msg[UDS_BUFSIZE];
+ uint8_t msg[UDS_TP_MTU];
} StuffToFuzz_t;
static StuffToFuzz_t fuzz;
-static uint8_t client_recv_buf[UDS_BUFSIZE];
+static uint8_t client_recv_buf[UDS_TP_MTU];
static uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
printf("Whoah, got event %d\n", ev);
diff --git a/test_iso14229.c b/test_iso14229.c
deleted file mode 100644
index 6cfd587..0000000
--- a/test_iso14229.c
+++ /dev/null
@@ -1,875 +0,0 @@
-#define UDS_TP UDS_TP_CUSTOM
-#include
-#include
-#include
-#include
-#include
-#include
-#include "iso14229.h"
-#include "tp/mock.h"
-
-#define _ASSERT_INT_COND(a, b, cond) \
- { \
- int _a = a; \
- int _b = b; \
- if (!((_a)cond(_b))) { \
- printf("%s:%d (%d %s %d)\n", __FILE__, __LINE__, _a, #cond, _b); \
- fflush(stdout); \
- assert(a cond b); \
- } \
- }
-
-#define ASSERT_INT_LT(a, b) _ASSERT_INT_COND(a, b, <)
-#define ASSERT_INT_LE(a, b) _ASSERT_INT_COND(a, b, <=)
-#define ASSERT_INT_GE(a, b) _ASSERT_INT_COND(a, b, >=)
-#define ASSERT_INT_EQUAL(a, b) _ASSERT_INT_COND(a, b, ==)
-#define ASSERT_INT_NE(a, b) _ASSERT_INT_COND(a, b, !=)
-
-#define ASSERT_PTR_EQUAL(a, b) \
- { \
- const void *_a = a; \
- const void *_b = b; \
- if ((_a) != (_b)) { \
- printf("%s:%d (%p != %p)\n", __FILE__, __LINE__, _a, _b); \
- fflush(stdout); \
- assert(a == b); \
- } \
- }
-
-#define ASSERT_MEMORY_EQUAL(a, b, len) \
- { \
- const uint8_t *_a = (const uint8_t *)a; \
- const uint8_t *_b = (const uint8_t *)b; \
- if (memcmp(_a, _b, len)) { \
- printf("A:"); \
- for (unsigned int i = 0; i < len; i++) { \
- printf("%02x,", _a[i]); \
- } \
- printf(" (%s)\nB:", #a); \
- for (unsigned int i = 0; i < len; i++) { \
- printf("%02x,", _b[i]); \
- } \
- printf(" (%s)\n", #b); \
- fflush(stdout); \
- assert(0); \
- } \
- }
-
-#define ANSI_RESET "\033[0m"
-#define ANSI_BOLD "\033[1m"
-#define ANSI_BRIGHT_GREEN "\033[92m"
-#define ANSI_BRIGHT_MAGENTA "\033[95m"
-
-#define CLIENT_TARGET_ADDR (0x7E0U)
-#define CLIENT_TARGET_ADDR_FUNC (0x7DFU)
-#define CLIENT_SOURCE_ADDR (0x7E8U)
-
-#define SERVER_TARGET_ADDR (0x7E8U)
-#define SERVER_SOURCE_ADDR (0x7E0U)
-#define SERVER_SOURCE_ADDR_FUNC (0x7DFU)
-
-/*
- ctx.server_tp = (struct mocktransport){.hdl = {.recv = mock_transport_recv, \
- .send = mock_transport_send, \
- .poll = mock_transport_poll}, \
- .tag = "server"}; \
- ctx.client_tp = (struct mocktransport){.hdl = {.recv = mock_transport_recv, \
- .send = mock_transport_send, \
- .poll = mock_transport_poll}, \
- .tag = "client"}; \
- UDSClientInit(&ctx.client, &(UDSClientConfig_t){.tp = &ctx.client_tp.hdl}); \
- UDSServerInit(&ctx.server, &(UDSServerConfig_t){.tp = &ctx.server_tp.hdl});
- */
-
-#define SERVER_ONLY 0
-#define CLIENT_ONLY 1
-
-#define _TEST_SETUP_SILENT(test_type, param_str) \
- memset(&ctx, 0, sizeof(ctx)); \
- ctx.func_name = __PRETTY_FUNCTION__; \
- if (SERVER_ONLY == test_type) { \
- UDSServerInit(&ctx.server, &(UDSServerConfig_t){ \
- .tp = TPMockNew("server"), \
- .source_addr = SERVER_SOURCE_ADDR, \
- .target_addr = SERVER_TARGET_ADDR, \
- .source_addr_func = SERVER_SOURCE_ADDR_FUNC, \
- }); \
- ctx.mock_tp = TPMockNew("mock_client"); \
- } \
- if (CLIENT_ONLY == test_type) { \
- UDSClientInit(&ctx.client, &(UDSClientConfig_t){ \
- .tp = TPMockNew("client"), \
- .target_addr = CLIENT_TARGET_ADDR, \
- .source_addr = CLIENT_SOURCE_ADDR, \
- .target_addr_func = CLIENT_TARGET_ADDR_FUNC, \
- }); \
- ctx.mock_tp = TPMockNew("mock_server"); \
- } \
- char logfilename[256] = {0}; \
- snprintf(logfilename, sizeof(logfilename), "%s%s.log", ctx.func_name, param_str); \
- TPMockLogToFile(logfilename);
-
-#define TEST_SETUP(test_type) \
- _TEST_SETUP_SILENT(test_type, ""); \
- printf("%s\n", ctx.func_name);
-
-#define TEST_SETUP_PARAMETRIZED(test_type, params_list) \
- for (size_t i = 0; i < sizeof(params_list) / sizeof(params_list[0]); i++) { \
- char _param_str[128]; \
- snprintf(_param_str, sizeof(_param_str), "%s_p_%ld_%s", ctx.func_name, i, \
- (*(char **)(&(params_list[i])))); \
- _TEST_SETUP_SILENT(test_type, _param_str); \
- printf("%s\n", _param_str);
-
-#define TEST_TEARDOWN_PARAMETRIZED() \
- TPMockReset(); \
- printf(ANSI_BOLD "OK [p:%ld]\n" ANSI_RESET, i); \
- }
-
-#define TEST_TEARDOWN() \
- { \
- TPMockReset(); \
- printf(ANSI_BOLD "OK\n" ANSI_RESET); \
- }
-
-// TODO: parameterize and fuzz this
-#define DEFAULT_ISOTP_BUFSIZE (2048U)
-
-struct MockTransport {
- UDSTpHandle_t hdl;
- uint8_t recv_buf[DEFAULT_ISOTP_BUFSIZE];
- uint8_t send_buf[DEFAULT_ISOTP_BUFSIZE];
- uint16_t recv_size;
- uint16_t send_size;
- UDSTpAddr_t recv_ta_type;
- UDSTpAddr_t send_ta_type;
- UDSTpStatus_t status;
- const char *tag;
-};
-
-static void printhex(const uint8_t *addr, int len) {
- for (int i = 0; i < len; i++) {
- printf("%02x,", addr[i]);
- }
- printf("\n");
-}
-
-// static ssize_t mock_transport_recv(UDSTpHandle_t *hdl, UDSSDU_t *msg) {
-// assert(hdl);
-// struct MockTransport *tp = (struct MockTransport *)hdl;
-// size_t size = tp->recv_size;
-
-// if (msg->A_DataBufSize < size) {
-// return -ENOBUFS;
-// }
-
-// if (size) {
-// memmove((void *)msg->A_Data, tp->recv_buf, size);
-// tp->recv_size = 0;
-// memset(tp->recv_buf, 0, sizeof(tp->recv_buf));
-// printf(ANSI_BRIGHT_MAGENTA "<-%s_tp_recv-%04d- [%02ld] ", tp->tag, UDSMillis(), size);
-// printhex(msg->A_Data, size);
-// printf(ANSI_RESET);
-// }
-// return size;
-// }
-
-// static ssize_t mock_transport_send(UDSTpHandle_t *hdl, UDSSDU_t *msg) {
-// assert(hdl);
-// struct MockTransport *tp = (struct MockTransport *)hdl;
-// printf(ANSI_BRIGHT_GREEN "--%s_tp_send-%04d->[%02d] ", tp->tag, UDSMillis(), msg->A_Length);
-// printhex(msg->A_Data, msg->A_Length);
-// printf(ANSI_RESET);
-// assert(msg->A_Length); // why send zero?
-// memmove(tp->send_buf, msg->A_Data, msg->A_Length);
-// tp->send_size = msg->A_Length;
-// return msg->A_Length;
-// }
-
-// static UDSTpStatus_t mock_transport_poll(UDSTpHandle_t *hdl) {
-// assert(hdl);
-// struct MockTransport *tp = (struct MockTransport *)hdl;
-// return tp->status;
-// }
-
-typedef struct {
- UDSServer_t server;
- UDSClient_t client;
- UDSTpHandle_t *mock_tp;
- uint8_t mock_recv_buf[DEFAULT_ISOTP_BUFSIZE];
- struct MockTransport client_tp;
- uint32_t time_ms;
- uint32_t deadline;
- int call_count;
- const char *func_name;
-} Ctx_t;
-
-Ctx_t ctx;
-
-uint32_t UDSMillis() { return ctx.time_ms; }
-
-static void poll_ctx(Ctx_t *ctx) {
- if (ctx->server.tp) {
- UDSServerPoll(&ctx->server);
- }
- if (ctx->client.tp) {
- UDSClientPoll(&ctx->client);
- }
- ctx->time_ms++;
-}
-
-/*
- memmove(&ctx.server_tp.recv_buf, d1, sizeof(d1)); \
- ctx.server_tp.recv_ta_type = reqType; \
- ctx.server_tp.recv_size = sizeof(d1); \
- poll_ctx(&ctx);
-*/
-
-#define SEND_TO_SERVER(d1, reqType) \
- { \
- UDSSDU_t msg = { \
- .A_Mtype = UDS_A_MTYPE_DIAG, \
- .A_Data = d1, \
- .A_Length = sizeof(d1), \
- .A_SA = CLIENT_SOURCE_ADDR, \
- .A_TA = \
- reqType == UDS_A_TA_TYPE_PHYSICAL ? SERVER_SOURCE_ADDR : SERVER_SOURCE_ADDR_FUNC, \
- .A_TA_Type = (int)reqType, \
- }; \
- ctx.mock_tp->send(ctx.mock_tp, &msg); \
- }
-
-#define ASSERT_CLIENT_SENT(d1, reqType) \
- { \
- UDSSDU_t msg = { \
- .A_DataBufSize = DEFAULT_ISOTP_BUFSIZE, \
- .A_Data = ctx.mock_recv_buf, \
- }; \
- int recv_len = ctx.mock_tp->recv(ctx.mock_tp, &msg); \
- ASSERT_INT_EQUAL(recv_len, sizeof(d1)); \
- ASSERT_MEMORY_EQUAL(ctx.mock_recv_buf, d1, sizeof(d1)); \
- if (reqType == UDS_A_TA_TYPE_PHYSICAL) { \
- ASSERT_INT_EQUAL(msg.A_TA, SERVER_SOURCE_ADDR); \
- } else if (reqType == UDS_A_TA_TYPE_FUNCTIONAL) { \
- ASSERT_INT_EQUAL(msg.A_TA, SERVER_SOURCE_ADDR_FUNC); \
- } else { \
- assert(0); \
- } \
- }
-
-// send data to the client
-static void send_to_client(const uint8_t *d1, size_t len, UDSTpAddr_t reqType) {
- assert(len <= sizeof(ctx.client_tp.recv_buf));
- ctx.mock_tp->send(ctx.mock_tp, &(UDSSDU_t){
- .A_Mtype = UDS_A_MTYPE_DIAG,
- .A_Data = d1,
- .A_Length = len,
- .A_SA = SERVER_SOURCE_ADDR,
- .A_TA = SERVER_TARGET_ADDR,
- .A_TA_Type = (int)reqType,
- });
- // memmove(&ctx.client_tp.recv_buf, d1, len);
- // ctx.client_tp.recv_ta_type = reqType;
- // ctx.client_tp.recv_size = len;
- poll_ctx(&ctx);
-}
-
-#define SEND_TO_CLIENT(d1, reqType) send_to_client(d1, sizeof(d1), reqType);
-/*
- while (0 == ctx.server_tp.send_size) { \
- poll_ctx(&ctx); \
- ASSERT_INT_LE(ctx.time_ms, deadline); \
- } \
- */
-
-// expect a server response within a timeout
-#define EXPECT_RESPONSE_WITHIN_MILLIS(d1, reqType, timeout_ms) \
- { \
- uint32_t deadline = ctx.time_ms + timeout_ms + 1; \
- UDSSDU_t msg = { \
- .A_DataBufSize = DEFAULT_ISOTP_BUFSIZE, \
- .A_Data = ctx.mock_recv_buf, \
- }; \
- while (0 == ctx.mock_tp->recv(ctx.mock_tp, &msg)) { \
- poll_ctx(&ctx); \
- printf("%d, %d, %d\n", UDSMillis(), ctx.time_ms, deadline); \
- ASSERT_INT_LE(ctx.time_ms, deadline); \
- } \
- printhex(msg.A_Data, msg.A_Length); \
- ASSERT_INT_EQUAL(msg.A_Length, sizeof(d1)); \
- ASSERT_MEMORY_EQUAL(msg.A_Data, d1, sizeof(d1)); \
- ASSERT_INT_EQUAL((int)msg.A_TA_Type, reqType); \
- }
-
-// expect no server response within a timeout
-#define EXPECT_NO_RESPONSE_FOR_MILLIS(timeout_ms) \
- { \
- uint32_t deadline = ctx.time_ms + timeout_ms; \
- while (ctx.time_ms <= deadline) { \
- poll_ctx(&ctx); \
- UDSSDU_t msg = { \
- .A_DataBufSize = DEFAULT_ISOTP_BUFSIZE, \
- .A_Data = ctx.mock_recv_buf, \
- }; \
- int resp_len = ctx.mock_tp->recv(ctx.mock_tp, &msg); \
- ASSERT_INT_EQUAL(resp_len, 0); \
- } \
- }
-
-void testServer0x10DiagSessCtrlIsDisabledByDefault() {
- TEST_SETUP(SERVER_ONLY);
- const uint8_t REQ[] = {0x10, 0x02};
- SEND_TO_SERVER(REQ, UDS_A_TA_TYPE_PHYSICAL);
- const uint8_t RESP[] = {0x7f, 0x10, 0x11};
- EXPECT_RESPONSE_WITHIN_MILLIS(RESP, UDS_A_TA_TYPE_PHYSICAL, 50);
- TEST_TEARDOWN();
-}
-
-void testServer0x10DiagSessCtrlFunctionalRequest() {
- TEST_SETUP(SERVER_ONLY);
- // sending a diagnostic session control request functional broadcast
- const uint8_t REQ[] = {0x10, 0x03};
- SEND_TO_SERVER(REQ, UDS_A_TA_TYPE_FUNCTIONAL);
- // should receive a physical response
- const uint8_t RESP[] = {0x7f, 0x10, 0x11};
- EXPECT_RESPONSE_WITHIN_MILLIS(RESP, UDS_A_TA_TYPE_PHYSICAL, 50);
- TEST_TEARDOWN();
-}
-
-uint8_t fn1_callCount = 0;
-uint8_t fn1(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
- switch (ev) {
- case UDS_SRV_EVT_EcuReset:
- fn1_callCount += 1;
- return kPositiveResponse;
- default:
- ASSERT_INT_EQUAL(UDS_SRV_EVT_DoScheduledReset, ev);
- return kPositiveResponse;
- }
-}
-
-// Special-case of ECU reset service
-// ISO-14229-1 2013 9.3.1:
-// on the behaviour of the ECU from the time following the positive response message to the ECU
-// reset request: It is recommended that during this time the ECU does not accept any request
-// messages and send any response messages.
-void testServer0x11DoesNotSendOrReceiveMessagesAfterECUReset() {
- TEST_SETUP(SERVER_ONLY);
- ctx.server.fn = fn1;
-
- const uint8_t REQ[] = {0x11, 0x01};
- const uint8_t RESP[] = {0x51, 0x01};
-
- // Sending the first ECU reset should result in a response
- SEND_TO_SERVER(REQ, UDS_A_TA_TYPE_PHYSICAL);
- EXPECT_RESPONSE_WITHIN_MILLIS(RESP, UDS_A_TA_TYPE_PHYSICAL, 50);
- // Sending subsequent ECU reset requests should not receive any response
- SEND_TO_SERVER(REQ, UDS_A_TA_TYPE_PHYSICAL);
- EXPECT_NO_RESPONSE_FOR_MILLIS(5000);
-
- // The ECU reset handler should have been called once.
- ASSERT_INT_EQUAL(fn1_callCount, 1);
- TEST_TEARDOWN();
-}
-
-uint8_t fn2(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
- ASSERT_INT_EQUAL(UDS_SRV_EVT_ReadDataByIdent, ev);
- const uint8_t vin[] = {0x57, 0x30, 0x4C, 0x30, 0x30, 0x30, 0x30, 0x34, 0x33,
- 0x4D, 0x42, 0x35, 0x34, 0x31, 0x33, 0x32, 0x36};
- const uint8_t data_0x010A[] = {0xA6, 0x66, 0x07, 0x50, 0x20, 0x1A,
- 0x00, 0x63, 0x4A, 0x82, 0x7E};
- const uint8_t data_0x0110[] = {0x8C};
-
- UDSRDBIArgs_t *r = (UDSRDBIArgs_t *)arg;
- switch (r->dataId) {
- case 0xF190:
- return r->copy(srv, vin, sizeof(vin));
- case 0x010A:
- return r->copy(srv, data_0x010A, sizeof(data_0x010A));
- case 0x0110:
- return r->copy(srv, data_0x0110, sizeof(data_0x0110));
- default:
- return kRequestOutOfRange;
- }
- return kPositiveResponse;
-}
-
-void testServer0x22RDBI1() {
- TEST_SETUP(SERVER_ONLY);
- ctx.server.fn = fn2;
- {
- uint8_t REQ[] = {0x22, 0xF1, 0x90};
- SEND_TO_SERVER(REQ, UDS_A_TA_TYPE_PHYSICAL);
- uint8_t RESP[] = {0x62, 0xF1, 0x90, 0x57, 0x30, 0x4C, 0x30, 0x30, 0x30, 0x30,
- 0x34, 0x33, 0x4D, 0x42, 0x35, 0x34, 0x31, 0x33, 0x32, 0x36};
- EXPECT_RESPONSE_WITHIN_MILLIS(RESP, UDS_A_TA_TYPE_PHYSICAL, 50);
- }
- {
- uint8_t REQ[] = {0x22, 0xF1, 0x91};
- SEND_TO_SERVER(REQ, UDS_A_TA_TYPE_PHYSICAL);
- uint8_t RESP[] = {0x7F, 0x22, 0x31};
- EXPECT_RESPONSE_WITHIN_MILLIS(RESP, UDS_A_TA_TYPE_PHYSICAL, 50);
- }
- TEST_TEARDOWN();
-}
-
-uint8_t fn10(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
- ASSERT_INT_EQUAL(ev, UDS_SRV_EVT_ReadMemByAddr);
- UDSReadMemByAddrArgs_t *r = (UDSReadMemByAddrArgs_t *)arg;
- // 1 2 3 4 5 6 7 8
- ASSERT_PTR_EQUAL(r->memAddr, (void *)0x000055555555f0c8);
- ASSERT_INT_EQUAL(r->memSize, 4);
- uint8_t FakeData[4] = {0x01, 0x02, 0x03, 0x04};
- return r->copy(srv, FakeData, r->memSize);
-}
-
-void testServer0x23ReadMemoryByAddress() {
- TEST_SETUP(SERVER_ONLY);
- ctx.server.fn = fn10;
- uint8_t REQ[] = {0x23, 0x18, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0xf0, 0xc8, 0x04};
- SEND_TO_SERVER(REQ, UDS_A_TA_TYPE_PHYSICAL);
- uint8_t RESP[] = {0x63, 0x01, 0x02, 0x03, 0x04};
- EXPECT_RESPONSE_WITHIN_MILLIS(RESP, UDS_A_TA_TYPE_PHYSICAL, 50);
- TEST_TEARDOWN();
-}
-
-uint8_t fn4(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
- switch (ev) {
- case UDS_SRV_EVT_SecAccessRequestSeed: {
- UDSSecAccessRequestSeedArgs_t *r = (UDSSecAccessRequestSeedArgs_t *)arg;
- const uint8_t seed[] = {0x36, 0x57};
- ASSERT_INT_NE(r->level, srv->securityLevel);
- return r->copySeed(srv, seed, sizeof(seed));
- break;
- }
- case UDS_SRV_EVT_SecAccessValidateKey: {
- UDSSecAccessValidateKeyArgs_t *r = (UDSSecAccessValidateKeyArgs_t *)arg;
- const uint8_t expected_key[] = {0xC9, 0xA9};
- ASSERT_INT_EQUAL(r->len, sizeof(expected_key));
- ASSERT_MEMORY_EQUAL(r->key, expected_key, sizeof(expected_key));
- break;
- }
- default:
- assert(0);
- }
- return kPositiveResponse;
-}
-
-// UDS-1 2013 9.4.5.2
-// UDS-1 2013 9.4.5.3
-void testServer0x27SecurityAccess() {
- TEST_SETUP(SERVER_ONLY);
- ctx.server.fn = fn4;
-
- // the server security level after initialization should be 0
- ASSERT_INT_EQUAL(ctx.server.securityLevel, 0);
-
- // sending a seed request should get this response
- const uint8_t SEED_REQUEST[] = {0x27, 0x01};
- const uint8_t SEED_RESPONSE[] = {0x67, 0x01, 0x36, 0x57};
- SEND_TO_SERVER(SEED_REQUEST, UDS_A_TA_TYPE_PHYSICAL);
- EXPECT_RESPONSE_WITHIN_MILLIS(SEED_RESPONSE, UDS_A_TA_TYPE_PHYSICAL, 50);
-
- // subsequently sending an unlock request should get this response
- const uint8_t UNLOCK_REQUEST[] = {0x27, 0x02, 0xC9, 0xA9};
- const uint8_t UNLOCK_RESPONSE[] = {0x67, 0x02};
- SEND_TO_SERVER(UNLOCK_REQUEST, UDS_A_TA_TYPE_PHYSICAL);
- EXPECT_RESPONSE_WITHIN_MILLIS(UNLOCK_RESPONSE, UDS_A_TA_TYPE_PHYSICAL, 50);
-
- // sending the same seed request should now result in the "already unlocked" response
- const uint8_t ALREADY_UNLOCKED_RESPONSE[] = {0x67, 0x01, 0x00, 0x00};
- SEND_TO_SERVER(SEED_REQUEST, UDS_A_TA_TYPE_PHYSICAL);
- EXPECT_RESPONSE_WITHIN_MILLIS(ALREADY_UNLOCKED_RESPONSE, UDS_A_TA_TYPE_PHYSICAL, 50);
-
- // Additionally, the security level should now be 1
- ASSERT_INT_EQUAL(ctx.server.securityLevel, 1);
- TEST_TEARDOWN();
-}
-
-static uint8_t ReturnRCRRP(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
- return kRequestCorrectlyReceived_ResponsePending;
-}
-static uint8_t ReturnPositiveResponse(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
- return kPositiveResponse;
-}
-
-// ISO-14229-1 2013 Table A.1 Byte Value 0x78: requestCorrectlyReceived-ResponsePending
-// "This NRC is in general supported by each diagnostic service".
-void testServer0x31RCRRP() {
- TEST_SETUP(SERVER_ONLY);
- // When a server handler func initially returns RRCRP
- ctx.server.fn = ReturnRCRRP;
-
- // sending a request to the server should return RCRRP
- const uint8_t REQUEST[] = {0x31, 0x01, 0x12, 0x34};
- const uint8_t RCRRP[] = {0x7F, 0x31, 0x78};
- SEND_TO_SERVER(REQUEST, UDS_A_TA_TYPE_PHYSICAL);
- EXPECT_RESPONSE_WITHIN_MILLIS(RCRRP, UDS_A_TA_TYPE_PHYSICAL, 50)
-
- // The server should again respond within p2_star ms, and keep responding
- EXPECT_RESPONSE_WITHIN_MILLIS(RCRRP, UDS_A_TA_TYPE_PHYSICAL, 50)
- EXPECT_RESPONSE_WITHIN_MILLIS(RCRRP, UDS_A_TA_TYPE_PHYSICAL, 50)
- EXPECT_RESPONSE_WITHIN_MILLIS(RCRRP, UDS_A_TA_TYPE_PHYSICAL, 50)
- EXPECT_RESPONSE_WITHIN_MILLIS(RCRRP, UDS_A_TA_TYPE_PHYSICAL, 50)
- EXPECT_RESPONSE_WITHIN_MILLIS(RCRRP, UDS_A_TA_TYPE_PHYSICAL, 50)
- EXPECT_RESPONSE_WITHIN_MILLIS(RCRRP, UDS_A_TA_TYPE_PHYSICAL, 50)
-
- // When the server handler func now returns a positive response
- ctx.server.fn = ReturnPositiveResponse;
-
- // the server's next response should be a positive one
- const uint8_t POSITIVE_RESPONSE[] = {0x71, 0x01, 0x12, 0x34};
- EXPECT_RESPONSE_WITHIN_MILLIS(POSITIVE_RESPONSE, UDS_A_TA_TYPE_PHYSICAL, 50)
-
- TEST_TEARDOWN();
-}
-
-void testServer0x34NotEnabled() {
- TEST_SETUP(SERVER_ONLY);
- // when no handler function is installed, sending this request to the server
- const uint8_t IN[] = {0x34, 0x11, 0x33, 0x60, 0x20, 0x00, 0x00, 0xFF, 0xFF};
- SEND_TO_SERVER(IN, UDS_A_TA_TYPE_PHYSICAL);
-
- // should return a kServiceNotSupported response
- const uint8_t OUT[] = {0x7F, 0x34, 0x11};
- EXPECT_RESPONSE_WITHIN_MILLIS(OUT, UDS_A_TA_TYPE_PHYSICAL, 50);
- TEST_TEARDOWN();
-}
-
-uint8_t fn7(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
- ASSERT_INT_EQUAL(ev, UDS_SRV_EVT_RequestDownload);
- UDSRequestDownloadArgs_t *r = (UDSRequestDownloadArgs_t *)arg;
- ASSERT_INT_EQUAL(0x11, r->dataFormatIdentifier);
- ASSERT_PTR_EQUAL((void *)0x602000, r->addr);
- ASSERT_INT_EQUAL(0x00FFFF, r->size);
- ASSERT_INT_EQUAL(r->maxNumberOfBlockLength, UDS_SERVER_DEFAULT_XFER_DATA_MAX_BLOCKLENGTH);
- r->maxNumberOfBlockLength = 0x0081;
- return kPositiveResponse;
-}
-
-void testServer0x34() {
- TEST_SETUP(SERVER_ONLY);
- // when a handler is installed that implements UDS-1:2013 Table 415
- ctx.server.fn = fn7;
-
- // sending this request to the server
- uint8_t REQ[] = {0x34, 0x11, 0x33, 0x60, 0x20, 0x00, 0x00, 0xFF, 0xFF};
- SEND_TO_SERVER(REQ, UDS_A_TA_TYPE_PHYSICAL);
-
- // should receive a positive response matching UDS-1:2013 Table 415
- uint8_t RESP[] = {0x74, 0x20, 0x00, 0x81};
- EXPECT_RESPONSE_WITHIN_MILLIS(RESP, UDS_A_TA_TYPE_PHYSICAL, 50)
- TEST_TEARDOWN();
-}
-
-/* UDS-1 2013 Table 72 */
-void testServer0x3ESuppressPositiveResponse() {
- TEST_SETUP(SERVER_ONLY);
- ctx.server.fn = ReturnPositiveResponse;
- // when the suppressPositiveResponse bit is set
- const uint8_t REQ[] = {0x3E, 0x80};
- // there should be no response
- SEND_TO_SERVER(REQ, UDS_A_TA_TYPE_PHYSICAL);
- EXPECT_NO_RESPONSE_FOR_MILLIS(5000);
- TEST_TEARDOWN();
-}
-
-void testServer0x83DiagnosticSessionControl() {
- TEST_SETUP(SERVER_ONLY);
- ctx.server.fn = ReturnPositiveResponse;
- // the server sessionType after initialization should be kDefaultSession.
- ASSERT_INT_EQUAL(ctx.server.sessionType, kDefaultSession);
-
- // When the suppressPositiveResponse bit is set, there should be no response.
- const uint8_t REQ[] = {0x10, 0x83};
- SEND_TO_SERVER(REQ, UDS_A_TA_TYPE_PHYSICAL);
- EXPECT_NO_RESPONSE_FOR_MILLIS(5000);
- // and the server sessionType should have changed
- ASSERT_INT_EQUAL(ctx.server.sessionType, kExtendedDiagnostic);
- TEST_TEARDOWN();
-}
-
-uint8_t fn9(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
- ASSERT_INT_EQUAL(UDS_SRV_EVT_SessionTimeout, ev);
- ctx.call_count++;
- return kPositiveResponse;
-}
-
-void testServerSessionTimeout() {
- struct {
- const char *tag;
- uint8_t (*fn)(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg);
- uint8_t sessType;
- int expectedCallCount;
- } p[] = {
- {.tag = "no timeout", .fn = fn9, .sessType = kDefaultSession, .expectedCallCount = 0},
- {.tag = "timeout", .fn = fn9, .sessType = kProgrammingSession, .expectedCallCount = 1},
- {.tag = "no handler", .fn = NULL, .sessType = kProgrammingSession, .expectedCallCount = 0},
- };
- TEST_SETUP_PARAMETRIZED(SERVER_ONLY, p);
- ctx.server.fn = p[i].fn;
- ctx.server.sessionType = p[i].sessType;
- while (ctx.time_ms < 5000)
- poll_ctx(&ctx);
- ASSERT_INT_GE(ctx.call_count, p[i].expectedCallCount);
- TEST_TEARDOWN_PARAMETRIZED();
-}
-
-#define POLL_UNTIL_TIME_MS(abs_time_ms) \
- while (ctx.time_ms < (abs_time_ms)) \
- poll_ctx(&ctx)
-
-#define POLL_FOR_MS(duration_ms) \
- { \
- uint32_t start_time_ms = ctx.time_ms; \
- while (ctx.time_ms < (start_time_ms + duration_ms)) \
- poll_ctx(&ctx); \
- }
-
-void testClientP2TimeoutExceeded() {
- TEST_SETUP(CLIENT_ONLY);
- // when sending a request that receives no response
- UDSSendECUReset(&ctx.client, kHardReset);
-
- // before p2 ms has elapsed, the client should have no error
- POLL_UNTIL_TIME_MS(UDS_CLIENT_DEFAULT_P2_MS - 10);
- ASSERT_INT_EQUAL(UDS_OK, ctx.client.err);
-
- // after p2 ms has elapsed, the client should have a timeout error
- POLL_UNTIL_TIME_MS(UDS_CLIENT_DEFAULT_P2_MS + 10);
- ASSERT_INT_EQUAL(UDS_ERR_TIMEOUT, ctx.client.err);
- TEST_TEARDOWN();
-}
-
-void testClientP2TimeoutNotExceeded() {
- TEST_SETUP(CLIENT_ONLY);
- // a client that sends an request
- UDSSendECUReset(&ctx.client, kHardReset);
-
- // which receives a positive response
- const uint8_t POSITIVE_RESPONSE[] = {0x51, 0x01};
- SEND_TO_CLIENT(POSITIVE_RESPONSE, UDS_A_TA_TYPE_PHYSICAL);
-
- POLL_UNTIL_TIME_MS(UDS_CLIENT_DEFAULT_P2_MS + 10);
- // should return to the idle state
- ASSERT_INT_EQUAL(kRequestStateIdle, ctx.client.state);
- // and should have no error.
- ASSERT_INT_EQUAL(UDS_OK, ctx.client.err);
- TEST_TEARDOWN();
-}
-
-void testClientSuppressPositiveResponse() {
- TEST_SETUP(CLIENT_ONLY);
- // Setting the suppressPositiveResponse flag before sending a request
- ctx.client.options |= UDS_SUPPRESS_POS_RESP;
- UDSSendECUReset(&ctx.client, kHardReset);
-
- // and not receiving a response after approximately p2 ms
- POLL_UNTIL_TIME_MS(UDS_CLIENT_DEFAULT_P2_MS + 10);
-
- // should not result in an error.
- ASSERT_INT_EQUAL(UDS_OK, ctx.client.err);
- ASSERT_INT_EQUAL(kRequestStateIdle, ctx.client.state);
- TEST_TEARDOWN();
-}
-
-void testClientBusy() {
- TEST_SETUP(CLIENT_ONLY);
- // Sending a request should not return an error
- ASSERT_INT_EQUAL(UDS_OK, UDSSendECUReset(&ctx.client, kHardReset));
-
- // unless there is an existing unresolved request
- ASSERT_INT_EQUAL(UDS_ERR_BUSY, UDSSendECUReset(&ctx.client, kHardReset));
- TEST_TEARDOWN();
-}
-
-void testClient0x11ECUReset() {
- TEST_SETUP(CLIENT_ONLY);
- const uint8_t GOOD[] = {0x51, 0x01};
- const uint8_t BAD_SID[] = {0x50, 0x01};
- const uint8_t TOO_SHORT[] = {0x51};
- const uint8_t BAD_SUBFUNC[] = {0x51, 0x02};
- const uint8_t NEG[] = {0x7F, 0x11, 0x10};
-#define CASE(d1, opt, err) \
- { \
- .tag = "resp: " #d1 ", expected_err: " #err, .resp = d1, .resp_len = sizeof(d1), \
- .options = opt, .expected_err = err \
- }
- struct {
- const char *tag;
- const uint8_t *resp;
- size_t resp_len;
- uint8_t options;
- UDSErr_t expected_err;
- } p[] = {
- CASE(GOOD, 0, UDS_OK),
- CASE(BAD_SID, 0, UDS_ERR_SID_MISMATCH),
- CASE(TOO_SHORT, 0, UDS_ERR_RESP_TOO_SHORT),
- CASE(BAD_SUBFUNC, 0, UDS_ERR_SUBFUNCTION_MISMATCH),
- CASE(NEG, 0, UDS_OK),
- CASE(NEG, UDS_NEG_RESP_IS_ERR, UDS_ERR_NEG_RESP),
- };
-#undef CASE
- TEST_SETUP_PARAMETRIZED(CLIENT_ONLY, p);
- // sending a request with these options
- ctx.client.options = p[i].options;
- UDSSendECUReset(&ctx.client, kHardReset);
- // that receives this response
- send_to_client(p[i].resp, p[i].resp_len, UDS_A_TA_TYPE_PHYSICAL);
- // should return to the idle state
- POLL_UNTIL_TIME_MS(UDS_CLIENT_DEFAULT_P2_MS + 10);
- ASSERT_INT_EQUAL(kRequestStateIdle, ctx.client.state);
- // with the expected error.
- ASSERT_INT_EQUAL(p[i].expected_err, ctx.client.err);
- TEST_TEARDOWN_PARAMETRIZED();
-}
-
-void testClient0x22RDBITxBufferTooSmall() {
- TEST_SETUP(CLIENT_ONLY);
-
- // attempting to send a request payload of 6 bytes
- uint16_t didList[] = {0x0001, 0x0002, 0x0003};
-
- // which is larger than the underlying buffer
- ctx.client.send_buf_size = 4;
-
- // should return an error
- ASSERT_INT_EQUAL(UDS_ERR_INVALID_ARG,
- UDSSendRDBI(&ctx.client, didList, sizeof(didList) / sizeof(didList[0])))
-
- // and no data should be sent
- ASSERT_INT_EQUAL(ctx.client.send_size, 0);
- TEST_TEARDOWN();
-}
-
-void testClient0x22RDBIUnpackResponse() {
- TEST_SETUP(CLIENT_ONLY);
- uint8_t RESPONSE[] = {0x72, 0x12, 0x34, 0x00, 0x00, 0xAA, 0x00, 0x56, 0x78, 0xAA, 0xBB};
- UDSClient_t client;
- memmove(client.recv_buf, RESPONSE, sizeof(RESPONSE));
- client.recv_size = sizeof(RESPONSE);
- uint8_t buf[4];
- uint16_t offset = 0;
- int err = 0;
- err = UDSUnpackRDBIResponse(&client, 0x1234, buf, 4, &offset);
- ASSERT_INT_EQUAL(err, UDS_OK);
- uint32_t d0 = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3];
- ASSERT_INT_EQUAL(d0, 0x0000AA00);
- err = UDSUnpackRDBIResponse(&client, 0x1234, buf, 2, &offset);
- ASSERT_INT_EQUAL(err, UDS_ERR_DID_MISMATCH);
- err = UDSUnpackRDBIResponse(&client, 0x5678, buf, 20, &offset);
- ASSERT_INT_EQUAL(err, UDS_ERR_RESP_TOO_SHORT);
- err = UDSUnpackRDBIResponse(&client, 0x5678, buf, 2, &offset);
- ASSERT_INT_EQUAL(err, UDS_OK);
- uint16_t d1 = (buf[0] << 8) + buf[1];
- ASSERT_INT_EQUAL(d1, 0xAABB);
- err = UDSUnpackRDBIResponse(&client, 0x5678, buf, 1, &offset);
- ASSERT_INT_EQUAL(err, UDS_ERR_RESP_TOO_SHORT);
- ASSERT_INT_EQUAL(offset, sizeof(RESPONSE));
- TEST_TEARDOWN();
-}
-
-void testClient0x31RCRRP() {
- TEST_SETUP(CLIENT_ONLY);
-
- { // Case 1: RCRRP Timeout
- // When a request is sent
- UDSSendRoutineCtrl(&ctx.client, kStartRoutine, 0x1234, NULL, 0);
-
- // that receives an RCRRP response
- const uint8_t RCRRP[] = {0x7F, 0x31, 0x78}; // RequestCorrectly-ReceievedResponsePending
- SEND_TO_CLIENT(RCRRP, UDS_A_TA_TYPE_PHYSICAL);
-
- // that remains unresolved at a time between p2 ms and p2 star ms
- POLL_FOR_MS(UDS_CLIENT_DEFAULT_P2_MS + 10);
- // the client should still be pending.
- ASSERT_INT_EQUAL(kRequestStateAwaitResponse, ctx.client.state)
-
- // after p2_star has elapsed, the client should timeout
- POLL_FOR_MS(UDS_CLIENT_DEFAULT_P2_STAR_MS + 10);
- ASSERT_INT_EQUAL(kRequestStateIdle, ctx.client.state)
- ASSERT_INT_EQUAL(ctx.client.err, UDS_ERR_TIMEOUT);
- }
-
- { // Case 2: Positive Response Received
- // When a request is sent
- UDSSendRoutineCtrl(&ctx.client, kStartRoutine, 0x1234, NULL, 0);
-
- // that receives an RCRRP response
- const uint8_t RCRRP[] = {0x7F, 0x31, 0x78}; // RequestCorrectly-ReceievedResponsePending
- SEND_TO_CLIENT(RCRRP, UDS_A_TA_TYPE_PHYSICAL);
-
- // that remains unresolved at a time between p2 ms and p2 star ms
- POLL_FOR_MS(UDS_CLIENT_DEFAULT_P2_MS + 10);
- // the client should still be pending.
- ASSERT_INT_EQUAL(ctx.client.err, UDS_OK);
- ASSERT_INT_EQUAL(kRequestStateAwaitResponse, ctx.client.state)
-
- // When the client receives a positive response from the server
- const uint8_t POSITIVE_RESPONSE[] = {0x71, 0x01, 0x12, 0x34};
- SEND_TO_CLIENT(POSITIVE_RESPONSE, UDS_A_TA_TYPE_PHYSICAL);
-
- POLL_FOR_MS(5);
-
- // the client should return to the idle state with no error
- ASSERT_INT_EQUAL(kRequestStateIdle, ctx.client.state)
- ASSERT_INT_EQUAL(ctx.client.err, UDS_OK);
- }
-
- TEST_TEARDOWN();
-}
-
-void testClient0x34RequestDownload() {
- TEST_SETUP(CLIENT_ONLY);
- // When RequestDownload is called with these arguments
- ASSERT_INT_EQUAL(UDS_OK, UDSSendRequestDownload(&ctx.client, 0x11, 0x33, 0x602000, 0x00FFFF));
-
- // the bytes sent should match UDS-1 2013 Table 415
- const uint8_t CORRECT_REQUEST[] = {0x34, 0x11, 0x33, 0x60, 0x20, 0x00, 0x00, 0xFF, 0xFF};
- ASSERT_CLIENT_SENT(CORRECT_REQUEST, UDS_A_TA_TYPE_PHYSICAL);
- TEST_TEARDOWN();
-}
-
-void testClient0x34UDSUnpackRequestDownloadResponse() {
- TEST_SETUP(CLIENT_ONLY);
- struct RequestDownloadResponse resp;
-
- // When the following raw bytes are received
- uint8_t RESPONSE[] = {0x74, 0x20, 0x00, 0x81};
- UDSClient_t client;
- memmove(client.recv_buf, RESPONSE, sizeof(RESPONSE));
- client.recv_size = sizeof(RESPONSE);
-
- UDSErr_t err = UDSUnpackRequestDownloadResponse(&client, &resp);
-
- // they should unpack without error
- ASSERT_INT_EQUAL(err, UDS_OK);
- ASSERT_INT_EQUAL(resp.maxNumberOfBlockLength, 0x81);
- TEST_TEARDOWN();
-}
-
-int main() {
- testServer0x10DiagSessCtrlIsDisabledByDefault();
- testServer0x10DiagSessCtrlFunctionalRequest();
- testServer0x11DoesNotSendOrReceiveMessagesAfterECUReset();
- testServer0x22RDBI1();
- testServer0x23ReadMemoryByAddress();
- testServer0x27SecurityAccess();
- testServer0x31RCRRP();
- testServer0x34NotEnabled();
- testServer0x34();
- testServer0x3ESuppressPositiveResponse();
- testServer0x83DiagnosticSessionControl();
- testServerSessionTimeout();
-
- testClientP2TimeoutExceeded();
- testClientP2TimeoutNotExceeded();
- testClientSuppressPositiveResponse();
- testClientBusy();
- testClient0x11ECUReset();
- testClient0x22RDBITxBufferTooSmall();
- testClient0x22RDBIUnpackResponse();
- testClient0x31RCRRP();
- testClient0x34RequestDownload();
- testClient0x34UDSUnpackRequestDownloadResponse();
-}
diff --git a/tp/BUILD b/tp/BUILD
deleted file mode 100644
index bf3e8bc..0000000
--- a/tp/BUILD
+++ /dev/null
@@ -1,63 +0,0 @@
-package(default_visibility = ["//visibility:public"])
-
-cc_library(
- name="mock",
- srcs=[
- "mock.c",
- "mock.h",
- "//:iso14229.h"
- ],
-)
-
-cc_library(
- name="isotp_sock",
- srcs=[
- "isotp_sock.c",
- "isotp_sock.h",
- "//:iso14229.h"
- ],
-)
-
-
-filegroup(
- name="isotp_c_srcs",
- srcs=[
- "isotp-c/isotp.c",
- "isotp-c/isotp.h",
- "isotp-c/isotp_config.h",
- "isotp-c/isotp_defines.h",
- ],
-)
-
-cc_library(
- name="isotp_c",
- srcs=[":isotp_c_srcs"],
- copts=["-Wno-unused-parameter"],
-)
-
-cc_library(
- name="isotp_c_socketcan",
- srcs=[
- "isotp_c_socketcan.c",
- "isotp_c_socketcan.h",
- "//:iso14229.h",
- ],
- deps = [
- ":isotp_c",
- ],
-)
-
-filegroup(
- name="srcs",
- srcs = [
- "mock.c",
- "mock.h",
- "isotp_sock.c",
- "isotp_sock.h",
- "isotp_c_socketcan.c",
- "isotp_c_socketcan.h",
- "isotp_c.c",
- "isotp_c.h",
- ":isotp_c_srcs",
- ]
-)
From 4b327a4a61dbd63b4e8b32ed780c158d8bbdda2f Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Sat, 9 Dec 2023 21:59:51 -0700
Subject: [PATCH 14/56] fix 0x27 test
---
WORKSPACE | 8 +-
src/sys_unix.h | 1 +
test/test_server_0x27_security_access.c | 97 +++++++++++++++++++++++--
test/test_tp_compliance.c | 1 -
4 files changed, 91 insertions(+), 16 deletions(-)
diff --git a/WORKSPACE b/WORKSPACE
index 6e5bd08..0e5a5d5 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -1,17 +1,11 @@
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
-
-# Hedron's Compile Commands Extractor for Bazel
-# https://github.com/hedronvision/bazel-compile-commands-extractor
http_archive(
name = "hedron_compile_commands",
-
- # Replace the commit hash in both places (below) with the latest, rather than using the stale one here.
- # Even better, set up Renovate and let it do the work for you (see "Suggestion: Updates" in the README).
url = "https://github.com/hedronvision/bazel-compile-commands-extractor/archive/e16062717d9b098c3c2ac95717d2b3e661c50608.tar.gz",
strip_prefix = "bazel-compile-commands-extractor-e16062717d9b098c3c2ac95717d2b3e661c50608",
- # When you first run this tool, it'll recommend a sha256 hash to put here with a message like: "DEBUG: Rule 'hedron_compile_commands' indicated that a canonical reproducible form can be obtained by modifying arguments sha256 = ..."
+ sha256 = "ed5aea1dc87856aa2029cb6940a51511557c5cac3dbbcb05a4abd989862c36b4"
)
load("@hedron_compile_commands//:workspace_setup.bzl", "hedron_compile_commands_setup")
hedron_compile_commands_setup()
diff --git a/src/sys_unix.h b/src/sys_unix.h
index b2baf19..0c19a42 100644
--- a/src/sys_unix.h
+++ b/src/sys_unix.h
@@ -8,5 +8,6 @@
#include
#include
#include
+#include
#endif
diff --git a/test/test_server_0x27_security_access.c b/test/test_server_0x27_security_access.c
index 6871d8d..ddf8c99 100644
--- a/test/test_server_0x27_security_access.c
+++ b/test/test_server_0x27_security_access.c
@@ -1,6 +1,8 @@
-#include "iso14229.h"
#include "test/test.h"
+static UDSTpHandle_t *mock_client = NULL;
+static UDSServer_t srv;
+
// UDS-1 2013 9.4.5.2
// UDS-1 2013 9.4.5.3
uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
@@ -15,8 +17,11 @@ uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
case UDS_SRV_EVT_SecAccessValidateKey: {
UDSSecAccessValidateKeyArgs_t *r = (UDSSecAccessValidateKeyArgs_t *)arg;
const uint8_t expected_key[] = {0xC9, 0xA9};
- TEST_INT_EQUAL(r->len, sizeof(expected_key));
- TEST_MEMORY_EQUAL(r->key, expected_key, sizeof(expected_key));
+ if (memcmp(r->key, expected_key, sizeof(expected_key))) {
+ return kSecurityAccessDenied;
+ } else {
+ return kPositiveResponse;
+ }
break;
}
default:
@@ -25,21 +30,84 @@ uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
return kPositiveResponse;
}
-int main() {
- UDSTpHandle_t *mock_client = ENV_TpNew("client");
- // UDSTpHandle_t *mock_client = ENV_TpNew("client");
- UDSServer_t srv;
+int setup(void **state) {
+ mock_client = ENV_TpNew("client");
ENV_SERVER_INIT(srv);
srv.fn = fn;
+ return 0;
+}
+int teardown(void **state) {
+ ENV_TpFree(mock_client);
+ ENV_TpFree(srv.tp);
+ return 0;
+}
+
+void TestSAInit(void **state) {
// the server security level after initialization should be 0
TEST_INT_EQUAL(srv.securityLevel, 0);
+}
+
+
+void TestSABruteForcePrevention1(void **state) {
+ // sending a seed request should get this response
+ const uint8_t SEED_REQUEST[] = {0x27, 0x01};
+ const uint8_t NEG_RESPONSE[] = {0x7F, 0x27, 0x37};
+ UDSTpSend(mock_client, SEED_REQUEST, sizeof(SEED_REQUEST), NULL);
+ EXPECT_IN_APPROX_MS(UDSTpGetRecvLen(mock_client) != 0, srv.p2_ms);
+ TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(mock_client, NULL), NEG_RESPONSE, sizeof(NEG_RESPONSE));
+ UDSTpAckRecv(mock_client);
+
+ // the server security level should still be 0
+ TEST_INT_EQUAL(srv.securityLevel, 0);
+}
+
+void TestSABruteForcePrevention2(void **state) {
+ // the server security level after initialization should be 0
+ TEST_INT_EQUAL(srv.securityLevel, 0);
+
+ // Wait for the anti-brute-force timeout to expire
+ ENV_RunMillis(1000);
// sending a seed request should get this response
const uint8_t SEED_REQUEST[] = {0x27, 0x01};
const uint8_t SEED_RESPONSE[] = {0x67, 0x01, 0x36, 0x57};
UDSTpSend(mock_client, SEED_REQUEST, sizeof(SEED_REQUEST), NULL);
+ EXPECT_WITHIN_MS(UDSTpGetRecvLen(mock_client) != 0, UDS_SERVER_DEFAULT_P2_MS);
+ TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(mock_client, NULL), SEED_RESPONSE, sizeof(SEED_RESPONSE));
+ UDSTpAckRecv(mock_client);
+
+ // the server security level should still be 0
+ TEST_INT_EQUAL(srv.securityLevel, 0);
+
+ // subsequently sending an unlock request should get this response
+ const uint8_t BAD_UNLOCK_REQUEST[] = {0x27, 0x02, 0xFF, 0xFF};
+ const uint8_t UNLOCK_FAIL[] = {0x7F, 0x27, 0x33};
+ UDSTpSend(mock_client, BAD_UNLOCK_REQUEST, sizeof(BAD_UNLOCK_REQUEST), NULL);
EXPECT_IN_APPROX_MS(UDSTpGetRecvLen(mock_client) != 0, srv.p2_ms);
+ TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(mock_client, NULL), UNLOCK_FAIL, sizeof(UNLOCK_FAIL));
+ UDSTpAckRecv(mock_client);
+
+ // the server security level should still be 0
+ TEST_INT_EQUAL(srv.securityLevel, 0);
+
+ // sending another seed request should get denied
+ const uint8_t DENIED[] = {0x7F, 0x27, 0x36};
+ UDSTpSend(mock_client, SEED_REQUEST, sizeof(SEED_REQUEST), NULL);
+ EXPECT_WITHIN_MS(UDSTpGetRecvLen(mock_client) != 0, UDS_SERVER_DEFAULT_P2_MS);
+ TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(mock_client, NULL), DENIED, sizeof(DENIED));
+ UDSTpAckRecv(mock_client);
+}
+
+void TestSAUnlock(void **state) {
+ // Wait for the anti-brute-force timeout to expire
+ ENV_RunMillis(1000);
+
+ // sending a seed request should get this response
+ const uint8_t SEED_REQUEST[] = {0x27, 0x01};
+ const uint8_t SEED_RESPONSE[] = {0x67, 0x01, 0x36, 0x57};
+ UDSTpSend(mock_client, SEED_REQUEST, sizeof(SEED_REQUEST), NULL);
+ EXPECT_WITHIN_MS(UDSTpGetRecvLen(mock_client) != 0, UDS_SERVER_DEFAULT_P2_MS);
TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(mock_client, NULL), SEED_RESPONSE, sizeof(SEED_RESPONSE));
UDSTpAckRecv(mock_client);
@@ -66,4 +134,17 @@ int main() {
// Additionally, the security level should still be 1
TEST_INT_EQUAL(srv.securityLevel, 1);
-}
\ No newline at end of file
+}
+
+
+int main() {
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(TestSAInit, setup, teardown),
+ cmocka_unit_test_setup_teardown(TestSABruteForcePrevention1, setup, teardown),
+ cmocka_unit_test_setup_teardown(TestSABruteForcePrevention2, setup, teardown),
+ cmocka_unit_test_setup_teardown(TestSAUnlock, setup, teardown),
+ };
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
+
+
diff --git a/test/test_tp_compliance.c b/test/test_tp_compliance.c
index 090cef0..36bd85a 100644
--- a/test/test_tp_compliance.c
+++ b/test/test_tp_compliance.c
@@ -1,4 +1,3 @@
-#include "test/env.h"
#include "test/test.h"
UDSTpHandle_t *srv = NULL;
From 126877834936b81b51678e7080faf4c0dd2e025f Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Sat, 9 Dec 2023 22:23:55 -0700
Subject: [PATCH 15/56] remove matrix test, replace with individual targets for
better cacheing
---
BUILD | 4 ++--
src/sys_unix.h | 10 ++++----
src/tp.h | 29 ++---------------------
src/tp/isotp_c.c | 4 +---
src/tp/isotp_c.h | 2 +-
src/tp/isotp_c_socketcan.h | 6 ++---
test/BUILD | 47 +++++++++++++++++++++++---------------
test/test_matrix.py | 17 --------------
8 files changed, 43 insertions(+), 76 deletions(-)
delete mode 100644 test/test_matrix.py
diff --git a/BUILD b/BUILD
index 869aba6..d8addec 100644
--- a/BUILD
+++ b/BUILD
@@ -5,14 +5,14 @@ genrule(
name = "isotp_c_wrapped_c",
srcs = glob(["src/tp/isotp-c/*.c"]),
outs = ["isotp_c_wrapped.c"],
- cmd = "echo '#if defined(UDS_TP) && UDS_TP==UDS_TP_ISOTP_C' >> $(OUTS) ; for f in $(SRCS); do cat $$f >> $(OUTS); done ; echo '#endif' >> $(OUTS)",
+ cmd = "echo '#if defined(UDS_ISOTP_C)' >> $(OUTS) ; for f in $(SRCS); do cat $$f >> $(OUTS); done ; echo '#endif' >> $(OUTS)",
)
genrule(
name = "isotp_c_wrapped_h",
srcs = glob(["src/tp/isotp-c/*.h"]),
outs = ["isotp_c_wrapped.h"],
- cmd = "echo '#if defined(UDS_TP) && UDS_TP==UDS_TP_ISOTP_C' >> $(OUTS) ; for f in $(SRCS); do cat $$f >> $(OUTS); done ; echo '#endif' >> $(OUTS)",
+ cmd = "echo '#if defined(UDS_ISOTP_C)' >> $(OUTS) ; for f in $(SRCS); do cat $$f >> $(OUTS); done ; echo '#endif' >> $(OUTS)",
)
genrule(
diff --git a/src/sys_unix.h b/src/sys_unix.h
index 0c19a42..ca3293b 100644
--- a/src/sys_unix.h
+++ b/src/sys_unix.h
@@ -2,12 +2,14 @@
#if UDS_SYS==UDS_SYS_UNIX
+#include
+#include
+#include
+#include
+#include
+#include
#include
#include
#include
-#include
-#include
-#include
-#include
#endif
diff --git a/src/tp.h b/src/tp.h
index 966cab5..a32fcf3 100644
--- a/src/tp.h
+++ b/src/tp.h
@@ -2,34 +2,9 @@
#include "sys.h"
-#if !defined(UDS_TP)
-#if (UDS_SYS == UDS_SYS_UNIX)
-#define UDS_TP UDS_TP_ISOTP_SOCKET
+#if defined(UDS_TP_ISOTP_C) || defined(UDS_TP_ISOTP_C_SOCKETCAN)
+#define UDS_ISOTP_C
#endif
-#endif
-
-#include
-#include
-#include
-#include
-#include
-
-#if (UDS_TP == UDS_TP_ISOTP_C)
-#include "tp/isotp-c/isotp.h"
-#include "tp/isotp-c/isotp_config.h"
-#include "tp/isotp-c/isotp_defines.h"
-#elif (UDS_TP == UDS_TP_ISOTP_SOCKET)
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#endif
-
enum UDSTpStatusFlags {
UDS_TP_IDLE = 0x00000000,
diff --git a/src/tp/isotp_c.c b/src/tp/isotp_c.c
index 05f6f76..a42da7c 100644
--- a/src/tp/isotp_c.c
+++ b/src/tp/isotp_c.c
@@ -1,6 +1,4 @@
-
-#include
-#if UDS_TP == UDS_TP_ISOTP_C
+#if defined(UDS_TP_ISOTP_C)
#include "util.h"
#include "tp/isotp_c.h"
diff --git a/src/tp/isotp_c.h b/src/tp/isotp_c.h
index 0226576..3e94abc 100644
--- a/src/tp/isotp_c.h
+++ b/src/tp/isotp_c.h
@@ -1,5 +1,5 @@
#pragma once
-#if UDS_TP == UDS_TP_ISOTP_C
+#if defined(UDS_TP_ISOTP_C)
#include "sys.h"
#include "config.h"
diff --git a/src/tp/isotp_c_socketcan.h b/src/tp/isotp_c_socketcan.h
index 893a62a..29da3d2 100644
--- a/src/tp/isotp_c_socketcan.h
+++ b/src/tp/isotp_c_socketcan.h
@@ -1,10 +1,10 @@
#pragma once
-#include "iso14229.h"
-#include "tp/isotp-c/isotp.h"
-
#if defined(UDS_TP_ISOTP_C_SOCKETCAN)
+#include "tp.h"
+#include "tp/isotp-c/isotp.h"
+
typedef struct {
UDSTpHandle_t hdl;
IsoTpLink phys_link;
diff --git a/test/BUILD b/test/BUILD
index 7fc4cea..e595b4e 100644
--- a/test/BUILD
+++ b/test/BUILD
@@ -48,31 +48,40 @@ TEST_NAMES = [ src.split(".c")[0] for src in TEST_SRCS ]
# These should pass on all architectures and transports
[
cc_test(
- name=name,
+ name=name + "_tp_mock",
srcs=[src],
deps=[":env"],
size = "small",
- env = {
- "UDS_TP_TYPE": "0",
- },
+ env = { "UDS_TP_TYPE": "0", },
copts = ["-g"],
- tags = [
- "exclusive",
- ],
- )
- for name, src in zip(TEST_NAMES, TEST_SRCS)
+ tags = [ "exclusive", ],
+ ) for name, src in zip(TEST_NAMES, TEST_SRCS)
+]
+
+[
+ cc_test(
+ name=name + "_tp_sock",
+ srcs=[src],
+ deps=[":env"],
+ size = "small",
+ env = { "UDS_TP_TYPE": "1"},
+ copts = ["-g"],
+ tags = [ "exclusive", ],
+ ) for name, src in zip(TEST_NAMES, TEST_SRCS)
+]
+
+[
+ cc_test(
+ name=name + "_tp_c",
+ srcs=[src],
+ deps=[":env"],
+ size = "small",
+ env = { "UDS_TP_TYPE": "2"},
+ copts = ["-g"],
+ tags = [ "exclusive", ],
+ ) for name, src in zip(TEST_NAMES, TEST_SRCS)
]
-py_test(
- name = "test_matrix",
- srcs = ["test_matrix.py"],
- size = "small",
- data = TEST_NAMES,
- args = TEST_NAMES,
- tags = [
- "exclusive",
- ],
-)
cc_test(
name = "test_fuzz_server",
diff --git a/test/test_matrix.py b/test/test_matrix.py
deleted file mode 100644
index 692d4e2..0000000
--- a/test/test_matrix.py
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/usr/bin/env python3
-
-__doc__ = """
-The core idea is that tests assert invariant properties that should be
-upheld regardless of the specific transport protocol, timing parameters, etc.
-"""
-
-import os
-import sys
-import subprocess
-
-for f in sys.argv[1:]:
- for tp_type in ["0", "1", "2"]:
- subprocess.check_call([f"test/{f}"], env={
- "UDS_TP_TYPE": tp_type
- })
-
From a0e199a31d87fdda73612dcae1a12c6226a6c334 Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Sat, 9 Dec 2023 22:28:51 -0700
Subject: [PATCH 16/56] search for issue in github actions
---
BUILD | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/BUILD b/BUILD
index d8addec..8f9dff6 100644
--- a/BUILD
+++ b/BUILD
@@ -30,7 +30,7 @@ genrule(
":isotp_c_wrapped_h",
],
outs = ["iso14229.h"],
- cmd = "echo $(SRCS); (cat ; echo '#ifndef ISO14229_H'; echo '#define ISO14229_H'; echo; echo '#ifdef __cplusplus'; echo 'extern \"C\" {'; echo '#endif'; cat src/sys.h src/sys_arduino.h src/sys_unix.h src/sys_win32.h src/sys_esp32.h src/config.h src/util.h src/tp.h src/uds.h src/client.h src/server.h $(location //:isotp_c_wrapped_h) src/tp/*.h |sed -e 's,#include \".*,,' -e 's,^#pragma once,,' ; echo '#endif'; echo '#ifdef __cplusplus'; echo '}'; echo '#endif';) > $(OUTS)",
+ cmd = "echo $(SRCS); (cat ; echo '#ifndef ISO14229_H'; echo '#define ISO14229_H'; echo; echo '#ifdef __cplusplus'; echo 'extern \"C\" {'; echo '#endif'; cat src/sys.h src/sys_arduino.h src/sys_unix.h src/sys_win32.h src/sys_esp32.h src/config.h src/util.h src/tp.h src/uds.h src/client.h src/server.h $(location //:isotp_c_wrapped_h) src/tp/*.h |sed -e 's,#include \".*,,' -e 's,^#pragma once,,' ; echo '#endif'; echo '#ifdef __cplusplus'; echo '}'; echo '#endif';) > $(OUTS) && cat $(OUTS)",
)
filegroup(
From eec6a6da30f338da5554f9405e3d079013f18f27 Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Sat, 9 Dec 2023 22:33:37 -0700
Subject: [PATCH 17/56] test
---
BUILD | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/BUILD b/BUILD
index 8f9dff6..3110469 100644
--- a/BUILD
+++ b/BUILD
@@ -18,7 +18,7 @@ genrule(
genrule(
name = "c_src",
srcs = glob(["src/*.c", "src/tp/*.c"]) + [
- ":isotp_c_wrapped_c",
+ ":isotp_c_wrapped.c",
],
outs = ["iso14229.c"],
cmd = "(echo '#include \"iso14229.h\"'; (for f in $(SRCS); do echo; echo '#ifdef UDS_LINES'; echo \"#line 1 \\\"$$f\"\\\"; echo '#endif'; cat $$f | sed -e 's,#include \".*,,'; done)) > $(OUTS)",
@@ -27,10 +27,10 @@ genrule(
genrule(
name = "h_src",
srcs = glob(["src/*.h", "src/tp/*.h"]) + [
- ":isotp_c_wrapped_h",
+ ":isotp_c_wrapped.h",
],
outs = ["iso14229.h"],
- cmd = "echo $(SRCS); (cat ; echo '#ifndef ISO14229_H'; echo '#define ISO14229_H'; echo; echo '#ifdef __cplusplus'; echo 'extern \"C\" {'; echo '#endif'; cat src/sys.h src/sys_arduino.h src/sys_unix.h src/sys_win32.h src/sys_esp32.h src/config.h src/util.h src/tp.h src/uds.h src/client.h src/server.h $(location //:isotp_c_wrapped_h) src/tp/*.h |sed -e 's,#include \".*,,' -e 's,^#pragma once,,' ; echo '#endif'; echo '#ifdef __cplusplus'; echo '}'; echo '#endif';) > $(OUTS) && cat $(OUTS)",
+ cmd = "echo $(SRCS); (cat ; echo '#ifndef ISO14229_H'; echo '#define ISO14229_H'; echo; echo '#ifdef __cplusplus'; echo 'extern \"C\" {'; echo '#endif'; cat src/sys.h src/sys_arduino.h src/sys_unix.h src/sys_win32.h src/sys_esp32.h src/config.h src/util.h src/tp.h src/uds.h src/client.h src/server.h $(location //:isotp_c_wrapped.h) src/tp/*.h |sed -e 's,#include \".*,,' -e 's,^#pragma once,,' ; echo '#endif'; echo '#ifdef __cplusplus'; echo '}'; echo '#endif';) > $(OUTS) && cat $(OUTS)",
)
filegroup(
From faab5bd79ff020d55a3731e2bf89022659cdef61 Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Sat, 9 Dec 2023 22:36:35 -0700
Subject: [PATCH 18/56] tets
---
BUILD | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/BUILD b/BUILD
index 3110469..026f950 100644
--- a/BUILD
+++ b/BUILD
@@ -12,7 +12,7 @@ genrule(
name = "isotp_c_wrapped_h",
srcs = glob(["src/tp/isotp-c/*.h"]),
outs = ["isotp_c_wrapped.h"],
- cmd = "echo '#if defined(UDS_ISOTP_C)' >> $(OUTS) ; for f in $(SRCS); do cat $$f >> $(OUTS); done ; echo '#endif' >> $(OUTS)",
+ cmd = "echo '#if defined(UDS_ISOTP_C)' >> $(OUTS) ; for f in $(SRCS); do cat $$f >> $(OUTS); done ; echo '#endif' >> $(OUTS); cat $(OUTS)",
)
genrule(
From 9f5c7dc0e33889a7191cce65c3d87b6ddf3ee904 Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Sat, 9 Dec 2023 22:44:20 -0700
Subject: [PATCH 19/56] checkout submodules
---
.github/workflows/runtests.yml | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/runtests.yml b/.github/workflows/runtests.yml
index c410297..06f2b07 100644
--- a/.github/workflows/runtests.yml
+++ b/.github/workflows/runtests.yml
@@ -12,6 +12,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - name: Checkout
+ uses: actions/checkout@v3
+ with:
+ submodules: true
- name: build and run unit test
run: bazel test //test:all
From 825dcb893882e30482cf091f231aaffba4d26025 Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Sat, 9 Dec 2023 23:03:26 -0700
Subject: [PATCH 20/56] remove isotp-c submodule
---
.gitmodules | 3 ---
src/tp/isotp-c | 1 -
2 files changed, 4 deletions(-)
delete mode 100644 .gitmodules
delete mode 160000 src/tp/isotp-c
diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644
index d7b4425..0000000
--- a/.gitmodules
+++ /dev/null
@@ -1,3 +0,0 @@
-[submodule "tp/isotp-c"]
- path = src/tp/isotp-c
- url = https://github.com/driftregion/isotp-c.git
diff --git a/src/tp/isotp-c b/src/tp/isotp-c
deleted file mode 160000
index 2737949..0000000
--- a/src/tp/isotp-c
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 27379492110d8ae1aaf7e4ca94cf65b31a2192b9
From 3980ca6a8a61e8369a82c07e57cfcd77b3e5b6c3 Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Sat, 9 Dec 2023 23:03:54 -0700
Subject: [PATCH 21/56] Squashed 'src/tp/isotp-c/' content from commit 2737949
git-subtree-dir: src/tp/isotp-c
git-subtree-split: 27379492110d8ae1aaf7e4ca94cf65b31a2192b9
---
.gitignore | 16 ++
.travis.yml | 6 +
CMakeLists.txt | 19 ++
LICENSE | 21 ++
Makefile | 66 ++++++
README.mkd | 198 ++++++++++++++++++
isotp.c | 531 ++++++++++++++++++++++++++++++++++++++++++++++++
isotp.h | 150 ++++++++++++++
isotp_config.h | 29 +++
isotp_defines.h | 225 ++++++++++++++++++++
vars.mk | 63 ++++++
11 files changed, 1324 insertions(+)
create mode 100644 .gitignore
create mode 100644 .travis.yml
create mode 100644 CMakeLists.txt
create mode 100644 LICENSE
create mode 100644 Makefile
create mode 100644 README.mkd
create mode 100644 isotp.c
create mode 100644 isotp.h
create mode 100644 isotp_config.h
create mode 100644 isotp_defines.h
create mode 100644 vars.mk
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..81bf9b5
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,16 @@
+###
+# .GITIGNORE FILE
+# This file contains instructions for filesystem entries git should ignore when
+# doing things to this repository.
+###
+
+###
+# Ignore Artifacts
+###
+*.o
+bin/
+
+###
+# Ignore Backups
+###
+*~
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..d46676c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,6 @@
+language: c++
+compiler:
+ - gcc
+ - g++
+ - clang
+script: make travis
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..162db5f
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 3.10)
+
+###
+# Project definition
+###
+project(isotp LANGUAGES C)
+
+###
+# Get all include directories
+###
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}/
+)
+
+###
+# Compile isotp as Shared Lib
+###
+add_library(isotp SHARED
+ isotp.c)
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..19e89e3
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 Shen Li & Co-Operators
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..bd65906
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,66 @@
+include vars.mk
+
+CFLAGS := -Wall -g -ggdb $(STD)
+LDFLAGS := -shared
+BIN := ./bin
+
+.PHONY: all clean fPIC no_opt $(BIN)/$(LIB_NAME) $(BIN)/$(LIB_NAME).$(MAJOR_VER) $(BIN)/$(LIB_NAME).$(MAJOR_VER).$(MINOR_VER).$(REVISION) travis
+
+###
+# BEGIN TARGETS
+###
+
+###
+# Builds all library artifacts
+###
+all: $(BIN)/$(LIB_NAME)
+ @printf "########## BUILT $^ ##########\n\n\n"
+
+fPIC: CFLAGS += "-fPIC"
+
+travis: fPIC all
+
+###
+# Builds all targets w/o optimisations enabled
+###
+no_opt: CFLAGS += -g -O0 all
+
+###
+# Removes all build artifacts
+###
+clean:
+ -rm -f *.o $(BIN)/$(LIB_NAME)*
+
+###
+# Builds all library artifacts, including all symlinks.
+###
+$(BIN)/$(LIB_NAME): $(BIN)/$(LIB_NAME).$(MAJOR_VER)
+ -ln -s $^ $@
+ @printf "Linked $^ --> $@...\n"
+
+###
+# Builds the shared object along with one symlink
+###
+$(BIN)/$(LIB_NAME).$(MAJOR_VER): $(BIN)/$(LIB_NAME).$(MAJOR_VER).$(MINOR_VER).$(REVISION)
+ -ln -s $^ $@
+ @printf "Linked $^ --> $@...\n"
+
+$(BIN)/$(LIB_NAME).$(MAJOR_VER).$(MINOR_VER).$(REVISION): libisotp.o
+ if [ ! -d $(BIN) ]; then mkdir $(BIN); fi;
+ ${COMP} $^ -o $@ ${LDFLAGS}
+
+###
+# Compiles the isotp.c TU to an object file.
+###
+libisotp.o: isotp.c
+ ${COMP} -c $^ -o $@ ${CFLAGS}
+
+install: all
+ @printf "Installing $(LIB_NAME) to $(INSTALL_DIR)...\n"
+ cp $(BIN)/$(LIB_NAME)* $(INSTALL_DIR)
+ @printf "Library was installed...\n"
+
+###
+# END TARGETS
+###
+
diff --git a/README.mkd b/README.mkd
new file mode 100644
index 0000000..4cc5093
--- /dev/null
+++ b/README.mkd
@@ -0,0 +1,198 @@
+ISO-TP (ISO 15765-2) Support Library in C
+================================
+
+**This project is inspired by [openxc isotp-c](https://github.com/openxc/isotp-c), but the code has been completely re-written.**
+
+This is a platform agnostic C library that implements the [ISO 15765-2](https://en.wikipedia.org/wiki/ISO_15765-2) (also known as ISO-TP) protocol, which runs over a CAN bus. Quoting Wikipedia:
+
+>ISO 15765-2, or ISO-TP, is an international standard for sending data packets over a CAN-Bus.
+>The protocol allows for the transport of messages that exceed the eight byte maximum payload of CAN frames.
+>ISO-TP segments longer messages into multiple frames, adding metadata that allows the interpretation of individual frames and reassembly
+>into a complete message packet by the recipient. It can carry up to 4095 bytes of payload per message packet.
+
+This library doesn't assume anything about the source of the ISO-TP messages or the underlying interface to CAN. It uses dependency injection to give you complete control.
+
+**The current version supports [ISO-15765-2](https://en.wikipedia.org/wiki/ISO_15765-2) single and multiple frame transmition, and works in Full-duplex mode.**
+
+## Builds
+
+### Master Build
+[![Build Status](https://api.travis-ci.com/Beatsleigher/isotp-c.svg?branch=master)](https://travis-ci.com/Beatsleigher/isotp-c)
+
+## Usage
+
+First, create some [shim](https://en.wikipedia.org/wiki/Shim_(computing)) functions to let this library use your lower level system:
+
+```C
+ /* required, this must send a single CAN message with the given arbitration
+ * ID (i.e. the CAN message ID) and data. The size will never be more than 8
+ * bytes. */
+ int isotp_user_send_can(const uint32_t arbitration_id,
+ const uint8_t* data, const uint8_t size) {
+ // ...
+ }
+
+ /* required, return system tick, unit is millisecond */
+ uint32_t isotp_user_get_ms(void) {
+ // ...
+ }
+
+ /* optional, provide to receive debugging log messages */
+ void isotp_user_debug(const char* message, ...) {
+ // ...
+ }
+```
+
+### API
+
+You can use isotp-c in the following way:
+
+```C
+ /* Alloc IsoTpLink statically in RAM */
+ static IsoTpLink g_link;
+
+ /* Alloc send and receive buffer statically in RAM */
+ static uint8_t g_isotpRecvBuf[ISOTP_BUFSIZE];
+ static uint8_t g_isotpSendBuf[ISOTP_BUFSIZE];
+
+ int main(void) {
+ /* Initialize CAN and other peripherals */
+
+ /* Initialize link, 0x7TT is the CAN ID you send with */
+ isotp_init_link(&g_link, 0x7TT,
+ g_isotpSendBuf, sizeof(g_isotpSendBuf),
+ g_isotpRecvBuf, sizeof(g_isotpRecvBuf),
+ isotp_user_get_ms,
+ isotp_user_send_can,
+ isotp_user_debug);
+
+ while(1) {
+
+ /* If receive any interested can message, call isotp_on_can_message to handle message */
+ ret = can_receive(&id, &data, &len);
+
+ /* 0x7RR is CAN ID you want to receive */
+ if (RET_OK == ret && 0x7RR == id) {
+ isotp_on_can_message(&g_link, data, len);
+ }
+
+ /* Poll link to handle multiple frame transmition */
+ isotp_poll(&g_link);
+
+ /* You can receive message with isotp_receive.
+ payload is upper layer message buffer, usually UDS;
+ payload_size is payload buffer size;
+ out_size is the actuall read size;
+ */
+ ret = isotp_receive(&g_link, payload, payload_size, &out_size);
+ if (ISOTP_RET_OK == ret) {
+ /* Handle received message */
+ }
+
+ /* And send message with isotp_send */
+ ret = isotp_send(&g_link, payload, payload_size);
+ if (ISOTP_RET_OK == ret) {
+ /* Send ok */
+ } else {
+ /* An error occured */
+ }
+
+ /* In case you want to send data w/ functional addressing, use isotp_send_with_id */
+ ret = isotp_send_with_id(&g_link, 0x7df, payload, payload_size);
+ if (ISOTP_RET_OK == ret) {
+ /* Send ok */
+ } else {
+ /* Error occur */
+ }
+ }
+
+ return;
+ }
+```
+
+You can call isotp_poll as frequently as you want, as it internally uses isotp_user_get_ms to measure timeout occurences.
+If you need handle functional addressing, you must use two separate links, one for each.
+
+```C
+ /* Alloc IsoTpLink statically in RAM */
+ static IsoTpLink g_phylink;
+ static IsoTpLink g_funclink;
+
+ /* Allocate send and receive buffer statically in RAM */
+ static uint8_t g_isotpPhyRecvBuf[512];
+ static uint8_t g_isotpPhySendBuf[512];
+ /* currently functional addressing is not supported with multi-frame messages */
+ static uint8_t g_isotpFuncRecvBuf[8];
+ static uint8_t g_isotpFuncSendBuf[8];
+
+ int main(void) {
+ /* Initialize CAN and other peripherals */
+
+ /* Initialize link, 0x7TT is the CAN ID you send with */
+ isotp_init_link(&g_phylink, 0x7TT,
+ g_isotpPhySendBuf, sizeof(g_isotpPhySendBuf),
+ g_isotpPhyRecvBuf, sizeof(g_isotpPhyRecvBuf),
+ isotp_user_get_ms,
+ isotp_user_send_can,
+ isotp_user_debug);
+ isotp_init_link(&g_funclink, 0x7TT,
+ g_isotpFuncSendBuf, sizeof(g_isotpFuncSendBuf),
+ g_isotpFuncRecvBuf, sizeof(g_isotpFuncRecvBuf),
+ isotp_user_get_ms,
+ isotp_user_send_can,
+ isotp_user_debug);
+
+ while(1) {
+
+ /* If any CAN messages are received, which are of interest, call isotp_on_can_message to handle the message */
+ ret = can_receive(&id, &data, &len);
+
+ /* 0x7RR is CAN ID you want to receive */
+ if (RET_OK == ret) {
+ if (0x7RR == id) {
+ isotp_on_can_message(&g_phylink, data, len);
+ } else if (0x7df == id) {
+ isotp_on_can_message(&g_funclink, data, len);
+ }
+ }
+
+ /* Poll link to handle multiple frame transmition */
+ isotp_poll(&g_phylink);
+ isotp_poll(&g_funclink);
+
+ /* You can receive message with isotp_receive.
+ payload is upper layer message buffer, usually UDS;
+ payload_size is payload buffer size;
+ out_size is the actuall read size;
+ */
+ ret = isotp_receive(&g_phylink, payload, payload_size, &out_size);
+ if (ISOTP_RET_OK == ret) {
+ /* Handle physical addressing message */
+ }
+
+ ret = isotp_receive(&g_funclink, payload, payload_size, &out_size);
+ if (ISOTP_RET_OK == ret) {
+ /* Handle functional addressing message */
+ }
+
+ /* And send message with isotp_send */
+ ret = isotp_send(&g_phylink, payload, payload_size);
+ if (ISOTP_RET_OK == ret) {
+ /* Send ok */
+ } else {
+ /* An error occured */
+ }
+ }
+
+ return;
+ }
+```
+
+## Authors
+
+* **shen.li lishen5@gmail.com** (Original author!)
+* **Simon Cahill** **s.cahill@grimme.de** (or **simon@h3lix.de**)
+
+## License
+
+Licensed under the MIT license.
diff --git a/isotp.c b/isotp.c
new file mode 100644
index 0000000..737911c
--- /dev/null
+++ b/isotp.c
@@ -0,0 +1,531 @@
+#include
+#include "assert.h"
+#include "isotp.h"
+
+///////////////////////////////////////////////////////
+/// STATIC FUNCTIONS ///
+///////////////////////////////////////////////////////
+
+/* st_min to microsecond */
+static uint8_t isotp_ms_to_st_min(uint8_t ms) {
+ uint8_t st_min;
+
+ st_min = ms;
+ if (st_min > 0x7F) {
+ st_min = 0x7F;
+ }
+
+ return st_min;
+}
+
+/* st_min to msec */
+static uint8_t isotp_st_min_to_ms(uint8_t st_min) {
+ uint8_t ms;
+
+ if (st_min >= 0xF1 && st_min <= 0xF9) {
+ ms = 1;
+ } else if (st_min <= 0x7F) {
+ ms = st_min;
+ } else {
+ ms = 0;
+ }
+
+ return ms;
+}
+
+static int isotp_send_flow_control(IsoTpLink* link, uint8_t flow_status, uint8_t block_size, uint8_t st_min_ms) {
+
+ IsoTpCanMessage message;
+ int ret;
+
+ /* setup message */
+ message.as.flow_control.type = ISOTP_PCI_TYPE_FLOW_CONTROL_FRAME;
+ message.as.flow_control.FS = flow_status;
+ message.as.flow_control.BS = block_size;
+ message.as.flow_control.STmin = isotp_ms_to_st_min(st_min_ms);
+
+ /* send message */
+#ifdef ISO_TP_FRAME_PADDING
+ (void) memset(message.as.flow_control.reserve, 0, sizeof(message.as.flow_control.reserve));
+ ret = link->isotp_user_send_can(link->send_arbitration_id, message.as.data_array.ptr, sizeof(message), link->user_data);
+#else
+ ret = link->isotp_user_send_can(link->send_arbitration_id,
+ message.as.data_array.ptr,
+ 3);
+#endif
+
+ return ret;
+}
+
+static int isotp_send_single_frame(IsoTpLink* link, uint32_t id) {
+
+ IsoTpCanMessage message;
+ int ret;
+
+ /* multi frame message length must greater than 7 */
+ assert(link->send_size <= 7);
+
+ /* setup message */
+ message.as.single_frame.type = ISOTP_PCI_TYPE_SINGLE;
+ message.as.single_frame.SF_DL = (uint8_t) link->send_size;
+ (void) memcpy(message.as.single_frame.data, link->send_buffer, link->send_size);
+
+ /* send message */
+#ifdef ISO_TP_FRAME_PADDING
+ (void) memset(message.as.single_frame.data + link->send_size, 0, sizeof(message.as.single_frame.data) - link->send_size);
+ ret = link->isotp_user_send_can(id, message.as.data_array.ptr, sizeof(message), link->user_data);
+#else
+ ret = link->isotp_user_send_can(id,
+ message.as.data_array.ptr,
+ link->send_size + 1);
+#endif
+
+ return ret;
+}
+
+static int isotp_send_first_frame(IsoTpLink* link, uint32_t id) {
+
+ IsoTpCanMessage message;
+ int ret;
+
+ /* multi frame message length must greater than 7 */
+ assert(link->send_size > 7);
+
+ /* setup message */
+ message.as.first_frame.type = ISOTP_PCI_TYPE_FIRST_FRAME;
+ message.as.first_frame.FF_DL_low = (uint8_t) link->send_size;
+ message.as.first_frame.FF_DL_high = (uint8_t) (0x0F & (link->send_size >> 8));
+ (void) memcpy(message.as.first_frame.data, link->send_buffer, sizeof(message.as.first_frame.data));
+
+ /* send message */
+ ret = link->isotp_user_send_can(id, message.as.data_array.ptr, sizeof(message), link->user_data);
+ if (ISOTP_RET_OK == ret) {
+ link->send_offset += sizeof(message.as.first_frame.data);
+ link->send_sn = 1;
+ }
+
+ return ret;
+}
+
+static int isotp_send_consecutive_frame(IsoTpLink* link) {
+
+ IsoTpCanMessage message;
+ uint16_t data_length;
+ int ret;
+
+ /* multi frame message length must greater than 7 */
+ assert(link->send_size > 7);
+
+ /* setup message */
+ message.as.consecutive_frame.type = TSOTP_PCI_TYPE_CONSECUTIVE_FRAME;
+ message.as.consecutive_frame.SN = link->send_sn;
+ data_length = link->send_size - link->send_offset;
+ if (data_length > sizeof(message.as.consecutive_frame.data)) {
+ data_length = sizeof(message.as.consecutive_frame.data);
+ }
+ (void) memcpy(message.as.consecutive_frame.data, link->send_buffer + link->send_offset, data_length);
+
+ /* send message */
+#ifdef ISO_TP_FRAME_PADDING
+ (void) memset(message.as.consecutive_frame.data + data_length, 0, sizeof(message.as.consecutive_frame.data) - data_length);
+ ret = link->isotp_user_send_can(link->send_arbitration_id, message.as.data_array.ptr, sizeof(message), link->user_data);
+#else
+ ret = link->isotp_user_send_can(link->send_arbitration_id,
+ message.as.data_array.ptr,
+ data_length + 1);
+#endif
+ if (ISOTP_RET_OK == ret) {
+ link->send_offset += data_length;
+ if (++(link->send_sn) > 0x0F) {
+ link->send_sn = 0;
+ }
+ }
+
+ return ret;
+}
+
+static int isotp_receive_single_frame(IsoTpLink *link, IsoTpCanMessage *message, uint8_t len) {
+ /* check data length */
+ if ((0 == message->as.single_frame.SF_DL) || (message->as.single_frame.SF_DL > (len - 1))) {
+ link->isotp_user_debug("Single-frame length too small.");
+ return ISOTP_RET_LENGTH;
+ }
+
+ /* copying data */
+ (void) memcpy(link->receive_buffer, message->as.single_frame.data, message->as.single_frame.SF_DL);
+ link->receive_size = message->as.single_frame.SF_DL;
+
+ return ISOTP_RET_OK;
+}
+
+static int isotp_receive_first_frame(IsoTpLink *link, IsoTpCanMessage *message, uint8_t len) {
+ uint16_t payload_length;
+
+ if (8 != len) {
+ link->isotp_user_debug("First frame should be 8 bytes in length.");
+ return ISOTP_RET_LENGTH;
+ }
+
+ /* check data length */
+ payload_length = message->as.first_frame.FF_DL_high;
+ payload_length = (payload_length << 8) + message->as.first_frame.FF_DL_low;
+
+ /* should not use multiple frame transmition */
+ if (payload_length <= 7) {
+ link->isotp_user_debug("Should not use multiple frame transmission.");
+ return ISOTP_RET_LENGTH;
+ }
+
+ if (payload_length > link->receive_buf_size) {
+ link->isotp_user_debug("Multi-frame response too large for receiving buffer.");
+ return ISOTP_RET_OVERFLOW;
+ }
+
+ /* copying data */
+ (void) memcpy(link->receive_buffer, message->as.first_frame.data, sizeof(message->as.first_frame.data));
+ link->receive_size = payload_length;
+ link->receive_offset = sizeof(message->as.first_frame.data);
+ link->receive_sn = 1;
+
+ return ISOTP_RET_OK;
+}
+
+static int isotp_receive_consecutive_frame(IsoTpLink *link, IsoTpCanMessage *message, uint8_t len) {
+ uint16_t remaining_bytes;
+
+ /* check sn */
+ if (link->receive_sn != message->as.consecutive_frame.SN) {
+ return ISOTP_RET_WRONG_SN;
+ }
+
+ /* check data length */
+ remaining_bytes = link->receive_size - link->receive_offset;
+ if (remaining_bytes > sizeof(message->as.consecutive_frame.data)) {
+ remaining_bytes = sizeof(message->as.consecutive_frame.data);
+ }
+ if (remaining_bytes > len - 1) {
+ link->isotp_user_debug("Consecutive frame too short.");
+ return ISOTP_RET_LENGTH;
+ }
+
+ /* copying data */
+ (void) memcpy(link->receive_buffer + link->receive_offset, message->as.consecutive_frame.data, remaining_bytes);
+
+ link->receive_offset += remaining_bytes;
+ if (++(link->receive_sn) > 0x0F) {
+ link->receive_sn = 0;
+ }
+
+ return ISOTP_RET_OK;
+}
+
+static int isotp_receive_flow_control_frame(IsoTpLink *link, IsoTpCanMessage *message, uint8_t len) {
+ /* check message length */
+ if (len < 3) {
+ link->isotp_user_debug("Flow control frame too short.");
+ return ISOTP_RET_LENGTH;
+ }
+
+ return ISOTP_RET_OK;
+}
+
+///////////////////////////////////////////////////////
+/// PUBLIC FUNCTIONS ///
+///////////////////////////////////////////////////////
+
+int isotp_send(IsoTpLink *link, const uint8_t payload[], uint16_t size) {
+ return isotp_send_with_id(link, link->send_arbitration_id, payload, size);
+}
+
+int isotp_send_with_id(IsoTpLink *link, uint32_t id, const uint8_t payload[], uint16_t size) {
+ int ret;
+
+ if (link == 0x0) {
+ link->isotp_user_debug("Link is null!");
+ return ISOTP_RET_ERROR;
+ }
+
+ if (size > link->send_buf_size) {
+ link->isotp_user_debug("Message size too large. Increase ISO_TP_MAX_MESSAGE_SIZE to set a larger buffer\n");
+ char message[128];
+ sprintf(&message[0], "Attempted to send %d bytes; max size is %d!\n", size, link->send_buf_size);
+ return ISOTP_RET_OVERFLOW;
+ }
+
+ if (ISOTP_SEND_STATUS_INPROGRESS == link->send_status) {
+ link->isotp_user_debug("Abort previous message, transmission in progress.\n");
+ return ISOTP_RET_INPROGRESS;
+ }
+
+ /* copy into local buffer */
+ link->send_size = size;
+ link->send_offset = 0;
+ (void) memcpy(link->send_buffer, payload, size);
+
+ if (link->send_size < 8) {
+ /* send single frame */
+ ret = isotp_send_single_frame(link, id);
+ } else {
+ /* send multi-frame */
+ ret = isotp_send_first_frame(link, id);
+
+ /* init multi-frame control flags */
+ if (ISOTP_RET_OK == ret) {
+ link->send_bs_remain = 0;
+ link->send_st_min = 0;
+ link->send_wtf_count = 0;
+ link->send_timer_st = link->isotp_user_get_ms();
+ link->send_timer_bs = link->isotp_user_get_ms() + ISO_TP_DEFAULT_RESPONSE_TIMEOUT;
+ link->send_protocol_result = ISOTP_PROTOCOL_RESULT_OK;
+ link->send_status = ISOTP_SEND_STATUS_INPROGRESS;
+ }
+ }
+
+ return ret;
+}
+
+void isotp_on_can_message(IsoTpLink *link, uint8_t *data, uint8_t len) {
+ IsoTpCanMessage message;
+ int ret;
+
+ if (len < 2 || len > 8) {
+ return;
+ }
+
+ memcpy(message.as.data_array.ptr, data, len);
+ memset(message.as.data_array.ptr + len, 0, sizeof(message.as.data_array.ptr) - len);
+
+ switch (message.as.common.type) {
+ case ISOTP_PCI_TYPE_SINGLE: {
+ /* update protocol result */
+ if (ISOTP_RECEIVE_STATUS_INPROGRESS == link->receive_status) {
+ link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_UNEXP_PDU;
+ } else {
+ link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_OK;
+ }
+
+ /* handle message */
+ ret = isotp_receive_single_frame(link, &message, len);
+
+ if (ISOTP_RET_OK == ret) {
+ /* change status */
+ link->receive_status = ISOTP_RECEIVE_STATUS_FULL;
+ }
+ break;
+ }
+ case ISOTP_PCI_TYPE_FIRST_FRAME: {
+ /* update protocol result */
+ if (ISOTP_RECEIVE_STATUS_INPROGRESS == link->receive_status) {
+ link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_UNEXP_PDU;
+ } else {
+ link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_OK;
+ }
+
+ /* handle message */
+ ret = isotp_receive_first_frame(link, &message, len);
+
+ /* if overflow happened */
+ if (ISOTP_RET_OVERFLOW == ret) {
+ /* update protocol result */
+ link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_BUFFER_OVFLW;
+ /* change status */
+ link->receive_status = ISOTP_RECEIVE_STATUS_IDLE;
+ /* send error message */
+ isotp_send_flow_control(link, PCI_FLOW_STATUS_OVERFLOW, 0, 0);
+ break;
+ }
+
+ /* if receive successful */
+ if (ISOTP_RET_OK == ret) {
+ /* change status */
+ link->receive_status = ISOTP_RECEIVE_STATUS_INPROGRESS;
+ /* send fc frame */
+ link->receive_bs_count = ISO_TP_DEFAULT_BLOCK_SIZE;
+ isotp_send_flow_control(link, PCI_FLOW_STATUS_CONTINUE, link->receive_bs_count, ISO_TP_DEFAULT_ST_MIN);
+ /* refresh timer cs */
+ link->receive_timer_cr = link->isotp_user_get_ms() + ISO_TP_DEFAULT_RESPONSE_TIMEOUT;
+ }
+
+ break;
+ }
+ case TSOTP_PCI_TYPE_CONSECUTIVE_FRAME: {
+ /* check if in receiving status */
+ if (ISOTP_RECEIVE_STATUS_INPROGRESS != link->receive_status) {
+ link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_UNEXP_PDU;
+ break;
+ }
+
+ /* handle message */
+ ret = isotp_receive_consecutive_frame(link, &message, len);
+
+ /* if wrong sn */
+ if (ISOTP_RET_WRONG_SN == ret) {
+ link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_WRONG_SN;
+ link->receive_status = ISOTP_RECEIVE_STATUS_IDLE;
+ break;
+ }
+
+ /* if success */
+ if (ISOTP_RET_OK == ret) {
+ /* refresh timer cs */
+ link->receive_timer_cr = link->isotp_user_get_ms() + ISO_TP_DEFAULT_RESPONSE_TIMEOUT;
+
+ /* receive finished */
+ if (link->receive_offset >= link->receive_size) {
+ link->receive_status = ISOTP_RECEIVE_STATUS_FULL;
+ } else {
+ /* send fc when bs reaches limit */
+ if (0 == --link->receive_bs_count) {
+ link->receive_bs_count = ISO_TP_DEFAULT_BLOCK_SIZE;
+ isotp_send_flow_control(link, PCI_FLOW_STATUS_CONTINUE, link->receive_bs_count, ISO_TP_DEFAULT_ST_MIN);
+ }
+ }
+ }
+
+ break;
+ }
+ case ISOTP_PCI_TYPE_FLOW_CONTROL_FRAME:
+ /* handle fc frame only when sending in progress */
+ if (ISOTP_SEND_STATUS_INPROGRESS != link->send_status) {
+ break;
+ }
+
+ /* handle message */
+ ret = isotp_receive_flow_control_frame(link, &message, len);
+
+ if (ISOTP_RET_OK == ret) {
+ /* refresh bs timer */
+ link->send_timer_bs = link->isotp_user_get_ms() + ISO_TP_DEFAULT_RESPONSE_TIMEOUT;
+
+ /* overflow */
+ if (PCI_FLOW_STATUS_OVERFLOW == message.as.flow_control.FS) {
+ link->send_protocol_result = ISOTP_PROTOCOL_RESULT_BUFFER_OVFLW;
+ link->send_status = ISOTP_SEND_STATUS_ERROR;
+ }
+
+ /* wait */
+ else if (PCI_FLOW_STATUS_WAIT == message.as.flow_control.FS) {
+ link->send_wtf_count += 1;
+ /* wait exceed allowed count */
+ if (link->send_wtf_count > ISO_TP_MAX_WFT_NUMBER) {
+ link->send_protocol_result = ISOTP_PROTOCOL_RESULT_WFT_OVRN;
+ link->send_status = ISOTP_SEND_STATUS_ERROR;
+ }
+ }
+
+ /* permit send */
+ else if (PCI_FLOW_STATUS_CONTINUE == message.as.flow_control.FS) {
+ if (0 == message.as.flow_control.BS) {
+ link->send_bs_remain = ISOTP_INVALID_BS;
+ } else {
+ link->send_bs_remain = message.as.flow_control.BS;
+ }
+ link->send_st_min = isotp_st_min_to_ms(message.as.flow_control.STmin);
+ link->send_wtf_count = 0;
+ }
+ }
+ break;
+ default:
+ break;
+ };
+
+ return;
+}
+
+int isotp_receive(IsoTpLink *link, uint8_t *payload, const uint16_t payload_size, uint16_t *out_size) {
+ uint16_t copylen;
+
+ if (ISOTP_RECEIVE_STATUS_FULL != link->receive_status) {
+ return ISOTP_RET_NO_DATA;
+ }
+
+ copylen = link->receive_size;
+ if (copylen > payload_size) {
+ copylen = payload_size;
+ }
+
+ memcpy(payload, link->receive_buffer, copylen);
+ *out_size = copylen;
+
+ link->receive_status = ISOTP_RECEIVE_STATUS_IDLE;
+
+ return ISOTP_RET_OK;
+}
+
+void isotp_init_link(
+ IsoTpLink *link,
+ uint32_t sendid,
+ uint8_t *sendbuf,
+ uint16_t sendbufsize,
+ uint8_t *recvbuf,
+ uint16_t recvbufsize,
+ uint32_t (*isotp_user_get_ms)(void),
+ int (*isotp_user_send_can)(const uint32_t arbitration_id, const uint8_t* data, const uint8_t size, void *user_data),
+ void (*isotp_user_debug)(const char* message, ...),
+ void *user_data
+ ) {
+ memset(link, 0, sizeof(*link));
+ link->receive_status = ISOTP_RECEIVE_STATUS_IDLE;
+ link->send_status = ISOTP_SEND_STATUS_IDLE;
+ link->send_arbitration_id = sendid;
+ link->send_buffer = sendbuf;
+ link->send_buf_size = sendbufsize;
+ link->receive_buffer = recvbuf;
+ link->receive_buf_size = recvbufsize;
+ link->isotp_user_get_ms = isotp_user_get_ms;
+ link->isotp_user_send_can = isotp_user_send_can;
+ link->isotp_user_debug = isotp_user_debug;
+ link->user_data = user_data;
+
+ return;
+}
+
+void isotp_poll(IsoTpLink *link) {
+ int ret;
+
+ /* only polling when operation in progress */
+ if (ISOTP_SEND_STATUS_INPROGRESS == link->send_status) {
+
+ /* continue send data */
+ if (/* send data if bs_remain is invalid or bs_remain large than zero */
+ (ISOTP_INVALID_BS == link->send_bs_remain || link->send_bs_remain > 0) &&
+ /* and if st_min is zero or go beyond interval time */
+ (0 == link->send_st_min || (0 != link->send_st_min && IsoTpTimeAfter(link->isotp_user_get_ms(), link->send_timer_st)))) {
+
+ ret = isotp_send_consecutive_frame(link);
+ if (ISOTP_RET_OK == ret) {
+ if (ISOTP_INVALID_BS != link->send_bs_remain) {
+ link->send_bs_remain -= 1;
+ }
+ link->send_timer_bs = link->isotp_user_get_ms() + ISO_TP_DEFAULT_RESPONSE_TIMEOUT;
+ link->send_timer_st = link->isotp_user_get_ms() + link->send_st_min;
+
+ /* check if send finish */
+ if (link->send_offset >= link->send_size) {
+ link->send_status = ISOTP_SEND_STATUS_IDLE;
+ }
+ } else {
+ link->send_status = ISOTP_SEND_STATUS_ERROR;
+ }
+ }
+
+ /* check timeout */
+ if (IsoTpTimeAfter(link->isotp_user_get_ms(), link->send_timer_bs)) {
+ link->send_protocol_result = ISOTP_PROTOCOL_RESULT_TIMEOUT_BS;
+ link->send_status = ISOTP_SEND_STATUS_ERROR;
+ }
+ }
+
+ /* only polling when operation in progress */
+ if (ISOTP_RECEIVE_STATUS_INPROGRESS == link->receive_status) {
+
+ /* check timeout */
+ if (IsoTpTimeAfter(link->isotp_user_get_ms(), link->receive_timer_cr)) {
+ link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_TIMEOUT_CR;
+ link->receive_status = ISOTP_RECEIVE_STATUS_IDLE;
+ }
+ }
+
+ return;
+}
+
diff --git a/isotp.h b/isotp.h
new file mode 100644
index 0000000..65171f3
--- /dev/null
+++ b/isotp.h
@@ -0,0 +1,150 @@
+#ifndef __ISOTP_H__
+#define __ISOTP_H__
+
+#include
+#include
+
+#ifdef __cplusplus
+#include
+
+extern "C" {
+#endif
+
+#include "isotp_defines.h"
+#include "isotp_config.h"
+
+/**
+ * @brief Struct containing the data for linking an application to a CAN instance.
+ * The data stored in this struct is used internally and may be used by software programs
+ * using this library.
+ */
+typedef struct IsoTpLink {
+ /* sender paramters */
+ uint32_t send_arbitration_id; /* used to reply consecutive frame */
+ /* message buffer */
+ uint8_t* send_buffer;
+ uint16_t send_buf_size;
+ uint16_t send_size;
+ uint16_t send_offset;
+ /* multi-frame flags */
+ uint8_t send_sn;
+ uint16_t send_bs_remain; /* Remaining block size */
+ uint8_t send_st_min; /* Separation Time between consecutive frames, unit millis */
+ uint8_t send_wtf_count; /* Maximum number of FC.Wait frame transmissions */
+ uint32_t send_timer_st; /* Last time send consecutive frame */
+ uint32_t send_timer_bs; /* Time until reception of the next FlowControl N_PDU
+ start at sending FF, CF, receive FC
+ end at receive FC */
+ int send_protocol_result;
+ uint8_t send_status;
+
+ /* receiver paramters */
+ uint32_t receive_arbitration_id;
+ /* message buffer */
+ uint8_t* receive_buffer;
+ uint16_t receive_buf_size;
+ uint16_t receive_size;
+ uint16_t receive_offset;
+ /* multi-frame control */
+ uint8_t receive_sn;
+ uint8_t receive_bs_count; /* Maximum number of FC.Wait frame transmissions */
+ uint32_t receive_timer_cr; /* Time until transmission of the next ConsecutiveFrame N_PDU
+ start at sending FC, receive CF
+ end at receive FC */
+ int receive_protocol_result;
+ uint8_t receive_status;
+
+ /* user implemented callback functions */
+ uint32_t (*isotp_user_get_ms)(void); /* get millisecond */
+ int (*isotp_user_send_can)(const uint32_t arbitration_id,
+ const uint8_t* data, const uint8_t size, void *user_data); /* send can message. should return ISOTP_RET_OK when success. */
+ void (*isotp_user_debug)(const char* message, ...); /* print debug message */
+ void* user_data; /* user data */
+} IsoTpLink;
+
+/**
+ * @brief Initialises the ISO-TP library.
+ *
+ * @param link The @code IsoTpLink @endcode instance used for transceiving data.
+ * @param sendid The ID used to send data to other CAN nodes.
+ * @param sendbuf A pointer to an area in memory which can be used as a buffer for data to be sent.
+ * @param sendbufsize The size of the buffer area.
+ * @param recvbuf A pointer to an area in memory which can be used as a buffer for data to be received.
+ * @param recvbufsize The size of the buffer area.
+ * @param isotp_user_get_ms A pointer to a function which returns the current time as milliseconds.
+ * @param isotp_user_send_can A pointer to a function which sends a can message. should return ISOTP_RET_OK when success.
+ * @param isotp_user_debug A pointer to a function which prints a debug message.
+ * @param isotp_user_debug A pointer to user data passed to the user implemented callback functions.
+ */
+void isotp_init_link(
+ IsoTpLink *link,
+ uint32_t sendid,
+ uint8_t *sendbuf,
+ uint16_t sendbufsize,
+ uint8_t *recvbuf,
+ uint16_t recvbufsize,
+ uint32_t (*isotp_user_get_ms)(void),
+ int (*isotp_user_send_can)(const uint32_t arbitration_id, const uint8_t* data, const uint8_t size, void *user_data),
+ void (*isotp_user_debug)(const char* message, ...),
+ void *user_data
+ );
+
+/**
+ * @brief Polling function; call this function periodically to handle timeouts, send consecutive frames, etc.
+ *
+ * @param link The @code IsoTpLink @endcode instance used.
+ */
+void isotp_poll(IsoTpLink *link);
+
+/**
+ * @brief Handles incoming CAN messages.
+ * Determines whether an incoming message is a valid ISO-TP frame or not and handles it accordingly.
+ *
+ * @param link The @code IsoTpLink @endcode instance used for transceiving data.
+ * @param data The data received via CAN.
+ * @param len The length of the data received.
+ */
+void isotp_on_can_message(IsoTpLink *link, uint8_t *data, uint8_t len);
+
+/**
+ * @brief Sends ISO-TP frames via CAN, using the ID set in the initialising function.
+ *
+ * Single-frame messages will be sent immediately when calling this function.
+ * Multi-frame messages will be sent consecutively when calling isotp_poll.
+ *
+ * @param link The @code IsoTpLink @endcode instance used for transceiving data.
+ * @param payload The payload to be sent. (Up to 4095 bytes).
+ * @param size The size of the payload to be sent.
+ *
+ * @return Possible return values:
+ * - @code ISOTP_RET_OVERFLOW @endcode
+ * - @code ISOTP_RET_INPROGRESS @endcode
+ * - @code ISOTP_RET_OK @endcode
+ * - The return value of the user shim function isotp_user_send_can().
+ */
+int isotp_send(IsoTpLink *link, const uint8_t payload[], uint16_t size);
+
+/**
+ * @brief See @link isotp_send @endlink, with the exception that this function is used only for functional addressing.
+ */
+int isotp_send_with_id(IsoTpLink *link, uint32_t id, const uint8_t payload[], uint16_t size);
+
+/**
+ * @brief Receives and parses the received data and copies the parsed data in to the internal buffer.
+ * @param link The @link IsoTpLink @endlink instance used to transceive data.
+ * @param payload A pointer to an area in memory where the raw data is copied from.
+ * @param payload_size The size of the received (raw) CAN data.
+ * @param out_size A reference to a variable which will contain the size of the actual (parsed) data.
+ *
+ * @return Possible return values:
+ * - @link ISOTP_RET_OK @endlink
+ * - @link ISOTP_RET_NO_DATA @endlink
+ */
+int isotp_receive(IsoTpLink *link, uint8_t *payload, const uint16_t payload_size, uint16_t *out_size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __ISOTP_H__
+
diff --git a/isotp_config.h b/isotp_config.h
new file mode 100644
index 0000000..7f4223d
--- /dev/null
+++ b/isotp_config.h
@@ -0,0 +1,29 @@
+#ifndef __ISOTP_CONFIG__
+#define __ISOTP_CONFIG__
+
+/* Max number of messages the receiver can receive at one time, this value
+ * is affectied by can driver queue length
+ */
+#define ISO_TP_DEFAULT_BLOCK_SIZE 8
+
+/* The STmin parameter value specifies the minimum time gap allowed between
+ * the transmission of consecutive frame network protocol data units
+ */
+#define ISO_TP_DEFAULT_ST_MIN 0
+
+/* This parameter indicate how many FC N_PDU WTs can be transmitted by the
+ * receiver in a row.
+ */
+#define ISO_TP_MAX_WFT_NUMBER 1
+
+/* Private: The default timeout to use when waiting for a response during a
+ * multi-frame send or receive.
+ */
+#define ISO_TP_DEFAULT_RESPONSE_TIMEOUT 100
+
+/* Private: Determines if by default, padding is added to ISO-TP message frames.
+ */
+#define ISO_TP_FRAME_PADDING
+
+#endif
+
diff --git a/isotp_defines.h b/isotp_defines.h
new file mode 100644
index 0000000..d8217ad
--- /dev/null
+++ b/isotp_defines.h
@@ -0,0 +1,225 @@
+#ifndef __ISOTP_TYPES__
+#define __ISOTP_TYPES__
+
+/**************************************************************
+ * compiler specific defines
+ *************************************************************/
+#ifdef __GNUC__
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#define ISOTP_BYTE_ORDER_LITTLE_ENDIAN
+#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#else
+#error "unsupported byte ordering"
+#endif
+#endif
+
+/**************************************************************
+ * OS specific defines
+ *************************************************************/
+#ifdef _WIN32
+#define snprintf _snprintf
+#endif
+
+#ifdef _WIN32
+#define ISOTP_BYTE_ORDER_LITTLE_ENDIAN
+#define __builtin_bswap8 _byteswap_uint8
+#define __builtin_bswap16 _byteswap_uint16
+#define __builtin_bswap32 _byteswap_uint32
+#define __builtin_bswap64 _byteswap_uint64
+#endif
+
+/**************************************************************
+ * internal used defines
+ *************************************************************/
+#define ISOTP_RET_OK 0
+#define ISOTP_RET_ERROR -1
+#define ISOTP_RET_INPROGRESS -2
+#define ISOTP_RET_OVERFLOW -3
+#define ISOTP_RET_WRONG_SN -4
+#define ISOTP_RET_NO_DATA -5
+#define ISOTP_RET_TIMEOUT -6
+#define ISOTP_RET_LENGTH -7
+
+/* return logic true if 'a' is after 'b' */
+#define IsoTpTimeAfter(a,b) ((int32_t)((int32_t)(b) - (int32_t)(a)) < 0)
+
+/* invalid bs */
+#define ISOTP_INVALID_BS 0xFFFF
+
+/* ISOTP sender status */
+typedef enum {
+ ISOTP_SEND_STATUS_IDLE,
+ ISOTP_SEND_STATUS_INPROGRESS,
+ ISOTP_SEND_STATUS_ERROR,
+} IsoTpSendStatusTypes;
+
+/* ISOTP receiver status */
+typedef enum {
+ ISOTP_RECEIVE_STATUS_IDLE,
+ ISOTP_RECEIVE_STATUS_INPROGRESS,
+ ISOTP_RECEIVE_STATUS_FULL,
+} IsoTpReceiveStatusTypes;
+
+/* can fram defination */
+#if defined(ISOTP_BYTE_ORDER_LITTLE_ENDIAN)
+typedef struct {
+ uint8_t reserve_1:4;
+ uint8_t type:4;
+ uint8_t reserve_2[7];
+} IsoTpPciType;
+
+typedef struct {
+ uint8_t SF_DL:4;
+ uint8_t type:4;
+ uint8_t data[7];
+} IsoTpSingleFrame;
+
+typedef struct {
+ uint8_t FF_DL_high:4;
+ uint8_t type:4;
+ uint8_t FF_DL_low;
+ uint8_t data[6];
+} IsoTpFirstFrame;
+
+typedef struct {
+ uint8_t SN:4;
+ uint8_t type:4;
+ uint8_t data[7];
+} IsoTpConsecutiveFrame;
+
+typedef struct {
+ uint8_t FS:4;
+ uint8_t type:4;
+ uint8_t BS;
+ uint8_t STmin;
+ uint8_t reserve[5];
+} IsoTpFlowControl;
+
+#else
+
+typedef struct {
+ uint8_t type:4;
+ uint8_t reserve_1:4;
+ uint8_t reserve_2[7];
+} IsoTpPciType;
+
+/*
+* single frame
+* +-------------------------+-----+
+* | byte #0 | ... |
+* +-------------------------+-----+
+* | nibble #0 | nibble #1 | ... |
+* +-------------+-----------+ ... +
+* | PCIType = 0 | SF_DL | ... |
+* +-------------+-----------+-----+
+*/
+typedef struct {
+ uint8_t type:4;
+ uint8_t SF_DL:4;
+ uint8_t data[7];
+} IsoTpSingleFrame;
+
+/*
+* first frame
+* +-------------------------+-----------------------+-----+
+* | byte #0 | byte #1 | ... |
+* +-------------------------+-----------+-----------+-----+
+* | nibble #0 | nibble #1 | nibble #2 | nibble #3 | ... |
+* +-------------+-----------+-----------+-----------+-----+
+* | PCIType = 1 | FF_DL | ... |
+* +-------------+-----------+-----------------------+-----+
+*/
+typedef struct {
+ uint8_t type:4;
+ uint8_t FF_DL_high:4;
+ uint8_t FF_DL_low;
+ uint8_t data[6];
+} IsoTpFirstFrame;
+
+/*
+* consecutive frame
+* +-------------------------+-----+
+* | byte #0 | ... |
+* +-------------------------+-----+
+* | nibble #0 | nibble #1 | ... |
+* +-------------+-----------+ ... +
+* | PCIType = 0 | SN | ... |
+* +-------------+-----------+-----+
+*/
+typedef struct {
+ uint8_t type:4;
+ uint8_t SN:4;
+ uint8_t data[7];
+} IsoTpConsecutiveFrame;
+
+/*
+* flow control frame
+* +-------------------------+-----------------------+-----------------------+-----+
+* | byte #0 | byte #1 | byte #2 | ... |
+* +-------------------------+-----------+-----------+-----------+-----------+-----+
+* | nibble #0 | nibble #1 | nibble #2 | nibble #3 | nibble #4 | nibble #5 | ... |
+* +-------------+-----------+-----------+-----------+-----------+-----------+-----+
+* | PCIType = 1 | FS | BS | STmin | ... |
+* +-------------+-----------+-----------------------+-----------------------+-----+
+*/
+typedef struct {
+ uint8_t type:4;
+ uint8_t FS:4;
+ uint8_t BS;
+ uint8_t STmin;
+ uint8_t reserve[5];
+} IsoTpFlowControl;
+
+#endif
+
+typedef struct {
+ uint8_t ptr[8];
+} IsoTpDataArray;
+
+typedef struct {
+ union {
+ IsoTpPciType common;
+ IsoTpSingleFrame single_frame;
+ IsoTpFirstFrame first_frame;
+ IsoTpConsecutiveFrame consecutive_frame;
+ IsoTpFlowControl flow_control;
+ IsoTpDataArray data_array;
+ } as;
+} IsoTpCanMessage;
+
+/**************************************************************
+ * protocol specific defines
+ *************************************************************/
+
+/* Private: Protocol Control Information (PCI) types, for identifying each frame of an ISO-TP message.
+ */
+typedef enum {
+ ISOTP_PCI_TYPE_SINGLE = 0x0,
+ ISOTP_PCI_TYPE_FIRST_FRAME = 0x1,
+ TSOTP_PCI_TYPE_CONSECUTIVE_FRAME = 0x2,
+ ISOTP_PCI_TYPE_FLOW_CONTROL_FRAME = 0x3
+} IsoTpProtocolControlInformation;
+
+/* Private: Protocol Control Information (PCI) flow control identifiers.
+ */
+typedef enum {
+ PCI_FLOW_STATUS_CONTINUE = 0x0,
+ PCI_FLOW_STATUS_WAIT = 0x1,
+ PCI_FLOW_STATUS_OVERFLOW = 0x2
+} IsoTpFlowStatus;
+
+/* Private: network layer resault code.
+ */
+#define ISOTP_PROTOCOL_RESULT_OK 0
+#define ISOTP_PROTOCOL_RESULT_TIMEOUT_A -1
+#define ISOTP_PROTOCOL_RESULT_TIMEOUT_BS -2
+#define ISOTP_PROTOCOL_RESULT_TIMEOUT_CR -3
+#define ISOTP_PROTOCOL_RESULT_WRONG_SN -4
+#define ISOTP_PROTOCOL_RESULT_INVALID_FS -5
+#define ISOTP_PROTOCOL_RESULT_UNEXP_PDU -6
+#define ISOTP_PROTOCOL_RESULT_WFT_OVRN -7
+#define ISOTP_PROTOCOL_RESULT_BUFFER_OVFLW -8
+#define ISOTP_PROTOCOL_RESULT_ERROR -9
+
+#endif
+
diff --git a/vars.mk b/vars.mk
new file mode 100644
index 0000000..aaccb13
--- /dev/null
+++ b/vars.mk
@@ -0,0 +1,63 @@
+###
+# CROSS variable
+# Use for cross-compilation.
+# Uncommenting and setting this variable to the prefix of
+# your cross compiler will allow you to cross compile this library.
+###
+#CROSS=powerpc-linux-gnu
+
+###
+# LANG variable
+# Set this value according to the language
+# you wish to compile against.
+# Possible (legal) values:
+# - C [c]
+# - C++ [c++]
+###
+LANG := "C++"
+
+###
+# STD variables.
+# Do NOT set the STD variable.
+# Instead, set the C/C++ STD variables
+# according to the standard you wish to use.
+###
+CSTD := "gnu99"
+CPPSTD := "c++0x"
+
+###
+# OUTPUT_NAME variable.
+# This variable contains the name of the output file (the .so).
+###
+LIB_NAME := "libisotp.so"
+MAJOR_VER := "1"
+MINOR_VER := "0"
+REVISION := "0"
+OUTPUT_NAME := $(LIB_NAME).$(MAJOR_VER).$(MINOR_VER).$(REVISION)
+
+###
+# INSTALL_DIR variable.
+# Set this variable to the location where the lib should be installed.
+###
+INSTALL_DIR := /usr/lib
+
+###
+# Compute compiler and language standard to use
+# This section determines which compiler to use.
+###
+ifeq ($(LANG), "C++")
+STD := "-std=$(CPPSTD)"
+ifeq ($(strip $(CROSS)),)
+COMP := g++
+else
+COMP := $(CROSS)g++
+endif
+endif
+ifeq ($(LANG), "C")
+STD := "-std=$(CSTD)"
+ifeq ($(strip $(CROSS)),)
+COMP := gcc
+else
+COMP := $(CROSS)gcc
+endif
+endif
From acbc7ba4c39b6ee27184ece918c4ab0b12c625be Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Sat, 9 Dec 2023 23:09:42 -0700
Subject: [PATCH 22/56] add vcan test filter: prevent vcan tests from running
on github-actions
---
.github/workflows/runtests.yml | 2 +-
BUILD | 4 ++--
test/BUILD | 5 ++---
3 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/.github/workflows/runtests.yml b/.github/workflows/runtests.yml
index 06f2b07..1567da5 100644
--- a/.github/workflows/runtests.yml
+++ b/.github/workflows/runtests.yml
@@ -17,4 +17,4 @@ jobs:
with:
submodules: true
- name: build and run unit test
- run: bazel test //test:all
+ run: bazel test //test:all --test_tag_filters=-vcan
diff --git a/BUILD b/BUILD
index 026f950..b3b7ba9 100644
--- a/BUILD
+++ b/BUILD
@@ -12,7 +12,7 @@ genrule(
name = "isotp_c_wrapped_h",
srcs = glob(["src/tp/isotp-c/*.h"]),
outs = ["isotp_c_wrapped.h"],
- cmd = "echo '#if defined(UDS_ISOTP_C)' >> $(OUTS) ; for f in $(SRCS); do cat $$f >> $(OUTS); done ; echo '#endif' >> $(OUTS); cat $(OUTS)",
+ cmd = "echo '#if defined(UDS_ISOTP_C)' >> $(OUTS) ; for f in $(SRCS); do cat $$f >> $(OUTS); done ; echo '#endif' >> $(OUTS)",
)
genrule(
@@ -30,7 +30,7 @@ genrule(
":isotp_c_wrapped.h",
],
outs = ["iso14229.h"],
- cmd = "echo $(SRCS); (cat ; echo '#ifndef ISO14229_H'; echo '#define ISO14229_H'; echo; echo '#ifdef __cplusplus'; echo 'extern \"C\" {'; echo '#endif'; cat src/sys.h src/sys_arduino.h src/sys_unix.h src/sys_win32.h src/sys_esp32.h src/config.h src/util.h src/tp.h src/uds.h src/client.h src/server.h $(location //:isotp_c_wrapped.h) src/tp/*.h |sed -e 's,#include \".*,,' -e 's,^#pragma once,,' ; echo '#endif'; echo '#ifdef __cplusplus'; echo '}'; echo '#endif';) > $(OUTS) && cat $(OUTS)",
+ cmd = "echo $(SRCS); (cat ; echo '#ifndef ISO14229_H'; echo '#define ISO14229_H'; echo; echo '#ifdef __cplusplus'; echo 'extern \"C\" {'; echo '#endif'; cat src/sys.h src/sys_arduino.h src/sys_unix.h src/sys_win32.h src/sys_esp32.h src/config.h src/util.h src/tp.h src/uds.h src/client.h src/server.h $(location //:isotp_c_wrapped.h) src/tp/*.h |sed -e 's,#include \".*,,' -e 's,^#pragma once,,' ; echo '#endif'; echo '#ifdef __cplusplus'; echo '}'; echo '#endif';) > $(OUTS)",
)
filegroup(
diff --git a/test/BUILD b/test/BUILD
index e595b4e..5ea4fcc 100644
--- a/test/BUILD
+++ b/test/BUILD
@@ -66,7 +66,7 @@ TEST_NAMES = [ src.split(".c")[0] for src in TEST_SRCS ]
size = "small",
env = { "UDS_TP_TYPE": "1"},
copts = ["-g"],
- tags = [ "exclusive", ],
+ tags = [ "exclusive", "vcan"],
) for name, src in zip(TEST_NAMES, TEST_SRCS)
]
@@ -78,11 +78,10 @@ TEST_NAMES = [ src.split(".c")[0] for src in TEST_SRCS ]
size = "small",
env = { "UDS_TP_TYPE": "2"},
copts = ["-g"],
- tags = [ "exclusive", ],
+ tags = [ "exclusive", "vcan"],
) for name, src in zip(TEST_NAMES, TEST_SRCS)
]
-
cc_test(
name = "test_fuzz_server",
srcs = [
From ab9840d10e580ca41ced649b99ce29f8b6d0db9c Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Sat, 9 Dec 2023 23:23:20 -0700
Subject: [PATCH 23/56] add artifact upload
---
.github/workflows/runtests.yml | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/.github/workflows/runtests.yml b/.github/workflows/runtests.yml
index 1567da5..b3e0b83 100644
--- a/.github/workflows/runtests.yml
+++ b/.github/workflows/runtests.yml
@@ -16,5 +16,14 @@ jobs:
uses: actions/checkout@v3
with:
submodules: true
+
- name: build and run unit test
run: bazel test //test:all --test_tag_filters=-vcan
+
+ - name: upload artifacts
+ uses: actions/upload-artifact@v2
+ with:
+ name: artifacts
+ path: |
+ bazel-bin/iso14229.h
+ bazel-bin/iso14229.c
From 9686f67347d0869973ae22d84c3cd2d7d1197917 Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Sat, 9 Dec 2023 23:27:15 -0700
Subject: [PATCH 24/56] adjust artifact path
---
.github/workflows/runtests.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/runtests.yml b/.github/workflows/runtests.yml
index b3e0b83..a959299 100644
--- a/.github/workflows/runtests.yml
+++ b/.github/workflows/runtests.yml
@@ -21,7 +21,7 @@ jobs:
run: bazel test //test:all --test_tag_filters=-vcan
- name: upload artifacts
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v3
with:
name: artifacts
path: |
From 9fc23014b9b0347a8ffe6d715af6adec06c263df Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Sat, 9 Dec 2023 23:30:56 -0700
Subject: [PATCH 25/56] remove noise from h_src rule
---
BUILD | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/BUILD b/BUILD
index b3b7ba9..07bcd3b 100644
--- a/BUILD
+++ b/BUILD
@@ -30,7 +30,7 @@ genrule(
":isotp_c_wrapped.h",
],
outs = ["iso14229.h"],
- cmd = "echo $(SRCS); (cat ; echo '#ifndef ISO14229_H'; echo '#define ISO14229_H'; echo; echo '#ifdef __cplusplus'; echo 'extern \"C\" {'; echo '#endif'; cat src/sys.h src/sys_arduino.h src/sys_unix.h src/sys_win32.h src/sys_esp32.h src/config.h src/util.h src/tp.h src/uds.h src/client.h src/server.h $(location //:isotp_c_wrapped.h) src/tp/*.h |sed -e 's,#include \".*,,' -e 's,^#pragma once,,' ; echo '#endif'; echo '#ifdef __cplusplus'; echo '}'; echo '#endif';) > $(OUTS)",
+ cmd = "(cat ; echo '#ifndef ISO14229_H'; echo '#define ISO14229_H'; echo; echo '#ifdef __cplusplus'; echo 'extern \"C\" {'; echo '#endif'; cat src/sys.h src/sys_arduino.h src/sys_unix.h src/sys_win32.h src/sys_esp32.h src/config.h src/util.h src/tp.h src/uds.h src/client.h src/server.h $(location //:isotp_c_wrapped.h) src/tp/*.h |sed -e 's,#include \".*,,' -e 's,^#pragma once,,' ; echo '#endif'; echo '#ifdef __cplusplus'; echo '}'; echo '#endif';) > $(OUTS)",
)
filegroup(
From acbc51bcb4c409bddfb46475eff51cc6041ea651 Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Mon, 11 Dec 2023 22:07:31 -0700
Subject: [PATCH 26/56] tidy build configuration and docs
---
BUILD | 2 +-
Makefile | 46 ++++----------------------------------
README.md | 20 +++++++----------
run_gdb.py | 7 ++++--
src/server.h | 6 -----
src/tp/isotp_c_socketcan.c | 1 +
src/version.h | 2 ++
test/BUILD | 10 ++++-----
test/README.md | 3 +--
test/test_fuzz_server.c | 15 +++----------
10 files changed, 30 insertions(+), 82 deletions(-)
create mode 100644 src/version.h
diff --git a/BUILD b/BUILD
index 07bcd3b..f53db32 100644
--- a/BUILD
+++ b/BUILD
@@ -30,7 +30,7 @@ genrule(
":isotp_c_wrapped.h",
],
outs = ["iso14229.h"],
- cmd = "(cat ; echo '#ifndef ISO14229_H'; echo '#define ISO14229_H'; echo; echo '#ifdef __cplusplus'; echo 'extern \"C\" {'; echo '#endif'; cat src/sys.h src/sys_arduino.h src/sys_unix.h src/sys_win32.h src/sys_esp32.h src/config.h src/util.h src/tp.h src/uds.h src/client.h src/server.h $(location //:isotp_c_wrapped.h) src/tp/*.h |sed -e 's,#include \".*,,' -e 's,^#pragma once,,' ; echo '#endif'; echo '#ifdef __cplusplus'; echo '}'; echo '#endif';) > $(OUTS)",
+ cmd = "(cat ; echo '#ifndef ISO14229_H'; echo '#define ISO14229_H'; echo; echo '#ifdef __cplusplus'; echo 'extern \"C\" {'; echo '#endif'; cat src/version.h src/sys.h src/sys_arduino.h src/sys_unix.h src/sys_win32.h src/sys_esp32.h src/config.h src/util.h src/tp.h src/uds.h src/client.h src/server.h $(location //:isotp_c_wrapped.h) src/tp/*.h |sed -e 's,#include \".*,,' -e 's,^#pragma once,,' ; echo '#endif'; echo '#ifdef __cplusplus'; echo '}'; echo '#endif';) > $(OUTS)",
)
filegroup(
diff --git a/Makefile b/Makefile
index 6d17ac5..0cea42d 100644
--- a/Makefile
+++ b/Makefile
@@ -1,45 +1,7 @@
-ifeq "$(TP)" "ISOTP_C"
-SRCS += isotp-c/isotp.c examples/isotp-c_on_socketcan.c
-CFLAGS += -DUDS_TP=UDS_TP_ISOTP_C
-endif
-
-cxx: CFLAGS+=-DUDS_TP=UDS_TP_CUSTOM
-cxx: Makefile iso14229.c iso14229.h
- $(CXX) iso14229.c $(CFLAGS) -c
-
-unit_test: CFLAGS+=-DUDS_TP=UDS_TP_CUSTOM -DUDS_CUSTOM_MILLIS
-unit_test: Makefile iso14229.h iso14229.c test_iso14229.c
- $(CC) iso14229.c test_iso14229.c $(CFLAGS) $(LDFLAGS) -o test_iso14229
- $(RUN) ./test_iso14229
-
-client: CFLAGS+=-g -DUDS_DBG_PRINT=printf
-client: examples/client.c examples/uds_params.h iso14229.h iso14229.c Makefile $(SRCS)
- $(CC) iso14229.c $(SRCS) $< $(CFLAGS) -o $@
-
-server: CFLAGS+=-g -DUDS_DBG_PRINT=printf
-server: examples/server.c examples/uds_params.h iso14229.h iso14229.c Makefile $(SRCS)
- $(CC) iso14229.c $(SRCS) $< $(CFLAGS) -o $@
-
-test_examples: test_examples.py
- $(RUN) ./test_examples.py
-
-uds_prefix: CFLAGS+=-DUDS_TP=UDS_TP_CUSTOM -DUDS_CUSTOM_MILLIS
-uds_prefix: iso14229.c iso14229.h
- $(CC) iso14229.c $(CFLAGS) -c -o /tmp/x.o && nm /tmp/x.o | grep ' T ' | grep -v 'UDS' ; test $$? = 1
-
-test_qemu: Makefile iso14229.h iso14229.c test_iso14229.c test_qemu.py
- $(RUN) ./test_qemu.py
-
-test: cxx unit_test test_examples uds_prefix test_qemu
-
-fuzz: CC=clang-15
-fuzz: ASAN = -fsanitize=fuzzer,signed-integer-overflow,address,undefined -fprofile-instr-generate -fcoverage-mapping
-fuzz: OPTS = -g -DUDS_TP=UDS_TP_CUSTOM -DUDS_CUSTOM_MILLIS -I.
-fuzz: iso14229.c iso14229.h test/test_fuzz_server.c Makefile
- $(CC) $(OPTS) $(WARN) $(INCS) $(TFLAGS) $(ASAN) test/test_fuzz_server.c iso14229.c -o fuzzer
- $(RUN) ./fuzzer corpus
+iso14229.c iso14229.h:
+ mkdir -p build && bazel build //:iso14229.h //:iso14229.c && cp bazel-bin/iso14229.h bazel-bin/iso14229.c build/
clean:
- rm -f client server test_iso14229 iso14229.o
+ rm -rf build
-.phony: clean test_examples
\ No newline at end of file
+.phony: clean
diff --git a/README.md b/README.md
index 187ebe5..5aea98f 100644
--- a/README.md
+++ b/README.md
@@ -16,17 +16,14 @@ API status: **not yet stable**.
## Features
- static memory allocation. does not use `malloc`, `calloc`
-- highly portable. tested on arm, x86-64, ppc, ppc64
- easy to integrate. Download `iso14229.c` and `iso14229.h` from the releases page and copy into your source tree.
-- supports:
- - linux
- - Windows
- - esp32
- - Arduino
- - NXP s32k
+- highly portable and tested
+ - architectures: arm, x86-64, ppc, ppc64
+ - systems: linux, Windows, esp32, Arduino, NXP s32k
+ - transports: isotp-c, linux isotp sockets
- cares about security
- server has fuzz test, see [test/README.md](test/README.md)
- -
+ -
## Quick Start
@@ -36,10 +33,9 @@ See [examples](./examples).
| Define | Description | Valid values |
| - | - | - |
-| `UDS_SYS` | Select a porting target | `UDS_SYS_CUSTOM`, `UDS_SYS_UNIX` |
-| `UDS_TP` | Select a transport layer | `UDS_TP_ISOTP_C`, `UDS_TP_ISOTP_SOCKET` |
-| `UDS_CUSTOM_MILLIS` | Use your own `millis()` implementation | defined or not defined |
-
+| `UDS_SYS` | Select a porting target | see `sys.h` |
+| `UDS_TP` | Select a transport layer | see `tp.h` |
+| `UDS_...` | Additional compile-time config options | see `config.h` |
## supported functions (server and client )
diff --git a/run_gdb.py b/run_gdb.py
index a9056cc..5c8a25e 100755
--- a/run_gdb.py
+++ b/run_gdb.py
@@ -9,6 +9,7 @@
import subprocess
import argparse
+import os
GDB = "gdb-multiarch"
QEMU = "qemu-arm"
@@ -23,16 +24,18 @@
print(f"building {args.test}...")
bazel_args = ["bazel", "build", "-c", "dbg", "--copt=-g", f"//test:{args.test}"]
+if args.config:
+ bazel_args.append(f"--config={args.config}")
subprocess.check_call(bazel_args)
procs = []
-
if args.config:
qemu = subprocess.Popen(
[QEMU, "-g", str(GDB_PORT),
"-L", "/usr/arm-linux-gnueabihf/",
f"bazel-bin/test/{args.test}"],
+ env=os.environ.copy(),
)
if qemu.returncode is not None:
@@ -43,7 +46,7 @@
try:
- gdb = subprocess.Popen(gdb_args)
+ gdb = subprocess.Popen(gdb_args, env=os.environ.copy())
procs.append(gdb)
gdb.wait()
except KeyboardInterrupt:
diff --git a/src/server.h b/src/server.h
index a741232..35b1359 100644
--- a/src/server.h
+++ b/src/server.h
@@ -67,12 +67,6 @@ typedef struct UDSServer {
UDSReq_t r;
} UDSServer_t;
-// TODO: Remove
-typedef struct {
- uint8_t (*fn)(UDSServer_t *srv, UDSServerEvent_t event, const void *arg);
- UDSTpHandle_t *tp;
-} UDSServerConfig_t;
-
typedef struct {
const uint8_t type; /*! requested diagnostic session type (enum UDSDiagnosticSessionType) */
uint16_t p2_ms; /*! optional: p2 timing override */
diff --git a/src/tp/isotp_c_socketcan.c b/src/tp/isotp_c_socketcan.c
index 1977c32..fb6f437 100644
--- a/src/tp/isotp_c_socketcan.c
+++ b/src/tp/isotp_c_socketcan.c
@@ -12,6 +12,7 @@
#include
#include
#include
+#include
static int SetupSocketCAN(const char *ifname) {
UDS_DBG_PRINT("setting up CAN\n");
diff --git a/src/version.h b/src/version.h
new file mode 100644
index 0000000..9518c32
--- /dev/null
+++ b/src/version.h
@@ -0,0 +1,2 @@
+#pragma once
+#define UDS_VERSION "0.7.0"
diff --git a/test/BUILD b/test/BUILD
index 5ea4fcc..4ce91f7 100644
--- a/test/BUILD
+++ b/test/BUILD
@@ -66,7 +66,7 @@ TEST_NAMES = [ src.split(".c")[0] for src in TEST_SRCS ]
size = "small",
env = { "UDS_TP_TYPE": "1"},
copts = ["-g"],
- tags = [ "exclusive", "vcan"],
+ tags = [ "exclusive", "vcan", "isotp_sock"],
) for name, src in zip(TEST_NAMES, TEST_SRCS)
]
@@ -86,11 +86,11 @@ cc_test(
name = "test_fuzz_server",
srcs = [
"test_fuzz_server.c",
- "//:iso14229_srcs",
- "//tp:srcs",
+ "//:iso14229.h",
+ "//:iso14229.c",
],
defines = [
- "UDS_TP=UDS_TP_CUSTOM",
+ "UDS_TP_MOCK",
"UDS_CUSTOM_MILLIS",
# "UDS_DBG_PRINT=printf",
],
@@ -139,4 +139,4 @@ cc_library(
"-Wno-unused-macros",
],
target_compatible_with = ["//platforms/compiler:clang"],
-)
\ No newline at end of file
+)
diff --git a/test/README.md b/test/README.md
index e7fa3b6..3924031 100644
--- a/test/README.md
+++ b/test/README.md
@@ -29,7 +29,7 @@ clang-15 \
bazel test //test:all
# run tests in qemu
-bazel test --config=arm //test:all
+bazel test --config=arm_linux //test:all
bazel test --config=ppc //test:all
bazel test --config=ppc64 //test:all
bazel test --config=ppc64le //test:all
@@ -41,7 +41,6 @@ mkdir .libfuzzer_artifacts .libfuzzer_corpus
bazel-bin/test/test_fuzz_server -jobs=8 -artifact_prefix=./.libfuzzer_artifacts/ .libfuzzer_corpus
```
-
If building fails with `/usr/bin/ld: cannot find -lstdc++: No such file or directory`
```sh
diff --git a/test/test_fuzz_server.c b/test/test_fuzz_server.c
index ed6c994..2a3c870 100644
--- a/test/test_fuzz_server.c
+++ b/test/test_fuzz_server.c
@@ -5,7 +5,6 @@
#include
#include
#include "iso14229.h"
-#include "tp/mock.h"
#ifdef __cplusplus
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *, size_t);
@@ -35,15 +34,9 @@ static UDSServer_t srv;
static UDSTpHandle_t *mock_client = NULL;
void DoInitialization() {
- UDSServerConfig_t cfg = {
- .fn = fn,
- .tp = TPMockNew("server"),
- .target_addr = 0x7E0,
- .source_addr = 0x7E8,
- .source_addr_func = 0x7DF,
- };
- UDSServerInit(&srv, &cfg);
- mock_client = TPMockNew("client");
+ UDSServerInit(&srv);
+ srv.tp = TPMockNew("server", TPMOCK_DEFAULT_SERVER_ARGS);
+ mock_client = TPMockNew("client", TPMOCK_DEFAULT_CLIENT_ARGS);
}
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
@@ -54,8 +47,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
}
memset(&fuzz, 0, sizeof(fuzz));
memmove(&fuzz, data, size);
- srv.tp = TPMockNew("server");
- mock_client = TPMockNew("client");
UDSSDU_t msg = {
.A_Mtype = UDS_A_MTYPE_DIAG,
From 4b16ef1e7d177c432f967ab62812e7352d09f8de Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Mon, 11 Dec 2023 22:12:21 -0700
Subject: [PATCH 27/56] add release action
---
.github/workflows/runtests.yml | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/runtests.yml b/.github/workflows/runtests.yml
index a959299..6b5faea 100644
--- a/.github/workflows/runtests.yml
+++ b/.github/workflows/runtests.yml
@@ -12,12 +12,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- - name: Checkout
+ - name: checkout
uses: actions/checkout@v3
with:
submodules: true
- - name: build and run unit test
+ - name: run unit tests
run: bazel test //test:all --test_tag_filters=-vcan
- name: upload artifacts
@@ -27,3 +27,16 @@ jobs:
path: |
bazel-bin/iso14229.h
bazel-bin/iso14229.c
+
+ - name: release
+ uses: softprops/action-gh-release@v1
+ with:
+ files: |
+ bazel-bin/iso14229.h
+ bazel-bin/iso14229.c
+ tag_name: ${{ github.ref }}
+ body: ${{ github.event.head_commit.message }}
+ draft: false
+ prerelease: false
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
From 636fe4e19e4044fa3b6fd766ca4436cefd7b35f7 Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Mon, 11 Dec 2023 22:23:53 -0700
Subject: [PATCH 28/56] try softprops/action-gh-release
---
.github/workflows/{runtests.yml => ci.yml} | 4 ----
1 file changed, 4 deletions(-)
rename .github/workflows/{runtests.yml => ci.yml} (84%)
diff --git a/.github/workflows/runtests.yml b/.github/workflows/ci.yml
similarity index 84%
rename from .github/workflows/runtests.yml
rename to .github/workflows/ci.yml
index 6b5faea..c994656 100644
--- a/.github/workflows/runtests.yml
+++ b/.github/workflows/ci.yml
@@ -34,9 +34,5 @@ jobs:
files: |
bazel-bin/iso14229.h
bazel-bin/iso14229.c
- tag_name: ${{ github.ref }}
- body: ${{ github.event.head_commit.message }}
- draft: false
- prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
From 1ce747b8a7984e3115bae903fa02b3fb69360400 Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Mon, 11 Dec 2023 22:28:26 -0700
Subject: [PATCH 29/56] add if to ci.yml
---
.github/workflows/ci.yml | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index c994656..791dda0 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -29,7 +29,8 @@ jobs:
bazel-bin/iso14229.c
- name: release
- uses: softprops/action-gh-release@v1
+ uses: softprops/action-gh-release@v3
+ if: startsWith(github.ref, 'refs/tags/')
with:
files: |
bazel-bin/iso14229.h
From dd3f6d1a904db7d0ddc5d4d64eb1379246618229 Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Mon, 11 Dec 2023 22:35:50 -0700
Subject: [PATCH 30/56] use correct gh-release version
---
.github/workflows/ci.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 791dda0..c37eb83 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -29,7 +29,7 @@ jobs:
bazel-bin/iso14229.c
- name: release
- uses: softprops/action-gh-release@v3
+ uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
with:
files: |
From a63afd4bc2e61d0448ee2ecde04224105d471a93 Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Mon, 11 Dec 2023 22:41:39 -0700
Subject: [PATCH 31/56] update token name
---
.github/workflows/ci.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index c37eb83..7d92f62 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -36,4 +36,4 @@ jobs:
bazel-bin/iso14229.h
bazel-bin/iso14229.c
env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ GITHUB_TOKEN: ${{ secrets.TOKEN }}
From 128c9443a8e2f326986246784bb458dcddbe5811 Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Tue, 12 Dec 2023 21:14:04 -0700
Subject: [PATCH 32/56] format
---
run_clang_format.sh | 2 +-
src/client.c | 2 +-
src/client.h | 3 ---
src/config.h | 2 --
src/server.c | 7 ++++---
src/server.h | 3 ++-
src/sys.h | 2 --
src/sys_arduino.h | 2 +-
src/sys_esp32.h | 3 +--
src/sys_unix.h | 4 ++--
src/sys_win32.h | 2 +-
src/tp/isotp_c.c | 3 +--
src/tp/isotp_c.h | 4 ++--
src/tp/isotp_c_socketcan.c | 11 +++++++----
src/tp/isotp_sock.c | 3 +--
src/tp/mock.c | 2 +-
src/tp/mock.h | 1 -
src/uds.h | 3 +--
src/util.h | 16 +++++++---------
test/BUILD | 7 +------
20 files changed, 34 insertions(+), 48 deletions(-)
diff --git a/run_clang_format.sh b/run_clang_format.sh
index 7643ebc..b5add7f 100755
--- a/run_clang_format.sh
+++ b/run_clang_format.sh
@@ -1,6 +1,6 @@
#! /bin/bash
-files=`find . -type f \( -name '*.c' -o -name '*.h' \) -not -path "./tp/isotp-c/*"`
+files=`find src -type f \( -name '*.c' -o -name '*.h'\) -not -path "src/tp/isotp-c/*"`
for file in $files ; do
if [ -z "$CHECK_FORMAT" ] ; then
diff --git a/src/client.c b/src/client.c
index 1351727..4c13488 100644
--- a/src/client.c
+++ b/src/client.c
@@ -131,7 +131,7 @@ static inline void _ClientHandleResponse(UDSClient_t *client) {
uint16_t p2 = (client->recv_buf[2] << 8) + client->recv_buf[3];
uint32_t p2_star = ((client->recv_buf[4] << 8) + client->recv_buf[5]) * 10;
- UDS_DBG_PRINT("received new timings: p2: %"PRIu16", p2*: %"PRIu32"\n", p2, p2_star);
+ UDS_DBG_PRINT("received new timings: p2: %" PRIu16 ", p2*: %" PRIu32 "\n", p2, p2_star);
client->p2_ms = p2;
client->p2_star_ms = p2_star;
break;
diff --git a/src/client.h b/src/client.h
index 141edc6..144948e 100644
--- a/src/client.h
+++ b/src/client.h
@@ -4,7 +4,6 @@
#include "tp.h"
#include "uds.h"
-
enum UDSClientRequestState {
kRequestStateIdle = 0, // 完成
kRequestStateSending, // 传输层现在传输数据
@@ -140,5 +139,3 @@ UDSSeqState_t UDSClientAwaitIdle(UDSClient_t *client);
UDSErr_t UDSConfigDownload(UDSClient_t *client, uint8_t dataFormatIdentifier,
uint8_t addressAndLengthFormatIdentifier, size_t memoryAddress,
size_t memorySize, FILE *fd);
-
-
diff --git a/src/config.h b/src/config.h
index 0f0d173..5382f53 100644
--- a/src/config.h
+++ b/src/config.h
@@ -25,7 +25,6 @@
_Static_assert(UDS_CLIENT_DEFAULT_P2_STAR_MS > UDS_CLIENT_DEFAULT_P2_MS, "");
-
#ifndef UDS_SERVER_DEFAULT_POWER_DOWN_TIME_MS
#define UDS_SERVER_DEFAULT_POWER_DOWN_TIME_MS (10)
#endif
@@ -63,4 +62,3 @@ message to inform the client how many data bytes (maxNumberOfBlockLength) to inc
TransferData request message from the client. */
#define UDS_SERVER_DEFAULT_XFER_DATA_MAX_BLOCKLENGTH (UDS_TP_MTU)
#endif
-
diff --git a/src/server.c b/src/server.c
index 38146a7..73d115a 100644
--- a/src/server.c
+++ b/src/server.c
@@ -282,7 +282,8 @@ static uint8_t _0x27_SecurityAccess(UDSServer_t *srv, UDSReq_t *r) {
response = EmitEvent(srv, UDS_SRV_EVT_SecAccessValidateKey, &args);
if (kPositiveResponse != response) {
- srv->sec_access_auth_fail_timer = UDSMillis() + UDS_SERVER_0x27_BRUTE_FORCE_MITIGATION_AUTH_FAIL_DELAY_MS;
+ srv->sec_access_auth_fail_timer =
+ UDSMillis() + UDS_SERVER_0x27_BRUTE_FORCE_MITIGATION_AUTH_FAIL_DELAY_MS;
return NegativeResponse(r, response);
}
@@ -870,7 +871,7 @@ void UDSServerPoll(UDSServer_t *srv) {
EmitEvent(srv, UDS_SRV_EVT_DoScheduledReset, &srv->ecuResetScheduled);
}
- UDSTpStatus_t tpStatus = UDSTpPoll(srv->tp);
+ UDSTpPoll(srv->tp);
UDSReq_t *r = &srv->r;
@@ -924,7 +925,7 @@ void UDSServerPoll(UDSServer_t *srv) {
if (r->recv_len > 0) {
if (r->send_buf == NULL) {
UDS_DBG_PRINT("Send buf null\n");
- }
+ }
if (r->recv_buf == NULL) {
UDS_DBG_PRINT("Recv buf null\n");
}
diff --git a/src/server.h b/src/server.h
index 35b1359..c54b378 100644
--- a/src/server.h
+++ b/src/server.h
@@ -34,7 +34,8 @@ typedef struct UDSServer {
// has been sent to the client
uint32_t p2_timer; // for rate limiting server responses
uint32_t s3_session_timeout_timer; // indicates that diagnostic session has timed out
- uint32_t sec_access_auth_fail_timer; // brute-force hardening: rate limit security access requests
+ uint32_t
+ sec_access_auth_fail_timer; // brute-force hardening: rate limit security access requests
/**
* @brief UDS-1-2013: Table 407 - 0x36 TransferData Supported negative
diff --git a/src/sys.h b/src/sys.h
index 417e908..8afea10 100644
--- a/src/sys.h
+++ b/src/sys.h
@@ -6,7 +6,6 @@
#define UDS_SYS_ARDUINO 3
#define UDS_SYS_ESP32 4
-
#if !defined(UDS_SYS)
#if defined(__unix__) || defined(__APPLE__)
@@ -27,4 +26,3 @@
#include "sys_win32.h"
#include "sys_arduino.h"
#include "sys_esp32.h"
-
diff --git a/src/sys_arduino.h b/src/sys_arduino.h
index 39e6731..a926d1b 100644
--- a/src/sys_arduino.h
+++ b/src/sys_arduino.h
@@ -1,6 +1,6 @@
#pragma once
-#if UDS_SYS==UDS_SYS_ARDUINO
+#if UDS_SYS == UDS_SYS_ARDUINO
#include
#include
diff --git a/src/sys_esp32.h b/src/sys_esp32.h
index 6a2df9f..39afafa 100644
--- a/src/sys_esp32.h
+++ b/src/sys_esp32.h
@@ -1,6 +1,6 @@
#pragma once
-#if UDS_SYS==UDS_SYS_ESP32
+#if UDS_SYS == UDS_SYS_ESP32
#include
#include
@@ -11,4 +11,3 @@
#define UDS_ENABLE_ASSERT 1
#endif
-
diff --git a/src/sys_unix.h b/src/sys_unix.h
index ca3293b..6222363 100644
--- a/src/sys_unix.h
+++ b/src/sys_unix.h
@@ -1,6 +1,6 @@
#pragma once
-#if UDS_SYS==UDS_SYS_UNIX
+#if UDS_SYS == UDS_SYS_UNIX
#include
#include
@@ -12,4 +12,4 @@
#include
#include
-#endif
+#endif
diff --git a/src/sys_win32.h b/src/sys_win32.h
index 25d6c43..0bf3d94 100644
--- a/src/sys_win32.h
+++ b/src/sys_win32.h
@@ -1,6 +1,6 @@
#pragma once
-#if UDS_SYS==UDS_SYS_WIN32
+#if UDS_SYS == UDS_SYS_WIN32
#include
typedef SSIZE_T ssize_t;
diff --git a/src/tp/isotp_c.c b/src/tp/isotp_c.c
index a42da7c..b69bd6e 100644
--- a/src/tp/isotp_c.c
+++ b/src/tp/isotp_c.c
@@ -130,9 +130,8 @@ static void tp_ack_recv(UDSTpHandle_t *hdl) {
assert(hdl);
printf("ack recv\n");
UDSISOTpC_t *tp = (UDSISOTpC_t *)hdl;
- uint16_t out_size = 0;
+ uint16_t out_size = 0;
isotp_receive(&tp->phys_link, tp->recv_buf, sizeof(tp->recv_buf), &out_size);
-
}
static ssize_t tp_get_send_buf(UDSTpHandle_t *hdl, uint8_t **p_buf) {
diff --git a/src/tp/isotp_c.h b/src/tp/isotp_c.h
index 3e94abc..b525fce 100644
--- a/src/tp/isotp_c.h
+++ b/src/tp/isotp_c.h
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
#if defined(UDS_TP_ISOTP_C)
#include "sys.h"
@@ -34,4 +34,4 @@ UDSErr_t UDSISOTpCInit(UDSISOTpC_t *tp, const UDSISOTpCConfig_t *cfg);
void UDSISOTpCDeinit(UDSISOTpC_t *tp);
-#endif
+#endif
diff --git a/src/tp/isotp_c_socketcan.c b/src/tp/isotp_c_socketcan.c
index fb6f437..d8d808c 100644
--- a/src/tp/isotp_c_socketcan.c
+++ b/src/tp/isotp_c_socketcan.c
@@ -114,7 +114,8 @@ static UDSTpStatus_t isotp_c_socketcan_tp_poll(UDSTpHandle_t *hdl) {
return status;
}
-static int isotp_c_socketcan_tp_peek_link(IsoTpLink *link, uint8_t *buf, size_t bufsize, bool functional) {
+static int isotp_c_socketcan_tp_peek_link(IsoTpLink *link, uint8_t *buf, size_t bufsize,
+ bool functional) {
assert(link);
assert(buf);
int ret = -1;
@@ -163,7 +164,8 @@ static ssize_t isotp_c_socketcan_tp_peek(UDSTpHandle_t *hdl, uint8_t **p_buf, UD
} else if (ret < 0) {
goto done;
} else {
- ret = isotp_c_socketcan_tp_peek_link(&tp->func_link, tp->recv_buf, sizeof(tp->recv_buf), true);
+ ret = isotp_c_socketcan_tp_peek_link(&tp->func_link, tp->recv_buf, sizeof(tp->recv_buf),
+ true);
if (ret > 0) {
printf("just got %d bytes on func link \n", ret);
ta = tp->func_sa;
@@ -193,7 +195,8 @@ static ssize_t isotp_c_socketcan_tp_peek(UDSTpHandle_t *hdl, uint8_t **p_buf, UD
return ret;
}
-static ssize_t isotp_c_socketcan_tp_send(UDSTpHandle_t *hdl, uint8_t *buf, size_t len, UDSSDU_t *info) {
+static ssize_t isotp_c_socketcan_tp_send(UDSTpHandle_t *hdl, uint8_t *buf, size_t len,
+ UDSSDU_t *info) {
assert(hdl);
ssize_t ret = -1;
UDSTpISOTpC_t *tp = (UDSTpISOTpC_t *)hdl;
@@ -244,7 +247,7 @@ static void isotp_c_socketcan_tp_ack_recv(UDSTpHandle_t *hdl) {
assert(hdl);
printf("ack recv\n");
UDSTpISOTpC_t *tp = (UDSTpISOTpC_t *)hdl;
- uint16_t out_size = 0;
+ uint16_t out_size = 0;
isotp_receive(&tp->phys_link, tp->recv_buf, sizeof(tp->recv_buf), &out_size);
}
diff --git a/src/tp/isotp_sock.c b/src/tp/isotp_sock.c
index 966542b..28972b3 100644
--- a/src/tp/isotp_sock.c
+++ b/src/tp/isotp_sock.c
@@ -239,5 +239,4 @@ void UDSTpIsoTpSockDeinit(UDSTpIsoTpSock_t *tp) {
}
}
-#endif
-
+#endif
diff --git a/src/tp/mock.c b/src/tp/mock.c
index 2ce0f27..8ee088d 100644
--- a/src/tp/mock.c
+++ b/src/tp/mock.c
@@ -208,4 +208,4 @@ void TPMockFree(UDSTpHandle_t *tp) {
free(tp);
}
-#endif
+#endif
diff --git a/src/tp/mock.h b/src/tp/mock.h
index 13cff58..8b3d16e 100644
--- a/src/tp/mock.h
+++ b/src/tp/mock.h
@@ -64,4 +64,3 @@ void TPMockLogToStdout(void);
void TPMockReset(void);
#endif
-
diff --git a/src/uds.h b/src/uds.h
index 455d11e..269b6b2 100644
--- a/src/uds.h
+++ b/src/uds.h
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
enum UDSServerEvent {
UDS_SRV_EVT_DiagSessCtrl, // UDSDiagSessCtrlArgs_t *
@@ -156,7 +156,6 @@ enum DTCSettingType {
kDTCSettingOFF = 0x02,
};
-
// ISO-14229-1:2013 Table 2
#define UDS_MAX_DIAGNOSTIC_SERVICES 0x7F
diff --git a/src/util.h b/src/util.h
index fda75e2..01e1d6c 100644
--- a/src/util.h
+++ b/src/util.h
@@ -5,17 +5,17 @@
#if UDS_ENABLE_ASSERT
#include
-#else
+#else
#define assert(x)
#endif
#if UDS_ENABLE_DBG_PRINT
- #if defined(UDS_DBG_PRINT_IMPL)
- #define UDS_DBG_PRINT UDS_DBG_PRINT_IMPL
- #else
- #include
- #define UDS_DBG_PRINT printf
- #endif
+#if defined(UDS_DBG_PRINT_IMPL)
+#define UDS_DBG_PRINT UDS_DBG_PRINT_IMPL
+#else
+#include
+#define UDS_DBG_PRINT printf
+#endif
#else
#define UDS_DBG_PRINT(fmt, ...) ((void)fmt)
#endif
@@ -26,7 +26,6 @@
} \
UDS_DBG_PRINT("\n");
-
/* returns true if `a` is after `b` */
static inline bool UDSTimeAfter(uint32_t a, uint32_t b) {
return ((int32_t)((int32_t)(b) - (int32_t)(a)) < 0);
@@ -38,5 +37,4 @@ static inline bool UDSTimeAfter(uint32_t a, uint32_t b) {
*/
uint32_t UDSMillis(void);
-
bool UDSSecurityAccessLevelIsReserved(uint8_t securityLevel);
diff --git a/test/BUILD b/test/BUILD
index 4ce91f7..22ff166 100644
--- a/test/BUILD
+++ b/test/BUILD
@@ -131,12 +131,7 @@ cc_library(
"-Wextra",
"-Wpedantic",
"-Wno-unused-parameter",
- "-Wno-unused-function",
- "-Wno-unused-variable",
- "-Wno-unused-label",
- "-Wno-unused-value",
- "-Wno-unused-result",
- "-Wno-unused-macros",
+ "-Wno-gnu-zero-variadic-macro-arguments",
],
target_compatible_with = ["//platforms/compiler:clang"],
)
From 77f77fcc8a1c6baa1eea5e967d775a07a908b611 Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Tue, 12 Dec 2023 21:15:03 -0700
Subject: [PATCH 33/56] fix run_clang_format.sh
---
run_clang_format.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/run_clang_format.sh b/run_clang_format.sh
index b5add7f..8a1e8af 100755
--- a/run_clang_format.sh
+++ b/run_clang_format.sh
@@ -1,6 +1,6 @@
#! /bin/bash
-files=`find src -type f \( -name '*.c' -o -name '*.h'\) -not -path "src/tp/isotp-c/*"`
+files=`find src -type f \( -name '*.c' -o -name '*.h' \) -not -path "src/tp/isotp-c/*"`
for file in $files ; do
if [ -z "$CHECK_FORMAT" ] ; then
From c4e86ebf9429af38bc1776b970b1394fc9346038 Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Tue, 12 Dec 2023 21:17:19 -0700
Subject: [PATCH 34/56] add lint to build
---
.github/workflows/ci.yml | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 7d92f62..1fc99d7 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -17,6 +17,10 @@ jobs:
with:
submodules: true
+ - name: lint
+ run: CHECK_FORMAT=1 ./run_clang_format.sh
+ continue-on-error: true
+
- name: run unit tests
run: bazel test //test:all --test_tag_filters=-vcan
From ea0b196f113a579bceb54ce75f0b19d67c666dc2 Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Thu, 14 Dec 2023 22:57:03 -0700
Subject: [PATCH 35/56] add ./release.sh, release dir
---
BUILD | 2 +-
README.md | 10 +-
examples/client_multiserver/BUILD | 15 -
examples/client_multiserver/main.c | 59 -
examples/client_multiserver/server1.c | 1 -
examples/client_multiserver/server2.c | 0
release.sh | 4 +
release/iso14229.c | 3375 +++++++++++++++++++++++++
release/iso14229.h | 1385 ++++++++++
test/README.md | 4 +-
10 files changed, 4773 insertions(+), 82 deletions(-)
delete mode 100644 examples/client_multiserver/BUILD
delete mode 100644 examples/client_multiserver/main.c
delete mode 100644 examples/client_multiserver/server1.c
delete mode 100644 examples/client_multiserver/server2.c
create mode 100755 release.sh
create mode 100644 release/iso14229.c
create mode 100644 release/iso14229.h
diff --git a/BUILD b/BUILD
index f53db32..33c78ef 100644
--- a/BUILD
+++ b/BUILD
@@ -71,4 +71,4 @@ refresh_compile_commands(
targets = {
"//examples/s32k144/...": "--config=s32k",
}
-)
\ No newline at end of file
+)
diff --git a/README.md b/README.md
index 5aea98f..9de9484 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,12 @@ iso14229 is an implementation of UDS (ISO14229-1:2013) targeting embedded system
API status: **not yet stable**.
+
+## Quick Start
+
+1. Get `iso14229.c` and `iso14229.h` from the [release](./release) directory, copy into your source tree and build.
+2. See [examples](./examples).
+
## Features
- static memory allocation. does not use `malloc`, `calloc`
@@ -25,10 +31,6 @@ API status: **not yet stable**.
- server has fuzz test, see [test/README.md](test/README.md)
-
-## Quick Start
-
-See [examples](./examples).
-
## Preprocessor Defines
| Define | Description | Valid values |
diff --git a/examples/client_multiserver/BUILD b/examples/client_multiserver/BUILD
deleted file mode 100644
index 4e5b9b7..0000000
--- a/examples/client_multiserver/BUILD
+++ /dev/null
@@ -1,15 +0,0 @@
-# cc_binary(
-# name = "client_multiserver",
-# srcs = [
-# "main.c",
-# "server1.c",
-# "server2.c",
-# ],
-# deps = [
-# "//:iso14229",
-# "//:tp_mock",
-# ],
-# defines = [
-# "UDS_TP=UDS_TP_CUSTOM",
-# ]
-# )
\ No newline at end of file
diff --git a/examples/client_multiserver/main.c b/examples/client_multiserver/main.c
deleted file mode 100644
index f859906..0000000
--- a/examples/client_multiserver/main.c
+++ /dev/null
@@ -1,59 +0,0 @@
-#include "iso14229.h"
-#include "tp_mock.h"
-
-typedef struct {
- bool Done;
- int NumResponses;
- int Step;
-} Ctx_t;
-
-void fn(UDSClient_t *client, UDSEvent_t evt, void *evtdata, void *fndata) {
- Ctx_t *ctx = (Ctx_t *)fndata;
- switch (evt) {
- case UDS_EVT_IDLE:
- switch (ctx->Step) {
- case 0:
- client->options |= UDS_FUNCTIONAL;
- uint16_t did_list[] = {0x1, 0x8};
- UDSSendRDBI(client, did_list, sizeof(did_list) / sizeof(did_list[0]));
- ctx->Step++;
- break;
- default:
- break;
- }
- break;
- case UDS_EVT_RESP_RECV:
- switch (ctx->Step) {
- case 1:
- ctx->NumResponses++;
- // int err = UDSUnpackRDBIResponse(client, evtdata);
- ctx->Step++;
- break;
- default:
- break;
- }
- break;
- }
-}
-
-int main() {
- UDSClient_t client;
- Ctx_t ctx = {0};
- UDSServer_t server1, server2, server3;
-
- {
- UDSClientConfig_t cfg = {
- .tp = TPMockNew(&(TPMockCfg_t){.phys_recv_addr = 0x1,
- .phys_send_addr = 0x2,
- .func_recv_addr = 0x3,
- .func_send_addr = 0x4});
- }
- UDSClientInit(&client, &cfg);
-}
-
-while (!ctx.Done) {
- UDSClientPoll2(&client, fn, &ctx);
- UDSServerPoll(&server1);
- UDSServerPoll(&server2);
-}
-}
\ No newline at end of file
diff --git a/examples/client_multiserver/server1.c b/examples/client_multiserver/server1.c
deleted file mode 100644
index 5a56d0d..0000000
--- a/examples/client_multiserver/server1.c
+++ /dev/null
@@ -1 +0,0 @@
-#include "iso14229.h"
diff --git a/examples/client_multiserver/server2.c b/examples/client_multiserver/server2.c
deleted file mode 100644
index e69de29..0000000
diff --git a/release.sh b/release.sh
new file mode 100755
index 0000000..d39eeeb
--- /dev/null
+++ b/release.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+rm -f release/iso14229.c release/iso14229.h
+cp bazel-bin/iso14229.c release/iso14229.c && chmod 644 release/iso14229.c
+cp bazel-bin/iso14229.h release/iso14229.h && chmod 644 release/iso14229.h
\ No newline at end of file
diff --git a/release/iso14229.c b/release/iso14229.c
new file mode 100644
index 0000000..ee3d88d
--- /dev/null
+++ b/release/iso14229.c
@@ -0,0 +1,3375 @@
+#include "iso14229.h"
+
+#ifdef UDS_LINES
+#line 1 "src/client.c"
+#endif
+
+
+
+
+static void clearRequestContext(UDSClient_t *client) {
+ assert(client);
+ client->recv_size = 0;
+ client->send_size = 0;
+ client->state = kRequestStateIdle;
+ client->err = UDS_OK;
+}
+
+UDSErr_t UDSClientInit(UDSClient_t *client) {
+ assert(client);
+ memset(client, 0, sizeof(*client));
+
+ client->p2_ms = UDS_CLIENT_DEFAULT_P2_MS;
+ client->p2_star_ms = UDS_CLIENT_DEFAULT_P2_STAR_MS;
+
+ if (client->p2_star_ms < client->p2_ms) {
+ fprintf(stderr, "p2_star_ms must be >= p2_ms\n");
+ client->p2_star_ms = client->p2_ms;
+ }
+
+ clearRequestContext(client);
+ return UDS_OK;
+}
+
+static const char *ClientStateName(enum UDSClientRequestState state) {
+ switch (state) {
+ case kRequestStateIdle:
+ return "Idle";
+ case kRequestStateSending:
+ return "Sending";
+ case kRequestStateAwaitSendComplete:
+ return "AwaitSendComplete";
+ case kRequestStateAwaitResponse:
+ return "AwaitResponse";
+ case kRequestStateProcessResponse:
+ return "ProcessResponse";
+ default:
+ return "Unknown";
+ }
+}
+
+static void changeState(UDSClient_t *client, enum UDSClientRequestState state) {
+ printf("client state: %s (%d) -> %s (%d)\n", ClientStateName(client->state), client->state,
+ ClientStateName(state), state);
+ client->state = state;
+}
+
+/**
+ * @brief Check that the response is a valid UDS response
+ *
+ * @param ctx
+ * @return UDSErr_t
+ */
+static UDSErr_t _ClientValidateResponse(const UDSClient_t *client) {
+
+ if (client->recv_size < 1) {
+ return UDS_ERR_RESP_TOO_SHORT;
+ }
+
+ if (0x7F == client->recv_buf[0]) { // 否定响应
+ if (client->recv_size < 2) {
+ return UDS_ERR_RESP_TOO_SHORT;
+ } else if (client->send_buf[0] != client->recv_buf[1]) {
+ return UDS_ERR_SID_MISMATCH;
+ } else if (kRequestCorrectlyReceived_ResponsePending == client->recv_buf[2]) {
+ return UDS_OK;
+ } else if (client->_options_copy & UDS_NEG_RESP_IS_ERR) {
+ return UDS_ERR_NEG_RESP;
+ } else {
+ ;
+ }
+ } else { // 肯定响应
+ if (UDS_RESPONSE_SID_OF(client->send_buf[0]) != client->recv_buf[0]) {
+ return UDS_ERR_SID_MISMATCH;
+ }
+ switch (client->send_buf[0]) {
+ case kSID_ECU_RESET:
+ if (client->recv_size < 2) {
+ return UDS_ERR_RESP_TOO_SHORT;
+ } else if (client->send_buf[1] != client->recv_buf[1]) {
+ return UDS_ERR_SUBFUNCTION_MISMATCH;
+ } else {
+ ;
+ }
+ break;
+ }
+ }
+
+ return UDS_OK;
+}
+
+/**
+ * @brief Handle validated server response
+ * @param client
+ */
+static inline void _ClientHandleResponse(UDSClient_t *client) {
+ if (0x7F == client->recv_buf[0]) {
+ if (kRequestCorrectlyReceived_ResponsePending == client->recv_buf[2]) {
+ UDS_DBG_PRINT("got RCRRP, setting p2 timer\n");
+ client->p2_timer = UDSMillis() + client->p2_star_ms;
+ memset(client->recv_buf, 0, client->recv_buf_size);
+ client->recv_size = 0;
+ UDSTpAckRecv(client->tp);
+ changeState(client, kRequestStateAwaitResponse);
+ return;
+ } else {
+ ;
+ }
+ } else {
+ uint8_t respSid = client->recv_buf[0];
+ switch (UDS_REQUEST_SID_OF(respSid)) {
+ case kSID_DIAGNOSTIC_SESSION_CONTROL: {
+ if (client->recv_size < UDS_0X10_RESP_LEN) {
+ UDS_DBG_PRINT("Error: SID %x response too short\n",
+ kSID_DIAGNOSTIC_SESSION_CONTROL);
+ client->err = UDS_ERR_RESP_TOO_SHORT;
+ UDSTpAckRecv(client->tp);
+ changeState(client, kRequestStateIdle);
+ return;
+ }
+
+ if (client->_options_copy & UDS_IGNORE_SRV_TIMINGS) {
+ UDSTpAckRecv(client->tp);
+ changeState(client, kRequestStateIdle);
+ return;
+ }
+
+ uint16_t p2 = (client->recv_buf[2] << 8) + client->recv_buf[3];
+ uint32_t p2_star = ((client->recv_buf[4] << 8) + client->recv_buf[5]) * 10;
+ UDS_DBG_PRINT("received new timings: p2: %" PRIu16 ", p2*: %" PRIu32 "\n", p2, p2_star);
+ client->p2_ms = p2;
+ client->p2_star_ms = p2_star;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ UDSTpAckRecv(client->tp);
+ changeState(client, kRequestStateIdle);
+}
+
+/**
+ * @brief execute the client request state machine
+ * @param client
+ */
+static void PollLowLevel(UDSClient_t *client) {
+ assert(client);
+ UDSTpStatus_t tp_status = client->tp->poll(client->tp);
+ switch (client->state) {
+ case kRequestStateIdle: {
+ client->options = client->defaultOptions;
+ break;
+ }
+ case kRequestStateSending: {
+ UDSTpAddr_t ta_type = client->_options_copy & UDS_FUNCTIONAL ? UDS_A_TA_TYPE_FUNCTIONAL
+ : UDS_A_TA_TYPE_PHYSICAL;
+ UDSSDU_t info = {
+ .A_Mtype = UDS_A_MTYPE_DIAG,
+ .A_TA_Type = ta_type,
+ };
+ ssize_t ret = UDSTpSend(client->tp, client->send_buf, client->send_size, &info);
+ if (ret < 0) {
+ client->err = UDS_ERR_TPORT;
+ UDS_DBG_PRINT("tport err: %zd\n", ret);
+ } else if (0 == ret) {
+ UDS_DBG_PRINT("send in progress...\n");
+ ; // 等待发送成功
+ } else if (client->send_size == ret) {
+ changeState(client, kRequestStateAwaitSendComplete);
+ } else {
+ client->err = UDS_ERR_BUFSIZ;
+ }
+ break;
+ }
+ case kRequestStateAwaitSendComplete: {
+ if (client->_options_copy & UDS_FUNCTIONAL) {
+ // "The Functional addressing is applied only to single frame transmission"
+ // Specification of Diagnostic Communication (Diagnostic on CAN - Network Layer)
+ changeState(client, kRequestStateIdle);
+ }
+ if (tp_status & UDS_TP_SEND_IN_PROGRESS) {
+ ; // await send complete
+ } else {
+ if (client->_options_copy & UDS_SUPPRESS_POS_RESP) {
+ changeState(client, kRequestStateIdle);
+ } else {
+ changeState(client, kRequestStateAwaitResponse);
+ client->p2_timer = UDSMillis() + client->p2_ms;
+ }
+ }
+ break;
+ }
+ case kRequestStateAwaitResponse: {
+ UDSSDU_t info = {0};
+ ssize_t len = UDSTpPeek(client->tp, &client->recv_buf, &info);
+
+ if (UDS_A_TA_TYPE_FUNCTIONAL == info.A_TA_Type) {
+ UDSTpAckRecv(client->tp);
+ break;
+ }
+ if (len < 0) {
+ client->err = UDS_ERR_TPORT;
+ changeState(client, kRequestStateIdle);
+ } else if (0 == len) {
+ if (UDSTimeAfter(UDSMillis(), client->p2_timer)) {
+ client->err = UDS_ERR_TIMEOUT;
+ changeState(client, kRequestStateIdle);
+ }
+ } else {
+ printf("received %zd bytes\n", len);
+ client->recv_size = len;
+ changeState(client, kRequestStateProcessResponse);
+ }
+ break;
+ }
+ case kRequestStateProcessResponse: {
+ client->err = _ClientValidateResponse(client);
+ if (UDS_OK == client->err) {
+ _ClientHandleResponse(client);
+ } else {
+ UDSTpAckRecv(client->tp);
+ changeState(client, kRequestStateIdle);
+ }
+ break;
+ }
+
+ default:
+ assert(0);
+ }
+}
+
+static UDSErr_t _SendRequest(UDSClient_t *client) {
+ client->_options_copy = client->options;
+
+ if (client->_options_copy & UDS_SUPPRESS_POS_RESP) {
+ // UDS-1:2013 8.2.2 Table 11
+ client->send_buf[1] |= 0x80;
+ }
+
+ changeState(client, kRequestStateSending);
+ PollLowLevel(client); // poll once to begin sending immediately
+ return UDS_OK;
+}
+
+static UDSErr_t PreRequestCheck(UDSClient_t *client) {
+ if (kRequestStateIdle != client->state) {
+ return UDS_ERR_BUSY;
+ }
+ clearRequestContext(client);
+ if (client->tp == NULL) {
+ return UDS_ERR_TPORT;
+ }
+ ssize_t ret = UDSTpGetSendBuf(client->tp, &client->send_buf);
+ if (ret < 0) {
+ return UDS_ERR_TPORT;
+ }
+ client->send_buf_size = ret;
+ return UDS_OK;
+}
+
+UDSErr_t UDSSendBytes(UDSClient_t *client, const uint8_t *data, uint16_t size) {
+ UDSErr_t err = PreRequestCheck(client);
+ if (err) {
+ return err;
+ }
+ if (size > client->send_buf_size) {
+ return UDS_ERR_BUFSIZ;
+ }
+ memmove(client->send_buf, data, size);
+ client->send_size = size;
+ return _SendRequest(client);
+}
+
+UDSErr_t UDSSendECUReset(UDSClient_t *client, UDSECUReset_t type) {
+ UDSErr_t err = PreRequestCheck(client);
+ if (err) {
+ return err;
+ }
+ client->send_buf[0] = kSID_ECU_RESET;
+ client->send_buf[1] = type;
+ client->send_size = 2;
+ return _SendRequest(client);
+}
+
+UDSErr_t UDSSendDiagSessCtrl(UDSClient_t *client, enum UDSDiagnosticSessionType mode) {
+ UDSErr_t err = PreRequestCheck(client);
+ if (err) {
+ return err;
+ }
+ client->send_buf[0] = kSID_DIAGNOSTIC_SESSION_CONTROL;
+ client->send_buf[1] = mode;
+ client->send_size = 2;
+ return _SendRequest(client);
+}
+
+UDSErr_t UDSSendCommCtrl(UDSClient_t *client, enum UDSCommunicationControlType ctrl,
+ enum UDSCommunicationType comm) {
+ UDSErr_t err = PreRequestCheck(client);
+ if (err) {
+ return err;
+ }
+ client->send_buf[0] = kSID_COMMUNICATION_CONTROL;
+ client->send_buf[1] = ctrl;
+ client->send_buf[2] = comm;
+ client->send_size = 3;
+ return _SendRequest(client);
+}
+
+UDSErr_t UDSSendTesterPresent(UDSClient_t *client) {
+ UDSErr_t err = PreRequestCheck(client);
+ if (err) {
+ return err;
+ }
+ client->send_buf[0] = kSID_TESTER_PRESENT;
+ client->send_buf[1] = 0;
+ client->send_size = 2;
+ return _SendRequest(client);
+}
+
+UDSErr_t UDSSendRDBI(UDSClient_t *client, const uint16_t *didList,
+ const uint16_t numDataIdentifiers) {
+ UDSErr_t err = PreRequestCheck(client);
+ if (err) {
+ return err;
+ }
+ assert(didList);
+ assert(numDataIdentifiers);
+ client->send_buf[0] = kSID_READ_DATA_BY_IDENTIFIER;
+ for (int i = 0; i < numDataIdentifiers; i++) {
+ uint16_t offset = 1 + sizeof(uint16_t) * i;
+ if (offset + 2 > client->send_buf_size) {
+ return UDS_ERR_INVALID_ARG;
+ }
+ (client->send_buf + offset)[0] = (didList[i] & 0xFF00) >> 8;
+ (client->send_buf + offset)[1] = (didList[i] & 0xFF);
+ }
+ client->send_size = 1 + (numDataIdentifiers * sizeof(uint16_t));
+ return _SendRequest(client);
+}
+
+UDSErr_t UDSSendWDBI(UDSClient_t *client, uint16_t dataIdentifier, const uint8_t *data,
+ uint16_t size) {
+ UDSErr_t err = PreRequestCheck(client);
+ if (err) {
+ return err;
+ }
+ assert(data);
+ assert(size);
+ client->send_buf[0] = kSID_WRITE_DATA_BY_IDENTIFIER;
+ if (client->send_buf_size <= 3 || size > client->send_buf_size - 3) {
+ return UDS_ERR_BUFSIZ;
+ }
+ client->send_buf[1] = (dataIdentifier & 0xFF00) >> 8;
+ client->send_buf[2] = (dataIdentifier & 0xFF);
+ memmove(&client->send_buf[3], data, size);
+ client->send_size = 3 + size;
+ return _SendRequest(client);
+}
+
+/**
+ * @brief RoutineControl
+ *
+ * @param client
+ * @param type
+ * @param routineIdentifier
+ * @param data
+ * @param size
+ * @return UDSErr_t
+ * @addtogroup routineControl_0x31
+ */
+UDSErr_t UDSSendRoutineCtrl(UDSClient_t *client, enum RoutineControlType type,
+ uint16_t routineIdentifier, const uint8_t *data, uint16_t size) {
+ UDSErr_t err = PreRequestCheck(client);
+ if (err) {
+ return err;
+ }
+ client->send_buf[0] = kSID_ROUTINE_CONTROL;
+ client->send_buf[1] = type;
+ client->send_buf[2] = routineIdentifier >> 8;
+ client->send_buf[3] = routineIdentifier;
+ if (size) {
+ assert(data);
+ if (size > client->send_buf_size - UDS_0X31_REQ_MIN_LEN) {
+ return UDS_ERR_BUFSIZ;
+ }
+ memmove(&client->send_buf[UDS_0X31_REQ_MIN_LEN], data, size);
+ } else {
+ assert(NULL == data);
+ }
+ client->send_size = UDS_0X31_REQ_MIN_LEN + size;
+ return _SendRequest(client);
+}
+
+/**
+ * @brief
+ *
+ * @param client
+ * @param dataFormatIdentifier
+ * @param addressAndLengthFormatIdentifier
+ * @param memoryAddress
+ * @param memorySize
+ * @return UDSErr_t
+ * @addtogroup requestDownload_0x34
+ */
+UDSErr_t UDSSendRequestDownload(UDSClient_t *client, uint8_t dataFormatIdentifier,
+ uint8_t addressAndLengthFormatIdentifier, size_t memoryAddress,
+ size_t memorySize) {
+ UDSErr_t err = PreRequestCheck(client);
+ if (err) {
+ return err;
+ }
+ uint8_t numMemorySizeBytes = (addressAndLengthFormatIdentifier & 0xF0) >> 4;
+ uint8_t numMemoryAddressBytes = addressAndLengthFormatIdentifier & 0x0F;
+
+ client->send_buf[0] = kSID_REQUEST_DOWNLOAD;
+ client->send_buf[1] = dataFormatIdentifier;
+ client->send_buf[2] = addressAndLengthFormatIdentifier;
+
+ uint8_t *ptr = &client->send_buf[UDS_0X34_REQ_BASE_LEN];
+
+ for (int i = numMemoryAddressBytes - 1; i >= 0; i--) {
+ *ptr = (memoryAddress & (0xFF << (8 * i))) >> (8 * i);
+ ptr++;
+ }
+
+ for (int i = numMemorySizeBytes - 1; i >= 0; i--) {
+ *ptr = (memorySize & (0xFF << (8 * i))) >> (8 * i);
+ ptr++;
+ }
+
+ client->send_size = UDS_0X34_REQ_BASE_LEN + numMemoryAddressBytes + numMemorySizeBytes;
+ return _SendRequest(client);
+}
+
+/**
+ * @brief
+ *
+ * @param client
+ * @param dataFormatIdentifier
+ * @param addressAndLengthFormatIdentifier
+ * @param memoryAddress
+ * @param memorySize
+ * @return UDSErr_t
+ * @addtogroup requestDownload_0x35
+ */
+UDSErr_t UDSSendRequestUpload(UDSClient_t *client, uint8_t dataFormatIdentifier,
+ uint8_t addressAndLengthFormatIdentifier, size_t memoryAddress,
+ size_t memorySize) {
+ UDSErr_t err = PreRequestCheck(client);
+ if (err) {
+ return err;
+ }
+ uint8_t numMemorySizeBytes = (addressAndLengthFormatIdentifier & 0xF0) >> 4;
+ uint8_t numMemoryAddressBytes = addressAndLengthFormatIdentifier & 0x0F;
+
+ client->send_buf[0] = kSID_REQUEST_UPLOAD;
+ client->send_buf[1] = dataFormatIdentifier;
+ client->send_buf[2] = addressAndLengthFormatIdentifier;
+
+ uint8_t *ptr = &client->send_buf[UDS_0X35_REQ_BASE_LEN];
+
+ for (int i = numMemoryAddressBytes - 1; i >= 0; i--) {
+ *ptr = (memoryAddress & (0xFF << (8 * i))) >> (8 * i);
+ ptr++;
+ }
+
+ for (int i = numMemorySizeBytes - 1; i >= 0; i--) {
+ *ptr = (memorySize & (0xFF << (8 * i))) >> (8 * i);
+ ptr++;
+ }
+
+ client->send_size = UDS_0X35_REQ_BASE_LEN + numMemoryAddressBytes + numMemorySizeBytes;
+ return _SendRequest(client);
+}
+
+/**
+ * @brief
+ *
+ * @param client
+ * @param blockSequenceCounter
+ * @param blockLength
+ * @param fd
+ * @return UDSErr_t
+ * @addtogroup transferData_0x36
+ */
+UDSErr_t UDSSendTransferData(UDSClient_t *client, uint8_t blockSequenceCounter,
+ const uint16_t blockLength, const uint8_t *data, uint16_t size) {
+ UDSErr_t err = PreRequestCheck(client);
+ if (err) {
+ return err;
+ }
+ assert(blockLength > 2); // blockLength must include SID and sequenceCounter
+ assert(size + 2 <= blockLength); // data must fit inside blockLength - 2
+ client->send_buf[0] = kSID_TRANSFER_DATA;
+ client->send_buf[1] = blockSequenceCounter;
+ memmove(&client->send_buf[UDS_0X36_REQ_BASE_LEN], data, size);
+ UDS_DBG_PRINT("size: %d, blocklength: %d\n", size, blockLength);
+ client->send_size = UDS_0X36_REQ_BASE_LEN + size;
+ return _SendRequest(client);
+}
+
+UDSErr_t UDSSendTransferDataStream(UDSClient_t *client, uint8_t blockSequenceCounter,
+ const uint16_t blockLength, FILE *fd) {
+ UDSErr_t err = PreRequestCheck(client);
+ if (err) {
+ return err;
+ }
+ assert(blockLength > 2); // blockLength must include SID and sequenceCounter
+ client->send_buf[0] = kSID_TRANSFER_DATA;
+ client->send_buf[1] = blockSequenceCounter;
+
+ uint16_t size = fread(&client->send_buf[2], 1, blockLength - 2, fd);
+ UDS_DBG_PRINT("size: %d, blocklength: %d\n", size, blockLength);
+ client->send_size = UDS_0X36_REQ_BASE_LEN + size;
+ return _SendRequest(client);
+}
+
+/**
+ * @brief
+ *
+ * @param client
+ * @return UDSErr_t
+ * @addtogroup requestTransferExit_0x37
+ */
+UDSErr_t UDSSendRequestTransferExit(UDSClient_t *client) {
+ UDSErr_t err = PreRequestCheck(client);
+ if (err) {
+ return err;
+ }
+ client->send_buf[0] = kSID_REQUEST_TRANSFER_EXIT;
+ client->send_size = 1;
+ return _SendRequest(client);
+}
+
+/**
+ * @brief
+ *
+ * @param client
+ * @param dtcSettingType
+ * @param data
+ * @param size
+ * @return UDSErr_t
+ * @addtogroup controlDTCSetting_0x85
+ */
+UDSErr_t UDSCtrlDTCSetting(UDSClient_t *client, uint8_t dtcSettingType, uint8_t *data,
+ uint16_t size) {
+ UDSErr_t err = PreRequestCheck(client);
+ if (err) {
+ return err;
+ }
+ if (0x00 == dtcSettingType || 0x7F == dtcSettingType ||
+ (0x03 <= dtcSettingType && dtcSettingType <= 0x3F)) {
+ assert(0); // reserved vals
+ }
+ client->send_buf[0] = kSID_CONTROL_DTC_SETTING;
+ client->send_buf[1] = dtcSettingType;
+
+ if (NULL == data) {
+ assert(size == 0);
+ } else {
+ assert(size > 0);
+ if (size > client->send_buf_size - 2) {
+ return UDS_ERR_BUFSIZ;
+ }
+ memmove(&client->send_buf[2], data, size);
+ }
+ client->send_size = 2 + size;
+ return _SendRequest(client);
+}
+
+/**
+ * @brief
+ *
+ * @param client
+ * @param level
+ * @param data
+ * @param size
+ * @return UDSErr_t
+ * @addtogroup securityAccess_0x27
+ */
+UDSErr_t UDSSendSecurityAccess(UDSClient_t *client, uint8_t level, uint8_t *data, uint16_t size) {
+ UDSErr_t err = PreRequestCheck(client);
+ if (err) {
+ return err;
+ }
+ if (UDSSecurityAccessLevelIsReserved(level)) {
+ return UDS_ERR_INVALID_ARG;
+ }
+ client->send_buf[0] = kSID_SECURITY_ACCESS;
+ client->send_buf[1] = level;
+ if (size) {
+ assert(data);
+ if (size > client->send_buf_size - UDS_0X27_REQ_BASE_LEN) {
+ return UDS_ERR_BUFSIZ;
+ }
+ } else {
+ assert(NULL == data);
+ }
+
+ memmove(&client->send_buf[UDS_0X27_REQ_BASE_LEN], data, size);
+ client->send_size = UDS_0X27_REQ_BASE_LEN + size;
+ return _SendRequest(client);
+}
+
+typedef struct {
+ uint8_t dataFormatIdentifier;
+ uint8_t addressAndLengthFormatIdentifier;
+ size_t memoryAddress;
+ size_t memorySize;
+ FILE *fd;
+ uint8_t blockSequenceCounter;
+ uint16_t blockLength;
+} UDSClientDownloadSequence_t;
+
+static UDSSeqState_t requestDownload(UDSClient_t *client) {
+ UDSClientDownloadSequence_t *pL_Seq = (UDSClientDownloadSequence_t *)client->cbData;
+ UDSSendRequestDownload(client, pL_Seq->dataFormatIdentifier,
+ pL_Seq->addressAndLengthFormatIdentifier, pL_Seq->memoryAddress,
+ pL_Seq->memorySize);
+ return UDSSeqStateGotoNext;
+}
+
+static UDSSeqState_t checkRequestDownloadResponse(UDSClient_t *client) {
+ UDSClientDownloadSequence_t *pL_Seq = (UDSClientDownloadSequence_t *)client->cbData;
+ struct RequestDownloadResponse resp = {0};
+ UDSErr_t err = UDSUnpackRequestDownloadResponse(client, &resp);
+ if (err) {
+ client->err = err;
+ return UDSSeqStateDone;
+ }
+ pL_Seq->blockLength = resp.maxNumberOfBlockLength;
+ if (0 == resp.maxNumberOfBlockLength) {
+ client->err = UDS_ERR;
+ return UDSSeqStateDone;
+ }
+ return UDSSeqStateGotoNext;
+}
+
+static UDSSeqState_t prepareToTransfer(UDSClient_t *client) {
+ UDSClientDownloadSequence_t *pL_Seq = (UDSClientDownloadSequence_t *)client->cbData;
+ pL_Seq->blockSequenceCounter = 1;
+ return UDSSeqStateGotoNext;
+}
+
+static UDSSeqState_t transferData(UDSClient_t *client) {
+ UDSClientDownloadSequence_t *pL_Seq = (UDSClientDownloadSequence_t *)client->cbData;
+ if (kRequestStateIdle == client->state) {
+ if (ferror(pL_Seq->fd)) {
+ fclose(pL_Seq->fd);
+ client->err = UDS_ERR_FILE_IO; // 读取文件故障
+ return UDSSeqStateDone;
+ } else if (feof(pL_Seq->fd)) { // 传完了
+ return UDSSeqStateGotoNext;
+ } else {
+ UDSSendTransferDataStream(client, pL_Seq->blockSequenceCounter++, pL_Seq->blockLength,
+ pL_Seq->fd);
+ }
+ }
+ return UDSSeqStateRunning;
+}
+
+static UDSSeqState_t requestTransferExit(UDSClient_t *client) {
+ UDSSendRequestTransferExit(client);
+ return UDSSeqStateGotoNext;
+}
+
+UDSErr_t UDSConfigDownload(UDSClient_t *client, uint8_t dataFormatIdentifier,
+ uint8_t addressAndLengthFormatIdentifier, size_t memoryAddress,
+ size_t memorySize, FILE *fd) {
+
+ static const UDSClientCallback callbacks[] = {
+ requestDownload, UDSClientAwaitIdle, checkRequestDownloadResponse, prepareToTransfer,
+ transferData, requestTransferExit, UDSClientAwaitIdle, NULL};
+ static UDSClientDownloadSequence_t seq = {0};
+ memset(&seq, 0, sizeof(seq));
+ seq.blockSequenceCounter = 1;
+ seq.dataFormatIdentifier = dataFormatIdentifier;
+ seq.addressAndLengthFormatIdentifier = addressAndLengthFormatIdentifier;
+ seq.memoryAddress = memoryAddress;
+ seq.memorySize = memorySize;
+ seq.fd = fd;
+ client->cbList = callbacks;
+ client->cbIdx = 0;
+ client->cbData = &seq;
+ return UDS_OK;
+}
+
+/**
+ * @brief
+ *
+ * @param client
+ * @param resp
+ * @return UDSErr_t
+ * @addtogroup securityAccess_0x27
+ */
+UDSErr_t UDSUnpackSecurityAccessResponse(const UDSClient_t *client,
+ struct SecurityAccessResponse *resp) {
+ assert(client);
+ assert(resp);
+ if (UDS_RESPONSE_SID_OF(kSID_SECURITY_ACCESS) != client->recv_buf[0]) {
+ return UDS_ERR_SID_MISMATCH;
+ }
+ if (client->recv_size < UDS_0X27_RESP_BASE_LEN) {
+ return UDS_ERR_RESP_TOO_SHORT;
+ }
+ resp->securityAccessType = client->recv_buf[1];
+ resp->securitySeedLength = client->recv_size - UDS_0X27_RESP_BASE_LEN;
+ resp->securitySeed = resp->securitySeedLength == 0 ? NULL : &client->recv_buf[2];
+ return UDS_OK;
+}
+
+/**
+ * @brief
+ *
+ * @param client
+ * @param resp
+ * @return UDSErr_t
+ * @addtogroup routineControl_0x31
+ */
+UDSErr_t UDSUnpackRoutineControlResponse(const UDSClient_t *client,
+ struct RoutineControlResponse *resp) {
+ assert(client);
+ assert(resp);
+ if (UDS_RESPONSE_SID_OF(kSID_ROUTINE_CONTROL) != client->recv_buf[0]) {
+ return UDS_ERR_SID_MISMATCH;
+ }
+ if (client->recv_size < UDS_0X31_RESP_MIN_LEN) {
+ return UDS_ERR_RESP_TOO_SHORT;
+ }
+ resp->routineControlType = client->recv_buf[1];
+ resp->routineIdentifier = (client->recv_buf[2] << 8) + client->recv_buf[3];
+ resp->routineStatusRecordLength = client->recv_size - UDS_0X31_RESP_MIN_LEN;
+ resp->routineStatusRecord =
+ resp->routineStatusRecordLength == 0 ? NULL : &client->recv_buf[UDS_0X31_RESP_MIN_LEN];
+ return UDS_OK;
+}
+
+/**
+ * @brief
+ *
+ * @param client
+ * @param resp
+ * @return UDSErr_t
+ * @addtogroup requestDownload_0x34
+ */
+UDSErr_t UDSUnpackRequestDownloadResponse(const UDSClient_t *client,
+ struct RequestDownloadResponse *resp) {
+ assert(client);
+ assert(resp);
+ if (UDS_RESPONSE_SID_OF(kSID_REQUEST_DOWNLOAD) != client->recv_buf[0]) {
+ return UDS_ERR_SID_MISMATCH;
+ }
+ if (client->recv_size < UDS_0X34_RESP_BASE_LEN) {
+ return UDS_ERR_RESP_TOO_SHORT;
+ }
+ uint8_t maxNumberOfBlockLengthSize = (client->recv_buf[1] & 0xF0) >> 4;
+
+ if (sizeof(resp->maxNumberOfBlockLength) < maxNumberOfBlockLengthSize) {
+ UDS_DBG_PRINT("WARNING: sizeof(maxNumberOfBlockLength) > sizeof(size_t)");
+ return UDS_ERR;
+ }
+ resp->maxNumberOfBlockLength = 0;
+ for (int byteIdx = 0; byteIdx < maxNumberOfBlockLengthSize; byteIdx++) {
+ uint8_t byte = client->recv_buf[UDS_0X34_RESP_BASE_LEN + byteIdx];
+ uint8_t shiftBytes = maxNumberOfBlockLengthSize - 1 - byteIdx;
+ resp->maxNumberOfBlockLength |= byte << (8 * shiftBytes);
+ }
+ return UDS_OK;
+}
+
+bool UDSClientPoll(UDSClient_t *client) {
+ PollLowLevel(client);
+
+ if (client->err) {
+ return UDS_CLIENT_IDLE;
+ }
+
+ if (kRequestStateIdle != client->state) {
+ return UDS_CLIENT_RUNNING;
+ }
+
+ if (NULL == client->cbList) {
+ return UDS_CLIENT_IDLE;
+ }
+
+ UDSClientCallback activeCallback = client->cbList[client->cbIdx];
+
+ if (NULL == activeCallback) {
+ return UDS_CLIENT_IDLE;
+ }
+
+ UDSSeqState_t state = activeCallback(client);
+
+ switch (state) {
+ case UDSSeqStateDone:
+ return UDS_CLIENT_IDLE;
+ case UDSSeqStateRunning:
+ return UDS_CLIENT_RUNNING;
+ case UDSSeqStateGotoNext: {
+ client->cbIdx += 1;
+ return UDS_CLIENT_RUNNING;
+ }
+ default:
+ assert(0);
+ return UDS_CLIENT_IDLE;
+ }
+}
+
+void UDSClientPoll2(UDSClient_t *client,
+ int (*fn)(UDSClient_t *client, UDSEvent_t evt, void *ev_data, void *fn_data),
+ void *fn_data) {
+ UDSClientPoll(client);
+}
+
+UDSSeqState_t UDSClientAwaitIdle(UDSClient_t *client) {
+ if (client->err) {
+ return UDSSeqStateDone;
+ } else if (kRequestStateIdle == client->state) {
+ return UDSSeqStateGotoNext;
+ } else {
+ return UDSSeqStateRunning;
+ }
+}
+
+UDSErr_t UDSUnpackRDBIResponse(const uint8_t *buf, size_t buf_len, uint16_t did, uint8_t *data,
+ uint16_t data_size, uint16_t *offset) {
+ assert(buf);
+ assert(data);
+ assert(offset);
+ if (0 == *offset) {
+ *offset = UDS_0X22_RESP_BASE_LEN;
+ }
+
+ if (*offset + sizeof(did) > buf_len) {
+ return UDS_ERR_RESP_TOO_SHORT;
+ }
+
+ uint16_t theirDID = (buf[*offset] << 8) + buf[*offset + 1];
+ if (theirDID != did) {
+ return UDS_ERR_DID_MISMATCH;
+ }
+
+ if (*offset + sizeof(uint16_t) + data_size > buf_len) {
+ return UDS_ERR_RESP_TOO_SHORT;
+ }
+
+ memmove(data, buf + *offset + sizeof(uint16_t), data_size);
+
+ *offset += sizeof(uint16_t) + data_size;
+ return UDS_OK;
+}
+
+#ifdef UDS_LINES
+#line 1 "src/server.c"
+#endif
+
+
+
+
+
+static inline uint8_t NegativeResponse(UDSReq_t *r, uint8_t response_code) {
+ r->send_buf[0] = 0x7F;
+ r->send_buf[1] = r->recv_buf[0];
+ r->send_buf[2] = response_code;
+ r->send_len = UDS_NEG_RESP_LEN;
+ return response_code;
+}
+
+static inline void NoResponse(UDSReq_t *r) { r->send_len = 0; }
+
+static uint8_t EmitEvent(UDSServer_t *srv, UDSServerEvent_t evt, void *data) {
+ if (srv->fn) {
+ return srv->fn(srv, evt, data);
+ } else {
+ UDS_DBG_PRINT("Unhandled UDSServerEvent %d, srv.fn not installed!\n", evt);
+ return kGeneralReject;
+ }
+}
+
+static uint8_t _0x10_DiagnosticSessionControl(UDSServer_t *srv, UDSReq_t *r) {
+ if (r->recv_len < UDS_0X10_REQ_LEN) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
+ }
+
+ uint8_t sessType = r->recv_buf[1] & 0x4F;
+
+ UDSDiagSessCtrlArgs_t args = {
+ .type = sessType,
+ .p2_ms = UDS_CLIENT_DEFAULT_P2_MS,
+ .p2_star_ms = UDS_CLIENT_DEFAULT_P2_STAR_MS,
+ };
+
+ uint8_t err = EmitEvent(srv, UDS_SRV_EVT_DiagSessCtrl, &args);
+
+ if (kPositiveResponse != err) {
+ return NegativeResponse(r, err);
+ }
+
+ srv->sessionType = sessType;
+
+ switch (sessType) {
+ case kDefaultSession:
+ break;
+ case kProgrammingSession:
+ case kExtendedDiagnostic:
+ default:
+ srv->s3_session_timeout_timer = UDSMillis() + srv->s3_ms;
+ break;
+ }
+
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_DIAGNOSTIC_SESSION_CONTROL);
+ r->send_buf[1] = sessType;
+
+ // UDS-1-2013: Table 29
+ // resolution: 1ms
+ r->send_buf[2] = args.p2_ms >> 8;
+ r->send_buf[3] = args.p2_ms;
+
+ // resolution: 10ms
+ r->send_buf[4] = (args.p2_star_ms / 10) >> 8;
+ r->send_buf[5] = args.p2_star_ms / 10;
+
+ r->send_len = UDS_0X10_RESP_LEN;
+ return kPositiveResponse;
+}
+
+static uint8_t _0x11_ECUReset(UDSServer_t *srv, UDSReq_t *r) {
+ uint8_t resetType = r->recv_buf[1] & 0x3F;
+
+ if (r->recv_len < UDS_0X11_REQ_MIN_LEN) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
+ }
+
+ UDSECUResetArgs_t args = {
+ .type = resetType,
+ .powerDownTimeMillis = UDS_SERVER_DEFAULT_POWER_DOWN_TIME_MS,
+ };
+
+ uint8_t err = EmitEvent(srv, UDS_SRV_EVT_EcuReset, &args);
+
+ if (kPositiveResponse == err) {
+ srv->notReadyToReceive = true;
+ srv->ecuResetScheduled = resetType;
+ srv->ecuResetTimer = UDSMillis() + args.powerDownTimeMillis;
+ } else {
+ return NegativeResponse(r, err);
+ }
+
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_ECU_RESET);
+ r->send_buf[1] = resetType;
+
+ if (kEnableRapidPowerShutDown == resetType) {
+ uint32_t powerDownTime = args.powerDownTimeMillis / 1000;
+ if (powerDownTime > 255) {
+ powerDownTime = 255;
+ }
+ r->send_buf[2] = powerDownTime;
+ r->send_len = UDS_0X11_RESP_BASE_LEN + 1;
+ } else {
+ r->send_len = UDS_0X11_RESP_BASE_LEN;
+ }
+ return kPositiveResponse;
+}
+
+static uint8_t safe_copy(UDSServer_t *srv, const void *src, uint16_t count) {
+ if (srv == NULL) {
+ return kGeneralReject;
+ }
+ UDSReq_t *r = (UDSReq_t *)&srv->r;
+ if (count <= r->send_buf_size - r->send_len) {
+ memmove(r->send_buf + r->send_len, src, count);
+ r->send_len += count;
+ return kPositiveResponse;
+ }
+ return kResponseTooLong;
+}
+
+static uint8_t _0x22_ReadDataByIdentifier(UDSServer_t *srv, UDSReq_t *r) {
+ uint8_t numDIDs;
+ uint16_t dataId = 0;
+ uint8_t ret = kPositiveResponse;
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_READ_DATA_BY_IDENTIFIER);
+ r->send_len = 1;
+
+ if (0 != (r->recv_len - 1) % sizeof(uint16_t)) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
+ }
+
+ numDIDs = r->recv_len / sizeof(uint16_t);
+
+ if (0 == numDIDs) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
+ }
+
+ for (int did = 0; did < numDIDs; did++) {
+ uint16_t idx = 1 + did * 2;
+ dataId = (r->recv_buf[idx] << 8) + r->recv_buf[idx + 1];
+
+ if (r->send_len + 3 > r->send_buf_size) {
+ return NegativeResponse(r, kResponseTooLong);
+ }
+ uint8_t *copylocation = r->send_buf + r->send_len;
+ copylocation[0] = dataId >> 8;
+ copylocation[1] = dataId;
+ r->send_len += 2;
+
+ UDSRDBIArgs_t args = {
+ .dataId = dataId,
+ .copy = safe_copy,
+ };
+
+ ret = EmitEvent(srv, UDS_SRV_EVT_ReadDataByIdent, &args);
+
+ if (kPositiveResponse != ret) {
+ return NegativeResponse(r, ret);
+ }
+ }
+ return kPositiveResponse;
+}
+
+/**
+ * @brief decode the addressAndLengthFormatIdentifier that appears in ReadMemoryByAddress (0x23),
+ * DynamicallyDefineDataIdentifier (0x2C), RequestDownload (0X34)
+ *
+ * @param srv
+ * @param buf pointer to addressAndDataLengthFormatIdentifier in recv_buf
+ * @param memoryAddress the decoded memory address
+ * @param memorySize the decoded memory size
+ * @return uint8_t
+ */
+static uint8_t decodeAddressAndLength(UDSReq_t *r, uint8_t *const buf, void **memoryAddress,
+ size_t *memorySize) {
+ assert(r);
+ assert(memoryAddress);
+ assert(memorySize);
+ long long unsigned int tmp = 0;
+ *memoryAddress = 0;
+ *memorySize = 0;
+
+ assert(buf >= r->recv_buf && buf <= r->recv_buf + sizeof(r->recv_buf));
+
+ if (r->recv_len < 3) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
+ }
+
+ uint8_t memorySizeLength = (buf[0] & 0xF0) >> 4;
+ uint8_t memoryAddressLength = buf[0] & 0x0F;
+
+ if (memorySizeLength == 0 || memorySizeLength > sizeof(size_t)) {
+ return NegativeResponse(r, kRequestOutOfRange);
+ }
+
+ if (memoryAddressLength == 0 || memoryAddressLength > sizeof(size_t)) {
+ return NegativeResponse(r, kRequestOutOfRange);
+ }
+
+ if (buf + memorySizeLength + memoryAddressLength > r->recv_buf + r->recv_len) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
+ }
+
+ for (int byteIdx = 0; byteIdx < memoryAddressLength; byteIdx++) {
+ long long unsigned int byte = buf[1 + byteIdx];
+ uint8_t shiftBytes = memoryAddressLength - 1 - byteIdx;
+ tmp |= byte << (8 * shiftBytes);
+ }
+ *memoryAddress = (void *)tmp;
+
+ for (int byteIdx = 0; byteIdx < memorySizeLength; byteIdx++) {
+ uint8_t byte = buf[1 + memoryAddressLength + byteIdx];
+ uint8_t shiftBytes = memorySizeLength - 1 - byteIdx;
+ *memorySize |= (size_t)byte << (8 * shiftBytes);
+ }
+ return kPositiveResponse;
+}
+
+static uint8_t _0x23_ReadMemoryByAddress(UDSServer_t *srv, UDSReq_t *r) {
+ uint8_t ret = kPositiveResponse;
+ void *address = 0;
+ size_t length = 0;
+
+ if (r->recv_len < UDS_0X23_REQ_MIN_LEN) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
+ }
+
+ ret = decodeAddressAndLength(r, &r->recv_buf[1], &address, &length);
+ if (kPositiveResponse != ret) {
+ return NegativeResponse(r, ret);
+ }
+
+ UDSReadMemByAddrArgs_t args = {
+ .memAddr = address,
+ .memSize = length,
+ .copy = safe_copy,
+ };
+
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_READ_MEMORY_BY_ADDRESS);
+ r->send_len = UDS_0X23_RESP_BASE_LEN;
+ ret = EmitEvent(srv, UDS_SRV_EVT_ReadMemByAddr, &args);
+ if (kPositiveResponse != ret) {
+ return NegativeResponse(r, ret);
+ }
+ if (r->send_len != UDS_0X23_RESP_BASE_LEN + length) {
+ return kGeneralProgrammingFailure;
+ }
+ return kPositiveResponse;
+}
+
+static uint8_t _0x27_SecurityAccess(UDSServer_t *srv, UDSReq_t *r) {
+ uint8_t subFunction = r->recv_buf[1];
+ uint8_t response = kPositiveResponse;
+
+ if (UDSSecurityAccessLevelIsReserved(subFunction)) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
+ }
+
+ if (!UDSTimeAfter(UDSMillis(), UDS_SERVER_0x27_BRUTE_FORCE_MITIGATION_BOOT_DELAY_MS)) {
+ return NegativeResponse(r, kRequiredTimeDelayNotExpired);
+ }
+
+ if (!(UDSTimeAfter(UDSMillis(), srv->sec_access_auth_fail_timer))) {
+ return NegativeResponse(r, kExceedNumberOfAttempts);
+ }
+
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_SECURITY_ACCESS);
+ r->send_buf[1] = subFunction;
+ r->send_len = UDS_0X27_RESP_BASE_LEN;
+
+ // Even: sendKey
+ if (0 == subFunction % 2) {
+ uint8_t requestedLevel = subFunction - 1;
+ UDSSecAccessValidateKeyArgs_t args = {
+ .level = requestedLevel,
+ .key = &r->recv_buf[UDS_0X27_REQ_BASE_LEN],
+ .len = r->recv_len - UDS_0X27_REQ_BASE_LEN,
+ };
+
+ response = EmitEvent(srv, UDS_SRV_EVT_SecAccessValidateKey, &args);
+
+ if (kPositiveResponse != response) {
+ srv->sec_access_auth_fail_timer =
+ UDSMillis() + UDS_SERVER_0x27_BRUTE_FORCE_MITIGATION_AUTH_FAIL_DELAY_MS;
+ return NegativeResponse(r, response);
+ }
+
+ // "requestSeed = 0x01" identifies a fixed relationship between
+ // "requestSeed = 0x01" and "sendKey = 0x02"
+ // "requestSeed = 0x03" identifies a fixed relationship between
+ // "requestSeed = 0x03" and "sendKey = 0x04"
+ srv->securityLevel = requestedLevel;
+ r->send_len = UDS_0X27_RESP_BASE_LEN;
+ return kPositiveResponse;
+ }
+
+ // Odd: requestSeed
+ else {
+ /* If a server supports security, but the requested security level is already unlocked when
+ a SecurityAccess ‘requestSeed’ message is received, that server shall respond with a
+ SecurityAccess ‘requestSeed’ positive response message service with a seed value equal to
+ zero (0). The server shall never send an all zero seed for a given security level that is
+ currently locked. The client shall use this method to determine if a server is locked for a
+ particular security level by checking for a non-zero seed.
+ */
+ if (subFunction == srv->securityLevel) {
+ // Table 52 sends a response of length 2. Use a preprocessor define if this needs
+ // customizing by the user.
+ const uint8_t already_unlocked[] = {0x00, 0x00};
+ return safe_copy(srv, already_unlocked, sizeof(already_unlocked));
+ } else {
+ UDSSecAccessRequestSeedArgs_t args = {
+ .level = subFunction,
+ .dataRecord = &r->recv_buf[UDS_0X27_REQ_BASE_LEN],
+ .len = r->recv_len - UDS_0X27_REQ_BASE_LEN,
+ .copySeed = safe_copy,
+ };
+
+ response = EmitEvent(srv, UDS_SRV_EVT_SecAccessRequestSeed, &args);
+
+ if (kPositiveResponse != response) {
+ return NegativeResponse(r, response);
+ }
+
+ if (r->send_len <= UDS_0X27_RESP_BASE_LEN) { // no data was copied
+ return NegativeResponse(r, kGeneralProgrammingFailure);
+ }
+ return kPositiveResponse;
+ }
+ }
+ return NegativeResponse(r, kGeneralProgrammingFailure);
+}
+
+static uint8_t _0x28_CommunicationControl(UDSServer_t *srv, UDSReq_t *r) {
+ uint8_t controlType = r->recv_buf[1] & 0x7F;
+ uint8_t communicationType = r->recv_buf[2];
+
+ if (r->recv_len < UDS_0X28_REQ_BASE_LEN) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
+ }
+
+ UDSCommCtrlArgs_t args = {
+ .ctrlType = controlType,
+ .commType = communicationType,
+ };
+
+ uint8_t err = EmitEvent(srv, UDS_SRV_EVT_CommCtrl, &args);
+ if (kPositiveResponse != err) {
+ return NegativeResponse(r, err);
+ }
+
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_COMMUNICATION_CONTROL);
+ r->send_buf[1] = controlType;
+ r->send_len = UDS_0X28_RESP_LEN;
+ return kPositiveResponse;
+}
+
+static uint8_t _0x2E_WriteDataByIdentifier(UDSServer_t *srv, UDSReq_t *r) {
+ uint16_t dataLen = 0;
+ uint16_t dataId = 0;
+ uint8_t err = kPositiveResponse;
+
+ /* UDS-1 2013 Figure 21 Key 1 */
+ if (r->recv_len < UDS_0X2E_REQ_MIN_LEN) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
+ }
+
+ dataId = (r->recv_buf[1] << 8) + r->recv_buf[2];
+ dataLen = r->recv_len - UDS_0X2E_REQ_BASE_LEN;
+
+ UDSWDBIArgs_t args = {
+ .dataId = dataId,
+ .data = &r->recv_buf[UDS_0X2E_REQ_BASE_LEN],
+ .len = dataLen,
+ };
+
+ err = EmitEvent(srv, UDS_SRV_EVT_WriteDataByIdent, &args);
+ if (kPositiveResponse != err) {
+ return NegativeResponse(r, err);
+ }
+
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_WRITE_DATA_BY_IDENTIFIER);
+ r->send_buf[1] = dataId >> 8;
+ r->send_buf[2] = dataId;
+ r->send_len = UDS_0X2E_RESP_LEN;
+ return kPositiveResponse;
+}
+
+static uint8_t _0x31_RoutineControl(UDSServer_t *srv, UDSReq_t *r) {
+ uint8_t err = kPositiveResponse;
+ if (r->recv_len < UDS_0X31_REQ_MIN_LEN) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
+ }
+
+ uint8_t routineControlType = r->recv_buf[1] & 0x7F;
+ uint16_t routineIdentifier = (r->recv_buf[2] << 8) + r->recv_buf[3];
+
+ UDSRoutineCtrlArgs_t args = {
+ .ctrlType = routineControlType,
+ .id = routineIdentifier,
+ .optionRecord = &r->recv_buf[UDS_0X31_REQ_MIN_LEN],
+ .len = r->recv_len - UDS_0X31_REQ_MIN_LEN,
+ .copyStatusRecord = safe_copy,
+ };
+
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_ROUTINE_CONTROL);
+ r->send_buf[1] = routineControlType;
+ r->send_buf[2] = routineIdentifier >> 8;
+ r->send_buf[3] = routineIdentifier;
+ r->send_len = UDS_0X31_RESP_MIN_LEN;
+
+ switch (routineControlType) {
+ case kStartRoutine:
+ case kStopRoutine:
+ case kRequestRoutineResults:
+ err = EmitEvent(srv, UDS_SRV_EVT_RoutineCtrl, &args);
+ if (kPositiveResponse != err) {
+ return NegativeResponse(r, err);
+ }
+ break;
+ default:
+ return NegativeResponse(r, kRequestOutOfRange);
+ }
+ return kPositiveResponse;
+}
+
+static void ResetTransfer(UDSServer_t *srv) {
+ assert(srv);
+ srv->xferBlockSequenceCounter = 1;
+ srv->xferByteCounter = 0;
+ srv->xferTotalBytes = 0;
+ srv->xferIsActive = false;
+}
+
+static uint8_t _0x34_RequestDownload(UDSServer_t *srv, UDSReq_t *r) {
+ uint8_t err;
+ void *memoryAddress = 0;
+ size_t memorySize = 0;
+
+ if (srv->xferIsActive) {
+ return NegativeResponse(r, kConditionsNotCorrect);
+ }
+
+ if (r->recv_len < UDS_0X34_REQ_BASE_LEN) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
+ }
+
+ err = decodeAddressAndLength(r, &r->recv_buf[2], &memoryAddress, &memorySize);
+ if (kPositiveResponse != err) {
+ return NegativeResponse(r, err);
+ }
+
+ UDSRequestDownloadArgs_t args = {
+ .addr = memoryAddress,
+ .size = memorySize,
+ .dataFormatIdentifier = r->recv_buf[1],
+ .maxNumberOfBlockLength = UDS_SERVER_DEFAULT_XFER_DATA_MAX_BLOCKLENGTH,
+ };
+
+ err = EmitEvent(srv, UDS_SRV_EVT_RequestDownload, &args);
+
+ if (args.maxNumberOfBlockLength < 3) {
+ UDS_DBG_PRINT("ERROR: maxNumberOfBlockLength too short");
+ return NegativeResponse(r, kGeneralProgrammingFailure);
+ }
+
+ if (kPositiveResponse != err) {
+ return NegativeResponse(r, err);
+ }
+
+ ResetTransfer(srv);
+ srv->xferIsActive = true;
+ srv->xferTotalBytes = memorySize;
+ srv->xferBlockLength = args.maxNumberOfBlockLength;
+
+ // ISO-14229-1:2013 Table 401:
+ uint8_t lengthFormatIdentifier = sizeof(args.maxNumberOfBlockLength) << 4;
+
+ /* ISO-14229-1:2013 Table 396: maxNumberOfBlockLength
+ This parameter is used by the requestDownload positive response message to
+ inform the client how many data bytes (maxNumberOfBlockLength) to include in
+ each TransferData request message from the client. This length reflects the
+ complete message length, including the service identifier and the
+ data-parameters present in the TransferData request message.
+ */
+ if (args.maxNumberOfBlockLength > UDS_TP_MTU) {
+ args.maxNumberOfBlockLength = UDS_TP_MTU;
+ }
+
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_REQUEST_DOWNLOAD);
+ r->send_buf[1] = lengthFormatIdentifier;
+ for (uint8_t idx = 0; idx < sizeof(args.maxNumberOfBlockLength); idx++) {
+ uint8_t shiftBytes = sizeof(args.maxNumberOfBlockLength) - 1 - idx;
+ uint8_t byte = args.maxNumberOfBlockLength >> (shiftBytes * 8);
+ r->send_buf[UDS_0X34_RESP_BASE_LEN + idx] = byte;
+ }
+ r->send_len = UDS_0X34_RESP_BASE_LEN + sizeof(args.maxNumberOfBlockLength);
+ return kPositiveResponse;
+}
+
+static uint8_t _0x35_RequestUpload(UDSServer_t *srv, UDSReq_t *r) {
+ uint8_t err;
+ void *memoryAddress = 0;
+ size_t memorySize = 0;
+
+ if (srv->xferIsActive) {
+ return NegativeResponse(r, kConditionsNotCorrect);
+ }
+
+ if (r->recv_len < UDS_0X35_REQ_BASE_LEN) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
+ }
+
+ err = decodeAddressAndLength(r, &r->recv_buf[2], &memoryAddress, &memorySize);
+ if (kPositiveResponse != err) {
+ return NegativeResponse(r, err);
+ }
+
+ UDSRequestUploadArgs_t args = {
+ .addr = memoryAddress,
+ .size = memorySize,
+ .dataFormatIdentifier = r->recv_buf[1],
+ .maxNumberOfBlockLength = UDS_SERVER_DEFAULT_XFER_DATA_MAX_BLOCKLENGTH,
+ };
+
+ err = EmitEvent(srv, UDS_SRV_EVT_RequestUpload, &args);
+
+ if (args.maxNumberOfBlockLength < 3) {
+ UDS_DBG_PRINT("ERROR: maxNumberOfBlockLength too short");
+ return NegativeResponse(r, kGeneralProgrammingFailure);
+ }
+
+ if (kPositiveResponse != err) {
+ return NegativeResponse(r, err);
+ }
+
+ ResetTransfer(srv);
+ srv->xferIsActive = true;
+ srv->xferTotalBytes = memorySize;
+ srv->xferBlockLength = args.maxNumberOfBlockLength;
+
+ uint8_t lengthFormatIdentifier = sizeof(args.maxNumberOfBlockLength) << 4;
+
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_REQUEST_UPLOAD);
+ r->send_buf[1] = lengthFormatIdentifier;
+ for (uint8_t idx = 0; idx < sizeof(args.maxNumberOfBlockLength); idx++) {
+ uint8_t shiftBytes = sizeof(args.maxNumberOfBlockLength) - 1 - idx;
+ uint8_t byte = args.maxNumberOfBlockLength >> (shiftBytes * 8);
+ r->send_buf[UDS_0X35_RESP_BASE_LEN + idx] = byte;
+ }
+ r->send_len = UDS_0X35_RESP_BASE_LEN + sizeof(args.maxNumberOfBlockLength);
+ return kPositiveResponse;
+}
+
+static uint8_t _0x36_TransferData(UDSServer_t *srv, UDSReq_t *r) {
+ uint8_t err = kPositiveResponse;
+ uint16_t request_data_len = r->recv_len - UDS_0X36_REQ_BASE_LEN;
+ uint8_t blockSequenceCounter = 0;
+
+ if (!srv->xferIsActive) {
+ return NegativeResponse(r, kUploadDownloadNotAccepted);
+ }
+
+ if (r->recv_len < UDS_0X36_REQ_BASE_LEN) {
+ err = kIncorrectMessageLengthOrInvalidFormat;
+ goto fail;
+ }
+
+ blockSequenceCounter = r->recv_buf[1];
+
+ if (!srv->RCRRP) {
+ if (blockSequenceCounter != srv->xferBlockSequenceCounter) {
+ err = kRequestSequenceError;
+ goto fail;
+ } else {
+ srv->xferBlockSequenceCounter++;
+ }
+ }
+
+ if (srv->xferByteCounter + request_data_len > srv->xferTotalBytes) {
+ err = kTransferDataSuspended;
+ goto fail;
+ }
+
+ {
+ UDSTransferDataArgs_t args = {
+ .data = &r->recv_buf[UDS_0X36_REQ_BASE_LEN],
+ .len = r->recv_len - UDS_0X36_REQ_BASE_LEN,
+ .maxRespLen = srv->xferBlockLength - UDS_0X36_RESP_BASE_LEN,
+ .copyResponse = safe_copy,
+ };
+
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_TRANSFER_DATA);
+ r->send_buf[1] = blockSequenceCounter;
+ r->send_len = UDS_0X36_RESP_BASE_LEN;
+
+ err = EmitEvent(srv, UDS_SRV_EVT_TransferData, &args);
+
+ switch (err) {
+ case kPositiveResponse:
+ srv->xferByteCounter += request_data_len;
+ return kPositiveResponse;
+ case kRequestCorrectlyReceived_ResponsePending:
+ return NegativeResponse(r, kRequestCorrectlyReceived_ResponsePending);
+ default:
+ goto fail;
+ }
+ }
+
+fail:
+ ResetTransfer(srv);
+ return NegativeResponse(r, err);
+}
+
+static uint8_t _0x37_RequestTransferExit(UDSServer_t *srv, UDSReq_t *r) {
+ uint8_t err = kPositiveResponse;
+
+ if (!srv->xferIsActive) {
+ return NegativeResponse(r, kUploadDownloadNotAccepted);
+ }
+
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_REQUEST_TRANSFER_EXIT);
+ r->send_len = UDS_0X37_RESP_BASE_LEN;
+
+ UDSRequestTransferExitArgs_t args = {
+ .data = &r->recv_buf[UDS_0X37_REQ_BASE_LEN],
+ .len = r->recv_len - UDS_0X37_REQ_BASE_LEN,
+ .copyResponse = safe_copy,
+ };
+
+ err = EmitEvent(srv, UDS_SRV_EVT_RequestTransferExit, &args);
+
+ switch (err) {
+ case kPositiveResponse:
+ ResetTransfer(srv);
+ return kPositiveResponse;
+ case kRequestCorrectlyReceived_ResponsePending:
+ return NegativeResponse(r, kRequestCorrectlyReceived_ResponsePending);
+ default:
+ ResetTransfer(srv);
+ return NegativeResponse(r, err);
+ }
+}
+
+static uint8_t _0x3E_TesterPresent(UDSServer_t *srv, UDSReq_t *r) {
+ if ((r->recv_len < UDS_0X3E_REQ_MIN_LEN) || (r->recv_len > UDS_0X3E_REQ_MAX_LEN)) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
+ }
+ uint8_t zeroSubFunction = r->recv_buf[1];
+
+ switch (zeroSubFunction) {
+ case 0x00:
+ case 0x80:
+ srv->s3_session_timeout_timer = UDSMillis() + srv->s3_ms;
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_TESTER_PRESENT);
+ r->send_buf[1] = 0x00;
+ r->send_len = UDS_0X3E_RESP_LEN;
+ return kPositiveResponse;
+ default:
+ return NegativeResponse(r, kSubFunctionNotSupported);
+ }
+}
+
+static uint8_t _0x85_ControlDTCSetting(UDSServer_t *srv, UDSReq_t *r) {
+ if (r->recv_len < UDS_0X85_REQ_BASE_LEN) {
+ return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
+ }
+ uint8_t dtcSettingType = r->recv_buf[1] & 0x3F;
+
+ r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_CONTROL_DTC_SETTING);
+ r->send_buf[1] = dtcSettingType;
+ r->send_len = UDS_0X85_RESP_LEN;
+ return kPositiveResponse;
+}
+
+typedef uint8_t (*UDSService)(UDSServer_t *srv, UDSReq_t *r);
+
+/**
+ * @brief Get the internal service handler matching the given SID.
+ * @param sid
+ * @return pointer to UDSService or NULL if no match
+ */
+static UDSService getServiceForSID(uint8_t sid) {
+ switch (sid) {
+ case kSID_DIAGNOSTIC_SESSION_CONTROL:
+ return _0x10_DiagnosticSessionControl;
+ case kSID_ECU_RESET:
+ return _0x11_ECUReset;
+ case kSID_CLEAR_DIAGNOSTIC_INFORMATION:
+ return NULL;
+ case kSID_READ_DTC_INFORMATION:
+ return NULL;
+ case kSID_READ_DATA_BY_IDENTIFIER:
+ return _0x22_ReadDataByIdentifier;
+ case kSID_READ_MEMORY_BY_ADDRESS:
+ return _0x23_ReadMemoryByAddress;
+ case kSID_READ_SCALING_DATA_BY_IDENTIFIER:
+ return NULL;
+ case kSID_SECURITY_ACCESS:
+ return _0x27_SecurityAccess;
+ case kSID_COMMUNICATION_CONTROL:
+ return _0x28_CommunicationControl;
+ case kSID_READ_PERIODIC_DATA_BY_IDENTIFIER:
+ return NULL;
+ case kSID_DYNAMICALLY_DEFINE_DATA_IDENTIFIER:
+ return NULL;
+ case kSID_WRITE_DATA_BY_IDENTIFIER:
+ return _0x2E_WriteDataByIdentifier;
+ case kSID_INPUT_CONTROL_BY_IDENTIFIER:
+ return NULL;
+ case kSID_ROUTINE_CONTROL:
+ return _0x31_RoutineControl;
+ case kSID_REQUEST_DOWNLOAD:
+ return _0x34_RequestDownload;
+ case kSID_REQUEST_UPLOAD:
+ return _0x35_RequestUpload;
+ case kSID_TRANSFER_DATA:
+ return _0x36_TransferData;
+ case kSID_REQUEST_TRANSFER_EXIT:
+ return _0x37_RequestTransferExit;
+ case kSID_REQUEST_FILE_TRANSFER:
+ return NULL;
+ case kSID_WRITE_MEMORY_BY_ADDRESS:
+ return NULL;
+ case kSID_TESTER_PRESENT:
+ return _0x3E_TesterPresent;
+ case kSID_ACCESS_TIMING_PARAMETER:
+ return NULL;
+ case kSID_SECURED_DATA_TRANSMISSION:
+ return NULL;
+ case kSID_CONTROL_DTC_SETTING:
+ return _0x85_ControlDTCSetting;
+ case kSID_RESPONSE_ON_EVENT:
+ return NULL;
+ default:
+ UDS_DBG_PRINT("no handler for request SID %x.\n", sid);
+ return NULL;
+ }
+}
+
+/**
+ * @brief Call the service if it exists, modifying the response if the spec calls for it.
+ * @note see UDS-1 2013 7.5.5 Pseudo code example of server response behavior
+ *
+ * @param srv
+ * @param addressingScheme
+ */
+static uint8_t evaluateServiceResponse(UDSServer_t *srv, UDSReq_t *r) {
+ uint8_t response = kPositiveResponse;
+ bool suppressResponse = false;
+ uint8_t sid = r->recv_buf[0];
+ UDSService service = getServiceForSID(sid);
+
+ if (NULL == service || NULL == srv->fn) {
+ return NegativeResponse(r, kServiceNotSupported);
+ }
+ assert(service);
+ assert(srv->fn); // service handler functions will call srv->fn. it must be valid
+
+ switch (sid) {
+ /* CASE Service_with_sub-function */
+ /* test if service with sub-function is supported */
+ case kSID_DIAGNOSTIC_SESSION_CONTROL:
+ case kSID_ECU_RESET:
+ case kSID_SECURITY_ACCESS:
+ case kSID_COMMUNICATION_CONTROL:
+ case kSID_ROUTINE_CONTROL:
+ case kSID_TESTER_PRESENT:
+ case kSID_CONTROL_DTC_SETTING: {
+ response = service(srv, r);
+
+ bool suppressPosRspMsgIndicationBit = r->recv_buf[1] & 0x80;
+
+ /* test if positive response is required and if responseCode is positive 0x00 */
+ if ((suppressPosRspMsgIndicationBit) && (response == kPositiveResponse) &&
+ (
+ // TODO: *not yet a NRC 0x78 response sent*
+ true)) {
+ suppressResponse = true;
+ } else {
+ suppressResponse = false;
+ }
+ break;
+ }
+
+ /* CASE Service_without_sub-function */
+ /* test if service without sub-function is supported */
+ case kSID_READ_DATA_BY_IDENTIFIER:
+ case kSID_READ_MEMORY_BY_ADDRESS:
+ case kSID_WRITE_DATA_BY_IDENTIFIER:
+ case kSID_REQUEST_DOWNLOAD:
+ case kSID_REQUEST_UPLOAD:
+ case kSID_TRANSFER_DATA:
+ case kSID_REQUEST_TRANSFER_EXIT: {
+ response = service(srv, r);
+ break;
+ }
+
+ /* CASE Service_not_implemented */
+ /* shouldn't get this far as getServiceForSID(sid) will return NULL*/
+ case kSID_CLEAR_DIAGNOSTIC_INFORMATION:
+ case kSID_READ_DTC_INFORMATION:
+ case kSID_READ_SCALING_DATA_BY_IDENTIFIER:
+ case kSID_READ_PERIODIC_DATA_BY_IDENTIFIER:
+ case kSID_DYNAMICALLY_DEFINE_DATA_IDENTIFIER:
+ case kSID_INPUT_CONTROL_BY_IDENTIFIER:
+ case kSID_REQUEST_FILE_TRANSFER:
+ case kSID_WRITE_MEMORY_BY_ADDRESS:
+ case kSID_ACCESS_TIMING_PARAMETER:
+ case kSID_SECURED_DATA_TRANSMISSION:
+ case kSID_RESPONSE_ON_EVENT:
+ default: {
+ response = kServiceNotSupported;
+ break;
+ }
+ }
+
+ if ((UDS_A_TA_TYPE_FUNCTIONAL == r->info.A_TA_Type) &&
+ ((kServiceNotSupported == response) || (kSubFunctionNotSupported == response) ||
+ (kServiceNotSupportedInActiveSession == response) ||
+ (kSubFunctionNotSupportedInActiveSession == response) ||
+ (kRequestOutOfRange == response)) &&
+ (
+ // TODO: *not yet a NRC 0x78 response sent*
+ true)) {
+ suppressResponse = true; /* Suppress negative response message */
+ NoResponse(r);
+ } else {
+ if (suppressResponse) { /* Suppress positive response message */
+ NoResponse(r);
+ } else { /* send negative or positive response */
+ ;
+ }
+ }
+ return response;
+}
+
+// ========================================================================
+// Public Functions
+// ========================================================================
+
+/**
+ * @brief \~chinese 初始化服务器 \~english Initialize the server
+ *
+ * @param srv
+ * @param cfg
+ * @return int
+ */
+UDSErr_t UDSServerInit(UDSServer_t *srv) {
+ assert(srv);
+ memset(srv, 0, sizeof(UDSServer_t));
+ srv->p2_ms = UDS_SERVER_DEFAULT_P2_MS;
+ srv->p2_star_ms = UDS_SERVER_DEFAULT_P2_STAR_MS;
+ srv->s3_ms = UDS_SERVER_DEFAULT_S3_MS;
+ srv->sessionType = kDefaultSession;
+ srv->p2_timer = UDSMillis() + srv->p2_ms;
+ srv->s3_session_timeout_timer = UDSMillis() + srv->s3_ms;
+ return UDS_OK;
+}
+
+void UDSServerPoll(UDSServer_t *srv) {
+ // UDS-1-2013 Figure 38: Session Timeout (S3)
+ if (kDefaultSession != srv->sessionType &&
+ UDSTimeAfter(UDSMillis(), srv->s3_session_timeout_timer)) {
+ EmitEvent(srv, UDS_SRV_EVT_SessionTimeout, NULL);
+ }
+
+ if (srv->ecuResetScheduled && UDSTimeAfter(UDSMillis(), srv->ecuResetTimer)) {
+ EmitEvent(srv, UDS_SRV_EVT_DoScheduledReset, &srv->ecuResetScheduled);
+ }
+
+ UDSTpPoll(srv->tp);
+
+ UDSReq_t *r = &srv->r;
+
+ if (srv->requestInProgress) {
+ if (srv->RCRRP) {
+ // responds only if
+ // 1. changed (no longer RCRRP), or
+ // 2. p2_timer has elapsed
+ uint8_t response = evaluateServiceResponse(srv, r);
+ if (kRequestCorrectlyReceived_ResponsePending == response) {
+ // it's the second time the service has responded with RCRRP
+ srv->notReadyToReceive = true;
+ } else {
+ // No longer RCRRP'ing
+ srv->RCRRP = false;
+ srv->notReadyToReceive = false;
+
+ // Not a consecutive 0x78 response, use p2 instead of p2_star * 0.3
+ srv->p2_timer = UDSMillis() + srv->p2_ms;
+ }
+ }
+
+ if (UDSTimeAfter(UDSMillis(), srv->p2_timer)) {
+ printf("len: %zu\n", r->send_len);
+ ssize_t ret = UDSTpSend(srv->tp, r->send_buf, r->send_len, NULL);
+ // TODO test injection of transport errors:
+ if (ret < 0) {
+ UDSErr_t err = UDS_ERR_TPORT;
+ EmitEvent(srv, UDS_SRV_EVT_Err, &err);
+ UDS_DBG_PRINT("UDSTpSend failed with %zd\n", ret);
+ }
+
+ if (srv->RCRRP) {
+ // ISO14229-2:2013 Table 4 footnote b
+ // min time between consecutive 0x78 responses is 0.3 * p2*
+ uint32_t wait_time = srv->p2_star_ms * 3 / 10;
+ srv->p2_timer = UDSMillis() + wait_time;
+ } else {
+ srv->p2_timer = UDSMillis() + srv->p2_ms;
+ UDSTpAckRecv(srv->tp);
+ srv->requestInProgress = false;
+ }
+ }
+
+ } else {
+ if (srv->notReadyToReceive) {
+ return; // cannot respond to request right now
+ }
+ r->recv_len = UDSTpPeek(srv->tp, &r->recv_buf, &r->info);
+ r->send_buf_size = UDSTpGetSendBuf(srv->tp, &r->send_buf);
+ if (r->recv_len > 0) {
+ if (r->send_buf == NULL) {
+ UDS_DBG_PRINT("Send buf null\n");
+ }
+ if (r->recv_buf == NULL) {
+ UDS_DBG_PRINT("Recv buf null\n");
+ }
+ if (r->send_buf == NULL || r->recv_buf == NULL) {
+ UDSErr_t err = UDS_ERR_TPORT;
+ EmitEvent(srv, UDS_SRV_EVT_Err, &err);
+ UDS_DBG_PRINT("bad tport\n");
+ return;
+ }
+ uint8_t response = evaluateServiceResponse(srv, r);
+ srv->requestInProgress = true;
+ if (kRequestCorrectlyReceived_ResponsePending == response) {
+ srv->RCRRP = true;
+ }
+ }
+ }
+}
+#ifdef UDS_LINES
+#line 1 "src/tp.c"
+#endif
+
+
+/**
+ * @brief
+ *
+ * @param hdl
+ * @param info, if NULL, the default values are used:
+ * A_Mtype: message type (diagnostic (DEFAULT), remote diagnostic, secure diagnostic, secure
+ * remote diagnostic)
+ * A_TA_Type: application target address type (physical (DEFAULT) or functional)
+ * A_SA: unused
+ * A_TA: unused
+ * A_AE: unused
+ * @return ssize_t
+ */
+ssize_t UDSTpGetSendBuf(struct UDSTpHandle *hdl, uint8_t **buf) {
+ assert(hdl);
+ assert(hdl->get_send_buf);
+ return hdl->get_send_buf(hdl, buf);
+}
+ssize_t UDSTpSend(struct UDSTpHandle *hdl, const uint8_t *buf, ssize_t len, UDSSDU_t *info) {
+ assert(hdl);
+ assert(hdl->send);
+ return hdl->send(hdl, (uint8_t *)buf, len, info);
+}
+
+UDSTpStatus_t UDSTpPoll(struct UDSTpHandle *hdl) {
+ assert(hdl);
+ assert(hdl->poll);
+ return hdl->poll(hdl);
+}
+
+ssize_t UDSTpPeek(struct UDSTpHandle *hdl, uint8_t **buf, UDSSDU_t *info) {
+ assert(hdl);
+ assert(hdl->peek);
+ return hdl->peek(hdl, buf, info);
+}
+
+const uint8_t *UDSTpGetRecvBuf(struct UDSTpHandle *hdl, size_t *p_len) {
+ assert(hdl);
+ ssize_t len = 0;
+ uint8_t *buf = NULL;
+ len = UDSTpPeek(hdl, &buf, NULL);
+ if (len > 0) {
+ if (p_len) {
+ *p_len = len;
+ }
+ return buf;
+ } else {
+ return NULL;
+ }
+}
+
+size_t UDSTpGetRecvLen(UDSTpHandle_t *hdl) {
+ assert(hdl);
+ size_t len = 0;
+ UDSTpGetRecvBuf(hdl, &len);
+ return len;
+}
+
+void UDSTpAckRecv(UDSTpHandle_t *hdl) {
+ assert(hdl);
+ hdl->ack_recv(hdl);
+}
+
+#ifdef UDS_LINES
+#line 1 "src/tp/isotp_c.c"
+#endif
+#if defined(UDS_TP_ISOTP_C)
+
+
+
+
+
+static UDSTpStatus_t tp_poll(UDSTpHandle_t *hdl) {
+ assert(hdl);
+ UDSTpStatus_t status = 0;
+ UDSISOTpC_t *impl = (UDSISOTpC_t *)hdl;
+ isotp_poll(&impl->phys_link);
+ if (impl->phys_link.send_status == ISOTP_SEND_STATUS_INPROGRESS) {
+ status |= UDS_TP_SEND_IN_PROGRESS;
+ }
+ return status;
+}
+
+int peek_link(IsoTpLink *link, uint8_t *buf, size_t bufsize, bool functional) {
+ assert(link);
+ assert(buf);
+ int ret = -1;
+ switch (link->receive_status) {
+ case ISOTP_RECEIVE_STATUS_IDLE:
+ ret = 0;
+ goto done;
+ case ISOTP_RECEIVE_STATUS_INPROGRESS:
+ ret = 0;
+ goto done;
+ case ISOTP_RECEIVE_STATUS_FULL:
+ ret = link->receive_size;
+ printf("The link is full. Copying %d bytes\n", ret);
+ memmove(buf, link->receive_buffer, link->receive_size);
+ break;
+ default:
+ UDS_DBG_PRINT("receive_status %d not implemented\n", link->receive_status);
+ ret = -1;
+ goto done;
+ }
+done:
+ return ret;
+}
+
+static ssize_t tp_peek(UDSTpHandle_t *hdl, uint8_t **p_buf, UDSSDU_t *info) {
+ assert(hdl);
+ assert(p_buf);
+ UDSISOTpC_t *tp = (UDSISOTpC_t *)hdl;
+ if (ISOTP_RECEIVE_STATUS_FULL == tp->phys_link.receive_status) { // recv not yet acked
+ *p_buf = tp->recv_buf;
+ return tp->phys_link.receive_size;
+ }
+ int ret = -1;
+ ret = peek_link(&tp->phys_link, tp->recv_buf, sizeof(tp->recv_buf), false);
+ UDS_A_TA_Type_t ta_type = UDS_A_TA_TYPE_PHYSICAL;
+ uint32_t ta = tp->phys_ta;
+ uint32_t sa = tp->phys_sa;
+
+ if (ret > 0) {
+ printf("just got %d bytes\n", ret);
+ ta = tp->phys_sa;
+ sa = tp->phys_ta;
+ ta_type = UDS_A_TA_TYPE_PHYSICAL;
+ *p_buf = tp->recv_buf;
+ goto done;
+ } else if (ret < 0) {
+ goto done;
+ } else {
+ ret = peek_link(&tp->func_link, tp->recv_buf, sizeof(tp->recv_buf), true);
+ if (ret > 0) {
+ printf("just got %d bytes on func link \n", ret);
+ ta = tp->func_sa;
+ sa = tp->func_ta;
+ ta_type = UDS_A_TA_TYPE_FUNCTIONAL;
+ *p_buf = tp->recv_buf;
+ goto done;
+ } else if (ret < 0) {
+ goto done;
+ }
+ }
+done:
+ if (ret > 0) {
+ if (info) {
+ info->A_TA = ta;
+ info->A_SA = sa;
+ info->A_TA_Type = ta_type;
+ }
+ }
+ return ret;
+}
+
+static ssize_t tp_send(UDSTpHandle_t *hdl, uint8_t *buf, size_t len, UDSSDU_t *info) {
+ assert(hdl);
+ ssize_t ret = -1;
+ UDSISOTpC_t *tp = (UDSISOTpC_t *)hdl;
+ IsoTpLink *link = NULL;
+ const UDSTpAddr_t ta_type = info ? info->A_TA_Type : UDS_A_TA_TYPE_PHYSICAL;
+ const uint32_t ta = ta_type == UDS_A_TA_TYPE_PHYSICAL ? tp->phys_ta : tp->func_ta;
+ switch (ta_type) {
+ case UDS_A_TA_TYPE_PHYSICAL:
+ link = &tp->phys_link;
+ break;
+ case UDS_A_TA_TYPE_FUNCTIONAL:
+ link = &tp->func_link;
+ if (len > 7) {
+ UDS_DBG_PRINT("Cannot send more than 7 bytes via functional addressing\n");
+ ret = -3;
+ goto done;
+ }
+ break;
+ default:
+ ret = -4;
+ goto done;
+ }
+
+ int send_status = isotp_send(link, buf, len);
+ switch (send_status) {
+ case ISOTP_RET_OK:
+ ret = len;
+ goto done;
+ case ISOTP_RET_INPROGRESS:
+ case ISOTP_RET_OVERFLOW:
+ default:
+ ret = send_status;
+ goto done;
+ }
+done:
+ return ret;
+}
+
+static void tp_ack_recv(UDSTpHandle_t *hdl) {
+ assert(hdl);
+ printf("ack recv\n");
+ UDSISOTpC_t *tp = (UDSISOTpC_t *)hdl;
+ uint16_t out_size = 0;
+ isotp_receive(&tp->phys_link, tp->recv_buf, sizeof(tp->recv_buf), &out_size);
+}
+
+static ssize_t tp_get_send_buf(UDSTpHandle_t *hdl, uint8_t **p_buf) {
+ assert(hdl);
+ UDSISOTpC_t *tp = (UDSISOTpC_t *)hdl;
+ *p_buf = tp->send_buf;
+ return sizeof(tp->send_buf);
+}
+
+UDSErr_t UDSISOTpCInit(UDSISOTpC_t *tp, const UDSISOTpCConfig_t *cfg) {
+ if (cfg == NULL || tp == NULL) {
+ return UDS_ERR;
+ }
+ tp->hdl.poll = tp_poll;
+ tp->hdl.send = tp_send;
+ tp->hdl.peek = tp_peek;
+ tp->hdl.ack_recv = tp_ack_recv;
+ tp->hdl.get_send_buf = tp_get_send_buf;
+ tp->phys_sa = cfg->source_addr;
+ tp->phys_ta = cfg->target_addr;
+ tp->func_sa = cfg->source_addr_func;
+ tp->func_ta = cfg->target_addr;
+
+ isotp_init_link(&tp->phys_link, tp->phys_ta, tp->send_buf, sizeof(tp->send_buf), tp->recv_buf,
+ sizeof(tp->recv_buf), UDSMillis, cfg->isotp_user_send_can,
+ cfg->isotp_user_debug, cfg->user_data);
+ isotp_init_link(&tp->func_link, tp->func_ta, tp->recv_buf, sizeof(tp->send_buf), tp->recv_buf,
+ sizeof(tp->recv_buf), UDSMillis, cfg->isotp_user_send_can,
+ cfg->isotp_user_debug, cfg->user_data);
+ return UDS_OK;
+}
+
+#endif
+
+#ifdef UDS_LINES
+#line 1 "src/tp/isotp_c_socketcan.c"
+#endif
+#if defined(UDS_TP_ISOTP_C_SOCKETCAN)
+
+
+
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+static int SetupSocketCAN(const char *ifname) {
+ UDS_DBG_PRINT("setting up CAN\n");
+ struct sockaddr_can addr;
+ struct ifreq ifr;
+ int sockfd = -1;
+
+ if ((sockfd = socket(PF_CAN, SOCK_RAW | SOCK_NONBLOCK, CAN_RAW)) < 0) {
+ perror("socket");
+ goto done;
+ }
+
+ strcpy(ifr.ifr_name, ifname);
+ ioctl(sockfd, SIOCGIFINDEX, &ifr);
+ memset(&addr, 0, sizeof(addr));
+ addr.can_family = AF_CAN;
+ addr.can_ifindex = ifr.ifr_ifindex;
+ if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ perror("bind");
+ }
+
+done:
+ return sockfd;
+}
+
+uint32_t isotp_user_get_ms() { return UDSMillis(); }
+
+void isotp_user_debug(const char *message, ...) {
+ va_list args;
+ va_start(args, message);
+ vprintf(message, args);
+ va_end(args);
+}
+
+int isotp_user_send_can(const uint32_t arbitration_id, const uint8_t *data, const uint8_t size,
+ void *user_data) {
+ assert(user_data);
+ int sockfd = *(int *)user_data;
+ struct can_frame frame = {0};
+ frame.can_id = arbitration_id;
+ frame.can_dlc = size;
+ memmove(frame.data, data, size);
+ if (write(sockfd, &frame, sizeof(struct can_frame)) != sizeof(struct can_frame)) {
+ perror("Write err");
+ return ISOTP_RET_ERROR;
+ }
+ return ISOTP_RET_OK;
+}
+
+static void printhex(const uint8_t *addr, int len) {
+ for (int i = 0; i < len; i++) {
+ printf("%02x,", addr[i]);
+ }
+ printf("\n");
+}
+
+static void SocketCANRecv(UDSTpISOTpC_t *tp) {
+ assert(tp);
+ struct can_frame frame = {0};
+ int nbytes = 0;
+
+ for (;;) {
+ nbytes = read(tp->fd, &frame, sizeof(struct can_frame));
+ if (nbytes < 0) {
+ if (EAGAIN == errno || EWOULDBLOCK == errno) {
+ break;
+ } else {
+ perror("read");
+ }
+ } else if (nbytes == 0) {
+ break;
+ } else {
+ if (frame.can_id == tp->phys_sa) {
+ UDS_DBG_PRINT("phys recvd can\n");
+ UDS_DBG_PRINTHEX(frame.data, frame.can_dlc);
+ isotp_on_can_message(&tp->phys_link, frame.data, frame.can_dlc);
+ } else if (frame.can_id == tp->func_sa) {
+ if (ISOTP_RECEIVE_STATUS_IDLE != tp->phys_link.receive_status) {
+ UDS_DBG_PRINT(
+ "func frame received but cannot process because link is not idle");
+ return;
+ }
+ // TODO: reject if it's longer than a single frame
+ isotp_on_can_message(&tp->func_link, frame.data, frame.can_dlc);
+ }
+ }
+ }
+}
+
+static UDSTpStatus_t isotp_c_socketcan_tp_poll(UDSTpHandle_t *hdl) {
+ assert(hdl);
+ UDSTpStatus_t status = 0;
+ UDSTpISOTpC_t *impl = (UDSTpISOTpC_t *)hdl;
+ SocketCANRecv(impl);
+ isotp_poll(&impl->phys_link);
+ if (impl->phys_link.send_status == ISOTP_SEND_STATUS_INPROGRESS) {
+ status |= UDS_TP_SEND_IN_PROGRESS;
+ }
+ return status;
+}
+
+static int isotp_c_socketcan_tp_peek_link(IsoTpLink *link, uint8_t *buf, size_t bufsize,
+ bool functional) {
+ assert(link);
+ assert(buf);
+ int ret = -1;
+ switch (link->receive_status) {
+ case ISOTP_RECEIVE_STATUS_IDLE:
+ ret = 0;
+ goto done;
+ case ISOTP_RECEIVE_STATUS_INPROGRESS:
+ ret = 0;
+ goto done;
+ case ISOTP_RECEIVE_STATUS_FULL:
+ ret = link->receive_size;
+ printf("The link is full. Copying %d bytes\n", ret);
+ memmove(buf, link->receive_buffer, link->receive_size);
+ break;
+ default:
+ UDS_DBG_PRINT("receive_status %d not implemented\n", link->receive_status);
+ ret = -1;
+ goto done;
+ }
+done:
+ return ret;
+}
+
+static ssize_t isotp_c_socketcan_tp_peek(UDSTpHandle_t *hdl, uint8_t **p_buf, UDSSDU_t *info) {
+ assert(hdl);
+ assert(p_buf);
+ UDSTpISOTpC_t *tp = (UDSTpISOTpC_t *)hdl;
+ if (ISOTP_RECEIVE_STATUS_FULL == tp->phys_link.receive_status) { // recv not yet acked
+ *p_buf = tp->recv_buf;
+ return tp->phys_link.receive_size;
+ }
+ int ret = -1;
+ ret = isotp_c_socketcan_tp_peek_link(&tp->phys_link, tp->recv_buf, sizeof(tp->recv_buf), false);
+ UDS_A_TA_Type_t ta_type = UDS_A_TA_TYPE_PHYSICAL;
+ uint32_t ta = tp->phys_ta;
+ uint32_t sa = tp->phys_sa;
+
+ if (ret > 0) {
+ printf("just got %d bytes\n", ret);
+ ta = tp->phys_sa;
+ sa = tp->phys_ta;
+ ta_type = UDS_A_TA_TYPE_PHYSICAL;
+ *p_buf = tp->recv_buf;
+ goto done;
+ } else if (ret < 0) {
+ goto done;
+ } else {
+ ret = isotp_c_socketcan_tp_peek_link(&tp->func_link, tp->recv_buf, sizeof(tp->recv_buf),
+ true);
+ if (ret > 0) {
+ printf("just got %d bytes on func link \n", ret);
+ ta = tp->func_sa;
+ sa = tp->func_ta;
+ ta_type = UDS_A_TA_TYPE_FUNCTIONAL;
+ *p_buf = tp->recv_buf;
+ goto done;
+ } else if (ret < 0) {
+ goto done;
+ }
+ }
+done:
+ if (ret > 0) {
+ if (info) {
+ info->A_TA = ta;
+ info->A_SA = sa;
+ info->A_TA_Type = ta_type;
+ }
+ fprintf(stdout, "%06d, %s recv, 0x%03x (%s), ", UDSMillis(), tp->tag, ta,
+ ta_type == UDS_A_TA_TYPE_PHYSICAL ? "phys" : "func");
+ for (unsigned i = 0; i < ret; i++) {
+ fprintf(stdout, "%02x ", (*p_buf)[i]);
+ }
+ fprintf(stdout, "\n");
+ fflush(stdout); // flush every time in case of crash
+ }
+ return ret;
+}
+
+static ssize_t isotp_c_socketcan_tp_send(UDSTpHandle_t *hdl, uint8_t *buf, size_t len,
+ UDSSDU_t *info) {
+ assert(hdl);
+ ssize_t ret = -1;
+ UDSTpISOTpC_t *tp = (UDSTpISOTpC_t *)hdl;
+ IsoTpLink *link = NULL;
+ const UDSTpAddr_t ta_type = info ? info->A_TA_Type : UDS_A_TA_TYPE_PHYSICAL;
+ const uint32_t ta = ta_type == UDS_A_TA_TYPE_PHYSICAL ? tp->phys_ta : tp->func_ta;
+ switch (ta_type) {
+ case UDS_A_TA_TYPE_PHYSICAL:
+ link = &tp->phys_link;
+ break;
+ case UDS_A_TA_TYPE_FUNCTIONAL:
+ link = &tp->func_link;
+ if (len > 7) {
+ UDS_DBG_PRINT("Cannot send more than 7 bytes via functional addressing\n");
+ ret = -3;
+ goto done;
+ }
+ break;
+ default:
+ ret = -4;
+ goto done;
+ }
+
+ int send_status = isotp_send(link, buf, len);
+ switch (send_status) {
+ case ISOTP_RET_OK:
+ ret = len;
+ goto done;
+ case ISOTP_RET_INPROGRESS:
+ case ISOTP_RET_OVERFLOW:
+ default:
+ ret = send_status;
+ goto done;
+ }
+done:
+ fprintf(stdout, "%06d, %s sends, 0x%03x (%s), ", UDSMillis(), tp->tag, ta,
+ ta_type == UDS_A_TA_TYPE_PHYSICAL ? "phys" : "func");
+ for (unsigned i = 0; i < len; i++) {
+ fprintf(stdout, "%02x ", buf[i]);
+ }
+ fprintf(stdout, "\n");
+ fflush(stdout); // flush every time in case of crash
+
+ return ret;
+}
+
+static void isotp_c_socketcan_tp_ack_recv(UDSTpHandle_t *hdl) {
+ assert(hdl);
+ printf("ack recv\n");
+ UDSTpISOTpC_t *tp = (UDSTpISOTpC_t *)hdl;
+ uint16_t out_size = 0;
+ isotp_receive(&tp->phys_link, tp->recv_buf, sizeof(tp->recv_buf), &out_size);
+}
+
+static ssize_t isotp_c_socketcan_tp_get_send_buf(UDSTpHandle_t *hdl, uint8_t **p_buf) {
+ assert(hdl);
+ UDSTpISOTpC_t *tp = (UDSTpISOTpC_t *)hdl;
+ *p_buf = tp->send_buf;
+ return sizeof(tp->send_buf);
+}
+
+UDSErr_t UDSTpISOTpCInit(UDSTpISOTpC_t *tp, const char *ifname, uint32_t source_addr,
+ uint32_t target_addr, uint32_t source_addr_func,
+ uint32_t target_addr_func) {
+ assert(tp);
+ assert(ifname);
+ tp->hdl.poll = isotp_c_socketcan_tp_poll;
+ tp->hdl.send = isotp_c_socketcan_tp_send;
+ tp->hdl.peek = isotp_c_socketcan_tp_peek;
+ tp->hdl.ack_recv = isotp_c_socketcan_tp_ack_recv;
+ tp->hdl.get_send_buf = isotp_c_socketcan_tp_get_send_buf;
+ tp->phys_sa = source_addr;
+ tp->phys_ta = target_addr;
+ tp->func_sa = source_addr_func;
+ tp->func_ta = target_addr;
+ tp->fd = SetupSocketCAN(ifname);
+
+ isotp_init_link(&tp->phys_link, target_addr, tp->send_buf, sizeof(tp->send_buf), tp->recv_buf,
+ sizeof(tp->recv_buf), isotp_user_get_ms, isotp_user_send_can, isotp_user_debug,
+ &tp->fd);
+ isotp_init_link(&tp->func_link, target_addr_func, tp->recv_buf, sizeof(tp->send_buf),
+ tp->recv_buf, sizeof(tp->recv_buf), isotp_user_get_ms, isotp_user_send_can,
+ isotp_user_debug, &tp->fd);
+ return UDS_OK;
+}
+
+void UDSTpISOTpCDeinit(UDSTpISOTpC_t *tp) {
+ assert(tp);
+ close(tp->fd);
+ tp->fd = -1;
+}
+
+#endif
+#ifdef UDS_LINES
+#line 1 "src/tp/isotp_sock.c"
+#endif
+#if defined(UDS_TP_ISOTP_SOCK)
+
+
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+static UDSTpStatus_t isotp_sock_tp_poll(UDSTpHandle_t *hdl) { return 0; }
+
+static ssize_t tp_recv_once(int fd, uint8_t *buf, size_t size) {
+ ssize_t ret = read(fd, buf, size);
+ if (ret < 0) {
+ if (EAGAIN == errno || EWOULDBLOCK == errno) {
+ ret = 0;
+ } else {
+ UDS_DBG_PRINT("read failed: %ld with errno: %d\n", ret, errno);
+ if (EILSEQ == errno) {
+ UDS_DBG_PRINT("Perhaps I received multiple responses?\n");
+ }
+ }
+ }
+ return ret;
+}
+
+static ssize_t isotp_sock_tp_peek(UDSTpHandle_t *hdl, uint8_t **p_buf, UDSSDU_t *info) {
+ assert(hdl);
+ assert(p_buf);
+ ssize_t ret = 0;
+ UDSTpIsoTpSock_t *impl = (UDSTpIsoTpSock_t *)hdl;
+ *p_buf = impl->recv_buf;
+ if (impl->recv_len) { // recv not yet acked
+ ret = impl->recv_len;
+ goto done;
+ }
+
+ UDSSDU_t *msg = &impl->recv_info;
+
+ // recv acked, OK to receive
+ ret = tp_recv_once(impl->phys_fd, impl->recv_buf, sizeof(impl->recv_buf));
+ if (ret > 0) {
+ msg->A_TA = impl->phys_sa;
+ msg->A_SA = impl->phys_ta;
+ msg->A_TA_Type = UDS_A_TA_TYPE_PHYSICAL;
+ } else {
+ ret = tp_recv_once(impl->func_fd, impl->recv_buf, sizeof(impl->recv_buf));
+ if (ret > 0) {
+ msg->A_TA = impl->func_sa;
+ msg->A_SA = impl->func_ta;
+ msg->A_TA_Type = UDS_A_TA_TYPE_FUNCTIONAL;
+ }
+ }
+
+ if (ret > 0) {
+ fprintf(stdout, "%06d, %s recv, 0x%03x (%s), ", UDSMillis(), impl->tag, msg->A_TA,
+ msg->A_TA_Type == UDS_A_TA_TYPE_PHYSICAL ? "phys" : "func");
+ for (unsigned i = 0; i < ret; i++) {
+ fprintf(stdout, "%02x ", impl->recv_buf[i]);
+ }
+ fprintf(stdout, "\n");
+ fflush(stdout); // flush every time in case of crash
+ // UDS_DBG_PRINT("<<< ");
+ // UDS_DBG_PRINTHEX(, ret);
+ }
+
+done:
+ if (ret > 0) {
+ impl->recv_len = ret;
+ }
+ if (info) {
+ *info = *msg;
+ }
+ return ret;
+}
+
+static void isotp_sock_tp_ack_recv(UDSTpHandle_t *hdl) {
+ assert(hdl);
+ UDSTpIsoTpSock_t *impl = (UDSTpIsoTpSock_t *)hdl;
+ impl->recv_len = 0;
+}
+
+static ssize_t isotp_sock_tp_send(UDSTpHandle_t *hdl, uint8_t *buf, size_t len, UDSSDU_t *info) {
+ assert(hdl);
+ ssize_t ret = -1;
+ UDSTpIsoTpSock_t *impl = (UDSTpIsoTpSock_t *)hdl;
+ int fd;
+ const UDSTpAddr_t ta_type = info ? info->A_TA_Type : UDS_A_TA_TYPE_PHYSICAL;
+
+ if (UDS_A_TA_TYPE_PHYSICAL == ta_type) {
+ fd = impl->phys_fd;
+ } else if (UDS_A_TA_TYPE_FUNCTIONAL == ta_type) {
+ if (len > 7) {
+ UDS_DBG_PRINT("UDSTpIsoTpSock: functional request too large\n");
+ return -1;
+ }
+ fd = impl->func_fd;
+ } else {
+ ret = -4;
+ goto done;
+ }
+ ret = write(fd, buf, len);
+ if (ret < 0) {
+ perror("write");
+ }
+done:
+ // UDS_DBG_PRINT(">>> ");
+ // UDS_DBG_PRINTHEX(buf, ret);
+
+ fprintf(stdout, "%06d, %s sends, (%s), ", UDSMillis(), impl->tag,
+ ta_type == UDS_A_TA_TYPE_PHYSICAL ? "phys" : "func");
+ for (unsigned i = 0; i < len; i++) {
+ fprintf(stdout, "%02x ", buf[i]);
+ }
+ fprintf(stdout, "\n");
+ fflush(stdout); // flush every time in case of crash
+
+ return ret;
+}
+
+static ssize_t isotp_sock_tp_get_send_buf(UDSTpHandle_t *hdl, uint8_t **p_buf) {
+ assert(hdl);
+ UDSTpIsoTpSock_t *impl = (UDSTpIsoTpSock_t *)hdl;
+ *p_buf = impl->send_buf;
+ return sizeof(impl->send_buf);
+}
+
+static int LinuxSockBind(const char *if_name, uint32_t rxid, uint32_t txid, bool functional) {
+ int fd = 0;
+ if ((fd = socket(AF_CAN, SOCK_DGRAM | SOCK_NONBLOCK, CAN_ISOTP)) < 0) {
+ perror("Socket");
+ return -1;
+ }
+
+ struct can_isotp_fc_options fcopts = {
+ .bs = 0x10,
+ .stmin = 3,
+ .wftmax = 0,
+ };
+ if (setsockopt(fd, SOL_CAN_ISOTP, CAN_ISOTP_RECV_FC, &fcopts, sizeof(fcopts)) < 0) {
+ perror("setsockopt");
+ return -1;
+ }
+
+ if (functional) {
+ printf("configuring fd: %d as functional\n", fd);
+ // configure the socket as listen-only to avoid sending FC frames
+ struct can_isotp_options opts;
+ memset(&opts, 0, sizeof(opts));
+ opts.flags |= CAN_ISOTP_LISTEN_MODE;
+ if (setsockopt(fd, SOL_CAN_ISOTP, CAN_ISOTP_OPTS, &opts, sizeof(opts)) < 0) {
+ perror("setsockopt (isotp_options):");
+ return -1;
+ }
+ }
+
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
+ ioctl(fd, SIOCGIFINDEX, &ifr);
+
+ struct sockaddr_can addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.can_family = AF_CAN;
+ addr.can_addr.tp.rx_id = rxid;
+ addr.can_addr.tp.tx_id = txid;
+ addr.can_ifindex = ifr.ifr_ifindex;
+
+ if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ printf("Bind: %s %s\n", strerror(errno), if_name);
+ return -1;
+ }
+ return fd;
+}
+
+UDSErr_t UDSTpIsoTpSockInitServer(UDSTpIsoTpSock_t *tp, const char *ifname, uint32_t source_addr,
+ uint32_t target_addr, uint32_t source_addr_func) {
+ assert(tp);
+ tp->hdl.peek = isotp_sock_tp_peek;
+ tp->hdl.send = isotp_sock_tp_send;
+ tp->hdl.poll = isotp_sock_tp_poll;
+ tp->hdl.ack_recv = isotp_sock_tp_ack_recv;
+ tp->hdl.get_send_buf = isotp_sock_tp_get_send_buf;
+ tp->phys_sa = source_addr;
+ tp->phys_ta = target_addr;
+ tp->func_sa = source_addr_func;
+
+ tp->phys_fd = LinuxSockBind(ifname, source_addr, target_addr, false);
+ tp->func_fd = LinuxSockBind(ifname, source_addr_func, 0, true);
+ if (tp->phys_fd < 0 || tp->func_fd < 0) {
+ printf("foo\n");
+ fflush(stdout);
+ return UDS_ERR;
+ }
+ UDS_DBG_PRINT("%s initialized phys link rx 0x%03x tx 0x%03x func link rx 0x%03x tx 0x%03x\n",
+ strlen(tp->tag) ? tp->tag : "server", source_addr, target_addr, source_addr_func,
+ target_addr);
+ return UDS_OK;
+}
+
+UDSErr_t UDSTpIsoTpSockInitClient(UDSTpIsoTpSock_t *tp, const char *ifname, uint32_t source_addr,
+ uint32_t target_addr, uint32_t target_addr_func) {
+ assert(tp);
+ tp->hdl.peek = isotp_sock_tp_peek;
+ tp->hdl.send = isotp_sock_tp_send;
+ tp->hdl.poll = isotp_sock_tp_poll;
+ tp->hdl.ack_recv = isotp_sock_tp_ack_recv;
+ tp->hdl.get_send_buf = isotp_sock_tp_get_send_buf;
+ tp->func_ta = target_addr_func;
+ tp->phys_ta = target_addr;
+ tp->phys_sa = source_addr;
+
+ tp->phys_fd = LinuxSockBind(ifname, source_addr, target_addr, false);
+ tp->func_fd = LinuxSockBind(ifname, 0, target_addr_func, true);
+ if (tp->phys_fd < 0 || tp->func_fd < 0) {
+ return UDS_ERR;
+ }
+ printf("%s initialized phys link (fd %d) rx 0x%03x tx 0x%03x func link (fd %d) rx 0x%03x tx "
+ "0x%03x\n",
+ strlen(tp->tag) ? tp->tag : "client", tp->phys_fd, source_addr, target_addr, tp->func_fd,
+ source_addr, target_addr_func);
+ return UDS_OK;
+}
+
+void UDSTpIsoTpSockDeinit(UDSTpIsoTpSock_t *tp) {
+ if (tp) {
+ if (close(tp->phys_fd) < 0) {
+ perror("failed to close socket");
+ }
+ if (close(tp->func_fd) < 0) {
+ perror("failed to close socket");
+ }
+ }
+}
+
+#endif
+
+#ifdef UDS_LINES
+#line 1 "src/tp/mock.c"
+#endif
+#if defined(UDS_TP_MOCK)
+
+
+
+#include
+#include
+#include
+#include
+#include
+
+#define MAX_NUM_TP 16
+#define NUM_MSGS 8
+static TPMock_t *TPs[MAX_NUM_TP];
+static unsigned TPCount = 0;
+static FILE *LogFile = NULL;
+static struct Msg {
+ uint8_t buf[UDS_ISOTP_MTU];
+ size_t len;
+ UDSSDU_t info;
+ uint32_t scheduled_tx_time;
+} msgs[NUM_MSGS];
+static unsigned MsgCount = 0;
+
+static void LogMsg(const char *prefix, const uint8_t *buf, size_t len, UDSSDU_t *info) {
+ if (!LogFile) {
+ return;
+ }
+ fprintf(LogFile, "%06d, %s sends, 0x%03x (%s), ", UDSMillis(), prefix, info->A_TA,
+ info->A_TA_Type == UDS_A_TA_TYPE_PHYSICAL ? "phys" : "func");
+ for (unsigned i = 0; i < len; i++) {
+ fprintf(LogFile, "%02x ", buf[i]);
+ }
+ fprintf(LogFile, "\n");
+ fflush(LogFile); // flush every time in case of crash
+}
+
+static void NetworkPoll() {
+ for (unsigned i = 0; i < MsgCount; i++) {
+ struct Msg *msg = &msgs[i];
+ if (UDSTimeAfter(UDSMillis(), msg->scheduled_tx_time)) {
+ for (unsigned j = 0; j < TPCount; j++) {
+ TPMock_t *tp = TPs[j];
+ if (tp->sa_phys == msg->info.A_TA || tp->sa_func == msg->info.A_TA) {
+ if (tp->recv_len > 0) {
+ fprintf(stderr, "TPMock: %s recv buffer is already full. Message dropped\n",
+ tp->name);
+ continue;
+ }
+ memmove(tp->recv_buf, msg->buf, msg->len);
+ tp->recv_len = msg->len;
+ tp->recv_info = msg->info;
+ }
+ }
+ LogMsg("network", msg->buf, msg->len, &msg->info);
+ for (unsigned j = i + 1; j < MsgCount; j++) {
+ msgs[j - 1] = msgs[j];
+ }
+ MsgCount--;
+ i--;
+ }
+ }
+}
+
+static ssize_t mock_tp_peek(struct UDSTpHandle *hdl, uint8_t **p_buf, UDSSDU_t *info) {
+ assert(hdl);
+ assert(p_buf);
+ TPMock_t *tp = (TPMock_t *)hdl;
+ if (p_buf) {
+ *p_buf = tp->recv_buf;
+ }
+ if (info) {
+ *info = tp->recv_info;
+ }
+ return tp->recv_len;
+}
+
+static ssize_t mock_tp_send(struct UDSTpHandle *hdl, uint8_t *buf, size_t len, UDSSDU_t *info) {
+ assert(hdl);
+ TPMock_t *tp = (TPMock_t *)hdl;
+ if (MsgCount > NUM_MSGS) {
+ fprintf(stderr, "TPMock: too many messages in the queue\n");
+ return -1;
+ }
+ struct Msg *m = &msgs[MsgCount++];
+ UDSTpAddr_t ta_type = info == NULL ? UDS_A_TA_TYPE_PHYSICAL : info->A_TA_Type;
+ m->len = len;
+ m->info.A_AE = info == NULL ? 0 : info->A_AE;
+ if (UDS_A_TA_TYPE_PHYSICAL == ta_type) {
+ m->info.A_TA = tp->ta_phys;
+ m->info.A_SA = tp->sa_phys;
+ } else if (UDS_A_TA_TYPE_FUNCTIONAL == ta_type) {
+ m->info.A_TA = tp->ta_func;
+ m->info.A_SA = tp->sa_func;
+ } else {
+ fprintf(stderr, "TPMock: unknown TA type: %d\n", ta_type);
+ return -1;
+ }
+ m->info.A_TA_Type = ta_type;
+ m->scheduled_tx_time = UDSMillis() + tp->send_tx_delay_ms;
+ memmove(m->buf, buf, len);
+ LogMsg(tp->name, buf, len, &m->info);
+ return len;
+}
+
+static UDSTpStatus_t mock_tp_poll(struct UDSTpHandle *hdl) {
+ NetworkPoll();
+ // todo: make this status reflect TX time
+ return UDS_TP_IDLE;
+}
+
+static ssize_t mock_tp_get_send_buf(struct UDSTpHandle *hdl, uint8_t **p_buf) {
+ assert(hdl);
+ assert(p_buf);
+ TPMock_t *tp = (TPMock_t *)hdl;
+ *p_buf = tp->send_buf;
+ return sizeof(tp->send_buf);
+}
+
+static void mock_tp_ack_recv(struct UDSTpHandle *hdl) {
+ assert(hdl);
+ TPMock_t *tp = (TPMock_t *)hdl;
+ tp->recv_len = 0;
+}
+
+static_assert(offsetof(TPMock_t, hdl) == 0, "TPMock_t must not have any members before hdl");
+
+static void TPMockAttach(TPMock_t *tp, TPMockArgs_t *args) {
+ assert(tp);
+ assert(args);
+ assert(TPCount < MAX_NUM_TP);
+ TPs[TPCount++] = tp;
+ tp->hdl.peek = mock_tp_peek;
+ tp->hdl.send = mock_tp_send;
+ tp->hdl.poll = mock_tp_poll;
+ tp->hdl.get_send_buf = mock_tp_get_send_buf;
+ tp->hdl.ack_recv = mock_tp_ack_recv;
+ tp->sa_func = args->sa_func;
+ tp->sa_phys = args->sa_phys;
+ tp->ta_func = args->ta_func;
+ tp->ta_phys = args->ta_phys;
+ tp->recv_len = 0;
+}
+
+static void TPMockDetach(TPMock_t *tp) {
+ assert(tp);
+ for (unsigned i = 0; i < TPCount; i++) {
+ if (TPs[i] == tp) {
+ for (unsigned j = i + 1; j < TPCount; j++) {
+ TPs[j - 1] = TPs[j];
+ }
+ TPCount--;
+ printf("TPMock: detached %s. TPCount: %d\n", tp->name, TPCount);
+ return;
+ }
+ }
+ assert(false);
+}
+
+UDSTpHandle_t *TPMockNew(const char *name, TPMockArgs_t *args) {
+ if (TPCount >= MAX_NUM_TP) {
+ printf("TPCount: %d, too many TPs\n", TPCount);
+ return NULL;
+ }
+ TPMock_t *tp = malloc(sizeof(TPMock_t));
+ if (name) {
+ strncpy(tp->name, name, sizeof(tp->name));
+ } else {
+ snprintf(tp->name, sizeof(tp->name), "TPMock%d", TPCount);
+ }
+ TPMockAttach(tp, args);
+ return &tp->hdl;
+}
+
+void TPMockConnect(UDSTpHandle_t *tp1, UDSTpHandle_t *tp2);
+
+void TPMockLogToFile(const char *filename) {
+ if (LogFile) {
+ fprintf(stderr, "Log file is already open\n");
+ return;
+ }
+ if (!filename) {
+ fprintf(stderr, "Filename is NULL\n");
+ return;
+ }
+ // create file
+ LogFile = fopen(filename, "w");
+ if (!LogFile) {
+ fprintf(stderr, "Failed to open log file %s\n", filename);
+ return;
+ }
+}
+
+void TPMockLogToStdout(void) {
+ if (LogFile) {
+ return;
+ }
+ LogFile = stdout;
+}
+
+void TPMockReset(void) {
+ memset(TPs, 0, sizeof(TPs));
+ TPCount = 0;
+}
+
+void TPMockFree(UDSTpHandle_t *tp) {
+ TPMock_t *tpm = (TPMock_t *)tp;
+ TPMockDetach(tpm);
+ free(tp);
+}
+
+#endif
+
+#ifdef UDS_LINES
+#line 1 "src/util.c"
+#endif
+
+
+#if UDS_CUSTOM_MILLIS
+#else
+uint32_t UDSMillis(void) {
+#if UDS_SYS == UDS_SYS_UNIX
+ struct timeval te;
+ gettimeofday(&te, NULL);
+ long long milliseconds = te.tv_sec * 1000LL + te.tv_usec / 1000;
+ return milliseconds;
+#elif UDS_SYS == UDS_SYS_WINDOWS
+ struct timespec ts;
+ timespec_get(&ts, TIME_UTC);
+ long long milliseconds = ts.tv_sec * 1000LL + ts.tv_nsec / 1000000;
+ return milliseconds;
+#elif UDS_SYS == UDS_SYS_ARDUINO
+ return millis();
+#elif UDS_SYS == UDS_SYS_ESP32
+ return esp_timer_get_time() / 1000;
+#else
+#error "UDSMillis() undefined!"
+#endif
+}
+#endif
+
+bool UDSSecurityAccessLevelIsReserved(uint8_t securityLevel) {
+ securityLevel &= 0x3f;
+ return (0 == securityLevel || (0x43 <= securityLevel && securityLevel >= 0x5E) ||
+ 0x7F == securityLevel);
+}
+
+#ifdef UDS_LINES
+#line 1 "bazel-out/k8-fastbuild/bin/isotp_c_wrapped.c"
+#endif
+#if defined(UDS_ISOTP_C)
+#include
+
+
+
+///////////////////////////////////////////////////////
+/// STATIC FUNCTIONS ///
+///////////////////////////////////////////////////////
+
+/* st_min to microsecond */
+static uint8_t isotp_ms_to_st_min(uint8_t ms) {
+ uint8_t st_min;
+
+ st_min = ms;
+ if (st_min > 0x7F) {
+ st_min = 0x7F;
+ }
+
+ return st_min;
+}
+
+/* st_min to msec */
+static uint8_t isotp_st_min_to_ms(uint8_t st_min) {
+ uint8_t ms;
+
+ if (st_min >= 0xF1 && st_min <= 0xF9) {
+ ms = 1;
+ } else if (st_min <= 0x7F) {
+ ms = st_min;
+ } else {
+ ms = 0;
+ }
+
+ return ms;
+}
+
+static int isotp_send_flow_control(IsoTpLink* link, uint8_t flow_status, uint8_t block_size, uint8_t st_min_ms) {
+
+ IsoTpCanMessage message;
+ int ret;
+
+ /* setup message */
+ message.as.flow_control.type = ISOTP_PCI_TYPE_FLOW_CONTROL_FRAME;
+ message.as.flow_control.FS = flow_status;
+ message.as.flow_control.BS = block_size;
+ message.as.flow_control.STmin = isotp_ms_to_st_min(st_min_ms);
+
+ /* send message */
+#ifdef ISO_TP_FRAME_PADDING
+ (void) memset(message.as.flow_control.reserve, 0, sizeof(message.as.flow_control.reserve));
+ ret = link->isotp_user_send_can(link->send_arbitration_id, message.as.data_array.ptr, sizeof(message), link->user_data);
+#else
+ ret = link->isotp_user_send_can(link->send_arbitration_id,
+ message.as.data_array.ptr,
+ 3);
+#endif
+
+ return ret;
+}
+
+static int isotp_send_single_frame(IsoTpLink* link, uint32_t id) {
+
+ IsoTpCanMessage message;
+ int ret;
+
+ /* multi frame message length must greater than 7 */
+ assert(link->send_size <= 7);
+
+ /* setup message */
+ message.as.single_frame.type = ISOTP_PCI_TYPE_SINGLE;
+ message.as.single_frame.SF_DL = (uint8_t) link->send_size;
+ (void) memcpy(message.as.single_frame.data, link->send_buffer, link->send_size);
+
+ /* send message */
+#ifdef ISO_TP_FRAME_PADDING
+ (void) memset(message.as.single_frame.data + link->send_size, 0, sizeof(message.as.single_frame.data) - link->send_size);
+ ret = link->isotp_user_send_can(id, message.as.data_array.ptr, sizeof(message), link->user_data);
+#else
+ ret = link->isotp_user_send_can(id,
+ message.as.data_array.ptr,
+ link->send_size + 1);
+#endif
+
+ return ret;
+}
+
+static int isotp_send_first_frame(IsoTpLink* link, uint32_t id) {
+
+ IsoTpCanMessage message;
+ int ret;
+
+ /* multi frame message length must greater than 7 */
+ assert(link->send_size > 7);
+
+ /* setup message */
+ message.as.first_frame.type = ISOTP_PCI_TYPE_FIRST_FRAME;
+ message.as.first_frame.FF_DL_low = (uint8_t) link->send_size;
+ message.as.first_frame.FF_DL_high = (uint8_t) (0x0F & (link->send_size >> 8));
+ (void) memcpy(message.as.first_frame.data, link->send_buffer, sizeof(message.as.first_frame.data));
+
+ /* send message */
+ ret = link->isotp_user_send_can(id, message.as.data_array.ptr, sizeof(message), link->user_data);
+ if (ISOTP_RET_OK == ret) {
+ link->send_offset += sizeof(message.as.first_frame.data);
+ link->send_sn = 1;
+ }
+
+ return ret;
+}
+
+static int isotp_send_consecutive_frame(IsoTpLink* link) {
+
+ IsoTpCanMessage message;
+ uint16_t data_length;
+ int ret;
+
+ /* multi frame message length must greater than 7 */
+ assert(link->send_size > 7);
+
+ /* setup message */
+ message.as.consecutive_frame.type = TSOTP_PCI_TYPE_CONSECUTIVE_FRAME;
+ message.as.consecutive_frame.SN = link->send_sn;
+ data_length = link->send_size - link->send_offset;
+ if (data_length > sizeof(message.as.consecutive_frame.data)) {
+ data_length = sizeof(message.as.consecutive_frame.data);
+ }
+ (void) memcpy(message.as.consecutive_frame.data, link->send_buffer + link->send_offset, data_length);
+
+ /* send message */
+#ifdef ISO_TP_FRAME_PADDING
+ (void) memset(message.as.consecutive_frame.data + data_length, 0, sizeof(message.as.consecutive_frame.data) - data_length);
+ ret = link->isotp_user_send_can(link->send_arbitration_id, message.as.data_array.ptr, sizeof(message), link->user_data);
+#else
+ ret = link->isotp_user_send_can(link->send_arbitration_id,
+ message.as.data_array.ptr,
+ data_length + 1);
+#endif
+ if (ISOTP_RET_OK == ret) {
+ link->send_offset += data_length;
+ if (++(link->send_sn) > 0x0F) {
+ link->send_sn = 0;
+ }
+ }
+
+ return ret;
+}
+
+static int isotp_receive_single_frame(IsoTpLink *link, IsoTpCanMessage *message, uint8_t len) {
+ /* check data length */
+ if ((0 == message->as.single_frame.SF_DL) || (message->as.single_frame.SF_DL > (len - 1))) {
+ link->isotp_user_debug("Single-frame length too small.");
+ return ISOTP_RET_LENGTH;
+ }
+
+ /* copying data */
+ (void) memcpy(link->receive_buffer, message->as.single_frame.data, message->as.single_frame.SF_DL);
+ link->receive_size = message->as.single_frame.SF_DL;
+
+ return ISOTP_RET_OK;
+}
+
+static int isotp_receive_first_frame(IsoTpLink *link, IsoTpCanMessage *message, uint8_t len) {
+ uint16_t payload_length;
+
+ if (8 != len) {
+ link->isotp_user_debug("First frame should be 8 bytes in length.");
+ return ISOTP_RET_LENGTH;
+ }
+
+ /* check data length */
+ payload_length = message->as.first_frame.FF_DL_high;
+ payload_length = (payload_length << 8) + message->as.first_frame.FF_DL_low;
+
+ /* should not use multiple frame transmition */
+ if (payload_length <= 7) {
+ link->isotp_user_debug("Should not use multiple frame transmission.");
+ return ISOTP_RET_LENGTH;
+ }
+
+ if (payload_length > link->receive_buf_size) {
+ link->isotp_user_debug("Multi-frame response too large for receiving buffer.");
+ return ISOTP_RET_OVERFLOW;
+ }
+
+ /* copying data */
+ (void) memcpy(link->receive_buffer, message->as.first_frame.data, sizeof(message->as.first_frame.data));
+ link->receive_size = payload_length;
+ link->receive_offset = sizeof(message->as.first_frame.data);
+ link->receive_sn = 1;
+
+ return ISOTP_RET_OK;
+}
+
+static int isotp_receive_consecutive_frame(IsoTpLink *link, IsoTpCanMessage *message, uint8_t len) {
+ uint16_t remaining_bytes;
+
+ /* check sn */
+ if (link->receive_sn != message->as.consecutive_frame.SN) {
+ return ISOTP_RET_WRONG_SN;
+ }
+
+ /* check data length */
+ remaining_bytes = link->receive_size - link->receive_offset;
+ if (remaining_bytes > sizeof(message->as.consecutive_frame.data)) {
+ remaining_bytes = sizeof(message->as.consecutive_frame.data);
+ }
+ if (remaining_bytes > len - 1) {
+ link->isotp_user_debug("Consecutive frame too short.");
+ return ISOTP_RET_LENGTH;
+ }
+
+ /* copying data */
+ (void) memcpy(link->receive_buffer + link->receive_offset, message->as.consecutive_frame.data, remaining_bytes);
+
+ link->receive_offset += remaining_bytes;
+ if (++(link->receive_sn) > 0x0F) {
+ link->receive_sn = 0;
+ }
+
+ return ISOTP_RET_OK;
+}
+
+static int isotp_receive_flow_control_frame(IsoTpLink *link, IsoTpCanMessage *message, uint8_t len) {
+ /* check message length */
+ if (len < 3) {
+ link->isotp_user_debug("Flow control frame too short.");
+ return ISOTP_RET_LENGTH;
+ }
+
+ return ISOTP_RET_OK;
+}
+
+///////////////////////////////////////////////////////
+/// PUBLIC FUNCTIONS ///
+///////////////////////////////////////////////////////
+
+int isotp_send(IsoTpLink *link, const uint8_t payload[], uint16_t size) {
+ return isotp_send_with_id(link, link->send_arbitration_id, payload, size);
+}
+
+int isotp_send_with_id(IsoTpLink *link, uint32_t id, const uint8_t payload[], uint16_t size) {
+ int ret;
+
+ if (link == 0x0) {
+ link->isotp_user_debug("Link is null!");
+ return ISOTP_RET_ERROR;
+ }
+
+ if (size > link->send_buf_size) {
+ link->isotp_user_debug("Message size too large. Increase ISO_TP_MAX_MESSAGE_SIZE to set a larger buffer\n");
+ char message[128];
+ sprintf(&message[0], "Attempted to send %d bytes; max size is %d!\n", size, link->send_buf_size);
+ return ISOTP_RET_OVERFLOW;
+ }
+
+ if (ISOTP_SEND_STATUS_INPROGRESS == link->send_status) {
+ link->isotp_user_debug("Abort previous message, transmission in progress.\n");
+ return ISOTP_RET_INPROGRESS;
+ }
+
+ /* copy into local buffer */
+ link->send_size = size;
+ link->send_offset = 0;
+ (void) memcpy(link->send_buffer, payload, size);
+
+ if (link->send_size < 8) {
+ /* send single frame */
+ ret = isotp_send_single_frame(link, id);
+ } else {
+ /* send multi-frame */
+ ret = isotp_send_first_frame(link, id);
+
+ /* init multi-frame control flags */
+ if (ISOTP_RET_OK == ret) {
+ link->send_bs_remain = 0;
+ link->send_st_min = 0;
+ link->send_wtf_count = 0;
+ link->send_timer_st = link->isotp_user_get_ms();
+ link->send_timer_bs = link->isotp_user_get_ms() + ISO_TP_DEFAULT_RESPONSE_TIMEOUT;
+ link->send_protocol_result = ISOTP_PROTOCOL_RESULT_OK;
+ link->send_status = ISOTP_SEND_STATUS_INPROGRESS;
+ }
+ }
+
+ return ret;
+}
+
+void isotp_on_can_message(IsoTpLink *link, uint8_t *data, uint8_t len) {
+ IsoTpCanMessage message;
+ int ret;
+
+ if (len < 2 || len > 8) {
+ return;
+ }
+
+ memcpy(message.as.data_array.ptr, data, len);
+ memset(message.as.data_array.ptr + len, 0, sizeof(message.as.data_array.ptr) - len);
+
+ switch (message.as.common.type) {
+ case ISOTP_PCI_TYPE_SINGLE: {
+ /* update protocol result */
+ if (ISOTP_RECEIVE_STATUS_INPROGRESS == link->receive_status) {
+ link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_UNEXP_PDU;
+ } else {
+ link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_OK;
+ }
+
+ /* handle message */
+ ret = isotp_receive_single_frame(link, &message, len);
+
+ if (ISOTP_RET_OK == ret) {
+ /* change status */
+ link->receive_status = ISOTP_RECEIVE_STATUS_FULL;
+ }
+ break;
+ }
+ case ISOTP_PCI_TYPE_FIRST_FRAME: {
+ /* update protocol result */
+ if (ISOTP_RECEIVE_STATUS_INPROGRESS == link->receive_status) {
+ link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_UNEXP_PDU;
+ } else {
+ link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_OK;
+ }
+
+ /* handle message */
+ ret = isotp_receive_first_frame(link, &message, len);
+
+ /* if overflow happened */
+ if (ISOTP_RET_OVERFLOW == ret) {
+ /* update protocol result */
+ link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_BUFFER_OVFLW;
+ /* change status */
+ link->receive_status = ISOTP_RECEIVE_STATUS_IDLE;
+ /* send error message */
+ isotp_send_flow_control(link, PCI_FLOW_STATUS_OVERFLOW, 0, 0);
+ break;
+ }
+
+ /* if receive successful */
+ if (ISOTP_RET_OK == ret) {
+ /* change status */
+ link->receive_status = ISOTP_RECEIVE_STATUS_INPROGRESS;
+ /* send fc frame */
+ link->receive_bs_count = ISO_TP_DEFAULT_BLOCK_SIZE;
+ isotp_send_flow_control(link, PCI_FLOW_STATUS_CONTINUE, link->receive_bs_count, ISO_TP_DEFAULT_ST_MIN);
+ /* refresh timer cs */
+ link->receive_timer_cr = link->isotp_user_get_ms() + ISO_TP_DEFAULT_RESPONSE_TIMEOUT;
+ }
+
+ break;
+ }
+ case TSOTP_PCI_TYPE_CONSECUTIVE_FRAME: {
+ /* check if in receiving status */
+ if (ISOTP_RECEIVE_STATUS_INPROGRESS != link->receive_status) {
+ link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_UNEXP_PDU;
+ break;
+ }
+
+ /* handle message */
+ ret = isotp_receive_consecutive_frame(link, &message, len);
+
+ /* if wrong sn */
+ if (ISOTP_RET_WRONG_SN == ret) {
+ link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_WRONG_SN;
+ link->receive_status = ISOTP_RECEIVE_STATUS_IDLE;
+ break;
+ }
+
+ /* if success */
+ if (ISOTP_RET_OK == ret) {
+ /* refresh timer cs */
+ link->receive_timer_cr = link->isotp_user_get_ms() + ISO_TP_DEFAULT_RESPONSE_TIMEOUT;
+
+ /* receive finished */
+ if (link->receive_offset >= link->receive_size) {
+ link->receive_status = ISOTP_RECEIVE_STATUS_FULL;
+ } else {
+ /* send fc when bs reaches limit */
+ if (0 == --link->receive_bs_count) {
+ link->receive_bs_count = ISO_TP_DEFAULT_BLOCK_SIZE;
+ isotp_send_flow_control(link, PCI_FLOW_STATUS_CONTINUE, link->receive_bs_count, ISO_TP_DEFAULT_ST_MIN);
+ }
+ }
+ }
+
+ break;
+ }
+ case ISOTP_PCI_TYPE_FLOW_CONTROL_FRAME:
+ /* handle fc frame only when sending in progress */
+ if (ISOTP_SEND_STATUS_INPROGRESS != link->send_status) {
+ break;
+ }
+
+ /* handle message */
+ ret = isotp_receive_flow_control_frame(link, &message, len);
+
+ if (ISOTP_RET_OK == ret) {
+ /* refresh bs timer */
+ link->send_timer_bs = link->isotp_user_get_ms() + ISO_TP_DEFAULT_RESPONSE_TIMEOUT;
+
+ /* overflow */
+ if (PCI_FLOW_STATUS_OVERFLOW == message.as.flow_control.FS) {
+ link->send_protocol_result = ISOTP_PROTOCOL_RESULT_BUFFER_OVFLW;
+ link->send_status = ISOTP_SEND_STATUS_ERROR;
+ }
+
+ /* wait */
+ else if (PCI_FLOW_STATUS_WAIT == message.as.flow_control.FS) {
+ link->send_wtf_count += 1;
+ /* wait exceed allowed count */
+ if (link->send_wtf_count > ISO_TP_MAX_WFT_NUMBER) {
+ link->send_protocol_result = ISOTP_PROTOCOL_RESULT_WFT_OVRN;
+ link->send_status = ISOTP_SEND_STATUS_ERROR;
+ }
+ }
+
+ /* permit send */
+ else if (PCI_FLOW_STATUS_CONTINUE == message.as.flow_control.FS) {
+ if (0 == message.as.flow_control.BS) {
+ link->send_bs_remain = ISOTP_INVALID_BS;
+ } else {
+ link->send_bs_remain = message.as.flow_control.BS;
+ }
+ link->send_st_min = isotp_st_min_to_ms(message.as.flow_control.STmin);
+ link->send_wtf_count = 0;
+ }
+ }
+ break;
+ default:
+ break;
+ };
+
+ return;
+}
+
+int isotp_receive(IsoTpLink *link, uint8_t *payload, const uint16_t payload_size, uint16_t *out_size) {
+ uint16_t copylen;
+
+ if (ISOTP_RECEIVE_STATUS_FULL != link->receive_status) {
+ return ISOTP_RET_NO_DATA;
+ }
+
+ copylen = link->receive_size;
+ if (copylen > payload_size) {
+ copylen = payload_size;
+ }
+
+ memcpy(payload, link->receive_buffer, copylen);
+ *out_size = copylen;
+
+ link->receive_status = ISOTP_RECEIVE_STATUS_IDLE;
+
+ return ISOTP_RET_OK;
+}
+
+void isotp_init_link(
+ IsoTpLink *link,
+ uint32_t sendid,
+ uint8_t *sendbuf,
+ uint16_t sendbufsize,
+ uint8_t *recvbuf,
+ uint16_t recvbufsize,
+ uint32_t (*isotp_user_get_ms)(void),
+ int (*isotp_user_send_can)(const uint32_t arbitration_id, const uint8_t* data, const uint8_t size, void *user_data),
+ void (*isotp_user_debug)(const char* message, ...),
+ void *user_data
+ ) {
+ memset(link, 0, sizeof(*link));
+ link->receive_status = ISOTP_RECEIVE_STATUS_IDLE;
+ link->send_status = ISOTP_SEND_STATUS_IDLE;
+ link->send_arbitration_id = sendid;
+ link->send_buffer = sendbuf;
+ link->send_buf_size = sendbufsize;
+ link->receive_buffer = recvbuf;
+ link->receive_buf_size = recvbufsize;
+ link->isotp_user_get_ms = isotp_user_get_ms;
+ link->isotp_user_send_can = isotp_user_send_can;
+ link->isotp_user_debug = isotp_user_debug;
+ link->user_data = user_data;
+
+ return;
+}
+
+void isotp_poll(IsoTpLink *link) {
+ int ret;
+
+ /* only polling when operation in progress */
+ if (ISOTP_SEND_STATUS_INPROGRESS == link->send_status) {
+
+ /* continue send data */
+ if (/* send data if bs_remain is invalid or bs_remain large than zero */
+ (ISOTP_INVALID_BS == link->send_bs_remain || link->send_bs_remain > 0) &&
+ /* and if st_min is zero or go beyond interval time */
+ (0 == link->send_st_min || (0 != link->send_st_min && IsoTpTimeAfter(link->isotp_user_get_ms(), link->send_timer_st)))) {
+
+ ret = isotp_send_consecutive_frame(link);
+ if (ISOTP_RET_OK == ret) {
+ if (ISOTP_INVALID_BS != link->send_bs_remain) {
+ link->send_bs_remain -= 1;
+ }
+ link->send_timer_bs = link->isotp_user_get_ms() + ISO_TP_DEFAULT_RESPONSE_TIMEOUT;
+ link->send_timer_st = link->isotp_user_get_ms() + link->send_st_min;
+
+ /* check if send finish */
+ if (link->send_offset >= link->send_size) {
+ link->send_status = ISOTP_SEND_STATUS_IDLE;
+ }
+ } else {
+ link->send_status = ISOTP_SEND_STATUS_ERROR;
+ }
+ }
+
+ /* check timeout */
+ if (IsoTpTimeAfter(link->isotp_user_get_ms(), link->send_timer_bs)) {
+ link->send_protocol_result = ISOTP_PROTOCOL_RESULT_TIMEOUT_BS;
+ link->send_status = ISOTP_SEND_STATUS_ERROR;
+ }
+ }
+
+ /* only polling when operation in progress */
+ if (ISOTP_RECEIVE_STATUS_INPROGRESS == link->receive_status) {
+
+ /* check timeout */
+ if (IsoTpTimeAfter(link->isotp_user_get_ms(), link->receive_timer_cr)) {
+ link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_TIMEOUT_CR;
+ link->receive_status = ISOTP_RECEIVE_STATUS_IDLE;
+ }
+ }
+
+ return;
+}
+
+#endif
diff --git a/release/iso14229.h b/release/iso14229.h
new file mode 100644
index 0000000..6505996
--- /dev/null
+++ b/release/iso14229.h
@@ -0,0 +1,1385 @@
+#ifndef ISO14229_H
+#define ISO14229_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define UDS_VERSION "0.7.0"
+
+
+#define UDS_SYS_CUSTOM 0
+#define UDS_SYS_UNIX 1
+#define UDS_SYS_WINDOWS 2
+#define UDS_SYS_ARDUINO 3
+#define UDS_SYS_ESP32 4
+
+#if !defined(UDS_SYS)
+
+#if defined(__unix__) || defined(__APPLE__)
+#define UDS_SYS UDS_SYS_UNIX
+#elif defined(_WIN32)
+#define UDS_SYS UDS_SYS_WINDOWS
+#elif defined(ARDUINO)
+#define UDS_SYS UDS_SYS_ARDUINO
+#elif defined(ESP_PLATFORM)
+#define UDS_SYS UDS_SYS_ESP32
+#else
+#define UDS_SYS UDS_SYS_CUSTOM
+#endif
+
+#endif
+
+
+
+
+
+
+
+#if UDS_SYS == UDS_SYS_ARDUINO
+
+#include
+#include
+#include
+#include
+
+#define UDS_TP UDS_TP_ISOTP_C
+#define UDS_ENABLE_DBG_PRINT 1
+#define UDS_ENABLE_ASSERT 1
+int print_impl(const char *fmt, ...);
+#define UDS_DBG_PRINT_IMPL print_impl
+
+#endif
+
+
+#if UDS_SYS == UDS_SYS_UNIX
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#endif
+
+
+#if UDS_SYS == UDS_SYS_WIN32
+
+#include
+typedef SSIZE_T ssize_t;
+
+#endif
+
+
+#if UDS_SYS == UDS_SYS_ESP32
+
+#include
+#include
+#include
+
+#define UDS_TP UDS_TP_ISOTP_C
+#define UDS_ENABLE_DBG_PRINT 1
+#define UDS_ENABLE_ASSERT 1
+
+#endif
+
+
+#ifndef UDS_ENABLE_DBG_PRINT
+#define UDS_ENABLE_DBG_PRINT 0
+#endif
+
+#ifndef UDS_ENABLE_ASSERT
+#define UDS_ENABLE_ASSERT 0
+#endif
+
+/** ISO-TP Maximum Transmissiable Unit (ISO-15764-2-2004 section 5.3.3) */
+#define UDS_ISOTP_MTU (4095)
+
+#ifndef UDS_TP_MTU
+#define UDS_TP_MTU UDS_ISOTP_MTU
+#endif
+
+#ifndef UDS_CLIENT_DEFAULT_P2_MS
+#define UDS_CLIENT_DEFAULT_P2_MS (150U)
+#endif
+
+#ifndef UDS_CLIENT_DEFAULT_P2_STAR_MS
+#define UDS_CLIENT_DEFAULT_P2_STAR_MS (1500U)
+#endif
+
+_Static_assert(UDS_CLIENT_DEFAULT_P2_STAR_MS > UDS_CLIENT_DEFAULT_P2_MS, "");
+
+#ifndef UDS_SERVER_DEFAULT_POWER_DOWN_TIME_MS
+#define UDS_SERVER_DEFAULT_POWER_DOWN_TIME_MS (10)
+#endif
+
+#ifndef UDS_SERVER_DEFAULT_P2_MS
+#define UDS_SERVER_DEFAULT_P2_MS (50)
+#endif
+
+#ifndef UDS_SERVER_DEFAULT_P2_STAR_MS
+#define UDS_SERVER_DEFAULT_P2_STAR_MS (2000)
+#endif
+
+#ifndef UDS_SERVER_DEFAULT_S3_MS
+#define UDS_SERVER_DEFAULT_S3_MS (3000)
+#endif
+
+_Static_assert(0 < UDS_SERVER_DEFAULT_P2_MS &&
+ UDS_SERVER_DEFAULT_P2_MS < UDS_SERVER_DEFAULT_P2_STAR_MS &&
+ UDS_SERVER_DEFAULT_P2_STAR_MS < UDS_SERVER_DEFAULT_S3_MS,
+ "");
+
+// Amount of time to wait after boot before accepting 0x27 requests.
+#ifndef UDS_SERVER_0x27_BRUTE_FORCE_MITIGATION_BOOT_DELAY_MS
+#define UDS_SERVER_0x27_BRUTE_FORCE_MITIGATION_BOOT_DELAY_MS (1000)
+#endif
+
+// Amount of time to wait after an authentication failure before accepting another 0x27 request.
+#ifndef UDS_SERVER_0x27_BRUTE_FORCE_MITIGATION_AUTH_FAIL_DELAY_MS
+#define UDS_SERVER_0x27_BRUTE_FORCE_MITIGATION_AUTH_FAIL_DELAY_MS (1000)
+#endif
+
+#ifndef UDS_SERVER_DEFAULT_XFER_DATA_MAX_BLOCKLENGTH
+/*! ISO14229-1:2013 Table 396. This parameter is used by the requestDownload positive response
+message to inform the client how many data bytes (maxNumberOfBlockLength) to include in each
+TransferData request message from the client. */
+#define UDS_SERVER_DEFAULT_XFER_DATA_MAX_BLOCKLENGTH (UDS_TP_MTU)
+#endif
+
+
+
+
+
+#if UDS_ENABLE_ASSERT
+#include
+#else
+#define assert(x)
+#endif
+
+#if UDS_ENABLE_DBG_PRINT
+#if defined(UDS_DBG_PRINT_IMPL)
+#define UDS_DBG_PRINT UDS_DBG_PRINT_IMPL
+#else
+#include
+#define UDS_DBG_PRINT printf
+#endif
+#else
+#define UDS_DBG_PRINT(fmt, ...) ((void)fmt)
+#endif
+
+#define UDS_DBG_PRINTHEX(addr, len) \
+ for (int i = 0; i < len; i++) { \
+ UDS_DBG_PRINT("%02x,", ((uint8_t *)addr)[i]); \
+ } \
+ UDS_DBG_PRINT("\n");
+
+/* returns true if `a` is after `b` */
+static inline bool UDSTimeAfter(uint32_t a, uint32_t b) {
+ return ((int32_t)((int32_t)(b) - (int32_t)(a)) < 0);
+}
+
+/**
+ * @brief Get time in milliseconds
+ * @return current time in milliseconds
+ */
+uint32_t UDSMillis(void);
+
+bool UDSSecurityAccessLevelIsReserved(uint8_t securityLevel);
+
+
+
+
+#if defined(UDS_TP_ISOTP_C) || defined(UDS_TP_ISOTP_C_SOCKETCAN)
+#define UDS_ISOTP_C
+#endif
+
+enum UDSTpStatusFlags {
+ UDS_TP_IDLE = 0x00000000,
+ UDS_TP_SEND_IN_PROGRESS = 0x00000001,
+ UDS_TP_RECV_COMPLETE = 0x00000002,
+};
+
+typedef uint32_t UDSTpStatus_t;
+
+typedef enum {
+ UDS_A_MTYPE_DIAG = 0,
+ UDS_A_MTYPE_REMOTE_DIAG,
+ UDS_A_MTYPE_SECURE_DIAG,
+ UDS_A_MTYPE_SECURE_REMOTE_DIAG,
+} UDS_A_Mtype_t;
+
+typedef enum {
+ UDS_A_TA_TYPE_PHYSICAL = 0, // unicast (1:1)
+ UDS_A_TA_TYPE_FUNCTIONAL, // multicast
+} UDS_A_TA_Type_t;
+
+typedef uint8_t UDSTpAddr_t;
+
+/**
+ * @brief Service data unit (SDU)
+ * @details data interface between the application layer and the transport layer
+ */
+typedef struct {
+ UDS_A_Mtype_t A_Mtype; // message type (diagnostic, remote diagnostic, secure diagnostic, secure
+ // remote diagnostic)
+ uint16_t A_SA; // application source address
+ uint16_t A_TA; // application target address
+ UDS_A_TA_Type_t A_TA_Type; // application target address type (physical or functional)
+ uint16_t A_AE; // application layer remote address
+} UDSSDU_t;
+
+#define UDS_TP_NOOP_ADDR (0xFFFFFFFF)
+
+/**
+ * @brief Interface to OSI layer 4 (transport layer)
+ * @note implementers should embed this struct at offset zero in their own transport layer handle
+ */
+typedef struct UDSTpHandle {
+ /**
+ * @brief Get the transport layer's send buffer
+ * @param hdl: pointer to transport handle
+ * @param buf: double pointer which will be pointed to the send buffer
+ * @return size of transport layer's send buffer on success, -1 on error
+ */
+ ssize_t (*get_send_buf)(struct UDSTpHandle *hdl, uint8_t **p_buf);
+
+ /**
+ * @brief Send the data in the buffer buf
+ * @param hdl: pointer to transport handle
+ * @param buf: a pointer to the data to send (this may be the buffer returned by @ref
+ * get_send_buf)
+ * @param info: pointer to SDU info (may be NULL). If NULL, implementation should send with
+ * physical addressing
+ */
+ ssize_t (*send)(struct UDSTpHandle *hdl, uint8_t *buf, size_t len, UDSSDU_t *info);
+
+ /**
+ * @brief Poll the transport layer.
+ * @param hdl: pointer to transport handle
+ * @note the transport layer user is responsible for calling this function periodically
+ * @note threaded implementations like linux isotp sockets don't need to do anything here.
+ * @return UDS_TP_IDLE if idle, otherwise UDS_TP_SEND_IN_PROGRESS or UDS_TP_RECV_COMPLETE
+ */
+ UDSTpStatus_t (*poll)(struct UDSTpHandle *hdl);
+
+ /**
+ * @brief Peek at the received data
+ * @param hdl: pointer to transport handle
+ * @param buf: set to the received data
+ * @param info: filled with SDU info by the callee if not NULL
+ * @return size of received data on success, -1 on error
+ * @note The transport will be unable to receive further data until @ref ack_recv is called
+ * @note The information returned by peek will not change until @ref ack_recv is called
+ */
+ ssize_t (*peek)(struct UDSTpHandle *hdl, uint8_t **buf, UDSSDU_t *info);
+
+ /**
+ * @brief Acknowledge that the received data has been processed and may be discarded
+ * @param hdl: pointer to transport handle
+ * @note: after ack_recv() is called and before new messages are received, peek must return 0.
+ */
+ void (*ack_recv)(struct UDSTpHandle *hdl);
+} UDSTpHandle_t;
+
+ssize_t UDSTpGetSendBuf(UDSTpHandle_t *hdl, uint8_t **buf);
+ssize_t UDSTpSend(UDSTpHandle_t *hdl, const uint8_t *buf, ssize_t len, UDSSDU_t *info);
+UDSTpStatus_t UDSTpPoll(UDSTpHandle_t *hdl);
+ssize_t UDSTpPeek(struct UDSTpHandle *hdl, uint8_t **buf, UDSSDU_t *info);
+const uint8_t *UDSTpGetRecvBuf(UDSTpHandle_t *hdl, size_t *len);
+size_t UDSTpGetRecvLen(UDSTpHandle_t *hdl);
+void UDSTpAckRecv(UDSTpHandle_t *hdl);
+
+
+enum UDSServerEvent {
+ UDS_SRV_EVT_DiagSessCtrl, // UDSDiagSessCtrlArgs_t *
+ UDS_SRV_EVT_EcuReset, // UDSECUResetArgs_t *
+ UDS_SRV_EVT_ReadDataByIdent, // UDSRDBIArgs_t *
+ UDS_SRV_EVT_ReadMemByAddr, // UDSReadMemByAddrArgs_t *
+ UDS_SRV_EVT_CommCtrl, // UDSCommCtrlArgs_t *
+ UDS_SRV_EVT_SecAccessRequestSeed, // UDSSecAccessRequestSeedArgs_t *
+ UDS_SRV_EVT_SecAccessValidateKey, // UDSSecAccessValidateKeyArgs_t *
+ UDS_SRV_EVT_WriteDataByIdent, // UDSWDBIArgs_t *
+ UDS_SRV_EVT_RoutineCtrl, // UDSRoutineCtrlArgs_t*
+ UDS_SRV_EVT_RequestDownload, // UDSRequestDownloadArgs_t*
+ UDS_SRV_EVT_RequestUpload, // UDSRequestUploadArgs_t *
+ UDS_SRV_EVT_TransferData, // UDSTransferDataArgs_t *
+ UDS_SRV_EVT_RequestTransferExit, // UDSRequestTransferExitArgs_t *
+ UDS_SRV_EVT_SessionTimeout, // NULL
+ UDS_SRV_EVT_DoScheduledReset, // enum UDSEcuResetType *
+ UDS_SRV_EVT_Err, // UDSErr_t *
+ UDS_EVT_IDLE,
+ UDS_EVT_RESP_RECV,
+};
+
+typedef int UDSServerEvent_t;
+typedef UDSServerEvent_t UDSEvent_t;
+
+typedef enum {
+ UDS_ERR = -1, // 通用错误
+ UDS_OK = 0, // 成功
+ UDS_ERR_TIMEOUT, // 请求超时
+ UDS_ERR_NEG_RESP, // 否定响应
+ UDS_ERR_DID_MISMATCH, // 响应DID对不上期待的DID
+ UDS_ERR_SID_MISMATCH, // 请求和响应SID对不上
+ UDS_ERR_SUBFUNCTION_MISMATCH, // 请求和响应SubFunction对不上
+ UDS_ERR_TPORT, // 传输层错误
+ UDS_ERR_FILE_IO, // 文件IO错误
+ UDS_ERR_RESP_TOO_SHORT, // 响应太短
+ UDS_ERR_BUFSIZ, // 缓冲器不够大
+ UDS_ERR_INVALID_ARG, // 参数不对、没发
+ UDS_ERR_BUSY, // 正在忙、没发
+} UDSErr_t;
+
+typedef enum {
+ UDSSeqStateDone = 0,
+ UDSSeqStateRunning = 1,
+ UDSSeqStateGotoNext = 2,
+} UDSSeqState_t;
+
+enum UDSDiagnosticSessionType {
+ kDefaultSession = 0x01,
+ kProgrammingSession = 0x02,
+ kExtendedDiagnostic = 0x03,
+ kSafetySystemDiagnostic = 0x04,
+};
+
+enum {
+ kPositiveResponse = 0,
+ kGeneralReject = 0x10,
+ kServiceNotSupported = 0x11,
+ kSubFunctionNotSupported = 0x12,
+ kIncorrectMessageLengthOrInvalidFormat = 0x13,
+ kResponseTooLong = 0x14,
+ kBusyRepeatRequest = 0x21,
+ kConditionsNotCorrect = 0x22,
+ kRequestSequenceError = 0x24,
+ kNoResponseFromSubnetComponent = 0x25,
+ kFailurePreventsExecutionOfRequestedAction = 0x26,
+ kRequestOutOfRange = 0x31,
+ kSecurityAccessDenied = 0x33,
+ kInvalidKey = 0x35,
+ kExceedNumberOfAttempts = 0x36,
+ kRequiredTimeDelayNotExpired = 0x37,
+ kUploadDownloadNotAccepted = 0x70,
+ kTransferDataSuspended = 0x71,
+ kGeneralProgrammingFailure = 0x72,
+ kWrongBlockSequenceCounter = 0x73,
+ kRequestCorrectlyReceived_ResponsePending = 0x78,
+ kSubFunctionNotSupportedInActiveSession = 0x7E,
+ kServiceNotSupportedInActiveSession = 0x7F,
+ kRpmTooHigh = 0x81,
+ kRpmTooLow = 0x82,
+ kEngineIsRunning = 0x83,
+ kEngineIsNotRunning = 0x84,
+ kEngineRunTimeTooLow = 0x85,
+ kTemperatureTooHigh = 0x86,
+ kTemperatureTooLow = 0x87,
+ kVehicleSpeedTooHigh = 0x88,
+ kVehicleSpeedTooLow = 0x89,
+ kThrottlePedalTooHigh = 0x8A,
+ kThrottlePedalTooLow = 0x8B,
+ kTransmissionRangeNotInNeutral = 0x8C,
+ kTransmissionRangeNotInGear = 0x8D,
+ kISOSAEReserved = 0x8E,
+ kBrakeSwitchNotClosed = 0x8F,
+ kShifterLeverNotInPark = 0x90,
+ kTorqueConverterClutchLocked = 0x91,
+ kVoltageTooHigh = 0x92,
+ kVoltageTooLow = 0x93,
+};
+
+/**
+ * @brief LEV_RT_
+ * @addtogroup ecuReset_0x11
+ */
+enum UDSECUResetType {
+ kHardReset = 1,
+ kKeyOffOnReset = 2,
+ kSoftReset = 3,
+ kEnableRapidPowerShutDown = 4,
+ kDisableRapidPowerShutDown = 5,
+};
+
+typedef uint8_t UDSECUReset_t;
+
+/**
+ * @addtogroup securityAccess_0x27
+ */
+enum UDSSecurityAccessType {
+ kRequestSeed = 0x01,
+ kSendKey = 0x02,
+};
+
+/**
+ * @addtogroup communicationControl_0x28
+ */
+enum UDSCommunicationControlType {
+ kEnableRxAndTx = 0,
+ kEnableRxAndDisableTx = 1,
+ kDisableRxAndEnableTx = 2,
+ kDisableRxAndTx = 3,
+};
+
+/**
+ * @addtogroup communicationControl_0x28
+ */
+enum UDSCommunicationType {
+ kNormalCommunicationMessages = 0x1,
+ kNetworkManagementCommunicationMessages = 0x2,
+ kNetworkManagementCommunicationMessagesAndNormalCommunicationMessages = 0x3,
+};
+
+/**
+ * @addtogroup routineControl_0x31
+ */
+enum RoutineControlType {
+ kStartRoutine = 1,
+ kStopRoutine = 2,
+ kRequestRoutineResults = 3,
+};
+
+/**
+ * @addtogroup controlDTCSetting_0x85
+ */
+enum DTCSettingType {
+ kDTCSettingON = 0x01,
+ kDTCSettingOFF = 0x02,
+};
+
+// ISO-14229-1:2013 Table 2
+#define UDS_MAX_DIAGNOSTIC_SERVICES 0x7F
+
+#define UDS_RESPONSE_SID_OF(request_sid) (request_sid + 0x40)
+#define UDS_REQUEST_SID_OF(response_sid) (response_sid - 0x40)
+
+#define UDS_NEG_RESP_LEN 3U
+#define UDS_0X10_REQ_LEN 2U
+#define UDS_0X10_RESP_LEN 6U
+#define UDS_0X11_REQ_MIN_LEN 2U
+#define UDS_0X11_RESP_BASE_LEN 2U
+#define UDS_0X23_REQ_MIN_LEN 4U
+#define UDS_0X23_RESP_BASE_LEN 1U
+#define UDS_0X22_RESP_BASE_LEN 1U
+#define UDS_0X27_REQ_BASE_LEN 2U
+#define UDS_0X27_RESP_BASE_LEN 2U
+#define UDS_0X28_REQ_BASE_LEN 3U
+#define UDS_0X28_RESP_LEN 2U
+#define UDS_0X2E_REQ_BASE_LEN 3U
+#define UDS_0X2E_REQ_MIN_LEN 4U
+#define UDS_0X2E_RESP_LEN 3U
+#define UDS_0X31_REQ_MIN_LEN 4U
+#define UDS_0X31_RESP_MIN_LEN 4U
+#define UDS_0X34_REQ_BASE_LEN 3U
+#define UDS_0X34_RESP_BASE_LEN 2U
+#define UDS_0X35_REQ_BASE_LEN 3U
+#define UDS_0X35_RESP_BASE_LEN 2U
+#define UDS_0X36_REQ_BASE_LEN 2U
+#define UDS_0X36_RESP_BASE_LEN 2U
+#define UDS_0X37_REQ_BASE_LEN 1U
+#define UDS_0X37_RESP_BASE_LEN 1U
+#define UDS_0X3E_REQ_MIN_LEN 2U
+#define UDS_0X3E_REQ_MAX_LEN 2U
+#define UDS_0X3E_RESP_LEN 2U
+#define UDS_0X85_REQ_BASE_LEN 2U
+#define UDS_0X85_RESP_LEN 2U
+
+enum UDSDiagnosticServiceId {
+ kSID_DIAGNOSTIC_SESSION_CONTROL = 0x10,
+ kSID_ECU_RESET = 0x11,
+ kSID_CLEAR_DIAGNOSTIC_INFORMATION = 0x14,
+ kSID_READ_DTC_INFORMATION = 0x19,
+ kSID_READ_DATA_BY_IDENTIFIER = 0x22,
+ kSID_READ_MEMORY_BY_ADDRESS = 0x23,
+ kSID_READ_SCALING_DATA_BY_IDENTIFIER = 0x24,
+ kSID_SECURITY_ACCESS = 0x27,
+ kSID_COMMUNICATION_CONTROL = 0x28,
+ kSID_READ_PERIODIC_DATA_BY_IDENTIFIER = 0x2A,
+ kSID_DYNAMICALLY_DEFINE_DATA_IDENTIFIER = 0x2C,
+ kSID_WRITE_DATA_BY_IDENTIFIER = 0x2E,
+ kSID_INPUT_CONTROL_BY_IDENTIFIER = 0x2F,
+ kSID_ROUTINE_CONTROL = 0x31,
+ kSID_REQUEST_DOWNLOAD = 0x34,
+ kSID_REQUEST_UPLOAD = 0x35,
+ kSID_TRANSFER_DATA = 0x36,
+ kSID_REQUEST_TRANSFER_EXIT = 0x37,
+ kSID_REQUEST_FILE_TRANSFER = 0x38,
+ kSID_WRITE_MEMORY_BY_ADDRESS = 0x3D,
+ kSID_TESTER_PRESENT = 0x3E,
+ kSID_ACCESS_TIMING_PARAMETER = 0x83,
+ kSID_SECURED_DATA_TRANSMISSION = 0x84,
+ kSID_CONTROL_DTC_SETTING = 0x85,
+ kSID_RESPONSE_ON_EVENT = 0x86,
+};
+
+
+
+
+
+
+enum UDSClientRequestState {
+ kRequestStateIdle = 0, // 完成
+ kRequestStateSending, // 传输层现在传输数据
+ kRequestStateAwaitSendComplete, // 等待传输发送完成
+ kRequestStateAwaitResponse, // 等待响应
+ kRequestStateProcessResponse, // 处理响应
+};
+
+typedef uint8_t UDSClientRequestState_t;
+
+enum UDSClientOptions {
+ UDS_SUPPRESS_POS_RESP = 0x1, // 服务器不应该发送肯定响应
+ UDS_FUNCTIONAL = 0x2, // 发功能请求
+ UDS_NEG_RESP_IS_ERR = 0x4, // 否定响应是属于故障
+ UDS_IGNORE_SRV_TIMINGS = 0x8, // 忽略服务器给的p2和p2_star
+};
+
+struct UDSClient;
+
+typedef UDSSeqState_t (*UDSClientCallback)(struct UDSClient *client);
+
+typedef struct UDSClient {
+ uint16_t p2_ms; // p2 超时时间
+ uint32_t p2_star_ms; // 0x78 p2* 超时时间
+ UDSTpHandle_t *tp;
+
+ // 内状态
+ uint32_t p2_timer;
+ uint8_t *recv_buf;
+ uint8_t *send_buf;
+ uint16_t recv_buf_size;
+ uint16_t send_buf_size;
+ uint16_t recv_size;
+ uint16_t send_size;
+ UDSErr_t err;
+ UDSClientRequestState_t state;
+
+ uint8_t options; // enum udsclientoptions
+ uint8_t defaultOptions; // enum udsclientoptions
+ // a copy of the options at the time a request is made
+ uint8_t _options_copy; // enum udsclientoptions
+ int (*fn)(struct UDSClient *, int, void *, void *);
+
+ const UDSClientCallback *cbList; // null-terminated list of callback functions
+ size_t cbIdx; // index of currently active callback function
+ void *cbData; // a pointer to data available to callbacks
+
+} UDSClient_t;
+
+struct SecurityAccessResponse {
+ uint8_t securityAccessType;
+ const uint8_t *securitySeed;
+ uint16_t securitySeedLength;
+};
+
+struct RequestDownloadResponse {
+ size_t maxNumberOfBlockLength;
+};
+
+struct RoutineControlResponse {
+ uint8_t routineControlType;
+ uint16_t routineIdentifier;
+ const uint8_t *routineStatusRecord;
+ uint16_t routineStatusRecordLength;
+};
+
+UDSErr_t UDSClientInit(UDSClient_t *client);
+
+#define UDS_CLIENT_IDLE (0)
+#define UDS_CLIENT_RUNNING (1)
+
+/**
+ * @brief poll the client (call this in a loop)
+ * @param client
+ * @return UDS_CLIENT_IDLE if idle, otherwise UDS_CLIENT_RUNNING
+ */
+bool UDSClientPoll(UDSClient_t *client);
+void UDSClientPoll2(UDSClient_t *client,
+ int (*fn)(UDSClient_t *client, int evt, void *ev_data, void *fn_data),
+ void *fn_data);
+
+UDSErr_t UDSSendBytes(UDSClient_t *client, const uint8_t *data, uint16_t size);
+UDSErr_t UDSSendECUReset(UDSClient_t *client, UDSECUReset_t type);
+UDSErr_t UDSSendDiagSessCtrl(UDSClient_t *client, enum UDSDiagnosticSessionType mode);
+UDSErr_t UDSSendSecurityAccess(UDSClient_t *client, uint8_t level, uint8_t *data, uint16_t size);
+UDSErr_t UDSSendCommCtrl(UDSClient_t *client, enum UDSCommunicationControlType ctrl,
+ enum UDSCommunicationType comm);
+UDSErr_t UDSSendRDBI(UDSClient_t *client, const uint16_t *didList,
+ const uint16_t numDataIdentifiers);
+UDSErr_t UDSSendWDBI(UDSClient_t *client, uint16_t dataIdentifier, const uint8_t *data,
+ uint16_t size);
+UDSErr_t UDSSendTesterPresent(UDSClient_t *client);
+UDSErr_t UDSSendRoutineCtrl(UDSClient_t *client, enum RoutineControlType type,
+ uint16_t routineIdentifier, const uint8_t *data, uint16_t size);
+
+UDSErr_t UDSSendRequestDownload(UDSClient_t *client, uint8_t dataFormatIdentifier,
+ uint8_t addressAndLengthFormatIdentifier, size_t memoryAddress,
+ size_t memorySize);
+
+UDSErr_t UDSSendRequestUpload(UDSClient_t *client, uint8_t dataFormatIdentifier,
+ uint8_t addressAndLengthFormatIdentifier, size_t memoryAddress,
+ size_t memorySize);
+UDSErr_t UDSSendTransferData(UDSClient_t *client, uint8_t blockSequenceCounter,
+ const uint16_t blockLength, const uint8_t *data, uint16_t size);
+UDSErr_t UDSSendTransferDataStream(UDSClient_t *client, uint8_t blockSequenceCounter,
+ const uint16_t blockLength, FILE *fd);
+UDSErr_t UDSSendRequestTransferExit(UDSClient_t *client);
+
+UDSErr_t UDSCtrlDTCSetting(UDSClient_t *client, uint8_t dtcSettingType,
+ uint8_t *dtcSettingControlOptionRecord, uint16_t len);
+UDSErr_t UDSUnpackRDBIResponse(const uint8_t *buf, size_t buf_len, uint16_t did, uint8_t *data,
+ uint16_t size, uint16_t *offset);
+UDSErr_t UDSUnpackSecurityAccessResponse(const UDSClient_t *client,
+ struct SecurityAccessResponse *resp);
+UDSErr_t UDSUnpackRequestDownloadResponse(const UDSClient_t *client,
+ struct RequestDownloadResponse *resp);
+UDSErr_t UDSUnpackRoutineControlResponse(const UDSClient_t *client,
+ struct RoutineControlResponse *resp);
+
+/**
+ * @brief Wait after request transmission for a response to be received
+ * @note if suppressPositiveResponse is set, this function will return
+ UDSSeqStateGotoNext as soon as the transport layer has completed transmission.
+ *
+ * @param client
+ * @param args
+ * @return UDSErr_t
+ - UDSSeqStateDone -- 流程完成
+ - UDSSeqStateRunning -- 流程正在跑、还没完成
+ */
+UDSSeqState_t UDSClientAwaitIdle(UDSClient_t *client);
+
+UDSErr_t UDSConfigDownload(UDSClient_t *client, uint8_t dataFormatIdentifier,
+ uint8_t addressAndLengthFormatIdentifier, size_t memoryAddress,
+ size_t memorySize, FILE *fd);
+
+
+
+
+
+
+/**
+ * @brief Server request context
+ */
+typedef struct {
+ uint8_t *recv_buf;
+ uint8_t *send_buf;
+ size_t recv_len;
+ size_t send_len;
+ size_t send_buf_size;
+ UDSSDU_t info;
+} UDSReq_t;
+
+typedef struct UDSServer {
+ UDSTpHandle_t *tp;
+ uint8_t (*fn)(struct UDSServer *srv, UDSServerEvent_t event, const void *arg);
+
+ /**
+ * @brief \~chinese 服务器时间参数(毫秒) \~ Server time constants (milliseconds) \~
+ */
+ uint16_t p2_ms; // Default P2_server_max timing supported by the server for
+ // the activated diagnostic session.
+ uint32_t p2_star_ms; // Enhanced (NRC 0x78) P2_server_max supported by the
+ // server for the activated diagnostic session.
+ uint16_t s3_ms; // Session timeout
+
+ uint8_t ecuResetScheduled; // nonzero indicates that an ECUReset has been scheduled
+ uint32_t ecuResetTimer; // for delaying resetting until a response
+ // has been sent to the client
+ uint32_t p2_timer; // for rate limiting server responses
+ uint32_t s3_session_timeout_timer; // indicates that diagnostic session has timed out
+ uint32_t
+ sec_access_auth_fail_timer; // brute-force hardening: rate limit security access requests
+
+ /**
+ * @brief UDS-1-2013: Table 407 - 0x36 TransferData Supported negative
+ * response codes requires that the server keep track of whether the
+ * transfer is active
+ */
+ bool xferIsActive;
+ // UDS-1-2013: 14.4.2.3, Table 404: The blockSequenceCounter parameter
+ // value starts at 0x01
+ uint8_t xferBlockSequenceCounter;
+ size_t xferTotalBytes; // total transfer size in bytes requested by the client
+ size_t xferByteCounter; // total number of bytes transferred
+ size_t xferBlockLength; // block length (convenience for the TransferData API)
+
+ uint8_t sessionType; // diagnostic session type (0x10)
+ uint8_t securityLevel; // SecurityAccess (0x27) level
+
+ bool RCRRP; // set to true when user fn returns 0x78 and false otherwise
+ bool requestInProgress; // set to true when a request has been processed but the response has
+ // not yet been sent
+
+ // UDS-1 2013 defines the following conditions under which the server does not
+ // process incoming requests:
+ // - not ready to receive (Table A.1 0x78)
+ // - not accepting request messages and not sending responses (9.3.1)
+ //
+ // when this variable is set to true, incoming ISO-TP data will not be processed.
+ bool notReadyToReceive;
+
+ UDSReq_t r;
+} UDSServer_t;
+
+typedef struct {
+ const uint8_t type; /*! requested diagnostic session type (enum UDSDiagnosticSessionType) */
+ uint16_t p2_ms; /*! optional: p2 timing override */
+ uint32_t p2_star_ms; /*! optional: p2* timing override */
+} UDSDiagSessCtrlArgs_t;
+
+typedef struct {
+ const uint8_t type; /**< \~chinese 客户端请求的复位类型 \~english reset type requested by client
+ (enum UDSECUResetType) */
+ uint32_t powerDownTimeMillis; /**< when this much time has elapsed after a kPositiveResponse, a
+ UDS_SRV_EVT_DoScheduledReset will be issued */
+} UDSECUResetArgs_t;
+
+typedef struct {
+ const uint16_t dataId; /*! RDBI Data Identifier */
+ uint8_t (*copy)(UDSServer_t *srv, const void *src,
+ uint16_t count); /*! function for copying data */
+} UDSRDBIArgs_t;
+
+typedef struct {
+ const void *memAddr;
+ const size_t memSize;
+ uint8_t (*copy)(UDSServer_t *srv, const void *src,
+ uint16_t count); /*! function for copying data */
+} UDSReadMemByAddrArgs_t;
+
+typedef struct {
+ uint8_t ctrlType; /* enum UDSCommunicationControlType */
+ uint8_t commType; /* enum UDSCommunicationType */
+} UDSCommCtrlArgs_t;
+
+typedef struct {
+ const uint8_t level; /*! requested security level */
+ const uint8_t *const dataRecord; /*! pointer to request data */
+ const uint16_t len; /*! size of request data */
+ uint8_t (*copySeed)(UDSServer_t *srv, const void *src,
+ uint16_t len); /*! function for copying data */
+} UDSSecAccessRequestSeedArgs_t;
+
+typedef struct {
+ const uint8_t level; /*! security level to be validated */
+ const uint8_t *const key; /*! key sent by client */
+ const uint16_t len; /*! length of key */
+} UDSSecAccessValidateKeyArgs_t;
+
+typedef struct {
+ const uint16_t dataId; /*! WDBI Data Identifier */
+ const uint8_t *const data; /*! pointer to data */
+ const uint16_t len; /*! length of data */
+} UDSWDBIArgs_t;
+
+typedef struct {
+ const uint8_t ctrlType; /*! routineControlType */
+ const uint16_t id; /*! routineIdentifier */
+ const uint8_t *optionRecord; /*! optional data */
+ const uint16_t len; /*! length of optional data */
+ uint8_t (*copyStatusRecord)(UDSServer_t *srv, const void *src,
+ uint16_t len); /*! function for copying response data */
+} UDSRoutineCtrlArgs_t;
+
+typedef struct {
+ const void *addr; /*! requested address */
+ const size_t size; /*! requested download size */
+ const uint8_t dataFormatIdentifier; /*! optional specifier for format of data */
+ uint16_t maxNumberOfBlockLength; /*! optional response: inform client how many data bytes to
+ send in each `TransferData` request */
+} UDSRequestDownloadArgs_t;
+
+typedef struct {
+ const void *addr; /*! requested address */
+ const size_t size; /*! requested download size */
+ const uint8_t dataFormatIdentifier; /*! optional specifier for format of data */
+ uint16_t maxNumberOfBlockLength; /*! optional response: inform client how many data bytes to
+ send in each `TransferData` request */
+} UDSRequestUploadArgs_t;
+
+typedef struct {
+ const uint8_t *const data; /*! transfer data */
+ const uint16_t len; /*! transfer data length */
+ const uint16_t maxRespLen; /*! don't send more than this many bytes with copyResponse */
+ uint8_t (*copyResponse)(
+ UDSServer_t *srv, const void *src,
+ uint16_t len); /*! function for copying transfer data response data (optional) */
+} UDSTransferDataArgs_t;
+
+typedef struct {
+ const uint8_t *const data; /*! request data */
+ const uint16_t len; /*! request data length */
+ uint8_t (*copyResponse)(UDSServer_t *srv, const void *src,
+ uint16_t len); /*! function for copying response data (optional) */
+} UDSRequestTransferExitArgs_t;
+
+UDSErr_t UDSServerInit(UDSServer_t *srv);
+void UDSServerPoll(UDSServer_t *srv);
+#if defined(UDS_ISOTP_C)
+#ifndef __ISOTP_H__
+#define __ISOTP_H__
+
+#include
+#include
+
+#ifdef __cplusplus
+#include
+
+extern "C" {
+#endif
+
+
+
+
+/**
+ * @brief Struct containing the data for linking an application to a CAN instance.
+ * The data stored in this struct is used internally and may be used by software programs
+ * using this library.
+ */
+typedef struct IsoTpLink {
+ /* sender paramters */
+ uint32_t send_arbitration_id; /* used to reply consecutive frame */
+ /* message buffer */
+ uint8_t* send_buffer;
+ uint16_t send_buf_size;
+ uint16_t send_size;
+ uint16_t send_offset;
+ /* multi-frame flags */
+ uint8_t send_sn;
+ uint16_t send_bs_remain; /* Remaining block size */
+ uint8_t send_st_min; /* Separation Time between consecutive frames, unit millis */
+ uint8_t send_wtf_count; /* Maximum number of FC.Wait frame transmissions */
+ uint32_t send_timer_st; /* Last time send consecutive frame */
+ uint32_t send_timer_bs; /* Time until reception of the next FlowControl N_PDU
+ start at sending FF, CF, receive FC
+ end at receive FC */
+ int send_protocol_result;
+ uint8_t send_status;
+
+ /* receiver paramters */
+ uint32_t receive_arbitration_id;
+ /* message buffer */
+ uint8_t* receive_buffer;
+ uint16_t receive_buf_size;
+ uint16_t receive_size;
+ uint16_t receive_offset;
+ /* multi-frame control */
+ uint8_t receive_sn;
+ uint8_t receive_bs_count; /* Maximum number of FC.Wait frame transmissions */
+ uint32_t receive_timer_cr; /* Time until transmission of the next ConsecutiveFrame N_PDU
+ start at sending FC, receive CF
+ end at receive FC */
+ int receive_protocol_result;
+ uint8_t receive_status;
+
+ /* user implemented callback functions */
+ uint32_t (*isotp_user_get_ms)(void); /* get millisecond */
+ int (*isotp_user_send_can)(const uint32_t arbitration_id,
+ const uint8_t* data, const uint8_t size, void *user_data); /* send can message. should return ISOTP_RET_OK when success. */
+ void (*isotp_user_debug)(const char* message, ...); /* print debug message */
+ void* user_data; /* user data */
+} IsoTpLink;
+
+/**
+ * @brief Initialises the ISO-TP library.
+ *
+ * @param link The @code IsoTpLink @endcode instance used for transceiving data.
+ * @param sendid The ID used to send data to other CAN nodes.
+ * @param sendbuf A pointer to an area in memory which can be used as a buffer for data to be sent.
+ * @param sendbufsize The size of the buffer area.
+ * @param recvbuf A pointer to an area in memory which can be used as a buffer for data to be received.
+ * @param recvbufsize The size of the buffer area.
+ * @param isotp_user_get_ms A pointer to a function which returns the current time as milliseconds.
+ * @param isotp_user_send_can A pointer to a function which sends a can message. should return ISOTP_RET_OK when success.
+ * @param isotp_user_debug A pointer to a function which prints a debug message.
+ * @param isotp_user_debug A pointer to user data passed to the user implemented callback functions.
+ */
+void isotp_init_link(
+ IsoTpLink *link,
+ uint32_t sendid,
+ uint8_t *sendbuf,
+ uint16_t sendbufsize,
+ uint8_t *recvbuf,
+ uint16_t recvbufsize,
+ uint32_t (*isotp_user_get_ms)(void),
+ int (*isotp_user_send_can)(const uint32_t arbitration_id, const uint8_t* data, const uint8_t size, void *user_data),
+ void (*isotp_user_debug)(const char* message, ...),
+ void *user_data
+ );
+
+/**
+ * @brief Polling function; call this function periodically to handle timeouts, send consecutive frames, etc.
+ *
+ * @param link The @code IsoTpLink @endcode instance used.
+ */
+void isotp_poll(IsoTpLink *link);
+
+/**
+ * @brief Handles incoming CAN messages.
+ * Determines whether an incoming message is a valid ISO-TP frame or not and handles it accordingly.
+ *
+ * @param link The @code IsoTpLink @endcode instance used for transceiving data.
+ * @param data The data received via CAN.
+ * @param len The length of the data received.
+ */
+void isotp_on_can_message(IsoTpLink *link, uint8_t *data, uint8_t len);
+
+/**
+ * @brief Sends ISO-TP frames via CAN, using the ID set in the initialising function.
+ *
+ * Single-frame messages will be sent immediately when calling this function.
+ * Multi-frame messages will be sent consecutively when calling isotp_poll.
+ *
+ * @param link The @code IsoTpLink @endcode instance used for transceiving data.
+ * @param payload The payload to be sent. (Up to 4095 bytes).
+ * @param size The size of the payload to be sent.
+ *
+ * @return Possible return values:
+ * - @code ISOTP_RET_OVERFLOW @endcode
+ * - @code ISOTP_RET_INPROGRESS @endcode
+ * - @code ISOTP_RET_OK @endcode
+ * - The return value of the user shim function isotp_user_send_can().
+ */
+int isotp_send(IsoTpLink *link, const uint8_t payload[], uint16_t size);
+
+/**
+ * @brief See @link isotp_send @endlink, with the exception that this function is used only for functional addressing.
+ */
+int isotp_send_with_id(IsoTpLink *link, uint32_t id, const uint8_t payload[], uint16_t size);
+
+/**
+ * @brief Receives and parses the received data and copies the parsed data in to the internal buffer.
+ * @param link The @link IsoTpLink @endlink instance used to transceive data.
+ * @param payload A pointer to an area in memory where the raw data is copied from.
+ * @param payload_size The size of the received (raw) CAN data.
+ * @param out_size A reference to a variable which will contain the size of the actual (parsed) data.
+ *
+ * @return Possible return values:
+ * - @link ISOTP_RET_OK @endlink
+ * - @link ISOTP_RET_NO_DATA @endlink
+ */
+int isotp_receive(IsoTpLink *link, uint8_t *payload, const uint16_t payload_size, uint16_t *out_size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __ISOTP_H__
+
+#ifndef __ISOTP_CONFIG__
+#define __ISOTP_CONFIG__
+
+/* Max number of messages the receiver can receive at one time, this value
+ * is affectied by can driver queue length
+ */
+#define ISO_TP_DEFAULT_BLOCK_SIZE 8
+
+/* The STmin parameter value specifies the minimum time gap allowed between
+ * the transmission of consecutive frame network protocol data units
+ */
+#define ISO_TP_DEFAULT_ST_MIN 0
+
+/* This parameter indicate how many FC N_PDU WTs can be transmitted by the
+ * receiver in a row.
+ */
+#define ISO_TP_MAX_WFT_NUMBER 1
+
+/* Private: The default timeout to use when waiting for a response during a
+ * multi-frame send or receive.
+ */
+#define ISO_TP_DEFAULT_RESPONSE_TIMEOUT 100
+
+/* Private: Determines if by default, padding is added to ISO-TP message frames.
+ */
+#define ISO_TP_FRAME_PADDING
+
+#endif
+
+#ifndef __ISOTP_TYPES__
+#define __ISOTP_TYPES__
+
+/**************************************************************
+ * compiler specific defines
+ *************************************************************/
+#ifdef __GNUC__
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#define ISOTP_BYTE_ORDER_LITTLE_ENDIAN
+#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#else
+#error "unsupported byte ordering"
+#endif
+#endif
+
+/**************************************************************
+ * OS specific defines
+ *************************************************************/
+#ifdef _WIN32
+#define snprintf _snprintf
+#endif
+
+#ifdef _WIN32
+#define ISOTP_BYTE_ORDER_LITTLE_ENDIAN
+#define __builtin_bswap8 _byteswap_uint8
+#define __builtin_bswap16 _byteswap_uint16
+#define __builtin_bswap32 _byteswap_uint32
+#define __builtin_bswap64 _byteswap_uint64
+#endif
+
+/**************************************************************
+ * internal used defines
+ *************************************************************/
+#define ISOTP_RET_OK 0
+#define ISOTP_RET_ERROR -1
+#define ISOTP_RET_INPROGRESS -2
+#define ISOTP_RET_OVERFLOW -3
+#define ISOTP_RET_WRONG_SN -4
+#define ISOTP_RET_NO_DATA -5
+#define ISOTP_RET_TIMEOUT -6
+#define ISOTP_RET_LENGTH -7
+
+/* return logic true if 'a' is after 'b' */
+#define IsoTpTimeAfter(a,b) ((int32_t)((int32_t)(b) - (int32_t)(a)) < 0)
+
+/* invalid bs */
+#define ISOTP_INVALID_BS 0xFFFF
+
+/* ISOTP sender status */
+typedef enum {
+ ISOTP_SEND_STATUS_IDLE,
+ ISOTP_SEND_STATUS_INPROGRESS,
+ ISOTP_SEND_STATUS_ERROR,
+} IsoTpSendStatusTypes;
+
+/* ISOTP receiver status */
+typedef enum {
+ ISOTP_RECEIVE_STATUS_IDLE,
+ ISOTP_RECEIVE_STATUS_INPROGRESS,
+ ISOTP_RECEIVE_STATUS_FULL,
+} IsoTpReceiveStatusTypes;
+
+/* can fram defination */
+#if defined(ISOTP_BYTE_ORDER_LITTLE_ENDIAN)
+typedef struct {
+ uint8_t reserve_1:4;
+ uint8_t type:4;
+ uint8_t reserve_2[7];
+} IsoTpPciType;
+
+typedef struct {
+ uint8_t SF_DL:4;
+ uint8_t type:4;
+ uint8_t data[7];
+} IsoTpSingleFrame;
+
+typedef struct {
+ uint8_t FF_DL_high:4;
+ uint8_t type:4;
+ uint8_t FF_DL_low;
+ uint8_t data[6];
+} IsoTpFirstFrame;
+
+typedef struct {
+ uint8_t SN:4;
+ uint8_t type:4;
+ uint8_t data[7];
+} IsoTpConsecutiveFrame;
+
+typedef struct {
+ uint8_t FS:4;
+ uint8_t type:4;
+ uint8_t BS;
+ uint8_t STmin;
+ uint8_t reserve[5];
+} IsoTpFlowControl;
+
+#else
+
+typedef struct {
+ uint8_t type:4;
+ uint8_t reserve_1:4;
+ uint8_t reserve_2[7];
+} IsoTpPciType;
+
+/*
+* single frame
+* +-------------------------+-----+
+* | byte #0 | ... |
+* +-------------------------+-----+
+* | nibble #0 | nibble #1 | ... |
+* +-------------+-----------+ ... +
+* | PCIType = 0 | SF_DL | ... |
+* +-------------+-----------+-----+
+*/
+typedef struct {
+ uint8_t type:4;
+ uint8_t SF_DL:4;
+ uint8_t data[7];
+} IsoTpSingleFrame;
+
+/*
+* first frame
+* +-------------------------+-----------------------+-----+
+* | byte #0 | byte #1 | ... |
+* +-------------------------+-----------+-----------+-----+
+* | nibble #0 | nibble #1 | nibble #2 | nibble #3 | ... |
+* +-------------+-----------+-----------+-----------+-----+
+* | PCIType = 1 | FF_DL | ... |
+* +-------------+-----------+-----------------------+-----+
+*/
+typedef struct {
+ uint8_t type:4;
+ uint8_t FF_DL_high:4;
+ uint8_t FF_DL_low;
+ uint8_t data[6];
+} IsoTpFirstFrame;
+
+/*
+* consecutive frame
+* +-------------------------+-----+
+* | byte #0 | ... |
+* +-------------------------+-----+
+* | nibble #0 | nibble #1 | ... |
+* +-------------+-----------+ ... +
+* | PCIType = 0 | SN | ... |
+* +-------------+-----------+-----+
+*/
+typedef struct {
+ uint8_t type:4;
+ uint8_t SN:4;
+ uint8_t data[7];
+} IsoTpConsecutiveFrame;
+
+/*
+* flow control frame
+* +-------------------------+-----------------------+-----------------------+-----+
+* | byte #0 | byte #1 | byte #2 | ... |
+* +-------------------------+-----------+-----------+-----------+-----------+-----+
+* | nibble #0 | nibble #1 | nibble #2 | nibble #3 | nibble #4 | nibble #5 | ... |
+* +-------------+-----------+-----------+-----------+-----------+-----------+-----+
+* | PCIType = 1 | FS | BS | STmin | ... |
+* +-------------+-----------+-----------------------+-----------------------+-----+
+*/
+typedef struct {
+ uint8_t type:4;
+ uint8_t FS:4;
+ uint8_t BS;
+ uint8_t STmin;
+ uint8_t reserve[5];
+} IsoTpFlowControl;
+
+#endif
+
+typedef struct {
+ uint8_t ptr[8];
+} IsoTpDataArray;
+
+typedef struct {
+ union {
+ IsoTpPciType common;
+ IsoTpSingleFrame single_frame;
+ IsoTpFirstFrame first_frame;
+ IsoTpConsecutiveFrame consecutive_frame;
+ IsoTpFlowControl flow_control;
+ IsoTpDataArray data_array;
+ } as;
+} IsoTpCanMessage;
+
+/**************************************************************
+ * protocol specific defines
+ *************************************************************/
+
+/* Private: Protocol Control Information (PCI) types, for identifying each frame of an ISO-TP message.
+ */
+typedef enum {
+ ISOTP_PCI_TYPE_SINGLE = 0x0,
+ ISOTP_PCI_TYPE_FIRST_FRAME = 0x1,
+ TSOTP_PCI_TYPE_CONSECUTIVE_FRAME = 0x2,
+ ISOTP_PCI_TYPE_FLOW_CONTROL_FRAME = 0x3
+} IsoTpProtocolControlInformation;
+
+/* Private: Protocol Control Information (PCI) flow control identifiers.
+ */
+typedef enum {
+ PCI_FLOW_STATUS_CONTINUE = 0x0,
+ PCI_FLOW_STATUS_WAIT = 0x1,
+ PCI_FLOW_STATUS_OVERFLOW = 0x2
+} IsoTpFlowStatus;
+
+/* Private: network layer resault code.
+ */
+#define ISOTP_PROTOCOL_RESULT_OK 0
+#define ISOTP_PROTOCOL_RESULT_TIMEOUT_A -1
+#define ISOTP_PROTOCOL_RESULT_TIMEOUT_BS -2
+#define ISOTP_PROTOCOL_RESULT_TIMEOUT_CR -3
+#define ISOTP_PROTOCOL_RESULT_WRONG_SN -4
+#define ISOTP_PROTOCOL_RESULT_INVALID_FS -5
+#define ISOTP_PROTOCOL_RESULT_UNEXP_PDU -6
+#define ISOTP_PROTOCOL_RESULT_WFT_OVRN -7
+#define ISOTP_PROTOCOL_RESULT_BUFFER_OVFLW -8
+#define ISOTP_PROTOCOL_RESULT_ERROR -9
+
+#endif
+
+#endif
+
+#if defined(UDS_TP_ISOTP_C)
+
+
+
+
+
+
+
+typedef struct {
+ UDSTpHandle_t hdl;
+ IsoTpLink phys_link;
+ IsoTpLink func_link;
+ uint8_t send_buf[UDS_ISOTP_MTU];
+ uint8_t recv_buf[UDS_ISOTP_MTU];
+ uint32_t phys_sa, phys_ta;
+ uint32_t func_sa, func_ta;
+} UDSISOTpC_t;
+
+typedef struct {
+ uint32_t source_addr;
+ uint32_t target_addr;
+ uint32_t source_addr_func;
+ uint32_t target_addr_func;
+ int (*isotp_user_send_can)(
+ const uint32_t arbitration_id, const uint8_t *data, const uint8_t size,
+ void *user_data); /* send can message. should return ISOTP_RET_OK when success. */
+ uint32_t (*isotp_user_get_ms)(void); /* get millisecond */
+ void (*isotp_user_debug)(const char *message, ...); /* print debug message */
+ void *user_data; /* user data */
+} UDSISOTpCConfig_t;
+
+UDSErr_t UDSISOTpCInit(UDSISOTpC_t *tp, const UDSISOTpCConfig_t *cfg);
+
+void UDSISOTpCDeinit(UDSISOTpC_t *tp);
+
+#endif
+
+
+#if defined(UDS_TP_ISOTP_C_SOCKETCAN)
+
+
+
+
+typedef struct {
+ UDSTpHandle_t hdl;
+ IsoTpLink phys_link;
+ IsoTpLink func_link;
+ uint8_t send_buf[UDS_ISOTP_MTU];
+ uint8_t recv_buf[UDS_ISOTP_MTU];
+ int fd;
+ uint32_t phys_sa, phys_ta;
+ uint32_t func_sa, func_ta;
+ char tag[16];
+} UDSTpISOTpC_t;
+
+UDSErr_t UDSTpISOTpCInit(UDSTpISOTpC_t *tp, const char *ifname, uint32_t source_addr,
+ uint32_t target_addr, uint32_t source_addr_func,
+ uint32_t target_addr_func);
+void UDSTpISOTpCDeinit(UDSTpISOTpC_t *tp);
+
+#endif
+#if defined(UDS_TP_ISOTP_SOCK)
+
+
+
+
+typedef struct {
+ UDSTpHandle_t hdl;
+ uint8_t recv_buf[UDS_ISOTP_MTU];
+ uint8_t send_buf[UDS_ISOTP_MTU];
+ size_t recv_len;
+ UDSSDU_t recv_info;
+ int phys_fd;
+ int func_fd;
+ uint32_t phys_sa, phys_ta;
+ uint32_t func_sa, func_ta;
+ char tag[16];
+} UDSTpIsoTpSock_t;
+
+UDSErr_t UDSTpIsoTpSockInitServer(UDSTpIsoTpSock_t *tp, const char *ifname, uint32_t source_addr,
+ uint32_t target_addr, uint32_t source_addr_func);
+UDSErr_t UDSTpIsoTpSockInitClient(UDSTpIsoTpSock_t *tp, const char *ifname, uint32_t source_addr,
+ uint32_t target_addr, uint32_t target_addr_func);
+void UDSTpIsoTpSockDeinit(UDSTpIsoTpSock_t *tp);
+
+#endif
+/**
+ * @file tp_mock.h
+ * @brief in-memory transport layer implementation for testing
+ * @date 2023-10-21
+ *
+ */
+#if defined(UDS_TP_MOCK)
+
+
+
+
+
+typedef struct TPMock {
+ UDSTpHandle_t hdl;
+ uint8_t recv_buf[UDS_TP_MTU];
+ uint8_t send_buf[UDS_TP_MTU];
+ size_t recv_len;
+ UDSSDU_t recv_info;
+ uint32_t sa_phys; // source address - physical messages are sent from this address
+ uint32_t ta_phys; // target address - physical messages are sent to this address
+ uint32_t sa_func; // source address - functional messages are sent from this address
+ uint32_t ta_func; // target address - functional messages are sent to this address
+ uint32_t send_tx_delay_ms; // simulated delay
+ uint32_t send_buf_size; // simulated size of the send buffer
+ char name[32]; // name for logging
+} TPMock_t;
+
+typedef struct {
+ uint32_t sa_phys; // source address - physical messages are sent from this address
+ uint32_t ta_phys; // target address - physical messages are sent to this address
+ uint32_t sa_func; // source address - functional messages are sent from this address
+ uint32_t ta_func; // target address - functional messages are sent to this address
+} TPMockArgs_t;
+
+#define TPMOCK_DEFAULT_CLIENT_ARGS \
+ &(TPMockArgs_t) { \
+ .sa_phys = 0x7E8, .ta_phys = 0x7E0, .sa_func = UDS_TP_NOOP_ADDR, .ta_func = 0x7DF \
+ }
+#define TPMOCK_DEFAULT_SERVER_ARGS \
+ &(TPMockArgs_t) { \
+ .sa_phys = 0x7E0, .ta_phys = 0x7E8, .sa_func = 0x7DF, .ta_func = UDS_TP_NOOP_ADDR \
+ }
+
+/**
+ * @brief Create a mock transport. It is connected by default to a broadcast network of all other
+ * mock transports in the same process.
+ * @param name optional name of the transport (can be NULL)
+ * @return UDSTpHandle_t*
+ */
+UDSTpHandle_t *TPMockNew(const char *name, TPMockArgs_t *args);
+void TPMockFree(UDSTpHandle_t *tp);
+
+/**
+ * @brief write all messages to a file
+ * @note uses UDSMillis() to get the current time
+ * @param filename log file name (will be overwritten)
+ */
+void TPMockLogToFile(const char *filename);
+void TPMockLogToStdout(void);
+
+/**
+ * @brief clear all transports and close the log file
+ */
+void TPMockReset(void);
+
+#endif
+#endif
+#ifdef __cplusplus
+}
+#endif
diff --git a/test/README.md b/test/README.md
index 3924031..982cdb0 100644
--- a/test/README.md
+++ b/test/README.md
@@ -35,10 +35,10 @@ bazel test --config=ppc64 //test:all
bazel test --config=ppc64le //test:all
# build the fuzzer
-bazel build -s --verbose_failures --config=x86_64_clang //test:test_fuzz_server
+bazel build -s --verbose_failures --config=x85_64_clang //test:test_fuzz_server
# run the fuzzer
mkdir .libfuzzer_artifacts .libfuzzer_corpus
-bazel-bin/test/test_fuzz_server -jobs=8 -artifact_prefix=./.libfuzzer_artifacts/ .libfuzzer_corpus
+bazel-bin/test/test_fuzz_server -jobs=7 -artifact_prefix=./.libfuzzer_artifacts/ .libfuzzer_corpus
```
If building fails with `/usr/bin/ld: cannot find -lstdc++: No such file or directory`
From 937374259903c67e7c86e0eac5c332ec22bc8b92 Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Thu, 14 Dec 2023 23:20:09 -0700
Subject: [PATCH 36/56] update ultra-strict build, fix esp32 build
---
.gitignore | 1 +
release/iso14229.c | 15 ++++-----------
release/iso14229.h | 2 +-
src/server.c | 2 +-
src/sys_esp32.h | 2 +-
src/tp/isotp_c_socketcan.c | 11 ++---------
src/tp/mock.c | 2 +-
test/BUILD | 5 +++++
test_all.sh | 24 ++++++++++++++++++++++++
9 files changed, 40 insertions(+), 24 deletions(-)
create mode 100755 test_all.sh
diff --git a/.gitignore b/.gitignore
index b0a5de7..9930e37 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,3 +13,4 @@ fuzzer
**/*.cache
**/build
**/sdkconfig*
+release/
diff --git a/release/iso14229.c b/release/iso14229.c
index ee3d88d..d870732 100644
--- a/release/iso14229.c
+++ b/release/iso14229.c
@@ -1043,7 +1043,7 @@ static uint8_t decodeAddressAndLength(UDSReq_t *r, uint8_t *const buf, void **me
assert(r);
assert(memoryAddress);
assert(memorySize);
- long long unsigned int tmp = 0;
+ uintptr_t tmp = 0;
*memoryAddress = 0;
*memorySize = 0;
@@ -2090,7 +2090,7 @@ static int SetupSocketCAN(const char *ifname) {
return sockfd;
}
-uint32_t isotp_user_get_ms() { return UDSMillis(); }
+uint32_t isotp_user_get_ms(void) { return UDSMillis(); }
void isotp_user_debug(const char *message, ...) {
va_list args;
@@ -2114,13 +2114,6 @@ int isotp_user_send_can(const uint32_t arbitration_id, const uint8_t *data, cons
return ISOTP_RET_OK;
}
-static void printhex(const uint8_t *addr, int len) {
- for (int i = 0; i < len; i++) {
- printf("%02x,", addr[i]);
- }
- printf("\n");
-}
-
static void SocketCANRecv(UDSTpISOTpC_t *tp) {
assert(tp);
struct can_frame frame = {0};
@@ -2238,7 +2231,7 @@ static ssize_t isotp_c_socketcan_tp_peek(UDSTpHandle_t *hdl, uint8_t **p_buf, UD
}
fprintf(stdout, "%06d, %s recv, 0x%03x (%s), ", UDSMillis(), tp->tag, ta,
ta_type == UDS_A_TA_TYPE_PHYSICAL ? "phys" : "func");
- for (unsigned i = 0; i < ret; i++) {
+ for (int i = 0; i < ret; i++) {
fprintf(stdout, "%02x ", (*p_buf)[i]);
}
fprintf(stdout, "\n");
@@ -2627,7 +2620,7 @@ static void LogMsg(const char *prefix, const uint8_t *buf, size_t len, UDSSDU_t
fflush(LogFile); // flush every time in case of crash
}
-static void NetworkPoll() {
+static void NetworkPoll(void) {
for (unsigned i = 0; i < MsgCount; i++) {
struct Msg *msg = &msgs[i];
if (UDSTimeAfter(UDSMillis(), msg->scheduled_tx_time)) {
diff --git a/release/iso14229.h b/release/iso14229.h
index 6505996..b4fe37a 100644
--- a/release/iso14229.h
+++ b/release/iso14229.h
@@ -81,7 +81,7 @@ typedef SSIZE_T ssize_t;
#include
#include
-#define UDS_TP UDS_TP_ISOTP_C
+#define UDS_TP_ISOTP_C 1
#define UDS_ENABLE_DBG_PRINT 1
#define UDS_ENABLE_ASSERT 1
diff --git a/src/server.c b/src/server.c
index 73d115a..db97c08 100644
--- a/src/server.c
+++ b/src/server.c
@@ -178,7 +178,7 @@ static uint8_t decodeAddressAndLength(UDSReq_t *r, uint8_t *const buf, void **me
assert(r);
assert(memoryAddress);
assert(memorySize);
- long long unsigned int tmp = 0;
+ uintptr_t tmp = 0;
*memoryAddress = 0;
*memorySize = 0;
diff --git a/src/sys_esp32.h b/src/sys_esp32.h
index 39afafa..ccb41e1 100644
--- a/src/sys_esp32.h
+++ b/src/sys_esp32.h
@@ -6,7 +6,7 @@
#include
#include
-#define UDS_TP UDS_TP_ISOTP_C
+#define UDS_TP_ISOTP_C 1
#define UDS_ENABLE_DBG_PRINT 1
#define UDS_ENABLE_ASSERT 1
diff --git a/src/tp/isotp_c_socketcan.c b/src/tp/isotp_c_socketcan.c
index d8d808c..4a569b3 100644
--- a/src/tp/isotp_c_socketcan.c
+++ b/src/tp/isotp_c_socketcan.c
@@ -38,7 +38,7 @@ static int SetupSocketCAN(const char *ifname) {
return sockfd;
}
-uint32_t isotp_user_get_ms() { return UDSMillis(); }
+uint32_t isotp_user_get_ms(void) { return UDSMillis(); }
void isotp_user_debug(const char *message, ...) {
va_list args;
@@ -62,13 +62,6 @@ int isotp_user_send_can(const uint32_t arbitration_id, const uint8_t *data, cons
return ISOTP_RET_OK;
}
-static void printhex(const uint8_t *addr, int len) {
- for (int i = 0; i < len; i++) {
- printf("%02x,", addr[i]);
- }
- printf("\n");
-}
-
static void SocketCANRecv(UDSTpISOTpC_t *tp) {
assert(tp);
struct can_frame frame = {0};
@@ -186,7 +179,7 @@ static ssize_t isotp_c_socketcan_tp_peek(UDSTpHandle_t *hdl, uint8_t **p_buf, UD
}
fprintf(stdout, "%06d, %s recv, 0x%03x (%s), ", UDSMillis(), tp->tag, ta,
ta_type == UDS_A_TA_TYPE_PHYSICAL ? "phys" : "func");
- for (unsigned i = 0; i < ret; i++) {
+ for (int i = 0; i < ret; i++) {
fprintf(stdout, "%02x ", (*p_buf)[i]);
}
fprintf(stdout, "\n");
diff --git a/src/tp/mock.c b/src/tp/mock.c
index 8ee088d..01b7b49 100644
--- a/src/tp/mock.c
+++ b/src/tp/mock.c
@@ -34,7 +34,7 @@ static void LogMsg(const char *prefix, const uint8_t *buf, size_t len, UDSSDU_t
fflush(LogFile); // flush every time in case of crash
}
-static void NetworkPoll() {
+static void NetworkPoll(void) {
for (unsigned i = 0; i < MsgCount; i++) {
struct Msg *msg = &msgs[i];
if (UDSTimeAfter(UDSMillis(), msg->scheduled_tx_time)) {
diff --git a/test/BUILD b/test/BUILD
index 22ff166..75c1723 100644
--- a/test/BUILD
+++ b/test/BUILD
@@ -133,5 +133,10 @@ cc_library(
"-Wno-unused-parameter",
"-Wno-gnu-zero-variadic-macro-arguments",
],
+ defines = [
+ "UDS_TP_ISOTP_C_SOCKETCAN",
+ "UDS_TP_ISOTP_SOCK",
+ "UDS_TP_MOCK",
+ ],
target_compatible_with = ["//platforms/compiler:clang"],
)
diff --git a/test_all.sh b/test_all.sh
new file mode 100755
index 0000000..5509ece
--- /dev/null
+++ b/test_all.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+# Run all the tests that will run on the host machine
+# Note: qemu must be installed, vcan must be set up
+# See test/README.md for more information
+
+bazel test //test:all
+
+##
+## QEMU tests
+##
+
+# ISO-TP linux sockets fail on qemu-arm with the following error:
+# ENOPROTOOPT 92 Protocol not available
+# however, socketcan linux sockets work fine.
+bazel test --config=arm_linux //test:all --test_tag_filters=-isotp_sock
+
+# It seems socketcan is not supported at all on qemu-ppc
+bazel test --config=ppc //test:all --test_tag_filters=-vcan
+bazel test --config=ppc64 //test:all --test_tag_filters=-vcan
+bazel test --config=ppc64le //test:all --test_tag_filters=-vcan
+
+# Test that the ultra strict build works
+bazel build -s --config=x86_64_clang //test:ultra_strict
\ No newline at end of file
From f1b141dc4117db5390921bd70e4a5a459ebea44c Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Wed, 20 Dec 2023 00:23:54 -0700
Subject: [PATCH 37/56] fix bug: zero-initialize tp in isotp_sock.c
---
.gitignore | 3 +++
README.md | 2 +-
examples/{s32k144 => s32k144_server}/.gdbinit | 0
examples/{s32k144 => s32k144_server}/BUILD | 0
examples/{s32k144 => s32k144_server}/README.md | 0
examples/{s32k144 => s32k144_server}/bsp.c | 0
examples/{s32k144 => s32k144_server}/bsp.h | 0
examples/{s32k144 => s32k144_server}/main.c | 0
release.sh | 1 +
release/iso14229.c | 8 +++++---
src/tp/isotp_sock.c | 8 +++++---
11 files changed, 15 insertions(+), 7 deletions(-)
rename examples/{s32k144 => s32k144_server}/.gdbinit (100%)
rename examples/{s32k144 => s32k144_server}/BUILD (100%)
rename examples/{s32k144 => s32k144_server}/README.md (100%)
rename examples/{s32k144 => s32k144_server}/bsp.c (100%)
rename examples/{s32k144 => s32k144_server}/bsp.h (100%)
rename examples/{s32k144 => s32k144_server}/main.c (100%)
diff --git a/.gitignore b/.gitignore
index 9930e37..4014184 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
bazel-*
+bazel-out/k8-fastbuild/bin
.rsync-filter
test_iso14229
client
@@ -14,3 +15,5 @@ fuzzer
**/build
**/sdkconfig*
release/
+examples/**/iso14229.c
+examples/**/iso14229.h
diff --git a/README.md b/README.md
index 9de9484..4ff83d7 100644
--- a/README.md
+++ b/README.md
@@ -24,7 +24,7 @@ API status: **not yet stable**.
- static memory allocation. does not use `malloc`, `calloc`
- easy to integrate. Download `iso14229.c` and `iso14229.h` from the releases page and copy into your source tree.
- highly portable and tested
- - architectures: arm, x86-64, ppc, ppc64
+ - architectures: arm, x86-64, ppc, ppc64, risc
- systems: linux, Windows, esp32, Arduino, NXP s32k
- transports: isotp-c, linux isotp sockets
- cares about security
diff --git a/examples/s32k144/.gdbinit b/examples/s32k144_server/.gdbinit
similarity index 100%
rename from examples/s32k144/.gdbinit
rename to examples/s32k144_server/.gdbinit
diff --git a/examples/s32k144/BUILD b/examples/s32k144_server/BUILD
similarity index 100%
rename from examples/s32k144/BUILD
rename to examples/s32k144_server/BUILD
diff --git a/examples/s32k144/README.md b/examples/s32k144_server/README.md
similarity index 100%
rename from examples/s32k144/README.md
rename to examples/s32k144_server/README.md
diff --git a/examples/s32k144/bsp.c b/examples/s32k144_server/bsp.c
similarity index 100%
rename from examples/s32k144/bsp.c
rename to examples/s32k144_server/bsp.c
diff --git a/examples/s32k144/bsp.h b/examples/s32k144_server/bsp.h
similarity index 100%
rename from examples/s32k144/bsp.h
rename to examples/s32k144_server/bsp.h
diff --git a/examples/s32k144/main.c b/examples/s32k144_server/main.c
similarity index 100%
rename from examples/s32k144/main.c
rename to examples/s32k144_server/main.c
diff --git a/release.sh b/release.sh
index d39eeeb..9c84d02 100755
--- a/release.sh
+++ b/release.sh
@@ -1,4 +1,5 @@
#!/bin/bash
rm -f release/iso14229.c release/iso14229.h
+bazel build //:iso14229.c //:iso14229.h
cp bazel-bin/iso14229.c release/iso14229.c && chmod 644 release/iso14229.c
cp bazel-bin/iso14229.h release/iso14229.h && chmod 644 release/iso14229.h
\ No newline at end of file
diff --git a/release/iso14229.c b/release/iso14229.c
index d870732..32b8808 100644
--- a/release/iso14229.c
+++ b/release/iso14229.c
@@ -2413,9 +2413,9 @@ static ssize_t isotp_sock_tp_peek(UDSTpHandle_t *hdl, uint8_t **p_buf, UDSSDU_t
done:
if (ret > 0) {
impl->recv_len = ret;
- }
- if (info) {
- *info = *msg;
+ if (info) {
+ *info = *msg;
+ }
}
return ret;
}
@@ -2522,6 +2522,7 @@ static int LinuxSockBind(const char *if_name, uint32_t rxid, uint32_t txid, bool
UDSErr_t UDSTpIsoTpSockInitServer(UDSTpIsoTpSock_t *tp, const char *ifname, uint32_t source_addr,
uint32_t target_addr, uint32_t source_addr_func) {
assert(tp);
+ memset(tp, 0, sizeof(*tp));
tp->hdl.peek = isotp_sock_tp_peek;
tp->hdl.send = isotp_sock_tp_send;
tp->hdl.poll = isotp_sock_tp_poll;
@@ -2547,6 +2548,7 @@ UDSErr_t UDSTpIsoTpSockInitServer(UDSTpIsoTpSock_t *tp, const char *ifname, uint
UDSErr_t UDSTpIsoTpSockInitClient(UDSTpIsoTpSock_t *tp, const char *ifname, uint32_t source_addr,
uint32_t target_addr, uint32_t target_addr_func) {
assert(tp);
+ memset(tp, 0, sizeof(*tp));
tp->hdl.peek = isotp_sock_tp_peek;
tp->hdl.send = isotp_sock_tp_send;
tp->hdl.poll = isotp_sock_tp_poll;
diff --git a/src/tp/isotp_sock.c b/src/tp/isotp_sock.c
index 28972b3..fdffa29 100644
--- a/src/tp/isotp_sock.c
+++ b/src/tp/isotp_sock.c
@@ -73,9 +73,9 @@ static ssize_t isotp_sock_tp_peek(UDSTpHandle_t *hdl, uint8_t **p_buf, UDSSDU_t
done:
if (ret > 0) {
impl->recv_len = ret;
- }
- if (info) {
- *info = *msg;
+ if (info) {
+ *info = *msg;
+ }
}
return ret;
}
@@ -182,6 +182,7 @@ static int LinuxSockBind(const char *if_name, uint32_t rxid, uint32_t txid, bool
UDSErr_t UDSTpIsoTpSockInitServer(UDSTpIsoTpSock_t *tp, const char *ifname, uint32_t source_addr,
uint32_t target_addr, uint32_t source_addr_func) {
assert(tp);
+ memset(tp, 0, sizeof(*tp));
tp->hdl.peek = isotp_sock_tp_peek;
tp->hdl.send = isotp_sock_tp_send;
tp->hdl.poll = isotp_sock_tp_poll;
@@ -207,6 +208,7 @@ UDSErr_t UDSTpIsoTpSockInitServer(UDSTpIsoTpSock_t *tp, const char *ifname, uint
UDSErr_t UDSTpIsoTpSockInitClient(UDSTpIsoTpSock_t *tp, const char *ifname, uint32_t source_addr,
uint32_t target_addr, uint32_t target_addr_func) {
assert(tp);
+ memset(tp, 0, sizeof(*tp));
tp->hdl.peek = isotp_sock_tp_peek;
tp->hdl.send = isotp_sock_tp_send;
tp->hdl.poll = isotp_sock_tp_poll;
From 57230354b0b6d97c1b95349149e9c650addbd01f Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Wed, 20 Dec 2023 00:45:26 -0700
Subject: [PATCH 38/56] fix brute force protection initialization bugs
---
release/iso14229.c | 5 ++++-
release/iso14229.h | 16 +++++++++-------
src/server.c | 4 +++-
src/server.h | 6 ++++--
4 files changed, 20 insertions(+), 11 deletions(-)
diff --git a/release/iso14229.c b/release/iso14229.c
index 32b8808..6a0a16f 100644
--- a/release/iso14229.c
+++ b/release/iso14229.c
@@ -1123,7 +1123,7 @@ static uint8_t _0x27_SecurityAccess(UDSServer_t *srv, UDSReq_t *r) {
return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
}
- if (!UDSTimeAfter(UDSMillis(), UDS_SERVER_0x27_BRUTE_FORCE_MITIGATION_BOOT_DELAY_MS)) {
+ if (!UDSTimeAfter(UDSMillis(), srv->sec_access_boot_delay_timer)) {
return NegativeResponse(r, kRequiredTimeDelayNotExpired);
}
@@ -1722,6 +1722,9 @@ UDSErr_t UDSServerInit(UDSServer_t *srv) {
srv->sessionType = kDefaultSession;
srv->p2_timer = UDSMillis() + srv->p2_ms;
srv->s3_session_timeout_timer = UDSMillis() + srv->s3_ms;
+ srv->sec_access_boot_delay_timer =
+ UDSMillis() + UDS_SERVER_0x27_BRUTE_FORCE_MITIGATION_BOOT_DELAY_MS;
+ srv->sec_access_auth_fail_timer = UDSMillis();
return UDS_OK;
}
diff --git a/release/iso14229.h b/release/iso14229.h
index b4fe37a..df13472 100644
--- a/release/iso14229.h
+++ b/release/iso14229.h
@@ -687,13 +687,15 @@ typedef struct UDSServer {
// server for the activated diagnostic session.
uint16_t s3_ms; // Session timeout
- uint8_t ecuResetScheduled; // nonzero indicates that an ECUReset has been scheduled
- uint32_t ecuResetTimer; // for delaying resetting until a response
- // has been sent to the client
- uint32_t p2_timer; // for rate limiting server responses
- uint32_t s3_session_timeout_timer; // indicates that diagnostic session has timed out
- uint32_t
- sec_access_auth_fail_timer; // brute-force hardening: rate limit security access requests
+ uint8_t ecuResetScheduled; // nonzero indicates that an ECUReset has been scheduled
+ uint32_t ecuResetTimer; // for delaying resetting until a response
+ // has been sent to the client
+ uint32_t p2_timer; // for rate limiting server responses
+ uint32_t s3_session_timeout_timer; // indicates that diagnostic session has timed out
+ uint32_t sec_access_auth_fail_timer; // brute-force hardening: rate limit security access
+ // requests
+ uint32_t sec_access_boot_delay_timer; // brute-force hardening: restrict security access until
+ // timer expires
/**
* @brief UDS-1-2013: Table 407 - 0x36 TransferData Supported negative
diff --git a/src/server.c b/src/server.c
index db97c08..5d89818 100644
--- a/src/server.c
+++ b/src/server.c
@@ -258,7 +258,7 @@ static uint8_t _0x27_SecurityAccess(UDSServer_t *srv, UDSReq_t *r) {
return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
}
- if (!UDSTimeAfter(UDSMillis(), UDS_SERVER_0x27_BRUTE_FORCE_MITIGATION_BOOT_DELAY_MS)) {
+ if (!UDSTimeAfter(UDSMillis(), srv->sec_access_boot_delay_timer)) {
return NegativeResponse(r, kRequiredTimeDelayNotExpired);
}
@@ -857,6 +857,8 @@ UDSErr_t UDSServerInit(UDSServer_t *srv) {
srv->sessionType = kDefaultSession;
srv->p2_timer = UDSMillis() + srv->p2_ms;
srv->s3_session_timeout_timer = UDSMillis() + srv->s3_ms;
+ srv->sec_access_boot_delay_timer = UDSMillis() + UDS_SERVER_0x27_BRUTE_FORCE_MITIGATION_BOOT_DELAY_MS;
+ srv->sec_access_auth_fail_timer = UDSMillis();
return UDS_OK;
}
diff --git a/src/server.h b/src/server.h
index c54b378..4b35788 100644
--- a/src/server.h
+++ b/src/server.h
@@ -34,8 +34,10 @@ typedef struct UDSServer {
// has been sent to the client
uint32_t p2_timer; // for rate limiting server responses
uint32_t s3_session_timeout_timer; // indicates that diagnostic session has timed out
- uint32_t
- sec_access_auth_fail_timer; // brute-force hardening: rate limit security access requests
+ uint32_t sec_access_auth_fail_timer; // brute-force hardening: rate limit security access
+ // requests
+ uint32_t sec_access_boot_delay_timer; // brute-force hardening: restrict security access until
+ // timer expires
/**
* @brief UDS-1-2013: Table 407 - 0x36 TransferData Supported negative
From 86c93e8bbf7a58d1612a922417965cae8c3bbe61 Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Wed, 20 Dec 2023 22:22:57 -0700
Subject: [PATCH 39/56] add attempt at Martin Thompson 0x27 implementation
---
.gitignore | 2 +
examples/linux_server/Makefile | 10 ++
examples/linux_server/main.c | 63 ++++++++++
examples/linux_server_0x27/Makefile | 24 ++++
examples/linux_server_0x27/README.md | 11 ++
examples/linux_server_0x27/client.c | 181 +++++++++++++++++++++++++++
examples/linux_server_0x27/server.c | 128 +++++++++++++++++++
src/server.c | 3 +-
src/server.h | 16 +--
9 files changed, 429 insertions(+), 9 deletions(-)
create mode 100644 examples/linux_server/Makefile
create mode 100644 examples/linux_server/main.c
create mode 100644 examples/linux_server_0x27/Makefile
create mode 100644 examples/linux_server_0x27/README.md
create mode 100644 examples/linux_server_0x27/client.c
create mode 100644 examples/linux_server_0x27/server.c
diff --git a/.gitignore b/.gitignore
index 4014184..ceb3ac1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,3 +17,5 @@ fuzzer
release/
examples/**/iso14229.c
examples/**/iso14229.h
+*.pem
+*.der
diff --git a/examples/linux_server/Makefile b/examples/linux_server/Makefile
new file mode 100644
index 0000000..10db91c
--- /dev/null
+++ b/examples/linux_server/Makefile
@@ -0,0 +1,10 @@
+SRCS += iso14229.c main.c
+HDRS += iso14229.h
+TARGET = server
+CFLAGS = -DUDS_TP_ISOTP_SOCK=1 -g
+
+all: $(SRCS) $(HDRS)
+ $(CC) $(CFLAGS) $(SRCS) -o $(TARGET)
+
+clean:
+ rm -f $(TARGET)
diff --git a/examples/linux_server/main.c b/examples/linux_server/main.c
new file mode 100644
index 0000000..c8182f4
--- /dev/null
+++ b/examples/linux_server/main.c
@@ -0,0 +1,63 @@
+#include "iso14229.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+static UDSServer_t srv;
+static UDSTpIsoTpSock_t tp;
+static bool done = false;
+
+void sigint_handler(int signum) {
+ printf("SIGINT received\n");
+ done = true;
+}
+
+static uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
+ switch (ev) {
+ default:
+ printf("Unhandled event: %d\n", ev);
+ return kServiceNotSupported;
+ }
+}
+
+static int sleep_ms(uint32_t tms) {
+ struct timespec ts;
+ int ret;
+ ts.tv_sec = tms / 1000;
+ ts.tv_nsec = (tms % 1000) * 1000000;
+ do {
+ ret = nanosleep(&ts, &ts);
+ } while (ret && errno == EINTR);
+ return ret;
+}
+
+int main(int ac, char **av) {
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = sigint_handler;
+ sigaction(SIGINT, &sa, NULL);
+
+ if (UDSTpIsoTpSockInitServer(&tp, "vcan0", 0x7E0, 0x7E8, 0x7DF)) {
+ fprintf(stderr, "UDSTpIsoTpSockInitServer failed\n");
+ exit(-1);
+ }
+
+ if (UDSServerInit(&srv)) {
+ fprintf(stderr, "UDSServerInit failed\n");
+ }
+
+ srv.tp = (UDSTpHandle_t *)&tp;
+ srv.fn = fn;
+
+ printf("server up, polling . . .\n");
+ while (!done) {
+ UDSServerPoll(&srv);
+ sleep_ms(1);
+ }
+ printf("server exiting\n");
+ return 0;
+}
diff --git a/examples/linux_server_0x27/Makefile b/examples/linux_server_0x27/Makefile
new file mode 100644
index 0000000..35fb955
--- /dev/null
+++ b/examples/linux_server_0x27/Makefile
@@ -0,0 +1,24 @@
+SRCS += iso14229.c
+HDRS += iso14229.h
+TARGETS = server client
+CFLAGS = -DUDS_TP_ISOTP_SOCK -DUDS_LINES -g
+MBEDTLS ?= /usr/local
+LDFLAGS = -L$(MBEDTLS)/lib -lmbedtls -lmbedcrypto -lmbedx509
+
+
+all: $(TARGETS) private_key.pem public_key.pem
+
+server: $(SRCS) $(HDRS) server.c Makefile
+ $(CC) $(CFLAGS) $(SRCS) server.c $(LDFLAGS) -o server
+
+client: $(SRCS) $(HDRS) client.c Makefile
+ $(CC) $(CFLAGS) $(SRCS) client.c $(LDFLAGS) -o client
+
+private_key.pem:
+ openssl genrsa -out private_key.pem 4096
+
+public_key.pem: private_key.pem
+ openssl rsa -in private_key.pem -pubout -outform PEM -out public_key.pem
+
+clean:
+ rm -f $(TARGETS) private_key.pem public_key.pem
diff --git a/examples/linux_server_0x27/README.md b/examples/linux_server_0x27/README.md
new file mode 100644
index 0000000..86dbd45
--- /dev/null
+++ b/examples/linux_server_0x27/README.md
@@ -0,0 +1,11 @@
+
+
+To compile the client you may need `libssl-dev`
+
+```sh
+openssl genpkey -algorithm RSA -out private_key.pem
+openssl rsa -pubout -in private_key.pem -out public_key.pem
+openssl rsa -pubout -in private_key.pem -outform DER -out public_key.der
+```
+
+https://github.com/amosnier/sha-2/
\ No newline at end of file
diff --git a/examples/linux_server_0x27/client.c b/examples/linux_server_0x27/client.c
new file mode 100644
index 0000000..582f59c
--- /dev/null
+++ b/examples/linux_server_0x27/client.c
@@ -0,0 +1,181 @@
+#include "iso14229.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+static UDSSeqState_t sendHardReset(UDSClient_t *client) {
+ uint8_t resetType = kHardReset;
+ printf("%s: sending ECU reset type: %d\n", __func__, resetType);
+ UDSSendECUReset(client, resetType);
+ return UDSSeqStateGotoNext;
+}
+
+static UDSSeqState_t awaitPositiveResponse(UDSClient_t *client) {
+ if (client->err) {
+ return client->err;
+ }
+ if (kRequestStateIdle == client->state) {
+ printf("got positive response\n");
+ return UDSSeqStateGotoNext;
+ } else {
+ return UDSSeqStateRunning;
+ }
+}
+
+static UDSSeqState_t awaitResponse(UDSClient_t *client) {
+ if (kRequestStateIdle == client->state) {
+ printf("got response\n");
+ return UDSSeqStateGotoNext;
+ } else {
+ return UDSSeqStateRunning;
+ }
+}
+
+static UDSSeqState_t requestSomeData(UDSClient_t *client) {
+ printf("%s: calling ReadDataByIdentifier\n", __func__);
+ static const uint16_t didList[] = {0x0001, 0x0008};
+ UDSSendRDBI(client, didList, 2);
+ return UDSSeqStateGotoNext;
+}
+
+
+static int SleepMillis(uint32_t tms) {
+ struct timespec ts;
+ int ret;
+ ts.tv_sec = tms / 1000;
+ ts.tv_nsec = (tms % 1000) * 1000000;
+ do {
+ ret = nanosleep(&ts, &ts);
+ } while (ret && errno == EINTR);
+ return ret;
+}
+
+int sign(const uint8_t *seed, size_t seed_len, uint8_t* key, size_t key_len) {
+ int ret = 0;
+ mbedtls_pk_context pk;
+ mbedtls_entropy_context entropy;
+ mbedtls_ctr_drbg_context ctr_drbg;
+ mbedtls_entropy_init(&entropy);
+ mbedtls_ctr_drbg_init(&ctr_drbg);
+ const char *pers = "rsa_sign";
+ mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *)pers, strlen(pers));
+
+ mbedtls_pk_init(&pk);
+
+ // Load your RSA private key
+ const char *private_key_pem = "private_key.pem";
+
+ if (mbedtls_pk_parse_keyfile(&pk, private_key_pem, NULL) != 0) {
+ mbedtls_printf("Failed to parse private key\n");
+ ret = -1;
+ goto exit;
+ }
+
+ // Verify that the loaded key is an RSA key
+ if (mbedtls_pk_get_type(&pk) != MBEDTLS_PK_RSA) {
+ mbedtls_printf("Loaded key is not an RSA key\n");
+ ret = -1;
+ goto exit;
+ }
+
+ mbedtls_rsa_context *rsa = mbedtls_pk_rsa(pk);
+
+ // // Allocate buffer for the signature
+ size_t sig_len = mbedtls_rsa_get_len(rsa);
+ if (sig_len != key_len) {
+ fprintf(stderr, "sig_len: %ld != %ld\n", sig_len, sizeof(key));
+ ret = -1;
+ goto exit;
+ }
+
+ // Perform RSA signing operation
+ if (mbedtls_rsa_rsassa_pkcs1_v15_sign(rsa, mbedtls_ctr_drbg_random, &ctr_drbg, MBEDTLS_RSA_PRIVATE,
+ MBEDTLS_MD_SHA256, seed_len, seed, key) != 0) {
+ mbedtls_printf("Failed to sign data\n");
+ ret = -1;
+ goto exit;
+ }
+
+ // 'key' now contains the RSA signature
+
+ exit:
+ mbedtls_rsa_free(rsa);
+ mbedtls_ctr_drbg_free(&ctr_drbg);
+ mbedtls_entropy_free(&entropy);
+ return ret;
+}
+
+
+int main(int ac, char **av) {
+ UDSClient_t client;
+ UDSTpIsoTpSock_t tp;
+ UDSErr_t err = 0;
+
+ if (UDSTpIsoTpSockInitClient(&tp, "vcan0", 0x7E8, 0x7E0, 0x7DF)) {
+ fprintf(stderr, "UDSTpIsoTpSockInitClient failed\n");
+ exit(-1);
+ }
+
+ if (UDSClientInit(&client)) {
+ exit(-1);
+ }
+
+ client.tp = (UDSTpHandle_t *)&tp;
+
+ // Request seed
+ err = UDSSendSecurityAccess(&client, 3, NULL, 0);
+ if (err) {
+ fprintf(stderr, "UDSSendSecurityAccess failed: %d\n", err);
+ exit(-1);
+ }
+
+ while (UDSClientPoll(&client));
+
+ if (client.err) {
+ fprintf(stderr, "UDSSendSecurityAccess failed: %d\n", client.err);
+ exit(-1);
+ }
+
+ struct SecurityAccessResponse sar = {0};
+ err = UDSUnpackSecurityAccessResponse(&client, &sar);
+ if (err) {
+ fprintf(stderr, "UDSUnpackSecurityAccessResponse failed: %d\n", err);
+ exit(-1);
+ }
+
+ printf("seed: ");
+ for (int i = 0; i < sar.securitySeedLength; i++) {
+ printf("%02X ", sar.securitySeed[i]);
+ }
+
+ uint8_t key[512] = {0};
+
+ if (sign(sar.securitySeed, sar.securitySeedLength, key, sizeof(key))) {
+ fprintf(stderr, "sign failed\n");
+ exit(-1);
+ }
+
+
+ err = UDSSendSecurityAccess(&client, 4, key, sizeof(key));
+ if (err) {
+ fprintf(stderr, "UDSSendSecurityAccess failed: %d\n", err);
+ exit(-1);
+ }
+
+ while (UDSClientPoll(&client));
+
+
+ return 0;
+}
diff --git a/examples/linux_server_0x27/server.c b/examples/linux_server_0x27/server.c
new file mode 100644
index 0000000..dd52e91
--- /dev/null
+++ b/examples/linux_server_0x27/server.c
@@ -0,0 +1,128 @@
+#include "iso14229.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+static UDSServer_t srv;
+static UDSTpIsoTpSock_t tp;
+static bool done = false;
+static uint8_t seed[32] = {0};
+
+void sigint_handler(int signum) {
+ printf("SIGINT received\n");
+ done = true;
+}
+
+int rsa_verify(const uint8_t *key, size_t key_len, bool *valid) {
+ int ret = 0;
+ mbedtls_pk_context pk;
+ const char *pubkey = "public_key.pem";
+ mbedtls_pk_init(&pk);
+
+ if ((ret = mbedtls_pk_parse_public_keyfile(&pk, pubkey) != 0)) {
+ mbedtls_printf(" failed\n ! Could not read key from '%s'\n", pubkey);
+ mbedtls_printf(" ! mbedtls_pk_parse_public_keyfile returned %d\n\n", ret);
+ goto exit;
+ }
+
+ if ((ret = mbedtls_pk_verify(&pk, MBEDTLS_MD_SHA256, seed, sizeof(seed),
+ key, key_len)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_pk_verify returned %d\n\n", ret);
+ goto exit;
+ }
+
+ exit:
+ *valid = (ret == 0);
+ // print the mbedtls error code
+ if (ret != 0) {
+ char buf[128];
+ mbedtls_strerror(ret, buf, sizeof(buf));
+ printf("mbedtls error: %s\n", buf);
+ }
+ return ret;
+}
+
+static uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
+ switch (ev) {
+ case UDS_SRV_EVT_SecAccessRequestSeed: {
+ UDSSecAccessRequestSeedArgs_t *req = (UDSSecAccessRequestSeedArgs_t *)arg;
+ // use urandom to generate a random seed
+ FILE *f = fopen("/dev/urandom", "r");
+ if (!f) {
+ fprintf(stderr, "Failed to open /dev/urandom\n");
+ return kGeneralReject;
+ }
+ fread(seed, sizeof(seed), 1, f);
+ fclose(f);
+ return req->copySeed(srv, seed, sizeof(seed));
+ }
+ case UDS_SRV_EVT_SecAccessValidateKey: {
+ UDSSecAccessValidateKeyArgs_t *req = (UDSSecAccessValidateKeyArgs_t *)arg;
+ bool valid = false;
+
+ if (0 != rsa_verify(req->key, req->len, &valid)) {
+ printf("rsa_verify failed\n");
+ return kGeneralReject;
+ } else {
+ if (valid) {
+ printf("Security level %d unlocked\n", req->level);
+ return kPositiveResponse;
+ } else {
+ return kSecurityAccessDenied;
+ }
+ }
+ }
+ default:
+ printf("Unhandled event: %d\n", ev);
+ return kServiceNotSupported;
+ }
+}
+
+static int sleep_ms(uint32_t tms) {
+ struct timespec ts;
+ int ret;
+ ts.tv_sec = tms / 1000;
+ ts.tv_nsec = (tms % 1000) * 1000000;
+ do {
+ ret = nanosleep(&ts, &ts);
+ } while (ret && errno == EINTR);
+ return ret;
+}
+
+int main(int ac, char **av) {
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = sigint_handler;
+ sigaction(SIGINT, &sa, NULL);
+
+ if (UDSTpIsoTpSockInitServer(&tp, "vcan0", 0x7E0, 0x7E8, 0x7DF)) {
+ fprintf(stderr, "UDSTpIsoTpSockInitServer failed\n");
+ exit(-1);
+ }
+
+ if (UDSServerInit(&srv)) {
+ fprintf(stderr, "UDSServerInit failed\n");
+ }
+
+ srv.tp = (UDSTpHandle_t *)&tp;
+ srv.fn = fn;
+
+ printf("server up, polling . . .\n");
+ while (!done) {
+ UDSServerPoll(&srv);
+ sleep_ms(1);
+ }
+ printf("server exiting\n");
+ return 0;
+}
diff --git a/src/server.c b/src/server.c
index 5d89818..6a959cd 100644
--- a/src/server.c
+++ b/src/server.c
@@ -857,7 +857,8 @@ UDSErr_t UDSServerInit(UDSServer_t *srv) {
srv->sessionType = kDefaultSession;
srv->p2_timer = UDSMillis() + srv->p2_ms;
srv->s3_session_timeout_timer = UDSMillis() + srv->s3_ms;
- srv->sec_access_boot_delay_timer = UDSMillis() + UDS_SERVER_0x27_BRUTE_FORCE_MITIGATION_BOOT_DELAY_MS;
+ srv->sec_access_boot_delay_timer =
+ UDSMillis() + UDS_SERVER_0x27_BRUTE_FORCE_MITIGATION_BOOT_DELAY_MS;
srv->sec_access_auth_fail_timer = UDSMillis();
return UDS_OK;
}
diff --git a/src/server.h b/src/server.h
index 4b35788..e1e57da 100644
--- a/src/server.h
+++ b/src/server.h
@@ -29,14 +29,14 @@ typedef struct UDSServer {
// server for the activated diagnostic session.
uint16_t s3_ms; // Session timeout
- uint8_t ecuResetScheduled; // nonzero indicates that an ECUReset has been scheduled
- uint32_t ecuResetTimer; // for delaying resetting until a response
- // has been sent to the client
- uint32_t p2_timer; // for rate limiting server responses
- uint32_t s3_session_timeout_timer; // indicates that diagnostic session has timed out
- uint32_t sec_access_auth_fail_timer; // brute-force hardening: rate limit security access
- // requests
- uint32_t sec_access_boot_delay_timer; // brute-force hardening: restrict security access until
+ uint8_t ecuResetScheduled; // nonzero indicates that an ECUReset has been scheduled
+ uint32_t ecuResetTimer; // for delaying resetting until a response
+ // has been sent to the client
+ uint32_t p2_timer; // for rate limiting server responses
+ uint32_t s3_session_timeout_timer; // indicates that diagnostic session has timed out
+ uint32_t sec_access_auth_fail_timer; // brute-force hardening: rate limit security access
+ // requests
+ uint32_t sec_access_boot_delay_timer; // brute-force hardening: restrict security access until
// timer expires
/**
From 8a785e77710b5d2792c2ad100f1da23f4fe46ee8 Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Wed, 20 Dec 2023 22:33:26 -0700
Subject: [PATCH 40/56] update readme for 0x27 example
---
examples/linux_server_0x27/README.md | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/examples/linux_server_0x27/README.md b/examples/linux_server_0x27/README.md
index 86dbd45..a8279e2 100644
--- a/examples/linux_server_0x27/README.md
+++ b/examples/linux_server_0x27/README.md
@@ -1,11 +1,11 @@
+```sh
+apt install libmbedtls-dev
+sudo ip link add name vcan0 type vcan
+sudo ip link set vcan0 up
+make
-To compile the client you may need `libssl-dev`
+./server
-```sh
-openssl genpkey -algorithm RSA -out private_key.pem
-openssl rsa -pubout -in private_key.pem -out public_key.pem
-openssl rsa -pubout -in private_key.pem -outform DER -out public_key.der
+./client
```
-
-https://github.com/amosnier/sha-2/
\ No newline at end of file
From d10ab940883ddd8ddd5d41fb8e1f2bed22456ec3 Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Thu, 21 Dec 2023 13:05:36 -0700
Subject: [PATCH 41/56] tidy linux_server_0x27 example client code
---
README.md | 26 ++++++++++----------
examples/linux_server_0x27/README.md | 6 +++++
examples/linux_server_0x27/client.c | 36 ----------------------------
3 files changed, 19 insertions(+), 49 deletions(-)
diff --git a/README.md b/README.md
index 4ff83d7..c64e83e 100644
--- a/README.md
+++ b/README.md
@@ -13,32 +13,32 @@ iso14229 is an implementation of UDS (ISO14229-1:2013) targeting embedded system
API status: **not yet stable**.
-
-## Quick Start
+## Quickstart
1. Get `iso14229.c` and `iso14229.h` from the [release](./release) directory, copy into your source tree and build.
2. See [examples](./examples).
-## Features
+## Building
-- static memory allocation. does not use `malloc`, `calloc`
-- easy to integrate. Download `iso14229.c` and `iso14229.h` from the releases page and copy into your source tree.
-- highly portable and tested
- - architectures: arm, x86-64, ppc, ppc64, risc
- - systems: linux, Windows, esp32, Arduino, NXP s32k
- - transports: isotp-c, linux isotp sockets
-- cares about security
- - server has fuzz test, see [test/README.md](test/README.md)
- -
+iso14229 uses bazel internally. You do not need bazel to use this library.
## Preprocessor Defines
| Define | Description | Valid values |
| - | - | - |
+| `UDS_TP` | Enable a transport layer | see `tp.h` |
| `UDS_SYS` | Select a porting target | see `sys.h` |
-| `UDS_TP` | Select a transport layer | see `tp.h` |
| `UDS_...` | Additional compile-time config options | see `config.h` |
+## Features
+
+- static memory allocation. does not use `malloc`, `calloc`
+- easy to integrate. Download `iso14229.c` and `iso14229.h` from the releases page and copy into your source tree.
+- highly portable and tested
+ - architectures: arm, x86-64, ppc, ppc64, risc
+ - systems: linux, Windows, esp32, Arduino, NXP s32k
+ - transports: isotp-c, linux isotp sockets
+
## supported functions (server and client )
| SID | name | supported |
diff --git a/examples/linux_server_0x27/README.md b/examples/linux_server_0x27/README.md
index a8279e2..9be7f8f 100644
--- a/examples/linux_server_0x27/README.md
+++ b/examples/linux_server_0x27/README.md
@@ -1,3 +1,5 @@
+# Running the example
+
```sh
apt install libmbedtls-dev
sudo ip link add name vcan0 type vcan
@@ -9,3 +11,7 @@ make
./client
```
+
+# Known issues
+
+- auth only works once
\ No newline at end of file
diff --git a/examples/linux_server_0x27/client.c b/examples/linux_server_0x27/client.c
index 582f59c..96d8eb8 100644
--- a/examples/linux_server_0x27/client.c
+++ b/examples/linux_server_0x27/client.c
@@ -15,41 +15,6 @@
#include
#include
-static UDSSeqState_t sendHardReset(UDSClient_t *client) {
- uint8_t resetType = kHardReset;
- printf("%s: sending ECU reset type: %d\n", __func__, resetType);
- UDSSendECUReset(client, resetType);
- return UDSSeqStateGotoNext;
-}
-
-static UDSSeqState_t awaitPositiveResponse(UDSClient_t *client) {
- if (client->err) {
- return client->err;
- }
- if (kRequestStateIdle == client->state) {
- printf("got positive response\n");
- return UDSSeqStateGotoNext;
- } else {
- return UDSSeqStateRunning;
- }
-}
-
-static UDSSeqState_t awaitResponse(UDSClient_t *client) {
- if (kRequestStateIdle == client->state) {
- printf("got response\n");
- return UDSSeqStateGotoNext;
- } else {
- return UDSSeqStateRunning;
- }
-}
-
-static UDSSeqState_t requestSomeData(UDSClient_t *client) {
- printf("%s: calling ReadDataByIdentifier\n", __func__);
- static const uint16_t didList[] = {0x0001, 0x0008};
- UDSSendRDBI(client, didList, 2);
- return UDSSeqStateGotoNext;
-}
-
static int SleepMillis(uint32_t tms) {
struct timespec ts;
@@ -74,7 +39,6 @@ int sign(const uint8_t *seed, size_t seed_len, uint8_t* key, size_t key_len) {
mbedtls_pk_init(&pk);
- // Load your RSA private key
const char *private_key_pem = "private_key.pem";
if (mbedtls_pk_parse_keyfile(&pk, private_key_pem, NULL) != 0) {
From 5dee99213bfccaa2a07fb6527402069ee81aec83 Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Thu, 21 Dec 2023 13:19:50 -0700
Subject: [PATCH 42/56] update linux_server_0x27 readme
---
examples/linux_server_0x27/README.md | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/examples/linux_server_0x27/README.md b/examples/linux_server_0x27/README.md
index 9be7f8f..85f7bdc 100644
--- a/examples/linux_server_0x27/README.md
+++ b/examples/linux_server_0x27/README.md
@@ -14,4 +14,8 @@ make
# Known issues
-- auth only works once
\ No newline at end of file
+- auth only works once
+
+# Todo
+
+- implement multiple security levels
\ No newline at end of file
From 7e63e381b7de18879ef368e041b9eb7806ecd33c Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Sat, 23 Dec 2023 12:39:22 -0700
Subject: [PATCH 43/56] add acknowledgement to linux_server_0x27 readme
---
examples/linux_server_0x27/README.md | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/examples/linux_server_0x27/README.md b/examples/linux_server_0x27/README.md
index 85f7bdc..c4a1dac 100644
--- a/examples/linux_server_0x27/README.md
+++ b/examples/linux_server_0x27/README.md
@@ -18,4 +18,8 @@ make
# Todo
-- implement multiple security levels
\ No newline at end of file
+- implement multiple security levels
+
+# Acknowledgement
+
+This example is based on Martin Thompson's paper "UDS Security Access for Constraint ECUs" https://doi.org/10.4271/2022-01-0132
\ No newline at end of file
From a68b7e80a542f7e8d7fb14b689adecdcbfe8fce6 Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Sat, 23 Dec 2023 13:04:52 -0700
Subject: [PATCH 44/56] add check for already unlocked
---
examples/linux_server_0x27/README.md | 8 --------
examples/linux_server_0x27/client.c | 15 +++++++++++++++
2 files changed, 15 insertions(+), 8 deletions(-)
diff --git a/examples/linux_server_0x27/README.md b/examples/linux_server_0x27/README.md
index c4a1dac..c8d9ece 100644
--- a/examples/linux_server_0x27/README.md
+++ b/examples/linux_server_0x27/README.md
@@ -12,14 +12,6 @@ make
./client
```
-# Known issues
-
-- auth only works once
-
-# Todo
-
-- implement multiple security levels
-
# Acknowledgement
This example is based on Martin Thompson's paper "UDS Security Access for Constraint ECUs" https://doi.org/10.4271/2022-01-0132
\ No newline at end of file
diff --git a/examples/linux_server_0x27/client.c b/examples/linux_server_0x27/client.c
index 96d8eb8..d3e8eed 100644
--- a/examples/linux_server_0x27/client.c
+++ b/examples/linux_server_0x27/client.c
@@ -123,6 +123,21 @@ int main(int ac, char **av) {
for (int i = 0; i < sar.securitySeedLength; i++) {
printf("%02X ", sar.securitySeed[i]);
}
+
+ // Check if all bytes in the seed are 0
+ bool all_zero = true;
+ for (int i = 0; i < sar.securitySeedLength; i++) {
+ if (sar.securitySeed[i] != 0) {
+ all_zero = false;
+ break;
+ }
+ }
+
+ if (all_zero) {
+ fprintf(stderr, "seed is all zero, already unlocked\n");
+ return 0;
+ }
+
uint8_t key[512] = {0};
From 1165c47c5d36c0c0a67bf390c8ae102ee2cbd62b Mon Sep 17 00:00:00 2001
From: Nick James Kirkby <20824939+driftregion@users.noreply.github.com>
Date: Sun, 21 Jan 2024 10:07:39 -0700
Subject: [PATCH 45/56] add amalgamate script. fix tests
---
BUILD | 58 +-
Makefile | 19 +-
amalgamate.py | 109 +
examples/BUILD | 0
examples/README.md | 65 -
examples/client.c | 143 -
examples/client.py | 106 -
examples/requirements.txt | 3 -
examples/server.c | 176 --
examples/server_minimal/BUILD | 10 -
examples/server_minimal/main.c | 70 -
examples/uds_params.h | 44 -
release.sh | 5 -
release/iso14229.c | 3373 -----------------------
release/iso14229.h | 1387 ----------
src/iso14229serverbufferedwriter.h | 114 -
test/BUILD | 2 +-
test/test_server_0x27_security_access.c | 4 +-
test_iso14229serverbufferedwriter.c | 124 -
19 files changed, 142 insertions(+), 5670 deletions(-)
create mode 100644 amalgamate.py
delete mode 100644 examples/BUILD
delete mode 100644 examples/README.md
delete mode 100644 examples/client.c
delete mode 100755 examples/client.py
delete mode 100644 examples/requirements.txt
delete mode 100644 examples/server.c
delete mode 100644 examples/server_minimal/BUILD
delete mode 100644 examples/server_minimal/main.c
delete mode 100644 examples/uds_params.h
delete mode 100755 release.sh
delete mode 100644 release/iso14229.c
delete mode 100644 release/iso14229.h
delete mode 100644 src/iso14229serverbufferedwriter.h
delete mode 100644 test_iso14229serverbufferedwriter.c
diff --git a/BUILD b/BUILD
index 33c78ef..ea7bc99 100644
--- a/BUILD
+++ b/BUILD
@@ -1,37 +1,5 @@
-package(default_visibility = ["//visibility:public"])
load("@hedron_compile_commands//:refresh_compile_commands.bzl", "refresh_compile_commands")
-
-genrule(
- name = "isotp_c_wrapped_c",
- srcs = glob(["src/tp/isotp-c/*.c"]),
- outs = ["isotp_c_wrapped.c"],
- cmd = "echo '#if defined(UDS_ISOTP_C)' >> $(OUTS) ; for f in $(SRCS); do cat $$f >> $(OUTS); done ; echo '#endif' >> $(OUTS)",
-)
-
-genrule(
- name = "isotp_c_wrapped_h",
- srcs = glob(["src/tp/isotp-c/*.h"]),
- outs = ["isotp_c_wrapped.h"],
- cmd = "echo '#if defined(UDS_ISOTP_C)' >> $(OUTS) ; for f in $(SRCS); do cat $$f >> $(OUTS); done ; echo '#endif' >> $(OUTS)",
-)
-
-genrule(
- name = "c_src",
- srcs = glob(["src/*.c", "src/tp/*.c"]) + [
- ":isotp_c_wrapped.c",
- ],
- outs = ["iso14229.c"],
- cmd = "(echo '#include \"iso14229.h\"'; (for f in $(SRCS); do echo; echo '#ifdef UDS_LINES'; echo \"#line 1 \\\"$$f\"\\\"; echo '#endif'; cat $$f | sed -e 's,#include \".*,,'; done)) > $(OUTS)",
-)
-
-genrule(
- name = "h_src",
- srcs = glob(["src/*.h", "src/tp/*.h"]) + [
- ":isotp_c_wrapped.h",
- ],
- outs = ["iso14229.h"],
- cmd = "(cat ; echo '#ifndef ISO14229_H'; echo '#define ISO14229_H'; echo; echo '#ifdef __cplusplus'; echo 'extern \"C\" {'; echo '#endif'; cat src/version.h src/sys.h src/sys_arduino.h src/sys_unix.h src/sys_win32.h src/sys_esp32.h src/config.h src/util.h src/tp.h src/uds.h src/client.h src/server.h $(location //:isotp_c_wrapped.h) src/tp/*.h |sed -e 's,#include \".*,,' -e 's,^#pragma once,,' ; echo '#endif'; echo '#ifdef __cplusplus'; echo '}'; echo '#endif';) > $(OUTS)",
-)
+package(default_visibility = ["//visibility:public"])
filegroup(
name = "srcs",
@@ -49,26 +17,28 @@ cc_library(
],
)
-cc_test(
- name = "test_bufferedwriter",
- srcs = [
- "iso14229serverbufferedwriter.h",
- "test_iso14229serverbufferedwriter.c",
- ],
- size = "small",
-)
-
-
cc_library(
name="iso14229_2",
srcs=glob(["src/**/*.c", "src/**/*.h"]),
copts=['-Isrc'],
)
-
refresh_compile_commands(
name = "s32k_refresh_compile_commands",
targets = {
"//examples/s32k144/...": "--config=s32k",
}
)
+
+py_binary(
+ name="amalgamate",
+ srcs=["amalgamate.py"],
+)
+
+genrule(
+ name="amalgamated",
+ srcs=glob(["src/**/*.c", "src/**/*.h"]),
+ outs=["iso14229.c", "iso14229.h"],
+ cmd="$(location //:amalgamate) --out_c $(location //:iso14229.c) --out_h $(location //:iso14229.h) $(SRCS)",
+ tools=["//:amalgamate"],
+)
diff --git a/Makefile b/Makefile
index 0cea42d..6786f80 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,20 @@
-iso14229.c iso14229.h:
- mkdir -p build && bazel build //:iso14229.h //:iso14229.c && cp bazel-bin/iso14229.h bazel-bin/iso14229.c build/
+all: iso14229.c iso14229.h
+ mkdir -p release
+ cp iso14229.c iso14229.h release/
clean:
- rm -rf build
+ rm -rf isotp_c_wrapped.c isotp_c_wrapped.h iso14229.c iso14229.h release/
+
+isotp_c_wrapped.c: $(shell find src/tp/isotp-c -name '*.c')
+ echo '#if defined(UDS_ISOTP_C)' >> $@ ; for f in $^; do cat $$f >> $@; done ; echo '#endif' >> $@
+
+isotp_c_wrapped.h: $(shell find src/tp/isotp-c -name '*.h')
+ echo '#if defined(UDS_ISOTP_C)' >> $@ ; for f in $^; do cat $$f >> $@; done ; echo '#endif' >> $@
+
+iso14229.c: $(shell find src -name '*.c') isotp_c_wrapped.c
+ echo '#include "iso14229.h"' > $@ ; for f in $^; do echo; echo '#ifdef UDS_LINES'; echo "#line 1 \"$$f\""; echo '#endif'; cat $$f | sed -e 's,#include ".*,,'; done >> $@
+
+iso14229.h: $(shell find src -name '*.h') isotp_c_wrapped.h
+ ( echo '#ifndef ISO14229_H'; echo '#define ISO14229_H'; echo; echo '#ifdef __cplusplus'; echo 'extern "C" {'; echo '#endif'; cat src/version.h src/sys.h src/sys_arduino.h src/sys_unix.h src/sys_win32.h src/sys_esp32.h src/config.h src/util.h src/tp.h src/uds.h src/client.h src/server.h isotp_c_wrapped.h src/tp/*.h |sed -e 's,#include ".*,,' -e 's,^#pragma once,,' ; echo '#endif'; echo '#ifdef __cplusplus'; echo '}'; echo '#endif';) > $@
.phony: clean
diff --git a/amalgamate.py b/amalgamate.py
new file mode 100644
index 0000000..60dff98
--- /dev/null
+++ b/amalgamate.py
@@ -0,0 +1,109 @@
+import os
+import re
+import argparse
+import glob
+
+out_dir = os.getenv("BUILD_WORKSPACE_DIRECTORY", os.getcwd())
+iso14229_h = os.path.join(out_dir, "iso14229.h")
+iso14229_c = os.path.join(out_dir, "iso14229.c")
+
+parser = argparse.ArgumentParser()
+parser.add_argument("--out_c", help="output c file", default=iso14229_c)
+parser.add_argument("--out_h", help="output h file", default=iso14229_h)
+parser.add_argument("srcs", nargs="*")
+args = parser.parse_args()
+srcs = {os.path.basename(src): src for src in args.srcs}
+
+
+def strip_includes(src):
+ return re.sub(r'#include ".*', "", src, flags=re.MULTILINE)
+
+isotp_c_wrapped_c = "#if defined(UDS_ISOTP_C)\n" + \
+ strip_includes(open("src/tp/isotp-c/isotp.c").read()) + \
+ "#endif\n"
+
+isotp_c_wrapped_h = "#if defined(UDS_ISOTP_C)\n" + \
+ "\n".join([strip_includes(open("src/tp/isotp-c/" + h).read()) for h in [
+ "isotp_config.h",
+ "isotp_defines.h",
+ "isotp.h",
+ ]]) + \
+ "#endif\n"
+
+with open(args.out_c, "w") as f:
+ f.write("#include \"iso14229.h\"\n")
+ for src in [
+ "src/client.c",
+ "src/server.c",
+ "src/tp.c",
+ "src/util.c",
+ "src/tp/isotp_c.c",
+ "src/tp/isotp_c_socketcan.c",
+ "src/tp/isotp_sock.c",
+ "src/tp/mock.c",
+ ]:
+ f.write("\n")
+ f.write("#ifdef UDS_LINES\n")
+ f.write(f'#line 1 "{src}"' + "\n")
+ f.write("#endif\n")
+ with open(src) as src_file:
+ f.write(strip_includes(src_file.read()))
+ f.write("\n")
+
+ f.write(isotp_c_wrapped_c)
+ f.write("\n")
+
+
+with open(args.out_h, "w") as f:
+ f.write("#ifndef ISO14229_H\n")
+ f.write("#define ISO14229_H\n")
+ f.write("\n")
+ f.write("#ifdef __cplusplus\n")
+ f.write("extern \"C\" {\n")
+ f.write("#endif\n")
+ f.write("\n")
+ for src in [
+ "src/version.h",
+ "src/sys.h",
+ "src/sys_arduino.h",
+ "src/sys_unix.h",
+ "src/sys_win32.h",
+ "src/sys_esp32.h",
+ "src/config.h",
+ "src/util.h",
+ "src/tp.h",
+ "src/uds.h",
+ "src/client.h",
+ "src/server.h",
+ ]:
+ f.write("\n")
+ with open(src) as src_file:
+ f.write(strip_includes(src_file.read()))
+ f.write("\n")
+
+ f.write(isotp_c_wrapped_h)
+
+
+ for src in [
+ "src/tp/isotp_c.h",
+ "src/tp/isotp_c_socketcan.h",
+ "src/tp/isotp_sock.h",
+ "src/tp/mock.h",
+ ]:
+ f.write("\n")
+ with open(src) as src_file:
+ f.write(strip_includes(src_file.read()))
+ f.write("\n")
+
+ f.write("\n")
+ f.write("#ifdef __cplusplus\n")
+ f.write("}\n")
+ f.write("#endif\n")
+ f.write("\n")
+ f.write("#endif\n")
+
+# os.chmod(iso14229_h, 0o444)
+# os.chmod(iso14229_c, 0o444)
+
+if __name__ == "__main__":
+ print(f"amalgamated source files written to {args.out_c} and {args.out_h}")
\ No newline at end of file
diff --git a/examples/BUILD b/examples/BUILD
deleted file mode 100644
index e69de29..0000000
diff --git a/examples/README.md b/examples/README.md
deleted file mode 100644
index 9ecb1a0..0000000
--- a/examples/README.md
+++ /dev/null
@@ -1,65 +0,0 @@
-# 例子 / Examples
-
-这个例子用linux socketcan. Windows用户可以用个linux虚拟机。WSL应该也可以。
-
-This example uses linux socketcan. Windows users can run it in a linux VM. It might work under WSL.
-
-
-# socketcan 虚拟接口设置 / virtual interface setup
-```sh
-# 设置虚拟socketCAN接口
-# setup a virtual socketCAN interface
-sudo ip link add name vcan0 type vcan
-sudo ip link set vcan0 up
-```
-# 构建例子 / building the example
-```
-make example
-```
-
-# 在vcan0接口上运行例子服务器 / run the server on vcan0
-```sh
-./server vcan0
-# 服务器会一直跑。用 ctrl+c 推出
-# The server will run continuously. Use ctrl+c to exit
-```
-
-# 在vcan0接口上运行客户端 (打开另一个终端) / run the client on vcan0 (open another shell)
-```sh
-./client vcan0
-# 客户端跑完流程后会自动退出
-# The client will exit after it has executed its sequence
-```
-
-# 用candump看看输出
-```sh
-> candump -tz vcan0
- (000.000000) vcan0 111 [4] 01 02 03 04
- (000.000028) vcan0 111 [4] 01 02 03 04
- (000.000090) vcan0 701 [8] 02 11 01 00 00 00 00 00 # 0x11 ECU复位请求
- (000.010199) vcan0 700 [8] 02 51 01 00 00 00 00 00 # 0x11 ECU复位肯定响应
- (000.010213) vcan0 701 [8] 05 22 00 01 00 08 00 00 # 0x22 RDBI请求
- (000.020318) vcan0 700 [8] 10 1B 62 00 01 00 00 08 # ISO-TP流控框
- (000.020326) vcan0 701 [8] 30 08 00 00 00 00 00 00 # 0x22 RDBI请求
- (000.030416) vcan0 700 [8] 21 49 27 6D 20 61 20 55 # 0x22 RDBI响应 (1)
- (000.040674) vcan0 700 [8] 22 44 53 20 73 65 72 76 # 0x22 RDBI响应 (2)
- (000.050829) vcan0 700 [8] 23 65 72 20 20 20 20 00 # 0x22 RDBI响应 (3)
- (000.051509) vcan0 701 [8] 02 10 03 00 00 00 00 00 # 0x10 会话控制
- (000.072713) vcan0 700 [8] 03 7F 10 33 00 00 00 00 # 0x10 会话控制否定响应
- (000.072979) vcan0 701 [8] 02 11 04 00 00 00 00 00 # 0x11 ECU复位请求
- (000.124015) vcan0 700 [8] 03 51 04 FF 00 00 00 00 # 0x11 ECU复位肯定响应
-
-```
-
-
-# 也可以用python-udsoncan实现客户端 / You can also use python-udsoncan to implement a client
-
-```sh
-# 在另外一个终端,安装python依赖性
-# In another shell, install the required python packages
-pip3 install -r example/requirements.txt
-
-# 然后运行客户端
-# then run the client
-./example/client.py vcan0
-```
diff --git a/examples/client.c b/examples/client.c
deleted file mode 100644
index 1bd8c2d..0000000
--- a/examples/client.c
+++ /dev/null
@@ -1,143 +0,0 @@
-#include "../iso14229.h"
-#include "uds_params.h"
-#include
-#include
-#include
-#include
-#include
-#if UDS_TP == UDS_TP_ISOTP_C
-#include "../isotp-c/isotp.h"
-#include "isotp-c_on_socketcan.h"
-#endif
-
-static UDSSeqState_t sendHardReset(UDSClient_t *client) {
- uint8_t resetType = kHardReset;
- printf("%s: sending ECU reset type: %d\n", __func__, resetType);
- UDSSendECUReset(client, resetType);
- return UDSSeqStateGotoNext;
-}
-
-static UDSSeqState_t awaitPositiveResponse(UDSClient_t *client) {
- if (client->err) {
- return client->err;
- }
- if (kRequestStateIdle == client->state) {
- printf("got positive response\n");
- return UDSSeqStateGotoNext;
- } else {
- return UDSSeqStateRunning;
- }
-}
-
-static UDSSeqState_t awaitResponse(UDSClient_t *client) {
- if (kRequestStateIdle == client->state) {
- printf("got response\n");
- return UDSSeqStateGotoNext;
- } else {
- return UDSSeqStateRunning;
- }
-}
-
-static UDSSeqState_t requestSomeData(UDSClient_t *client) {
- printf("%s: calling ReadDataByIdentifier\n", __func__);
- static const uint16_t didList[] = {0x0001, 0x0008};
- UDSSendRDBI(client, didList, 2);
- return UDSSeqStateGotoNext;
-}
-
-static UDSSeqState_t printTheData(UDSClient_t *client) {
- uint8_t buf[21];
- uint16_t offset = 0;
- int err;
-
- printf("Unpacked:\n");
- err = UDSUnpackRDBIResponse(client, 0x0001, buf, DID_0x0001_LEN, &offset);
- if (err) {
- client->err = err;
- return UDSSeqStateDone;
- }
- printf("DID 0x%04x: %d\n", 0x0001, buf[0]);
-
- err = UDSUnpackRDBIResponse(client, 0x0008, buf, DID_0x0008_LEN, &offset);
- if (err) {
- client->err = err;
- return UDSSeqStateDone;
- }
- printf("DID 0x%04x: %s\n", 0x0008, buf);
- return UDSSeqStateGotoNext;
-}
-
-static UDSSeqState_t enterDiagnosticSession(UDSClient_t *client) {
- const uint8_t session = kExtendedDiagnostic;
- UDSSendDiagSessCtrl(client, session);
- printf("%s: entering diagnostic session %d\n", __func__, session);
- return UDSSeqStateGotoNext;
-}
-
-static UDSSeqState_t terminateServerProcess(UDSClient_t *client) {
- printf("%s: requesting server shutdown...\n", __func__);
- client->options |= UDS_SUPPRESS_POS_RESP;
- UDSSendRoutineCtrl(client, kStartRoutine, RID_TERMINATE_PROCESS, NULL, 0);
- return UDSSeqStateGotoNext;
-}
-
-static int SleepMillis(uint32_t tms) {
- struct timespec ts;
- int ret;
- ts.tv_sec = tms / 1000;
- ts.tv_nsec = (tms % 1000) * 1000000;
- do {
- ret = nanosleep(&ts, &ts);
- } while (ret && errno == EINTR);
- return ret;
-}
-
-// clang-format off
-/**
- * @brief 流程定义 Sequence Definition
- */
-static UDSClientCallback callbacks[] = {
- requestSomeData,
- awaitPositiveResponse,
- printTheData,
-
- enterDiagnosticSession,
- awaitResponse,
-
- // terminateServerProcess,
- NULL,
-};
-// clang-format on
-
-int main(int ac, char **av) {
- UDSClient_t client;
- UDSClientConfig_t cfg = {
-#if UDS_TP == UDS_TP_ISOTP_SOCKET
- .if_name = "vcan0",
-#endif
- .source_addr = 0x7E8,
- .target_addr = 0x7E0,
- .target_addr_func = 0x7DF,
- };
-
- if (UDSClientInit(&client, &cfg)) {
- exit(-1);
- }
-
- client.cbList = callbacks;
- client.cbIdx = 0;
-
- printf("running sequence. . .\n");
- int running = 1;
- do {
- running = UDSClientPoll(&client);
-#if UDS_TP == UDS_TP_ISOTP_C
- SocketCANRecv((UDSTpISOTpC_t *)client.tp, cfg.source_addr);
-#endif
- SleepMillis(1);
- } while (running);
-
- printf("sequence completed %ld callbacks with client err: %d\n", client.cbIdx, client.err);
- UDSClientDeInit(&client);
- return 0;
-}
diff --git a/examples/client.py b/examples/client.py
deleted file mode 100755
index 7d885c2..0000000
--- a/examples/client.py
+++ /dev/null
@@ -1,106 +0,0 @@
-#!/usr/bin/env python3
-
-from can.interfaces.socketcan import SocketcanBus
-
-import isotp
-
-from udsoncan.client import Client
-from udsoncan.connections import PythonIsoTpConnection
-from udsoncan.services import *
-
-SRV_SEND_ID = 0x7E8
-SRV_PHYS_RECV_ID = 0x7E0
-SRV_FUNC_RECV_ID = 0x7DF
-
-
-def security_algo(level, seed, params):
- print(f"level: {level}, seed: {seed}, params: {params}")
- return bytes([0])
-
-
-UDSONCAN_CLIENT_CONFIG = {
- "exception_on_negative_response": True,
- "exception_on_invalid_response": True,
- "exception_on_unexpected_response": True,
- "security_algo": security_algo,
- "security_algo_params": None,
- "tolerate_zero_padding": True,
- "ignore_all_zero_dtc": True,
- "dtc_snapshot_did_size": 2, # Not specified in standard. 2 bytes matches other services format.
- "server_address_format": None, # 8,16,24,32,40
- "server_memorysize_format": None, # 8,16,24,32,40
- "data_identifiers": {
- 0x0000: "B",
- 0x0001: "b",
- 0x0002: "H",
- 0x0003: "h",
- 0x0004: "I",
- 0x0005: "i",
- 0x0006: "Q",
- 0x0007: "q",
- 0x0008: "20B",
- },
- "input_output": {},
- "request_timeout": 5,
- "p2_timeout": 1.5,
- "p2_star_timeout": 5,
- "standard_version": 2013, # 2006, 2013, 2020
- "use_server_timing": False,
- "exception_on_negative_response": False,
-}
-
-if __name__ == "__main__":
- with Client(
- conn=PythonIsoTpConnection(
- isotp_layer=isotp.CanStack(
- bus=(SocketcanBus(channel="vcan0")),
- address=isotp.Address(rxid=SRV_SEND_ID, txid=SRV_PHYS_RECV_ID),
- params={
- "tx_data_min_length": 8,
- "blocksize": 0,
- "squash_stmin_requirement": True,
- },
- )
- ),
- config=UDSONCAN_CLIENT_CONFIG,
- ) as client:
-
- response = client.ecu_reset(ECUReset.ResetType.hardReset)
- print(f"Received: {response}")
-
- response = client.change_session(
- DiagnosticSessionControl.Session.extendedDiagnosticSession
- )
- print(f"Received: {response}")
-
- response = client.unlock_security_access(1)
- print(f"Received: {response}")
-
- response = client.change_session(
- DiagnosticSessionControl.Session.extendedDiagnosticSession
- )
- print(f"Received: {response}")
-
- response = client.read_data_by_identifier([0x0008])
- print(f"Received: {response}")
- print(
- f"rdbi data: {bytes(response.service_data.values[0x0008]).decode('ascii')}"
- )
-
- response = client.read_data_by_identifier([0x0001])
- print(f"Received: {response}")
- print(f"rdbi data: {response.service_data.values[0x0001]}")
-
- response = client.write_data_by_identifier(0x0001, 2)
- print(f"Received: {response}")
-
- response = client.read_data_by_identifier([0x0001])
- print(f"Received: {response}")
- print(f"rdbi data: {response.service_data.values[0x0001]}")
-
- response = client.write_data_by_identifier(0x0001, 0)
- print(f"Received: {response}")
-
- response = client.read_data_by_identifier([0x0001])
- print(f"Received: {response}")
- print(f"rdbi data: {response.service_data.values[0x0001]}")
diff --git a/examples/requirements.txt b/examples/requirements.txt
deleted file mode 100644
index b852065..0000000
--- a/examples/requirements.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-python-can==4.0.0
-can-isotp==1.7
-udsoncan==1.14
\ No newline at end of file
diff --git a/examples/server.c b/examples/server.c
deleted file mode 100644
index e1fa53d..0000000
--- a/examples/server.c
+++ /dev/null
@@ -1,176 +0,0 @@
-#include "../iso14229.h"
-#include "uds_params.h"
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#if UDS_TP == UDS_TP_ISOTP_C
-#include "../isotp-c/isotp.h"
-#include "isotp-c_on_socketcan.h"
-#endif
-
-static uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg);
-
-static UDSServer_t srv;
-static const UDSServerConfig_t cfg = {
- .fn = fn,
-#if UDS_TP == UDS_TP_ISOTP_SOCKET
- .if_name = "vcan0",
-#endif
- .target_addr = SERVER_FUNC_ID,
- .source_addr = SERVER_PHYS_RECV_ID,
- .source_addr_func = SERVER_FUNC_RECV_ID,
-};
-static bool serverWantsExit = false;
-static struct RWDBIData {
- uint8_t d1;
- int8_t d2;
- uint16_t d3;
- int16_t d4;
-} myData = {0};
-
-// 用初始化服务器实例来简单模拟一个ECU复位
-// mock an ECU reset by resetting the server
-static void mockECUReset(enum UDSECUResetType resetType) {
- printf("Resetting ECU (type: %d)\n", resetType);
- switch (resetType) {
- case kHardReset:
- case kSoftReset:
- UDSServerDeInit(&srv);
- UDSServerInit(&srv, &cfg);
- break;
- default:
- printf("unknown reset type %d\n", resetType);
- break;
- }
-}
-
-static uint8_t RDBI(UDSServer_t *srv, UDSRDBIArgs_t *r) {
- static const uint8_t msg[] = "I'm a UDS server ";
- switch (r->dataId) {
- case 0x1:
- return r->copy(srv, &myData.d1, sizeof(myData.d1));
- case 0x8:
- return r->copy(srv, (void *)msg, sizeof(msg));
- default:
- return kRequestOutOfRange;
- }
- return kPositiveResponse;
-}
-
-static uint8_t WDBI(UDSServer_t *srv, UDSWDBIArgs_t *r) {
- switch (r->dataId) {
- case 0x1:
- if (r->len != sizeof(myData.d1)) {
- return kIncorrectMessageLengthOrInvalidFormat;
- }
- myData.d1 = r->data[0];
- break;
- default:
- return kRequestOutOfRange;
- }
- return kPositiveResponse;
-}
-
-static uint8_t fn(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
- switch (ev) {
- case UDS_SRV_EVT_EcuReset: { // 0x10
- UDSECUResetArgs_t *r = (UDSECUResetArgs_t *)arg;
- printf("got ECUReset request of type %x\n", r->type);
- switch (r->type) {
- case kHardReset:
- case kSoftReset:
- return kPositiveResponse;
- break;
- default:
- return kSubFunctionNotSupported;
- }
- break;
- }
- case UDS_SRV_EVT_DiagSessCtrl: { // 0x11
- UDSDiagSessCtrlArgs_t *r = (UDSDiagSessCtrlArgs_t *)arg;
- switch (r->type) {
- case kDefaultSession:
- return kPositiveResponse;
- case kProgrammingSession:
- case kExtendedDiagnostic:
- if (srv->securityLevel > 0) {
- return kPositiveResponse;
- } else {
- return kSecurityAccessDenied;
- }
- break;
- default:
- return kSubFunctionNotSupported;
- }
- }
- case UDS_SRV_EVT_ReadDataByIdent: // 0x22
- return RDBI(srv, (UDSRDBIArgs_t *)arg);
- case UDS_SRV_EVT_SecAccessRequestSeed: { // 0x27
- const uint8_t seed[] = {1, 2, 3, 4};
- UDSSecAccessRequestSeedArgs_t *r = (UDSSecAccessRequestSeedArgs_t *)arg;
- return r->copySeed(srv, seed, sizeof(seed));
- }
- case UDS_SRV_EVT_SecAccessValidateKey: { // 0x27
- return kPositiveResponse;
- }
- case UDS_SRV_EVT_WriteDataByIdent: // 0x2E
- return WDBI(srv, (UDSWDBIArgs_t *)arg);
- case UDS_SRV_EVT_RoutineCtrl: { // 0x31
- UDSRoutineCtrlArgs_t *r = (UDSRoutineCtrlArgs_t *)arg;
- if (RID_TERMINATE_PROCESS == r->id) {
- serverWantsExit = true;
- return kPositiveResponse;
- } else {
- return kRequestOutOfRange;
- }
- break;
- }
- case UDS_SRV_EVT_SessionTimeout:
- printf("server session timed out!\n");
- UDSServerDeInit(srv);
- UDSServerInit(srv, &cfg);
- break;
- case UDS_SRV_EVT_DoScheduledReset:
- printf("powering down!\n");
- mockECUReset(*((enum UDSECUResetType *)arg));
- break;
- default:
- printf("Unhandled event: %d\n", ev);
- return kServiceNotSupported;
- }
- return kGeneralProgrammingFailure;
-}
-
-static int SleepMillis(uint32_t tms) {
- struct timespec ts;
- int ret;
- ts.tv_sec = tms / 1000;
- ts.tv_nsec = (tms % 1000) * 1000000;
- do {
- ret = nanosleep(&ts, &ts);
- } while (ret && errno == EINTR);
- return ret;
-}
-
-int main(int ac, char **av) {
- if (UDSServerInit(&srv, &cfg)) {
- exit(-1);
- }
-
- printf("server up, polling . . .\n");
- while (!serverWantsExit) {
- UDSServerPoll(&srv);
-#if UDS_TP == UDS_TP_ISOTP_C
- SocketCANRecv((UDSTpISOTpC_t *)srv.tp, cfg.source_addr);
-#endif
- SleepMillis(1);
- }
- printf("server exiting\n");
- UDSServerDeInit(&srv);
- return 0;
-}
diff --git a/examples/server_minimal/BUILD b/examples/server_minimal/BUILD
deleted file mode 100644
index 4b2bb79..0000000
--- a/examples/server_minimal/BUILD
+++ /dev/null
@@ -1,10 +0,0 @@
-# cc_binary(
-# name = "server_minimal",
-# srcs = [
-# "main.c",
-# "//:iso14229_srcs",
-# ],
-# deps = [
-# "//:tp_mock",
-# ]
-# )
\ No newline at end of file
diff --git a/examples/server_minimal/main.c b/examples/server_minimal/main.c
deleted file mode 100644
index afc63a5..0000000
--- a/examples/server_minimal/main.c
+++ /dev/null
@@ -1,70 +0,0 @@
-#include "iso14229.h"
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include