mirror of
https://github.com/nasa/trick.git
synced 2024-12-22 14:32:24 +00:00
295 lines
9.2 KiB
C++
295 lines
9.2 KiB
C++
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <cstring> // for memcpy
|
|
#include <unistd.h>
|
|
|
|
#include "trick/MSSharedMem.hh"
|
|
#include "trick/tsm_proto.h"
|
|
#include "trick/command_line_protos.h"
|
|
|
|
Trick::MSSharedMem::MSSharedMem() : tsm_dev() {
|
|
tsm_dev.default_val = -1;
|
|
|
|
// default is a non-zero sync wait limit; helpful when slave reading initial data from master
|
|
sync_wait_limit = 5.0 ;
|
|
}
|
|
|
|
Trick::MSSharedMem::~MSSharedMem() {
|
|
// detach shared memory
|
|
tsm_disconnect(&tsm_dev);
|
|
}
|
|
|
|
int Trick::MSSharedMem::set_sync_wait_limit(double in_limit) {
|
|
/** @par Detailed Design */
|
|
if ( in_limit > 0.0 ) {
|
|
/** @li if the incoming limit time is greater than zero, we will use it
|
|
as the timeout value during read and write */
|
|
sync_wait_limit = in_limit ;
|
|
} else {
|
|
/** @li if the incoming limit time is less than or equal to zero, wait forever */
|
|
sync_wait_limit = TSM_MAX_TIMEOUT_LIMIT;
|
|
}
|
|
return(0) ;
|
|
}
|
|
|
|
std::string Trick::MSSharedMem::add_sim_args(std::string slave_type __attribute__((unused))) {
|
|
|
|
/** @par Detailed Design */
|
|
|
|
/** @li nothing to do here for shared memory. */
|
|
return("");
|
|
}
|
|
|
|
int Trick::MSSharedMem::process_sim_args() {
|
|
|
|
//int ii ;
|
|
//int argc ;
|
|
//char ** argv ;
|
|
|
|
//argc = command_line_args_get_argc() ;
|
|
//argv = command_line_args_get_argv() ;
|
|
|
|
/** @par Detailed Design */
|
|
|
|
/** @li no shared memory arguments to search for, return 1 to enable slave */
|
|
//for (ii = 2; ii < argc; ii++) {
|
|
//}
|
|
return(1) ;
|
|
}
|
|
|
|
int Trick::MSSharedMem::accept() {
|
|
|
|
int ret ;
|
|
/** @par Detailed Design */
|
|
/** @li Call tsm_init to create shared memory for master. */
|
|
tsm_dev.size = sizeof(MSSharedMemData);
|
|
ret = tsm_init(&tsm_dev);
|
|
shm_addr = (MSSharedMemData*) tsm_dev.addr;
|
|
/** @li Save master process id so we can keep master and slave data seperate. */
|
|
// (the master calls accept)
|
|
if (ret==TSM_SUCCESS) {
|
|
shm_addr->master_pid = getpid();
|
|
//fprintf(stderr, "====accept master=%d\n", getpid());
|
|
MSQ_INIT(shm_addr->master_time);
|
|
MSQ_INIT(shm_addr->master_command);
|
|
MSQ_INIT(shm_addr->slave_command);
|
|
shm_addr->slave_port = MS_ERROR_PORT;
|
|
shm_addr->chkpnt_name[0] = MS_ERROR_NAME;
|
|
} else {
|
|
//fprintf(stderr, "====accept SHARED MEMORY ERROR\n");
|
|
}
|
|
return(ret) ;
|
|
}
|
|
|
|
int Trick::MSSharedMem::connect() {
|
|
int ret ;
|
|
/** @par Detailed Design */
|
|
/** @li Call tsm_init to create shared memory for slave. */
|
|
if (tsm_dev.size == 0) {
|
|
tsm_dev.size = sizeof(MSSharedMemData);
|
|
ret = tsm_init(&tsm_dev);
|
|
} else {
|
|
ret = tsm_reconnect(&tsm_dev);
|
|
}
|
|
shm_addr = (MSSharedMemData*) tsm_dev.addr;
|
|
return(ret) ;
|
|
}
|
|
|
|
int Trick::MSSharedMem::disconnect() {
|
|
return(0) ;
|
|
}
|
|
|
|
|
|
double Trick::MSSharedMem::read_wait(struct timespec *in_start) {
|
|
struct timespec ts_Current, ts_Difference;
|
|
|
|
RELEASE();
|
|
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts_Current);
|
|
if ((ts_Current.tv_nsec - in_start->tv_nsec) < 0) {
|
|
ts_Difference.tv_sec = ts_Current.tv_sec - in_start->tv_sec - 1;
|
|
ts_Difference.tv_nsec = 1000000000 + ts_Current.tv_nsec - in_start->tv_nsec;
|
|
} else {
|
|
ts_Difference.tv_sec = ts_Current.tv_sec - in_start->tv_sec;
|
|
ts_Difference.tv_nsec = ts_Current.tv_nsec - in_start->tv_nsec;
|
|
}
|
|
// return the total elapsed time we've waited since in_start
|
|
return ((double)ts_Difference.tv_nsec / 1000000000.0) + ts_Difference.tv_sec;
|
|
}
|
|
|
|
long long Trick::MSSharedMem::read_time() {
|
|
|
|
long long in_time;
|
|
double readtry_time = 0.0;
|
|
struct timespec ts_Start;
|
|
|
|
/** @par Detailed Design */
|
|
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts_Start);
|
|
|
|
/** @li Get time from shared memory */
|
|
while (MSQ_ISEMPTY(shm_addr->master_time)) {
|
|
if (readtry_time >= sync_wait_limit) {
|
|
break;
|
|
}
|
|
readtry_time = read_wait(&ts_Start);
|
|
}
|
|
if (!MSQ_ISEMPTY(shm_addr->master_time)) {
|
|
in_time = MSQ_FRONT(shm_addr->master_time);
|
|
//fprintf(stderr, "+++++read_time pid=%d time=%lld readtry=%f\n", getpid(), in_time, readtry_time);
|
|
MSQ_POP(shm_addr->master_time);
|
|
return (in_time) ;
|
|
/** @li If no new data before timeout limit, return "error" time */
|
|
} else {
|
|
//fprintf(stderr, "+++++read_time pid=%d time=%lld ERROR readtry=%f\n", getpid(), in_time, readtry_time,); fflush(stderr);
|
|
return (MS_ERROR_TIME) ;
|
|
}
|
|
}
|
|
|
|
MS_SIM_COMMAND Trick::MSSharedMem::read_command() {
|
|
|
|
MS_SIM_COMMAND command;
|
|
double readtry_time = 0.0;
|
|
struct timespec ts_Start;
|
|
|
|
/** @par Detailed Design */
|
|
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts_Start);
|
|
|
|
if (getpid() == shm_addr->master_pid) {
|
|
/** @li Get slave command from shared memory */
|
|
// I am master, so read slave command
|
|
while (MSQ_ISEMPTY(shm_addr->slave_command)) {
|
|
if (readtry_time >= sync_wait_limit) {
|
|
break;
|
|
}
|
|
readtry_time = read_wait(&ts_Start);
|
|
}
|
|
if (!MSQ_ISEMPTY(shm_addr->slave_command)) {
|
|
command = MSQ_FRONT(shm_addr->slave_command);
|
|
//fprintf(stderr, "+++++read_command pid=%d command=%d (from slave)\n", getpid(), command);
|
|
MSQ_POP(shm_addr->slave_command);
|
|
return (command) ;
|
|
/** @li If no new data before timeout limit, return "error" command */
|
|
} else {
|
|
//fprintf(stderr, "+++++read_command pid=%d command=%d (from slave) ERROR readtry=%f\n", getpid(), command, readtry_time);
|
|
return (MS_ErrorCmd) ;
|
|
}
|
|
} else {
|
|
/** @li Get master command from shared memory */
|
|
// I am slave, so read master command
|
|
while (MSQ_ISEMPTY(shm_addr->master_command)) {
|
|
if (readtry_time >= sync_wait_limit) {
|
|
break;
|
|
}
|
|
readtry_time = read_wait(&ts_Start);
|
|
}
|
|
if (!MSQ_ISEMPTY(shm_addr->master_command)) {
|
|
command = MSQ_FRONT(shm_addr->master_command);
|
|
//fprintf(stderr, "+++++read_command pid=%d command=%d (from master)\n", getpid(), command);
|
|
MSQ_POP(shm_addr->master_command);
|
|
return (command) ;
|
|
/** @li If no new data before timeout limit, return "error" command */
|
|
} else {
|
|
//fprintf(stderr, "+++++read_command pid=%d command=%d (from master) ERROR readtry=%f\n", getpid(), command, readtry_time);
|
|
return (MS_ErrorCmd) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
int Trick::MSSharedMem::read_port() {
|
|
|
|
int in_port;
|
|
double readtry_time = 0.0;
|
|
struct timespec ts_Start;
|
|
|
|
/** @par Detailed Design */
|
|
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts_Start);
|
|
|
|
/** @li Get port number from shared memory */
|
|
while (shm_addr->slave_port == MS_ERROR_PORT) {
|
|
if (readtry_time >= sync_wait_limit) {
|
|
break;
|
|
}
|
|
readtry_time = read_wait(&ts_Start);
|
|
}
|
|
if (shm_addr->slave_port != MS_ERROR_PORT) {
|
|
in_port = shm_addr->slave_port;
|
|
shm_addr->slave_port = MS_ERROR_PORT; // default value
|
|
return (in_port) ;
|
|
/** @li If no new data before timeout limit, return "error" port */
|
|
} else {
|
|
return (MS_ERROR_PORT) ;
|
|
}
|
|
}
|
|
|
|
char Trick::MSSharedMem::read_name(char * read_data, size_t size) {
|
|
|
|
double readtry_time = 0.0;
|
|
struct timespec ts_Start;
|
|
|
|
/** @par Detailed Design */
|
|
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts_Start);
|
|
|
|
/** @li Get name (character array) from shared memory */
|
|
while (shm_addr->chkpnt_name[0] == MS_ERROR_NAME) {
|
|
if (readtry_time >= sync_wait_limit) {
|
|
break;
|
|
}
|
|
readtry_time = read_wait(&ts_Start);
|
|
}
|
|
if (shm_addr->chkpnt_name[0] != MS_ERROR_NAME) {
|
|
memcpy(read_data, shm_addr->chkpnt_name, size);
|
|
shm_addr->chkpnt_name[0] = MS_ERROR_NAME; // default value
|
|
return (0) ;
|
|
/** @li If no new data before timeout limit, return "error" name */
|
|
} else {
|
|
return (MS_ERROR_NAME) ;
|
|
}
|
|
}
|
|
|
|
int Trick::MSSharedMem::write_time(long long in_time) {
|
|
|
|
/** @par Detailed Design */
|
|
/** @li Write time to shared memory */
|
|
//fprintf(stderr, "====write_time pid=%d time=%lld\n", getpid(), in_time);
|
|
MSQ_PUSH(shm_addr->master_time, in_time);
|
|
|
|
/** @li Return the number of bytes written */
|
|
return(sizeof(long long)) ;
|
|
}
|
|
|
|
int Trick::MSSharedMem::write_command(MS_SIM_COMMAND command) {
|
|
|
|
/** @par Detailed Design */
|
|
/** @li Write command to shared memory */
|
|
if (getpid() == shm_addr->master_pid) {
|
|
//fprintf(stderr, "====write_command pid=%d command=%d (master)\n", getpid(), command);
|
|
MSQ_PUSH(shm_addr->master_command, command);
|
|
} else {
|
|
//fprintf(stderr, "====write_command pid=%d command=%d (slave)\n", getpid(), command);
|
|
MSQ_PUSH(shm_addr->slave_command, command);
|
|
}
|
|
|
|
/** @li Return the number of bytes written */
|
|
return(sizeof(MS_SIM_COMMAND)) ;
|
|
}
|
|
|
|
int Trick::MSSharedMem::write_port(int in_port) {
|
|
|
|
/** @par Detailed Design */
|
|
/** @li Write port number to shared memory */
|
|
shm_addr->slave_port = in_port;
|
|
|
|
/** @li Return the number of bytes written */
|
|
return(sizeof(int)) ;
|
|
}
|
|
|
|
int Trick::MSSharedMem::write_name(char * in_data, size_t size) {
|
|
|
|
/** @par Detailed Design */
|
|
/** @li Write name (character array) to shared memory */
|
|
memcpy(shm_addr->chkpnt_name, in_data, size);
|
|
|
|
/** @li Return the number of bytes written */
|
|
return(size);
|
|
}
|