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/z21emu/z21emu.cc

297 lines
7.0 KiB

#include <stdio.h>
#include <stdlib.h>
#include <string>
#include "config.h"
#include "udp.h"
#include "debug.h"
#include "z21prot.h"
#include "z21emu.h"
#include "i2csensor.h"
using namespace std;
struct s_rbussensor rbus[RBUS_MAXSENSORBYTES] = { 0 };
struct s_xlanturnout xlturn[XLAN_TURNOUT_MAX] = { 0 };
void i2cloop(I2C *i2c);
void i2cscan(I2C *i2c);
void i2ccfgprint();
int i2ccfgload(const char *fname);
int debug = 0;
void help();
int main (int argc, char **argv) {
// time_t t1, t2;
string cfgfile = DEFAULT_CONFIG;
Z21Server z21server;
I2C i2c;
int i;
int numofclients = 0;
for (i = 1; i < argc; i++) {
if (strcmp (argv[i], "-help") == 0) {
help();
exit (0);
}
if (strcmp (argv[i], "-scan") == 0) {
i2cscan(&i2c);
i2ccfgprint();
exit (0);
}
if (strcmp (argv[i], "-debug") == 0) {
debug = 1;
}
if (strcmp (argv[i], "-config") == 0) {
i++;
cfgfile = argv[i];
printf ("using configfile: %s\n", cfgfile.c_str());
}
}
if (i2ccfgload(cfgfile.c_str()) == 0) {
i2cscan(&i2c);
}
z21server.Start();
while ( 1 ) {
//
// for detection of changed values
for (i = 0; i < RBUS_MAXSENSORBYTES; i++)
rbus[i].last = rbus[i].status;
/* t2 = time (NULL);
if (t2-t1 > 1) {
rbus_status[2]++;
rbus_status[15]--;
t1 = t2;
}
*/
if (numofclients > 0) i2cloop (&i2c);
numofclients = z21server.Loop();
usleep(25000);
};
return 0;
};
void i2cloop (I2C *i2c) {
int index; // sensorbox number --> sbox + 0x30 = i2c address
//
// digital in
for (index = 0; index < RBUS_MAXSENSORBYTES; index++) {
if (rbus[index].i2c_addr != 0) {
if (!i2c->ReadByte(rbus[index].i2c_addr, rbus[index].i2c_reg, &rbus[index].status)) {
if (debug) printf ("i2cloop: Read ADDR:%02x REG:%02x Value:%2x Error\n", rbus[index].i2c_addr, rbus[index].i2c_reg, rbus[index].status);
rbus[index].status = 0xFF; // error
}
else if (debug) {
printf ("i2cloop: Read ADDR:%02x REG:%02x Value:%2x\n", rbus[index].i2c_addr, rbus[index].i2c_reg, rbus[index].status);
}
}
}
//
// digital out
for (index = 0; index < XLAN_TURNOUTBYTES; index++) {
if (xlturn[index].last != xlturn[index].output) {
// ignore if addr is not set
if (xlturn[index].i2c_addr == 0) xlturn[index].last = xlturn[index].output;
// send data
else if (i2c->SendByte(xlturn[index].i2c_addr, xlturn[index].i2c_reg, xlturn[index].output)) {
xlturn[index].last = xlturn[index].output;
}
}
}
}
//
// scan all i2c devices read version and create configuration
void i2cscan(I2C *i2c) {
int dicnt;
int docnt;
int addr;
unsigned char ver;
for (dicnt = 0, docnt = 0, addr = 0x20; addr < 0x7f; addr++) {
if (i2c->ReadByte(addr, 0x20, &ver)) {
if (ver == 1) {
if (dicnt < RBUS_MAXSENSORBYTES) {
rbus[dicnt].i2c_addr = addr;
rbus[dicnt].i2c_reg = 0x0;
dicnt++;
}
if (dicnt < RBUS_MAXSENSORBYTES) {
rbus[dicnt].i2c_addr = addr;
rbus[dicnt].i2c_reg = 0x1;
dicnt++;
}
}
else if (ver == 2) {
if (dicnt < RBUS_MAXSENSORBYTES) {
rbus[dicnt].i2c_addr = addr;
rbus[dicnt].i2c_reg = 0x0;
dicnt++;
}
if (docnt < RBUS_MAXSENSORBYTES) {
xlturn[docnt].i2c_addr = addr;
xlturn[docnt].i2c_reg = 0x1;
docnt++;
}
}
else if (ver == 3 || ver == 4) {
if (dicnt < RBUS_MAXSENSORBYTES) {
rbus[dicnt].i2c_addr = addr;
rbus[dicnt].i2c_reg = 0x0;
dicnt++;
}
if (dicnt < RBUS_MAXSENSORBYTES) {
rbus[dicnt].i2c_addr = addr;
rbus[dicnt].i2c_reg = 0x1;
dicnt++;
}
if (dicnt < RBUS_MAXSENSORBYTES) {
rbus[dicnt].i2c_addr = addr;
rbus[dicnt].i2c_reg = 0x2;
dicnt++;
}
if (dicnt < RBUS_MAXSENSORBYTES) {
rbus[dicnt].i2c_addr = addr;
rbus[dicnt].i2c_reg = 0x3;
dicnt++;
}
}
}
}
};
void i2ccfgprint() {
int i;
printf ("# autoscan configuration\n");
printf ("#\n");
printf ("# digital input configuration\n");
printf ("#\n");
printf ("# di NUM addr ADDR reg REG\n");
for (i = 0; i < RBUS_MAXSENSORBYTES; i++) if (rbus[i].i2c_addr != 0)
printf ("di %d addr %x reg %x\n", i, rbus[i].i2c_addr, rbus[i].i2c_reg);
printf ("#\n");
printf ("# digital output configuration\n");
printf ("#\n");
printf ("# do NUM addr ADDR reg REG\n");
for (i = 0; i < XLAN_TURNOUTBYTES; i++) if (xlturn[i].i2c_addr != 0)
printf ("do %d addr %x reg %x\n", i, xlturn[i].i2c_addr, xlturn[i].i2c_reg);
};
#define STR_TOK_NOSPACE(_pnt_) while (_pnt_[0] != 0 && (_pnt_[0] == ' ' || _pnt_[0] == '\t')) _pnt_++
#define STR_TOK_NEXT(_pnt_) while (_pnt_[0] != 0 && _pnt_[0] != ' ' && _pnt_[0] != '\t') _pnt_++
int i2ccfgload(const char *fname) {
FILE *f;
char buf[1024];
char *pos;
int index = -1;
int type;
int addr;
int reg;
printf ("loading file: %s\n", fname);
f = fopen (fname, (char*)"r");
if (f == NULL) {
printf ("error:%s\n", strerror(errno));
return 0;
}
while (fgets (buf, sizeof (buf), f) != NULL) {
pos = buf;
if (pos[0] == '#') continue;
type = I2CREGTYPE_UNDEF;
addr = 0;
reg = 0;
index = -1;
while (pos != NULL && pos[0] != 0) {
STR_TOK_NOSPACE(pos);
if (strncmp ("di", pos, strlen ("di")) == 0) {
STR_TOK_NEXT(pos);
sscanf (pos, "%d", &index);
type = I2CREGTYPE_DI;
printf (" di %d", index);
}
if (strncmp ("do", pos, strlen ("do")) == 0) {
STR_TOK_NEXT(pos);
sscanf (pos, "%d", &index);
type = I2CREGTYPE_DO;
printf (" do %d", index);
}
if (strncmp ("addr", pos, strlen ("addr")) == 0) {
STR_TOK_NEXT(pos);
sscanf (pos, "%x", &addr);
printf (" addr %x", addr);
}
if (strncmp ("reg", pos, strlen ("reg")) == 0) {
STR_TOK_NEXT(pos);
sscanf (pos, "%x", &reg);
printf (" reg %x", reg);
}
else STR_TOK_NEXT(pos);
}
if (type == I2CREGTYPE_DI && index >= 0 && index < RBUS_MAXSENSORBYTES) {
rbus[index].i2c_addr = addr;
rbus[index].i2c_reg = reg;
printf ("--> DI (%d) OK\n", index);
}
else if (type == I2CREGTYPE_DO && index >= 0 && index < XLAN_TURNOUTBYTES) {
xlturn[index].i2c_addr = addr;
xlturn[index].i2c_reg = reg;
printf ("--> DO (%d) OK\n", index);
}
else {
printf (" error\n");
}
}
fclose (f);
return 0;
};
#undef STR_TOK_NEXT
void help () {
printf ("z21emu:\n");
printf ("=======\n");
printf ("\n");
printf ("parameters: without any parameters the config will be read from file.\n");
printf (" if no file is found, autoscan is used first.\n");
printf (" -scan scanning i2c bus and print out a sample device config\n");
printf (" -debug enabling debugging\n");
printf (" -config FILE finename used for configuration (default %s/\n", DEFAULT_CONFIG);
printf ("\n");
}
void xlan_turnout (int addr, bool enable) {
int addrbyte = (addr-1)/8;
int bit = (addr-1)%8;
if (addr == 0) return;
if (addrbyte < 0 || addrbyte >= XLAN_TURNOUTBYTES) return;
if (enable) xlturn[addrbyte].output |= (1 << bit);
else xlturn[addrbyte].output &= ~(1 << bit);
}