# Code examples The following section will describe the basic usage of License-manager from C++ code snippets. CrossControl also provides a larger Qt application with a full implementation using a larger set of the funtionality. ## Acquire license To read if the system contains a valid license for the software, the method **acquire_license** is used. Basic usage is to call the method without parameters to check the default feature. ```cpp #include #include #include using namespace std; LicenseInfo licenseInfo; LCC_EVENT_TYPE result = acquire_license(nullptr, nullptr, &licenseInfo); if (result == LICENSE_OK) { cout << "license for main software OK" << endl; } ``` In case of failure to acquire a valid license, the following set of possible return values are mapped as: ```cpp unordered_map stringByEventType = { {LICENSE_OK, "OK "}, {LICENSE_FILE_NOT_FOUND, "license file not found "}, {LICENSE_SERVER_NOT_FOUND, "license server can't be contacted "}, {ENVIRONMENT_VARIABLE_NOT_DEFINED, "environment variable not defined "}, {FILE_FORMAT_NOT_RECOGNIZED, "license file has invalid format (not .ini file) "}, {LICENSE_MALFORMED, "some mandatory field are missing, or data can't be fully read. "}, {PRODUCT_NOT_LICENSED, "this product was not licensed "}, {PRODUCT_EXPIRED, "license expired "}, {LICENSE_CORRUPTED, "license signature didn't match with current license "}, {IDENTIFIERS_MISMATCH, "Calculated identifier and the one provided in license didn't match"} }; ``` The **acquire_license** method call can be used to query specific parts of the license by adding CallerInformation to the call. ```cpp CallerInformations callerInfo = {"\0", "FULL_SELF_DRIVING_SUPPORT", 0}; result = acquire_license(&callerInfo, nullptr, &licenseInfo); if (result == LICENSE_OK) { cout << "FULL_SELF_DRIVING_SUPPORT is licensed" << endl; } else { cout << "FULL_SELF_DRIVING_SUPPORT is NOT licensed" << endl; } ``` ## Read hardware identifier To read the unique hardware ID of a CCpilot device, the license manager call **identify_pc** is used. See Public API for additional information. The C++ code for this will look like: ```cpp size_t hw_id_sz = LCC_API_PC_IDENTIFIER_SIZE + 1; char hw_identifier[LCC_API_PC_IDENTIFIER_SIZE + 1]; if (identify_pc(STRATEGY_DEFAULT, hw_identifier, &hw_id_sz, nullptr)) { cout << "hardware identifier is :" << hw_identifier << endl; } ``` ## Using a Demo license If the issued license file does not have a hardware signature, it can be used as a "demo license" for the application that can work on any device with limited functionality. Example usage: ```cpp LicenseInfo licenseInfo; size_t pc_id_sz = LCC_API_PC_IDENTIFIER_SIZE + 1; char pc_identifier[LCC_API_PC_IDENTIFIER_SIZE + 1]; LCC_EVENT_TYPE result = acquire_license(nullptr, nullptr, &licenseInfo); if (result == LICENSE_OK) { cout << "license OK" << endl; if (!licenseInfo.linked_to_pc) { cout << "No hardware signature in license file. This is a 'demo' license that works on every device." << endl; } } ``` ## Display date limited license If license already has expired you will get the PRODUCT_EXPIRED as a result instead of LICENSE_OK. If license has not expired you can check for the *has_expiry* field and look at the *days_left* and *expiry_date* fields of LicenseInfo. See example below. ```c++ LicenseInfo licenseInfo; size_t pc_id_sz = LCC_API_PC_IDENTIFIER_SIZE + 1; char pc_identifier[LCC_API_PC_IDENTIFIER_SIZE + 1]; LCC_EVENT_TYPE result = acquire_license(nullptr, nullptr, &licenseInfo); if (result == LICENSE_OK) { cout << "license OK" << endl; if (licenseInfo.has_expiry) { cout << "Days left " << licenseInfo.days_left << endl; cout << "Expired date " << licenseInfo.expiry_date << endl; } } ``` ## Display hardware ID using a QrCode If a feature in your sofware is unlicenced it can be nice to show the Hardware ID as a QrCode in your UI, enabling scanning it via a mobile phone and send the ID to the license issuer. Using the public api you can retrieve the hardware ID which would look something like this **AAAC-QtjM-1R8=** Below an idea of what the UI can look like ![Qr Example](images/QrExample.png) ### Convert HW ID to Qr and display it Using this qr-code-generator-library [Link](https://www.nayuki.io/page/qr-code-generator-library) you can use the code-snippet to create SVG including the hardware ID. Displaying it via Qt is pretty straight forward. Using Qt's SVG ```c++ void QrHelper::createQrCode(QString input) { // Hardware ID does not change during program run, so it is only necessary to generate the code once if (_qrImage.isNull()) { const QrCode::Ecc errCorLvl = QrCode::Ecc::LOW; // Error correction level std::string s = input.toStdString(); const char *qrData = s.data(); const QrCode qr = QrCode::encodeText(qrData, errCorLvl); std::string svgStr = toSvgString(qr, 4); QXmlStreamReader reader(svgStr.c_str()); QSvgRenderer renderer(&reader); qDebug() << "QrCode ready to be rendered " << renderer.isValid(); _qrImage = QImage(200, 200, QImage::Format_ARGB32_Premultiplied); QPainter imagePainter(&_qrImage); imagePainter.setRenderHint(QPainter::Antialiasing, false); renderer.render(&imagePainter); imagePainter.end(); // Rough transparency conversion of the white background for (int i = 0; i < _qrImage.width(); i++) { for (int j = 0; j < _qrImage.height(); j++) { QColor c = _qrImage.pixelColor(i, j); if (c == Qt::white) { _qrImage.setPixelColor(i, j, Qt::transparent); } } } } emit qrImageChanged(&_qrImage); } ``` ## Load license at specific location By providing the struct **LicenseLocation** when you acquire a license you can name the license anything (instead of the default same name as your binary) ```c++ // Result after acuire_license stored in licenseInfo LicenseInfo licenseInfo; // Path to license file LicenseLocation loc {LICENSE_PATH, "/opt/cclicenses/onelicense.lic"}; // What feature should we check CallerInformations ci = {"\0", "SOME_FEATURE", 0}; LCC_EVENT_TYPE result = acquire_license(&ci, &loc, &licenseInfo); if (result == LICENSE_OK) { cout << "license OK" << endl; } ``` ## Using multiple license files An idea for using more than one license file. If your software has X features, you could try loading all license files found in a specific folder and keep track of the most benificial one per feature you have. Doing this it will be easy to drop in new license files and when you restart the software it will correctly choose the best license. In our Qt demo example we use this approach (can be requested). ![Workflow](images/LicenseDemo.png)