| [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/ |