Add LULZBOT_TOUCH_UI (#14967)
This commit is contained in:
committed by
Scott Lahteine
parent
179d6c4ed1
commit
274934ad81
@@ -0,0 +1,560 @@
|
||||
/*********************
|
||||
* flash_storage.cpp *
|
||||
*********************/
|
||||
|
||||
/****************************************************************************
|
||||
* Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
|
||||
* Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* To view a copy of the GNU General Public License, go to the following *
|
||||
* location: <http://www.gnu.org/licenses/>. *
|
||||
****************************************************************************/
|
||||
|
||||
#include "../compat.h"
|
||||
|
||||
#if ENABLED(LULZBOT_TOUCH_UI)
|
||||
|
||||
#include "../ftdi_eve_lib/ftdi_eve_lib.h"
|
||||
|
||||
#include "media_file_reader.h"
|
||||
#include "flash_storage.h"
|
||||
|
||||
// The following must be changed whenever the layout of the flash
|
||||
// data is changed in a manner that would render the data invalid.
|
||||
|
||||
constexpr uint32_t flash_eeprom_version = 1;
|
||||
|
||||
/* SPI Flash Memory Map:
|
||||
*
|
||||
* The following offsets and sizes are specified in 4k erase units:
|
||||
*
|
||||
* Page Size Description
|
||||
* 0 16 DATA STORAGE AREA
|
||||
* 16 1 VERSIONING DATA
|
||||
* 17 inf MEDIA STORAGE AREA
|
||||
*
|
||||
*/
|
||||
|
||||
#define DATA_STORAGE_SIZE_64K
|
||||
|
||||
using namespace FTDI::SPI;
|
||||
using namespace FTDI::SPI::most_significant_byte_first;
|
||||
|
||||
bool UIFlashStorage::is_present = false;
|
||||
|
||||
#ifdef SPI_FLASH_SS
|
||||
/************************** SPI Flash Chip Interface **************************/
|
||||
|
||||
void SPIFlash::wait_while_busy() {
|
||||
uint8_t status;
|
||||
safe_delay(1);
|
||||
do {
|
||||
spi_flash_select();
|
||||
spi_write_8(READ_STATUS_1);
|
||||
status = spi_read_8();
|
||||
spi_flash_deselect();
|
||||
safe_delay(1);
|
||||
} while (status & 1);
|
||||
}
|
||||
|
||||
void SPIFlash::erase_sector_4k(uint32_t addr) {
|
||||
spi_flash_select();
|
||||
spi_write_8(WRITE_ENABLE);
|
||||
spi_flash_deselect();
|
||||
|
||||
spi_flash_select();
|
||||
spi_write_8(ERASE_4K);
|
||||
spi_write_24(addr);
|
||||
spi_flash_deselect();
|
||||
|
||||
wait_while_busy();
|
||||
}
|
||||
|
||||
void SPIFlash::erase_sector_64k(uint32_t addr) {
|
||||
spi_flash_select();
|
||||
spi_write_8(WRITE_ENABLE);
|
||||
spi_flash_deselect();
|
||||
|
||||
spi_flash_select();
|
||||
spi_write_8(ERASE_64K);
|
||||
spi_write_24(addr);
|
||||
spi_flash_deselect();
|
||||
|
||||
wait_while_busy();
|
||||
}
|
||||
|
||||
void SPIFlash::spi_write_begin(uint32_t addr) {
|
||||
spi_flash_select();
|
||||
spi_write_8(WRITE_ENABLE);
|
||||
spi_flash_deselect();
|
||||
|
||||
spi_flash_select();
|
||||
spi_write_8(PAGE_PROGRAM);
|
||||
spi_write_24(addr);
|
||||
}
|
||||
|
||||
void SPIFlash::spi_write_end() {
|
||||
spi_flash_deselect();
|
||||
wait_while_busy();
|
||||
}
|
||||
|
||||
void SPIFlash::spi_read_begin(uint32_t addr) {
|
||||
spi_flash_select();
|
||||
spi_write_8(READ_DATA);
|
||||
spi_write_24(addr);
|
||||
}
|
||||
|
||||
void SPIFlash::spi_read_end() {
|
||||
spi_flash_deselect();
|
||||
}
|
||||
|
||||
void SPIFlash::erase_chip() {
|
||||
spi_flash_select();
|
||||
spi_write_8(WRITE_ENABLE);
|
||||
spi_flash_deselect();
|
||||
|
||||
spi_flash_select();
|
||||
spi_write_8(ERASE_CHIP);
|
||||
spi_flash_deselect();
|
||||
wait_while_busy();
|
||||
}
|
||||
|
||||
void SPIFlash::read_jedec_id(uint8_t &manufacturer_id, uint8_t &device_type, uint8_t &capacity) {
|
||||
spi_flash_select();
|
||||
spi_write_8(READ_JEDEC_ID);
|
||||
manufacturer_id = spi_recv();
|
||||
device_type = spi_recv();
|
||||
capacity = spi_recv();
|
||||
spi_flash_deselect ();
|
||||
}
|
||||
|
||||
/* This function writes "size" bytes from "data" starting at addr, while properly
|
||||
* taking into account the special case of writing across a 256 byte page boundary.
|
||||
* Returns the addr directly after the write.
|
||||
*/
|
||||
uint32_t SPIFlash::write(uint32_t addr, const void *_data, size_t size) {
|
||||
const uint8_t *data = (const uint8_t*) _data;
|
||||
while (size) {
|
||||
const uint32_t page_start = addr & 0xFFFF00ul;
|
||||
const uint32_t page_end = page_start + 256;
|
||||
const uint32_t write_size = min(page_end - addr, size);
|
||||
spi_write_begin(addr);
|
||||
spi_write_bulk<ram_write>(data, write_size);
|
||||
spi_write_end();
|
||||
addr += write_size;
|
||||
size -= write_size;
|
||||
data += write_size;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
uint32_t SPIFlash::read(uint32_t addr, void *data, size_t size) {
|
||||
spi_read_begin(addr);
|
||||
spi_read_bulk(data, size);
|
||||
spi_read_end();
|
||||
return addr + size;
|
||||
}
|
||||
|
||||
/********************************** UTILITY ROUTINES *********************************/
|
||||
|
||||
bool UIFlashStorage::check_known_device() {
|
||||
uint8_t manufacturer_id, device_type, capacity;
|
||||
read_jedec_id(manufacturer_id, device_type, capacity);
|
||||
|
||||
const bool is_known =
|
||||
((manufacturer_id == 0xEF) && (device_type == 0x40) && (capacity == 0x15)) || // unknown
|
||||
((manufacturer_id == 0x01) && (device_type == 0x40) && (capacity == 0x15)) || // Cypress S25FL116K
|
||||
((manufacturer_id == 0xEF) && (device_type == 0x14) && (capacity == 0x15)) || // Winbond W25Q16JV
|
||||
((manufacturer_id == 0x1F) && (device_type == 0x86) && (capacity == 0x01)) ; // Adesto AT255F161
|
||||
|
||||
if (!is_known) {
|
||||
SERIAL_ECHO_START(); SERIAL_ECHOLNPGM("Unable to locate supported SPI Flash Memory.");
|
||||
SERIAL_ECHO_START(); SERIAL_ECHOLNPAIR(" Manufacturer ID, got: ", manufacturer_id);
|
||||
SERIAL_ECHO_START(); SERIAL_ECHOLNPAIR(" Device Type , got: ", device_type);
|
||||
SERIAL_ECHO_START(); SERIAL_ECHOLNPAIR(" Capacity , got: ", capacity);
|
||||
}
|
||||
|
||||
return is_known;
|
||||
}
|
||||
|
||||
void UIFlashStorage::initialize() {
|
||||
for(uint8_t i = 0; i < 10; i++) {
|
||||
if (check_known_device()) {
|
||||
is_present = true;
|
||||
break;
|
||||
}
|
||||
safe_delay(1000);
|
||||
}
|
||||
}
|
||||
|
||||
/**************************** DATA STORAGE AREA (first 4K or 64k) ********************/
|
||||
|
||||
#ifdef DATA_STORAGE_SIZE_64K
|
||||
constexpr uint32_t data_storage_area_size = 64 * 1024; // Large erase unit
|
||||
#else
|
||||
constexpr uint32_t data_storage_area_size = 4 * 1024; // Small erase unit
|
||||
#endif
|
||||
|
||||
/* In order to provide some degree of wear leveling, each data write to the
|
||||
* SPI Flash chip is appended to data that was already written before, until
|
||||
* the data storage area is completely filled. New data is written preceeded
|
||||
* with a 32-bit delimiter 'LULZ', so that we can distinguish written and
|
||||
* unwritten data:
|
||||
*
|
||||
* 'LULZ' <--- 1st record delimiter
|
||||
* <data_byte>
|
||||
* <data_byte>
|
||||
* <data_byte>
|
||||
* 'LULZ' <--- 2nd record delimiter
|
||||
* <data_byte>
|
||||
* <data_byte>
|
||||
* <data_byte>
|
||||
* ...
|
||||
* 'LULZ' <--- Last record delimiter
|
||||
* <data_byte>
|
||||
* <data_byte>
|
||||
* <data_byte>
|
||||
* 0xFF <--- Start of free space
|
||||
* 0xFF
|
||||
* ...
|
||||
*
|
||||
* This function walks down the data storage area, verifying that the
|
||||
* delimiters are either 'LULZ' or 0xFFFFFFFF. In the case that an invalid
|
||||
* delimiter is found, this function returns -1, indicating that the Flash
|
||||
* data is invalid (this will happen if the block_size changed with respect
|
||||
* to earlier firmware). Otherwise, it returns the offset of the last
|
||||
* valid delimiter 'LULZ', indicating the most recently written data.
|
||||
*/
|
||||
int32_t UIFlashStorage::get_config_read_offset(uint32_t block_size) {
|
||||
uint16_t stride = 4 + block_size;
|
||||
int32_t read_offset = -1;
|
||||
|
||||
for(uint32_t offset = 0; offset < (data_storage_area_size - stride); offset += stride) {
|
||||
uint32_t delim;
|
||||
spi_read_begin(offset);
|
||||
spi_read_bulk (&delim, sizeof(delim));
|
||||
spi_read_end();
|
||||
switch (delim) {
|
||||
case 0xFFFFFFFFul: return read_offset;
|
||||
case delimiter: read_offset = offset; break;
|
||||
default:
|
||||
SERIAL_ECHO_START(); SERIAL_ECHOLNPAIR("Invalid delimiter in Flash: ", delim);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
SERIAL_ECHO_START(); SERIAL_ECHOLNPGM("No LULZ delimiter found.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* This function returns the offset at which new data should be
|
||||
* appended, or -1 if the Flash needs to be erased */
|
||||
int32_t UIFlashStorage::get_config_write_offset(uint32_t block_size) {
|
||||
int32_t read_offset = get_config_read_offset(block_size);
|
||||
if (read_offset == -1) return -1; // The SPI flash is invalid
|
||||
|
||||
int32_t write_offset = read_offset + 4 + block_size;
|
||||
if ((write_offset + 4 + block_size) > data_storage_area_size) {
|
||||
SERIAL_ECHO_START(); SERIAL_ECHOLNPGM("Not enough free space in Flash.");
|
||||
return -1; // Not enough free space
|
||||
}
|
||||
return write_offset;
|
||||
}
|
||||
|
||||
bool UIFlashStorage::verify_config_data(const void *data, size_t size) {
|
||||
if (!is_present) return false;
|
||||
|
||||
int32_t read_addr = get_config_read_offset(size);
|
||||
if (read_addr == -1) return false;
|
||||
|
||||
uint32_t delim;
|
||||
spi_read_begin(read_addr);
|
||||
spi_read_bulk (&delim, sizeof(delim));
|
||||
bool ok = spi_verify_bulk(data,size);
|
||||
spi_read_end();
|
||||
return ok && delim == delimiter;
|
||||
}
|
||||
|
||||
bool UIFlashStorage::read_config_data(void *data, size_t size) {
|
||||
if (!is_present) return false;
|
||||
|
||||
int32_t read_addr = get_config_read_offset(size);
|
||||
if (read_addr == -1) return false;
|
||||
|
||||
uint32_t delim;
|
||||
spi_read_begin(read_addr);
|
||||
spi_read_bulk (&delim, sizeof(delim));
|
||||
spi_read_bulk (data, size);
|
||||
spi_read_end();
|
||||
return delim == delimiter;
|
||||
}
|
||||
|
||||
void UIFlashStorage::write_config_data(const void *data, size_t size) {
|
||||
if (!is_present) {
|
||||
SERIAL_ECHO_START(); SERIAL_ECHOLNPGM("SPI Flash chip not present. Not saving UI settings.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Since Flash storage has a limited number of write cycles,
|
||||
// make sure that the data is different before rewriting.
|
||||
|
||||
if (verify_config_data(data, size)) {
|
||||
SERIAL_ECHO_START(); SERIAL_ECHOLNPGM("UI settings already written, skipping write.");
|
||||
return;
|
||||
}
|
||||
|
||||
int16_t write_addr = get_config_write_offset(size);
|
||||
if (write_addr == -1) {
|
||||
SERIAL_ECHO_START();
|
||||
SERIAL_ECHOPGM("Erasing UI settings from SPI Flash... ");
|
||||
#ifdef DATA_STORAGE_SIZE_64K
|
||||
erase_sector_64k(0);
|
||||
#else
|
||||
erase_sector_4k(0);
|
||||
#endif
|
||||
write_addr = 0;
|
||||
SERIAL_ECHOLNPGM("DONE");
|
||||
}
|
||||
|
||||
SERIAL_ECHO_START();
|
||||
SERIAL_ECHOPAIR("Writing UI settings to SPI Flash (offset ", write_addr);
|
||||
SERIAL_ECHOPGM(")...");
|
||||
|
||||
const uint32_t delim = delimiter;
|
||||
write_addr = write(write_addr, &delim, sizeof(delim));
|
||||
write_addr = write(write_addr, data, size);
|
||||
|
||||
SERIAL_ECHOLNPGM("DONE");
|
||||
}
|
||||
|
||||
/************************** VERSIONING INFO AREA ************************/
|
||||
|
||||
/* The version info area follows the data storage area. If the version
|
||||
* is incorrect, the data on the chip is invalid and format_flash should
|
||||
* be called.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
uint32_t magic;
|
||||
uint32_t version;
|
||||
} flash_version_info;
|
||||
|
||||
constexpr uint32_t version_info_addr = data_storage_area_size;
|
||||
constexpr uint32_t version_info_size = 4 * 1024; // Small erase unit
|
||||
|
||||
bool UIFlashStorage::is_valid() {
|
||||
flash_version_info info;
|
||||
|
||||
spi_read_begin(version_info_addr);
|
||||
spi_read_bulk (&info, sizeof(flash_version_info));
|
||||
spi_read_end();
|
||||
|
||||
return info.magic == delimiter && info.version == flash_eeprom_version;
|
||||
}
|
||||
|
||||
void UIFlashStorage::write_version_info() {
|
||||
flash_version_info info;
|
||||
|
||||
info.magic = delimiter;
|
||||
info.version = flash_eeprom_version;
|
||||
|
||||
spi_write_begin(version_info_addr);
|
||||
spi_write_bulk<ram_write>(&info, sizeof(flash_version_info));
|
||||
spi_write_end();
|
||||
}
|
||||
|
||||
/**************************** MEDIA STORAGE AREA *****************************/
|
||||
|
||||
/* The media storage area follows the versioning info area. It consists
|
||||
* of a file index followed by the data for one or more media files.
|
||||
*
|
||||
* The file index consists of an array of 32-bit file sizes. If a file
|
||||
* is not present, the file's size will be set to 0xFFFFFFFF
|
||||
*/
|
||||
|
||||
constexpr uint32_t media_storage_addr = version_info_addr + version_info_size;
|
||||
constexpr uint8_t media_storage_slots = 4;
|
||||
|
||||
void UIFlashStorage::format_flash() {
|
||||
SERIAL_ECHO_START(); SERIAL_ECHOPGM("Erasing SPI Flash...");
|
||||
SPIFlash::erase_chip();
|
||||
SERIAL_ECHOLNPGM("DONE");
|
||||
|
||||
write_version_info();
|
||||
}
|
||||
|
||||
uint32_t UIFlashStorage::get_media_file_start(uint8_t slot) {
|
||||
uint32_t addr = media_storage_addr + sizeof(uint32_t) * media_storage_slots;
|
||||
spi_read_begin(media_storage_addr);
|
||||
for(uint8_t i = 0; i < slot; i++) {
|
||||
addr += spi_read_32();
|
||||
}
|
||||
spi_read_end();
|
||||
return addr;
|
||||
}
|
||||
|
||||
void UIFlashStorage::set_media_file_size(uint8_t slot, uint32_t size) {
|
||||
spi_write_begin(media_storage_addr + sizeof(uint32_t) * slot);
|
||||
spi_write_32(size);
|
||||
spi_write_end();
|
||||
}
|
||||
|
||||
uint32_t UIFlashStorage::get_media_file_size(uint8_t slot) {
|
||||
spi_read_begin(media_storage_addr + sizeof(uint32_t) * slot);
|
||||
uint32_t size = spi_read_32();
|
||||
spi_read_end();
|
||||
return size;
|
||||
}
|
||||
|
||||
/* Writes a media file from the SD card/USB flash drive into a slot on the SPI Flash. Media
|
||||
* files must be written sequentially following by a chip erase and it is not possible to
|
||||
* overwrite files. */
|
||||
UIFlashStorage::error_t UIFlashStorage::write_media_file(progmem_str filename, uint8_t slot) {
|
||||
#if ENABLED(SDSUPPORT)
|
||||
uint32_t addr;
|
||||
uint8_t buff[write_page_size];
|
||||
|
||||
strcpy_P( (char*) buff, (const char*) filename);
|
||||
|
||||
MediaFileReader reader;
|
||||
if (!reader.open((char*) buff)) {
|
||||
SERIAL_ECHO_START(); SERIAL_ECHOLNPGM("Unable to find media file");
|
||||
return FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (get_media_file_size(slot) != 0xFFFFFFFFUL) {
|
||||
SERIAL_ECHO_START(); SERIAL_ECHOLNPGM("Media file already exists");
|
||||
return WOULD_OVERWRITE;
|
||||
}
|
||||
|
||||
SERIAL_ECHO_START(); SERIAL_ECHOPGM("Writing SPI Flash...");
|
||||
|
||||
set_media_file_size(slot, reader.size());
|
||||
addr = get_media_file_start(slot);
|
||||
|
||||
// Write out the file itself
|
||||
for(;;) {
|
||||
const int16_t nBytes = reader.read(buff, write_page_size);
|
||||
if (nBytes == -1) {
|
||||
SERIAL_ECHOLNPGM("Failed to read from file");
|
||||
return READ_ERROR;
|
||||
}
|
||||
|
||||
addr = write(addr, buff, nBytes);
|
||||
if (nBytes != write_page_size)
|
||||
break;
|
||||
|
||||
#if ENABLED(EXTENSIBLE_UI)
|
||||
ExtUI::yield();
|
||||
#endif
|
||||
}
|
||||
|
||||
SERIAL_ECHOLNPGM("DONE");
|
||||
|
||||
SERIAL_ECHO_START(); SERIAL_ECHOPGM("Verifying SPI Flash...");
|
||||
|
||||
bool verifyOk = true;
|
||||
|
||||
// Verify the file index
|
||||
|
||||
if (get_media_file_start(slot+1) != (get_media_file_start(slot) + reader.size())) {
|
||||
SERIAL_ECHOLNPGM("File index verification failed. ");
|
||||
verifyOk = false;
|
||||
}
|
||||
|
||||
// Verify the file itself
|
||||
addr = get_media_file_start(slot);
|
||||
reader.rewind();
|
||||
|
||||
while (verifyOk) {
|
||||
const int16_t nBytes = reader.read(buff, write_page_size);
|
||||
if (nBytes == -1) {
|
||||
SERIAL_ECHOPGM("Failed to read from file");
|
||||
verifyOk = false;
|
||||
break;
|
||||
}
|
||||
|
||||
spi_read_begin(addr);
|
||||
if (!spi_verify_bulk(buff, nBytes)) {
|
||||
verifyOk = false;
|
||||
spi_read_end();
|
||||
break;
|
||||
}
|
||||
spi_read_end();
|
||||
|
||||
addr += nBytes;
|
||||
if (nBytes != write_page_size) break;
|
||||
#if ENABLED(EXTENSIBLE_UI)
|
||||
ExtUI::yield();
|
||||
#endif
|
||||
};
|
||||
|
||||
if (verifyOk) {
|
||||
SERIAL_ECHOLNPGM("DONE");
|
||||
return SUCCESS;
|
||||
} else {
|
||||
SERIAL_ECHOLNPGM("FAIL");
|
||||
return VERIFY_ERROR;
|
||||
}
|
||||
#else
|
||||
return VERIFY_ERROR;
|
||||
#endif // ENABLED(SDSUPPORT)
|
||||
}
|
||||
|
||||
bool UIFlashStorage::BootMediaReader::isAvailable(uint32_t slot) {
|
||||
if (!is_present) return false;
|
||||
|
||||
bytes_remaining = get_media_file_size(slot);
|
||||
if (bytes_remaining != 0xFFFFFFFFUL) {
|
||||
SERIAL_ECHO_START(); SERIAL_ECHOLNPAIR("Boot media file size:", bytes_remaining);
|
||||
addr = get_media_file_start(slot);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int16_t UIFlashStorage::BootMediaReader::read(void *data, const size_t size) {
|
||||
if (bytes_remaining == 0xFFFFFFFFUL) return -1;
|
||||
|
||||
if (size > bytes_remaining)
|
||||
return read(data, bytes_remaining);
|
||||
|
||||
if (size > 0) {
|
||||
spi_read_begin(addr);
|
||||
spi_read_bulk(data, size);
|
||||
spi_read_end();
|
||||
addr += size;
|
||||
bytes_remaining -= size;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
int16_t UIFlashStorage::BootMediaReader::read(void *obj, void *data, const size_t size) {
|
||||
return reinterpret_cast<UIFlashStorage::BootMediaReader*>(obj)->read(data, size);
|
||||
}
|
||||
|
||||
#else
|
||||
void UIFlashStorage::initialize() {}
|
||||
bool UIFlashStorage::is_valid() {return true;}
|
||||
void UIFlashStorage::write_config_data(const void *, size_t) {}
|
||||
bool UIFlashStorage::verify_config_data(const void *, size_t) {return false;}
|
||||
bool UIFlashStorage::read_config_data(void *, size_t ) {return false;}
|
||||
UIFlashStorage::error_t UIFlashStorage::write_media_file(progmem_str, uint8_t) {return FILE_NOT_FOUND;}
|
||||
void UIFlashStorage::format_flash() {}
|
||||
|
||||
bool UIFlashStorage::BootMediaReader::isAvailable(uint32_t) {return false;}
|
||||
int16_t UIFlashStorage::BootMediaReader::read(void *, const size_t) {return -1;}
|
||||
int16_t UIFlashStorage::BootMediaReader::read(void *, void *, const size_t) {return -1;}
|
||||
#endif // SPI_FLASH_SS
|
||||
#endif // LULZBOT_TOUCH_UI
|
||||
@@ -0,0 +1,110 @@
|
||||
/*******************
|
||||
* flash_storage.h *
|
||||
*******************/
|
||||
|
||||
/****************************************************************************
|
||||
* Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
|
||||
* Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* To view a copy of the GNU General Public License, go to the following *
|
||||
* location: <http://www.gnu.org/licenses/>. *
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef LULZBOT_TOUCH_UI
|
||||
|
||||
class SPIFlash {
|
||||
public:
|
||||
static constexpr uint32_t erase_unit_size = 4 * 1024; // Minimum erase unit
|
||||
static constexpr uint32_t write_page_size = 256; // Minimum page write unit
|
||||
|
||||
enum {
|
||||
READ_STATUS_1 = 0x05,
|
||||
READ_STATUS_2 = 0x35,
|
||||
READ_STATUS_3 = 0x33,
|
||||
WRITE_ENABLE = 0x06,
|
||||
WRITE_DISABLE = 0x04,
|
||||
READ_ID = 0x90,
|
||||
READ_JEDEC_ID = 0x9F,
|
||||
READ_DATA = 0x03,
|
||||
PAGE_PROGRAM = 0x02,
|
||||
ERASE_4K = 0x20,
|
||||
ERASE_64K = 0xD8,
|
||||
ERASE_CHIP = 0xC7
|
||||
};
|
||||
|
||||
static void wait_while_busy();
|
||||
static void erase_sector_4k(uint32_t addr);
|
||||
static void erase_sector_64k(uint32_t addr);
|
||||
static void erase_chip ();
|
||||
|
||||
static void read_jedec_id(uint8_t &manufacturer_id, uint8_t &device_type, uint8_t &capacity);
|
||||
|
||||
static void spi_read_begin(uint32_t addr);
|
||||
static void spi_read_end();
|
||||
|
||||
static void spi_write_begin(uint32_t addr);
|
||||
static void spi_write_end();
|
||||
|
||||
static uint32_t write(uint32_t addr, const void *data, size_t size);
|
||||
static uint32_t read(uint32_t addr, void *data, size_t size);
|
||||
};
|
||||
|
||||
class UIFlashStorage : private SPIFlash {
|
||||
private:
|
||||
|
||||
static bool is_present;
|
||||
static int32_t get_config_read_offset(uint32_t block_size);
|
||||
static int32_t get_config_write_offset(uint32_t block_size);
|
||||
|
||||
static uint32_t get_media_file_start(uint8_t slot);
|
||||
static void set_media_file_size(uint8_t slot, uint32_t size);
|
||||
static uint32_t get_media_file_size(uint8_t slot);
|
||||
|
||||
static constexpr uint32_t delimiter = 0x4C554C5A; // 'LULZ'
|
||||
public:
|
||||
enum error_t {
|
||||
SUCCESS,
|
||||
FILE_NOT_FOUND,
|
||||
READ_ERROR,
|
||||
VERIFY_ERROR,
|
||||
WOULD_OVERWRITE
|
||||
};
|
||||
|
||||
static void initialize ();
|
||||
static void format_flash ();
|
||||
static bool check_known_device();
|
||||
|
||||
static bool is_valid ();
|
||||
static void write_version_info();
|
||||
|
||||
static void write_config_data (const void *data, size_t size);
|
||||
static bool verify_config_data (const void *data, size_t size);
|
||||
static bool read_config_data (void *data, size_t size);
|
||||
static error_t write_media_file (progmem_str filename, uint8_t slot = 0);
|
||||
|
||||
class BootMediaReader;
|
||||
};
|
||||
|
||||
class UIFlashStorage::BootMediaReader {
|
||||
private:
|
||||
uint32_t addr;
|
||||
uint32_t bytes_remaining;
|
||||
|
||||
public:
|
||||
bool isAvailable(uint32_t slot = 0);
|
||||
int16_t read(void *buffer, size_t const size);
|
||||
|
||||
static int16_t read(void *obj, void *buffer, const size_t size);
|
||||
};
|
||||
|
||||
#endif // LULZBOT_TOUCH_UI
|
||||
@@ -0,0 +1,63 @@
|
||||
/************************
|
||||
* media_filereader.cpp *
|
||||
************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
|
||||
* Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* To view a copy of the GNU General Public License, go to the following *
|
||||
* location: <http://www.gnu.org/licenses/>. *
|
||||
****************************************************************************/
|
||||
|
||||
#include "../compat.h"
|
||||
|
||||
#if ENABLED(LULZBOT_TOUCH_UI)
|
||||
#include "media_file_reader.h"
|
||||
|
||||
#if ENABLED(SDSUPPORT)
|
||||
bool MediaFileReader::open(const char* filename) {
|
||||
card.init(SPI_SPEED, SDSS);
|
||||
volume.init(&card);
|
||||
root.openRoot(&volume);
|
||||
return file.open(&root, filename, O_READ);
|
||||
}
|
||||
|
||||
int16_t MediaFileReader::read(void *buff, size_t bytes) {
|
||||
return file.read(buff, bytes);
|
||||
}
|
||||
|
||||
void MediaFileReader::close() {
|
||||
file.close();
|
||||
}
|
||||
|
||||
uint32_t MediaFileReader::size() {
|
||||
return file.fileSize();
|
||||
}
|
||||
|
||||
void MediaFileReader::rewind() {
|
||||
file.rewind();
|
||||
}
|
||||
|
||||
int16_t MediaFileReader::read(void *obj, void *buff, size_t bytes) {
|
||||
return reinterpret_cast<MediaFileReader*>(obj)->read(buff, bytes);
|
||||
}
|
||||
#else
|
||||
bool MediaFileReader::open(const char*) {return -1;}
|
||||
int16_t MediaFileReader::read(void *, size_t) {return 0;}
|
||||
void MediaFileReader::close() {}
|
||||
uint32_t MediaFileReader::size() {return 0;}
|
||||
void MediaFileReader::rewind() {}
|
||||
int16_t MediaFileReader::read(void *, void *, size_t) {return 0;}
|
||||
#endif
|
||||
#endif // LULZBOT_TOUCH_UI
|
||||
@@ -0,0 +1,44 @@
|
||||
/**********************
|
||||
* media_filereader.h *
|
||||
**********************/
|
||||
|
||||
/****************************************************************************
|
||||
* Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
|
||||
* Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* To view a copy of the GNU General Public License, go to the following *
|
||||
* location: <http://www.gnu.org/licenses/>. *
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../../../../sd/SdFile.h"
|
||||
#include "../../../../../sd/cardreader.h"
|
||||
|
||||
class MediaFileReader {
|
||||
private:
|
||||
#if ENABLED(SDSUPPORT)
|
||||
Sd2Card card;
|
||||
SdVolume volume;
|
||||
SdFile root, file;
|
||||
#endif
|
||||
|
||||
public:
|
||||
bool open(const char* filename);
|
||||
int16_t read(void *buff, size_t bytes);
|
||||
uint32_t size();
|
||||
void rewind();
|
||||
void close();
|
||||
|
||||
static int16_t read(void *obj, void *buff, size_t bytes);
|
||||
};
|
||||
Reference in New Issue
Block a user