Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
connector_firmware.h
00001 /* 00002 * Copyright (c) 2013 Digi International Inc., 00003 * All rights not expressly granted are reserved. 00004 * 00005 * This Source Code Form is subject to the terms of the Mozilla Public 00006 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 00007 * You can obtain one at http://mozilla.org/MPL/2.0/. 00008 * 00009 * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 00010 * ======================================================================= 00011 */ 00012 00013 #define FW_ID_STRING_LENGTH 128 /* bytes */ 00014 00015 /* time to send target list to keep download alive */ 00016 #define FW_TARGET_LIST_MSG_INTERVAL_IN_SECONDS 30 00017 00018 /** 00019 * Firmware Upgrade Facility Opcodes 00020 * @doc These are the valid opcodes for the Firmware Upgrade Facility 00021 */ 00022 typedef enum { 00023 fw_target_list_opcode, 00024 fw_info_request_opcode, 00025 fw_info_response_opcode, 00026 fw_download_request_opcode, 00027 fw_download_response_opcode, 00028 fw_binary_block_opcode, 00029 fw_binary_block_ack_opcode, 00030 fw_download_abort_opcode, 00031 fw_download_complete_opcode, 00032 fw_download_complete_response_opcode, 00033 fw_target_reset_opcode, 00034 fw_download_status_opcode, 00035 fw_error_opcode 00036 } fw_opcodes_t; 00037 00038 typedef union { 00039 enum { 00040 fw_invalid_target, 00041 fw_invalid_opcode, 00042 fw_invalid_msg 00043 } error_status; 00044 00045 enum { 00046 fw_user_abort, 00047 fw_device_error, 00048 fw_invalid_offset, 00049 fw_invalid_data, 00050 fw_hardware_error 00051 } abort_status; 00052 00053 connector_firmware_status_t user_status; 00054 00055 } fw_abort_status_t; 00056 00057 /* Firmware message header format: 00058 * ------------------------ 00059 * | 0 | 1 | 3... | 00060 * ------------------------ 00061 * | opcode | target | data | 00062 * ------------------------ 00063 * 00064 */ 00065 enum fw_message { 00066 field_define(fw_message, opcode, uint8_t), 00067 field_define(fw_message, target, uint8_t), 00068 record_end(fw_message) 00069 }; 00070 #define FW_MESSAGE_HEADER_SIZE record_bytes(fw_message) 00071 #define FW_MESSAGE_RESPONSE_MAX_SIZE 16 00072 00073 enum fw_target_list_hdr { 00074 field_define(fw_target_list, opcode, uint8_t) 00075 }; 00076 00077 /* target + version pairs format: */ 00078 enum fw_target_list{ 00079 field_define(fw_target_list, target, uint8_t), 00080 field_define(fw_target_list, version, uint32_t), 00081 record_end(fw_target_list) 00082 }; 00083 00084 #define FW_VERSION_NUMBER(version) (MAKE32_4(version.major, version.minor, version.revision, version.build)) 00085 00086 static size_t const target_list_header_size = field_named_data(fw_target_list, opcode, size); 00087 static size_t const target_list_size = record_bytes(fw_target_list); 00088 00089 typedef struct { 00090 connector_data_t * connector_ptr; 00091 unsigned long last_fw_keepalive_sent_time; 00092 00093 size_t desc_length; 00094 size_t spec_length; 00095 size_t response_size; 00096 connector_bool_t send_busy; 00097 connector_bool_t update_started; 00098 connector_bool_t fw_keepalive_start; 00099 connector_firmware_info_t target_info; 00100 00101 uint8_t response_buffer[FW_MESSAGE_RESPONSE_MAX_SIZE + PACKET_EDP_FACILITY_SIZE]; 00102 uint8_t target_count; 00103 } connector_firmware_data_t; 00104 00105 #if defined CONNECTOR_RCI_SERVICE 00106 static connector_status_t confirm_fw_version(connector_firmware_data_t * const fw_ptr, uint8_t target_number, connector_firmware_version_t const version) 00107 { 00108 connector_status_t result = connector_working; 00109 uint32_t const version_number = FW_VERSION_NUMBER(version); 00110 00111 if (target_number == 0 && version_number != rci_get_firmware_target_zero_version()) 00112 { 00113 connector_data_t * const connector_ptr = fw_ptr->connector_ptr; 00114 connector_request_id_t request_id; 00115 00116 connector_debug_printf("confirm_fw_version: 0x%X != FIRMWARE_TARGET_ZERO_VERSION (0x%X)\n", version_number, rci_get_firmware_target_zero_version()); 00117 request_id.firmware_request = connector_request_id_firmware_info; 00118 if (notify_error_status(connector_ptr->callback, connector_class_id_firmware, request_id, connector_bad_version) != connector_working) 00119 { 00120 result = connector_abort; 00121 } 00122 } 00123 return result; 00124 } 00125 #endif 00126 00127 static connector_status_t get_fw_config(connector_firmware_data_t * const fw_ptr, 00128 connector_request_id_firmware_t const fw_request_id, 00129 void * const data) 00130 { 00131 00132 connector_data_t * const connector_ptr = fw_ptr->connector_ptr; 00133 connector_status_t result = connector_working; 00134 00135 unsigned long end_time_stamp = 0; 00136 00137 { 00138 connector_request_id_t request_id; 00139 connector_callback_status_t status; 00140 00141 request_id.firmware_request = fw_request_id; 00142 status = connector_callback(connector_ptr->callback, connector_class_id_firmware, request_id, data); 00143 00144 if (get_system_time(connector_ptr, &end_time_stamp) != connector_working) 00145 { 00146 result = connector_abort; 00147 goto done; 00148 } 00149 00150 switch (status) 00151 { 00152 case connector_callback_continue: 00153 break; 00154 case connector_callback_busy: 00155 result = connector_pending; 00156 break; 00157 case connector_callback_abort: 00158 case connector_callback_unrecognized: 00159 case connector_callback_error: 00160 result = connector_abort; 00161 goto done; 00162 } 00163 } 00164 00165 if (result == connector_pending && fw_ptr->last_fw_keepalive_sent_time > 0) 00166 { 00167 /* 00168 * Check whether we need to send target list message 00169 * to keep connection alive. 00170 */ 00171 fw_ptr->fw_keepalive_start = ((end_time_stamp - fw_ptr->last_fw_keepalive_sent_time) >= FW_TARGET_LIST_MSG_INTERVAL_IN_SECONDS) ? connector_true : connector_false; 00172 } 00173 else 00174 { 00175 fw_ptr->fw_keepalive_start = connector_false; 00176 } 00177 00178 done: 00179 return result; 00180 } 00181 00182 static fw_abort_status_t get_abort_status_code(connector_firmware_status_t const status) 00183 { 00184 fw_abort_status_t code; 00185 00186 code.abort_status = fw_user_abort; 00187 00188 /* convert status to abort status code for abort message */ 00189 switch (status) 00190 { 00191 case connector_firmware_status_user_abort: 00192 code.abort_status = fw_user_abort; 00193 break; 00194 case connector_firmware_status_invalid_offset: 00195 code.abort_status = fw_invalid_offset; 00196 break; 00197 case connector_firmware_status_invalid_data: 00198 code.abort_status = fw_invalid_data; 00199 break; 00200 case connector_firmware_status_hardware_error: 00201 code.abort_status = fw_hardware_error; 00202 break; 00203 case connector_firmware_status_device_error: 00204 case connector_firmware_status_download_denied: 00205 case connector_firmware_status_download_invalid_size: 00206 case connector_firmware_status_download_invalid_version: 00207 case connector_firmware_status_download_unauthenticated: 00208 case connector_firmware_status_download_not_allowed: 00209 case connector_firmware_status_download_configured_to_reject: 00210 case connector_firmware_status_encountered_error: 00211 /* not abort status so default to device error */ 00212 code.abort_status = fw_device_error; 00213 break; 00214 case connector_firmware_status_success: 00215 ASSERT(connector_false); 00216 break; 00217 00218 } 00219 return code; 00220 } 00221 00222 /* abort and error message format: 00223 * -------------------------- 00224 * | 0 | 1 | 2 | 00225 * -------------------------- 00226 * | opcode | target | status | 00227 * -------------------------- 00228 * 00229 */ 00230 enum fw_abort { 00231 field_define(fw_abort, opcode, uint8_t), 00232 field_define(fw_abort, target, uint8_t), 00233 field_define(fw_abort, status, uint8_t), 00234 record_end(fw_abort) 00235 }; 00236 00237 #define FW_ABORT_HEADER_SIZE record_bytes(fw_abort) 00238 00239 static connector_status_t send_fw_message(connector_firmware_data_t * const fw_ptr) 00240 { 00241 00242 connector_status_t result; 00243 00244 result = tcp_initiate_send_facility_packet(fw_ptr->connector_ptr, fw_ptr->response_buffer, fw_ptr->response_size, E_MSG_FAC_FW_NUM, NULL, NULL); 00245 fw_ptr->send_busy = (result == connector_pending) ? connector_true : connector_false; 00246 return result; 00247 00248 } 00249 00250 static connector_status_t send_fw_abort(connector_firmware_data_t * const fw_ptr, uint8_t const target, uint8_t const msg_opcode, fw_abort_status_t const abort_status) 00251 { 00252 00253 connector_status_t result; 00254 00255 uint8_t * fw_abort = GET_PACKET_DATA_POINTER(fw_ptr->response_buffer, PACKET_EDP_FACILITY_SIZE); 00256 uint8_t abort_code = (uint8_t)abort_status.error_status; 00257 00258 ASSERT(abort_status.error_status <= UCHAR_MAX); 00259 00260 /* need to adjust abort status code in the fw_status_t */ 00261 if (msg_opcode != fw_error_opcode) 00262 { 00263 fw_abort_status_t status; 00264 status = get_abort_status_code(abort_status.user_status); 00265 00266 ASSERT(status.abort_status <= UCHAR_MAX); 00267 abort_code = (uint8_t)status.abort_status; 00268 00269 } 00270 00271 ASSERT((sizeof fw_ptr->response_buffer - PACKET_EDP_FACILITY_SIZE) > FW_ABORT_HEADER_SIZE); 00272 00273 /* build abort message */ 00274 message_store_u8(fw_abort, opcode, msg_opcode); 00275 message_store_u8(fw_abort, target, target); 00276 message_store_u8(fw_abort, status, abort_code); 00277 00278 fw_ptr->response_size = FW_ABORT_HEADER_SIZE; 00279 result = send_fw_message(fw_ptr); 00280 00281 if (fw_ptr->target_info.target_number == target) 00282 { 00283 fw_ptr->update_started = connector_false; 00284 } 00285 return result; 00286 00287 } 00288 00289 static connector_status_t process_fw_info_request(connector_firmware_data_t * const fw_ptr, uint8_t * const fw_message, uint16_t const length) 00290 { 00291 /* firmware info response message format: 00292 * --------------------------------------------------- 00293 * | 0 | 1 | 2 - 5 | 6 - 9 | 10 ... | 00294 * --------------------------------------------------- 00295 * | opcode | target | version | Available | Firmware | 00296 * | | | | code size | ID string | 00297 * --------------------------------------------------- 00298 * 00299 * Firmware ID string = [descr]0xa[file name spec] 00300 */ 00301 enum fw_info { 00302 field_define(fw_info, opcode, uint8_t), 00303 field_define(fw_info, target, uint8_t), 00304 field_define(fw_info, version, uint32_t), 00305 field_define(fw_info, code_size, uint32_t), 00306 record_end(fw_info) 00307 }; 00308 00309 #define MAX_FW_INFO_REQUEST_LENGTH 2 00310 00311 connector_data_t * const connector_ptr = fw_ptr->connector_ptr; 00312 connector_status_t result = connector_idle; 00313 uint8_t const target = message_load_u8(fw_message, target); 00314 00315 connector_debug_printf("Firmware Facility: process info request\n"); 00316 /* parse firmware info request 00317 * ----------------- 00318 * | 0 | 1 | 00319 * ----------------- 00320 * | opcode | target | 00321 * ----------------- 00322 */ 00323 fw_ptr->last_fw_keepalive_sent_time = 0; 00324 fw_ptr->fw_keepalive_start = connector_false; 00325 00326 if (length != MAX_FW_INFO_REQUEST_LENGTH) 00327 { 00328 fw_abort_status_t fw_status; 00329 connector_debug_printf("process_fw_info_request: invalid message length\n"); 00330 00331 fw_status.error_status = fw_invalid_msg; 00332 result = send_fw_abort(fw_ptr, target, fw_error_opcode, fw_status); 00333 goto done; 00334 00335 } 00336 00337 /* let's get and build target info response */ 00338 { 00339 connector_firmware_info_t * firmware_info = &fw_ptr->target_info; 00340 00341 firmware_info->target_number = target; 00342 00343 result = get_fw_config(fw_ptr, connector_request_id_firmware_info, firmware_info); 00344 if (result != connector_working) 00345 { 00346 goto done; 00347 } 00348 #if defined CONNECTOR_RCI_SERVICE 00349 else 00350 { 00351 result = confirm_fw_version(fw_ptr, firmware_info->target_number, firmware_info->version); 00352 } 00353 #endif 00354 fw_ptr->desc_length = strlen(firmware_info->description); 00355 fw_ptr->spec_length = strlen(firmware_info->filespec); 00356 00357 if ((fw_ptr->desc_length + fw_ptr->spec_length) > (FW_ID_STRING_LENGTH -1)) 00358 { 00359 connector_request_id_t request_id; 00360 00361 request_id.firmware_request = connector_request_id_firmware_info; 00362 connector_debug_printf("process_fw_info_request: description length = %lu + name spec length = %lu\n", 00363 (unsigned long int)fw_ptr->desc_length, (unsigned long int)fw_ptr->spec_length); 00364 notify_error_status(connector_ptr->callback, connector_class_id_firmware, request_id, connector_invalid_data_size); 00365 fw_ptr->desc_length = 0; 00366 fw_ptr->spec_length = 0; 00367 result = connector_abort; 00368 } 00369 } 00370 00371 /* let's build a response. 00372 * build and send firmware info response 00373 */ 00374 { 00375 connector_firmware_info_t * firmware_info = &fw_ptr->target_info; 00376 00377 uint8_t * edp_header; 00378 uint8_t * fw_info; 00379 uint8_t * start_ptr; 00380 size_t avail_length; 00381 00382 edp_header = tcp_get_packet_buffer(connector_ptr, E_MSG_FAC_FW_NUM, &fw_info, &avail_length); 00383 if (edp_header == NULL) 00384 { 00385 result = connector_pending; 00386 goto done; 00387 } 00388 start_ptr = fw_info; 00389 00390 ASSERT(avail_length > (record_bytes(fw_info) + fw_ptr->desc_length + fw_ptr->spec_length + 1)); 00391 00392 message_store_u8(fw_info, opcode, fw_info_response_opcode); 00393 message_store_u8(fw_info, target, target); 00394 message_store_be32(fw_info, version, FW_VERSION_NUMBER(firmware_info->version)); 00395 message_store_be32(fw_info, code_size, INT32_C(0)); 00396 fw_info += record_bytes(fw_info); 00397 00398 connector_debug_printf("firmware description = %d %s %s\n", fw_ptr->desc_length, firmware_info->description, firmware_info->filespec); 00399 if (firmware_info->description != NULL) 00400 { 00401 memcpy(fw_info, firmware_info->description, fw_ptr->desc_length); 00402 fw_info += fw_ptr->desc_length; 00403 } 00404 *fw_info++ = '\n'; 00405 00406 if (firmware_info->filespec != NULL) 00407 { 00408 memcpy(fw_info, firmware_info->filespec, fw_ptr->spec_length); 00409 fw_info += fw_ptr->spec_length; 00410 } 00411 00412 /* reset back to initial values */ 00413 firmware_info->version.major = 0; 00414 firmware_info->version.minor = 0; 00415 firmware_info->version.revision = 0; 00416 firmware_info->version.build = 0; 00417 fw_ptr->desc_length = 0; 00418 fw_ptr->spec_length = 0; 00419 00420 { 00421 size_t const send_packet_length = (size_t)(fw_info-start_ptr); 00422 00423 result = tcp_initiate_send_facility_packet(connector_ptr, edp_header, send_packet_length, E_MSG_FAC_FW_NUM, tcp_release_packet_buffer, NULL); 00424 00425 if (result != connector_working) 00426 { 00427 tcp_release_packet_buffer(connector_ptr, edp_header, connector_working, NULL); 00428 } 00429 } 00430 } 00431 00432 done: 00433 return result; 00434 } 00435 00436 static connector_status_t process_fw_download_request(connector_firmware_data_t * const fw_ptr, uint8_t * fw_download_request, uint16_t const length) 00437 { 00438 #define FW_STRING_ID_ITEMS 2 00439 00440 /* Firmware download request message format: 00441 * ----------------------------------------------------------- 00442 * | 0 | 1 | 2 - 5 | 6 - 9 | 10... | 00443 * ----------------------------------------------------------- 00444 * | opcode | target | version | code size | firmware ID string | 00445 * ------------------------------------------------------------ 00446 * 00447 * Firmware ID string: [label]0x0a[file name spec]0xa[file name] 00448 * 00449 * Call the callback with these values and send download request response. 00450 */ 00451 enum fw_download_request { 00452 field_define(fw_download_request, opcode, uint8_t), 00453 field_define(fw_download_request, target, uint8_t), 00454 field_define(fw_download_request, version, uint32_t), 00455 field_define(fw_download_request, code_size, uint32_t), 00456 record_end(fw_download_request) 00457 }; 00458 00459 00460 /* Firmware download response message format: 00461 * --------------------------------- 00462 * | 0 | 1 | 2 | 00463 * --------------------------------- 00464 * | opcode | target | response type | 00465 * --------------------------------- 00466 * 00467 */ 00468 enum fw_download_response { 00469 field_define(fw_download_response, opcode, uint8_t), 00470 field_define(fw_download_response, target, uint8_t), 00471 field_define(fw_download_response, response_type, uint8_t), 00472 record_end(fw_download_response) 00473 }; 00474 00475 connector_status_t result = connector_working; 00476 connector_firmware_download_start_t download_request; 00477 fw_abort_status_t response_status; 00478 size_t string_id_length; 00479 00480 uint8_t abort_opcode = fw_download_abort_opcode; 00481 00482 download_request.target_number = message_load_u8(fw_download_request, target); 00483 00484 response_status.user_status = connector_firmware_status_device_error; 00485 if (length < record_bytes(fw_download_request)) 00486 { 00487 connector_debug_printf("process_fw_download_request: invalid message length\n"); 00488 abort_opcode = fw_error_opcode; 00489 response_status.error_status = fw_invalid_msg; 00490 goto error; 00491 } 00492 00493 if (fw_ptr->update_started == connector_true) 00494 { 00495 connector_debug_printf("process_fw_download_request: cannot start another firmware update target %d\n", download_request.target_number); 00496 goto error; 00497 } 00498 00499 /* Parse firmware download request. Then, call the callback 00500 * with these values and send download request response. 00501 */ 00502 #if (CONNECTOR_VERSION >= 0x02010000) 00503 download_request.code_size = message_load_be32(fw_download_request, code_size); 00504 #endif 00505 00506 string_id_length = (size_t)(length - record_bytes(fw_download_request)); 00507 00508 { 00509 char * string_id_ptr = (char *)fw_download_request; 00510 unsigned int i; 00511 00512 string_id_ptr += record_bytes(fw_download_request); 00513 00514 /* parse firmware ID String for label and filename spec 00515 * separated by 0x0a. 00516 */ 00517 for (i=0; i < FW_STRING_ID_ITEMS; i++) 00518 { 00519 char * end_ptr; 00520 00521 end_ptr = strchr(string_id_ptr, '\n'); 00522 if (end_ptr != NULL) *end_ptr = '\0'; 00523 { 00524 size_t const label_length = (size_t)(end_ptr - string_id_ptr); 00525 string_id_length -= (UINT32_C(1) + label_length); 00526 } 00527 string_id_ptr++; 00528 } 00529 /* get filename */ 00530 download_request.filename = string_id_ptr; 00531 *(download_request.filename + string_id_length) = '\0'; 00532 } 00533 00534 /* call callback */ 00535 download_request.status = connector_firmware_status_success; 00536 result = get_fw_config(fw_ptr, connector_request_id_firmware_download_start, &download_request); 00537 if (result == connector_working) response_status.user_status = download_request.status; 00538 00539 error: 00540 if (result != connector_pending) 00541 { 00542 uint8_t * fw_download_response = GET_PACKET_DATA_POINTER(fw_ptr->response_buffer, PACKET_EDP_FACILITY_SIZE); 00543 00544 if (response_status.user_status >= connector_firmware_status_user_abort) 00545 { 00546 send_fw_abort(fw_ptr, download_request.target_number, abort_opcode, response_status); 00547 goto done; 00548 } 00549 00550 /* get a buffer for sending a response */ 00551 ASSERT((sizeof fw_ptr->response_buffer - PACKET_EDP_FACILITY_SIZE) > record_bytes(fw_download_response)); 00552 00553 /* send firmware download response */ 00554 message_store_u8(fw_download_response, opcode, fw_download_response_opcode); 00555 message_store_u8(fw_download_response, target, download_request.target_number); 00556 message_store_u8(fw_download_response, response_type, download_request.status); 00557 00558 fw_ptr->response_size = record_bytes(fw_download_response); 00559 00560 send_fw_message(fw_ptr); 00561 if (download_request.status == connector_firmware_status_success) 00562 { 00563 fw_ptr->update_started = connector_true; 00564 fw_ptr->target_info.target_number = download_request.target_number; 00565 } 00566 00567 } 00568 00569 done: 00570 return result; 00571 } 00572 00573 static connector_status_t process_fw_binary_block(connector_firmware_data_t * const fw_ptr, uint8_t * const fw_binary_block, uint16_t const length) 00574 { 00575 /* Firmware binary block message format: 00576 * -------------------------------------------------------- 00577 * | 0 | 1 | 2 | 3 - 6 | 7.. | 00578 * -------------------------------------------------------- 00579 * | opcode | target | Ack required | offset | binary data | 00580 * -------------------------------------------------------- 00581 * 00582 */ 00583 enum fw_binary_block { 00584 field_define(fw_binary_block, opcode, uint8_t), 00585 field_define(fw_binary_block, target, uint8_t), 00586 field_define(fw_binary_block, ack_required, uint8_t), 00587 field_define(fw_binary_block, offset, uint32_t), 00588 record_end(fw_binary_block) 00589 }; 00590 00591 /* Firmware binary block acknowledge message format: 00592 * ----------------------------------- 00593 * | 0 | 1 | 2 - 5 | 6 | 00594 * ----------------------------------- 00595 * | opcode | target | offset | status | 00596 * ----------------------------------- 00597 * 00598 */ 00599 enum fw_binary_ack { 00600 field_define(fw_binary_ack, opcode, uint8_t), 00601 field_define(fw_binary_ack, target, uint8_t), 00602 field_define(fw_binary_ack, offset, uint32_t), 00603 field_define(fw_binary_ack, status, uint8_t), 00604 record_end(fw_binary_ack) 00605 }; 00606 connector_status_t result = connector_idle; 00607 00608 uint8_t ack_required; 00609 connector_firmware_download_data_t download_data; 00610 00611 /* Parse firmware binary block */ 00612 download_data.target_number = message_load_u8(fw_binary_block, target); 00613 00614 if (fw_ptr->update_started == connector_false) 00615 { 00616 /* Ignore this packet since we have not started downloading. 00617 * We may already abort download request. 00618 */ 00619 goto done; 00620 } 00621 00622 if ((fw_ptr->target_info.target_number != download_data.target_number) || (length < record_bytes(fw_binary_block))) 00623 { 00624 fw_abort_status_t fw_status; 00625 00626 connector_debug_printf("process_fw_binary_block: invalid target or message length\n"); 00627 fw_status.error_status = fw_invalid_msg; 00628 result = send_fw_abort(fw_ptr, download_data.target_number, fw_error_opcode, fw_status); 00629 goto done; 00630 } 00631 00632 /* Parse firmware binary block */ 00633 ack_required = message_load_u8(fw_binary_block, ack_required); 00634 download_data.image.offset = message_load_be32(fw_binary_block, offset); 00635 download_data.image.bytes_used = (size_t)(length - record_bytes(fw_binary_block)); 00636 00637 download_data.image.data = (fw_binary_block + record_bytes(fw_binary_block)); 00638 download_data.status = connector_firmware_status_success; 00639 00640 result = get_fw_config(fw_ptr, connector_request_id_firmware_download_data, &download_data); 00641 00642 if (result == connector_working && download_data.status == connector_firmware_status_success) 00643 { 00644 00645 if(ack_required) 00646 { 00647 uint8_t * fw_binary_ack = GET_PACKET_DATA_POINTER(fw_ptr->response_buffer, PACKET_EDP_FACILITY_SIZE); 00648 00649 ASSERT((sizeof fw_ptr->response_buffer - PACKET_EDP_FACILITY_SIZE) > record_bytes(fw_binary_ack)); 00650 /* send firmware binary block acknowledge */ 00651 message_store_u8(fw_binary_ack, opcode, fw_binary_block_ack_opcode); 00652 message_store_u8(fw_binary_ack, target, download_data.target_number); 00653 message_store_be32(fw_binary_ack, offset, download_data.image.offset); 00654 message_store_u8(fw_binary_ack, status, connector_firmware_status_success); 00655 00656 fw_ptr->response_size = record_bytes(fw_binary_ack); 00657 result = send_fw_message(fw_ptr); 00658 } 00659 } 00660 else if (result != connector_pending) 00661 { 00662 fw_abort_status_t fw_status; 00663 fw_status.user_status = download_data.status; 00664 result = send_fw_abort(fw_ptr, download_data.target_number, fw_download_abort_opcode, fw_status); 00665 } 00666 done: 00667 return result; 00668 } 00669 00670 static connector_status_t process_fw_abort(connector_firmware_data_t * const fw_ptr, uint8_t * const fw_abort, uint16_t const length) 00671 { 00672 00673 connector_status_t result = connector_working; 00674 00675 /* parse firmware download abort */ 00676 if (length != FW_ABORT_HEADER_SIZE) 00677 { 00678 connector_debug_printf("process_fw_abort: invalid message length\n"); 00679 } 00680 else if (fw_ptr->update_started) 00681 { 00682 connector_firmware_download_abort_t request_data; 00683 uint8_t abort_status = message_load_u8(fw_abort, status); 00684 00685 request_data.target_number = message_load_u8(fw_abort, target); 00686 switch (abort_status) 00687 { 00688 case fw_user_abort: 00689 request_data.status = connector_firmware_status_user_abort; 00690 break; 00691 case fw_device_error: 00692 request_data.status = connector_firmware_status_device_error; 00693 break; 00694 case fw_invalid_offset: 00695 request_data.status = connector_firmware_status_invalid_offset; 00696 break; 00697 case fw_invalid_data: 00698 request_data.status = connector_firmware_status_invalid_data; 00699 break; 00700 case fw_hardware_error: 00701 request_data.status = connector_firmware_status_hardware_error; 00702 break; 00703 default: 00704 ASSERT(connector_false); 00705 break; 00706 } 00707 00708 /* call callback */ 00709 if (fw_ptr->target_info.target_number == request_data.target_number) 00710 { 00711 result = get_fw_config(fw_ptr, connector_request_id_firmware_download_abort, &request_data); 00712 if (result != connector_pending) 00713 { 00714 fw_ptr->update_started = connector_false; 00715 } 00716 fw_ptr->last_fw_keepalive_sent_time = 0; 00717 } 00718 } 00719 return result; 00720 00721 } 00722 00723 static connector_status_t process_fw_complete(connector_firmware_data_t * const fw_ptr, uint8_t * const fw_complete_request, uint16_t const length) 00724 { 00725 00726 /* Firmware download complete message format: 00727 * ---------------------------------------- 00728 * | 0 | 1 | 2 - 5 | 6 - 9 | 00729 * ---------------------------------------- 00730 * | opcode | target | code size | checksum | 00731 * ---------------------------------------- 00732 * 00733 */ 00734 enum fw_complete_request { 00735 field_define(fw_complete_request, opcode, uint8_t), 00736 field_define(fw_complete_request, target, uint8_t), 00737 field_define(fw_complete_request, code_size, uint32_t), 00738 field_define(fw_complete_request, checksum, uint32_t), 00739 record_end(fw_complete_request) 00740 }; 00741 00742 /* Firmware download complete response message format: 00743 * ------------------------------------------------- 00744 * | 0 | 1 | 2 - 5 | 6 - 9 | 10 | 00745 * -------------------------------------------------- 00746 * | opcode | target | version | calculated | status | 00747 * | | | | checksum | | 00748 * -------------------------------------------------- 00749 */ 00750 enum fw_complete_response { 00751 field_define(fw_complete_response, opcode, uint8_t), 00752 field_define(fw_complete_response, target, uint8_t), 00753 field_define(fw_complete_response, version, uint32_t), 00754 field_define(fw_complete_response, checksum, uint32_t), 00755 field_define(fw_complete_response, status, uint8_t), 00756 record_end(fw_complete_response) 00757 }; 00758 00759 connector_status_t result = connector_working; 00760 connector_firmware_download_complete_t download_complete; 00761 00762 download_complete.target_number = message_load_u8(fw_complete_request, target); 00763 download_complete.status = connector_firmware_download_success; 00764 00765 if ((length != record_bytes(fw_complete_request)) || 00766 (fw_ptr->update_started == connector_false) || 00767 (fw_ptr->target_info.target_number != download_complete.target_number)) 00768 { 00769 fw_abort_status_t fw_status; 00770 00771 connector_debug_printf("process_fw_complete: invalid message length, invalid target or no firmware update started\n"); 00772 fw_status.error_status = fw_invalid_msg; 00773 result = send_fw_abort(fw_ptr, download_complete.target_number, fw_error_opcode, fw_status); 00774 goto done; 00775 } 00776 00777 00778 /* call callback */ 00779 result = get_fw_config(fw_ptr, connector_request_id_firmware_download_complete, &download_complete); 00780 if (result == connector_working) 00781 { 00782 uint8_t * fw_complete_response = GET_PACKET_DATA_POINTER(fw_ptr->response_buffer, PACKET_EDP_FACILITY_SIZE); 00783 00784 ASSERT((sizeof fw_ptr->response_buffer - PACKET_EDP_FACILITY_SIZE) > record_bytes(fw_complete_response)); 00785 00786 /* send firmware download complete response */ 00787 message_store_u8(fw_complete_response, opcode, fw_download_complete_response_opcode); 00788 message_store_u8(fw_complete_response, target, download_complete.target_number); 00789 message_store_be32(fw_complete_response, version, INT32_C(0)); 00790 message_store_be32(fw_complete_response, checksum, INT32_C(0)); 00791 message_store_u8(fw_complete_response, status, download_complete.status); 00792 00793 fw_ptr->last_fw_keepalive_sent_time = 0; 00794 fw_ptr->fw_keepalive_start = connector_false; 00795 00796 fw_ptr->response_size = record_bytes(fw_complete_response); 00797 result = send_fw_message(fw_ptr); 00798 fw_ptr->update_started = connector_false; 00799 } 00800 else if (result != connector_pending) 00801 { 00802 fw_abort_status_t fw_status; 00803 00804 fw_status.user_status = connector_firmware_status_user_abort; 00805 send_fw_abort(fw_ptr, download_complete.target_number, fw_download_abort_opcode, fw_status); 00806 } 00807 00808 00809 done: 00810 return result; 00811 00812 } 00813 00814 static connector_status_t process_target_reset(connector_firmware_data_t * const fw_ptr, uint8_t * const fw_message, uint16_t const length) 00815 { 00816 connector_status_t result; 00817 connector_firmware_reset_t firmware_reset; 00818 00819 UNUSED_PARAMETER(length); 00820 connector_debug_printf("Firmware Facility: process target reset\n"); 00821 00822 firmware_reset.target_number = message_load_u8(fw_message, target); 00823 00824 result = get_fw_config(fw_ptr, connector_request_id_firmware_target_reset, &firmware_reset); 00825 00826 return result; 00827 } 00828 00829 static connector_status_t send_discovery_packet_callback(connector_data_t * const connector_ptr, uint8_t const * const packet, 00830 connector_status_t const send_status, void * const user_data) 00831 { 00832 connector_status_t result; 00833 connector_firmware_data_t * const fw_ptr = user_data; 00834 /* update fw download keepalive timing */ 00835 result = get_system_time(connector_ptr, &fw_ptr->last_fw_keepalive_sent_time); 00836 00837 tcp_release_packet_buffer(connector_ptr, packet, send_status, user_data); 00838 00839 return result; 00840 } 00841 00842 static connector_status_t fw_discovery(connector_data_t * const connector_ptr, void * const facility_data, 00843 uint8_t * const packet, unsigned int * receive_timeout) 00844 { 00845 /* Firmware target list message format: 00846 * 00847 * -------------------------------------------------------- 00848 * | 0 | 1 | 2 - 5 | 6 ... | 00849 * ------------------------------------------------------- 00850 * | opcode | target | version | Additional target-version | 00851 * | | | | pairs | 00852 * ------------------------------------------------------- 00853 * 00854 */ 00855 00856 connector_status_t result = connector_idle; 00857 connector_firmware_data_t * const fw_ptr = facility_data; 00858 00859 UNUSED_PARAMETER(packet); 00860 UNUSED_PARAMETER(receive_timeout); 00861 00862 /* Construct a target list message. 00863 * Get target count and then get version for each target to build target list message 00864 * 00865 */ 00866 00867 if (fw_ptr->target_count > 0) 00868 { 00869 uint8_t * edp_header; 00870 uint8_t * fw_target_list; 00871 size_t avail_length; 00872 size_t discovery_length = 0; 00873 uint8_t target_number; 00874 00875 /* get packet pointer for constructing target list info */ 00876 edp_header = tcp_get_packet_buffer(connector_ptr, E_MSG_FAC_FW_NUM, &fw_target_list, &avail_length); 00877 if (edp_header == NULL) 00878 { 00879 result = connector_pending; 00880 goto done; 00881 } 00882 00883 message_store_u8(fw_target_list, opcode, fw_target_list_opcode); 00884 00885 discovery_length = target_list_header_size; 00886 fw_target_list += discovery_length; 00887 00888 for (target_number=0; target_number < fw_ptr->target_count; target_number++) 00889 { 00890 connector_firmware_info_t firmware_info; 00891 00892 /* get the current firmware version for this target */ 00893 firmware_info.target_number = target_number; 00894 memset(&firmware_info.version, 0x00, sizeof firmware_info.version); 00895 /* call callback */ 00896 result = get_fw_config(fw_ptr, connector_request_id_firmware_info, &firmware_info); 00897 if (result == connector_working) 00898 { 00899 00900 #if defined CONNECTOR_RCI_SERVICE 00901 /* coverity[uninit_use] */ 00902 result = confirm_fw_version(fw_ptr, firmware_info.target_number, firmware_info.version); 00903 if (result != connector_working) goto error; 00904 #endif 00905 message_store_u8(fw_target_list, target, firmware_info.target_number); 00906 message_store_be32(fw_target_list, version, FW_VERSION_NUMBER(firmware_info.version)); 00907 00908 /* set up for next target pair info*/ 00909 fw_target_list += target_list_size; 00910 discovery_length += target_list_size; 00911 } 00912 else 00913 { 00914 goto error; 00915 } 00916 } 00917 00918 result = tcp_initiate_send_facility_packet(connector_ptr, edp_header, discovery_length, 00919 E_MSG_FAC_FW_NUM, send_discovery_packet_callback, fw_ptr); 00920 error: 00921 if (result != connector_working) 00922 { 00923 tcp_release_packet_buffer(connector_ptr, edp_header, connector_working, NULL); 00924 } 00925 } 00926 00927 done: 00928 return result; 00929 } 00930 00931 static connector_status_t fw_process(connector_data_t * const connector_ptr, void * const facility_data, 00932 uint8_t * const edp_header, unsigned int * const receive_timeout) 00933 { 00934 connector_status_t result = connector_idle; 00935 connector_firmware_data_t * const fw_ptr = facility_data; 00936 uint8_t opcode; 00937 uint8_t target; 00938 uint8_t * fw_message; 00939 uint16_t length; 00940 00941 if (edp_header == NULL) 00942 { 00943 if (fw_ptr->update_started) 00944 { 00945 result = connector_pending; 00946 } 00947 goto done; 00948 } 00949 00950 if (fw_ptr->fw_keepalive_start) 00951 { 00952 result = fw_discovery(connector_ptr, facility_data, edp_header, receive_timeout); 00953 if (result == connector_working) 00954 { 00955 if (get_system_time(connector_ptr, &fw_ptr->last_fw_keepalive_sent_time) != connector_working) 00956 { 00957 result = connector_abort; 00958 goto done; 00959 } 00960 fw_ptr->fw_keepalive_start = connector_false; 00961 result = connector_pending; 00962 } 00963 goto done; 00964 } 00965 00966 if (fw_ptr->send_busy == connector_true) 00967 { 00968 /* callback is already called for this message. 00969 * We're here because we were unable to send a response 00970 * message which already message is constructed in 00971 * fw_ptr->response_buffer. 00972 */ 00973 result = send_fw_message(fw_ptr); 00974 goto done; 00975 } 00976 00977 length = message_load_be16(edp_header, length); 00978 if (length < FW_MESSAGE_HEADER_SIZE) 00979 { 00980 connector_debug_printf("fw_process: invalid packet size %d\n", length); 00981 goto done; 00982 } 00983 00984 fw_message = GET_PACKET_DATA_POINTER(edp_header, PACKET_EDP_FACILITY_SIZE); 00985 opcode = message_load_u8(fw_message, opcode); 00986 target = message_load_u8(fw_message, target); 00987 00988 if (target >= fw_ptr->target_count) 00989 { 00990 fw_abort_status_t fw_status; 00991 00992 connector_debug_printf("fw_process: invalid target\n"); 00993 00994 fw_status.error_status = fw_invalid_target; 00995 result = send_fw_abort(fw_ptr, target, fw_error_opcode, fw_status); 00996 goto done; 00997 } 00998 00999 switch(opcode) 01000 { 01001 case fw_info_request_opcode: 01002 result = process_fw_info_request(fw_ptr, fw_message, length); 01003 break; 01004 case fw_download_request_opcode: 01005 result = process_fw_download_request(fw_ptr, fw_message, length); 01006 break; 01007 case fw_binary_block_opcode: 01008 result = process_fw_binary_block(fw_ptr, fw_message, length); 01009 break; 01010 case fw_download_abort_opcode: 01011 result = process_fw_abort(fw_ptr, fw_message, length); 01012 fw_ptr->last_fw_keepalive_sent_time = 0; 01013 fw_ptr->fw_keepalive_start = connector_false; 01014 break; 01015 case fw_download_complete_opcode: 01016 if (fw_ptr->last_fw_keepalive_sent_time == 0) 01017 { 01018 /* start firmware keepalive which allow firmware download complete 01019 * callback to start flash (which requires device to 01020 * send target list message). 01021 * 01022 * Note. We only start firmware keepalive when we receive this complete 01023 * code. Can we start when we receive block opcode? 01024 */ 01025 fw_ptr->last_fw_keepalive_sent_time = connector_ptr->edp_data.keepalive.last_tx_received_time; 01026 } 01027 result = process_fw_complete(fw_ptr, fw_message, length); 01028 break; 01029 case fw_target_reset_opcode: 01030 result = process_target_reset(fw_ptr, fw_message, length); 01031 fw_ptr->last_fw_keepalive_sent_time = 0; 01032 fw_ptr->fw_keepalive_start = connector_false; 01033 break; 01034 default: 01035 { 01036 fw_abort_status_t fw_status; 01037 fw_status.error_status = fw_invalid_opcode; 01038 result = send_fw_abort(fw_ptr, target, fw_error_opcode, fw_status); 01039 break; 01040 } 01041 } 01042 01043 done: 01044 return result; 01045 } 01046 01047 static connector_status_t connector_facility_firmware_delete(connector_data_t * const connector_ptr) 01048 { 01049 return del_facility_data(connector_ptr, E_MSG_FAC_FW_NUM); 01050 } 01051 01052 static connector_status_t connector_facility_firmware_init(connector_data_t * const connector_ptr, unsigned int const facility_index) 01053 { 01054 connector_status_t result = connector_working; 01055 connector_firmware_data_t * fw_ptr; 01056 01057 /* Add firmware access facility to Connector 01058 * 01059 * Make sure firmware access facility is not already created. If firmware 01060 * access facility is already created, we probably reconnect to Device Cloud 01061 * so just need to reset to initial state. 01062 * 01063 */ 01064 fw_ptr = get_facility_data(connector_ptr, E_MSG_FAC_FW_NUM); 01065 if (fw_ptr == NULL) 01066 { 01067 void * ptr; 01068 result = add_facility_data(connector_ptr, facility_index, E_MSG_FAC_FW_NUM, &ptr, sizeof *fw_ptr); 01069 01070 if (result != connector_working || ptr == NULL) 01071 { 01072 goto done; 01073 } 01074 fw_ptr = ptr; 01075 } 01076 fw_ptr->target_count = 0; 01077 fw_ptr->target_info.target_number = 0; 01078 fw_ptr->desc_length = 0; 01079 fw_ptr->spec_length = 0; 01080 fw_ptr->last_fw_keepalive_sent_time = 0; 01081 fw_ptr->fw_keepalive_start = connector_false; 01082 fw_ptr->send_busy = connector_false; 01083 fw_ptr->update_started = connector_false; 01084 fw_ptr->connector_ptr = connector_ptr; 01085 01086 { 01087 connector_firmware_count_t firmware_data; 01088 01089 result = get_fw_config(fw_ptr, connector_request_id_firmware_target_count, &firmware_data); 01090 if (result == connector_working) 01091 { 01092 /* coverity[uninit_use] */ 01093 fw_ptr->target_count = firmware_data.count; 01094 if (fw_ptr->target_count > 0) 01095 { 01096 size_t const buffer_size = sizeof connector_ptr->edp_data.send_packet.packet_buffer.buffer; 01097 size_t const overhead = (PACKET_EDP_FACILITY_SIZE + target_list_header_size); 01098 size_t const max_targets = (buffer_size - overhead) / target_list_size; 01099 01100 /* get max count of targets that fit into the response buffer */ 01101 if (fw_ptr->target_count > max_targets) 01102 { 01103 connector_request_id_t request_id; 01104 01105 request_id.firmware_request = connector_request_id_firmware_target_count; 01106 notify_error_status(connector_ptr->callback, connector_class_id_firmware, request_id, connector_invalid_data_range); 01107 result = connector_abort; 01108 goto done; 01109 } 01110 } 01111 else 01112 { 01113 connector_debug_printf("fw_discovery: No target supported\n"); 01114 } 01115 } 01116 } 01117 01118 done: 01119 return result; 01120 } 01121 01122
Generated on Tue Jul 12 2022 19:18:38 by
1.7.2