├── LICENSE ├── README.md ├── go.mod ├── isotp ├── address.go ├── isotp_connection.go ├── isotp_test.go ├── message.go ├── rx.go ├── test_helper.go ├── timer.go ├── transport.go └── tx.go ├── uds ├── client.go ├── connections.go ├── memory_location.go ├── request.go ├── response.go ├── service_diagnostic_session.go ├── service_read_data_by_id.go ├── service_request_download.go ├── service_security_access.go ├── service_transfer.go ├── test_helper.go └── uds_test.go └── util ├── interface_queue.go └── queue.go /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Andrew Arrow 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go-uds 2 | Go implementation of UDS (ISO-14229) standard. 3 | 4 | This project is an implementation of the Unified Diagnostic Services (UDS) protocol defined by ISO-14229 written in golang. 5 | 6 | It is a port of python version: https://github.com/pylessard/python-udsoncan 7 | 8 | UDS runs on top of the isotp protocol: 9 | 10 | also port of Python version https://github.com/pylessard/python-can-isotp 11 | 12 | does not require https://github.com/hartkopp/can-isotp 13 | 14 | but reading canbus data from real device requires native c code for darwin, windows and linux. 15 | 16 | you define stack_rxfn and stack_txfn functions that will call the native c code for real data. 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/andrewarrow/go-uds 2 | 3 | go 1.13 4 | -------------------------------------------------------------------------------- /isotp/address.go: -------------------------------------------------------------------------------- 1 | package isotp 2 | 3 | const Normal_11bits = 0 4 | const Normal_29bits = 1 5 | const NormalFixed_29bits = 2 6 | const Extended_11bits = 3 7 | const Extended_29bits = 4 8 | const Mixed_11bits = 5 9 | const Mixed_29bits = 6 10 | 11 | const Physical = 0 12 | const Functional = 1 13 | 14 | type Address struct { 15 | rx_prefix_size int 16 | addressing_mode int 17 | txid int64 18 | rxid int64 19 | target_address int 20 | source_address int 21 | address_extension int 22 | tx_payload_prefix []byte 23 | } 24 | 25 | func NewAddress(rxid, txid int64) Address { 26 | a := Address{} 27 | a.tx_payload_prefix = []byte{} 28 | a.addressing_mode = Normal_11bits 29 | //a.target_address = target_address 30 | //a.source_address = source_address 31 | //a.address_extension = address_extension 32 | a.rxid = rxid 33 | a.txid = txid 34 | 35 | return a 36 | } 37 | 38 | func (a Address) is_for_me(msg Message) bool { 39 | //if a.is_29bits() == msg.extended_id { 40 | //} 41 | return msg.Id == a.rxid 42 | } 43 | 44 | func (a Address) _get_tx_arbitraton_id(address_type int) int64 { 45 | if a.addressing_mode == Normal_11bits { 46 | return a.txid 47 | } else if a.addressing_mode == Normal_29bits { 48 | return a.txid 49 | } else if a.addressing_mode == NormalFixed_29bits { 50 | bits23_16 := 0xDB0000 51 | if address_type == Physical { 52 | bits23_16 = 0xDA0000 53 | } 54 | return int64(0x18000000 | bits23_16 | (a.target_address << 8) | a.source_address) 55 | } else if a.addressing_mode == Extended_11bits { 56 | return a.txid 57 | } else if a.addressing_mode == Extended_29bits { 58 | return a.txid 59 | } else if a.addressing_mode == Mixed_11bits { 60 | return a.txid 61 | } else if a.addressing_mode == Mixed_29bits { 62 | bits23_16 := 0xCD0000 63 | if address_type == Physical { 64 | bits23_16 = 0xCE0000 65 | } 66 | return int64(0x18000000 | bits23_16 | (a.target_address << 8) | a.source_address) 67 | } 68 | return 0 69 | } 70 | 71 | func (a Address) is_29bits() bool { 72 | if a.addressing_mode == Normal_29bits || 73 | a.addressing_mode == NormalFixed_29bits || 74 | a.addressing_mode == Extended_29bits || 75 | a.addressing_mode == Mixed_29bits { 76 | return true 77 | } 78 | return false 79 | } 80 | -------------------------------------------------------------------------------- /isotp/isotp_connection.go: -------------------------------------------------------------------------------- 1 | package isotp 2 | 3 | import "time" 4 | 5 | import "fmt" 6 | import "github.com/andrewarrow/go-uds/util" 7 | 8 | type AnyConn interface { 9 | Empty_rxqueue() 10 | Empty_txqueue() 11 | Send(payload []byte) 12 | Wait_frame() []byte 13 | Send_and_grant_flow_request(payload []byte, length int) []byte 14 | Send_and_wait_for_reply(payload []byte) []byte 15 | Send_and_no_wait_for_reply(payload []byte) []byte 16 | } 17 | 18 | type IsotpConnection struct { 19 | name string 20 | mtu int 21 | fromIsoTPQueue *util.Queue 22 | toIsoTPQueue *util.Queue 23 | Stack *Transport 24 | rxfn func() (Message, bool) 25 | txfn func(msg Message) 26 | } 27 | 28 | func NewIsotpConnection(rx, tx int64, rxfn func() (Message, bool), 29 | txfn func(msg Message)) *IsotpConnection { 30 | ic := IsotpConnection{} 31 | a := NewAddress(rx, tx) 32 | ic.Stack = NewTransport(a, rxfn, txfn) 33 | ic.rxfn = rxfn 34 | ic.txfn = txfn 35 | ic.fromIsoTPQueue = util.NewQueue() 36 | ic.toIsoTPQueue = util.NewQueue() 37 | return &ic 38 | } 39 | 40 | func (ic *IsotpConnection) asSingleFrameOrMulti(payload []byte) []Message { 41 | tx_buffer := append([]byte{}, payload...) 42 | tx_frame_length := len(payload) 43 | encode_length_on_2_first_bytes := false 44 | if tx_frame_length <= 4095 { 45 | encode_length_on_2_first_bytes = true 46 | } 47 | 48 | ms := []Message{} 49 | if len(payload) <= 8 { 50 | //fmt.Println("less than 8") 51 | msg_data := append([]byte{byte(0x0 | len(payload))}, payload...) 52 | msg := ic.Stack.make_tx_msg(ic.Stack.address.txid, msg_data) 53 | //ic.Stack.txfn(msg) 54 | ms = append(ms, msg) 55 | } else { 56 | //fmt.Println("more than 8") 57 | seq := 0 58 | first_time := true 59 | for { 60 | msg_data := []byte{} 61 | data_length := 7 62 | if len(tx_buffer) < 7 { 63 | data_length = len(tx_buffer) 64 | } 65 | if seq == 0 && first_time { 66 | first_time = false 67 | if encode_length_on_2_first_bytes { 68 | data_length = 6 69 | msg_data = append([]byte{0x10 | byte((tx_frame_length>>8)&0xF), byte(tx_frame_length & 0xFF)}, 70 | tx_buffer[0:data_length]...) 71 | } else { 72 | data_length = 2 73 | msg_data = append([]byte{0x10, 0x00, byte(tx_frame_length>>24) & 0xFF, byte(tx_frame_length>>16) & 0xFF, byte(tx_frame_length>>8) & 0xFF, byte(tx_frame_length>>0) & 0xFF}, tx_buffer[0:data_length]...) 74 | } 75 | } else { 76 | msg_data = append([]byte{0x20 | byte(seq)}, tx_buffer[0:data_length]...) 77 | } 78 | 79 | msg := ic.Stack.make_tx_msg(ic.Stack.address.txid, msg_data) 80 | //fmt.Println("sending ", msg) 81 | // ic.Stack.txfn(msg) 82 | ms = append(ms, msg) 83 | seq = (seq + 1) & 0xF 84 | if len(tx_buffer) > 7 { 85 | tx_buffer = tx_buffer[data_length:] 86 | } else { 87 | break 88 | } 89 | } 90 | } 91 | return ms 92 | } 93 | 94 | func (ic *IsotpConnection) Send_and_no_wait_for_reply(payload []byte) []byte { 95 | 96 | msgs := ic.asSingleFrameOrMulti(payload) 97 | for _, msg := range msgs { 98 | ic.Stack.txfn(msg) 99 | } 100 | time.Sleep(time.Millisecond * 250) 101 | return []byte{} 102 | } 103 | func (ic *IsotpConnection) Send_and_wait_for_reply(payload []byte) []byte { 104 | 105 | msgs := ic.asSingleFrameOrMulti(payload) 106 | flow := []byte{} 107 | 108 | t1 := time.Now().Unix() 109 | for _, msg := range msgs { 110 | flow = []byte{} 111 | ic.Stack.txfn(msg) 112 | for { 113 | if time.Now().Unix()-t1 > 5 { 114 | fmt.Println("timeout1") 115 | break 116 | } 117 | msg, _ := ic.Stack.rxfn() 118 | if ic.Stack.address.is_for_me(msg) == false { 119 | continue 120 | } 121 | fmt.Println("got reply", msg.Payload) 122 | flow = append(flow, msg.Payload...) 123 | if true { 124 | break 125 | } 126 | } 127 | } 128 | return flow 129 | } 130 | func (ic *IsotpConnection) Send_and_grant_flow_request(payload []byte, length int) []byte { 131 | msg_data := append([]byte{byte(0x0 | len(payload))}, payload...) 132 | msg := ic.Stack.make_tx_msg(ic.Stack.address.txid, msg_data) 133 | ic.Stack.txfn(msg) 134 | flow := []byte{} 135 | // wait for flow request 136 | 137 | t1 := time.Now().Unix() 138 | for { 139 | if time.Now().Unix()-t1 > 2 { 140 | fmt.Println("timeout1") 141 | break 142 | } 143 | msg, _ := ic.Stack.rxfn() 144 | if ic.Stack.address.is_for_me(msg) == false { 145 | continue 146 | } 147 | flow = append(flow, msg.Payload...) 148 | if length < 7 { 149 | flow = append([]byte{0}, flow...) 150 | return flow 151 | } 152 | if true { 153 | break 154 | } 155 | } 156 | msg = ic.Stack.make_flow_control(CONTINUE) 157 | ic.Stack.txfn(msg) 158 | // read flow 159 | t1 = time.Now().Unix() 160 | for { 161 | if time.Now().Unix()-t1 > 2 { 162 | fmt.Println("timeout2") 163 | break 164 | } 165 | msg, _ := ic.Stack.rxfn() 166 | if ic.Stack.address.is_for_me(msg) == false { 167 | continue 168 | } 169 | flow = append(flow, msg.Payload[1:]...) 170 | if len(flow) > length { 171 | break 172 | } 173 | } 174 | 175 | return flow 176 | } 177 | 178 | func (ic *IsotpConnection) Open() { 179 | go func() { 180 | for { 181 | //fmt.Println(" [ml] toIsoTP") 182 | for { 183 | if ic.toIsoTPQueue.Len() == 0 { 184 | break 185 | } 186 | payload := ic.toIsoTPQueue.Get() 187 | ic.Stack.Send(payload) 188 | } 189 | 190 | ic.Stack.Process() 191 | 192 | //fmt.Println(" [ml] fromIsoTP") 193 | for { 194 | if ic.Stack.available() == false { 195 | break 196 | } 197 | stuff := ic.Stack.Recv() 198 | ic.fromIsoTPQueue.Put(stuff) 199 | } 200 | //fmt.Println(" [ml] sleep") 201 | time.Sleep(time.Millisecond * 10) 202 | } 203 | }() 204 | } 205 | 206 | func (ic *IsotpConnection) Empty_rxqueue() { 207 | ic.fromIsoTPQueue.Clear() 208 | } 209 | func (ic *IsotpConnection) Empty_txqueue() { 210 | ic.toIsoTPQueue.Clear() 211 | } 212 | func (ic *IsotpConnection) Send(payload []byte) { 213 | //msg := NewMessage(ic.Stack.address.rxid, payload) 214 | ic.toIsoTPQueue.Put(payload) 215 | } 216 | func (ic *IsotpConnection) Wait_frame() []byte { 217 | 218 | count := 0 219 | for { 220 | if ic.fromIsoTPQueue.Len() > 0 { 221 | m := ic.fromIsoTPQueue.Get() 222 | return m 223 | } 224 | time.Sleep(500 * time.Millisecond) 225 | count++ 226 | if count > 30 { 227 | break 228 | } 229 | } 230 | return []byte{} 231 | } 232 | -------------------------------------------------------------------------------- /isotp/isotp_test.go: -------------------------------------------------------------------------------- 1 | package isotp 2 | 3 | import "testing" 4 | import "os" 5 | 6 | import "time" 7 | import "github.com/andrewarrow/go-uds/util" 8 | 9 | import "fmt" 10 | 11 | func TestMain(m *testing.M) { 12 | RXID = 701 13 | TXID = 702 14 | test_rx_queue = util.NewInterfaceQueue() 15 | test_tx_queue = util.NewInterfaceQueue() 16 | a := NewAddress(RXID, TXID) 17 | test_stack = NewTransport(a, stack_rxfn, stack_txfn) 18 | os.Exit(m.Run()) 19 | } 20 | func TestRead15DigitAsciiString(t *testing.T) { 21 | //askForDid := []byte{byte(TXID), 0x22, 0xFF, 0xFD} 22 | //flowRequest := []byte{byte(RXID), 0x37, 45, 92} 23 | //flowGranted := []byte{byte(TXID), 0x39, 55, 52} 24 | //flowContent1 := []byte{byte(RXID), 0x37, 0xFF, 0xFD, 45, 92, 11, 12} 25 | //flowContent2 := []byte{byte(RXID), 45, 92, 11, 12, 13, 14, 15} 26 | //flowContent3 := []byte{byte(RXID), 11, 12, 13, 14} 27 | 28 | //msg := NewMessage(RXID, a) 29 | //test_rx_queue.Put(msg) 30 | //test_stack.Process() 31 | //eq(t, test_stack.Recv(), payload) 32 | } 33 | func TestSingleFrame(t *testing.T) { 34 | a := []byte{0x05, 0x11, 0x22, 0x33, 0x44, 0x55} 35 | msg := NewMessage(RXID, a) 36 | test_rx_queue.Put(msg) 37 | test_stack.Process() 38 | compareStrings(t, test_stack.Recv(), a[1:], "") 39 | } 40 | 41 | func TestMultiSingleFrame(t *testing.T) { 42 | test_stack.Process() 43 | test_stack.Process() 44 | a := []byte{0x05, 0x11, 0x22, 0x33, 0x44, 0x55} 45 | msg := NewMessage(RXID, a) 46 | test_rx_queue.Put(msg) 47 | test_stack.Process() 48 | compareStrings(t, test_stack.Recv(), a[1:], "") 49 | 50 | if len(test_stack.Recv()) != 0 { 51 | t.Fail() 52 | } 53 | test_stack.Process() 54 | if len(test_stack.Recv()) != 0 { 55 | t.Fail() 56 | } 57 | 58 | b := []byte{0x05, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE} 59 | msg = NewMessage(RXID, b) 60 | test_rx_queue.Put(msg) 61 | test_stack.Process() 62 | compareStrings(t, test_stack.Recv(), b[1:], "") 63 | if len(test_stack.Recv()) != 0 { 64 | t.Fail() 65 | } 66 | test_stack.Process() 67 | if len(test_stack.Recv()) != 0 { 68 | t.Fail() 69 | } 70 | } 71 | 72 | func TestMultipleSingleProcess(t *testing.T) { 73 | a := []byte{0x05, 0x11, 0x22, 0x33, 0x44, 0x55} 74 | b := []byte{0x05, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE} 75 | test_rx_queue.Put(NewMessage(RXID, a)) 76 | test_rx_queue.Put(NewMessage(RXID, b)) 77 | test_stack.Process() 78 | compareStrings(t, test_stack.Recv(), a[1:], "") 79 | compareStrings(t, test_stack.Recv(), b[1:], "") 80 | if len(test_stack.Recv()) != 0 { 81 | t.Fail() 82 | } 83 | } 84 | 85 | func TestMultiFrame(t *testing.T) { 86 | size := 10 87 | payload := make_payload(size, 0) 88 | simulate_rx(append([]byte{0x10, byte(size)}, payload[0:6]...)) 89 | simulate_rx(append([]byte{0x21}, payload[6:10]...)) 90 | 91 | test_stack.Process() 92 | eq(t, test_stack.Recv(), payload) 93 | ensureEmpty(t, test_stack.Recv()) 94 | } 95 | 96 | func TestTwoMultiFrame(t *testing.T) { 97 | size := 10 98 | payload := make_payload(size, 0) 99 | simulate_rx(append([]byte{0x10, byte(size)}, payload[0:6]...)) 100 | simulate_rx(append([]byte{0x21}, payload[6:10]...)) 101 | simulate_rx(append([]byte{0x10, byte(size)}, payload[0:6]...)) 102 | simulate_rx(append([]byte{0x21}, payload[6:10]...)) 103 | test_stack.Process() 104 | compareStrings(t, test_stack.Recv(), payload, "") 105 | compareStrings(t, test_stack.Recv(), payload, "") 106 | ensureEmpty(t, test_stack.Recv()) 107 | } 108 | func TestMultiFrameFlowControl(t *testing.T) { 109 | test_stack.Stmin = 0x02 110 | test_stack.Blocksize = 0x05 111 | size := 10 112 | payload := make_payload(size, 0) 113 | simulate_rx(append([]byte{0x10, byte(size)}, payload[0:6]...)) 114 | test_stack.Process() 115 | assert_sent_flow_control(t, 2, 5, 0) 116 | ensureEmpty(t, test_stack.Recv()) 117 | simulate_rx(append([]byte{0x21}, payload[6:10]...)) 118 | test_stack.Process() 119 | compareStrings(t, test_stack.Recv(), payload, "") 120 | ensureEmpty(t, test_stack.Recv()) 121 | } 122 | 123 | /* 124 | def test_receive_overflow_handling(self): 125 | def test_receive_overflow_handling_escape_sequence(self): 126 | */ 127 | 128 | func TestMultiFrameFlowControlPadding(t *testing.T) { 129 | test_stack.Stmin = 0x02 130 | test_stack.Blocksize = 0x05 131 | test_stack.tx_padding = 0x22 132 | size := 10 133 | payload := make_payload(size, 0) 134 | simulate_rx(append([]byte{0x10, byte(size)}, payload[0:6]...)) 135 | test_stack.Process() 136 | assert_sent_flow_control(t, 2, 5, test_stack.tx_padding) 137 | ensureEmpty(t, test_stack.Recv()) 138 | simulate_rx(append([]byte{0x21}, payload[6:10]...)) 139 | test_stack.Process() 140 | compareStrings(t, test_stack.Recv(), payload, "") 141 | ensureEmpty(t, test_stack.Recv()) 142 | } 143 | func TestLongMultiframeFlowControl(t *testing.T) { 144 | size := 30 145 | payload := make_payload(size, 0) 146 | test_stack.Stmin = 0x05 147 | test_stack.Blocksize = 0x3 148 | test_stack.tx_padding = 0 149 | simulate_rx(append([]byte{0x10, byte(size)}, payload[0:6]...)) 150 | test_stack.Process() 151 | assert_sent_flow_control(t, 5, 3, 0) 152 | ensureEmpty(t, test_stack.Recv()) 153 | simulate_rx(append([]byte{0x21}, payload[6:13]...)) 154 | test_stack.Process() 155 | ensureEmpty(t, test_stack.Recv()) 156 | simulate_rx(append([]byte{0x22}, payload[13:20]...)) 157 | test_stack.Process() 158 | ensureEmpty(t, test_stack.Recv()) 159 | simulate_rx(append([]byte{0x23}, payload[20:27]...)) 160 | test_stack.Process() 161 | assert_sent_flow_control(t, 5, 3, 0) 162 | ensureEmpty(t, test_stack.Recv()) 163 | simulate_rx(append([]byte{0x24}, payload[27:30]...)) 164 | test_stack.Process() 165 | compareStrings(t, test_stack.Recv(), payload, "TestLongMultiframeFlowControl") 166 | ensureEmpty(t, test_stack.Recv()) 167 | } 168 | func TestMultiFrameBadSeqNum(t *testing.T) { 169 | test_stack.Stmin = 0x02 170 | test_stack.Blocksize = 0x05 171 | size := 10 172 | payload := make_payload(size, 0) 173 | simulate_rx(append([]byte{0x10, byte(size)}, payload[0:6]...)) 174 | simulate_rx(append([]byte{0x22}, payload[6:10]...)) 175 | test_stack.Process() 176 | ensureEmpty(t, test_stack.Recv()) 177 | _, ok := get_tx_can_msg() 178 | if ok { 179 | fmt.Println("get_tx_can_msg has msg") 180 | t.Fail() 181 | } 182 | } 183 | 184 | func TestTimeoutFrameAfterFirst(t *testing.T) { 185 | test_stack.rx_consecutive_frame_timeout = 200 186 | test_stack.makeTimers() 187 | size := 10 188 | payload := make_payload(size, 0) 189 | simulate_rx(append([]byte{0x10, byte(size)}, payload[0:6]...)) 190 | test_stack.Process() 191 | time.Sleep(200 * time.Millisecond) 192 | simulate_rx(append([]byte{0x21}, payload[6:10]...)) 193 | test_stack.Process() 194 | ensureEmpty(t, test_stack.Recv()) 195 | } 196 | 197 | func TestRecoverTimeoutFrameAfterFirst(t *testing.T) { 198 | test_stack.rx_consecutive_frame_timeout = 200 199 | test_stack.makeTimers() 200 | size := 10 201 | payload1 := make_payload(size, 0) 202 | payload2 := make_payload(size, 1) 203 | compareNotEqStrings(t, payload1, payload2, "TestRecoverTimeoutFrameAfterFirst") 204 | simulate_rx(append([]byte{0x10, byte(size)}, payload1[0:6]...)) 205 | test_stack.Process() 206 | time.Sleep(200 * time.Millisecond) 207 | simulate_rx(append([]byte{0x21}, payload1[6:10]...)) 208 | test_stack.Process() 209 | ensureEmpty(t, test_stack.Recv()) 210 | simulate_rx(append([]byte{0x10, byte(size)}, payload2[0:6]...)) 211 | simulate_rx(append([]byte{0x21}, payload2[6:10]...)) 212 | test_stack.Process() 213 | compareStrings(t, test_stack.Recv(), payload2, "TestRecoverTimeoutFrameAfterFirst") 214 | } 215 | 216 | func TestReceive_multiframe_interrupting_another(t *testing.T) { 217 | size := 10 218 | payload1 := make_payload(size, 0) 219 | payload2 := make_payload(size, 1) 220 | simulate_rx(append([]byte{0x10, byte(size)}, payload1[0:6]...)) 221 | simulate_rx(append([]byte{0x10, byte(size)}, payload2[0:6]...)) 222 | simulate_rx(append([]byte{0x21}, payload2[6:10]...)) 223 | test_stack.Process() 224 | eq(t, test_stack.Recv(), payload2) 225 | ensureEmpty(t, test_stack.Recv()) 226 | } 227 | 228 | func TestReceive_single_frame_interrupt_multiframe_then_recover(t *testing.T) { 229 | payload1 := make_payload(16, 0) 230 | payload2 := make_payload(16, 1) 231 | sf_payload := make_payload(5, 2) 232 | simulate_rx(append([]byte{0x10, byte(16)}, payload1[0:6]...)) 233 | test_stack.Process() 234 | simulate_rx(append([]byte{0x21}, payload1[6:13]...)) 235 | simulate_rx(append([]byte{0x05}, sf_payload...)) 236 | simulate_rx(append([]byte{0x10, byte(16)}, payload2[0:6]...)) 237 | test_stack.Process() 238 | simulate_rx(append([]byte{0x21}, payload2[6:13]...)) 239 | simulate_rx(append([]byte{0x22}, payload2[13:16]...)) 240 | test_stack.Process() 241 | eq(t, test_stack.Recv(), sf_payload) 242 | eq(t, test_stack.Recv(), payload2) 243 | ensureEmpty(t, test_stack.Recv()) 244 | } 245 | func TestReceive_4095_multiframe(t *testing.T) { 246 | payload_size := 4095 247 | payload := make_payload(payload_size, 0) 248 | simulate_rx(append([]byte{0x1F, 0xFF}, payload[0:6]...)) 249 | n := 6 250 | seqnum := byte(1) 251 | for { 252 | simulate_rx(append([]byte{0x20 | (seqnum & 0xF)}, payload[n:min(n+7, payload_size)]...)) 253 | test_stack.Process() 254 | n += 7 255 | seqnum += 1 256 | if n > payload_size { 257 | break 258 | } 259 | } 260 | eq(t, test_stack.Recv(), payload) 261 | ensureEmpty(t, test_stack.Recv()) 262 | } 263 | func TestReceive_4095_multiframe_check_blocksize(t *testing.T) {} 264 | func TestReceive_data_length_12_bytes(t *testing.T) {} 265 | func TestReceive_data_length_5_bytes(t *testing.T) {} 266 | func TestReceive_data_length_12_but_set_8_bytes(t *testing.T) {} 267 | func TestSend_single_frame(t *testing.T) {} 268 | func TestPadding_single_frame(t *testing.T) {} 269 | func TestPadding_single_frame_dl_12_bytes(t *testing.T) {} 270 | func TestSend_multiple_single_frame_one_process(t *testing.T) {} 271 | func TestSend_small_multiframe(t *testing.T) {} 272 | func TestPadding_multi_frame(t *testing.T) {} 273 | func TestPadding_multi_frame_dl_12_bytes(t *testing.T) {} 274 | func TestSend_2_small_multiframe(t *testing.T) {} 275 | func TestSend_multiframe_flow_control_timeout(t *testing.T) {} 276 | func TestSend_multiframe_flow_control_timeout_recover(t *testing.T) {} 277 | func TestSend_unexpected_flow_control(t *testing.T) {} 278 | func TestSend_respect_wait_frame(t *testing.T) {} 279 | func TestSend_respect_wait_frame_but_timeout(t *testing.T) {} 280 | func TestSend_wait_frame_after_first_frame_wftmax_0(t *testing.T) {} 281 | func TestSend_wait_frame_after_consecutive_frame_wftmax_0(t *testing.T) {} 282 | func TestSend_wait_frame_after_first_frame_reach_max(t *testing.T) {} 283 | func TestSend_wait_frame_after_conscutive_frame_reach_max(t *testing.T) {} 284 | func TestSend_4095_multiframe_zero_stmin(t *testing.T) {} 285 | func TestSend_128_multiframe_variable_blocksize(t *testing.T) {} 286 | func TestSquash_timing_requirement(t *testing.T) {} 287 | 288 | /* 289 | def assert_tx_timing_spin_wait_for_msg(self, mintime, maxtime): 290 | msg = None 291 | diff = 0 292 | t = time.time() 293 | while msg is None: 294 | self.stack.process() 295 | msg = self.get_tx_can_msg() 296 | diff = time.time() - t 297 | self.assertLess(diff, maxtime, 'Timed out') # timeout 298 | self.assertGreater(diff, mintime, 'Stack sent a message too quickly') 299 | return msg 300 | */ 301 | func TestStmin_requirement(t *testing.T) { 302 | test_tx_queue = util.NewInterfaceQueue() 303 | stmin := byte(100) 304 | size := 30 305 | blocksize := byte(3) 306 | payload := make_payload(size, 0) 307 | test_stack.Send(payload) 308 | test_stack.Process() 309 | msg, _ := get_tx_can_msg() 310 | eq(t, msg.Payload, append([]byte{byte(0x10 | ((size >> 8) & 0xF)), byte(size & 0xFF)}, payload[:6]...)) 311 | simulate_rx_flowcontrol(SINGLE, stmin, blocksize) 312 | /* 313 | for { 314 | test_stack.Process() 315 | msg, ok := get_tx_can_msg() 316 | fmt.Println(msg, ok) 317 | time.Sleep(300 * time.Millisecond) 318 | } 319 | t = time.time() 320 | self.simulate_rx_flowcontrol(flow_status=0, stmin=stmin, blocksize=blocksize) 321 | msg = self.assert_tx_timing_spin_wait_for_msg(mintime=0.095, maxtime=1) 322 | self.assertEqual(msg.data, bytearray([0x21] + payload[6:13])) 323 | msg = self.assert_tx_timing_spin_wait_for_msg(mintime=0.095, maxtime=1) 324 | self.assertEqual(msg.data, bytearray([0x22] + payload[13:20])) 325 | msg = self.assert_tx_timing_spin_wait_for_msg(mintime=0.095, maxtime=1) 326 | self.assertEqual(msg.data, bytearray([0x23] + payload[20:27])) 327 | self.simulate_rx_flowcontrol(flow_status=0, stmin=stmin, blocksize=blocksize) 328 | msg = self.assert_tx_timing_spin_wait_for_msg(mintime=0.095, maxtime=1) 329 | self.assertEqual(msg.data, bytearray([0x24] + payload[27:30])) 330 | */ 331 | } 332 | func TestSend_nothing_with_empty_payload(t *testing.T) {} 333 | func TestSend_single_frame_after_empty_payload(t *testing.T) {} 334 | func TestSend_blocksize_zero(t *testing.T) {} 335 | func TestTransmit_data_length_12_bytes(t *testing.T) {} 336 | func TestTransmit_data_length_5_bytes(t *testing.T) {} 337 | -------------------------------------------------------------------------------- /isotp/message.go: -------------------------------------------------------------------------------- 1 | package isotp 2 | 3 | //import "fmt" 4 | 5 | type Message struct { 6 | Id int64 7 | Payload []byte 8 | extended_id bool 9 | } 10 | 11 | func NewMessage(id int64, payload []byte) Message { 12 | m := Message{} 13 | m.Id = id 14 | m.Payload = payload 15 | return m 16 | } 17 | 18 | func (m Message) ToBytes() []byte { 19 | return append([]byte{byte(m.Id)}, m.Payload...) 20 | } 21 | 22 | type PDU struct { 23 | msg Message 24 | flavor string 25 | length int 26 | payload []byte 27 | blocksize int 28 | stmin int 29 | stmin_sec int 30 | seqnum int 31 | flow string 32 | } 33 | 34 | func NewPDU(msg Message, start_of_data int, data_length int) PDU { 35 | pdu := PDU{} 36 | pdu.msg = msg 37 | 38 | if len(msg.Payload) > start_of_data { 39 | h := (msg.Payload[start_of_data] >> 4) & 0xF 40 | if h == 0 { 41 | pdu.flavor = SINGLE 42 | } else if h == 1 { 43 | pdu.flavor = FIRST 44 | } else if h == 2 { 45 | pdu.flavor = CONSECUTIVE 46 | } else if h == 3 { 47 | pdu.flavor = FLOW 48 | } 49 | } 50 | if pdu.flavor == SINGLE { 51 | lp := int(msg.Payload[start_of_data]) & 0xF 52 | if lp != 0 { 53 | pdu.length = lp 54 | pdu.payload = msg.Payload[1+start_of_data:][:lp] 55 | } else { 56 | pdu.length = int(msg.Payload[start_of_data+1]) 57 | pdu.payload = msg.Payload[2+start_of_data:][:pdu.length] 58 | } 59 | } else if pdu.flavor == FIRST { 60 | lp := ((int(msg.Payload[start_of_data]) & 0xF) << 8) | int(msg.Payload[start_of_data+1]) 61 | if lp != 0 { 62 | pdu.length = lp 63 | pdu.payload = msg.Payload[2+start_of_data:][:min(lp, data_length-2-start_of_data)] 64 | } else { 65 | data_temp := msg.Payload[start_of_data:] 66 | pdu.length = int((data_temp[2] << 24) | (data_temp[3] << 16) | (data_temp[4] << 8) | (data_temp[5] << 0)) 67 | pdu.payload = msg.Payload[6+start_of_data:][:min(pdu.length, data_length-6-start_of_data)] 68 | } 69 | } else if pdu.flavor == CONSECUTIVE { 70 | pdu.seqnum = int(msg.Payload[start_of_data]) & 0xF 71 | if data_length >= len(msg.Payload) { 72 | pdu.payload = msg.Payload[start_of_data+1:] 73 | } else { 74 | pdu.payload = msg.Payload[start_of_data+1 : data_length] 75 | } 76 | } else if pdu.flavor == FLOW { 77 | f := int(msg.Payload[start_of_data]) & 0xF 78 | if f == 0 { 79 | pdu.flow = SINGLE 80 | } else if f == 1 { 81 | pdu.flow = FIRST 82 | } else if f == 2 { 83 | pdu.flow = CONSECUTIVE 84 | } else if f == 3 { 85 | pdu.flow = FLOW 86 | } 87 | 88 | pdu.blocksize = int(msg.Payload[1+start_of_data]) 89 | stmin_temp := int(msg.Payload[2+start_of_data]) 90 | 91 | if stmin_temp >= 0 && stmin_temp <= 0x7F { 92 | pdu.stmin_sec = stmin_temp / 1000 93 | } else if stmin_temp >= 0xf1 && stmin_temp <= 0xF9 { 94 | pdu.stmin_sec = (stmin_temp - 0xF0) / 10000 95 | } 96 | pdu.stmin = stmin_temp 97 | 98 | } 99 | return pdu 100 | } 101 | 102 | func min(a, b int) int { 103 | if a < b { 104 | return a 105 | } 106 | return b 107 | } 108 | -------------------------------------------------------------------------------- /isotp/rx.go: -------------------------------------------------------------------------------- 1 | package isotp 2 | 3 | import "fmt" 4 | 5 | func (t *Transport) process_rx(msg Message) { 6 | if t.address.is_for_me(msg) == false { 7 | // fmt.Println("ID", msg.Id) 8 | return 9 | } 10 | //fmt.Println("calling process_rx ", msg) 11 | pdu := NewPDU(msg, t.address.rx_prefix_size, t.data_length) 12 | //fmt.Println(pdu.flavor) 13 | if t.timer_rx_cf.is_timed_out() { 14 | //fmt.Println("Reception of CONSECUTIVE_FRAME timed out.") 15 | t.stop_receiving() 16 | } 17 | if pdu.flavor == FLOW { 18 | t.last_flow_control_frame = &pdu 19 | if t.rx_state == WAIT { 20 | if pdu.flow == WAIT || pdu.flow == CONTINUE { 21 | t.timer_rx_cf.start() 22 | } 23 | } 24 | return 25 | } 26 | 27 | if t.rx_state == IDLE { 28 | t.rx_frame_length = 0 29 | t.timer_rx_cf.stop() 30 | if pdu.flavor == SINGLE && pdu.length > 0 { 31 | t.rx_queue.Put(pdu.payload) 32 | } else if pdu.flavor == FIRST { 33 | t.start_reception_after_first_frame(pdu) 34 | } else if pdu.flavor == CONSECUTIVE { 35 | fmt.Println("Received a ConsecutiveFrame while reception was idle.") 36 | } 37 | } else if t.rx_state == WAIT { 38 | if pdu.flavor == SINGLE && pdu.length > 0 { 39 | t.rx_queue.Put(pdu.payload) 40 | t.rx_state = IDLE 41 | fmt.Println("Reception of IsoTP frame interrupted with a new SingleFrame") 42 | } else if pdu.flavor == FIRST { 43 | t.start_reception_after_first_frame(pdu) 44 | fmt.Println("Reception of IsoTP frame interrupted with a new FirstFrame") 45 | } else if pdu.flavor == CONSECUTIVE { 46 | t.timer_rx_cf.start() 47 | expected_seqnum := (t.last_seqnum + 1) & 0xF 48 | if pdu.seqnum == expected_seqnum { 49 | t.last_seqnum = pdu.seqnum 50 | 51 | bytes_to_receive := (t.rx_frame_length - len(t.rx_buffer)) 52 | //in python they do t.rx_buffer = append(t.rx_buffer, pdu.payload[:bytes_to_receive]...) 53 | if len(pdu.payload) > bytes_to_receive { 54 | t.rx_buffer = append(t.rx_buffer, pdu.payload[0:bytes_to_receive]...) 55 | } else { 56 | t.rx_buffer = append(t.rx_buffer, pdu.payload...) 57 | } 58 | 59 | if len(t.rx_buffer) >= t.rx_frame_length { 60 | t.rx_queue.Put(append([]byte{}, t.rx_buffer...)) 61 | t.stop_receiving() 62 | } else { 63 | t.rx_block_counter += 1 64 | if (t.Blocksize > 0) && (t.rx_block_counter%t.Blocksize == 0) { 65 | t.pending_flow_control_tx = true 66 | t.timer_rx_cf.stop() 67 | } 68 | } 69 | } else { 70 | t.stop_receiving() 71 | fmt.Println("Received a ConsecutiveFrame with wrong SequenceNumber") 72 | } 73 | } 74 | } 75 | //fmt.Println(pdu) 76 | } 77 | -------------------------------------------------------------------------------- /isotp/test_helper.go: -------------------------------------------------------------------------------- 1 | package isotp 2 | 3 | import "testing" 4 | import "github.com/andrewarrow/go-uds/util" 5 | import "fmt" 6 | 7 | var test_rx_queue *util.InterfaceQueue 8 | var test_tx_queue *util.InterfaceQueue 9 | var test_stack *Transport 10 | var RXID int64 11 | var TXID int64 12 | 13 | func eq(t *testing.T, a, b interface{}) { 14 | as := fmt.Sprintf("%v", a) 15 | bs := fmt.Sprintf("%v", b) 16 | if as != bs { 17 | fmt.Printf("%s: %s != %s\n", t.Name(), as, bs) 18 | t.Fail() 19 | } 20 | } 21 | func neq(t *testing.T, a, b interface{}) { 22 | as := fmt.Sprintf("%v", a) 23 | bs := fmt.Sprintf("%v", b) 24 | if as == bs { 25 | fmt.Printf("%s: %s == %s\n", t.Name(), as, bs) 26 | t.Fail() 27 | } 28 | } 29 | func compareStrings(t *testing.T, a, b interface{}, msg string) { 30 | as := fmt.Sprintf("%v", a) 31 | bs := fmt.Sprintf("%v", b) 32 | if as != bs { 33 | fmt.Printf("%s: %s != %s\n", msg, as, bs) 34 | t.Fail() 35 | } 36 | } 37 | func compareNotEqStrings(t *testing.T, a, b interface{}, msg string) { 38 | as := fmt.Sprintf("%v", a) 39 | bs := fmt.Sprintf("%v", b) 40 | if as == bs { 41 | fmt.Printf("%s: %s == %s\n", msg, as, bs) 42 | t.Fail() 43 | } 44 | } 45 | 46 | func make_payload(size, start_val int) []byte { 47 | a := []byte{} 48 | i := start_val 49 | for { 50 | a = append(a, byte(i%0x100)) 51 | i++ 52 | if i >= start_val+size { 53 | break 54 | } 55 | } 56 | return a 57 | } 58 | 59 | func simulate_rx(b []byte) { 60 | test_rx_queue.Put(NewMessage(RXID, b)) 61 | } 62 | func flow_status_byte(flavor string) byte { 63 | if flavor == FIRST { 64 | return 1 65 | } 66 | if flavor == CONSECUTIVE { 67 | return 2 68 | } 69 | if flavor == FLOW { 70 | return 3 71 | } 72 | return 0 73 | } 74 | func simulate_rx_flowcontrol(flow string, stmin, blocksize byte) { 75 | fsb := flow_status_byte(flow) 76 | data := []byte{0x30 | (fsb & 0xF), blocksize, stmin} 77 | simulate_rx(data) 78 | } 79 | 80 | func ensureEmpty(t *testing.T, b []byte) { 81 | if len(b) != 0 { 82 | t.Logf("%v", b) 83 | t.Fail() 84 | } 85 | } 86 | func assert_sent_flow_control(t *testing.T, stmin, blocksize, tx_padding int) { 87 | msg, ok := get_tx_can_msg() 88 | if ok == false { 89 | fmt.Println("get_tx_can_msg has no msg") 90 | t.Fail() 91 | } 92 | data := []byte{} 93 | data = append(data, 0x30, byte(blocksize), byte(stmin)) 94 | if tx_padding > 0 { 95 | for { 96 | data = append(data, byte(tx_padding)) 97 | if len(data) == 8 { 98 | break 99 | } 100 | } 101 | } 102 | 103 | compareStrings(t, msg.Payload, data, "hi") 104 | } 105 | 106 | func stack_rxfn() (Message, bool) { 107 | if test_rx_queue.Len() > 0 { 108 | e := test_rx_queue.Get() 109 | return e.(Message), true 110 | } 111 | return Message{}, false 112 | } 113 | func get_tx_can_msg() (Message, bool) { 114 | if test_tx_queue.Len() > 0 { 115 | e := test_tx_queue.Get() 116 | return e.(Message), true 117 | } 118 | return Message{}, false 119 | } 120 | func stack_txfn(m Message) { 121 | test_tx_queue.Put(m) 122 | } 123 | -------------------------------------------------------------------------------- /isotp/timer.go: -------------------------------------------------------------------------------- 1 | package isotp 2 | 3 | import "time" 4 | 5 | type Timer struct { 6 | timeout float32 7 | startedAt int64 8 | } 9 | 10 | func NewTimer(timeout float32) *Timer { 11 | t := Timer{} 12 | t.timeout = timeout 13 | return &t 14 | } 15 | 16 | func (t *Timer) is_timed_out() bool { 17 | if t.startedAt == 0 { 18 | return false 19 | } 20 | if ((time.Now().UnixNano() / 1000 / 1000) - t.startedAt) > int64(t.timeout*1000.0) { 21 | return true 22 | } 23 | return false 24 | } 25 | func (t *Timer) stop() { 26 | t.startedAt = 0 27 | } 28 | func (t *Timer) start() { 29 | t.startedAt = time.Now().UnixNano() / 1000 / 1000 30 | } 31 | func (t *Timer) set_timeout(msec int) { 32 | t.timeout = float32(msec) / 1000.0 33 | } 34 | -------------------------------------------------------------------------------- /isotp/transport.go: -------------------------------------------------------------------------------- 1 | package isotp 2 | 3 | import "github.com/andrewarrow/go-uds/util" 4 | 5 | //import "fmt" 6 | 7 | const FLOW = "FLOW" 8 | const WAIT = "WAIT" 9 | const CONTINUE = "CONTINUE" 10 | const OVERFLOW = "OVERFLOW" 11 | const IDLE = "IDLE" 12 | const TRANSMIT = "TRANSMIT" 13 | const SINGLE = "SINGLE" 14 | const FIRST = "FIRST" 15 | const CONSECUTIVE = "CONSECUTIVE" 16 | 17 | type Transport struct { 18 | rxfn func() (Message, bool) 19 | txfn func(m Message) 20 | rx_queue *util.Queue 21 | tx_queue *util.Queue 22 | address Address 23 | rx_state string 24 | tx_state string 25 | last_seqnum int 26 | rx_block_counter int 27 | rx_frame_length int 28 | tx_frame_length int 29 | rx_buffer []byte 30 | pending_flow_control_tx bool 31 | last_flow_control_frame *PDU 32 | Stmin int 33 | Blocksize int 34 | squash_stmin_requirement bool 35 | rx_flowcontrol_timeout int 36 | rx_consecutive_frame_timeout int 37 | wftmax int 38 | data_length int 39 | timer_rx_cf *Timer 40 | timer_rx_fc *Timer 41 | timer_tx_stmin *Timer 42 | tx_padding int 43 | tx_buffer []byte 44 | remote_blocksize int 45 | tx_block_counter int 46 | tx_seqnum int 47 | wft_counter int 48 | } 49 | 50 | func NewTransport(a Address, rxfn func() (Message, bool), txfn func(m Message)) *Transport { 51 | t := Transport{} 52 | t.rxfn = rxfn 53 | t.txfn = txfn 54 | t.rx_queue = util.NewQueue() 55 | t.tx_queue = util.NewQueue() 56 | t.address = a 57 | t.rx_state = IDLE 58 | t.tx_state = IDLE 59 | t.rx_buffer = []byte{} 60 | t.rx_frame_length = 0 61 | t.Stmin = 1 62 | t.Blocksize = 8 63 | t.data_length = 8 64 | t.rx_flowcontrol_timeout = 1000 65 | t.rx_consecutive_frame_timeout = 1000 66 | t.makeTimers() 67 | return &t 68 | } 69 | 70 | func (t *Transport) makeTimers() { 71 | t.timer_rx_fc = NewTimer(float32(t.rx_flowcontrol_timeout) / 1000.0) 72 | t.timer_rx_cf = NewTimer(float32(t.rx_consecutive_frame_timeout) / 1000.0) 73 | t.timer_tx_stmin = NewTimer(float32(t.rx_consecutive_frame_timeout) / 1000.0) 74 | } 75 | 76 | func (t *Transport) Process() { 77 | i := 0 78 | for { 79 | msg, ok := t.rxfn() 80 | if ok == false { 81 | break 82 | } 83 | t.process_rx(msg) 84 | i++ 85 | if i > 150 { 86 | break 87 | } 88 | } 89 | 90 | for { 91 | msg, ok := t.process_tx() 92 | if ok == false { 93 | break 94 | } 95 | t.txfn(msg) 96 | } 97 | } 98 | 99 | func (t *Transport) start_reception_after_first_frame(frame PDU) { 100 | t.last_seqnum = 0 101 | t.rx_block_counter = 0 102 | t.rx_frame_length = frame.length 103 | t.rx_state = WAIT 104 | t.rx_buffer = append([]byte{}, frame.payload...) 105 | t.pending_flow_control_tx = true 106 | //fmt.Println("start_reception_after_first_frame", t.timer_rx_cf.startedAt) 107 | t.timer_rx_cf.start() 108 | //fmt.Println("start_reception_after_first_frame", t.timer_rx_cf.startedAt) 109 | } 110 | 111 | func (t *Transport) Send(data []byte) { 112 | t.tx_queue.Put(data) 113 | //self.tx_queue.put( {'data':data, 'target_address_type':target_address_type}) # frame is always an IsoTPFrame here 114 | } 115 | func (t *Transport) Recv() []byte { 116 | if t.rx_queue.Len() == 0 { 117 | return []byte{} 118 | } 119 | return t.rx_queue.Get() 120 | } 121 | 122 | func (t *Transport) stop_receiving() { 123 | t.rx_state = IDLE 124 | t.rx_buffer = []byte{} 125 | t.pending_flow_control_tx = false 126 | t.last_flow_control_frame = nil 127 | t.timer_rx_cf.stop() 128 | } 129 | func (t *Transport) stop_sending() { 130 | t.tx_state = IDLE 131 | t.tx_buffer = []byte{} 132 | t.tx_frame_length = 0 133 | t.timer_rx_fc.stop() 134 | t.timer_tx_stmin.stop() 135 | t.remote_blocksize = 0 136 | t.tx_block_counter = 0 137 | t.tx_seqnum = 0 138 | t.wft_counter = 0 139 | } 140 | 141 | func (t *Transport) available() bool { 142 | return t.rx_queue.Len() > 0 143 | } 144 | -------------------------------------------------------------------------------- /isotp/tx.go: -------------------------------------------------------------------------------- 1 | package isotp 2 | 3 | import "fmt" 4 | 5 | func (t *Transport) process_tx() (Message, bool) { 6 | m := Message{} 7 | 8 | if t.pending_flow_control_tx { 9 | t.pending_flow_control_tx = false 10 | return t.make_flow_control(CONTINUE), true 11 | } 12 | 13 | flow_control_frame := t.last_flow_control_frame 14 | 15 | if flow_control_frame != nil { 16 | if flow_control_frame.flow == OVERFLOW { 17 | t.stop_sending() 18 | return m, false 19 | } 20 | if t.tx_state == IDLE { 21 | fmt.Println("Received a FlowControl message while transmission was Idle.") 22 | } else { 23 | if flow_control_frame.flow == WAIT { 24 | if t.wftmax == 0 { 25 | fmt.Println("Received a FlowControl requesting to wait, but fwtmax is set to 0") 26 | } else if t.wft_counter >= t.wftmax { 27 | fmt.Println("Received d wait frame which is the maximum set in params.wftmax") 28 | t.stop_sending() 29 | } else { 30 | t.wft_counter += 1 31 | if t.tx_state == WAIT || t.tx_state == TRANSMIT { 32 | t.tx_state = WAIT 33 | t.timer_rx_fc.start() 34 | } 35 | } 36 | } else if flow_control_frame.flow == CONTINUE && !t.timer_rx_fc.is_timed_out() { 37 | t.wft_counter = 0 38 | t.timer_rx_fc.stop() 39 | t.timer_tx_stmin.set_timeout(flow_control_frame.stmin_sec) 40 | t.remote_blocksize = flow_control_frame.blocksize 41 | if t.tx_state == WAIT { 42 | t.tx_block_counter = 0 43 | t.timer_tx_stmin.start() 44 | } 45 | t.tx_state = TRANSMIT 46 | } 47 | } 48 | } 49 | 50 | if t.timer_rx_fc.is_timed_out() { 51 | fmt.Println("Reception of FlowControl timed out. Stopping transmission") 52 | t.stop_sending() 53 | } 54 | 55 | if t.tx_state != IDLE && len(t.tx_buffer) == 0 { 56 | t.stop_sending() 57 | } 58 | 59 | if t.tx_state == IDLE { 60 | if t.tx_queue.Len() > 0 { 61 | payload := t.tx_queue.Get() 62 | t.tx_buffer = payload 63 | size_on_first_byte := false 64 | if len(t.tx_buffer) <= 7 { 65 | size_on_first_byte = true 66 | } 67 | size_offset := 2 68 | if size_on_first_byte { 69 | size_offset = 1 70 | } 71 | msg_data := []byte{} 72 | if len(t.tx_buffer) <= t.data_length-size_offset-len(t.address.tx_payload_prefix) { 73 | if size_on_first_byte { 74 | msg_data = append([]byte{byte(0x0 | len(t.tx_buffer))}, t.tx_buffer...) 75 | } else { 76 | msg_data = append([]byte{0x0, byte(len(t.tx_buffer))}, t.tx_buffer...) 77 | } 78 | 79 | } else { 80 | t.tx_frame_length = len(t.tx_buffer) 81 | encode_length_on_2_first_bytes := false 82 | if t.tx_frame_length <= 4095 { 83 | encode_length_on_2_first_bytes = true 84 | } 85 | data_length := 0 86 | if encode_length_on_2_first_bytes { 87 | data_length = t.data_length - 2 - len(t.address.tx_payload_prefix) 88 | msg_data = append([]byte{0x10 | byte((t.tx_frame_length>>8)&0xF), byte(t.tx_frame_length & 0xFF)}, t.tx_buffer[:data_length]...) 89 | } else { 90 | data_length = t.data_length - 6 - len(t.address.tx_payload_prefix) 91 | msg_data = append([]byte{0x10, 0x00, byte(t.tx_frame_length>>24) & 0xFF, byte(t.tx_frame_length>>16) & 0xFF, byte(t.tx_frame_length>>8) & 0xFF, byte(t.tx_frame_length>>0) & 0xFF}, t.tx_buffer[:data_length]...) 92 | } 93 | t.tx_buffer = t.tx_buffer[data_length:] 94 | t.tx_state = WAIT 95 | t.tx_seqnum = 1 96 | t.timer_rx_fc.start() 97 | 98 | } 99 | m = t.make_tx_msg(t.address.txid, msg_data) 100 | return m, true 101 | } 102 | } else if t.tx_state == WAIT { 103 | } else if t.tx_state == TRANSMIT { 104 | if t.timer_tx_stmin.is_timed_out() || t.squash_stmin_requirement { 105 | data_length := t.data_length - 1 - len(t.address.tx_payload_prefix) 106 | msg_data := append([]byte{0x20 | byte(t.tx_seqnum)}, t.tx_buffer[:data_length]...) 107 | m = t.make_tx_msg(t.address.txid, msg_data) 108 | t.tx_buffer = t.tx_buffer[data_length:] 109 | t.tx_seqnum = (t.tx_seqnum + 1) & 0xF 110 | t.timer_tx_stmin.start() 111 | t.tx_block_counter += 1 112 | return m, true 113 | } 114 | if t.remote_blocksize != 0 && t.tx_block_counter >= t.remote_blocksize { 115 | t.tx_state = WAIT 116 | t.timer_rx_fc.start() 117 | } 118 | 119 | } 120 | return m, false 121 | } 122 | 123 | func (t *Transport) make_flow_control(status string) Message { 124 | payload := craft_flow_control_data(status, t.Blocksize, t.Stmin) 125 | return t.make_tx_msg(t.address._get_tx_arbitraton_id(Physical), append(t.address.tx_payload_prefix, payload...)) 126 | } 127 | 128 | func craft_flow_control_data(status string, blocksize int, stmin int) []byte { 129 | f := 0 130 | if status == WAIT { 131 | f = 1 132 | } else if status == OVERFLOW { 133 | f = 2 134 | } 135 | 136 | return []byte{byte(0x30 | (f)&0xF), byte(blocksize & 0xFF), byte(stmin & 0xFF)} 137 | } 138 | 139 | func (t *Transport) pad_message_data(payload []byte) []byte { 140 | if len(payload) < t.data_length && t.tx_padding > 0 { 141 | a := []byte{} 142 | for { 143 | a = append(a, byte(t.tx_padding&0xFF)) 144 | if len(a) == t.data_length-len(payload) { 145 | break 146 | } 147 | } 148 | return append(payload, a...) 149 | } 150 | return payload 151 | } 152 | 153 | func (t *Transport) make_tx_msg(arbitration_id int64, payload []byte) Message { 154 | data := t.pad_message_data(payload) 155 | m := NewMessage(arbitration_id, data) 156 | m.extended_id = t.address.is_29bits() 157 | return m 158 | } 159 | -------------------------------------------------------------------------------- /uds/client.go: -------------------------------------------------------------------------------- 1 | package uds 2 | 3 | import "fmt" 4 | import "github.com/andrewarrow/go-uds/isotp" 5 | import "errors" 6 | import "encoding/binary" 7 | 8 | type Client struct { 9 | conn isotp.AnyConn 10 | timeout float32 11 | suppress_positive_response bool 12 | Data_identifiers map[int]int 13 | Release func() int 14 | } 15 | 16 | func NewClient(connection isotp.AnyConn, timeout float32, rf func() int) *Client { 17 | c := Client{} 18 | c.conn = connection 19 | c.suppress_positive_response = true 20 | c.Data_identifiers = map[int]int{} 21 | c.Release = rf 22 | return &c 23 | } 24 | func (c *Client) send_request(request *Request) *Response { 25 | //fmt.Println(111) 26 | c.conn.Empty_rxqueue() 27 | payload := []byte{} 28 | //override_suppress_positive_response := false 29 | if c.suppress_positive_response && request.use_subfunction { 30 | payload = request.get_payload(true) 31 | //override_suppress_positive_response = true 32 | } else { 33 | payload = request.get_payload(false) 34 | } 35 | //fmt.Println(888, payload) 36 | c.conn.Send(payload) 37 | data := c.conn.Wait_frame() 38 | //fmt.Println(777, data) 39 | response := response_from_payload(data) 40 | return response 41 | } 42 | 43 | func (c *Client) Read_data_by_id(data []int) *Response { 44 | req := service_read_data_by_id_make_request(data) 45 | response := c.send_request(req) 46 | c.service_read_data_by_id_handle_response(response) 47 | return response 48 | } 49 | func (c *Client) Simple_read_data_by_id(did, length int, flavor string) string { 50 | request := service_read_data_by_id_make_request([]int{did}) 51 | payload := request.get_payload(false) 52 | data := c.conn.Send_and_grant_flow_request(payload, length) 53 | if flavor == "text" { 54 | if len(data) > 5 { 55 | return string(data[5:]) 56 | } 57 | return string(data) 58 | } 59 | if len(data) > 5 { 60 | return fmt.Sprintf("%v", data[5:]) 61 | } 62 | return fmt.Sprintf("%v", data) 63 | } 64 | func (c *Client) Request_download(ml MemoryLocation) int { 65 | request := service_request_download_make_request(ml) 66 | payload := request.get_payload(false) 67 | fmt.Println("client, Request_download", payload) 68 | data := c.conn.Send_and_wait_for_reply(payload) 69 | data = data[2:] 70 | 71 | fmt.Println(data) 72 | todecode := []byte{0, 0, 0, 0, 0, 0, 0, 0} 73 | lfid := int(data[0] >> 4) 74 | i := 1 75 | for { 76 | if i >= lfid+1 { 77 | break 78 | } 79 | todecode[7-(i-1)] = data[lfid+1-i] 80 | i += 1 81 | } 82 | 83 | fmt.Println(lfid, todecode, int(binary.BigEndian.Uint64(todecode))) 84 | return int(binary.BigEndian.Uint64(todecode)) 85 | } 86 | func (c *Client) Transfer_data(i int, data []byte) string { 87 | request := service_transfer_data_make_request(i, data) 88 | payload := request.get_payload(false) 89 | response := c.conn.Send_and_no_wait_for_reply(payload) 90 | return fmt.Sprintf("%v", response) 91 | } 92 | func (c *Client) Request_transfer_exit(crc int) string { 93 | r := NewRequest(0x37, "transfer_exit") 94 | bs := make([]byte, 4) 95 | binary.BigEndian.PutUint32(bs, uint32(crc)) 96 | fmt.Println(bs) 97 | r.data = bs 98 | r.use_subfunction = false 99 | payload := r.get_payload(false) 100 | c.conn.Send_and_no_wait_for_reply(payload) 101 | return fmt.Sprintf("%v", crc) 102 | } 103 | func (c *Client) Change_session(session int) string { 104 | request := service_diagnostic_session_make_request(session) 105 | payload := request.get_payload(false) 106 | data := c.conn.Send_and_wait_for_reply(payload) 107 | return fmt.Sprintf("%v", data) 108 | } 109 | func (c *Client) Unlock_security_access(level int, algo func(seed []byte, params int) []byte) error { 110 | request := service_security_access_make_request(level, "request_seed", []byte{}) 111 | payload := request.get_payload(false) 112 | seed := c.conn.Send_and_wait_for_reply(payload) 113 | seed = seed[3:] 114 | fmt.Printf("%v", seed) 115 | 116 | request = service_security_access_make_request(level, "send_key", algo(seed, 0)) 117 | payload = request.get_payload(false) 118 | data := c.conn.Send_and_wait_for_reply(payload) 119 | fmt.Printf("%v", data) 120 | 121 | if data[1] == 127 { 122 | return errors.New("Authenticaiton error") 123 | } 124 | return nil 125 | } 126 | -------------------------------------------------------------------------------- /uds/connections.go: -------------------------------------------------------------------------------- 1 | package uds 2 | 3 | import "time" 4 | 5 | //import "fmt" 6 | import "github.com/andrewarrow/go-uds/util" 7 | import "sync" 8 | 9 | type QueueConnection struct { 10 | name string 11 | mtu int 12 | fromuser *util.Queue 13 | fromuserm sync.Mutex 14 | touser *util.Queue 15 | touserm sync.Mutex 16 | } 17 | 18 | func NewQueueConnection(name string, mtu int) *QueueConnection { 19 | q := QueueConnection{} 20 | q.name = name 21 | q.mtu = mtu 22 | q.fromuser = util.NewQueue() 23 | q.touser = util.NewQueue() 24 | return &q 25 | } 26 | 27 | func (q *QueueConnection) Send_and_no_wait_for_reply(payload []byte) []byte { 28 | return []byte{} 29 | } 30 | func (q *QueueConnection) Send_and_wait_for_reply(payload []byte) []byte { 31 | return []byte{} 32 | } 33 | func (q *QueueConnection) Send_and_grant_flow_request(payload []byte, length int) []byte { 34 | return []byte{} 35 | } 36 | func (q *QueueConnection) Empty_rxqueue() { 37 | q.fromuserm.Lock() 38 | defer q.fromuserm.Unlock() 39 | q.fromuser.Clear() 40 | } 41 | func (q *QueueConnection) Empty_txqueue() { 42 | q.touserm.Lock() 43 | defer q.touserm.Unlock() 44 | q.touser.Clear() 45 | } 46 | func (q *QueueConnection) Send(payload []byte) { 47 | //fmt.Printf(" sending to touser %v\n", payload) 48 | q.touserm.Lock() 49 | defer q.touserm.Unlock() 50 | q.touser.Put(payload) 51 | } 52 | func (q *QueueConnection) touser_frame() []byte { 53 | for { 54 | q.touserm.Lock() 55 | if q.touser.Len() > 0 { 56 | val := q.touser.Get() 57 | q.touserm.Unlock() 58 | //fmt.Printf(" reading from touser %v\n", val) 59 | return val 60 | } 61 | q.touserm.Unlock() 62 | time.Sleep(1 * time.Millisecond) 63 | } 64 | return []byte{} 65 | } 66 | func (q *QueueConnection) Wait_frame() []byte { 67 | for { 68 | q.fromuserm.Lock() 69 | if q.fromuser.Len() > 0 { 70 | val := q.fromuser.Get() 71 | q.fromuserm.Unlock() 72 | //fmt.Printf(" reading from fromuser %v\n", val) 73 | return val 74 | } 75 | q.fromuserm.Unlock() 76 | time.Sleep(1 * time.Millisecond) 77 | } 78 | return []byte{} 79 | } 80 | -------------------------------------------------------------------------------- /uds/memory_location.go: -------------------------------------------------------------------------------- 1 | package uds 2 | 3 | import "encoding/binary" 4 | //import "fmt" 5 | 6 | var address_map = map[int]int{ 7 | 8: 1, 8 | 16: 2, 9 | 24: 3, 10 | 32: 4, 11 | 40: 5, 12 | } 13 | var memsize_map = map[int]int{ 14 | 8: 1, 15 | 16: 2, 16 | 24: 3, 17 | 32: 4, 18 | } 19 | 20 | type MemoryLocation struct { 21 | address int 22 | length int 23 | address_format int 24 | memorysize_format int 25 | } 26 | 27 | func NewMemoryLocation(address, length, address_format, memorysize_format int) *MemoryLocation { 28 | m := MemoryLocation{} 29 | m.address = address 30 | m.length = length 31 | m.address_format = address_format 32 | m.memorysize_format = memorysize_format 33 | return &m 34 | } 35 | func (m *MemoryLocation) AlfidByte() byte { 36 | return byte(((memsize_map[m.memorysize_format] << 4) | (address_map[m.address_format])) & 0xFF) 37 | } 38 | func DataFormatId() byte { 39 | compression := 0 40 | encryption := 0 41 | return byte(((compression & 0xF) << 4) | (encryption & 0xF)) 42 | } 43 | 44 | func (m *MemoryLocation) GetAddressBytes() []byte { 45 | //n := address_map[m.address_format] 46 | bs := make([]byte, 8) 47 | binary.BigEndian.PutUint64(bs, uint64(m.address)) 48 | 49 | return bs[4:8] 50 | } 51 | func (m *MemoryLocation) GetMemorySizeBytes() []byte { 52 | //n := memsize_map[m.memorysize_format] 53 | bs := make([]byte, 8) 54 | binary.BigEndian.PutUint64(bs, uint64(m.length)) 55 | 56 | return bs[4:8] 57 | } 58 | 59 | /* 60 | 61 | def set_format_if_none(self, address_format=None, memorysize_format=None): 62 | previous_address_format = self.address_format 63 | previous_memorysize_format = self.memorysize_format 64 | try: 65 | if address_format is not None: 66 | if self.address_format is None: 67 | self.address_format = address_format 68 | 69 | if memorysize_format is not None: 70 | if self.memorysize_format is None: 71 | self.memorysize_format=memorysize_format 72 | 73 | address_format = self.address_format if self.address_format is not None else self.autosize_address(self.address) 74 | memorysize_format = self.memorysize_format if self.memorysize_format is not None else self.autosize_memorysize(self.memorysize) 75 | 76 | self.alfid = AddressAndLengthFormatIdentifier(memorysize_format=memorysize_format, address_format=address_format) 77 | except: 78 | self.address_format = previous_address_format 79 | self.memorysize_format = previous_memorysize_format 80 | raise 81 | 82 | def autosize_address(self, val): 83 | fmt = math.ceil(val.bit_length()/8)*8 84 | if fmt > 40: 85 | raise ValueError("address size must be smaller or equal than 40 bits") 86 | return fmt 87 | 88 | def autosize_memorysize(self, val): 89 | fmt = math.ceil(val.bit_length()/8)*8 90 | if fmt > 32: 91 | raise ValueError("memory size must be smaller or equal than 32 bits") 92 | return fmt 93 | 94 | def get_address_bytes(self): 95 | n = AddressAndLengthFormatIdentifier.address_map[self.alfid.address_format] 96 | 97 | data = struct.pack('>q', self.address) 98 | return data[-n:] 99 | 100 | 101 | def get_memorysize_bytes(self): 102 | n = AddressAndLengthFormatIdentifier.memsize_map[self.alfid.memorysize_format] 103 | 104 | data = struct.pack('>q', self.memorysize) 105 | return data[-n:] 106 | 107 | def from_bytes(cls, address_bytes, memorysize_bytes): 108 | if not isinstance(address_bytes, bytes): 109 | raise ValueError('address_bytes must be a valid bytes object') 110 | 111 | if not isinstance(memorysize_bytes, bytes): 112 | raise ValueError('memorysize_bytes must be a valid bytes object') 113 | 114 | if len(address_bytes) > 5: 115 | raise ValueError('Address must be at most 40 bits long') 116 | 117 | if len(memorysize_bytes) > 4: 118 | raise ValueError('Memory size must be at most 32 bits long') 119 | 120 | address_bytes_padded = b'\x00' * (8-len(address_bytes)) + address_bytes 121 | memorysize_bytes_padded = b'\x00' * (8-len(memorysize_bytes)) + memorysize_bytes 122 | 123 | address = struct.unpack('>q', address_bytes_padded)[0] 124 | memorysize = struct.unpack('>q', memorysize_bytes_padded)[0] 125 | address_format = len(address_bytes) * 8 126 | memorysize_format = len(memorysize_bytes) * 8 127 | 128 | return cls(address=address, memorysize=memorysize, address_format=address_format, memorysize_format=memorysize_format) 129 | 130 | def __str__(self): 131 | return 'Address=0x%x (%d bits), Size=0x%x (%d bits)' % (self.address, self.alfid.address_format, self.memorysize, self.alfid.memorysize_format) 132 | 133 | def __repr__(self): 134 | return '<%s: %s at 0x%08x>' % (self.__class__.__name__, str(self), id(self)) 135 | */ 136 | -------------------------------------------------------------------------------- /uds/request.go: -------------------------------------------------------------------------------- 1 | package uds 2 | 3 | type Request struct { 4 | service string 5 | data []byte 6 | sid byte 7 | subfunction byte 8 | use_subfunction bool 9 | } 10 | 11 | func NewRequest(sid byte, service string) *Request { 12 | r := Request{} 13 | r.sid = sid 14 | r.service = service 15 | r.data = []byte{} 16 | return &r 17 | } 18 | 19 | func (r *Request) get_payload(suppress_positive_response bool) []byte { 20 | payload := []byte{r.sid} 21 | if r.use_subfunction { 22 | r.data = append([]byte{r.subfunction}, r.data...) 23 | } else { 24 | } 25 | return append(payload, r.data...) 26 | } 27 | -------------------------------------------------------------------------------- /uds/response.go: -------------------------------------------------------------------------------- 1 | package uds 2 | 3 | type Response struct { 4 | Service string 5 | Data []byte 6 | Service_data map[string]interface{} 7 | } 8 | 9 | func NewResponse(service string) *Response { 10 | r := Response{} 11 | r.Service = service 12 | r.Data = []byte{} 13 | r.Service_data = map[string]interface{}{} 14 | return &r 15 | } 16 | func response_from_payload(data []byte) *Response { 17 | r := Response{} 18 | if len(data) == 0 { 19 | return &r 20 | } 21 | r.Data = data[1:] 22 | r.Service_data = map[string]interface{}{} 23 | return &r 24 | } 25 | -------------------------------------------------------------------------------- /uds/service_diagnostic_session.go: -------------------------------------------------------------------------------- 1 | package uds 2 | 3 | //import "fmt" 4 | 5 | func service_diagnostic_session_make_request(session int) *Request { 6 | r := NewRequest(0x10, "diagnostic_session") 7 | r.use_subfunction = true 8 | r.subfunction = byte(session) 9 | return r 10 | } 11 | 12 | func (c *Client) service_disagnostic_session_handle_response(r *Response) { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /uds/service_read_data_by_id.go: -------------------------------------------------------------------------------- 1 | package uds 2 | 3 | //import "fmt" 4 | import "encoding/binary" 5 | 6 | func convertIntArrayToByteArray(data []int) []byte { 7 | 8 | buff := []byte{} 9 | for _, short := range data { 10 | bs := make([]byte, 2) 11 | binary.BigEndian.PutUint16(bs, uint16(short)) 12 | buff = append(buff, bs...) 13 | } 14 | return buff 15 | } 16 | 17 | func service_read_data_by_id_make_request(data []int) *Request { 18 | r := NewRequest(0x22, "read_data_by_id") 19 | r.data = convertIntArrayToByteArray(data) 20 | r.use_subfunction = false 21 | return r 22 | } 23 | 24 | func (c *Client) service_read_data_by_id_handle_response(r *Response) { 25 | 26 | /* 27 | did := 0 28 | //did := binary.BigEndian.Uint16(r.Data[0:1]) 29 | offset := 0 30 | for { 31 | if len(r.Data) <= offset { 32 | break 33 | } 34 | if len(r.Data) <= offset+1 { 35 | if true && r.Data[len(r.Data)-1] == 0 { 36 | break 37 | } 38 | } 39 | 40 | if did == 0 && true { 41 | compare := []byte{} 42 | for { 43 | compare = append(compare, 0) 44 | if len(compare) == len(r.Data)-offset { 45 | break 46 | } 47 | } 48 | if fmt.Sprintf("%v", r.Data[offset:]) == fmt.Sprintf("%v", compare) { 49 | break 50 | } 51 | } 52 | offset += 2 53 | 54 | codec_length := c.Data_identifiers[int(did)] 55 | subpayload := r.Data[offset:] 56 | if offset+codec_length < len(r.Data) { 57 | subpayload = r.Data[offset : offset+codec_length] 58 | } 59 | offset += codec_length 60 | r.Service_data[fmt.Sprintf("%d", did)] = subpayload 61 | } 62 | */ 63 | 64 | } 65 | -------------------------------------------------------------------------------- /uds/service_request_download.go: -------------------------------------------------------------------------------- 1 | package uds 2 | 3 | import "fmt" 4 | 5 | func service_request_download_make_request(ml MemoryLocation) *Request { 6 | 7 | r := NewRequest(0x34, "request_download") 8 | r.use_subfunction = false 9 | r.data = append(r.data, DataFormatId()) 10 | r.data = append(r.data, ml.AlfidByte()) 11 | r.data = append(r.data, ml.GetAddressBytes()...) 12 | r.data = append(r.data, ml.GetMemorySizeBytes()...) 13 | 14 | fmt.Println("request_download", r.data) 15 | return r 16 | } 17 | 18 | func (c *Client) service_request_download_handle_response(r *Response) { 19 | 20 | //lfid = int(response.data[0]) >> 4 21 | /* 22 | todecode = bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') 23 | for i in range(1,lfid+1): 24 | todecode[-i] = response.data[lfid+1-i] 25 | response.service_data.max_length = struct.unpack('>q', todecode)[0] 26 | */ 27 | } 28 | -------------------------------------------------------------------------------- /uds/service_security_access.go: -------------------------------------------------------------------------------- 1 | package uds 2 | 3 | //import "fmt" 4 | 5 | func service_security_access_make_request(level int, mode string, key []byte) *Request { 6 | r := NewRequest(0x27, "security") 7 | r.use_subfunction = true 8 | 9 | if mode == "request_seed" { 10 | if level%2 == 1 { 11 | r.subfunction = byte(level) 12 | } else { 13 | r.subfunction = byte(level) - 1 14 | } 15 | } else if mode == "send_key" { 16 | if level%2 == 0 { 17 | r.subfunction = byte(level) 18 | } else { 19 | r.subfunction = byte(level) + 1 20 | } 21 | } 22 | 23 | if mode == "send_key" { 24 | r.data = append(r.data, key...) 25 | } 26 | return r 27 | } 28 | -------------------------------------------------------------------------------- /uds/service_transfer.go: -------------------------------------------------------------------------------- 1 | package uds 2 | 3 | func service_transfer_data_make_request(i int, data []byte) *Request { 4 | r := NewRequest(0x36, "transfer_data") 5 | r.data = []byte{byte(i)} 6 | r.data = append(r.data, data...) 7 | r.use_subfunction = false 8 | return r 9 | } 10 | 11 | func service_transfer_data_handle_response(r *Response) { 12 | 13 | r.Service_data["sequence_number_echo"] = r.Data[0] 14 | r.Service_data["parameter_records"] = []byte{} 15 | if len(r.Data) > 1 { 16 | r.Service_data["parameter_records"] = r.Data[1:] 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /uds/test_helper.go: -------------------------------------------------------------------------------- 1 | package uds 2 | 3 | import "testing" 4 | import "fmt" 5 | 6 | func eq(t *testing.T, a, b interface{}) { 7 | as := fmt.Sprintf("%v", a) 8 | bs := fmt.Sprintf("%v", b) 9 | if as != bs { 10 | fmt.Printf("%s: %s != %s\n", t.Name(), as, bs) 11 | t.Fail() 12 | } 13 | } 14 | func neq(t *testing.T, a, b interface{}) { 15 | as := fmt.Sprintf("%v", a) 16 | bs := fmt.Sprintf("%v", b) 17 | if as == bs { 18 | fmt.Printf("%s: %s == %s\n", t.Name(), as, bs) 19 | t.Fail() 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /uds/uds_test.go: -------------------------------------------------------------------------------- 1 | package uds 2 | 3 | import "fmt" 4 | import "testing" 5 | import "time" 6 | import "os" 7 | 8 | var conn *QueueConnection 9 | var client *Client 10 | 11 | func ri() int { 12 | return 0 13 | } 14 | 15 | func TestMain(m *testing.M) { 16 | conn = NewQueueConnection("test", 4095) 17 | client = NewClient(conn, 0.2, ri) 18 | os.Exit(m.Run()) 19 | } 20 | 21 | func TestTransferData(t *testing.T) { 22 | 23 | go func() { 24 | r := conn.touser_frame() 25 | eq(t, r, []byte{0x36, 0x22, 0x12, 0x34, 0x56}) 26 | conn.fromuserm.Lock() 27 | conn.fromuser.Put([]byte{0x76, 0x22, 0x89, 0xab, 0xcd, 0xef}) 28 | conn.fromuserm.Unlock() 29 | }() 30 | 31 | //response := client.Transfer_data(0x22, []byte{0x12, 0x34, 0x56}) 32 | //eq(t, response.Service_data["sequence_number_echo"], 0x22) 33 | //eq(t, response.Service_data["parameter_records"], []byte{0x89, 0xab, 0xcd, 0xef}) 34 | 35 | time.Sleep(20 * time.Millisecond) 36 | } 37 | 38 | func TestReadDataById(t *testing.T) { 39 | 40 | go func() { 41 | r := conn.touser_frame() 42 | eq(t, r, []byte{0x22, 0x00, 0x01}) 43 | conn.fromuserm.Lock() 44 | conn.fromuser.Put([]byte{0x62, 0x00, 0x01, 0x12, 0x34}) 45 | conn.fromuserm.Unlock() 46 | }() 47 | 48 | client.Data_identifiers[1] = 1 49 | response := client.Read_data_by_id([]int{0x1}) 50 | //self.assertTrue(response.positive) 51 | //self.assertEqual(values[1], (0x1234,)) 52 | //eq(t, response.Service_data["parameter_records"], []byte{0x89, 0xab, 0xcd, 0xef}) 53 | fmt.Println("", response) 54 | 55 | time.Sleep(20 * time.Millisecond) 56 | } 57 | -------------------------------------------------------------------------------- /util/interface_queue.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import "container/list" 4 | 5 | import "fmt" 6 | 7 | type InterfaceQueue struct { 8 | data *list.List 9 | } 10 | 11 | func NewInterfaceQueue() *InterfaceQueue { 12 | q := InterfaceQueue{} 13 | q.data = list.New() 14 | return &q 15 | } 16 | 17 | func (q *InterfaceQueue) Empty() bool { 18 | return q.data.Len() == 0 19 | } 20 | func (q *InterfaceQueue) Clear() { 21 | q.data.Init() 22 | } 23 | 24 | func (q *InterfaceQueue) Len() int { 25 | return q.data.Len() 26 | } 27 | func (q *InterfaceQueue) Available() bool { 28 | return q.data.Len() > 0 29 | } 30 | func (q *InterfaceQueue) Get() interface{} { 31 | e := q.data.Front() 32 | q.data.Remove(e) 33 | return e.Value 34 | } 35 | func (q *InterfaceQueue) Put(b interface{}) { 36 | q.data.PushBack(b) 37 | } 38 | func (q *InterfaceQueue) String() string { 39 | return fmt.Sprintf("%v", q.data.Front()) 40 | } 41 | -------------------------------------------------------------------------------- /util/queue.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import "container/list" 4 | 5 | type Queue struct { 6 | data *list.List 7 | } 8 | 9 | func NewQueue() *Queue { 10 | q := Queue{} 11 | q.data = list.New() 12 | return &q 13 | } 14 | 15 | func (q *Queue) Empty() bool { 16 | return q.data.Len() == 0 17 | } 18 | func (q *Queue) Clear() { 19 | q.data.Init() 20 | } 21 | 22 | func (q *Queue) Len() int { 23 | return q.data.Len() 24 | } 25 | func (q *Queue) Available() bool { 26 | return q.data.Len() > 0 27 | } 28 | func (q *Queue) Get() []byte { 29 | e := q.data.Front() 30 | q.data.Remove(e) 31 | return e.Value.([]byte) 32 | } 33 | func (q *Queue) Put(b []byte) { 34 | q.data.PushBack(b) 35 | } 36 | --------------------------------------------------------------------------------