- Timestamp:
- 04/27/10 13:31:47 (15 years ago)
- Files:
-
- 1 modified
Legend:
- Unmodified
- Added
- Removed
-
pykocard/trunk/pykocard/cartadistcrs.py
r3543 r3544 23 23 24 24 import sys 25 import time 25 26 26 27 import serial # On Debian/Ubuntu : apt-get install python-serial … … 57 58 SENSORUNKNOWN3=3 # Partially inside the TCRS 58 59 59 class CartadisTCRS : 60 # Waiting loop delay 61 WAITDELAY=1.0 # 1 second 62 63 class 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 83 class CartadisTCRS(Terminal) : 60 84 """A class to manage Cartadis TCRS vending card readers. 61 85 … … 69 93 self.timeout = timeout 70 94 self.debug = debug 95 96 self.debitCardTypes = (3, 5, 6, 7) # TODO : define some constants for these card types 71 97 72 98 self.lastcommand = None … … 112 138 self.serialNumber)) 113 139 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) : 137 141 """Sends a command to the TCRS.""" 138 142 if self.tcrs is not None : … … 165 169 self.logError("Device %s is not open" % self.device) 166 170 171 # Device specific calls 167 172 def help(self) : 168 173 """Returns the list of commands supported by the TCRS.""" 169 return self. sendCommand("help")174 return self._sendCommand("help") 170 175 171 176 def version(self) : 172 177 """Returns the TCRS' version string.""" 173 return self. sendCommand("version")178 return self._sendCommand("version") 174 179 175 180 def serial(self) : 176 181 """Returns the TCRS' serial number.'""" 177 return self. sendCommand("serial")182 return self._sendCommand("serial") 178 183 179 184 def read(self) : 180 185 """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) 182 187 183 188 def write(self) : 184 189 """Writes the TCRS values to the card. Returns 0 or error value.""" 185 return int(self. sendCommand("write"))190 return int(self._sendCommand("write")) 186 191 187 192 def sensor(self) : 188 193 """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")) 190 195 191 196 def eject(self) : 192 197 """Ejects the card from the TCRS.""" 193 return self. sendCommand("eject")198 return self._sendCommand("eject") 194 199 195 200 def trnum(self) : 196 201 """Returns the number of transactions made with this card.""" 197 return int(self. sendCommand("trnum"))202 return int(self._sendCommand("trnum")) 198 203 199 204 def value(self, value=None) : 200 205 """Returns the last value read, or sets the new value of the card, but doesn't write it to the card yet.""" 201 206 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)) 205 210 206 211 def account(self, account=None) : 207 212 """Returns the last account number read, or sets the account number, but doesn't write it to the card yet.'""" 208 213 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)) 212 217 213 218 def department(self, department=None) : 214 219 """Returns the last department number read, or sets the department number, but doesn't write it to the card yet.'""" 215 220 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)) 219 224 220 225 def group(self, group=None) : 221 226 """Returns the last group number read, or sets the group number, but doesn't write it to the card yet.'""" 222 227 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)) 226 231 227 232 def addgrp(self, group=None) : 228 233 """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))) 230 235 231 236 def listgrp(self) : 232 237 """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()] 234 239 235 240 def delgrp(self, group) : 236 241 """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))) 238 243 239 244 def cardtype(self, cardtype=None) : … … 241 246 # TODO : doesn't seem to return a meaningful answer 242 247 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)) 246 251 try : 247 252 return int(answer) … … 252 257 def display(self, text) : 253 258 """Displays a string of text on the TCRS' screen.""" 254 return self. sendCommand("display", text)259 return self._sendCommand("display", text) 255 260 256 261 def echo(self, echo) : … … 281 286 """Changes the text displayed after the value of the card (e.g. 'EURO').""" 282 287 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 303 class 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" 283 350 284 351 if __name__ == "__main__" : … … 295 362 sys.stdout.write("Allowed groups : %s\n" % tcrs.listgrp()) 296 363 297 import time298 364 sys.stdout.write("Please insert your card into the TCRS...") 299 365 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() 306 367 sys.stdout.write("\n") 307 368 … … 324 385 #tcrs.read() 325 386 #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() 326 395 finally : 327 # We always do an eject, even if card not present328 tcrs.eject()329 396 tcrs.close()