Changeset 3544 for pykocard/trunk

Show
Ignore:
Timestamp:
04/27/10 13:31:47 (15 years ago)
Author:
jerome
Message:

Some untested code, for a change.

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • pykocard/trunk/pykocard/cartadistcrs.py

    r3543 r3544  
    2323 
    2424import sys 
     25import time 
    2526 
    2627import serial # On Debian/Ubuntu : apt-get install python-serial 
     
    5758SENSORUNKNOWN3=3   # Partially inside the TCRS 
    5859 
    59 class CartadisTCRS : 
     60# Waiting loop delay 
     61WAITDELAY=1.0 # 1 second 
     62 
     63class Terminal : 
     64    """Base class for all terminals.""" 
     65    def __init__(self, device, timeout=1.0, debug=False) : 
     66        """Must be implemented elsewhere.""" 
     67        raise NotImplementedError 
     68 
     69    def __del__(self) : 
     70        """Ensures the serial link is closed on deletion.""" 
     71        self.close() 
     72 
     73    def logError(self, message) : 
     74        """Logs an error message.""" 
     75        sys.stderr.write("%s\n" % message) 
     76        sys.stderr.flush() 
     77 
     78    def logDebug(self, message) : 
     79        """Logs a debug message.""" 
     80        if self.debug : 
     81            self.logError(message) 
     82 
     83class CartadisTCRS(Terminal) : 
    6084    """A class to manage Cartadis TCRS vending card readers. 
    6185 
     
    6993        self.timeout = timeout 
    7094        self.debug = debug 
     95 
     96        self.debitCardTypes = (3, 5, 6, 7) # TODO : define some constants for these card types 
    7197 
    7298        self.lastcommand = None 
     
    112138                                 self.serialNumber)) 
    113139 
    114     def __del__(self) : 
    115         """Ensures the serial link is closed on deletion.""" 
    116         self.close() 
    117  
    118     def close(self) : 
    119         """Closes the serial link if it is open.""" 
    120         if self.tcrs is not None : 
    121             self.logDebug("Closing serial link...") 
    122             self.tcrs.close() 
    123             self.tcrs = None 
    124             self.logDebug("Serial link closed.") 
    125  
    126     def logError(self, message) : 
    127         """Logs an error message.""" 
    128         sys.stderr.write("%s\n" % message) 
    129         sys.stderr.flush() 
    130  
    131     def logDebug(self, message) : 
    132         """Logs a debug message.""" 
    133         if self.debug : 
    134             self.logError(message) 
    135  
    136     def sendCommand(self, cmd, param=None) : 
     140    def _sendCommand(self, cmd, param=None) : 
    137141        """Sends a command to the TCRS.""" 
    138142        if self.tcrs is not None : 
     
    165169            self.logError("Device %s is not open" % self.device) 
    166170 
     171    # Device specific calls 
    167172    def help(self) : 
    168173        """Returns the list of commands supported by the TCRS.""" 
    169         return self.sendCommand("help") 
     174        return self._sendCommand("help") 
    170175 
    171176    def version(self) : 
    172177        """Returns the TCRS' version string.""" 
    173         return self.sendCommand("version") 
     178        return self._sendCommand("version") 
    174179 
    175180    def serial(self) : 
    176181        """Returns the TCRS' serial number.'""" 
    177         return self.sendCommand("serial") 
     182        return self._sendCommand("serial") 
    178183 
    179184    def read(self) : 
    180185        """Reads the card's content to the TCRS. Returns the type of card or an error value.""" 
    181         return int(self.sendCommand("read") or -1) 
     186        return int(self._sendCommand("read") or -1) 
    182187 
    183188    def write(self) : 
    184189        """Writes the TCRS values to the card. Returns 0 or error value.""" 
    185         return int(self.sendCommand("write")) 
     190        return int(self._sendCommand("write")) 
    186191 
    187192    def sensor(self) : 
    188193        """Returns 0 if there's no card in TCRS, else 1, 2 or 3.""" 
    189         return int(self.sendCommand("sensor")) 
     194        return int(self._sendCommand("sensor")) 
    190195 
    191196    def eject(self) : 
    192197        """Ejects the card from the TCRS.""" 
    193         return self.sendCommand("eject") 
     198        return self._sendCommand("eject") 
    194199 
    195200    def trnum(self) : 
    196201        """Returns the number of transactions made with this card.""" 
    197         return int(self.sendCommand("trnum")) 
     202        return int(self._sendCommand("trnum")) 
    198203 
    199204    def value(self, value=None) : 
    200205        """Returns the last value read, or sets the new value of the card, but doesn't write it to the card yet.""" 
    201206        if value is None : 
    202             return int(self.sendCommand("value")) 
    203         else : 
    204             return self.sendCommand("value", str(value)) 
     207            return int(self._sendCommand("value")) 
     208        else : 
     209            return self._sendCommand("value", str(value)) 
    205210 
    206211    def account(self, account=None) : 
    207212        """Returns the last account number read, or sets the account number, but doesn't write it to the card yet.'""" 
    208213        if account is None : 
    209             return int(self.sendCommand("account")) 
    210         else : 
    211             return self.sendCommand("account", str(account)) 
     214            return int(self._sendCommand("account")) 
     215        else : 
     216            return self._sendCommand("account", str(account)) 
    212217 
    213218    def department(self, department=None) : 
    214219        """Returns the last department number read, or sets the department number, but doesn't write it to the card yet.'""" 
    215220        if department is None : 
    216             return int(self.sendCommand("department")) 
    217         else : 
    218             return self.sendCommand("department", str(department)) 
     221            return int(self._sendCommand("department")) 
     222        else : 
     223            return self._sendCommand("department", str(department)) 
    219224 
    220225    def group(self, group=None) : 
    221226        """Returns the last group number read, or sets the group number, but doesn't write it to the card yet.'""" 
    222227        if group is None : 
    223             return int(self.sendCommand("group")) 
    224         else : 
    225             return self.sendCommand("group", str(group)) 
     228            return int(self._sendCommand("group")) 
     229        else : 
     230            return self._sendCommand("group", str(group)) 
    226231 
    227232    def addgrp(self, group=None) : 
    228233        """Adds the group to the list of allowed ones. If no group, the one on the admin card is used.""" 
    229         return int(self.sendCommand("addgrp", str(group))) 
     234        return int(self._sendCommand("addgrp", str(group))) 
    230235 
    231236    def listgrp(self) : 
    232237        """Returns the list of allowed group numbers.""" 
    233         return [int(g) for g in self.sendCommand("listgrp").split()] 
     238        return [int(g) for g in self._sendCommand("listgrp").split()] 
    234239 
    235240    def delgrp(self, group) : 
    236241        """Deletes the group from the list of allowed groups.""" 
    237         return int(self.sendCommand("delgrp", str(group))) 
     242        return int(self._sendCommand("delgrp", str(group))) 
    238243 
    239244    def cardtype(self, cardtype=None) : 
     
    241246        # TODO : doesn't seem to return a meaningful answer 
    242247        if cardtype is None : 
    243             answer = self.sendCommand("cardtype") 
    244         else : 
    245             answer = self.sendCommand("cardtype", str(cardtype)) 
     248            answer = self._sendCommand("cardtype") 
     249        else : 
     250            answer = self._sendCommand("cardtype", str(cardtype)) 
    246251        try : 
    247252            return int(answer) 
     
    252257    def display(self, text) : 
    253258        """Displays a string of text on the TCRS' screen.""" 
    254         return self.sendCommand("display", text) 
     259        return self._sendCommand("display", text) 
    255260 
    256261    def echo(self, echo) : 
     
    281286        """Changes the text displayed after the value of the card (e.g. 'EURO').""" 
    282287        raise NotImplementedError 
     288 
     289    # Public API 
     290    def close(self) : 
     291        """Closes the serial link if it is open.""" 
     292        if self.tcrs is not None : 
     293            self.logDebug("Closing serial link...") 
     294            self.tcrs.close() 
     295            self.tcrs = None 
     296            self.logDebug("Serial link closed.") 
     297 
     298    def waitForCard(self) : 
     299        """Waits for the card to be inserted into the terminal.""" 
     300        while tcrs.sensor() != SENSORCARDINSIDE : 
     301            time.sleep(WAITDELAY) 
     302 
     303class CreditCard : 
     304    """A class for cards.""" 
     305    def __init__(self, terminal) : 
     306        """Initializes a card present in the terminal.""" 
     307        self.terminal = terminal 
     308        self.value = None 
     309        terminal.waitForCard() 
     310        if terminal.read() in terminal.debitCardTypes : 
     311            self.value = terminal.value() 
     312 
     313    def releaseCard(self) : 
     314        """Ejects the card from the terminal.""" 
     315        result = self.terminal.eject() 
     316        self.value = None 
     317        return result 
     318 
     319    def __int__(self) : 
     320        """Returns the number of credits on the card as an integer.""" 
     321        return int(self.value) 
     322 
     323    def __float__(self) : 
     324        """Returns the number of credits on the card as a float.""" 
     325        return float(self.value) 
     326 
     327    def __iadd__(self, other) : 
     328        """Increases the number of credits on a card with 'card += amount'.""" 
     329        newvalue = self.value + other 
     330        writtenvalue = self.terminal.value(newvalue) 
     331        if writtenvalue == newvalue : 
     332            if self.terminal.write() == NOERROR : 
     333                # TODO : should we return 'writtenvalue' or read from the card again to be sure ? 
     334                # Is another read() call needed before ? TODO : check this again with the real card reader. 
     335                self.value = self.terminal.value() 
     336                return self.value 
     337        raise ValueError, "Unable to read or write the card" 
     338 
     339    def __isub__(self, other) : 
     340        """Decreases the number of credits on a card with 'card -= amount'.""" 
     341        newvalue = self.value - other 
     342        writtenvalue = self.terminal.value(newvalue) 
     343        if writtenvalue == newvalue : 
     344            if self.terminal.write() == NOERROR : 
     345                # TODO : should we return 'writtenvalue' or read from the card again to be sure ? 
     346                # Is another read() call needed before ? TODO : check this again with the real card reader. 
     347                self.value = self.terminal.value() 
     348                return self.value 
     349        raise ValueError, "Unable to read or write the card" 
    283350 
    284351if __name__ == "__main__" : 
     
    295362        sys.stdout.write("Allowed groups : %s\n" % tcrs.listgrp()) 
    296363 
    297         import time 
    298364        sys.stdout.write("Please insert your card into the TCRS...") 
    299365        sys.stdout.flush() 
    300         while True : 
    301             cardpresent = tcrs.sensor() 
    302             tcrs.logDebug("Sensor Status : %i\n" % cardpresent) 
    303             if cardpresent == SENSORCARDINSIDE : 
    304                 break 
    305             time.sleep(1.0) 
     366        tcrs.waitForCard() 
    306367        sys.stdout.write("\n") 
    307368 
     
    324385        #tcrs.read() 
    325386        #sys.stdout.write("Card now has %s credits\n" % tcrs.value()) 
     387        # 
     388        tcrs.eject() 
     389        # 
     390        # And now some higher level API 
     391        creditcard = CreditCard(tcrs) # Waits until card is inserted 
     392        creditcard += 5 # This one will fail with my terminal, but won't consume my credits :-) 
     393        # creditcard -= 1 # This one would work with my terminal, but would consume my credits :-) 
     394        creditcard.release() 
    326395    finally : 
    327         # We always do an eject, even if card not present 
    328         tcrs.eject() 
    329396        tcrs.close()