void system_pending_shutdown() { uint8_t was_set = false; system_get_flag(SYSTEM_FLAG_RESET_PENDING, &was_set, nullptr); if (!was_set) { system_set_flag(SYSTEM_FLAG_RESET_PENDING, 1, nullptr); system_notify_event(reset_pending); } }
int Spark_Prepare_For_Firmware_Update(FileTransfer::Descriptor& file, uint32_t flags, void* reserved) { if (file.store==FileTransfer::Store::FIRMWARE) { // address is relative to the OTA region. Normally will be 0. file.file_address = HAL_OTA_FlashAddress() + file.chunk_address; // chunk_size 0 indicates defaults. if (file.chunk_size==0) { file.chunk_size = HAL_OTA_ChunkSize(); file.file_length = HAL_OTA_FlashLength(); } } int result = 0; if (flags & 1) { // only check address } else { uint32_t start = HAL_Timer_Milliseconds(); system_set_flag(SYSTEM_FLAG_OTA_UPDATE_PENDING, 1, nullptr); volatile bool flag = false; system_notify_event(firmware_update_pending, 0, nullptr, set_flag, (void*)&flag); System.waitCondition([&flag]{return flag;}, timeRemaining(start, 30000)); system_set_flag(SYSTEM_FLAG_OTA_UPDATE_PENDING, 0, nullptr); if (System.updatesEnabled()) // application event is handled asynchronously { RGB.control(true); RGB.color(RGB_COLOR_MAGENTA); SPARK_FLASH_UPDATE = 1; TimingFlashUpdateTimeout = 0; system_notify_event(firmware_update, firmware_update_begin, &file); HAL_FLASH_Begin(file.file_address, file.file_length, NULL); } else { result = 1; // updates disabled } } return result; }
template<typename Config> void SystemSetupConsole<Config>::handle(char c) { if ('i' == c) { // see if we have any additional properties. This is true // for Cellular and Mesh devices. hal_system_info_t info = {}; info.size = sizeof(info); HAL_OTA_Add_System_Info(&info, true, nullptr); LOG(TRACE, "device info key/value count: %d", info.key_value_count); if (info.key_value_count) { print("Device ID: "); String id = spark_deviceID(); print(id.c_str()); print("\r\n"); for (int i=0; i<info.key_value_count; i++) { char key[20]; if (!filter_key(info.key_values[i].key, key, sizeof(key))) { print(key); print(": "); print(info.key_values[i].value); print("\r\n"); } } } else { #if PLATFORM_ID<3 print("Your core id is "); #else print("Your device id is "); #endif String id = spark_deviceID(); print(id.c_str()); print("\r\n"); } HAL_OTA_Add_System_Info(&info, false, nullptr); } else if ('m' == c) { print("Your device MAC address is\r\n"); IPConfig config = {}; #if !HAL_PLATFORM_WIFI auto conf = static_cast<const IPConfig*>(network_config(0, 0, 0)); #else auto conf = static_cast<const IPConfig*>(network_config(NETWORK_INTERFACE_WIFI_STA, 0, 0)); #endif if (conf && conf->size) { memcpy(&config, conf, std::min(sizeof(config), (size_t)conf->size)); } const uint8_t* addr = config.nw.uaMacAddr; print(bytes2hex(addr++, 1).c_str()); for (int i = 1; i < 6; i++) { print(":"); print(bytes2hex(addr++, 1).c_str()); } print("\r\n"); } else if ('f' == c) { serial.println("Waiting for the binary file to be sent ... (press 'a' to abort)"); system_firmwareUpdate(&serial); } else if ('x' == c) { exit(); } else if ('s' == c) { auto prefix = "{"; auto suffix = "}\r\n"; WrappedStreamAppender appender(serial, (const uint8_t*)prefix, strlen(prefix), (const uint8_t*)suffix, strlen(suffix)); system_module_info(append_instance, &appender); } else if ('v' == c) { StreamAppender appender(serial); append_system_version_info(&appender); print("\r\n"); } else if ('L' == c) { system_set_flag(SYSTEM_FLAG_STARTUP_LISTEN_MODE, 1, nullptr); System.enterSafeMode(); } else if ('c' == c) { bool claimed = HAL_IsDeviceClaimed(nullptr); print("Device claimed: "); print(claimed ? "yes" : "no"); print("\r\n"); } else if ('C' == c) { char code[64]; print("Enter 63-digit claim code: "); read_line(code, 63); if (strlen(code)==63) { HAL_Set_Claim_Code(code); print("Claim code set to: "); print(code); } else { print("Sorry, claim code is not 63 characters long. Claim code unchanged."); } print("\r\n"); } else if ('d' == c) { system_format_diag_data(nullptr, 0, 0, StreamAppender::append, &serial, nullptr); print("\r\n"); } }
uint8_t SystemControlInterface::handleVendorRequest(HAL_USB_SetupRequest* req) { /* * This callback should process vendor-specific SETUP requests from the host. * NOTE: This callback is called from an ISR. * * Each request contains the following fields: * - bmRequestType - request type bit mask. Since only vendor-specific device requests are forwarded * to this callback, the only bit that should be of intereset is * "Data Phase Transfer Direction", easily accessed as req->bmRequestTypeDirection: * 0 - Host to Device * 1 - Device to Host * - bRequest - 1 byte, request identifier. The only reserved request that will not be forwarded to this callback * is 0xee, which is used for Microsoft-specific vendor requests. * - wIndex - 2 byte index, any value between 0x0000 and 0xffff. * - wValue - 2 byte value, any value between 0x0000 and 0xffff. * - wLength - each request might have an optional data stage of up to 0xffff (65535) bytes. * Host -> Device requests contain data sent by the host to the device. * Device -> Host requests request the device to send up to wLength bytes of data. * * This callback should return 0 if the request has been correctly handled or 1 otherwise. * * When handling Device->Host requests with data stage, this callback should fill req->data buffer with * up to wLength bytes of data if req->data != NULL (which should be the case when wLength <= 64) * or set req->data to point to some buffer which contains up to wLength bytes of data. * wLength may be safely modified to notify that there is less data in the buffer than requested by the host. * * [1] Host -> Device requests with data stage containing up to 64 bytes can be handled by * an internal buffer in HAL. For requests larger than 64 bytes, the vendor request callback * needs to provide a buffer of an appropriate size: * * req->data = buffer; // sizeof(buffer) >= req->wLength * return 0; * * The callback will be called again once the data stage completes * It will contain the same bmRequest, bRequest, wIndex, wValue and wLength fields. * req->data should contain wLength bytes received from the host. */ /* * We are handling only bRequest = 0x50 ('P') requests. * The request type itself (enum USBRequestType) should be in wIndex field. */ if (req->bRequest != 0x50) return 1; if (req->bmRequestTypeDirection == 0) { // Host -> Device switch (req->wIndex) { case USB_REQUEST_RESET: { // FIXME: We probably shouldn't reset from an ISR. // The host will probably get an error that control request has timed out since we // didn't respond to it. System.reset(req->wValue); break; } case USB_REQUEST_DFU_MODE: { // FIXME: We probably shouldn't enter DFU mode from an ISR. // The host will probably get an error that control request has timed out since we // didn't respond to it. System.dfu(false); break; } case USB_REQUEST_LISTENING_MODE: { // FIXME: We probably shouldn't enter listening mode from an ISR. // The host will probably get an error that control request has timed out since we // didn't respond to it. system_set_flag(SYSTEM_FLAG_STARTUP_SAFE_LISTEN_MODE, 1, nullptr); System.enterSafeMode(); break; } case USB_REQUEST_LOG_CONFIG: { return enqueueRequest(req, DATA_FORMAT_JSON); } case USB_REQUEST_CUSTOM: { return enqueueRequest(req); } default: { // Unknown request return 1; } } } else { // Device -> Host switch (req->wIndex) { case USB_REQUEST_DEVICE_ID: { if (req->wLength == 0 || req->data == NULL) { // No data stage or requested > 64 bytes return 1; } if (req->wValue == 0x0001) { // Return as buffer if (req->wLength < 12) return 1; HAL_device_ID(req->data, req->wLength); req->wLength = 12; } else { // Return as string String id = System.deviceID(); if (req->wLength < (id.length() + 1)) return 1; strncpy((char*)req->data, id.c_str(), req->wLength); req->wLength = id.length() + 1; } break; } case USB_REQUEST_SYSTEM_VERSION: { if (req->wLength == 0 || req->data == NULL) { // No data stage or requested > 64 bytes return 1; } strncpy((char*)req->data, __XSTRING(SYSTEM_VERSION_STRING), req->wLength); req->wLength = sizeof(__XSTRING(SYSTEM_VERSION_STRING)) + 1; break; } case USB_REQUEST_LOG_CONFIG: case USB_REQUEST_CUSTOM: { return fetchRequestResult(req); } default: { // Unknown request return 1; } } } return 0; }