aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Phillips <dbphillipsnz@gmail.com>2016-01-20 14:03:21 +1300
committerDavid Phillips <dbphillipsnz@gmail.com>2016-01-20 14:03:21 +1300
commitb9fc5fed91512208d861e287b1369f3122861144 (patch)
treee11e3cc823b19feed7fb6c84d92990e9585e3d8b
downloadcasio-9850-b9fc5fed91512208d861e287b1369f3122861144.tar.xz
Initial import
-rw-r--r--.gitignore3
-rw-r--r--Makefile20
-rw-r--r--casio-get.c129
-rw-r--r--casio-get.h8
-rw-r--r--error.c15
-rw-r--r--error.h6
-rw-r--r--packet.c50
-rw-r--r--packet.h32
-rw-r--r--port.c92
-rw-r--r--port.h14
-rw-r--r--screen-to-xpm.c152
11 files changed, 521 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5ecf1be
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+*.o
+screen-to-xpm
+casio-get
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..058c0b7
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,20 @@
+
+CFLAGS = -Wall -Werror -Wextra
+
+.PHONY: all
+all: casio-get screen-to-xpm
+
+screen-to-xpm: screen-to-xpm.o packet.o
+ $(CC) -o $@ $^ $(LDFLAGS)
+
+casio-get: casio-get.o error.o port.o packet.o
+ $(CC) -o $@ $^ $(LDFLAGS) -lserialport
+
+
+%.o: %.c
+ $(CC) -c -o $@ $< $(CFLAGS)
+
+
+.PHONY: clean
+clean:
+ rm -fv casio-get screen-to-xpm *.o
diff --git a/casio-get.c b/casio-get.c
new file mode 100644
index 0000000..9beb87f
--- /dev/null
+++ b/casio-get.c
@@ -0,0 +1,129 @@
+#include "casio-get.h"
+
+#define SMALL_PACKET_WAIT 100
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+void print_checksum_msg(unsigned char expected, unsigned short actual)
+{
+ fprintf(stderr, "Checksum\t: %s (needed 0x%x, found 0x%x)\n", expected==actual? "OK" : "BAD", expected, actual);
+}
+
+int main()
+{
+ unsigned int read;
+ unsigned char temp_buffer[1024];
+ unsigned char rx_buffer[65536];
+
+ setbuf(stdout, NULL);
+ memset(rx_buffer, 0, sizeof(rx_buffer));
+
+ long expected;
+ unsigned int x,y;
+
+ unsigned char colours = 3;
+ unsigned char colour;
+ unsigned int i;
+ struct sp_port *port;
+ port = port_init("/dev/ttyUSB0");
+
+ // Wait for calculator and ACK
+ wait_calc(port);
+ send_calc_byte(port, ATTENTION_ACK);
+ fprintf(stderr,"Sent 0x%x (ACK)\n",ATTENTION_ACK);
+
+
+
+ /*******************************************
+ * Receive header packet
+ *******************************************/
+ read = calc_read(port, rx_buffer, PKT_HEADER_MAX_SIZE);
+ fprintf(stderr, "\n== HEADER ========================================\n");
+ fprintf(stderr, "Size (bytes)\t: %d\n", read);
+
+ unsigned char sum_expected = rx_buffer[read-1];
+ unsigned char sum = calculate_checksum((const char*)rx_buffer+1, (const char*)rx_buffer+read-1);
+
+ print_checksum_msg(sum_expected, sum);
+
+ for(i = 0; i < read; i++)
+ printf("%c", (unsigned char)rx_buffer[i]);
+
+ colours = 3;
+
+ switch (get_packet_type(rx_buffer))
+ {
+ /* Screenshot (F<->D button) */
+ case PKT_SCREEN_HEADER_BW:
+ colours = 1;
+ case PKT_SCREEN_HEADER_COL:
+ send_calc_byte(port, MISC_ACK);
+ x = rx_buffer[4];
+ y = rx_buffer[3];
+ expected = (x*y)/8 + 2;
+
+ /* multi-colour images have an extra byte per colour frame for colour identification */
+ if (colours > 1)
+ expected++;
+ fprintf(stderr,
+ "Data type\t: Screen dump\n"
+ "Dimensions\t: %d x %d\n", x,y);
+
+ fprintf(stderr, "\n== DATA ==========================================\n");
+
+ for (colour = 0; colour < colours; colour++)
+ {
+ read = calc_read(port, rx_buffer, expected);
+ fprintf(stderr,"Colour %d/%d read\t: %d bytes\n", colour+1, colours, read);
+ for(i = 0; i < read; i++)
+ printf("%c", rx_buffer[i]);
+
+ sum_expected = rx_buffer[read-1];
+ sum = calculate_checksum((const char*)rx_buffer+1+(colours > 1), (const char*)rx_buffer+read-1);
+ print_checksum_msg(sum_expected, sum);
+
+ send_calc_byte(port, MISC_ACK);
+
+ }
+ break;
+
+ /* Full memory backup */
+ case PKT_BACKUP_HEADER:
+ /* Get firmware name (starts at byte 27 and is hival-terminated */
+ i = 27;
+ while((rx_buffer[i] != 0xff) && i < sizeof(temp_buffer))
+ {
+ temp_buffer[i-27] = rx_buffer[i];
+ i++;
+ }
+ temp_buffer[i-27] = '\0';
+
+ fprintf(stderr, "Memory backup coming (firmware %s)...\n", temp_buffer);
+ break;
+ case PKT_FUNCTION_HEADER:
+ fprintf(stderr, "Function(s) coming...\nNOT IMPLEMENTED\n");
+ break;
+ case PKT_VALUE_HEADER:
+ fprintf(stderr, "Value coming...\nNOT IMPLEMENTED\n");
+ //break;
+ case PKT_PROGRAM_HEADER:
+ fprintf(stderr, "Program coming...\nNOT IMPLEMENTED\n");
+ //break;
+ default:
+ fprintf(stderr, "List(s) coming...\n");
+ fprintf(stderr, "Matrix/Matrices coming...\n");
+ fprintf(stderr, "NOT IMPLEMENTEEEED, NOT ANNYYYY OF THIIIIIIS!!!\n");
+ break;
+ }
+
+
+
+
+ sp_close(port);
+
+
+ return 0;
+}
diff --git a/casio-get.h b/casio-get.h
new file mode 100644
index 0000000..9324e2c
--- /dev/null
+++ b/casio-get.h
@@ -0,0 +1,8 @@
+#ifndef GETSCREEN_H
+#define GETSCREEN_H
+
+#include "error.h"
+#include "packet.h"
+#include "port.h"
+
+#endif
diff --git a/error.c b/error.c
new file mode 100644
index 0000000..bf30cd8
--- /dev/null
+++ b/error.c
@@ -0,0 +1,15 @@
+#include "casio-get.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+void serial_error(const char* fname);
+
+/******************************************************************************
+ * Report error related to serial port read/write etc
+ ******************************************************************************/
+void serial_error(const char *fname)
+{
+ fprintf(stderr, "Error in %s: %s\n", fname, sp_last_error_message());
+ exit(EXIT_FAILURE);
+}
diff --git a/error.h b/error.h
new file mode 100644
index 0000000..9869e7d
--- /dev/null
+++ b/error.h
@@ -0,0 +1,6 @@
+#ifndef ERROR_H
+#define ERROR_H
+
+void serial_error(const char* fname);
+
+#endif
diff --git a/packet.c b/packet.c
new file mode 100644
index 0000000..663778e
--- /dev/null
+++ b/packet.c
@@ -0,0 +1,50 @@
+#include "casio-get.h"
+#include <string.h>
+
+
+/*****************************************************************************
+ * Calculate the checksum of the data area of a packet
+ *****************************************************************************/
+unsigned char calculate_checksum(const char *start, const char *stop)
+{
+ unsigned char sum = 0;
+ while (start != stop)
+ sum += *(start++);
+
+ return 1 + ~(sum);
+}
+
+
+unsigned short calculate_checksum_word(const char *start, const char *stop)
+{
+ unsigned short sum = 0;
+ while (start != stop)
+ sum += (unsigned char)(*(start++));
+
+ return 1 + ~(sum);
+}
+
+/*****************************************************************************
+ * Returns the type of packet as determined from the packet header
+ *****************************************************************************/
+enum packet_types get_packet_type(const unsigned char* data)
+{
+ if (strncmp((char*)data, ":END", 4) == 0)
+ return PKT_END;
+ if (strncmp((char*)data, ":VAL", 4) == 0)
+ return PKT_VALUE_HEADER;
+ if (strncmp((char*)data, ":DD", 3) == 0)
+ return PKT_SCREEN_HEADER_BW;
+ if (strncmp((char*)data, ":DC", 3) == 0)
+ return PKT_SCREEN_HEADER_COL;
+ if (strncmp((char*)data, ":MEM", 4) == 0)
+ return PKT_BACKUP_HEADER;
+ if (strncmp((char*)data, ":FNC", 4) == 0)
+ return PKT_FUNCTION_HEADER;
+ if (strncmp((char*)data, ":TXT", 4) == 0)
+ return PKT_PROGRAM_HEADER;
+ if (strncmp((char*)data, ":\x00\x01\x00\x01", 4) == 0)
+ return PKT_VAL;
+
+ return PKT_UNKNOWN;
+}
diff --git a/packet.h b/packet.h
new file mode 100644
index 0000000..4850cb6
--- /dev/null
+++ b/packet.h
@@ -0,0 +1,32 @@
+#ifndef PACKET_H
+#define PACKET_H
+
+#define MISC_ACK 0x06
+
+/*#define REQUEST_TYPE_VAR 0x4D56 // VM
+#define REQUEST_TYPE_PICTURE 0x4350 // PC
+#define REQUEST_TYPE_LIST 0x544C // LT
+#define REQUEST_TYPE_MATRIX 0x544D // MT
+*/
+
+#define PKT_HEADER_MAX_SIZE 50
+
+
+enum packet_types
+{
+ PKT_END,
+ PKT_VALUE_HEADER,
+ PKT_SCREEN_HEADER_BW,
+ PKT_SCREEN_HEADER_COL,
+ PKT_BACKUP_HEADER,
+ PKT_PROGRAM_HEADER,
+ PKT_FUNCTION_HEADER,
+ PKT_VAL,
+ PKT_UNKNOWN
+};
+
+unsigned char calculate_checksum(const char *start, const char *stop);
+unsigned short calculate_checksum_word(const char *start, const char *stop);
+enum packet_types get_packet_type(const unsigned char* data);
+
+#endif
diff --git a/port.c b/port.c
new file mode 100644
index 0000000..91e3a8c
--- /dev/null
+++ b/port.c
@@ -0,0 +1,92 @@
+#include "casio-get.h"
+
+#define PACKET_WAIT_PER_BYTE 2
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <libserialport.h>
+
+/******************************************************************************
+ * Wait for the calculator to request a data transfer
+ ******************************************************************************/
+void wait_calc(struct sp_port *port)
+{
+ char buf[1];
+ int read;
+ fprintf(stderr, "Waiting for calculator... ");
+ while((read = sp_blocking_read(port, buf, 1, 0)) > 0)
+ {
+ if (buf[0] == ATTENTION_REQ)
+ break;
+ }
+
+ if (read <= 0)
+ serial_error("sp_blocking_read");
+
+ fprintf(stderr, "transfer request received!\n");
+}
+
+
+/******************************************************************************
+ * Send single byte to calculator
+ ******************************************************************************/
+void send_calc_byte(struct sp_port *port, const char val)
+{
+ char data[1];
+ data[0] = val;
+ if (sp_blocking_write(port, data, 1, 0) != 1)
+ serial_error("sp_blocking_write");
+}
+
+enum sp_return calc_read(struct sp_port *port, unsigned char* buffer, size_t size)
+{
+ enum sp_return ret = sp_blocking_read(port, buffer, size, PACKET_WAIT_PER_BYTE*size);
+ if (ret < 0)
+ serial_error("sp_blocking_read");
+
+ return ret;
+}
+
+
+/******************************************************************************
+ * Open and initialise serial port
+ ******************************************************************************/
+struct sp_port* port_init(const char* device)
+{
+ struct sp_port* port;
+ if (sp_get_port_by_name(device, &port) != SP_OK)
+ serial_error("sp_get_port_by_name");
+
+ if (sp_open(port, SP_MODE_READ|SP_MODE_WRITE) != SP_OK)
+ serial_error("sp_open");
+
+
+ /* Port config is more or less hard-coded
+ The Casio calcs operate at 9600,8N with 2 stop bits RX
+ and 1 stop bit TX but 2 stop bits both ways can't hurt :) */
+ if (sp_set_baudrate(port, 9600) != SP_OK)
+ serial_error("sp_set_baudrate");
+
+ if (sp_set_parity(port, SP_PARITY_NONE) != SP_OK)
+ serial_error("sp_set_parity");
+
+ if (sp_set_bits(port, 8) != SP_OK)
+ serial_error("sp_set_bits");
+
+ if (sp_set_stopbits(port, 1) != SP_OK)
+ serial_error("sp_set_stopbits");
+
+ if (sp_set_flowcontrol(port, SP_FLOWCONTROL_NONE) != SP_OK)
+ serial_error("sp_set_flowcontrol");
+
+ if (sp_set_xon_xoff(port, SP_XONXOFF_DISABLED) != SP_OK)
+ serial_error("sp_set_xon_xoff");
+
+ if (sp_set_dtr(port, SP_DTR_ON) != SP_OK)
+ serial_error("sp_set_dtr");
+
+ if (sp_set_rts(port, SP_RTS_OFF) != SP_OK)
+ serial_error("sp_set_rts");
+
+ return port;
+}
diff --git a/port.h b/port.h
new file mode 100644
index 0000000..9b86a48
--- /dev/null
+++ b/port.h
@@ -0,0 +1,14 @@
+#ifndef PORT_H
+#define PORT_H
+
+#include <libserialport.h>
+
+#define ATTENTION_REQ 0x16
+#define ATTENTION_ACK 0x13
+
+void wait_calc(struct sp_port *port);
+void send_calc_byte(struct sp_port *port, const char val);
+enum sp_return calc_read(struct sp_port *port, unsigned char* buffer, size_t size);
+struct sp_port* port_init(const char* device);
+
+#endif
diff --git a/screen-to-xpm.c b/screen-to-xpm.c
new file mode 100644
index 0000000..35a293a
--- /dev/null
+++ b/screen-to-xpm.c
@@ -0,0 +1,152 @@
+#include <stdio.h>
+#include <string.h>
+
+#include "packet.h"
+
+
+#define IMAGE_HEADER_BYTES_BW 40
+#define IMAGE_HEADER_BYTES_COL 41
+#define HEADER_SIZE 3
+#define IMAGE_WIDTH 128
+#define IMAGE_HEIGHT 64
+#define NUM_COLOURS 3
+
+#define COLOUR_BLANK '0'
+
+const char colours[] = {'B', 'G', 'R'};
+
+
+void load_mono(char (*image)[IMAGE_WIDTH][IMAGE_HEIGHT])
+{
+ unsigned short x, y;
+ char c;
+ char i;
+ for (x = 0; x < IMAGE_WIDTH && !feof(stdin); x+=8)
+ {
+ for (y = 0; y < IMAGE_HEIGHT && !feof(stdin); y++)
+ {
+ c = fgetc(stdin);
+ for (i = 0; i < 8; i++)
+ (*image)[x+i][y] = c & (1<<(i))? colours[0] : COLOUR_BLANK;
+ }
+ }
+}
+
+void load_colour(char (*image)[IMAGE_WIDTH][IMAGE_HEIGHT])
+{
+ short x, y, colour;
+ char buffer[IMAGE_WIDTH/8][IMAGE_HEIGHT];
+ char c;
+ char i;
+ for (colour = 0; colour < NUM_COLOURS; colour++)
+ {
+ fread(buffer, sizeof(buffer), 1, stdin);
+ for (x = 0; x < IMAGE_WIDTH && !feof(stdin); x+=8)
+ {
+ for (y = 0; y < IMAGE_HEIGHT && !feof(stdin); y++)
+ {
+ c = buffer[x/8][IMAGE_HEIGHT-1-y];
+ for (i = 0; i < 8; i++)
+ {
+ if ((*image)[x+i][y] == COLOUR_BLANK)
+ (*image)[x+i][y] = c & (1<<(i))? colours[colour] : COLOUR_BLANK;
+ }
+ }
+ }
+ /* eat the checksum */
+ fgetc(stdin);
+
+ /* eat the : and the colour identification bytes if another channel remains */
+ if (colour != NUM_COLOURS-1)
+ {
+ fgetc(stdin);
+ fgetc(stdin);
+ }
+ }
+}
+
+
+
+int main(int argc, char **argv)
+{
+ unsigned char header[PKT_HEADER_MAX_SIZE];
+ char image[IMAGE_WIDTH][IMAGE_HEIGHT];
+ int x, y, read, expected;
+ enum packet_types type;
+
+ if (argc != 1)
+ {
+ fprintf(stderr,
+ "Converts monochrom CASIO FX-9850 screen dumps to XPM images.\n"
+ "Reads screen dump from stdin and outputs XPM to stdout\n"
+ "Also prints information and warning messages to stderr when necessary\n"
+ "\n"
+ "Syntax: %s < screen.dump > screen.xpm\n", argv[0]);
+ return 1;
+ }
+
+ /* Lazy here, we just catch EOF later */
+ /* magic number: 3 == strlen(":DD") == strlen(":DC") */
+ read = fread(header, 3, 1, stdin);
+
+ switch (get_packet_type(header))
+ {
+ case PKT_SCREEN_HEADER_BW:
+ type = PKT_SCREEN_HEADER_BW;
+ expected = IMAGE_HEADER_BYTES_BW;
+ break;
+ case PKT_SCREEN_HEADER_COL:
+ type = PKT_SCREEN_HEADER_COL;
+ expected = IMAGE_HEADER_BYTES_COL;
+ break;
+ default:
+ fprintf(stderr, "Invalid header '%s', not a Casio FX 9850 screenshot\n", header);
+ return 1;
+ break;
+ }
+
+ fprintf(stderr, "Detected %s screenshot\n",
+ type == PKT_SCREEN_HEADER_BW? "monochrome" : "colour");
+
+ /* skip over rest of header */
+ expected -= read;
+ while (--expected)
+ fgetc(stdin);
+
+ memset(image, COLOUR_BLANK, sizeof(image));
+
+ if (type == PKT_SCREEN_HEADER_BW)
+ load_mono(&image);
+ else
+ load_colour(&image);
+
+ /* Tasty! A hard-coded XPM header! */
+ printf( "/* XPM */\n"
+ "static char *Pic_colors[] = {\n"
+ " \"%d %d 4 1\"\n"
+ " \"B c #000033\"\n"
+ " \"G c #005555\"\n"
+ " \"R c #FF6633\"\n"
+ " \"0 c #FFFFFF\"\n"
+ "};\n"
+ "static char *Pic_pixels[] = {\n",IMAGE_WIDTH,IMAGE_HEIGHT
+ );
+
+
+ for (y = 0; y < IMAGE_HEIGHT; y++)
+ {
+ printf("\""); /* XPM stuff */
+
+ for (x = IMAGE_WIDTH-1; x >= 0; x--)
+ printf("%c",image[x][y]);
+
+ printf("\",\n"); /* Again, XPM stuff */
+ }
+
+
+ /* Hard-coded XPM footer */
+ printf("\"};");
+
+ return 0;
+}
+