Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/driftregion/iso14229 into c…
Browse files Browse the repository at this point in the history
…ustomServiceHandler
  • Loading branch information
Sam Weaver committed Sep 24, 2024
2 parents 3890f5a + 37e285b commit 5f9e104
Show file tree
Hide file tree
Showing 10 changed files with 285 additions and 3 deletions.
1 change: 1 addition & 0 deletions AUTHORS.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
Nick James Kirkby <iso14229dev@gmail.com>
Mark Corbin <mcorbin@lunarenergy.com>
Jens Fernández Mühlke <fernandezjens@gmail.com>
Zhifa Lee <lzhifa@163.com>
30 changes: 29 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ iso14229 is designed to build on any platform.
| 0x35 | request upload ||
| 0x36 | transfer data ||
| 0x37 | request transfer exit ||
| 0x38 | request file transfer | |
| 0x38 | request file transfer | |
| 0x3D | write memory by address ||
| 0x3E | tester present ||
| 0x83 | access timing parameter ||
Expand Down Expand Up @@ -312,6 +312,34 @@ typedef struct {
| `0x31` | `kRequestOutOfRange` | `data` contents invalid, length incorrect |
| `0x72` | `kGeneralProgrammingFailure` | finalizing the data transfer failed |

### `UDS_SRV_EVT_RequestFileTransfer` (0x38)

#### Arguments

```c
typedef struct {
const uint8_t modeOfOperation; /*! requested specifier for operation mode */
const uint16_t filePathLen; /*! request data length */
const uint8_t *filePath; /*! requested file path and name */
const uint8_t dataFormatIdentifier; /*! optional specifier for format of data */
const size_t fileSizeUnCompressed; /*! optional file size */
const size_t fileSizeCompressed; /*! optional file size */
uint16_t maxNumberOfBlockLength; /*! optional response: inform client how many data bytes to
send in each `TransferData` request */
} UDSRequestFileTransferArgs_t;
```

#### Supported Responses

| Value | enum | Meaning |
| - | - | - |
| `0x00` | `kPositiveResponse` | Request accepted |
| `0x13` | `kIncorrectMessageLengthOrInvalidFormat` | Length of the message is wrong |
| `0x22` | `kConditionsNotCorrect` | Downloading or uploading data is ongoing or other conditions to be able to execute this service are not met |
| `0x31` | `kRequestOutOfRange` | `data` contents invalid, length incorrect |
| `0x33` | `kSecurityAccessDenied` | The server is secure |
| `0x70` | `kUploadDownloadNotAccepted` | An attempt to download to a server's memory cannot be accomplished due to some fault conditions |

## Examples

[examples/README.md](examples/README.md)
Expand Down
46 changes: 46 additions & 0 deletions src/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,52 @@ UDSErr_t UDSSendRequestTransferExit(UDSClient_t *client) {
return _SendRequest(client);
}

UDSErr_t UDSSendRequestFileTransfer(UDSClient_t *client, enum FileOperationMode mode, const char *filePath,
uint8_t dataFormatIdentifier, uint8_t fileSizeParameterLength,
size_t fileSizeUncompressed, size_t fileSizeCompressed){
UDSErr_t err = PreRequestCheck(client);
if (err) {
return err;
}
uint16_t filePathLen = strlen(filePath);
if (filePathLen < 1)return UDS_ERR;

uint8_t fileSizeBytes = 0;
if ((mode == kAddFile) || (mode == kReplaceFile)){
fileSizeBytes = fileSizeParameterLength;
}
size_t bufSize = 5 + filePathLen + fileSizeBytes + fileSizeBytes;
if ((mode == kAddFile) || (mode == kReplaceFile) || (mode == kReadFile)){
bufSize += 1;
}
if (client->send_buf_size < bufSize)return UDS_ERR_BUFSIZ;

client->send_buf[0] = kSID_REQUEST_FILE_TRANSFER;
client->send_buf[1] = mode;
client->send_buf[2] = (filePathLen >> 8) & 0xFF;
client->send_buf[3] = filePathLen & 0xFF;
memcpy(&client->send_buf[4], filePath, filePathLen);
if ((mode == kAddFile) || (mode == kReplaceFile) || (mode == kReadFile)){
client->send_buf[4 + filePathLen] = dataFormatIdentifier;
}
if ((mode == kAddFile) || (mode == kReplaceFile)){
client->send_buf[5 + filePathLen] = fileSizeParameterLength;
uint8_t *ptr = &client->send_buf[6 + filePathLen];
for (int i = fileSizeParameterLength - 1; i >= 0; i--) {
*ptr = (fileSizeUncompressed & (0xFF << (8 * i))) >> (8 * i);
ptr++;
}

for (int i = fileSizeParameterLength - 1; i >= 0; i--) {
*ptr = (fileSizeCompressed & (0xFF << (8 * i))) >> (8 * i);
ptr++;
}
}

client->send_size = bufSize;
return _SendRequest(client);
}

/**
* @brief
*
Expand Down
4 changes: 4 additions & 0 deletions src/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ UDSErr_t UDSSendTransferDataStream(UDSClient_t *client, uint8_t blockSequenceCou
const uint16_t blockLength, FILE *fd);
UDSErr_t UDSSendRequestTransferExit(UDSClient_t *client);

UDSErr_t UDSSendRequestFileTransfer(UDSClient_t *client, enum FileOperationMode mode, const char *filePath,
uint8_t dataFormatIdentifier, uint8_t fileSizeParameterLength,
size_t fileSizeUncompressed, size_t fileSizeCompressed);

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,
Expand Down
75 changes: 73 additions & 2 deletions src/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,77 @@ static uint8_t _0x37_RequestTransferExit(UDSServer_t *srv, UDSReq_t *r) {
return NegativeResponse(r, err);
}
}
static uint8_t _0x38_RequestFileTransfer(UDSServer_t *srv, UDSReq_t *r) {
uint8_t err = kPositiveResponse;

if (srv->xferIsActive) {
return NegativeResponse(r, kConditionsNotCorrect);
}
if (r->recv_len < UDS_0X38_REQ_BASE_LEN) {
return NegativeResponse(r, kIncorrectMessageLengthOrInvalidFormat);
}

uint8_t operation = r->recv_buf[1];
uint16_t file_path_len = ((uint16_t)r->recv_buf[2] << 8) + r->recv_buf[3];
uint8_t file_mode = 0;
if ((operation == kAddFile) || (operation == kReplaceFile) || (operation == kReadFile)){
file_mode = r->recv_buf[UDS_0X38_REQ_BASE_LEN + file_path_len];
}
size_t file_size_uncompressed = 0;
size_t file_size_compressed = 0;
if ((operation == kAddFile) || (operation == kReplaceFile)){
size_t size = r->recv_buf[UDS_0X38_REQ_BASE_LEN + file_path_len + 1];
if (size > sizeof(size_t)){
return NegativeResponse(r, kRequestOutOfRange);
}
for (size_t byteIdx = 0; byteIdx < size; byteIdx++) {
size_t byte = r->recv_buf[UDS_0X38_REQ_BASE_LEN + file_path_len + 2 + byteIdx];
uint8_t shiftBytes = size - 1 - byteIdx;
file_size_uncompressed |= byte << (8 * shiftBytes);
}
for (size_t byteIdx = 0; byteIdx < size; byteIdx++) {
size_t byte = r->recv_buf[UDS_0X38_REQ_BASE_LEN + file_path_len + 2 + size + byteIdx];
uint8_t shiftBytes = size - 1 - byteIdx;
file_size_compressed |= byte << (8 * shiftBytes);
}
}
UDSRequestFileTransferArgs_t args = {
.modeOfOperation = operation,
.filePathLen = file_path_len,
.filePath = &r->recv_buf[UDS_0X38_REQ_BASE_LEN],
.dataFormatIdentifier = file_mode,
.fileSizeUnCompressed = file_size_uncompressed,
.fileSizeCompressed = file_size_compressed,
};

err = EmitEvent(srv, UDS_SRV_EVT_RequestFileTransfer, &args);

if (kPositiveResponse != err) {
return NegativeResponse(r, err);
}

ResetTransfer(srv);
srv->xferIsActive = true;
srv->xferTotalBytes = args.fileSizeCompressed;
srv->xferBlockLength = args.maxNumberOfBlockLength;

if (args.maxNumberOfBlockLength > UDS_TP_MTU) {
args.maxNumberOfBlockLength = UDS_TP_MTU;
}

r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_REQUEST_FILE_TRANSFER);
r->send_buf[1] = args.modeOfOperation;
r->send_buf[2] = sizeof(args.maxNumberOfBlockLength);
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_0X38_RESP_BASE_LEN + idx] = byte;
}
r->send_buf[UDS_0X38_RESP_BASE_LEN + sizeof(args.maxNumberOfBlockLength)] = args.dataFormatIdentifier;

r->send_len = UDS_0X38_RESP_BASE_LEN + sizeof(args.maxNumberOfBlockLength) + 1;
return kPositiveResponse;
}

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)) {
Expand Down Expand Up @@ -721,7 +792,7 @@ static UDSService getServiceForSID(uint8_t sid) {
case kSID_REQUEST_TRANSFER_EXIT:
return _0x37_RequestTransferExit;
case kSID_REQUEST_FILE_TRANSFER:
return NULL;
return _0x38_RequestFileTransfer;
case kSID_WRITE_MEMORY_BY_ADDRESS:
return NULL;
case kSID_TESTER_PRESENT:
Expand Down Expand Up @@ -791,6 +862,7 @@ static uint8_t evaluateServiceResponse(UDSServer_t *srv, UDSReq_t *r) {
case kSID_REQUEST_DOWNLOAD:
case kSID_REQUEST_UPLOAD:
case kSID_TRANSFER_DATA:
case kSID_REQUEST_FILE_TRANSFER:
case kSID_REQUEST_TRANSFER_EXIT: {
assert(service);
response = service(srv, r);
Expand All @@ -804,7 +876,6 @@ static uint8_t evaluateServiceResponse(UDSServer_t *srv, UDSReq_t *r) {
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:
Expand Down
11 changes: 11 additions & 0 deletions src/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,17 @@ typedef struct {
uint16_t len); /*! function for copying response data (optional) */
} UDSRequestTransferExitArgs_t;

typedef struct {
const uint8_t modeOfOperation; /*! requested specifier for operation mode */
const uint16_t filePathLen; /*! request data length */
const uint8_t *filePath; /*! requested file path and name */
const uint8_t dataFormatIdentifier; /*! optional specifier for format of data */
const size_t fileSizeUnCompressed; /*! optional file size */
const size_t fileSizeCompressed; /*! optional file size */
uint16_t maxNumberOfBlockLength; /*! optional response: inform client how many data bytes to
send in each `TransferData` request */
} UDSRequestFileTransferArgs_t;

typedef struct {
const uint16_t sid; /*! serviceIdentifier */
const uint8_t *optionRecord; /*! optional data */
Expand Down
14 changes: 14 additions & 0 deletions src/uds.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ enum UDSServerEvent {
UDS_SRV_EVT_RequestUpload, // UDSRequestUploadArgs_t *
UDS_SRV_EVT_TransferData, // UDSTransferDataArgs_t *
UDS_SRV_EVT_RequestTransferExit, // UDSRequestTransferExitArgs_t *
UDS_SRV_EVT_RequestFileTransfer, // UDSRequestFileTransferArgs_t *
UDS_SRV_EVT_SessionTimeout, // NULL
UDS_SRV_EVT_DoScheduledReset, // enum UDSEcuResetType *
UDS_SRV_EVT_CUSTOM, // UDSCustomArgs_t *
Expand Down Expand Up @@ -149,6 +150,17 @@ enum RoutineControlType {
kRequestRoutineResults = 3,
};

/**
* @addtogroup requestFileTransfer_0x38
*/
enum FileOperationMode {
kAddFile = 1,
kDeleteFile = 2,
kReplaceFile = 3,
kReadFile = 4,
kReadDir = 5,
};

/**
* @addtogroup controlDTCSetting_0x85
*/
Expand Down Expand Up @@ -188,6 +200,8 @@ enum DTCSettingType {
#define UDS_0X36_RESP_BASE_LEN 2U
#define UDS_0X37_REQ_BASE_LEN 1U
#define UDS_0X37_RESP_BASE_LEN 1U
#define UDS_0X38_REQ_BASE_LEN 4U
#define UDS_0X38_RESP_BASE_LEN 3U
#define UDS_0X3E_REQ_MIN_LEN 2U
#define UDS_0X3E_REQ_MAX_LEN 2U
#define UDS_0X3E_RESP_LEN 2U
Expand Down
2 changes: 2 additions & 0 deletions test/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ TEST_SRCS = [
"test_client_0x22_RDBI_unpack_response.c",
"test_client_0x31_RCRRP.c",
"test_client_0x34_request_download.c",
"test_client_0x38_request_file_transfer.c",
"test_client_busy.c",
"test_client_p2.c",
"test_client_suppress_positive_response.c",
Expand All @@ -36,6 +37,7 @@ TEST_SRCS = [
"test_server_0x27_security_access.c",
"test_server_0x31_RCRRP.c",
"test_server_0x34.c",
"test_server_0x38_request_file_transfer.c",
"test_server_0x3E_suppress_positive_response.c",
"test_server_0x83_diagnostic_session_control.c",
"test_server_session_timeout.c",
Expand Down
24 changes: 24 additions & 0 deletions test/test_client_0x38_request_file_transfer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#include "test/test.h"

int main() {
UDSClient_t client;
{
ENV_CLIENT_INIT(client);

EXPECT_OK(UDSSendRequestFileTransfer(&client, kAddFile, "/data/testfile.zip", 0x00, 3, 0x112233, 0x001122));

const uint8_t ADDFILE_REQUEST[] = {0x38, 0x01, 0x00, 0x12, 0x2F, 0x64, 0x61, 0x74, 0x61, 0x2F, 0x74, 0x65,
0x73, 0x74, 0x66, 0x69, 0x6C, 0x65, 0x2E, 0x7A, 0x69, 0x70, 0x00, 0x03,
0x11, 0x22, 0x33, 0x00, 0x11, 0x22};
TEST_MEMORY_EQUAL(client.send_buf, ADDFILE_REQUEST, sizeof(ADDFILE_REQUEST));
}
{
ENV_CLIENT_INIT(client);

EXPECT_OK(UDSSendRequestFileTransfer(&client, kDeleteFile, "/data/testfile.zip", 0x00, 0, 0, 0));

const uint8_t DELETEFILE_REQUEST[] = {0x38, 0x02, 0x00, 0x12, 0x2F, 0x64, 0x61, 0x74, 0x61, 0x2F, 0x74, 0x65,
0x73, 0x74, 0x66, 0x69, 0x6C, 0x65, 0x2E, 0x7A, 0x69, 0x70};
TEST_MEMORY_EQUAL(client.send_buf, DELETEFILE_REQUEST, sizeof(DELETEFILE_REQUEST));
}
}
81 changes: 81 additions & 0 deletions test/test_server_0x38_request_file_transfer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#include "test/test.h"

uint8_t fn_addfile(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
TEST_INT_EQUAL(ev, UDS_SRV_EVT_RequestFileTransfer);
UDSRequestFileTransferArgs_t *r = (UDSRequestFileTransferArgs_t *)arg;
TEST_INT_EQUAL(0x01, r->modeOfOperation);
TEST_INT_EQUAL(18, r->filePathLen);
TEST_MEMORY_EQUAL((void *)"/data/testfile.zip", r->filePath, r->filePathLen);
TEST_INT_EQUAL(0x00, r->dataFormatIdentifier);
TEST_INT_EQUAL(0x112233, r->fileSizeUnCompressed);
TEST_INT_EQUAL(0x001122, r->fileSizeCompressed);
r->maxNumberOfBlockLength = 0x0081;
return kPositiveResponse;
}

uint8_t fn_delfile(UDSServer_t *srv, UDSServerEvent_t ev, const void *arg) {
TEST_INT_EQUAL(ev, UDS_SRV_EVT_RequestFileTransfer);
UDSRequestFileTransferArgs_t *r = (UDSRequestFileTransferArgs_t *)arg;
TEST_INT_EQUAL(0x02, r->modeOfOperation);
TEST_INT_EQUAL(18, r->filePathLen);
TEST_MEMORY_EQUAL((void *)"/data/testfile.zip", r->filePath, r->filePathLen);
return kPositiveResponse;
}

int main() {
{ // case 0: No handler
UDSTpHandle_t *mock_client = ENV_TpNew("client");
UDSServer_t srv;
ENV_SERVER_INIT(srv);

// when no handler function is installed, sending this request to the server
uint8_t ADDFILE_REQUEST[] = {0x38, 0x01, 0x00, 0x12, 0x2F, 0x64, 0x61, 0x74, 0x61, 0x2F, 0x74, 0x65,
0x73, 0x74, 0x66, 0x69, 0x6C, 0x65, 0x2E, 0x7A, 0x69, 0x70, 0x00, 0x03,
0x11, 0x22, 0x33, 0x00, 0x11, 0x22};
UDSTpSend(mock_client, ADDFILE_REQUEST, sizeof(ADDFILE_REQUEST), NULL);

// should return a kServiceNotSupported response
uint8_t RESP[] = {0x7F, 0x38, 0x11};
EXPECT_IN_APPROX_MS(UDSTpGetRecvLen(mock_client) > 0, srv.p2_ms);
TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(mock_client, NULL), RESP, sizeof(RESP));
TPMockReset();
}

{ // case 1: add file
UDSTpHandle_t *mock_client = ENV_TpNew("client");
UDSServer_t srv;
ENV_SERVER_INIT(srv);
// when a handler is installed that implements UDS-1:2013 Table 435
srv.fn = fn_addfile;

// sending this request to the server
uint8_t ADDFILE_REQUEST[] = {0x38, 0x01, 0x00, 0x12, 0x2F, 0x64, 0x61, 0x74, 0x61, 0x2F, 0x74, 0x65,
0x73, 0x74, 0x66, 0x69, 0x6C, 0x65, 0x2E, 0x7A, 0x69, 0x70, 0x00, 0x03,
0x11, 0x22, 0x33, 0x00, 0x11, 0x22};
UDSTpSend(mock_client, ADDFILE_REQUEST, sizeof(ADDFILE_REQUEST), NULL);

// should receive a positive response matching UDS-1:2013 Table 435
uint8_t RESP[] = {0x78, 0x01, 0x02, 0x00, 0x81};
EXPECT_IN_APPROX_MS(UDSTpGetRecvLen(mock_client) > 0, srv.p2_ms);
TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(mock_client, NULL), RESP, sizeof(RESP));
TPMockReset();
}
{ // case 2: delete file
UDSTpHandle_t *mock_client = ENV_TpNew("client");
UDSServer_t srv;
ENV_SERVER_INIT(srv);
// when a handler is installed that implements UDS-1:2013 Table 435
srv.fn = fn_delfile;

// sending this request to the server
const uint8_t DELETEFILE_REQUEST[] = {0x38, 0x02, 0x00, 0x12, 0x2F, 0x64, 0x61, 0x74, 0x61, 0x2F, 0x74, 0x65,
0x73, 0x74, 0x66, 0x69, 0x6C, 0x65, 0x2E, 0x7A, 0x69, 0x70};
UDSTpSend(mock_client, DELETEFILE_REQUEST, sizeof(DELETEFILE_REQUEST), NULL);

// should receive a positive response matching UDS-1:2013 Table 435
uint8_t RESP[] = {0x78, 0x02};
EXPECT_IN_APPROX_MS(UDSTpGetRecvLen(mock_client) > 0, srv.p2_ms);
TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(mock_client, NULL), RESP, sizeof(RESP));
TPMockReset();
}
}

0 comments on commit 5f9e104

Please sign in to comment.