Exemplo n.º 1
0
void display_thread(
  sampbuf_sync_t & sampbuf_sync,
  global_thread_data_t & global_thread_data,
  tracked_cell_list_t & tracked_cell_list,
  bool & expert_mode
) {
  global_thread_data.display_thread_id=syscall(SYS_gettid);

  // Initialize the curses screen
  initscr();
  start_color();
  use_default_colors();
  if (LINES<LINES_MIN) {
    //endwin();
    cerr << "Error: resize window so it has at least " << LINES_MIN << " rows and " << COLS_MIN << " columns" << endl;
    ABORT(-1);
  }
  if (COLS<COLS_MIN) {
    //endwin();
    cerr << "Error: resize window so it has at least " << LINES_MIN << " rows and " << COLS_MIN << " columns" << endl;
    ABORT(-1);
  }
  // Do not echo input chars to screen.
  noecho();
  // Turn off display of cursor.
  curs_set(0);
  // Enable function keys, arrow keys, etc.
  keypad(stdscr,true);
  //init_color(COLOR_BLACK,0,0,0);
  //init_pair(3,COLOR_GREEN,-1);
  init_pair(RED,COLOR_RED,-1);
  init_pair(GREEN,COLOR_GREEN,-1);
  init_pair(YELLOW,COLOR_YELLOW,-1);
  init_pair(BLUE,COLOR_BLUE,-1);
  init_pair(MAGENTA,COLOR_MAGENTA,-1);
  init_pair(CYAN,COLOR_CYAN,-1);
  init_pair(WHITE,COLOR_WHITE,-1);
  // Reduce delay between pressing 'Esc' and having this program
  // respond.
  // In ms.
  set_escdelay(50);

  // Start, end, and size of cell info display area.
  const uint16 CELL_DISP_START_ROW=2;
  const uint16 CELL_DISP_END_ROW=LINES-6;
  const uint16 CELL_DISP_N_ROWS=CELL_DISP_END_ROW-CELL_DISP_START_ROW+1;

  // Record where a particular cell was most recently printed.
  ivec disp_history(504);
  disp_history=-1;
  vector <row_desc_t> row_desc(CELL_DISP_N_ROWS);
  //bvec row_occupied(CELL_DISP_N_ROWS);

  // Settings that the user can change in realtime
  bool auto_refresh=true;
  double refresh_delay_sec=1;
  bool fifo_status=false;
  bool avg_values=true;
  disp_mode_t disp_mode=STD;
  int8 detail_type=0;
#define N_DETAILS 2
  // Send control chars directly to program.
  //cbreak();
  halfdelay(round_i(refresh_delay_sec*10.0));
  int16 highlight_row=-1;
  while (true) {
    clear();
    //attron(COLOR_PAIR(3));

    // No matter which display mode we are in, always update row_disc
    // and highlight_row.
    bool all_cells_displayed=true;
    for (uint16 t=0;t<CELL_DISP_N_ROWS;t++) {
      row_desc[t].occupied=false;
      row_desc[t].n_id_cell=-1;
      row_desc[t].duplex_mode=-3;
      row_desc[t].port_num=-2;
      //row_occupied(t)=false;
    }
    move(2,0);
    {
      boost::mutex::scoped_lock lock(tracked_cell_list.mutex);
      list <tracked_cell_t *>::iterator it=tracked_cell_list.tracked_cells.begin();
      vector <tracked_cell_t *> pass2_display;
      while (it!=tracked_cell_list.tracked_cells.end()) {
        tracked_cell_t & tracked_cell=(*(*it));

        // Deadlock possible???
        boost::mutex::scoped_lock lock1(tracked_cell.fifo_mutex);
        boost::mutex::scoped_lock lock2(tracked_cell.meas_mutex);

        uint8 n_rows_required=tracked_cell.n_ports+2;

        // If this cell has been displayed before, try to display it
        // in the same location.
        if (disp_history(tracked_cell.n_id_cell)!=-1) {
          uint16 row_desired=disp_history(tracked_cell.n_id_cell);
          if (will_fit(row_desc,row_desired,n_rows_required-1)) {
            if (disp_mode==STD)
              display_cell(tracked_cell,row_desired+CELL_DISP_START_ROW,fifo_status,avg_values,expert_mode);
            set_occupied(tracked_cell,row_desc,row_desired);
          } else {
            pass2_display.push_back(&tracked_cell);
          }
        } else {
          pass2_display.push_back(&tracked_cell);
        }
        ++it;
      }

      // Display cells that cannot be displayed where they have previously
      // been displayed.
      for (uint8 t=0;t<pass2_display.size();t++) {
        tracked_cell_t & tracked_cell=(*pass2_display[t]);

        // Deadlock possible???
        boost::mutex::scoped_lock lock1(tracked_cell.fifo_mutex);
        boost::mutex::scoped_lock lock2(tracked_cell.meas_mutex);

        uint8 n_rows_required=tracked_cell.n_ports+2;
        bool placed=false;
        for (uint16 k=0;k<CELL_DISP_N_ROWS-n_rows_required+1;k++) {
          if (will_fit(row_desc,k,n_rows_required)) {
            if (disp_mode==STD)
              display_cell(tracked_cell,k+CELL_DISP_START_ROW,fifo_status,avg_values,expert_mode);
            set_occupied(tracked_cell,row_desc,k);
            disp_history(tracked_cell.n_id_cell)=k;
            placed=true;
            break;
          }
        }
        if (!placed)
          all_cells_displayed=false;
      }
    }

    // Always highlight a row, if a cell exists.
    if (highlight_row==-1) {
      for (uint16 t=0;t<CELL_DISP_N_ROWS;t++) {
        if (row_desc[t].n_id_cell!=-1) {
          highlight_row=t;
          break;
        }
      }
    }

    if (disp_mode==STD) {
      // Header and footer
      {
        stringstream ss;
        ss << "LTE-Tracker www.evrytania.com; 1.0 to " << MAJOR_VERSION << "." << MINOR_VERSION << "." << PATCH_LEVEL << ": OpenCL/TDD/HACKRF/bladeRF/ext-LNB added by Jiao.([email protected]).";
        move(0,0);
        attron(COLOR_PAIR(CYAN));
        print_center(ss.str());
        attroff(COLOR_PAIR(CYAN));
      }

      move(CELL_DISP_END_ROW+1,0);
      if (!all_cells_displayed) {
        attron(COLOR_PAIR(YELLOW));
        printw("Warning: some tracked cells could not be displayed! (screen has too few rows)\n");
        attroff(COLOR_PAIR(YELLOW));
      } else {
        printw("\n");
      }
      if (global_thread_data.cell_seconds_dropped()||global_thread_data.raw_seconds_dropped()) {
        attron(COLOR_PAIR(RED));
        printw("[dropped cell/raw data: %i/%i s]\n",global_thread_data.cell_seconds_dropped(),global_thread_data.raw_seconds_dropped());
        attroff(COLOR_PAIR(RED));
      } else {
        printw("\n");
      }
      if (expert_mode) {
        if (avg_values) {
          printw("Showing average measurements\n");
        } else {
          printw("Showing instant measurements\n");
        }
      } else {
        printw("\n");
      }
      attron(COLOR_PAIR(MAGENTA));
      printw("[InitFO: %5.0lfHz][TrackFO: %5.2lfHz]",global_thread_data.initial_frequency_offset(), global_thread_data.frequency_offset()-global_thread_data.initial_frequency_offset());
      //attron(A_BOLD);
//      printw("[searcher delay: %.1lf s]",global_thread_data.searcher_cycle_time());
      printw("[SearcherDelay: %4.2fs][rqst %5.2lfMHz][prog %5.2lfMHz][fs %5.2lfMHz][k %5.3lf][twist %d]",global_thread_data.searcher_cycle_time(), global_thread_data.fc_requested/1e6, global_thread_data.fc_programmed/1e6, global_thread_data.fs_programmed/1e6, global_thread_data.k_factor(), global_thread_data.sampling_carrier_twist());
      //attroff(A_BOLD);

      if (fifo_status) {
        boost::mutex::scoped_lock lock(sampbuf_sync.mutex);
        stringstream ss;
        uint8 w=ceil(log10(sampbuf_sync.fifo_peak_size));
        ss << "[inp buf: " << setw(w) << sampbuf_sync.fifo.size() << "/" << sampbuf_sync.fifo_peak_size << "]";
        //attron(A_BOLD);
        printw("%s\n",ss.str().c_str());
        //attroff(A_BOLD);
      } else {
        printw("\n");
      }
      attroff(COLOR_PAIR(MAGENTA));

      /*
      printw("Searcher thread ID: %5i\n",global_thread_data.searcher_thread_id);
      printw("Producer thread ID: %5i\n",global_thread_data.producer_thread_id);
      printw("Main     thread ID: %5i\n",global_thread_data.main_thread_id);
      printw("Display  thread ID: %5i\n\n",global_thread_data.display_thread_id);
      */

      attron(COLOR_PAIR(GREEN));
      //printw("Up/down = select, left/right = details, (h)elp, (q)uit\n");
      print_right("right arrow > TF");
      print_center("(h)elp, (q)uit");
      attroff(COLOR_PAIR(GREEN));
      //attroff(A_BOLD);

      // Highlight one of the rows
      if (highlight_row!=-1) {
        if (row_desc[highlight_row].n_id_cell==-1) {
          highlight_row=-1;
        } else {
          move(CELL_DISP_START_ROW+highlight_row,0);
          chgat(-1,A_REVERSE,0,NULL);
        }
      }

    } else {
      // Zoom into port details

      // Shortcuts
      const int16 & n_id_cell=row_desc[highlight_row].n_id_cell;
      const int8 & duplex_mode=row_desc[highlight_row].duplex_mode;
      const int8 & port_num=row_desc[highlight_row].port_num;

      {
        boost::mutex::scoped_lock lock(tracked_cell_list.mutex);
        list <tracked_cell_t *>::iterator it=tracked_cell_list.tracked_cells.begin();
        vector <tracked_cell_t *> pass2_display;
        bool cell_found=false;
        while (it!=tracked_cell_list.tracked_cells.end()) {
          tracked_cell_t & tracked_cell=(*(*it));
          if ((tracked_cell.n_id_cell==n_id_cell)&&((port_num==-1)||(port_num<tracked_cell.n_ports))) {
            cell_found=true;
            break;
          }
          ++it;
        }
        if (cell_found) {
          tracked_cell_t & tracked_cell=(*(*it));
          boost::mutex::scoped_lock lock2(tracked_cell.meas_mutex);
          if (detail_type==0) {
            // Plot transfer function mag
            vec trace;
            if (port_num==-1) {
              trace=db10(sqr(tracked_cell.sync_ce));
            } else {
              trace=db10(sqr(tracked_cell.ce.get_row(port_num)));
            }
            plot_trace(
              // Trace desc.
              trace,itpp_ext::matlab_range(0.0,71.0),
              // X axis
              0,71,12,NAN,
              // Y axis
              -50,0,10,
              // UL corner
              1,0,
              // LR corner
              LINES-2,0+72+4,
              true
            );
            move(0,0);
            stringstream ss;
            if (duplex_mode==0)
                ss << "FDD Cell " << n_id_cell;
            else
                ss << "TDD Cell " << n_id_cell;
            if (port_num==-1) {
              ss << " Sync channel magnitude\n";
            } else {
              ss << " port " << port_num << " magnitude\n";
            }
            attron(COLOR_PAIR(CYAN));
            print_center(ss.str());
            attroff(COLOR_PAIR(CYAN));
            move(LINES-1,0);
            attron(COLOR_PAIR(GREEN));
            print_center("(h)elp, (q)uit");
            print_right("right arrow > phase resp");
            print_left("top menu < left arrow");
            attroff(COLOR_PAIR(GREEN));
          } else if (detail_type==1) {
            // Plot transfer function phase
            vec trace;
            double mean_ang;
            if (port_num==-1) {
              trace=arg(tracked_cell.sync_ce);
              mean_ang=arg(sum(exp(J*trace(5,66))));
              trace=arg(tracked_cell.sync_ce*exp(J*-mean_ang));
              trace(0)=NAN;
              trace(1)=NAN;
              trace(2)=NAN;
              trace(3)=NAN;
              trace(4)=NAN;
              trace(67)=NAN;
              trace(68)=NAN;
              trace(69)=NAN;
              trace(70)=NAN;
              trace(71)=NAN;
            } else {
              trace=arg(tracked_cell.ce.get_row(port_num));
              mean_ang=arg(sum(exp(J*trace)));
              trace=arg(tracked_cell.ce.get_row(port_num)*exp(J*-mean_ang));
            }
            trace=trace/pi*180;
            plot_trace(
              // Trace desc.
              trace,itpp_ext::matlab_range(0.0,71.0),
              // X axis
              0,71,12,(mean_ang+pi)/(2*pi)*71,
              // Y axis
              -40,40,10,
              // UL corner
              1,0,
              // LR corner
              LINES-2,0+72+4,
              false
            );
            move(0,0);
            stringstream ss;
            if (duplex_mode==0)
                ss << "FDD Cell " << n_id_cell;
            else
                ss << "TDD Cell " << n_id_cell;
            if (port_num==-1) {
              ss << " Sync channel phase\n";
            } else {
              ss << " port " << port_num << " phase\n";
            }
            attron(COLOR_PAIR(CYAN));
            print_center(ss.str());
            attroff(COLOR_PAIR(CYAN));
            move(LINES-1,0);
            attron(COLOR_PAIR(GREEN));
            print_center("(h)elp, (q)uit");
            //print_right("right arrow > phase response");
            print_left("mag resp < left arrow");
            attroff(COLOR_PAIR(GREEN));
          } else if (detail_type==2) {
            // Frequency domain autocorrelation
            const vec trace=abs(tracked_cell.ac_fd);
            plot_trace(
              // Trace desc.
              trace,itpp_ext::matlab_range(0.0,11.0),
              // X axis
              0,11,2,NAN,
              // Y axis
              0,1.2,.5,
              // UL corner
              0,0,
              // LR corner
              LINES-3,0+72+4,
              true
            );
            move(LINES-2,0);
            if (duplex_mode==0)
                printw("FDD Cell ID: %i\n",n_id_cell);
            else
                printw("TDD Cell ID: %i\n",n_id_cell);
            printw("Frequency domain channel autocorrelation function. x-axis spans 1.26MHz\n");
          } else if (detail_type==3) {
            // Time domain autocorrelation
            const vec trace=abs(tracked_cell.ac_td);
            plot_trace(
              // Trace desc.
              trace,itpp_ext::matlab_range(0.0,71.0)*.0005,
              // X axis
              0,71*.0005,.010,NAN,
              // Y axis
              0,3.2,.5,
              // UL corner
              0,0,
              // LR corner
              LINES-3,0+72+4,
              true
            );
            move(LINES-2,0);
            if (duplex_mode == 0)
                printw("FDD Cell ID: %i\n",n_id_cell);
            else
                printw("TDD Cell ID: %i\n",n_id_cell);
            printw("Time domain channel autocorrelation function. x-axis spans 35.5ms\n");
          }
        } else {
          move(1,0);
          printw("Cell is no longer being tracked. Press left arrow to go back!\n");
        }
      }

    }

    refresh();

    // Handle keyboard input.
    // Previous halfdelay() function ensures that this will not block.
    int ch=getch();
    switch (ch) {
      case 'q':
      case 'Q':
        if (global_thread_data.dev_use() == dev_type_t::RTLSDR) {
          #ifdef HAVE_RTLSDR
          if ( global_thread_data.rtlsdr_dev()!=NULL ) {
            rtlsdr_close( global_thread_data.rtlsdr_dev() );
            global_thread_data.rtlsdr_dev(NULL);
          }
          #endif
        } else if (global_thread_data.dev_use() == dev_type_t::HACKRF) {
          #ifdef HAVE_HACKRF
          if (global_thread_data.hackrf_dev()!=NULL) {
            hackrf_close( global_thread_data.hackrf_dev() );
            global_thread_data.hackrf_dev(NULL);
            hackrf_exit();
          }
          #endif
        } else if (global_thread_data.dev_use() == dev_type_t::BLADERF) {
          #ifdef HAVE_BLADERF
          if (global_thread_data.bladerf_dev()!=NULL) {
            bladerf_close( global_thread_data.bladerf_dev() );
            global_thread_data.bladerf_dev(NULL);
          }
          #endif
        }
        ABORT(-1);
        break;
      case 'r':
      case 'R':
        auto_refresh=!auto_refresh;
        if (auto_refresh) {
          halfdelay(1+round_i(refresh_delay_sec*10.0));
        } else {
          cbreak();
        }
        break;
      case '-':
      case '_':
        refresh_delay_sec=MIN(15,refresh_delay_sec*1.5);
        halfdelay(round_i(refresh_delay_sec*10.0));
        break;
      case '+':
      case '=':
        refresh_delay_sec=MAX(0.001,refresh_delay_sec/1.5);
        halfdelay(round_i(refresh_delay_sec*10.0));
        break;
      case 'f':
      case 'F':
        fifo_status=!fifo_status;
        break;
      case 'a':
      case 'A':
        avg_values=!avg_values;
        break;
      case 27:
        // Escape key
        disp_mode=STD;
        break;
      case 'k':
      case 'K':
      case KEY_UP:
        for (int16 t=highlight_row-1;t>=0;t--) {
          if (row_desc[t].n_id_cell!=-1) {
            highlight_row=t;
            break;
          }
        }
        break;
      case 'j':
      case 'J':
      case KEY_DOWN:
        for (uint16 t=highlight_row+1;t<CELL_DISP_N_ROWS;t++) {
          if (row_desc[t].n_id_cell!=-1) {
            highlight_row=t;
            break;
          }
        }
        break;
      case 'l':
      case 'L':
      case KEY_RIGHT:
      case '\n':
        if (disp_mode==STD) {
          disp_mode=DETAIL;
          detail_type=0;
        } else {
          detail_type=MIN(detail_type+1,N_DETAILS-1);
        }
        break;
      case KEY_LEFT:
        if (disp_mode==DETAIL) {
          if (detail_type==0) {
            disp_mode=STD;
          } else {
            detail_type-=1;
          }
        }
        break;
      case 'h':
      case 'H':
        clear();
        move(0,0);
        if (disp_mode==STD) {
          print_center("LTE-Tracker main display help menu\n");
          printw("\n");
          //printw("Display frequency response:\n");
          printw("up/down keys move selection bar\n");
          printw("'Enter' or right-arrow displays the frequency response\n");
          printw("\n");
          printw("P0 : SNR received from port 0\n");
          printw("S  : SNR of the PSS/SSS synchronization channel\n");
          printw("TO : frame timing referenced to the dongle's timescale of 19200 samples\n");
          printw("FO : dongle's current residual frequency offset\n");
          printw("\n");
          printw("'q' exits the program\n");
          printw("+/- increases or decreases screen refresh rate\n");
          printw("'r' turns automatic screen refresh on/off\n");
          printw("'f' displays the current status of the fifo's\n");
          printw("Esc always returns to the top menu\n");
          printw("\n");
          printw("Health is a measure of the amount of time since the last time the MIB\n");
          printw("was successfully decoded for that cell. Cells are dropped when health\n");
          printw("reaches 0.\n");
          printw("\n");
          printw("searcher delay is the amount of time (in seconds) that it takes for the\n");
          printw("searcher to complete a full search cycle\n");
          printw("\n");
          printw("Press any key to exit help screen!\n");
          cbreak();
          getch();
          if (auto_refresh) {
            halfdelay(round_i(refresh_delay_sec*10.0));
          }
        } else {
          print_center("LTE-Tracker mag/phase response help menu\n");
          printw("\n");
          printw("up/down keys change port and cell ID\n");
          printw("left/right keys change to phase response and main menu\n");
          printw("\n");
          printw("'q' exits the program\n");
          printw("+/- increases or decreases screen refresh rate\n");
          printw("'r' turns automatic screen refresh on/off\n");
          printw("Esc always returns to the top menu\n");
          printw("\n");
          printw("For the phase plot, the average phase offset is removed from the trace, but\n");
          printw("the value of this phase offset is indicated by an asterisk on the x axis.\n");
          printw("\n");
          printw("Press any key to exit help screen!\n");
          cbreak();
          getch();
          if (auto_refresh) {
            halfdelay(round_i(refresh_delay_sec*10.0));
          }
        }
        break;
    }
  }
}