openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

173 lines
4.7 KiB

#include <iostream>
#include <QFile>
#include <QDebug>
#include <QHBoxLayout>
#include <QLabel>
#include <QPixmap>
#include <QPushButton>
#include <QLineEdit>
#include <QJsonDocument>
#include <QJsonObject>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QCryptographicHash>
#include <openssl/rsa.h>
#include <openssl/bio.h>
#include <openssl/pem.h>
#include "drive_stats.hpp"
#include "common/params.h"
#include "common/utilpp.h"
double MILE_TO_KM = 1.60934;
#if defined(QCOM) || defined(QCOM2)
const std::string private_key_path = "/persist/comma/id_rsa";
#else
const std::string private_key_path = util::getenv_default("HOME", "/.comma/persist/comma/id_rsa", "/persist/comma/id_rsa");
#endif
QByteArray rsa_sign(QByteArray data){
auto file = QFile(private_key_path.c_str());
bool r = file.open(QIODevice::ReadOnly);
assert(r);
auto key = file.readAll();
BIO *mem = BIO_new_mem_buf(key.data(), key.size());
assert(mem);
RSA *rsa_private = PEM_read_bio_RSAPrivateKey(mem, NULL, NULL, NULL);
assert(rsa_private);
auto sig = QByteArray();
sig.resize(RSA_size(rsa_private));
unsigned int sig_len;
int ret = RSA_sign(NID_sha256, (unsigned char*)data.data(), data.size(), (unsigned char*)sig.data(), &sig_len, rsa_private);
assert(ret == 1);
assert(sig_len == sig.size());
BIO_free(mem);
RSA_free(rsa_private);
return sig;
}
QString create_jwt(QString dongle_id, int expiry=3600){
QJsonObject header;
header.insert("alg", "RS256");
header.insert("typ", "JWT");
auto t = QDateTime::currentSecsSinceEpoch();
QJsonObject payload;
payload.insert("identity", dongle_id);
payload.insert("nbf", t);
payload.insert("iat", t);
payload.insert("exp", t + expiry);
QString jwt =
QJsonDocument(header).toJson(QJsonDocument::Compact).toBase64() +
'.' +
QJsonDocument(payload).toJson(QJsonDocument::Compact).toBase64();
auto hash = QCryptographicHash::hash(jwt.toUtf8(), QCryptographicHash::Sha256);
auto sig = rsa_sign(hash);
jwt += '.' + sig.toBase64();
return jwt;
}
QString bold(QString s) {
return "<b>" + s + "</b>";
}
QWidget *widget(QLayout *l){
QWidget *q = new QWidget();
q->setLayout(l);
return q;
}
QWidget *build_stat(QString name, int stat){
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(new QLabel(bold(QString("%1").arg(stat))), 1, Qt::AlignCenter);
layout->addWidget(new QLabel(name),1, Qt::AlignCenter);
return widget(layout);
}
void DriveStats::replyFinished(QNetworkReply *l){
QString answer = l->readAll();
answer.chop(1);
QJsonDocument doc = QJsonDocument::fromJson(answer.toUtf8());
if (doc.isNull()) {
qDebug() << "JSON Parse failed";
}
QString IsMetric = QString::fromStdString(Params().get("IsMetric"));
bool metric = (IsMetric =="1");
QJsonObject json = doc.object();
auto all = json["all"].toObject();
auto week = json["week"].toObject();
QGridLayout *gl = new QGridLayout();
int all_distance = all["distance"].toDouble()*(metric ? MILE_TO_KM : 1);
gl->addWidget(new QLabel(bold("ALL TIME")), 0, 0, 1, 3);
gl->addWidget(build_stat("DRIVES", all["routes"].toDouble()), 1, 0, 3, 1);
gl->addWidget(build_stat(metric ? "KM" : "MILES", all_distance), 1, 1, 3, 1);
gl->addWidget(build_stat("HOURS", all["minutes"].toDouble() / 60), 1, 2, 3, 1);
QFrame *lineA = new QFrame;
lineA->setFrameShape(QFrame::HLine);
lineA->setFrameShadow(QFrame::Sunken);
lineA->setProperty("class", "line");
gl->addWidget(lineA, 5, 0, 1, 3);
int week_distance = week["distance"].toDouble()*(metric ? MILE_TO_KM : 1);
gl->addWidget(new QLabel(bold("PAST WEEK")), 6, 0, 1, 3);
gl->addWidget(build_stat("DRIVES", week["routes"].toDouble()), 7, 0, 3, 1);
gl->addWidget(build_stat(metric ? "KM" : "MILES", week_distance), 7, 1, 3, 1);
gl->addWidget(build_stat("HOURS", week["minutes"].toDouble() / 60), 7, 2, 3, 1);
f->setLayout(gl);
f->setStyleSheet(R"(
[class="line"]{
border: 2px solid white;
}
[class="outside"]{
border-radius: 20px;
border: 2px solid white;
padding: 10px;
}
QLabel{
font-size: 70px;
font-weight: 200;
}
)");
}
DriveStats::DriveStats(QWidget *parent) : QWidget(parent){
f = new QFrame;
f->setProperty("class", "outside");
QVBoxLayout *v = new QVBoxLayout;
v->addWidget(f);
setLayout(v);
QString dongle_id = QString::fromStdString(Params().get("DongleId"));
QString token = create_jwt(dongle_id);
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
connect(manager, &QNetworkAccessManager::finished, this, &DriveStats::replyFinished);
QNetworkRequest request;
request.setUrl(QUrl("https://api.commadotai.com/v1.1/devices/" + dongle_id + "/stats"));
request.setRawHeader("Authorization", ("JWT "+token).toUtf8());
manager->get(request);
}