/*
* Copyright Daniel Jones 2016-2018
*
* This file is part of RGBController.
*
* RGBController is free software: you can redistribute it and/or modifiy
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* RGBController 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 RGBController. If not, see .
*/
#include "controllerwindow.h"
controllerWindow::controllerWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::controllerWindow)
{
/* this is our setup function, we set things up here */
ui->setupUi(this);
info_log("RGB Controller started");
/* serial */
ser = new QSerialPort(this);
connect(ser, &QSerialPort::readyRead, this, &controllerWindow::read);
ptimer = new QTimer(this);
connect(ptimer, SIGNAL(timeout()), this, SLOT(ping()));
connect(&ircbot, SIGNAL(sendcmd(QString)), this, SLOT(cmdrecv(QString)));
connect(&srv, SIGNAL(sendcmd(QString)), this, SLOT(cmdrecv(QString)));
pingtries = 0;
irccon = false;
pingcount = 0;
server_started = false;
/* disable buttons and widgets that should not be enabled yet, set slider values to 0 */
ui->disconnect_button->setEnabled(false);
ui->connect_button->setEnabled(false);
ui->red_button->setEnabled(false);
ui->green_button->setEnabled(false);
ui->blue_button->setEnabled(false);
ui->off_button->setEnabled(false);
ui->reload_preset_button->setEnabled(false);
ui->set_preset_button->setEnabled(false);
ui->preset_save_button->setEnabled(false);
ui->preset_delete_button->setEnabled(false);
ui->preset_name_textbox->setEnabled(false);
ui->presets_dropdown->setEnabled(false);
ui->r_slider->setEnabled(false);
ui->g_slider->setEnabled(false);
ui->b_slider->setEnabled(false);
ui->r_slider->setValue(0);
ui->g_slider->setValue(0);
ui->b_slider->setValue(0);
ui->red_fade_button->setEnabled(false);
ui->green_fade_button->setEnabled(false);
ui->blue_fade_button->setEnabled(false);
ui->speed_button->setEnabled(false);
ui->rfrom->setEnabled(false);
ui->rto->setEnabled(false);
ui->gfrom->setEnabled(false);
ui->gto->setEnabled(false);
ui->bfrom->setEnabled(false);
ui->bto->setEnabled(false);
ui->r_speed_slider->setEnabled(false);
ui->g_speed_slider->setEnabled(false);
ui->b_speed_slider->setEnabled(false);
ui->speed_slider->setEnabled(false);
ui->r_speed_slider->setValue(0);
ui->g_speed_slider->setValue(0);
ui->b_speed_slider->setValue(0);
ui->speed_slider->setValue(0);
presetsfile = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/presets.txt";
tempfile = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/tmp.file";
/* set some crucial ints */
preset_index = 0, r = 0, g = 0, b = 0;
/* populate our serial port dropdown box */
populate_serial_list();
/* load our presets file */
load_presets();
}
controllerWindow::~controllerWindow()
{
/* this function will end our program and clean up */
delete ui;
}
void controllerWindow::info_log(QString text)
{
/* this function is used to append logging information to our text area */
ui->info_log_textarea->append(text);
}
void controllerWindow::populate_serial_list()
{
/*
* things to be done here:
* - clear anything inside our serial dropdown box
* - re-populate the serial dropdown box
*/
/* remove anything in the list */
ui->arduino_port_dropdown->clear();
/* populate the list */
for (int x = 0; x < QSerialPortInfo::availablePorts().size(); x++)
{
if (!QSerialPortInfo::availablePorts().at(x).description().isEmpty())
ui->arduino_port_dropdown->addItem(QSerialPortInfo::availablePorts().at(x).portName());
}
if (!ui->arduino_port_dropdown->itemText(0).isEmpty())
{
ui->connect_button->setEnabled(true);
info_log("Serial port list populated");
} else
{
info_log("No serial port found!");
ui->arduino_port_dropdown->addItem("None");
}
}
void controllerWindow::load_presets()
{
/*
* this function will load presets from file and put them into a drop down box
* How i plan for it to work:
* -> load file
* -> parse line by line
* -> split line at delimeter
* -> add [0] to dropdown (name), add [1] to an array that stores all the values
*/
QFile inputFile(presetsfile);
if (inputFile.open(QIODevice::ReadOnly))
{
QTextStream in(&inputFile);
while (!in.atEnd())
{
QString line = in.readLine();
if (line.contains("="))
{
ui->presets_dropdown->addItem(line.split("=")[0]);
presets.append(line.split("=")[1]);
}
}
inputFile.close();
info_log("Presets loaded");
} else
{
show_msgbox("Unable to load the presets file.\n");
info_log("Presets file not found.");
}
}
void controllerWindow::save_preset(QString name)
{
/* this function will save our preset to file */
if (!QDir("Folder").exists())
QDir().mkdir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
QFile file(presetsfile);
if(!file.open(QIODevice::Append)) {
show_msgbox("Fatal error opening presets for appending text.");
} else
{
QTextStream stream(&file);
stream << name << "=" << ui->r_slider->value() << "," << ui->g_slider->value() << "," << ui->b_slider->value() << endl;
file.close();
info_log("Saved preset: " + name);
/* things to fix the presets list */
ui->presets_dropdown->clear();
presets.clear();
preset_index = 0;
load_presets();
}
}
void controllerWindow::delete_preset(QString name)
{
/*
* here we will delete a preset from the presets file
* process:
* retrieve preset name
* go through preset file line by line and write it to a seperate tmp file
* if the [0] of split('=') equals the preset name, don't write it to the tmp file
* delete the old preset file
* rename the tmp file to presets.txt
*/
int ret = show_question_box("Are you sure want to delete this preset?", "This process cannot be reverted.");
switch (ret)
{
case QMessageBox::Ok:
{
info_log("deleting preset: " + name);
QFile file(tempfile);
if(!file.open(QIODevice::Append)) {
show_msgbox("Fatal error opening temp file for writing");
} else
{
QTextStream stream(&file);
//stream << "test tmp file" << endl;
for (int x = 0; x < ui->presets_dropdown->count(); x++)
{
if(name != ui->presets_dropdown->itemText(x))
{
stream << ui->presets_dropdown->itemText(x) << "=" << presets.at(x) << endl;
}
}
file.close();
/* remove the current presets file then rename the temp file to presets.txt */
QFile::remove(presetsfile);
QFile::rename(tempfile, presetsfile);
/* reload presets into memory and clear the drop down box */
ui->presets_dropdown->clear();
presets.clear();
preset_index = 0;
load_presets();
break;
}
}
case QMessageBox::Cancel:
show_msgbox("Preset was not deleted.");
break;
default:
info_log("Unknown response received.");
break;
}
}
void controllerWindow::serial_rgb_change(int r, int g, int b)
{
/* un used function */
rgb_change(r, g, b);
}
void controllerWindow::show_msgbox(QString message)
{
/* show message box to the user */
QMessageBox msgbox;
msgbox.setText(message);
msgbox.exec();
}
int controllerWindow::show_question_box(QString message, QString omessage)
{
/*
* shows a question box to the user with ok/cancel, returns result
*/
QMessageBox qbox;
qbox.setText(message);
qbox.setInformativeText(omessage);
qbox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
qbox.setDefaultButton(QMessageBox::Cancel);
return qbox.exec();
}
/*
*
* button and widget functions below
*
*/
void controllerWindow::on_connect_button_clicked()
{
/*
* here we need to call our serial port connect function
* if our connection is sucessful we need to enable and disable a few buttons and widgets
* we must also change our rgb sliders etc
*/
pingtries = 0;
port = ui->arduino_port_dropdown->currentText();
if (serial_connect(port))
{ // if true we are connected
info_log("Connection established");
ui->arduino_status_label->setText("Connected");
/* now we need to disabled and enable some buttons and objects */
ui->disconnect_button->setEnabled(true);
ui->connect_button->setEnabled(false);
ui->red_button->setEnabled(true);
ui->green_button->setEnabled(true);
ui->blue_button->setEnabled(true);
ui->off_button->setEnabled(true);
ui->reload_preset_button->setEnabled(true);
ui->set_preset_button->setEnabled(true);
ui->preset_save_button->setEnabled(true);
ui->preset_delete_button->setEnabled(true);
ui->preset_name_textbox->setEnabled(true);
ui->presets_dropdown->setEnabled(true);
ui->r_slider->setEnabled(true);
ui->g_slider->setEnabled(true);
ui->b_slider->setEnabled(true);
ui->refresh_port_button->setEnabled(false);
ui->arduino_port_dropdown->setEnabled(false);
ui->red_fade_button->setEnabled(true);
ui->green_fade_button->setEnabled(true);
ui->blue_fade_button->setEnabled(true);
ui->speed_button->setEnabled(true);
ui->rfrom->setEnabled(true);
ui->rto->setEnabled(true);
ui->gfrom->setEnabled(true);
ui->gto->setEnabled(true);
ui->bfrom->setEnabled(true);
ui->bto->setEnabled(true);
ui->r_speed_slider->setEnabled(true);
ui->g_speed_slider->setEnabled(true);
ui->b_speed_slider->setEnabled(true);
ui->speed_slider->setEnabled(true);
ptimer->start(60000);
} else
{
info_log("Unable to connect (port in use?)");
}
}
void controllerWindow::on_disconnect_button_clicked()
{
/*
* here we will attempt to disconnect from our serial port
* we will also enable/disable some buttons and widgets and set slider values to 0
*/
if (serial_disconnect())
{
info_log("Disconnected from serial port");
ui->arduino_status_label->setText("Disconnected");
ui->disconnect_button->setEnabled(false);
ui->connect_button->setEnabled(true);
ui->red_button->setEnabled(false);
ui->green_button->setEnabled(false);
ui->blue_button->setEnabled(false);
ui->off_button->setEnabled(false);
ui->reload_preset_button->setEnabled(false);
ui->preset_save_button->setEnabled(false);
ui->preset_delete_button->setEnabled(false);
ui->preset_name_textbox->setEnabled(false);
ui->set_preset_button->setEnabled(false);
ui->presets_dropdown->setEnabled(false);
ui->refresh_port_button->setEnabled(true);
ui->arduino_port_dropdown->setEnabled(true);
ui->r_slider->setEnabled(false);
ui->g_slider->setEnabled(false);
ui->b_slider->setEnabled(false);
ui->r_slider->setValue(0);
ui->g_slider->setValue(0);
ui->b_slider->setValue(0);
ui->red_fade_button->setEnabled(false);
ui->green_fade_button->setEnabled(false);
ui->blue_fade_button->setEnabled(false);
ui->speed_button->setEnabled(false);
ui->rfrom->setEnabled(false);
ui->rto->setEnabled(false);
ui->gfrom->setEnabled(false);
ui->gto->setEnabled(false);
ui->bfrom->setEnabled(false);
ui->bto->setEnabled(false);
ui->r_speed_slider->setEnabled(false);
ui->g_speed_slider->setEnabled(false);
ui->b_speed_slider->setEnabled(false);
ui->speed_slider->setEnabled(false);
ui->r_speed_slider->setValue(0);
ui->g_speed_slider->setValue(0);
ui->b_speed_slider->setValue(0);
ui->speed_slider->setValue(0);
} else
{
/* I have no clue how we'd get here */
info_log("Cannot disconnect");
}
}
void controllerWindow::on_refresh_port_button_clicked()
{
populate_serial_list();
}
void controllerWindow::on_reload_preset_button_clicked()
{
ui->presets_dropdown->clear();
presets.clear();
preset_index = 0;
load_presets();
}
void controllerWindow::on_r_slider_valueChanged(int value)
{
r = value;
//serial_rgb_change(r, g, b);
send("red=" + QString::number(r));
}
void controllerWindow::on_g_slider_valueChanged(int value)
{
g = value;
//serial_rgb_change(r, g, b);
send("green=" + QString::number(g));
}
void controllerWindow::on_b_slider_valueChanged(int value)
{
b = value;
//serial_rgb_change(r, g, b);
send("blue=" + QString::number(b));
}
void controllerWindow::on_red_button_clicked()
{
ui->r_slider->setValue(255);
ui->g_slider->setValue(0);
ui->b_slider->setValue(0);
}
void controllerWindow::on_green_button_clicked()
{
ui->r_slider->setValue(0);
ui->g_slider->setValue(255);
ui->b_slider->setValue(0);
}
void controllerWindow::on_blue_button_clicked()
{
ui->r_slider->setValue(0);
ui->g_slider->setValue(0);
ui->b_slider->setValue(255);
}
void controllerWindow::on_off_button_clicked()
{
ui->r_slider->setValue(1);
ui->g_slider->setValue(1);
ui->b_slider->setValue(1);
ui->r_slider->setValue(0);
ui->g_slider->setValue(0);
ui->b_slider->setValue(0);
send("off");
}
void controllerWindow::on_set_preset_button_clicked()
{
if (!presets.empty())
{
QString tempstore = presets.at(preset_index);
QStringList temparray = tempstore.split(",");
//info_log("Preset selected: " + temparray[0] + " " + temparray[1] + " " + temparray[2]);
ui->r_slider->setValue(temparray[0].toInt());
ui->g_slider->setValue(temparray[1].toInt());
ui->b_slider->setValue(temparray[2].toInt());
} else
show_msgbox("There are no loaded presets!");
}
void controllerWindow::on_presets_dropdown_currentIndexChanged(int index)
{
preset_index = index;
}
void controllerWindow::on_preset_save_button_clicked()
{
QString tempname = ui->preset_name_textbox->text();
if (tempname.contains("="))
{
show_msgbox("Cannot save a preset with a name that contains an '='.");
} else if (tempname.isEmpty())
{
show_msgbox("Cannot save a preset without a name.");
} else
{
save_preset(tempname);
}
ui->preset_name_textbox->clear();
}
void controllerWindow::on_preset_delete_button_clicked()
{
delete_preset(ui->presets_dropdown->currentText());
}
void controllerWindow::on_red_fade_button_clicked()
{
send("redfade");
}
void controllerWindow::on_green_fade_button_clicked()
{
send("greenfade");
}
void controllerWindow::on_blue_fade_button_clicked()
{
send("bluefade");
}
void controllerWindow::on_speed_button_clicked()
{
send("speed=" + QString::number(ui->speed_slider->value()));
}
void controllerWindow::on_r_speed_slider_valueChanged(int value)
{
send("rspeed=" + QString::number(value));
}
void controllerWindow::on_g_speed_slider_valueChanged(int value)
{
send("gspeed=" + QString::number(value));
}
void controllerWindow::on_b_speed_slider_valueChanged(int value)
{
send("bspeed=" + QString::number(value));
}
void controllerWindow::on_rfrom_valueChanged(int arg1)
{
send("rf=" + QString::number(arg1));
//ui->r_slider->setValue(arg1);
}
void controllerWindow::on_rto_valueChanged(int arg1)
{
send("rt=" + QString::number(arg1));
}
void controllerWindow::on_gfrom_valueChanged(int arg1)
{
send("gf=" + QString::number(arg1));
//ui->g_slider->setValue(arg1);
}
void controllerWindow::on_gto_valueChanged(int arg1)
{
send("gt=" + QString::number(arg1));
}
void controllerWindow::on_bfrom_valueChanged(int arg1)
{
send("bf=" + QString::number(arg1));
//ui->b_slider->setValue(arg1);
}
void controllerWindow::on_bto_valueChanged(int arg1)
{
send("bt=" + QString::number(arg1));
}
bool controllerWindow::serial_connect(QString port)
{
/* this function will attempt a ser.connection if we are not already connected */
if (!ser->isOpen())
{
ser->setPortName(port);
ser->setBaudRate(QSerialPort::Baud9600);
ser->setDataBits(QSerialPort::Data8);
ser->setParity(QSerialPort::NoParity);
ser->setStopBits(QSerialPort::OneStop);
ser->setFlowControl(QSerialPort::NoFlowControl);
ser->open(QIODevice::ReadWrite);
ser->waitForBytesWritten(9000);
if (ser->isWritable())
{
return true;
}
}
return false;
}
bool controllerWindow::serial_disconnect()
{
/* this function disconnects from the serial port if it is connected already */
if (ser->isOpen())
{
ser->close();
ptimer->stop();
return true;
}
return false;
}
void controllerWindow::send(QString com)
{
data = "";
data.append(com + "\n");
if (ser->isOpen())
ser->write(data);
}
void controllerWindow::rgb_change(int r, int g, int b)
{
// NOT USED FUNCTION
/* here we send our rgb values to the serial port */
data = "";
/* the 0 is a hack, i need to look into it at some point */
data.append("red=" + QString::number(r) + "," + QString::number(g) + "," + QString::number(b) + "\n");
if (ser->isOpen())
ser->write(data);
}
void controllerWindow::read()
{
if (serdata[serdata.size() - 1] == '\n')
{
parse(QString(serdata));
serdata = "";
}
else
serdata = serdata + ser->readAll();
}
void controllerWindow::parse(QString message)
{
qDebug() << message;
if (message.contains("="))
{
QString command = message.split("=")[0].remove(QRegExp("[\\n\\t\\r]"));
QString text = message.split("=")[1].remove(QRegExp("[\\n\\t\\r]"));
if (command == "msgbox")
show_msgbox(text);
if (command == "ping")
{
qDebug() << "pong from arduino";
tping = true;
}
}
}
void controllerWindow::on_serial_send_button_clicked()
{
send(ui->serial_input->text());
}
// timer after ping send, if the timer timeout()'s, disconnect, claim no connection
void controllerWindow::ping()
{
qDebug() << "sending ping";
send("ping\n");
tping = false;
QTimer::singleShot(1000, this, SLOT(check_ping()));
pingcount++;
ui->ping_count_label->setText("Ping: " + QString::number(pingcount));
}
void controllerWindow::check_ping()
{
if (tping)
{
qDebug() << "connection fine";
tping = false;
pingtries = 0;
}
else
{
if (pingtries >= 3)
{
qDebug() << "connection lost";
on_disconnect_button_clicked();
show_msgbox("Disconnected from Arduino.\nNo ping response after 3 tries.");
}
else
{
pingtries++;
qDebug() << "no ping response try" << pingtries;
}
}
}
void controllerWindow::on_irc_connect_button_clicked()
{
if (irccon == false)
{
irccon = true;
ircbot.setup(ui->irc_server_input->text(), ui->irc_bot_spinbox->value(), ui->irc_channel_input->text(), ui->irc_name_input->text());
ui->irc_connect_button->setText("Disconnect");
}
else
{
irccon = false;
ircbot.discon();
ui->irc_connect_button->setText("Connect");
}
}
void controllerWindow::on_server_start_button_clicked()
{
if (!server_started)
{
if (srv.server_start())
{
server_started = true;
ui->server_start_button->setText("Stop server");
info_log("Server started");
}
else
{
info_log("Server could not start");
}
}
else if (server_started)
{
if (srv.server_stop())
{
server_started = false;
ui->server_start_button->setText("Start server");
info_log("Server stopped");
}
else
{
info_log("Server not not be stopped");
}
}
}
void controllerWindow::cmdrecv(QString cmd)
{
qDebug() << "received command:" << cmd;
send(cmd);
}