new cmd line handling; try to fix event thread on mac

This commit is contained in:
Christopher A. Mosher 2022-12-04 22:45:35 -05:00
parent 3301251d90
commit e55e3f4c1d
10 changed files with 151 additions and 87 deletions

View File

@ -18,8 +18,12 @@
Created on December 3, 2022, 3:02 PM Created on December 3, 2022, 3:02 PM
*/ */
#include "config.h"
#include "E2wxApp.h" #include "E2wxApp.h"
#include "E2wxFrame.h" #include "E2wxFrame.h"
#include "emulator.h"
#include "gui.h"
#include "configep2.h"
#include <wx/app.h> #include <wx/app.h>
#include <wx/xrc/xmlres.h> #include <wx/xrc/xmlres.h>
#include <wx/fileconf.h> #include <wx/fileconf.h>
@ -35,6 +39,9 @@
#include <boost/date_time/posix_time/posix_time.hpp> #include <boost/date_time/posix_time/posix_time.hpp>
#include <wx/debugrpt.h> #include <wx/debugrpt.h>
#include <iostream> #include <iostream>
#include <thread>
#include <string>
#include <memory>
#include <algorithm> #include <algorithm>
@ -89,7 +96,9 @@ bool E2wxApp::OnInit() {
return false; return false;
} }
#ifdef wxUSE_ON_FATAL_EXCEPTION
wxHandleFatalExceptions(); wxHandleFatalExceptions();
#endif
wxStandardPaths& stdpaths = wxStandardPaths::Get(); wxStandardPaths& stdpaths = wxStandardPaths::Get();
//stdpaths.SetInstallPrefix("."); //stdpaths.SetInstallPrefix(".");
@ -135,6 +144,10 @@ bool E2wxApp::OnInit() {
StartSdlEpple2();
E2wxFrame *frame = new E2wxFrame(); E2wxFrame *frame = new E2wxFrame();
frame->DoInit(); frame->DoInit();
frame->Show(); frame->Show();
@ -144,6 +157,31 @@ bool E2wxApp::OnInit() {
return true; return true;
} }
static int run(const std::string config_file) {
std::unique_ptr<Emulator> emu(new Emulator());
Config cfg(config_file);
emu->config(cfg);
emu->init();
return emu->run();
}
void E2wxApp::StartSdlEpple2() {
std::cout << "starting sdl thread..." << std::endl;
this->thread_sdl = new std::thread(run, this->arg_configfile);
std::cout << "started sdl thread." << std::endl;
}
int E2wxApp::OnExit() {
std::cout << "stopping sdl thread..." << std::endl;
GUI::queueQuit();
this->thread_sdl->join();
std::cout << "exiting wx application..." << std::endl;
return 0;
}
void E2wxApp::OnFatalException() { void E2wxApp::OnFatalException() {
wxDebugReport report; wxDebugReport report;
report.AddAll(); report.AddAll();
@ -154,10 +192,33 @@ void E2wxApp::OnFatalException() {
} }
} }
int E2wxApp::OnExit() { static const wxCmdLineEntryDesc cmdLineDesc[] =
return 0; {
{ wxCMD_LINE_PARAM, NULL, NULL, "config file", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
wxCMD_LINE_DESC_END
};
void E2wxApp::OnInitCmdLine(wxCmdLineParser& parser) {
wxApp::OnInitCmdLine(parser);
parser.SetDesc(cmdLineDesc);
} }
bool E2wxApp::OnCmdLineParsed(wxCmdLineParser& parser) {
if (!wxApp::OnCmdLineParsed(parser)) {
return false;
}
const int n = parser.GetParamCount();
if (n <= 0) {
std::cout << "no config file specified on the command line; will use config file specified in user-preferences" << std::endl;
} else {
this->arg_configfile = parser.GetParam(0);
std::cout << "using config file specified on the command line: " << this->arg_configfile << std::endl;
}
return true;
}
const std::filesystem::path E2wxApp::GetLogFile() const { const std::filesystem::path E2wxApp::GetLogFile() const {

View File

@ -25,7 +25,10 @@
#ifndef WX_PRECOMP #ifndef WX_PRECOMP
#include <wx/wx.h> #include <wx/wx.h>
#endif #endif
#include <wx/app.h>
#include <wx/cmdline.h>
#include <wx/string.h> #include <wx/string.h>
#include <thread>
#include <filesystem> #include <filesystem>
#include <string> #include <string>
@ -37,9 +40,12 @@ class E2wxApp : public wxApp {
std::filesystem::path conffile; std::filesystem::path conffile;
std::filesystem::path confdir; std::filesystem::path confdir;
std::filesystem::path docsdir; std::filesystem::path docsdir;
std::string arg_configfile;
std::thread *thread_sdl;
const std::filesystem::path BuildLogFilePath() const; const std::filesystem::path BuildLogFilePath() const;
void InitBoostLog(); void InitBoostLog();
void StartSdlEpple2();
public: public:
E2wxApp(); E2wxApp();
@ -56,6 +62,8 @@ public:
virtual bool OnInit() override; virtual bool OnInit() override;
virtual int OnExit() override; virtual int OnExit() override;
virtual void OnFatalException() override; virtual void OnFatalException() override;
virtual void OnInitCmdLine(wxCmdLineParser& parser) override;
virtual bool OnCmdLineParsed(wxCmdLineParser& parser) override;
}; };
wxDECLARE_APP(E2wxApp); wxDECLARE_APP(E2wxApp);

View File

@ -21,14 +21,18 @@
#include "E2wxFrame.h" #include "E2wxFrame.h"
#include "E2wxApp.h" #include "E2wxApp.h"
#include "PreferencesDialog.h" #include "PreferencesDialog.h"
#include "gui.h"
#include <wx/persist/toplevel.h> #include <wx/persist/toplevel.h>
enum E2MenuID {
ID_MENUITEM_POWER = wxID_HIGHEST+1
};
wxBEGIN_EVENT_TABLE(E2wxFrame, wxFrame) wxBEGIN_EVENT_TABLE(E2wxFrame, wxFrame)
EVT_MENU(wxID_EXIT, E2wxFrame::OnExit) EVT_MENU(wxID_EXIT, E2wxFrame::OnExit)
EVT_MENU(wxID_PREFERENCES, E2wxFrame::OnPreferences) EVT_MENU(wxID_PREFERENCES, E2wxFrame::OnPreferences)
EVT_MENU(wxID_ABOUT, E2wxFrame::OnAbout) EVT_MENU(wxID_ABOUT, E2wxFrame::OnAbout)
EVT_MENU(ID_MENUITEM_POWER, E2wxFrame::OnTogglePower)
wxEND_EVENT_TABLE() wxEND_EVENT_TABLE()
@ -60,6 +64,10 @@ void E2wxFrame::InitMenuBar() {
menuBar->Append(menuEdit, "&Edit"); menuBar->Append(menuEdit, "&Edit");
menuEdit->Append(wxID_PREFERENCES); menuEdit->Append(wxID_PREFERENCES);
wxMenu *menuMachine = new wxMenu();
menuBar->Append(menuMachine, "&Machine");
menuMachine->Append(ID_MENUITEM_POWER, "Toggle Power");
wxMenu *menuHelp = new wxMenu(); wxMenu *menuHelp = new wxMenu();
menuBar->Append(menuHelp, "&Help"); menuBar->Append(menuHelp, "&Help");
menuHelp->Append(wxID_ABOUT); menuHelp->Append(wxID_ABOUT);
@ -94,3 +102,7 @@ void E2wxFrame::OnPreferences(wxCommandEvent& event) {
dlg->OnInit(); dlg->OnInit();
dlg->ShowModal(); dlg->ShowModal();
} }
void E2wxFrame::OnTogglePower(wxCommandEvent& event) {
GUI::queueTogglePower();
}

View File

@ -39,6 +39,7 @@ private:
void OnExit(wxCommandEvent& event); void OnExit(wxCommandEvent& event);
void OnPreferences(wxCommandEvent& event); void OnPreferences(wxCommandEvent& event);
void OnAbout(wxCommandEvent& event); void OnAbout(wxCommandEvent& event);
void OnTogglePower(wxCommandEvent& event);
void InitMenuBar(); void InitMenuBar();
void InitStatusBar(); void InitStatusBar();

View File

@ -204,21 +204,12 @@ void PreferencesDialog::OnTreeSelectionChanged(wxTreeEvent& evt) {
void PreferencesDialog::PreSelectUserConfigItemName(const std::filesystem::path& n) { void PreferencesDialog::PreSelectUserConfigItemName(const std::filesystem::path& n) {
CTRL(wxTreeCtrl, treItems); CTRL(wxTreeCtrl, treItems);
wxTreeItemId id = treItems->GetRootItem();
wxTreeItemIdValue ctx; wxTreeItemId i = treItems->GetRootItem();
wxTreeItemId i = treItems->GetFirstChild(id, ctx); while (i.IsOk() && treItems->GetItemText(i) != wxFileName::FileName(n.c_str()).GetName()) {
while (i.IsOk() && treItems->GetItemText(i) != wxT("user")) { i = treItems->GetNextVisible(i);
i = treItems->GetNextChild(id, ctx);
}
if (!i.IsOk()) {
return;
} }
id = i;
i = treItems->GetFirstChild(id, ctx);
while (i.IsOk() && treItems->GetItemText(i) != wxFileName::FileName(n.c_str()).GetName()) {
i = treItems->GetNextChild(id, ctx);
}
if (!i.IsOk()) { if (!i.IsOk()) {
return; return;
} }
@ -247,6 +238,7 @@ void PreferencesDialog::OnActive(wxCommandEvent& evt) {
const std::filesystem::path p = data->path(); const std::filesystem::path p = data->path();
wxString name = wxFileName::FileName(p.c_str()).GetName(); wxString name = wxFileName::FileName(p.c_str()).GetName();
this->active = name; this->active = name;
std::cout << "setting current active config file to: " << this->active << std::endl;
wxConfigBase::Get()->Write(wxT("/ActivePreferences/name"), this->active); wxConfigBase::Get()->Write(wxT("/ActivePreferences/name"), this->active);
BuildItemTree(); // invalidates "data" pointer variable BuildItemTree(); // invalidates "data" pointer variable
PreSelectUserConfigItemName(p); PreSelectUserConfigItemName(p);

View File

@ -15,8 +15,8 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef CONFIG_H #ifndef CONFIGEP2_H
#define CONFIG_H #define CONFIGEP2_H
#include <string> #include <string>
class Memory; class Memory;

View File

@ -25,9 +25,9 @@ help from John Morris, Tom Greene, Michael Guidero, and Lane Roathe.
Stepper motor has 2 cans each with a center-tapped coil, allowing Stepper motor has 2 cans each with a center-tapped coil, allowing
for current flow in one of either direction, causing a N/S or S/N for current flow in one of either direction, causing a N/S or S/N
polarity fo the top/bottom of the can. Each top/bottom has fingers polarity of the top/bottom of the can. Each top/bottom has fingers
bending down/up towards the center, the fingers from alternate surfaces bending down/up towards the center, the fingers from alternate surfaces
being interlased. These fingers transfer the polarity from the coil. being interlaced. These fingers transfer the polarity from the coil.
Example of coil-0, controlled by phases 0 and 2, Example of coil-0, controlled by phases 0 and 2,
the two possible energized states, N/S and S/N, the two possible energized states, N/S and S/N,
@ -134,7 +134,7 @@ But 7&1 is a special case (calculation-wise): since it's a circle, they
Adjacent fingers within a can are of reverse polarity, and are 4 positions apart. Adjacent fingers within a can are of reverse polarity, and are 4 positions apart.
Cans are offset from each other by 2 positions. Cans are offset from each other by 2 positions.
PH = phase 0-4 (on or off) PH = phase 0-3 (on or off)
CAN = can 0-1 (north, south, or off) CAN = can 0-1 (north, south, or off)
CAN0 = PH0+PH2 CAN0 = PH0+PH2
@ -288,6 +288,7 @@ int Disk2StepperMotor::magnetic_position() const {
return this->can_1.magnetic_position(); return this->can_1.magnetic_position();
} }
assert(false); assert(false);
return 0; // quell compiler warning "control reaches end of non-void function"
} }
void Disk2StepperMotor::tick() { void Disk2StepperMotor::tick() {

View File

@ -35,7 +35,41 @@ GUI::~GUI() {
SDL_Quit(); SDL_Quit();
} }
GUI::NotInitException::NotInitException() : static void pushSdlEvent(SDL_Event *e) {
runtime_error("Unable to initialize SDL") { const int r = SDL_PushEvent(e);
if (r < 0) {
std::cerr << "SDL reported error: " << SDL_GetError() << std::endl;
} else if (r == 0) {
std::cerr << "SDL filtered event, sorry" << std::endl;
} else if (r == 1) {
std::cerr << "Pushed event to SDL" << std::endl;
} else {
std::cerr << "SDL reported unexpected error code: " << r << std::endl;
}
}
void GUI::queueTogglePower() {
SDL_Event *e = new SDL_Event(); // note: creating struct on the stack doesn't seem to work
e->type = SDL_KEYDOWN;
e->key.keysym.sym = SDLK_F1;
pushSdlEvent(e);
delete e;
}
void GUI::queueQuit() {
SDL_Event *e = new SDL_Event();
e->type = SDL_KEYDOWN;
e->key.keysym.sym = SDLK_F9;
pushSdlEvent(e);
delete e;
}
GUI::NotInitException::NotInitException() : runtime_error("Unable to initialize SDL") {
SDL_GetError(); SDL_GetError();
} }
GUI::NotInitException::~NotInitException() {
}

View File

@ -20,19 +20,19 @@
#include <stdexcept> #include <stdexcept>
class GUI class GUI {
{
public: public:
GUI(); GUI();
~GUI(); virtual ~GUI();
class NotInitException : public std::runtime_error static void queueQuit();
{ static void queueTogglePower();
class NotInitException : public std::runtime_error {
public: public:
NotInitException(); NotInitException();
virtual ~NotInitException() throw () {} virtual ~NotInitException();
}; };
}; };
#endif #endif

View File

@ -15,81 +15,36 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <SDL.h>
#include "emulator.h"
#include "configep2.h"
#include "gui.h"
#include "e2const.h" #include "e2const.h"
#include "gui.h"
#include <wx/app.h> #include <wx/app.h>
#include <string>
#include <memory>
#include <stdexcept>
#include <iostream> #include <iostream>
#include <iomanip> #include <ostream>
#include <thread> #include <stdexcept>
#include <cstdio>
#include <cstddef>
static std::string parse_args(int argc, char* argv[]) {
if (argc > 2) {
throw std::runtime_error("usage: epple2 [config-file]" );
}
if (argc <= 1) {
return std::string();
}
return std::string(argv[1]);
}
static int run(const std::string config_file) {
GUI gui;
std::unique_ptr<Emulator> emu(new Emulator());
Config cfg(config_file);
emu->config(cfg);
emu->init();
return emu->run();
}
static void queueEmuQuit() {
SDL_Event f9;
f9.type = SDL_KEYDOWN;
f9.key.keysym.sym = SDLK_F9;
SDL_PushEvent(&f9);
}
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C"
#endif #endif
int main(int argc, char* argv[]) { int main(int argc, char *argv[]) {
setbuf(stdout, NULL); ::setbuf(::stdout, nullptr);
setbuf(stderr, NULL); ::setbuf(::stderr, nullptr);
int x = E2Const::test(); const int x = E2Const::test();
if (x != -1) { if (x != -1) {
std::cerr << x << std::endl; std::cerr << x << std::endl;
throw std::runtime_error("bad constant in e2const.h" ); throw std::runtime_error("bad constant in e2const.h" );
} }
const std::string config_file = parse_args(argc, argv); GUI gui;
wxEntry(argc, argv);
std::thread sdl_thread(run, config_file);
int none(0);
wxEntry(none, (char**)nullptr);
// Runs wxWidgets main event loop and waits for user to File/Exit.
queueEmuQuit();
sdl_thread.join();
return 0; return 0;
} }