diff --git a/Makefile.am b/Makefile.am index 5327646..12decd3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -54,7 +54,7 @@ SRC_FILES += $(ECUTOOLS_SRC_FILES) #LOG_FLAGS += -DIOT_WARN #LOG_FLAGS += -DIOT_ERROR -COMPILER_FLAGS = -g3 +COMPILER_FLAGS = -g3 -w COMPILER_FLAGS += $(LOG_FLAGS) # ecutools diff --git a/README.md b/README.md index 97268a0..27d04d2 100755 --- a/README.md +++ b/README.md @@ -55,11 +55,11 @@ Dynamic libraries (not included): To install, - ./autogen.sh - ./configure + ./autogen.sh + ./configure make mbedtls - make - sudo make install + make + sudo make install ## Development diff --git a/bindings/ruby/lib/ecutools/j2534.rb b/bindings/ruby/lib/ecutools/j2534.rb index c6009a1..af14083 100644 --- a/bindings/ruby/lib/ecutools/j2534.rb +++ b/bindings/ruby/lib/ecutools/j2534.rb @@ -50,13 +50,13 @@ def PassThruOpen(name, deviceId) pDeviceId = FFI::MemoryPointer.new(:ulong, 8).put_ulong(0, deviceId) response = Libj2534.PassThruOpen(pName, pDeviceId) raise Ecutools::J2534Error, Error[response] unless response === STATUS_NOERROR - true + response end def PassThruClose(deviceId) response = Libj2534.PassThruClose(deviceId) raise Ecutools::J2534Error, Error[response] unless response === STATUS_NOERROR - true + response end def PassThruConnect(deviceId, protocolId, flags, baudRate, resource, channelId) @@ -68,13 +68,13 @@ def PassThruConnect(deviceId, protocolId, flags, baudRate, resource, channelId) pChannelID = FFI::MemoryPointer.new(:ulong, 8).put_ulong(0, channelId) response = Libj2534.PassThruConnect(deviceId, protocolId, flags, baudRate, resourceStruct, pChannelID) raise Ecutools::J2534Error, Error[response] unless response === STATUS_NOERROR - true + response end def PassThruDisconnect(channelId) response = Libj2534.PassThruDisconnect(channelId) raise Ecutools::J2534Error, Error[response] unless response === STATUS_NOERROR - true + response end def PassThruLogicalConnect(physicalChannelId, protocolId, flags, channelDescriptor, channelId) @@ -92,7 +92,47 @@ def PassThruSelect(channelSet, selectType, timeout) ).put_array_of_ulong(0, channelSet.ChannelList) response = Libj2534.PassThruSelect(channelset, selectType, timeout) raise Ecutools::J2534Error, Error[response] unless response === STATUS_NOERROR - true + response + end + + def PassThruReadMsgs(channelId, message, numMsgs, timeout) + end + + def PassThruQueueMsgs(channelId, message, numMsgs) + end + + def PassThruStartPeriodicMsg(channelId, message, messageId, timeInterval) + end + + def PassThruStopPeriodicMsg(channelId, messageId) + end + + # long PassThruStartMsgFilter(unsigned long ChannelID, unsigned long FilterType, PASSTHRU_MSG *pMaskMsg, PASSTHRU_MSG *pPatternMsg, unsigned long *pFilterID); + + # attach_function :PassThruStartMsgFilter, [ :ulong, :ulong, Ecutools::J2534::Structs::PASSTHRU_MSG.by_ref, Ecutools::J2534::Structs::PASSTHRU_MSG.by_ref, :pointer ], :long + + def PassThruStartMsgFilter(channelId, filterType, maskMsg, patternMsg, filterId) + pMaskMsg = map_model_to_passthru_msg(maskMsg, Ecutools::J2534::Structs::PASSTHRU_MSG.new) + pPatternMsg = map_model_to_passthru_msg(patternMsg, Ecutools::J2534::Structs::PASSTHRU_MSG.new) + pFilterID = FFI::MemoryPointer.new(:ulong, 8).put_ulong(0, filterId) + response = Libj2534.PassThruStartMsgFilter(channelId, filterType, pMaskMsg, pPatternMsg, pFilterID) + raise Ecutools::J2534Error, Error[response] unless response === STATUS_NOERROR + response + end + + def PassThruStopMsgFilter(channelId, filterId) + end + + def PassThruSetProgrammingVoltage(deviceId, resourceStruct, voltage) + end + + def PassThruReadVersion(deviceId) + end + + def PassThruGetLastError + end + + def PassThruIoctl(controlTarget, ioctlId) end private @@ -108,5 +148,18 @@ def map_sdevice_to_model(sdevice, device) device end + def map_model_to_passthru_msg(model, passthru_msg) + passthru_msg[:ProtocolID] = model.ProtocolID || 0 + passthru_msg[:MsgHandle] = model.MsgHandle + passthru_msg[:RxStatus] = model.RxStatus || 0 + passthru_msg[:TxFlags] = model.TxFlags || 0 + passthru_msg[:Timestamp] = model.Timestamp || 0 + passthru_msg[:DataLength] = model.DataLength + passthru_msg[:ExtraDataIndex] = model.ExtraDataIndex || 0 + passthru_msg[:DataBuffer] = model.DataBuffer + passthru_msg[:DataBufferSize] = model.DataBufferSize || 0 + passthru_msg + end + end end diff --git a/bindings/ruby/spec/PassThruConnect_STATUS_NOERROR_integration_spec.rb b/bindings/ruby/spec/PassThruConnect_STATUS_NOERROR_integration_spec.rb index 1f36373..944f28b 100644 --- a/bindings/ruby/spec/PassThruConnect_STATUS_NOERROR_integration_spec.rb +++ b/bindings/ruby/spec/PassThruConnect_STATUS_NOERROR_integration_spec.rb @@ -23,10 +23,17 @@ it 'returns STATUS_NOERROR when connected' do things.test_with_ecutuned { - expect(j2534.PassThruOpen(things[0][:name], 1)).to eq(true) + expect(j2534.PassThruOpen(things[0][:name], 1)).to eq(Ecutools::J2534::Error::STATUS_NOERROR) resource = Ecutools::J2534::Models::Resource.new resource.Connector = Ecutools::J2534::J1962_CONNECTOR - expect(j2534.PassThruConnect(1, Ecutools::J2534::CAN, Ecutools::J2534::CAN_ID_BOTH, 500000, resource, 1)).to eq(true) + expect(j2534.PassThruConnect( + 1, + Ecutools::J2534::CAN, + Ecutools::J2534::CAN_ID_BOTH, + 500000, + resource, + 1 + )).to eq(Ecutools::J2534::Error::STATUS_NOERROR) } end diff --git a/bindings/ruby/spec/PassThruDisconnect_STATUS_NOERROR_integration_spec.rb b/bindings/ruby/spec/PassThruDisconnect_STATUS_NOERROR_integration_spec.rb index 9eea54d..65a5da2 100644 --- a/bindings/ruby/spec/PassThruDisconnect_STATUS_NOERROR_integration_spec.rb +++ b/bindings/ruby/spec/PassThruDisconnect_STATUS_NOERROR_integration_spec.rb @@ -24,13 +24,19 @@ it 'returns STATUS_NOERROR when disconnected' do things.test_with_ecutuned { - expect(j2534.PassThruOpen(things[0][:name], 1)).to eq(true) + expect(j2534.PassThruOpen(things[0][:name], 1)).to eq(Ecutools::J2534::Error::STATUS_NOERROR) resource = Ecutools::J2534::Models::Resource.new resource.Connector = Ecutools::J2534::J1962_CONNECTOR - expect(j2534.PassThruConnect(1, Ecutools::J2534::CAN, Ecutools::J2534::CAN_ID_BOTH, 500000, resource, 1)).to eq(true) - - expect(j2534.PassThruDisconnect(1)).to eq(true) + expect(j2534.PassThruConnect( + 1, + Ecutools::J2534::CAN, + Ecutools::J2534::CAN_ID_BOTH, 500000, + resource, + 1 + )).to eq(Ecutools::J2534::Error::STATUS_NOERROR) + + expect(j2534.PassThruDisconnect(1)).to eq(Ecutools::J2534::Error::STATUS_NOERROR) } end diff --git a/bindings/ruby/spec/PassThruStartMsgFilter_ERR_EXCEEDED_LIMIT_integration_spec.rb b/bindings/ruby/spec/PassThruStartMsgFilter_ERR_EXCEEDED_LIMIT_integration_spec.rb new file mode 100644 index 0000000..0c21e1b --- /dev/null +++ b/bindings/ruby/spec/PassThruStartMsgFilter_ERR_EXCEEDED_LIMIT_integration_spec.rb @@ -0,0 +1,58 @@ +## +# ecutools: IoT Automotive Tuning, Diagnostics & Analytics +# Copyright (C) 2014 Jeremy Hahn +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +require 'spec_helper' + +describe Ecutools::J2534 do + include_context 'J2534' do + context 'PassThruSelect' do + + it 'returns ERR_EXCEEDED_LIMIT when more than 10 filters are specified' do + things.test_with_ecutuned { + + expect(j2534.PassThruOpen(things[0][:name], 1)).to eq(true) + + resource = Ecutools::J2534::Models::Resource.new + resource.Connector = Ecutools::J2534::J1962_CONNECTOR + expect(j2534.PassThruConnect(1, Ecutools::J2534::CAN, Ecutools::J2534::CAN_ID_BOTH, 500000, resource, 1)).to eq(true) + + maskMsg = Ecutools::J2534::Models::Message.new + maskMsg.ProtocolID = Ecutools::J2534::CAN + maskMsg.MsgHandle = 1 + maskMsg.DataBuffer = 0x7FF + maskMsg.DataLength = 11 + + patternMsg = Ecutools::J2534::Models::Message.new + patternMsg.ProtocolID = Ecutools::J2534::CAN + patternMsg.MsgHandle = 2 + patternMsg.DataBuffer = 0x7DF + patternMsg.DataLength = 11 + + i = 0 + 10.times do + i = i + 1 + expect(j2534.PassThruStartMsgFilter(i, Ecutools::J2534::PASS_FILTER, maskMsg, patternMsg, 1)).to eq(true) + end + expect{j2534.PassThruStartMsgFilter(11, Ecutools::J2534::PASS_FILTER, maskMsg, patternMsg, 1)}.to raise_error /ERR_EXCEEDED_LIMIT/ + } + end + + end + + end + +end diff --git a/bindings/ruby/spec/PassThruStartMsgFilter_ERR_FILTER_TYPE_NOT_SUPPORTED_integration_spec.rb b/bindings/ruby/spec/PassThruStartMsgFilter_ERR_FILTER_TYPE_NOT_SUPPORTED_integration_spec.rb new file mode 100644 index 0000000..eb34546 --- /dev/null +++ b/bindings/ruby/spec/PassThruStartMsgFilter_ERR_FILTER_TYPE_NOT_SUPPORTED_integration_spec.rb @@ -0,0 +1,53 @@ +## +# ecutools: IoT Automotive Tuning, Diagnostics & Analytics +# Copyright (C) 2014 Jeremy Hahn +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +require 'spec_helper' + +describe Ecutools::J2534 do + include_context 'J2534' do + context 'PassThruSelect' do + + it 'returns ERR_FILTER_TYPE_NOT_SUPPORTED when an invalid filter is specified' do + things.test_with_ecutuned { + + expect(j2534.PassThruOpen(things[0][:name], 1)).to eq(true) + + resource = Ecutools::J2534::Models::Resource.new + resource.Connector = Ecutools::J2534::J1962_CONNECTOR + expect(j2534.PassThruConnect(1, Ecutools::J2534::CAN, Ecutools::J2534::CAN_ID_BOTH, 500000, resource, 1)).to eq(true) + + maskMsg = Ecutools::J2534::Models::Message.new + maskMsg.ProtocolID = Ecutools::J2534::CAN + maskMsg.MsgHandle = 1 + maskMsg.DataBuffer = 0x7FF + maskMsg.DataLength = 11 + + patternMsg = Ecutools::J2534::Models::Message.new + patternMsg.ProtocolID = Ecutools::J2534::CAN + patternMsg.MsgHandle = 2 + patternMsg.DataBuffer = 0x7DF + patternMsg.DataLength = 11 + + expect{j2534.PassThruStartMsgFilter(1, 1, maskMsg, patternMsg, 1)}.to raise_error /ERR_FILTER_TYPE_NOT_SUPPORTED/ + } + end + + end + + end + +end diff --git a/bindings/ruby/spec/PassThruStartMsgFilter_ERR_INVALID_MSG_integration_spec.rb b/bindings/ruby/spec/PassThruStartMsgFilter_ERR_INVALID_MSG_integration_spec.rb new file mode 100644 index 0000000..39da686 --- /dev/null +++ b/bindings/ruby/spec/PassThruStartMsgFilter_ERR_INVALID_MSG_integration_spec.rb @@ -0,0 +1,53 @@ +## +# ecutools: IoT Automotive Tuning, Diagnostics & Analytics +# Copyright (C) 2014 Jeremy Hahn +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +require 'spec_helper' + +describe Ecutools::J2534 do + include_context 'J2534' do + context 'PassThruSelect' do + + it 'returns ERR_INVALID_MSG when an invalid data length is specified' do + things.test_with_ecutuned { + + expect(j2534.PassThruOpen(things[0][:name], 1)).to eq(true) + + resource = Ecutools::J2534::Models::Resource.new + resource.Connector = Ecutools::J2534::J1962_CONNECTOR + expect(j2534.PassThruConnect(1, Ecutools::J2534::CAN, Ecutools::J2534::CAN_ID_BOTH, 500000, resource, 1)).to eq(true) + + maskMsg = Ecutools::J2534::Models::Message.new + maskMsg.ProtocolID = Ecutools::J2534::CAN + maskMsg.MsgHandle = 1 + maskMsg.DataBuffer = 0x7FF + maskMsg.DataLength = 13 + + patternMsg = Ecutools::J2534::Models::Message.new + patternMsg.ProtocolID = Ecutools::J2534::CAN + patternMsg.MsgHandle = 2 + patternMsg.DataBuffer = 0x7DF + patternMsg.DataLength = 13 + + expect{j2534.PassThruStartMsgFilter(1, Ecutools::J2534::PASS_FILTER, maskMsg, patternMsg, 1)}.to raise_error /ERR_INVALID_MSG/ + } + end + + end + + end + +end diff --git a/bindings/ruby/spec/PassThruStartMsgFilter_ERR_MSG_PROTOCOL_ID_integration_spec.rb b/bindings/ruby/spec/PassThruStartMsgFilter_ERR_MSG_PROTOCOL_ID_integration_spec.rb new file mode 100644 index 0000000..829ba38 --- /dev/null +++ b/bindings/ruby/spec/PassThruStartMsgFilter_ERR_MSG_PROTOCOL_ID_integration_spec.rb @@ -0,0 +1,53 @@ +## +# ecutools: IoT Automotive Tuning, Diagnostics & Analytics +# Copyright (C) 2014 Jeremy Hahn +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +require 'spec_helper' + +describe Ecutools::J2534 do + include_context 'J2534' do + context 'PassThruSelect' do + + it 'returns ERR_MSG_PROTOCOL_ID when an invalid protocol id is specified' do + things.test_with_ecutuned { + + expect(j2534.PassThruOpen(things[0][:name], 1)).to eq(true) + + resource = Ecutools::J2534::Models::Resource.new + resource.Connector = Ecutools::J2534::J1962_CONNECTOR + expect(j2534.PassThruConnect(1, Ecutools::J2534::CAN, Ecutools::J2534::CAN_ID_BOTH, 500000, resource, 1)).to eq(true) + + maskMsg = Ecutools::J2534::Models::Message.new + maskMsg.ProtocolID = 0 + maskMsg.MsgHandle = 1 + maskMsg.DataBuffer = 0x7FF + maskMsg.DataLength = 11 + + patternMsg = Ecutools::J2534::Models::Message.new + patternMsg.ProtocolID = 0 + patternMsg.MsgHandle = 2 + patternMsg.DataBuffer = 0x7DF + patternMsg.DataLength = 11 + + expect{j2534.PassThruStartMsgFilter(1, Ecutools::J2534::PASS_FILTER, maskMsg, patternMsg, 1)}.to raise_error /ERR_MSG_PROTOCOL_ID/ + } + end + + end + + end + +end diff --git a/bindings/ruby/spec/PassThruStartMsgFilter_STATUS_NOERROR_integration_spec.rb b/bindings/ruby/spec/PassThruStartMsgFilter_STATUS_NOERROR_integration_spec.rb new file mode 100644 index 0000000..ab0fc4b --- /dev/null +++ b/bindings/ruby/spec/PassThruStartMsgFilter_STATUS_NOERROR_integration_spec.rb @@ -0,0 +1,53 @@ +## +# ecutools: IoT Automotive Tuning, Diagnostics & Analytics +# Copyright (C) 2014 Jeremy Hahn +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +require 'spec_helper' + +describe Ecutools::J2534 do + include_context 'J2534' do + context 'PassThruSelect' do + + it 'returns STATUS_NOERROR when a filter is successfully added' do + things.test_with_ecutuned { + + expect(j2534.PassThruOpen(things[0][:name], 1)).to eq(Ecutools::J2534::STATUS_NOERROR) + + resource = Ecutools::J2534::Models::Resource.new + resource.Connector = Ecutools::J2534::J1962_CONNECTOR + expect(j2534.PassThruConnect(1, Ecutools::J2534::CAN, Ecutools::J2534::CAN_ID_BOTH, 500000, resource, 1)).to eq(Ecutools::J2534::STATUS_NOERROR) + + maskMsg = Ecutools::J2534::Models::Message.new + maskMsg.ProtocolID = Ecutools::J2534::CAN + maskMsg.MsgHandle = 1 + maskMsg.DataBuffer = 0x7FF + maskMsg.DataLength = 11 + + patternMsg = Ecutools::J2534::Models::Message.new + patternMsg.ProtocolID = Ecutools::J2534::CAN + patternMsg.MsgHandle = 2 + patternMsg.DataBuffer = 0x7DF + patternMsg.DataLength = 11 + + expect(j2534.PassThruStartMsgFilter(1, Ecutools::J2534::PASS_FILTER, maskMsg, patternMsg, 1)).to eq(Ecutools::J2534::STATUS_NOERROR) + } + end + + end + + end + +end diff --git a/bindings/ruby/spec/spec_helper.rb b/bindings/ruby/spec/spec_helper.rb index 4b5fd36..9c0988b 100644 --- a/bindings/ruby/spec/spec_helper.rb +++ b/bindings/ruby/spec/spec_helper.rb @@ -94,7 +94,7 @@ def test_with_ecutuned(&block) rescue Errno::ENOMEM => nomem puts "Garbage collecting to free up room for cleanup..." GC.start - sleep(5) + sleep(7) `pkill -9 ecutuned` `rm -rf /var/ecutools/cache/state_log` end diff --git a/cli/lib/ecutools/awsiot/service.rb b/cli/lib/ecutools/awsiot/service.rb index 33ca2c2..b5c6f33 100644 --- a/cli/lib/ecutools/awsiot/service.rb +++ b/cli/lib/ecutools/awsiot/service.rb @@ -88,9 +88,7 @@ def list_things Ecutools.aws.iot.list_things({ max_results: 100, attribute_name: "type", - attribute_value: "j2534", - attribute_name: "acct", - attribute_value: acct, + attribute_value: "j2534" })[:things].map { |thing| thing[:thing_name] } diff --git a/src/aws_iot_src/src/aws_iot_shadow.c b/src/aws_iot_src/src/aws_iot_shadow.c index bb63c85..93ed0d7 100644 --- a/src/aws_iot_src/src/aws_iot_shadow.c +++ b/src/aws_iot_src/src/aws_iot_shadow.c @@ -63,7 +63,7 @@ IoT_Error_t aws_iot_shadow_init(AWS_IoT_Client *pClient, ShadowInitParameters_t mqttInitParams.pRootCALocation = pParams->pRootCA; mqttInitParams.pDeviceCertLocation = pParams->pClientCRT; mqttInitParams.pDevicePrivateKeyLocation = pParams->pClientKey; - mqttInitParams.mqttCommandTimeout_ms = 5000; + mqttInitParams.mqttCommandTimeout_ms = 7000; mqttInitParams.tlsHandshakeTimeout_ms = 10000; mqttInitParams.isSSLHostnameVerify = true; mqttInitParams.disconnectHandler = pParams->disconnectHandler; diff --git a/src/awsiot_client.c b/src/awsiot_client.c index 0abb940..2239c46 100755 --- a/src/awsiot_client.c +++ b/src/awsiot_client.c @@ -41,7 +41,7 @@ unsigned int awsiot_client_connect(awsiot_client *awsiot) { mqttInitParams.pRootCALocation = rootCA; mqttInitParams.pDeviceCertLocation = clientCRT; mqttInitParams.pDevicePrivateKeyLocation = clientKey; - mqttInitParams.mqttCommandTimeout_ms = 5000; + mqttInitParams.mqttCommandTimeout_ms = 7000; mqttInitParams.tlsHandshakeTimeout_ms = 5000; mqttInitParams.isSSLHostnameVerify = true; mqttInitParams.disconnectHandler = awsiot->ondisconnect; @@ -114,9 +114,7 @@ unsigned int awsiot_client_unsubscribe(awsiot_client *awsiot, const char *topic) unsigned int awsiot_client_publish(awsiot_client *awsiot, const char *topic, char *payload) { - int payload_len = strlen(payload);// + 1; -// payload[payload_len] = '\0'; - + int payload_len = strlen(payload); syslog(LOG_DEBUG, "awsiot_client_publish: topic=%s, payload_len=%d, payload=%s", topic, payload_len, payload); IoT_Publish_Message_Params paramsQOS0; diff --git a/src/canbus.c b/src/canbus.c index e533b75..bc32f94 100755 --- a/src/canbus.c +++ b/src/canbus.c @@ -176,6 +176,19 @@ unsigned int canbus_write(canbus_client *canbus, struct can_frame *frame) { return bytes; } +int canbus_filter(canbus_client *canbus, struct can_filter *filters, unsigned int filter_len) { + if((canbus->state & CANBUS_STATE_CONNECTED) == 0) { + syslog(LOG_ERR, "canbus_write: CAN socket not connected"); + return 1; + } + syslog(LOG_DEBUG, "canbus_filter: applying filters"); + int i; + for(i=0; isocket, SOL_CAN_RAW, CAN_RAW_FILTER, filters, sizeof(struct can_filter) * filter_len); +} + void canbus_shutdown(canbus_client *canbus, int how) { if(canbus->socket != NULL) { if(shutdown(canbus->socket, SHUT_RD) != 0) { diff --git a/src/canbus.h b/src/canbus.h index 2f61fa7..88977b6 100755 --- a/src/canbus.h +++ b/src/canbus.h @@ -58,6 +58,7 @@ unsigned int canbus_connect(canbus_client *canbus); bool canbus_isconnected(canbus_client *canbus); ssize_t canbus_read(canbus_client *canbus, struct can_frame *frame); unsigned int canbus_write(canbus_client *canbus, struct can_frame *frame); +int canbus_filter(canbus_client *canbus, struct can_filter *filters, unsigned int filter_len); void canbus_shutdown(canbus_client *canbus, int how); void canbus_close(canbus_client *canbus); void canbus_framecpy(struct can_frame * frame, char *buf); diff --git a/src/j2534.c b/src/j2534.c index 22f5740..99b9d62 100755 --- a/src/j2534.c +++ b/src/j2534.c @@ -21,7 +21,7 @@ // not j2534 spec static bool j2534_initialized = false; static bool j2534_opened = false; -static unsigned int j2534_current_api_call = 0; +static unsigned long j2534_current_api_call = 0; static long j2534_device_count = 0; static char j2534_last_error[80] = {0}; static int *j2534_awsiot_error = NULL; @@ -30,7 +30,7 @@ static SDEVICE j2534_device_list[25] = {0}; static vector j2534_client_vector; static vector j2534_selected_channels; -unsigned long unless_concurrent_call(unsigned long status, unsigned int api_call) { +unsigned long unless_concurrent_call(unsigned long status, unsigned long api_call) { syslog(LOG_DEBUG, "unless_concurrent_call: status=%x, api_call=%d", status, api_call); if(j2534_current_api_call != api_call) { strcpy(j2534_last_error, "ERR_CONCURRENT_API_CALL"); @@ -109,6 +109,45 @@ void j2534_onerror(awsiot_client *awsiot, const char *message) { syslog(LOG_ERR, "j2534_onerror: message=%s", message); } +char *filter_json(j2534_client *client) { + +syslog(LOG_DEBUG, "filter_json: client->filters->count=%d", client->filters->count); + + unsigned int json_len = client->filters->count * 27; + j2534_canfilter *canfilter = NULL; + char *json = malloc(sizeof(char) * json_len); + memset(json, '\0', sizeof(char) * json_len); + strcpy(json, "["); + + int i; + for(i=0; ifilters->count; i++) { + + char tmp_format[json_len]; + char tmp[json_len]; + + canfilter = (j2534_canfilter *)vector_get(client->filters, i); + + strcpy(tmp_format, "{\"id\":\""); + strcat(tmp_format, "%x"); + strcat(tmp_format, "\","); + strcat(tmp_format, "\"mask\":\""); + strcat(tmp_format, "%x"); + strcat(tmp_format, "\"}"); + + snprintf(tmp, json_len, tmp_format, canfilter->can_id, canfilter->can_mask); + strcat(json, tmp); + + if(i < client->filters->count-1) { + strcat(json, ","); + } + } + strcat(json, "]"); + +syslog(LOG_DEBUG, "filter_json: json=%s", json); + + return json; +} + unsigned int j2534_publish_state(j2534_client *client, int desired_state) { char json_format[255] = "{\"state\":{\"desired\":{\"j2534\":{\"deviceId\":%i,\"state\":%i}}}}"; @@ -434,6 +473,7 @@ long PassThruOpen(const char *pName, unsigned long *pDeviceID) { client->device = malloc(sizeof(SDEVICE)); client->deviceId = *pDeviceID; + client->protocolId = 0; client->state = NULL; client->awsiot = malloc(sizeof(awsiot_client)); @@ -450,6 +490,9 @@ long PassThruOpen(const char *pName, unsigned long *pDeviceID) { vector_init(client->rxQueue); vector_init(client->txQueue); + client->filters = malloc(sizeof(vector)); + vector_init(client->filters); + client->channelSet = malloc(sizeof(SCHANNELSET)); client->channelSet->ChannelCount = 0; client->channelSet->ChannelThreshold = 0; @@ -549,6 +592,7 @@ long PassThruClose(unsigned long DeviceID) { free(client->channelSet); free(client->txQueue); free(client->rxQueue); + free(client->filters); free(client->name); free(client->device); free(client->awsiot); @@ -658,6 +702,8 @@ long PassThruConnect(unsigned long DeviceID, unsigned long ProtocolID, unsigned return unless_concurrent_call(ERR_INVALID_DEVICE_ID, J2534_PassThruConnect); } + client->protocolId = ProtocolID; + /* if(ProtocolID != J1850VPW && ProtocolID != J1850PWM && ProtocolID != ISO9141 && ProtocolID != ISO14230 && ProtocolID != CAN && ProtocolID != J2610 && @@ -1432,7 +1478,56 @@ long PassThruStopPeriodicMsg(unsigned long ChannelID, unsigned long MsgID) { * STATUS_NOERROR Function call was successful */ long PassThruStartMsgFilter(unsigned long ChannelID, unsigned long FilterType, PASSTHRU_MSG *pMaskMsg, PASSTHRU_MSG *pPatternMsg, unsigned long *pFilterID) { - return ERR_NOT_SUPPORTED; + + j2534_current_api_call = J2534_PassThruStartMsgFilter; + + if(pMaskMsg == NULL || pPatternMsg == NULL || pFilterID == NULL) { + return unless_concurrent_call(ERR_NULL_PARAMETER, J2534_PassThruStartMsgFilter); + } + + if(!j2534_opened) { + return unless_concurrent_call(ERR_DEVICE_NOT_OPEN, J2534_PassThruStartMsgFilter); + } + + j2534_client *client = j2534_client_by_channel_id(ChannelID); + if(client == NULL) { + return unless_concurrent_call(ERR_INVALID_DEVICE_ID, J2534_PassThruStartMsgFilter); + } + + if(FilterType != PASS_FILTER && FilterType != BLOCK_FILTER) { + return unless_concurrent_call(ERR_FILTER_TYPE_NOT_SUPPORTED, J2534_PassThruStartMsgFilter); + } + + if(pMaskMsg->ProtocolID != client->protocolId || pPatternMsg->ProtocolID != client->protocolId) { + return unless_concurrent_call(ERR_MSG_PROTOCOL_ID, J2534_PassThruStartMsgFilter); + } + + if(pMaskMsg->DataLength < 1 || pMaskMsg->DataLength > 12) { + return unless_concurrent_call(ERR_INVALID_MSG, J2534_PassThruStartMsgFilter); + } + + if(pPatternMsg->DataLength < 1 || pPatternMsg->DataLength > 12) { + return unless_concurrent_call(ERR_INVALID_MSG, J2534_PassThruStartMsgFilter); + } + + if(client->filters->size >= 10) { + return unless_concurrent_call(ERR_EXCEEDED_LIMIT, J2534_PassThruStartMsgFilter); + } + + j2534_canfilter *filter = malloc(sizeof(j2534_canfilter)); + filter->id = pFilterID; + filter->can_id = pPatternMsg->DataBuffer; + filter->can_mask = pMaskMsg->DataBuffer; + vector_add(client->filters, filter); + +filter_json(client); + +return STATUS_NOERROR; + + return unless_concurrent_call( + j2534_publish_state(client, J2534_PassThruStartMsgFilter), + J2534_PassThruStartMsgFilter + ); } /** diff --git a/src/j2534.h b/src/j2534.h index 88659dd..4589ecc 100755 --- a/src/j2534.h +++ b/src/j2534.h @@ -22,6 +22,7 @@ #include #include #include +#include #include "vector.h" #include "passthru_thing.h" #include "passthru_shadow_parser.h" @@ -326,11 +327,18 @@ long PassThruIoctl(unsigned long ControlTarget, unsigned long IoctlID, void *Inp #define J2534_PassThruGetLastError 18 #define J2534_PassThruIoctl 19 +typedef struct { + unsigned long *id; + canid_t can_id; + canid_t can_mask; +} j2534_canfilter; + typedef struct { char *name; int *state; unsigned long deviceId; unsigned long channelId; + unsigned long protocolId; bool opened; char *shadow_update_topic; char *shadow_update_accepted_topic; @@ -338,11 +346,12 @@ typedef struct { char *msg_rx_topic; char *msg_tx_topic; SDEVICE *device; + SCHANNELSET *channelSet; awsiot_client *awsiot; + canbus_client *canbus; vector *rxQueue; vector *txQueue; - SCHANNELSET *channelSet; - canbus_client *canbus; + vector *filters; } j2534_client; void j2534_send_error(awsiot_client *awsiot, unsigned int error); diff --git a/src/passthru_shadow.h b/src/passthru_shadow.h index 1fb4218..d0e9e4d 100644 --- a/src/passthru_shadow.h +++ b/src/passthru_shadow.h @@ -36,7 +36,6 @@ #define PASSTHRU_SHADOW_GET_ACCEPTED_TOPIC "$aws/things/%s/shadow/get/accepted" char DELTA_REPORT[SHADOW_MAX_SIZE_OF_RX_BUFFER]; -//bool messageArrivedOnDelta; typedef struct { int *type; diff --git a/src/passthru_shadow_j2534_handler.c b/src/passthru_shadow_j2534_handler.c index 64cb2c3..4cd6837 100644 --- a/src/passthru_shadow_j2534_handler.c +++ b/src/passthru_shadow_j2534_handler.c @@ -96,6 +96,7 @@ syslog(LOG_DEBUG, "passthru_shadow_j2534_handler_desired_open: j2534->deviceId=% client = malloc(sizeof(j2534_client)); client->state = J2534_PassThruOpen; client->deviceId = MYINT_DUP(j2534->deviceId); + client->opened = true; unsigned int shadow_update_topic_len = PASSTHRU_SHADOW_UPDATE_TOPIC + strlen(client->name) + 1; unsigned int shadow_update_accepted_topic_len = PASSTHRU_SHADOW_UPDATE_ACCEPTED_TOPIC + strlen(client->name) + 1; @@ -211,46 +212,32 @@ void passthru_shadow_j2534_handler_desired_select(passthru_thing *thing, shadow_ void passthru_shadow_j2534_handler_desired_startMsgFilter(passthru_thing *thing, shadow_j2534 *j2534) { - struct timeval start, stop; - float milliseconds = 0; - - int can_frame_len = sizeof(struct can_frame); - struct can_frame frame; - memset(&frame, 0, can_frame_len); - - int data_len = can_frame_len + 25; - char data[data_len]; - memset(data, 0, data_len); + int i; j2534_client *client = passthru_shadow_j2534_handler_get_client(thing, j2534->deviceId); if(client == NULL) { - syslog(LOG_ERR, "passthru_shadow_j2534_handler_desired_startMsgFilter: unable to locate client: %s", j2534->deviceId); return passthru_shadow_j2534_handler_send_error(thing, J2534_PassThruSelect, ERR_DEVICE_NOT_CONNECTED); } - client->state = J2534_PassThruStartMsgFilter; - passthru_shadow_j2534_handler_send_report(J2534_PassThruStartMsgFilter); + if(!client->opened) { + return passthru_shadow_j2534_handler_send_error(thing, J2534_PassThruStartMsgFilter, ERR_DEVICE_NOT_OPEN); + } - gettimeofday(&start, NULL); - while(client->state == J2534_PassThruStartMsgFilter && milliseconds < J2534_TIMEOUT_MILLIS && - canbus_isconnected(client->canbus) && canbus_read(client->canbus, &frame) > 0) { + client->state = J2534_PassThruStartMsgFilter; - canbus_framecpy(&frame, data); - if(frame.can_id & CAN_ERR_FLAG) { - syslog(LOG_ERR, "passthru_shadow_j2534_handler_desired_select: CAN ERROR: %s", data); - continue; - } + struct can_filter *filters = malloc(sizeof(struct can_filter) * client->filters->size); - gettimeofday(&stop, NULL); - milliseconds = (stop.tv_sec - start.tv_sec) * 1000.0f + (stop.tv_usec - start.tv_usec) / 1000.0f; - syslog(LOG_DEBUG, "passthru_shadow_j2534_handler_desired_select: milliseconds=%f", milliseconds); + for(i=0; ifilters->count; i++) { - if(awsiot_client_publish(client->awsiot, client->msg_rx_topic, data) != 0) { - syslog(LOG_ERR, "passthru_shadow_j2534_handler_desired_select: failed to publish. topic=%s, rc=%d", client->msg_rx_topic, client->awsiot->rc); - return passthru_shadow_j2534_handler_send_error(thing, J2534_PassThruSelect, client->awsiot->rc); - } + j2534_canfilter *canfilter = (j2534_canfilter *)vector_get(client->filters, i); + filters[i].can_id = canfilter->can_id; + filters[i].can_mask = canfilter->can_mask; } + + canbus_filter(client->canbus, filters, client->filters->size); + + passthru_shadow_j2534_handler_send_report(J2534_PassThruStartMsgFilter); } void passthru_shadow_j2534_handler_handle_desired_state(passthru_thing *thing, shadow_j2534 *j2534) { @@ -279,6 +266,10 @@ void passthru_shadow_j2534_handler_handle_desired_state(passthru_thing *thing, s return passthru_shadow_j2534_handler_desired_select(thing, j2534); } + if(j2534->state == J2534_PassThruStartMsgFilter) { + return passthru_shadow_j2534_handler_desired_startMsgFilter(thing, j2534); + } + syslog(LOG_ERR, "passthru_shadow_j2534_handler_handle_desired_state: invalid state: %d", j2534->state); }