This commit is contained in:
Alex Lin 2019-07-19 16:06:54 -05:00
commit 90c1564a0c
16 changed files with 706 additions and 240 deletions

View File

@ -60,6 +60,7 @@ sub read_files_to_process() {
# skip system headers that are missed by the compiler -MM flag
next if ( $word =~ /^\/usr\/include/ ) ;
next if ( $word =~ /^\/usr\/local\/include/ ) ;
# skip Trick headers
my $trick_home = $ENV{'TRICK_HOME'} ;

View File

@ -1,4 +0,0 @@
my_integ_loop.getIntegrator(trick.Runge_Kutta_2, 4);
trick.exec_set_terminate_time(300.0)

View File

@ -1,11 +0,0 @@
execfile("RUN_test/input.py")
# Disable real-time (if applicable)
trick.real_time_disable()
# Disable all GUIs
trick_sys.sched.set_freeze_command(False)
trick.remove_all_external_applications()
trick_utest.unit_tests.enable() ;
trick_utest.unit_tests.set_file_name( os.getenv("TRICK_HOME") + "/trick_test/SIM_ball_L1.xml" ) ;

View File

@ -1,141 +0,0 @@
/************************TRICK HEADER*************************
PURPOSE:
(This Trick header comment lists out simulation model file dependencies that are not c++.
The model files are complete relative path to the "C" file and not the object file as
in the source code comments. Multiple trick comments with multiple sets of
LIBRARY DEPENDENCIES are allowed in the S_define file.)
LIBRARY DEPENDENCIES:
(
)
DEFAULT DATA:
(
(BFORCE ball.force ball/L1/data/ball_force.d)
(BSTATE ball.state ball/L1/data/ball_state.d)
)
*************************************************************/
/*
* There are 2 types of include files in Trick 10 S_define files. The single "#"
* include files are processed with the S_define file is parsed. Therefore any files
* that are single "#" included will be processed by CP. Files with a single "#"
* usually include SimObject definitions and instantiations.
*
* Files with a double "##" are passed to S_source.hh. They are not processed by
* CP except for stripping a "#" and copying the resultant string to S_source.hh.
* files with a double "##" usually contain structure/class definitions of the models
* used in the simulation.
*/
/*
* default_trick_sys.sm contains the default Trick system SimObjects and instantiations.
* Users are free to include a different file that lists out a different set of
* system objects.
*/
#include "sim_objects/default_trick_sys.sm"
/*
* Header files that contain structure/class definitions are included using the
* double "##" notation.
*/
##include "ball/L1/include/ball_state.h"
##include "ball/L1/include/ball_force.h"
##include "ball/L1/include/ball_proto.h"
/*
* %header{ ... %} is a new feature in Trick 10 that copys user code to the S_source.hh
*/
%header{
/*
* Header files listed here will be included in S_source.hh but not be input processed.
* If the prototype file ball_proto.h was included here, the simulation would have
* compiled, but the ball routines would not be available in the input processor.
*/
// ##include "ball/L1/include/ball_proto.h"
%}
/*
* %{ ... %} contains user code that is copied into S_source.cpp
*/
%{
// This user code section is empty for this simulation
%}
/*
* sim_objects are defined and instantiated separately in Trick 10 S_define files.
* Each sim_object is a C++ class definition. Each sim_object class must inherit
* from "public Trick::SimObject" or another SimObject.
*
*/
class ballSimObject : public Trick::SimObject {
/*
* Data members and functions may be public or private. If members are
* labled private they will not be available in the input processor.
*/
public:
/*
* Model structures/classes are declared as member data in the SimObject
*/
BSTATE state ;
BFORCE force ;
Trick::Integrator* my_integ ;
/*
* Jobs are declared in the constructors of the SimObject. The job syntax is
* unchanged from Trick 07. The constructors may have arguments which may be
* used as job. state and force are zeroed out at construction time using the
* ballSimObject() constructor initializer list.
*/
ballSimObject() : state() , force() {
/*
* One of several ways to get default data into the simulation is to create
* default data class jobs. default_data class jobs are run before initialization
*/
// INITIALIZATION JOBS
("initialization") ball_state_init( &state ) ;
// EOM DERIVATIVE AND STATE INTEGRATION JOBS
("derivative") ball_force_field( &force, state.output.position ) ;
("derivative") ball_state_deriv( &state ) ;
("integration", &my_integ) trick_ret = ball_state_integ( &state ) ;
(10.0 , "scheduled") ball_print( &state ) ;
}
} ;
/*
* SimObjects are instantiated. SimObjects may be multiply instantiated.
*/
ballSimObject ball ;
collect ball.state.work.external_force = { ball.force.output.force[0] };
/*
* Integrate statements have an argument after the integrate keyword that
* specifies the name of the integrator SimObject. This name is accessible
* within the input processor.
*/
integrate my_integ_loop (0.01) ball;
#define NUM_VARIABLES 4 /* x,y position state and x,y velocity state */
/*
* All code listed in the create_connections routine is copied into S_source.cpp and is
* executed directly after simobject instantiations. This routine may be used to
* to connect data structures between SimObjects.
*/
void create_connections() {
// We can set a default integrator here. This can be overridden in the input file.
ball.my_integ = my_integ_loop.getIntegrator( Runge_Kutta_2, NUM_VARIABLES);
}

View File

@ -1,4 +0,0 @@
TRICK_CFLAGS += -I../models
TRICK_CXXFLAGS += -I../models

View File

@ -4,45 +4,85 @@
<title>WS Experiments</title>
</head>
<body>
<style>
table { border-collapse: collapse; width: 100%; }
th, td { text-align: left; padding: 8px; }
tr:nth-child(even){background-color: #f2f2f2}
th { background-color: #562399; color: white; }
</style>
<header>
</header>
<section>
</section>
<div class="variableDisplay"></div>
<table class="variables">
<tr>
<th>Variable</th>
<th>Value</th>
</tr>
</table>
<div id="output"></div>
<script type="text/javascript">
function log(s) {
var p = document.createElement("p");
p.style.wordWrap = "break-word";
p.textContent = s;
output.appendChild(p);
}
function sendMessage(msg) {
ws.send(msg);
log("Message sent");
//log("Sent : " + msg);
}
function log(s) {
var p = document.createElement("p");
p.style.wordWrap = "break-word";
p.textContent = s;
output.appendChild(p);
//console.log(s);
// Interface to Trick WebSocket Variable Server
function setPeriod(period) {
sendMessage(`{ "cmd" : "var_cycle", "period" : "${period}" }`);
}
function addVariable(v) {
sendMessage(`{ "cmd" : "var_add", "var_name" : "${v}" }`);
// create a row in the table that contains two <td>s, one for the var_name and one for its value.
let tr = document.createElement('tr');
let td1 = document.createElement('td');
td1.textContent = `${v}`;
let td2 = document.createElement('td');
td2.textContent = "";
td2.className = "values";
tr.appendChild(td1);
tr.appendChild(td2);
varTable.appendChild(tr);
}
var varTable = document.querySelector('table.variables');
var ws = new WebSocket("ws://localhost:8888", "myProtocol");
// Event handler for the WebSocket connection opening
// WebSocket Event Handlers
ws.onopen = function(e) {
log("Connection established");
sendMessage("Hello WebSocket Server from Browser Client!");
setPeriod(100);
addVariable("dyn.cannon.pos[0]");
addVariable("dyn.cannon.pos[1]");
addVariable("dyn.cannon.vel[0]");
addVariable("dyn.cannon.vel[1]");
addVariable("I.dont.exist");
sendMessage("{ \"cmd\" : \"var_unpause\" }");
};
// Event handler for receiving text messages
ws.onmessage = function(e) {
log(e.data);
//log("Recieved : " + e.data);
let msg = JSON.parse(e.data);
if (msg.msg_type == "values") {
let valueNodes = varTable.getElementsByClassName("values");
for (let i = 0; i < msg.values.length; i++ ) {
valueNodes[i].textContent = msg.values[i];
}
}
};
// Event handler for errors in the WebSocket object
ws.onerror = function(e) {
console.log("WebSocket Error: " , e);
//Custom function for handling errors
handleErrors(e);
};
// Event handler for closed connections
ws.onclose = function(e) {
console.log("Connection closed", e);
};

View File

@ -1,7 +1,7 @@
/*************************************************************************
PURPOSE: (Represent Websocket variable server connection.)
LIBRARY DEPENDENCIES:
( (../src/WSSession.cpp))
( (../src/WSSession.o))
**************************************************************************/
#ifndef WSSESSION_HH
#define WSSESSION_HH
@ -9,6 +9,7 @@ LIBRARY DEPENDENCIES:
#include <time.h>
#include <vector>
#include <mongoose.h>
#include "WSSessionVariable.hh"
inline uint64_t to_nanoseconds(struct timespec* t) {
return t->tv_sec * (uint64_t)1000000000L + t->tv_nsec;
@ -19,18 +20,23 @@ class WSsession {
public:
WSsession( struct mg_connection *c );
void setTimeInterval(unsigned int milliseconds);
void addVariable(const char* vname);
void addVariable(char* vname);
void sendValues();
void synchSend(); // This must be called at a frequency greater than or equal to the interval.
void pause();
void unpause();
int emitError(const char* fmt, ... );
static int bad_ref_int ;
private:
WSsession() {}
REF2* make_error_ref(const char* in_name);
struct mg_connection* connection;
std::vector<const char*> varNames;
std::vector<WSsessionVariable*> sessionVariables;
struct timespec lastTime;
struct timespec interval;
bool enabled;
};
#endif

View File

@ -0,0 +1,35 @@
/*************************************************************************
PURPOSE: (Represent Websocket variable server variable.)
LIBRARY DEPENDENCIES:
( (../src/WSSessionVariable.o))
**************************************************************************/
#ifndef WSSESSIONVARIABLE_HH
#define WSSESSIONVARIABLE_HH
#include <time.h>
#include <vector>
#include <mongoose.h>
#include <iostream>
#include <trick/reference.h>
#define MAX_ARRAY_LENGTH 4096
class WSsessionVariable {
public:
WSsessionVariable( REF2* variableType);
~WSsessionVariable();
const char* getName();
void write_value( std::ostream& chkpnt_os );
private:
WSsessionVariable() {}
REF2 *varInfo;
void *address;
int size;
void *buffer_in;
void *buffer_out;
bool deref;
};
#endif

View File

@ -0,0 +1,21 @@
/*************************************************************************
PURPOSE: (Represent Websocket variable server connection.)
LIBRARY DEPENDENCIES:
( (../src/WSSession.o))
**************************************************************************/
#ifndef SIMPLEJSON_HH
#define SIMPLEJSON_HH
#include <vector>
class Member {
public:
const char* key;
const char* valText;
int type;
Member(const char *k, const char *v, int t);
};
std::vector<Member*> parseJSON( const char *json_s);
#endif

View File

@ -1,4 +1,11 @@
#include "trick/memorymanager_c_intf.h"
#include "../include/WSSession.hh"
#include <sstream>
WSsession::WSsession( struct mg_connection *c ) {
connection = c;
@ -9,19 +16,109 @@ void WSsession::setTimeInterval(unsigned int milliseconds) {
interval.tv_sec = milliseconds / 1000;
interval.tv_nsec = (milliseconds % 1000) * 1000000L;
}
void WSsession::addVariable(const char* vname){
varNames.push_back(vname);
int WSsession::bad_ref_int = 0 ;
REF2* WSsession::make_error_ref(const char* in_name) {
REF2* new_ref;
new_ref = (REF2*)calloc(1, sizeof(REF2));
new_ref->reference = strdup(in_name) ;
new_ref->units = NULL ;
new_ref->address = (char *)&bad_ref_int ;
new_ref->attr = (ATTRIBUTES*)calloc(1, sizeof(ATTRIBUTES)) ;
new_ref->attr->type = TRICK_NUMBER_OF_TYPES ;
new_ref->attr->units = (char *)"--" ;
new_ref->attr->size = sizeof(int) ;
return new_ref;
}
void WSsession::sendValues() {
std::vector<const char*>::iterator it;
for (it = varNames.begin(); it != varNames.end(); it++ ) {
// ==================================================================
// FIXME: Get the values of the variables and send them to the client.
// Currently we just send the names for testing.
// ==================================================================
mg_send_websocket_frame(connection, WEBSOCKET_OP_TEXT, *it, strlen(*it));
//
// #include "trick/exec_proto.h"
// time = (double)exec_get_time_tics() / exec_get_time_tic_value() ;
//REF2* Trick::VariableServerThread::make_time_ref() {
// REF2* new_ref;
// new_ref = (REF2*)calloc(1, sizeof(REF2));
// new_ref->reference = strdup("time") ;
// new_ref->units = strdup("s") ;
// new_ref->address = (char *)&time ;
// new_ref->attr = (ATTRIBUTES*)calloc(1, sizeof(ATTRIBUTES)) ;
// new_ref->attr->type = TRICK_DOUBLE ;
// new_ref->attr->units = strdup("s") ;
// new_ref->attr->size = sizeof(double) ;
// return new_ref;
//}
#define MAX_MSG_SIZE 4096
int WSsession::emitError(const char* fmt, ... ) {
char errText[MAX_MSG_SIZE];
char msgText[MAX_MSG_SIZE];
va_list args;
errText[0]=0;
msgText[0]=0;
va_start(args, fmt);
(void) vsnprintf(errText, MAX_MSG_SIZE, fmt, args);
va_end(args);
sprintf(msgText, "{ \"msg_type\" : \"error\",\n"
" \"error\" : \"%s\"}\n", errText);
mg_send_websocket_frame(connection, WEBSOCKET_OP_TEXT, msgText, strlen(msgText));
return (0);
}
void WSsession::addVariable(char* vname){
REF2 * new_ref ;
// if ( strcmp(vname, "time") == 0 ) {
// new_ref = make_time_ref();
// } else {
new_ref = ref_attributes(vname) ;
// }
if ( new_ref == NULL ) {
emitError("Variable Server could not find variable %s.\n", vname);
new_ref = make_error_ref(vname);
} else if ( new_ref->attr ) {
if ( new_ref->attr->type == TRICK_STRUCTURED ) {
emitError("Variable Server: var_add cant add \"%s\" because its a composite variable.\n", vname);
free(new_ref);
new_ref = make_error_ref(vname);
} else if ( new_ref->attr->type == TRICK_STL ) {
emitError("Variable Server: var_add cant add \"%s\" because its an STL variable.\n", vname);
free(new_ref);
new_ref = make_error_ref(vname);
}
} else {
emitError("Variable Server: BAD MOJO - Missing ATTRIBUTES.");
free(new_ref);
new_ref = make_error_ref(vname);
}
if ( new_ref != NULL ) {
WSsessionVariable *sessionVariable = new WSsessionVariable( new_ref ) ;
sessionVariables.push_back( sessionVariable ) ;
}
}
void WSsession::sendValues() {
std::vector<WSsessionVariable*>::iterator it;
std::stringstream ss;
ss << "{ \"msg_type\" : \"values\",\n";
ss << " \"values\" : [\n";
for (it = sessionVariables.begin(); it != sessionVariables.end(); it++ ) {
if (it != sessionVariables.begin()) ss << ",\n";
(*it)->write_value(ss);
}
ss << "]}" << std::endl;
std::string tmp = ss.str();
const char * message = tmp.c_str();
mg_send_websocket_frame(connection, WEBSOCKET_OP_TEXT, message, strlen(message));
}
void WSsession::synchSend() { // This must be called at a frequency greater than or equal to the interval.
struct timespec now;
clock_gettime(CLOCK_MONOTONIC_RAW, &now);
@ -34,24 +131,3 @@ void WSsession::synchSend() { // This must be called at a frequency greater than
}
void WSsession::pause() { enabled = false;}
void WSsession::unpause() { enabled = true; }
// int main ( int argc, char* argv[]) {
// WSsessionMap wsmap;
// struct mg_connection *c
// WSsession* wsess = new WSsession(c);
// struct timespec nap, t2;
// nap.tv_sec = 0;
// nap.tv_nsec = 10000000L;
//
// wsess->setTimeInterval(500);
// wsess->addVariable("dyn.cannon.pos[0]");
// wsess->addVariable("dyn.cannon.pos[1]");
// wsess->unpause();
//
// while(1) {
// wsess->synchSend();
// if ( nanosleep(&nap, &t2) < 0) { return -1; };
// }
// return 0;
// }

View File

@ -0,0 +1,177 @@
#include "trick/memorymanager_c_intf.h" // for get_size.
#include "../include/WSSessionVariable.hh"
#include <math.h> // for fpclassify
#include <iomanip> // for setprecision
WSsessionVariable::WSsessionVariable(REF2 * ref ) {
varInfo = ref;
address = varInfo->address;
size = varInfo->attr->size ;
deref = false;
TRICK_TYPE string_type = varInfo->attr->type ;
if ( varInfo->num_index == varInfo->attr->num_index ) {
// single value
} else if ( varInfo->attr->index[varInfo->attr->num_index - 1].size != 0 ) {
// Constrained array
for ( int i = varInfo->attr->num_index-1; i > varInfo->num_index-1 ; i-- ) {
size *= varInfo->attr->index[i].size ;
}
} else {
// Unconstrained array
if ((varInfo->attr->num_index - varInfo->num_index) > 1 ) {
printf("Variable Server Error: var_add(%s) requests more than one dimension of dynamic array.\n", varInfo->reference);
printf("Data is not contiguous so returned values are unpredictable.\n") ;
}
if ( varInfo->attr->type == TRICK_CHARACTER ) {
string_type = TRICK_STRING ;
deref = true;
} else if ( varInfo->attr->type == TRICK_WCHAR ) {
string_type = TRICK_WSTRING ;
} else {
deref = true ;
size *= get_size((char*)address) ;
}
}
// handle strings: set a max buffer size, the copy size may vary so will be set in copy_sim_data
if (( string_type == TRICK_STRING ) || ( string_type == TRICK_WSTRING )) {
size = MAX_ARRAY_LENGTH ;
}
buffer_in = calloc( size, 1 ) ;
buffer_out = calloc( size, 1 ) ;
}
WSsessionVariable::~WSsessionVariable() {
if (buffer_in != NULL) free( buffer_in );
if (buffer_out != NULL) free( buffer_out );
if (varInfo != NULL) free( varInfo );
}
const char* WSsessionVariable::getName() {
return varInfo->reference;
}
static void write_quoted_str( std::ostream& os, const char* s) {
int ii;
int len = strlen(s);
os << "\"" ;
for (ii=0 ; ii<len ; ii++) {
switch ((s)[ii]) {
case '\n': os << "\\n"; break;
case '\t': os << "\\t"; break;
case '\b': os << "\\b"; break;
case '\"': os << "\\\""; break;
default : os << s[ii] ; break;
}
}
os << "\"" ;
}
void WSsessionVariable::write_value( std::ostream& outs ) {
switch(varInfo->attr->type) {
case TRICK_UNSIGNED_CHARACTER:
outs << std::dec << (int)*(unsigned char*)address ;
break;
case TRICK_BOOLEAN:
if (*(bool*)address) {
outs << "\"true\"" ;
} else {
outs << "\"false\"" ;
}
break;
case TRICK_CHARACTER:
if (isprint( *(char*)address) ) {
outs << "'" << *(char*)address << "'" ;
} else {
unsigned int ch = *(unsigned char*)address;
outs << "'\\x" << std::hex << ch << "'" ;
}
break;
case TRICK_WCHAR:
outs << std::dec << *(wchar_t*)address;
break;
case TRICK_SHORT:
outs << std::dec << *(short*)address;
break;
case TRICK_UNSIGNED_SHORT:
outs << std::dec << *(unsigned short*)address;
break;
case TRICK_INTEGER:
outs << std::dec << *(int*)address;
break;
case TRICK_UNSIGNED_INTEGER:
outs << std::dec << *(unsigned int*)address;
break;
case TRICK_LONG:
outs << std::dec << *(long*)address;
break;
case TRICK_UNSIGNED_LONG:
outs << std::dec << *(unsigned long*)address;
break;
case TRICK_FLOAT:
if (fpclassify( *(float*)address) != FP_NAN) {
outs << std::setprecision(8) << *(float*)address;
} else {
outs << "NAN";
}
break;
case TRICK_DOUBLE:
if (fpclassify( *(double*)address) != FP_NAN) {
outs << std::setprecision(16) << *(double*)address;
} else {
outs << "NAN";
}
break;
// case TRICK_BITFIELD: {
// int sbf = 0;
// src_addr = (char*)address + offset * (size_t)attr->size;
// if (attr->size == sizeof(int)) {
// sbf = extract_bitfield_any( *(int*)src_addr, attr->size, attr->index[0].start, attr->index[0].size);
// } else if (attr->size == sizeof(short)) {
// sbf = extract_bitfield_any( *(short*)src_addr, attr->size, attr->index[0].start, attr->index[0].size);
// } else if (attr->size == sizeof(char)) {
// sbf = extract_bitfield_any( *(char*)src_addr, attr->size, attr->index[0].start, attr->index[0].size);
// } else {
// message_publish(MSG_ERROR, "Checkpoint Agent INTERNAL ERROR:\n"
// "Unsupported bitfield size (%d) bytes.\n", attr->size) ;
// }
// outs << std::dec << sbf;
// } break;
// case TRICK_UNSIGNED_BITFIELD: {
// int bf = 0;
// src_addr = (char*)address + offset * (size_t)attr->size;
// if (attr->size == sizeof(int)) {
// bf = extract_unsigned_bitfield_any( *(unsigned int*)src_addr, attr->size, attr->index[0].start, attr->index[0].size);
// } else if (attr->size == sizeof(short)) {
// bf = extract_unsigned_bitfield_any( *(unsigned short*)src_addr, attr->size, attr->index[0].start, attr->index[0].size);
// } else if (attr->size == sizeof(char)) {
// bf = extract_unsigned_bitfield_any( *(unsigned char*)src_addr, attr->size, attr->index[0].start, attr->index[0].size);
// } else {
// message_publish(MSG_ERROR, "Checkpoint Agent INTERNAL ERROR:\n"
// "Unsupported bitfield size (%d) bytes.\n", attr->size) ;
// }
// outs << std::dec << bf;
// } break;
case TRICK_LONG_LONG:
outs << std::dec << *(long long*)address;
break;
case TRICK_UNSIGNED_LONG_LONG:
outs << std::dec << *(unsigned long long*)address;
break;
case TRICK_STRING:
write_quoted_str(outs, (*(std::string*)address).c_str());
break;
default:
outs << "\"Error\""; // ERROR
break;
}
}

View File

@ -1,7 +1,11 @@
/************************************************************************
PURPOSE: (Represent the state and initial conditions of an http server)
LIBRARY DEPENDENCIES:
((WSSession.o))
(
(WSSession.o)
(WSSessionVariable.o)
(simpleJSON.o)
)
**************************************************************************/
/*
Messages sent from Client to Server
@ -26,20 +30,16 @@ Messages sent from Server to Client
{ "msg_type" : "var_list"
"values" : []
}
LEXEMES:
{
}
"[^""]"
:
,
[0-9]+
}
*/
#include "../include/http_server.h"
#include <sstream>
#include <unistd.h>
#include <string.h>
//#include <glib.h>
//#include <json-glib/json-glib.h>
#include "../include/http_server.h"
#include "../include/WSSession.hh"
#include "../include/simpleJSON.hh"
#include "trick/VariableServer.hh"
extern Trick::VariableServer * the_vs ;
@ -92,7 +92,55 @@ void handle_HTTP_GET_alloc_info(struct mg_connection *nc, struct http_message *h
}
// =============================================================================
int handle_JSON_var_server_msg (WSsession* session, const char* client_msg) {
int status = 0;
std::vector<Member*> members = parseJSON(client_msg);
std::vector<Member*>::iterator it;
const char *cmd;
const char *var_name;
int period;
for (it = members.begin(); it != members.end(); it++ ) {
if (strcmp((*it)->key, "cmd") == 0) {
cmd = (*it)->valText;
} else if (strcmp((*it)->key, "var_name") == 0) {
var_name = (*it)->valText;
} else if (strcmp((*it)->key, "period") == 0) {
period = atoi((*it)->valText);
}
}
if (cmd == NULL) {
printf ("No \"cmd\" member found in client message.\n");
status = 1;
} else if (strcmp(cmd, "var_add") == 0) {
//const gchar* var_name = json_object_get_string_member( object, "var_name");
session->addVariable( strdup(var_name) );
printf("session->addVariable(\"%s\")\n", var_name);
} else if ( strcmp(cmd, "var_cycle") == 0 ) {
//int period = json_object_get_int_member( object, "period");
session->setTimeInterval(period);
printf("session->setTimeInterval(%d)\n", period);
} else if ( strcmp(cmd, "var_pause") == 0 ) {
session->pause();
printf("session->pause()\n");
} else if ( strcmp(cmd, "var_unpause") == 0 ) {
session->unpause();
printf("session->unpause()\n");
} else if ( strcmp(cmd, "var_send") == 0 ) {
//TODO
} else if ( strcmp(cmd, "var_clear") == 0 ) {
//TODO
} else if ( strcmp(cmd, "var_exit") == 0 ) {
//TODO
} else {
printf ("Unknown Command \"%s\".\n", cmd);
status = 1;
}
return status;
}
#define DEBUG
static struct mg_serve_http_opts http_server_options;
std::map<mg_connection*, WSsession*> wsSessionMap;
@ -102,26 +150,30 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
switch(ev) {
case MG_EV_WEBSOCKET_HANDSHAKE_DONE: {
#ifdef DEBUG
printf("DEBUG: Event MG_EV_WEBSOCKET_HANDSHAKE_DONE. nc = %p.\n", nc);
char * s = strndup(hm->uri.p, hm->uri.len);
printf("DEBUG: WS URI = \"%s\"\n", s);
#endif
WSsession* session = new WSsession(nc);
session->setTimeInterval(500); // TEMPORARY for development
session->addVariable("dyn.cannon.pos[0]");// TEMPORARY for development
session->addVariable("dyn.cannon.pos[1]");// TEMPORARY for development
session->unpause(); // TEMPORARY for development
wsSessionMap.insert( std::pair<mg_connection*, WSsession*>(nc, session) );
} break;
case MG_EV_WEBSOCKET_FRAME: {
printf("DEBUG: Event MG_EV_WEBSOCKET_FRAME. nc = %p.\n", nc);
// Process messages recieved from the (web browser) client.
struct websocket_message *wm = (struct websocket_message *) ev_data;
char* msg = strndup((char*)wm->data, wm->size);
#ifdef DEBUG
printf("DEBUG: Even t MG_EV_WEBSOCKET_FRAME: nc = %p message = %s\n", nc, msg);
#endif
if (nc->flags & MG_F_IS_WEBSOCKET) {
std::map<mg_connection*, WSsession*>::iterator iter;
// Find the session that goes with this connection.
iter = wsSessionMap.find(nc);
if (iter != wsSessionMap.end()) {
WSsession* session = iter->second;
handle_JSON_var_server_msg(session, msg);
}
}
free(msg);
} break;
@ -145,9 +197,6 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
}
} break;
case MG_EV_POLL: {
#ifdef DEBUG
printf("DEBUG: Event MG_EV_POLL. nc = %p.\n", nc);
#endif
if (nc->flags & MG_F_IS_WEBSOCKET) {
std::map<mg_connection*, WSsession*>::iterator iter;
// Find the session that goes with this connection.
@ -161,12 +210,10 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
case MG_EV_HTTP_REQUEST: {
#ifdef DEBUG
printf("DEBUG: Event MG_EV_HTTP_REQUEST.\n");
#endif
char * s = strndup(hm->uri.p, hm->uri.len);
#ifdef DEBUG
printf("DEBUG: URI = \"%s\"\n", s);
#endif
free(s);
#endif
if (has_prefix(&hm->uri, &api_prefix)) {
struct mg_str key;
key.p = hm->uri.p + api_prefix.len;
@ -202,7 +249,7 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
void* service_connections (void* arg) {
HTTP_Server *S = (HTTP_Server*)arg;
while (!S->shutting_down) {
mg_mgr_poll(&S->mgr, 1000);
mg_mgr_poll(&S->mgr, 50);
struct timespec nap, t2;
nap.tv_sec = 0;
nap.tv_nsec = 100000000L;

View File

@ -0,0 +1,215 @@
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include "../include/simpleJSON.hh"
class LexicalAnalyzer {
public:
enum Lexeme {
END_OF_INPUT,
ERROR,
LEFT_BRACE,
RIGHT_BRACE,
LEFT_SQUARE_BRACKET,
RIGHT_SQUARE_BRACKET,
COLON,
COMMA,
STRING,
INTEGER
};
LexicalAnalyzer(const char*);
int next_lexeme();
char* getLexText();
private:
const char * s;
const char * p;
const char * vs;
size_t vlen;
char getch();
void ungetch() ;
LexicalAnalyzer(){}
};
LexicalAnalyzer::LexicalAnalyzer(const char* str) {
s = str;
p = str;
vs = NULL;
vlen = 0;
}
char LexicalAnalyzer::getch() {
char ch;
if ((ch = *p) != 0) { p++; }
return ch;
}
void LexicalAnalyzer::ungetch() {
if (p > s) { p--; }
}
char* LexicalAnalyzer::getLexText() {
if (vlen > 0) {
return strndup(vs, vlen);
} else {
return NULL;
}
}
int LexicalAnalyzer::next_lexeme() {
int state = 0;
vlen = 0;
char ch;
while ((ch = getch()) != 0) {
switch (state) {
case 0 : { // Initial state.
if (ch == '{') {
return LEFT_BRACE ;
} else if (ch == '}') {
return RIGHT_BRACE ;
} else if (ch == '[') {
return LEFT_SQUARE_BRACKET ;
} else if (ch == ']') {
return RIGHT_SQUARE_BRACKET ;
} else if (ch == ':') {
return COLON ;
} else if (ch == ',') {
return COMMA ;
} else if ( ch == '"') {
state = 1;
vs = p;
} else if ( isdigit(ch) ) {
ungetch();
state = 2;
vs = p;
} else if (isspace(ch)) {
state = 0;
}
} break;
case 1 : { // String literal accumulation state.
while ((ch != 0 ) && (ch != '"'))
ch = getch();
if (ch == '"') {
vlen = p-vs-1 ;
return STRING ;
} else {
return ERROR ;
}
} break;
case 2 : { // Integer literal accumulation state.
while ((ch != 0 ) && (isdigit(ch)))
ch = getch();
vlen = p-vs-1;
return INTEGER ;
} break;
default:
return ERROR ;
}
}
return END_OF_INPUT;
}
const char *token_text(int token) {
const char *text;
switch (token) {
case LexicalAnalyzer::END_OF_INPUT : text = "END_OF_INPUT"; break;
case LexicalAnalyzer::ERROR : text = "ERROR"; break;
case LexicalAnalyzer::LEFT_BRACE : text = "LEFT_BRACE"; break;
case LexicalAnalyzer::RIGHT_BRACE : text = "RIGHT_BRACE"; break;
case LexicalAnalyzer::LEFT_SQUARE_BRACKET : text = "LEFT_SQUARE_BRACKET"; break;
case LexicalAnalyzer::RIGHT_SQUARE_BRACKET : text = "RIGHT_SQUARE_BRACKET"; break;
case LexicalAnalyzer::COLON : text = "COLON"; break;
case LexicalAnalyzer::COMMA : text = "COMMA"; break;
case LexicalAnalyzer::STRING : text = "STRING"; break;
case LexicalAnalyzer::INTEGER : text = "INTEGER"; break;
default : text = "**UNKNOWN**"; break;
}
return text;
}
Member::Member(const char *k, const char *v, int t) {
key=k;
valText=v;
type=t;
}
Member* parseJSON_member(LexicalAnalyzer &lexan) {
const char* key;
const char* valText;
int type;
int token;
token = lexan.next_lexeme();
if ( token == LexicalAnalyzer::STRING ) {
key = lexan.getLexText();
} else {
std::cout << "ERROR: Expected STRING. Found \"" << token_text(token) << "\"." << std::endl;
return NULL;
}
token = lexan.next_lexeme();
if ( token != LexicalAnalyzer::COLON ) {
std::cout << "ERROR: Expected COLON. Found \"" << token_text(token) << "\"." << std::endl;
token_text(token);
delete key;
return NULL;
}
token = lexan.next_lexeme();
if (( token == LexicalAnalyzer::STRING) || ( token == LexicalAnalyzer::INTEGER )) {
valText = lexan.getLexText();
type = token;
} else {
std::cout << "ERROR: Expected STRING or INTEGER. Found \"" << token_text(token) << "." << std::endl;
token_text(token);
return NULL;
}
Member *member = new Member(key, valText, type);
return member;
}
std::vector<Member*> parseJSON( const char *json_s) {
std::vector<Member*> members;
Member* member;
int token;
bool okiedokey = true;
LexicalAnalyzer lexan(json_s);
token = lexan.next_lexeme();
if ( token == LexicalAnalyzer::LEFT_BRACE ) {
member = parseJSON_member(lexan);
if (member != NULL) {
members.push_back(member);
token = lexan.next_lexeme();
while ( okiedokey && (token == LexicalAnalyzer::COMMA) ) {
member = parseJSON_member(lexan);
if (member != NULL) {
members.push_back(member);
} else {
okiedokey = false;
}
token = lexan.next_lexeme();
}
} else {
okiedokey = false;
}
if ( token != LexicalAnalyzer::RIGHT_BRACE ) {
std::cout << "ERROR: Expected RIGHT_BRACE. Found \"" << token_text(token) << "\"." << std::endl;
token_text(token);
okiedokey = false;
}
} else {
std::cout << "ERROR: Expected LEFT_BRACE. Found \"" << token_text(token) << "\"." << std::endl;
okiedokey = false;
}
if (okiedokey == false) {
std::vector<Member*>::iterator it;
it = members.begin();
while (it != members.end()) {
delete *it;
it = members.erase(it);
}
}
return members;
}

View File

@ -6,7 +6,6 @@ COMPILE_DIRS = \
Ball/SIM_ball_L1 \
Ball/SIM_ball_L2 \
Ball/SIM_ball_L3 \
Ball/SIM_ball_default_data \
Cannon/SIM_amoeba \
Cannon/SIM_cannon_aero \
Cannon/SIM_cannon_analytic \
@ -24,7 +23,6 @@ TEST_DIRS = \
Ball/SIM_ball_L1 \
Ball/SIM_ball_L2 \
Ball/SIM_ball_L3 \
Ball/SIM_ball_default_data \
Cannon/SIM_amoeba \
Cannon/SIM_cannon_aero \
Cannon/SIM_cannon_analytic \

View File

@ -172,6 +172,15 @@ int Trick::CommandLineArguments::process_sim_args(int nargs , char **args) {
}
}
if (access(input_file.c_str(), F_OK) != 0) {
input_file = "";
if(strcmp(argv[1], "trick_version") && strcmp(argv[1], "sie") && strcmp(argv[1], "-help") && strcmp(argv[1], "--help") &&
strcmp(argv[1], "-h") && strcmp(argv[1], "help")) {
std::cerr << "\nERROR: Invalid input file or command line argument." << std::endl;
exit(1);
}
}
found = run_dir.find_last_of("/") ;
if ( found != std::string::npos ) {
run_dir.erase(found) ;

View File

@ -64,6 +64,7 @@ int Trick::Executive::process_sim_args() {
} else if (!strcmp(argv[1], "-help") || !strcmp(argv[1], "--help") ||
!strcmp(argv[1], "-h") || !strcmp(argv[1], "help") ) {
/* Try and help the user */
printf("%s", buf);
exit(0);
} else if (!strcmp(argv[1], "sie")) {
/* do not create init_log.csv if we are generating sie */