Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
289 lines (241 sloc) 8.81 KB
/*
* Downloads a file from the web via CommStack and ESP and handles request and
* responses and UI with progress bar
*
* More Info and documentation:
* http://www.appfruits.com/2016/11/behind-the-scenes-printrbot-simple-2016/
*
* Copyright (c) 2016 Printrbot Inc.
* Author: Phillip Schuster
* https://github.com/Printrbot/Printrhub
*
* Developed in cooperation with Phillip Schuster (@appfruits) from appfruits.com
* http://www.appfruits.com
*
* 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 "DownloadFileController.h"
#include "SD.h"
#include "projects/ProjectsScene.h"
#include "projects/JobsScene.h"
#include "materials/MaterialsScene.h"
#include "print/PrintStatusScene.h"
//#include "print/PrintStatusSceneController.h"
//#include "print/CleanPlasticSceneController.h"
//#include "ConfirmSceneController.h"
#include "framework/views/ProgressBar.h"
#include "UIBitmaps.h"
#include "font_LiberationSans.h"
extern UIBitmaps uiBitmaps;
extern int lastProjectIndex;
extern int lastJobIndex;
extern int totalProjects;
DownloadFileController::DownloadFileController(String url, String fileName) :
SidebarSceneController::SidebarSceneController(),
_fileSize(0),
_bytesRead(0),
_previousPercent(0),
_url(url),
_fileName(fileName),
_nextScene(NextScene::NewProject) {
_localFilePath = String(IndexDb::projectFolderName) + fileName;
}
DownloadFileController::DownloadFileController(String url) :
SidebarSceneController::SidebarSceneController(),
_fileSize(0),
_bytesRead(0),
_previousPercent(0),
_url(url),
_nextScene(NextScene::Materials) {
_localFilePath = String("matlib");
}
DownloadFileController::DownloadFileController(String url, String localFilePath, String jobFilePath, Project project, Job job)
:
SidebarSceneController::SidebarSceneController(),
_fileSize(0),
_bytesRead(0),
_previousPercent(0),
_localFilePath(localFilePath),
_url(url),
_jobFilePath(jobFilePath),
_project(project),
_job(job),
_nextScene(NextScene::StartPrint) {
}
DownloadFileController::DownloadFileController() :
SidebarSceneController::SidebarSceneController(),
_fileSize(0),
_bytesRead(0),
_previousPercent(0) {
}
DownloadFileController::~DownloadFileController() {
}
uint16_t DownloadFileController::getBackgroundColor() {
return Application.getTheme()->getColor(BackgroundColor);
}
String DownloadFileController::getName() {
return "DownloadFileController";
}
UIBitmap *DownloadFileController::getSidebarIcon() {
return &uiBitmaps.btn_exit;
}
UIBitmap *DownloadFileController::getSidebarBitmap() {
return &uiBitmaps.sidebar_downloading;
}
void DownloadFileController::onWillAppear() {
if (_nextScene == NextScene::NewProject) {
if (SD.exists(_localFilePath.c_str())) {
SD.remove(_localFilePath.c_str());
}
}
if (_nextScene == NextScene::Materials) {
if (SD.exists(_localFilePath.c_str())) {
SD.remove(_localFilePath.c_str());
}
}
BitmapView *icon = new BitmapView(Rect(0, 0, uiBitmaps.downloading_scene.width, uiBitmaps.downloading_scene.height));
icon->setBitmap(&uiBitmaps.downloading_scene);
addView(icon);
_progressBar = new ProgressBar(Rect(0, 228, 270, 12));
_progressBar->setBackgroundColor(RGB565(75, 165, 232));
_progressBar->setValue(0.0f);
addView(_progressBar);
//Trigger file download
const char *url = _url.c_str();
Application.getESPStack()->requestTask(TaskID::DownloadFile, strlen(url), (uint8_t *) url);
SidebarSceneController::onWillAppear();
}
void DownloadFileController::onSidebarButtonTouchUp() {
//Send cancel download message to ESP to stop download
Application.getESPStack()->requestTask(TaskID::CancelDownload);
//Close file and remove download fragments
_file.close();
SD.remove(_localFilePath.c_str());
ProjectsScene *scene = new ProjectsScene();
Application.pushScene(scene);
}
bool DownloadFileController::handlesTask(TaskID taskID) {
switch (taskID) {
case TaskID::GetJobWithID:
case TaskID::FileSaveData:
case TaskID::FileClose:
case TaskID::SaveProjectWithID:
case TaskID::SaveMaterials:
case TaskID::FileSetSize:
case TaskID::Error:
case TaskID::DownloadFile:return true;
break;
default:return false;
}
}
bool DownloadFileController::runTask(CommHeader &header, const uint8_t *data, size_t dataSize, uint8_t *responseData, uint16_t *responseDataSize, bool *sendResponse, bool *success) {
LOG_VALUE("DownloadFileController handling task", header.getCurrentTask());
if (header.getCurrentTask() == TaskID::FileSetSize) {
uint32_t contentLength;
memcpy(&contentLength, data, sizeof(uint32_t));
_fileSize = contentLength;
_bytesRead = 0;
*sendResponse = true;
*responseDataSize = 0;
} else if (header.getCurrentTask() == TaskID::DownloadFile) {
LOG("Handling GetJobWithID Task");
if (header.commType == ResponseSuccess) {
if (dataSize != sizeof(uint32_t)) {
LOG_VALUE("Expected content of GetJobWithID to be uint32_t with the number of bytes to receive, but received a content length of", *responseDataSize);
} else {
uint32_t contentLength;
memcpy(&contentLength, data, sizeof(uint32_t));
_fileSize = contentLength;
_bytesRead = 0;
LOG_VALUE("Expected file size of", _fileSize);
//Open a file on SD card
//char * fp[_localFilePath.length() + 1];
//_localFilePath.toCharArray(fp, _localFilePath.length());
//SD.remove(fp);
_file = SD.open(_localFilePath.c_str(), O_WRITE | O_CREAT | O_TRUNC);
if (!_file.available()) {
//TODO: We should handle that. For now we will have to read data from ESP to clean the pipe but there should be better ways to handle errors
//Application.getESPStack()->requestTask(Error);
//return false;
}
LOG("File opened for writing. Now waiting for number of bytes to read");
LOG("Now Expecting file chunks with FileSaveData tasks");
}
} else {
//TODO: Show an error message
ProjectsScene *scene = new ProjectsScene();
Application.pushScene(scene);
}
} else if (header.getCurrentTask() == TaskID::FileSaveData) {
LOG("Handling FileSaveData Task");
if (header.commType == Request) {
LOG_VALUE("Received Chunk of Data with Size", dataSize);
int numBytesWritten = _file.write(data, dataSize);
LOG_VALUE("Written number of bytes to file", numBytesWritten);
*sendResponse = true;
*responseDataSize = 0;
//Add number of bytes received to total bytes read
_bytesRead += dataSize;
float fraction = (float) _bytesRead / (float) _fileSize;
int percent = (int) (fraction * 100.0f);
if (percent != _previousPercent) {
_progressBar->setValue(fraction);
}
_previousPercent = percent;
}
} else if (header.getCurrentTask() == TaskID::FileClose) {
LOG("Handling FileClose Task");
LOG_VALUE("Bytes read", _bytesRead);
_file.close();
if (_nextScene == NextScene::StartPrint) {
PrintStatusScene *scene = new PrintStatusScene(_jobFilePath, _project, _job);
Application.pushScene(scene);
}
if (_nextScene == NextScene::NewProject) {
// add project to the indexdb
IndexDb *idb = new IndexDb();
idb->addProjectFile(_fileName);
delete idb;
lastProjectIndex = 0;
ProjectsScene *scene = new ProjectsScene();
Application.pushScene(scene);
}
if (_nextScene == NextScene::Materials) {
MaterialsScene *scene = new MaterialsScene();
Application.pushScene(scene);
}
} else if (header.getCurrentTask() == TaskID::SaveProjectWithID) {
char _fp[header.contentLength + 1];
memset(_fp, 0, header.contentLength + 1);
memcpy(_fp, data, header.contentLength);
_localFilePath = String(_fp);
_localFilePath = String(IndexDb::projectFolderName) + _localFilePath;
//Open a file on SD card
SD.remove(_fp);
//SD.remove(_localFilePath.c_str());
_file = SD.open(_localFilePath.c_str(), FILE_WRITE);
*sendResponse = true;
*responseDataSize = 0;
_nextScene = NextScene::NewProject;
}
return true;
}
#pragma mark ButtonDelegate Implementation
void DownloadFileController::buttonPressed(void *button) {
SidebarSceneController::buttonPressed(button);
}