/*
# Docsis cable modem diagnostics (cmdiag)
#
# Copyright (C) 2006-2007 Emil Penchev
#
# This program is free software, distributed under the terms of
# the GNU General Public License 2.0
#
*/


#include <ncurses.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "bar.h"
#include "pbar.h"
#include "globals.h"
#include "cmodem.h"
#include "func.h"

int main(int argc, char ** argv)
{
	CModem * cmodem = NULL;
	
	screen_size_check();
	
	char * cm_ip = get_cmd_option(argc, argv, CMIP);
	char * cm_str = get_cmd_option(argc, argv, CM_STRING);
	char * cmts_ip = get_cmd_option(argc, argv, CMTSIP);
	char * cmts_str = get_cmd_option(argc, argv, CMTS_STRING);
	
	initscr();      /* initialize ncurses */
	cbreak();
	noecho();
	keypad(stdscr, TRUE);
	start_color();   /*start color mode */
	curs_set(0);     /* Make cursor invisible */

	attron(A_BOLD);
	mvwaddstr(stdscr, 1, 32, "POWER MONITOR");
	attroff(A_BOLD);
 
	if ((!cmts_str) || (!cmts_ip))
		cmodem = new CModem(cm_ip, " ", cm_str, " ");
	else 
		cmodem = new CModem(cm_ip, cmts_ip, cm_str, cmts_str);
	//CModem * cmodem = new CModem("10.0.1.34", "83.222.168.65", "modems", "modems");
	PowerBar * ds = new PowerBar(3, 3, "Downstream", "dBmv", "dBmv", -30, 30, DS_BAR_LENGHT, DS_MAX_PARTS, 1);
	ds->Draw();
	
	PowerBar * us = new PowerBar(3, 9, "Upstream", "dBmv", "dBmv", 0, 60, US_BAR_LENGHT, US_MAX_PARTS, 2);
	us->Draw();
	
	attron(A_BOLD);
	mvwaddstr(stdscr, 13, 32, "SIGNAL TO NOISE RATIO");
	attroff(A_BOLD);
	
	PowerBar * snrds = new PowerBar(3, 15, "Downstream SNR", "dBmv", "dBmv", 0, 50, SNR_BAR_LENGHT, SNR_MAX_PARTS, 3);
	snrds->Draw();

	PowerBar * snrus = new PowerBar(3, 21, "Upstream SNR", "dBmv", "dBmv", 0, 50, SNR_BAR_LENGHT, SNR_MAX_PARTS, 3);
	snrus->Draw(); 
 
	attron(A_BOLD);
	mvwaddstr(stdscr, 25, 28, "DATA PERFORMANCE (RF INTERFACE)");
	attroff(A_BOLD);

	Bar * dsthr = new Bar(3, 28, "Downstream Throughput", "bps", " kbps", 0, 500, DAT_BAR_LENGHT);
	dsthr->Draw();
 
	Bar * usthr = new Bar(61, 28, "Upstream Throughput", "bps", " kbps", 0, 500, DAT_BAR_LENGHT);
	usthr->Draw();
 
	Bar * rxpower = new Bar(77, 21, "Receive Power at CMTS", "dBmv", " dBmv", 0, 40, DAT_BAR_LENGHT);
	rxpower->Draw();

	PowerBar * errds = new PowerBar(3, 34, "Downstream Error Rate", "bps", "bps", 0, 80, ERR_RATE_BAR_LENGHT, ERR_RATE_MAX_PARTS, 4);
	errds->Draw();
 
	PowerBar * errus = new PowerBar(61, 34, "Upstream Error Rate", "bps", "bps", 0, 80, ERR_RATE_BAR_LENGHT, ERR_RATE_MAX_PARTS, 4);
	errus->Draw();
 
	mvwaddstr(stdscr, 1, 80, "CM IP Address: ");
	mvwaddstr(stdscr, 1, 97, cm_ip);
	
	mvwaddstr(stdscr, 2, 80, "CMTS IP Address: ");
	if (!cmts_ip)
		mvwaddstr(stdscr, 2, 97, "N/A");
	else 
		mvwaddstr(stdscr, 2, 97, cmts_ip);
	
	mvwaddstr(stdscr, 3, 80, "CM Mac: ");
	mvwaddstr(stdscr, 4, 80, "Uptime: ");
	attron(A_BOLD);
	mvwaddstr(stdscr, 6, 89, "DOWNSTEAM");
	attroff(A_BOLD);
	mvwaddstr(stdscr, 7, 77, "Frequency :");
	mvwaddstr(stdscr, 8, 77, "Width :");
	//mvwaddstr(stdscr, 12, 77, "Modulation :");
	attron(A_BOLD);
	mvwaddstr(stdscr, 6, 107, "UPSTREAM");
	attroff(A_BOLD);
	
	mvwaddstr(stdscr, 10, 77, "RF inits/resets : ");
	mvwaddstr(stdscr, 11, 77, "Invalid ranging response messages : ");
	mvwaddstr(stdscr, 12, 77, "Ranging process aborted by the CMTS : ");
	mvwaddstr(stdscr, 13, 77, "Invalid registration response messages : ");
	attron(A_BOLD);
	mvwaddstr(stdscr, 14, 90, "FEC COUNTERS");
	attroff(A_BOLD);
	mvwaddstr(stdscr, 15, 77, "Codewords without error : ");
	mvwaddstr(stdscr, 16, 77, "Codewords with correctable errors : ");
	mvwaddstr(stdscr, 17, 77, "Codewords with uncorrectable errors : ");  
	refresh();
	
	// Get mac addres //
	if (string * cmac = cmodem->Get_Mac()) {
		// Display MAC
		mvwaddstr(stdscr, 3, 97, cmac->c_str());
	}
	// Exit function
	attron(A_BOLD);
	mvwaddstr(stdscr, 43, 110, "'Ctrl-c to Exit'"); 
	attroff(A_BOLD);
		
	while(1) {
		if (cmodem->CM_Online()) {
			// Display downstream power level
			if (string * d_power_level = cmodem->Get_Ds_Power())
				ds->SignalUpdate(atoi(d_power_level->c_str()), d_power_level->c_str());
			else ds->SignalUpdate(0, "");
		
			// Display upstream power level	
			if (string * u_power_level = cmodem->Get_Us_Power())
				us->SignalUpdate(atoi(u_power_level->c_str()), u_power_level->c_str());
			else us->SignalUpdate(0, "");
			
			// Display downstream snr
			if (string * d_snr = cmodem->Get_Ds_Snr())
				snrds->SignalUpdate(atoi(d_snr->c_str()), d_snr->c_str());
			else snrds->SignalUpdate(0, "");
			
			// Display upstream snr
			if (cmodem->CMTS_Online()) {
				if (string * u_snr = cmodem->Get_Us_Snr())
					snrus->SignalUpdate(atoi(u_snr->c_str()), u_snr->c_str());
				else snrus->SignalUpdate(0, "");
			}
			
			// Display downstream rf cable flow
			if (string * d_cable_flow = cmodem->Get_RfDs_Data())
				dsthr->DataUpdate(atoi(d_cable_flow->c_str()));
			else dsthr->DataUpdate(0);
			
			// Display upstream rf cable flow
			if (string * u_cable_flow = cmodem->Get_RfUs_Data())
				usthr->DataUpdate(atoi(u_cable_flow->c_str()));
			else usthr->DataUpdate(0);
			
			// Display downstream cable rf error bytes 
			if (string * d_cable_err = cmodem->Get_RfDs_Err()) {
				errds->ErrRateUpdate(8*(atoi(d_cable_err->c_str())));
				string disgbytes = *d_cable_err; 
				disgbytes = disgbytes + " disgarted bytes";
				mvwaddstr(stdscr, 38, 2, disgbytes.c_str());
			}
			
			// Discplay upstream cable rf error bytes
			if (string * u_cable_err = cmodem->Get_RfUs_Err()) {
				errus->ErrRateUpdate(8*(atoi(u_cable_err->c_str())));
				string disgbytes = *u_cable_err;
				disgbytes = disgbytes + " disgarted bytes";
				mvwaddstr(stdscr, 38, 60, disgbytes.c_str());
			}
			// Display CMTS RX Power 
			if (cmodem->CMTS_Online()) {
				if (string * prx_power = cmodem->Get_CMTS_Rx_Power()) {
					rxpower->RxUpdate(atoi(prx_power->c_str()));
				}
			}
			
			// Display Frequency 
			if (string * d_freq = cmodem->Get_Ds_Freq())
				//mvwaddstr(stdscr, 10, 107, d_freq->c_str());
				mvwaddstr(stdscr, 7, 89, d_freq->c_str());
			
			if (string * u_freq = cmodem->Get_Us_Freq())
				//mvwaddstr(stdscr, 10, 89, u_freq->c_str());
				mvwaddstr(stdscr, 7, 107, u_freq->c_str());
			
			// Display channel width 
			if (string * d_width = cmodem->Get_Ds_Width()) {
				//mvwaddstr(stdscr, 11, 89, d_width->c_str());
				mvwaddstr(stdscr, 8, 89, d_width->c_str());
			}
			
			if (string * u_width = cmodem->Get_Us_Width()) 
				mvwaddstr(stdscr, 8, 107, u_width->c_str());
			
			//Display uptime
			if (string * uptime = cmodem->Get_Uptime())
				mvwaddstr(stdscr, 4, 96, uptime->c_str());

			// Display cable modem system description
			if (string * sys_info = cmodem->Get_SysDesc()) {
				attron(A_BOLD);
				mvwaddstr(stdscr, 41, 2, "CM INFO:");
				attroff(A_BOLD);
				mvaddnstr(41, 12, sys_info->c_str(), sys_info->find("<<", 0));
				mvwaddstr(stdscr, 42, 12, strstr(sys_info->c_str(), "<<"));
				refresh();
			}
			
			// Display number of times the CM reset or initialized RF interface
			if (string * resets = cmodem->Get_CM_Resets()) {
				//mvwaddstr(stdscr, 13, 77, "RF inits/resets : ");
				mvwaddstr(stdscr, 10, 95, resets->c_str());
				refresh();
			}
			
			// Display number of times the CM received invalid ranging response messages
			if (string * invalid_rangs = cmodem->Get_Recv_Inv_Rang()) {
				//mvwaddstr(stdscr, 14, 77, "Invalid ranging response messages : ");
				mvwaddstr(stdscr, 11, 118, invalid_rangs->c_str());
				refresh();
			}
			
			// Display number of times the ranging process was aborted by the CMTS
			if (string * abort_rangs = cmodem->Get_Abort_Rang()) {
				//mvwaddstr(stdscr, 15, 77, "Ranging process aborted by the CMTS : ");
				mvwaddstr(stdscr, 12, 118, abort_rangs->c_str());
				refresh();
			}
			
			// Display number of times the CM received invalid registration response messages
			if (string * invalid_regs = cmodem->Get_Recv_Inv_Reg()) {
				//mvwaddstr(stdscr, 16, 77, "Invalid registration response messages : ");
				mvwaddstr(stdscr, 13, 118, invalid_regs->c_str());
				refresh();
			}
			
			/* Display FEC counters */
			//Codewords received without error 
			if (string * sig_unerr = cmodem->Get_Unerror_Words()) {
				mvwaddstr(stdscr, 15, 105, sig_unerr->c_str());
				refresh();
			}
			
			//Codewords with correctable errors
			if (string * sig_corectwords = cmodem->Get_Corerror_Words()) {
				mvwaddstr(stdscr, 16, 114, sig_corectwords->c_str());
				refresh();
			}
			// Codewords with uncorrectable errors
			if (string * sig_uncorectwords = cmodem->Get_Uncorerror_Words()) {
				mvwaddstr(stdscr, 17, 114, sig_uncorectwords->c_str());
				refresh();
			}
		}
		else {
			ds->SignalUpdate(0, "");
			us->SignalUpdate(0, "");
			snrds->SignalUpdate(0, "");
			snrus->SignalUpdate(0, "");
			dsthr->DataUpdate(0);
			usthr->DataUpdate(0);
		}
		
		sleep(1);
	}
	endwin();
 
	return 0;
}
