diff options
m--------- | deps/bitfield-c | 10 | ||||
m--------- | deps/isotp-c | 10 | ||||
-rw-r--r-- | src/obd2/obd2.c | 92 | ||||
-rw-r--r-- | src/obd2/obd2.h | 14 |
4 files changed, 87 insertions, 39 deletions
diff --git a/deps/bitfield-c b/deps/bitfield-c -Subproject cd74b88432054107c439c4e565bea14840dd9ea +Subproject 4af52c415f1668fbd168da74d0aca903c592463 diff --git a/deps/isotp-c b/deps/isotp-c -Subproject bc7c0205d8dd7550060f6f0bbe8e2064d28ace8 +Subproject 10a35b0a7c380d77cdd24ac90d6aa0abd4601f3 diff --git a/src/obd2/obd2.c b/src/obd2/obd2.c index 3d501d6..33e6da1 100644 --- a/src/obd2/obd2.c +++ b/src/obd2/obd2.c @@ -1,14 +1,15 @@ #include <obd2/obd2.h> +#define MAX_DIAGNOSTIC_PAYLOAD_SIZE 6 +#define MODE_BYTE_INDEX 0 +#define PID_BYTE_INDEX 1 + DiagnosticShims diagnostic_init_shims(LogShim log, SendCanMessageShim send_can_message, SetTimerShim set_timer) { DiagnosticShims shims = { - isotp_shims: { - log: log, - send_can_message: send_can_message, - set_timer: set_timer - }, + send_can_message: send_can_message, + set_timer: set_timer, log: log }; return shims; @@ -16,34 +17,60 @@ DiagnosticShims diagnostic_init_shims(LogShim log, DiagnosticRequestHandle diagnostic_request(DiagnosticShims* shims, DiagnosticRequest* request, DiagnosticResponseReceived callback) { - // TODO hmm, where is message_received coming from? we would need 2 layers - // of callbacks. if we do it in the obd2 library, we have to have some - // context passed to that message_received handler so we can then retreive - // the obd2 callback. there was an option question of if we should pass a - // context with that callback, and maybe this answers it. - // - // alternatively, what if don't hide isotp and allow that to also be - // injected. the user has the iso_tp message_received callback, and in that - // they call a message_received handler from obd2. - // - // in fact that makes more sense - all the diagnostic_can_frame_received - // function is going to be able to do is call the equivalent function in the - // isotp library. it may or may not have a complete ISO-TP message. huh. DiagnosticRequestHandle handle = { - // TODO why are teh shims stored as a reference in the isotp handler? - // it's just 3 pointers - isotp_handler: isotp_init(&shims->isotp_shims, request->arbitration_id, - NULL, // TODO need a callback here! - NULL, NULL), - type: 0 //DIAGNOSTIC_.... // TODO how would we know the type? - //does it matter? we were going to have a different callback + type: DIAGNOSTIC_REQUEST_TYPE_PID, + callback: callback, + status: true }; + uint8_t payload[MAX_DIAGNOSTIC_PAYLOAD_SIZE]; + payload[MODE_BYTE_INDEX] = request->mode; + if(request->pid_length > 0) { + copy_bytes_right_aligned(request->pid, sizeof(request->pid), + PID_BYTE_INDEX, request->pid_length, payload, sizeof(payload)); + } + if(request->payload_length > 0) { + memcpy(payload[PID_BYTE_INDEX + request->pid_length], + request->payload, request->payload_length); + } + + IsoTpShims isotp_shims = isotp_init_shims(shims->log, + shims->send_can_message, + shims->set_timer); + handle.status = isotp_send(&isotp_shims, request->arbitration_id, + payload, 1 + request->payload_length + request->pid_length, + diagnostic_receive_isotp_message); + + // TODO need to set up an isotp receive handler. in isotp, rx and tx are + // kind of intermingled at this point. really, there's not explicit link + // between send and receveice...well except for flow control. hm, damn. + // so there's 2 things: + // + // isotp_send needs to return a handle. if it was a single frame, we + // probably sent it right away so the status true and the callback was hit. + // the handle needs another flag to say if it was completed or not, so you + // know you can destroy it. you will continue to throw can frames at that + // handler until it returns completed (either with a flag, or maybe + // receive_can_frame returns true if it's complete) + // + // the second thing is that we need to be able to arbitrarly set up to + // receive an iso-tp message on a particular arb id. again, you keep + // throwing can frames at it until it returns a handle with the status + // completed and calls your callback + // + // so the diagnostic request needs 2 isotp handles and they should both be + // hidden from the user + // + // when a can frame is received and passes to the diagnostic handle + // if we haven't successfuly sent the entire message yet, give it to the + // isottp send handle + // if we have sent it, give it to the isotp rx handle + // if we've received properly, mark this request as completed + return handle; } DiagnosticRequestHandle diagnostic_request_pid(DiagnosticShims* shims, DiagnosticPidRequestType pid_request_type, uint16_t pid, DiagnosticResponseReceived callback) { - // decide mode 0x1 / 0x22 based on pid type DiagnosticRequest request = { mode: pid_request_type == DIAGNOSTIC_STANDARD_PID ? 0x1 : 0x22, pid: pid @@ -52,12 +79,21 @@ DiagnosticRequestHandle diagnostic_request_pid(DiagnosticShims* shims, return diagnostic_request(shims, &request, callback); } -void diagnostic_receive_can_frame(DiagnosticRequestHandle* handler, +void diagnostic_receive_isotp_message(const IsoTpMessage* message) { + // TODO +} + +void diagnostic_receive_can_frame(DiagnosticRequestHandle* handle, const uint16_t arbitration_id, const uint8_t data[], const uint8_t size) { - isotp_receive_can_frame(handler->isotp_handler, arbitration_id, data, size); + isotp_receive_can_frame(handle->isotp_handler, arbitration_id, data, size); } +// TODO argh, we're now saying that user code will rx CAN messages, but who does +// it hand them to? isotp handlers are encapsulated in diagnostic handles + + + // TODO everything below here is for future work...not critical for now. DiagnosticRequestHandle diagnostic_request_malfunction_indicator_status( diff --git a/src/obd2/obd2.h b/src/obd2/obd2.h index e4ffc7a..8d7d664 100644 --- a/src/obd2/obd2.h +++ b/src/obd2/obd2.h @@ -16,10 +16,15 @@ typedef struct { uint16_t arbitration_id; uint8_t mode; uint16_t pid; + uint8_t pid_length; uint8_t payload[MAX_OBD2_PAYLOAD_LENGTH]; uint8_t payload_length; } DiagnosticRequest; +// TODO I don't like this, it's hard coding isotp library stuff here +typedef bool (*SendIsoTpMessageShim)(IsoTpHandler* handler, + const uint8_t* payload, uint16_t payload_size); + // Thanks to // http://www.canbushack.com/blog/index.php?title=scanning-for-diagnostic-data&more=1&c=1&tb=1&pb=1 // for the list of NRCs @@ -116,6 +121,7 @@ typedef struct { // compare an incoming CAN message to see if it matches the service / PID! // TODO i'm not sure this type/callback in here is too useful - see the // comments in obd2.c:diagnostic_request + DiagnosticRequestType type; DiagnosticResponseReceived callback; DiagnosticMilStatusReceived mil_status_callback; @@ -129,7 +135,8 @@ typedef enum { } DiagnosticPidRequestType; typedef struct { - IsoTpShims isotp_shims; + SetTimerShim set_timer; + SendCanMessageShim send_can_message; LogShim log; } DiagnosticShims; @@ -161,6 +168,11 @@ bool diagnostic_clear_dtc(DiagnosticShims* shims); DiagnosticRequestHandle diagnostic_enumerate_pids(DiagnosticShims* shims, DiagnosticRequest* request, DiagnosticPidEnumerationReceived callback); +// TODO +// void diagnostic_receive_isotp_message(DiagnosticRequestHandle* handle, + // const IsoTpMessage* message); +void diagnostic_receive_isotp_message(const IsoTpMessage* message); + void diagnostic_receive_can_frame(DiagnosticRequestHandle* handle, const uint16_t arbitration_id, const uint8_t data[], const uint8_t size); |