2022-03-24 13:41:22 +01:00
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <signal.h>
|
2015-07-26 11:16:05 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/time.h>
|
2022-03-24 13:41:22 +01:00
|
|
|
#include <unistd.h>
|
2023-05-04 15:53:39 +02:00
|
|
|
#include <langinfo.h>
|
|
|
|
#include <locale.h>
|
2015-07-26 11:16:05 +02:00
|
|
|
|
2023-09-13 12:21:08 +02:00
|
|
|
#include <getopt.h>
|
|
|
|
|
2023-09-07 14:51:31 +02:00
|
|
|
#include "options.h"
|
2022-03-24 13:41:22 +01:00
|
|
|
#include "hp48.h"
|
2023-05-04 15:53:39 +02:00
|
|
|
#include "x48.h"
|
2015-07-26 11:16:05 +02:00
|
|
|
|
2023-04-27 12:15:59 +02:00
|
|
|
void signal_handler( int sig ) {
|
|
|
|
switch ( sig ) {
|
|
|
|
case SIGALRM:
|
|
|
|
got_alarm = 1;
|
|
|
|
break;
|
|
|
|
case SIGPIPE:
|
2023-09-13 15:07:31 +02:00
|
|
|
exit_emulator();
|
2023-04-27 12:15:59 +02:00
|
|
|
exit( 0 );
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2015-07-26 11:16:05 +02:00
|
|
|
}
|
|
|
|
|
2023-09-13 12:21:08 +02:00
|
|
|
int parse_args( int argc, char* argv[] ) {
|
|
|
|
int option_index;
|
|
|
|
char c = '?';
|
|
|
|
|
2023-09-13 15:07:31 +02:00
|
|
|
char* optstring = "c:r:S:hvVtsiRT";
|
2023-09-13 12:21:08 +02:00
|
|
|
static struct option long_options[] = {
|
|
|
|
{ "config-dir", required_argument, NULL, 'c' },
|
|
|
|
{ "rom", required_argument, NULL, 'r' },
|
|
|
|
{ "serial-line", required_argument, NULL, 'S' },
|
|
|
|
|
|
|
|
{ "help", no_argument, NULL, 'h' },
|
|
|
|
{ "version", no_argument, NULL, 'v' },
|
|
|
|
{ "verbose", no_argument, NULL, 'V' },
|
|
|
|
|
|
|
|
{ "use-terminal", no_argument, NULL, 't' },
|
|
|
|
{ "use-serial", no_argument, NULL, 's' },
|
|
|
|
|
|
|
|
{ "initialize", no_argument, NULL, 'i' },
|
|
|
|
{ "reset", no_argument, NULL, 'R' },
|
|
|
|
{ "throttle", no_argument, NULL, 'T' },
|
|
|
|
|
|
|
|
{ 0, 0, 0, 0 } };
|
|
|
|
|
|
|
|
char* help_text =
|
2023-09-13 15:07:31 +02:00
|
|
|
"x48ng [options]\n"
|
2023-09-13 12:21:08 +02:00
|
|
|
"\t-h --help :\n\t\t what you are reading\n"
|
|
|
|
"\t-v --version :\n\t\t show version\n"
|
|
|
|
"\t-c<path> --config-dir=<path> :\n\t\t use <path> as x48ng's home\n"
|
|
|
|
"\t-r<filename> --rom=<filename> :\n\t\t use <filename> as ROM\n"
|
|
|
|
"\t-S<path> --serial-line=<path> :\n\t\t use <path> as serial device\n"
|
|
|
|
"\t-V --verbose :\n\t\t be verbose\n"
|
|
|
|
"\t-t --use-terminal\n"
|
|
|
|
"\t-s --use-serial\n"
|
2023-09-13 13:11:52 +02:00
|
|
|
"\t-i --initialize :\n\t\t initialize the config and content of "
|
|
|
|
"x48ng's home\n"
|
2023-09-13 12:21:08 +02:00
|
|
|
"\t-R --reset\n"
|
2023-09-13 13:11:52 +02:00
|
|
|
"\t-T --throttle :\n\t\t try to emulate real speed\n";
|
2023-09-13 12:21:08 +02:00
|
|
|
|
|
|
|
while ( c != EOF ) {
|
|
|
|
c = getopt_long( argc, argv, optstring, long_options, &option_index );
|
|
|
|
|
|
|
|
switch ( c ) {
|
|
|
|
case 'c':
|
|
|
|
homeDirectory = optarg;
|
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
romFileName = optarg;
|
|
|
|
break;
|
|
|
|
case 'S':
|
|
|
|
serialLine = optarg;
|
|
|
|
break;
|
|
|
|
case 'h':
|
|
|
|
fprintf( stdout, "%s", help_text );
|
|
|
|
exit( 0 );
|
|
|
|
break;
|
|
|
|
case 'v':
|
2023-09-13 13:11:52 +02:00
|
|
|
fprintf( stdout, "\nx48ng %d.%d.%d", VERSION_MAJOR,
|
|
|
|
VERSION_MINOR, PATCHLEVEL );
|
|
|
|
|
|
|
|
fprintf( stdout, "\n\
|
|
|
|
COPYRIGHT\n\
|
|
|
|
\n\
|
|
|
|
x48ng is an Emulator for the HP-48 Handheld Calculator.\n\
|
|
|
|
\n\
|
|
|
|
This program is free software; you can redistribute it and/or modify\n\
|
|
|
|
it under the terms of the GNU General Public License as published by\n\
|
|
|
|
the Free Software Foundation; either version 2 of the License, or\n\
|
|
|
|
(at your option) any later version.\n\
|
|
|
|
\n\
|
|
|
|
This program is distributed in the hope that it will be useful,\n\
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\
|
|
|
|
GNU General Public License for more details.\n\
|
|
|
|
\n\
|
|
|
|
You should have received a copy of the GNU General Public License\n\
|
|
|
|
along with this program; if not, write to the Free Software\n\
|
|
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n" );
|
|
|
|
|
|
|
|
fprintf( stdout, "\n\
|
|
|
|
NO WARRANTY\n\
|
|
|
|
\n\
|
|
|
|
BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n\
|
|
|
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n\
|
|
|
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n\
|
|
|
|
PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n\
|
|
|
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n\
|
|
|
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n\
|
|
|
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n\
|
|
|
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n\
|
|
|
|
REPAIR OR CORRECTION.\n\
|
|
|
|
\n\
|
|
|
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n\
|
|
|
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n\
|
|
|
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n\
|
|
|
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n\
|
|
|
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n\
|
|
|
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n\
|
|
|
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n\
|
|
|
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n\
|
|
|
|
POSSIBILITY OF SUCH DAMAGES.\n\n" );
|
2023-09-13 12:21:08 +02:00
|
|
|
break;
|
|
|
|
case 'V':
|
|
|
|
verbose = 1;
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
useTerminal = 1;
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
useSerial = 1;
|
|
|
|
break;
|
|
|
|
case 'i':
|
|
|
|
initialize = 1;
|
|
|
|
break;
|
|
|
|
case 'R':
|
|
|
|
resetOnStartup = 1;
|
|
|
|
break;
|
|
|
|
case 'T':
|
|
|
|
throttle = 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '?':
|
|
|
|
case ':':
|
|
|
|
exit( 0 );
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( optind < argc ) {
|
2023-09-13 13:11:52 +02:00
|
|
|
fprintf( stderr, "Invalid arguments : " );
|
2023-09-13 12:21:08 +02:00
|
|
|
while ( optind < argc )
|
2023-09-13 13:11:52 +02:00
|
|
|
fprintf( stderr, "%s\n", argv[ optind++ ] );
|
|
|
|
fprintf( stderr, "\n" );
|
2023-09-13 12:21:08 +02:00
|
|
|
}
|
|
|
|
|
2023-09-13 15:07:31 +02:00
|
|
|
if ( verbose ) {
|
|
|
|
fprintf( stderr, "verbose = %i\n", verbose );
|
|
|
|
fprintf( stderr, "useTerminal = %i\n", useTerminal );
|
|
|
|
fprintf( stderr, "useSerial = %i\n", useSerial );
|
|
|
|
fprintf( stderr, "throttle = %i\n", throttle );
|
|
|
|
fprintf( stderr, "initialize = %i\n", initialize );
|
|
|
|
fprintf( stderr, "resetOnStartup = %i\n", resetOnStartup );
|
|
|
|
|
|
|
|
fprintf( stderr, "serialLine = %s\n", serialLine );
|
|
|
|
fprintf( stderr, "romFileName = %s\n", romFileName );
|
|
|
|
fprintf( stderr, "homeDirectory = %s\n", homeDirectory );
|
|
|
|
}
|
|
|
|
|
2023-09-13 12:21:08 +02:00
|
|
|
return ( optind );
|
|
|
|
}
|
|
|
|
|
2023-04-27 12:15:59 +02:00
|
|
|
int main( int argc, char** argv ) {
|
|
|
|
setlocale( LC_ALL, "C" );
|
|
|
|
|
2023-09-13 12:21:08 +02:00
|
|
|
/**********/
|
|
|
|
/* getopt */
|
|
|
|
/**********/
|
|
|
|
parse_args( argc, argv );
|
|
|
|
|
2023-04-27 12:15:59 +02:00
|
|
|
/*
|
|
|
|
* initialize emulator stuff
|
|
|
|
*/
|
2023-05-16 16:48:55 +02:00
|
|
|
init_emulator();
|
2023-05-09 14:48:24 +02:00
|
|
|
|
2023-09-13 15:07:31 +02:00
|
|
|
serial_init();
|
|
|
|
|
|
|
|
// SDL Initialization
|
|
|
|
SDLInit();
|
|
|
|
|
2023-04-27 12:15:59 +02:00
|
|
|
/*
|
|
|
|
* Create the HP-48 window
|
|
|
|
*/
|
2023-04-30 15:14:17 +02:00
|
|
|
SDLCreateHP();
|
2023-04-27 12:15:59 +02:00
|
|
|
|
2023-05-05 08:59:14 +02:00
|
|
|
init_display();
|
2023-05-04 16:06:57 +02:00
|
|
|
|
2023-05-16 16:48:55 +02:00
|
|
|
/*****************************************/
|
|
|
|
/* handlers for SIGALRM, SIGINT, SIGPIPE */
|
|
|
|
/*****************************************/
|
|
|
|
sigset_t set;
|
|
|
|
struct sigaction sa;
|
2023-04-27 12:15:59 +02:00
|
|
|
sigemptyset( &set );
|
|
|
|
sigaddset( &set, SIGALRM );
|
|
|
|
sa.sa_handler = signal_handler;
|
|
|
|
sa.sa_mask = set;
|
2015-07-26 11:16:05 +02:00
|
|
|
#ifdef SA_RESTART
|
2023-04-27 12:15:59 +02:00
|
|
|
sa.sa_flags = SA_RESTART;
|
2015-07-26 11:16:05 +02:00
|
|
|
#endif
|
2023-04-27 12:15:59 +02:00
|
|
|
sigaction( SIGALRM, &sa, ( struct sigaction* )0 );
|
|
|
|
|
|
|
|
sigemptyset( &set );
|
|
|
|
sigaddset( &set, SIGPIPE );
|
|
|
|
sa.sa_handler = signal_handler;
|
|
|
|
sa.sa_mask = set;
|
2015-07-26 11:16:05 +02:00
|
|
|
#ifdef SA_RESTART
|
2023-04-27 12:15:59 +02:00
|
|
|
sa.sa_flags = SA_RESTART;
|
2015-07-26 11:16:05 +02:00
|
|
|
#endif
|
2023-04-27 12:15:59 +02:00
|
|
|
sigaction( SIGPIPE, &sa, ( struct sigaction* )0 );
|
|
|
|
|
2023-05-16 16:48:55 +02:00
|
|
|
/************************************/
|
|
|
|
/* set the real time interval timer */
|
|
|
|
/************************************/
|
|
|
|
struct itimerval it;
|
2023-04-30 15:14:17 +02:00
|
|
|
int interval = 20000;
|
2023-04-27 12:15:59 +02:00
|
|
|
it.it_interval.tv_sec = 0;
|
2023-04-30 15:14:17 +02:00
|
|
|
it.it_interval.tv_usec = interval;
|
2023-04-27 12:15:59 +02:00
|
|
|
it.it_value.tv_sec = 0;
|
2023-04-30 15:14:17 +02:00
|
|
|
it.it_value.tv_usec = interval;
|
2023-04-27 12:15:59 +02:00
|
|
|
setitimer( ITIMER_REAL, &it, ( struct itimerval* )0 );
|
|
|
|
|
2023-05-16 16:48:55 +02:00
|
|
|
/**********************************************************/
|
|
|
|
/* Set stdin flags to not include O_NDELAY and O_NONBLOCK */
|
|
|
|
/**********************************************************/
|
|
|
|
long flags;
|
2023-04-27 12:15:59 +02:00
|
|
|
flags = fcntl( STDIN_FILENO, F_GETFL, 0 );
|
|
|
|
flags &= ~O_NDELAY;
|
|
|
|
flags &= ~O_NONBLOCK;
|
|
|
|
fcntl( STDIN_FILENO, F_SETFL, flags );
|
|
|
|
|
2023-05-02 13:42:58 +02:00
|
|
|
/************************/
|
|
|
|
/* Start emulation loop */
|
|
|
|
/************************/
|
2023-04-27 12:15:59 +02:00
|
|
|
do {
|
2023-09-07 12:39:01 +02:00
|
|
|
emulate();
|
2023-04-27 12:15:59 +02:00
|
|
|
} while ( 1 );
|
2015-07-26 11:16:05 +02:00
|
|
|
|
2023-04-27 12:15:59 +02:00
|
|
|
return 0;
|
2015-07-26 11:16:05 +02:00
|
|
|
}
|