Compare commits
85 Commits
Author | SHA1 | Date |
---|---|---|
|
519b59e215 | 9 months ago |
|
d6c4907557 | 2 years ago |
|
b370dbf930 | 2 years ago |
|
63e9778929 | 2 years ago |
|
4a4735ab33 | 2 years ago |
|
48922c20ea | 2 years ago |
|
b24a76aa72 | 2 years ago |
|
4990065ada | 2 years ago |
|
f0bf67f740 | 2 years ago |
|
2df7d6e032 | 2 years ago |
|
0845f417d2 | 2 years ago |
|
1018ec5990 | 2 years ago |
|
54e3342a5e | 2 years ago |
|
d4efc193c7 | 2 years ago |
|
0c73a38dc8 | 2 years ago |
|
db27a5a02a | 3 years ago |
|
67c73836f8 | 3 years ago |
|
0a446a26df | 4 years ago |
|
9b1eb38f29 | 4 years ago |
|
206871b2c0 | 4 years ago |
|
8ce86bbbee | 4 years ago |
|
27d89c3ffa | 4 years ago |
|
115615e853 | 4 years ago |
|
a82dc79ea8 | 4 years ago |
|
5e1142e4e2 | 4 years ago |
|
8d44d32e6b | 4 years ago |
|
4ae0036c4f | 4 years ago |
|
0bdaeaa5e4 | 4 years ago |
|
0b0339b924 | 4 years ago |
|
47ebbf3ada | 4 years ago |
|
0e75d05c14 | 4 years ago |
|
1c5c98752d | 4 years ago |
|
936fb74dcd | 4 years ago |
|
abafaec083 | 4 years ago |
|
ad14dc0428 | 4 years ago |
|
c16145bedb | 4 years ago |
|
23253e6840 | 4 years ago |
|
574552eae8 | 4 years ago |
|
5f41ef2ec5 | 4 years ago |
|
1fa6c2f02f | 4 years ago |
|
4ae0eb60e8 | 4 years ago |
|
e13f9dec8b | 4 years ago |
|
deadf57961 | 4 years ago |
|
30eff69499 | 4 years ago |
|
a0b390886f | 4 years ago |
|
dc48847baf | 4 years ago |
|
6e926f9b2f | 5 years ago |
|
181898259c | 5 years ago |
|
98d1d04207 | 5 years ago |
|
11dab29de7 | 5 years ago |
|
5843b0d365 | 5 years ago |
|
4e68939126 | 5 years ago |
|
f1580d3713 | 5 years ago |
|
9c633da3ec | 5 years ago |
|
c2493ab90e | 5 years ago |
|
0585a8c367 | 5 years ago |
|
3970afd8c8 | 5 years ago |
|
c2d69e3014 | 5 years ago |
|
39ff08c896 | 5 years ago |
|
c0eb61ed8b | 5 years ago |
|
1bb15da346 | 5 years ago |
|
50cef93a49 | 5 years ago |
|
62f450ba97 | 5 years ago |
|
b5a6396a18 | 5 years ago |
|
22d750a63a | 5 years ago |
|
277e8934b2 | 5 years ago |
|
36a930c06d | 5 years ago |
|
25a6b63541 | 5 years ago |
|
e9070992d9 | 5 years ago |
|
686570b9ad | 5 years ago |
|
c9fb7383e0 | 5 years ago |
|
dc7bbe8099 | 5 years ago |
|
5987dde99b | 5 years ago |
|
7d66e1a77e | 5 years ago |
|
db2196b709 | 5 years ago |
|
87a3a7abfa | 5 years ago |
|
ddb0e30e01 | 5 years ago |
|
976a1fc281 | 5 years ago |
|
8a05671f60 | 5 years ago |
|
e30f480973 | 5 years ago |
|
f493c40816 | 6 years ago |
|
3ffbeee7f0 | 6 years ago |
|
3009c38ac9 | 6 years ago |
|
12441ee0fb | 6 years ago |
|
ebe25b2b87 | 6 years ago |
@ -0,0 +1,24 @@
|
||||
.cproject
|
||||
.project
|
||||
.settings
|
||||
gmon.out
|
||||
*/.depend
|
||||
server/gmon.out
|
||||
server/modelbahn-cgi
|
||||
server/modelbahn-server
|
||||
server/test-json
|
||||
z21emu/gmon.out
|
||||
z21emu/config.h
|
||||
z21emu/z21emu
|
||||
*~
|
||||
*.oo
|
||||
*.o
|
||||
*.elf
|
||||
*.bin
|
||||
track.json
|
||||
track.json.backup.*
|
||||
Modelbahn.anjuta
|
||||
*.track.json
|
||||
Backup/
|
||||
.anjuta_sym_db.db
|
||||
.anjuta/
|
@ -1,7 +1,3 @@
|
||||
|
||||
2020-02-09:
|
||||
- Züge fahren falsch herrum
|
||||
- Speed und Fahrtrichtung werden nicht in den Zügen geupdated
|
||||
- Max Speed ist nicht gleich der Maximalste Step
|
||||
|
||||
|
||||
|
@ -0,0 +1,9 @@
|
||||
TOPTARGETS := all clean
|
||||
|
||||
SUBDIRS := server
|
||||
|
||||
$(TOPTARGETS): $(SUBDIRS)
|
||||
$(SUBDIRS):
|
||||
$(MAKE) -C $@ $(MAKECMDGOALS)
|
||||
|
||||
.PHONY: $(TOPTARGETS) $(SUBDIRS)
|
@ -0,0 +1,34 @@
|
||||
# Modelbahn
|
||||
|
||||
## Requirements:
|
||||
Webserver with CGI enabled
|
||||
|
||||
|
||||
## Installation:
|
||||
+ copy the webinterface files to your location of the webserver
|
||||
+ compile the server
|
||||
+ copy the modelbahn-cgi binary to the cgi folder of the webserver
|
||||
+ run the modelbahn-server application.
|
||||
|
||||

|
||||
|
||||
|
||||
## Z21EMU and ATmega Sensors
|
||||
|
||||
Per default all devices get the same I2C defive address. As soon as the device is connected you should set up a new address for them. The following commands will set the device [0x2f] to address 0x31 and save this setting in the EPROM.
|
||||
|
||||
i2cset -y 1 0x2f 0x22 0x31
|
||||
i2cset -y 1 0x2f 0x21 0x02
|
||||
|
||||
The following registers are used:
|
||||
|
||||
0x00 .. 0x08 INPUT and OUTPUT registers dependung on device
|
||||
0x20 VERSION of the device
|
||||
0x21 Command Register
|
||||
0 no command
|
||||
1 EEPROM read
|
||||
2 EEPORM write
|
||||
0x22 I2C Address
|
||||
0x23 Input Off Delay
|
||||
|
||||
|
@ -1,11 +0,0 @@
|
||||
|
||||
Requirements:
|
||||
- Webserver with CGI enabled
|
||||
|
||||
|
||||
Installation:
|
||||
- copy the webinterface files to your location of the webserver
|
||||
- compile the server
|
||||
- copy the modelbahn-cgi binary to the cgi folder of the webserver
|
||||
- run the modelbahn-server application.
|
||||
|
Binary file not shown.
@ -0,0 +1,293 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "modelbahn.h"
|
||||
#include "interface.h"
|
||||
#include "interface-z21.h"
|
||||
#include "interfaces.h"
|
||||
|
||||
|
||||
// **************************************************************************
|
||||
// *
|
||||
// * I N T E R F A C E S (gateway to all devices)
|
||||
// *
|
||||
// **************************************************************************
|
||||
|
||||
Interfaces::Interfaces () {
|
||||
max = INTERFACES_MAX;
|
||||
pthread_mutex_init(&mtx, NULL);
|
||||
|
||||
for (int i = 0; i < max; i++) interfaces[i] = NULL;
|
||||
changed = 0;
|
||||
};
|
||||
|
||||
Interfaces::~Interfaces() {
|
||||
max = 0;
|
||||
};
|
||||
|
||||
|
||||
int Interfaces::LockThread() {
|
||||
if (pthread_mutex_lock(&mtx) == 0) return 1;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
|
||||
int Interfaces::UnLockThread() {
|
||||
if (pthread_mutex_unlock(&mtx) == 0) return 1;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
|
||||
JSONParse Interfaces::_GetJSON(int idx) {
|
||||
JSONParse json;
|
||||
JSONElement je;
|
||||
string s = "";
|
||||
|
||||
json.Clear();
|
||||
|
||||
if (interfaces[idx] != NULL) {
|
||||
s = interfaces[idx]->name; json.AddObject("name", s);
|
||||
s = interfaces[idx]->host; json.AddObject("host", s);
|
||||
json.AddObject("flags", interfaces[idx]->flags);
|
||||
json.AddObject("type", interfaces[idx]->type);
|
||||
}
|
||||
|
||||
return json;
|
||||
};
|
||||
|
||||
|
||||
JSONParse Interfaces::GetJSON(string name) {
|
||||
int i;
|
||||
JSONParse jp;
|
||||
|
||||
jp.Clear();
|
||||
|
||||
LockThread();
|
||||
for (i = 0; i < max; i++) if (interfaces[i] != NULL){
|
||||
if (interfaces[i]->name[0] != 0) {
|
||||
if (name.compare(interfaces[i]->name) == 0) {
|
||||
jp = _GetJSON(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
UnLockThread();
|
||||
|
||||
return jp;
|
||||
};
|
||||
|
||||
|
||||
void Interfaces::GetJSONAll(JSONParse *json) {
|
||||
int i, cnt;
|
||||
JSONElement je;
|
||||
|
||||
LockThread();
|
||||
|
||||
//
|
||||
// write all railway data
|
||||
// create json object array manualy
|
||||
je.type = JSON_T_ARRAY;
|
||||
je.name = "interfaces";
|
||||
for (cnt = 0, i = 0; i < max; i++) if(interfaces[i] != NULL)
|
||||
if (interfaces[i]->name[0] != 0) {
|
||||
if (cnt != 0) je.value += ","; // not first element
|
||||
je.value += _GetJSON(i).ToString();
|
||||
cnt++;
|
||||
}
|
||||
json->AddObject(je);
|
||||
|
||||
UnLockThread();
|
||||
};
|
||||
|
||||
|
||||
Interface Interfaces::GetInterfaceFromJSON(JSONParse *j) {
|
||||
Interface i;
|
||||
string s;
|
||||
|
||||
i.name[0] = 0;
|
||||
i.host[0] = 0;
|
||||
|
||||
j->GetValue("name", &s);
|
||||
strncpy (i.name, s.c_str(), REFERENCENAME_LEN);
|
||||
j->GetValue("host", &s);
|
||||
strncpy (i.host, s.c_str(), REFERENCENAME_LEN);
|
||||
j->GetValueInt("flags", &i.flags);
|
||||
j->GetValueInt("type", &i.type);
|
||||
|
||||
return i;
|
||||
};
|
||||
|
||||
|
||||
int Interfaces::Change(Interface *iface) {
|
||||
int i;
|
||||
int ifree = -1;
|
||||
|
||||
printf ("Interface Type:%d\n", iface->type);
|
||||
|
||||
LockThread();
|
||||
for (i = 0; i < max; i++) {
|
||||
if (interfaces[i] != NULL) {
|
||||
// found element
|
||||
if (strncmp(interfaces[i]->name, iface->name, REFERENCENAME_LEN) == 0) {
|
||||
delete interfaces[i];
|
||||
interfaces[i] = NULL;
|
||||
ifree = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (ifree == -1) ifree = i;
|
||||
}
|
||||
|
||||
// element found or we need to add the element.
|
||||
if (ifree != -1 && ifree < max) {
|
||||
if (iface->type == INTF_T_Z21) interfaces[ifree] = new InterfaceZ21();
|
||||
else interfaces[ifree] = new Interface();
|
||||
strncpy (interfaces[ifree]->name, iface->name, REFERENCENAME_LEN);
|
||||
strncpy (interfaces[ifree]->host, iface->host, REFERENCENAME_LEN);
|
||||
interfaces[ifree]->flags = iface->flags;
|
||||
interfaces[ifree]->type = iface->type;
|
||||
interfaces[ifree]->Connect();
|
||||
}
|
||||
changed = 1;
|
||||
UnLockThread();
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
|
||||
int Interfaces::Delete(string name) {
|
||||
int i;
|
||||
|
||||
LockThread();
|
||||
for (i = 0; i < max; i++) if (interfaces[i] != NULL) {
|
||||
if (name.compare(interfaces[i]->name) == 0) {
|
||||
interfaces[i]->Disconnect();
|
||||
interfaces[i]->name[0] = 0;
|
||||
interfaces[i]->host[0] = 0;
|
||||
interfaces[i]->flags = 0;
|
||||
interfaces[i]->type = INTF_T_OFF_UNKNOWN;
|
||||
delete interfaces[i];
|
||||
interfaces[i] = NULL;
|
||||
changed = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UnLockThread();
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
|
||||
void Interfaces::PowerOnOff(int onoff) {
|
||||
int i;
|
||||
|
||||
LockThread();
|
||||
|
||||
for (i = 0; i < max; i++) if (interfaces[i] != NULL) {
|
||||
if (!interfaces[i]->IsConnected()) interfaces[i]->Connect();
|
||||
interfaces[i]->PowerOnOff(onoff);
|
||||
}
|
||||
|
||||
UnLockThread();
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Turnouts
|
||||
//
|
||||
void Interfaces::SetTurnout(Turnout *t, int active, int motoractive) {
|
||||
int i;
|
||||
|
||||
if (t == NULL) return;
|
||||
|
||||
LockThread();
|
||||
debug (0, "%s:%d Interfaces::SetTurnout Name:%s active:%d Output%d", __FILE__, __LINE__, t->name, active, motoractive);
|
||||
|
||||
//
|
||||
// if the interfacename is debug ... simulate a change in the turnout
|
||||
//
|
||||
if (strncmp(t->ifname, "DEBUG", REFERENCENAME_LEN) == 0) {
|
||||
if (active) t->flags |= TURNOUT_F_ACTIVE;
|
||||
else t->flags &= ~TURNOUT_F_ACTIVE;
|
||||
|
||||
server->TurnoutAddrMode(t->ifname, t->addr, active);
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < max; i++) if (interfaces[i] != NULL) {
|
||||
if (!interfaces[i]->IsConnected()) interfaces[i]->Connect();
|
||||
if (strncmp(t->ifname, interfaces[i]->name, REFERENCENAME_LEN) == 0)
|
||||
interfaces[i]->SetTurnout(t, active, motoractive);
|
||||
}
|
||||
}
|
||||
|
||||
UnLockThread();
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Locomotives
|
||||
//
|
||||
void Interfaces::SetLocoSpeed(Locomotive *l, int speed) {
|
||||
int i;
|
||||
int step = 0, maxstep = 0;
|
||||
|
||||
debug (0, "Interfaces::SetLocoSpeed Loco:'%s' Speed:%d", l->name, speed);
|
||||
|
||||
switch(l->stepcode) {
|
||||
case LOCO_INT_DCC14: maxstep = 14; break;
|
||||
case LOCO_INT_DCC28: maxstep = 28; break;
|
||||
case LOCO_INT_DCC128: maxstep = 126; break;
|
||||
default: maxstep = 0; break;
|
||||
}
|
||||
|
||||
if (abs(speed) < l->vmin) step = 0;
|
||||
if (abs(speed) >= l->vmin) step = (speed * (maxstep)) / l->vmax;
|
||||
if (abs(speed) > l->vmax) step = maxstep;
|
||||
|
||||
l->speed = speed;
|
||||
|
||||
LockThread();
|
||||
|
||||
for (i = 0; i < max; i++) if (interfaces[i] != NULL) {
|
||||
if (!interfaces[i]->IsConnected()) interfaces[i]->Connect();
|
||||
if (strncmp(l->ifname, interfaces[i]->name, REFERENCENAME_LEN) == 0)
|
||||
interfaces[i]->SetLocoSpeed(l, step);
|
||||
}
|
||||
|
||||
UnLockThread();
|
||||
};
|
||||
|
||||
|
||||
void Interfaces::SetLocoFunction(Locomotive *l, int func, int value) {
|
||||
int i;
|
||||
|
||||
debug (0, "Interfaces::SetLocoFunction Loco:'%s' Function:%d Value:%d", l->name, func, value);
|
||||
|
||||
LockThread();
|
||||
|
||||
for (i = 0; i < max; i++) if (interfaces[i] != NULL) {
|
||||
if (!interfaces[i]->IsConnected()) interfaces[i]->Connect();
|
||||
if (strncmp(l->ifname, interfaces[i]->name, REFERENCENAME_LEN) == 0)
|
||||
interfaces[i]->SetLocoFunction(l, func, value);
|
||||
}
|
||||
|
||||
UnLockThread();
|
||||
};
|
||||
|
||||
|
||||
|
||||
void Interfaces::Loop() {
|
||||
int i;
|
||||
JSONParse jout;
|
||||
|
||||
for (i = 0; i < max; i++) if (interfaces[i] != NULL) {
|
||||
if (interfaces[i]->Loop()) {
|
||||
//
|
||||
// now we need to send an update
|
||||
jout.Clear();
|
||||
jout.AddObject ("interface", _GetJSON(i));
|
||||
if (network) network->ChangeListPushToAll(jout.ToString());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -0,0 +1,61 @@
|
||||
|
||||
#ifndef _INTERFACES_H_
|
||||
#define _INTERFACES_H_
|
||||
|
||||
#include "modelbahn.h"
|
||||
#include "server.h"
|
||||
#include "UDPTCPNetwork.h"
|
||||
#include "json.h"
|
||||
#include "interface.h"
|
||||
#include "interfaces.h"
|
||||
|
||||
#define INTF_F_CONNECTED 0x0001
|
||||
#define INTF_F_POWER 0x0002
|
||||
#define INTF_F_STOP 0x0004
|
||||
#define INTF_F_SHORT_CIRCUIT 0x0008
|
||||
#define INTF_F_PROGRAMMING 0x0010
|
||||
#define INTF_F_NEEDUPDATE 0x8000 // if something changes during the Loop
|
||||
|
||||
enum {
|
||||
INTF_T_OFF_UNKNOWN = 0,
|
||||
INTF_T_Z21,
|
||||
INTF_T_MAX
|
||||
};
|
||||
|
||||
class Interfaces {
|
||||
private:
|
||||
Interface *interfaces[INTERFACES_MAX];
|
||||
int max;
|
||||
int changed;
|
||||
|
||||
pthread_mutex_t mtx;
|
||||
int LockThread();
|
||||
int UnLockThread();
|
||||
|
||||
// not thread safe
|
||||
JSONParse _GetJSON(int idx);
|
||||
public:
|
||||
Interfaces();
|
||||
~Interfaces();
|
||||
|
||||
bool IsChanged() { return changed; }
|
||||
void ClearChanged() { changed = 0; };
|
||||
|
||||
int Change(Interface *iface);
|
||||
int Delete(string name);
|
||||
|
||||
JSONParse GetJSON(string name);
|
||||
void GetJSONAll(JSONParse *json);
|
||||
Interface GetInterfaceFromJSON(JSONParse *j);
|
||||
|
||||
//
|
||||
//
|
||||
void PowerOnOff(int onoff);
|
||||
void SetLocoSpeed(Locomotive *l, int speed);
|
||||
void SetLocoFunction(Locomotive *l, int func, int value);
|
||||
void SetTurnout(Turnout *t, int active, int outputactive);
|
||||
|
||||
void Loop();
|
||||
};
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,9 +0,0 @@
|
||||
|
||||
function debug (t) {
|
||||
var pre = document.getElementById("debug");
|
||||
var div = document.getElementById("debug_div");
|
||||
|
||||
if (pre) pre.innerHTML = pre.innerHTML + "<br>" + t;
|
||||
if (div) div.scrollTop = div.scrollHeight;
|
||||
};
|
||||
|
After Width: | Height: | Size: 6.7 KiB |
After Width: | Height: | Size: 5.6 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 6.7 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 6.8 KiB |
@ -0,0 +1,123 @@
|
||||
# .SILENT:
|
||||
|
||||
DEPENDFILE=.depend
|
||||
VERSION=0.1
|
||||
|
||||
#
|
||||
# default configuration
|
||||
# after chaning run make config
|
||||
# default ports: 21105, 21106 and 3472?
|
||||
PREFIX=/usr/local
|
||||
DATAPREFIX=/var/lib
|
||||
RUNPID=/var/run/z21Emulation.pid
|
||||
ETCPREFIX=/etc
|
||||
# DEFAULT_Z21PORT=21105
|
||||
DEFAULT_Z21PORT=21104
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
ifndef CXX
|
||||
CXX=g++
|
||||
endif
|
||||
#CXX=/data/CreateImages/RaspberryPi/tools/arm-bcm2708/arm-bcm2708-linux-gnueabi/bin/arm-bcm2708-linux-gnueabi-g++
|
||||
CXXFLAGS= -ggdb -fPIC -Wall -pg
|
||||
LDFLAGS= -lm -lc -pg
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
all: dep z21emu
|
||||
|
||||
# install: $(OBJSLAVES) collect-master collectd
|
||||
# cp -rf collectd $(PREFIX)/bin
|
||||
# cp -rf collect-master $(PREFIX)/bin
|
||||
# $(foreach i,$(OBJSLAVES), cp -rf $(i) $(PREFIX)/bin;)
|
||||
#
|
||||
# mkdir -p $(ETCPREFIX)/collect
|
||||
# $(foreach i,$(shell ls *.conf.sample), cp -rvf $(i) $(ETCPREFIX)/collect/;)
|
||||
# $(foreach i,$(shell ls *.map), cp -rvf $(i) $(ETCPREFIX)/collect/;)
|
||||
# $(foreach i,$(shell ls *.conf), echo $(i);)
|
||||
# mkdir -p $(DATAPREFIX)/collect
|
||||
#
|
||||
#
|
||||
# installinitd: install
|
||||
# cp -rf collectd.sh /etc/init.d
|
||||
# ln -fs ../init.d/collectd.sh /etc/rc2.d/S20collectd.sh
|
||||
# ln -fs ../init.d/collectd.sh /etc/rc0.d/K10collectd.sh
|
||||
# ln -fs ../init.d/collectd.sh /etc/rc1.d/K10collectd.sh
|
||||
# ln -fs ../init.d/collectd.sh /etc/rc6.d/K10collectd.sh
|
||||
#
|
||||
# uninstall:
|
||||
# rm -rf $(PREFIX)/bin/collectd
|
||||
# rm -rf $(PREFIX)/bin/collect-master
|
||||
# rm -rf /etc/init.d/collectd.sh
|
||||
# rm -rf /etc/rc2.d/S10collectd.sh
|
||||
# rm -rf /etc/rc0.d/K10collectd.sh
|
||||
# rm -rf /etc/rc1.d/K10collectd.sh
|
||||
# rm -rf /etc/rc6.d/K10collectd.sh
|
||||
#
|
||||
# $(foreach i,$(OBJSLAVES), rm -rf $(PREFIX)/bin/$(i);)
|
||||
# # rm -rf $(ETCPREFIX)/collect
|
||||
#
|
||||
|
||||
z21emu: z21emu.o udp.o debug.o z21prot.o i2csensor.o
|
||||
$(CXX) $^ -o $@ $(LDFLAGS)
|
||||
|
||||
|
||||
config:
|
||||
echo "#ifndef _CONFIG_H_" > config.h
|
||||
echo "#define _CONFIG_H_" >> config.h
|
||||
echo "" >> config.h
|
||||
echo "#define VERSION \"$(VERSION)\"" >> config.h
|
||||
echo "" >> config.h
|
||||
echo "#define PREFIX \"$(PREFIX)\"" >> config.h
|
||||
echo "#define RUNPID \"$(RUNPID)\"" >> config.h
|
||||
echo "#define DATAPREFIX \"$(DATAPREFIX)\"" >> config.h
|
||||
echo "#define ETCPREFIX \"$(ETCPREFIX)\"" >> config.h
|
||||
echo "" >> config.h
|
||||
echo "#define DEFAULT_Z21PORT $(DEFAULT_Z21PORT)" >> config.h
|
||||
echo "" >> config.h
|
||||
# ifeq ($(HAVE_SIMPLEHD),1)
|
||||
# echo "#define HAVE_SIMPLEHD 1" >> config.h
|
||||
# else
|
||||
# echo "// #define HAVE_SIMPLEHD 1" >> config.h
|
||||
# endif
|
||||
echo "" >> config.h
|
||||
|
||||
echo "#endif" >> config.h
|
||||
|
||||
rebuild: clean all
|
||||
|
||||
dep:
|
||||
$(CXX) -MM `ls *.cc` $(CXXFLAGS) > $(DEPENDFILE)
|
||||
|
||||
dist:
|
||||
mkdir z21emu-$(VERSION)
|
||||
cp -rf *.conf.sample z21emu-$(VERSION)/
|
||||
cp -rf *.cc z21emu-$(VERSION)/
|
||||
cp -rf *.h z21emu-$(VERSION)/
|
||||
cp -rf *.sh z21emu-$(VERSION)/
|
||||
cp -rf Makefile z21emu-$(VERSION)/
|
||||
cp -rf INSTALL z21emu-$(VERSION)/
|
||||
tar cvzf z21emu-$(VERSION).tgz z21emu-$(VERSION)
|
||||
rm -rf z21emu-$(VERSION)
|
||||
|
||||
clean:
|
||||
rm *.s -rf
|
||||
rm *.o -rf
|
||||
rm *.oo -rf
|
||||
rm *~ -rf
|
||||
rm -rf .depend
|
||||
rm -rf *.so
|
||||
rm -rf *.so.*
|
||||
rm -rf z21emu
|
||||
rm -rf gmon.out
|
||||
rm -rf config.h
|
||||
rm -rf Makefile.rules
|
||||
|
||||
cleanall: clean
|
||||
|
||||
source: cleanall
|
||||
|
||||
-include $(DEPENDFILE)
|
@ -0,0 +1,41 @@
|
||||
# .SILENT:
|
||||
|
||||
# Atmega88
|
||||
# CFLAGS= -Os -g -Wall -mmcu=atmega16 -DF_CPU=8000000UL
|
||||
# LDFLAGS= -mmcu=atmega16
|
||||
|
||||
CPUTYPE1= atmega16
|
||||
CPUTYPE2= m16
|
||||
|
||||
# Atmega32
|
||||
CFLAGS= -Os -g -Wall -mmcu=$(CPUTYPE1) -DF_CPU=16000000UL
|
||||
LDFLAGS= -mmcu=$(CPUTYPE1)
|
||||
|
||||
all: gleiserkennung-v3.bin
|
||||
|
||||
%.o: %.c
|
||||
avr-gcc $(CFLAGS) -c -o $@ $^
|
||||
|
||||
rebuild: clean all
|
||||
|
||||
gleiserkennung-v3.elf: gleiserkennung-v3.o eprom.o
|
||||
avr-gcc $^ -o $@ $(LDFLAGS)
|
||||
|
||||
|
||||
%.bin: %.elf
|
||||
avr-objcopy -j .text -j .data -O binary $^ $@
|
||||
|
||||
clean:
|
||||
rm *.o -rf
|
||||
rm *.bin -rf
|
||||
rm *.elf -rf
|
||||
rm *~ -rf
|
||||
|
||||
cleanall: clean
|
||||
|
||||
source: cleanall
|
||||
|
||||
upload-v3: gleiserkennung-v3.bin
|
||||
avrdude -c avrispmkII -P usb -p $(CPUTYPE2) -v -V -U flash:w:gleiserkennung-v3.bin:r
|
||||
|
||||
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* eprom.c
|
||||
*
|
||||
* Created on: 11.02.2018
|
||||
* Author: steffen
|
||||
*/
|
||||
|
||||
|
||||
#include "eprom.h"
|
||||
|
||||
void EEPROM_write(unsigned int uiAddress, unsigned char ucData) {
|
||||
while(EECR & (1<<EEWE)); // Wait for completion of previous write
|
||||
EEAR = uiAddress; // Set up address and data registers
|
||||
EEDR = ucData;
|
||||
EECR |= (1<<EEMWE); // Write logical one to EEMWE
|
||||
EECR |= (1<<EEWE); // Start eeprom write by setting EEWE
|
||||
}
|
||||
|
||||
|
||||
unsigned char EEPROM_read(unsigned int uiAddress) {
|
||||
while(EECR & (1<<EEWE)); // Wait for completion of previous write
|
||||
EEAR = uiAddress; // Set up address register
|
||||
EECR |= (1<<EERE); // Start eeprom read by writing EERE
|
||||
return EEDR; // return eeprom data register
|
||||
}
|
||||
|
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* eprom.h
|
||||
*
|
||||
* Created on: 11.02.2018
|
||||
* Author: steffen
|
||||
*/
|
||||
|
||||
#ifndef EPROM_H_
|
||||
#define EPROM_H_
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
void EEPROM_write(unsigned int uiAddress, unsigned char ucData);
|
||||
unsigned char EEPROM_read(unsigned int uiAddress);
|
||||
|
||||
|
||||
#endif /* ATMEGA8_DETECT_EPROM_H_ */
|
@ -0,0 +1,283 @@
|
||||
/************************************************************
|
||||
|
||||
* reads some dis and make them readable over i2c bus.
|
||||
*
|
||||
* Atmega 16
|
||||
* +-------+
|
||||
* S26 (XCK/T0) PB0 -|1 O 40|- PA0 (ADC0) S14
|
||||
* S25 (T1) PB1 -|2 39|- PA1 (ADC1) S13
|
||||
* S24 (INT2/AIN0) PB2 -|3 38|- PA2 (ADC2) S12
|
||||
* S23 (OC0/AIN1) PB3 -|4 37|- PA3 (ADC3) S11
|
||||
* S22 (SS) PB4 -|5 36|- PA4 (ADC4) S10
|
||||
* (MOSI) PB5 -|6 35|- PA5 (ADC5) S9
|
||||
* (MISO) PB6 -|7 34|- PA6 (ADC6) S8
|
||||
* (SCK) PB7 -|8 33|- PA7 (ADC7)
|
||||
* RESET -|9 32|- AREF
|
||||
* VCC -|10 31|- GND
|
||||
* GND -|11 30|- AVCC
|
||||
* XTAL2 -|12 29|- PC7 (TOSC2) S7
|
||||
* XTAL1 -|13 28|- PC6 (TOSC1) S6
|
||||
* S21 (RXD) PD0 -|14 27|- PC5 (TDI) S5
|
||||
* S20 (TXD) PD1 -|15 26|- PC4 (TDO) S4
|
||||
* S19 (INT0) PD2 -|16 25|- PC3 (TMS) S3
|
||||
* S18 (INT1) PD3 -|17 24|- PC2 (TCK) S2
|
||||
* S17 (OC1B) PD4 -|18 23|- PC1 (DSA) I2C
|
||||
* S16 (OC1A) PD5 -|19 22|- PC0 (SCL) I2C
|
||||
* S15 (ICP1) PD6 -|20 21|- PD7 (OC2) S1
|
||||
* +-------+ */
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <util/delay.h>
|
||||
#include <util/twi.h>
|
||||
|
||||
#include "eprom.h"
|
||||
|
||||
#define TWCR_ACK TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA);
|
||||
#define TWCR_NACK TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)
|
||||
#define TWCR_RESET TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA)|(1<<TWSTO);
|
||||
|
||||
#define I2C_NUM_REGS 8
|
||||
#define I2C_DEFAULT_ADDR 0x2F
|
||||
#define VERSION 3
|
||||
|
||||
#define I2C_SREGS_OFFSET 0x20
|
||||
|
||||
enum {
|
||||
I2C_SREG_VERSION = 0,
|
||||
I2C_SREG_CMD,
|
||||
I2C_SREG_ADDR,
|
||||
I2C_SREG_DIOFFDELAY,
|
||||
|
||||
I2C_SREG_MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
I2C_CMD_NONE = 0,
|
||||
I2C_CMD_EEPROMREAD,
|
||||
I2C_CMD_EEPROMWRITE
|
||||
};
|
||||
|
||||
volatile uint8_t i2c_reg;
|
||||
volatile uint8_t i2c_system[I2C_SREG_MAX];
|
||||
volatile uint8_t i2c_regs[I2C_NUM_REGS];
|
||||
|
||||
//
|
||||
// i2c slave addresse festlegen und interrupts einschalten
|
||||
void i2c_slave_init(uint8_t adr) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < I2C_NUM_REGS; i++) {
|
||||
i2c_regs[i] = 0;
|
||||
}
|
||||
|
||||
TWAR = adr << 1;
|
||||
TWCR &= ~(1<<TWSTA) | (1<<TWSTO);
|
||||
TWCR |= (1<<TWEA) | (1<<TWEN) | (1<<TWIE);
|
||||
|
||||
i2c_reg = 0x0;
|
||||
|
||||
sei();
|
||||
}
|
||||
|
||||
ISR (TWI_vect) {
|
||||
char data=0;
|
||||
|
||||
switch (TW_STATUS) {
|
||||
case TW_SR_SLA_ACK: // 0x60 Slave Receiver, Slave wurde adressiert
|
||||
TWCR_ACK;
|
||||
i2c_reg=0xFF;
|
||||
break;
|
||||
|
||||
case TW_SR_DATA_ACK: // 0x80 Slave Receiver, ein Datenbyte wurde empfangen
|
||||
data=TWDR;
|
||||
if (i2c_reg == 0xFF) {
|
||||
if(data < I2C_NUM_REGS || (data >= I2C_SREGS_OFFSET && data < I2C_SREGS_OFFSET+I2C_SREG_MAX)) {
|
||||
i2c_reg = data;
|
||||
TWCR_ACK;
|
||||
}
|
||||
else
|
||||
TWCR_NACK;
|
||||
}
|
||||
else {
|
||||
if(i2c_reg < I2C_NUM_REGS) {
|
||||
i2c_regs[i2c_reg] = data;
|
||||
i2c_reg++;
|
||||
TWCR_ACK;
|
||||
}
|
||||
else if (i2c_reg >= I2C_SREGS_OFFSET && i2c_reg < I2C_SREGS_OFFSET+I2C_SREG_MAX) {
|
||||
i2c_system[i2c_reg-I2C_SREGS_OFFSET] = data;
|
||||
i2c_reg++;
|
||||
TWCR_ACK;
|
||||
}
|
||||
else TWCR_NACK;
|
||||
}
|
||||
break;
|
||||
|
||||
case TW_ST_SLA_ACK: //0xA8 Slave wurde im Lesemodus adressiert und hat ein ACK zurückgegeben.
|
||||
case TW_ST_DATA_ACK: //0xB8 Slave Transmitter, Daten wurden angefordert
|
||||
if (i2c_reg == 0xFF) {
|
||||
i2c_reg = 0;
|
||||
}
|
||||
if (i2c_reg < I2C_NUM_REGS) {
|
||||
TWDR = i2c_regs[i2c_reg];
|
||||
i2c_reg++;
|
||||
TWCR_ACK;
|
||||
}
|
||||
else if (i2c_reg >= I2C_SREGS_OFFSET && i2c_reg < I2C_SREGS_OFFSET+I2C_SREG_MAX) {
|
||||
TWDR = i2c_system[i2c_reg-I2C_SREGS_OFFSET];
|
||||
i2c_reg++;
|
||||
TWCR_ACK;
|
||||
}
|
||||
else TWCR_NACK;
|
||||
break;
|
||||
|
||||
case TW_SR_STOP:
|
||||
TWCR_ACK;
|
||||
break;
|
||||
|
||||
case TW_ST_DATA_NACK: // 0xC0 Keine Daten mehr gefordert
|
||||
case TW_SR_DATA_NACK: // 0x88
|
||||
case TW_ST_LAST_DATA: // 0xC8 Last data byte in TWDR has been transmitted (TWEA = “0”); ACK has been received
|
||||
default:
|
||||
TWCR_RESET;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
int main( void ) {
|
||||
uint32_t cnt[32] = { 0 };
|
||||
unsigned int i;
|
||||
uint32_t inval = 0;
|
||||
uint32_t temp = 0;
|
||||
int offdelay;
|
||||
|
||||
//
|
||||
// disable JTAG
|
||||
MCUCSR |= (1<<JTD);
|
||||
MCUCSR |= (1<<JTD);
|
||||
|
||||
// enable inputs
|
||||
DDRA = 0;
|
||||
PORTA = 0xFF;
|
||||
DDRB = 0;
|
||||
PORTB = 0xFF;
|
||||
DDRC = 0;
|
||||
PORTC = 0xFF;
|
||||
DDRD = 0;
|
||||
PORTD = 0xFF;
|
||||
|
||||
//
|
||||
// read all variables from eeprom
|
||||
i2c_system[I2C_SREG_VERSION] = VERSION;
|
||||
i2c_system[I2C_SREG_CMD] = 0;
|
||||
|
||||
i2c_system[I2C_SREG_ADDR] = EEPROM_read(I2C_SREG_ADDR);
|
||||
if (i2c_system[I2C_SREG_ADDR] > 0x4f || i2c_system[I2C_SREG_ADDR] < 0x20) {
|
||||
i2c_system[I2C_SREG_ADDR] = I2C_DEFAULT_ADDR;
|
||||
}
|
||||
|
||||
i2c_system[I2C_SREG_DIOFFDELAY] = EEPROM_read(I2C_SREG_DIOFFDELAY);
|
||||
if (i2c_system[I2C_SREG_DIOFFDELAY] == 0 || i2c_system[I2C_SREG_DIOFFDELAY] == 0xFF) {
|
||||
i2c_system[I2C_SREG_DIOFFDELAY] = 0x20;
|
||||
}
|
||||
|
||||
i2c_slave_init (i2c_system[I2C_SREG_ADDR]);
|
||||
|
||||
for (i = 0; i < 32; i++) cnt[i] = 0;
|
||||
|
||||
//
|
||||
// system loop
|
||||
while( 1 ) {
|
||||
//
|
||||
// digital in registers..
|
||||
offdelay = i2c_system[I2C_SREG_DIOFFDELAY] << 8;
|
||||
|
||||
// S1 - S14
|
||||
i = 0; if (!(PIND & (1 << 7))) cnt[i] = offdelay;
|
||||
i++; if (!(PINC & (1 << 2))) cnt[i] = offdelay;
|
||||
i++; if (!(PINC & (1 << 3))) cnt[i] = offdelay;
|
||||
i++; if (!(PINC & (1 << 4))) cnt[i] = offdelay;
|
||||
i++; if (!(PINC & (1 << 5))) cnt[i] = offdelay;
|
||||
i++; if (!(PINC & (1 << 6))) cnt[i] = offdelay;
|
||||
i++; if (!(PINC & (1 << 7))) cnt[i] = offdelay;
|
||||
|
||||
i++; if (!(PINA & (1 << 6))) cnt[i] = offdelay;
|
||||
i++; if (!(PINA & (1 << 5))) cnt[i] = offdelay;
|
||||
i++; if (!(PINA & (1 << 4))) cnt[i] = offdelay;
|
||||
i++; if (!(PINA & (1 << 3))) cnt[i] = offdelay;
|
||||
i++; if (!(PINA & (1 << 2))) cnt[i] = offdelay;
|
||||
i++; if (!(PINA & (1 << 1))) cnt[i] = offdelay;
|
||||
i++; if (!(PINA & (1 << 0))) cnt[i] = offdelay;
|
||||
|
||||
// S15 - S26
|
||||
i++; if (!(PIND & (1 << 6))) cnt[i] = offdelay;
|
||||
i++; if (!(PIND & (1 << 5))) cnt[i] = offdelay;
|
||||
i++; if (!(PIND & (1 << 4))) cnt[i] = offdelay;
|
||||
i++; if (!(PIND & (1 << 3))) cnt[i] = offdelay;
|
||||
i++; if (!(PIND & (1 << 2))) cnt[i] = offdelay;
|
||||
i++; if (!(PIND & (1 << 1))) cnt[i] = offdelay;
|
||||
i++; if (!(PIND & (1 << 0))) cnt[i] = offdelay;
|
||||
|
||||
i++; if (!(PINB & (1 << 4))) cnt[i] = offdelay;
|
||||
i++; if (!(PINB & (1 << 3))) cnt[i] = offdelay;
|
||||
i++; if (!(PINB & (1 << 2))) cnt[i] = offdelay;
|
||||
i++; if (!(PINB & (1 << 1))) cnt[i] = offdelay;
|
||||
i++; if (!(PINB & (1 << 0))) cnt[i] = offdelay;
|
||||
|
||||
|
||||
// all values
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (cnt[i] == 0) inval &= ~(1 << (i));
|
||||
else {
|
||||
cnt[i]--;
|
||||
inval |= (1 << (i));
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (cnt[16+i] == 0) temp &= ~(1 << (i));
|
||||
else {
|
||||
cnt[16+i]--;
|
||||
temp |= (1 << (i));
|
||||
}
|
||||
}
|
||||
|
||||
i2c_regs[0] = (unsigned char) (inval & 0x000000FF);
|
||||
i2c_regs[1] = (unsigned char) ((inval & 0x0000FF00) >> 8);
|
||||
i2c_regs[2] = (unsigned char) (temp & 0x000000FF);
|
||||
i2c_regs[3] = (unsigned char) ((temp & 0x0000FF00) >> 8);
|
||||
|
||||
|
||||
//
|
||||
// system registers
|
||||
if (i2c_system[I2C_SREG_CMD] != 0) {
|
||||
if (i2c_system[I2C_SREG_CMD] == I2C_CMD_EEPROMREAD) {
|
||||
cli();
|
||||
i2c_system[I2C_SREG_CMD] = 0;
|
||||
for (i = 0; i < I2C_SREG_MAX; i++) {
|
||||
i2c_system[i] = EEPROM_read(i);
|
||||
}
|
||||
sei();
|
||||
}
|
||||
|
||||
if (i2c_system[I2C_SREG_CMD] == I2C_CMD_EEPROMWRITE) {
|
||||
cli();
|
||||
i2c_system[I2C_SREG_CMD] = 0;
|
||||
for (i = 0; i < I2C_SREG_MAX; i++) {
|
||||
EEPROM_write(i, i2c_system[i]);
|
||||
}
|
||||
sei();
|
||||
}
|
||||
}
|
||||
i2c_system[I2C_SREG_CMD] = 0;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
@ -0,0 +1,41 @@
|
||||
# .SILENT:
|
||||
|
||||
# Atmega88
|
||||
# CFLAGS= -Os -g -Wall -mmcu=atmega16 -DF_CPU=8000000UL
|
||||
# LDFLAGS= -mmcu=atmega16
|
||||
|
||||
CPUTYPE1= atmega32
|
||||
CPUTYPE2= m32
|
||||
|
||||
# Atmega32
|
||||
CFLAGS= -Os -g -Wall -mmcu=$(CPUTYPE1) -DF_CPU=16000000UL
|
||||
LDFLAGS= -mmcu=$(CPUTYPE1)
|
||||
|
||||
all: gleiserkennung-v4.bin
|
||||
|
||||
%.o: %.c
|
||||
avr-gcc $(CFLAGS) -c -o $@ $^
|
||||
|
||||
rebuild: clean all
|
||||
|
||||
gleiserkennung-v4.elf: gleiserkennung-v4.o eprom.o
|
||||
avr-gcc $^ -o $@ $(LDFLAGS)
|
||||
|
||||
|
||||
%.bin: %.elf
|
||||
avr-objcopy -j .text -j .data -O binary $^ $@
|
||||
|
||||
clean:
|
||||
rm *.o -rf
|
||||
rm *.bin -rf
|
||||
rm *.elf -rf
|
||||
rm *~ -rf
|
||||
|
||||
cleanall: clean
|
||||
|
||||
source: cleanall
|
||||
|
||||
upload-v4: gleiserkennung-v4.bin
|
||||
avrdude -c avrispmkII -P usb -p $(CPUTYPE2) -v -V -U flash:w:gleiserkennung-v4.bin:r
|
||||
|
||||
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* eprom.c
|
||||
*
|
||||
* Created on: 11.02.2018
|
||||
* Author: steffen
|
||||
*/
|
||||
|
||||
|
||||
#include "eprom.h"
|
||||
|
||||
void EEPROM_write(unsigned int uiAddress, unsigned char ucData) {
|
||||
while(EECR & (1<<EEWE)); // Wait for completion of previous write
|
||||
EEAR = uiAddress; // Set up address and data registers
|
||||
EEDR = ucData;
|
||||
EECR |= (1<<EEMWE); // Write logical one to EEMWE
|
||||
EECR |= (1<<EEWE); // Start eeprom write by setting EEWE
|
||||
}
|
||||
|
||||
|
||||
unsigned char EEPROM_read(unsigned int uiAddress) {
|
||||
while(EECR & (1<<EEWE)); // Wait for completion of previous write
|
||||
EEAR = uiAddress; // Set up address register
|
||||
EECR |= (1<<EERE); // Start eeprom read by writing EERE
|
||||
return EEDR; // return eeprom data register
|
||||
}
|
||||
|
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* eprom.h
|
||||
*
|
||||
* Created on: 11.02.2018
|
||||
* Author: steffen
|
||||
*/
|
||||
|
||||
#ifndef EPROM_H_
|
||||
#define EPROM_H_
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
void EEPROM_write(unsigned int uiAddress, unsigned char ucData);
|
||||
unsigned char EEPROM_read(unsigned int uiAddress);
|
||||
|
||||
|
||||
#endif /* ATMEGA8_DETECT_EPROM_H_ */
|
@ -0,0 +1,281 @@
|
||||
/******************************************************************
|
||||
|
||||
* reads some digital inputs and make them readable over i2c bus.
|
||||
*
|
||||
* Atmega 32
|
||||
* +-------+
|
||||
* S17 (XCK/T0) PB0 -|1 O 40|- PA0 (ADC0) S9
|
||||
* S18 (T1) PB1 -|2 39|- PA1 (ADC1) S10
|
||||
* S19 (INT2/AIN0) PB2 -|3 38|- PA2 (ADC2) S11
|
||||
* S20 (OC0/AIN1) PB3 -|4 37|- PA3 (ADC3) S12
|
||||
* S21 (SS) PB4 -|5 36|- PA4 (ADC4) S13
|
||||
* S22 (MOSI) PB5 -|6 35|- PA5 (ADC5) S14
|
||||
* S23 (MISO) PB6 -|7 34|- PA6 (ADC6) S15
|
||||
* S24 (SCK) PB7 -|8 33|- PA7 (ADC7) S16
|
||||
* RESET -|9 32|- AREF
|
||||
* VCC -|10 31|- GND
|
||||
* GND -|11 30|- AVCC
|
||||
* XTAL2 -|12 29|- PC7 (TOSC2)
|
||||
* XTAL1 -|13 28|- PC6 (TOSC1)
|
||||
* S1 (RXD) PD0 -|14 27|- PC5 (TDI)
|
||||
* S2 (TXD) PD1 -|15 26|- PC4 (TDO)
|
||||
* S3 (INT0) PD2 -|16 25|- PC3 (TMS)
|
||||
* S4 (INT1) PD3 -|17 24|- PC2 (TCK)
|
||||
* S5 (OC1B) PD4 -|18 23|- PC1 (DSA) I2C
|
||||
* S6 (OC1A) PD5 -|19 22|- PC0 (SCL) I2C
|
||||
* S7 (ICP1) PD6 -|20 21|- PD7 (OC2) S8
|
||||
* +-------+ */
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <util/delay.h>
|
||||
#include <util/twi.h>
|
||||
|
||||
#include "eprom.h"
|
||||
|
||||
#define TWCR_ACK TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA);
|
||||
#define TWCR_NACK TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)
|
||||
#define TWCR_RESET TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA)|(1<<TWSTO);
|
||||
|
||||
#define I2C_NUM_REGS 8
|
||||
#define I2C_DEFAULT_ADDR 0x2F
|
||||
#define VERSION 4
|
||||
|
||||
#define I2C_SREGS_OFFSET 0x20
|
||||
|
||||
enum {
|
||||
I2C_SREG_VERSION = 0,
|
||||
I2C_SREG_CMD,
|
||||
I2C_SREG_ADDR,
|
||||
I2C_SREG_DIOFFDELAY,
|
||||
|
||||
I2C_SREG_MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
I2C_CMD_NONE = 0,
|
||||
I2C_CMD_EEPROMREAD,
|
||||
I2C_CMD_EEPROMWRITE
|
||||
};
|
||||
|
||||
volatile uint8_t i2c_reg;
|
||||
volatile uint8_t i2c_system[I2C_SREG_MAX];
|
||||
volatile uint8_t i2c_regs[I2C_NUM_REGS];
|
||||
|
||||
//
|
||||
// i2c slave addresse festlegen und interrupts einschalten
|
||||
void i2c_slave_init(uint8_t adr) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < I2C_NUM_REGS; i++) {
|
||||
i2c_regs[i] = 0;
|
||||
}
|
||||
|
||||
TWAR = adr << 1;
|
||||
TWCR &= ~(1<<TWSTA) | (1<<TWSTO);
|
||||
TWCR |= (1<<TWEA) | (1<<TWEN) | (1<<TWIE);
|
||||
|
||||
i2c_reg = 0x0;
|
||||
|
||||
sei();
|
||||
}
|
||||
|
||||
ISR (TWI_vect) {
|
||||
char data=0;
|
||||
|
||||
switch (TW_STATUS) {
|
||||
case TW_SR_SLA_ACK: // 0x60 Slave Receiver, Slave wurde adressiert
|
||||
TWCR_ACK;
|
||||
i2c_reg=0xFF;
|
||||
break;
|
||||
|
||||
case TW_SR_DATA_ACK: // 0x80 Slave Receiver, ein Datenbyte wurde empfangen
|
||||
data=TWDR;
|
||||
if (i2c_reg == 0xFF) {
|
||||
if(data < I2C_NUM_REGS || (data >= I2C_SREGS_OFFSET && data < I2C_SREGS_OFFSET+I2C_SREG_MAX)) {
|
||||
i2c_reg = data;
|
||||
TWCR_ACK;
|
||||
}
|
||||
else
|
||||
TWCR_NACK;
|
||||
}
|
||||
else {
|
||||
if(i2c_reg < I2C_NUM_REGS) {
|
||||
i2c_regs[i2c_reg] = data;
|
||||
i2c_reg++;
|
||||
TWCR_ACK;
|
||||
}
|
||||
else if (i2c_reg >= I2C_SREGS_OFFSET && i2c_reg < I2C_SREGS_OFFSET+I2C_SREG_MAX) {
|
||||
i2c_system[i2c_reg-I2C_SREGS_OFFSET] = data;
|
||||
i2c_reg++;
|
||||
TWCR_ACK;
|
||||
}
|
||||
else TWCR_NACK;
|
||||
}
|
||||
break;
|
||||
|
||||
case TW_ST_SLA_ACK: //0xA8 Slave wurde im Lesemodus adressiert und hat ein ACK zurückgegeben.
|
||||
case TW_ST_DATA_ACK: //0xB8 Slave Transmitter, Daten wurden angefordert
|
||||
if (i2c_reg == 0xFF) {
|
||||
i2c_reg = 0;
|
||||
}
|
||||
if (i2c_reg < I2C_NUM_REGS) {
|
||||
TWDR = i2c_regs[i2c_reg];
|
||||
i2c_reg++;
|
||||
TWCR_ACK;
|
||||
}
|
||||
else if (i2c_reg >= I2C_SREGS_OFFSET && i2c_reg < I2C_SREGS_OFFSET+I2C_SREG_MAX) {
|
||||
TWDR = i2c_system[i2c_reg-I2C_SREGS_OFFSET];
|
||||
i2c_reg++;
|
||||
TWCR_ACK;
|
||||
}
|
||||
else TWCR_NACK;
|
||||
break;
|
||||
|
||||
case TW_SR_STOP:
|
||||
TWCR_ACK;
|
||||
break;
|
||||
|
||||
case TW_ST_DATA_NACK: // 0xC0 Keine Daten mehr gefordert
|
||||
case TW_SR_DATA_NACK: // 0x88
|
||||
case TW_ST_LAST_DATA: // 0xC8 Last data byte in TWDR has been transmitted (TWEA = “0”); ACK has been received
|
||||
default:
|
||||
TWCR_RESET;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
int main( void ) {
|
||||
uint32_t cnt[32] = { 0 };
|
||||
unsigned int i;
|
||||
uint32_t inval = 0;
|
||||
uint32_t temp = 0;
|
||||
int offdelay;
|
||||
|
||||
//
|
||||
// disable JTAG
|
||||
MCUCSR |= (1<<JTD);
|
||||
MCUCSR |= (1<<JTD);
|
||||
|
||||
// enable inputs
|
||||
DDRA = 0;
|
||||
PORTA = 0xFF;
|
||||
DDRB = 0;
|
||||
PORTB = 0xFF;
|
||||
DDRC = 0;
|
||||
PORTC = 0xFF;
|
||||
DDRD = 0;
|
||||
PORTD = 0xFF;
|
||||
|
||||
//
|
||||
// read all variables from eeprom
|
||||
i2c_system[I2C_SREG_VERSION] = VERSION;
|
||||
i2c_system[I2C_SREG_CMD] = 0;
|
||||
|
||||
i2c_system[I2C_SREG_ADDR] = EEPROM_read(I2C_SREG_ADDR);
|
||||
if (i2c_system[I2C_SREG_ADDR] > 0x4f || i2c_system[I2C_SREG_ADDR] < 0x20) {
|
||||
i2c_system[I2C_SREG_ADDR] = I2C_DEFAULT_ADDR;
|
||||
}
|
||||
|
||||
i2c_system[I2C_SREG_DIOFFDELAY] = EEPROM_read(I2C_SREG_DIOFFDELAY);
|
||||
if (i2c_system[I2C_SREG_DIOFFDELAY] == 0 || i2c_system[I2C_SREG_DIOFFDELAY] == 0xFF) {
|
||||
i2c_system[I2C_SREG_DIOFFDELAY] = 0x20;
|
||||
}
|
||||
|
||||
i2c_slave_init (i2c_system[I2C_SREG_ADDR]);
|
||||
|
||||
for (i = 0; i < 32; i++) cnt[i] = 0;
|
||||
|
||||
//
|
||||
// system loop
|
||||
while( 1 ) {
|
||||
//
|
||||
// digital in registers..
|
||||
offdelay = i2c_system[I2C_SREG_DIOFFDELAY] << 8;
|
||||
|
||||
// S1 - S8
|
||||
i = 0; if (!(PINB & (1 << 0))) cnt[i] = offdelay;
|
||||
i++; if (!(PINB & (1 << 1))) cnt[i] = offdelay;
|
||||
i++; if (!(PINB & (1 << 2))) cnt[i] = offdelay;
|
||||
i++; if (!(PINB & (1 << 3))) cnt[i] = offdelay;
|
||||
i++; if (!(PINB & (1 << 4))) cnt[i] = offdelay;
|
||||
i++; if (!(PINB & (1 << 5))) cnt[i] = offdelay;
|
||||
i++; if (!(PINB & (1 << 6))) cnt[i] = offdelay;
|
||||
i++; if (!(PINB & (1 << 7))) cnt[i] = offdelay;
|
||||
|
||||
// S9 - S16
|
||||
i++; if (!(PINA & (1 << 0))) cnt[i] = offdelay;
|
||||
i++; if (!(PINA & (1 << 1))) cnt[i] = offdelay;
|
||||
i++; if (!(PINA & (1 << 2))) cnt[i] = offdelay;
|
||||
i++; if (!(PINA & (1 << 3))) cnt[i] = offdelay;
|
||||
i++; if (!(PINA & (1 << 4))) cnt[i] = offdelay;
|
||||
i++; if (!(PINA & (1 << 5))) cnt[i] = offdelay;
|
||||
i++; if (!(PINA & (1 << 6))) cnt[i] = offdelay;
|
||||
i++; if (!(PINA & (1 << 7))) cnt[i] = offdelay;
|
||||
|
||||
// S17 - S24
|
||||
i++; if (!(PIND & (1 << 0))) cnt[i] = offdelay;
|
||||
i++; if (!(PIND & (1 << 1))) cnt[i] = offdelay;
|
||||
i++; if (!(PIND & (1 << 2))) cnt[i] = offdelay;
|
||||
i++; if (!(PIND & (1 << 3))) cnt[i] = offdelay;
|
||||
i++; if (!(PIND & (1 << 4))) cnt[i] = offdelay;
|
||||
i++; if (!(PIND & (1 << 5))) cnt[i] = offdelay;
|
||||
i++; if (!(PIND & (1 << 6))) cnt[i] = offdelay;
|
||||
i++; if (!(PIND & (1 << 7))) cnt[i] = offdelay;
|
||||
|
||||
// all values
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (cnt[i] == 0) inval &= ~(1 << (i));
|
||||
else {
|
||||
cnt[i]--;
|
||||
inval |= (1 << (i));
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (cnt[16+i] == 0) temp &= ~(1 << (i));
|
||||
else {
|
||||
cnt[16+i]--;
|
||||
temp |= (1 << (i));
|
||||
}
|
||||
}
|
||||
|
||||
i2c_regs[0] = (unsigned char) (inval & 0x000000FF);
|
||||
i2c_regs[1] = (unsigned char) ((inval & 0x0000FF00) >> 8);
|
||||
i2c_regs[2] = (unsigned char) (temp & 0x000000FF);
|
||||
i2c_regs[3] = (unsigned char) ((temp & 0x0000FF00) >> 8);
|
||||
|
||||
|
||||
//
|
||||
// system registers
|
||||
if (i2c_system[I2C_SREG_CMD] != 0) {
|
||||
if (i2c_system[I2C_SREG_CMD] == I2C_CMD_EEPROMREAD) {
|
||||
cli();
|
||||
i2c_system[I2C_SREG_CMD] = 0;
|
||||
for (i = 0; i < I2C_SREG_MAX; i++) {
|
||||
i2c_system[i] = EEPROM_read(i);
|
||||
}
|
||||
sei();
|
||||
}
|
||||
|
||||
if (i2c_system[I2C_SREG_CMD] == I2C_CMD_EEPROMWRITE) {
|
||||
cli();
|
||||
i2c_system[I2C_SREG_CMD] = 0;
|
||||
for (i = 0; i < I2C_SREG_MAX; i++) {
|
||||
EEPROM_write(i, i2c_system[i]);
|
||||
}
|
||||
sei();
|
||||
}
|
||||
}
|
||||
i2c_system[I2C_SREG_CMD] = 0;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
@ -0,0 +1,47 @@
|
||||
# .SILENT:
|
||||
|
||||
# Atmega88
|
||||
# CFLAGS= -Os -g -Wall -mmcu=atmega16 -DF_CPU=8000000UL
|
||||
# LDFLAGS= -mmcu=atmega16
|
||||
|
||||
CPUTYPE1= atmega8
|
||||
CPUTYPE2= m8
|
||||
|
||||
# Atmega32
|
||||
CFLAGS= -Os -g -Wall -mmcu=$(CPUTYPE1) -DF_CPU=16000000UL
|
||||
LDFLAGS= -mmcu=$(CPUTYPE1)
|
||||
|
||||
all: gleiserkennung-v1.bin gleiserkennung-v2.bin
|
||||
|
||||
%.o: %.c
|
||||
avr-gcc $(CFLAGS) -c -o $@ $^
|
||||
|
||||
rebuild: clean all
|
||||
|
||||
gleiserkennung-v2.elf: gleiserkennung-v2.o eprom.o
|
||||
avr-gcc $^ -o $@ $(LDFLAGS)
|
||||
|
||||
|
||||
gleiserkennung-v1.elf: gleiserkennung-v1.o eprom.o
|
||||
avr-gcc $^ -o $@ $(LDFLAGS)
|
||||
|
||||
%.bin: %.elf
|
||||
avr-objcopy -j .text -j .data -O binary $^ $@
|
||||
|
||||
clean:
|
||||
rm *.o -rf
|
||||
rm *.bin -rf
|
||||
rm *.elf -rf
|
||||
rm *~ -rf
|
||||
|
||||
cleanall: clean
|
||||
|
||||
source: cleanall
|
||||
|
||||
upload-v1: gleiserkennung-v1.bin
|
||||
avrdude -c avrispmkII -P usb -p $(CPUTYPE2) -v -V -U flash:w:gleiserkennung-v1.bin:r
|
||||
|
||||
upload-v2: gleiserkennung-v2.bin
|
||||
avrdude -c avrispmkII -P usb -p $(CPUTYPE2) -v -V -U flash:w:gleiserkennung-v2.bin:r
|
||||
|
||||
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* eprom.c
|
||||
*
|
||||
* Created on: 11.02.2018
|
||||
* Author: steffen
|
||||
*/
|
||||
|
||||
|
||||
#include "eprom.h"
|
||||
|
||||
void EEPROM_write(unsigned int uiAddress, unsigned char ucData) {
|
||||
while(EECR & (1<<EEWE)); // Wait for completion of previous write
|
||||
EEAR = uiAddress; // Set up address and data registers
|
||||
EEDR = ucData;
|
||||
EECR |= (1<<EEMWE); // Write logical one to EEMWE
|
||||
EECR |= (1<<EEWE); // Start eeprom write by setting EEWE
|
||||
}
|
||||
|
||||
|
||||
unsigned char EEPROM_read(unsigned int uiAddress) {
|
||||
while(EECR & (1<<EEWE)); // Wait for completion of previous write
|
||||
EEAR = uiAddress; // Set up address register
|
||||
EECR |= (1<<EERE); // Start eeprom read by writing EERE
|
||||
return EEDR; // return eeprom data register
|
||||
}
|
||||
|
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* eprom.h
|
||||
*
|
||||
* Created on: 11.02.2018
|
||||
* Author: steffen
|
||||
*/
|
||||
|
||||
#ifndef EPROM_H_
|
||||
#define EPROM_H_
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
void EEPROM_write(unsigned int uiAddress, unsigned char ucData);
|
||||
unsigned char EEPROM_read(unsigned int uiAddress);
|
||||
|
||||
|
||||
#endif /* ATMEGA8_DETECT_EPROM_H_ */
|
@ -0,0 +1,247 @@
|
||||
/************************************************************
|
||||
* reads some digital in and make them readable over i2c bus.
|
||||
* register 0 -
|
||||
*
|
||||
* +-------+
|
||||
* (RESET) PC6 -|1 O 28|- PC5 (ADC5/SCL)
|
||||
* S3 (RXD) PD0 -|2 27|- PC4 (ADC4/SDA)
|
||||
* S2 (TXD) PD1 -|3 26|- PC3 (ADC3)
|
||||
* S1 (INT0) PD2 -|4 25|- PC2 (ADC2) S12
|
||||
* S10 (INT1) PD3 -|5 24|- PC1 (ADC1) S16
|
||||
* S7 (XCK/T0)PD4 -|6 23|- PC0 (ADC0) S15
|
||||
* VCC -|7 22|- GND
|
||||
* GND -|8 21|- AREF
|
||||
* S8 (XTAL2/TOSC2) PB6 -|9 20|- AVCC
|
||||
* S9 (XTAL2/TOSC2) PB7 -|10 19|- PB5 (SCK)
|
||||
* S4 (T1) PD5 -|11 18|- PB4 (MISO)
|
||||
* S5 (AIN0) PD6 -|12 17|- PB3 (MOSI(OC2)
|
||||
* S6 (AIN1) PD7 -|13 16|- PB2 (SS/OC1B) S14
|
||||
* S11 (ICP1) PB0 -|14 15|- PB1 (OC1A) S13
|
||||
* +-------+
|
||||
*/
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <util/delay.h>
|
||||
#include <util/twi.h>
|
||||
|
||||
#include "eprom.h"
|
||||
|
||||
#define TWCR_ACK TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA);
|
||||
#define TWCR_NACK TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)
|
||||
#define TWCR_RESET TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA)|(1<<TWSTO);
|
||||
|
||||
#define I2C_NUM_REGS 8
|
||||
#define I2C_DEFAULT_ADDR 0x4F
|
||||
#define VERSION 1
|
||||
|
||||
#define I2C_SREGS_OFFSET 0x20
|
||||
|
||||
enum {
|
||||
I2C_SREG_VERSION = 0,
|
||||
I2C_SREG_CMD,
|
||||
I2C_SREG_ADDR,
|
||||
I2C_SREG_DIOFFDELAY,
|
||||
I2C_SREG_DOOFFDELAY,
|
||||
|
||||
I2C_SREG_MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
I2C_CMD_NONE = 0,
|
||||
I2C_CMD_EEPROMREAD,
|
||||
I2C_CMD_EEPROMWRITE
|
||||
};
|
||||
|
||||
volatile uint8_t i2c_reg;
|
||||
volatile uint8_t i2c_system[I2C_SREG_MAX];
|
||||
volatile uint8_t i2c_regs[I2C_NUM_REGS];
|
||||
|
||||
//
|
||||
// i2c slave addresse festlegen und interrupts einschalten
|
||||
void i2c_slave_init(uint8_t adr) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < I2C_NUM_REGS; i++) {
|
||||
i2c_regs[i] = 0;
|
||||
}
|
||||
|
||||
TWAR = adr << 1;
|
||||
TWCR &= ~(1<<TWSTA) | (1<<TWSTO);
|
||||
TWCR |= (1<<TWEA) | (1<<TWEN) | (1<<TWIE);
|
||||
|
||||
i2c_reg = 0x0;
|
||||
|
||||
sei();
|
||||
}
|
||||
|
||||
ISR (TWI_vect) {
|
||||
char data=0;
|
||||
|
||||
switch (TW_STATUS) {
|
||||
case TW_SR_SLA_ACK: // 0x60 Slave Receiver, Slave wurde adressiert
|
||||
TWCR_ACK;
|
||||
i2c_reg=0xFF;
|
||||
break;
|
||||
|
||||
case TW_SR_DATA_ACK: // 0x80 Slave Receiver, ein Datenbyte wurde empfangen
|
||||
data=TWDR;
|
||||
if (i2c_reg == 0xFF) {
|
||||
if(data < I2C_NUM_REGS || (data >= I2C_SREGS_OFFSET && data < I2C_SREGS_OFFSET+I2C_SREG_MAX)) {
|
||||
i2c_reg = data;
|
||||
TWCR_ACK;
|
||||
}
|
||||
else
|
||||
TWCR_NACK;
|
||||
}
|
||||
else {
|
||||
if(i2c_reg < I2C_NUM_REGS) {
|
||||
i2c_regs[i2c_reg] = data;
|
||||
i2c_reg++;
|
||||
TWCR_ACK;
|
||||
}
|
||||
else if (i2c_reg >= I2C_SREGS_OFFSET && i2c_reg < I2C_SREGS_OFFSET+I2C_SREG_MAX) {
|
||||
i2c_system[i2c_reg-I2C_SREGS_OFFSET] = data;
|
||||
i2c_reg++;
|
||||
TWCR_ACK;
|
||||
}
|
||||
else TWCR_NACK;
|
||||
}
|
||||
break;
|
||||
|
||||
case TW_ST_SLA_ACK: //0xA8 Slave wurde im Lesemodus adressiert und hat ein ACK zurückgegeben.
|
||||
case TW_ST_DATA_ACK: //0xB8 Slave Transmitter, Daten wurden angefordert
|
||||
if (i2c_reg == 0xFF) {
|
||||
i2c_reg = 0;
|
||||
}
|
||||
if (i2c_reg < I2C_NUM_REGS) {
|
||||
TWDR = i2c_regs[i2c_reg];
|
||||
i2c_reg++;
|
||||
TWCR_ACK;
|
||||
}
|
||||
else if (i2c_reg >= I2C_SREGS_OFFSET && i2c_reg < I2C_SREGS_OFFSET+I2C_SREG_MAX) {
|
||||
TWDR = i2c_system[i2c_reg-I2C_SREGS_OFFSET];
|
||||
i2c_reg++;
|
||||
TWCR_ACK;
|
||||
}
|
||||
else TWCR_NACK;
|
||||
break;
|
||||
|
||||
case TW_SR_STOP:
|
||||
TWCR_ACK;
|
||||
break;
|
||||
|
||||
case TW_ST_DATA_NACK: // 0xC0 Keine Daten mehr gefordert
|
||||
case TW_SR_DATA_NACK: // 0x88
|
||||
case TW_ST_LAST_DATA: // 0xC8 Last data byte in TWDR has been transmitted (TWEA = “0”); ACK has been received
|
||||
default:
|
||||
TWCR_RESET;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
int main( void ) {
|
||||
long int cnt[16] = { 0 };
|
||||
unsigned int i;
|
||||
unsigned short int inval = 0;
|
||||
unsigned short int temp = 0;
|
||||
int offdelay;
|
||||
|
||||
//
|
||||
// read all variables from eeprom
|
||||
i2c_system[I2C_SREG_VERSION] = VERSION;
|
||||
i2c_system[I2C_SREG_CMD] = 0;
|
||||
|
||||
i2c_system[I2C_SREG_ADDR] = EEPROM_read(I2C_SREG_ADDR);
|
||||
if (i2c_system[I2C_SREG_ADDR] > 0x4f || i2c_system[I2C_SREG_ADDR] < 0x20) {
|
||||
i2c_system[I2C_SREG_ADDR] = I2C_DEFAULT_ADDR;
|
||||
}
|
||||
|
||||
i2c_system[I2C_SREG_DIOFFDELAY] = EEPROM_read(I2C_SREG_DIOFFDELAY);
|
||||
if (i2c_system[I2C_SREG_DIOFFDELAY] == 0 || i2c_system[I2C_SREG_DIOFFDELAY] == 0xFF) {
|
||||
i2c_system[I2C_SREG_DIOFFDELAY] = 0x20;
|
||||
}
|
||||
|
||||
i2c_system[I2C_SREG_DOOFFDELAY] = EEPROM_read(I2C_SREG_DOOFFDELAY);
|
||||
if (i2c_system[I2C_SREG_DOOFFDELAY] == 0) {
|
||||
i2c_system[I2C_SREG_DOOFFDELAY] = 0xFF;
|
||||
}
|
||||
|
||||
i2c_slave_init (i2c_system[I2C_SREG_ADDR]);
|
||||
|
||||
//
|
||||
// system loop
|
||||
while( 1 ) {
|
||||
//
|
||||
// digital in registers..
|
||||
offdelay = i2c_system[I2C_SREG_DIOFFDELAY] << 8;
|
||||
|
||||
i = 0;
|
||||
if (PIND & (1 << 2)) cnt[0] = offdelay;
|
||||
if (PIND & (1 << 1)) cnt[1] = offdelay;
|
||||
if (PIND & (1 << 0)) cnt[2] = offdelay;
|
||||
if (PIND & (1 << 5)) cnt[3] = offdelay;
|
||||
if (PIND & (1 << 6)) cnt[4] = offdelay;
|
||||
if (PIND & (1 << 7)) cnt[5] = offdelay;
|
||||
if (PIND & (1 << 4)) cnt[6] = offdelay;
|
||||
if (PINB & (1 << 6)) cnt[7] = offdelay;
|
||||
|
||||
if (PINB & (1 << 7)) cnt[8] = offdelay;
|
||||
if (PIND & (1 << 3)) cnt[9] = offdelay;
|
||||
if (PINB & (1 << 0)) cnt[10] = offdelay;
|
||||
if (PINC & (1 << 2)) cnt[11] = offdelay;
|
||||
if (PINB & (1 << 1)) cnt[12] = offdelay;
|
||||
if (PINB & (1 << 2)) cnt[13] = offdelay;
|
||||
if (PINC & (1 << 0)) cnt[14] = offdelay;
|
||||
if (PINC & (1 << 1)) cnt[15] = offdelay;
|
||||
|
||||
// all values
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (cnt[i] == 0) inval &= ~(1 << (i));
|
||||
else {
|
||||
cnt[i]--;
|
||||
inval |= (1 << (i));
|
||||
}
|
||||
}
|
||||
|
||||
i2c_regs[0] = (unsigned char) (inval & 0x00FF);
|
||||
i2c_regs[1] = (unsigned char) ((inval & 0xFF00) >> 8);
|
||||
|
||||
temp++;
|
||||
i2c_regs[2] = (unsigned char) (temp & 0x00FF);
|
||||
i2c_regs[3] = (unsigned char) ((temp & 0xFF00) >> 8);
|
||||
|
||||
|
||||
//
|
||||
// system registers
|
||||
if (i2c_system[I2C_SREG_CMD] != 0) {
|
||||
if (i2c_system[I2C_SREG_CMD] == I2C_CMD_EEPROMREAD) {
|
||||
cli();
|
||||
i2c_system[I2C_SREG_CMD] = 0;
|
||||
for (i = 0; i < I2C_SREG_MAX; i++) {
|
||||
i2c_system[i] = EEPROM_read(i);
|
||||
}
|
||||
sei();
|
||||
}
|
||||
|
||||
if (i2c_system[I2C_SREG_CMD] == I2C_CMD_EEPROMWRITE) {
|
||||
cli();
|
||||
i2c_system[I2C_SREG_CMD] = 0;
|
||||
for (i = 0; i < I2C_SREG_MAX; i++) {
|
||||
EEPROM_write(i, i2c_system[i]);
|
||||
}
|
||||
sei();
|
||||
}
|
||||
}
|
||||
i2c_system[I2C_SREG_CMD] = 0;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
@ -0,0 +1,250 @@
|
||||
/************************************************************
|
||||
* reads some dis and make them readable over i2c bus.
|
||||
* out of 8 registers only the register 1 is needed
|
||||
*
|
||||
* +-------+
|
||||
* (RESET) PC6 -|1 O 28|- PC5 (ADC5/SCL)
|
||||
* Sensor 1 (RXD) PD0 -|2 27|- PC4 (ADC4/SDA)
|
||||
* Sensor 2 (TXD) PD1 -|3 26|- PC3 (ADC3) Relais 1
|
||||
* Sensor 3 (INT0) PD2 -|4 25|- PC2 (ADC2) Relais 2
|
||||
* Sensor 4 (INT1) PD3 -|5 24|- PC1 (ADC1) Relais 3
|
||||
* Sensor 5 (XCK/T0) PD4 -|6 23|- PC0 (ADC0) Relais 4
|
||||
* VCC -|7 22|- GND
|
||||
* GND -|8 21|- AREF
|
||||
* Sen6(XTAL2/TOSC2) PB6 -|9 20|- AVCC
|
||||
* Sen7(XTAL2/TOSC2) PB7 -|10 19|- PB5 (SCK)
|
||||
* Sensor 8 (T1) PD5 -|11 18|- PB4 (MISO)
|
||||
* (AIN0) PD6 -|12 17|- PB3 (MOSI(OC2)
|
||||
* Relais 7 (AIN1) PD7 -|13 16|- PB2 (SS/OC1B) Relais 5
|
||||
* Relais 8 (ICP1) PB0 -|14 15|- PB1 (OC1A) Relais 6
|
||||
* +-------+
|
||||
*/
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <util/delay.h>
|
||||
#include <util/twi.h>
|
||||
|
||||
#include "eprom.h"
|
||||
|
||||
#define TWCR_ACK TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA);
|
||||
#define TWCR_NACK TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)
|
||||
#define TWCR_RESET TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA)|(1<<TWSTO);
|
||||
|
||||
#define I2C_NUM_REGS 8
|
||||
#define VERSION 2
|
||||
#define I2C_DEFAULT_ADDR 0x4F
|
||||
#define I2C_SREGS_OFFSET 0x20
|
||||
|
||||
enum {
|
||||
I2C_SREG_VERSION = 0,
|
||||
I2C_SREG_CMD,
|
||||
I2C_SREG_ADDR,
|
||||
I2C_SREG_DIOFFDELAY,
|
||||
I2C_SREG_DOOFFDELAY,
|
||||
|
||||
I2C_SREG_MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
I2C_CMD_NONE = 0,
|
||||
I2C_CMD_EEPROMREAD,
|
||||
I2C_CMD_EEPROMWRITE
|
||||
};
|
||||
|
||||
volatile uint8_t i2c_reg;
|
||||
volatile uint8_t i2c_system[I2C_SREG_MAX];
|
||||
volatile uint8_t i2c_regs[I2C_NUM_REGS];
|
||||
|
||||
//
|
||||
// i2c slave addresse festlegen und interrupts einschalten
|
||||
void i2c_slave_init(uint8_t adr) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < I2C_NUM_REGS; i++) {
|
||||
i2c_regs[i] = 0;
|
||||
}
|
||||
|
||||
TWAR = adr << 1;
|
||||
TWCR &= ~(1<<TWSTA) | (1<<TWSTO);
|
||||
TWCR |= (1<<TWEA) | (1<<TWEN) | (1<<TWIE);
|
||||
|
||||
i2c_reg = 0x0;
|
||||
|
||||
sei();
|
||||
}
|
||||
|
||||
ISR (TWI_vect) {
|
||||
char data=0;
|
||||
|
||||
switch (TW_STATUS) {
|
||||
case TW_SR_SLA_ACK: // 0x60 Slave Receiver, Slave wurde adressiert
|
||||
TWCR_ACK;
|
||||
i2c_reg=0xFF;
|
||||
break;
|
||||
|
||||
case TW_SR_DATA_ACK: // 0x80 Slave Receiver, ein Datenbyte wurde empfangen
|
||||
data=TWDR;
|
||||
if (i2c_reg == 0xFF) {
|
||||
if(data < I2C_NUM_REGS || (data >= I2C_SREGS_OFFSET && data < I2C_SREGS_OFFSET+I2C_SREG_MAX)) {
|
||||
i2c_reg = data;
|
||||
TWCR_ACK;
|
||||
}
|
||||
else
|
||||
TWCR_NACK;
|
||||
}
|
||||
else {
|
||||
if(i2c_reg < I2C_NUM_REGS) {
|
||||
i2c_regs[i2c_reg] = data;
|
||||
i2c_reg++;
|
||||
TWCR_ACK;
|
||||
}
|
||||
else if (i2c_reg >= I2C_SREGS_OFFSET && i2c_reg < I2C_SREGS_OFFSET+I2C_SREG_MAX) {
|
||||
i2c_system[i2c_reg-I2C_SREGS_OFFSET] = data;
|
||||
i2c_reg++;
|
||||
TWCR_ACK;
|
||||
}
|
||||
else TWCR_NACK;
|
||||
}
|
||||
break;
|
||||
|
||||
case TW_ST_SLA_ACK: //0xA8 Slave wurde im Lesemodus adressiert und hat ein ACK zurückgegeben.
|
||||
case TW_ST_DATA_ACK: //0xB8 Slave Transmitter, Daten wurden angefordert
|
||||
if (i2c_reg == 0xFF) {
|
||||
i2c_reg = 0;
|
||||
}
|
||||
if (i2c_reg < I2C_NUM_REGS) {
|
||||
TWDR = i2c_regs[i2c_reg];
|
||||
i2c_reg++;
|
||||
TWCR_ACK;
|
||||
}
|
||||
else if (i2c_reg >= I2C_SREGS_OFFSET && i2c_reg < I2C_SREGS_OFFSET+I2C_SREG_MAX) {
|
||||
TWDR = i2c_system[i2c_reg-I2C_SREGS_OFFSET];
|
||||
i2c_reg++;
|
||||
TWCR_ACK;
|
||||
}
|
||||
else TWCR_NACK;
|
||||
break;
|
||||
|
||||
case TW_SR_STOP:
|
||||
TWCR_ACK;
|
||||
break;
|
||||
|
||||
case TW_ST_DATA_NACK: // 0xC0 Keine Daten mehr gefordert
|
||||
case TW_SR_DATA_NACK: // 0x88
|
||||
case TW_ST_LAST_DATA: // 0xC8 Last data byte in TWDR has been transmitted (TWEA = “0”); ACK has been received
|
||||
default:
|
||||
TWCR_RESET;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
int main( void ) {
|
||||
long int cnt[8] = { 0 };
|
||||
unsigned int i;
|
||||
char inval = 0;
|
||||
int offdelay;
|
||||
|
||||
//
|
||||
// read all variables from eeprom
|
||||
i2c_system[I2C_SREG_VERSION] = VERSION;
|
||||
i2c_system[I2C_SREG_CMD] = 0;
|
||||
|
||||
i2c_system[I2C_SREG_ADDR] = EEPROM_read(I2C_SREG_ADDR);
|
||||
if (i2c_system[I2C_SREG_ADDR] > 0x4f || i2c_system[I2C_SREG_ADDR] < 0x20) {
|
||||
i2c_system[I2C_SREG_ADDR] = I2C_DEFAULT_ADDR;
|
||||
}
|
||||
|
||||
i2c_system[I2C_SREG_DIOFFDELAY] = EEPROM_read(I2C_SREG_DIOFFDELAY);
|
||||
if (i2c_system[I2C_SREG_DIOFFDELAY] == 0 || i2c_system[I2C_SREG_DIOFFDELAY] == 0xFF) {
|
||||
i2c_system[I2C_SREG_DIOFFDELAY] = 0x20;
|
||||
}
|
||||
|
||||
i2c_system[I2C_SREG_DOOFFDELAY] = EEPROM_read(I2C_SREG_DOOFFDELAY);
|
||||
if (i2c_system[I2C_SREG_DOOFFDELAY] == 0) {
|
||||
i2c_system[I2C_SREG_DOOFFDELAY] = 0xFF;
|
||||
}
|
||||
|
||||
i2c_slave_init (i2c_system[I2C_SREG_ADDR]);
|
||||
|
||||
DDRB |= 1 | (1<<1) | (1<<2);
|
||||
DDRC |= 1 | (1<<1) | (1<<2) | (1<<3);
|
||||
DDRD |= (1<<7);
|
||||
|
||||
//
|
||||
// system loop
|
||||
while( 1 ) {
|
||||
//
|
||||
// digital in registers..
|
||||
offdelay = i2c_system[I2C_SREG_DIOFFDELAY] << 8;
|
||||
|
||||
if (PIND & 0x01) cnt[0] = offdelay;
|
||||
if (PIND & 0x02) cnt[1] = offdelay;
|
||||
if (PIND & 0x04) cnt[2] = offdelay;
|
||||
if (PIND & 0x08) cnt[3] = offdelay;
|
||||
if (PIND & 0x10) cnt[4] = offdelay;
|
||||
if (PINB & 0x40) cnt[5] = offdelay;
|
||||
if (PINB & 0x80) cnt[6] = offdelay;
|
||||
if (PIND & 0x20) cnt[7] = offdelay;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (cnt[i] == 0) inval &= ~(1 << (i));
|
||||
else {
|
||||
cnt[i]--;
|
||||
inval |= (1 << (i));
|
||||
}
|
||||
}
|
||||
i2c_regs[0] = inval;
|
||||
|
||||
//
|
||||
// digital out registers..
|
||||
if (i2c_regs[1] & 0x01) PORTC |= (1 << 3);
|
||||
else PORTC &= ~(1 << 3);
|
||||
if (i2c_regs[1] & 0x02) PORTC |= (1 << 2);
|
||||
else PORTC &= ~(1 << 2);
|
||||
if (i2c_regs[1] & 0x04) PORTC |= (1 << 1);
|
||||
else PORTC &= ~(1 << 1);
|
||||
if (i2c_regs[1] & 0x08) PORTC |= 1;
|
||||
else PORTC &= ~1;
|
||||
if (i2c_regs[1] & 0x10) PORTB |= (1 << 2);
|
||||
else PORTB &= ~(1 << 2);
|
||||
if (i2c_regs[1] & 0x20) PORTB |= (1 << 1);
|
||||
else PORTB &= ~(1 << 1);
|
||||
if (i2c_regs[1] & 0x40) PORTD |= (1 << 7);
|
||||
else PORTD &= ~(1 << 7);
|
||||
if (i2c_regs[1] & 0x80) PORTB |= 1;
|
||||
else PORTB &= ~1;
|
||||
|
||||
//
|
||||
// system registers
|
||||
if (i2c_system[I2C_SREG_CMD] != 0) {
|
||||
if (i2c_system[I2C_SREG_CMD] == I2C_CMD_EEPROMREAD) {
|
||||
cli();
|
||||
i2c_system[I2C_SREG_CMD] = 0;
|
||||
for (i = 0; i < I2C_SREG_MAX; i++) {
|
||||
i2c_system[i] = EEPROM_read(i);
|
||||
}
|
||||
sei();
|
||||
}
|
||||
|
||||
if (i2c_system[I2C_SREG_CMD] == I2C_CMD_EEPROMWRITE) {
|
||||
cli();
|
||||
i2c_system[I2C_SREG_CMD] = 0;
|
||||
for (i = 0; i < I2C_SREG_MAX; i++) {
|
||||
EEPROM_write(i, i2c_system[i]);
|
||||
}
|
||||
sei();
|
||||
}
|
||||
}
|
||||
i2c_system[I2C_SREG_CMD] = 0;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
@ -0,0 +1,153 @@
|
||||
/************************************************************
|
||||
* reads some dis and make them readable over i2c bus.
|
||||
* out of 8 registers only the register 1 is needed
|
||||
*
|
||||
* +-------+
|
||||
* (RESET) PC6 -|1 O 28|- PC5 (ADC5/SCL)
|
||||
* (RXD) PD0 -|2 27|- PC4 (ADC4/SDA)
|
||||
* (TXD) PD1 -|3 26|- PC3 (ADC3)
|
||||
* (INT0) PD2 -|4 25|- PC2 (ADC2)
|
||||
* (INT1) PD3 -|5 24|- PC1 (ADC1) Sensor 4
|
||||
* (XCK/T0) PD4 -|6 23|- PC0 (ADC0) Sensor 3
|
||||
* VCC -|7 22|- GND
|
||||
* GND -|8 21|- AREF
|
||||
* (XTAL2/TOSC2) PB6 -|9 20|- AVCC
|
||||
* (XTAL2/TOSC2) PB7 -|10 19|- PB5 (SCK)
|
||||
* Sensor 8 (T1) PD5 -|11 18|- PB4 (MISO)
|
||||
* Sensor 7 (AIN0) PD6 -|12 17|- PB3 (MOSI(OC2)
|
||||
* Sensor 6 (AIN1) PD7 -|13 16|- PB2 (SS/OC1B) Sensor 2
|
||||
* Sensor 5 (ICP1) PB0 -|14 15|- PB1 (OC1A) Sensor 1
|
||||
* +-------+
|
||||
*/
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <util/delay.h>
|
||||
#include <util/twi.h>
|
||||
|
||||
#define TWCR_ACK TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA);
|
||||
#define TWCR_NACK TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)
|
||||
#define TWCR_RESET TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA)|(1<<TWSTO);
|
||||
|
||||
#define I2C_NUM_REGS 8
|
||||
|
||||
volatile int i2c_reg;
|
||||
volatile uint8_t i2c_inregs[I2C_NUM_REGS];
|
||||
volatile uint8_t i2c_outregs[I2C_NUM_REGS];
|
||||
|
||||
//
|
||||
// i2c slave addresse festlegen und interrupts einschalten
|
||||
void i2c_slave_init(uint8_t adr) {
|
||||
char i;
|
||||
|
||||
for (i = 0; i < I2C_NUM_REGS; i++) {
|
||||
i2c_inregs[i] = i;
|
||||
i2c_outregs[i] = i | 0x80;
|
||||
}
|
||||
|
||||
TWAR = adr << 1;
|
||||
TWCR &= ~(1<<TWSTA) | (1<<TWSTO);
|
||||
TWCR |= (1<<TWEA) | (1<<TWEN) | (1<<TWIE);
|
||||
|
||||
i2c_reg = 0x0;
|
||||
|
||||
sei();
|
||||
}
|
||||
|
||||
ISR (TWI_vect) {
|
||||
char data=0;
|
||||
|
||||
switch (TW_STATUS) {
|
||||
case TW_SR_SLA_ACK: // 0x60 Slave Receiver, Slave wurde adressiert
|
||||
TWCR_ACK;
|
||||
i2c_reg=0xFF;
|
||||
break;
|
||||
|
||||
case TW_SR_DATA_ACK: // 0x80 Slave Receiver, ein Datenbyte wurde empfangen
|
||||
data=TWDR;
|
||||
if (i2c_reg == 0xFF) {
|
||||
if(data < I2C_NUM_REGS)
|
||||
i2c_reg = data;
|
||||
else
|
||||
i2c_reg = 0; // FIXME: wrong address so start at register 0
|
||||
TWCR_ACK;
|
||||
}
|
||||
else {
|
||||
if(i2c_reg < I2C_NUM_REGS) {
|
||||
i2c_inregs[i2c_reg] = data;
|
||||
i2c_reg++;
|
||||
}
|
||||
TWCR_ACK;
|
||||
}
|
||||
break;
|
||||
|
||||
case TW_ST_SLA_ACK: //0xA8 Slave wurde im Lesemodus adressiert und hat ein ACK zurückgegeben.
|
||||
case TW_ST_DATA_ACK: //0xB8 Slave Transmitter, Daten wurden angefordert
|
||||
if (i2c_reg == 0xFF) {
|
||||
i2c_reg = 0;
|
||||
}
|
||||
|
||||
if (i2c_reg < I2C_NUM_REGS) {
|
||||
TWDR = i2c_outregs[i2c_reg];
|
||||
// TWDR = 0xF3;
|
||||
i2c_reg++;
|
||||
}
|
||||
else {
|
||||
TWDR = 0; //Kein Daten mehr im Buffer
|
||||
}
|
||||
TWCR_ACK;
|
||||
break;
|
||||
|
||||
case TW_SR_STOP:
|
||||
TWCR_ACK;
|
||||
break;
|
||||
|
||||
case TW_ST_DATA_NACK: // 0xC0 Keine Daten mehr gefordert
|
||||
case TW_SR_DATA_NACK: // 0x88
|
||||
case TW_ST_LAST_DATA: // 0xC8 Last data byte in TWDR has been transmitted (TWEA = “0”); ACK has been received
|
||||
default:
|
||||
TWCR_RESET;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
#define OFFDELAY 0x2000;
|
||||
int main( void ) {
|
||||
long int cnt[8] = { 0 };
|
||||
unsigned int i;
|
||||
char inval = 0;
|
||||
long int t;
|
||||
|
||||
// i2c benutzt PORTC bit5+C4
|
||||
i2c_slave_init (0x30);
|
||||
|
||||
|
||||
|
||||
while( 1 ) {
|
||||
if (PINB & 0x02) cnt[0] = OFFDELAY;
|
||||
if (PINB & 0x04) cnt[1] = OFFDELAY;
|
||||
if (PINC & 0x02) cnt[2] = OFFDELAY;
|
||||
if (PINC & 0x01) cnt[3] = OFFDELAY;
|
||||
if (PINB & 0x01) cnt[4] = OFFDELAY;
|
||||
if (PIND & 0x80) cnt[5] = OFFDELAY;
|
||||
if (PIND & 0x40) cnt[6] = OFFDELAY;
|
||||
if (PIND & 0x20) cnt[7] = OFFDELAY;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (cnt[i] == 0) inval &= ~(1 << (i));
|
||||
else {
|
||||
cnt[i]--;
|
||||
inval |= (1 << (i));
|
||||
}
|
||||
}
|
||||
i2c_outregs[1] = inval;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* debug.cc
|
||||
*
|
||||
* Created on: 15.12.2017
|
||||
* Author: steffen
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
char *int2hex (int val, char *buf, int len) {
|
||||
char tmp[] = "0123456789ABCDEF";
|
||||
int i;
|
||||
unsigned int v;
|
||||
|
||||
if (buf == NULL) return NULL;
|
||||
|
||||
memset (buf, '0', len-1);
|
||||
buf[len-1] = 0;
|
||||
for (v = val, i = 0; i < len-1; i++) {
|
||||
buf[len-2-i] = tmp[v % 16];
|
||||
v = v >> 4;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void debug_mem (char *c, int len) {
|
||||
int i;
|
||||
int v;
|
||||
char _hexpos[32];
|
||||
char _hexval[32];
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (i > 0 && (i % 16) == 0) printf ("\n");
|
||||
if ((i % 16) == 0)
|
||||
printf (" 0x%s ", int2hex(i, _hexpos, 5));
|
||||
if ((i % 8) == 0) printf (" ");
|
||||
v = (unsigned char) c[i];
|
||||
printf ("%s ", int2hex(v, _hexval, 3));
|
||||
}
|
||||
printf ("\n");
|
||||
};
|
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* debug.h
|
||||
*
|
||||
* Created on: 15.12.2017
|
||||
* Author: steffen
|
||||
*/
|
||||
|
||||
#ifndef DEBUG_H_
|
||||
#define DEBUG_H_
|
||||
|
||||
|
||||
void debug_mem (char *c, int len);
|
||||
char *int2hex (int val, char *buf, int len);
|
||||
|
||||
|
||||
#endif /* DEBUG_H_ */
|
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* i2csensor.cc
|
||||
*
|
||||
* Created on: 18.12.2017
|
||||
* Author: steffen
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/i2c-dev.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "i2csensor.h"
|
||||
|
||||
|
||||
#define LEN_FILENAME 255
|
||||
#define LEN_BUFFER 32
|
||||
|
||||
I2C::I2C () {
|
||||
i2cdev = 1;
|
||||
};
|
||||
|
||||
I2C::~I2C () {
|
||||
};
|
||||
|
||||
bool I2C::ReadByte(int addr, int reg, uint8_t *readval) {
|
||||
int file;
|
||||
char filename[LEN_FILENAME];
|
||||
unsigned char buffer[LEN_BUFFER];
|
||||
|
||||
if (readval == NULL) return false;
|
||||
// i2c device
|
||||
snprintf(filename, 255, "/dev/i2c-%d", i2cdev);
|
||||
file = open(filename, O_RDWR);
|
||||
if (file < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// setup slave addresse
|
||||
if (ioctl(file, I2C_SLAVE, addr) < 0) {
|
||||
close (file);
|
||||
return false;
|
||||
}
|
||||
|
||||
usleep (10000);
|
||||
|
||||
// write register
|
||||
buffer[0] = reg;
|
||||
if (write(file, buffer, 1) != 1) {
|
||||
close (file);
|
||||
return false;
|
||||
}
|
||||
|
||||
// read value
|
||||
if (read(file, buffer, 1) != 1) {
|
||||
close (file);
|
||||
return false;
|
||||
}
|
||||
|
||||
*readval = buffer[0];
|
||||
close (file);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
bool I2C::SendByte(int addr, int reg, uint8_t data) {
|
||||
int file;
|
||||
char filename[LEN_FILENAME];
|
||||
unsigned char buffer[LEN_BUFFER];
|
||||
|
||||
// i2c device
|
||||
snprintf(filename, 255, "/dev/i2c-%d", i2cdev);
|
||||
file = open(filename, O_RDWR);
|
||||
if (file < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// setup slave addresse
|
||||
if (ioctl(file, I2C_SLAVE, addr) < 0) {
|
||||
close (file);
|
||||
return false;
|
||||
}
|
||||
|
||||
usleep (10000);
|
||||
|
||||
// write register and value
|
||||
buffer[0] = reg;
|
||||
buffer[1] = data;
|
||||
if (write(file, buffer, 2) != 2) {
|
||||
close (file);
|
||||
return false;
|
||||
}
|
||||
close (file);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* i2csensor.h
|
||||
*
|
||||
* Created on: 18.12.2017
|
||||
* Author: steffen
|
||||
*/
|
||||
|
||||
#ifndef I2CSENSOR_H_
|
||||
#define I2CSENSOR_H_
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class I2C {
|
||||
private:
|
||||
int i2cdev;
|
||||
|
||||
public:
|
||||
I2C ();
|
||||
~I2C ();
|
||||
bool ReadByte(int addr, int reg, uint8_t *readval);
|
||||
bool SendByte(int addr, int reg, uint8_t data);
|
||||
};
|
||||
|
||||
|
||||
#endif /* I2CSENSOR_H_ */
|
@ -0,0 +1,183 @@
|
||||
/*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h> /* close() */
|
||||
#include <string.h> /* memset() */
|
||||
|
||||
#include "udp.h"
|
||||
|
||||
char dnsip[NET_HOSTLEN];
|
||||
|
||||
int dns_filladdr (string host, string port, int ai_family, struct sockaddr_in *sAddr) {
|
||||
struct addrinfo hints, *res;
|
||||
int err;
|
||||
|
||||
/* we have to complete the sAddr struct */
|
||||
bzero (&hints, sizeof (struct addrinfo));
|
||||
hints.ai_family = ai_family;
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
|
||||
if ((err = getaddrinfo (host.c_str(), port.c_str(), &hints, &res)) < 0) {
|
||||
fprintf (stdout, "dns_filladdr (getaddrinfo):%s\n", gai_strerror (err));
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy (sAddr, res->ai_addr, res->ai_addrlen);
|
||||
freeaddrinfo (res);
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
|
||||
UDPConnection::UDPConnection() {
|
||||
sock = -1;
|
||||
port = "";
|
||||
writecnt = 0;
|
||||
readcnt = 0;
|
||||
};
|
||||
|
||||
|
||||
UDPConnection::~UDPConnection() {
|
||||
Close();
|
||||
}
|
||||
|
||||
|
||||
void UDPConnection::Close () {
|
||||
if (sock > -1) close (sock);
|
||||
sock = -1;
|
||||
}
|
||||
|
||||
|
||||
int UDPConnection::Listen(int port) {
|
||||
struct sockaddr_in servAddr;
|
||||
|
||||
/* socket creation */
|
||||
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
printf("%s: socket error: %s \n",__FUNCTION__, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* bind local server port */
|
||||
servAddr.sin_family = AF_INET;
|
||||
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
servAddr.sin_port = htons(port);
|
||||
if (bind (sock, (struct sockaddr *) &servAddr,sizeof(servAddr)) < 0) {
|
||||
printf("%s: bind error: %s \n",__FUNCTION__, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int UDPConnection::Listen(string port) {
|
||||
return Listen (atoi(port.c_str()));
|
||||
}
|
||||
|
||||
|
||||
long int UDPConnection::ReadTimeout(string *source, char *buffer, long int len, int timeout) {
|
||||
int i;
|
||||
|
||||
i = isData(timeout);
|
||||
if (i > 0) {
|
||||
return Read (source, buffer, len);
|
||||
}
|
||||
else
|
||||
return i;
|
||||
}
|
||||
|
||||
long int UDPConnection::Read(string *source, char *buffer, long int len) {
|
||||
int n;
|
||||
socklen_t addrlen;
|
||||
sockaddr_in srcAddr;
|
||||
|
||||
if (!isListen()) return -1;
|
||||
|
||||
memset(buffer, 0x0, len);
|
||||
|
||||
addrlen = sizeof(srcAddr);
|
||||
n = recvfrom(sock, buffer, len, 0, (sockaddr *) &srcAddr, &addrlen);
|
||||
if(n<0) {
|
||||
printf("%s: recvfrom error:%s\n",__FUNCTION__, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* print received message */
|
||||
char addr[NET_HOSTLEN];
|
||||
snprintf (addr, NET_HOSTLEN, "%s:%d", inet_ntoa(srcAddr.sin_addr), ntohs(srcAddr.sin_port));
|
||||
(*source) = (char*)addr;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
long int UDPConnection::Send(string destaddr, char *buffer, long int len) {
|
||||
int s;
|
||||
int addrlen = sizeof (struct sockaddr_in);
|
||||
sockaddr_in dstAddr;
|
||||
string host;
|
||||
string port;
|
||||
|
||||
if (!isListen()) {
|
||||
/* socket creation */
|
||||
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
printf("%s: socket error: %s \n",__FUNCTION__, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else s = sock;
|
||||
|
||||
int pos = destaddr.rfind(':', destaddr.length());
|
||||
if (pos == -1) {
|
||||
port = "NET_PORT";
|
||||
host = destaddr;
|
||||
}
|
||||
else {
|
||||
port = destaddr.substr (pos+1, destaddr.length() - pos);
|
||||
host = destaddr.substr (0, pos);
|
||||
}
|
||||
|
||||
dns_filladdr (host, port, PF_INET, &dstAddr);
|
||||
if (sendto (s, buffer, len, 0, (sockaddr *) &dstAddr, addrlen) == -1) {
|
||||
printf("%s: sendto error: %s \n",__FUNCTION__, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!isListen()) close (s);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int UDPConnection::isListen() {
|
||||
return (sock != -1);
|
||||
}
|
||||
|
||||
int UDPConnection::isData(int timeout) {
|
||||
fd_set sockset;
|
||||
struct timeval tval;
|
||||
|
||||
if (sock <= 0) {
|
||||
printf ("isData:socket error\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
FD_ZERO (&sockset);
|
||||
FD_SET (sock, &sockset);
|
||||
tval.tv_sec = timeout / 1000;
|
||||
tval.tv_usec = (timeout % 1000);
|
||||
|
||||
if (select (sock + 1, &sockset, NULL, NULL, &tval) >= 0) {
|
||||
if (FD_ISSET (sock, &sockset)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,55 @@
|
||||
|
||||
#ifndef _SP_UDP_H_
|
||||
#define _SP_UDP_H_
|
||||
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/wait.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define NET_HOSTLEN 128
|
||||
#define NET_PORTLEN 6
|
||||
#define NET_BUFFERSIZE 1024
|
||||
|
||||
|
||||
class UDPConnection {
|
||||
private:
|
||||
string port;
|
||||
int sock;
|
||||
size_t readcnt;
|
||||
size_t writecnt;
|
||||
public:
|
||||
UDPConnection();
|
||||
~UDPConnection();
|
||||
|
||||
int Listen(int port);
|
||||
int Listen(string port);
|
||||
|
||||
long int ReadTimeout(string *srcaddr, char *buffer, long int len, int timeout);
|
||||
long int Read(string *srcaddr, char *buffer, long int len);
|
||||
long int Send(string destaddr, char *buffer, long int len);
|
||||
|
||||
void Close();
|
||||
int isListen();
|
||||
int isData(int timeout); // timeout in ms;
|
||||
|
||||
int getSocket() { return sock; };
|
||||
void setSocket(int s);
|
||||
};
|
||||
|
||||
#endif
|
@ -0,0 +1,296 @@
|
||||
#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", ®);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,22 @@
|
||||
# autoscan configuration
|
||||
# sensor NUM addr ADDR reg REG
|
||||
sbox 0 addr 30 reg 0
|
||||
sbox 1 addr 31 reg 0
|
||||
sbox 2 addr 31 reg 1
|
||||
sbox 3 addr 0 reg 0
|
||||
sbox 4 addr 0 reg 0
|
||||
sbox 5 addr 0 reg 0
|
||||
sbox 6 addr 0 reg 0
|
||||
sbox 7 addr 0 reg 0
|
||||
sbox 8 addr 0 reg 0
|
||||
sbox 9 addr 0 reg 0
|
||||
sbox 10 addr 0 reg 0
|
||||
sbox 11 addr 0 reg 0
|
||||
sbox 12 addr 0 reg 0
|
||||
sbox 13 addr 0 reg 0
|
||||
sbox 14 addr 0 reg 0
|
||||
sbox 15 addr 0 reg 0
|
||||
sbox 16 addr 0 reg 0
|
||||
sbox 17 addr 0 reg 0
|
||||
sbox 18 addr 0 reg 0
|
||||
sbox 19 addr 0 reg 0
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* z21emu.h
|
||||
*
|
||||
* Created on: 16.12.2017
|
||||
* Author: steffen
|
||||
*/
|
||||
|
||||
#ifndef Z21EMU_H_
|
||||
#define Z21EMU_H_
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define DEFAULT_CONFIG ETCPREFIX"/z21emu.conf"
|
||||
|
||||
#define RBUS_BYTESPERGROUP 10
|
||||
#define RBUS_GROUPS 2
|
||||
#define RBUS_MAXSENSORBYTES (RBUS_GROUPS*RBUS_BYTESPERGROUP)
|
||||
|
||||
#define XLAN_TURNOUT_MAX 1024
|
||||
#define XLAN_TURNOUTBYTES (XLAN_TURNOUT_MAX / 8)
|
||||
|
||||
enum {
|
||||
I2CREGTYPE_UNDEF,
|
||||
I2CREGTYPE_DI,
|
||||
I2CREGTYPE_DO
|
||||
};
|
||||
|
||||
struct s_rbussensor {
|
||||
unsigned char status; // current value
|
||||
unsigned char last; // last value
|
||||
|
||||
unsigned char i2c_addr; // i2c address
|
||||
unsigned char i2c_reg; // i2c register
|
||||
};
|
||||
|
||||
extern struct s_rbussensor rbus[RBUS_MAXSENSORBYTES];
|
||||
|
||||
struct s_xlanturnout {
|
||||
unsigned char i2c_addr; // i2c address
|
||||
unsigned char i2c_reg; // i2c register
|
||||
|
||||
unsigned char output; // current value
|
||||
unsigned char last; // last value
|
||||
};
|
||||
|
||||
extern struct s_xlanturnout xlturn[XLAN_TURNOUT_MAX];
|
||||
extern int debug;
|
||||
|
||||
void xlan_turnout (int addr, bool enable);
|
||||
|
||||
|
||||
#endif /* Z21EMU_H_ */
|
@ -0,0 +1,36 @@
|
||||
#! /bin/sh
|
||||
### BEGIN INIT INFO
|
||||
# Provides: z21emu
|
||||
# Required-Start:
|
||||
# Required-Stop:
|
||||
# Should-Start:
|
||||
# Default-Start:
|
||||
# Default-Stop:
|
||||
# Short-Description: z21 wrapper to support i2c sensors
|
||||
# Description: z21 is a control device for model trains. this software implements a wrapper onto the z21 protocoll so you can connect some i2c devices to the rocrail or any other model train controlling software supporting z21.
|
||||
### END INIT INFO
|
||||
|
||||
PATH=/sbin:/bin:/usr/local/bin:/usr/bin:/usr/sbin
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
/usr/local/bin/z21emu >&2 > /dev/null &
|
||||
;;
|
||||
restart|reload|force-reload)
|
||||
echo "not pupported yet" >&2
|
||||
exit 3
|
||||
;;
|
||||
stop)
|
||||
killall z21emu
|
||||
;;
|
||||
status)
|
||||
ps xa -H | grep z21emu
|
||||
exit $?
|
||||
;;
|
||||
*)
|
||||
echo "Usage: z21emu.sh [start|stop|status]" >&2
|
||||
exit 3
|
||||
;;
|
||||
esac
|
||||
|
||||
:
|
@ -0,0 +1,268 @@
|
||||
/*
|
||||
* z21prot.cc
|
||||
*
|
||||
* Created on: 15.12.2017
|
||||
* Author: steffen
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "z21prot.h"
|
||||
#include "z21emu.h"
|
||||
#include "debug.h"
|
||||
|
||||
Z21Client::Z21Client() {
|
||||
// printf ("** %s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
};
|
||||
|
||||
Z21Client::~Z21Client() {
|
||||
// printf ("** %s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
};
|
||||
|
||||
bool Z21Client::LoopData (UDPConnection *udp, char *buffer, size_t len) {
|
||||
short unsigned int pktlen = le16toh(bufgetint16(buffer, 0));
|
||||
short int pktheader = le16toh(bufgetint16(buffer, 2));
|
||||
int i, k;
|
||||
|
||||
// LAN_GET_SERIAL_NUMBER
|
||||
if (pktlen == 4 && pktheader == 0x10) {
|
||||
bufsetint16 (outbuf, 0, htole16(8));
|
||||
bufsetint16 (outbuf, 2, htole16(0x10));
|
||||
bufsetint32 (outbuf, 4, htole32(55555953));
|
||||
udp->Send(source, outbuf, 8);
|
||||
}
|
||||
|
||||
// LAN_LOGOFF
|
||||
else if (pktlen == 4 && pktheader == 0x0030) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// LAN_X_ Commandos
|
||||
else if (pktheader == 0x0040) {
|
||||
if (pktlen > len) {
|
||||
printf ("ERROR: got broken udp paket? pktlen(%d) > len(%ld)\n", pktlen, len);
|
||||
} else {
|
||||
Z21_lan_x_data xdata;
|
||||
int pos = 4;
|
||||
int chksum;
|
||||
char db;
|
||||
|
||||
while (pos < pktlen) {
|
||||
xdata.xheader = buffer[pos++];
|
||||
for (i = 0; i < Z21_X_LEN && (unsigned int) i+pos < len; i++)
|
||||
xdata.db[i] = buffer[pos+i];
|
||||
|
||||
// LAN_X_GET_VERSION
|
||||
if (xdata.xheader == 0x21 &&
|
||||
xdata.db[0] == 0x21 && xdata.db[1] == 0x00) {
|
||||
printf ("LAN_X_GET_VERSION\n");
|
||||
pos += 2;
|
||||
|
||||
bufsetint16 (outbuf, 0, htole16(9));
|
||||
bufsetint16 (outbuf, 2, htole16(0x40));
|
||||
|
||||
k = 4;
|
||||
bufsetint8 (outbuf, k++, db=0x63); // XHeader
|
||||
chksum = db;
|
||||
|
||||
bufsetint8 (outbuf, k++, db=0x21); // DB0
|
||||
chksum = chksum ^ db;
|
||||
|
||||
bufsetint8 (outbuf, k++, db=0x30); // DB1
|
||||
chksum = chksum ^ db;
|
||||
|
||||
bufsetint8 (outbuf, k++, db=0x12); // DB2
|
||||
chksum = chksum ^ db;
|
||||
|
||||
bufsetint8 (outbuf, k++, chksum); // XOR-Byte
|
||||
// debug_mem(outbuf, k);
|
||||
udp->Send(source, outbuf, k);
|
||||
}
|
||||
|
||||
// LAN_X_GET_FIRMWARE_VERSION
|
||||
else if (xdata.xheader == 0xF1 &&
|
||||
xdata.db[0] == 0x0A && xdata.db[1] == 0xFB) {
|
||||
printf ("LAN_X_GET_FIRMWARE_VERSION\n");
|
||||
pos += 3;
|
||||
|
||||
bufsetint16 (outbuf, 0, htole16(9)); // LEN
|
||||
bufsetint16 (outbuf, 2, htole16(0x40)); // X_CMD
|
||||
|
||||
k = 4;
|
||||
bufsetint8 (outbuf, k++, db=0xF3); // XHeader
|
||||
chksum = db;
|
||||
|
||||
bufsetint8 (outbuf, k++, db=0x0A); // DB0
|
||||
chksum = chksum ^ db;
|
||||
|
||||
bufsetint8 (outbuf, k++, db=0x01); // DB1
|
||||
chksum = chksum ^ db;
|
||||
|
||||
bufsetint8 (outbuf, k++, db=0x20); // DB2
|
||||
chksum = chksum ^ db;
|
||||
|
||||
bufsetint8 (outbuf, k++, chksum); // XOR-Byte
|
||||
// debug_mem(outbuf, k);
|
||||
udp->Send(source, outbuf, k);
|
||||
}
|
||||
|
||||
// LAN_X_SET_TURNOUT
|
||||
else if (xdata.xheader == 0x53) {
|
||||
int addr = (xdata.db[0] << 8) + xdata.db[1];
|
||||
int cmd = xdata.db[2];
|
||||
int cmd_q = cmd & 0x20;
|
||||
int cmd_a = cmd & 0x08;
|
||||
int cmd_p = cmd & 0x01;
|
||||
pos += 4;
|
||||
printf ("LAN_X_SETTURNOUT addr: %d cmd: %x (q:%d a:%d p:%d)\n", addr, cmd, cmd_q, cmd_a, cmd_p);
|
||||
xlan_turnout (addr, (cmd_a != 0));
|
||||
}
|
||||
|
||||
else {
|
||||
printf ("LAN_X command not understood: %x\n", xdata.xheader);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// LAN_RMBUS_GETDATA --> send LAN_RMBUS_DATACHANGED
|
||||
else if (pktheader == 0x0081 && pktlen == 5) {
|
||||
unsigned char rmbus_grpidx = bufgetint8(buffer, 4);
|
||||
printf ("LAN_RMBUS_GETDATA\n");
|
||||
Send_LAN_RMBUS_DATACHANGED(udp, rmbus_grpidx);
|
||||
}
|
||||
|
||||
else {
|
||||
printf ("unknown command: ");
|
||||
// debug_mem (buffer, len);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Z21Client::Send_LAN_RMBUS_DATACHANGED (UDPConnection *udp, unsigned char grpidx) {
|
||||
int k, i;
|
||||
|
||||
printf ("Send LAN_RMBUS_DATACHANGED\n");
|
||||
if (grpidx >= RBUS_GROUPS) {
|
||||
printf (" giving group (%d) is not supported.\n", grpidx);
|
||||
return;
|
||||
}
|
||||
bufsetint16 (outbuf, 0, htole16(15)); // LEN
|
||||
bufsetint16 (outbuf, 2, htole16(0x80)); // X_CMD
|
||||
|
||||
k = 4;
|
||||
bufsetint8 (outbuf, k++, grpidx); // Gruppenindex
|
||||
|
||||
for (i = 0; i < RBUS_BYTESPERGROUP; i++)
|
||||
bufsetint8 (outbuf, k++, rbus[grpidx*RBUS_BYTESPERGROUP + i].status);
|
||||
|
||||
udp->Send(source, outbuf, k);
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
Z21Server::Z21Server () {
|
||||
// printf ("** %s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
};
|
||||
|
||||
Z21Server::~Z21Server () {
|
||||
// printf ("** %s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
};
|
||||
|
||||
void Z21Server::Start() {
|
||||
// printf ("** %s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
udp.Listen(DEFAULT_Z21PORT);
|
||||
};
|
||||
|
||||
|
||||
int Z21Server::Loop() {
|
||||
string source;
|
||||
size_t len;
|
||||
int newclient = 1;
|
||||
list<Z21Client*>::iterator iter;
|
||||
int i, grp;
|
||||
|
||||
if (udp.isListen()) {
|
||||
//
|
||||
// read new data from UDP
|
||||
len = udp.ReadTimeout(&source, buffer, NET_BUFFERSIZE, 25); // timeout 25ms
|
||||
if (len > 0) {
|
||||
//
|
||||
// check known connection
|
||||
newclient = 1;
|
||||
iter = clients.begin();
|
||||
while (iter != clients.end()) {
|
||||
if ((*iter)->isSource(source)) {
|
||||
newclient = 0;
|
||||
if (!((*iter)->LoopData(&udp, buffer, len))) {
|
||||
printf ("remove client: '%s' count:%ld\n", source.c_str(), clients.size());
|
||||
iter = clients.erase(iter);
|
||||
}
|
||||
break;
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
|
||||
//
|
||||
// new connection
|
||||
if (newclient && iter == clients.end()) {
|
||||
Z21Client *client;
|
||||
client = new Z21Client();
|
||||
client->setSource(source);
|
||||
if (client->LoopData(&udp, buffer, len)) {
|
||||
clients.push_back(client);
|
||||
printf ("add client: '%s' count:%ld\n", source.c_str(), clients.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// broadcast changed values
|
||||
for (grp = 0; grp < RBUS_GROUPS; grp++) {
|
||||
for (i = 0; i < RBUS_BYTESPERGROUP; i++)
|
||||
if (rbus[grp*RBUS_BYTESPERGROUP+i].status != rbus[grp*RBUS_BYTESPERGROUP+i].last) break;
|
||||
if (i != RBUS_BYTESPERGROUP) {
|
||||
//
|
||||
// send broadcast to all clients
|
||||
for (iter = clients.begin(); iter != clients.end(); iter++)
|
||||
(*iter)->Send_LAN_RMBUS_DATACHANGED(&udp, grp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return clients.size();
|
||||
};
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
uint8_t bufgetint8 (char *buf, int pos) {
|
||||
int8_t i;
|
||||
memcpy (&i, buf+pos, 1);
|
||||
return i;
|
||||
};
|
||||
|
||||
uint16_t bufgetint16 (char *buf, int pos) {
|
||||
int16_t i;
|
||||
memcpy (&i, buf+pos, 2);
|
||||
return i;
|
||||
};
|
||||
|
||||
uint32_t bufgetint32 (char *buf, int pos) {
|
||||
int32_t i;
|
||||
memcpy (&i, buf+pos, 4);
|
||||
return i;
|
||||
};
|
||||
|
||||
void bufsetint8 (char *buf, int pos, uint8_t i) {
|
||||
memcpy (buf+pos, &i, 1);
|
||||
};
|
||||
|
||||
void bufsetint16 (char *buf, int pos, uint16_t i) {
|
||||
memcpy (buf+pos, &i, 2);
|
||||
};
|
||||
|
||||
void bufsetint32 (char *buf, int pos, uint32_t i) {
|
||||
memcpy (buf+pos, &i, 4);
|
||||
};
|
||||
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* z21prot.h
|
||||
*
|
||||
* Created on: 15.12.2017
|
||||
* Author: steffen
|
||||
*/
|
||||
|
||||
#ifndef Z21PROT_H_
|
||||
#define Z21PROT_H_
|
||||
|
||||
#include <list>
|
||||
#include "udp.h"
|
||||
|
||||
#define Z21_X_LEN 16
|
||||
|
||||
struct {
|
||||
unsigned char xheader;
|
||||
unsigned char db[Z21_X_LEN];
|
||||
} typedef Z21_lan_x_data;
|
||||
|
||||
//
|
||||
// work around for memory alignment on some CPUs/PocketPCs
|
||||
uint8_t bufgetint8 (char *buf, int pos);
|
||||
uint16_t bufgetint16 (char *buf, int pos);
|
||||
uint32_t bufgetint32 (char *buf, int pos);
|
||||
void bufsetint8 (char *buf, int pos, uint8_t i);
|
||||
void bufsetint16 (char *buf, int pos, uint16_t i);
|
||||
void bufsetint32 (char *buf, int pos, uint32_t i);
|
||||
|
||||
class Z21Client {
|
||||
private:
|
||||
char outbuf[NET_BUFFERSIZE];
|
||||
string source;
|
||||
public:
|
||||
Z21Client();
|
||||
~Z21Client();
|
||||
|
||||
void setSource(string newsrc) { source = newsrc; };
|
||||
string getSource() { return source; };
|
||||
bool isSource(string srcaddr) { return (source.compare(srcaddr) == 0); };
|
||||
bool LoopData (UDPConnection *udp, char *buffer, size_t len);
|
||||
void Send_LAN_RMBUS_DATACHANGED (UDPConnection *udp, unsigned char grpidx);
|
||||
};
|
||||
|
||||
class Z21Server{
|
||||
private:
|
||||
list<Z21Client*> clients;
|
||||
UDPConnection udp;
|
||||
char buffer[NET_BUFFERSIZE];
|
||||
public:
|
||||
Z21Server ();
|
||||
~Z21Server ();
|
||||
|
||||
int Loop(); // returns number of connections
|
||||
void Start();
|
||||
};
|
||||
|
||||
#endif /* Z21PROT_H_ */
|
Loading…
Reference in new issue