1 /*
2  * TilEm II
3  *
4  * Copyright (c) 2011-2012 Benjamin Moody
5  * Copyright (c) 2011 Duponchelle Thibault
6  *
7  * This program is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation, either version 3 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 /* Key binding */
22 typedef struct _TilemKeyBinding {
23 	unsigned int keysym;     /* host keysym value */
24 	unsigned int modifiers;  /* modifier mask */
25 	int nscancodes;          /* number of calculator scancodes */
26 	byte *scancodes;         /* calculator scancodes */
27 } TilemKeyBinding;
28 
29 /* A single action */
30 typedef struct _TilemMacroAtom {
31 	char* value;
32 	int type;
33 } TilemMacroAtom;
34 
35 /* All the actions */
36 typedef struct _TilemMacro {
37 	TilemMacroAtom** actions;
38 	int n;
39 } TilemMacro;
40 
41 
42 
43 typedef struct _TilemCalcEmulator {
44 	GThread *z80_thread;
45 
46 	/* Mutex controlling access to the calc.  Use
47 	   tilem_calc_emulator_lock()/unlock() rather than
48 	   g_mutex_lock()/unlock() directly. */
49 	GMutex *calc_mutex;
50 	int calc_lock_waiting;
51 
52 	GCond *calc_wakeup_cond;
53 	TilemCalc *calc;
54 	gboolean paused;
55 	gboolean exiting;
56 	gboolean limit_speed;   /* limit to actual speed */
57 
58 	/* Timer used for speed limiting */
59 	GTimer *timer;
60 	gulong timevalue;
61 
62 	/* Queue of tasks to be performed */
63 	GQueue *task_queue;
64 	gboolean task_busy;
65 	gboolean task_abort;
66 	GCond *task_finished_cond;
67 
68 	/* Sequence of keys to be pressed */
69 	byte *key_queue;
70 	int key_queue_len;
71 	int key_queue_timer;
72 	int key_queue_pressed;
73 	int key_queue_cur;
74 	int key_queue_hold;
75 
76 	GMutex *lcd_mutex;
77 	TilemLCDBuffer *lcd_buffer;
78 	TilemLCDBuffer *tmp_lcd_buffer;
79 	TilemGrayLCD *glcd;
80 	gboolean grayscale;
81 	gboolean lcd_update_pending;
82 
83 	TilemAnimation *anim; /* animation being recorded */
84 	gboolean anim_grayscale; /* use grayscale in animation */
85 
86 	char *rom_file_name;
87 	char *state_file_name;
88 
89 	/* List of key bindings */
90 	TilemKeyBinding *keybindings;
91 	int nkeybindings;
92 
93 	struct _TilemMacro *macro;
94 
95 	/* Link transfer state */
96 	gboolean ilp_active;
97 	CalcUpdate *link_update; /* CalcUpdate (status and callbacks for ticalcs) */
98 	GMutex *pbar_mutex;
99 	char *pbar_title;
100 	char *pbar_status;
101 	gdouble pbar_progress;
102 	gboolean pbar_update_pending;
103 	gboolean progress_changed;
104 
105 	/* GUI widgets */
106 	struct _TilemDebugger *dbg;
107 	struct _TilemEmulatorWindow *ewin;
108 	struct _TilemScreenshotDialog *ssdlg;
109 	struct _TilemReceiveDialog *rcvdlg;
110 	struct _TilemLinkProgress *linkpb;
111 
112 
113 	FILE * macro_file;	/* The macro file */
114 	gboolean isMacroRecording; /* A flag to know everywhere that macro is recording */
115 
116 } TilemCalcEmulator;
117 
118 /* Errors */
119 #define TILEM_EMULATOR_ERROR g_quark_from_static_string("tilem-emulator-error")
120 enum {
121 	TILEM_EMULATOR_ERROR_NO_ROM,
122 	TILEM_EMULATOR_ERROR_INVALID_ROM,
123 	TILEM_EMULATOR_ERROR_INVALID_STATE
124 };
125 
126 /* Create a new TilemCalcEmulator. */
127 TilemCalcEmulator *tilem_calc_emulator_new(void);
128 
129 /* Free a TilemCalcEmulator. */
130 void tilem_calc_emulator_free(TilemCalcEmulator *emu);
131 
132 /* Lock calculator so we can directly access it from outside the core
133    thread. */
134 void tilem_calc_emulator_lock(TilemCalcEmulator *emu);
135 
136 /* Unlock calculator and allow emulation to continue. */
137 void tilem_calc_emulator_unlock(TilemCalcEmulator *emu);
138 
139 /* Load the calculator state from the given ROM file (and accompanying
140    sav file, if any.) */
141 gboolean tilem_calc_emulator_load_state(TilemCalcEmulator *emu,
142                                         const char *romfname,
143                                         const char *statefname,
144                                         int model, GError **err);
145 
146 /* Reload the calculator state from the most recently loaded file. */
147 gboolean tilem_calc_emulator_revert_state(TilemCalcEmulator *emu,
148                                           GError **err);
149 
150 /* Save the calculator state. */
151 gboolean tilem_calc_emulator_save_state(TilemCalcEmulator *emu,
152                                         GError **err);
153 
154 /* Reset the calculator. */
155 void tilem_calc_emulator_reset(TilemCalcEmulator *emu);
156 
157 /* Pause emulation (if currently running.) */
158 void tilem_calc_emulator_pause(TilemCalcEmulator *emu);
159 
160 /* Resume emulation (if currently paused.) */
161 void tilem_calc_emulator_run(TilemCalcEmulator *emu);
162 
163 /* Enable/disable speed limiting (TRUE means attempt to run at the
164    actual CPU speed; FALSE means run as fast as we can.) */
165 void tilem_calc_emulator_set_limit_speed(TilemCalcEmulator *emu,
166                                          gboolean limit);
167 
168 /* Enable/disable grayscale */
169 void tilem_calc_emulator_set_grayscale(TilemCalcEmulator *emu,
170                                        gboolean grayscale);
171 
172 /* Press a single key. */
173 void tilem_calc_emulator_press_key(TilemCalcEmulator *emu, int key);
174 
175 /* Release a single key. */
176 void tilem_calc_emulator_release_key(TilemCalcEmulator *emu, int key);
177 
178 /* Add keys to the input queue. */
179 void tilem_calc_emulator_queue_keys(TilemCalcEmulator *emu,
180                                     const byte *keys, int nkeys);
181 
182 /* Release final key in input queue. */
183 void tilem_calc_emulator_release_queued_key(TilemCalcEmulator *emu);
184 
185 /* If input queue is empty, press key immediately; otherwise, add to
186    the input queue.  Return TRUE if key was added to the queue. */
187 gboolean tilem_calc_emulator_press_or_queue(TilemCalcEmulator *emu, int key);
188 
189 /* Retrieve a static screenshot of current calculator screen.
190    Returned object has a reference count of 1 (free it with
191    g_object_unref().) */
192 TilemAnimation * tilem_calc_emulator_get_screenshot(TilemCalcEmulator *emu,
193                                                     gboolean grayscale);
194 
195 /* Begin recording an animated screenshot. */
196 void tilem_calc_emulator_begin_animation(TilemCalcEmulator *emu,
197                                          gboolean grayscale);
198 
199 /* Finish recording an animated screenshot.  Returned object has a
200    reference count of 1 (free it with g_object_unref().) */
201 TilemAnimation * tilem_calc_emulator_end_animation(TilemCalcEmulator *emu);
202 
203 /* Prompt for a ROM file to open */
204 int tilem_calc_emulator_prompt_open_rom(TilemCalcEmulator *emu);
205 
206 
207 /* Run slowly to play macro */
208 void run_with_key_slowly(TilemCalc* calc, int key);
209 
210 
211 /* Task handling */
212 
213 typedef gboolean (*TilemTaskMainFunc)(TilemCalcEmulator *emu, gpointer data);
214 typedef void (*TilemTaskFinishedFunc)(TilemCalcEmulator *emu, gpointer data,
215                                       gboolean cancelled);
216 
217 /* Add a task to the queue.  MAINF is a function to perform in the
218    core thread.  If it returns FALSE, all further tasks will be
219    cancelled.  Tasks can also be cancelled early by calling
220    tilem_calc_emulator_cancel_tasks().
221 
222    After the task finishes or is cancelled, FINISHEDF will be called
223    in the GUI thread.  Task-finished functions might not be called in
224    the same order the tasks were originally added to the queue. */
225 void tilem_calc_emulator_begin(TilemCalcEmulator *emu,
226                                TilemTaskMainFunc taskf,
227                                TilemTaskFinishedFunc finishedf,
228                                gpointer data);
229 
230 /* Cancel all pending tasks.  If a task is currently running, this
231    will attempt to cancel it and wait for it to exit. */
232 void tilem_calc_emulator_cancel_tasks(TilemCalcEmulator *emu);
233 
234 
235 /* Macros */
236 
237 /* Start to record a macro */
238 void tilem_macro_start(TilemCalcEmulator *emu);
239 
240 
241 /* Add an action to the macro */
242 void tilem_macro_add_action(TilemMacro* macro, int type, char * value);
243 
244 
245 /* Stop recording a macro */
246 void tilem_macro_stop(TilemCalcEmulator *emu);
247 
248 
249 /* Print the macro (debug) */
250 void tilem_macro_print(TilemMacro *macro);
251 
252 
253 /* Write a macro file */
254 void tilem_macro_write_file(TilemCalcEmulator *emu);
255 
256 
257 /* Play a macro (loaded or recorded before) */
258 void tilem_macro_play(TilemCalcEmulator *emu);
259 
260 
261 /* Load a macro from filename or if filename == NULL prompt user */
262 void tilem_macro_load(TilemCalcEmulator *emu, char* filename);
263 
264