Subversion Repositories svn.mios32

Rev

Rev 1502 | Rev 1759 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
877 tk 1
/* -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- */
2
// $Id: UploadWindow.cpp 1724 2013-03-28 20:23:40Z tk $
3
/*
4
 * Upload Window Component
5
 *
6
 * ==========================================================================
7
 *
8
 *  Copyright (C) 2010 Thorsten Klose (tk@midibox.org)
9
 *  Licensed for personal non-commercial use only.
10
 *  All other rights reserved.
11
 *
12
 * ==========================================================================
13
 */
14
 
15
#include "UploadWindow.h"
878 tk 16
#include "MiosStudio.h"
877 tk 17
 
886 tk 18
#include <list>
878 tk 19
 
886 tk 20
 
21
#define TIMER_LOAD_HEXFILE             1
22
#define TIMER_LOAD_HEXFILE_AND_UPLOAD  2
23
#define TIMER_UPLOAD                   3
891 tk 24
#define TIMER_DELAYED_PROGRESS_OFF     4
25
#define TIMER_QUERY_CORE               5
886 tk 26
 
27
 
877 tk 28
//==============================================================================
878 tk 29
UploadWindow::UploadWindow(MiosStudio *_miosStudio)
30
    : miosStudio(_miosStudio)
891 tk 31
    , progress(0)
1050 tk 32
    , waitUploadRequestMessagePrint(0)
877 tk 33
{
34
    addAndMakeVisible(fileChooser = new FilenameComponent (T("hexfile"),
35
                                                           File::nonexistent,
36
                                                           true, false, false,
37
                                                           "*.hex",
38
                                                           String::empty,
39
                                                           T("(choose a .hex file to upload)")));
40
    fileChooser->addListener(this);
41
    fileChooser->setBrowseButtonText(T("Browse"));
927 tk 42
    fileChooser->setEnabled(true);
877 tk 43
 
44
    addAndMakeVisible(queryButton = new TextButton(T("Query Button")));
45
    queryButton->setButtonText(T("Query"));
1502 tk 46
    queryButton->addListener(this);
877 tk 47
 
927 tk 48
    addAndMakeVisible(deviceIdLabel = new Label(T("Device ID"), T("Device ID")));
49
    deviceIdLabel->setJustificationType(Justification::centred);
50
 
51
    addAndMakeVisible(deviceIdSlider = new Slider(T("Device ID")));
52
    deviceIdSlider->setRange(0, 127, 1);
908 tk 53
    deviceIdSlider->setValue(miosStudio->uploadHandler->getDeviceId()); // restored from setup file
891 tk 54
    deviceIdSlider->setSliderStyle(Slider::IncDecButtons);
55
    deviceIdSlider->setTextBoxStyle(Slider::TextBoxAbove, false, 80, 20);
894 tk 56
    deviceIdSlider->setDoubleClickReturnValue(true, 0);
57
    deviceIdSlider->addListener(this);
891 tk 58
 
894 tk 59
    addAndMakeVisible(uploadQuery = new LogBox(T("Upload Query")));
920 tk 60
    uploadQuery->addEntry(Colours::grey, T("Waiting for first query."));
891 tk 61
 
894 tk 62
    addAndMakeVisible(uploadStatus = new LogBox(T("Upload Status")));
891 tk 63
 
64
    addAndMakeVisible(startButton = new TextButton(T("Start Button")));
65
    startButton->setButtonText(T("Start"));
1502 tk 66
    startButton->addListener(this);
891 tk 67
    startButton->setEnabled(false);
68
 
69
    addAndMakeVisible(stopButton = new TextButton(T("Stop Button")));
70
    stopButton->setButtonText(T("Stop"));
1502 tk 71
    stopButton->addListener(this);
891 tk 72
    stopButton->setEnabled(false);
73
 
74
    addAndMakeVisible(progressBar = new ProgressBar(progress));
75
 
908 tk 76
    // restore settings
1724 tk 77
    PropertiesFile *propertiesFile = MiosStudioProperties::getInstance()->getCommonSettings(true);
908 tk 78
    if( propertiesFile ) {
79
        String recentlyUsedHexFiles = propertiesFile->getValue(T("recentlyUsedHexFiles"), String::empty);
80
        // seems that Juce doesn't provide a split function?
81
        StringArray recentlyUsedHexFilesArray;
82
        int index = 0;
83
        while( (index=recentlyUsedHexFiles.indexOfChar(';')) >= 0 ) {
84
            recentlyUsedHexFilesArray.add(recentlyUsedHexFiles.substring(0, index));
85
            recentlyUsedHexFiles = recentlyUsedHexFiles.substring(index+1);
86
        }
87
        if( recentlyUsedHexFiles != String::empty )
88
            recentlyUsedHexFilesArray.add(recentlyUsedHexFiles);
89
        fileChooser->setRecentlyUsedFilenames(recentlyUsedHexFilesArray);
90
 
91
        fileChooser->setDefaultBrowseTarget(propertiesFile->getValue(T("defaultFile"), String::empty));
92
    }
93
 
877 tk 94
    setSize(400, 200);
95
}
96
 
97
UploadWindow::~UploadWindow()
98
{
99
}
100
 
101
//==============================================================================
102
void UploadWindow::paint (Graphics& g)
103
{
928 tk 104
    g.fillAll(Colours::white);
877 tk 105
}
106
 
107
void UploadWindow::resized()
108
{
109
    fileChooser->setBounds(4, 4, getWidth()-8, 24);
891 tk 110
 
910 tk 111
    int middleX = getWidth()/2 - 75;
894 tk 112
 
927 tk 113
    int buttonY = 4+56;
891 tk 114
    int buttonWidth = 72;
927 tk 115
    deviceIdLabel->setBounds(4, 30, buttonWidth, 40);
891 tk 116
    deviceIdSlider->setBounds(4, buttonY+0*36, buttonWidth, 40);
117
    queryButton->setBounds(4, buttonY+1*36+10, buttonWidth, 24);
118
 
119
    int uploadQueryX = 4+buttonWidth+4;
894 tk 120
    int uploadQueryWidth = middleX - 4 - uploadQueryX;
891 tk 121
    uploadQuery->setBounds(uploadQueryX, 4+30, uploadQueryWidth, getHeight()-(4+24+4+10));
122
 
894 tk 123
    int uploadStatusX = middleX + 4;
891 tk 124
    int uploadStatusY = 4+30;
894 tk 125
    int uploadStatusWidth = getWidth() - 4 - buttonWidth - 4 - uploadStatusX;
891 tk 126
    int uploadStatusHeight = getHeight()-(4+24+4+10+24+4);
127
    uploadStatus->setBounds(uploadStatusX, uploadStatusY, uploadStatusWidth, uploadStatusHeight);
128
    progressBar->setBounds(uploadStatusX, uploadStatusY+4+uploadStatusHeight, uploadStatusWidth, 24);
129
 
927 tk 130
    buttonY = 4+40;
894 tk 131
    int startStopButtonX = getWidth() - 4 - buttonWidth;
891 tk 132
    startButton->setBounds(startStopButtonX, buttonY+0*36, buttonWidth, 24);
133
    stopButton->setBounds (startStopButtonX, buttonY+1*36, buttonWidth, 24);
877 tk 134
}
135
 
891 tk 136
void UploadWindow::buttonClicked(Button* buttonThatWasClicked)
877 tk 137
{
138
    if( buttonThatWasClicked == startButton ) {
886 tk 139
        File inFile = fileChooser->getCurrentFile();
140
        uploadStatus->clear();
920 tk 141
        uploadStatus->addEntry(Colours::black, T("Reading ") + inFile.getFileName());
891 tk 142
        uploadStart();
927 tk 143
    } else if( buttonThatWasClicked == stopButton ) {
886 tk 144
        uploadStop();
920 tk 145
        uploadStatus->addEntry(Colours::red, T("Upload has been stopped by user!"));
927 tk 146
    } else if( buttonThatWasClicked == queryButton ) {
891 tk 147
        queryCore();
877 tk 148
    }
149
}
150
 
891 tk 151
void UploadWindow::sliderValueChanged(Slider* slider)
152
{
153
    if( slider == deviceIdSlider ) {
154
        uploadStop();
908 tk 155
        miosStudio->uploadHandler->setDeviceId((uint8)slider->getValue());
891 tk 156
    }
157
}
158
 
877 tk 159
void UploadWindow::filenameComponentChanged(FilenameComponent *fileComponentThatHasChanged)
160
{
886 tk 161
    if( fileComponentThatHasChanged == fileChooser ) {
162
        File inFile = fileChooser->getCurrentFile();
163
 
164
        uploadStatus->clear();
920 tk 165
        uploadStatus->addEntry(Colours::black, T("Reading ") + inFile.getFileName());
886 tk 166
        MultiTimer::startTimer(TIMER_LOAD_HEXFILE, 1);
167
        startButton->setEnabled(false); // will be enabled if file is valid
908 tk 168
 
169
        // store setting
1724 tk 170
        PropertiesFile *propertiesFile = MiosStudioProperties::getInstance()->getCommonSettings(true);
908 tk 171
        if( propertiesFile ) {
172
            String recentlyUsedHexFiles = fileChooser->getRecentlyUsedFilenames().joinIntoString(";");
173
            propertiesFile->setValue(T("recentlyUsedHexFiles"), recentlyUsedHexFiles);
174
            propertiesFile->setValue(T("defaultFile"), inFile.getFullPathName());
175
        }
886 tk 176
    }
877 tk 177
}
178
 
878 tk 179
 
180
//==============================================================================
891 tk 181
void UploadWindow::midiPortChanged(void)
878 tk 182
{
900 tk 183
    miosStudio->uploadHandler->finish();
891 tk 184
    stopButton->setEnabled(false);
185
    queryButton->setEnabled(true);
186
    deviceIdSlider->setEnabled(true);
927 tk 187
    fileChooser->setEnabled(true);
878 tk 188
 
891 tk 189
    uploadQuery->clear();
920 tk 190
    uploadQuery->addEntry(Colours::red, T("No response from a core yet..."));
1050 tk 191
    uploadQuery->addEntry(Colours::red, T("Check MIDI IN/OUT connections"));
192
    uploadQuery->addEntry(Colours::red, T("and Device ID!"));
878 tk 193
    uploadStatus->clear();
891 tk 194
    queryCore();
878 tk 195
}
196
 
197
//==============================================================================
891 tk 198
void UploadWindow::queryCore(void)
878 tk 199
{
891 tk 200
    if( !miosStudio->uploadHandler->startQuery() ) {
894 tk 201
        uploadQuery->clear();
920 tk 202
        uploadQuery->addEntry(Colours::red, T("Please try again later - ongoing transactions!"));
891 tk 203
    } else {
908 tk 204
        uploadQuery->clear();
891 tk 205
        queryButton->setEnabled(false);
206
        deviceIdSlider->setEnabled(false);
927 tk 207
        fileChooser->setEnabled(false);
891 tk 208
        MultiTimer::startTimer(TIMER_QUERY_CORE, 10);
209
    }
878 tk 210
}
886 tk 211
 
212
 
213
//==============================================================================
891 tk 214
void UploadWindow::uploadStart(void)
886 tk 215
{
891 tk 216
    progress = 0;
1050 tk 217
    waitUploadRequestMessagePrint = 0;
886 tk 218
 
894 tk 219
    startButton->setEnabled(false); // will be enabled again if file is valid
220
    queryButton->setEnabled(false);
221
    deviceIdSlider->setEnabled(false);
927 tk 222
    fileChooser->setEnabled(false);
894 tk 223
 
920 tk 224
    uploadStatus->addEntry(Colours::grey, T("Trying to contact the core..."));
894 tk 225
 
226
    uploadQuery->clear();
920 tk 227
    uploadQuery->addEntry(Colours::black, T("Upload in progress..."));
894 tk 228
 
229
    MultiTimer::startTimer(TIMER_LOAD_HEXFILE_AND_UPLOAD, 1);
886 tk 230
}
231
 
232
 
233
void UploadWindow::uploadStop(void)
234
{
900 tk 235
    miosStudio->uploadHandler->finish();
891 tk 236
    startButton->setEnabled(miosStudio->uploadHandler->hexFileLoader.hexDumpAddressBlocks.size() >= 1);
886 tk 237
    stopButton->setEnabled(false);
891 tk 238
    queryButton->setEnabled(true);
239
    deviceIdSlider->setEnabled(true);
927 tk 240
    fileChooser->setEnabled(true);
886 tk 241
}
242
 
243
 
244
//==============================================================================
245
void UploadWindow::timerCallback(const int timerId)
246
{
247
    // always stop timer, it has to be restarted if required
248
    MultiTimer::stopTimer(timerId);
249
 
250
    // check for requested service
251
    if( timerId == TIMER_LOAD_HEXFILE || timerId == TIMER_LOAD_HEXFILE_AND_UPLOAD ) {
252
        File inFile = fileChooser->getCurrentFile();
253
        String statusMessage;
891 tk 254
        if( miosStudio->uploadHandler->hexFileLoader.loadFile(inFile, statusMessage) ) {
920 tk 255
            uploadStatus->addEntry(Colours::black, statusMessage);
886 tk 256
 
891 tk 257
            if( miosStudio->uploadHandler->hexFileLoader.hexDumpAddressBlocks.size() < 1 ) {
920 tk 258
                uploadStatus->addEntry(Colours::red, T("ERROR: no blocks found"));
955 tk 259
                uploadStop();
886 tk 260
            } else {
261
                // display and check ranges
903 tk 262
                if( !miosStudio->uploadHandler->checkAndDisplayRanges(uploadStatus) ) {
920 tk 263
                    uploadStatus->addEntry(Colours::red, T("ERROR: Range check failed!"));
955 tk 264
                    uploadStop();
903 tk 265
                } else if( timerId == TIMER_LOAD_HEXFILE_AND_UPLOAD ) {
891 tk 266
                    // start upload of first block
267
                    stopButton->setEnabled(true);
268
                    queryButton->setEnabled(false);
269
                    deviceIdSlider->setEnabled(false);
270
                    miosStudio->uploadHandler->startUpload();
271
                    MultiTimer::startTimer(TIMER_UPLOAD, 10);
272
                } else {
920 tk 273
                    uploadStatus->addEntry(Colours::black, T("Press start button to begin upload."));
891 tk 274
                    startButton->setEnabled(true);
275
                }
886 tk 276
            }
277
        } else {
920 tk 278
            uploadStatus->addEntry(Colours::red, T("ERROR: ") + statusMessage);
955 tk 279
            uploadStop();
886 tk 280
        }
281
    } else if( timerId == TIMER_UPLOAD ) {
891 tk 282
        progress = (double)miosStudio->uploadHandler->currentBlock / (double)miosStudio->uploadHandler->totalBlocks;
900 tk 283
 
1050 tk 284
        int busyState;
285
        if( (busyState=miosStudio->uploadHandler->busy()) > 0 ) {
286
            if( busyState == 2 && !waitUploadRequestMessagePrint ) {
287
                uploadStatus->addEntry(Colours::brown, T("WARNING: no response from core"));
288
                uploadStatus->addEntry(Colours::brown, T("Please reboot the core (e.g. turning off/on power)!"));
289
                uploadStatus->addEntry(Colours::brown, T("Waiting for upload request..."));
290
                waitUploadRequestMessagePrint = true;
291
            } else if( busyState == 1 && waitUploadRequestMessagePrint ) {
292
                uploadStatus->addEntry(Colours::brown, T("Received upload request!"));
293
                waitUploadRequestMessagePrint = false;
294
            }
295
 
900 tk 296
            // wait again for 10 mS - the uploader provides an own timeout mechanism
891 tk 297
            MultiTimer::startTimer(TIMER_UPLOAD, 10);
298
        } else {
900 tk 299
            String errorMessage = miosStudio->uploadHandler->finish();
300
 
301
            if( errorMessage != String::empty ) {
302
                // TODO: word-wrapping required here for multiple lines
920 tk 303
                uploadStatus->addEntry(Colours::red, errorMessage);
900 tk 304
                uploadQuery->clear();
894 tk 305
            } else {
903 tk 306
                uint32 totalBlocks = miosStudio->uploadHandler->totalBlocks - miosStudio->uploadHandler->excludedBlocks;
904 tk 307
                float timeUpload = miosStudio->uploadHandler->timeUpload;
894 tk 308
                float transferRateKb = ((totalBlocks * 256) / timeUpload) / 1024;
921 tk 309
                uploadStatus->addEntry(Colours::green, String::formatted(T("Upload of %d bytes completed after %3.2fs (%3.2f kb/s)"),
920 tk 310
                                                                         totalBlocks*256,
311
                                                                         timeUpload,
312
                                                                         transferRateKb));
900 tk 313
 
903 tk 314
                if( miosStudio->uploadHandler->recoveredErrorsCounter > 0 ) {
920 tk 315
                    uploadStatus->addEntry(Colours::grey, String::formatted(T("%d ignorable errors during upload solved (no issue!)"),
316
                                                                            miosStudio->uploadHandler->recoveredErrorsCounter));
903 tk 317
                }
318
 
900 tk 319
                uploadQuery->clear();
920 tk 320
                uploadQuery->addEntry(Colours::grey, T("Waiting for reboot..."));
894 tk 321
            }
886 tk 322
            uploadStop();
894 tk 323
 
324
            // delay must be long enough so that it is ensured that the application has booted and can repond on queries
325
            MultiTimer::startTimer(TIMER_DELAYED_PROGRESS_OFF, 5000);
891 tk 326
        }
327
    } else if( timerId == TIMER_DELAYED_PROGRESS_OFF ) {
900 tk 328
        if( !miosStudio->uploadHandler->busy() ) { // only if loader still unbusy
891 tk 329
            progress = 0;
894 tk 330
            queryCore(); // query for new application
331
        }
891 tk 332
    } else if( timerId == TIMER_QUERY_CORE ) {
900 tk 333
        if( miosStudio->uploadHandler->busy() ) {
334
            // wait again for 10 mS - the uploader provides an own timeout mechanism
335
            MultiTimer::startTimer(TIMER_QUERY_CORE, 10);
336
        } else {
337
            String errorMessage = miosStudio->uploadHandler->finish();
338
            uploadStop();
339
 
340
            if( errorMessage != String::empty ) {
891 tk 341
                uploadQuery->clear();
920 tk 342
                uploadQuery->addEntry(Colours::red, errorMessage);
1050 tk 343
                uploadQuery->addEntry(Colours::red, T("Check MIDI IN/OUT connections"));
344
                uploadQuery->addEntry(Colours::red, T("and Device ID!"));
886 tk 345
            } else {
900 tk 346
                String str;
347
                uploadQuery->clear();
348
                if( !(str=miosStudio->uploadHandler->coreOperatingSystem).isEmpty() )
1011 tk 349
                    uploadQuery->addEntry(Colours::black, "Operating System: " + str);
900 tk 350
                if( !(str=miosStudio->uploadHandler->coreBoard).isEmpty() )
920 tk 351
                    uploadQuery->addEntry(Colours::black, "Board: " + str);
900 tk 352
                if( !(str=miosStudio->uploadHandler->coreFamily).isEmpty() )
920 tk 353
                    uploadQuery->addEntry(Colours::black, "Core Family: " + str);
900 tk 354
                if( !(str=miosStudio->uploadHandler->coreChipId).isEmpty() )
920 tk 355
                    uploadQuery->addEntry(Colours::black, "Chip ID: 0x" + str);
900 tk 356
                if( !(str=miosStudio->uploadHandler->coreSerialNumber).isEmpty() )
920 tk 357
                    uploadQuery->addEntry(Colours::black, "Serial: #" + str);
900 tk 358
                if( !(str=miosStudio->uploadHandler->coreFlashSize).isEmpty() )
920 tk 359
                    uploadQuery->addEntry(Colours::black, "Flash Memory Size: " + str + " bytes");
900 tk 360
                if( !(str=miosStudio->uploadHandler->coreRamSize).isEmpty() )
920 tk 361
                    uploadQuery->addEntry(Colours::black, "RAM Size: " + str + " bytes");
900 tk 362
                if( !(str=miosStudio->uploadHandler->coreAppHeader1).isEmpty() )
920 tk 363
                    uploadQuery->addEntry(Colours::black, str);
900 tk 364
                if( !(str=miosStudio->uploadHandler->coreAppHeader2).isEmpty() )
920 tk 365
                    uploadQuery->addEntry(Colours::black, str);
886 tk 366
            }
367
        }
368
    }
369
}