diff options
19 files changed, 939 insertions, 54 deletions
diff --git a/conf.d/cmake/config.cmake b/conf.d/cmake/config.cmake index f6573671..30d2b467 100644 --- a/conf.d/cmake/config.cmake +++ b/conf.d/cmake/config.cmake @@ -58,6 +58,23 @@ else() add_definitions(-DJ1939_NAME_ECU=${J1939_NAME_ECU}) endif() +# Activate ISO TP +# Need module in kernel +# -------------- + +execute_process(COMMAND ls /usr/include/linux/can/isotp.h RESULT_VARIABLE result2 OUTPUT_QUIET ERROR_QUIET) + +if(result2) + message("Feature ISO TP disabled") + set(WITH_FEATURE_ISOTP OFF) +else() + message("Feature ISOTP enabled") + set(WITH_FEATURE_ISOTP ON) + add_definitions(-DUSE_FEATURE_ISOTP) +endif() + + + # Kernel selection if needed. You can choose between a # mandatory version to impose a minimal version. # Or check Kernel minimal version and just print a Warning diff --git a/examples/tests/application-generated.cpp b/examples/tests/application-generated.cpp index 06ee30e4..7dd03d73 100644 --- a/examples/tests/application-generated.cpp +++ b/examples/tests/application-generated.cpp @@ -7,7 +7,187 @@ application_t::application_t() , message_set_{ {std::make_shared<message_set_t>(message_set_t{0,"AGL Virtual Car", { // beginning message_definition_ vector - {std::make_shared<message_definition_t>(message_definition_t{"ls",0x30,"",8,4,frequency_clock_t(5.00000f),true, + {std::make_shared<message_definition_t>(message_definition_t{"ls",0x111,"",16,66,frequency_clock_t(5.00000f),true, + { // beginning signals vector + {std::make_shared<signal_t> (signal_t{ + "sig1.1",// generic_name + 0,// bit_position + 16,// bit_size + 1.00000f,// factor + 0.00000f,// offset + 0,// min_value + 0,// max_value + frequency_clock_t(0.00000f),// frequency + true,// send_same + false,// force_send_changed + { + },// states + true,// writable + nullptr,// decoder + nullptr,// encoder + false,// received + std::make_pair<bool, int>(false, 0),// multiplex + 0,// is_big_endian + 0,// is_signed + ""// unit + })}, + {std::make_shared<signal_t> (signal_t{ + "sig1.2",// generic_name + 16,// bit_position + 16,// bit_size + 1.00000f,// factor + 0.00000f,// offset + 0,// min_value + 0,// max_value + frequency_clock_t(0.00000f),// frequency + true,// send_same + false,// force_send_changed + { + },// states + true,// writable + nullptr,// decoder + nullptr,// encoder + false,// received + std::make_pair<bool, int>(false, 0),// multiplex + 0,// is_big_endian + 0,// is_signed + ""// unit + })}, + {std::make_shared<signal_t> (signal_t{ + "sig2.1",// generic_name + 32,// bit_position + 16,// bit_size + 1.00000f,// factor + 0.00000f,// offset + 0,// min_value + 0,// max_value + frequency_clock_t(0.00000f),// frequency + true,// send_same + false,// force_send_changed + { + },// states + true,// writable + nullptr,// decoder + nullptr,// encoder + false,// received + std::make_pair<bool, int>(false, 0),// multiplex + 0,// is_big_endian + 0,// is_signed + ""// unit + })}, + {std::make_shared<signal_t> (signal_t{ + "sig2.2",// generic_name + 48,// bit_position + 16,// bit_size + 1.00000f,// factor + 0.00000f,// offset + 0,// min_value + 0,// max_value + frequency_clock_t(0.00000f),// frequency + true,// send_same + false,// force_send_changed + { + },// states + true,// writable + nullptr,// decoder + nullptr,// encoder + false,// received + std::make_pair<bool, int>(false, 0),// multiplex + 0,// is_big_endian + 0,// is_signed + ""// unit + })}, + {std::make_shared<signal_t> (signal_t{ + "sig3.1",// generic_name + 64,// bit_position + 16,// bit_size + 1.00000f,// factor + 0.00000f,// offset + 0,// min_value + 0,// max_value + frequency_clock_t(0.00000f),// frequency + true,// send_same + false,// force_send_changed + { + },// states + true,// writable + nullptr,// decoder + nullptr,// encoder + false,// received + std::make_pair<bool, int>(false, 0),// multiplex + 0,// is_big_endian + 0,// is_signed + ""// unit + })}, + {std::make_shared<signal_t> (signal_t{ + "sig3.2",// generic_name + 80,// bit_position + 16,// bit_size + 1.00000f,// factor + 0.00000f,// offset + 0,// min_value + 0,// max_value + frequency_clock_t(0.00000f),// frequency + true,// send_same + false,// force_send_changed + { + },// states + true,// writable + nullptr,// decoder + nullptr,// encoder + false,// received + std::make_pair<bool, int>(false, 0),// multiplex + 0,// is_big_endian + 0,// is_signed + ""// unit + })}, + {std::make_shared<signal_t> (signal_t{ + "sig4.1",// generic_name + 96,// bit_position + 16,// bit_size + 1.00000f,// factor + 0.00000f,// offset + 0,// min_value + 0,// max_value + frequency_clock_t(0.00000f),// frequency + true,// send_same + false,// force_send_changed + { + },// states + true,// writable + nullptr,// decoder + nullptr,// encoder + false,// received + std::make_pair<bool, int>(false, 0),// multiplex + 0,// is_big_endian + 0,// is_signed + ""// unit + })}, + {std::make_shared<signal_t> (signal_t{ + "sig4.2",// generic_name + 112,// bit_position + 16,// bit_size + 1.00000f,// factor + 0.00000f,// offset + 0,// min_value + 0,// max_value + frequency_clock_t(0.00000f),// frequency + true,// send_same + false,// force_send_changed + { + },// states + true,// writable + nullptr,// decoder + nullptr,// encoder + false,// received + std::make_pair<bool, int>(false, 0),// multiplex + 0,// is_big_endian + 0,// is_signed + ""// unit + })} + } // end signals vector + })} // end message_definition entry +, {std::make_shared<message_definition_t>(message_definition_t{"ls",0x30,"",8,4,frequency_clock_t(5.00000f),true, { // beginning signals vector {std::make_shared<signal_t> (signal_t{ "hvac.fan.speed",// generic_name diff --git a/examples/tests/signal.json b/examples/tests/signal.json index 1478caf8..a4de3584 100644 --- a/examples/tests/signal.json +++ b/examples/tests/signal.json @@ -213,6 +213,80 @@ } } }, + "0x111": { + "bus": "ls", + "is_fd" : false, + "is_extended": false, + "is_j1939" : false, + "is_isotp" : true, + "length" : 16, + "signals": { + "sig11": { + "generic_name": "sig1.1", + "bit_position": 0, + "bit_size": 16, + "factor": 1, + "offset": 0, + "writable": true + }, + "sig12": { + "generic_name": "sig1.2", + "bit_position": 16, + "bit_size": 16, + "factor": 1, + "offset": 0, + "writable": true + }, + "sig21": { + "generic_name": "sig2.1", + "bit_position": 32, + "bit_size": 16, + "factor": 1, + "offset": 0, + "writable": true + }, + "sig22": { + "generic_name": "sig2.2", + "bit_position": 48, + "bit_size": 16, + "factor": 1, + "offset": 0, + "writable": true + }, + "sig31": { + "generic_name": "sig3.1", + "bit_position": 64, + "bit_size": 16, + "factor": 1, + "offset": 0, + "writable": true + }, + "sig32": { + "generic_name": "sig3.2", + "bit_position": 80, + "bit_size": 16, + "factor": 1, + "offset": 0, + "writable": true + }, + "sig41": { + "generic_name": "sig4.1", + "bit_position": 96, + "bit_size": 16, + "factor": 1, + "offset": 0, + "writable": true + }, + "sig42": { + "generic_name": "sig4.2", + "bit_position": 112, + "bit_size": 16, + "factor": 1, + "offset": 0, + "writable": true + } + } + }, "61442": { "comment": "Electronic Transmission Controller 1", "length": 8, diff --git a/low-can-binding/CMakeLists.txt b/low-can-binding/CMakeLists.txt index 3c698c73..ada0e808 100644 --- a/low-can-binding/CMakeLists.txt +++ b/low-can-binding/CMakeLists.txt @@ -49,6 +49,14 @@ PROJECT_TARGET_ADD(low-can) binding/application-generated.cpp ) + + if(WITH_FEATURE_ISOTP) + set(SOURCES_ISOTP + utils/socketcan-isotp.cpp + ) + endif() + + if(WITH_FEATURE_J1939) set(SOURCES_J1939 can/message/j1939-message.cpp @@ -58,7 +66,7 @@ PROJECT_TARGET_ADD(low-can) ) endif() - add_library(${TARGET_NAME} MODULE ${SOURCES} ${SOURCES_J1939}) + add_library(${TARGET_NAME} MODULE ${SOURCES} ${SOURCES_J1939} ${SOURCES_ISOTP}) set(OPENAPI_DEF "binding/low-can-apidef" CACHE STRING "name and path to the JSON API definition without extension") # Binder exposes a unique public entry point diff --git a/low-can-binding/binding/application-generated.cpp b/low-can-binding/binding/application-generated.cpp index 47fdafa5..bd1837fc 100644 --- a/low-can-binding/binding/application-generated.cpp +++ b/low-can-binding/binding/application-generated.cpp @@ -449,6 +449,188 @@ application_t::application_t() })} } // end signals vector })} // end message_definition entry +#ifdef USE_FEATURE_ISOTP +, {std::make_shared<message_definition_t>(message_definition_t{"ls",0x111,"",16,66,frequency_clock_t(5.00000f),true, + { // beginning signals vector + {std::make_shared<signal_t> (signal_t{ + "sig1.1",// generic_name + 0,// bit_position + 16,// bit_size + 1.00000f,// factor + 0.00000f,// offset + 0,// min_value + 0,// max_value + frequency_clock_t(0.00000f),// frequency + true,// send_same + false,// force_send_changed + { + },// states + true,// writable + nullptr,// decoder + nullptr,// encoder + false,// received + std::make_pair<bool, int>(false, 0),// multiplex + 0,// is_big_endian + 0,// is_signed + ""// unit + })}, + {std::make_shared<signal_t> (signal_t{ + "sig1.2",// generic_name + 16,// bit_position + 16,// bit_size + 1.00000f,// factor + 0.00000f,// offset + 0,// min_value + 0,// max_value + frequency_clock_t(0.00000f),// frequency + true,// send_same + false,// force_send_changed + { + },// states + true,// writable + nullptr,// decoder + nullptr,// encoder + false,// received + std::make_pair<bool, int>(false, 0),// multiplex + 0,// is_big_endian + 0,// is_signed + ""// unit + })}, + {std::make_shared<signal_t> (signal_t{ + "sig2.1",// generic_name + 32,// bit_position + 16,// bit_size + 1.00000f,// factor + 0.00000f,// offset + 0,// min_value + 0,// max_value + frequency_clock_t(0.00000f),// frequency + true,// send_same + false,// force_send_changed + { + },// states + true,// writable + nullptr,// decoder + nullptr,// encoder + false,// received + std::make_pair<bool, int>(false, 0),// multiplex + 0,// is_big_endian + 0,// is_signed + ""// unit + })}, + {std::make_shared<signal_t> (signal_t{ + "sig2.2",// generic_name + 48,// bit_position + 16,// bit_size + 1.00000f,// factor + 0.00000f,// offset + 0,// min_value + 0,// max_value + frequency_clock_t(0.00000f),// frequency + true,// send_same + false,// force_send_changed + { + },// states + true,// writable + nullptr,// decoder + nullptr,// encoder + false,// received + std::make_pair<bool, int>(false, 0),// multiplex + 0,// is_big_endian + 0,// is_signed + ""// unit + })}, + {std::make_shared<signal_t> (signal_t{ + "sig3.1",// generic_name + 64,// bit_position + 16,// bit_size + 1.00000f,// factor + 0.00000f,// offset + 0,// min_value + 0,// max_value + frequency_clock_t(0.00000f),// frequency + true,// send_same + false,// force_send_changed + { + },// states + true,// writable + nullptr,// decoder + nullptr,// encoder + false,// received + std::make_pair<bool, int>(false, 0),// multiplex + 0,// is_big_endian + 0,// is_signed + ""// unit + })}, + {std::make_shared<signal_t> (signal_t{ + "sig3.2",// generic_name + 80,// bit_position + 16,// bit_size + 1.00000f,// factor + 0.00000f,// offset + 0,// min_value + 0,// max_value + frequency_clock_t(0.00000f),// frequency + true,// send_same + false,// force_send_changed + { + },// states + true,// writable + nullptr,// decoder + nullptr,// encoder + false,// received + std::make_pair<bool, int>(false, 0),// multiplex + 0,// is_big_endian + 0,// is_signed + ""// unit + })}, + {std::make_shared<signal_t> (signal_t{ + "sig4.1",// generic_name + 96,// bit_position + 16,// bit_size + 1.00000f,// factor + 0.00000f,// offset + 0,// min_value + 0,// max_value + frequency_clock_t(0.00000f),// frequency + true,// send_same + false,// force_send_changed + { + },// states + true,// writable + nullptr,// decoder + nullptr,// encoder + false,// received + std::make_pair<bool, int>(false, 0),// multiplex + 0,// is_big_endian + 0,// is_signed + ""// unit + })}, + {std::make_shared<signal_t> (signal_t{ + "sig4.2",// generic_name + 112,// bit_position + 16,// bit_size + 1.00000f,// factor + 0.00000f,// offset + 0,// min_value + 0,// max_value + frequency_clock_t(0.00000f),// frequency + true,// send_same + false,// force_send_changed + { + },// states + true,// writable + nullptr,// decoder + nullptr,// encoder + false,// received + std::make_pair<bool, int>(false, 0),// multiplex + 0,// is_big_endian + 0,// is_signed + ""// unit + })} + } // end signals vector + })} // end message_definition entry +#endif #ifdef USE_FEATURE_J1939 , {std::make_shared<message_definition_t>(message_definition_t{"j1939",61442,"ETC1",8,18,frequency_clock_t(5.00000f),true, { // beginning signals vector diff --git a/low-can-binding/binding/low-can-cb.cpp b/low-can-binding/binding/low-can-cb.cpp index c677b172..2c6e2be3 100644 --- a/low-can-binding/binding/low-can-cb.cpp +++ b/low-can-binding/binding/low-can-cb.cpp @@ -334,6 +334,12 @@ static event_filter_t generate_filter(json_object* args) if (json_object_object_get_ex(filter, "max", &obj) && (json_object_is_type(obj, json_type_double) || json_object_is_type(obj, json_type_int))) {event_filter.max = (float)json_object_get_double(obj);} + if (json_object_object_get_ex(filter, "rx_id", &obj) + && (json_object_is_type(obj, json_type_int))) + {event_filter.rx_id = (canid_t) json_object_get_int(obj);} + if (json_object_object_get_ex(filter, "tx_id", &obj) + && (json_object_is_type(obj, json_type_int))) + {event_filter.tx_id = (canid_t) json_object_get_int(obj);} } return event_filter; } @@ -515,7 +521,7 @@ static int send_frame(struct canfd_frame& cfd, const std::string& bus_name, sock } } */ -static int send_message(message_t *message, const std::string& bus_name, uint32_t flags) +static int send_message(message_t *message, const std::string& bus_name, uint32_t flags, event_filter_t &event_filter, std::shared_ptr<signal_t> signal) { if(bus_name.empty()) { @@ -526,14 +532,22 @@ static int send_message(message_t *message, const std::string& bus_name, uint32_ if( cd.count(bus_name) == 0) { - cd[bus_name] = std::make_shared<low_can_subscription_t>(low_can_subscription_t()); + cd[bus_name] = std::make_shared<low_can_subscription_t>(low_can_subscription_t(event_filter)); } + cd[bus_name]->set_signal(signal); + if(flags&BCM_PROTOCOL) { return low_can_subscription_t::tx_send(*cd[bus_name], message, bus_name); } +#ifdef USE_FEATURE_ISOTP + else if(flags&ISOTP_PROTOCOL) + { + return low_can_subscription_t::isotp_send(*cd[bus_name], message, bus_name); + } +#endif #ifdef USE_FEATURE_J1939 else if(flags&J1939_PROTOCOL) { @@ -547,7 +561,8 @@ static int send_message(message_t *message, const std::string& bus_name, uint32_ } -static void write_raw_frame(afb_req_t request, const std::string& bus_name, message_t *message, struct json_object *can_data, uint32_t flags) +static void write_raw_frame(afb_req_t request, const std::string& bus_name, message_t *message, + struct json_object *can_data, uint32_t flags, event_filter_t &event_filter) { struct utils::signals_found sf; @@ -570,17 +585,22 @@ static void write_raw_frame(afb_req_t request, const std::string& bus_name, mess AFB_DEBUG("CAN_MAX_DLEN"); message->set_maxdlen(CAN_MAX_DLEN); } + + if(sf.signals[0]->get_message()->is_isotp()) + { + flags = ISOTP_PROTOCOL; + message->set_maxdlen(MAX_ISOTP_FRAMES * message->get_maxdlen()); + } + } + +#ifdef USE_FEATURE_J1939 + if(flags&J1939_PROTOCOL) + { + message->set_maxdlen(J1939_MAX_DLEN); } +#endif - if((message->get_length()> 0 && ( - ((flags&BCM_PROTOCOL) && ( - (message->get_length() <= CANFD_MAX_DLEN * MAX_BCM_CAN_FRAMES && message->get_flags() & CAN_FD_FRAME) - || (message->get_length() <= CAN_MAX_DLEN * MAX_BCM_CAN_FRAMES && !(message->get_flags() & CAN_FD_FRAME)) - )) - #ifdef USE_FEATURE_J1939 - || (message->get_length() <= J1939_MAX_DLEN && flags&J1939_PROTOCOL) - #endif - ))) + if(message->get_length() > 0 && message->get_length() <= message->get_maxdlen()) { std::vector<uint8_t> data; for (int i = 0 ; i < message->get_length() ; i++) @@ -601,6 +621,10 @@ static void write_raw_frame(afb_req_t request, const std::string& bus_name, mess { afb_req_fail(request, "Invalid", "Frame J1939"); } + else if(flags&ISOTP_PROTOCOL) + { + afb_req_fail(request, "Invalid", "Frame ISOTP"); + } else { afb_req_fail(request, "Invalid", "Frame"); @@ -608,7 +632,7 @@ static void write_raw_frame(afb_req_t request, const std::string& bus_name, mess return; } - if(! send_message(message, application_t::instance().get_can_bus_manager().get_can_device_name(bus_name),flags)) + if(! send_message(message, application_t::instance().get_can_bus_manager().get_can_device_name(bus_name), flags, event_filter, sf.signals[0])) { afb_req_success(request, nullptr, "Message correctly sent"); } @@ -624,7 +648,7 @@ static void write_raw_frame(afb_req_t request, const std::string& bus_name, mess } -static void write_frame(afb_req_t request, const std::string& bus_name, json_object *json_value) +static void write_frame(afb_req_t request, const std::string& bus_name, json_object *json_value, event_filter_t &event_filter) { message_t *message; int id; @@ -640,7 +664,7 @@ static void write_frame(afb_req_t request, const std::string& bus_name, json_obj "can_data", &can_data)) { message = new can_message_t(0,(uint32_t)id,(uint32_t)length,false,0,data,0); - write_raw_frame(request,bus_name,message,can_data,BCM_PROTOCOL); + write_raw_frame(request,bus_name,message,can_data,BCM_PROTOCOL,event_filter); } #ifdef USE_FEATURE_J1939 else if(!wrap_json_unpack(json_value, "{si, si, so !}", @@ -649,7 +673,7 @@ static void write_frame(afb_req_t request, const std::string& bus_name, json_obj "data", &can_data)) { message = new j1939_message_t((uint32_t)length,data,0,J1939_NO_NAME,(pgn_t)id,J1939_NO_ADDR); - write_raw_frame(request,bus_name,message,can_data,J1939_PROTOCOL); + write_raw_frame(request,bus_name,message,can_data,J1939_PROTOCOL, event_filter); } #endif else @@ -660,7 +684,7 @@ static void write_frame(afb_req_t request, const std::string& bus_name, json_obj delete message; } -static void write_signal(afb_req_t request, const std::string& name, json_object *json_value) +static void write_signal(afb_req_t request, const std::string& name, json_object *json_value, event_filter_t &event_filter) { struct canfd_frame cfd; struct utils::signals_found sf; @@ -679,7 +703,7 @@ static void write_signal(afb_req_t request, const std::string& name, json_object return; } - std::shared_ptr<signal_t>& sig = sf.signals[0]; + std::shared_ptr<signal_t> sig = sf.signals[0]; if(! sig->get_writable()) { afb_req_fail_f(request, "%s isn't writable. Message not sent.", sig->get_name().c_str()); @@ -696,6 +720,10 @@ static void write_signal(afb_req_t request, const std::string& name, json_object { flags = J1939_PROTOCOL; } + else if(sig->get_message()->is_isotp()) + { + flags = ISOTP_PROTOCOL; + } else { flags = BCM_PROTOCOL; @@ -704,7 +732,7 @@ static void write_signal(afb_req_t request, const std::string& name, json_object // cfd = encoder_t::build_frame(sig, value); message_t *message = encoder_t::build_message(sig,value,false,false); - if(! send_message(message, sig->get_message()->get_bus_device_name(), flags) && send) + if(! send_message(message, sig->get_message()->get_bus_device_name(), flags, event_filter, sig) && send) { afb_req_success(request, nullptr, "Message correctly sent"); } @@ -727,25 +755,43 @@ static void write_signal(afb_req_t request, const std::string& name, json_object void write(afb_req_t request) { - struct json_object* args = nullptr, *json_value = nullptr; - const char *name = nullptr; - + struct json_object* args = nullptr, *json_value = nullptr, *name = nullptr; args = afb_req_json(request); - // Process about Raw CAN message on CAN bus directly - if (args != NULL && ! wrap_json_unpack(args, "{ss, so !}", - "bus_name", &name, - "frame", &json_value)) - write_frame(request, name, json_value); - - // Search signal then encode value. - else if(args != NULL && - ! wrap_json_unpack(args, "{ss, so !}", - "signal_name", &name, - "signal_value", &json_value)) - write_signal(request, std::string(name), json_value); + if(args != NULL) + { + event_filter_t event_filter = generate_filter(args); + + if(json_object_object_get_ex(args,"bus_name",&name)) + { + if(json_object_object_get_ex(args,"frame",&json_value)) + { + write_frame(request, (std::string)json_object_get_string(name), json_value, event_filter); + } + else + { + afb_req_fail(request, "Error", "Request argument malformed"); + } + } + else if(json_object_object_get_ex(args,"signal_name",&name)) + { + if(json_object_object_get_ex(args,"signal_value",&json_value)) + { + write_signal(request, (std::string)json_object_get_string(name), json_value, event_filter); + } + else + { + afb_req_fail(request, "Error", "Request argument malformed"); + } + } + else { + afb_req_fail(request, "Error", "Request argument malformed"); + } + } else - afb_req_fail(request, "Error", "Request argument malformed"); + { + afb_req_fail(request, "Error", "Request argument null"); + } } static struct json_object *get_signals_value(const std::string& name) diff --git a/low-can-binding/binding/low-can-subscription.cpp b/low-can-binding/binding/low-can-subscription.cpp index 0f4bf0c9..6d02b101 100644 --- a/low-can-binding/binding/low-can-subscription.cpp +++ b/low-can-binding/binding/low-can-subscription.cpp @@ -22,6 +22,10 @@ #include "../utils/socketcan-bcm.hpp" #include "../can/can-encoder.hpp" +#ifdef USE_FEATURE_ISOTP +#include "../utils/socketcan-isotp.hpp" +#endif + #ifdef USE_FEATURE_J1939 #include "../utils/socketcan-j1939/socketcan-j1939-data.hpp" #endif @@ -212,6 +216,16 @@ float low_can_subscription_t::get_max() const return event_filter_.max; } +canid_t low_can_subscription_t::get_rx_id() const +{ + return event_filter_.rx_id; +} + +canid_t low_can_subscription_t::get_tx_id() const +{ + return event_filter_.tx_id; +} + std::shared_ptr<utils::socketcan_t> low_can_subscription_t::get_socket() { return socket_; @@ -232,11 +246,27 @@ void low_can_subscription_t::set_max(float max) event_filter_.max = max; } +void low_can_subscription_t::set_rx_id(canid_t rx_id) +{ + event_filter_.rx_id = rx_id; +} + +void low_can_subscription_t::set_tx_id(canid_t tx_id) +{ + event_filter_.tx_id = tx_id; +} + void low_can_subscription_t::set_index(int index) { index_ = index; } +void low_can_subscription_t::set_signal(std::shared_ptr<signal_t> signal) +{ + signal_ = signal; +} + + /// @brief Based upon which object is a subscribed CAN signal or diagnostic message /// it will open the socket with the required CAN bus device name. /// @@ -265,6 +295,36 @@ int low_can_subscription_t::open_socket(low_can_subscription_t &subscription, co } subscription.index_ = (int)subscription.socket_->socket(); } +#ifdef USE_FEATURE_ISOTP + else if(flags&ISOTP_PROTOCOL) + { + if(subscription.signal_ != nullptr) + { + canid_t rx = NO_CAN_ID; + canid_t tx = NO_CAN_ID; + if(flags&ISOTP_SEND) + { + rx = subscription.get_rx_id(); + tx = subscription.signal_->get_message()->get_id(); + } + else if(flags&ISOTP_RECEIVE) + { + rx = subscription.signal_->get_message()->get_id(); + tx = subscription.get_tx_id(); + } + std::shared_ptr<utils::socketcan_isotp_t> socket = std::make_shared<utils::socketcan_isotp_t>(); + ret = socket->open(subscription.signal_->get_message()->get_bus_device_name(),rx,tx); + subscription.socket_ = socket; + } + else if(!bus_name.empty()) + { + std::shared_ptr<utils::socketcan_isotp_t> socket = std::make_shared<utils::socketcan_isotp_t>(); + ret = socket->open(bus_name, subscription.get_rx_id(),subscription.get_tx_id()); + subscription.socket_ = socket; + } + subscription.index_ = (int)subscription.socket_->socket(); + } +#endif #ifdef USE_FEATURE_J1939 else if(flags&J1939_ADDR_CLAIM_PROTOCOL) { @@ -374,6 +434,18 @@ int low_can_subscription_t::create_rx_filter_j1939(low_can_subscription_t &subsc } #endif +int low_can_subscription_t::create_rx_filter_isotp(low_can_subscription_t &subscription, std::shared_ptr<signal_t> sig) +{ + subscription.signal_= sig; + + // Make sure that socket is opened. + if(open_socket(subscription,"",ISOTP_PROTOCOL|ISOTP_RECEIVE) < 0) + { + return -1; + } + return 0; +} + /// @brief Create a RX_SETUP receive job to be used by the BCM socket for a CAN signal /// subscription /// @@ -462,18 +534,27 @@ int low_can_subscription_t::create_rx_filter_can(low_can_subscription_t &subscri int low_can_subscription_t::create_rx_filter(std::shared_ptr<signal_t> sig) { - #ifdef USE_FEATURE_J1939 - if(sig->get_message()->is_j1939()) + if(!sig->get_message()->is_isotp() && !sig->get_message()->is_j1939()) + { + return low_can_subscription_t::create_rx_filter_can(*this, sig); + } +#ifdef USE_FEATURE_ISOTP + else if(sig->get_message()->is_isotp()) + { + return low_can_subscription_t::create_rx_filter_isotp(*this,sig); + } +#endif +#ifdef USE_FEATURE_J1939 + else if(sig->get_message()->is_j1939()) { return low_can_subscription_t::create_rx_filter_j1939(*this, sig); } +#endif else { - #endif - return low_can_subscription_t::create_rx_filter_can(*this, sig); - #ifdef USE_FEATURE_J1939 + AFB_ERROR("Signal can't be j1939 and isotp"); + return -1; } - #endif } @@ -607,3 +688,24 @@ int low_can_subscription_t::j1939_send(low_can_subscription_t &subscription, mes return 0; } #endif + + +int low_can_subscription_t::isotp_send(low_can_subscription_t &subscription, message_t *message, const std::string& bus_name) +{ + //struct bcm_msg bcm_msg = subscription.make_bcm_head(TX_SEND, cfd.can_id); + //subscription.add_one_bcm_frame(cfd, bcm_msg); + + if(subscription.open_socket(subscription, bus_name, ISOTP_PROTOCOL|ISOTP_SEND) < 0) + { + return -1; + } + + can_message_t *cm = static_cast<can_message_t*>(message); + if(subscription.socket_->write_message(*cm) < 0) + { + AFB_ERROR("Error write iso tp message"); + return -1; + } + + return 0; +}
\ No newline at end of file diff --git a/low-can-binding/binding/low-can-subscription.hpp b/low-can-binding/binding/low-can-subscription.hpp index b152e4b2..3f2c3acd 100644 --- a/low-can-binding/binding/low-can-subscription.hpp +++ b/low-can-binding/binding/low-can-subscription.hpp @@ -35,10 +35,12 @@ struct event_filter_t float frequency; ///< frequency - Maximum frequency which will be received and pushed to a subscribed event. float min; ///< min - Minimum value that the signal doesn't have to go below to be pushed. float max; ///< max - Maximum value that the signal doesn't have to go above to be pushed. + canid_t rx_id; + canid_t tx_id; - event_filter_t() : frequency{0}, min{-__FLT_MAX__}, max{__FLT_MAX__} {}; + event_filter_t() : frequency{0}, min{-__FLT_MAX__}, max{__FLT_MAX__}, rx_id{NO_CAN_ID}, tx_id{NO_CAN_ID} {}; bool operator==(const event_filter_t& ext) const { - return frequency == ext.frequency && min == ext.min && max == ext.max; + return frequency == ext.frequency && min == ext.min && max == ext.max && rx_id == ext.rx_id && tx_id == ext.tx_id; } }; @@ -84,12 +86,17 @@ public: float get_frequency() const; float get_min() const; float get_max() const; + canid_t get_rx_id() const; + canid_t get_tx_id() const; std::shared_ptr<utils::socketcan_t> get_socket(); void set_frequency(float freq); void set_min(float min); void set_max(float max); void set_index(int index); + void set_rx_id(canid_t rx_id); + void set_tx_id(canid_t tx_id); + void set_signal(std::shared_ptr<signal_t> signal); static struct bcm_msg make_bcm_head(uint32_t opcode, uint32_t can_id = 0, uint32_t flags = 0, const struct timeval& timeout = {0,0}, const struct timeval& frequency_thinning = {0,0}); static void add_one_bcm_frame(struct canfd_frame& cfd, struct bcm_msg& bcm_msg); @@ -101,8 +108,10 @@ public: int create_rx_filter(std::shared_ptr<diagnostic_message_t> sig); static int create_rx_filter_can(low_can_subscription_t &subscription, std::shared_ptr<signal_t> sig); static int create_rx_filter_j1939(low_can_subscription_t &subscription, std::shared_ptr<signal_t> sig); + static int create_rx_filter_isotp(low_can_subscription_t &subscription, std::shared_ptr<signal_t> sig); static int create_rx_filter_bcm(low_can_subscription_t &subscription, bcm_msg& bcm_msg); static int tx_send(low_can_subscription_t &subscription, message_t *message, const std::string& bus_name); static int j1939_send(low_can_subscription_t &subscription, message_t *message, const std::string& bus_name); + static int isotp_send(low_can_subscription_t &subscription, message_t *message, const std::string& bus_name); }; diff --git a/low-can-binding/can/message-definition.cpp b/low-can-binding/can/message-definition.cpp index 407ad750..a875dafa 100644 --- a/low-can-binding/can/message-definition.cpp +++ b/low-can-binding/can/message-definition.cpp @@ -77,6 +77,11 @@ bool message_definition_t::is_j1939() const return (flags_&J1939_PROTOCOL); } +bool message_definition_t::is_isotp() const +{ + return (flags_&ISOTP_PROTOCOL); +} + std::vector<std::shared_ptr<signal_t>>& message_definition_t::get_signals() { return signals_; diff --git a/low-can-binding/can/message-definition.hpp b/low-can-binding/can/message-definition.hpp index 13ae2289..f46d3adb 100644 --- a/low-can-binding/can/message-definition.hpp +++ b/low-can-binding/can/message-definition.hpp @@ -82,6 +82,7 @@ public: uint32_t get_id() const; bool is_fd() const; bool is_j1939() const; + bool is_isotp() const; std::vector<std::shared_ptr<signal_t>>& get_signals(); uint32_t get_length() const; uint32_t get_flags() const; diff --git a/low-can-binding/can/message/can-message.cpp b/low-can-binding/can/message/can-message.cpp index 0ef693c7..b274206b 100644 --- a/low-can-binding/can/message/can-message.cpp +++ b/low-can-binding/can/message/can-message.cpp @@ -55,6 +55,11 @@ uint32_t can_message_t::get_id() const } +void can_message_t::set_id(const canid_t id) +{ + id_ = id; +} + /// @brief Control whether the object is correctly initialized /// to be sent over the CAN bus /// diff --git a/low-can-binding/can/message/can-message.hpp b/low-can-binding/can/message/can-message.hpp index 769899ea..acc3bfc1 100644 --- a/low-can-binding/can/message/can-message.hpp +++ b/low-can-binding/can/message/can-message.hpp @@ -39,8 +39,16 @@ class can_message_t : public message_t { public: can_message_t(); - can_message_t(uint32_t maxdlen, uint32_t id, uint32_t length, bool rtr_flag_, uint32_t flags, std::vector<uint8_t>& data, uint64_t timestamp); + can_message_t( uint32_t maxdlen, + uint32_t id, + uint32_t length, + bool rtr_flag_, + uint32_t flags, + std::vector<uint8_t>& data, + uint64_t timestamp); + uint32_t get_id() const; + void set_id(const canid_t id); static std::shared_ptr<can_message_t> convert_from_frame(const canfd_frame& frame, size_t nbytes, uint64_t timestamp); struct canfd_frame convert_to_canfd_frame(); @@ -53,5 +61,4 @@ class can_message_t : public message_t { void set_bcm_msg(struct bcm_msg bcm_msg); std::string get_debug_message(); - }; diff --git a/low-can-binding/can/message/j1939-message.cpp b/low-can-binding/can/message/j1939-message.cpp index ec65cba4..8e056c17 100644 --- a/low-can-binding/can/message/j1939-message.cpp +++ b/low-can-binding/can/message/j1939-message.cpp @@ -159,6 +159,12 @@ uint32_t j1939_message_t::get_id() const return get_pgn(); } +void j1939_message_t::set_id(const canid_t id) +{ + pgn_ = id; +} + + /** * @brief Return the sockname of the message * diff --git a/low-can-binding/can/message/j1939-message.hpp b/low-can-binding/can/message/j1939-message.hpp index 9e9cea4a..a513e94e 100644 --- a/low-can-binding/can/message/j1939-message.hpp +++ b/low-can-binding/can/message/j1939-message.hpp @@ -75,6 +75,7 @@ class j1939_message_t : public message_t bool is_set(); std::string get_debug_message(); uint32_t get_id() const; + void set_id(const canid_t id); struct sockaddr_can get_sockname(); void set_sockname(struct sockaddr_can sockname); void set_sockname(pgn_t pgn, name_t name, uint8_t addr); diff --git a/low-can-binding/can/message/message.cpp b/low-can-binding/can/message/message.cpp index aaab99f5..2496b672 100644 --- a/low-can-binding/can/message/message.cpp +++ b/low-can-binding/can/message/message.cpp @@ -135,7 +135,7 @@ uint32_t message_t::get_length() const * * @param data A vector of data */ -void message_t::set_data(std::vector<uint8_t> &data) +void message_t::set_data(std::vector<uint8_t> data) { data_ = data; } @@ -170,13 +170,22 @@ void message_t::set_flags(uint32_t flags) flags_ = flags_ | flags; } +void message_t::erase_flags() +{ + flags_ = 0; +} + uint32_t message_t::get_maxdlen() { return maxdlen_; } - void message_t::set_maxdlen(uint32_t maxdlen) { maxdlen_ = maxdlen; +} + +void message_t::set_length(uint32_t length) +{ + length_ = length; }
\ No newline at end of file diff --git a/low-can-binding/can/message/message.hpp b/low-can-binding/can/message/message.hpp index 6cef0185..db06eb38 100644 --- a/low-can-binding/can/message/message.hpp +++ b/low-can-binding/can/message/message.hpp @@ -29,6 +29,7 @@ #define CAN_MESSAGE_SIZE 8 #define MAX_BCM_CAN_FRAMES 257 +#define MAX_ISOTP_FRAMES 4096 /** @@ -42,6 +43,8 @@ #define J1939_PROTOCOL 0x0010 #define J1939_ADDR_CLAIM_PROTOCOL 0x0020 #define ISOTP_PROTOCOL 0x0040 +#define ISOTP_SEND 0x0080 +#define ISOTP_RECEIVE 0x0100 #define FD_FRAME 0x0800 /// @class message_t @@ -69,16 +72,17 @@ public: uint32_t get_length() const; uint64_t get_timestamp() const; - void set_data(std::vector<uint8_t> &data); + void set_data(std::vector<uint8_t> data); void set_sub_id(int sub_id); void set_timestamp(uint64_t timestamp); virtual bool is_set() = 0; virtual std::string get_debug_message() = 0; virtual uint32_t get_id() const = 0; + virtual void set_id(canid_t id) = 0; uint32_t get_flags(); void set_flags(uint32_t flags); + void erase_flags(); uint32_t get_maxdlen(); void set_maxdlen(uint32_t maxdlen); - - + void set_length(uint32_t length); }; diff --git a/low-can-binding/utils/socketcan-isotp.cpp b/low-can-binding/utils/socketcan-isotp.cpp new file mode 100644 index 00000000..1aab9afa --- /dev/null +++ b/low-can-binding/utils/socketcan-isotp.cpp @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2019, 2020 "IoT.bzh" + * Author "Arthur Guyader" <arthur.guyader@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "socketcan-isotp.hpp" + +#include <net/if.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <unistd.h> +#include "../utils/converter.hpp" +#include "../binding/application.hpp" + +namespace utils +{ + /** + * @brief Open ISOTP socket this default function will not work, because + * isotp need rx_id and tx_id + * + * @param device_name The device name where to open socket + * @return int -1 fail + */ + int socketcan_isotp_t::open(std::string device_name) + { + AFB_WARNING("NOT USE THIS FUNCTION !"); + return open(device_name,NO_CAN_ID,NO_CAN_ID); + } + + /** + * @brief Open ISOTP socket, the socket will be open and bind + * with rx_id and tx_id + * + * @param device_name The device name where to open socket + * @param rx_id The source can_id + * @param tx_id The destination can_id + * @return int 0 if ok else -1 + */ + int socketcan_isotp_t::open(std::string device_name, canid_t rx_id, canid_t tx_id) + { + close(); + socket_ = socketcan_t::open(PF_CAN, SOCK_DGRAM, CAN_ISOTP); + + if(socket_ < 0) + { + AFB_ERROR("Error open ISO TP socket"); + return -1; + } + + if(define_tx_address(device_name,rx_id,tx_id) < 0) + { + return -1; + } + + struct can_isotp_options opts; + memset(&opts,0,sizeof(opts)); + setopt(SOL_CAN_ISOTP, CAN_ISOTP_OPTS, &opts, sizeof(opts)); + + if(bind((struct sockaddr *)&tx_address_, sizeof(tx_address_)) < 0) + { + AFB_ERROR("Bind failed. %s", strerror(errno)); + close(); + return -1; + } + + return socket_; + } + + /** + * @brief Allows to read message + * + * @return std::shared_ptr<message_t> The message that was read + */ + std::shared_ptr<message_t> socketcan_isotp_t::read_message() + { + + std::shared_ptr<can_message_t> cm = std::make_shared<can_message_t>(); + uint8_t msg[MAX_ISOTP_FRAMES]; + ssize_t nbytes = read(socket(),msg,MAX_ISOTP_FRAMES); + + cm->set_id(tx_address_.can_addr.tp.rx_id); + + if(nbytes < 0) + { + AFB_ERROR("Can't read the next message from socket '%d'. '%s'", socket(), strerror(errno)); + return cm; + } + + std::vector<uint8_t> data; + for (int i=0; i < nbytes; i++) + { + data.push_back(msg[i]); + } + + std::string data_string; + data_string = converter_t::to_hex(msg,nbytes); + AFB_DEBUG("DATA ISO TP for id : %x = %s",cm->get_id(),data_string.c_str()); + + + cm->set_data(data); + cm->erase_flags(); + cm->set_flags(ISOTP_PROTOCOL); + cm->set_length((uint32_t)nbytes); + cm->set_sub_id((int)socket()); + // Need to define behaviour + + return cm; + } + + /** + * @brief Allows to write can message + * + * @param m The message to send + * @return int 0 if ok else -1 + */ + int socketcan_isotp_t::write_message(message_t& m) + { + size_t size = m.get_length(); + if(size < MAX_ISOTP_FRAMES) + { + ssize_t ret = write(socket(),m.get_data(),size); + if(ret < 0) + { + AFB_ERROR("Error sending : %i %s", errno, ::strerror(errno)); + return -1; + } + + if(ret != size) + { + AFB_WARNING("ISOTP wrote only %zd byte",ret); + } + } + else + { + AFB_ERROR("Error sending too much data"); + return -1; + } + + return 0; + } + + /** + * @brief Define the tx address for the bind function + * + * @param device_name The device can that you want to bind + * @param rx_id The source can_id + * @param tx_id The destination can_id + * @return int 0 if ok else -1 + */ + int socketcan_isotp_t::define_tx_address(std::string device_name, canid_t rx_id, canid_t tx_id) + { + struct ifreq ifr; + ::strcpy(ifr.ifr_name, device_name.c_str()); + AFB_DEBUG("ifr_name is : %s", ifr.ifr_name); + + if(::ioctl(socket_, SIOCGIFINDEX, &ifr) < 0) + { + AFB_ERROR("ioctl failed. Error was : %s", strerror(errno)); + close(); + } + else + { + tx_address_.can_ifindex = ifr.ifr_ifindex; + } + + tx_address_.can_family = AF_CAN; + + if(tx_id == NO_CAN_ID || rx_id == NO_CAN_ID) + { + AFB_ERROR("Error tx_id or rx_id"); + return -1; + } + + tx_address_.can_addr.tp.rx_id = rx_id; + tx_address_.can_addr.tp.tx_id = tx_id; + + return 0; + } +}
\ No newline at end of file diff --git a/low-can-binding/utils/socketcan-isotp.hpp b/low-can-binding/utils/socketcan-isotp.hpp new file mode 100644 index 00000000..86ed9faf --- /dev/null +++ b/low-can-binding/utils/socketcan-isotp.hpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019, 2020 "IoT.bzh" + * Author "Arthur Guyader" <arthur.guyader@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <linux/can/isotp.h> +#include "socketcan.hpp" +#include "../can/message/can-message.hpp" + +#define CAN_ISOTP_MAX_DLEN 4096 + +namespace utils +{ + class socketcan_isotp_t : public socketcan_t + { + public: + using socketcan_t::socketcan_t; + + virtual int open(std::string device_name); + virtual int open(std::string device_name, canid_t rx_id, canid_t tx_id); + virtual std::shared_ptr<message_t> read_message(); + virtual int write_message(message_t& obj); + int define_tx_address(std::string device_name, canid_t rx_id, canid_t tx_id); + }; +}
\ No newline at end of file diff --git a/low-can-binding/utils/socketcan.hpp b/low-can-binding/utils/socketcan.hpp index 6391d011..a3b31591 100644 --- a/low-can-binding/utils/socketcan.hpp +++ b/low-can-binding/utils/socketcan.hpp @@ -27,6 +27,7 @@ #include "../can/message/can-message.hpp" #define INVALID_SOCKET -1 +#define NO_CAN_ID 0xFFFFFFFFU namespace utils { @@ -58,6 +59,4 @@ namespace utils int bind(const struct sockaddr* addr, socklen_t len); int connect(const struct sockaddr* addr, socklen_t len); }; - - } |