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.
Modelbahn/server/locomotive.cc

664 lines
17 KiB

#include "modelbahn.h"
#include "locomotive.h"
Locomotives::Locomotives () {
changed = 0;
locomotives = (Locomotive*) malloc(sizeof(Locomotive)*LOCOMOTIVES_MAX);
memset(locomotives, 0x0, sizeof(Locomotive)*LOCOMOTIVES_MAX);
max = SENSORS_MAX;
};
Locomotives::~Locomotives() {
free (locomotives);
locomotives = NULL;
max = 0;
};
int Locomotives::Lock() {
if (pthread_mutex_lock(&mtx) == 0) return 1;
else return 0;
}
int Locomotives::UnLock() {
if (pthread_mutex_unlock(&mtx) == 0) return 1;
else return 0;
}
JSONParse Locomotives::_GetJSON(int idx) {
JSONParse json;
JSONElement je;
string s = "";
json.Clear();
s = locomotives[idx].name; json.AddObject("name", s);
s = locomotives[idx].ifname; json.AddObject("ifname", s);
s = locomotives[idx].blockdest; json.AddObject("blockdest", s);
s = locomotives[idx].blocknext; json.AddObject("blocknext", s);
s = locomotives[idx].blockassign; json.AddObject("blockassign", s);
s = locomotives[idx].blockprev; json.AddObject("blockprev", s);
s = locomotives[idx].auto_way; json.AddObject("auto_way", s);
json.AddObject("addr", locomotives[idx].addr);
json.AddObject("stepcode", locomotives[idx].stepcode);
json.AddObject("speed", locomotives[idx].speed);
json.AddObject("func", locomotives[idx].func);
json.AddObject("flags", locomotives[idx].flags);
json.AddObject("vmin", locomotives[idx].vmin);
json.AddObject("vslow", locomotives[idx].vslow);
json.AddObject("vmid", locomotives[idx].vmid);
json.AddObject("vfast", locomotives[idx].vfast);
json.AddObject("vmax", locomotives[idx].vmax);
return json;
};
JSONParse Locomotives::GetJSON(string name) {
int i;
JSONParse jp;
jp.Clear();
Lock();
for (i = 0; i < max; i++) if (locomotives[i].name[0] != 0) {
if (name.compare(locomotives[i].name) == 0) {
jp = _GetJSON(i);
}
}
UnLock();
return jp;
};
void Locomotives::GetJSONAll(JSONParse *json) {
int i, cnt;
JSONElement je;
Lock();
//
// write all railway data
// create json object array manualy
je.type = JSON_T_ARRAY;
je.name = "locomotives";
for (cnt = 0, i = 0; i < max; i++)
if (locomotives[i].name[0] != 0) {
if (cnt != 0) je.value += ","; // not first element
je.value += _GetJSON(i).ToString();
cnt++;
}
json->AddObject(je);
UnLock();
};
Locomotive Locomotives::GetLocomotiveFromJSON(JSONParse *j) {
Locomotive l;
string s;
l.name[0] = 0;
l.ifname[0] = 0;
l.addr = 0;
l.stepcode = 0;
l.vmin = 0;
l.vslow = 0;
l.vmid = 0;
l.vfast = 0;
l.vmax = 0;
l.flags = 0;
l.speed = 0;
l.func = 0;
l.blockassign[0] = 0;
l.blockdest[0] = 0;
l.blocknext[0] = 0;
l.blockprev[0] = 0;
l.auto_way[0] = 0;
l.auto_onroute = 0;
l.auto_timenext = {0};
j->GetValue("name", &s);
strncpy (l.name, s.c_str(), REFERENCENAME_LEN);
j->GetValue("ifname", &s);
strncpy (l.ifname, s.c_str(), REFERENCENAME_LEN);
j->GetValue("blockassign", &s);
strncpy (l.blockassign, s.c_str(), REFERENCENAME_LEN);
j->GetValue("blockdest", &s);
strncpy (l.blockdest, s.c_str(), REFERENCENAME_LEN);
j->GetValue("blockprev", &s);
strncpy (l.blockprev, s.c_str(), REFERENCENAME_LEN);
j->GetValue("blocknext", &s);
strncpy (l.blocknext, s.c_str(), REFERENCENAME_LEN);
j->GetValueInt("addr", &l.addr);
j->GetValueInt("stepcode", &l.stepcode);
j->GetValueInt("speed", &l.speed);
j->GetValueInt64("func", &l.func);
j->GetValueInt("flags", &l.flags);
j->GetValueInt("vmin", &l.vmin);
j->GetValueInt("vslow", &l.vslow);
j->GetValueInt("vmid", &l.vmid);
j->GetValueInt("vfast", &l.vfast);
j->GetValueInt("vmax", &l.vmax);
return l;
};
int Locomotives::Change(Locomotive *loco) {
int i;
int ifree = -1;
Lock();
printf ("%s:%d Change Locomotive\n", __FILE__, __LINE__);
for (i = 0; i < max; i++) {
if (locomotives[i].name[0] != 0) {
// found element
if (strncmp(locomotives[i].name, loco->name, REFERENCENAME_LEN) == 0) {
// copy block data
strncpy (locomotives[i].ifname, loco->name, REFERENCENAME_LEN);
locomotives[i].addr = loco->addr;
locomotives[i].stepcode = loco->stepcode;
locomotives[i].vmin = loco->vmin;
locomotives[i].vslow = loco->vslow;
locomotives[i].vmid = loco->vmid;
locomotives[i].vfast = loco->vfast;
locomotives[i].vmax = loco->vmax;
locomotives[i].flags = loco->flags;
// locomotives[i].speed = 0;
// locomotives[i].func = 0;
ifree = i;
break;
}
}
else if (ifree == -1) ifree = i;
}
// element not found add new element
if (ifree != -1 && ifree < max) {
locomotives[ifree] = *loco;
strncpy (locomotives[ifree].name, loco->name, REFERENCENAME_LEN);
strncpy (locomotives[ifree].ifname, loco->ifname, REFERENCENAME_LEN);
}
changed = 1;
UnLock();
return 1;
};
int Locomotives::Delete(string name) {
int i;
Lock();
for (i = 0; i < max; i++) if (locomotives[i].name[0] != 0) {
if (name.compare(locomotives[i].name) == 0) {
locomotives[i].name[0] = 0;
locomotives[i].ifname[0] = 0;
locomotives[i].addr = 0;
locomotives[i].stepcode = 0;
locomotives[i].vmin = 0;
locomotives[i].vslow = 0;
locomotives[i].vmid = 0;
locomotives[i].vfast = 0;
locomotives[i].vmax = 0;
locomotives[i].flags = 0;
locomotives[i].auto_way[0] = 0;
locomotives[i].auto_onroute = -1;
locomotives[i].auto_timenext = {0};
changed = 1;
break;
}
}
UnLock();
return 1;
};
int Locomotives::SetSpeed(string name, int speed) {
int i;
Lock();
for (i = 0; i < max; i++) if (locomotives[i].name[0] != 0) {
if (name.compare(locomotives[i].name) == 0) {
server->interfaces.SetLocoSpeed(&locomotives[i], speed);
break;
}
}
UnLock();
return 1;
};
int Locomotives::SetReverse(string name, int reverse) {
int i;
Lock();
for (i = 0; i < max; i++) if (locomotives[i].name[0] != 0) {
if (name.compare(locomotives[i].name) == 0) {
if (reverse)
locomotives[i].flags |= LOCO_F_REVERSE;
else
locomotives[i].flags &= ~LOCO_F_REVERSE;
server->interfaces.SetLocoSpeed(&locomotives[i], locomotives[i].speed);
break;
}
}
UnLock();
return 1;
};
int Locomotives::SetFunction(string name, int func, int value) {
int i;
Lock();
for (i = 0; i < max; i++) if (locomotives[i].name[0] != 0) {
if (name.compare(locomotives[i].name) == 0) {
server->interfaces.SetLocoFunction(&locomotives[i], func, value);
break;
}
}
UnLock();
return 1;
};
int Locomotives::SetDestination (string name, string block, int direction) {
int i;
string way;
Lock();
for (i = 0; i < max; i++) if (locomotives[i].name[0] != 0)
if (name.compare(locomotives[i].name) == 0) {
debug (0, "Locomotives::SetDestination (Name:%s Block:%s Direction:%d)\n", name.c_str(), block.c_str(), direction);
if (direction) snprintf (locomotives[i].blockdest, REFERENCENAME_LEN, "-:%s", block.c_str());
else snprintf (locomotives[i].blockdest, REFERENCENAME_LEN, "+:%s", block.c_str());
printf ("%s:%d Locomotive '%s' blockdest:%s\n", __FILE__, __LINE__, locomotives[i].name, locomotives[i].blockdest);
break;
}
UnLock();
printf ("%s:%d %s ************** finish me **************\n", __FILE__, __LINE__, __FUNCTION__);
return 1;
}
int Locomotives::SetAssign (string name, string block, int direction) {
int i, x = -1;
int y = -1;
Lock();
for (i = 0; i < max; i++) if (locomotives[i].name[0] != 0)
if (name.compare(locomotives[i].name) == 0) {
debug (0, "Locomotives::SetAssign (Name:%s Block:%s Direction:%d)\n", name.c_str(), block.c_str(), direction);
if (locomotives[i].blockassign[0] != 0) // still locked unlock
server->blocks.SetLockedby(locomotives[i].blockassign, name, 0);
if (direction) snprintf (locomotives[i].blockassign, REFERENCENAME_LEN, "-:%s", block.c_str());
else snprintf (locomotives[i].blockassign, REFERENCENAME_LEN, "+:%s", block.c_str());
server->blocks.SetLockedby(block, name, 1);
break;
}
UnLock();
while (server->railways.FindReference(&x, &y, block)) {
printf ("%s:%d Reference found at %d, %d\n", __FILE__, __LINE__, x, y);
string bl = server->blocks.GetLockedby(block);
if(bl.length() == 0 || bl.compare(name) == 0) {
server->blocks.SetLockedby(block, name, 1);
server->railways.SetLockedby(x, y, name, 1);
}
}
printf ("%s:%d %s ************** finish me **************\n", __FILE__, __LINE__, __FUNCTION__);
return 1;
}
int Locomotives::Reset(string name) {
Railway rw;
int i;
JSONParse jp;
Lock();
for (i = 0; i < max; i++) if (locomotives[i].name[0] != 0)
if (name.compare(locomotives[i].name) == 0) {
debug (0, "Locomotives::Reset (Name:%s)\n", name.c_str());
locomotives[i].blockassign[0] = 0;
locomotives[i].blockdest[0] = 0;
locomotives[i].blockprev[0] = 0;
locomotives[i].blocknext[0] = 0;
locomotives[i].auto_way[0] = 0;
locomotives[i].auto_onroute = -1;
break;
}
server->railways.ClearLockedby(name);
server->blocks.ClearLockedby(name);
jp.AddObject("locomotive",_GetJSON(i));
if(network) network->ChangeListPushToAll(jp.ToString());
UnLock();
return 1;
};
int Locomotives::SetMan(string name) {
int i;
Lock();
for (i = 0; i < max; i++) if (locomotives[i].name[0] != 0)
if (name.compare(locomotives[i].name) == 0) {
debug (0, "Locomotives::SetMan (Name:%s)\n", name.c_str());
locomotives[i].flags &= ~(LOCO_F_AUTO | LOCO_F_AUTOSTOP | LOCO_F_RANDOM);
locomotives[i].auto_onroute = 0;
locomotives[i].auto_way[0] = 0;
break;
}
UnLock();
SetSpeed(name, 0);
return 1;
};
int Locomotives::SetAutoMan(string name) {
int i;
Lock();
for (i = 0; i < max; i++) if (locomotives[i].name[0] != 0)
if (name.compare(locomotives[i].name) == 0 && (locomotives[i].flags & LOCO_F_AUTO)) {
debug (0, "Locomotives::SetAutoMan (Name:%s)\n", name.c_str());
locomotives[i].flags |= LOCO_F_AUTOSTOP;
locomotives[i].flags &= ~LOCO_F_RANDOM;
break;
}
UnLock();
return 1;
};
int Locomotives::SetAuto(string name) {
int i;
Lock();
for (i = 0; i < max; i++) if (locomotives[i].name[0] != 0)
if (name.compare(locomotives[i].name) == 0) {
debug (0, "Locomotives::SetAuto (Name:%s)\n", name.c_str());
locomotives[i].flags |= LOCO_F_AUTO;
locomotives[i].auto_onroute = 0;
break;
}
UnLock();
return 1;
};
int Locomotives::SetAutoRand(string name) {
int i;
Lock();
for (i = 0; i < max; i++) if (locomotives[i].name[0] != 0)
if (name.compare(locomotives[i].name) == 0 && (locomotives[i].flags & LOCO_F_AUTO)) {
debug (0, "Locomotives::SetRandom (Name:%s)\n", name.c_str());
locomotives[i].flags |= LOCO_F_RANDOM;
locomotives[i].flags &= ~LOCO_F_AUTOSTOP;
break;
}
UnLock();
return 1;
};
//
// set values from bus...
//
int Locomotives::SetSpeedFromBus(string ifname, int addr, int speed) {
int i;
JSONParse jp;
debug (0, "%s:%d SetSpeedFromBus IfName:%s Addr:%d Speed:%d", __FILE__, __LINE__, ifname.c_str(), addr, speed);
for (i = 0; i < max; i++) if (locomotives[i].name[0] != 0) {
if (ifname.compare(locomotives[i].ifname) == 0 && locomotives[i].addr == addr) {
int maxstep;
switch(locomotives[i].stepcode) {
case LOCO_INT_DCC14: maxstep = 14; break;
case LOCO_INT_DCC28: maxstep = 28; break;
case LOCO_INT_DCC128: maxstep = 126; break;
default: maxstep = -1; break;
}
if (speed == 0) locomotives[i].speed = 0;
if (speed >= (127-((127/maxstep)+1))) locomotives[i].speed = locomotives[i].vmax;
else {
locomotives[i].speed = speed * locomotives[i].vmax / 127;
if (locomotives[i].speed > locomotives[i].vmax) locomotives[i].speed = locomotives[i].vmax;
}
jp.AddObject("locomotive",_GetJSON(i));
if(network) network->ChangeListPushToAll(jp.ToString());
return 1;
}
}
return 0;
};
int Locomotives::SetFunctionFromBus(string ifname, int addr, int func) {
int i;
JSONParse jp;
debug (0, "%s:%d SetDirectionFromBus IfName:%s Addr:%d function:%d", __FILE__, __LINE__, ifname.c_str(), addr, func);
for (i = 0; i < max; i++) if (locomotives[i].name[0] != 0) {
if (ifname.compare(locomotives[i].ifname) == 0 && locomotives[i].addr == addr) {
if (func & 32) locomotives[i].flags |= LOCO_F_REVERSE;
else locomotives[i].flags &= ~LOCO_F_REVERSE;
jp.AddObject("locomotive",_GetJSON(i));
if(network) network->ChangeListPushToAll(jp.ToString());
return 1;
}
}
return 0;
};
string Locomotives::GetName(int idx) {
string result = "";
Lock();
if (idx <= max && idx >= 0)
result = locomotives[idx].name;
UnLock();
return result;
};
//
// with each call only check one single step of the way, if we have to
// turn a turnout try to do it and return 0
// if everything is set up till the destination block return 1
//
int Locomotives::AutoCheckWaySingleStep(string way, string locname) {
int res = 0;
size_t pos1, pos2;
size_t curpos;
int val, state;
curpos = 0;
do {
curpos = way.find (",t:", curpos+1);
if (curpos != string::npos) {
pos1 = way.find(":", curpos+3);
if (pos1 == string::npos) {
debug (0, "%s:%d turnout without value? '%s'", __FILE__, __LINE__, way.c_str());
return 0;
}
state = server->turnouts.Get(way.substr(curpos+3, pos1-curpos-3));
if (state == -1) {
debug (0, "%s:%d turnout not found '%s'", __FILE__, __LINE__, way.substr(curpos+3, pos1-curpos-3).c_str());
return 0;
}
if (way[pos1+1] == '0' && state != 0) {
server->TurnoutSet(way.substr(curpos+3, pos1-curpos-3), 0);
break;
}
else if (way[pos1+1] == '1' && state != 1) {
server->TurnoutSet(way.substr(curpos+3, pos1-curpos-3), 1);
break;
}
printf ("%s:%d Checked:%s\n", __FILE__, __LINE__, way.substr(curpos+3, pos1-curpos-3).c_str());
}
} while (curpos != string::npos);
if (curpos == string::npos) res = 1;
return res;
}
int Locomotives::Loop() {
int lnum;
string way;
Locomotive *loco = NULL;
string block;
string sensor;
for (lnum = 0; lnum < max; lnum++) if (locomotives[lnum].name[0] != 0) {
loco = &locomotives[lnum];
if (loco->flags & LOCO_F_AUTO) {
//
// only in automate do anything alone
//
if (loco->blockassign[0] == 0 || loco->blockdest[0] == 0) continue;
if (loco->auto_onroute == LOCO_OR_NOTHING) {
timer_start(&loco->auto_timenext);
loco->auto_onroute = LOCO_OR_SEARCH;
}
if (loco->auto_onroute == LOCO_OR_SEARCH) {
if (loco->auto_timenext.tv_sec == 0 || timer_get(&loco->auto_timenext) > 1000) {
printf ("%s:%d Locomotive::Loop '%s' auto_onroute:%d\n", __FILE__, __LINE__,
loco->name, loco->auto_onroute);
if (server->railways.FindWay(loco->blockassign, loco->blockdest, loco->name, &way)) {
size_t pos;
if ((pos = way.find(",b:", 1)) != string::npos) {
strncpy (loco->blocknext, way.substr(pos+3,string::npos).c_str(), REFERENCENAME_LEN);
strncpy (loco->auto_way, way.c_str(), WAYDATA_LEN);
if (server->railways.LockWay(way, loco->name) == 1) {
loco->auto_onroute = LOCO_OR_PREPARE;
}
else timer_start(&loco->auto_timenext);
}
}
else timer_start(&loco->auto_timenext);
}
}
else if (loco->auto_onroute == LOCO_OR_PREPARE) {
if (loco->auto_timenext.tv_sec == 0 || timer_get(&loco->auto_timenext) > 1000) {
if (AutoCheckWaySingleStep(loco->auto_way, loco->name) == 1)
loco->auto_onroute = LOCO_OR_ONTHEWAY;
else timer_start(&loco->auto_timenext);
}
}
else if (loco->auto_onroute == LOCO_OR_ONTHEWAY) {
if (loco->flags & LOCO_F_CARGO) SetSpeed(loco->name, loco->vmid);
else SetSpeed(loco->name, loco->vfast);
loco->auto_onroute = LOCO_OR_ONTHEWAYPREPARE;
}
else if (loco->auto_onroute == LOCO_OR_ONTHEWAYPREPARE) {
// check enter block
block = loco->blocknext+2;
if (loco->blocknext[0] == '-')
sensor = server->blocks.GetSensorMinus(block);
else
sensor = server->blocks.GetSensorPlus(block);
if (server->sensors.GetActive(sensor) == 1) {
SetSpeed(loco->name, loco->vslow);
loco->auto_onroute = LOCO_OR_ENTERBLOCK;
if (loco->blockassign != 0) {
server->blocks.SetLockedby((string)(loco->blockassign+2), loco->name, 0);
}
}
}
else if (loco->auto_onroute == LOCO_OR_ENTERBLOCK) {
// check enter block
block = loco->blocknext+2;
if (loco->blocknext[0] == '-')
sensor = server->blocks.GetSensorPlus(block);
else
sensor = server->blocks.GetSensorMinus(block);
if (server->sensors.GetActive(sensor) == 1) {
debug (0, "Locomotives::Loop '%s' UnLockWay\n", loco->name);
SetSpeed(loco->name, 0);
loco->auto_onroute = LOCO_OR_STOPWAIT;
server->railways.UnLockWay(loco->auto_way, loco->name);
strncpy (loco->blockassign, loco->blocknext, REFERENCENAME_LEN);
loco->blocknext[0] = 0;
timer_start(&loco->auto_timenext);
}
}
else if (loco->auto_onroute == LOCO_OR_STOPWAIT) {
if (loco->auto_timenext.tv_sec == 0 || timer_get(&loco->auto_timenext) > 5000) {
loco->auto_onroute = LOCO_OR_SEARCH;
}
}
}
}
return 0;
}
int Locomotives::Test(string loco) {
int res = 0;
int i;
printf ("%s:%d LocoTest.\n", __FILE__, __LINE__);
for (i = 0; i < max; i++) if (locomotives[i].name[0] != 0)
if (loco.compare(locomotives[i].name) == 0) {
res = AutoCheckWaySingleStep(locomotives[i].auto_way, loco);
}
printf ("%s:%d LocoTest ---> Return %d\n", __FILE__, __LINE__, res);
return 0;
};