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