They are as far as I used and verified the RN2483 Module. I did not venture into the WAN (mac commands) part. getStatus(...) may have something that is frequency wise not compatible, but I did not look into it (yet). I also did not use any configuration, for example setting transmit power, frequency, etc. For now - my next and first real field validation (with sensors) - I plan to just use plain radio functions (.radioTX(...) and .radioRX(...).
Below is the code I used - changing the onInit() before upload for the station's specific tx or rx function. The transmitting station sends an autoText() - time in HH:MM:SS format - every 5 seconds. The receiving station does a 90% receiving duty cycle every 10 seconds. First, I just requested the RN2483 module code, but I was not successful in getting a communication link going (TX/RX-RX/TX wiring mess up). In addition I wanted to better understand the module implementation and had temporary added more output. Now, there is no need anymore for having the module code inline.
Interesting detail may be the way do the logging 'to console' in absence of a console / when disconnected.
If *logging to console is off, I still DO log*... using Morse code in functions lg(...) and bl():
T logMessigIdDigit with red LED 'morse-ing' for errors, and green LED for information (ok) . Since I use setTimeouts() the messaging is not real time / synchronous, but async... with the given timing of 5 and 10 seconds respective, this is not an issue. I can say on the receiver that it was successful when I see 'morse-blinking' T4 on green LED (Long - Short, Short,Short, Short, Long blinks / Dash - Dot Dot Dot Dot Dash) and in error case, ***T3 on red LED ***. (cds is the coded string. A new log message id is appended at the end of the string and the string's first char is consumed to do the Dash and Dot timing; some extra characters do the Breaks between the characters - T and Digit - and G(reen) and R(ed) select LED2 and LED1 respective). ;-)
// loraRN2309Test.js
// PICO - DIL pin numbering USB to the left
// Lora - SIL pin numbering bottom DrAzzy break out board
// Pin PICO Pin LORA
// 1 GND ------------ 8 GND (antena/bottom most right side)
// 2 VBat 7 Vin
// 3 3V3 ------------ 6 3.3v
// ( 4 B3 ------------- 5 RST - reset, optional)
// 5 B4 4 RTS (Serial)
// 6 B5 3 CTS (Serial)
// 7 B6 USART1 TX --- 2 RX (Serial)
// 8 B7 USART2 RX --- 1 TX (Serial)
// var Lora = require("RN2483"); // same(?) as RN2309
// module emulation =========================================
// module code from http://www.espruino.com/modules/RN2483.js:
// module emulation
var Lora = (function(){ // module emulation...
var exports = {}; // ...begin 'bracket'
/* Copyright (c) 2016 Gordon Williams, Pur3 Ltd. See the file LICENSE for copying permission. */
function toHex(m) {
m = E.toString(m);
var hex = "";
for (var i in m)
hex += (m.charCodeAt(i)+256).toString(16).substr(-2);
return hex;
}
function fromHex(d, startIdx) {
var msg = "";
for (var i=startIdx;i<d.length;i+=2)
msg += String.fromCharCode(parseInt(d.substr(i,2),16));
return msg;
}
/** Connect to a RN2483.
First argument is the serial device, second is an
object containing:
{
reset : pin // optional
debug : true // optional
}
*/
function RN2483(serial, options) {
this.ser = serial;
this.options = options||{};
this.at = require("AT").connect(serial);
if (this.options.debug) this.at.debug();
var lora = this;
this.at.registerLine("mac_rx 1",function(d) {
lora.emit("message", fromHex(d,9));
});
this.macOn = true; // are we in LoRaWAN mode or not?
}
/// Reset, either via the reset line if defined, or by a serial command
RN2483.prototype.reset = function(callback) {
if (this.options.reset) {
this.options.reset.reset();
this.options.reset.set();
} else {
this.at.cmd("sys reset\r\n",1000,callback);
}
if (callback) callback();
};
/// Call the callback with the RN2483's firmware version
RN2483.prototype.getVersion = function(callback) {
this.at.cmd("sys get ver\r\n",1000,function(d) {
if (!d) {callback();return;}
d = d.split(" ");
callback({
type : d[0],
version : d[1],
date : d.slice(2).join(" ")
});
});
};
/** Call the callback with the current status as an object.
Includes: EUI, VDD, appEUI, devEUI, band, dataRate, rxDelay1 and rxDelay2 */
RN2483.prototype.getStatus = function(callback) {
var status = {};
var at = this.at;
(new Promise(function(resolve) {
at.cmd("sys get hweui\r\n",500,resolve);
})).then(function(d) {
status.EUI = d;
return new Promise(function(resolve) {
at.cmd("sys get vdd\r\n",500,resolve);
});
}).then(function(d) {
status.VDD = parseInt(d,10)/1000;
return new Promise(function(resolve) {
at.cmd("mac get appeui\r\n",500,resolve);
});
}).then(function(d) {
status.appEUI = d;
return new Promise(function(resolve) {
at.cmd("mac get deveui\r\n",500,resolve);
});
}).then(function(d) {
status.devEUI = d;
return new Promise(function(resolve) {
at.cmd("mac get band\r\n",500,resolve);
});
}).then(function(d) {
status.band = d;
return new Promise(function(resolve) {
at.cmd("mac get dr\r\n",500,resolve);
});
}).then(function(d) {
status.dataRate = d;
return new Promise(function(resolve) {
at.cmd("mac get rxdelay1\r\n",500,resolve);
});
}).then(function(d) {
status.rxDelay1 = d;
return new Promise(function(resolve) {
at.cmd("mac get rxdelay2\r\n",500,resolve);
});
}).then(function(d) {
status.rxDelay2 = d;
return new Promise(function(resolve) {
at.cmd("mac get rx2 868\r\n",500,resolve);
});
}).then(function(d) {
status.rxFreq2_868 = d;
callback(status);
});
};
/** configure the LoRaWAN parameters
devAddr = 4 byte address for this device as hex - eg. "01234567"
nwkSKey = 16 byte network session key as hex - eg. "01234567012345670123456701234567"
appSKey = 16 byte application session key as hex - eg. "01234567012345670123456701234567"
*/
RN2483.prototype.LoRaWAN = function(devAddr,nwkSKey,appSKey, callback)
{
var at = this.at;
(new Promise(function(resolve) {
at.cmd("mac set devaddr "+devAddr+"\r\n",500,resolve);
})).then(function(d) {
return new Promise(function(resolve) {
at.cmd("mac set nwkskey "+nwkSKey+"\r\n",500,resolve);
});
}).then(function(d) {
return new Promise(function(resolve) {
at.cmd("mac set appskey "+appSKey+"\r\n",500,resolve);
});
}).then(function(d) {
return new Promise(function(resolve) {
at.cmd("mac join ABP\r\n",2000,resolve);
});
}).then(function(d) {
callback((d=="ok")?null:((d===undefined?"Timeout":d)));
});
};
/// Set whether the MAC (LoRaWan) is enabled or disabled
RN2483.prototype.setMAC = function(on, callback) {
if (this.macOn==on) return callback();
this.macOn = on;
this.at.cmd("mac "+(on?"resume":"pause")+"\r\n",500,callback);
};
/// Transmit a message over the radio (not using LoRaWAN)
RN2483.prototype.radioTX = function(msg, callback) {
var at = this.at;
this.setMAC(false, function() {
// convert to hex
at.cmd("radio tx "+toHex(msg)+"\r\n",2000,callback);
});
};
/** Transmit a message (using LoRaWAN). Will call the callback with 'null'
on success, or the error message on failure.
In LoRa, messages are received right after data is transmitted - if
a message was received, the 'message' event will be fired, which
can be received if you added a handler as follows:
lora.on('message', function(data) { ... });
*/
RN2483.prototype.loraTX = function(msg, callback) {
var at = this.at;
this.setMAC(true, function() {
// convert to hex
at.cmd("mac tx uncnf 1 "+toHex(msg)+"\r\n",2000,function(d) {
callback((d=="ok")?null:((d===undefined?"Timeout":d)));
});
});
};
/** Receive a message from the radio (not using LoRaWAN) with the given timeout
in miliseconds. If the timeout is reached, callback will be called with 'undefined' */
RN2483.prototype.radioRX = function(timeout, callback) {
var at = this.at;
this.setMAC(false, function() {
at.cmd("radio set wdt "+timeout+"\r\n", 500, function() {
at.cmd("radio rx 0\r\n", timeout+500, function cb(d) {
if (d=="ok") return cb;
if (d===undefined || d.substr(0,10)!="radio_rx ") { callback(); return; }
callback(fromHex(d,10));
});
});
});
};
exports = RN2483;
// / module emulation
return exports; // module emulation...
})(); // ...end 'bracket'
// app. cont. =========================================
var loraDbg = true; // Debug
var loraRst = B3; // Reset
var loraBd = 57600; // Baud
var loraSer = Serial1; // USART1
var loraTx = B6; // USART1 TX
var loraRx = B7; // USART1 RX
var rxIntMs = 10000; // rx cycle interval in [ms]
var rxIntId = null; // rx cycle interval id
var rxDtyMs = 9000; // rx duty interval in [ms] (in of rxIntMs)
var txIntMs = 5000; // tx cycle interval in [ms]
var txIntId = null; // tx interval id
var logging = true; // log activities to console
var cds="";
var cdl=LED2;
function lg(ok,cd,obj) { // logging / LED blinking
if (logging) console.log(obj);
var l = cds.length;
cds += "BB"+((ok) ? "G" : "R")+"LB"+blds[cd];
if (l === 0) bl();
}
var blts= {"L":300,"S":80,"P":120,"B":450};
var blds = ["LLLLL", "SLLLL", "SSLLL", "SSSLL", "SSSSL", "SSSSS", "LSSSS", "LLSSS", "LLLSS", "LLLLS"];
function bl() {
var c = cds.charAt(0);
if (c=="G") { cdl = LED2; cds = cds.substr(1); c = cds.charAt(0); }
else if (c=="R") { cdl = LED1; cds = cds.substr(1); c = cds.charAt(0); }
if (c!="B") cdl.set();
setTimeout(function(){
cdl.reset();
setTimeout(function(){
cds = cds.substr(1);
if (cds.length > 0) setTimeout(bl,1);
},blts.P);
},blts[c]);
}
function setup() {
loraSetup();
lg(1,0,"0: setup done.");
}
function loraSetup() {
var d = loraDbg && logging; // compound d(ebug)
loraSer.setup(loraBd, { tx:loraTx, rx:loraRx });
lora = new Lora(loraSer, { reset:loraRst, debug: d });
lora.reset(function(data){
lg(1,1,"1: reset: "+data);
});
}
function tx(txtIn) {
var txt = ""
+ ((txtIn)
? txtIn
: "default tx text: " + autoText()
);
lora.radioTX(txt, function() { lg(1,2,"2: sent: " + txt); });
}
function txc() {
if (txIntId) return; // already continuously sending
txIntId = setInterval(function(){
tx(autoText());
},txIntMs);
}
function rx() {
lora.radioRX(rxDtyMs, function(data) {
if (data === undefined) {
lg(0,3,"3: No data received");
} else {
lg(1,4,"4: Data: "+JSON.stringify(data));
}
});
}
function rxc() {
if (rxIntId) return; // already continuously receiving
rxIntId = setInterval(function(){
rx();
},rxIntMs);
}
function getStatus() {
lora.getStatus(function(sta){
lg(1,5,JSON.stringify(sta));
});
}
function getVersion() {
lora.getVersion(function(ver){
lg(1,9,"9: ver: "+JSON.stringify(ver));
});
}
function h() { // halt any ongoing tx / rx
if (txIntId) { // halt continuous sending
txIntId = clearInterval(txIntId);
}
if (rxIntId) { // halt continuous receiving
rxIntId = clearInterval(rxIntId);
}
}
function autoText() { // auto text for continous tx: time hh:mm:ss
var d = new Date();
hs = "0" + d.getHours();
ms = "0" + d.getMinutes();
ss = "0" + d.getSeconds();
t = hs.substr(hs.length-2)
+":"+ ms.substr(ms.length-2)
+":"+ ss.substr(ss.length-2);
return t;
}
function onInit() {
logging = false;
setup();
txc();
}
Espruino is a JavaScript interpreter for low-power Microcontrollers. This site is both a support community for Espruino and a place to share what you are working on.
They are as far as I used and verified the RN2483 Module. I did not venture into the WAN (mac commands) part.
getStatus(...)
may have something that is frequency wise not compatible, but I did not look into it (yet). I also did not use any configuration, for example setting transmit power, frequency, etc. For now - my next and first real field validation (with sensors) - I plan to just use plain radio functions (.radioTX(...)
and.radioRX(...)
.Below is the code I used - changing the onInit() before upload for the station's specific tx or rx function. The transmitting station sends an autoText() - time in HH:MM:SS format - every 5 seconds. The receiving station does a 90% receiving duty cycle every 10 seconds. First, I just requested the RN2483 module code, but I was not successful in getting a communication link going (TX/RX-RX/TX wiring mess up). In addition I wanted to better understand the module implementation and had temporary added more output. Now, there is no need anymore for having the module code inline.
Interesting detail may be the way do the logging 'to console' in absence of a console / when disconnected.
If *logging to console is off, I still DO log*... using Morse code in functions
lg(...)
andbl()
:T logMessigIdDigit with red LED 'morse-ing' for errors, and green LED for information (ok) . Since I use
setTimeouts()
the messaging is not real time / synchronous, but async... with the given timing of 5 and 10 seconds respective, this is not an issue. I can say on the receiver that it was successful when I see 'morse-blinking' T4 on green LED (Long - Short, Short,Short, Short, Long blinks / Dash - Dot Dot Dot Dot Dash) and in error case, ***T3 on red LED ***. (cds
is the coded string. A new log message id is appended at the end of the string and the string's first char is consumed to do the Dash and Dot timing; some extra characters do the Breaks between the characters - T and Digit - and G(reen) and R(ed) select LED2 and LED1 respective). ;-)