mirror of
https://github.com/livingcomputermuseum/UniBone.git
synced 2026-01-13 23:35:42 +00:00
337 lines
9.8 KiB
C++
337 lines
9.8 KiB
C++
/* application.cpp: UniBone "demo" application, global resources
|
|
|
|
Copyright (c) 2018, Joerg Hoppe, j_hoppe@t-online.de, www.retrocmp.com
|
|
|
|
All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions
|
|
are met:
|
|
|
|
- Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
- Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
|
|
- Neither the name of the copyright holder nor the names of its
|
|
contributors may be used to endorse or promote products derived from
|
|
this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
|
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
12-nov-2018 JH entered beta phase
|
|
14-May-2018 JH created
|
|
|
|
*/
|
|
|
|
#define _MAIN_C_
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <time.h>
|
|
//#include <string.h>
|
|
//#include <stdint.h>
|
|
#include <unistd.h>
|
|
#include <limits.h>
|
|
//#include <errno.h>
|
|
//#include <ctype.h>
|
|
#include <stdarg.h>
|
|
#include <strings.h>
|
|
#include <string>
|
|
#include <iostream>
|
|
|
|
using namespace std;
|
|
|
|
#include "logsource.hpp"
|
|
#include "logger.hpp"
|
|
|
|
#include "getopt2.hpp"
|
|
#include "kbhit.h"
|
|
#include "inputline.hpp"
|
|
#include "pru.hpp"
|
|
#include "mailbox.h"
|
|
#include "gpios.hpp"
|
|
#include "memoryimage.hpp"
|
|
#include "iopageregister.h"
|
|
#include "panel.hpp"
|
|
#include "unibus.h"
|
|
#include "unibusadapter.hpp"
|
|
|
|
#include "logger.hpp"
|
|
#include "application.hpp" // own
|
|
|
|
// Singleton
|
|
application_c *app;
|
|
|
|
|
|
application_c::application_c() {
|
|
log_label = "APP";
|
|
}
|
|
|
|
/*
|
|
* help()
|
|
*/
|
|
void application_c::help() {
|
|
cout << "\n";
|
|
cout << "NAME\n";
|
|
cout << "\n";
|
|
cout << version << "\n";
|
|
cout << copyright << "\n";
|
|
cout << "\n";
|
|
cout << "SYNOPSIS\n";
|
|
cout << "\n";
|
|
cout << "TEST SETUP\n";
|
|
cout << " - UniBone must be plugged into SPC slots C-F on DD11-CK backplane.\n";
|
|
cout << " - 2 passive M903 terminators plugged into backplane.\n";
|
|
cout << " - Short cut BR4,5,6,NPR IN/OUT with jumpers.\n";
|
|
cout << " - Install the \"PRU\" device tree overlay:\n";
|
|
cout << " - cp UniBone-00B0.dtbo /lib/firmware UniBone-00B0.dtbo\n";
|
|
cout << " - reboot\n";
|
|
cout << "\n";
|
|
// cout << "Command line options are processed strictly left-to-right. \n\n");
|
|
// getopt must be initialized to print the syntax
|
|
getopt_parser.help(cout, opt_linewidth, 10, PROGNAME);
|
|
cout << "\n";
|
|
cout << "EXAMPLES\n";
|
|
cout << "\n";
|
|
cout << "sudo ./" PROGNAME "\n";
|
|
cout << " Show interactive menus.\n";
|
|
cout << "\n";
|
|
|
|
exit(1);
|
|
}
|
|
|
|
// show error for one option
|
|
void application_c::commandline_error() {
|
|
cerr << "Error while parsing command line:\n";
|
|
cerr << " " << getopt_parser.curerrortext.c_str() << "\n";
|
|
exit(1);
|
|
}
|
|
|
|
// parameter wrong for currently parsed option
|
|
void application_c::commandline_option_error(char *errtext, ...) {
|
|
char buffer[1024];
|
|
va_list args;
|
|
cerr << "Error while parsing commandline option:\n";
|
|
if (errtext) {
|
|
va_start(args, errtext);
|
|
vsprintf(buffer, errtext, args);
|
|
cerr << buffer << "\nSyntax: ";
|
|
va_end(args);
|
|
} else
|
|
cerr << " " << getopt_parser.curerrortext << "\nSyntax: ";
|
|
getopt_parser.help_option(cerr, 96, 10);
|
|
exit(1);
|
|
}
|
|
|
|
/* check whether the given device parameter configuration
|
|
* my cause problems.
|
|
*/
|
|
|
|
/*
|
|
* read commandline parameters into global "param_" vars
|
|
* result: 0 = OK, 1 = error
|
|
*/
|
|
void application_c::parse_commandline(int argc, char **argv) {
|
|
int res;
|
|
|
|
// define commandline syntax
|
|
getopt_parser.init(/*ignore_case*/1);
|
|
|
|
// getopt_def(&getopt_parser, NULL, NULL, "hostname", NULL, NULL, "Connect to the Blinkenlight API server on <hostname>\n"
|
|
// "<hostname> may be numerical or ar DNS name",
|
|
// "127.0.0.1", "connect to the server running on the same machine.",
|
|
// "raspberrypi", "connected to a RaspberryPi with default name.");
|
|
|
|
// !!!1 Do not define any defaults... else these will be set very time!!!
|
|
|
|
getopt_parser.ignore_case = 1;
|
|
getopt_parser.define("?", "help", "", "", "", "Print help.", "", "", "", "");
|
|
getopt_parser.define("v", "verbose", "", "", "", "Print info about operation.", "", "", "",
|
|
"");
|
|
getopt_parser.define("dbg", "debug", "", "", "", "Print debug messages.\n"
|
|
// getopt_parser.define("dbg", "debug", "", "channelmask", "",
|
|
// "Print debug messages. Optional reduces to channels wit <channelmask>.\n"
|
|
"Outputfile is \"unibone.log\"", "", "", "", "");
|
|
getopt_parser.define("cf", "cmdfile", "cmdfilename", "", "",
|
|
"File from which commands are read.\n"
|
|
"Lines are processed as if typed in.", "testseq",
|
|
"read commands from file \"testseq\" and execute line by line", "", "");
|
|
|
|
// test options
|
|
|
|
getopt_parser.define("t", "test", "iarg1,iarg2", "soptarg", "8 15",
|
|
"Tests the new c++ getop2.cpp\n"
|
|
"Multiline info, fix and optional args, short and long examples", "1,2",
|
|
"simple sets both mandatory int args", "1 2 hello",
|
|
"Sets integer args and option string arg");
|
|
// if (argc < 2)
|
|
// help(); // at least 1 required
|
|
logger->default_level = LL_WARNING;
|
|
res = getopt_parser.first(argc, argv);
|
|
while (res > 0) {
|
|
if (getopt_parser.isoption("help")) {
|
|
help();
|
|
} else if (getopt_parser.isoption("verbose")) {
|
|
logger->default_level = LL_INFO;
|
|
} else if (getopt_parser.isoption("debug")) {
|
|
logger->default_level = LL_DEBUG;
|
|
} else if (getopt_parser.isoption("cmdfile")) {
|
|
if (getopt_parser.arg_s("cmdfilename", opt_cmdfilename) < 0)
|
|
commandline_option_error(NULL);
|
|
} else if (getopt_parser.isoption("test")) {
|
|
int i1, i2;
|
|
string s;
|
|
if (getopt_parser.arg_i("iarg1", &i1) < 0)
|
|
commandline_option_error(NULL);
|
|
if (getopt_parser.arg_i("iarg2", &i2) < 0)
|
|
commandline_option_error(NULL);
|
|
cout << "iarg1=" << i1 << ", iarg2=" << i2;
|
|
if (getopt_parser.arg_s("soptarg", s))
|
|
cout << ", soptarg=" << s;
|
|
cout << "\n";
|
|
}
|
|
res = getopt_parser.next();
|
|
}
|
|
if (res == GETOPT_STATUS_MINARGCOUNT || res == GETOPT_STATUS_MAXARGCOUNT)
|
|
// known option, but wrong number of arguments
|
|
commandline_option_error(NULL);
|
|
else if (res < 0)
|
|
commandline_error();
|
|
}
|
|
|
|
// configure all hardware related subsystems:
|
|
// PRU, shard memory, GPIOs
|
|
void application_c::hardware_startup(enum pru_c::prucode_enum prucode_id) {
|
|
INFO("Connecting to PRU.");
|
|
/* initialize the library, PRU and interrupt; launch our PRU program */
|
|
|
|
pru->start(prucode_id);
|
|
mailbox_connect();
|
|
|
|
INFO("Registering non-PRU pins.");
|
|
gpios->init();
|
|
INFO("Disable DS8641 drivers.");
|
|
buslatches_output_enable(0);
|
|
INFO("Leave SYSBOOT mode.");
|
|
GPIO_SETVAL(gpios->reg_enable, 1);
|
|
// input registers can now be read
|
|
|
|
INFO("Registering multiplex bus latches, initialized later by PRU code.");
|
|
// INFO("Setup bus multiplex latches.");
|
|
buslatches_register();
|
|
|
|
INFO("Initializing device register maps.");
|
|
iopageregisters_init();
|
|
}
|
|
|
|
|
|
// disable all hardware related subsystems:
|
|
void application_c::hardware_shutdown() {
|
|
pru->stop();
|
|
}
|
|
|
|
int application_c::run(int argc, char *argv[]) {
|
|
void error_clear(void);
|
|
|
|
opt_linewidth = 80;
|
|
/* Intializes random number generator */
|
|
{
|
|
time_t t;
|
|
srand((unsigned) time(&t));
|
|
}
|
|
|
|
// returns only if everything is OK
|
|
// Std options already executed
|
|
parse_commandline(argc, argv);
|
|
|
|
logger->reset_log_levels(); // logger.default_level maybe info or debug
|
|
logger->life_level = LL_INFO; // show message up to this level immediately on console
|
|
//logger->life_level = LL_DEBUG; // show message up to this level immediately on console
|
|
logger->default_filepath = "unibone.log.csv";
|
|
|
|
// Test messages: visible if -verbose, -debug set.
|
|
INFO("Printing verbose output.");
|
|
DEBUG("Printing DEBUG output. Log file = \"%s\"", logger->default_filepath.c_str());
|
|
|
|
/* prussdrv_init() will segfault if called with EUID != 0 */
|
|
if (geteuid()) {
|
|
FATAL("%s must be run as root to use prussdrv\n", argv[0]);
|
|
}
|
|
|
|
inputline.init();
|
|
if (!opt_cmdfilename.empty()) {
|
|
// read commands from file
|
|
if (!inputline.openfile((char*) opt_cmdfilename.c_str())) {
|
|
printf("%s\n",
|
|
fileErrorText("Could not open command file \"%s\"",
|
|
opt_cmdfilename.c_str()));
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
cout << version << "\n";
|
|
|
|
// Multiplex latches are intialized by PRU code after each code download
|
|
INFO("Registering Non-PRU GPIO pins.");
|
|
gpios->init();
|
|
INFO("Disable DS8641 UNIBUS drivers.");
|
|
buslatches_output_enable(0);
|
|
INFO("Leave SYSBOOT mode.");
|
|
GPIO_SETVAL(gpios->reg_enable, 1);
|
|
// input registers can now be read
|
|
|
|
menu_main();
|
|
|
|
// hardware_shutdown();
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* construct all singletons in proper order
|
|
*/
|
|
static void factory() {
|
|
// logger first, all logsource_c connect to it.
|
|
logger = new logger_c();
|
|
|
|
pru = new pru_c();
|
|
gpios = new gpios_c();
|
|
unibus_signals = new unibus_signals_c();
|
|
ddrmem = new ddrmem_c();
|
|
|
|
// paneldriver before all devices who use lamps or buttons
|
|
paneldriver = new paneldriver_c();
|
|
|
|
membuffer = new memoryimage_c();
|
|
|
|
unibus = new unibus_c();
|
|
// unibusadapter.worker() needs initialized mailbox
|
|
unibusadapter = new unibusadapter_c();
|
|
|
|
app = new application_c();
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
|
|
// flush stuff on stdin. (Eclipse remote debugging)
|
|
while (os_kbhit())
|
|
;
|
|
|
|
factory();
|
|
return app->run(argc, argv);
|
|
}
|
|
|