Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

[RS232] Problèmes à des vitesses >56

21 réponses
Avatar
Romain PETIT
Bonjour,

J'ai un soucis avec les fonctions du port série (ou émulation via USB)
de Windev (version 20 mais je pense que c'est pareil avec toutes les
version).

Je dois récupérer un fichier binaire d'environ 80~100 ko à 115200 bps
sans contrôle de flux ni matériel ni logiciel (pas le choix).
Une première commande permet d'avoir la taille exacte du fichier, on
envoie une seconde commande pour initier la demande de transfert.
Un écho à la commande est reçu et après une petite tempo le flux arrive
en lecture.
La fin est détectée avec un timeout et/ou en vérifiant la taille du
fichier et un CRC est lu et recalculé pour vérification.

- Tout ça marche bien avec mes fonctions de lecture/écriture que
j'utilise depuis 10 ans, jusqu'à une vitesse de 19200 bps.

- Avec une vitesse supérieure (57600 ou 115200 bps, j'ai beau essayer
tous les paramètres possibles (buffer, branchement d'un évenement avec
uniquement la lecture ou utilisation d'une boucle sans fin, paramètre
"temporisation"), il manque toujours 200 à 300 octets dans le fichier
(bizarement toujours situés à peu prêt au même endroit sans que j'ai pu
déterminer une raison, vers l'octet 4300.)

- Je peux exclure un problème matériel car si j'utilise un terminal
(hyperterminal, teraterm) tout se passe correctement.

- J'ai déjà testé avec succès une solution alternative en utilisant une
DLL payante facile à utiliser et performante
(http://www.marshallsoft.com/wsc4vb.htm) mais je voudrais avoir votre
avis :

- Une expérience similaire ? Une solution possible sans un composant
tiers ?
- Une autre référence de DLL ? (une solution opensource sans activeX à
enregistrer serait l'idéal).

Merci
A+

--
Romain PETIT
contact : rompetit chez free fr
+-+ posté sur Usenet avec MesNews et non depuis un forum web +-+
news:fr.comp.developpement.agl.windev
http://www.mesnews.net/
http://fr.wikipedia.org/wiki/Newsgroup

10 réponses

1 2 3
Avatar
André STASZEWSKI
Daniel avait soumis l'idée :
Tu as fait en c ou en VB ?



En W-Langage :-) avec AppelDLL32 et en m'inspirant surtout du code VB...
Je posterai la solution après avoir écrit un truc plus propre.
Si ça interesse quelqu'un ?

A+



Salut Romain !

Peut être pas dans l'immédiat, mais possible un jour.
Donc la réponse est OUI.

--
Cordialement,
André STASZEWSKI
http://www.SoftSolution.fr
Pour me contacter, cliquez ici :
http://cerbermail.com/?Z8IP9sIahR
Avatar
titou44
Romain PETIT a exprimé avec précision :
Daniel avait soumis l'idée :
Tu as fait en c ou en VB ?



En W-Langage :-) avec AppelDLL32 et en m'inspirant surtout du code VB...
Je posterai la solution après avoir écrit un truc plus propre.
Si ça interesse quelqu'un ?

A+




bonsoir

oh que oui !!

titou44 chez libresurf.com
Avatar
Eric Laurent
Oui bien sûr.
Un grand merci d'avance.

Eric
Avatar
Daniel
Le 11/03/2015 18:15, Romain PETIT a écrit :
Daniel avait soumis l'idée :
Tu as fait en c ou en VB ?



En W-Langage :-) avec AppelDLL32 et en m'inspirant surtout du code VB...


J'avais complètement oublié cette fonction...
C'est comme le Q lorsqu'on ne pratique plus on perd les réflexes.

Je posterai la solution après avoir écrit un truc plus propre.
Si ça interesse quelqu'un ?

A+




Oui, cela me rappellera des souvenirs...
--
suivre ce lien pour répondre:
http://cerbermail.com/?2KrV3YZXnn
Daniel
;-)

---
L'absence de virus dans ce courrier électronique a été vérifiée par le logiciel antivirus Avast.
http://www.avast.com
Avatar
Daniel
Le 11/03/2015 18:15, Romain PETIT a écrit :
Daniel avait soumis l'idée :
Tu as fait en c ou en VB ?



En W-Langage :-) avec AppelDLL32 et en m'inspirant surtout du code VB...


J'avais complètement oublié cette fonction...
C'est comme le Q lorsqu'on ne pratique plus on perd les réflexes.

Je posterai la solution après avoir écrit un truc plus propre.
Si ça interesse quelqu'un ?

A+




Oui, cela me rappellera des souvenirs...
--
suivre ce lien pour répondre:
http://cerbermail.com/?2KrV3YZXnn
Daniel
;-)

---
L'absence de virus dans ce courrier électronique a été vérifiée par le logiciel antivirus Avast.
http://www.avast.com
Avatar
Romain PETIT
Dans son message précédent, Romain PETIT a écrit :
Je posterai la solution après avoir écrit un truc plus propre.
Si ça interesse quelqu'un ?



Bon bé voilà.
C'est sous forme d'une petite classe WD20 sous licence WD-Libre.
Tout est expliqué dans le code de la classe.
Téléchargeable ici : http://www.windasso.org/
(rubrique téléchargement)

(sinon, j'ai mis le code ci-dessous pour d'autres versions de WD, mais
il va falloir copier-coller et gérer les lignes qui risquent d'être
tronquées...)

Je n'ai pas tout testé, notamment en 64b, ou encore les paramétrages de
contrôle de flux...
Faites-moi un retour si vous constatez un pbm.

A+


************************************************************************

Je réceptionne mon fichier ainsi (simplifié) :

// port COM11
oRS est un objet cRS232API(11)
// On passe en vitesse 115200 bps
oRS:stParam.eVitesse = 115200
// Ouverture du port + paramétrage
SI oRS:OpenComPort(sErreur) ALORS
// Envoi de la commande
SI oRS:Send(sCommande,sErreur) ALORS
SI oRS:Receive(sReponse,*, Taille(sCommande),sErreur,bTO) ALORS
// On a reçu l'écho de la commande...le fichier arrive
SI sReponse=sCommande ALORS
// je connais la taille de mon fichier...
// (sinon utiliser le TO)
SI oRS:Receive(sContenuFichier,*,39364,sErreur)
fSauveTexte("C:testapi.txt", sContenuFichier)
FIN
FIN
FIN
FIN
FIN
************************************************************************

************ DECLARATION DE cRS232API **********************************

////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// CLASSE cRS232API
// =============== // (c) mars 2015 Romain PETIT sous licence WDLibre (cf. http://www.windasso.org/ rubrique FAQ)
//
// Env. developpement : WD20-51m
//-------------------------------------------------------------------------------------------------------------------------------------//
// Auteur : RPE : Romain PETIT (rompetit chez free.fr)
//-------------------------------------------------------------------------------------------------------------------------------------//
// Contributions : Forum fdaw, inspiré très largement du code VB https://strokescribe.com/en/serial-port-vb-winapi.html
//-------------------------------------------------------------------------------------------------------------------------------------//
// Infos : Utilisation d'API Windows pour certains besoins spécifiques de dialogue avec le port COM que Windev
// peut mal géré (typiquement : téléchargement d'un fichier sans contrôle de flux à une vitesse>19200 bps)
//-------------------------------------------------------------------------------------------------------------------------------------//
// Mise en oeuvre : - Déclarer un objet cRS232API en précisant le N° de port COMM (1 à 255)
// - affecter éventuellement des paramètres en initialisant le membre stParam (structure)
// - Ouvrir le port avec :OpenComPort() (le SetComPort est appelé en cas de succès d'ouverture)
// - Utiliser :Send et :Receive pour envoyer et recevoir des trames
// - Fermer le port avec :CloseComPort (ou liberer l'objet)
//-------------------------------------------------------------------------------------------------------------------------------------//
// TODO : Plein de choses au fur et à mesure des besoins... (gestion de caractères de fin de trame par exemple)
//-------------------------------------------------------------------------------------------------------------------------------------//
// Version :
CONSTANT CRS232API_CT_VERSION = "1.0.0"
//-------------------------------------------------------------------------------------------------------------------------------------//
// Historique :
// 12/03/2015 1.0.0 RPE Version initiale

// Structure pour sauvegarder puis paramétrer les TO
strPARAM_COMM est une Structure
eVitesse est un entier
eParite est un entier
eBitData est un entier
eBitStop est un entier
eDTRDSR est un entier
eRTSCTS est un entier
eXOnXoff est un entier
FIN
strCOMMTIMEOUTS est une Structure
ReadIntervalTimeout est un entier
ReadTotalTimeoutMultiplier est un entier
ReadTotalTimeoutConstant est un entier
WriteTotalTimeoutMultiplier est un entier
WriteTotalTimeoutConstant est un entier
FIN

cRS232API est une Classe
PRIVÉ
eNumComPort est un entier // Numéro du port com
eHandle est un entier // Handle du port com ouvert
stTO_Orig est une strCOMMTIMEOUTS // POur sauvegarder les TO et les restituer
PUBLIC
stParam est une strPARAM_COMM // Structure pour paramétrer le port
FIN
CONSTANTE
CT_eDefaultTO = 300 // Time-Out en 1/100e de sec (300=3 sec)
CT_sNomDLL = "kernel32.dll" // Même en 64b, la dll se nomme kernel32
FIN
************************************************************************


************ CONSTRUCTEUR **********************************************
PROCEDURE Constructeur(LOCAL eNumComPort est un entier)
:eHandle = -1
:eNumComPort = eNumComPort
:stParam:eVitesse = -1 // si pas redéfini, on prend la vitesse actuelle
:stParam:eBitData = -1
:stParam:eParite = -1
:stParam:eBitStop = -1
:stParam:eRTSCTS = -1
:stParam:eDTRDSR = -1
:stParam:eXOnXoff = -1
************************************************************************


************ DESTRUCTEUR ***********************************************
PROCEDURE Destructeur()
:CloseComPort()
************************************************************************


************ METHODE OpenComPort ***************************************
// Résumé : Ouvre le port com
// Syntaxe :
//[ <Résultat> = ] OpenComPort ( [<Addr_sRetourErreur> est chaîne])
//
// Paramètres :
// Addr_sRetourErreur (chaîne ANSI - valeur par défaut="") : Si la fonction retourne faux, l'erreur est retournée via cette chaine passée par adresse en paramètre
// Valeur de retour :
// booléen : Vrai si le port est bien ouvert, faux en cas d'erreur
//
// Exemple :
// SI PAS oRS232API:OpenComPort(sRetourErreur) ALORS Erreur(sRetourErreur)
//
PROCEDURE OpenComPort(Addr_sRetourErreur est une chaîne = "")
bRes est un booléen
//https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858%28v=vs.85%29.aspx
eErreurSys est un entier
Addr_sRetourErreur = ""
//FILE_SHARE_READ est un entier = 0x1
//FILE_SHARE_WRITE est un entier = 0x2
GENERIC_READ est un entier =0x80000000
GENERIC_WRITE est un entier =0x40000000
OPEN_EXISTING est un entier =0x3
// Code retours erreurs :
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382%28v=vs.85%29.aspx
ERROR_FILE_NOT_FOUND est un entier = 0x2
ERROR_ACCESS_DENIED est un entier = 0x5


//INVALID_HANDLE_VALUE est un entier = -1
:eHandle = API(::CT_sNomDLL,"CreateFileA", ".COM"+:eNumComPort, ...
GENERIC_READ|GENERIC_WRITE, ...
0, ... // No share
Null, // No security
OPEN_EXISTING,...
0,... // No thread
Null) // No template

SI :eHandle <=0 ALORS
Addr_sRetourErreur = "Erreur ouverture port com "+ :eNumComPort+" : "
eErreurSys = ErreurInfo(errCodeSystème)
SELON eErreurSys
CAS ERROR_ACCESS_DENIED
Addr_sRetourErreur+="le port est déjà ouvert"
CAS ERROR_FILE_NOT_FOUND
Addr_sRetourErreur+="le port n'existe pas"
AUTRE CAS
Addr_sRetourErreur+="erreur système "+eErreurSys
FIN
SINON
bRes = :SetComPort(Addr_sRetourErreur)
FIN
SI PAS Addr_sRetourErreur~="" ALORS :Tracer(Addr_sRetourErreur)
RENVOYER bRes
************************************************************************


************ METHODE SetComPort ****************************************
// Résumé : Lecture des paramètres actuels du Port com et redéfinition
// Syntaxe :
//[ <Résultat> = ] SetComPort ( [<Addr_sRetourErreur> est chaîne])
//
// Paramètres :
// Addr_sRetourErreur (chaîne ANSI - valeur par défaut="") : Si la fonction retourne faux, l'erreur est retournée via cette chaine passée par adresse en paramètre
// Valeur de retour :
// booléen : Vrai/Faux en cas d'échec
//
// Exemple :
// Indiquez ici un exemple d'utilisation.
//
// ePartité (entier) : <indiquez ici le rôle de ePartité>
// strParamPort (strPARAM_COMM - valeur par défaut=0) : <indiquez ici le rôle de strParamPort>
PROCEDURE PRIVÉE SetComPort(Addr_sRetourErreur est une chaîne = "")
bRes est un booléen
bParamModif est un booléen
//https://msdn.microsoft.com/en-us/library/windows/desktop/aa363214%28v=vs.85%29.aspx
Addr_sRetourErreur = ""
MAXDWORD est un entier = 0xFFFFFFFF

strDCB est une Structure
DCBlength est un entier // Long 4 bytes (DWORD)
BaudRate est un entier
fBitField est un entier // structure de 32 bits, cf la description MSDN et ci-dessous
// FieldName Bit # Description
// ----------------- ----- ------------------------------
// fBinary 1 Windows does not support nonbinary mode transfers, so this member must be =1.
// fParity 2 If =1, parity checking is performed and errors are reported
// fOutxCtsFlow 3 If =1 and CTS is turned off, output is suspended until CTS is sent again.
// fOutxDsrFlow 4 If =1 and DSR is turned off, output is suspended until DSR is sent again.
// fDtrControl 5,6 DTR flow control (2 bits)
// fDsrSensitivity 7 The driver ignores any bytes received, unless the DSR modem input line is high.
// fTXContinueOnXoff 8 XOFF continues Tx
// fOutX 9 If =1, TX stops when the XoffChar character is received and starts again when the XonChar character is received.
// fInX 10 Indicates whether XON/XOFF flow control is used during reception.
// fErrorChar 11 Indicates whether bytes received with parity errors are replaced with the character specified by the ErrorChar.
// fNull 12 If =1, null bytes are discarded when received.
// fRtsControl 13,14 RTS flow control (2 bits)
// fAbortOnError 15 If =1, the driver terminates all I/O operations with an error status if an error occurs.
// fDummy2 16 reserved
wReserved est un entier sur 2 octets // Integer
XonLim est un entier sur 2 octets // Integer
XoffLim est un entier sur 2 octets
ByteSize est un entier sur 1 octet // byte
Parity est un entier sur 1 octet
StopBits est un entier sur 1 octet
XonChar est un entier sur 1 octet // définition du Char XON (0x17)
XoffChar est un entier sur 1 octet // définition du Char XOFF (0x19)
ErrorChar est un entier sur 1 octet
EofChar est un entier sur 1 octet
EvtChar est un entier sur 1 octet
wReserved1 est un entier sur 2 octets
FIN

stDCB est une strDCB
stTO est une strCOMMTIMEOUTS
eRes est un entier
// on récupère l'état actuel du port com (paramétré en amont par exemple avec la dernière fonction sOuvre/sFixeParamètres)
eRes = API(::CT_sNomDLL, "GetCommState",eHandle,&stDCB)
SI eRes ALORS
// on peux alors affecter de nouvelles valeurs
// (dans mon cas, je n'en ai pas besoin)
// Par exemple, si on veut changer le baudrate :
// stDCB:BaudRate = 115200
// ou si on veut changer le DTR sans handshake, on passe le bits 5 à 1 et le 6 à 0
// stDCB:fBitField[5] = 1
// stDCB:fBitField[6] = 0

SI PAS :stParam.eVitesse = -1 _ET_ :stParam.eVitesse<>stDCB:BaudRate ALORS
SI :stParam.eVitesse DANS (110,300,600,1200,2400,4800,9600,14400,19200,38400,57600,115200,128000,256000,230400,460800,921600) ALORS
// voir https://rt.cpan.org/Public/Bug/Display.html?ids763
stDCB:BaudRate = :stParam.eVitesse
bParamModif = Vrai
SINON
Addr_sRetourErreur+="Erreur de paramétrage vitesse, la valeur <"+:stParam.eVitesse+"> n'est pas valide."+RC+"La valeur actuelle ("+stDCB:BaudRate+") sera utilisée"+RC
FIN
FIN
SI PAS :stParam.eBitData = -1 _ET_ :stParam.eBitData<>stDCB:ByteSize ALORS
SI :stParam.eBitData DANS (4,5,6,7,8) ALORS
stDCB:ByteSize = :stParam.eBitData
bParamModif = Vrai
SINON
Addr_sRetourErreur+="Erreur de paramétrage bit de donnée, la valeur <"+:stParam.eBitData+"> n'est pas valide."+RC+"La valeur actuelle ("+stDCB:ByteSize+") sera utilisée"+RC
FIN
FIN
SI PAS :stParam.eBitStop = -1 _ET_ :stParam.eBitStop<>stDCB:StopBits ALORS
SI :stParam.eBitStop DANS (0,1,2) ALORS
stDCB:StopBits = :stParam.eBitStop // 0=1 stop bit, 1=1.5, 2=2 stop bits
bParamModif = Vrai
SINON
Addr_sRetourErreur+="Erreur de paramétrage bit de stop, la valeur <"+:stParam.eBitStop+"> n'est pas valide."+RC+"La valeur actuelle ("+stDCB:StopBits+") sera utilisée"+RC
FIN
FIN
SI PAS :stParam.eParite = -1 _ET_ :stParam.eParite<>stDCB:Parity ALORS
SI :stParam.eParite DANS (0,1,2,3,4) ALORS
stDCB:Parity = :stParam.eParite // 0=Pas de parité, 1=ODD (Paire), 2=EVEN (Impaire), 3=MARK, 4=SPACE
// faut-il aussi activer le bit 2 de fBitField ?
bParamModif = Vrai
SINON
Addr_sRetourErreur+="Erreur de paramétrage de la parité, la valeur <"+:stParam.eParite+"> n'est pas valide."+RC+"La valeur actuelle ("+stDCB:Parity+") sera utilisée"+RC
FIN
FIN

SELON :stParam.eRTSCTS
CAS -1 // rien, on garde ce qui est déjà défini
CAS 0 //RTS_CONTROL_DISABLE, Disables the RTS line when the device is opened and leaves it disabled.
stDCB:fBitField[13]=0
stDCB:fBitField[14]=0
bParamModif = Vrai
CAS 1 //0x1000 RTS_CONTROL_ENABLE, Enables the RTS line when the device is opened and leaves it on.
stDCB:fBitField[13]=1 //0x1000
stDCB:fBitField[14]=0
bParamModif = Vrai
CAS 2 //0x2000 RTS_CONTROL_HANDSHAKE, Enables RTS handshaking. The driver raises the RTS line when the "type-ahead" (input) buffer is less than one-half full and lowers the RTS line when the buffer is more than three-quarters full. If handshaking is enabled, it is an error for the application to adjust the line by using the EscapeCommFunction function.
stDCB:fBitField[13]=0
stDCB:fBitField[14]=1 //0x2000
bParamModif = Vrai
CAS 3 //0x3000 RTS_CONTROL_TOGGLE, Specifies that the RTS line will be high if bytes are available for transmission. After all buffered bytes have been sent, the RTS line will be low.
stDCB:fBitField[13]=1
stDCB:fBitField[14]=1
bParamModif = Vrai
AUTRE CAS
Addr_sRetourErreur+="Erreur de paramétrage du contrôle de flux RTS/CTS, la valeur <"+:stParam.eRTSCTS+"> n'est pas valide."+RC+"La valeur actuelle (bits 13-14) ("+NumériqueVersChaîne(stDCB:fBitField[13])+NumériqueVersChaîne(stDCB:fBitField[14])+") sera utilisée"+RC
FIN
SELON :stParam.eDTRDSR
CAS -1 // rien, on garde ce qui est déjà défini
CAS 0 //DTR_CONTROL_DISABLE, Disables the DTR line when the device is opened and leaves it disabled.
stDCB:fBitField[5]=0
stDCB:fBitField[6]=0
bParamModif = Vrai
CAS 1 // 0x10 DTR_CONTROL_ENABLE, Enables the DTR line when the device is opened and leaves it on.
stDCB:fBitField[5]=1
stDCB:fBitField[6]=0
bParamModif = Vrai
CAS 2 // 0x20 DTR_CONTROL_HANDSHAKE, Enables DTR handshaking. The driver raises the DTR line when the "type-ahead" (input) buffer is less than one-half full and lowers the DTR line when the buffer is more than three-quarters full. If handshaking is enabled, it is an error for the application to adjust the line by using the EscapeCommFunction function.
stDCB:fBitField[5]=0
stDCB:fBitField[6]=1 //0x20
bParamModif = Vrai
AUTRE CAS
Addr_sRetourErreur+="Erreur de paramétrage du contrôle de flux DTR/DSR, la valeur <"+:stParam.eDTRDSR+"> n'est pas valide."+RC+"La valeur actuelle (bits 5-6) ("+NumériqueVersChaîne(stDCB:fBitField[5])+NumériqueVersChaîne(stDCB:fBitField[6])+") sera utilisée"+RC
FIN
SELON :stParam.eXOnXoff
CAS -1 // rien, on garde ce qui est déjà défini
CAS 0
stDCB:fBitField[9]=0 // XONXOFF inactif en émission
stDCB:fBitField[10]=0// XONXOFF inactif en réception
CAS 1
stDCB:fBitField[9]=1
stDCB:fBitField[10]=1
AUTRE CAS
Addr_sRetourErreur+="Erreur de paramétrage du contrôle de flux XonXoff la valeur <"+:stParam.eXOnXoff+"> n'est pas valide."+RC+"La valeur actuelle (bits 9-10) ("+NumériqueVersChaîne(stDCB:fBitField[9])+NumériqueVersChaîne(stDCB:fBitField[10])+") sera utilisée"+RC
FIN

SI bParamModif ALORS
eRes = API(::CT_sNomDLL, "SetCommState",eHandle,&stDCB)
SI eRes<=0 ALORS
Addr_sRetourErreur+="Erreur lors de la redéfinition des paramètres du port com : erreur système "+ErreurInfo(errCodeSystème)+RC
FIN
FIN

// Réglages des TimeOuts, on récupère les param actuels
// Voir https://msdn.microsoft.com/en-us/library/windows/hardware/hh439614%28v=vs.85%29.aspx
eRes = API(::CT_sNomDLL, "GetCommTimeouts", eHandle, &stTO)
SI eRes>0 ALORS
// On sauvegarde pour rendre dans l'état où on l'a trouvé en sortant...
:stTO_Orig = stTO
// Attention également si on ne définit pas de TO, ce sont ceux par défaut -ou les derniers utilisés par une autre ouverture du port com-, qui seront utilisés
// Le paramètre <Durée d'attente> de fonction sOuvre du W-Langage correspond à ReadTotalTimeoutMultiplier et WriteTotalTimeoutMultiplier
// Les TO sont très important en cas d'utilisation d'événements...
// -> A value of MAXDWORD, combined with zero values for both the ReadTotalTimeoutConstant and ReadTotalTimeoutMultiplier members, specifies that the read operation is to return immediately with the characters that have already been received, even if no characters have been received...
// On gère le TO dans la méthode
stTO.ReadIntervalTimeout = MAXDWORD
stTO.ReadTotalTimeoutMultiplier = 0 // -> correspond à la valeur <Durée d'attente> dans sOuvre
stTO.ReadTotalTimeoutConstant = 0
stTO.WriteTotalTimeoutMultiplier = 0
stTO.WriteTotalTimeoutConstant = 0

// http://www.lookrs232.com/com_port_programming/api_timeout.htm
// J'ai lu quelque part ces paramètres pour adapter les TO à la vitesse (mais pas testé...)
// stTO.ReadIntervalTimeout = (20000 / stDCB.BaudRate) + 100 // -> 100ms pour 115200, 102 ms pour 9600 -> pas sûr que ce soit pertinent...
// stTO.ReadTotalTimeoutMultiplier = 10
// stto.ReadTotalTimeoutConstant = 1000
// stto.WriteTotalTimeoutMultiplier = 0
// stto.WriteTotalTimeoutConstant = 0
eRes = API(::CT_sNomDLL, "SetCommTimeouts", eHandle, &stTO)
SI eRes>0 ALORS
bRes = Vrai
SINON
Addr_sRetourErreur+="Erreur lors de la redéfinition des paramètres Time-Out du port com : erreur système "+ErreurInfo(errCodeSystème)+RC
FIN
SINON
Addr_sRetourErreur+="Erreur lors de la récupération des paramètres Time-Out du port com : erreur système "+ErreurInfo(errCodeSystème)+RC
FIN
SINON
Addr_sRetourErreur="Erreur lors de la récupération des paramètres du port com : erreur système "+ErreurInfo(errCodeSystème)
FIN
// (erreur éventuellement tracée dans OpenComPort)
RENVOYER bRes
************************************************************************


************ METHODE Send **********************************************
// Résumé : Envoi d'une chaine sur le port com
// Syntaxe :
//[ <Résultat> = ] Send (<sChaineEnvoi> est chaîne [, <Addr_sRetourErreur> est chaîne])
//
// Paramètres :
// sChaineEnvoi (chaîne ANSI) : Chaine/buffer à envoyer
// Addr_sRetourErreur (chaîne ANSI - valeur par défaut="") : Si la fonction retourne faux, l'erreur est retournée via cette chaine passée par adresse en paramètre
// Valeur de retour :
// booléen : Vrai si la chaine a été envoyé, faux en cas d'erreur
//
// Exemple :
// SI PAS oRS232API:Send("MaCommande", sRetourErreur) ALORS Erreur(sRetourErreur)
//
PROCEDURE Send(LOCAL sChaineEnvoi est une chaîne, Addr_sRetourErreur est une chaîne="")
bRes est un booléen
c est un entier
eNbOctets est un entier = Taille(sChaineEnvoi)
//eTabOctets est un tableau de eNbOctets entiers sur 1 octet
eNbOctetsEcrits est un entier
eOctet est un entier sur 1 octet
eRes est un entier
Addr_sRetourErreur =""
// Envoi d'un tableau d'octet-> Pas très fiable (ou alors il faudrait vérifier les params de temporisations ?)
// Le receveur semble recevoir une chaine tronquée
//pour c=1 _a_ eNbOctets
// eTabOctets[c] = asc(schaineenvoi[[c]])
//FIN
//eRes = api(::CT_sNomDLL, "WriteFile", eHandle, &eTabOctets, eNbOctets, &eNbOctetsEcrits,0)

// -> Méthode d'envoi caractère par caractère...
bRes = Vrai
POUR c=1 _A_ eNbOctets
eOctet = Asc(sChaineEnvoi[[c]])
eRes = API(::CT_sNomDLL, "WriteFile", eHandle, &eOctet, 1, &eNbOctetsEcrits,0)
SI PAS eRes ALORS
bRes = Faux
SORTIR
FIN
FIN

SI bRes ALORS
:Tracer(Répète(">",3)+"HEX "+Remplace(BufferVersHexa(sChaineEnvoi), RC, " "))
:Tracer(Répète(">",3)+"ASC "+Remplace(sChaineEnvoi, RC, "<CR><LF>"))
SINON
Addr_sRetourErreur = "Erreur lors de l'envoi (octet n°"+c+"), code système="+ErreurInfo(errCodeSystème)
FIN
SI PAS Addr_sRetourErreur~="" ALORS :Tracer(Addr_sRetourErreur)
RENVOYER bRes
************************************************************************


************ METHODE Receive *******************************************
// Résumé : Réception sur le port com
// Syntaxe :
//[ <Résultat> = ] Receive (<Addr_sBufferRecu> est chaîne [, <eTimeOut> est entier [, <eTailleAttendue> est entier [, <Addr_sRetourErreur> est chaîne [, <Addr_bRetourTO> est booléen]]]])
//
// Paramètres :
// Addr_sBufferRecu (chaîne ANSI) : Buffer reçu (passé par adresse)
// eTimeOut (entier - valeur par défaut00) : Valeur du time out en 1/100s (300=3s). Si aucun octet n'est reçu durant ce laps de temps, on sort de la fonction
// eTailleAttendue (entier - valeur par défaut=0) : Taille attendue en octet du buffer de réception. On sort de la fonction dès que cette taille est atteinte (même s'il reste des octets lus ou à lire)
// Addr_sRetourErreur (chaîne ANSI - valeur par défaut="") : Si la fonction retourne faux, l'erreur est retournée via cette chaine passée par adresse en paramètre
// Addr_bRetourTO (booléen - valeur par défaut=0) : Mis à vrai si on est sorti avec un Time-Out
// Valeur de retour :
// entier : -1=Erreur lors de la réception, sinon taille du Buffer lu (correspond à la taille de sBufferRecu)
//
// Exemple :
// oRS:Receive(sReponse,10)
//
PROCEDURE Receive(Addr_sBufferRecu est une chaîne, LOCAL eTimeOut est un entier=::CT_eDefaultTO, LOCAL eTailleAttendue est un entier=0, Addr_sRetourErreur est une chaîne="", Addr_bRetourTO est un booléenúux)
sBufferPartielRecu est une chaîne
eTailleBufferPartielReçu est un entier
eTailleBufferReçu est un entier
szRetour est une chaîne fixe sur 4096 // Buffer max à paramétrer ?
eRes est un entier
eResFinal est un entier
eHeureDepart est un entier
eDelaisTO est un entier


Addr_sBufferRecu = ""
Addr_sRetourErreur = ""
Addr_bRetourTO = Faux

// Heure de départ pour détecter le TO
eHeureDepart = DateVersEntier(DateSys())+HeureVersEntier(HeureSys())

BOUCLE
Multitâche(-1) // nécessaire (mais voir si on peut le remplacer par un sleep plus court ?)
eRes = API(::CT_sNomDLL, "ReadFile",eHandle, &szRetour, Dimension(szRetour),&eTailleBufferPartielReçu,0)
SI eRes<=0 ALORS
Addr_sRetourErreur="Erreur réception, code système=" +ErreurInfo(errCodeSystème)
eResFinal = -1
SORTIR
SINON
// on calcule le temps écoulé depuis l'heure de départ (ou de reset)
eDelaisTO = DateVersEntier(DateSys())+HeureVersEntier(HeureSys()) - eHeureDepart

SI eTailleBufferPartielReçu>0 ALORS
// On a reçu qque chose, on reset l'heure de départ
eHeureDepart = DateVersEntier(DateSys())+HeureVersEntier(HeureSys())
sBufferPartielRecu= szRetour[[A eTailleBufferPartielReçu]]
:Tracer(Répète("<",3)+"HEX "+Remplace(BufferVersHexa(sBufferPartielRecu), RC, " "))
:Tracer(Répète("<",3)+"ASC " + Remplace(sBufferPartielRecu, RC, "<CR><LF>"))

// on concatène au buffer reçu dans les boucle précédentes
Addr_sBufferRecu+=sBufferPartielRecu
eTailleBufferReçu = Taille(Addr_sBufferRecu)
// A-t-on atteint la taille attendue ?
SI eTailleAttendue>0 ALORS
Jauge(eTailleBufferReçu,eTailleAttendue,"Réception en cours...")
SI eTailleBufferReçu>=eTailleAttendue ALORS
:Tracer("Taille attendue reçue ("+eTailleAttendue+" octets), Fin de réception")
// On a reçu plus que prévu...A traiter au retour de la fonction (on a la taille reçue en retour)
SI eTailleBufferReçu>eTailleAttendue ALORS
:Tracer("mais il y a "+(eTailleBufferReçu-eTailleAttendue) + " octets de plus")
FIN
eResFinal = eTailleBufferReçu
SORTIR
FIN
FIN
SINON
// est-on en TO ?
SI eDelaisTO>eTimeOut ALORS
eResFinal = eTailleBufferReçu
Addr_bRetourTO = Vrai
:Tracer("TO "+(eTimeOut*10)+" ms, fin de réception ("+eResFinal+ " octets reçus)")
SORTIR
FIN
FIN
FIN
FIN
Jauge()
SI PAS Addr_sRetourErreur~="" ALORS :Tracer(Addr_sRetourErreur)
RENVOYER eResFinal
************************************************************************


************ METHODE CloseComPort **************************************
// Résumé : Fermeture du port com
// Syntaxe :
//[ <Résultat> = ] CloseComPort ( [<Addr_sRetourErreur> est chaîne])
//
// Paramètres :
// Addr_sRetourErreur (chaîne ANSI - valeur par défaut="") : Si la fonction retourne faux ou si la restitution des time-out d'origine a échouée, l'erreur est retournée via cette chaine passée par adresse en paramètre
// Valeur de retour :
// booléen : Vrai si le port est bien fermé, faux en cas d'erreur
//
// Exemples :
// SI PAS oRSAPI:CloseComPort(sErreur) ALORS Erreur(sErreur)
//
PROCEDURE CloseComPort(Addr_sRetourErreur est une chaîne="")

bRes est un booléen
eRes est un entier
Addr_sRetourErreur = ""
// Restauration des TO d'origine
SI :eHandle>0 ALORS
eRes = API(::CT_sNomDLL, "SetCommTimeouts", :eHandle, &:stTO_Orig)
SI PAS eRes ALORS
Addr_sRetourErreur = "Erreur lors de la restauration des Time-out d'origine"+RC
FIN
eRes = API(::CT_sNomDLL, "CloseHandle", :eHandle)
SI eRes<=0 ALORS
Addr_sRetourErreur += "Erreur lors de la fermeture du port com"+:eNumComPort
SINON
bRes = Vrai
FIN
FIN
SI PAS Addr_sRetourErreur~="" ALORS :Tracer(Addr_sRetourErreur)
RENVOYER bRes
************************************************************************


************ METHODE Tracer ********************************************
// Résumé : Tracer les événements de la classe
// Syntaxe :
//Tracer (<sChaine> est chaîne)
//
// Paramètres :
// sChaine (chaîne ANSI) : Chaine à tracer
// Valeur de retour :
// Aucune
//
// Exemple :
// Trace("Don't Worry, be API")
//
PROCEDURE VIRTUELLE Tracer(LOCAL sChaine est une chaîne)
// A redéfinir pour trace dans un fichier, un xml etc...
Trace(DateVersChaîne(DateSys())+" "+HeureVersChaîne(HeureSys())+" [COM"+:eNumComPort+"] "+sChaine)

************ FIN DU CODE DE cRS232API **********************************

--
Romain PETIT
contact : rompetit chez free fr
+-+ posté sur Usenet avec MesNews et non depuis un forum web +-+
news:fr.comp.developpement.agl.windev
http://www.mesnews.net/
http://fr.wikipedia.org/wiki/Newsgroup
Avatar
André STASZEWSKI
Dans son message précédent, Romain PETIT a écrit :
Je posterai la solution après avoir écrit un truc plus propre.
Si ça interesse quelqu'un ?



Bon bé voilà.
C'est sous forme d'une petite classe WD20 sous licence WD-Libre.
Tout est expliqué dans le code de la classe.
Téléchargeable ici : http://www.windasso.org/
(rubrique téléchargement)

(sinon, j'ai mis le code ci-dessous pour d'autres versions de WD, mais
il va falloir copier-coller et gérer les lignes qui risquent d'être
tronquées...)

Je n'ai pas tout testé, notamment en 64b, ou encore les paramétrages de
contrôle de flux...
Faites-moi un retour si vous constatez un pbm.

A+


************************************************************************




Bien bossé...
Merci Romain !

--
Cordialement,
André STASZEWSKI
http://www.SoftSolution.fr
Pour me contacter, cliquez ici :
http://cerbermail.com/?Z8IP9sIahR
Avatar
Eric Laurent
Merci Romain,
Bon boulot, bien documenté !
Avatar
eric
Le mercredi 11 mars 2015 10:59:30 UTC+1, Romain PETIT a écrit :

Bonjour,

j'ecrit peut étre un peu tard,
pourquoi ne pas utiliser un buffer hardware ( en téléphonie nous utilis ons cela pour éviter la perte de données) il y a 2 com 1 in et 1 out
cela permet de travailler avec un " fil de l'eau " même en cas de coupure .

eric

ps pour une telle vitesse un cable blindé et une connectique compléte s ont peut étre nécessaire , rts cet cts ainsi que les autres pins doiven te étre reliés , le shéma 2x3 et masse risque d'étre léger.

eric

Bonjour,

J'ai un soucis avec les fonctions du port série (ou émulation via USB )
de Windev (version 20 mais je pense que c'est pareil avec toutes les
version).

Je dois récupérer un fichier binaire d'environ 80~100 ko à 115200 b ps
sans contrôle de flux ni matériel ni logiciel (pas le choix).
Une première commande permet d'avoir la taille exacte du fichier, on
envoie une seconde commande pour initier la demande de transfert.
Un écho à la commande est reçu et après une petite tempo le flux arrive
en lecture.
La fin est détectée avec un timeout et/ou en vérifiant la taille du
fichier et un CRC est lu et recalculé pour vérification.

- Tout ça marche bien avec mes fonctions de lecture/écriture que
j'utilise depuis 10 ans, jusqu'à une vitesse de 19200 bps.

- Avec une vitesse supérieure (57600 ou 115200 bps, j'ai beau essayer
tous les paramètres possibles (buffer, branchement d'un évenement ave c
uniquement la lecture ou utilisation d'une boucle sans fin, paramètre
"temporisation"), il manque toujours 200 à 300 octets dans le fichier
(bizarement toujours situés à peu prêt au même endroit sans que j 'ai pu
déterminer une raison, vers l'octet 4300.)

- Je peux exclure un problème matériel car si j'utilise un terminal
(hyperterminal, teraterm) tout se passe correctement.

- J'ai déjà testé avec succès une solution alternative en utilisa nt une
DLL payante facile à utiliser et performante
(http://www.marshallsoft.com/wsc4vb.htm) mais je voudrais avoir votre
avis :

- Une expérience similaire ? Une solution possible sans un composant
tiers ?
- Une autre référence de DLL ? (une solution opensource sans activeX à
enregistrer serait l'idéal).

Merci
A+

--
Romain PETIT
contact : rompetit chez free fr
+-+ posté sur Usenet avec MesNews et non depuis un forum web +-+
news:fr.comp.developpement.agl.windev
http://www.mesnews.net/
http://fr.wikipedia.org/wiki/Newsgroup
Avatar
Romain PETIT
eric a formulé la demande :
Le mercredi 11 mars 2015 10:59:30 UTC+1, Romain PETIT a écrit :

Bonjour,



Bonjour,

j'ecrit peut étre un peu tard,
pourquoi ne pas utiliser un buffer hardware ( en téléphonie nous utilisons
cela pour éviter la perte de données) il y a 2 com 1 in et 1 out cela permet
de travailler avec un " fil de l'eau " même en cas de coupure.



Idée interessante mais peu applicable dans mon cas car il faudrait
alors fournir le matériel à tous nos clients...

ps pour une telle vitesse un cable blindé et une connectique compléte sont
peut étre nécessaire , rts cet cts ainsi que les autres pins doivente étre
reliés , le shéma 2x3 et masse risque d'étre léger.



J'utilise un câble USB/RS232 FTDI de 2m (ou 3?), et ca fonctionne
correctement (avec les API, pas avec Windev). Je peux avoir une erreur
de checksum de temps en temps mais le gain de vitesse en passant de
19200 à 115200 compense largement l'inconvénient de devoir recommencer
le téléchargement si cela survient..

A+

--
Romain PETIT
contact : rompetit chez free fr
+-+ posté sur Usenet avec MesNews et non depuis un forum web +-+
news:fr.comp.developpement.agl.windev
http://www.mesnews.net/
http://fr.wikipedia.org/wiki/Newsgroup

---
L'absence de virus dans ce courrier électronique a été vérifiée par le logiciel antivirus Avast.
http://www.avast.com
1 2 3