Index: /pykocard/trunk/pykocard/cartadistcrs.py
===================================================================
--- /pykocard/trunk/pykocard/cartadistcrs.py (revision 3539)
+++ /pykocard/trunk/pykocard/cartadistcrs.py (revision 3540)
@@ -26,4 +26,30 @@
 import serial # On Debian/Ubuntu : apt-get install python-serial
 
+# Some constants : names are mine, not Cartadis.
+#
+# Write errors
+NOERROR = 0
+ERRWRITEERROR = -1
+ERRNOCARD = -2
+ERRCARDBLOCKED = -3
+ERRUNKNOWNCARD = -4
+ERRINVALID = -5
+ERRMAXTRANSACTION = -6
+ERRVALUETOOHIGH = -7
+ERRGROUPNOTALLOWED = -8
+ERRWRITEBEFOREREAD = -9
+ERRREADBEFOREWRITE = -10
+ERRCOMPARISON = -11
+#
+# Read errors
+ERRREADERROR = -1
+#
+# Other errors
+ERRILLEGALGROUP = -1
+ERRNOTADMIN = -9
+ERRLISTFULL = -10
+ERRADMINNOTALLOWED = -11
+
+
 class CartadisTCRS :
     """A class to manage Cartadis TCRS vending card readers.
@@ -34,5 +60,5 @@
     """
     def __init__(self, device, timeout=5.0, debug=False) :
-        """Initializes the connection to the reader."""
+        """Initializes the connection to the TCRS."""
         self.device = device
         self.timeout = timeout
@@ -40,24 +66,19 @@
 
         self.lastcommand = None
-        self.tcrsprompt = chr(13) + chr(10) + '$' # the prompt
+        self.sol = chr(13) + chr(10) # start of line (begins each answer)
+        self.sollen = len(self.sol)
+        self.prompt = chr(13) + chr(10) + '$' # the prompt
+        self.promptlen = len(self.prompt)
         self.eoc = chr(13) # end of command
 
         # Each Cartadis vending card contain the following informations :
-        #
-        # the card can only be read on readers for which this group number
-        # was specifically allowed.
-        self.group = None
-        # the number of credits on the card.
-        self.value = None
-        # the two following fields allow the card
-        # to be assigned to a particular individual.
-        # only plastic cards can use such attributes,
-        # for throw-away cards, these values should both be set to 0
-        self.department = None
-        self.account = None
-        # transaction number. Max 3000 for plastic cards, else 500.
-        self.trnum = None
-
-        # opens the connection to the reader
+        self.cardcontent = { "group" : None, # the card can only be read on a TCRS for which this group number was specifically allowed.
+                             "value" : None, # the number of credits on the card.
+                             "department" : None, # these two fields can be used to identify the owner of the card
+                             "account" : None,
+                             "trnum" : None  # Transaction number : Max 3000 for plastic cars, else 500.
+                           }
+
+        # opens the connection to the TCRS
         self.tcrs = serial.Serial(device,
                                   baudrate=9600,
@@ -70,13 +91,19 @@
 
         # cleans up any data waiting to be read
-        self.tcrs.flushInput()
-
-        # Identifies the terminal
-        self.versionNumber = self.version()
-        self.serialNumber = self.serial()
-        self.logDebug("%s terminal detected on device %s with serial number %s" \
-                          % (self.versionNumber,
-                             self.device,
-                             self.serialNumber))
+        try :
+            self.tcrs.flushInput()
+        except serial.serialutil.SerialException, msg :
+            self.logError(msg)
+            self.close()
+        else :
+            # Identifies the terminal
+            self.versionNumber = self.version()
+            self.serialNumber = self.serial()
+            self.logDebug("%s terminal detected on device %s with serial number %s" \
+                              % (self.versionNumber,
+                                 self.device,
+                                 self.serialNumber))
+            self.supportedCommands = self.help()
+            self.logDebug("Supported commands : %s" % self.supportedCommands)
 
     def __del__(self) :
@@ -92,32 +119,43 @@
             self.logDebug("Serial link closed.")
 
+    def logError(self, message) :
+        """Logs an error message."""
+        sys.stderr.write("%s\n" % message)
+        sys.stderr.flush()
+
     def logDebug(self, message) :
         """Logs a debug message."""
         if self.debug :
-            sys.stderr.write("%s\n" % message)
-            sys.stderr.flush()
+            self.logError(message)
 
     def sendCommand(self, cmd, param=None) :
-        """Sends a command to the reader."""
-        if param is not None :
-            command = "%s %s%s" % (cmd, param, self.eoc)
-        else :
-            command = "%s%s" % (cmd, self.eoc)
-        self.logDebug("Sending %s to reader" % repr(command))
-        self.tcrs.write(command)
-        self.tcrs.flush()
-        self.lastcommand = command
-        #
-        # IMPORTANT : the following code doesn't work because currently
-        # PySerial doesn't allow an EOL marker to be several chars long.
-        # I've just sent a patch for this to PySerial's author, and we'll
-        # see what happens. If not accepted, I'll write it another way.
-        return = self.tcrs.readline(eol=self.tcrsprompt)[:-len(self.tcrsprompt)]
+        """Sends a command to the TCRS."""
+        if self.tcrs is not None :
+            if param is not None :
+                command = "%s %s%s" % (cmd, param, self.eoc)
+            else :
+                command = "%s%s" % (cmd, self.eoc)
+            self.logDebug("Sending %s to TCRS" % repr(command))
+            self.tcrs.write(command)
+            self.tcrs.flush()
+            self.lastcommand = command
+            #
+            # IMPORTANT : the following code doesn't work because currently
+            # PySerial doesn't allow an EOL marker to be several chars long.
+            # I've just sent a patch for this to PySerial's author, and we'll
+            # see what happens. If not accepted, I'll write it another way.
+            answer = self.tcrs.readline(eol=self.prompt)
+            self.logDebug("TCRS answered %s" % repr(answer))
+            if answer.startswith(self.sol) and answer.endswith(self.prompt) :
+                return answer[self.sollen:-self.promptlen]
+            else :
+                self.logError("Unknown answer %s" % repr(answer))
+                return None
+        else :
+            self.logError("Device %s is not open" % self.device)
 
     def help(self) :
         """Returns the list of commands supported by the TCRS."""
-        result = self.sendCommand("help")
-        self.logDebug("Supported commands : %s" % result)
-        return result
+        return self.sendCommand("help")
 
     def version(self) :
@@ -128,4 +166,100 @@
         """Returns the TCRS' serial number.'"""
         return self.sendCommand("serial")
+
+    def read(self) :
+        """Reads the card's content to the TCRS. Returns the type of card or an error value."""
+        return int(self.sendCommand("read"))
+
+    def write(self) :
+        """Writes the TCRS values to the card. Returns 0 or error value."""
+        return int(self.sendCommand("write"))
+
+    def sensor(self) :
+        """Returns 0 if there's no card in TCRS, else 1, 2 or 3."""
+        return int(self.sendCommand("sensor"))
+
+    def eject(self) :
+        """Ejects the card from the TCRS."""
+        return self.sendCommand("eject")
+
+    def trnum(self) :
+        """Returns the number of transactions made with this card."""
+        return int(self.sendCommand("trnum"))
+
+    def value(self, value=None) :
+        """Returns the last value read, or sets the new value of the card, but doesn't write it to the card yet."""
+        if value is None :
+            return int(self.sendCommand("value"))
+        else :
+            return self.sendCommand("value", value)
+
+    def account(self, account) :
+        """Returns the last account number read, or sets the account number, but doesn't write it to the card yet.'"""
+        if account is None :
+            return int(self.sendCommand("account"))
+        else :
+            return self.sendCommand("account", account)
+
+    def department(self, department) :
+        """Returns the last department number read, or sets the department number, but doesn't write it to the card yet.'"""
+        if department is None :
+            return int(self.sendCommand("department"))
+        else :
+            return self.sendCommand("department", department)
+
+    def group(self, group) :
+        """Returns the last group number read, or sets the group number, but doesn't write it to the card yet.'"""
+        if group is None :
+            return int(self.sendCommand("group"))
+        else :
+            return self.sendCommand("group", group)
+
+    def addgrp(self, group=None) :
+        """Adds the group to the list of allowed ones. If no group, the one on the admin card is used."""
+        return int(self.sendCommand("addgrp", group))
+
+    def listgrp(self) :
+        """Returns the list of allowed group numbers."""
+        return self.sendCommand("listgrp")
+
+    def delgrp(self, group) :
+        """Deletes the group from the list of allowed groups."""
+        return int(self.sendCommand("delgrp", group))
+
+    def cardtype(self, cardtype) :
+        """Returns the type of card, or sets it (not clear in the doc if a write call is needed or not)."""
+        return int(self.sendCommand("cardtype", cardtype))
+
+    def display(self, text) :
+        """Displays a string of text on the TCRS' screen."""
+        return self.sendCommand("display", text)
+
+    def echo(self, echo) :
+        """Changes the type of echo for the TCRS' keyboard."""
+        raise NotImplementedError
+
+    def key(self, key) :
+        """Not really clear what it does..."""
+        raise NotImplementedError
+
+    def getstr(self) :
+        """Returns a string from keyboard or -1 if buffer is empty."""
+        raise NotImplementedError
+
+    def getkey(self) :
+        """Returns the value of the key pressed, or -1 if no key was hit."""
+        raise NotImplementedError
+
+    def prompt1(self, prompt1) :
+        """Changes the 'Introduce card' message."""
+        raise NotImplementedError
+
+    def prompt2(self, prompt2) :
+        """Changes the 'Credit:' message."""
+        raise NotImplementedError
+
+    def prompt3(self, prompt3) :
+        """Changes the text displayed after the value of the card (e.g. 'EURO')."""
+        raise NotImplementedError
 
 if __name__ == "__main__" :
