diff --git a/examples/server.js b/examples/server.js index 7f33efa..36a5dc7 100644 --- a/examples/server.js +++ b/examples/server.js @@ -2,19 +2,21 @@ var SAME = require('../index'); var message = { originator: 'PEP', - code: 'EAN', + sender: 'WHITEHSE', + code: 'CEM', region: { - subdiv: '0', - stateCode: '00', - countyCode: '000' + // note that these are strings. Multiple codes can be specified separated by a semicolon + subdiv: '0;0', + stateCode: '34;34', + countyCode: '001;003' }, - length: 600, - start: { - day: 123, - hour: 5, - minute: 30 - }, - sender: 'WHITEHSE' + // note that these are numbers + length: 1200, // message applicability period (NOT event length!) as HHMM + start: { // message applicability period begins: + day: 205, // on this Julian day + hour: 18, // at this UTC hour + minute: 13 // and this UTC minute + } }; SAME.Writer.write(SAME.Encoder.encode(message), './output.wav'); diff --git a/lib/same-validator.js b/lib/same-validator.js index 31f5ee8..728511e 100644 --- a/lib/same-validator.js +++ b/lib/same-validator.js @@ -12,19 +12,53 @@ function jq(obj, path) { } function hasValidCountyCode(region) { - var s = parseInt(region.stateCode, 10); - var c = parseInt(region.countyCode, 10); - - // easy cases: - if (s === 0 && c === 0) return true; // 0 for both is allowed, as "whole country" - if (s !== 0 && c === 0) return true; // 0 for county is allowed, as "whole state" - if (s === 0 && c !== 0) return false; // but 0 for state and nonzero county isn't - - // usual case: if the state is defined, and if the state contains - // the given county code, it's valid - return (typeof SAMEValues.countyCode[region.stateCode] !== 'undefined') + //parse region codes + var subdivArr = region.subdiv.toString().split(';'); + var stateCodeArr = region.stateCode.toString().split(';'); + var countyCodeArr = region.countyCode.toString().split(';'); + + //Only want to return false if failed, will return true at very end assuming nothing failed + for (var i = 0; i < subdivArr.length; i = i + 1) { + var s = parseInt(stateCodeArr[i], 10); + var c = parseInt(countyCodeArr[i], 10); + + // easy cases: + //if (s === 0 && c === 0) return true; // 0 for both is allowed, as "whole country" + //if (s !== 0 && c === 0) return true; // 0 for county is allowed, as "whole state" + if (s === 0 && c !== 0) return false; // but 0 for state and nonzero county isn't + + // usual case: if the state is defined, and if the state contains + // the given county code, it's valid + var isFalse = (typeof SAMEValues.countyCode[region.stateCode] !== 'undefined') && SAMEValues.countyCode[region.stateCode] .hasOwnProperty(region.countyCode); + if (isFalse) { + return false; + } + } + return true; +} + +function hasValidSubdivCode(subdiv) { + var subdivArr = subdiv.toString().split(';'); + for (var i = 0; i < subdivArr.length; i = i + 1) { + if (!SAMEValues.subdiv.hasOwnProperty(subdivArr[i])) { + return false; + } + } + return true; +} + +function hasValidStateCode(stateCode) { + var stateCodeArr = stateCode.toString().split(';'); + for (var i = 0; i < stateCodeArr.length; i = i + 1) { + var pass = parseInt(stateCode) === 0 + || SAMEValues.stateCode.hasOwnProperty(stateCodeArr[i]); + if (!pass) { + return false; + } + } + return true; } function isValidLength(n) { @@ -102,8 +136,7 @@ module.exports = function(message) { 'message.region must be a non-empty object'], [check('.region.stateCode', 'str') - && (parseInt(message.region.stateCode) === 0 - || SAMEValues.stateCode.hasOwnProperty(message.region.stateCode)), + && hasValidStateCode(message.region.stateCode), 'message.region.stateCode must be a defined SAME state code'], [check('.region.countyCode', 'str') @@ -111,7 +144,7 @@ module.exports = function(message) { 'message.region.countyCode must be a defined SAME county code'], [check('.region.subdiv', 'str') - && SAMEValues.subdiv.hasOwnProperty(message.region.subdiv), + && hasValidSubdivCode(message.region.subdiv), 'message.region.subdiv must be a defined SAME region subdivision value (try 0)'], [check('.length', 'int') @@ -147,6 +180,5 @@ module.exports = function(message) { } } }); - return errors; }; diff --git a/lib/same.js b/lib/same.js index ebb0d0e..6e58116 100644 --- a/lib/same.js +++ b/lib/same.js @@ -53,6 +53,9 @@ function zeropad (str, len) { */ SAME.constructMessageByteArray = function(message) { var msgContent = []; + var subdivArr = []; + var stateCodeArr = []; + var countyCodeArr = []; if (message !== null) { // message header @@ -62,10 +65,25 @@ SAME.constructMessageByteArray = function(message) { message.originator, '-', message.code, - '-', - zeropad(message.region.subdiv.toString(), 1), - zeropad(message.region.stateCode.toString(), 2), - zeropad(message.region.countyCode.toString(), 3), + ]; + + //parse region codes + subdivArr = message.region.subdiv.toString().split(';'); + stateCodeArr = message.region.stateCode.toString().split(';'); + countyCodeArr = message.region.countyCode.toString().split(';'); + + //add region codes to msgContent + for (var i = 0; i < subdivArr.length; i = i + 1) { + msgContent.push( + '-', + zeropad(subdivArr[i], 1), + zeropad(stateCodeArr[i], 2), + zeropad(countyCodeArr[i], 3), + ); + } + + //add the rest of the data + msgContent.push( '+', zeropad(message.length.toString(), 4), '-', @@ -73,8 +91,9 @@ SAME.constructMessageByteArray = function(message) { zeropad(message.start.hour.toString(), 2), zeropad(message.start.minute.toString(), 2), '-', - message.sender - ]; + message.sender, + '-' + ); } else { // message footer msgContent = [ @@ -139,8 +158,6 @@ SAME.generateWaveData = function(byteArray) { */ SAME.encode = function(message) { var validationErrors = this.validateMessage(message); - var msgBytes = []; - if (validationErrors.length > 0) { throw new Error('Message failed to validate: ' + validationErrors.join('; '));