pebble/src/fw/mfg/mfg_command.c
2025-01-27 11:38:16 -08:00

194 lines
5.7 KiB
C

/*
* Copyright 2024 Google LLC
*
* 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 "mfg_command.h"
#include "applib/app_launch_reason.h"
#include "applib/app_watch_info.h"
#include "console/prompt.h"
#include "kernel/util/standby.h"
#include "mfg/mfg_info.h"
#include "process_management/app_install_manager.h"
#include "process_management/app_manager.h"
void command_enter_standby(void) {
enter_standby(RebootReasonCode_MfgShutdown);
}
void command_color_read(void) {
char buffer[10];
prompt_send_response_fmt(buffer, sizeof(buffer), "%d", mfg_info_get_watch_color());
}
void command_color_write(const char* color_num) {
char *end;
int color = strtol(color_num, &end, 10);
if (*end) {
prompt_send_response("Invalid color");
return;
}
mfg_info_set_watch_color(color);
const WatchInfoColor written_color = mfg_info_get_watch_color();
if (written_color == color) {
prompt_send_response("OK");
} else {
prompt_send_response("ERROR");
}
}
void command_disp_offset_read(void) {
char buffer[16];
prompt_send_response_fmt(buffer, sizeof(buffer), "X: %"PRId16" Y: %"PRId16,
mfg_info_get_disp_offsets().x,
mfg_info_get_disp_offsets().y);
}
void command_disp_offset_write(const char* offset_x_str, const char* offset_y_str) {
char *nonnumeric_x, *nonnumeric_y;
int8_t offset_x = strtol(offset_x_str, &nonnumeric_x, 10);
if (*nonnumeric_x) {
prompt_send_response("Invalid x offset");
}
int8_t offset_y = strtol(offset_y_str, &nonnumeric_y, 10);
if (*nonnumeric_y) {
prompt_send_response("Invalid y offset");
}
if (!*nonnumeric_x && !*nonnumeric_y) {
mfg_info_set_disp_offsets((GPoint) {offset_x, offset_y});
}
}
void command_rtcfreq_read(void) {
char buffer[10];
prompt_send_response_fmt(buffer, sizeof(buffer), "%"PRIu32, mfg_info_get_rtc_freq());
}
void command_rtcfreq_write(const char* rtc_freq_string) {
char *end;
uint32_t rtc_freq = strtol(rtc_freq_string, &end, 10);
if (*end) {
prompt_send_response("Invalid rtcfreq");
return;
}
mfg_info_set_rtc_freq(rtc_freq);
}
void command_model_read(void) {
char model_buffer[MFG_INFO_MODEL_STRING_LENGTH];
mfg_info_get_model(model_buffer);
// Just send it straight out, as it's already null-terminated
prompt_send_response(model_buffer);
}
void command_model_write(const char* model) {
// mfg_info_set_model will truncate if the string is too long, so no need to check
mfg_info_set_model(model);
char written_model[MFG_INFO_MODEL_STRING_LENGTH];
mfg_info_get_model(written_model);
if (!strncmp(model, written_model, MFG_INFO_MODEL_STRING_LENGTH)) {
prompt_send_response("OK");
} else {
prompt_send_response("ERROR");
}
}
#if BOOTLOADER_TEST_STAGE1
#include "bootloader_test_bin.auto.h"
#include "drivers/flash.h"
#include "flash_region/flash_region.h"
#include "system/firmware_storage.h"
#include "system/bootbits.h"
#include "system/logging.h"
#include "system/reset.h"
#include "util/crc32.h"
#include "util/legacy_checksum.h"
static void prv_bootloader_test_copy(uint32_t flash_addr, uint32_t flash_end) {
const uint8_t *bin;
size_t size;
bin = s_bootloader_test_stage2;
size = sizeof(s_bootloader_test_stage2);
flash_region_erase_optimal_range(flash_addr,
flash_addr,
flash_addr+size+sizeof(FirmwareDescription),
flash_end);
FirmwareDescription fw_desc = {
.description_length = sizeof(FirmwareDescription),
.firmware_length = size,
.checksum = 0,
};
#if CAPABILITY_HAS_DEFECTIVE_FW_CRC
fw_desc.checksum = legacy_defective_checksum_memory(bin, size);
#else
fw_desc.checksum = crc32(CRC32_INIT, bin, size);
#endif
flash_write_bytes((uint8_t *)&fw_desc, flash_addr, sizeof(FirmwareDescription));
flash_write_bytes(bin, flash_addr+sizeof(FirmwareDescription), size);
}
#define BLTEST_LOG(x...) pbl_log(LOG_LEVEL_ALWAYS, __FILE__, __LINE__, x)
void command_bootloader_test(const char *dest_type) {
prompt_command_finish();
BLTEST_LOG("BOOTLOADER TEST STAGE 1");
boot_bit_set(BOOT_BIT_FW_STABLE);
BLTEST_LOG("STAGE 1 -- Setting test boot bits");
boot_bit_clear(BOOT_BIT_BOOTLOADER_TEST_A | BOOT_BIT_BOOTLOADER_TEST_B);
boot_bit_set(BOOT_BIT_BOOTLOADER_TEST_A);
bool as_fw = true;
if (strcmp(dest_type, "prf") == 0) {
as_fw = false;
}
if (as_fw) {
BLTEST_LOG("STAGE 1 -- Copying STAGE 2 to scratch");
prv_bootloader_test_copy(FLASH_REGION_FIRMWARE_SCRATCH_BEGIN,
FLASH_REGION_FIRMWARE_SCRATCH_END);
BLTEST_LOG("STAGE 1 -- Marking new FW boot bit");
boot_bit_set(BOOT_BIT_NEW_FW_AVAILABLE);
} else {
BLTEST_LOG("STAGE 1 -- Copying STAGE 2 to PRF");
flash_prf_set_protection(false);
prv_bootloader_test_copy(FLASH_REGION_SAFE_FIRMWARE_BEGIN, FLASH_REGION_SAFE_FIRMWARE_END);
BLTEST_LOG("STAGE 1 -- Marking PRF boot bit");
boot_bit_set(BOOT_BIT_FORCE_PRF);
}
BLTEST_LOG("STAGE 1 -- Rebooting");
RebootReason reason = { RebootReasonCode_PrfReset, 0 };
reboot_reason_set(&reason);
system_hard_reset();
}
#else
void command_bootloader_test(void) {
prompt_send_response("Not configured for bootloader test");
}
#endif