You've already forked fm-dx-webserver
mirror of
https://github.com/KubaPro010/fm-dx-webserver.git
synced 2026-02-26 14:11:59 +01:00
Compare commits
4 Commits
d0a26d2346
...
34363b6c3b
| Author | SHA1 | Date | |
|---|---|---|---|
|
34363b6c3b
|
|||
|
f87f3c8eaa
|
|||
|
d3ab634846
|
|||
|
ddff8f51e5
|
61
.github/workflows/librdsparser.yml
vendored
61
.github/workflows/librdsparser.yml
vendored
@@ -1,61 +0,0 @@
|
||||
name: Fetch and Commit librdsparser
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: 'Release version'
|
||||
required: true
|
||||
default: 'v1.1'
|
||||
|
||||
jobs:
|
||||
fetch-and-commit:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Download all librdsparser release assets
|
||||
run: |
|
||||
set -e
|
||||
cd server/libraries
|
||||
|
||||
VERSION="${{ github.event.inputs.version }}"
|
||||
echo "Fetching librdsparser release: $VERSION"
|
||||
|
||||
platforms=(
|
||||
"aarch64"
|
||||
"arm"
|
||||
"macos"
|
||||
"mingw32"
|
||||
"mingw64"
|
||||
"x86"
|
||||
"x86_64"
|
||||
)
|
||||
|
||||
base_url="https://github.com/kkonradpl/librdsparser/releases/download/$VERSION"
|
||||
|
||||
for platform in "${platforms[@]}"; do
|
||||
filename="librdsparser-${platform}.zip"
|
||||
dir="${platform}"
|
||||
mkdir -p "$dir"
|
||||
|
||||
echo "Downloading $filename..."
|
||||
curl -sSL -o "$dir/$filename" "$base_url/$filename"
|
||||
|
||||
echo "Extracting from $filename..."
|
||||
unzip -j "$dir/$filename" "*.dll" "*.so" "*.dylib" -d "$dir" || echo "No binaries in $filename"
|
||||
rm "$dir/$filename"
|
||||
done
|
||||
|
||||
- name: Commit and push binaries to the repo
|
||||
run: |
|
||||
git config user.name "github-actions"
|
||||
git config user.email "github-actions@github.com"
|
||||
|
||||
git add server/libraries
|
||||
git diff --cached --quiet || git commit -m "Add librdsparser ${{ github.event.inputs.version }}"
|
||||
git push
|
||||
@@ -33,7 +33,6 @@ This project utilizes these libraries:
|
||||
|
||||
- [3LAS](https://github.com/jojobond/3LAS) library by JoJoBond for Low Latency Audio Streaming.
|
||||
- [flat-flags](https://github.com/luishdez/flat-flags) library by luishdez for RDS country flags.
|
||||
- [librdsparser](https://github.com/kkonradpl/librdsparser) library by Konrad Kosmatka for RDS parsing.
|
||||
|
||||
All of these libraries are already bundled with the webserver.
|
||||
|
||||
|
||||
9
package-lock.json
generated
9
package-lock.json
generated
@@ -6,7 +6,7 @@
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "fm-dx-webserver",
|
||||
"version": "1.3.11",
|
||||
"version": "1.3.12",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@mapbox/node-pre-gyp": "2.0.0",
|
||||
@@ -16,7 +16,6 @@
|
||||
"express-session": "1.18.2",
|
||||
"ffmpeg-static": "5.2.0",
|
||||
"http": "0.0.1-security",
|
||||
"koffi": "2.7.2",
|
||||
"net": "1.0.2",
|
||||
"serialport": "12.0.0",
|
||||
"ws": "8.18.1"
|
||||
@@ -1195,12 +1194,6 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/koffi": {
|
||||
"version": "2.7.2",
|
||||
"resolved": "https://registry.npmjs.org/koffi/-/koffi-2.7.2.tgz",
|
||||
"integrity": "sha512-AWcsEKETQuELxK0Wq/aXDkDiNFFY41TxZQSrKm2Nd6HO/KTHeohPOOIlh2OfQnBXJbRjx5etpWt8cbqMUZo2sg==",
|
||||
"hasInstallScript": true
|
||||
},
|
||||
"node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
"express-session": "1.18.2",
|
||||
"ffmpeg-static": "5.2.0",
|
||||
"http": "0.0.1-security",
|
||||
"koffi": "2.7.2",
|
||||
"net": "1.0.2",
|
||||
"serialport": "12.0.0",
|
||||
"ws": "8.18.1"
|
||||
|
||||
@@ -1,213 +1,7 @@
|
||||
/* Libraries / Imports */
|
||||
const fs = require('fs');
|
||||
const https = require('https');
|
||||
const koffi = require('koffi');
|
||||
const path = require('path');
|
||||
const os = require('os');
|
||||
const platform = os.platform();
|
||||
const cpuArchitecture = os.arch();
|
||||
const { configName, serverConfig, configUpdate, configSave } = require('./server_config');
|
||||
let unicode_type;
|
||||
let shared_Library;
|
||||
|
||||
if (platform === 'win32') {
|
||||
unicode_type = 'int16_t';
|
||||
arch_type = (cpuArchitecture === 'x64' ? 'mingw64' : 'mingw32');
|
||||
shared_Library=path.join(__dirname, "libraries", arch_type, "librdsparser.dll");
|
||||
} else if (platform === 'linux') {
|
||||
unicode_type = 'int32_t';
|
||||
arch_type = (cpuArchitecture === 'x64' ? 'x86_64' :
|
||||
(cpuArchitecture === 'ia32' ? 'x86' :
|
||||
(cpuArchitecture === 'arm64' ? 'aarch64' : cpuArchitecture)));
|
||||
shared_Library=path.join(__dirname, "libraries", arch_type, "librdsparser.so");
|
||||
} else if (platform === 'darwin') {
|
||||
unicode_type = 'int32_t';
|
||||
shared_Library=path.join(__dirname, "libraries", "macos", "librdsparser.dylib");
|
||||
}
|
||||
|
||||
const lib = koffi.load(shared_Library);
|
||||
const RDSDecoder = require("./rds.js");
|
||||
const { fetchTx } = require('./tx_search.js');
|
||||
|
||||
koffi.proto('void callback_pi(void *rds, void *user_data)');
|
||||
koffi.proto('void callback_pty(void *rds, void *user_data)');
|
||||
koffi.proto('void callback_tp(void *rds, void *user_data)');
|
||||
koffi.proto('void callback_ta(void *rds, void *user_data)');
|
||||
koffi.proto('void callback_ms(void *rds, void *user_data)');
|
||||
koffi.proto('void callback_ecc(void *rds, void *user_data)');
|
||||
koffi.proto('void callback_country(void *rds, void *user_data)');
|
||||
koffi.proto('void callback_af(void *rds, uint32_t af, void *user_data)');
|
||||
koffi.proto('void callback_ps(void *rds, void *user_data)');
|
||||
koffi.proto('void callback_rt(void *rds, int flag, void *user_data)');
|
||||
koffi.proto('void callback_ptyn(void *rds, void *user_data)');
|
||||
koffi.proto('void callback_ct(void *rds, void *ct, void *user_data)');
|
||||
|
||||
const rdsparser = {
|
||||
new: lib.func('void* rdsparser_new()'),
|
||||
free: lib.func('void rdsparser_free(void *rds)'),
|
||||
clear: lib.func('void rdsparser_clear(void *rds)'),
|
||||
parse_string: lib.func('bool rdsparser_parse_string(void *rds, const char *input)'),
|
||||
set_text_correction: lib.func('void rdsparser_set_text_correction(void *rds, uint8_t text, uint8_t type, uint8_t error)'),
|
||||
set_text_progressive: lib.func('void rdsparser_set_text_progressive(void *rds, uint8_t string, uint8_t state)'),
|
||||
get_pi: lib.func('int32_t rdsparser_get_pi(void *rds)'),
|
||||
get_pty: lib.func('int8_t rdsparser_get_pty(void *rds)'),
|
||||
get_tp: lib.func('int8_t rdsparser_get_tp(void *rds)'),
|
||||
get_ta: lib.func('int8_t rdsparser_get_ta(void *rds)'),
|
||||
get_ms: lib.func('int8_t rdsparser_get_ms(void *rds)'),
|
||||
get_ecc: lib.func('int16_t rdsparser_get_ecc(void *rds)'),
|
||||
get_country: lib.func('int rdsparser_get_country(void *rds)'),
|
||||
get_ps: lib.func('void* rdsparser_get_ps(void *rds)'),
|
||||
get_rt: lib.func('void* rdsparser_get_rt(void *rds, int flag)'),
|
||||
get_ptyn: lib.func('void* rdsparser_get_ptyn(void *rds)'),
|
||||
register_pi: lib.func('void rdsparser_register_pi(void *rds, void *cb)'),
|
||||
register_pty: lib.func('void rdsparser_register_pty(void *rds, void *cb)'),
|
||||
register_tp: lib.func('void rdsparser_register_tp(void *rds, void *cb)'),
|
||||
register_ta: lib.func('void rdsparser_register_ta(void *rds, void *cb)'),
|
||||
register_ms: lib.func('void rdsparser_register_ms(void *rds, void *cb)'),
|
||||
register_ecc: lib.func('void rdsparser_register_ecc(void *rds, void *cb)'),
|
||||
register_country: lib.func('void rdsparser_register_country(void *rds, void *cb)'),
|
||||
register_af: lib.func('void rdsparser_register_af(void *rds, void *cb)'),
|
||||
register_ps: lib.func('void rdsparser_register_ps(void *rds, void *cb)'),
|
||||
register_rt: lib.func('void rdsparser_register_rt(void *rds, void *cb)'),
|
||||
register_ptyn: lib.func('void rdsparser_register_ptyn(void *rds, void *cb)'),
|
||||
register_ct: lib.func('void rdsparser_register_ct(void *rds, void *cb)'),
|
||||
string_get_content: lib.func(unicode_type + '* rdsparser_string_get_content(void *string)'),
|
||||
string_get_errors: lib.func('uint8_t* rdsparser_string_get_errors(void *string)'),
|
||||
string_get_length: lib.func('uint8_t rdsparser_string_get_length(void *string)'),
|
||||
ct_get_year: lib.func('uint16_t rdsparser_ct_get_year(void *ct)'),
|
||||
ct_get_month: lib.func('uint8_t rdsparser_ct_get_month(void *ct)'),
|
||||
ct_get_day: lib.func('uint8_t rdsparser_ct_get_day(void *ct)'),
|
||||
ct_get_hour: lib.func('uint8_t rdsparser_ct_get_hour(void *ct)'),
|
||||
ct_get_minute: lib.func('uint8_t rdsparser_ct_get_minute(void *ct)'),
|
||||
ct_get_offset: lib.func('int8_t rdsparser_ct_get_offset(void *ct)'),
|
||||
pty_lookup_short: lib.func('const char* rdsparser_pty_lookup_short(int8_t pty, bool rbds)'),
|
||||
pty_lookup_long: lib.func('const char* rdsparser_pty_lookup_long(int8_t pty, bool rbds)'),
|
||||
country_lookup_name: lib.func('const char* rdsparser_country_lookup_name(int country)'),
|
||||
country_lookup_iso: lib.func('const char* rdsparser_country_lookup_iso(int country)')
|
||||
}
|
||||
|
||||
const callbacks = {
|
||||
pi: koffi.register(rds => (
|
||||
value = rdsparser.get_pi(rds)
|
||||
//console.log('PI: ' + value.toString(16).toUpperCase())
|
||||
), 'callback_pi*'),
|
||||
|
||||
pty: koffi.register(rds => (
|
||||
value = rdsparser.get_pty(rds),
|
||||
dataToSend.pty = value
|
||||
), 'callback_pty*'),
|
||||
|
||||
tp: koffi.register(rds => (
|
||||
value = rdsparser.get_tp(rds),
|
||||
dataToSend.tp = value
|
||||
), 'callback_tp*'),
|
||||
|
||||
ta: koffi.register(rds => (
|
||||
value = rdsparser.get_ta(rds),
|
||||
dataToSend.ta = value
|
||||
), 'callback_ta*'),
|
||||
|
||||
ms: koffi.register(rds => (
|
||||
value = rdsparser.get_ms(rds),
|
||||
dataToSend.ms = value
|
||||
), 'callback_ms*'),
|
||||
|
||||
af: koffi.register((rds, value) => (
|
||||
dataToSend.af.push(value)
|
||||
), 'callback_af*'),
|
||||
|
||||
ecc: koffi.register(rds => (
|
||||
value = rdsparser.get_ecc(rds),
|
||||
dataToSend.ecc = value
|
||||
), 'callback_ecc*'),
|
||||
|
||||
country: koffi.register(rds => (
|
||||
value = rdsparser.get_country(rds),
|
||||
display = rdsparser.country_lookup_name(value),
|
||||
iso = rdsparser.country_lookup_iso(value),
|
||||
dataToSend.country_name = display,
|
||||
dataToSend.country_iso = iso
|
||||
), 'callback_country*'),
|
||||
|
||||
ps: koffi.register(rds => (
|
||||
ps = rdsparser.get_ps(rds),
|
||||
dataToSend.ps = decode_unicode(ps),
|
||||
dataToSend.ps_errors = decode_errors(ps)
|
||||
), 'callback_ps*'),
|
||||
|
||||
rt: koffi.register((rds, flag) => {
|
||||
const rt = rdsparser.get_rt(rds, flag);
|
||||
|
||||
if (flag === 0) {
|
||||
dataToSend.rt0 = decode_unicode(rt);
|
||||
dataToSend.rt0_errors = decode_errors(rt);
|
||||
}
|
||||
|
||||
if (flag === 1) {
|
||||
dataToSend.rt1 = decode_unicode(rt);
|
||||
dataToSend.rt1_errors = decode_errors(rt);
|
||||
}
|
||||
dataToSend.rt_flag = flag;
|
||||
}, 'callback_rt*'),
|
||||
|
||||
ptyn: koffi.register((rds, flag) => (
|
||||
value = decode_unicode(rdsparser.get_ptyn(rds))
|
||||
/*console.log('PTYN: ' + value)*/
|
||||
), 'callback_ptyn*'),
|
||||
|
||||
ct: koffi.register((rds, ct) => (
|
||||
year = rdsparser.ct_get_year(ct),
|
||||
month = String(rdsparser.ct_get_month(ct)).padStart(2, '0'),
|
||||
day = String(rdsparser.ct_get_day(ct)).padStart(2, '0'),
|
||||
hour = String(rdsparser.ct_get_hour(ct)).padStart(2, '0'),
|
||||
minute = String(rdsparser.ct_get_minute(ct)).padStart(2, '0'),
|
||||
offset = rdsparser.ct_get_offset(ct),
|
||||
tz_sign = (offset >= 0 ? '+' : '-'),
|
||||
tz_hour = String(Math.abs(Math.floor(offset / 60))).padStart(2, '0'),
|
||||
tz_minute = String(Math.abs(offset % 60)).padStart(2, '0')
|
||||
//console.log('CT: ' + year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ' (' + tz_sign + tz_hour + ':' + tz_minute + ')')
|
||||
), 'callback_ct*')
|
||||
};
|
||||
|
||||
let rds = rdsparser.new()
|
||||
rdsparser.set_text_correction(rds, 0, 0, 2);
|
||||
rdsparser.set_text_correction(rds, 0, 1, 2);
|
||||
rdsparser.set_text_correction(rds, 1, 0, 2);
|
||||
rdsparser.set_text_correction(rds, 1, 1, 2);
|
||||
rdsparser.set_text_progressive(rds, 0, 1)
|
||||
rdsparser.set_text_progressive(rds, 1, 1)
|
||||
rdsparser.register_pi(rds, callbacks.pi);
|
||||
rdsparser.register_pty(rds, callbacks.pty);
|
||||
rdsparser.register_tp(rds, callbacks.tp);
|
||||
rdsparser.register_ta(rds, callbacks.ta);
|
||||
rdsparser.register_ms(rds, callbacks.ms);
|
||||
rdsparser.register_ecc(rds, callbacks.ecc);
|
||||
rdsparser.register_country(rds, callbacks.country);
|
||||
rdsparser.register_af(rds, callbacks.af);
|
||||
rdsparser.register_ps(rds, callbacks.ps);
|
||||
rdsparser.register_rt(rds, callbacks.rt);
|
||||
rdsparser.register_ptyn(rds, callbacks.ptyn);
|
||||
rdsparser.register_ct(rds, callbacks.ct);
|
||||
|
||||
const decode_unicode = function(string) {
|
||||
let length = rdsparser.string_get_length(string);
|
||||
if (length) {
|
||||
let content = rdsparser.string_get_content(string);
|
||||
let array = koffi.decode(content, unicode_type + ' [' + length + ']');
|
||||
return String.fromCodePoint.apply(String, array);
|
||||
}
|
||||
return '';
|
||||
};
|
||||
|
||||
const decode_errors = function(string) {
|
||||
let length = rdsparser.string_get_length(string);
|
||||
if (length) {
|
||||
let errors = rdsparser.string_get_errors(string);
|
||||
let array = koffi.decode(errors, 'uint8_t [' + length + ']');
|
||||
return Uint8Array.from(array).toString();
|
||||
}
|
||||
return '';
|
||||
};
|
||||
|
||||
const updateInterval = 75;
|
||||
|
||||
// Initialize the data object
|
||||
@@ -229,7 +23,9 @@ var dataToSend = {
|
||||
ecc: null,
|
||||
af: [],
|
||||
rt0: '',
|
||||
rt0_errors: '',
|
||||
rt1: '',
|
||||
rt1_errors: '',
|
||||
rt_flag: '',
|
||||
ims: 0,
|
||||
eq: 0,
|
||||
@@ -251,6 +47,8 @@ var dataToSend = {
|
||||
users: 0,
|
||||
};
|
||||
|
||||
const rds = new RDSDecoder(dataToSend);
|
||||
|
||||
const filterMappings = {
|
||||
'G11': { eq: 1, ims: 1 },
|
||||
'G01': { eq: 0, ims: 1 },
|
||||
@@ -283,7 +81,7 @@ function rdsReceived() {
|
||||
function rdsReset() {
|
||||
resetToDefault(dataToSend);
|
||||
dataToSend.af.length = 0;
|
||||
rdsparser.clear(rds);
|
||||
rds.clear();
|
||||
if (rdsTimeoutTimer) {
|
||||
clearTimeout(rdsTimeoutTimer);
|
||||
rdsTimeoutTimer = null;
|
||||
@@ -400,11 +198,18 @@ function handleData(wss, receivedData, rdsWss) {
|
||||
data += (((errors & 0x03) == 0) ? modifiedData.slice(12, 16) : '----');
|
||||
|
||||
const newDataString = "G:\r\n" + data + "\r\n\r\n";
|
||||
const finalBuffer = Buffer.from(newDataString, 'utf-8');
|
||||
client.send(finalBuffer);
|
||||
client.send(newDataString);
|
||||
});
|
||||
|
||||
rdsparser.parse_string(rds, modifiedData);
|
||||
var data2 = "";
|
||||
for(var i = 0; i < modifiedData.length; i++) {
|
||||
data2 += modifiedData[i]
|
||||
if ((i + 1) % 4 === 0 && i !== modifiedData.length - 1) data2 += " ";
|
||||
}
|
||||
var data = [];
|
||||
data2.split(" ").forEach((i) => {data.push(parseInt(i, 16))})
|
||||
|
||||
rds.decodeGroup(data[0], data[1], data[2], data[3], data[4])
|
||||
legacyRdsPiBuffer = null;
|
||||
break;
|
||||
}
|
||||
|
||||
175
server/rds.js
Normal file
175
server/rds.js
Normal file
@@ -0,0 +1,175 @@
|
||||
const { rdsEccLookup, iso, countries } = require("./rds_country.js")
|
||||
|
||||
class RDSDecoder {
|
||||
constructor(data) {
|
||||
this.data = data;
|
||||
this.clear()
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.data.pi = '?';
|
||||
this.ps = Array(8).fill(' ');
|
||||
this.ps_errors = Array(8).fill("0");
|
||||
this.rt0 = Array(64).fill(' ');
|
||||
this.rt0_errors = Array(64).fill("0");
|
||||
this.rt1 = Array(64).fill(' ');
|
||||
this.rt1_errors = Array(64).fill("0");
|
||||
this.data.ps = '';
|
||||
this.data.rt1 = '';
|
||||
this.data.rt0 = '';
|
||||
this.data.pty = 0;
|
||||
this.data.tp = 0;
|
||||
this.data.ta = 0;
|
||||
this.data.ms = -1;
|
||||
this.data.rt_flag = 0;
|
||||
this.rt1_to_clear = false;
|
||||
this.rt0_to_clear = false;
|
||||
this.data.ecc = null;
|
||||
this.data.country_name = ""
|
||||
this.data.country_iso = "UN"
|
||||
|
||||
this.af_len = 0;
|
||||
this.data.af = []
|
||||
this.af_am_follows = false;
|
||||
}
|
||||
|
||||
decodeGroup(blockA, blockB, blockC, blockD, error) {
|
||||
if(error > 2) return; // TODO: handle errors
|
||||
// console.log(error)
|
||||
this.data.pi = blockA.toString(16).toUpperCase().padStart(4, '0');
|
||||
|
||||
const group = (blockB >> 12) & 0xF;
|
||||
const version = (blockB >> 11) & 0x1;
|
||||
this.data.tp = Number((blockB >> 10) & 1);
|
||||
this.data.pty = (blockB >> 5) & 0b11111;
|
||||
|
||||
if (group === 0) {
|
||||
this.data.ta = (blockB >> 4) & 1;
|
||||
this.data.ms = (blockB >> 3) & 1;
|
||||
|
||||
if(version === 0) {
|
||||
var af_high = blockC >> 8;
|
||||
var af_low = blockC & 0xFF;
|
||||
var BASE = 224;
|
||||
var FILLER = 205;
|
||||
var AM_FOLLOWS = 250;
|
||||
|
||||
if(af_high >= BASE && af_high <= (BASE+25)) {
|
||||
this.af_len = af_high-BASE;
|
||||
if(this.af_len !== this.data.af.length) {
|
||||
this.data.af = [];
|
||||
this.af_am_follows = false;
|
||||
|
||||
if(af_low != FILLER && af_low != AM_FOLLOWS) this.data.af.push((af_low+875)*100)
|
||||
else if(af_low == AM_FOLLOWS) this.af_am_follows = true;
|
||||
}
|
||||
} else if(this.data.af.length != this.af_len) {
|
||||
if(!(af_high == AM_FOLLOWS || this.af_am_follows)) {
|
||||
var freq = (af_high+875)*100;
|
||||
if(!this.data.af.includes(freq)) this.data.af.push(freq);
|
||||
}
|
||||
if(this.af_am_follows) this.af_am_follows = false;
|
||||
if(!(af_high == AM_FOLLOWS || af_low == FILLER || af_low == AM_FOLLOWS)) {
|
||||
var freq = (af_low+875)*100;
|
||||
if(!this.data.af.includes(freq)) this.data.af.push(freq);
|
||||
}
|
||||
if(af_low == AM_FOLLOWS) this.af_am_follows = true;
|
||||
}
|
||||
}
|
||||
|
||||
const idx = blockB & 0x3;
|
||||
this.ps[idx * 2] = String.fromCharCode(blockD >> 8);
|
||||
this.ps[idx * 2 + 1] = String.fromCharCode(blockD & 0xFF);
|
||||
this.ps_errors[idx * 2] = error;
|
||||
this.ps_errors[idx * 2 + 1] = error;
|
||||
this.data.ps = this.ps.join('');
|
||||
this.data.ps_errors = this.ps_errors.join(',');
|
||||
} else if (group === 1 && version === 0) {
|
||||
var la = Boolean(blockC & 0x8000);
|
||||
var variant_code = (blockC >> 12) & 0x7;
|
||||
switch (variant_code) {
|
||||
case 0:
|
||||
this.data.ecc = blockC & 0xff;
|
||||
this.data.country_name = rdsEccLookup(blockA, this.data.ecc);
|
||||
if(this.data.country_name.length === 0) this.data.country_iso = "UN";
|
||||
else this.data.country_iso = iso[countries.indexOf(this.data.country_name)]
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (group === 2) {
|
||||
const idx = blockB & 0b1111;
|
||||
this.rt_ab = Boolean((blockB >> 4) & 1);
|
||||
// TODO: rt_errors
|
||||
if(this.rt_ab) {
|
||||
if(this.rt1_to_clear) {
|
||||
this.rt1 = Array(64).fill(' ');
|
||||
this.rt1_errors = Array(64).fill("0");
|
||||
this.rt1_to_clear = false;
|
||||
}
|
||||
|
||||
if(version == 0) {
|
||||
this.rt1[idx * 4] = String.fromCharCode(blockC >> 8);
|
||||
this.rt1[idx * 4 + 1] = String.fromCharCode(blockC & 0xFF);
|
||||
this.rt1[idx * 4 + 2] = String.fromCharCode(blockD >> 8);
|
||||
this.rt1[idx * 4 + 3] = String.fromCharCode(blockD & 0xFF);
|
||||
this.rt1_errors[idx * 4] = error;
|
||||
this.rt1_errors[idx * 4 + 1] = error;
|
||||
this.rt1_errors[idx * 4 + 2] = error;
|
||||
this.rt1_errors[idx * 4 + 3] = error;
|
||||
} else {
|
||||
this.rt1[idx * 2] = String.fromCharCode(blockD >> 8);
|
||||
this.rt1[idx * 2 + 1] = String.fromCharCode(blockD & 0xFF);
|
||||
this.rt1_errors[idx * 2] = error;
|
||||
this.rt1_errors[idx * 2 + 1] = error;
|
||||
}
|
||||
|
||||
var i = this.rt1.indexOf("\r")
|
||||
while(i != -1) {
|
||||
this.rt1[i] = " ";
|
||||
i = this.rt1.indexOf("\r");
|
||||
}
|
||||
|
||||
this.data.rt1 = this.rt1.join('');
|
||||
this.data.rt1_errors = this.rt1_errors.join(',');
|
||||
this.data.rt_flag = 1;
|
||||
this.rt0_to_clear = true;
|
||||
} else {
|
||||
if(this.rt0_to_clear) {
|
||||
this.rt0 = Array(64).fill(' ');
|
||||
this.rt0_errors = Array(64).fill("0");
|
||||
this.rt0_to_clear = false;
|
||||
}
|
||||
if(version == 0) {
|
||||
this.rt0[idx * 4] = String.fromCharCode(blockC >> 8);
|
||||
this.rt0[idx * 4 + 1] = String.fromCharCode(blockC & 0xFF);
|
||||
this.rt0[idx * 4 + 2] = String.fromCharCode(blockD >> 8);
|
||||
this.rt0[idx * 4 + 3] = String.fromCharCode(blockD & 0xFF);
|
||||
this.rt0_errors[idx * 4] = error;
|
||||
this.rt0_errors[idx * 4 + 1] = error;
|
||||
this.rt0_errors[idx * 4 + 2] = error;
|
||||
this.rt0_errors[idx * 4 + 3] = error;
|
||||
} else {
|
||||
this.rt0[idx * 2] = String.fromCharCode(blockD >> 8);
|
||||
this.rt0[idx * 2 + 1] = String.fromCharCode(blockD & 0xFF);
|
||||
this.rt0_errors[idx * 2] = error;
|
||||
this.rt0_errors[idx * 2 + 1] = error;
|
||||
}
|
||||
|
||||
var i = this.rt0.indexOf("\r");
|
||||
while(i != -1) {
|
||||
this.rt0[i] = " ";
|
||||
i = this.rt0.indexOf("\r");
|
||||
}
|
||||
|
||||
this.data.rt0 = this.rt0.join('');
|
||||
this.data.rt0_errors = this.rt0_errors.join(',');
|
||||
this.data.rt_flag = 0;
|
||||
this.rt1_to_clear = true;
|
||||
}
|
||||
} else {
|
||||
// console.log(group, version)
|
||||
}
|
||||
}
|
||||
}
|
||||
module.exports = RDSDecoder;
|
||||
632
server/rds_country.js
Normal file
632
server/rds_country.js
Normal file
@@ -0,0 +1,632 @@
|
||||
var countries = [
|
||||
"Albania",
|
||||
"Estonia",
|
||||
"Algeria",
|
||||
"Ethiopia",
|
||||
"Andorra",
|
||||
"Angola",
|
||||
"Finland",
|
||||
"Armenia",
|
||||
"France",
|
||||
"Ascension Island",
|
||||
"Gabon",
|
||||
"Austria",
|
||||
"Gambia",
|
||||
"Azerbaijan",
|
||||
"Georgia",
|
||||
"Germany",
|
||||
"Bahrein",
|
||||
"Ghana",
|
||||
"Belarus",
|
||||
"Gibraltar",
|
||||
"Belgium",
|
||||
"Greece",
|
||||
"Benin",
|
||||
"Guinea",
|
||||
"Bosnia Herzegovina",
|
||||
"Guinea-Bissau",
|
||||
"Botswana",
|
||||
"Hungary",
|
||||
"Bulgaria",
|
||||
"Iceland",
|
||||
"Burkina Faso",
|
||||
"Iraq",
|
||||
"Burundi",
|
||||
"Ireland",
|
||||
"Cabinda",
|
||||
"Israel",
|
||||
"Cameroon",
|
||||
"Italy",
|
||||
"Jordan",
|
||||
"Cape Verde",
|
||||
"Kazakhstan",
|
||||
"Central African Republic",
|
||||
"Kenya",
|
||||
"Chad",
|
||||
"Kosovo",
|
||||
"Comoros",
|
||||
"Kuwait",
|
||||
"DR Congo",
|
||||
"Kyrgyzstan",
|
||||
"Republic of Congo",
|
||||
"Latvia",
|
||||
"Cote d'Ivoire",
|
||||
"Lebanon",
|
||||
"Croatia",
|
||||
"Lesotho",
|
||||
"Cyprus",
|
||||
"Liberia",
|
||||
"Czechia",
|
||||
"Libya",
|
||||
"Denmark",
|
||||
"Liechtenstein",
|
||||
"Djiboutia",
|
||||
"Lithuania",
|
||||
"Egypt",
|
||||
"Luxembourg",
|
||||
"Equatorial Guinea",
|
||||
"Macedonia",
|
||||
"Eritrea",
|
||||
"Madagascar",
|
||||
"Seychelles",
|
||||
"Malawi",
|
||||
"Sierra Leone",
|
||||
"Mali",
|
||||
"Slovakia",
|
||||
"Malta",
|
||||
"Slovenia",
|
||||
"Mauritania",
|
||||
"Somalia",
|
||||
"Mauritius",
|
||||
"South Africa",
|
||||
"Moldova",
|
||||
"South Sudan",
|
||||
"Monaco",
|
||||
"Spain",
|
||||
"Mongolia",
|
||||
"Sudan",
|
||||
"Montenegro",
|
||||
"Swaziland",
|
||||
"Morocco",
|
||||
"Sweden",
|
||||
"Mozambique",
|
||||
"Switzerland",
|
||||
"Namibia",
|
||||
"Syria",
|
||||
"Netherlands",
|
||||
"Tajikistan",
|
||||
"Niger",
|
||||
"Tanzania",
|
||||
"Nigeria",
|
||||
"Togo",
|
||||
"Norway",
|
||||
"Tunisia",
|
||||
"Oman",
|
||||
"Turkey",
|
||||
"Palestine",
|
||||
"Turkmenistan",
|
||||
"Poland",
|
||||
"Uganda",
|
||||
"Portugal",
|
||||
"Ukraine",
|
||||
"Qatar",
|
||||
"United Arab Emirates",
|
||||
"Romania",
|
||||
"United Kingdom",
|
||||
"Russia",
|
||||
"Uzbekistan",
|
||||
"Rwanda",
|
||||
"Vatican",
|
||||
"San Marino",
|
||||
"Western Sahara",
|
||||
"Sao Tome and Principe",
|
||||
"Yemen",
|
||||
"Saudi Arabia",
|
||||
"Zambia",
|
||||
"Senegal",
|
||||
"Zimbabwe",
|
||||
"Serbia",
|
||||
"Anguilla",
|
||||
"Guyana",
|
||||
"Antigua and Barbuda",
|
||||
"Haiti",
|
||||
"Argentina",
|
||||
"Honduras",
|
||||
"Aruba",
|
||||
"Jamaica",
|
||||
"Bahamas",
|
||||
"Martinique",
|
||||
"Barbados",
|
||||
"Mexico",
|
||||
"Belize",
|
||||
"Montserrat",
|
||||
"Brazil/Bermuda",
|
||||
"Brazil/AN",
|
||||
"Bolivia",
|
||||
"Nicaragua",
|
||||
"Brazil",
|
||||
"Panama",
|
||||
"Canada",
|
||||
"Paraguay",
|
||||
"Cayman Islands",
|
||||
"Peru",
|
||||
"Chile",
|
||||
"USA/VI/PR",
|
||||
"Colombia",
|
||||
"St. Kitts",
|
||||
"Costa Rica",
|
||||
"St. Lucia",
|
||||
"Cuba",
|
||||
"St. Pierre and Miquelon",
|
||||
"Dominica",
|
||||
"St. Vincent",
|
||||
"Dominican Republic",
|
||||
"Suriname",
|
||||
"El Salvador",
|
||||
"Trinidad and Tobago",
|
||||
"Turks and Caicos islands",
|
||||
"Falkland Islands",
|
||||
"Greenland",
|
||||
"Uruguay",
|
||||
"Grenada",
|
||||
"Venezuela",
|
||||
"Guadeloupe",
|
||||
"Virgin Islands",
|
||||
"Guatemala",
|
||||
"Afghanistan",
|
||||
"South Korea",
|
||||
"Laos",
|
||||
"Australia Capital Territory",
|
||||
"Macao",
|
||||
"Australia New South Wales",
|
||||
"Malaysia",
|
||||
"Australia Victoria",
|
||||
"Maldives",
|
||||
"Australia Queensland",
|
||||
"Marshall Islands",
|
||||
"Australia South Australia",
|
||||
"Micronesia",
|
||||
"Australia Western Australia",
|
||||
"Myanmar",
|
||||
"Australia Tasmania",
|
||||
"Nauru",
|
||||
"Australia Northern Territory",
|
||||
"Nepal",
|
||||
"Bangladesh",
|
||||
"New Zealand",
|
||||
"Bhutan",
|
||||
"Pakistan",
|
||||
"Brunei Darussalam",
|
||||
"Papua New Guinea",
|
||||
"Cambodia",
|
||||
"Philippines",
|
||||
"China",
|
||||
"Samoa",
|
||||
"Singapore",
|
||||
"Solomon Islands",
|
||||
"Fiji",
|
||||
"Sri Lanka",
|
||||
"Hong Kong",
|
||||
"Taiwan",
|
||||
"India",
|
||||
"Thailand",
|
||||
"Indonesia",
|
||||
"Tonga",
|
||||
"Iran",
|
||||
"Vanuatu",
|
||||
"Japan",
|
||||
"Vietnam",
|
||||
"Kiribati",
|
||||
"North Korea",
|
||||
"Brazil/Equator"
|
||||
]
|
||||
|
||||
var iso = [
|
||||
"AL",
|
||||
"EE",
|
||||
"DZ",
|
||||
"ET",
|
||||
"AD",
|
||||
"AO",
|
||||
"FI",
|
||||
"AM",
|
||||
"FR",
|
||||
"SH",
|
||||
"GA",
|
||||
"AT",
|
||||
"GM",
|
||||
"AZ",
|
||||
"GE",
|
||||
"DE",
|
||||
"BH",
|
||||
"GH",
|
||||
"BY",
|
||||
"GI",
|
||||
"BE",
|
||||
"GR",
|
||||
"BJ",
|
||||
"GN",
|
||||
"BA",
|
||||
"GW",
|
||||
"BW",
|
||||
"HU",
|
||||
"BG",
|
||||
"IS",
|
||||
"BF",
|
||||
"IQ",
|
||||
"BI",
|
||||
"IE",
|
||||
"--",
|
||||
"IL",
|
||||
"CM",
|
||||
"IT",
|
||||
"JO",
|
||||
"CV",
|
||||
"KZ",
|
||||
"CF",
|
||||
"KE",
|
||||
"TD",
|
||||
"XK",
|
||||
"KM",
|
||||
"KW",
|
||||
"CD",
|
||||
"KG",
|
||||
"CG",
|
||||
"LV",
|
||||
"CI",
|
||||
"LB",
|
||||
"HR",
|
||||
"LS",
|
||||
"CY",
|
||||
"LR",
|
||||
"CZ",
|
||||
"LY",
|
||||
"DK",
|
||||
"LI",
|
||||
"DJ",
|
||||
"LT",
|
||||
"EG",
|
||||
"LU",
|
||||
"GQ",
|
||||
"MK",
|
||||
"ER",
|
||||
"MG",
|
||||
"SC",
|
||||
"MW",
|
||||
"SL",
|
||||
"ML",
|
||||
"SK",
|
||||
"MT",
|
||||
"SI",
|
||||
"MR",
|
||||
"SO",
|
||||
"MU",
|
||||
"ZA",
|
||||
"MD",
|
||||
"SS",
|
||||
"MC",
|
||||
"ES",
|
||||
"MN",
|
||||
"SD",
|
||||
"ME",
|
||||
"SZ",
|
||||
"MA",
|
||||
"SE",
|
||||
"MZ",
|
||||
"CH",
|
||||
"NA",
|
||||
"SY",
|
||||
"NL",
|
||||
"TJ",
|
||||
"NE",
|
||||
"TZ",
|
||||
"NG",
|
||||
"TG",
|
||||
"NO",
|
||||
"TN",
|
||||
"OM",
|
||||
"TR",
|
||||
"PS",
|
||||
"TM",
|
||||
"PL",
|
||||
"UG",
|
||||
"PT",
|
||||
"UA",
|
||||
"QA",
|
||||
"AE",
|
||||
"RO",
|
||||
"GB",
|
||||
"RU",
|
||||
"UZ",
|
||||
"RW",
|
||||
"VA",
|
||||
"SM",
|
||||
"EH",
|
||||
"ST",
|
||||
"YE",
|
||||
"SA",
|
||||
"ZM",
|
||||
"SN",
|
||||
"ZW",
|
||||
"RS",
|
||||
"AI",
|
||||
"GY",
|
||||
"AG",
|
||||
"HT",
|
||||
"AR",
|
||||
"HN",
|
||||
"AW",
|
||||
"JM",
|
||||
"BS",
|
||||
"MQ",
|
||||
"BB",
|
||||
"MX",
|
||||
"BZ",
|
||||
"MS",
|
||||
"--",
|
||||
"--",
|
||||
"BO",
|
||||
"NI",
|
||||
"BR",
|
||||
"PA",
|
||||
"CA",
|
||||
"PY",
|
||||
"KY",
|
||||
"PE",
|
||||
"CL",
|
||||
"--",
|
||||
"CO",
|
||||
"KN",
|
||||
"CR",
|
||||
"LC",
|
||||
"CU",
|
||||
"PM",
|
||||
"DM",
|
||||
"VC",
|
||||
"DO",
|
||||
"SR",
|
||||
"SN",
|
||||
"TT",
|
||||
"TB",
|
||||
"FK",
|
||||
"GL",
|
||||
"UY",
|
||||
"GD",
|
||||
"VE",
|
||||
"GP",
|
||||
"VG",
|
||||
"GT",
|
||||
"AF",
|
||||
"KR",
|
||||
"LA",
|
||||
"AU",
|
||||
"MO",
|
||||
"AU",
|
||||
"MY",
|
||||
"AU",
|
||||
"MV",
|
||||
"AU",
|
||||
"MH",
|
||||
"AU",
|
||||
"FM",
|
||||
"AU",
|
||||
"MM",
|
||||
"AU",
|
||||
"NR",
|
||||
"AU",
|
||||
"NP",
|
||||
"BD",
|
||||
"NZ",
|
||||
"BT",
|
||||
"PK",
|
||||
"BN",
|
||||
"PG",
|
||||
"KH",
|
||||
"PH",
|
||||
"CN",
|
||||
"WS",
|
||||
"SG",
|
||||
"SB",
|
||||
"FJ",
|
||||
"LK",
|
||||
"HK",
|
||||
"TW",
|
||||
"IN",
|
||||
"TH",
|
||||
"ID",
|
||||
"TO",
|
||||
"IR",
|
||||
"VU",
|
||||
"JP",
|
||||
"VN",
|
||||
"KI",
|
||||
"KP",
|
||||
"--"
|
||||
]
|
||||
|
||||
// RDS ECC Lookup Tables - Converted from C to JavaScript
|
||||
|
||||
const rdsEccA0A6Lut = [
|
||||
// A0
|
||||
[
|
||||
"USA/VI/PR", "USA/VI/PR", "USA/VI/PR", "USA/VI/PR", "USA/VI/PR",
|
||||
"USA/VI/PR", "USA/VI/PR", "USA/VI/PR", "USA/VI/PR", "USA/VI/PR",
|
||||
"USA/VI/PR", null, "USA/VI/PR", "USA/VI/PR", null
|
||||
],
|
||||
// A1
|
||||
[
|
||||
null, null, null, null, null,
|
||||
null, null, null, null, null,
|
||||
"Canada", "Canada", "Canada", "Canada", "Greenland"
|
||||
],
|
||||
// A2
|
||||
[
|
||||
"Anguilla", "Antigua and Barbuda", "Brazil/Equator", "Falkland Islands", "Barbados",
|
||||
"Belize", "Cayman Islands", "Costa Rica", "Cuba", "Argentina",
|
||||
"Brazil", "Brazil/Bermuda", "Brazil/AN", "Guadeloupe", "Bahamas"
|
||||
],
|
||||
// A3
|
||||
[
|
||||
"Bolivia", "Colombia", "Jamaica", "Martinique", null,
|
||||
"Paraguay", "Nicaragua", null, "Panama", "Dominica",
|
||||
"Dominican Republic", "Chile", "Grenada", "Turks and Caicos islands", "Guyana"
|
||||
],
|
||||
// A4
|
||||
[
|
||||
"Guatemala", "Honduras", "Aruba", null, "Montserrat",
|
||||
"Trinidad and Tobago", "Peru", "Suriname", "Uruguay", "St. Kitts",
|
||||
"St. Lucia", "El Salvador", "Haiti", "Venezuela", "Virgin Islands"
|
||||
],
|
||||
// A5
|
||||
[
|
||||
null, null, null, null, null,
|
||||
null, null, null, null, null,
|
||||
"Mexico", "St. Vincent", "Mexico", "Mexico", "Mexico"
|
||||
],
|
||||
// A6
|
||||
[
|
||||
null, null, null, null, null,
|
||||
null, null, null, null, null,
|
||||
null, null, null, null, "St. Pierre and Miquelon"
|
||||
]
|
||||
];
|
||||
|
||||
const rdsEccD0D4Lut = [
|
||||
// D0
|
||||
[
|
||||
"Cameroon", "Central African Republic", "Djiboutia", "Madagascar", "Mali",
|
||||
"Angola", "Equatorial Guinea", "Gabon", "Guinea", "South Africa",
|
||||
"Burkina Faso", "Republic of Congo", "Togo", "Benin", "Malawi"
|
||||
],
|
||||
// D1
|
||||
[
|
||||
"Namibia", "Liberia", "Ghana", "Mauritania", "Sao Tome and Principe",
|
||||
"Cape Verde", "Senegal", "Gambia", "Burundi", "Ascension Island",
|
||||
"Botswana", "Comoros", "Tanzania", "Ethiopia", "Nigeria"
|
||||
],
|
||||
// D2
|
||||
[
|
||||
"Sierra Leone", "Zimbabwe", "Mozambique", "Uganda", "Swaziland",
|
||||
"Kenya", "Somalia", "Niger", "Chad", "Guinea-Bissau",
|
||||
"DR Congo", "Cote d'Ivoire", null, "Zambia", "Eritrea"
|
||||
],
|
||||
// D3
|
||||
[
|
||||
null, null, "Western Sahara", "Cabinda", "Rwanda",
|
||||
"Lesotho", null, "Seychelles", null, "Mauritius",
|
||||
null, "Sudan", null, null, null
|
||||
],
|
||||
// D4
|
||||
[
|
||||
null, null, null, null, null,
|
||||
null, null, null, null, "South Sudan",
|
||||
null, null, null, null, null
|
||||
]
|
||||
];
|
||||
|
||||
const rdsEccE0E5Lut = [
|
||||
// E0
|
||||
[
|
||||
"Germany", "Algeria", "Andorra", "Israel", "Italy",
|
||||
"Belgium", "Russia", "Palestine", "Albania", "Austria",
|
||||
"Hungary", "Malta", "Germany", null, "Egypt"
|
||||
],
|
||||
// E1
|
||||
[
|
||||
"Greece", "Cyprus", "San Marino", "Switzerland", "Jordan",
|
||||
"Finland", "Luxembourg", "Bulgaria", "Denmark", "Gibraltar",
|
||||
"Iraq", "United Kingdom", "Libya", "Romania", "France"
|
||||
],
|
||||
// E2
|
||||
[
|
||||
"Morocco", "Czechia", "Poland", "Vatican", "Slovakia",
|
||||
"Syria", "Tunisia", null, "Liechtenstein", "Iceland",
|
||||
"Monaco", "Lithuania", "Serbia", "Spain", "Norway"
|
||||
],
|
||||
// E3
|
||||
[
|
||||
"Montenegro", "Ireland", "Turkey", null, "Tajikistan",
|
||||
null, null, "Netherlands", "Latvia", "Lebanon",
|
||||
"Azerbaijan", "Croatia", "Kazakhstan", "Sweden", "Belarus"
|
||||
],
|
||||
// E4
|
||||
[
|
||||
"Moldova", "Estonia", "Macedonia", null, null,
|
||||
"Ukraine", "Kosovo", "Portugal", "Slovenia", "Armenia",
|
||||
"Uzbekistan", "Georgia", null, "Turkmenistan", "Bosnia Herzegovina"
|
||||
],
|
||||
// E5
|
||||
[
|
||||
null, null, "Kyrgyzstan", null, null,
|
||||
null, null, null, null, null,
|
||||
null, null, null, null, null
|
||||
]
|
||||
];
|
||||
|
||||
const rdsEccF0F4Lut = [
|
||||
// F0
|
||||
[
|
||||
"Australia Capital Territory", "Australia New South Wales", "Australia Victoria", "Australia Queensland", "Australia South Australia",
|
||||
"Australia Western Australia", "Australia Tasmania", "Australia Northern Territory", "Saudi Arabia", "Afghanistan",
|
||||
"Myanmar", "China", "North Korea", "Bahrein", "Malaysia"
|
||||
],
|
||||
// F1
|
||||
[
|
||||
"Kiribati", "Bhutan", "Bangladesh", "Pakistan", "Fiji",
|
||||
"Oman", "Nauru", "Iran", "New Zealand", "Solomon Islands",
|
||||
"Brunei Darussalam", "Sri Lanka", "Taiwan", "South Korea", "Hong Kong"
|
||||
],
|
||||
// F2
|
||||
[
|
||||
"Kuwait", "Qatar", "Cambodia", "Samoa", "India",
|
||||
"Macao", "Vietnam", "Philippines", "Japan", "Singapore",
|
||||
"Maldives", "Indonesia", "United Arab Emirates", "Nepal", "Vanuatu"
|
||||
],
|
||||
// F3
|
||||
[
|
||||
"Laos", "Thailand", "Tonga", null, null,
|
||||
null, null, "China", "Papua New Guinea", null,
|
||||
"Yemen", null, null, "Micronesia", "Mongolia"
|
||||
],
|
||||
// F4
|
||||
[
|
||||
null, null, null, null, null,
|
||||
null, null, null, "China", null,
|
||||
"Marshall Islands", null, null, null, null
|
||||
]
|
||||
];
|
||||
|
||||
function rdsEccLookup(pi, ecc) {
|
||||
const PI_UNKNOWN = -1;
|
||||
|
||||
const piCountry = (pi >> 12) & 0xF;
|
||||
|
||||
if (pi === PI_UNKNOWN || piCountry === 0) {
|
||||
return ""
|
||||
}
|
||||
|
||||
const piId = piCountry - 1;
|
||||
|
||||
const eccRanges = [
|
||||
{ min: 0xA0, max: 0xA6, lut: rdsEccA0A6Lut },
|
||||
{ min: 0xD0, max: 0xD4, lut: rdsEccD0D4Lut },
|
||||
{ min: 0xE0, max: 0xE5, lut: rdsEccE0E5Lut },
|
||||
{ min: 0xF0, max: 0xF4, lut: rdsEccF0F4Lut }
|
||||
];
|
||||
|
||||
// Check each range
|
||||
for (const range of eccRanges) {
|
||||
if (ecc >= range.min && ecc <= range.max) {
|
||||
const eccId = ecc - range.min;
|
||||
return range.lut[eccId][piId];
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
rdsEccLookup,
|
||||
iso,
|
||||
countries
|
||||
};
|
||||
Reference in New Issue
Block a user