Beispiel #1
0
/// \brief      Handler for the `update` command
static inline bool exec_update(const char * const command)
{
    // Make sure the command is well-formed
    if (command[8] != ' ') {
        return false;
    }

    // Parse size of incoming update packet
    update_bytes_pending = atoi(command + 9);
    if (update_bytes_pending == 0) {
        return false;
    }

    // Calculate number of pages
    num_pages = update_bytes_pending / SPM_PAGESIZE;
    if (update_bytes_pending % SPM_PAGESIZE) {
        ++num_pages;
    }

    // Abort if the program is too big to fit into memory
    if (num_pages > MAX_PAGE_NUM) {
        usb_puts(PSTR("Program is too big! Aborting."));
        return true;
    }

    // Warn if the program is approaching the maximum size
    uint8_t pages_left = MAX_PAGE_NUM - num_pages;
    if (pages_left < 20) {
        usb_printf(PSTR("Warning: Only %u pages of program space left!" USB_NEWLINE), pages_left);
    }

    // Erase temporary application memory
    usb_puts(PSTR("Erasing temporary application flash section..."));
    wdt_disable();
    uint8_t error_code = xboot_app_temp_erase();
    if (error_code != XB_SUCCESS) {
        usb_printf(PSTR("Error erasing temporary application section: %d" USB_NEWLINE), error_code);
        return true;
    }
    wdt_reenable();

    // Switch to update mode
    usb_printf(PSTR("Ready to receive %u bytes (%u pages)..." USB_NEWLINE),
               update_bytes_pending,
               num_pages);
    echo_on = false;
    update_in_progress = true;
    page_buffer_index = 0;
    temp_app_addr = 0;
    return true;
}
Beispiel #2
0
/// \brief      Handles ANSI escape sequences
/// \return     `true` as long as we are in the middle of an escape sequence
static bool handle_escape_sequence(const char data)
{
    static uint8_t escape_byte_index = 0;
    if (data == ESCAPE_CHAR_CODE) {
        escape_byte_index = 1;
        return true;
    }
    if (escape_byte_index == 1) {
        if (data == '[') {
            escape_byte_index = 2;
        }
        else {
            usb_puts(PSTR("Unrecognized escape sequence!"));
            escape_byte_index = 0;
        }
        return true;
    }
    if (escape_byte_index == 2) {
        if (data == 'A') {
            print_command_from_history(-1);
        }
        if (data == 'B') {
            print_command_from_history(1);
        }
        escape_byte_index = 0;
        return true;
    }
    return false;
}
Beispiel #3
0
/// \brief      Executes an interactive command
/// \details    Tries to match the beginning of the supplied string to the registered commands.
///             If a matching command string is found, its handler is invoked.
///             In case no suitable command could be matched, or the executed handler returns a
///             non-zero value, an error message is sent.
/// \param      command
///                 the full command line as a C-string
static inline void execute_command(const char * const command)
{
    bool success = true;

    if (strcmp(command, "clear") == 0) {
        for (int i=0; i<80; ++i) {
            usb_puts(PSTR(""));
        }
    }

    else if (strncmp(command, "fwupdate", 8) == 0) {
        success = exec_update(command);
    }

    else if (strcmp(command, "help") == 0) {
        success = exec_help();
    }

    else if (strcmp(command, "reset") == 0) {
        usb_puts(PSTR("Resetting device..."));
        reset = true;
    }

    else {
        // Iterate all user-defined commands and try to find a matching one
        for (uint8_t i=0; i<user_commands_size; ++i) {
            const struct serial_command* user_command = user_commands + i;
            if (strncmp_P(command, user_command->cmd_string, strlen_P(user_command->cmd_string)) == 0) {
                success = user_command->handler(command);
                goto cleanup;
            }
        }

        // No known command matches :-(
        usb_printf(PSTR("Unknown command: [%s]" USB_NEWLINE), command);
        usb_puts(PSTR("Type `help` for help." USB_NEWLINE));
    }

cleanup:
    if (!success) {
        usb_printf(PSTR("Error executing command: [%s]" USB_NEWLINE), command);
    }

    // Clear command buffer and reset write pointer
    memset(cmd_buffer, '\0', sizeof(cmd_buffer));
    cmd_buffer_index = 0;
}
Beispiel #4
0
int usb_putc(int c)
{
	char string[2];

	string[0] = c;
	string[1] = '\0';
	return usb_puts(string);
}
Beispiel #5
0
/* ===================================================================*/
void save_params() {
	char str[100];
	FlashMem_TAddress FlashAdr = FLASH_BASE_ADR;

	if (FlashMem_SetBlockFlash((FlashMem_TDataAddress) &configParameter, FlashAdr, sizeof(configParameter)) != ERR_OK) {
		strcpy(str, "\nError: cannot save configuration parameters into FLASH\n");
		usb_puts(str);		
	}
}
Beispiel #6
0
/* ===================================================================*/
void save_logdata(const int16 record_nr, logParameter_s *param) {
	char str[100];
	FlashMem_TAddress FlashAdr = FLASH_BASE_ADR + sizeof(configParameterP) + record_nr * sizeof(*param);
	
		FlashReady = FALSE;
		if (FlashMem_SetBlockFlash((FlashMem_TDataAddress) param, FlashAdr, sizeof(*param)) != ERR_OK) {
			strcpy(str, "\nError: cannot save log data into FLASH\n");
			usb_puts(str);
			FlashReady = TRUE;			
		}
	
}
Beispiel #7
0
/// \brief      Processes a command character
/// \details    If the supplied character is a carriage return, the command line read so far is
///             executed, otherwise the character is simply appended to a (circular!) buffer.
///             If #echo_on is set, the character is also immediately sent back to the sender,
///             whereby carriage return characters are replaced by #USB_NEWLINE.
static inline void process_command_char(void)
{
    // Fetch a character from the USB data buffer
    char data = usb_getc();

    // Handle escape sequence if any and abort
    if (handle_escape_sequence(data)) {
        return;
    }

    // Echo back the received character if desired and possible
    if (echo_on) {
        if (data == '\r') {
            usb_puts(PSTR(""));
        }
        else if (0 <= data && data < 128) {
            usb_putc(data);
        }
    }

    // Parse and execute commands if the enter key was hit
    if (data == '\r') {
        // Ignore empty command
        if (strcmp(cmd_buffer, "") == 0) {
            return;
        }
        strncpy(cmd_history[cmd_history_index], cmd_buffer, CMD_BUFFER_SIZE);
        ++cmd_history_index;
        cmd_history_index %= CMD_HISTORY_SIZE;
        execute_command(cmd_buffer);
        return;
    }

    // Clear last character and rewind buffer index if backspace was received
    if (data == '\b') {
        usb_printf(PSTR(" \b"));
        if (cmd_buffer_index > 0) {
            --cmd_buffer_index;
        }
        cmd_buffer[cmd_buffer_index] = '\0';
        return;
    }

    // Add char to command buffer; cycle on overflow
    cmd_buffer[cmd_buffer_index] = data;
    ++cmd_buffer_index;
    cmd_buffer_index %= CMD_BUFFER_SIZE;
}
Beispiel #8
0
/* ===================================================================*/
void erase_flash() {
	byte sector;
	int error;
	FlashMem_TAddress flash_adr;
	char str[100], tmp_str[20];

	for (sector = 0; sector < 32; sector++) {
		// 32 1 KiB blocks
//		FlashReady = FALSE;
		flash_adr = FLASH_BASE_ADR + IntFlashLdd1_ERASABLE_UNIT_SIZE * sector;
		error = FlashMem_EraseSector(flash_adr);
		if (error != ERR_OK) {
			strcpy(str, "\nError: cannot erase FLASH sector at address ");
			ltoa((long)flash_adr, tmp_str);
			strcat(str, tmp_str);
			strcat(str, "\n");
			usb_puts(str);
			FlashReady = TRUE;
		}
//		while (! FlashReady) {
//			wait_ms(1);
//		}
	}
}
Beispiel #9
0
/// \brief      Handler for the `help` command
static inline bool exec_help(void)
{
    usb_puts(PSTR(""));
    usb_puts(PSTR("Welcome to the uMIDI serial interface!"));
    usb_printf(PSTR("Software ID: %s" USB_NEWLINE), UMIDI_SOFTWARE_ID);
    usb_puts(PSTR("Built-in commands:"));
    usb_puts(PSTR("    clear             :  Clears the console by printing CR/LFs."));
    usb_puts(PSTR("    fwupdate <s>      :  Initiates a firmware update:"));
    usb_puts(PSTR("                         <s> : firmware update packet size"));
    usb_puts(PSTR("    help              :  Prints this help message."));
    usb_puts(PSTR("    reset             :  Resets the device."));

    if (user_commands_size) {
        usb_puts(PSTR("Special commands:"));
    }

    for (uint8_t i=0; i<user_commands_size; ++i) {
        // Copy strings to RAM for processing
        uint16_t cmd_string_size = strlen_P(user_commands[i].cmd_string)+1;
        char* cmd_string = malloc(cmd_string_size);
        strlcpy_P(cmd_string, user_commands[i].cmd_string, cmd_string_size);

        uint16_t help_string_size = strlen_P(user_commands[i].help_string)+1;
        char* help_string = malloc(help_string_size);
        strlcpy_P(help_string, user_commands[i].help_string, help_string_size);

        // Check if the help string contains newline characters
        const char* first_nl = strchr(help_string, '\n');
        if (first_nl) {
            // Parse specified options / parameters to the command string
            char* params = strtok(help_string, "\n");

            if (help_string == first_nl) {
                // If the first character of the help string is a newline character, the parsed
                // params are actually the first line of the description text.
                usb_printf(PSTR("    %-16s  :  %s" USB_NEWLINE), cmd_string, params);
            }
            else {
                // Append options / parameters to command string and print the whole thing
                char first_column[17] = "";
                snprintf(first_column, sizeof(first_column),
                         "%s %s", cmd_string, params);
                usb_printf(PSTR("    %-16s  :  "), first_column);

                // Complete the first line of the help string
                usb_printf(PSTR("%s" USB_NEWLINE), strtok(NULL, "\n"));
            }

            // Split remaining command description at '\n' chars, pad with spaces and print
            char* tail = strtok(NULL, "\n");
            while (tail) {
                usb_printf(PSTR("                         %s" USB_NEWLINE), tail);
                tail = strtok(NULL, "\n");
            }
        }
        else {
            // Print simple command description
            usb_printf(PSTR("    %-16s  :  %s" USB_NEWLINE), cmd_string, help_string);
        }

        free(help_string);
    }

    usb_puts(PSTR("Please enter a command:"));

    // Success
    return true;
}
Beispiel #10
0
/// \brief      Processes binary data arriving over USB during the update process
/// \details    If the supplied character is a carriage return, the command line read so far is
///             executed, otherwise the character is simply appended to a (circular!) buffer.
static inline void process_update_data(void)
{
    // Receive and copy bytes to page buffer
    while (usb_bytes_received()) {
        page_buffer[page_buffer_index] = usb_getc();
        ++page_buffer_index;
        --update_bytes_pending;
    }

    // When the last byte has arrived
    if (update_bytes_pending == 0) {
        // Extract expected CRC checksum
        expected_crc = page_buffer[page_buffer_index-2] << 8;
        expected_crc |= page_buffer[page_buffer_index-1];
        if (expected_crc == 0) {
            usb_puts(PSTR("Invalid empty CRC found!"));
            return;
        }
        usb_printf(PSTR("Expected CRC checksum: %x" USB_NEWLINE), expected_crc);

        // Rewind page_buffer_index
        page_buffer_index -= 2;

        // Pad last page with 0xFF for CRC calculation
        usb_puts(PSTR("Padding last application page..."));
        while (page_buffer_index < SPM_PAGESIZE)
        {
            page_buffer[page_buffer_index] = 0xff;
            ++page_buffer_index;
        }
    }

    // When a page is full, write it to the temporary application flash
    if (page_buffer_index == SPM_PAGESIZE) {
        // TODO: For unknown reasons, the following call prints 0 for the total number of pages:
        /*
        usb_printf(PSTR("Writing temporary application page [%3u/%3u]..." USB_NEWLINE),
                   temp_app_addr / SPM_PAGESIZE + 1,
                   num_pages);
        */
        usb_printf(PSTR("Writing temporary application page [%3u"), temp_app_addr / SPM_PAGESIZE + 1);
        usb_printf(PSTR("/%3u/%3u]..." USB_NEWLINE), num_pages, MAX_PAGE_NUM);
        if (xboot_app_temp_write_page(temp_app_addr, page_buffer, 0) != XB_SUCCESS) {
            goto fail;
        }
        temp_app_addr += SPM_PAGESIZE;
        page_buffer_index = 0;
    }

    if (update_bytes_pending == 0) {
        // Calculate CRC of the written application and compare with expected CRC
        usb_puts(PSTR("Performing CRC..."));
        uint16_t actual_crc = 0;
        xboot_app_temp_crc16(&actual_crc);
        if (expected_crc != actual_crc) {
            usb_printf(PSTR("CRC checksum mismatch: %x != %x" USB_NEWLINE), expected_crc, actual_crc);
            goto fail;
        }
        usb_puts(PSTR("Success!"));

        // Tell xboot to install the firmware on next reset
        if (xboot_install_firmware(expected_crc) != XB_SUCCESS) {
            goto fail;
        }

        // Reset device
        usb_puts(PSTR("Resetting device and installing new firmware..."));
        reset = true;
    }

    return;
fail:
    // Return to normal operation if the update failed
    usb_puts(PSTR("Update failed!"));
    update_in_progress = false;
    echo_on = true;
}