diff --git a/Firmware/fibre/cpp/include/fibre/protocol.hpp b/Firmware/fibre/cpp/include/fibre/protocol.hpp index bfe774db..883ba544 100644 --- a/Firmware/fibre/cpp/include/fibre/protocol.hpp +++ b/Firmware/fibre/cpp/include/fibre/protocol.hpp @@ -1,5 +1,3 @@ -#pragma GCC optimize ("O3") - /* see protocol.md for the protocol specification */ @@ -1100,7 +1098,7 @@ public: extern Endpoint** endpoint_list_; extern size_t n_endpoints_; extern uint16_t json_crc_; -extern uint32_t json_fibre_cache_entropy_; +extern uint32_t json_version_id_; // exposed to hosts to facilitate cache lookup extern JSONDescriptorEndpoint json_file_endpoint_; extern EndpointProvider* application_endpoints_; @@ -1134,9 +1132,11 @@ int fibre_publish(T& application_objects) { // Add entropy for fibre cache json_file_endpoint_.handle(offset, sizeof(offset), &crc16_calculator); - json_fibre_cache_entropy_ = (uint32_t) crc16_calculator.get_crc16(); - json_fibre_cache_entropy_ += json_crc_ << 16; + json_version_id_ = (uint32_t) crc16_calculator.get_crc16(); + json_version_id_ += json_crc_ << 16; return 0; } + + #endif diff --git a/Firmware/fibre/cpp/protocol.cpp b/Firmware/fibre/cpp/protocol.cpp index 857bb6bc..d5af8a0b 100644 --- a/Firmware/fibre/cpp/protocol.cpp +++ b/Firmware/fibre/cpp/protocol.cpp @@ -1,3 +1,4 @@ + /* Includes ------------------------------------------------------------------*/ #include @@ -15,7 +16,7 @@ Endpoint** endpoint_list_ = nullptr; // initialized by calling fibre_publish size_t n_endpoints_ = 0; // initialized by calling fibre_publish uint16_t json_crc_; // initialized by calling fibre_publish -uint32_t json_fibre_cache_entropy_; // initialized by calling fibre_publish +uint32_t json_version_id_; // initialized by calling fibre_publish JSONDescriptorEndpoint json_file_endpoint_ = JSONDescriptorEndpoint(); EndpointProvider* application_endpoints_; @@ -141,10 +142,9 @@ void JSONDescriptorEndpoint::handle(const uint8_t* input, size_t input_length, S uint32_t offset = 0; read_le(&offset, input); - // If the offset is special value 0xFFFFFFFF, send back the JSON crc instead + // If the offset is special value 0xFFFFFFFF, send back the JSON version ID instead if (offset == 0xffffffff) { - //default_readwrite_endpoint_handler(&json_crc_, nullptr, 0, output); - default_readwrite_endpoint_handler(&json_fibre_cache_entropy_, nullptr, 0, output); + default_readwrite_endpoint_handler(&json_version_id_, nullptr, 0, output); } else { NullStreamSink output_with_offset = NullStreamSink(offset, *output); @@ -188,8 +188,8 @@ int BidirectionalPacketBasedChannel::process_packet(const uint8_t* buffer, size_ // Verify packet trailer. The expected trailer value depends on the selected endpoint. // For endpoint 0 this is just the protocol version, for all other endpoints it's a // CRC over the entire JSON descriptor tree (this may change in future versions). - uint32_t expected_trailer = endpoint_id ? json_crc_ : PROTOCOL_VERSION; - uint32_t actual_trailer = buffer[length - 2] | (buffer[length - 1] << 8); + uint16_t expected_trailer = endpoint_id ? json_crc_ : PROTOCOL_VERSION; + uint16_t actual_trailer = buffer[length - 2] | (buffer[length - 1] << 8); if (expected_trailer != actual_trailer) { LOG_FIBRE("trailer mismatch for endpoint %d: expected %04x, got %04x\r\n", endpoint_id, expected_trailer, actual_trailer); return -1; diff --git a/Firmware/fibre/python/fibre/discovery.py b/Firmware/fibre/python/fibre/discovery.py index 347fae85..12836f11 100644 --- a/Firmware/fibre/python/fibre/discovery.py +++ b/Firmware/fibre/python/fibre/discovery.py @@ -54,36 +54,11 @@ def find_all(path, serial_number, channel_termination_token, logger): """ - Load a json file from disk, return None if it does not exist or is invalid json - """ - def load_json_file(name): - try: - file = open(name, "r+") - except: - logger.debug(f"Failed to open json file {name}") - return None - - try: - file_str = file.read() - except: - logger.debug(f"Failed to read json file {name}") - return None - - try: - json_data = json.loads(file_str) - except: - logger.debug(f"Failed to deserialize json file {name}") - return None - - file.close() - - return json_data - - """ Starts scanning for Fibre nodes that match the specified path spec and calls the callback for each Fibre node that is found. This function is non-blocking. """ + def did_discover_channel(channel): """ Inits an object from a given channel and then calls did_discover_object_callback @@ -94,26 +69,32 @@ def find_all(path, serial_number, try: logger.debug("Connecting to device on " + channel._name) - temp_dir = appdirs.user_cache_dir("odrivetool") + cache_dir = appdirs.user_cache_dir("odrivetool") + cache_path = None + + # Fetch the json version tag to check cache (only supported on firmware v0.5 or later) try: - os.mkdir(temp_dir) - except FileExistsError: - pass + json_version_tag = channel.remote_endpoint_operation(0, struct.pack("> 16 - - logger.debug("Device reported JSON entropy: {:08d}".format(json_fibre_cache_entropy)) - cache_path = temp_dir + '/fibre_schema_cache_' + str(json_fibre_cache_entropy) + logger.debug("Device reported JSON version ID: {:08d}".format(json_version_tag)) + cache_path = os.path.join(cache_dir, 'fibre_schema_cache_{:08d}'.format(json_version_tag)) except: logger.debug("Failed to get JSON checksum") - if cache_path == "" or load_json_file(cache_path) is None: + # Check cache + json_data = None + try: + if not cache_path is None: + with open(cache_path, 'rb') as fp: + json_crc16 = fibre.protocol.calc_crc16(fibre.protocol.PROTOCOL_VERSION, fp.read()) + fp.seek(0) + json_data = json.load(fp) + except: + logger.debug(f"Failed load JSON cache file {cache_path}") + + # Fallback to loading JSON from device + if json_data is None: # Downloading json data logger.info("Downloading json data from ODrive... (this might take a while)") json_bytes = channel.remote_endpoint_read_buffer(0) @@ -124,25 +105,19 @@ def find_all(path, serial_number, raise UnicodeDecodeError json_crc16 = fibre.protocol.calc_crc16(fibre.protocol.PROTOCOL_VERSION, json_bytes) - json_fibre_cache_entropy = fibre.protocol.calc_crc16(json_crc16, json_bytes) | (json_crc16 << 16) - cache_path = temp_dir + '/fibre_schema_cache_' + str(json_fibre_cache_entropy) - logger.debug(f"Creating new JSON cache file {cache_path}") - with open(cache_path, 'w+') as json_cache: - json_cache.write(json_string) - logger.debug("Saved JSON to cache file " + cache_path) - json_data = load_json_file(cache_path) - else: - with open(cache_path, "rb") as f: - logger.debug(f"Loaded JSON from cache file {cache_path}") - json_crc16 = fibre.protocol.calc_crc16(fibre.protocol.PROTOCOL_VERSION, f.read()) - f.seek(0) - json_fibre_cache_entropy = fibre.protocol.calc_crc16(json_crc16, f.read()) | (json_crc16 << 16) - json_data = load_json_file(cache_path) + json_data = json.loads(json_string) + + # Save JSON to cache + if not cache_path is None: + logger.debug(f"Creating new JSON cache file {cache_path}") + os.makedirs(cache_dir, exist_ok=True) + with open(cache_path, 'w+') as json_cache: + json_cache.write(json_string) + logger.debug(f"Saved JSON to cache file {cache_path}") channel._interface_definition_crc = json_crc16 logger.debug("JSON: " + str(json_data).replace("{'name'", "\n{'name'")) - logger.debug("Local cache JSON entropy: {:08d}".format(json_fibre_cache_entropy)) json_data = {"name": "fibre_node", "members": json_data} obj = fibre.remote_object.RemoteObject(json_data, None, channel, logger)