Add msgq to op25_decoder_ff to permit passing of snapshots to UI.

Change swabbing to use a bit decoding map, make argument types template parameters (so bvec/bit_vector can be interchanged).
Use a bit_queue (deque<bool>) for the frame buffer, pass this to all data_unit constructors.
Add plumbing to send snapshot to the UI.
New voice_data_unit as result of re-factoring LDU1/LDU2.
Re-factor op25_decoder_ff to use the bit_queue for correlation and frame header (and body - but that's ignored just now).


git-svn-id: http://op25.osmocom.org/svn/trunk@135 65a5c917-d112-43f1-993d-58c26a4786be
This commit is contained in:
stevie 2009-01-28 04:50:25 +00:00
parent e54eca540b
commit fa75c57851
24 changed files with 399 additions and 538 deletions

View File

@ -68,6 +68,7 @@ _op25_la_SOURCES = \
tdu.cc \
imbe_decoder.cc \
dummy_imbe_decoder.cc \
voice_data_unit.cc \
op25.cc \
op25_decoder_ff.cc \
vc55_imbe_decoder.cc

View File

@ -25,8 +25,10 @@
#include <algorithm>
#include <cstring>
#include <functional>
#include <stdexcept>
#include <sstream>
#include <utility>
using namespace std;
@ -88,9 +90,17 @@ abstract_data_unit::is_complete() const
return d_frame_body.size() >= frame_size_max();
}
abstract_data_unit::abstract_data_unit(const_bit_vector& frame_body) :
d_frame_body(frame_body)
std::string
abstract_data_unit::snapshot() const
{
string empty;
return empty;
}
abstract_data_unit::abstract_data_unit(const_bit_queue& frame_body) :
d_frame_body(frame_body.size())
{
copy(frame_body.begin(), frame_body.end(), d_frame_body.begin());
}
void
@ -107,7 +117,7 @@ abstract_data_unit::decode_audio(const_bit_vector& frame_body, imbe_decoder& imb
size_t
abstract_data_unit::decode_body(const_bit_vector& frame_body, size_t msg_sz, uint8_t *msg)
{
return swab(frame_body, 0, frame_body.size(), msg);
return extract(frame_body, 0, frame_body.size(), msg);
}
uint16_t

View File

@ -25,6 +25,7 @@
#define INCLUDED_ABSTRACT_DATA_UNIT_H
#include <data_unit.h>
#include <string>
#include <vector>
/**
@ -79,14 +80,23 @@ public:
*/
virtual bool is_complete() const;
/**
* Return a snapshot of the key fields from this frame in a manner
* suitable for display by the UI. The string is encoded as a
* pickled Python dictionary.
*
* \return A string containing the fields to display.
*/
virtual std::string snapshot() const;
protected:
/**
* abstract_data_unit constructor.
*
* \param frame_body A const_bit_vector representing the frame body.
* \param frame_body A const_bit_queue representing the frame body.
*/
abstract_data_unit(const_bit_vector& frame_body);
abstract_data_unit(const_bit_queue& frame_body);
/**
* Applies error correction code to the specified bit_vector.
@ -116,6 +126,13 @@ protected:
*/
virtual size_t decode_body(const_bit_vector& frame_body, size_t msg_sz, uint8_t *msg);
/**
* Returns a string describing the Data Unit ID (DUID).
*
* \return A string identifying the DUID.
*/
virtual std::string duid_str() const = 0;
/**
* Returns the expected size (in bits) of this data_unit. For
* variable-length data this should return UINT16_MAX until the

View File

@ -26,12 +26,12 @@
#include <ldu1.h>
#include <ldu2.h>
#include <pdu.h>
#include <swab.h>
#include <tdu.h>
data_unit_sptr
data_unit::make_data_unit(const_bit_vector& frame_body)
data_unit::make_data_unit(const_bit_queue& frame_body)
{
// ToDo: check frame_body length is at least 64 bits long!
data_unit_sptr d;
uint8_t duid = extract(frame_body, 60, 64);
switch(duid) {

View File

@ -31,6 +31,9 @@
#include <stdint.h>
#include <swab.h>
typedef std::deque<bool> bit_queue;
typedef const std::deque<bool> const_bit_queue;
typedef uint8_t dibit;
typedef std::deque<float> float_queue;
@ -51,7 +54,7 @@ public:
* \param nid The network ID for this data_unit.
* \return A (possibly null-valued) pointer to the data_unit.
*/
static data_unit_sptr make_data_unit(const_bit_vector& frame_body);
static data_unit_sptr make_data_unit(const_bit_queue& frame_body);
/**
* data_unit (virtual) destructor.
@ -97,6 +100,16 @@ public:
*/
virtual bool is_complete() const = 0;
/**
* Return a snapshot of the key fields from this frame in a manner
* suitable for display by the UI. The string is encoded using the
* Python pickle format allowing for different fields to be
* returned.
*
* \return A string containing the fields to display.
*/
virtual std::string snapshot() const = 0;
protected:
/**

View File

@ -25,7 +25,9 @@
#include <itpp/comm/egolay.h>
#include <itpp/comm/reedsolomon.h>
hdu::hdu(const_bit_vector& frame_body) :
using std::string;
hdu::hdu(const_bit_queue& frame_body) :
abstract_data_unit(frame_body)
{
}
@ -34,6 +36,19 @@ hdu::~hdu()
{
}
string
hdu::duid_str() const
{
return string("HDU");
}
std::string
hdu::snapshot() const
{
string empty;
return empty;
}
void
hdu::correct_errors(bit_vector& frame)
{
@ -44,14 +59,63 @@ hdu::correct_errors(bit_vector& frame)
void
hdu::apply_golay_correction(bit_vector& frame)
{
// static itpp::Extended_Golay golay;
static itpp::Extended_Golay golay;
static const size_t nof_golay_codewords = 36, golay_codeword_sz = 18;
static const size_t golay_codewords[nof_golay_codewords][golay_codeword_sz] = {
{ 119, 118, 117, 116, 115, 114, 131, 130, 129, 128, 127, 126, 125, 124, 123, 122, 121, 120 },
{ 137, 136, 135, 134, 133, 132, 151, 150, 149, 148, 147, 146, 145, 144, 141, 140, 139, 138 },
{ 157, 156, 155, 154, 153, 152, 169, 168, 167, 166, 165, 164, 163, 162, 161, 160, 159, 158 },
{ 175, 174, 173, 172, 171, 170, 187, 186, 185, 184, 183, 182, 181, 180, 179, 178, 177, 176 },
{ 193, 192, 191, 190, 189, 188, 205, 204, 203, 202, 201, 200, 199, 198, 197, 196, 195, 194 },
{ 211, 210, 209, 208, 207, 206, 225, 224, 223, 222, 221, 220, 219, 218, 217, 216, 213, 212 },
{ 231, 230, 229, 228, 227, 226, 243, 242, 241, 240, 239, 238, 237, 236, 235, 234, 233, 232 },
{ 249, 248, 247, 246, 245, 244, 261, 260, 259, 258, 257, 256, 255, 254, 253, 252, 251, 250 },
{ 267, 266, 265, 264, 263, 262, 279, 278, 277, 276, 275, 274, 273, 272, 271, 270, 269, 268 },
{ 285, 284, 283, 282, 281, 280, 299, 298, 297, 296, 295, 294, 293, 292, 291, 290, 289, 288 },
{ 305, 304, 303, 302, 301, 300, 317, 316, 315, 314, 313, 312, 311, 310, 309, 308, 307, 306 },
{ 323, 322, 321, 320, 319, 318, 335, 334, 333, 332, 331, 330, 329, 328, 327, 326, 325, 324 },
{ 341, 340, 339, 338, 337, 336, 353, 352, 351, 350, 349, 348, 347, 346, 345, 344, 343, 342 },
{ 361, 360, 357, 356, 355, 354, 373, 372, 371, 370, 369, 368, 367, 366, 365, 364, 363, 362 },
{ 379, 378, 377, 376, 375, 374, 391, 390, 389, 388, 387, 386, 385, 384, 383, 382, 381, 380 },
{ 397, 396, 395, 394, 393, 392, 409, 408, 407, 406, 405, 404, 403, 402, 401, 400, 399, 398 },
{ 415, 414, 413, 412, 411, 410, 427, 426, 425, 424, 423, 422, 421, 420, 419, 418, 417, 416 },
{ 435, 434, 433, 432, 429, 428, 447, 446, 445, 444, 443, 442, 441, 440, 439, 438, 437, 436 },
{ 453, 452, 451, 450, 449, 448, 465, 464, 463, 462, 461, 460, 459, 458, 457, 456, 455, 454 },
{ 471, 470, 469, 468, 467, 466, 483, 482, 481, 480, 479, 478, 477, 476, 475, 474, 473, 472 },
{ 489, 488, 487, 486, 485, 484, 501, 500, 499, 498, 497, 496, 495, 494, 493, 492, 491, 490 },
{ 509, 508, 507, 506, 505, 504, 521, 520, 519, 518, 517, 516, 515, 514, 513, 512, 511, 510 },
{ 527, 526, 525, 524, 523, 522, 539, 538, 537, 536, 535, 534, 533, 532, 531, 530, 529, 528 },
{ 545, 544, 543, 542, 541, 540, 557, 556, 555, 554, 553, 552, 551, 550, 549, 548, 547, 546 },
{ 563, 562, 561, 560, 559, 558, 577, 576, 573, 572, 571, 570, 569, 568, 567, 566, 565, 564 },
{ 583, 582, 581, 580, 579, 578, 595, 594, 593, 592, 591, 590, 589, 588, 587, 586, 585, 584 },
{ 601, 600, 599, 598, 597, 596, 613, 612, 611, 610, 609, 608, 607, 606, 605, 604, 603, 602 },
{ 619, 618, 617, 616, 615, 614, 631, 630, 629, 628, 627, 626, 625, 624, 623, 622, 621, 620 },
{ 637, 636, 635, 634, 633, 632, 651, 650, 649, 648, 645, 644, 643, 642, 641, 640, 639, 638 },
{ 657, 656, 655, 654, 653, 652, 669, 668, 667, 666, 665, 664, 663, 662, 661, 660, 659, 658 },
{ 675, 674, 673, 672, 671, 670, 687, 686, 685, 684, 683, 682, 681, 680, 679, 678, 677, 676 },
{ 693, 692, 691, 690, 689, 688, 705, 704, 703, 702, 701, 700, 699, 698, 697, 696, 695, 694 },
{ 711, 710, 709, 708, 707, 706, 725, 724, 723, 722, 721, 720, 717, 716, 715, 714, 713, 712 },
{ 731, 730, 729, 728, 727, 726, 743, 742, 741, 740, 739, 738, 737, 736, 735, 734, 733, 732 },
{ 749, 748, 747, 746, 745, 744, 761, 760, 759, 758, 757, 756, 755, 754, 753, 752, 751, 750 },
{ 767, 766, 765, 764, 763, 762, 779, 778, 777, 776, 775, 774, 773, 772, 771, 770, 769, 768 }
};
for(size_t i = 0; i < nof_golay_codewords; ++i) {
// ToDo:
}
}
void
hdu::apply_rs_correction(bit_vector& frame)
{
// static itpp::Reed_Solomon rs(63, 47, 17, true);
static itpp::Reed_Solomon rs(6, 8, true);
#if 0
const size_t rs_codeword[][6] = {
};
const size_t nof_codeword_bits = sizeof(codeword_bits) / sizeof(codeword_bits[0]);
#endif
}
uint16_t

View File

@ -37,15 +37,29 @@ public:
/**
* hdu constructor.
*
* \param frame_body A const_bit_vector representing the frame body.
* \param frame_body A const_bit_queue representing the frame body.
*/
hdu(const bit_vector& frame_body);
hdu(const_bit_queue& frame_body);
/**
* hdu virtual destructor.
*/
virtual ~hdu();
/**
* Returns a string describing the Data Unit ID (DUID).
*/
std::string duid_str() const;
/**
* Return a snapshot of the key fields from this frame in a manner
* suitable for display by the UI. The string is encoded as a
* pickled Python dictionary.
*
* \return A string containing the fields to display.
*/
virtual std::string snapshot() const;
protected:
/**

View File

@ -24,13 +24,13 @@
#ifndef INCLUDED_IMBE_DECODER_H
#define INCLUDED_IMBE_DECODER_H
#include <bitset>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
#include <deque>
#include <vector>
typedef std::bitset<144> voice_codeword;
typedef std::deque<float> audio_output;
typedef std::vector<bool> voice_codeword;
typedef boost::shared_ptr<class imbe_decoder> imbe_decoder_sptr;

View File

@ -23,8 +23,10 @@
#include <ldu1.h>
ldu1::ldu1(const_bit_vector& frame_body) :
abstract_data_unit(frame_body)
using std::string;
ldu1::ldu1(const_bit_queue& frame_body) :
voice_data_unit(frame_body)
{
}
@ -32,149 +34,8 @@ ldu1::~ldu1()
{
}
void
ldu1::correct_errors(bit_vector& frame_body)
string
ldu1::duid_str() const
{
}
size_t
ldu1::decode_audio(const_bit_vector& frame_body, imbe_decoder& imbe, float_queue& audio)
{
static const size_t nof_voice_codewords = 9, voice_codeword_sz = 144;
static const size_t voice_codeword_bits[nof_voice_codewords][voice_codeword_sz] = {
{ 114, 121, 126, 133, 138, 147, 152, 159, 164, 171, 176, 183,
188, 195, 200, 207, 212, 221, 226, 233, 238, 245, 250, 257,
115, 120, 127, 132, 139, 146, 153, 158, 165, 170, 177, 182,
189, 194, 201, 206, 213, 220, 227, 232, 239, 244, 251, 256,
116, 123, 128, 135, 140, 149, 154, 161, 166, 173, 178, 185,
190, 197, 202, 209, 216, 223, 228, 235, 240, 247, 252, 259,
117, 122, 129, 134, 141, 148, 155, 160, 167, 172, 179, 184,
191, 196, 203, 208, 217, 222, 229, 234, 241, 246, 253, 258,
118, 125, 130, 137, 144, 151, 156, 163, 168, 175, 180, 187,
192, 199, 204, 211, 218, 225, 230, 237, 242, 249, 254, 261,
119, 124, 131, 136, 145, 150, 157, 162, 169, 174, 181, 186,
193, 198, 205, 210, 219, 224, 231, 236, 243, 248, 255, 260 },
{ 262, 269, 274, 281, 288, 295, 300, 307, 312, 319, 324, 331,
336, 343, 348, 355, 362, 369, 374, 381, 386, 393, 398, 405,
263, 268, 275, 280, 289, 294, 301, 306, 313, 318, 325, 330,
337, 342, 349, 354, 363, 368, 375, 380, 387, 392, 399, 404,
264, 271, 276, 283, 290, 297, 302, 309, 314, 321, 326, 333,
338, 345, 350, 357, 364, 371, 376, 383, 388, 395, 400, 407,
265, 270, 277, 282, 291, 296, 303, 308, 315, 320, 327, 332,
339, 344, 351, 356, 365, 370, 377, 382, 389, 394, 401, 406,
266, 273, 278, 285, 292, 299, 304, 311, 316, 323, 328, 335,
340, 347, 352, 361, 366, 373, 378, 385, 390, 397, 402, 409,
267, 272, 279, 284, 293, 298, 305, 310, 317, 322, 329, 334,
341, 346, 353, 360, 367, 372, 379, 384, 391, 396, 403, 408 },
{ 452, 459, 464, 471, 476, 483, 488, 495, 500, 509, 514, 521,
526, 533, 538, 545, 550, 557, 562, 569, 576, 583, 588, 595,
453, 458, 465, 470, 477, 482, 489, 494, 501, 508, 515, 520,
527, 532, 539, 544, 551, 556, 563, 568, 577, 582, 589, 594,
454, 461, 466, 473, 478, 485, 490, 497, 504, 511, 516, 523,
528, 535, 540, 547, 552, 559, 564, 571, 578, 585, 590, 597,
455, 460, 467, 472, 479, 484, 491, 496, 505, 510, 517, 522,
529, 534, 541, 546, 553, 558, 565, 570, 579, 584, 591, 596,
456, 463, 468, 475, 480, 487, 492, 499, 506, 513, 518, 525,
530, 537, 542, 549, 554, 561, 566, 573, 580, 587, 592, 599,
457, 462, 469, 474, 481, 486, 493, 498, 507, 512, 519, 524,
531, 536, 543, 548, 555, 560, 567, 572, 581, 586, 593, 598 },
{ 640, 649, 654, 661, 666, 673, 678, 685, 690, 697, 702, 709,
714, 723, 728, 735, 740, 747, 752, 759, 764, 771, 776, 783,
641, 648, 655, 660, 667, 672, 679, 684, 691, 696, 703, 708,
715, 722, 729, 734, 741, 746, 753, 758, 765, 770, 777, 782,
642, 651, 656, 663, 668, 675, 680, 687, 692, 699, 704, 711,
716, 725, 730, 737, 742, 749, 754, 761, 766, 773, 778, 785,
643, 650, 657, 662, 669, 674, 681, 686, 693, 698, 705, 710,
717, 724, 731, 736, 743, 748, 755, 760, 767, 772, 779, 784,
644, 653, 658, 665, 670, 677, 682, 689, 694, 701, 706, 713,
720, 727, 732, 739, 744, 751, 756, 763, 768, 775, 780, 787,
645, 652, 659, 664, 671, 676, 683, 688, 695, 700, 707, 712,
721, 726, 733, 738, 745, 750, 757, 762, 769, 774, 781, 786 },
{ 830, 837, 842, 849, 854, 861, 868, 875, 880, 887, 892, 899,
904, 911, 916, 923, 928, 937, 942, 949, 954, 961, 966, 973,
831, 836, 843, 848, 855, 860, 869, 874, 881, 886, 893, 898,
905, 910, 917, 922, 929, 936, 943, 948, 955, 960, 967, 972,
832, 839, 844, 851, 856, 865, 870, 877, 882, 889, 894, 901,
906, 913, 918, 925, 930, 939, 944, 951, 956, 963, 968, 975,
833, 838, 845, 850, 857, 864, 871, 876, 883, 888, 895, 900,
907, 912, 919, 924, 931, 938, 945, 950, 957, 962, 969, 974,
834, 841, 846, 853, 858, 867, 872, 879, 884, 891, 896, 903,
908, 915, 920, 927, 932, 941, 946, 953, 958, 965, 970, 977,
835, 840, 847, 852, 859, 866, 873, 878, 885, 890, 897, 902,
909, 914, 921, 926, 933, 940, 947, 952, 959, 964, 971, 976 },
{ 1020, 1027, 1032, 1039, 1044, 1051, 1056, 1063, 1068, 1075, 1082, 1089,
1094, 1101, 1106, 1113, 1118, 1125, 1130, 1137, 1142, 1149, 1156, 1163,
1021, 1026, 1033, 1038, 1045, 1050, 1057, 1062, 1069, 1074, 1083, 1088,
1095, 1100, 1107, 1112, 1119, 1124, 1131, 1136, 1143, 1148, 1157, 1162,
1022, 1029, 1034, 1041, 1046, 1053, 1058, 1065, 1070, 1077, 1084, 1091,
1096, 1103, 1108, 1115, 1120, 1127, 1132, 1139, 1144, 1153, 1158, 1165,
1023, 1028, 1035, 1040, 1047, 1052, 1059, 1064, 1071, 1076, 1085, 1090,
1097, 1102, 1109, 1114, 1121, 1126, 1133, 1138, 1145, 1152, 1159, 1164,
1024, 1031, 1036, 1043, 1048, 1055, 1060, 1067, 1072, 1081, 1086, 1093,
1098, 1105, 1110, 1117, 1122, 1129, 1134, 1141, 1146, 1155, 1160, 1167,
1025, 1030, 1037, 1042, 1049, 1054, 1061, 1066, 1073, 1080, 1087, 1092,
1099, 1104, 1111, 1116, 1123, 1128, 1135, 1140, 1147, 1154, 1161, 1166 },
{ 1208, 1215, 1220, 1229, 1234, 1241, 1246, 1253, 1258, 1265, 1270, 1277,
1282, 1289, 1296, 1303, 1308, 1315, 1320, 1327, 1332, 1339, 1344, 1351,
1209, 1214, 1221, 1228, 1235, 1240, 1247, 1252, 1259, 1264, 1271, 1276,
1283, 1288, 1297, 1302, 1309, 1314, 1321, 1326, 1333, 1338, 1345, 1350,
1210, 1217, 1224, 1231, 1236, 1243, 1248, 1255, 1260, 1267, 1272, 1279,
1284, 1291, 1298, 1305, 1310, 1317, 1322, 1329, 1334, 1341, 1346, 1353,
1211, 1216, 1225, 1230, 1237, 1242, 1249, 1254, 1261, 1266, 1273, 1278,
1285, 1290, 1299, 1304, 1311, 1316, 1323, 1328, 1335, 1340, 1347, 1352,
1212, 1219, 1226, 1233, 1238, 1245, 1250, 1257, 1262, 1269, 1274, 1281,
1286, 1293, 1300, 1307, 1312, 1319, 1324, 1331, 1336, 1343, 1348, 1355,
1213, 1218, 1227, 1232, 1239, 1244, 1251, 1256, 1263, 1268, 1275, 1280,
1287, 1292, 1301, 1306, 1313, 1318, 1325, 1330, 1337, 1342, 1349, 1354 },
{ 1398, 1405, 1410, 1417, 1422, 1429, 1434, 1443, 1448, 1455, 1460, 1467,
1472, 1479, 1484, 1491, 1496, 1503, 1508, 1517, 1522, 1529, 1534, 1541,
1399, 1404, 1411, 1416, 1423, 1428, 1435, 1442, 1449, 1454, 1461, 1466,
1473, 1478, 1485, 1490, 1497, 1502, 1509, 1516, 1523, 1528, 1535, 1540,
1400, 1407, 1412, 1419, 1424, 1431, 1436, 1445, 1450, 1457, 1462, 1469,
1474, 1481, 1486, 1493, 1498, 1505, 1512, 1519, 1524, 1531, 1536, 1543,
1401, 1406, 1413, 1418, 1425, 1430, 1437, 1444, 1451, 1456, 1463, 1468,
1475, 1480, 1487, 1492, 1499, 1504, 1513, 1518, 1525, 1530, 1537, 1542,
1402, 1409, 1414, 1421, 1426, 1433, 1440, 1447, 1452, 1459, 1464, 1471,
1476, 1483, 1488, 1495, 1500, 1507, 1514, 1521, 1526, 1533, 1538, 1545,
1403, 1408, 1415, 1420, 1427, 1432, 1441, 1446, 1453, 1458, 1465, 1470,
1477, 1482, 1489, 1494, 1501, 1506, 1515, 1520, 1527, 1532, 1539, 1544 },
{ 1578, 1587, 1592, 1599, 1604, 1611, 1616, 1623, 1628, 1635, 1640, 1647,
1652, 1661, 1666, 1673, 1678, 1685, 1690, 1697, 1702, 1709, 1714, 1721,
1579, 1586, 1593, 1598, 1605, 1610, 1617, 1622, 1629, 1634, 1641, 1646,
1653, 1660, 1667, 1672, 1679, 1684, 1691, 1696, 1703, 1708, 1715, 1720,
1580, 1589, 1594, 1601, 1606, 1613, 1618, 1625, 1630, 1637, 1642, 1649,
1656, 1663, 1668, 1675, 1680, 1687, 1692, 1699, 1704, 1711, 1716, 1723,
1581, 1588, 1595, 1600, 1607, 1612, 1619, 1624, 1631, 1636, 1643, 1648,
1657, 1662, 1669, 1674, 1681, 1686, 1693, 1698, 1705, 1710, 1717, 1722,
1584, 1591, 1596, 1603, 1608, 1615, 1620, 1627, 1632, 1639, 1644, 1651,
1658, 1665, 1670, 1677, 1682, 1689, 1694, 1701, 1706, 1713, 1718, 1725,
1585, 1590, 1597, 1602, 1609, 1614, 1621, 1626, 1633, 1638, 1645, 1650,
1659, 1664, 1671, 1676, 1683, 1688, 1695, 1700, 1707, 1712, 1719, 1724 },
};
size_t nof_samples = 0;
for(size_t i = 0; i < nof_voice_codewords; ++i) {
voice_codeword cw;
for(size_t j = 0; j < voice_codeword_sz; ++j) {
cw[j] = frame_body[voice_codeword_bits[i][j]];
}
nof_samples += imbe.decode(cw, audio);
}
return nof_samples;
}
uint16_t
ldu1::frame_size_max() const
{
return 1728;
return string("LDU1");
}

View File

@ -24,58 +24,31 @@
#ifndef INCLUDED_LDU1_H
#define INCLUDED_LDU1_H
#include <abstract_data_unit.h>
#include <voice_data_unit.h>
/**
* P25 Logical Data Unit 1 (compressed IBME voice).
* P25 Logical Data Unit 1.
*/
class ldu1 : public abstract_data_unit
class ldu1 : public voice_data_unit
{
public:
/**
* ldu1 constuctor
*
* \param frame_body A const_bit_vector representing the frame body.
* \param frame_body A const_bit_queue representing the frame body.
*/
ldu1(const_bit_vector& frame_body);
ldu1(const_bit_queue& frame_body);
/**
* ldu1 (virtual) destuctor
*/
virtual ~ldu1();
protected:
/**
* Applies error correction code to the specified bit_vector. Not
* that this function removes the PN sequences from the source
* frame.
*
* \param frame_body The bit vector to decode.
* \return
* Returns a string describing the Data Unit ID (DUID).
*/
virtual void correct_errors(bit_vector& frame_body);
/**
* Decode compressed audio using the supplied imbe_decoder and
* writes output to audio.
*
* \param frame_body The const_bit_vector to decode.
* \param imbe The imbe_decoder to use to generate the audio.
* \param audio A deque<float> to which the audio (if any) is appended.
* \return The number of samples written to audio.
*/
virtual size_t decode_audio(const_bit_vector& frame_body, imbe_decoder& imbe, float_queue& audio);
/**
* Returns the expected size (in bits) of this data_unit. For
* variable-length data this should return UINT16_MAX until the
* actual length of this frame is known.
*
* \return The expected size (in bits) of this data_unit when encoded.
*/
virtual uint16_t frame_size_max() const;
std::string duid_str() const;
};

View File

@ -23,8 +23,10 @@
#include <ldu2.h>
ldu2::ldu2(const_bit_vector& frame_body) :
abstract_data_unit(frame_body)
using std::string;
ldu2::ldu2(const_bit_queue& frame_body) :
voice_data_unit(frame_body)
{
}
@ -32,149 +34,8 @@ ldu2::~ldu2()
{
}
void
ldu2::correct_errors(bit_vector& frame_body)
string
ldu2::duid_str() const
{
}
size_t
ldu2::decode_audio(const_bit_vector& frame_body, imbe_decoder& imbe, float_queue& audio)
{
static const size_t nof_voice_codewords = 9, voice_codeword_sz = 144;
static const size_t voice_codeword_bits[nof_voice_codewords][voice_codeword_sz] = {
{ 114, 121, 126, 133, 138, 147, 152, 159, 164, 171, 176, 183,
188, 195, 200, 207, 212, 221, 226, 233, 238, 245, 250, 257,
115, 120, 127, 132, 139, 146, 153, 158, 165, 170, 177, 182,
189, 194, 201, 206, 213, 220, 227, 232, 239, 244, 251, 256,
116, 123, 128, 135, 140, 149, 154, 161, 166, 173, 178, 185,
190, 197, 202, 209, 216, 223, 228, 235, 240, 247, 252, 259,
117, 122, 129, 134, 141, 148, 155, 160, 167, 172, 179, 184,
191, 196, 203, 208, 217, 222, 229, 234, 241, 246, 253, 258,
118, 125, 130, 137, 144, 151, 156, 163, 168, 175, 180, 187,
192, 199, 204, 211, 218, 225, 230, 237, 242, 249, 254, 261,
119, 124, 131, 136, 145, 150, 157, 162, 169, 174, 181, 186,
193, 198, 205, 210, 219, 224, 231, 236, 243, 248, 255, 260 },
{ 262, 269, 274, 281, 288, 295, 300, 307, 312, 319, 324, 331,
336, 343, 348, 355, 362, 369, 374, 381, 386, 393, 398, 405,
263, 268, 275, 280, 289, 294, 301, 306, 313, 318, 325, 330,
337, 342, 349, 354, 363, 368, 375, 380, 387, 392, 399, 404,
264, 271, 276, 283, 290, 297, 302, 309, 314, 321, 326, 333,
338, 345, 350, 357, 364, 371, 376, 383, 388, 395, 400, 407,
265, 270, 277, 282, 291, 296, 303, 308, 315, 320, 327, 332,
339, 344, 351, 356, 365, 370, 377, 382, 389, 394, 401, 406,
266, 273, 278, 285, 292, 299, 304, 311, 316, 323, 328, 335,
340, 347, 352, 361, 366, 373, 378, 385, 390, 397, 402, 409,
267, 272, 279, 284, 293, 298, 305, 310, 317, 322, 329, 334,
341, 346, 353, 360, 367, 372, 379, 384, 391, 396, 403, 408 },
{ 452, 459, 464, 471, 476, 483, 488, 495, 500, 509, 514, 521,
526, 533, 538, 545, 550, 557, 562, 569, 576, 583, 588, 595,
453, 458, 465, 470, 477, 482, 489, 494, 501, 508, 515, 520,
527, 532, 539, 544, 551, 556, 563, 568, 577, 582, 589, 594,
454, 461, 466, 473, 478, 485, 490, 497, 504, 511, 516, 523,
528, 535, 540, 547, 552, 559, 564, 571, 578, 585, 590, 597,
455, 460, 467, 472, 479, 484, 491, 496, 505, 510, 517, 522,
529, 534, 541, 546, 553, 558, 565, 570, 579, 584, 591, 596,
456, 463, 468, 475, 480, 487, 492, 499, 506, 513, 518, 525,
530, 537, 542, 549, 554, 561, 566, 573, 580, 587, 592, 599,
457, 462, 469, 474, 481, 486, 493, 498, 507, 512, 519, 524,
531, 536, 543, 548, 555, 560, 567, 572, 581, 586, 593, 598 },
{ 640, 649, 654, 661, 666, 673, 678, 685, 690, 697, 702, 709,
714, 723, 728, 735, 740, 747, 752, 759, 764, 771, 776, 783,
641, 648, 655, 660, 667, 672, 679, 684, 691, 696, 703, 708,
715, 722, 729, 734, 741, 746, 753, 758, 765, 770, 777, 782,
642, 651, 656, 663, 668, 675, 680, 687, 692, 699, 704, 711,
716, 725, 730, 737, 742, 749, 754, 761, 766, 773, 778, 785,
643, 650, 657, 662, 669, 674, 681, 686, 693, 698, 705, 710,
717, 724, 731, 736, 743, 748, 755, 760, 767, 772, 779, 784,
644, 653, 658, 665, 670, 677, 682, 689, 694, 701, 706, 713,
720, 727, 732, 739, 744, 751, 756, 763, 768, 775, 780, 787,
645, 652, 659, 664, 671, 676, 683, 688, 695, 700, 707, 712,
721, 726, 733, 738, 745, 750, 757, 762, 769, 774, 781, 786 },
{ 830, 837, 842, 849, 854, 861, 868, 875, 880, 887, 892, 899,
904, 911, 916, 923, 928, 937, 942, 949, 954, 961, 966, 973,
831, 836, 843, 848, 855, 860, 869, 874, 881, 886, 893, 898,
905, 910, 917, 922, 929, 936, 943, 948, 955, 960, 967, 972,
832, 839, 844, 851, 856, 865, 870, 877, 882, 889, 894, 901,
906, 913, 918, 925, 930, 939, 944, 951, 956, 963, 968, 975,
833, 838, 845, 850, 857, 864, 871, 876, 883, 888, 895, 900,
907, 912, 919, 924, 931, 938, 945, 950, 957, 962, 969, 974,
834, 841, 846, 853, 858, 867, 872, 879, 884, 891, 896, 903,
908, 915, 920, 927, 932, 941, 946, 953, 958, 965, 970, 977,
835, 840, 847, 852, 859, 866, 873, 878, 885, 890, 897, 902,
909, 914, 921, 926, 933, 940, 947, 952, 959, 964, 971, 976 },
{ 1020, 1027, 1032, 1039, 1044, 1051, 1056, 1063, 1068, 1075, 1082, 1089,
1094, 1101, 1106, 1113, 1118, 1125, 1130, 1137, 1142, 1149, 1156, 1163,
1021, 1026, 1033, 1038, 1045, 1050, 1057, 1062, 1069, 1074, 1083, 1088,
1095, 1100, 1107, 1112, 1119, 1124, 1131, 1136, 1143, 1148, 1157, 1162,
1022, 1029, 1034, 1041, 1046, 1053, 1058, 1065, 1070, 1077, 1084, 1091,
1096, 1103, 1108, 1115, 1120, 1127, 1132, 1139, 1144, 1153, 1158, 1165,
1023, 1028, 1035, 1040, 1047, 1052, 1059, 1064, 1071, 1076, 1085, 1090,
1097, 1102, 1109, 1114, 1121, 1126, 1133, 1138, 1145, 1152, 1159, 1164,
1024, 1031, 1036, 1043, 1048, 1055, 1060, 1067, 1072, 1081, 1086, 1093,
1098, 1105, 1110, 1117, 1122, 1129, 1134, 1141, 1146, 1155, 1160, 1167,
1025, 1030, 1037, 1042, 1049, 1054, 1061, 1066, 1073, 1080, 1087, 1092,
1099, 1104, 1111, 1116, 1123, 1128, 1135, 1140, 1147, 1154, 1161, 1166 },
{ 1208, 1215, 1220, 1229, 1234, 1241, 1246, 1253, 1258, 1265, 1270, 1277,
1282, 1289, 1296, 1303, 1308, 1315, 1320, 1327, 1332, 1339, 1344, 1351,
1209, 1214, 1221, 1228, 1235, 1240, 1247, 1252, 1259, 1264, 1271, 1276,
1283, 1288, 1297, 1302, 1309, 1314, 1321, 1326, 1333, 1338, 1345, 1350,
1210, 1217, 1224, 1231, 1236, 1243, 1248, 1255, 1260, 1267, 1272, 1279,
1284, 1291, 1298, 1305, 1310, 1317, 1322, 1329, 1334, 1341, 1346, 1353,
1211, 1216, 1225, 1230, 1237, 1242, 1249, 1254, 1261, 1266, 1273, 1278,
1285, 1290, 1299, 1304, 1311, 1316, 1323, 1328, 1335, 1340, 1347, 1352,
1212, 1219, 1226, 1233, 1238, 1245, 1250, 1257, 1262, 1269, 1274, 1281,
1286, 1293, 1300, 1307, 1312, 1319, 1324, 1331, 1336, 1343, 1348, 1355,
1213, 1218, 1227, 1232, 1239, 1244, 1251, 1256, 1263, 1268, 1275, 1280,
1287, 1292, 1301, 1306, 1313, 1318, 1325, 1330, 1337, 1342, 1349, 1354 },
{ 1398, 1405, 1410, 1417, 1422, 1429, 1434, 1443, 1448, 1455, 1460, 1467,
1472, 1479, 1484, 1491, 1496, 1503, 1508, 1517, 1522, 1529, 1534, 1541,
1399, 1404, 1411, 1416, 1423, 1428, 1435, 1442, 1449, 1454, 1461, 1466,
1473, 1478, 1485, 1490, 1497, 1502, 1509, 1516, 1523, 1528, 1535, 1540,
1400, 1407, 1412, 1419, 1424, 1431, 1436, 1445, 1450, 1457, 1462, 1469,
1474, 1481, 1486, 1493, 1498, 1505, 1512, 1519, 1524, 1531, 1536, 1543,
1401, 1406, 1413, 1418, 1425, 1430, 1437, 1444, 1451, 1456, 1463, 1468,
1475, 1480, 1487, 1492, 1499, 1504, 1513, 1518, 1525, 1530, 1537, 1542,
1402, 1409, 1414, 1421, 1426, 1433, 1440, 1447, 1452, 1459, 1464, 1471,
1476, 1483, 1488, 1495, 1500, 1507, 1514, 1521, 1526, 1533, 1538, 1545,
1403, 1408, 1415, 1420, 1427, 1432, 1441, 1446, 1453, 1458, 1465, 1470,
1477, 1482, 1489, 1494, 1501, 1506, 1515, 1520, 1527, 1532, 1539, 1544 },
{ 1578, 1587, 1592, 1599, 1604, 1611, 1616, 1623, 1628, 1635, 1640, 1647,
1652, 1661, 1666, 1673, 1678, 1685, 1690, 1697, 1702, 1709, 1714, 1721,
1579, 1586, 1593, 1598, 1605, 1610, 1617, 1622, 1629, 1634, 1641, 1646,
1653, 1660, 1667, 1672, 1679, 1684, 1691, 1696, 1703, 1708, 1715, 1720,
1580, 1589, 1594, 1601, 1606, 1613, 1618, 1625, 1630, 1637, 1642, 1649,
1656, 1663, 1668, 1675, 1680, 1687, 1692, 1699, 1704, 1711, 1716, 1723,
1581, 1588, 1595, 1600, 1607, 1612, 1619, 1624, 1631, 1636, 1643, 1648,
1657, 1662, 1669, 1674, 1681, 1686, 1693, 1698, 1705, 1710, 1717, 1722,
1584, 1591, 1596, 1603, 1608, 1615, 1620, 1627, 1632, 1639, 1644, 1651,
1658, 1665, 1670, 1677, 1682, 1689, 1694, 1701, 1706, 1713, 1718, 1725,
1585, 1590, 1597, 1602, 1609, 1614, 1621, 1626, 1633, 1638, 1645, 1650,
1659, 1664, 1671, 1676, 1683, 1688, 1695, 1700, 1707, 1712, 1719, 1724 },
};
size_t nof_samples = 0;
for(size_t i = 0; i < nof_voice_codewords; ++i) {
voice_codeword cw;
for(size_t j = 0; j < voice_codeword_sz; ++j) {
cw[j] = frame_body[voice_codeword_bits[i][j]];
}
nof_samples += imbe.decode(cw, audio);
}
return nof_samples;
}
uint16_t
ldu2::frame_size_max() const
{
return 1728;
return string("LDU2");
}

View File

@ -24,55 +24,31 @@
#ifndef INCLUDED_LDU2_H
#define INCLUDED_LDU2_H
#include <abstract_data_unit.h>
#include <voice_data_unit.h>
/**
* P25 Logical Data Unit 2 (compressed IBME voice).
* P25 Logical Data Unit 2.
*/
class ldu2 : public abstract_data_unit
class ldu2 : public voice_data_unit
{
public:
/**
* ldu2 constructor.
*
* \param frame_body A bit_vector representing the frame body.
* \param frame_body A const_bit_queue representing the frame body.
*/
ldu2(const_bit_vector& frame_body);
ldu2(const_bit_queue& frame_body);
/**
* ldu2 (virtual) destructor.
*/
virtual ~ldu2();
protected:
/**
* Applies error correction code to the specified bit_vector.
*
* \param frame_body The bit vector to decode.
* Returns a string describing the Data Unit ID (DUID).
*/
virtual void correct_errors(bit_vector& frame_body);
/**
* Decode compressed audio using the supplied imbe_decoder and
* writes output to audio.
*
* \param frame_body The const_bit_vector to decode.
* \param imbe The imbe_decoder to use to generate the audio.
* \param audio A deque<float> to which the audio (if any) is appended.
* \return The number of samples written to audio.
*/
virtual size_t decode_audio(const_bit_vector& frame_body, imbe_decoder& imbe, float_queue& audio);
/**
* Returns the expected size (in bits) of this data_unit. For
* variable-length data this should return UINT16_MAX until the
* actual length of this frame is known.
*
* \return The expected size (in bits) of this data_unit when encoded.
*/
virtual uint16_t frame_size_max() const;
std::string duid_str() const;
};
#endif /* INCLUDED_LDU2_H */

View File

@ -23,7 +23,7 @@ GR_SWIG_BLOCK_MAGIC(op25, decoder_ff);
/*
* Publicly-accesible constuctor function for op25_decoder_ff.
*/
op25_decoder_ff_sptr op25_make_decoder_ff();
op25_decoder_ff_sptr op25_make_decoder_ff(gr_msg_queue_sptr msgq);
/*
* The actual op25_decoder block.
@ -31,7 +31,7 @@ op25_decoder_ff_sptr op25_make_decoder_ff();
class op25_decoder_ff : public gr_block
{
private:
op25_decoder_ff();
op25_decoder_ff(gr_msg_queue_sptr msgq);
public:
const char *device_name() const;
};

View File

@ -26,7 +26,6 @@
#endif
#include <algorithm>
#include <bitset>
#include <gr_io_signature.h>
#include <gr_message.h>
#include <iostream>
@ -40,9 +39,9 @@
using namespace std;
op25_decoder_ff_sptr
op25_make_decoder_ff()
op25_make_decoder_ff(gr_msg_queue_sptr msgq)
{
return op25_decoder_ff_sptr(new op25_decoder_ff);
return op25_decoder_ff_sptr(new op25_decoder_ff(msgq));
}
op25_decoder_ff::~op25_decoder_ff()
@ -56,7 +55,7 @@ void
op25_decoder_ff::forecast(int nof_output_items, gr_vector_int &nof_input_items_reqd)
{
const size_t nof_inputs = nof_input_items_reqd.size();
std::fill(&nof_input_items_reqd[0], &nof_input_items_reqd[nof_inputs], nof_output_items);
fill(&nof_input_items_reqd[0], &nof_input_items_reqd[nof_inputs], nof_output_items);
}
int
@ -82,7 +81,7 @@ op25_decoder_ff::general_work(int nof_output_items, gr_vector_int& nof_input_ite
for(int i = 0; i < nof_output_items; ++i) {
float *out = reinterpret_cast<float*>(&output_items[i]);
std::fill(&out[0], &out[nof_output_items], 0.0); // audio silence - for now
fill(&out[0], &out[nof_output_items], 0.0); // audio silence - for now
}
return nof_output_items;
@ -91,8 +90,7 @@ op25_decoder_ff::general_work(int nof_output_items, gr_vector_int& nof_input_ite
exit(1);
} catch(...) {
cerr << "unhandled exception" << endl;
exit(2);
}
exit(2); }
}
const char*
@ -101,16 +99,16 @@ op25_decoder_ff::device_name() const
return d_tap_device.c_str();
}
op25_decoder_ff::op25_decoder_ff() :
op25_decoder_ff::op25_decoder_ff(gr_msg_queue_sptr msgq) :
gr_block("decoder_ff", gr_make_io_signature(1, 1, sizeof(float)), gr_make_io_signature(0, 1, sizeof(float))),
d_msgq(msgq),
d_state(SYNCHRONIZING),
d_bad_NIDs(0),
d_bch(63, 16, 11,"6 3 3 1 1 4 1 3 6 7 2 3 5 4 5 3", true),
d_data_unit(),
d_data_units(0),
d_frame_hdr(114),
d_fs(0),
d_frame_hdr(),
d_imbe(imbe_decoder::make_imbe_decoder()),
d_symbol(0),
d_tap(-1),
d_tap_device("not available"),
d_unrecognized(0)
@ -153,53 +151,112 @@ op25_decoder_ff::op25_decoder_ff() :
}
bool
op25_decoder_ff::correlates(dibit d)
op25_decoder_ff::correlated()
{
size_t errs = 0;
const size_t ERR_THRESHOLD = 4;
const size_t NOF_FS_BITS = 48;
const frame_sync FS = 0x5575f5ff77ffLL;
const frame_sync FS_MASK = 0xffffffffffffLL;
d_fs = (d_fs << 2) | d;
d_fs &= FS_MASK;
size_t diff = FS ^ d_fs;
for(size_t i = 0; i < NOF_FS_BITS; ++i) {
if(diff & 0x1) {
static const bool FS[] = {
0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 1, 1, 0, 1, 0, 1,
1, 1, 1, 1, 0, 1, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1,
0, 1, 1, 1, 0, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1
};
static const size_t FS_SZ = sizeof(FS)/sizeof(FS[0]);
uint8_t errs = 0;
for(size_t i = 0; i < FS_SZ; ++i) {
if(d_frame_hdr[i] ^ FS[i]) {
++errs;
}
diff >>= 1;
}
return errs < ERR_THRESHOLD;
return (errs <= 6);
}
bool
op25_decoder_ff::identified()
{
static const size_t NID[] = {
63, 62, 61, 60, 59, 58, 57, 56,
55, 54, 53, 52, 51, 50, 49, 48,
112, 111, 110, 109, 108, 107, 106, 105,
104, 103, 102, 101, 100, 99, 98, 97,
96, 95, 94, 93, 92, 91, 90, 89,
88, 87, 86, 85, 84, 83, 82, 81,
80, 79, 78, 77, 76, 75, 74, 73,
72, 69, 68, 67, 66, 65, 64,
};
size_t NID_SZ = sizeof(NID) / sizeof(NID[0]);
itpp::bvec b(63), zeroes(16);
swab(d_frame_hdr, NID, NID_SZ, b, 0);
b = d_bch.decode(b);
if(b != zeroes) {
b = d_bch.encode(b);
unswab(b, 0, d_frame_hdr, NID, NID_SZ);
d_data_unit = data_unit::make_data_unit(d_frame_hdr);
} else {
cout << __PRETTY_FUNCTION__ << ":" << __LINE__ << "NID decode error" << endl;
cout << "\tNID=";
for(int i = 0; i < b.size(); ++i) {
cout << b[i] << ",";
}
cout << endl;
++d_bad_NIDs;
data_unit_sptr null;
d_data_unit = null;
}
return d_data_unit;
}
void
op25_decoder_ff::process_data_unit()
{
const size_t msg_hdr_sz = 14;
const size_t msg_sz = d_data_unit->data_size();
const size_t total_msg_sz = msg_hdr_sz + msg_sz;
uint8_t msg_data[total_msg_sz];
if(d_data_unit->decode(msg_sz, msg_data + msg_hdr_sz, *d_imbe, d_audio)) {
if(-1 != d_tap) {
memset(&msg_data[0], 0xff, 6);
memset(&msg_data[6], 0x00, 6);
memset(&msg_data[12], 0xff, 2);
write(d_tap, msg_data, total_msg_sz);
}
if(d_msgq) {
string snapshot(d_data_unit->snapshot());
if(snapshot.size() > 0) {
const size_t snapshot_sz = snapshot.size() + 1;
gr_message_sptr msg = gr_make_message(/*type*/0, /*arg1*/++d_data_units, /*arg2*/0, snapshot_sz);
char *snapshot_data = reinterpret_cast<char*>(msg->msg());
memcpy(snapshot_data, snapshot.c_str(), snapshot_sz);
d_msgq->handle(msg);
}
}
}
}
void
op25_decoder_ff::receive_symbol(dibit d)
{
d_frame_hdr.push_back(d & 0x2);
d_frame_hdr.push_back(d & 0x1);
const size_t frame_hdr_sz = d_frame_hdr.size();
switch(d_state) {
case SYNCHRONIZING:
if(correlates(d)) {
d_symbol = 23;
d_state = IDENTIFYING;
swab(d_fs, 47, -1, d_frame_hdr, 0);
if(48 <= frame_hdr_sz) {
d_frame_hdr.erase(d_frame_hdr.begin(), d_frame_hdr.begin() + (frame_hdr_sz - 48));
if(correlated()) {
d_state = IDENTIFYING;
}
}
break;
case IDENTIFYING:
++d_symbol;
d_frame_hdr[2 * d_symbol] = d & 2;
d_frame_hdr[(2 * d_symbol) + 1] = d & 1;
if(56 == d_symbol) {
itpp::bvec b(63);
swab(d_frame_hdr, 63, 47, b, 0);
swab(d_frame_hdr, 112, 71, b, 16);
swab(d_frame_hdr, 69, 63, b, 57);
b = d_bch.decode(b);
#if __x86_64
unswab(b, 57, d_frame_hdr, 69, 63);
unswab(b, 16, d_frame_hdr, 112, 71);
unswab(b, 0, d_frame_hdr, 63, 47);
#endif
d_data_unit = data_unit::make_data_unit(d_frame_hdr);
if(d_data_unit) {
if(114 <= frame_hdr_sz) {
if(identified()) {
d_state = READING;
} else {
++d_unrecognized;
@ -210,16 +267,7 @@ op25_decoder_ff::receive_symbol(dibit d)
case READING:
d_data_unit->extend(d);
if(d_data_unit->is_complete()) {
const size_t msg_hdr_sz = 14;
const size_t msg_sz = d_data_unit->data_size();
const size_t total_msg_sz = msg_hdr_sz + msg_sz;
uint8_t msg_data[total_msg_sz];
if(d_data_unit->decode(msg_sz, msg_data + msg_hdr_sz, *d_imbe, d_audio) && (-1 != d_tap)) {
memset(&msg_data[0], 0xff, 6);
memset(&msg_data[6], 0x00, 6);
memset(&msg_data[12], 0xff, 2);
write(d_tap, msg_data, total_msg_sz);
}
process_data_unit();
data_unit_sptr null;
d_data_unit = null;
d_state = SYNCHRONIZING;

View File

@ -24,18 +24,16 @@
#ifndef INCLUDED_OP25_DECODER_FF_H
#define INCLUDED_OP25_DECODER_FF_H
#include <bitset>
#include <data_unit.h>
#include <gr_block.h>
#include <gr_msg_queue.h>
#include <imbe_decoder.h>
#include <itpp/comm/bch.h>
#include <string>
typedef boost::shared_ptr<class op25_decoder_ff> op25_decoder_ff_sptr;
op25_decoder_ff_sptr op25_make_decoder_ff();
typedef uint64_t frame_sync;
op25_decoder_ff_sptr op25_make_decoder_ff(gr_msg_queue_sptr msgq);
/**
* op25_decoder_ff is a GNU Radio block for decoding APCO P25
@ -77,41 +75,60 @@ private:
* op25_decoder_ff and wrap it in a shared_ptr. This is effectively
* the public constructor.
*/
friend op25_decoder_ff_sptr op25_make_decoder_ff();
friend op25_decoder_ff_sptr op25_make_decoder_ff(gr_msg_queue_sptr msgq);
/**
* op25_decoder_ff protected constructor.
*/
op25_decoder_ff();
op25_decoder_ff(gr_msg_queue_sptr msgq);
/**
* Tests whether the received dibit symbol completes a frame sync
* sequence. Returns true when d completes a frame sync bit string
* otherwise returns false. When found d_fs contains the frame sync
* value.
* Tests whether d_frame_header correlates with the APCO P25 frame
* sync sequence. This method must only be called when the frame
* header is larger than 48 bits in length (the minimum size for
* the FS).
*
* \param d The symbol to process.
* \return true if the frame header correlates; otherwise false.
*/
bool correlates(dibit d);
bool correlated();
/**
* Process a received symbol.
* Tests whether d_frame_header identifies a known data unit and if
* so sets d_data_unit to point to an appropriate instance. This
* method must only be called when the frame header is larger than
* 114 bits in length (the minimum size for a frame containing a
* NID).
*
* \return true if the frame header identifies a known data unit;
* otherwise false.
*/
bool identified();
/**
* Process the completed data_unit (pointed at by
* d_data_unit). This decodes the data_unit and then sends the
* result to wireshark. Attempts to snapshot the data_unit and, if
* successfull, it passes the result to the user interface.
*/
void process_data_unit();
/**
* Handle a received symbol.
*
* \param d The symbol to process.
*/
void receive_symbol(dibit d);
private:
gr_msg_queue_sptr d_msgq;
enum { SYNCHRONIZING, IDENTIFYING, READING } d_state;
float_queue d_audio;
uint32_t d_bad_NIDs;
itpp::BCH d_bch;
data_unit_sptr d_data_unit;
uint32_t d_data_units;
bit_vector d_frame_hdr;
frame_sync d_fs;
bit_queue d_frame_hdr;
imbe_decoder_sptr d_imbe;
uint32_t d_symbol;
int32_t d_tap;
std::string d_tap_device;
uint32_t d_unrecognized;

View File

@ -23,7 +23,9 @@
#include <pdu.h>
pdu::pdu(const_bit_vector& frame_body) :
using std::string;
pdu::pdu(const_bit_queue& frame_body) :
abstract_data_unit(frame_body)
{
}
@ -31,6 +33,12 @@ pdu::~pdu()
{
}
string
pdu::duid_str() const
{
return string("PDU");
}
void
pdu::correct_errors(bit_vector& frame_body)
{

View File

@ -36,15 +36,20 @@ public:
/**
* P25 packet data unit (PDU) constructor.
*
* \param frame_body A const_bit_vector representing the frame body.
* \param frame_body A const_bit_queue representing the frame body.
*/
pdu(const_bit_vector& frame_body);
pdu(const_bit_queue& frame_body);
/**
* pdu (virtual) destructor.
*/
virtual ~pdu();
/**
* Returns a string describing the Data Unit ID (DUID).
*/
std::string duid_str() const;
protected:
/**

View File

@ -3,48 +3,47 @@
#include <bitset>
#include <itpp/base/vec.h>
#include <stdexcept>
#include <vector>
typedef std::vector<bool> bit_vector;
typedef const std::vector<bool> const_bit_vector;
/**
* Swab bits from in[begin, end) to out[where,...).
* Swab in[bits[0..nof_bits)) to out[where..where+nof_bits).
*
* \param in A uint64_t representing a set of bits.
* \param begin The offset of the first bit to copy.
* \param end The offset of the end bit (this bit is not copied).
* \param out The bit_vector into which bits are copied.
* \param where The starting point for writing bits.
* \param in A const reference to the source.
* \param bits An array specifying the ordinals of the bits to copy.
* \param bits_sz The size of the bits array.
* \param out A reference to the destination.
* \param where The offset of the first bit to write.
*/
inline void
swab(uint64_t in, int begin, int end, bit_vector& out, int where)
template <class X, class Y>
void swab(const X& in, const size_t bits[], size_t bits_sz, Y& out, size_t where)
{
for(int i = begin; i != end; (begin < end ? ++i : --i)) {
out[where++] = (in & (1 << i) ? 1 : 0);
for(size_t i = 0; i < bits_sz; ++i) {
out[where+i] = in[bits[i]];
}
}
/**
* Swab bits from in[begin, end) to out[where,...).
* Swab from in[0..nof_bits) to out[bits[0..nof_bits)).
*
* \param in A const_bit_vector reference to the source.
* \param begin The offset of the first bit to copy.
* \param end The offset of the end bit (this bit is not copied).
* \param out A bvec into which bits are copied.
* \param where The starting point for writing bits.
* \param in A const bvec reference to the source.
* \param where The offset of the first bit to read.
* \param out A bit_vector reference to the destination.
* \param bits An array specifying the ordinals of the bits to copy.
* \param bits_sz The size of the bits array.
*/
inline void
swab(const_bit_vector& in, int begin, int end, itpp::bvec& out, int where)
template <class X, class Y>
void unswab(const X& in, size_t where, Y& out, const size_t bits[], size_t bits_sz)
{
for(int i = begin; i != end; (begin < end ? ++i : --i)) {
out[where++] = in[i];
for(size_t i = 0; i < bits_sz; ++i) {
out[bits[i]] = in[where+i];
}
}
/**
* Swabs a bit_vector in[begin,end) to an octet buffer.
* Extract a bit_vector in[begin,end) to an octet buffer.
*
* \param in A const reference to the bit_vector.
* \param begin The offset of the first bit to copy.
@ -52,52 +51,16 @@ swab(const_bit_vector& in, int begin, int end, itpp::bvec& out, int where)
* \param out Address of the octet buffer to write into.
* \return The number of octers written.
*/
inline size_t
swab(const_bit_vector& in, int begin, int end, uint8_t *out)
template<class X>
size_t extract(const X& in, int begin, int end, uint8_t *out)
{
const size_t out_sz = (7 + abs(end - begin)) / 8;
memset(out, 0, out_sz);
for(int i = begin, j = 0; i != end; (begin < end ? ++i : --i), ++j) {
for(int i = begin, j = 0; i < end; ++i, ++j) {
out[j / 8] ^= in[i] << (7 - (j % 8));
}
return out_sz;
}
/**
* Swabs a bitset<N> in[begin,end) to an octet buffer.
*
* \param in A const reference to the bitset.
* \param begin The offset of the first bit to copy.
* \param end The offset of the end bit (this bit is not copied).
* \param out Address of the octet buffer to write into.
* \return The number of octers written.
*/
template <size_t N> size_t
swab(const std::bitset<N>& in, int begin, int end, uint8_t *out)
{
const size_t out_sz = (7 + abs(end - begin)) / 8;
memset(out, 0, out_sz);
for(int i = begin, j = 0; i != end; (begin < end ? ++i : --i), ++j) {
out[j / 8] ^= in[i] << (7 - (j % 8));
}
return out_sz;
}
/**
* Swab bits from bvec in[where] in to out[begin,end).
*
* \param in A const reference to the bvec.
* \param begin The offset of the first bit to copy.
* \param end The offset of the end bit.
* \param out A bvec into which bits are written.
* \param where The starting point for writing bits.
*/
inline void
unswab(const itpp::bvec& in, int where, bit_vector& out, int begin, int end)
{
for(int i = begin; i != end; (begin < end ? ++i : --i)) {
out[i] = in[where++];
}
}
/**
* Extract value of bits from in[begin,end).
@ -107,11 +70,11 @@ unswab(const itpp::bvec& in, int where, bit_vector& out, int begin, int end)
* \param end The offset of the end bit.
* \return A uint64_t containing the value
*/
inline uint64_t
extract(const_bit_vector& in, int begin, int end)
template<class X>
uint64_t extract(const X& in, int begin, int end)
{
uint64_t x = 0LL;
for(int i = begin; i != end; (begin < end ? ++i : --i)) {
for(int i = begin; i < end; ++i) {
x = (x << 1) | (in[i] ? 1 : 0);
}
return x;

View File

@ -27,7 +27,9 @@
#include <swab.h>
#include <tdu.h>
tdu::tdu(const_bit_vector& frame_body, bool has_link_control) :
using std::string;
tdu::tdu(const_bit_queue& frame_body, bool has_link_control) :
abstract_data_unit(frame_body),
d_has_link_control(has_link_control)
{
@ -37,6 +39,12 @@ tdu::~tdu()
{
}
string
tdu::duid_str() const
{
return string("TDU");
}
void
tdu::correct_errors(bit_vector& frame)
{

View File

@ -36,16 +36,21 @@ public:
/**
* tdu constructor.
*
* \param frame_body A const_bit_vector representing the frame body.
* \param frame_body A const_bit_queue representing the frame body.
* \param has_link_control true if frame has link control data, otherwise false.
*/
tdu(const_bit_vector& frame_body, bool has_link_control);
tdu(const_bit_queue& frame_body, bool has_link_control);
/**
* tdu constructor.
*/
virtual ~tdu();
/**
* Returns a string describing the Data Unit ID (DUID).
*/
std::string duid_str() const;
protected:
/**

View File

@ -25,6 +25,7 @@
#include <cerrno>
#include <sstream>
#include <fcntl.h>
#include <stdexcept>
#include <stdint.h>
#include <swab.h>
#include <sys/types.h>
@ -74,8 +75,7 @@ vc55_imbe_decoder::decode(voice_codeword& in_out, audio_output& out)
uint8_t packet[20];
packet[0] = 0x56;
packet[1] = 0xf0;
swab(in_out, 0, 144, &packet[2]);
/* ToDo: extract(in_out, 0, 144, &packet[2]); */
if(-1 == write(d_fd, packet, sizeof(packet))) {
perror("write(d_fd, packet, sizeof(packet))");
close(d_fd);

View File

@ -39,7 +39,8 @@ class qa_op25(gr_unittest.TestCase):
def test_constructor(self):
framing_sequence = (3, 3, 3, 3, 3, -3, 3, 3, -3, -3, 3, 3, -3, -3, -3, -3, 3, -3, 3, -3, -3, -3, -3, -3)
src = gr.vector_source_f(framing_sequence, False)
p25 = op25.decoder_ff()
msgq = gr.msg_queue()
p25 = op25.decoder_ff(msgq)
self.fg.connect(src, p25)
# ToDo: add test cases!

View File

@ -186,6 +186,12 @@ class p25_rx_block (stdgui2.std_top_block):
toolbar_new = self.toolbar.AddSimpleTool(wx.ID_NEW, new_icon, u"New Capture")
open_icon = wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, wx.ART_TOOLBAR, icon_size)
toolbar_open = self.toolbar.AddSimpleTool(wx.ID_OPEN, open_icon, u"Open")
#
# self.toolbar.AddSeparator()
# self.gain_control = wx.Slider(self.toolbar, 100, 50, 1, 100, style=wx.SL_HORIZONTAL)
# slider.SetTickFreq(5, 1)
# self.toolbar.AddControl(self.gain_control)
#
self.toolbar.Realize()
else:
self.toolbar = None
@ -210,8 +216,10 @@ class p25_rx_block (stdgui2.std_top_block):
# Traffic snapshot
self.traffic = TrafficPane(self.notebook)
self.notebook.AddPage(self.traffic, "Traffic")
# The P25 decoder
self.p25_decoder = op25.decoder_ff()
# Setup the decoder and report the TUN/TAP device name
msgq = gr.msg_queue(2)
self.decode_watcher = decode_watcher(msgq, self.traffic)
self.p25_decoder = op25.decoder_ff(msgq)
self.frame.SetStatusText("TUN/TAP: " + self.p25_decoder.device_name())
# read capture file properties (decimation etc.)
@ -283,6 +291,7 @@ class p25_rx_block (stdgui2.std_top_block):
self.spectrum_plotter.Clear()
self.signal_plotter.Clear()
self.symbol_plotter.Clear()
self.traffic.clear()
elif "RUNNING" == self.state:
# menu items
self.file_new.Enable(False)
@ -362,7 +371,7 @@ class p25_rx_block (stdgui2.std_top_block):
self.stop()
self.wait()
# ToDo: get open_usrp() arguments from wizard
self.open_usrp((1,0), 128, None, 468.0e06, True)
self.open_usrp((0,0), 256, None, 434.08e06, True)
self.start()
# Open an existing capture
@ -460,33 +469,33 @@ class TrafficPane(wx.Panel):
label = wx.StaticText(self, -1, "DUID:")
sizer.Add(label, pos=(1,1))
field = wx.TextCtrl(self, -1, "", size=(175, -1), style=wx.TE_READONLY)
field = wx.TextCtrl(self, -1, "", size=(72, -1), style=wx.TE_READONLY)
sizer.Add(field, pos=(1,2))
self.fields["duid"] = field;
label = wx.StaticText(self, -1, "Source:")
label = wx.StaticText(self, -1, "NAC:")
sizer.Add(label, pos=(2,1))
field = wx.TextCtrl(self, -1, "", size=(175, -1), style=wx.TE_READONLY)
sizer.Add(field, pos=(2,2))
self.fields["source"] = field;
self.fields["nac"] = field;
label = wx.StaticText(self, -1, "Destination:")
label = wx.StaticText(self, -1, "Source:")
sizer.Add(label, pos=(3,1))
field = wx.TextCtrl(self, -1, "", size=(175, -1), style=wx.TE_READONLY)
sizer.Add(field, pos=(3,2))
self.fields["dest"] = field;
self.fields["source"] = field;
label = wx.StaticText(self, -1, "NID:")
label = wx.StaticText(self, -1, "Destination:")
sizer.Add(label, pos=(4,1))
field = wx.TextCtrl(self, -1, "", size=(175, -1), style=wx.TE_READONLY)
sizer.Add(field, pos=(4,2))
self.fields["nid"] = field;
self.fields["dest"] = field;
label = wx.StaticText(self, -1, "NAC:")
label = wx.StaticText(self, -1, "NID:")
sizer.Add(label, pos=(5,1))
field = wx.TextCtrl(self, -1, "", size=(175, -1), style=wx.TE_READONLY)
sizer.Add(field, pos=(5,2))
self.fields["nac"] = field;
self.fields["nid"] = field;
label = wx.StaticText(self, -1, "MFID:")
sizer.Add(label, pos=(1,4))
@ -502,19 +511,19 @@ class TrafficPane(wx.Panel):
label = wx.StaticText(self, -1, "KID:")
sizer.Add(label, pos=(3,4))
field = wx.TextCtrl(self, -1, "", size=(175, -1), style=wx.TE_READONLY)
field = wx.TextCtrl(self, -1, "", size=(72, -1), style=wx.TE_READONLY)
sizer.Add(field, pos=(3,5))
self.fields["kid"] = field;
label = wx.StaticText(self, -1, "MI:")
sizer.Add(label, pos=(4,4))
field = wx.TextCtrl(self, -1, "", size=(175, -1), style=wx.TE_READONLY)
field = wx.TextCtrl(self, -1, "", size=(216, -1), style=wx.TE_READONLY)
sizer.Add(field, pos=(4,5))
self.fields["mi"] = field;
label = wx.StaticText(self, -1, "TGID:")
sizer.Add(label, pos=(5,4))
field = wx.TextCtrl(self, -1, "", size=(175, -1), style=wx.TE_READONLY)
field = wx.TextCtrl(self, -1, "", size=(72, -1), style=wx.TE_READONLY)
sizer.Add(field, pos=(5,5))
self.fields["tgid"] = field;
@ -603,7 +612,7 @@ class demod_watcher(threading.Thread):
#
class decode_watcher(threading.Thread):
def __init__(self, msgq, traffic_pane, **kwds):
def __init__(self, msgq, traffic_pane, **kwds):
threading.Thread.__init__ (self, **kwds)
self.setDaemon(1)
self.msgq = msgq
@ -614,8 +623,9 @@ class decode_watcher(threading.Thread):
def run(self):
while(self.keep_running):
msg = self.msgq.delete_head()
# pickle_dict = msg.arg1()
self.callback(frequency_correction)
pickled_dict = msg.to_string()
attrs = pickle.loads(pickled_dict)
self.traffic_pane.update(attrs)
# Start the receiver

View File

@ -2,8 +2,14 @@
S'capture-rate'
p1
I250000
sS'capture-dev'
sS'source-decim'
p2
S'USRP1'
I256
sS'source-dev'
p3
S'USRP'
p4
sS'center-freq'
p5
F434075000.0
s.