The DDEC Web Application provides REST APIs for engine controller programming and calibration management. These APIs are designed to support external clients (including the C++ DRS Client) for downloading and uploading calibration data.
Base URL: http://<server>:8080
Authentication: HTTP Basic Auth or Keycloak SSO
Initiates a download request for engine calibration data from the DDEC batch server.
Endpoint: POST /engineering/ddec/basecal/process
Authorization: Requires authentication (hasRole('ANY'))
Content-Type: multipart/form-data
Response Type: application/json
| Parameter | Type | Required | Description |
|---|---|---|---|
calibrationName |
String | Yes | 06N04 number (e.g., "06N04D0602") or engine serial number (e.g., "5262003107") |
calibrationType |
String | Yes | Type of calibration to download |
historyFile |
File | No | DDECHIST.DAT file for history-based downloads |
| Value | Description |
|---|---|
100 |
Test Calibration |
200 |
Base Calibration (without history) |
600 |
Base Calibration (with history) - requires historyFile |
{
"status": "OK",
"message": "Calibration processed successfully",
"downloadFileName": "download.file",
"archiveFileName": "split_download.file_admin_1706387200000.zip",
"jobParameter": "200"
}
| Field | Description |
|---|---|
status |
"OK" for success, "ERROR" for failure |
message |
Human-readable status message |
downloadFileName |
Internal batch job output filename |
archiveFileName |
ZIP filename to use for download endpoint |
jobParameter |
Job type that was executed |
curl -X POST "http://localhost:8080/engineering/ddec/basecal/process" \
-u admin:admin \
-H "X-CSRF-TOKEN: <csrf_token>" \
-F "calibrationName=06N04D0602" \
-F "calibrationType=200"
// Using libcurl
CURL *curl = curl_easy_init();
curl_mime *form = curl_mime_init(curl);
// Add calibration name
curl_mimepart *field = curl_mime_addpart(form);
curl_mime_name(field, "calibrationName");
curl_mime_data(field, "06N04D0602", CURL_ZERO_TERMINATED);
// Add calibration type
field = curl_mime_addpart(form);
curl_mime_name(field, "calibrationType");
curl_mime_data(field, "200", CURL_ZERO_TERMINATED);
curl_easy_setopt(curl, CURLOPT_URL, "http://server:8080/engineering/ddec/basecal/process");
curl_easy_setopt(curl, CURLOPT_MIMEPOST, form);
curl_easy_setopt(curl, CURLOPT_USERPWD, "admin:admin");
Downloads the processed calibration data as a ZIP archive.
Endpoint: GET /engineering/ddec/basecal
Authorization: Requires authentication (hasRole('ANY'))
Response Type: application/octet-stream (binary)
| Parameter | Type | Required | Description |
|---|---|---|---|
archiveFileName |
String | Yes | Filename from process endpoint response |
Binary ZIP file containing extracted calibration segments.
Response Headers:
Content-Type: application/octet-stream
Content-Disposition: attachment; filename="split_download.file_admin_1706387200000.zip"
curl -X GET "http://localhost:8080/engineering/ddec/basecal?archiveFileName=split_download.file_admin_1706387200000.zip" \
-u admin:admin \
-o calibration.zip
The endpoint validates that the requested filename starts with split_download.file_{userId} to prevent directory traversal attacks.
Uploads and programs a calibration to the engine controller via the batch server.
Endpoint: POST /engineering/ddec/releasecal
Authorization: Requires authentication (hasRole('ANY'))
Content-Type: multipart/form-data
Response Type: application/json
| Parameter | Type | Required | Description |
|---|---|---|---|
reqFile0 |
File | Yes | DDECREQ0.DAT file from DRS Client |
calibrationType |
String | Yes | Type of release operation |
| Value | Description |
|---|---|
300 |
Base Calibration Release |
400 |
Test Calibration Release |
{
"status": "OK",
"message": "Calibration released successfully - ECM programmed",
"downloadFileName": null,
"archiveFileName": null,
"jobParameter": "300"
}
curl -X POST "http://localhost:8080/engineering/ddec/releasecal" \
-u admin:admin \
-H "X-CSRF-TOKEN: <csrf_token>" \
-F "reqFile0=@DDECREQ0.DAT" \
-F "calibrationType=300"
Returns cached SPDB (Special Database) configuration data.
Endpoint: GET /admin/spdb/list
Authorization: Requires admin role (hasRole('ADMIN'))
Response Type: application/json
{
"R35DPSP_ROOT": { },
"R35DPSP_CONT": { }
}
The download.dat file contains multiple record types:
| Record Type | Content Type | Description |
|---|---|---|
| D01 | ASCII | Configuration data |
| D02 | ASCII | Parameter definitions |
| D03 | COMPRESSED_BINARY | Compressed calibration data |
| D04 | COMPRESSED_BINARY | Compressed parameter sets |
| D05 | ASCII | Text descriptions |
| D06 | UNCOMPRESSED_ENCRYPTED_BINARY | Encrypted binary data |
| D07 | ASCII | Metadata |
| D08 | COMPRESSED_BINARY | Primary calibration segments |
| D09 | DDEC2_UNCOMPRESSED_BINARY | Legacy DDEC2 format |
The downloaded ZIP file contains extracted and processed calibration segments:
calibration.zip
├── D01_06N04D0602.dat # ASCII configuration
├── D03_06N04D0602.dat # Decompressed binary
├── D08_06N04D0602.dat # Decompressed calibration
└── manifest.txt # File listing
Request file format for release operations:
{CalibrationName}{UserID} {JobParameter}
Example:
06N04D0602USER001 9999999999
The application uses PKWARE Data Compression Library (DCL Implode) for binary data compression.
Native Library: XCompress.so (Linux) or XCompress.dll (Windows)
Location: /opt/app/clib/
Binary data is encrypted using a simple XOR-based algorithm:
For each byte:
1. XOR with 0x3F (63 decimal)
2. Swap nibbles (rotate 4 bits)
Decryption (pseudocode):
uint8_t decrypt_byte(uint8_t encrypted) {
// Apply XOR key
uint8_t temp = encrypted ^ 0x3F;
// Swap nibbles (arrange bytes)
uint8_t low = temp & 0x0F;
uint8_t high = temp >> 4;
return (low << 4) | high;
}
Mainframe data uses EBCDIC encoding (Code Page 037). The application converts to ASCII for processing.
| Code | Description |
|---|---|
| 200 | Success |
| 400 | Bad Request - Invalid parameters |
| 401 | Unauthorized - Authentication required |
| 403 | Forbidden - Insufficient permissions |
| 404 | Not Found - File or resource not found |
| 500 | Internal Server Error - Processing failed |
{
"status": "ERROR",
"message": "Detailed error description",
"downloadFileName": null,
"archiveFileName": null,
"jobParameter": null
}
| Error | Cause | Solution |
|---|---|---|
| "SFTP connection failed" | Cannot reach batch server | Check SFTP host configuration |
| "File not found after retries" | Batch job didn't complete | Check batch server logs |
| "Invalid calibration name" | Format not recognized | Use 06N04 or serial number format |
| "Decompression failed" | Native library missing | Install XCompress.so |
1. Client sends POST /engineering/ddec/basecal/process
2. Server builds request files (DDECREQ0.DAT, DDECHIST.DAT)
3. Server generates KSH 500 script
4. Server uploads files via SFTP to batch server
5. Batch server executes job, produces download.file
6. Server polls for completion (10 retries, 6-sec interval)
7. Server downloads result file
8. Server parses, decompresses, decrypts segments
9. Server creates ZIP archive
10. Client calls GET /engineering/ddec/basecal to download ZIP
1. Client sends POST /engineering/ddec/releasecal with DDECREQ0.DAT
2. Server validates file format
3. Server generates KSH 505 script
4. Server uploads files via SFTP
5. Batch server executes release job
6. Server polls for completion
7. Server retrieves status file
8. Server converts EBCDIC response to ASCII
9. Server returns status message to client
# SFTP Configuration
ddec.file-server.sftp-host=batch.server.local
ddec.file-server.sftp-account=ddec
ddec.file-server.sftp-password=secret
# Data Directories
# Base: /opt/qte/data/
# Subdirectory: /r24at/
# Scripts: /opt/qte/scripts/batch/drs/
/opt/qte/
├── data/
│ └── r24at/
│ ├── request0.file
│ ├── history.file
│ ├── download.file
│ └── split_download.file_*.zip
└── scripts/
└── batch/
└── drs/
├── r24kd500.sh
└── r24kd505.sh
| Component | File Path |
|---|---|
| REST Controller | src/ddec-web/src/main/java/com/detroitdiesel/ddec/utils/EngineeringController.java |
| SFTP Client | src/ddec-web/src/main/java/com/detroitdiesel/ddec/engineering/util/SftpClient.java |
| Calibration Splitter | src/ddec-web/src/main/java/com/detroitdiesel/ddec/engineering/V2DdecCalibrationSplitter.java |
| Encoding Utilities | src/ddec-web/src/main/java/com/detroitdiesel/ddec/engineering/util/EncodingUtil.java |
| File Utilities | src/ddec-web/src/main/java/com/detroitdiesel/ddec/engineering/util/FileUtil.java |
| DTOs | src/ddec-web/src/main/java/com/detroitdiesel/ddec/engineering/dto/ |
| Download Request Builder | src/ddec-web/src/main/java/com/detroitdiesel/ddec/engineering/R24kd500shDownloadRequestBuilder.java |
| Release Request Builder | src/ddec-web/src/main/java/com/detroitdiesel/ddec/engineering/R24kd505shReleaseRequestBuilder.java |
The DRS C++ Client should:
POST requests require CSRF token:
X-CSRF-TOKEN header with POST requestsarchiveFileName// 1. Request calibration processing
HttpResponse processResp = httpPost(
"/engineering/ddec/basecal/process",
{{"calibrationName", "06N04D0602"}, {"calibrationType", "200"}}
);
// 2. Parse JSON response
JsonObject json = parseJson(processResp.body);
if (json["status"] == "OK") {
std::string archiveFile = json["archiveFileName"];
// 3. Download ZIP file
HttpResponse downloadResp = httpGet(
"/engineering/ddec/basecal?archiveFileName=" + archiveFile
);
// 4. Save binary response to file
saveToFile("calibration.zip", downloadResp.body);
// 5. Extract and process calibration data
extractZip("calibration.zip", "output/");
}
The web application also provides terminal-emulation screens that may be used programmatically:
| Screen | Transaction | Purpose |
|---|---|---|
download-calibration.jsp |
Engineering | Download calibration UI |
release-calibration.jsp |
Engineering | Release calibration UI |
Various D2*Form.jsp |
R24P* | Data entry/display |
Various Bm4*Form.jsp |
R24P* | Basic maintenance |
These JSP screens use AJAX to call the REST endpoints documented above.