代码拉取完成,页面将自动刷新
同步操作将从 bilaizi/iso14229 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
iso14229是个针对嵌入式系统的UDS(ISO14229-1:2013)服务器和客户端会话层实现。为了让你能够更快上手、本库已包含isotp-c
以及linux内核ISO15765-2 (ISO-TP)传输层实现。
API状态: 未稳定
#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;
}
}
}
int main() {
UDSServer_t server;
UDSServerConfig_t cfg = {
.fn = &fn,
};
UDSServerInit(&server, &cfg);
for (;;) {
UDSServerPoll(&server);
}
}
// 参考 examples/client.c
特点:
SID | 英文名 | 支持 |
---|---|---|
0x10 | diagnostic session control | ✅ |
0x11 | ECU reset | ✅ |
0x14 | clear diagnostic information | ❌ |
0x19 | read DTC information | ❌ |
0x22 | read data by identifier | ✅ |
0x23 | read memory by address | ❌ |
0x24 | read scaling data by identifier | ❌ |
0x27 | security access | ✅ |
0x28 | communication control | ✅ |
0x2A | read periodic data by identifier | ❌ |
0x2C | dynamically define data identifier | ❌ |
0x2E | write data by identifier | ✅ |
0x2F | input control by identifier | ❌ |
0x31 | routine control | ✅ |
0x34 | request download | ✅ |
0x35 | request upload | ✅ |
0x36 | transfer data | ✅ |
0x37 | request transfer exit | ✅ |
0x38 | request file transfer | ❌ |
0x3D | write memory by address | ❌ |
0x3E | tester present | ✅ |
0x83 | access timing parameter | ❌ |
0x84 | secured data transmission | ❌ |
0x85 | control DTC setting | ✅ |
0x86 | response on event | ❌ |
参考iso14229.h enum UDSServerEvent
UDS_SRV_EVT_DiagSessCtrl
(0x10) 会话控制typedef struct {
const enum UDSDiagnosticSessionType type; /**< 请求会话类型 */
uint16_t p2_ms; /**< 可选返回值: p2时间设置 */
uint32_t p2_star_ms; /**< 可选返回值: p2*时间设置 */
} UDSDiagSessCtrlArgs_t;
值 | 枚举 | 意义 |
---|---|---|
0x00 |
kPositiveResponse |
允许进入请求中的会话类型 |
0x12 |
kSubFunctionNotSupported |
本器不支持请求中的会话类型 |
0x22 |
kConditionsNotCorrect |
本器当前无法进入请求的会话类型 |
UDS_SRV_EVT_ECUReset
(0x11) ECU复位typedef struct {
const enum UDSECUResetType type; /**< 请求的复位类型 */
uint8_t powerDownTime; /**< 可选返回值: 通知客户端离关机的时间(0-254秒) 255表示无法判断具体关机时间*/
} UDSECUResetArgs_t;
值 | 枚举 | 意义 |
---|---|---|
0x00 |
kPositiveResponse |
允许复位 |
0x12 |
kSubFunctionNotSupported |
本器不支持请求的复位类型 |
0x22 |
kConditionsNotCorrect |
本器目前无法复位 |
0x33 |
kSecurityAccessDenied |
当前安全级别不允许复位 |
UDS_SRV_EVT_ReadDataByIdent
(0x22) 读取数据typedef struct {
const uint16_t dataId; /*! 数据标识符 */
/*! 函数:拷贝数据到服务器发送缓冲器. 成功会返回`kPositiveResponse`。若数据大小超过了服务器发送缓冲器的大小、会返回`kResponseTooLong`。*/
const uint8_t (*copy)(UDSServer_t *srv, const void *src,
uint16_t count);
} UDSRDBIArgs_t;
值 | 枚举 | 意义 |
---|---|---|
0x00 |
kPositiveResponse |
允许读取 (注意调用copy(...) ) |
0x14 |
kResponseTooLong |
响应大小超过发送缓冲器大小 |
0x31 |
kRequestOutOfRange |
请求的标识符不支持 |
0x33 |
kSecurityAccessDenied |
当前安全级别不允许读取请求的数据标识符 |
UDS_SRV_EVT_SecAccessRequestSeed
, UDS_SRV_EVT_SecAccessValidateKey
(0x27) 安全访问typedef struct {
const uint8_t level; /*! 请求安全级别 */
const uint8_t *const dataRecord; /*! 请求数据 */
const uint16_t len; /*! 请求数据大小 */
/*! 函数:拷贝数据到服务器发送缓冲器. 成功会返回`kPositiveResponse`。若数据大小超过了服务器发送缓冲器的大小、会返回`kResponseTooLong`。*/
uint8_t (*copySeed)(UDSServer_t *srv, const void *src,
uint16_t len);
} UDSSecAccessRequestSeedArgs_t;
typedef struct {
const uint8_t level; /*! 请求安全访问级别 */
const uint8_t *const key; /*! 客户端发过来的密钥 */
const uint16_t len; /*! 密钥大小 */
} UDSSecAccessValidateKeyArgs_t;
值 | 枚举 | 意义 |
---|---|---|
0x00 |
kPositiveResponse |
肯定响应 |
0x12 |
kSubFunctionNotSupported |
该安全级别未支持 |
0x22 |
kConditionsNotCorrect |
当前无法处理该请求 |
0x31 |
kRequestOutOfRange |
dataRecord 的数据无效 |
0x35 |
kInvalidKey |
密钥对不上 |
0x36 |
kExceededNumberOfAttempts |
密码错误太多 |
0x37 |
kRequiredTimeDelayNotExpired |
不晓得 |
UDS_SRV_EVT_CommCtrl
(0x28) 通讯控制typedef struct {
enum UDSCommunicationControlType ctrlType;
enum UDSCommunicationType commType;
} UDSCommCtrlArgs_t;
值 | 枚举 | 意义 |
---|---|---|
0x00 |
kPositiveResponse |
肯定响应 |
0x12 |
kSubFunctionNotSupported |
请求中的通讯控制类型未支持 |
0x22 |
kConditionsNotCorrect |
当前无法开启/关闭请求中的通讯控制类型 |
0x31 |
kRequestOutOfRange |
请求中的通讯控制类型或者通讯类型有错 |
UDS_SRV_EVT_WriteDataByIdent
(0x2E) 写入数据typedef struct {
const uint16_t dataId; /*! 数据标识符 */
const uint8_t *const data; /*! 数据 */
const uint16_t len; /*! 数据大小 */
} UDSWDBIArgs_t;
值 | 枚举 | 意义 |
---|---|---|
0x00 |
kPositiveResponse |
写入成功 |
0x22 |
kConditionsNotCorrect |
当前无法写入 |
0x31 |
kRequestOutOfRange |
数据标识符不支持或者数据内容有错 |
0x33 |
kSecurityAccessDenied |
当前安全级别不允许写入请求中的数据标识符 |
0x72 |
kGeneralProgrammingFailure |
写入内存失败 |
UDS_SRV_EVT_RoutineCtrl
(0x31) 例程控制typedef struct {
const uint8_t ctrlType; /*! 例程控制类型 */
const uint16_t id; /*! 例程标识符 */
const uint8_t *optionRecord; /*! 客户端可选数据 */
const uint16_t len; /*! 数据大小 */
/*! 函数:拷贝数据到服务器发送缓冲器. 成功会返回`kPositiveResponse`。若数据大小超过了服务器发送缓冲器的大小、会返回`kResponseTooLong`。*/
uint8_t (*copyStatusRecord)(UDSServer_t *srv, const void *src,
uint16_t len);
} UDSRoutineCtrlArgs_t;
值 | 枚举 | 意义 |
---|---|---|
0x00 |
kPositiveResponse |
肯定响应 |
0x22 |
kConditionsNotCorrect |
当前无法操作 |
0x24 |
kRequestSequenceError |
要求停止但未开始。要求开始但已开始(可选)。没有结果因为例程从来没有开始。 |
0x31 |
kRequestOutOfRange |
请求中的例程标识符未支持或者optionRecord 无效 |
0x33 |
kSecurityAccessDenied |
当前安全访问级别不允许请求的操作 |
0x72 |
kGeneralProgrammingFailure |
内部内存操作失败(如:擦除flash) |
UDS_SRV_EVT_RequestDownload
(0x34) 请求下载typedef struct {
const void *addr; /*! 请求下载地址 */
const size_t size; /*! 请求下载大小 */
const uint8_t dataFormatIdentifier; /*! 可选:数据格式标识符 */
uint16_t maxNumberOfBlockLength; /*! 返回值: 通知客户端能接受的`TransferData`长度是多长 */
} UDSRequestDownloadArgs_t;
值 | 枚举 | 意义 |
---|---|---|
0x00 |
kPositiveResponse |
肯定响应 |
0x22 |
kConditionsNotCorrect |
当前无法操作 |
0x31 |
kRequestOutOfRange |
dataFormatIdentifier ,addr 或者size 无效。 |
0x33 |
kSecurityAccessDenied |
当前安全访问级别不允许请求的操作 |
0x34 |
kAuthenticationRequired |
客户端权利不足 |
0x70 |
kUploadDownloadNotAccepted |
因故障无法下载 |
UDS_SRV_EVT_TransferData
(0x36) 传输数据typedef struct {
const uint8_t *const data; /*! 数据 */
const uint16_t len; /*! 数据大小 */
/*! 函数:拷贝数据到服务器发送缓冲器. 成功会返回`kPositiveResponse`。若数据大小超过了服务器发送缓冲器的大小、会返回`kResponseTooLong`。*/
uint8_t (*copyResponse)(
UDSServer_t *srv, const void *src,
uint16_t len);
} UDSTransferDataArgs_t;
值 | 枚举 | 意义 |
---|---|---|
0x00 |
kPositiveResponse |
肯定响应 |
0x31 |
kRequestOutOfRange |
data 内容无效或者大小不对 |
0x72 |
kGeneralProgrammingFailure |
写入内存失败 |
0x92 |
kVoltageTooHigh |
无法写flash:电压过高 |
0x93 |
kVoltageTooLow |
无法写flash:电压过低 |
UDS_SRV_EVT_RequestTransferExit
(0x37) 请求传输结束typedef struct {
const uint8_t *const data; /*! 数据 */
const uint16_t len; /*! 数据大小 */
/*! 函数:拷贝数据到服务器发送缓冲器. 成功会返回`kPositiveResponse`。若数据大小超过了服务器发送缓冲器的大小、会返回`kResponseTooLong`。*/
uint8_t (*copyResponse)(UDSServer_t *srv, const void *src,
uint16_t len);
} UDSRequestTransferExitArgs_t;
值 | 枚举 | 意义 |
---|---|---|
0x00 |
kPositiveResponse |
肯定响应 |
0x31 |
kRequestOutOfRange |
data 内容无效或者大小不对 |
0x72 |
kGeneralProgrammingFailure |
完成数据传输失败 |
make test
CC=powerpc-linux-gnu-gcc make test_bin
qemu-ppc -L /usr/powerpc-linux-gnu test_bin
CC=x86_64-w64-mingw32-gcc make test_bin
wine test_bin.exe
欢迎提交贡献
isotp
which this project embedsMIT
__attribute__((packed))
udsServerEnableService
udsClientRunSequenceBlocking(...)
isotp-c
同时也支持。看看例子 examples
UDS
前缀在所有导出函数上UDSClientErr_t
合并到UDSErr_t
TP_SEND_INPROGRESS
改名为UDS_TP_SEND_IN_PROGRESS
UDSTpHandle_t
UDS_TP_LINUX_SOCKET
改名为UDS_TP_ISOTP_SOCKET
UDS_SRV_EVT_DoScheduledReset
服务器事件@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
@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
@startuml
' !pragma useVerticalIf on
title 客户端请求流程
start
:clientSendRequest();
if (验证参数) then (对)
:ok;
else (不对)
:foo;
detach
endif
:clearRequestContext();
if (等待UDS访问) then (访问接收了,进入UDS会话)
else (时间超过<b>20ms)
@enduml
@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
@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
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。