aboutsummaryrefslogtreecommitdiff
path: root/include/libcasio/format/cas.h
blob: f4574aece7688b75b7853fa5a1ae64eaec543866 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
/* ****************************************************************************
 * libcasio/format/cas.h -- the older CAS file format description.
 * Copyright (C) 2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
 *
 * This file is part of libcasio.
 * libcasio is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 3.0 of the License,
 * or (at your option) any later version.
 *
 * libcasio 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with libcasio; if not, see <http://www.gnu.org/licenses/>.
 * ************************************************************************* */
#ifndef  LIBCASIO_FORMAT_CAS_H
# define LIBCASIO_FORMAT_CAS_H
# include "../cdefs.h"
# pragma pack(1)
CASIO_BEGIN_NAMESPACE

/* See `libcasio/format.h` for general information about what the CASIOLINK
 * format is.
 *
 * The CASIOLINK file format is linked to how the legacy (CAS) protocol works:
 * one-byte packets are sent between the two machines (for initiating
 * communication, ACKing, NAKing, ...), unless the sent/receiving byte is
 * the double-colon ':' (0x3A) -- then it is the beginning of something
 * that is more than one-byte long. CAS files do not include the one-byte
 * packets, or repeated headers/parts (because of bad checksum or timeouts,
 * for example) -- see the legacy protocol documentation for this.
 *
 * Actually, there are three main things that start with a ':'. The main type
 * is a header, that describes the content that follows. A content can have
 * no data part (e.g. END packet), one data part (e.g. programs), or
 * more (e.g. width*height content parts for lists and matrixes, which
 * represent the individual cells). These content parts have different formats
 * according to the global content part.
 *
 * But I told you there were three things. The third is a little subtle:
 * one header can correspond to several contents. Then we have what we
 * call the CAS file*s* part (or heads part).
 * An example is 'FN' (set of editor files): we receive the main head,
 * with the count of editor files that are sent to us, then we receive one part
 * indicating the size of each files, then for each file, we receive one part,
 * which is the file content.
 *
 * We have one protocol, the CASIOLINK protocol (also called 'legacy protocol'
 * in the libcasio scope), but we have two different type of headers. The two
 * have a fixed width, so they are named by the number of bytes they occupy.
 * Notice that, for what I know, content formats don't vary between header
 * types. The checksuming technique neither. */
/* ************************************************************************* */
/*  CAS40 header                                                             */
/* ************************************************************************* */
/* The first header to have appeared is the CAS40 (40 bytes long).
 * It is known in CaS as the protocol the CFX-9700G uses.
 *
 * The header format is the following: */

typedef struct casio_cas40_s {
	casio_uint8_t casio_cas40_data[2];      /* data type -- see `type/cas.c` */
	casio_uint8_t casio_cas40_misc[5];      /* type-specific subheader */
	casio_uint8_t casio_cas40_filename[12]; /* editor filename. */
	casio_uint8_t casio_cas40_password[12]; /* editor password. */
	casio_uint8_t casio_cas40__reserved0[7]; /* 0xFFs */
	casio_uint8_t casio_cas40_checksum;
} casio_cas40_t;

/* The specific bytes are different according to the datatype, but its
 * length is fixed. */
/* ************************************************************************* */
/*  CASDYN header                                                            */
/* ************************************************************************* */
/* The CASDYN (dynamic size, super header) header appeared later.
 * It is known in CaS as the protocol the CFX-9850G uses.
 *
 * This header format was previously named 'caspro' in libcasio, then CAS50
 * when I thought the header was always 50 bytes long, then CASDYN as soon as
 * I realized this application system was there on headers of different sizes.
 *
 * I started understanding that this byte between the app and data type I
 * thought was useless was in fact not when I saw in Flash100 sources that it
 * was always 0x31 ('1' in ASCII), which are 40 bytes long. From there and
 * other pieces of documentation, here are the extension types I could find: */

# define casio_casdyn_9850  0x00 /* 50 bytes long */
# define casio_casdyn_end   0xFF /* yet an alias to `casdyn_ext_9850`,
                                  * used by the END packet. */
# define casio_casdyn_g100  0x31 /* 40 bytes long */
# define casio_casdyn_g100b 0x32 /* yet an alias to `casdyn_ext_g100`,
                                  * used for some commands */

/* Here are the common fields to all packets: */

typedef struct casio_casdyn_s {
	/* app */
	casio_uint8_t casio_casdyn_app[3];

	/* type of extension - see the `casdyn_ext_*` macros above */
	casio_uint8_t casio_casdyn_ext;
} casio_casdyn_t;

/* The known apps are:
 *
 *  Ext. | App. | Description/role
 * ------+------+----------------------------------
 *  0x00 | TXT  | Editor (not program editor);
 *  0x00 | VAL  | Send() or Receive() function
 *  0x00 | IMG  | Screen shooter?
 *  0x00 | REQ  | Request a file.
 * ------+------+----------------------------------
 *  0xFF | END  | End packet.
 * ------+------+----------------------------------
 *  0x31 | MDL  | Model description (reference)
 *  0x31 | END  | End packet.
 *  0x31 | REQ  | Request a file.
 *  0x31 | ADN  | Send a file.
 *  0x31 | FMV  | ???
 *  0x31 | FCL  | ???
 *  0x31 | MCS  | ??? (main memory?)
 * ------+------+----------------------------------
 *  0x32 | ADN  | Send a file. (bis, Flash100?)
 *  0x32 | REQ  | Request a file. (bis, Flash100?)
 *
 * The format the CFX-9850G uses (extension bytes 0x00 and 0xFF) is 50 bytes
 * long, so we'll name it CAS50. Here is the header format the CASDYN header
 * is read: */

typedef struct casio_cas50_s {
	/* types */
	casio_uint8_t  casio_cas50_data[2];

	/* data length */
	casio_uint16_t casio_cas50_width;
	casio_uint16_t casio_cas50_height;
	casio_uint8_t  casio_cas50_name[8];

	/* variable-related data */
	casio_uint8_t  casio_cas50_prefix[8]; /* "Variable" for vars,
	                                 * "PROG\x99" "0\xFF\xFF" for progs,
	                                 *  0xFFs otherwise */
	casio_uint8_t  casio_cas50_aux[8]; /* variable: "R\x0A"/"C\x0A",
	                              * editor: password */

	/* something else (?) */
	casio_uint8_t  casio_cas50_option1[2]; /* 'NL'? "\xFF\xFF" for progs */
	casio_uint8_t  casio_cas50__reserved[12]; /* other options?
	                                           * -> cf. CAT format */

	/* end of packet */
	casio_uint8_t  casio_cas50_checksum;
} casio_cas50_t;

/* The format the G100 (AlgebraFX, extension bytes 0x31 and 0x32) uses is
 * 40 bytes long, but as CAS40 already exists, we'll name this format CAS100
 * (which is funny because the Graph 100 has a CAS, Computer Algebra System).
 *
 * Information from here is mainly decoded from Flash100 sources.
 * Anyway, here is the CAS100 header after the CASDYN header is read: */

typedef struct casio_cas100_s {
	/* drive?
	 * - "INF": system
	 * - "FR0": segment
	 * - "MSG": language
	 * - "MR0": ?
	 * - "S00": ? */
	casio_uint8_t  casio_cas100_drive[3];

	/* driver number, in ASCII (0x30 + <num>)
	 * "INF" is 1, "FR0" is 1-6, "MSG" is 1, "MR0" is 4, "S00" is 0 */
	casio_uint8_t  casio_cas100_id;

	/* group size (size of each fragment group part to be sent): 0x400, 1024 */
	casio_uint32_t casio_cas100_size;

	/* ExportDrive: 0x80, type? */
	casio_uint32_t casio_cas100_type;

	/* drive size: 0x20000 bytes */
	casio_uint32_t casio_cas100_drive_size;

	/* 0xFFs */
	casio_uint8_t  casio_cas100__unknown[18];

	/* checksum */
	casio_uint8_t  casio_cas100_checksum;
} casio_cas100_t;

/* However, the CAS100 header has a variant, with the 'MDL' application: it
 * looks like system info. The information here is obtained from Flash100's
 * source code, once again. */

typedef struct casio_cas100info_s {
	/* board identifier? "ZX945" */
	casio_uint8_t  casio_cas100info_board[5];
	casio_uint8_t  casio_cas100info_delim0; /* 0xFF */

	/* serial settings? "038400N"
	 * this would mean 38400 bauds, no parity (2 stop bits?) */
	casio_uint8_t  casio_cas100info_settings[11];

	/* ROM version? "1.00" or "1.01" */
	casio_uint8_t  casio_cas100info_version[4];

	/* values? */
	casio_uint32_t casio_cas100info__val1; /* 0xF00 or 0x1000;common: 0x1000 */
	casio_uint32_t casio_cas100info__val2; /* 0x400 */
	casio_uint32_t casio_cas100info__val3; /* 0x100 */

	/* hex value with prefix... what? */
	casio_uint8_t  casio_cas100info_hex[4]; /* "0x07", litterally,
	                                   * or 0x07 followed by three 0xFFs */
	casio_uint8_t  casio_cas100info_delim1; /* 0xFF */

	/* checksum */
	casio_uint8_t  casio_cas100info_checksum;
} casio_cas100info_t;

/* As you can guess, CAS40 and CASDYN are, in theory, incompatible.
 * In practice, anyhow, they more or less are: libcasio reads the first 4 bytes
 * from the header, and tries to identify a CASDYN header; if it doesn't
 * manage, it falls back on CAS40.
 *
 * Here are the content formats for the two header types: */

CASIO_END_NAMESPACE
# pragma pack()
# include "cas/program.h" /* programs, f-mem */
# include "cas/cell.h" /* lists, matrixes, variables */
# include "cas/backup.h"
# include "cas/picture.h"
# include "cas/graph.h"
# include "cas/gmem.h"
#endif /* LIBCASIO_FORMAT_CAS_H */