Import first working version
[fuse-aexplorer.git] / AEpy / AESession.py
1 import binascii
2 import serial
3 import struct
4
5
6 class AESession:
7     def __init__(self, link):
8         self.link = link
9         self.seq = 1
10         self.sendInit()
11         self.packetsize = 512
12
13
14     def recvMsg(self):
15         rawHeader = self.link.recv(12)
16         if len(rawHeader) != 12:
17             print('recvMsg: len(rawHeader) == ' + str(len(rawHeader)) + ' data: ' + binascii.hexlify(rawHeader))
18         #assert len(rawHeader) == 12
19
20         (type, datalen, seq, crc) = struct.unpack('!HHLL', rawHeader)
21         assert crc == (binascii.crc32(rawHeader[0:8]) & 0xffffffff)
22         # TODO: Send PkRs if CRC mismatches
23
24         data = b''
25
26         if datalen > 0:
27             data = self.link.recv(datalen)
28             assert len(data) == datalen
29
30             # Note: Python calculates signed CRCs.
31             #       Thus, we parse the incoming CRC as signed.
32             datacrc = self.link.recv(4)
33             assert len(datacrc) == 4
34             (datacrc,) = struct.unpack('!L', datacrc)
35
36             assert datacrc == (binascii.crc32(data) & 0xffffffff)
37             # TODO: Send PkRs if CRC mismatches
38
39         self.link.send(b'PkOk')
40
41         # seq is currently ignored when receiving
42         return (type, data)
43
44
45     def sendMsg(self, type, data):
46         stream = struct.pack('!HHL', type, len(data), self.seq)
47         stream += struct.pack('!L', binascii.crc32(stream) & 0xffffffff)
48
49         if len(data) > 0:
50             stream += data
51             stream += struct.pack('!L', binascii.crc32(data) & 0xffffffff)
52
53         self.link.send(stream)
54
55         # TODO: Re-send on 'PkRs'
56         assert self.link.recv(4) == b'PkOk'
57
58         self.seq += 1;
59
60
61
62     def sendInit(self):
63         self.sendMsg(2, b'Cloanto(r)')
64         # TBD: Password support.
65         #      It is CRC32'd and the CRC is appended to the string above.
66
67         # TODO: Recover from desynced state
68         #if not self.isAcked():
69         #    self.sendAck()
70         #    return self.sendInit()
71
72         (type, data) = self.recvMsg()
73         assert type == 2
74         assert data.startswith(b'Cloanto')
75
76
77     def sendClose(self):
78         print('sendClose')
79
80         self.sendMsg(0x6d, b'')
81
82         (type, data) = self.recvMsg()
83         assert type == 0x0a
84         if data != b'\0\0\0\0\0':
85             print('sendClose: data == ' + binascii.hexlify(data))
86         # Format of data returned:
87         # Byte 0: ?
88         # Byte 1: ?
89         # Byte 2: ?
90         # Byte 3: 00 - No error
91         #         06 - File no longer exists
92         #         1c - Timed out waiting for host to request next read block
93         # Byte 4: Path in case of error 06.
94         #         Empty (null-terminated) otherwise?
95         #         Null-terminated string.
96         #assert data == b'\0\0\0\0\0'