You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
347 lines
7.9 KiB
347 lines
7.9 KiB
|
|
#include <string>
|
|
#include <sys/time.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <netdb.h>
|
|
#include <errno.h>
|
|
#include <math.h>
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/wait.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <syslog.h>
|
|
#include <pthread.h>
|
|
#include <sys/syscall.h>
|
|
|
|
|
|
#include "modelbahn.h"
|
|
#include "server.h"
|
|
|
|
int Server::Start() {
|
|
int err;
|
|
pthread_attr_t attr;
|
|
mtx = { 0 };
|
|
mtx = PTHREAD_MUTEX_INITIALIZER;
|
|
thread_running = 1;
|
|
pthread_attr_init (&attr);
|
|
pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_JOINABLE);
|
|
err = pthread_create (&thread, &attr, ThreadEntry, this);
|
|
if (err != 0) {
|
|
debug (DEBUG_ERROR, (char*)"%s(%s:%d) pthread_create errror: %s", __FUNCTION__, __FILE__, __LINE__, strerror (errno));
|
|
running = 0;
|
|
return 0;
|
|
}
|
|
return 1;
|
|
};
|
|
|
|
|
|
Server::Server() {
|
|
thread = 0;
|
|
thread_running = 0;
|
|
railways.SetSize(200, 200);
|
|
status_text = "init server";
|
|
mode = SMODE_STARTUP;
|
|
data_reset.mr_idx = -1;
|
|
data_reset.mr_step = SMRESET_STEP_INIT;
|
|
gettimeofday(&data_reset.mr_timestamp, NULL);
|
|
|
|
Load ();
|
|
};
|
|
|
|
|
|
Server::~Server() {
|
|
if (IsChanged()) Save();
|
|
};
|
|
|
|
|
|
int Server::TurnoutSet(string name, int active) {
|
|
int x, y, locked = 0;
|
|
string lockedby;
|
|
Railway r;
|
|
//
|
|
// check if locked
|
|
while (server->railways.FindReference(&x, &y, name)) {
|
|
r = server->railways.Get(x, y);
|
|
printf ("Reference %d,%d Name:%s Lockedby:%d\n", x, y, r.name, r.lockedby);
|
|
if (r.lockedby[0] != 0) {
|
|
locked = 1;
|
|
lockedby = r.lockedby;
|
|
}
|
|
}
|
|
|
|
if (locked == 0) return turnouts.Set(name, active);
|
|
else {
|
|
debug (0, "%s:%d SetJSONTurnout Element %s is locked by %s", __FILE__, __LINE__, name.c_str(), lockedby.c_str());
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// server thread will cycle as long as running is set to true
|
|
// most important in each cycle there will be
|
|
void Server::ThreadProcess() {
|
|
int i = 0;
|
|
|
|
int timeout10s;
|
|
int cyclelooptime_max = 0;
|
|
int cycletime_max = 0;
|
|
struct timeval tv_loop, tv;
|
|
|
|
gettimeofday (&tv, NULL);
|
|
gettimeofday (&tv_loop, NULL);
|
|
timeout10s = tv.tv_sec + 10;
|
|
|
|
while (running) {
|
|
interfaces.Loop();
|
|
turnouts.Loop();
|
|
|
|
//
|
|
// startup process
|
|
if (mode == SMODE_STARTUP) {
|
|
mode = SMODE_MANUAL;
|
|
printf ("%s:%d ************************************************************ fix me\n", __FILE__, __LINE__);
|
|
SetModeReset(); // currently there is not much to do.
|
|
}
|
|
|
|
//
|
|
// reset all internal data
|
|
else if (mode == SMODE_RESET)
|
|
CycleModeReset();
|
|
|
|
//
|
|
// mode manual
|
|
else if (mode == SMODE_MANUAL) {
|
|
}
|
|
|
|
//
|
|
// mode auto
|
|
else if (mode == SMODE_AUTO) {
|
|
server->locomotives.Loop();
|
|
}
|
|
|
|
gettimeofday (&tv, NULL);
|
|
i = (tv.tv_sec-tv_loop.tv_sec) * 1000 + (tv.tv_usec - tv_loop.tv_usec) / 1000;
|
|
if (i > cycletime_max) cycletime_max = i;
|
|
if (i < 25 && i >= 0) usleep (25000 - i*1000);
|
|
gettimeofday (&tv, NULL);
|
|
i = (tv.tv_sec-tv_loop.tv_sec) * 1000 + (tv.tv_usec - tv_loop.tv_usec) / 1000;
|
|
if (i > cyclelooptime_max) cyclelooptime_max = i;
|
|
|
|
if (tv_loop.tv_sec > timeout10s) {
|
|
timeout10s = tv.tv_sec + 10;
|
|
debug (DEBUG_INFO, "Server::ThreadProcess max Cycletime: %dms Cyclelooptime:%dms", cycletime_max, cyclelooptime_max);
|
|
cycletime_max = 0;
|
|
cyclelooptime_max = 0;
|
|
}
|
|
tv_loop = tv;
|
|
}
|
|
debug (0, "Server::ThreadProcess Finished");
|
|
thread_running = 0;
|
|
};
|
|
|
|
|
|
void Server::LockThread() {
|
|
pthread_mutex_lock (&mtx);
|
|
};
|
|
|
|
|
|
void Server::UnLockThread() {
|
|
pthread_mutex_unlock (&mtx);
|
|
};
|
|
|
|
|
|
//
|
|
// return JSONObject with all data
|
|
void Server::GetJSONAll(JSONParse *json) {
|
|
debug (DEBUG_INFO, "* Track::GetJSONAll data");
|
|
if (json == NULL) return;
|
|
|
|
railways.GetJSONAll(json);
|
|
interfaces.GetJSONAll(json);
|
|
sensors.GetJSONAll(json);
|
|
locomotives.GetJSONAll(json);
|
|
turnouts.GetJSONAll(json);
|
|
blocks.GetJSONAll(json);
|
|
}
|
|
|
|
|
|
bool Server::IsChanged() {
|
|
if (railways.IsChanged() ||
|
|
interfaces.IsChanged() ||
|
|
locomotives.IsChanged() ||
|
|
sensors.IsChanged() ||
|
|
turnouts.IsChanged()) return true;
|
|
else return false;
|
|
}
|
|
|
|
|
|
//
|
|
// Set Mode Auto
|
|
void Server::SetModeAuto() {
|
|
debug (0, "%s:%d * Set Mode Auto", __FILE__, __LINE__);
|
|
if (mode == SMODE_MANUAL) {
|
|
mode = SMODE_AUTO;
|
|
status_text = "Mode Auto";
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set Mode Manual
|
|
void Server::SetModeManual() {
|
|
debug (0, "%s:%d * Set Mode Manual", __FILE__, __LINE__);
|
|
mode = SMODE_MANUAL;
|
|
status_text = "Mode Manual";
|
|
}
|
|
|
|
|
|
//
|
|
// run a single cycle in reset mode
|
|
// each step will only reset one single step.
|
|
#define INTERFACE_LOCO_TIME 250
|
|
#define INTERFACE_TURN_TIME 750
|
|
void Server::CycleModeReset() {
|
|
JSONParse json;
|
|
list<JSONElement> elements;
|
|
list<JSONElement>::iterator iter;
|
|
json.Clear();
|
|
|
|
// debug (0, "* CycleModeReset Step:%d", data_reset.mr_step);
|
|
|
|
if (data_reset.mr_step == SMRESET_STEP_INIT) {
|
|
//
|
|
// init reset
|
|
data_reset.mr_idx = -1;
|
|
data_reset.mr_step++;
|
|
}
|
|
else if (data_reset.mr_step == SMRESET_STEP_LOCKS) {
|
|
//
|
|
// clear all locks
|
|
debug (0, "* Clear all Locks", data_reset.mr_lastelm.c_str());
|
|
|
|
data_reset.mr_idx = -1;
|
|
data_reset.mr_step++;
|
|
}
|
|
else if (data_reset.mr_step == SMRESET_STEP_INTERFACES) {
|
|
//
|
|
// clear locks
|
|
data_reset.mr_idx = -1;
|
|
data_reset.mr_step++;
|
|
}
|
|
else if (data_reset.mr_step == SMRESET_STEP_LOCOMOTIVES) {
|
|
//
|
|
// reset locomotives, cycle 30ms per locomotive
|
|
if (data_reset.mr_idx < 0 || timer_get(&data_reset.mr_timestamp) > INTERFACE_LOCO_TIME) {
|
|
if (data_reset.mr_idx < -1) data_reset.mr_idx = -1;
|
|
|
|
data_reset.mr_idx++;
|
|
data_reset.mr_lastelm = locomotives.GetName(data_reset.mr_idx);
|
|
timer_start (&data_reset.mr_timestamp);
|
|
|
|
if (data_reset.mr_lastelm.length() > 0) {
|
|
debug (0, "* Reset Locomotive %s", data_reset.mr_lastelm.c_str());
|
|
LocomotiveSetReverse(data_reset.mr_lastelm, 0);
|
|
LocomotiveSetSpeed(data_reset.mr_lastelm, 0);
|
|
}
|
|
else {
|
|
data_reset.mr_idx = -1;
|
|
data_reset.mr_step++;
|
|
data_reset.mr_lastelm;
|
|
}
|
|
}
|
|
}
|
|
else if (data_reset.mr_step == SMRESET_STEP_TURNOUTS) {
|
|
//
|
|
// reset turnouts
|
|
if (data_reset.mr_idx < 0 || timer_get(&data_reset.mr_timestamp) > INTERFACE_TURN_TIME) {
|
|
int flags, active;
|
|
if (data_reset.mr_idx < -1) data_reset.mr_idx = -1;
|
|
|
|
data_reset.mr_idx++;
|
|
data_reset.mr_lastelm = turnouts.GetName(data_reset.mr_idx);
|
|
flags = turnouts.GetFlags(data_reset.mr_idx);
|
|
if (flags & TURNOUT_F_TURNOUT) active = 1;
|
|
else active = 0;
|
|
timer_start (&data_reset.mr_timestamp);
|
|
|
|
if (data_reset.mr_lastelm.length() > 0) {
|
|
debug (0, "* Reset Turnout %s", data_reset.mr_lastelm.c_str());
|
|
TurnoutSet(data_reset.mr_lastelm, active);
|
|
}
|
|
else {
|
|
data_reset.mr_idx = -1;
|
|
data_reset.mr_step++;
|
|
data_reset.mr_lastelm;
|
|
}
|
|
}
|
|
}
|
|
else if (data_reset.mr_step == SMRESET_STEP_SENSORS) {
|
|
//
|
|
// reset sensors
|
|
// all can be done in one single cycle.
|
|
//
|
|
int i; // index of sensor
|
|
int oldflags; // old flags
|
|
Sensor sensor; // sensor data
|
|
|
|
for (i = 0; sensors.Get(i, &sensor) == 1; i++) {
|
|
oldflags = sensor.flags;
|
|
sensor.flags &= ~(SENSOR_F_ACTIVE);
|
|
debug (0, "* Reset Sensor: '%s' (%d -> %d)", sensor.name, oldflags, sensor.flags);
|
|
if (oldflags != sensor.flags) // only update if needed
|
|
sensors.Change(&sensor);
|
|
}
|
|
|
|
sensors.GetJSONAll(&json);
|
|
data_reset.mr_idx = -1;
|
|
data_reset.mr_step++;
|
|
}
|
|
else {
|
|
SetModeManual();
|
|
}
|
|
|
|
//
|
|
// adding update data
|
|
elements = json.GetElements();
|
|
for (iter = elements.begin(); iter != elements.end(); iter++) {
|
|
if (network) network->ChangeListPushToAll("{"+(*iter).GetString()+"}");
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Set Mode Error
|
|
void Server::SetModeError(string text) {
|
|
debug (0, "%s:%d * Set Mode Error :'%s'", __FILE__, __LINE__, text.c_str());
|
|
status_text = "Error:'" + text + "'";
|
|
}
|
|
|
|
//
|
|
// Set Mode Reset
|
|
void Server::SetModeReset() {
|
|
debug (0, "%s:%d * Set Reset Data", __FILE__, __LINE__);
|
|
status_text = "Mode Reset";
|
|
|
|
mode = SMODE_RESET;
|
|
data_reset.mr_step = SMRESET_STEP_INIT;
|
|
data_reset.mr_idx = -1;
|
|
data_reset.mr_lastelm = "";
|
|
gettimeofday(&data_reset.mr_timestamp, NULL);
|
|
};
|
|
|
|
|
|
string Server::GetStatus(void) {
|
|
string retval;
|
|
|
|
LockThread();
|
|
retval = status_text;
|
|
UnLockThread();
|
|
|
|
return retval;
|
|
};
|