This commit is contained in:
Alex Lin 2019-05-03 09:15:16 -05:00
commit 52b30d5e2c
15 changed files with 598 additions and 24 deletions

View File

@ -658,6 +658,9 @@ namespace Trick {
static void emitError( std::string s);
static void emitWarning( std::string s);
void write_JSON_alloc_info( std::ostream& s, ALLOC_INFO *alloc_info) ;
void write_JSON_alloc_list( std::ostream& s, int start_ix, int num) ;
private:
static int instance_count; /**< -- Number of instances of MemoryManager. Not allowed to exceed 1.*/

View File

@ -860,7 +860,7 @@ class VariableServer(object):
self.Channel.BOTH: [self._synchronous_socket,
self._asynchronous_socket]
}[channel]:
channel.sendall(command)
channel.sendall(command.encode())
def readline(self, synchronous_channel=True):
"""

View File

@ -9,8 +9,11 @@ LIBRARY DEPENDENCIES:
*************************************************************/
#include "sim_objects/default_trick_sys.sm"
##include "cannon/gravity/include/cannon_numeric.h"
// Uncomment to get a webserver. Also uncomment lines in S_overrise.mk to link in mongoose lib.
// #include "mongoose_httpd/mongoose_httpd.sm"
##include "cannon/gravity/include/cannon_numeric.h"
class CannonSimObject : public Trick::SimObject {
public:
@ -24,8 +27,6 @@ class CannonSimObject : public Trick::SimObject {
("dynamic_event") cannon_impact( &cannon) ;
}
} ;
// Instantiations
CannonSimObject dyn ;
IntegLoop dyn_integloop (0.01) dyn;

View File

@ -1,4 +1,6 @@
TRICK_CFLAGS += -I../models
TRICK_CFLAGS += -I../models
TRICK_CXXFLAGS += -I../models
TRICK_SFLAGS += -I../models
#TRICK_LDFLAGS += -L/usr/local/lib
#TRICK_USER_LINK_LIBS += -lmongoose

View File

@ -0,0 +1,156 @@
<!DOCTYPE html>
<html>
<head>
<title>Trick Memory Allocations</title>
</head>
<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>
<body>
<header>
</header>
<div class="trickMemoryAllocations">
</div>
<div class="navigation" style="background:#562399">
<button class="previous" style="font-size:20px" onClick="previous_page()">Previous</button>
<button class="next" style="font-size:20px" onClick="next_page()">Next</button>
<select id="countSelect" style="font-size:20px" onChange="updatePageWithSelectedCount()">
<option value="10" >10 per page</option>
<option value="20" >20 per page</option>
<option value="50" >50 per page</option>
<option value="100">100 per page</option>
</select>
</div>
<script type="text/javascript">
function showHeader(allocData) {
let para = document.createElement('p');
para.textContent = `URL: ${document.URL}`;
header.appendChild(para);
let label = document.createElement('h2');
label.textContent = 'Trick Memory Allocations';
header.appendChild(label);
}
function updateHeader(allocData) {
let first = allocData.chunk_start + 1;
let last = allocData.chunk_start + allocData.alloc_list.length;
let label = header.getElementsByTagName("h2")[0];
label.textContent = `Trick Memory Allocations (${first}..${last}) of ${allocData.alloc_total}`;
}
function createAllocInfoTable(allocData) {
let mytable = document.createElement('table');
let trow = document.createElement('tr');
let table_headings = ['Name', 'Address', 'Num', 'Size', 'Type Specifier', 'StorageClass'];
for (let i = 0; i < table_headings.length ; i++) {
let th = document.createElement('th');
th.textContent = table_headings[i];
trow.appendChild(th);
}
mytable.appendChild(trow);
for (let i = 0; i < allocData.alloc_list.length; i++) {
let trow = document.createElement('tr');
let td1 = document.createElement('td');
td1.textContent = allocData.alloc_list[i].name;
let td2 = document.createElement('td');
td2.textContent = allocData.alloc_list[i].start;
let td3 = document.createElement('td');
td3.textContent = allocData.alloc_list[i].num;
let td4 = document.createElement('td');
td4.textContent = allocData.alloc_list[i].size;
let td5 = document.createElement('td');
td5.textContent = allocData.alloc_list[i].type;
let td6 = document.createElement('td');
td6.textContent = allocData.alloc_list[i].stcl;
trow.appendChild(td1);
trow.appendChild(td2);
trow.appendChild(td3);
trow.appendChild(td4);
trow.appendChild(td5);
trow.appendChild(td6);
mytable.appendChild(trow);
}
return mytable;
}
function updateNavButtons(allocData) {
nextButton.style.opacity = "1.0"
if (allocData.chunk_start + allocData.chunk_size >= allocData.alloc_total) {
nextButton.style.opacity = "0.6";
}
prevButton.style.opacity = "1.0";
if (allocData.chunk_start - allocData.chunk_size < 0) {
prevButton.style.opacity = "0.6";
}
}
function updatePage(start, count) {
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == XMLHttpRequest.DONE && xhr.status == 200) {
allocData = JSON.parse(xhr.responseText);
let newTable = createAllocInfoTable(allocData);
let oldTable = trickMemoryAllocations.getElementsByTagName("table")[0];
trickMemoryAllocations.replaceChild(newTable, oldTable);
updateNavButtons(allocData);
updateHeader(allocData);
}
}
xhr.open('GET', `/api/v1/alloc_info?start=${start}&count=${count}`);
xhr.send(null);
}
function updatePageWithSelectedCount() {
let newCount = parseInt( document.getElementById("countSelect").value, 10);
updatePage(allocData.chunk_start, newCount);
}
function next_page() {
let nextStart = allocData.chunk_start + allocData.chunk_size;
if (nextStart < allocData.alloc_total) {
updatePage(nextStart, allocData.chunk_size);
}
}
function previous_page() {
if (allocData.chunk_start > 0) {
let prevStart = allocData.chunk_start - allocData.chunk_size;
if (prevStart < 0) prevStart = 0;
updatePage(prevStart, allocData.chunk_size);
}
}
var myOrigin = new URL(document.URL);
var header = document.querySelector('header');
var trickMemoryAllocations = document.querySelector('div.trickMemoryAllocations');
var prevButton = document.querySelector('button.previous');
var nextButton = document.querySelector('button.next');
var allocData;
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == XMLHttpRequest.DONE && xhr.status == 200) {
allocData = JSON.parse(xhr.responseText);
showHeader();
let allocInfoTable = createAllocInfoTable(allocData);
trickMemoryAllocations.appendChild(allocInfoTable);
updateNavButtons(allocData);
updateHeader(allocData);
}
}
xhr.open('GET', '/api/v1/alloc_info?start=0&count=10');
xhr.send(null);
</script>
</body>
</html>

View File

@ -0,0 +1,74 @@
<!DOCTYPE html>
<html>
<head>
<title>Variable Server Connections</title>
</head>
<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>
<body>
<header>
</header>
<section>
</section>
<script type="text/javascript">
function showHeader() {
let para = document.createElement('p');
para.textContent = `URL: ${document.URL}`;
header.appendChild(para);
let label = document.createElement('h2');
label.textContent = 'Variable Server Connections';
header.appendChild(label);
}
function showVSConnections(myObj) {
let mytable = document.createElement('table');
let trow = document.createElement('tr');
let table_headings = ['Name', 'Address', 'Port', 'Format', 'Rate'];
for (let i = 0; i < table_headings.length ; i++) {
let th = document.createElement('th');
th.textContent = table_headings[i];
trow.appendChild(th);
}
mytable.appendChild(trow);
for (let i = 0; i < myObj.variable_server_connections.length; i++) {
let trow = document.createElement('tr');
let td1 = document.createElement('td');
td1.textContent = myObj.variable_server_connections[i].connection.client_tag;
let td2 = document.createElement('td');
td2.textContent = myObj.variable_server_connections[i].connection.client_IP_address;
let td3 = document.createElement('td');
td3.textContent = myObj.variable_server_connections[i].connection.client_port;
let td4 = document.createElement('td');
td4.textContent = myObj.variable_server_connections[i].connection.format;
let td5 = document.createElement('td');
td5.textContent = myObj.variable_server_connections[i].connection.update_rate;
trow.appendChild(td1);
trow.appendChild(td2);
trow.appendChild(td3);
trow.appendChild(td4);
trow.appendChild(td5);
mytable.appendChild(trow);
}
section.appendChild(mytable);
}
var header = document.querySelector('header');
var section = document.querySelector('section');
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == XMLHttpRequest.DONE && xhr.status == 200) {
var myObj = JSON.parse(xhr.responseText);
showHeader();
showVSConnections(myObj);
}
}
xhr.open('GET', '/api/v1/vs_connections');
xhr.send(null);
</script>
</body>
</html>

View File

@ -0,0 +1,41 @@
<!DOCTYPE html>
<html>
<head>
<title>WS Experiments</title>
</head>
<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>
<body>
<header>
</header>
<section>
</section>
<script type="text/javascript">
var ws = new WebSocket("ws://localhost:8888", "myProtocol");
// Event handler for the WebSocket connection opening
ws.onopen = function(e) {
console.log("Connection established");
};
// Event handler for receiving text messages
ws.onmessage = function(e) {
console.log("Message received", e, e.data);
};
// 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);
};
</script>
</body>
</html>

View File

@ -0,0 +1,28 @@
<!DOCTYPE html>
<html>
<head>
<title>Trick Simulation Pages</title>
</head>
<body>
<div style="background:#efefff">
<h2>SIM_cannon_numeric</h2>
</div>
<div style="background:#efefef">
<ul>
<li><a href="http://github.com/nasa/trick">Trick on GitHub</a></li>
<li><a href="http://github.com/nasa/trick/wiki/Tutorial">Trick Tutorial</a></li>
<li><a href="http://github.com/nasa/trick/wiki/Documentation-Home">Trick Documentation</a></li>
</ul>
</div>
<div style="background:#efefef">
<ul>
<li><a href="/apps/vs_connections.html">Variable Server Connections</a></li>
<li><a href="/apps/alloc_info.html">Trick Memory Allocations</a></li>
</ul>
</div>
</body>
</html>

View File

@ -0,0 +1,35 @@
/*************************************************************************
PURPOSE: (Represent the state and initial conditions of an http server)
LIBRARY DEPENDENCIES:
( (../src/http_server.cpp))
**************************************************************************/
#ifndef HTTP_SERVER_H
#define HTTP_SERVER_H
#include <sys/types.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <mongoose.h>
#include <pthread.h>
typedef struct {
struct mg_mgr mgr; /* ** mongoose */
struct mg_connection *nc; /* ** mongoose */
const char* port;
pthread_t server_thread; /* ** */
bool shutting_down;
} HTTP_Server ;
#ifdef __cplusplus
extern "C" {
#endif
int http_default_data(HTTP_Server * S) ;
int http_init(HTTP_Server * S) ;
int http_shutdown(HTTP_Server * S) ;
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,21 @@
/************************TRICK HEADER*************************
PURPOSE:
(HTTP Server)
LIBRARY DEPENDENCIES:
((src/http_server.cpp))
*************************************************************/
##include "mongoose_httpd/include/http_server.h"
class HttpSimObject : public Trick::SimObject {
public:
HTTP_Server http_server ;
HttpSimObject() {
("default_data") http_default_data( &http_server ) ;
("initialization") http_init( &http_server ) ;
("shutdown") http_shutdown( &http_server ) ;
}
};
HttpSimObject http ;

View File

@ -0,0 +1,150 @@
/************************************************************************
PURPOSE: (Represent the state and initial conditions of an http server)
**************************************************************************/
#include "../include/http_server.h"
#include <sstream>
#include "trick/VariableServer.hh"
extern Trick::VariableServer * the_vs ;
#include "trick/MemoryManager.hh"
extern Trick::MemoryManager* trick_MM;
static const struct mg_str s_get_method = MG_MK_STR("GET");
static const struct mg_str s_put_method = MG_MK_STR("PUT");
static const struct mg_str s_delele_method = MG_MK_STR("DELETE");
int getIntegerQueryValue(struct http_message *hm, const char* key, int defaultVal) {
char value_text[100];
if ( mg_get_http_var(&(hm->query_string), key, value_text, sizeof(value_text)) > 0) {
return atoi(value_text);
} else {
return defaultVal;
}
}
void handle_vs_connections_call(struct mg_connection *nc, struct http_message *hm) {
/* Send headers */
mg_printf(nc, "%s", "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
std::stringstream ss;
ss << *the_vs << std::endl;
std::string tmp = ss.str();
mg_printf_http_chunk(nc, "%s", tmp.c_str());
mg_send_http_chunk(nc, "", 0);
}
void handle_alloc_info_call(struct mg_connection *nc, struct http_message *hm) {
int start = getIntegerQueryValue(hm, "start", 0);
int count = getIntegerQueryValue(hm, "count", 10);
mg_printf(nc, "%s", "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
std::stringstream ss;
trick_MM->write_JSON_alloc_list(ss, start, count);
std::string tmp = ss.str();
mg_printf_http_chunk(nc, "%s", tmp.c_str());
mg_send_http_chunk(nc, "", 0);
}
static int has_prefix(const struct mg_str *uri, const struct mg_str *prefix) {
return uri->len > prefix->len && memcmp(uri->p, prefix->p, prefix->len) == 0;
}
static int is_equal(const struct mg_str *s1, const struct mg_str *s2) {
return s1->len == s2->len && memcmp(s1->p, s2->p, s2->len) == 0;
}
static struct mg_serve_http_opts http_server_options;
static const struct mg_str api_prefix = MG_MK_STR("/api/v1");
static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
http_message *hm = (struct http_message *)ev_data;
switch(ev) {
case MG_EV_WEBSOCKET_HANDSHAKE_DONE: {
printf("DEBUG: Event MG_EV_WEBSOCKET_HANDSHAKE_DONE.\n");
const char* s = "Bingo boingo.";
mg_send_websocket_frame(nc, WEBSOCKET_OP_TEXT, s, strlen(s));
} break;
case MG_EV_WEBSOCKET_FRAME: {
printf("DEBUG: Event MG_EV_WEBSOCKET_FRAME.\n");
} break;
case MG_EV_CONNECT: {
printf("DEBUG: Event MG_EV_CONNECT.\n");
} break;
// case MG_EV_RECV: {
// printf("DEBUG: Event MG_EV_RECV.\n");
// } break;
// case MG_EV_SEND: {
// printf("DEBUG: Event MG_EV_SEND.\n");
// } break;
case MG_EV_CLOSE: {
printf("DEBUG: Event MG_EV_CLOSE.\n");
} break;
// case MG_EV_POLL: {
// printf("DEBUG: Event MG_EV_POLL.\n");
// } break;
case MG_EV_HTTP_REQUEST: {
printf("DEBUG: Event MG_EV_HTTP_REQUEST.\n");
char * s = strndup(hm->uri.p, hm->uri.len);
printf("DEBUG: URI = \"%s\"\n", s);
free(s);
if (has_prefix(&hm->uri, &api_prefix)) {
struct mg_str key;
key.p = hm->uri.p + api_prefix.len;
key.len = hm->uri.len - api_prefix.len;
if (is_equal(&hm->method, &s_get_method)) {
printf("DEBUG: HTTP GET method.\n");
if (mg_vcmp(&key, "/vs_connections") == 0) {
handle_vs_connections_call(nc, hm);
} else if (mg_vcmp(&key, "/alloc_info") == 0) {
handle_alloc_info_call(nc, hm);
}
} else if (is_equal(&hm->method, &s_put_method)) {
printf("DEBUG: HTTP PUT method.\n");
} else if (is_equal(&hm->method, &s_delele_method)) {
printf("DEBUG: HTTP DELETE method.\n");
}
} else {
mg_serve_http(nc, (struct http_message *) ev_data, http_server_options);
}
} break;
default: {
} break;
}
}
void* service_connections (void* arg) {
HTTP_Server *S = (HTTP_Server*)arg;
while(!S->shutting_down) {
mg_mgr_poll(&S->mgr, 1000);
}
return NULL;
}
int http_default_data(HTTP_Server *S) {
S->port = "8888";
S->shutting_down = false;
return 0;
}
int http_init(HTTP_Server *S) {
http_server_options.document_root = "www";
http_server_options.enable_directory_listing = "yes";
mg_mgr_init(&S->mgr, NULL);
printf("Starting web server on port %s\n", S->port);
S->nc = mg_bind(&S->mgr, S->port, ev_handler);
if (S->nc == NULL) {
printf("Failed to create listener.\n");
return 1;
}
mg_set_protocol_http_websocket(S->nc);
pthread_create( &S->server_thread, NULL, service_connections, (void*)S);
return 0;
}
int http_shutdown(HTTP_Server *S) {
printf("Shutting down web server on port %s\n", S->port);
S->shutting_down = true;
pthread_join(S->server_thread, NULL);
return 0;
}

View File

@ -22,7 +22,8 @@ public class TVInteger extends VSInteger implements TrickViewFluent<TVInteger.Fo
Binary {
public String format(int value, boolean unsigned) {
return Integer.toBinaryString(value);
String result = Integer.toBinaryString(value);
return "00000000000000000000000000000000".substring(result.length()) + result;
}
public int parse(String value) {
@ -32,14 +33,12 @@ public class TVInteger extends VSInteger implements TrickViewFluent<TVInteger.Fo
Decimal {
public String format(int value, boolean unsigned) {
String result;
if (unsigned && value < 0) {
result = Long.toString(value + 4294967296L);
return Long.toString(value + 4294967296L);
}
else {
result = Integer.toString(value);
return Integer.toString(value);
}
return "00000000000000000000000000000000".substring(result.length()) + result;
}
public int parse(String value) {

View File

@ -0,0 +1,64 @@
#include <iostream>
#include "trick/MemoryManager.hh"
void Trick::MemoryManager::write_JSON_alloc_info(std::ostream& s, ALLOC_INFO *alloc_info) {
s << "{" << std::endl;
if (!alloc_info->name) {
s << "\"name\":null," << std::endl;
} else {
s << "\"name\":\"" << alloc_info->name << "\"," << std::endl;
}
s << "\"start\":\"" << alloc_info->start << "\"," << std::endl;
s << "\"end\":\"" << alloc_info->end << "\"," << std::endl;
s << "\"num\":\"" << alloc_info->num << "\"," << std::endl;
s << "\"size\":\"" << alloc_info->size << "\"," << std::endl;
s << "\"type\":\"" << trickTypeCharString(alloc_info->type, alloc_info->user_type_name) << "\"," << std::endl;
s << "\"stcl\":" ;
if (alloc_info->stcl == TRICK_LOCAL) {
s << "\"TRICK_LOCAL\"," << std::endl;
}
if (alloc_info->stcl == TRICK_EXTERN) {
s << "\"TRICK_EXTERN\"," << std::endl;
}
s << "\"language\":";
if (alloc_info->language == Language_C ) {
s << "\"Language_C\"," << std::endl;
}
if (alloc_info->language == Language_CPP) {
s << "\"Language_CPP\"," << std::endl;
}
s << "\"index\": [" ;
for (int ii=0; ii<alloc_info->num_index; ii++) {
if (ii != 0) {
s << "," ;
}
s << alloc_info->index[ii] ;
}
s << "]}" ;
}
void Trick::MemoryManager::write_JSON_alloc_list(std::ostream& s, int chunk_start, int chunk_size) {
ALLOC_INFO_MAP::iterator pos;
ALLOC_INFO* alloc_info;
int size = alloc_info_map.size();
s << "{" << std::endl;
s << "\"alloc_total\":" << size << "," << std::endl;
s << "\"chunk_size\":" << chunk_size << "," << std::endl;
s << "\"chunk_start\":" << chunk_start << "," << std::endl;
s << "\"alloc_list\":[" << std::endl;
pos = alloc_info_map.begin();
std::advance(pos, chunk_start);
for (int count = 0; count < chunk_size && pos!=alloc_info_map.end() ; pos++, count++) {
alloc_info = pos->second;
if (count != 0) {
s << "," << std::endl;
}
write_JSON_alloc_info(s, alloc_info);
}
s << "]}" << std::endl;
}

View File

@ -29,6 +29,7 @@ const char* trickTypeCharString( TRICK_TYPE type, const char* name) {
case TRICK_ENUMERATED: type_spec = name; break;
case TRICK_STRUCTURED: type_spec = name; break;
case TRICK_OPAQUE_TYPE: type_spec = name; break;
case TRICK_STL: type_spec = name; break;
default: type_spec = "UNKNOWN_TYPE"; break;
}
return (type_spec);

View File

@ -228,9 +228,6 @@ int Trick::RealtimeSync::start_realtime(double in_frame_time , long long ref_tim
/* Reset the clock reference time to the desired reference time */
rt_clock->clock_reset(ref_time) ;
/* Set top of frame time for 1st frame (used in frame logging). */
last_clock_time = rt_clock->clock_time() ;
/* Start the sleep timer hardware */
start_sleep_timer();
@ -247,6 +244,9 @@ int Trick::RealtimeSync::start_realtime(double in_frame_time , long long ref_tim
}
/* Set top of frame time for 1st frame (used in frame logging). */
last_clock_time = rt_clock->clock_time() ;
return(0) ;
}
@ -283,6 +283,12 @@ int Trick::RealtimeSync::rt_monitor(long long sim_time_tics) {
long long curr_clock_time ;
char buf[512];
/* calculate the current underrun/overrun */
curr_clock_time = rt_clock->clock_time() ;
frame_sched_time = curr_clock_time - last_clock_time ;
/* Set the next frame overrun/underrun reference time to the current time */
last_clock_time = curr_clock_time ;
/* determine if the state of real-time has changed this frame */
if ( ! active ) {
if ( enable_flag ) {
@ -303,10 +309,6 @@ int Trick::RealtimeSync::rt_monitor(long long sim_time_tics) {
disable_flag = false ;
}
/* calculate the current underrun/overrun */
curr_clock_time = rt_clock->clock_time() ;
frame_overrun_time = 0 ;
frame_sched_time = curr_clock_time - last_clock_time ;
frame_overrun_time = curr_clock_time - sim_time_tics ;
/* If the wall clock time is greater than the sim time an overrun occurred. */
@ -363,9 +365,6 @@ int Trick::RealtimeSync::rt_monitor(long long sim_time_tics) {
}
/* Set the next frame overrun/underrun reference time to the current time */
last_clock_time = curr_clock_time ;
return(0) ;
}
@ -456,14 +455,14 @@ int Trick::RealtimeSync::unfreeze(long long sim_time_tics, double software_frame
/* Adjust the real-time clock reference by the amount of time we were frozen */
rt_clock->adjust_ref_time(freeze_time_tics - sim_time_tics) ;
/* Set top of frame time for 1st frame (used in frame logging). */
last_clock_time = rt_clock->clock_time() ;
/* Start the sleep timer with the software frame expiration */
sleep_timer->start(software_frame_sec / rt_clock->get_rt_clock_ratio()) ;
}
/* Set top of frame time for 1st frame (used in frame logging). */
last_clock_time = rt_clock->clock_time() ;
return(0) ;
}