我将outputTagJson设置为cordova app对象的全局变量。但是,当我尝试在函数readDataBlock: function()
中显示时,我无法显示整个JSON,只会收到一条消息并将被复制。如果我在onListeningData: function(data)
中显示JSON,则数据正确且完整。我认为可能导致此问题的部分来自concat部分,其中我将每个响应与回车连接(ASCII代码= 13)。但是,我没有机会遇到这个问题。事实上,我认为我的问题可以更通用地描述为:我在javascript中设置全局变量,但是我无法从某个函数范围中获取完整的值。
var app = {
macAddress: "00:0B:CE:07:36:AB", // get your mac address from bluetoothSerial.list
chars: "",
responseGroup: [],
responseHeader: [''],
outputTagJson: {},
timeList: [],
Execution_List: ['M,0\rU,18\rGR\rG,LOCATE,04,0,1,3\rO,2,30,0,0\rR,8\rS,2\rM,433\r'],
/*
Application constructor
*/
initialize: function() {
this.bindEvents();
console.log("Starting SimpleSerial app");
},
/*
bind any events that are required on startup to listeners:
*/
bindEvents: function() {
document.addEventListener('deviceready', this.onDeviceReady, false);
connectButton.addEventListener('touchend', app.Connect, false);
scanButton.addEventListener('touchend', app.disCover, false);
},
/*
this runs when the device is ready for user interaction:
*/
onDeviceReady: function() {
// check to see if Bluetooth is turned on.
// this function is called only
//if isEnabled(), below, returns success:
var listPorts = function() {
// list the available BT ports:
bluetoothSerial.list(
function(results) {
app.display(JSON.stringify(results));
},
function(error) {
app.display(JSON.stringify(error));
}
);
};
// if isEnabled returns failure, this function is called:
var notEnabled = function() {
app.display("Bluetooth is not enabled.")
};
// check if Bluetooth is on:
bluetoothSerial.isEnabled(
listPorts,
notEnabled
);
},
disCover: function() {
var scan = function () {
app.clear();
app.display("Scanning available Devices...");
bluetoothSerial.discoverUnpaired(
function(results) {
app.display(JSON.stringify(results));
},
function(error) {
app.display(JSON.stringify(error));
}
);
};
var notEnabled = function() {
app.display("Bluetooth is not enabled.")
};
bluetoothSerial.isEnabled(
scan,
notEnabled
);
},
/*
Connects if not connected, and disconnects if connected:
*/
Connect: function() {
// connect() will get called only if isConnected() (below)
// returns failure. In other words, if not connected, then connect:
var connect = function () {
// if not connected, do this:
// clear the screen and display an attempt to connect
app.clear();
app.display("Attempting to connect. " +
"Make sure the serial port is open on the target device.");
app.display("Connected to: " + app.macAddress);
connectButton.innerHTML = "Disconnect";
// attempt to connect:
bluetoothSerial.connect(
app.macAddress, // device to connect to
app.connectSuccess, // start listening if you succeed
app.showError // show the error if you fail
);
};
// disconnect() will get called only if isConnected() (below)
// returns success In other words, if connected, then disconnect:
var disconnect = function () {
app.display("attempting to disconnect");
// if connected, do this:
bluetoothSerial.disconnect(
app.closePort, // stop listening to the port
app.showError // show the error if you fail
);
};
// here's the real action of the manageConnection function:
bluetoothSerial.isConnected(disconnect, connect);
},
/*
subscribes to a Bluetooth serial listener for newline
and changes the button:
*/
getBatteryInfo: function() {
var Bcomm = 'WB\r';
app.writeCommand(Bcomm);
},
// On Connection Success, we want to display battery info
// and send command immediately
connectSuccess: function() {
app.getBatteryInfo();
for (var i = 0; i < app.Execution_List.length;i++)
{
(function(n) {
app.writeCommand(app.Execution_List[n]);
})(i);
}
},
// Wrapper of bluetooth write, read reponse immediately
// after sending commands
writeCommand: function(data) {
bluetoothSerial.write(data,
function(data) {
console.log('sending %s',data);
}, function(error){
console.log(error);
});
app.readDataBlock();
app.responseGroup = [];
},
/*
Processor part:
Parsing Response String and out a JSON of each Attributes
*/
onParsing: function(data){
var alphabeticRegex = /^[A-Z]+$/i; // Response header start with an alphabetic string
var decimalRegex = /^\d+\.?\d*$/;
app.outputTagJson = {};
if (data == null || data == '\r') // Sanity Check
{
return;
}
Element = data.split(',');
while (true) // For some response, it didn't start with 'A-z'
{
if (alphabeticRegex.test(Element[0]) != true)
{
Element.splice(0,1);
}
else
{
break;
}
}
// Parsing each options, not generic, have to deal with each specific case.
switch (Element[0]) {
case 'VV':
app.outputTagJson.readerIdentifier = {};
app.outputTagJson.readerIdentifier.buildID = Element[2];
app.outputTagJson.readerIdentifier.modelID = Element[3];
break;
case 'V':
app.outputTagJson.Battery = {};
app.outputTagJson.Battery.percentage = Element[2];
if (Element[3] != null)
{
app.outputTagJson.Battery.chargingmode = "Charging";
}
else
{
app.outputTagJson.Battery.chargingmode = "Not charged";
}
break;
case 'U':
app.outputTagJson.timeStamp = {};
app.outputTagJson.timeStamp.range = 10;
app.outputTagJson.timeStamp.range = 1.00;
break;
case 'M':
app.outputTagJson.readerMode = {};
if (Element[1] == 0) app.outputTagJson.readerMode.message = 'Standby';
if (Element[1] == 20) app.outputTagJson.readerMode.message = '303MHz';
if (Element[1] == 40) app.outputTagJson.readerMode.message = 'Japanese 303MHz';
if (Element[1] == 433) app.outputTagJson.readerMode.message = '433MHz';
else app.outputTagJson.readerMode.message = 'In motion';
break;
case 'H':
var len = Element.length;
var props = ['tagID','groupID','payload','timeStamp','sigStrenthA','sigStrenthB'];
app.outputTagJson.Tag = {};
if (len >= 2)
{
app.outputTagJson.Tag[props[0]] = Element[1];
app.outputTagJson.Tag.isLost = "False";
for(var i=3;i<=len;i++)
app.outputTagJson.Tag[props[i-2]] = Element[i-1].slice(1,Element[i-1].length);
}
break;
case 'L':
var len = Element.length;
var props = ['tagID','groupID','payload','timeStamp'];
app.outputTagJson.Tag = {};
if (len >= 2)
{
app.outputTagJson.Tag[props[0]] = Element[1];
app.outputTagJson.Tag.isLost = "True";
for(var i=3;i<=len;i++)
app.outputTagJson.Tag[props[i-2]] = Element[i-1].slice(1,Element[i-1].length);
}
break;
case 'E':
app.outputTagJson.Error = {};
if (Element[1] == 2) app.outputTagJson.Error.message = "Received command is invalid";
if (Element[1] == 3) app.outputTagJson.Error.message = "Command has too many parameters";
if (Element[1] == 4) app.outputTagJson.Error.message = "A command parameter is out of range";
if (Element[1] == 5) app.outputTagJson.Error.message = "Maximum number of group codes is exceeded";
if (Element[1] == 6) app.outputTagJson.Error.message = "Character buffer is full. One or more tag reports were dropped";
if (Element[1] == 7) app.outputTagJson.Error.message = "DSP offline. Indicates DSP failure or failed upgrade of DSP firmware";
if (Element[1] == 8) app.outputTagJson.Error.message = "Access denied. Indicates security is enabled and a valid ':login' is required";
break;
default:
break;
}
},
// Listening to data, function will be continuous invoked
// until there's no more incoming data or unsubscribe/disconnect
// appears
onListeningData: function(data) {
var responseLine = [];
console.log('Receiving data from reader');
// Convert raw data (binary arrays) to Unit8Array (ASCII code)
var bytes = new Uint8Array(data);
// Concat all integer until carriage return appears.
for (var i = 0; i< bytes.length; i++)
{
responseLine.push(bytes[i]);
if (bytes[i] == 13)
{
app.responseGroup.push(responseLine);
app.responseGroup = Array.prototype.concat.apply([],app.responseGroup);
responseLine = [];
}
else if (bytes[i] != 13 && i == bytes.length-1)
{
app.responseGroup.push(responseLine);
}
}
// Once we get the carriage return, parse it to string
// Do sanity check for null data and single carriage return
// single carraige return appears when <set-like> command is sent
// to the reader (a mark as <set-like> command success)
try {
var i = 0;
if (app.responseGroup.length > 0)
{
while (i<app.responseGroup.length)
{
if (app.responseGroup[i] == 13)
{
var strGroup = app.responseGroup.splice(0,i+1);
strGroup.splice(-1);
var response = String.fromCharCode.apply(null, strGroup);
app.onParsing(response);
//app.display(JSON.stringify(app.outputTagJson));
i = 0;
}
else
{
i++;
}
}
}
else{
throw err;
}
} catch(err) {
console.log(err);
}
},
readDataBlock: function() {
// set up a listener to listen for newlines
// and display any new data that's come in since
// the last newline:
console.log('going to send data to the reader');
//'M,0\rGR\rG,LOCATE,04,0,1,3\rO,2,30,0,0\rR,8\rS,2\rM,433\r'
//'G,LOCATE,04,0,0,0\rS,2\rO,1,0,0,2\rU,18\rN,0\rM,433\rZ,99,99\r'
bluetoothSerial.subscribeRawData(app.onListeningData,
function(error){
console.log(error);
});
if (JSON.stringify(app.outputTagJson) != "{}")
app.display(JSON.stringify(app.outputTagJson));
},
/*
unsubscribes from any Bluetooth serial listener and changes the button:
*/
closePort: function() {
// if you get a good Bluetooth serial connection:
app.display("Disconnected from: " + app.macAddress);
// change the button's name:
connectButton.innerHTML = "Connect";
// unsubscribe from listening:
bluetoothSerial.unsubscribe(
function (data) {
app.display(data);
},
app.showError
);
},
/*
appends @error to the message div:
*/
showError: function(error) {
app.display(error);
},
/*
appends @message to the message div:
*/
display: function(message) {
var display = document.getElementById("message"), // the message div
lineBreak = document.createElement("p"), // a line break
label = document.createTextNode(message); // create the label
display.appendChild(lineBreak); // add a line break
display.appendChild(label); // add the message node
},
/*
clears the message div:
*/
clear: function() {
var display = document.getElementById("message");
display.innerHTML = "";
}
}; // end of app
答案 0 :(得分:1)
您的问题是您的功能范围。当您尝试在app中使用app.something时,您将在app对象的范围内创建新的var app并使用它的.something。换句话说,当您尝试在对象内部使用对象名称时,您将创建具有相同名称的局部变量,该变量将在执行代码时覆盖全局变量。应始终避免在本地覆盖全局变量。
这里完美地解释了:How do JavaScript closures work?
答案 1 :(得分:0)
我同意@Teo在他的回答中所说的内容,所以我重构了我的代码,它现在有效。基本上,我还需要一个回调来包装我的局部变量和函数。
然后我在函数和main中分隔了我的代码:
reader.js:
var reader = {
location_command: 'M,0\rU,18\rGR\rG,LOCATE,04,0,1,3\rO,2,30,0,0\rR,8\rS,2\rM,433\r',
tagLocation_callback: "",
getTagLocation: function(tagId,timeout,callback) {
console.log('in getTagLocation func')
reader.tagLocation_callback = callback;
reader.writeCommand(reader.location_command);
// Subscribe Raw Data
bluetoothSerial.subscribe(
'\r',
reader.onListeningData,
function(error){
console.log(error);
});
},
// Wrapper of bluetooth write, read reponse immediately
// after sending commands
writeCommand: function(command) {
console.log('sending %s', command[0]);
bluetoothSerial.write(command,
function(data) {
console.log('sent data %s',data);
}, function(error){
console.log(error);
});
},
// Listening to data, function will be continuous invoked
// until there's no more incoming data or unsubscribe/disconnect
// appears
onListeningData: function(data) {
var outputTagJson = reader.onParsing(data);
reader.tagLocation_callback(outputTagJson);
},
/*
Processor part:
Parsing Response String and out a JSON of each Attributes
*/
onParsing: function(data){
data = data.slice(0,data.length-1);
var alphabeticRegex = /^[A-Z]+$/i; // Response header start with an alphabetic string
var decimalRegex = /^\d+\.?\d*$/;
var outputTagJson = {};
if (data == null || data == '\r') // Sanity Check
{
return;
}
Element = data.split(',');
while (true) // For some response, it didn't start with 'A-z'
{
if (alphabeticRegex.test(Element[0]) != true)
{
Element.splice(0,1);
}
else
{
break;
}
}
// Parsing each options, not generic, have to deal with each specific case.
switch (Element[0]) {
case 'VV':
outputTagJson.readerIdentifier = {};
outputTagJson.readerIdentifier.buildID = Element[2];
outputTagJson.readerIdentifier.modelID = Element[3];
break;
case 'V':
outputTagJson.Battery = {};
outputTagJson.Battery.percentage = Element[2];
if (Element[3] != null)
{
outputTagJson.Battery.chargingmode = "Charging";
}
else
{
outputTagJson.Battery.chargingmode = "Not charged";
}
break;
case 'U':
outputTagJson.timeStamp = {};
outputTagJson.timeStamp.range = 10;
outputTagJson.timeStamp.range = 1.00;
break;
case 'M':
outputTagJson.readerMode = {};
if (Element[1] == 0) outputTagJson.readerMode.message = 'Standby';
if (Element[1] == 20) outputTagJson.readerMode.message = '303MHz';
if (Element[1] == 40) outputTagJson.readerMode.message = 'Japanese 303MHz';
if (Element[1] == 433) outputTagJson.readerMode.message = '433MHz';
else outputTagJson.readerMode.message = 'In motion';
break;
case 'H':
var len = Element.length;
var props = ['tagID','groupID','payload','timeStamp','sigStrenthA','sigStrenthB'];
outputTagJson.Tag = {};
if (len >= 2)
{
outputTagJson.Tag[props[0]] = Element[1];
outputTagJson.Tag.isLost = "False";
for(var i=3;i<=len;i++)
outputTagJson.Tag[props[i-2]] = Element[i-1].slice(1,Element[i-1].length);
}
break;
case 'L':
var len = Element.length;
var props = ['tagID','groupID','payload','timeStamp'];
outputTagJson.Tag = {};
if (len >= 2)
{
outputTagJson.Tag[props[0]] = Element[1];
outputTagJson.Tag.isLost = "True";
for(var i=3;i<=len;i++)
outputTagJson.Tag[props[i-2]] = Element[i-1].slice(1,Element[i-1].length);
}
break;
case 'E':
outputTagJson.Error = {};
if (Element[1] == 2) outputTagJson.Error.message = "Received command is invalid";
if (Element[1] == 3) outputTagJson.Error.message = "Command has too many parameters";
if (Element[1] == 4) outputTagJson.Error.message = "A command parameter is out of range";
if (Element[1] == 5) outputTagJson.Error.message = "Maximum number of group codes is exceeded";
if (Element[1] == 6) outputTagJson.Error.message = "Character buffer is full. One or more tag reports were dropped";
if (Element[1] == 7) outputTagJson.Error.message = "DSP offline. Indicates DSP failure or failed upgrade of DSP firmware";
if (Element[1] == 8) outputTagJson.Error.message = "Access denied. Indicates security is enabled and a valid ':login' is required";
break;
default:
break;
}
return outputTagJson;
},
unsubscribeTagLocation: function(callback){
console.log("in unsubscribeTagLocation function ");
bluetoothSerial.unsubscribe(
function(data){
console.log(data);
callback("{message: 'tag location unsubscribed successfully!'}")
},
function(error) {
console.log(error);
});
},
};
app.js:
var app = {
macAddress: "00:0B:CE:01:A4:D7", // get your mac address from bluetoothSerial.list
//00:0B:CE:01:A4:D7
//"00:0B:CE:07:36:AB"
responseHeader: [''],
timeList: [],
/*
Application constructor
*/
initialize: function() {
this.bindEvents();
console.log("Starting SimpleSerial app");
},
/*
bind any events that are required on startup to listeners:
*/
bindEvents: function() {
document.addEventListener('deviceready', this.onDeviceReady, false);
connectButton.addEventListener('touchend', app.Connect, false);
scanButton.addEventListener('touchend', app.disCover, false);
},
/*
this runs when the device is ready for user interaction:
*/
onDeviceReady: function() {
// check to see if Bluetooth is turned on.
// this function is called only
//if isEnabled(), below, returns success:
var listPorts = function() {
// list the available BT ports:
bluetoothSerial.list(
function(results) {
app.display(JSON.stringify(results));
},
function(error) {
app.display(JSON.stringify(error));
}
);
};
// if isEnabled returns failure, this function is called:
var notEnabled = function() {
app.display("Bluetooth is not enabled.")
};
// check if Bluetooth is on:
bluetoothSerial.isEnabled(
listPorts,
notEnabled
);
},
disCover: function() {
var scan = function () {
app.clear();
app.display("Scanning available Devices...");
bluetoothSerial.discoverUnpaired(
function(results) {
app.display(JSON.stringify(results));
},
function(error) {
app.display(JSON.stringify(error));
}
);
};
var notEnabled = function() {
app.display("Bluetooth is not enabled.")
};
bluetoothSerial.isEnabled(
scan,
notEnabled
);
},
/*
Connects if not connected, and disconnects if connected:
*/
Connect: function() {
// connect() will get called only if isConnected() (below)
// returns failure. In other words, if not connected, then connect:
var connect = function () {
// if not connected, do this:
// clear the screen and display an attempt to connect
app.clear();
app.display("Attempting to connect. " +
"Make sure the serial port is open on the target device.");
// attempt to connect:
bluetoothSerial.connect(
app.macAddress, // device to connect to
app.connectSuccess, // start listening if you succeed
app.showError // show the error if you fail
);
};
// disconnect() will get called only if isConnected() (below)
// returns success In other words, if connected, then disconnect:
var disconnect = function () {
app.display("attempting to disconnect");
// if connected, do this:
bluetoothSerial.disconnect(
app.closePort, // stop listening to the port
app.showError // show the error if you fail
);
};
// here's the real action of the manageConnection function:
bluetoothSerial.isConnected(disconnect, connect);
},
/*
subscribes to a Bluetooth serial listener for newline
and changes the button:
*/
/*getBatteryInfo: function() {
var Bcomm = 'WB\r';
app.writeCommand(Bcomm);
if (JSON.stringify(app.outputTagJson) != "{}")
{
bluetoothSerial.unsubscribe(function(data) {
app.display(JSON.stringify(app.outputTagJson));
},
function(error) {
console.log(error);
});
return;
}
bluetoothSerial.subscribe(
'\r',
reader.onListeningData,
function(error){
console.log(error);
});
},*/
displayResult: function(data){
app.display("output message : ");
app.display(JSON.stringify(data));
},
// On Connection Success, we want to display battery info
// and send command immediately
connectSuccess: function() {
console.log("in connectSuccess");
app.display("Connected to: " + app.macAddress);
connectButton.innerHTML = "Disconnect";
reader.getTagLocation('00198525',10000, app.displayResult);
setTimeout(function(){
reader.unsubscribeTagLocation(app.displayResult);
}, 5000);
},
/*
unsubscribes from any Bluetooth serial listener and changes the button:
*/
closePort: function() {
app.clear();
// if you get a good Bluetooth serial connection:
app.display("Disconnected from: " + app.macAddress);
// change the button's name:
connectButton.innerHTML = "Connect";
// unsubscribe from listening:
bluetoothSerial.unsubscribe(
function (data) {
app.display(data);
},
app.showError
);
},
/*
appends @error to the message div:
*/
showError: function(error) {
app.display(error);
},
/*
appends @message to the message div:
*/
display: function(message) {
var display = document.getElementById("message"), // the message div
lineBreak = document.createElement("p"), // a line break
label = document.createTextNode(message); // create the label
display.appendChild(lineBreak); // add a line break
display.appendChild(label); // add the message node
},
/*
clears the message div:
*/
clear: function() {
var display = document.getElementById("message");
display.innerHTML = "";
}
}; // end of app