Skip to content

Commit

Permalink
Refactor animation uploader to make it easier to upload sketches by t…
Browse files Browse the repository at this point in the history
…hemselves
  • Loading branch information
cibomahto committed Dec 8, 2013
1 parent 7c8158a commit 8d4dfea
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 33 deletions.
20 changes: 13 additions & 7 deletions animationuploader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,13 @@ void AnimationUploader::startUpload(BlinkyTape& tape, Animation animation) {
// that we trash the firmware if there is a problem later

// First, convert the sketch binary data into a qbytearray
sketch = QByteArray(PatternPlayerSketch,PATTERNPLAYER_LENGTH);
QByteArray sketch = QByteArray(PatternPlayerSketch,PATTERNPLAYER_LENGTH);

// Next, append the image data to it
// TODO: Compress the animation
sketch += animation.data;

// Finally, write the metadata about the animation to the end of flash
metadata = QByteArray(FLASH_MEMORY_PAGE_SIZE, 0xFF); // TODO: Connect this to the block size
QByteArray metadata = QByteArray(FLASH_MEMORY_PAGE_SIZE, 0xFF);
metadata[metadata.length()-7] = (animation.encoding) & 0xFF;
metadata[metadata.length()-6] = (PATTERNPLAYER_LENGTH >> 8) & 0xFF;
metadata[metadata.length()-5] = (PATTERNPLAYER_LENGTH ) & 0xFF;
Expand All @@ -108,6 +107,10 @@ void AnimationUploader::startUpload(BlinkyTape& tape, Animation animation) {
return;
}

// Put the sketch, animation, and metadata into the programming queue.
flashData.push_back(FlashSection(0, sketch));
flashData.push_back(FlashSection(FLASH_MEMORY_AVAILABLE - FLASH_MEMORY_PAGE_SIZE, metadata));

/// Attempt to reset the strip using the 1200 baud rate method, and identify the newly connected bootloader
///
// Next, tell the tape to reset.
Expand Down Expand Up @@ -172,10 +175,13 @@ void AnimationUploader::doWork() {
// Send Check Device Signature command
programmer.checkDeviceSignature();

// TODO: Break this into pieces so we can respond individually, or just send it all
// at once and fail gloriously?
programmer.writeFlash(sketch, 0);
programmer.writeFlash(metadata, FLASH_MEMORY_AVAILABLE - FLASH_MEMORY_PAGE_SIZE);
// Queue all of the flash sections to memory
while(!flashData.empty()) {
FlashSection f = flashData.front();
programmer.writeFlash(f.data, f.address);
flashData.pop_front();
}

programmer.reset();

// TODO: Read back
Expand Down
16 changes: 14 additions & 2 deletions animationuploader.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@
#define ANIMATIONUPLOADER_H


struct FlashSection {
FlashSection(int address_,
QByteArray data_) :
address(address_),
data(data_) {}
int address;
QByteArray data;
};

// This is an re-entreant version of an animation uploader.
// Each task in the upload process is broken into a single state, and the state
// machine is driven forward by receiving events from the connected serial port,
Expand All @@ -30,6 +39,7 @@ class AnimationUploader : public QObject

// Start an upload, using the passed blinkytape as a launching point
// Note that the blinkytape will be disconnected during the upload process.
//
void startUpload(BlinkyTape& tape, Animation animation);

signals:
Expand Down Expand Up @@ -76,8 +86,10 @@ private slots:

AvrProgrammer programmer;

QByteArray sketch;
QByteArray metadata;
QQueue<FlashSection> flashData;

// QByteArray sketch;
// QByteArray metadata;

QByteArray responseData; // Response data left over.

Expand Down
26 changes: 13 additions & 13 deletions avrprogrammer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,11 @@ bool AvrProgrammer::isConnected() {
return serial->isOpen();
}

void AvrProgrammer::queueCommand(QString commandName,
QByteArray commandData,
QByteArray expectedResponseData) {
void AvrProgrammer::queueCommand(QString name,
QByteArray data,
QByteArray expectedRespone) {

commandQueue.push_back(Command(commandName, commandData, expectedResponseData));
commandQueue.push_back(Command(name, data, expectedRespone));

// If this is the only command, start processing commands
// TODO: Merge this with the implementation in handleReadData()
Expand All @@ -71,12 +71,12 @@ void AvrProgrammer::processCommandQueue() {
// Note: don't call this if there is a command already running; perhaps add some state?
responseData.clear();

qDebug() << "Command started:" << commandQueue.front().commandName;
qDebug() << "Command started:" << commandQueue.front().name;
if(!isConnected()) {
qCritical() << "Device disappeared, cannot run command";
return;
}
if(serial->write(commandQueue.front().commandData) != commandQueue.front().commandData.length()) {
if(serial->write(commandQueue.front().data) != commandQueue.front().data.length()) {
qCritical() << "Error writing to device";
return;
}
Expand All @@ -96,26 +96,26 @@ void AvrProgrammer::handleReadData() {

responseData.append(serial->readAll());

if(responseData.length() > commandQueue.front().expectedResponseData.length()) {
if(responseData.length() > commandQueue.front().expectedResponse.length()) {
// TODO: error, we got unexpected data.
qCritical() << "Got more data than we expected";
return;
}

if(responseData.length() < commandQueue.front().expectedResponseData.length()) {
if(responseData.length() < commandQueue.front().expectedResponse.length()) {
qDebug() << "Didn't get enough data yet, so just waiting";
return;
}

// If the command was to read from flash, short-circuit the response data check.
if(commandQueue.front().commandName == "readFlash") {
if(commandQueue.front().name == "readFlash") {
// TODO: Test me?
if(responseData.at(responseData.length()-1) != '\r') {
qCritical() << "readFlash response didn't end with a \\r";
return;
}
}
else if(responseData != commandQueue.front().expectedResponseData) {
else if(responseData != commandQueue.front().expectedResponse) {
qCritical() << "Got unexpected data back";
return;
}
Expand All @@ -124,13 +124,13 @@ void AvrProgrammer::handleReadData() {
commandTimeoutTimer->stop();

// If the command was reset, disconnect from the programmer
if(commandQueue.front().commandName == "reset") {
if(commandQueue.front().name == "reset") {
qDebug() << "Disconnecting from programmer";
closeSerial();
}

qDebug() << "Command completed successfully: " << commandQueue.front().commandName;
emit(commandFinished(commandQueue.front().commandName,responseData));
qDebug() << "Command completed successfully: " << commandQueue.front().name;
emit(commandFinished(commandQueue.front().name,responseData));
commandQueue.pop_front();

// Start another command, if there is one.
Expand Down
22 changes: 11 additions & 11 deletions avrprogrammer.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,16 +63,16 @@ private slots:

private:
struct Command {
Command(QString name,
QByteArray command,
QByteArray expectedResponse) :
commandName(name),
commandData(command),
expectedResponseData(expectedResponse) {}

QString commandName;
QByteArray commandData;
QByteArray expectedResponseData;
Command(QString name_,
QByteArray command_,
QByteArray expectedResponse_) :
name(name_),
data(command_),
expectedResponse(expectedResponse_) {}

QString name;
QByteArray data;
QByteArray expectedResponse;
};

QSerialPort* serial; // Serial device the programmer is attached to
Expand All @@ -83,7 +83,7 @@ private slots:
QTimer *commandTimeoutTimer; // Timer fires if a command has failed to complete quickly enough

// Queue a new command
void queueCommand(QString commandName, QByteArray commandData, QByteArray expectedResponseData);
void queueCommand(QString name, QByteArray data, QByteArray expectedRespone);

// If there is another command in the queue, start processing it.
void processCommandQueue();
Expand Down
12 changes: 12 additions & 0 deletions mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -331,3 +331,15 @@ void MainWindow::on_actionFlip_Vertical_triggered()
QImage pattern = ui->animationEditor->getPattern();
ui->animationEditor->init(pattern.mirrored(false, true));
}

void MainWindow::on_actionLoad_rainbow_sketch_triggered()
{
// if(!(tape->isConnected())) {
// return;
// }

// uploader->startUpload(*tape, animation);

// progress->setValue(progress->minimum());
// progress->show();
}
2 changes: 2 additions & 0 deletions mainwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ private slots:

void on_actionFlip_Vertical_triggered();

void on_actionLoad_rainbow_sketch_triggered();

private:
Ui::MainWindow *ui;

Expand Down
12 changes: 12 additions & 0 deletions mainwindow.ui
Original file line number Diff line number Diff line change
Expand Up @@ -314,8 +314,15 @@
<addaction name="actionFlip_Horizontal"/>
<addaction name="actionFlip_Vertical"/>
</widget>
<widget class="QMenu" name="menuTools">
<property name="title">
<string>Tools</string>
</property>
<addaction name="actionLoad_rainbow_sketch"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menuEdit"/>
<addaction name="menuTools"/>
<addaction name="menuHelp"/>
</widget>
<action name="actionLoad_Animation">
Expand Down Expand Up @@ -389,6 +396,11 @@
<string>Flip the Animation in the vertical direction</string>
</property>
</action>
<action name="actionLoad_rainbow_sketch">
<property name="text">
<string>Load rainbow sketch</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
Expand Down

0 comments on commit 8d4dfea

Please sign in to comment.