Added project
This commit is contained in:
parent
fe9aa14dfd
commit
2d73cc8845
51
.gitignore
vendored
Normal file
51
.gitignore
vendored
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
#
|
||||||
|
# Xensit Xnode Ignore list
|
||||||
|
#
|
||||||
|
|
||||||
|
# Ignore all build folders
|
||||||
|
build
|
||||||
|
|
||||||
|
# Ignore all generated source
|
||||||
|
*.generated
|
||||||
|
|
||||||
|
# Ignore local include makefile
|
||||||
|
lib-build/make/Makefile.inc.local
|
||||||
|
|
||||||
|
# Ignore nodejs deps + www logs
|
||||||
|
lib-build/debug-server/www_logs
|
||||||
|
lib-build/debug-server/node_modules
|
||||||
|
lib-build/debug-server/npm-debug.log
|
||||||
|
lib-build/debug-server/www_static/js/lib
|
||||||
|
lib-build/debug-server/www_static/css/lib
|
||||||
|
|
||||||
|
# Ignore binary files
|
||||||
|
*.o
|
||||||
|
*.class
|
||||||
|
*.old
|
||||||
|
*.bak
|
||||||
|
*.backup
|
||||||
|
*.dat
|
||||||
|
*.data
|
||||||
|
*.gif
|
||||||
|
*.pdf
|
||||||
|
*.doc
|
||||||
|
|
||||||
|
# Ignore ~ backup files.
|
||||||
|
*~
|
||||||
|
|
||||||
|
# Ignore some eclipse files
|
||||||
|
.settings
|
||||||
|
.classpath
|
||||||
|
|
||||||
|
# Ignore netbeans directory
|
||||||
|
nbproject
|
||||||
|
|
||||||
|
# Ignore mac finder files
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Ignore windows files.
|
||||||
|
Thumbs.db
|
||||||
|
Desktop.ini
|
||||||
|
|
||||||
|
# Ignore kde dolphin files
|
||||||
|
.directory
|
11
.project
Normal file
11
.project
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>xnode</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
52
Makefile
Normal file
52
Makefile
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
#
|
||||||
|
# Call ordered depency make commands
|
||||||
|
#
|
||||||
|
|
||||||
|
# Save command line option for child
|
||||||
|
ARD_HOME_ARGU = ${ARD_HOME}
|
||||||
|
|
||||||
|
# Optional include an local override for arduino home
|
||||||
|
-include lib-build/make/Makefile.inc.local
|
||||||
|
|
||||||
|
# Safety check
|
||||||
|
ifndef ARD_HOME
|
||||||
|
$(error $$(ARD_HOME) not defined)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Only pass to child if defined from command line.
|
||||||
|
ifndef ARD_HOME_ARGU
|
||||||
|
ARD_HOME_ARGU_CHILD = ARD_HOME=${ARD_HOME}
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Locate and check for avr-size
|
||||||
|
AVR_SIZE ?= $(ARD_HOME)/hardware/tools/avr/bin/avr-size
|
||||||
|
ifeq ("$(wildcard $(AVR_SIZE))","")
|
||||||
|
$(error $$(AVR_SIZE) not found)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Define all projects to build
|
||||||
|
PROJECTS = \
|
||||||
|
xnode-base \
|
||||||
|
xnode-mega-flash \
|
||||||
|
xnode-satellite \
|
||||||
|
xnode-test-blink
|
||||||
|
|
||||||
|
# Hook all to projects
|
||||||
|
all: projects
|
||||||
|
|
||||||
|
# Declare subprojects targets
|
||||||
|
.PHONY: $(PROJECTS)
|
||||||
|
projects: $(PROJECTS) projects-result
|
||||||
|
$(PROJECTS):
|
||||||
|
$(MAKE) -s -C $@ clean all ${ARD_HOME_ARGU_CHILD}
|
||||||
|
projects-result:
|
||||||
|
@echo
|
||||||
|
@echo "Full xnode build is ready to burn."
|
||||||
|
@echo
|
||||||
|
@echo "Binary program sizes;"
|
||||||
|
${AVR_SIZE} xnode*/build/*.hex
|
||||||
|
@echo
|
||||||
|
@echo "Done."
|
||||||
|
|
||||||
|
# Declare subprojects depencies
|
||||||
|
xnode-mega-flash: xnode-satellite xnode-base xnode-test-blink
|
38
build.txt
Normal file
38
build.txt
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
|
||||||
|
Minimal build setup:
|
||||||
|
|
||||||
|
1) Download+unzip arduino ide version 1.6.0 is tested !
|
||||||
|
Get it from http://www.arduino.cc/
|
||||||
|
|
||||||
|
2) Install make and tcl;
|
||||||
|
apt-get install tcl make
|
||||||
|
|
||||||
|
3) Build all project in one go;
|
||||||
|
make ARD_HOME=/path/to/arduino-ide-1.6.0
|
||||||
|
|
||||||
|
Optional:
|
||||||
|
|
||||||
|
To override multiple flags and parameters for every
|
||||||
|
build there is a local makefile include template.
|
||||||
|
|
||||||
|
1) cp lib-build/make/Makefile.inc.local-template lib-build/make/Makefile.inc.local
|
||||||
|
2) Edit lib-build/make/Makefile.inc.local
|
||||||
|
3) make or cd xnode-base;make/etc
|
||||||
|
|
||||||
|
Now the make command of the sub projects and this parent build
|
||||||
|
will use the local make settings.
|
||||||
|
|
||||||
|
Build commands;
|
||||||
|
|
||||||
|
Build all hex files;
|
||||||
|
cd project-root/
|
||||||
|
make
|
||||||
|
|
||||||
|
Build clean satellite only
|
||||||
|
cd project-root/xnode-satellite
|
||||||
|
make clean all
|
||||||
|
|
||||||
|
Build and upload clean base only
|
||||||
|
cd project-root/xnode-base
|
||||||
|
make clean upload
|
||||||
|
make clean upload ISP_PORT=/dev/ttyACM1
|
291
lib-build/debug-server/node_lib/device/xdevice-connector-a.js
Normal file
291
lib-build/debug-server/node_lib/device/xdevice-connector-a.js
Normal file
|
@ -0,0 +1,291 @@
|
||||||
|
var XDeviceEncryption = require('./xdevice-encryption');
|
||||||
|
var Mongoose = require('mongoose');
|
||||||
|
var XSystemState = Mongoose.model( 'xsystem-state' );
|
||||||
|
var XNode = Mongoose.model( 'xnode' );
|
||||||
|
var XNodeBase = Mongoose.model( 'xnode-base' );
|
||||||
|
var XNodeBaseCommand = Mongoose.model( 'xnode-base-command' );
|
||||||
|
var XNodeData = Mongoose.model( 'xnode-data' );
|
||||||
|
var XNodeDataValue = Mongoose.model( 'xnode-data-value' );
|
||||||
|
var Async = require('async');
|
||||||
|
var Winston = require('winston');
|
||||||
|
var Log = Winston.loggers.get('main');
|
||||||
|
|
||||||
|
var createXnodeBase = function(created_ip,callbackResult) {
|
||||||
|
Async.series({
|
||||||
|
cnt_base_net_id: function(callback) {
|
||||||
|
XSystemState.incHexByName('_a_seq_base_net_id', function(err, xprop) {
|
||||||
|
callback(err,xprop.value);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
cnt_base_net_key: function(callback){
|
||||||
|
XSystemState.incHexByName('_a_seq_base_net_key', function(err, xprop) {
|
||||||
|
callback(err,xprop.value);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
cnt_base_net_mac: function(callback){
|
||||||
|
XSystemState.incHexByName('_a_seq_base_net_mac', function(err, xprop) {
|
||||||
|
callback(err,xprop.value);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
cnt_base_rf_key: function(callback){
|
||||||
|
XSystemState.incHexByName('_a_seq_base_rf_key', function(err, xprop) {
|
||||||
|
callback(err,xprop.value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
function(err, result) {
|
||||||
|
if (err) {
|
||||||
|
callbackResult(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var xnodeBase = new XNodeBase();
|
||||||
|
xnodeBase.created_ip = created_ip;
|
||||||
|
xnodeBase.net_id = result.cnt_base_net_id;
|
||||||
|
xnodeBase.net_key = result.cnt_base_net_key;
|
||||||
|
xnodeBase.net_mac = result.cnt_base_net_mac;
|
||||||
|
xnodeBase.rf_key = result.cnt_base_rf_key;
|
||||||
|
xnodeBase.init_index = 0;
|
||||||
|
xnodeBase.save(function(err,xnodeBase) {
|
||||||
|
Log.debug("XDeviceConnectorA.createXnodeBase _id="+xnodeBase._id+" net_id="+xnodeBase.net_id);
|
||||||
|
callbackResult(err,xnodeBase);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var handleInit = function(req,res,next) {
|
||||||
|
Log.debug('XDeviceConnectorA.handleInit');
|
||||||
|
var net_id = req.body.ni;
|
||||||
|
if (net_id == 0) {
|
||||||
|
createXnodeBase(req.ip,function(err,xnodeBase) {
|
||||||
|
if (err) { return next(err); }
|
||||||
|
Log.info('XDeviceConnectorA.handleInit response: Xinet_id '+xnodeBase.net_id);
|
||||||
|
res.send('Xinet_id '+xnodeBase.net_id+'\n');
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
XNodeBase.findOneByNetId(net_id,function(err,xnodeBase) {
|
||||||
|
if (err) { return next(err); }
|
||||||
|
if (xnodeBase == null) {
|
||||||
|
Log.warn('XDeviceConnectorA.handleInit illegal net_id='+req.body.ni);
|
||||||
|
res.send('X');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (xnodeBase.init_index > 4) {
|
||||||
|
Log.error('initXnode stateError, device was already init-ited.');
|
||||||
|
res.send('XXreboot');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
xnodeBase.init_index++;
|
||||||
|
xnodeBase.save(function(err) {
|
||||||
|
var result;
|
||||||
|
if (xnodeBase.init_index == 1) {
|
||||||
|
result = 'Xinet_key '+xnodeBase.net_key;
|
||||||
|
} else if (xnodeBase.init_index == 2) {
|
||||||
|
result = 'Xinet_mac '+xnodeBase.net_mac;
|
||||||
|
} else if (xnodeBase.init_index == 3) {
|
||||||
|
result = 'Xirf_key '+xnodeBase.rf_key;
|
||||||
|
} else if (xnodeBase.init_index == 4) {
|
||||||
|
result = 'Xireboot';
|
||||||
|
XNodeBaseCommand.insert(net_id,'help',req.ip,next); // trigger node data on next ping :)
|
||||||
|
} else {
|
||||||
|
result = 'X'; // code error
|
||||||
|
}
|
||||||
|
Log.info('XDeviceConnectorA.initXnode response net_id='+xnodeBase.net_id+' step='+xnodeBase.init_index+' reply='+result);
|
||||||
|
res.send(result);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var replyCommand = function(req,res,next) {
|
||||||
|
XNodeBaseCommand.findOpenByNetId(req.body.ni, function ( err, data ) {
|
||||||
|
if (err) { return next(err); }
|
||||||
|
if (data.length > 0) {
|
||||||
|
Log.debug('XDeviceConnectorA.replyCommand send cmd: '+data[0].command);
|
||||||
|
data[0].send_date = new Date();
|
||||||
|
data[0].save(function(err) {
|
||||||
|
if (err) { return next(err); }
|
||||||
|
res.send('XX'+data[0].command);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
res.send('X');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var logData = function(xnode,data_raw,data_text,req) {
|
||||||
|
var xdata = new XNodeData();
|
||||||
|
xdata.remote_ip = req.ip;
|
||||||
|
xdata.node_id = xnode.node_id;
|
||||||
|
xdata.net_id = req.body.ni;
|
||||||
|
xdata.data_raw = data_raw;
|
||||||
|
xdata.data_text = data_text;
|
||||||
|
xdata.save(function(err,xdata) {
|
||||||
|
if (err) { return next(err); }
|
||||||
|
Log.debug("XDeviceConnectorA.logData _id="+xdata._id+" net_id="+xdata.net_id+" node_id="+xdata.node_id+" data_text.length="+xdata.data_text.length);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var logDataValue = function(xnode,data_text,req, next) {
|
||||||
|
if (data_text.indexOf('help') > 0) {
|
||||||
|
return; // done't save help cmds as values.
|
||||||
|
}
|
||||||
|
if (data_text.indexOf('#ERR') > 0) {
|
||||||
|
return; // done't save errors.
|
||||||
|
}
|
||||||
|
var data_lines = data_text.split('\n');
|
||||||
|
for(var i = 0; i < data_lines.length; i ++) {
|
||||||
|
var data_line = data_lines[i];
|
||||||
|
var data_rows = data_line.split('=');
|
||||||
|
var data_name = data_rows[0];
|
||||||
|
var data_value = data_rows[1];
|
||||||
|
if (data_name.length == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
xval = new XNodeDataValue();
|
||||||
|
xval.net_id = xnode.net_id;
|
||||||
|
xval.node_id = xnode.node_id;
|
||||||
|
xval.name = data_name;
|
||||||
|
xval.value = data_value;
|
||||||
|
xval.save(function(err,xval) {
|
||||||
|
if (err) { return next(err); }
|
||||||
|
Log.debug("XDeviceConnectorA.logDataValue _id="+xval._id+" net_id="+xval.net_id+" node_id="+xval.node_id+" name="+xval.name+" value="+xval.value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var logRxCount = function(xnode,data_text,next) {
|
||||||
|
xnode.rx_date=new Date();
|
||||||
|
xnode.rx_requests++;
|
||||||
|
xnode.rx_bytes=data_text.length + xnode.rx_bytes;
|
||||||
|
xnode.save(function(err,xnode) {
|
||||||
|
if (err) { return next(err); }
|
||||||
|
Log.debug("XDeviceConnectorA.logRxCount _id="+xnode._id+" rx_requests="+xnode.rx_requests);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var updateMetaInfo = function(xnode,req, next) {
|
||||||
|
if (xnode.info_date == null) {
|
||||||
|
xnode.info_date = new Date(new Date().getTime() - 60*60*1000 - 1000); // triggers update
|
||||||
|
}
|
||||||
|
var dateLastHour = new Date(new Date().getTime() - 60*60*1000);
|
||||||
|
if (dateLastHour.getTime() > xnode.info_date.getTime() ) {
|
||||||
|
|
||||||
|
if (xnode.node_id == 1) {
|
||||||
|
XNodeBaseCommand.insert(xnode.net_id,'sys_info',req.ip, next);
|
||||||
|
XNodeBaseCommand.insert(xnode.net_id,'rf_info',req.ip, next);
|
||||||
|
XNodeBaseCommand.insert(xnode.net_id,'net_info',req.ip, next);
|
||||||
|
XNodeBaseCommand.insert(xnode.net_id,'net_info_eth0',req.ip, next);
|
||||||
|
} else {
|
||||||
|
Log.debug("todo");
|
||||||
|
//XNodeBaseCommand.insert(xnode.net_id,'@2 sys_info',req.ip, next);
|
||||||
|
//XNodeBaseCommand.insert(xnode.net_id,'@2 rf_info',req.ip, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
xnode.info_date = new Date();
|
||||||
|
xnode.save(function(err,xsat) {
|
||||||
|
if (err) { return next(err); }
|
||||||
|
Log.debug("XDeviceConnectorA.updateMetaInfo _id="+xnode._id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var handleDataNode = function(xnode,req,res,next) {
|
||||||
|
var net_id = req.body.ni;
|
||||||
|
var node_id = req.body.nn;
|
||||||
|
var data_raw = req.body.nd;
|
||||||
|
|
||||||
|
Log.debug('XDeviceConnectorA.handleDataNode ni='+xnode.net_id);
|
||||||
|
|
||||||
|
// log.debug('XDeviceConnectorA.handleData TODO FIX XXTEA');
|
||||||
|
// var result = XDeviceEncryption.xxteaDecrypt(req.body.nd,xnode.hw_net_key);
|
||||||
|
// log.debug('XDeviceConnectorA.handleData xxteaDecrypt='+result+' hw_net_key='+xnode.hw_net_key);
|
||||||
|
|
||||||
|
var data_text = data_raw;
|
||||||
|
|
||||||
|
logRxCount (xnode,data_text,next);
|
||||||
|
logData (xnode,data_raw,data_text,req);
|
||||||
|
logDataValue (xnode,data_text, req, next);
|
||||||
|
updateMetaInfo (xnode,req, next);
|
||||||
|
replyCommand (req,res,next);
|
||||||
|
}
|
||||||
|
|
||||||
|
var handleData = function(req,res,next) {
|
||||||
|
var net_id = req.body.ni;
|
||||||
|
var node_id = req.body.nn;
|
||||||
|
if (net_id == '000000000000') {
|
||||||
|
Log.warn('XDeviceConnectorA.handleData zero net_id='+net_id);
|
||||||
|
res.send('X');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (node_id == 0) {
|
||||||
|
Log.warn('XDeviceConnectorA.handleData zero node_id='+node_id);
|
||||||
|
res.send('X');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Log.debug('XDeviceConnectorA.handleData ni='+net_id+' nn='+node_id);
|
||||||
|
XNode.findByNetIdAndNodeId(net_id,node_id,function(err,xnode) {
|
||||||
|
if (err) { return next(err); }
|
||||||
|
if (xnode == null) {
|
||||||
|
Log.debug('XDeviceConnectorA.handleData creating new XNode.');
|
||||||
|
xnode = new XNode();
|
||||||
|
xnode.net_id = net_id;
|
||||||
|
xnode.node_id = node_id;
|
||||||
|
xnode.save(function(err) {
|
||||||
|
if (err) { return next(err); }
|
||||||
|
handleDataNode(xnode,req,res,next);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
handleDataNode(xnode,req,res,next);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var handlePing = function(req,res,next) {
|
||||||
|
var net_id = req.body.ni;
|
||||||
|
if (net_id == '000000000000') {
|
||||||
|
Log.debug('XDeviceConnectorA.handlePing zero net_id='+net_id);
|
||||||
|
res.send('X');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Log.debug('XDeviceConnectorA.handlePing net_id='+net_id);
|
||||||
|
XNodeBase.findOneByNetId(net_id,function(err,xnodeBase) {
|
||||||
|
if (err) { return next(err); }
|
||||||
|
if (xnodeBase == null) {
|
||||||
|
Log.warn('XDeviceConnectorA.handlePing illegal net_id='+net_id);
|
||||||
|
res.send('X');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
xnodeBase.ping_counter++;
|
||||||
|
xnodeBase.ping_last_date=new Date();
|
||||||
|
xnodeBase.save(function(err) {
|
||||||
|
if (err) { return next(err); }
|
||||||
|
if (req.body.rc == 0) {
|
||||||
|
res.send('X'); // no cmd on first ping.
|
||||||
|
} else {
|
||||||
|
replyCommand(req,res,next);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.deviceControl = function(req, res, next) {
|
||||||
|
var postType = req.body.pt;
|
||||||
|
var url = req.originalUrl || req.url;
|
||||||
|
var ip = req.ip;
|
||||||
|
Log.debug('POST '+url+' ip='+ip+' pt='+postType+' rc='+req.body.rc+' ni='+req.body.ni);
|
||||||
|
if (postType == 'i') {
|
||||||
|
handleInit(req,res,next);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (postType == 'p') {
|
||||||
|
handlePing(req,res,next);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (postType == 'd') {
|
||||||
|
handleData(req,res,next);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Log.warn('XDeviceConnectorA.deviceControl unknown postType='+postType);
|
||||||
|
res.send('X');
|
||||||
|
}
|
||||||
|
|
120
lib-build/debug-server/node_lib/device/xdevice-encryption.js
Normal file
120
lib-build/debug-server/node_lib/device/xdevice-encryption.js
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
var winston = require('winston');
|
||||||
|
var log = winston.loggers.get('main');
|
||||||
|
|
||||||
|
var delta = 0x9E3779B9;
|
||||||
|
var XXTEA_NUM_ROUNDS = 32;
|
||||||
|
|
||||||
|
//var xxxteaEncrypt = function(unsigned long v[2]) {
|
||||||
|
// unsigned int i;
|
||||||
|
// unsigned long v0=v[0], v1=v[1], sum=0, delta=0x9E3779B9;
|
||||||
|
// for (i=0; i < XXTEA_NUM_ROUNDS; i++) {
|
||||||
|
// v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + XBHardware.config.net_key.u32[sum & 3]);
|
||||||
|
// sum += delta;
|
||||||
|
// v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + XBHardware.config.net_key.u32[(sum>>11) & 3]);
|
||||||
|
// }
|
||||||
|
// v[0]=v0; v[1]=v1;
|
||||||
|
//}
|
||||||
|
|
||||||
|
var xxxteaDecrypt = function(vArray,keyBuff) {
|
||||||
|
log.debug('XDeviceEncryption.xxxteaDecrypt vArray='+JSON.stringify(vArray)+' keyBuff='+JSON.stringify(keyBuff));
|
||||||
|
var v0=vArray.v0;
|
||||||
|
var v1=vArray.v1;
|
||||||
|
|
||||||
|
log.debug('XDeviceEncryption.xxxteaDecrypt start v0='+v0.toString(16)+' v1='+v1.toString(16));
|
||||||
|
|
||||||
|
var delta=0x9E3779B9
|
||||||
|
var sum=delta*XXTEA_NUM_ROUNDS;
|
||||||
|
for (var i=0; i < XXTEA_NUM_ROUNDS; i++) {
|
||||||
|
v1 -= (((v0 << 4) ^ (v0 >>> 5)) + v0) ^ (sum + keyBuff.readUInt32BE((sum>>>11) & 3));
|
||||||
|
var v1Org = v1;
|
||||||
|
|
||||||
|
sum -= delta;
|
||||||
|
v0 -= (((v1 << 4) ^ (v1 >>> 5)) + v1) ^ (sum + keyBuff.readUInt32BE(sum & 3));
|
||||||
|
|
||||||
|
//log.debug('XDeviceEncryption.xxxteaDecrypt v0='+v0.toString(16)+' v1='+v1.toString(16));
|
||||||
|
|
||||||
|
if (v0 < 0) { v0 = Math.pow(2,32) + v0; }
|
||||||
|
if (v0 > Math.pow(2,32)) { v0 = v0 - Math.pow(2,32); }
|
||||||
|
|
||||||
|
if (v1 < 0) { v1 = Math.pow(2,32) + v1; }
|
||||||
|
if (v1 > Math.pow(2,32)) { v1 = v1 - Math.pow(2,32); }
|
||||||
|
}
|
||||||
|
|
||||||
|
//v0 = v0 & 0xFFFFFFFF;
|
||||||
|
//v1 = v1 & 0xFFFFFFFF;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var result = {v0: v0,v1: v1};
|
||||||
|
log.debug('XDeviceEncryption.xxxteaDecrypt result='+JSON.stringify(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// public static method encrypt
|
||||||
|
exports.xxteaEncrypt = function(string, key) {
|
||||||
|
log.debug('XDeviceEncryption.xxteaEncrypt key='+key+' data='+string);
|
||||||
|
if (string.length == 0) {
|
||||||
|
return('');
|
||||||
|
}
|
||||||
|
|
||||||
|
//var v = strToLongs(Utf8.encode(string));
|
||||||
|
//var k = strToLongs(Utf8.encode(key).slice(0,16));
|
||||||
|
var v = buffToLongs(new Buffer(string, 'hex'));
|
||||||
|
var k = buffToLongs(new Buffer(key, 'hex'));
|
||||||
|
|
||||||
|
//if (v.length <= 1) v[1] = 0; // algorithm doesn't work for n<2 so fudge by adding a null
|
||||||
|
var n = v.length;
|
||||||
|
|
||||||
|
// ---- <TEA coding> ----
|
||||||
|
|
||||||
|
var z = v[n-1], y = v[0], delta = 0x9E3779B9;
|
||||||
|
var mx, e, q = Math.floor(6 + 52/n), sum = 0;
|
||||||
|
|
||||||
|
while (q-- > 0) { // 6 + 52/n operations gives between 6 & 32 mixes on each word
|
||||||
|
sum += delta;
|
||||||
|
e = sum>>>2 & 3;
|
||||||
|
for (var p = 0; p < n; p++) {
|
||||||
|
y = v[(p+1)%n];
|
||||||
|
mx = (z>>>5 ^ y<<2) + (y>>>3 ^ z<<4) ^ (sum^y) + (k[p&3 ^ e] ^ z);
|
||||||
|
z = v[p] += mx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- </TEA> ----
|
||||||
|
|
||||||
|
var buff = longsToBuff(v);
|
||||||
|
return buff.toString('ascii');
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.xxteaDecrypt = function(data, key) {
|
||||||
|
log.debug('XDeviceEncryption.xxteaDecrypt key='+key+' data='+data);
|
||||||
|
if (data.length == 0) {
|
||||||
|
return('');
|
||||||
|
}
|
||||||
|
var d = new Buffer(data, 'hex');
|
||||||
|
var k = new Buffer(key, 'hex');
|
||||||
|
var n = d.length;
|
||||||
|
var r = new Buffer(n);
|
||||||
|
|
||||||
|
log.debug('XDeviceEncryption.xxteaDecrypt dataBuffer='+d.toString('hex'));
|
||||||
|
|
||||||
|
// ---- <TEA decoding> ----
|
||||||
|
|
||||||
|
for (var i=0;i<n/4-1;i=i+2) {
|
||||||
|
//log.debug('XDeviceEncryption.xxteaDecrypt n='+n+' i='+i+' c='+(i*4)+' cc='+(i*4+1)+' r='+d.readUInt32LE(i*4).toString(16)+' r1='+d.readUInt32BE(i*4).toString(16));
|
||||||
|
var ed = {v0: d.readUInt32BE(i*4),v1: d.readUInt32BE((i+1)*4)};
|
||||||
|
var dd = xxxteaDecrypt(ed,k);
|
||||||
|
r.writeUInt32BE(dd.v0,i*4);
|
||||||
|
r.writeUInt32BE(dd.v1,(i+1)*4);
|
||||||
|
}
|
||||||
|
return r.toString('ascii');
|
||||||
|
|
||||||
|
//var plaintext = longsToStr(v);
|
||||||
|
//plaintext = plaintext.replace(/\0+$/,'');
|
||||||
|
//return plaintext;
|
||||||
|
//return new Buffer(plaintext,'utf8').toString('ascii');
|
||||||
|
|
||||||
|
//var plaintext = longsToStr(v);
|
||||||
|
//plaintext = plaintext.replace(/\0+$/,'');// strip trailing null chars resulting from filling 4-char blocks:
|
||||||
|
//return Utf8.decode(plaintext);
|
||||||
|
}
|
123
lib-build/debug-server/node_lib/lib/build-backend-mongoose.js
Normal file
123
lib-build/debug-server/node_lib/lib/build-backend-mongoose.js
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
var logger = require('winston').loggers.get('main');
|
||||||
|
var clone = require('clone');
|
||||||
|
var mongoose = require('mongoose');
|
||||||
|
var validate = require('validate.io');
|
||||||
|
var tcrudField = require('./tcrud-field');
|
||||||
|
var buildConfig = require('./build-config');
|
||||||
|
|
||||||
|
function autoFieldType(fieldMeta,fieldType) {
|
||||||
|
if (!fieldMeta) {
|
||||||
|
throw new Error('no fieldMeta');
|
||||||
|
}
|
||||||
|
if (fieldType && fieldType.length != 0) {
|
||||||
|
return fieldType;
|
||||||
|
}
|
||||||
|
if (fieldMeta.type == Date) {
|
||||||
|
return 'date';
|
||||||
|
}
|
||||||
|
return 'text';
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.buildFields = function(modelMeta) {
|
||||||
|
if (!modelMeta) {
|
||||||
|
throw new Error('no modelMeta');
|
||||||
|
}
|
||||||
|
var tfields = {};
|
||||||
|
var keys = Object.keys(modelMeta);
|
||||||
|
for (i = 0; i < keys.length; i++) {
|
||||||
|
var key = keys[i];
|
||||||
|
var value = modelMeta[key];
|
||||||
|
var tfield = null;
|
||||||
|
if (key && value && value.tfield) {
|
||||||
|
//console.log('tfield model cloned');
|
||||||
|
tfield = clone(value.tfield);
|
||||||
|
tfield.tid = key;
|
||||||
|
tfield.tname = tcrudField.autoFieldName(key,tfield.tname);
|
||||||
|
tfield.type = autoFieldType(value,tfield.ttype);
|
||||||
|
} else if (key && value) {
|
||||||
|
//console.log('tfield model auto created');
|
||||||
|
tfield = tcrudField.newInstance(key);
|
||||||
|
tfield.tname = tcrudField.autoFieldName(key);
|
||||||
|
tfield.type = autoFieldType(value);
|
||||||
|
}
|
||||||
|
if (tfield.tvalidate && tfield.tvalidate.io) {
|
||||||
|
//console.log('tfield validate rule: '+tfield.tvalidate.io);
|
||||||
|
}
|
||||||
|
tcrudField.fillDefaults(tfield);
|
||||||
|
tfields[tfield.tid] = tfield;
|
||||||
|
}
|
||||||
|
return tfields;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ss(valueRule) {
|
||||||
|
return function (value, response) {
|
||||||
|
response(validate(valueRule,value));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.createModelValidators = function (modelSchema,modelFields) {
|
||||||
|
if (!modelSchema) {
|
||||||
|
throw new Error('no modelSchema');
|
||||||
|
}
|
||||||
|
if (!modelFields) {
|
||||||
|
throw new Error('no modelFields');
|
||||||
|
}
|
||||||
|
var keys = Object.keys(modelFields);
|
||||||
|
for (var i = 0; i < keys.length; i++) {
|
||||||
|
var key = keys[i];
|
||||||
|
var tfield = modelFields[key];
|
||||||
|
if (!tfield.tvalidate) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!tfield.tvalidate.io) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
modelSchema.path(tfield.tid).validate(ss(tfield.tvalidate.io), '{PATH} validation failed: '+tfield.tvalidate.io);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.buildStatics = function(modelFields,modelStatics) {
|
||||||
|
if (!modelFields) {
|
||||||
|
throw new Error('no modelFields');
|
||||||
|
}
|
||||||
|
if (!modelStatics) {
|
||||||
|
modelStatics = {};
|
||||||
|
}
|
||||||
|
modelStatics['ff_tcrud_fields'] = modelFields;
|
||||||
|
return modelStatics;
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.buildTCrudModel = function(mongoose,tcrudParent,name) {
|
||||||
|
var model = mongoose.model(name);
|
||||||
|
var tcrud = buildConfig.createTCrud(tcrudParent,name);
|
||||||
|
var tfields = model['ff_tcrud_fields'];
|
||||||
|
if (tfields) {
|
||||||
|
tcrud.tmeta.tfields = tfields;
|
||||||
|
}
|
||||||
|
tcrud.tmodel = name;
|
||||||
|
//tcrud.tbackend = 'mongoose';
|
||||||
|
return tcrud;
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.buildTCrudModels = function(mongoose,tcrudParent) {
|
||||||
|
var result = [];
|
||||||
|
var modelNames = mongoose.connection.modelNames();
|
||||||
|
for (var i = 0; i < modelNames.length; i++) {
|
||||||
|
result.push(exports.buildTCrudModel(mongoose,tcrudParent,modelNames[i]))
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ----- wrappers
|
||||||
|
|
||||||
|
exports.buildStaticsModel = function(modelMeta,modelStatics) {
|
||||||
|
return exports.buildStatics(exports.buildFields(modelMeta),modelStatics);
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.buildStaticsModelValidated = function(modelMeta,modelSchema,modelStatics) {
|
||||||
|
var modelFields = exports.buildFields(modelMeta);
|
||||||
|
exports.createModelValidators(modelSchema,modelFields);
|
||||||
|
return exports.buildStatics(modelFields,modelStatics);
|
||||||
|
}
|
||||||
|
|
16
lib-build/debug-server/node_lib/lib/build-config.js
Normal file
16
lib-build/debug-server/node_lib/lib/build-config.js
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
var logger = require('winston').loggers.get('main');
|
||||||
|
var clone = require('clone');
|
||||||
|
var tcrud = require('./tcrud');
|
||||||
|
var tcrudField = require('./tcrud-field');
|
||||||
|
|
||||||
|
|
||||||
|
exports.createTCrudRoot = function() {
|
||||||
|
return tcrud.newInstance('root');
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.createTCrud = function(parent, id) {
|
||||||
|
var result = tcrud.newInstance(id);
|
||||||
|
parent.tchilds.push(result);
|
||||||
|
result.tparent = parent;
|
||||||
|
return result;
|
||||||
|
}
|
95
lib-build/debug-server/node_lib/lib/build-view.js
Normal file
95
lib-build/debug-server/node_lib/lib/build-view.js
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
var logger = require('winston').loggers.get('main');
|
||||||
|
var clone = require('clone');
|
||||||
|
var tcrud = require('./tcrud');
|
||||||
|
var tcrudView = require('./tcrud-view');
|
||||||
|
|
||||||
|
|
||||||
|
exports.createBaseApiUri = function(tview, tech, action) {
|
||||||
|
var uriView = tview.tslug;
|
||||||
|
var uriTech = tview.tmeta.texport[tech].tslug;
|
||||||
|
var uriAction = '';
|
||||||
|
if (action) {
|
||||||
|
uriAction = '/' + tview[action].texport[tech].tslug;
|
||||||
|
}
|
||||||
|
|
||||||
|
//logger.info('createBaseApiUri uriTech: '+uriTech+' uriView: '+uriView+' uriAction: '+uriAction);
|
||||||
|
|
||||||
|
if (tview.tmeta.tserver.tpopfix) {
|
||||||
|
return uriTech + '/' + uriView + uriAction;
|
||||||
|
} else {
|
||||||
|
return uriView + '/' + uriTech + uriAction;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function allowSlugSlash(tcrud) {
|
||||||
|
var result = true;
|
||||||
|
if (tcrud.tparent) {
|
||||||
|
result = allowSlugSlash(tcrud.tparent);
|
||||||
|
if (!result) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tcrud.tcount.tslug === '') {
|
||||||
|
return 'tcount';
|
||||||
|
}
|
||||||
|
if (tcrud.tlist.tslug === '') {
|
||||||
|
return 'tlist';
|
||||||
|
}
|
||||||
|
if (tcrud.tcreate.tslug === '') {
|
||||||
|
return 'tcreate';
|
||||||
|
}
|
||||||
|
if (tcrud.tread.tslug === '') {
|
||||||
|
return 'tread';
|
||||||
|
}
|
||||||
|
if (tcrud.tedit.tslug === '') {
|
||||||
|
return 'tedit';
|
||||||
|
}
|
||||||
|
if (tcrud.tdelete.tslug === '') {
|
||||||
|
return 'tdelete';
|
||||||
|
}
|
||||||
|
// if (tcrud.tverify.tslug === '') {
|
||||||
|
//return false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createTCrudViewSlug(tcrud) {
|
||||||
|
var uriViewSlash = '/';
|
||||||
|
var slug = uriViewSlash + tcrud.tslug;
|
||||||
|
if (!tcrud.tenable || !tcrud.tparent) {
|
||||||
|
slug = '';
|
||||||
|
}
|
||||||
|
if (tcrud.tparent) {
|
||||||
|
return createTCrudViewSlug(tcrud.tparent)+slug;
|
||||||
|
}
|
||||||
|
return slug;
|
||||||
|
}
|
||||||
|
|
||||||
|
var fetchEmptyRoles = function() {
|
||||||
|
return function (callback) {
|
||||||
|
callback(null,[]);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.createTCrudView = function(tcrud,xrollesCallback) {
|
||||||
|
if (!tcrud) {
|
||||||
|
throw new Error('no tcrud');
|
||||||
|
}
|
||||||
|
if (!xrollesCallback) {
|
||||||
|
xrollesCallback = fetchEmptyRoles;
|
||||||
|
}
|
||||||
|
var tview = tcrudView.newInstance(tcrud);
|
||||||
|
tview.tslug = createTCrudViewSlug(tcrud).substring(1);
|
||||||
|
/*
|
||||||
|
var uriViewSlashAllow = allowSlugSlash(tcrud);
|
||||||
|
if (uriViewSlashAllow !== null) {
|
||||||
|
uriViewSlash = '_';
|
||||||
|
console.log('detected crud actions with empty tslug; deploying in list mode slash; '+uriViewSlash+' in: '+uriViewSlashAllow+' of: '+tcrud.xid);
|
||||||
|
tview.tslug = buildSlug(uriViewSlash,tcrud).substring(1);
|
||||||
|
} else {
|
||||||
|
tview.tslug = buildSlug(uriViewSlash,tcrud);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
return tview;
|
||||||
|
}
|
338
lib-build/debug-server/node_lib/lib/factory-express-api.js
Normal file
338
lib-build/debug-server/node_lib/lib/factory-express-api.js
Normal file
|
@ -0,0 +1,338 @@
|
||||||
|
var logger = require('winston').loggers.get('main');
|
||||||
|
var clone = require('clone');
|
||||||
|
var fs = require('fs');
|
||||||
|
var ejs = require('ejs');
|
||||||
|
var xmlmapping = require('xml-mapping');
|
||||||
|
var rawbody = require('raw-body');
|
||||||
|
var typeis = require('type-is');
|
||||||
|
var mcrud = require('crud-mongoose');
|
||||||
|
var ncrud = require('node-crud');
|
||||||
|
var mongoose = require('mongoose');
|
||||||
|
var buildView = require('./build-view');
|
||||||
|
|
||||||
|
exports.bodyParserXml = function() {
|
||||||
|
return function(req, res, next) {
|
||||||
|
if (req._body) return next();
|
||||||
|
req.body = req.body || {};
|
||||||
|
|
||||||
|
if (!typeis(req, 'xml')) return next();
|
||||||
|
|
||||||
|
// flag as parsed
|
||||||
|
req._body = true;
|
||||||
|
|
||||||
|
// parse
|
||||||
|
rawbody(req, {
|
||||||
|
limit: options.limit || '100kb',
|
||||||
|
length: req.headers['content-length'],
|
||||||
|
encoding: 'utf8'
|
||||||
|
}, function (err, buf) {
|
||||||
|
if (err) return next(err);
|
||||||
|
|
||||||
|
if (0 == buf.length) {
|
||||||
|
return next(error(400, 'invalid xml, empty body'));
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
req.body = xmlmapping.dump(buf/*, options.reviver*/);
|
||||||
|
} catch (err){
|
||||||
|
err.body = buf;
|
||||||
|
err.status = 400;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var renderTemplateDataRead = function(tview, exportType, contentType, model, projection) {
|
||||||
|
return function(data, query, cb) {
|
||||||
|
var res = this.response;
|
||||||
|
res.set('Content-Type', contentType);
|
||||||
|
|
||||||
|
var cursor, fields;
|
||||||
|
if (query.hasOwnProperty('fields')) {
|
||||||
|
fields = query.fields;
|
||||||
|
delete query.fields;
|
||||||
|
}
|
||||||
|
delete query.export;
|
||||||
|
cursor = model.findOne(query);
|
||||||
|
cursor.select(mcrud.tools.select(projection, fields));
|
||||||
|
cursor.lean().exec(function(err,doc) {
|
||||||
|
if (err) {
|
||||||
|
cb(err || 'error in stream');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (doc == null) {
|
||||||
|
cb('no data'); // TODO: error is still in json...
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//var templateReadHeader = fs.readFileSync('node_code/lib/www_views/node-ff-tcrud/'+exportType+'/read-header.ejs', 'utf8');
|
||||||
|
var templateReadRecord = fs.readFileSync('node_code/lib/www_views/node-ff-tcrud/'+exportType+'/read-record.ejs', 'utf8');
|
||||||
|
//var templateReadFooter = fs.readFileSync('node_code/lib/www_views/node-ff-tcrud/'+exportType+'/read-footer.ejs', 'utf8');
|
||||||
|
res.write(ejs.render(templateReadRecord,{
|
||||||
|
tview: tview,
|
||||||
|
record: doc,
|
||||||
|
}));
|
||||||
|
res.end();
|
||||||
|
|
||||||
|
//cb(); // FIXME
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var renderTemplateDataList = function(tview, exportType, contentType) {
|
||||||
|
return function(res, cursor, cb) {
|
||||||
|
res.set('Content-Type', contentType);
|
||||||
|
|
||||||
|
var templateHeader = fs.readFileSync('node_code/lib/www_views/node-ff-tcrud/'+exportType+'/list-header.ejs', 'utf8');
|
||||||
|
var templateRecord = fs.readFileSync('node_code/lib/www_views/node-ff-tcrud/'+exportType+'/list-record.ejs', 'utf8');
|
||||||
|
var templateFooter = fs.readFileSync('node_code/lib/www_views/node-ff-tcrud/'+exportType+'/list-footer.ejs', 'utf8');
|
||||||
|
|
||||||
|
res.write(ejs.render(templateHeader,{
|
||||||
|
tview: tview,
|
||||||
|
}));
|
||||||
|
cursor.stream()
|
||||||
|
.on('data', function(doc) {
|
||||||
|
res.write(ejs.render(templateRecord,{
|
||||||
|
tview: tview,
|
||||||
|
record: doc,
|
||||||
|
}));
|
||||||
|
})
|
||||||
|
.on('error', function(e) {
|
||||||
|
cb(e || 'error in stream');
|
||||||
|
})
|
||||||
|
.on('close', function() {
|
||||||
|
res.write(ejs.render(templateFooter,{
|
||||||
|
tview: tview,
|
||||||
|
}));
|
||||||
|
res.end();
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.injectExportFormat = function(apiBase) {
|
||||||
|
return function ( req, res, next ) {
|
||||||
|
if (req.url.indexOf(apiBase) >= 0) {
|
||||||
|
if (req.url.indexOf('xml') > 0) {
|
||||||
|
req.query['export'] = 'xml';
|
||||||
|
} else if (req.url.indexOf('csv') > 0) {
|
||||||
|
req.query['export'] = 'csv';
|
||||||
|
} else if (req.url.indexOf('rss') > 0) {
|
||||||
|
req.query['export'] = 'rss';
|
||||||
|
}
|
||||||
|
if (req.url.indexOf('json') == 0) {
|
||||||
|
console.log('inject export type: '+req.query['export']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = require('underscore');
|
||||||
|
|
||||||
|
var filterQueryList = function (model) {
|
||||||
|
return mcrud.parseQuery()
|
||||||
|
.defaults({ limit: '10' })
|
||||||
|
.overrides({})
|
||||||
|
.maxes({ limit: 1000 });
|
||||||
|
//.removes()
|
||||||
|
}
|
||||||
|
|
||||||
|
var filterDataUpdate = function (model) {
|
||||||
|
return mcrud.parseData()
|
||||||
|
overrides({});
|
||||||
|
//.removes('auth')
|
||||||
|
//.overrides({ updated: Date.now })
|
||||||
|
//.defaults({ 'info.gender': 'M' }))
|
||||||
|
}
|
||||||
|
|
||||||
|
function allowCrudType(tview,tcrudType) {
|
||||||
|
return tview[tcrudType].tenable; // todo add roles
|
||||||
|
}
|
||||||
|
|
||||||
|
//var rssXNodeMap = function(link,feed,data) {
|
||||||
|
// feed.addNewItem(data.net_id, link+'/ui/XNode/read/'+data._id, data.changed_data, data.net_id+' id', {});
|
||||||
|
//}
|
||||||
|
|
||||||
|
var sendRedirect = function (location) {
|
||||||
|
if (!location) {
|
||||||
|
throw new Error('no location');
|
||||||
|
}
|
||||||
|
return function(req, res) {
|
||||||
|
res.redirect(location);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
var renderCrudView = function (tview) {
|
||||||
|
return function (req, res, next) {
|
||||||
|
var result = {
|
||||||
|
tview: tview,
|
||||||
|
}
|
||||||
|
res.json({
|
||||||
|
data: result
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var renderCrudController = function (tview, thtmlPrefix, tapiPrefix) {
|
||||||
|
return function (req, res, next) {
|
||||||
|
res.set('Content-Type', 'text/javascript');
|
||||||
|
res.render('node-ff-tcrud/angular/controller',{
|
||||||
|
tview: tview,
|
||||||
|
thtmlPrefix: thtmlPrefix,
|
||||||
|
tapiPrefix: tapiPrefix,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var renderCrudTemplate = function (tview,paction) {
|
||||||
|
return function (req, res, next) {
|
||||||
|
res.render('node-ff-tcrud/angular/'+paction+'/'+req.params.action,{
|
||||||
|
tview: tview,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var buildCrud = function (server,tcrud) {
|
||||||
|
|
||||||
|
if (!tcrud.tenable || !tcrud.tmodel) {
|
||||||
|
logger.info('disabled server: '+tcrud.tid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tview = buildView.createTCrudView(tcrud /*, fetchCrudRoles()*/);
|
||||||
|
var model = mongoose.model( tcrud.tmodel );
|
||||||
|
|
||||||
|
// Export tdebug
|
||||||
|
var uriDebug = tcrud.tmeta.tserver.tslug + '/' +buildView.createBaseApiUri(tview,'json') + '/_debug/';
|
||||||
|
var tcrudClone = clone(tcrud);
|
||||||
|
tcrudClone.tparent = null; // rm loop: tparent.tchilds[] = this
|
||||||
|
server.get(uriDebug + 'tview', renderCrudView(tview));
|
||||||
|
server.get(uriDebug + 'tcrud', renderCrudView(tcrudClone));
|
||||||
|
|
||||||
|
if (_.contains(tview.tmeta.tserver.texports,'json')) {
|
||||||
|
|
||||||
|
if (allowCrudType(tview,'tlist')) {
|
||||||
|
ncrud.entity(buildView.createBaseApiUri(tview,'json','tlist')).Read()
|
||||||
|
.pipe(filterQueryList(model))
|
||||||
|
.pipe(mcrud.findAll(model).stream());
|
||||||
|
}
|
||||||
|
if (allowCrudType(tview,'tcreate')) {
|
||||||
|
ncrud.entity(buildView.createBaseApiUri(tview,'json','tcreate')).Create()
|
||||||
|
.pipe(mcrud.createNew(model));
|
||||||
|
}
|
||||||
|
if (allowCrudType(tview,'tread')) {
|
||||||
|
ncrud.entity(buildView.createBaseApiUri(tview,'json','tread') + '/:_id').Read()
|
||||||
|
.pipe(mcrud.findOne(model));
|
||||||
|
}
|
||||||
|
if (allowCrudType(tview,'tedit')) {
|
||||||
|
ncrud.entity(buildView.createBaseApiUri(tview,'json','tedit') + '/:_id').Update()
|
||||||
|
.pipe(filterDataUpdate(model))
|
||||||
|
.pipe(mcrud.updateOne (model));
|
||||||
|
}
|
||||||
|
if (allowCrudType(tview,'tdelete')) {
|
||||||
|
ncrud.entity(buildView.createBaseApiUri(tview,'json','tdelete') +'/:_id').Delete()
|
||||||
|
.pipe(mcrud.removeOne(model));
|
||||||
|
}
|
||||||
|
if (allowCrudType(tview,'tcount')) {
|
||||||
|
ncrud.entity(buildView.createBaseApiUri(tview,'json','tcount')).Read()
|
||||||
|
.pipe(filterQueryList(model))
|
||||||
|
.pipe(mcrud.findAll(model).stream());
|
||||||
|
}
|
||||||
|
if (allowCrudType(tview,'tverify')) {
|
||||||
|
ncrud.entity(buildView.createBaseApiUri(tview,'json','tverify') + '/:_id').Update()
|
||||||
|
.pipe(mcrud.findOne(model));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_.contains(tview.tmeta.tserver.texports,'xml')) {
|
||||||
|
if (allowCrudType(tview,'tlist')) {
|
||||||
|
ncrud.entity(buildView.createBaseApiUri(tview,'xml','tlist')).Read()
|
||||||
|
.pipe(filterQueryList(model))
|
||||||
|
.pipe(mcrud.findAll(model).stream().exports({ xml: renderTemplateDataList(tview,'xml','text/xml') }));
|
||||||
|
}
|
||||||
|
if (allowCrudType(tview,'tcreate')) {
|
||||||
|
ncrud.entity(buildView.createBaseApiUri(tview,'xml','tcreate')).Create()
|
||||||
|
.pipe(mcrud.createNew(model));
|
||||||
|
}
|
||||||
|
if (allowCrudType(tview,'tread')) {
|
||||||
|
ncrud.entity(buildView.createBaseApiUri(tview,'xml','tread') +'/:_id').Read()
|
||||||
|
.pipe(renderTemplateDataRead(tview,'xml','text/xml',model));
|
||||||
|
}
|
||||||
|
if (allowCrudType(tview,'tedit')) {
|
||||||
|
ncrud.entity(buildView.createBaseApiUri(tview,'xml','tedit')+'/:_id').Update()
|
||||||
|
.pipe(filterDataUpdate(model))
|
||||||
|
.pipe(mcrud.updateOne (model));
|
||||||
|
}
|
||||||
|
if (allowCrudType(tview,'tdelete')) {
|
||||||
|
ncrud.entity(buildView.createBaseApiUri(tview,'xml','tdelete')+'/:_id').Delete()
|
||||||
|
.pipe(mcrud.removeOne (model));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_.contains(tview.tmeta.tserver.texports,'csv')) {
|
||||||
|
if (allowCrudType(tview,'tlist')) {
|
||||||
|
ncrud.entity(buildView.createBaseApiUri(tview,'csv','tlist')).Read()
|
||||||
|
.pipe(filterQueryList(model))
|
||||||
|
.pipe(mcrud.findAll(model).stream().exports({ csv: renderTemplateDataList(tview,'csv','text/csv') }));
|
||||||
|
}
|
||||||
|
if (allowCrudType(tview,'tread')) {
|
||||||
|
ncrud.entity(buildView.createBaseApiUri(tview,'csv','tread') +'/:_id').Read()
|
||||||
|
.pipe(renderTemplateDataRead(tview,'csv','text/csv',model));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_.contains(tview.tmeta.tserver.texports,'rss')) {
|
||||||
|
if (allowCrudType(tview,'tlist')) {
|
||||||
|
ncrud.entity(buildView.createBaseApiUri(tview,'rss','tlist')).Read()
|
||||||
|
.pipe(mcrud.parseQuery()
|
||||||
|
.defaults({ limit: '10' })
|
||||||
|
.maxes({ limit: 50 })
|
||||||
|
)
|
||||||
|
.pipe(mcrud.findAll(model)
|
||||||
|
.stream()
|
||||||
|
.exports({ rss: renderTemplateDataList(tview,'rss','text/xml') })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
//.exports({ rss: exports.exportRss('todo',tview.xid,rssXNodeMap) })
|
||||||
|
}
|
||||||
|
if (_.contains(tview.tmeta.tserver.texports,'angular')) {
|
||||||
|
|
||||||
|
var uriPrefix = tcrud.tmeta.tserver.tslug + '/' + buildView.createBaseApiUri(tview,'angular');
|
||||||
|
var thtmlPrefix = uriPrefix + '/' + tview.tmeta.texport.angular.thtml;
|
||||||
|
var tapiPrefix = tcrud.tmeta.tserver.tslug + '/' +buildView.createBaseApiUri(tview,'json');
|
||||||
|
|
||||||
|
//server.get('/ui/include/crud/:name/:action', XViewInclude.renderTemplateCrud);
|
||||||
|
//server.get('/ui/include/js/controller/:name', XViewInclude.renderCrudController);
|
||||||
|
|
||||||
|
server.get(uriPrefix + '/thtml/crud/:action', renderCrudTemplate(tview,'thtml/crud/'));
|
||||||
|
server.get(uriPrefix + '/controller.js', renderCrudController(tview,thtmlPrefix,tapiPrefix));
|
||||||
|
//server.get(uriPrefix + '/service.js', renderCrudService(tview))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function walkViews(server,tcrud) {
|
||||||
|
//logger.debug('walk views: '+tcrud.tid);
|
||||||
|
if (tcrud.tparent) {
|
||||||
|
buildCrud(server,tcrud);
|
||||||
|
}
|
||||||
|
for (var i = 0; i < tcrud.tchilds.length; i++) {
|
||||||
|
walkViews(server,tcrud.tchilds[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildCrudApi(server) { // todo add return function
|
||||||
|
|
||||||
|
troot = server.get('ff_root_tcrud_view');
|
||||||
|
walkViews(server,troot);
|
||||||
|
|
||||||
|
server.use(exports.injectExportFormat(troot.tmeta.tserver.tslug));
|
||||||
|
server.use(exports.bodyParserXml());
|
||||||
|
ncrud.launch(server,{
|
||||||
|
base: troot.tmeta.tserver.tslug,
|
||||||
|
cors: false,
|
||||||
|
timeoute: 10e3
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = buildCrudApi;
|
138
lib-build/debug-server/node_lib/lib/factory-express.js
Normal file
138
lib-build/debug-server/node_lib/lib/factory-express.js
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
var logger = require('winston').loggers.get('main');
|
||||||
|
var clone = require('clone');
|
||||||
|
|
||||||
|
/*
|
||||||
|
var createRouter = function(server,path) {
|
||||||
|
var router = express.Router();
|
||||||
|
router.path = path;
|
||||||
|
server.use(router.path,router);
|
||||||
|
return router;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
var walkRouteTree = function(result,stack,parent_path) {
|
||||||
|
if (parent_path == null) {
|
||||||
|
parent_path = '';
|
||||||
|
}
|
||||||
|
stack.forEach(function(middleware) {
|
||||||
|
if (middleware.route){
|
||||||
|
var path = parent_path + middleware.route.path;
|
||||||
|
for (var httpMethod in middleware.route.methods) {
|
||||||
|
var data = {
|
||||||
|
"uriPath": path,
|
||||||
|
"httpMethod": httpMethod
|
||||||
|
};
|
||||||
|
result.push(data);
|
||||||
|
}
|
||||||
|
} else if (middleware.name === 'router') {
|
||||||
|
var pp = parent_path + middleware.handle.path;
|
||||||
|
walkRouteTree(result,middleware.handle.stack,pp);
|
||||||
|
} else {
|
||||||
|
//log.info('route err: '+JSON.stringify(middleware));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.renderServerUptime = function(options) {
|
||||||
|
if (!options) {
|
||||||
|
options: {};
|
||||||
|
}
|
||||||
|
var timeBoot = new Date().getTime();
|
||||||
|
return function (req, res, next) {
|
||||||
|
var timeNow = new Date().getTime();
|
||||||
|
var result = {
|
||||||
|
time_boot: timeBoot,
|
||||||
|
time_now: timeNow,
|
||||||
|
uptime: timeNow-timeBoot
|
||||||
|
}
|
||||||
|
res.json({
|
||||||
|
data: result
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.renderServerRoutes = function(server) {
|
||||||
|
if (!server) {
|
||||||
|
throw new Error('no server');
|
||||||
|
}
|
||||||
|
return function (req, res, next) {
|
||||||
|
var routeList = server.get('ff_tcrud_route_list');
|
||||||
|
if (!routeList) {
|
||||||
|
console.log('no routeList');
|
||||||
|
routeList = [];
|
||||||
|
}
|
||||||
|
var reqGroups = req.query.groups;
|
||||||
|
var groupList = [];
|
||||||
|
if (reqGroups) {
|
||||||
|
groupList = reqGroups.split(',');
|
||||||
|
}
|
||||||
|
//console.log('groups: '+reqGroups);
|
||||||
|
var result = {
|
||||||
|
all: [],
|
||||||
|
};
|
||||||
|
for (var i = 0; i < groupList.length; i++) {
|
||||||
|
var groupName = groupList[i].split('/').join('_');
|
||||||
|
result[groupName] = [];
|
||||||
|
}
|
||||||
|
groupList.sort(function(a, b) {
|
||||||
|
return a.length < b.length; // longest first as we break on first hit
|
||||||
|
});
|
||||||
|
|
||||||
|
for (i = 0; i < routeList.length; i++) {
|
||||||
|
var route = routeList[i];
|
||||||
|
var added = false;
|
||||||
|
for (var ii = 0; ii < groupList.length; ii++) {
|
||||||
|
if (route.uriPath.indexOf(groupList[ii]) > 0) {
|
||||||
|
var groupName = groupList[ii].split('/').join('_');
|
||||||
|
result[groupName].push(route);
|
||||||
|
added = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!added) {
|
||||||
|
result.all.push(route);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.json({
|
||||||
|
data: result
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.buildServerRoutes = function(server) { // todo add return function
|
||||||
|
if (!server) {
|
||||||
|
throw new Error('no server');
|
||||||
|
}
|
||||||
|
var result = walkRouteTree([],server._router.stack);
|
||||||
|
result.sort(function(a, b) {
|
||||||
|
return a.uriPath.localeCompare(b.uriPath);
|
||||||
|
});
|
||||||
|
server.set('ff_tcrud_route_list',result);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.sendRedirect = function (location) {
|
||||||
|
if (!location) {
|
||||||
|
throw new Error('no location');
|
||||||
|
}
|
||||||
|
return function(req, res) {
|
||||||
|
res.redirect(location);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.renderTemplatePath = function (viewPath) {
|
||||||
|
if (!viewPath) {
|
||||||
|
viewPath = '';
|
||||||
|
}
|
||||||
|
return function (req, res) {
|
||||||
|
res.locals.query = req.query;
|
||||||
|
//console.log('template query keys: '+Object.keys(req.query));
|
||||||
|
var qi = req.url.indexOf('?');
|
||||||
|
if (qi === -1) {
|
||||||
|
qi = req.url.length;
|
||||||
|
}
|
||||||
|
res.render(viewPath + req.url.substring(req.route.path.length-1, qi));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.buildCrudApi = require('./factory-express-api');
|
54
lib-build/debug-server/node_lib/lib/node-ff-tcrud.js
Normal file
54
lib-build/debug-server/node_lib/lib/node-ff-tcrud.js
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var tcrud = {
|
||||||
|
factory: {
|
||||||
|
express: require('./factory-express'),
|
||||||
|
},
|
||||||
|
build: {
|
||||||
|
config: require('./build-config'),
|
||||||
|
view: require('./build-view'),
|
||||||
|
backend: {
|
||||||
|
mongoose: require('./build-backend-mongoose'),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = tcrud;
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
//app.use(function (req, res, next) {res.locals.c_var='test';next();});
|
||||||
|
|
||||||
|
|
||||||
|
var http = require('http');
|
||||||
|
var ejs = require('ejs');
|
||||||
|
var fs = require('fs');
|
||||||
|
http.createServer(function (req, res) {
|
||||||
|
res.writeHead(200, {'Content-Type': 'text/xml'});
|
||||||
|
fs.readFile('placemark.ejs', 'utf8', function (err, template) {
|
||||||
|
|
||||||
|
var content = ejs.render(template,{
|
||||||
|
name:"test name",
|
||||||
|
description:"this is the description",
|
||||||
|
coordinates:"-122.0822035425683,37.42228990140251,0",
|
||||||
|
filename: __dirname + '/placemark.ejs'
|
||||||
|
});
|
||||||
|
|
||||||
|
res.write(content);
|
||||||
|
res.end()
|
||||||
|
});
|
||||||
|
}).listen(8000);
|
||||||
|
|
||||||
|
|
||||||
|
var scripts = document.getElementsByTagName("script");
|
||||||
|
var currentScriptPath = scripts[scripts.length-1].src;
|
||||||
|
console.log("currentScriptPath:"+currentScriptPath);
|
||||||
|
var baseUrl = currentScriptPath.substring(0, currentScriptPath.lastIndexOf('/') + 1);
|
||||||
|
console.log("baseUrl:"+baseUrl);
|
||||||
|
var bu2 = document.querySelector("script[src$='routes.js']");
|
||||||
|
currentScriptPath = bu2.src;
|
||||||
|
console.log("bu2:"+bu2);
|
||||||
|
console.log("src:"+bu2.src);
|
||||||
|
baseUrl = currentScriptPath.substring(0, currentScriptPath.lastIndexOf('/') + 1);
|
||||||
|
console.log("baseUrl:"+baseUrl);
|
||||||
|
*/
|
110
lib-build/debug-server/node_lib/lib/tcrud-field.js
Normal file
110
lib-build/debug-server/node_lib/lib/tcrud-field.js
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
var clone = require('clone');
|
||||||
|
|
||||||
|
var template = {
|
||||||
|
tid: null,
|
||||||
|
tname: null,
|
||||||
|
ttype: null,
|
||||||
|
tslug: null,
|
||||||
|
tvalidate: {
|
||||||
|
io: null,
|
||||||
|
},
|
||||||
|
tlist: {
|
||||||
|
tenable: true,
|
||||||
|
ttext: null,
|
||||||
|
troles: [],
|
||||||
|
},
|
||||||
|
tread: {
|
||||||
|
tenable: true,
|
||||||
|
ttext: null,
|
||||||
|
troles: [],
|
||||||
|
},
|
||||||
|
tedit: {
|
||||||
|
tenable: true,
|
||||||
|
ttext: null,
|
||||||
|
troles: [],
|
||||||
|
},
|
||||||
|
tcreate: {
|
||||||
|
tenable: true,
|
||||||
|
ttext: null,
|
||||||
|
troles: [],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.autoFieldName = function (fieldKey,fieldName) {
|
||||||
|
if (fieldKey === undefined) {
|
||||||
|
throw new Error('no fieldKey');
|
||||||
|
}
|
||||||
|
if (fieldName && fieldName.length !== 0) {
|
||||||
|
return fieldName;
|
||||||
|
}
|
||||||
|
var result = '';
|
||||||
|
var names = fieldKey.split('_');
|
||||||
|
for (var i in names) {
|
||||||
|
var name = names[i];
|
||||||
|
if (name.length > 1) {
|
||||||
|
name = name.substring(0,1).toUpperCase() + name.substring(1);
|
||||||
|
}
|
||||||
|
result = result + name + ' ';
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
var autoFieldEnable = function(tfield,type) {
|
||||||
|
if (type === undefined) {
|
||||||
|
throw new Error('no type');
|
||||||
|
}
|
||||||
|
if (tfield[type] === undefined) {
|
||||||
|
tfield[type] = {};
|
||||||
|
}
|
||||||
|
if (tfield[type].tenable !== undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var fieldKey = tfield.tid;
|
||||||
|
var result = true;
|
||||||
|
if ('tlist' === type) {
|
||||||
|
var name = fieldKey.toLowerCase();
|
||||||
|
if (fieldKey.indexOf('description') >= 0) {
|
||||||
|
result = false;
|
||||||
|
} else if (fieldKey.indexOf('comment') >= 0) {
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tfield[type].tenable = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
exports.newInstance = function (id) {
|
||||||
|
var tfield = clone(template);
|
||||||
|
tfield.tid = id;
|
||||||
|
return tfield;
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.fillDefaults = function (tfield) {
|
||||||
|
if (tfield === undefined) {
|
||||||
|
throw new Error('no tfield');
|
||||||
|
}
|
||||||
|
var tid = tfield.tid;
|
||||||
|
if (tid === undefined) {
|
||||||
|
throw new Error('no tfield.tid');
|
||||||
|
}
|
||||||
|
if (tfield.tname === undefined) {
|
||||||
|
tfield.tname = exports.autoFieldName(tid);
|
||||||
|
}
|
||||||
|
if (tfield.tname === undefined) {
|
||||||
|
tfield.tname = exports.autoFieldName(tid);
|
||||||
|
}
|
||||||
|
if (tfield.tslug === undefined) {
|
||||||
|
tfield.tslug = tid;
|
||||||
|
}
|
||||||
|
if (tfield.ttype === undefined) {
|
||||||
|
tfield.ttype = 'text';
|
||||||
|
}
|
||||||
|
if (tfield.tlist === undefined) {
|
||||||
|
tfield.tlist = {};
|
||||||
|
}
|
||||||
|
autoFieldEnable(tfield,'tlist');
|
||||||
|
autoFieldEnable(tfield,'tread');
|
||||||
|
autoFieldEnable(tfield,'tedit');
|
||||||
|
autoFieldEnable(tfield,'tcreate');
|
||||||
|
}
|
||||||
|
|
204
lib-build/debug-server/node_lib/lib/tcrud-view.js
Normal file
204
lib-build/debug-server/node_lib/lib/tcrud-view.js
Normal file
|
@ -0,0 +1,204 @@
|
||||||
|
var clone = require('clone');
|
||||||
|
var tsurgeon = require('tree-surgeon');
|
||||||
|
|
||||||
|
var template = {
|
||||||
|
tid: null,
|
||||||
|
tname: null,
|
||||||
|
tplural: null,
|
||||||
|
tslug: null,
|
||||||
|
tcode: null,
|
||||||
|
tmodel: null,
|
||||||
|
tcount: {
|
||||||
|
ttext: null,
|
||||||
|
tenable: null,
|
||||||
|
texport: null,
|
||||||
|
},
|
||||||
|
tlist: {
|
||||||
|
tfields: [],
|
||||||
|
ttext: null,
|
||||||
|
tlinks: null,
|
||||||
|
tenable: null,
|
||||||
|
texport: null,
|
||||||
|
},
|
||||||
|
tread: {
|
||||||
|
tfields: [],
|
||||||
|
ttext: null,
|
||||||
|
tenable: null,
|
||||||
|
texport: null,
|
||||||
|
},
|
||||||
|
tedit: {
|
||||||
|
tfields: [],
|
||||||
|
ttext: null,
|
||||||
|
tenable: null,
|
||||||
|
texport: null,
|
||||||
|
},
|
||||||
|
tcreate: {
|
||||||
|
tfields: [],
|
||||||
|
ttext: null,
|
||||||
|
tenable: null,
|
||||||
|
texport: null,
|
||||||
|
},
|
||||||
|
tdelete: {
|
||||||
|
ttext: null,
|
||||||
|
tenable: null,
|
||||||
|
texport: null,
|
||||||
|
},
|
||||||
|
tverify: {
|
||||||
|
ttext: null,
|
||||||
|
tenable: null,
|
||||||
|
texport: null,
|
||||||
|
},
|
||||||
|
tmeta: {
|
||||||
|
tfields: null,
|
||||||
|
tvalidate: null,
|
||||||
|
tserver: null,
|
||||||
|
texport: null,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
function copyByTemplate(prefix,objectDest,objectSrc,copyTemplate) {
|
||||||
|
var keys = Object.keys(copyTemplate);
|
||||||
|
var result = [];
|
||||||
|
for (var i = 0; i < keys.length; i++) {
|
||||||
|
var key = keys[i];
|
||||||
|
var value = objectSrc[key];
|
||||||
|
if (!value) {
|
||||||
|
//console.log(prefix+'.'+key+' src object has no value.');
|
||||||
|
continue; // no src value
|
||||||
|
}
|
||||||
|
var templateValue = copyTemplate[key];
|
||||||
|
if (templateValue === null) {
|
||||||
|
if (objectDest[key] !== null) {
|
||||||
|
//console.log(prefix+'.'+key+' has own value: '+objectDest[key]);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
//console.log(prefix+'.'+key+' copy value: '+value);
|
||||||
|
objectDest[key] = clone(value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//console.log(prefix+'.'+key+' going deeper');
|
||||||
|
copyByTemplate(prefix+'.'+key,objectDest[key],value,templateValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addFilteredFields(tview,type,tcrud) {
|
||||||
|
result = [];
|
||||||
|
var keys = Object.keys(tcrud.tmeta.tfields);
|
||||||
|
var result = [];
|
||||||
|
for (var i = 0; i < keys.length; i++) {
|
||||||
|
var key = keys[i];
|
||||||
|
var tfield = tcrud.tmeta.tfields[key];
|
||||||
|
if (tfield[type]) {
|
||||||
|
if (!tfield[type].tenable) {
|
||||||
|
//console.log('------------- type: ' + type + ' key: ' + key + ' res: ' + tfield[type].tenable)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.push(key); // default is true..
|
||||||
|
}
|
||||||
|
tview[type].tfields = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function forceLookupKeySimple() {
|
||||||
|
var low = 100000;
|
||||||
|
var high = 999999;
|
||||||
|
return Math.floor(Math.random() * (high - low + 1) + low).toString(16).toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
function forceLookupTFields(tview) {
|
||||||
|
var keys = Object.keys(tview.tmeta.tfields);
|
||||||
|
for (var i = 0; i < keys.length; i++) {
|
||||||
|
var key = keys[i];
|
||||||
|
var keyNew = 'FTL_' +forceLookupKeySimple() + '_' + key.substring(key.length/3,key.length/3*2); // no....its; Force template lookup
|
||||||
|
var tfield = tview.tmeta.tfields[key];
|
||||||
|
tview.tmeta.tfields[key] = undefined;
|
||||||
|
tview.tmeta.tfields[keyNew] = tfield;
|
||||||
|
|
||||||
|
var ckeys = Object.keys(tview);
|
||||||
|
for (var ii = 0; ii < ckeys.length; ii++) {
|
||||||
|
var ckey = ckeys[ii];
|
||||||
|
if (ckey === 'tmeta') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var obj = tview[ckey];
|
||||||
|
if (obj && obj.tfields) {
|
||||||
|
var tfieldsNew = [];
|
||||||
|
for (var iii = 0; iii < obj.tfields.length; iii++) {
|
||||||
|
var tkey = obj.tfields[iii];
|
||||||
|
if (tkey === key) {
|
||||||
|
tfieldsNew.push(keyNew);
|
||||||
|
} else {
|
||||||
|
tfieldsNew.push(tkey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
obj.tfields = tfieldsNew;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatValuePart(value,replaceChar,splitChar,partFn) {
|
||||||
|
var result = '';
|
||||||
|
var parts = value.split(splitChar);
|
||||||
|
for (var i = 0; i < parts.length; i++) {
|
||||||
|
var part = parts[i];
|
||||||
|
if (part.length > 1) {
|
||||||
|
result += partFn(part);
|
||||||
|
} else {
|
||||||
|
result += part;
|
||||||
|
}
|
||||||
|
if (i < parts.length - 1) {
|
||||||
|
result += replaceChar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatValue(value,removeChars,replaceChar,partFn) {
|
||||||
|
for (var i = 0; i < removeChars.length; i++) {
|
||||||
|
value = formatValuePart(value,replaceChar,removeChars[i],partFn);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.newInstance = function (tcrud) {
|
||||||
|
var tview = clone(template);
|
||||||
|
var tid = tcrud.tid;
|
||||||
|
tview.tid = tid;
|
||||||
|
|
||||||
|
copyByTemplate('tview',tview,tcrud,template);
|
||||||
|
|
||||||
|
//console.info('TCrudView.tslug: '+tview.tslug);
|
||||||
|
|
||||||
|
if (!tview.tslug) {
|
||||||
|
tview.tslug = formatValue(tid,['.',',','/','=','&','?',' '],'', function (part) {
|
||||||
|
return part; // todo use fully correct uri removeal and escaping.
|
||||||
|
})
|
||||||
|
//console.info('TCrudView.tslug auto: '+tview.tslug);
|
||||||
|
}
|
||||||
|
if (!tview.tname) {
|
||||||
|
tview.tname = formatValue(tid,['_','-','.',','],' ', function (part) {
|
||||||
|
return part.substring(0,1).toUpperCase()+part.substring(1).toLowerCase();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!tview.tcode) {
|
||||||
|
tview.tcode = formatValue(tid,[' ','_','-','.',','],'',function (part) {
|
||||||
|
return part.toLowerCase();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tview.tplural) {
|
||||||
|
tview.tplural = tview.tname + 's';
|
||||||
|
}
|
||||||
|
|
||||||
|
addFilteredFields(tview,'tlist',tcrud);
|
||||||
|
addFilteredFields(tview,'tread',tcrud);
|
||||||
|
addFilteredFields(tview,'tedit',tcrud);
|
||||||
|
addFilteredFields(tview,'tcreate',tcrud);
|
||||||
|
|
||||||
|
forceLookupTFields(tview);
|
||||||
|
|
||||||
|
return tview;
|
||||||
|
}
|
||||||
|
|
230
lib-build/debug-server/node_lib/lib/tcrud.js
Normal file
230
lib-build/debug-server/node_lib/lib/tcrud.js
Normal file
|
@ -0,0 +1,230 @@
|
||||||
|
var clone = require('clone');
|
||||||
|
|
||||||
|
var template = {
|
||||||
|
tid: null,
|
||||||
|
tname: null,
|
||||||
|
tplural: null,
|
||||||
|
tslug: null,
|
||||||
|
tmodel: null,
|
||||||
|
tenable: true,
|
||||||
|
tparam: null,
|
||||||
|
troles: [],
|
||||||
|
tparent: null,
|
||||||
|
tchilds: [],
|
||||||
|
tlist: {
|
||||||
|
tenable: true,
|
||||||
|
ttext: 'Listing of ..',
|
||||||
|
troles: [],
|
||||||
|
tserver: {
|
||||||
|
tpipe: {
|
||||||
|
query: {
|
||||||
|
defaults: { limit: '10' },
|
||||||
|
maxes: { limit: 50 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
texport: {
|
||||||
|
json: {
|
||||||
|
tslug: 'list',
|
||||||
|
},
|
||||||
|
xml: {
|
||||||
|
tslug: 'list',
|
||||||
|
},
|
||||||
|
rss: {
|
||||||
|
tslug: 'list',
|
||||||
|
},
|
||||||
|
csv: {
|
||||||
|
tslug: 'list',
|
||||||
|
},
|
||||||
|
angular: {
|
||||||
|
tslug: 'list',
|
||||||
|
thtml: 'crud/list',
|
||||||
|
tcontroller: {
|
||||||
|
prefix: 'tcrudAuto',
|
||||||
|
postfix: 'ListCntr',
|
||||||
|
argu: '$scope, $http, $location, $routeParams',
|
||||||
|
},
|
||||||
|
tlinks: {
|
||||||
|
'DataTODO':'/ui/XNodeData/list/XNode/{{row.net_id}}/{{row.net_id}}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tcreate: {
|
||||||
|
tenable: true,
|
||||||
|
ttext: null,
|
||||||
|
troles: [],
|
||||||
|
texport: {
|
||||||
|
json: {
|
||||||
|
tslug: 'create',
|
||||||
|
},
|
||||||
|
xml: {
|
||||||
|
tslug: 'create',
|
||||||
|
},
|
||||||
|
angular: {
|
||||||
|
tslug: 'create',
|
||||||
|
thtml: 'crud/create',
|
||||||
|
tcontroller: {
|
||||||
|
prefix: 'tcrudAuto',
|
||||||
|
postfix: 'CreateCntr',
|
||||||
|
argu: '$scope, $http, $location, $routeParams',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tedit: {
|
||||||
|
tenable: true,
|
||||||
|
ttext: null,
|
||||||
|
troles: [],
|
||||||
|
texport: {
|
||||||
|
json: {
|
||||||
|
tslug: 'edit',
|
||||||
|
},
|
||||||
|
xml: {
|
||||||
|
tslug: 'edit',
|
||||||
|
},
|
||||||
|
angular: {
|
||||||
|
tslug: 'edit',
|
||||||
|
thtml: 'crud/edit',
|
||||||
|
tcontroller: {
|
||||||
|
prefix: 'tcrudAuto',
|
||||||
|
postfix: 'EditCntr',
|
||||||
|
argu: '$scope, $http, $location, $routeParams',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tread: {
|
||||||
|
tenable: true,
|
||||||
|
ttext: null,
|
||||||
|
troles: [],
|
||||||
|
tslug: '',
|
||||||
|
texport: {
|
||||||
|
json: {
|
||||||
|
tslug: 'read',
|
||||||
|
},
|
||||||
|
xml: {
|
||||||
|
tslug: 'read',
|
||||||
|
},
|
||||||
|
csv: {
|
||||||
|
tslug: 'read',
|
||||||
|
},
|
||||||
|
angular: {
|
||||||
|
tslug: 'read',
|
||||||
|
thtml: 'crud/read',
|
||||||
|
troute: {
|
||||||
|
|
||||||
|
},
|
||||||
|
tcontroller: {
|
||||||
|
prefix: 'tcrudAuto',
|
||||||
|
postfix: 'ReadCntr',
|
||||||
|
argu: '$scope, $http, $location, $routeParams',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tdelete: {
|
||||||
|
tenable: true,
|
||||||
|
ttext: null,
|
||||||
|
troles: [],
|
||||||
|
texport: {
|
||||||
|
json: {
|
||||||
|
tslug: 'delete',
|
||||||
|
},
|
||||||
|
xml: {
|
||||||
|
tslug: 'delete',
|
||||||
|
},
|
||||||
|
angular: {
|
||||||
|
tslug: 'delete',
|
||||||
|
thtml: 'crud/delete',
|
||||||
|
tcontroller: {
|
||||||
|
prefix: 'tcrudAuto',
|
||||||
|
postfix: 'DeleteCntr',
|
||||||
|
argu: '$scope, $http, $location, $routeParams',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tcount: {
|
||||||
|
tenable: true,
|
||||||
|
ttext: 'Count records',
|
||||||
|
troles: [],
|
||||||
|
texport: {
|
||||||
|
json: {
|
||||||
|
tslug: 'list-count',
|
||||||
|
},
|
||||||
|
xml: {
|
||||||
|
tslug: 'list-count',
|
||||||
|
},
|
||||||
|
csv: {
|
||||||
|
tslug: 'list-count',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tverify: {
|
||||||
|
tenable: true,
|
||||||
|
ttext: 'Verify data',
|
||||||
|
troles: [],
|
||||||
|
texport: {
|
||||||
|
json: {
|
||||||
|
tslug: 'verify',
|
||||||
|
},
|
||||||
|
xml: {
|
||||||
|
tslug: 'verify',
|
||||||
|
},
|
||||||
|
csv: {
|
||||||
|
tslug: 'verify',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ttemplate: {
|
||||||
|
tid: '_id',
|
||||||
|
tname: '_id',
|
||||||
|
tdescription: '_id',
|
||||||
|
},
|
||||||
|
tmeta: {
|
||||||
|
troles: [],
|
||||||
|
tfields: {},
|
||||||
|
tvalidate: {
|
||||||
|
io: { 'admin_role': 'object|properties[test]' },
|
||||||
|
},
|
||||||
|
tserver: {
|
||||||
|
thost: 'http://localhost:8080/',
|
||||||
|
tslug: '/api',
|
||||||
|
tpopfix: true,
|
||||||
|
texports: ['json','xml','csv','rss','angular'],
|
||||||
|
},
|
||||||
|
texport: {
|
||||||
|
json: {
|
||||||
|
tslug: 'json',
|
||||||
|
},
|
||||||
|
xml: {
|
||||||
|
tslug: 'xml',
|
||||||
|
},
|
||||||
|
csv: {
|
||||||
|
tslug: 'csv',
|
||||||
|
},
|
||||||
|
rss: {
|
||||||
|
tslug: 'rss',
|
||||||
|
itemTitle: '$data._id',
|
||||||
|
itemLink: '$siteLink/ui/$modelUri/read/$[\'data._id\']',
|
||||||
|
itemDate: '',
|
||||||
|
itemDescription: '',
|
||||||
|
//itemFields: '',
|
||||||
|
},
|
||||||
|
angular: {
|
||||||
|
tslug: 'angular',
|
||||||
|
tbase: '/ui',
|
||||||
|
thtml: 'thtml',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.newInstance = function (tid) {
|
||||||
|
var tcrud = clone(template);
|
||||||
|
tcrud.tid = tid;
|
||||||
|
tcrud.tslug = tid; // view fills more defaults.
|
||||||
|
return tcrud;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
$scope.<%= taction %>None = function () {
|
||||||
|
<% if (tview.tlist) { %>
|
||||||
|
$location.url('<%= tview.tmeta.texport.angular.tbase %>/<%= tview.tslug %>/<%= tview.tlist.texport.angular.tslug %>');
|
||||||
|
<% } else { %>
|
||||||
|
$location.url('<%= tview.tmeta.texport.angular.tbase %>/');
|
||||||
|
<% } %>
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
|
||||||
|
$routeProvider.when('<%= tview.tmeta.texport.angular.tbase %>/<%= tview.tslug %>/<%= tview[taction].texport.angular.tslug %><%= routeEnd %>', {
|
||||||
|
templateUrl: '<%= thtmlPrefix %>/<%= tview[taction].texport.angular.thtml %>',
|
||||||
|
controller: <%= tview[taction].texport.angular.tcontroller.prefix %><%= tview.tcode %><%= tview[taction].texport.angular.tcontroller.postfix %>
|
||||||
|
});
|
|
@ -0,0 +1,99 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// Auto generated controller mapping for: <%= tview.tid %>
|
||||||
|
|
||||||
|
|
||||||
|
crudRouteInit.push(<%= tview.tcode %>Init);
|
||||||
|
|
||||||
|
function <%= tview.tcode %>Init($routeProvider, $locationProvider) {
|
||||||
|
<% if (tview.tlist) { %>
|
||||||
|
$routeProvider.when('<%= tview.tmeta.texport.angular.tbase %>/<%= tview.tslug %>/', {
|
||||||
|
redirectTo: '<%= tview.tmeta.texport.angular.tbase %>/<%= tview.tslug %>/<%= tview.tlist.texport.angular.tslug %>'
|
||||||
|
});
|
||||||
|
<%- include('controller-route', {tview: tview,thtmlPrefix:thtmlPrefix,taction: 'tlist', routeEnd: ''}); %>
|
||||||
|
<% } %>
|
||||||
|
<% if (tview.tcreate) { %>
|
||||||
|
<%- include('controller-route', {tview: tview,thtmlPrefix:thtmlPrefix,taction: 'tcreate', routeEnd: ''}); %>
|
||||||
|
<% } %>
|
||||||
|
<% if (tview.tedit) { %>
|
||||||
|
<%- include('controller-route', {tview: tview,thtmlPrefix:thtmlPrefix,taction: 'tedit', routeEnd: '/:id'}); %>
|
||||||
|
<% } %>
|
||||||
|
<% if (tview.tread) { %>
|
||||||
|
<%- include('controller-route', {tview: tview,thtmlPrefix:thtmlPrefix,taction: 'tread', routeEnd: '/:id'}); %>
|
||||||
|
<% } %>
|
||||||
|
<% if (tview.tdelete) { %>
|
||||||
|
<%- include('controller-route', {tview: tview,thtmlPrefix:thtmlPrefix,taction: 'tdelete', routeEnd: '/:id'}); %>
|
||||||
|
<% } %>
|
||||||
|
}
|
||||||
|
|
||||||
|
<% if (tview.tlist) { %>
|
||||||
|
function <%= tview.tlist.texport.angular.tcontroller.prefix %><%= tview.tcode %><%= tview.tlist.texport.angular.tcontroller.postfix %>(<%= tview.tlist.texport.angular.tcontroller.argu %>) {
|
||||||
|
$http.get('<%= tapiPrefix %>/<%= tview.tlist.texport.json.tslug %>').success(function(data, status, headers, config) {
|
||||||
|
$scope.data = data.data;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
<% } %>
|
||||||
|
|
||||||
|
<% if (tview.tcreate) { %>
|
||||||
|
function <%= tview.tcreate.texport.angular.tcontroller.prefix %><%= tview.tcode %><%= tview.tcreate.texport.angular.tcontroller.postfix %>(<%= tview.tcreate.texport.angular.tcontroller.argu %>) {
|
||||||
|
$scope.data = {};
|
||||||
|
$scope.tcreateData = function () {
|
||||||
|
$http.post('<%= tapiPrefix %>/<%= tview.tcreate.texport.json.tslug %>', $scope.data).success(function(data) {
|
||||||
|
<% if (tview.tlist) { %>
|
||||||
|
$location.url('<%= tview.tmeta.texport.angular.tbase %>/<%= tview.tslug %>/<%= tview.tlist.texport.angular.tslug %>');
|
||||||
|
<% } else { %>
|
||||||
|
$location.url('<%= tview.tmeta.texport.angular.tbase %>/');
|
||||||
|
<% } %>
|
||||||
|
});
|
||||||
|
}
|
||||||
|
<%- include('controller-action-none', {tview: tview,taction: 'tcreate'}); %>
|
||||||
|
}
|
||||||
|
<% } %>
|
||||||
|
|
||||||
|
<% if (tview.tread) { %>
|
||||||
|
function <%= tview.tread.texport.angular.tcontroller.prefix %><%= tview.tcode %><%= tview.tread.texport.angular.tcontroller.postfix %>(<%= tview.tread.texport.angular.tcontroller.argu %>) {
|
||||||
|
$scope.data = {};
|
||||||
|
$http.get('<%= tapiPrefix %>/<%= tview.tread.texport.json.tslug %>/' + $routeParams.id).success(function(data) {
|
||||||
|
$scope.data = data.data;
|
||||||
|
});
|
||||||
|
<%- include('controller-action-none', {tview: tview,taction: 'tread'}); %>
|
||||||
|
}
|
||||||
|
<% } %>
|
||||||
|
|
||||||
|
<% if (tview.tedit) { %>
|
||||||
|
function <%= tview.tedit.texport.angular.tcontroller.prefix %><%= tview.tcode %><%= tview.tedit.texport.angular.tcontroller.postfix %>(<%= tview.tedit.texport.angular.tcontroller.argu %>) {
|
||||||
|
$scope.data = {};
|
||||||
|
$http.get('<%= tapiPrefix %>/<%= tview.tread.texport.json.tslug %>/' + $routeParams.id).success(function(data) {
|
||||||
|
$scope.data = data.data;
|
||||||
|
});
|
||||||
|
$scope.teditData = function () {
|
||||||
|
$http.put('<%= tapiPrefix %>/<%= tview.tedit.texport.json.tslug %>/' + $routeParams.id, $scope.data ).success(function(data) {
|
||||||
|
<% if (tview.tread) { %>
|
||||||
|
$location.url('<%= tview.tmeta.texport.angular.tbase %>/<%= tview.tslug %>/<%= tview.tread.texport.angular.tslug %>/' + $routeParams.id);
|
||||||
|
<% } else { %>
|
||||||
|
$location.url('<%= tview.tmeta.texport.angular.tbase %>/');
|
||||||
|
<% } %>
|
||||||
|
});
|
||||||
|
}
|
||||||
|
<%- include('controller-action-none', {tview: tview,taction: 'tedit'}); %>
|
||||||
|
}
|
||||||
|
<% } %>
|
||||||
|
|
||||||
|
<% if (tview.tdelete) { %>
|
||||||
|
function <%= tview.tdelete.texport.angular.tcontroller.prefix %><%= tview.tcode %><%= tview.tdelete.texport.angular.tcontroller.postfix %>(<%= tview.tdelete.texport.angular.tcontroller.argu %>) {
|
||||||
|
$scope.data = {};
|
||||||
|
$http.get('<%= tapiPrefix %>/<%= tview.tread.texport.json.tslug %>/' + $routeParams.id).success(function(data) {
|
||||||
|
$scope.data = data.data;
|
||||||
|
});
|
||||||
|
$scope.tdeleteData = function () {
|
||||||
|
$http.delete('<%= tapiPrefix %>/<%= tview.tdelete.texport.json.tslug %>/'+ $routeParams.id, $scope.data).success(function(data) {
|
||||||
|
<% if (tview.tlist) { %>
|
||||||
|
$location.url('<%= tview.tmeta.texport.angular.tbase %>/<%= tview.tslug %>/<%= tview.tlist.texport.angular.tslug %>');
|
||||||
|
<% } else { %>
|
||||||
|
$location.url('<%= tview.tmeta.texport.angular.tbase %>/');
|
||||||
|
<% } %>
|
||||||
|
});
|
||||||
|
}
|
||||||
|
<%- include('controller-action-none', {tview: tview,taction: 'tdelete'}); %>
|
||||||
|
}
|
||||||
|
<% } %>
|
|
@ -0,0 +1,20 @@
|
||||||
|
<h2>Create <%= tview.tname %></h2>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<form role="form">
|
||||||
|
<% tview.tedit.tfields.forEach(function (fieldKey) { %>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="<%= tview.tmeta.tfields[fieldKey].tid %>"><%= tview.tmeta.tfields[fieldKey].tname %></label>
|
||||||
|
<input ng-model="data.<%= tview.tmeta.tfields[fieldKey].tid %>" name="<%= tview.tmeta.tfields[fieldKey].tid %>" class="form-control"></input>
|
||||||
|
</div>
|
||||||
|
<% }) %>
|
||||||
|
<button type="submit" class="btn btn-default" ng-click="tcreateData()">Submit</button>
|
||||||
|
<button type="submit" class="btn btn-default" ng-click="tcreateNone()">Cancel</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-4"></div>
|
||||||
|
</div>
|
||||||
|
<!--
|
||||||
|
06 308 500 37
|
||||||
|
-->
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
<h2>Delete <%= tview.tname %></h2>
|
||||||
|
<div>
|
||||||
|
<p>Are you sure you want to delete this <%= tview.tname %> {{data._id}} ?</p>
|
||||||
|
<button ng-click="tdeleteData()">Yes</button> | -
|
||||||
|
<button ng-click="tdeleteNone()">No thanks</button>
|
||||||
|
<div>
|
|
@ -0,0 +1,16 @@
|
||||||
|
|
||||||
|
<h2> Edit <%= tview.tname %></h2>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<form role="form">
|
||||||
|
<% tview.tedit.tfields.forEach(function (fieldKey) { %>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="<%= tview.tmeta.tfields[fieldKey].tid %>"><%= tview.tmeta.tfields[fieldKey].tname %></label>
|
||||||
|
<input ng-model="data.<%= tview.tmeta.tfields[fieldKey].tid %>" name="<%= tview.tmeta.tfields[fieldKey].tid %>" class="form-control"></input>
|
||||||
|
</div>
|
||||||
|
<% }) %>
|
||||||
|
<button type="submit" class="btn btn-default" ng-click="teditData()">Submit</button>
|
||||||
|
<button type="submit" class="btn btn-default" ng-click="teditNone()">Cancel</button>
|
||||||
|
</form>
|
||||||
|
<div class="col-lg-4"></div>
|
||||||
|
</div>
|
|
@ -0,0 +1,50 @@
|
||||||
|
|
||||||
|
<p>There are {{data.length}} <%= tview.tplural %></p>
|
||||||
|
|
||||||
|
<% if (tview.tcreate) { %>
|
||||||
|
<p>
|
||||||
|
<a href="<%= tview.tmeta.texport.angular.tbase %>/<%= tview.tslug %>/<%= tview.tcreate.texport.angular.tslug %>">Create New</a>
|
||||||
|
</p>
|
||||||
|
<% } %>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-bordered table-hover table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<% if (tview.tread) { %><th>Open</th><% } %>
|
||||||
|
<% if (tview.tedit) { %><th>Edit</th><% } %>
|
||||||
|
<% if (tview.tdelete) { %><th>Delete</th><% } %>
|
||||||
|
<% tview.tlist.tfields.forEach(function (fieldKey) { %>
|
||||||
|
<th><%= tview.tmeta.tfields[fieldKey].tname %></th>
|
||||||
|
<% }) %>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr ng-repeat="row in data">
|
||||||
|
<% if (tview.tread) { %>
|
||||||
|
<td>
|
||||||
|
<a href="<%= tview.tmeta.texport.angular.tbase %>/<%= tview.tslug %>/<%= tview.tread.texport.angular.tslug %>/{{row._id}}">Read</a>
|
||||||
|
</td>
|
||||||
|
<% } %>
|
||||||
|
<% if (tview.tedit) { %>
|
||||||
|
<td>
|
||||||
|
<a href="<%= tview.tmeta.texport.angular.tbase %>/<%= tview.tslug %>/<%= tview.tedit.texport.angular.tslug %>/{{row._id}}">Edit</a>
|
||||||
|
</td>
|
||||||
|
<% } %>
|
||||||
|
<% if (tview.tdelete) { %>
|
||||||
|
<td>
|
||||||
|
<a href="<%= tview.tmeta.texport.angular.tbase %>/<%= tview.tslug %>/<%= tview.tdelete.texport.angular.tslug %>/{{row._id}}">Delete</a>
|
||||||
|
</td>
|
||||||
|
<% } %>
|
||||||
|
<% tview.tlist.tfields.forEach(function (fieldKey) { %>
|
||||||
|
<td>{{row.<%= tview.tmeta.tfields[fieldKey].tid %>}}</td>
|
||||||
|
<% }) %>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<% if (tview.tcreate) { %>
|
||||||
|
<p>
|
||||||
|
<a href="<%= tview.tmeta.texport.angular.tbase %>/<%= tview.tslug %>/<%= tview.tcreate.texport.angular.tslug %>">Create New</a>
|
||||||
|
</p>
|
||||||
|
<% } %>
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
<section>
|
||||||
|
<h2> {{data._id}} </h2>
|
||||||
|
<% if (tview.tedit) { %>
|
||||||
|
<p>
|
||||||
|
<a href="<%= tview.tmeta.texport.angular.tbase %>/<%= tview.tslug %>/<%= tview.tedit.texport.angular.tslug %>/{{data._id}}">Edit</a>
|
||||||
|
</p>
|
||||||
|
<% } %>
|
||||||
|
<% if (tview.tdelete) { %>
|
||||||
|
<p>
|
||||||
|
<a href="<%= tview.tmeta.texport.angular.tbase %>/<%= tview.tslug %>/<%= tview.tdelete.texport.angular.tslug %>/{{data._id}}">Delete</a>
|
||||||
|
</p>
|
||||||
|
<% } %>
|
||||||
|
<% tview.tread.tfields.forEach(function (fieldKey) { %>
|
||||||
|
<p><%= tview.tmeta.tfields[fieldKey].tname %>: {{data.<%= tview.tmeta.tfields[fieldKey].tid %>}}</p>
|
||||||
|
<% }) %>
|
||||||
|
<p>
|
||||||
|
<button ng-click="treadNone()">Back</button>
|
||||||
|
</p>
|
||||||
|
<sector>
|
|
@ -0,0 +1 @@
|
||||||
|
# END
|
|
@ -0,0 +1 @@
|
||||||
|
# CSV: <%= tview.tid %>
|
|
@ -0,0 +1 @@
|
||||||
|
<% Object.keys(tview.tlist.tfields).forEach(function (tfieldKey) {var tfield = tview.tlist.tfields[tfieldKey]; %><%= record[tfield.tid] %>,<% }) %>
|
|
@ -0,0 +1 @@
|
||||||
|
<% Object.keys(tview.tlist.tfields).forEach(function (tfieldKey) {var tfield = tview.tlist.tfields[tfieldKey]; %><%= record[tfield.tid] %>,<% }) %>
|
|
@ -0,0 +1 @@
|
||||||
|
</<%= tview.tid %>List>
|
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<<%= tview.tid %>List>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<<%= tview.tid %>>
|
||||||
|
<% Object.keys(tview.tlist.tfields).forEach(function (tfieldKey) {var tfield = tview.tlist.tfields[tfieldKey]; %>
|
||||||
|
<<%= tfieldKey %> type="<%= tfield.type %>"><%= record[tfield.tid] %></<%= tfieldKey %>>
|
||||||
|
<% }) %>
|
||||||
|
</<%= tview.tid %>>
|
|
@ -0,0 +1,2 @@
|
||||||
|
</<%= tview.tid %>List>
|
||||||
|
</data>
|
|
@ -0,0 +1,3 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<data>
|
||||||
|
<<%= tview.tid %>List>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<<%= tview.tid %>>
|
||||||
|
<% Object.keys(tview.tlist.tfields).forEach(function (tfieldKey) {var tfield = tview.tlist.tfields[tfieldKey]; %>
|
||||||
|
<<%= tfieldKey %> type="<%= tfield.type %>"><%= record[tfield.tid] %></<%= tfieldKey %>>
|
||||||
|
<% }) %>
|
||||||
|
</<%= tview.tid %>>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<data>
|
||||||
|
<<%= tview.tid %>>
|
||||||
|
<% Object.keys(tview.tlist.tfields).forEach(function (tfieldKey) {var tfield = tview.tlist.tfields[tfieldKey]; %>
|
||||||
|
<<%= tfieldKey %> type="<%= tfield.type %>"><%= record[tfield.tid] %></<%= tfieldKey %>>
|
||||||
|
<% }) %>
|
||||||
|
</<%= tview.tid %>>
|
||||||
|
</data>
|
75
lib-build/debug-server/node_lib/model/xnode-base-command.js
Normal file
75
lib-build/debug-server/node_lib/model/xnode-base-command.js
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
var logger = require('winston').loggers.get('main');
|
||||||
|
var mongoose = require('mongoose');
|
||||||
|
var tmongoose = require('../lib/node-ff-tcrud').build.backend.mongoose;
|
||||||
|
var modelName = __filename.split('/').pop().split('.')[0];
|
||||||
|
var modelBackend = modelName.split('-').join('_');
|
||||||
|
|
||||||
|
var modelMeta = {
|
||||||
|
net_id: {
|
||||||
|
type: String,
|
||||||
|
index: { unique: false },
|
||||||
|
tfield: {
|
||||||
|
tvalidate: { io: 'string' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
command: {
|
||||||
|
type: String,
|
||||||
|
tfield: {
|
||||||
|
tvalidate: { io: 'string' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
insert_ip: {
|
||||||
|
type: String,
|
||||||
|
tfield: {
|
||||||
|
tvalidate: { io: 'string' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
insert_date: {
|
||||||
|
type: Date,
|
||||||
|
default: Date.now,
|
||||||
|
tfield: {
|
||||||
|
tlist: { tenable: false },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
send_date: {
|
||||||
|
type: Date
|
||||||
|
},
|
||||||
|
done_date: {
|
||||||
|
type: Date
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var modelSchema = new mongoose.Schema(modelMeta);
|
||||||
|
|
||||||
|
modelSchema.statics = tmongoose.buildStaticsModelValidated(modelMeta,modelSchema, {
|
||||||
|
findByNetIdLimit10: function (net_id, callback) {
|
||||||
|
logger.debug(modelBackend+'.findByNetId net_id='+net_id);
|
||||||
|
this.find({net_id:net_id}).sort('-insert_date').limit(10).exec(callback);
|
||||||
|
},
|
||||||
|
findOpenByNetId: function (net_id, callback) {
|
||||||
|
logger.debug(modelBackend+'.findOpenByNetId net_id='+net_id);
|
||||||
|
this.find({net_id:net_id}).where('send_date',null).sort('insert_date').limit(1).exec(callback);
|
||||||
|
},
|
||||||
|
findOpenCommandLimit5: function (callback) {
|
||||||
|
logger.debug(modelBackend+'.findOpenCommands');
|
||||||
|
var dateLastHour = new Date(new Date().getTime() - 30*60*1000); // soft limit on long open errors.
|
||||||
|
this.find({insert_date: { $gt: dateLastHour}}).where('send_date',null).sort('insert_date').limit(5).exec(callback);
|
||||||
|
},
|
||||||
|
findSendCommandLimit5: function (callback) {
|
||||||
|
logger.debug(modelBackend+'.findSendCommands');
|
||||||
|
var dateLastHour = new Date(new Date().getTime() - 60*60*1000);
|
||||||
|
this.find({send_date: { $gt: dateLastHour}}).sort('-insert_date').limit(5).exec(callback);
|
||||||
|
},
|
||||||
|
insert: function (net_id,command,insert_ip, next) {
|
||||||
|
var xcmd = new this();
|
||||||
|
xcmd.net_id = net_id;
|
||||||
|
xcmd.command = command;
|
||||||
|
xcmd.insert_ip = insert_ip;
|
||||||
|
xcmd.save(function(err,xcmd) {
|
||||||
|
if (err) { return next(err); }
|
||||||
|
logger.debug(modelBackend+'.insert _id='+xcmd._id+' net_id='+xcmd.net_id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = mongoose.model(modelName, modelSchema, modelBackend);
|
98
lib-build/debug-server/node_lib/model/xnode-base.js
Normal file
98
lib-build/debug-server/node_lib/model/xnode-base.js
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
var logger = require('winston').loggers.get('main');
|
||||||
|
var mongoose = require('mongoose');
|
||||||
|
var tmongoose = require('../lib/node-ff-tcrud').build.backend.mongoose;
|
||||||
|
var modelName = __filename.split('/').pop().split('.')[0];
|
||||||
|
var modelBackend = modelName.split('-').join('_');
|
||||||
|
|
||||||
|
var modelMeta = {
|
||||||
|
net_id: {
|
||||||
|
type: String,
|
||||||
|
index: { unique: true },
|
||||||
|
tfield: {
|
||||||
|
tvalidate: { io: 'string' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
net_key: {
|
||||||
|
type: String,
|
||||||
|
tfield: {
|
||||||
|
tvalidate: { io: 'string' },
|
||||||
|
tlist: { tenable: false },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
net_mac: {
|
||||||
|
type: String,
|
||||||
|
tcrud: {
|
||||||
|
tname: 'Net MAC',
|
||||||
|
tlist: { tenable: false },
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rf_key: {
|
||||||
|
type: String,
|
||||||
|
tfield: {
|
||||||
|
tname: 'RF Key',
|
||||||
|
tlist: { tenable: false },
|
||||||
|
}
|
||||||
|
},
|
||||||
|
init_index: {
|
||||||
|
type: Number,
|
||||||
|
tfield: {
|
||||||
|
tlist: { tenable: false },
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
ping_counter: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
tfield: {
|
||||||
|
tname: 'Ping #'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ping_last_date: {
|
||||||
|
type: Date,
|
||||||
|
index: { unique: true, sparse: true }
|
||||||
|
},
|
||||||
|
ping_rtt: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
tfield: {
|
||||||
|
tname: 'Ping RTT'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
changed_date: {
|
||||||
|
type: Date,
|
||||||
|
default: Date.now,
|
||||||
|
tfield: {
|
||||||
|
tlist: { tenable: false },
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created_date: {
|
||||||
|
type: Date,
|
||||||
|
default: Date.now,
|
||||||
|
tfield: {
|
||||||
|
tlist: { tenable: false },
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created_ip: {
|
||||||
|
type: String,
|
||||||
|
tfield: {
|
||||||
|
tvalidate: { io: 'string' },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var modelSchema = new mongoose.Schema(modelMeta);
|
||||||
|
|
||||||
|
modelSchema.statics = tmongoose.buildStaticsModelValidated(modelMeta,modelSchema, {
|
||||||
|
findOneByNetId: function (net_id, callback) {
|
||||||
|
logger.debug(modelBackend+'.findByNetId net_id='+net_id);
|
||||||
|
this.findOne({net_id:net_id}).exec(callback);
|
||||||
|
},
|
||||||
|
findLastPingLimit5: function (callback) {
|
||||||
|
var dateLastHour = new Date(new Date().getTime() - 60*60*1000);
|
||||||
|
logger.debug(modelBackend+'.findLastPinged lastDate: '+dateLastHour);
|
||||||
|
this.find({}).where('ping_last_date').gt(dateLastHour).sort('-ping_last_date').limit(5).exec(callback);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = mongoose.model(modelName, modelSchema, modelBackend);
|
59
lib-build/debug-server/node_lib/model/xnode-data-value.js
Normal file
59
lib-build/debug-server/node_lib/model/xnode-data-value.js
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
var logger = require('winston').loggers.get('main');
|
||||||
|
var mongoose = require('mongoose');
|
||||||
|
var tmongoose = require('../lib/node-ff-tcrud').build.backend.mongoose;
|
||||||
|
var modelName = __filename.split('/').pop().split('.')[0];
|
||||||
|
var modelBackend = modelName.split('-').join('_');
|
||||||
|
|
||||||
|
var modelMeta = {
|
||||||
|
/*
|
||||||
|
uuid: {
|
||||||
|
type: String,
|
||||||
|
index: { unique: true },
|
||||||
|
tfield: {
|
||||||
|
tvalidate: { io: 'string' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
node_id: {
|
||||||
|
type: Number,
|
||||||
|
index: { unique: false },
|
||||||
|
tfield: {
|
||||||
|
tvalidate: { io: 'number' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
insert_date: {
|
||||||
|
type: Date,
|
||||||
|
index: { unique: false },
|
||||||
|
default: Date.now,
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
index: { unique: false },
|
||||||
|
tfield: {
|
||||||
|
tvalidate: { io: 'string' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var modelSchema = new mongoose.Schema(modelMeta);
|
||||||
|
|
||||||
|
modelSchema.statics = tmongoose.buildStaticsModelValidated(modelMeta,modelSchema, {
|
||||||
|
findLastAddedLimit5: function (callback) {
|
||||||
|
logger.debug(modelBackend+'.findLastAddedLimit5');
|
||||||
|
this.find({}).sort('-insert_date').limit(5).exec(callback);
|
||||||
|
},
|
||||||
|
findByNetIdAndNodeId: function (net_id,node_id, callback) {
|
||||||
|
logger.debug(modelBackend+'.findByNetIdAndNodeId net_id='+net_id+' node_id='+node_id);
|
||||||
|
this
|
||||||
|
.aggregate({ $match: { net_id:net_id ,node_id:node_id }})
|
||||||
|
.group({ _id: "$name", value: { $min : "$value" } })
|
||||||
|
.sort("_id")
|
||||||
|
.exec(callback);
|
||||||
|
//this.find({net_id:net_id,node_id:node_id}).sort('insert_date').exec(callback);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = mongoose.model(modelName, modelSchema, modelBackend);
|
53
lib-build/debug-server/node_lib/model/xnode-data.js
Normal file
53
lib-build/debug-server/node_lib/model/xnode-data.js
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
var logger = require('winston').loggers.get('main');
|
||||||
|
var mongoose = require('mongoose');
|
||||||
|
var tmongoose = require('../lib/node-ff-tcrud').build.backend.mongoose;
|
||||||
|
var modelName = __filename.split('/').pop().split('.')[0];
|
||||||
|
var modelBackend = modelName.split('-').join('_');
|
||||||
|
|
||||||
|
var modelMeta = {
|
||||||
|
//node : {type : Schema.ObjectId, ref : 'XNode'}
|
||||||
|
node_id: {
|
||||||
|
type: Number,
|
||||||
|
index: { unique: false },
|
||||||
|
tfield: {
|
||||||
|
tvalidate: { io: 'number' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data_raw: {
|
||||||
|
type: String,
|
||||||
|
tfield: {
|
||||||
|
ttype: 'textarea',
|
||||||
|
tvalidate: { io: 'string' },
|
||||||
|
tlist: { tenable: false },
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data_text: {
|
||||||
|
type: String,
|
||||||
|
tfield: {
|
||||||
|
tvalidate: { io: 'number' },
|
||||||
|
ttype: 'textarea',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
remote_ip: {
|
||||||
|
type: String,
|
||||||
|
tfield: {
|
||||||
|
tname: 'Remote IP',
|
||||||
|
tvalidate: { io: 'ip_address' },
|
||||||
|
tlist: { tenable: false },
|
||||||
|
}
|
||||||
|
},
|
||||||
|
insert_date: {
|
||||||
|
type: Date, default: Date.now,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var modelSchema = new mongoose.Schema(modelMeta);
|
||||||
|
|
||||||
|
modelSchema.statics = tmongoose.buildStaticsModelValidated(modelMeta,modelSchema, {
|
||||||
|
findLastLimit5: function (callback) {
|
||||||
|
logger.debug(modelBackend+'.findLastLimit5');
|
||||||
|
this.find({}).sort('-insert_date').limit(5).exec(callback);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = mongoose.model(modelName, modelSchema, modelBackend);
|
98
lib-build/debug-server/node_lib/model/xnode.js
Normal file
98
lib-build/debug-server/node_lib/model/xnode.js
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
var logger = require('winston').loggers.get('main');
|
||||||
|
var mongoose = require('mongoose');
|
||||||
|
var tmongoose = require('../lib/node-ff-tcrud').build.backend.mongoose;
|
||||||
|
var modelName = __filename.split('/').pop().split('.')[0];
|
||||||
|
var modelBackend = modelName.split('-').join('_');
|
||||||
|
|
||||||
|
var modelMeta = {
|
||||||
|
net_id: {
|
||||||
|
type: String,
|
||||||
|
index: { unique: false },
|
||||||
|
tfield: {
|
||||||
|
tvalidate: { io: 'string' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
node_id: {
|
||||||
|
type: Number,
|
||||||
|
index: { unique: false },
|
||||||
|
tfield: {
|
||||||
|
tvalidate: { io: 'number' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
insert_date: {
|
||||||
|
type: Date,
|
||||||
|
index: { unique: false },
|
||||||
|
default: Date.now,
|
||||||
|
tfield: {
|
||||||
|
tlist: { tenable: false },
|
||||||
|
}
|
||||||
|
},
|
||||||
|
info_date: {
|
||||||
|
type: Date,
|
||||||
|
tfield: {
|
||||||
|
tlist: { tenable: false },
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
type: String,
|
||||||
|
tfield: {
|
||||||
|
tlist: { tenable: false },
|
||||||
|
}
|
||||||
|
},
|
||||||
|
gps_latitude: {
|
||||||
|
type: Number,
|
||||||
|
tfield: {
|
||||||
|
tname: 'Latitude',
|
||||||
|
tlist: { tenable: false },
|
||||||
|
}
|
||||||
|
},
|
||||||
|
gps_longitude: {
|
||||||
|
type: Number,
|
||||||
|
tfield: {
|
||||||
|
tname: 'Longitude',
|
||||||
|
tlist: { tenable: false },
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
rx_bytes: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
tfield: {
|
||||||
|
tname: 'RX bytes'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rx_requests: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
tfield: {
|
||||||
|
tname: 'RX req#'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rx_date: {
|
||||||
|
type: Date,
|
||||||
|
index: { unique: false },
|
||||||
|
default: Date.now,
|
||||||
|
tfield: {
|
||||||
|
tname: 'RX Date'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var modelSchema = new mongoose.Schema(modelMeta);
|
||||||
|
|
||||||
|
modelSchema.statics = tmongoose.buildStaticsModelValidated(modelMeta,modelSchema, {
|
||||||
|
findByNetId: function (net_id, callback) {
|
||||||
|
logger.debug(modelBackend+'.findByNetId net_id='+net_id+"");
|
||||||
|
this.find({net_id:net_id}).sort('insert_date').exec(callback);
|
||||||
|
},
|
||||||
|
findByNetIdAndNodeId: function (net_id,node_id, callback) {
|
||||||
|
logger.debug(modelBackend+'.findByNetIdAndNodeId net_id='+net_id+' node_id='+node_id);
|
||||||
|
this.findOne({net_id:net_id,node_id:node_id}).sort('insert_date').exec(callback);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = mongoose.model(modelName, modelSchema, modelBackend);
|
35
lib-build/debug-server/node_lib/model/xsystem-session.js
Normal file
35
lib-build/debug-server/node_lib/model/xsystem-session.js
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
var logger = require('winston').loggers.get('main');
|
||||||
|
var mongoose = require('mongoose');
|
||||||
|
var tmongoose = require('../lib/node-ff-tcrud').build.backend.mongoose;
|
||||||
|
var modelName = __filename.split('/').pop().split('.')[0];
|
||||||
|
var modelBackend = modelName.split('-').join('_');
|
||||||
|
|
||||||
|
var modelMeta = {
|
||||||
|
_id: {
|
||||||
|
type: String,
|
||||||
|
tfield: {
|
||||||
|
tname: 'SID',
|
||||||
|
ttype: 'textarea'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
session: {
|
||||||
|
type: String,
|
||||||
|
tfield: {
|
||||||
|
ttype: 'textarea'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
expires: {
|
||||||
|
type: Date,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
var modelSchema = new mongoose.Schema(modelMeta);
|
||||||
|
|
||||||
|
modelSchema.statics = tmongoose.buildStaticsModelValidated(modelMeta,modelSchema, {
|
||||||
|
findLastChangedLimit5: function (callback) {
|
||||||
|
logger.debug(modelBackend+'.findLastChangedLimit5');
|
||||||
|
this.find({}).sort('-changed_date').limit(5).exec(callback);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = mongoose.model(modelName, modelSchema, modelBackend);
|
146
lib-build/debug-server/node_lib/model/xsystem-state.js
Normal file
146
lib-build/debug-server/node_lib/model/xsystem-state.js
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
var logger = require('winston').loggers.get('main');
|
||||||
|
var mongoose = require('mongoose');
|
||||||
|
var tmongoose = require('../lib/node-ff-tcrud').build.backend.mongoose;
|
||||||
|
var modelName = __filename.split('/').pop().split('.')[0];
|
||||||
|
var modelBackend = modelName.split('-').join('_');
|
||||||
|
|
||||||
|
var modelMeta = {
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
trim: true,
|
||||||
|
index: { unique: true },
|
||||||
|
tfield: {
|
||||||
|
tvalidate: { io: 'string' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
trim: true,
|
||||||
|
index: { unique: false },
|
||||||
|
tfield: {
|
||||||
|
tvalidate: { io: 'string' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
trim: true,
|
||||||
|
tfield: {
|
||||||
|
xtype: 'textarea',
|
||||||
|
tvalidate: { io: 'string' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
type: String,
|
||||||
|
trim: true,
|
||||||
|
tfield: {
|
||||||
|
ttype: 'textarea',
|
||||||
|
tvalidate: { io: 'string' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
changed_date: {
|
||||||
|
type: Date,
|
||||||
|
default: Date.now,
|
||||||
|
tfield: {
|
||||||
|
tlist: { tenable: false },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created_date: {
|
||||||
|
type: Date,
|
||||||
|
default: Date.now,
|
||||||
|
tfield: {
|
||||||
|
tlist: { tenable: false },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var modelSchema = new mongoose.Schema(modelMeta);
|
||||||
|
|
||||||
|
modelSchema.statics = tmongoose.buildStaticsModelValidated(modelMeta,modelSchema, {
|
||||||
|
findLastChangedLimit5: function (callback) {
|
||||||
|
logger.debug(modelBackend+'.findLastChangedLimit5');
|
||||||
|
this.find({}).sort('-changed_date').limit(5).exec(callback);
|
||||||
|
},
|
||||||
|
findOneByName: function (name, callback) {
|
||||||
|
logger.debug(modelBackend+'.findByName name='+name);
|
||||||
|
this.findOne({name:name}).exec(callback);
|
||||||
|
},
|
||||||
|
ensureExcists: function (name, type, defaultValue, description, callback) {
|
||||||
|
this.findOneByName(name, function(err, xprop) {
|
||||||
|
if (err) {
|
||||||
|
callback(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (xprop == null) {
|
||||||
|
logger.debug(modelBackend+'.getByName create name='+name+' defaultValue='+defaultValue);
|
||||||
|
var model = mongoose.model(modelName);
|
||||||
|
xprop = new model();
|
||||||
|
xprop.name = name;
|
||||||
|
xprop.type = type;
|
||||||
|
xprop.value = defaultValue;
|
||||||
|
xprop.description = description;
|
||||||
|
xprop.save(function(err,xprop) {
|
||||||
|
if (callback) {
|
||||||
|
callback(err, xprop);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
logger.debug(modelBackend+'.getByName fetched name='+name);
|
||||||
|
if (callback) {
|
||||||
|
callback(null, xprop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
setByName: function (name, value, callback) {
|
||||||
|
this.findOneByName(name, function(err, xprop) {
|
||||||
|
if (err) { throw err }
|
||||||
|
logger.debug(modelBackend+'.setByName name='+name+' valueNew='+value+' valueOld='+xprop.value);
|
||||||
|
xprop.value = value;
|
||||||
|
xprop.save(function(err) {
|
||||||
|
callback(err, xprop);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
incByName: function (name, callback) {
|
||||||
|
this.findOneByName(name, function(err, xprop) {
|
||||||
|
if (err) { throw err }
|
||||||
|
xprop.value++;
|
||||||
|
logger.debug(modelBackend+'.incByName name='+name+' value='+xprop.value);
|
||||||
|
xprop.save(function(err) {
|
||||||
|
callback(err, xprop);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
incHexByName: function (name, callback) {
|
||||||
|
this.findOneByName(name, function(err, xprop) {
|
||||||
|
// DIY inc per 8 chars as JS goes to ~14chars before zering the rest.
|
||||||
|
var v = xprop.value;
|
||||||
|
var r = '';
|
||||||
|
var inc = true;
|
||||||
|
for (var i=0;i<v.length/8;i++) {
|
||||||
|
var sv = v.substring(v.length-(i*8)-8,v.length-(i*8));
|
||||||
|
var svNum = parseInt(sv, 16);
|
||||||
|
if (inc) {
|
||||||
|
svNum++;
|
||||||
|
inc = false;
|
||||||
|
}
|
||||||
|
if (svNum == (1+0xFFFFFFFF)) {
|
||||||
|
svNum = 0;
|
||||||
|
inc = true;
|
||||||
|
}
|
||||||
|
sv = svNum.toString(16).toUpperCase();
|
||||||
|
while (i<((v.length/8)-1) && sv.length < 8) {
|
||||||
|
sv = '0' + sv;
|
||||||
|
}
|
||||||
|
r = sv + r;
|
||||||
|
}
|
||||||
|
xprop.value = r; ///(parseInt(xprop.value, 16)+1).toString(16).toUpperCase();
|
||||||
|
logger.debug(modelBackend+'.incHexByName name='+name+' value='+xprop.value);
|
||||||
|
xprop.save(function(err) {
|
||||||
|
callback(err, xprop);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = mongoose.model(modelName, modelSchema, modelBackend);
|
46
lib-build/debug-server/node_lib/model/xsystem-user.js
Normal file
46
lib-build/debug-server/node_lib/model/xsystem-user.js
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
var logger = require('winston').loggers.get('main');
|
||||||
|
var mongoose = require('mongoose');
|
||||||
|
var tmongoose = require('../lib/node-ff-tcrud').build.backend.mongoose;
|
||||||
|
var modelName = __filename.split('/').pop().split('.')[0];
|
||||||
|
var modelBackend = modelName.split('-').join('_');
|
||||||
|
|
||||||
|
var modelMeta = {
|
||||||
|
username: {
|
||||||
|
type: String,
|
||||||
|
trim: true,
|
||||||
|
index: { unique: true },
|
||||||
|
tfield: {
|
||||||
|
tvalidate: { io: 'string' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
password: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
active: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
changed_date: {
|
||||||
|
type: Date,
|
||||||
|
default: Date.now
|
||||||
|
},
|
||||||
|
created_date: {
|
||||||
|
type: Date,
|
||||||
|
default: Date.now
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var modelSchema = new mongoose.Schema(modelMeta);
|
||||||
|
|
||||||
|
modelSchema.statics = tmongoose.buildStaticsModelValidated(modelMeta,modelSchema, {
|
||||||
|
findLastChangedLimit5: function (callback) {
|
||||||
|
logger.debug(modelBackend+'.findLastChangedLimit5');
|
||||||
|
this.find({}).sort('-changed_date').limit(5).exec(callback);
|
||||||
|
},
|
||||||
|
findOneByUsername: function (username, callback) {
|
||||||
|
logger.debug(modelBackend+'.findByName username='+username);
|
||||||
|
this.findOne({username:username}).exec(callback);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = mongoose.model(modelName, modelSchema, modelBackend);
|
38
lib-build/debug-server/node_lib/server-build.js
Normal file
38
lib-build/debug-server/node_lib/server-build.js
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
var favicon = require('static-favicon');
|
||||||
|
var morgan = require('morgan')
|
||||||
|
var cookieParser = require('cookie-parser')
|
||||||
|
var bodyParser = require('body-parser');
|
||||||
|
var express = require('express');
|
||||||
|
var tcrud = require('./lib/node-ff-tcrud');
|
||||||
|
var xdeviceA = require('./device/xdevice-connector-a');
|
||||||
|
|
||||||
|
var renderIndex = function(server) {
|
||||||
|
return function (req, res, next) {
|
||||||
|
res.render('index', {
|
||||||
|
pageTitle: server.get('config').application.index.pageTitle,
|
||||||
|
pageKeywords: server.get('config').application.index.pageKeywords,
|
||||||
|
pageCssFiles: server.get('ff_assets_css'),
|
||||||
|
pageJsFiles: server.get('ff_assets_js'),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.initConfig = function(server,config) {
|
||||||
|
server.use(favicon());
|
||||||
|
server.use(morgan(config.options.morgan.logLevel));
|
||||||
|
server.use(cookieParser(config.options.cookieParser.secretKey));
|
||||||
|
server.use(bodyParser.json());
|
||||||
|
server.use(bodyParser.urlencoded());
|
||||||
|
|
||||||
|
server.post('/_a', xdeviceA.deviceControl);
|
||||||
|
|
||||||
|
tcrud.factory.express.buildCrudApi(server);
|
||||||
|
server.get('/api/json/server/uptime', tcrud.factory.express.renderServerUptime());
|
||||||
|
server.get('/api/json/server/routes', tcrud.factory.express.renderServerRoutes(server));
|
||||||
|
|
||||||
|
server.get('/', tcrud.factory.express.sendRedirect('/ui'));
|
||||||
|
server.get('/ui', renderIndex(server));
|
||||||
|
server.get('/ui/thtml/*', tcrud.factory.express.renderTemplatePath('thtml/'));
|
||||||
|
server.get('/ui/*', renderIndex(server)); // must be last; for HTML5 history
|
||||||
|
}
|
||||||
|
|
44
lib-build/debug-server/package.json
Normal file
44
lib-build/debug-server/package.json
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
{
|
||||||
|
"name": "xnode-debug-server",
|
||||||
|
"description": "XNode Debug Server",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"start": "node server.js",
|
||||||
|
"size": "npm run-script size-json;npm run-script size-html;npm run-script size-code",
|
||||||
|
"size-code": "find . -type f -name '*.js' |egrep -v '/node_modules|/lib' | xargs wc -l",
|
||||||
|
"size-json": "find . -type f -name '*.json' |egrep -v '/node_modules|/lib' | xargs wc -l",
|
||||||
|
"size-html": "find . -type f -name '*.ejs' |egrep -v '/node_modules|/lib' | xargs wc -l"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"async": "~0.9.0",
|
||||||
|
"body-parser": "~1.0.1",
|
||||||
|
"bootstrap": "3.3.2",
|
||||||
|
"clone": "^1.0.0",
|
||||||
|
"connect-mongo": "^0.7.0",
|
||||||
|
"cookie-parser": "^1.0.1",
|
||||||
|
"crud-mongoose": "^1.0.10",
|
||||||
|
"ejs": "^2.3.1",
|
||||||
|
"errorhandler": "^1.1.1",
|
||||||
|
"express": "^4.11.0",
|
||||||
|
"express-session": "^1.10.3",
|
||||||
|
"fetch": "^0.3.6",
|
||||||
|
"flot": "0.8.0-alpha",
|
||||||
|
"fs-extra": "^0.16.3",
|
||||||
|
"mongoose": "~3.8.13",
|
||||||
|
"morgan": "~1.1.1",
|
||||||
|
"node-crud": "2.0.8",
|
||||||
|
"node-ff-assets": "^0.2.4",
|
||||||
|
"raw-body": "1.2.2",
|
||||||
|
"static-favicon": "~1.0.0",
|
||||||
|
"tree-surgeon": "0.0.13",
|
||||||
|
"type-is": "1.1.0",
|
||||||
|
"underscore": "^1.8.2",
|
||||||
|
"validate.io": "^1.5.0",
|
||||||
|
"winston": "~0.7.3",
|
||||||
|
"xml-mapping": "~1.6.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"mocha-jshint": "0.0.9"
|
||||||
|
}
|
||||||
|
}
|
27
lib-build/debug-server/server-assets.json
Normal file
27
lib-build/debug-server/server-assets.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"linkMapping" : {
|
||||||
|
"/static/module/bootstrap/": "node_modules/bootstrap/dist/",
|
||||||
|
"/static/module/flot/": "node_modules/flot/",
|
||||||
|
"/static/": "www_static/"
|
||||||
|
},
|
||||||
|
"css": {
|
||||||
|
"linkTarget": "/static/css/lib/assets.css",
|
||||||
|
"linkSources": [
|
||||||
|
"/static/module/bootstrap/css/bootstrap.css"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"js": {
|
||||||
|
"linkTarget": "/static/js/lib/assets.js",
|
||||||
|
"linkSources": [
|
||||||
|
"/static/js/lib/jquery-2.1.3/jquery.js@http://code.jquery.com/jquery-2.1.3.js",
|
||||||
|
"/static/module/bootstrap/js/bootstrap.js",
|
||||||
|
"/static/module/flot/jquery.flot.js",
|
||||||
|
"/static/module/flot/jquery.flot.resize.js",
|
||||||
|
"/static/module/flot/jquery.flot.pie.js",
|
||||||
|
"/static/js/lib/angularjs-1.4.0-b4/angular.js@https://code.angularjs.org/1.4.0-beta.4/angular.js",
|
||||||
|
"/static/js/lib/angularjs-1.4.0-b4/angular-route.js@https://code.angularjs.org/1.4.0-beta.4/angular-route.js",
|
||||||
|
"/static/js/lib/angularjs-1.4.0-b4/angular-resource.js@https://code.angularjs.org/1.4.0-beta.4/angular-resource.js",
|
||||||
|
"/static/js/lib/angularjs-1.4.0-b4/angular-touch.js@https://code.angularjs.org/1.4.0-beta.4/angular-touch.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
71
lib-build/debug-server/server-config.js
Normal file
71
lib-build/debug-server/server-config.js
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
module.exports = {
|
||||||
|
winston: {
|
||||||
|
console: {
|
||||||
|
level: 'debug',
|
||||||
|
silent: false,
|
||||||
|
colorize: true,
|
||||||
|
timestamp: null
|
||||||
|
},
|
||||||
|
file: {
|
||||||
|
level: 'info',
|
||||||
|
silent: false,
|
||||||
|
colorize: false,
|
||||||
|
json: false,
|
||||||
|
//timestamp: null,
|
||||||
|
//maxFiles: 100,
|
||||||
|
//maxsize: 1024*1024*1024,
|
||||||
|
filename: 'www_logs/server.log'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mongo: {
|
||||||
|
url: process.env.MONGO_URL || 'mongodb://localhost:27017/xnode-debug-server',
|
||||||
|
options : {
|
||||||
|
//user: 'myUserName',
|
||||||
|
//pass: 'myPassword',
|
||||||
|
db: {
|
||||||
|
fsync: false,
|
||||||
|
journal: false,
|
||||||
|
native_parser: true,
|
||||||
|
forceServerObjectId: true
|
||||||
|
},
|
||||||
|
server: {
|
||||||
|
poolSize: 4,
|
||||||
|
socketOptions: {
|
||||||
|
connectTimeoutMS: 500,
|
||||||
|
keepAlive: 1,
|
||||||
|
auto_reconnect: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
server: {
|
||||||
|
httpPort: process.env.HTTP_PORT || 8008,
|
||||||
|
httpTrustProxy: true,
|
||||||
|
sessionSecret: 'xensitXDS',
|
||||||
|
sessionTTL: 14 * 24 * 60 * 60, // = 14 days. Default
|
||||||
|
},
|
||||||
|
application: {
|
||||||
|
name: 'Xensit Debug Server',
|
||||||
|
index: {
|
||||||
|
pageTitle: 'Xensit Debug Server',
|
||||||
|
pageKeywords: 'xnode,sensor,data,weather,wireless',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
static: {
|
||||||
|
maxAge: 86400000
|
||||||
|
},
|
||||||
|
morgan: {
|
||||||
|
logLevel: process.env.LOG_MORGAN || 'dev'
|
||||||
|
},
|
||||||
|
cookieParser: {
|
||||||
|
secretKey: 'DeBugMe@11'
|
||||||
|
},
|
||||||
|
rss: {
|
||||||
|
link: 'http://localhost:8008',
|
||||||
|
author: 'Xensit',
|
||||||
|
options: {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
102
lib-build/debug-server/server-init.js
Normal file
102
lib-build/debug-server/server-init.js
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var logger = require('winston').loggers.get('main');
|
||||||
|
var mongoose = require('mongoose');
|
||||||
|
var async = require('async');
|
||||||
|
var fs = require('fs');
|
||||||
|
var tcrud = require('./node_lib/lib/node-ff-tcrud');
|
||||||
|
var assets = require('node-ff-assets');
|
||||||
|
var xsystemState = mongoose.model( 'xsystem-state' );
|
||||||
|
|
||||||
|
function walkTree(builderConfigJs,server,crud) {
|
||||||
|
if (crud.tparent && crud.tenable && crud.tmodel) {
|
||||||
|
var localPort = server.get('config').server.httpPort;
|
||||||
|
var tview = tcrud.build.view.createTCrudView(crud/*, fetchCrudRoles()*/);
|
||||||
|
var base = troot.tmeta.tserver.tslug + '/' + tcrud.build.view.createBaseApiUri(tview,'angular');
|
||||||
|
var assetLink = '/static/js/lib/tcrud/'+tview.tslug+'/controller.js@@http://localhost:'+localPort+base+'/controller.js';
|
||||||
|
//console.log('asssetLinkDyna; '+assetLink);
|
||||||
|
builderConfigJs.linkSources.push(assetLink);
|
||||||
|
}
|
||||||
|
for (var i = 0; i < crud.tchilds.length; i++) {
|
||||||
|
walkTree(builderConfigJs,server,crud.tchilds[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function pushDynamicLinkSourcesJs(builderConfigJs,server) {
|
||||||
|
return function(callback) {
|
||||||
|
// Extend js list with crud entries
|
||||||
|
troot = server.get('ff_root_tcrud_view');
|
||||||
|
walkTree(builderConfigJs,server,troot);
|
||||||
|
callback();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildAssets(server,callbackDone) {
|
||||||
|
var singleResult = 'false' !== process.env.DEV_ASSETS_SINGLE_RESULT;
|
||||||
|
var assetsConfig = require('./server-assets.json');
|
||||||
|
assets.build({
|
||||||
|
assets: {
|
||||||
|
js: {
|
||||||
|
configCreate: assets.factory.builder.configCreate.fromJSON(assetsConfig,'js'),
|
||||||
|
configFill: function (config, callback) {
|
||||||
|
async.series([
|
||||||
|
assets.factory.lib.async.pushLinkSources(config, '/static/js/', 'www_static/js/'),
|
||||||
|
assets.factory.lib.async.pushLinkSources(config, '/static/js/controller/', 'www_static/js/controller/'),
|
||||||
|
pushDynamicLinkSourcesJs(config,server),
|
||||||
|
],callback);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
css: {
|
||||||
|
configCreate: assets.factory.builder.configCreate.fromJSON(assetsConfig,'css'),
|
||||||
|
configFill: function (config, callback) {
|
||||||
|
async.series([
|
||||||
|
assets.factory.lib.async.pushLinkSources(config, '/static/css/', 'www_static/css/'),
|
||||||
|
],callback);
|
||||||
|
|
||||||
|
},
|
||||||
|
//assemblerCreate: function (assemblerConfig, callback) {
|
||||||
|
// callback(null,new assets.AssetAssembler(assemblerConfig,assets.factory.assembler.constructor.readFileMinify()));
|
||||||
|
//},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// assemblerCreate: assets.factory.builder.assemblerCreate.readFileRegex(),
|
||||||
|
assemblerFill: function (assembler, callback) {
|
||||||
|
var serverResultKey = 'ff_assets_'+assembler.config.assetType;
|
||||||
|
assembler.on ('log', assets.factory.assembler.event.log.winston(logger,assembler.config.assetType));
|
||||||
|
assembler.on ('result', assets.factory.assembler.event.result.objectSet(server,serverResultKey));
|
||||||
|
assembler.config.linkTargetSingleResult = singleResult;
|
||||||
|
callback();
|
||||||
|
},
|
||||||
|
},callbackDone);
|
||||||
|
}
|
||||||
|
|
||||||
|
var initServerStateValue = function(server,type,name,defaultValue,description) {
|
||||||
|
xsystemState.ensureExcists(name,type,defaultValue,description,function(err,data) {
|
||||||
|
if (err) { throw err }
|
||||||
|
logger.info('state checked: '+data.name);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.build = function(server) {
|
||||||
|
buildAssets(server,function(err) {
|
||||||
|
if (err) {
|
||||||
|
logger.info('Server init failed: '+err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
logger.info('Server init done.');
|
||||||
|
// init other stuff...
|
||||||
|
|
||||||
|
initServerStateValue(server,'_a','_a_seq_base_net_id', '1F2E3D4C5B6A','XNode Base net_id sequence');
|
||||||
|
initServerStateValue(server,'_a','_a_seq_base_net_key' ,'9A2EE3A293486E9FE73D77EFC8087D2F','XNode Base net_key sequence')
|
||||||
|
initServerStateValue(server,'_a','_a_seq_base_net_mac', '7469694D33B1','XNode Base net_mac sequence')
|
||||||
|
initServerStateValue(server,'_a','_a_seq_base_rf_key', '1A2B93586E9F170D72EFC8FE72D53A9F','XNode Base rf_key sequence');
|
||||||
|
|
||||||
|
initServerStateValue(server,'xds','xds_boot_date',new Date().getTime(),'Server Last boot date');
|
||||||
|
initServerStateValue(server,'xds','xds_boot_count','0','Server Boot Counter');
|
||||||
|
|
||||||
|
setTimeout(function() {
|
||||||
|
xsystemState.incByName('xds_boot_count',function(err,data) {});
|
||||||
|
xsystemState.setByName('xds_boot_date',new Date().getTime(),function(err,data) {});
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
}
|
115
lib-build/debug-server/server.js
Normal file
115
lib-build/debug-server/server.js
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
// server.js
|
||||||
|
var config = require('./server-config');
|
||||||
|
var winston = require('winston');
|
||||||
|
winston.loggers.add('main',config.winston);
|
||||||
|
var log = winston.loggers.get('main');
|
||||||
|
var express = require('express');
|
||||||
|
var path = require('path');
|
||||||
|
var fs = require('fs');
|
||||||
|
var mongoose = require('mongoose');
|
||||||
|
var expressSession = require('express-session');
|
||||||
|
var mongoStore = require('connect-mongo')(expressSession);
|
||||||
|
var tcrud = require('./node_lib/lib/node-ff-tcrud');
|
||||||
|
|
||||||
|
function startMongoose(callback) {
|
||||||
|
log.info('Starting '+config.application.name);
|
||||||
|
log.info('Connecting to: ' + config.mongo.url);
|
||||||
|
mongoose.connection.on('error', callback);
|
||||||
|
mongoose.connection.on('connected', callback);
|
||||||
|
mongoose.connect(config.mongo.url,config.mongo.options);
|
||||||
|
}
|
||||||
|
|
||||||
|
function startMongooseModels(server,callback) {
|
||||||
|
var modelsCount = 0;
|
||||||
|
var modelsPath = __dirname + '/node_lib/model';
|
||||||
|
fs.readdirSync(modelsPath).forEach(function (file) {
|
||||||
|
if (~file.indexOf('.js')) {
|
||||||
|
log.debug('Loading mongoose model: '+file);
|
||||||
|
require(modelsPath + '/' + file);
|
||||||
|
modelsCount++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
log.info('Loaded mongoose models: '+modelsCount);
|
||||||
|
|
||||||
|
var crudRoot = tcrud.build.config.createTCrudRoot();
|
||||||
|
|
||||||
|
|
||||||
|
var crudAdmin = tcrud.build.config.createTCrud(crudRoot,'admin');
|
||||||
|
crudAdmin.troles.push('admin');
|
||||||
|
//crudAdmin.tenable = false;
|
||||||
|
|
||||||
|
var crudAdminModels = tcrud.build.backend.mongoose.buildTCrudModels(mongoose,crudAdmin);
|
||||||
|
log.info('crud admin models created: '+crudAdminModels.length);
|
||||||
|
|
||||||
|
//var crudAdminNodeBaseCmd = crudAdmin
|
||||||
|
|
||||||
|
server.set('ff_root_tcrud_view',crudRoot);
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build Server
|
||||||
|
function createServerSync() {
|
||||||
|
var server = express();
|
||||||
|
server.disable('x-powered-by');
|
||||||
|
server.set('config', config);
|
||||||
|
server.set('trust proxy', config.server.httpTrustProxy);
|
||||||
|
server.set('views', [path.join(__dirname, 'www_views'),path.join(__dirname, 'node_lib/lib/www_views')]);
|
||||||
|
server.set('view engine', 'ejs');
|
||||||
|
server.use('/static',express.static(path.join(__dirname,'www_static'),config.options.static));
|
||||||
|
server.use('/static/module/bootstrap',express.static(path.join(__dirname,'node_modules/bootstrap/dist'),config.options.static));
|
||||||
|
server.use('/static/module/flot',express.static(path.join(__dirname,'node_modules/flot'),config.options.static));
|
||||||
|
|
||||||
|
// Add Server session support
|
||||||
|
// server.use(expressSession({
|
||||||
|
// secret: config.server.sessionSecret,
|
||||||
|
// store: new mongoStore({
|
||||||
|
// mongooseConnection: mongoose.connection,
|
||||||
|
// collection: 'xsystem_session',
|
||||||
|
// ttl: server.sessionTTL,
|
||||||
|
// })
|
||||||
|
// }));
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
function configServer(server,callback) {
|
||||||
|
// Add Server config and routing
|
||||||
|
var router = require('./node_lib/server-build');
|
||||||
|
router.initConfig(server,config);
|
||||||
|
|
||||||
|
// Store router list for server/routes page
|
||||||
|
tcrud.factory.express.buildServerRoutes(server);
|
||||||
|
|
||||||
|
// Auto build site assets
|
||||||
|
var ServerInit = require('./server-init');
|
||||||
|
ServerInit.build(server);
|
||||||
|
|
||||||
|
// Test
|
||||||
|
//var test = require('./node_lib/device/xdevice-encryption');
|
||||||
|
//log.info('testA='+test.xxteaDecrypt('D57408F9D7F10917AFE9AA92C8051450','9A2EE3A293486E9FE73D77EFC8087D31'));
|
||||||
|
//log.info('testA='+test.xxteaDecrypt('9A2EE3A293486E9F','D57408F9D7F10917AFE9AA92C8051450'));
|
||||||
|
//log.info('testB=rf_fail=1');
|
||||||
|
//log.info('testC='+test.xxteaDecrypt('944DF85BAEE43DC0D7914910D2B69547','9A2EE3A293486E9F'));
|
||||||
|
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
function startServer(server) {
|
||||||
|
server.listen(config.server.httpPort);
|
||||||
|
log.info('Started '+config.application.name+' on port: ' + config.server.httpPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
startMongoose(function(err) {
|
||||||
|
if (err) { throw err };
|
||||||
|
server = createServerSync();
|
||||||
|
startMongooseModels(server,function(err) {
|
||||||
|
if (err) { throw err };
|
||||||
|
configServer(server,function(err) {
|
||||||
|
if (err) { throw err };
|
||||||
|
startServer(server)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
version: 'development'
|
||||||
|
};
|
149
lib-build/debug-server/www_static/css/boot.css
Normal file
149
lib-build/debug-server/www_static/css/boot.css
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin-top: 100px;
|
||||||
|
background-color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media(min-width:768px) {
|
||||||
|
body {
|
||||||
|
margin-top: 50px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#wrapper {
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#page-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.huge {
|
||||||
|
font-size: 50px;
|
||||||
|
line-height: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media(min-width:768px) {
|
||||||
|
#wrapper {
|
||||||
|
padding-left: 225px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#page-wrapper {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Top Navigation */
|
||||||
|
|
||||||
|
.top-nav {
|
||||||
|
padding: 0 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-nav>li {
|
||||||
|
display: inline-block;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-nav>li>a {
|
||||||
|
padding-top: 15px;
|
||||||
|
padding-bottom: 15px;
|
||||||
|
line-height: 20px;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-nav>li>a:hover,
|
||||||
|
.top-nav>li>a:focus,
|
||||||
|
.top-nav>.open>a,
|
||||||
|
.top-nav>.open>a:hover,
|
||||||
|
.top-nav>.open>a:focus {
|
||||||
|
color: #fff;
|
||||||
|
background-color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-nav>.open>.dropdown-menu {
|
||||||
|
float: left;
|
||||||
|
position: absolute;
|
||||||
|
margin-top: 0;
|
||||||
|
border: 1px solid rgba(0,0,0,.15);
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
border-top-right-radius: 0;
|
||||||
|
background-color: #fff;
|
||||||
|
-webkit-box-shadow: 0 6px 12px rgba(0,0,0,.175);
|
||||||
|
box-shadow: 0 6px 12px rgba(0,0,0,.175);
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-nav>.open>.dropdown-menu>li>a {
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.message-dropdown {
|
||||||
|
padding: 0;
|
||||||
|
max-height: 250px;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
li.message-preview {
|
||||||
|
width: 275px;
|
||||||
|
border-bottom: 1px solid rgba(0,0,0,.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
li.message-preview>a {
|
||||||
|
padding-top: 15px;
|
||||||
|
padding-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
li.message-footer {
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.alert-dropdown {
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Side Navigation */
|
||||||
|
|
||||||
|
@media(min-width:768px) {
|
||||||
|
.side-nav {
|
||||||
|
position: fixed;
|
||||||
|
top: 51px;
|
||||||
|
left: 225px;
|
||||||
|
width: 225px;
|
||||||
|
margin-left: -225px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 0;
|
||||||
|
overflow-y: auto;
|
||||||
|
background-color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
.side-nav>li>a {
|
||||||
|
width: 225px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.side-nav li a:hover,
|
||||||
|
.side-nav li a:focus {
|
||||||
|
outline: none;
|
||||||
|
background-color: #000 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.side-nav>li>ul {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.side-nav>li>ul>li>a {
|
||||||
|
display: block;
|
||||||
|
padding: 10px 15px 10px 38px;
|
||||||
|
text-decoration: none;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.side-nav>li>ul>li>a:hover {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.huge {
|
||||||
|
font-size: 40px;
|
||||||
|
}
|
11
lib-build/debug-server/www_static/css/flot.css
Normal file
11
lib-build/debug-server/www_static/css/flot.css
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
|
||||||
|
.flot-chart {
|
||||||
|
display: block;
|
||||||
|
height: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flot-chart-content {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
56
lib-build/debug-server/www_static/css/panel.css
Normal file
56
lib-build/debug-server/www_static/css/panel.css
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
|
||||||
|
.panel-green {
|
||||||
|
border-color: #5cb85c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-green .panel-heading {
|
||||||
|
border-color: #5cb85c;
|
||||||
|
color: #fff;
|
||||||
|
background-color: #5cb85c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-green a {
|
||||||
|
color: #5cb85c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-green a:hover {
|
||||||
|
color: #3d8b3d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-red {
|
||||||
|
border-color: #d9534f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-red .panel-heading {
|
||||||
|
border-color: #d9534f;
|
||||||
|
color: #fff;
|
||||||
|
background-color: #d9534f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-red a {
|
||||||
|
color: #d9534f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-red a:hover {
|
||||||
|
color: #b52b27;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-yellow {
|
||||||
|
border-color: #f0ad4e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-yellow .panel-heading {
|
||||||
|
border-color: #f0ad4e;
|
||||||
|
color: #fff;
|
||||||
|
background-color: #f0ad4e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-yellow a {
|
||||||
|
color: #f0ad4e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-yellow a:hover {
|
||||||
|
color: #df8a13;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
54
lib-build/debug-server/www_static/css/style.css
Normal file
54
lib-build/debug-server/www_static/css/style.css
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
|
||||||
|
#wrapper {
|
||||||
|
padding-right: 0px;
|
||||||
|
padding-left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.side-nav {
|
||||||
|
right: 0px;
|
||||||
|
left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-footer {
|
||||||
|
margin-left: 45%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-toggle {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-brand {
|
||||||
|
background-color: #2CABE1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-inverse .navbar-brand {
|
||||||
|
color: #FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-inverse .navbar-brand:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-inverse .navbar-brand:hover {
|
||||||
|
background-color: #FF9A28;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-inverse {
|
||||||
|
background-color: #2CABE1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menuLogo {
|
||||||
|
position: absolute;
|
||||||
|
top: 47px;
|
||||||
|
right: 0px;
|
||||||
|
background: url("../img/xensit-sm.png") 50% 0px no-repeat transparent !important;
|
||||||
|
height: 77px;
|
||||||
|
width: 212px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
BIN
lib-build/debug-server/www_static/img/xensit-sm.png
Normal file
BIN
lib-build/debug-server/www_static/img/xensit-sm.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.3 KiB |
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
pageRouteInit.push(function ($routeProvider, $locationProvider) {
|
||||||
|
$routeProvider.when('/ui/server/about', {
|
||||||
|
templateUrl: '/ui/thtml/server/about',
|
||||||
|
controller: XPageServerAbout
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function XPageServerAbout($scope, $http) {
|
||||||
|
//$http.get('/api/posts').success(function(data, status, headers, config) {
|
||||||
|
// $scope.posts = data.posts;
|
||||||
|
//});
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
|
||||||
|
pageRouteInit.push(function ($routeProvider, $locationProvider) {
|
||||||
|
$routeProvider.when('server/dash', {
|
||||||
|
templateUrl: '/ui/thtml/server/dash',
|
||||||
|
controller: XPageServerDash
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function XPageServerDash($scope, $http) {
|
||||||
|
//$http.get('/api/posts').success(function(data, status, headers, config) {
|
||||||
|
// $scope.posts = data.posts;
|
||||||
|
//});
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
pageRouteInit.push(function ($routeProvider, $locationProvider) {
|
||||||
|
$routeProvider.when('/ui', {
|
||||||
|
templateUrl: '/ui/thtml/server/index',
|
||||||
|
controller: XPageServerIndex
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function XPageServerIndex($scope, $http) {
|
||||||
|
//$http.get('/api/posts').success(function(data, status, headers, config) {
|
||||||
|
// $scope.posts = data.posts;
|
||||||
|
//});
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
|
||||||
|
pageRouteInit.push(function ($routeProvider, $locationProvider) {
|
||||||
|
$routeProvider.when('/ui/server/routes', {
|
||||||
|
redirectTo: '/ui/server/routes/tech',
|
||||||
|
});
|
||||||
|
$routeProvider.when('/ui/server/routes/tech', {
|
||||||
|
templateUrl: '/ui/thtml/server/routes?group1=all,rss,json&group2=csv,xml,ui,angular',
|
||||||
|
controller: XPageServerTechRoutes,
|
||||||
|
});
|
||||||
|
$routeProvider.when('/ui/server/routes/model', {
|
||||||
|
templateUrl: '/ui/thtml/server/routes?group1=xnode,xnode_base,xnode-base-command&group2=xnode-data,xnode-data-value,xsystem-state,all',
|
||||||
|
controller: XPageServerModelRoutes,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function XPageServerTechRoutes($scope, $http) {
|
||||||
|
$http.get('/api/json/server/routes?groups=json,xml,rss,csv,ui,angular').success(function(data, status, headers, config) {
|
||||||
|
$scope.serverRoutes = data.data;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function XPageServerModelRoutes($scope, $http) {
|
||||||
|
$http.get('/api/json/server/routes?groups=xnode,xnode-base,xnode-base-command,xnode-data,xnode-data-value,system-state').success(function(data, status, headers, config) {
|
||||||
|
$scope.serverRoutes = data.data;
|
||||||
|
});
|
||||||
|
}
|
9
lib-build/debug-server/www_static/js/xds-directives.js
Normal file
9
lib-build/debug-server/www_static/js/xds-directives.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
angular.module('xdsUI.directives', []).
|
||||||
|
directive('appVersion', ['version', function(version) {
|
||||||
|
return function(scope, elm, attrs) {
|
||||||
|
elm.text(version);
|
||||||
|
};
|
||||||
|
}]);
|
||||||
|
|
9
lib-build/debug-server/www_static/js/xds-filters.js
Normal file
9
lib-build/debug-server/www_static/js/xds-filters.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
angular.module('xdsUI.filters', []).
|
||||||
|
filter('interpolate', ['version', function(version) {
|
||||||
|
return function(text) {
|
||||||
|
return String(text).replace(/\%VERSION\%/mg, version);
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
|
5
lib-build/debug-server/www_static/js/xds-services.js
Normal file
5
lib-build/debug-server/www_static/js/xds-services.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
angular.module('xdsUI.services', []).
|
||||||
|
value('version', '0.1');
|
||||||
|
|
27
lib-build/debug-server/www_static/js/xds.js
Normal file
27
lib-build/debug-server/www_static/js/xds.js
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var crudRouteInit = [];
|
||||||
|
var pageRouteInit = [];
|
||||||
|
|
||||||
|
angular.module('xdsUI', ['ngRoute','xdsUI.filters', 'xdsUI.services', 'xdsUI.directives']).
|
||||||
|
config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) {
|
||||||
|
|
||||||
|
// init page controllers
|
||||||
|
for (var i = 0; i < pageRouteInit.length; i++) {
|
||||||
|
pageRouteInit[i]($routeProvider, $locationProvider);
|
||||||
|
}
|
||||||
|
// init crud controllers
|
||||||
|
for (var i = 0; i < crudRouteInit.length; i++) {
|
||||||
|
crudRouteInit[i]($routeProvider, $locationProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
//$routeProvider.otherwise("/404", {
|
||||||
|
// templateUrl: "partials/404.html",
|
||||||
|
// controller: "PageCtrl"
|
||||||
|
//});
|
||||||
|
|
||||||
|
$routeProvider.otherwise({ redirectTo: '/ui' });
|
||||||
|
// todo: add ie9 warning, base kills svg url property
|
||||||
|
$locationProvider.html5Mode({enabled: true, requireBase: false});
|
||||||
|
}]);
|
||||||
|
|
23
lib-build/debug-server/www_views/index.ejs
Normal file
23
lib-build/debug-server/www_views/index.ejs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" ng-app="xdsUI">
|
||||||
|
<head>
|
||||||
|
<title><%= pageTitle %></title>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="keywords" content="<%= pageKeywords %>">
|
||||||
|
<% if (pageCssFiles.length) { %><% pageCssFiles.forEach(function (cssFile) { %><link rel="stylesheet" href="<%= cssFile %>"><% }) %><% } %>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="wrapper">
|
||||||
|
<div ng-include="'/ui/thtml/layout/header'"></div>
|
||||||
|
<div id="page-wrapper">
|
||||||
|
<div id="container-fluid">
|
||||||
|
<div ng-view></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div ng-include="'/ui/thtml/layout/footer'"></div>
|
||||||
|
<% if (pageJsFiles.length) { %><% pageJsFiles.forEach(function (jsFile) { %><script src="<%= jsFile %>"></script><% }) %><% } %>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,7 @@
|
||||||
|
<div>
|
||||||
|
<h1>400</h1>
|
||||||
|
<h2>Page Not Found</h2>
|
||||||
|
<pre>
|
||||||
|
Please check you url.
|
||||||
|
</pre>
|
||||||
|
</div>
|
|
@ -0,0 +1,7 @@
|
||||||
|
<div>
|
||||||
|
<h1>500</h1>
|
||||||
|
<h2>Server Error</h2>
|
||||||
|
<pre>
|
||||||
|
Sorry server at fault.
|
||||||
|
</pre>
|
||||||
|
</div>
|
7
lib-build/debug-server/www_views/thtml/layout/footer.ejs
Normal file
7
lib-build/debug-server/www_views/thtml/layout/footer.ejs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<nav class="navbar">
|
||||||
|
<div class="navbar-footer">
|
||||||
|
<a href="/ui/">Home</a> | -
|
||||||
|
<a href="/ui/server/about">About</a> | -
|
||||||
|
<a href="/ui/server/routes">Routes<a/>
|
||||||
|
</div>
|
||||||
|
</nav>
|
16
lib-build/debug-server/www_views/thtml/layout/header.ejs
Normal file
16
lib-build/debug-server/www_views/thtml/layout/header.ejs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
|
||||||
|
<div class="navbar-header">
|
||||||
|
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse">
|
||||||
|
<span class="sr-only">Toggle navigation</span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
</button>
|
||||||
|
<a class="navbar-brand" href="/ui/">Home</a>
|
||||||
|
<a class="navbar-brand" href="/ui/admin/xnode/list">XNodes</a>
|
||||||
|
<a class="navbar-brand" href="/ui/admin/xnode-base/list">XNodeBase</a>
|
||||||
|
<a class="navbar-brand" href="/ui/admin/xsystem-state/list">XSysState</a>
|
||||||
|
<a class="navbar-brand" href="/ui/admin/xsystem-session/list">XSysSession</a>
|
||||||
|
</div>
|
||||||
|
<div id="menuLogo"></div>
|
||||||
|
</nav>
|
5
lib-build/debug-server/www_views/thtml/server/about.ejs
Normal file
5
lib-build/debug-server/www_views/thtml/server/about.ejs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<div>
|
||||||
|
<h2>About</h2>
|
||||||
|
<p>Testing debug server for xensit xnodes.</p>
|
||||||
|
<p>Internal use only.</p>
|
||||||
|
</div>
|
96
lib-build/debug-server/www_views/thtml/server/dash.ejs
Normal file
96
lib-build/debug-server/www_views/thtml/server/dash.ejs
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
extends layout
|
||||||
|
|
||||||
|
block content
|
||||||
|
h1= title
|
||||||
|
div
|
||||||
|
h2 Last five node data.
|
||||||
|
table
|
||||||
|
thead
|
||||||
|
tr
|
||||||
|
th Net id
|
||||||
|
th Node Id
|
||||||
|
th Value
|
||||||
|
tbody
|
||||||
|
each row in lastData
|
||||||
|
tr
|
||||||
|
td #{row.net_id}
|
||||||
|
td #{row.node_id}
|
||||||
|
td
|
||||||
|
p #{row.insert_date}
|
||||||
|
p #{row.data_text}
|
||||||
|
|
||||||
|
div(id='split')
|
||||||
|
div(id='splitLeft')
|
||||||
|
div
|
||||||
|
h2 Last five node values.
|
||||||
|
table
|
||||||
|
thead
|
||||||
|
tr
|
||||||
|
th Net id
|
||||||
|
th Name
|
||||||
|
th Value
|
||||||
|
th insert_date
|
||||||
|
tbody
|
||||||
|
each row in lastValues
|
||||||
|
tr
|
||||||
|
td #{row.net_id}
|
||||||
|
td #{row.name}
|
||||||
|
td #{row.value}
|
||||||
|
td #{row.insert_date}
|
||||||
|
div
|
||||||
|
h2 Last five changed settings
|
||||||
|
table
|
||||||
|
thead
|
||||||
|
tr
|
||||||
|
th Name
|
||||||
|
th Value
|
||||||
|
tbody
|
||||||
|
each row in lastSettings
|
||||||
|
tr
|
||||||
|
td #{row.name}
|
||||||
|
td #{row.value}
|
||||||
|
|
||||||
|
div(id='splitRight')
|
||||||
|
div
|
||||||
|
h2 Last five pings
|
||||||
|
table
|
||||||
|
thead
|
||||||
|
tr
|
||||||
|
th Net id
|
||||||
|
th Ping Count
|
||||||
|
th Ping Last
|
||||||
|
tbody
|
||||||
|
each xnode in lastPinged
|
||||||
|
tr
|
||||||
|
td #{xnode.hw_net_id}
|
||||||
|
td #{xnode.ping_counter}
|
||||||
|
td #{xnode.ping_last_date}
|
||||||
|
div
|
||||||
|
h2 Last five open Cmds
|
||||||
|
table
|
||||||
|
thead
|
||||||
|
tr
|
||||||
|
th Net id
|
||||||
|
th Command
|
||||||
|
th Insert date
|
||||||
|
tbody
|
||||||
|
each xnode in openCommands
|
||||||
|
tr
|
||||||
|
td #{xnode.net_id}
|
||||||
|
td #{xnode.command}
|
||||||
|
td #{xnode.insert_date}
|
||||||
|
div
|
||||||
|
h2 Last five send Cmds
|
||||||
|
table
|
||||||
|
thead
|
||||||
|
tr
|
||||||
|
th Net id
|
||||||
|
th Command
|
||||||
|
th Send date
|
||||||
|
tbody
|
||||||
|
each xnode in sendCommands
|
||||||
|
tr
|
||||||
|
td #{xnode.net_id}
|
||||||
|
td #{xnode.command}
|
||||||
|
td #{xnode.send_date}
|
||||||
|
|
5
lib-build/debug-server/www_views/thtml/server/index.ejs
Normal file
5
lib-build/debug-server/www_views/thtml/server/index.ejs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<div>
|
||||||
|
<h2>XNode Debug Server Home</h2>
|
||||||
|
<p>Welcome</p>
|
||||||
|
<p>Make your self at home.</p>
|
||||||
|
</div>
|
|
@ -0,0 +1,17 @@
|
||||||
|
<div class="table-responsive">
|
||||||
|
<h3><%= routeGroup.toUpperCase() %></h3>
|
||||||
|
<table class="table table-bordered table-hover table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Path</th>
|
||||||
|
<th>Method</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr ng-repeat="route in serverRoutes['<%= routeGroup %>']">
|
||||||
|
<td>{{route.uriPath}}</td>
|
||||||
|
<td>{{route.httpMethod}}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
28
lib-build/debug-server/www_views/thtml/server/routes.ejs
Normal file
28
lib-build/debug-server/www_views/thtml/server/routes.ejs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<div>
|
||||||
|
<h2>Server Routes</h2>
|
||||||
|
<p>This page show all the nodejs express routes.</p>
|
||||||
|
<div class="row">
|
||||||
|
<% if (query.group1 && query.group2) { %>
|
||||||
|
<div class="col-lg-6">
|
||||||
|
<% query.group1.split(',').forEach(function (routeGroup) { %>
|
||||||
|
<%- include('routes-group', {routeGroup: routeGroup}); %>
|
||||||
|
<% }) %>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-6">
|
||||||
|
<% query.group2.split(',').forEach(function (routeGroup) { %>
|
||||||
|
<%- include('routes-group', {routeGroup: routeGroup}); %>
|
||||||
|
<% }) %>
|
||||||
|
</div>
|
||||||
|
<% } else if (query.group1) { %>
|
||||||
|
<div class="col-lg-12">
|
||||||
|
<% query.group1.split(',').forEach(function (routeGroup) { %>
|
||||||
|
<%- include('routes-group', {routeGroup: routeGroup}); %>
|
||||||
|
<% }) %>
|
||||||
|
</div>
|
||||||
|
<% } else { %>
|
||||||
|
<div class="col-lg-12">
|
||||||
|
<%- include('routes-group', {routeGroup: 'all'}); %>
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
</div>
|
||||||
|
</div>
|
40
lib-build/make/Makefile.inc.debug
Normal file
40
lib-build/make/Makefile.inc.debug
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#
|
||||||
|
# Managed debug logging
|
||||||
|
#
|
||||||
|
# Supported arguments are: NONE,ALL,NETWORK,RADIO,SYSTEM,SERIAL,SENSOR
|
||||||
|
|
||||||
|
# Replace keywords with debug flags.
|
||||||
|
ifneq (,$(findstring NETWORK,$(DEBUG_LOGGING)))
|
||||||
|
DEBUG_NETWORK ?= -DDEBUG_NETWORK
|
||||||
|
endif
|
||||||
|
ifneq (,$(findstring RADIO,$(DEBUG_LOGGING)))
|
||||||
|
DEBUG_RADIO ?= -DDEBUG_RADIO
|
||||||
|
endif
|
||||||
|
ifneq (,$(findstring SYSTEM,$(DEBUG_LOGGING)))
|
||||||
|
DEBUG_SYSTEM ?= -DDEBUG_SYSTEM
|
||||||
|
endif
|
||||||
|
ifneq (,$(findstring SERIAL,$(DEBUG_LOGGING)))
|
||||||
|
DEBUG_SERIAL ?= -DDEBUG_SERIAL
|
||||||
|
endif
|
||||||
|
ifneq (,$(findstring SENSOR,$(DEBUG_LOGGING)))
|
||||||
|
DEBUG_SENSOR ?= -DDEBUG_SENSOR
|
||||||
|
endif
|
||||||
|
ifneq (,$(findstring ALL,$(DEBUG_LOGGING)))
|
||||||
|
DEBUG_NETWORK ?= -DDEBUG_NETWORK
|
||||||
|
DEBUG_RADIO ?= -DDEBUG_RADIO
|
||||||
|
DEBUG_SYSTEM ?= -DDEBUG_SYSTEM
|
||||||
|
DEBUG_SERIAL ?= -DDEBUG_SERIAL
|
||||||
|
DEBUG_SENSOR ?= -DDEBUG_SENSOR
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Let NONE keyword override to disable.
|
||||||
|
ifeq (,$(findstring NONE,$(DEBUG_LOGGING)))
|
||||||
|
# Argragate debug flags to build.
|
||||||
|
DEBUG_FLAGS ?= \
|
||||||
|
$(DEBUG_NETWORK) \
|
||||||
|
$(DEBUG_RADIO) \
|
||||||
|
$(DEBUG_SYSTEM) \
|
||||||
|
$(DEBUG_SERIAL) \
|
||||||
|
$(DEBUG_SENSOR)
|
||||||
|
endif
|
||||||
|
|
36
lib-build/make/Makefile.inc.libs
Normal file
36
lib-build/make/Makefile.inc.libs
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#
|
||||||
|
# Managed libraries versions
|
||||||
|
#
|
||||||
|
|
||||||
|
# Replace libraries with versioned libraries paths.
|
||||||
|
ifneq (,$(findstring spi,$(MASTER_LIBS)))
|
||||||
|
II_SPI = $(ARD_HOME)/hardware/arduino/avr/libraries/SPI
|
||||||
|
endif
|
||||||
|
ifneq (,$(findstring rfm,$(MASTER_LIBS)))
|
||||||
|
II_RFM = ../lib-ext/rfm-69.git
|
||||||
|
endif
|
||||||
|
ifneq (,$(findstring dht,$(MASTER_LIBS)))
|
||||||
|
II_DHT = ../lib-ext/dht.git
|
||||||
|
endif
|
||||||
|
ifneq (,$(findstring ethercard,$(MASTER_LIBS)))
|
||||||
|
II_ETHERCARD = ../lib-ext/ethercard.git
|
||||||
|
endif
|
||||||
|
ifneq (,$(findstring isp-repair,$(MASTER_LIBS)))
|
||||||
|
II_ISP_REPAIR = ../lib/isp-repair
|
||||||
|
endif
|
||||||
|
ifneq (,$(findstring xnode-shared,$(MASTER_LIBS)))
|
||||||
|
II_XNODE_SHARED = ../lib/xnode-shared
|
||||||
|
endif
|
||||||
|
ifneq (,$(findstring xnode-shared-satellite,$(MASTER_LIBS)))
|
||||||
|
II_XNODE_SHARED_SATELLITE = ../lib/xnode-shared-satellite
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Argragate Internal Includes to ROOT_LIBS
|
||||||
|
ROOT_LIBS = \
|
||||||
|
$(II_SPI) \
|
||||||
|
$(II_RFM) \
|
||||||
|
$(II_DHT) \
|
||||||
|
$(II_ETHERCARD) \
|
||||||
|
$(II_ISP_REPAIR) \
|
||||||
|
$(II_XNODE_SHARED) \
|
||||||
|
$(II_XNODE_SHARED_SATELLITE)
|
20
lib-build/make/Makefile.inc.local-template
Normal file
20
lib-build/make/Makefile.inc.local-template
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# Local env included makefile
|
||||||
|
# This file should be ignored in version control
|
||||||
|
# note: the ?= is so you can override those again in cmdline.
|
||||||
|
#
|
||||||
|
# Change to local arduino installation.
|
||||||
|
ARD_HOME ?= /home/willemc/devv/avr/ide/arduino-1.6.0
|
||||||
|
|
||||||
|
# Default port to isp
|
||||||
|
# PORT ?= /dev/ttyACM0
|
||||||
|
|
||||||
|
# Uncomment to have serial debug printing
|
||||||
|
# Supported arguments are: NONE,ALL,NETWORK,RADIO,SYSTEM,SERIAL,SENSOR
|
||||||
|
# DEBUG_LOGGING ?= ALL
|
||||||
|
|
||||||
|
# Uncomment to disable lookup and this this address.
|
||||||
|
# DEBUG_NET_HISIP ?= {10,11,12,177}
|
||||||
|
|
||||||
|
# Only needed in some extreme cases where there is
|
||||||
|
# transparant http proxy filtering in the network...
|
||||||
|
# DEBUG_NET_GATE ?= {10,11,12,177}
|
284
lib-build/make/Makefile.inc.root
Normal file
284
lib-build/make/Makefile.inc.root
Normal file
|
@ -0,0 +1,284 @@
|
||||||
|
#
|
||||||
|
# Copyright 2011 Alan Burlison, alan@bleaklow.com. All rights reserved.
|
||||||
|
# Subsequently modified by Matthieu Weber, matthieu.weber@jyu.fi.
|
||||||
|
# Use is subject to license terms.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions are met:
|
||||||
|
#
|
||||||
|
# 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer.
|
||||||
|
#
|
||||||
|
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer in the documentation
|
||||||
|
# and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY ALAN BURLISON "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||||
|
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||||
|
# EVENT SHALL ALAN BURLISON OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||||
|
# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Changed some code for working without pde/ino files.
|
||||||
|
# Added extra build flag and libary support.
|
||||||
|
# wc, 2014-01-13
|
||||||
|
#
|
||||||
|
# Minor adjustments for Mac OS X and for educational purposes by Maik Schmidt,
|
||||||
|
# contact@maik-schmidt.de.
|
||||||
|
#
|
||||||
|
# Makefile for building Arduino projects outside of the Arduino environment
|
||||||
|
#
|
||||||
|
# This makefile should be included into a per-project Makefile of the following
|
||||||
|
# form:
|
||||||
|
#
|
||||||
|
# ----------
|
||||||
|
# BOARD = mega
|
||||||
|
# PORT = /dev/term/0
|
||||||
|
# INC_DIRS = ../common
|
||||||
|
# LIB_DIRS = ../libraries/Task ../../libraries/VirtualWire
|
||||||
|
# include ../../Makefile.master
|
||||||
|
# ----------
|
||||||
|
#
|
||||||
|
# Where:
|
||||||
|
# BOARD : Arduino board type, from $(ARD_HOME)/hardware/boards.txt
|
||||||
|
# PORT : USB port
|
||||||
|
# INC_DIRS : List pf directories containing header files
|
||||||
|
# LIB_DIRS : List of directories containing library source
|
||||||
|
#
|
||||||
|
# Before using this Makefile you can adjust the following macros to suit
|
||||||
|
# your environment, either by editing this file directly or by defining them in
|
||||||
|
# the Makefile that includes this one, in which case they will override the
|
||||||
|
# definitions below:
|
||||||
|
# ARD_REV : arduino software revision, e.g. 0017, 0018
|
||||||
|
# ARD_HOME : installation directory of the Arduino software.
|
||||||
|
# ARD_BIN : location of compiler binaries
|
||||||
|
# AVRDUDE : location of avrdude executable
|
||||||
|
# AVRDUDE_CONF : location of avrdude configuration file
|
||||||
|
# PROGRAMMER : avrdude programmer type
|
||||||
|
# MON_CMD : serial monitor command
|
||||||
|
# MON_SPEED : serial monitor speed
|
||||||
|
#
|
||||||
|
|
||||||
|
# Global configuration.
|
||||||
|
ARD_REV ?= 0022
|
||||||
|
ARD_HOME ?= /Applications/Arduino.app/Contents/Resources/Java
|
||||||
|
ARD_BIN ?= /usr/local/CrossPack-AVR/bin
|
||||||
|
AVRDUDE ?= $(ARD_HOME)/hardware/tools/avr/bin/avrdude
|
||||||
|
AVRDUDE_CONF ?= $(ARD_HOME)/hardware/tools/avr/etc/avrdude.conf
|
||||||
|
PROGRAMMER ?= stk500v1
|
||||||
|
MON_SPEED ?= 57600
|
||||||
|
MON_CMD ?= picocom
|
||||||
|
PORT ?= /dev/tty.usbserial-A60061a3
|
||||||
|
BOARD ?= atmega328
|
||||||
|
|
||||||
|
### Nothing below here should require editing. ###
|
||||||
|
|
||||||
|
# Check for the required definitions.
|
||||||
|
|
||||||
|
ifndef BOARD
|
||||||
|
$(error $$(BOARD) not defined)
|
||||||
|
endif
|
||||||
|
ifndef PORT
|
||||||
|
$(error $$(PORT) not defined)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Version-specific settings
|
||||||
|
ARD_BOARDS = $(ARD_HOME)/hardware/arduino/avr/boards.txt
|
||||||
|
ARD_SRC_DIR = $(ARD_HOME)/hardware/arduino/avr/cores/arduino
|
||||||
|
ARD_MAIN = $(ARD_SRC_DIR)/main.cpp
|
||||||
|
|
||||||
|
# Standard macros.
|
||||||
|
SKETCH = $(notdir $(CURDIR))
|
||||||
|
BUILD_DIR = build
|
||||||
|
VPATH = $(LIB_DIRS)
|
||||||
|
|
||||||
|
# Macros derived from boards.txt
|
||||||
|
MCU := $(shell sed -n 's/$(BOARD)\.build\.mcu=\(.*\)/\1/p' < $(ARD_BOARDS))
|
||||||
|
F_CPU := $(shell sed -n 's/$(BOARD)\.build\.f_cpu=\(.*\)/\1/p' < $(ARD_BOARDS))
|
||||||
|
UPLOAD_SPEED := \
|
||||||
|
$(shell sed -n 's/$(BOARD)\.upload\.speed=\(.*\)/\1/p' < $(ARD_BOARDS))
|
||||||
|
|
||||||
|
# Build tools.
|
||||||
|
CC = $(ARD_BIN)/avr-gcc
|
||||||
|
CXX = $(ARD_BIN)/avr-g++
|
||||||
|
CXXFILT = $(ARD_BIN)/avr-c++filt
|
||||||
|
OBJCOPY = $(ARD_BIN)/avr-objcopy
|
||||||
|
OBJDUMP = $(ARD_BIN)/avr-objdump
|
||||||
|
AR = $(ARD_BIN)/avr-ar
|
||||||
|
SIZE = $(ARD_BIN)/avr-size
|
||||||
|
NM = $(ARD_BIN)/avr-nm
|
||||||
|
MKDIR = mkdir -p
|
||||||
|
RM = rm -rf
|
||||||
|
MV = mv -f
|
||||||
|
LN = ln -f
|
||||||
|
|
||||||
|
# Compiler flags.
|
||||||
|
INC_FLAGS = \
|
||||||
|
$(addprefix -I,$(INC_DIRS)) $(addprefix -I,$(LIB_DIRS)) -I$(ARD_SRC_DIR)
|
||||||
|
ARD_FLAGS = -mmcu=$(MCU) -DF_CPU=$(F_CPU) -DARDUINO=$(ARD_REV) $(SKETCH_FLAGS)
|
||||||
|
C_CXX_FLAGS = \
|
||||||
|
-Wall -Wextra -Wundef -Wno-unused-parameter \
|
||||||
|
-fdiagnostics-show-option -g -Wa,-adhlns=$(BUILD_DIR)/$*.lst
|
||||||
|
C_FLAGS = \
|
||||||
|
$(C_CXX_FLAGS) -std=gnu99 -Wstrict-prototypes -Wno-old-style-declaration
|
||||||
|
CXX_FLAGS = $(C_CXX_FLAGS)
|
||||||
|
|
||||||
|
# Optimiser flags.
|
||||||
|
# optimise for size, unsigned by default, pack data.
|
||||||
|
# separate sections, drop unused ones, shorten branches, jumps.
|
||||||
|
# don't inline, vectorise loops. no exceptions.
|
||||||
|
# no os preamble, use function calls in prologues.
|
||||||
|
# http://gcc.gnu.org/onlinedocs/gcc-4.3.5/gcc/
|
||||||
|
# http://www.tty1.net/blog/2008-04-29-avr-gcc-optimisations_en.html
|
||||||
|
OPT_FLAGS = \
|
||||||
|
-Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums \
|
||||||
|
-ffunction-sections -fdata-sections -Wl,--gc-sections,--relax \
|
||||||
|
-fno-inline-small-functions -fno-tree-scev-cprop -fno-exceptions \
|
||||||
|
-ffreestanding -mcall-prologues
|
||||||
|
|
||||||
|
# Build parameters.
|
||||||
|
IMAGE = $(BUILD_DIR)/$(SKETCH)
|
||||||
|
ARD_C_SRC = $(wildcard $(ARD_SRC_DIR)/*.c)
|
||||||
|
ARD_CXX_SRC = $(wildcard $(ARD_SRC_DIR)/*.cpp)
|
||||||
|
ARD_C_OBJ = $(patsubst %.c,%.o,$(notdir $(ARD_C_SRC)))
|
||||||
|
ARD_CXX_OBJ = $(patsubst %.cpp,%.o,$(notdir $(ARD_CXX_SRC)))
|
||||||
|
ARD_LIB = arduino
|
||||||
|
ARD_AR = $(BUILD_DIR)/lib$(ARD_LIB).a
|
||||||
|
ARD_AR_OBJ = $(ARD_AR)($(ARD_C_OBJ) $(ARD_CXX_OBJ))
|
||||||
|
ARD_LD_FLAG = -l$(ARD_LIB)
|
||||||
|
|
||||||
|
# Workaround for http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34734
|
||||||
|
$(ARD_AR)(Tone.o) : CXX_FLAGS += -w
|
||||||
|
|
||||||
|
# Sketch libraries.
|
||||||
|
LIB_C_SRC = $(foreach ld,$(LIB_DIRS),$(wildcard $(ld)/*.c))
|
||||||
|
LIB_CXX_SRC = $(foreach ld,$(LIB_DIRS),$(wildcard $(ld)/*.cpp))
|
||||||
|
LIB_SRC = $(LIB_C_SRC) $(LIB_CXX_SRC)
|
||||||
|
ifneq "$(strip $(LIB4_C_SRC) $(LIB_CXX_SRC))" ""
|
||||||
|
LIB_C_OBJ = $(patsubst %.c,%.o,$(notdir $(LIB_C_SRC)))
|
||||||
|
LIB_CXX_OBJ = $(patsubst %.cpp,%.o,$(notdir $(LIB_CXX_SRC)))
|
||||||
|
LIB_LIB = library
|
||||||
|
LIB_AR = $(BUILD_DIR)/lib$(LIB_LIB).a
|
||||||
|
LIB_AR_OBJ = $(LIB_AR)($(LIB_C_OBJ)$(LIB_CXX_OBJ))
|
||||||
|
LIB_LD_FLAG = -l$(LIB_LIB)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Sketch PDE source.
|
||||||
|
# SKT_PDE_SRC = $(wildcard *.pde)
|
||||||
|
#ifneq "$(strip $(SKT_PDE_SRC))" ""
|
||||||
|
# SKT_PDE_OBJ = $(BUILD_DIR)/$(SKETCH)_pde.o
|
||||||
|
#endif
|
||||||
|
SKT_PDE_OBJ = $(patsubst %.cpp,%.o,$(notdir $(SKT_PDE_SRC)))
|
||||||
|
|
||||||
|
# C and C++ source.
|
||||||
|
SKT_C_SRC = $(wildcard *.c)
|
||||||
|
SKT_CXX_SRC = $(wildcard *.cpp)
|
||||||
|
ifneq "$(strip $(SKT_C_SRC) $(SKT_CXX_SRC))" ""
|
||||||
|
SKT_C_OBJ = $(patsubst %.c,%.o,$(SKT_C_SRC))
|
||||||
|
SKT_CXX_OBJ = $(patsubst %.cpp,%.o,$(SKT_CXX_SRC))
|
||||||
|
SKT_LIB = sketch
|
||||||
|
SKT_AR = $(BUILD_DIR)/lib$(SKT_LIB).a
|
||||||
|
SKT_AR_OBJ = $(SKT_AR)($(SKT_C_OBJ) $(SKT_CXX_OBJ))
|
||||||
|
#SKT_AR_OBJ = $(SKT_AR)/($(SKT_C_OBJ) $(SKT_CXX_OBJ)) // mmm: '/' rmed after make 4.0 to work
|
||||||
|
SKT_LD_FLAG = -l$(SKT_LIB)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Definitions.
|
||||||
|
define run-cc
|
||||||
|
@ $(CC) $(ARD_FLAGS) $(INC_FLAGS) -M -MT '$@($%)' -MF $@_$*.dep $<
|
||||||
|
$(CC) -c $(C_FLAGS) $(OPT_FLAGS) $(ARD_FLAGS) $(INC_FLAGS) \
|
||||||
|
$< -o $(BUILD_DIR)/$%
|
||||||
|
@ $(AR) rc $@ $(BUILD_DIR)/$%
|
||||||
|
@ $(RM) $(BUILD_DIR)/$%
|
||||||
|
@ $(CXXFILT) < $(BUILD_DIR)/$*.lst > $(BUILD_DIR)/$*.lst.tmp
|
||||||
|
@ $(MV) $(BUILD_DIR)/$*.lst.tmp $(BUILD_DIR)/$*.lst
|
||||||
|
endef
|
||||||
|
|
||||||
|
define run-cxx
|
||||||
|
@ $(CXX) $(ARD_FLAGS) $(INC_FLAGS) -M -MT '$@($%)' -MF $@_$*.dep $<
|
||||||
|
$(CXX) -c $(CXX_FLAGS) $(OPT_FLAGS) $(ARD_FLAGS) $(INC_FLAGS) \
|
||||||
|
$< -o $(BUILD_DIR)/$%
|
||||||
|
@ $(AR) rc $@ $(BUILD_DIR)/$%
|
||||||
|
@ $(RM) $(BUILD_DIR)/$%
|
||||||
|
@ $(CXXFILT) < $(BUILD_DIR)/$*.lst > $(BUILD_DIR)/$*.lst.tmp
|
||||||
|
@ $(MV) $(BUILD_DIR)/$*.lst.tmp $(BUILD_DIR)/$*.lst
|
||||||
|
endef
|
||||||
|
|
||||||
|
# Rules.
|
||||||
|
.PHONY : all clean upload monitor upload_monitor
|
||||||
|
|
||||||
|
all : $(BUILD_DIR) $(IMAGE).hex
|
||||||
|
|
||||||
|
clean :
|
||||||
|
$(RM) $(BUILD_DIR)
|
||||||
|
|
||||||
|
$(BUILD_DIR) :
|
||||||
|
$(MKDIR) $@
|
||||||
|
|
||||||
|
$(SKT_PDE_OBJ) : $(SKT_PDE_SRC)
|
||||||
|
$(CXX) -c $(CXX_FLAGS) $(OPT_FLAGS) $(ARD_FLAGS) $(INC_FLAGS) \
|
||||||
|
$< -o $(BUILD_DIR)/$(SKT_PDE_OBJ)
|
||||||
|
|
||||||
|
# echo '#include <Arduino.h>' > $(BUILD_DIR)/$(SKETCH)_pde.cpp
|
||||||
|
# echo '#include "$(SKT_PDE_SRC)"' >> $(BUILD_DIR)/$(SKETCH)_pde.cpp
|
||||||
|
# $(LN) $(SKT_PDE_SRC) $(BUILD_DIR)/$(SKT_PDE_SRC)
|
||||||
|
# cd $(BUILD_DIR) && ../$(CXX) -c $(subst build/,,$(CXX_FLAGS)) \
|
||||||
|
# $(OPT_FLAGS) $(ARD_FLAGS) -I.. \
|
||||||
|
# $(patsubst -I..%,-I../..%,$(INC_FLAGS)) \
|
||||||
|
# $(SKETCH)_pde.cpp -o $(@F)
|
||||||
|
|
||||||
|
|
||||||
|
(%.o) : $(ARD_SRC_DIR)/%.c
|
||||||
|
$(run-cc)
|
||||||
|
|
||||||
|
(%.o) : $(ARD_SRC_DIR)/%.cpp
|
||||||
|
$(run-cxx)
|
||||||
|
|
||||||
|
(%.o) : %.c
|
||||||
|
$(run-cc)
|
||||||
|
|
||||||
|
(%.o) : %.cpp
|
||||||
|
$(run-cxx)
|
||||||
|
|
||||||
|
# not used
|
||||||
|
#$(BUILD_DIR)/%.d %.c
|
||||||
|
# $(run-cc-d)
|
||||||
|
#
|
||||||
|
#$(BUILD_DIR)/%.d %.cpp
|
||||||
|
# $(run-cxx-d)
|
||||||
|
|
||||||
|
#build/libsketch.a build/libarduino.a
|
||||||
|
$(IMAGE).hex : $(ARD_AR_OBJ) $(LIB_AR_OBJ) $(SKT_AR_OBJ) $(SKT_PDE_OBJ)
|
||||||
|
$(CC) $(CXX_FLAGS) $(OPT_FLAGS) $(ARD_FLAGS) -L$(BUILD_DIR) \
|
||||||
|
$(BUILD_DIR)/$(SKT_PDE_OBJ) $(SKT_LD_FLAG) $(LIB_LD_FLAG) $(ARD_LD_FLAG) -lm \
|
||||||
|
-o $(IMAGE).elf
|
||||||
|
$(OBJCOPY) -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load \
|
||||||
|
--no-change-warnings --change-section-lma .eeprom=0 $(IMAGE).elf \
|
||||||
|
$(IMAGE).eep
|
||||||
|
$(OBJCOPY) -O ihex -R .eeprom $(IMAGE).elf $(IMAGE).hex
|
||||||
|
$(OBJDUMP) -h -S $(IMAGE).elf | $(CXXFILT) -t > $(IMAGE).lst
|
||||||
|
$(SIZE) $(IMAGE).hex
|
||||||
|
|
||||||
|
# START:makemods
|
||||||
|
upload : all
|
||||||
|
- pkill -f '$(MON_CMD).*$(PORT)'
|
||||||
|
- sleep 1
|
||||||
|
- stty -f $(PORT) hupcl
|
||||||
|
- $(AVRDUDE) -V -C$(AVRDUDE_CONF) -p$(MCU) -c$(PROGRAMMER) \
|
||||||
|
-P$(PORT) -b$(UPLOAD_SPEED) -D -Uflash:w:$(IMAGE).hex:i
|
||||||
|
|
||||||
|
monitor :
|
||||||
|
$(MON_CMD) $(PORT) $(MON_SPEED)
|
||||||
|
# END:makemods
|
||||||
|
|
||||||
|
upload_monitor : upload monitor
|
||||||
|
|
||||||
|
-include $(wildcard $(BUILD_DIR)/*.dep))
|
||||||
|
|
||||||
|
# vim:ft=make
|
50
lib-build/make/Makefile.master
Normal file
50
lib-build/make/Makefile.master
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
# Include this makefile per project
|
||||||
|
#
|
||||||
|
# Optional parameters;
|
||||||
|
# MASTER_LIBS = Simple library name list.
|
||||||
|
# MASTER_INC_DIRS = hook to include extra header files.
|
||||||
|
# MASTER_LIB_DIRS = hook to include extra libraries.
|
||||||
|
# MASTER_FLAGS = hook for extra build flags
|
||||||
|
#
|
||||||
|
|
||||||
|
ifndef SKT_PDE_SRC
|
||||||
|
$(error $$(SKT_PDE_SRC) not defined)
|
||||||
|
endif
|
||||||
|
|
||||||
|
THIS_PATH = ../lib-build/make/
|
||||||
|
INC_LOCAL = .
|
||||||
|
|
||||||
|
# Optional include an local override
|
||||||
|
-include $(THIS_PATH)/Makefile.inc.local
|
||||||
|
|
||||||
|
# Copy debug ips
|
||||||
|
ifdef DEBUG_NET_HISIP
|
||||||
|
DEBUG_NET_FLAG_HISIP = -DDEBUG_NET_HISIP=$(DEBUG_NET_HISIP)
|
||||||
|
endif
|
||||||
|
ifdef DEBUG_NET_GATE
|
||||||
|
DEBUG_NET_FLAG_GATE = -DDEBUG_NET_GATE=$(DEBUG_NET_GATE)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Add some normal defaults for root makefile
|
||||||
|
ARD_REV ?= 105
|
||||||
|
ARD_BIN ?= $(ARD_HOME)/hardware/tools/avr/bin
|
||||||
|
AVRDUDE ?= $(ARD_HOME)/hardware/tools/avr/bin/avrdude
|
||||||
|
AVRDUDE_CONF ?= $(ARD_HOME)/hardware/tools/avr/etc/avrdude.conf
|
||||||
|
BOARD ?= uno
|
||||||
|
PORT ?= /dev/ttyACM0
|
||||||
|
PROGRAMMER ?= arduino
|
||||||
|
MON_SPEED ?= 115200
|
||||||
|
MON_CMD ?= picocom
|
||||||
|
ROOT_INCS = $(ARD_HOME)/hardware/arduino/avr/variants/standard/
|
||||||
|
|
||||||
|
# Include managed build parameters
|
||||||
|
include $(THIS_PATH)/Makefile.inc.debug
|
||||||
|
include $(THIS_PATH)/Makefile.inc.libs
|
||||||
|
|
||||||
|
# Create build dirs for root makefile
|
||||||
|
INC_DIRS = $(MASTER_INC_DIRS) $(ROOT_INCS) $(INC_LOCAL)
|
||||||
|
LIB_DIRS = $(MASTER_LIB_DIRS) $(ROOT_LIBS)
|
||||||
|
SKETCH_FLAGS = $(MASTER_FLAGS) $(DEBUG_NET_FLAG_HISIP) $(DEBUG_NET_FLAG_GATE) $(DEBUG_FLAGS)
|
||||||
|
|
||||||
|
# Include the root parent makefile
|
||||||
|
include $(THIS_PATH)/Makefile.inc.root
|
45
lib-build/make/Makefile.master-flash
Normal file
45
lib-build/make/Makefile.master-flash
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
# Master makefile to flash tool projects
|
||||||
|
#
|
||||||
|
# Parameter;
|
||||||
|
# MASTER_FLASH_PROG = The hex file to flash
|
||||||
|
#
|
||||||
|
# Option Parameter;
|
||||||
|
# MASTER_FLASH_BOOT = The bootloader to flash
|
||||||
|
# MASTER_FLASH_PAIR_EXTRA = extra pair list of hex files to flash,
|
||||||
|
# note where the keyword optiboot get replaced by the optiboot hex file.
|
||||||
|
#
|
||||||
|
|
||||||
|
ifndef MASTER_FLASH_PROG
|
||||||
|
$(error $$(MASTER_FLASH_PROG) not defined)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Define libary includes
|
||||||
|
MASTER_LIBS = isp-repair
|
||||||
|
|
||||||
|
# Include our master
|
||||||
|
include ../lib-build/make/Makefile.master
|
||||||
|
|
||||||
|
HEX_FILE_BOOT_OPTI = $(ARD_HOME)/hardware/arduino/avr/bootloaders/optiboot/optiboot_atmega328.hex
|
||||||
|
HEX_FILE_BLINK_TEST = ../xnode-test-blink/build/xnode-test-blink.hex
|
||||||
|
|
||||||
|
# Define local variables
|
||||||
|
HEX2C = tclsh ../lib-build/tools/mega-hex2c.tcl
|
||||||
|
HEX_DATA = xnode-flashdata.generated
|
||||||
|
HEX_PAIR_BLINK = $(HEX_FILE_BOOT_OPTI) $(HEX_FILE_BLINK_TEST)
|
||||||
|
MASTER_FLASH_BOOT ?= $(HEX_FILE_BOOT_OPTI)
|
||||||
|
HEX_PAIR_MASTER = $(MASTER_FLASH_BOOT) $(MASTER_FLASH_PROG)
|
||||||
|
HEX_PAIR_EXTRA = $(subst optiboot,$(HEX_FILE_BOOT_OPTI),$(MASTER_FLASH_PAIR_EXTRA))
|
||||||
|
HEX_PAIR_LIST = $(HEX_PAIR_BLINK) $(HEX_PAIR_MASTER) $(HEX_PAIR_EXTRA)
|
||||||
|
|
||||||
|
# Hook in our local extra build targets
|
||||||
|
clean : clean-hex
|
||||||
|
$(BUILD_DIR) : $(HEX_DATA)
|
||||||
|
|
||||||
|
# Generate flashdata before compiling
|
||||||
|
$(HEX_DATA) :
|
||||||
|
$(HEX2C) $(HEX_PAIR_LIST) > $(HEX_DATA)
|
||||||
|
|
||||||
|
clean-hex :
|
||||||
|
$(RM) $(HEX_DATA)
|
||||||
|
|
||||||
|
|
86
lib-build/tools/mega-hex2c.tcl
Normal file
86
lib-build/tools/mega-hex2c.tcl
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
#!/usr/bin/env tclsh
|
||||||
|
|
||||||
|
# Changed to byte array per file with index struct for mega version
|
||||||
|
# wc, 2014-01-13
|
||||||
|
|
||||||
|
# Generate a C include file from one or more Intel HEX files (avr-gcc output)
|
||||||
|
# jcw, 2010-04-18
|
||||||
|
|
||||||
|
# Examples:
|
||||||
|
# ./hex2c.tcl Blink.cpp.hex ATmegaBOOT_168_atmega328.hex >data_blink.h
|
||||||
|
# ./hex2c.tcl RF12demo.cpp.hex ATmegaBOOT_168_atmega328.hex >data_rf12demo.h
|
||||||
|
# ./hex2c.tcl Blink.cpp.hex optiboot_atmega328.hex >opti_blink.h
|
||||||
|
# ./hex2c.tcl RF12demo.cpp.hex optiboot_atmega328.hex >opti_rf12demo.h
|
||||||
|
|
||||||
|
if {$argv eq ""} {
|
||||||
|
puts stderr "Usage: [info script] infile.hex ?...? >outfile.h"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
set bytes {}
|
||||||
|
set psi 0
|
||||||
|
foreach a $argv {
|
||||||
|
set start [llength $bytes]
|
||||||
|
set mtime [clock format [file mtime $a] -format "%Y-%m-%d"]
|
||||||
|
puts stderr $a:
|
||||||
|
set fd [open $a]
|
||||||
|
while {[gets $fd line] > 0} {
|
||||||
|
if {[scan $line {:%2x%4x%2x%s} count addr type data]} {
|
||||||
|
if {$type == 0} {
|
||||||
|
if {![info exists next]} {
|
||||||
|
set first [format 0x%04X $addr]
|
||||||
|
set next $addr
|
||||||
|
}
|
||||||
|
while {$next < $addr} {
|
||||||
|
lappend bytes 255 ;# pad with unset bytes if there is a gap
|
||||||
|
incr next
|
||||||
|
}
|
||||||
|
if {$next != $addr} {
|
||||||
|
puts stderr "non-contiguous data ($next vs $addr)"
|
||||||
|
}
|
||||||
|
incr next $count
|
||||||
|
foreach {x y} [split [string range $data 0 end-2] ""] {
|
||||||
|
lappend bytes [scan $x$y %x]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
incr next -$first
|
||||||
|
set f [format %-30s [file tail $a]]
|
||||||
|
lappend sections "\"$f\",\"$mtime\",progdata_$psi,$first,$start,$next"
|
||||||
|
#lappend sections "\"$mtime $f ${next}b @ $first\",$first,$start,$next"
|
||||||
|
unset next
|
||||||
|
close $fd
|
||||||
|
|
||||||
|
lappend byte_sections $bytes
|
||||||
|
set bytes {}
|
||||||
|
incr psi
|
||||||
|
}
|
||||||
|
|
||||||
|
puts "// This file was generated by hex2c.tcl on [clock format [clock seconds]]"
|
||||||
|
puts ""
|
||||||
|
puts ""
|
||||||
|
|
||||||
|
set pgi 0
|
||||||
|
foreach bs $byte_sections {
|
||||||
|
puts "const unsigned char progdata_$pgi\[] PROGMEM = {"
|
||||||
|
set out " "
|
||||||
|
foreach x $bs {
|
||||||
|
if {[string length $out$x,] > 80} {
|
||||||
|
puts $out
|
||||||
|
set out " "
|
||||||
|
}
|
||||||
|
append out $x ,
|
||||||
|
}
|
||||||
|
puts $out
|
||||||
|
puts "};"
|
||||||
|
incr pgi
|
||||||
|
}
|
||||||
|
|
||||||
|
puts ""
|
||||||
|
puts "mega_flash_data_struct sections\[] = {"
|
||||||
|
foreach x $sections {
|
||||||
|
puts " {$x},"
|
||||||
|
}
|
||||||
|
puts "};"
|
||||||
|
puts ""
|
171
lib-build/tools/xxtea.c
Normal file
171
lib-build/tools/xxtea.c
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define DELTA 0x9e3779b9
|
||||||
|
#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))
|
||||||
|
|
||||||
|
void btea(uint32_t *v, int n, uint32_t const key[4]) {
|
||||||
|
uint32_t y, z, sum;
|
||||||
|
unsigned p, rounds, e;
|
||||||
|
if (n > 1) { /* Coding Part */
|
||||||
|
rounds = 6 + 52/n;
|
||||||
|
sum = 0;
|
||||||
|
z = v[n-1];
|
||||||
|
do {
|
||||||
|
sum += DELTA;
|
||||||
|
e = (sum >> 2) & 3;
|
||||||
|
for (p=0; p<n-1; p++) {
|
||||||
|
y = v[p+1];
|
||||||
|
z = v[p] += MX;
|
||||||
|
}
|
||||||
|
y = v[0];
|
||||||
|
z = v[n-1] += MX;
|
||||||
|
} while (--rounds);
|
||||||
|
} else if (n < -1) { /* Decoding Part */
|
||||||
|
n = -n;
|
||||||
|
rounds = 6 + 52/n;
|
||||||
|
sum = rounds*DELTA;
|
||||||
|
y = v[0];
|
||||||
|
do {
|
||||||
|
e = (sum >> 2) & 3;
|
||||||
|
for (p=n-1; p>0; p--) {
|
||||||
|
z = v[p-1];
|
||||||
|
y = v[p] -= MX;
|
||||||
|
}
|
||||||
|
z = v[n-1];
|
||||||
|
y = v[0] -= MX;
|
||||||
|
sum -= DELTA;
|
||||||
|
} while (--rounds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void convToQU32(uint32_t *v/*, int n*/,int *data,int dataOffset) {
|
||||||
|
for (int i=0;i<4;i++) {
|
||||||
|
int idx = dataOffset + i*4;
|
||||||
|
//uint32_t value = (data[idx]) + (data[idx+1] << 8) + (data[idx+2] << 16) + (data[idx+3] << 24);
|
||||||
|
uint32_t value = (data[idx+3]) + (data[idx+2] << 8) + (data[idx+1] << 16) + (data[idx+0] << 24);
|
||||||
|
printf("convToQU32 %08x \n", value);
|
||||||
|
v[i] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define XXTEA_NUM_ROUNDS 32
|
||||||
|
void xxteaDecrypt(unsigned long v[2],unsigned long net_key[4])
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
uint32_t v0=v[0], v1=v[1], delta=0x9E3779B9, sum=delta*XXTEA_NUM_ROUNDS;
|
||||||
|
for (i=0; i < XXTEA_NUM_ROUNDS; i++) {
|
||||||
|
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + net_key[(sum>>11) & 3]);
|
||||||
|
sum -= delta;
|
||||||
|
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + net_key[sum & 3]);
|
||||||
|
}
|
||||||
|
v[0]=v0; v[1]=v1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main (int argc, char *argv[] ) {
|
||||||
|
// Arguments parsing
|
||||||
|
if ( argc != 4 ) {
|
||||||
|
printf( "usage: %s encrypt|decrypt key message\n", argv[0] ); // prog name
|
||||||
|
printf( "note: parameters are pure hex and key should be 32 chars. \n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
int operation = 0;
|
||||||
|
if (strcmp("encrypt", argv[1]) == 0) {
|
||||||
|
operation = 1;
|
||||||
|
}
|
||||||
|
if (strcmp("decrypt", argv[1]) == 0) {
|
||||||
|
operation = -1;
|
||||||
|
}
|
||||||
|
if (operation == 0) {
|
||||||
|
printf( "Could not parse first argument.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
printf( "operation: %d.\n",operation);
|
||||||
|
char* keyBuffer = argv[2];
|
||||||
|
int keyBufferLength = strlen(keyBuffer);
|
||||||
|
if (keyBufferLength != 32) {
|
||||||
|
printf( "key should by 32 chars.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
char* messageBuffer = argv[3];
|
||||||
|
int messageBufferLength = strlen(messageBuffer);
|
||||||
|
if (messageBufferLength < 16) {
|
||||||
|
printf( "message should be minimal 16 chars.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
// Done arguments
|
||||||
|
|
||||||
|
// Convert data
|
||||||
|
int keyData[16];
|
||||||
|
int keyDataIndex = 0;
|
||||||
|
for (int i=0;i<keyBufferLength/2;i++) {
|
||||||
|
int value;
|
||||||
|
sscanf(keyBuffer+2*i,"%02x",&value);
|
||||||
|
keyData[keyDataIndex] = value;
|
||||||
|
keyDataIndex++;
|
||||||
|
}
|
||||||
|
printf( "Key data size %d\n", keyDataIndex );
|
||||||
|
for (int i=0;i<keyDataIndex;i++) {
|
||||||
|
printf( "%02x", keyData[i] );
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
int messageData[512];
|
||||||
|
int messageDataIndex = 0;
|
||||||
|
for (int i=0;i<512;i++) {
|
||||||
|
messageData[i] = 0;
|
||||||
|
}
|
||||||
|
for (int i=0;i<messageBufferLength/2;i++) {
|
||||||
|
int value;
|
||||||
|
sscanf(messageBuffer+2*i,"%02x",&value);
|
||||||
|
messageData[messageDataIndex] = value;
|
||||||
|
messageDataIndex++;
|
||||||
|
}
|
||||||
|
printf( "Message data size %d\n", messageDataIndex );
|
||||||
|
for (int i=0;i<messageDataIndex;i++) {
|
||||||
|
printf( "%02x", messageData[i] );
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
uint32_t key[4];
|
||||||
|
uint32_t data[4];
|
||||||
|
|
||||||
|
convToQU32(key,keyData,0);
|
||||||
|
convToQU32(data,messageData,0);
|
||||||
|
|
||||||
|
printf("OUT-ppre: ");
|
||||||
|
for (int i=0;i<4;i++) {
|
||||||
|
printf("%08x", data[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
operation = operation* (messageDataIndex/4);
|
||||||
|
printf( "word length: %d\n",operation);
|
||||||
|
|
||||||
|
//btea(data,operation,key);
|
||||||
|
xxteaDecrypt(data,key);
|
||||||
|
|
||||||
|
printf("OUT-post: ");
|
||||||
|
for (int i=0;i<4;i++) {
|
||||||
|
printf("%08x", data[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
printf("OUT-AS: ");
|
||||||
|
for (int i=0;i<4;i++) {
|
||||||
|
//printf("%02x ", data[i] & 255);
|
||||||
|
//printf("%02x ", data[i] >> 8 & 255);
|
||||||
|
//printf("%02x ", data[i] >> 16 & 255);
|
||||||
|
//printf("%02x ", data[i] >> 24 & 255);
|
||||||
|
|
||||||
|
printf("%c ", data[i] & 255);
|
||||||
|
printf("%c ", data[i] >> 8 & 255);
|
||||||
|
printf("%c ", data[i] >> 16 & 255);
|
||||||
|
printf("%c ", data[i] >> 24 & 255);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
return 0;
|
||||||
|
}
|
179
lib-ext/dht.git/DHT.cpp
Normal file
179
lib-ext/dht.git/DHT.cpp
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
/* DHT library
|
||||||
|
|
||||||
|
MIT license
|
||||||
|
written by Adafruit Industries
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "DHT.h"
|
||||||
|
|
||||||
|
DHT::DHT(uint8_t pin, uint8_t type, uint8_t count) {
|
||||||
|
_pin = pin;
|
||||||
|
_type = type;
|
||||||
|
_count = count;
|
||||||
|
firstreading = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DHT::begin(void) {
|
||||||
|
// set up the pins!
|
||||||
|
pinMode(_pin, INPUT);
|
||||||
|
digitalWrite(_pin, HIGH);
|
||||||
|
_lastreadtime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//boolean S == Scale. True == Farenheit; False == Celcius
|
||||||
|
float DHT::readTemperature(bool S) {
|
||||||
|
float f;
|
||||||
|
|
||||||
|
if (read()) {
|
||||||
|
switch (_type) {
|
||||||
|
case DHT11:
|
||||||
|
f = data[2];
|
||||||
|
if(S)
|
||||||
|
f = convertCtoF(f);
|
||||||
|
|
||||||
|
return f;
|
||||||
|
case DHT22:
|
||||||
|
case DHT21:
|
||||||
|
f = data[2] & 0x7F;
|
||||||
|
f *= 256;
|
||||||
|
f += data[3];
|
||||||
|
f /= 10;
|
||||||
|
if (data[2] & 0x80)
|
||||||
|
f *= -1;
|
||||||
|
if(S)
|
||||||
|
f = convertCtoF(f);
|
||||||
|
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
float DHT::convertCtoF(float c) {
|
||||||
|
return c * 9 / 5 + 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
float DHT::convertFtoC(float f) {
|
||||||
|
return (f - 32) * 5 / 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
float DHT::readHumidity(void) {
|
||||||
|
float f;
|
||||||
|
if (read()) {
|
||||||
|
switch (_type) {
|
||||||
|
case DHT11:
|
||||||
|
f = data[0];
|
||||||
|
return f;
|
||||||
|
case DHT22:
|
||||||
|
case DHT21:
|
||||||
|
f = data[0];
|
||||||
|
f *= 256;
|
||||||
|
f += data[1];
|
||||||
|
f /= 10;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
float DHT::computeHeatIndex(float tempFahrenheit, float percentHumidity) {
|
||||||
|
// Adapted from equation at: https://github.com/adafruit/DHT-sensor-library/issues/9 and
|
||||||
|
// Wikipedia: http://en.wikipedia.org/wiki/Heat_index
|
||||||
|
return -42.379 +
|
||||||
|
2.04901523 * tempFahrenheit +
|
||||||
|
10.14333127 * percentHumidity +
|
||||||
|
-0.22475541 * tempFahrenheit*percentHumidity +
|
||||||
|
-0.00683783 * pow(tempFahrenheit, 2) +
|
||||||
|
-0.05481717 * pow(percentHumidity, 2) +
|
||||||
|
0.00122874 * pow(tempFahrenheit, 2) * percentHumidity +
|
||||||
|
0.00085282 * tempFahrenheit*pow(percentHumidity, 2) +
|
||||||
|
-0.00000199 * pow(tempFahrenheit, 2) * pow(percentHumidity, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
boolean DHT::read(void) {
|
||||||
|
uint8_t laststate = HIGH;
|
||||||
|
uint8_t counter = 0;
|
||||||
|
uint8_t j = 0, i;
|
||||||
|
unsigned long currenttime;
|
||||||
|
|
||||||
|
// Check if sensor was read less than two seconds ago and return early
|
||||||
|
// to use last reading.
|
||||||
|
currenttime = millis();
|
||||||
|
if (currenttime < _lastreadtime) {
|
||||||
|
// ie there was a rollover
|
||||||
|
_lastreadtime = 0;
|
||||||
|
}
|
||||||
|
if (!firstreading && ((currenttime - _lastreadtime) < 2000)) {
|
||||||
|
return true; // return last correct measurement
|
||||||
|
//delay(2000 - (currenttime - _lastreadtime));
|
||||||
|
}
|
||||||
|
firstreading = false;
|
||||||
|
/*
|
||||||
|
Serial.print("Currtime: "); Serial.print(currenttime);
|
||||||
|
Serial.print(" Lasttime: "); Serial.print(_lastreadtime);
|
||||||
|
*/
|
||||||
|
_lastreadtime = millis();
|
||||||
|
|
||||||
|
data[0] = data[1] = data[2] = data[3] = data[4] = 0;
|
||||||
|
|
||||||
|
// pull the pin high and wait 250 milliseconds
|
||||||
|
digitalWrite(_pin, HIGH);
|
||||||
|
delay(250);
|
||||||
|
|
||||||
|
// now pull it low for ~20 milliseconds
|
||||||
|
pinMode(_pin, OUTPUT);
|
||||||
|
digitalWrite(_pin, LOW);
|
||||||
|
delay(20);
|
||||||
|
noInterrupts();
|
||||||
|
digitalWrite(_pin, HIGH);
|
||||||
|
delayMicroseconds(40);
|
||||||
|
pinMode(_pin, INPUT);
|
||||||
|
|
||||||
|
// read in timings
|
||||||
|
for ( i=0; i< MAXTIMINGS; i++) {
|
||||||
|
counter = 0;
|
||||||
|
while (digitalRead(_pin) == laststate) {
|
||||||
|
counter++;
|
||||||
|
delayMicroseconds(1);
|
||||||
|
if (counter == 255) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
laststate = digitalRead(_pin);
|
||||||
|
|
||||||
|
if (counter == 255) break;
|
||||||
|
|
||||||
|
// ignore first 3 transitions
|
||||||
|
if ((i >= 4) && (i%2 == 0)) {
|
||||||
|
// shove each bit into the storage bytes
|
||||||
|
data[j/8] <<= 1;
|
||||||
|
if (counter > _count)
|
||||||
|
data[j/8] |= 1;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
interrupts();
|
||||||
|
|
||||||
|
/*
|
||||||
|
Serial.println(j, DEC);
|
||||||
|
Serial.print(data[0], HEX); Serial.print(", ");
|
||||||
|
Serial.print(data[1], HEX); Serial.print(", ");
|
||||||
|
Serial.print(data[2], HEX); Serial.print(", ");
|
||||||
|
Serial.print(data[3], HEX); Serial.print(", ");
|
||||||
|
Serial.print(data[4], HEX); Serial.print(" =? ");
|
||||||
|
Serial.println(data[0] + data[1] + data[2] + data[3], HEX);
|
||||||
|
*/
|
||||||
|
|
||||||
|
// check we read 40 bits and that the checksum matches
|
||||||
|
if ((j >= 40) &&
|
||||||
|
(data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
41
lib-ext/dht.git/DHT.h
Normal file
41
lib-ext/dht.git/DHT.h
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#ifndef DHT_H
|
||||||
|
#define DHT_H
|
||||||
|
#if ARDUINO >= 100
|
||||||
|
#include "Arduino.h"
|
||||||
|
#else
|
||||||
|
#include "WProgram.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* DHT library
|
||||||
|
|
||||||
|
MIT license
|
||||||
|
written by Adafruit Industries
|
||||||
|
*/
|
||||||
|
|
||||||
|
// how many timing transitions we need to keep track of. 2 * number bits + extra
|
||||||
|
#define MAXTIMINGS 85
|
||||||
|
|
||||||
|
#define DHT11 11
|
||||||
|
#define DHT22 22
|
||||||
|
#define DHT21 21
|
||||||
|
#define AM2301 21
|
||||||
|
|
||||||
|
class DHT {
|
||||||
|
private:
|
||||||
|
uint8_t data[6];
|
||||||
|
uint8_t _pin, _type, _count;
|
||||||
|
unsigned long _lastreadtime;
|
||||||
|
boolean firstreading;
|
||||||
|
|
||||||
|
public:
|
||||||
|
DHT(uint8_t pin, uint8_t type, uint8_t count=6);
|
||||||
|
void begin(void);
|
||||||
|
float readTemperature(bool S=false);
|
||||||
|
float convertCtoF(float);
|
||||||
|
float convertFtoC(float);
|
||||||
|
float computeHeatIndex(float tempFahrenheit, float percentHumidity);
|
||||||
|
float readHumidity(void);
|
||||||
|
boolean read(void);
|
||||||
|
|
||||||
|
};
|
||||||
|
#endif
|
3
lib-ext/dht.git/README.txt
Normal file
3
lib-ext/dht.git/README.txt
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
This is an Arduino library for the DHT series of low cost temperature/humidity sensors.
|
||||||
|
|
||||||
|
To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder DHT. Check that the DHT folder contains DHT.cpp and DHT.h. Place the DHT library folder your <arduinosketchfolder>/libraries/ folder. You may need to create the libraries subfolder if its your first library. Restart the IDE.
|
71
lib-ext/dht.git/examples/DHTtester/DHTtester.ino
Normal file
71
lib-ext/dht.git/examples/DHTtester/DHTtester.ino
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
// Example testing sketch for various DHT humidity/temperature sensors
|
||||||
|
// Written by ladyada, public domain
|
||||||
|
|
||||||
|
#include "DHT.h"
|
||||||
|
|
||||||
|
#define DHTPIN 2 // what pin we're connected to
|
||||||
|
|
||||||
|
// Uncomment whatever type you're using!
|
||||||
|
//#define DHTTYPE DHT11 // DHT 11
|
||||||
|
#define DHTTYPE DHT22 // DHT 22 (AM2302)
|
||||||
|
//#define DHTTYPE DHT21 // DHT 21 (AM2301)
|
||||||
|
|
||||||
|
// Connect pin 1 (on the left) of the sensor to +5V
|
||||||
|
// NOTE: If using a board with 3.3V logic like an Arduino Due connect pin 1
|
||||||
|
// to 3.3V instead of 5V!
|
||||||
|
// Connect pin 2 of the sensor to whatever your DHTPIN is
|
||||||
|
// Connect pin 4 (on the right) of the sensor to GROUND
|
||||||
|
// Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor
|
||||||
|
|
||||||
|
// Initialize DHT sensor for normal 16mhz Arduino
|
||||||
|
DHT dht(DHTPIN, DHTTYPE);
|
||||||
|
// NOTE: For working with a faster chip, like an Arduino Due or Teensy, you
|
||||||
|
// might need to increase the threshold for cycle counts considered a 1 or 0.
|
||||||
|
// You can do this by passing a 3rd parameter for this threshold. It's a bit
|
||||||
|
// of fiddling to find the right value, but in general the faster the CPU the
|
||||||
|
// higher the value. The default for a 16mhz AVR is a value of 6. For an
|
||||||
|
// Arduino Due that runs at 84mhz a value of 30 works.
|
||||||
|
// Example to initialize DHT sensor for Arduino Due:
|
||||||
|
//DHT dht(DHTPIN, DHTTYPE, 30);
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
Serial.println("DHTxx test!");
|
||||||
|
|
||||||
|
dht.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// Wait a few seconds between measurements.
|
||||||
|
delay(2000);
|
||||||
|
|
||||||
|
// Reading temperature or humidity takes about 250 milliseconds!
|
||||||
|
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
|
||||||
|
float h = dht.readHumidity();
|
||||||
|
// Read temperature as Celsius
|
||||||
|
float t = dht.readTemperature();
|
||||||
|
// Read temperature as Fahrenheit
|
||||||
|
float f = dht.readTemperature(true);
|
||||||
|
|
||||||
|
// Check if any reads failed and exit early (to try again).
|
||||||
|
if (isnan(h) || isnan(t) || isnan(f)) {
|
||||||
|
Serial.println("Failed to read from DHT sensor!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute heat index
|
||||||
|
// Must send in temp in Fahrenheit!
|
||||||
|
float hi = dht.computeHeatIndex(f, h);
|
||||||
|
|
||||||
|
Serial.print("Humidity: ");
|
||||||
|
Serial.print(h);
|
||||||
|
Serial.print(" %\t");
|
||||||
|
Serial.print("Temperature: ");
|
||||||
|
Serial.print(t);
|
||||||
|
Serial.print(" *C ");
|
||||||
|
Serial.print(f);
|
||||||
|
Serial.print(" *F\t");
|
||||||
|
Serial.print("Heat index: ");
|
||||||
|
Serial.print(hi);
|
||||||
|
Serial.println(" *F");
|
||||||
|
}
|
3
lib-ext/ethercard.git/.gitignore
vendored
Normal file
3
lib-ext/ethercard.git/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
.DS_Store
|
||||||
|
*.esproj
|
||||||
|
/html
|
22
lib-ext/ethercard.git/CONTRIBUTING.md
Normal file
22
lib-ext/ethercard.git/CONTRIBUTING.md
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
Contributing to EtherCard
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Contributions to the EtherCard codebase are welcome using the usual Github pull request workflow.
|
||||||
|
|
||||||
|
Please remember that memory, particularly RAM, is often limited on Arduino, so try and be efficient when adding new features.
|
||||||
|
|
||||||
|
|
||||||
|
Code Style
|
||||||
|
----------
|
||||||
|
|
||||||
|
When making contributions, please use the following code style to keep the codebase consistent:
|
||||||
|
|
||||||
|
* Indent using *4 spaces* not tabs
|
||||||
|
* When placing an opening brace on the same line, there should be one space before it
|
||||||
|
* Closing braces should be broken from the preceding line
|
||||||
|
|
||||||
|
If in doubt, this is the same as the default [astyle] settings, so use the astyle tool to check your code.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[astyle]: http://astyle.sourceforge.net/
|
1923
lib-ext/ethercard.git/Doxyfile
Normal file
1923
lib-ext/ethercard.git/Doxyfile
Normal file
File diff suppressed because it is too large
Load diff
BIN
lib-ext/ethercard.git/Doxylogo.png
Normal file
BIN
lib-ext/ethercard.git/Doxylogo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.5 KiB |
73
lib-ext/ethercard.git/Doxymods.css
Normal file
73
lib-ext/ethercard.git/Doxymods.css
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
/* Get rid of all those overriden font families */
|
||||||
|
body, table, div, p, dl,
|
||||||
|
#projectname,
|
||||||
|
#projectbrief,
|
||||||
|
#nav-tree .label {
|
||||||
|
font: 15px/21px Georgia,serif
|
||||||
|
}
|
||||||
|
|
||||||
|
#projectname {
|
||||||
|
color: #990000;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#titlearea table {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
dl.reflist dt, div.memproto {
|
||||||
|
border: 1px solid #A8B8D9;
|
||||||
|
}
|
||||||
|
|
||||||
|
dl.reflist dd, div.memdoc {
|
||||||
|
border-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.contents {
|
||||||
|
margin-left: 20px; margin-right: 16px;
|
||||||
|
width: 700 px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get rid of the gradient backgrounds and background colors */
|
||||||
|
div.header,
|
||||||
|
#nav-tree,
|
||||||
|
.navpath ul,
|
||||||
|
.memproto, dl.reflist dt {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
#nav-tree .selected {
|
||||||
|
background: none;
|
||||||
|
background-color: #990000;
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a, a:link, a:visited {
|
||||||
|
color: #2A5685;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
a:active, a:hover {
|
||||||
|
color: #CC0000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.directory tr.even,
|
||||||
|
pre.fragment,
|
||||||
|
.mdescLeft, .mdescRight, .memItemLeft, .memItemRight, .memTemplItemLeft, .memTemplItemRight, .memTemplParams,
|
||||||
|
.memproto, dl.reflist dt {
|
||||||
|
background-color: #EEE;
|
||||||
|
box-shadow: none;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
.memdoc, dl.reflist dd {
|
||||||
|
background: none;
|
||||||
|
box-shadow: none;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
pre.fragment {
|
||||||
|
background-color: #FAFAFA;
|
||||||
|
border: 1px solid #DADADA;
|
||||||
|
margin: 1em 1em 1em 1.6em;
|
||||||
|
overflow-x: auto;
|
||||||
|
overflow-y: hidden;
|
||||||
|
width: auto;
|
||||||
|
}
|
416
lib-ext/ethercard.git/EtherCard.cpp
Normal file
416
lib-ext/ethercard.git/EtherCard.cpp
Normal file
|
@ -0,0 +1,416 @@
|
||||||
|
// This code slightly follows the conventions of, but is not derived from:
|
||||||
|
// EHTERSHIELD_H library for Arduino etherShield
|
||||||
|
// Copyright (c) 2008 Xing Yu. All right reserved. (this is LGPL v2.1)
|
||||||
|
// It is however derived from the enc28j60 and ip code (which is GPL v2)
|
||||||
|
// Author: Pascal Stang
|
||||||
|
// Modified by: Guido Socher
|
||||||
|
// DHCP code: Andrew Lindsay
|
||||||
|
// Hence: GPL V2
|
||||||
|
//
|
||||||
|
// 2010-05-19 <jc@wippler.nl>
|
||||||
|
|
||||||
|
#include <EtherCard.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <avr/eeprom.h>
|
||||||
|
|
||||||
|
//#define FLOATEMIT // uncomment line to enable $T in emit_P for float emitting
|
||||||
|
|
||||||
|
byte Stash::map[256/8];
|
||||||
|
Stash::Block Stash::bufs[2];
|
||||||
|
|
||||||
|
uint8_t Stash::allocBlock () {
|
||||||
|
for (uint8_t i = 0; i < sizeof map; ++i)
|
||||||
|
if (map[i] != 0)
|
||||||
|
for (uint8_t j = 0; j < 8; ++j)
|
||||||
|
if (bitRead(map[i], j)) {
|
||||||
|
bitClear(map[i], j);
|
||||||
|
return (i << 3) + j;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stash::freeBlock (uint8_t block) {
|
||||||
|
bitSet(map[block>>3], block & 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t Stash::fetchByte (uint8_t blk, uint8_t off) {
|
||||||
|
return blk == bufs[0].bnum ? bufs[0].bytes[off] :
|
||||||
|
blk == bufs[1].bnum ? bufs[1].bytes[off] :
|
||||||
|
ether.peekin(blk, off);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stash::initMap (uint8_t last) {
|
||||||
|
while (--last > 0)
|
||||||
|
freeBlock(last);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stash::load (uint8_t idx, uint8_t blk) {
|
||||||
|
if (blk != bufs[idx].bnum) {
|
||||||
|
if (idx == 0) {
|
||||||
|
ether.copyout(bufs[idx].bnum, bufs[idx].bytes);
|
||||||
|
if (blk == bufs[1].bnum)
|
||||||
|
bufs[1].bnum = 255; // forget read page if same
|
||||||
|
} else if (blk == bufs[0].bnum) {
|
||||||
|
// special case: read page is same as write buffer
|
||||||
|
memcpy(&bufs[1], &bufs[0], sizeof bufs[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bufs[idx].bnum = blk;
|
||||||
|
ether.copyin(bufs[idx].bnum, bufs[idx].bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t Stash::freeCount () {
|
||||||
|
uint8_t count = 0;
|
||||||
|
for (uint8_t i = 0; i < 256/8; ++i)
|
||||||
|
for (uint8_t m = 0x80; m != 0; m >>= 1)
|
||||||
|
if (map[i] & m)
|
||||||
|
++count;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t Stash::create () {
|
||||||
|
uint8_t blk = allocBlock();
|
||||||
|
load(0, blk);
|
||||||
|
bufs[0].head.count = 0;
|
||||||
|
bufs[0].head.first = bufs[0].head.last = blk;
|
||||||
|
bufs[0].tail = sizeof (StashHeader);
|
||||||
|
bufs[0].next = 0;
|
||||||
|
return open(blk);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t Stash::open (uint8_t blk) {
|
||||||
|
curr = blk;
|
||||||
|
offs = sizeof (StashHeader);
|
||||||
|
load(1, curr);
|
||||||
|
memcpy((StashHeader*) this, bufs[1].bytes, sizeof (StashHeader));
|
||||||
|
return curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stash::save () {
|
||||||
|
load(0, first);
|
||||||
|
memcpy(bufs[0].bytes, (StashHeader*) this, sizeof (StashHeader));
|
||||||
|
if (bufs[1].bnum == first)
|
||||||
|
load(1, 0); // invalidates original in case it was the same block
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stash::release () {
|
||||||
|
while (first > 0) {
|
||||||
|
freeBlock(first);
|
||||||
|
first = ether.peekin(first, 63);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stash::put (char c) {
|
||||||
|
load(0, last);
|
||||||
|
uint8_t t = bufs[0].tail;
|
||||||
|
bufs[0].bytes[t++] = c;
|
||||||
|
if (t <= 62)
|
||||||
|
bufs[0].tail = t;
|
||||||
|
else {
|
||||||
|
bufs[0].next = allocBlock();
|
||||||
|
last = bufs[0].next;
|
||||||
|
load(0, last);
|
||||||
|
bufs[0].tail = bufs[0].next = 0;
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char Stash::get () {
|
||||||
|
load(1, curr);
|
||||||
|
if (curr == last && offs >= bufs[1].tail)
|
||||||
|
return 0;
|
||||||
|
uint8_t b = bufs[1].bytes[offs];
|
||||||
|
if (++offs >= 63 && curr != last) {
|
||||||
|
curr = bufs[1].next;
|
||||||
|
offs = 0;
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t Stash::size () {
|
||||||
|
return 63 * count + fetchByte(last, 62) - sizeof (StashHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char* wtoa (uint16_t value, char* ptr) {
|
||||||
|
if (value > 9)
|
||||||
|
ptr = wtoa(value / 10, ptr);
|
||||||
|
*ptr = '0' + value % 10;
|
||||||
|
*++ptr = 0;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stash::prepare (PGM_P fmt, ...) {
|
||||||
|
Stash::load(0, 0);
|
||||||
|
uint16_t* segs = Stash::bufs[0].words;
|
||||||
|
*segs++ = strlen_P(fmt);
|
||||||
|
#ifdef __AVR__
|
||||||
|
*segs++ = (uint16_t) fmt;
|
||||||
|
#else
|
||||||
|
*segs++ = (uint32_t) fmt;
|
||||||
|
*segs++ = (uint32_t) fmt >> 16;
|
||||||
|
#endif
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
for (;;) {
|
||||||
|
char c = pgm_read_byte(fmt++);
|
||||||
|
if (c == 0)
|
||||||
|
break;
|
||||||
|
if (c == '$') {
|
||||||
|
#ifdef __AVR__
|
||||||
|
uint16_t argval = va_arg(ap, uint16_t), arglen = 0;
|
||||||
|
#else
|
||||||
|
uint32_t argval = va_arg(ap, int), arglen = 0;
|
||||||
|
#endif
|
||||||
|
switch (pgm_read_byte(fmt++)) {
|
||||||
|
case 'D': {
|
||||||
|
char buf[7];
|
||||||
|
wtoa(argval, buf);
|
||||||
|
arglen = strlen(buf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'S':
|
||||||
|
arglen = strlen((const char*) argval);
|
||||||
|
break;
|
||||||
|
case 'F':
|
||||||
|
arglen = strlen_P((PGM_P) argval);
|
||||||
|
break;
|
||||||
|
case 'E': {
|
||||||
|
byte* s = (byte*) argval;
|
||||||
|
char d;
|
||||||
|
while ((d = eeprom_read_byte(s++)) != 0)
|
||||||
|
++arglen;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'H': {
|
||||||
|
Stash stash (argval);
|
||||||
|
arglen = stash.size();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef __AVR__
|
||||||
|
*segs++ = argval;
|
||||||
|
#else
|
||||||
|
*segs++ = argval;
|
||||||
|
*segs++ = argval >> 16;
|
||||||
|
#endif
|
||||||
|
Stash::bufs[0].words[0] += arglen - 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t Stash::length () {
|
||||||
|
Stash::load(0, 0);
|
||||||
|
return Stash::bufs[0].words[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stash::extract (uint16_t offset, uint16_t count, void* buf) {
|
||||||
|
Stash::load(0, 0);
|
||||||
|
uint16_t* segs = Stash::bufs[0].words;
|
||||||
|
#ifdef __AVR__
|
||||||
|
PGM_P fmt = (PGM_P) *++segs;
|
||||||
|
#else
|
||||||
|
PGM_P fmt = (PGM_P)((segs[2] << 16) | segs[1]);
|
||||||
|
segs += 2;
|
||||||
|
#endif
|
||||||
|
Stash stash;
|
||||||
|
char mode = '@', tmp[7], *ptr = NULL, *out = (char*) buf;
|
||||||
|
for (uint16_t i = 0; i < offset + count; ) {
|
||||||
|
char c = 0;
|
||||||
|
switch (mode) {
|
||||||
|
case '@': {
|
||||||
|
c = pgm_read_byte(fmt++);
|
||||||
|
if (c == 0)
|
||||||
|
return;
|
||||||
|
if (c != '$')
|
||||||
|
break;
|
||||||
|
#ifdef __AVR__
|
||||||
|
uint16_t arg = *++segs;
|
||||||
|
#else
|
||||||
|
uint32_t arg = *++segs;
|
||||||
|
arg |= *++segs << 16;
|
||||||
|
#endif
|
||||||
|
mode = pgm_read_byte(fmt++);
|
||||||
|
switch (mode) {
|
||||||
|
case 'D':
|
||||||
|
wtoa(arg, tmp);
|
||||||
|
ptr = tmp;
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
case 'F':
|
||||||
|
case 'E':
|
||||||
|
ptr = (char*) arg;
|
||||||
|
break;
|
||||||
|
case 'H':
|
||||||
|
stash.open(arg);
|
||||||
|
ptr = (char*) &stash;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
case 'D':
|
||||||
|
case 'S':
|
||||||
|
c = *ptr++;
|
||||||
|
break;
|
||||||
|
case 'F':
|
||||||
|
c = pgm_read_byte(ptr++);
|
||||||
|
break;
|
||||||
|
case 'E':
|
||||||
|
c = eeprom_read_byte((byte*) ptr++);
|
||||||
|
break;
|
||||||
|
case 'H':
|
||||||
|
c = ((Stash*) ptr)->get();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (c == 0) {
|
||||||
|
mode = '@';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (i >= offset)
|
||||||
|
*out++ = c;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stash::cleanup () {
|
||||||
|
Stash::load(0, 0);
|
||||||
|
uint16_t* segs = Stash::bufs[0].words;
|
||||||
|
#ifdef __AVR__
|
||||||
|
PGM_P fmt = (PGM_P) *++segs;
|
||||||
|
#else
|
||||||
|
PGM_P fmt = (PGM_P)((segs[2] << 16) | segs[1]);
|
||||||
|
segs += 2;
|
||||||
|
#endif
|
||||||
|
for (;;) {
|
||||||
|
char c = pgm_read_byte(fmt++);
|
||||||
|
if (c == 0)
|
||||||
|
break;
|
||||||
|
if (c == '$') {
|
||||||
|
#ifdef __AVR__
|
||||||
|
uint16_t arg = *++segs;
|
||||||
|
#else
|
||||||
|
uint32_t arg = *++segs;
|
||||||
|
arg |= *++segs << 16;
|
||||||
|
#endif
|
||||||
|
if (pgm_read_byte(fmt++) == 'H') {
|
||||||
|
Stash stash (arg);
|
||||||
|
stash.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BufferFiller::emit_p(PGM_P fmt, ...) {
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
for (;;) {
|
||||||
|
char c = pgm_read_byte(fmt++);
|
||||||
|
if (c == 0)
|
||||||
|
break;
|
||||||
|
if (c != '$') {
|
||||||
|
*ptr++ = c;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
c = pgm_read_byte(fmt++);
|
||||||
|
switch (c) {
|
||||||
|
case 'D':
|
||||||
|
#ifdef __AVR__
|
||||||
|
wtoa(va_arg(ap, uint16_t), (char*) ptr);
|
||||||
|
#else
|
||||||
|
wtoa(va_arg(ap, int), (char*) ptr);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
#ifdef FLOATEMIT
|
||||||
|
case 'T':
|
||||||
|
dtostrf ( va_arg(ap, double), 10, 3, (char*)ptr );
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case 'H': {
|
||||||
|
#ifdef __AVR__
|
||||||
|
char p1 = va_arg(ap, uint16_t);
|
||||||
|
#else
|
||||||
|
char p1 = va_arg(ap, int);
|
||||||
|
#endif
|
||||||
|
char p2;
|
||||||
|
p2 = (p1 >> 4) & 0x0F;
|
||||||
|
p1 = p1 & 0x0F;
|
||||||
|
if (p1 > 9) p1 += 0x07; // adjust 0x0a-0x0f to come out 'a'-'f'
|
||||||
|
p1 += 0x30; // and complete
|
||||||
|
if (p2 > 9) p2 += 0x07; // adjust 0x0a-0x0f to come out 'a'-'f'
|
||||||
|
p2 += 0x30; // and complete
|
||||||
|
*ptr++ = p2;
|
||||||
|
*ptr++ = p1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
case 'L':
|
||||||
|
ltoa(va_arg(ap, long), (char*) ptr, 10);
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
strcpy((char*) ptr, va_arg(ap, const char*));
|
||||||
|
break;
|
||||||
|
case 'F': {
|
||||||
|
PGM_P s = va_arg(ap, PGM_P);
|
||||||
|
char d;
|
||||||
|
while ((d = pgm_read_byte(s++)) != 0)
|
||||||
|
*ptr++ = d;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
case 'E': {
|
||||||
|
byte* s = va_arg(ap, byte*);
|
||||||
|
char d;
|
||||||
|
while ((d = eeprom_read_byte(s++)) != 0)
|
||||||
|
*ptr++ = d;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
*ptr++ = c;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ptr += strlen((char*) ptr);
|
||||||
|
}
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
EtherCard ether;
|
||||||
|
|
||||||
|
uint8_t EtherCard::mymac[6]; // my MAC address
|
||||||
|
uint8_t EtherCard::myip[4]; // my ip address
|
||||||
|
uint8_t EtherCard::netmask[4]; // subnet mask
|
||||||
|
uint8_t EtherCard::broadcastip[4]; // broadcast address
|
||||||
|
uint8_t EtherCard::gwip[4]; // gateway
|
||||||
|
uint8_t EtherCard::dhcpip[4]; // dhcp server
|
||||||
|
uint8_t EtherCard::dnsip[4]; // dns server
|
||||||
|
uint8_t EtherCard::hisip[4]; // ip address of remote host
|
||||||
|
uint16_t EtherCard::hisport = 80; // tcp port to browse to
|
||||||
|
bool EtherCard::using_dhcp = false;
|
||||||
|
bool EtherCard::persist_tcp_connection = false;
|
||||||
|
int16_t EtherCard::delaycnt = 0; //request gateway ARP lookup
|
||||||
|
|
||||||
|
uint8_t EtherCard::begin (const uint16_t size,
|
||||||
|
const uint8_t* macaddr,
|
||||||
|
uint8_t csPin) {
|
||||||
|
using_dhcp = false;
|
||||||
|
Stash::initMap(56);
|
||||||
|
copyMac(mymac, macaddr);
|
||||||
|
return initialize(size, mymac, csPin);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EtherCard::staticSetup (const uint8_t* my_ip,
|
||||||
|
const uint8_t* gw_ip,
|
||||||
|
const uint8_t* dns_ip,
|
||||||
|
const uint8_t* mask) {
|
||||||
|
using_dhcp = false;
|
||||||
|
|
||||||
|
if (my_ip != 0)
|
||||||
|
copyIp(myip, my_ip);
|
||||||
|
if (gw_ip != 0)
|
||||||
|
setGwIp(gw_ip);
|
||||||
|
if (dns_ip != 0)
|
||||||
|
copyIp(dnsip, dns_ip);
|
||||||
|
if(mask != 0)
|
||||||
|
copyIp(netmask, mask);
|
||||||
|
updateBroadcastAddress();
|
||||||
|
delaycnt = 0; //request gateway ARP lookup
|
||||||
|
return true;
|
||||||
|
}
|
587
lib-ext/ethercard.git/EtherCard.h
Normal file
587
lib-ext/ethercard.git/EtherCard.h
Normal file
|
@ -0,0 +1,587 @@
|
||||||
|
// This code slightly follows the conventions of, but is not derived from:
|
||||||
|
// EHTERSHIELD_H library for Arduino etherShield
|
||||||
|
// Copyright (c) 2008 Xing Yu. All right reserved. (this is LGPL v2.1)
|
||||||
|
// It is however derived from the enc28j60 and ip code (which is GPL v2)
|
||||||
|
// Author: Pascal Stang
|
||||||
|
// Modified by: Guido Socher
|
||||||
|
// DHCP code: Andrew Lindsay
|
||||||
|
// Hence: GPL V2
|
||||||
|
//
|
||||||
|
// 2010-05-19 <jc@wippler.nl>
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// PIN Connections (Using Arduino UNO):
|
||||||
|
// VCC - 3.3V
|
||||||
|
// GND - GND
|
||||||
|
// SCK - Pin 13
|
||||||
|
// SO - Pin 12
|
||||||
|
// SI - Pin 11
|
||||||
|
// CS - Pin 8
|
||||||
|
//
|
||||||
|
#define __PROG_TYPES_COMPAT__
|
||||||
|
|
||||||
|
#ifndef EtherCard_h
|
||||||
|
#define EtherCard_h
|
||||||
|
|
||||||
|
|
||||||
|
#if ARDUINO >= 100
|
||||||
|
#include <Arduino.h> // Arduino 1.0
|
||||||
|
#define WRITE_RESULT size_t
|
||||||
|
#define WRITE_RETURN return 1;
|
||||||
|
#else
|
||||||
|
#include <WProgram.h> // Arduino 0022
|
||||||
|
#define WRITE_RESULT void
|
||||||
|
#define WRITE_RETURN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <avr/pgmspace.h>
|
||||||
|
#include "enc28j60.h"
|
||||||
|
#include "net.h"
|
||||||
|
|
||||||
|
/** This type definition defines the structure of a UDP server event handler callback funtion */
|
||||||
|
typedef void (*UdpServerCallback)(
|
||||||
|
uint16_t dest_port, ///< Port the packet was sent to
|
||||||
|
uint8_t src_ip[4], ///< IP address of the sender
|
||||||
|
const char *data, ///< UDP payload data
|
||||||
|
uint16_t len); ///< Length of the payload data
|
||||||
|
|
||||||
|
/** This type definition defines the structure of a DHCP Option callback funtion */
|
||||||
|
typedef void (*DhcpOptionCallback)(
|
||||||
|
uint8_t option, ///< The option number
|
||||||
|
const byte* data, ///< DHCP option data
|
||||||
|
uint8_t len); ///< Length of the DHCP option data
|
||||||
|
|
||||||
|
|
||||||
|
/** This structure describes the structure of memory used within the ENC28J60 network interface. */
|
||||||
|
typedef struct {
|
||||||
|
uint8_t count; ///< Number of allocated pages
|
||||||
|
uint8_t first; ///< First allocated page
|
||||||
|
uint8_t last; ///< Last allocated page
|
||||||
|
} StashHeader;
|
||||||
|
|
||||||
|
/** This class provides access to the memory within the ENC28J60 network interface. */
|
||||||
|
class Stash : public /*Stream*/ Print, private StashHeader {
|
||||||
|
uint8_t curr; //!< Current page
|
||||||
|
uint8_t offs; //!< Current offset in page
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
union {
|
||||||
|
uint8_t bytes[64];
|
||||||
|
uint16_t words[32];
|
||||||
|
struct {
|
||||||
|
StashHeader head;
|
||||||
|
uint8_t filler[59];
|
||||||
|
uint8_t tail;
|
||||||
|
uint8_t next;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
uint8_t bnum;
|
||||||
|
} Block;
|
||||||
|
|
||||||
|
static uint8_t allocBlock ();
|
||||||
|
static void freeBlock (uint8_t block);
|
||||||
|
static uint8_t fetchByte (uint8_t blk, uint8_t off);
|
||||||
|
|
||||||
|
static Block bufs[2];
|
||||||
|
static uint8_t map[256/8];
|
||||||
|
|
||||||
|
public:
|
||||||
|
static void initMap (uint8_t last);
|
||||||
|
static void load (uint8_t idx, uint8_t blk);
|
||||||
|
static uint8_t freeCount ();
|
||||||
|
|
||||||
|
Stash () : curr (0) { first = 0; }
|
||||||
|
Stash (uint8_t fd) { open(fd); }
|
||||||
|
|
||||||
|
uint8_t create ();
|
||||||
|
uint8_t open (uint8_t blk);
|
||||||
|
void save ();
|
||||||
|
void release ();
|
||||||
|
|
||||||
|
void put (char c);
|
||||||
|
char get ();
|
||||||
|
uint16_t size ();
|
||||||
|
|
||||||
|
virtual WRITE_RESULT write(uint8_t b) { put(b); WRITE_RETURN }
|
||||||
|
|
||||||
|
// virtual int available() {
|
||||||
|
// if (curr != last)
|
||||||
|
// return 1;
|
||||||
|
// load(1, last);
|
||||||
|
// return offs < bufs[1].tail;
|
||||||
|
// }
|
||||||
|
// virtual int read() {
|
||||||
|
// return available() ? get() : -1;
|
||||||
|
// }
|
||||||
|
// virtual int peek() {
|
||||||
|
// return available() ? bufs[1].bytes[offs] : -1;
|
||||||
|
// }
|
||||||
|
// virtual void flush() {
|
||||||
|
// curr = last;
|
||||||
|
// offs = 63;
|
||||||
|
// }
|
||||||
|
|
||||||
|
static void prepare (PGM_P fmt, ...);
|
||||||
|
static uint16_t length ();
|
||||||
|
static void extract (uint16_t offset, uint16_t count, void* buf);
|
||||||
|
static void cleanup ();
|
||||||
|
|
||||||
|
friend void dumpBlock (const char* msg, uint8_t idx); // optional
|
||||||
|
friend void dumpStash (const char* msg, void* ptr); // optional
|
||||||
|
};
|
||||||
|
|
||||||
|
/** This class populates network send and receive buffers.
|
||||||
|
*
|
||||||
|
* This class provides formatted printing into memory. Users can use it to write into send buffers.
|
||||||
|
*
|
||||||
|
* Nota: PGM_P: is a pointer to a string in program space (defined in the source code)
|
||||||
|
*
|
||||||
|
* # Format string
|
||||||
|
*
|
||||||
|
* | Format | Parameter | Output
|
||||||
|
* |--------|-------------|----------
|
||||||
|
* | $D | uint16_t | Decimal representation
|
||||||
|
* | $T ¤ | double | Decimal representation with 3 digits after decimal sign ([-]d.ddd)
|
||||||
|
* | $H | uint16_t | Hexadecimal value of lsb (from 00 to ff)
|
||||||
|
* | $L | long | Decimal representation
|
||||||
|
* | $S | const char* | Copy null terminated string from main memory
|
||||||
|
* | $F | PGM_P | Copy null terminated string from program space
|
||||||
|
* | $E | byte* | Copy null terminated string from EEPROM space
|
||||||
|
* | $$ | _none_ | '$'
|
||||||
|
*
|
||||||
|
* ¤ _Available only if FLOATEMIT is defined_
|
||||||
|
*
|
||||||
|
* # Examples
|
||||||
|
* ~~~~~~~~~~~~~{.c}
|
||||||
|
* uint16_t ddd = 123;
|
||||||
|
* double ttt = 1.23;
|
||||||
|
* uint16_t hhh = 0xa4;
|
||||||
|
* long lll = 123456789;
|
||||||
|
* char * sss;
|
||||||
|
* char fff[] PROGMEM = "MyMemory";
|
||||||
|
*
|
||||||
|
* sss[0] = 'G';
|
||||||
|
* sss[1] = 'P';
|
||||||
|
* sss[2] = 'L';
|
||||||
|
* sss[3] = 0;
|
||||||
|
* buf.emit_p( PSTR("ddd=$D\n"), ddd ); // "ddd=123\n"
|
||||||
|
* buf.emit_p( PSTR("ttt=$T\n"), ttt ); // "ttt=1.23\n" **TO CHECK**
|
||||||
|
* buf.emit_p( PSTR("hhh=$H\n"), hhh ); // "hhh=a4\n"
|
||||||
|
* buf.emit_p( PSTR("lll=$L\n"), lll ); // "lll=123456789\n"
|
||||||
|
* buf.emit_p( PSTR("sss=$S\n"), sss ); // "sss=GPL\n"
|
||||||
|
* buf.emit_p( PSTR("fff=$F\n"), fff ); // "fff=MyMemory\n"
|
||||||
|
* ~~~~~~~~~~~~~
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class BufferFiller : public Print {
|
||||||
|
uint8_t *start; //!< Pointer to start of buffer
|
||||||
|
uint8_t *ptr; //!< Pointer to cursor position
|
||||||
|
public:
|
||||||
|
/** @brief Empty constructor
|
||||||
|
*/
|
||||||
|
BufferFiller () {}
|
||||||
|
|
||||||
|
/** @brief Constructor
|
||||||
|
* @param buf Pointer to the ethernet data buffer
|
||||||
|
*/
|
||||||
|
BufferFiller (uint8_t* buf) : start (buf), ptr (buf) {}
|
||||||
|
|
||||||
|
/** @brief Add formatted text to buffer
|
||||||
|
* @param fmt Format string (see Class description)
|
||||||
|
* @param ... parameters for format string
|
||||||
|
*/
|
||||||
|
void emit_p (PGM_P fmt, ...);
|
||||||
|
|
||||||
|
/** @brief Add data to buffer from main memory
|
||||||
|
* @param s Pointer to data
|
||||||
|
* @param n Number of characters to copy
|
||||||
|
*/
|
||||||
|
void emit_raw (const char* s, uint16_t n) { memcpy(ptr, s, n); ptr += n; }
|
||||||
|
|
||||||
|
/** @brief Add data to buffer from program space string
|
||||||
|
* @param p Program space string pointer
|
||||||
|
* @param n Number of characters to copy
|
||||||
|
*/
|
||||||
|
void emit_raw_p (PGM_P p, uint16_t n) { memcpy_P(ptr, p, n); ptr += n; }
|
||||||
|
|
||||||
|
/** @brief Get pointer to start of buffer
|
||||||
|
* @return <i>uint8_t*</i> Pointer to start of buffer
|
||||||
|
*/
|
||||||
|
uint8_t* buffer () const { return start; }
|
||||||
|
|
||||||
|
/** @brief Get cursor position
|
||||||
|
* @return <i>uint16_t</i> Cursor postion
|
||||||
|
*/
|
||||||
|
uint16_t position () const { return ptr - start; }
|
||||||
|
|
||||||
|
/** @brief Write one byte to buffer
|
||||||
|
* @param v Byte to add to buffer
|
||||||
|
*/
|
||||||
|
virtual WRITE_RESULT write (uint8_t v) { *ptr++ = v; WRITE_RETURN }
|
||||||
|
};
|
||||||
|
|
||||||
|
/** This class provides the main interface to a ENC28J60 based network interface card and is the class most users will use.
|
||||||
|
* @note All TCP/IP client (outgoing) connections are made from source port in range 2816-3071. Do not use these source ports for other purposes.
|
||||||
|
*/
|
||||||
|
class EtherCard : public Ethernet {
|
||||||
|
public:
|
||||||
|
static uint8_t mymac[6]; ///< MAC address
|
||||||
|
static uint8_t myip[4]; ///< IP address
|
||||||
|
static uint8_t netmask[4]; ///< Netmask
|
||||||
|
static uint8_t broadcastip[4]; ///< Subnet broadcast address
|
||||||
|
static uint8_t gwip[4]; ///< Gateway
|
||||||
|
static uint8_t dhcpip[4]; ///< DHCP server IP address
|
||||||
|
static uint8_t dnsip[4]; ///< DNS server IP address
|
||||||
|
static uint8_t hisip[4]; ///< DNS lookup result
|
||||||
|
static uint16_t hisport; ///< TCP port to connect to (default 80)
|
||||||
|
static bool using_dhcp; ///< True if using DHCP
|
||||||
|
static bool persist_tcp_connection; ///< False to break connections on first packet received
|
||||||
|
static int16_t delaycnt; ///< Counts number of cycles of packetLoop when no packet received - used to trigger periodic gateway ARP request
|
||||||
|
|
||||||
|
// EtherCard.cpp
|
||||||
|
/** @brief Initialise the network interface
|
||||||
|
* @param size Size of data buffer
|
||||||
|
* @param macaddr Hardware address to assign to the network interface (6 bytes)
|
||||||
|
* @param csPin Arduino pin number connected to chip select. Default = 8
|
||||||
|
* @return <i>uint8_t</i> Firmware version or zero on failure.
|
||||||
|
*/
|
||||||
|
static uint8_t begin (const uint16_t size, const uint8_t* macaddr,
|
||||||
|
uint8_t csPin =8);
|
||||||
|
|
||||||
|
/** @brief Configure network interface with static IP
|
||||||
|
* @param my_ip IP address (4 bytes). 0 for no change.
|
||||||
|
* @param gw_ip Gateway address (4 bytes). 0 for no change. Default = 0
|
||||||
|
* @param dns_ip DNS address (4 bytes). 0 for no change. Default = 0
|
||||||
|
* @param mask Subnet mask (4 bytes). 0 for no change. Default = 0
|
||||||
|
* @return <i>bool</i> Returns true on success - actually always true
|
||||||
|
*/
|
||||||
|
static bool staticSetup (const uint8_t* my_ip,
|
||||||
|
const uint8_t* gw_ip = 0,
|
||||||
|
const uint8_t* dns_ip = 0,
|
||||||
|
const uint8_t* mask = 0);
|
||||||
|
|
||||||
|
// tcpip.cpp
|
||||||
|
/** @brief Sends a UDP packet to the IP address of last processed received packet
|
||||||
|
* @param data Pointer to data payload
|
||||||
|
* @param len Size of data payload (max 220)
|
||||||
|
* @param port Source IP port
|
||||||
|
*/
|
||||||
|
static void makeUdpReply (const char *data, uint8_t len, uint16_t port);
|
||||||
|
|
||||||
|
/** @brief Parse received data
|
||||||
|
* @param plen Size of data to parse (e.g. return value of packetReceive()).
|
||||||
|
* @return <i>uint16_t</i> Offset of TCP payload data in data buffer or zero if packet processed
|
||||||
|
* @note Data buffer is shared by receive and transmit functions
|
||||||
|
* @note Only handles ARP and IP
|
||||||
|
*/
|
||||||
|
static uint16_t packetLoop (uint16_t plen);
|
||||||
|
|
||||||
|
/** @brief Accept a TCP/IP connection
|
||||||
|
* @param port IP port to accept on - do nothing if wrong port
|
||||||
|
* @param plen Number of bytes in packet
|
||||||
|
* @return <i>uint16_t</i> Offset within packet of TCP payload. Zero for no data.
|
||||||
|
*/
|
||||||
|
static uint16_t accept (uint16_t port, uint16_t plen);
|
||||||
|
|
||||||
|
/** @brief Send a response to a HTTP request
|
||||||
|
* @param dlen Size of the HTTP (TCP) payload
|
||||||
|
*/
|
||||||
|
static void httpServerReply (uint16_t dlen);
|
||||||
|
|
||||||
|
/** @brief Send a response to a HTTP request
|
||||||
|
* @param dlen Size of the HTTP (TCP) payload
|
||||||
|
* @param flags TCP flags
|
||||||
|
*/
|
||||||
|
static void httpServerReply_with_flags (uint16_t dlen , uint8_t flags);
|
||||||
|
|
||||||
|
/** @brief Acknowledge TCP message
|
||||||
|
* @todo Is this / should this be private?
|
||||||
|
*/
|
||||||
|
static void httpServerReplyAck ();
|
||||||
|
|
||||||
|
/** @brief Set the gateway address
|
||||||
|
* @param gwipaddr Gateway address (4 bytes)
|
||||||
|
*/
|
||||||
|
static void setGwIp (const uint8_t *gwipaddr);
|
||||||
|
|
||||||
|
/** @brief Updates the broadcast address based on current IP address and subnet mask
|
||||||
|
*/
|
||||||
|
static void updateBroadcastAddress();
|
||||||
|
|
||||||
|
/** @brief Check if got gateway hardware address (ARP lookup)
|
||||||
|
* @return <i>unit8_t</i> True if gateway found
|
||||||
|
*/
|
||||||
|
static uint8_t clientWaitingGw ();
|
||||||
|
|
||||||
|
/** @brief Check if got gateway DNS address (ARP lookup)
|
||||||
|
* @return <i>unit8_t</i> True if DNS found
|
||||||
|
*/
|
||||||
|
static uint8_t clientWaitingDns ();
|
||||||
|
|
||||||
|
/** @brief Prepare a TCP request
|
||||||
|
* @param result_cb Pointer to callback function that handles TCP result
|
||||||
|
* @param datafill_cb Pointer to callback function that handles TCP data payload
|
||||||
|
* @param port Remote TCP/IP port to connect to
|
||||||
|
* @return <i>unit8_t</i> ID of TCP/IP session (0-7)
|
||||||
|
* @note Return value provides id of the request to allow up to 7 concurrent requests
|
||||||
|
*/
|
||||||
|
static uint8_t clientTcpReq (uint8_t (*result_cb)(uint8_t,uint8_t,uint16_t,uint16_t),
|
||||||
|
uint16_t (*datafill_cb)(uint8_t),uint16_t port);
|
||||||
|
|
||||||
|
/** @brief Prepare HTTP request
|
||||||
|
* @param urlbuf Pointer to c-string URL folder
|
||||||
|
* @param urlbuf_varpart Pointer to c-string URL file
|
||||||
|
* @param hoststr Pointer to c-string hostname
|
||||||
|
* @param additionalheaderline Pointer to c-string with additional HTTP header info
|
||||||
|
* @param callback Pointer to callback function to handle response
|
||||||
|
* @note Request sent in main packetloop
|
||||||
|
*/
|
||||||
|
static void browseUrl (const char *urlbuf, const char *urlbuf_varpart,
|
||||||
|
const char *hoststr, const char *additionalheaderline,
|
||||||
|
void (*callback)(uint8_t,uint16_t,uint16_t));
|
||||||
|
|
||||||
|
/** @brief Prepare HTTP request
|
||||||
|
* @param urlbuf Pointer to c-string URL folder
|
||||||
|
* @param urlbuf_varpart Pointer to c-string URL file
|
||||||
|
* @param hoststr Pointer to c-string hostname
|
||||||
|
* @param callback Pointer to callback function to handle response
|
||||||
|
* @note Request sent in main packetloop
|
||||||
|
*/
|
||||||
|
static void browseUrl (const char *urlbuf, const char *urlbuf_varpart,
|
||||||
|
const char *hoststr,
|
||||||
|
void (*callback)(uint8_t,uint16_t,uint16_t));
|
||||||
|
|
||||||
|
/** @brief Prepare HTTP post message
|
||||||
|
* @param urlbuf Pointer to c-string URL folder
|
||||||
|
* @param hoststr Pointer to c-string hostname
|
||||||
|
* @param additionalheaderline Pointer to c-string with additional HTTP header info
|
||||||
|
* @param postval Pointer to c-string HTML Post value
|
||||||
|
* @param callback Pointer to callback function to handle response
|
||||||
|
* @note Request sent in main packetloop
|
||||||
|
*/
|
||||||
|
static void httpPost (const char *urlbuf, const char *hoststr,
|
||||||
|
const char *additionalheaderline, const char *postval,
|
||||||
|
void (*callback)(uint8_t,uint16_t,uint16_t));
|
||||||
|
|
||||||
|
/** @brief Send NTP request
|
||||||
|
* @param ntpip IP address of NTP server
|
||||||
|
* @param srcport IP port to send from
|
||||||
|
*/
|
||||||
|
static void ntpRequest (uint8_t *ntpip,uint8_t srcport);
|
||||||
|
|
||||||
|
/** @brief Process network time protocol response
|
||||||
|
* @param time Pointer to integer to hold result
|
||||||
|
* @param dstport_l Destination port to expect response. Set to zero to accept on any port
|
||||||
|
* @return <i>uint8_t</i> True (1) on success
|
||||||
|
*/
|
||||||
|
static uint8_t ntpProcessAnswer (uint32_t *time, uint8_t dstport_l);
|
||||||
|
|
||||||
|
/** @brief Prepare a UDP message for transmission
|
||||||
|
* @param sport Source port
|
||||||
|
* @param dip Pointer to 4 byte destination IP address
|
||||||
|
* @param dport Destination port
|
||||||
|
*/
|
||||||
|
static void udpPrepare (uint16_t sport, const uint8_t *dip, uint16_t dport);
|
||||||
|
|
||||||
|
/** @brief Transmit UDP packet
|
||||||
|
* @param len Size of payload
|
||||||
|
*/
|
||||||
|
static void udpTransmit (uint16_t len);
|
||||||
|
|
||||||
|
/** @brief Sends a UDP packet
|
||||||
|
* @param data Pointer to data
|
||||||
|
* @param len Size of payload (maximum 220 octets / bytes)
|
||||||
|
* @param sport Source port
|
||||||
|
* @param dip Pointer to 4 byte destination IP address
|
||||||
|
* @param dport Destination port
|
||||||
|
*/
|
||||||
|
static void sendUdp (const char *data, uint8_t len, uint16_t sport,
|
||||||
|
const uint8_t *dip, uint16_t dport);
|
||||||
|
|
||||||
|
/** @brief Resister the function to handle ping events
|
||||||
|
* @param cb Pointer to function
|
||||||
|
*/
|
||||||
|
static void registerPingCallback (void (*cb)(uint8_t*));
|
||||||
|
|
||||||
|
/** @brief Send ping
|
||||||
|
* @param destip Ponter to 4 byte destination IP address
|
||||||
|
*/
|
||||||
|
static void clientIcmpRequest (const uint8_t *destip);
|
||||||
|
|
||||||
|
/** @brief Check for ping response
|
||||||
|
* @param ip_monitoredhost Pointer to 4 byte IP address of host to check
|
||||||
|
* @return <i>uint8_t</i> True (1) if ping response from specified host
|
||||||
|
*/
|
||||||
|
static uint8_t packetLoopIcmpCheckReply (const uint8_t *ip_monitoredhost);
|
||||||
|
|
||||||
|
/** @brief Send a wake on lan message
|
||||||
|
* @param wolmac Pointer to 6 byte hardware (MAC) address of host to send message to
|
||||||
|
*/
|
||||||
|
static void sendWol (uint8_t *wolmac);
|
||||||
|
|
||||||
|
// new stash-based API
|
||||||
|
/** @brief Send TCP request
|
||||||
|
*/
|
||||||
|
static uint8_t tcpSend ();
|
||||||
|
|
||||||
|
/** @brief Get TCP reply
|
||||||
|
* @return <i>char*</i> Pointer to TCP reply payload. NULL if no data.
|
||||||
|
*/
|
||||||
|
static const char* tcpReply (uint8_t fd);
|
||||||
|
|
||||||
|
/** @brief Configure TCP connections to be persistent or not
|
||||||
|
* @param persist True to maintain TCP connection. False to finish TCP connection after first packet.
|
||||||
|
*/
|
||||||
|
static void persistTcpConnection(bool persist);
|
||||||
|
|
||||||
|
//udpserver.cpp
|
||||||
|
/** @brief Register function to handle incomint UDP events
|
||||||
|
* @param callback Function to handle event
|
||||||
|
* @param port Port to listen on
|
||||||
|
*/
|
||||||
|
static void udpServerListenOnPort(UdpServerCallback callback, uint16_t port);
|
||||||
|
|
||||||
|
/** @brief Pause listing on UDP port
|
||||||
|
* @brief port Port to pause
|
||||||
|
*/
|
||||||
|
static void udpServerPauseListenOnPort(uint16_t port);
|
||||||
|
|
||||||
|
/** @brief Resume listing on UDP port
|
||||||
|
* @brief port Port to pause
|
||||||
|
*/
|
||||||
|
static void udpServerResumeListenOnPort(uint16_t port);
|
||||||
|
|
||||||
|
/** @brief Check if UDP server is listening on any ports
|
||||||
|
* @return <i>bool</i> True if listening on any ports
|
||||||
|
*/
|
||||||
|
static bool udpServerListening(); //called by tcpip, in packetLoop
|
||||||
|
|
||||||
|
/** @brief Passes packet to UDP Server
|
||||||
|
* @param len Not used
|
||||||
|
* @return <i>bool</i> True if packet processed
|
||||||
|
*/
|
||||||
|
static bool udpServerHasProcessedPacket(uint16_t len); //called by tcpip, in packetLoop
|
||||||
|
|
||||||
|
// dhcp.cpp
|
||||||
|
/** @brief Update DHCP state
|
||||||
|
* @param len Length of received data packet
|
||||||
|
*/
|
||||||
|
static void DhcpStateMachine(uint16_t len);
|
||||||
|
|
||||||
|
/** @brief Not implemented
|
||||||
|
* @todo Implement dhcpStartTime or remove declaration
|
||||||
|
*/
|
||||||
|
static uint32_t dhcpStartTime ();
|
||||||
|
|
||||||
|
/** @brief Not implemented
|
||||||
|
* @todo Implement dhcpLeaseTime or remove declaration
|
||||||
|
*/
|
||||||
|
static uint32_t dhcpLeaseTime ();
|
||||||
|
|
||||||
|
/** @brief Not implemented
|
||||||
|
* @todo Implement dhcpLease or remove declaration
|
||||||
|
*/
|
||||||
|
static bool dhcpLease ();
|
||||||
|
|
||||||
|
/** @brief Configure network interface with DHCP
|
||||||
|
* @return <i>bool</i> True if DHCP successful
|
||||||
|
* @note Blocks until DHCP complete or timeout after 60 seconds
|
||||||
|
*/
|
||||||
|
static bool dhcpSetup (const char *hname = NULL, bool fromRam =false);
|
||||||
|
|
||||||
|
/** @brief Register a callback for a specific DHCP option number
|
||||||
|
* @param option The option number to request from the DHCP server
|
||||||
|
* @param callback The function to be call when the option is received
|
||||||
|
*/
|
||||||
|
static void dhcpAddOptionCallback(uint8_t option, DhcpOptionCallback callback);
|
||||||
|
|
||||||
|
// dns.cpp
|
||||||
|
/** @brief Perform DNS lookup
|
||||||
|
* @param name Host name to lookup
|
||||||
|
* @param fromRam Set true to look up cached name. Default = false
|
||||||
|
* @return <i>bool</i> True on success.
|
||||||
|
* @note Result is stored in <i>hisip</i> member
|
||||||
|
*/
|
||||||
|
static bool dnsLookup (const char* name, bool fromRam =false);
|
||||||
|
|
||||||
|
// webutil.cpp
|
||||||
|
/** @brief Copies an IP address
|
||||||
|
* @param dst Pointer to the 4 byte destination
|
||||||
|
* @param src Pointer to the 4 byte source
|
||||||
|
* @note There is no check of source or destination size. Ensure both are 4 bytes
|
||||||
|
*/
|
||||||
|
static void copyIp (uint8_t *dst, const uint8_t *src);
|
||||||
|
|
||||||
|
/** @brief Copies a hardware address
|
||||||
|
* @param dst Pointer to the 6 byte destination
|
||||||
|
* @param src Pointer to the 6 byte destination
|
||||||
|
* @note There is no check of source or destination size. Ensure both are 6 bytes
|
||||||
|
*/
|
||||||
|
static void copyMac (uint8_t *dst, const uint8_t *src);
|
||||||
|
|
||||||
|
/** @brief Output to serial port in dotted decimal IP format
|
||||||
|
* @param buf Pointer to 4 byte IP address
|
||||||
|
* @note There is no check of source or destination size. Ensure both are 4 bytes
|
||||||
|
*/
|
||||||
|
static void printIp (const uint8_t *buf);
|
||||||
|
|
||||||
|
/** @brief Output message and IP address to serial port in dotted decimal IP format
|
||||||
|
* @param msg Pointer to null terminated string
|
||||||
|
* @param buf Pointer to 4 byte IP address
|
||||||
|
* @note There is no check of source or destination size. Ensure both are 4 bytes
|
||||||
|
*/
|
||||||
|
static void printIp (const char* msg, const uint8_t *buf);
|
||||||
|
|
||||||
|
/** @brief Output Flash String Helper and IP address to serial port in dotted decimal IP format
|
||||||
|
* @param ifsh Pointer to Flash String Helper
|
||||||
|
* @param buf Pointer to 4 byte IP address
|
||||||
|
* @note There is no check of source or destination size. Ensure both are 4 bytes
|
||||||
|
* @todo What is a FlashStringHelper?
|
||||||
|
*/
|
||||||
|
static void printIp (const __FlashStringHelper *ifsh, const uint8_t *buf);
|
||||||
|
|
||||||
|
/** @brief Search for a string of the form key=value in a string that looks like q?xyz=abc&uvw=defgh HTTP/1.1\\r\\n
|
||||||
|
* @param str Pointer to the null terminated string to search
|
||||||
|
* @param strbuf Pointer to buffer to hold null terminated result string
|
||||||
|
* @param maxlen Maximum length of result
|
||||||
|
* @param key Pointer to null terminated string holding the key to search for
|
||||||
|
* @return <i>unit_t</i> Length of the value. 0 if not found
|
||||||
|
* @note Ensure strbuf has memory allocated of at least maxlen + 1 (to accomodate result plus terminating null)
|
||||||
|
*/
|
||||||
|
static uint8_t findKeyVal(const char *str,char *strbuf,
|
||||||
|
uint8_t maxlen, const char *key);
|
||||||
|
|
||||||
|
/** @brief Decode a URL string e.g "hello%20joe" or "hello+joe" becomes "hello joe"
|
||||||
|
* @param urlbuf Pointer to the null terminated URL
|
||||||
|
* @note urlbuf is modified
|
||||||
|
*/
|
||||||
|
static void urlDecode(char *urlbuf);
|
||||||
|
|
||||||
|
/** @brief Encode a URL, replacing illegal charaters like ' '
|
||||||
|
* @param str Pointer to the null terminated string to encode
|
||||||
|
* @param urlbuf Pointer to a buffer to contain the null terminated encoded URL
|
||||||
|
* @note There must be enough space in urlbuf. In the worst case that is 3 times the length of str
|
||||||
|
*/
|
||||||
|
static void urlEncode(char *str,char *urlbuf);
|
||||||
|
|
||||||
|
/** @brief Convert an IP address from dotted decimal formated string to 4 bytes
|
||||||
|
* @param bytestr Pointer to the 4 byte array to store IP address
|
||||||
|
* @param str Pointer to string to parse
|
||||||
|
* @return <i>uint8_t</i> 0 on success
|
||||||
|
*/
|
||||||
|
static uint8_t parseIp(uint8_t *bytestr,char *str);
|
||||||
|
|
||||||
|
/** @brief Convert a byte array to a human readable display string
|
||||||
|
* @param resultstr Pointer to a buffer to hold the resulting null terminated string
|
||||||
|
* @param bytestr Pointer to the byte array containing the address to convert
|
||||||
|
* @param len Length of the array (4 for IP address, 6 for hardware (MAC) address)
|
||||||
|
* @param separator Delimiter character (typically '.' for IP address and ':' for hardware (MAC) address)
|
||||||
|
* @param base Base for numerical representation (typically 10 for IP address and 16 for hardware (MAC) address
|
||||||
|
*/
|
||||||
|
static void makeNetStr(char *resultstr,uint8_t *bytestr,uint8_t len,
|
||||||
|
char separator,uint8_t base);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern EtherCard ether; //!< Global presentation of EtherCard class
|
||||||
|
|
||||||
|
#endif
|
46
lib-ext/ethercard.git/README.md
Normal file
46
lib-ext/ethercard.git/README.md
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
# EtherCard
|
||||||
|
|
||||||
|
**EtherCard** is a driver for the ENC28J60 chip, compatible with Arduino IDE.
|
||||||
|
Adapted and extended from code written by Guido Socher and Pascal Stang.
|
||||||
|
|
||||||
|
License: GPL2
|
||||||
|
|
||||||
|
The documentation for this library is at http://jeelabs.net/pub/docs/ethercard/.
|
||||||
|
|
||||||
|
## Library Installation
|
||||||
|
|
||||||
|
1. Download the ZIP file from https://github.com/jcw/ethercard/archive/master.zip
|
||||||
|
2. From the Arduino IDE: Sketch -> Import Library... -> Add Library...
|
||||||
|
3. Restart the Arduino IDE to see the new "EtherCard" library with examples
|
||||||
|
|
||||||
|
See the comments in the example sketches for details about how to try them out.
|
||||||
|
|
||||||
|
## Physical Installation
|
||||||
|
|
||||||
|
### PIN Connections (Using Arduino UNO):
|
||||||
|
|
||||||
|
VCC - 3.3V
|
||||||
|
GND - GND
|
||||||
|
SCK - Pin 13
|
||||||
|
SO - Pin 12
|
||||||
|
SI - Pin 11
|
||||||
|
CS - Pin 8 # Selectable with the ether.begin() function
|
||||||
|
|
||||||
|
### PIN Connections using an Arduino Mega
|
||||||
|
|
||||||
|
VCC - 3.3V
|
||||||
|
GND - GND
|
||||||
|
SCK - Pin 52
|
||||||
|
SO - Pin 50
|
||||||
|
SI - Pin 51
|
||||||
|
CS - Pin 53 # Selectable with the ether.begin() function
|
||||||
|
# The default CS pin defaults to 8, so you have to set it on a mega:
|
||||||
|
ether.begin(sizeof Ethernet::buffer, mymac, 53)
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
For questions and help, see the [forums][F] (at JeeLabs.net).
|
||||||
|
The issue tracker has been moved back to [Github][I] again.
|
||||||
|
|
||||||
|
[F]: http://jeenet.net/projects/cafe/boards
|
||||||
|
[I]: https://github.com/jcw/ethercard/issues
|
432
lib-ext/ethercard.git/dhcp.cpp
Normal file
432
lib-ext/ethercard.git/dhcp.cpp
Normal file
|
@ -0,0 +1,432 @@
|
||||||
|
// DHCP look-up functions based on the udp client
|
||||||
|
// http://www.ietf.org/rfc/rfc2131.txt
|
||||||
|
//
|
||||||
|
// Author: Andrew Lindsay
|
||||||
|
// Rewritten and optimized by Jean-Claude Wippler, http://jeelabs.org/
|
||||||
|
//
|
||||||
|
// Rewritten dhcpStateMachine by Chris van den Hooven
|
||||||
|
// as to implement dhcp-renew when lease expires (jun 2012)
|
||||||
|
//
|
||||||
|
// Various modifications and bug fixes contributed by Victor Aprea (oct 2012)
|
||||||
|
//
|
||||||
|
// Copyright: GPL V2
|
||||||
|
// See http://www.gnu.org/licenses/gpl.html
|
||||||
|
|
||||||
|
//#define DHCPDEBUG
|
||||||
|
|
||||||
|
#include "EtherCard.h"
|
||||||
|
#include "net.h"
|
||||||
|
|
||||||
|
#define gPB ether.buffer
|
||||||
|
|
||||||
|
#define DHCP_BOOTREQUEST 1
|
||||||
|
#define DHCP_BOOTRESPONSE 2
|
||||||
|
|
||||||
|
// DHCP Message Type (option 53) (ref RFC 2132)
|
||||||
|
#define DHCP_DISCOVER 1
|
||||||
|
#define DHCP_OFFER 2
|
||||||
|
#define DHCP_REQUEST 3
|
||||||
|
#define DHCP_DECLINE 4
|
||||||
|
#define DHCP_ACK 5
|
||||||
|
#define DHCP_NAK 6
|
||||||
|
#define DHCP_RELEASE 7
|
||||||
|
|
||||||
|
// DHCP States for access in applications (ref RFC 2131)
|
||||||
|
enum {
|
||||||
|
DHCP_STATE_INIT,
|
||||||
|
DHCP_STATE_SELECTING,
|
||||||
|
DHCP_STATE_REQUESTING,
|
||||||
|
DHCP_STATE_BOUND,
|
||||||
|
DHCP_STATE_RENEWING,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
op 1 Message op code / message type.
|
||||||
|
1 = BOOTREQUEST, 2 = BOOTREPLY
|
||||||
|
htype 1 Hardware address type, see ARP section in "Assigned
|
||||||
|
Numbers" RFC; e.g., '1' = 10mb ethernet.
|
||||||
|
hlen 1 Hardware address length (e.g. '6' for 10mb
|
||||||
|
ethernet).
|
||||||
|
hops 1 Client sets to zero, optionally used by relay agents
|
||||||
|
when booting via a relay agent.
|
||||||
|
xid 4 Transaction ID, a random number chosen by the
|
||||||
|
client, used by the client and server to associate
|
||||||
|
messages and responses between a client and a
|
||||||
|
server.
|
||||||
|
secs 2 Filled in by client, seconds elapsed since client
|
||||||
|
began address acquisition or renewal process.
|
||||||
|
flags 2 Flags (see figure 2).
|
||||||
|
ciaddr 4 Client IP address; only filled in if client is in
|
||||||
|
BOUND, RENEW or REBINDING state and can respond
|
||||||
|
to ARP requests.
|
||||||
|
yiaddr 4 'your' (client) IP address.
|
||||||
|
siaddr 4 IP address of next server to use in bootstrap;
|
||||||
|
returned in DHCPOFFER, DHCPACK by server.
|
||||||
|
giaddr 4 Relay agent IP address, used in booting via a
|
||||||
|
relay agent.
|
||||||
|
chaddr 16 Client hardware address.
|
||||||
|
sname 64 Optional server host name, null terminated string.
|
||||||
|
file 128 Boot file name, null terminated string; "generic"
|
||||||
|
name or null in DHCPDISCOVER, fully qualified
|
||||||
|
directory-path name in DHCPOFFER.
|
||||||
|
options var Optional parameters field. See the options
|
||||||
|
documents for a list of defined options.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// size 236
|
||||||
|
typedef struct {
|
||||||
|
byte op, htype, hlen, hops;
|
||||||
|
uint32_t xid;
|
||||||
|
uint16_t secs, flags;
|
||||||
|
byte ciaddr[4], yiaddr[4], siaddr[4], giaddr[4];
|
||||||
|
byte chaddr[16], sname[64], file[128];
|
||||||
|
// options
|
||||||
|
} DHCPdata;
|
||||||
|
|
||||||
|
#define DHCP_SERVER_PORT 67
|
||||||
|
#define DHCP_CLIENT_PORT 68
|
||||||
|
|
||||||
|
// timeouts im ms
|
||||||
|
#define DHCP_REQUEST_TIMEOUT 10000
|
||||||
|
|
||||||
|
#define DHCP_HOSTNAME_MAX_LEN 32
|
||||||
|
|
||||||
|
// RFC 2132 Section 3.3:
|
||||||
|
// The time value of 0xffffffff is reserved to represent "infinity".
|
||||||
|
#define DHCP_INFINITE_LEASE 0xffffffff
|
||||||
|
|
||||||
|
static byte dhcpState = DHCP_STATE_INIT;
|
||||||
|
static char hostname[DHCP_HOSTNAME_MAX_LEN] = "Arduino-00";
|
||||||
|
static uint32_t currentXid;
|
||||||
|
static uint32_t stateTimer;
|
||||||
|
static uint32_t leaseStart;
|
||||||
|
static uint32_t leaseTime;
|
||||||
|
static byte* bufPtr;
|
||||||
|
|
||||||
|
static uint8_t dhcpCustomOptionNum = 0;
|
||||||
|
static DhcpOptionCallback dhcpCustomOptionCallback = NULL;
|
||||||
|
|
||||||
|
// static uint8_t allOnes[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||||
|
|
||||||
|
static void addToBuf (byte b) {
|
||||||
|
*bufPtr++ = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void addBytes (byte len, const byte* data) {
|
||||||
|
while (len-- > 0)
|
||||||
|
addToBuf(*data++);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Main DHCP sending function
|
||||||
|
|
||||||
|
// implemented
|
||||||
|
// state / msgtype
|
||||||
|
// INIT / DHCPDISCOVER
|
||||||
|
// SELECTING / DHCPREQUEST
|
||||||
|
// BOUND (RENEWING) / DHCPREQUEST
|
||||||
|
|
||||||
|
// ----------------------------------------------------------
|
||||||
|
// | |SELECTING |RENEWING |INIT |
|
||||||
|
// ----------------------------------------------------------
|
||||||
|
// |broad/unicast |broadcast |unicast |broadcast |
|
||||||
|
// |server-ip |MUST |MUST NOT |MUST NOT | option 54
|
||||||
|
// |requested-ip |MUST |MUST NOT |MUST NOT | option 50
|
||||||
|
// |ciaddr |zero |IP address |zero |
|
||||||
|
// ----------------------------------------------------------
|
||||||
|
|
||||||
|
// options used (both send/receive)
|
||||||
|
// 12 Host Name Option
|
||||||
|
// 50 Requested IP Address
|
||||||
|
// 51 IP Address Lease Time
|
||||||
|
// 53 DHCP message type
|
||||||
|
// 54 Server-identifier
|
||||||
|
// 55 Parameter request list
|
||||||
|
// 58 Renewal (T1) Time Value
|
||||||
|
// 61 Client-identifier
|
||||||
|
// 255 End
|
||||||
|
|
||||||
|
static void send_dhcp_message(uint8_t *requestip) {
|
||||||
|
|
||||||
|
uint8_t allOnes[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||||
|
|
||||||
|
memset(gPB, 0, UDP_DATA_P + sizeof( DHCPdata ));
|
||||||
|
|
||||||
|
EtherCard::udpPrepare(DHCP_CLIENT_PORT,
|
||||||
|
(dhcpState == DHCP_STATE_BOUND ? EtherCard::dhcpip : allOnes),
|
||||||
|
DHCP_SERVER_PORT);
|
||||||
|
|
||||||
|
// If we ever don't do this, the DHCP renewal gets sent to whatever random
|
||||||
|
// destmacaddr was used by other code. Rather than cache the MAC address of
|
||||||
|
// the DHCP server, just force a broadcast here in all cases.
|
||||||
|
EtherCard::copyMac(gPB + ETH_DST_MAC, allOnes); //force broadcast mac
|
||||||
|
|
||||||
|
// Build DHCP Packet from buf[UDP_DATA_P]
|
||||||
|
DHCPdata *dhcpPtr = (DHCPdata*) (gPB + UDP_DATA_P);
|
||||||
|
dhcpPtr->op = DHCP_BOOTREQUEST;
|
||||||
|
dhcpPtr->htype = 1;
|
||||||
|
dhcpPtr->hlen = 6;
|
||||||
|
dhcpPtr->xid = currentXid;
|
||||||
|
if (dhcpState == DHCP_STATE_BOUND) {
|
||||||
|
EtherCard::copyIp(dhcpPtr->ciaddr, EtherCard::myip);
|
||||||
|
}
|
||||||
|
EtherCard::copyMac(dhcpPtr->chaddr, EtherCard::mymac);
|
||||||
|
|
||||||
|
// options defined as option, length, value
|
||||||
|
bufPtr = gPB + UDP_DATA_P + sizeof( DHCPdata );
|
||||||
|
// DHCP magic cookie, followed by message type
|
||||||
|
static byte cookie[] = { 99, 130, 83, 99, 53, 1 };
|
||||||
|
addBytes(sizeof cookie, cookie);
|
||||||
|
// addToBuf(53); // DHCP_STATE_SELECTING, DHCP_STATE_REQUESTING
|
||||||
|
// addToBuf(1); // Length
|
||||||
|
addToBuf(dhcpState == DHCP_STATE_INIT ? DHCP_DISCOVER : DHCP_REQUEST);
|
||||||
|
|
||||||
|
// Client Identifier Option, this is the client mac address
|
||||||
|
addToBuf(61); // Client identifier
|
||||||
|
addToBuf(7); // Length
|
||||||
|
addToBuf(0x01); // Ethernet
|
||||||
|
addBytes(6, EtherCard::mymac);
|
||||||
|
|
||||||
|
addToBuf(12); // Host name Option
|
||||||
|
addToBuf(10);
|
||||||
|
addBytes(10, (byte*) hostname);
|
||||||
|
|
||||||
|
if (requestip != NULL) {
|
||||||
|
addToBuf(50); // Request IP address
|
||||||
|
addToBuf(4);
|
||||||
|
addBytes(4, requestip);
|
||||||
|
|
||||||
|
addToBuf(54); // DHCP Server IP address
|
||||||
|
addToBuf(4);
|
||||||
|
addBytes(4, EtherCard::dhcpip);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Additional info in parameter list - minimal list for what we need
|
||||||
|
byte len = 3;
|
||||||
|
if (dhcpCustomOptionNum)
|
||||||
|
len++;
|
||||||
|
addToBuf(55); // Parameter request list
|
||||||
|
addToBuf(len); // Length
|
||||||
|
addToBuf(1); // Subnet mask
|
||||||
|
addToBuf(3); // Route/Gateway
|
||||||
|
addToBuf(6); // DNS Server
|
||||||
|
if (dhcpCustomOptionNum)
|
||||||
|
addToBuf(dhcpCustomOptionNum); // Custom option
|
||||||
|
addToBuf(255); // end option
|
||||||
|
|
||||||
|
// packet size will be under 300 bytes
|
||||||
|
EtherCard::udpTransmit((bufPtr - gPB) - UDP_DATA_P);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void process_dhcp_offer(uint16_t len, uint8_t *offeredip) {
|
||||||
|
// Map struct onto payload
|
||||||
|
DHCPdata *dhcpPtr = (DHCPdata*) (gPB + UDP_DATA_P);
|
||||||
|
|
||||||
|
// Offered IP address is in yiaddr
|
||||||
|
EtherCard::copyIp(offeredip, dhcpPtr->yiaddr);
|
||||||
|
|
||||||
|
// Search for the
|
||||||
|
byte *ptr = (byte*) (dhcpPtr + 1) + 4;
|
||||||
|
do {
|
||||||
|
byte option = *ptr++;
|
||||||
|
byte optionLen = *ptr++;
|
||||||
|
if (option == 54) {
|
||||||
|
EtherCard::copyIp(EtherCard::dhcpip, ptr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ptr += optionLen;
|
||||||
|
} while (ptr < gPB + len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void process_dhcp_ack(uint16_t len) {
|
||||||
|
// Map struct onto payload
|
||||||
|
DHCPdata *dhcpPtr = (DHCPdata*) (gPB + UDP_DATA_P);
|
||||||
|
|
||||||
|
// Allocated IP address is in yiaddr
|
||||||
|
EtherCard::copyIp(EtherCard::myip, dhcpPtr->yiaddr);
|
||||||
|
|
||||||
|
// Scan through variable length option list identifying options we want
|
||||||
|
byte *ptr = (byte*) (dhcpPtr + 1) + 4;
|
||||||
|
bool done = false;
|
||||||
|
do {
|
||||||
|
byte option = *ptr++;
|
||||||
|
byte optionLen = *ptr++;
|
||||||
|
switch (option) {
|
||||||
|
case 1:
|
||||||
|
EtherCard::copyIp(EtherCard::netmask, ptr);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
EtherCard::copyIp(EtherCard::gwip, ptr);
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
EtherCard::copyIp(EtherCard::dnsip, ptr);
|
||||||
|
break;
|
||||||
|
case 51:
|
||||||
|
case 58:
|
||||||
|
leaseTime = 0; // option 58 = Renewal Time, 51 = Lease Time
|
||||||
|
for (byte i = 0; i<4; i++)
|
||||||
|
leaseTime = (leaseTime << 8) + ptr[i];
|
||||||
|
if (leaseTime != DHCP_INFINITE_LEASE) {
|
||||||
|
leaseTime *= 1000; // milliseconds
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 255:
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
default: {
|
||||||
|
// Is is a custom configured option?
|
||||||
|
if (dhcpCustomOptionCallback && option == dhcpCustomOptionNum) {
|
||||||
|
dhcpCustomOptionCallback(option, ptr, optionLen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ptr += optionLen;
|
||||||
|
} while (!done && ptr < gPB + len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool dhcp_received_message_type (uint16_t len, byte msgType) {
|
||||||
|
// Map struct onto payload
|
||||||
|
DHCPdata *dhcpPtr = (DHCPdata*) (gPB + UDP_DATA_P);
|
||||||
|
|
||||||
|
if (len >= 70 && gPB[UDP_SRC_PORT_L_P] == DHCP_SERVER_PORT &&
|
||||||
|
dhcpPtr->xid == currentXid ) {
|
||||||
|
|
||||||
|
byte *ptr = (byte*) (dhcpPtr + 1) + 4;
|
||||||
|
do {
|
||||||
|
byte option = *ptr++;
|
||||||
|
byte optionLen = *ptr++;
|
||||||
|
if(option == 53 && *ptr == msgType ) {
|
||||||
|
// DHCP Message type match found
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
ptr += optionLen;
|
||||||
|
} while (ptr < gPB + len);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char toAsciiHex(byte b) {
|
||||||
|
char c = b & 0x0f;
|
||||||
|
c += (c <= 9) ? '0' : 'A'-10;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EtherCard::dhcpSetup (const char *hname, bool fromRam) {
|
||||||
|
// Use during setup, as this discards all incoming requests until it returns.
|
||||||
|
// That shouldn't be a problem, because we don't have an IP-address yet.
|
||||||
|
// Will try 60 secs to obtain DHCP-lease.
|
||||||
|
|
||||||
|
using_dhcp = true;
|
||||||
|
|
||||||
|
if(hname != NULL) {
|
||||||
|
if(fromRam) {
|
||||||
|
strncpy(hostname, hname, DHCP_HOSTNAME_MAX_LEN);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
strncpy_P(hostname, hname, DHCP_HOSTNAME_MAX_LEN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Set a unique hostname, use Arduino-?? with last octet of mac address
|
||||||
|
hostname[8] = toAsciiHex(mymac[5] >> 4);
|
||||||
|
hostname[9] = toAsciiHex(mymac[5]);
|
||||||
|
}
|
||||||
|
|
||||||
|
dhcpState = DHCP_STATE_INIT;
|
||||||
|
uint16_t start = millis();
|
||||||
|
|
||||||
|
while (dhcpState != DHCP_STATE_BOUND && (uint16_t) (millis() - start) < 60000) {
|
||||||
|
if (isLinkUp()) DhcpStateMachine(packetReceive());
|
||||||
|
}
|
||||||
|
updateBroadcastAddress();
|
||||||
|
delaycnt = 0;
|
||||||
|
return dhcpState == DHCP_STATE_BOUND ;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EtherCard::dhcpAddOptionCallback(uint8_t option, DhcpOptionCallback callback)
|
||||||
|
{
|
||||||
|
dhcpCustomOptionNum = option;
|
||||||
|
dhcpCustomOptionCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EtherCard::DhcpStateMachine (uint16_t len)
|
||||||
|
{
|
||||||
|
|
||||||
|
#ifdef DHCPDEBUG
|
||||||
|
if (dhcpState != DHCP_STATE_BOUND) {
|
||||||
|
Serial.print(millis());
|
||||||
|
Serial.print(" State: ");
|
||||||
|
}
|
||||||
|
switch (dhcpState) {
|
||||||
|
case DHCP_STATE_INIT:
|
||||||
|
Serial.println("Init");
|
||||||
|
break;
|
||||||
|
case DHCP_STATE_SELECTING:
|
||||||
|
Serial.println("Selecting");
|
||||||
|
break;
|
||||||
|
case DHCP_STATE_REQUESTING:
|
||||||
|
Serial.println("Requesting");
|
||||||
|
break;
|
||||||
|
case DHCP_STATE_RENEWING:
|
||||||
|
Serial.println("Renew");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
switch (dhcpState) {
|
||||||
|
|
||||||
|
case DHCP_STATE_BOUND:
|
||||||
|
//!@todo Due to millis() 49 day wrap-around, DHCP renewal may not work as expected
|
||||||
|
if (leaseTime != DHCP_INFINITE_LEASE && millis() >= leaseStart + leaseTime) {
|
||||||
|
send_dhcp_message(myip);
|
||||||
|
dhcpState = DHCP_STATE_RENEWING;
|
||||||
|
stateTimer = millis();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DHCP_STATE_INIT:
|
||||||
|
currentXid = millis();
|
||||||
|
memset(myip,0,4); // force ip 0.0.0.0
|
||||||
|
send_dhcp_message(NULL);
|
||||||
|
enableBroadcast(true); //Temporarily enable broadcasts
|
||||||
|
dhcpState = DHCP_STATE_SELECTING;
|
||||||
|
stateTimer = millis();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DHCP_STATE_SELECTING:
|
||||||
|
if (dhcp_received_message_type(len, DHCP_OFFER)) {
|
||||||
|
uint8_t offeredip[4];
|
||||||
|
process_dhcp_offer(len, offeredip);
|
||||||
|
send_dhcp_message(offeredip);
|
||||||
|
dhcpState = DHCP_STATE_REQUESTING;
|
||||||
|
stateTimer = millis();
|
||||||
|
} else {
|
||||||
|
if (millis() > stateTimer + DHCP_REQUEST_TIMEOUT) {
|
||||||
|
dhcpState = DHCP_STATE_INIT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DHCP_STATE_REQUESTING:
|
||||||
|
case DHCP_STATE_RENEWING:
|
||||||
|
if (dhcp_received_message_type(len, DHCP_ACK)) {
|
||||||
|
disableBroadcast(true); //Disable broadcast after temporary enable
|
||||||
|
process_dhcp_ack(len);
|
||||||
|
leaseStart = millis();
|
||||||
|
if (gwip[0] != 0) setGwIp(gwip); // why is this? because it initiates an arp request
|
||||||
|
dhcpState = DHCP_STATE_BOUND;
|
||||||
|
} else {
|
||||||
|
if (millis() > stateTimer + DHCP_REQUEST_TIMEOUT) {
|
||||||
|
dhcpState = DHCP_STATE_INIT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
117
lib-ext/ethercard.git/dns.cpp
Normal file
117
lib-ext/ethercard.git/dns.cpp
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
// DNS look-up functions based on the udp client
|
||||||
|
// Author: Guido Socher
|
||||||
|
// Copyright: GPL V2
|
||||||
|
//
|
||||||
|
// 2010-05-20 <jc@wippler.nl>
|
||||||
|
|
||||||
|
#include "EtherCard.h"
|
||||||
|
#include "net.h"
|
||||||
|
|
||||||
|
#define gPB ether.buffer
|
||||||
|
|
||||||
|
static byte dnstid_l; // a counter for transaction ID
|
||||||
|
#define DNSCLIENT_SRC_PORT_H 0xE0
|
||||||
|
|
||||||
|
static void dnsRequest (const char *hostname, bool fromRam) {
|
||||||
|
++dnstid_l; // increment for next request, finally wrap
|
||||||
|
if (ether.dnsip[0] == 0)
|
||||||
|
memset(ether.dnsip, 8, 4); // use 8.8.8.8 Google DNS as default
|
||||||
|
ether.udpPrepare((DNSCLIENT_SRC_PORT_H << 8) | dnstid_l, ether.dnsip, 53);
|
||||||
|
memset(gPB + UDP_DATA_P, 0, 12);
|
||||||
|
|
||||||
|
byte *p = gPB + UDP_DATA_P + 12;
|
||||||
|
char c;
|
||||||
|
do {
|
||||||
|
byte n = 0;
|
||||||
|
for(;;) {
|
||||||
|
c = fromRam ? *hostname : pgm_read_byte(hostname);
|
||||||
|
++hostname;
|
||||||
|
if (c == '.' || c == 0)
|
||||||
|
break;
|
||||||
|
p[++n] = c;
|
||||||
|
}
|
||||||
|
*p++ = n;
|
||||||
|
p += n;
|
||||||
|
} while (c != 0);
|
||||||
|
|
||||||
|
*p++ = 0; // terminate with zero, means root domain.
|
||||||
|
*p++ = 0;
|
||||||
|
*p++ = 1; // type A
|
||||||
|
*p++ = 0;
|
||||||
|
*p++ = 1; // class IN
|
||||||
|
byte i = p - gPB - UDP_DATA_P;
|
||||||
|
gPB[UDP_DATA_P] = i;
|
||||||
|
gPB[UDP_DATA_P+1] = dnstid_l;
|
||||||
|
gPB[UDP_DATA_P+2] = 1; // flags, standard recursive query
|
||||||
|
gPB[UDP_DATA_P+5] = 1; // 1 question
|
||||||
|
ether.udpTransmit(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Check if packet is DNS response.
|
||||||
|
@param plen Size of packet
|
||||||
|
@return <i>bool</i> True if DNS response has error. False if not DNS response or DNS response OK.
|
||||||
|
@note hisip contains IP address of requested host or 0.0.0.0 on failure
|
||||||
|
*/
|
||||||
|
static bool checkForDnsAnswer (uint16_t plen) {
|
||||||
|
byte *p = gPB + UDP_DATA_P; //start of UDP payload
|
||||||
|
if (plen < 70 || gPB[UDP_SRC_PORT_L_P] != 53 || //from DNS source port
|
||||||
|
gPB[UDP_DST_PORT_H_P] != DNSCLIENT_SRC_PORT_H || //response to same port as we sent from (MSB)
|
||||||
|
gPB[UDP_DST_PORT_L_P] != dnstid_l || //response to same port as we sent from (LSB)
|
||||||
|
p[1] != dnstid_l) //message id same as we sent
|
||||||
|
return false; //not our DNS response
|
||||||
|
if((p[3] & 0x0F) != 0)
|
||||||
|
return true; //DNS response recieved with error
|
||||||
|
|
||||||
|
p += *p; // we encoded the query len into tid
|
||||||
|
for (;;) {
|
||||||
|
if (*p & 0xC0)
|
||||||
|
p += 2;
|
||||||
|
else
|
||||||
|
while (++p < gPB + plen) {
|
||||||
|
if (*p == 0) {
|
||||||
|
++p;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (p + 14 > gPB + plen)
|
||||||
|
break;
|
||||||
|
if (p[1] == 1 && p[9] == 4) { // type "A" and IPv4
|
||||||
|
ether.copyIp(ether.hisip, p + 10);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
p += p[9] + 10;
|
||||||
|
}
|
||||||
|
return false; //No error
|
||||||
|
}
|
||||||
|
|
||||||
|
// use during setup, as this discards all incoming requests until it returns
|
||||||
|
bool EtherCard::dnsLookup (const char* name, bool fromRam) {
|
||||||
|
word start = millis();
|
||||||
|
|
||||||
|
while(!isLinkUp())
|
||||||
|
{
|
||||||
|
if ((word) (millis() - start) >= 30000)
|
||||||
|
return false; //timeout waiting for link
|
||||||
|
}
|
||||||
|
while(clientWaitingDns())
|
||||||
|
{
|
||||||
|
packetLoop(packetReceive());
|
||||||
|
if ((word) (millis() - start) >= 30000)
|
||||||
|
return false; //timeout waiting for gateway ARP
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(hisip, 0, 4);
|
||||||
|
dnsRequest(name, fromRam);
|
||||||
|
|
||||||
|
start = millis();
|
||||||
|
while (hisip[0] == 0) {
|
||||||
|
if ((word) (millis() - start) >= 30000)
|
||||||
|
return false; //timout waiting for dns response
|
||||||
|
word len = packetReceive();
|
||||||
|
if (len > 0 && packetLoop(len) == 0) //packet not handled by tcp/ip packet loop
|
||||||
|
if(checkForDnsAnswer(len))
|
||||||
|
return false; //DNS response recieved with error
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
96
lib-ext/ethercard.git/docu.dox
Normal file
96
lib-ext/ethercard.git/docu.dox
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
/**
|
||||||
|
@mainpage EtherCard is a driver for the ENC28J60 chip, compatible with Arduino IDE.<br/>
|
||||||
|
Adapted and extended from code written by Guido Socher and Pascal Stang.<br/>
|
||||||
|
The home page for this library is at http://jeelabs.net/projects/ethercard/wiki.<br/>
|
||||||
|
License: <a href="http://www.gnu.org/licenses/gpl-2.0.html">GPL2</a><br/><br/>
|
||||||
|
<b>PIN Connections (Using Arduino UNO):</b>
|
||||||
|
<table border="1">
|
||||||
|
<tr><th>EtherCard</th><th>Arduino UNO</th></tr>
|
||||||
|
<tr><td>VCC</td><td>3.3V</td></tr>
|
||||||
|
<tr><td>GND</td><td>GND</td></tr>
|
||||||
|
<tr><td>SCK</td><td>Pin 13</td></tr>
|
||||||
|
<tr><td>SO</td><td>Pin 12</td></tr>
|
||||||
|
<tr><td>SI</td><td>Pin 11</td></tr>
|
||||||
|
<tr><td>CS</td><td>Pin 8</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
@section intro_sec Introduction
|
||||||
|
EtherCard is a library that performs low-level interfacing with network interfaces based on the MicroChip (C) ENC28J60.
|
||||||
|
High-level routines are provided to allow a variety of purposes including simple data transfer through to HTTP handling.
|
||||||
|
EtherCard is a driver for the ENC28J60 chip, compatible with Arduino IDE.
|
||||||
|
|
||||||
|
Adapted and extended from code written by Guido Socher and Pascal Stang.
|
||||||
|
|
||||||
|
The documentation for this library is at http://jeelabs.net/pub/docs/ethercard/
|
||||||
|
|
||||||
|
The code is available on GitHub, at https://github.com/jcw/ethercard - to install:
|
||||||
|
|
||||||
|
Download the ZIP file from https://github.com/jcw/ethercard/archive/master.zip
|
||||||
|
From the Arduino IDE: Sketch -> Import Library... -> Add Library...
|
||||||
|
Restart the Arduino IDE to see the new "EtherCard" library with examples
|
||||||
|
See the comments in the example sketches for details about how to try them out.
|
||||||
|
|
||||||
|
For questions and help, see the forums. For bugs and feature requests, see the issue tracker.
|
||||||
|
@section eg_sec Examples
|
||||||
|
Several @link examples example scripts @endlink are provided with the library which demonstrate various features. Below are descriptions on how to use the library.
|
||||||
|
|
||||||
|
<p>Note: <b>ether</b> is defined globally and may be used to access the library thus: ether.<i>member</i>.
|
||||||
|
|
||||||
|
@subsection Initiate To initiate the library call EtherCard::begin
|
||||||
|
<pre>
|
||||||
|
uint8_t Ethernet::buffer[700]; // configure buffer size to 700 octets
|
||||||
|
static uint8_t mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 }; // define (unique on LAN) hardware (MAC) address
|
||||||
|
|
||||||
|
uint8_type nFirmwareVersion ether.begin(sizeof Ethernet::buffer, mymac);
|
||||||
|
if(0 == nFirmwareVersion)
|
||||||
|
{
|
||||||
|
// handle failure to initiate network interface
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
@subsection DHCP To configure IP address via DHCP use EtherCard::dhcpSetup
|
||||||
|
<pre>
|
||||||
|
if(!ether.dhcpSetup())
|
||||||
|
{
|
||||||
|
// handle failure to obtain IP address via DHCP
|
||||||
|
}
|
||||||
|
ether.printIp("IP: ", ether.myip); // output IP address to Serial
|
||||||
|
ether.printIp("GW: ", ether.gwip); // output gateway address to Serial
|
||||||
|
ether.printIp("Mask: ", ether.mymask); // output netmask to Serial
|
||||||
|
ether.printIp("DHCP server: ", ether.dhcpip); // output IP address of the DHCP server
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
@subsection StaticIP To configure a static IP address use EtherCard::staticSetup
|
||||||
|
<pre>
|
||||||
|
const static uint8_t ip[] = {192,168,0,100};
|
||||||
|
const static uint8_t gw[] = {192,168,0,254};
|
||||||
|
const static uint8_t dns[] = {192,168,0,1};
|
||||||
|
|
||||||
|
if(!ether.staticSetup(ip, gw, dns);
|
||||||
|
{
|
||||||
|
// handle failure to configure static IP address (current implementation always returns true!)
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
@subsection SendUDP Send UDP packet
|
||||||
|
To send a UDP packet use EtherCard::sendUdp
|
||||||
|
<pre>
|
||||||
|
char payload[] = "My UDP message";
|
||||||
|
uint8_t nSourcePort = 1234;
|
||||||
|
uint8_t nDestinationPort = 5678;
|
||||||
|
uint8_t ipDestinationAddress[4];
|
||||||
|
ether.parseIp(ipDestinationAddress, "192.168.0.200");
|
||||||
|
|
||||||
|
ether.sendUdp(payload, sizeof(payload), nSourcePort, ipDestinationAddress, nDestinationPort);
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
@subsection DNSLookup DNS Lookup
|
||||||
|
To perform a DNS lookup use EtherCard::dnsLookup
|
||||||
|
<pre>
|
||||||
|
if(!ether.dnsLookup("google.com"))
|
||||||
|
{
|
||||||
|
// handle failure of DNS lookup
|
||||||
|
}
|
||||||
|
ether.printIp("Server: ", ether.hispip); // Result of DNS lookup is placed in the hisip member of EtherCard.
|
||||||
|
</pre>
|
||||||
|
*/
|
611
lib-ext/ethercard.git/enc28j60.cpp
Normal file
611
lib-ext/ethercard.git/enc28j60.cpp
Normal file
|
@ -0,0 +1,611 @@
|
||||||
|
// Microchip ENC28J60 Ethernet Interface Driver
|
||||||
|
// Author: Guido Socher
|
||||||
|
// Copyright: GPL V2
|
||||||
|
//
|
||||||
|
// Based on the enc28j60.c file from the AVRlib library by Pascal Stang.
|
||||||
|
// For AVRlib See http://www.procyonengineering.com/
|
||||||
|
// Used with explicit permission of Pascal Stang.
|
||||||
|
//
|
||||||
|
// 2010-05-20 <jc@wippler.nl>
|
||||||
|
|
||||||
|
#if ARDUINO >= 100
|
||||||
|
#include <Arduino.h> // Arduino 1.0
|
||||||
|
#else
|
||||||
|
#include <Wprogram.h> // Arduino 0022
|
||||||
|
#endif
|
||||||
|
#include "enc28j60.h"
|
||||||
|
|
||||||
|
uint16_t ENC28J60::bufferSize;
|
||||||
|
bool ENC28J60::broadcast_enabled = false;
|
||||||
|
|
||||||
|
// ENC28J60 Control Registers
|
||||||
|
// Control register definitions are a combination of address,
|
||||||
|
// bank number, and Ethernet/MAC/PHY indicator bits.
|
||||||
|
// - Register address (bits 0-4)
|
||||||
|
// - Bank number (bits 5-6)
|
||||||
|
// - MAC/PHY indicator (bit 7)
|
||||||
|
#define ADDR_MASK 0x1F
|
||||||
|
#define BANK_MASK 0x60
|
||||||
|
#define SPRD_MASK 0x80
|
||||||
|
// All-bank registers
|
||||||
|
#define EIE 0x1B
|
||||||
|
#define EIR 0x1C
|
||||||
|
#define ESTAT 0x1D
|
||||||
|
#define ECON2 0x1E
|
||||||
|
#define ECON1 0x1F
|
||||||
|
// Bank 0 registers
|
||||||
|
#define ERDPT (0x00|0x00)
|
||||||
|
#define EWRPT (0x02|0x00)
|
||||||
|
#define ETXST (0x04|0x00)
|
||||||
|
#define ETXND (0x06|0x00)
|
||||||
|
#define ERXST (0x08|0x00)
|
||||||
|
#define ERXND (0x0A|0x00)
|
||||||
|
#define ERXRDPT (0x0C|0x00)
|
||||||
|
// #define ERXWRPT (0x0E|0x00)
|
||||||
|
#define EDMAST (0x10|0x00)
|
||||||
|
#define EDMAND (0x12|0x00)
|
||||||
|
// #define EDMADST (0x14|0x00)
|
||||||
|
#define EDMACS (0x16|0x00)
|
||||||
|
// Bank 1 registers
|
||||||
|
#define EHT0 (0x00|0x20)
|
||||||
|
#define EHT1 (0x01|0x20)
|
||||||
|
#define EHT2 (0x02|0x20)
|
||||||
|
#define EHT3 (0x03|0x20)
|
||||||
|
#define EHT4 (0x04|0x20)
|
||||||
|
#define EHT5 (0x05|0x20)
|
||||||
|
#define EHT6 (0x06|0x20)
|
||||||
|
#define EHT7 (0x07|0x20)
|
||||||
|
#define EPMM0 (0x08|0x20)
|
||||||
|
#define EPMM1 (0x09|0x20)
|
||||||
|
#define EPMM2 (0x0A|0x20)
|
||||||
|
#define EPMM3 (0x0B|0x20)
|
||||||
|
#define EPMM4 (0x0C|0x20)
|
||||||
|
#define EPMM5 (0x0D|0x20)
|
||||||
|
#define EPMM6 (0x0E|0x20)
|
||||||
|
#define EPMM7 (0x0F|0x20)
|
||||||
|
#define EPMCS (0x10|0x20)
|
||||||
|
// #define EPMO (0x14|0x20)
|
||||||
|
#define EWOLIE (0x16|0x20)
|
||||||
|
#define EWOLIR (0x17|0x20)
|
||||||
|
#define ERXFCON (0x18|0x20)
|
||||||
|
#define EPKTCNT (0x19|0x20)
|
||||||
|
// Bank 2 registers
|
||||||
|
#define MACON1 (0x00|0x40|0x80)
|
||||||
|
#define MACON2 (0x01|0x40|0x80)
|
||||||
|
#define MACON3 (0x02|0x40|0x80)
|
||||||
|
#define MACON4 (0x03|0x40|0x80)
|
||||||
|
#define MABBIPG (0x04|0x40|0x80)
|
||||||
|
#define MAIPG (0x06|0x40|0x80)
|
||||||
|
#define MACLCON1 (0x08|0x40|0x80)
|
||||||
|
#define MACLCON2 (0x09|0x40|0x80)
|
||||||
|
#define MAMXFL (0x0A|0x40|0x80)
|
||||||
|
#define MAPHSUP (0x0D|0x40|0x80)
|
||||||
|
#define MICON (0x11|0x40|0x80)
|
||||||
|
#define MICMD (0x12|0x40|0x80)
|
||||||
|
#define MIREGADR (0x14|0x40|0x80)
|
||||||
|
#define MIWR (0x16|0x40|0x80)
|
||||||
|
#define MIRD (0x18|0x40|0x80)
|
||||||
|
// Bank 3 registers
|
||||||
|
#define MAADR1 (0x00|0x60|0x80)
|
||||||
|
#define MAADR0 (0x01|0x60|0x80)
|
||||||
|
#define MAADR3 (0x02|0x60|0x80)
|
||||||
|
#define MAADR2 (0x03|0x60|0x80)
|
||||||
|
#define MAADR5 (0x04|0x60|0x80)
|
||||||
|
#define MAADR4 (0x05|0x60|0x80)
|
||||||
|
#define EBSTSD (0x06|0x60)
|
||||||
|
#define EBSTCON (0x07|0x60)
|
||||||
|
#define EBSTCS (0x08|0x60)
|
||||||
|
#define MISTAT (0x0A|0x60|0x80)
|
||||||
|
#define EREVID (0x12|0x60)
|
||||||
|
#define ECOCON (0x15|0x60)
|
||||||
|
#define EFLOCON (0x17|0x60)
|
||||||
|
#define EPAUS (0x18|0x60)
|
||||||
|
|
||||||
|
// ENC28J60 ERXFCON Register Bit Definitions
|
||||||
|
#define ERXFCON_UCEN 0x80
|
||||||
|
#define ERXFCON_ANDOR 0x40
|
||||||
|
#define ERXFCON_CRCEN 0x20
|
||||||
|
#define ERXFCON_PMEN 0x10
|
||||||
|
#define ERXFCON_MPEN 0x08
|
||||||
|
#define ERXFCON_HTEN 0x04
|
||||||
|
#define ERXFCON_MCEN 0x02
|
||||||
|
#define ERXFCON_BCEN 0x01
|
||||||
|
// ENC28J60 EIE Register Bit Definitions
|
||||||
|
#define EIE_INTIE 0x80
|
||||||
|
#define EIE_PKTIE 0x40
|
||||||
|
#define EIE_DMAIE 0x20
|
||||||
|
#define EIE_LINKIE 0x10
|
||||||
|
#define EIE_TXIE 0x08
|
||||||
|
#define EIE_WOLIE 0x04
|
||||||
|
#define EIE_TXERIE 0x02
|
||||||
|
#define EIE_RXERIE 0x01
|
||||||
|
// ENC28J60 EIR Register Bit Definitions
|
||||||
|
#define EIR_PKTIF 0x40
|
||||||
|
#define EIR_DMAIF 0x20
|
||||||
|
#define EIR_LINKIF 0x10
|
||||||
|
#define EIR_TXIF 0x08
|
||||||
|
#define EIR_WOLIF 0x04
|
||||||
|
#define EIR_TXERIF 0x02
|
||||||
|
#define EIR_RXERIF 0x01
|
||||||
|
// ENC28J60 ESTAT Register Bit Definitions
|
||||||
|
#define ESTAT_INT 0x80
|
||||||
|
#define ESTAT_LATECOL 0x10
|
||||||
|
#define ESTAT_RXBUSY 0x04
|
||||||
|
#define ESTAT_TXABRT 0x02
|
||||||
|
#define ESTAT_CLKRDY 0x01
|
||||||
|
// ENC28J60 ECON2 Register Bit Definitions
|
||||||
|
#define ECON2_AUTOINC 0x80
|
||||||
|
#define ECON2_PKTDEC 0x40
|
||||||
|
#define ECON2_PWRSV 0x20
|
||||||
|
#define ECON2_VRPS 0x08
|
||||||
|
// ENC28J60 ECON1 Register Bit Definitions
|
||||||
|
#define ECON1_TXRST 0x80
|
||||||
|
#define ECON1_RXRST 0x40
|
||||||
|
#define ECON1_DMAST 0x20
|
||||||
|
#define ECON1_CSUMEN 0x10
|
||||||
|
#define ECON1_TXRTS 0x08
|
||||||
|
#define ECON1_RXEN 0x04
|
||||||
|
#define ECON1_BSEL1 0x02
|
||||||
|
#define ECON1_BSEL0 0x01
|
||||||
|
// ENC28J60 MACON1 Register Bit Definitions
|
||||||
|
#define MACON1_LOOPBK 0x10
|
||||||
|
#define MACON1_TXPAUS 0x08
|
||||||
|
#define MACON1_RXPAUS 0x04
|
||||||
|
#define MACON1_PASSALL 0x02
|
||||||
|
#define MACON1_MARXEN 0x01
|
||||||
|
// ENC28J60 MACON2 Register Bit Definitions
|
||||||
|
#define MACON2_MARST 0x80
|
||||||
|
#define MACON2_RNDRST 0x40
|
||||||
|
#define MACON2_MARXRST 0x08
|
||||||
|
#define MACON2_RFUNRST 0x04
|
||||||
|
#define MACON2_MATXRST 0x02
|
||||||
|
#define MACON2_TFUNRST 0x01
|
||||||
|
// ENC28J60 MACON3 Register Bit Definitions
|
||||||
|
#define MACON3_PADCFG2 0x80
|
||||||
|
#define MACON3_PADCFG1 0x40
|
||||||
|
#define MACON3_PADCFG0 0x20
|
||||||
|
#define MACON3_TXCRCEN 0x10
|
||||||
|
#define MACON3_PHDRLEN 0x08
|
||||||
|
#define MACON3_HFRMLEN 0x04
|
||||||
|
#define MACON3_FRMLNEN 0x02
|
||||||
|
#define MACON3_FULDPX 0x01
|
||||||
|
// ENC28J60 MICMD Register Bit Definitions
|
||||||
|
#define MICMD_MIISCAN 0x02
|
||||||
|
#define MICMD_MIIRD 0x01
|
||||||
|
// ENC28J60 MISTAT Register Bit Definitions
|
||||||
|
#define MISTAT_NVALID 0x04
|
||||||
|
#define MISTAT_SCAN 0x02
|
||||||
|
#define MISTAT_BUSY 0x01
|
||||||
|
|
||||||
|
// ENC28J60 EBSTCON Register Bit Definitions
|
||||||
|
#define EBSTCON_PSV2 0x80
|
||||||
|
#define EBSTCON_PSV1 0x40
|
||||||
|
#define EBSTCON_PSV0 0x20
|
||||||
|
#define EBSTCON_PSEL 0x10
|
||||||
|
#define EBSTCON_TMSEL1 0x08
|
||||||
|
#define EBSTCON_TMSEL0 0x04
|
||||||
|
#define EBSTCON_TME 0x02
|
||||||
|
#define EBSTCON_BISTST 0x01
|
||||||
|
|
||||||
|
// PHY registers
|
||||||
|
#define PHCON1 0x00
|
||||||
|
#define PHSTAT1 0x01
|
||||||
|
#define PHHID1 0x02
|
||||||
|
#define PHHID2 0x03
|
||||||
|
#define PHCON2 0x10
|
||||||
|
#define PHSTAT2 0x11
|
||||||
|
#define PHIE 0x12
|
||||||
|
#define PHIR 0x13
|
||||||
|
#define PHLCON 0x14
|
||||||
|
|
||||||
|
// ENC28J60 PHY PHCON1 Register Bit Definitions
|
||||||
|
#define PHCON1_PRST 0x8000
|
||||||
|
#define PHCON1_PLOOPBK 0x4000
|
||||||
|
#define PHCON1_PPWRSV 0x0800
|
||||||
|
#define PHCON1_PDPXMD 0x0100
|
||||||
|
// ENC28J60 PHY PHSTAT1 Register Bit Definitions
|
||||||
|
#define PHSTAT1_PFDPX 0x1000
|
||||||
|
#define PHSTAT1_PHDPX 0x0800
|
||||||
|
#define PHSTAT1_LLSTAT 0x0004
|
||||||
|
#define PHSTAT1_JBSTAT 0x0002
|
||||||
|
// ENC28J60 PHY PHCON2 Register Bit Definitions
|
||||||
|
#define PHCON2_FRCLINK 0x4000
|
||||||
|
#define PHCON2_TXDIS 0x2000
|
||||||
|
#define PHCON2_JABBER 0x0400
|
||||||
|
#define PHCON2_HDLDIS 0x0100
|
||||||
|
|
||||||
|
// ENC28J60 Packet Control Byte Bit Definitions
|
||||||
|
#define PKTCTRL_PHUGEEN 0x08
|
||||||
|
#define PKTCTRL_PPADEN 0x04
|
||||||
|
#define PKTCTRL_PCRCEN 0x02
|
||||||
|
#define PKTCTRL_POVERRIDE 0x01
|
||||||
|
|
||||||
|
// SPI operation codes
|
||||||
|
#define ENC28J60_READ_CTRL_REG 0x00
|
||||||
|
#define ENC28J60_READ_BUF_MEM 0x3A
|
||||||
|
#define ENC28J60_WRITE_CTRL_REG 0x40
|
||||||
|
#define ENC28J60_WRITE_BUF_MEM 0x7A
|
||||||
|
#define ENC28J60_BIT_FIELD_SET 0x80
|
||||||
|
#define ENC28J60_BIT_FIELD_CLR 0xA0
|
||||||
|
#define ENC28J60_SOFT_RESET 0xFF
|
||||||
|
|
||||||
|
// The RXSTART_INIT must be zero. See Rev. B4 Silicon Errata point 5.
|
||||||
|
// Buffer boundaries applied to internal 8K ram
|
||||||
|
// the entire available packet buffer space is allocated
|
||||||
|
|
||||||
|
#define RXSTART_INIT 0x0000 // start of RX buffer, room for 2 packets
|
||||||
|
#define RXSTOP_INIT 0x0BFF // end of RX buffer
|
||||||
|
|
||||||
|
#define TXSTART_INIT 0x0C00 // start of TX buffer, room for 1 packet
|
||||||
|
#define TXSTOP_INIT 0x11FF // end of TX buffer
|
||||||
|
|
||||||
|
#define SCRATCH_START 0x1200 // start of scratch area
|
||||||
|
#define SCRATCH_LIMIT 0x2000 // past end of area, i.e. 3.5 Kb
|
||||||
|
#define SCRATCH_PAGE_SHIFT 6 // addressing is in pages of 64 bytes
|
||||||
|
#define SCRATCH_PAGE_SIZE (1 << SCRATCH_PAGE_SHIFT)
|
||||||
|
|
||||||
|
// max frame length which the conroller will accept:
|
||||||
|
// (note: maximum ethernet frame length would be 1518)
|
||||||
|
#define MAX_FRAMELEN 1500
|
||||||
|
|
||||||
|
#define FULL_SPEED 1 // switch to full-speed SPI for bulk transfers
|
||||||
|
|
||||||
|
static byte Enc28j60Bank;
|
||||||
|
static int gNextPacketPtr;
|
||||||
|
static byte selectPin;
|
||||||
|
|
||||||
|
void ENC28J60::initSPI () {
|
||||||
|
pinMode(SS, OUTPUT);
|
||||||
|
digitalWrite(SS, HIGH);
|
||||||
|
pinMode(MOSI, OUTPUT);
|
||||||
|
pinMode(SCK, OUTPUT);
|
||||||
|
pinMode(MISO, INPUT);
|
||||||
|
|
||||||
|
digitalWrite(MOSI, HIGH);
|
||||||
|
digitalWrite(MOSI, LOW);
|
||||||
|
digitalWrite(SCK, LOW);
|
||||||
|
|
||||||
|
SPCR = bit(SPE) | bit(MSTR); // 8 MHz @ 16
|
||||||
|
bitSet(SPSR, SPI2X);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void enableChip () {
|
||||||
|
cli();
|
||||||
|
digitalWrite(selectPin, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void disableChip () {
|
||||||
|
digitalWrite(selectPin, HIGH);
|
||||||
|
sei();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xferSPI (byte data) {
|
||||||
|
SPDR = data;
|
||||||
|
while (!(SPSR&(1<<SPIF)))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
static byte readOp (byte op, byte address) {
|
||||||
|
enableChip();
|
||||||
|
xferSPI(op | (address & ADDR_MASK));
|
||||||
|
xferSPI(0x00);
|
||||||
|
if (address & 0x80)
|
||||||
|
xferSPI(0x00);
|
||||||
|
byte result = SPDR;
|
||||||
|
disableChip();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void writeOp (byte op, byte address, byte data) {
|
||||||
|
enableChip();
|
||||||
|
xferSPI(op | (address & ADDR_MASK));
|
||||||
|
xferSPI(data);
|
||||||
|
disableChip();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void readBuf(uint16_t len, byte* data) {
|
||||||
|
enableChip();
|
||||||
|
xferSPI(ENC28J60_READ_BUF_MEM);
|
||||||
|
while (len--) {
|
||||||
|
xferSPI(0x00);
|
||||||
|
*data++ = SPDR;
|
||||||
|
}
|
||||||
|
disableChip();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void writeBuf(uint16_t len, const byte* data) {
|
||||||
|
enableChip();
|
||||||
|
xferSPI(ENC28J60_WRITE_BUF_MEM);
|
||||||
|
while (len--)
|
||||||
|
xferSPI(*data++);
|
||||||
|
disableChip();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SetBank (byte address) {
|
||||||
|
if ((address & BANK_MASK) != Enc28j60Bank) {
|
||||||
|
writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_BSEL1|ECON1_BSEL0);
|
||||||
|
Enc28j60Bank = address & BANK_MASK;
|
||||||
|
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, Enc28j60Bank>>5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static byte readRegByte (byte address) {
|
||||||
|
SetBank(address);
|
||||||
|
return readOp(ENC28J60_READ_CTRL_REG, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t readReg(byte address) {
|
||||||
|
return readRegByte(address) + (readRegByte(address+1) << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void writeRegByte (byte address, byte data) {
|
||||||
|
SetBank(address);
|
||||||
|
writeOp(ENC28J60_WRITE_CTRL_REG, address, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void writeReg(byte address, uint16_t data) {
|
||||||
|
writeRegByte(address, data);
|
||||||
|
writeRegByte(address + 1, data >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t readPhyByte (byte address) {
|
||||||
|
writeRegByte(MIREGADR, address);
|
||||||
|
writeRegByte(MICMD, MICMD_MIIRD);
|
||||||
|
while (readRegByte(MISTAT) & MISTAT_BUSY)
|
||||||
|
;
|
||||||
|
writeRegByte(MICMD, 0x00);
|
||||||
|
return readRegByte(MIRD+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void writePhy (byte address, uint16_t data) {
|
||||||
|
writeRegByte(MIREGADR, address);
|
||||||
|
writeReg(MIWR, data);
|
||||||
|
while (readRegByte(MISTAT) & MISTAT_BUSY)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte ENC28J60::initialize (uint16_t size, const byte* macaddr, byte csPin) {
|
||||||
|
bufferSize = size;
|
||||||
|
if (bitRead(SPCR, SPE) == 0)
|
||||||
|
initSPI();
|
||||||
|
selectPin = csPin;
|
||||||
|
pinMode(selectPin, OUTPUT);
|
||||||
|
disableChip();
|
||||||
|
|
||||||
|
writeOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
|
||||||
|
delay(2); // errata B7/2
|
||||||
|
while (!readOp(ENC28J60_READ_CTRL_REG, ESTAT) & ESTAT_CLKRDY)
|
||||||
|
;
|
||||||
|
|
||||||
|
gNextPacketPtr = RXSTART_INIT;
|
||||||
|
writeReg(ERXST, RXSTART_INIT);
|
||||||
|
writeReg(ERXRDPT, RXSTART_INIT);
|
||||||
|
writeReg(ERXND, RXSTOP_INIT);
|
||||||
|
writeReg(ETXST, TXSTART_INIT);
|
||||||
|
writeReg(ETXND, TXSTOP_INIT);
|
||||||
|
enableBroadcast(); // change to add ERXFCON_BCEN recommended by epam
|
||||||
|
writeReg(EPMM0, 0x303f);
|
||||||
|
writeReg(EPMCS, 0xf7f9);
|
||||||
|
writeRegByte(MACON1, MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS);
|
||||||
|
writeRegByte(MACON2, 0x00);
|
||||||
|
writeOp(ENC28J60_BIT_FIELD_SET, MACON3,
|
||||||
|
MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN);
|
||||||
|
writeReg(MAIPG, 0x0C12);
|
||||||
|
writeRegByte(MABBIPG, 0x12);
|
||||||
|
writeReg(MAMXFL, MAX_FRAMELEN);
|
||||||
|
writeRegByte(MAADR5, macaddr[0]);
|
||||||
|
writeRegByte(MAADR4, macaddr[1]);
|
||||||
|
writeRegByte(MAADR3, macaddr[2]);
|
||||||
|
writeRegByte(MAADR2, macaddr[3]);
|
||||||
|
writeRegByte(MAADR1, macaddr[4]);
|
||||||
|
writeRegByte(MAADR0, macaddr[5]);
|
||||||
|
writePhy(PHCON2, PHCON2_HDLDIS);
|
||||||
|
SetBank(ECON1);
|
||||||
|
writeOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE|EIE_PKTIE);
|
||||||
|
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
|
||||||
|
|
||||||
|
byte rev = readRegByte(EREVID);
|
||||||
|
// microchip forgot to step the number on the silcon when they
|
||||||
|
// released the revision B7. 6 is now rev B7. We still have
|
||||||
|
// to see what they do when they release B8. At the moment
|
||||||
|
// there is no B8 out yet
|
||||||
|
if (rev > 5) ++rev;
|
||||||
|
return rev;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ENC28J60::isLinkUp() {
|
||||||
|
return (readPhyByte(PHSTAT2) >> 2) & 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ENC28J60::packetSend(uint16_t len) {
|
||||||
|
// see http://forum.mysensors.org/topic/536/
|
||||||
|
// while (readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_TXRTS)
|
||||||
|
if (readRegByte(EIR) & EIR_TXERIF) {
|
||||||
|
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST);
|
||||||
|
writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST);
|
||||||
|
writeOp(ENC28J60_BIT_FIELD_CLR, EIR, EIR_TXERIF);
|
||||||
|
}
|
||||||
|
writeReg(EWRPT, TXSTART_INIT);
|
||||||
|
writeReg(ETXND, TXSTART_INIT+len);
|
||||||
|
writeOp(ENC28J60_WRITE_BUF_MEM, 0, 0x00);
|
||||||
|
writeBuf(len, buffer);
|
||||||
|
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t ENC28J60::packetReceive() {
|
||||||
|
uint16_t len = 0;
|
||||||
|
if (readRegByte(EPKTCNT) > 0) {
|
||||||
|
writeReg(ERDPT, gNextPacketPtr);
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint16_t nextPacket;
|
||||||
|
uint16_t byteCount;
|
||||||
|
uint16_t status;
|
||||||
|
} header;
|
||||||
|
|
||||||
|
readBuf(sizeof header, (byte*) &header);
|
||||||
|
|
||||||
|
gNextPacketPtr = header.nextPacket;
|
||||||
|
len = header.byteCount - 4; //remove the CRC count
|
||||||
|
if (len>bufferSize-1)
|
||||||
|
len=bufferSize-1;
|
||||||
|
if ((header.status & 0x80)==0)
|
||||||
|
len = 0;
|
||||||
|
else
|
||||||
|
readBuf(len, buffer);
|
||||||
|
buffer[len] = 0;
|
||||||
|
if (gNextPacketPtr - 1 > RXSTOP_INIT)
|
||||||
|
writeReg(ERXRDPT, RXSTOP_INIT);
|
||||||
|
else
|
||||||
|
writeReg(ERXRDPT, gNextPacketPtr - 1);
|
||||||
|
writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC);
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ENC28J60::copyout (byte page, const byte* data) {
|
||||||
|
uint16_t destPos = SCRATCH_START + (page << SCRATCH_PAGE_SHIFT);
|
||||||
|
if (destPos < SCRATCH_START || destPos > SCRATCH_LIMIT - SCRATCH_PAGE_SIZE)
|
||||||
|
return;
|
||||||
|
writeReg(EWRPT, destPos);
|
||||||
|
writeBuf(SCRATCH_PAGE_SIZE, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ENC28J60::copyin (byte page, byte* data) {
|
||||||
|
uint16_t destPos = SCRATCH_START + (page << SCRATCH_PAGE_SHIFT);
|
||||||
|
if (destPos < SCRATCH_START || destPos > SCRATCH_LIMIT - SCRATCH_PAGE_SIZE)
|
||||||
|
return;
|
||||||
|
writeReg(ERDPT, destPos);
|
||||||
|
readBuf(SCRATCH_PAGE_SIZE, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte ENC28J60::peekin (byte page, byte off) {
|
||||||
|
byte result = 0;
|
||||||
|
uint16_t destPos = SCRATCH_START + (page << SCRATCH_PAGE_SHIFT) + off;
|
||||||
|
if (SCRATCH_START <= destPos && destPos < SCRATCH_LIMIT) {
|
||||||
|
writeReg(ERDPT, destPos);
|
||||||
|
readBuf(1, &result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contributed by Alex M. Based on code from: http://blog.derouineau.fr
|
||||||
|
// /2011/07/putting-enc28j60-ethernet-controler-in-sleep-mode/
|
||||||
|
void ENC28J60::powerDown() {
|
||||||
|
writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_RXEN);
|
||||||
|
while(readRegByte(ESTAT) & ESTAT_RXBUSY);
|
||||||
|
while(readRegByte(ECON1) & ECON1_TXRTS);
|
||||||
|
writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_VRPS);
|
||||||
|
writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PWRSV);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ENC28J60::powerUp() {
|
||||||
|
writeOp(ENC28J60_BIT_FIELD_CLR, ECON2, ECON2_PWRSV);
|
||||||
|
while(!readRegByte(ESTAT) & ESTAT_CLKRDY);
|
||||||
|
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ENC28J60::enableBroadcast (bool temporary) {
|
||||||
|
writeRegByte(ERXFCON, readRegByte(ERXFCON) | ERXFCON_BCEN);
|
||||||
|
if(!temporary)
|
||||||
|
broadcast_enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ENC28J60::disableBroadcast (bool temporary) {
|
||||||
|
if(!temporary)
|
||||||
|
broadcast_enabled = false;
|
||||||
|
if(!broadcast_enabled)
|
||||||
|
writeRegByte(ERXFCON, readRegByte(ERXFCON) & ~ERXFCON_BCEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ENC28J60::enableMulticast () {
|
||||||
|
writeRegByte(ERXFCON, readRegByte(ERXFCON) | ERXFCON_MCEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ENC28J60::disableMulticast () {
|
||||||
|
writeRegByte(ERXFCON, readRegByte(ERXFCON) & ~ERXFCON_MCEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ENC28J60::doBIST ( byte csPin) {
|
||||||
|
#define RANDOM_FILL 0b0000
|
||||||
|
#define ADDRESS_FILL 0b0100
|
||||||
|
#define PATTERN_SHIFT 0b1000
|
||||||
|
#define RANDOM_RACE 0b1100
|
||||||
|
|
||||||
|
// init
|
||||||
|
if (bitRead(SPCR, SPE) == 0)
|
||||||
|
initSPI();
|
||||||
|
selectPin = csPin;
|
||||||
|
pinMode(selectPin, OUTPUT);
|
||||||
|
disableChip();
|
||||||
|
|
||||||
|
writeOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
|
||||||
|
delay(2); // errata B7/2
|
||||||
|
while (!readOp(ENC28J60_READ_CTRL_REG, ESTAT) & ESTAT_CLKRDY) ;
|
||||||
|
|
||||||
|
|
||||||
|
// now we can start the memory test
|
||||||
|
|
||||||
|
uint16_t macResult;
|
||||||
|
uint16_t bitsResult;
|
||||||
|
|
||||||
|
// clear some of the registers registers
|
||||||
|
writeRegByte(ECON1, 0);
|
||||||
|
writeReg(EDMAST, 0);
|
||||||
|
|
||||||
|
// Set up necessary pointers for the DMA to calculate over the entire memory
|
||||||
|
writeReg(EDMAND, 0x1FFFu);
|
||||||
|
writeReg(ERXND, 0x1FFFu);
|
||||||
|
|
||||||
|
// Enable Test Mode and do an Address Fill
|
||||||
|
SetBank(EBSTCON);
|
||||||
|
writeRegByte(EBSTCON, EBSTCON_TME | EBSTCON_BISTST | ADDRESS_FILL);
|
||||||
|
|
||||||
|
// wait for BISTST to be reset, only after that are we actually ready to
|
||||||
|
// start the test
|
||||||
|
// this was undocumented :(
|
||||||
|
while (readOp(ENC28J60_READ_CTRL_REG, EBSTCON) & EBSTCON_BISTST);
|
||||||
|
writeOp(ENC28J60_BIT_FIELD_CLR, EBSTCON, EBSTCON_TME);
|
||||||
|
|
||||||
|
|
||||||
|
// now start the actual reading an calculating the checksum until the end is
|
||||||
|
// reached
|
||||||
|
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_DMAST | ECON1_CSUMEN);
|
||||||
|
SetBank(EDMACS);
|
||||||
|
while(readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_DMAST);
|
||||||
|
macResult = readReg(EDMACS);
|
||||||
|
bitsResult = readReg(EBSTCS);
|
||||||
|
// Compare the results
|
||||||
|
// 0xF807 should always be generated in Address fill mode
|
||||||
|
if ((macResult != bitsResult) || (bitsResult != 0xF807)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// reset test flag
|
||||||
|
writeOp(ENC28J60_BIT_FIELD_CLR, EBSTCON, EBSTCON_TME);
|
||||||
|
|
||||||
|
|
||||||
|
// Now start the BIST with random data test, and also keep on swapping the
|
||||||
|
// DMA/BIST memory ports.
|
||||||
|
writeRegByte(EBSTSD, 0b10101010 | millis());
|
||||||
|
writeRegByte(EBSTCON, EBSTCON_TME | EBSTCON_PSEL | EBSTCON_BISTST | RANDOM_FILL);
|
||||||
|
|
||||||
|
|
||||||
|
// wait for BISTST to be reset, only after that are we actually ready to
|
||||||
|
// start the test
|
||||||
|
// this was undocumented :(
|
||||||
|
while (readOp(ENC28J60_READ_CTRL_REG, EBSTCON) & EBSTCON_BISTST);
|
||||||
|
writeOp(ENC28J60_BIT_FIELD_CLR, EBSTCON, EBSTCON_TME);
|
||||||
|
|
||||||
|
|
||||||
|
// now start the actual reading an calculating the checksum until the end is
|
||||||
|
// reached
|
||||||
|
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_DMAST | ECON1_CSUMEN);
|
||||||
|
SetBank(EDMACS);
|
||||||
|
while(readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_DMAST);
|
||||||
|
|
||||||
|
macResult = readReg(EDMACS);
|
||||||
|
bitsResult = readReg(EBSTCS);
|
||||||
|
// The checksum should be equal
|
||||||
|
return macResult == bitsResult;
|
||||||
|
}
|
||||||
|
|
114
lib-ext/ethercard.git/enc28j60.h
Normal file
114
lib-ext/ethercard.git/enc28j60.h
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
// Microchip ENC28J60 Ethernet Interface Driver
|
||||||
|
// Author: Pascal Stang
|
||||||
|
// Modified by: Guido Socher
|
||||||
|
// Copyright: GPL V2
|
||||||
|
//
|
||||||
|
// This driver provides initialization and transmit/receive
|
||||||
|
// functions for the Microchip ENC28J60 10Mb Ethernet Controller and PHY.
|
||||||
|
// This chip is novel in that it is a full MAC+PHY interface all in a 28-pin
|
||||||
|
// chip, using an SPI interface to the host processor.
|
||||||
|
//
|
||||||
|
// 2010-05-20 <jc@wippler.nl>
|
||||||
|
|
||||||
|
#ifndef ENC28J60_H
|
||||||
|
#define ENC28J60_H
|
||||||
|
|
||||||
|
/** This class provide low-level interfacing with the ENC28J60 network interface. This is used by the EtherCard class and not intended for use by (normal) end users. */
|
||||||
|
class ENC28J60 {
|
||||||
|
public:
|
||||||
|
static uint8_t buffer[]; //!< Data buffer (shared by recieve and transmit)
|
||||||
|
static uint16_t bufferSize; //!< Size of data buffer
|
||||||
|
static bool broadcast_enabled; //!< True if broadcasts enabled (used to allow temporary disable of broadcast for DHCP or other internal functions)
|
||||||
|
|
||||||
|
static uint8_t* tcpOffset () { return buffer + 0x36; } //!< Pointer to the start of TCP payload
|
||||||
|
|
||||||
|
/** @brief Initialise SPI interface
|
||||||
|
* @note Configures Arduino pins as input / output, etc.
|
||||||
|
*/
|
||||||
|
static void initSPI ();
|
||||||
|
|
||||||
|
/** @brief Initialise network interface
|
||||||
|
* @param size Size of data buffer
|
||||||
|
* @param macaddr Pointer to 6 byte hardware (MAC) address
|
||||||
|
* @param csPin Arduino pin used for chip select (enable network interface SPI bus). Default = 8
|
||||||
|
* @return <i>uint8_t</i> ENC28J60 firmware version or zero on failure.
|
||||||
|
*/
|
||||||
|
static uint8_t initialize (const uint16_t size, const uint8_t* macaddr,
|
||||||
|
uint8_t csPin = 8);
|
||||||
|
|
||||||
|
/** @brief Check if network link is connected
|
||||||
|
* @return <i>bool</i> True if link is up
|
||||||
|
*/
|
||||||
|
static bool isLinkUp ();
|
||||||
|
|
||||||
|
/** @brief Sends data to network interface
|
||||||
|
* @param len Size of data to send
|
||||||
|
* @note Data buffer is shared by recieve and transmit functions
|
||||||
|
*/
|
||||||
|
static void packetSend (uint16_t len);
|
||||||
|
|
||||||
|
/** @brief Copy recieved packets to data buffer
|
||||||
|
* @return <i>uint16_t</i> Size of recieved data
|
||||||
|
* @note Data buffer is shared by recieve and transmit functions
|
||||||
|
*/
|
||||||
|
static uint16_t packetReceive ();
|
||||||
|
|
||||||
|
/** @brief Copy data from ENC28J60 memory
|
||||||
|
* @param page Data page of memory
|
||||||
|
* @param data Pointer to buffer to copy data to
|
||||||
|
*/
|
||||||
|
static void copyout (uint8_t page, const uint8_t* data);
|
||||||
|
|
||||||
|
/** @brief Copy data to ENC28J60 memory
|
||||||
|
* @param page Data page of memory
|
||||||
|
* @param data Pointer to buffer to copy data from
|
||||||
|
*/
|
||||||
|
static void copyin (uint8_t page, uint8_t* data);
|
||||||
|
|
||||||
|
/** @brief Get single byte of data from ENC28J60 memory
|
||||||
|
* @param page Data page of memory
|
||||||
|
* @param off Offset of data within page
|
||||||
|
* @return Data value
|
||||||
|
*/
|
||||||
|
static uint8_t peekin (uint8_t page, uint8_t off);
|
||||||
|
|
||||||
|
/** @brief Put ENC28J60 in sleep mode
|
||||||
|
*/
|
||||||
|
static void powerDown(); // contrib by Alex M.
|
||||||
|
|
||||||
|
/** @brief Wake ENC28J60 from sleep mode
|
||||||
|
*/
|
||||||
|
static void powerUp(); // contrib by Alex M.
|
||||||
|
|
||||||
|
/** @brief Enable reception of broadcast messages
|
||||||
|
* @param temporary Set true to temporarily enable broadcast
|
||||||
|
* @note This will increase load on recieved data handling
|
||||||
|
*/
|
||||||
|
static void enableBroadcast(bool temporary = false);
|
||||||
|
|
||||||
|
/** @brief Disable reception of broadcast messages
|
||||||
|
* @param temporary Set true to only disable if temporarily enabled
|
||||||
|
* @note This will reduce load on recieved data handling
|
||||||
|
*/
|
||||||
|
static void disableBroadcast(bool temporary = false);
|
||||||
|
|
||||||
|
/** @brief Enables reception of mulitcast messages
|
||||||
|
* @note This will increase load on recieved data handling
|
||||||
|
*/
|
||||||
|
static void enableMulticast ();
|
||||||
|
|
||||||
|
/** @brief Disable reception of mulitcast messages
|
||||||
|
* @note This will reduce load on recieved data handling
|
||||||
|
*/
|
||||||
|
static void disableMulticast();
|
||||||
|
|
||||||
|
/** @brief Reset and fully initialise ENC28J60
|
||||||
|
* @param csPin Arduino pin used for chip select (enable SPI bus)
|
||||||
|
* @return <i>uint8_t</i> 0 on failure
|
||||||
|
*/
|
||||||
|
static uint8_t doBIST(uint8_t csPin = 8);
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef ENC28J60 Ethernet; //!< Define alias Ethernet for ENC28J60
|
||||||
|
|
||||||
|
#endif
|
320
lib-ext/ethercard.git/examples/JeeUdp/JeeUdp.ino
Normal file
320
lib-ext/ethercard.git/examples/JeeUdp/JeeUdp.ino
Normal file
|
@ -0,0 +1,320 @@
|
||||||
|
// Collect RF12 packets and send them on as UDP collectd packets on Ethernet.
|
||||||
|
// 2010-05-20 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
|
||||||
|
|
||||||
|
// This sketch is derived from RF12eth.pde (and etherNode.ino):
|
||||||
|
// May 2010, Andras Tucsni, http://opensource.org/licenses/mit-license.php
|
||||||
|
|
||||||
|
#include <EtherCard.h>
|
||||||
|
#include <JeeLib.h>
|
||||||
|
#include <avr/eeprom.h>
|
||||||
|
|
||||||
|
#define DEBUG 1 // set to 1 to display free RAM on web page
|
||||||
|
#define SERIAL 1 // set to 1 to show incoming requests on serial port
|
||||||
|
|
||||||
|
#define CONFIG_EEPROM_ADDR ((byte*) 0x10)
|
||||||
|
|
||||||
|
// configuration, as stored in EEPROM
|
||||||
|
struct Config {
|
||||||
|
byte band;
|
||||||
|
byte group;
|
||||||
|
byte collect;
|
||||||
|
word port;
|
||||||
|
byte valid; // keep this as last byte
|
||||||
|
} config;
|
||||||
|
|
||||||
|
// ethernet interface mac address - must be unique on your network
|
||||||
|
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
|
||||||
|
|
||||||
|
// buffer for an outgoing data packet
|
||||||
|
static byte outBuf[RF12_MAXDATA], outDest;
|
||||||
|
static char outCount = -1;
|
||||||
|
|
||||||
|
// this buffer will be used to construct a collectd UDP packet
|
||||||
|
static byte collBuf [200], collPos;
|
||||||
|
|
||||||
|
#define NUM_MESSAGES 3 // Number of messages saved in history
|
||||||
|
#define MESSAGE_TRUNC 15 // Truncate message payload to reduce memory use
|
||||||
|
|
||||||
|
static BufferFiller bfill; // used as cursor while filling the buffer
|
||||||
|
|
||||||
|
static byte history_rcvd[NUM_MESSAGES][MESSAGE_TRUNC+1]; //history record
|
||||||
|
static byte history_len[NUM_MESSAGES]; // # of RF12 messages+header in history
|
||||||
|
static byte next_msg; // pointer to next rf12rcvd line
|
||||||
|
static word msgs_rcvd; // total number of lines received modulo 10,000
|
||||||
|
|
||||||
|
byte Ethernet::buffer[700]; // tcp/ip send and receive buffer
|
||||||
|
|
||||||
|
static void loadConfig () {
|
||||||
|
for (byte i = 0; i < sizeof config; ++i)
|
||||||
|
((byte*) &config)[i] = eeprom_read_byte(CONFIG_EEPROM_ADDR + i);
|
||||||
|
if (config.valid != 253) {
|
||||||
|
config.valid = 253;
|
||||||
|
config.band = 8;
|
||||||
|
config.group = 1;
|
||||||
|
config.collect = 1;
|
||||||
|
config.port = 25827;
|
||||||
|
}
|
||||||
|
byte freq = config.band == 4 ? RF12_433MHZ :
|
||||||
|
config.band == 8 ? RF12_868MHZ :
|
||||||
|
RF12_915MHZ;
|
||||||
|
rf12_initialize(31, freq, config.group);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void saveConfig () {
|
||||||
|
for (byte i = 0; i < sizeof config; ++i)
|
||||||
|
eeprom_write_byte(CONFIG_EEPROM_ADDR + i, ((byte*) &config)[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
static int freeRam () {
|
||||||
|
extern int __heap_start, *__brkval;
|
||||||
|
int v;
|
||||||
|
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void setup (){
|
||||||
|
Serial.begin(57600);
|
||||||
|
Serial.println("\n[JeeUdp]");
|
||||||
|
loadConfig();
|
||||||
|
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
|
||||||
|
Serial.println( "Failed to access Ethernet controller");
|
||||||
|
if (!ether.dhcpSetup())
|
||||||
|
Serial.println("DHCP failed");
|
||||||
|
ether.printIp("IP: ", ether.myip);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char okHeader[] PROGMEM =
|
||||||
|
"HTTP/1.0 200 OK\r\n"
|
||||||
|
"Content-Type: text/html\r\n"
|
||||||
|
"Pragma: no-cache\r\n"
|
||||||
|
;
|
||||||
|
|
||||||
|
static void homePage (BufferFiller& buf) {
|
||||||
|
word mhz = config.band == 4 ? 433 : config.band == 8 ? 868 : 915;
|
||||||
|
buf.emit_p(PSTR("$F\r\n"
|
||||||
|
"<title>RF12 JeeUdp</title>"
|
||||||
|
"<h2>RF12 JeeUdp @ $D - RF12 @ $D.$D</h2>"
|
||||||
|
"<a href='c'>Configure</a> - <a href='s'>Send Packet</a>"
|
||||||
|
"<h3>Last $D messages:</h3>"
|
||||||
|
"<pre>"), okHeader, config.port, mhz, config.group, NUM_MESSAGES);
|
||||||
|
for (byte i = 0; i < NUM_MESSAGES; ++i) {
|
||||||
|
byte j = (next_msg + i) % NUM_MESSAGES;
|
||||||
|
if (history_len[j] > 0) {
|
||||||
|
word n = msgs_rcvd - NUM_MESSAGES + i;
|
||||||
|
buf.emit_p(PSTR("\n$D$D$D$D: OK"), // hack, to show leading zero's
|
||||||
|
n/1000, (n/100) % 10, (n/10) % 10, n % 10);
|
||||||
|
for (byte k = 0; k < history_len[j]; ++k)
|
||||||
|
buf.emit_p(PSTR(" $D"), history_rcvd[j][k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
long t = millis() / 1000;
|
||||||
|
word h = t / 3600;
|
||||||
|
byte m = (t / 60) % 60;
|
||||||
|
byte s = t % 60;
|
||||||
|
buf.emit_p(PSTR(
|
||||||
|
"</pre>"
|
||||||
|
"Uptime is $D$D:$D$D:$D$D"), h/10, h%10, m/10, m%10, s/10, s%10);
|
||||||
|
#if DEBUG
|
||||||
|
buf.emit_p(PSTR(" ($D bytes free)"), freeRam());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getIntArg(const char* data, const char* key, int value =-1) {
|
||||||
|
char temp[10];
|
||||||
|
if (ether.findKeyVal(data + 7, temp, sizeof temp, key) > 0)
|
||||||
|
value = atoi(temp);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void configPage (const char* data, BufferFiller& buf) {
|
||||||
|
// pick up submitted data, if present
|
||||||
|
if (data[6] == '?') {
|
||||||
|
byte b = getIntArg(data, "b", 8);
|
||||||
|
byte g = getIntArg(data, "g", 1);
|
||||||
|
byte c = getIntArg(data, "c", 0);
|
||||||
|
word p = getIntArg(data, "p", 25827);
|
||||||
|
if (1 <= g && g <= 250 && 1024 <= p && p <= 30000) {
|
||||||
|
// store values as new settings
|
||||||
|
config.band = b;
|
||||||
|
config.group = g;
|
||||||
|
config.collect = c;
|
||||||
|
config.port = p;
|
||||||
|
saveConfig();
|
||||||
|
// re-init RF12 driver
|
||||||
|
loadConfig();
|
||||||
|
// clear history
|
||||||
|
memset(history_len, 0, sizeof history_len);
|
||||||
|
// redirect to the home page
|
||||||
|
buf.emit_p(PSTR(
|
||||||
|
"HTTP/1.0 302 found\r\n"
|
||||||
|
"Location: /\r\n"
|
||||||
|
"\r\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// else show a configuration form
|
||||||
|
buf.emit_p(PSTR("$F\r\n"
|
||||||
|
"<h3>Server node configuration</h3>"
|
||||||
|
"<form>"
|
||||||
|
"<p>"
|
||||||
|
"Freq band <input type=text name=b value='$D' size=1> (4, 8, or 9)<br>"
|
||||||
|
"Net group <input type=text name=g value='$D' size=3> (1..250)<br>"
|
||||||
|
"Collect mode: <input type=checkbox name=c value='1' $S> "
|
||||||
|
"(don't send ACKs)<br><br>"
|
||||||
|
"UDP Port <input type=text name=p value='$D' size=5> (1024..30000)"
|
||||||
|
"</p>"
|
||||||
|
"<input type=submit value=Set>"
|
||||||
|
"</form>"), okHeader, config.band, config.group,
|
||||||
|
config.collect ? "CHECKED" : "",
|
||||||
|
config.port);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sendPage (const char* data, BufferFiller& buf) {
|
||||||
|
// pick up submitted data, if present
|
||||||
|
const char* p = strstr(data, "b=");
|
||||||
|
byte d = getIntArg(data, "d");
|
||||||
|
if (data[6] == '?' && p != 0 && 0 <= d && d <= 31) {
|
||||||
|
// prepare to send data as soon as possible in loop()
|
||||||
|
outDest = d & RF12_HDR_MASK ? RF12_HDR_DST | d : 0;
|
||||||
|
outCount = 0;
|
||||||
|
// convert the input string to a number of decimal data bytes in outBuf
|
||||||
|
++p;
|
||||||
|
while (*p != 0 && *p != '&') {
|
||||||
|
outBuf[outCount] = 0;
|
||||||
|
while ('0' <= *++p && *p <= '9')
|
||||||
|
outBuf[outCount] = 10 * outBuf[outCount] + (*p - '0');
|
||||||
|
++outCount;
|
||||||
|
}
|
||||||
|
#if SERIAL
|
||||||
|
Serial.print("Send to ");
|
||||||
|
Serial.print(outDest, DEC);
|
||||||
|
Serial.print(':');
|
||||||
|
for (byte i = 0; i < outCount; ++i) {
|
||||||
|
Serial.print(' ');
|
||||||
|
Serial.print(outBuf[i], DEC);
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
#endif
|
||||||
|
// redirect to home page
|
||||||
|
buf.emit_p(PSTR(
|
||||||
|
"HTTP/1.0 302 found\r\n"
|
||||||
|
"Location: /\r\n"
|
||||||
|
"\r\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// else show a send form
|
||||||
|
buf.emit_p(PSTR("$F\r\n"
|
||||||
|
"<h3>Send a wireless data packet</h3>"
|
||||||
|
"<form>"
|
||||||
|
"<p>"
|
||||||
|
"Data bytes <input type=text name=b size=50> (decimal)<br>"
|
||||||
|
"Destination node <input type=text name=d size=3> "
|
||||||
|
"(1..31, or 0 to broadcast)<br>"
|
||||||
|
"</p>"
|
||||||
|
"<input type=submit value=Send>"
|
||||||
|
"</form>"), okHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void collectTypeLen (word type, word len) {
|
||||||
|
len += 4;
|
||||||
|
collBuf[collPos++] = type >> 8;
|
||||||
|
collBuf[collPos++] = (byte) type;
|
||||||
|
collBuf[collPos++] = len >> 8;
|
||||||
|
collBuf[collPos++] = (byte) len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void collectStr (word type, const char* data) {
|
||||||
|
word len = strlen(data) + 1;
|
||||||
|
collectTypeLen(type, len);
|
||||||
|
strcpy((char*) collBuf + collPos, data);
|
||||||
|
collPos += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void collectPayload (word type) {
|
||||||
|
// Copy the received RF12 data into a as many values as needed.
|
||||||
|
byte num = rf12_len / 8 + 1; // this many values will be needed
|
||||||
|
collectTypeLen(type, 2 + 9 * num);
|
||||||
|
collBuf[collPos++] = 0;
|
||||||
|
collBuf[collPos++] = num;
|
||||||
|
for (byte i = 0; i < num; ++i)
|
||||||
|
collBuf[collPos++] = 0; // counter
|
||||||
|
for (char i = 0; i < 8 * num; ++i) // include -1, i.e. the length byte
|
||||||
|
collBuf[collPos++] = i <= rf12_len ? rf12_data[i-1] : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void forwardToUDP () {
|
||||||
|
static byte destIp[] = { 239,192,74,66 }; // UDP multicast address
|
||||||
|
char buf[10];
|
||||||
|
|
||||||
|
collPos = 0;
|
||||||
|
collectStr(0x0000, "JeeUdp");
|
||||||
|
collectStr(0x0002, "RF12");
|
||||||
|
word mhz = config.band == 4 ? 433 : config.band == 8 ? 868 : 915;
|
||||||
|
sprintf(buf, "%d.%d", mhz, config.group);
|
||||||
|
collectStr(0x0003, buf);
|
||||||
|
collectStr(0x0004, "OK");
|
||||||
|
sprintf(buf, "%d", rf12_hdr);
|
||||||
|
collectStr(0x0005, buf);
|
||||||
|
collectPayload(0x0006);
|
||||||
|
|
||||||
|
ether.sendUdp ((char*) collBuf, collPos, 23456, destIp, config.port);
|
||||||
|
#if SERIAL
|
||||||
|
Serial.println("UDP sent");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop (){
|
||||||
|
word len = ether.packetReceive();
|
||||||
|
word pos = ether.packetLoop(len);
|
||||||
|
// check if valid tcp data is received
|
||||||
|
if (pos) {
|
||||||
|
bfill = ether.tcpOffset();
|
||||||
|
char* data = (char *) Ethernet::buffer + pos;
|
||||||
|
#if SERIAL
|
||||||
|
Serial.println(data);
|
||||||
|
#endif
|
||||||
|
// receive buf hasn't been clobbered by reply yet
|
||||||
|
if (strncmp("GET / ", data, 6) == 0)
|
||||||
|
homePage(bfill);
|
||||||
|
else if (strncmp("GET /c", data, 6) == 0)
|
||||||
|
configPage(data, bfill);
|
||||||
|
else if (strncmp("GET /s", data, 6) == 0)
|
||||||
|
sendPage(data, bfill);
|
||||||
|
else
|
||||||
|
bfill.emit_p(PSTR(
|
||||||
|
"HTTP/1.0 401 Unauthorized\r\n"
|
||||||
|
"Content-Type: text/html\r\n"
|
||||||
|
"\r\n"
|
||||||
|
"<h1>401 Unauthorized</h1>"));
|
||||||
|
ether.httpServerReply(bfill.position()); // send web page data
|
||||||
|
}
|
||||||
|
|
||||||
|
// RFM12 loop runner, don't report acks
|
||||||
|
if (rf12_recvDone() && rf12_crc == 0 && (rf12_hdr & RF12_HDR_CTL) == 0) {
|
||||||
|
history_rcvd[next_msg][0] = rf12_hdr;
|
||||||
|
for (byte i = 0; i < rf12_len; ++i)
|
||||||
|
if (i < MESSAGE_TRUNC)
|
||||||
|
history_rcvd[next_msg][i+1] = rf12_data[i];
|
||||||
|
history_len[next_msg] = rf12_len < MESSAGE_TRUNC ? rf12_len+1
|
||||||
|
: MESSAGE_TRUNC+1;
|
||||||
|
next_msg = (next_msg + 1) % NUM_MESSAGES;
|
||||||
|
msgs_rcvd = (msgs_rcvd + 1) % 10000;
|
||||||
|
|
||||||
|
if (RF12_WANTS_ACK && !config.collect) {
|
||||||
|
#if SERIAL
|
||||||
|
Serial.println(" -> ack");
|
||||||
|
#endif
|
||||||
|
rf12_sendStart(RF12_ACK_REPLY, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
forwardToUDP();
|
||||||
|
}
|
||||||
|
|
||||||
|
// send a data packet out if requested
|
||||||
|
if (outCount >= 0 && rf12_canSend()) {
|
||||||
|
rf12_sendStart(outDest, outBuf, outCount, 1);
|
||||||
|
outCount = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
144
lib-ext/ethercard.git/examples/SSDP/SSDP.ino
Normal file
144
lib-ext/ethercard.git/examples/SSDP/SSDP.ino
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
#include <EtherCard.h>// |Mac adress|
|
||||||
|
const char SSDP_RESPONSE[] PROGMEM = "HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=1200\r\nEXT:\r\nSERVER:Arduino\r\nST: upnp:rootdevice\r\nUSN: uuid:abcdefgh-7dec-11d0-a765-7499692d3040\r\nLOCATION: http://"; //dont forget our mac adress USN: uuid:abcdefgh-7dec-11d0-a765-Mac addr
|
||||||
|
const char SSDP_RESPONSE_XML[] PROGMEM = "/??\r\n\r\n"; // here is the adress of xml file /?? in this exemple but you could use another /upnp.xml\r\n\r\n
|
||||||
|
const char XML_DESCRIP[] PROGMEM = "HTTP/1.1 200 OK\r\nContent-Type: text/xml\r\n\r\n<?xml version='1.0'?>\r<root xmlns='urn:schemas-upnp-org:device-1-0'><device><deviceType>urn:schemas-upnp-org:device:BinaryLight:1</deviceType><presentationURL>/</presentationURL><friendlyName>Arduino</friendlyName><manufacturer>Fredycpu</manufacturer><manufacturerURL>http://fredycpu.pro</manufacturerURL><serialNumber>1</serialNumber><UDN>uuid:abcdefgh-7dec-11d0-a765-7499692d3040</UDN></device></root> ";
|
||||||
|
const char SSDP_NOTIFY[] PROGMEM = "NOTIFY * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nCACHE-CONTROL: max-age=1200\r\nNT: upnp:rootdevice\r\nUSN: uuid:abcdefga-7dec-11d0-a765-7499692d3040::upnp:rootdevice\r\nNTS: ssdp:alive\r\nSERVER: Arduino UPnP/1.0\r\nLOCATION: http://"; //dont forget our mac adress USN: uuid:abcdefgh-7dec-11d0-a765-Mac addr
|
||||||
|
// in XML_DESCRIP // <deviceType>urn:schemas-upnp-org:device:BinaryLight:1</deviceType> // declare as home automation
|
||||||
|
// in XML_DESCRIP // <friendlyName>Arduino</friendlyName> // declare the name of the service here Arduino
|
||||||
|
// in XML_DESCRIP // <presentationURL>/</presentationURL> // adress of the page who would opened on service double click ,you could use http://ip but if you use dhcp it's better so and dont wase memory
|
||||||
|
// this is the entire protocol, but you can try to use SSDP_NOTIFY as SSDP_RESPONSE with most systems will work and you can free a bit of flash mem.
|
||||||
|
static byte myip[] = {
|
||||||
|
192,168,0,67 };
|
||||||
|
static byte gwip[] = {
|
||||||
|
192,168,0,250 };
|
||||||
|
static byte ssdp[] = {
|
||||||
|
239,255,255,250 };
|
||||||
|
static byte mymac[] = {
|
||||||
|
0x74,0x99,0x69,0x2D,0x30,0x40 }; // if you change it you must update SSDP_RESPONSE and XML_DESCRIP
|
||||||
|
byte Ethernet::buffer[750]; // tcp ip send and receive buffer
|
||||||
|
unsigned long timer=9999;
|
||||||
|
const char pageA[] PROGMEM =
|
||||||
|
"HTTP/1.0 200 OK\r\n"
|
||||||
|
"Content-Type: text/html\r\n"
|
||||||
|
"\r\n"
|
||||||
|
"<html>"
|
||||||
|
"<head><title>"
|
||||||
|
"multipackets Test"
|
||||||
|
"</title></head>"
|
||||||
|
"<body>"
|
||||||
|
"<a href='/'>Start here</a><br>"
|
||||||
|
"<a href='/test.jpg'>Image test</a><br>"
|
||||||
|
"<h3>packet 1</h3>"
|
||||||
|
"<p><em>"
|
||||||
|
"the first packet send "
|
||||||
|
"</em></p>"
|
||||||
|
;
|
||||||
|
const char pageB[] PROGMEM =
|
||||||
|
"<h3>packet 2</h3>"
|
||||||
|
"<p><em>"
|
||||||
|
"if you read this it mean it works"
|
||||||
|
"</em></p>"
|
||||||
|
;
|
||||||
|
const char pageC[] PROGMEM =
|
||||||
|
"<h3>packet 3</h3>"
|
||||||
|
"<p><em>"
|
||||||
|
"if you read this it mean it works"
|
||||||
|
"</em></p>"
|
||||||
|
;
|
||||||
|
const char pageD[] PROGMEM =
|
||||||
|
"<h3>packet 4</h3>"
|
||||||
|
"<p><em>"
|
||||||
|
"if you read this it mean it works"
|
||||||
|
"</em></p>"
|
||||||
|
;
|
||||||
|
|
||||||
|
void setup(){
|
||||||
|
ether.begin(sizeof Ethernet::buffer, mymac , 10);// 53 for the mega ethernet shield and 10 for normal ethernet shield
|
||||||
|
ether.staticSetup(myip, gwip);
|
||||||
|
ENC28J60::disableMulticast(); //disable multicast filter means enable multicast reception
|
||||||
|
Serial.begin(115200);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop(){
|
||||||
|
wait:
|
||||||
|
word pos = ether.packetLoop(ether.packetReceive());
|
||||||
|
// check if valid tcp data is received
|
||||||
|
if (pos) {
|
||||||
|
char* data = (char *) Ethernet::buffer + pos;
|
||||||
|
if (strncmp("GET / ", data, 6) == 0) {
|
||||||
|
ether.httpServerReplyAck(); // send ack to the request
|
||||||
|
memcpy_P(ether.tcpOffset(), pageA, sizeof pageA); // send first packet and not send the terminate flag
|
||||||
|
ether.httpServerReply_with_flags(sizeof pageA - 1,TCP_FLAGS_ACK_V);
|
||||||
|
memcpy_P(ether.tcpOffset(), pageB, sizeof pageB); // send second packet and not send the terminate flag
|
||||||
|
ether.httpServerReply_with_flags(sizeof pageB - 1,TCP_FLAGS_ACK_V);
|
||||||
|
memcpy_P(ether.tcpOffset(), pageC, sizeof pageC); // send thirdt packet and not send the terminate flag
|
||||||
|
ether.httpServerReply_with_flags(sizeof pageC - 1,TCP_FLAGS_ACK_V);
|
||||||
|
memcpy_P(ether.tcpOffset(), pageD, sizeof pageD); // send fourth packet and send the terminate flag
|
||||||
|
ether.httpServerReply_with_flags(sizeof pageD - 1,TCP_FLAGS_ACK_V|TCP_FLAGS_FIN_V);
|
||||||
|
goto wait;
|
||||||
|
}
|
||||||
|
if (strncmp("GET /??", data, 7) == 0) { // description of services (normaly an xml file but here .....)
|
||||||
|
ether.httpServerReplyAck();
|
||||||
|
memcpy_P(Ethernet::buffer + TCP_OPTIONS_P,XML_DESCRIP, sizeof XML_DESCRIP);
|
||||||
|
ether.httpServerReply_with_flags(sizeof XML_DESCRIP - 1 ,TCP_FLAGS_ACK_V|TCP_FLAGS_FIN_V);
|
||||||
|
goto wait;
|
||||||
|
}
|
||||||
|
if (strncmp("M-SEARCH", data, 8) == 0) { // service discovery request comes here (udp protocol)
|
||||||
|
ssdpresp();
|
||||||
|
goto wait;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (((millis()-timer)>50000)||(timer>millis())) {
|
||||||
|
timer=millis();
|
||||||
|
ssdpnotify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void ssdpresp() { //response to m-search
|
||||||
|
byte ip_dst[4];
|
||||||
|
unsigned int port_dst=Ethernet::buffer[34]*256+Ethernet::buffer[35];//extract source port of request
|
||||||
|
for( int i=0; i<4;i++) { //extract source IP of request
|
||||||
|
ip_dst[i]=Ethernet::buffer[i+26];
|
||||||
|
}
|
||||||
|
int udppos = UDP_DATA_P;
|
||||||
|
|
||||||
|
EtherCard::udpPrepare(1900,ip_dst,port_dst);
|
||||||
|
memcpy_P(Ethernet::buffer + udppos, SSDP_RESPONSE, sizeof SSDP_RESPONSE);
|
||||||
|
udppos = udppos + sizeof SSDP_RESPONSE-1;
|
||||||
|
addip(udppos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ssdpnotify() { //Notification
|
||||||
|
int udppos = UDP_DATA_P;
|
||||||
|
EtherCard::udpPrepare(1900,ssdp,1900);
|
||||||
|
memcpy_P(Ethernet::buffer + udppos, SSDP_NOTIFY, sizeof SSDP_NOTIFY);
|
||||||
|
udppos = udppos + sizeof SSDP_NOTIFY-1;
|
||||||
|
addip(udppos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addip(int udppos) { // add current ip to the request and send it
|
||||||
|
int adr;
|
||||||
|
for(int i=0;i<4;i++) { // extract the current ip of arduino
|
||||||
|
adr = ether.myip[i]/100;
|
||||||
|
if (adr) {
|
||||||
|
Ethernet::buffer[udppos]=adr+48;
|
||||||
|
udppos++;
|
||||||
|
}
|
||||||
|
adr=(ether.myip[i]%100)/10;
|
||||||
|
if (adr) {
|
||||||
|
Ethernet::buffer[udppos]=adr+48;
|
||||||
|
udppos++;
|
||||||
|
}
|
||||||
|
adr=ether.myip[i]%10;
|
||||||
|
Ethernet::buffer[udppos]=adr+48;
|
||||||
|
udppos++;
|
||||||
|
Ethernet::buffer[udppos]=46;
|
||||||
|
udppos++; //"."
|
||||||
|
}
|
||||||
|
udppos--;//erase the last point
|
||||||
|
memcpy_P(Ethernet::buffer + udppos,SSDP_RESPONSE_XML,sizeof SSDP_RESPONSE_XML);
|
||||||
|
udppos = udppos + sizeof SSDP_RESPONSE_XML;
|
||||||
|
udppos--;
|
||||||
|
EtherCard::udpTransmit(udppos-UDP_DATA_P); // send all to the computer who make the request on her ip and port who make the request
|
||||||
|
}
|
||||||
|
|
||||||
|
|
63
lib-ext/ethercard.git/examples/backSoon/backSoon.ino
Normal file
63
lib-ext/ethercard.git/examples/backSoon/backSoon.ino
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
// Present a "Will be back soon web page", as stand-in webserver.
|
||||||
|
// 2011-01-30 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
|
||||||
|
|
||||||
|
#include <EtherCard.h>
|
||||||
|
|
||||||
|
#define STATIC 0 // set to 1 to disable DHCP (adjust myip/gwip values below)
|
||||||
|
|
||||||
|
#if STATIC
|
||||||
|
// ethernet interface ip address
|
||||||
|
static byte myip[] = { 192,168,1,200 };
|
||||||
|
// gateway ip address
|
||||||
|
static byte gwip[] = { 192,168,1,1 };
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ethernet mac address - must be unique on your network
|
||||||
|
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
|
||||||
|
|
||||||
|
byte Ethernet::buffer[500]; // tcp/ip send and receive buffer
|
||||||
|
|
||||||
|
const char page[] PROGMEM =
|
||||||
|
"HTTP/1.0 503 Service Unavailable\r\n"
|
||||||
|
"Content-Type: text/html\r\n"
|
||||||
|
"Retry-After: 600\r\n"
|
||||||
|
"\r\n"
|
||||||
|
"<html>"
|
||||||
|
"<head><title>"
|
||||||
|
"Service Temporarily Unavailable"
|
||||||
|
"</title></head>"
|
||||||
|
"<body>"
|
||||||
|
"<h3>This service is currently unavailable</h3>"
|
||||||
|
"<p><em>"
|
||||||
|
"The main server is currently off-line.<br />"
|
||||||
|
"Please try again later."
|
||||||
|
"</em></p>"
|
||||||
|
"</body>"
|
||||||
|
"</html>"
|
||||||
|
;
|
||||||
|
|
||||||
|
void setup(){
|
||||||
|
Serial.begin(57600);
|
||||||
|
Serial.println("\n[backSoon]");
|
||||||
|
|
||||||
|
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
|
||||||
|
Serial.println( "Failed to access Ethernet controller");
|
||||||
|
#if STATIC
|
||||||
|
ether.staticSetup(myip, gwip);
|
||||||
|
#else
|
||||||
|
if (!ether.dhcpSetup())
|
||||||
|
Serial.println("DHCP failed");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ether.printIp("IP: ", ether.myip);
|
||||||
|
ether.printIp("GW: ", ether.gwip);
|
||||||
|
ether.printIp("DNS: ", ether.dnsip);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop(){
|
||||||
|
// wait for an incoming TCP packet, but ignore its contents
|
||||||
|
if (ether.packetLoop(ether.packetReceive())) {
|
||||||
|
memcpy_P(ether.tcpOffset(), page, sizeof page);
|
||||||
|
ether.httpServerReply(sizeof page - 1);
|
||||||
|
}
|
||||||
|
}
|
276
lib-ext/ethercard.git/examples/etherNode/etherNode.ino
Normal file
276
lib-ext/ethercard.git/examples/etherNode/etherNode.ino
Normal file
|
@ -0,0 +1,276 @@
|
||||||
|
// Arduino demo sketch for testing RFM12B + ethernet
|
||||||
|
// 2010-05-20 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
|
||||||
|
|
||||||
|
// Listens for RF12 messages and displays valid messages on a webpage
|
||||||
|
// Memory usage exceeds 1K, so use Atmega328 or decrease history/buffers
|
||||||
|
//
|
||||||
|
// This sketch is derived from RF12eth.pde:
|
||||||
|
// May 2010, Andras Tucsni, http://opensource.org/licenses/mit-license.php
|
||||||
|
|
||||||
|
#include <EtherCard.h>
|
||||||
|
#include <JeeLib.h>
|
||||||
|
#include <avr/eeprom.h>
|
||||||
|
|
||||||
|
#define DEBUG 1 // set to 1 to display free RAM on web page
|
||||||
|
#define SERIAL 0 // set to 1 to show incoming requests on serial port
|
||||||
|
|
||||||
|
#define CONFIG_EEPROM_ADDR ((byte*) 0x10)
|
||||||
|
|
||||||
|
// configuration, as stored in EEPROM
|
||||||
|
struct Config {
|
||||||
|
byte band;
|
||||||
|
byte group;
|
||||||
|
byte collect;
|
||||||
|
word refresh;
|
||||||
|
byte valid; // keep this as last byte
|
||||||
|
} config;
|
||||||
|
|
||||||
|
// ethernet interface mac address - must be unique on your network
|
||||||
|
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
|
||||||
|
|
||||||
|
// buffer for an outgoing data packet
|
||||||
|
static byte outBuf[RF12_MAXDATA], outDest;
|
||||||
|
static char outCount = -1;
|
||||||
|
|
||||||
|
#define NUM_MESSAGES 10 // Number of messages saved in history
|
||||||
|
#define MESSAGE_TRUNC 15 // Truncate message payload to reduce memory use
|
||||||
|
|
||||||
|
static BufferFiller bfill; // used as cursor while filling the buffer
|
||||||
|
|
||||||
|
static byte history_rcvd[NUM_MESSAGES][MESSAGE_TRUNC+1]; //history record
|
||||||
|
static byte history_len[NUM_MESSAGES]; // # of RF12 messages+header in history
|
||||||
|
static byte next_msg; // pointer to next rf12rcvd line
|
||||||
|
static word msgs_rcvd; // total number of lines received modulo 10,000
|
||||||
|
|
||||||
|
byte Ethernet::buffer[1000]; // tcp/ip send and receive buffer
|
||||||
|
|
||||||
|
static void loadConfig() {
|
||||||
|
for (byte i = 0; i < sizeof config; ++i)
|
||||||
|
((byte*) &config)[i] = eeprom_read_byte(CONFIG_EEPROM_ADDR + i);
|
||||||
|
if (config.valid != 253) {
|
||||||
|
config.valid = 253;
|
||||||
|
config.band = 8;
|
||||||
|
config.group = 1;
|
||||||
|
config.collect = 1;
|
||||||
|
config.refresh = 5;
|
||||||
|
}
|
||||||
|
byte freq = config.band == 4 ? RF12_433MHZ :
|
||||||
|
config.band == 8 ? RF12_868MHZ :
|
||||||
|
RF12_915MHZ;
|
||||||
|
rf12_initialize(31, freq, config.group);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void saveConfig() {
|
||||||
|
for (byte i = 0; i < sizeof config; ++i)
|
||||||
|
eeprom_write_byte(CONFIG_EEPROM_ADDR + i, ((byte*) &config)[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
static int freeRam () {
|
||||||
|
extern int __heap_start, *__brkval;
|
||||||
|
int v;
|
||||||
|
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void setup(){
|
||||||
|
#if SERIAL
|
||||||
|
Serial.begin(57600);
|
||||||
|
Serial.println("\n[etherNode]");
|
||||||
|
#endif
|
||||||
|
loadConfig();
|
||||||
|
|
||||||
|
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
|
||||||
|
Serial.println( "Failed to access Ethernet controller");
|
||||||
|
if (!ether.dhcpSetup())
|
||||||
|
Serial.println("DHCP failed");
|
||||||
|
#if SERIAL
|
||||||
|
ether.printIp("IP: ", ether.myip);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
const char okHeader[] PROGMEM =
|
||||||
|
"HTTP/1.0 200 OK\r\n"
|
||||||
|
"Content-Type: text/html\r\n"
|
||||||
|
"Pragma: no-cache\r\n"
|
||||||
|
;
|
||||||
|
|
||||||
|
static void homePage(BufferFiller& buf) {
|
||||||
|
word mhz = config.band == 4 ? 433 : config.band == 8 ? 868 : 915;
|
||||||
|
buf.emit_p(PSTR("$F\r\n"
|
||||||
|
"<meta http-equiv='refresh' content='$D'/>"
|
||||||
|
"<title>RF12 etherNode - $D MHz, group $D</title>"
|
||||||
|
"RF12 etherNode - $D MHz, group $D "
|
||||||
|
"- <a href='c'>configure</a> - <a href='s'>send packet</a>"
|
||||||
|
"<h3>Last $D messages:</h3>"
|
||||||
|
"<pre>"), okHeader, config.refresh, mhz, config.group,
|
||||||
|
mhz, config.group, NUM_MESSAGES);
|
||||||
|
for (byte i = 0; i < NUM_MESSAGES; ++i) {
|
||||||
|
byte j = (next_msg + i) % NUM_MESSAGES;
|
||||||
|
if (history_len[j] > 0) {
|
||||||
|
word n = msgs_rcvd - NUM_MESSAGES + i;
|
||||||
|
buf.emit_p(PSTR("\n$D$D$D$D: OK"), // hack, to show leading zero's
|
||||||
|
n/1000, (n/100) % 10, (n/10) % 10, n % 10);
|
||||||
|
for (byte k = 0; k < history_len[j]; ++k)
|
||||||
|
buf.emit_p(PSTR(" $D"), history_rcvd[j][k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
long t = millis() / 1000;
|
||||||
|
word h = t / 3600;
|
||||||
|
byte m = (t / 60) % 60;
|
||||||
|
byte s = t % 60;
|
||||||
|
buf.emit_p(PSTR(
|
||||||
|
"</pre>"
|
||||||
|
"Uptime is $D$D:$D$D:$D$D"), h/10, h%10, m/10, m%10, s/10, s%10);
|
||||||
|
#if DEBUG
|
||||||
|
buf.emit_p(PSTR(" ($D bytes free)"), freeRam());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getIntArg(const char* data, const char* key, int value =-1) {
|
||||||
|
char temp[10];
|
||||||
|
if (ether.findKeyVal(data + 7, temp, sizeof temp, key) > 0)
|
||||||
|
value = atoi(temp);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void configPage(const char* data, BufferFiller& buf) {
|
||||||
|
// pick up submitted data, if present
|
||||||
|
if (data[6] == '?') {
|
||||||
|
byte b = getIntArg(data, "b");
|
||||||
|
byte g = getIntArg(data, "g");
|
||||||
|
byte c = getIntArg(data, "c", 0);
|
||||||
|
word r = getIntArg(data, "r");
|
||||||
|
if (1 <= g && g <= 250 && 1 <= r && r <= 3600) {
|
||||||
|
// store values as new settings
|
||||||
|
config.band = b;
|
||||||
|
config.group = g;
|
||||||
|
config.collect = c;
|
||||||
|
config.refresh = r;
|
||||||
|
saveConfig();
|
||||||
|
// re-init RF12 driver
|
||||||
|
loadConfig();
|
||||||
|
// clear history
|
||||||
|
memset(history_len, 0, sizeof history_len);
|
||||||
|
// redirect to the home page
|
||||||
|
buf.emit_p(PSTR(
|
||||||
|
"HTTP/1.0 302 found\r\n"
|
||||||
|
"Location: /\r\n"
|
||||||
|
"\r\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// else show a configuration form
|
||||||
|
buf.emit_p(PSTR("$F\r\n"
|
||||||
|
"<h3>Server node configuration</h3>"
|
||||||
|
"<form>"
|
||||||
|
"<p>"
|
||||||
|
"Freq band <input type=text name=b value='$D' size=1> (4, 8, or 9)<br>"
|
||||||
|
"Net group <input type=text name=g value='$D' size=3> (1..250)<br>"
|
||||||
|
"Collect mode: <input type=checkbox name=c value='1' $S> "
|
||||||
|
"Don't send ACKs<br><br>"
|
||||||
|
"Refresh rate <input type=text name=r value='$D' size=4> (1..3600 seconds)"
|
||||||
|
"</p>"
|
||||||
|
"<input type=submit value=Set>"
|
||||||
|
"</form>"), okHeader, config.band, config.group,
|
||||||
|
config.collect ? "CHECKED" : "",
|
||||||
|
config.refresh);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sendPage(const char* data, BufferFiller& buf) {
|
||||||
|
// pick up submitted data, if present
|
||||||
|
const char* p = strstr(data, "b=");
|
||||||
|
byte d = getIntArg(data, "d");
|
||||||
|
if (data[6] == '?' && p != 0 && 0 <= d && d <= 31) {
|
||||||
|
// prepare to send data as soon as possible in loop()
|
||||||
|
outDest = d & RF12_HDR_MASK ? RF12_HDR_DST | d : 0;
|
||||||
|
outCount = 0;
|
||||||
|
// convert the input string to a number of decimal data bytes in outBuf
|
||||||
|
++p;
|
||||||
|
while (*p != 0 && *p != '&') {
|
||||||
|
outBuf[outCount] = 0;
|
||||||
|
while ('0' <= *++p && *p <= '9')
|
||||||
|
outBuf[outCount] = 10 * outBuf[outCount] + (*p - '0');
|
||||||
|
++outCount;
|
||||||
|
}
|
||||||
|
#if SERIAL
|
||||||
|
Serial.print("Send to ");
|
||||||
|
Serial.print(outDest, DEC);
|
||||||
|
Serial.print(':');
|
||||||
|
for (byte i = 0; i < outCount; ++i) {
|
||||||
|
Serial.print(' ');
|
||||||
|
Serial.print(outBuf[i], DEC);
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
#endif
|
||||||
|
// redirect to home page
|
||||||
|
buf.emit_p(PSTR(
|
||||||
|
"HTTP/1.0 302 found\r\n"
|
||||||
|
"Location: /\r\n"
|
||||||
|
"\r\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// else show a send form
|
||||||
|
buf.emit_p(PSTR("$F\r\n"
|
||||||
|
"<h3>Send a wireless data packet</h3>"
|
||||||
|
"<form>"
|
||||||
|
"<p>"
|
||||||
|
"Data bytes <input type=text name=b size=50> (decimal)<br>"
|
||||||
|
"Destination node <input type=text name=d size=3> "
|
||||||
|
"(1..31, or 0 to broadcast)<br>"
|
||||||
|
"</p>"
|
||||||
|
"<input type=submit value=Send>"
|
||||||
|
"</form>"), okHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop(){
|
||||||
|
word len = ether.packetReceive();
|
||||||
|
word pos = ether.packetLoop(len);
|
||||||
|
// check if valid tcp data is received
|
||||||
|
if (pos) {
|
||||||
|
bfill = ether.tcpOffset();
|
||||||
|
char* data = (char *) Ethernet::buffer + pos;
|
||||||
|
#if SERIAL
|
||||||
|
Serial.println(data);
|
||||||
|
#endif
|
||||||
|
// receive buf hasn't been clobbered by reply yet
|
||||||
|
if (strncmp("GET / ", data, 6) == 0)
|
||||||
|
homePage(bfill);
|
||||||
|
else if (strncmp("GET /c", data, 6) == 0)
|
||||||
|
configPage(data, bfill);
|
||||||
|
else if (strncmp("GET /s", data, 6) == 0)
|
||||||
|
sendPage(data, bfill);
|
||||||
|
else
|
||||||
|
bfill.emit_p(PSTR(
|
||||||
|
"HTTP/1.0 401 Unauthorized\r\n"
|
||||||
|
"Content-Type: text/html\r\n"
|
||||||
|
"\r\n"
|
||||||
|
"<h1>401 Unauthorized</h1>"));
|
||||||
|
ether.httpServerReply(bfill.position()); // send web page data
|
||||||
|
}
|
||||||
|
|
||||||
|
// RFM12 loop runner, don't report acks
|
||||||
|
if (rf12_recvDone() && rf12_crc == 0 && (rf12_hdr & RF12_HDR_CTL) == 0) {
|
||||||
|
history_rcvd[next_msg][0] = rf12_hdr;
|
||||||
|
for (byte i = 0; i < rf12_len; ++i)
|
||||||
|
if (i < MESSAGE_TRUNC)
|
||||||
|
history_rcvd[next_msg][i+1] = rf12_data[i];
|
||||||
|
history_len[next_msg] = rf12_len < MESSAGE_TRUNC ? rf12_len+1
|
||||||
|
: MESSAGE_TRUNC+1;
|
||||||
|
next_msg = (next_msg + 1) % NUM_MESSAGES;
|
||||||
|
msgs_rcvd = (msgs_rcvd + 1) % 10000;
|
||||||
|
|
||||||
|
if (RF12_WANTS_ACK && !config.collect) {
|
||||||
|
#if SERIAL
|
||||||
|
Serial.println(" -> ack");
|
||||||
|
#endif
|
||||||
|
rf12_sendStart(RF12_ACK_REPLY, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// send a data packet out if requested
|
||||||
|
if (outCount >= 0 && rf12_canSend()) {
|
||||||
|
rf12_sendStart(outDest, outBuf, outCount, 1);
|
||||||
|
outCount = -1;
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue