[casetta] Files... for previous mail |
[ Thread Index | Date Index | More lists.tuxfamily.org/casetta Archives ]
--
Fabien ANDRE aka Xion345 Linux User #418689 -- fabien.andre.g@xxxxxxxxxx -- xion345@xxxxxxxxxxxxx ...Unix, MS-DOS, and Windows NT (also known as the Good, the Bad, and the Ugly). ( Matt Welsh, Not dated ) |
# -*- coding: utf-8 -*- # ############################################################################ # # (c) 2007 Xion345 aka Fabien ANDRE <fabien.andre.g@xxxxxxxxxx> # (c) 2006-2007 Thesa aka Florian Birée <florian.biree@xxxxxxxxxxx> # # Website: <URL:http://casetta.tuxfamily.org> # # Version 0.3.0dev # # changelog: # # # 0.3.0 version: # # o First release (extract password function is from casetta_gtk code) # o Add the DOTALL flag in regular expressions # o Remove the find_password function (replaced by the improved # find_prgm_metadata function) # ############################################################################ # # 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 # ############################################################################ """Pictures manager for casetta""" __author__ = "Fabien ANDRE, Florian Birée" __version__ = "0.3.0dev" __copyright__ = "Copyright (c) 2006-2007, Fabien ANDRE, Florian Birée" __license__ = "GPL" __revision__ = "$Revision: $" # $Source: $ __date__ = "$Date: $" import re def find_prgm_list(rawback): """Return a list like [(name1, use_base1, offset1, password1),... ] Where name1 is the raw name of the first program ; use_base1 is True if the program use base calculation, False else ; offset1 is the offset of the first program (for find_prgm_data function) ; password1 is the raw password of the first program. """ names_pattern = re.compile( """ [\x00\xee] # first character (0x00 except if the last prgm have a # password. In this case, 0xee) ([a-zA-Z0-9\x99\xa9\xb9 \xcd\xce\x89\x20'"~.{}\[\]] # A program name begins by a charater [a-zA-Z0-9 \x99\xa9\xb9\xcd\xce\x89\x20'"~.{}\[\]\xff] {7}) # End of program name: 7 of the above charaters or 0xff .{2} # 2 charaters [\x00]{2} # 2 0x00 characters ([\x00\x01]) # 0x01 if using base calculation, 0x00 else (.{2}) # offset of the beginning of the prgm data # If a password is present: (?:[\x10] # A 0x10 character (ie a password) ([a-zA-Z0-9\x99\xa9\xb9\xcd\xce\x89\x20'"~.{}\[\]] # Password (same as name) [a-zA-Z0-9\x99\xa9\xb9\xcd\xce\x89\x20'"~.{}\[\]\xff]{7}) [\x00]{7} # 7 0x00 characters )? """, re.VERBOSE | re.DOTALL) names_list = names_pattern.findall(rawback) return [(i[0].replace('\xff',''), # Clean the name bool(ord(i[1])), # Boolean base attribut i[2], # offset i[3].replace('\xff', '') # Clean the password ) for i in names_list] def find_prgm_data(offset, rawback): """Return raw data of a program in a backup with its offset""" #hex1 = hex(ord(offset[1])) #hex2 = hex(ord(offset[0])) #ad2 = int(hex1 + hex2.replace('0x',''), 16) ad2 = ord(offset[1]) * 0x100 + ord(offset[0]) i = ad2 prgm_data = "" while i > 0: prgm_data += (rawback[i]) if rawback[i] == '\xff': break i -= 1 return prgm_data
# -*- 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: ## Xion345 : I think this can now be wiped/commented ;-) # 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.Variable: header = 'VAL'+'\x00'+'VM'+'\x00\x01\x00\x01' header += data.name header += '\xff'*7 + 'VariableR' + '\x0a' header += '\xff'*20 elif data.__class__ == datacls.ViewVariable: header = 'VAL'+'\x00'+'WD'+'\x00\x01\x00\x01' header += data.name header += '\xff'*(8-len(data.name)) header += 'V\x99Win'+str(data.belongs_to_file) header += '\xff'*2 + 'R\n' header += '\xff'*20 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.List: header = 'VAL'+'\x00'+'LT'+'\x00'+'\x01' header += '\x00'+chr(data.dimension)+data.name if data.belongs_to_file == None: header += '\xff'*10 else: header += '\xff'*2+'File '+str(data.belongs_to_file)+'\xff'*2 header += '\x52'+'\x0a'+'\xff'*20 elif data.__class__ == datacls.SimlEquationMatrix: header = 'VAL'+'\x00'+'SE'+'\x00'+chr(data.dimensions[0]) header += '\x00'+chr(data.dimensions[1]) header += data.name +'EquationR\n' + '\xff'*20 elif data.__class__ == datacls.PolyEquationMatrix: header = 'VAL'+'\x00'+'PE'+'\x00'+chr(data.dimensions[0]) header += '\x00'+chr(data.dimensions[1]) header += data.name +'EquationR\n' + '\xff'*20 elif data.__class__ == datacls.FMem: header = 'TXT' +'\x00'+'FM' header += '\x00'*3 + chr(data_len) header += data.name header += '\xff'*6+'F\x99Mem'+'\xff'*25 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.__class__]) # 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 == "WD": # Variable used to define a view-window header_type = 'viewvar' headerlen = 49 elif type_id == "VAL" and sub_id == "LT": # List header_type = 'list' headerlen = 49 elif type_id == "VAL" and sub_id == "SE": header_type = 'simlequation-matrix' headerlen = 49 elif type_id == "VAL" and sub_id == "PE": header_type = 'polyequation-matrix' headerlen = 49 elif type_id == "TXT" and sub_id == "FM": header_type = 'function-memory' headerlen = 49 elif type_id == "FNC" and sub_id == "GF": header_type = "graph-func" 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' or 'simlequation-matrix' or data_type == 'polyequation-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 # 14 bytes for the value itself # + 1 byte \x3a, transfer inititation # + 1 byte CRC data_len=14*ord(header[7])*ord(header[9]) 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]) elif data_type == 'var' or data_type == 'viewvar': data_len = 14 elif data_type == 'function-memory': data_len = ord(header[9])-2 elif data_type == "graph-func": data_len = ord(header[9])-2 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 ? # FIXME : Why not to use the name_rule ? 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 ### Matrices ### elif data.__class__ == datacls.Matrix or data.__class__ == datacls.SimlEquationMatrix or data.__class__ == datacls.PolyEquationMatrix : # Dimensions data.dimensions = (ord(header[7]),ord(header[9])) ### Lists ### elif data.__class__ == datacls.List: # Dimension data.dimension = ord(header[7]) # Belongs to a FileList ? if header[23] in [str(i+1) for i in range(6)]: data.belongs_to_file = int(header[23]) elif data.__class__ == datacls.ViewVariable: if header[23] in [str(i+1) for i in range(6)]: data.belongs_to_file = int(header[23]) elif data.__class__ == datacls.GraphFunc: # F-Type if header[10] != 'f': data.ftype = header[10] else: data.ftype = 'param' # Equal_type data.equal_type = header[17] # Color if header[29:31] == 'BL': data.color = 'blue' elif header[29:31] == 'OR': data.color = 'orange' elif header[29:31] == 'GN': data.color = 'green' # Selected ? if header[32:35] == 'SLD': data.selected = True ### Pictures ### elif data.__class__ == datacls.Picture: data.pallet = PICTURE_PALLET data.color_byte = 3 ### Screen capture ### elif data.__class__ == datacls.ScreenCapture: data.name = "Capture" 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 import catdic import pictures import backups import errors from math import log10 class Data: """Data manipulation class""" name_rule = r'^.' dType = 'unknown' 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) class Program(Data): """Class for a casio program""" name_rule = r'^.{1,8}$' dType = 'program' def __init__(self, name = '', raw_data = '', date = None, password = "", \ use_base = False): """Make an empty program""" Data.__init__(self, name, raw_data, self.dType, 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'^.' dType = 'backup' def __init__(self, name = '', raw_data = '', date = None): """Make an empty backup""" Data.__init__(self, name, raw_data, self.dType, 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_list(self): """Find the program list from the backup Return a list like [(name1, use_base1, offset1, password1),... ] Where name1 is the raw name of the first program ; use_base1 is True if the program use base calculation, False else ; offset1 is the offset of the location of the first program ; password1 is the raw password of the first program. """ return backups.find_prgm_list(self.raw_data) def get_program_by_name(self, program_name): """Return raw data of program from its offset""" # Get metadata list metadata_list = self.find_program_list() # Find metadata for program_name for (name, use_base, offset, password) in metadata_list: if name == program_name: return Program(name = name, raw_data = backups.find_prgm_data(offset, self.raw_data), use_base = use_base, password = password) def copy(self): """Creat a new Backup object from this object.""" return Backup(self.name, self.raw_data, self.date) ################# Management of various types of VARIABLES ################### # Casio variables (I mean simple variables like A,B...Z, matrix and lists) # are stored in a similar way. ### Low level functions ### 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] block 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: len(string_num) if (i+2) <= len(string_num): sli = string_num[i:i+2] raw_line += chr(int(sli,16)) elif i == len(string_num)-1: sli = string_num[i] 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 # 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 ### Variables and ViewVariables management ### class Variable(Data): """Class for a casio simple var like A,B...Z""" name_rule = r'^[A-Z]$' dType = 'variable' def __init__(self, name='', raw_data='', date=None): """Makes an empty variable""" Data.__init__(self, name, raw_data, self.dType, 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_val(number) class ViewVariable(Variable): """ Class for a variable used to define a view-window""" name_rule = r'^Xmin|Xmax|Xscl|Ymin|Ymax|Yscl|T\xcemin|T\xcemax|T\xceptch$' dType = 'view-variable' def __init__(self, name='', raw_data='', date=None, belongs_to_vwin = None ): """Makes an empty variable""" Data.__init__(self, name, raw_data, self.dType, date) self.belongs_to_vwin = belongs_to_vwin def copy(self): """ Create a new ViewVariable object from this object""" return ViewVariable(self.name, self.raw_data, self.date, self.belongs_to_vwin) ### Matrices and Lists ### class Matrix(Data): """Class for a casio matrix""" name_rule = r'^Mat [A-Z]$' dType = 'matrix' def __init__(self, name='', raw_data='', date = None, dimensions=(0,0)): """Makes an empty matrix""" Data.__init__(self, name, raw_data, self.dType, date) self.dimensions=dimensions def set_dimensions(self, dimensions): if dimensions[0] > 0 and dimensions[0] <= 255 and dimensions[1] > 0 and dimensions[1] <= 255: self.dimensions = dimensions else: raise errors.BadMatrix(dimensions, 'Bad dimensions, maximum size for matrices is 255x255') def copy(self): """ Create a new Matrix object from this object """ return Matrix(self.name, self.raw_data, self.date, self.dimensions) def get_raw_data_list(self): """ Returns a list of rawdata composed of each value of the matrix. Useful when sending a matrix (each value has to be transferred independently, and has its own checksum""" raw_data_list=[] for i in range(len(self.raw_data)/14): # Counts the number of variables inside the matrix # A variable is 14 octets long raw_data_list.append(self.raw_data[i*14:(i+1)*14]) # Add each variable to the list return raw_data_list def get_val(self): """ Returns values contained in the matrix in a human-readable format using a list of list""" current_line=0 raw_data_list=self.get_raw_data_list() 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): """ Sets the the matrix content. Takes a python list of list""" ## ***IMPORTANT*** : The checking and the actual remplacement of ## --------------- ## values are done into two different blocks to avoid ## the matrix to be partially modified, and not ## completely if an error appears. Therefore, if ## an error is raised during the checking, you can BE SURE ## the list was not modifed at all. ## Some tests to check the py_list givent is valid ## FIXME : Maybe there's a cleaner way to do that !!! for line in py_list: if type(line) == list: if len(line)==len(py_list[0]): for el in line: if type(el) != float and type(el)!=int: raise errors.BadMatrix( el, 'Matrices must' \ ' be composed of numbers only') else: raise errors.BadMatrix(line, 'Not all lines have same length') else: raise errors.BadMatrix(line, 'You must give a list of lists') self.raw_data='' self.set_dimensions((len(py_list), len(py_list[0]))) # Update dimensions before modifing/creatind values ## Actually sets the matrix content for num_line in range(len(py_list)): for index in range(len(py_list[num_line])): coord1=num_line+1 # Add 1 because numbering starts at 0 in python # compared to 1 on the calculator coord2=index+1 # Add raw_number (number + coords) self.raw_data += '\x00'+chr(coord1)+'\x00'+chr(coord2)+set_simple_val(py_list[num_line][index]) class List(Data): """Class for a casio list""" name_rule = r'^List [1-6]$' dType = 'list' def __init__(self, name='', raw_data='', date = None, dimension=0, belongs_to_file = None ): """Makes an empty list""" Data.__init__(self, name, raw_data, self.dType, date) self.dimension = dimension # This var is used to specify if the list belongs to a file self.belongs_to_file = belongs_to_file def set_dimension(self, dimension): if dimension >= 0 and dimension <= 255: self.dimension = dimension else: raise errors.BadList(dimensions, 'Bad dimensions, maximum size for lists is 255') def copy(self): """ Create a new List object from this object """ return List(self.name, self.raw_data, self.date, self.dimension, self.belongs_to_file) def get_raw_data_list(self): raw_data_list=[] for i in range(len(self.raw_data)/14): raw_data_list.append(self.raw_data[i*14:(i+1)*14]) return raw_data_list def get_val(self): raw_data_list=self.get_raw_data_list() data_list=[] for i in raw_data_list: value=get_simple_val(i) data_list.append(value) return data_list def set_val(self,py_list): ## ***IMPORTANT*** : The checking and the actual remplacement of ## --------------- ## values are done into two different blocks to avoid ## the list to be partially modified, and not ## completely if an error appears. Therefore, if ## an error is raised during the checking, you can BE SURE ## the list was not modifed at all. ## A test to check the list is valid for el in py_list: if type(el) != int and type(el) != float: raise errors.BadList(el, 'The list must be composed of numbers only') self.raw_data='' self.set_dimension=len(py_list) ## Actually sets the list content for index in range(len(py_list)): self.raw_data += '\x00'+chr(index+1)+'\x00\x01'+set_simple_val(py_list[index]) class SimlEquationMatrix(Matrix): name_rule = r'^Mat Siml$' dType = 'simlequation-matrix' def __init__(self, name='', raw_data='', date = None, dimensions=(2,3)): Data.__init__(self, name, raw_data, self.dType, date) self.dimensions = dimensions def set_dimensions(self,dimensions): if dimensions in [(int(i)+2,int(i)+3) for i in range(5)]: self.dimensions = dimensions else: raise errors.BadMatrix(dimensions, 'Bad dimensions') class PolyEquationMatrix(Matrix): name_rule = r'^Mat Poly$' dType = 'polyequation-matrix' def __init__(self, name='', raw_data='', date = None, dimensions=(1,3)): Data.__init__(self, name, raw_data, self.dType, date) self.dimensions = dimensions def set_dimensions(self,dimensions): if dimensions in [(1,3),(1,4)]: self.dimensions = dimensions else: raise errors.BadMatrix(dimensions, 'Bad dimensions') ############################################################################################ class FMem(Data): """Class for a casio F-Mem definition""" name_rule = r'^f[1-6]$' dType = 'function-memory' def __init__(self, name='', raw_data='', date=None): """ Makes an empty function memory""" Data.__init__(self, name, raw_data, self.dType, date) def get_text(self): """ Returns the content of the F-Mem in an human readable format""" return catdic.text_encode(self.raw_data) def set_text(self, text): """ Sets the content of the F-Mem from a newcat-like string""" self.raw_data = catdic.text_decode(text) class GraphFunc(Data): """ Class for a casio Graph. Function. Behaviour of this class is different according to the type of the function : Y,X,Param,r """ name_rule = r'^Y[1-20]|r[1-20]|f[1-20]|X[1-20]' dType = 'graph-function' func_types = ('Y','X','r','param') equal_types = ('=', '>', '<', '\\<=', '\\>=') colors = ('blue','orange','green') def __init__(self, name='', raw_data='', date=None, ftype='Y', equal_type='=', color='blue', selected=False ): """ Makes an empty Graph. Function """ Data.__init__(self, name, raw_data, self.dType, date) self.set_type(ftype, equal_type) self.set_color(color) self.selected = selected def copy(self): """ Create a new GraphFunc object from this object """ return GraphFunc(self.name, self.raw_data, self.date, self.ftype, self.equal_type, self.color, self.selected) def set_color(self, color): if color in self.colors: self.color = color return True else: return False def set_type(self, ftype, equal_type): if ftype in self.func_types: self.ftype = ftype else: raise errors.BadFunction(ftype, 'Bad function type. Possible types are : '+str(func_types) ) if equal_type != '=': if ftype == 'Y': if equal_type in self.equal_types: self.equal_type = catdic.text_decode(equal_type, True) else: raise errors.BadFunction(ftype, 'Bad equality/inequality. Possibilities are '+str(self.equal_types)) else: raise errors.BadFunction(ftype, 'It is only possible to use inequalities with "Y" functions') def get_properties(self): """ Returns metadata about this function (type,equal_type,color, selected)""" return (self.ftype, catdic.text_encode(self.equal_type), self.color, self.selected) def get_text(self): """Returns the content of the fucntion in an human-readable format""" return catdic.text_encode(self.raw_data) def set_text(self, raw_data): """Sets the function content from a newcat-like string""" ### FIXME + WARNING : Maybe it would be good to add some tests !! e.g. : verify there are no instructions like \Prog etc... in the text / There are no X in X function types / there are one \xf6 chjaarcter in Param. functions self.raw_data = catdic.text_decode(raw_data, True) class Picture(Data): """Class for a casio picture""" name_rule = r'^Picture[1-6]$' dType = 'picture' def __init__(self, name = '', raw_data = '', date = None, pallet = None, \ color_byte = None): """Make an empty picture""" Data.__init__(self, name, raw_data, self.dType, 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): """Create 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'^.' dType = 'screencapture' 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) 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) ############## Classes for various types of files ################### class FileList(Data): """File List management class. It can only contains Lists""" name_rule = r'^File [1-6]$' dType = 'filelist' def __init__(self, number): """Create a filelist""" self.data = [] self.number = number self.name = 'File ' + str(self.number) def __getitem__(self,index): """ Same as self.data[index] This function is supposed to be used to get a list from the filelist. (eg: filelist[5], the returns the fifth list of the filelist""" return self.data[index-1] def __len__(self,index): """Returns the number of lists in the file. Same as len(self.data)""" return len(self.data) def add_list(self, lis): self.data.append(lis) ### Top-level file, able to contain any number of the above defined files 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 __len__(self): """Returns the len of self.data, number of items contained in the file_data""" return len(self.data) 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}
# -*- 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 ### Opened files for log : filereceived=open('/home/fabien_kubuntu/src/casetta/casetta-work/matrix/current-received.hex','w') filesent=open('/home/fabien_kubuntu/src/casetta/casetta-work/matrix/current-sent.hex','w') # Default functions def default_status(data_name, current_size, total_size, is_header = False): """Print the status of a transfert on the standard output.""" if total_size > 1: # Xion345 : I added this line to avoid a Zero-division error when receiving data of length 1 percent = ((current_size * 100) / total_size) else: percent = 100 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 wants 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=5, # or None xonxoff=0, #0 rtscts=0) #(o:1)0 self.status = status self.overwrite = overwrite self.cancel = False def check_cancel(self): """If the cancel flag is set, unset it and raise TransferAborted""" if self.cancel: self.cancel = False raise errors.TransferAborted() ################## 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.check_cancel() 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(): self.check_cancel() for data in data_list: if data.__class__ == datacls.FileList: for i in data: self.send_data(i) else: self.send_data(data) ### Here to manage file list 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""" self.send_header(data) response = self.get_byte() if response == '\x06': # Calculator accept the header pass elif response == '\x24': raise errors.DataNoManaged([data.__class__]) 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: data.change_pallet(cas.PICTURE_PALLET, ['\x00\x01\x00'] * 4) 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 or data.__class__ == datacls.List or data.__class__ == datacls.SimlEquationMatrix or data.__class__ == datacls.PolyEquationMatrix: raw_data_list = data.get_raw_data_list() else: raw_data_list = [data.raw_data] for raw_data in raw_data_list: # CRC calcul crc = 0 for byte in raw_data: crc += ord(byte) #crc = abs(255 - (crc % 256)) + 1 crc = (abs(255 - (crc % 256)) + 1) % 256 #print "old crc=", crc #crc = 0 #for byte in raw_data: # crc += ord(byte) # if crc > 255: # crc -= 256 #crc = 256 - crc #print "new crc=", crc # Now sending the data filesent.write('\x3a' + raw_data) self.send_string('\x3a' + raw_data, self.status, data.name, False) # All data sent, let the calc check the CRC filesent.write(chr(crc)) self.send_byte(chr(crc)) response = self.get_byte() if response != '\x06': raise errors.ChecksumError() 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 receive from the calc.""" file_data = datacls.FileData() while not self.calc_is_ready_to_send(): self.check_cancel() # Debut de la réception while True: data = self.receive_data() if data.__class__ == cas.End: break if data.__class__ == datacls.List and data.belongs_to_file != None: #print "Liste appartenant à un fichier " + str(data.belongs_to_file) if data.name[-1] == '1': #print "1ère liste détectée" filelist = datacls.FileList(number = data.belongs_to_file) #print filelist.__class__ file_data.data.append(filelist) ## FIXME : It would be better to use a method #print file_data[0].__class__ for i in range(len(file_data)): ## FIXME : It would be better to remember index of file_list if file_data[i].__class__== datacls.FileList and file_data[i].name == 'File '+str(data.belongs_to_file): print file_data[i] file_data[i].add_list(data) else: 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 self.status('unknown', 0, 49, True) header, data_type, sub_type = self.get_header() print [data_type, sub_type] 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': # shorter 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 == 'viewvar': data = datacls.ViewVariable() elif data_type == 'matrix': data = datacls.Matrix() #data.dimensions=(ord(header[7]),ord(header[9])) -> Moved to the function fill_metadata in cas.py elif data_type == 'list': data = datacls.List() #data.dimension=ord(header[7]) -> Moved to the function fill_metadata in cas.py elif data_type == 'simlequation-matrix': data = datacls.SimlEquationMatrix() elif data_type == 'polyequation-matrix': data = datacls.PolyEquationMatrix() elif data_type == 'function-memory': data = datacls.FMem() elif data_type == 'graph-func': data = datacls.GraphFunc() else: # unknown data, refuse header self.send_byte("\x00") raise errors.HeaderError() cas.fill_metadata(data, header) print data.__class__ #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") ### Transfer part ## The transfer part is executed only if data_len > 0. You can receive empty list ## when receiving a file list from the calculator. ## In this case only a header is transmitted ! ## So, the read byte is not the byte to initiate the transfer ## but the byte to initiate the transfer of the next header but the first byte of the next ## header. Same thing happens when receiving all "Variables". if data_len > 0: if not self.get_byte() == '\x3a': raise errors.BadAnswerFromCalc() crc = 0 raw_data = '' #print [data_len] for index in range(data_len): self.check_cancel() byte = self.get_byte() filereceived.write(byte) print [byte] crc = crc + ord(byte) ## List/Matrix management specific block if ( data_type == 'list' or data_type == 'matrix' or data_type == 'simlequation-matrix' or data_type == 'polyequation-matrix' ) and (index-13)%14==0 and index <= data_len-14: # Checksum test calc_crc=self.get_byte() filereceived.write(calc_crc) if abs(255 - (crc % 256)) + 1 == ord(calc_crc): self.send_byte('\x06') crc=0 resp=self.get_byte() filereceived.write(resp) if resp != '\x3a': raise errors.BadAnswerFromCalc(resp) else: raise errors.ChecksumError() ## Screencapture management specific block 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 ## Picture management specific block 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 #self.status(data.name, index, data_len - 1, False) self.status(data.name, index, data_len-1, False) ## Check CRC newcrc = ord(self.get_byte()) crc = abs(255 - (crc % 256)) + 1 #print 'new crc=', newcrc, 'crc=', crc if newcrc != crc and (data_type != 'screencapture' and \ sub_type != 'color') and data_len != 0 : # Warning: the crc check is not done for color screencapture # because the crc of color screencapture is never # valid. raise errors.ChecksumError() #if data_type == 8 and data_sub_type == 13: # print "coincoin (cf.perl)" / Ah ça, c'est vraiment malin ! 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 # Everything is OK self.send_byte('\x06') return data # Returns the data even if it is empty def get_header(self): """Return [header, header_type]""" byte = self.get_byte() if not byte == '\x3a': #while byte !='': #print [byte] # byte=self.get_byte() 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 if h_crc != ord(byte) : raise errors.ChecksumError() print [header] return [header, header_type, sub_type]
# -*- 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 exceptions for the serial transfer tool # ############################################################################ # # 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 # ############################################################################ """Exceptions used in 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: $" class FormatCantOpen(Exception): """Exception raised when a format cannot open a file (write only)""" def __init__(self, format): Exception.__init__(self) self.format = format def __str__(self): return repr(self.format.name) class FormatCantSave(Exception): """Exception raised when a format canot save a file (read only)""" def __init__(self, format): Exception.__init__(self) self.format = format def __str__(self): return repr(self.format.name) class ToolNotFound(Exception): """Exception raised when a tool cannot be used (the open function is not found for this tool or the command is not in the path)""" def __init__(self, tool): Exception.__init__(self) self.tool = tool def __str__(self): return repr(self.tool) class FormatNotFound(Exception): """Exception raised when a function cannot select the right format""" pass class DataNoManaged(Exception): """Exception raised when a format cannot manage some data type""" def __init__(self, data_type_list): Exception.__init__(self) self.data_type_list = data_type_list def __str__(self): return repr(self.data_type_list) class NoCommand(Exception): """Exception raised when a command is not found in the PATH""" def __init__(self, command): Exception.__init__(self) self.command = command def __str__(self): return repr(self.command) class ToolNotConfigured(Exception): """Exception raised when a mistake arrives using a transfer tool""" pass class CalcOutOfMemory(Exception): """To be raised when the calculator is out of memory during a transfer""" pass class ChecksumError(Exception): """To be raised when the calulator answer a CRC error""" pass class CannotOverwrite(Exception): """To be raised when the calculator refuse to overwrite a data""" def __init__(self, data_name): Exception.__init__(self) self.data_name = data_name def __str__(self): return repr(self.data_name) class BadAnswerFromCalc(Exception): """To be raised if an unexpected answer is sended by the calculator.""" def __init__(self, byte): Exception.__init__(self) self.byte = byte def __str__(self): return repr(chr(ord(self.byte))) class TransferAborted(Exception): """To be raised when a transfer is aborted.""" pass class HeaderError(Exception): """To be raised when the calculator answer an header error or send a bad/ unknown header.""" pass class BadMatrix(Exception): """To be raised when giving a bad matrix to Matrix.set_val() (e.g.: a matrix with lines of different lengths, a matrix containning strings or a matrix not given under the form of a list of lists)""" def __init__(self, value, message): Exception.__init__(self) self.value = value self.message = message def __str__(self): return self.message +' : '+ repr(self.value) class BadList(Exception): """To be raised when giving a bad list to List.set_val() (e.g.: a list containning strings or a list not given under the form of a list)""" def __init__(self, value, message): Exception.__init__(self) self.value = value self.message = message def __str__(self): return self.message +' : '+ repr(self.value) class BadNumber(Exception): """ To be raised when the absolute value of the number is too high/low, especially in data.set_simple_val()""" def __str__(self): return "The absolute value of the number is too high/too low and not supported by the calculator" class BadFunction(Exception): def __init__(self, value, message): Exception.__init__(self) self.value = value self.message = message def __str__(self): return self.message +' : '+ repr(self.value)
Mail converted by MHonArc 2.6.19+ | http://listengine.tuxfamily.org/ |