last save
This commit is contained in:
95
create_firmware_package.py
Normal file
95
create_firmware_package.py
Normal file
@@ -0,0 +1,95 @@
|
||||
import zlib
|
||||
import gzip
|
||||
import shutil
|
||||
import tarfile
|
||||
import os
|
||||
|
||||
Import("env")
|
||||
|
||||
#print("Current CLI targets", COMMAND_LINE_TARGETS)
|
||||
#print("Current Build targets", BUILD_TARGETS)
|
||||
|
||||
def post_program_action(source, target, env):
|
||||
print("Program has been built!")
|
||||
program_path = target[0].get_abspath()
|
||||
print("Program path", program_path)
|
||||
# Use case: sign a firmware, do any manipulations with ELF, etc
|
||||
# env.Execute(f"sign --elf {program_path}")
|
||||
|
||||
env.AddPostAction("$PROGPATH", post_program_action)
|
||||
|
||||
|
||||
def post_bin_action(source, target, env):
|
||||
print("Program has built bin file")
|
||||
bin_path = target[0].get_abspath()
|
||||
print("BIN path", bin_path)
|
||||
print("source path", source[0].get_abspath())
|
||||
#firmware_data = open(bin_path, 'rb').read()
|
||||
#compressed_data = zlib.compress(firmware_data, zlib.Z_BEST_COMPRESSION)
|
||||
#compress_ratio = (float(len(firmware_data)) - float(len(compressed_data))) / float(len(firmware_data))
|
||||
#print('Compressed: %d%%' % (100.0 * compress_ratio))
|
||||
#f = open('firmware.data', 'wb')
|
||||
#f.write(compressed_data)
|
||||
#f.close()
|
||||
|
||||
#with open(bin_path, 'rb') as f_in:
|
||||
# with gzip.open('firmware.bin.gz', 'wb') as f_out:
|
||||
# shutil.copyfileobj(f_in, f_out)
|
||||
|
||||
print("create tar file")
|
||||
with tarfile.open("firmware.tar", "w", format=tarfile.GNU_FORMAT) as tar:
|
||||
tar.add(bin_path, arcname="firmware.bin")
|
||||
#tar.add("data", arcname=os.path.basename("data"))
|
||||
tar.add("data", arcname=os.path.basename(""))
|
||||
|
||||
|
||||
env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", post_bin_action)
|
||||
|
||||
#
|
||||
# Upload actions
|
||||
#
|
||||
|
||||
# def before_upload(source, target, env):
|
||||
# print("before_upload")
|
||||
# do some actions
|
||||
|
||||
# call Node.JS or other script
|
||||
# env.Execute("node --version")
|
||||
|
||||
|
||||
# def after_upload(source, target, env):
|
||||
# print("after_upload")
|
||||
# do some actions
|
||||
|
||||
# env.AddPreAction("upload", before_upload)
|
||||
# env.AddPostAction("upload", after_upload)
|
||||
|
||||
#
|
||||
# Custom actions when building program/firmware
|
||||
#
|
||||
|
||||
# env.AddPreAction("buildprog", callback...)
|
||||
# env.AddPostAction("buildprog", callback...)
|
||||
|
||||
#
|
||||
# Custom actions for specific files/objects
|
||||
#
|
||||
|
||||
#env.AddPreAction("$PROGPATH", callback...)
|
||||
#env.AddPreAction("$BUILD_DIR/${PROGNAME}.elf", [callback1, callback2,...])
|
||||
#env.AddPostAction("$BUILD_DIR/${PROGNAME}.hex", callback...)
|
||||
|
||||
# custom action before building SPIFFS image. For example, compress HTML, etc.
|
||||
# env.AddPreAction("$BUILD_DIR/spiffs.bin", callback...)
|
||||
|
||||
# custom action for project's main.cpp
|
||||
# env.AddPostAction("$BUILD_DIR/src/main.cpp.o", callback...)
|
||||
|
||||
# Custom HEX from ELF
|
||||
# env.AddPostAction(
|
||||
# "$BUILD_DIR/${PROGNAME}.elf",
|
||||
# env.VerboseAction(" ".join([
|
||||
# "$OBJCOPY", "-O", "ihex", "-R", ".eeprom",
|
||||
# "$BUILD_DIR/${PROGNAME}.elf", "$BUILD_DIR/${PROGNAME}.hex"
|
||||
# ]), "Building $BUILD_DIR/${PROGNAME}.hex")
|
||||
#)
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
<div class='dataitem'>
|
||||
<label>Use SSL :</label>
|
||||
<input type='checkbox' id='useSSL' name='useSSL' >
|
||||
<input type='checkbox' id='acsuseSSL' name='acsuseSSL' >
|
||||
</div>
|
||||
|
||||
<div class="dataitem">
|
||||
@@ -39,7 +39,7 @@
|
||||
</div>
|
||||
<div class="dataitem">
|
||||
<label>ACS Server Port :</label>
|
||||
<input id="acsport" name='acsport' min='0' max='65535' type='number'>
|
||||
<input id="acsserverport" name='acsserverport' min='0' max='65535' type='number'>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -29,11 +29,11 @@
|
||||
<h2>Credential Settings</h2>
|
||||
<div class="dataitem">
|
||||
<label>Username :</label>
|
||||
<input id="username" name="www_user" maxlength="31" size="32" type="text">
|
||||
<input id="username" name="username" maxlength="31" size="32" type="text">
|
||||
</div>
|
||||
<div class="dataitem">
|
||||
<label>Password :</label>
|
||||
<input id="password" name='www_pass' maxlength='31' size='32' type='text'>
|
||||
<input id="password" name='password' maxlength='31' size='32' type='text'>
|
||||
</div>
|
||||
</div>
|
||||
<div class='datafield'>
|
||||
|
||||
@@ -73,9 +73,6 @@
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="datafield">
|
||||
<h2>User files</h2>
|
||||
</div>
|
||||
<div class="datafield">
|
||||
<h2>Firmware</h2>
|
||||
<div class="dataitem">
|
||||
@@ -85,11 +82,15 @@
|
||||
</div>
|
||||
<div class="datafield">
|
||||
<h2>Update Firmware</h2>
|
||||
<div class="dataitem itemcenter saveconfig">
|
||||
<form method="POST" action="startupdate">
|
||||
<input value="Update firmware" type="submit">
|
||||
</form>
|
||||
</div>
|
||||
<form method="POST" action="startupdate">
|
||||
<div class="dataitem">
|
||||
<label>Update Server :</label>
|
||||
<input id="server" name='server' maxlength='63' size='64' type='text'>
|
||||
</div>
|
||||
<div class="dataitem itemcenter saveconfig">
|
||||
<input value="Update firmware" type="submit">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
BIN
firmware.tar
Normal file
BIN
firmware.tar
Normal file
Binary file not shown.
@@ -8,82 +8,137 @@
|
||||
#include "mbed.h"
|
||||
//#include "Arduino.h"
|
||||
#include "ACSFileSystem.h"
|
||||
//#include "PluggableUSBMSD.h"
|
||||
//#include "USBMSD.h"
|
||||
#include "ACSUSBMSD.h"
|
||||
//#include "USBDevice.h"
|
||||
//#include "USBMSD.h"
|
||||
#include "QSPIFBlockDevice.h"
|
||||
#include "MBRBlockDevice.h"
|
||||
#include "FATFileSystem.h"
|
||||
//#include "FATFileSystem.h"
|
||||
#include "KVStore.h"
|
||||
#include "kvstore_global_api.h"
|
||||
//#include "LittleFileSystem.h"
|
||||
#include "TDBStore.h"
|
||||
#include "SlicingBlockDevice.h"
|
||||
#include "FileSystemStore.h"
|
||||
#include "kvstore_global_api.h"
|
||||
#include "DeviceKey.h"
|
||||
//#include "ACSQSPIFBlockDevice.h"
|
||||
|
||||
//AT25SF128A - MX25L12833F
|
||||
|
||||
QSPIFBlockDevice root(QSPI_SO0, QSPI_SO1, QSPI_SO2, QSPI_SO3, QSPI_SCK, QSPI_CS, QSPIF_POLARITY_MODE_1, 40000000);
|
||||
//QSPIFBlockDevice root(QSPI_SO0, QSPI_SO1, QSPI_SO2, QSPI_SO3, QSPI_SCK, QSPI_CS, QSPIF_POLARITY_MODE_1, 80000000);
|
||||
mbed::MBRBlockDevice ota_data(&root, 1);
|
||||
mbed::MBRBlockDevice user_data(&root, 2);
|
||||
static mbed::FATFileSystem ota_data_fs("ota");
|
||||
static mbed::FATFileSystem user_data_fs("user");
|
||||
//ACSQSPIFBlockDevice root(QSPI_SO0, QSPI_SO1, QSPI_SO2, QSPI_SO3, QSPI_SCK, QSPI_CS, QSPIF_POLARITY_MODE_1, 40000000);
|
||||
|
||||
ACSUSBMSD usbStorage(&root);
|
||||
//mbed::MBRBlockDevice user_data(&root, 1);
|
||||
//mbed::BufferedBlockDevice user_data(&root);
|
||||
//mbed::SlicingBlockDevice user_data(&root, USER_START, USER_SIZE);
|
||||
//mbed::FATFileSystem user_data_fs("user", &user_data);
|
||||
mbed::FATFileSystem user_data_fs("user", &root);
|
||||
|
||||
//static mbed::LittleFileSystem user_data_fs("user");
|
||||
|
||||
//mbed::MBRBlockDevice ota_data(&root, 2);
|
||||
//mbed::BufferedBlockDevice ota_data(&root);
|
||||
|
||||
//mbed::SlicingBlockDevice ota_data(&root, OTA_START, OTA_SIZE);
|
||||
//static mbed::FATFileSystem ota_data_fs("ota", &ota_data);
|
||||
|
||||
//static mbed::LittleFileSystem ota_data_fs("ota");
|
||||
|
||||
//mbed::MBRBlockDevice kv_data(&root, 3);
|
||||
//static mbed::TDBStore kv_store_fs(&kv_data);
|
||||
|
||||
//mbed::FileSystemStore system_store(&user_data_fs);
|
||||
|
||||
|
||||
//ACSUSBMSD usbStorage(&root);
|
||||
//ACSUSBMSD usbStorage(&user_data);
|
||||
//ACSUSBMSD usbStorage(&user_data_fs);
|
||||
|
||||
void ACSFileSystem::begin()
|
||||
{
|
||||
int err = root.init();
|
||||
if (err != 0) {
|
||||
Serial.print("Error Initializing the QSPIF: ");
|
||||
Serial.println(err);
|
||||
return;
|
||||
}
|
||||
err = ota_data_fs.mount(&ota_data);
|
||||
if (err != 0)
|
||||
{
|
||||
Serial.println("ota fs error");
|
||||
formatPartitions();
|
||||
return;
|
||||
}
|
||||
err = user_data_fs.mount(&user_data);
|
||||
if (err != 0)
|
||||
{
|
||||
Serial.println("user fs error");
|
||||
formatPartitions();
|
||||
return;
|
||||
}
|
||||
}
|
||||
// int err = root.init();
|
||||
// if (err != 0) {
|
||||
// Serial.print("Error Initializing the QSPIF: ");
|
||||
// Serial.println(err);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// void ACSFileSystem::process()
|
||||
// {
|
||||
// //usbStorage.process();
|
||||
// }
|
||||
// err = user_data.init();
|
||||
// if (err != 0) {
|
||||
// Serial.print("Error Initializing the user_data: ");
|
||||
// Serial.println(err);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// err = user_data_fs.mount(&root);
|
||||
// if (err != 0)
|
||||
// {
|
||||
// Serial.print("user fs error: ");
|
||||
// Serial.println(err);
|
||||
// //formatPartitions();
|
||||
// return;
|
||||
// }
|
||||
|
||||
// err = ota_data.init();
|
||||
// if (err != 0) {
|
||||
// Serial.print("Error Initializing the ota_data: ");
|
||||
// Serial.println(err);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// err = ota_data_fs.mount(&ota_data);
|
||||
// if (err != 0)
|
||||
// {
|
||||
// Serial.print("ota fs error: ");
|
||||
// Serial.println(err);
|
||||
// formatPartitions();
|
||||
// return;
|
||||
// }
|
||||
|
||||
|
||||
// err = system_store.init();
|
||||
// if (err != 0)
|
||||
// {
|
||||
// Serial.print("system store error: ");
|
||||
// Serial.println(err);
|
||||
// //formatPartitions();
|
||||
// return;
|
||||
// }
|
||||
|
||||
// err = kv_reset("/kv/");
|
||||
// if (err != 0)
|
||||
// {
|
||||
// Serial.print("kv reset error: ");
|
||||
// Serial.println(err);
|
||||
// }
|
||||
//kv_set("TEST")
|
||||
|
||||
}
|
||||
|
||||
void ACSFileSystem::erasePartitions()
|
||||
{
|
||||
Serial.println("Start erasing");
|
||||
|
||||
ota_data_fs.unmount();
|
||||
user_data_fs.unmount();
|
||||
//ota_data_fs.unmount();
|
||||
|
||||
int err = 0;
|
||||
const mbed::bd_size_t erase_size = root.get_erase_size();
|
||||
const mbed::bd_size_t size = root.size();
|
||||
const mbed::bd_size_t eraseSectors = size / erase_size;
|
||||
|
||||
//Serial.println(erase_size);
|
||||
//Serial.println(size);
|
||||
//Serial.println(eraseSectors);
|
||||
|
||||
for (mbed::bd_size_t i = 0; i < eraseSectors; i++) {
|
||||
err = root.erase(i * erase_size, erase_size);
|
||||
int err = root.erase(i * erase_size, erase_size);
|
||||
if (i % 64 == 0) {
|
||||
Serial.print(".");
|
||||
Serial.print("sector: ");
|
||||
Serial.println(i);
|
||||
}
|
||||
if (err != 0) {
|
||||
Serial.print("Error erasing sector ");
|
||||
Serial.println(i);
|
||||
Serial.print(" [");
|
||||
Serial.print(i * erase_size);
|
||||
Serial.print(" - ");
|
||||
Serial.print(float{ i } / float{ eraseSectors } * 100);
|
||||
Serial.print("%] -> ");
|
||||
Serial.print(err ? "KO" : "OK");
|
||||
Serial.println();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -94,29 +149,75 @@ void ACSFileSystem::formatPartitions()
|
||||
{
|
||||
Serial.println("Start formatting");
|
||||
|
||||
ota_data_fs.unmount();
|
||||
user_data_fs.unmount();
|
||||
|
||||
// Format the partitions and create filesystem instances
|
||||
mbed::MBRBlockDevice::partition(&root, 1, 0x0B, OTA_START, OTA_SIZE); //ota = 1MB
|
||||
mbed::MBRBlockDevice::partition(&root, 2, 0x0B, USER_START, USER_SIZE); //user = 15MB
|
||||
|
||||
Serial.print("Formatting ota partition... ");
|
||||
int err = ota_data_fs.reformat(&ota_data);
|
||||
if (err != 0) {
|
||||
Serial.println("Error formatting ota partition");
|
||||
return;
|
||||
}
|
||||
Serial.println("done.");
|
||||
//ota_data_fs.unmount();
|
||||
|
||||
Serial.print("Formatting user partition...");
|
||||
err = user_data_fs.reformat(&user_data);
|
||||
if (err != 0) {
|
||||
Serial.println("Error formatting user partition");
|
||||
int err = user_data_fs.reformat(&root);
|
||||
if (err != 0) {
|
||||
Serial.print("Error formatting user partition: ");
|
||||
Serial.println(err);
|
||||
return;
|
||||
}
|
||||
Serial.println("done.");
|
||||
|
||||
// Serial.print("Formatting ota partition... ");
|
||||
// err = ota_data_fs.reformat(&ota_data);
|
||||
// if (err != 0) {
|
||||
// Serial.print("Error formatting ota partition: ");
|
||||
// Serial.println(err);
|
||||
// return;
|
||||
// }
|
||||
// Serial.println("done.");
|
||||
|
||||
//user_data_fs.mount(&root);
|
||||
|
||||
|
||||
|
||||
//ota_data_fs.unmount();
|
||||
//user_data_fs.unmount();
|
||||
|
||||
// Format the partitions and create filesystem instances
|
||||
//mbed::MBRBlockDevice::partition(&root, 1, 0x0B, USER_START, USER_SIZE); //user = 10MB
|
||||
//mbed::MBRBlockDevice::partition(&root, 2, 0x0B, OTA_START, OTA_SIZE); //ota = 6MB
|
||||
//mbed::MBRBlockDevice::partition(&root, 2, 0x0B, OTA_START); //ota = 6MB
|
||||
//mbed::MBRBlockDevice::partition(&root, 3, 0x0B, KV_START);
|
||||
|
||||
// Serial.print("Formatting user partition...");
|
||||
// int err = user_data_fs.reformat(&user_data);
|
||||
// if (err != 0) {
|
||||
// Serial.println(err);
|
||||
// Serial.println("Error formatting user partition");
|
||||
// return;
|
||||
// }
|
||||
// Serial.println("done.");
|
||||
|
||||
// Serial.print("Formatting ota partition... ");
|
||||
// err = ota_data_fs.reformat(&ota_data);
|
||||
// if (err != 0) {
|
||||
// Serial.println(err);
|
||||
// Serial.println("Error formatting ota partition");
|
||||
// return;
|
||||
// }
|
||||
// Serial.println("done.");
|
||||
|
||||
|
||||
// Serial.print("Formatting kv partition...");
|
||||
// err = kv_data.init();
|
||||
// if (err != 0) {
|
||||
// Serial.println("Error formatting user partition");
|
||||
// return;
|
||||
// }
|
||||
// Serial.println("done.");
|
||||
|
||||
// int err = user_data_fs.mount(&root);
|
||||
// if (err != 0)
|
||||
// {
|
||||
// Serial.println("user fs error");
|
||||
// formatPartitions();
|
||||
// return;
|
||||
// }
|
||||
|
||||
mbed::File file;
|
||||
err = file.open(&user_data_fs, "user.txt", O_CREAT);
|
||||
if(err != 0)
|
||||
@@ -124,74 +225,39 @@ void ACSFileSystem::formatPartitions()
|
||||
Serial.println("file write error");
|
||||
}
|
||||
file.close();
|
||||
//user_data.sync();
|
||||
|
||||
Serial.println("QSPI Flash formatted!");
|
||||
//Serial.println("QSPI Flash formatted!");
|
||||
}
|
||||
|
||||
|
||||
int ACSFileSystem::openFile(const char* filename, mbed::File *file, int flags)
|
||||
int ACSFileSystem::openFile(const char* filename, mbed::File *file, int flags, bool ota)
|
||||
{
|
||||
return file->open(&user_data_fs, filename, flags);
|
||||
// //Serial.println(filename);
|
||||
// int err = file->open(&user_data_fs, filename, flags);
|
||||
// //Serial.println(err);
|
||||
// if (err != MBED_SUCCESS)
|
||||
// if(ota)
|
||||
// {
|
||||
// Serial.println("Unable to open file");
|
||||
// Serial.println(strerror(err));
|
||||
// return -1;
|
||||
// return file->open(&ota_data_fs, filename, flags);
|
||||
// }
|
||||
// //Serial.print(" [");
|
||||
// //Serial.print(file->size());
|
||||
// //Serial.println(" bytes]");
|
||||
|
||||
// return MBED_SUCCESS;
|
||||
return file->open(&user_data_fs, filename, flags);
|
||||
}
|
||||
|
||||
int ACSFileSystem::removeFile(const char* filename)
|
||||
int ACSFileSystem::removeFile(const char* filename, bool ota)
|
||||
{
|
||||
return user_data_fs.remove(filename);
|
||||
}
|
||||
|
||||
|
||||
int ACSFileSystem::openFirmwarefile(mbed::File *file)
|
||||
{
|
||||
ota_data_fs.remove("firmware.bin");
|
||||
return file->open(&ota_data_fs, "firmware.bin", O_RDWR | O_CREAT | O_APPEND);
|
||||
}
|
||||
|
||||
void ACSFileSystem::writeFirmware(char *data, size_t length, uint16_t block)
|
||||
{
|
||||
Serial.println("Write firmware");
|
||||
Serial.println(length);
|
||||
Serial.println(block);
|
||||
|
||||
if(block == 1)
|
||||
{
|
||||
ota_data_fs.remove("firmware.bin");
|
||||
}
|
||||
mbed::File file;
|
||||
file.open(&ota_data_fs, "firmware.bin", O_RDWR | O_CREAT | O_APPEND);
|
||||
|
||||
file.write(data, length);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//void ACSFileSystem::writeTest()
|
||||
//{
|
||||
// FILE *fd = fopen("/user/user.txt", "w+"); // Creates an empty file for both reading and writing.
|
||||
// //FILE *fd = fopen("/user/user.txt", (FA_WRITE | FA_CREATE_ALWAYS)); // Creates an empty file for both reading and writing.
|
||||
// fprintf(fd, "user parttion file");
|
||||
// if (!fd) {
|
||||
// Serial.print("file write error: ");
|
||||
// Serial.println(strerror(errno));
|
||||
// return;
|
||||
// if(ota)
|
||||
// {
|
||||
// return ota_data_fs.remove(filename);
|
||||
// }
|
||||
// Serial.println("file write oke");
|
||||
// fclose(fd);
|
||||
//}
|
||||
return user_data_fs.remove(filename);
|
||||
}
|
||||
|
||||
int ACSFileSystem::createDirectory(const char* path, mode_t mode, bool ota)
|
||||
{
|
||||
// if(ota)
|
||||
// {
|
||||
// return ota_data_fs.mkdir(path, mode);
|
||||
// }
|
||||
return user_data_fs.mkdir(path, mode);
|
||||
}
|
||||
|
||||
|
||||
void ACSFileSystem::listDirectory(char* name)
|
||||
{
|
||||
|
||||
@@ -5,33 +5,31 @@
|
||||
#include "mbed.h"
|
||||
#include <vector>
|
||||
|
||||
#define OTA_START 0
|
||||
#define OTA_SIZE 1024 * 1024 //1 MB
|
||||
#define USER_START OTA_SIZE
|
||||
#define USER_SIZE 15 * 1024 * 1024 //15 MB
|
||||
//#define LITTLE_START OTA_SIZE + USER_SIZE
|
||||
//#define LITTLE_SIZE 5 * 1024 * 1024 //5 MB
|
||||
#define USER_START 0
|
||||
#define USER_SIZE 5 * 1024 * 1024 //5 MB
|
||||
|
||||
#define OTA_START USER_SIZE
|
||||
#define OTA_SIZE 5 * 1024 * 1024 //5 MB
|
||||
|
||||
#define KV_START USER_SIZE + OTA_SIZE
|
||||
#define KV_SIZE 1 * 1024 * 1024
|
||||
|
||||
|
||||
class ACSFileSystem
|
||||
{
|
||||
public:
|
||||
//ACSFileSystem();
|
||||
static void begin();
|
||||
//static void process();
|
||||
static void erasePartitions();
|
||||
static void formatPartitions();
|
||||
static int openFile(const char* filename, mbed::File *file, int flags = 0);
|
||||
static int removeFile(const char* filename);
|
||||
|
||||
//void writeTest();
|
||||
static int openFile(const char* filename, mbed::File *file, int flags, bool ota = false);
|
||||
static int removeFile(const char* filename, bool ota = false);
|
||||
static int createDirectory(const char* path, mode_t mode, bool ota = false);
|
||||
|
||||
static void listDirectory(char* name);
|
||||
static std::vector<std::string> directoryList(char *name);
|
||||
|
||||
static void listPartitions();
|
||||
//void partition();
|
||||
|
||||
static void writeFirmware(char *data, size_t length, uint16_t block);
|
||||
static int openFirmwarefile(mbed::File *file);
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
1622
lib/ACSFileSystem/ACSQSPIFBlockDevice.cpp
Normal file
1622
lib/ACSFileSystem/ACSQSPIFBlockDevice.cpp
Normal file
File diff suppressed because it is too large
Load Diff
401
lib/ACSFileSystem/ACSQSPIFBlockDevice.h
Normal file
401
lib/ACSFileSystem/ACSQSPIFBlockDevice.h
Normal file
@@ -0,0 +1,401 @@
|
||||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2018 ARM Limited
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef ACS_QSPIF_BLOCK_DEVICE_H
|
||||
#define ACS_QSPIF_BLOCK_DEVICE_H
|
||||
|
||||
//#include "drivers/QSPI.h"
|
||||
#include "blockdevice/internal/SFDP.h"
|
||||
//#include "blockdevice/BlockDevice.h"
|
||||
//#include "platform/Callback.h"
|
||||
#include "mbed.h"
|
||||
|
||||
// #ifndef MBED_CONF_QSPIF_QSPI_IO0
|
||||
// #define MBED_CONF_QSPIF_QSPI_IO0 NC
|
||||
// #endif
|
||||
// #ifndef MBED_CONF_QSPIF_QSPI_IO1
|
||||
// #define MBED_CONF_QSPIF_QSPI_IO1 NC
|
||||
// #endif
|
||||
// #ifndef MBED_CONF_QSPIF_QSPI_IO2
|
||||
// #define MBED_CONF_QSPIF_QSPI_IO2 NC
|
||||
// #endif
|
||||
// #ifndef MBED_CONF_QSPIF_QSPI_IO3
|
||||
// #define MBED_CONF_QSPIF_QSPI_IO3 NC
|
||||
// #endif
|
||||
// #ifndef MBED_CONF_QSPIF_QSPI_SCK
|
||||
// #define MBED_CONF_QSPIF_QSPI_SCK NC
|
||||
// #endif
|
||||
// #ifndef MBED_CONF_QSPIF_QSPI_CSN
|
||||
// #define MBED_CONF_QSPIF_QSPI_CSN NC
|
||||
// #endif
|
||||
// #ifndef MBED_CONF_QSPIF_QSPI_POLARITY_MODE
|
||||
// #define MBED_CONF_QSPIF_QSPI_POLARITY_MODE 0
|
||||
// #endif
|
||||
// #ifndef MBED_CONF_QSPIF_QSPI_FREQ
|
||||
// #define MBED_CONF_QSPIF_QSPI_FREQ 40000000
|
||||
// #endif
|
||||
|
||||
/** Enum qspif standard error codes
|
||||
*
|
||||
* @enum qspif_bd_error
|
||||
*/
|
||||
enum qspif_bd_error {
|
||||
QSPIF_BD_ERROR_OK = 0, /*!< no error */
|
||||
QSPIF_BD_ERROR_DEVICE_ERROR = mbed::BD_ERROR_DEVICE_ERROR, /*!< device specific error -4001 */
|
||||
QSPIF_BD_ERROR_PARSING_FAILED = -4002, /* SFDP Parsing failed */
|
||||
QSPIF_BD_ERROR_READY_FAILED = -4003, /* Wait for Mem Ready failed */
|
||||
QSPIF_BD_ERROR_WREN_FAILED = -4004, /* Write Enable Failed */
|
||||
QSPIF_BD_ERROR_INVALID_ERASE_PARAMS = -4005, /* Erase command not on sector aligned addresses or exceeds device size */
|
||||
QSPIF_BD_ERROR_DEVICE_NOT_UNIQUE = -4006, /* Only one instance per csel is allowed */
|
||||
QSPIF_BD_ERROR_DEVICE_MAX_EXCEED = -4007 /* Max active QSPIF devices exceeded */
|
||||
};
|
||||
|
||||
/** Enum qspif polarity mode
|
||||
*
|
||||
* @enum qspif_polarity_mode
|
||||
*/
|
||||
enum qspif_polarity_mode {
|
||||
QSPIF_POLARITY_MODE_0 = 0, /* CPOL=0, CPHA=0 */
|
||||
QSPIF_POLARITY_MODE_1 /* CPOL=1, CPHA=1 */
|
||||
};
|
||||
|
||||
#define QSPIF_MAX_ACTIVE_FLASH_DEVICES 10
|
||||
|
||||
/** BlockDevice for SFDP based flash devices over QSPI bus
|
||||
*
|
||||
* @code
|
||||
* // Here's an example using QSPI flash device on DISCO_L476VG target
|
||||
* #include "mbed.h"
|
||||
* #include "QSPIFBlockDevice.h"
|
||||
*
|
||||
* QSPIFBlockDevice block_device(QSPI_FLASH1_IO0, QSPI_FLASH1_IO1, QSPI_FLASH1_IO2, QSPI_FLASH1_IO3,
|
||||
* QSPI_FLASH1_SCK, QSPI_FLASH1_CSN, QSPIF_POLARITY_MODE_0, MBED_CONF_QSPIF_QSPI_FREQ);
|
||||
*
|
||||
* int main()
|
||||
* {
|
||||
* printf("QSPI SFDP Flash Block Device example\n");
|
||||
*
|
||||
* // Initialize the SPI flash device and print the memory layout
|
||||
* block_device.init();
|
||||
* bd_size_t sector_size_at_address_0 = block_device.get_erase_size(0);
|
||||
*
|
||||
* printf("QSPIF BD size: %llu\n", block_device.size());
|
||||
* printf("QSPIF BD read size: %llu\n", block_device.get_read_size());
|
||||
* printf("QSPIF BD program size: %llu\n", block_device.get_program_size());
|
||||
* printf("QSPIF BD erase size (at address 0): %llu\n", sector_size_at_address_0);
|
||||
*
|
||||
* // Write "Hello World!" to the first block
|
||||
* char *buffer = (char *) malloc(sector_size_at_address_0);
|
||||
* sprintf(buffer, "Hello World!\n");
|
||||
* block_device.erase(0, sector_size_at_address_0);
|
||||
* block_device.program(buffer, 0, sector_size_at_address_0);
|
||||
*
|
||||
* // Read back what was stored
|
||||
* block_device.read(buffer, 0, sector_size_at_address_0);
|
||||
* printf("%s", buffer);
|
||||
*
|
||||
* // Deinitialize the device
|
||||
* block_device.deinit();
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
class ACSQSPIFBlockDevice : public mbed::BlockDevice {
|
||||
public:
|
||||
/** Create QSPIFBlockDevice - An SFDP based Flash Block Device over QSPI bus
|
||||
*
|
||||
* @param io0 1st IO pin used for sending/receiving data during data phase of a transaction
|
||||
* @param io1 2nd IO pin used for sending/receiving data during data phase of a transaction
|
||||
* @param io2 3rd IO pin used for sending/receiving data during data phase of a transaction
|
||||
* @param io3 4th IO pin used for sending/receiving data during data phase of a transaction
|
||||
* @param sclk QSPI Clock pin
|
||||
* @param csel QSPI chip select pin
|
||||
* @param clock_mode specifies the QSPI Clock Polarity mode (QSPIF_POLARITY_MODE_0/QSPIF_POLARITY_MODE_1)
|
||||
* default value = 0
|
||||
* @param freq Clock frequency of the QSPI bus (defaults to 40MHz)
|
||||
*/
|
||||
ACSQSPIFBlockDevice(PinName io0 = MBED_CONF_QSPIF_QSPI_IO0,
|
||||
PinName io1 = MBED_CONF_QSPIF_QSPI_IO1,
|
||||
PinName io2 = MBED_CONF_QSPIF_QSPI_IO2,
|
||||
PinName io3 = MBED_CONF_QSPIF_QSPI_IO3,
|
||||
PinName sclk = MBED_CONF_QSPIF_QSPI_SCK,
|
||||
PinName csel = MBED_CONF_QSPIF_QSPI_CSN,
|
||||
int clock_mode = MBED_CONF_QSPIF_QSPI_POLARITY_MODE,
|
||||
int freq = MBED_CONF_QSPIF_QSPI_FREQ);
|
||||
|
||||
/** Initialize a block device
|
||||
*
|
||||
* @return QSPIF_BD_ERROR_OK(0) - success
|
||||
* QSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
|
||||
* QSPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timedout
|
||||
* QSPIF_BD_ERROR_PARSING_FAILED - unexpected format or values in one of the SFDP tables
|
||||
*/
|
||||
virtual int init();
|
||||
|
||||
/** Deinitialize a block device
|
||||
*
|
||||
* @return QSPIF_BD_ERROR_OK(0) - success
|
||||
* QSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
|
||||
*/
|
||||
virtual int deinit();
|
||||
|
||||
/** Desctruct QSPIFBlockDevie
|
||||
*/
|
||||
~ACSQSPIFBlockDevice()
|
||||
{
|
||||
deinit();
|
||||
}
|
||||
|
||||
/** Read blocks from a block device
|
||||
*
|
||||
* @param buffer Buffer to write blocks to
|
||||
* @param addr Address of block to begin reading from
|
||||
* @param size Size to read in bytes, must be a multiple of read block size
|
||||
* @return QSPIF_BD_ERROR_OK(0) - success
|
||||
* QSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
|
||||
*/
|
||||
virtual int read(void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size);
|
||||
|
||||
/** Program blocks to a block device
|
||||
*
|
||||
* The blocks must have been erased prior to being programmed
|
||||
*
|
||||
* @param buffer Buffer of data to write to blocks
|
||||
* @param addr Address of block to begin writing to
|
||||
* @param size Size to write in bytes, must be a multiple of program block size
|
||||
* @return QSPIF_BD_ERROR_OK(0) - success
|
||||
* QSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
|
||||
* QSPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timed out
|
||||
* QSPIF_BD_ERROR_WREN_FAILED - Write Enable failed
|
||||
* QSPIF_BD_ERROR_PARSING_FAILED - unexpected format or values in one of the SFDP tables
|
||||
*/
|
||||
virtual int program(const void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size);
|
||||
|
||||
/** Erase blocks on a block device
|
||||
*
|
||||
* The state of an erased block is undefined until it has been programmed
|
||||
*
|
||||
* @param addr Address of block to begin erasing
|
||||
* @param size Size to erase in bytes, must be a multiple of erase block size
|
||||
* @return QSPIF_BD_ERROR_OK(0) - success
|
||||
* QSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
|
||||
* QSPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timed out
|
||||
* QSPIF_BD_ERROR_WREN_FAILED - Write Enable failed
|
||||
* QSPIF_BD_ERROR_PARSING_FAILED - unexpected format or values in one of the SFDP tables
|
||||
* QSPIF_BD_ERROR_INVALID_ERASE_PARAMS - Trying to erase unaligned address or size
|
||||
*/
|
||||
virtual int erase(mbed::bd_addr_t addr, mbed::bd_size_t size);
|
||||
|
||||
/** Get the size of a readable block
|
||||
*
|
||||
* @return Size of a readable block in bytes
|
||||
*/
|
||||
virtual mbed::bd_size_t get_read_size() const;
|
||||
|
||||
/** Get the size of a programable block
|
||||
*
|
||||
* @return Size of a program block size in bytes
|
||||
* @note Must be a multiple of the read size
|
||||
*/
|
||||
virtual mbed::bd_size_t get_program_size() const;
|
||||
|
||||
/** Get the size of a eraseable block
|
||||
*
|
||||
* @return Size of a minimal erase block, common to all regions, in bytes
|
||||
* @note Must be a multiple of the program size
|
||||
*/
|
||||
virtual mbed::bd_size_t get_erase_size() const;
|
||||
|
||||
/** Get the size of minimal eraseable sector size of given address
|
||||
*
|
||||
* @param addr Any address within block queried for erase sector size (can be any address within flash size offset)
|
||||
* @return Size of minimal erase sector size, in given address region, in bytes
|
||||
* @note Must be a multiple of the program size
|
||||
*/
|
||||
virtual mbed::bd_size_t get_erase_size(mbed::bd_addr_t addr) const;
|
||||
|
||||
/** Get the value of storage byte after it was erased
|
||||
*
|
||||
* If get_erase_value returns a non-negative byte value, the underlying
|
||||
* storage is set to that value when erased, and storage containing
|
||||
* that value can be programmed without another erase.
|
||||
*
|
||||
* @return The value of storage when erased, or -1 if you can't
|
||||
* rely on the value of erased storage
|
||||
*/
|
||||
virtual int get_erase_value() const;
|
||||
|
||||
/** Get the total size of the underlying device
|
||||
*
|
||||
* @return Size of the underlying device in bytes
|
||||
*/
|
||||
virtual mbed::bd_size_t size() const;
|
||||
|
||||
/** Get the BlockDevice class type.
|
||||
*
|
||||
* @return A string represent the BlockDevice class type.
|
||||
*/
|
||||
virtual const char *get_type() const;
|
||||
|
||||
private:
|
||||
/********************************/
|
||||
/* Different Device Csel Mgmt */
|
||||
/********************************/
|
||||
// Add a new QSPI device CS to existing devices list.
|
||||
// Only one QSPIFBlockDevice instance per CS is allowed
|
||||
int add_new_csel_instance(PinName csel);
|
||||
|
||||
// Remove device CS from existing device list upon destroying object (last deinit is called)
|
||||
int remove_csel_instance(PinName csel);
|
||||
|
||||
/********************************/
|
||||
/* Calls to QSPI Driver APIs */
|
||||
/********************************/
|
||||
// Send Program/Write command to Driver
|
||||
qspi_status_t _qspi_send_program_command(mbed::qspi_inst_t prog_instruction, const void *buffer,
|
||||
mbed::bd_addr_t addr, mbed::bd_size_t *size);
|
||||
|
||||
// Send Read command to Driver
|
||||
qspi_status_t _qspi_send_read_command(mbed::qspi_inst_t read_instruction, void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size);
|
||||
|
||||
// Send Erase Instruction using command_transfer command to Driver
|
||||
qspi_status_t _qspi_send_erase_command(mbed::qspi_inst_t erase_instruction, mbed::bd_addr_t addr, mbed::bd_size_t size);
|
||||
|
||||
// Send Generic command_transfer command to Driver
|
||||
qspi_status_t _qspi_send_general_command(mbed::qspi_inst_t instruction_int, mbed::bd_addr_t addr, const char *tx_buffer,
|
||||
mbed::bd_size_t tx_length, const char *rx_buffer, mbed::bd_size_t rx_length);
|
||||
|
||||
// Send command to read from the SFDP table
|
||||
int _qspi_send_read_sfdp_command(mbed::bd_addr_t addr, mbed::sfdp_cmd_addr_size_t addr_size,
|
||||
uint8_t inst, uint8_t dummy_cycles,
|
||||
void *rx_buffer, mbed::bd_size_t rx_length);
|
||||
|
||||
// Read the contents of status registers 1 and 2 into a buffer (buffer must have a length of 2)
|
||||
qspi_status_t _qspi_read_status_registers(uint8_t *reg_buffer);
|
||||
|
||||
// Set the contents of status registers 1 and 2 from a buffer (buffer must have a length of 2)
|
||||
qspi_status_t _qspi_write_status_registers(uint8_t *reg_buffer);
|
||||
|
||||
// Send set_frequency command to Driver
|
||||
qspi_status_t _qspi_set_frequency(int freq);
|
||||
|
||||
// Update the 4-byte addressing extension register with the MSB of the address if it is in use
|
||||
qspi_status_t _qspi_update_4byte_ext_addr_reg(mbed::bd_addr_t addr);
|
||||
|
||||
/*********************************/
|
||||
/* Flash Configuration Functions */
|
||||
/*********************************/
|
||||
// Clear the device's block protection
|
||||
int _clear_block_protection();
|
||||
|
||||
// Configure Write Enable in Status Register
|
||||
int _set_write_enable();
|
||||
|
||||
// Wait on status register until write not-in-progress
|
||||
bool _is_mem_ready();
|
||||
|
||||
// Enable Fast Mode - for flash chips with low power default
|
||||
int _enable_fast_mode();
|
||||
|
||||
// Query vendor ID and handle special behavior that isn't covered by SFDP data
|
||||
int _handle_vendor_quirks();
|
||||
|
||||
/****************************************/
|
||||
/* SFDP Detection and Parsing Functions */
|
||||
/****************************************/
|
||||
// Parse and Detect required Basic Parameters from Table
|
||||
int _sfdp_parse_basic_param_table(mbed::Callback<int(mbed::bd_addr_t, mbed::sfdp_cmd_addr_size_t, uint8_t, uint8_t, void *, mbed::bd_size_t)> sfdp_reader,
|
||||
mbed::sfdp_hdr_info &sfdp_info);
|
||||
|
||||
// Detect the soft reset protocol and reset - returns error if soft reset is not supported
|
||||
int _sfdp_detect_reset_protocol_and_reset(uint8_t *basic_param_table_ptr);
|
||||
|
||||
// Detect fastest read Bus mode supported by device
|
||||
int _sfdp_detect_best_bus_read_mode(uint8_t *basic_param_table_ptr, int basic_param_table_size,
|
||||
bool &set_quad_enable, bool &is_qpi_mode);
|
||||
|
||||
// Enable Quad mode if supported (1-1-4, 1-4-4, 4-4-4 bus modes)
|
||||
int _sfdp_set_quad_enabled(uint8_t *basic_param_table_ptr);
|
||||
|
||||
// Enable QPI mode (4-4-4)
|
||||
int _sfdp_set_qpi_enabled(uint8_t *basic_param_table_ptr);
|
||||
|
||||
// Detect 4-byte addressing mode and enable it if supported
|
||||
int _sfdp_detect_and_enable_4byte_addressing(uint8_t *basic_param_table_ptr, int basic_param_table_size);
|
||||
|
||||
private:
|
||||
enum qspif_clear_protection_method_t {
|
||||
QSPIF_BP_ULBPR, // Issue global protection unlock instruction
|
||||
QSPIF_BP_CLEAR_SR, // Clear protection bits in status register 1
|
||||
};
|
||||
|
||||
// QSPI Driver Object
|
||||
mbed::QSPI _qspi;
|
||||
|
||||
// Number of active OSPIFBlockDevice chip select pins
|
||||
static int _number_of_active_qspif_flash_csel;
|
||||
|
||||
int _unique_device_status;
|
||||
PinName _csel;
|
||||
|
||||
// Mutex is used to protect Flash device for some QSPI Driver commands that must be done sequentially with no other commands in between
|
||||
// e.g. (1)Set Write Enable, (2)Program, (3)Wait Memory Ready
|
||||
rtos::Mutex _mutex;
|
||||
|
||||
// Command Instructions
|
||||
mbed::qspi_inst_t _read_instruction;
|
||||
|
||||
// Status register write/read instructions
|
||||
unsigned int _num_status_registers;
|
||||
mbed::qspi_inst_t _write_status_reg_2_inst;
|
||||
mbed::qspi_inst_t _read_status_reg_2_inst; // If three registers, this instruction reads the latter two
|
||||
|
||||
// Attempt to enable 4-byte addressing. True by default, but may be disabled for some vendors
|
||||
bool _attempt_4_byte_addressing;
|
||||
// 4-byte addressing extension register write instruction
|
||||
mbed::qspi_inst_t _4byte_msb_reg_write_inst;
|
||||
|
||||
// Quad mode enable status register and bit
|
||||
int _quad_enable_register_idx;
|
||||
int _quad_enable_bit;
|
||||
|
||||
bool _needs_fast_mode;
|
||||
|
||||
// S25FS512S needs a quirk
|
||||
bool _S25FS512S_quirk;
|
||||
|
||||
// Clear block protection
|
||||
qspif_clear_protection_method_t _clear_protection_method;
|
||||
|
||||
// Data extracted from the devices SFDP structure
|
||||
mbed::sfdp_hdr_info _sfdp_info;
|
||||
|
||||
unsigned int _page_size_bytes; // Page size - 256 Bytes default
|
||||
int _freq;
|
||||
|
||||
// Bus speed configuration
|
||||
qspi_bus_width_t _inst_width; //Bus width for Instruction phase
|
||||
qspi_bus_width_t _address_width; //Bus width for Address phase
|
||||
qspi_address_size_t _address_size; //Number of bits for address
|
||||
qspi_alt_size_t _alt_size; //Number of bits for alt
|
||||
bool _alt_enabled; //Whether alt is enabled
|
||||
uint8_t _dummy_cycles; //Number of Dummy cycles required by Current Bus Mode
|
||||
qspi_bus_width_t _data_width; //Bus width for Data phase
|
||||
|
||||
uint32_t _init_ref_count;
|
||||
bool _is_initialized;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -74,18 +74,16 @@ enum Status : uint8_t
|
||||
};
|
||||
|
||||
ACSUSBMSD::ACSUSBMSD(mbed::BlockDevice *bd, bool connect_blocking, uint16_t vendor_id, uint16_t product_id, uint16_t product_release)
|
||||
: arduino::internal::PluggableUSBModule(1), _in_task(&_queue), _out_task(&_queue),
|
||||
_initialized(false), _media_removed(false), _bd(bd)
|
||||
: arduino::internal::PluggableUSBModule(1), _in_task(&_queue), _out_task(&_queue), _initialized(false), _media_removed(false), _bd(bd)
|
||||
{
|
||||
PluggableUSBD().plug(this);
|
||||
}
|
||||
|
||||
ACSUSBMSD::ACSUSBMSD(USBPhy *phy, mbed::BlockDevice *bd, uint16_t vendor_id, uint16_t product_id, uint16_t product_release)
|
||||
: arduino::internal::PluggableUSBModule(1), _in_task(&_queue), _out_task(&_queue),
|
||||
_initialized(false), _media_removed(false), _bd(bd)
|
||||
{
|
||||
PluggableUSBD().plug(this);
|
||||
}
|
||||
// ACSUSBMSD::ACSUSBMSD(USBPhy *phy, mbed::BlockDevice *bd, uint16_t vendor_id, uint16_t product_id, uint16_t product_release)
|
||||
// : arduino::internal::PluggableUSBModule(1), _in_task(&_queue), _out_task(&_queue), _initialized(false), _media_removed(false), _bd(bd)
|
||||
// {
|
||||
// PluggableUSBD().plug(this);
|
||||
// }
|
||||
|
||||
static rtos::Thread _usbmsdThread(osPriorityNormal, 2 * 1024, NULL, "ACS_usbmsd");
|
||||
|
||||
@@ -222,12 +220,19 @@ int ACSUSBMSD::disk_write(const uint8_t *data, uint64_t block, uint8_t count)
|
||||
// this operation must be executed in another thread
|
||||
mbed::bd_addr_t addr = block * _bd->get_erase_size();
|
||||
mbed::bd_size_t size = count * _bd->get_erase_size();
|
||||
|
||||
int ret = _bd->erase(addr, size);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = _bd->program(data, addr, size);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
return _bd->sync();
|
||||
|
||||
return _bd->program(data, addr, size);
|
||||
///return _bd->program(data, addr, size);
|
||||
}
|
||||
|
||||
int ACSUSBMSD::disk_initialize()
|
||||
|
||||
@@ -103,7 +103,7 @@ public:
|
||||
* @param product_id Your product_id
|
||||
* @param product_release Your preoduct_release
|
||||
*/
|
||||
ACSUSBMSD(USBPhy *phy, mbed::BlockDevice *bd, uint16_t vendor_id, uint16_t product_id, uint16_t product_release);
|
||||
//ACSUSBMSD(USBPhy *phy, mbed::BlockDevice *bd, uint16_t vendor_id, uint16_t product_id, uint16_t product_release);
|
||||
|
||||
/**
|
||||
* Destroy this object
|
||||
|
||||
303
lib/TFTPServer/MD5.cpp
Normal file
303
lib/TFTPServer/MD5.cpp
Normal file
@@ -0,0 +1,303 @@
|
||||
#include "MD5.h"
|
||||
|
||||
// MD5::MD5()
|
||||
// {
|
||||
// //nothing
|
||||
// return;
|
||||
// }
|
||||
|
||||
char* MD5::make_digest(const unsigned char *digest, int len) /* {{{ */
|
||||
{
|
||||
char * md5str = (char*) malloc(sizeof(char)*(len*2+1));
|
||||
static const char hexits[17] = "0123456789abcdef";
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
md5str[i * 2] = hexits[digest[i] >> 4];
|
||||
md5str[(i * 2) + 1] = hexits[digest[i] & 0x0F];
|
||||
}
|
||||
md5str[len * 2] = '\0';
|
||||
return md5str;
|
||||
}
|
||||
|
||||
/*
|
||||
* The basic MD5 functions.
|
||||
*
|
||||
* E and G are optimized compared to their RFC 1321 definitions for
|
||||
* architectures that lack an AND-NOT instruction, just like in Colin Plumb's
|
||||
* implementation.
|
||||
* E() has been used instead of F() because F() is already defined in the Arduino core
|
||||
*/
|
||||
#define E(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
|
||||
#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
|
||||
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
||||
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
|
||||
|
||||
/*
|
||||
* The MD5 transformation for all four rounds.
|
||||
*/
|
||||
#define STEP(f, a, b, c, d, x, t, s) \
|
||||
(a) += f((b), (c), (d)) + (x) + (t); \
|
||||
(a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
|
||||
(a) += (b);
|
||||
|
||||
/*
|
||||
* SET reads 4 input bytes in little-endian byte order and stores them
|
||||
* in a properly aligned word in host byte order.
|
||||
*
|
||||
* The check for little-endian architectures that tolerate unaligned
|
||||
* memory accesses is just an optimization. Nothing will break if it
|
||||
* doesn't work.
|
||||
*/
|
||||
#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
|
||||
# define SET(n) \
|
||||
(*(MD5_u32plus *)&ptr[(n) * 4])
|
||||
# define GET(n) \
|
||||
SET(n)
|
||||
#else
|
||||
# define SET(n) \
|
||||
(ctx->block[(n)] = \
|
||||
(MD5_u32plus)ptr[(n) * 4] | \
|
||||
((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \
|
||||
((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
|
||||
((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
|
||||
# define GET(n) \
|
||||
(ctx->block[(n)])
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This processes one or more 64-byte data blocks, but does NOT update
|
||||
* the bit counters. There are no alignment requirements.
|
||||
*/
|
||||
const void *MD5::body(void *ctxBuf, const void *data, size_t size)
|
||||
{
|
||||
MD5_CTX *ctx = (MD5_CTX*)ctxBuf;
|
||||
const unsigned char *ptr;
|
||||
MD5_u32plus a, b, c, d;
|
||||
MD5_u32plus saved_a, saved_b, saved_c, saved_d;
|
||||
|
||||
ptr = (unsigned char*)data;
|
||||
|
||||
a = ctx->a;
|
||||
b = ctx->b;
|
||||
c = ctx->c;
|
||||
d = ctx->d;
|
||||
|
||||
do {
|
||||
saved_a = a;
|
||||
saved_b = b;
|
||||
saved_c = c;
|
||||
saved_d = d;
|
||||
|
||||
/* Round 1
|
||||
* E() has been used instead of F() because F() is already defined in the Arduino core
|
||||
*/
|
||||
STEP(E, a, b, c, d, SET(0), 0xd76aa478, 7)
|
||||
STEP(E, d, a, b, c, SET(1), 0xe8c7b756, 12)
|
||||
STEP(E, c, d, a, b, SET(2), 0x242070db, 17)
|
||||
STEP(E, b, c, d, a, SET(3), 0xc1bdceee, 22)
|
||||
STEP(E, a, b, c, d, SET(4), 0xf57c0faf, 7)
|
||||
STEP(E, d, a, b, c, SET(5), 0x4787c62a, 12)
|
||||
STEP(E, c, d, a, b, SET(6), 0xa8304613, 17)
|
||||
STEP(E, b, c, d, a, SET(7), 0xfd469501, 22)
|
||||
STEP(E, a, b, c, d, SET(8), 0x698098d8, 7)
|
||||
STEP(E, d, a, b, c, SET(9), 0x8b44f7af, 12)
|
||||
STEP(E, c, d, a, b, SET(10), 0xffff5bb1, 17)
|
||||
STEP(E, b, c, d, a, SET(11), 0x895cd7be, 22)
|
||||
STEP(E, a, b, c, d, SET(12), 0x6b901122, 7)
|
||||
STEP(E, d, a, b, c, SET(13), 0xfd987193, 12)
|
||||
STEP(E, c, d, a, b, SET(14), 0xa679438e, 17)
|
||||
STEP(E, b, c, d, a, SET(15), 0x49b40821, 22)
|
||||
|
||||
/* Round 2 */
|
||||
STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
|
||||
STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
|
||||
STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
|
||||
STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
|
||||
STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
|
||||
STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
|
||||
STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
|
||||
STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
|
||||
STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
|
||||
STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
|
||||
STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
|
||||
STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
|
||||
STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
|
||||
STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
|
||||
STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
|
||||
STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
|
||||
|
||||
/* Round 3 */
|
||||
STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
|
||||
STEP(H, d, a, b, c, GET(8), 0x8771f681, 11)
|
||||
STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
|
||||
STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23)
|
||||
STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
|
||||
STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11)
|
||||
STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
|
||||
STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23)
|
||||
STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
|
||||
STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11)
|
||||
STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
|
||||
STEP(H, b, c, d, a, GET(6), 0x04881d05, 23)
|
||||
STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
|
||||
STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11)
|
||||
STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
|
||||
STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23)
|
||||
|
||||
/* Round 4 */
|
||||
STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
|
||||
STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
|
||||
STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
|
||||
STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
|
||||
STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
|
||||
STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
|
||||
STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
|
||||
STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
|
||||
STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
|
||||
STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
|
||||
STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
|
||||
STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
|
||||
STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
|
||||
STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
|
||||
STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
|
||||
STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
|
||||
|
||||
a += saved_a;
|
||||
b += saved_b;
|
||||
c += saved_c;
|
||||
d += saved_d;
|
||||
|
||||
ptr += 64;
|
||||
} while (size -= 64);
|
||||
|
||||
ctx->a = a;
|
||||
ctx->b = b;
|
||||
ctx->c = c;
|
||||
ctx->d = d;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void MD5::MD5Init(void *ctxBuf)
|
||||
{
|
||||
MD5_CTX *ctx = (MD5_CTX*)ctxBuf;
|
||||
ctx->a = 0x67452301;
|
||||
ctx->b = 0xefcdab89;
|
||||
ctx->c = 0x98badcfe;
|
||||
ctx->d = 0x10325476;
|
||||
|
||||
ctx->lo = 0;
|
||||
ctx->hi = 0;
|
||||
|
||||
memset(ctx->block, 0, sizeof(ctx->block));
|
||||
memset(ctx->buffer, 0, sizeof(ctx->buffer));
|
||||
}
|
||||
|
||||
void MD5::MD5Update(void *ctxBuf, const void *data, size_t size)
|
||||
{
|
||||
MD5_CTX *ctx = (MD5_CTX*)ctxBuf;
|
||||
MD5_u32plus saved_lo;
|
||||
MD5_u32plus used, free;
|
||||
|
||||
saved_lo = ctx->lo;
|
||||
if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo) {
|
||||
ctx->hi++;
|
||||
}
|
||||
ctx->hi += size >> 29;
|
||||
|
||||
used = saved_lo & 0x3f;
|
||||
|
||||
if (used) {
|
||||
free = 64 - used;
|
||||
|
||||
if (size < free) {
|
||||
memcpy(&ctx->buffer[used], data, size);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&ctx->buffer[used], data, free);
|
||||
data = (unsigned char *)data + free;
|
||||
size -= free;
|
||||
body(ctx, ctx->buffer, 64);
|
||||
}
|
||||
|
||||
if (size >= 64) {
|
||||
data = body(ctx, data, size & ~(size_t)0x3f);
|
||||
size &= 0x3f;
|
||||
}
|
||||
|
||||
memcpy(ctx->buffer, data, size);
|
||||
}
|
||||
|
||||
void MD5::MD5Final(unsigned char *result, void *ctxBuf)
|
||||
{
|
||||
MD5_CTX *ctx = (MD5_CTX*)ctxBuf;
|
||||
MD5_u32plus used, free;
|
||||
|
||||
used = ctx->lo & 0x3f;
|
||||
|
||||
ctx->buffer[used++] = 0x80;
|
||||
|
||||
free = 64 - used;
|
||||
|
||||
if (free < 8) {
|
||||
memset(&ctx->buffer[used], 0, free);
|
||||
body(ctx, ctx->buffer, 64);
|
||||
used = 0;
|
||||
free = 64;
|
||||
}
|
||||
|
||||
memset(&ctx->buffer[used], 0, free - 8);
|
||||
|
||||
ctx->lo <<= 3;
|
||||
ctx->buffer[56] = ctx->lo;
|
||||
ctx->buffer[57] = ctx->lo >> 8;
|
||||
ctx->buffer[58] = ctx->lo >> 16;
|
||||
ctx->buffer[59] = ctx->lo >> 24;
|
||||
ctx->buffer[60] = ctx->hi;
|
||||
ctx->buffer[61] = ctx->hi >> 8;
|
||||
ctx->buffer[62] = ctx->hi >> 16;
|
||||
ctx->buffer[63] = ctx->hi >> 24;
|
||||
|
||||
body(ctx, ctx->buffer, 64);
|
||||
|
||||
result[0] = ctx->a;
|
||||
result[1] = ctx->a >> 8;
|
||||
result[2] = ctx->a >> 16;
|
||||
result[3] = ctx->a >> 24;
|
||||
result[4] = ctx->b;
|
||||
result[5] = ctx->b >> 8;
|
||||
result[6] = ctx->b >> 16;
|
||||
result[7] = ctx->b >> 24;
|
||||
result[8] = ctx->c;
|
||||
result[9] = ctx->c >> 8;
|
||||
result[10] = ctx->c >> 16;
|
||||
result[11] = ctx->c >> 24;
|
||||
result[12] = ctx->d;
|
||||
result[13] = ctx->d >> 8;
|
||||
result[14] = ctx->d >> 16;
|
||||
result[15] = ctx->d >> 24;
|
||||
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
}
|
||||
|
||||
// unsigned char* MD5::make_hash(char *arg)
|
||||
// {
|
||||
// MD5_CTX context;
|
||||
// unsigned char * hash = (unsigned char *) malloc(16);
|
||||
// MD5Init(&context);
|
||||
// MD5Update(&context, arg, strlen(arg));
|
||||
// MD5Final(hash, &context);
|
||||
// return hash;
|
||||
// }
|
||||
// unsigned char* MD5::make_hash(char *arg,size_t size)
|
||||
// {
|
||||
// MD5_CTX context;
|
||||
// unsigned char * hash = (unsigned char *) malloc(16);
|
||||
// MD5Init(&context);
|
||||
// MD5Update(&context, arg, size);
|
||||
// MD5Final(hash, &context);
|
||||
// return hash;
|
||||
// }
|
||||
|
||||
56
lib/TFTPServer/MD5.h
Normal file
56
lib/TFTPServer/MD5.h
Normal file
@@ -0,0 +1,56 @@
|
||||
#ifndef MD5_h
|
||||
#define MD5_h
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
/*
|
||||
* This is an OpenSSL-compatible implementation of the RSA Data Security,
|
||||
* Inc. MD5 Message-Digest Algorithm (RFC 1321).
|
||||
*
|
||||
* Written by Solar Designer <solar at openwall.com> in 2001, and placed
|
||||
* in the public domain. There's absolutely no warranty.
|
||||
*
|
||||
* This differs from Colin Plumb's older public domain implementation in
|
||||
* that no 32-bit integer data type is required, there's no compile-time
|
||||
* endianness configuration, and the function prototypes match OpenSSL's.
|
||||
* The primary goals are portability and ease of use.
|
||||
*
|
||||
* This implementation is meant to be fast, but not as fast as possible.
|
||||
* Some known optimizations are not included to reduce source code size
|
||||
* and avoid compile-time configuration.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Updated by Scott MacVicar for arduino
|
||||
* <scott@macvicar.net>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
typedef unsigned long MD5_u32plus;
|
||||
|
||||
typedef struct {
|
||||
MD5_u32plus lo, hi;
|
||||
MD5_u32plus a, b, c, d;
|
||||
unsigned char buffer[64];
|
||||
MD5_u32plus block[16];
|
||||
} MD5_CTX;
|
||||
|
||||
class MD5
|
||||
{
|
||||
public:
|
||||
//MD5();
|
||||
//static unsigned char* make_hash(char *arg);
|
||||
//static unsigned char* make_hash(char *arg,size_t size);
|
||||
//static char* make_digest(const unsigned char *digest, int len);
|
||||
//static const void *body(void *ctxBuf, const void *data, size_t size);
|
||||
|
||||
static void MD5Init(void *ctxBuf);
|
||||
static void MD5Final(unsigned char *result, void *ctxBuf);
|
||||
static void MD5Update(void *ctxBuf, const void *data, size_t size);
|
||||
private:
|
||||
static char* make_digest(const unsigned char *digest, int len);
|
||||
static const void *body(void *ctxBuf, const void *data, size_t size);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -2,123 +2,79 @@
|
||||
#include "TFTPClient.h"
|
||||
#include <iterator>
|
||||
#include "ACSFileSystem.h"
|
||||
//#include <stdint.h>
|
||||
//#include <array>
|
||||
//#include <vector>
|
||||
//#include <functional>
|
||||
//#include <memory>
|
||||
//#define TFTP_DEBUG
|
||||
#include "MD5.h"
|
||||
#include "microtar.h"
|
||||
#include "untar.h"
|
||||
|
||||
/**
|
||||
* @brief Creates a new TFTP server listening on myPort.
|
||||
* @note
|
||||
* @param net A pointer to NetworkInterface object.
|
||||
* @param port A port to listen on (defaults to 69).
|
||||
* @retval
|
||||
*/
|
||||
TFTPClient::TFTPClient()
|
||||
{
|
||||
// #ifdef TFTP_DEBUG
|
||||
// printf("TFTPServer(): port=%d\r\n", myPort);
|
||||
// #endif
|
||||
// Serial.println("Create socket");
|
||||
// _socket = new UDPSocket();
|
||||
// _socket->open(net);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Destroys this instance of the TFTP server.
|
||||
* @note
|
||||
* @param
|
||||
* @retval
|
||||
*/
|
||||
TFTPClient::~TFTPClient()
|
||||
{
|
||||
//_socket->close();
|
||||
//delete(_socket);
|
||||
//strcpy(_remoteIP, "");
|
||||
//_state = DELETED;
|
||||
}
|
||||
UDPSocket TFTPClient::_socket;
|
||||
|
||||
//uint16_t currentBlock = 0;
|
||||
|
||||
void TFTPClient::connect(const char *host, uint16_t port /* = 69 */, std::string filename)
|
||||
bool TFTPClient::connect(const char *host, uint16_t port /* = 69 */)
|
||||
{
|
||||
Serial.println("Connect");
|
||||
|
||||
Serial.println("Create socket");
|
||||
UDPSocket socket;// = new UDPSocket();
|
||||
//socket.open(NetworkInterface::get_default_instance());
|
||||
if (socket.open(NetworkInterface::get_default_instance()) != NSAPI_ERROR_OK) {
|
||||
if (_socket.open(NetworkInterface::get_default_instance()) != NSAPI_ERROR_OK) {
|
||||
Serial.println("open error");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
Serial.println("resolve");
|
||||
SocketAddress sockAddr;
|
||||
sockAddr.set_port(port);
|
||||
if (NetworkInterface::get_default_instance()->gethostbyname(host, &sockAddr) != NSAPI_ERROR_OK) {
|
||||
Serial.println("Resolve error");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
socket.set_blocking(true);
|
||||
//_fileCounter = 0;
|
||||
|
||||
Serial.println("Connect");
|
||||
if (socket.connect(sockAddr) != NSAPI_ERROR_OK) {
|
||||
_socket.set_blocking(true);
|
||||
if (_socket.connect(sockAddr) != NSAPI_ERROR_OK) {
|
||||
Serial.println("Connect error");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
Serial.println("Connect done");
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<char> buffer;
|
||||
buffer.push_back(0x00);
|
||||
buffer.push_back(static_cast<char>(opcode::ReadRequest));
|
||||
buffer.insert(buffer.end(), filename.begin(), filename.end());
|
||||
buffer.push_back(0x00);
|
||||
std::string octet = "octet";
|
||||
buffer.insert(buffer.end(), octet.begin(), octet.end());
|
||||
buffer.push_back(0x00);
|
||||
socket.sendto(sockAddr, buffer.data(), buffer.size());
|
||||
void TFTPClient::close()
|
||||
{
|
||||
Serial.println("Close Request");
|
||||
sendCommand(opCode::CloseRequest);
|
||||
_socket.close();
|
||||
}
|
||||
|
||||
Serial.println("recieve socket");
|
||||
socket.set_blocking(true);
|
||||
socket.set_timeout(5000);
|
||||
bool TFTPClient::receiveFirmware()
|
||||
{
|
||||
Serial.println("receive");
|
||||
|
||||
if(!sendCommand(opCode::ReadRequest))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
_socket.set_blocking(true);
|
||||
_socket.set_timeout(5000);
|
||||
|
||||
ACSFileSystem::removeFile("firmware.tar", true);
|
||||
mbed::File firmwareFile;
|
||||
if(ACSFileSystem::openFirmwarefile(&firmwareFile) != 0)
|
||||
if(ACSFileSystem::openFile("firmware.tar", &firmwareFile, O_RDWR | O_CREAT | O_APPEND, true) != 0)
|
||||
{
|
||||
Serial.println("file error");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
char buff[516];
|
||||
int len = socket.recv(buff, sizeof(buff));
|
||||
Serial.println(len);
|
||||
int len = _socket.recv(buff, sizeof(buff));
|
||||
|
||||
//Serial.println(len);
|
||||
|
||||
if(len <= 0)
|
||||
break;
|
||||
|
||||
if(buff[1] == 0x03)
|
||||
if(buff[1] == static_cast<char>(opCode::Data))
|
||||
{
|
||||
//Serial.println("data packet");
|
||||
uint16_t block = (buff[2] << 8) + buff[3];
|
||||
|
||||
Serial.print("block: ");
|
||||
Serial.println(block);
|
||||
///Serial.print("block: ");
|
||||
//Serial.println(block);
|
||||
|
||||
firmwareFile.write(&buff[4], len -4);
|
||||
|
||||
//send ack
|
||||
std::vector<char> buffer;
|
||||
buffer.push_back(0x00);
|
||||
buffer.push_back(static_cast<char>(opcode::Acknowledgment));
|
||||
buffer.push_back(block >> 8);
|
||||
buffer.push_back(block & 255);
|
||||
socket.sendto(sockAddr, buffer.data(), buffer.size());
|
||||
ack(block);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -126,584 +82,250 @@ void TFTPClient::connect(const char *host, uint16_t port /* = 69 */, std::string
|
||||
}
|
||||
}
|
||||
firmwareFile.close();
|
||||
socket.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
void TFTPClient::ack(uint16_t val)
|
||||
{
|
||||
std::vector<char> buffer;
|
||||
buffer.push_back(0x00);
|
||||
buffer.push_back(static_cast<char>(opCode::Acknowledgment));
|
||||
buffer.push_back(val >> 8);
|
||||
buffer.push_back(val & 255);
|
||||
_socket.send(buffer.data(), buffer.size());
|
||||
}
|
||||
|
||||
bool TFTPClient::sendCommand(opCode opcode)
|
||||
{
|
||||
std::vector<char> buffer;
|
||||
buffer.push_back(0x00);
|
||||
buffer.push_back(static_cast<char>(opcode));
|
||||
if(_socket.send(buffer.data(), buffer.size()) <= 0)
|
||||
{
|
||||
Serial.println("data send error");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void TFTPClient::sendRemaining(size_t remaining)
|
||||
{
|
||||
Serial.print("Remaining: ");
|
||||
Serial.println(remaining);
|
||||
|
||||
std::vector<char> buffer;
|
||||
buffer.push_back(0x00);
|
||||
buffer.push_back(static_cast<char>(opCode::Remaining));
|
||||
buffer.push_back(remaining >> 8);
|
||||
buffer.push_back(remaining & 255);
|
||||
|
||||
if(_socket.send(buffer.data(), buffer.size()) <= 0)
|
||||
{
|
||||
Serial.println("data send error");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool TFTPClient::checkCRC()
|
||||
{
|
||||
Serial.println("checkCRC");
|
||||
|
||||
if(!sendCommand(opCode::CRCRequest))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<byte> serverHash(18);
|
||||
nsapi_size_or_error_t result = _socket.recv(serverHash.data(), serverHash.size());
|
||||
|
||||
//Serial.print("recv result: ");
|
||||
//Serial.println(result);
|
||||
|
||||
if(result > 0)
|
||||
{
|
||||
Serial.println("Server hash");
|
||||
for (size_t i = 2; i < result; i++)
|
||||
{
|
||||
Serial.print(serverHash[i], HEX);
|
||||
Serial.print("-");
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
if(result != 18)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(serverHash[1] != static_cast<char>(opCode::CRCResponse))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//Serial.println("Calc crc");
|
||||
|
||||
mbed::File diskfile;
|
||||
if (ACSFileSystem::openFile("firmware.tar", &diskfile, O_RDONLY, true) != MBED_SUCCESS)
|
||||
{
|
||||
Serial.println("Open firmware file failed");
|
||||
return false;
|
||||
}
|
||||
diskfile.rewind();
|
||||
|
||||
MD5_CTX context;
|
||||
MD5::MD5Init(&context);
|
||||
uint8_t buf[512];
|
||||
size_t len;
|
||||
while ((len = diskfile.read(buf, 512)) > 0)
|
||||
{
|
||||
MD5::MD5Update(&context, buf, len);
|
||||
}
|
||||
std::vector<byte> diskHash(16);
|
||||
MD5::MD5Final(&diskHash[0], &context);
|
||||
diskfile.close();
|
||||
|
||||
Serial.println("disk hash");
|
||||
for (size_t i = 0; i < 16; i++)
|
||||
{
|
||||
Serial.print(diskHash[i], HEX);
|
||||
Serial.print("-");
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
//Serial.println((serverHash.begin() + 3));
|
||||
|
||||
if(!std::equal(serverHash.begin() + 2, serverHash.end(), diskHash.begin()))
|
||||
{
|
||||
Serial.println("NOT EQUAL");
|
||||
return false;
|
||||
}
|
||||
Serial.println("EQUAL");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TFTPClient::decompress()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// void TFTPClient::ack(int val)
|
||||
// {
|
||||
// char ack[4];
|
||||
// ack[0] = 0x00;
|
||||
// ack[1] = 0x04;
|
||||
// if ((val > 603135) || (val < 0))
|
||||
// val = 0;
|
||||
// ack[2] = val >> 8;
|
||||
// ack[3] = val & 255;
|
||||
// _socket->sendto(_socketAddr, ack, 4);
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// void TFTPClient::closeConnection()
|
||||
// {
|
||||
// Serial.println("Close");
|
||||
// _socket->close();
|
||||
// delete(_socket);
|
||||
// Serial.println("Close done");
|
||||
// }
|
||||
|
||||
// void TFTPClient::readRequest(std::string filename)
|
||||
// {
|
||||
// std::vector<char> buffer;
|
||||
// buffer.push_back(0x00);
|
||||
// buffer.push_back(static_cast<char>(opcode::ReadRequest));
|
||||
// buffer.insert(buffer.end(), filename.begin(), filename.end());
|
||||
// buffer.push_back(0x00);
|
||||
// std::string octet = "octet";
|
||||
// buffer.insert(buffer.end(), octet.begin(), octet.end());
|
||||
// buffer.push_back(0x00);
|
||||
// _socket->sendto(_socketAddr, buffer.data(), buffer.size());
|
||||
|
||||
// //_state = RECEIVING;
|
||||
// }
|
||||
|
||||
// void TFTPClient::receive()
|
||||
// {
|
||||
// Serial.println("RX");
|
||||
|
||||
// _socket->set_blocking(true);
|
||||
// _socket->set_timeout(100);
|
||||
|
||||
// // std::string buffer;
|
||||
// // nsapi_size_or_error_t recv_ret;
|
||||
// // //get whole message (multiple packets) uses the timeout to progress
|
||||
// // while ((recv_ret = client->recv(_rxBuffer, sizeof(_rxBuffer))) > 0) {
|
||||
|
||||
// // //Serial.println(recv_ret);
|
||||
// // buffer.append(_rxBuffer, recv_ret);
|
||||
// // if(buffer.size() > WEBSERVER_RX_BUFFER_SIZE)
|
||||
// // {
|
||||
// // break;
|
||||
// // }
|
||||
// // // if(recv_ret > 0){
|
||||
// // // buffer.append(_rxBuffer, recv_ret);
|
||||
// // // }
|
||||
// // }
|
||||
|
||||
|
||||
// while (_state == RECEIVING)
|
||||
// {
|
||||
// char buff[516];
|
||||
// int len = _socket->recvfrom(&_socketAddr, buff, sizeof(buff));
|
||||
|
||||
// Serial.println(len);
|
||||
// Serial.println(buff[1]);
|
||||
|
||||
// //if(len <= 0)
|
||||
// //break;
|
||||
// }
|
||||
// Serial.println("RX done");
|
||||
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Resets the TFTP server.
|
||||
* @note
|
||||
* @param
|
||||
* @retval
|
||||
*/
|
||||
// void TFTPClient::reset()
|
||||
// {
|
||||
// _socket->close();
|
||||
// delete(_socket);
|
||||
// strcpy(_remoteIP, "");
|
||||
// _socket = new UDPSocket();
|
||||
// _state = LISTENING;
|
||||
// if (_socket->bind(_port))
|
||||
// {
|
||||
// _socketAddr = SocketAddress(0, _port);
|
||||
// _state = ERROR;
|
||||
// }
|
||||
|
||||
// _socket->set_blocking(false);
|
||||
// strcpy(_fileName, "");
|
||||
// _fileCounter = 0;
|
||||
// }
|
||||
|
||||
/**
|
||||
* @brief Gets current TFTP status.
|
||||
* @note
|
||||
* @param
|
||||
* @retval
|
||||
*/
|
||||
// TFTPClient::State TFTPClient::getState()
|
||||
// {
|
||||
// return _state;
|
||||
// }
|
||||
|
||||
/**
|
||||
* @brief Temporarily disables incoming TFTP connections.
|
||||
* @note
|
||||
* @param
|
||||
* @retval
|
||||
*/
|
||||
// void TFTPClient::suspend()
|
||||
// {
|
||||
// _state = SUSPENDED;
|
||||
// }
|
||||
|
||||
/**
|
||||
* @brief Resumes incoming TFTP connection after suspension.
|
||||
* @note
|
||||
* @param
|
||||
* @retval
|
||||
*/
|
||||
// void TFTPClient::resume()
|
||||
// {
|
||||
// if (_state == SUSPENDED)
|
||||
// _state = LISTENING;
|
||||
// }
|
||||
|
||||
/**
|
||||
* @brief Polls for data or new connection.
|
||||
* @note
|
||||
* @param
|
||||
* @retval
|
||||
*/
|
||||
// void TFTPClient::poll()
|
||||
// {
|
||||
// if ((_state == SUSPENDED) || (_state == DELETED) || (_state == ERROR))
|
||||
// return;
|
||||
|
||||
// _socket->set_blocking(false);
|
||||
|
||||
// char buff[516];
|
||||
// int len = _socket->recvfrom(&_socketAddr, buff, sizeof(buff));
|
||||
|
||||
// Serial.println(len);
|
||||
|
||||
// if (len <= 0)
|
||||
// return;
|
||||
|
||||
// #ifdef TFTP_DEBUG
|
||||
// printf("Got block with size %d.\n\r", len);
|
||||
// #endif
|
||||
// switch (_state) {
|
||||
// case LISTENING:
|
||||
// {
|
||||
// switch (buff[1]) {
|
||||
// case 0x01: // RRQ
|
||||
// connectRead(buff);
|
||||
// break;
|
||||
|
||||
// case 0x02: // WRQ
|
||||
// connectWrite(buff);
|
||||
// break;
|
||||
|
||||
// case 0x03: // DATA before connection established
|
||||
// sendError("No data expected.\r\n");
|
||||
// break;
|
||||
|
||||
// case 0x04: // ACK before connection established
|
||||
// sendError("No ack expected.\r\n");
|
||||
// break;
|
||||
|
||||
// case 0x05: // ERROR packet received
|
||||
// #ifdef TFTP_DEBUG
|
||||
// printf("TFTP Eror received.\r\n");
|
||||
// #endif
|
||||
// break;
|
||||
|
||||
// default: // unknown TFTP packet type
|
||||
// sendError("Unknown TFTP packet type.\r\n");
|
||||
// break;
|
||||
// } // switch buff[1]
|
||||
// break; // case listening
|
||||
// }
|
||||
|
||||
// case READING:
|
||||
// {
|
||||
// if (cmpHost())
|
||||
// {
|
||||
// switch (buff[1]) {
|
||||
// case 0x01:
|
||||
// // if this is the receiving host, send first packet again
|
||||
// if (_blockCounter == 1)
|
||||
// {
|
||||
// ack(0);
|
||||
// _dupCounter++;
|
||||
// }
|
||||
|
||||
// if (_dupCounter > 10)
|
||||
// { // too many dups, stop sending
|
||||
// sendError("Too many dups");
|
||||
// fclose(_file);
|
||||
// _state = LISTENING;
|
||||
// strcpy(_remoteIP, "");
|
||||
// }
|
||||
// break;
|
||||
|
||||
// case 0x02:
|
||||
// // this should never happen, ignore
|
||||
// sendError("WRQ received on open read socket");
|
||||
// fclose(_file);
|
||||
// _state = LISTENING;
|
||||
// strcpy(_remoteIP, "");
|
||||
// break;
|
||||
|
||||
// case 0x03:
|
||||
// // we are the sending side, ignore
|
||||
// sendError("Received data package on sending socket");
|
||||
// fclose(_file);
|
||||
// _state = LISTENING;
|
||||
// strcpy(_remoteIP, "");
|
||||
// break;
|
||||
|
||||
// case 0x04:
|
||||
// // last packet received, send next if there is one
|
||||
// _dupCounter = 0;
|
||||
// if (_blockSize == 516)
|
||||
// {
|
||||
// getBlock();
|
||||
// sendBlock();
|
||||
// }
|
||||
// else
|
||||
// { //EOF
|
||||
// fclose(_file);
|
||||
// _state = LISTENING;
|
||||
// strcpy(_remoteIP, "");
|
||||
// }
|
||||
// break;
|
||||
|
||||
// default: // this includes 0x05 errors
|
||||
// sendError("Received 0x05 error message");
|
||||
// fclose(_file);
|
||||
// _state = LISTENING;
|
||||
// strcpy(_remoteIP, "");
|
||||
// break;
|
||||
// } // switch (buff[1])
|
||||
// }
|
||||
|
||||
// #ifdef TFTP_DEBUG
|
||||
// else
|
||||
// printf("Ignoring package from other remote client during RRQ.\r\n");
|
||||
// #endif
|
||||
// break; // reading
|
||||
// }
|
||||
|
||||
// case WRITING:
|
||||
// {
|
||||
// if (cmpHost())
|
||||
// {
|
||||
// switch (buff[1]) {
|
||||
// case 0x02:
|
||||
// {
|
||||
// // if this is a returning host, send ack again
|
||||
// ack(0);
|
||||
// #ifdef TFTP_DEBUG
|
||||
// TFTP_DEBUG("Resending Ack on WRQ.\r\n");
|
||||
// #endif
|
||||
// break; // case 0x02
|
||||
// }
|
||||
|
||||
// case 0x03:
|
||||
// {
|
||||
// int block = (buff[2] << 8) + buff[3];
|
||||
// if ((_blockCounter + 1) == block)
|
||||
// {
|
||||
// ack(block);
|
||||
// // new packet
|
||||
// char* data = &buff[4];
|
||||
// fwrite(data, 1, len - 4, _file);
|
||||
// _blockCounter++;
|
||||
// _dupCounter = 0;
|
||||
// }
|
||||
// else
|
||||
// { // mismatch in block nr
|
||||
// if ((_blockCounter + 1) < block)
|
||||
// { // too high
|
||||
// sendError("Packet count mismatch");
|
||||
// fclose(_file);
|
||||
// _state = LISTENING;
|
||||
// remove(_fileName);
|
||||
// strcpy(_remoteIP, "");
|
||||
// }
|
||||
// else
|
||||
// { // duplicate packet, send ACK again
|
||||
// if (_dupCounter > 10)
|
||||
// {
|
||||
// sendError("Too many dups");
|
||||
// fclose(_file);
|
||||
// remove(_fileName);
|
||||
// _state = LISTENING;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// ack(_blockCounter);
|
||||
// _dupCounter++;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (len < 516)
|
||||
// {
|
||||
// ack(_blockCounter);
|
||||
// fclose(_file);
|
||||
// _state = LISTENING;
|
||||
// strcpy(_remoteIP, "");
|
||||
// _fileCounter++;
|
||||
// #ifdef TFTP_DEBUG
|
||||
// printf("File receive finished.\r\n");
|
||||
// #endif
|
||||
// }
|
||||
// break; // case 0x03
|
||||
// }
|
||||
|
||||
// default:
|
||||
// {
|
||||
// sendError("No idea why you're sending me this!");
|
||||
// break; // default
|
||||
// }
|
||||
// } // switch (buff[1])
|
||||
// }
|
||||
|
||||
// #ifdef TFTP_DEBUG
|
||||
// else
|
||||
// printf("Ignoring packege from other remote client during WRQ.\r\n");
|
||||
// #endif
|
||||
// break; // writing
|
||||
// }
|
||||
|
||||
// case ERROR:
|
||||
// case SUSPENDED:
|
||||
// case DELETED:
|
||||
// default:
|
||||
// { }
|
||||
// } // state
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * @brief Gets the file name during read and write.
|
||||
// * @note
|
||||
// * @param name A pointer to C-style string to be filled with file name.
|
||||
// * @retval
|
||||
// */
|
||||
// void TFTPClient::getFileName(char* name)
|
||||
// {
|
||||
// sprintf(name, "%s", _fileName);
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * @brief Returns number of received files.
|
||||
// * @note
|
||||
// * @param
|
||||
// * @retval
|
||||
// */
|
||||
// int TFTPClient::fileCount()
|
||||
// {
|
||||
// return _fileCounter;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * @brief Creates a new connection reading a file from server.
|
||||
// * @note Sends the file to the remote client.
|
||||
// * Sends en error message to the remote client in case of failure.
|
||||
// * @param buff A char array to pass data.
|
||||
// * @retval
|
||||
// */
|
||||
// void TFTPClient::connectRead(char* buff)
|
||||
// {
|
||||
// _remoteIP = const_cast<char*>(_socketAddr.get_ip_address());
|
||||
// _remotePort = _socketAddr.get_port();
|
||||
// _blockCounter = 0;
|
||||
// _dupCounter = 0;
|
||||
|
||||
// sprintf(_fileName, "%s", &buff[2]);
|
||||
|
||||
// if (modeOctet(buff))
|
||||
// _file = fopen(_fileName, "rb");
|
||||
// else
|
||||
// _file = fopen(_fileName, "r");
|
||||
|
||||
// if (!_file)
|
||||
// {
|
||||
// _state = LISTENING;
|
||||
// char msg[123] = { "Could not read file: " };
|
||||
// strcat(msg, _fileName);
|
||||
// strcat(msg, "\r\n");
|
||||
// sendError(msg);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// // file ready for reading
|
||||
// _state = READING;
|
||||
// #ifdef TFTP_DEBUG
|
||||
// printf
|
||||
// (
|
||||
// "Listening: Requested file %s from TFTP connection %d.%d.%d.%d port %d\r\n",
|
||||
// fileName,
|
||||
// clientIp[0],
|
||||
// clientIp[1],
|
||||
// clientIp[2],
|
||||
// clientIp[3],
|
||||
// clientPort
|
||||
// );
|
||||
// #endif
|
||||
// getBlock();
|
||||
// sendBlock();
|
||||
// }
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * @brief Creates a new connection for writing a file to the server.
|
||||
// * @note Sends the file to the TFTP server.
|
||||
// * Sends error message to the remote client in case of failure.
|
||||
// * @param buff A char array to pass data.
|
||||
// * @retval
|
||||
// */
|
||||
// void TFTPClient::connectWrite(char* buff)
|
||||
// {
|
||||
// _remoteIP = const_cast<char*>(_socketAddr.get_ip_address());
|
||||
// _remotePort = _socketAddr.get_port();
|
||||
// ack(0);
|
||||
// _blockCounter = 0;
|
||||
// _dupCounter = 0;
|
||||
// sprintf(_fileName, "%s", &buff[2]);
|
||||
|
||||
// if (modeOctet(buff))
|
||||
// _file = fopen(_fileName, "wb");
|
||||
// else
|
||||
// _file = fopen(_fileName, "w");
|
||||
|
||||
// if (_file == NULL)
|
||||
// {
|
||||
// sendError("Could not open file to write.\r\n");
|
||||
// _state = LISTENING;
|
||||
// strcpy(_remoteIP, "");
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// // file ready for writing
|
||||
// _blockCounter = 0;
|
||||
// _state = WRITING;
|
||||
// #ifdef TFTP_DEBUG
|
||||
// printf
|
||||
// (
|
||||
// "Listening: Incoming file %s on TFTP connection from %d.%d.%d.%d clientPort %d\r\n",
|
||||
// fileName,
|
||||
// clientIp[0],
|
||||
// clientIp[1],
|
||||
// clientIp[2],
|
||||
// clientIp[3],
|
||||
// clientPort
|
||||
// );
|
||||
// #endif
|
||||
// }
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * @brief Gets DATA block from file on disk into memory.
|
||||
// * @note
|
||||
// * @param
|
||||
// * @retval
|
||||
// */
|
||||
// void TFTPClient::getBlock()
|
||||
// {
|
||||
// _blockCounter++;
|
||||
|
||||
// _blockBuff[0] = 0x00;
|
||||
// _blockBuff[1] = 0x03;
|
||||
// _blockBuff[2] = _blockCounter >> 8;
|
||||
// _blockBuff[3] = _blockCounter & 255;
|
||||
// _blockSize = 4 + fread((void*) &_blockBuff[4], 1, 512, _file);
|
||||
// }
|
||||
|
||||
|
||||
// /**
|
||||
// * @brief Sends DATA block to remote client.
|
||||
// * @note
|
||||
// * @param
|
||||
// * @retval
|
||||
// */
|
||||
// void TFTPClient::sendBlock()
|
||||
// {
|
||||
// _socket->sendto(_socketAddr, _blockBuff, _blockSize);
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * @brief Compares host's IP and Port with connected remote machine.
|
||||
// * @note
|
||||
// * @param
|
||||
// * @retval
|
||||
// */
|
||||
// int TFTPClient::cmpHost()
|
||||
// {
|
||||
// char ip[17];
|
||||
// strcpy(ip, _socketAddr.get_ip_address());
|
||||
|
||||
// int port = _socketAddr.get_port();
|
||||
// return((strcmp(ip, _remoteIP) == 0) && (port == _remotePort));
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * @brief Sends ACK to remote client.
|
||||
// * @note
|
||||
// * @param
|
||||
// * @retval
|
||||
// */
|
||||
|
||||
|
||||
// /**
|
||||
// * @brief Sends ERROR message to remote client.
|
||||
// * @note msg A C-style string with error message to be sent.
|
||||
// * @param
|
||||
// * @retval
|
||||
// */
|
||||
// void TFTPClient::sendError(const char* msg)
|
||||
// {
|
||||
// _errorBuff[0] = 0x00;
|
||||
// _errorBuff[1] = 0x05;
|
||||
// _errorBuff[2] = 0x00;
|
||||
// _errorBuff[3] = 0x00;
|
||||
// _errorBuff[4] = '\0'; // termination char
|
||||
// strcat(&_errorBuff[4], msg);
|
||||
|
||||
// int len = 4 + strlen(&_errorBuff[4]) + 1;
|
||||
// _socket->sendto(_socketAddr, _errorBuff, len);
|
||||
// #ifdef TFTP_DEBUG
|
||||
// printf("Error: %s\r\n", msg);
|
||||
// #endif
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * @brief Checks if connection mode of client is octet/binary.
|
||||
// * @note buff A char array.
|
||||
// * @param
|
||||
// * @retval
|
||||
// */
|
||||
// int TFTPClient::modeOctet(char* buff)
|
||||
// {
|
||||
// int x = 2;
|
||||
|
||||
// while (buff[x++] != 0);
|
||||
// // get beginning of mode field
|
||||
// int y = x;
|
||||
// while (buff[y] != 0)
|
||||
// {
|
||||
// buff[y] = tolower(buff[y]);
|
||||
// y++;
|
||||
// } // make mode field lowercase
|
||||
|
||||
// return(strcmp(&buff[x++], "octet") == 0);
|
||||
// }
|
||||
//#define FILENAME "/test.tar"
|
||||
|
||||
//Tar<FS> tar(&SPIFFS); // Declare and initialize class passing pointer to SPIFFS as target filesystem
|
||||
|
||||
bool printFile(char* name) {
|
||||
Serial.println(name);
|
||||
// if (strcmp(name, filename) == 0) {
|
||||
// Serial.println();
|
||||
// write = true;
|
||||
// return true;
|
||||
// }
|
||||
// Serial.println(" - SKIP");
|
||||
//return false;
|
||||
return true;
|
||||
}
|
||||
void blinkWrite(char* data, size_t s) {
|
||||
//if (!write) return;
|
||||
//digitalWrite(PIN, !digitalRead(PIN));
|
||||
Serial.println("write");
|
||||
}
|
||||
|
||||
void remaining(size_t s) {
|
||||
Serial.print("remianing: ");
|
||||
Serial.println(s);
|
||||
//sendremain
|
||||
}
|
||||
|
||||
void eof() {
|
||||
//digitalWrite(PIN, HIGH);
|
||||
//write = false;
|
||||
Serial.println("End of file");
|
||||
}
|
||||
|
||||
bool TFTPClient::unpack()
|
||||
{
|
||||
Serial.println("unpack tar");
|
||||
|
||||
Tar tar;
|
||||
|
||||
tar.onFile(printFile);
|
||||
//tar.onData(blinkWrite);
|
||||
//tar.onRemaining(remaining);
|
||||
tar.onRemaining(sendRemaining);
|
||||
tar.onEof(eof);
|
||||
|
||||
mbed::File file;
|
||||
if(ACSFileSystem::openFile("firmware.tar", &file, O_RDONLY, true) != MBED_SUCCESS)
|
||||
{
|
||||
Serial.println("Open firmware file failed");
|
||||
return false;
|
||||
}
|
||||
//tar.open((Stream*)&file);
|
||||
//tar.open(&file);
|
||||
//tar.dest("update/");
|
||||
tar.extract(&file);
|
||||
|
||||
|
||||
return true;
|
||||
|
||||
// mbed::File f = SPIFFS.open(FILENAME, "r"); // Open source file
|
||||
// if (f) {
|
||||
// tar.open((Stream*)&f); // Pass source file as Stream to Tar object
|
||||
// tar.dest("/"); // Set destination prefix to append to all files in archive. Should start with "/" for SPIFFS
|
||||
// tar.extract(); // Process with extraction
|
||||
// } else {
|
||||
// Serial.println("Error open .tar file");
|
||||
// }
|
||||
|
||||
|
||||
// mtar_t tar;
|
||||
|
||||
// //Serial.println("open");
|
||||
// /* Open archive for reading */
|
||||
// MTAR_RESULT result = mtar_open(&tar, "firmware.tar");
|
||||
// //Serial.println(result);
|
||||
|
||||
|
||||
// /* Print all file names and sizes */
|
||||
// mtar_header_t h;
|
||||
// mtar_read_header(&tar, &h);
|
||||
|
||||
// Serial.print("linkname: ");
|
||||
// Serial.println(h.linkname);
|
||||
|
||||
// Serial.print("type: ");
|
||||
// Serial.println(static_cast<char>(h.type));
|
||||
|
||||
// Serial.print(h.name);
|
||||
// Serial.print(" (");
|
||||
// Serial.print(h.size);
|
||||
// Serial.println(" bytes)");
|
||||
|
||||
|
||||
// while ((mtar_read_header(&tar, &h)) == MTAR_RESULT::ESUCCESS ) {
|
||||
// Serial.print("linkname: ");
|
||||
// Serial.println(h.linkname);
|
||||
// Serial.println(tar.raw_data.linkname);
|
||||
// //Serial.print("type: ");
|
||||
// //Serial.println(h.type);
|
||||
// Serial.print(h.name);
|
||||
// Serial.print(" (");
|
||||
// Serial.print(h.size);
|
||||
// Serial.println(" bytes)");
|
||||
// //mtar_next(&tar);
|
||||
// }
|
||||
|
||||
// //char *p;
|
||||
// /* Load and print contents of file "test.txt" */
|
||||
// //mtar_find(&tar, "test.txt", &h);
|
||||
// //p = calloc(1, h.size + 1);
|
||||
// //mtar_read_data(&tar, p, h.size);
|
||||
// //printf("%s", p);
|
||||
// //free(p);
|
||||
|
||||
// /* Close archive */
|
||||
// mtar_close(&tar);
|
||||
|
||||
}
|
||||
@@ -2,8 +2,6 @@
|
||||
#define _TFTPCLIENT_H_
|
||||
|
||||
//Arduino.h PlatformIO Dependency scanner
|
||||
//#include <stdio.h>
|
||||
//#include <ctype.h>
|
||||
#include "mbed.h"
|
||||
#include <vector>
|
||||
|
||||
@@ -12,84 +10,29 @@
|
||||
class TFTPClient
|
||||
{
|
||||
public:
|
||||
// enum State
|
||||
// {
|
||||
// RECEIVING,
|
||||
// //CONNECTING,
|
||||
// LISTENING,
|
||||
// READING,
|
||||
// WRITING,
|
||||
// ERROR,
|
||||
// SUSPENDED,
|
||||
// DELETED
|
||||
// };
|
||||
|
||||
enum class opcode
|
||||
enum class opCode
|
||||
{
|
||||
ReadRequest = 0x01,
|
||||
WriteRequest = 0x02,
|
||||
Data = 0x03,
|
||||
Acknowledgment = 0x04,
|
||||
Error = 0x05,
|
||||
Data = 0x02,
|
||||
Acknowledgment = 0x03,
|
||||
CRCRequest = 0x04,
|
||||
CRCResponse = 0x05,
|
||||
CloseRequest = 0x06,
|
||||
Remaining = 0x07,
|
||||
};
|
||||
|
||||
TFTPClient();
|
||||
~TFTPClient();
|
||||
|
||||
void connect(const char *host, uint16_t port = TFTP_PORT, std::string filename = "");
|
||||
|
||||
//void closeConnection();
|
||||
//void readRequest(std::string filename);
|
||||
//void receive();
|
||||
|
||||
|
||||
// Resets the TFTP server.
|
||||
//void reset();
|
||||
// Gets current TFTP status
|
||||
//State getState();
|
||||
// Temporarily disables incoming TFTP connections.
|
||||
//void suspend();
|
||||
// Resumes incoming TFTP connections after suspension.
|
||||
//void resume();
|
||||
// Polls for data or new connection.
|
||||
//void poll();
|
||||
// Gets the filename during read and write.
|
||||
//void getFileName(char* name);
|
||||
// Returns number of received files.
|
||||
//int fileCount();
|
||||
|
||||
static bool connect(const char *host, uint16_t port = TFTP_PORT);
|
||||
static void close();
|
||||
static bool receiveFirmware();
|
||||
static bool checkCRC();
|
||||
static bool decompress();
|
||||
static bool unpack();
|
||||
private:
|
||||
// Creates a new connection reading a file from server.
|
||||
//void connectRead(char* buff);
|
||||
// Creates a new connection writing a file to the server.
|
||||
//void connectWrite(char* buff);
|
||||
// Gets DATA block from file on disk into memory.
|
||||
//void getBlock();
|
||||
// Sends DATA block to remote client.
|
||||
//void sendBlock();
|
||||
// Compares host's IP and Port with connected remote machine.
|
||||
//int cmpHost();
|
||||
// Sends ACK to remote client.
|
||||
//void ack(int val);
|
||||
// Sends ERROR message to remote client.
|
||||
//void sendError(const char* msg);
|
||||
// Checks if connection mode of client is octet/binary.
|
||||
//int modeOctet(char* buff);
|
||||
|
||||
//uint16_t _port; // TFTP port
|
||||
//UDPSocket* _socket; // Main listening socket (dflt: UDP port 69)
|
||||
//State _state; // Current TFTP server state
|
||||
//char* _remoteIP; // Connected remote Host IP
|
||||
//int _remotePort; // Connected remote Host Port
|
||||
//uint16_t _blockCounter, _dupCounter; // Block counter, and DUP counter
|
||||
//FILE* _file; // Current file to read or write
|
||||
//char _blockBuff[516]; // Current DATA block;
|
||||
//int _blockSize; // Last DATA block size while sending
|
||||
//char _fileName[256]; // Current (or most recent) filename
|
||||
//int _fileCounter; // Received file counter
|
||||
//char _errorBuff[128]; // Error message buffer
|
||||
//SocketAddress _socketAddr; // Socket's addres (used to get remote host's address)
|
||||
//std::vector<char> _buffer;
|
||||
static void ack(uint16_t val);
|
||||
static bool sendCommand(opCode opcode);
|
||||
static void sendRemaining(size_t remaining);
|
||||
|
||||
static UDPSocket _socket;
|
||||
};
|
||||
|
||||
#endif
|
||||
542
lib/TFTPServer/lz.cpp
Normal file
542
lib/TFTPServer/lz.cpp
Normal file
@@ -0,0 +1,542 @@
|
||||
/*************************************************************************
|
||||
* Name: lz.c
|
||||
* Author: Marcus Geelnard
|
||||
* Description: LZ77 coder/decoder implementation.
|
||||
* Reentrant: Yes
|
||||
*
|
||||
* The LZ77 compression scheme is a substitutional compression scheme
|
||||
* proposed by Abraham Lempel and Jakob Ziv in 1977. It is very simple in
|
||||
* its design, and uses no fancy bit level compression.
|
||||
*
|
||||
* This is my first attempt at an implementation of a LZ77 code/decoder.
|
||||
*
|
||||
* The principle of the LZ77 compression algorithm is to store repeated
|
||||
* occurrences of strings as references to previous occurrences of the same
|
||||
* string. The point is that the reference consumes less space than the
|
||||
* string itself, provided that the string is long enough (in this
|
||||
* implementation, the string has to be at least 4 bytes long, since the
|
||||
* minimum coded reference is 3 bytes long). Also note that the term
|
||||
* "string" refers to any kind of byte sequence (it does not have to be
|
||||
* an ASCII string, for instance).
|
||||
*
|
||||
* The coder uses a brute force approach to finding string matches in the
|
||||
* history buffer (or "sliding window", if you wish), which is very, very
|
||||
* slow. I recon the complexity is somewhere between O(n^2) and O(n^3),
|
||||
* depending on the input data.
|
||||
*
|
||||
* There is also a faster implementation that uses a large working buffer
|
||||
* in which a "jump table" is stored, which is used to quickly find
|
||||
* possible string matches (see the source code for LZ_CompressFast() for
|
||||
* more information). The faster method is an order of magnitude faster,
|
||||
* but still quite slow compared to other compression methods.
|
||||
*
|
||||
* The upside is that decompression is very fast, and the compression ratio
|
||||
* is often very good.
|
||||
*
|
||||
* The reference to a string is coded as a (length,offset) pair, where the
|
||||
* length indicates the length of the string, and the offset gives the
|
||||
* offset from the current data position. To distinguish between string
|
||||
* references and literal strings (uncompressed bytes), a string reference
|
||||
* is preceded by a marker byte, which is chosen as the least common byte
|
||||
* symbol in the input data stream (this marker byte is stored in the
|
||||
* output stream as the first byte).
|
||||
*
|
||||
* Occurrences of the marker byte in the stream are encoded as the marker
|
||||
* byte followed by a zero byte, which means that occurrences of the marker
|
||||
* byte have to be coded with two bytes.
|
||||
*
|
||||
* The lengths and offsets are coded in a variable length fashion, allowing
|
||||
* values of any magnitude (up to 4294967295 in this implementation).
|
||||
*
|
||||
* With this compression scheme, the worst case compression result is
|
||||
* (257/256)*insize + 1.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
* Copyright (c) 2003-2006 Marcus Geelnard
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would
|
||||
* be appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not
|
||||
* be misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
* Marcus Geelnard
|
||||
* marcus.geelnard at home.se
|
||||
*************************************************************************/
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* Constants used for LZ77 coding
|
||||
*************************************************************************/
|
||||
|
||||
/* Maximum offset (can be any size < 2^31). Lower values give faster
|
||||
compression, while higher values gives better compression. The default
|
||||
value of 100000 is quite high. Experiment to see what works best for
|
||||
you. */
|
||||
#define LZ_MAX_OFFSET 100000
|
||||
|
||||
/*************************************************************************
|
||||
* INTERNAL FUNCTIONS *
|
||||
*************************************************************************/
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* _LZ_StringCompare() - Return maximum length string match.
|
||||
*************************************************************************/
|
||||
|
||||
static unsigned int _LZ_StringCompare( unsigned char * str1,
|
||||
unsigned char * str2, unsigned int minlen, unsigned int maxlen )
|
||||
{
|
||||
unsigned int len;
|
||||
|
||||
for( len = minlen; (len < maxlen) && (str1[len] == str2[len]); ++ len );
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* _LZ_WriteVarSize() - Write unsigned integer with variable number of
|
||||
* bytes depending on value.
|
||||
*************************************************************************/
|
||||
|
||||
static int _LZ_WriteVarSize( unsigned int x, unsigned char * buf )
|
||||
{
|
||||
unsigned int y;
|
||||
int num_bytes, i, b;
|
||||
|
||||
/* Determine number of bytes needed to store the number x */
|
||||
y = x >> 3;
|
||||
for( num_bytes = 5; num_bytes >= 2; -- num_bytes )
|
||||
{
|
||||
if( y & 0xfe000000 ) break;
|
||||
y <<= 7;
|
||||
}
|
||||
|
||||
/* Write all bytes, seven bits in each, with 8:th bit set for all */
|
||||
/* but the last byte. */
|
||||
for( i = num_bytes-1; i >= 0; -- i )
|
||||
{
|
||||
b = (x >> (i*7)) & 0x0000007f;
|
||||
if( i > 0 )
|
||||
{
|
||||
b |= 0x00000080;
|
||||
}
|
||||
*buf ++ = (unsigned char) b;
|
||||
}
|
||||
|
||||
/* Return number of bytes written */
|
||||
return num_bytes;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* _LZ_ReadVarSize() - Read unsigned integer with variable number of
|
||||
* bytes depending on value.
|
||||
*************************************************************************/
|
||||
|
||||
static int _LZ_ReadVarSize( unsigned int * x, unsigned char * buf )
|
||||
{
|
||||
unsigned int y, b, num_bytes;
|
||||
|
||||
/* Read complete value (stop when byte contains zero in 8:th bit) */
|
||||
y = 0;
|
||||
num_bytes = 0;
|
||||
do
|
||||
{
|
||||
b = (unsigned int) (*buf ++);
|
||||
y = (y << 7) | (b & 0x0000007f);
|
||||
++ num_bytes;
|
||||
}
|
||||
while( b & 0x00000080 );
|
||||
|
||||
/* Store value in x */
|
||||
*x = y;
|
||||
|
||||
/* Return number of bytes read */
|
||||
return num_bytes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* PUBLIC FUNCTIONS *
|
||||
*************************************************************************/
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* LZ_Compress() - Compress a block of data using an LZ77 coder.
|
||||
* in - Input (uncompressed) buffer.
|
||||
* out - Output (compressed) buffer. This buffer must be 0.4% larger
|
||||
* than the input buffer, plus one byte.
|
||||
* insize - Number of input bytes.
|
||||
* The function returns the size of the compressed data.
|
||||
*************************************************************************/
|
||||
|
||||
int LZ_Compress( unsigned char *in, unsigned char *out,
|
||||
unsigned int insize )
|
||||
{
|
||||
unsigned char marker, symbol;
|
||||
unsigned int inpos, outpos, bytesleft, i;
|
||||
unsigned int maxoffset, offset, bestoffset;
|
||||
unsigned int maxlength, length, bestlength;
|
||||
unsigned int histogram[ 256 ];
|
||||
unsigned char *ptr1, *ptr2;
|
||||
|
||||
|
||||
/* Do we have anything to compress? */
|
||||
if( insize < 1 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Create histogram */
|
||||
for( i = 0; i < 256; ++ i )
|
||||
{
|
||||
histogram[ i ] = 0;
|
||||
}
|
||||
for( i = 0; i < insize; ++ i )
|
||||
{
|
||||
++ histogram[ in[ i ] ];
|
||||
}
|
||||
|
||||
/* Find the least common byte, and use it as the marker symbol */
|
||||
marker = 0;
|
||||
for( i = 1; i < 256; ++ i )
|
||||
{
|
||||
if( histogram[ i ] < histogram[ marker ] )
|
||||
{
|
||||
marker = i;
|
||||
}
|
||||
}
|
||||
|
||||
/* Remember the marker symbol for the decoder */
|
||||
out[ 0 ] = marker;
|
||||
|
||||
/* Start of compression */
|
||||
inpos = 0;
|
||||
outpos = 1;
|
||||
|
||||
/* Main compression loop */
|
||||
bytesleft = insize;
|
||||
do
|
||||
{
|
||||
|
||||
|
||||
/* Determine most distant position */
|
||||
if( inpos > LZ_MAX_OFFSET ) maxoffset = LZ_MAX_OFFSET;
|
||||
else maxoffset = inpos;
|
||||
|
||||
/* Get pointer to current position */
|
||||
ptr1 = &in[ inpos ];
|
||||
|
||||
/* Search history window for maximum length string match */
|
||||
bestlength = 3;
|
||||
bestoffset = 0;
|
||||
for( offset = 3; offset <= maxoffset; ++ offset )
|
||||
{
|
||||
/* Get pointer to candidate string */
|
||||
ptr2 = &ptr1[ -(int)offset ];
|
||||
|
||||
/* Quickly determine if this is a candidate (for speed) */
|
||||
if( (ptr1[ 0 ] == ptr2[ 0 ]) &&
|
||||
(ptr1[ bestlength ] == ptr2[ bestlength ]) )
|
||||
{
|
||||
/* Determine maximum length for this offset */
|
||||
maxlength = (bytesleft < offset ? bytesleft : offset);
|
||||
|
||||
/* Count maximum length match at this offset */
|
||||
length = _LZ_StringCompare( ptr1, ptr2, 0, maxlength );
|
||||
|
||||
/* Better match than any previous match? */
|
||||
if( length > bestlength )
|
||||
{
|
||||
bestlength = length;
|
||||
bestoffset = offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Was there a good enough match? */
|
||||
if( (bestlength >= 8) ||
|
||||
((bestlength == 4) && (bestoffset <= 0x0000007f)) ||
|
||||
((bestlength == 5) && (bestoffset <= 0x00003fff)) ||
|
||||
((bestlength == 6) && (bestoffset <= 0x001fffff)) ||
|
||||
((bestlength == 7) && (bestoffset <= 0x0fffffff)) )
|
||||
{
|
||||
out[ outpos ++ ] = (unsigned char) marker;
|
||||
outpos += _LZ_WriteVarSize( bestlength, &out[ outpos ] );
|
||||
outpos += _LZ_WriteVarSize( bestoffset, &out[ outpos ] );
|
||||
inpos += bestlength;
|
||||
bytesleft -= bestlength;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Output single byte (or two bytes if marker byte) */
|
||||
symbol = in[ inpos ++ ];
|
||||
out[ outpos ++ ] = symbol;
|
||||
if( symbol == marker )
|
||||
{
|
||||
out[ outpos ++ ] = 0;
|
||||
}
|
||||
-- bytesleft;
|
||||
}
|
||||
}
|
||||
while( bytesleft > 3 );
|
||||
|
||||
/* Dump remaining bytes, if any */
|
||||
while( inpos < insize )
|
||||
{
|
||||
if( in[ inpos ] == marker )
|
||||
{
|
||||
out[ outpos ++ ] = marker;
|
||||
out[ outpos ++ ] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
out[ outpos ++ ] = in[ inpos ];
|
||||
}
|
||||
++ inpos;
|
||||
}
|
||||
|
||||
return outpos;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* LZ_CompressFast() - Compress a block of data using an LZ77 coder.
|
||||
* in - Input (uncompressed) buffer.
|
||||
* out - Output (compressed) buffer. This buffer must be 0.4% larger
|
||||
* than the input buffer, plus one byte.
|
||||
* insize - Number of input bytes.
|
||||
* work - Pointer to a temporary buffer (internal working buffer), which
|
||||
* must be able to hold (insize+65536) unsigned integers.
|
||||
* The function returns the size of the compressed data.
|
||||
*************************************************************************/
|
||||
|
||||
int LZ_CompressFast( unsigned char *in, unsigned char *out,
|
||||
unsigned int insize, unsigned int *work )
|
||||
{
|
||||
unsigned char marker, symbol;
|
||||
unsigned int inpos, outpos, bytesleft, i, index, symbols;
|
||||
unsigned int offset, bestoffset;
|
||||
unsigned int maxlength, length, bestlength;
|
||||
unsigned int histogram[ 256 ], *lastindex, *jumptable;
|
||||
unsigned char *ptr1, *ptr2;
|
||||
|
||||
/* Do we have anything to compress? */
|
||||
if( insize < 1 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Assign arrays to the working area */
|
||||
lastindex = work;
|
||||
jumptable = &work[ 65536 ];
|
||||
|
||||
/* Build a "jump table". Here is how the jump table works:
|
||||
jumptable[i] points to the nearest previous occurrence of the same
|
||||
symbol pair as in[i]:in[i+1], so in[i] == in[jumptable[i]] and
|
||||
in[i+1] == in[jumptable[i]+1], and so on... Following the jump table
|
||||
gives a dramatic boost for the string search'n'match loop compared
|
||||
to doing a brute force search. The jump table is built in O(n) time,
|
||||
so it is a cheap operation in terms of time, but it is expensice in
|
||||
terms of memory consumption. */
|
||||
for( i = 0; i < 65536; ++ i )
|
||||
{
|
||||
lastindex[ i ] = 0xffffffff;
|
||||
}
|
||||
for( i = 0; i < insize-1; ++ i )
|
||||
{
|
||||
symbols = (((unsigned int)in[i]) << 8) | ((unsigned int)in[i+1]);
|
||||
index = lastindex[ symbols ];
|
||||
lastindex[ symbols ] = i;
|
||||
jumptable[ i ] = index;
|
||||
}
|
||||
jumptable[ insize-1 ] = 0xffffffff;
|
||||
|
||||
/* Create histogram */
|
||||
for( i = 0; i < 256; ++ i )
|
||||
{
|
||||
histogram[ i ] = 0;
|
||||
}
|
||||
for( i = 0; i < insize; ++ i )
|
||||
{
|
||||
++ histogram[ in[ i ] ];
|
||||
}
|
||||
|
||||
/* Find the least common byte, and use it as the marker symbol */
|
||||
marker = 0;
|
||||
for( i = 1; i < 256; ++ i )
|
||||
{
|
||||
if( histogram[ i ] < histogram[ marker ] )
|
||||
{
|
||||
marker = i;
|
||||
}
|
||||
}
|
||||
|
||||
/* Remember the marker symbol for the decoder */
|
||||
out[ 0 ] = marker;
|
||||
|
||||
/* Start of compression */
|
||||
inpos = 0;
|
||||
outpos = 1;
|
||||
|
||||
/* Main compression loop */
|
||||
bytesleft = insize;
|
||||
do
|
||||
{
|
||||
/* Get pointer to current position */
|
||||
ptr1 = &in[ inpos ];
|
||||
|
||||
/* Search history window for maximum length string match */
|
||||
bestlength = 3;
|
||||
bestoffset = 0;
|
||||
index = jumptable[ inpos ];
|
||||
while( (index != 0xffffffff) && ((inpos - index) < LZ_MAX_OFFSET) )
|
||||
{
|
||||
/* Get pointer to candidate string */
|
||||
ptr2 = &in[ index ];
|
||||
|
||||
/* Quickly determine if this is a candidate (for speed) */
|
||||
if( ptr2[ bestlength ] == ptr1[ bestlength ] )
|
||||
{
|
||||
/* Determine maximum length for this offset */
|
||||
offset = inpos - index;
|
||||
maxlength = (bytesleft < offset ? bytesleft : offset);
|
||||
|
||||
/* Count maximum length match at this offset */
|
||||
length = _LZ_StringCompare( ptr1, ptr2, 2, maxlength );
|
||||
|
||||
/* Better match than any previous match? */
|
||||
if( length > bestlength )
|
||||
{
|
||||
bestlength = length;
|
||||
bestoffset = offset;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get next possible index from jump table */
|
||||
index = jumptable[ index ];
|
||||
}
|
||||
|
||||
/* Was there a good enough match? */
|
||||
if( (bestlength >= 8) ||
|
||||
((bestlength == 4) && (bestoffset <= 0x0000007f)) ||
|
||||
((bestlength == 5) && (bestoffset <= 0x00003fff)) ||
|
||||
((bestlength == 6) && (bestoffset <= 0x001fffff)) ||
|
||||
((bestlength == 7) && (bestoffset <= 0x0fffffff)) )
|
||||
{
|
||||
out[ outpos ++ ] = (unsigned char) marker;
|
||||
outpos += _LZ_WriteVarSize( bestlength, &out[ outpos ] );
|
||||
outpos += _LZ_WriteVarSize( bestoffset, &out[ outpos ] );
|
||||
inpos += bestlength;
|
||||
bytesleft -= bestlength;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Output single byte (or two bytes if marker byte) */
|
||||
symbol = in[ inpos ++ ];
|
||||
out[ outpos ++ ] = symbol;
|
||||
if( symbol == marker )
|
||||
{
|
||||
out[ outpos ++ ] = 0;
|
||||
}
|
||||
-- bytesleft;
|
||||
}
|
||||
}
|
||||
while( bytesleft > 3 );
|
||||
|
||||
/* Dump remaining bytes, if any */
|
||||
while( inpos < insize )
|
||||
{
|
||||
if( in[ inpos ] == marker )
|
||||
{
|
||||
out[ outpos ++ ] = marker;
|
||||
out[ outpos ++ ] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
out[ outpos ++ ] = in[ inpos ];
|
||||
}
|
||||
++ inpos;
|
||||
}
|
||||
|
||||
return outpos;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* LZ_Uncompress() - Uncompress a block of data using an LZ77 decoder.
|
||||
* in - Input (compressed) buffer.
|
||||
* out - Output (uncompressed) buffer. This buffer must be large
|
||||
* enough to hold the uncompressed data.
|
||||
* insize - Number of input bytes.
|
||||
*************************************************************************/
|
||||
|
||||
void LZ_Uncompress( unsigned char *in, unsigned char *out,
|
||||
unsigned int insize )
|
||||
{
|
||||
unsigned char marker, symbol;
|
||||
unsigned int i, inpos, outpos, length, offset;
|
||||
|
||||
/* Do we have anything to uncompress? */
|
||||
if( insize < 1 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get marker symbol from input stream */
|
||||
marker = in[ 0 ];
|
||||
inpos = 1;
|
||||
|
||||
/* Main decompression loop */
|
||||
outpos = 0;
|
||||
do
|
||||
{
|
||||
symbol = in[ inpos ++ ];
|
||||
if( symbol == marker )
|
||||
{
|
||||
/* We had a marker byte */
|
||||
if( in[ inpos ] == 0 )
|
||||
{
|
||||
/* It was a single occurrence of the marker byte */
|
||||
out[ outpos ++ ] = marker;
|
||||
++ inpos;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Extract true length and offset */
|
||||
inpos += _LZ_ReadVarSize( &length, &in[ inpos ] );
|
||||
inpos += _LZ_ReadVarSize( &offset, &in[ inpos ] );
|
||||
|
||||
/* Copy corresponding data from history window */
|
||||
for( i = 0; i < length; ++ i )
|
||||
{
|
||||
out[ outpos ] = out[ outpos - offset ];
|
||||
++ outpos;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No marker, plain copy */
|
||||
out[ outpos ++ ] = symbol;
|
||||
}
|
||||
}
|
||||
while( inpos < insize );
|
||||
}
|
||||
56
lib/TFTPServer/lz.h
Normal file
56
lib/TFTPServer/lz.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*************************************************************************
|
||||
* Name: lz.h
|
||||
* Author: Marcus Geelnard
|
||||
* Description: LZ77 coder/decoder interface.
|
||||
* Reentrant: Yes
|
||||
*-------------------------------------------------------------------------
|
||||
* Copyright (c) 2003-2006 Marcus Geelnard
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would
|
||||
* be appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not
|
||||
* be misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
* Marcus Geelnard
|
||||
* marcus.geelnard at home.se
|
||||
*************************************************************************/
|
||||
|
||||
#ifndef _lz_h_
|
||||
#define _lz_h_
|
||||
|
||||
//#ifdef __cplusplus
|
||||
//extern "C" {
|
||||
//#endif
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* Function prototypes
|
||||
*************************************************************************/
|
||||
|
||||
int LZ_Compress( unsigned char *in, unsigned char *out,
|
||||
unsigned int insize );
|
||||
int LZ_CompressFast( unsigned char *in, unsigned char *out,
|
||||
unsigned int insize, unsigned int *work );
|
||||
void LZ_Uncompress( unsigned char *in, unsigned char *out,
|
||||
unsigned int insize );
|
||||
|
||||
|
||||
//#ifdef __cplusplus
|
||||
//}
|
||||
//#endif
|
||||
|
||||
#endif /* _lz_h_ */
|
||||
397
lib/TFTPServer/microtar.cpp
Normal file
397
lib/TFTPServer/microtar.cpp
Normal file
@@ -0,0 +1,397 @@
|
||||
/*
|
||||
* Copyright (c) 2017 rxi
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "microtar.h"
|
||||
#include "ACSFileSystem.h"
|
||||
|
||||
typedef struct {
|
||||
char name[100];
|
||||
char mode[8];
|
||||
char owner[8];
|
||||
char group[8];
|
||||
char size[12];
|
||||
char mtime[12];
|
||||
char checksum[8];
|
||||
char type;
|
||||
char linkname[100];
|
||||
//char _padding[255];
|
||||
|
||||
// New UStar fields
|
||||
char magic_bytes[6];
|
||||
char version[2];
|
||||
char owner_user_name[32];
|
||||
char owner_group_name[32];
|
||||
char device_major_number[8];
|
||||
char device_minor_number[8];
|
||||
char prefix[155];
|
||||
|
||||
char padding[12];
|
||||
|
||||
char data[512];
|
||||
} mtar_raw_header_t;
|
||||
|
||||
|
||||
static unsigned round_up(unsigned n, unsigned incr) {
|
||||
return n + (incr - n % incr) % incr;
|
||||
}
|
||||
|
||||
static unsigned checksum(const mtar_raw_header_t* rh) {
|
||||
unsigned i;
|
||||
unsigned char *p = (unsigned char*) rh;
|
||||
unsigned res = 256;
|
||||
for (i = 0; i < offsetof(mtar_raw_header_t, checksum); i++) {
|
||||
res += p[i];
|
||||
}
|
||||
for (i = offsetof(mtar_raw_header_t, type); i < sizeof(*rh); i++) {
|
||||
res += p[i];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static MTAR_RESULT tread(mtar_t *tar, void *data, unsigned int size)
|
||||
{
|
||||
ssize_t res = tar->stream.read(data, size);
|
||||
tar->pos += size;
|
||||
return (res == size) ? MTAR_RESULT::ESUCCESS : MTAR_RESULT::EREADFAIL;
|
||||
}
|
||||
|
||||
static MTAR_RESULT read_block(mtar_t *tar)
|
||||
{
|
||||
ssize_t res = tar->stream.read(&tar->raw_data, 1024);
|
||||
tar->pos += 1024;
|
||||
return (res == 1024) ? MTAR_RESULT::ESUCCESS : MTAR_RESULT::EREADFAIL;
|
||||
}
|
||||
|
||||
// static MTAR_RESULT twrite(mtar_t *tar, const void *data, unsigned int size)
|
||||
// {
|
||||
// ssize_t res = tar->stream.write(data, size);
|
||||
// tar->pos += size;
|
||||
// return (res == size) ? MTAR_RESULT::ESUCCESS : MTAR_RESULT::EWRITEFAIL;
|
||||
// }
|
||||
|
||||
|
||||
// static MTAR_RESULT write_null_bytes(mtar_t *tar, int n) {
|
||||
// int i;
|
||||
// char nul = '\0';
|
||||
// for (i = 0; i < n; i++) {
|
||||
// MTAR_RESULT err = twrite(tar, &nul, 1);
|
||||
// if (err != MTAR_RESULT::ESUCCESS) {
|
||||
// return err;
|
||||
// }
|
||||
// }
|
||||
// return MTAR_RESULT::ESUCCESS;
|
||||
// }
|
||||
|
||||
|
||||
static MTAR_RESULT raw_to_header(mtar_header_t *h, const mtar_raw_header_t *rh)
|
||||
{
|
||||
//unsigned chksum1, chksum2;
|
||||
|
||||
/* If the checksum starts with a null byte we assume the record is NULL */
|
||||
if (*rh->checksum == '\0') {
|
||||
return MTAR_RESULT::ENULLRECORD;
|
||||
}
|
||||
|
||||
/* Build and compare checksum */
|
||||
unsigned int chksum1 = checksum(rh);
|
||||
unsigned int chksum2;
|
||||
sscanf(rh->checksum, "%o", &chksum2);
|
||||
if (chksum1 != chksum2) {
|
||||
return MTAR_RESULT::EBADCHKSUM;
|
||||
}
|
||||
|
||||
/* Load raw header into header */
|
||||
sscanf(rh->mode, "%o", &h->mode);
|
||||
sscanf(rh->owner, "%o", &h->owner);
|
||||
sscanf(rh->size, "%o", &h->size);
|
||||
sscanf(rh->mtime, "%o", &h->mtime);
|
||||
//(char)h->type = rh->type;
|
||||
h->type = static_cast<TypeFlag>(rh->type);
|
||||
strcpy(h->name, rh->name);
|
||||
strcpy(h->linkname, rh->linkname);
|
||||
|
||||
return MTAR_RESULT::ESUCCESS;
|
||||
}
|
||||
|
||||
static MTAR_RESULT raw_to_header(mtar_t *tar, mtar_header_t *h)
|
||||
{
|
||||
//unsigned chksum1, chksum2;
|
||||
|
||||
/* If the checksum starts with a null byte we assume the record is NULL */
|
||||
// if (*rh->checksum == '\0') {
|
||||
// return MTAR_RESULT::ENULLRECORD;
|
||||
// }
|
||||
|
||||
/* Build and compare checksum */
|
||||
// unsigned int chksum1 = checksum(rh);
|
||||
// unsigned int chksum2;
|
||||
// sscanf(rh->checksum, "%o", &chksum2);
|
||||
// if (chksum1 != chksum2) {
|
||||
// return MTAR_RESULT::EBADCHKSUM;
|
||||
// }
|
||||
|
||||
// /* Load raw header into header */
|
||||
// sscanf(rh->mode, "%o", &h->mode);
|
||||
// sscanf(rh->owner, "%o", &h->owner);
|
||||
// sscanf(rh->size, "%o", &h->size);
|
||||
// sscanf(rh->mtime, "%o", &h->mtime);
|
||||
// //(char)h->type = rh->type;
|
||||
// h->type = static_cast<TypeFlag>(rh->type);
|
||||
// strcpy(h->name, rh->name);
|
||||
// strcpy(h->linkname, rh->linkname);
|
||||
|
||||
return MTAR_RESULT::ESUCCESS;
|
||||
}
|
||||
|
||||
// static MTAR_RESULT header_to_raw(mtar_raw_header_t *rh, const mtar_header_t *h) {
|
||||
// unsigned chksum;
|
||||
|
||||
// /* Load header into raw header */
|
||||
// memset(rh, 0, sizeof(*rh));
|
||||
// sprintf(rh->mode, "%o", h->mode);
|
||||
// sprintf(rh->owner, "%o", h->owner);
|
||||
// sprintf(rh->size, "%o", h->size);
|
||||
// sprintf(rh->mtime, "%o", h->mtime);
|
||||
// rh->type = static_cast<char>(h->type) ? static_cast<char>(h->type) : static_cast<char>(TypeFlag::REG);
|
||||
// strcpy(rh->name, h->name);
|
||||
// strcpy(rh->linkname, h->linkname);
|
||||
|
||||
// /* Calculate and write checksum */
|
||||
// chksum = checksum(rh);
|
||||
// sprintf(rh->checksum, "%06o", chksum);
|
||||
// rh->checksum[7] = ' ';
|
||||
|
||||
// return MTAR_RESULT::ESUCCESS;
|
||||
// }
|
||||
|
||||
|
||||
const char* mtar_strerror(MTAR_RESULT err) {
|
||||
switch (err) {
|
||||
case MTAR_RESULT::ESUCCESS : return "success";
|
||||
case MTAR_RESULT::EFAILURE : return "failure";
|
||||
case MTAR_RESULT::EOPENFAIL : return "could not open";
|
||||
case MTAR_RESULT::EREADFAIL : return "could not read";
|
||||
case MTAR_RESULT::EWRITEFAIL : return "could not write";
|
||||
case MTAR_RESULT::ESEEKFAIL : return "could not seek";
|
||||
case MTAR_RESULT::EBADCHKSUM : return "bad checksum";
|
||||
case MTAR_RESULT::ENULLRECORD : return "null record";
|
||||
case MTAR_RESULT::ENOTFOUND : return "file not found";
|
||||
}
|
||||
return "unknown error";
|
||||
}
|
||||
|
||||
MTAR_RESULT mtar_open(mtar_t *tar, const char *filename)
|
||||
{
|
||||
tar->pos = 0;
|
||||
tar->last_header = 0;
|
||||
tar->remaining_data = 0;
|
||||
|
||||
if(ACSFileSystem::openFile(filename, &tar->stream, O_RDONLY, true) != MBED_SUCCESS)
|
||||
{
|
||||
Serial.println("Open firmware file failed");
|
||||
return MTAR_RESULT::EOPENFAIL;
|
||||
}
|
||||
return MTAR_RESULT::ESUCCESS;
|
||||
}
|
||||
|
||||
// MTAR_RESULT mtar_open(mtar_t *tar, const char *filename, const char *mode)
|
||||
// {
|
||||
// MTAR_RESULT err;
|
||||
// mtar_header_t h;
|
||||
|
||||
// /* Init tar struct and functions */
|
||||
// memset(tar, 0, sizeof(*tar));
|
||||
// //tar->write = file_write;
|
||||
// //tar->read = file_read;
|
||||
// //tar->seek = file_seek;
|
||||
// //tar->close = file_close;
|
||||
|
||||
// /* Assure mode is always binary */
|
||||
// if ( strchr(mode, 'r') ) mode = "rb";
|
||||
// if ( strchr(mode, 'w') ) mode = "wb";
|
||||
// if ( strchr(mode, 'a') ) mode = "ab";
|
||||
// /* Open file */
|
||||
// //tar->stream = fopen(filename, mode);
|
||||
// if(ACSFileSystem::openFile(filename, &tar->stream, O_RDONLY, true) != MBED_SUCCESS)
|
||||
// {
|
||||
// Serial.println("Open firmware file failed");
|
||||
// return MTAR_RESULT::EOPENFAIL;
|
||||
// }
|
||||
|
||||
// // if (!tar->stream) {
|
||||
// // return MTAR_EOPENFAIL;
|
||||
// // }
|
||||
// /* Read first header to check it is valid if mode is `r` */
|
||||
// if (*mode == 'r') {
|
||||
// err = mtar_read_header(tar, &h);
|
||||
// if (err != MTAR_RESULT::ESUCCESS) {
|
||||
// mtar_close(tar);
|
||||
// return err;
|
||||
// }
|
||||
// }
|
||||
|
||||
// /* Return ok */
|
||||
// return MTAR_RESULT::ESUCCESS;
|
||||
// }
|
||||
|
||||
MTAR_RESULT mtar_close(mtar_t *tar)
|
||||
{
|
||||
tar->stream.close();
|
||||
return MTAR_RESULT::ESUCCESS;
|
||||
}
|
||||
|
||||
MTAR_RESULT mtar_seek(mtar_t *tar, unsigned pos)
|
||||
{
|
||||
ssize_t res = tar->stream.seek(pos, SEEK_SET);
|
||||
tar->pos = pos;
|
||||
return (res == 0) ? MTAR_RESULT::ESUCCESS : MTAR_RESULT::ESEEKFAIL;
|
||||
}
|
||||
|
||||
MTAR_RESULT mtar_rewind(mtar_t *tar)
|
||||
{
|
||||
tar->remaining_data = 0;
|
||||
tar->last_header = 0;
|
||||
return mtar_seek(tar, 0);
|
||||
}
|
||||
|
||||
MTAR_RESULT mtar_next(mtar_t *tar)
|
||||
{
|
||||
mtar_header_t h;
|
||||
MTAR_RESULT err = mtar_read_header(tar, &h);
|
||||
if (err != MTAR_RESULT::ESUCCESS) {
|
||||
return err;
|
||||
}
|
||||
/* Seek to next record */
|
||||
int n = round_up(h.size, 512) + sizeof(mtar_raw_header_t);
|
||||
return mtar_seek(tar, tar->pos + n);
|
||||
}
|
||||
|
||||
|
||||
MTAR_RESULT mtar_find(mtar_t *tar, const char *name, mtar_header_t *h)
|
||||
{
|
||||
/* Start at beginning */
|
||||
MTAR_RESULT err = mtar_rewind(tar);
|
||||
if (err != MTAR_RESULT::ESUCCESS) {
|
||||
return err;
|
||||
}
|
||||
/* Iterate all files until we hit an error or find the file */
|
||||
mtar_header_t header;
|
||||
while ( (err = mtar_read_header(tar, &header)) == MTAR_RESULT::ESUCCESS )
|
||||
{
|
||||
if (!strcmp(header.name, name))
|
||||
{
|
||||
if (h)
|
||||
{
|
||||
*h = header;
|
||||
}
|
||||
return MTAR_RESULT::ESUCCESS;
|
||||
}
|
||||
mtar_next(tar);
|
||||
}
|
||||
/* Return error */
|
||||
if (err == MTAR_RESULT::ENULLRECORD) {
|
||||
err = MTAR_RESULT::ENOTFOUND;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
MTAR_RESULT mtar_read_header(mtar_t *tar, mtar_header_t *h)
|
||||
{
|
||||
|
||||
|
||||
tar->last_header = tar->pos;
|
||||
|
||||
//MTAR_RESULT err = tread(tar, &rh, sizeof(rh));
|
||||
MTAR_RESULT err = read_block(tar);
|
||||
|
||||
mtar_raw_header_t rh;
|
||||
//memccpy()
|
||||
// for (size_t i = 0; i < 512; i++)
|
||||
// {
|
||||
// Serial.print(((char *)&rh)[i]);
|
||||
// Serial.print("-");
|
||||
// }
|
||||
// Serial.println();
|
||||
|
||||
Serial.print("read: ");
|
||||
Serial.println(mtar_strerror(err));
|
||||
|
||||
Serial.print("pos: ");
|
||||
Serial.println(tar->pos);
|
||||
|
||||
if (err != MTAR_RESULT::ESUCCESS) {
|
||||
return err;
|
||||
}
|
||||
/* Seek back to start of header */
|
||||
//err = mtar_seek(tar, tar->last_header);
|
||||
|
||||
//Serial.print("err seek: ");
|
||||
//Serial.println(mtar_strerror(err));
|
||||
|
||||
//Serial.print("pos: ");
|
||||
//Serial.println(tar->pos);
|
||||
|
||||
//if (err != MTAR_RESULT::ESUCCESS) {
|
||||
// return err;
|
||||
//}
|
||||
/* Load raw header into header struct and return */
|
||||
return raw_to_header(h, &rh);
|
||||
}
|
||||
|
||||
|
||||
MTAR_RESULT mtar_read_data(mtar_t *tar, void *ptr, unsigned size) {
|
||||
MTAR_RESULT err;
|
||||
/* If we have no remaining data then this is the first read, we get the size,
|
||||
* set the remaining data and seek to the beginning of the data */
|
||||
if (tar->remaining_data == 0) {
|
||||
mtar_header_t h;
|
||||
/* Read header */
|
||||
err = mtar_read_header(tar, &h);
|
||||
if (err != MTAR_RESULT::ESUCCESS) {
|
||||
return err;
|
||||
}
|
||||
/* Seek past header and init remaining data */
|
||||
err = mtar_seek(tar, tar->pos + sizeof(mtar_raw_header_t));
|
||||
if (err != MTAR_RESULT::ESUCCESS) {
|
||||
return err;
|
||||
}
|
||||
tar->remaining_data = h.size;
|
||||
}
|
||||
/* Read data */
|
||||
err = tread(tar, ptr, size);
|
||||
if (err != MTAR_RESULT::ESUCCESS) {
|
||||
return err;
|
||||
}
|
||||
tar->remaining_data -= size;
|
||||
/* If there is no remaining data we've finished reading and seek back to the
|
||||
* header */
|
||||
if (tar->remaining_data == 0) {
|
||||
return mtar_seek(tar, tar->last_header);
|
||||
}
|
||||
return MTAR_RESULT::ESUCCESS;
|
||||
}
|
||||
119
lib/TFTPServer/microtar.h
Normal file
119
lib/TFTPServer/microtar.h
Normal file
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* Copyright (c) 2017 rxi
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the MIT license. See `microtar.c` for details.
|
||||
*/
|
||||
|
||||
#ifndef MICROTAR_H
|
||||
#define MICROTAR_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "mbed.h"
|
||||
|
||||
#define MTAR_VERSION "0.1.0"
|
||||
|
||||
enum class MTAR_RESULT
|
||||
{
|
||||
ESUCCESS = 0,
|
||||
EFAILURE = -1,
|
||||
EOPENFAIL = -2,
|
||||
EREADFAIL = -3,
|
||||
EWRITEFAIL = -4,
|
||||
ESEEKFAIL = -5,
|
||||
EBADCHKSUM = -6,
|
||||
ENULLRECORD = -7,
|
||||
ENOTFOUND = -8
|
||||
};
|
||||
|
||||
enum class TypeFlag
|
||||
{
|
||||
REG = '0',
|
||||
LNK = '1',
|
||||
SYM = '2',
|
||||
CHR = '3',
|
||||
BLK = '4',
|
||||
DIR = '5',
|
||||
FIFO = '6',
|
||||
CONT = '7',
|
||||
XHD = 'x',
|
||||
XGL = 'g'
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
unsigned int mode;
|
||||
unsigned int owner;
|
||||
unsigned int size;
|
||||
unsigned int mtime;
|
||||
TypeFlag type;
|
||||
char name[100];
|
||||
char linkname[100];
|
||||
} mtar_header_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char name[100];
|
||||
char mode[8];
|
||||
char owner[8];
|
||||
char group[8];
|
||||
char size[12];
|
||||
char mtime[12];
|
||||
char checksum[8];
|
||||
char type;
|
||||
char linkname[100];
|
||||
//char _padding[255];
|
||||
|
||||
// New UStar fields
|
||||
char magic_bytes[6];
|
||||
char version[2];
|
||||
char owner_user_name[32];
|
||||
char owner_group_name[32];
|
||||
char device_major_number[8];
|
||||
char device_minor_number[8];
|
||||
char prefix[155];
|
||||
|
||||
char padding[12];
|
||||
|
||||
char data[512];
|
||||
} tar_raw_data_t;
|
||||
|
||||
typedef struct mtar_t mtar_t;
|
||||
|
||||
struct mtar_t
|
||||
{
|
||||
//int (*read)(mtar_t *tar, void *data, unsigned size);
|
||||
//int (*write)(mtar_t *tar, const void *data, unsigned size);
|
||||
//int (*seek)(mtar_t *tar, unsigned pos);
|
||||
//int (*close)(mtar_t *tar);
|
||||
//void *stream;
|
||||
mbed::File stream;
|
||||
unsigned int pos;
|
||||
unsigned int remaining_data;
|
||||
unsigned int last_header;
|
||||
//char data[1024];
|
||||
tar_raw_data_t raw_data;
|
||||
};
|
||||
|
||||
|
||||
const char* mtar_strerror(MTAR_RESULT err);
|
||||
|
||||
//MTAR_RESULT mtar_open(mtar_t *tar, const char *filename, const char *mode);
|
||||
MTAR_RESULT mtar_open(mtar_t *tar, const char *filename);
|
||||
MTAR_RESULT mtar_close(mtar_t *tar);
|
||||
|
||||
MTAR_RESULT mtar_seek(mtar_t *tar, unsigned int pos);
|
||||
MTAR_RESULT mtar_rewind(mtar_t *tar);
|
||||
MTAR_RESULT mtar_next(mtar_t *tar);
|
||||
MTAR_RESULT mtar_find(mtar_t *tar, const char *name, mtar_header_t *h);
|
||||
MTAR_RESULT mtar_read_header(mtar_t *tar, mtar_header_t *h);
|
||||
MTAR_RESULT mtar_read_data(mtar_t *tar, void *ptr, unsigned int size);
|
||||
|
||||
//MTAR_RESULT mtar_write_header(mtar_t *tar, const mtar_header_t *h);
|
||||
//MTAR_RESULT mtar_write_file_header(mtar_t *tar, const char *name, unsigned int size);
|
||||
//MTAR_RESULT mtar_write_dir_header(mtar_t *tar, const char *name);
|
||||
//MTAR_RESULT mtar_write_data(mtar_t *tar, const void *data, unsigned int size);
|
||||
//MTAR_RESULT mtar_finalize(mtar_t *tar);
|
||||
|
||||
|
||||
#endif
|
||||
158
lib/TFTPServer/tarex.cpp
Normal file
158
lib/TFTPServer/tarex.cpp
Normal file
@@ -0,0 +1,158 @@
|
||||
// //Arduino.h PlatformIO Dependency scanner
|
||||
// #include <stdio.h>
|
||||
// #include <stdlib.h>
|
||||
// #include <unistd.h>
|
||||
// #include <sys/stat.h>
|
||||
// #include <string.h>
|
||||
// #include "mbed.h"
|
||||
|
||||
// struct file_header {
|
||||
// // Original tar header fields
|
||||
// char file_path[100];
|
||||
// char file_mode[8];
|
||||
// char owner_user_id[8];
|
||||
// char owner_group_id[8];
|
||||
// char file_size[12];
|
||||
// char file_mtime[12];
|
||||
// char header_checksum[8];
|
||||
// char file_type;
|
||||
// char link_path[100];
|
||||
|
||||
// // New UStar fields
|
||||
// char magic_bytes[6];
|
||||
// char version[2];
|
||||
// char owner_user_name[32];
|
||||
// char owner_group_name[32];
|
||||
// char device_major_number[8];
|
||||
// char device_minor_number[8];
|
||||
// char prefix[155];
|
||||
|
||||
// char padding[12];
|
||||
// };
|
||||
|
||||
// // We don't bother with great error reporting, just abort on error
|
||||
// #define check(x) if (!(x)) abort()
|
||||
|
||||
// // Utilities to abort on short read/write
|
||||
// #define xfread(ptr, size, f) check(fread(ptr, 1, size, f) == size)
|
||||
// #define xfwrite(ptr, size, f) check(fwrite(ptr, 1, size, f) == size)
|
||||
|
||||
// // Tar represents all its numbers as octal
|
||||
// size_t parse_octal(char *str, size_t maxlen) {
|
||||
// size_t num = 0;
|
||||
// for (size_t i = 0; i < maxlen && str[i] >= '0' && str[i] <= '7'; ++i) {
|
||||
// num *= 8;
|
||||
// num += str[i] - '0';
|
||||
// }
|
||||
|
||||
// return num;
|
||||
// }
|
||||
|
||||
// void read_path(char dest[257], char path[100], char prefix[100]) {
|
||||
// // If there's no prefix, use name directly
|
||||
// if (prefix[0] == '\0') {
|
||||
// memcpy(dest, path, 100);
|
||||
// dest[100] = '\0';
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // If there is a prefix, the path is: <prefix> '/' <path>
|
||||
// size_t prefix_len = strnlen(prefix, 155);
|
||||
// memcpy(dest, prefix, prefix_len);
|
||||
// dest[prefix_len] = '/';
|
||||
// memcpy(&dest[prefix_len + 1], path, 100);
|
||||
// dest[256] = '\0';
|
||||
// }
|
||||
|
||||
// // Extract one file from the archive.
|
||||
// // Returns 1 if it extracted something, or 0 if it reached the end.
|
||||
// int extract(mbed::File *f) {
|
||||
// unsigned char header_block[512];
|
||||
// xfread(header_block, sizeof(header_block), f);
|
||||
// struct file_header *header = (struct file_header *)header_block;
|
||||
|
||||
// // The end of the archive is represented with blocks of all-zero content.
|
||||
// // For simplicity, assume that if the file path is empty, the block is all zero
|
||||
// // and we reached the end.
|
||||
// if (header->file_path[0] == '\0') {
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
// // The file path and link path fields aren't always 0-terminated, so we need to copy them
|
||||
// // into our own buffers, otherwise we break on files with exactly 100 character paths.
|
||||
// // char file_path[101] = {0};
|
||||
// // memcpy(file_path, header->file_path, 100);
|
||||
// // char link_path[101] = {0};
|
||||
// // memcpy(link_path, header->link_path, 100);
|
||||
// char file_path[257];
|
||||
// read_path(file_path, header->file_path, header->prefix);
|
||||
// char link_path[257];
|
||||
// read_path(link_path, header->link_path, header->prefix);
|
||||
|
||||
// // We need these for later
|
||||
// size_t file_size = parse_octal(header->file_size, sizeof(header->file_size));
|
||||
// FILE *out_file = NULL;
|
||||
|
||||
// if (header->file_type == '0' || header->file_type == '\0') {
|
||||
// // A type of '0' means that this is a plain file.
|
||||
// // Some early implementations also use a NUL character ('\0') instead of an ASCII zero.
|
||||
|
||||
// fprintf(stderr, "Regular file: %s\n", file_path);
|
||||
// out_file = fopen(file_path, "w");
|
||||
// check(out_file != NULL);
|
||||
|
||||
// } else if (header->file_type == '1') {
|
||||
// // A type of '1' means that this is a hard link.
|
||||
// // That means we create a hard link at 'file_path' which links to the file at 'link_path'.
|
||||
|
||||
// fprintf(stderr, "Hard link: %s -> %s\n", file_path, link_path);
|
||||
// check(link(link_path, file_path) >= 0);
|
||||
|
||||
// } else if (header->file_type == '2') {
|
||||
// // A type of '2' means that this is a symbolic link.
|
||||
// // That means we create a symlink at 'file_path' which links to the file at 'link_path'.
|
||||
|
||||
// fprintf(stderr, "Symbolic link: %s -> %s\n", file_path, link_path);
|
||||
// check(symlink(link_path, file_path) >= 0);
|
||||
|
||||
// } else if (header->file_type == '5') {
|
||||
// // A type of '5' means that this is a directory.
|
||||
|
||||
// fprintf(stderr, "Directory: %s\n", file_path);
|
||||
// check(mkdir(file_path, 0777) >= 0);
|
||||
|
||||
// // Directories sometimes use the size field, but they don't contain data blocks.
|
||||
// // Zero out file_size to avoid skipping entries.
|
||||
// file_size = 0;
|
||||
|
||||
// } else {
|
||||
// // There are other possible fields added by various tar implementations and standards,
|
||||
// // but we'll ignore those for this implementation.
|
||||
// fprintf(stderr, "Unsupported file type %c: %s\n", header->file_type, file_path);
|
||||
// }
|
||||
|
||||
// // We have read the header block, now we need to read the payload.
|
||||
// // If we're reading a file (i.e if 'outfile' is non-NULL) we will also write the body,
|
||||
// // but otherwise we'll just skip it.
|
||||
// char block[512];
|
||||
// while (file_size > 0) {
|
||||
// xfread(block, sizeof(block), f);
|
||||
// size_t n = file_size > 512 ? 512 : file_size;
|
||||
|
||||
// file_size -= n;
|
||||
// if (out_file != NULL) {
|
||||
// xfwrite(block, n, out_file);
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (out_file != NULL) {
|
||||
// check(fclose(out_file) >= 0);
|
||||
// }
|
||||
|
||||
// // Indicate that we have successfully extracted a file object, and are ready to read the next
|
||||
// return 1;
|
||||
// }
|
||||
|
||||
// // int main() {
|
||||
// // while (extract(stdin));
|
||||
// // }
|
||||
0
lib/TFTPServer/tarex.h
Normal file
0
lib/TFTPServer/tarex.h
Normal file
448
lib/TFTPServer/untar.h
Normal file
448
lib/TFTPServer/untar.h
Normal file
@@ -0,0 +1,448 @@
|
||||
/*
|
||||
* This code based on
|
||||
*
|
||||
* "untar" is an extremely simple tar extractor
|
||||
*
|
||||
* Written by Tim Kientzle, March 2009.
|
||||
*
|
||||
* Released into the public domain.
|
||||
*
|
||||
* Ported to Arduino library by Alexander Emelainov (a.m.emelianov@gmail.com), August 2017
|
||||
* https://github.com/emelianov/untarArduino
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mbed.h"
|
||||
#include "ACSFileSystem.h"
|
||||
|
||||
// Uncomment following definition to enable not flat namespace filesystems
|
||||
//#define TAR_MKDIR
|
||||
|
||||
// Unomment to suppress output extracting process messages to Serial
|
||||
//#define TAR_SILENT
|
||||
|
||||
// Comment to remove callback support
|
||||
#define TAR_CALLBACK
|
||||
|
||||
enum tar_state {
|
||||
TAR_IDLE,
|
||||
TAR_SHORT_READ,
|
||||
TAR_WRITE_ERROR,
|
||||
TAR_FILE_EXTRACT,
|
||||
TAR_SOURCE_EOF,
|
||||
TAR_CHECKSUM_MISMACH,
|
||||
TAR_DONE
|
||||
};
|
||||
|
||||
#ifdef TAR_CALLBACK
|
||||
typedef void (*cbTarData)(char* buff, size_t size);
|
||||
typedef void (*cbTarRemaining)(size_t remaining);
|
||||
typedef bool (*cbTarProcess)(char* buff);
|
||||
typedef void (*cbTarEof)();
|
||||
#endif
|
||||
|
||||
class Tar {
|
||||
public:
|
||||
|
||||
// Tar() {
|
||||
// pathprefix = "";
|
||||
// }
|
||||
|
||||
//void dest(char* path); // Set directory extract to. tar -C
|
||||
|
||||
static void extract(mbed::File *tarfile); // Extract a tar archive
|
||||
|
||||
#ifdef TAR_CALLBACK
|
||||
static void onFile(cbTarProcess cb); // Sets callback that executed on each file in archive.
|
||||
static void onData(cbTarData cb); // Sets callback that executed on each 512 bytes data block in file
|
||||
static void onRemaining(cbTarRemaining cb);
|
||||
static void onEof(cbTarEof cb); // Sets callback that executed on each file end
|
||||
#endif
|
||||
|
||||
private:
|
||||
//char* pathprefix; // Stores filename prefix to be added to each file
|
||||
|
||||
static int parseoct(const char *p, size_t n); // Parse an octal number, ignoring leading and trailing nonsense.
|
||||
static int is_end_of_archive(const char *p); // Returns true if this is 512 zero bytes.
|
||||
|
||||
// #ifdef TAR_MKDIR
|
||||
// void create_dir(char *pathname, int mode); // Create a directory, including parent directories as necessary.
|
||||
// #endif
|
||||
|
||||
//mbed::File *create_file(char *pathname, int mode); // Create a file, including parent directory as necessary.
|
||||
//void create_file(char *pathname, int mode); // Create a file, including parent directory as necessary.
|
||||
|
||||
static int verify_checksum(const char *p); // Verify the tar checksum.
|
||||
|
||||
#ifdef TAR_CALLBACK
|
||||
static cbTarProcess cbProcess; // bool cbExclude(filename) calback. Return 'false' means skip file creation then
|
||||
static cbTarData cbData; // cbNull(data, size) callback. Called for each data block if file creation was skipped.
|
||||
static cbTarRemaining cbRemaining;
|
||||
static cbTarEof cbEof; // cnEof() callback. Called on end of file if file was skipped or not.
|
||||
#endif
|
||||
|
||||
//mbed::File currentfile;
|
||||
//tar_state _state = TAR_IDLE;
|
||||
};
|
||||
|
||||
|
||||
cbTarProcess Tar::cbProcess = NULL;
|
||||
cbTarData Tar::cbData = NULL;
|
||||
cbTarRemaining Tar::cbRemaining = NULL;
|
||||
cbTarEof Tar::cbEof = NULL;
|
||||
|
||||
#ifdef TAR_CALLBACK
|
||||
void Tar::onFile(cbTarProcess cb){
|
||||
cbProcess = cb;
|
||||
}
|
||||
|
||||
void Tar::onData(cbTarData cb){
|
||||
cbData = cb;
|
||||
}
|
||||
|
||||
void Tar::onRemaining(cbTarRemaining cb){
|
||||
cbRemaining = cb;
|
||||
}
|
||||
|
||||
void Tar::onEof(cbTarEof cb){
|
||||
cbEof = cb;
|
||||
}
|
||||
#endif
|
||||
|
||||
// void Tar::dest(char* path){
|
||||
// pathprefix = (char*)malloc (strlen(path) + 1);
|
||||
// if (pathprefix != NULL) {
|
||||
// strcpy (pathprefix, path);
|
||||
// } else {
|
||||
// #ifndef TAR_SILENT
|
||||
// Serial.println("Memory allocation error");
|
||||
// #endif
|
||||
// pathprefix = "";
|
||||
// }
|
||||
// }
|
||||
|
||||
int Tar::parseoct(const char *p, size_t n)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (*p < '0' || *p > '7') {
|
||||
++p;
|
||||
--n;
|
||||
}
|
||||
while (*p >= '0' && *p <= '7' && n > 0) {
|
||||
i *= 8;
|
||||
i += *p - '0';
|
||||
++p;
|
||||
--n;
|
||||
}
|
||||
return (i);
|
||||
}
|
||||
|
||||
int Tar::is_end_of_archive(const char *p)
|
||||
{
|
||||
int n;
|
||||
for (n = 511; n >= 0; --n)
|
||||
if (p[n] != '\0')
|
||||
return (0);
|
||||
return (1);
|
||||
}
|
||||
|
||||
// #ifdef TAR_MKDIR
|
||||
// void Tar::create_dir(char *pathname, int mode)
|
||||
// {
|
||||
// char *p;
|
||||
// int r;
|
||||
|
||||
// /* Strip trailing '/' */
|
||||
// if (pathname[strlen(pathname) - 1] == '/')
|
||||
// pathname[strlen(pathname) - 1] = '\0';
|
||||
|
||||
// /* Try creating the directory. */
|
||||
// //r = FSC->mkdir(pathname, mode);
|
||||
// r = ACSFileSystem::createDirectory(pathname, mode);
|
||||
|
||||
// if (r != 0) {
|
||||
// /* On failure, try creating parent directory. */
|
||||
// p = strrchr(pathname, '/');
|
||||
// if (p != NULL) {
|
||||
// *p = '\0';
|
||||
// create_dir(pathname, 0755);
|
||||
// *p = '/';
|
||||
// //r = FSC->mkdir(pathname, mode);
|
||||
// r = ACSFileSystem::createDirectory(pathname, mode);
|
||||
// }
|
||||
// }
|
||||
// if (r != 0)
|
||||
// #ifndef TAR_SILENT
|
||||
// Serial.print("Could not create directory %s");
|
||||
// Serial.println(pathname);
|
||||
// #endif
|
||||
// }
|
||||
// #endif
|
||||
|
||||
// mbed::File* Tar::create_file(char *pathname, int mode)
|
||||
// {
|
||||
// //mbed::File f;
|
||||
// //f = new File();
|
||||
// //*f = FSC->open(pathname, "w+");
|
||||
// if(ACSFileSystem::openFile(pathname, ¤tfile, O_RDWR | O_CREAT, true) != MBED_SUCCESS)
|
||||
// {
|
||||
// Serial.println("Open file failed");
|
||||
// }
|
||||
|
||||
// #ifdef TAR_MKDIR
|
||||
// if (f == NULL) {
|
||||
// /* Try creating parent dir and then creating file. */
|
||||
// char *p = strrchr(pathname, '/');
|
||||
// if (p != NULL) {
|
||||
// *p = '\0';
|
||||
// create_dir(pathname, 0755);
|
||||
// *p = '/';
|
||||
// //f = FSC->open(pathname, "w+");
|
||||
// ACSFileSystem::openFile(pathname, f, O_RDWR | O_CREAT, true);
|
||||
// }
|
||||
// }
|
||||
// #endif
|
||||
|
||||
// return (f);
|
||||
// }
|
||||
// void Tar::create_file(char *pathname, int mode)
|
||||
// {
|
||||
// //mbed::File f;
|
||||
// //f = new File();
|
||||
// //*f = FSC->open(pathname, "w+");
|
||||
// if(ACSFileSystem::openFile(pathname, ¤tfile, O_RDWR | O_CREAT, true) != MBED_SUCCESS)
|
||||
// {
|
||||
// Serial.println("Open file failed");
|
||||
// }
|
||||
|
||||
// // #ifdef TAR_MKDIR
|
||||
// // if (f == NULL) {
|
||||
// // /* Try creating parent dir and then creating file. */
|
||||
// // char *p = strrchr(pathname, '/');
|
||||
// // if (p != NULL) {
|
||||
// // *p = '\0';
|
||||
// // create_dir(pathname, 0755);
|
||||
// // *p = '/';
|
||||
// // //f = FSC->open(pathname, "w+");
|
||||
// // ACSFileSystem::openFile(pathname, f, O_RDWR | O_CREAT, true);
|
||||
// // }
|
||||
// // }
|
||||
// // #endif
|
||||
|
||||
// //return (f);
|
||||
// }
|
||||
|
||||
int Tar::verify_checksum(const char *p)
|
||||
{
|
||||
int n, u = 0;
|
||||
for (n = 0; n < 512; ++n) {
|
||||
if (n < 148 || n > 155)
|
||||
/* Standard tar checksum adds unsigned bytes. */
|
||||
u += ((unsigned char *)p)[n];
|
||||
else
|
||||
u += 0x20;
|
||||
|
||||
}
|
||||
return (u == parseoct(p + 148, 8));
|
||||
}
|
||||
|
||||
void Tar::extract(mbed::File *tarfile)
|
||||
{
|
||||
int filesize = 0;
|
||||
//_state = TAR_IDLE;
|
||||
//tar_state _state = TAR_IDLE;
|
||||
char buff[512];
|
||||
ssize_t bytes_read = 0;
|
||||
mbed::File currentfile;
|
||||
//char* fullpath = NULL;
|
||||
char fullpath[100];
|
||||
|
||||
#ifndef TAR_SILENT
|
||||
if (filesize == 0) {
|
||||
Serial.println("Extracting tar");
|
||||
} else {
|
||||
Serial.println("Resume file extraction");
|
||||
}
|
||||
#endif
|
||||
|
||||
for (;;) {
|
||||
bytes_read = tarfile->read(buff, 512);
|
||||
Serial.println(bytes_read);
|
||||
|
||||
if (bytes_read < 512) {
|
||||
#ifndef TAR_SILENT
|
||||
Serial.print(" * Short read: expected 512, got ");
|
||||
Serial.println(bytes_read);
|
||||
#endif
|
||||
//_state = TAR_SHORT_READ;
|
||||
return;
|
||||
}
|
||||
|
||||
if (filesize == 0) {
|
||||
if (is_end_of_archive(buff)) {
|
||||
#ifndef TAR_SILENT
|
||||
Serial.println("End of source file");
|
||||
#endif
|
||||
//_state = TAR_SOURCE_EOF;
|
||||
return;
|
||||
}
|
||||
if (!verify_checksum(buff)) {
|
||||
#ifndef TAR_SILENT
|
||||
Serial.println("* Checksum failure");
|
||||
#endif
|
||||
//_state = TAR_CHECKSUM_MISMACH;
|
||||
return;
|
||||
}
|
||||
//fullpath = (char*)malloc (strlen(pathprefix) + strlen(buff) + 1);
|
||||
//fullpath = (char*)malloc (strlen(buff) + 1);
|
||||
|
||||
//Serial.print("full path: ");
|
||||
//Serial.println(fullpath);
|
||||
|
||||
if (fullpath == NULL) {
|
||||
#ifndef TAR_SILENT
|
||||
Serial.println("* Memory allocation error. Ignoring entry");
|
||||
#endif
|
||||
} else {
|
||||
//_state = TAR_IDLE;
|
||||
//filesize = parseoct(buff + 124, 12);
|
||||
//strcpy (fullpath, pathprefix);
|
||||
//strcat (fullpath, buff);
|
||||
strncpy(fullpath, buff, sizeof(fullpath));
|
||||
|
||||
Serial.print("full path: ");
|
||||
Serial.println(fullpath);
|
||||
|
||||
switch (buff[156]) {
|
||||
case '1':
|
||||
#ifndef TAR_SILENT
|
||||
Serial.print("- Ignoring hardlink ");
|
||||
Serial.println(buff);
|
||||
#endif
|
||||
break;
|
||||
case '2':
|
||||
#ifndef TAR_SILENT
|
||||
Serial.print("- Ignoring symlink");
|
||||
Serial.println(buff);
|
||||
#endif
|
||||
break;
|
||||
case '3':
|
||||
#ifndef TAR_SILENT
|
||||
Serial.print("- Ignoring character device");
|
||||
Serial.println(buff);
|
||||
#endif
|
||||
break;
|
||||
case '4':
|
||||
#ifndef TAR_SILENT
|
||||
Serial.print("- Ignoring block device");
|
||||
Serial.println(buff);
|
||||
#endif
|
||||
break;
|
||||
case '5':
|
||||
filesize = 0;
|
||||
#ifdef TAR_MKDIR
|
||||
#ifndef TAR_SILENT
|
||||
Serial.print("- Extracting dir ");
|
||||
Serial.println(buff);
|
||||
#endif
|
||||
create_dir(buff, parseoct(buff + 100, 8));
|
||||
#else
|
||||
#ifndef TAR_SILENT
|
||||
Serial.print("- Ignoring dir ");
|
||||
Serial.println(buff);
|
||||
#endif
|
||||
#endif
|
||||
break;
|
||||
case '6':
|
||||
#ifndef TAR_SILENT
|
||||
Serial.print("- Ignoring FIFO ");
|
||||
Serial.println(buff);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
#ifndef TAR_SILENT
|
||||
Serial.print("- Extracting file ");
|
||||
Serial.println(buff);
|
||||
#endif
|
||||
//filesize = parseoct(buff + 124, 12);
|
||||
filesize = parseoct(&buff[124], 12);
|
||||
//_state = TAR_FILE_EXTRACT;
|
||||
#ifdef TAR_CALLBACK
|
||||
if (cbProcess == NULL || cbProcess(buff)) {
|
||||
#endif
|
||||
//f = create_file(fullpath, parseoct(buff + 100, 8));
|
||||
//create_file(fullpath, parseoct(buff + 100, 8));
|
||||
Serial.print("fullpath: ");
|
||||
Serial.println(fullpath);
|
||||
|
||||
if(ACSFileSystem::openFile(fullpath, ¤tfile, O_RDWR | O_CREAT, true) != MBED_SUCCESS)
|
||||
{
|
||||
Serial.println("Open file failed");
|
||||
return;
|
||||
}
|
||||
#ifdef TAR_CALLBACK
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
bytes_read = 0;
|
||||
}
|
||||
|
||||
while (filesize > 0) {
|
||||
//#ifndef TAR_SILENT
|
||||
//Serial.println(filesize);
|
||||
//#endif
|
||||
|
||||
if (bytes_read == 0){
|
||||
bytes_read = tarfile->read(buff, 512);
|
||||
}
|
||||
|
||||
if (bytes_read < 512) {
|
||||
#ifndef TAR_SILENT
|
||||
Serial.print("Data short read: Expected 512, got ");
|
||||
Serial.println(bytes_read);
|
||||
#endif
|
||||
//_state = TAR_SHORT_READ;
|
||||
return;
|
||||
}
|
||||
|
||||
if (filesize < 512)
|
||||
{
|
||||
bytes_read = filesize;
|
||||
}
|
||||
|
||||
if (currentfile.write((uint8_t*)buff, bytes_read) != bytes_read) {
|
||||
#ifndef TAR_SILENT
|
||||
Serial.println(" - Failed write");
|
||||
#endif
|
||||
//_state = TAR_WRITE_ERROR;
|
||||
currentfile.close();
|
||||
}
|
||||
|
||||
#ifdef TAR_CALLBACK
|
||||
if (cbData != NULL)
|
||||
cbData(buff, bytes_read);
|
||||
if (cbRemaining != NULL)
|
||||
cbRemaining(filesize);
|
||||
#endif
|
||||
|
||||
filesize -= bytes_read;
|
||||
bytes_read = 0;
|
||||
}
|
||||
currentfile.close();
|
||||
|
||||
//_state = TAR_DONE;
|
||||
if (fullpath){
|
||||
free(fullpath);
|
||||
}
|
||||
|
||||
#ifdef TAR_CALLBACK
|
||||
if (cbEof != NULL)
|
||||
cbEof();
|
||||
#endif
|
||||
|
||||
bytes_read = 0;
|
||||
}
|
||||
}
|
||||
3
lib/TFTPServer/zconf.h
Normal file
3
lib/TFTPServer/zconf.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#define MAX_MEM_LEVEL 3
|
||||
#define MAX_WBITS 10
|
||||
#define Z_PREFIX
|
||||
1744
lib/TFTPServer/zlib.h
Normal file
1744
lib/TFTPServer/zlib.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -57,8 +57,8 @@ void WebServer::begin()
|
||||
app.post("/clear", std::bind(&WebServer::clearPost, std::placeholders::_1, std::placeholders::_2));
|
||||
app.post("/reboot", std::bind(&WebServer::rebootPost, std::placeholders::_1, std::placeholders::_2));
|
||||
|
||||
app.post("/firmware", std::bind(&WebServer::firmwarePost, std::placeholders::_1, std::placeholders::_2));
|
||||
app.post("/filesystem", std::bind(&WebServer::filesystemPost, std::placeholders::_1, std::placeholders::_2));
|
||||
//app.post("/firmware", std::bind(&WebServer::firmwarePost, std::placeholders::_1, std::placeholders::_2));
|
||||
//app.post("/filesystem", std::bind(&WebServer::filesystemPost, std::placeholders::_1, std::placeholders::_2));
|
||||
app.post("/startupdate", std::bind(&WebServer::startFirmwareUpdate, std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
|
||||
@@ -486,15 +486,6 @@ void WebServer::firmwareGet(HTTPWebServer::Request &req, HTTPWebServer::Response
|
||||
|
||||
fileData["gitver"] = std::string(GIT_REV);
|
||||
|
||||
//fileData["filelist"] = _filesystem->directoryList("user");
|
||||
//JsonArray array = dst.to<JsonArray>();
|
||||
|
||||
// JsonArray array;
|
||||
// for (std::string item : _filesystem->directoryList("user")){
|
||||
// array.add(item);
|
||||
// }
|
||||
// fileData.add(array);
|
||||
|
||||
std::string json;
|
||||
serializeJson(fileData, json);
|
||||
res.writeContent(json);
|
||||
@@ -504,48 +495,66 @@ void WebServer::startFirmwareUpdate(HTTPWebServer::Request &req, HTTPWebServer::
|
||||
{
|
||||
Serial.println("Start Firmware update");
|
||||
|
||||
//NetworkInterface *_net = NetworkInterface::get_default_instance();
|
||||
TFTPClient tftpclient;
|
||||
tftpclient.connect("192.168.0.141", 69, "firmware.bin");
|
||||
if(TFTPClient::connect("192.168.0.141", 69) == false)
|
||||
{
|
||||
goto sendpage;
|
||||
}
|
||||
if(TFTPClient::receiveFirmware() == false)
|
||||
{
|
||||
TFTPClient::close();
|
||||
goto sendpage;
|
||||
}
|
||||
if(TFTPClient::checkCRC() == false)
|
||||
{
|
||||
TFTPClient::close();
|
||||
goto sendpage;
|
||||
}
|
||||
if(TFTPClient::unpack() == false)
|
||||
{
|
||||
TFTPClient::close();
|
||||
goto sendpage;
|
||||
}
|
||||
|
||||
//tftpclient.readRequest("firmware.bin");
|
||||
//tftpclient.receive();
|
||||
//tftpclient.closeConnection();
|
||||
|
||||
TFTPClient::close();
|
||||
|
||||
|
||||
|
||||
sendpage:
|
||||
getStaticFile((char *)"/update.html", res);
|
||||
}
|
||||
|
||||
void WebServer::firmwarePost(HTTPWebServer::Request &req, HTTPWebServer::Response &res)
|
||||
{
|
||||
Serial.println("Firmware post");
|
||||
//char filename[64];
|
||||
//Serial.print(filename);
|
||||
//req.
|
||||
//req.route("filename", filename, 64);
|
||||
//Serial.print(filename);
|
||||
// void WebServer::firmwarePost(HTTPWebServer::Request &req, HTTPWebServer::Response &res)
|
||||
// {
|
||||
// Serial.println("Firmware post");
|
||||
// //char filename[64];
|
||||
// //Serial.print(filename);
|
||||
// //req.
|
||||
// //req.route("filename", filename, 64);
|
||||
// //Serial.print(filename);
|
||||
|
||||
//File file = SPIFFS.open(filename, "w");
|
||||
// //File file = SPIFFS.open(filename, "w");
|
||||
|
||||
//char name[10];
|
||||
//char value[64];
|
||||
// while (req.left()) {
|
||||
// //req.form(name, 10, value, 64);
|
||||
// //char name[10];
|
||||
// //char value[64];
|
||||
// // while (req.left()) {
|
||||
// // //req.form(name, 10, value, 64);
|
||||
|
||||
// //Serial.print(name);
|
||||
// //Serial.print(": ");
|
||||
// //Serial.println(value);
|
||||
// // //Serial.print(name);
|
||||
// // //Serial.print(": ");
|
||||
// // //Serial.println(value);
|
||||
|
||||
// //file.write(req.read());
|
||||
// }
|
||||
//file.close();
|
||||
//res.sendStatus(204);
|
||||
// // //file.write(req.read());
|
||||
// // }
|
||||
// //file.close();
|
||||
// //res.sendStatus(204);
|
||||
|
||||
getStaticFile((char *)"/update.html", res);
|
||||
}
|
||||
// getStaticFile((char *)"/update.html", res);
|
||||
// }
|
||||
|
||||
void WebServer::filesystemPost(HTTPWebServer::Request &req, HTTPWebServer::Response &res)
|
||||
{
|
||||
Serial.println("filesystem post");
|
||||
// void WebServer::filesystemPost(HTTPWebServer::Request &req, HTTPWebServer::Response &res)
|
||||
// {
|
||||
// Serial.println("filesystem post");
|
||||
|
||||
getStaticFile((char *)"/update.html", res);
|
||||
}
|
||||
// getStaticFile((char *)"/update.html", res);
|
||||
// }
|
||||
@@ -37,8 +37,8 @@ class WebServer
|
||||
|
||||
static void firmwareGet(HTTPWebServer::Request &req, HTTPWebServer::Response &res);
|
||||
static void startFirmwareUpdate(HTTPWebServer::Request &req, HTTPWebServer::Response &res);
|
||||
static void firmwarePost(HTTPWebServer::Request &req, HTTPWebServer::Response &res);
|
||||
static void filesystemPost(HTTPWebServer::Request &req, HTTPWebServer::Response &res);
|
||||
//static void firmwarePost(HTTPWebServer::Request &req, HTTPWebServer::Response &res);
|
||||
//static void filesystemPost(HTTPWebServer::Request &req, HTTPWebServer::Response &res);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -31,6 +31,8 @@ check_src_filters =
|
||||
+<src/>
|
||||
+<lib/>
|
||||
-<lib/ArduinoJson/>
|
||||
extra_scripts =
|
||||
post:create_firmware_package.py
|
||||
|
||||
[env:native_dataTypes]
|
||||
platform = native
|
||||
|
||||
40
src/main.cpp
40
src/main.cpp
@@ -40,11 +40,11 @@ mbed::DigitalOut LedGreen(LED_GREEN);
|
||||
//mbed::DigitalOut UserLed(PE_5); //only on wifi version
|
||||
mbed::DigitalIn Button(PE_4);
|
||||
|
||||
rtos::Thread heartBeatThread(osPriorityNormal, 256, NULL, "HeartBeat");
|
||||
rtos::Thread ioThread(osPriorityNormal, 256, NULL, "I/O");
|
||||
rtos::Thread mf700Thread(osPriorityNormal, 512, NULL, "MF700");
|
||||
rtos::Thread consoleThread(osPriorityNormal, 5 * 1024, NULL, "Console");
|
||||
rtos::Thread aperioThread(osPriorityNormal, 5 * 1024, NULL, "Aperio");
|
||||
const rtos::Thread heartBeatThread(osPriorityNormal, 256, NULL, "HeartBeat");
|
||||
const rtos::Thread ioThread(osPriorityNormal, 256, NULL, "I/O");
|
||||
const rtos::Thread mf700Thread(osPriorityNormal, 512, NULL, "MF700");
|
||||
const rtos::Thread consoleThread(osPriorityNormal, 5 * 1024, NULL, "Console");
|
||||
const rtos::Thread aperioThread(osPriorityNormal, 5 * 1024, NULL, "Aperio");
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -357,7 +357,7 @@ void setup()
|
||||
|
||||
//Serial.println("Connecting to the network...");
|
||||
nsapi_error_t result = _net->connect();
|
||||
Serial.println(result);
|
||||
//Serial.println(result);
|
||||
if (result != 0) {
|
||||
Serial.print("Error! _eth->connect() returned: ");
|
||||
Serial.println(result);
|
||||
@@ -372,18 +372,18 @@ void setup()
|
||||
// Serial.println("Failed to increment counter");
|
||||
// }
|
||||
|
||||
MF700::begin(RS485_SERIAL_PORT);
|
||||
ACSFileSystem::begin();
|
||||
ConfigStore::init();
|
||||
Console::begin(Serial, printStack);
|
||||
WebServer::begin();
|
||||
Aperio::begin();
|
||||
//MF700::begin(RS485_SERIAL_PORT);
|
||||
//ACSFileSystem::begin();
|
||||
//ConfigStore::init();
|
||||
//Console::begin(Serial, printStack);
|
||||
//WebServer::begin();
|
||||
//Aperio::begin();
|
||||
|
||||
//ioThread.start(inputOutputTask);
|
||||
//mf700Thread.start(mf700ReaderTask);
|
||||
//consoleThread.start(consoleTask);
|
||||
//aperioThread.start(aperioTask);
|
||||
|
||||
ioThread.start(inputOutputTask);
|
||||
mf700Thread.start(mf700ReaderTask);
|
||||
consoleThread.start(consoleTask);
|
||||
aperioThread.start(aperioTask);
|
||||
|
||||
heartBeatState.clear(HEARTBEAT_STARTUP);
|
||||
}
|
||||
|
||||
@@ -391,9 +391,9 @@ void loop()
|
||||
{
|
||||
bool connected = (heartBeatState.get() & HEARTBEAT_NETWORKCONNECTED) == HEARTBEAT_NETWORKCONNECTED;
|
||||
|
||||
WebServer::listen(connected);
|
||||
rtos::ThisThread::yield();
|
||||
//WebServer::listen(connected);
|
||||
//rtos::ThisThread::yield();
|
||||
|
||||
NTP::checkUpdateTime(connected);
|
||||
//NTP::checkUpdateTime(connected);
|
||||
rtos::ThisThread::yield();
|
||||
}
|
||||
Reference in New Issue
Block a user