# Guide d'utilisation QtXpl2 Ce guide explique comment utiliser le module QML `Xpl2` pour piloter un Jetting Controller Alchemie depuis une interface Qt Quick. ## Import et connexion ```qml import Xpl2 // Xpl2Client est un singleton — pas besoin de l'instancier. // Configurer l'adresse du contrôleur : Xpl2Client.host = "192.168.1.100" // Se connecter / se déconnecter : Xpl2Client.connectToServer() Xpl2Client.disconnectFromServer() ``` ### Propriétés de connexion | Propriété | Type | Description | |---|---|---| | `host` | string | Adresse IP du Jetting Controller (défaut : `"127.0.0.1"`) | | `connected` | bool | `true` quand les 3 ports TCP sont connectés | | `controllerId` | int | ID du contrôleur (renseigné après `getJcVersion()`) | | `firmwareVersion` | string | Version firmware du contrôleur | | `hardwareVersion` | string | Version hardware du contrôleur | | `printheadCount` | int | Nombre de têtes connectées | ### Signaux généraux | Signal | Description | |---|---| | `errorOccurred(string error)` | Erreur de connexion ou de commande | | `statusMessage(string message)` | Message de log pour chaque réponse reçue | | `shuttingDown()` | Le serveur est en train de s'éteindre | --- ## Informations version ### Obtenir la version du contrôleur ```qml Xpl2Client.getJcVersion() ``` La réponse met à jour les propriétés `controllerId`, `firmwareVersion`, `hardwareVersion` et `printheadCount`. Le signal `jcVersionReceived()` est émis. ### Obtenir la version d'une tête ```qml Xpl2Client.getPhVersion(3) // tête n°3 ``` **Signal :** `phVersionReceived(controllerId, printheadId, mcuFirmwareVersion, mcuHardwareVersion, mcuFirmwareVariant, fpgaFirmwareVersion, fpgaHardwareVersion, bootloaderVersion)` ```qml Connections { target: Xpl2Client function onPhVersionReceived(cid, phId, mcuFw, mcuHw, mcuVar, fpgaFw, fpgaHw, boot) { console.log("Tête", phId, "— MCU:", mcuFw, "FPGA:", fpgaFw) } } ``` --- ## Contrôle du jetting ### Activer / désactiver le jetting ```qml // Toutes les têtes Xpl2Client.jettingAllOn() // → signal jettingAllOnResult(cid, success) Xpl2Client.jettingOff() // → signal jettingOffResult(cid, success) // Avec un masque de buses (180 caractères, 12 par tête × 15 têtes) // Chaque caractère : 'F' = jet actif, '0' = jet inactif Xpl2Client.jettingOn("FFFF..." ) // → signal jettingOnResult(cid, success) // Une seule tête avec masque (12 caractères) Xpl2Client.phJettingOn(3, "FFFFFFFFFFFF") // → signal phJettingOnResult(cid, phId, success) Xpl2Client.phJettingOff(3) // → signal phJettingOffResult(cid, phId, success) ``` ### LEDs d'identification ```qml // LED du contrôleur Xpl2Client.jcIdLedOn() // → signal jcIdLedOnResult(cid, success) Xpl2Client.jcIdLedOff() // → signal jcIdLedOffResult(cid, success) // LED d'une tête Xpl2Client.phIdLedOn(3) // → signal phIdLedOnResult(cid, phId, success) Xpl2Client.phIdLedOff(3) // → signal phIdLedOffResult(cid, phId, success) ``` ### Calibration ```qml // Calibrer toutes les têtes Xpl2Client.jcCalibration() // → signal jcCalibrationResult(cid, success) // Calibrer une tête Xpl2Client.phCalibration(3) // → signal phCalibrationResult(cid, phId, success) // Récupérer les données de calibration (48 fréquences par tête, -1 = non calibré) Xpl2Client.phCalibrationData(3) // → signal phCalibrationDataReceived(cid, phId, frequencies) Xpl2Client.phCalibrationRawData(3) // → signal phCalibrationRawDataReceived(cid, phId, frequencies) // Fréquence de base calibrée Xpl2Client.phCalibratedBaseFrequency(3) // → signal phCalibratedBaseFrequencyReceived(cid, phId, baseFreq, activeBaseFreq) ``` ### Codes de défaut ```qml // Réinitialiser les codes de défaut Xpl2Client.jcResetFaultCodes() // → signal jcResetFaultCodesResult(cid, success) Xpl2Client.phResetFaultCodes(3) // → signal phResetFaultCodesResult(cid, phId, success) ``` ### Désactivation de buses ```qml // Masque de 12 caractères : '0' = buse active, autre = buse désactivée // "000000000000" réactive toutes les buses Xpl2Client.phNozzlesDisabled(3, "000000000000") // → signal phNozzlesDisabledResult(cid, phId, success) ``` --- ## Messages de statut Le contrôleur peut envoyer périodiquement des messages de statut détaillés. ### Démarrer / arrêter les messages ```qml // Niveau 1 = basique, niveau 2 = étendu // Intervalle en millisecondes Xpl2Client.jcStatusMessagingStart(1, 1000) // JC, niveau 1, toutes les secondes Xpl2Client.jcStatusMessagingStop() Xpl2Client.phStatusMessagingStart(2, 500) // Têtes, niveau 2, toutes les 500ms Xpl2Client.phStatusMessagingStop() ``` **Signaux de confirmation :** - `jcStatusMessagingStartResult(cid, statusLevel, sendIntervalMs, success)` - `jcStatusMessagingStopResult(cid, success)` - `phStatusMessagingStartResult(cid, statusLevel, sendIntervalMs, success)` - `phStatusMessagingStopResult(cid, success)` ### Recevoir les statuts Les messages de statut arrivent sous forme d'objets structurés avec des propriétés nommées. ```qml Connections { target: Xpl2Client function onJcStatusReceived(status) { // status est un objet Xpl2JcStatus tempLabel.text = status.temperature.toFixed(1) + "°C" cpuLabel.text = status.cpuPercentageBusy.toFixed(1) + "%" } function onPhStatusReceived(status) { // status est un objet Xpl2PhStatus console.log("Tête", status.printheadId, "temp:", status.temperature) } } ``` ### Champs du statut JC (`Xpl2JcStatus`) #### Niveau 1 | Propriété | Type | Description | |---|---|---| | `controllerId` | int | ID du contrôleur | | `statusLevel` | int | Niveau de statut (1 ou 2) | | `cpuPercentageBusy` | float | Charge CPU (%) | | `rail5V` | float | Tension rail 5V | | `railCanBus8V` | float | Tension bus CAN 8V | | `temperature` | float | Température (°C) | | `humidity` | float | Humidité (%) | | `busCurrent` | float | Courant bus (A) | | `onTimeSeconds` | int | Temps de fonctionnement (s) | #### Niveau 2 (inclut le niveau 1 +) | Propriété | Type | Description | |---|---|---| | `ipAddress` | string | Adresse IP | | `eFuseVoltage` | float | Tension eFuse (V) | | `eFuseBusEnabled` | bool | Bus eFuse activé | | `busPowerEnabled` | bool | Alimentation bus activée | | `busPowerOk` | bool | Alimentation bus OK | | `switchValue` | int | Valeur du commutateur | | `firmwareVersion` | string | Version firmware | | `hardwareVersion` | string | Version hardware | | `indicator0` .. `indicator5` | bool | Indicateurs 0 à 5 | ### Champs du statut PH (`Xpl2PhStatus`) #### Niveau 1 | Propriété | Type | Description | |---|---|---| | `controllerId` | int | ID du contrôleur | | `statusLevel` | int | Niveau de statut | | `printheadId` | int | ID de la tête | | `temperature` | float | Température (°C) | | `humidity` | float | Humidité (%) | | `mcuTemperature` | float | Température MCU (°C) | | `pdsVoltage` | float | Tension PDS (V) | | `mdsVoltage` | float | Tension MDS (V) | | `systemVoltage` | float | Tension système (V) | | `eFuseCurrent` | float | Courant eFuse (A) | | `nozzleCurrent` | float | Courant buses (A) | | `vdd` | float | Tension VDD (V) | | `temperatureTrip` | bool | Seuil température dépassé | | `pdsOverVoltageTrip` | bool | Surtension PDS | | `pdsUnderVoltageTrip` | bool | Sous-tension PDS | | `pdsSupplyErrorTrip` | bool | Erreur alimentation PDS | | `mdsOverVoltageTrip` | bool | Surtension MDS | | `mdsUnderVoltageTrip` | bool | Sous-tension MDS | | `supplyOverVoltageTrip` | bool | Surtension alimentation | | `supplyUnderVoltageTrip` | bool | Sous-tension alimentation | | `eFuseOverCurrentTrip` | bool | Surintensité eFuse | | `eFuseInputVoltageErrorTrip` | bool | Erreur tension entrée eFuse | | `eFuseFaultTrip` | bool | Défaut eFuse | | `flashFaultyTrip` | bool | Défaut flash | | `flashChecksumErrorTrip` | bool | Erreur checksum flash | | `dutyCycle` | float | Rapport cyclique (%) | | `pwmFrequency` | float | Fréquence PWM (Hz) | | `drive` | int | Drive | | `nozzleDriveFrequency` | float | Fréquence drive buses (Hz) | | `nozzleDriveDutyCycle` | float | Rapport cyclique drive buses (%) | | `onTimeSeconds` | int | Temps de fonctionnement (s) | #### Niveau 2 (inclut le niveau 1 +) | Propriété | Type | Description | |---|---|---| | `accelerometerId` | int | ID accéléromètre | | `mcuId` | string | ID MCU | | `flashMemoryId` | string | ID mémoire flash | | `temperatureSensorSerialNumber` | int | N° série capteur température | | `mcuHardwareVersion` | string | Version hardware MCU | | `mcuFirmwareVersion` | string | Version firmware MCU | | `mcuFirmwareVariant` | string | Variante firmware MCU | | `fpgaHardwareVersion` | string | Version hardware FPGA | | `fpgaFirmwareVersion` | string | Version firmware FPGA | | `bootloaderVersion` | string | Version bootloader | | `maxAllowedTemperature` | float | Température max autorisée (°C) | | `pdsVoltageMax` | float | Tension PDS max (V) | | `pdsVoltageMin` | float | Tension PDS min (V) | | `pdsVoltageSetting` | float | Réglage tension PDS (V) | | `mdsVoltageMax` | float | Tension MDS max (V) | | `mdsVoltageMin` | float | Tension MDS min (V) | | `eFuseCurrentMax` | float | Courant eFuse max (A) | | `measuredHardwareVersion` | string | Version hardware mesurée | | `gyroX`, `gyroY`, `gyroZ` | int | Gyroscope X/Y/Z | | `accelerationX`, `accelerationY`, `accelerationZ` | int | Accélération X/Y/Z | | `purge`, `purgeState`, `purgeDelay`, `purgeCounter` | int | Paramètres de purge | | `cleaningStartPeriod`, `cleaningEndPeriod`, `cleaningStepPeriod`, `cleaningPeriod` | int | Paramètres de nettoyage | --- ## Configuration ### ID des têtes ```qml Xpl2Client.phSetId(3) // → signal phSetIdResult(cid, phId, success) Xpl2Client.phDeassignId() // → signal phDeassignIdResult(cid, success) ``` ### Paramètres de jetting ```qml // Pour tout le contrôleur Xpl2Client.jcSetJettingParams(dutyCycle, pwmFreq, drive, nozzleDriveFreq, nozzleDriveDutyCycle) // → signal jcSetJettingParamsResult(cid, dutyCycle, pwmFreq, drive, nozzleDriveFreq, nozzleDriveDutyCycle, result) // Pour une tête Xpl2Client.phSetJettingParams(phId, dutyCycle, pwmFreq, drive, nozzleDriveFreq, nozzleDriveDutyCycle) // → signal phSetJettingParamsResult(cid, phId, dutyCycle, pwmFreq, drive, nozzleDriveFreq, nozzleDriveDutyCycle, result) // Lire les paramètres d'une tête Xpl2Client.phGetJettingParams(3) // → signal phGetJettingParamsResult(cid, phId, dutyCycle, pwmFreq, drive, nozzleDriveFreq, nozzleDriveDutyCycle, result) ``` Le paramètre `result` est un `JettingParamsResult` : | Valeur | Signification | |---|---| | `1` (Ok) | Succès | | `0` (Failed) | Échec | | `-1` (DutyCycle) | Rapport cyclique invalide | | `-2` (PwmFrequency) | Fréquence PWM invalide | | `-3` (Drive) | Drive invalide | | `-4` (NozzleDriveFrequency) | Fréquence drive buses invalide | | `-5` (NozzleDriveDutyCycle) | Rapport cyclique drive buses invalide | ### Calibration ```qml Xpl2Client.jcSaveCalibration() // → jcSaveCalibrationResult(cid, success) Xpl2Client.phSaveCalibration(3) // → phSaveCalibrationResult(cid, phId, success) Xpl2Client.jcResetCalibration() // → jcResetCalibrationResult(cid, success) Xpl2Client.phResetCalibration(3) // → phResetCalibrationResult(cid, phId, success) ``` ### Purge ```qml // Configurer : intervalle (ms) et durée de jet (ms) // La durée doit être inférieure à l'intervalle Xpl2Client.jcSetPurgeSettings(5000, 200) // → jcSetPurgeSettingsResult(cid, interval, time, success) Xpl2Client.jcSwitchOffPurge() // → jcSwitchOffPurgeResult(cid, success) ``` ### Setter / Getter générique Permet de lire ou écrire n'importe quel paramètre par son ID (voir Appendice D du protocole). ```qml // Écrire un paramètre du contrôleur // saveNewValue : true pour sauvegarder en mémoire permanente Xpl2Client.jcSetter(true, 4, "35.0") // setter ID 4 = température // → signal jcSetterResult(cid, saveNewValue, setterId, newValue, result) // Écrire un paramètre d'une tête Xpl2Client.phSetter(3, false, 23, "50.0") // tête 3, setter ID 23 = duty cycle // → signal phSetterResult(cid, phId, saveNewValue, setterId, newValue, result) // Lire un paramètre du contrôleur // getSavedValue : true pour la valeur sauvegardée, false pour la valeur courante Xpl2Client.jcGetter(false, 4) // → signal jcGetterResult(cid, savedValue, getterId, currentValue, success) // Lire un paramètre d'une tête Xpl2Client.phGetter(3, false, 1) // → signal phGetterResult(cid, phId, savedValue, getterId, currentValue, success) ``` Le `result` des setters est un `SetterResult` : | Valeur | Signification | |---|---| | `1` (Ok) | Succès | | `0` (Failed) | Échec | | `-1` (IncorrectNewValue) | Valeur incorrecte | ### Sauvegarde et réinitialisation ```qml // Sauvegarder tous les réglages Xpl2Client.jcSaveAllPrintheadSettings() // → jcSaveAllPrintheadSettingsResult(cid, success) Xpl2Client.phSaveSettings(3) // → phSaveSettingsResult(cid, phId, success) // Réinitialiser les réglages Xpl2Client.jcResetSettingsAllPrintheads() // → jcResetSettingsAllPrintheadsResult(cid, success) Xpl2Client.phResetAllSettings(3) // → phResetAllSettingsResult(cid, phId, success) ``` ### Redémarrage et arrêt ```qml Xpl2Client.jcRebootAllPrintheads() // → jcRebootAllPrintheadsResult(cid, success) Xpl2Client.phReboot(3) // → phRebootResult(cid, phId, success) Xpl2Client.jcResetControllerSoftware() // → jcResetControllerSoftwareResult(cid, success) Xpl2Client.jcRestart() // → jcRestartResult(cid, success) Xpl2Client.jcShutdown() // → jcShutdownResult(cid, success) ``` --- ## Imaging Les commandes d'imaging sont envoyées sur le port 2 (9111). ### Démarrer / arrêter l'impression ```qml Xpl2Client.imagingStart(1.0) // vitesse d'impression // → signal imagingReply(imageLines) — nombre de lignes d'image à envoyer Xpl2Client.imagingStop() // → signal imagingStopResult(success) ``` ### Masques d'image Les masques définissent quelles buses sont actives pour chaque ligne d'image. Le masque fait 12 caractères par tête (180 caractères pour 15 têtes). ```qml // Envoyer un masque : m0 démarre, m1 termine et déclenche l'envoi Xpl2Client.imageMaskStart("FFFFFFFFFFFF...") // 180 caractères Xpl2Client.imageMaskEnd("fin_du_message") // → signal imagingReply(imageLines) ``` ### Masques de rapport cyclique Même principe avec 2 caractères hexadécimaux par tête. ```qml Xpl2Client.dutyCycleMaskStart("FF...") Xpl2Client.dutyCycleMaskEnd("fin") // → signal imagingReply(imageLines) ``` ### Compteur d'images Vérifie le nombre de lignes d'image restantes. Utilisé avant d'arrêter l'impression pour s'assurer que toutes les lignes ont été envoyées. ```qml Xpl2Client.imageCount() // → signal imagingReply(imageLines) — 0 signifie que tout est envoyé ``` --- ## Événements serveur Ces signaux sont émis automatiquement quand le serveur envoie des événements. ### Erreurs ```qml Connections { target: Xpl2Client // Erreur du contrôleur (codes 3000+) function onJcErrorCode(controllerId, errorCode, params) { console.log("Erreur JC:", errorCode, params) } // Erreur d'une tête (codes 4000+) function onPhErrorCode(controllerId, printheadId, errorCode, params) { console.log("Erreur tête", printheadId, ":", errorCode) } // Erreur d'imaging (codes 5000+) function onImgErrorCode(controllerId, errorCode, params) { } // Erreur de statut (codes 6000+) function onStatusErrorCode(controllerId, errorCode, params) { } } ``` ### Connexion des têtes ```qml Connections { target: Xpl2Client function onPhConnectionChanged(controllerId, printheadId, connected) { console.log("Tête", printheadId, connected ? "connectée" : "déconnectée") } } ``` ### Arrêt du serveur ```qml Connections { target: Xpl2Client function onShuttingDown() { console.log("Le serveur s'éteint") } } ```