[casetta] Variables, Matrices, Lists (Receive and read) |
[ Thread Index | Date Index | More lists.tuxfamily.org/casetta Archives ]
Hello, It is almost 12:00 ! I did not succeded in sending a matrix to my calculator, it is a complete failure. I have a checksum error which is very similar to the one I get when I try to send a picture and that I mentionned by mail (same problem !, in the send_data function in devices_serial). However, I wrote the doc on the raw format page in the wiki. It is possible to receive simple variables, matrices and lists and extract values from them. Build_header works only with matrices. Inserting values is only supported for matrices and simple variables (When I have some free time I will add it : that would be very easy). I have a little problem when receiving multiple variables (With Link > Transmit > sel > Variables), for the last variable, instead of sending its content the calculator sends a header where the content of the variable would be (cafix, has also problems when recieving multiple vairables. So I found a bad solution : if the transfert tool detects the beginning of the header inside a variable's content, it stops. So everything is OK on the computer's side but you have to manually interrupt the com. on the calc. Values are correctly saved in the computer. So has you may have noticed nothing is finnished.... :-) (I am not at my home next week, I will quit my Normandy, so I will not play with casetta). remote-ctrl is for xmms because I don't understand dcop :-). Cheers, --
Linux User #418689 -- fabien.andre.g@xxxxxxxxxx -- xion345@xxxxxxxxxxxxx Note that nobody reads every post in linux-kernel. In fact, nobody who expects to have time left over to actually do any real kernel work will read even half. Except Alan Cox, but he's actually not human, but about a thousand gnomes working in under-ground caves in Swansea. None of the individual gnomes read all the postings either, they just work together really well. ( Linus Torvalds, 2000 ) |
# -*- coding: utf-8 -*- # ############################################################################ # # (c) 2007 Florian Birée aka Thesa <florian.biree@xxxxxxxxxxx> # # Website: <URL:http://casetta.tuxfamily.org> # # Version 0.3.0dev # # changelog: # # # 0.3.0 version: # # o First release # This code is hardly inspired by cafix softwares (cafix.sourceforge.com) # A lot of thanks for cafix coders. # ############################################################################ # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301, USA. # # http://www.gnu.org/copyleft/gpl.html # ############################################################################ """Internal serial tansfer tool""" __author__ = "Florian Birée" __version__ = "0.3.0dev" __copyright__ = "Copyright (c) 2007, Florian Birée" __license__ = "GPL" __revision__ = "$Revision: $" # $Source: $ __date__ = "$Date: $" import serial import time import sys import cas import errors import data as datacls # Default functions def default_status(data_name, current_size, total_size, is_header = False): """Print the status of a transfert on the standard output.""" percent = ((current_size * 100) / total_size) if is_header: progress_line = 'Header ' else: progress_line = data_name + ' ' * (9 - len(data_name)) progress_line += '[' + '=' * (percent / 2) progress_line += ' ' * (50 - (percent / 2)) + '] ' progress_line += '(%i%%) %i/%i' % (percent, current_size, total_size) if current_size != 0: progress_line = '\r' + progress_line sys.stdout.write(progress_line) sys.stdout.flush() if current_size >= total_size: sys.stdout.write('\n') def default_overwrite(data_name): """Ask the user if he want to overwrite data_name on the calculator.""" user_rep = raw_input('Overwrite %s (Y/N): ' % data_name) return user_rep.lower().startswith('y') # Serial management classes class Connexion: """Casetta serial transfer tool.""" name = 'serial' managed_data = [datacls.Program, datacls.Backup, datacls.Picture, \ datacls.ScreenCapture] def __init__(self, serial_port = 0, status = default_status, \ overwrite = default_overwrite): """Initial configuration of the serial port status is a function which is runned as status(current_data_name, current_size, total_size, is_header) each time the status change. overwrite is a function which is runned as overwrite(data_name) and which must return True or False. """ if type(serial_port) == str and serial_port.isdigit(): serial_port = int(serial_port) self.serial = serial.Serial( port=serial_port, baudrate=9600, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, timeout=None, xonxoff=0, #0 rtscts=1) #1 self.status = status self.overwrite = overwrite # low level serial functions def get_byte(self): """Read a single byte""" byte = self.serial.read() return byte def send_byte(self, byte): """Send a single byte""" self.serial.write(byte) def send_string(self, string, status = None, data_name = '', \ is_header = False): """Send a string of bytes""" for index in range(len(string)): self.send_byte(string[index]) time.sleep(0.005) if status != None: status(data_name, index, len(string) - 1, is_header) # send system def send(self, data_list): """Send all data in data_list Warning: a backup must be the only data to send """ while not self.calc_is_ready_to_receive(): pass for data in data_list: self.send_data(data) if data_list[-1].__class__ != datacls.Backup: # Send the END header self.send_header(cas.End()) def calc_is_ready_to_receive(self): """Return if the calculator is ready to receive some data""" interactive = False if interactive: code = '\x06' else: code = '\x16' self.send_byte(code) byte_rep = self.get_byte() if interactive and byte_rep == '\x06': return True elif not interactive and byte_rep == '\x13': return True else: return False def send_data(self, data): """Send a data to the calc""" file3=open('sums-sent.hex','w') self.send_header(data) response = self.get_byte() if response == '\x06': # Calculator accepted the header pass elif response == '\x24': raise errors.DataNoManaged() elif response == '\x2b': raise errors.ChecksumError() elif response == '\x21': #File already exist in the calculator. if self.overwrite(data.name) : self.send_byte('\x06') sec_resp = self.get_byte() if sec_resp != '\x06': raise errors.CannotOverwrite(data.name) # Calculator accept to overwrite. else: # send abort code self.send_byte('\x15') sec_resp = self.get_byte() if sec_resp != '\x06': raise errors.BadAnswerFromCalc(sec_resp) raise errors.TransferAborted() elif response == '\x51': raise errors.HeaderError() else: raise errors.BadAnswerFromCalc(response) # Make the data list to be transfered if data.__class__ == datacls.Picture: raw_data_list = [data.raw_data[0:1028], data.raw_data[1028:2056], data.raw_data[2056:3084], data.raw_data[3084:4112]] elif data.__class__ == datacls.Matrix: raw_data_list = data.get_raw_data_list()[:-1] else: raw_data_list = [data.raw_data] for raw_data in raw_data_list: # CRC calculation crc = 0 for byte in raw_data: crc += ord(byte) crc = abs(255 - (crc % 256)) + 1 #crc = (abs(255 - (crc % 256)) + 1) % 256 #crc = abs(255 - (crc % 256)) + 1 # Now sending the data self.send_string('\x3a' + raw_data, self.status, data.name, False) # All data sent, let the calc check the CRC file3.write(chr(crc)+'\xff') self.send_byte(chr(crc)) response = self.get_byte() if response != '\x06': raise errors.ChecksumError() if data.__class__ == datacls.Matrix: self.send_string('\x3a'+data.get_raw_data_list()[-1]) file3.close() return def send_header(self, data): """Send the header corresponding to data""" header = cas.build_header(data) if data.__class__ == cas.End: self.send_string('\x3a' + header, self.status, 'End', False) else: self.send_string('\x3a' + header, self.status, data.name, True) return #Receive system def receive(self): """Return a file_data with all data received from the calc.""" file_data = datacls.FileData() while not self.calc_is_ready_to_send(): pass # Debut de la réception while True: data = self.receive_data() if data.__class__ == cas.End: break file_data.data.append(data) if data.__class__ == datacls.ScreenCapture or \ data.__class__ == datacls.Backup: break return file_data def calc_is_ready_to_send(self): """Waiting for receiving data""" byte = self.get_byte() if byte == '\x15': # Received request for interactive handshake (0x15) # -- responding with 0x13 self.send_byte("\x13") return True elif byte == '\x16': # Received request for noninteractive handshake (0x16) # -- responding with 0x13 self.send_byte("\x13") return True else: return False def receive_data(self): """Receive a data""" # Get header #file=open('/home/fabien_kubuntu/src/casetta/current-content.hex','w') #log=open('/home/fabien_kubuntu/src/casetta/current-trans.log','w') file2=open('/home/fabien_kubuntu/src/casetta/sums.hex','w') self.status('unknown', 0, 49, True) header, data_type, sub_type = self.get_header() self.status('unknown', 49, 49, True) if data_type == 'end': # End of the transfer : no data return cas.End() # Get data informations data_len = cas.get_data_len(header, data_type, sub_type) # Make the data if data_type == 'program': # Xion345 : It is possible to data = datacls.Program() # replace all this code by something elif data_type == 'backup': # smaller like : getattr('datacls.'\ data = datacls.Backup() # + data_type[0].upper() + data_type elif data_type == 'picture': # [1:]+'()') data = datacls.Picture() elif data_type == 'screencapture': data = datacls.ScreenCapture() elif data_type == 'var': data = datacls.Variable() elif data_type == 'matrix': data = datacls.Matrix() data.dimensions=(ord(header[7]),ord(header[9])) elif data_type == 'list': data = datacls.List() data.dimension=ord(header[7]) else: # unknown data, refuse header self.send_byte("\x00") raise errors.HeaderError() cas.fill_metadata(data, header) #if data_len == 0: # #datalen is 0 -- sending 0x00 # self.send_byte('\x00') # we accepted the header -- so we send 0x06 to the calc self.send_byte("\x06") if not self.get_byte() == '\x3a': raise errors.BadAnswerFromCalc() crc = 0 raw_data = '' for index in range(data_len): # byte = self.get_byte() #file.write(byte) crc = crc + ord(byte) if (data_type == 'list' or data_type == 'matrix') and (index-13)%14==0:# and index >=12: # Checksum test calc_crc=self.get_byte() file2.write(calc_crc+'\xff') #log.write(str(abs(255 - (crc % 256)) + 1)+'/'+str(ord(calc_crc))) if abs(255 - (crc % 256)) + 1 == ord(calc_crc) or index >= data_len-50: self.send_byte('\x06') crc=0 if index<=data_len-50: resp=self.get_byte() if resp != '\x3a': raise errors.BadAnswerFromCalc(resp) else: raise errors.ChecksumError() # if data_type == 'screencapture' and sub_type == 'color' \ and (index == 1024 or index == 2048): resp2 = self.get_byte() self.send_byte('\x06') resp2 = self.get_byte() crc = 0 if data_type == 'picture' and (index + 1) % 1028 == 0 \ and index != 0 and index + 1 < data_len: # IMAGE / color screencapture newcrc = ord(self.get_byte()) crc = abs(255 - (crc % 256)) + 1 if not newcrc == crc : raise errors.ChecksumError() crc = 0 self.send_byte('\x06') resp2 = self.get_byte() if not resp2 == '\x3a': raise errors.BadAnswerFromCalc(resp2) #if data_type == 1 and bytesproc + 1 == 62684: # print 'byte 62684 of a backup : send 0x06' # send_byte('\x06') raw_data += byte #bytectrl += 1 self.status(data.name, index, data_len - 1, False) newcrc = ord(self.get_byte()) crc = abs(255 - (crc % 256)) + 1 if "VAL\x00VM" in raw_data: # This works around a bug while receiving #print "End of var trans." #for i in range(49): # self.get_byte() return cas.End() # Many variables from the calc. # It sends two variables which have no values #if newcrc != crc and (data_type != 'screencapture' and \ #sub_type != 'color'): # Warning: the crc check is not done for color screencapture # because the crc of color screencapture is never # valid. # raise errors.ChecksumError() self.send_byte('\x06') #if data_type == 8 and data_sub_type == 13: # print "coincoin (cf.perl)" if data_type == 'screencapture' and sub_type == 'color': data.raw_data = cas.color_screencapture_to_raw(raw_data) elif data_type == 'screencapture' and sub_type == 'mono': data.raw_data = cas.mono_screencapture_to_raw(raw_data) else: data.raw_data = raw_data file2.close() #log.close() return data def get_header(self): """Return [header, header_type]""" file2=open('/home/fabien_kubuntu/src/casetta/current-header.hex','w') byte = self.get_byte() if not byte == '\x3a': raise errors.HeaderError() header = '' total_bytes = 100 cur_byte = 0 h_crc = 0 while cur_byte < total_bytes: byte = self.get_byte() header += byte if cur_byte == 7: header_len, header_type, sub_type = \ cas.get_header_format(header) total_bytes = header_len cur_byte += 1 if cur_byte < total_bytes: h_crc = (h_crc + ord(byte)) % 256 h_crc = (0 - h_crc) % 256 file2.write(header) file2.close() if h_crc != ord(byte) : raise errors.ChecksumError() return [header, header_type, sub_type]
# -*- coding: utf-8 -*- # ############################################################################ # # (c) 2007 Florian Birée aka Thesa <florian.biree@xxxxxxxxxxx> # # Website: <URL:http://casetta.tuxfamily.org> # # Version 0.3.0dev # # changelog: # # # 0.3.0 version: # # o First release # This code is hardly inspired by cafix softwares (cafix.sourceforge.com) # A lot of thanks for cafix coders. # ############################################################################ # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301, USA. # # http://www.gnu.org/copyleft/gpl.html # ############################################################################ """cas (CASIOLINK format) management module""" __author__ = "Florian Birée" __version__ = "0.3.0dev" __copyright__ = "Copyright (c) 2007, Florian Birée" __license__ = "GPL" __revision__ = "$Revision: $" # $Source: $ __date__ = "$Date: $" import datetime import errors import data as datacls # Constant PICTURE_PALLET = ['o', 'b', 'g', 'w'] SCREEN_PALLET = ['b', 'g', 'w', 'o'] # Special Data class class End(datacls.Data): """Special data to end a transfer.""" def __init__(self): """New end data""" datacls.Data.__init__(self) self.dType = 'end' # Cas format functions def build_header(data): """Return a cas header built from data""" if data.__class__ == End: header = 'END' + '\xff' * 45 else: #header_len = 49 data_len = len(data.raw_data) + 2 #header = '\xff' * header_len if data.__class__ == datacls.Program: header = 'TXT\x00PG' header += chr(data_len / (256 ** 3)) header += chr((data_len % 256 ** 3) / (256 ** 2)) header += chr((data_len % 256 ** 2) / 256) header += chr(data_len % 256) # 0 -> 9 header += data.name[:8] + '\xff' * (8 - len(data.name[:8])) #10->17 header += '\xff' * 8 header += data.password[:8] + '\xff' * (8 - len(data.password[:8])) if data.use_base: header += 'BN' else: header += 'NL' header += '\xff' * 12 elif data.__class__ == datacls.Backup: header = data.raw_data[2048: 2048 + 48] header = header[:33] + '\x00\x10\x00\x00\x00\x00' + header[39:] #elif data.dType == 'variable' and False: # TO BE CHECKED #header += 'VAL\x00' #for (my $a = 0; $a < length($self->{dataname}); $a++) { # last if ($a > 8); # my $bar = sprintf "0x%lx", # ord(substr($self->{dataname}, $a, 1)); # $foo[10+$a] = $bar; #} #$foo[18] = "0x56"; # V #$foo[19] = "0x61"; # a #$foo[20] = "0x72"; # r #$foo[21] = "0x69"; # i #$foo[22] = "0x61"; # a #$foo[23] = "0x62"; # b #$foo[24] = "0x6c"; # l #$foo[25] = "0x65"; # e #$foo[26] = "0x52"; # R #$foo[27] = "0x0a"; # LF #if ($self->{subtype} == 13) { # $foo[4] = "0x56"; # V # $foo[5] = "0x4d"; # M # $foo[6] = "0x00"; # NUL # $foo[7] = "0x01"; # SOH # $foo[8] = "0x00"; # NUL # $foo[9] = "0x01"; # SOH #} elif data.__class__== datacls.Matrix: header = 'VAL'+'\x00'+'MT'+'\x00'+chr(data.dimensions[0]) header += '\x00'+chr(data.dimensions[1])+data.name header += '\xff'*11 + '\x52'+'\x0a' header += '\xff'*20 elif data.__class__ == datacls.Picture: header = 'IMG\x00PC' header += '\x00\x40\x00\x80' # len ? header += data.name header += '\xff' * 8 header += 'DRUWF' header += '\x00\x04\x00\x01' # len ? header += '\xff' * 13 else: raise errors.DataNoManaged([data.dType]) # h_crc (header checksum) calcul h_crc = 0 for byte in header: h_crc = (h_crc + ord(byte)) % 256 h_crc = (0 - h_crc) % 256 header += chr(h_crc) return header def get_header_format(header): """Return [header_len, header_type, sub_type].""" sub_type = None type_id = header[0:3] sub_id = header[4:6] if type_id == "MEM" and sub_id == "BU": header_type = 'backup' headerlen = 49 elif type_id == "DD@": header_type = 'screencapture' headerlen = 39 sub_type = 'mono' elif type_id == "DC@": header_type = 'screencapture' headerlen = 39 sub_type = 'color' # elif type_id == "FNC": # datatype = 4 # headerlen = 49 elif type_id == "IMG" and sub_id == "PC": header_type = 'picture' headerlen = 49 elif type_id == "TXT" and sub_id == "PG": header_type = 'program' headerlen = 49 elif type_id == "VAL" and sub_id == "MT": # Matrix header_type = 'matrix' headerlen = 49 elif type_id == "VAL" and sub_id == "VM": # Simple variable like A,B,...,Z header_type = 'var' # For cafix : format=8 headerlen = 49 # datatype=13 size=14 elif type_id == "VAL" and sub_id == "LT": header_type = 'list' headerlen = 49 # elif type_id == "VAL": # datatype = 8 # headerlen = 49 # elif type_id == "REQ": # datatype = 7 # headerlen = 49 elif type_id == "END": header_type = 'end' headerlen = 49 else: header_type = 'unknown' headerlen = 49 return [headerlen, header_type, sub_type] def get_data_len(header, data_type, sub_type): """Return data len from the header""" std_len = ord(header[6]) * (256 ** 3) + ord(header[7]) * (256 ** 2) + \ ord(header[8]) * 256 + ord(header[9]) - 2 if data_type == 'program': data_len = std_len elif data_type == 'backup': # bck data_len = std_len elif data_type == 'end': data_len = 0 # elif data_type == 'val' : # data_len = stdlen # if data_sub_type == 13: # data_len = 14 # elif data_sub_type == 6: # data_len = 2 * (ord(header[8]) + ord(header[9])) - 2 elif data_type == 'program': data_len = std_len elif data_type == 'matrix': # A matrix is a table with 2 dimensions # header[7] is the first dimension # header[9] is the second dimension # 16 bytes per value transfered # 49 byte for a sort of footer data_len=14*ord(header[7])*ord(header[9])+47 elif data_type == 'list': # A list is a table with 1 dimension # header[7] is the first dimension # 16 bytes per value transfered # 49 byte for a sort of footer (so it is very similar to matrixes) data_len = 14*ord(header[7])+47 elif data_type == 'var': data_len = 14 elif data_type == 'screencapture' and sub_type == 'color': #screencapture color data_len = 3075 elif data_type == 'screencapture' and sub_type == 'mono': #screencapture mono data_len = 1024 elif data_type == 'picture': #image data_len = 4112 else: data_len = std_len return data_len def fill_metadata(data, header, add_date = True): """Fill a data object with metadata from header""" ### All data ### # Name: # lazy code : what append if \xff are followed by non ff characters ? data.name = header[10:18].replace('\xff', '') # Date: if add_date: data.date = datetime.date.today() ### Programs ### if data.__class__ == datacls.Program: # Password: data.password = header[26:34].replace('\xff', '') # Base: if header[34:36] == 'BN': data.use_base = True else: data.use_base = False ### Pictures ### elif data.__class__ == datacls.Picture: data.pallet = PICTURE_PALLET data.color_byte = 3 elif data.__class__ == datacls.ScreenCapture: data.pallet = SCREEN_PALLET data.color_byte = 0 def color_screencapture_to_raw(screen_capture): """Return picture raw data from raw color screen capture.""" return screen_capture[:0x400 * 2 + 2] +\ '\x03' + '\x00' * 0x400 +\ screen_capture[0x400 * 2 + 2:] def mono_screencapture_to_raw(screen_capture): """Return picture raw data from raw mono screen capture.""" # Convert screencapture (invert up and down) columns = [''] * 16 for index in range(len(screen_capture)): col = index / 64 columns[col] += screen_capture[index] for col in range(len(columns)): byte_list = list(columns[col]) byte_list.reverse() columns[col] = ''.join(byte_list) black_sheet = ''.join(columns) return '\x01' + black_sheet +\ '\x02' + '\x00' * 0x400 +\ '\x03' + '\x00' * 0x400 +\ '\x04' + '\x00' * 0x400 # File format management classes class CasFile: """Cas (Casiolink) file format manager.""" name = 'cas' managed_data = [datacls.Program, datacls.Backup, datacls.Picture, \ datacls.ScreenCapture] read = True write = False list_ext = ['cas'] def __init__(self, filename = None): """Make a cas file object with filename""" self.filename = filename def open_file(self): """Open a file in the cas Format""" # Build the FileData file_data = datacls.FileData() cas_file = open(self.filename, 'r') ctn = cas_file.read() cas_file.close() # Init var index = 0 is_header = True header = "" header_len = 100 data = None data_len = 100 raw_data = "" # Loop on bytes in ctn while index < len(ctn): if is_header and ctn[index] != ':' and len(header) < header_len: header += ctn[index] if len(header) == 7: # Get metadata header_len, data_type, sub_type = \ get_header_format(header) elif is_header and len(header) == header_len: # Crc byte, init the data record is_header = False if data_type == 'end': break data_len = get_data_len(header, data_type, sub_type) # Make the data if data_type == 'program': data = file_data.new_record(datacls.Program) elif data_type == 'backup': data = file_data.new_record(datacls.Backup) elif data_type == 'picture': data = file_data.new_record(datacls.Picture) elif data_type == 'ScreenCapture': data = file_data.new_record(datacls.ScreenCapture) else: data = file_data.new_record(datacls.Data) fill_metadata(data, header, False) elif not is_header and len(raw_data) == 0 and ctn[index] == ':': # Not header, first : pass elif not is_header and len(raw_data) < data_len: # Raw_data if data_type == 'screencapture' and sub_type == 'color' \ and (len(raw_data) == 1024 or len(raw_data) == 2048): # Jump two bytes (checksum and :) index += 2 if data_type == 'picture' and (len(raw_data) + 1) % 1028 == 0 \ and len(raw_data) != 0 and len(raw_data) + 1 < data_len: # Jump two bytes (checksum and :) index += 2 raw_data += ctn[index] elif not is_header and len(raw_data) == data_len: # Data Crc, save raw_data (and make some convertions) if data_type == 'screencapture' and sub_type == 'color': data.raw_data = color_screencapture_to_raw(raw_data) elif data_type == 'screencapture' and sub_type == 'mono': data.raw_data = mono_screencapture_to_raw(raw_data) else: data.raw_data = raw_data # Init vars is_header = True header = "" header_len = 100 data = None raw_data = "" index += 1 return file_data
# -*- coding: utf-8 -*- # ############################################################################ # # (c) 2006-2007 Florian Birée aka Thesa <florian.biree@xxxxxxxxxxx> # (c) 2006 Achraf Cherti aka Asher256 <achrafcherti@xxxxxxxxx> # # Website: <URL:http://casetta.tuxfamily.org> # # Version 0.3.0dev # # changelog: # # # 0.3.0 version: # # o First release (code from __init__.py) # o Add picture-specific data properties # o Add new classes for each data type # o Change methods in FileData to have a better behaviour # ############################################################################ # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301, USA. # # http://www.gnu.org/copyleft/gpl.html # ############################################################################ """Data management classes for casetta""" __author__ = "Florian Birée, Achraf Cherti" __version__ = "0.3.0dev" __copyright__ = "Copyright (c) 2006-2007, Florian Birée, Achraf Cherti" __license__ = "GPL" __revision__ = "$Revision: $" # $Source: $ __date__ = "$Date: $" import re from math import log10 import catdic import pictures import backups import errors class Data: """Data manipulation class""" name_rule = r'^.' def __init__(self, name = '', raw_data = '', data_type = 'unknown', \ date = None): """Make an empty data""" self.name = name self.raw_data = raw_data self.dType = data_type self.date = date def __repr__(self): """Descript this data""" return "<Data '%s', type: '%s'>" % (self.name, self.dType) def copy(self): """Creat a new Data object from this object.""" return Data(self.name, self.raw_data, self.dType, self.date) def get_name(self): """Return the name in an human readable format""" return catdic.text_encode(self.name, True) def set_name(self, new_name): """Set the name from a newcat-like string.""" self.name = catdic.text_decode(new_name, True) ### Management of various types of variables ### ### IMPORTANT ### # Casio variables (I mean simple variables like A,B...Z, matrix and lists) # are stored in a similar way. def get_simple_val(raw_line): """Returns the value of the variable in *decimal* format""" val='' # raw_line[4:10] is where figures are stored for i in raw_line[4:10]: if ord(i) >= 10: val += hex(ord(i)).replace('0x','') else: val += '0'+hex(ord(i)).replace('0x','') val=val[0]+'.'+val[1:] # raw_line[12]=special code // raw_line[13]=power # raw_line[12]==\x01 -> positive number + positive power # raw_line[12]==\x00 -> positive number + negative power # raw_line[12]==\x51 -> negative number + positive power # raw_line[12]==\x50 -> negative number + negative power if raw_line[12]=='\x01' or raw_line[12]=='\x51': #Then value > 0 data[13] is positive power power= int(hex(ord(raw_line[13])).replace('0x',''))+1 else: # Then value < 0 data[13] is a negative power power=-100+int(hex(ord(raw_line[13])).replace('0x',''))+1 if raw_line[12]=='\x50' or raw_line[12]=='\x51': # Then we have a negative number return float(val)*(10**power)*-1 else: # Then we have a positive number return float(val)*(10**power) def set_simple_val(nbre): if abs(nbre) >= 9.99999999*(10**99) or abs(nbre) <= 9.99999999*(10**-99) and nbre != 0: return "Absolute value of number is too high/low and not supported by the calculator" elif nbre==0: return '\x00\x01\x00\x01'+'\x00'*8+'\x01'+'\x00' raw_line = '' string_num=str(nbre) if 'e' in string_num: string_num=string_num.split('e')[0] string_num=string_num.replace('-','').replace('.','') string_num=re.sub('^0*','',string_num) #print '*'+string_num+'*' # Numbers are stored this way : # [0|0] [0|1] [0|0] [0|1] [0|1stfig] [2ndFig|3rdFig] [4thFig|5thFig] # [6thFig|7thFig] [8thFig|9thFig] [10thFig|0] [0|0] [0|0] [special code] # [power] # Each [x|x] is one byte # Each xxFig is one figure of the number you entered # So you can see that except for 5th and the 10th byte, # 2 Fig are are stored in each byte # Stores the first figure in the first byte raw_line += chr(int(string_num[0],16)) i=1 # Stores figures 2-8 in the corresponding bytes # or \x00 if figures are not present while i <= 7: #print "--" len(string_num) if (i+2) <= len(string_num): sli = string_num[i:i+2] #print sli raw_line += chr(int(sli,16)) elif i == len(string_num)-1: sli = string_num[i] #print sli raw_line += chr(int(sli+'0',16)) else: raw_line += '\x00' i +=2 # Stores the last figure or \x00 if len(string_num)>=10: raw_line += chr(int(string_num[9]+'0',16)) else: raw_line += '\x00' raw_line=raw_line+'\x00\x00' if abs(nbre)>=1 or string_num=='1': power=int(log10(abs(nbre))) else: power=int(log10(abs(nbre)))-1 # print power # Sets the correct code and power # See get_val for more info. if nbre >= 0 and power >=0 : raw_line += '\x01'+ chr(int(str(power),16)) elif nbre >= 0 and power < 0: raw_line += '\x00'+ chr(int(str(100+power),16)) elif nbre < 0 and power >=0: raw_line += '\x51'+ chr(int(str(power),16)) elif nbre < 0 and power <=0: raw_line += '\x50'+ chr(int(str(100+power),16)) return raw_line class Variable(Data): """Class for a casio simple var like A,B...Z""" name_rule = r'^[A-Z]$' def __init__(self, name='', raw_data='', date=None): """Makes an empty variable""" Data.__init__(self, name, raw_data, 'variable', date) def get_val(self): """ Returns the value of raw_data under the form of a *decimal* floatting point number""" return get_simple_val(self.raw_data) def set_val(self, number): """Takes a decimal integer or floatting point number and puts its value in raw_data""" self.raw_data='\x00\x01\x00\x01'+set_simple_var(number) class Matrix(Data): """Class for a casio matrix""" name_rule = r'^Mat [A-Z]$' def __init__(self, name='', raw_data='', date = None, dimensions=(1,1) ): """Makes an empty matrix""" Data.__init__(self, name, raw_data, 'matrix', date) self.dimensions=dimensions def get_raw_data_list(self): raw_data_list=[] #loh.write(self.raw_data) for i in range(abs(len(self.raw_data[:-47])/14)): raw_data_list.append(self.raw_data[i*14:(i+1)*14]) raw_data_list.append(self.raw_data[-47:]) return raw_data_list def get_val(self): current_line=0 raw_data_list=self.get_raw_data_list()[:-1] data_list=[[]] for i in raw_data_list: value=get_simple_val(i) if ord(i[1]) == (current_line + 2): data_list.append([]) current_line += 1 data_list[current_line].append(value) return data_list def set_val(self, py_list): self.raw_data='' for line in py_list: ## FIXME Test here if line is a list otherwise raise error ## FIXME Test here if all lines have same length otherwise raise error crc = 0 #log.write(str(line)) for i in line: #log.write(str(i)) ## FIXME Test here if i is an integer otherwise raise error # Calculation of the coords coord1=py_list.index(line)+1 coord2=py_list[coord1-1].index(i)+1 # Number in raw format raw_nbre='\x00'+chr(coord1)+'\x00'+chr(coord2)+set_simple_val(i) # Checksum calculation -> moved to transfert tool ## #log.write(raw_nbre+'\xff') #crc = 0 #for i in raw_nbre: # crc += ord(i) #crc = abs(255 - (crc % 256)) + 1 # Add raw_number (number + coords) self.raw_data += (raw_nbre) #log.write(raw_nbre+'\xff') ### Add footer ### FIXME : Add this in the transfer tool part ? self.raw_data += 'END'+'\xff'*43+'V' #log.write(self.raw_data) #log.close() class List(Data): """Class for a casio list""" name_rule = r'^List [1-6]$' def __init__(self, name='', raw_data='', date = None, dimension=1 ): """Makes an empty list""" Data.__init__(self, name, raw_data, 'list', date) self.dimension=dimension def get_raw_data_list(self): raw_data_list=[] for i in range(abs(len(self.raw_data[:-47])/14)): raw_data_list.append(self.raw_data[i*14:(i+1)*14]) raw_data_list.append(self.raw_data[-47:]) return raw_data_list def get_val(self): raw_data_list=self.get_raw_data_list()[:-1] data_list=[] for i in raw_data_list: value=get_simple_val(i) data_list.append(value) return data_list ################################### class Program(Data): """Class for a casio program""" name_rule = r'^.{1,8}$' def __init__(self, name = '', raw_data = '', date = None, password = "", \ use_base = False): """Make an empty program""" Data.__init__(self, name, raw_data, 'program', date) # Program specific properties self.password = password self.use_base = use_base def copy(self): """Creat a new Program object from this object.""" return Program(self.name, self.raw_data, self.date, \ self.password, self.use_base) def get_text(self): """Return the program in an human readable format""" return catdic.text_encode(self.raw_data) def set_text(self, text): """Set the program from a newcat-like string""" self.raw_data = catdic.text_decode(text) def get_password(self): """Return the password in an human readable format""" return catdic.text_encode(self.password, True) def set_password(self, new_password): """Set the password from a newcat-like string.""" self.password = catdic.text_decode(new_password, True) class Backup(Data): """Class for a casio backup""" name_rule = r'^.' def __init__(self, name = '', raw_data = '', date = None): """Make an empty backup""" Data.__init__(self, name, raw_data, 'backup', date) def find_password(self, program_name): """Return a list of possible passwords for a program_name""" return backups.find_password(self.raw_data, program_name) def find_program_names(self): """Find the program list from the backup Return a list of list like ['Program Name', 'offset']. """ return backups.find_prgm_names(self.raw_data) def find_program_data(self, offset): """Return raw data of program from its offset""" return backups.find_prgm_data(offset, self.raw_data) def copy(self): """Creat a new Backup object from this object.""" return Backup(self.name, self.raw_data, self.date) class Picture(Data): """Class for a casio picture""" name_rule = r'^Picture[1-6]$' def __init__(self, name = '', raw_data = '', date = None, pallet = None, \ color_byte = None): """Make an empty picture""" Data.__init__(self, name, raw_data, 'picture', date) # self.pallet must be a list of characters as ['o','g','b','w'] self.pallet = pallet self.color_byte = color_byte def copy(self): """Creat a new Picture object from this object.""" return Picture(self.name, self.raw_data, self.date, self.pallet, \ self.color_byte) def get_picture(self): """Return a list of pixels from the picture""" return pictures.raw_to_data(self.raw_data, \ self.color_byte, \ self.pallet) def set_picture(self, pixels_list): """Set the picture from a list of pixels""" self.raw_data = pictures.data_to_raw(pixels_list, \ wanted_pallet = self.pallet) def change_pallet(self, new_pallet, headers = None): """Convert the picture from the current pallet to new_pallet. You can add a header using headers (like pictures.sheets_to_raw). """ self.raw_data = pictures.sheets_to_raw(\ pictures.change_sheets_pallet(\ pictures.raw_to_sheets( \ self.raw_data, \ self.color_byte, \ len(self.pallet)), \ self.pallet, new_pallet), \ headers) self.pallet = new_pallet if headers != None: # Change the color_byte self.color_byte = len(headers[0]) def get_program(self): """Return a program in newcat-like format to draw the picture.""" return pictures.img_to_basic(self.get_picture) class ScreenCapture(Picture): """Class for a screen capture""" name_rule = r'^.' def __init__(self, name = '', raw_data = '', date = None, pallet = None, \ color_byte = None): """Make an empty screen capture""" Picture.__init__(self, name, raw_data, date, pallet, color_byte) self.dType = 'screencapture' def copy(self): """Creat a new ScreenCapture object from this object.""" return ScreenCapture(self.name, self.raw_data, self.date, self.pallet, \ self.color_byte) class FileData: """Data file manipulation class""" def __init__(self, filename = None, format = None): """Make a FileData. If filename is filled, the file given is opened. If format is None, the format is autodetected.""" self.data = [] self.export = [] if filename != None: self.import_file(filename, format) def __repr__(self): """Descript this data""" out = "<File of %s casio data:\n" % str(len(self.data)) for data_index in range(len(self.data)) : out += "#%s: %s\n" % (str(data_index), \ self.data[data_index].__repr__()) out += '>' return out def __getitem__(self, index): """The same of self.data[index]""" return self.data[index] def export_list(self): """Return the list of data to be exported.""" out_list = [] for index in self.export: out_list.append(self.data[index]) return out_list def remove(self, data): """Remove the data record.""" self.data.remove(data) # clear the export list because index list has changed self.export = [] def new_record(self, data_class, arg_list = [], arg_dic = {}): """Make a new data from the data_class (Program, Backup, etc) The new data object is append to the file data, and the the data object is returned. arg_list and arg_dic can be used to give arguments in the class initialization. The name of the returned data should be checked. """ new_data = data_class(*arg_list, **arg_dic) self.data.append(new_data) return new_data def save(self, filename, format=None, ignore_warnings=False, \ export=False): """Save in (a) file(s) the data. If all data aren't managed by this format, raise DataNoManaged with the list of data type not managed (['all'] for all ;-) ) Use ignore_warnings = True to save managed data in this format. """ if format == None: from formats import choose_format format = choose_format(filename) if not format.write: raise errors.FormatCantSave(format) if not ignore_warnings : no_managed_data = self.check_no_managed_data(format, export) if no_managed_data != []: raise errors.DataNoManaged(no_managed_data) afile = format(filename) if export: afile.save(self.export_list()) else: afile.save(self.data) def add_records(self, file_data): """Add records from another file_data. Return the list of new records. The name of returned data should be checked. """ self.data += file_data.data return file_data.data def import_file(self, filename, format = None): """Import all records from filename. Return the list of new records. The name of returned data should be checked. """ if format == None: from formats import choose_format format = choose_format(filename) if not format.read: raise errors.FormatCantOpen(format) imported_file = format(filename).open_file() return self.add_records(imported_file) def list_data_types(self, export=False): """Return the list of data types used""" ret = [] if export: data_list = self.export_list() else : data_list = self.data for data in data_list: if not data.__class__ in ret: ret.append(data.__class__) return ret def check_name(self, checked_data): """Return 1 if the name of this data is correct Return 0 if the name syntax is bad Return -1 if the name is already used""" # check the syntax of the name if re.search(checked_data.name_rule, checked_data.name) == None: return 0 # check if already employed for data in self.data: if data is not checked_data and \ data.__class__ == checked_data.__class__ and \ data.name == checked_data.name: return -1 return 1 def copy_record(self, data): """Copy data. Return the copy. The name of the returned data must be changed. """ copy = data.copy() self.data.append(copy) return copy def split_by_data_type(self): """Split this file_data by data type. Return a dictionary of file data with data classes as keys. """ ret = {} for data in self.data: if not data.__class__ in ret.keys(): ret[data.__class__] = FileData() ret[data.__class__].data += data.copy() return ret def check_no_managed_data(self, format, export = False): """ Return the list of data classes no managed in format. Return [] if all data type are managed, ['all'] if nothing is managed """ ret = [] for data_class in self.list_data_types(export) : if not data_class in format.managed_data: ret.append(data_class) ret.sort() fd_list = self.list_data_types() fd_list.sort() if fd_list == ret : ret = ['all'] return ret def send(self, tool, export = False): """Send data using tool.""" if export: tool.send(self.export_list()) else: tool.send(self.data) # Deprecated methods (here for compatibility reason): def del_data(self, delete_index): """Del the data with the index i Deprecated: please use remove instead """ del(self.data[delete_index]) # clear the export list because index list has changed self.export = [] def add_data(self, file_data): """Add data from another file_data Return the list of new index (You should check the name of those datas) Deprecated: please use add_records instead """ length = len(self.data) self.data += file_data.data return range(length, len(self.data)) # def add(self, filename, format = 'unknown'): # """Open datas from filename and add them in the file . # Return the list of new index # (You should check the name of those datas) # # Deprecated: please use import instead # """ # if format == 'unknown' : # format = formats.choose_format(filename) # if format == 'unknown': # raise errors.FormatNotFound # return self.add_data(formats.openFunc[format](filename)) def copy_data(self, data_index): """Copy data from dataIndex. Return the new index (You should check the name of the copy) Deprecated: use copy_record instead """ new_index = self.new_data() self.data[new_index].name = self.data[data_index].name self.data[new_index].raw_data = self.data[data_index].raw_data self.data[new_index].dType = self.data[data_index].dType self.data[new_index].date = self.data[data_index].date self.data[new_index].password = self.data[data_index].password return new_index def new_data(self): """Make a new empty data, and return it index. Deprecated, use new_record instead """ self.data.append(Data()) return len(self.data) - 1 # Static data: data_type_list = [Data, Program, Backup, Picture, ScreenCapture] data_type_dic = {'unknown' : Data, 'program' : Program, 'backup' : Backup, 'picture' : Picture, 'screencapture' : ScreenCapture}
#!/usr/bin/env python # -*- coding: utf-8 -*- import os import casetta connect=casetta.devices_serial.Connexion() touche=0 while touche != 47: while not connect.calc_is_ready_to_send(): pass #num2=hex(ord(data[5])).replace('0x','') #num1=hex(ord(data[4])).replace('0x','') #touche=int(num1)*10+int(num2)/10 var=connect.receive_data() touche=int(var.get_val()) print touche if touche==79: os.popen('xmms --play-pause') elif touche==69: os.popen('xmms --stop') elif touche==28: os.popen('dcop kmix Mixer0 increaseVolume 0') elif touche==37: os.popen('dcop kmix Mixer0 decreaseVolume 0') elif touche==38: os.popen('xmms --rew') elif touche==27: os.popen('xmms --fwd') elif touche==68: os.popen('xmms --toggle-repeat')
%Header Record Format:TXT Data Type:PG File Name:XMMSCTRL Date:20070420 %Data Record \While 1 0\->\theta \While \theta=0 \Getkey\->\theta \WhileEnd \Send(\theta) \If \theta=79 \Then "Play-Pause" \IfEnd \If \theta=69 \Then "Stop" \IfEnd \If \theta=28 \Then "Vol +" \IfEnd \If \theta=37 \Then "Vol -" \IfEnd \If \theta=38 \Then "Rew" \IfEnd \If \theta=27 \Then "Fwd" \IfEnd \If \theta=68 \Then "Toggle Repeat" \IfEnd \WhileEnd %End
Mail converted by MHonArc 2.6.19+ | http://listengine.tuxfamily.org/ |