mbed-simulator
Version:
Mbed OS 5 simulator
129 lines (107 loc) • 4.75 kB
JavaScript
window.MbedJSHal.lora = (function() {
var host = window.location.protocol + '//' + window.location.host;
var radioPtr = 0;
var ts = null; // timesync
// based on https://docs.google.com/spreadsheets/d/1voGAtQAjC1qBmaVuP1ApNKs1ekgUjavHuVQIXyYSvNc/edit#gid=0
function calculateTimeOnAir(_dataLength, _datarate, _bandwidth) {
var payloadSize = _dataLength;
var spreadFactor = _datarate; // already normalized
var explicitHeader = 1;
var lowDr = 0;
var codingRate = 5; // 4/5
var preamble = 8;
var bandwidth = 125;
switch (_bandwidth) {
case 7: bandwidth = 125; break;
case 8: bandwidth = 250; break;
case 9: bandwidth = 500; break;
}
var tsym = Math.pow(2, spreadFactor) / (bandwidth * 1000) * 1000;
// console.log('tsym', tsym);
var tPreamble = (preamble + 4.25) * tsym;
// console.log('tpreamb', tPreamble);
var payloadSymNb = 8+(Math.max(Math.ceil((8*payloadSize-4*spreadFactor+28+16-20*(1-explicitHeader))/(4*(spreadFactor-2*lowDr)))*(codingRate),0));
// console.log('payloadSymNb', payloadSymNb);
var tPayload = payloadSymNb * tsym;
var tPacket = tPayload + tPreamble;
// console.log('tPacket', tPacket);
return tPacket;
}
window.socket.on('lora-downlink', function (ev) {
let buffer = ev.data;
// todo check if its actually msg for us
// console.log(Date.now(), 'lora-downlink', ev);
obj.downlinkMsg = buffer;
var dataPtr = Module._malloc(buffer.length);
var dataHeap = new Uint8Array(Module.HEAPU8.buffer, dataPtr, buffer.length);
for (var ix = 0; ix < buffer.length; ix++) {
dataHeap[ix] = buffer[ix];
}
if (!radioPtr) {
return console.error('LoRa radio ptr is 0!');
}
// when to send?
var timeOnAir = calculateTimeOnAir(buffer.length, ev.datarate, ev.bandwidth);
var delay = ev.sendTs - ts.now() + timeOnAir;
console.log('lora RX send delay is', delay);
function go() {
console.log(/*Date.now(), */'handle_lora_downlink', 'dataLength', buffer.length, 'freq', ev.freq, 'bandwidth', ev.bandwidth, 'datarate', ev.datarate);
// @todo: check modulation
ccall('handle_lora_downlink', null,
[ 'number', 'number', 'number', 'number', 'number', 'number' ],
[ radioPtr, dataPtr, buffer.length, ev.freq, ev.bandwidth, ev.datarate ],
{ async: true });
}
if (delay <= 0) {
// this shouldn't be necessary as it'll be impossible to hit the windows on f.e. Class C, but
// need it to work on some slow internet connections
go();
}
else {
setTimeout(go, delay);
}
});
function init(ptr) {
console.log('LoRa radio init', ptr);
radioPtr = ptr;
// create a timesync instance
ts = timesync.create({
server: '/timesync',
interval: 10000
});
}
function sendLoRa(channel, power, bandwidth, datarate, data, size) {
var buffer = [].slice.call(new Uint8Array(Module.HEAPU8.buffer, data, size));
var timeOnAir = calculateTimeOnAir(buffer.length, datarate, bandwidth);
setTimeout(function() {
var x = new XMLHttpRequest();
x.onload = function() {
console.log('sendLoRa', x.status, x.responseText);
};
x.open('POST', host + '/api/lora/send');
x.setRequestHeader('Content-Type', 'application/json');
x.send(JSON.stringify({
payload: buffer,
freq: channel,
bandwidth: bandwidth,
datarate: datarate
}));
console.log('sendLoRa', 'timeOnAir', timeOnAir, 'channel', channel, 'power', power, 'bandwidth', bandwidth, 'datarate', datarate, 'buffer', buffer, 'size', size);
console.log('encoded packet', buffer.map(function(b) {
var j = b.toString(16).toUpperCase();
if (j.length === 1) return '0' + j;
return j;
}).join(''));
}, timeOnAir);
}
function sendFsk(channel, power, bandwidth, datarate, data, size) {
var buffer = [].slice.call(new Uint8Array(Module.HEAPU8.buffer, data, size));
console.log('sendFsk', 'channel', channel, 'power', power, 'bandwidth', bandwidth, 'datarate', datarate, 'buffer', buffer, 'size', size);
}
var obj = {
init: init,
sendLoRa: sendLoRa,
sendFsk: sendFsk
};
return obj;
})();