Attribute VB_Name = "MdlCommunication"
Option Explicit

Public Const MAX_INJECTEUR = 8


Public Enum EModeleBras
    EModeleBras_Aucun = 0
    EModeleBras_8Injecteurs = 1
    EModeleBras_AdditifColorant = 2
    EModeleBras_BE = 4
    EModeleBras_Blending = 8
    EModeleBras_TypeChargement = &H30
    EModeleBras_Dome = 0
    EModeleBras_SrcApi = &H10
    'EModeleBras_SrcEuropia = &H20
    'EModeleBras_SrcSymasec = &H30
    EModeleBras_Ticket = &H40
    EModeleBras_Inter = &H80
    EModeleBras_TypeUnite = &H300
    EModeleBras_VT = &H100
    EModeleBras_V15 = &H0
    EModeleBras_M = &H200
    EModeleBras_32Bits = &H400
End Enum

Public Type TLiaison
    Port As Integer
    RxFrame As Long
    TxFrame As Long
    RxFrameReject As Long
End Type

Public Type TInjecteur
    RxTaux As Long
    RxTotalisateur As Long
    RxCommande As Boolean
    TrancheInjectee As Long
End Type

Public Type TBras
    Numero As Long 'N° esclave
    Modele As EModeleBras
    
    
    ' Zones Modbus
    LectureModbusDebut As Long
    LectureModbusFin As Long
    LectureModbusLongueur As Long
    
    
    EcritureModbusDebut As Long
    EcritureModbusFin As Long
    EcritureModbusLongueur As Long
    
    
    TxFrame As Long
    RxFrame As Long
    
    ' Données Reçues
    ' ==============
    TxProduit As Integer
    TxAdditif As Integer
    TxColorant As Integer
    TxQuota As Long
    TxDejaChargee As Long
    TxTemperatureDejaChargee As Single
    TxCodeDefaut As Long
    TxLibelleDefaut As String * 10
    TxLibelleProduit As String * 6
    TxLibelleAdditif As String * 6
    TxLibelleColorant As String * 6
    TxPPMAdditif As Single
    TxPPMColorant As Single
    TxAutorisationCalculateur As Boolean
    TxAutorisationClient As Boolean
    TxVolumeControle As Long
    TxPriseEnCompteVolume As Boolean
    TxVolumeReleve As Boolean
    TxAcquit As Boolean
    TxPresenceSondeCamion As Boolean
    TxCustomOutPut1 As Boolean
    TxCustomOutPut2 As Boolean
'    TxIdentifiantAutorisation As Long
'
'    TxBlendingRun As Long
    TxBlendingRate As Single
    
    TxForcagePresenceTicket As Boolean
    TxDebitConsigne As Long
    'TxNumeroMaitreInter As Long
    TxMasseVolumique As Single
    TxIdBe As Long
    TxEtatMetro As Long
    
    TxTerreD As Boolean
    TxTerreG As Boolean
    TxConnexionBrasD As Boolean
    TxConnexionBrasG As Boolean
    TxOrientationD As Boolean
    TxOrientationG As Boolean
    TxConnecte As Boolean
    
    
    ' Données Emises
    ' ==============
    RxDebit As Integer
    RxHaveDebit As Boolean
    RxTemperatureInstantannée As Single
    RxTemperatureMoyenne As Single
    RxAffichage As String * 10
    RxPression As Single
    RxMasseVolumique As Single
    'RxTV As Single
    RxVolume As Long
    RxVolumeV15 As Long
    RxVolumeFuite As Long
    'RxFuite As Long
    RxPrede As Long
    RxIdentifiantAutorisation As Long
    RxVolumeAdditif As Long
    RxVolumeColorant As Long
    RxCodeDefaut As Long
    RxSondeAPi As Boolean
    RxTerre As Boolean
    RxTerreD As Boolean
    RxBrasVapeur As Boolean
    RxDemandeChargement As Boolean
    RxDemandeChargementD As Boolean
    RxDemandeProduit As Boolean
    RxDemandeReleve As Boolean
    RxPriseEnCompteCorrecte As Boolean
    
    RxPhaseAutomatisme As Long
    RxTensionVapeur As Single
    RxDemandePurge As Boolean
    RxCommandeVARC As Boolean
    RxIdBe As Long
    RxNumeroSIM As Long
    RxEtatMetro As Long
    RxIdOperation As Long
    
    'RxForcageDemandeReleve As Boolean
    'RxForcagePriseEnCompteCorrecte As Boolean
    RxBrasBaisse As Boolean
    RxPasserelleG As Boolean
    RxPasserelleD As Boolean
    RxOrientationG As Boolean
    RxOrientationD As Boolean
    
    RxTotalisateur As Long
    RxInjecteurAdditif As Long
    RxInjecteurColorant As Long
    RxAutonome As Boolean
    RxCustomInput1 As Boolean
    RxCustomInput2 As Boolean
    RxPSL As Boolean
    RxDemandeAcquit As Boolean
    RxChangementBE As Boolean
    
    RxRecopieGD As Boolean
    RxRecopiePD As Boolean
    RxPresenceTicket As Boolean
    
    Injecteur(MAX_INJECTEUR) As TInjecteur
    
    'CoeffBlending As Long
    RxBlendingVolume As Long
    'RxBlendingRate As Single
    RxBlendingTemperature As Single
    RxBlendingTemperatureMoyenne As Single
    RxBlendingTauxRealise As Single
    RxBlendingTauxSatis As Single
    RxBlendingTotalisateur As Long
End Type

Public Bras As TBras

Public PauseInterTrameDelay As Long 'Pause en ms

Public TimeOutDelay As Long 'TimeOut en ms

Public Liaison As TLiaison


Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)



Public Sub MonitorMaitre(ByRef pComm As MSComm, Optional ByVal pSendData As Boolean = False)
    Dim ltRecv() As Byte
    
    If pSendData Then
        ltRecv = SendData()
        
        If UBound(ltRecv) >= 0 Then
            Debug.Print "MCB <- " & ProtocoleModbus.TranslateBinaryToHexaAscii(ltRecv)
            AddFrameLog ltRecv, False
            pComm.InBufferCount = 0
            pComm.Output = ltRecv
            Liaison.TxFrame = Liaison.TxFrame + 1
            DoEvents
            ltRecv = Recept(pComm)
            If UBound(ltRecv) >= 0 Then
                AddFrameLog ltRecv, True
                TranslateInput ltRecv
                Debug.Print "MCB -> " & ProtocoleModbus.TranslateBinaryToHexaAscii(ltRecv)
            End If
        End If
        
        PauseInterTrame
    End If
    
    ltRecv = SendRead()
    
    If UBound(ltRecv) >= 0 Then
        Debug.Print "MCB <- " & ProtocoleModbus.TranslateBinaryToHexaAscii(ltRecv)
        AddFrameLog ltRecv, False
        pComm.InBufferCount = 0
        pComm.Output = ltRecv
        Liaison.TxFrame = Liaison.TxFrame + 1
        DoEvents
        ltRecv = Recept(pComm)
        If UBound(ltRecv) >= 0 Then
            AddFrameLog ltRecv, True
            TranslateInputData ltRecv
            Debug.Print "MCB -> " & ProtocoleModbus.TranslateBinaryToHexaAscii(ltRecv)
        End If
    End If
End Sub


Private Sub PauseInterTrame()
    Sleep PauseInterTrameDelay
End Sub

Private Function Recept(ByRef pComm As MSComm) As Byte()
    Dim ltRecv() As Byte
    Dim lLng As Long
    Dim lStart As Single
    Dim lEnd As Single
    
    lStart = Timer
    lEnd = lStart + TimeOutDelay / 1000#
    
    Do While (Timer <= lEnd) And (lLng = 0 Or lLng <> pComm.InBufferCount)
        lLng = pComm.InBufferCount
        Sleep 10
        DoEvents
    Loop
        
    If pComm.InBufferCount Then
        pComm.InputLen = 0
        ltRecv = pComm.Input
    Else
        ReDim ltRecv(-1 To -1)
    End If
    
    Recept = ltRecv
End Function


Private Function SendData() As Byte()
    'Fct 16
    Dim lMot As Long
    Dim lValue As Long
    Dim ltData() As Byte
    
    ReDim ltData(0 To 34 * 2 + 9 - 1)
    
    ProtocoleModbusCreateHeaderWriteFrame CInt(Bras.Numero), 16, 0, 34, ltData
    
    
    lMot = 0
    lValue = 0
    
    If Bras.TxAcquit Then lValue = lValue Or 1
    If (Bras.Modele And EModeleBras_TypeUnite) = EModeleBras_V15 Then lValue = lValue Or 2
    If Bras.TxAutorisationCalculateur Then lValue = lValue Or 4
    If Bras.TxAutorisationClient Then lValue = lValue Or &H8
    If Bras.TxForcagePresenceTicket Then lValue = lValue Or &H10
    If (Bras.Modele And EModeleBras_TypeUnite) = EModeleBras_M Then lValue = lValue Or &H20
    If Bras.TxPriseEnCompteVolume Then lValue = lValue Or &H40
    If Bras.TxVolumeReleve Then lValue = lValue Or &H80
    
    lValue = lValue Or (Bras.TxCodeDefaut * &H100)
    
    ProtocoleModbusSetWord ltData, lMot + 1, lValue
    
    lValue = 0
    lMot = lMot + 1 '1
    lValue = lValue Or (Bras.TxProduit And &HFF)
    lValue = lValue Or (Bras.TxAdditif And &HF) * &H100
    lValue = lValue Or (Bras.TxColorant And &H7) * &H1000
    If (Bras.TxColorant And &H8) <> 0 Then lValue = lValue Or &H8000
    ProtocoleModbusSetWord ltData, lMot + 1, lValue
    
    lMot = lMot + 1 '2
    ProtocoleModbusSetWord ltData, lMot + 1, Bras.TxQuota
    
    lMot = lMot + 1 '3
    ProtocoleModbusSetWord ltData, lMot + 1, Bras.TxDejaChargee
    
    lMot = lMot + 1 '4
    ProtocoleModbusSetWord ltData, lMot + 1, CLng(Bras.TxTemperatureDejaChargee * 10)
    
    lMot = lMot + 1 '5
    lValue = Asc(Mid$(Bras.TxLibelleDefaut, 1, 1)) * &H100 + Asc(Mid$(Bras.TxLibelleDefaut, 2, 1))
    ProtocoleModbusSetWord ltData, lMot + 1, lValue
    lMot = lMot + 1 '6
    lValue = Asc(Mid$(Bras.TxLibelleDefaut, 3, 1)) * &H100 + Asc(Mid$(Bras.TxLibelleDefaut, 4, 1))
    ProtocoleModbusSetWord ltData, lMot + 1, lValue
    lMot = lMot + 1 '7
    lValue = Asc(Mid$(Bras.TxLibelleDefaut, 5, 1)) * &H100 + Asc(Mid$(Bras.TxLibelleDefaut, 6, 1))
    ProtocoleModbusSetWord ltData, lMot + 1, lValue
    lMot = lMot + 1 '8
    lValue = Asc(Mid$(Bras.TxLibelleDefaut, 7, 1)) * &H100 + Asc(Mid$(Bras.TxLibelleDefaut, 8, 1))
    ProtocoleModbusSetWord ltData, lMot + 1, lValue
    lMot = lMot + 1 '9
    lValue = Asc(Mid$(Bras.TxLibelleDefaut, 9, 1)) * &H100 + Asc(Mid$(Bras.TxLibelleDefaut, 10, 1))
    ProtocoleModbusSetWord ltData, lMot + 1, lValue
    
    lMot = lMot + 1 '10
    ProtocoleModbusSetWord ltData, lMot + 1, Bras.TxVolumeControle
    
    lMot = lMot + 1 '11
    ProtocoleModbusSetWord ltData, lMot + 1, Bras.TxDebitConsigne
    
    lMot = lMot + 1 '12
    lValue = 0
    If Bras.TxTerreD Then lValue = lValue Or &H1
    If Bras.TxTerreG Then lValue = lValue Or &H2
    If Bras.TxConnexionBrasD Then lValue = lValue Or &H4
    If Bras.TxConnexionBrasG Then lValue = lValue Or &H8
    If Bras.TxOrientationD Then lValue = lValue Or &H10
    If Bras.TxOrientationG Then lValue = lValue Or &H20
    If Bras.TxConnecte Then lValue = lValue Or &H40
    If Bras.TxCustomOutPut1 Then lValue = lValue Or &H100
    If Bras.TxCustomOutPut2 Then lValue = lValue Or &H200
    If Bras.TxPresenceSondeCamion Then lValue = lValue Or &H4000
    ProtocoleModbusSetWord ltData, lMot + 1, lValue
    
    lMot = lMot + 1 '13
    'lValue = Bras.TxNumeroMaitreInter And &HFF
    lValue = 0
    If (Bras.TxQuota And &H10000) <> 0 Then lValue = lValue Or &H100
    If (Bras.TxDejaChargee And &H10000) <> 0 Then lValue = lValue Or &H200
    If (Bras.TxVolumeControle And &H10000) <> 0 Then lValue = lValue Or &H400
    ProtocoleModbusSetWord ltData, lMot + 1, lValue
    
    lMot = lMot + 1 '14
    ProtocoleModbusSetWord ltData, lMot + 1, CLng(Bras.TxMasseVolumique * 10)
    
    lMot = lMot + 1 '15
    If (Bras.Modele And EModeleBras_32Bits) <> 0 Then ProtocoleModbusSetWord ltData, lMot + 1, (Bras.TxQuota And &HFFFF0000) / &H10000
    
    lMot = lMot + 1 '16
    If (Bras.Modele And EModeleBras_32Bits) <> 0 Then ProtocoleModbusSetWord ltData, lMot + 1, (Bras.TxDejaChargee And &HFFFF0000) / &H10000
    
    lMot = lMot + 1 '17
    If (Bras.Modele And EModeleBras_32Bits) <> 0 Then ProtocoleModbusSetWord ltData, lMot + 1, (Bras.TxVolumeControle And &HFFFF0000) / &H10000
    
    lMot = lMot + 1 '18-19
    ProtocoleModbusSetDoubleWord ltData, lMot + 1, Bras.TxIdBe
    
    'Libelle produit
    lMot = lMot + 2 '20
    lValue = Asc(Mid$(Bras.TxLibelleProduit, 1, 1)) * &H100 + Asc(Mid$(Bras.TxLibelleProduit, 2, 1))
    ProtocoleModbusSetWord ltData, lMot + 1, lValue
    lMot = lMot + 1 '21
    lValue = Asc(Mid$(Bras.TxLibelleProduit, 3, 1)) * &H100 + Asc(Mid$(Bras.TxLibelleProduit, 4, 1))
    ProtocoleModbusSetWord ltData, lMot + 1, lValue
    lMot = lMot + 1 '22
    lValue = Asc(Mid$(Bras.TxLibelleProduit, 5, 1)) * &H100 + Asc(Mid$(Bras.TxLibelleProduit, 6, 1))
    ProtocoleModbusSetWord ltData, lMot + 1, lValue
    
    'Libelle additif
    lMot = lMot + 1 '23
    lValue = Asc(Mid$(Bras.TxLibelleAdditif, 1, 1)) * &H100 + Asc(Mid$(Bras.TxLibelleAdditif, 2, 1))
    ProtocoleModbusSetWord ltData, lMot + 1, lValue
    lMot = lMot + 1 '24
    lValue = Asc(Mid$(Bras.TxLibelleAdditif, 3, 1)) * &H100 + Asc(Mid$(Bras.TxLibelleAdditif, 4, 1))
    ProtocoleModbusSetWord ltData, lMot + 1, lValue
    lMot = lMot + 1 '25
    lValue = Asc(Mid$(Bras.TxLibelleAdditif, 5, 1)) * &H100 + Asc(Mid$(Bras.TxLibelleAdditif, 6, 1))
    ProtocoleModbusSetWord ltData, lMot + 1, lValue
    
    'Libelle colorant
    lMot = lMot + 1 '26
    lValue = Asc(Mid$(Bras.TxLibelleColorant, 1, 1)) * &H100 + Asc(Mid$(Bras.TxLibelleColorant, 2, 1))
    ProtocoleModbusSetWord ltData, lMot + 1, lValue
    lMot = lMot + 1 '27
    lValue = Asc(Mid$(Bras.TxLibelleColorant, 3, 1)) * &H100 + Asc(Mid$(Bras.TxLibelleColorant, 4, 1))
    ProtocoleModbusSetWord ltData, lMot + 1, lValue
    lMot = lMot + 1 '28
    lValue = Asc(Mid$(Bras.TxLibelleColorant, 5, 1)) * &H100 + Asc(Mid$(Bras.TxLibelleColorant, 6, 1))
    ProtocoleModbusSetWord ltData, lMot + 1, lValue
    
    lMot = lMot + 1 '29
    ProtocoleModbusSetWord ltData, lMot + 1, CLng(Bras.TxPPMAdditif * 1000)
    
    lMot = lMot + 1 '30
    ProtocoleModbusSetWord ltData, lMot + 1, CLng(Bras.TxPPMColorant * 1000)
    
    lMot = lMot + 1 '31
    ProtocoleModbusSetWord ltData, lMot + 1, Bras.TxEtatMetro And &HFF
    
    lMot = lMot + 1 '32
    ProtocoleModbusSetWord ltData, lMot + 1, Bras.TxBlendingRate * 100
    
    lMot = lMot + 1 '33
    ProtocoleModbusSetWord ltData, lMot + 1, Bras.TxBlendingRate * 100
    
    ProtocoleModbusBuildAndAddCRC16 ltData, UBound(ltData)
    
    SendData = ltData
End Function

Private Sub TranslateInput(ByRef ptData() As Byte)
    'Fct 16
    '5 Err - 8 Good
    
    Dim lSize As Integer
    Dim lGood As Boolean
    Dim lErr As Boolean
    lGood = True
    lErr = False
    
'  0 : OK
' -1 : Erreur CRC 16
' -2 : Err Esclave
' -3 : Erreur fonction
' -4 : Erreur Longueur
    
    lSize = UBound(ptData) - LBound(ptData) + 1
    Select Case ProtocoleModbusIsAnswerStructOk(ptData, lSize, CByte(Bras.Numero), 16)
        Case 0 'OK
            lGood = (lSize = 8)
        Case -1 'Erreur CRC 16
            lGood = False
        Case -2 'Erreur Esclave
            lGood = False
        Case -3 'Erreur fonction
            lGood = (ProtocoleModbusIsAnswerStructOk(ptData, lSize, CByte(Bras.Numero), &H90) = 0 And lSize = 5)
            lErr = True
        Case -4 'Erreur Longueur
            lGood = False
    End Select
    
    'Trame Modbus NOK
    If lGood = False Then
        Liaison.RxFrameReject = Liaison.RxFrameReject + 1
    End If
    
    Liaison.RxFrame = Liaison.RxFrame + 1
    
    'Réponse d'erreur ou non
    If lErr Then
        'undone
    Else
        'undone
    End If
End Sub


Private Function SendRead() As Byte()
    'Fct 3
    Dim ltSend(0 To 7) As Byte
    Dim ltRej(-1 To -1) As Byte
    
    Dim lLength As Integer
    
    'If (Bras.Modele And EModeleBras_8Injecteurs) <> 0 Then
    '    lLength = 0
    'Else
    '    lLength = -15
    'End If
    
    'If (Bras.Modele And EModeleBras_Blending) <> 0 Then
        lLength = lLength + 70
    'Else
    '    lLength = lLength + 62
    'End If
    
    If lLength = 0 Then
        SendRead = ltRej
    Else
        ProtocoleModbusCreateHeaderReadFrame CByte(Bras.Numero), 3, 0, lLength, ltSend
        ProtocoleModbusBuildAndAddCRC16 ltSend, UBound(ltSend)
        SendRead = ltSend
    End If
End Function

Private Sub TranslateInputData(ByRef ptData() As Byte)
    'undone
    'Fct 3
    '5 Err - 8 Good
    
    Dim lSize As Long
    Dim lGood As Boolean
    Dim lErr As Boolean
    lGood = True
    lErr = False
    
    Dim lLength As Long
    
    'If (Bras.Modele And EModeleBras_8Injecteurs) <> 0 Then
    '    lLength = 0
    'Else
    '    lLength = -15
    'End If
    '
    'If (Bras.Modele And EModeleBras_Blending) <> 0 Then
        lLength = lLength + 70
    'Else
    '    lLength = lLength + 62
    'End If

    lLength = 5 + 2 * lLength
    
    
'  0 : OK
' -1 : Erreur CRC 16
' -2 : Err Esclave
' -3 : Erreur fonction
' -4 : Erreur Longueur
    
    lSize = UBound(ptData) - LBound(ptData) + 1
    Select Case ProtocoleModbusIsAnswerStructOk(ptData, CInt(lSize), CByte(Bras.Numero), 3)
        Case 0 'OK
            lGood = (lSize = lLength)
        Case -1 'Erreur CRC 16
            lGood = False
        Case -2 'Erreur Esclave
            lGood = False
        Case -3 'Erreur fonction
            lGood = (ProtocoleModbusIsAnswerStructOk(ptData, CInt(lSize), CByte(Bras.Numero), &H83) _
                = 0 And lSize = 5)
            lErr = True
        Case -4 'Erreur Longueur
            lGood = False
    End Select
    
    'Trame Modbus NOK
    If lGood = False Then
        Liaison.RxFrameReject = Liaison.RxFrameReject + 1
        Exit Sub
    End If
    
    Liaison.RxFrame = Liaison.RxFrame + 1
    
    Dim lMot As Long
    Dim lValue As Long
    Dim i As Long
        
    'Réponse sans erreur
    If Not lErr Then
        With Bras
            lMot = 0
            lValue = ProtocoleModbusExtractWord(ptData, lMot + 1)
            
            'Défaut température
            If (lValue And 1) <> 0 Then
                .RxTemperatureMoyenne = -1
                .RxTemperatureMoyenne = -1
            Else
                .RxTemperatureMoyenne = 0
                .RxTemperatureMoyenne = 0
            End If
            'Bras baissé (Dome) ou connecté (Source)
            .RxBrasBaisse = (lValue And 2) <> 0
            'Bras rangé (source) ou passerelle D (Dome)
            .RxPasserelleD = (lValue And 4) <> 0
            'Passerelle G (Dome)
            .RxPasserelleG = (lValue And &H8) <> 0
            'Orientation D (Dome)
            .RxOrientationD = (lValue And &H10) <> 0
            
            .RxOrientationG = (lValue And &H20) <> 0 And (.Modele And EModeleBras_TypeChargement) = _
                EModeleBras_Dome
            .RxSondeAPi = (lValue And &H20) <> 0 And (.Modele And EModeleBras_TypeChargement) <> _
                EModeleBras_Dome
            
            .RxTerreD = (lValue And &H40) <> 0
            'Terre G (Dome) ou Terre (Source)
            .RxTerre = (lValue And &H80) <> 0
            'Source API uniquement
            .RxBrasVapeur = (lValue And &H100) <> 0
            'Demande nouveau BE
            .RxChangementBE = (lValue And &H400) <> 0
            
            .RxDemandeProduit = (lValue And &H800) <> 0
            'Signale si un débit est présent
            .RxHaveDebit = (lValue And &H1000) <> 0
            
            .RxDemandeReleve = (lValue And &H2000) <> 0
            
            .RxPriseEnCompteCorrecte = (lValue And &H4000) <> 0
            
            .RxCodeDefaut = IIf((lValue And &H8000) <> 0, 0, -1)
            
            
            lMot = 1
            lValue = ProtocoleModbusExtractWord(ptData, lMot + 1)
            
            'Code du défaut si présent
            If .RxCodeDefaut >= 0 Then
                .RxCodeDefaut = lValue And &HFF
            End If
            
            .RxDemandeChargement = (lValue And &H200) <> 0
            
            .RxDemandeChargementD = (lValue And &H100) <> 0
            
            'Bits 17 des volumes courant et de fuite
            .RxVolume = (lValue And &H400) * &H400
            .RxVolumeFuite = (lValue And &H800) * &H200
            'MCB en autonome
            .RxAutonome = (lValue And &H1000) <> 0
            'Volumes sur 32Bits
            .Modele = (.Modele And Not CLng(EModeleBras_32Bits)) Or IIf((lValue And &H4000) <> 0, _
                EModeleBras_32Bits, 0)
            'Si validé, test la présence d'un ticket
            If (.Modele And EModeleBras_Ticket) <> 0 Then .RxPresenceTicket = (lValue And &H8000) <> _
                0
            
            lMot = 2
            .RxVolume = .RxVolume + ProtocoleModbusExtractWord(ptData, lMot + 1)
            
            lMot = 3
            .RxVolumeFuite = .RxVolumeFuite + ProtocoleModbusExtractWord(ptData, lMot + 1)
            
            lMot = 4
            .RxDebit = ProtocoleModbusExtractWord(ptData, lMot + 1)
            
            lMot = 5
            .RxTemperatureInstantannée = ProtocoleModbusExtractWord(ptData, lMot + 1) / 10#
            
            lMot = 6
            .RxTemperatureMoyenne = ProtocoleModbusExtractWord(ptData, lMot + 1) / 10#
            
            'Affichage du MCB
            i = 0
            For lMot = 7 To 11
                lValue = ProtocoleModbusExtractWord(ptData, lMot + 1)
                i = i + 1
                Mid$(.RxAffichage, i, 1) = Chr$((lValue And &HFF00) / &H100)
                i = i + 1
                Mid$(.RxAffichage, i, 1) = Chr$(lValue And &HFF)
            Next lMot
            
            lMot = 12
            .RxPression = ProtocoleModbusExtractWord(ptData, lMot + 1) / 10#
            
            lMot = 13
            .RxMasseVolumique = ProtocoleModbusExtractWord(ptData, lMot + 1) / 10#
            
            lMot = 14
            For i = 0 To IIf((.Modele And EModeleBras_8Injecteurs) <> 0, 7, 2)
                lValue = ProtocoleModbusExtractWord(ptData, lMot + 1 + i)
                
                .Injecteur(i + 1).RxTaux = lValue And &HFF
                .Injecteur(i + 1).TrancheInjectee = (lValue And &HFF00) / &H100
            Next i
            lMot = lMot + i '22
            
            For i = 0 To IIf((.Modele And EModeleBras_8Injecteurs) <> 0, 7, 2)
                .Injecteur(i + 1).RxTotalisateur = ProtocoleModbusExtractDoubleWord(ptData, lMot + 1 + 2 * i)
            Next i
            lMot = lMot + 2 * i '38
            
            .RxPhaseAutomatisme = ProtocoleModbusExtractWord(ptData, lMot + 1)
            lMot = lMot + 1 '39
            
            .RxTotalisateur = ProtocoleModbusExtractDoubleWord(ptData, lMot + 1)
            lMot = lMot + 2 '41
            lMot = lMot + 1 '42
            
            .RxTensionVapeur = ProtocoleModbusExtractWord(ptData, lMot + 1) / 10#
            lMot = lMot + 1 '43
            
            lValue = ProtocoleModbusExtractWord(ptData, lMot + 1)
            lMot = lMot + 1 '44
            
            .RxCustomInput1 = (lValue And &H1) <> 0
            .RxCustomInput2 = (lValue And &H2) <> 0
            .RxRecopieGD = (lValue And &H4) <> 0
            .RxRecopiePD = (lValue And &H8) <> 0
            .RxPSL = (lValue And &H10) <> 0
            .RxDemandeAcquit = (lValue And &H20) <> 0
            .RxDemandePurge = (lValue And &H40) <> 0
            .RxCommandeVARC = (lValue And &H80) <> 0
            For i = 1 To 8
                .Injecteur(i).RxCommande = (lValue And (&H80 * (2 ^ i))) <> 0
            Next i
            
            .RxPrede = ProtocoleModbusExtractWord(ptData, lMot + 1)
            lMot = lMot + 1 '45
            
            If (.Modele And EModeleBras_32Bits) <> 0 Then .RxVolume = .RxVolume Or (ProtocoleModbusExtractWord(ptData, lMot + 1) * &H10000)
            lMot = lMot + 1 '46
            
            If (.Modele And EModeleBras_32Bits) <> 0 Then .RxVolumeFuite = .RxVolumeFuite Or (ProtocoleModbusExtractWord(ptData, lMot + 1) * &H10000)
            lMot = lMot + 1 '47
            
            If (.Modele And EModeleBras_32Bits) <> 0 Then .RxPrede = .RxPrede Or (ProtocoleModbusExtractWord(ptData, lMot + 1) * &H10000)
            lMot = lMot + 1 '48
            
            lValue = ProtocoleModbusExtractWord(ptData, lMot + 1)
            lMot = lMot + 1 '49

            .RxInjecteurAdditif = lValue And &HFF
            .RxInjecteurColorant = (lValue And &HFF00) / &H100
            
            .RxIdBe = ProtocoleModbusExtractDoubleWord(ptData, lMot + 1)
            lMot = lMot + 2 '51
            
            .RxVolumeAdditif = ProtocoleModbusExtractDoubleWord(ptData, lMot + 1)
            lMot = lMot + 2 '53
            
            .RxVolumeColorant = ProtocoleModbusExtractDoubleWord(ptData, lMot + 1)
            lMot = lMot + 2 '55
            
            .RxNumeroSIM = ProtocoleModbusExtractWord(ptData, lMot + 1)
            lMot = lMot + 1 '56
            
            If (.Modele And EModeleBras_32Bits) <> 0 Then .RxVolume = .RxVolume Or (ProtocoleModbusExtractWord(ptData, lMot + 1) * &H10000)
            lMot = lMot + 1 '57
            
            .RxVolumeV15 = ProtocoleModbusExtractWord(ptData, lMot + 1)
            lMot = lMot + 1 '58
            
            .RxPression = ProtocoleModbusExtractWord(ptData, lMot + 1) / 10#
            lMot = lMot + 1
            
            .RxEtatMetro = ProtocoleModbusExtractWord(ptData, lMot + 1) And &HFF
            lMot = lMot + 1
            
            .RxIdOperation = ProtocoleModbusExtractDoubleWord(ptData, lMot + 1)
            lMot = lMot + 2
            
            .RxBlendingTotalisateur = ProtocoleModbusExtractDoubleWord(ptData, lMot + 1)
            lMot = lMot + 2
            
            .RxBlendingVolume = ProtocoleModbusExtractDoubleWord(ptData, lMot + 1) / 10#
            lMot = lMot + 2
            
            .RxBlendingTauxRealise = ProtocoleModbusExtractWord(ptData, lMot + 1) / 100#
            lMot = lMot + 1
            
            .RxBlendingTauxSatis = ProtocoleModbusExtractWord(ptData, lMot + 1) / 100#
            lMot = lMot + 1
            
            .RxBlendingTemperature = ProtocoleModbusExtractWord(ptData, lMot + 1) / 10#
            lMot = lMot + 1
            
            .RxBlendingTemperatureMoyenne = ProtocoleModbusExtractWord(ptData, lMot + 1) / 10#
            lMot = lMot + 1
        End With
    Else
        'undone
    End If
End Sub

Private Sub AddFrameLog(ByRef ptData() As Byte, ByVal pFromMCB As Boolean)
    Dim lStr As String
    Dim i As Long
    
    For i = LBound(ptData) To UBound(ptData)
        lStr = lStr & " " & Right$("00" & Hex$(ptData(i)), 2)
    Next i
    
    FrmPrinc.LstFrameLog.AddItem IIf(pFromMCB, "->", "<-") & lStr, 0
    
    If FrmPrinc.LstFrameLog.ListCount > 50 Then
        FrmPrinc.LstFrameLog.RemoveItem (50)
    End If
End Sub
