MiniDisplay/minidisplay.cpp
author sl
Wed, 04 Jun 2014 18:30:37 +0200
changeset 33 cf5eba52cb1d
parent 32 1c2a7f563019
permissions -rw-r--r--
Marquee loop can now be paused and resumed.
Cleaning up our MiniDisplay coneection to render loop API.
sl@2
     1
#include "minidisplay.h"
sl@5
     2
#include <QPainter>
sl@9
     3
#include <QTimer>
sl@9
     4
sl@9
     5
const int KMaxReadAttempt=100;
sl@2
     6
sl@2
     7
MiniDisplay::MiniDisplay(QQuickItem *parent):
sl@33
     8
    QQuickItem(parent),
sl@33
     9
    iReadAttempt(0),
sl@33
    10
    iBrightness(iDisplay.MaxBrightness()),
sl@33
    11
    iAfterAnimatingCallback(NULL),
sl@33
    12
    iWindow(NULL),
sl@33
    13
    iFrameCount(0)
sl@2
    14
{
sl@2
    15
    // By default, QQuickItem does not draw anything. If you subclass
sl@2
    16
    // QQuickItem to create a visual item, you will need to uncomment the
sl@2
    17
    // following line and re-implement updatePaintNode()
sl@2
    18
sl@2
    19
    // setFlag(ItemHasContents, true);
sl@3
    20
    //
sl@4
    21
    //qDebug() << "New MiniDisplay";
sl@2
    22
}
sl@2
    23
sl@2
    24
MiniDisplay::~MiniDisplay()
sl@2
    25
{
sl@4
    26
    //qDebug() << "Delete MiniDisplay";
sl@11
    27
    close();
sl@2
    28
}
sl@2
    29
sl@4
    30
sl@4
    31
void MiniDisplay::open()
sl@4
    32
{
sl@4
    33
    if (iDisplay.Open())
sl@4
    34
    {
sl@10
    35
        iDisplay.SetBrightness(iBrightness);
sl@5
    36
        emit opened();
sl@5
    37
        emit statusChanged();
sl@4
    38
    }
sl@4
    39
    else
sl@4
    40
    {
sl@5
    41
        emit openError();
sl@4
    42
    }
sl@4
    43
}
sl@4
    44
sl@4
    45
sl@4
    46
void MiniDisplay::close()
sl@4
    47
{
sl@11
    48
    //qDebug() << "MiniDisplay::close";
sl@11
    49
    //Try to put back ourframe position to RAM 0,0 which is a multiple of 128
sl@11
    50
    if (iDisplay.IsOpen())
sl@11
    51
    {
sl@11
    52
        emit closing();
sl@11
    53
sl@11
    54
        if (iDisplay.DisplayPositionY()%128!=0)
sl@11
    55
        {
sl@11
    56
            //qDebug() << "SwapBuffer to put back our frame position to zero " << iDisplay.DisplayPositionY();
sl@11
    57
            iDisplay.SwapBuffers();
sl@11
    58
        }
sl@11
    59
    }
sl@4
    60
    iDisplay.Close();
sl@33
    61
    disconnectRenderLoop();
sl@5
    62
    emit closed();
sl@5
    63
    emit statusChanged();
sl@4
    64
}
sl@4
    65
sl@4
    66
bool MiniDisplay::isOpen()
sl@4
    67
{
sl@4
    68
    return iDisplay.IsOpen();
sl@4
    69
}
sl@4
    70
sl@4
    71
void MiniDisplay::clear()
sl@4
    72
{
sl@4
    73
    if (!iDisplay.IsOpen()) return;
sl@4
    74
    //
sl@4
    75
    iDisplay.Clear();
sl@4
    76
}
sl@4
    77
sl@4
    78
void MiniDisplay::fill()
sl@4
    79
{
sl@4
    80
    if (!iDisplay.IsOpen()) return;
sl@4
    81
    //
sl@4
    82
    iDisplay.SetAllPixels(0xFF);
sl@4
    83
}
sl@4
    84
sl@4
    85
void MiniDisplay::swapBuffers()
sl@4
    86
{
sl@4
    87
    if (!iDisplay.IsOpen()) return;
sl@4
    88
    //
sl@4
    89
    iDisplay.SwapBuffers();
sl@4
    90
}
sl@5
    91
sl@9
    92
void MiniDisplay::requestPowerStatus()
sl@9
    93
{
sl@9
    94
    if (!iDisplay.IsOpen()) return;
sl@9
    95
sl@9
    96
    iDisplay.RequestPowerSupplyStatus();
sl@9
    97
    QTimer::singleShot(4, this, SLOT(readTimer()));
sl@9
    98
    iReadAttempt=0;
sl@9
    99
}
sl@9
   100
sl@9
   101
void MiniDisplay::requestDeviceId()
sl@9
   102
{
sl@9
   103
    if (!iDisplay.IsOpen()) return;
sl@9
   104
sl@9
   105
    iDisplay.RequestDeviceId();
sl@9
   106
    QTimer::singleShot(4, this, SLOT(readTimer()));
sl@9
   107
    iReadAttempt=0;
sl@9
   108
}
sl@9
   109
sl@9
   110
void MiniDisplay::requestFirmwareVersion()
sl@9
   111
{
sl@9
   112
    if (!iDisplay.IsOpen()) return;
sl@9
   113
sl@9
   114
    iDisplay.RequestFirmwareRevision();
sl@9
   115
    QTimer::singleShot(4, this, SLOT(readTimer()));
sl@9
   116
    iReadAttempt=0;
sl@9
   117
}
sl@9
   118
sl@9
   119
sl@9
   120
sl@5
   121
/**
sl@5
   122
 * @brief setFont
sl@5
   123
 * @param aFont
sl@5
   124
 */
sl@5
   125
void MiniDisplay::setFont(const QFont& aFont)
sl@5
   126
{
sl@5
   127
    iFont=aFont;
sl@6
   128
    iFont.setStyleStrategy(QFont::NoAntialias);
sl@5
   129
    QString strDemo="0123456789ABCDEF";
sl@5
   130
    QFontMetrics metrics(iFont);
sl@14
   131
    int w=metrics.boundingRect(strDemo).width();
sl@6
   132
    int h=metrics.height();
sl@14
   133
    //int h=metrics.boundingRect(strDemo).height();
sl@6
   134
    QSize size(w,h);
sl@12
   135
    //Rendering in mono is quite broken we need RGB32
sl@12
   136
    QImage image(size,QImage::Format_RGB32);
sl@5
   137
    image.fill(0xFFFFFFFF);
sl@6
   138
    //Draw some text into our image
sl@5
   139
    {
sl@5
   140
        QPainter painter(&image);
sl@5
   141
        painter.setPen(0xFF000000);
sl@5
   142
        painter.setFont(iFont);
sl@5
   143
        painter.drawText(0,metrics.ascent(),strDemo);
sl@5
   144
    }
sl@6
   145
    //Save image as PNG for validation
sl@15
   146
    //image.save("font.png");
sl@6
   147
    //
sl@15
   148
    renderImage(&image);
sl@15
   149
}
sl@15
   150
sl@15
   151
/**
sl@15
   152
 * @brief MiniDisplay::renderWindow
sl@15
   153
 */
sl@15
   154
void MiniDisplay::renderOwnWindow()
sl@15
   155
{
sl@15
   156
    QImage image=window()->grabWindow();
sl@15
   157
    //image.save("window.png");
sl@15
   158
    renderImage(&image);
sl@15
   159
}
sl@15
   160
sl@15
   161
/**
sl@15
   162
 * @brief MiniDisplay::render
sl@15
   163
 * @param aWindow
sl@15
   164
 */
sl@15
   165
void MiniDisplay::renderWindow(QQuickWindow* aWindow)
sl@15
   166
{
sl@30
   167
    //if (!iDisplay.IsOpen()) return;
sl@30
   168
sl@15
   169
    QImage image=aWindow->grabWindow();
sl@15
   170
    //image.save("window.png");
sl@15
   171
    renderImage(&image);
sl@15
   172
}
sl@15
   173
sl@15
   174
/**
sl@15
   175
 * @brief MiniDisplay::render
sl@15
   176
 * @param aImage
sl@15
   177
 */
sl@15
   178
void MiniDisplay::renderImage(QImage* aImage)
sl@15
   179
{
sl@15
   180
    if (!iDisplay.IsOpen())
sl@15
   181
    {
sl@15
   182
        return;
sl@15
   183
    }
sl@15
   184
sl@15
   185
    //Convert our image into a bit array
sl@15
   186
    int w=aImage->width();
sl@15
   187
    int h=aImage->height();
sl@15
   188
sl@6
   189
    int pixelCount=w*h;
sl@6
   190
    BitArray bits(pixelCount);
sl@6
   191
sl@6
   192
    for (int i=0;i<w;i++)
sl@6
   193
        {
sl@6
   194
        for (int j=0;j<h;j++)
sl@6
   195
            {
sl@15
   196
            QRgb color=aImage->pixel(i,j);
sl@6
   197
            if (color!=0xffffffff)
sl@6
   198
                {
sl@6
   199
                bits.SetBit(i*h+j);
sl@6
   200
                }
sl@6
   201
            }
sl@6
   202
        }
sl@6
   203
sl@15
   204
    //Just blit it then
sl@15
   205
    iDisplay.BitBlit(bits,w,h,0,0);
sl@5
   206
}
sl@8
   207
sl@29
   208
sl@29
   209
/**
sl@33
   210
Connect to the render loop of the given window.
sl@33
   211
This is achieved using the afterAnimating event.
sl@33
   212
If any JavaScript callback is provided it will be called on every frame.
sl@33
   213
sl@33
   214
@brief MiniDisplay::connectRenderLoop
sl@33
   215
@param aWindow The window to connect to.
sl@33
   216
@param aFunction An optional JavaScript callback function
sl@29
   217
 */
sl@33
   218
void MiniDisplay::connectRenderLoop(QQuickWindow* aWindow, QJSValue aFunction)
sl@29
   219
{
sl@29
   220
    QObject::connect(aWindow, SIGNAL(afterAnimating()),
sl@29
   221
                     this,  SLOT(onAfterAnimating()));
sl@29
   222
sl@29
   223
    iAfterAnimatingCallback = aFunction;
sl@29
   224
    iWindow = aWindow;
sl@29
   225
}
sl@29
   226
sl@29
   227
/**
sl@33
   228
sl@33
   229
@brief MiniDisplay::disconnectRenderLoop
sl@33
   230
*/
sl@33
   231
void MiniDisplay::disconnectRenderLoop()
sl@33
   232
{
sl@33
   233
    if (iWindow)
sl@33
   234
    {
sl@33
   235
        QObject::disconnect(iWindow, SIGNAL(afterAnimating()),this,  SLOT(onAfterAnimating()));
sl@33
   236
        iWindow = NULL;
sl@33
   237
        iAfterAnimatingCallback = NULL;
sl@33
   238
        iFrameCount=0;
sl@33
   239
    }
sl@33
   240
sl@33
   241
}
sl@33
   242
sl@33
   243
/**
sl@33
   244
Once connected to a window render loop this is called on every frame.
sl@33
   245
sl@33
   246
@brief MiniDisplay::onAfterAnimating
sl@33
   247
*/
sl@29
   248
void MiniDisplay::onAfterAnimating()
sl@29
   249
{
sl@32
   250
    //qDebug() << frame << "MiniDisplay::onAfterAnimating";
sl@29
   251
    /*
sl@29
   252
    if (iAfterAnimatingCallback.isCallable())
sl@29
   253
    {
sl@29
   254
        iAfterAnimatingCallback.call();
sl@29
   255
    }*/
sl@29
   256
sl@31
   257
    //renderWindow(iWindow);
sl@31
   258
    //swapBuffers();
sl@29
   259
sl@30
   260
sl@29
   261
    //Interrestingly rendering will suspend when we stop changing our text field content
sl@31
   262
    //if (frame%8==0)
sl@29
   263
    {
sl@29
   264
        if (iAfterAnimatingCallback.isCallable())
sl@29
   265
        {
sl@33
   266
            iAfterAnimatingCallback.call(QJSValueList() << iFrameCount);
sl@29
   267
        }
sl@29
   268
    }
sl@29
   269
sl@33
   270
    iFrameCount++;
sl@29
   271
}
sl@29
   272
sl@29
   273
sl@15
   274
/**
sl@16
   275
 * @brief MiniDisplay::setPixel
sl@16
   276
 * @param x
sl@16
   277
 * @param y
sl@16
   278
 * @param on
sl@16
   279
 */
sl@16
   280
void MiniDisplay::setPixel(int x, int y, bool on)
sl@16
   281
{
sl@16
   282
    if (!iDisplay.IsOpen())
sl@16
   283
    {
sl@16
   284
        return;
sl@16
   285
    }
sl@16
   286
sl@18
   287
    iDisplay.SetPixel(x,y,on);
sl@16
   288
}
sl@16
   289
sl@16
   290
/**
sl@18
   291
 * @brief MiniDisplay::offScreenMode
sl@18
   292
 * @return
sl@18
   293
 */
sl@18
   294
bool MiniDisplay::offScreenMode()
sl@18
   295
{
sl@18
   296
   return iDisplay.OffScreenMode();
sl@18
   297
}
sl@18
   298
sl@18
   299
/**
sl@18
   300
 * @brief MiniDisplay::setOffScreenMode
sl@18
   301
 * @param aOn
sl@18
   302
 */
sl@18
   303
void MiniDisplay::setOffScreenMode(bool aOn)
sl@18
   304
{
sl@18
   305
    if (!iDisplay.IsOpen())
sl@18
   306
    {
sl@18
   307
        return;
sl@18
   308
    }
sl@18
   309
sl@18
   310
    iDisplay.SetOffScreenMode(aOn);
sl@18
   311
}
sl@18
   312
sl@18
   313
sl@18
   314
sl@18
   315
sl@18
   316
/**
sl@15
   317
 * @brief MiniDisplay::vendor
sl@15
   318
 * @return
sl@15
   319
 */
sl@8
   320
QString MiniDisplay::vendor()
sl@8
   321
{
sl@8
   322
    return QString::fromWCharArray(iDisplay.Vendor());
sl@8
   323
}
sl@8
   324
sl@15
   325
/**
sl@15
   326
 * @brief MiniDisplay::product
sl@15
   327
 * @return
sl@15
   328
 */
sl@8
   329
QString MiniDisplay::product()
sl@8
   330
{
sl@8
   331
    return QString::fromWCharArray(iDisplay.Product());
sl@8
   332
}
sl@8
   333
sl@15
   334
/**
sl@15
   335
 * @brief MiniDisplay::serialNumber
sl@15
   336
 * @return
sl@15
   337
 */
sl@8
   338
QString MiniDisplay::serialNumber()
sl@8
   339
{
sl@8
   340
    return QString::fromWCharArray(iDisplay.SerialNumber());
sl@8
   341
}
sl@8
   342
sl@9
   343
/**
sl@9
   344
 * @brief MiniDisplay::readTimer
sl@10
   345
 * Called when our read timer completes.
sl@10
   346
 * We then attempt to complete our pending display request.
sl@10
   347
 * We typically attempt to read an input report from our HID device.
sl@9
   348
 */
sl@9
   349
void MiniDisplay::readTimer()
sl@9
   350
{
sl@9
   351
    if (!iDisplay.IsOpen()) return;
sl@9
   352
    if (!iDisplay.RequestPending()) return;
sl@8
   353
sl@9
   354
    iReadAttempt++;
sl@9
   355
    GP1212A01A::Request request = iDisplay.AttemptRequestCompletion();
sl@9
   356
sl@9
   357
    if (!request)
sl@9
   358
    {
sl@9
   359
        if (iReadAttempt<KMaxReadAttempt)
sl@9
   360
        {
sl@9
   361
            //Will try again later
sl@9
   362
            QTimer::singleShot(4, this, SLOT(readTimer()));
sl@9
   363
        }
sl@9
   364
sl@9
   365
        return;
sl@9
   366
    }
sl@9
   367
sl@9
   368
    //TODO: Find a way to remove device specific stuff from here
sl@9
   369
    if (request==GP1212A01A::ERequestFirmwareRevision)
sl@9
   370
    {
sl@9
   371
        QString version=QString::fromLocal8Bit((const char*)iDisplay.InputReport().Buffer()+1);
sl@9
   372
        emit firmwareVersion(version);
sl@9
   373
    }
sl@9
   374
    else if (request==GP1212A01A::ERequestDeviceId)
sl@9
   375
    {
sl@9
   376
        QString id=QString::fromLocal8Bit((const char*)iDisplay.InputReport().Buffer()+1);
sl@9
   377
        emit deviceId(id);
sl@9
   378
    }
sl@9
   379
    else if (request==GP1212A01A::ERequestPowerSupplyStatus)
sl@9
   380
    {
sl@9
   381
        emit powerStatus(iDisplay.PowerOn());
sl@9
   382
    }
sl@9
   383
}
sl@9
   384
sl@10
   385
sl@10
   386
int MiniDisplay::maxBrightness() const
sl@10
   387
{
sl@10
   388
    return iDisplay.MaxBrightness();
sl@10
   389
}
sl@10
   390
sl@10
   391
int MiniDisplay::minBrightness() const
sl@10
   392
{
sl@10
   393
    return iDisplay.MinBrightness();
sl@10
   394
}
sl@10
   395
sl@10
   396
int MiniDisplay::brightness() const
sl@10
   397
{
sl@10
   398
    return iBrightness;
sl@10
   399
}
sl@10
   400
sl@10
   401
void MiniDisplay::setBrightness(int aBrightness)
sl@10
   402
{
sl@10
   403
    //Still track the brightness when disconnected
sl@10
   404
    iBrightness=aBrightness;
sl@10
   405
sl@10
   406
    if (!iDisplay.IsOpen()) return;
sl@10
   407
sl@10
   408
    iDisplay.SetBrightness(aBrightness);
sl@10
   409
}
sl@10
   410
sl@23
   411
/**
sl@23
   412
@brief MiniDisplay::frameDifferencing
sl@23
   413
@return
sl@23
   414
*/
sl@23
   415
bool MiniDisplay::frameDifferencing() const
sl@23
   416
{
sl@23
   417
    return iDisplay.FrameDifferencing();
sl@23
   418
}
sl@23
   419
sl@23
   420
/**
sl@23
   421
@brief MiniDisplay::setFrameDifferencing
sl@23
   422
@param aOn
sl@23
   423
*/
sl@23
   424
void MiniDisplay::setFrameDifferencing(bool aOn)
sl@23
   425
{
sl@23
   426
    iDisplay.SetFrameDifferencing(aOn);
sl@23
   427
}
sl@23
   428
sl@23
   429
sl@11
   430
QPoint MiniDisplay::framePosition() const
sl@11
   431
{
sl@11
   432
    return QPoint(iDisplay.DisplayPositionX(),iDisplay.DisplayPositionX());
sl@11
   433
}
sl@10
   434
sl@11
   435
void MiniDisplay::setFramePosition(const QPoint& aPoint)
sl@11
   436
{
sl@11
   437
    iFramePosition = aPoint;
sl@11
   438
sl@11
   439
    if (!iDisplay.IsOpen()) return;
sl@11
   440
sl@11
   441
    iDisplay.SetDisplayPosition(aPoint.x(),aPoint.y());
sl@11
   442
}
sl@11
   443
sl@11
   444
sl@11
   445