Compare commits
14 Commits
0fef710b8f
...
feature/mo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4181b98f83
|
||
|
e5273c7012
|
|||
|
e19e7c9253
|
|||
|
50fe918561
|
|||
|
9d18c40a43
|
|||
|
|
fc87693d64 | ||
|
|
5279b14975 | ||
|
|
af0c6ad421 | ||
|
|
ebd0479cd9 | ||
|
|
d1991d9abc | ||
|
|
5b0666920c | ||
|
|
cd2839e6ca | ||
|
|
dd176256bb | ||
|
|
ec09cb9625 |
@@ -1,15 +1,11 @@
|
|||||||
#include "about.h"
|
#include "about.h"
|
||||||
#include "ui_about.h"
|
#include "ui_about.h"
|
||||||
|
|
||||||
About::About(QWidget *parent) :
|
About::About(QWidget* parent) : QDialog(parent), ui(new Ui::About) {
|
||||||
QDialog(parent),
|
|
||||||
ui(new Ui::About)
|
|
||||||
{
|
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
ui->lblVersion->setText(ui->lblVersion->text() + " " + __DATE__ + " " + __TIME__);
|
ui->lblVersion->setText(ui->lblVersion->text() + " " + __DATE__ + " " + __TIME__);
|
||||||
}
|
}
|
||||||
|
|
||||||
About::~About()
|
About::~About() {
|
||||||
{
|
|
||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,16 +7,15 @@ namespace Ui {
|
|||||||
class About;
|
class About;
|
||||||
}
|
}
|
||||||
|
|
||||||
class About : public QDialog
|
class About : public QDialog {
|
||||||
{
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit About(QWidget *parent = nullptr);
|
explicit About(QWidget* parent = nullptr);
|
||||||
~About();
|
~About();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::About *ui;
|
Ui::About* ui;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ABOUT_H
|
#endif // ABOUT_H
|
||||||
|
|||||||
@@ -2,8 +2,7 @@
|
|||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char* argv[]) {
|
||||||
{
|
|
||||||
QApplication a(argc, argv);
|
QApplication a(argc, argv);
|
||||||
MainWindow w;
|
MainWindow w;
|
||||||
w.show();
|
w.show();
|
||||||
|
|||||||
@@ -1,107 +1,97 @@
|
|||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "ui_mainwindow.h"
|
|
||||||
#include "QUdpSocket"
|
#include "QUdpSocket"
|
||||||
|
#include "ui_mainwindow.h"
|
||||||
|
|
||||||
MainWindow::MainWindow(QWidget *parent)
|
MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow) {
|
||||||
: QMainWindow(parent)
|
|
||||||
, ui(new Ui::MainWindow)
|
|
||||||
{
|
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
m_udpSocket = new QUdpSocket(this);
|
m_udpSocket = new QUdpSocket(this);
|
||||||
m_udpSocket->bind(QHostAddress::Any, UDP_PORT, QUdpSocket::ShareAddress);
|
m_udpSocket->bind(QHostAddress::Any, UDP_PORT, QUdpSocket::ShareAddress);
|
||||||
|
|
||||||
connect(m_udpSocket, &QUdpSocket::readyRead,
|
connect(m_udpSocket, &QUdpSocket::readyRead, this, &MainWindow::processPendingDatagrams);
|
||||||
this, &MainWindow::processPendingDatagrams);
|
|
||||||
|
|
||||||
//Timer just to ask twice (udp)
|
// Timer just to ask twice (udp)
|
||||||
m_timer = new QTimer(this);
|
m_timer = new QTimer(this);
|
||||||
m_timer->setSingleShot(true);
|
m_timer->setSingleShot(true);
|
||||||
m_timer->setInterval(500);
|
m_timer->setInterval(500);
|
||||||
connect(m_timer,&QTimer::timeout, this, &MainWindow::SendRequest);
|
connect(m_timer, &QTimer::timeout, this, &MainWindow::SendRequest);
|
||||||
|
|
||||||
//Send Request on startup
|
// Send Request on startup
|
||||||
on_pbRefresh_clicked();
|
on_pbRefresh_clicked();
|
||||||
|
|
||||||
ui->devices->setIconSize(QSize(48,48));
|
ui->devices->setIconSize(QSize(48, 48));
|
||||||
ui->devices->setContextMenuPolicy(Qt::CustomContextMenu);
|
ui->devices->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
|
|
||||||
ui->comboBox->addItem("default");
|
ui->comboBox->addItem("default");
|
||||||
ui->comboBox->addItem("192.168.69.10"); //test
|
ui->comboBox->addItem("192.168.69.10"); // test
|
||||||
if (ui->comboBox->currentText()=="default"){
|
if (ui->comboBox->currentText() == "default") {
|
||||||
ui->ChangeOwner->setDisabled(true);
|
ui->ChangeOwner->setDisabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// //Example items for screenshot:
|
// //Example items for screenshot:
|
||||||
// QListWidgetItem * item = new QListWidgetItem(QIcon(":/res/stm32.png"), "00:80:E1:05:44:21 @ 192.168.0.11 (John Doe)");
|
// QListWidgetItem * item = new QListWidgetItem(QIcon(":/res/stm32.png"), "00:80:E1:05:44:21 @ 192.168.0.11 (John
|
||||||
// ui->devices->addItem(item);
|
// Doe)"); ui->devices->addItem(item); QListWidgetItem * item2 = new QListWidgetItem(QIcon(":/res/rpi.png"),
|
||||||
// QListWidgetItem * item2 = new QListWidgetItem(QIcon(":/res/rpi.png"), "E4:5F:01:05:44:21 @ 192.168.0.11 (Jane Doe)");
|
// "E4:5F:01:05:44:21 @ 192.168.0.11 (Jane Doe)"); ui->devices->addItem(item2); QListWidgetItem * item3 = new
|
||||||
// ui->devices->addItem(item2);
|
// QListWidgetItem(QIcon(":/res/unknown.png"), "44:44:44:05:44:21 @ 192.168.0.11 (Juul Doe)");
|
||||||
// QListWidgetItem * item3 = new QListWidgetItem(QIcon(":/res/unknown.png"), "44:44:44:05:44:21 @ 192.168.0.11 (Juul Doe)");
|
// ui->devices->addItem(item3);
|
||||||
// ui->devices->addItem(item3);
|
|
||||||
connect(ui->actionAbout_Qt, &QAction::triggered, QApplication::aboutQt);
|
connect(ui->actionAbout_Qt, &QAction::triggered, QApplication::aboutQt);
|
||||||
}
|
}
|
||||||
|
|
||||||
MainWindow::~MainWindow()
|
MainWindow::~MainWindow() {
|
||||||
{
|
|
||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_pbRefresh_clicked()
|
void MainWindow::on_pbRefresh_clicked() {
|
||||||
{
|
|
||||||
this->func = 0;
|
this->func = 0;
|
||||||
SendRequest();
|
SendRequest();
|
||||||
m_timer->start();
|
m_timer->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::SendRequest()
|
void MainWindow::SendRequest() {
|
||||||
{
|
|
||||||
int broadcasts_send = 0;
|
int broadcasts_send = 0;
|
||||||
int data_send = 0;
|
int data_send = 0;
|
||||||
QUdpSocket udpSocket;
|
QUdpSocket udpSocket;
|
||||||
QByteArray datagram;
|
QByteArray datagram;
|
||||||
if(this->func == 0){
|
if (this->func == 0) {
|
||||||
datagram = UDP_REQUEST"v1.0";
|
datagram = UDP_REQUEST "v1.0";
|
||||||
//Get all the Network Interface Cards of this Computer
|
// Get all the Network Interface Cards of this Computer
|
||||||
QList<QNetworkInterface> NICs = QNetworkInterface::allInterfaces();
|
QList<QNetworkInterface> NICs = QNetworkInterface::allInterfaces();
|
||||||
foreach(QNetworkInterface NIC, NICs){
|
foreach (QNetworkInterface NIC, NICs) {
|
||||||
//Get all the adresses on this NIC
|
// Get all the adresses on this NIC
|
||||||
QList<QNetworkAddressEntry> adresses = NIC.addressEntries();
|
QList<QNetworkAddressEntry> adresses = NIC.addressEntries();
|
||||||
foreach(QNetworkAddressEntry adress, adresses){
|
foreach (QNetworkAddressEntry adress, adresses) {
|
||||||
QD << NIC.name() << adress.ip();
|
QD << NIC.name() << adress.ip();
|
||||||
//If broadcast adress = null => IPv6 (no support for broadcasts)
|
// If broadcast adress = null => IPv6 (no support for broadcasts)
|
||||||
QHostAddress broadc_addr = adress.broadcast();
|
QHostAddress broadc_addr = adress.broadcast();
|
||||||
if(!broadc_addr.isNull()){
|
if (!broadc_addr.isNull()) {
|
||||||
//Send UDP packet
|
// Send UDP packet
|
||||||
udpSocket.writeDatagram(datagram, adress.broadcast(), UDP_PORT);
|
udpSocket.writeDatagram(datagram, adress.broadcast(), UDP_PORT);
|
||||||
broadcasts_send++;
|
broadcasts_send++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else if (this->func == 1) {
|
||||||
else if(this->func == 1){
|
|
||||||
QHostAddress addr(ui->comboBox->currentText());
|
QHostAddress addr(ui->comboBox->currentText());
|
||||||
udpSocket.writeDatagram(this->data, addr, UDP_PORT);
|
udpSocket.writeDatagram(this->data, addr, UDP_PORT);
|
||||||
data_send++;
|
data_send++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (broadcasts_send == 0 && data_send == 0) {
|
||||||
if(broadcasts_send == 0 && data_send == 0){
|
ui->pteLog->appendPlainText(
|
||||||
ui->pteLog->appendPlainText("Warning: no Network Interface Cards or valid IP adresses found (no broadcasts send)");
|
"Warning: no Network Interface Cards or valid IP adresses found (no broadcasts send)");
|
||||||
}else if(data_send != 0){
|
} else if (data_send != 0) {
|
||||||
ui->pteLog->appendPlainText(tr("Info: %1 message sent to %2").arg(data_send).arg(ui->comboBox->currentText()));
|
ui->pteLog->appendPlainText(tr("Info: %1 message sent to %2").arg(data_send).arg(ui->comboBox->currentText()));
|
||||||
}else{
|
} else {
|
||||||
ui->pteLog->appendPlainText(tr("Info: %1 broadcasts send").arg(broadcasts_send));
|
ui->pteLog->appendPlainText(tr("Info: %1 broadcasts send").arg(broadcasts_send));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::processPendingDatagrams()
|
void MainWindow::processPendingDatagrams() {
|
||||||
{
|
|
||||||
QByteArray datagram;
|
QByteArray datagram;
|
||||||
QHostAddress host;
|
QHostAddress host;
|
||||||
|
|
||||||
// just get rid of every host in the combobox, not pretty code, i know
|
// just get rid of every host in the combobox, not pretty code, i know
|
||||||
if(this->func == 0){
|
if (this->func == 0) {
|
||||||
for(int i = 1; i < ui->comboBox->count(); i++){
|
for (int i = 1; i < ui->comboBox->count(); i++) {
|
||||||
ui->comboBox->removeItem(i);
|
ui->comboBox->removeItem(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -114,74 +104,69 @@ void MainWindow::processPendingDatagrams()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::processDatagram(QString msg,QString host)
|
void MainWindow::processDatagram(QString msg, QString host) {
|
||||||
{
|
// Append received data to log
|
||||||
|
QString logLine = tr("Van %1: \"%2\"").arg(host).arg(msg);
|
||||||
//Append received data to log
|
|
||||||
QString logLine = tr("Van %1: \"%2\"")
|
|
||||||
.arg(host)
|
|
||||||
.arg(msg);
|
|
||||||
ui->pteLog->appendPlainText(logLine);
|
ui->pteLog->appendPlainText(logLine);
|
||||||
|
|
||||||
//We receive our own request. So a check to see if it is the request:
|
// We receive our own request. So a check to see if it is the request:
|
||||||
if(msg.indexOf(UDP_REQUEST) != -1){
|
if (msg.indexOf(UDP_REQUEST) != -1) {
|
||||||
return; //we are done here...
|
return; // we are done here...
|
||||||
}
|
}
|
||||||
|
|
||||||
// add new host to select in combobox
|
// add new host to select in combobox
|
||||||
if(this->func == 0){
|
if (this->func == 0) {
|
||||||
ui->comboBox->addItem(host);
|
ui->comboBox->addItem(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RegEx for MAC adress
|
||||||
//RegEx for MAC adress
|
QRegularExpression macRegExp(
|
||||||
QRegularExpression macRegExp("([0-9A-F]{2})[:-]([0-9A-F]{2})[:-]([0-9A-F]{2})[:-]([0-9A-F]{2})[:-]([0-9A-F]{2})[:-]([0-9A-F]{2})");
|
"([0-9A-F]{2})[:-]([0-9A-F]{2})[:-]([0-9A-F]{2})[:-]([0-9A-F]{2})[:-]([0-9A-F]{2})[:-]([0-9A-F]{2})");
|
||||||
QRegularExpressionMatch match = macRegExp.match(msg.toUpper());
|
QRegularExpressionMatch match = macRegExp.match(msg.toUpper());
|
||||||
if(match.hasMatch()){
|
if (match.hasMatch()) {
|
||||||
QString foundOUI = match.captured(1) % match.captured(2) % match.captured(3);
|
QString foundOUI = match.captured(1) % match.captured(2) % match.captured(3);
|
||||||
QString foundMAC = match.captured(0);
|
QString foundMAC = match.captured(0);
|
||||||
QString imgName = ":/res/unknown.png";
|
QString imgName = ":/res/unknown.png";
|
||||||
/*grep STMicro oui.txt | grep base
|
/*grep STMicro oui.txt | grep base
|
||||||
0080E1 (base 16) STMicroelectronics SRL
|
0080E1 (base 16) STMicroelectronics SRL
|
||||||
10E77A (base 16) STMicrolectronics International NV*/
|
10E77A (base 16) STMicrolectronics International NV*/
|
||||||
if(foundOUI == "0080E1" || foundOUI == "10E77A") {
|
if (foundOUI == "0080E1" || foundOUI == "10E77A") {
|
||||||
imgName = ":/res/stm32.png";
|
imgName = ":/res/stm32.png";
|
||||||
}
|
}
|
||||||
/*grep Raspberry oui.txt | grep base
|
/*grep Raspberry oui.txt | grep base
|
||||||
DCA632 (base 16) Raspberry Pi Trading Ltd
|
DCA632 (base 16) Raspberry Pi Trading Ltd
|
||||||
E45F01 (base 16) Raspberry Pi Trading Ltd
|
E45F01 (base 16) Raspberry Pi Trading Ltd
|
||||||
B827EB (base 16) Raspberry Pi Foundation*/
|
B827EB (base 16) Raspberry Pi Foundation*/
|
||||||
if(foundOUI == "DCA632" || foundOUI == "E45F01" || foundOUI == "B827EB") {
|
if (foundOUI == "DCA632" || foundOUI == "E45F01" || foundOUI == "B827EB") {
|
||||||
imgName = ":/res/rpi.png";
|
imgName = ":/res/rpi.png";
|
||||||
}
|
}
|
||||||
QString needle = UDP_ANS_OWNER;
|
QString needle = UDP_ANS_OWNER;
|
||||||
QString owner = "???";
|
QString owner = "???";
|
||||||
int index = msg.indexOf(needle);
|
int index = msg.indexOf(needle);
|
||||||
if(index != -1){
|
if (index != -1) {
|
||||||
owner = msg.mid(index + needle.length());
|
owner = msg.mid(index + needle.length());
|
||||||
}else{
|
} else {
|
||||||
ui->pteLog->appendPlainText("Warning: no OWNER found in message");
|
ui->pteLog->appendPlainText("Warning: no OWNER found in message");
|
||||||
}
|
}
|
||||||
|
|
||||||
QListWidgetItem * item = searchItem(foundMAC);
|
QListWidgetItem* item = searchItem(foundMAC);
|
||||||
if(item == nullptr){
|
if (item == nullptr) {
|
||||||
item = new QListWidgetItem();
|
item = new QListWidgetItem();
|
||||||
ui->devices->addItem(item);
|
ui->devices->addItem(item);
|
||||||
}
|
}
|
||||||
item->setIcon(QIcon(imgName));
|
item->setIcon(QIcon(imgName));
|
||||||
item->setText(tr("%1 @ %2 (%3)").arg(foundMAC).arg(host).arg(owner));
|
item->setText(tr("%1 @ %2 (%3)").arg(foundMAC).arg(host).arg(owner));
|
||||||
item->setToolTip(tr("Last seen: %1").arg(QTime::currentTime().toString("H:mm:ss.zzz")));
|
item->setToolTip(tr("Last seen: %1").arg(QTime::currentTime().toString("H:mm:ss.zzz")));
|
||||||
}else{
|
} else {
|
||||||
ui->pteLog->appendPlainText("Warning: no MAC found in message");
|
ui->pteLog->appendPlainText("Warning: no MAC found in message");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QListWidgetItem *MainWindow::searchItem(QString MAC)
|
QListWidgetItem* MainWindow::searchItem(QString MAC) {
|
||||||
{
|
QListWidgetItem* item = nullptr;
|
||||||
QListWidgetItem * item = nullptr;
|
for (int i = 0; i < ui->devices->count(); i++) {
|
||||||
for(int i = 0; i < ui->devices->count(); i++){
|
|
||||||
item = ui->devices->item(i);
|
item = ui->devices->item(i);
|
||||||
if(item->text().contains(MAC)){
|
if (item->text().contains(MAC)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
item = nullptr;
|
item = nullptr;
|
||||||
@@ -189,70 +174,56 @@ QListWidgetItem *MainWindow::searchItem(QString MAC)
|
|||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_devices_itemDoubleClicked(QListWidgetItem *item)
|
void MainWindow::on_devices_itemDoubleClicked(QListWidgetItem* item) {
|
||||||
{
|
// Copy the IP to the clipboard
|
||||||
//Copy the IP to the clipboard
|
|
||||||
QString itemText = item->text();
|
QString itemText = item->text();
|
||||||
int start = itemText.indexOf('@')+2;
|
int start = itemText.indexOf('@') + 2;
|
||||||
int end = itemText.indexOf('(')-1;
|
int end = itemText.indexOf('(') - 1;
|
||||||
QString ip = itemText.mid(start,end - start);
|
QString ip = itemText.mid(start, end - start);
|
||||||
QClipboard *clipboard = QGuiApplication::clipboard();
|
QClipboard* clipboard = QGuiApplication::clipboard();
|
||||||
clipboard->setText(ip);
|
clipboard->setText(ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_devices_customContextMenuRequested(const QPoint &pos)
|
void MainWindow::on_devices_customContextMenuRequested(const QPoint& pos) {
|
||||||
{
|
// create menu
|
||||||
//create menu
|
QAction copyAction(QIcon(":/res/copy-icon.png"), "Copy IP");
|
||||||
QAction copyAction(QIcon(":/res/copy-icon.png"),"Copy IP");
|
|
||||||
QMenu menu;
|
QMenu menu;
|
||||||
menu.addAction(©Action);
|
menu.addAction(©Action);
|
||||||
|
|
||||||
//execute menu
|
// execute menu
|
||||||
QAction * action = menu.exec(ui->devices->mapToGlobal(pos));
|
QAction* action = menu.exec(ui->devices->mapToGlobal(pos));
|
||||||
if(action == ©Action){
|
if (action == ©Action) {
|
||||||
QListWidgetItem *item = ui->devices->itemAt(pos);
|
QListWidgetItem* item = ui->devices->itemAt(pos);
|
||||||
if(item){
|
if (item) {
|
||||||
on_devices_itemDoubleClicked(item);
|
on_devices_itemDoubleClicked(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_actionAbout_triggered()
|
void MainWindow::on_actionAbout_triggered() {
|
||||||
{
|
|
||||||
About ab(this);
|
About ab(this);
|
||||||
ab.exec();
|
ab.exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_name_textEdited(const QString &arg1)
|
void MainWindow::on_name_textEdited(const QString& arg1) {
|
||||||
{
|
|
||||||
this->name = arg1;
|
this->name = arg1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_surname_textEdited(const QString& arg1) {
|
||||||
|
|
||||||
void MainWindow::on_surname_textEdited(const QString &arg1)
|
|
||||||
{
|
|
||||||
this->surname = arg1;
|
this->surname = arg1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_comboBox_currentIndexChanged(int index) {
|
||||||
void MainWindow::on_comboBox_currentIndexChanged(int index)
|
if (index == 0) {
|
||||||
{
|
|
||||||
if(index == 0){
|
|
||||||
ui->ChangeOwner->setDisabled(true);
|
ui->ChangeOwner->setDisabled(true);
|
||||||
}
|
} else {
|
||||||
else{
|
|
||||||
ui->ChangeOwner->setDisabled(false);
|
ui->ChangeOwner->setDisabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_ChangeOwner_clicked() {
|
||||||
void MainWindow::on_ChangeOwner_clicked()
|
|
||||||
{
|
|
||||||
this->data = ("func1:name: " + this->name + ", surname: " + this->surname + "").toUtf8();
|
this->data = ("func1:name: " + this->name + ", surname: " + this->surname + "").toUtf8();
|
||||||
this->func = 1;
|
this->func = 1;
|
||||||
SendRequest();
|
SendRequest();
|
||||||
m_timer->start();
|
m_timer->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,52 +6,53 @@
|
|||||||
#include <QtWidgets>
|
#include <QtWidgets>
|
||||||
#define QD qDebug() << __FILE__ << __LINE__
|
#define QD qDebug() << __FILE__ << __LINE__
|
||||||
|
|
||||||
#include "about.h"
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include "about.h"
|
||||||
|
|
||||||
// UDP protocol:
|
// UDP protocol:
|
||||||
//REQ= Where are you?v1.0
|
// REQ= Where are you?v1.0
|
||||||
//ANS= XX:XX:XX:XX:XX:XX is present and my owner is YYYYYY ZZZZZZ
|
// ANS= XX:XX:XX:XX:XX:XX is present and my owner is YYYYYY ZZZZZZ
|
||||||
#define UDP_PORT 64000
|
#define UDP_PORT 64000
|
||||||
#define UDP_REQUEST "Where are you?"
|
#define UDP_REQUEST "Where are you?"
|
||||||
#define UDP_ANS_OWNER "my owner is "
|
#define UDP_ANS_OWNER "my owner is "
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
namespace Ui { class MainWindow; }
|
namespace Ui {
|
||||||
|
class MainWindow;
|
||||||
|
}
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
class MainWindow : public QMainWindow
|
class MainWindow : public QMainWindow {
|
||||||
{
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MainWindow(QWidget *parent = nullptr);
|
MainWindow(QWidget* parent = nullptr);
|
||||||
~MainWindow();
|
~MainWindow();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void SendRequest();
|
void SendRequest();
|
||||||
void processPendingDatagrams();
|
void processPendingDatagrams();
|
||||||
|
|
||||||
void on_pbRefresh_clicked();
|
void on_pbRefresh_clicked();
|
||||||
void on_devices_itemDoubleClicked(QListWidgetItem *item);
|
void on_devices_itemDoubleClicked(QListWidgetItem* item);
|
||||||
void on_devices_customContextMenuRequested(const QPoint &pos);
|
void on_devices_customContextMenuRequested(const QPoint& pos);
|
||||||
|
|
||||||
void on_actionAbout_triggered();
|
void on_actionAbout_triggered();
|
||||||
|
|
||||||
void on_name_textEdited(const QString &arg1);
|
void on_name_textEdited(const QString& arg1);
|
||||||
|
|
||||||
void on_surname_textEdited(const QString &arg1);
|
void on_surname_textEdited(const QString& arg1);
|
||||||
|
|
||||||
void on_comboBox_currentIndexChanged(int index);
|
void on_comboBox_currentIndexChanged(int index);
|
||||||
|
|
||||||
void on_ChangeOwner_clicked();
|
void on_ChangeOwner_clicked();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::MainWindow *ui;
|
Ui::MainWindow* ui;
|
||||||
QTimer * m_timer;
|
QTimer* m_timer;
|
||||||
QUdpSocket *m_udpSocket = nullptr;
|
QUdpSocket* m_udpSocket = nullptr;
|
||||||
void processDatagram(QString msg, QString host);
|
void processDatagram(QString msg, QString host);
|
||||||
QListWidgetItem *searchItem(QString MAC);
|
QListWidgetItem* searchItem(QString MAC);
|
||||||
QString name;
|
QString name;
|
||||||
QString surname;
|
QString surname;
|
||||||
QByteArray data;
|
QByteArray data;
|
||||||
|
|||||||
BIN
llfs-data/base.bmp
Normal file
|
After Width: | Height: | Size: 79 KiB |
BIN
llfs-data/clap.gif
Normal file
|
After Width: | Height: | Size: 59 KiB |
BIN
llfs-data/dafoe.bmp
Normal file
|
After Width: | Height: | Size: 97 KiB |
BIN
llfs-data/fellowkids.bmp
Normal file
|
After Width: | Height: | Size: 94 KiB |
BIN
llfs-data/goose.bmp
Normal file
|
After Width: | Height: | Size: 117 KiB |
122
llfs-data/index.css
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
body{
|
||||||
|
font-family:Arial;
|
||||||
|
}
|
||||||
|
h1{
|
||||||
|
font-size: 175%;
|
||||||
|
padding: 10px;
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
font-size: 150%;
|
||||||
|
padding: 8px;
|
||||||
|
position: absolute;
|
||||||
|
top: -6px;
|
||||||
|
left: 20px;
|
||||||
|
background-color:orangered;
|
||||||
|
color: white;
|
||||||
|
border-radius: 20px;
|
||||||
|
padding-left: 30px;
|
||||||
|
padding-right: 30px;
|
||||||
|
}
|
||||||
|
h3 {
|
||||||
|
font-size: 125%;
|
||||||
|
padding: 10px;
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
padding: 10px;
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
header {
|
||||||
|
padding: 30px;
|
||||||
|
background-color: orangered;
|
||||||
|
}
|
||||||
|
header:after {
|
||||||
|
content:"";
|
||||||
|
display: block;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
.logo{
|
||||||
|
width:100px;
|
||||||
|
transform:rotate(-10deg);
|
||||||
|
-moz-transform:rotate(-10deg);
|
||||||
|
-webkit-transform:rotate(-10deg);
|
||||||
|
-o-transform:rotate(-10deg);
|
||||||
|
float:left;
|
||||||
|
}
|
||||||
|
.title{
|
||||||
|
color: white;
|
||||||
|
font-size: 40px;
|
||||||
|
font: 60px "Lucida Sans Unicode", "Lucida Grande", sans-serif;
|
||||||
|
text-align: center;
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
.column {
|
||||||
|
flex-grow: 0;
|
||||||
|
flex-basis: 48%;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.right {
|
||||||
|
margin-left: 2%;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
padding: 20px;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
/*Geef vorm aan de vakjes op de site*/
|
||||||
|
.card {
|
||||||
|
background-color: white;
|
||||||
|
border-radius:10px;
|
||||||
|
padding:1%;
|
||||||
|
border: 1px solid black;
|
||||||
|
margin: 2% 0;
|
||||||
|
width: 100%;
|
||||||
|
padding-top: 30px;
|
||||||
|
}
|
||||||
|
.image {
|
||||||
|
width: 25%;
|
||||||
|
height: auto;
|
||||||
|
border: 10px solid transparent;
|
||||||
|
}
|
||||||
|
.image:hover {
|
||||||
|
border: 10px solid lightsalmon;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
#selected {
|
||||||
|
border: 10px solid lightsalmon;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
.sendButton {
|
||||||
|
position: absolute;
|
||||||
|
margin-top: 8%;
|
||||||
|
text-align: center;
|
||||||
|
margin-left: 40%;
|
||||||
|
font-size: 150%;
|
||||||
|
padding: 20px;
|
||||||
|
background-color:orangered;
|
||||||
|
color: white;
|
||||||
|
border-radius: 20px;
|
||||||
|
}
|
||||||
|
.sendButton:hover {
|
||||||
|
background-color:white;
|
||||||
|
color: orangered ;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------------------*/
|
||||||
|
footer {
|
||||||
|
background-color: orangered;
|
||||||
|
padding: 20px;
|
||||||
|
text-align: center;
|
||||||
|
border-top:20px solid lightskyblue; /*solid is vast*/
|
||||||
|
border-bottom:20px solid lightskyblue;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
.foot {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
html{
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
#myImg {
|
||||||
|
border: none;
|
||||||
|
transition: border 0.3s;
|
||||||
|
}
|
||||||
133
llfs-data/index.html
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>Webservices & Applications</title>
|
||||||
|
<link href="reset.css" rel="stylesheet" />
|
||||||
|
<link href="index.css" rel="stylesheet" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
<header>
|
||||||
|
<img class="logo" src="st.bmp" alt="STM"/>
|
||||||
|
<p class="title">
|
||||||
|
Webservices & Applications
|
||||||
|
</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<form action="cgi">
|
||||||
|
<div class="content row">
|
||||||
|
<div class="column left">
|
||||||
|
<div class="card">
|
||||||
|
<h2>Adjustments</h2>
|
||||||
|
<label for="send_text">Text LCD:</label>
|
||||||
|
<input type="text" id="send_text" name="vtxt"><br><br>
|
||||||
|
<label for="send_colorTxt">Select the text color:</label>
|
||||||
|
<input type="color" id="send_colorTxt" name="vktxt" value="#0000ff"><br><br>
|
||||||
|
<label for="send_colorBack">Select the background color:</label>
|
||||||
|
<input type="color" id="send_colorBack" name="vka" value="#0000ff"><br><br>
|
||||||
|
<!--<span class="sendButton" onClick="start();">
|
||||||
|
<input type="submit" value="Send">
|
||||||
|
</span>-->
|
||||||
|
<input type="submit" value="Send" class="sendButton" onClick="start();">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="column right">
|
||||||
|
<div class="card">
|
||||||
|
<h2 >Images</h2>
|
||||||
|
<label for="vfo">Choose your photo:</label>
|
||||||
|
<div class="gallery" id="gallery">
|
||||||
|
<input type="hidden" id="gallery1" name="vfo" value="">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
document.getElementById('send_colorBack').addEventListener('input', function() { document.body.style.backgroundColor = this.value; });
|
||||||
|
document.getElementById('send_colorTxt').addEventListener('input', function() { document.getElementById('send_text').style.color = this.value; });
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------*/
|
||||||
|
|
||||||
|
// Function to load images from the folder
|
||||||
|
function loadImages() {
|
||||||
|
console.log("loadImages");
|
||||||
|
const xhttp = new XMLHttpRequest();
|
||||||
|
|
||||||
|
xhttp.onload = function() {
|
||||||
|
const imageContainer = document.getElementById('gallery');
|
||||||
|
console.log(this.responseText);
|
||||||
|
images = this.responseText.split('|');
|
||||||
|
console.log(images);
|
||||||
|
for (let i = 0; i < images.length; i++) {
|
||||||
|
console.log(images[i]);
|
||||||
|
const img = document.createElement('img');;
|
||||||
|
img.src= images[i];
|
||||||
|
img.alt = images[i];
|
||||||
|
img.className = `image ${i}`;
|
||||||
|
img.value = images[i];
|
||||||
|
img.onload = () => {
|
||||||
|
imageContainer.appendChild(img);
|
||||||
|
}
|
||||||
|
img.onclick = () => {
|
||||||
|
selecteerFoto(img, i, images[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xhttp.open("GET", "images.info");
|
||||||
|
xhttp.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
function selecteerFoto(image, i, images) {
|
||||||
|
var gallery = document.getElementById('gallery1');
|
||||||
|
var value = gallery.getAttribute('value');
|
||||||
|
var Pictures = document.querySelectorAll('.gallery img');
|
||||||
|
Pictures.forEach(function(image) {
|
||||||
|
image.removeAttribute('id');
|
||||||
|
image.removeAttribute('name');
|
||||||
|
});
|
||||||
|
image.id = "selected";
|
||||||
|
image.name = "vfo";
|
||||||
|
image.value = images[i];
|
||||||
|
gallery.setAttribute('value', images);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call the function to load the images
|
||||||
|
loadImages();
|
||||||
|
const xhr = new XMLHttpRequest();
|
||||||
|
|
||||||
|
function start() {
|
||||||
|
var send_text = document.getElementById("send_text").value;
|
||||||
|
var send_colorTxt = document.getElementById("send_colorTxt").value;
|
||||||
|
var send_colorBack = document.getElementById("send_colorBack").value;
|
||||||
|
var sendPicture = document.getElementById("selected").alt;
|
||||||
|
var url = "cgi?";
|
||||||
|
|
||||||
|
var queryString = url + "vtxt=" + send_text + "&vktxt=" + encodeURIComponent(send_colorTxt) + "&vka=" + encodeURIComponent(send_colorBack) + "&vfo=" + sendPicture;
|
||||||
|
console.log(queryString);
|
||||||
|
|
||||||
|
xhr.onreadystatechange = showAnswer;
|
||||||
|
xhr.open("GET", queryString);
|
||||||
|
xhr.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
function showAnswer() {
|
||||||
|
if (xhr.readyState == 4 && xhr.status == 200) {
|
||||||
|
alert(xhr.responseText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<footer>
|
||||||
|
<p class="foot">
|
||||||
|
Copyright © Thomas More Mechelen-Antwerpen vzw -
|
||||||
|
Campus De Nayer - Professionele bachelor elektronica-ict –
|
||||||
|
2023
|
||||||
|
</p>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
BIN
llfs-data/mind.gif
Normal file
|
After Width: | Height: | Size: 3.3 MiB |
62
llfs-data/reset.css
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
/* http://meyerweb.com/eric/tools/css/reset/
|
||||||
|
v2.0b1 | 201101
|
||||||
|
NOTE: WORK IN PROGRESS
|
||||||
|
USE WITH CAUTION AND TEST WITH ABANDON */
|
||||||
|
|
||||||
|
html, body, div, span, applet, object, iframe,
|
||||||
|
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||||
|
a, abbr, acronym, address, big, cite, code,
|
||||||
|
del, dfn, em, img, ins, kbd, q, s, samp,
|
||||||
|
small, strike, strong, sub, sup, tt, var,
|
||||||
|
b, u, i, center,
|
||||||
|
dl, dt, dd, ol, ul, li,
|
||||||
|
fieldset, form, label, legend,
|
||||||
|
table, caption, tbody, tfoot, thead, tr, th, td,
|
||||||
|
article, aside, canvas, details, figcaption, figure,
|
||||||
|
footer, header, hgroup, menu, nav, section, summary,
|
||||||
|
time, mark, audio, video {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
outline: 0;
|
||||||
|
font-size: 100%;
|
||||||
|
font: inherit;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
/* HTML5 display-role reset for older browsers */
|
||||||
|
article, aside, details, figcaption, figure,
|
||||||
|
footer, header, hgroup, menu, nav, section {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
ol, ul {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
blockquote, q {
|
||||||
|
quotes: none;
|
||||||
|
}
|
||||||
|
blockquote:before, blockquote:after,
|
||||||
|
q:before, q:after {
|
||||||
|
content: '';
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remember to define visible focus styles!
|
||||||
|
:focus {
|
||||||
|
outline: ?????;
|
||||||
|
} */
|
||||||
|
|
||||||
|
/* remember to highlight inserts somehow! */
|
||||||
|
ins {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
del {
|
||||||
|
text-decoration: line-through;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
BIN
llfs-data/webp.bmp
Normal file
|
After Width: | Height: | Size: 114 KiB |
@@ -60,11 +60,12 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write the header of the output file
|
// Write the header of the output file
|
||||||
fprintf(out_file, "/**\n"
|
fprintf(out_file,
|
||||||
" * @file %s\n"
|
"/**\n"
|
||||||
" * @brief Linked list file system (llfs) data file.\n"
|
" * @file %s\n"
|
||||||
" * This file was generated by mkllfs %s.\n"
|
" * @brief Linked list file system (llfs) data file.\n"
|
||||||
" * @date %s\n */\n\n",
|
" * This file was generated by mkllfs %s.\n"
|
||||||
|
" * @date %s\n */\n\n",
|
||||||
argv[argc - 1], VERSION, __DATE__);
|
argv[argc - 1], VERSION, __DATE__);
|
||||||
|
|
||||||
// Write the headers of the output file
|
// Write the headers of the output file
|
||||||
@@ -125,7 +126,8 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
// Make the last file the root file of the llfs
|
// Make the last file the root file of the llfs
|
||||||
fprintf(out_file, "\n");
|
fprintf(out_file, "\n");
|
||||||
fprintf(out_file, "const struct llfs_data_file *llfs_root =%s%s;\n", (strcmp(prev_llfs_name, "NULL") == 0 ? " " : " &"), prev_llfs_name);
|
fprintf(out_file, "const struct llfs_data_file *llfs_root =%s%s;\n",
|
||||||
|
(strcmp(prev_llfs_name, "NULL") == 0 ? " " : " &"), prev_llfs_name);
|
||||||
|
|
||||||
// Print the number of files
|
// Print the number of files
|
||||||
printf("Successfully converted %d files.\r\n", file_count);
|
printf("Successfully converted %d files.\r\n", file_count);
|
||||||
|
|||||||
543
mkllfs/tinydir.h
@@ -45,63 +45,62 @@ extern "C" {
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
# ifndef WIN32_LEAN_AND_MEAN
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
# define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
# endif
|
#endif
|
||||||
# include <windows.h>
|
#include <tchar.h>
|
||||||
# include <tchar.h>
|
#include <windows.h>
|
||||||
# pragma warning(push)
|
#pragma warning(push)
|
||||||
# pragma warning (disable : 4996)
|
#pragma warning(disable : 4996)
|
||||||
#else
|
#else
|
||||||
# include <dirent.h>
|
#include <dirent.h>
|
||||||
# include <libgen.h>
|
#include <libgen.h>
|
||||||
# include <sys/stat.h>
|
#include <stddef.h>
|
||||||
# include <stddef.h>
|
#include <sys/stat.h>
|
||||||
#endif
|
#endif
|
||||||
#ifdef __MINGW32__
|
#ifdef __MINGW32__
|
||||||
# include <tchar.h>
|
#include <tchar.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* types */
|
/* types */
|
||||||
|
|
||||||
/* Windows UNICODE wide character support */
|
/* Windows UNICODE wide character support */
|
||||||
#if defined _MSC_VER || defined __MINGW32__
|
#if defined _MSC_VER || defined __MINGW32__
|
||||||
# define _tinydir_char_t TCHAR
|
#define _tinydir_char_t TCHAR
|
||||||
# define TINYDIR_STRING(s) _TEXT(s)
|
#define TINYDIR_STRING(s) _TEXT(s)
|
||||||
# define _tinydir_strlen _tcslen
|
#define _tinydir_strlen _tcslen
|
||||||
# define _tinydir_strcpy _tcscpy
|
#define _tinydir_strcpy _tcscpy
|
||||||
# define _tinydir_strcat _tcscat
|
#define _tinydir_strcat _tcscat
|
||||||
# define _tinydir_strcmp _tcscmp
|
#define _tinydir_strcmp _tcscmp
|
||||||
# define _tinydir_strrchr _tcsrchr
|
#define _tinydir_strrchr _tcsrchr
|
||||||
# define _tinydir_strncmp _tcsncmp
|
#define _tinydir_strncmp _tcsncmp
|
||||||
#else
|
#else
|
||||||
# define _tinydir_char_t char
|
#define _tinydir_char_t char
|
||||||
# define TINYDIR_STRING(s) s
|
#define TINYDIR_STRING(s) s
|
||||||
# define _tinydir_strlen strlen
|
#define _tinydir_strlen strlen
|
||||||
# define _tinydir_strcpy strcpy
|
#define _tinydir_strcpy strcpy
|
||||||
# define _tinydir_strcat strcat
|
#define _tinydir_strcat strcat
|
||||||
# define _tinydir_strcmp strcmp
|
#define _tinydir_strcmp strcmp
|
||||||
# define _tinydir_strrchr strrchr
|
#define _tinydir_strrchr strrchr
|
||||||
# define _tinydir_strncmp strncmp
|
#define _tinydir_strncmp strncmp
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (defined _MSC_VER || defined __MINGW32__)
|
#if (defined _MSC_VER || defined __MINGW32__)
|
||||||
# include <windows.h>
|
#include <windows.h>
|
||||||
# define _TINYDIR_PATH_MAX MAX_PATH
|
#define _TINYDIR_PATH_MAX MAX_PATH
|
||||||
#elif defined __linux__
|
#elif defined __linux__
|
||||||
# include <limits.h>
|
#include <limits.h>
|
||||||
# ifdef PATH_MAX
|
#ifdef PATH_MAX
|
||||||
# define _TINYDIR_PATH_MAX PATH_MAX
|
#define _TINYDIR_PATH_MAX PATH_MAX
|
||||||
# endif
|
#endif
|
||||||
#elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
|
#elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
|
||||||
# include <sys/param.h>
|
#include <sys/param.h>
|
||||||
# if defined(BSD)
|
#if defined(BSD)
|
||||||
# include <limits.h>
|
#include <limits.h>
|
||||||
# ifdef PATH_MAX
|
#ifdef PATH_MAX
|
||||||
# define _TINYDIR_PATH_MAX PATH_MAX
|
#define _TINYDIR_PATH_MAX PATH_MAX
|
||||||
# endif
|
#endif
|
||||||
# endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef _TINYDIR_PATH_MAX
|
#ifndef _TINYDIR_PATH_MAX
|
||||||
@@ -110,9 +109,9 @@ extern "C" {
|
|||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
/* extra chars for the "\\*" mask */
|
/* extra chars for the "\\*" mask */
|
||||||
# define _TINYDIR_PATH_EXTRA 2
|
#define _TINYDIR_PATH_EXTRA 2
|
||||||
#else
|
#else
|
||||||
# define _TINYDIR_PATH_EXTRA 0
|
#define _TINYDIR_PATH_EXTRA 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define _TINYDIR_FILENAME_MAX 256
|
#define _TINYDIR_FILENAME_MAX 256
|
||||||
@@ -122,16 +121,16 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
# define _TINYDIR_FUNC static __inline
|
#define _TINYDIR_FUNC static __inline
|
||||||
#elif !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L
|
#elif !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L
|
||||||
# define _TINYDIR_FUNC static __inline__
|
#define _TINYDIR_FUNC static __inline__
|
||||||
#elif defined(__cplusplus)
|
#elif defined(__cplusplus)
|
||||||
# define _TINYDIR_FUNC static inline
|
#define _TINYDIR_FUNC static inline
|
||||||
#elif defined(__GNUC__)
|
#elif defined(__GNUC__)
|
||||||
/* Suppress unused function warning */
|
/* Suppress unused function warning */
|
||||||
# define _TINYDIR_FUNC __attribute__((unused)) static
|
#define _TINYDIR_FUNC __attribute__((unused)) static
|
||||||
#else
|
#else
|
||||||
# define _TINYDIR_FUNC static
|
#define _TINYDIR_FUNC static
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* readdir_r usage; define TINYDIR_USE_READDIR_R to use it (if supported) */
|
/* readdir_r usage; define TINYDIR_USE_READDIR_R to use it (if supported) */
|
||||||
@@ -139,52 +138,48 @@ extern "C" {
|
|||||||
|
|
||||||
/* readdir_r is a POSIX-only function, and may not be available under various
|
/* readdir_r is a POSIX-only function, and may not be available under various
|
||||||
* environments/settings, e.g. MinGW. Use readdir fallback */
|
* environments/settings, e.g. MinGW. Use readdir fallback */
|
||||||
#if _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE ||\
|
#if _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE || _POSIX_SOURCE
|
||||||
_POSIX_SOURCE
|
#define _TINYDIR_HAS_READDIR_R
|
||||||
# define _TINYDIR_HAS_READDIR_R
|
|
||||||
#endif
|
#endif
|
||||||
#if _POSIX_C_SOURCE >= 200112L
|
#if _POSIX_C_SOURCE >= 200112L
|
||||||
# define _TINYDIR_HAS_FPATHCONF
|
#define _TINYDIR_HAS_FPATHCONF
|
||||||
# include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
#if _BSD_SOURCE || _SVID_SOURCE || \
|
#if _BSD_SOURCE || _SVID_SOURCE || (_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700)
|
||||||
(_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700)
|
#define _TINYDIR_HAS_DIRFD
|
||||||
# define _TINYDIR_HAS_DIRFD
|
#include <sys/types.h>
|
||||||
# include <sys/types.h>
|
|
||||||
#endif
|
#endif
|
||||||
#if defined _TINYDIR_HAS_FPATHCONF && defined _TINYDIR_HAS_DIRFD &&\
|
#if defined _TINYDIR_HAS_FPATHCONF && defined _TINYDIR_HAS_DIRFD && defined _PC_NAME_MAX
|
||||||
defined _PC_NAME_MAX
|
#define _TINYDIR_USE_FPATHCONF
|
||||||
# define _TINYDIR_USE_FPATHCONF
|
|
||||||
#endif
|
#endif
|
||||||
#if defined __MINGW32__ || !defined _TINYDIR_HAS_READDIR_R ||\
|
#if defined __MINGW32__ || !defined _TINYDIR_HAS_READDIR_R || !(defined _TINYDIR_USE_FPATHCONF || defined NAME_MAX)
|
||||||
!(defined _TINYDIR_USE_FPATHCONF || defined NAME_MAX)
|
#define _TINYDIR_USE_READDIR
|
||||||
# define _TINYDIR_USE_READDIR
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Use readdir by default */
|
/* Use readdir by default */
|
||||||
#else
|
#else
|
||||||
# define _TINYDIR_USE_READDIR
|
#define _TINYDIR_USE_READDIR
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* MINGW32 has two versions of dirent, ASCII and UNICODE*/
|
/* MINGW32 has two versions of dirent, ASCII and UNICODE*/
|
||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
#if (defined __MINGW32__) && (defined _UNICODE)
|
#if (defined __MINGW32__) && (defined _UNICODE)
|
||||||
#define _TINYDIR_DIR _WDIR
|
#define _TINYDIR_DIR _WDIR
|
||||||
#define _tinydir_dirent _wdirent
|
#define _tinydir_dirent _wdirent
|
||||||
#define _tinydir_opendir _wopendir
|
#define _tinydir_opendir _wopendir
|
||||||
#define _tinydir_readdir _wreaddir
|
#define _tinydir_readdir _wreaddir
|
||||||
#define _tinydir_closedir _wclosedir
|
#define _tinydir_closedir _wclosedir
|
||||||
#else
|
#else
|
||||||
#define _TINYDIR_DIR DIR
|
#define _TINYDIR_DIR DIR
|
||||||
#define _tinydir_dirent dirent
|
#define _tinydir_dirent dirent
|
||||||
#define _tinydir_opendir opendir
|
#define _tinydir_opendir opendir
|
||||||
#define _tinydir_readdir readdir
|
#define _tinydir_readdir readdir
|
||||||
#define _tinydir_closedir closedir
|
#define _tinydir_closedir closedir
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Allow user to use a custom allocator by defining _TINYDIR_MALLOC and _TINYDIR_FREE. */
|
/* Allow user to use a custom allocator by defining _TINYDIR_MALLOC and _TINYDIR_FREE. */
|
||||||
#if defined(_TINYDIR_MALLOC) && defined(_TINYDIR_FREE)
|
#if defined(_TINYDIR_MALLOC) && defined(_TINYDIR_FREE)
|
||||||
#elif !defined(_TINYDIR_MALLOC) && !defined(_TINYDIR_FREE)
|
#elif !defined(_TINYDIR_MALLOC) && !defined(_TINYDIR_FREE)
|
||||||
#else
|
#else
|
||||||
#error "Either define both alloc and free or none of them!"
|
#error "Either define both alloc and free or none of them!"
|
||||||
@@ -195,11 +190,10 @@ extern "C" {
|
|||||||
#define _TINYDIR_FREE(_ptr) free(_ptr)
|
#define _TINYDIR_FREE(_ptr) free(_ptr)
|
||||||
#endif /* !defined(_TINYDIR_MALLOC) */
|
#endif /* !defined(_TINYDIR_MALLOC) */
|
||||||
|
|
||||||
typedef struct tinydir_file
|
typedef struct tinydir_file {
|
||||||
{
|
|
||||||
_tinydir_char_t path[_TINYDIR_PATH_MAX];
|
_tinydir_char_t path[_TINYDIR_PATH_MAX];
|
||||||
_tinydir_char_t name[_TINYDIR_FILENAME_MAX];
|
_tinydir_char_t name[_TINYDIR_FILENAME_MAX];
|
||||||
_tinydir_char_t *extension;
|
_tinydir_char_t* extension;
|
||||||
int is_dir;
|
int is_dir;
|
||||||
int is_reg;
|
int is_reg;
|
||||||
|
|
||||||
@@ -212,80 +206,74 @@ typedef struct tinydir_file
|
|||||||
#endif
|
#endif
|
||||||
} tinydir_file;
|
} tinydir_file;
|
||||||
|
|
||||||
typedef struct tinydir_dir
|
typedef struct tinydir_dir {
|
||||||
{
|
|
||||||
_tinydir_char_t path[_TINYDIR_PATH_MAX];
|
_tinydir_char_t path[_TINYDIR_PATH_MAX];
|
||||||
int has_next;
|
int has_next;
|
||||||
size_t n_files;
|
size_t n_files;
|
||||||
|
|
||||||
tinydir_file *_files;
|
tinydir_file* _files;
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
HANDLE _h;
|
HANDLE _h;
|
||||||
WIN32_FIND_DATA _f;
|
WIN32_FIND_DATA _f;
|
||||||
#else
|
#else
|
||||||
_TINYDIR_DIR *_d;
|
_TINYDIR_DIR* _d;
|
||||||
struct _tinydir_dirent *_e;
|
struct _tinydir_dirent* _e;
|
||||||
#ifndef _TINYDIR_USE_READDIR
|
#ifndef _TINYDIR_USE_READDIR
|
||||||
struct _tinydir_dirent *_ep;
|
struct _tinydir_dirent* _ep;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
} tinydir_dir;
|
} tinydir_dir;
|
||||||
|
|
||||||
|
|
||||||
/* declarations */
|
/* declarations */
|
||||||
|
|
||||||
_TINYDIR_FUNC
|
_TINYDIR_FUNC
|
||||||
int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path);
|
int tinydir_open(tinydir_dir* dir, const _tinydir_char_t* path);
|
||||||
_TINYDIR_FUNC
|
_TINYDIR_FUNC
|
||||||
int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path);
|
int tinydir_open_sorted(tinydir_dir* dir, const _tinydir_char_t* path);
|
||||||
_TINYDIR_FUNC
|
_TINYDIR_FUNC
|
||||||
void tinydir_close(tinydir_dir *dir);
|
void tinydir_close(tinydir_dir* dir);
|
||||||
|
|
||||||
_TINYDIR_FUNC
|
_TINYDIR_FUNC
|
||||||
int tinydir_next(tinydir_dir *dir);
|
int tinydir_next(tinydir_dir* dir);
|
||||||
_TINYDIR_FUNC
|
_TINYDIR_FUNC
|
||||||
int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file);
|
int tinydir_readfile(const tinydir_dir* dir, tinydir_file* file);
|
||||||
_TINYDIR_FUNC
|
_TINYDIR_FUNC
|
||||||
int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i);
|
int tinydir_readfile_n(const tinydir_dir* dir, tinydir_file* file, size_t i);
|
||||||
_TINYDIR_FUNC
|
_TINYDIR_FUNC
|
||||||
int tinydir_open_subdir_n(tinydir_dir *dir, size_t i);
|
int tinydir_open_subdir_n(tinydir_dir* dir, size_t i);
|
||||||
|
|
||||||
_TINYDIR_FUNC
|
_TINYDIR_FUNC
|
||||||
int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path);
|
int tinydir_file_open(tinydir_file* file, const _tinydir_char_t* path);
|
||||||
_TINYDIR_FUNC
|
_TINYDIR_FUNC
|
||||||
void _tinydir_get_ext(tinydir_file *file);
|
void _tinydir_get_ext(tinydir_file* file);
|
||||||
_TINYDIR_FUNC
|
_TINYDIR_FUNC
|
||||||
int _tinydir_file_cmp(const void *a, const void *b);
|
int _tinydir_file_cmp(const void* a, const void* b);
|
||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
#ifndef _TINYDIR_USE_READDIR
|
#ifndef _TINYDIR_USE_READDIR
|
||||||
_TINYDIR_FUNC
|
_TINYDIR_FUNC
|
||||||
size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp);
|
size_t _tinydir_dirent_buf_size(_TINYDIR_DIR* dirp);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* definitions*/
|
/* definitions*/
|
||||||
|
|
||||||
_TINYDIR_FUNC
|
_TINYDIR_FUNC
|
||||||
int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path)
|
int tinydir_open(tinydir_dir* dir, const _tinydir_char_t* path) {
|
||||||
{
|
|
||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
#ifndef _TINYDIR_USE_READDIR
|
#ifndef _TINYDIR_USE_READDIR
|
||||||
int error;
|
int error;
|
||||||
int size; /* using int size */
|
int size; /* using int size */
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
_tinydir_char_t path_buf[_TINYDIR_PATH_MAX];
|
_tinydir_char_t path_buf[_TINYDIR_PATH_MAX];
|
||||||
#endif
|
#endif
|
||||||
_tinydir_char_t *pathp;
|
_tinydir_char_t* pathp;
|
||||||
|
|
||||||
if (dir == NULL || path == NULL || _tinydir_strlen(path) == 0)
|
if (dir == NULL || path == NULL || _tinydir_strlen(path) == 0) {
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
|
if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX) {
|
||||||
{
|
|
||||||
errno = ENAMETOOLONG;
|
errno = ENAMETOOLONG;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -305,26 +293,23 @@ int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path)
|
|||||||
_tinydir_strcpy(dir->path, path);
|
_tinydir_strcpy(dir->path, path);
|
||||||
/* Remove trailing slashes */
|
/* Remove trailing slashes */
|
||||||
pathp = &dir->path[_tinydir_strlen(dir->path) - 1];
|
pathp = &dir->path[_tinydir_strlen(dir->path) - 1];
|
||||||
while (pathp != dir->path && (*pathp == TINYDIR_STRING('\\') || *pathp == TINYDIR_STRING('/')))
|
while (pathp != dir->path && (*pathp == TINYDIR_STRING('\\') || *pathp == TINYDIR_STRING('/'))) {
|
||||||
{
|
|
||||||
*pathp = TINYDIR_STRING('\0');
|
*pathp = TINYDIR_STRING('\0');
|
||||||
pathp++;
|
pathp++;
|
||||||
}
|
}
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
_tinydir_strcpy(path_buf, dir->path);
|
_tinydir_strcpy(path_buf, dir->path);
|
||||||
_tinydir_strcat(path_buf, TINYDIR_STRING("\\*"));
|
_tinydir_strcat(path_buf, TINYDIR_STRING("\\*"));
|
||||||
#if (defined WINAPI_FAMILY) && (WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP)
|
#if (defined WINAPI_FAMILY) && (WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP)
|
||||||
dir->_h = FindFirstFileEx(path_buf, FindExInfoStandard, &dir->_f, FindExSearchNameMatch, NULL, 0);
|
dir->_h = FindFirstFileEx(path_buf, FindExInfoStandard, &dir->_f, FindExSearchNameMatch, NULL, 0);
|
||||||
#else
|
#else
|
||||||
dir->_h = FindFirstFile(path_buf, &dir->_f);
|
dir->_h = FindFirstFile(path_buf, &dir->_f);
|
||||||
#endif
|
#endif
|
||||||
if (dir->_h == INVALID_HANDLE_VALUE)
|
if (dir->_h == INVALID_HANDLE_VALUE) {
|
||||||
{
|
errno = ENOENT;
|
||||||
errno = ENOENT;
|
|
||||||
#else
|
#else
|
||||||
dir->_d = _tinydir_opendir(path);
|
dir->_d = _tinydir_opendir(path);
|
||||||
if (dir->_d == NULL)
|
if (dir->_d == NULL) {
|
||||||
{
|
|
||||||
#endif
|
#endif
|
||||||
goto bail;
|
goto bail;
|
||||||
}
|
}
|
||||||
@@ -336,77 +321,69 @@ int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path)
|
|||||||
dir->_e = _tinydir_readdir(dir->_d);
|
dir->_e = _tinydir_readdir(dir->_d);
|
||||||
#else
|
#else
|
||||||
/* allocate dirent buffer for readdir_r */
|
/* allocate dirent buffer for readdir_r */
|
||||||
size = _tinydir_dirent_buf_size(dir->_d); /* conversion to int */
|
size = _tinydir_dirent_buf_size(dir->_d); /* conversion to int */
|
||||||
if (size == -1) return -1;
|
if (size == -1)
|
||||||
dir->_ep = (struct _tinydir_dirent*)_TINYDIR_MALLOC(size);
|
return -1;
|
||||||
if (dir->_ep == NULL) return -1;
|
dir->_ep = (struct _tinydir_dirent*)_TINYDIR_MALLOC(size);
|
||||||
|
if (dir->_ep == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
error = readdir_r(dir->_d, dir->_ep, &dir->_e);
|
error = readdir_r(dir->_d, dir->_ep, &dir->_e);
|
||||||
if (error != 0) return -1;
|
if (error != 0)
|
||||||
|
return -1;
|
||||||
#endif
|
#endif
|
||||||
if (dir->_e == NULL)
|
if (dir->_e == NULL) {
|
||||||
{
|
|
||||||
dir->has_next = 0;
|
dir->has_next = 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
bail:
|
bail:
|
||||||
tinydir_close(dir);
|
tinydir_close(dir);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
_TINYDIR_FUNC
|
_TINYDIR_FUNC
|
||||||
int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path)
|
int tinydir_open_sorted(tinydir_dir* dir, const _tinydir_char_t* path) {
|
||||||
{
|
|
||||||
/* Count the number of files first, to pre-allocate the files array */
|
/* Count the number of files first, to pre-allocate the files array */
|
||||||
size_t n_files = 0;
|
size_t n_files = 0;
|
||||||
if (tinydir_open(dir, path) == -1)
|
if (tinydir_open(dir, path) == -1) {
|
||||||
{
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
while (dir->has_next)
|
while (dir->has_next) {
|
||||||
{
|
|
||||||
n_files++;
|
n_files++;
|
||||||
if (tinydir_next(dir) == -1)
|
if (tinydir_next(dir) == -1) {
|
||||||
{
|
|
||||||
goto bail;
|
goto bail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tinydir_close(dir);
|
tinydir_close(dir);
|
||||||
|
|
||||||
if (n_files == 0 || tinydir_open(dir, path) == -1)
|
if (n_files == 0 || tinydir_open(dir, path) == -1) {
|
||||||
{
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
dir->n_files = 0;
|
dir->n_files = 0;
|
||||||
dir->_files = (tinydir_file *)_TINYDIR_MALLOC(sizeof *dir->_files * n_files);
|
dir->_files = (tinydir_file*)_TINYDIR_MALLOC(sizeof *dir->_files * n_files);
|
||||||
if (dir->_files == NULL)
|
if (dir->_files == NULL) {
|
||||||
{
|
|
||||||
goto bail;
|
goto bail;
|
||||||
}
|
}
|
||||||
while (dir->has_next)
|
while (dir->has_next) {
|
||||||
{
|
tinydir_file* p_file;
|
||||||
tinydir_file *p_file;
|
|
||||||
dir->n_files++;
|
dir->n_files++;
|
||||||
|
|
||||||
p_file = &dir->_files[dir->n_files - 1];
|
p_file = &dir->_files[dir->n_files - 1];
|
||||||
if (tinydir_readfile(dir, p_file) == -1)
|
if (tinydir_readfile(dir, p_file) == -1) {
|
||||||
{
|
|
||||||
goto bail;
|
goto bail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tinydir_next(dir) == -1)
|
if (tinydir_next(dir) == -1) {
|
||||||
{
|
|
||||||
goto bail;
|
goto bail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Just in case the number of files has changed between the first and
|
/* Just in case the number of files has changed between the first and
|
||||||
second reads, terminate without writing into unallocated memory */
|
second reads, terminate without writing into unallocated memory */
|
||||||
if (dir->n_files == n_files)
|
if (dir->n_files == n_files) {
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -415,16 +392,14 @@ int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
bail:
|
bail:
|
||||||
tinydir_close(dir);
|
tinydir_close(dir);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
_TINYDIR_FUNC
|
_TINYDIR_FUNC
|
||||||
void tinydir_close(tinydir_dir *dir)
|
void tinydir_close(tinydir_dir* dir) {
|
||||||
{
|
if (dir == NULL) {
|
||||||
if (dir == NULL)
|
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -434,35 +409,30 @@ void tinydir_close(tinydir_dir *dir)
|
|||||||
_TINYDIR_FREE(dir->_files);
|
_TINYDIR_FREE(dir->_files);
|
||||||
dir->_files = NULL;
|
dir->_files = NULL;
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
if (dir->_h != INVALID_HANDLE_VALUE)
|
if (dir->_h != INVALID_HANDLE_VALUE) {
|
||||||
{
|
FindClose(dir->_h);
|
||||||
FindClose(dir->_h);
|
}
|
||||||
}
|
dir->_h = INVALID_HANDLE_VALUE;
|
||||||
dir->_h = INVALID_HANDLE_VALUE;
|
|
||||||
#else
|
#else
|
||||||
if (dir->_d)
|
if (dir->_d) {
|
||||||
{
|
|
||||||
_tinydir_closedir(dir->_d);
|
_tinydir_closedir(dir->_d);
|
||||||
}
|
}
|
||||||
dir->_d = NULL;
|
dir->_d = NULL;
|
||||||
dir->_e = NULL;
|
dir->_e = NULL;
|
||||||
#ifndef _TINYDIR_USE_READDIR
|
#ifndef _TINYDIR_USE_READDIR
|
||||||
_TINYDIR_FREE(dir->_ep);
|
_TINYDIR_FREE(dir->_ep);
|
||||||
dir->_ep = NULL;
|
dir->_ep = NULL;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
_TINYDIR_FUNC
|
_TINYDIR_FUNC
|
||||||
int tinydir_next(tinydir_dir *dir)
|
int tinydir_next(tinydir_dir* dir) {
|
||||||
{
|
if (dir == NULL) {
|
||||||
if (dir == NULL)
|
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (!dir->has_next)
|
if (!dir->has_next) {
|
||||||
{
|
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -473,27 +443,23 @@ int tinydir_next(tinydir_dir *dir)
|
|||||||
#ifdef _TINYDIR_USE_READDIR
|
#ifdef _TINYDIR_USE_READDIR
|
||||||
dir->_e = _tinydir_readdir(dir->_d);
|
dir->_e = _tinydir_readdir(dir->_d);
|
||||||
#else
|
#else
|
||||||
if (dir->_ep == NULL)
|
if (dir->_ep == NULL) {
|
||||||
{
|
return -1;
|
||||||
return -1;
|
}
|
||||||
}
|
if (readdir_r(dir->_d, dir->_ep, &dir->_e) != 0) {
|
||||||
if (readdir_r(dir->_d, dir->_ep, &dir->_e) != 0)
|
return -1;
|
||||||
{
|
}
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
if (dir->_e == NULL)
|
if (dir->_e == NULL)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
dir->has_next = 0;
|
dir->has_next = 0;
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
if (GetLastError() != ERROR_SUCCESS &&
|
if (GetLastError() != ERROR_SUCCESS && GetLastError() != ERROR_NO_MORE_FILES) {
|
||||||
GetLastError() != ERROR_NO_MORE_FILES)
|
tinydir_close(dir);
|
||||||
{
|
errno = EIO;
|
||||||
tinydir_close(dir);
|
return -1;
|
||||||
errno = EIO;
|
}
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -501,11 +467,9 @@ int tinydir_next(tinydir_dir *dir)
|
|||||||
}
|
}
|
||||||
|
|
||||||
_TINYDIR_FUNC
|
_TINYDIR_FUNC
|
||||||
int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file)
|
int tinydir_readfile(const tinydir_dir* dir, tinydir_file* file) {
|
||||||
{
|
const _tinydir_char_t* filename;
|
||||||
const _tinydir_char_t *filename;
|
if (dir == NULL || file == NULL) {
|
||||||
if (dir == NULL || file == NULL)
|
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -520,20 +484,16 @@ int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file)
|
|||||||
}
|
}
|
||||||
filename =
|
filename =
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
dir->_f.cFileName;
|
dir->_f.cFileName;
|
||||||
#else
|
#else
|
||||||
dir->_e->d_name;
|
dir->_e->d_name;
|
||||||
#endif
|
#endif
|
||||||
if (_tinydir_strlen(dir->path) +
|
if (_tinydir_strlen(dir->path) + _tinydir_strlen(filename) + 1 + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX) {
|
||||||
_tinydir_strlen(filename) + 1 + _TINYDIR_PATH_EXTRA >=
|
|
||||||
_TINYDIR_PATH_MAX)
|
|
||||||
{
|
|
||||||
/* the path for the file will be too long */
|
/* the path for the file will be too long */
|
||||||
errno = ENAMETOOLONG;
|
errno = ENAMETOOLONG;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (_tinydir_strlen(filename) >= _TINYDIR_FILENAME_MAX)
|
if (_tinydir_strlen(filename) >= _TINYDIR_FILENAME_MAX) {
|
||||||
{
|
|
||||||
errno = ENAMETOOLONG;
|
errno = ENAMETOOLONG;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -546,17 +506,15 @@ int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file)
|
|||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
#ifdef __MINGW32__
|
#ifdef __MINGW32__
|
||||||
if (_tstat(
|
if (_tstat(
|
||||||
#elif (defined _BSD_SOURCE) || (defined _DEFAULT_SOURCE) \
|
#elif (defined _BSD_SOURCE) || (defined _DEFAULT_SOURCE) || ((defined _XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500)) \
|
||||||
|| ((defined _XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500)) \
|
|| ((defined _POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) || ((defined __APPLE__) && (defined __MACH__)) \
|
||||||
|| ((defined _POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) \
|
|| (defined BSD)
|
||||||
|| ((defined __APPLE__) && (defined __MACH__)) \
|
if (lstat(
|
||||||
|| (defined BSD)
|
|
||||||
if (lstat(
|
|
||||||
#else
|
#else
|
||||||
if (stat(
|
if (stat(
|
||||||
#endif
|
#endif
|
||||||
file->path, &file->_s) == -1)
|
file->path, &file->_s)
|
||||||
{
|
== -1) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -564,42 +522,38 @@ int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file)
|
|||||||
|
|
||||||
file->is_dir =
|
file->is_dir =
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
|
!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
|
||||||
#else
|
#else
|
||||||
S_ISDIR(file->_s.st_mode);
|
S_ISDIR(file->_s.st_mode);
|
||||||
#endif
|
#endif
|
||||||
file->is_reg =
|
file->is_reg =
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) ||
|
!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NORMAL)
|
||||||
(
|
|| (!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DEVICE)
|
||||||
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) &&
|
&& !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||||
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
|
&& !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) &&
|
||||||
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) &&
|
|
||||||
#ifdef FILE_ATTRIBUTE_INTEGRITY_STREAM
|
#ifdef FILE_ATTRIBUTE_INTEGRITY_STREAM
|
||||||
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM) &&
|
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM) &&
|
||||||
#endif
|
#endif
|
||||||
#ifdef FILE_ATTRIBUTE_NO_SCRUB_DATA
|
#ifdef FILE_ATTRIBUTE_NO_SCRUB_DATA
|
||||||
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA) &&
|
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA) &&
|
||||||
#endif
|
#endif
|
||||||
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) &&
|
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE)
|
||||||
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY));
|
&& !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY));
|
||||||
#else
|
#else
|
||||||
S_ISREG(file->_s.st_mode);
|
S_ISREG(file->_s.st_mode);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_TINYDIR_FUNC
|
_TINYDIR_FUNC
|
||||||
int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i)
|
int tinydir_readfile_n(const tinydir_dir* dir, tinydir_file* file, size_t i) {
|
||||||
{
|
if (dir == NULL || file == NULL) {
|
||||||
if (dir == NULL || file == NULL)
|
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (i >= dir->n_files)
|
if (i >= dir->n_files) {
|
||||||
{
|
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -611,24 +565,20 @@ int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i)
|
|||||||
}
|
}
|
||||||
|
|
||||||
_TINYDIR_FUNC
|
_TINYDIR_FUNC
|
||||||
int tinydir_open_subdir_n(tinydir_dir *dir, size_t i)
|
int tinydir_open_subdir_n(tinydir_dir* dir, size_t i) {
|
||||||
{
|
|
||||||
_tinydir_char_t path[_TINYDIR_PATH_MAX];
|
_tinydir_char_t path[_TINYDIR_PATH_MAX];
|
||||||
if (dir == NULL)
|
if (dir == NULL) {
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (i >= dir->n_files || !dir->_files[i].is_dir)
|
if (i >= dir->n_files || !dir->_files[i].is_dir) {
|
||||||
{
|
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
_tinydir_strcpy(path, dir->_files[i].path);
|
_tinydir_strcpy(path, dir->_files[i].path);
|
||||||
tinydir_close(dir);
|
tinydir_close(dir);
|
||||||
if (tinydir_open_sorted(dir, path) == -1)
|
if (tinydir_open_sorted(dir, path) == -1) {
|
||||||
{
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -637,66 +587,52 @@ int tinydir_open_subdir_n(tinydir_dir *dir, size_t i)
|
|||||||
|
|
||||||
/* Open a single file given its path */
|
/* Open a single file given its path */
|
||||||
_TINYDIR_FUNC
|
_TINYDIR_FUNC
|
||||||
int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path)
|
int tinydir_file_open(tinydir_file* file, const _tinydir_char_t* path) {
|
||||||
{
|
|
||||||
tinydir_dir dir;
|
tinydir_dir dir;
|
||||||
int result = 0;
|
int result = 0;
|
||||||
int found = 0;
|
int found = 0;
|
||||||
_tinydir_char_t dir_name_buf[_TINYDIR_PATH_MAX];
|
_tinydir_char_t dir_name_buf[_TINYDIR_PATH_MAX];
|
||||||
_tinydir_char_t file_name_buf[_TINYDIR_FILENAME_MAX];
|
_tinydir_char_t file_name_buf[_TINYDIR_FILENAME_MAX];
|
||||||
_tinydir_char_t *dir_name;
|
_tinydir_char_t* dir_name;
|
||||||
_tinydir_char_t *base_name;
|
_tinydir_char_t* base_name;
|
||||||
#if (defined _MSC_VER || defined __MINGW32__)
|
#if (defined _MSC_VER || defined __MINGW32__)
|
||||||
_tinydir_char_t drive_buf[_TINYDIR_PATH_MAX];
|
_tinydir_char_t drive_buf[_TINYDIR_PATH_MAX];
|
||||||
_tinydir_char_t ext_buf[_TINYDIR_FILENAME_MAX];
|
_tinydir_char_t ext_buf[_TINYDIR_FILENAME_MAX];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (file == NULL || path == NULL || _tinydir_strlen(path) == 0)
|
if (file == NULL || path == NULL || _tinydir_strlen(path) == 0) {
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
|
if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX) {
|
||||||
{
|
|
||||||
errno = ENAMETOOLONG;
|
errno = ENAMETOOLONG;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the parent path */
|
/* Get the parent path */
|
||||||
#if (defined _MSC_VER || defined __MINGW32__)
|
#if (defined _MSC_VER || defined __MINGW32__)
|
||||||
#if ((defined _MSC_VER) && (_MSC_VER >= 1400))
|
#if ((defined _MSC_VER) && (_MSC_VER >= 1400))
|
||||||
errno = _tsplitpath_s(
|
errno = _tsplitpath_s(path, drive_buf, _TINYDIR_DRIVE_MAX, dir_name_buf, _TINYDIR_FILENAME_MAX, file_name_buf,
|
||||||
path,
|
_TINYDIR_FILENAME_MAX, ext_buf, _TINYDIR_FILENAME_MAX);
|
||||||
drive_buf, _TINYDIR_DRIVE_MAX,
|
|
||||||
dir_name_buf, _TINYDIR_FILENAME_MAX,
|
|
||||||
file_name_buf, _TINYDIR_FILENAME_MAX,
|
|
||||||
ext_buf, _TINYDIR_FILENAME_MAX);
|
|
||||||
#else
|
#else
|
||||||
_tsplitpath(
|
_tsplitpath(path, drive_buf, dir_name_buf, file_name_buf, ext_buf);
|
||||||
path,
|
|
||||||
drive_buf,
|
|
||||||
dir_name_buf,
|
|
||||||
file_name_buf,
|
|
||||||
ext_buf);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (errno)
|
if (errno) {
|
||||||
{
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* _splitpath_s not work fine with only filename and widechar support */
|
/* _splitpath_s not work fine with only filename and widechar support */
|
||||||
#ifdef _UNICODE
|
#ifdef _UNICODE
|
||||||
if (drive_buf[0] == L'\xFEFE')
|
if (drive_buf[0] == L'\xFEFE')
|
||||||
drive_buf[0] = '\0';
|
drive_buf[0] = '\0';
|
||||||
if (dir_name_buf[0] == L'\xFEFE')
|
if (dir_name_buf[0] == L'\xFEFE')
|
||||||
dir_name_buf[0] = '\0';
|
dir_name_buf[0] = '\0';
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Emulate the behavior of dirname by returning "." for dir name if it's
|
/* Emulate the behavior of dirname by returning "." for dir name if it's
|
||||||
empty */
|
empty */
|
||||||
if (drive_buf[0] == '\0' && dir_name_buf[0] == '\0')
|
if (drive_buf[0] == '\0' && dir_name_buf[0] == '\0') {
|
||||||
{
|
|
||||||
_tinydir_strcpy(dir_name_buf, TINYDIR_STRING("."));
|
_tinydir_strcpy(dir_name_buf, TINYDIR_STRING("."));
|
||||||
}
|
}
|
||||||
/* Concatenate the drive letter and dir name to form full dir name */
|
/* Concatenate the drive letter and dir name to form full dir name */
|
||||||
@@ -707,19 +643,19 @@ int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path)
|
|||||||
base_name = file_name_buf;
|
base_name = file_name_buf;
|
||||||
#else
|
#else
|
||||||
_tinydir_strcpy(dir_name_buf, path);
|
_tinydir_strcpy(dir_name_buf, path);
|
||||||
dir_name = dirname(dir_name_buf);
|
dir_name = dirname(dir_name_buf);
|
||||||
_tinydir_strcpy(file_name_buf, path);
|
_tinydir_strcpy(file_name_buf, path);
|
||||||
base_name = basename(file_name_buf);
|
base_name = basename(file_name_buf);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Special case: if the path is a root dir, open the parent dir as the file */
|
/* Special case: if the path is a root dir, open the parent dir as the file */
|
||||||
#if (defined _MSC_VER || defined __MINGW32__)
|
#if (defined _MSC_VER || defined __MINGW32__)
|
||||||
if (_tinydir_strlen(base_name) == 0)
|
if (_tinydir_strlen(base_name) == 0)
|
||||||
#else
|
#else
|
||||||
if ((_tinydir_strcmp(base_name, TINYDIR_STRING("/"))) == 0)
|
if ((_tinydir_strcmp(base_name, TINYDIR_STRING("/"))) == 0)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
memset(file, 0, sizeof * file);
|
memset(file, 0, sizeof *file);
|
||||||
file->is_dir = 1;
|
file->is_dir = 1;
|
||||||
file->is_reg = 0;
|
file->is_reg = 0;
|
||||||
_tinydir_strcpy(file->path, dir_name);
|
_tinydir_strcpy(file->path, dir_name);
|
||||||
@@ -728,59 +664,48 @@ int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Open the parent directory */
|
/* Open the parent directory */
|
||||||
if (tinydir_open(&dir, dir_name) == -1)
|
if (tinydir_open(&dir, dir_name) == -1) {
|
||||||
{
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read through the parent directory and look for the file */
|
/* Read through the parent directory and look for the file */
|
||||||
while (dir.has_next)
|
while (dir.has_next) {
|
||||||
{
|
if (tinydir_readfile(&dir, file) == -1) {
|
||||||
if (tinydir_readfile(&dir, file) == -1)
|
|
||||||
{
|
|
||||||
result = -1;
|
result = -1;
|
||||||
goto bail;
|
goto bail;
|
||||||
}
|
}
|
||||||
if (_tinydir_strcmp(file->name, base_name) == 0)
|
if (_tinydir_strcmp(file->name, base_name) == 0) {
|
||||||
{
|
|
||||||
/* File found */
|
/* File found */
|
||||||
found = 1;
|
found = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tinydir_next(&dir);
|
tinydir_next(&dir);
|
||||||
}
|
}
|
||||||
if (!found)
|
if (!found) {
|
||||||
{
|
|
||||||
result = -1;
|
result = -1;
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
bail:
|
bail:
|
||||||
tinydir_close(&dir);
|
tinydir_close(&dir);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
_TINYDIR_FUNC
|
_TINYDIR_FUNC
|
||||||
void _tinydir_get_ext(tinydir_file *file)
|
void _tinydir_get_ext(tinydir_file* file) {
|
||||||
{
|
_tinydir_char_t* period = _tinydir_strrchr(file->name, TINYDIR_STRING('.'));
|
||||||
_tinydir_char_t *period = _tinydir_strrchr(file->name, TINYDIR_STRING('.'));
|
if (period == NULL) {
|
||||||
if (period == NULL)
|
|
||||||
{
|
|
||||||
file->extension = &(file->name[_tinydir_strlen(file->name)]);
|
file->extension = &(file->name[_tinydir_strlen(file->name)]);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
file->extension = period + 1;
|
file->extension = period + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_TINYDIR_FUNC
|
_TINYDIR_FUNC
|
||||||
int _tinydir_file_cmp(const void *a, const void *b)
|
int _tinydir_file_cmp(const void* a, const void* b) {
|
||||||
{
|
const tinydir_file* fa = (const tinydir_file*)a;
|
||||||
const tinydir_file *fa = (const tinydir_file *)a;
|
const tinydir_file* fb = (const tinydir_file*)b;
|
||||||
const tinydir_file *fb = (const tinydir_file *)b;
|
if (fa->is_dir != fb->is_dir) {
|
||||||
if (fa->is_dir != fb->is_dir)
|
|
||||||
{
|
|
||||||
return -(fa->is_dir - fb->is_dir);
|
return -(fa->is_dir - fb->is_dir);
|
||||||
}
|
}
|
||||||
return _tinydir_strncmp(fa->name, fb->name, _TINYDIR_FILENAME_MAX);
|
return _tinydir_strncmp(fa->name, fb->name, _TINYDIR_FILENAME_MAX);
|
||||||
@@ -793,36 +718,34 @@ The following authored by Ben Hutchings <ben@decadent.org.uk>
|
|||||||
from https://womble.decadent.org.uk/readdir_r-advisory.html
|
from https://womble.decadent.org.uk/readdir_r-advisory.html
|
||||||
*/
|
*/
|
||||||
/* Calculate the required buffer size (in bytes) for directory *
|
/* Calculate the required buffer size (in bytes) for directory *
|
||||||
* entries read from the given directory handle. Return -1 if this *
|
* entries read from the given directory handle. Return -1 if this *
|
||||||
* this cannot be done. *
|
* this cannot be done. *
|
||||||
* *
|
* *
|
||||||
* This code does not trust values of NAME_MAX that are less than *
|
* This code does not trust values of NAME_MAX that are less than *
|
||||||
* 255, since some systems (including at least HP-UX) incorrectly *
|
* 255, since some systems (including at least HP-UX) incorrectly *
|
||||||
* define it to be a smaller value. */
|
* define it to be a smaller value. */
|
||||||
_TINYDIR_FUNC
|
_TINYDIR_FUNC
|
||||||
size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp)
|
size_t _tinydir_dirent_buf_size(_TINYDIR_DIR* dirp) {
|
||||||
{
|
long name_max;
|
||||||
long name_max;
|
size_t name_end;
|
||||||
size_t name_end;
|
/* parameter may be unused */
|
||||||
/* parameter may be unused */
|
(void)dirp;
|
||||||
(void)dirp;
|
|
||||||
|
|
||||||
#if defined _TINYDIR_USE_FPATHCONF
|
#if defined _TINYDIR_USE_FPATHCONF
|
||||||
name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
|
name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
|
||||||
if (name_max == -1)
|
if (name_max == -1)
|
||||||
#if defined(NAME_MAX)
|
#if defined(NAME_MAX)
|
||||||
name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
|
name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
|
||||||
#else
|
#else
|
||||||
return (size_t)(-1);
|
return (size_t)(-1);
|
||||||
#endif
|
#endif
|
||||||
#elif defined(NAME_MAX)
|
#elif defined(NAME_MAX)
|
||||||
name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
|
name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
|
||||||
#else
|
#else
|
||||||
#error "buffer size for readdir_r cannot be determined"
|
#error "buffer size for readdir_r cannot be determined"
|
||||||
#endif
|
#endif
|
||||||
name_end = (size_t)offsetof(struct _tinydir_dirent, d_name) + name_max + 1;
|
name_end = (size_t)offsetof(struct _tinydir_dirent, d_name) + name_max + 1;
|
||||||
return (name_end > sizeof(struct _tinydir_dirent) ?
|
return (name_end > sizeof(struct _tinydir_dirent) ? name_end : sizeof(struct _tinydir_dirent));
|
||||||
name_end : sizeof(struct _tinydir_dirent));
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
@@ -831,8 +754,8 @@ size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
# if defined (_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
# pragma warning(pop)
|
#pragma warning(pop)
|
||||||
# endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -20,22 +20,24 @@
|
|||||||
#include "lcd_api.h"
|
#include "lcd_api.h"
|
||||||
|
|
||||||
// Defines used by UDP callback
|
// Defines used by UDP callback
|
||||||
#define UDP_BROADCAST_MAX_DATA_SIZE ((UDP_BROADCAST_MAX_NAME_SIZE * 2) - 2 + 25) // Define the maximum expected data size
|
#define UDP_BROADCAST_MAX_DATA_SIZE \
|
||||||
#define UDP_BROADCAST_UDP_QUESTION1 "Where are you?v1.0" // Expected question from UDP client
|
((UDP_BROADCAST_MAX_NAME_SIZE * 2) - 2 + 25) // Define the maximum expected data size
|
||||||
#define UDP_BROADCAST_MAX_FUNC_LEN 7
|
#define UDP_BROADCAST_UDP_QUESTION1 "Where are you?v1.0" // Expected question from UDP client
|
||||||
|
#define UDP_BROADCAST_MAX_FUNC_LEN 7
|
||||||
#define UDP_BROADCAST_MAX_COLON_COMMA_COUNT 4
|
#define UDP_BROADCAST_MAX_COLON_COMMA_COUNT 4
|
||||||
|
|
||||||
// Defines used by owner details
|
// Defines used by owner details
|
||||||
#define UDP_BROADCAST_MAX_REPLY_SIZE (UDP_BROADCAST_MAX_MAC_ADDR_LEN + sizeof(UDP_BROADCAST_REPLY_MIDDLE_TEXT) + (UDP_BROADCAST_MAX_NAME_SIZE * 2) + UDP_BROADCAST_MAX_REPLY_SIZE_EXTRA)
|
#define UDP_BROADCAST_MAX_REPLY_SIZE \
|
||||||
|
(UDP_BROADCAST_MAX_MAC_ADDR_LEN + sizeof(UDP_BROADCAST_REPLY_MIDDLE_TEXT) + (UDP_BROADCAST_MAX_NAME_SIZE * 2) \
|
||||||
|
+ UDP_BROADCAST_MAX_REPLY_SIZE_EXTRA)
|
||||||
#define UDP_BROADCAST_REPLY_MIDDLE_TEXT "is present and my owner is"
|
#define UDP_BROADCAST_REPLY_MIDDLE_TEXT "is present and my owner is"
|
||||||
|
|
||||||
#define UDP_BROADCAST_MAX_MAC_ADDR_LEN 19 // Format is: "xx:xx:xx:xx:xx:xx"
|
#define UDP_BROADCAST_MAX_MAC_ADDR_LEN 19 // Format is: "xx:xx:xx:xx:xx:xx"
|
||||||
#define UDP_BROADCAST_MAX_NAME_SIZE 21 // Code automatically leaves 1 char for '\0' (actual length = length - 1)
|
#define UDP_BROADCAST_MAX_NAME_SIZE 21 // Code automatically leaves 1 char for '\0' (actual length = length - 1)
|
||||||
#define UDP_BROADCAST_MAX_REPLY_SIZE_EXTRA 20 // Just a bit extra
|
#define UDP_BROADCAST_MAX_REPLY_SIZE_EXTRA 20 // Just a bit extra
|
||||||
|
|
||||||
#define UDP_BROADCAST_LCD_NAME_PRE_TEXT "New owner: "
|
#define UDP_BROADCAST_LCD_NAME_PRE_TEXT "New owner: "
|
||||||
#define UDP_BROADCAST_LCD_TEXT_SIZE (strlen(UDP_BROADCAST_LCD_NAME_PRE_TEXT) + UDP_BROADCAST_MAX_NAME_SIZE)
|
#define UDP_BROADCAST_LCD_TEXT_SIZE (strlen(UDP_BROADCAST_LCD_NAME_PRE_TEXT) + UDP_BROADCAST_MAX_NAME_SIZE)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @struct owner_details_t
|
* @struct owner_details_t
|
||||||
|
|||||||
@@ -13,10 +13,10 @@
|
|||||||
#ifndef __ANIMATEDGIF__
|
#ifndef __ANIMATEDGIF__
|
||||||
#define __ANIMATEDGIF__
|
#define __ANIMATEDGIF__
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
#define memcpy_P memcpy
|
#define memcpy_P memcpy
|
||||||
#define PROGMEM
|
#define PROGMEM
|
||||||
|
|
||||||
@@ -39,9 +39,9 @@
|
|||||||
// with 256 entries
|
// with 256 entries
|
||||||
//
|
//
|
||||||
#define MAX_CODE_SIZE 12
|
#define MAX_CODE_SIZE 12
|
||||||
#define MAX_COLORS 256
|
#define MAX_COLORS 256
|
||||||
#define LZW_BUF_SIZE (6*MAX_CHUNK_SIZE)
|
#define LZW_BUF_SIZE (6 * MAX_CHUNK_SIZE)
|
||||||
#define LZW_HIGHWATER (4*MAX_CHUNK_SIZE)
|
#define LZW_HIGHWATER (4 * MAX_CHUNK_SIZE)
|
||||||
#ifdef __LINUX__
|
#ifdef __LINUX__
|
||||||
#define MAX_WIDTH 2048
|
#define MAX_WIDTH 2048
|
||||||
#else
|
#else
|
||||||
@@ -50,13 +50,13 @@
|
|||||||
// This buffer is used to store the pixel sequence in reverse order
|
// This buffer is used to store the pixel sequence in reverse order
|
||||||
// it needs to be large enough to hold the longest possible
|
// it needs to be large enough to hold the longest possible
|
||||||
// sequence (1<<MAX_CODE_SIZE)
|
// sequence (1<<MAX_CODE_SIZE)
|
||||||
#define FILE_BUF_SIZE (1<<MAX_CODE_SIZE)
|
#define FILE_BUF_SIZE (1 << MAX_CODE_SIZE)
|
||||||
|
|
||||||
#define PIXEL_FIRST 0
|
#define PIXEL_FIRST 0
|
||||||
#define PIXEL_LAST (1<<MAX_CODE_SIZE)
|
#define PIXEL_LAST (1 << MAX_CODE_SIZE)
|
||||||
#define LINK_UNUSED 5911 // 0x1717 to use memset
|
#define LINK_UNUSED 5911 // 0x1717 to use memset
|
||||||
#define LINK_END 5912
|
#define LINK_END 5912
|
||||||
#define MAX_HASH 5003
|
#define MAX_HASH 5003
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
GIF_PALETTE_RGB565_LE = 0, // little endian (default)
|
GIF_PALETTE_RGB565_LE = 0, // little endian (default)
|
||||||
@@ -65,16 +65,13 @@ enum {
|
|||||||
};
|
};
|
||||||
// for compatibility with older code
|
// for compatibility with older code
|
||||||
#define LITTLE_ENDIAN_PIXELS GIF_PALETTE_RGB565_LE
|
#define LITTLE_ENDIAN_PIXELS GIF_PALETTE_RGB565_LE
|
||||||
#define BIG_ENDIAN_PIXELS GIF_PALETTE_RGB565_BE
|
#define BIG_ENDIAN_PIXELS GIF_PALETTE_RGB565_BE
|
||||||
//
|
//
|
||||||
// Draw callback pixel type
|
// Draw callback pixel type
|
||||||
// RAW = 8-bit palettized pixels requiring transparent pixel handling
|
// RAW = 8-bit palettized pixels requiring transparent pixel handling
|
||||||
// COOKED = 16 or 24-bpp fully rendered pixels ready for display
|
// COOKED = 16 or 24-bpp fully rendered pixels ready for display
|
||||||
//
|
//
|
||||||
enum {
|
enum { GIF_DRAW_RAW = 0, GIF_DRAW_COOKED };
|
||||||
GIF_DRAW_RAW = 0,
|
|
||||||
GIF_DRAW_COOKED
|
|
||||||
};
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
GIF_SUCCESS = 0,
|
GIF_SUCCESS = 0,
|
||||||
@@ -89,134 +86,136 @@ enum {
|
|||||||
GIF_ERROR_MEMORY
|
GIF_ERROR_MEMORY
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct gif_file_tag
|
typedef struct gif_file_tag {
|
||||||
{
|
int32_t iPos; // current file position
|
||||||
int32_t iPos; // current file position
|
int32_t iSize; // file size
|
||||||
int32_t iSize; // file size
|
uint8_t* pData; // memory file pointer
|
||||||
uint8_t *pData; // memory file pointer
|
void* fHandle; // class pointer to File/SdFat or whatever you want
|
||||||
void * fHandle; // class pointer to File/SdFat or whatever you want
|
|
||||||
} GIFFILE;
|
} GIFFILE;
|
||||||
|
|
||||||
typedef struct gif_info_tag
|
typedef struct gif_info_tag {
|
||||||
{
|
|
||||||
int32_t iFrameCount; // total frames in file
|
int32_t iFrameCount; // total frames in file
|
||||||
int32_t iDuration; // duration of animation in milliseconds
|
int32_t iDuration; // duration of animation in milliseconds
|
||||||
int32_t iMaxDelay; // maximum frame delay
|
int32_t iMaxDelay; // maximum frame delay
|
||||||
int32_t iMinDelay; // minimum frame delay
|
int32_t iMinDelay; // minimum frame delay
|
||||||
} GIFINFO;
|
} GIFINFO;
|
||||||
|
|
||||||
typedef struct gif_draw_tag
|
typedef struct gif_draw_tag {
|
||||||
{
|
int iX, iY; // Corner offset of this frame on the canvas
|
||||||
int iX, iY; // Corner offset of this frame on the canvas
|
int y; // current line being drawn (0 = top line of image)
|
||||||
int y; // current line being drawn (0 = top line of image)
|
int iWidth, iHeight; // size of this frame
|
||||||
int iWidth, iHeight; // size of this frame
|
void* pUser; // user supplied pointer
|
||||||
void *pUser; // user supplied pointer
|
uint8_t* pPixels; // 8-bit source pixels for this line
|
||||||
uint8_t *pPixels; // 8-bit source pixels for this line
|
uint16_t* pPalette; // little or big-endian RGB565 palette entries (default)
|
||||||
uint16_t *pPalette; // little or big-endian RGB565 palette entries (default)
|
uint8_t* pPalette24; // RGB888 palette (optional)
|
||||||
uint8_t *pPalette24; // RGB888 palette (optional)
|
uint8_t ucTransparent; // transparent color
|
||||||
uint8_t ucTransparent; // transparent color
|
|
||||||
uint8_t ucHasTransparency; // flag indicating the transparent color is in use
|
uint8_t ucHasTransparency; // flag indicating the transparent color is in use
|
||||||
uint8_t ucDisposalMethod; // frame disposal method
|
uint8_t ucDisposalMethod; // frame disposal method
|
||||||
uint8_t ucBackground; // background color
|
uint8_t ucBackground; // background color
|
||||||
uint8_t ucIsGlobalPalette; // Flag to indicate that a global palette, rather than a local palette is being used
|
uint8_t ucIsGlobalPalette; // Flag to indicate that a global palette, rather than a local palette is being used
|
||||||
} GIFDRAW;
|
} GIFDRAW;
|
||||||
|
|
||||||
// Callback function prototypes
|
// Callback function prototypes
|
||||||
typedef int32_t (GIF_READ_CALLBACK)(GIFFILE *pFile, uint8_t *pBuf, int32_t iLen);
|
typedef int32_t(GIF_READ_CALLBACK)(GIFFILE* pFile, uint8_t* pBuf, int32_t iLen);
|
||||||
typedef int32_t (GIF_SEEK_CALLBACK)(GIFFILE *pFile, int32_t iPosition);
|
typedef int32_t(GIF_SEEK_CALLBACK)(GIFFILE* pFile, int32_t iPosition);
|
||||||
typedef void (GIF_DRAW_CALLBACK)(GIFDRAW *pDraw);
|
typedef void(GIF_DRAW_CALLBACK)(GIFDRAW* pDraw);
|
||||||
typedef void * (GIF_OPEN_CALLBACK)(const char *szFilename, int32_t *pFileSize);
|
typedef void*(GIF_OPEN_CALLBACK)(const char* szFilename, int32_t* pFileSize);
|
||||||
typedef void (GIF_CLOSE_CALLBACK)(void *pHandle);
|
typedef void(GIF_CLOSE_CALLBACK)(void* pHandle);
|
||||||
typedef void * (GIF_ALLOC_CALLBACK)(uint32_t iSize);
|
typedef void*(GIF_ALLOC_CALLBACK)(uint32_t iSize);
|
||||||
typedef void (GIF_FREE_CALLBACK)(void *buffer);
|
typedef void(GIF_FREE_CALLBACK)(void* buffer);
|
||||||
//
|
//
|
||||||
// our private structure to hold a GIF image decode state
|
// our private structure to hold a GIF image decode state
|
||||||
//
|
//
|
||||||
typedef struct gif_image_tag
|
typedef struct gif_image_tag {
|
||||||
{
|
|
||||||
int iWidth, iHeight, iCanvasWidth, iCanvasHeight;
|
int iWidth, iHeight, iCanvasWidth, iCanvasHeight;
|
||||||
int iX, iY; // GIF corner offset
|
int iX, iY; // GIF corner offset
|
||||||
int iBpp;
|
int iBpp;
|
||||||
int iError; // last error
|
int iError; // last error
|
||||||
int iFrameDelay; // delay in milliseconds for this frame
|
int iFrameDelay; // delay in milliseconds for this frame
|
||||||
int iRepeatCount; // NETSCAPE animation repeat count. 0=forever
|
int iRepeatCount; // NETSCAPE animation repeat count. 0=forever
|
||||||
int iXCount, iYCount; // decoding position in image (countdown values)
|
int iXCount, iYCount; // decoding position in image (countdown values)
|
||||||
int iLZWOff; // current LZW data offset
|
int iLZWOff; // current LZW data offset
|
||||||
int iLZWSize; // current quantity of data in the LZW buffer
|
int iLZWSize; // current quantity of data in the LZW buffer
|
||||||
int iCommentPos; // file offset of start of comment data
|
int iCommentPos; // file offset of start of comment data
|
||||||
short sCommentLen; // length of comment
|
short sCommentLen; // length of comment
|
||||||
GIF_READ_CALLBACK *pfnRead;
|
GIF_READ_CALLBACK* pfnRead;
|
||||||
GIF_SEEK_CALLBACK *pfnSeek;
|
GIF_SEEK_CALLBACK* pfnSeek;
|
||||||
GIF_DRAW_CALLBACK *pfnDraw;
|
GIF_DRAW_CALLBACK* pfnDraw;
|
||||||
GIF_OPEN_CALLBACK *pfnOpen;
|
GIF_OPEN_CALLBACK* pfnOpen;
|
||||||
GIF_CLOSE_CALLBACK *pfnClose;
|
GIF_CLOSE_CALLBACK* pfnClose;
|
||||||
GIFFILE GIFFile;
|
GIFFILE GIFFile;
|
||||||
void *pUser;
|
void* pUser;
|
||||||
unsigned char *pFrameBuffer;
|
unsigned char* pFrameBuffer;
|
||||||
unsigned char *pPixels, *pOldPixels;
|
unsigned char *pPixels, *pOldPixels;
|
||||||
unsigned char ucLineBuf[MAX_WIDTH]; // current line
|
unsigned char ucLineBuf[MAX_WIDTH]; // current line
|
||||||
unsigned char ucFileBuf[FILE_BUF_SIZE]; // holds temp data and pixel stack
|
unsigned char ucFileBuf[FILE_BUF_SIZE]; // holds temp data and pixel stack
|
||||||
unsigned short pPalette[(MAX_COLORS * 3)/2]; // can hold RGB565 or RGB888 - set in begin()
|
unsigned short pPalette[(MAX_COLORS * 3) / 2]; // can hold RGB565 or RGB888 - set in begin()
|
||||||
unsigned short pLocalPalette[(MAX_COLORS * 3)/2]; // color palettes for GIF images
|
unsigned short pLocalPalette[(MAX_COLORS * 3) / 2]; // color palettes for GIF images
|
||||||
unsigned char ucLZW[LZW_BUF_SIZE]; // holds 6 chunks (6x255) of GIF LZW data packed together
|
unsigned char ucLZW[LZW_BUF_SIZE]; // holds 6 chunks (6x255) of GIF LZW data packed together
|
||||||
unsigned short usGIFTable[1<<MAX_CODE_SIZE];
|
unsigned short usGIFTable[1 << MAX_CODE_SIZE];
|
||||||
unsigned char ucGIFPixels[(PIXEL_LAST*2)];
|
unsigned char ucGIFPixels[(PIXEL_LAST * 2)];
|
||||||
unsigned char bEndOfFrame;
|
unsigned char bEndOfFrame;
|
||||||
unsigned char ucGIFBits, ucBackground, ucTransparent, ucCodeStart, ucMap, bUseLocalPalette;
|
unsigned char ucGIFBits, ucBackground, ucTransparent, ucCodeStart, ucMap, bUseLocalPalette;
|
||||||
unsigned char ucPaletteType; // RGB565 or RGB888
|
unsigned char ucPaletteType; // RGB565 or RGB888
|
||||||
unsigned char ucDrawType; // RAW or COOKED
|
unsigned char ucDrawType; // RAW or COOKED
|
||||||
} GIFIMAGE;
|
} GIFIMAGE;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
//
|
//
|
||||||
// The GIF class wraps portable C code which does the actual work
|
// The GIF class wraps portable C code which does the actual work
|
||||||
//
|
//
|
||||||
class AnimatedGIF
|
class AnimatedGIF {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
int open(uint8_t *pData, int iDataSize, GIF_DRAW_CALLBACK *pfnDraw);
|
int open(uint8_t* pData, int iDataSize, GIF_DRAW_CALLBACK* pfnDraw);
|
||||||
int openFLASH(uint8_t *pData, int iDataSize, GIF_DRAW_CALLBACK *pfnDraw);
|
int openFLASH(uint8_t* pData, int iDataSize, GIF_DRAW_CALLBACK* pfnDraw);
|
||||||
int open(const char *szFilename, GIF_OPEN_CALLBACK *pfnOpen, GIF_CLOSE_CALLBACK *pfnClose, GIF_READ_CALLBACK *pfnRead, GIF_SEEK_CALLBACK *pfnSeek, GIF_DRAW_CALLBACK *pfnDraw);
|
int open(const char* szFilename,
|
||||||
|
GIF_OPEN_CALLBACK* pfnOpen,
|
||||||
|
GIF_CLOSE_CALLBACK* pfnClose,
|
||||||
|
GIF_READ_CALLBACK* pfnRead,
|
||||||
|
GIF_SEEK_CALLBACK* pfnSeek,
|
||||||
|
GIF_DRAW_CALLBACK* pfnDraw);
|
||||||
void close();
|
void close();
|
||||||
void reset();
|
void reset();
|
||||||
void begin(unsigned char ucPaletteType = GIF_PALETTE_RGB565_LE);
|
void begin(unsigned char ucPaletteType = GIF_PALETTE_RGB565_LE);
|
||||||
void begin(int iEndian, unsigned char ucPaletteType) { begin(ucPaletteType); };
|
void begin(int iEndian, unsigned char ucPaletteType) {
|
||||||
int playFrame(bool bSync, int *delayMilliseconds, void *pUser = NULL);
|
begin(ucPaletteType);
|
||||||
|
};
|
||||||
|
int playFrame(bool bSync, int* delayMilliseconds, void* pUser = NULL);
|
||||||
int getCanvasWidth();
|
int getCanvasWidth();
|
||||||
int allocFrameBuf(GIF_ALLOC_CALLBACK *pfnAlloc);
|
int allocFrameBuf(GIF_ALLOC_CALLBACK* pfnAlloc);
|
||||||
int setDrawType(int iType);
|
int setDrawType(int iType);
|
||||||
int freeFrameBuf(GIF_FREE_CALLBACK *pfnFree);
|
int freeFrameBuf(GIF_FREE_CALLBACK* pfnFree);
|
||||||
uint8_t *getFrameBuf();
|
uint8_t* getFrameBuf();
|
||||||
int getCanvasHeight();
|
int getCanvasHeight();
|
||||||
int getLoopCount();
|
int getLoopCount();
|
||||||
int getInfo(GIFINFO *pInfo);
|
int getInfo(GIFINFO* pInfo);
|
||||||
int getLastError();
|
int getLastError();
|
||||||
int getComment(char *destBuffer);
|
int getComment(char* destBuffer);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
GIFIMAGE _gif;
|
GIFIMAGE _gif;
|
||||||
};
|
};
|
||||||
#else
|
#else
|
||||||
// C interface
|
// C interface
|
||||||
int GIF_openRAM(GIFIMAGE *pGIF, uint8_t *pData, int iDataSize, GIF_DRAW_CALLBACK *pfnDraw);
|
int GIF_openRAM(GIFIMAGE* pGIF, uint8_t* pData, int iDataSize, GIF_DRAW_CALLBACK* pfnDraw);
|
||||||
int GIF_openFile(GIFIMAGE *pGIF, const char *szFilename, GIF_DRAW_CALLBACK *pfnDraw);
|
int GIF_openFile(GIFIMAGE* pGIF, const char* szFilename, GIF_DRAW_CALLBACK* pfnDraw);
|
||||||
void GIF_close(GIFIMAGE *pGIF);
|
void GIF_close(GIFIMAGE* pGIF);
|
||||||
void GIF_begin(GIFIMAGE *pGIF, unsigned char ucPaletteType);
|
void GIF_begin(GIFIMAGE* pGIF, unsigned char ucPaletteType);
|
||||||
void GIF_reset(GIFIMAGE *pGIF);
|
void GIF_reset(GIFIMAGE* pGIF);
|
||||||
int GIF_playFrame(GIFIMAGE *pGIF, int *delayMilliseconds, void *pUser);
|
int GIF_playFrame(GIFIMAGE* pGIF, int* delayMilliseconds, void* pUser);
|
||||||
int GIF_getCanvasWidth(GIFIMAGE *pGIF);
|
int GIF_getCanvasWidth(GIFIMAGE* pGIF);
|
||||||
int GIF_getCanvasHeight(GIFIMAGE *pGIF);
|
int GIF_getCanvasHeight(GIFIMAGE* pGIF);
|
||||||
int GIF_getComment(GIFIMAGE *pGIF, char *destBuffer);
|
int GIF_getComment(GIFIMAGE* pGIF, char* destBuffer);
|
||||||
int GIF_getInfo(GIFIMAGE *pGIF, GIFINFO *pInfo);
|
int GIF_getInfo(GIFIMAGE* pGIF, GIFINFO* pInfo);
|
||||||
int GIF_getLastError(GIFIMAGE *pGIF);
|
int GIF_getLastError(GIFIMAGE* pGIF);
|
||||||
int GIF_getLoopCount(GIFIMAGE *pGIF);
|
int GIF_getLoopCount(GIFIMAGE* pGIF);
|
||||||
#endif // __cplusplus
|
#endif // __cplusplus
|
||||||
|
|
||||||
// Due to unaligned memory causing an exception, we have to do these macros the slow way
|
// Due to unaligned memory causing an exception, we have to do these macros the slow way
|
||||||
#define INTELSHORT(p) ((*p) + (*(p+1)<<8))
|
#define INTELSHORT(p) ((*p) + (*(p + 1) << 8))
|
||||||
#define INTELLONG(p) ((*p) + (*(p+1)<<8) + (*(p+2)<<16) + (*(p+3)<<24))
|
#define INTELLONG(p) ((*p) + (*(p + 1) << 8) + (*(p + 2) << 16) + (*(p + 3) << 24))
|
||||||
#define MOTOSHORT(p) (((*(p))<<8) + (*(p+1)))
|
#define MOTOSHORT(p) (((*(p)) << 8) + (*(p + 1)))
|
||||||
#define MOTOLONG(p) (((*p)<<24) + ((*(p+1))<<16) + ((*(p+2))<<8) + (*(p+3)))
|
#define MOTOLONG(p) (((*p) << 24) + ((*(p + 1)) << 16) + ((*(p + 2)) << 8) + (*(p + 3)))
|
||||||
|
|
||||||
// Must be a 32-bit target processor
|
// Must be a 32-bit target processor
|
||||||
#define REGISTER_WIDTH 32
|
#define REGISTER_WIDTH 32
|
||||||
|
|||||||
@@ -7,15 +7,15 @@
|
|||||||
|
|
||||||
#ifndef INC_LCD_API_H_
|
#ifndef INC_LCD_API_H_
|
||||||
#define INC_LCD_API_H_
|
#define INC_LCD_API_H_
|
||||||
|
#include <ctype.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
|
||||||
|
|
||||||
#define LOGGER_LEVEL_ALL
|
#define LOGGER_LEVEL_ALL
|
||||||
#include "log.h"
|
|
||||||
#include "../../Drivers/BSP/STM32746G-Discovery/stm32746g_discovery_lcd.h"
|
#include "../../Drivers/BSP/STM32746G-Discovery/stm32746g_discovery_lcd.h"
|
||||||
#include "llfs.h"
|
|
||||||
#include "gifdec.h"
|
#include "gifdec.h"
|
||||||
|
#include "llfs.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The maximum amount of GIFs that can be displayed at the same time
|
* @brief The maximum amount of GIFs that can be displayed at the same time
|
||||||
@@ -23,46 +23,45 @@
|
|||||||
*/
|
*/
|
||||||
#define LCD_MAX_GIFS 5
|
#define LCD_MAX_GIFS 5
|
||||||
|
|
||||||
#define LCD_BLUE LCD_COLOR_BLUE
|
#define LCD_BLUE LCD_COLOR_BLUE
|
||||||
#define LCD_GREEN LCD_COLOR_GREEN
|
#define LCD_GREEN LCD_COLOR_GREEN
|
||||||
#define LCD_RED LCD_COLOR_RED
|
#define LCD_RED LCD_COLOR_RED
|
||||||
#define LCD_CYAN LCD_COLOR_CYAN
|
#define LCD_CYAN LCD_COLOR_CYAN
|
||||||
#define LCD_MAGENTA LCD_COLOR_MAGENTA
|
#define LCD_MAGENTA LCD_COLOR_MAGENTA
|
||||||
#define LCD_YELLOW LCD_COLOR_YELLOW
|
#define LCD_YELLOW LCD_COLOR_YELLOW
|
||||||
#define LCD_LIGHTBLUE LCD_COLOR_LIGHTBLUE
|
#define LCD_LIGHTBLUE LCD_COLOR_LIGHTBLUE
|
||||||
#define LCD_LIGHTGREEN LCD_COLOR_LIGHTGREEN
|
#define LCD_LIGHTGREEN LCD_COLOR_LIGHTGREEN
|
||||||
#define LCD_LIGHTRED LCD_COLOR_LIGHTRED
|
#define LCD_LIGHTRED LCD_COLOR_LIGHTRED
|
||||||
#define LCD_LIGHTCYAN LCD_COLOR_LIGHTCYAN
|
#define LCD_LIGHTCYAN LCD_COLOR_LIGHTCYAN
|
||||||
#define LCD_LIGHTMAGENTA LCD_COLOR_LIGHTMAGENTA
|
#define LCD_LIGHTMAGENTA LCD_COLOR_LIGHTMAGENTA
|
||||||
#define LCD_LIGHTYELLOW LCD_COLOR_LIGHTYELLOW
|
#define LCD_LIGHTYELLOW LCD_COLOR_LIGHTYELLOW
|
||||||
#define LCD_DARKBLUE LCD_COLOR_DARKBLUE
|
#define LCD_DARKBLUE LCD_COLOR_DARKBLUE
|
||||||
#define LCD_DARKGREEN LCD_COLOR_DARKGREEN
|
#define LCD_DARKGREEN LCD_COLOR_DARKGREEN
|
||||||
#define LCD_DARKRED LCD_COLOR_DARKRED
|
#define LCD_DARKRED LCD_COLOR_DARKRED
|
||||||
#define LCD_DARKCYAN LCD_COLOR_DARKCYAN
|
#define LCD_DARKCYAN LCD_COLOR_DARKCYAN
|
||||||
#define LCD_DARKMAGENTA LCD_COLOR_DARKMAGENTA
|
#define LCD_DARKMAGENTA LCD_COLOR_DARKMAGENTA
|
||||||
#define LCD_DARKYELLOW LCD_COLOR_DARKYELLOW
|
#define LCD_DARKYELLOW LCD_COLOR_DARKYELLOW
|
||||||
#define LCD_WHITE LCD_COLOR_WHITE
|
#define LCD_WHITE LCD_COLOR_WHITE
|
||||||
#define LCD_LIGHTGRAY LCD_COLOR_LIGHTGRAY
|
#define LCD_LIGHTGRAY LCD_COLOR_LIGHTGRAY
|
||||||
#define LCD_GRAY LCD_COLOR_GRAY
|
#define LCD_GRAY LCD_COLOR_GRAY
|
||||||
#define LCD_DARKGRAY LCD_COLOR_DARKGRAY
|
#define LCD_DARKGRAY LCD_COLOR_DARKGRAY
|
||||||
#define LCD_BLACK LCD_COLOR_BLACK
|
#define LCD_BLACK LCD_COLOR_BLACK
|
||||||
#define LCD_BROWN LCD_COLOR_BROWN
|
#define LCD_BROWN LCD_COLOR_BROWN
|
||||||
#define LCD_ORANGE LCD_COLOR_ORANGE
|
#define LCD_ORANGE LCD_COLOR_ORANGE
|
||||||
#define LCD_TRANSPARENT LCD_COLOR_TRANSPARENT
|
#define LCD_TRANSPARENT LCD_COLOR_TRANSPARENT
|
||||||
|
|
||||||
#define LCD_ARGB8888 0x00000000U
|
#define LCD_ARGB8888 0x00000000U
|
||||||
#define LCD_RGB888 0x00000001U
|
#define LCD_RGB888 0x00000001U
|
||||||
#define LCD_RGB565 0x00000002U
|
#define LCD_RGB565 0x00000002U
|
||||||
#define LCD_ARGB1555 0x00000003U
|
#define LCD_ARGB1555 0x00000003U
|
||||||
|
|
||||||
#define LCD_FONT8 (&Font8)
|
#define LCD_FONT8 (&Font8)
|
||||||
#define LCD_FONT12 (&Font12)
|
#define LCD_FONT12 (&Font12)
|
||||||
#define LCD_FONT16 (&Font16)
|
#define LCD_FONT16 (&Font16)
|
||||||
#define LCD_FONT20 (&Font20)
|
#define LCD_FONT20 (&Font20)
|
||||||
#define LCD_FONT24 (&Font24)
|
#define LCD_FONT24 (&Font24)
|
||||||
|
|
||||||
|
extern LTDC_HandleTypeDef hLtdcHandler;
|
||||||
extern LTDC_HandleTypeDef hLtdcHandler;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
GIFIMAGE gif;
|
GIFIMAGE gif;
|
||||||
@@ -105,7 +104,7 @@ void lcd_task(void);
|
|||||||
* @param[in] bg_color Text background color
|
* @param[in] bg_color Text background color
|
||||||
* @param[in] font Font size, see defines above in file
|
* @param[in] font Font size, see defines above in file
|
||||||
*/
|
*/
|
||||||
void lcd_display_text(const char* text, uint32_t x_pos, uint32_t y_pos, uint32_t color, uint32_t bg_color, sFONT *font);
|
void lcd_display_text(const char* text, uint32_t x_pos, uint32_t y_pos, uint32_t color, uint32_t bg_color, sFONT* font);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Draw BMP image on screen
|
* @brief Draw BMP image on screen
|
||||||
@@ -121,7 +120,12 @@ void lcd_display_text(const char* text, uint32_t x_pos, uint32_t y_pos, uint32_t
|
|||||||
* @param[in] y_size Height of image
|
* @param[in] y_size Height of image
|
||||||
* @param[in] color_mode Color mode (see defined color modes above in file)
|
* @param[in] color_mode Color mode (see defined color modes above in file)
|
||||||
*/
|
*/
|
||||||
void lcd_draw_raw_img(const void* p_src, uint32_t x_pos, uint32_t y_pos, uint32_t x_size, uint32_t y_size, uint32_t color_mode);
|
void lcd_draw_raw_img(const void* p_src,
|
||||||
|
uint32_t x_pos,
|
||||||
|
uint32_t y_pos,
|
||||||
|
uint32_t x_size,
|
||||||
|
uint32_t y_size,
|
||||||
|
uint32_t color_mode);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Draw BMP image on screen
|
* @brief Draw BMP image on screen
|
||||||
@@ -148,8 +152,8 @@ void lcd_draw_img_from_fs(const char* name, uint32_t x_pos, uint32_t y_pos);
|
|||||||
/**
|
/**
|
||||||
* @brief Draw BMP image on screen by specifying the llfs_file_t, the BMP image has in the file system
|
* @brief Draw BMP image on screen by specifying the llfs_file_t, the BMP image has in the file system
|
||||||
* Draw BMP image from C array to the LCD screen at position X, Y by specifying the BMP image name on the filesystem
|
* Draw BMP image from C array to the LCD screen at position X, Y by specifying the BMP image name on the filesystem
|
||||||
* Supports ARGB8888, RGB565, RGB888
|
* Supports ARGB8888, RGB565, RGB888
|
||||||
*
|
*
|
||||||
* @param file pointer to the llfs_file_t
|
* @param file pointer to the llfs_file_t
|
||||||
* @param x_pos X-position
|
* @param x_pos X-position
|
||||||
* @param y_pos Y-position
|
* @param y_pos Y-position
|
||||||
@@ -187,7 +191,8 @@ void lcd_stop_all_gifs(void);
|
|||||||
/**
|
/**
|
||||||
* @brief Draw GIF image on screen from memory
|
* @brief Draw GIF image on screen from memory
|
||||||
* Draw GIF image from memory to the LCD screen at position X, Y
|
* Draw GIF image from memory to the LCD screen at position X, Y
|
||||||
* @warning If the GIF has a loop count specified, it will stop after the specified amount of loops and the lcd_gif_t handle will be invalid for further use
|
* @warning If the GIF has a loop count specified, it will stop after the specified amount of loops and the lcd_gif_t
|
||||||
|
* handle will be invalid for further use
|
||||||
* @note Before drawing over a GIF, make sure to call lcd_stop_gif(), otherwise the GIF will keep overwriting the screen
|
* @note Before drawing over a GIF, make sure to call lcd_stop_gif(), otherwise the GIF will keep overwriting the screen
|
||||||
*
|
*
|
||||||
* @param src Pointer to the GIF image data
|
* @param src Pointer to the GIF image data
|
||||||
@@ -201,7 +206,8 @@ lcd_gif_t* lcd_draw_gif(uint8_t* src, size_t size, uint32_t x_pos, uint32_t y_po
|
|||||||
/**
|
/**
|
||||||
* @brief Draw GIF image on screen from filesystem
|
* @brief Draw GIF image on screen from filesystem
|
||||||
* Draw GIF image from filesystem to the LCD screen at position X, Y
|
* Draw GIF image from filesystem to the LCD screen at position X, Y
|
||||||
* @warning If the GIF has a loop count specified, it will stop after the specified amount of loops and the lcd_git_t handle will be invalidated
|
* @warning If the GIF has a loop count specified, it will stop after the specified amount of loops and the lcd_git_t
|
||||||
|
* handle will be invalidated
|
||||||
* @note Before drawing over a GIF, make sure to call lcd_stop_gif(), otherwise the GIF will keep overwriting the screen
|
* @note Before drawing over a GIF, make sure to call lcd_stop_gif(), otherwise the GIF will keep overwriting the screen
|
||||||
*
|
*
|
||||||
* @param name The filename of the GIF image
|
* @param name The filename of the GIF image
|
||||||
@@ -212,11 +218,12 @@ lcd_gif_t* lcd_draw_gif(uint8_t* src, size_t size, uint32_t x_pos, uint32_t y_po
|
|||||||
lcd_gif_t* lcd_draw_gif_from_fs(const char* name, uint32_t x_pos, uint32_t y_pos);
|
lcd_gif_t* lcd_draw_gif_from_fs(const char* name, uint32_t x_pos, uint32_t y_pos);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Draw GIF image on screen from filesystem
|
* @brief Draw GIF image on screen from filesystem
|
||||||
* Draw GIF image from filesystem to the LCD screen at position X, Y
|
* Draw GIF image from filesystem to the LCD screen at position X, Y
|
||||||
* @warning If the GIF has a loop count specified, it will stop after the specified amount of loops and the lcd_git_t handle will be invalidated
|
* @warning If the GIF has a loop count specified, it will stop after the specified amount of loops and the lcd_git_t
|
||||||
* @note Before drawing over a GIF, make sure to call lcd_stop_gif(), otherwise the GIF will keep overwriting the screen
|
* handle will be invalidated
|
||||||
*
|
* @note Before drawing over a GIF, make sure to call lcd_stop_gif(), otherwise the GIF will keep overwriting the screen
|
||||||
|
*
|
||||||
* @param file The pointer to the llfs_file_t
|
* @param file The pointer to the llfs_file_t
|
||||||
* @param x_pos The X position on the screen
|
* @param x_pos The X position on the screen
|
||||||
* @param y_pos The Y position on the screen
|
* @param y_pos The Y position on the screen
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
#ifndef LOG_H
|
#ifndef LOG_H
|
||||||
#define LOG_H
|
#define LOG_H
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/times.h>
|
#include <sys/times.h>
|
||||||
@@ -52,24 +52,24 @@
|
|||||||
|
|
||||||
#define CLEAR_SCREEN "\033c"
|
#define CLEAR_SCREEN "\033c"
|
||||||
|
|
||||||
#define CURSOR_RESET ANSI_ESC "[H"
|
#define CURSOR_RESET ANSI_ESC "[H"
|
||||||
#define CURSOR_UP(n) ANSI_ESC "[" #n "A"
|
#define CURSOR_UP(n) ANSI_ESC "[" #n "A"
|
||||||
#define CURSOR_DOWN(n) ANSI_ESC "[" #n "B"
|
#define CURSOR_DOWN(n) ANSI_ESC "[" #n "B"
|
||||||
#define CURSOR_RIGHT(n) ANSI_ESC "[" #n "C"
|
#define CURSOR_RIGHT(n) ANSI_ESC "[" #n "C"
|
||||||
#define CURSOR_LEFT(n) ANSI_ESC "[" #n "D"
|
#define CURSOR_LEFT(n) ANSI_ESC "[" #n "D"
|
||||||
#define CURSOR_NEXT_N_LINES(n) ANSI_ESC "[" #n "E"
|
#define CURSOR_NEXT_N_LINES(n) ANSI_ESC "[" #n "E"
|
||||||
#define CURSOR_PREV_N_LINES(n) ANSI_ESC "[" #n "F"
|
#define CURSOR_PREV_N_LINES(n) ANSI_ESC "[" #n "F"
|
||||||
#define CURSOR_COL(n) ANSI_ESC "[" #n "G"
|
#define CURSOR_COL(n) ANSI_ESC "[" #n "G"
|
||||||
#define CURSOR_POS ANSI_ESC "[" #n ";" #n "H"
|
#define CURSOR_POS ANSI_ESC "[" #n ";" #n "H"
|
||||||
#define CURSOR_SAVE ANSI_ESC "7"
|
#define CURSOR_SAVE ANSI_ESC "7"
|
||||||
#define CURSOR_RESTORE ANSI_ESC "8"
|
#define CURSOR_RESTORE ANSI_ESC "8"
|
||||||
|
|
||||||
#define ERASE_FROM_CURSOR_TO_END ANSI_ESC "[0J"
|
#define ERASE_FROM_CURSOR_TO_END ANSI_ESC "[0J"
|
||||||
#define ERASE_FROM_CURSOR_TO_BEGINNING ANSI_ESC "[1J"
|
#define ERASE_FROM_CURSOR_TO_BEGINNING ANSI_ESC "[1J"
|
||||||
#define ERASE_ENTIRE_SCREEN ANSI_ESC "[2J"
|
#define ERASE_ENTIRE_SCREEN ANSI_ESC "[2J"
|
||||||
#define ERASE_FROM_CURSOR_TO_END_LINE ANSI_ESC "[0K"
|
#define ERASE_FROM_CURSOR_TO_END_LINE ANSI_ESC "[0K"
|
||||||
#define ERASE_FROM_CURSOR_TO_BEGINNING_LINE ANSI_ESC "[1K"
|
#define ERASE_FROM_CURSOR_TO_BEGINNING_LINE ANSI_ESC "[1K"
|
||||||
#define ERASE_ENTIRE_LINE ANSI_ESC "[2K"
|
#define ERASE_ENTIRE_LINE ANSI_ESC "[2K"
|
||||||
|
|
||||||
#if LOGGER_COLOR == 1
|
#if LOGGER_COLOR == 1
|
||||||
#define LOG_RESET_COLOR "\033[0m"
|
#define LOG_RESET_COLOR "\033[0m"
|
||||||
@@ -88,27 +88,37 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if LOGGER_LEVEL <= 1
|
#if LOGGER_LEVEL <= 1
|
||||||
#define LOG_DEBUG(tag, fmt, ...) printf(LOG_COLOR_D"[Debug] (%8lu) [%s]: " fmt LOG_RESET_COLOR "\r\n", logger_get_timestamp(), tag, ##__VA_ARGS__)
|
#define LOG_DEBUG(tag, fmt, ...) \
|
||||||
|
printf(LOG_COLOR_D "[Debug] (%8lu) [%s]: " fmt LOG_RESET_COLOR "\r\n", logger_get_timestamp(), tag, \
|
||||||
|
##__VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define LOG_DEBUG(tag, fmt, ...)
|
#define LOG_DEBUG(tag, fmt, ...)
|
||||||
#endif
|
#endif
|
||||||
#if LOGGER_LEVEL <= 2
|
#if LOGGER_LEVEL <= 2
|
||||||
#define LOG_INFO(tag, fmt, ...) printf(LOG_COLOR_I"[Info] (%8lu) [%s]: " fmt LOG_RESET_COLOR "\r\n", logger_get_timestamp(), tag, ##__VA_ARGS__)
|
#define LOG_INFO(tag, fmt, ...) \
|
||||||
|
printf(LOG_COLOR_I "[Info] (%8lu) [%s]: " fmt LOG_RESET_COLOR "\r\n", logger_get_timestamp(), tag, \
|
||||||
|
##__VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define LOG_INFO(tag, fmt, ...)
|
#define LOG_INFO(tag, fmt, ...)
|
||||||
#endif
|
#endif
|
||||||
#if LOGGER_LEVEL <= 3
|
#if LOGGER_LEVEL <= 3
|
||||||
#define LOG_WARN(tag, fmt, ...) printf(LOG_COLOR_W"[Warning] (%8lu) [%s]: " fmt LOG_RESET_COLOR "\r\n", logger_get_timestamp(), tag, ##__VA_ARGS__)
|
#define LOG_WARN(tag, fmt, ...) \
|
||||||
|
printf(LOG_COLOR_W "[Warning] (%8lu) [%s]: " fmt LOG_RESET_COLOR "\r\n", logger_get_timestamp(), tag, \
|
||||||
|
##__VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define LOG_WARN(tag, fmt, ...)
|
#define LOG_WARN(tag, fmt, ...)
|
||||||
#endif
|
#endif
|
||||||
#if LOGGER_LEVEL <= 4
|
#if LOGGER_LEVEL <= 4
|
||||||
#define LOG_CRIT(tag, fmt, ...) printf(LOG_COLOR_C"[Critical] (%8lu) [%s]: " fmt LOG_RESET_COLOR "\r\n", logger_get_timestamp(), tag, ##__VA_ARGS__)
|
#define LOG_CRIT(tag, fmt, ...) \
|
||||||
|
printf(LOG_COLOR_C "[Critical] (%8lu) [%s]: " fmt LOG_RESET_COLOR "\r\n", logger_get_timestamp(), tag, \
|
||||||
|
##__VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define LOG_CRIT(tag, fmt, ...)
|
#define LOG_CRIT(tag, fmt, ...)
|
||||||
#endif
|
#endif
|
||||||
#if LOGGER_LEVEL <= 4
|
#if LOGGER_LEVEL <= 4
|
||||||
#define LOG_FATAL(tag, fmt, ...) printf(LOG_COLOR_F"[Fatal] (%8lu) [%s]: " fmt LOG_RESET_COLOR "\r\n", logger_get_timestamp(), tag, ##__VA_ARGS__)
|
#define LOG_FATAL(tag, fmt, ...) \
|
||||||
|
printf(LOG_COLOR_F "[Fatal] (%8lu) [%s]: " fmt LOG_RESET_COLOR "\r\n", logger_get_timestamp(), tag, \
|
||||||
|
##__VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define LOG_FATAL(tag, fmt, ...)
|
#define LOG_FATAL(tag, fmt, ...)
|
||||||
#endif
|
#endif
|
||||||
@@ -117,6 +127,6 @@
|
|||||||
* Use the LOG_* macros instead e.g., LOG_DEBUG(TAG, "Debug message");
|
* Use the LOG_* macros instead e.g., LOG_DEBUG(TAG, "Debug message");
|
||||||
*/
|
*/
|
||||||
uint32_t logger_get_timestamp(void);
|
uint32_t logger_get_timestamp(void);
|
||||||
int _write(int file, char *data, int len);
|
int _write(int file, char* data, int len);
|
||||||
|
|
||||||
#endif /* LOG_H */
|
#endif /* LOG_H */
|
||||||
@@ -1,29 +1,20 @@
|
|||||||
/**
|
/**
|
||||||
* @file modbus_tcp.h
|
* @file modbus_tcp.h
|
||||||
*
|
* @brief TCP Modbus server
|
||||||
* @brief TCP Modbus handler
|
* @date Nov 29, 2023
|
||||||
* @date Nov 6, 2023
|
|
||||||
* @author Obe
|
* @author Obe
|
||||||
|
* @author Lorenz C.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef INC_MODBUS_H_
|
#ifndef INC_MODBUS_H_
|
||||||
#define INC_MODBUS_H_
|
#define INC_MODBUS_H_
|
||||||
|
|
||||||
#define MODBUSPORT 502 // 502 is the default
|
#define MODBUS_TCP_PORT 502
|
||||||
|
|
||||||
|
|
||||||
#include <tcp.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "lcd_api.h"
|
|
||||||
#include "llfs.h"
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fn void modbus_init
|
* @brief Initializes the modbus tcp server
|
||||||
* @brief Initializes the modbus tcp
|
|
||||||
*/
|
*/
|
||||||
void modbus_init(void);
|
void modbus_tcp_init(void);
|
||||||
|
|
||||||
#endif /* INC_MODBUS_H_ */
|
#endif /* INC_MODBUS_H_ */
|
||||||
|
|||||||
@@ -1,21 +1,19 @@
|
|||||||
/**
|
/**
|
||||||
* @file tcp_cmd.h
|
* @file tcp_cmd.h
|
||||||
* @brief TCP CMD interface
|
* @brief TCP CMD interface
|
||||||
* @author Gert R.
|
* @author Gert R.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef INC_TCP_CMD_H_
|
#ifndef INC_TCP_CMD_H_
|
||||||
#define INC_TCP_CMD_H_
|
#define INC_TCP_CMD_H_
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <tcp.h>
|
||||||
#include "lcd_api.h"
|
#include "lcd_api.h"
|
||||||
#include "llfs.h"
|
#include "llfs.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include <tcp.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
|
|
||||||
void tcp_cmd_init( void );
|
|
||||||
|
|
||||||
|
void tcp_cmd_init(void);
|
||||||
|
|
||||||
#endif /* INC_TCP_CMD_H_ */
|
#endif /* INC_TCP_CMD_H_ */
|
||||||
|
|||||||
82
project/Core/Inc/website_backend.h
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
/**
|
||||||
|
* @file website_backend.h
|
||||||
|
* @brief Backend for the website to operate
|
||||||
|
* @author Toon B.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INC_WEBSITE_BACKEND_
|
||||||
|
#define INC_WEBSITE_BACKEND_
|
||||||
|
|
||||||
|
/* Include headers C lib */
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* Defines */
|
||||||
|
#define LOGGER_LEVEL_ALL
|
||||||
|
#define STR_MAX 200
|
||||||
|
#define CLR_MAX 11
|
||||||
|
#define IMG_X 0
|
||||||
|
#define IMG_Y 0
|
||||||
|
#define SD_IMG "st.bmp"
|
||||||
|
|
||||||
|
/* Include headers */
|
||||||
|
#include "httpd.h"
|
||||||
|
#include "lcd_api.h"
|
||||||
|
#include "llfs.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "lwip.h"
|
||||||
|
#include "lwip/apps/fs.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fn void wbe_init(void)
|
||||||
|
* @brief Initialise the http server. It also sets the beginning screen
|
||||||
|
* of the display.
|
||||||
|
*/
|
||||||
|
void wbe_init(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fn int fs_open_custom(struct fs_file*, const char*)
|
||||||
|
* @brief Function is called when the frontend wants to reach/open a file
|
||||||
|
* or endpoint on the backend.
|
||||||
|
*
|
||||||
|
* @param[in] file, the file pointer of the file that the frontend wants
|
||||||
|
* @param[in] name, the name of the file or endpoint that the frontend asks for
|
||||||
|
* @return[out] returns 0 if file or endpoint was not found, 1 if it was found
|
||||||
|
*/
|
||||||
|
int fs_open_custom(struct fs_file* file, const char* name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fn void fs_close_custom(struct fs_file*)
|
||||||
|
* @brief Called when closing files and endpoints
|
||||||
|
*
|
||||||
|
* @param[in] file, the file pointer of the file that the frontend wants
|
||||||
|
*/
|
||||||
|
void fs_close_custom(struct fs_file* file);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fn void httpd_cgi_handler(struct fs_file*, const char*, int, char**, char**)
|
||||||
|
* @brief When data is send from the frontend to the backend with the CGI
|
||||||
|
* tag and parameters, this function is called. With this comes parameters that
|
||||||
|
* we want to read for further use.
|
||||||
|
*
|
||||||
|
* @param[in] file, the file pointer of the file that the frontend wants
|
||||||
|
* @param[in] uri, the URI that is given to the backend from the frontend (here cgi)
|
||||||
|
* @param[in] num_parm, the number of parameters that is given with the URI
|
||||||
|
* @param[in] pc_param, contains the name of each parameter
|
||||||
|
* @param[in] pc_value, is the value of each parameter
|
||||||
|
*/
|
||||||
|
void httpd_cgi_handler(struct fs_file* file, const char* uri, int num_parm, char** pc_param, char** pc_value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fn void wbe_display(const char*, const uint32_t, const uint32_t, const char*)
|
||||||
|
* @brief Function displays the sentence, its color, the background and the given
|
||||||
|
* image on the LCD screen.
|
||||||
|
*
|
||||||
|
* @param[in] txt, is the text string that needs to be displayed
|
||||||
|
* @param[in] txt_color, the color of the wanted string
|
||||||
|
* @param[in] background_color, color of the background of the screen
|
||||||
|
* @param[in] image, name of the wanted image to be displayed
|
||||||
|
*/
|
||||||
|
void wbe_display(const char* txt, const uint32_t txt_color, const uint32_t background_color, const char* image);
|
||||||
|
|
||||||
|
#endif /* INC_WEBSITE_BACKEND_ */
|
||||||
@@ -49,20 +49,18 @@ static void udp_broadcast_set_owner_details_mac(void) {
|
|||||||
* @see UDP_BROADCAST_LCD_NAME_PRE_TEXT in front of it
|
* @see UDP_BROADCAST_LCD_NAME_PRE_TEXT in front of it
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void udp_broadcast_name_to_lcd(void){
|
static void udp_broadcast_name_to_lcd(void) {
|
||||||
char text[UDP_BROADCAST_LCD_TEXT_SIZE];
|
char text[UDP_BROADCAST_LCD_TEXT_SIZE];
|
||||||
|
|
||||||
memset(text,' ',UDP_BROADCAST_LCD_TEXT_SIZE); // Fill with spaces
|
memset(text, ' ', UDP_BROADCAST_LCD_TEXT_SIZE); // Fill with spaces
|
||||||
text[UDP_BROADCAST_LCD_TEXT_SIZE - 1] = '\0'; // Make the last a NULL byte
|
text[UDP_BROADCAST_LCD_TEXT_SIZE - 1] = '\0'; // Make the last a NULL byte
|
||||||
lcd_display_text(text, owner_name_x_pos, owner_name_y_pos, LCD_BLACK, LCD_WHITE, LCD_FONT12);
|
lcd_display_text(text, owner_name_x_pos, owner_name_y_pos, LCD_BLACK, LCD_WHITE, LCD_FONT12);
|
||||||
|
|
||||||
snprintf(text, UDP_BROADCAST_LCD_TEXT_SIZE, "%s%s",UDP_BROADCAST_LCD_NAME_PRE_TEXT,
|
snprintf(text, UDP_BROADCAST_LCD_TEXT_SIZE, "%s%s", UDP_BROADCAST_LCD_NAME_PRE_TEXT, udp_owner.name);
|
||||||
udp_owner.name);
|
|
||||||
|
|
||||||
lcd_display_text(text, owner_name_x_pos, owner_name_y_pos, LCD_BLACK, LCD_WHITE, LCD_FONT12);
|
lcd_display_text(text, owner_name_x_pos, owner_name_y_pos, LCD_BLACK, LCD_WHITE, LCD_FONT12);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fn uint8_t udp_broadcast_set_owner_details_name(owner_details_t*, const char*)
|
* @fn uint8_t udp_broadcast_set_owner_details_name(owner_details_t*, const char*)
|
||||||
* @brief set_owner_details_name() sets the owner's name in the owner_details_t struct
|
* @brief set_owner_details_name() sets the owner's name in the owner_details_t struct
|
||||||
@@ -76,13 +74,12 @@ static void udp_broadcast_name_to_lcd(void){
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static uint8_t udp_broadcast_set_owner_details_name(const char* name) {
|
static uint8_t udp_broadcast_set_owner_details_name(const char* name) {
|
||||||
|
|
||||||
if (name == NULL) {
|
if (name == NULL) {
|
||||||
LOG_WARN(TAG, "%s: string given is a NULL pointer", __func__);
|
LOG_WARN(TAG, "%s: string given is a NULL pointer", __func__);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
LOG_DEBUG(TAG, "set: %s", name);
|
LOG_DEBUG(TAG, "set: %s", name);
|
||||||
strncpy(udp_owner.name, name, sizeof(udp_owner.name) - 1); // -1: compensate for '\0'
|
strncpy(udp_owner.name, name, sizeof(udp_owner.name) - 1); // -1: compensate for '\0'
|
||||||
|
|
||||||
udp_broadcast_name_to_lcd();
|
udp_broadcast_name_to_lcd();
|
||||||
return 0;
|
return 0;
|
||||||
@@ -104,7 +101,7 @@ static uint8_t udp_broadcast_set_owner_details_surname(const char* surname) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
LOG_DEBUG(TAG, "set: %s", surname);
|
LOG_DEBUG(TAG, "set: %s", surname);
|
||||||
strncpy(udp_owner.surname, surname, sizeof(udp_owner.surname)-1); // -1: compensate for '\0'
|
strncpy(udp_owner.surname, surname, sizeof(udp_owner.surname) - 1); // -1: compensate for '\0'
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,7 +122,7 @@ static uint8_t udp_broadcast_set_owner_details_reply(const char* reply) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
LOG_DEBUG(TAG, "set: %s", reply);
|
LOG_DEBUG(TAG, "set: %s", reply);
|
||||||
strncpy(udp_owner.reply, reply, sizeof(udp_owner.reply) - 1); // -1: compensate for '\0'
|
strncpy(udp_owner.reply, reply, sizeof(udp_owner.reply) - 1); // -1: compensate for '\0'
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,8 +141,8 @@ static void udp_broadcast_format_reply(void) {
|
|||||||
udp_owner.mac_address[1], udp_owner.mac_address[2], udp_owner.mac_address[3], udp_owner.mac_address[4],
|
udp_owner.mac_address[1], udp_owner.mac_address[2], udp_owner.mac_address[3], udp_owner.mac_address[4],
|
||||||
udp_owner.mac_address[5]);
|
udp_owner.mac_address[5]);
|
||||||
|
|
||||||
snprintf(reply_buf, UDP_BROADCAST_MAX_REPLY_SIZE, "%s %s %s %s", mac_addr_str, UDP_BROADCAST_REPLY_MIDDLE_TEXT, udp_owner.surname,
|
snprintf(reply_buf, UDP_BROADCAST_MAX_REPLY_SIZE, "%s %s %s %s", mac_addr_str, UDP_BROADCAST_REPLY_MIDDLE_TEXT,
|
||||||
udp_owner.name);
|
udp_owner.surname, udp_owner.name);
|
||||||
udp_broadcast_set_owner_details_reply(reply_buf);
|
udp_broadcast_set_owner_details_reply(reply_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,7 +160,6 @@ static void udp_broadcast_format_reply(void) {
|
|||||||
*/
|
*/
|
||||||
err_t udp_broadcast_set_owner_details(const char* name, const char* surname) {
|
err_t udp_broadcast_set_owner_details(const char* name, const char* surname) {
|
||||||
if (!udp_broadcast_set_owner_details_name(name) && !udp_broadcast_set_owner_details_surname(surname)) {
|
if (!udp_broadcast_set_owner_details_name(name) && !udp_broadcast_set_owner_details_surname(surname)) {
|
||||||
|
|
||||||
// If both return 0 it's okay
|
// If both return 0 it's okay
|
||||||
udp_broadcast_set_owner_details_mac();
|
udp_broadcast_set_owner_details_mac();
|
||||||
udp_broadcast_format_reply();
|
udp_broadcast_format_reply();
|
||||||
@@ -234,7 +230,7 @@ static uint8_t udp_broadcast_check_function(const char data[UDP_BROADCAST_MAX_DA
|
|||||||
memset(func, 0, sizeof(func));
|
memset(func, 0, sizeof(func));
|
||||||
memset(buffer, 0, sizeof(buffer));
|
memset(buffer, 0, sizeof(buffer));
|
||||||
|
|
||||||
memcpy(func,data,UDP_BROADCAST_MAX_FUNC_LEN - 1);
|
memcpy(func, data, UDP_BROADCAST_MAX_FUNC_LEN - 1);
|
||||||
if (strcmp(func, "func1:") != 0) {
|
if (strcmp(func, "func1:") != 0) {
|
||||||
LOG_WARN(TAG, "%s: datagram does not contain function that's currently available", __func__);
|
LOG_WARN(TAG, "%s: datagram does not contain function that's currently available", __func__);
|
||||||
return 1;
|
return 1;
|
||||||
@@ -245,16 +241,16 @@ static uint8_t udp_broadcast_check_function(const char data[UDP_BROADCAST_MAX_DA
|
|||||||
counter++;
|
counter++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (enders[2] - enders[1] < UDP_BROADCAST_MAX_NAME_SIZE + 2 && data_len - enders[3] < UDP_BROADCAST_MAX_NAME_SIZE + 2
|
if (enders[2] - enders[1] < UDP_BROADCAST_MAX_NAME_SIZE + 2
|
||||||
&& strncmp(data + enders[0], ":name", 5) == 0 && strncmp(data + enders[2], ", surname", 9) == 0) {
|
&& data_len - enders[3] < UDP_BROADCAST_MAX_NAME_SIZE + 2 && strncmp(data + enders[0], ":name", 5) == 0
|
||||||
|
&& strncmp(data + enders[2], ", surname", 9) == 0) {
|
||||||
counter = 0;
|
counter = 0;
|
||||||
for (uint8_t i = enders[1] + 2; i < enders[2]; i++) {
|
for (uint8_t i = enders[1] + 2; i < enders[2]; i++) {
|
||||||
buffer[counter] = data[i];
|
buffer[counter] = data[i];
|
||||||
counter++;
|
counter++;
|
||||||
}
|
}
|
||||||
if (buffer[0]=='\0') {
|
if (buffer[0] == '\0') {
|
||||||
strncpy(buffer, "name", sizeof(buffer) - 1); // -1: compensate for '\0'
|
strncpy(buffer, "name", sizeof(buffer) - 1); // -1: compensate for '\0'
|
||||||
}
|
}
|
||||||
LOG_INFO(TAG, "new owner name:%s", buffer);
|
LOG_INFO(TAG, "new owner name:%s", buffer);
|
||||||
udp_broadcast_set_owner_details_name(buffer);
|
udp_broadcast_set_owner_details_name(buffer);
|
||||||
@@ -264,15 +260,15 @@ static uint8_t udp_broadcast_check_function(const char data[UDP_BROADCAST_MAX_DA
|
|||||||
buffer[counter] = data[i];
|
buffer[counter] = data[i];
|
||||||
counter++;
|
counter++;
|
||||||
}
|
}
|
||||||
if (buffer[0]=='\0') {
|
if (buffer[0] == '\0') {
|
||||||
strncpy(buffer, "default", sizeof(buffer) - 1); // -1: compensate for '\0'
|
strncpy(buffer, "default", sizeof(buffer) - 1); // -1: compensate for '\0'
|
||||||
}
|
}
|
||||||
LOG_INFO(TAG, "new owner surname:%s", buffer);
|
LOG_INFO(TAG, "new owner surname:%s", buffer);
|
||||||
udp_broadcast_set_owner_details_surname(buffer);
|
udp_broadcast_set_owner_details_surname(buffer);
|
||||||
udp_broadcast_format_reply();
|
udp_broadcast_format_reply();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
LOG_WARN(TAG,"%s: function didn't receive the right formatting", __func__);
|
LOG_WARN(TAG, "%s: function didn't receive the right formatting", __func__);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,7 +307,7 @@ static void udp_receive_callback(void* arg,
|
|||||||
}
|
}
|
||||||
pc = (char*)p->payload;
|
pc = (char*)p->payload;
|
||||||
len = p->tot_len;
|
len = p->tot_len;
|
||||||
if (len >= UDP_BROADCAST_MAX_DATA_SIZE) { // >= : only if it's smaller to compensate for '\0'
|
if (len >= UDP_BROADCAST_MAX_DATA_SIZE) { // >= : only if it's smaller to compensate for '\0'
|
||||||
LOG_WARN(TAG, "%s: input buffer was bigger than or was max size %d", __func__, UDP_BROADCAST_MAX_DATA_SIZE);
|
LOG_WARN(TAG, "%s: input buffer was bigger than or was max size %d", __func__, UDP_BROADCAST_MAX_DATA_SIZE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -328,15 +324,14 @@ static void udp_receive_callback(void* arg,
|
|||||||
LOG_INFO(TAG, "%s: received data from %s at port: %d: %s", __func__, source_ip_str, port, data);
|
LOG_INFO(TAG, "%s: received data from %s at port: %d: %s", __func__, source_ip_str, port, data);
|
||||||
LOG_INFO(TAG, "%s: checking which function was called", __func__);
|
LOG_INFO(TAG, "%s: checking which function was called", __func__);
|
||||||
|
|
||||||
if(!udp_broadcast_check_function(data)){ // Should return 0 to reply
|
if (!udp_broadcast_check_function(data)) { // Should return 0 to reply
|
||||||
p_data->payload = udp_owner.reply;
|
p_data->payload = udp_owner.reply;
|
||||||
p_data->len = strlen(udp_owner.reply);
|
p_data->len = strlen(udp_owner.reply);
|
||||||
p_data->tot_len = strlen(udp_owner.reply);
|
p_data->tot_len = strlen(udp_owner.reply);
|
||||||
udp_sendto(connection, p_data, addr, 64000); // QT app listens on port 64000
|
udp_sendto(connection, p_data, addr, 64000); // QT app listens on port 64000
|
||||||
LOG_INFO(TAG, "%s: tried to reply to %s at port: %d: %s", __func__, source_ip_str, 64000, udp_owner.reply);
|
LOG_INFO(TAG, "%s: tried to reply to %s at port: %d: %s", __func__, source_ip_str, 64000, udp_owner.reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
defer:
|
defer:
|
||||||
pbuf_free(p);
|
pbuf_free(p);
|
||||||
pbuf_free(p_data);
|
pbuf_free(p_data);
|
||||||
@@ -375,8 +370,6 @@ err_t udp_broadcast_connection_init(void) {
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fn err_t udp_broadcast_init()
|
* @fn err_t udp_broadcast_init()
|
||||||
* @brief udp_broadcast_init() initializes the owner's variables and calls upon @see udp_broadcast_connection_init()
|
* @brief udp_broadcast_init() initializes the owner's variables and calls upon @see udp_broadcast_connection_init()
|
||||||
@@ -391,7 +384,7 @@ err_t udp_broadcast_connection_init(void) {
|
|||||||
err_t udp_broadcast_init(uint32_t x_pos, uint32_t y_pos) {
|
err_t udp_broadcast_init(uint32_t x_pos, uint32_t y_pos) {
|
||||||
owner_name_x_pos = x_pos;
|
owner_name_x_pos = x_pos;
|
||||||
owner_name_y_pos = y_pos;
|
owner_name_y_pos = y_pos;
|
||||||
if(udp_broadcast_set_owner_details("name", "default") != ERR_OK){
|
if (udp_broadcast_set_owner_details("name", "default") != ERR_OK) {
|
||||||
LOG_WARN(TAG, "%s: don't give NULL pointers as arguments for the owner's details", __func__);
|
LOG_WARN(TAG, "%s: don't give NULL pointers as arguments for the owner's details", __func__);
|
||||||
return ERR_ARG;
|
return ERR_ARG;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
#include "lcd_api.h"
|
#include "lcd_api.h"
|
||||||
|
|
||||||
|
|
||||||
static const char* TAG = "lcd_api";
|
static const char* TAG = "lcd_api";
|
||||||
|
|
||||||
static DMA2D_HandleTypeDef hDma2dHandler2;
|
static DMA2D_HandleTypeDef hDma2dHandler2;
|
||||||
@@ -85,7 +84,12 @@ void lcd_task(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void lcd_display_text(const char* text, uint32_t x_pos, uint32_t y_pos, uint32_t color, uint32_t bg_color, sFONT* font) {
|
void lcd_display_text(const char* text,
|
||||||
|
uint32_t x_pos,
|
||||||
|
uint32_t y_pos,
|
||||||
|
uint32_t color,
|
||||||
|
uint32_t bg_color,
|
||||||
|
sFONT* font) {
|
||||||
BSP_LCD_SelectLayer(1);
|
BSP_LCD_SelectLayer(1);
|
||||||
LOG_INFO(TAG, "Display text: %s @x=%d,y=%d", text, x_pos, y_pos);
|
LOG_INFO(TAG, "Display text: %s @x=%d,y=%d", text, x_pos, y_pos);
|
||||||
|
|
||||||
@@ -118,7 +122,12 @@ void lcd_display_text(const char* text, uint32_t x_pos, uint32_t y_pos, uint32_t
|
|||||||
BSP_LCD_DisplayStringAt(x_pos, y_pos, (uint8_t*)text, LEFT_MODE);
|
BSP_LCD_DisplayStringAt(x_pos, y_pos, (uint8_t*)text, LEFT_MODE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void lcd_draw_raw_img(const void* p_src, uint32_t x_pos, uint32_t y_pos, uint32_t x_size, uint32_t y_size, uint32_t color_mode) {
|
void lcd_draw_raw_img(const void* p_src,
|
||||||
|
uint32_t x_pos,
|
||||||
|
uint32_t y_pos,
|
||||||
|
uint32_t x_size,
|
||||||
|
uint32_t y_size,
|
||||||
|
uint32_t color_mode) {
|
||||||
LOG_INFO(TAG, "Displaying raw image: @x=%lu, @y=%lu, width=%lu, height=%lu", x_pos, y_pos, x_size, y_size);
|
LOG_INFO(TAG, "Displaying raw image: @x=%lu, @y=%lu, width=%lu, height=%lu", x_pos, y_pos, x_size, y_size);
|
||||||
BSP_LCD_SelectLayer(0);
|
BSP_LCD_SelectLayer(0);
|
||||||
uint32_t address = hLtdcHandler.LayerCfg[1].FBStartAdress + (((BSP_LCD_GetXSize() * y_pos) + x_pos) * (4));
|
uint32_t address = hLtdcHandler.LayerCfg[1].FBStartAdress + (((BSP_LCD_GetXSize() * y_pos) + x_pos) * (4));
|
||||||
@@ -197,7 +206,7 @@ void lcd_clear_images(void) {
|
|||||||
BSP_LCD_Clear(0);
|
BSP_LCD_Clear(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void lcd_set_bg_color_layer0(uint32_t color){
|
void lcd_set_bg_color_layer0(uint32_t color) {
|
||||||
BSP_LCD_SelectLayer(0);
|
BSP_LCD_SelectLayer(0);
|
||||||
BSP_LCD_Clear(color);
|
BSP_LCD_Clear(color);
|
||||||
}
|
}
|
||||||
@@ -316,9 +325,9 @@ static inline void free_gif_slot(lcd_gif_t* gif) {
|
|||||||
static void gif_draw_cb(GIFDRAW* pDraw) {
|
static void gif_draw_cb(GIFDRAW* pDraw) {
|
||||||
BSP_LCD_SelectLayer(0);
|
BSP_LCD_SelectLayer(0);
|
||||||
lcd_gif_t* gif = (lcd_gif_t*)pDraw->pUser;
|
lcd_gif_t* gif = (lcd_gif_t*)pDraw->pUser;
|
||||||
uint8_t* palette = pDraw->pPalette24; // The RGB888 color palette
|
uint8_t* palette = pDraw->pPalette24; // The RGB888 color palette
|
||||||
uint8_t* p_src = pDraw->pPixels; // Source pixel pointer
|
uint8_t* p_src = pDraw->pPixels; // Source pixel pointer
|
||||||
int y = pDraw->iY + pDraw->y; // Current line being drawn
|
int y = pDraw->iY + pDraw->y; // Current line being drawn
|
||||||
|
|
||||||
// Calculate the destination address of the first pixel in the line
|
// Calculate the destination address of the first pixel in the line
|
||||||
uint32_t address = hLtdcHandler.LayerCfg[0].FBStartAdress + (((BSP_LCD_GetXSize() * gif->y_pos) + gif->x_pos) * 4)
|
uint32_t address = hLtdcHandler.LayerCfg[0].FBStartAdress + (((BSP_LCD_GetXSize() * gif->y_pos) + gif->x_pos) * 4)
|
||||||
@@ -344,10 +353,10 @@ static void gif_draw_cb(GIFDRAW* pDraw) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the color from the palette and convert it to ARGB8888
|
// Get the color from the palette and convert it to ARGB8888
|
||||||
uint8_t *p = palette + (pixel * 3);
|
uint8_t* p = palette + (pixel * 3);
|
||||||
uint32_t color = (0xFF << 24) | (p[0] << 16) | (p[1] << 8) | p[2];
|
uint32_t color = (0xFF << 24) | (p[0] << 16) | (p[1] << 8) | p[2];
|
||||||
|
|
||||||
// Draw the pixel
|
// Draw the pixel
|
||||||
((uint32_t *)address)[x] = color;
|
((uint32_t*)address)[x] = color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,8 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#define LOGGER_LEVEL_WARN
|
#define LOGGER_LEVEL_WARN
|
||||||
#include "log.h"
|
|
||||||
#include "llfs.h"
|
#include "llfs.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The maximum number of files that can be opened concurrently using the POSIX API
|
* @brief The maximum number of files that can be opened concurrently using the POSIX API
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
extern struct llfs_data_file* llfs_root;
|
extern struct llfs_data_file* llfs_root;
|
||||||
static const char* TAG = "llfs";
|
static const char* TAG = "llfs";
|
||||||
static size_t file_count = 0; // Cache for the number of files in the filesystem
|
static size_t file_count = 0; // Cache for the number of files in the filesystem
|
||||||
static FILE* file_table[POSIX_MAX_FILES];
|
static FILE* file_table[POSIX_MAX_FILES];
|
||||||
|
|
||||||
#ifndef TESTING
|
#ifndef TESTING
|
||||||
@@ -331,7 +331,7 @@ off_t _lseek(int file, int ptr, int dir) {
|
|||||||
*/
|
*/
|
||||||
int _fstat(int file, struct stat* st) {
|
int _fstat(int file, struct stat* st) {
|
||||||
FILE* stream;
|
FILE* stream;
|
||||||
llfs_file_t *llfs_file;
|
llfs_file_t* llfs_file;
|
||||||
|
|
||||||
// Check if the file is stdin, stdout or stderr
|
// Check if the file is stdin, stdout or stderr
|
||||||
if (file == STDIN_FILENO || file == STDOUT_FILENO || file == STDERR_FILENO) {
|
if (file == STDIN_FILENO || file == STDOUT_FILENO || file == STDERR_FILENO) {
|
||||||
@@ -353,7 +353,7 @@ int _fstat(int file, struct stat* st) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
st->st_mode = S_IFREG; // Regular file
|
st->st_mode = S_IFREG; // Regular file
|
||||||
st->st_size = (off_t)llfs_file->len;
|
st->st_size = (off_t)llfs_file->len;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -442,4 +442,3 @@ static uint8_t file_ext_cmp(const char* const filename, const char* const ext) {
|
|||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
295717
project/Core/Src/llfs_data.c
@@ -7,8 +7,8 @@
|
|||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "stm32f7xx_hal.h"
|
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "stm32f7xx_hal.h"
|
||||||
|
|
||||||
extern UART_HandleTypeDef huart1;
|
extern UART_HandleTypeDef huart1;
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ extern UART_HandleTypeDef huart1;
|
|||||||
* @return The current timestamp in milliseconds since boot
|
* @return The current timestamp in milliseconds since boot
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int _write(int file, char *data, int len) {
|
int _write(int file, char* data, int len) {
|
||||||
HAL_StatusTypeDef status;
|
HAL_StatusTypeDef status;
|
||||||
|
|
||||||
switch (file) {
|
switch (file) {
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
/* USER CODE BEGIN Header */
|
/* USER CODE BEGIN Header */
|
||||||
/**
|
/**
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* @file : main.c
|
* @file : main.c
|
||||||
* @brief : Main program body
|
* @brief : Main program body
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* @attention
|
* @attention
|
||||||
*
|
*
|
||||||
* Copyright (c) 2023 STMicroelectronics.
|
* Copyright (c) 2023 STMicroelectronics.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This software is licensed under terms that can be found in the LICENSE file
|
* This software is licensed under terms that can be found in the LICENSE file
|
||||||
* in the root directory of this software component.
|
* in the root directory of this software component.
|
||||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||||
*
|
*
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
/* USER CODE END Header */
|
/* USER CODE END Header */
|
||||||
/* Includes ------------------------------------------------------------------*/
|
/* Includes ------------------------------------------------------------------*/
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
@@ -33,6 +33,7 @@
|
|||||||
#include "modbus_tcp.h"
|
#include "modbus_tcp.h"
|
||||||
#include "UDP_broadcast.h"
|
#include "UDP_broadcast.h"
|
||||||
#include "tcp_cmd.h"
|
#include "tcp_cmd.h"
|
||||||
|
#include "website_backend.h"
|
||||||
|
|
||||||
/* USER CODE END Includes */
|
/* USER CODE END Includes */
|
||||||
|
|
||||||
@@ -43,7 +44,7 @@
|
|||||||
|
|
||||||
/* Private define ------------------------------------------------------------*/
|
/* Private define ------------------------------------------------------------*/
|
||||||
/* USER CODE BEGIN PD */
|
/* USER CODE BEGIN PD */
|
||||||
static const char *TAG = "main";
|
static const char* TAG = "main";
|
||||||
/* USER CODE END PD */
|
/* USER CODE END PD */
|
||||||
|
|
||||||
/* Private macro -------------------------------------------------------------*/
|
/* Private macro -------------------------------------------------------------*/
|
||||||
@@ -85,453 +86,434 @@ static void MX_QUADSPI_Init(void);
|
|||||||
/* USER CODE END 0 */
|
/* USER CODE END 0 */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The application entry point.
|
* @brief The application entry point.
|
||||||
* @retval int
|
* @retval int
|
||||||
*/
|
*/
|
||||||
int main(void)
|
int main(void) {
|
||||||
{
|
/* USER CODE BEGIN 1 */
|
||||||
/* USER CODE BEGIN 1 */
|
|
||||||
|
|
||||||
/* USER CODE END 1 */
|
/* USER CODE END 1 */
|
||||||
|
|
||||||
/* MCU Configuration--------------------------------------------------------*/
|
/* MCU Configuration--------------------------------------------------------*/
|
||||||
|
|
||||||
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
|
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
|
||||||
HAL_Init();
|
HAL_Init();
|
||||||
|
|
||||||
/* USER CODE BEGIN Init */
|
/* USER CODE BEGIN Init */
|
||||||
|
|
||||||
/* USER CODE END Init */
|
/* USER CODE END Init */
|
||||||
|
|
||||||
/* Configure the system clock */
|
/* Configure the system clock */
|
||||||
SystemClock_Config();
|
SystemClock_Config();
|
||||||
|
|
||||||
/* USER CODE BEGIN SysInit */
|
/* USER CODE BEGIN SysInit */
|
||||||
|
|
||||||
/* USER CODE END SysInit */
|
/* USER CODE END SysInit */
|
||||||
|
|
||||||
/* Initialize all configured peripherals */
|
/* Initialize all configured peripherals */
|
||||||
MX_GPIO_Init();
|
MX_GPIO_Init();
|
||||||
MX_LTDC_Init();
|
MX_LTDC_Init();
|
||||||
MX_USART1_UART_Init();
|
MX_USART1_UART_Init();
|
||||||
MX_DMA2D_Init();
|
MX_DMA2D_Init();
|
||||||
MX_FMC_Init();
|
MX_FMC_Init();
|
||||||
MX_LWIP_Init();
|
MX_LWIP_Init();
|
||||||
MX_QUADSPI_Init();
|
MX_QUADSPI_Init();
|
||||||
/* USER CODE BEGIN 2 */
|
/* USER CODE BEGIN 2 */
|
||||||
|
|
||||||
/* Initialize QSPI */
|
/* Initialize QSPI */
|
||||||
BSP_QSPI_Init();
|
BSP_QSPI_Init();
|
||||||
BSP_QSPI_MemoryMappedMode();
|
BSP_QSPI_MemoryMappedMode();
|
||||||
WRITE_REG(QUADSPI->LPTR, 0xFFF);
|
WRITE_REG(QUADSPI->LPTR, 0xFFF);
|
||||||
|
|
||||||
/* Clear terminal */
|
/* Clear terminal */
|
||||||
printf(CLEAR_SCREEN);
|
printf(CLEAR_SCREEN);
|
||||||
|
|
||||||
/* Initialize the LCD */
|
/* Initialize the LCD */
|
||||||
lcd_init(true);
|
lcd_init(true);
|
||||||
|
|
||||||
/* Initialize the filesystem */
|
/* Initialize the filesystem */
|
||||||
llfs_init();
|
llfs_init();
|
||||||
|
|
||||||
/* Initialize the tftp server */
|
/* Initialize the tftp server */
|
||||||
tftp_server_init();
|
tftp_server_init();
|
||||||
|
|
||||||
/* Initialize tcp command interface*/
|
|
||||||
tcp_cmd_init();
|
|
||||||
|
|
||||||
/* Initialize Modbus*/
|
/* Initialize tcp command interface*/
|
||||||
modbus_init();
|
tcp_cmd_init();
|
||||||
|
|
||||||
/* Initialize the MQTT application */
|
|
||||||
mqtt_application_init();
|
|
||||||
|
|
||||||
// Initialize the UDP broadcast service
|
/* Initialize Modbus*/
|
||||||
|
modbus_init();
|
||||||
|
|
||||||
if (udp_broadcast_init(10,255) != ERR_OK){
|
/* Initialize the MQTT application */
|
||||||
LOG_WARN(TAG,"error initializing udp connection, check warnings from udp_broadcast_init() or udp_broadcast_connection_init()");
|
mqtt_application_init();
|
||||||
}
|
|
||||||
if (udp_broadcast_set_owner_details("Joran", "Van Nieuwenhoven") != ERR_OK){
|
|
||||||
LOG_WARN(TAG,"error setting owner's details");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* USER CODE END 2 */
|
// Initialize the UDP broadcast service
|
||||||
|
|
||||||
/* Infinite loop */
|
if (udp_broadcast_init(10, 255) != ERR_OK) {
|
||||||
/* USER CODE BEGIN WHILE */
|
LOG_WARN(TAG, "error initializing udp connection, check warnings from udp_broadcast_init() or "
|
||||||
while (1)
|
"udp_broadcast_connection_init()");
|
||||||
{
|
}
|
||||||
/* USER CODE END WHILE */
|
if (udp_broadcast_set_owner_details("Joran", "Van Nieuwenhoven") != ERR_OK) {
|
||||||
|
LOG_WARN(TAG, "error setting owner's details");
|
||||||
|
}
|
||||||
|
|
||||||
/* USER CODE BEGIN 3 */
|
/* Initialize website backend */
|
||||||
MX_LWIP_Process();
|
wbe_init();
|
||||||
lcd_task();
|
|
||||||
}
|
/* USER CODE END 2 */
|
||||||
/* USER CODE END 3 */
|
|
||||||
|
/* Infinite loop */
|
||||||
|
/* USER CODE BEGIN WHILE */
|
||||||
|
while (1) {
|
||||||
|
/* USER CODE END WHILE */
|
||||||
|
|
||||||
|
/* USER CODE BEGIN 3 */
|
||||||
|
MX_LWIP_Process();
|
||||||
|
lcd_task();
|
||||||
|
}
|
||||||
|
/* USER CODE END 3 */
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief System Clock Configuration
|
* @brief System Clock Configuration
|
||||||
* @retval None
|
* @retval None
|
||||||
*/
|
*/
|
||||||
void SystemClock_Config(void)
|
void SystemClock_Config(void) {
|
||||||
{
|
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
|
||||||
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
|
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
|
||||||
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
|
|
||||||
|
|
||||||
/** Configure LSE Drive Capability
|
/** Configure LSE Drive Capability
|
||||||
*/
|
*/
|
||||||
HAL_PWR_EnableBkUpAccess();
|
HAL_PWR_EnableBkUpAccess();
|
||||||
|
|
||||||
/** Configure the main internal regulator output voltage
|
/** Configure the main internal regulator output voltage
|
||||||
*/
|
*/
|
||||||
__HAL_RCC_PWR_CLK_ENABLE();
|
__HAL_RCC_PWR_CLK_ENABLE();
|
||||||
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
|
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
|
||||||
|
|
||||||
/** Initializes the RCC Oscillators according to the specified parameters
|
/** Initializes the RCC Oscillators according to the specified parameters
|
||||||
* in the RCC_OscInitTypeDef structure.
|
* in the RCC_OscInitTypeDef structure.
|
||||||
*/
|
*/
|
||||||
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
|
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
|
||||||
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
|
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
|
||||||
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
|
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
|
||||||
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
|
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
|
||||||
RCC_OscInitStruct.PLL.PLLM = 25;
|
RCC_OscInitStruct.PLL.PLLM = 25;
|
||||||
RCC_OscInitStruct.PLL.PLLN = 400;
|
RCC_OscInitStruct.PLL.PLLN = 400;
|
||||||
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
|
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
|
||||||
RCC_OscInitStruct.PLL.PLLQ = 2;
|
RCC_OscInitStruct.PLL.PLLQ = 2;
|
||||||
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
|
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
|
||||||
{
|
Error_Handler();
|
||||||
Error_Handler();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/** Activate the Over-Drive mode
|
/** Activate the Over-Drive mode
|
||||||
*/
|
*/
|
||||||
if (HAL_PWREx_EnableOverDrive() != HAL_OK)
|
if (HAL_PWREx_EnableOverDrive() != HAL_OK) {
|
||||||
{
|
Error_Handler();
|
||||||
Error_Handler();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/** Initializes the CPU, AHB and APB buses clocks
|
/** Initializes the CPU, AHB and APB buses clocks
|
||||||
*/
|
*/
|
||||||
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
|
||||||
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
|
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
|
||||||
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
|
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
|
||||||
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
|
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
|
||||||
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
|
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
|
||||||
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
|
|
||||||
|
|
||||||
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_6) != HAL_OK)
|
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_6) != HAL_OK) {
|
||||||
{
|
Error_Handler();
|
||||||
Error_Handler();
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief DMA2D Initialization Function
|
* @brief DMA2D Initialization Function
|
||||||
* @param None
|
* @param None
|
||||||
* @retval None
|
* @retval None
|
||||||
*/
|
*/
|
||||||
static void MX_DMA2D_Init(void)
|
static void MX_DMA2D_Init(void) {
|
||||||
{
|
|
||||||
|
|
||||||
/* USER CODE BEGIN DMA2D_Init 0 */
|
/* USER CODE BEGIN DMA2D_Init 0 */
|
||||||
|
|
||||||
/* USER CODE END DMA2D_Init 0 */
|
/* USER CODE END DMA2D_Init 0 */
|
||||||
|
|
||||||
/* USER CODE BEGIN DMA2D_Init 1 */
|
/* USER CODE BEGIN DMA2D_Init 1 */
|
||||||
|
|
||||||
/* USER CODE END DMA2D_Init 1 */
|
/* USER CODE END DMA2D_Init 1 */
|
||||||
hdma2d.Instance = DMA2D;
|
hdma2d.Instance = DMA2D;
|
||||||
hdma2d.Init.Mode = DMA2D_M2M;
|
hdma2d.Init.Mode = DMA2D_M2M;
|
||||||
hdma2d.Init.ColorMode = DMA2D_OUTPUT_ARGB8888;
|
hdma2d.Init.ColorMode = DMA2D_OUTPUT_ARGB8888;
|
||||||
hdma2d.Init.OutputOffset = 0;
|
hdma2d.Init.OutputOffset = 0;
|
||||||
hdma2d.LayerCfg[1].InputOffset = 0;
|
hdma2d.LayerCfg[1].InputOffset = 0;
|
||||||
hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB8888;
|
hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB8888;
|
||||||
hdma2d.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA;
|
hdma2d.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA;
|
||||||
hdma2d.LayerCfg[1].InputAlpha = 0;
|
hdma2d.LayerCfg[1].InputAlpha = 0;
|
||||||
if (HAL_DMA2D_Init(&hdma2d) != HAL_OK)
|
if (HAL_DMA2D_Init(&hdma2d) != HAL_OK) {
|
||||||
{
|
Error_Handler();
|
||||||
Error_Handler();
|
}
|
||||||
}
|
if (HAL_DMA2D_ConfigLayer(&hdma2d, 1) != HAL_OK) {
|
||||||
if (HAL_DMA2D_ConfigLayer(&hdma2d, 1) != HAL_OK)
|
Error_Handler();
|
||||||
{
|
}
|
||||||
Error_Handler();
|
/* USER CODE BEGIN DMA2D_Init 2 */
|
||||||
}
|
|
||||||
/* USER CODE BEGIN DMA2D_Init 2 */
|
|
||||||
|
|
||||||
/* USER CODE END DMA2D_Init 2 */
|
/* USER CODE END DMA2D_Init 2 */
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief LTDC Initialization Function
|
* @brief LTDC Initialization Function
|
||||||
* @param None
|
* @param None
|
||||||
* @retval None
|
* @retval None
|
||||||
*/
|
*/
|
||||||
static void MX_LTDC_Init(void)
|
static void MX_LTDC_Init(void) {
|
||||||
{
|
|
||||||
|
|
||||||
/* USER CODE BEGIN LTDC_Init 0 */
|
/* USER CODE BEGIN LTDC_Init 0 */
|
||||||
|
|
||||||
/* USER CODE END LTDC_Init 0 */
|
/* USER CODE END LTDC_Init 0 */
|
||||||
|
|
||||||
LTDC_LayerCfgTypeDef pLayerCfg = {0};
|
LTDC_LayerCfgTypeDef pLayerCfg = {0};
|
||||||
LTDC_LayerCfgTypeDef pLayerCfg1 = {0};
|
LTDC_LayerCfgTypeDef pLayerCfg1 = {0};
|
||||||
|
|
||||||
/* USER CODE BEGIN LTDC_Init 1 */
|
/* USER CODE BEGIN LTDC_Init 1 */
|
||||||
|
|
||||||
/* USER CODE END LTDC_Init 1 */
|
/* USER CODE END LTDC_Init 1 */
|
||||||
hltdc.Instance = LTDC;
|
hltdc.Instance = LTDC;
|
||||||
hltdc.Init.HSPolarity = LTDC_HSPOLARITY_AL;
|
hltdc.Init.HSPolarity = LTDC_HSPOLARITY_AL;
|
||||||
hltdc.Init.VSPolarity = LTDC_VSPOLARITY_AL;
|
hltdc.Init.VSPolarity = LTDC_VSPOLARITY_AL;
|
||||||
hltdc.Init.DEPolarity = LTDC_DEPOLARITY_AL;
|
hltdc.Init.DEPolarity = LTDC_DEPOLARITY_AL;
|
||||||
hltdc.Init.PCPolarity = LTDC_PCPOLARITY_IPC;
|
hltdc.Init.PCPolarity = LTDC_PCPOLARITY_IPC;
|
||||||
hltdc.Init.HorizontalSync = 40;
|
hltdc.Init.HorizontalSync = 40;
|
||||||
hltdc.Init.VerticalSync = 9;
|
hltdc.Init.VerticalSync = 9;
|
||||||
hltdc.Init.AccumulatedHBP = 53;
|
hltdc.Init.AccumulatedHBP = 53;
|
||||||
hltdc.Init.AccumulatedVBP = 11;
|
hltdc.Init.AccumulatedVBP = 11;
|
||||||
hltdc.Init.AccumulatedActiveW = 533;
|
hltdc.Init.AccumulatedActiveW = 533;
|
||||||
hltdc.Init.AccumulatedActiveH = 283;
|
hltdc.Init.AccumulatedActiveH = 283;
|
||||||
hltdc.Init.TotalWidth = 565;
|
hltdc.Init.TotalWidth = 565;
|
||||||
hltdc.Init.TotalHeigh = 285;
|
hltdc.Init.TotalHeigh = 285;
|
||||||
hltdc.Init.Backcolor.Blue = 0;
|
hltdc.Init.Backcolor.Blue = 0;
|
||||||
hltdc.Init.Backcolor.Green = 255;
|
hltdc.Init.Backcolor.Green = 255;
|
||||||
hltdc.Init.Backcolor.Red = 0;
|
hltdc.Init.Backcolor.Red = 0;
|
||||||
if (HAL_LTDC_Init(&hltdc) != HAL_OK)
|
if (HAL_LTDC_Init(&hltdc) != HAL_OK) {
|
||||||
{
|
Error_Handler();
|
||||||
Error_Handler();
|
}
|
||||||
}
|
pLayerCfg.WindowX0 = 0;
|
||||||
pLayerCfg.WindowX0 = 0;
|
pLayerCfg.WindowX1 = 480;
|
||||||
pLayerCfg.WindowX1 = 480;
|
pLayerCfg.WindowY0 = 0;
|
||||||
pLayerCfg.WindowY0 = 0;
|
pLayerCfg.WindowY1 = 272;
|
||||||
pLayerCfg.WindowY1 = 272;
|
pLayerCfg.PixelFormat = LTDC_PIXEL_FORMAT_ARGB1555;
|
||||||
pLayerCfg.PixelFormat = LTDC_PIXEL_FORMAT_ARGB1555;
|
pLayerCfg.Alpha = 255;
|
||||||
pLayerCfg.Alpha = 255;
|
pLayerCfg.Alpha0 = 0;
|
||||||
pLayerCfg.Alpha0 = 0;
|
pLayerCfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA;
|
||||||
pLayerCfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA;
|
pLayerCfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA;
|
||||||
pLayerCfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA;
|
pLayerCfg.FBStartAdress = 0;
|
||||||
pLayerCfg.FBStartAdress = 0;
|
pLayerCfg.ImageWidth = 480;
|
||||||
pLayerCfg.ImageWidth = 480;
|
pLayerCfg.ImageHeight = 272;
|
||||||
pLayerCfg.ImageHeight = 272;
|
pLayerCfg.Backcolor.Blue = 0;
|
||||||
pLayerCfg.Backcolor.Blue = 0;
|
pLayerCfg.Backcolor.Green = 0;
|
||||||
pLayerCfg.Backcolor.Green = 0;
|
pLayerCfg.Backcolor.Red = 0;
|
||||||
pLayerCfg.Backcolor.Red = 0;
|
if (HAL_LTDC_ConfigLayer(&hltdc, &pLayerCfg, 0) != HAL_OK) {
|
||||||
if (HAL_LTDC_ConfigLayer(&hltdc, &pLayerCfg, 0) != HAL_OK)
|
Error_Handler();
|
||||||
{
|
}
|
||||||
Error_Handler();
|
pLayerCfg1.WindowX0 = 0;
|
||||||
}
|
pLayerCfg1.WindowX1 = 480;
|
||||||
pLayerCfg1.WindowX0 = 0;
|
pLayerCfg1.WindowY0 = 0;
|
||||||
pLayerCfg1.WindowX1 = 480;
|
pLayerCfg1.WindowY1 = 272;
|
||||||
pLayerCfg1.WindowY0 = 0;
|
pLayerCfg1.PixelFormat = LTDC_PIXEL_FORMAT_ARGB1555;
|
||||||
pLayerCfg1.WindowY1 = 272;
|
pLayerCfg1.Alpha = 255;
|
||||||
pLayerCfg1.PixelFormat = LTDC_PIXEL_FORMAT_ARGB1555;
|
pLayerCfg1.Alpha0 = 0;
|
||||||
pLayerCfg1.Alpha = 255;
|
pLayerCfg1.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA;
|
||||||
pLayerCfg1.Alpha0 = 0;
|
pLayerCfg1.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA;
|
||||||
pLayerCfg1.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA;
|
pLayerCfg1.FBStartAdress = 0;
|
||||||
pLayerCfg1.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA;
|
pLayerCfg1.ImageWidth = 480;
|
||||||
pLayerCfg1.FBStartAdress = 0;
|
pLayerCfg1.ImageHeight = 272;
|
||||||
pLayerCfg1.ImageWidth = 480;
|
pLayerCfg1.Backcolor.Blue = 0;
|
||||||
pLayerCfg1.ImageHeight = 272;
|
pLayerCfg1.Backcolor.Green = 0;
|
||||||
pLayerCfg1.Backcolor.Blue = 0;
|
pLayerCfg1.Backcolor.Red = 0;
|
||||||
pLayerCfg1.Backcolor.Green = 0;
|
if (HAL_LTDC_ConfigLayer(&hltdc, &pLayerCfg1, 1) != HAL_OK) {
|
||||||
pLayerCfg1.Backcolor.Red = 0;
|
Error_Handler();
|
||||||
if (HAL_LTDC_ConfigLayer(&hltdc, &pLayerCfg1, 1) != HAL_OK)
|
}
|
||||||
{
|
/* USER CODE BEGIN LTDC_Init 2 */
|
||||||
Error_Handler();
|
|
||||||
}
|
|
||||||
/* USER CODE BEGIN LTDC_Init 2 */
|
|
||||||
|
|
||||||
/* USER CODE END LTDC_Init 2 */
|
/* USER CODE END LTDC_Init 2 */
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief QUADSPI Initialization Function
|
* @brief QUADSPI Initialization Function
|
||||||
* @param None
|
* @param None
|
||||||
* @retval None
|
* @retval None
|
||||||
*/
|
*/
|
||||||
static void MX_QUADSPI_Init(void)
|
static void MX_QUADSPI_Init(void) {
|
||||||
{
|
|
||||||
|
|
||||||
/* USER CODE BEGIN QUADSPI_Init 0 */
|
/* USER CODE BEGIN QUADSPI_Init 0 */
|
||||||
|
|
||||||
/* USER CODE END QUADSPI_Init 0 */
|
/* USER CODE END QUADSPI_Init 0 */
|
||||||
|
|
||||||
/* USER CODE BEGIN QUADSPI_Init 1 */
|
/* USER CODE BEGIN QUADSPI_Init 1 */
|
||||||
|
|
||||||
/* USER CODE END QUADSPI_Init 1 */
|
/* USER CODE END QUADSPI_Init 1 */
|
||||||
/* QUADSPI parameter configuration*/
|
/* QUADSPI parameter configuration*/
|
||||||
hqspi.Instance = QUADSPI;
|
hqspi.Instance = QUADSPI;
|
||||||
hqspi.Init.ClockPrescaler = 1;
|
hqspi.Init.ClockPrescaler = 1;
|
||||||
hqspi.Init.FifoThreshold = 4;
|
hqspi.Init.FifoThreshold = 4;
|
||||||
hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
|
hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
|
||||||
hqspi.Init.FlashSize = 16;
|
hqspi.Init.FlashSize = 16;
|
||||||
hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_6_CYCLE;
|
hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_6_CYCLE;
|
||||||
hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0;
|
hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0;
|
||||||
hqspi.Init.FlashID = QSPI_FLASH_ID_1;
|
hqspi.Init.FlashID = QSPI_FLASH_ID_1;
|
||||||
hqspi.Init.DualFlash = QSPI_DUALFLASH_DISABLE;
|
hqspi.Init.DualFlash = QSPI_DUALFLASH_DISABLE;
|
||||||
if (HAL_QSPI_Init(&hqspi) != HAL_OK)
|
if (HAL_QSPI_Init(&hqspi) != HAL_OK) {
|
||||||
{
|
Error_Handler();
|
||||||
Error_Handler();
|
}
|
||||||
}
|
/* USER CODE BEGIN QUADSPI_Init 2 */
|
||||||
/* USER CODE BEGIN QUADSPI_Init 2 */
|
|
||||||
|
|
||||||
/* USER CODE END QUADSPI_Init 2 */
|
/* USER CODE END QUADSPI_Init 2 */
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief USART1 Initialization Function
|
* @brief USART1 Initialization Function
|
||||||
* @param None
|
* @param None
|
||||||
* @retval None
|
* @retval None
|
||||||
*/
|
*/
|
||||||
static void MX_USART1_UART_Init(void)
|
static void MX_USART1_UART_Init(void) {
|
||||||
{
|
|
||||||
|
|
||||||
/* USER CODE BEGIN USART1_Init 0 */
|
/* USER CODE BEGIN USART1_Init 0 */
|
||||||
|
|
||||||
/* USER CODE END USART1_Init 0 */
|
/* USER CODE END USART1_Init 0 */
|
||||||
|
|
||||||
/* USER CODE BEGIN USART1_Init 1 */
|
/* USER CODE BEGIN USART1_Init 1 */
|
||||||
|
|
||||||
/* USER CODE END USART1_Init 1 */
|
/* USER CODE END USART1_Init 1 */
|
||||||
huart1.Instance = USART1;
|
huart1.Instance = USART1;
|
||||||
huart1.Init.BaudRate = 115200;
|
huart1.Init.BaudRate = 115200;
|
||||||
huart1.Init.WordLength = UART_WORDLENGTH_8B;
|
huart1.Init.WordLength = UART_WORDLENGTH_8B;
|
||||||
huart1.Init.StopBits = UART_STOPBITS_1;
|
huart1.Init.StopBits = UART_STOPBITS_1;
|
||||||
huart1.Init.Parity = UART_PARITY_NONE;
|
huart1.Init.Parity = UART_PARITY_NONE;
|
||||||
huart1.Init.Mode = UART_MODE_TX_RX;
|
huart1.Init.Mode = UART_MODE_TX_RX;
|
||||||
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
|
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
|
||||||
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
|
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
|
||||||
huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
|
huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
|
||||||
huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
|
huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
|
||||||
if (HAL_UART_Init(&huart1) != HAL_OK)
|
if (HAL_UART_Init(&huart1) != HAL_OK) {
|
||||||
{
|
Error_Handler();
|
||||||
Error_Handler();
|
}
|
||||||
}
|
/* USER CODE BEGIN USART1_Init 2 */
|
||||||
/* USER CODE BEGIN USART1_Init 2 */
|
|
||||||
|
|
||||||
/* USER CODE END USART1_Init 2 */
|
/* USER CODE END USART1_Init 2 */
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FMC initialization function */
|
/* FMC initialization function */
|
||||||
static void MX_FMC_Init(void)
|
static void MX_FMC_Init(void) {
|
||||||
{
|
|
||||||
|
|
||||||
/* USER CODE BEGIN FMC_Init 0 */
|
/* USER CODE BEGIN FMC_Init 0 */
|
||||||
|
|
||||||
/* USER CODE END FMC_Init 0 */
|
/* USER CODE END FMC_Init 0 */
|
||||||
|
|
||||||
FMC_SDRAM_TimingTypeDef SdramTiming = {0};
|
FMC_SDRAM_TimingTypeDef SdramTiming = {0};
|
||||||
|
|
||||||
/* USER CODE BEGIN FMC_Init 1 */
|
/* USER CODE BEGIN FMC_Init 1 */
|
||||||
|
|
||||||
/* USER CODE END FMC_Init 1 */
|
/* USER CODE END FMC_Init 1 */
|
||||||
|
|
||||||
/** Perform the SDRAM1 memory initialization sequence
|
/** Perform the SDRAM1 memory initialization sequence
|
||||||
*/
|
*/
|
||||||
hsdram1.Instance = FMC_SDRAM_DEVICE;
|
hsdram1.Instance = FMC_SDRAM_DEVICE;
|
||||||
/* hsdram1.Init */
|
/* hsdram1.Init */
|
||||||
hsdram1.Init.SDBank = FMC_SDRAM_BANK1;
|
hsdram1.Init.SDBank = FMC_SDRAM_BANK1;
|
||||||
hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_8;
|
hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_8;
|
||||||
hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12;
|
hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12;
|
||||||
hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16;
|
hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16;
|
||||||
hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
|
hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
|
||||||
hsdram1.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_1;
|
hsdram1.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_1;
|
||||||
hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
|
hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
|
||||||
hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_DISABLE;
|
hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_DISABLE;
|
||||||
hsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_DISABLE;
|
hsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_DISABLE;
|
||||||
hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0;
|
hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0;
|
||||||
/* SdramTiming */
|
/* SdramTiming */
|
||||||
SdramTiming.LoadToActiveDelay = 16;
|
SdramTiming.LoadToActiveDelay = 16;
|
||||||
SdramTiming.ExitSelfRefreshDelay = 16;
|
SdramTiming.ExitSelfRefreshDelay = 16;
|
||||||
SdramTiming.SelfRefreshTime = 16;
|
SdramTiming.SelfRefreshTime = 16;
|
||||||
SdramTiming.RowCycleDelay = 16;
|
SdramTiming.RowCycleDelay = 16;
|
||||||
SdramTiming.WriteRecoveryTime = 16;
|
SdramTiming.WriteRecoveryTime = 16;
|
||||||
SdramTiming.RPDelay = 16;
|
SdramTiming.RPDelay = 16;
|
||||||
SdramTiming.RCDDelay = 16;
|
SdramTiming.RCDDelay = 16;
|
||||||
|
|
||||||
if (HAL_SDRAM_Init(&hsdram1, &SdramTiming) != HAL_OK)
|
if (HAL_SDRAM_Init(&hsdram1, &SdramTiming) != HAL_OK) {
|
||||||
{
|
Error_Handler();
|
||||||
Error_Handler( );
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* USER CODE BEGIN FMC_Init 2 */
|
/* USER CODE BEGIN FMC_Init 2 */
|
||||||
|
|
||||||
/* USER CODE END FMC_Init 2 */
|
/* USER CODE END FMC_Init 2 */
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief GPIO Initialization Function
|
* @brief GPIO Initialization Function
|
||||||
* @param None
|
* @param None
|
||||||
* @retval None
|
* @retval None
|
||||||
*/
|
*/
|
||||||
static void MX_GPIO_Init(void)
|
static void MX_GPIO_Init(void) {
|
||||||
{
|
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||||||
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
/* USER CODE BEGIN MX_GPIO_Init_1 */
|
||||||
/* USER CODE BEGIN MX_GPIO_Init_1 */
|
/* USER CODE END MX_GPIO_Init_1 */
|
||||||
/* USER CODE END MX_GPIO_Init_1 */
|
|
||||||
|
|
||||||
/* GPIO Ports Clock Enable */
|
/* GPIO Ports Clock Enable */
|
||||||
__HAL_RCC_GPIOE_CLK_ENABLE();
|
__HAL_RCC_GPIOE_CLK_ENABLE();
|
||||||
__HAL_RCC_GPIOG_CLK_ENABLE();
|
__HAL_RCC_GPIOG_CLK_ENABLE();
|
||||||
__HAL_RCC_GPIOB_CLK_ENABLE();
|
__HAL_RCC_GPIOB_CLK_ENABLE();
|
||||||
__HAL_RCC_GPIOJ_CLK_ENABLE();
|
__HAL_RCC_GPIOJ_CLK_ENABLE();
|
||||||
__HAL_RCC_GPIOD_CLK_ENABLE();
|
__HAL_RCC_GPIOD_CLK_ENABLE();
|
||||||
__HAL_RCC_GPIOK_CLK_ENABLE();
|
__HAL_RCC_GPIOK_CLK_ENABLE();
|
||||||
__HAL_RCC_GPIOF_CLK_ENABLE();
|
__HAL_RCC_GPIOF_CLK_ENABLE();
|
||||||
__HAL_RCC_GPIOI_CLK_ENABLE();
|
__HAL_RCC_GPIOI_CLK_ENABLE();
|
||||||
__HAL_RCC_GPIOC_CLK_ENABLE();
|
__HAL_RCC_GPIOC_CLK_ENABLE();
|
||||||
__HAL_RCC_GPIOA_CLK_ENABLE();
|
__HAL_RCC_GPIOA_CLK_ENABLE();
|
||||||
__HAL_RCC_GPIOH_CLK_ENABLE();
|
__HAL_RCC_GPIOH_CLK_ENABLE();
|
||||||
|
|
||||||
/*Configure GPIO pin Output Level */
|
/*Configure GPIO pin Output Level */
|
||||||
HAL_GPIO_WritePin(LCD_BL_CTRL_GPIO_Port, LCD_BL_CTRL_Pin, GPIO_PIN_RESET);
|
HAL_GPIO_WritePin(LCD_BL_CTRL_GPIO_Port, LCD_BL_CTRL_Pin, GPIO_PIN_RESET);
|
||||||
|
|
||||||
/*Configure GPIO pin Output Level */
|
/*Configure GPIO pin Output Level */
|
||||||
HAL_GPIO_WritePin(GPIOI, LED_Pin|LCD_DISP_Pin, GPIO_PIN_RESET);
|
HAL_GPIO_WritePin(GPIOI, LED_Pin | LCD_DISP_Pin, GPIO_PIN_RESET);
|
||||||
|
|
||||||
/*Configure GPIO pin : LCD_BL_CTRL_Pin */
|
/*Configure GPIO pin : LCD_BL_CTRL_Pin */
|
||||||
GPIO_InitStruct.Pin = LCD_BL_CTRL_Pin;
|
GPIO_InitStruct.Pin = LCD_BL_CTRL_Pin;
|
||||||
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
|
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
|
||||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||||||
HAL_GPIO_Init(LCD_BL_CTRL_GPIO_Port, &GPIO_InitStruct);
|
HAL_GPIO_Init(LCD_BL_CTRL_GPIO_Port, &GPIO_InitStruct);
|
||||||
|
|
||||||
/*Configure GPIO pins : LED_Pin LCD_DISP_Pin */
|
/*Configure GPIO pins : LED_Pin LCD_DISP_Pin */
|
||||||
GPIO_InitStruct.Pin = LED_Pin|LCD_DISP_Pin;
|
GPIO_InitStruct.Pin = LED_Pin | LCD_DISP_Pin;
|
||||||
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
|
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
|
||||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||||||
HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);
|
HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);
|
||||||
|
|
||||||
/*Configure GPIO pin : BUTTON_Pin */
|
/*Configure GPIO pin : BUTTON_Pin */
|
||||||
GPIO_InitStruct.Pin = BUTTON_Pin;
|
GPIO_InitStruct.Pin = BUTTON_Pin;
|
||||||
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
|
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
|
||||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||||
HAL_GPIO_Init(BUTTON_GPIO_Port, &GPIO_InitStruct);
|
HAL_GPIO_Init(BUTTON_GPIO_Port, &GPIO_InitStruct);
|
||||||
|
|
||||||
/* USER CODE BEGIN MX_GPIO_Init_2 */
|
/* USER CODE BEGIN MX_GPIO_Init_2 */
|
||||||
/* USER CODE END MX_GPIO_Init_2 */
|
/* USER CODE END MX_GPIO_Init_2 */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* USER CODE BEGIN 4 */
|
/* USER CODE BEGIN 4 */
|
||||||
/* USER CODE END 4 */
|
/* USER CODE END 4 */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This function is executed in case of error occurrence.
|
* @brief This function is executed in case of error occurrence.
|
||||||
* @retval None
|
* @retval None
|
||||||
*/
|
*/
|
||||||
void Error_Handler(void)
|
void Error_Handler(void) {
|
||||||
{
|
/* USER CODE BEGIN Error_Handler_Debug */
|
||||||
/* USER CODE BEGIN Error_Handler_Debug */
|
/* User can add his own implementation to report the HAL error return state */
|
||||||
/* User can add his own implementation to report the HAL error return state */
|
__disable_irq();
|
||||||
__disable_irq();
|
while (1) {
|
||||||
while (1)
|
}
|
||||||
{
|
/* USER CODE END Error_Handler_Debug */
|
||||||
}
|
|
||||||
/* USER CODE END Error_Handler_Debug */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_FULL_ASSERT
|
#ifdef USE_FULL_ASSERT
|
||||||
|
|||||||
@@ -1,163 +1,594 @@
|
|||||||
/**
|
/**
|
||||||
* @file modbus_tcp.c
|
* @file modbus_tcp.c
|
||||||
*
|
* @brief TCP Modbus server
|
||||||
* @brief TCP Modbus handler
|
* @date Nov 29, 2023
|
||||||
* @date Nov 6, 2023
|
|
||||||
* @author Obe
|
* @author Obe
|
||||||
|
* @author Lorenz C.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Includes
|
#include <stdint.h>
|
||||||
#include "modbus_tcp.h"
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <tcp.h>
|
||||||
|
#include "lcd_api.h"
|
||||||
|
#include "llfs.h"
|
||||||
|
#define LOGGER_LEVEL_ALL
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "modbus_tcp.h"
|
||||||
|
|
||||||
// Defines
|
// TCP server constants
|
||||||
#define MAX_REG REG_LENGTH
|
#define TCP_POLL_INTERVAL 10 // About 5 seconds
|
||||||
#define EXTENSION_LENGTH 4
|
|
||||||
#define TEXT_LENGTH 200
|
|
||||||
#define MULTIPLE_REG 0x10
|
|
||||||
#define REG_LENGTH 428
|
|
||||||
#define START_DATA 28
|
|
||||||
#define MODBUS_MODE 7
|
|
||||||
|
|
||||||
#define REG_COLOR_B_RED 14
|
// Modbus constants (See Modbus_Application_Protocol_V1_1b3 and Modbus_Messaging_Implementation_Guide_V1_0b)
|
||||||
#define REG_COLOR_B_GREEN 16
|
#define PDU_MAX_LENGTH 253
|
||||||
#define REG_COLOR_B_BLUE 18
|
#define ADU_MAX_LENGTH 260
|
||||||
|
|
||||||
#define REG_COLOR_F_RED 20
|
#define MBAP_HEADER_LENGTH 7
|
||||||
#define REG_COLOR_F_GREEN 22
|
#define PROTOCOL_ID_MODBUS 0x0000
|
||||||
#define REG_COLOR_F_BLUE 24
|
|
||||||
|
|
||||||
#define REG_IMAGE_NR 26
|
#define WRITE_MULTIPLE_REG_REQ_MIN_LENGTH 5
|
||||||
|
#define WRITE_MULTIPLE_REG_RSP_LENGTH 4
|
||||||
|
#define WRITE_MULTIPLE_REG_QUANTITY_MIN 0x0001
|
||||||
|
#define WRITE_MULTIPLE_REG_QUANTITY_MAX 0x007B // See m
|
||||||
|
|
||||||
// Global variables
|
#define EXCEPTION_OFFSET 0x80
|
||||||
static char* TAG = "Modbus_TCP"; // Tag used in logs
|
|
||||||
|
|
||||||
static struct tcp_pcb* modbus_pcb;
|
// Application specific constants
|
||||||
uint8_t registers[MAX_REG];
|
#define REGISTER_COUNT 208
|
||||||
|
#define REG_ADDR_BG_COLOR_RED 0x0000 // 8-bit red background color
|
||||||
// Functions
|
#define REG_ADDR_BG_COLOR_GREEN 0x0001 // 8-bit green background color
|
||||||
static err_t modbus_incoming_data(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t err);
|
#define REG_ADDR_BG_COLOR_BLUE 0x0002 // 8-bit blue background colo
|
||||||
static err_t modbus_accept(void* arg, struct tcp_pcb* pcb, err_t err);
|
#define REG_ADDR_FG_COLOR_RED 0x0003 // 8-bit red text color
|
||||||
|
#define REG_ADDR_FG_COLOR_GREEN 0x0004 // 8-bit green text color
|
||||||
|
#define REG_ADDR_FG_COLOR_BLUE 0x0005 // 8-bit blue text color
|
||||||
|
#define REG_ADDR_IMAGE_NUM 0x0006 // 16-bit image number
|
||||||
|
#define REG_ADDR_TEXT 0x0007 // Start of text registers (1 reg / ascii character, null terminated)
|
||||||
|
#define REG_SIZE_TEXT 0x00C8 // 200 registers / characters
|
||||||
|
#define TEXT_POS_X 10
|
||||||
|
#define TEXT_POS_Y 10
|
||||||
|
#define IMG_POS_X 0
|
||||||
|
#define IMG_POS_Y 75
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fn static err_t modbus_incoming_data(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
|
* @brief Error codes for internal use in the modbus tcp server.
|
||||||
* @brief Function that's called when there is a new request on port 502.
|
|
||||||
* It handles the incoming data from QModMaster
|
|
||||||
*/
|
*/
|
||||||
static err_t modbus_incoming_data(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t err) {
|
typedef enum {
|
||||||
uint8_t counter;
|
MB_TCP_ERR_OK,
|
||||||
char text[TEXT_LENGTH];
|
MB_TCP_ERR_FAILED,
|
||||||
uint32_t result_background = 0xff000000;
|
MB_TCP_ERR_INVALID_ADU,
|
||||||
uint32_t text_foreground_color = 0xff000000;
|
MB_TCP_ERR_INVALID_PROTOCOL_ID,
|
||||||
|
MB_TCP_ERR_INVALID_LENGTH,
|
||||||
LWIP_UNUSED_ARG(arg); // This is used to prevent a warning
|
MB_TCP_ERR_MEM,
|
||||||
|
} mb_tcp_err_t;
|
||||||
// Putting underscores in the whole array
|
|
||||||
memset(text, '_', TEXT_LENGTH);
|
|
||||||
text[TEXT_LENGTH - 1] = '\0';
|
|
||||||
|
|
||||||
if (p != NULL) {
|
|
||||||
LOG_INFO(TAG, "data is valid\n");
|
|
||||||
// Process the modbus data
|
|
||||||
tcp_recved(pcb, p->tot_len);
|
|
||||||
|
|
||||||
// Putting the buffer in the register array
|
|
||||||
for (uint16_t i = 0; i < p->tot_len && i < MAX_REG; i++) {
|
|
||||||
registers[i] = ((uint8_t*)p->payload)[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (registers[MODBUS_MODE] == MULTIPLE_REG) {
|
|
||||||
// Check if it's a Modbus Write Multiple Registers request (0x10)
|
|
||||||
LOG_INFO(TAG, "in writing multiple register mode\n");
|
|
||||||
|
|
||||||
LOG_INFO(TAG, "Background R:%d G:%d B:%d\nForeground: R:%d G:%d B:%d\nImage Nr: %d",
|
|
||||||
registers[REG_COLOR_B_RED], registers[REG_COLOR_B_GREEN], registers[REG_COLOR_B_BLUE],
|
|
||||||
registers[REG_COLOR_F_RED], registers[REG_COLOR_F_GREEN], registers[REG_COLOR_F_BLUE],
|
|
||||||
registers[REG_IMAGE_NR]);
|
|
||||||
|
|
||||||
counter = 0;
|
|
||||||
for (int i = START_DATA; i < REG_LENGTH; i++) {
|
|
||||||
if (i % 2 == 0) {
|
|
||||||
text[counter] = registers[i];
|
|
||||||
counter++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result_background |= ((uint32_t)registers[REG_COLOR_B_RED]) << 16;
|
|
||||||
result_background |= ((uint32_t)registers[REG_COLOR_B_GREEN]) << 8;
|
|
||||||
result_background |= (uint32_t)registers[REG_COLOR_B_BLUE];
|
|
||||||
|
|
||||||
text_foreground_color |= ((uint32_t)registers[REG_COLOR_F_RED]) << 16;
|
|
||||||
text_foreground_color |= ((uint32_t)registers[REG_COLOR_F_GREEN]) << 8;
|
|
||||||
text_foreground_color |= (uint32_t)registers[REG_COLOR_F_BLUE];
|
|
||||||
|
|
||||||
// Processing the image index
|
|
||||||
size_t number_of_files = llfs_file_count(); // How many files that there are
|
|
||||||
|
|
||||||
if (number_of_files > 0) {
|
|
||||||
llfs_file_t file_list[number_of_files];
|
|
||||||
number_of_files = llfs_file_list(file_list, number_of_files, NULL);
|
|
||||||
|
|
||||||
lcd_clear_text();
|
|
||||||
lcd_clear_images();
|
|
||||||
lcd_stop_all_gifs();
|
|
||||||
|
|
||||||
lcd_display_text(text, 10, 10, text_foreground_color, result_background, LCD_FONT24);
|
|
||||||
|
|
||||||
if (number_of_files < registers[REG_IMAGE_NR]) {
|
|
||||||
lcd_display_text("FILE NOT IN FILESYSTEM", 10, 75, LCD_RED, LCD_BLACK, LCD_FONT24);
|
|
||||||
} else {
|
|
||||||
const char* ext = strrchr(file_list[registers[REG_IMAGE_NR] - 1].name, '.');
|
|
||||||
if (ext == NULL) {
|
|
||||||
LOG_CRIT(TAG, "No valid extension found");
|
|
||||||
} else if (strcmp(ext, ".gif") == 0) {
|
|
||||||
lcd_draw_gif_from_llfs_file(&file_list[registers[REG_IMAGE_NR] - 1], 0, 75);
|
|
||||||
} else if (strcmp(ext, ".bmp") == 0) {
|
|
||||||
lcd_draw_img_from_llfs_file(&file_list[registers[REG_IMAGE_NR] - 1], 0, 75);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
LOG_INFO(TAG, "not in writing multiple register mode!!!\n");
|
|
||||||
}
|
|
||||||
} else if (err == ERR_OK) {
|
|
||||||
tcp_close(pcb); // When everything was ok close the TCP connection
|
|
||||||
}
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fn static err_t modbus_accept(void *arg, struct tcp_pcb *pcb, err_t err)
|
* @brief Modbus function codes
|
||||||
* @brief Sets the function that's being called when theirs incoming data
|
|
||||||
*/
|
*/
|
||||||
static err_t modbus_accept(void* arg, struct tcp_pcb* pcb, err_t err) {
|
enum {
|
||||||
LWIP_UNUSED_ARG(arg);
|
WRITE_MULTIPLE_REGISTERS = 0x10,
|
||||||
LWIP_UNUSED_ARG(err);
|
};
|
||||||
|
|
||||||
// Sets the priority of a connection.
|
|
||||||
tcp_setprio(pcb, TCP_PRIO_MIN);
|
|
||||||
|
|
||||||
// Sets which function is being called when new data arrives
|
|
||||||
tcp_recv(pcb, modbus_incoming_data);
|
|
||||||
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fn void modbus_init
|
* @brief Modbus exception codes
|
||||||
* @brief Initializes the modbus tcp
|
|
||||||
*/
|
*/
|
||||||
void modbus_init(void) {
|
typedef enum {
|
||||||
LOG_INFO(TAG, "Initializing");
|
ILLEGAL_FUNCTION = 0x01,
|
||||||
// Creating a new tcp pcb
|
ILLEGAL_DATA_ADDRESS = 0x02,
|
||||||
|
ILLEGAL_DATA_VALUE = 0x03,
|
||||||
|
SERVER_DEVICE_FAILURE = 0x04,
|
||||||
|
ACKNOWLEDGE = 0x05,
|
||||||
|
SERVER_DEVICE_BUSY = 0x06,
|
||||||
|
MEMORY_PARITY_ERROR = 0x08,
|
||||||
|
GATEWAY_PATH_UNAVAILABLE = 0x0A,
|
||||||
|
GATEWAY_TARGET_DEVICE_FAILED_TO_RESPOND = 0x0B,
|
||||||
|
} mb_exception_code_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Modbus TCP Application Data Unit (ADU)
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
struct {
|
||||||
|
uint16_t transaction_id;
|
||||||
|
uint16_t protocol_id;
|
||||||
|
uint16_t length;
|
||||||
|
uint8_t unit_id;
|
||||||
|
} mbap_header;
|
||||||
|
uint8_t function_code;
|
||||||
|
uint8_t* data;
|
||||||
|
} modbus_tcp_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The data fields of the write multiple registers request PDU.
|
||||||
|
* @note The data field is not included in the struct.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint16_t start_address;
|
||||||
|
uint16_t quantity;
|
||||||
|
uint8_t byte_count;
|
||||||
|
} write_multiple_reg_req_t;
|
||||||
|
|
||||||
|
// Static global variables
|
||||||
|
static char* TAG = "Modbus_TCP"; // Tag used in logs
|
||||||
|
static uint16_t registers[REGISTER_COUNT]; // The modbus registers
|
||||||
|
|
||||||
|
// Function prototypes
|
||||||
|
static err_t tcp_accept_cb(void* arg, struct tcp_pcb* new_pcb, err_t err);
|
||||||
|
static void tcp_err_cb(void* arg, err_t err);
|
||||||
|
static err_t tcp_poll_cb(void* arg, struct tcp_pcb* pcb);
|
||||||
|
static err_t tcp_sent_cb(void* arg, struct tcp_pcb* pcb, u16_t len);
|
||||||
|
static err_t tcp_recv_cb(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t err);
|
||||||
|
static mb_tcp_err_t parse_data_to_adu(modbus_tcp_t* adu, uint8_t* data, size_t length);
|
||||||
|
static mb_tcp_err_t handle_modbus_request(modbus_tcp_t* req_adu, modbus_tcp_t* rsp_adu);
|
||||||
|
static mb_tcp_err_t send_modbus_response(struct tcp_pcb* pcb, modbus_tcp_t* rsp_adu);
|
||||||
|
static void handle_mb_func_write_multiple_req(modbus_tcp_t* req_adu, modbus_tcp_t* rsp_adu);
|
||||||
|
static void generate_modbus_exception_rsp(modbus_tcp_t* req_adu,
|
||||||
|
modbus_tcp_t* rsp_adu,
|
||||||
|
mb_exception_code_t exception_code);
|
||||||
|
static void modbus_update_app(void);
|
||||||
|
static const char* img_num_to_filename(uint16_t img_num);
|
||||||
|
static void dump_adu(modbus_tcp_t* adu);
|
||||||
|
|
||||||
|
void modbus_tcp_init(void) {
|
||||||
|
struct tcp_pcb* modbus_pcb;
|
||||||
|
|
||||||
|
// Initialize the modbus tcp pcb
|
||||||
modbus_pcb = tcp_new();
|
modbus_pcb = tcp_new();
|
||||||
|
if (modbus_pcb == NULL) {
|
||||||
|
LOG_CRIT(TAG, "Failed to create modbus pcb");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Bind the modbus_pcb to port 502
|
// Listen on all interfaces (port 502)
|
||||||
tcp_bind(modbus_pcb, IP_ADDR_ANY, MODBUSPORT);
|
if (tcp_bind(modbus_pcb, IP_ADDR_ANY, MODBUS_TCP_PORT) != ERR_OK) {
|
||||||
|
LOG_CRIT(TAG, "Failed to bind modbus pcb");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the state of the pcb to LISTEN
|
||||||
modbus_pcb = tcp_listen(modbus_pcb);
|
modbus_pcb = tcp_listen(modbus_pcb);
|
||||||
// Set callback function for incoming connections
|
if (modbus_pcb == NULL) {
|
||||||
tcp_accept(modbus_pcb, modbus_accept);
|
LOG_CRIT(TAG, "Failed to listen on modbus pcb");
|
||||||
LOG_INFO(TAG, "initialized");
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the callback function for incoming connections
|
||||||
|
tcp_accept(modbus_pcb, tcp_accept_cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback function for incoming connections.
|
||||||
|
*
|
||||||
|
* @param arg not used
|
||||||
|
* @param new_pcb
|
||||||
|
* @param err
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
static err_t tcp_accept_cb(void* arg, struct tcp_pcb* new_pcb, err_t err) {
|
||||||
|
LOG_DEBUG(TAG, "TCP accept");
|
||||||
|
|
||||||
|
if (err != ERR_OK) {
|
||||||
|
LOG_WARN(TAG, "TCP accept failed with error(%d): %s", err, lwip_strerr(err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the callback functions for the new pcb
|
||||||
|
tcp_recv(new_pcb, tcp_recv_cb);
|
||||||
|
tcp_sent(new_pcb, tcp_sent_cb);
|
||||||
|
tcp_err(new_pcb, tcp_err_cb);
|
||||||
|
tcp_poll(new_pcb, tcp_poll_cb, TCP_POLL_INTERVAL);
|
||||||
|
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback function for tcp errors.
|
||||||
|
*
|
||||||
|
* @param arg
|
||||||
|
* @param err
|
||||||
|
*/
|
||||||
|
static void tcp_err_cb(void* arg, err_t err) {
|
||||||
|
LOG_WARN(TAG, "TCP error(%d): %s", err, lwip_strerr(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback function for tcp poll.
|
||||||
|
*
|
||||||
|
* This function is called periodically to check if the connection is still alive.
|
||||||
|
* The interval is set by TCP_POLL_INTERVAL.
|
||||||
|
*
|
||||||
|
* @param arg
|
||||||
|
* @param pcb
|
||||||
|
* @return ERR_OK
|
||||||
|
*/
|
||||||
|
static err_t tcp_poll_cb(void* arg, struct tcp_pcb* pcb) {
|
||||||
|
LOG_DEBUG(TAG, "TCP poll");
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback function for tcp sent.
|
||||||
|
*
|
||||||
|
* Called when sent data has been acknowledged by the remote side.
|
||||||
|
*
|
||||||
|
* @param arg
|
||||||
|
* @param pcb
|
||||||
|
* @param len
|
||||||
|
* @return ERR_OK
|
||||||
|
*/
|
||||||
|
static err_t tcp_sent_cb(void* arg, struct tcp_pcb* pcb, u16_t len) {
|
||||||
|
LOG_DEBUG(TAG, "TCP data acknowledged");
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback function for tcp receive.
|
||||||
|
*
|
||||||
|
* Called when data has been received.
|
||||||
|
*
|
||||||
|
* @param arg
|
||||||
|
* @param pcb
|
||||||
|
* @param p
|
||||||
|
* @param err
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
static err_t tcp_recv_cb(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t err) {
|
||||||
|
modbus_tcp_t mb_req_adu; // Modbus request adu to store the received data in
|
||||||
|
|
||||||
|
LOG_DEBUG(TAG, "TCP data received");
|
||||||
|
|
||||||
|
// Connection closed?
|
||||||
|
if (p == NULL && err == ERR_OK) {
|
||||||
|
LOG_INFO(TAG, "Remote closed connection");
|
||||||
|
return tcp_close(pcb);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err != ERR_OK) {
|
||||||
|
LOG_WARN(TAG, "TCP data received with error(%d): %s", err, lwip_strerr(err));
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the data from the pbuf to the modbus request adu
|
||||||
|
mb_tcp_err_t mb_err = parse_data_to_adu(&mb_req_adu, p->payload, p->len);
|
||||||
|
if (mb_err != MB_TCP_ERR_OK) {
|
||||||
|
LOG_WARN(TAG, "Invalid modbus adu received");
|
||||||
|
goto err_adu_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle the modbus request
|
||||||
|
modbus_tcp_t mb_rsp_adu;
|
||||||
|
handle_modbus_request(&mb_req_adu, &mb_rsp_adu);
|
||||||
|
|
||||||
|
// Tell the tcp stack that we have taken the data
|
||||||
|
tcp_recved(pcb, p->tot_len);
|
||||||
|
|
||||||
|
// Send the modbus response
|
||||||
|
if (send_modbus_response(pcb, &mb_rsp_adu) != MB_TCP_ERR_OK) {
|
||||||
|
LOG_WARN(TAG, "Failed to send modbus response");
|
||||||
|
goto err_rsp_fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
err_rsp_fail:
|
||||||
|
free(mb_rsp_adu.data);
|
||||||
|
err_adu_read:
|
||||||
|
pbuf_free(p);
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Parses the given data into the tcp ADU struct.
|
||||||
|
*
|
||||||
|
* This function takes the raw data received and parses it into a modbus TCP Application Data Unit (ADU).
|
||||||
|
*
|
||||||
|
* @note The data field of the ADU still points to the raw data, so it must stay valid until the ADU is no longer
|
||||||
|
* needed.
|
||||||
|
* @todo Store the data in the ADU struct instead of just pointing to it?
|
||||||
|
*
|
||||||
|
* @param[out] adu Pointer to a modbus_tcp_t structure where the parsed ADU will be stored.
|
||||||
|
* @param[in] data Pointer to the raw data received from the modbus TCP server.
|
||||||
|
* @param[in] length Length of the raw data.
|
||||||
|
*/
|
||||||
|
static mb_tcp_err_t parse_data_to_adu(modbus_tcp_t* adu, uint8_t* data, size_t length) {
|
||||||
|
if (length > ADU_MAX_LENGTH) {
|
||||||
|
LOG_DEBUG(TAG, "Invalid adu length: %d, expected max %d", length, ADU_MAX_LENGTH);
|
||||||
|
return MB_TCP_ERR_INVALID_ADU;
|
||||||
|
}
|
||||||
|
if (length < MBAP_HEADER_LENGTH) {
|
||||||
|
LOG_DEBUG(TAG, "Invalid adu length: %d, expected at least %d", length, MBAP_HEADER_LENGTH);
|
||||||
|
return MB_TCP_ERR_INVALID_ADU;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The adu struct is a one-to-one map of the modbus adu, so we can just copy the data
|
||||||
|
// But modbus fields are big endian, so we need to convert them to little endian
|
||||||
|
adu->mbap_header.transaction_id = (data[0] << 8) | data[1];
|
||||||
|
adu->mbap_header.protocol_id = (data[2] << 8) | data[3];
|
||||||
|
adu->mbap_header.length = (data[4] << 8) | data[5];
|
||||||
|
adu->mbap_header.unit_id = data[6];
|
||||||
|
adu->function_code = data[7];
|
||||||
|
adu->data = &data[8]; // Don't change the data endianness yet, since it's structure is function dependent
|
||||||
|
|
||||||
|
// Correct protocol id?
|
||||||
|
if (adu->mbap_header.protocol_id != PROTOCOL_ID_MODBUS) {
|
||||||
|
LOG_DEBUG(TAG, "Invalid protocol id: %d, expected %d", adu->mbap_header.protocol_id, PROTOCOL_ID_MODBUS);
|
||||||
|
return MB_TCP_ERR_INVALID_PROTOCOL_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Length matches length field?
|
||||||
|
if (adu->mbap_header.length != length - MBAP_HEADER_LENGTH + 1) {
|
||||||
|
LOG_DEBUG(TAG, "Length mismatch: %d, expected %d", adu->mbap_header.length, length - MBAP_HEADER_LENGTH + 1);
|
||||||
|
return MB_TCP_ERR_INVALID_ADU;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MB_TCP_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handles the given modbus request and generates a response.
|
||||||
|
*
|
||||||
|
* Handles the given modbus request and generates a response, either a normal response or an exception response.
|
||||||
|
* The response data field is allocated and must be freed by the caller.
|
||||||
|
*
|
||||||
|
* @param[in] req_adu Pointer to the modbus request adu.
|
||||||
|
* @param[out] rsp_adu Pointer to the modbus response adu.
|
||||||
|
* @return MB_TCP_ERR_OK if the request was handled successfully, otherwise an error code.
|
||||||
|
*/
|
||||||
|
static mb_tcp_err_t handle_modbus_request(modbus_tcp_t* req_adu, modbus_tcp_t* rsp_adu) {
|
||||||
|
// Check if the function code is supported
|
||||||
|
switch (req_adu->function_code) {
|
||||||
|
case WRITE_MULTIPLE_REGISTERS: {
|
||||||
|
LOG_INFO(TAG, "Write multiple registers request received");
|
||||||
|
handle_mb_func_write_multiple_req(req_adu, rsp_adu);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
LOG_WARN(TAG, "Unsupported function code: %d", req_adu->function_code);
|
||||||
|
generate_modbus_exception_rsp(req_adu, rsp_adu, ILLEGAL_FUNCTION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return MB_TCP_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generates a modbus exception response.
|
||||||
|
*
|
||||||
|
* Generates a modbus exception response based on the given request adu and exception code.
|
||||||
|
* The response data field is allocated and must be freed by the caller.
|
||||||
|
*
|
||||||
|
* @param[in] req_adu The request adu to base the response adu on.
|
||||||
|
* @param[out] rsp_adu The response adu to fill.
|
||||||
|
* @param[in] exception_code The exception code to use.
|
||||||
|
*/
|
||||||
|
static void generate_modbus_exception_rsp(modbus_tcp_t* req_adu,
|
||||||
|
modbus_tcp_t* rsp_adu,
|
||||||
|
mb_exception_code_t exception_code) {
|
||||||
|
uint16_t pdu_length = 2; // Function code + exception code
|
||||||
|
|
||||||
|
// Fill the response adu based on the request adu
|
||||||
|
rsp_adu->mbap_header.transaction_id = req_adu->mbap_header.transaction_id;
|
||||||
|
rsp_adu->mbap_header.protocol_id = PROTOCOL_ID_MODBUS;
|
||||||
|
rsp_adu->mbap_header.length = 1 + pdu_length; // 1 for the unit id
|
||||||
|
rsp_adu->mbap_header.unit_id = req_adu->mbap_header.unit_id;
|
||||||
|
rsp_adu->function_code = req_adu->function_code + EXCEPTION_OFFSET;
|
||||||
|
|
||||||
|
// Allocate memory for the exception code
|
||||||
|
rsp_adu->data = malloc(1);
|
||||||
|
if (rsp_adu->data == NULL) {
|
||||||
|
LOG_CRIT(TAG, "Failed to allocate memory for exception code");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rsp_adu->data[0] = exception_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sends the given modbus response.
|
||||||
|
*
|
||||||
|
* Sends the given modbus response to the given tcp pcb.
|
||||||
|
* A copy of the response data is made, so the response adu data can be freed after this function returns.
|
||||||
|
*
|
||||||
|
* @param[in,out] pcb The tcp pcb to send the response to (same as the pcb used to receive the request).
|
||||||
|
* @param[in] rsp_adu The response adu to send.
|
||||||
|
* @return MB_TCP_ERR_OK if the response was sent successfully, otherwise an error code.
|
||||||
|
*/
|
||||||
|
static mb_tcp_err_t send_modbus_response(struct tcp_pcb* pcb, modbus_tcp_t* rsp_adu) {
|
||||||
|
uint16_t pdu_length = rsp_adu->mbap_header.length - 1; // Length of the data + 1 (for the unit id)
|
||||||
|
uint16_t adu_length = MBAP_HEADER_LENGTH + pdu_length;
|
||||||
|
uint8_t data[adu_length];
|
||||||
|
err_t err;
|
||||||
|
|
||||||
|
if (pdu_length > PDU_MAX_LENGTH) {
|
||||||
|
LOG_WARN(TAG, "Invalid pdu length: %d, expected less than %d", pdu_length, PDU_MAX_LENGTH);
|
||||||
|
return MB_TCP_ERR_INVALID_ADU;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DEBUG(TAG, "Sending modbus response with length: %d", adu_length);
|
||||||
|
|
||||||
|
// Serialize the adu (little endian -> big endian)
|
||||||
|
data[0] = rsp_adu->mbap_header.transaction_id >> 8;
|
||||||
|
data[1] = rsp_adu->mbap_header.transaction_id & 0xFF;
|
||||||
|
data[2] = rsp_adu->mbap_header.protocol_id >> 8;
|
||||||
|
data[3] = rsp_adu->mbap_header.protocol_id & 0xFF;
|
||||||
|
data[4] = rsp_adu->mbap_header.length >> 8;
|
||||||
|
data[5] = rsp_adu->mbap_header.length & 0xFF;
|
||||||
|
data[6] = rsp_adu->mbap_header.unit_id;
|
||||||
|
data[7] = rsp_adu->function_code;
|
||||||
|
|
||||||
|
// The data should already be in big endian, so we can just copy it
|
||||||
|
memcpy(&data[8], rsp_adu->data, pdu_length - 1); // -1 function code is also in the pdu
|
||||||
|
|
||||||
|
if (adu_length > tcp_sndbuf(pcb)) {
|
||||||
|
LOG_WARN(TAG, "Not enough space in tcp buffer to send modbus response");
|
||||||
|
return MB_TCP_ERR_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the data
|
||||||
|
err = tcp_write(pcb, data, adu_length, TCP_WRITE_FLAG_COPY);
|
||||||
|
if (err != ERR_OK) {
|
||||||
|
LOG_WARN(TAG, "Failed to send modbus response with error(%d): %s", err, lwip_strerr(err));
|
||||||
|
return MB_TCP_ERR_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MB_TCP_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handles a write multiple registers request.
|
||||||
|
*
|
||||||
|
* Handles a write multiple registers request and generates a response adu accordingly.
|
||||||
|
*
|
||||||
|
* @param[in] req_adu The request adu to handle.
|
||||||
|
* @param[out] rsp_adu The response adu to fill.
|
||||||
|
*/
|
||||||
|
static void handle_mb_func_write_multiple_req(modbus_tcp_t* req_adu, modbus_tcp_t* rsp_adu) {
|
||||||
|
write_multiple_reg_req_t req_pdu;
|
||||||
|
uint16_t req_data_length = req_adu->mbap_header.length - 2; // -2 for the unit id and function code
|
||||||
|
|
||||||
|
// Request at least enough data for the minimum length?
|
||||||
|
if (req_data_length < WRITE_MULTIPLE_REG_REQ_MIN_LENGTH) {
|
||||||
|
LOG_WARN(TAG, "Invalid write multiple registers request length, not enough data for minimum length");
|
||||||
|
generate_modbus_exception_rsp(req_adu, rsp_adu, ILLEGAL_DATA_VALUE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map the data to the write multiple registers request struct and convert it to little endian
|
||||||
|
req_pdu.start_address = (req_adu->data[0] << 8) | req_adu->data[1];
|
||||||
|
req_pdu.quantity = (req_adu->data[2] << 8) | req_adu->data[3];
|
||||||
|
req_pdu.byte_count = req_adu->data[4];
|
||||||
|
|
||||||
|
// Request the correct length? Do the byte and register count match?
|
||||||
|
if (req_data_length != WRITE_MULTIPLE_REG_REQ_MIN_LENGTH + req_pdu.byte_count
|
||||||
|
|| req_pdu.quantity < WRITE_MULTIPLE_REG_QUANTITY_MIN || req_pdu.quantity > WRITE_MULTIPLE_REG_QUANTITY_MAX
|
||||||
|
|| req_pdu.quantity * 2 != req_pdu.byte_count) {
|
||||||
|
LOG_WARN(TAG, "Invalid write multiple registers request length");
|
||||||
|
generate_modbus_exception_rsp(req_adu, rsp_adu, ILLEGAL_DATA_VALUE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invalid start address or quantity?
|
||||||
|
if (req_pdu.start_address + req_pdu.quantity >= REGISTER_COUNT) {
|
||||||
|
LOG_DEBUG(TAG, "Invalid start address or quantity");
|
||||||
|
generate_modbus_exception_rsp(req_adu, rsp_adu, ILLEGAL_DATA_ADDRESS);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the data to register values (big endian -> little endian)
|
||||||
|
for (uint16_t i = 0; i < req_pdu.quantity; i++) {
|
||||||
|
registers[req_pdu.start_address + i] = (req_adu->data[WRITE_MULTIPLE_REG_REQ_MIN_LENGTH + i * 2] << 8)
|
||||||
|
| req_adu->data[WRITE_MULTIPLE_REG_REQ_MIN_LENGTH + 1 + i * 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the application with the new register values
|
||||||
|
modbus_update_app(); // TODO: do this when the request is handled successfully, to avoid timeouts.
|
||||||
|
|
||||||
|
// Fill the response adu based on the request adu
|
||||||
|
rsp_adu->mbap_header.transaction_id = req_adu->mbap_header.transaction_id;
|
||||||
|
rsp_adu->mbap_header.protocol_id = PROTOCOL_ID_MODBUS;
|
||||||
|
rsp_adu->mbap_header.length = 2 + WRITE_MULTIPLE_REG_RSP_LENGTH; // 2 for the unit id and function code
|
||||||
|
rsp_adu->mbap_header.unit_id = req_adu->mbap_header.unit_id;
|
||||||
|
rsp_adu->function_code = req_adu->function_code;
|
||||||
|
|
||||||
|
// Allocate memory for the response data
|
||||||
|
rsp_adu->data = malloc(WRITE_MULTIPLE_REG_RSP_LENGTH);
|
||||||
|
if (rsp_adu->data == NULL) {
|
||||||
|
LOG_CRIT(TAG, "Failed to allocate memory for response data");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The response data are the same 4 bytes as the request data
|
||||||
|
memcpy(rsp_adu->data, req_adu->data, WRITE_MULTIPLE_REG_RSP_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Dumps the given ADU to the log.
|
||||||
|
*
|
||||||
|
* @param[in] adu Pointer to the ADU to dump.
|
||||||
|
*/
|
||||||
|
static void dump_adu(modbus_tcp_t* adu) {
|
||||||
|
LOG_DEBUG(TAG, "Modbus adu:");
|
||||||
|
LOG_DEBUG(TAG, " Transaction id: %d", adu->mbap_header.transaction_id);
|
||||||
|
LOG_DEBUG(TAG, " Protocol id: %d", adu->mbap_header.protocol_id);
|
||||||
|
LOG_DEBUG(TAG, " Length: %d", adu->mbap_header.length);
|
||||||
|
LOG_DEBUG(TAG, " Unit id: %d", adu->mbap_header.unit_id);
|
||||||
|
LOG_DEBUG(TAG, " Function code: %d", adu->function_code);
|
||||||
|
LOG_DEBUG(TAG, " Data: ");
|
||||||
|
for (size_t i = 0; i < adu->mbap_header.length - 2; i++) {
|
||||||
|
LOG_DEBUG(TAG, " [%d]:%d", i, adu->data[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Update the application with the new register values
|
||||||
|
*/
|
||||||
|
static void modbus_update_app(void) {
|
||||||
|
uint32_t text_color; // Text color in ARGB888
|
||||||
|
uint32_t bg_color; // Background color in ARGB888
|
||||||
|
char text[REG_SIZE_TEXT];
|
||||||
|
const char* filename;
|
||||||
|
|
||||||
|
LOG_INFO(TAG, "Updating application with new register values");
|
||||||
|
|
||||||
|
// Get the colors from the registers
|
||||||
|
text_color = 0xFF000000 | (registers[REG_ADDR_FG_COLOR_RED] << 16) | (registers[REG_ADDR_FG_COLOR_GREEN] << 8)
|
||||||
|
| registers[REG_ADDR_FG_COLOR_BLUE];
|
||||||
|
bg_color = 0xFF000000 | (registers[REG_ADDR_BG_COLOR_RED] << 16) | (registers[REG_ADDR_BG_COLOR_GREEN] << 8)
|
||||||
|
| registers[REG_ADDR_BG_COLOR_BLUE];
|
||||||
|
|
||||||
|
// Get the text from the registers
|
||||||
|
for (int i = 0; i < REG_SIZE_TEXT; i++) {
|
||||||
|
text[i] = registers[REG_ADDR_TEXT + i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the filename based on the image number register
|
||||||
|
filename = img_num_to_filename(registers[REG_ADDR_IMAGE_NUM]);
|
||||||
|
|
||||||
|
// Clear the screen
|
||||||
|
lcd_clear_images();
|
||||||
|
lcd_clear_text();
|
||||||
|
|
||||||
|
// Display the text
|
||||||
|
lcd_display_text(text, TEXT_POS_X, TEXT_POS_Y, text_color, bg_color, LCD_FONT24);
|
||||||
|
|
||||||
|
// Try to display the image
|
||||||
|
if (filename != NULL) {
|
||||||
|
LOG_DEBUG(TAG, "Displaying image: %s", filename);
|
||||||
|
|
||||||
|
char* ext = strrchr(filename, '.');
|
||||||
|
if (ext == NULL) {
|
||||||
|
LOG_WARN(TAG, "File %s has no valid extension", filename);
|
||||||
|
} else if (strcmp(ext, ".gif") == 0) {
|
||||||
|
lcd_draw_gif_from_fs(filename, IMG_POS_X, IMG_POS_Y);
|
||||||
|
} else if (strcmp(ext, ".bmp") == 0) {
|
||||||
|
lcd_draw_img_from_fs(filename, IMG_POS_X, IMG_POS_Y);
|
||||||
|
} else {
|
||||||
|
LOG_WARN(TAG, "File %s is not a valid img", filename);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG_WARN(TAG, "No image found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert the image number register to a filename
|
||||||
|
*
|
||||||
|
* Converts the image number register to a filename by looking up the file in the filesystem.
|
||||||
|
*
|
||||||
|
* @note This function doesn't check if the file is a valid image file.
|
||||||
|
* So the image number is more a file number.
|
||||||
|
*
|
||||||
|
* @param[in] img_num The image number register
|
||||||
|
* @return The filename of the image or NULL if no file is found
|
||||||
|
*/
|
||||||
|
static const char* img_num_to_filename(uint16_t img_num) {
|
||||||
|
size_t number_of_files = llfs_file_count();
|
||||||
|
|
||||||
|
LOG_DEBUG(TAG, "Converting image number %d to filename, %d files found", img_num, number_of_files);
|
||||||
|
|
||||||
|
if (number_of_files == 0 || img_num > number_of_files) {
|
||||||
|
LOG_DEBUG(TAG, "No files found or invalid image number: %d", img_num);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
llfs_file_t files[number_of_files];
|
||||||
|
llfs_file_list(files, number_of_files, NULL);
|
||||||
|
return files[img_num].name;
|
||||||
|
}
|
||||||
@@ -17,24 +17,18 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
#define ATTEMPT_RECONNECT_AMOUNT 50
|
#define ATTEMPT_RECONNECT_AMOUNT 50
|
||||||
#define PUBLISH_QOS 2
|
#define PUBLISH_QOS 2
|
||||||
#define PUBLISH_RETAIN 1
|
#define PUBLISH_RETAIN 1
|
||||||
#define PRINT_XPOS 50
|
#define PRINT_XPOS 50
|
||||||
#define PRINT_YPOS 50
|
#define PRINT_YPOS 50
|
||||||
#define MAX_FILES 20
|
#define MAX_FILES 20
|
||||||
#define SERVER_IP4_A 192
|
#define SERVER_IP4_A 192
|
||||||
#define SERVER_IP4_B 168
|
#define SERVER_IP4_B 168
|
||||||
#define SERVER_IP4_C 69
|
#define SERVER_IP4_C 69
|
||||||
#define SERVER_IP4_D 11
|
#define SERVER_IP4_D 11
|
||||||
#define SERVER_PORT 1883
|
#define SERVER_PORT 1883
|
||||||
|
|
||||||
typedef enum input_topic {
|
typedef enum input_topic { set_text, set_text_color, set_color, set_image, other_topic } input_topic_t;
|
||||||
set_text,
|
|
||||||
set_text_color,
|
|
||||||
set_color,
|
|
||||||
set_image,
|
|
||||||
other_topic
|
|
||||||
} input_topic_t;
|
|
||||||
|
|
||||||
// Function prototypes
|
// Function prototypes
|
||||||
static void mqtt_pub_request_cb(void*, err_t);
|
static void mqtt_pub_request_cb(void*, err_t);
|
||||||
@@ -47,7 +41,8 @@ static void mosquitto_connect(mqtt_client_t*);
|
|||||||
static uint32_t color_picker(char*);
|
static uint32_t color_picker(char*);
|
||||||
static void create_publish_string(char*, char*, size_t);
|
static void create_publish_string(char*, char*, size_t);
|
||||||
|
|
||||||
// Global variables used in mqtt_incoming_publish_cb and mqtt_incoming_data_cb to give an easy to use ID to the subscribed topics
|
// Global variables used in mqtt_incoming_publish_cb and mqtt_incoming_data_cb to give an easy to use ID to the
|
||||||
|
// subscribed topics
|
||||||
static sFONT* font;
|
static sFONT* font;
|
||||||
static uint16_t xpos;
|
static uint16_t xpos;
|
||||||
static uint16_t ypos;
|
static uint16_t ypos;
|
||||||
@@ -80,9 +75,10 @@ static void publish_data(mqtt_client_t* client, void* arg) {
|
|||||||
|
|
||||||
LOG_DEBUG(TAG, "Entering publish");
|
LOG_DEBUG(TAG, "Entering publish");
|
||||||
|
|
||||||
create_publish_string("*.bmp", pub_payload,sizeof(pub_payload));
|
create_publish_string("*.bmp", pub_payload, sizeof(pub_payload));
|
||||||
|
|
||||||
err = mqtt_publish(client, "getImageList", pub_payload, strlen(pub_payload), PUBLISH_QOS, PUBLISH_RETAIN, mqtt_pub_request_cb, arg);
|
err = mqtt_publish(client, "getImageList", pub_payload, strlen(pub_payload), PUBLISH_QOS, PUBLISH_RETAIN,
|
||||||
|
mqtt_pub_request_cb, arg);
|
||||||
if (err != ERR_OK) {
|
if (err != ERR_OK) {
|
||||||
LOG_DEBUG(TAG, "Publish err: %d", err);
|
LOG_DEBUG(TAG, "Publish err: %d", err);
|
||||||
}
|
}
|
||||||
@@ -90,7 +86,8 @@ static void publish_data(mqtt_client_t* client, void* arg) {
|
|||||||
pub_payload[0] = '\0';
|
pub_payload[0] = '\0';
|
||||||
create_publish_string("*.gif", pub_payload, sizeof(pub_payload));
|
create_publish_string("*.gif", pub_payload, sizeof(pub_payload));
|
||||||
|
|
||||||
err = mqtt_publish(client, "getGifList", pub_payload, strlen(pub_payload), PUBLISH_QOS, PUBLISH_RETAIN, mqtt_pub_request_cb, arg);
|
err = mqtt_publish(client, "getGifList", pub_payload, strlen(pub_payload), PUBLISH_QOS, PUBLISH_RETAIN,
|
||||||
|
mqtt_pub_request_cb, arg);
|
||||||
if (err != ERR_OK) {
|
if (err != ERR_OK) {
|
||||||
LOG_DEBUG(TAG, "Publish err: %d", err);
|
LOG_DEBUG(TAG, "Publish err: %d", err);
|
||||||
}
|
}
|
||||||
@@ -142,8 +139,8 @@ static void mqtt_incoming_data_cb(void* arg, const uint8_t* data, uint16_t len,
|
|||||||
|
|
||||||
LOG_INFO(TAG, "Incoming publish payload with length %d, flags %d", len, flags);
|
LOG_INFO(TAG, "Incoming publish payload with length %d, flags %d", len, flags);
|
||||||
if (!(flags & MQTT_DATA_FLAG_LAST)) {
|
if (!(flags & MQTT_DATA_FLAG_LAST)) {
|
||||||
LOG_WARN(TAG, "incoming data too big to fit in buffer.");
|
LOG_WARN(TAG, "incoming data too big to fit in buffer.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
memcpy(data_buffer, data, len);
|
memcpy(data_buffer, data, len);
|
||||||
data_buffer[len] = '\0';
|
data_buffer[len] = '\0';
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
*/
|
*/
|
||||||
#include "tcp_cmd.h"
|
#include "tcp_cmd.h"
|
||||||
|
|
||||||
static uint32_t result_txt = 0xff000000; // Store text color
|
static uint32_t result_txt = 0xff000000; // Store text color
|
||||||
static uint32_t result_bg = 0xff000000; // Store background color
|
static uint32_t result_bg = 0xff000000; // Store background color
|
||||||
|
|
||||||
static void tcp_cmd_close(struct tcp_pcb* pcb) {
|
static void tcp_cmd_close(struct tcp_pcb* pcb) {
|
||||||
tcp_arg(pcb, NULL);
|
tcp_arg(pcb, NULL);
|
||||||
@@ -36,7 +36,6 @@ static err_t tcp_cmd_recv(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t
|
|||||||
|
|
||||||
char* endptr;
|
char* endptr;
|
||||||
|
|
||||||
|
|
||||||
if (err == ERR_OK && p != NULL) {
|
if (err == ERR_OK && p != NULL) {
|
||||||
tcp_recved(pcb, p->tot_len);
|
tcp_recved(pcb, p->tot_len);
|
||||||
pc = (char*)p->payload;
|
pc = (char*)p->payload;
|
||||||
@@ -48,13 +47,15 @@ static err_t tcp_cmd_recv(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t
|
|||||||
|
|
||||||
if (!strncmp(tcp_buffer, "help", 4)) {
|
if (!strncmp(tcp_buffer, "help", 4)) {
|
||||||
check = 1;
|
check = 1;
|
||||||
tcp_write(pcb, "help : laat lijst zien met alle commando's\r\n"
|
tcp_write(pcb,
|
||||||
"text : geeft tekst mee die op LCD komt (uw_text)\r\n"
|
"help : laat lijst zien met alle commando's\r\n"
|
||||||
"color : kleur achtergrond van scherm (255 255 255)\r\n"
|
"text : geeft tekst mee die op LCD komt (uw_text)\r\n"
|
||||||
"textColor : kleur van tekst (255 255 255)\r\n"
|
"color : kleur achtergrond van scherm (255 255 255)\r\n"
|
||||||
"listImages: laat een lijst zien van de mogelijke afbeeldingen\r\n"
|
"textColor : kleur van tekst (255 255 255)\r\n"
|
||||||
"setImage : veranderd te afbeelding (naam_afbeelding)\r\n"
|
"listImages: laat een lijst zien van de mogelijke afbeeldingen\r\n"
|
||||||
"exit : sluit de verbinding\r\n", 354, TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE);
|
"setImage : veranderd te afbeelding (naam_afbeelding)\r\n"
|
||||||
|
"exit : sluit de verbinding\r\n",
|
||||||
|
354, TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE);
|
||||||
} else if (!strncmp(tcp_buffer, "text ", 5)) {
|
} else if (!strncmp(tcp_buffer, "text ", 5)) {
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < len - 4; i++) {
|
for (i = 0; i < len - 4; i++) {
|
||||||
@@ -64,7 +65,6 @@ static err_t tcp_cmd_recv(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t
|
|||||||
lcd_clear_text();
|
lcd_clear_text();
|
||||||
lcd_display_text(text, 10, 10, result_txt, result_bg, LCD_FONT24);
|
lcd_display_text(text, 10, 10, result_txt, result_bg, LCD_FONT24);
|
||||||
|
|
||||||
|
|
||||||
check = 1;
|
check = 1;
|
||||||
} else if (!strncmp(tcp_buffer, "color", 5)) {
|
} else if (!strncmp(tcp_buffer, "color", 5)) {
|
||||||
for (size_t i = 0; i < 3; i++) {
|
for (size_t i = 0; i < 3; i++) {
|
||||||
@@ -96,7 +96,8 @@ static err_t tcp_cmd_recv(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t
|
|||||||
number_of_files = llfs_file_list(file_list, number_of_files, NULL);
|
number_of_files = llfs_file_list(file_list, number_of_files, NULL);
|
||||||
|
|
||||||
for (size_t i = 0; i < number_of_files; i++) {
|
for (size_t i = 0; i < number_of_files; i++) {
|
||||||
tcp_write(pcb, file_list[i].name, strlen(file_list[i].name), TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE);
|
tcp_write(pcb, file_list[i].name, strlen(file_list[i].name),
|
||||||
|
TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE);
|
||||||
tcp_write(pcb, "\r\n", 2, TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE);
|
tcp_write(pcb, "\r\n", 2, TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -117,7 +118,7 @@ static err_t tcp_cmd_recv(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t
|
|||||||
|
|
||||||
number_of_files = llfs_file_count();
|
number_of_files = llfs_file_count();
|
||||||
|
|
||||||
if(number_of_files > 0) {
|
if (number_of_files > 0) {
|
||||||
llfs_file_t file_list[number_of_files];
|
llfs_file_t file_list[number_of_files];
|
||||||
|
|
||||||
number_of_files = llfs_file_list(file_list, number_of_files, NULL);
|
number_of_files = llfs_file_list(file_list, number_of_files, NULL);
|
||||||
@@ -154,7 +155,8 @@ static err_t tcp_cmd_recv(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!check && (strncmp(tcp_buffer, "\r\n", 2) != 0)) {
|
if (!check && (strncmp(tcp_buffer, "\r\n", 2) != 0)) {
|
||||||
tcp_write(pcb, "Onbestaand commando: help voor lijst van commando's\r\n", 53, TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE);
|
tcp_write(pcb, "Onbestaand commando: help voor lijst van commando's\r\n", 53,
|
||||||
|
TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE);
|
||||||
}
|
}
|
||||||
|
|
||||||
pbuf_free(p);
|
pbuf_free(p);
|
||||||
@@ -184,10 +186,12 @@ static err_t tcp_cmd_accept(void* arg, struct tcp_pcb* pcb, err_t err) {
|
|||||||
tcp_recv(pcb, tcp_cmd_recv);
|
tcp_recv(pcb, tcp_cmd_recv);
|
||||||
tcp_err(pcb, NULL);
|
tcp_err(pcb, NULL);
|
||||||
tcp_poll(pcb, NULL, 4);
|
tcp_poll(pcb, NULL, 4);
|
||||||
tcp_write(pcb, " Welcom bij de TCP CMD Interface\r\n"
|
tcp_write(pcb,
|
||||||
"(Typ help voor een lijst van de commando's! X om te sluiten)\r\n"
|
" Welcom bij de TCP CMD Interface\r\n"
|
||||||
"============================================================\r\n"
|
"(Typ help voor een lijst van de commando's! X om te sluiten)\r\n"
|
||||||
"User: ", 168, TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE);
|
"============================================================\r\n"
|
||||||
|
"User: ",
|
||||||
|
168, TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE);
|
||||||
tcp_sent(pcb, NULL);
|
tcp_sent(pcb, NULL);
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
@@ -200,4 +204,3 @@ void tcp_cmd_init(void) {
|
|||||||
tcp_pcb = tcp_listen(tcp_pcb);
|
tcp_pcb = tcp_listen(tcp_pcb);
|
||||||
tcp_accept(tcp_pcb, tcp_cmd_accept);
|
tcp_accept(tcp_pcb, tcp_cmd_accept);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,10 @@ static void* tftp_open(const char* fname, const char* mode, uint8_t write);
|
|||||||
static void tftp_close(void* handle);
|
static void tftp_close(void* handle);
|
||||||
static int tftp_read(void* handle, void* buf, int bytes);
|
static int tftp_read(void* handle, void* buf, int bytes);
|
||||||
static int tftp_write(void* handle, struct pbuf* p);
|
static int tftp_write(void* handle, struct pbuf* p);
|
||||||
static struct tftp_context tftpContext_s = {.open = tftp_open, .close = tftp_close, .read = tftp_read, .write = tftp_write};
|
static struct tftp_context tftpContext_s = {.open = tftp_open,
|
||||||
|
.close = tftp_close,
|
||||||
|
.read = tftp_read,
|
||||||
|
.write = tftp_write};
|
||||||
/**
|
/**
|
||||||
* @brief tftp custom file functions to set the offset and read the data
|
* @brief tftp custom file functions to set the offset and read the data
|
||||||
* @param[in,out] handle Custom file handles
|
* @param[in,out] handle Custom file handles
|
||||||
@@ -237,7 +240,7 @@ void init_index(void) {
|
|||||||
for (int i = 0; i < MAX_VIRT_FILES; i++) {
|
for (int i = 0; i < MAX_VIRT_FILES; i++) {
|
||||||
len += strlen(virt_file[i].name) + 1;
|
len += strlen(virt_file[i].name) + 1;
|
||||||
}
|
}
|
||||||
void* mem = NULL; // Pointer for internal use by the llfs library
|
void* mem = NULL; // Pointer for internal use by the llfs library
|
||||||
llfs_file_t* file;
|
llfs_file_t* file;
|
||||||
while ((file = llfs_next_file(&mem, NULL)) != NULL) {
|
while ((file = llfs_next_file(&mem, NULL)) != NULL) {
|
||||||
len += strlen(file->name) + 1;
|
len += strlen(file->name) + 1;
|
||||||
|
|||||||
301
project/Core/Src/website_backend.c
Normal file
@@ -0,0 +1,301 @@
|
|||||||
|
/**
|
||||||
|
* @file website_backend.h
|
||||||
|
* @brief Backend for the website to operate
|
||||||
|
* @author Toon B.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Includes
|
||||||
|
#include "website_backend.h"
|
||||||
|
|
||||||
|
// Static functions
|
||||||
|
static size_t wbe_get_images(char* images_string, size_t file_count_fs);
|
||||||
|
static inline void wbe_build_infostring(const llfs_file_t* file_list, char* info_string, const size_t cnt);
|
||||||
|
static void wbe_decoding_url(const char* encoded, char* decoded);
|
||||||
|
static uint32_t wbe_color_value(const char* rgb);
|
||||||
|
|
||||||
|
void wbe_init(void) {
|
||||||
|
httpd_init();
|
||||||
|
LOG_DEBUG("WBE", "Initialize webserver");
|
||||||
|
|
||||||
|
// Set starting LCD screen
|
||||||
|
wbe_display("Please Edit Me !", LCD_GREEN, LCD_BLACK, SD_IMG);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fs_open_custom(struct fs_file* file, const char* name) {
|
||||||
|
// Variables
|
||||||
|
llfs_file_t* wanted_file = llfs_file_open(name + 1);
|
||||||
|
size_t buffer_len = 0;
|
||||||
|
static char image_stringbuffer[STR_MAX] = "";
|
||||||
|
|
||||||
|
// The wanted file was found in the filesystem
|
||||||
|
if (wanted_file != NULL) {
|
||||||
|
// Debug info
|
||||||
|
LOG_DEBUG("WBE", "The file : %s was found", wanted_file->name);
|
||||||
|
|
||||||
|
// Give the information about the file to the client
|
||||||
|
file->data = (const char*)wanted_file->data;
|
||||||
|
file->len = (int)wanted_file->len;
|
||||||
|
file->index = (int)wanted_file->len;
|
||||||
|
file->is_custom_file = 1;
|
||||||
|
file->pextension = NULL;
|
||||||
|
file->flags = FS_FILE_FLAGS_HEADER_INCLUDED;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The endpoint '/images.info' is called when the client wants to call for the
|
||||||
|
* information string that contains the names of the available images.
|
||||||
|
*/
|
||||||
|
if (strncmp(name, "/images.info", strlen("/images.info")) == 0) {
|
||||||
|
// Create the information string for the images in the filesystem
|
||||||
|
buffer_len = wbe_get_images(image_stringbuffer, llfs_file_count());
|
||||||
|
|
||||||
|
// Give the string back to the client
|
||||||
|
file->data = image_stringbuffer;
|
||||||
|
file->len = (int)buffer_len;
|
||||||
|
file->index = (int)buffer_len;
|
||||||
|
file->is_custom_file = 1;
|
||||||
|
file->pextension = NULL;
|
||||||
|
file->flags = FS_FILE_FLAGS_HEADER_INCLUDED;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Endpoint when client wants to send information to the backend
|
||||||
|
if (strncmp(name, "/cgi", 3) == 0) {
|
||||||
|
// Give the original index.html back to the client
|
||||||
|
wanted_file = llfs_file_open("index.html");
|
||||||
|
|
||||||
|
if (wanted_file != NULL) {
|
||||||
|
file->data = (const char*)wanted_file->data;
|
||||||
|
file->len = (int)wanted_file->len;
|
||||||
|
file->index = (int)wanted_file->len;
|
||||||
|
file->is_custom_file = 1;
|
||||||
|
file->pextension = NULL;
|
||||||
|
file->flags = FS_FILE_FLAGS_HEADER_INCLUDED;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fs_close_custom(struct fs_file* file) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fn void wbe_get_images(char*, size_t)
|
||||||
|
* @brief Function searches filesystem for files with extention ".bmp" and ".gif" and put them
|
||||||
|
* combined in a string that needs to be send to the frontend.
|
||||||
|
*
|
||||||
|
* @param[in] images_string, string that will contain the image names
|
||||||
|
* @param[in] file_count_fs, the number of files in the filesystem
|
||||||
|
*/
|
||||||
|
static size_t wbe_get_images(char* images_string, size_t file_count_fs) {
|
||||||
|
// Allocate space for the files
|
||||||
|
llfs_file_t file_list[file_count_fs];
|
||||||
|
|
||||||
|
size_t file_count_bmp = 0;
|
||||||
|
size_t file_count_gif = 0;
|
||||||
|
|
||||||
|
// Reset string
|
||||||
|
strcpy(images_string, "");
|
||||||
|
|
||||||
|
// Get all the ".bmp" and ".gif" files
|
||||||
|
file_count_bmp = llfs_file_list(file_list, file_count_fs, ".bmp");
|
||||||
|
file_count_gif = llfs_file_list(file_list + file_count_bmp, file_count_fs, ".gif");
|
||||||
|
|
||||||
|
// Create the info string
|
||||||
|
wbe_build_infostring(file_list, images_string, file_count_gif + file_count_bmp);
|
||||||
|
|
||||||
|
// Debug info
|
||||||
|
LOG_DEBUG("WBE", "Images string : %s ", images_string);
|
||||||
|
|
||||||
|
// Return the length of the string
|
||||||
|
return strlen(images_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fn void wbe_build_infostring(const llfs_file_t*, char*, const size_t)
|
||||||
|
* @brief Function adds the names of the files in "file_list" and adds them in "infoStr".
|
||||||
|
* The names are seperated by '|' characters.
|
||||||
|
*
|
||||||
|
* @param[in] file_list, list with files
|
||||||
|
* @param[in] info_string, string that will contain the filenames
|
||||||
|
* @param[in] cnt, the number of files
|
||||||
|
*/
|
||||||
|
static inline void wbe_build_infostring(const llfs_file_t* file_list, char* info_string, const size_t cnt) {
|
||||||
|
// Add the filenames to the info string
|
||||||
|
for (size_t i = 0; i < cnt; ++i) {
|
||||||
|
strncat(info_string, file_list[i].name, strlen(file_list[i].name));
|
||||||
|
strncat(info_string, "|", 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove last seperator '|'
|
||||||
|
info_string[strlen(info_string) - 1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
void httpd_cgi_handler(struct fs_file* file, const char* uri, int num_parm, char** pc_param, char** pc_value) {
|
||||||
|
// Variables
|
||||||
|
uint32_t vktxt = LCD_GREEN;
|
||||||
|
uint32_t vka = LCD_BLACK;
|
||||||
|
|
||||||
|
// Allocate space for parameters
|
||||||
|
char vtxt[STR_MAX]; // The sentence that we want to print on the LCD.
|
||||||
|
char vfo[STR_MAX]; // Name of the selected image on the website.
|
||||||
|
char s_vktxt[CLR_MAX]; // The color of the sentence. (in #RGB)
|
||||||
|
char s_vka[CLR_MAX]; // Color of the background. (also in #RGB)
|
||||||
|
|
||||||
|
if (strcmp("/cgi", uri) == 0) {
|
||||||
|
for (size_t i = 0; i < num_parm; ++i) {
|
||||||
|
// The given sentence
|
||||||
|
if (strcmp("vtxt", pc_param[i]) == 0) {
|
||||||
|
wbe_decoding_url(pc_value[i], vtxt);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The color of the sentence
|
||||||
|
if (strcmp("vktxt", pc_param[i]) == 0) {
|
||||||
|
wbe_decoding_url(pc_value[i], s_vktxt);
|
||||||
|
|
||||||
|
// Convert to hex value
|
||||||
|
if (s_vktxt != NULL) {
|
||||||
|
vktxt = wbe_color_value(s_vktxt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Color of the background
|
||||||
|
if (strcmp("vka", pc_param[i]) == 0) {
|
||||||
|
wbe_decoding_url(pc_value[i], s_vka);
|
||||||
|
|
||||||
|
// convert to hex value
|
||||||
|
if (s_vka != NULL) {
|
||||||
|
vka = wbe_color_value(s_vka);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name of the image
|
||||||
|
if (strcmp("vfo", pc_param[i]) == 0) {
|
||||||
|
wbe_decoding_url(pc_value[i], vfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug info
|
||||||
|
LOG_DEBUG("WBE", "CGI DATA : %s , %x , %x , %s", vtxt, vktxt, vka, vfo);
|
||||||
|
|
||||||
|
// Display on LCD
|
||||||
|
wbe_display(vtxt, vktxt, vka, vfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fn void wbe_decoding_url(const char*, char*)
|
||||||
|
* @brief The given information from the CGI parameters are URL encoded.
|
||||||
|
* This function translates this encoded string in a readable
|
||||||
|
* decoded string. The lengthe of "char* decoded" is at least the
|
||||||
|
* length of "char* encoded" + 1.
|
||||||
|
*
|
||||||
|
* @param[in] encoded, the encoded URL string that needs to be decoded
|
||||||
|
* @param[in] decoded, string that will contain the decoded URL.
|
||||||
|
*/
|
||||||
|
static void wbe_decoding_url(const char* encoded, char* decoded) {
|
||||||
|
// Variables
|
||||||
|
char* endptr;
|
||||||
|
size_t decoded_index = 0;
|
||||||
|
size_t encoded_length = strlen(encoded);
|
||||||
|
uint32_t hex_val;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < encoded_length; ++i) {
|
||||||
|
// If we encounter a %xx, decode it to ascii
|
||||||
|
if ((encoded[i] == '%') && (i + 2 < encoded_length)) {
|
||||||
|
// Decode %xx
|
||||||
|
hex_val = (uint32_t)strtoul(&encoded[i + 1], &endptr, 16);
|
||||||
|
|
||||||
|
// Check for conversion errors
|
||||||
|
if (endptr == &encoded[i + 1] || *endptr != '\0') {
|
||||||
|
LOG_DEBUG("WBE", "URL text conversion error");
|
||||||
|
}
|
||||||
|
|
||||||
|
decoded[decoded_index++] = (char)hex_val;
|
||||||
|
|
||||||
|
// Skip 2 characters
|
||||||
|
i += 2;
|
||||||
|
|
||||||
|
// If we encounter a +, add a space character
|
||||||
|
} else if (encoded[i] == '+') {
|
||||||
|
decoded[decoded_index++] = ' ';
|
||||||
|
|
||||||
|
// If no % or +, just put what stands in 'encoded'
|
||||||
|
} else {
|
||||||
|
decoded[decoded_index++] = encoded[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finish the string
|
||||||
|
decoded[decoded_index] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t wbe_color_value(const char* rgb) {
|
||||||
|
// Variables
|
||||||
|
char* endptr;
|
||||||
|
uint32_t color = LCD_BLACK;
|
||||||
|
char argb[11] = "0xff";
|
||||||
|
|
||||||
|
// Create argb string (also, skip the '#' char)
|
||||||
|
strncat(argb, rgb + 1, strlen(rgb + 1));
|
||||||
|
|
||||||
|
// Get argb value
|
||||||
|
color = (uint32_t)strtoul(argb, &endptr, 16);
|
||||||
|
|
||||||
|
// Check for conversion errors
|
||||||
|
if (*endptr != '\0') {
|
||||||
|
color = LCD_BLACK;
|
||||||
|
LOG_DEBUG("WBE", "URL color conversion error");
|
||||||
|
}
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wbe_display(const char* txt, const uint32_t txt_color, const uint32_t bg_color, const char* image) {
|
||||||
|
// Variables
|
||||||
|
lcd_gif_t* gif;
|
||||||
|
const char* extension;
|
||||||
|
|
||||||
|
// clear the screen
|
||||||
|
lcd_clear_text();
|
||||||
|
lcd_clear_images();
|
||||||
|
|
||||||
|
// Display the text and the background
|
||||||
|
lcd_set_bg_color_layer0(bg_color);
|
||||||
|
lcd_display_text(txt, 10, 10, txt_color, bg_color, LCD_FONT16);
|
||||||
|
|
||||||
|
// Get the extension of the file
|
||||||
|
extension = llfs_get_filename_ext(image);
|
||||||
|
|
||||||
|
// Check extension
|
||||||
|
if (extension != NULL) {
|
||||||
|
// Draw bmp
|
||||||
|
if (strcmp(extension, "bmp") == 0) {
|
||||||
|
lcd_draw_img_from_fs(image, IMG_X, IMG_Y);
|
||||||
|
|
||||||
|
// Draw gif
|
||||||
|
} else if (strcmp(extension, "gif") == 0) {
|
||||||
|
gif = lcd_draw_gif_from_fs(image, IMG_X, IMG_Y);
|
||||||
|
|
||||||
|
if (gif == NULL) {
|
||||||
|
LOG_DEBUG("WBE", "GIF could not be drawn");
|
||||||
|
}
|
||||||
|
|
||||||
|
// If nothing, then draw the standard image
|
||||||
|
} else {
|
||||||
|
lcd_draw_img_from_fs(SD_IMG, IMG_X, IMG_Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If nothing, then draw the standard image
|
||||||
|
} else {
|
||||||
|
lcd_draw_img_from_fs(SD_IMG, IMG_X, IMG_Y);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,9 +17,10 @@ target_compile_definitions(tests
|
|||||||
target_sources(tests
|
target_sources(tests
|
||||||
PRIVATE
|
PRIVATE
|
||||||
${TEST_SOURCES}
|
${TEST_SOURCES}
|
||||||
../project/Core/Src/tftp.c
|
${CMAKE_SOURCE_DIR}
|
||||||
../project/Core/Src/llfs_data.c
|
${CMAKE_SOURCE_DIR}/project/Core/Src/llfs_data.c
|
||||||
../project/Core/Src/llfs.c
|
${CMAKE_SOURCE_DIR}/project/Core/Src/llfs.c
|
||||||
|
${CMAKE_SOURCE_DIR}/project/Core/Src/tftp.c
|
||||||
)
|
)
|
||||||
|
|
||||||
target_compile_options(tests PRIVATE $<$<CONFIG:Debug>:
|
target_compile_options(tests PRIVATE $<$<CONFIG:Debug>:
|
||||||
@@ -35,7 +36,7 @@ target_include_directories(tests
|
|||||||
PUBLIC
|
PUBLIC
|
||||||
${CMAKE_CURRENT_LIST_DIR}
|
${CMAKE_CURRENT_LIST_DIR}
|
||||||
${PROJECT_BINARY_DIR}
|
${PROJECT_BINARY_DIR}
|
||||||
../project/Core/Inc/
|
${CMAKE_SOURCE_DIR}/project/Core/Inc/
|
||||||
)
|
)
|
||||||
|
|
||||||
include(GoogleTest)
|
include(GoogleTest)
|
||||||
|
|||||||
13
tests/mocs.c
@@ -12,7 +12,12 @@ int tftp_init(struct tftp_context* context) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void lcd_display_text(const char* text, uint16_t x_pos, uint16_t y_pos, uint32_t color, uint32_t bg_color, sFONT* font) {
|
void lcd_display_text(const char* text,
|
||||||
|
uint16_t x_pos,
|
||||||
|
uint16_t y_pos,
|
||||||
|
uint32_t color,
|
||||||
|
uint32_t bg_color,
|
||||||
|
sFONT* font) {
|
||||||
UNUSED(color);
|
UNUSED(color);
|
||||||
UNUSED(bg_color);
|
UNUSED(bg_color);
|
||||||
UNUSED(font);
|
UNUSED(font);
|
||||||
@@ -54,19 +59,19 @@ struct tcp_pcb* tcp_new(void) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
err_t tcp_bind(void *pcb, void *ipaddr, uint16_t port) {
|
err_t tcp_bind(void* pcb, void* ipaddr, uint16_t port) {
|
||||||
UNUSED(pcb);
|
UNUSED(pcb);
|
||||||
UNUSED(ipaddr);
|
UNUSED(ipaddr);
|
||||||
UNUSED(port);
|
UNUSED(port);
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct tcp_pcb* tcp_listen(void *pcb) {
|
struct tcp_pcb* tcp_listen(void* pcb) {
|
||||||
UNUSED(pcb);
|
UNUSED(pcb);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tcp_accept(void *pcb, tcp_accept_fn arg) {
|
void tcp_accept(void* pcb, tcp_accept_fn arg) {
|
||||||
UNUSED(pcb);
|
UNUSED(pcb);
|
||||||
UNUSED(arg);
|
UNUSED(arg);
|
||||||
}
|
}
|
||||||
|
|||||||
127
tests/mocs.h
@@ -4,8 +4,8 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#ifndef UNUSED
|
#ifndef UNUSED
|
||||||
#define UNUSED(x) (void)(x)
|
#define UNUSED(x) (void)(x)
|
||||||
@@ -16,53 +16,53 @@ extern "C" {
|
|||||||
typedef int8_t err_t;
|
typedef int8_t err_t;
|
||||||
/** Definitions for error constants. */
|
/** Definitions for error constants. */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
/** No error, everything OK. */
|
/** No error, everything OK. */
|
||||||
ERR_OK = 0,
|
ERR_OK = 0,
|
||||||
/** Out of memory error. */
|
/** Out of memory error. */
|
||||||
ERR_MEM = -1,
|
ERR_MEM = -1,
|
||||||
/** Buffer error. */
|
/** Buffer error. */
|
||||||
ERR_BUF = -2,
|
ERR_BUF = -2,
|
||||||
/** Timeout. */
|
/** Timeout. */
|
||||||
ERR_TIMEOUT = -3,
|
ERR_TIMEOUT = -3,
|
||||||
/** Routing problem. */
|
/** Routing problem. */
|
||||||
ERR_RTE = -4,
|
ERR_RTE = -4,
|
||||||
/** Operation in progress */
|
/** Operation in progress */
|
||||||
ERR_INPROGRESS = -5,
|
ERR_INPROGRESS = -5,
|
||||||
/** Illegal value. */
|
/** Illegal value. */
|
||||||
ERR_VAL = -6,
|
ERR_VAL = -6,
|
||||||
/** Operation would block. */
|
/** Operation would block. */
|
||||||
ERR_WOULDBLOCK = -7,
|
ERR_WOULDBLOCK = -7,
|
||||||
/** Address in use. */
|
/** Address in use. */
|
||||||
ERR_USE = -8,
|
ERR_USE = -8,
|
||||||
/** Already connecting. */
|
/** Already connecting. */
|
||||||
ERR_ALREADY = -9,
|
ERR_ALREADY = -9,
|
||||||
/** Conn already established.*/
|
/** Conn already established.*/
|
||||||
ERR_ISCONN = -10,
|
ERR_ISCONN = -10,
|
||||||
/** Not connected. */
|
/** Not connected. */
|
||||||
ERR_CONN = -11,
|
ERR_CONN = -11,
|
||||||
/** Low-level netif error */
|
/** Low-level netif error */
|
||||||
ERR_IF = -12,
|
ERR_IF = -12,
|
||||||
|
|
||||||
/** Connection aborted. */
|
/** Connection aborted. */
|
||||||
ERR_ABRT = -13,
|
ERR_ABRT = -13,
|
||||||
/** Connection reset. */
|
/** Connection reset. */
|
||||||
ERR_RST = -14,
|
ERR_RST = -14,
|
||||||
/** Connection closed. */
|
/** Connection closed. */
|
||||||
ERR_CLSD = -15,
|
ERR_CLSD = -15,
|
||||||
/** Illegal argument. */
|
/** Illegal argument. */
|
||||||
ERR_ARG = -16
|
ERR_ARG = -16
|
||||||
} err_enum_t;
|
} err_enum_t;
|
||||||
|
|
||||||
struct pbuf {
|
struct pbuf {
|
||||||
struct pbuf *next;
|
struct pbuf* next;
|
||||||
void *payload;
|
void* payload;
|
||||||
uint16_t tot_len;
|
uint16_t tot_len;
|
||||||
uint16_t len;
|
uint16_t len;
|
||||||
uint8_t type_internal;
|
uint8_t type_internal;
|
||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
//LWIP_PBUF_REF_T ref;
|
// LWIP_PBUF_REF_T ref;
|
||||||
|
|
||||||
uint8_t if_idx;
|
uint8_t if_idx;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tcp_pcb {
|
struct tcp_pcb {
|
||||||
@@ -70,10 +70,10 @@ struct tcp_pcb {
|
|||||||
};
|
};
|
||||||
typedef void sFONT;
|
typedef void sFONT;
|
||||||
|
|
||||||
#define ERR_OK 0
|
#define ERR_OK 0
|
||||||
#define LCD_COLOR_BLACK 0
|
#define LCD_COLOR_BLACK 0
|
||||||
#define LCD_COLOR_WHITE 1
|
#define LCD_COLOR_WHITE 1
|
||||||
#define LCD_TRANSPARENT 2
|
#define LCD_TRANSPARENT 2
|
||||||
|
|
||||||
#define LCD_FONT16 0
|
#define LCD_FONT16 0
|
||||||
#define LCD_FONT24 (void*)1
|
#define LCD_FONT24 (void*)1
|
||||||
@@ -86,14 +86,13 @@ typedef void sFONT;
|
|||||||
#define TCP_PRIO_MAX 127
|
#define TCP_PRIO_MAX 127
|
||||||
#define IP_ADDR_ANY 0
|
#define IP_ADDR_ANY 0
|
||||||
|
|
||||||
typedef err_t (*tcp_recv_fn)(void *arg, struct tcp_pcb *tpcb,
|
typedef err_t (*tcp_recv_fn)(void* arg, struct tcp_pcb* tpcb, struct pbuf* p, err_t err);
|
||||||
struct pbuf *p, err_t err);
|
|
||||||
|
typedef err_t (*tcp_accept_fn)(void* arg, struct tcp_pcb* newpcb, err_t err);
|
||||||
typedef err_t (*tcp_accept_fn)(void *arg, struct tcp_pcb *newpcb, err_t err);
|
|
||||||
|
|
||||||
uint32_t logger_get_timestamp(void);
|
uint32_t logger_get_timestamp(void);
|
||||||
|
|
||||||
void lcd_display_text(const char* text, uint16_t x_pos, uint16_t y_pos, uint32_t color, uint32_t bg_color, sFONT *font);
|
void lcd_display_text(const char* text, uint16_t x_pos, uint16_t y_pos, uint32_t color, uint32_t bg_color, sFONT* font);
|
||||||
void lcd_draw_img_from_fs(char* filename, uint32_t x_pos, uint32_t y_pos);
|
void lcd_draw_img_from_fs(char* filename, uint32_t x_pos, uint32_t y_pos);
|
||||||
void lcd_draw_gif_from_fs(char* filename, uint32_t x_pos, uint32_t y_pos);
|
void lcd_draw_gif_from_fs(char* filename, uint32_t x_pos, uint32_t y_pos);
|
||||||
void lcd_draw_bmp_img(uint8_t* bmp_buff, uint32_t x_pos, uint32_t y_pos);
|
void lcd_draw_bmp_img(uint8_t* bmp_buff, uint32_t x_pos, uint32_t y_pos);
|
||||||
@@ -103,23 +102,23 @@ void lcd_clear_images(void);
|
|||||||
void lcd_clear_text(void);
|
void lcd_clear_text(void);
|
||||||
|
|
||||||
struct tcp_pcb* tcp_new(void);
|
struct tcp_pcb* tcp_new(void);
|
||||||
err_t tcp_bind(void *pcb, void *ipaddr, uint16_t port);
|
err_t tcp_bind(void* pcb, void* ipaddr, uint16_t port);
|
||||||
struct tcp_pcb* tcp_listen(void *pcb);
|
struct tcp_pcb* tcp_listen(void* pcb);
|
||||||
void tcp_accept(void *pcb, tcp_accept_fn arg);
|
void tcp_accept(void* pcb, tcp_accept_fn arg);
|
||||||
void tcp_arg(void *pcb, void *arg);
|
void tcp_arg(void* pcb, void* arg);
|
||||||
void tcp_sent(void *pcb, void *arg);
|
void tcp_sent(void* pcb, void* arg);
|
||||||
void tcp_recv(void *pcb, tcp_recv_fn arg);
|
void tcp_recv(void* pcb, tcp_recv_fn arg);
|
||||||
void tcp_setprio(void *pcb, uint8_t prio);
|
void tcp_setprio(void* pcb, uint8_t prio);
|
||||||
void tcp_err(void *pcb, void* err);
|
void tcp_err(void* pcb, void* err);
|
||||||
void tcp_poll(void *pcb, void* poll, uint8_t interval);
|
void tcp_poll(void* pcb, void* poll, uint8_t interval);
|
||||||
void tcp_close(void *pcb);
|
void tcp_close(void* pcb);
|
||||||
|
|
||||||
void tcp_write(void *pcb, const char *data, size_t len, uint8_t apiflags);
|
void tcp_write(void* pcb, const char* data, size_t len, uint8_t apiflags);
|
||||||
void tcp_output(void *pcb);
|
void tcp_output(void* pcb);
|
||||||
void tcp_recved(void *pcb, uint16_t len);
|
void tcp_recved(void* pcb, uint16_t len);
|
||||||
void pbuf_free(struct pbuf* p);
|
void pbuf_free(struct pbuf* p);
|
||||||
|
|
||||||
size_t tcp_sndbuf(void *pcb);
|
size_t tcp_sndbuf(void* pcb);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,47 +1,35 @@
|
|||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "mocs.h"
|
#include "mocs.h"
|
||||||
#include "tftp.h"
|
#include "tftp.h"
|
||||||
|
|
||||||
tftp_custom_file_t file = {
|
tftp_custom_file_t file = {.data = (char*)"1234567890", .len = 11, .name = (char*)"test.txt", .offset = 0};
|
||||||
.data = (char*)"1234567890",
|
tftp_custom_file_t write_file = {.data = NULL, .len = 0, .name = (char*)"test.txt", .offset = 0};
|
||||||
.len = 11,
|
|
||||||
.name = (char*)"test.txt",
|
|
||||||
.offset = 0
|
|
||||||
};
|
|
||||||
tftp_custom_file_t write_file = {
|
|
||||||
.data = NULL,
|
|
||||||
.len = 0,
|
|
||||||
.name = (char*)"test.txt",
|
|
||||||
.offset = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST(TFTP, custom_fseek)
|
TEST(TFTP, custom_fseek) {
|
||||||
{
|
|
||||||
tftp_custom_fseek(&file, 5, SEEK_SET);
|
tftp_custom_fseek(&file, 5, SEEK_SET);
|
||||||
EXPECT_EQ(file.offset, 5);
|
EXPECT_EQ(file.offset, 5);
|
||||||
tftp_custom_fseek(&file, 5, SEEK_CUR);
|
tftp_custom_fseek(&file, 5, SEEK_CUR);
|
||||||
EXPECT_EQ(file.offset, 10);
|
EXPECT_EQ(file.offset, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TFTP, custom_fread)
|
TEST(TFTP, custom_fread) {
|
||||||
{
|
|
||||||
char buf[11];
|
char buf[11];
|
||||||
tftp_custom_fseek(&file, 0, SEEK_SET);
|
tftp_custom_fseek(&file, 0, SEEK_SET);
|
||||||
size_t bytes = tftp_custom_fread(buf, 11, &file);
|
size_t bytes = tftp_custom_fread(buf, 11, &file);
|
||||||
EXPECT_EQ(bytes, 10);
|
EXPECT_EQ(bytes, 11);
|
||||||
EXPECT_EQ(file.offset, 10);
|
EXPECT_EQ(file.offset, 11);
|
||||||
EXPECT_EQ(memcmp(buf, "1234567890", 10), 0);
|
EXPECT_EQ(memcmp(buf, "1234567890", 10), 0);
|
||||||
|
|
||||||
memset(buf, 0, 11);
|
memset(buf, 0, 11);
|
||||||
|
|
||||||
tftp_custom_fseek(&file, 0, SEEK_SET);
|
tftp_custom_fseek(&file, 0, SEEK_SET);
|
||||||
bytes = tftp_custom_fread(buf, 11, &file);
|
bytes = tftp_custom_fread(buf, 11, &file);
|
||||||
EXPECT_EQ(bytes, 10);
|
EXPECT_EQ(bytes, 11);
|
||||||
EXPECT_EQ(memcmp(buf, "1234567890", 10), 0);
|
EXPECT_EQ(memcmp(buf, "1234567890", 10), 0);
|
||||||
|
|
||||||
memset(buf, 0, 11);
|
memset(buf, 0, 11);
|
||||||
|
|||||||
@@ -4,15 +4,15 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include "mocs.h"
|
#include "mocs.h"
|
||||||
|
|
||||||
struct tftp_context {
|
struct tftp_context {
|
||||||
void* (*open)(const char* fname, const char* mode, uint8_t write);
|
void* (*open)(const char* fname, const char* mode, uint8_t write);
|
||||||
void (*close)(void* handle);
|
void (*close)(void* handle);
|
||||||
int (*read)(void* handle, void* buf, int bytes);
|
int (*read)(void* handle, void* buf, int bytes);
|
||||||
int (*write)(void* handle, struct pbuf* p);
|
int (*write)(void* handle, struct pbuf* p);
|
||||||
};
|
};
|
||||||
|
|
||||||
void tftp_cleanup(void);
|
void tftp_cleanup(void);
|
||||||
|
|||||||