Added LICENSE and README
This commit is contained in:
parent
2f77975f65
commit
8dd29cfa95
|
@ -0,0 +1,20 @@
|
|||
Copyright 2018, Seth Morabito <web@loomcom.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,20 @@
|
|||
# GTK DMD 5620 Emulator
|
||||
|
||||
This is a GTK+ 3.0 implementation of an AT&T / Teletype DMD 5620 emulator.
|
||||
|
||||
## Status
|
||||
|
||||
Version: 0.1
|
||||
|
||||
This is an actively developed project, and is not ready for use yet.
|
||||
|
||||
## See Also
|
||||
|
||||
* [dmd_core](https://github.com/sethm/dmd_core): DMD 5620 core
|
||||
implementation library, used by this project.
|
||||
|
||||
## License
|
||||
|
||||
MIT license. See the file [LICENSE.md](LICENSE.md)
|
||||
|
||||
Copyright (c) 2018, Seth Morabito <web@loomcom.com>
|
92
src/dmd.c
92
src/dmd.c
|
@ -1,10 +1,17 @@
|
|||
#include <gtk/gtk.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <stdint.h>
|
||||
#include <pthread.h>
|
||||
|
||||
static cairo_surface_t *surface = NULL;
|
||||
static pthread_t dmd_thread;
|
||||
|
||||
uint8_t last_kb_char;
|
||||
uint8_t kb_pending = 0;
|
||||
volatile int dmd_thread_run = 1;
|
||||
|
||||
extern int dmd_init();
|
||||
extern int dmd_reset();
|
||||
|
@ -53,10 +60,7 @@ static void
|
|||
close_window(void)
|
||||
{
|
||||
printf("[close_window]\n");
|
||||
gtk_main_quit();
|
||||
if (surface) {
|
||||
cairo_surface_destroy(surface);
|
||||
}
|
||||
dmd_thread_run = 0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -82,9 +86,15 @@ long get_current_time_ms()
|
|||
return (s * 1000) + ms;
|
||||
}
|
||||
|
||||
static void
|
||||
refresh_display(GtkWidget *widget)
|
||||
static gboolean
|
||||
refresh_display(gpointer data)
|
||||
{
|
||||
GtkWidget *widget = (GtkWidget *)data;
|
||||
|
||||
if (widget == NULL || !GTK_IS_WIDGET(widget)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GdkPixbuf *pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
|
||||
TRUE,
|
||||
8,
|
||||
|
@ -132,6 +142,8 @@ refresh_display(GtkWidget *widget)
|
|||
cairo_destroy(cr);
|
||||
|
||||
gtk_widget_queue_draw(widget);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -148,24 +160,41 @@ button_press_event_cb(GtkWidget *widget, GdkEventButton *event, gpointer data)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
uint8_t last_kb_char;
|
||||
uint8_t kb_pending = 0;
|
||||
|
||||
static gboolean
|
||||
run_dmd(gpointer user_data)
|
||||
void *dmd_run(void *threadid)
|
||||
{
|
||||
for (int i = 0; i < 40000; i++) {
|
||||
long double steps = 0;
|
||||
int rs;
|
||||
struct timespec sleep_time_req, sleep_time_rem;
|
||||
|
||||
sleep_time_req.tv_sec = 0;
|
||||
sleep_time_req.tv_nsec = 10000000;
|
||||
|
||||
printf("[DMD thread starting]");
|
||||
dmd_init();
|
||||
dmd_reset();
|
||||
|
||||
while (dmd_thread_run) {
|
||||
dmd_step();
|
||||
|
||||
// Stop every once in a while to poll for I/O and idle.
|
||||
if (steps++ == 250000) {
|
||||
if (kb_pending && dmd_rx_keyboard(last_kb_char)) {
|
||||
printf("[DMD thread] Sent char 0x%02x\n", last_kb_char);
|
||||
kb_pending = 0;
|
||||
}
|
||||
|
||||
steps = 0;
|
||||
rs = nanosleep(&sleep_time_req, &sleep_time_rem);
|
||||
if (rs) {
|
||||
printf("[DMD thread] SLEEP FAILED. Result=%d\n", rs);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Poll.
|
||||
if (kb_pending && dmd_rx_keyboard(last_kb_char)) {
|
||||
printf("[run_dmd] Just sent char 0x%02x\n", last_kb_char);
|
||||
kb_pending = 0;
|
||||
}
|
||||
printf("[DMD thread exiting]\n");
|
||||
|
||||
refresh_display((GtkWidget *)user_data);
|
||||
return G_SOURCE_CONTINUE;
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -204,7 +233,7 @@ activate(GtkApplication *app, gpointer user_data)
|
|||
|
||||
gtk_container_add(GTK_CONTAINER(frame), drawing_area);
|
||||
|
||||
g_timeout_add(33, run_dmd, drawing_area);
|
||||
g_timeout_add(20, refresh_display, drawing_area);
|
||||
|
||||
/* Signals used to handle the backing surface */
|
||||
g_signal_connect(drawing_area, "draw",
|
||||
|
@ -241,11 +270,13 @@ main(int argc, char *argv[])
|
|||
|
||||
GtkApplication *app;
|
||||
int status;
|
||||
long thread_id;
|
||||
int rc;
|
||||
|
||||
dmd_init();
|
||||
dmd_reset();
|
||||
for (int i = 0; i < 1000000; i++) {
|
||||
dmd_step();
|
||||
rc = pthread_create(&dmd_thread, NULL, dmd_run, (void *)thread_id);
|
||||
if (rc) {
|
||||
printf("ERROR: Could not create main DMD cpu thread. Status=%d\n", rc);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
app = gtk_application_new("com.loomcom.dmd", G_APPLICATION_FLAGS_NONE);
|
||||
|
@ -253,6 +284,19 @@ main(int argc, char *argv[])
|
|||
|
||||
status = g_application_run(G_APPLICATION(app), argc, argv);
|
||||
|
||||
void *join_status;
|
||||
rc = pthread_join(dmd_thread, &join_status);
|
||||
if (rc) {
|
||||
printf("ERROR: Could not join thread. Status=%d\n", rc);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
printf("Main: DMD thread is done.\n");
|
||||
|
||||
/* if (surface) { */
|
||||
/* cairo_surface_destroy(surface); */
|
||||
/* } */
|
||||
|
||||
g_object_unref(app);
|
||||
|
||||
return status;
|
||||
|
|
Loading…
Reference in New Issue