Add 'CAN-binder/libs/isotp-c/' from commit 'ee24440b7c123ab1b0317e57be33e837a1cb51f1'
[apps/agl-service-can-low-level.git] / CAN-binder / libs / isotp-c / src / isotp / send.c
1 #include <isotp/send.h>
2 #include <bitfield/bitfield.h>
3 #include <string.h>
4
5 #define PCI_NIBBLE_INDEX 0
6 #define PAYLOAD_LENGTH_NIBBLE_INDEX 1
7 #define PAYLOAD_BYTE_INDEX 1
8
9 void isotp_complete_send(IsoTpShims* shims, IsoTpMessage* message,
10         bool status, IsoTpMessageSentHandler callback) {
11     if(callback != NULL) {
12         callback(message, status);
13     }
14 }
15
16 IsoTpSendHandle isotp_send_single_frame(IsoTpShims* shims, IsoTpMessage* message,
17         IsoTpMessageSentHandler callback) {
18     IsoTpSendHandle handle = {
19         success: false,
20         completed: true
21     };
22
23     uint8_t can_data[CAN_MESSAGE_BYTE_SIZE] = {0};
24     if(!set_nibble(PCI_NIBBLE_INDEX, PCI_SINGLE, can_data, sizeof(can_data))) {
25         shims->log("Unable to set PCI in CAN data");
26         return handle;
27     }
28
29     if(!set_nibble(PAYLOAD_LENGTH_NIBBLE_INDEX, message->size, can_data,
30                 sizeof(can_data))) {
31         shims->log("Unable to set payload length in CAN data");
32         return handle;
33     }
34
35     if(message->size > 0) {
36         memcpy(&can_data[1], message->payload, message->size);
37     }
38
39     shims->send_can_message(message->arbitration_id, can_data,
40             shims->frame_padding ? 8 : 1 + message->size);
41     handle.success = true;
42     isotp_complete_send(shims, message, true, callback);
43     return handle;
44 }
45
46 IsoTpSendHandle isotp_send_multi_frame(IsoTpShims* shims, IsoTpMessage* message,
47         IsoTpMessageSentHandler callback) {
48     // TODO make sure to copy message into a local buffer
49     shims->log("Only single frame messages are supported");
50     IsoTpSendHandle handle = {
51         success: false,
52         completed: true
53     };
54     // TODO need to set sending and receiving arbitration IDs separately if we
55     // can't always just add 0x8 (and I think we can't)
56     return handle;
57 }
58
59 IsoTpSendHandle isotp_send(IsoTpShims* shims, const uint16_t arbitration_id,
60         const uint8_t payload[], uint16_t size,
61         IsoTpMessageSentHandler callback) {
62     IsoTpMessage message = {
63         arbitration_id: arbitration_id,
64         size: size
65     };
66
67     memcpy(message.payload, payload, size);
68     if(size < 8) {
69         return isotp_send_single_frame(shims, &message, callback);
70     } else {
71         return isotp_send_multi_frame(shims, &message, callback);
72     }
73 }
74
75 bool isotp_continue_send(IsoTpShims* shims, IsoTpSendHandle* handle,
76         const uint16_t arbitration_id, const uint8_t data[],
77         const uint8_t size) {
78     // TODO this will need to be tested when we add multi-frame support,
79     // which is when it'll be necessary to pass in CAN messages to SENDING
80     // handles.
81     if(handle->receiving_arbitration_id != arbitration_id) {
82         if(shims->log != NULL) {
83             shims->log("The arb ID 0x%x doesn't match the expected tx continuation ID 0x%x",
84                     arbitration_id, handle->receiving_arbitration_id);
85         }
86         return false;
87     }
88     return false;
89 }