last save

This commit is contained in:
Martijn Scheepers
2024-07-09 12:02:52 +02:00
parent db054cd14d
commit a255872fa2
28 changed files with 6547 additions and 957 deletions

View 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")
#)

View File

@@ -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>

View File

@@ -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'>

View File

@@ -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

Binary file not shown.

View File

@@ -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)
{

View File

@@ -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:
};

File diff suppressed because it is too large Load Diff

View 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

View File

@@ -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()

View File

@@ -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
View 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
View 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

View File

@@ -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);
}

View File

@@ -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
View 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
View 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
View 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
View 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
View 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
View File

448
lib/TFTPServer/untar.h Normal file
View 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, &currentfile, 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, &currentfile, 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, &currentfile, 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
View File

@@ -0,0 +1,3 @@
#define MAX_MEM_LEVEL 3
#define MAX_WBITS 10
#define Z_PREFIX

1744
lib/TFTPServer/zlib.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -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);
// }

View File

@@ -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

View File

@@ -31,6 +31,8 @@ check_src_filters =
+<src/>
+<lib/>
-<lib/ArduinoJson/>
extra_scripts =
post:create_firmware_package.py
[env:native_dataTypes]
platform = native

View File

@@ -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();
}