Bonjour,

Je souhaiterais récupérer, dans un programme java, les glycémies conservées par mon lecteur de glycémies (FreeStyle Papillon fabriqué désormais par la société Abbott) via une connexion série.

Le fabriquant de cet appareil propose de relier l’appareil au PC via un câble USB. Il faut installer un driver qui permet de créer un port série virtuel pour communiquer avec l’appareil.

En utilisant le logiciel fournit par Abbott (nommé coPilot) et un logiciel me permettant de sniffer la communication sur le port série virtuel (HDD Serial Monitor), j’ai pu déterminer les commandes à envoyer au lecteur pour récupérer les données :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Port ouvert par le processus "CoPilot.exe" (PID: 1268)

Requête:02/02/2010 22:13:55.830239064 (+188.8698027000 seconds)
 00                                                .               

Requête:02/02/2010 22:13:56.160257964 (+0.3300189000 seconds)
 00                                                .               

Requête:02/02/2010 22:13:56.490276764 (+0.3300188000 seconds)
 6D 65 6D                                          mem             

Réponse:02/02/2010 22:13:56.616283964 (+0.1260072000 seconds)
 0D 0A 44 42 47 4D 31 30 36 2D 46 30 39 34 39 0D   ..DBGM106-F0949.
 0A 31 2E 31 34 20 20 20 20 20 20 20 2D 50 0D 0A   .1.14       -P..
 46 65 62 20 20 30 32 20 32 30 31 30 20 32 32 3A   Feb  02 2010 22:
 31 33 3A 30 31 0D 0A 30 30 36 0D 0A 0A 30 35 36   13:01..006...056
 20 20 4A 61 6E 20 20 33 30 20 32 30 31 30 20 31     Jan  30 2010 1
 33 3A 33 39 20 30 30 20 30 78 30 30 0D 0A 30 34   3:39 00 0x00..04
 37 20 20 4A 61 6E 20 20 33 30 20 32 30 31 30 20   7  Jan  30 2010 
 31 33 3A 33 31 20 30 30 20 30 78 30 30 0D 0A 31   13:31 00 0x00..1
 31 35 20 20 4A 61 6E 20 20 33 30 20 32 30 31 30   15  Jan  30 2010
 20 31 33 3A 33 30 20 30 30 20 30 78 30 30 0D 0A    13:30 00 0x00..
 31 35 30 20 20 4A 61 6E 20 20 33 30 20 32 30 31   150  Jan  30 201
 30 20 31 31 3A 32 30 20 30 30 20 30 78 30 30 0D   0 11:20 00 0x00.
 0A 31 34 35 20 20 4A 61 6E 20 20 33 30 20 32 30   .145  Jan  30 20
 31 30 20 31 31 3A 31 39 20 30 30 20 30 78 30 31   10 11:19 00 0x01
 0D 0A 31 39 38 20 20 4A 61 6E 20 20 32 37 20 32   ..198  Jan  27 2
 30 31 30 20 30 38 3A 34 39 20 30 30 20 30 78 30   010 08:49 00 0x0
 30 0D 0A 30 78 33 30 41 41 20 20 45 4E 44 0D 0A   0..0x30AA  END..

Port fermé
De plus, je dispose également du paramétrage du port à utiliser : Nom : paramConnexion.png
Affichages : 309
Taille : 1,2 Ko et Nom : paramConnexion2.png
Affichages : 347
Taille : 106,2 Ko.

En java, j’ai essayé d’utiliser les deux APIs disponibles pour interroger le port série (javax.comm et RXTX). En utilisant l’outil pour sniffer la communication entre le PC et le port série virtuel, je ne trouve pas d’écart avec le logiciel fournit par Abbott (j’envoi bien deux fois le caractère hexa 0x00 séparé de 300ms puis les caractères « mem »… mais pourtant, le lecteur de glycémies ne retourne aucune informations…

Voici mon code java avec l’API javax.comm :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
 
package fr;
 
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.TooManyListenersException;
 
import javax.comm.CommPortIdentifier;
import javax.comm.NoSuchPortException;
import javax.comm.PortInUseException;
import javax.comm.SerialPort;
import javax.comm.SerialPortEvent;
import javax.comm.SerialPortEventListener;
import javax.comm.UnsupportedCommOperationException;
 
import com.sun.comm.Win32Driver;
 
public class TesterCommunicationFreeStylePapillon implements SerialPortEventListener {
	private final String port; 
	private CommPortIdentifier portId;
	private SerialPort serialPort;
 
	private BufferedReader fluxLecture = null;
	private OutputStream fluxEcriture = null;
 
	public TesterCommunicationFreeStylePapillon(String port) throws Exception
	{
		this.port = port;
 
		//initialisation du driver
		Win32Driver w32Driver = new Win32Driver();
		w32Driver.initialize();
		//récupération de l'identifiant du port
		try {
			portId = CommPortIdentifier.getPortIdentifier(port);
		} catch (NoSuchPortException e) {
			throw e;
		}
 
		//ouverture du port
		try {
			serialPort = (SerialPort) portId.open("ModeEvenement", 2000);
		} catch (PortInUseException e) {
			throw e;
		}
 
 
		//paramétrage du port
		serialPort.notifyOnDataAvailable(true);
		serialPort.setRTS(true);
		serialPort.notifyOnCTS(true);
		serialPort.setDTR(true);
 
		try {
			serialPort.setSerialPortParams(
				9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
 
			serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);
		} catch (UnsupportedCommOperationException e) {
			throw e;
		}
 
		// ajout du listener
		try {
			serialPort.addEventListener(this);
		} catch (TooManyListenersException e) {
			throw e;
		}
 
		// récupération du flux de lecture et écriture du port
		try {
			fluxEcriture = serialPort.getOutputStream();
			fluxLecture = new BufferedReader( new InputStreamReader(serialPort.getInputStream()) );
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
 
		System.out.println("port ouvert, flux ouvert, attente opération...");
 
		// Cette solution envoie les 4 premières lignes
		sendMessage((char)0);
		Thread.sleep(300);
		sendMessage((char)0);
		Thread.sleep(300);
		sendMessage("mem");
 
		Thread.sleep(10000);
		System.out.println("8 - Fin du test...");
		fluxEcriture.close();
		fluxLecture.close();
		serialPort.close();
		System.out.println("9 - Fermeture du port série.");
	}
 
	private void sendMessage(String s) throws RuntimeException, IllegalArgumentException {
   		try {
			fluxEcriture.write(s.getBytes());
   			//fluxEcriture.write(s.getBytes(Charset.forName("UTF-8")));
		} catch (IOException e) {
			e.printStackTrace();
		}
    }
 
	private void sendMessage(char envoie) throws RuntimeException {
		try {
			fluxEcriture.write((int) envoie);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
 
	@Override
	public void serialEvent(SerialPortEvent event) {
		//gestion des événements sur le port :
		//on ne fait rien sauf quand les données sont disponibles
		switch (event.getEventType()) {
			case SerialPortEvent.BI :
			case SerialPortEvent.OE :
			case SerialPortEvent.FE :
			case SerialPortEvent.PE :
			case SerialPortEvent.CD :
			case SerialPortEvent.CTS :
			case SerialPortEvent.DSR :
			case SerialPortEvent.RI :
			case SerialPortEvent.OUTPUT_BUFFER_EMPTY :
				System.out.println("vide " + event.getEventType());
				break;
 
			case SerialPortEvent.DATA_AVAILABLE :
				String reponse = new String(); 
				try {
					//lecture du buffer et affichage
					reponse = (String) fluxLecture.readLine();
					System.out.println("<--- " + reponse);
				} catch (IOException e) {
					e.printStackTrace();
				}
				break;
		}
	}
 
	/**
         * @param args
         */
	public static void main(String[] args) throws Exception {
		new TesterCommunicationFreeStylePapillon("COM12");
	}
}
En utilisant l'API RXTX :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
 
package portCom;
 
import gnu.io.CommDriver;
import gnu.io.CommPortIdentifier;
import gnu.io.NoSuchPortException;
import gnu.io.PortInUseException;
import gnu.io.RXTXCommDriver;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import gnu.io.UnsupportedCommOperationException;
 
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TooManyListenersException;
 
public class TestCommunicationFreeStyle {
	private CommDriver myDriver = null;
	private CommPortIdentifier portId = null;
	private SerialPort serialPort = null;
 
	private BufferedReader fluxLecture = null;
	private OutputStream fluxEcriture = null;
 
	public TestCommunicationFreeStyle(String port) {
		System.out.println("1 - Initialisation du driver RXTX");
		myDriver = new RXTXCommDriver(); 
 
		if (myDriver != null) {
			myDriver.initialize();
		} 
 
		System.out.println("2 - Détection du port " + port);
		// détection du port série
		try {
			portId = CommPortIdentifier.getPortIdentifier(port);
		} catch (NoSuchPortException e) {
			e.printStackTrace();
		}
 
		if (portId == null) {
			e.printStackTrace();
		}
 
		try {
			System.out.println("3 - Début ouverture du port");
			serialPort = (SerialPort) portId.open("FreeStylePapillon", 2000);
 
			// on sélectionne tous les paramètres de la connexion série:
			serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);
			serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
			serialPort.notifyOnDataAvailable(true);
			serialPort.notifyOnCTS(true);
			serialPort.setRTS(true);
			serialPort.setDTR(true);
 
			System.out.println("4 - Fin du paramétrage du port");
		} catch (PortInUseException e1) {
			System.out.println(e1);
 
		} catch (UnsupportedCommOperationException e1) {
			System.out.println(e1);
		}
 
		// récupération du flux de lecture et écriture du port
		try {
			fluxEcriture = serialPort.getOutputStream();
			fluxLecture = new BufferedReader( new InputStreamReader(serialPort.getInputStream()) );
		} catch (IOException e) {
			e.printStackTrace();
		}
 
		// ajout du listener
		try {
			serialPort.addEventListener(
				new LectureFlux(fluxLecture)
			);
 
		} catch (TooManyListenersException e) {
			e.printStackTrace();
		}
 
		try {
			// 1 : Lecture du paramétrage
			System.out.println("\n\n*****************\nLecture des données");
			sendMessage((char)0x00);
			Thread.sleep(300);
			sendMessage((char)0x00);
			Thread.sleep(300);
			sendMessage("mem");
 
			Thread.sleep(10000);
			System.out.println("\n13 - Fermeture du port série.");
			serialPort.close();
			System.out.println("14 - Fin de l'application.");
			System.exit(0);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
 
	private void sendMessage(char envoie) throws RuntimeException {
		try {
			fluxEcriture.write((int) envoie);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
 
 
	private void sendMessage(String s) throws RuntimeException, IllegalArgumentException {
   		byte[] tab = s.getBytes();
   		try {
			fluxEcriture.write(tab);
		} catch (IOException e) {
			e.printStackTrace();
		}
    }
 
	/**
         * @param args
         */
	public static void main(String[] args) {
		new TestCommunicationFreeStyle("COM12");
	}
 
 
	public class LectureFlux implements SerialPortEventListener {
		private BufferedReader myFluxLecture = null;
 
		public LectureFlux(BufferedReader fluxLecture) throws IllegalArgumentException {
			myFluxLecture = fluxLecture;
		}
 
		public void serialEvent(SerialPortEvent event) {
			// gestion des événements sur le port :
			//on ne fait rien sauf quand les données sont disponibles
			switch (event.getEventType()) {
				case SerialPortEvent.BI :
				case SerialPortEvent.OE :
				case SerialPortEvent.FE :
				case SerialPortEvent.PE :
				case SerialPortEvent.CD :
				case SerialPortEvent.CTS :
				case SerialPortEvent.DSR :
				case SerialPortEvent.RI :
				case SerialPortEvent.OUTPUT_BUFFER_EMPTY :
					System.out.println("Réponse inaudible !");
					break;
 
				case SerialPortEvent.DATA_AVAILABLE :
					String commande = new String(); 
					try {
						//lecture du buffer et affichage
						commande = (String) myFluxLecture.readLine();
						System.out.println(" <--- " + commande);
					} catch (IOException e) {
						e.printStackTrace();
					}
 
 	                break;
			}
		}
	}
}
Je n’obtiens pas d’erreur java mais le lecteur de glycémies ne réponds pas. Par contre, il s’allume…. donc il reçoit bien quelques signaux…

Avez-vous une idée de pourquoi cela ne marche po ?
C'est grave docteur ?
Que peut-il se passer ?
Et que puis-je faire ?

Merci d'avance pour votre aide.
A.