summaryrefslogtreecommitdiffstats
path: root/src/obd2/obd2.c
blob: 33e6da15d7ffce89f047050c72e732b45555c5bc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#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 = {
        send_can_message: send_can_message,
        set_timer: set_timer,
        log: log
    };
    return shims;
}

DiagnosticRequestHandle diagnostic_request(DiagnosticShims* shims,
        DiagnosticRequest* request, DiagnosticResponseReceived callback) {
    DiagnosticRequestHandle handle = {
        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) {
    DiagnosticRequest request = {
        mode: pid_request_type == DIAGNOSTIC_STANDARD_PID ? 0x1 : 0x22,
        pid: pid
    };

    return diagnostic_request(shims, &request, callback);
}

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(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(
        DiagnosticShims* shims,
        DiagnosticMilStatusReceived callback) {
    // TODO request malfunction indicator light (MIL) status - request mode 1
    // pid 1, parse first bit
}

DiagnosticRequestHandle diagnostic_request_vin(DiagnosticShims* shims,
        DiagnosticVinReceived callback) {
}

DiagnosticRequestHandle diagnostic_request_dtc(DiagnosticShims* shims,
        DiagnosticTroubleCodeType dtc_type,
        DiagnosticTroubleCodesReceived callback) {
}

bool diagnostic_clear_dtc(DiagnosticShims* shims) {
}

DiagnosticRequestHandle diagnostic_enumerate_pids(DiagnosticShims* shims,
        DiagnosticRequest* request, DiagnosticPidEnumerationReceived callback) {
    // before calling the callback, split up the received bytes into 1 or 2 byte
    // chunks depending on the mode so the final pid list is actual 1 or 2 byte PIDs
    // TODO request supported PIDs  - request PID 0 and parse 4 bytes in response
}