13 changed files with 798 additions and 360 deletions
@ -0,0 +1,45 @@ |
|||||||
|
<?xml version="1.0"?> |
||||||
|
<block> |
||||||
|
<name>RDS Decoder (cr)</name> |
||||||
|
<key>crfa_rds_decoder</key> |
||||||
|
<category>[crfa]</category> |
||||||
|
<import>import crfa</import> |
||||||
|
<make>crfa.rds_decoder($log, $debug)</make> |
||||||
|
<param> |
||||||
|
<name>Log</name> |
||||||
|
<key>log</key> |
||||||
|
<value>False</value> |
||||||
|
<type>bool</type> |
||||||
|
<option> |
||||||
|
<name>Enable</name> |
||||||
|
<key>True</key> |
||||||
|
</option> |
||||||
|
<option> |
||||||
|
<name>Disable</name> |
||||||
|
<key>False</key> |
||||||
|
</option> |
||||||
|
</param> |
||||||
|
<param> |
||||||
|
<name>Debug</name> |
||||||
|
<key>debug</key> |
||||||
|
<value>False</value> |
||||||
|
<type>bool</type> |
||||||
|
<option> |
||||||
|
<name>Enable</name> |
||||||
|
<key>True</key> |
||||||
|
</option> |
||||||
|
<option> |
||||||
|
<name>Disable</name> |
||||||
|
<key>False</key> |
||||||
|
</option> |
||||||
|
</param> |
||||||
|
<sink> |
||||||
|
<name>in</name> |
||||||
|
<type>byte</type> |
||||||
|
</sink> |
||||||
|
<source> |
||||||
|
<name>out</name> |
||||||
|
<type>message</type> |
||||||
|
<optional>1</optional> |
||||||
|
</source> |
||||||
|
</block> |
||||||
@ -0,0 +1,45 @@ |
|||||||
|
<?xml version="1.0"?> |
||||||
|
<block> |
||||||
|
<name>RDS Decoder (cr)</name> |
||||||
|
<key>gr_rds_decoder_cr</key> |
||||||
|
<category>[RDS]</category> |
||||||
|
<import>import rds</import> |
||||||
|
<make>rds.decoder($log, $debug)</make> |
||||||
|
<param> |
||||||
|
<name>Log</name> |
||||||
|
<key>log</key> |
||||||
|
<value>False</value> |
||||||
|
<type>bool</type> |
||||||
|
<option> |
||||||
|
<name>Enable</name> |
||||||
|
<key>True</key> |
||||||
|
</option> |
||||||
|
<option> |
||||||
|
<name>Disable</name> |
||||||
|
<key>False</key> |
||||||
|
</option> |
||||||
|
</param> |
||||||
|
<param> |
||||||
|
<name>Debug</name> |
||||||
|
<key>debug</key> |
||||||
|
<value>False</value> |
||||||
|
<type>bool</type> |
||||||
|
<option> |
||||||
|
<name>Enable</name> |
||||||
|
<key>True</key> |
||||||
|
</option> |
||||||
|
<option> |
||||||
|
<name>Disable</name> |
||||||
|
<key>False</key> |
||||||
|
</option> |
||||||
|
</param> |
||||||
|
<sink> |
||||||
|
<name>in</name> |
||||||
|
<type>byte</type> |
||||||
|
</sink> |
||||||
|
<source> |
||||||
|
<name>out</name> |
||||||
|
<type>message</type> |
||||||
|
<optional>1</optional> |
||||||
|
</source> |
||||||
|
</block> |
||||||
@ -0,0 +1,56 @@ |
|||||||
|
/* -*- c++ -*- */ |
||||||
|
/*
|
||||||
|
* Copyright 2016 <+YOU OR YOUR COMPANY+>. |
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU General Public License as published by |
||||||
|
* the Free Software Foundation; either version 3, or (at your option) |
||||||
|
* any later version. |
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this software; see the file COPYING. If not, write to |
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street, |
||||||
|
* Boston, MA 02110-1301, USA. |
||||||
|
*/ |
||||||
|
|
||||||
|
|
||||||
|
#ifndef INCLUDED_CRFA_RDS_DECODER_H |
||||||
|
#define INCLUDED_CRFA_RDS_DECODER_H |
||||||
|
|
||||||
|
#include <crfa/api.h> |
||||||
|
#include <gnuradio/sync_block.h> |
||||||
|
|
||||||
|
namespace gr { |
||||||
|
namespace crfa { |
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief <+description of block+> |
||||||
|
* \ingroup crfa |
||||||
|
* |
||||||
|
*/ |
||||||
|
class CRFA_API rds_decoder : virtual public gr::sync_block |
||||||
|
{ |
||||||
|
public: |
||||||
|
typedef boost::shared_ptr<rds_decoder> sptr; |
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Return a shared_ptr to a new instance of crfa::rds_decoder. |
||||||
|
* |
||||||
|
* To avoid accidental use of raw pointers, crfa::rds_decoder's |
||||||
|
* constructor is in a private implementation |
||||||
|
* class. crfa::rds_decoder::make is the public interface for |
||||||
|
* creating new instances. |
||||||
|
*/ |
||||||
|
static sptr make(bool log, bool debug); |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace crfa
|
||||||
|
} // namespace gr
|
||||||
|
|
||||||
|
#endif /* INCLUDED_CRFA_RDS_DECODER_H */ |
||||||
|
|
||||||
@ -0,0 +1,201 @@ |
|||||||
|
/*
|
||||||
|
* Copyright 2004 Free Software Foundation, Inc. |
||||||
|
* |
||||||
|
* This file is part of GNU Radio |
||||||
|
* |
||||||
|
* GNU Radio is free software; you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU General Public License as published by |
||||||
|
* the Free Software Foundation; either version 2, or (at your option) |
||||||
|
* any later version. |
||||||
|
* |
||||||
|
* GNU Radio is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with GNU Radio; see the file COPYING. If not, write to |
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street, |
||||||
|
* Boston, MA 02110-1301, USA. |
||||||
|
*/ |
||||||
|
|
||||||
|
|
||||||
|
/* see page 59, Annex C, table C.1 in the standard
|
||||||
|
* offset word C' has been put at the end */ |
||||||
|
static const unsigned int offset_pos[5]={0,1,2,3,2}; |
||||||
|
static const unsigned int offset_word[5]={252,408,360,436,848}; |
||||||
|
static const unsigned int syndrome[5]={383,14,303,663,748}; |
||||||
|
static const char * const offset_name[]={"A","B","C","D","C'"}; |
||||||
|
|
||||||
|
/* Annex F of RBDS Standard Table F.1 (North America) and
|
||||||
|
* Table F.2 (Europe) */ |
||||||
|
const std::string pty_table[32][2]={ |
||||||
|
{"Undefined", "Undefined"}, |
||||||
|
{"News", "News"}, |
||||||
|
{"Current Affairs", "Information"}, |
||||||
|
{"Information", "Sports"}, |
||||||
|
{"Sport", "Talk"}, |
||||||
|
{"Education", "Rock"}, |
||||||
|
{"Drama", "Classic Rock"}, |
||||||
|
{"Culture", "Adult Hits"}, |
||||||
|
{"Science", "Soft Rock"}, |
||||||
|
{"Varied", "Top 40"}, |
||||||
|
{"Pop Music", "Country"}, |
||||||
|
{"Rock Music", "Oldies"}, |
||||||
|
{"Easy Listening", "Soft"}, |
||||||
|
{"Light Classical", "Nostalgia"}, |
||||||
|
{"Serious Classical", "Jazz"}, |
||||||
|
{"Other Music", "Classical"}, |
||||||
|
{"Weather", "Rhythm & Blues"}, |
||||||
|
{"Finance", "Soft Rhythm & Blues"}, |
||||||
|
{"Children’s Programmes", "Language"}, |
||||||
|
{"Social Affairs", "Religious Music"}, |
||||||
|
{"Religion", "Religious Talk"}, |
||||||
|
{"Phone-In", "Personality"}, |
||||||
|
{"Travel", "Public"}, |
||||||
|
{"Leisure", "College"}, |
||||||
|
{"Jazz Music", "Spanish Talk"}, |
||||||
|
{"Country Music", "Spanish Music"}, |
||||||
|
{"National Music", "Hip Hop"}, |
||||||
|
{"Oldies Music", "Unassigned"}, |
||||||
|
{"Folk Music", "Unassigned"}, |
||||||
|
{"Documentary", "Weather"}, |
||||||
|
{"Alarm Test", "Emergency Test"}, |
||||||
|
{"Alarm", "Emergency"}}; |
||||||
|
|
||||||
|
/* page 71, Annex D, table D.1 in the standard */ |
||||||
|
const std::string pi_country_codes[15][5]={ |
||||||
|
{"DE","GR","MA","__","MD"}, |
||||||
|
{"DZ","CY","CZ","IE","EE"}, |
||||||
|
{"AD","SM","PL","TR","__"}, |
||||||
|
{"IL","CH","VA","MK","__"}, |
||||||
|
{"IT","JO","SK","__","__"}, |
||||||
|
{"BE","FI","SY","__","UA"}, |
||||||
|
{"RU","LU","TN","__","__"}, |
||||||
|
{"PS","BG","__","NL","PT"}, |
||||||
|
{"AL","DK","LI","LV","SI"}, |
||||||
|
{"AT","GI","IS","LB","__"}, |
||||||
|
{"HU","IQ","MC","__","__"}, |
||||||
|
{"MT","GB","LT","HR","__"}, |
||||||
|
{"DE","LY","YU","__","__"}, |
||||||
|
{"__","RO","ES","SE","__"}, |
||||||
|
{"EG","FR","NO","BY","BA"}}; |
||||||
|
|
||||||
|
/* page 72, Annex D, table D.2 in the standard */ |
||||||
|
const std::string coverage_area_codes[16]={ |
||||||
|
"Local", |
||||||
|
"International", |
||||||
|
"National", |
||||||
|
"Supra-regional", |
||||||
|
"Regional 1", |
||||||
|
"Regional 2", |
||||||
|
"Regional 3", |
||||||
|
"Regional 4", |
||||||
|
"Regional 5", |
||||||
|
"Regional 6", |
||||||
|
"Regional 7", |
||||||
|
"Regional 8", |
||||||
|
"Regional 9", |
||||||
|
"Regional 10", |
||||||
|
"Regional 11", |
||||||
|
"Regional 12"}; |
||||||
|
|
||||||
|
const std::string rds_group_acronyms[16]={ |
||||||
|
"BASIC", |
||||||
|
"PIN/SL", |
||||||
|
"RT", |
||||||
|
"AID", |
||||||
|
"CT", |
||||||
|
"TDC", |
||||||
|
"IH", |
||||||
|
"RP", |
||||||
|
"TMC", |
||||||
|
"EWS", |
||||||
|
"___", |
||||||
|
"___", |
||||||
|
"___", |
||||||
|
"___", |
||||||
|
"EON", |
||||||
|
"___"}; |
||||||
|
|
||||||
|
/* page 74, Annex E, table E.1 in the standard: that's the ASCII table!!! */ |
||||||
|
|
||||||
|
/* see page 84, Annex J in the standard */ |
||||||
|
const std::string language_codes[44]={ |
||||||
|
"Unkown/not applicable", |
||||||
|
"Albanian", |
||||||
|
"Breton", |
||||||
|
"Catalan", |
||||||
|
"Croatian", |
||||||
|
"Welsh", |
||||||
|
"Czech", |
||||||
|
"Danish", |
||||||
|
"German", |
||||||
|
"English", |
||||||
|
"Spanish", |
||||||
|
"Esperanto", |
||||||
|
"Estonian", |
||||||
|
"Basque", |
||||||
|
"Faroese", |
||||||
|
"French", |
||||||
|
"Frisian", |
||||||
|
"Irish", |
||||||
|
"Gaelic", |
||||||
|
"Galician", |
||||||
|
"Icelandic", |
||||||
|
"Italian", |
||||||
|
"Lappish", |
||||||
|
"Latin", |
||||||
|
"Latvian", |
||||||
|
"Luxembourgian", |
||||||
|
"Lithuanian", |
||||||
|
"Hungarian", |
||||||
|
"Maltese", |
||||||
|
"Dutch", |
||||||
|
"Norwegian", |
||||||
|
"Occitan", |
||||||
|
"Polish", |
||||||
|
"Portuguese", |
||||||
|
"Romanian", |
||||||
|
"Romansh", |
||||||
|
"Serbian", |
||||||
|
"Slovak", |
||||||
|
"Slovene", |
||||||
|
"Finnish", |
||||||
|
"Swedish", |
||||||
|
"Turkish", |
||||||
|
"Flemish", |
||||||
|
"Walloon"}; |
||||||
|
|
||||||
|
/* see page 12 in ISO 14819-1 */ |
||||||
|
const std::string tmc_duration[8][2]={ |
||||||
|
{"no duration given", "no duration given"}, |
||||||
|
{"15 minutes", "next few hours"}, |
||||||
|
{"30 minutes", "rest of the day"}, |
||||||
|
{"1 hour", "until tomorrow evening"}, |
||||||
|
{"2 hours", "rest of the week"}, |
||||||
|
{"3 hours", "end of next week"}, |
||||||
|
{"4 hours", "end of the month"}, |
||||||
|
{"rest of the day", "long period"}}; |
||||||
|
|
||||||
|
/* optional message content, data field lengths and labels
|
||||||
|
* see page 15 in ISO 14819-1 */ |
||||||
|
const int optional_content_lengths[16]={3,3,5,5,5,8,8,8,8,11,16,16,16,16,0,0}; |
||||||
|
|
||||||
|
const std::string label_descriptions[16]={ |
||||||
|
"Duration", |
||||||
|
"Control code", |
||||||
|
"Length of route affected", |
||||||
|
"Speed limit advice", |
||||||
|
"Quantifier", |
||||||
|
"Quantifier", |
||||||
|
"Supplementary information code", |
||||||
|
"Explicit start time", |
||||||
|
"Explicit stop time", |
||||||
|
"Additional event", |
||||||
|
"Detailed diversion instructions", |
||||||
|
"Destination", |
||||||
|
"RFU (Reserved for future use)", |
||||||
|
"Cross linkage to source of problem, or another route", |
||||||
|
"Separator", |
||||||
|
"RFU (Reserved for future use)"}; |
||||||
@ -0,0 +1,256 @@ |
|||||||
|
/* -*- c++ -*- */ |
||||||
|
/*
|
||||||
|
* Copyright 2016 <+YOU OR YOUR COMPANY+>. |
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU General Public License as published by |
||||||
|
* the Free Software Foundation; either version 3, or (at your option) |
||||||
|
* any later version. |
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this software; see the file COPYING. If not, write to |
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street, |
||||||
|
* Boston, MA 02110-1301, USA. |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H |
||||||
|
#include "config.h" |
||||||
|
#endif |
||||||
|
|
||||||
|
#define dout debug && std::cout |
||||||
|
#define lout log && std::cout |
||||||
|
|
||||||
|
#include <gnuradio/io_signature.h> |
||||||
|
#include "constants.h" |
||||||
|
#include "rds_decoder_impl.h" |
||||||
|
|
||||||
|
namespace gr { |
||||||
|
namespace crfa { |
||||||
|
|
||||||
|
rds_decoder::sptr |
||||||
|
rds_decoder::make(bool log, bool debug) |
||||||
|
{ |
||||||
|
return gnuradio::get_initial_sptr |
||||||
|
(new rds_decoder_impl(log, debug)); |
||||||
|
} |
||||||
|
|
||||||
|
/*
|
||||||
|
* The private constructor |
||||||
|
*/ |
||||||
|
rds_decoder_impl::rds_decoder_impl(bool log, bool debug) |
||||||
|
: gr::sync_block("rds_decoder", |
||||||
|
gr::io_signature::make (1, 1, sizeof(char)), |
||||||
|
gr::io_signature::make (0, 0, 0)), |
||||||
|
log(log), |
||||||
|
debug(debug) |
||||||
|
{ |
||||||
|
set_output_multiple(104); // 1 RDS datagroup = 104 bits
|
||||||
|
message_port_register_out(pmt::mp("out")); |
||||||
|
enter_no_sync(); |
||||||
|
} |
||||||
|
|
||||||
|
/*
|
||||||
|
* Our virtual destructor. |
||||||
|
*/ |
||||||
|
rds_decoder_impl::~rds_decoder_impl() |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
////////////////////////// HELPER FUNTIONS /////////////////////////
|
||||||
|
|
||||||
|
void rds_decoder_impl::enter_no_sync() { |
||||||
|
presync = false; |
||||||
|
d_state = NO_SYNC; |
||||||
|
} |
||||||
|
|
||||||
|
void rds_decoder_impl::enter_sync(unsigned int sync_block_number) { |
||||||
|
last_wrong_blocks_counter = 0; |
||||||
|
wrong_blocks_counter = 0; |
||||||
|
blocks_counter = 0; |
||||||
|
block_bit_counter = 0; |
||||||
|
block_number = (sync_block_number + 1) % 4; |
||||||
|
group_assembly_started = false; |
||||||
|
d_state = SYNC; |
||||||
|
} |
||||||
|
|
||||||
|
/* see Annex B, page 64 of the standard */ |
||||||
|
unsigned int rds_decoder_impl::calc_syndrome(unsigned long message, |
||||||
|
unsigned char mlen) { |
||||||
|
unsigned long reg = 0; |
||||||
|
unsigned int i; |
||||||
|
const unsigned long poly = 0x5B9; |
||||||
|
const unsigned char plen = 10; |
||||||
|
|
||||||
|
for (i = mlen; i > 0; i--) { |
||||||
|
reg = (reg << 1) | ((message >> (i-1)) & 0x01); |
||||||
|
if (reg & (1 << plen)) reg = reg ^ poly; |
||||||
|
} |
||||||
|
for (i = plen; i > 0; i--) { |
||||||
|
reg = reg << 1; |
||||||
|
if (reg & (1<<plen)) reg = reg ^ poly; |
||||||
|
} |
||||||
|
return (reg & ((1<<plen)-1)); // select the bottom plen bits of reg
|
||||||
|
} |
||||||
|
|
||||||
|
void rds_decoder_impl::decode_group(unsigned int *group) { |
||||||
|
// raw data bytes, as received from RDS.
|
||||||
|
// 8 info bytes, followed by 4 RDS offset chars: ABCD/ABcD/EEEE (in US)
|
||||||
|
unsigned char bytes[12]; |
||||||
|
|
||||||
|
// RDS information words
|
||||||
|
bytes[0] = (group[0] >> 8U) & 0xffU; |
||||||
|
bytes[1] = (group[0] ) & 0xffU; |
||||||
|
bytes[2] = (group[1] >> 8U) & 0xffU; |
||||||
|
bytes[3] = (group[1] ) & 0xffU; |
||||||
|
bytes[4] = (group[2] >> 8U) & 0xffU; |
||||||
|
bytes[5] = (group[2] ) & 0xffU; |
||||||
|
bytes[6] = (group[3] >> 8U) & 0xffU; |
||||||
|
bytes[7] = (group[3] ) & 0xffU; |
||||||
|
|
||||||
|
// RDS offset words
|
||||||
|
bytes[8] = offset_chars[0]; |
||||||
|
bytes[9] = offset_chars[1]; |
||||||
|
bytes[10] = offset_chars[2]; |
||||||
|
bytes[11] = offset_chars[3]; |
||||||
|
bytes[12]=last_wrong_blocks_counter; |
||||||
|
pmt::pmt_t data(pmt::make_blob(bytes, 13)); |
||||||
|
pmt::pmt_t meta(pmt::PMT_NIL); |
||||||
|
|
||||||
|
pmt::pmt_t pdu(pmt::cons(meta, data)); // make PDU: (metadata, data) pair
|
||||||
|
message_port_pub(pmt::mp("out"), pdu); |
||||||
|
} |
||||||
|
//work function
|
||||||
|
int rds_decoder_impl::work (int noutput_items, |
||||||
|
gr_vector_const_void_star &input_items, |
||||||
|
gr_vector_void_star &output_items) |
||||||
|
{ |
||||||
|
const bool *in = (const bool *) input_items[0]; |
||||||
|
|
||||||
|
dout << "RDS data decoder at work: input_items = " |
||||||
|
<< noutput_items << ", /104 = " |
||||||
|
<< noutput_items / 104 << std::endl; |
||||||
|
|
||||||
|
int i=0,j; |
||||||
|
unsigned long bit_distance, block_distance; |
||||||
|
unsigned int block_calculated_crc, block_received_crc, checkword,dataword; |
||||||
|
unsigned int reg_syndrome; |
||||||
|
unsigned char offset_char('x'); // x = error while decoding the word offset
|
||||||
|
|
||||||
|
/* the synchronization process is described in Annex C, page 66 of the standard */ |
||||||
|
while (i<noutput_items) { |
||||||
|
reg=(reg<<1)|in[i]; // reg contains the last 26 rds bits
|
||||||
|
switch (d_state) { |
||||||
|
case NO_SYNC: |
||||||
|
reg_syndrome = calc_syndrome(reg,26); |
||||||
|
for (j=0;j<5;j++) { |
||||||
|
if (reg_syndrome==syndrome[j]) { |
||||||
|
if (!presync) { |
||||||
|
lastseen_offset=j; |
||||||
|
lastseen_offset_counter=bit_counter; |
||||||
|
presync=true; |
||||||
|
} |
||||||
|
else { |
||||||
|
bit_distance=bit_counter-lastseen_offset_counter; |
||||||
|
if (offset_pos[lastseen_offset]>=offset_pos[j])
|
||||||
|
block_distance=offset_pos[j]+4-offset_pos[lastseen_offset]; |
||||||
|
else |
||||||
|
block_distance=offset_pos[j]-offset_pos[lastseen_offset]; |
||||||
|
if ((block_distance*26)!=bit_distance) presync=false; |
||||||
|
else { |
||||||
|
lout << "@@@@@ Sync State Detected" << std::endl; |
||||||
|
enter_sync(j); |
||||||
|
} |
||||||
|
} |
||||||
|
break; //syndrome found, no more cycles
|
||||||
|
} |
||||||
|
} |
||||||
|
break; |
||||||
|
case SYNC: |
||||||
|
/* wait until 26 bits enter the buffer */ |
||||||
|
if (block_bit_counter<25) block_bit_counter++; |
||||||
|
else { |
||||||
|
good_block=false; |
||||||
|
dataword=(reg>>10) & 0xffff; |
||||||
|
block_calculated_crc=calc_syndrome(dataword,16); |
||||||
|
checkword=reg & 0x3ff; |
||||||
|
/* manage special case of C or C' offset word */ |
||||||
|
if (block_number==2) { |
||||||
|
block_received_crc=checkword^offset_word[block_number]; |
||||||
|
if (block_received_crc==block_calculated_crc) { |
||||||
|
good_block=true; |
||||||
|
offset_char = 'C'; |
||||||
|
} else { |
||||||
|
block_received_crc=checkword^offset_word[4]; |
||||||
|
if (block_received_crc==block_calculated_crc) { |
||||||
|
good_block=true; |
||||||
|
offset_char = 'c'; // C' (C-Tag)
|
||||||
|
} else { |
||||||
|
wrong_blocks_counter++; |
||||||
|
good_block=false; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
else { |
||||||
|
block_received_crc=checkword^offset_word[block_number]; |
||||||
|
if (block_received_crc==block_calculated_crc) { |
||||||
|
good_block=true; |
||||||
|
if (block_number==0) offset_char = 'A'; |
||||||
|
else if (block_number==1) offset_char = 'B'; |
||||||
|
else if (block_number==3) offset_char = 'D'; |
||||||
|
} else { |
||||||
|
wrong_blocks_counter++; |
||||||
|
good_block=false; |
||||||
|
} |
||||||
|
} |
||||||
|
/* done checking CRC */ |
||||||
|
if (block_number==0 && good_block) { |
||||||
|
group_assembly_started=true; |
||||||
|
group_good_blocks_counter=1; |
||||||
|
} |
||||||
|
if (group_assembly_started) { |
||||||
|
if (!good_block) group_assembly_started=false; |
||||||
|
else { |
||||||
|
group[block_number]=dataword; |
||||||
|
offset_chars[block_number] = offset_char; |
||||||
|
group_good_blocks_counter++; |
||||||
|
} |
||||||
|
if (group_good_blocks_counter==5) decode_group(group); |
||||||
|
} |
||||||
|
block_bit_counter=0; |
||||||
|
block_number=(block_number+1) % 4; |
||||||
|
blocks_counter++; |
||||||
|
/* 1187.5 bps / 104 bits = 11.4 groups/sec, or 45.7 blocks/sec */ |
||||||
|
if (blocks_counter==50) { |
||||||
|
last_wrong_blocks_counter=wrong_blocks_counter; |
||||||
|
if (wrong_blocks_counter>35) { |
||||||
|
lout << "@@@@@ Lost Sync (Got " << wrong_blocks_counter |
||||||
|
<< " bad blocks on " << blocks_counter |
||||||
|
<< " total)" << std::endl; |
||||||
|
enter_no_sync(); |
||||||
|
} else { |
||||||
|
lout << "@@@@@ Still Sync-ed (Got " << wrong_blocks_counter |
||||||
|
<< " bad blocks on " << blocks_counter |
||||||
|
<< " total)" << std::endl; |
||||||
|
} |
||||||
|
blocks_counter=0; |
||||||
|
wrong_blocks_counter=0; |
||||||
|
} |
||||||
|
} |
||||||
|
break; |
||||||
|
default: |
||||||
|
d_state=NO_SYNC; |
||||||
|
break; |
||||||
|
} |
||||||
|
i++; |
||||||
|
bit_counter++; |
||||||
|
} |
||||||
|
return noutput_items; |
||||||
|
}/*work function*/ |
||||||
|
} /* namespace crfa */ |
||||||
|
} /* namespace gr */ |
||||||
|
|
||||||
@ -0,0 +1,70 @@ |
|||||||
|
/* -*- c++ -*- */ |
||||||
|
/*
|
||||||
|
* Copyright 2016 <+YOU OR YOUR COMPANY+>. |
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU General Public License as published by |
||||||
|
* the Free Software Foundation; either version 3, or (at your option) |
||||||
|
* any later version. |
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this software; see the file COPYING. If not, write to |
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street, |
||||||
|
* Boston, MA 02110-1301, USA. |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef INCLUDED_CRFA_RDS_DECODER_IMPL_H |
||||||
|
#define INCLUDED_CRFA_RDS_DECODER_IMPL_H |
||||||
|
|
||||||
|
#include <crfa/rds_decoder.h> |
||||||
|
|
||||||
|
namespace gr { |
||||||
|
namespace crfa { |
||||||
|
|
||||||
|
class rds_decoder_impl : public rds_decoder |
||||||
|
{ |
||||||
|
public: |
||||||
|
rds_decoder_impl(bool log, bool debug); |
||||||
|
|
||||||
|
private: |
||||||
|
~rds_decoder_impl(); |
||||||
|
|
||||||
|
// Where all the action really happens
|
||||||
|
int work(int noutput_items, |
||||||
|
gr_vector_const_void_star &input_items, |
||||||
|
gr_vector_void_star &output_items); |
||||||
|
void enter_no_sync(); |
||||||
|
void enter_sync(unsigned int); |
||||||
|
unsigned int calc_syndrome(unsigned long, unsigned char); |
||||||
|
void decode_group(unsigned int*); |
||||||
|
|
||||||
|
unsigned long bit_counter; |
||||||
|
unsigned long lastseen_offset_counter, reg; |
||||||
|
unsigned int block_bit_counter; |
||||||
|
unsigned int wrong_blocks_counter; |
||||||
|
unsigned int blocks_counter; |
||||||
|
unsigned int group_good_blocks_counter; |
||||||
|
unsigned int group[4]; |
||||||
|
unsigned char offset_chars[4]; // [ABCcDEx] (x=error)
|
||||||
|
bool debug; |
||||||
|
bool log; |
||||||
|
bool presync; |
||||||
|
bool good_block; |
||||||
|
bool group_assembly_started; |
||||||
|
unsigned char last_wrong_blocks_counter; |
||||||
|
unsigned char lastseen_offset; |
||||||
|
unsigned char block_number; |
||||||
|
enum { NO_SYNC, SYNC } d_state; |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace crfa
|
||||||
|
} // namespace gr
|
||||||
|
|
||||||
|
#endif /* INCLUDED_CRFA_RDS_DECODER_IMPL_H */ |
||||||
|
|
||||||
@ -0,0 +1,38 @@ |
|||||||
|
from PyQt4.QtGui import QGraphicsScene, QApplication, QGraphicsView, QGraphicsEllipseItem |
||||||
|
from PyQt4 import Qt, QtCore, QtGui |
||||||
|
from PyQt4.Qt import QColor |
||||||
|
import sys, random,code |
||||||
|
|
||||||
|
|
||||||
|
app = QApplication(sys.argv) |
||||||
|
scene = QGraphicsScene() |
||||||
|
|
||||||
|
families = [1,2,3,4,5,6,7,8,9,10] |
||||||
|
total = 0 |
||||||
|
set_angle = 0 |
||||||
|
count1 = 0 |
||||||
|
colours = [] |
||||||
|
total = sum(families) |
||||||
|
size=300 |
||||||
|
for count in range(len(families)): |
||||||
|
number = [] |
||||||
|
for count in range(3): |
||||||
|
number.append(random.randrange(0, 255)) |
||||||
|
colours.append(QColor(number[0],number[1],number[2])) |
||||||
|
|
||||||
|
for family in families: |
||||||
|
# Max span is 5760, so we have to calculate corresponding span angle |
||||||
|
angle = round(float(family*5760)/total) |
||||||
|
ellipse = QGraphicsEllipseItem(0,0,size,size) |
||||||
|
ellipse.setPos(0,0) |
||||||
|
ellipse.setStartAngle(set_angle) |
||||||
|
ellipse.setSpanAngle(angle) |
||||||
|
ellipse.setBrush(colours[count1]) |
||||||
|
set_angle += angle |
||||||
|
count1 += 1 |
||||||
|
scene.addItem(ellipse) |
||||||
|
|
||||||
|
view = QGraphicsView(scene) |
||||||
|
view.show() |
||||||
|
view.setFixedSize(size+10,size+10) |
||||||
|
app.exec_(code.interact(local=locals())) |
||||||
@ -1,335 +0,0 @@ |
|||||||
#!/usr/bin/env python |
|
||||||
# -*- coding: utf-8 -*- |
|
||||||
# |
|
||||||
# Copyright 2016 <+YOU OR YOUR COMPANY+>. |
|
||||||
# |
|
||||||
# This is free software; you can redistribute it and/or modify |
|
||||||
# it under the terms of the GNU General Public License as published by |
|
||||||
# the Free Software Foundation; either version 3, or (at your option) |
|
||||||
# any later version. |
|
||||||
# |
|
||||||
# This software is distributed in the hope that it will be useful, |
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
# GNU General Public License for more details. |
|
||||||
# |
|
||||||
# You should have received a copy of the GNU General Public License |
|
||||||
# along with this software; see the file COPYING. If not, write to |
|
||||||
# the Free Software Foundation, Inc., 51 Franklin Street, |
|
||||||
# Boston, MA 02110-1301, USA. |
|
||||||
# |
|
||||||
|
|
||||||
import numpy |
|
||||||
from gnuradio import gr |
|
||||||
import code,pmt,functools |
|
||||||
from PyQt4 import Qt, QtCore, QtGui |
|
||||||
import pprint |
|
||||||
pp = pprint.PrettyPrinter() |
|
||||||
|
|
||||||
from PyQt4.QtCore import QObject, pyqtSignal |
|
||||||
|
|
||||||
class rds_parser_table_qt_Signals(QObject): |
|
||||||
DataUpdateEvent = QtCore.pyqtSignal(dict) |
|
||||||
def __init__(self, parent=None): |
|
||||||
super(QtCore.QObject, self).__init__() |
|
||||||
|
|
||||||
class rds_parser_table_qt(gr.sync_block): |
|
||||||
""" |
|
||||||
docstring for block qtguitest |
|
||||||
""" |
|
||||||
def __init__(self,signals,nPorts): |
|
||||||
#QObject.__init__() |
|
||||||
gr.sync_block.__init__(self, |
|
||||||
name="RDS Table", |
|
||||||
in_sig=None, |
|
||||||
out_sig=None) |
|
||||||
for i in range(0,nPorts): |
|
||||||
self.message_port_register_in(pmt.intern('in%d'%i)) |
|
||||||
self.set_msg_handler(pmt.intern('in%d'%i), functools.partial(self.handle_msg, port=i)) |
|
||||||
|
|
||||||
self.signals=signals |
|
||||||
self.RTdict={} |
|
||||||
self.RTvalid={} |
|
||||||
self.PSNdict={} |
|
||||||
self.PSNvalid={} |
|
||||||
self.AFdata={} |
|
||||||
self.blockcounts={} |
|
||||||
self.printcounter=0 |
|
||||||
def handle_msg(self, msg, port): |
|
||||||
#code.interact(local=locals()) |
|
||||||
array=pmt.to_python(msg)[1] |
|
||||||
groupNR=array[2]&0b11110000 |
|
||||||
groupVar=array[2]&0b00001000 |
|
||||||
if (groupVar == 0): |
|
||||||
groupType=str(groupNR >> 4)+"A" |
|
||||||
else: |
|
||||||
groupType=str(groupNR >> 4)+"B" |
|
||||||
#print("raw:"+str(pmt.to_python(msg))+"\n") |
|
||||||
PI="%02X%02X" %(array[0],array[1]) |
|
||||||
#print("1st block:"+str(array[0])+","+str(array[1])+"= ID: %s" %PI) |
|
||||||
#print("2st block:"+str(array[2])+","+str(array[3])+"= type:"+groupType) |
|
||||||
#print("3st block:"+str(array[4])+","+str(array[5])) |
|
||||||
#print("4st block:"+str(array[6])+","+str(array[7])) |
|
||||||
if (groupType == "0A"):#AF PSN |
|
||||||
adr=array[3]&0b00000011 |
|
||||||
segment=self.decode_chars(chr(array[6])+chr(array[7])) |
|
||||||
if(not self.PSNdict.has_key(PI)):#initialize dict |
|
||||||
self.PSNdict[PI]="_"*8 |
|
||||||
self.PSNvalid[PI]=[False]*8 |
|
||||||
self.AFdata[PI]={} |
|
||||||
#1110 0000 = no AF |
|
||||||
#1110 0001 = 1AF |
|
||||||
#1111 1001 = 25AF |
|
||||||
|
|
||||||
if(array[5]>= 224 and array[5]<= 249): |
|
||||||
print("AF1 detected") |
|
||||||
self.AFdata[PI]['number']=array[5]-224 |
|
||||||
self.signals.DataUpdateEvent.emit({'row':port,'AF':self.AFdata[PI]}) |
|
||||||
if(array[6]>= 224 and array[6]<= 249): |
|
||||||
print("AF2 detected") |
|
||||||
|
|
||||||
name_list=list(self.PSNdict[PI]) |
|
||||||
if (name_list[adr*2:adr*2+2]==list(segment)):#segment already there |
|
||||||
segmentcolor="green" |
|
||||||
elif(name_list[adr*2:adr*2+2]==['_']*2): #segment new |
|
||||||
segmentcolor="orange" |
|
||||||
name_list[adr*2:adr*2+2]=segment |
|
||||||
else:#name changed (böse) |
|
||||||
segmentcolor="red" |
|
||||||
name_list=['_']*8 #reset name |
|
||||||
name_list[adr*2:adr*2+2]=segment |
|
||||||
#reset stored text: |
|
||||||
self.PSNdict[PI]="_"*8 |
|
||||||
self.PSNvalid[PI]=[False]*8 |
|
||||||
self.PSNvalid[PI][adr*2:adr*2+2]=[True] *2 |
|
||||||
self.PSNdict[PI]="".join(name_list) |
|
||||||
#determine if text is valid |
|
||||||
valid=True |
|
||||||
for i in range(0,8): |
|
||||||
if (not self.PSNvalid[PI][i]): |
|
||||||
valid = False |
|
||||||
if(valid): |
|
||||||
textcolor="black" |
|
||||||
else: |
|
||||||
textcolor="gray" |
|
||||||
formatted_text=self.color_text(self.PSNdict[PI],adr*2,adr*2+2,textcolor,segmentcolor) |
|
||||||
self.signals.DataUpdateEvent.emit({'col':5,'row':port,'PI':PI,'PSN':formatted_text}) |
|
||||||
elif (groupType == "2A"):#RT radiotext |
|
||||||
if(not self.RTdict.has_key(PI)):#initialize dict |
|
||||||
self.RTdict[PI]="_"*64 |
|
||||||
self.RTvalid[PI]=[False]*64 |
|
||||||
else: |
|
||||||
adr=array[3]&0b00001111 |
|
||||||
segment=self.decode_chars(chr(array[4])+chr(array[5])+chr(array[6])+chr(array[7])) |
|
||||||
#print("RT:adress: %d, segment:%s"%(adr,segment)) |
|
||||||
#self.signals.DataUpdateEvent.emit({'col':5,'row':port,'PI':PI,'groupType':groupType,'adress':adr,'segment':segment}) |
|
||||||
text_list=list(self.RTdict[PI]) |
|
||||||
#determine text length: |
|
||||||
try: |
|
||||||
text_end=text_list.index('\r') |
|
||||||
except ValueError: |
|
||||||
text_end=64 #assume whole string is important |
|
||||||
pass |
|
||||||
|
|
||||||
if (text_list[adr*4:adr*4+4]==list(segment)):#segment already there |
|
||||||
segmentcolor="green" |
|
||||||
elif (text_list[adr*4:adr*4+4]==['_']*4):#segment new |
|
||||||
segmentcolor="orange" |
|
||||||
text_list[adr*4:adr*4+4]=segment |
|
||||||
else: |
|
||||||
segmentcolor="red" |
|
||||||
text_list=['_']*64 #clear text |
|
||||||
text_list[adr*4:adr*4+4]=segment |
|
||||||
#reset stored text: |
|
||||||
self.RTdict[PI]="_"*64 |
|
||||||
self.RTvalid[PI]=[False]*64 |
|
||||||
|
|
||||||
self.RTvalid[PI][adr*4:adr*4+4]=[True] *4 |
|
||||||
self.RTdict[PI]="".join(text_list) |
|
||||||
|
|
||||||
#determine if (new) text is valid |
|
||||||
valid=True |
|
||||||
for i in range(0,text_end): |
|
||||||
if (not self.RTvalid[PI][i]): |
|
||||||
valid = False |
|
||||||
if(valid): |
|
||||||
textcolor="black" |
|
||||||
else: |
|
||||||
textcolor="gray" |
|
||||||
#formatted_text="<font face='Courier New' color='%s'>%s</font><font face='Courier New' color='%s'>%s</font><font face='Courier New' color='%s'>%s</font>"% (textcolor,self.RTdict[PI][:adr*4],segmentcolor,self.RTdict[PI][adr*4:adr*4+4],textcolor,self.RTdict[PI][adr*4+4:]) |
|
||||||
formatted_text=self.color_text(self.RTdict[PI],adr*4,adr*4+4,textcolor,segmentcolor) |
|
||||||
#print(self.RTdict[PI]+" valid:"+str(valid)+"valarr:"+str(self.RTvalid[PI])) |
|
||||||
|
|
||||||
|
|
||||||
self.signals.DataUpdateEvent.emit({'col':5,'row':port,'PI':PI,'string':formatted_text}) |
|
||||||
#code.interact(local=locals()) |
|
||||||
elif (groupType == "4A"):#CT clock time |
|
||||||
datecode=((array[3] & 0x03) << 15) | (array[4] <<7)|((array[5] >> 1) & 0x7f) |
|
||||||
hours=((array[5] & 0x1) << 4) | ((array[6] >> 4) & 0x0f) |
|
||||||
minutes=((array[6] &0x0F)<<2)|((array[7] >>6)&0x3) |
|
||||||
offsetdir=(array[7]>>5)&0x1 |
|
||||||
local_time_offset=0.5*((array[7])&0x1F) |
|
||||||
if(offsetdir==1): |
|
||||||
local_time_offset*=-1 |
|
||||||
year=int((datecode - 15078.2) / 365.25) |
|
||||||
month=int((datecode - 14956.1 - int(year * 365.25)) / 30.6001) |
|
||||||
day=datecode - 14956 - int(year * 365.25) - int(month * 30.6001) |
|
||||||
if(month == 14 or month == 15):#no idea why -> annex g of RDS spec |
|
||||||
year += 1; |
|
||||||
month -= 13 |
|
||||||
year+=1900 |
|
||||||
datestring="%02i.%02i.%4i, %02i:%02i (%+.1fh)" % (day,month,year,hours,minutes,local_time_offset) |
|
||||||
self.signals.DataUpdateEvent.emit({'col':4,'row':port,'PI':PI,'string':datestring}) |
|
||||||
else:#other group |
|
||||||
printfreq=100 |
|
||||||
self.printcounter+=1 |
|
||||||
if self.blockcounts.has_key(PI):#1st group on this station |
|
||||||
if self.blockcounts[PI].has_key(groupType):#1st group of this type |
|
||||||
self.blockcounts[PI][groupType] +=1 #increment |
|
||||||
else: |
|
||||||
self.blockcounts[PI][groupType] = 1 #initialize |
|
||||||
else: |
|
||||||
self.blockcounts[PI]={}#initialize dict |
|
||||||
if self.printcounter == printfreq: |
|
||||||
pp.pprint(self.blockcounts) |
|
||||||
self.printcounter=0 |
|
||||||
#print("group of type %s not decoded on station %s"% (groupType,PI)) |
|
||||||
def decode_chars(self,charstring): |
|
||||||
alphabet={ |
|
||||||
0b1000:u"áàéèíìóòúùÑÇŞßiIJ", |
|
||||||
0b1001:u"âäêëîïôöûüñçş??ij", |
|
||||||
0b1100:u"ÁÀÉÈÍÌÓÒÚÙŘČŠŽĐĿ", |
|
||||||
0b1101:u"áàéèíìóòúùřčšžđŀ"} |
|
||||||
charlist=list(charstring) |
|
||||||
for i,char in enumerate(charstring): |
|
||||||
#code.interact(local=locals()) |
|
||||||
if ord(char)<= 0b01111111: |
|
||||||
charlist[i]=char #use ascii |
|
||||||
else: |
|
||||||
#split byte |
|
||||||
alnr=(ord(char)&0xF0 )>>4 #upper 4 bit |
|
||||||
index=ord(char)&0x0F #lower 4 bit |
|
||||||
#code.interact(local=locals()) |
|
||||||
try: |
|
||||||
charlist[i]=alphabet[alnr][index] |
|
||||||
except KeyError: |
|
||||||
charlist[i]=char |
|
||||||
pass |
|
||||||
return "".join(charlist) |
|
||||||
def color_text(self, text, start,end,textcolor,segmentcolor): |
|
||||||
formatted_text="<font face='Courier New' color='%s'>%s</font><font face='Courier New' color='%s'>%s</font><font face='Courier New' color='%s'>%s</font>"% (textcolor,text[:start],segmentcolor,text[start:end],textcolor,text[end:]) |
|
||||||
return formatted_text |
|
||||||
class rds_parser_table_qt_Widget(QtGui.QWidget): |
|
||||||
def __init__(self, signals,label): |
|
||||||
print("gui initializing") |
|
||||||
self.signals = signals |
|
||||||
self.signals.DataUpdateEvent.connect(self.display_data) |
|
||||||
""" Creates the QT Range widget """ |
|
||||||
QtGui.QWidget.__init__(self) |
|
||||||
layout = Qt.QVBoxLayout() |
|
||||||
self.label = Qt.QLabel(label) |
|
||||||
layout.addWidget(self.label) |
|
||||||
self.setLayout(layout) |
|
||||||
self.table=QtGui.QTableWidget(self) |
|
||||||
self.table.setRowCount(5) |
|
||||||
self.table.setColumnCount(7) |
|
||||||
self.table.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) #disallow editing |
|
||||||
#Data |
|
||||||
empty_text32='________________________________' |
|
||||||
empty_text64='________________________________________________________________' |
|
||||||
#empty_text64='\xe4'*64 |
|
||||||
self.data = {'ID':range(1,6), |
|
||||||
'freq':['','','',''], |
|
||||||
'name':[], |
|
||||||
'AF':['','','',''], |
|
||||||
'time':[], |
|
||||||
'text':[], |
|
||||||
'buttons':[]} |
|
||||||
#Enter data onto Table |
|
||||||
horHeaders = [] |
|
||||||
for n, key in enumerate(['ID','freq','name','AF','time','text','buttons']): |
|
||||||
#for n, key in enumerate(sorted(self.data.keys())): |
|
||||||
horHeaders.append(key) |
|
||||||
for m, item in enumerate(self.data[key]): |
|
||||||
if type(item)==int:#convert ints to strings |
|
||||||
newitem = QtGui.QTableWidgetItem(str(item)) |
|
||||||
else: |
|
||||||
newitem = QtGui.QTableWidgetItem(item) |
|
||||||
self.table.setItem(m, n, newitem) |
|
||||||
for i in range(0,4):#create buttons |
|
||||||
button=QtGui.QPushButton("play") |
|
||||||
self.table.setCellWidget(i,self.table.columnCount()-1,button) |
|
||||||
button.clicked.connect(self.onCLick) |
|
||||||
for i in range(0,4):#create text labels |
|
||||||
label=QtGui.QLabel(empty_text64) |
|
||||||
#label.setFont(QtGui.QFont("Courier New")) |
|
||||||
self.table.setCellWidget(i,self.table.columnCount()-2,label) |
|
||||||
for i in range(0,4):#create name labels |
|
||||||
label=QtGui.QLabel("_"*8) |
|
||||||
#label.setFont(QtGui.QFont("Courier New")) |
|
||||||
self.table.setCellWidget(i,2,label) |
|
||||||
for i in range(0,4):#create time labels |
|
||||||
label=QtGui.QLabel() |
|
||||||
#label.setFont(QtGui.QFont("Courier New")) |
|
||||||
self.table.setCellWidget(i,4,label) |
|
||||||
#Add Header |
|
||||||
self.table.setHorizontalHeaderLabels(horHeaders) |
|
||||||
layout.addWidget(self.label) |
|
||||||
layout.addWidget(self.table) |
|
||||||
self.button = QtGui.QPushButton("i am a button") |
|
||||||
layout.addWidget(self.button) |
|
||||||
|
|
||||||
def display_data(self, event): |
|
||||||
#pp.pprint(event) |
|
||||||
if type(event)==dict and event.has_key('row'): |
|
||||||
if event.has_key('string'): |
|
||||||
item=self.table.cellWidget(event['row'],event['col']) |
|
||||||
item.setText(event['string']) |
|
||||||
if event.has_key('PI'): |
|
||||||
#setPI |
|
||||||
PIcol=0 |
|
||||||
self.table.item(event['row'],PIcol).setText(event['PI']) |
|
||||||
if event.has_key('AF'): |
|
||||||
#setAF |
|
||||||
PIcol=3 |
|
||||||
self.table.item(event['row'],PIcol).setText(event['AF']['number']) |
|
||||||
if event.has_key('PSN'): |
|
||||||
#setPSN |
|
||||||
PSNcol=2 |
|
||||||
item=self.table.cellWidget(event['row'],PSNcol) |
|
||||||
item.setText(event['PSN']) |
|
||||||
self.table.resizeColumnsToContents() |
|
||||||
#def reset_color(self): |
|
||||||
#for i in range(0,self.table.rowCount()): |
|
||||||
#for j in range(0,self.table.columnCount()): |
|
||||||
#item = self.table.item(i,j) |
|
||||||
##code.interact(local=locals()) |
|
||||||
##print(item.type()) |
|
||||||
#if item != '': |
|
||||||
#try: |
|
||||||
#item.setTextColor(QtCore.Qt.black) |
|
||||||
#except: |
|
||||||
#pass |
|
||||||
def onCLick(self): |
|
||||||
print("button clicked") |
|
||||||
#self.reset_color() |
|
||||||
#pp.pprint(event) |
|
||||||
if __name__ == "__main__": |
|
||||||
from PyQt4 import Qt |
|
||||||
import sys |
|
||||||
|
|
||||||
# def valueChanged(frequency): |
|
||||||
# print("Value updated - " + str(frequency)) |
|
||||||
|
|
||||||
app = Qt.QApplication(sys.argv) |
|
||||||
# widget = RangeWidget(Range(0, 100, 10, 1, 100), valueChanged, "Test", "counter_slider", int) |
|
||||||
mainobj= rds_parser_table_qt_Signals() |
|
||||||
#mainobj=None |
|
||||||
widget = rds_parser_table_qt_Widget(mainobj,"TestLabel") |
|
||||||
widget.show() |
|
||||||
widget.setWindowTitle("Test Qt gui") |
|
||||||
widget.setGeometry(200,200,600,300) |
|
||||||
#code.interact(local=locals()) |
|
||||||
sys.exit(app.exec_()) |
|
||||||
|
|
||||||
widget = None |
|
||||||
Loading…
Reference in new issue