C
Porting DeviceLink Communication
The device link component enables communication between host and device. It allows them to exchange touch, screenshot, performance, or log data, for debugging or testing purposes.
Custom Device Link
The Platform::DeviceLinkInterface provides the interface between the protocol facilities and the hardware. The following functions must be implemented:
- DeviceLinkInterface::platformInit initializes the hardware receiving the data, for example the serial port.
- DeviceLinkInterface::transmitChars writes data that is ready to be sent to the serial port.
- DeviceLinkInterface::framebufferFormat retrieves information about the framebuffer of a given layer.
The following is an example implementation for the functions mentioned above:
struct ExampleDeviceLinkInterface : Qul::Platform::DeviceLinkInterface { void platformInit() { // Enable and start actual transfer and reception of the serial port, // eg. enabling interrupts } void transmitChars(const uint8_t *data, uint32_t size) { QUL_UNUSED(data); QUL_UNUSED(size); // Use the serial port to transfer the data to the host // HAL_UART_Transmit(&uartHandle, (uint8_t *) data, size, 0xFFFF); } Qul::Platform::FramebufferFormat framebufferFormat(const Qul::PlatformInterface::LayerEngine::ItemLayer *layer) QUL_DECL_OVERRIDE { // Assuming we use 32bpp framebuffers static const int BytesPerPixel = 4; static const int ScreenWidth = QUL_PLATFORM_DEFAULT_SCREEN_WIDTH; static const int ScreenHeight = QUL_PLATFORM_DEFAULT_SCREEN_HEIGHT; Qul::Platform::FramebufferFormat format; format.address = frontBuffer(); format.width = ScreenWidth; format.height = ScreenHeight; format.bytesPerLine = ScreenWidth * BytesPerPixel; format.bitsPerPixel = BytesPerPixel * 4; format.redChannel.offset = 16; format.redChannel.length = 8; format.greenChannel.offset = 8; format.greenChannel.length = 8; format.blueChannel.offset = 0; format.blueChannel.length = 8; format.swapBytes = 0; return format; } };
In case the ported platform has a layer engine, the framebufferFormat function needs to be implemented differently to account for this:
Qul::Platform::FramebufferFormat framebufferFormat(const PlatformInterface::LayerEngine::ItemLayer *layer) { const ExampleItemLayerBase *base = static_cast<const ExampleItemLayerBase *>(layer); Qul::Platform::FramebufferFormat format; format.address = base->drawingDevice.bits(); format.width = base->drawingDevice.width(); format.height = base->drawingDevice.height(); format.bytesPerLine = base->drawingDevice.bytesPerLine(); format.bitsPerPixel = base->drawingDevice.bitsPerPixel(); switch (format.bitsPerPixel) { case 16: format.redChannel.offset = 0; format.redChannel.length = 5; format.greenChannel.offset = 5; format.greenChannel.length = 6; format.blueChannel.offset = 11; format.blueChannel.length = 5; format.swapBytes = 2; break; case 32: format.redChannel.offset = 16; format.redChannel.length = 8; format.greenChannel.offset = 8; format.greenChannel.length = 8; format.blueChannel.offset = 0; format.blueChannel.length = 8; format.swapBytes = 0; break; default: QUL_ASSERT(false, QulError_LayerEngine_UnsupportedColorDepth, format.bitsPerPixel); } return format; }
To allow Qt Quick Ultralite to use your custom device link implementation, create a function to return the device link interface for your device.
DeviceLinkInterface *getDeviceLinkInterface() { static ExampleDeviceLinkInterface deviceLink; return &deviceLink; }
See also QUL_PLATFORM_DEVICELINK_ENABLED.
Hardware setup
In your implementation of PlatformContext::initializeHardware, add the initialization of the device link library after initializing the hardware of the desired channel, which is usually a serial port,
if (Qul::Platform::DeviceLink::instance()) Qul::Platform::DeviceLink::instance()->init();
This will also call the platformInit function implemented above to start data reception.
In your serial receiver function, transfer the received data to the device link component for decoding:
void UART_ReceiveInterrupt() { Qul::PlatformInterface::deviceLinkBytesReceived(&receivedByte, 1); }
Avoid writing any other data to the serial port, because this will interfere with the transfer protocol. To be sure, reimplement the low-level write functions that printf or others may use, to direct their content through the device link protocol.
On most platforms the low-level write functions that need to be reimplemented are:
void putChar(char &character); int _write(int file, char *ptr, int len);
The following example implementation should be adapted for each of these. All messages printed through the Qt Quick Ultralite logging system are automatically transferred via device link when active.
int _write(char *message, int len) { auto deviceLink = Qul::Platform::DeviceLink::instance(); if (deviceLink) deviceLink->printMessage(message, len); else sendDataDirectlyToSerialPort(); }
Updating the logging implementation
Modify the consoleWrite
function implemented in an earlier step to use the device link transfer as well.
void ExamplePlatform::consoleWrite(char character) { if (deviceLink) { // You should think about collecting several characters and send them in chunks // instead of 1 by 1 because this will be slow. deviceLink->printMessage(&character, 1); } else { // Write the charactor to your boards output device sendDataDirectlyToSerialPort(); } }
Requirements for rebuilding the platform
Install the protobuf
and grpcio-tools
Python packages to rebuild the platform with device link enabled.
Available under certain Qt licenses.
Find out more.